[gtk+] gsk: Add GskColorMatrixNode
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] gsk: Add GskColorMatrixNode
- Date: Sat, 31 Dec 2016 01:57:39 +0000 (UTC)
commit 7540702cf0196cf4890de87f4225165a5f2f53f2
Author: Benjamin Otte <otte redhat com>
Date: Sat Dec 31 01:13:19 2016 +0100
gsk: Add GskColorMatrixNode
This node essentially implements the feColorMatrix SVG filter. I got the
idea yesterday after looking at the opacity implementation.
It can be used for opacity (not sure if we want to) and to implement a
bunch of the CSS filters.
docs/reference/gsk/gsk4-sections.txt | 1 +
gsk/gskenums.h | 1 +
gsk/gskrendernode.h | 5 +
gsk/gskrendernodeimpl.c | 246 ++++++++++++++++++++++++++++++++
gsk/gskrendernodeprivate.h | 4 +
gtk/inspector/gtktreemodelrendernode.c | 4 +
gtk/inspector/recorder.c | 2 +
7 files changed, 263 insertions(+), 0 deletions(-)
---
diff --git a/docs/reference/gsk/gsk4-sections.txt b/docs/reference/gsk/gsk4-sections.txt
index a56cd4a..a74d4ad 100644
--- a/docs/reference/gsk/gsk4-sections.txt
+++ b/docs/reference/gsk/gsk4-sections.txt
@@ -55,6 +55,7 @@ gsk_transform_node_new
gsk_transform_node_get_child
gsk_opacity_node_new
gsk_opacity_node_get_child
+gsk_color_matrix_node_new
gsk_clip_node_new
gsk_clip_node_get_child
gsk_rounded_clip_node_new
diff --git a/gsk/gskenums.h b/gsk/gskenums.h
index 9199782..060febb 100644
--- a/gsk/gskenums.h
+++ b/gsk/gskenums.h
@@ -61,6 +61,7 @@ typedef enum {
GSK_OUTSET_SHADOW_NODE,
GSK_TRANSFORM_NODE,
GSK_OPACITY_NODE,
+ GSK_COLOR_MATRIX_NODE,
GSK_CLIP_NODE,
GSK_ROUNDED_CLIP_NODE,
GSK_SHADOW_NODE,
diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h
index 649dc69..e4a75ab 100644
--- a/gsk/gskrendernode.h
+++ b/gsk/gskrendernode.h
@@ -135,6 +135,11 @@ GDK_AVAILABLE_IN_3_90
GskRenderNode * gsk_opacity_node_get_child (GskRenderNode *node);
GDK_AVAILABLE_IN_3_90
+GskRenderNode * gsk_color_matrix_node_new (GskRenderNode *child,
+ const graphene_matrix_t *color_matrix,
+ const graphene_vec4_t *color_offset);
+
+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 6a632f0..61d504e 100644
--- a/gsk/gskrendernodeimpl.c
+++ b/gsk/gskrendernodeimpl.c
@@ -2336,6 +2336,251 @@ gsk_opacity_node_get_opacity (GskRenderNode *node)
return self->opacity;
}
+/*** GSK_COLOR_MATRIX_NODE ***/
+
+typedef struct _GskColorMatrixNode GskColorMatrixNode;
+
+struct _GskColorMatrixNode
+{
+ GskRenderNode render_node;
+
+ GskRenderNode *child;
+ graphene_matrix_t color_matrix;
+ graphene_vec4_t color_offset;
+};
+
+static void
+gsk_color_matrix_node_finalize (GskRenderNode *node)
+{
+ GskColorMatrixNode *self = (GskColorMatrixNode *) node;
+
+ gsk_render_node_unref (self->child);
+}
+
+static void
+gsk_color_matrix_node_draw (GskRenderNode *node,
+ cairo_t *cr)
+{
+ GskColorMatrixNode *self = (GskColorMatrixNode *) node;
+ cairo_pattern_t *pattern;
+ cairo_surface_t *surface, *image_surface;
+ graphene_vec4_t pixel;
+ guint32* pixel_data;
+ guchar *data;
+ gsize x, y, width, height, stride;
+ float alpha;
+
+ cairo_save (cr);
+
+ /* clip so the push_group() creates a smaller surface */
+ cairo_rectangle (cr, node->bounds.origin.x, node->bounds.origin.y,
+ node->bounds.size.width, node->bounds.size.height);
+ cairo_clip (cr);
+
+ cairo_push_group (cr);
+
+ gsk_render_node_draw (self->child, cr);
+
+ pattern = cairo_pop_group (cr);
+ cairo_pattern_get_surface (pattern, &surface);
+ image_surface = cairo_surface_map_to_image (surface, NULL);
+
+ data = cairo_image_surface_get_data (image_surface);
+ width = cairo_image_surface_get_width (image_surface);
+ height = cairo_image_surface_get_height (image_surface);
+ stride = cairo_image_surface_get_stride (image_surface);
+
+ for (y = 0; y < height; y++)
+ {
+ pixel_data = (guint32 *) data;
+ for (x = 0; x < width; x++)
+ {
+ alpha = ((pixel_data[x] >> 24) & 0xFF) / 255.0;
+
+ if (alpha == 0)
+ {
+ graphene_vec4_init (&pixel, 0.0, 0.0, 0.0, 0.0);
+ }
+ else
+ {
+ graphene_vec4_init (&pixel,
+ ((pixel_data[x] >> 16) & 0xFF) / (255.0 * alpha),
+ ((pixel_data[x] >> 8) & 0xFF) / (255.0 * alpha),
+ ( pixel_data[x] & 0xFF) / (255.0 * alpha),
+ alpha);
+ graphene_matrix_transform_vec4 (&self->color_matrix, &pixel, &pixel);
+ }
+
+ graphene_vec4_add (&pixel, &self->color_offset, &pixel);
+
+ alpha = graphene_vec4_get_w (&pixel);
+ if (alpha > 0.0)
+ {
+ alpha = MIN (alpha, 1.0);
+ pixel_data[x] = (((guint32) (alpha * 255)) << 24) |
+ (((guint32) (CLAMP (graphene_vec4_get_x (&pixel), 0, 1) * alpha * 255)) << 16)
|
+ (((guint32) (CLAMP (graphene_vec4_get_y (&pixel), 0, 1) * alpha * 255)) << 8)
|
+ ((guint32) (CLAMP (graphene_vec4_get_z (&pixel), 0, 1) * alpha * 255));
+ }
+ else
+ {
+ pixel_data[x] = 0;
+ }
+ }
+ data += stride;
+ }
+
+ cairo_surface_mark_dirty (image_surface);
+ cairo_surface_unmap_image (surface, image_surface);
+
+ cairo_set_source (cr, pattern);
+ cairo_paint (cr);
+
+ cairo_restore (cr);
+}
+
+#define GSK_COLOR_MATRIX_NODE_VARIANT_TYPE "(dddddddddddddddddddduv)"
+
+static GVariant *
+gsk_color_matrix_node_serialize (GskRenderNode *node)
+{
+ GskColorMatrixNode *self = (GskColorMatrixNode *) node;
+ float mat[16], vec[4];
+
+ graphene_matrix_to_float (&self->color_matrix, mat);
+ graphene_vec4_to_float (&self->color_offset, vec);
+
+ return g_variant_new (GSK_COLOR_MATRIX_NODE_VARIANT_TYPE,
+ (double) mat[0], (double) mat[1], (double) mat[2], (double) mat[3],
+ (double) mat[4], (double) mat[5], (double) mat[6], (double) mat[7],
+ (double) mat[8], (double) mat[9], (double) mat[10], (double) mat[11],
+ (double) mat[12], (double) mat[13], (double) mat[14], (double) mat[15],
+ (double) vec[0], (double) vec[1], (double) vec[2], (double) vec[3],
+ (guint32) gsk_render_node_get_node_type (self->child),
+ gsk_render_node_serialize_node (self->child));
+}
+
+static GskRenderNode *
+gsk_color_matrix_node_deserialize (GVariant *variant,
+ GError **error)
+{
+ double mat[16], vec[4];
+ guint32 child_type;
+ GVariant *child_variant;
+ GskRenderNode *result, *child;
+ graphene_matrix_t matrix;
+ graphene_vec4_t offset;
+
+ if (!check_variant_type (variant, GSK_COLOR_MATRIX_NODE_VARIANT_TYPE, error))
+ return NULL;
+
+ g_variant_get (variant, GSK_COLOR_MATRIX_NODE_VARIANT_TYPE,
+ &mat[0], &mat[1], &mat[2], &mat[3],
+ &mat[4], &mat[5], &mat[6], &mat[7],
+ &mat[8], &mat[9], &mat[10], &mat[11],
+ &mat[12], &mat[13], &mat[14], &mat[15],
+ &vec[0], &vec[1], &vec[2], &vec[3],
+ &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;
+
+ graphene_matrix_init_from_float (&matrix,
+ (float[16]) {
+ mat[0], mat[1], mat[2], mat[3],
+ mat[4], mat[5], mat[6], mat[7],
+ mat[8], mat[9], mat[10], mat[11],
+ mat[12], mat[13], mat[14], mat[15]
+ });
+ graphene_vec4_init (&offset, vec[0], vec[1], vec[2], vec[3]);
+
+ result = gsk_color_matrix_node_new (child, &matrix, &offset);
+
+ gsk_render_node_unref (child);
+
+ return result;
+}
+
+static const GskRenderNodeClass GSK_COLOR_MATRIX_NODE_CLASS = {
+ GSK_COLOR_MATRIX_NODE,
+ sizeof (GskColorMatrixNode),
+ "GskColorMatrixNode",
+ gsk_color_matrix_node_finalize,
+ gsk_color_matrix_node_draw,
+ gsk_color_matrix_node_serialize,
+ gsk_color_matrix_node_deserialize
+};
+
+/**
+ * gsk_color_matrix_node_new:
+ * @child: The node to draw
+ * @color_matrix: The matrix to apply
+ * @color_offset: Values to add to the color
+ *
+ * Creates a #GskRenderNode that will drawn the @child with reduced
+ * @color_matrix.
+ *
+ * In particular, the node will transform the operation
+ * pixel = color_matrix * pixel + color_offset
+ * for every pixel.
+ *
+ * Returns: A new #GskRenderNode
+ *
+ * Since: 3.90
+ */
+GskRenderNode *
+gsk_color_matrix_node_new (GskRenderNode *child,
+ const graphene_matrix_t *color_matrix,
+ const graphene_vec4_t *color_offset)
+{
+ GskColorMatrixNode *self;
+
+ g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL);
+
+ self = (GskColorMatrixNode *) gsk_render_node_new (&GSK_COLOR_MATRIX_NODE_CLASS, 0);
+
+ self->child = gsk_render_node_ref (child);
+ graphene_matrix_init_from_matrix (&self->color_matrix, color_matrix);
+ graphene_vec4_init_from_vec4 (&self->color_offset, color_offset);
+
+ graphene_rect_init_from_rect (&self->render_node.bounds, &child->bounds);
+
+ return &self->render_node;
+}
+
+GskRenderNode *
+gsk_color_matrix_node_get_child (GskRenderNode *node)
+{
+ GskColorMatrixNode *self = (GskColorMatrixNode *) node;
+
+ g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_COLOR_MATRIX_NODE), NULL);
+
+ return self->child;
+}
+
+const graphene_matrix_t *
+gsk_color_matrix_node_peek_color_matrix (GskRenderNode *node)
+{
+ GskColorMatrixNode *self = (GskColorMatrixNode *) node;
+
+ g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_COLOR_MATRIX_NODE), NULL);
+
+ return &self->color_matrix;
+}
+
+const graphene_vec4_t *
+gsk_color_matrix_node_peek_color_offset (GskRenderNode *node)
+{
+ GskColorMatrixNode *self = (GskColorMatrixNode *) node;
+
+ g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_COLOR_MATRIX_NODE), NULL);
+
+ return &self->color_offset;
+}
+
/*** GSK_CLIP_NODE ***/
typedef struct _GskClipNode GskClipNode;
@@ -3279,6 +3524,7 @@ static const GskRenderNodeClass *klasses[] = {
[GSK_OUTSET_SHADOW_NODE] = &GSK_OUTSET_SHADOW_NODE_CLASS,
[GSK_TRANSFORM_NODE] = &GSK_TRANSFORM_NODE_CLASS,
[GSK_OPACITY_NODE] = &GSK_OPACITY_NODE_CLASS,
+ [GSK_COLOR_MATRIX_NODE] = &GSK_COLOR_MATRIX_NODE_CLASS,
[GSK_CLIP_NODE] = &GSK_CLIP_NODE_CLASS,
[GSK_ROUNDED_CLIP_NODE] = &GSK_ROUNDED_CLIP_NODE_CLASS,
[GSK_SHADOW_NODE] = &GSK_SHADOW_NODE_CLASS,
diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h
index 7290263..90deb10 100644
--- a/gsk/gskrendernodeprivate.h
+++ b/gsk/gskrendernodeprivate.h
@@ -46,6 +46,10 @@ GskRenderNode * gsk_render_node_deserialize_node (GskRenderNodeType type, GVaria
double gsk_opacity_node_get_opacity (GskRenderNode *node);
+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);
+
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);
diff --git a/gtk/inspector/gtktreemodelrendernode.c b/gtk/inspector/gtktreemodelrendernode.c
index 1a37680..ddf6d21 100644
--- a/gtk/inspector/gtktreemodelrendernode.c
+++ b/gtk/inspector/gtktreemodelrendernode.c
@@ -541,6 +541,10 @@ append_node (GtkTreeModelRenderNode *nodemodel,
append_node (nodemodel, gsk_opacity_node_get_child (node), priv->nodes->len - 1);
break;
+ case GSK_COLOR_MATRIX_NODE:
+ append_node (nodemodel, gsk_color_matrix_node_get_child (node), priv->nodes->len - 1);
+ break;
+
case GSK_CLIP_NODE:
append_node (nodemodel, gsk_clip_node_get_child (node), priv->nodes->len - 1);
break;
diff --git a/gtk/inspector/recorder.c b/gtk/inspector/recorder.c
index 25f98a5..f6b1fc6 100644
--- a/gtk/inspector/recorder.c
+++ b/gtk/inspector/recorder.c
@@ -162,6 +162,8 @@ node_type_name (GskRenderNodeType type)
return "Transform";
case GSK_OPACITY_NODE:
return "Opacity";
+ case GSK_COLOR_MATRIX_NODE:
+ return "Color Matrix";
case GSK_CLIP_NODE:
return "Clip";
case GSK_ROUNDED_CLIP_NODE:
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]