diff --git a/gsk/gskrectprivate.h b/gsk/gskrectprivate.h index 20ae3f2fd8..413b202143 100644 --- a/gsk/gskrectprivate.h +++ b/gsk/gskrectprivate.h @@ -85,6 +85,81 @@ gsk_rect_intersection (const graphene_rect_t *r1, } } +/** + * gsk_rect_coverage: + * @r1: a valid rectangle + * @r2: another valid rectangle + * @res: The result, may be one of r1/r2 + * + * Computes the largest rectangle that is fully covered by + * r1 and r2. + * + * Note that this is different from a union, which is the smallest + * rectangle that covers the rectangles. + * + * The use case for this function is joining opaque rectangles. + **/ +static inline void +gsk_rect_coverage (const graphene_rect_t *r1, + const graphene_rect_t *r2, + graphene_rect_t *res) +{ + float x1min, y1min, x2min, y2min; + float x1max, y1max, x2max, y2max; + float size, size2; + graphene_rect_t r; + + /* Assumes both rects are already normalized, as they usually are */ + size = r1->size.width * r1->size.height; + size2 = r2->size.width * r2->size.height; + if (size >= size2) + { + r = *r1; + } + else + { + r = *r2; + size = size2; + } + + x1min = MIN (r1->origin.x, r2->origin.x); + y1min = MIN (r1->origin.y, r2->origin.y); + x1max = MAX (r1->origin.x, r2->origin.x); + y1max = MAX (r1->origin.y, r2->origin.y); + x2min = MIN (r1->origin.x + r1->size.width, r2->origin.x + r2->size.width); + y2min = MIN (r1->origin.y + r1->size.height, r2->origin.y + r2->size.height); + x2max = MAX (r1->origin.x + r1->size.width, r2->origin.x + r2->size.width); + y2max = MAX (r1->origin.y + r1->size.height, r2->origin.y + r2->size.height); + + if (x2min >= x1max) + { + float w, h; + w = x2min - x1max; + h = y2max - y1min; + size2 = w * h; + if (size2 > size) + { + r = GRAPHENE_RECT_INIT (x1max, y1min, w, h); + size = size2; + } + } + + if (y2min >= y1max) + { + float w, h; + w = x2max - x1min; + h = y2min - y1max; + size2 = w * h; + if (size2 > size) + { + r = GRAPHENE_RECT_INIT (x1min, y1max, w, h); + size = size2; + } + } + + *res = r; +} + static inline gboolean G_GNUC_PURE gsk_rect_is_empty (const graphene_rect_t *rect) { diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index 00ed97db35..919e73cffc 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -3315,7 +3315,6 @@ gsk_container_node_get_opaque_rect (GskRenderNode *node, { GskContainerNode *self = (GskContainerNode *) node; graphene_rect_t child_opaque; - double size, child_size, desired_size; guint i; for (i = 0; i < self->n_children; i++) @@ -3327,28 +3326,12 @@ gsk_container_node_get_opaque_rect (GskRenderNode *node, if (i == self->n_children) return FALSE; - size = opaque->size.width * opaque->size.height; - /* the 80% is random. I just want it to be low enough to catch - * rounded corners, but not so small it catches on to .view - * backgrounds for the smaller child of a paned. - */ - desired_size = node->bounds.size.width * node->bounds.size.height * 0.8; - for (i++; i < self->n_children; i++) { - if (size >= desired_size) - break; - if (!gsk_render_node_get_opaque_rect (self->children[i], &child_opaque)) continue; - child_size = child_opaque.size.width * child_opaque.size.height; - /* We allow == here because we want to find the topmost opaque child */ - if (child_size < size) - continue; - - *opaque = child_opaque; - size = child_size; + gsk_rect_coverage (opaque, &child_opaque, opaque); } return TRUE; diff --git a/testsuite/gsk/opaque/grid-0-0-100-100.node b/testsuite/gsk/opaque/grid-0-0-100-100.node new file mode 100644 index 0000000000..3f59742883 --- /dev/null +++ b/testsuite/gsk/opaque/grid-0-0-100-100.node @@ -0,0 +1,26 @@ +/* the covered node */ +color { + bounds: 30 30 40 40; + color: black; +} + +container { + color { + bounds: 0 0 50 50; + color: lime; + } + color { + bounds: 50 0 50 50; + color: red; + } +} +container { + color { + bounds: 0 50 50 50; + color: blue; + } + color { + bounds: 50 50 50 50; + color: yellow; + } +} diff --git a/testsuite/gsk/opaque/horizontal-merge-0-0-100-50.node b/testsuite/gsk/opaque/horizontal-merge-0-0-100-50.node new file mode 100644 index 0000000000..94da8e9eb3 --- /dev/null +++ b/testsuite/gsk/opaque/horizontal-merge-0-0-100-50.node @@ -0,0 +1,12 @@ +color { + bounds: 0 0 25 50; +} +color { + bounds: 25 0 25 50; +} +color { + bounds: 50 0 25 50; +} +color { + bounds: 75 0 25 50; +} diff --git a/testsuite/gsk/opaque/horizontal-merge-backwards-0-0-100-50.node b/testsuite/gsk/opaque/horizontal-merge-backwards-0-0-100-50.node new file mode 100644 index 0000000000..efb583be83 --- /dev/null +++ b/testsuite/gsk/opaque/horizontal-merge-backwards-0-0-100-50.node @@ -0,0 +1,12 @@ +color { + bounds: 75 0 25 50; +} +color { + bounds: 50 0 25 50; +} +color { + bounds: 25 0 25 50; +} +color { + bounds: 0 0 25 50; +} diff --git a/testsuite/gsk/opaque/horizontal-merge-backwards-overlap-0-0-125-50.node b/testsuite/gsk/opaque/horizontal-merge-backwards-overlap-0-0-125-50.node new file mode 100644 index 0000000000..2a3eb53477 --- /dev/null +++ b/testsuite/gsk/opaque/horizontal-merge-backwards-overlap-0-0-125-50.node @@ -0,0 +1,12 @@ +color { + bounds: 75 0 50 50; +} +color { + bounds: 50 0 50 50; +} +color { + bounds: 25 0 50 50; +} +color { + bounds: 0 0 50 50; +} diff --git a/testsuite/gsk/opaque/horizontal-merge-overlap-0-0-125-50.node b/testsuite/gsk/opaque/horizontal-merge-overlap-0-0-125-50.node new file mode 100644 index 0000000000..ab15c805b8 --- /dev/null +++ b/testsuite/gsk/opaque/horizontal-merge-overlap-0-0-125-50.node @@ -0,0 +1,12 @@ +color { + bounds: 0 0 50 50; +} +color { + bounds: 25 0 50 50; +} +color { + bounds: 50 0 50 50; +} +color { + bounds: 75 0 50 50; +} diff --git a/testsuite/gsk/opaque/horizontal-overlap-0-10-90-40.node b/testsuite/gsk/opaque/horizontal-overlap-0-10-90-40.node new file mode 100644 index 0000000000..5c5eea035c --- /dev/null +++ b/testsuite/gsk/opaque/horizontal-overlap-0-10-90-40.node @@ -0,0 +1,8 @@ +color { + bounds: 0 0 50 50; + color: lime; +} +color { + bounds: 40 10 50 50; + color: red; +} diff --git a/testsuite/gsk/opaque/vertical-merge-0-0-50-100.node b/testsuite/gsk/opaque/vertical-merge-0-0-50-100.node new file mode 100644 index 0000000000..5edbfe0b00 --- /dev/null +++ b/testsuite/gsk/opaque/vertical-merge-0-0-50-100.node @@ -0,0 +1,12 @@ +color { + bounds: 0 0 50 25; +} +color { + bounds: 0 25 50 25; +} +color { + bounds: 0 50 50 25; +} +color { + bounds: 0 75 50 25; +} diff --git a/testsuite/gsk/opaque/vertical-merge-backwards-0-0-50-100.node b/testsuite/gsk/opaque/vertical-merge-backwards-0-0-50-100.node new file mode 100644 index 0000000000..e2b0d43274 --- /dev/null +++ b/testsuite/gsk/opaque/vertical-merge-backwards-0-0-50-100.node @@ -0,0 +1,12 @@ +color { + bounds: 0 75 50 25; +} +color { + bounds: 0 50 50 25; +} +color { + bounds: 0 25 50 25; +} +color { + bounds: 0 0 50 25; +} diff --git a/testsuite/gsk/opaque/vertical-merge-overlap-0-0-50-125.node b/testsuite/gsk/opaque/vertical-merge-overlap-0-0-50-125.node new file mode 100644 index 0000000000..be92b716ff --- /dev/null +++ b/testsuite/gsk/opaque/vertical-merge-overlap-0-0-50-125.node @@ -0,0 +1,12 @@ +color { + bounds: 0 0 50 50; +} +color { + bounds: 0 25 50 50; +} +color { + bounds: 0 50 50 50; +} +color { + bounds: 0 75 50 50; +} diff --git a/testsuite/gsk/opaque/vertical-overlap-10-0-40-90.node b/testsuite/gsk/opaque/vertical-overlap-10-0-40-90.node new file mode 100644 index 0000000000..4b89c77271 --- /dev/null +++ b/testsuite/gsk/opaque/vertical-overlap-10-0-40-90.node @@ -0,0 +1,8 @@ +color { + bounds: 0 0 50 50; + color: lime; +} +color { + bounds: 10 40 50 50; + color: red; +}