1428d7b3dSmrg#ifndef SNA_DAMAGE_H
2428d7b3dSmrg#define SNA_DAMAGE_H
3428d7b3dSmrg
4428d7b3dSmrg#include <regionstr.h>
5428d7b3dSmrg
6428d7b3dSmrg#include "compiler.h"
7428d7b3dSmrg
8428d7b3dSmrgstruct sna_damage {
9428d7b3dSmrg	BoxRec extents;
10428d7b3dSmrg	pixman_region16_t region;
11428d7b3dSmrg	enum sna_damage_mode {
12428d7b3dSmrg		DAMAGE_ADD = 0,
13428d7b3dSmrg		DAMAGE_SUBTRACT,
14428d7b3dSmrg		DAMAGE_ALL,
15428d7b3dSmrg	} mode;
16428d7b3dSmrg	int remain, dirty;
17428d7b3dSmrg	BoxPtr box;
18428d7b3dSmrg	struct {
19428d7b3dSmrg		struct list list;
20428d7b3dSmrg		int size;
21428d7b3dSmrg		BoxRec box[8];
22428d7b3dSmrg	} embedded_box;
23428d7b3dSmrg};
24428d7b3dSmrg
25428d7b3dSmrg#define DAMAGE_IS_ALL(ptr) (((uintptr_t)(ptr))&1)
26428d7b3dSmrg#define DAMAGE_MARK_ALL(ptr) ((struct sna_damage *)(((uintptr_t)(ptr))|1))
27428d7b3dSmrg#define DAMAGE_PTR(ptr) ((struct sna_damage *)(((uintptr_t)(ptr))&~1))
28428d7b3dSmrg#define DAMAGE_REGION(ptr) (&DAMAGE_PTR(ptr)->region)
29428d7b3dSmrg
30428d7b3dSmrgstruct sna_damage *sna_damage_create(void);
31428d7b3dSmrg
32428d7b3dSmrgstruct sna_damage *__sna_damage_all(struct sna_damage *damage,
33428d7b3dSmrg				    int width, int height);
34428d7b3dSmrgstatic inline struct sna_damage *
35428d7b3dSmrg_sna_damage_all(struct sna_damage *damage,
36428d7b3dSmrg		int width, int height)
37428d7b3dSmrg{
38428d7b3dSmrg	damage = __sna_damage_all(damage, width, height);
39428d7b3dSmrg	return DAMAGE_MARK_ALL(damage);
40428d7b3dSmrg}
41428d7b3dSmrg
42428d7b3dSmrgstatic inline void sna_damage_all(struct sna_damage **damage,
43428d7b3dSmrg				  PixmapPtr pixmap)
44428d7b3dSmrg{
45428d7b3dSmrg	if (!DAMAGE_IS_ALL(*damage))
46428d7b3dSmrg		*damage = _sna_damage_all(*damage,
47428d7b3dSmrg					  pixmap->drawable.width,
48428d7b3dSmrg					  pixmap->drawable.height);
49428d7b3dSmrg}
50428d7b3dSmrg
51428d7b3dSmrgstruct sna_damage *_sna_damage_combine(struct sna_damage *l,
52428d7b3dSmrg				       struct sna_damage *r,
53428d7b3dSmrg				       int dx, int dy);
54428d7b3dSmrgstatic inline void sna_damage_combine(struct sna_damage **l,
55428d7b3dSmrg				      struct sna_damage *r,
56428d7b3dSmrg				      int dx, int dy)
57428d7b3dSmrg{
58428d7b3dSmrg	assert(!DAMAGE_IS_ALL(*l));
59428d7b3dSmrg	*l = _sna_damage_combine(*l, DAMAGE_PTR(r), dx, dy);
60428d7b3dSmrg}
61428d7b3dSmrg
62428d7b3dSmrgfastcall struct sna_damage *_sna_damage_add(struct sna_damage *damage,
63428d7b3dSmrg					    RegionPtr region);
64428d7b3dSmrgstatic inline void sna_damage_add(struct sna_damage **damage,
65428d7b3dSmrg				  RegionPtr region)
66428d7b3dSmrg{
67428d7b3dSmrg	assert(!DAMAGE_IS_ALL(*damage));
68428d7b3dSmrg	*damage = _sna_damage_add(*damage, region);
69428d7b3dSmrg}
70428d7b3dSmrg
71428d7b3dSmrgstatic inline bool sna_damage_add_to_pixmap(struct sna_damage **damage,
72428d7b3dSmrg					    RegionPtr region,
73428d7b3dSmrg					    PixmapPtr pixmap)
74428d7b3dSmrg{
75428d7b3dSmrg	assert(!DAMAGE_IS_ALL(*damage));
76428d7b3dSmrg	if (region->data == NULL &&
77428d7b3dSmrg	    region->extents.x2 - region->extents.x1 >= pixmap->drawable.width &&
78428d7b3dSmrg	    region->extents.y2 - region->extents.y1 >= pixmap->drawable.height) {
79428d7b3dSmrg		*damage = _sna_damage_all(*damage,
80428d7b3dSmrg					  pixmap->drawable.width,
81428d7b3dSmrg					  pixmap->drawable.height);
82428d7b3dSmrg		return true;
83428d7b3dSmrg	} else {
84428d7b3dSmrg		*damage = _sna_damage_add(*damage, region);
85428d7b3dSmrg		return false;
86428d7b3dSmrg	}
87428d7b3dSmrg}
88428d7b3dSmrg
89428d7b3dSmrgfastcall struct sna_damage *_sna_damage_add_box(struct sna_damage *damage,
90428d7b3dSmrg						const BoxRec *box);
91428d7b3dSmrgstatic inline void sna_damage_add_box(struct sna_damage **damage,
92428d7b3dSmrg				      const BoxRec *box)
93428d7b3dSmrg{
94428d7b3dSmrg	assert(!DAMAGE_IS_ALL(*damage));
95428d7b3dSmrg	*damage = _sna_damage_add_box(*damage, box);
96428d7b3dSmrg}
97428d7b3dSmrg
98428d7b3dSmrgstruct sna_damage *_sna_damage_add_boxes(struct sna_damage *damage,
99428d7b3dSmrg					 const BoxRec *box, int n,
100428d7b3dSmrg					 int16_t dx, int16_t dy);
101428d7b3dSmrgstatic inline void sna_damage_add_boxes(struct sna_damage **damage,
102428d7b3dSmrg					const BoxRec *box, int n,
103428d7b3dSmrg					int16_t dx, int16_t dy)
104428d7b3dSmrg{
105428d7b3dSmrg	assert(!DAMAGE_IS_ALL(*damage));
106428d7b3dSmrg	*damage = _sna_damage_add_boxes(*damage, box, n, dx, dy);
107428d7b3dSmrg}
108428d7b3dSmrg
109428d7b3dSmrgstruct sna_damage *_sna_damage_add_rectangles(struct sna_damage *damage,
110428d7b3dSmrg					      const xRectangle *r, int n,
111428d7b3dSmrg					      int16_t dx, int16_t dy);
112428d7b3dSmrgstatic inline void sna_damage_add_rectangles(struct sna_damage **damage,
113428d7b3dSmrg					     const xRectangle *r, int n,
114428d7b3dSmrg					     int16_t dx, int16_t dy)
115428d7b3dSmrg{
116428d7b3dSmrg	if (damage) {
117428d7b3dSmrg		assert(!DAMAGE_IS_ALL(*damage));
118428d7b3dSmrg		*damage = _sna_damage_add_rectangles(*damage, r, n, dx, dy);
119428d7b3dSmrg	}
120428d7b3dSmrg}
121428d7b3dSmrg
122428d7b3dSmrgstruct sna_damage *_sna_damage_add_points(struct sna_damage *damage,
123428d7b3dSmrg					  const DDXPointRec *p, int n,
124428d7b3dSmrg					  int16_t dx, int16_t dy);
125428d7b3dSmrgstatic inline void sna_damage_add_points(struct sna_damage **damage,
126428d7b3dSmrg					 const DDXPointRec *p, int n,
127428d7b3dSmrg					 int16_t dx, int16_t dy)
128428d7b3dSmrg{
129428d7b3dSmrg	if (damage) {
130428d7b3dSmrg		assert(!DAMAGE_IS_ALL(*damage));
131428d7b3dSmrg		*damage = _sna_damage_add_points(*damage, p, n, dx, dy);
132428d7b3dSmrg	}
133428d7b3dSmrg}
134428d7b3dSmrg
135428d7b3dSmrgstruct sna_damage *_sna_damage_is_all(struct sna_damage *damage,
136428d7b3dSmrg				       int width, int height);
137428d7b3dSmrgstatic inline bool sna_damage_is_all(struct sna_damage **_damage,
138428d7b3dSmrg				     int width, int height)
139428d7b3dSmrg{
140428d7b3dSmrg	struct sna_damage *damage = *_damage;
141428d7b3dSmrg
142428d7b3dSmrg	if (damage == NULL)
143428d7b3dSmrg		return false;
144428d7b3dSmrg	if (DAMAGE_IS_ALL(damage))
145428d7b3dSmrg		return true;
146428d7b3dSmrg
147428d7b3dSmrg	switch (damage->mode) {
148428d7b3dSmrg	case DAMAGE_ALL:
149428d7b3dSmrg		assert(0);
150428d7b3dSmrg		return true;
151428d7b3dSmrg	case DAMAGE_SUBTRACT:
152428d7b3dSmrg		return false;
153428d7b3dSmrg	default:
154428d7b3dSmrg		assert(0);
155428d7b3dSmrg	case DAMAGE_ADD:
156428d7b3dSmrg		if (damage->extents.x2 < width  || damage->extents.x1 > 0)
157428d7b3dSmrg			return false;
158428d7b3dSmrg		if (damage->extents.y2 < height || damage->extents.y1 > 0)
159428d7b3dSmrg			return false;
160428d7b3dSmrg		damage = _sna_damage_is_all(damage, width, height);
161428d7b3dSmrg		if (damage->mode == DAMAGE_ALL) {
162428d7b3dSmrg			*_damage = DAMAGE_MARK_ALL(damage);
163428d7b3dSmrg			return true;
164428d7b3dSmrg		} else {
165428d7b3dSmrg			*_damage = damage;
166428d7b3dSmrg			return false;
167428d7b3dSmrg		}
168428d7b3dSmrg	}
169428d7b3dSmrg}
170428d7b3dSmrg
171428d7b3dSmrgfastcall struct sna_damage *_sna_damage_subtract(struct sna_damage *damage,
172428d7b3dSmrg						 RegionPtr region);
173428d7b3dSmrgstatic inline void sna_damage_subtract(struct sna_damage **damage,
174428d7b3dSmrg				       RegionPtr region)
175428d7b3dSmrg{
176428d7b3dSmrg	*damage = _sna_damage_subtract(DAMAGE_PTR(*damage), region);
177428d7b3dSmrg	assert(*damage == NULL || (*damage)->mode != DAMAGE_ALL);
178428d7b3dSmrg}
179428d7b3dSmrg
180428d7b3dSmrgfastcall struct sna_damage *_sna_damage_subtract_box(struct sna_damage *damage,
181428d7b3dSmrg						     const BoxRec *box);
182428d7b3dSmrgstatic inline void sna_damage_subtract_box(struct sna_damage **damage,
183428d7b3dSmrg					   const BoxRec *box)
184428d7b3dSmrg{
185428d7b3dSmrg	*damage = _sna_damage_subtract_box(DAMAGE_PTR(*damage), box);
186428d7b3dSmrg	assert(*damage == NULL || (*damage)->mode != DAMAGE_ALL);
187428d7b3dSmrg}
188428d7b3dSmrg
189428d7b3dSmrgfastcall struct sna_damage *_sna_damage_subtract_boxes(struct sna_damage *damage,
190428d7b3dSmrg						       const BoxRec *box, int n,
191428d7b3dSmrg						       int dx, int dy);
192428d7b3dSmrgstatic inline void sna_damage_subtract_boxes(struct sna_damage **damage,
193428d7b3dSmrg					     const BoxRec *box, int n,
194428d7b3dSmrg					     int dx, int dy)
195428d7b3dSmrg{
196428d7b3dSmrg	*damage = _sna_damage_subtract_boxes(DAMAGE_PTR(*damage),
197428d7b3dSmrg					     box, n, dx, dy);
198428d7b3dSmrg	assert(*damage == NULL || (*damage)->mode != DAMAGE_ALL);
199428d7b3dSmrg}
200428d7b3dSmrg
201428d7b3dSmrgbool _sna_damage_intersect(struct sna_damage *damage,
202428d7b3dSmrg			  RegionPtr region, RegionPtr result);
203428d7b3dSmrg
204428d7b3dSmrgstatic inline bool sna_damage_intersect(struct sna_damage *damage,
205428d7b3dSmrg					RegionPtr region, RegionPtr result)
206428d7b3dSmrg{
207428d7b3dSmrg	assert(damage);
208428d7b3dSmrg	assert(RegionNotEmpty(region));
209428d7b3dSmrg	assert(!DAMAGE_IS_ALL(damage));
210428d7b3dSmrg
211428d7b3dSmrg	return _sna_damage_intersect(damage, region, result);
212428d7b3dSmrg}
213428d7b3dSmrg
214428d7b3dSmrgstatic inline bool
215428d7b3dSmrgsna_damage_overlaps_box(const struct sna_damage *damage,
216428d7b3dSmrg			const BoxRec *box)
217428d7b3dSmrg{
218428d7b3dSmrg	if (box->x2 <= damage->extents.x1 ||
219428d7b3dSmrg	    box->x1 >= damage->extents.x2)
220428d7b3dSmrg		return false;
221428d7b3dSmrg
222428d7b3dSmrg	if (box->y2 <= damage->extents.y1 ||
223428d7b3dSmrg	    box->y1 >= damage->extents.y2)
224428d7b3dSmrg		return false;
225428d7b3dSmrg
226428d7b3dSmrg	return true;
227428d7b3dSmrg}
228428d7b3dSmrg
229428d7b3dSmrgint _sna_damage_contains_box(struct sna_damage **damage,
230428d7b3dSmrg			     const BoxRec *box);
231428d7b3dSmrgstatic inline int sna_damage_contains_box(struct sna_damage **damage,
232428d7b3dSmrg					  const BoxRec *box)
233428d7b3dSmrg{
234428d7b3dSmrg	if (DAMAGE_IS_ALL(*damage))
235428d7b3dSmrg		return PIXMAN_REGION_IN;
236428d7b3dSmrg	if (*damage == NULL)
237428d7b3dSmrg		return PIXMAN_REGION_OUT;
238428d7b3dSmrg
239428d7b3dSmrg	return _sna_damage_contains_box(damage, box);
240428d7b3dSmrg}
241428d7b3dSmrgstatic inline int sna_damage_contains_box__offset(struct sna_damage **damage,
242428d7b3dSmrg						  const BoxRec *box, int dx, int dy)
243428d7b3dSmrg{
244428d7b3dSmrg	BoxRec b;
245428d7b3dSmrg
246428d7b3dSmrg	if (DAMAGE_IS_ALL(*damage))
247428d7b3dSmrg		return PIXMAN_REGION_IN;
248428d7b3dSmrg	if (*damage == NULL)
249428d7b3dSmrg		return PIXMAN_REGION_OUT;
250428d7b3dSmrg
251428d7b3dSmrg	b = *box;
252428d7b3dSmrg	b.x1 += dx; b.x2 += dx;
253428d7b3dSmrg	b.y1 += dy; b.y2 += dy;
254428d7b3dSmrg	return _sna_damage_contains_box(damage, &b);
255428d7b3dSmrg}
256428d7b3dSmrgbool _sna_damage_contains_box__no_reduce(const struct sna_damage *damage,
257428d7b3dSmrg					const BoxRec *box);
258428d7b3dSmrgstatic inline bool
259428d7b3dSmrgsna_damage_contains_box__no_reduce(const struct sna_damage *damage,
260428d7b3dSmrg				   const BoxRec *box)
261428d7b3dSmrg{
262428d7b3dSmrg	assert(!DAMAGE_IS_ALL(damage));
263428d7b3dSmrg	return _sna_damage_contains_box__no_reduce(damage, box);
264428d7b3dSmrg}
265428d7b3dSmrg
266428d7b3dSmrgint _sna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes);
267428d7b3dSmrgstatic inline int
268428d7b3dSmrgsna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes)
269428d7b3dSmrg{
270428d7b3dSmrg	assert(damage);
271428d7b3dSmrg
272428d7b3dSmrg	if (DAMAGE_IS_ALL(damage)) {
273428d7b3dSmrg		*boxes = &DAMAGE_PTR(damage)->extents;
274428d7b3dSmrg		return 1;
275428d7b3dSmrg	} else
276428d7b3dSmrg		return _sna_damage_get_boxes(damage, boxes);
277428d7b3dSmrg}
278428d7b3dSmrg
279428d7b3dSmrgstruct sna_damage *_sna_damage_reduce(struct sna_damage *damage);
280428d7b3dSmrgstatic inline void sna_damage_reduce(struct sna_damage **damage)
281428d7b3dSmrg{
282428d7b3dSmrg	if (*damage == NULL)
283428d7b3dSmrg		return;
284428d7b3dSmrg
285428d7b3dSmrg	if (!DAMAGE_IS_ALL(*damage) && (*damage)->dirty)
286428d7b3dSmrg		*damage = _sna_damage_reduce(*damage);
287428d7b3dSmrg}
288428d7b3dSmrg
289428d7b3dSmrgstatic inline void sna_damage_reduce_all(struct sna_damage **_damage,
290428d7b3dSmrg					 PixmapPtr pixmap)
291428d7b3dSmrg{
292428d7b3dSmrg	struct sna_damage *damage = *_damage;
293428d7b3dSmrg
294428d7b3dSmrg	if (damage == NULL || DAMAGE_IS_ALL(damage))
295428d7b3dSmrg		return;
296428d7b3dSmrg
297428d7b3dSmrg	DBG(("%s(width=%d, height=%d)\n", __FUNCTION__, pixmap->drawable.width, pixmap->drawable.height));
298428d7b3dSmrg
299428d7b3dSmrg	if (damage->mode == DAMAGE_ADD) {
300428d7b3dSmrg		if (damage->extents.x1 <= 0 &&
301428d7b3dSmrg		    damage->extents.y1 <= 0 &&
302428d7b3dSmrg		    damage->extents.x2 >= pixmap->drawable.width &&
303428d7b3dSmrg		    damage->extents.y2 >= pixmap->drawable.height) {
304428d7b3dSmrg			if (damage->dirty) {
305428d7b3dSmrg				damage = *_damage = _sna_damage_reduce(damage);
306428d7b3dSmrg				if (damage == NULL)
307428d7b3dSmrg					return;
308428d7b3dSmrg			}
309428d7b3dSmrg
310428d7b3dSmrg			if (damage->region.data == NULL)
311428d7b3dSmrg				*_damage = _sna_damage_all(damage,
312428d7b3dSmrg							   pixmap->drawable.width,
313428d7b3dSmrg							   pixmap->drawable.height);
314428d7b3dSmrg		}
315428d7b3dSmrg	} else
316428d7b3dSmrg		*_damage = _sna_damage_reduce(damage);
317428d7b3dSmrg}
318428d7b3dSmrg
319428d7b3dSmrgvoid __sna_damage_destroy(struct sna_damage *damage);
320428d7b3dSmrgstatic inline void sna_damage_destroy(struct sna_damage **damage)
321428d7b3dSmrg{
322428d7b3dSmrg	if (*damage == NULL)
323428d7b3dSmrg		return;
324428d7b3dSmrg
325428d7b3dSmrg	__sna_damage_destroy(DAMAGE_PTR(*damage));
326428d7b3dSmrg	*damage = NULL;
327428d7b3dSmrg}
328428d7b3dSmrg
329428d7b3dSmrgvoid _sna_damage_debug_get_region(struct sna_damage *damage, RegionRec *r);
330428d7b3dSmrg
331428d7b3dSmrg#if HAS_DEBUG_FULL && TEST_DAMAGE
332428d7b3dSmrgvoid sna_damage_selftest(void);
333428d7b3dSmrg#else
334428d7b3dSmrgstatic inline void sna_damage_selftest(void) {}
335428d7b3dSmrg#endif
336428d7b3dSmrg
337428d7b3dSmrg#endif /* SNA_DAMAGE_H */
338