summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2020-11-11 00:44:32 +0100
committerBenjamin Otte <otte@redhat.com>2020-12-27 00:31:17 +0100
commit4eb7d68970fdffb5612c8cf61cb68adfd5e15a39 (patch)
tree99861188e12412e8d99bb95a3255eedd1593e628
parent98337f71157c3fac5e06c6057f3034a476e807c0 (diff)
downloadgtk+-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.txt8
-rw-r--r--gsk/broadway/gskbroadwayrenderer.c2
-rw-r--r--gsk/gl/gskglrenderer.c1
-rw-r--r--gsk/gskenums.h29
-rw-r--r--gsk/gskrendernode.h15
-rw-r--r--gsk/gskrendernodeimpl.c190
-rw-r--r--gsk/gskrendernodeparser.c15
-rw-r--r--gsk/vulkan/gskvulkanrenderpass.c1
-rw-r--r--gtk/inspector/recorder.c16
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);