#ifndef SNA_DAMAGE_H #define SNA_DAMAGE_H #include #include "compiler.h" struct sna_damage { BoxRec extents; pixman_region16_t region; enum sna_damage_mode { DAMAGE_ADD = 0, DAMAGE_SUBTRACT, DAMAGE_ALL, } mode; int remain, dirty; BoxPtr box; struct { struct list list; int size; BoxRec box[8]; } embedded_box; }; #define DAMAGE_IS_ALL(ptr) (((uintptr_t)(ptr))&1) #define DAMAGE_MARK_ALL(ptr) ((struct sna_damage *)(((uintptr_t)(ptr))|1)) #define DAMAGE_PTR(ptr) ((struct sna_damage *)(((uintptr_t)(ptr))&~1)) #define DAMAGE_REGION(ptr) (&DAMAGE_PTR(ptr)->region) struct sna_damage *sna_damage_create(void); struct sna_damage *__sna_damage_all(struct sna_damage *damage, int width, int height); static inline struct sna_damage * _sna_damage_all(struct sna_damage *damage, int width, int height) { damage = __sna_damage_all(damage, width, height); return DAMAGE_MARK_ALL(damage); } static inline void sna_damage_all(struct sna_damage **damage, PixmapPtr pixmap) { if (!DAMAGE_IS_ALL(*damage)) *damage = _sna_damage_all(*damage, pixmap->drawable.width, pixmap->drawable.height); } struct sna_damage *_sna_damage_combine(struct sna_damage *l, struct sna_damage *r, int dx, int dy); static inline void sna_damage_combine(struct sna_damage **l, struct sna_damage *r, int dx, int dy) { assert(!DAMAGE_IS_ALL(*l)); *l = _sna_damage_combine(*l, DAMAGE_PTR(r), dx, dy); } fastcall struct sna_damage *_sna_damage_add(struct sna_damage *damage, RegionPtr region); static inline void sna_damage_add(struct sna_damage **damage, RegionPtr region) { assert(!DAMAGE_IS_ALL(*damage)); *damage = _sna_damage_add(*damage, region); } static inline bool sna_damage_add_to_pixmap(struct sna_damage **damage, RegionPtr region, PixmapPtr pixmap) { assert(!DAMAGE_IS_ALL(*damage)); if (region->data == NULL && region->extents.x2 - region->extents.x1 >= pixmap->drawable.width && region->extents.y2 - region->extents.y1 >= pixmap->drawable.height) { *damage = _sna_damage_all(*damage, pixmap->drawable.width, pixmap->drawable.height); return true; } else { *damage = _sna_damage_add(*damage, region); return false; } } fastcall struct sna_damage *_sna_damage_add_box(struct sna_damage *damage, const BoxRec *box); static inline void sna_damage_add_box(struct sna_damage **damage, const BoxRec *box) { assert(!DAMAGE_IS_ALL(*damage)); *damage = _sna_damage_add_box(*damage, box); } struct sna_damage *_sna_damage_add_boxes(struct sna_damage *damage, const BoxRec *box, int n, int16_t dx, int16_t dy); static inline void sna_damage_add_boxes(struct sna_damage **damage, const BoxRec *box, int n, int16_t dx, int16_t dy) { assert(!DAMAGE_IS_ALL(*damage)); *damage = _sna_damage_add_boxes(*damage, box, n, dx, dy); } struct sna_damage *_sna_damage_add_rectangles(struct sna_damage *damage, const xRectangle *r, int n, int16_t dx, int16_t dy); static inline void sna_damage_add_rectangles(struct sna_damage **damage, const xRectangle *r, int n, int16_t dx, int16_t dy) { if (damage) { assert(!DAMAGE_IS_ALL(*damage)); *damage = _sna_damage_add_rectangles(*damage, r, n, dx, dy); } } struct sna_damage *_sna_damage_add_points(struct sna_damage *damage, const DDXPointRec *p, int n, int16_t dx, int16_t dy); static inline void sna_damage_add_points(struct sna_damage **damage, const DDXPointRec *p, int n, int16_t dx, int16_t dy) { if (damage) { assert(!DAMAGE_IS_ALL(*damage)); *damage = _sna_damage_add_points(*damage, p, n, dx, dy); } } struct sna_damage *_sna_damage_is_all(struct sna_damage *damage, int width, int height); static inline bool sna_damage_is_all(struct sna_damage **_damage, int width, int height) { struct sna_damage *damage = *_damage; if (damage == NULL) return false; if (DAMAGE_IS_ALL(damage)) return true; switch (damage->mode) { case DAMAGE_ALL: assert(0); return true; case DAMAGE_SUBTRACT: return false; default: assert(0); /* fall through */ case DAMAGE_ADD: if (damage->extents.x2 < width || damage->extents.x1 > 0) return false; if (damage->extents.y2 < height || damage->extents.y1 > 0) return false; damage = _sna_damage_is_all(damage, width, height); if (damage->mode == DAMAGE_ALL) { *_damage = DAMAGE_MARK_ALL(damage); return true; } else { *_damage = damage; return false; } } } fastcall struct sna_damage *_sna_damage_subtract(struct sna_damage *damage, RegionPtr region); static inline void sna_damage_subtract(struct sna_damage **damage, RegionPtr region) { *damage = _sna_damage_subtract(DAMAGE_PTR(*damage), region); assert(*damage == NULL || (*damage)->mode != DAMAGE_ALL); } fastcall struct sna_damage *_sna_damage_subtract_box(struct sna_damage *damage, const BoxRec *box); static inline void sna_damage_subtract_box(struct sna_damage **damage, const BoxRec *box) { *damage = _sna_damage_subtract_box(DAMAGE_PTR(*damage), box); assert(*damage == NULL || (*damage)->mode != DAMAGE_ALL); } fastcall struct sna_damage *_sna_damage_subtract_boxes(struct sna_damage *damage, const BoxRec *box, int n, int dx, int dy); static inline void sna_damage_subtract_boxes(struct sna_damage **damage, const BoxRec *box, int n, int dx, int dy) { *damage = _sna_damage_subtract_boxes(DAMAGE_PTR(*damage), box, n, dx, dy); assert(*damage == NULL || (*damage)->mode != DAMAGE_ALL); } bool _sna_damage_intersect(struct sna_damage *damage, RegionPtr region, RegionPtr result); static inline bool sna_damage_intersect(struct sna_damage *damage, RegionPtr region, RegionPtr result) { assert(damage); assert(RegionNotEmpty(region)); assert(!DAMAGE_IS_ALL(damage)); return _sna_damage_intersect(damage, region, result); } static inline bool sna_damage_overlaps_box(const struct sna_damage *damage, const BoxRec *box) { if (box->x2 <= damage->extents.x1 || box->x1 >= damage->extents.x2) return false; if (box->y2 <= damage->extents.y1 || box->y1 >= damage->extents.y2) return false; return true; } int _sna_damage_contains_box(struct sna_damage **damage, const BoxRec *box); static inline int sna_damage_contains_box(struct sna_damage **damage, const BoxRec *box) { if (DAMAGE_IS_ALL(*damage)) return PIXMAN_REGION_IN; if (*damage == NULL) return PIXMAN_REGION_OUT; return _sna_damage_contains_box(damage, box); } static inline int sna_damage_contains_box__offset(struct sna_damage **damage, const BoxRec *box, int dx, int dy) { BoxRec b; if (DAMAGE_IS_ALL(*damage)) return PIXMAN_REGION_IN; if (*damage == NULL) return PIXMAN_REGION_OUT; b = *box; b.x1 += dx; b.x2 += dx; b.y1 += dy; b.y2 += dy; return _sna_damage_contains_box(damage, &b); } bool _sna_damage_contains_box__no_reduce(const struct sna_damage *damage, const BoxRec *box); static inline bool sna_damage_contains_box__no_reduce(const struct sna_damage *damage, const BoxRec *box) { assert(!DAMAGE_IS_ALL(damage)); return _sna_damage_contains_box__no_reduce(damage, box); } int _sna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes); static inline int sna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes) { assert(DAMAGE_PTR(damage)); if (DAMAGE_IS_ALL(damage)) { *boxes = &DAMAGE_PTR(damage)->extents; return 1; } else return _sna_damage_get_boxes(damage, boxes); } struct sna_damage *_sna_damage_reduce(struct sna_damage *damage); static inline void sna_damage_reduce(struct sna_damage **damage) { if (*damage == NULL) return; if (!DAMAGE_IS_ALL(*damage) && (*damage)->dirty) *damage = _sna_damage_reduce(*damage); } static inline void sna_damage_reduce_all(struct sna_damage **_damage, PixmapPtr pixmap) { struct sna_damage *damage = *_damage; if (damage == NULL || DAMAGE_IS_ALL(damage)) return; DBG(("%s(width=%d, height=%d)\n", __FUNCTION__, pixmap->drawable.width, pixmap->drawable.height)); if (damage->mode == DAMAGE_ADD) { if (damage->extents.x1 <= 0 && damage->extents.y1 <= 0 && damage->extents.x2 >= pixmap->drawable.width && damage->extents.y2 >= pixmap->drawable.height) { if (damage->dirty) { damage = *_damage = _sna_damage_reduce(damage); if (damage == NULL) return; } if (damage->region.data == NULL) *_damage = _sna_damage_all(damage, pixmap->drawable.width, pixmap->drawable.height); } } else *_damage = _sna_damage_reduce(damage); } void __sna_damage_destroy(struct sna_damage *damage); static inline void sna_damage_destroy(struct sna_damage **damage) { if (*damage == NULL) return; if (DAMAGE_PTR(*damage)) __sna_damage_destroy(DAMAGE_PTR(*damage)); *damage = NULL; } void _sna_damage_debug_get_region(struct sna_damage *damage, RegionRec *r); #if HAS_DEBUG_FULL && TEST_DAMAGE void sna_damage_selftest(void); #else static inline void sna_damage_selftest(void) {} #endif #endif /* SNA_DAMAGE_H */