From a178c8b58e37550a897062f1edfe1f674bf7d210 Mon Sep 17 00:00:00 2001 From: Alan Third Date: Sun, 25 Oct 2020 15:45:07 +0000 Subject: [PATCH] Calculate SVG image sizes more accurately (bug#44206) * src/image.c (svg_css_length_to_pixels): New function. (svg_load_image): Try more methods to work out the image size. --- src/image.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 93 insertions(+), 5 deletions(-) diff --git a/src/image.c b/src/image.c index 5f6d9f4c44..2f9c21cbcc 100644 --- a/src/image.c +++ b/src/image.c @@ -9724,6 +9724,44 @@ svg_load (struct frame *f, struct image *img) return success_p; } +static double +svg_css_length_to_pixels (RsvgLength length) +{ + /* FIXME: 96 appears to be a pretty standard DPI but we should + probably use the real DPI if we can get it. */ + double dpi = 96; + double value = length.length; + + switch (length.unit) + { + case RSVG_UNIT_PX: + /* Already a pixel value. */ + break; + case RSVG_UNIT_CM: + /* 2.54 cm in an inch. */ + value = dpi * value / 2.54; + case RSVG_UNIT_MM: + /* 25.4 mm in an inch. */ + value = dpi * value / 25.4; + break; + case RSVG_UNIT_PT: + /* 72 points in an inch. */ + value = dpi * value / 72; + case RSVG_UNIT_PC: + /* 6 picas in an inch. */ + value = dpi * value / 6; + case RSVG_UNIT_IN: + value *= dpi; + break; + default: + /* Probably one of em, ex, or %. We can't know what the pixel + value is without more information. */ + value = 0; + } + + return value; +} + /* Load frame F and image IMG. CONTENTS contains the SVG XML data to be parsed, SIZE is its size, and FILENAME is the name of the SVG file being loaded. @@ -9792,11 +9830,48 @@ svg_load_image (struct frame *f, struct image *img, char *contents, #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; + /* Try the instrinsic dimensions first. */ + gboolean has_width, has_height, has_viewbox; + RsvgLength iwidth, iheight; + + rsvg_handle_get_intrinsic_dimensions (rsvg_handle, + &has_width, &iwidth, + &has_height, &iheight, + &has_viewbox, &viewbox); + + if (has_width && has_height) + { + /* Success! We can use these values directly. */ + viewbox_width = svg_css_length_to_pixels (iwidth); + viewbox_height = svg_css_length_to_pixels (iheight); + } + else if (has_width && has_viewbox) + { + viewbox_width = svg_css_length_to_pixels (iwidth); + viewbox_height = svg_css_length_to_pixels (iwidth) + * viewbox.width / viewbox.height; + } + else if (has_height && has_viewbox) + { + viewbox_height = svg_css_length_to_pixels (iheight); + viewbox_width = svg_css_length_to_pixels (iheight) + * viewbox.height / viewbox.width; + } + else if (has_viewbox) + { + viewbox_width = viewbox.width; + viewbox_height = viewbox.height; + } + else + { + /* We haven't found a useable set of sizes, so try working out + the visible area. */ + 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 @@ -9809,6 +9884,19 @@ svg_load_image (struct frame *f, struct image *img, char *contents, viewbox_width = dimension_data.width; viewbox_height = dimension_data.height; #endif + + if (viewbox_width == 0 || viewbox_height == 0) + { + /* We do not have any usable dimensions, so make some up. The + values below are supposedly the default values most web + browsers use for SVGs with no set size. */ + /* FIXME: At this stage we should perhaps consider rendering the + image out to a bitmap and getting the dimensions from + that. */ + viewbox_width = 300; + viewbox_height = 150; + } + compute_image_size (viewbox_width, viewbox_height, img->spec, &width, &height); -- 2.26.1