diff --git a/docs/reference/gsk/gsk4-sections.txt b/docs/reference/gsk/gsk4-sections.txt index 1fe5cdd3d6..102d08467c 100644 --- a/docs/reference/gsk/gsk4-sections.txt +++ b/docs/reference/gsk/gsk4-sections.txt @@ -28,7 +28,6 @@ gsk_render_node_ref gsk_render_node_unref GskRenderNodeType gsk_render_node_get_node_type -gsk_render_node_set_transform gsk_render_node_set_opacity GskBlendMode gsk_render_node_set_blend_mode @@ -42,6 +41,8 @@ gsk_container_node_new gsk_container_node_append_child gsk_container_node_get_n_children gsk_container_node_get_child +gsk_transform_node_new +gsk_transform_node_get_child GSK_IS_RENDER_NODE GSK_RENDER_NODE diff --git a/gsk/gskcairorenderer.c b/gsk/gskcairorenderer.c index 7d4dcff496..4fd85927d9 100644 --- a/gsk/gskcairorenderer.c +++ b/gsk/gskcairorenderer.c @@ -52,24 +52,10 @@ gsk_cairo_renderer_render_node (GskCairoRenderer *self, cairo_t *cr) { gboolean pop_group = FALSE; - graphene_matrix_t mat; - cairo_matrix_t ctm; graphene_rect_t frame; cairo_save (cr); - gsk_render_node_get_transform (node, &mat); - if (graphene_matrix_to_2d (&mat, &ctm.xx, &ctm.yx, &ctm.xy, &ctm.yy, &ctm.x0, &ctm.y0)) - { - GSK_NOTE (CAIRO, g_print ("CTM = { .xx = %g, .yx = %g, .xy = %g, .yy = %g, .x0 = %g, .y0 = %g }\n", - ctm.xx, ctm.yx, - ctm.xy, ctm.yy, - ctm.x0, ctm.y0)); - cairo_transform (cr, &ctm); - } - else - g_critical ("Invalid non-affine transformation for node %p", node); - gsk_render_node_get_bounds (node, &frame); GSK_NOTE (CAIRO, g_print ("CLIP = { .x = %g, .y = %g, .width = %g, .height = %g }\n", frame.origin.x, frame.origin.y, @@ -131,6 +117,27 @@ gsk_cairo_renderer_render_node (GskCairoRenderer *self, cairo_paint (cr); } break; + + case GSK_TRANSFORM_NODE: + { + graphene_matrix_t mat; + cairo_matrix_t ctm; + + gsk_transform_node_get_transform (node, &mat); + if (graphene_matrix_to_2d (&mat, &ctm.xx, &ctm.yx, &ctm.xy, &ctm.yy, &ctm.x0, &ctm.y0)) + { + GSK_NOTE (CAIRO, g_print ("CTM = { .xx = %g, .yx = %g, .xy = %g, .yy = %g, .x0 = %g, .y0 = %g }\n", + ctm.xx, ctm.yx, + ctm.xy, ctm.yy, + ctm.x0, ctm.y0)); + cairo_transform (cr, &ctm); + } + else + g_critical ("Invalid non-affine transformation for node %p", node); + + gsk_cairo_renderer_render_node (self, gsk_transform_node_get_child (node), cr); + } + break; } if (GSK_RENDER_MODE_CHECK (GEOMETRY)) diff --git a/gsk/gskenums.h b/gsk/gskenums.h index 9040c69cbf..26ce47ff92 100644 --- a/gsk/gskenums.h +++ b/gsk/gskenums.h @@ -28,6 +28,8 @@ * @GSK_CONTAINER_NODE: A node containing a stack of children * @GSK_CAIRO_NODE: A node drawing a #cairo_surface_t * @GSK_TEXTURE_NODE: A node drawing a #GskTexture + * @GSK_TRANSFORM_NODE: A node that renders its child after applying a + * matrix transform * * The type of a node determines what the node is rendering. * @@ -37,7 +39,8 @@ typedef enum { GSK_NOT_A_RENDER_NODE = 0, GSK_CONTAINER_NODE, GSK_CAIRO_NODE, - GSK_TEXTURE_NODE + GSK_TEXTURE_NODE, + GSK_TRANSFORM_NODE } GskRenderNodeType; /** diff --git a/gsk/gskglrenderer.c b/gsk/gskglrenderer.c index 36b158fee3..5cbb0a0029 100644 --- a/gsk/gskglrenderer.c +++ b/gsk/gskglrenderer.c @@ -603,13 +603,12 @@ render_node_needs_render_target (GskRenderNode *node) static void gsk_gl_renderer_add_render_item (GskGLRenderer *self, const graphene_matrix_t *projection, - const graphene_matrix_t *parent_modelview, + const graphene_matrix_t *modelview, GArray *render_items, GskRenderNode *node, RenderItem *parent) { graphene_rect_t viewport; - graphene_matrix_t mv, transform; graphene_rect_t bounds; RenderItem item; RenderItem *ritem = NULL; @@ -645,10 +644,8 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self, item.max.z = 0.f; /* The location of the item, in normalized world coordinates */ - gsk_render_node_get_transform (node, &transform); - graphene_matrix_multiply (&transform, parent_modelview, &mv); - graphene_matrix_multiply (&mv, &self->mvp, &item.mvp); - item.z = project_item (projection, &mv); + graphene_matrix_multiply (modelview, &self->mvp, &item.mvp); + item.z = project_item (projection, modelview); item.opacity = gsk_render_node_get_opacity (node); @@ -743,11 +740,25 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self, for (i = 0; i < gsk_container_node_get_n_children (node); i++) { GskRenderNode *child = gsk_container_node_get_child (node, i); - gsk_gl_renderer_add_render_item (self, projection, &mv, render_items, child, ritem); + gsk_gl_renderer_add_render_item (self, projection, modelview, render_items, child, ritem); } } return; + case GSK_TRANSFORM_NODE: + { + graphene_matrix_t transform, transformed_mv; + + gsk_transform_node_get_transform (node, &transform); + graphene_matrix_multiply (&transform, modelview, &transformed_mv); + gsk_gl_renderer_add_render_item (self, + projection, &transformed_mv, + render_items, + gsk_transform_node_get_child (node), + ritem); + } + return; + case GSK_NOT_A_RENDER_NODE: default: return; diff --git a/gsk/gskrendernode.c b/gsk/gskrendernode.c index 641ab2f653..5b53c9197f 100644 --- a/gsk/gskrendernode.c +++ b/gsk/gskrendernode.c @@ -97,8 +97,6 @@ gsk_render_node_new (const GskRenderNodeClass *node_class) self->ref_count = 1; - graphene_matrix_init_identity (&self->transform); - self->opacity = 1.0; self->min_filter = GSK_SCALING_FILTER_NEAREST; @@ -187,47 +185,6 @@ gsk_render_node_get_bounds (GskRenderNode *node, node->node_class->get_bounds (node, bounds); } -/** - * gsk_render_node_set_transform: - * @node: a #GskRenderNode - * @transform: (nullable): a transformation matrix - * - * Sets the transformation matrix used when rendering the @node. - * - * Since: 3.90 - */ -void -gsk_render_node_set_transform (GskRenderNode *node, - const graphene_matrix_t *transform) -{ - g_return_if_fail (GSK_IS_RENDER_NODE (node)); - g_return_if_fail (node->is_mutable); - - if (transform == NULL) - graphene_matrix_init_identity (&node->transform); - else - graphene_matrix_init_from_matrix (&node->transform, transform); -} - -/** - * gsk_render_node_get_transform: - * @node: a #GskRenderNode - * @mv: (out caller-allocates): return location for the transform matrix - * - * Retrieves the transform matrix set using gsk_render_node_set_transform(). - * - * Since: 3.90 - */ -void -gsk_render_node_get_transform (GskRenderNode *node, - graphene_matrix_t *mv) -{ - g_return_if_fail (GSK_IS_RENDER_NODE (node)); - g_return_if_fail (mv != NULL); - - graphene_matrix_init_from_matrix (mv, &node->transform); -} - /** * gsk_render_node_set_opacity: * @node: a #GskRenderNode diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h index 70d26a553e..b98bd56ce6 100644 --- a/gsk/gskrendernode.h +++ b/gsk/gskrendernode.h @@ -66,8 +66,11 @@ GskRenderNode * gsk_container_node_get_child (GskRenderNode guint idx); GDK_AVAILABLE_IN_3_90 -void gsk_render_node_set_transform (GskRenderNode *node, +GskRenderNode * gsk_transform_node_new (GskRenderNode *child, const graphene_matrix_t *transform); +GDK_AVAILABLE_IN_3_90 +GskRenderNode * gsk_transform_node_get_child (GskRenderNode *node); + GDK_AVAILABLE_IN_3_90 void gsk_render_node_set_opacity (GskRenderNode *node, double opacity); diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index 40c2ad6365..e719a1d6e9 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -424,3 +424,112 @@ gsk_container_node_get_child (GskRenderNode *node, return g_ptr_array_index (container->children, idx); } +/*** GSK_TRANSFORM_NODE ***/ + +typedef struct _GskTransformNode GskTransformNode; + +struct _GskTransformNode +{ + GskRenderNode render_node; + + GskRenderNode *child; + graphene_matrix_t transform; +}; + +static void +gsk_transform_node_finalize (GskRenderNode *node) +{ + GskTransformNode *self = (GskTransformNode *) node; + + gsk_render_node_unref (self->child); +} + +static void +gsk_transform_node_make_immutable (GskRenderNode *node) +{ + GskTransformNode *self = (GskTransformNode *) node; + + gsk_render_node_make_immutable (self->child); +} + +static void +gsk_transform_node_get_bounds (GskRenderNode *node, + graphene_rect_t *bounds) +{ + GskTransformNode *self = (GskTransformNode *) node; + graphene_rect_t child_bounds; + + gsk_render_node_get_bounds (self->child, &child_bounds); + + graphene_matrix_transform_bounds (&self->transform, + &child_bounds, + bounds); +} + +static const GskRenderNodeClass GSK_TRANSFORM_NODE_CLASS = { + GSK_TRANSFORM_NODE, + sizeof (GskTransformNode), + "GskTransformNode", + gsk_transform_node_finalize, + gsk_transform_node_make_immutable, + gsk_transform_node_get_bounds +}; + +/** + * gsk_transform_node_new: + * @child: The node to transform + * @transform: The transform to apply + * + * Creates a #GskRenderNode that will transform the given @child + * with the given @transform. + * + * Returns: A new #GskRenderNode + * + * Since: 3.90 + */ +GskRenderNode * +gsk_transform_node_new (GskRenderNode *child, + const graphene_matrix_t *transform) +{ + GskTransformNode *self; + + g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL); + g_return_val_if_fail (transform != NULL, NULL); + + self = (GskTransformNode *) gsk_render_node_new (&GSK_TRANSFORM_NODE_CLASS); + + self->child = gsk_render_node_ref (child); + graphene_matrix_init_from_matrix (&self->transform, transform); + + return &self->render_node; +} + +/** + * gsk_transform_node_get_child: + * @node: a transform @GskRenderNode + * + * Gets the child node that is getting transformed by the given @node. + * + * Returns: (transfer none): The child that is getting transformed + **/ +GskRenderNode * +gsk_transform_node_get_child (GskRenderNode *node) +{ + GskTransformNode *self = (GskTransformNode *) node; + + g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_TRANSFORM_NODE), NULL); + + return self->child; +} + +void +gsk_transform_node_get_transform (GskRenderNode *node, + graphene_matrix_t *transform) +{ + GskTransformNode *self = (GskTransformNode *) node; + + g_return_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_TRANSFORM_NODE)); + + graphene_matrix_init_from_matrix (transform, &self->transform); +} + diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h index 5e35396f91..85117f4aa7 100644 --- a/gsk/gskrendernodeprivate.h +++ b/gsk/gskrendernodeprivate.h @@ -29,9 +29,6 @@ struct _GskRenderNode GskScalingFilter min_filter; GskScalingFilter mag_filter; - /* Transformations applied to the node */ - graphene_matrix_t transform; - /* Bit fields; leave at the end */ gboolean is_mutable : 1; }; @@ -53,14 +50,14 @@ void gsk_render_node_make_immutable (GskRenderNode *node); void gsk_render_node_get_bounds (GskRenderNode *node, graphene_rect_t *frame); -void gsk_render_node_get_transform (GskRenderNode *node, - graphene_matrix_t *mv); double gsk_render_node_get_opacity (GskRenderNode *node); cairo_surface_t *gsk_cairo_node_get_surface (GskRenderNode *node); GskTexture *gsk_texture_node_get_texture (GskRenderNode *node); +void gsk_transform_node_get_transform (GskRenderNode *node, graphene_matrix_t *transform); + GskBlendMode gsk_render_node_get_blend_mode (GskRenderNode *node); G_END_DECLS diff --git a/gsk/gskvulkanrender.c b/gsk/gskvulkanrender.c index 8c145193b7..8727cde02b 100644 --- a/gsk/gskvulkanrender.c +++ b/gsk/gskvulkanrender.c @@ -233,7 +233,7 @@ gsk_vulkan_render_add_node (GskVulkanRender *self, self->render_passes = g_slist_prepend (self->render_passes, pass); - gsk_vulkan_render_pass_add_node (pass, self, node); + gsk_vulkan_render_pass_add (pass, self, &self->mvp, node); } void @@ -466,7 +466,7 @@ gsk_vulkan_render_draw (GskVulkanRender *self, for (l = self->render_passes; l; l = l->next) { - gsk_vulkan_render_pass_draw (l->data, self, &self->mvp, self->pipeline, self->command_buffer); + gsk_vulkan_render_pass_draw (l->data, self, self->pipeline, self->command_buffer); } vkCmdEndRenderPass (self->command_buffer); diff --git a/gsk/gskvulkanrenderpass.c b/gsk/gskvulkanrenderpass.c index f9398f2973..595ad63e31 100644 --- a/gsk/gskvulkanrenderpass.c +++ b/gsk/gskvulkanrenderpass.c @@ -12,7 +12,8 @@ typedef struct _GskVulkanRenderOp GskVulkanRenderOp; typedef enum { GSK_VULKAN_OP_FALLBACK, GSK_VULKAN_OP_SURFACE, - GSK_VULKAN_OP_TEXTURE + GSK_VULKAN_OP_TEXTURE, + GSK_VULKAN_OP_BIND_MVP } GskVulkanOpType; struct _GskVulkanRenderOp @@ -20,6 +21,7 @@ struct _GskVulkanRenderOp GskVulkanOpType type; GskRenderNode *node; /* node that's the source of this op */ GskVulkanImage *source; /* source image to render */ + graphene_matrix_t mvp; /* new mvp to set */ gsize vertex_offset; /* offset into vertex buffer */ gsize vertex_count; /* number of vertices */ gsize descriptor_set_index; /* index into descriptor sets array for the right descriptor set to bind */ @@ -54,9 +56,10 @@ gsk_vulkan_render_pass_free (GskVulkanRenderPass *self) } void -gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self, - GskVulkanRender *render, - GskRenderNode *node) +gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self, + GskVulkanRender *render, + const graphene_matrix_t *mvp, + GskRenderNode *node) { GskVulkanRenderOp op = { .type = GSK_VULKAN_OP_FALLBACK, @@ -89,10 +92,24 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self, for (i = 0; i < gsk_container_node_get_n_children (node); i++) { - gsk_vulkan_render_pass_add_node (self, render, gsk_container_node_get_child (node, i)); + gsk_vulkan_render_pass_add_node (self, render, mvp, gsk_container_node_get_child (node, i)); } } break; + case GSK_TRANSFORM_NODE: + { + graphene_matrix_t transform; + + op.type = GSK_VULKAN_OP_BIND_MVP; + gsk_transform_node_get_transform (node, &transform); + graphene_matrix_multiply (&transform, mvp, &op.mvp); + g_array_append_val (self->render_ops, op); + gsk_vulkan_render_pass_add_node (self, render, &op.mvp, gsk_transform_node_get_child (node)); + graphene_matrix_init_from_matrix (&op.mvp, mvp); + g_array_append_val (self->render_ops, op); + } + break; + } return; @@ -101,6 +118,22 @@ fallback: g_array_append_val (self->render_ops, op); } +void +gsk_vulkan_render_pass_add (GskVulkanRenderPass *self, + GskVulkanRender *render, + const graphene_matrix_t *mvp, + GskRenderNode *node) +{ + GskVulkanRenderOp op = { + .type = GSK_VULKAN_OP_BIND_MVP, + .mvp = *mvp + }; + + g_array_append_val (self->render_ops, op); + + gsk_vulkan_render_pass_add_node (self, render, mvp, node); +} + static void gsk_vulkan_render_pass_upload_fallback (GskVulkanRenderPass *self, GskVulkanRenderOp *op, @@ -182,6 +215,7 @@ gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self, default: g_assert_not_reached (); + case GSK_VULKAN_OP_BIND_MVP: break; } } @@ -237,6 +271,9 @@ gsk_vulkan_render_pass_collect_vertices (GskVulkanRenderPass *self, default: g_assert_not_reached (); + case GSK_VULKAN_OP_BIND_MVP: + op->vertex_offset = 0; + op->vertex_count = 0; break; } @@ -268,6 +305,7 @@ gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self, default: g_assert_not_reached (); + case GSK_VULKAN_OP_BIND_MVP: break; } } @@ -276,12 +314,10 @@ gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self, void gsk_vulkan_render_pass_draw (GskVulkanRenderPass *self, GskVulkanRender *render, - const graphene_matrix_t *parent_mvp, GskVulkanPipeline *pipeline, VkCommandBuffer command_buffer) { GskVulkanRenderOp *op; - graphene_matrix_t transform, mvp; float float_matrix[16]; guint i; @@ -289,30 +325,41 @@ gsk_vulkan_render_pass_draw (GskVulkanRenderPass *self, { op = &g_array_index (self->render_ops, GskVulkanRenderOp, i); - vkCmdBindDescriptorSets (command_buffer, - VK_PIPELINE_BIND_POINT_GRAPHICS, - gsk_vulkan_pipeline_get_pipeline_layout (pipeline), - 0, - 1, - (VkDescriptorSet[1]) { - gsk_vulkan_render_get_descriptor_set (render, op->descriptor_set_index) - }, - 0, - NULL); + switch (op->type) + { + case GSK_VULKAN_OP_FALLBACK: + case GSK_VULKAN_OP_SURFACE: + case GSK_VULKAN_OP_TEXTURE: + vkCmdBindDescriptorSets (command_buffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + gsk_vulkan_pipeline_get_pipeline_layout (pipeline), + 0, + 1, + (VkDescriptorSet[1]) { + gsk_vulkan_render_get_descriptor_set (render, op->descriptor_set_index) + }, + 0, + NULL); - gsk_render_node_get_transform (op->node, &transform); - graphene_matrix_multiply (&transform, parent_mvp, &mvp); - graphene_matrix_to_float (&mvp, float_matrix); + vkCmdDraw (command_buffer, + op->vertex_count, 1, + op->vertex_offset, 0); + break; - vkCmdPushConstants (command_buffer, - gsk_vulkan_pipeline_get_pipeline_layout (pipeline), - VK_SHADER_STAGE_VERTEX_BIT, - 0, - sizeof (float_matrix), - &float_matrix); + case GSK_VULKAN_OP_BIND_MVP: + graphene_matrix_to_float (&op->mvp, float_matrix); + vkCmdPushConstants (command_buffer, + gsk_vulkan_pipeline_get_pipeline_layout (pipeline), + VK_SHADER_STAGE_VERTEX_BIT, + 0, + sizeof (float_matrix), + &float_matrix); - vkCmdDraw (command_buffer, - op->vertex_count, 1, - op->vertex_offset, 0); + break; + + default: + g_assert_not_reached (); + break; + } } } diff --git a/gsk/gskvulkanrenderpassprivate.h b/gsk/gskvulkanrenderpassprivate.h index 1cc826d588..5bb8d0193f 100644 --- a/gsk/gskvulkanrenderpassprivate.h +++ b/gsk/gskvulkanrenderpassprivate.h @@ -13,8 +13,9 @@ typedef struct _GskVulkanRenderPass GskVulkanRenderPass; GskVulkanRenderPass * gsk_vulkan_render_pass_new (GdkVulkanContext *context); void gsk_vulkan_render_pass_free (GskVulkanRenderPass *self); -void gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self, +void gsk_vulkan_render_pass_add (GskVulkanRenderPass *self, GskVulkanRender *render, + const graphene_matrix_t*mvp, GskRenderNode *node); void gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self, @@ -31,7 +32,6 @@ void gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulk GskVulkanRender *render); void gsk_vulkan_render_pass_draw (GskVulkanRenderPass *self, GskVulkanRender *render, - const graphene_matrix_t*root_mvp, GskVulkanPipeline *pipeline, VkCommandBuffer command_buffer); diff --git a/gtk/gtkrendericon.c b/gtk/gtkrendericon.c index 409e940988..0304f0d02f 100644 --- a/gtk/gtkrendericon.c +++ b/gtk/gtkrendericon.c @@ -96,9 +96,9 @@ gtk_css_style_snapshot_icon (GtkCssStyle *style, GtkCssImageBuiltinType builtin_type) { const GtkCssValue *shadows, *transform; - graphene_matrix_t transform_matrix, m1, m2, m3, saved_matrix; - GtkCssImage *image; static gboolean shadow_warning; + graphene_matrix_t transform_matrix; + GtkCssImage *image; g_return_if_fail (GTK_IS_CSS_STYLE (style)); g_return_if_fail (snapshot != NULL); @@ -113,23 +113,39 @@ gtk_css_style_snapshot_icon (GtkCssStyle *style, if (!gtk_css_transform_value_get_matrix (transform, &transform_matrix)) return; - graphene_matrix_init_from_matrix (&saved_matrix, gtk_snapshot_get_transform (snapshot)); - - /* XXX: Implement -gtk-icon-transform-origin instead of hardcoding "50% 50%" here */ - graphene_matrix_init_translate (&m1, &GRAPHENE_POINT3D_INIT(width / 2.0, height / 2.0, 0)); - graphene_matrix_multiply (&transform_matrix, &m1, &m3); - graphene_matrix_init_translate (&m2, &GRAPHENE_POINT3D_INIT(- width / 2.0, - height / 2.0, 0)); - graphene_matrix_multiply (&m2, &m3, &m1); - gtk_snapshot_transform (snapshot, &m1); - if (!_gtk_css_shadows_value_is_none (shadows) && !shadow_warning) { g_warning ("Painting shadows not implemented for textures yet."); shadow_warning = TRUE; } - gtk_css_image_builtin_snapshot (image, snapshot, width, height, builtin_type); - gtk_snapshot_set_transform (snapshot, &saved_matrix); + if (graphene_matrix_is_identity (&transform_matrix)) + { + gtk_css_image_builtin_snapshot (image, snapshot, width, height, builtin_type); + } + else + { + graphene_matrix_t m1, m2, m3; + GskRenderNode *transform_node, *container_node; + double offset_x, offset_y; + + gtk_snapshot_get_offset (snapshot, &offset_x, &offset_y); + /* XXX: Implement -gtk-icon-transform-origin instead of hardcoding "50% 50%" here */ + graphene_matrix_init_translate (&m1, &GRAPHENE_POINT3D_INIT(offset_x + width / 2.0, offset_y + height / 2.0, 0)); + graphene_matrix_multiply (&transform_matrix, &m1, &m3); + graphene_matrix_init_translate (&m2, &GRAPHENE_POINT3D_INIT(- width / 2.0, - height / 2.0, 0)); + graphene_matrix_multiply (&m2, &m3, &m1); + + container_node = gsk_container_node_new (); + gsk_render_node_set_name (container_node, "CSS Icon Transform Container"); + transform_node = gsk_transform_node_new (container_node, &m1); + gsk_render_node_set_name (transform_node, "CSS Icon Transform"); + gtk_snapshot_append_node (snapshot, transform_node); + + gtk_snapshot_push_node (snapshot, container_node); + gtk_css_image_builtin_snapshot (image, snapshot, width, height, builtin_type); + gtk_snapshot_pop (snapshot); + } } static gboolean @@ -253,9 +269,9 @@ gtk_css_style_snapshot_icon_texture (GtkCssStyle *style, double texture_scale) { const GtkCssValue *shadows, *transform; - graphene_matrix_t transform_matrix, translate, matrix, saved_matrix; + graphene_matrix_t transform_matrix; graphene_rect_t bounds; - GskRenderNode *node; + GskRenderNode *icon_node, *transform_node; double width, height; static gboolean shadow_warning; @@ -272,26 +288,47 @@ gtk_css_style_snapshot_icon_texture (GtkCssStyle *style, if (!gtk_css_transform_value_get_matrix (transform, &transform_matrix)) return; - graphene_matrix_init_from_matrix (&saved_matrix, gtk_snapshot_get_transform (snapshot)); - - /* XXX: Implement -gtk-icon-transform-origin instead of hardcoding "50% 50%" here */ - graphene_matrix_init_translate (&translate, &GRAPHENE_POINT3D_INIT(width / 2.0, height / 2.0, 0)); - graphene_matrix_multiply (&transform_matrix, &translate, &matrix); - graphene_matrix_translate (&matrix, &GRAPHENE_POINT3D_INIT(- width / 2.0, - height / 2.0, 0)); - graphene_matrix_scale (&matrix, 1.0 / texture_scale, 1.0 / texture_scale, 1); - gtk_snapshot_transform (snapshot, &matrix); - - graphene_rect_init (&bounds, 0, 0, gsk_texture_get_width (texture), gsk_texture_get_height (texture)); - - node = gsk_texture_node_new (texture, &bounds); - gsk_render_node_set_name (node, "Icon"); - gtk_snapshot_append_node (snapshot, node); if (!_gtk_css_shadows_value_is_none (shadows) && !shadow_warning) { g_warning ("Painting shadows not implemented for textures yet."); shadow_warning = TRUE; } - gsk_render_node_unref (node); - gtk_snapshot_set_transform (snapshot, &saved_matrix); + if (graphene_matrix_is_identity (&transform_matrix)) + { + double offset_x, offset_y; + + gtk_snapshot_get_offset (snapshot, &offset_x, &offset_y); + graphene_rect_init (&bounds, + offset_x, offset_y, + gsk_texture_get_width (texture) / texture_scale, + gsk_texture_get_height (texture) / texture_scale); + icon_node = gsk_texture_node_new (texture, &bounds); + gsk_render_node_set_name (icon_node, "Icon"); + + gtk_snapshot_append_node (snapshot, icon_node); + } + else + { + graphene_matrix_t translate, matrix; + double offset_x, offset_y; + + gtk_snapshot_get_offset (snapshot, &offset_x, &offset_y); + /* XXX: Implement -gtk-icon-transform-origin instead of hardcoding "50% 50%" here */ + graphene_matrix_init_translate (&translate, &GRAPHENE_POINT3D_INIT(offset_x + width / 2.0, offset_y + height / 2.0, 0)); + graphene_matrix_multiply (&transform_matrix, &translate, &matrix); + graphene_matrix_translate (&matrix, &GRAPHENE_POINT3D_INIT(- width / 2.0, - height / 2.0, 0)); + graphene_matrix_scale (&matrix, 1.0 / texture_scale, 1.0 / texture_scale, 1); + + graphene_rect_init (&bounds, 0, 0, gsk_texture_get_width (texture), gsk_texture_get_height (texture)); + icon_node = gsk_texture_node_new (texture, &bounds); + gsk_render_node_set_name (icon_node, "Icon"); + + transform_node = gsk_transform_node_new (icon_node, &matrix); + gsk_render_node_set_name (transform_node, "Icon Transform"); + gtk_snapshot_append_node (snapshot, transform_node); + + gsk_render_node_unref (icon_node); + gsk_render_node_unref (transform_node); + } } diff --git a/gtk/gtksnapshot.c b/gtk/gtksnapshot.c index 63d5a6a7d5..946c308fef 100644 --- a/gtk/gtksnapshot.c +++ b/gtk/gtksnapshot.c @@ -41,7 +41,7 @@ * transformations. * * The node at the top of the stack is the the one that gtk_snapshot_append_node() - * operates on. Use the gtk_snapshot_push_() and gtk_snapshot_pop() functions to + * operates on. Use the gtk_snapshot_push() and gtk_snapshot_pop() functions to * change the current node. * * The only way to obtain a #GtkSnapshot object is as an argument to @@ -58,7 +58,6 @@ gtk_snapshot_state_new (GtkSnapshotState *parent, state->node = node; state->parent = parent; - graphene_matrix_init_identity (&state->transform); return state; } @@ -69,33 +68,6 @@ gtk_snapshot_state_free (GtkSnapshotState *state) g_slice_free (GtkSnapshotState, state); } -static void -gtk_snapshot_state_set_transform (GtkSnapshotState *state, - const graphene_matrix_t *transform) -{ - graphene_matrix_init_from_matrix (&state->transform, transform); - - state->world_is_valid = FALSE; -} - -static const graphene_matrix_t * -gtk_snapshot_state_get_world_transform (GtkSnapshotState *state) -{ - if (!state->world_is_valid) - { - if (state->parent) - graphene_matrix_multiply (gtk_snapshot_state_get_world_transform (state->parent), - &state->transform, - &state->world_transform); - else - graphene_matrix_init_from_matrix (&state->world_transform, &state->transform); - - state->world_is_valid = TRUE; - } - - return &state->world_transform; -} - void gtk_snapshot_init (GtkSnapshot *snapshot, GskRenderer *renderer, @@ -147,8 +119,8 @@ gtk_snapshot_finish (GtkSnapshot *snapshot) * @snapshot: a #GtkSnapshot * @node: the render node to push * - * Appends @node to the current render node of @snapshot, - * and makes @node the new current render node. + * Makes @node the new current render node. You are responsible for adding + * @node to the snapshot. * * Since: 3.90 */ @@ -158,8 +130,6 @@ gtk_snapshot_push_node (GtkSnapshot *snapshot, { g_return_if_fail (gsk_render_node_get_node_type (node) == GSK_CONTAINER_NODE); - gtk_snapshot_append_node (snapshot, node); - snapshot->state = gtk_snapshot_state_new (snapshot->state, node); } @@ -198,6 +168,7 @@ gtk_snapshot_push (GtkSnapshot *snapshot, g_free (str); } + gtk_snapshot_append_node (snapshot, node); gtk_snapshot_push_node (snapshot, node); gsk_render_node_unref (node); } @@ -245,45 +216,6 @@ gtk_snapshot_get_renderer (const GtkSnapshot *snapshot) return snapshot->renderer; } -/** - * gtk_snapshot_set_transform: - * @snapshot: a #GtkSnapshot - * @transform: a transformation matrix - * - * Replaces the current transformation with the given @transform. - * - * Since: 3.90 - */ -void -gtk_snapshot_set_transform (GtkSnapshot *snapshot, - const graphene_matrix_t *transform) -{ - g_return_if_fail (snapshot->state != NULL); - - gtk_snapshot_state_set_transform (snapshot->state, transform); -} - -/** - * gtk_snapshot_transform: - * @snapshot: a #GtkSnapshot - * @transform: a transformation matrix - * - * Appends @transform to the current transformation. - * - * Since: 3.90 - */ -void -gtk_snapshot_transform (GtkSnapshot *snapshot, - const graphene_matrix_t *transform) -{ - graphene_matrix_t result; - - g_return_if_fail (snapshot->state != NULL); - - graphene_matrix_multiply (transform, &snapshot->state->transform, &result); - gtk_snapshot_state_set_transform (snapshot->state, &result); -} - /** * gtk_snapshot_translate_2d: * @snapshot: a $GtkSnapshot @@ -299,12 +231,37 @@ gtk_snapshot_translate_2d (GtkSnapshot *snapshot, int x, int y) { - graphene_matrix_t transform; - graphene_point3d_t point; + snapshot->state->translate_x += x; + snapshot->state->translate_y += y; +} - graphene_point3d_init (&point, x, y, 0); - graphene_matrix_init_translate (&transform, &point); - gtk_snapshot_transform (snapshot, &transform); +/** + * gtk_snapshot_get_offset: + * @snapshot: a #GtkSnapshot + * @x: (out allow-none): return location for x offset + * @y: (out allow-none): return location for y offset + * + * Queries the offset managed by @snapshot. This offset is the + * accumulated sum of calls to gtk_snapshot_translate_2d(). + * + * Use this offset to determine how to offset nodes that you + * manually add to the snapshot using + * gtk_snapshot_append_node(). + * + * Note that other functions that add nodes for you, such as + * gtk_snapshot_append_cairo_node() will add this offset for + * you. + **/ +void +gtk_snapshot_get_offset (GtkSnapshot *snapshot, + double *x, + double *y) +{ + if (x) + *x = snapshot->state->translate_x; + + if (y) + *y = snapshot->state->translate_y; } /** @@ -327,7 +284,6 @@ gtk_snapshot_append_node (GtkSnapshot *snapshot, if (snapshot->state) { gsk_container_node_append_child (snapshot->state->node, node); - gsk_render_node_set_transform (node, &snapshot->state->transform); } else { @@ -357,11 +313,14 @@ gtk_snapshot_append_cairo_node (GtkSnapshot *snapshot, ...) { GskRenderNode *node; + graphene_rect_t real_bounds; + cairo_t *cr; g_return_val_if_fail (snapshot != NULL, NULL); g_return_val_if_fail (bounds != NULL, NULL); - node = gsk_cairo_node_new (bounds); + graphene_rect_offset_r (bounds, snapshot->state->translate_x, snapshot->state->translate_y, &real_bounds); + node = gsk_cairo_node_new (&real_bounds); if (name) { @@ -380,7 +339,11 @@ gtk_snapshot_append_cairo_node (GtkSnapshot *snapshot, gtk_snapshot_append_node (snapshot, node); gsk_render_node_unref (node); - return gsk_cairo_node_get_draw_context (node, snapshot->renderer); + cr = gsk_cairo_node_get_draw_context (node, snapshot->renderer); + + cairo_translate (cr, snapshot->state->translate_x, snapshot->state->translate_y); + + return cr; } static void @@ -408,22 +371,11 @@ gboolean gtk_snapshot_clips_rect (GtkSnapshot *snapshot, const graphene_rect_t *bounds) { + graphene_rect_t offset_bounds; cairo_rectangle_int_t rect; - if (snapshot->state) - { - const graphene_matrix_t *world; - graphene_rect_t transformed; - - world = gtk_snapshot_state_get_world_transform (snapshot->state); - - graphene_matrix_transform_bounds (world, bounds, &transformed); - rectangle_init_from_graphene (&rect, &transformed); - } - else - { - rectangle_init_from_graphene (&rect, bounds); - } + graphene_rect_offset_r (bounds, snapshot->state->translate_x, snapshot->state->translate_y, &offset_bounds); + rectangle_init_from_graphene (&rect, &offset_bounds); return cairo_region_contains_rectangle (snapshot->clip_region, &rect) == CAIRO_REGION_OVERLAP_OUT; } diff --git a/gtk/gtksnapshot.h b/gtk/gtksnapshot.h index e79d7134db..6acb5aa50a 100644 --- a/gtk/gtksnapshot.h +++ b/gtk/gtksnapshot.h @@ -49,16 +49,14 @@ void gtk_snapshot_push_node (GtkSnapshot GDK_AVAILABLE_IN_3_90 void gtk_snapshot_pop (GtkSnapshot *snapshot); -GDK_AVAILABLE_IN_3_90 -void gtk_snapshot_set_transform (GtkSnapshot *snapshot, - const graphene_matrix_t *transform); -GDK_AVAILABLE_IN_3_90 -void gtk_snapshot_transform (GtkSnapshot *snapshot, - const graphene_matrix_t *transform); GDK_AVAILABLE_IN_3_90 void gtk_snapshot_translate_2d (GtkSnapshot *snapshot, int x, int y); +GDK_AVAILABLE_IN_3_90 +void gtk_snapshot_get_offset (GtkSnapshot *snapshot, + double *x, + double *y); GDK_AVAILABLE_IN_3_90 void gtk_snapshot_append_node (GtkSnapshot *snapshot, diff --git a/gtk/gtksnapshotprivate.h b/gtk/gtksnapshotprivate.h index 2f7096287f..74fbf9f5f8 100644 --- a/gtk/gtksnapshotprivate.h +++ b/gtk/gtksnapshotprivate.h @@ -29,9 +29,8 @@ struct _GtkSnapshotState { GskRenderNode *node; - graphene_matrix_t transform; - graphene_matrix_t world_transform; - guint world_is_valid : 1; + double translate_x; + double translate_y; }; struct _GtkSnapshot { @@ -49,12 +48,6 @@ void gtk_snapshot_init (GtkSnapshot *state, ...) G_GNUC_PRINTF (4, 5); GskRenderNode * gtk_snapshot_finish (GtkSnapshot *state); -static inline const graphene_matrix_t * -gtk_snapshot_get_transform (const GtkSnapshot *snapshot) -{ - return &snapshot->state->transform; -} - G_END_DECLS #endif /* __GTK_SNAPSHOT_PRIVATE_H__ */ diff --git a/gtk/inspector/gtktreemodelrendernode.c b/gtk/inspector/gtktreemodelrendernode.c index 5f15586f8c..8bfbfe2855 100644 --- a/gtk/inspector/gtktreemodelrendernode.c +++ b/gtk/inspector/gtktreemodelrendernode.c @@ -525,6 +525,10 @@ append_node (GtkTreeModelRenderNode *nodemodel, /* no children */ break; + case GSK_TRANSFORM_NODE: + append_node (nodemodel, gsk_transform_node_get_child (node), priv->nodes->len - 1); + break; + case GSK_CONTAINER_NODE: { gint elt_index; diff --git a/gtk/inspector/recorder.c b/gtk/inspector/recorder.c index 11a0b10ab4..659921c242 100644 --- a/gtk/inspector/recorder.c +++ b/gtk/inspector/recorder.c @@ -132,36 +132,13 @@ static void populate_render_node_properties (GtkListStore *store, GskRenderNode *node) { - graphene_matrix_t m; graphene_rect_t bounds; - GString *s; int i; char *tmp; GEnumClass *class; gtk_list_store_clear (store); - gsk_render_node_get_transform (node, &m); - - s = g_string_new (""); - for (i = 0; i < 4; i++) - { - if (i > 0) - g_string_append (s, "\n"); - g_string_append_printf (s, "| %+.6f %+.6f %+.6f %+.6f |", - graphene_matrix_get_value (&m, i, 0), - graphene_matrix_get_value (&m, i, 1), - graphene_matrix_get_value (&m, i, 2), - graphene_matrix_get_value (&m, i, 3)); - } - - gtk_list_store_insert_with_values (store, NULL, -1, - 0, "Transform", - 1, s->str, - -1); - - g_string_free (s, TRUE); - gsk_render_node_get_bounds (node, &bounds); tmp = g_strdup_printf ("%.6f x %.6f + %.6f + %.6f",