From 10b161d77d187f054fa58993e95ac27641b034d3 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 22 Nov 2020 10:32:00 -0500 Subject: [PATCH] Implement line caps and joins This is just passing things through to cairo, for the most part. --- gsk/gskenums.h | 14 ++++ gsk/gskrendernodeimpl.c | 2 + gsk/gskrendernodeparser.c | 148 +++++++++++++++++++++++++++++++++++++- gsk/gskstroke.c | 25 +++++++ gsk/gskstroke.h | 14 ++++ gsk/gskstrokeprivate.h | 2 + gtk/inspector/recorder.c | 28 ++++++-- 7 files changed, 226 insertions(+), 7 deletions(-) diff --git a/gsk/gskenums.h b/gsk/gskenums.h index 44e8854874..db77f48381 100644 --- a/gsk/gskenums.h +++ b/gsk/gskenums.h @@ -300,4 +300,18 @@ typedef enum } GskGLUniformType; +typedef enum +{ + GSK_LINE_CAP_BUTT, + GSK_LINE_CAP_ROUND, + GSK_LINE_CAP_SQUARE +} GskLineCap; + +typedef enum +{ + GSK_LINE_JOIN_MITER, + GSK_LINE_JOIN_ROUND, + GSK_LINE_JOIN_BEVEL +} GskLineJoin; + #endif /* __GSK_TYPES_H__ */ diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index 0fae26f198..5274296f40 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -3464,6 +3464,8 @@ gsk_stroke_node_draw (GskRenderNode *node, cairo_pop_group_to_source (cr); cairo_set_line_width (cr, self->stroke.line_width); + cairo_set_line_cap (cr, (cairo_line_cap_t)self->stroke.line_cap); + cairo_set_line_join (cr, (cairo_line_join_t)self->stroke.line_join); gsk_path_to_cairo (self->path, cr); cairo_stroke (cr); diff --git a/gsk/gskrendernodeparser.c b/gsk/gskrendernodeparser.c index 804976d2a5..613b503bcc 100644 --- a/gsk/gskrendernodeparser.c +++ b/gsk/gskrendernodeparser.c @@ -28,6 +28,7 @@ #include "gskrendernodeprivate.h" #include "gskstroke.h" #include "gsktransformprivate.h" +#include "gskenumtypes.h" #include "gdk/gdkrgbaprivate.h" #include "gdk/gdktextureprivate.h" @@ -1727,6 +1728,118 @@ parse_rounded_clip_node (GtkCssParser *parser) return result; } +static gboolean +parse_path (GtkCssParser *parser, + gpointer out_path) +{ + return FALSE; +} + +static gboolean +parse_enum (GtkCssParser *parser, + GType type, + gpointer out_value) +{ + GEnumClass *class; + GEnumValue *v; + const GtkCssToken *token; + + token = gtk_css_parser_get_token (parser); + if (!gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT)) + return FALSE; + + class = g_type_class_ref (type); + + v = g_enum_get_value_by_nick (class, token->string.string); + *(int*)out_value = v->value; + + g_type_class_unref (class); + + gtk_css_parser_consume_token (parser); + + return TRUE; +} + +static gboolean +parse_fill_rule (GtkCssParser *parser, + gpointer out_rule) +{ + return parse_enum (parser, GSK_TYPE_FILL_RULE, out_rule); +} + +static gboolean +parse_line_cap (GtkCssParser *parser, + gpointer out) +{ + return parse_enum (parser, GSK_TYPE_LINE_CAP, out); +} + +static gboolean +parse_line_join (GtkCssParser *parser, + gpointer out) +{ + return parse_enum (parser, GSK_TYPE_LINE_JOIN, out); +} + +static GskRenderNode * +parse_fill_node (GtkCssParser *parser) +{ + GskRenderNode *child = NULL; + GskPath *path = NULL; + GskFillRule rule = GSK_FILL_RULE_WINDING; + const Declaration declarations[] = { + { "child", parse_node, clear_node, &child }, + { "path", parse_path, NULL, &path }, + { "fill-rule", parse_fill_rule, NULL, &rule }, + }; + GskRenderNode *result; + + parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + if (child == NULL) + child = create_default_render_node (); + + result = gsk_fill_node_new (child, path, rule); + + gsk_render_node_unref (child); + + return result; +} + +static GskRenderNode * +parse_stroke_node (GtkCssParser *parser) +{ + GskRenderNode *child = NULL; + GskPath *path = NULL; + double line_width = 1.0; + double line_cap = GSK_LINE_CAP_BUTT; + double line_join = GSK_LINE_JOIN_MITER; + GskStroke *stroke; + + const Declaration declarations[] = { + { "child", parse_node, clear_node, &child }, + { "path", parse_path, NULL, &path }, + { "line-width", parse_double, NULL, &line_width }, + { "line-cap", parse_line_cap, NULL, &line_cap }, + { "line-join", parse_line_join, NULL, &line_join }, + }; + GskRenderNode *result; + + parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + if (child == NULL) + child = create_default_render_node (); + + stroke = gsk_stroke_new (line_width); + gsk_stroke_set_line_cap (stroke, line_cap); + gsk_stroke_set_line_join (stroke, line_join); + + result = gsk_stroke_node_new (child, path, stroke); + + gsk_stroke_free (stroke); + gsk_render_node_unref (child); + + return result; +} + static GskRenderNode * parse_shadow_node (GtkCssParser *parser) { @@ -1805,6 +1918,8 @@ parse_node (GtkCssParser *parser, { "repeating-linear-gradient", parse_repeating_linear_gradient_node }, { "repeating-radial-gradient", parse_repeating_radial_gradient_node }, { "rounded-clip", parse_rounded_clip_node }, + { "fill", parse_fill_node }, + { "stroke", parse_stroke_node }, { "shadow", parse_shadow_node }, { "text", parse_text_node }, { "texture", parse_texture_node }, @@ -2247,6 +2362,33 @@ base64_encode_with_linebreaks (const guchar *data, return out; } +static const char * +enum_to_nick (GType type, + int value) +{ + GEnumClass *class; + GEnumValue *v; + + class = g_type_class_ref (type); + v = g_enum_get_value (class, value); + g_type_class_unref (class); + + return v->value_nick; +} + +static void +append_enum_param (Printer *p, + const char *param_name, + GType type, + int value) +{ + _indent (p); + g_string_append_printf (p->str, "%s: ", param_name); + g_string_append (p->str, enum_to_nick (type, value)); + g_string_append_c (p->str, ';'); + g_string_append_c (p->str, '\n'); +} + static void render_node_print (Printer *p, GskRenderNode *node) @@ -2423,6 +2565,7 @@ render_node_print (Printer *p, path_str = gsk_path_to_string (gsk_fill_node_get_path (node)); append_string_param (p, "path", path_str); g_free (path_str); + append_enum_param (p, "fill-rule", GSK_TYPE_FILL_RULE, gsk_fill_node_get_fill_rule (node)); end_node (p); } @@ -2430,8 +2573,8 @@ render_node_print (Printer *p, case GSK_STROKE_NODE: { - const GskStroke *stroke; char *path_str; + const GskStroke *stroke; start_node (p, "stroke"); @@ -2443,6 +2586,9 @@ render_node_print (Printer *p, stroke = gsk_stroke_node_get_stroke (node); append_float_param (p, "line-width", gsk_stroke_get_line_width (stroke), 0.0); + append_enum_param (p, "line-cap", GSK_TYPE_LINE_CAP, gsk_stroke_get_line_cap (stroke)); + append_enum_param (p, "line-join", GSK_TYPE_LINE_JOIN, gsk_stroke_get_line_join (stroke)); + end_node (p); } break; diff --git a/gsk/gskstroke.c b/gsk/gskstroke.c index 755c9cdfe8..af1e793401 100644 --- a/gsk/gskstroke.c +++ b/gsk/gskstroke.c @@ -109,3 +109,28 @@ gsk_stroke_get_line_width (const GskStroke *self) return self->line_width; } +void +gsk_stroke_set_line_cap (GskStroke *self, + GskLineCap line_cap) +{ + self->line_cap = line_cap; +} + +GskLineCap +gsk_stroke_get_line_cap (const GskStroke *self) +{ + return self->line_cap; +} + +void +gsk_stroke_set_line_join (GskStroke *self, + GskLineJoin line_join) +{ + self->line_join = line_join; +} + +GskLineJoin +gsk_stroke_get_line_join (const GskStroke *self) +{ + return self->line_join; +} diff --git a/gsk/gskstroke.h b/gsk/gskstroke.h index 3650325606..d9d1404ec6 100644 --- a/gsk/gskstroke.h +++ b/gsk/gskstroke.h @@ -26,6 +26,7 @@ #include +#include G_BEGIN_DECLS @@ -50,6 +51,19 @@ void gsk_stroke_set_line_width (GskStroke GDK_AVAILABLE_IN_ALL float gsk_stroke_get_line_width (const GskStroke *self); +GDK_AVAILABLE_IN_ALL +void gsk_stroke_set_line_cap (GskStroke *self, + GskLineCap line_cap); + +GDK_AVAILABLE_IN_ALL +GskLineCap gsk_stroke_get_line_cap (const GskStroke *self); + +GDK_AVAILABLE_IN_ALL +void gsk_stroke_set_line_join (GskStroke *self, + GskLineJoin line_join); + +GDK_AVAILABLE_IN_ALL +GskLineJoin gsk_stroke_get_line_join (const GskStroke *self); G_END_DECLS diff --git a/gsk/gskstrokeprivate.h b/gsk/gskstrokeprivate.h index aa77b88b12..f3754997d8 100644 --- a/gsk/gskstrokeprivate.h +++ b/gsk/gskstrokeprivate.h @@ -28,6 +28,8 @@ G_BEGIN_DECLS struct _GskStroke { float line_width; + GskLineCap line_cap; + GskLineJoin line_join; }; static inline void diff --git a/gtk/inspector/recorder.c b/gtk/inspector/recorder.c index 4bf094a38c..267ad0de57 100644 --- a/gtk/inspector/recorder.c +++ b/gtk/inspector/recorder.c @@ -583,6 +583,20 @@ add_float_row (GtkListStore *store, g_free (text); } +static const char * +enum_to_nick (GType type, + int value) +{ + GEnumClass *class; + GEnumValue *v; + + class = g_type_class_ref (type); + v = g_enum_get_value (class, value); + g_type_class_unref (class); + + return v->value_nick; +} + static void populate_render_node_properties (GtkListStore *store, GskRenderNode *node) @@ -811,9 +825,7 @@ populate_render_node_properties (GtkListStore *store, case GSK_BLEND_NODE: { GskBlendMode mode = gsk_blend_node_get_blend_mode (node); - tmp = g_enum_to_string (GSK_TYPE_BLEND_MODE, mode); - add_text_row (store, "Blendmode", tmp); - g_free (tmp); + add_text_row (store, "Blendmode", enum_to_nick (GSK_TYPE_BLEND_MODE, mode)); } break; @@ -1049,14 +1061,13 @@ populate_render_node_properties (GtkListStore *store, case GSK_FILL_NODE: { GskPath *path = gsk_fill_node_get_path (node); + GskFillRule fill_rule = gsk_fill_node_get_fill_rule (node); tmp = gsk_path_to_string (path); add_text_row (store, "Path", tmp); g_free (tmp); - tmp = g_enum_to_string (GSK_TYPE_FILL_RULE, gsk_fill_node_get_fill_rule (node)); - add_text_row (store, "Fill rule", tmp); - g_free (tmp); + add_text_row (store, "Fill rule", enum_to_nick (GSK_TYPE_FILL_RULE, fill_rule)); } break; @@ -1064,6 +1075,8 @@ populate_render_node_properties (GtkListStore *store, { GskPath *path = gsk_stroke_node_get_path (node); const GskStroke *stroke = gsk_stroke_node_get_stroke (node); + GskLineCap line_cap = gsk_stroke_get_line_cap (stroke); + GskLineJoin line_join = gsk_stroke_get_line_join (stroke); tmp = gsk_path_to_string (path); add_text_row (store, "Path", tmp); @@ -1072,6 +1085,9 @@ populate_render_node_properties (GtkListStore *store, tmp = g_strdup_printf ("%.2f", gsk_stroke_get_line_width (stroke)); add_text_row (store, "Line width", tmp); g_free (tmp); + + add_text_row (store, "Line cap", enum_to_nick (GSK_TYPE_LINE_CAP, line_cap)); + add_text_row (store, "Line join", enum_to_nick (GSK_TYPE_LINE_JOIN, line_join)); } break;