103b705cfSriastradh#ifndef SNA_DAMAGE_H
203b705cfSriastradh#define SNA_DAMAGE_H
303b705cfSriastradh
403b705cfSriastradh#include <regionstr.h>
503b705cfSriastradh
603b705cfSriastradh#include "compiler.h"
703b705cfSriastradh
803b705cfSriastradhstruct sna_damage {
903b705cfSriastradh	BoxRec extents;
1003b705cfSriastradh	pixman_region16_t region;
1103b705cfSriastradh	enum sna_damage_mode {
1203b705cfSriastradh		DAMAGE_ADD = 0,
1303b705cfSriastradh		DAMAGE_SUBTRACT,
1403b705cfSriastradh		DAMAGE_ALL,
1503b705cfSriastradh	} mode;
1603b705cfSriastradh	int remain, dirty;
1703b705cfSriastradh	BoxPtr box;
1803b705cfSriastradh	struct {
1903b705cfSriastradh		struct list list;
2003b705cfSriastradh		int size;
2103b705cfSriastradh		BoxRec box[8];
2203b705cfSriastradh	} embedded_box;
2303b705cfSriastradh};
2403b705cfSriastradh
2503b705cfSriastradh#define DAMAGE_IS_ALL(ptr) (((uintptr_t)(ptr))&1)
2603b705cfSriastradh#define DAMAGE_MARK_ALL(ptr) ((struct sna_damage *)(((uintptr_t)(ptr))|1))
2703b705cfSriastradh#define DAMAGE_PTR(ptr) ((struct sna_damage *)(((uintptr_t)(ptr))&~1))
2842542f5fSchristos#define DAMAGE_REGION(ptr) (&DAMAGE_PTR(ptr)->region)
2903b705cfSriastradh
3003b705cfSriastradhstruct sna_damage *sna_damage_create(void);
3103b705cfSriastradh
3213496ba1Ssnjstruct sna_damage *__sna_damage_all(struct sna_damage *damage,
3313496ba1Ssnj				    int width, int height);
3413496ba1Ssnjstatic inline struct sna_damage *
3513496ba1Ssnj_sna_damage_all(struct sna_damage *damage,
3613496ba1Ssnj		int width, int height)
3713496ba1Ssnj{
3813496ba1Ssnj	damage = __sna_damage_all(damage, width, height);
3913496ba1Ssnj	return DAMAGE_MARK_ALL(damage);
4013496ba1Ssnj}
4113496ba1Ssnj
4213496ba1Ssnjstatic inline void sna_damage_all(struct sna_damage **damage,
4313496ba1Ssnj				  PixmapPtr pixmap)
4413496ba1Ssnj{
4513496ba1Ssnj	if (!DAMAGE_IS_ALL(*damage))
4613496ba1Ssnj		*damage = _sna_damage_all(*damage,
4713496ba1Ssnj					  pixmap->drawable.width,
4813496ba1Ssnj					  pixmap->drawable.height);
4913496ba1Ssnj}
5013496ba1Ssnj
5103b705cfSriastradhstruct sna_damage *_sna_damage_combine(struct sna_damage *l,
5203b705cfSriastradh				       struct sna_damage *r,
5303b705cfSriastradh				       int dx, int dy);
5403b705cfSriastradhstatic inline void sna_damage_combine(struct sna_damage **l,
5503b705cfSriastradh				      struct sna_damage *r,
5603b705cfSriastradh				      int dx, int dy)
5703b705cfSriastradh{
5803b705cfSriastradh	assert(!DAMAGE_IS_ALL(*l));
5903b705cfSriastradh	*l = _sna_damage_combine(*l, DAMAGE_PTR(r), dx, dy);
6003b705cfSriastradh}
6103b705cfSriastradh
6203b705cfSriastradhfastcall struct sna_damage *_sna_damage_add(struct sna_damage *damage,
6303b705cfSriastradh					    RegionPtr region);
6403b705cfSriastradhstatic inline void sna_damage_add(struct sna_damage **damage,
6503b705cfSriastradh				  RegionPtr region)
6603b705cfSriastradh{
6703b705cfSriastradh	assert(!DAMAGE_IS_ALL(*damage));
6803b705cfSriastradh	*damage = _sna_damage_add(*damage, region);
6903b705cfSriastradh}
7003b705cfSriastradh
7113496ba1Ssnjstatic inline bool sna_damage_add_to_pixmap(struct sna_damage **damage,
7213496ba1Ssnj					    RegionPtr region,
7313496ba1Ssnj					    PixmapPtr pixmap)
7413496ba1Ssnj{
7513496ba1Ssnj	assert(!DAMAGE_IS_ALL(*damage));
7613496ba1Ssnj	if (region->data == NULL &&
7713496ba1Ssnj	    region->extents.x2 - region->extents.x1 >= pixmap->drawable.width &&
7813496ba1Ssnj	    region->extents.y2 - region->extents.y1 >= pixmap->drawable.height) {
7913496ba1Ssnj		*damage = _sna_damage_all(*damage,
8013496ba1Ssnj					  pixmap->drawable.width,
8113496ba1Ssnj					  pixmap->drawable.height);
8213496ba1Ssnj		return true;
8313496ba1Ssnj	} else {
8413496ba1Ssnj		*damage = _sna_damage_add(*damage, region);
8513496ba1Ssnj		return false;
8613496ba1Ssnj	}
8713496ba1Ssnj}
8813496ba1Ssnj
8903b705cfSriastradhfastcall struct sna_damage *_sna_damage_add_box(struct sna_damage *damage,
9003b705cfSriastradh						const BoxRec *box);
9103b705cfSriastradhstatic inline void sna_damage_add_box(struct sna_damage **damage,
9203b705cfSriastradh				      const BoxRec *box)
9303b705cfSriastradh{
9403b705cfSriastradh	assert(!DAMAGE_IS_ALL(*damage));
9503b705cfSriastradh	*damage = _sna_damage_add_box(*damage, box);
9603b705cfSriastradh}
9703b705cfSriastradh
9803b705cfSriastradhstruct sna_damage *_sna_damage_add_boxes(struct sna_damage *damage,
9903b705cfSriastradh					 const BoxRec *box, int n,
10003b705cfSriastradh					 int16_t dx, int16_t dy);
10103b705cfSriastradhstatic inline void sna_damage_add_boxes(struct sna_damage **damage,
10203b705cfSriastradh					const BoxRec *box, int n,
10303b705cfSriastradh					int16_t dx, int16_t dy)
10403b705cfSriastradh{
10503b705cfSriastradh	assert(!DAMAGE_IS_ALL(*damage));
10603b705cfSriastradh	*damage = _sna_damage_add_boxes(*damage, box, n, dx, dy);
10703b705cfSriastradh}
10803b705cfSriastradh
10903b705cfSriastradhstruct sna_damage *_sna_damage_add_rectangles(struct sna_damage *damage,
11003b705cfSriastradh					      const xRectangle *r, int n,
11103b705cfSriastradh					      int16_t dx, int16_t dy);
11203b705cfSriastradhstatic inline void sna_damage_add_rectangles(struct sna_damage **damage,
11303b705cfSriastradh					     const xRectangle *r, int n,
11403b705cfSriastradh					     int16_t dx, int16_t dy)
11503b705cfSriastradh{
11603b705cfSriastradh	if (damage) {
11703b705cfSriastradh		assert(!DAMAGE_IS_ALL(*damage));
11803b705cfSriastradh		*damage = _sna_damage_add_rectangles(*damage, r, n, dx, dy);
11903b705cfSriastradh	}
12003b705cfSriastradh}
12103b705cfSriastradh
12203b705cfSriastradhstruct sna_damage *_sna_damage_add_points(struct sna_damage *damage,
12303b705cfSriastradh					  const DDXPointRec *p, int n,
12403b705cfSriastradh					  int16_t dx, int16_t dy);
12503b705cfSriastradhstatic inline void sna_damage_add_points(struct sna_damage **damage,
12603b705cfSriastradh					 const DDXPointRec *p, int n,
12703b705cfSriastradh					 int16_t dx, int16_t dy)
12803b705cfSriastradh{
12903b705cfSriastradh	if (damage) {
13003b705cfSriastradh		assert(!DAMAGE_IS_ALL(*damage));
13103b705cfSriastradh		*damage = _sna_damage_add_points(*damage, p, n, dx, dy);
13203b705cfSriastradh	}
13303b705cfSriastradh}
13403b705cfSriastradh
13503b705cfSriastradhstruct sna_damage *_sna_damage_is_all(struct sna_damage *damage,
13603b705cfSriastradh				       int width, int height);
13703b705cfSriastradhstatic inline bool sna_damage_is_all(struct sna_damage **_damage,
13803b705cfSriastradh				     int width, int height)
13903b705cfSriastradh{
14003b705cfSriastradh	struct sna_damage *damage = *_damage;
14103b705cfSriastradh
14203b705cfSriastradh	if (damage == NULL)
14303b705cfSriastradh		return false;
14403b705cfSriastradh	if (DAMAGE_IS_ALL(damage))
14503b705cfSriastradh		return true;
14603b705cfSriastradh
14703b705cfSriastradh	switch (damage->mode) {
14803b705cfSriastradh	case DAMAGE_ALL:
14903b705cfSriastradh		assert(0);
15003b705cfSriastradh		return true;
15103b705cfSriastradh	case DAMAGE_SUBTRACT:
15203b705cfSriastradh		return false;
15303b705cfSriastradh	default:
15403b705cfSriastradh		assert(0);
15503b705cfSriastradh	case DAMAGE_ADD:
15603b705cfSriastradh		if (damage->extents.x2 < width  || damage->extents.x1 > 0)
15703b705cfSriastradh			return false;
15803b705cfSriastradh		if (damage->extents.y2 < height || damage->extents.y1 > 0)
15903b705cfSriastradh			return false;
16003b705cfSriastradh		damage = _sna_damage_is_all(damage, width, height);
16103b705cfSriastradh		if (damage->mode == DAMAGE_ALL) {
16203b705cfSriastradh			*_damage = DAMAGE_MARK_ALL(damage);
16303b705cfSriastradh			return true;
16403b705cfSriastradh		} else {
16503b705cfSriastradh			*_damage = damage;
16603b705cfSriastradh			return false;
16703b705cfSriastradh		}
16803b705cfSriastradh	}
16903b705cfSriastradh}
17003b705cfSriastradh
17103b705cfSriastradhfastcall struct sna_damage *_sna_damage_subtract(struct sna_damage *damage,
17203b705cfSriastradh						 RegionPtr region);
17303b705cfSriastradhstatic inline void sna_damage_subtract(struct sna_damage **damage,
17403b705cfSriastradh				       RegionPtr region)
17503b705cfSriastradh{
17603b705cfSriastradh	*damage = _sna_damage_subtract(DAMAGE_PTR(*damage), region);
17703b705cfSriastradh	assert(*damage == NULL || (*damage)->mode != DAMAGE_ALL);
17803b705cfSriastradh}
17903b705cfSriastradh
18003b705cfSriastradhfastcall struct sna_damage *_sna_damage_subtract_box(struct sna_damage *damage,
18103b705cfSriastradh						     const BoxRec *box);
18203b705cfSriastradhstatic inline void sna_damage_subtract_box(struct sna_damage **damage,
18303b705cfSriastradh					   const BoxRec *box)
18403b705cfSriastradh{
18503b705cfSriastradh	*damage = _sna_damage_subtract_box(DAMAGE_PTR(*damage), box);
18603b705cfSriastradh	assert(*damage == NULL || (*damage)->mode != DAMAGE_ALL);
18703b705cfSriastradh}
18803b705cfSriastradh
18903b705cfSriastradhfastcall struct sna_damage *_sna_damage_subtract_boxes(struct sna_damage *damage,
19003b705cfSriastradh						       const BoxRec *box, int n,
19103b705cfSriastradh						       int dx, int dy);
19203b705cfSriastradhstatic inline void sna_damage_subtract_boxes(struct sna_damage **damage,
19303b705cfSriastradh					     const BoxRec *box, int n,
19403b705cfSriastradh					     int dx, int dy)
19503b705cfSriastradh{
19603b705cfSriastradh	*damage = _sna_damage_subtract_boxes(DAMAGE_PTR(*damage),
19703b705cfSriastradh					     box, n, dx, dy);
19803b705cfSriastradh	assert(*damage == NULL || (*damage)->mode != DAMAGE_ALL);
19903b705cfSriastradh}
20003b705cfSriastradh
20103b705cfSriastradhbool _sna_damage_intersect(struct sna_damage *damage,
20203b705cfSriastradh			  RegionPtr region, RegionPtr result);
20303b705cfSriastradh
20403b705cfSriastradhstatic inline bool sna_damage_intersect(struct sna_damage *damage,
20503b705cfSriastradh					RegionPtr region, RegionPtr result)
20603b705cfSriastradh{
20703b705cfSriastradh	assert(damage);
20803b705cfSriastradh	assert(RegionNotEmpty(region));
20903b705cfSriastradh	assert(!DAMAGE_IS_ALL(damage));
21003b705cfSriastradh
21103b705cfSriastradh	return _sna_damage_intersect(damage, region, result);
21203b705cfSriastradh}
21303b705cfSriastradh
21403b705cfSriastradhstatic inline bool
21503b705cfSriastradhsna_damage_overlaps_box(const struct sna_damage *damage,
21603b705cfSriastradh			const BoxRec *box)
21703b705cfSriastradh{
21803b705cfSriastradh	if (box->x2 <= damage->extents.x1 ||
21903b705cfSriastradh	    box->x1 >= damage->extents.x2)
22003b705cfSriastradh		return false;
22103b705cfSriastradh
22203b705cfSriastradh	if (box->y2 <= damage->extents.y1 ||
22303b705cfSriastradh	    box->y1 >= damage->extents.y2)
22403b705cfSriastradh		return false;
22503b705cfSriastradh
22603b705cfSriastradh	return true;
22703b705cfSriastradh}
22803b705cfSriastradh
22942542f5fSchristosint _sna_damage_contains_box(struct sna_damage **damage,
23003b705cfSriastradh			     const BoxRec *box);
23142542f5fSchristosstatic inline int sna_damage_contains_box(struct sna_damage **damage,
23203b705cfSriastradh					  const BoxRec *box)
23303b705cfSriastradh{
23442542f5fSchristos	if (DAMAGE_IS_ALL(*damage))
23503b705cfSriastradh		return PIXMAN_REGION_IN;
23642542f5fSchristos	if (*damage == NULL)
23742542f5fSchristos		return PIXMAN_REGION_OUT;
23803b705cfSriastradh
23903b705cfSriastradh	return _sna_damage_contains_box(damage, box);
24003b705cfSriastradh}
24142542f5fSchristosstatic inline int sna_damage_contains_box__offset(struct sna_damage **damage,
24242542f5fSchristos						  const BoxRec *box, int dx, int dy)
24342542f5fSchristos{
24442542f5fSchristos	BoxRec b;
24542542f5fSchristos
24642542f5fSchristos	if (DAMAGE_IS_ALL(*damage))
24742542f5fSchristos		return PIXMAN_REGION_IN;
24842542f5fSchristos	if (*damage == NULL)
24942542f5fSchristos		return PIXMAN_REGION_OUT;
25042542f5fSchristos
25142542f5fSchristos	b = *box;
25242542f5fSchristos	b.x1 += dx; b.x2 += dx;
25342542f5fSchristos	b.y1 += dy; b.y2 += dy;
25442542f5fSchristos	return _sna_damage_contains_box(damage, &b);
25542542f5fSchristos}
25603b705cfSriastradhbool _sna_damage_contains_box__no_reduce(const struct sna_damage *damage,
25703b705cfSriastradh					const BoxRec *box);
25803b705cfSriastradhstatic inline bool
25903b705cfSriastradhsna_damage_contains_box__no_reduce(const struct sna_damage *damage,
26003b705cfSriastradh				   const BoxRec *box)
26103b705cfSriastradh{
26203b705cfSriastradh	assert(!DAMAGE_IS_ALL(damage));
26303b705cfSriastradh	return _sna_damage_contains_box__no_reduce(damage, box);
26403b705cfSriastradh}
26503b705cfSriastradh
26642542f5fSchristosint _sna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes);
26703b705cfSriastradhstatic inline int
26842542f5fSchristossna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes)
26903b705cfSriastradh{
270fe8aea9eSmrg	assert(DAMAGE_PTR(damage));
27103b705cfSriastradh
27203b705cfSriastradh	if (DAMAGE_IS_ALL(damage)) {
27303b705cfSriastradh		*boxes = &DAMAGE_PTR(damage)->extents;
27403b705cfSriastradh		return 1;
27503b705cfSriastradh	} else
27603b705cfSriastradh		return _sna_damage_get_boxes(damage, boxes);
27703b705cfSriastradh}
27803b705cfSriastradh
27903b705cfSriastradhstruct sna_damage *_sna_damage_reduce(struct sna_damage *damage);
28003b705cfSriastradhstatic inline void sna_damage_reduce(struct sna_damage **damage)
28103b705cfSriastradh{
28203b705cfSriastradh	if (*damage == NULL)
28303b705cfSriastradh		return;
28403b705cfSriastradh
28503b705cfSriastradh	if (!DAMAGE_IS_ALL(*damage) && (*damage)->dirty)
28603b705cfSriastradh		*damage = _sna_damage_reduce(*damage);
28703b705cfSriastradh}
28803b705cfSriastradh
28903b705cfSriastradhstatic inline void sna_damage_reduce_all(struct sna_damage **_damage,
29042542f5fSchristos					 PixmapPtr pixmap)
29103b705cfSriastradh{
29203b705cfSriastradh	struct sna_damage *damage = *_damage;
29303b705cfSriastradh
29403b705cfSriastradh	if (damage == NULL || DAMAGE_IS_ALL(damage))
29503b705cfSriastradh		return;
29603b705cfSriastradh
29742542f5fSchristos	DBG(("%s(width=%d, height=%d)\n", __FUNCTION__, pixmap->drawable.width, pixmap->drawable.height));
29842542f5fSchristos
29903b705cfSriastradh	if (damage->mode == DAMAGE_ADD) {
30003b705cfSriastradh		if (damage->extents.x1 <= 0 &&
30103b705cfSriastradh		    damage->extents.y1 <= 0 &&
30242542f5fSchristos		    damage->extents.x2 >= pixmap->drawable.width &&
30342542f5fSchristos		    damage->extents.y2 >= pixmap->drawable.height) {
30403b705cfSriastradh			if (damage->dirty) {
30503b705cfSriastradh				damage = *_damage = _sna_damage_reduce(damage);
30603b705cfSriastradh				if (damage == NULL)
30703b705cfSriastradh					return;
30803b705cfSriastradh			}
30903b705cfSriastradh
31003b705cfSriastradh			if (damage->region.data == NULL)
31142542f5fSchristos				*_damage = _sna_damage_all(damage,
31242542f5fSchristos							   pixmap->drawable.width,
31342542f5fSchristos							   pixmap->drawable.height);
31403b705cfSriastradh		}
31503b705cfSriastradh	} else
31603b705cfSriastradh		*_damage = _sna_damage_reduce(damage);
31703b705cfSriastradh}
31803b705cfSriastradh
31903b705cfSriastradhvoid __sna_damage_destroy(struct sna_damage *damage);
32003b705cfSriastradhstatic inline void sna_damage_destroy(struct sna_damage **damage)
32103b705cfSriastradh{
32203b705cfSriastradh	if (*damage == NULL)
32303b705cfSriastradh		return;
32403b705cfSriastradh
325fe8aea9eSmrg	if (DAMAGE_PTR(*damage))
326fe8aea9eSmrg		__sna_damage_destroy(DAMAGE_PTR(*damage));
32703b705cfSriastradh	*damage = NULL;
32803b705cfSriastradh}
32903b705cfSriastradh
33003b705cfSriastradhvoid _sna_damage_debug_get_region(struct sna_damage *damage, RegionRec *r);
33103b705cfSriastradh
33203b705cfSriastradh#if HAS_DEBUG_FULL && TEST_DAMAGE
33303b705cfSriastradhvoid sna_damage_selftest(void);
33403b705cfSriastradh#else
33503b705cfSriastradhstatic inline void sna_damage_selftest(void) {}
33603b705cfSriastradh#endif
33703b705cfSriastradh
33803b705cfSriastradh#endif /* SNA_DAMAGE_H */
339