nodeparser: Support texture-scale nodes
authorMatthias Clasen <mclasen@redhat.com>
Wed, 8 Feb 2023 12:06:09 +0000 (07:06 -0500)
committerMatthias Clasen <mclasen@redhat.com>
Sat, 11 Feb 2023 20:09:38 +0000 (15:09 -0500)
demos/node-editor/node-format.md
gsk/gskrendernodeparser.c

index ca9417f7d00b22b5303562a6f6465cdd483a3594..557a8950a5572b7685cf18f80d45f69dda732abd 100644 (file)
@@ -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   | `<rect>`         | 50                     | always      |
+| texture  | `<url>`          | *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     |
index 68069b477e8b60b9239575e814747f6f5b59221f..ee27eda5a7ab8c9b9ff22e5c839cdd8c4cde1017 100644 (file)
@@ -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);