summaryrefslogtreecommitdiff
path: root/gsk
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2019-04-19 03:37:55 +0200
committerBenjamin Otte <otte@redhat.com>2019-04-19 03:39:57 +0200
commit9b6f822f15e5e75b1900dc65e3527a7f5ae985ff (patch)
treeb53515f5e165449bf374c6abea4864ccbb138a8e /gsk
parent70fb29e81af3bd6cd26805ef6824170f0f6108e4 (diff)
downloadgtk+-9b6f822f15e5e75b1900dc65e3527a7f5ae985ff.tar.gz
rendernode: Fix border rendering
This fixed the reftest introduced in the previous commit. I'm using a mesh gradient here instead of drawing 4 individual sides to avoid artifacts when those sides overlap in rounded corners.
Diffstat (limited to 'gsk')
-rw-r--r--gsk/gskrendernodeimpl.c99
1 files changed, 73 insertions, 26 deletions
diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c
index cbf96179fd..d76c6b6609 100644
--- a/gsk/gskrendernodeimpl.c
+++ b/gsk/gskrendernodeimpl.c
@@ -515,6 +515,30 @@ gsk_border_node_finalize (GskRenderNode *node)
}
static void
+gsk_border_node_mesh_add_patch (cairo_pattern_t *pattern,
+ const GdkRGBA *color,
+ double x0,
+ double y0,
+ double x1,
+ double y1,
+ double x2,
+ double y2,
+ double x3,
+ double y3)
+{
+ cairo_mesh_pattern_begin_patch (pattern);
+ cairo_mesh_pattern_move_to (pattern, x0, y0);
+ cairo_mesh_pattern_line_to (pattern, x1, y1);
+ cairo_mesh_pattern_line_to (pattern, x2, y2);
+ cairo_mesh_pattern_line_to (pattern, x3, y3);
+ cairo_mesh_pattern_set_corner_color_rgba (pattern, 0, color->red, color->green, color->blue, color->alpha);
+ cairo_mesh_pattern_set_corner_color_rgba (pattern, 1, color->red, color->green, color->blue, color->alpha);
+ cairo_mesh_pattern_set_corner_color_rgba (pattern, 2, color->red, color->green, color->blue, color->alpha);
+ cairo_mesh_pattern_set_corner_color_rgba (pattern, 3, color->red, color->green, color->blue, color->alpha);
+ cairo_mesh_pattern_end_patch (pattern);
+}
+
+static void
gsk_border_node_draw (GskRenderNode *node,
cairo_t *cr)
{
@@ -537,59 +561,82 @@ gsk_border_node_draw (GskRenderNode *node,
gdk_rgba_equal (&self->border_color[0], &self->border_color[3]))
{
gdk_cairo_set_source_rgba (cr, &self->border_color[0]);
- cairo_fill (cr);
}
else
{
const graphene_rect_t *bounds = &self->outline.bounds;
+ /* distance to center "line":
+ * +-------------------------+
+ * | |
+ * | |
+ * | ---this-line--- |
+ * | |
+ * | |
+ * +-------------------------+
+ * That line is equidistant from all sides. It's either horiontal
+ * or vertical, depending on if the rect is wider or taller.
+ * We use the 4 sides spanned up by connecting the line to the corner
+ * points to color the regions of the rectangle differently.
+ * Note that the call to cairo_fill() will add the potential final
+ * segment by closing the path, so we don't have to care.
+ */
+ float dst = MIN (bounds->size.width, bounds->size.height) / 2.0;
+ cairo_pattern_t *mesh;
+ cairo_matrix_t mat;
- cairo_clip (cr);
+ mesh = cairo_pattern_create_mesh ();
+ cairo_matrix_init_translate (&mat, -bounds->origin.x, -bounds->origin.y);
+ cairo_pattern_set_matrix (mesh, &mat);
/* Top */
if (self->border_width[0] > 0)
{
- cairo_move_to (cr, bounds->origin.x, bounds->origin.y);
- cairo_rel_line_to (cr, self->border_width[3], self->border_width[0]);
- cairo_rel_line_to (cr, bounds->size.width - self->border_width[3] - self->border_width[1], 0);
- cairo_rel_line_to (cr, self->border_width[1], - self->border_width[0]);
- gdk_cairo_set_source_rgba (cr, &self->border_color[0]);
- cairo_fill (cr);
+ gsk_border_node_mesh_add_patch (mesh,
+ &self->border_color[0],
+ 0, 0,
+ dst * self->border_width[3] / self->border_width[0], dst,
+ bounds->size.width - dst * self->border_width[1] / self->border_width[0], dst,
+ bounds->size.width, 0);
}
/* Right */
if (self->border_width[1] > 0)
{
- cairo_move_to (cr, bounds->origin.x + bounds->size.width, bounds->origin.y);
- cairo_rel_line_to (cr, - self->border_width[1], self->border_width[0]);
- cairo_rel_line_to (cr, 0, bounds->size.height - self->border_width[0] - self->border_width[2]);
- cairo_rel_line_to (cr, self->border_width[1], self->border_width[2]);
- gdk_cairo_set_source_rgba (cr, &self->border_color[1]);
- cairo_fill (cr);
+ gsk_border_node_mesh_add_patch (mesh,
+ &self->border_color[1],
+ bounds->size.width, 0,
+ bounds->size.width - dst, dst * self->border_width[0] / self->border_width[1],
+ bounds->size.width - dst, bounds->size.height - dst * self->border_width[2] / self->border_width[1],
+ bounds->size.width, bounds->size.height);
}
/* Bottom */
if (self->border_width[2] > 0)
{
- cairo_move_to (cr, bounds->origin.x, bounds->origin.y + bounds->size.height);
- cairo_rel_line_to (cr, self->border_width[3], - self->border_width[2]);
- cairo_rel_line_to (cr, bounds->size.width - self->border_width[3] - self->border_width[1], 0);
- cairo_rel_line_to (cr, self->border_width[1], self->border_width[2]);
- gdk_cairo_set_source_rgba (cr, &self->border_color[2]);
- cairo_fill (cr);
+ gsk_border_node_mesh_add_patch (mesh,
+ &self->border_color[2],
+ 0, bounds->size.height,
+ dst * self->border_width[3] / self->border_width[2], bounds->size.height - dst,
+ bounds->size.width - dst * self->border_width[1] / self->border_width[2], bounds->size.height - dst,
+ bounds->size.width, bounds->size.height);
}
/* Left */
if (self->border_width[3] > 0)
{
- cairo_move_to (cr, bounds->origin.x, bounds->origin.y);
- cairo_rel_line_to (cr, self->border_width[3], self->border_width[0]);
- cairo_rel_line_to (cr, 0, bounds->size.height - self->border_width[0] - self->border_width[2]);
- cairo_rel_line_to (cr, - self->border_width[3], self->border_width[2]);
- gdk_cairo_set_source_rgba (cr, &self->border_color[3]);
- cairo_fill (cr);
+ gsk_border_node_mesh_add_patch (mesh,
+ &self->border_color[3],
+ 0, 0,
+ dst, dst * self->border_width[0] / self->border_width[3],
+ dst, bounds->size.height - dst * self->border_width[2] / self->border_width[3],
+ 0, bounds->size.height);
}
+
+ cairo_set_source (cr, mesh);
+ cairo_pattern_destroy (mesh);
}
+ cairo_fill (cr);
cairo_restore (cr);
}