From: Alan Third Date: Sun, 25 Oct 2020 15:45:07 +0000 (+0000) Subject: Calculate SVG image sizes more accurately (bug#44206) X-Git-Tag: emacs-28.0.90~5212^2~2 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=4469e0de011c2c5862f6c1c970b9ad1dfbbda496;p=emacs.git 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. --- diff --git a/src/image.c b/src/image.c index c857b8e62a4..b4cb1b7bf83 100644 --- a/src/image.c +++ b/src/image.c @@ -9545,6 +9545,9 @@ DEF_DLL_FN (gboolean, rsvg_handle_close, (RsvgHandle *, GError **)); #endif #if LIBRSVG_CHECK_VERSION (2, 46, 0) +DEF_DLL_FN (void, rsvg_handle_get_intrinsic_dimensions, + RsvgHandle *, gboolean *, RsvgLength *, gboolean *, + RsvgLength *, gboolean *, RsvgRectangle *)); DEF_DLL_FN (gboolean, rsvg_handle_get_geometry_for_layer, (RsvgHandle *, const char *, const RsvgRectangle *, RsvgRectangle *, RsvgRectangle *, GError **)); @@ -9599,6 +9602,7 @@ init_svg_functions (void) LOAD_DLL_FN (library, rsvg_handle_close); #endif #if LIBRSVG_CHECK_VERSION (2, 46, 0) + LOAD_DLL_FN (library, rsvg_handle_get_intrinsic_dimensions); LOAD_DLL_FN (library, rsvg_handle_get_geometry_for_layer); #else LOAD_DLL_FN (library, rsvg_handle_get_dimensions); @@ -9742,6 +9746,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. @@ -9810,11 +9852,48 @@ svg_load_image (struct frame *f, struct image *img, char *contents, #if LIBRSVG_CHECK_VERSION (2, 46, 0) RsvgRectangle zero_rect, viewbox, out_logical_rect; - rsvg_handle_get_geometry_for_layer (rsvg_handle, NULL, - &zero_rect, &viewbox, - &out_logical_rect, 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, + &out_logical_rect, 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 @@ -9827,6 +9906,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);