From b42481e22eb1c1adfcef419d45bf9733837684cb Mon Sep 17 00:00:00 2001 From: Alan Third Date: Mon, 19 Oct 2020 21:19:57 +0100 Subject: [PATCH] Fix SVG image dimension calculations (bug#44065) * src/image.c (svg_load_image): Calculate the image size by using the viewBox size and applying it to the image. * etc/PROBLEMS: Describe the problem with librsvg 2.45 and below. --- etc/PROBLEMS | 4 ++++ src/image.c | 46 ++++++++++++++++++++++++++++++++-------------- 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/etc/PROBLEMS b/etc/PROBLEMS index 41d5ea1bb75..8ed92ab75e0 100644 --- a/etc/PROBLEMS +++ b/etc/PROBLEMS @@ -181,6 +181,10 @@ Configure checks for the correct version, but this problem could occur if a binary built against a shared libungif is run on a system with an older version. +** SVG images may be cropped incorrectly with librsvg 2.45 and below. +Librsvg 2.46 and above have improved geometry code which Emacs is able +to take advantage of. + ** Emacs aborts inside the function 'tparam1'. This can happen if Emacs was built without terminfo support, but the diff --git a/src/image.c b/src/image.c index 25d5af8a8d5..5f6d9f4c443 100644 --- a/src/image.c +++ b/src/image.c @@ -9736,7 +9736,7 @@ svg_load_image (struct frame *f, struct image *img, char *contents, ptrdiff_t size, char *filename) { RsvgHandle *rsvg_handle; - RsvgDimensionData dimension_data; + double viewbox_width, viewbox_height; GError *err = NULL; GdkPixbuf *pixbuf; int width; @@ -9789,15 +9789,38 @@ svg_load_image (struct frame *f, struct image *img, char *contents, #endif /* Get the image dimensions. */ +#if LIBRSVG_CHECK_VERSION (2, 46, 0) + RsvgRectangle zero_rect, viewbox; + + rsvg_handle_get_geometry_for_layer (rsvg_handle, NULL, + &zero_rect, &viewbox, + NULL, NULL); + viewbox_width = viewbox.x + viewbox.width; + viewbox_height = viewbox.y + viewbox.height; +#else + /* The function used above to get the geometry of the visible area + of the SVG are only available in librsvg 2.46 and above, so in + certain circumstances this code path can result in some parts of + the SVG being cropped. */ + RsvgDimensionData dimension_data; + rsvg_handle_get_dimensions (rsvg_handle, &dimension_data); + viewbox_width = dimension_data.width; + viewbox_height = dimension_data.height; +#endif + compute_image_size (viewbox_width, viewbox_height, img->spec, + &width, &height); + + if (! check_image_size (f, width, height)) + { + image_size_error (); + goto rsvg_error; + } + /* We are now done with the unmodified data. */ g_object_unref (rsvg_handle); - /* Calculate the final image size. */ - compute_image_size (dimension_data.width, dimension_data.height, - img->spec, &width, &height); - /* Wrap the SVG data in another SVG. This allows us to set the width and height, as well as modify the foreground and background colors. */ @@ -9820,7 +9843,7 @@ svg_load_image (struct frame *f, struct image *img, char *contents, "xmlns:xi=\"http://www.w3.org/2001/XInclude\" " "style=\"color: #%06X; fill: currentColor;\" " "width=\"%d\" height=\"%d\" preserveAspectRatio=\"none\" " - "viewBox=\"0 0 %d %d\">" + "viewBox=\"0 0 %f %f\">" "" "" ""; @@ -9845,8 +9868,9 @@ svg_load_image (struct frame *f, struct image *img, char *contents, if (!wrapped_contents || buffer_size <= snprintf (wrapped_contents, buffer_size, wrapper, foreground & 0xFFFFFF, width, height, - dimension_data.width, dimension_data.height, - background & 0xFFFFFF, SSDATA (encoded_contents))) + viewbox_width, viewbox_height, + background & 0xFFFFFF, + SSDATA (encoded_contents))) goto rsvg_error; wrapped_size = strlen (wrapped_contents); @@ -9887,12 +9911,6 @@ svg_load_image (struct frame *f, struct image *img, char *contents, if (err) goto rsvg_error; #endif - rsvg_handle_get_dimensions (rsvg_handle, &dimension_data); - if (! check_image_size (f, dimension_data.width, dimension_data.height)) - { - image_size_error (); - goto rsvg_error; - } /* We can now get a valid pixel buffer from the svg file, if all went ok. */ -- 2.39.2