1#ifndef SNA_DAMAGE_H
2#define SNA_DAMAGE_H
3
4#include <regionstr.h>
5
6#include "compiler.h"
7
8struct sna_damage {
9	BoxRec extents;
10	pixman_region16_t region;
11	enum sna_damage_mode {
12		DAMAGE_ADD = 0,
13		DAMAGE_SUBTRACT,
14		DAMAGE_ALL,
15	} mode;
16	int remain, dirty;
17	BoxPtr box;
18	struct {
19		struct list list;
20		int size;
21		BoxRec box[8];
22	} embedded_box;
23};
24
25#define DAMAGE_IS_ALL(ptr) (((uintptr_t)(ptr))&1)
26#define DAMAGE_MARK_ALL(ptr) ((struct sna_damage *)(((uintptr_t)(ptr))|1))
27#define DAMAGE_PTR(ptr) ((struct sna_damage *)(((uintptr_t)(ptr))&~1))
28#define DAMAGE_REGION(ptr) (&DAMAGE_PTR(ptr)->region)
29
30struct sna_damage *sna_damage_create(void);
31
32struct sna_damage *__sna_damage_all(struct sna_damage *damage,
33				    int width, int height);
34static inline struct sna_damage *
35_sna_damage_all(struct sna_damage *damage,
36		int width, int height)
37{
38	damage = __sna_damage_all(damage, width, height);
39	return DAMAGE_MARK_ALL(damage);
40}
41
42static inline void sna_damage_all(struct sna_damage **damage,
43				  PixmapPtr pixmap)
44{
45	if (!DAMAGE_IS_ALL(*damage))
46		*damage = _sna_damage_all(*damage,
47					  pixmap->drawable.width,
48					  pixmap->drawable.height);
49}
50
51struct sna_damage *_sna_damage_combine(struct sna_damage *l,
52				       struct sna_damage *r,
53				       int dx, int dy);
54static inline void sna_damage_combine(struct sna_damage **l,
55				      struct sna_damage *r,
56				      int dx, int dy)
57{
58	assert(!DAMAGE_IS_ALL(*l));
59	*l = _sna_damage_combine(*l, DAMAGE_PTR(r), dx, dy);
60}
61
62fastcall struct sna_damage *_sna_damage_add(struct sna_damage *damage,
63					    RegionPtr region);
64static inline void sna_damage_add(struct sna_damage **damage,
65				  RegionPtr region)
66{
67	assert(!DAMAGE_IS_ALL(*damage));
68	*damage = _sna_damage_add(*damage, region);
69}
70
71static inline bool sna_damage_add_to_pixmap(struct sna_damage **damage,
72					    RegionPtr region,
73					    PixmapPtr pixmap)
74{
75	assert(!DAMAGE_IS_ALL(*damage));
76	if (region->data == NULL &&
77	    region->extents.x2 - region->extents.x1 >= pixmap->drawable.width &&
78	    region->extents.y2 - region->extents.y1 >= pixmap->drawable.height) {
79		*damage = _sna_damage_all(*damage,
80					  pixmap->drawable.width,
81					  pixmap->drawable.height);
82		return true;
83	} else {
84		*damage = _sna_damage_add(*damage, region);
85		return false;
86	}
87}
88
89fastcall struct sna_damage *_sna_damage_add_box(struct sna_damage *damage,
90						const BoxRec *box);
91static inline void sna_damage_add_box(struct sna_damage **damage,
92				      const BoxRec *box)
93{
94	assert(!DAMAGE_IS_ALL(*damage));
95	*damage = _sna_damage_add_box(*damage, box);
96}
97
98struct sna_damage *_sna_damage_add_boxes(struct sna_damage *damage,
99					 const BoxRec *box, int n,
100					 int16_t dx, int16_t dy);
101static inline void sna_damage_add_boxes(struct sna_damage **damage,
102					const BoxRec *box, int n,
103					int16_t dx, int16_t dy)
104{
105	assert(!DAMAGE_IS_ALL(*damage));
106	*damage = _sna_damage_add_boxes(*damage, box, n, dx, dy);
107}
108
109struct sna_damage *_sna_damage_add_rectangles(struct sna_damage *damage,
110					      const xRectangle *r, int n,
111					      int16_t dx, int16_t dy);
112static inline void sna_damage_add_rectangles(struct sna_damage **damage,
113					     const xRectangle *r, int n,
114					     int16_t dx, int16_t dy)
115{
116	if (damage) {
117		assert(!DAMAGE_IS_ALL(*damage));
118		*damage = _sna_damage_add_rectangles(*damage, r, n, dx, dy);
119	}
120}
121
122struct sna_damage *_sna_damage_add_points(struct sna_damage *damage,
123					  const DDXPointRec *p, int n,
124					  int16_t dx, int16_t dy);
125static inline void sna_damage_add_points(struct sna_damage **damage,
126					 const DDXPointRec *p, int n,
127					 int16_t dx, int16_t dy)
128{
129	if (damage) {
130		assert(!DAMAGE_IS_ALL(*damage));
131		*damage = _sna_damage_add_points(*damage, p, n, dx, dy);
132	}
133}
134
135struct sna_damage *_sna_damage_is_all(struct sna_damage *damage,
136				       int width, int height);
137static inline bool sna_damage_is_all(struct sna_damage **_damage,
138				     int width, int height)
139{
140	struct sna_damage *damage = *_damage;
141
142	if (damage == NULL)
143		return false;
144	if (DAMAGE_IS_ALL(damage))
145		return true;
146
147	switch (damage->mode) {
148	case DAMAGE_ALL:
149		assert(0);
150		return true;
151	case DAMAGE_SUBTRACT:
152		return false;
153	default:
154		assert(0);
155	case DAMAGE_ADD:
156		if (damage->extents.x2 < width  || damage->extents.x1 > 0)
157			return false;
158		if (damage->extents.y2 < height || damage->extents.y1 > 0)
159			return false;
160		damage = _sna_damage_is_all(damage, width, height);
161		if (damage->mode == DAMAGE_ALL) {
162			*_damage = DAMAGE_MARK_ALL(damage);
163			return true;
164		} else {
165			*_damage = damage;
166			return false;
167		}
168	}
169}
170
171fastcall struct sna_damage *_sna_damage_subtract(struct sna_damage *damage,
172						 RegionPtr region);
173static inline void sna_damage_subtract(struct sna_damage **damage,
174				       RegionPtr region)
175{
176	*damage = _sna_damage_subtract(DAMAGE_PTR(*damage), region);
177	assert(*damage == NULL || (*damage)->mode != DAMAGE_ALL);
178}
179
180fastcall struct sna_damage *_sna_damage_subtract_box(struct sna_damage *damage,
181						     const BoxRec *box);
182static inline void sna_damage_subtract_box(struct sna_damage **damage,
183					   const BoxRec *box)
184{
185	*damage = _sna_damage_subtract_box(DAMAGE_PTR(*damage), box);
186	assert(*damage == NULL || (*damage)->mode != DAMAGE_ALL);
187}
188
189fastcall struct sna_damage *_sna_damage_subtract_boxes(struct sna_damage *damage,
190						       const BoxRec *box, int n,
191						       int dx, int dy);
192static inline void sna_damage_subtract_boxes(struct sna_damage **damage,
193					     const BoxRec *box, int n,
194					     int dx, int dy)
195{
196	*damage = _sna_damage_subtract_boxes(DAMAGE_PTR(*damage),
197					     box, n, dx, dy);
198	assert(*damage == NULL || (*damage)->mode != DAMAGE_ALL);
199}
200
201bool _sna_damage_intersect(struct sna_damage *damage,
202			  RegionPtr region, RegionPtr result);
203
204static inline bool sna_damage_intersect(struct sna_damage *damage,
205					RegionPtr region, RegionPtr result)
206{
207	assert(damage);
208	assert(RegionNotEmpty(region));
209	assert(!DAMAGE_IS_ALL(damage));
210
211	return _sna_damage_intersect(damage, region, result);
212}
213
214static inline bool
215sna_damage_overlaps_box(const struct sna_damage *damage,
216			const BoxRec *box)
217{
218	if (box->x2 <= damage->extents.x1 ||
219	    box->x1 >= damage->extents.x2)
220		return false;
221
222	if (box->y2 <= damage->extents.y1 ||
223	    box->y1 >= damage->extents.y2)
224		return false;
225
226	return true;
227}
228
229int _sna_damage_contains_box(struct sna_damage **damage,
230			     const BoxRec *box);
231static inline int sna_damage_contains_box(struct sna_damage **damage,
232					  const BoxRec *box)
233{
234	if (DAMAGE_IS_ALL(*damage))
235		return PIXMAN_REGION_IN;
236	if (*damage == NULL)
237		return PIXMAN_REGION_OUT;
238
239	return _sna_damage_contains_box(damage, box);
240}
241static inline int sna_damage_contains_box__offset(struct sna_damage **damage,
242						  const BoxRec *box, int dx, int dy)
243{
244	BoxRec b;
245
246	if (DAMAGE_IS_ALL(*damage))
247		return PIXMAN_REGION_IN;
248	if (*damage == NULL)
249		return PIXMAN_REGION_OUT;
250
251	b = *box;
252	b.x1 += dx; b.x2 += dx;
253	b.y1 += dy; b.y2 += dy;
254	return _sna_damage_contains_box(damage, &b);
255}
256bool _sna_damage_contains_box__no_reduce(const struct sna_damage *damage,
257					const BoxRec *box);
258static inline bool
259sna_damage_contains_box__no_reduce(const struct sna_damage *damage,
260				   const BoxRec *box)
261{
262	assert(!DAMAGE_IS_ALL(damage));
263	return _sna_damage_contains_box__no_reduce(damage, box);
264}
265
266int _sna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes);
267static inline int
268sna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes)
269{
270	assert(DAMAGE_PTR(damage));
271
272	if (DAMAGE_IS_ALL(damage)) {
273		*boxes = &DAMAGE_PTR(damage)->extents;
274		return 1;
275	} else
276		return _sna_damage_get_boxes(damage, boxes);
277}
278
279struct sna_damage *_sna_damage_reduce(struct sna_damage *damage);
280static inline void sna_damage_reduce(struct sna_damage **damage)
281{
282	if (*damage == NULL)
283		return;
284
285	if (!DAMAGE_IS_ALL(*damage) && (*damage)->dirty)
286		*damage = _sna_damage_reduce(*damage);
287}
288
289static inline void sna_damage_reduce_all(struct sna_damage **_damage,
290					 PixmapPtr pixmap)
291{
292	struct sna_damage *damage = *_damage;
293
294	if (damage == NULL || DAMAGE_IS_ALL(damage))
295		return;
296
297	DBG(("%s(width=%d, height=%d)\n", __FUNCTION__, pixmap->drawable.width, pixmap->drawable.height));
298
299	if (damage->mode == DAMAGE_ADD) {
300		if (damage->extents.x1 <= 0 &&
301		    damage->extents.y1 <= 0 &&
302		    damage->extents.x2 >= pixmap->drawable.width &&
303		    damage->extents.y2 >= pixmap->drawable.height) {
304			if (damage->dirty) {
305				damage = *_damage = _sna_damage_reduce(damage);
306				if (damage == NULL)
307					return;
308			}
309
310			if (damage->region.data == NULL)
311				*_damage = _sna_damage_all(damage,
312							   pixmap->drawable.width,
313							   pixmap->drawable.height);
314		}
315	} else
316		*_damage = _sna_damage_reduce(damage);
317}
318
319void __sna_damage_destroy(struct sna_damage *damage);
320static inline void sna_damage_destroy(struct sna_damage **damage)
321{
322	if (*damage == NULL)
323		return;
324
325	if (DAMAGE_PTR(*damage))
326		__sna_damage_destroy(DAMAGE_PTR(*damage));
327	*damage = NULL;
328}
329
330void _sna_damage_debug_get_region(struct sna_damage *damage, RegionRec *r);
331
332#if HAS_DEBUG_FULL && TEST_DAMAGE
333void sna_damage_selftest(void);
334#else
335static inline void sna_damage_selftest(void) {}
336#endif
337
338#endif /* SNA_DAMAGE_H */
339