From 3f16f7e0d4ff44ff62d10fc0b4c2fb230999f36d Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 30 Jul 2023 20:00:34 +0200 Subject: [PATCH] rendernode-tool: Add another magic format Make .svg use the Cairo renderer to save to an SVG file. It's useful when comparing rendering behavior and times with web browsers (as long as one is aware that browsers build a full DOM tree out of those SVGs). --- tools/gtk-rendernode-tool-render.c | 101 ++++++++++++++++++++++++----- 1 file changed, 86 insertions(+), 15 deletions(-) diff --git a/tools/gtk-rendernode-tool-render.c b/tools/gtk-rendernode-tool-render.c index 066ac661c8..c8d98da3f8 100644 --- a/tools/gtk-rendernode-tool-render.c +++ b/tools/gtk-rendernode-tool-render.c @@ -28,6 +28,9 @@ #include #include #include "gtk-rendernode-tool.h" +#ifdef CAIRO_HAS_SVG_SURFACE +#include +#endif static char * get_save_filename (const char *filename) @@ -48,6 +51,58 @@ get_save_filename (const char *filename) return result; } +#ifdef CAIRO_HAS_SVG_SURFACE +static cairo_status_t +cairo_serializer_write (gpointer user_data, + const unsigned char *data, + unsigned int length) +{ + g_byte_array_append (user_data, data, length); + + return CAIRO_STATUS_SUCCESS; +} + +static GBytes * +create_svg (GskRenderNode *node, + GError **error) +{ + cairo_surface_t *surface; + cairo_t *cr; + graphene_rect_t bounds; + GByteArray *array; + + gsk_render_node_get_bounds (node, &bounds); + array = g_byte_array_new (); + + surface = cairo_svg_surface_create_for_stream (cairo_serializer_write, + array, + bounds.size.width, + bounds.size.height); + cairo_svg_surface_set_document_unit (surface, CAIRO_SVG_UNIT_PX); + cairo_surface_set_device_offset (surface, -bounds.origin.x, -bounds.origin.y); + + cr = cairo_create (surface); + gsk_render_node_draw (node, cr); + cairo_destroy (cr); + + cairo_surface_finish (surface); + if (cairo_surface_status (surface) == CAIRO_STATUS_SUCCESS) + { + cairo_surface_destroy (surface); + return g_byte_array_free_to_bytes (array); + } + else + { + g_set_error (error, + G_IO_ERROR, G_IO_ERROR_FAILED, + "%s", cairo_status_to_string (cairo_surface_status (surface))); + cairo_surface_destroy (surface); + g_byte_array_unref (array); + return NULL; + } +} +#endif + static void render_file (const char *filename, const char *renderer_name, @@ -55,10 +110,7 @@ render_file (const char *filename, { GskRenderNode *node; GBytes *bytes; - GdkTexture *texture; char *save_to; - GskRenderer *renderer; - GdkSurface *window; GError *error = NULL; save_to = (char *) save_file; @@ -76,20 +128,40 @@ render_file (const char *filename, node = load_node_file (filename); - if (renderer_name) - g_object_set_data_full (G_OBJECT (gdk_display_get_default ()), "gsk-renderer", - g_strdup (renderer_name), g_free); +#ifdef CAIRO_HAS_SVG_SURFACE + if (g_str_has_suffix (save_to, ".svg")) + { + bytes = create_svg (node, &error); + if (bytes == NULL) + { + g_printerr (_("Failed to generate SVG: %s\n"), error->message); + exit (1); + } + } + else +#endif + { + GdkTexture *texture; + GskRenderer *renderer; + GdkSurface *window; - window = gdk_surface_new_toplevel (gdk_display_get_default ()); - renderer = gsk_renderer_new_for_surface (window); + if (renderer_name) + g_object_set_data_full (G_OBJECT (gdk_display_get_default ()), "gsk-renderer", + g_strdup (renderer_name), g_free); - texture = gsk_renderer_render_texture (renderer, node, NULL); + window = gdk_surface_new_toplevel (gdk_display_get_default ()); + renderer = gsk_renderer_new_for_surface (window); - if (g_str_has_suffix (save_to, ".tif") || - g_str_has_suffix (save_to, ".tiff")) - bytes = gdk_texture_save_to_tiff_bytes (texture); - else - bytes = gdk_texture_save_to_png_bytes (texture); + texture = gsk_renderer_render_texture (renderer, node, NULL); + + if (g_str_has_suffix (save_to, ".tif") || + g_str_has_suffix (save_to, ".tiff")) + bytes = gdk_texture_save_to_tiff_bytes (texture); + else + bytes = gdk_texture_save_to_png_bytes (texture); + + g_object_unref (texture); + } if (g_file_set_contents (save_to, g_bytes_get_data (bytes, NULL), @@ -110,7 +182,6 @@ render_file (const char *filename, if (save_to != save_file) g_free (save_to); - g_object_unref (texture); gsk_render_node_unref (node); } -- 2.30.2