diff --git a/demos/node-editor/node-format.md b/demos/node-editor/node-format.md index e769865887..b174662f32 100644 --- a/demos/node-editor/node-format.md +++ b/demos/node-editor/node-format.md @@ -6,15 +6,25 @@ The format is a text format that follows the [CSS syntax rules](https://drafts.c The grammar of a node text representation using [the CSS value definition syntax](https://drafts.csswg.org/css-values-3/#value-defs) looks like this: **document**: `\*` -**node**: container { } | ` { * }` +**node**: container [ "name" ] { } | ` [ "name" ] { * }` | "name" **property**: `: | ;` -Each node has its own `` and supports a custom set of properties, each with their own `` and syntax. The following paragraphs document each of the nodes and their properties. +Each node has its own `` and supports a custom set of properties, each with their own `` and syntax. The following paragraphs document each of the nodes and their properties. When serializing and the value of a property equals the default value, this value will not be serialized. Serialization aims to produce an output as small as possible. To embed newlines in strings, use \A. To break a long string into multiple lines, escape the newline with a \. +# Names + +### Nodes + +Nodes can be given a name by adding a string after the `` in their definition. That same node can then be used further down in the document by specifying just the name identifying the node. + +### Textures + +Just like nodes, textures can be referenced by name. When definining the named texture, the name has to be placed in front of the URL. + # Nodes ### container diff --git a/gsk/gskrendernodeparser.c b/gsk/gskrendernodeparser.c index 6cceafcad7..522bacbf6e 100644 --- a/gsk/gskrendernodeparser.c +++ b/gsk/gskrendernodeparser.c @@ -41,18 +41,40 @@ #include #endif +typedef struct _Context Context; + +struct _Context +{ + GHashTable *named_nodes; + GHashTable *named_textures; +}; + typedef struct _Declaration Declaration; struct _Declaration { const char *name; - gboolean (* parse_func) (GtkCssParser *parser, gpointer result); + gboolean (* parse_func) (GtkCssParser *parser, Context *context, gpointer result); void (* clear_func) (gpointer data); gpointer result; }; +static void +context_init (Context *context) +{ + memset (context, 0, sizeof (Context)); +} + +static void +context_finish (Context *context) +{ + g_clear_pointer (&context->named_nodes, g_hash_table_unref); + g_clear_pointer (&context->named_textures, g_hash_table_unref); +} + static gboolean parse_rect (GtkCssParser *parser, + Context *context, gpointer out_rect) { double numbers[4]; @@ -70,6 +92,7 @@ parse_rect (GtkCssParser *parser, static gboolean parse_vec4 (GtkCssParser *parser, + Context *context, gpointer out_vec4) { double numbers[4]; @@ -87,12 +110,46 @@ parse_vec4 (GtkCssParser *parser, static gboolean parse_texture (GtkCssParser *parser, + Context *context, gpointer out_data) { GdkTexture *texture; GError *error = NULL; + const GtkCssToken *token; GtkCssLocation start_location; - char *url, *scheme; + char *url, *scheme, *texture_name; + + token = gtk_css_parser_get_token (parser); + if (gtk_css_token_is (token, GTK_CSS_TOKEN_STRING)) + { + texture_name = gtk_css_parser_consume_string (parser); + + if (context->named_textures) + texture = g_hash_table_lookup (context->named_textures, texture_name); + else + texture = NULL; + + if (texture) + { + *(GdkTexture **) out_data = g_object_ref (texture); + g_free (texture_name); + return TRUE; + } + else if (gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF)) + { + gtk_css_parser_error_value (parser, "No texture named \"%s\"", texture_name); + g_free (texture_name); + return FALSE; + } + + if (context->named_textures && g_hash_table_lookup (context->named_textures, texture_name)) + { + gtk_css_parser_error_value (parser, "A texture named \"%s\" already exists.", texture_name); + g_clear_pointer (&texture_name, g_free); + } + } + else + texture_name = NULL; start_location = *gtk_css_parser_get_start_location (parser); url = gtk_css_parser_consume_url (parser); @@ -128,6 +185,10 @@ parse_texture (GtkCssParser *parser, } else { + g_set_error (&error, + GTK_CSS_PARSER_ERROR, + GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE, + "Failed to resolve URL"); texture = NULL; } } @@ -148,6 +209,14 @@ parse_texture (GtkCssParser *parser, return FALSE; } + if (texture_name) + { + if (context->named_textures == NULL) + context->named_textures = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_object_unref); + g_hash_table_insert (context->named_textures, texture_name, g_object_ref (texture)); + } + *(GdkTexture **) out_data = texture; return TRUE; } @@ -200,6 +269,7 @@ csi_hooks_context_destroy (void *closure, static gboolean parse_script (GtkCssParser *parser, + Context *context, gpointer out_data) { #ifdef HAVE_CAIRO_SCRIPT_INTERPRETER @@ -229,8 +299,19 @@ parse_script (GtkCssParser *parser, GFile *file; file = gtk_css_parser_resolve_url (parser, url); - bytes = g_file_load_bytes (file, NULL, NULL, &error); - g_object_unref (file); + if (file) + { + bytes = g_file_load_bytes (file, NULL, NULL, &error); + g_object_unref (file); + } + else + { + g_set_error (&error, + GTK_CSS_PARSER_ERROR, + GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE, + "Failed to resolve URL"); + bytes = NULL; + } } g_free (scheme); @@ -285,6 +366,7 @@ clear_surface (gpointer inout_surface) static gboolean parse_rounded_rect (GtkCssParser *parser, + Context *context, gpointer out_rect) { graphene_rect_t r; @@ -292,7 +374,7 @@ parse_rounded_rect (GtkCssParser *parser, double d; guint i; - if (!parse_rect (parser, &r)) + if (!parse_rect (parser, context, &r)) return FALSE; if (!gtk_css_parser_try_delim (parser, '/')) @@ -357,6 +439,7 @@ parse_rounded_rect (GtkCssParser *parser, static gboolean parse_color (GtkCssParser *parser, + Context *context, gpointer out_color) { return gdk_rgba_parser_parse (parser, out_color); @@ -364,6 +447,7 @@ parse_color (GtkCssParser *parser, static gboolean parse_double (GtkCssParser *parser, + Context *context, gpointer out_double) { return gtk_css_parser_consume_number (parser, out_double); @@ -371,6 +455,7 @@ parse_double (GtkCssParser *parser, static gboolean parse_point (GtkCssParser *parser, + Context *context, gpointer out_point) { double x, y; @@ -386,6 +471,7 @@ parse_point (GtkCssParser *parser, static gboolean parse_transform (GtkCssParser *parser, + Context *context, gpointer out_transform) { GskTransform *transform; @@ -409,6 +495,7 @@ clear_transform (gpointer inout_transform) static gboolean parse_string (GtkCssParser *parser, + Context *context, gpointer out_string) { const GtkCssToken *token; @@ -416,7 +503,10 @@ parse_string (GtkCssParser *parser, token = gtk_css_parser_get_token (parser); if (!gtk_css_token_is (token, GTK_CSS_TOKEN_STRING)) - return FALSE; + { + gtk_css_parser_error_syntax (parser, "Expected a string"); + return FALSE; + } s = g_strdup (gtk_css_token_get_string (token)); gtk_css_parser_consume_token (parser); @@ -435,6 +525,7 @@ clear_string (gpointer inout_string) static gboolean parse_stops (GtkCssParser *parser, + Context *context, gpointer out_stops) { GArray *stops; @@ -501,6 +592,7 @@ clear_stops (gpointer inout_stops) static gboolean parse_float4 (GtkCssParser *parser, + Context *context, gpointer out_floats) { float *floats = (float *) out_floats; @@ -532,6 +624,7 @@ parse_float4 (GtkCssParser *parser, static gboolean parse_colors4 (GtkCssParser *parser, + Context *context, gpointer out_colors) { GdkRGBA colors[4]; @@ -559,6 +652,7 @@ parse_colors4 (GtkCssParser *parser, static gboolean parse_shadows (GtkCssParser *parser, + Context *context, gpointer out_shadows) { GArray *shadows = out_shadows; @@ -612,6 +706,7 @@ static const struct static gboolean parse_scaling_filter (GtkCssParser *parser, + Context *context, gpointer out_filter) { for (unsigned int i = 0; i < G_N_ELEMENTS (scaling_filters); i++) @@ -665,6 +760,7 @@ get_blend_mode_name (GskBlendMode mode) static gboolean parse_blend_mode (GtkCssParser *parser, + Context *context, gpointer out_mode) { guint i; @@ -708,6 +804,7 @@ get_mask_mode_name (GskMaskMode mode) static gboolean parse_mask_mode (GtkCssParser *parser, + Context *context, gpointer out_mode) { guint i; @@ -811,6 +908,7 @@ create_ascii_glyphs (PangoFont *font) static gboolean parse_font (GtkCssParser *parser, + Context *context, gpointer out_font) { PangoFont *font; @@ -842,6 +940,7 @@ clear_font (gpointer inout_font) static gboolean parse_glyphs (GtkCssParser *parser, + Context *context, gpointer out_glyphs) { PangoGlyphString *glyph_string; @@ -922,7 +1021,7 @@ clear_glyphs (gpointer inout_glyphs) } static gboolean -parse_node (GtkCssParser *parser, gpointer out_node); +parse_node (GtkCssParser *parser, Context *context, gpointer out_node); static void clear_node (gpointer inout_node) @@ -931,7 +1030,8 @@ clear_node (gpointer inout_node) } static GskRenderNode * -parse_container_node (GtkCssParser *parser) +parse_container_node (GtkCssParser *parser, + Context *context) { GPtrArray *nodes; const GtkCssToken *token; @@ -949,7 +1049,7 @@ parse_container_node (GtkCssParser *parser) */ gtk_css_parser_start_semicolon_block (parser, GTK_CSS_TOKEN_OPEN_CURLY); - if (parse_node (parser, &node)) + if (parse_node (parser, context, &node)) g_ptr_array_add (nodes, node); gtk_css_parser_end_block (parser); @@ -964,6 +1064,7 @@ parse_container_node (GtkCssParser *parser) static guint parse_declarations (GtkCssParser *parser, + Context *context, const Declaration *declarations, guint n_declarations) { @@ -994,7 +1095,7 @@ parse_declarations (GtkCssParser *parser, if (declarations[i].clear_func) declarations[i].clear_func (declarations[i].result); } - if (!declarations[i].parse_func (parser, declarations[i].result)) + if (!declarations[i].parse_func (parser, context, declarations[i].result)) { /* nothing to do */ } @@ -1058,7 +1159,8 @@ create_default_render_node (void) } static GskRenderNode * -parse_color_node (GtkCssParser *parser) +parse_color_node (GtkCssParser *parser, + Context *context) { graphene_rect_t bounds = GRAPHENE_RECT_INIT (0, 0, 50, 50); GdkRGBA color = GDK_RGBA("FF00CC"); @@ -1067,13 +1169,14 @@ parse_color_node (GtkCssParser *parser) { "color", parse_color, NULL, &color }, }; - parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations)); return gsk_color_node_new (&color, &bounds); } static GskRenderNode * parse_linear_gradient_node_internal (GtkCssParser *parser, + Context *context, gboolean repeating) { graphene_rect_t bounds = GRAPHENE_RECT_INIT (0, 0, 50, 50); @@ -1088,7 +1191,7 @@ parse_linear_gradient_node_internal (GtkCssParser *parser, }; GskRenderNode *result; - parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations)); if (stops == NULL) { GskColorStop from = { 0.0, GDK_RGBA("AAFF00") }; @@ -1110,19 +1213,22 @@ parse_linear_gradient_node_internal (GtkCssParser *parser, } static GskRenderNode * -parse_linear_gradient_node (GtkCssParser *parser) +parse_linear_gradient_node (GtkCssParser *parser, + Context *context) { - return parse_linear_gradient_node_internal (parser, FALSE); + return parse_linear_gradient_node_internal (parser, context, FALSE); } static GskRenderNode * -parse_repeating_linear_gradient_node (GtkCssParser *parser) +parse_repeating_linear_gradient_node (GtkCssParser *parser, + Context *context) { - return parse_linear_gradient_node_internal (parser, TRUE); + return parse_linear_gradient_node_internal (parser, context, TRUE); } static GskRenderNode * parse_radial_gradient_node_internal (GtkCssParser *parser, + Context *context, gboolean repeating) { graphene_rect_t bounds = GRAPHENE_RECT_INIT (0, 0, 50, 50); @@ -1143,7 +1249,7 @@ parse_radial_gradient_node_internal (GtkCssParser *parser, }; GskRenderNode *result; - parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations)); if (stops == NULL) { GskColorStop from = { 0.0, GDK_RGBA("AAFF00") }; @@ -1167,19 +1273,22 @@ parse_radial_gradient_node_internal (GtkCssParser *parser, } static GskRenderNode * -parse_radial_gradient_node (GtkCssParser *parser) +parse_radial_gradient_node (GtkCssParser *parser, + Context *context) { - return parse_radial_gradient_node_internal (parser, FALSE); + return parse_radial_gradient_node_internal (parser, context, FALSE); } static GskRenderNode * -parse_repeating_radial_gradient_node (GtkCssParser *parser) +parse_repeating_radial_gradient_node (GtkCssParser *parser, + Context *context) { - return parse_radial_gradient_node_internal (parser, TRUE); + return parse_radial_gradient_node_internal (parser, context, TRUE); } static GskRenderNode * -parse_conic_gradient_node (GtkCssParser *parser) +parse_conic_gradient_node (GtkCssParser *parser, + Context *context) { graphene_rect_t bounds = GRAPHENE_RECT_INIT (0, 0, 50, 50); graphene_point_t center = GRAPHENE_POINT_INIT (25, 25); @@ -1193,7 +1302,7 @@ parse_conic_gradient_node (GtkCssParser *parser) }; GskRenderNode *result; - parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations)); if (stops == NULL) { GskColorStop from = { 0.0, GDK_RGBA("AAFF00") }; @@ -1213,7 +1322,8 @@ parse_conic_gradient_node (GtkCssParser *parser) } static GskRenderNode * -parse_inset_shadow_node (GtkCssParser *parser) +parse_inset_shadow_node (GtkCssParser *parser, + Context *context) { GskRoundedRect outline = GSK_ROUNDED_RECT_INIT (0, 0, 50, 50); GdkRGBA color = GDK_RGBA("000000"); @@ -1227,7 +1337,7 @@ parse_inset_shadow_node (GtkCssParser *parser) { "blur", parse_double, NULL, &blur } }; - parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations)); return gsk_inset_shadow_node_new (&outline, &color, dx, dy, spread, blur); } @@ -1252,6 +1362,7 @@ clear_shader_info (gpointer data) static gboolean parse_shader (GtkCssParser *parser, + Context *context, gpointer out_shader_info) { ShaderInfo *shader_info = out_shader_info; @@ -1259,7 +1370,7 @@ parse_shader (GtkCssParser *parser, GBytes *bytes; GskGLShader *shader; - if (!parse_string (parser, &sourcecode)) + if (!parse_string (parser, context, &sourcecode)) return FALSE; bytes = g_bytes_new_take (sourcecode, strlen (sourcecode)); @@ -1369,7 +1480,9 @@ parse_uniform_value (GtkCssParser *parser, } static gboolean -parse_shader_args (GtkCssParser *parser, gpointer data) +parse_shader_args (GtkCssParser *parser, + Context *context, + gpointer data) { ShaderInfo *shader_info = data; int n_uniforms; @@ -1388,7 +1501,8 @@ parse_shader_args (GtkCssParser *parser, gpointer data) } static GskRenderNode * -parse_glshader_node (GtkCssParser *parser) +parse_glshader_node (GtkCssParser *parser, + Context *context) { graphene_rect_t bounds = GRAPHENE_RECT_INIT (0, 0, 50, 50); GskRenderNode *child[4] = { NULL, }; @@ -1410,7 +1524,7 @@ parse_glshader_node (GtkCssParser *parser) GBytes *args = NULL; int len, i; - parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations)); for (len = 0; len < 4; len++) { @@ -1436,7 +1550,8 @@ parse_glshader_node (GtkCssParser *parser) } static GskRenderNode * -parse_mask_node (GtkCssParser *parser) +parse_mask_node (GtkCssParser *parser, + Context *context) { GskRenderNode *source = NULL; GskRenderNode *mask = NULL; @@ -1448,7 +1563,7 @@ parse_mask_node (GtkCssParser *parser) }; GskRenderNode *result; - parse_declarations (parser, declarations, G_N_ELEMENTS(declarations)); + parse_declarations (parser, context, declarations, G_N_ELEMENTS(declarations)); if (source == NULL) source = create_default_render_node (); if (mask == NULL) @@ -1463,7 +1578,8 @@ parse_mask_node (GtkCssParser *parser) } static GskRenderNode * -parse_border_node (GtkCssParser *parser) +parse_border_node (GtkCssParser *parser, + Context *context) { GskRoundedRect outline = GSK_ROUNDED_RECT_INIT (0, 0, 50, 50); float widths[4] = { 1, 1, 1, 1 }; @@ -1474,13 +1590,14 @@ parse_border_node (GtkCssParser *parser) { "colors", parse_colors4, NULL, &colors } }; - parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations)); return gsk_border_node_new (&outline, widths, colors); } static GskRenderNode * -parse_texture_node (GtkCssParser *parser) +parse_texture_node (GtkCssParser *parser, + Context *context) { graphene_rect_t bounds = GRAPHENE_RECT_INIT (0, 0, 50, 50); GdkTexture *texture = NULL; @@ -1490,7 +1607,7 @@ parse_texture_node (GtkCssParser *parser) }; GskRenderNode *node; - parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations)); if (texture == NULL) texture = create_default_texture (); @@ -1502,7 +1619,8 @@ parse_texture_node (GtkCssParser *parser) } static GskRenderNode * -parse_texture_scale_node (GtkCssParser *parser) +parse_texture_scale_node (GtkCssParser *parser, + Context *context) { graphene_rect_t bounds = GRAPHENE_RECT_INIT (0, 0, 50, 50); GdkTexture *texture = NULL; @@ -1514,7 +1632,7 @@ parse_texture_scale_node (GtkCssParser *parser) }; GskRenderNode *node; - parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations)); if (texture == NULL) texture = create_default_texture (); @@ -1526,7 +1644,8 @@ parse_texture_scale_node (GtkCssParser *parser) } static GskRenderNode * -parse_cairo_node (GtkCssParser *parser) +parse_cairo_node (GtkCssParser *parser, + Context *context) { graphene_rect_t bounds = GRAPHENE_RECT_INIT (0, 0, 50, 50); GdkTexture *pixels = NULL; @@ -1538,7 +1657,7 @@ parse_cairo_node (GtkCssParser *parser) }; GskRenderNode *node; - parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations)); node = gsk_cairo_node_new (&bounds); @@ -1569,7 +1688,8 @@ parse_cairo_node (GtkCssParser *parser) } static GskRenderNode * -parse_outset_shadow_node (GtkCssParser *parser) +parse_outset_shadow_node (GtkCssParser *parser, + Context *context) { GskRoundedRect outline = GSK_ROUNDED_RECT_INIT (0, 0, 50, 50); GdkRGBA color = GDK_RGBA("000000"); @@ -1583,13 +1703,14 @@ parse_outset_shadow_node (GtkCssParser *parser) { "blur", parse_double, NULL, &blur } }; - parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations)); return gsk_outset_shadow_node_new (&outline, &color, dx, dy, spread, blur); } static GskRenderNode * -parse_transform_node (GtkCssParser *parser) +parse_transform_node (GtkCssParser *parser, + Context *context) { GskRenderNode *child = NULL; GskTransform *transform = NULL; @@ -1599,7 +1720,7 @@ parse_transform_node (GtkCssParser *parser) }; GskRenderNode *result; - parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations)); if (child == NULL) child = create_default_render_node (); @@ -1616,7 +1737,8 @@ parse_transform_node (GtkCssParser *parser) } static GskRenderNode * -parse_opacity_node (GtkCssParser *parser) +parse_opacity_node (GtkCssParser *parser, + Context *context) { GskRenderNode *child = NULL; double opacity = 0.5; @@ -1626,7 +1748,7 @@ parse_opacity_node (GtkCssParser *parser) }; GskRenderNode *result; - parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations)); if (child == NULL) child = create_default_render_node (); @@ -1638,7 +1760,8 @@ parse_opacity_node (GtkCssParser *parser) } static GskRenderNode * -parse_color_matrix_node (GtkCssParser *parser) +parse_color_matrix_node (GtkCssParser *parser, + Context *context) { GskRenderNode *child = NULL; graphene_matrix_t matrix; @@ -1653,7 +1776,7 @@ parse_color_matrix_node (GtkCssParser *parser) graphene_vec4_init (&offset, 0, 0, 0, 0); - parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations)); if (child == NULL) child = create_default_render_node (); @@ -1668,7 +1791,8 @@ parse_color_matrix_node (GtkCssParser *parser) } static GskRenderNode * -parse_cross_fade_node (GtkCssParser *parser) +parse_cross_fade_node (GtkCssParser *parser, + Context *context) { GskRenderNode *start = NULL; GskRenderNode *end = NULL; @@ -1680,7 +1804,7 @@ parse_cross_fade_node (GtkCssParser *parser) }; GskRenderNode *result; - parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations)); if (start == NULL) start = gsk_color_node_new (&GDK_RGBA("AAFF00"), &GRAPHENE_RECT_INIT (0, 0, 50, 50)); if (end == NULL) @@ -1695,7 +1819,8 @@ parse_cross_fade_node (GtkCssParser *parser) } static GskRenderNode * -parse_blend_node (GtkCssParser *parser) +parse_blend_node (GtkCssParser *parser, + Context *context) { GskRenderNode *bottom = NULL; GskRenderNode *top = NULL; @@ -1707,7 +1832,7 @@ parse_blend_node (GtkCssParser *parser) }; GskRenderNode *result; - parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations)); if (bottom == NULL) bottom = gsk_color_node_new (&GDK_RGBA("AAFF00"), &GRAPHENE_RECT_INIT (0, 0, 50, 50)); if (top == NULL) @@ -1722,7 +1847,8 @@ parse_blend_node (GtkCssParser *parser) } static GskRenderNode * -parse_repeat_node (GtkCssParser *parser) +parse_repeat_node (GtkCssParser *parser, + Context *context) { GskRenderNode *child = NULL; graphene_rect_t bounds = GRAPHENE_RECT_INIT (0, 0, 0, 0); @@ -1735,7 +1861,7 @@ parse_repeat_node (GtkCssParser *parser) GskRenderNode *result; guint parse_result; - parse_result = parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + parse_result = parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations)); if (child == NULL) child = create_default_render_node (); @@ -1785,7 +1911,8 @@ unpack_glyphs (PangoFont *font, } static GskRenderNode * -parse_text_node (GtkCssParser *parser) +parse_text_node (GtkCssParser *parser, + Context *context) { PangoFont *font = NULL; graphene_point_t offset = GRAPHENE_POINT_INIT (0, 0); @@ -1799,7 +1926,7 @@ parse_text_node (GtkCssParser *parser) }; GskRenderNode *result; - parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations)); if (font == NULL) { @@ -1847,7 +1974,8 @@ parse_text_node (GtkCssParser *parser) } static GskRenderNode * -parse_blur_node (GtkCssParser *parser) +parse_blur_node (GtkCssParser *parser, + Context *context) { GskRenderNode *child = NULL; double blur_radius = 1.0; @@ -1857,7 +1985,7 @@ parse_blur_node (GtkCssParser *parser) }; GskRenderNode *result; - parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations)); if (child == NULL) child = create_default_render_node (); @@ -1869,7 +1997,8 @@ parse_blur_node (GtkCssParser *parser) } static GskRenderNode * -parse_clip_node (GtkCssParser *parser) +parse_clip_node (GtkCssParser *parser, + Context *context) { GskRoundedRect clip = GSK_ROUNDED_RECT_INIT (0, 0, 50, 50); GskRenderNode *child = NULL; @@ -1879,7 +2008,7 @@ parse_clip_node (GtkCssParser *parser) }; GskRenderNode *result; - parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations)); if (child == NULL) child = create_default_render_node (); @@ -1894,7 +2023,8 @@ parse_clip_node (GtkCssParser *parser) } static GskRenderNode * -parse_rounded_clip_node (GtkCssParser *parser) +parse_rounded_clip_node (GtkCssParser *parser, + Context *context) { GskRoundedRect clip = GSK_ROUNDED_RECT_INIT (0, 0, 50, 50); GskRenderNode *child = NULL; @@ -1904,7 +2034,7 @@ parse_rounded_clip_node (GtkCssParser *parser) }; GskRenderNode *result; - parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations)); if (child == NULL) child = create_default_render_node (); @@ -1916,7 +2046,8 @@ parse_rounded_clip_node (GtkCssParser *parser) } static GskRenderNode * -parse_shadow_node (GtkCssParser *parser) +parse_shadow_node (GtkCssParser *parser, + Context *context) { GskRenderNode *child = NULL; GArray *shadows = g_array_new (FALSE, TRUE, sizeof (GskShadow)); @@ -1926,7 +2057,7 @@ parse_shadow_node (GtkCssParser *parser) }; GskRenderNode *result; - parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations)); if (child == NULL) child = create_default_render_node (); @@ -1945,7 +2076,8 @@ parse_shadow_node (GtkCssParser *parser) } static GskRenderNode * -parse_debug_node (GtkCssParser *parser) +parse_debug_node (GtkCssParser *parser, + Context *context) { char *message = NULL; GskRenderNode *child = NULL; @@ -1955,7 +2087,7 @@ parse_debug_node (GtkCssParser *parser) }; GskRenderNode *result; - parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations)); if (child == NULL) child = create_default_render_node (); @@ -1968,11 +2100,12 @@ parse_debug_node (GtkCssParser *parser) static gboolean parse_node (GtkCssParser *parser, + Context *context, gpointer out_node) { static struct { const char *name; - GskRenderNode * (* func) (GtkCssParser *); + GskRenderNode * (* func) (GtkCssParser *, Context *); } node_parsers[] = { { "blend", parse_blend_node }, { "blur", parse_blur_node }, @@ -2003,29 +2136,92 @@ parse_node (GtkCssParser *parser, { "mask", parse_mask_node }, }; GskRenderNode **node_p = out_node; + const GtkCssToken *token; guint i; + token = gtk_css_parser_get_token (parser); + if (gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_STRING)) + if (gtk_css_token_is (token, GTK_CSS_TOKEN_STRING)) + { + GskRenderNode *node; + char *node_name; + + node_name = gtk_css_parser_consume_string (parser); + + if (context->named_nodes) + node = g_hash_table_lookup (context->named_nodes, node_name); + else + node = NULL; + + if (node) + { + *node_p = gsk_render_node_ref (node); + g_free (node_name); + return TRUE; + } + else + { + gtk_css_parser_error_value (parser, "No node named \"%s\"", node_name); + g_free (node_name); + return FALSE; + } + } + for (i = 0; i < G_N_ELEMENTS (node_parsers); i++) { if (gtk_css_parser_try_ident (parser, node_parsers[i].name)) { GskRenderNode *node; + GtkCssLocation node_name_start_location, node_name_end_location; + char *node_name; + + if (gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_STRING)) + { + node_name_start_location = *gtk_css_parser_get_start_location (parser); + node_name_end_location = *gtk_css_parser_get_end_location (parser); + node_name = gtk_css_parser_consume_string (parser); + } + else + node_name = NULL; if (!gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF)) { gtk_css_parser_error_syntax (parser, "Expected '{' after node name"); return FALSE; } + gtk_css_parser_end_block_prelude (parser); - node = node_parsers[i].func (parser); + node = node_parsers[i].func (parser, context); if (node) { if (!gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF)) gtk_css_parser_error_syntax (parser, "Expected '}' at end of node definition"); g_clear_pointer (node_p, gsk_render_node_unref); + + if (node_name) + { + if (context->named_nodes == NULL) + context->named_nodes = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, (GDestroyNotify) gsk_render_node_unref); + if (g_hash_table_lookup (context->named_nodes, node_name)) + { + gtk_css_parser_error (parser, + GTK_CSS_PARSER_ERROR_FAILED, + &node_name_start_location, + &node_name_end_location, + "A node named \"%s\" already exists.", node_name); + } + else + { + g_hash_table_insert (context->named_nodes, g_strdup (node_name), gsk_render_node_ref (node)); + } + } + *node_p = node; } + g_free (node_name); + return node != NULL; } } @@ -2065,6 +2261,7 @@ gsk_render_node_deserialize_from_bytes (GBytes *bytes, { GskRenderNode *root = NULL; GtkCssParser *parser; + Context context; struct { GskParseErrorFunc error_func; gpointer user_data; @@ -2072,7 +2269,8 @@ gsk_render_node_deserialize_from_bytes (GBytes *bytes, parser = gtk_css_parser_new_for_bytes (bytes, NULL, gsk_render_node_parser_error, &error_func_pair, NULL); - root = parse_container_node (parser); + context_init (&context); + root = parse_container_node (parser, &context); if (root && gsk_container_node_get_n_children (root) == 1) { @@ -2083,6 +2281,7 @@ gsk_render_node_deserialize_from_bytes (GBytes *bytes, root = child; } + context_finish (&context); gtk_css_parser_unref (parser); return root; @@ -2093,13 +2292,152 @@ typedef struct { int indentation_level; GString *str; + GHashTable *named_nodes; + gsize named_node_counter; + GHashTable *named_textures; + gsize named_texture_counter; } Printer; static void -printer_init (Printer *self) +printer_init_check_texture (Printer *printer, + GdkTexture *texture) +{ + gpointer name; + + if (!g_hash_table_lookup_extended (printer->named_textures, texture, NULL, &name)) + g_hash_table_insert (printer->named_textures, texture, NULL); + else if (name == NULL) + g_hash_table_insert (printer->named_textures, texture, g_strdup ("")); +} + +static void +printer_init_duplicates_for_node (Printer *printer, + GskRenderNode *node) +{ + gpointer name; + + if (!g_hash_table_lookup_extended (printer->named_nodes, node, NULL, &name)) + g_hash_table_insert (printer->named_nodes, node, NULL); + else if (name == NULL) + g_hash_table_insert (printer->named_nodes, node, g_strdup ("")); + + switch (gsk_render_node_get_node_type (node)) + { + case GSK_CAIRO_NODE: + case GSK_TEXT_NODE: + case GSK_COLOR_NODE: + case GSK_LINEAR_GRADIENT_NODE: + case GSK_REPEATING_LINEAR_GRADIENT_NODE: + case GSK_RADIAL_GRADIENT_NODE: + case GSK_REPEATING_RADIAL_GRADIENT_NODE: + case GSK_CONIC_GRADIENT_NODE: + case GSK_BORDER_NODE: + case GSK_INSET_SHADOW_NODE: + case GSK_OUTSET_SHADOW_NODE: + /* no children */ + break; + + case GSK_TEXTURE_NODE: + printer_init_check_texture (printer, gsk_texture_node_get_texture (node)); + break; + + case GSK_TEXTURE_SCALE_NODE: + printer_init_check_texture (printer, gsk_texture_scale_node_get_texture (node)); + break; + + case GSK_TRANSFORM_NODE: + printer_init_duplicates_for_node (printer, gsk_transform_node_get_child (node)); + break; + + case GSK_OPACITY_NODE: + printer_init_duplicates_for_node (printer, gsk_opacity_node_get_child (node)); + break; + + case GSK_COLOR_MATRIX_NODE: + printer_init_duplicates_for_node (printer, gsk_color_matrix_node_get_child (node)); + break; + + case GSK_BLUR_NODE: + printer_init_duplicates_for_node (printer, gsk_blur_node_get_child (node)); + break; + + case GSK_REPEAT_NODE: + printer_init_duplicates_for_node (printer, gsk_repeat_node_get_child (node)); + break; + + case GSK_CLIP_NODE: + printer_init_duplicates_for_node (printer, gsk_clip_node_get_child (node)); + break; + + case GSK_ROUNDED_CLIP_NODE: + printer_init_duplicates_for_node (printer, gsk_rounded_clip_node_get_child (node)); + break; + + case GSK_SHADOW_NODE: + printer_init_duplicates_for_node (printer, gsk_shadow_node_get_child (node)); + break; + + case GSK_DEBUG_NODE: + printer_init_duplicates_for_node (printer, gsk_debug_node_get_child (node)); + break; + + case GSK_BLEND_NODE: + printer_init_duplicates_for_node (printer, gsk_blend_node_get_bottom_child (node)); + printer_init_duplicates_for_node (printer, gsk_blend_node_get_top_child (node)); + break; + + case GSK_MASK_NODE: + printer_init_duplicates_for_node (printer, gsk_mask_node_get_source (node)); + printer_init_duplicates_for_node (printer, gsk_mask_node_get_mask (node)); + break; + + case GSK_CROSS_FADE_NODE: + printer_init_duplicates_for_node (printer, gsk_cross_fade_node_get_start_child (node)); + printer_init_duplicates_for_node (printer, gsk_cross_fade_node_get_end_child (node)); + break; + + case GSK_GL_SHADER_NODE: + { + guint i; + + for (i = 0; i < gsk_gl_shader_node_get_n_children (node); i++) + { + printer_init_duplicates_for_node (printer, gsk_gl_shader_node_get_child (node, i)); + } + } + break; + + case GSK_CONTAINER_NODE: + { + guint i; + + for (i = 0; i < gsk_container_node_get_n_children (node); i++) + { + printer_init_duplicates_for_node (printer, gsk_container_node_get_child (node, i)); + } + } + break; + + default: + case GSK_NOT_A_RENDER_NODE: + g_assert_not_reached (); + break; + + } +} + +static void +printer_init (Printer *self, + GskRenderNode *node) { self->indentation_level = 0; self->str = g_string_new (NULL); + self->named_nodes = g_hash_table_new_full (NULL, NULL, NULL, g_free); + self->named_node_counter = 0; + self->named_textures = g_hash_table_new_full (NULL, NULL, NULL, g_free); + self->named_texture_counter = 0; + + printer_init_duplicates_for_node (self, node); } #define IDENT_LEVEL 2 /* Spaces per level */ @@ -2113,9 +2451,16 @@ _indent (Printer *self) static void start_node (Printer *self, + const char *node_type, const char *node_name) { - g_string_append_printf (self->str, "%s {\n", node_name); + g_string_append_printf (self->str, "%s ", node_type); + if (node_name) + { + gtk_css_print_string (self->str, node_name, FALSE); + g_string_append_c (self->str, ' '); + } + g_string_append_printf (self->str, "{\n"); self->indentation_level ++; } @@ -2462,6 +2807,82 @@ base64_encode_with_linebreaks (const guchar *data, return out; } +static void +append_texture_param (Printer *p, + const char *param_name, + GdkTexture *texture) +{ + GBytes *bytes; + char *b64; + const char *texture_name; + + _indent (p); + + g_string_append_printf (p->str, "%s: ", param_name); + + texture_name = g_hash_table_lookup (p->named_textures, texture); + if (texture_name == NULL) + { + /* nothing to do here, texture is unique */ + } + else if (texture_name[0]) + { + /* texture has been named already */ + gtk_css_print_string (p->str, texture_name, TRUE); + g_string_append (p->str, ";\n"); + return; + } + else + { + /* texture needs a name */ + char *new_name = g_strdup_printf ("texture%zu", ++p->named_texture_counter); + gtk_css_print_string (p->str, new_name, TRUE); + g_string_append_c (p->str, ' '); + g_hash_table_insert (p->named_textures, texture, new_name); + } + + switch (gdk_texture_get_format (texture)) + { + case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED: + case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED: + case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED: + case GDK_MEMORY_B8G8R8A8: + case GDK_MEMORY_A8R8G8B8: + case GDK_MEMORY_R8G8B8A8: + case GDK_MEMORY_A8B8G8R8: + case GDK_MEMORY_R8G8B8: + case GDK_MEMORY_B8G8R8: + case GDK_MEMORY_R16G16B16: + case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: + case GDK_MEMORY_R16G16B16A16: + bytes = gdk_texture_save_to_png_bytes (texture); + g_string_append (p->str, "url(\"data:image/png;base64,"); + break; + + case GDK_MEMORY_R16G16B16_FLOAT: + case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: + case GDK_MEMORY_R16G16B16A16_FLOAT: + case GDK_MEMORY_R32G32B32_FLOAT: + case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: + case GDK_MEMORY_R32G32B32A32_FLOAT: + bytes = gdk_texture_save_to_tiff_bytes (texture); + g_string_append (p->str, "url(\"data:image/tiff;base64,"); + break; + + case GDK_MEMORY_N_FORMATS: + default: + g_assert_not_reached (); + } + + b64 = base64_encode_with_linebreaks (g_bytes_get_data (bytes, NULL), + g_bytes_get_size (bytes)); + append_escaping_newlines (p->str, b64); + g_free (b64); + g_string_append (p->str, "\");\n"); + + g_bytes_unref (bytes); +} + void gsk_text_node_serialize_glyphs (GskRenderNode *node, GString *p) @@ -2548,6 +2969,27 @@ render_node_print (Printer *p, GskRenderNode *node) { char *b64; + const char *node_name; + + node_name = g_hash_table_lookup (p->named_nodes, node); + if (node_name == NULL) + { + /* nothing to do here, node is unique */ + } + else if (node_name[0]) + { + /* node has been named already */ + gtk_css_print_string (p->str, node_name, TRUE); + g_string_append (p->str, ";\n"); + return; + } + else + { + /* node needs a name */ + char *new_name = g_strdup_printf ("node%zu", ++p->named_node_counter); + g_hash_table_insert (p->named_nodes, node, new_name); + node_name = new_name; + } switch (gsk_render_node_get_node_type (node)) { @@ -2555,7 +2997,7 @@ render_node_print (Printer *p, { guint i; - start_node (p, "container"); + start_node (p, "container", node_name); for (i = 0; i < gsk_container_node_get_n_children (node); i ++) { GskRenderNode *child = gsk_container_node_get_child (node, i); @@ -2570,7 +3012,7 @@ render_node_print (Printer *p, case GSK_COLOR_NODE: { - start_node (p, "color"); + start_node (p, "color", node_name); append_rect_param (p, "bounds", &node->bounds); append_rgba_param (p, "color", gsk_color_node_get_color (node)); end_node (p); @@ -2579,7 +3021,7 @@ render_node_print (Printer *p, case GSK_CROSS_FADE_NODE: { - start_node (p, "cross-fade"); + start_node (p, "cross-fade", node_name); append_float_param (p, "progress", gsk_cross_fade_node_get_progress (node), 0.5f); append_node_param (p, "start", gsk_cross_fade_node_get_start_child (node)); @@ -2593,9 +3035,9 @@ render_node_print (Printer *p, case GSK_LINEAR_GRADIENT_NODE: { if (gsk_render_node_get_node_type (node) == GSK_REPEATING_LINEAR_GRADIENT_NODE) - start_node (p, "repeating-linear-gradient"); + start_node (p, "repeating-linear-gradient", node_name); else - start_node (p, "linear-gradient"); + start_node (p, "linear-gradient", node_name); append_rect_param (p, "bounds", &node->bounds); append_point_param (p, "start", gsk_linear_gradient_node_get_start (node)); @@ -2611,9 +3053,9 @@ render_node_print (Printer *p, case GSK_RADIAL_GRADIENT_NODE: { if (gsk_render_node_get_node_type (node) == GSK_REPEATING_RADIAL_GRADIENT_NODE) - start_node (p, "repeating-radial-gradient"); + start_node (p, "repeating-radial-gradient", node_name); else - start_node (p, "radial-gradient"); + start_node (p, "radial-gradient", node_name); append_rect_param (p, "bounds", &node->bounds); append_point_param (p, "center", gsk_radial_gradient_node_get_center (node)); @@ -2631,7 +3073,7 @@ render_node_print (Printer *p, case GSK_CONIC_GRADIENT_NODE: { - start_node (p, "conic-gradient"); + start_node (p, "conic-gradient", node_name); append_rect_param (p, "bounds", &node->bounds); append_point_param (p, "center", gsk_conic_gradient_node_get_center (node)); @@ -2646,7 +3088,7 @@ render_node_print (Printer *p, case GSK_OPACITY_NODE: { - start_node (p, "opacity"); + start_node (p, "opacity", node_name); append_float_param (p, "opacity", gsk_opacity_node_get_opacity (node), 0.5f); append_node_param (p, "child", gsk_opacity_node_get_child (node)); @@ -2659,7 +3101,7 @@ render_node_print (Printer *p, { const GdkRGBA *color = gsk_outset_shadow_node_get_color (node); - start_node (p, "outset-shadow"); + start_node (p, "outset-shadow", node_name); append_float_param (p, "blur", gsk_outset_shadow_node_get_blur_radius (node), 0.0f); if (!gdk_rgba_equal (color, &GDK_RGBA("000"))) @@ -2675,7 +3117,7 @@ render_node_print (Printer *p, case GSK_CLIP_NODE: { - start_node (p, "clip"); + start_node (p, "clip", node_name); append_rect_param (p, "clip", gsk_clip_node_get_clip (node)); append_node_param (p, "child", gsk_clip_node_get_child (node)); @@ -2686,7 +3128,7 @@ render_node_print (Printer *p, case GSK_ROUNDED_CLIP_NODE: { - start_node (p, "rounded-clip"); + start_node (p, "rounded-clip", node_name); append_rounded_rect_param (p, "clip", gsk_rounded_clip_node_get_clip (node)); append_node_param (p, "child", gsk_rounded_clip_node_get_child (node)); @@ -2699,7 +3141,7 @@ render_node_print (Printer *p, case GSK_TRANSFORM_NODE: { GskTransform *transform = gsk_transform_node_get_transform (node); - start_node (p, "transform"); + start_node (p, "transform", node_name); if (gsk_transform_get_category (transform) != GSK_TRANSFORM_CATEGORY_IDENTITY) append_transform_param (p, "transform", transform); @@ -2711,7 +3153,7 @@ render_node_print (Printer *p, case GSK_COLOR_MATRIX_NODE: { - start_node (p, "color-matrix"); + start_node (p, "color-matrix", node_name); if (!graphene_matrix_is_identity (gsk_color_matrix_node_get_color_matrix (node))) append_matrix_param (p, "matrix", gsk_color_matrix_node_get_color_matrix (node)); @@ -2728,7 +3170,7 @@ render_node_print (Printer *p, const GdkRGBA *colors = gsk_border_node_get_colors (node); const float *widths = gsk_border_node_get_widths (node); guint i, n; - start_node (p, "border"); + start_node (p, "border", node_name); if (!gdk_rgba_equal (&colors[3], &colors[1])) n = 4; @@ -2789,7 +3231,7 @@ render_node_print (Printer *p, const guint n_shadows = gsk_shadow_node_get_n_shadows (node); int i; - start_node (p, "shadow"); + start_node (p, "shadow", node_name); _indent (p); g_string_append (p->str, "shadows: "); @@ -2827,7 +3269,7 @@ render_node_print (Printer *p, case GSK_INSET_SHADOW_NODE: { const GdkRGBA *color = gsk_inset_shadow_node_get_color (node); - start_node (p, "inset-shadow"); + start_node (p, "inset-shadow", node_name); append_float_param (p, "blur", gsk_inset_shadow_node_get_blur_radius (node), 0.0f); if (!gdk_rgba_equal (color, &GDK_RGBA("000"))) @@ -2843,65 +3285,20 @@ render_node_print (Printer *p, case GSK_TEXTURE_NODE: { - GdkTexture *texture = gsk_texture_node_get_texture (node); - GBytes *bytes; + start_node (p, "texture", node_name); - start_node (p, "texture"); append_rect_param (p, "bounds", &node->bounds); + append_texture_param (p, "texture", gsk_texture_node_get_texture (node)); - _indent (p); - - switch (gdk_texture_get_format (texture)) - { - case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED: - case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED: - case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED: - case GDK_MEMORY_B8G8R8A8: - case GDK_MEMORY_A8R8G8B8: - case GDK_MEMORY_R8G8B8A8: - case GDK_MEMORY_A8B8G8R8: - case GDK_MEMORY_R8G8B8: - case GDK_MEMORY_B8G8R8: - case GDK_MEMORY_R16G16B16: - case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: - case GDK_MEMORY_R16G16B16A16: - bytes = gdk_texture_save_to_png_bytes (texture); - g_string_append (p->str, "texture: url(\"data:image/png;base64,"); - break; - - case GDK_MEMORY_R16G16B16_FLOAT: - case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: - case GDK_MEMORY_R16G16B16A16_FLOAT: - case GDK_MEMORY_R32G32B32_FLOAT: - case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: - case GDK_MEMORY_R32G32B32A32_FLOAT: - bytes = gdk_texture_save_to_tiff_bytes (texture); - g_string_append (p->str, "texture: url(\"data:image/tiff;base64,"); - break; - - case GDK_MEMORY_N_FORMATS: - default: - g_assert_not_reached (); - } - - b64 = base64_encode_with_linebreaks (g_bytes_get_data (bytes, NULL), - g_bytes_get_size (bytes)); - append_escaping_newlines (p->str, b64); - g_free (b64); - g_string_append (p->str, "\");\n"); end_node (p); - - g_bytes_unref (bytes); } break; case GSK_TEXTURE_SCALE_NODE: { - GdkTexture *texture = gsk_texture_scale_node_get_texture (node); GskScalingFilter filter = gsk_texture_scale_node_get_filter (node); - GBytes *bytes; - start_node (p, "texture-scale"); + start_node (p, "texture-scale", node_name); append_rect_param (p, "bounds", &node->bounds); if (filter != GSK_SCALING_FILTER_LINEAR) @@ -2916,49 +3313,9 @@ render_node_print (Printer *p, } } } - _indent (p); - switch (gdk_texture_get_format (texture)) - { - case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED: - case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED: - case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED: - case GDK_MEMORY_B8G8R8A8: - case GDK_MEMORY_A8R8G8B8: - case GDK_MEMORY_R8G8B8A8: - case GDK_MEMORY_A8B8G8R8: - case GDK_MEMORY_R8G8B8: - case GDK_MEMORY_B8G8R8: - case GDK_MEMORY_R16G16B16: - case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: - case GDK_MEMORY_R16G16B16A16: - bytes = gdk_texture_save_to_png_bytes (texture); - g_string_append (p->str, "texture: url(\"data:image/png;base64,"); - break; - - case GDK_MEMORY_R16G16B16_FLOAT: - case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: - case GDK_MEMORY_R16G16B16A16_FLOAT: - case GDK_MEMORY_R32G32B32_FLOAT: - case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: - case GDK_MEMORY_R32G32B32A32_FLOAT: - bytes = gdk_texture_save_to_tiff_bytes (texture); - g_string_append (p->str, "texture: url(\"data:image/tiff;base64,"); - break; - - case GDK_MEMORY_N_FORMATS: - default: - g_assert_not_reached (); - } - - b64 = base64_encode_with_linebreaks (g_bytes_get_data (bytes, NULL), - g_bytes_get_size (bytes)); - append_escaping_newlines (p->str, b64); - g_free (b64); - g_string_append (p->str, "\");\n"); + append_texture_param (p, "texture", gsk_texture_scale_node_get_texture (node)); end_node (p); - - g_bytes_unref (bytes); } break; @@ -2970,7 +3327,7 @@ render_node_print (Printer *p, PangoFontDescription *desc; char *font_name; - start_node (p, "text"); + start_node (p, "text", node_name); if (!gdk_rgba_equal (color, &GDK_RGBA("000000"))) append_rgba_param (p, "color", color); @@ -3001,7 +3358,7 @@ render_node_print (Printer *p, { const char *message = gsk_debug_node_get_message (node); - start_node (p, "debug"); + start_node (p, "debug", node_name); /* TODO: We potentially need to escape certain characters in the message */ if (message) @@ -3017,7 +3374,7 @@ render_node_print (Printer *p, case GSK_BLUR_NODE: { - start_node (p, "blur"); + start_node (p, "blur", node_name); append_float_param (p, "blur", gsk_blur_node_get_radius (node), 1.0f); append_node_param (p, "child", gsk_blur_node_get_child (node)); @@ -3031,7 +3388,7 @@ render_node_print (Printer *p, GskGLShader *shader = gsk_gl_shader_node_get_shader (node); GBytes *args = gsk_gl_shader_node_get_args (node); - start_node (p, "glshader"); + start_node (p, "glshader", node_name); append_rect_param (p, "bounds", &node->bounds); @@ -3149,7 +3506,7 @@ render_node_print (Printer *p, GskRenderNode *child = gsk_repeat_node_get_child (node); const graphene_rect_t *child_bounds = gsk_repeat_node_get_child_bounds (node); - start_node (p, "repeat"); + start_node (p, "repeat", node_name); if (!graphene_rect_equal (&node->bounds, &child->bounds)) append_rect_param (p, "bounds", &node->bounds); @@ -3165,7 +3522,7 @@ render_node_print (Printer *p, { GskBlendMode mode = gsk_blend_node_get_blend_mode (node); - start_node (p, "blend"); + start_node (p, "blend", node_name); if (mode != GSK_BLEND_MODE_DEFAULT) { @@ -3183,7 +3540,7 @@ render_node_print (Printer *p, { GskMaskMode mode = gsk_mask_node_get_mask_mode (node); - start_node (p, "mask"); + start_node (p, "mask", node_name); if (mode != GSK_MASK_MODE_ALPHA) { @@ -3206,7 +3563,7 @@ render_node_print (Printer *p, cairo_surface_t *surface = gsk_cairo_node_get_surface (node); GByteArray *array; - start_node (p, "cairo"); + start_node (p, "cairo", node_name); append_rect_param (p, "bounds", &node->bounds); if (surface != NULL) @@ -3285,7 +3642,7 @@ gsk_render_node_serialize (GskRenderNode *node) { Printer p; - printer_init (&p); + printer_init (&p, node); if (gsk_render_node_get_node_type (node) == GSK_CONTAINER_NODE) { diff --git a/testsuite/gsk/compare/scaled-texture.node b/testsuite/gsk/compare/scaled-texture.node index ffcf9127cc..21e9d83127 100644 --- a/testsuite/gsk/compare/scaled-texture.node +++ b/testsuite/gsk/compare/scaled-texture.node @@ -1,6 +1,17 @@ container { texture-scale { - texture: url("some-10x10-image-with-content.png"); + texture: url("data:image/png;base64,\ +iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9\ +kT1Iw1AUhU9TpSIVBztIUchQxcEuKuKoVShChVArtOpg8tI/aNKQpLg4Cq4FB38Wqw4uzro6uAqC\ +4A+Iq4uToouUeF9SaBHjhcf7OO+ew3v3AUKjwjSraxbQdNtMJxNiNrcqhl4RxDACGENUZpYxJ0kp\ ++NbXPXVS3cV5ln/fn9Wn5i0GBETiWWaYNvEG8fSmbXDeJ46wkqwSnxOPm3RB4keuKx6/cS66LPDM\ +iJlJzxNHiMViBysdzEqmRjxFHFM1nfKFrMcq5y3OWqXGWvfkLwzn9ZVlrtMaQhKLWIIEEQpqKKMC\ +G3HadVIspOk84eOPun6JXAq5ymDkWEAVGmTXD/4Hv2drFSYnvKRwAuh+cZyPESC0CzTrjvN97DjN\ +EyD4DFzpbX+1Acx8kl5va7EjoH8buLhua8oecLkDDD4Zsim7UpCWUCgA72f0TTlg4BboXfPm1jrH\ +6QOQoVmlboCDQ2C0SNnrPu/u6Zzbvz2t+f0AkpVys4Vzl18AAAAGYktHRABmAGYAZge6Sm0AAAAJ\ +cEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQfnAx0BLBeZZvBWAAAAGXRFWHRDb21tZW50AENyZWF0\ +ZWQgd2l0aCBHSU1QV4EOFwAAACpJREFUGNNj/M/A8J+BgYGB4T+EYmBkZMDGZ2IgErAQMgnGJ9pE\ +xhHpRgAVIB4MSL68ZgAAAABJRU5ErkJggg=="); bounds: 0 0 100 100; filter: nearest; } diff --git a/testsuite/gsk/compare/scaled-texture.png b/testsuite/gsk/compare/scaled-texture.png index acc16bf0dd..eeb6a572ff 100644 Binary files a/testsuite/gsk/compare/scaled-texture.png and b/testsuite/gsk/compare/scaled-texture.png differ diff --git a/testsuite/gsk/meson.build b/testsuite/gsk/meson.build index e9abda85d2..cfc1338aae 100644 --- a/testsuite/gsk/meson.build +++ b/testsuite/gsk/meson.build @@ -221,6 +221,10 @@ node_parser_tests = [ 'gradient-fail.errors', 'mask-modes.node', 'mask-modes.ref.node', + 'node-names.node', + 'node-names-everywhere.errors', + 'node-names-everywhere.node', + 'node-names-everywhere.ref.node', 'radial-gradient.node', 'radial-gradient.ref.node', 'repeating-linear-gradient.node', @@ -232,6 +236,9 @@ node_parser_tests = [ 'shadow-fail.node', 'shadow-fail.ref.node', 'shadow-fail.errors', + 'string-error.errors', + 'string-error.node', + 'string-error.ref.node', 'testswitch.node', 'text-fail.node', 'text-fail.ref.node', @@ -239,6 +246,7 @@ node_parser_tests = [ 'texture-fail.node', 'texture-fail.ref.node', 'texture-fail.ref.errors', + 'texture-names.node', 'texture-scale-filters.node', 'texture-scale-filters.ref.node', 'texture-scale-unknown-filter.errors', diff --git a/testsuite/gsk/nodeparser/node-names-everywhere.errors b/testsuite/gsk/nodeparser/node-names-everywhere.errors new file mode 100644 index 0000000000..394cbf8c1b --- /dev/null +++ b/testsuite/gsk/nodeparser/node-names-everywhere.errors @@ -0,0 +1,4 @@ +:1:1-6: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE +:3:3-8: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE +:5:5-10: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE +:2:11-16: error: GTK_CSS_PARSER_ERROR_FAILED diff --git a/testsuite/gsk/nodeparser/node-names-everywhere.node b/testsuite/gsk/nodeparser/node-names-everywhere.node new file mode 100644 index 0000000000..29f4a22328 --- /dev/null +++ b/testsuite/gsk/nodeparser/node-names-everywhere.node @@ -0,0 +1,9 @@ +"foo"; +container "foo" { + "foo"; + container "foo" { + "foo"; + } + "foo"; +} +"foo"; diff --git a/testsuite/gsk/nodeparser/node-names-everywhere.ref.node b/testsuite/gsk/nodeparser/node-names-everywhere.ref.node new file mode 100644 index 0000000000..1314f75b40 --- /dev/null +++ b/testsuite/gsk/nodeparser/node-names-everywhere.ref.node @@ -0,0 +1,6 @@ +container { + container "node1" { + } + "node1"; +} +"node1"; diff --git a/testsuite/gsk/nodeparser/node-names.node b/testsuite/gsk/nodeparser/node-names.node new file mode 100644 index 0000000000..d2b22060e9 --- /dev/null +++ b/testsuite/gsk/nodeparser/node-names.node @@ -0,0 +1,8 @@ +color "node1" { + bounds: 0 0 10 10; + color: rgb(23,42,69); +} +transform { + transform: translate(20, 0); + child: "node1"; +} diff --git a/testsuite/gsk/nodeparser/string-error.errors b/testsuite/gsk/nodeparser/string-error.errors new file mode 100644 index 0000000000..47ad1d1e75 --- /dev/null +++ b/testsuite/gsk/nodeparser/string-error.errors @@ -0,0 +1 @@ +:2:12-13: error: GTK_CSS_PARSER_ERROR_SYNTAX diff --git a/testsuite/gsk/nodeparser/string-error.node b/testsuite/gsk/nodeparser/string-error.node new file mode 100644 index 0000000000..6e62f6a6f5 --- /dev/null +++ b/testsuite/gsk/nodeparser/string-error.node @@ -0,0 +1,3 @@ +debug { + message: 5; +} diff --git a/testsuite/gsk/nodeparser/string-error.ref.node b/testsuite/gsk/nodeparser/string-error.ref.node new file mode 100644 index 0000000000..fc7e73a4c7 --- /dev/null +++ b/testsuite/gsk/nodeparser/string-error.ref.node @@ -0,0 +1,6 @@ +debug { + child: color { + bounds: 0 0 50 50; + color: rgb(255,0,204); + } +} diff --git a/testsuite/gsk/nodeparser/texture-names.node b/testsuite/gsk/nodeparser/texture-names.node new file mode 100644 index 0000000000..ac080fa2ed --- /dev/null +++ b/testsuite/gsk/nodeparser/texture-names.node @@ -0,0 +1,10 @@ +texture { + bounds: 0 0 1 1; + texture: "texture1" url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWP4z8DwHwAFAAH/q842\ +iQAAAABJRU5ErkJggg==\ +"); +} +texture { + bounds: 2 0 1 1; + texture: "texture1"; +}