Subject: bug#64908: 29.1; svg parse failure

From: Alan Third <[email-masked]>
Date: Sat, 5 Aug 2023 11:24:19 +0100

On Sat, Aug 05, 2023 at 01:07:38PM +0300, Eli Zaretskii wrote:
> > Date: Sat, 5 Aug 2023 10:58:26 +0100
> > From: Alan Third <[email-masked]>
> > Cc: Eli Zaretskii <[email-masked]>, [email-masked]
> > 
> > diff --git a/src/image.c b/src/image.c
> > index c9420b48f4a..96e0f2a7225 100644
> > --- a/src/image.c
> > +++ b/src/image.c
> > @@ -11161,6 +11161,21 @@ svg_css_length_to_pixels (RsvgLength length, double dpi, int font_size)
> >      case RSVG_UNIT_IN:
> >        value *= dpi;
> >        break;
> > +    case RSVG_UNIT_PERCENT:
> > +      /* Percent is a ratio of the containing "viewport".  We don't
> > +	 have a viewport, as such, as we try to draw the image to it's
> > +	 own desired size rather than dictate the size as if we were
> > +	 drawing icons on a toolbar or similar.  This means that
> > +	 percent values are useless to us and we are best off just
> > +	 drawing the image according to whatever other sizes we can
> > +	 derive.
> > +
> > +	 If we do set explicit width and height values in the image
> > +	 spec, this will work out correctly as librsvg will still
> > +	 honour the percentage sizes in its final rendering no matter
> > +	 what size we make the image.  */
> > +      value = 0;
> > +      break;
> 
> I don't see RSVG_UNIT_PERCENT anywhere in the librsvg headers on my
> system, so perhaps this was introduced by some later version, and
> should be guarded by LIBRSVG_CHECK_VERSION?

Hmm, I can't find any reference to when it was introduced, so it's
probably easier just to remove it and put the comment in the default
case.

(Interestingly while searching for the version I discovered this code
has been used, almost verbatim, in libvips. The main difference is
they're defining "ex" as half of "em", so perhaps we should copy that
change back over...)
-- 
Alan Third
>From 126ee4b2dffc183e48a47a562a05a142f420ea4d Mon Sep 17 00:00:00 2001
From: Alan Third <[email-masked]>
Date: Sat, 5 Aug 2023 10:39:31 +0100
Subject: [PATCH v2] Fix percentage sizes in SVG display (bug#64908)

* src/image.c (svg_css_length_to_pixels): Make percent units always
return zero.
(svg_load_image): Don't rely on the width and height values from the
SVG actually having any useful data, even if they're explicitly set.
---
 src/image.c | 60 ++++++++++++++++++++++++++++++++---------------------
 1 file changed, 36 insertions(+), 24 deletions(-)

diff --git a/src/image.c b/src/image.c
index c9420b48f4a..4e07ea8268d 100644
--- a/src/image.c
+++ b/src/image.c
@@ -11169,8 +11169,26 @@ svg_css_length_to_pixels (RsvgLength length, double dpi, int font_size)
       break;
 #endif
     default:
-      /* Probably ex or %.  We can't know what the pixel value is
-         without more information.  */
+      /* If it's ex then we can't know what the pixel value is without
+         more information.
+
+	 FIXME: perhaps ex should be 1/2 of an em?  I imagine we
+	 should try to match what librsvg does.
+
+	 If it's percent then we don't want to do anything with it.
+
+         Percent is a ratio of the containing "viewport".  We don't
+	 have a viewport, as such, as we try to draw the image to it's
+	 own desired size rather than dictate the size as if we were
+	 drawing icons on a toolbar or similar.  This means that
+	 percent values are useless to us and we are best off just
+	 drawing the image according to whatever other sizes we can
+	 derive.
+
+	 If we do set explicit width and height values in the image
+	 spec, this will work out correctly as librsvg will still
+	 honour the percentage sizes in its final rendering no matter
+	 what size we make the image.  */
       value = 0;
     }
 
@@ -11302,6 +11320,7 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
   else
     {
       RsvgRectangle zero_rect, viewbox, out_logical_rect;
+      double explicit_width = 0, explicit_height = 0;
 
       /* Try the intrinsic dimensions first.  */
       gboolean has_width, has_height;
@@ -11313,34 +11332,27 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
 					    &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, dpi,
+      if (has_width)
+	explicit_width = svg_css_length_to_pixels (iwidth, dpi,
+						   img->face_font_size);
+      if (has_height)
+	explicit_height = svg_css_length_to_pixels (iheight, dpi,
 						    img->face_font_size);
-	  viewbox_height = svg_css_length_to_pixels (iheight, dpi,
-						     img->face_font_size);
 
-	  /* Here one dimension could be zero because in percent unit.
-	     So calculate this dimension with the other.  */
-	  if (! (0 < viewbox_width) && (iwidth.unit == RSVG_UNIT_PERCENT))
-	    viewbox_width = (viewbox_height * viewbox.width / viewbox.height)
-	      * iwidth.length;
-	  else if (! (0 < viewbox_height) && (iheight.unit == RSVG_UNIT_PERCENT))
-	    viewbox_height = (viewbox_width * viewbox.height / viewbox.width)
-	      * iheight.length;
+      if (explicit_width > 0 && explicit_height > 0)
+	{
+	  viewbox_width = explicit_width;
+	  viewbox_height = explicit_height;
 	}
-      else if (has_width && has_viewbox)
+      else if (explicit_width > 0 && has_viewbox)
 	{
-	  viewbox_width = svg_css_length_to_pixels (iwidth, dpi,
-						    img->face_font_size);
-	  viewbox_height = viewbox_width * viewbox.height / viewbox.width;
+	  viewbox_width = explicit_width;
+	  viewbox_height = explicit_width * viewbox.height / viewbox.width;
 	}
-      else if (has_height && has_viewbox)
+      else if (explicit_height > 0 && has_viewbox)
 	{
-	  viewbox_height = svg_css_length_to_pixels (iheight, dpi,
-						     img->face_font_size);
-	  viewbox_width = viewbox_height * viewbox.width / viewbox.height;
+	  viewbox_height = explicit_height;
+	  viewbox_width = explicit_height * viewbox.width / viewbox.height;
 	}
       else if (has_viewbox)
 	{
-- 
2.40.1