diff options
author | Benjamin Otte <otte@redhat.com> | 2017-01-01 19:52:18 +0100 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2017-01-01 19:53:36 +0100 |
commit | b993acfe2c7b81e6ed4c35eb4f30bac29f43254e (patch) | |
tree | b55debbc063d8e126e8bfa5c1ee5d4b89be4dd7b /gsk | |
parent | aa917ce3b77ab3fbf4f9417ddb8801bdf1a3bffc (diff) | |
download | gtk+-b993acfe2c7b81e6ed4c35eb4f30bac29f43254e.tar.gz |
gsk: Add GskRepeatNode
Also add gtk_snapshot_push_repeat() and use that to draw backgrounds.
With that change, CSS background snapshots are created without Cairo
nodes.
Diffstat (limited to 'gsk')
-rw-r--r-- | gsk/gskenums.h | 3 | ||||
-rw-r--r-- | gsk/gskrendernode.h | 5 | ||||
-rw-r--r-- | gsk/gskrendernodeimpl.c | 171 | ||||
-rw-r--r-- | gsk/gskrendernodeprivate.h | 3 |
4 files changed, 182 insertions, 0 deletions
diff --git a/gsk/gskenums.h b/gsk/gskenums.h index 060febb61d..bc828b0ffb 100644 --- a/gsk/gskenums.h +++ b/gsk/gskenums.h @@ -38,6 +38,8 @@ * @GSK_TRANSFORM_NODE: A node that renders its child after applying a * matrix transform * @GSK_OPACITY_NODE: A node that changes the opacity of its child + * @GSK_COLOR_MATRIX_NODE: A node that applies a color matrix to every pixel + * @GSK_REPEAT_NODE: A node that repeats the child's contents * @GSK_CLIP_NODE: A node that clips its child to a rectangular area * @GSK_ROUNDED_CLIP_NODE: A node that clips its child to a rounded rectangle * @GSK_SHADOW_NODE: A node that draws a shadow below its child @@ -62,6 +64,7 @@ typedef enum { GSK_TRANSFORM_NODE, GSK_OPACITY_NODE, GSK_COLOR_MATRIX_NODE, + GSK_REPEAT_NODE, GSK_CLIP_NODE, GSK_ROUNDED_CLIP_NODE, GSK_SHADOW_NODE, diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h index e4a75ab490..f46c283ba1 100644 --- a/gsk/gskrendernode.h +++ b/gsk/gskrendernode.h @@ -140,6 +140,11 @@ GskRenderNode * gsk_color_matrix_node_new (GskRenderNode const graphene_vec4_t *color_offset); GDK_AVAILABLE_IN_3_90 +GskRenderNode * gsk_repeat_node_new (const graphene_rect_t *bounds, + GskRenderNode *child, + const graphene_rect_t *child_bounds); + +GDK_AVAILABLE_IN_3_90 GskRenderNode * gsk_clip_node_new (GskRenderNode *child, const graphene_rect_t *clip); GDK_AVAILABLE_IN_3_90 diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index 9a4203f588..af356d5798 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -2581,6 +2581,177 @@ gsk_color_matrix_node_peek_color_offset (GskRenderNode *node) return &self->color_offset; } +/*** GSK_REPEAT_NODE ***/ + +typedef struct _GskRepeatNode GskRepeatNode; + +struct _GskRepeatNode +{ + GskRenderNode render_node; + + GskRenderNode *child; + graphene_rect_t child_bounds; +}; + +static void +gsk_repeat_node_finalize (GskRenderNode *node) +{ + GskRepeatNode *self = (GskRepeatNode *) node; + + gsk_render_node_unref (self->child); +} + +static void +gsk_repeat_node_draw (GskRenderNode *node, + cairo_t *cr) +{ + GskRepeatNode *self = (GskRepeatNode *) node; + cairo_pattern_t *pattern; + cairo_surface_t *surface; + cairo_t *surface_cr; + + surface = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, + ceilf (self->child_bounds.size.width), + ceilf (self->child_bounds.size.height)); + surface_cr = cairo_create (surface); + cairo_translate (surface_cr, + - self->child_bounds.origin.x, + - self->child_bounds.origin.y); + gsk_render_node_draw (self->child, surface_cr); + cairo_destroy (surface_cr); + + pattern = cairo_pattern_create_for_surface (surface); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); + cairo_pattern_set_matrix (pattern, + &(cairo_matrix_t) { + .xx = 1.0, + .yy = 1.0, + .x0 = - self->child_bounds.origin.x, + .y0 = - self->child_bounds.origin.y + }); + + cairo_set_source (cr, pattern); + cairo_paint (cr); + + cairo_pattern_destroy (pattern); + cairo_surface_destroy (surface); +} + +#define GSK_REPEAT_NODE_VARIANT_TYPE "(dddddddduv)" + +static GVariant * +gsk_repeat_node_serialize (GskRenderNode *node) +{ + GskRepeatNode *self = (GskRepeatNode *) node; + + return g_variant_new (GSK_REPEAT_NODE_VARIANT_TYPE, + (double) node->bounds.origin.x, (double) node->bounds.origin.y, + (double) node->bounds.size.width, (double) node->bounds.size.height, + (double) self->child_bounds.origin.x, (double) self->child_bounds.origin.y, + (double) self->child_bounds.size.width, (double) self->child_bounds.size.height, + (guint32) gsk_render_node_get_node_type (self->child), + gsk_render_node_serialize_node (self->child)); +} + +static GskRenderNode * +gsk_repeat_node_deserialize (GVariant *variant, + GError **error) +{ + double x, y, width, height, child_x, child_y, child_width, child_height; + guint32 child_type; + GVariant *child_variant; + GskRenderNode *result, *child; + + if (!check_variant_type (variant, GSK_REPEAT_NODE_VARIANT_TYPE, error)) + return NULL; + + g_variant_get (variant, GSK_REPEAT_NODE_VARIANT_TYPE, + &x, &y, &width, &height, + &child_x, &child_y, &child_width, &child_height, + &child_type, &child_variant); + + child = gsk_render_node_deserialize_node (child_type, child_variant, error); + g_variant_unref (child_variant); + + if (child == NULL) + return NULL; + + result = gsk_repeat_node_new (&GRAPHENE_RECT_INIT (x, y, width, height), + child, + &GRAPHENE_RECT_INIT (child_x, child_y, child_width, child_height)); + + gsk_render_node_unref (child); + + return result; +} + +static const GskRenderNodeClass GSK_REPEAT_NODE_CLASS = { + GSK_REPEAT_NODE, + sizeof (GskRepeatNode), + "GskRepeatNode", + gsk_repeat_node_finalize, + gsk_repeat_node_draw, + gsk_repeat_node_serialize, + gsk_repeat_node_deserialize +}; + +/** + * gsk_repeat_node_new: + * @bounds: The bounds of the area to be painted + * @child: The child to repeat + * @child_bounds: (optional): The area of the child to repeat or %NULL to + * use the child's bounds + * + * Creates a #GskRenderNode that will repeat the drawing of @child across + * the given @bounds. + * + * Returns: A new #GskRenderNode + * + * Since: 3.90 + */ +GskRenderNode * +gsk_repeat_node_new (const graphene_rect_t *bounds, + GskRenderNode *child, + const graphene_rect_t *child_bounds) +{ + GskRepeatNode *self; + + g_return_val_if_fail (bounds != NULL, NULL); + g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL); + + self = (GskRepeatNode *) gsk_render_node_new (&GSK_REPEAT_NODE_CLASS, 0); + + graphene_rect_init_from_rect (&self->render_node.bounds, bounds); + self->child = gsk_render_node_ref (child); + if (child_bounds) + graphene_rect_init_from_rect (&self->child_bounds, child_bounds); + else + graphene_rect_init_from_rect (&self->child_bounds, &child->bounds); + + return &self->render_node; +} + +GskRenderNode * +gsk_repeat_node_get_child (GskRenderNode *node) +{ + GskRepeatNode *self = (GskRepeatNode *) node; + + g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_REPEAT_NODE), NULL); + + return self->child; +} + +const graphene_rect_t * +gsk_repeat_node_peek_child_bounds (GskRenderNode *node) +{ + GskRepeatNode *self = (GskRepeatNode *) node; + + g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_REPEAT_NODE), NULL); + + return &self->child_bounds; +} + /*** GSK_CLIP_NODE ***/ typedef struct _GskClipNode GskClipNode; diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h index 90deb10a48..938c948002 100644 --- a/gsk/gskrendernodeprivate.h +++ b/gsk/gskrendernodeprivate.h @@ -50,6 +50,9 @@ GskRenderNode * gsk_color_matrix_node_get_child (GskRenderNode *node); const graphene_matrix_t * gsk_color_matrix_node_peek_color_matrix (GskRenderNode *node); const graphene_vec4_t * gsk_color_matrix_node_peek_color_offset (GskRenderNode *node); +GskRenderNode * gsk_repeat_node_get_child (GskRenderNode *node); +const graphene_rect_t * gsk_repeat_node_peek_child_bounds (GskRenderNode *node); + const graphene_point_t * gsk_linear_gradient_node_peek_start (GskRenderNode *node); const graphene_point_t * gsk_linear_gradient_node_peek_end (GskRenderNode *node); const gsize gsk_linear_gradient_node_get_n_color_stops (GskRenderNode *node); |