From 2dc85d7e5f1c22a54754b5efd13198c34f1bc2c1 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 8 Jun 2024 19:55:22 -0400 Subject: [PATCH] Add a color state node --- demos/node-editor/node-format.md | 9 ++ gsk/gl/gskglrenderjob.c | 6 + gsk/gpu/gskgpunodeprocessor.c | 24 ++++ gsk/gskenums.h | 9 ++ gsk/gskoffload.c | 4 + gsk/gskrendernode.h | 12 ++ gsk/gskrendernodeimpl.c | 160 +++++++++++++++++++++++++ gsk/gskrendernodeparser.c | 177 ++++++++++++++++++++++++++++ gsk/gskrendernodeprivate.h | 2 +- gtk/inspector/recorder.c | 15 +++ testsuite/gsk/gskrendernodeattach.c | 6 + tools/gtk-rendernode-tool-extract.c | 53 ++++++++- tools/gtk-rendernode-tool-info.c | 6 +- 13 files changed, 480 insertions(+), 3 deletions(-) diff --git a/demos/node-editor/node-format.md b/demos/node-editor/node-format.md index 14afb7d209..c953b90b0f 100644 --- a/demos/node-editor/node-format.md +++ b/demos/node-editor/node-format.md @@ -117,6 +117,15 @@ should be aware that the allowed values are meant to be used on 3D transformatio so their naming might appear awkward. However, it is always possible to use the matrix3d() production to specify all 16 values individually. +### color-state + +| property | syntax | default | printed | +| ----------- | ---------------- | ---------------------- | ----------- | +| bounds | `` | 50 | always | +| color-state | `|` | srgb | always | + +Creates a node like `gsk_color_state_node_new()` with the given properties. + ### conic-gradient | property | syntax | default | printed | diff --git a/gsk/gl/gskglrenderjob.c b/gsk/gl/gskglrenderjob.c index 10f4184da6..b7dc15f044 100644 --- a/gsk/gl/gskglrenderjob.c +++ b/gsk/gl/gskglrenderjob.c @@ -300,6 +300,7 @@ node_supports_2d_transform (const GskRenderNode *node) case GSK_FILL_NODE: case GSK_STROKE_NODE: case GSK_SUBSURFACE_NODE: + case GSK_COLOR_STATE_NODE: return TRUE; case GSK_SHADOW_NODE: @@ -357,6 +358,7 @@ node_supports_transform (const GskRenderNode *node) case GSK_FILL_NODE: case GSK_STROKE_NODE: case GSK_SUBSURFACE_NODE: + case GSK_COLOR_STATE_NODE: return TRUE; case GSK_SHADOW_NODE: @@ -4228,6 +4230,10 @@ gsk_gl_render_job_visit_node (GskGLRenderJob *job, gsk_gl_render_job_visit_subsurface_node (job, node); break; + case GSK_COLOR_STATE_NODE: + gsk_gl_render_job_visit_node (job, gsk_color_state_node_get_child (node)); + break; + case GSK_NOT_A_RENDER_NODE: default: g_assert_not_reached (); diff --git a/gsk/gpu/gskgpunodeprocessor.c b/gsk/gpu/gskgpunodeprocessor.c index dce0ddf397..765c4a5f23 100644 --- a/gsk/gpu/gskgpunodeprocessor.c +++ b/gsk/gpu/gskgpunodeprocessor.c @@ -1164,6 +1164,7 @@ gsk_gpu_node_processor_ubershader_instead_of_offscreen (GskGpuNodeProcessor *sel case GSK_BLEND_NODE: case GSK_TEXT_NODE: case GSK_MASK_NODE: + case GSK_COLOR_STATE_NODE: return TRUE; case GSK_CONTAINER_NODE: @@ -3801,6 +3802,23 @@ gsk_gpu_node_processor_create_subsurface_pattern (GskGpuPatternWriter *self, return gsk_gpu_node_processor_create_node_pattern (self, gsk_subsurface_node_get_child (node)); } +static void +gsk_gpu_node_processor_add_color_state_node (GskGpuNodeProcessor *self, + GskRenderNode *node) +{ + GskGpuImage *image; + GskRenderNode *child; + + child = gsk_color_state_node_get_child (node); + + image = gsk_gpu_node_processor_create_offscreen (self->frame, + &self->scale, + &node->bounds, + child); + + gsk_gpu_node_processor_image_op (self, image, &node->bounds, &node->bounds); +} + static void gsk_gpu_node_processor_add_container_node (GskGpuNodeProcessor *self, GskRenderNode *node) @@ -4028,6 +4046,12 @@ static const struct gsk_gpu_node_processor_add_subsurface_node, gsk_gpu_node_processor_create_subsurface_pattern, }, + [GSK_COLOR_STATE_NODE] = { + 0, + 0, + gsk_gpu_node_processor_add_color_state_node, + NULL, + }, }; static void diff --git a/gsk/gskenums.h b/gsk/gskenums.h index ba9dd011b2..c1ec0420ff 100644 --- a/gsk/gskenums.h +++ b/gsk/gskenums.h @@ -93,6 +93,14 @@ * Since: 4.14 */ +/** + * GSK_COLOR_STATE_NODE: + * + * A node that changes the compositing color state. + * + * Since: 4.16 + */ + typedef enum { GSK_NOT_A_RENDER_NODE = 0, GSK_CONTAINER_NODE, @@ -125,6 +133,7 @@ typedef enum { GSK_FILL_NODE, GSK_STROKE_NODE, GSK_SUBSURFACE_NODE, + GSK_COLOR_STATE_NODE, } GskRenderNodeType; /** diff --git a/gsk/gskoffload.c b/gsk/gskoffload.c index 0a3d7dd1bd..a250b12186 100644 --- a/gsk/gskoffload.c +++ b/gsk/gskoffload.c @@ -619,6 +619,10 @@ complex_clip: visit_node (self, gsk_debug_node_get_child (node)); break; + case GSK_COLOR_STATE_NODE: + visit_node (self, gsk_color_state_node_get_child (node)); + break; + case GSK_SUBSURFACE_NODE: { GdkSubsurface *subsurface = gsk_subsurface_node_get_subsurface (node); diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h index ed02edbbbe..91ca90db36 100644 --- a/gsk/gskrendernode.h +++ b/gsk/gskrendernode.h @@ -167,6 +167,7 @@ GskRenderNode * gsk_render_node_deserialize (GBytes #define GSK_TYPE_MASK_NODE (gsk_mask_node_get_type()) #define GSK_TYPE_GL_SHADER_NODE (gsk_gl_shader_node_get_type()) #define GSK_TYPE_SUBSURFACE_NODE (gsk_subsurface_node_get_type()) +#define GSK_TYPE_COLOR_STATE_NODE (gsk_color_state_node_get_type()) typedef struct _GskDebugNode GskDebugNode; typedef struct _GskColorNode GskColorNode; @@ -198,6 +199,7 @@ typedef struct _GskBlurNode GskBlurNode; typedef struct _GskMaskNode GskMaskNode; typedef struct _GskGLShaderNode GskGLShaderNode; typedef struct _GskSubsurfaceNode GskSubsurfaceNode; +typedef struct _GskColorStateNode GskColorStateNode; GDK_AVAILABLE_IN_ALL GType gsk_debug_node_get_type (void) G_GNUC_CONST; @@ -602,6 +604,16 @@ GskRenderNode * gsk_subsurface_node_get_child (const GskRender GDK_AVAILABLE_IN_4_14 gpointer gsk_subsurface_node_get_subsurface (const GskRenderNode *node); +GDK_AVAILABLE_IN_4_16 +GType gsk_color_state_node_get_type (void) G_GNUC_CONST; +GDK_AVAILABLE_IN_4_16 +GskRenderNode * gsk_color_state_node_new (GskRenderNode *child, + GdkColorState *color_state); +GDK_AVAILABLE_IN_4_16 +GskRenderNode * gsk_color_state_node_get_child (const GskRenderNode *node) G_GNUC_PURE; +GDK_AVAILABLE_IN_4_16 +GdkColorState * gsk_color_state_node_get_color_state (const GskRenderNode *node); + /** * GSK_VALUE_HOLDS_RENDER_NODE: * @value: a `GValue` diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index 04a28fbee6..1eb43df8c9 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -7171,6 +7171,160 @@ gsk_subsurface_node_get_subsurface (const GskRenderNode *node) return self->subsurface; } +/* }}} */ +/* {{{ GSK_COLOR_STATE_NODE */ + +/** + * GskColorStateNode: + * + * A render node that changes the compositing color state for its children. + * + * Since: 4.16 + */ +struct _GskColorStateNode +{ + GskRenderNode render_node; + + GskRenderNode *child; + GdkColorState *color_state; +}; + +static void +gsk_color_state_node_finalize (GskRenderNode *node) +{ + GskColorStateNode *self = (GskColorStateNode *) node; + GskRenderNodeClass *parent_class = g_type_class_peek (g_type_parent (GSK_TYPE_COLOR_STATE_NODE)); + + gsk_render_node_unref (self->child); + gdk_color_state_unref (self->color_state); + + parent_class->finalize (node); +} + +static void +gsk_color_state_node_draw (GskRenderNode *node, + cairo_t *cr) +{ + GskColorStateNode *self = (GskColorStateNode *) node; + + /* FIXME */ + gsk_render_node_draw (self->child, cr); +} + +static gboolean +gsk_color_state_node_can_diff (const GskRenderNode *node1, + const GskRenderNode *node2) +{ + GskColorStateNode *self1 = (GskColorStateNode *) node1; + GskColorStateNode *self2 = (GskColorStateNode *) node2; + + return gdk_color_state_equal (self1->color_state, self2->color_state); +} + +static void +gsk_color_state_node_diff (GskRenderNode *node1, + GskRenderNode *node2, + GskDiffData *data) +{ + GskColorStateNode *self1 = (GskColorStateNode *) node1; + GskColorStateNode *self2 = (GskColorStateNode *) node2; + + if (!gdk_color_state_equal (self1->color_state, self2->color_state)) + { + /* Shouldn't happen, can_diff() avoids this, but to be sure */ + gsk_render_node_diff_impossible (node1, node2, data); + } + else + { + gsk_render_node_diff (self1->child, self2->child, data); + } +} + +static void +gsk_color_state_node_class_init (gpointer g_class, + gpointer class_data) +{ + GskRenderNodeClass *node_class = g_class; + + node_class->node_type = GSK_COLOR_STATE_NODE; + + node_class->finalize = gsk_color_state_node_finalize; + node_class->draw = gsk_color_state_node_draw; + node_class->can_diff = gsk_color_state_node_can_diff; + node_class->diff = gsk_color_state_node_diff; +} + +/** + * gsk_color_state_node_new: (skip) + * @child: The child to composite in the new color state + * @color_state: the color state to use + * + * Creates a `GskRenderNode` that will change the compositing + * color state for its children. + * + * Returns: (transfer full) (type GskColorStateNode): A new `GskRenderNode` + * + * Since: 4.16 + */ +GskRenderNode * +gsk_color_state_node_new (GskRenderNode *child, + GdkColorState *color_state) +{ + GskColorStateNode *self; + GskRenderNode *node; + + g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL); + + self = gsk_render_node_alloc (GSK_COLOR_STATE_NODE); + node = (GskRenderNode *) self; + node->offscreen_for_opacity = child->offscreen_for_opacity; + + self->child = gsk_render_node_ref (child); + self->color_state = gdk_color_state_ref (color_state); + + gsk_rect_init_from_rect (&node->bounds, &child->bounds); + + node->preferred_depth = gsk_render_node_get_preferred_depth (child); + + return node; +} + +/** + * gsk_color_state_node_get_child: + * @node: (type GskColorStateNode): a debug `GskRenderNode` + * + * Gets the child node that is getting drawn by the given @node. + * + * Returns: (transfer none): the child `GskRenderNode` + * + * Since: 4.16 + */ +GskRenderNode * +gsk_color_state_node_get_child (const GskRenderNode *node) +{ + const GskColorStateNode *self = (const GskColorStateNode *) node; + + return self->child; +} + +/** + * gsk_color_state_node_get_color_state: (skip) + * @node: (type GskColorStateNode): a color state `GskRenderNode` + * + * Gets the color state that was set on this node. + * + * Returns: (transfer none): the color state + * + * Since: 4.16 + */ +GdkColorState * +gsk_color_state_node_get_color_state (const GskRenderNode *node) +{ + const GskColorStateNode *self = (const GskColorStateNode *) node; + + return self->color_state; +} + /* }}} */ GType gsk_render_node_types[GSK_RENDER_NODE_TYPE_N_TYPES]; @@ -7217,6 +7371,7 @@ GSK_DEFINE_RENDER_NODE_TYPE (gsk_mask_node, GSK_MASK_NODE) GSK_DEFINE_RENDER_NODE_TYPE (gsk_gl_shader_node, GSK_GL_SHADER_NODE) GSK_DEFINE_RENDER_NODE_TYPE (gsk_debug_node, GSK_DEBUG_NODE) GSK_DEFINE_RENDER_NODE_TYPE (gsk_subsurface_node, GSK_SUBSURFACE_NODE) +GSK_DEFINE_RENDER_NODE_TYPE (gsk_color_state_node, GSK_COLOR_STATE_NODE) static void gsk_render_node_init_types_once (void) @@ -7372,6 +7527,11 @@ gsk_render_node_init_types_once (void) sizeof (GskSubsurfaceNode), gsk_subsurface_node_class_init); gsk_render_node_types[GSK_SUBSURFACE_NODE] = node_type; + + node_type = gsk_render_node_type_register_static (I_("GskColorStateNode"), + sizeof (GskColorStateNode), + gsk_color_state_node_class_init); + gsk_render_node_types[GSK_COLOR_STATE_NODE] = node_type; } static void diff --git a/gsk/gskrendernodeparser.c b/gsk/gskrendernodeparser.c index b9fd5f873d..91b73c21f6 100644 --- a/gsk/gskrendernodeparser.c +++ b/gsk/gskrendernodeparser.c @@ -35,6 +35,7 @@ #include "gdk/gdkrgbaprivate.h" #include "gdk/gdktextureprivate.h" #include "gdk/gdkmemoryformatprivate.h" +#include "gdk/gdkcolorstateprivate.h" #include #include "gtk/css/gtkcssdataurlprivate.h" #include "gtk/css/gtkcssparserprivate.h" @@ -1477,6 +1478,101 @@ parse_color_node (GtkCssParser *parser, return gsk_color_node_new (&color, &bounds); } +static gboolean +parse_color_state (GtkCssParser *parser, + Context *context, + gpointer out_color_state) +{ + GdkColorState *color_state = NULL; + + if (gtk_css_parser_try_ident (parser, "srgb")) + color_state = gdk_color_state_get_srgb (); + else if (gtk_css_parser_try_ident (parser, "srgb-linear")) + color_state = gdk_color_state_get_srgb_linear (); + else if (gtk_css_parser_try_ident (parser, "hsl")) + color_state = gdk_color_state_get_hsl (); + else if (gtk_css_parser_try_ident (parser, "hwb")) + color_state = gdk_color_state_get_hwb (); + else if (gtk_css_parser_try_ident (parser, "oklab")) + color_state = gdk_color_state_get_oklab (); + else if (gtk_css_parser_try_ident (parser, "oklch")) + color_state = gdk_color_state_get_oklch (); + else if (gtk_css_parser_try_ident (parser, "xyz")) + color_state = gdk_color_state_get_xyz (); + else if (gtk_css_parser_try_ident (parser, "display-p3")) + color_state = gdk_color_state_get_display_p3 (); + else if (gtk_css_parser_try_ident (parser, "rec2020")) + color_state = gdk_color_state_get_rec2020 (); + else if (gtk_css_parser_try_ident (parser, "rec2100-pq")) + color_state = gdk_color_state_get_rec2100_pq (); + else if (gtk_css_parser_try_ident (parser, "rec2100-linear")) + color_state = gdk_color_state_get_rec2100_linear (); + else + { + char *url, *scheme, *mimetype; + GBytes *bytes; + GError *error = NULL; + + url = gtk_css_parser_consume_url (parser); + if (url == NULL) + return FALSE; + + scheme = g_uri_parse_scheme (url); + if (!scheme || g_ascii_strcasecmp (scheme, "data") != 0) + { + g_free (scheme); + g_free (url); + return FALSE; + } + g_free (scheme); + + bytes = gtk_css_data_url_parse (url, &mimetype, &error); + if (!bytes) + { + gtk_css_parser_error_value (parser, "Could not parse data url: %s", error->message); + g_error_free (error); + g_free (mimetype); + return FALSE; + } + g_free (url); + + if (g_strcmp0 (mimetype, "application/vnd.iccprofile") != 0) + { + gtk_css_parser_error_value (parser, "Wrong mimetype for color-state: %s", mimetype); + g_free (mimetype); + g_bytes_unref (bytes); + return FALSE; + } + g_free (mimetype); + + color_state = gdk_color_state_new_from_icc_profile (bytes, &error); + if (!color_state) + { + gtk_css_parser_error_value (parser, "Invalid ICC profile: %s", error->message); + g_error_free (error); + g_bytes_unref (bytes); + return FALSE; + } + g_bytes_unref (bytes); + } + + if (color_state == NULL) + { + gtk_css_parser_error_value (parser, "Invalid color-state"); + return FALSE; + } + + *((GdkColorState **) out_color_state) = color_state; + + return TRUE; +} + +static void +clear_color_state (gpointer inout_color_state) +{ + g_clear_pointer ((GdkColorState **) inout_color_state, gdk_color_state_unref); +} + static GskRenderNode * parse_linear_gradient_node_internal (GtkCssParser *parser, Context *context, @@ -2738,6 +2834,33 @@ parse_subsurface_node (GtkCssParser *parser, return result; } +static GskRenderNode * +parse_color_state_node (GtkCssParser *parser, + Context *context) +{ + GskRenderNode *child = NULL; + GdkColorState *color_state = NULL; + const Declaration declarations[] = { + { "child", parse_node, clear_node, &child }, + { "color-state", parse_color_state, clear_color_state, &color_state }, + }; + GskRenderNode *result; + + parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations)); + if (child == NULL) + child = create_default_render_node (); + + if (color_state == NULL) + color_state = gdk_color_state_get_srgb (); + + result = gsk_color_state_node_new (child, color_state); + + gsk_render_node_unref (child); + gdk_color_state_unref (color_state); + + return result; +} + static gboolean parse_node (GtkCssParser *parser, Context *context, @@ -2777,6 +2900,7 @@ parse_node (GtkCssParser *parser, { "glshader", parse_glshader_node }, { "mask", parse_mask_node }, { "subsurface", parse_subsurface_node }, + { "color-state", parse_color_state_node }, }; GskRenderNode **node_p = out_node; const GtkCssToken *token; @@ -3132,6 +3256,10 @@ printer_init_duplicates_for_node (Printer *printer, printer_init_duplicates_for_node (printer, gsk_subsurface_node_get_child (node)); break; + case GSK_COLOR_STATE_NODE: + printer_init_duplicates_for_node (printer, gsk_color_state_node_get_child (node)); + break; + default: case GSK_NOT_A_RENDER_NODE: g_assert_not_reached (); @@ -3866,6 +3994,40 @@ append_dash_param (Printer *p, g_string_append (p->str, ";\n"); } +static void +color_state_serialize (GdkColorState *cs, + Printer *p) +{ + if (GDK_IS_NAMED_COLOR_STATE (cs)) + { + g_string_append_printf (p->str, "%s", gdk_color_state_get_name (cs)); + return; + } + else if (GDK_IS_LCMS_COLOR_STATE (cs)) + { + GBytes *bytes; + + bytes = gdk_color_state_save_to_icc_profile (cs, NULL); + if (bytes) + { + const guchar *data; + gsize len; + char *b64; + + g_string_append (p->str, "url(\"data:application/vnc.iccprofile;base64,\\\n"); + data = g_bytes_get_data (bytes, &len); + b64 = base64_encode_with_linebreaks (data, len); + append_escaping_newlines (p->str, b64); + g_free (b64); + g_string_append (p->str, "\")"); + g_bytes_unref (bytes); + return; + } + } + + g_string_append (p->str, "srgb"); +} + static void render_node_print (Printer *p, GskRenderNode *node) @@ -4557,6 +4719,21 @@ render_node_print (Printer *p, } break; + case GSK_COLOR_STATE_NODE: + { + start_node (p, "color-state", node_name); + + _indent (p); + g_string_append (p->str, "color-state: "); + color_state_serialize (gsk_color_state_node_get_color_state (node), p); + g_string_append (p->str, ";\n"); + + append_node_param (p, "child", gsk_color_state_node_get_child (node)); + + end_node (p); + } + break; + default: g_error ("Unhandled node: %s", g_type_name_from_instance ((GTypeInstance *) node)); break; diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h index 9c8565cfb3..6287d7760b 100644 --- a/gsk/gskrendernodeprivate.h +++ b/gsk/gskrendernodeprivate.h @@ -14,7 +14,7 @@ typedef struct _GskRenderNodeClass GskRenderNodeClass; * We don't add an "n-types" value to avoid having to handle * it in every single switch. */ -#define GSK_RENDER_NODE_TYPE_N_TYPES (GSK_SUBSURFACE_NODE + 1) +#define GSK_RENDER_NODE_TYPE_N_TYPES (GSK_COLOR_STATE_NODE + 1) extern GType gsk_render_node_types[]; diff --git a/gtk/inspector/recorder.c b/gtk/inspector/recorder.c index 0f31e52322..e4beb5205e 100644 --- a/gtk/inspector/recorder.c +++ b/gtk/inspector/recorder.c @@ -59,6 +59,7 @@ #include "gtk/gtkdebug.h" #include "gtk/gtkbuiltiniconprivate.h" #include "gtk/gtkrendernodepaintableprivate.h" +#include "gdk/gdkcolorstateprivate.h" #include "recording.h" #include "renderrecording.h" @@ -373,6 +374,9 @@ create_list_model_for_render_node (GskRenderNode *node) case GSK_SUBSURFACE_NODE: return create_render_node_list_model ((GskRenderNode *[1]) { gsk_subsurface_node_get_child (node) }, 1); + + case GSK_COLOR_STATE_NODE: + return create_render_node_list_model ((GskRenderNode *[1]) { gsk_color_state_node_get_child (node) }, 1); } } @@ -461,6 +465,8 @@ node_type_name (GskRenderNodeType type) return "GL Shader"; case GSK_SUBSURFACE_NODE: return "Subsurface"; + case GSK_COLOR_STATE_NODE: + return "Color State"; } } @@ -498,6 +504,7 @@ node_name (GskRenderNode *node) case GSK_BLUR_NODE: case GSK_GL_SHADER_NODE: case GSK_SUBSURFACE_NODE: + case GSK_COLOR_STATE_NODE: return g_strdup (node_type_name (gsk_render_node_get_node_type (node))); case GSK_DEBUG_NODE: @@ -1530,6 +1537,14 @@ populate_render_node_properties (GListStore *store, } break; + case GSK_COLOR_STATE_NODE: + { + GdkColorState *color_state = gsk_color_state_node_get_color_state (node); + + add_text_row (store, "Color State", "%s", gdk_color_state_get_name (color_state)); + } + break; + case GSK_NOT_A_RENDER_NODE: default: break; diff --git a/testsuite/gsk/gskrendernodeattach.c b/testsuite/gsk/gskrendernodeattach.c index 6e92344fdd..e700d23653 100644 --- a/testsuite/gsk/gskrendernodeattach.c +++ b/testsuite/gsk/gskrendernodeattach.c @@ -203,6 +203,12 @@ node_attach (const GskRenderNode *node, return res; } + case GSK_COLOR_STATE_NODE: + child = node_attach (gsk_color_state_node_get_child (node), surface, idx); + res = gsk_color_state_node_new (child, gsk_color_state_node_get_color_state (node)); + gsk_render_node_unref (child); + return res; + case GSK_NOT_A_RENDER_NODE: default: g_assert_not_reached (); diff --git a/tools/gtk-rendernode-tool-extract.c b/tools/gtk-rendernode-tool-extract.c index c85ea9b88a..bd2efc49f6 100644 --- a/tools/gtk-rendernode-tool-extract.c +++ b/tools/gtk-rendernode-tool-extract.c @@ -34,6 +34,7 @@ static char *directory = NULL; static guint texture_count; static guint font_count; +static guint icc_profile_count; static GHashTable *fonts; @@ -155,7 +156,52 @@ extract_font (GskRenderNode *node) font_count++; } -#define N_NODE_TYPES (GSK_SUBSURFACE_NODE + 1) +static void +extract_icc_profile (GskRenderNode *node) +{ + GdkColorState *cs; + GBytes *bytes; + const gchar *data; + gsize len; + char *filename; + char *path; + + cs = gsk_color_state_node_get_color_state (node); + bytes = gdk_color_state_save_to_icc_profile (cs, NULL); + + if (bytes == NULL) + return; + + do { + filename = g_strdup_printf ("gtk-icc-profile-%u.ttf", icc_profile_count); + path = g_build_path ("/", directory, filename, NULL); + + if (!g_file_test (path, G_FILE_TEST_EXISTS)) + break; + + g_free (path); + g_free (filename); + icc_profile_count++; + } while (TRUE); + + if (verbose) + g_print ("Writing ICC profile to %s\n", filename); + + data = g_bytes_get_data (bytes, &len); + if (!g_file_set_contents (path, data, len, NULL)) + { + g_printerr (_("Failed to write %s\n"), filename); + } + + g_bytes_unref (bytes); + + g_free (path); + g_free (filename); + + icc_profile_count++; +} + +#define N_NODE_TYPES (GSK_COLOR_STATE_NODE + 1) static void extract_from_node (GskRenderNode *node) { @@ -257,6 +303,11 @@ extract_from_node (GskRenderNode *node) extract_from_node (gsk_subsurface_node_get_child (node)); break; + case GSK_COLOR_STATE_NODE: + extract_icc_profile (node); + extract_from_node (gsk_color_state_node_get_child (node)); + break; + case GSK_NOT_A_RENDER_NODE: default: g_assert_not_reached (); diff --git a/tools/gtk-rendernode-tool-info.c b/tools/gtk-rendernode-tool-info.c index 2ad6880b11..37b0c4e18f 100644 --- a/tools/gtk-rendernode-tool-info.c +++ b/tools/gtk-rendernode-tool-info.c @@ -29,7 +29,7 @@ #include #include "gtk-rendernode-tool.h" -#define N_NODE_TYPES (GSK_SUBSURFACE_NODE + 1) +#define N_NODE_TYPES (GSK_COLOR_STATE_NODE + 1) static void count_nodes (GskRenderNode *node, unsigned int *counts, @@ -144,6 +144,10 @@ count_nodes (GskRenderNode *node, count_nodes (gsk_subsurface_node_get_child (node), counts, &d); break; + case GSK_COLOR_STATE_NODE: + count_nodes (gsk_color_state_node_get_child (node), counts, &d); + break; + case GSK_NOT_A_RENDER_NODE: default: g_assert_not_reached ();