diff --git a/demos/node-editor/node-format.md b/demos/node-editor/node-format.md index ca9417f7d0..557a8950a5 100644 --- a/demos/node-editor/node-format.md +++ b/demos/node-editor/node-format.md @@ -297,6 +297,21 @@ The default texture is a 10x10 checkerboard with the top left and bottom right representation for this texture is `url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABmJLR0QA/wD/AP+gvaeTAAAAKUlEQVQYlWP8z3DmPwMaYGQwYUQXY0IXwAUGUCGGoxkYGBiweXAoeAYAz44F3e3U1xUAAAAASUVORK5CYII=") `. +### texture-scale + +| property | syntax | default | printed | +| -------- | ---------------- | ---------------------- | ----------- | +| bounds | `` | 50 | always | +| texture | `` | *see below* | always | +| filter | `filter` | *see below* | non-default | + +Creates a node like `gsk_texture_scale_node_new()` with the given properties. + +The default texture is a 10x10 checkerboard, just like for texture. + +The possible filter values are `linear`, `nearest` and `trilinear`, with +`linear` being the default. + ### transform | property | syntax | default | printed | diff --git a/gsk/gskrendernodeparser.c b/gsk/gskrendernodeparser.c index 68069b477e..ee27eda5a7 100644 --- a/gsk/gskrendernodeparser.c +++ b/gsk/gskrendernodeparser.c @@ -600,6 +600,32 @@ clear_shadows (gpointer inout_shadows) g_array_set_size (*(GArray **) inout_shadows, 0); } +static const struct +{ + GskScalingFilter filter; + const char *name; +} scaling_filters[] = { + { GSK_SCALING_FILTER_LINEAR, "linear" }, + { GSK_SCALING_FILTER_NEAREST, "nearest" }, + { GSK_SCALING_FILTER_TRILINEAR, "trilinear" }, +}; + +static gboolean +parse_scaling_filter (GtkCssParser *parser, + gpointer out_filter) +{ + for (unsigned int i = 0; i < G_N_ELEMENTS (scaling_filters); i++) + { + if (gtk_css_parser_try_ident (parser, scaling_filters[i].name)) + { + *(GskScalingFilter *) out_filter = scaling_filters[i].filter; + return TRUE; + } + } + + return FALSE; +} + static const struct { GskBlendMode mode; @@ -1389,6 +1415,30 @@ parse_texture_node (GtkCssParser *parser) return node; } +static GskRenderNode * +parse_texture_scale_node (GtkCssParser *parser) +{ + graphene_rect_t bounds = GRAPHENE_RECT_INIT (0, 0, 50, 50); + GdkTexture *texture = NULL; + GskScalingFilter filter = GSK_SCALING_FILTER_LINEAR; + const Declaration declarations[] = { + { "bounds", parse_rect, NULL, &bounds }, + { "texture", parse_texture, clear_texture, &texture }, + { "filter", parse_scaling_filter, NULL, &filter } + }; + GskRenderNode *node; + + parse_declarations (parser, declarations, G_N_ELEMENTS (declarations)); + + if (texture == NULL) + texture = create_default_texture (); + + node = gsk_texture_scale_node_new (texture, &bounds, filter); + g_object_unref (texture); + + return node; +} + static GskRenderNode * parse_cairo_node (GtkCssParser *parser) { @@ -1861,6 +1911,7 @@ parse_node (GtkCssParser *parser, { "shadow", parse_shadow_node }, { "text", parse_text_node }, { "texture", parse_texture_node }, + { "texture-scale", parse_texture_scale_node }, { "transform", parse_transform_node }, { "glshader", parse_glshader_node }, }; @@ -2757,6 +2808,73 @@ render_node_print (Printer *p, } 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"); + append_rect_param (p, "bounds", &node->bounds); + + if (filter != GSK_SCALING_FILTER_LINEAR) + { + _indent (p); + for (unsigned int i = 0; i < G_N_ELEMENTS (scaling_filters); i++) + { + if (scaling_filters[i].filter == filter) + { + g_string_append_printf (p->str, "filter: %s;\n", scaling_filters[i].name); + break; + } + } + } + _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_TEXT_NODE: { const graphene_point_t *offset = gsk_text_node_get_offset (node);