diff options
author | Benjamin Otte <otte@redhat.com> | 2020-11-11 00:44:32 +0100 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2020-12-27 00:31:17 +0100 |
commit | 4eb7d68970fdffb5612c8cf61cb68adfd5e15a39 (patch) | |
tree | 99861188e12412e8d99bb95a3255eedd1593e628 | |
parent | 98337f71157c3fac5e06c6057f3034a476e807c0 (diff) | |
download | gtk+-4eb7d68970fdffb5612c8cf61cb68adfd5e15a39.tar.gz |
gsk: Add GskFillNode
Take a rendernode as source and a GskPath and fill the region in the
path just like cairo_fill() would.
-rw-r--r-- | docs/reference/gsk/gsk4-sections.txt | 8 | ||||
-rw-r--r-- | gsk/broadway/gskbroadwayrenderer.c | 2 | ||||
-rw-r--r-- | gsk/gl/gskglrenderer.c | 1 | ||||
-rw-r--r-- | gsk/gskenums.h | 29 | ||||
-rw-r--r-- | gsk/gskrendernode.h | 15 | ||||
-rw-r--r-- | gsk/gskrendernodeimpl.c | 190 | ||||
-rw-r--r-- | gsk/gskrendernodeparser.c | 15 | ||||
-rw-r--r-- | gsk/vulkan/gskvulkanrenderpass.c | 1 | ||||
-rw-r--r-- | gtk/inspector/recorder.c | 16 |
9 files changed, 277 insertions, 0 deletions
diff --git a/docs/reference/gsk/gsk4-sections.txt b/docs/reference/gsk/gsk4-sections.txt index e734a3f24d..8ffe2a490a 100644 --- a/docs/reference/gsk/gsk4-sections.txt +++ b/docs/reference/gsk/gsk4-sections.txt @@ -182,6 +182,12 @@ gsk_rounded_clip_node_new gsk_rounded_clip_node_get_child gsk_rounded_clip_node_get_clip <SUBSECTION> +GskFillRule +gsk_fill_node_new +gsk_fill_node_get_child +gsk_fill_node_get_path +gsk_fill_node_get_fill_rule +<SUBSECTION> GskShadow gsk_shadow_node_new gsk_shadow_node_get_shadow @@ -235,6 +241,7 @@ GSK_TYPE_CONTAINER_NODE GSK_TYPE_CONIC_GRADIENT_NODE GSK_TYPE_CROSS_FADE_NODE GSK_TYPE_DEBUG_NODE +GSK_TYPE_FILL_NODE GSK_TYPE_GL_SHADER_NODE GSK_TYPE_INSET_SHADOW_NODE GSK_TYPE_LINEAR_GRADIENT_NODE @@ -265,6 +272,7 @@ gsk_conic_gradient_node_get_type gsk_container_node_get_type gsk_cross_fade_node_get_type gsk_debug_node_get_type +gsk_fill_node_get_type gsk_gl_shader_node_get_type gsk_inset_shadow_node_get_type gsk_linear_gradient_node_get_type diff --git a/gsk/broadway/gskbroadwayrenderer.c b/gsk/broadway/gskbroadwayrenderer.c index 5ac62e7ee0..6a0b2a2aaf 100644 --- a/gsk/broadway/gskbroadwayrenderer.c +++ b/gsk/broadway/gskbroadwayrenderer.c @@ -269,6 +269,7 @@ collect_reused_child_nodes (GskRenderer *renderer, case GSK_BLEND_NODE: case GSK_CROSS_FADE_NODE: case GSK_BLUR_NODE: + case GSK_FILL_NODE: default: @@ -855,6 +856,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer, case GSK_CROSS_FADE_NODE: case GSK_BLUR_NODE: case GSK_GL_SHADER_NODE: + case GSK_FILL_NODE: default: break; /* Fallback */ } diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index 89cc3684ce..ad66e3b7d4 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -3813,6 +3813,7 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self, case GSK_REPEATING_LINEAR_GRADIENT_NODE: case GSK_REPEATING_RADIAL_GRADIENT_NODE: + case GSK_FILL_NODE: case GSK_CAIRO_NODE: default: { diff --git a/gsk/gskenums.h b/gsk/gskenums.h index 243ab67cc8..5048559866 100644 --- a/gsk/gskenums.h +++ b/gsk/gskenums.h @@ -73,6 +73,7 @@ typedef enum { GSK_REPEAT_NODE, GSK_CLIP_NODE, GSK_ROUNDED_CLIP_NODE, + GSK_FILL_NODE, GSK_SHADOW_NODE, GSK_BLEND_NODE, GSK_CROSS_FADE_NODE, @@ -168,6 +169,34 @@ typedef enum { } GskCorner; /** + * GskFillRule: + * @GSK_FILL_RULE_WINDING: If the path crosses the ray from + * left-to-right, counts +1. If the path crosses the ray + * from right to left, counts -1. (Left and right are determined + * from the perspective of looking along the ray from the starting + * point.) If the total count is non-zero, the point will be filled. + * @GSK_FILL_RULE_EVEN_ODD: Counts the total number of + * intersections, without regard to the orientation of the contour. If + * the total number of intersections is odd, the point will be + * filled. + * + * #GskFillRule is used to select how paths are filled, for example in + * gsk_fill_node_new(). Whether or not a point is included in the fill is + * determined by taking a ray from that point to infinity and looking + * at intersections with the path. The ray can be in any direction, + * as long as it doesn't pass through the end point of a segment + * or have a tricky intersection such as intersecting tangent to the path. + * (Note that filling is not actually implemented in this way. This + * is just a description of the rule that is applied.) + * + * New entries may be added in future versions. + **/ +typedef enum { + GSK_FILL_RULE_WINDING, + GSK_FILL_RULE_EVEN_ODD +} GskFillRule; + +/** * GskSerializationError: * @GSK_SERIALIZATION_UNSUPPORTED_FORMAT: The format can not be * identified diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h index 99af00286f..554360da74 100644 --- a/gsk/gskrendernode.h +++ b/gsk/gskrendernode.h @@ -158,6 +158,7 @@ GskRenderNode * gsk_render_node_deserialize (GBytes #define GSK_TYPE_REPEAT_NODE (gsk_repeat_node_get_type()) #define GSK_TYPE_CLIP_NODE (gsk_clip_node_get_type()) #define GSK_TYPE_ROUNDED_CLIP_NODE (gsk_rounded_clip_node_get_type()) +#define GSK_TYPE_FILL_NODE (gsk_fill_node_get_type()) #define GSK_TYPE_SHADOW_NODE (gsk_shadow_node_get_type()) #define GSK_TYPE_BLEND_NODE (gsk_blend_node_get_type()) #define GSK_TYPE_CROSS_FADE_NODE (gsk_cross_fade_node_get_type()) @@ -184,6 +185,7 @@ typedef struct _GskColorMatrixNode GskColorMatrixNode; typedef struct _GskRepeatNode GskRepeatNode; typedef struct _GskClipNode GskClipNode; typedef struct _GskRoundedClipNode GskRoundedClipNode; +typedef struct _GskFillNode GskFillNode; typedef struct _GskShadowNode GskShadowNode; typedef struct _GskBlendNode GskBlendNode; typedef struct _GskCrossFadeNode GskCrossFadeNode; @@ -444,6 +446,19 @@ GDK_AVAILABLE_IN_ALL const GskRoundedRect * gsk_rounded_clip_node_get_clip (GskRenderNode *node); GDK_AVAILABLE_IN_ALL +GType gsk_fill_node_get_type (void) G_GNUC_CONST; +GDK_AVAILABLE_IN_ALL +GskRenderNode * gsk_fill_node_new (GskRenderNode *child, + GskPath *path, + GskFillRule fill_rule); +GDK_AVAILABLE_IN_ALL +GskRenderNode * gsk_fill_node_get_child (GskRenderNode *node); +GDK_AVAILABLE_IN_ALL +GskPath * gsk_fill_node_get_path (GskRenderNode *node); +GDK_AVAILABLE_IN_ALL +GskFillRule gsk_fill_node_get_fill_rule (GskRenderNode *node); + +GDK_AVAILABLE_IN_ALL GType gsk_shadow_node_get_type (void) G_GNUC_CONST; GDK_AVAILABLE_IN_ALL GskRenderNode * gsk_shadow_node_new (GskRenderNode *child, diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index acc6f529a1..777bbe3a14 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -23,6 +23,7 @@ #include "gskcairoblurprivate.h" #include "gskdebugprivate.h" #include "gskdiffprivate.h" +#include "gskpath.h" #include "gskrendererprivate.h" #include "gskroundedrectprivate.h" #include "gsktransformprivate.h" @@ -3682,6 +3683,178 @@ gsk_rounded_clip_node_get_clip (GskRenderNode *node) return &self->clip; } +/*** GSK_FILL_NODE ***/ + +struct _GskFillNode +{ + GskRenderNode render_node; + + GskRenderNode *child; + GskPath *path; + GskFillRule fill_rule; +}; + +static void +gsk_fill_node_finalize (GskRenderNode *node) +{ + GskFillNode *self = (GskFillNode *) node; + GskRenderNodeClass *parent_class = g_type_class_peek (g_type_parent (GSK_TYPE_FILL_NODE)); + + gsk_render_node_unref (self->child); + gsk_path_unref (self->path); + + parent_class->finalize (node); +} + +static void +gsk_fill_node_draw (GskRenderNode *node, + cairo_t *cr) +{ + GskFillNode *self = (GskFillNode *) node; + + cairo_save (cr); + + switch (self->fill_rule) + { + case GSK_FILL_RULE_WINDING: + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING); + break; + case GSK_FILL_RULE_EVEN_ODD: + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + break; + default: + g_assert_not_reached (); + break; + } + gsk_path_to_cairo (self->path, cr); + cairo_clip (cr); + + gsk_render_node_draw (self->child, cr); + + cairo_restore (cr); +} + +static void +gsk_fill_node_diff (GskRenderNode *node1, + GskRenderNode *node2, + cairo_region_t *region) +{ + GskFillNode *self1 = (GskFillNode *) node1; + GskFillNode *self2 = (GskFillNode *) node2; + + if (self1->path == self2->path) + { + cairo_region_t *sub; + cairo_rectangle_int_t clip_rect; + graphene_rect_t rect; + + sub = cairo_region_create(); + gsk_render_node_diff (self1->child, self2->child, sub); + graphene_rect_union (&node1->bounds, &node2->bounds, &rect); + rectangle_init_from_graphene (&clip_rect, &rect); + cairo_region_intersect_rectangle (sub, &clip_rect); + cairo_region_union (region, sub); + cairo_region_destroy (sub); + } + else + { + gsk_render_node_diff_impossible (node1, node2, region); + } +} + +/** + * gsk_fill_node_new: + * @child: The node to fill the area with + * @path: The path describing the area to fill + * @fill_rule: The fill rule to use + * + * Creates a #GskRenderNode that will fill the @child in the area + * given by @path and @fill_rule. + * + * Returns: (transfer none) (type GskFillNode): A new #GskRenderNode + */ +GskRenderNode * +gsk_fill_node_new (GskRenderNode *child, + GskPath *path, + GskFillRule fill_rule) +{ + GskFillNode *self; + GskRenderNode *node; + graphene_rect_t path_bounds; + + g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL); + g_return_val_if_fail (path != NULL, NULL); + + self = gsk_render_node_alloc (GSK_FILL_NODE); + node = (GskRenderNode *) self; + + self->child = gsk_render_node_ref (child); + self->path = gsk_path_ref (path); + self->fill_rule = fill_rule; + + if (gsk_path_get_bounds (path, &path_bounds)) + graphene_rect_intersection (&path_bounds, &child->bounds, &node->bounds); + else + graphene_rect_init_from_rect (&node->bounds, graphene_rect_zero ()); + + return node; +} + +/** + * gsk_fill_node_get_child: + * @node: (type GskFillNode): a fill #GskRenderNode + * + * Gets the child node that is getting drawn by the given @node. + * + * Returns: (transfer none): The child that is getting drawn + **/ +GskRenderNode * +gsk_fill_node_get_child (GskRenderNode *node) +{ + GskFillNode *self = (GskFillNode *) node; + + g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_FILL_NODE), NULL); + + return self->child; +} + +/** + * gsk_fill_node_get_path: + * @node: (type GskFillNode): a fill #GskRenderNode + * + * Retrievs the path used to describe the area filled with the contents of + * the @node. + * + * Returns: (transfer none): a #GskPath + */ +GskPath * +gsk_fill_node_get_path (GskRenderNode *node) +{ + GskFillNode *self = (GskFillNode *) node; + + g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_FILL_NODE), NULL); + + return self->path; +} + +/** + * gsk_fill_node_get_fill_rule: + * @node: (type GskFillNode): a fill #GskRenderNode + * + * Retrievs the fill rule used to determine how the path is filled. + * + * Returns: a #GskFillRule + */ +GskFillRule +gsk_fill_node_get_fill_rule (GskRenderNode *node) +{ + GskFillNode *self = (GskFillNode *) node; + + g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_FILL_NODE), GSK_FILL_RULE_WINDING); + + return self->fill_rule; +} + /*** GSK_SHADOW_NODE ***/ /** @@ -5230,6 +5403,7 @@ GSK_DEFINE_RENDER_NODE_TYPE (gsk_color_matrix_node, GSK_COLOR_MATRIX_NODE) GSK_DEFINE_RENDER_NODE_TYPE (gsk_repeat_node, GSK_REPEAT_NODE) GSK_DEFINE_RENDER_NODE_TYPE (gsk_clip_node, GSK_CLIP_NODE) GSK_DEFINE_RENDER_NODE_TYPE (gsk_rounded_clip_node, GSK_ROUNDED_CLIP_NODE) +GSK_DEFINE_RENDER_NODE_TYPE (gsk_fill_node, GSK_FILL_NODE) GSK_DEFINE_RENDER_NODE_TYPE (gsk_shadow_node, GSK_SHADOW_NODE) GSK_DEFINE_RENDER_NODE_TYPE (gsk_blend_node, GSK_BLEND_NODE) GSK_DEFINE_RENDER_NODE_TYPE (gsk_cross_fade_node, GSK_CROSS_FADE_NODE) @@ -5532,6 +5706,22 @@ gsk_render_node_init_types_once (void) { const GskRenderNodeTypeInfo node_info = { + GSK_FILL_NODE, + sizeof (GskFillNode), + NULL, + gsk_fill_node_finalize, + gsk_fill_node_draw, + NULL, + gsk_fill_node_diff, + }; + + GType node_type = gsk_render_node_type_register_static (I_("GskFillNode"), &node_info); + gsk_render_node_types[GSK_FILL_NODE] = node_type; + } + + { + const GskRenderNodeTypeInfo node_info = + { GSK_SHADOW_NODE, sizeof (GskShadowNode), NULL, diff --git a/gsk/gskrendernodeparser.c b/gsk/gskrendernodeparser.c index 90183482f2..a678e28df5 100644 --- a/gsk/gskrendernodeparser.c +++ b/gsk/gskrendernodeparser.c @@ -23,6 +23,7 @@ #include "gskrendernodeparserprivate.h" +#include "gskpath.h" #include "gskroundedrectprivate.h" #include "gskrendernodeprivate.h" #include "gsktransformprivate.h" @@ -2536,6 +2537,20 @@ render_node_print (Printer *p, append_node_param (p, "child", gsk_rounded_clip_node_get_child (node)); append_rounded_rect_param (p, "clip", gsk_rounded_clip_node_get_clip (node)); + end_node (p); + } + break; + + case GSK_FILL_NODE: + { + char *path_str; + + start_node (p, "fill"); + + append_node_param (p, "child", gsk_fill_node_get_child (node)); + path_str = gsk_path_to_string (gsk_fill_node_get_path (node)); + append_string_param (p, "path", path_str); + g_free (path_str); end_node (p); } diff --git a/gsk/vulkan/gskvulkanrenderpass.c b/gsk/vulkan/gskvulkanrenderpass.c index d81d38fa33..253157ac5d 100644 --- a/gsk/vulkan/gskvulkanrenderpass.c +++ b/gsk/vulkan/gskvulkanrenderpass.c @@ -260,6 +260,7 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self, case GSK_RADIAL_GRADIENT_NODE: case GSK_REPEATING_RADIAL_GRADIENT_NODE: case GSK_CONIC_GRADIENT_NODE: + case GSK_FILL_NODE: default: FALLBACK ("Unsupported node '%s'", g_type_name_from_instance ((GTypeInstance *) node)); diff --git a/gtk/inspector/recorder.c b/gtk/inspector/recorder.c index 5b6452f340..3fc884884a 100644 --- a/gtk/inspector/recorder.c +++ b/gtk/inspector/recorder.c @@ -161,6 +161,9 @@ create_list_model_for_render_node (GskRenderNode *node) case GSK_ROUNDED_CLIP_NODE: return create_render_node_list_model ((GskRenderNode *[1]) { gsk_rounded_clip_node_get_child (node) }, 1); + case GSK_FILL_NODE: + return create_render_node_list_model ((GskRenderNode *[1]) { gsk_fill_node_get_child (node) }, 1); + case GSK_SHADOW_NODE: return create_render_node_list_model ((GskRenderNode *[1]) { gsk_shadow_node_get_child (node) }, 1); @@ -282,6 +285,8 @@ node_type_name (GskRenderNodeType type) return "Clip"; case GSK_ROUNDED_CLIP_NODE: return "Rounded Clip"; + case GSK_FILL_NODE: + return "Fill"; case GSK_SHADOW_NODE: return "Shadow"; case GSK_BLEND_NODE: @@ -321,6 +326,7 @@ node_name (GskRenderNode *node) case GSK_REPEAT_NODE: case GSK_CLIP_NODE: case GSK_ROUNDED_CLIP_NODE: + case GSK_FILL_NODE: case GSK_SHADOW_NODE: case GSK_BLEND_NODE: case GSK_CROSS_FADE_NODE: @@ -1072,6 +1078,16 @@ populate_render_node_properties (GtkListStore *store, } break; + case GSK_FILL_NODE: + { + GskPath *path = gsk_fill_node_get_path (node); + + tmp = gsk_path_to_string (path); + add_text_row (store, "Path", tmp); + g_free (tmp); + } + break; + case GSK_CONTAINER_NODE: tmp = g_strdup_printf ("%d", gsk_container_node_get_n_children (node)); add_text_row (store, "Children", tmp); |