1 #ifndef SNA_DAMAGE_H
2 #define SNA_DAMAGE_H
3
4 #include <regionstr.h>
5
6 #include "compiler.h"
7
8 struct 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
30 struct sna_damage *sna_damage_create(void);
31
32 struct sna_damage *__sna_damage_all(struct sna_damage *damage,
33 int width, int height);
34 static inline struct sna_damage *
_sna_damage_all(struct sna_damage * damage,int width,int height)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
sna_damage_all(struct sna_damage ** damage,PixmapPtr pixmap)42 static 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
51 struct sna_damage *_sna_damage_combine(struct sna_damage *l,
52 struct sna_damage *r,
53 int dx, int dy);
sna_damage_combine(struct sna_damage ** l,struct sna_damage * r,int dx,int dy)54 static 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
62 fastcall struct sna_damage *_sna_damage_add(struct sna_damage *damage,
63 RegionPtr region);
sna_damage_add(struct sna_damage ** damage,RegionPtr region)64 static 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
sna_damage_add_to_pixmap(struct sna_damage ** damage,RegionPtr region,PixmapPtr pixmap)71 static 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
89 fastcall struct sna_damage *_sna_damage_add_box(struct sna_damage *damage,
90 const BoxRec *box);
sna_damage_add_box(struct sna_damage ** damage,const BoxRec * box)91 static 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
98 struct sna_damage *_sna_damage_add_boxes(struct sna_damage *damage,
99 const BoxRec *box, int n,
100 int16_t dx, int16_t dy);
sna_damage_add_boxes(struct sna_damage ** damage,const BoxRec * box,int n,int16_t dx,int16_t dy)101 static 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
109 struct sna_damage *_sna_damage_add_rectangles(struct sna_damage *damage,
110 const xRectangle *r, int n,
111 int16_t dx, int16_t dy);
sna_damage_add_rectangles(struct sna_damage ** damage,const xRectangle * r,int n,int16_t dx,int16_t dy)112 static 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
122 struct sna_damage *_sna_damage_add_points(struct sna_damage *damage,
123 const DDXPointRec *p, int n,
124 int16_t dx, int16_t dy);
sna_damage_add_points(struct sna_damage ** damage,const DDXPointRec * p,int n,int16_t dx,int16_t dy)125 static 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
135 struct sna_damage *_sna_damage_is_all(struct sna_damage *damage,
136 int width, int height);
sna_damage_is_all(struct sna_damage ** _damage,int width,int height)137 static 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 /* fall through */
156 case DAMAGE_ADD:
157 if (damage->extents.x2 < width || damage->extents.x1 > 0)
158 return false;
159 if (damage->extents.y2 < height || damage->extents.y1 > 0)
160 return false;
161 damage = _sna_damage_is_all(damage, width, height);
162 if (damage->mode == DAMAGE_ALL) {
163 *_damage = DAMAGE_MARK_ALL(damage);
164 return true;
165 } else {
166 *_damage = damage;
167 return false;
168 }
169 }
170 }
171
172 fastcall struct sna_damage *_sna_damage_subtract(struct sna_damage *damage,
173 RegionPtr region);
sna_damage_subtract(struct sna_damage ** damage,RegionPtr region)174 static inline void sna_damage_subtract(struct sna_damage **damage,
175 RegionPtr region)
176 {
177 *damage = _sna_damage_subtract(DAMAGE_PTR(*damage), region);
178 assert(*damage == NULL || (*damage)->mode != DAMAGE_ALL);
179 }
180
181 fastcall struct sna_damage *_sna_damage_subtract_box(struct sna_damage *damage,
182 const BoxRec *box);
sna_damage_subtract_box(struct sna_damage ** damage,const BoxRec * box)183 static inline void sna_damage_subtract_box(struct sna_damage **damage,
184 const BoxRec *box)
185 {
186 *damage = _sna_damage_subtract_box(DAMAGE_PTR(*damage), box);
187 assert(*damage == NULL || (*damage)->mode != DAMAGE_ALL);
188 }
189
190 fastcall struct sna_damage *_sna_damage_subtract_boxes(struct sna_damage *damage,
191 const BoxRec *box, int n,
192 int dx, int dy);
sna_damage_subtract_boxes(struct sna_damage ** damage,const BoxRec * box,int n,int dx,int dy)193 static inline void sna_damage_subtract_boxes(struct sna_damage **damage,
194 const BoxRec *box, int n,
195 int dx, int dy)
196 {
197 *damage = _sna_damage_subtract_boxes(DAMAGE_PTR(*damage),
198 box, n, dx, dy);
199 assert(*damage == NULL || (*damage)->mode != DAMAGE_ALL);
200 }
201
202 bool _sna_damage_intersect(struct sna_damage *damage,
203 RegionPtr region, RegionPtr result);
204
sna_damage_intersect(struct sna_damage * damage,RegionPtr region,RegionPtr result)205 static inline bool sna_damage_intersect(struct sna_damage *damage,
206 RegionPtr region, RegionPtr result)
207 {
208 assert(damage);
209 assert(RegionNotEmpty(region));
210 assert(!DAMAGE_IS_ALL(damage));
211
212 return _sna_damage_intersect(damage, region, result);
213 }
214
215 static inline bool
sna_damage_overlaps_box(const struct sna_damage * damage,const BoxRec * box)216 sna_damage_overlaps_box(const struct sna_damage *damage,
217 const BoxRec *box)
218 {
219 if (box->x2 <= damage->extents.x1 ||
220 box->x1 >= damage->extents.x2)
221 return false;
222
223 if (box->y2 <= damage->extents.y1 ||
224 box->y1 >= damage->extents.y2)
225 return false;
226
227 return true;
228 }
229
230 int _sna_damage_contains_box(struct sna_damage **damage,
231 const BoxRec *box);
sna_damage_contains_box(struct sna_damage ** damage,const BoxRec * box)232 static inline int sna_damage_contains_box(struct sna_damage **damage,
233 const BoxRec *box)
234 {
235 if (DAMAGE_IS_ALL(*damage))
236 return PIXMAN_REGION_IN;
237 if (*damage == NULL)
238 return PIXMAN_REGION_OUT;
239
240 return _sna_damage_contains_box(damage, box);
241 }
sna_damage_contains_box__offset(struct sna_damage ** damage,const BoxRec * box,int dx,int dy)242 static inline int sna_damage_contains_box__offset(struct sna_damage **damage,
243 const BoxRec *box, int dx, int dy)
244 {
245 BoxRec b;
246
247 if (DAMAGE_IS_ALL(*damage))
248 return PIXMAN_REGION_IN;
249 if (*damage == NULL)
250 return PIXMAN_REGION_OUT;
251
252 b = *box;
253 b.x1 += dx; b.x2 += dx;
254 b.y1 += dy; b.y2 += dy;
255 return _sna_damage_contains_box(damage, &b);
256 }
257 bool _sna_damage_contains_box__no_reduce(const struct sna_damage *damage,
258 const BoxRec *box);
259 static inline bool
sna_damage_contains_box__no_reduce(const struct sna_damage * damage,const BoxRec * box)260 sna_damage_contains_box__no_reduce(const struct sna_damage *damage,
261 const BoxRec *box)
262 {
263 assert(!DAMAGE_IS_ALL(damage));
264 return _sna_damage_contains_box__no_reduce(damage, box);
265 }
266
267 int _sna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes);
268 static inline int
sna_damage_get_boxes(struct sna_damage * damage,const BoxRec ** boxes)269 sna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes)
270 {
271 assert(DAMAGE_PTR(damage));
272
273 if (DAMAGE_IS_ALL(damage)) {
274 *boxes = &DAMAGE_PTR(damage)->extents;
275 return 1;
276 } else
277 return _sna_damage_get_boxes(damage, boxes);
278 }
279
280 struct sna_damage *_sna_damage_reduce(struct sna_damage *damage);
sna_damage_reduce(struct sna_damage ** damage)281 static inline void sna_damage_reduce(struct sna_damage **damage)
282 {
283 if (*damage == NULL)
284 return;
285
286 if (!DAMAGE_IS_ALL(*damage) && (*damage)->dirty)
287 *damage = _sna_damage_reduce(*damage);
288 }
289
sna_damage_reduce_all(struct sna_damage ** _damage,PixmapPtr pixmap)290 static inline void sna_damage_reduce_all(struct sna_damage **_damage,
291 PixmapPtr pixmap)
292 {
293 struct sna_damage *damage = *_damage;
294
295 if (damage == NULL || DAMAGE_IS_ALL(damage))
296 return;
297
298 DBG(("%s(width=%d, height=%d)\n", __FUNCTION__, pixmap->drawable.width, pixmap->drawable.height));
299
300 if (damage->mode == DAMAGE_ADD) {
301 if (damage->extents.x1 <= 0 &&
302 damage->extents.y1 <= 0 &&
303 damage->extents.x2 >= pixmap->drawable.width &&
304 damage->extents.y2 >= pixmap->drawable.height) {
305 if (damage->dirty) {
306 damage = *_damage = _sna_damage_reduce(damage);
307 if (damage == NULL)
308 return;
309 }
310
311 if (damage->region.data == NULL)
312 *_damage = _sna_damage_all(damage,
313 pixmap->drawable.width,
314 pixmap->drawable.height);
315 }
316 } else
317 *_damage = _sna_damage_reduce(damage);
318 }
319
320 void __sna_damage_destroy(struct sna_damage *damage);
sna_damage_destroy(struct sna_damage ** damage)321 static inline void sna_damage_destroy(struct sna_damage **damage)
322 {
323 if (*damage == NULL)
324 return;
325
326 if (DAMAGE_PTR(*damage))
327 __sna_damage_destroy(DAMAGE_PTR(*damage));
328 *damage = NULL;
329 }
330
331 void _sna_damage_debug_get_region(struct sna_damage *damage, RegionRec *r);
332
333 #if HAS_DEBUG_FULL && TEST_DAMAGE
334 void sna_damage_selftest(void);
335 #else
sna_damage_selftest(void)336 static inline void sna_damage_selftest(void) {}
337 #endif
338
339 #endif /* SNA_DAMAGE_H */
340