Subject: bug#64908: 29.1; svg parse failure

From: David Ponce <[email-masked]>
Date: Fri, 4 Aug 2023 18:23:11 +0200

On 04/08/2023 12:26, Eli Zaretskii wrote:
>> Date: Fri, 4 Aug 2023 09:55:03 +0200
>> Cc: [email-masked]
>> From: David Ponce <[email-masked]>
>>
>> On 04/08/2023 07:23, Eli Zaretskii wrote:
>>>> Date: Thu, 3 Aug 2023 21:16:35 +0200
>>>> From: David Ponce <[email-masked]>
>>>>
>>>> In case it could help, using emacs from master (see details at end
>>>> below), with librsvg2-2.56.0-1.fc38.x86_64 I can insert-image
>>>> dir-src-open.svg and dir-public-open.svg in the *scratch-buffer*
>>>> without issue (see Screenshot1).
>>>>
>>>> However, the same failed using librsvg2-2.56.3-1.fc38.x86_64 (see
>>>> Screenshot2).
>>>>
>>>> I did test also with some KDE breeze icons.
>>>>
>>>> No issue with librsvg2-2.56.0-1.fc38.x86_64.
>>>>
>>>> With librsvg2-2.56.3-1.fc38.x86_64 some icons works, some not (see an
>>>> example in Screenshot3):
>>>>
>>>> /usr/share/icons/breeze/actions/22/go-next.svg doesn't work:
>>>>
>> [...]
>>>>
>>>> /usr/share/icons/breeze/actions/22/go-next.svg works:
>>>>
>> [...]
>>>>
>>>> As far as I can see, other applications (Gwenview, Geeqie, Firefox) don't have
>>>> problem to display the same images with librsvg2-2.56.3-1.fc38.x86_64 installed.
>>>
>>> Thanks, this helps.
>>>
>>> When an image fails to display, do you see any error messages from
>>> librsvg?  Those are usually emitted to stderr, so perhaps you need to
>>> run Emacs in a way that stderr is not discarded, but either shown on
>>> the terminal or written to a file.
>>
>> Hello ELi,
>>
>> I don't see any message on stderr, but a bunch of messages:
>> "Invalid image size (see ‘max-image-size’)" in the *Messages* buffer,
>> probably related to the display of an invalid image (empty square)
>> in the *scratch* buffer. Also, the result of image-size is not the
>> expected image size (22x22 px in example). I attached a screenshot.
> 
> Thanks.  I hope this will help an SVG expert to figure out what's
> going on with these images.
> 
> Alan, do you have time to look into this, per chance?

I investigated further the issue with GDB, with a break in
svg_load_image in image.c, trying to display the image
"/usr/share/icons/breeze/actions/22/go-next.svg":

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22">
    <defs id="defs3051">
      <style type="text/css" id="current-color-scheme">
        .ColorScheme-Text {
          color:#232629;
        }
        </style>
    </defs>
   <path
      style="fill:currentColor;fill-opacity:1;stroke:none"
	d="m7.707031 3l-.707031.707031 6.125 6.125 1.167969 1.167969-1.167969 1.167969-6.125 6.125.707031.707031 6.125-6.125 1.875-1.875-1.875-1.875-6.125-6.125"
      class="ColorScheme-Text"
      />
</svg>

I think the problem is after the call to
rsvg_handle_get_intrinsic_dimensions at line 11354 in image.c.
Here is the relevant portion of code:

       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, 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;
         }

After the call to rsvg_handle_get_intrinsic_dimensions, the returned
values are:

(gdb) print has_width
$8 = 1
(gdb) print iwidth
$9 = {length = 1, unit = RSVG_UNIT_PERCENT}
(gdb) print iheight
$10 = {length = 1, unit = RSVG_UNIT_PERCENT}
(gdb) print viewbox
$11 = {x = 0, y = 0, width = 22, height = 22}

has_width and has_height are both 1 with iwidth and iheight set to
100%.  has_viewbox is also set to 1, and viewport contains the
dimensions of the image (22x22 pixels).

Then, the code matching "if (has_width && has_height)" is executed,
which, in this case, sets both viewbox_width and viewbox_height to 0,
which further leads to an image_size_error.

Maybe, it is due to a change of specifications since librsvg 2.54.0.

Here is what the spec I found at
<https://gnome.pages.gitlab.gnome.org/librsvg/Rsvg-2.0/method.Handle.get_intrinsic_dimensions.html>
says:

-----
Before librsvg 2.54.0, the out_has_width and out_has_height arguments
would be set to true or false depending on whether the SVG document
actually had width and height attributes, respectively.

However, since librsvg 2.54.0, width and height are now geometry
properties per the SVG2 specification; they are not plain
attributes. SVG2 made it so that the initial value of those properties
is auto, which is equivalent to specifing a value of 100%. In this
sense, even SVG documents which lack width or height attributes
semantically have to make them default to 100%. This is why since
librsvg 2.54.0, out_has_width and out_has_heigth are always returned
as TRUE, since with SVG2 all documents have a default width and height
of 100%.

As an example, the following SVG element has a width of 100 pixels and
a height of 400 pixels, but no viewBox. This function will return
those sizes in out_width and out_height, and set out_has_viewbox to
FALSE.

<svg xmlns="http://www.w3.org/2000/svg" width="100" height="400">

Conversely, the following element has a viewBox, but no width or
height. This function will set out_has_viewbox to TRUE, and it will
also set out_has_width and out_has_height to TRUE but return both
length values as 100%.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 400">
-----

I hope it will help an SVG expert to fix the issue.

Thanks