diff --git a/gsk/gskroundedrect.c b/gsk/gskroundedrect.c index 76efe4d9ae..7c1a9cc6ec 100644 --- a/gsk/gskroundedrect.c +++ b/gsk/gskroundedrect.c @@ -945,3 +945,44 @@ gsk_rounded_rect_to_string (const GskRoundedRect *self) self->corner[3].width, self->corner[3].height); } + +/* + * gsk_rounded_rect_get_largest_cover: + * @self: the rounded rect to intersect with + * @rect: the rectangle to intersect + * @result: (out caller-allocates): The resulting rectangle + * + * Computes the largest rectangle that is fully covered by both + * the given rect and the rounded rect. + * In particular, this function respects corners, so + * gsk_rounded_rect_get_largest_cover(self, &self->bounds, &rect) + * can be used to compute a decomposition for a rounded rect itself. + **/ +void +gsk_rounded_rect_get_largest_cover (const GskRoundedRect *self, + const graphene_rect_t *rect, + graphene_rect_t *result) +{ + graphene_rect_t wide, high; + double start, end; + + wide = self->bounds; + start = MAX(self->corner[GSK_CORNER_TOP_LEFT].height, self->corner[GSK_CORNER_TOP_RIGHT].height); + end = MAX(self->corner[GSK_CORNER_BOTTOM_LEFT].height, self->corner[GSK_CORNER_BOTTOM_RIGHT].height); + wide.size.height -= MIN (wide.size.height, start + end); + wide.origin.y += start; + graphene_rect_intersection (&wide, rect, &wide); + + high = self->bounds; + start = MAX(self->corner[GSK_CORNER_TOP_LEFT].width, self->corner[GSK_CORNER_BOTTOM_LEFT].width); + end = MAX(self->corner[GSK_CORNER_TOP_RIGHT].width, self->corner[GSK_CORNER_BOTTOM_RIGHT].width); + high.size.width -= MIN (high.size.width, start + end); + high.origin.x += start; + graphene_rect_intersection (&high, rect, &high); + + if (wide.size.width * wide.size.height > high.size.width * high.size.height) + *result = wide; + else + *result = high; +} + diff --git a/gsk/gskroundedrectprivate.h b/gsk/gskroundedrectprivate.h index 64c3469df9..964e0edf84 100644 --- a/gsk/gskroundedrectprivate.h +++ b/gsk/gskroundedrectprivate.h @@ -53,6 +53,10 @@ gboolean gsk_rounded_rect_equal (gconstpointer gconstpointer rect2) G_GNUC_PURE; char * gsk_rounded_rect_to_string (const GskRoundedRect *self) G_GNUC_MALLOC; +void gsk_rounded_rect_get_largest_cover (const GskRoundedRect *self, + const graphene_rect_t *rect, + graphene_rect_t *result); + typedef enum { GSK_INTERSECTION_EMPTY, GSK_INTERSECTION_NONEMPTY, diff --git a/gsk/vulkan/gskvulkanrenderpass.c b/gsk/vulkan/gskvulkanrenderpass.c index 4d331ddfc1..51d849c1c6 100644 --- a/gsk/vulkan/gskvulkanrenderpass.c +++ b/gsk/vulkan/gskvulkanrenderpass.c @@ -368,21 +368,70 @@ gsk_vulkan_render_pass_add_color_node (GskVulkanRenderPass *self, return TRUE; /* we have handled the bounds, now do the corners */ - if (state->clip.type != GSK_VULKAN_CLIP_ROUNDED || - gsk_vulkan_clip_contains_rect (&state->clip, - graphene_point_zero (), - &GRAPHENE_RECT_INIT ( - int_clipped.x / graphene_vec2_get_x (&state->scale), - int_clipped.y / graphene_vec2_get_y (&state->scale), - int_clipped.width / graphene_vec2_get_x (&state->scale), - int_clipped.height / graphene_vec2_get_y (&state->scale) - ))) + if (state->clip.type == GSK_VULKAN_CLIP_ROUNDED) { - gsk_vulkan_clear_op (render, - &int_clipped, - color); - return TRUE; + graphene_rect_t cover; + const char *clip_type; + float scale_x = graphene_vec2_get_x (&state->scale); + float scale_y = graphene_vec2_get_y (&state->scale); + clipped = GRAPHENE_RECT_INIT (int_clipped.x / scale_x, int_clipped.y / scale_y, + int_clipped.width / scale_x, int_clipped.height / scale_y); + clip_type = gsk_vulkan_clip_get_clip_type (&state->clip, graphene_point_zero(), &clipped); + if (clip_type[0] != '\0') + { + gsk_rounded_rect_get_largest_cover (&state->clip.rect, &clipped, &cover); + int_clipped.x = ceil (cover.origin.x * scale_x); + int_clipped.y = ceil (cover.origin.y * scale_y); + int_clipped.width = floor ((cover.origin.x + cover.size.width) * scale_x) - int_clipped.x; + int_clipped.height = floor ((cover.origin.y + cover.size.height) * scale_y) - int_clipped.y; + if (int_clipped.width == 0 || int_clipped.height == 0) + { + gsk_vulkan_color_op (render, + clip_type, + &clipped, + graphene_point_zero (), + color); + return TRUE; + } + cover = GRAPHENE_RECT_INIT (int_clipped.x / scale_x, int_clipped.y / scale_y, + int_clipped.width / scale_x, int_clipped.height / scale_y); + if (clipped.origin.x != cover.origin.x) + gsk_vulkan_color_op (render, + clip_type, + &GRAPHENE_RECT_INIT (clipped.origin.x, clipped.origin.y, cover.origin.x - clipped.origin.x, clipped.size.height), + graphene_point_zero (), + color); + if (clipped.origin.y != cover.origin.y) + gsk_vulkan_color_op (render, + clip_type, + &GRAPHENE_RECT_INIT (clipped.origin.x, clipped.origin.y, clipped.size.width, cover.origin.y - clipped.origin.y), + graphene_point_zero (), + color); + if (clipped.origin.x + clipped.size.width != cover.origin.x + cover.size.width) + gsk_vulkan_color_op (render, + clip_type, + &GRAPHENE_RECT_INIT (cover.origin.x + cover.size.width, + clipped.origin.y, + clipped.origin.x + clipped.size.width - cover.origin.x - cover.size.width, + clipped.size.height), + graphene_point_zero (), + color); + if (clipped.origin.y + clipped.size.height != cover.origin.y + cover.size.height) + gsk_vulkan_color_op (render, + clip_type, + &GRAPHENE_RECT_INIT (clipped.origin.x, + cover.origin.y + cover.size.height, + clipped.size.width, + clipped.origin.y + clipped.size.height - cover.origin.y - cover.size.height), + graphene_point_zero (), + color); + } } + + gsk_vulkan_clear_op (render, + &int_clipped, + color); + return TRUE; } gsk_vulkan_color_op (render,