summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2023-02-07 22:52:06 -0500
committerMatthias Clasen <mclasen@redhat.com>2023-02-11 15:09:38 -0500
commitb937c19dd4970b8c516505bfa43bdcc0260ca3e9 (patch)
treef8b2512ec413a927466717aa0c12ba57490a885d
parentcc43f5dcdec256f5a7a32ee14505dfb69981ec68 (diff)
downloadgtk+-b937c19dd4970b8c516505bfa43bdcc0260ca3e9.tar.gz
gsk: Introduce GskTextureScaleNode
-rw-r--r--gsk/broadway/gskbroadwayrenderer.c2
-rw-r--r--gsk/gl/gskglrenderjob.c4
-rw-r--r--gsk/gskenums.h2
-rw-r--r--gsk/gskrendernode.h13
-rw-r--r--gsk/gskrendernodeimpl.c202
-rw-r--r--gsk/vulkan/gskvulkanrenderpass.c3
-rw-r--r--gtk/inspector/recorder.c20
7 files changed, 246 insertions, 0 deletions
diff --git a/gsk/broadway/gskbroadwayrenderer.c b/gsk/broadway/gskbroadwayrenderer.c
index bfd7270f56..6fee960edf 100644
--- a/gsk/broadway/gskbroadwayrenderer.c
+++ b/gsk/broadway/gskbroadwayrenderer.c
@@ -250,6 +250,7 @@ collect_reused_child_nodes (GskRenderer *renderer,
/* Leaf nodes */
case GSK_TEXTURE_NODE:
+ case GSK_TEXTURE_SCALE_NODE:
case GSK_CAIRO_NODE:
case GSK_COLOR_NODE:
case GSK_BORDER_NODE:
@@ -845,6 +846,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
}
break; /* Fallback */
+ case GSK_TEXTURE_SCALE_NODE:
case GSK_TEXT_NODE:
case GSK_RADIAL_GRADIENT_NODE:
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
diff --git a/gsk/gl/gskglrenderjob.c b/gsk/gl/gskglrenderjob.c
index e30a1e1341..103f40c029 100644
--- a/gsk/gl/gskglrenderjob.c
+++ b/gsk/gl/gskglrenderjob.c
@@ -3762,6 +3762,10 @@ gsk_gl_render_job_visit_node (GskGLRenderJob *job,
gsk_gl_render_job_visit_texture_node (job, node);
break;
+ case GSK_TEXTURE_SCALE_NODE:
+ gsk_gl_render_job_visit_as_fallback (job, node);
+ break;
+
case GSK_TRANSFORM_NODE:
gsk_gl_render_job_visit_transform_node (job, node);
break;
diff --git a/gsk/gskenums.h b/gsk/gskenums.h
index 0dfeb0a0ea..0c92555cfd 100644
--- a/gsk/gskenums.h
+++ b/gsk/gskenums.h
@@ -35,6 +35,7 @@
* @GSK_CONIC_GRADIENT_NODE: A node drawing a conic gradient
* @GSK_BORDER_NODE: A node stroking a border around an area
* @GSK_TEXTURE_NODE: A node drawing a `GdkTexture`
+ * @GSK_TEXTURE_SCALE_NODE: A node drawing a `GdkTexture` scaled and filtered
* @GSK_INSET_SHADOW_NODE: A node drawing an inset shadow
* @GSK_OUTSET_SHADOW_NODE: A node drawing an outset shadow
* @GSK_TRANSFORM_NODE: A node that renders its child after applying a matrix transform
@@ -65,6 +66,7 @@ typedef enum {
GSK_CONIC_GRADIENT_NODE,
GSK_BORDER_NODE,
GSK_TEXTURE_NODE,
+ GSK_TEXTURE_SCALE_NODE,
GSK_INSET_SHADOW_NODE,
GSK_OUTSET_SHADOW_NODE,
GSK_TRANSFORM_NODE,
diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h
index 3fa1d057c2..fb6e1f51f6 100644
--- a/gsk/gskrendernode.h
+++ b/gsk/gskrendernode.h
@@ -142,6 +142,7 @@ GskRenderNode * gsk_render_node_deserialize (GBytes
#define GSK_TYPE_DEBUG_NODE (gsk_debug_node_get_type())
#define GSK_TYPE_COLOR_NODE (gsk_color_node_get_type())
#define GSK_TYPE_TEXTURE_NODE (gsk_texture_node_get_type())
+#define GSK_TYPE_TEXTURE_SCALE_NODE (gsk_texture_scale_node_get_type())
#define GSK_TYPE_LINEAR_GRADIENT_NODE (gsk_linear_gradient_node_get_type())
#define GSK_TYPE_REPEATING_LINEAR_GRADIENT_NODE (gsk_repeating_linear_gradient_node_get_type())
#define GSK_TYPE_RADIAL_GRADIENT_NODE (gsk_radial_gradient_node_get_type())
@@ -168,6 +169,7 @@ GskRenderNode * gsk_render_node_deserialize (GBytes
typedef struct _GskDebugNode GskDebugNode;
typedef struct _GskColorNode GskColorNode;
typedef struct _GskTextureNode GskTextureNode;
+typedef struct _GskTextureScaleNode GskTextureScaleNode;
typedef struct _GskLinearGradientNode GskLinearGradientNode;
typedef struct _GskRepeatingLinearGradientNode GskRepeatingLinearGradientNode;
typedef struct _GskRadialGradientNode GskRadialGradientNode;
@@ -217,6 +219,17 @@ GskRenderNode * gsk_texture_node_new (GdkTexture
GDK_AVAILABLE_IN_ALL
GdkTexture * gsk_texture_node_get_texture (const GskRenderNode *node) G_GNUC_PURE;
+GDK_AVAILABLE_IN_4_10
+GType gsk_texture_scale_node_get_type (void) G_GNUC_CONST;
+GDK_AVAILABLE_IN_4_10
+GskRenderNode * gsk_texture_scale_node_new (GdkTexture *texture,
+ const graphene_rect_t *bounds,
+ GskScalingFilter filter);
+GDK_AVAILABLE_IN_4_10
+GdkTexture * gsk_texture_scale_node_get_texture (const GskRenderNode *node) G_GNUC_PURE;
+GDK_AVAILABLE_IN_4_10
+GskScalingFilter gsk_texture_scale_node_get_filter (const GskRenderNode *node) G_GNUC_PURE;
+
GDK_AVAILABLE_IN_ALL
GType gsk_linear_gradient_node_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c
index cb747802ba..376d32cb4e 100644
--- a/gsk/gskrendernodeimpl.c
+++ b/gsk/gskrendernodeimpl.c
@@ -1582,6 +1582,191 @@ gsk_texture_node_new (GdkTexture *texture,
}
/* }}} */
+/* {{{ GSK_TEXTURE_SCALE_NODE */
+
+/**
+ * GskTextureScaleNode:
+ *
+ * A render node for a `GdkTexture`.
+ */
+struct _GskTextureScaleNode
+{
+ GskRenderNode render_node;
+
+ GdkTexture *texture;
+ GskScalingFilter filter;
+};
+
+static void
+gsk_texture_scale_node_finalize (GskRenderNode *node)
+{
+ GskTextureScaleNode *self = (GskTextureScaleNode *) node;
+ GskRenderNodeClass *parent_class = g_type_class_peek (g_type_parent (GSK_TYPE_TEXTURE_SCALE_NODE));
+
+ g_clear_object (&self->texture);
+
+ parent_class->finalize (node);
+}
+
+static void
+gsk_texture_scale_node_draw (GskRenderNode *node,
+ cairo_t *cr)
+{
+ GskTextureScaleNode *self = (GskTextureScaleNode *) node;
+ cairo_surface_t *surface;
+ cairo_pattern_t *pattern;
+ cairo_matrix_t matrix;
+ cairo_filter_t filters[] = {
+ CAIRO_FILTER_BILINEAR,
+ CAIRO_FILTER_NEAREST,
+ CAIRO_FILTER_GOOD,
+ };
+ cairo_t *cr2;
+ cairo_surface_t *surface2;
+
+ surface2 = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ (int) ceilf (node->bounds.size.width),
+ (int) ceilf (node->bounds.size.height));
+ cr2 = cairo_create (surface2);
+
+ cairo_set_source_rgba (cr2, 0, 0, 0, 0);
+ cairo_paint (cr2);
+
+ surface = gdk_texture_download_surface (self->texture);
+ pattern = cairo_pattern_create_for_surface (surface);
+ cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
+
+ cairo_matrix_init_scale (&matrix,
+ gdk_texture_get_width (self->texture) / node->bounds.size.width,
+ gdk_texture_get_height (self->texture) / node->bounds.size.height);
+ cairo_pattern_set_matrix (pattern, &matrix);
+ cairo_pattern_set_filter (pattern, filters[self->filter]);
+
+ cairo_set_source (cr2, pattern);
+ cairo_pattern_destroy (pattern);
+ cairo_surface_destroy (surface);
+
+ cairo_rectangle (cr2, 0, 0, node->bounds.size.width, node->bounds.size.height);
+ cairo_fill (cr2);
+
+ cairo_destroy (cr2);
+
+ cairo_save (cr);
+
+ pattern = cairo_pattern_create_for_surface (surface2);
+ cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
+
+ cairo_matrix_init_identity (&matrix);
+ cairo_matrix_translate (&matrix,
+ -node->bounds.origin.x,
+ -node->bounds.origin.y);
+ cairo_pattern_set_matrix (pattern, &matrix);
+ cairo_set_source (cr, pattern);
+ cairo_pattern_destroy (pattern);
+ cairo_surface_destroy (surface2);
+
+ gsk_cairo_rectangle (cr, &node->bounds);
+ cairo_fill (cr);
+
+ cairo_restore (cr);
+}
+
+static void
+gsk_texture_scale_node_diff (GskRenderNode *node1,
+ GskRenderNode *node2,
+ cairo_region_t *region)
+{
+ GskTextureScaleNode *self1 = (GskTextureScaleNode *) node1;
+ GskTextureScaleNode *self2 = (GskTextureScaleNode *) node2;
+
+ if (graphene_rect_equal (&node1->bounds, &node2->bounds) &&
+ self1->texture == self2->texture &&
+ self1->filter == self2->filter)
+ return;
+
+ gsk_render_node_diff_impossible (node1, node2, region);
+}
+
+/**
+ * gsk_texture_scale_node_get_texture:
+ * @node: (type GskTextureNode): a `GskRenderNode` of type %GSK_TEXTURE_SCALE_NODE
+ *
+ * Retrieves the `GdkTexture` used when creating this `GskRenderNode`.
+ *
+ * Returns: (transfer none): the `GdkTexture`
+ *
+ * Since: 4.10
+ */
+GdkTexture *
+gsk_texture_scale_node_get_texture (const GskRenderNode *node)
+{
+ const GskTextureScaleNode *self = (const GskTextureScaleNode *) node;
+
+ return self->texture;
+}
+
+/**
+ * gsk_texture_scale_node_get_filter:
+ * @node: (type GskTextureNode): a `GskRenderNode` of type %GSK_TEXTURE_SCALE_NODE
+ *
+ * Retrieves the `GskScalingFilter` used when creating this `GskRenderNode`.
+ *
+ * Returns: (transfer none): the `GskScalingFilter`
+ *
+ * Since: 4.10
+ */
+GskScalingFilter
+gsk_texture_scale_node_get_filter (const GskRenderNode *node)
+{
+ const GskTextureScaleNode *self = (const GskTextureScaleNode *) node;
+
+ return self->filter;
+}
+
+/**
+ * gsk_texture_scale_node_new:
+ * @texture: the texture to scale
+ * @bounds: the size of the texture to scale to
+ * @filter: how to scale the texture
+ *
+ * Creates a node that scales the texture to the size given by the
+ * bounds and the filter and then places it at the bounds' position.
+ *
+ * This node is intended for tight control over scaling applied
+ * to a texture, such as in image editors and requires the
+ * application to be aware of the whole render tree as further
+ * transforms may be applied that conflict with the desired effect
+ * of this node.
+ *
+ * Returns: (transfer full) (type GskTextureScaleNode): A new `GskRenderNode`
+ *
+ * Since: 4.10
+ */
+GskRenderNode *
+gsk_texture_scale_node_new (GdkTexture *texture,
+ const graphene_rect_t *bounds,
+ GskScalingFilter filter)
+{
+ GskTextureScaleNode *self;
+ GskRenderNode *node;
+
+ g_return_val_if_fail (GDK_IS_TEXTURE (texture), NULL);
+ g_return_val_if_fail (bounds != NULL, NULL);
+
+ self = gsk_render_node_alloc (GSK_TEXTURE_SCALE_NODE);
+ node = (GskRenderNode *) self;
+ node->offscreen_for_opacity = FALSE;
+
+ self->texture = g_object_ref (texture);
+ graphene_rect_init_from_rect (&node->bounds, bounds);
+ self->filter = filter;
+
+ node->prefers_high_depth = gdk_memory_format_prefers_high_depth (gdk_texture_get_format (texture));
+
+ return node;
+}
+
+/* }}} */
/* {{{ GSK_INSET_SHADOW_NODE */
/**
@@ -5357,6 +5542,7 @@ GSK_DEFINE_RENDER_NODE_TYPE (gsk_repeating_radial_gradient_node, GSK_REPEATING_R
GSK_DEFINE_RENDER_NODE_TYPE (gsk_conic_gradient_node, GSK_CONIC_GRADIENT_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_border_node, GSK_BORDER_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_texture_node, GSK_TEXTURE_NODE)
+GSK_DEFINE_RENDER_NODE_TYPE (gsk_texture_scale_node, GSK_TEXTURE_SCALE_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_inset_shadow_node, GSK_INSET_SHADOW_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_outset_shadow_node, GSK_OUTSET_SHADOW_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_transform_node, GSK_TRANSFORM_NODE)
@@ -5539,6 +5725,22 @@ gsk_render_node_init_types_once (void)
{
const GskRenderNodeTypeInfo node_info =
{
+ GSK_TEXTURE_SCALE_NODE,
+ sizeof (GskTextureScaleNode),
+ NULL,
+ gsk_texture_scale_node_finalize,
+ gsk_texture_scale_node_draw,
+ NULL,
+ gsk_texture_scale_node_diff,
+ };
+
+ GType node_type = gsk_render_node_type_register_static (I_("GskTextureScaleNode"), &node_info);
+ gsk_render_node_types[GSK_TEXTURE_SCALE_NODE] = node_type;
+ }
+
+ {
+ const GskRenderNodeTypeInfo node_info =
+ {
GSK_INSET_SHADOW_NODE,
sizeof (GskInsetShadowNode),
NULL,
diff --git a/gsk/vulkan/gskvulkanrenderpass.c b/gsk/vulkan/gskvulkanrenderpass.c
index 48127e20b9..3008c42154 100644
--- a/gsk/vulkan/gskvulkanrenderpass.c
+++ b/gsk/vulkan/gskvulkanrenderpass.c
@@ -440,6 +440,9 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
g_array_append_val (self->render_ops, op);
return;
+ case GSK_TEXTURE_SCALE_NODE:
+ goto fallback;
+
case GSK_COLOR_NODE:
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
pipeline_type = GSK_VULKAN_PIPELINE_COLOR;
diff --git a/gtk/inspector/recorder.c b/gtk/inspector/recorder.c
index e33d058b05..53528a26cb 100644
--- a/gtk/inspector/recorder.c
+++ b/gtk/inspector/recorder.c
@@ -264,6 +264,7 @@ create_list_model_for_render_node (GskRenderNode *node)
case GSK_CAIRO_NODE:
case GSK_TEXT_NODE:
case GSK_TEXTURE_NODE:
+ case GSK_TEXTURE_SCALE_NODE:
case GSK_COLOR_NODE:
case GSK_LINEAR_GRADIENT_NODE:
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
@@ -402,6 +403,8 @@ node_type_name (GskRenderNodeType type)
return "Border";
case GSK_TEXTURE_NODE:
return "Texture";
+ case GSK_TEXTURE_SCALE_NODE:
+ return "Scaled Texture";
case GSK_INSET_SHADOW_NODE:
return "Inset Shadow";
case GSK_OUTSET_SHADOW_NODE:
@@ -476,6 +479,11 @@ node_name (GskRenderNode *node)
GdkTexture *texture = gsk_texture_node_get_texture (node);
return g_strdup_printf ("%dx%d Texture", gdk_texture_get_width (texture), gdk_texture_get_height (texture));
}
+ case GSK_TEXTURE_SCALE_NODE:
+ {
+ GdkTexture *texture = gsk_texture_node_get_texture (node);
+ return g_strdup_printf ("%dx%d Texture, Filter %d", gdk_texture_get_width (texture), gdk_texture_get_height (texture), gsk_texture_scale_node_get_filter (node));
+ }
}
}
@@ -933,6 +941,18 @@ populate_render_node_properties (GListStore *store,
}
break;
+ case GSK_TEXTURE_SCALE_NODE:
+ {
+ GdkTexture *texture = g_object_ref (gsk_texture_scale_node_get_texture (node));
+ GskScalingFilter filter = gsk_texture_scale_node_get_filter (node);
+ g_list_store_append (store, object_property_new ("Texture", "", texture));
+
+ tmp = g_enum_to_string (GSK_TYPE_SCALING_FILTER, filter);
+ add_text_row (store, "Filter", tmp);
+ g_free (tmp);
+ }
+ break;
+
case GSK_COLOR_NODE:
add_color_row (store, "Color", gsk_color_node_get_color (node));
break;