Page MenuHomePhabricator

librsvg ignores functional URLs that use single quotation marks
Open, LowPublicBUG REPORT

Description

Steps to Reproduce:
See https://commons.wikimedia.org/wiki/File:SVG_Gradient.svg.
The top row of rectangles all use rect elements with fill="url('#idgrad')".

Actual Results:

The top row of rectangles are rendered with the default black fill.

Expected Results:

The top row of rectangles should have gradient fills similar to the bottom left rectangle.

If I change the fills to url(#idgrad) (i.e., remove the single quotation marks from the functional url), then they work

Event Timeline

Aklapper moved this task from Backlog to Patch merged upstream on the Upstream board.

This does not happen anymore in my local version of librsvg2-2.45.6

AntiCompositeNumber moved this task from Backlog to Upstream (librsvg) on the Thumbor board.

Confirming fixed in rsvg-convert version 2.44.10.

SVG_Gradient.svg-44.png (200×300 px, 5 KB)

@Glrx: Is there a definition in the W3C-Standard that Quotes are allowed?

Doesn't look like it, though there is no EBNF grammar given for FuncIRI. https://www.w3.org/TR/SVG11/types.html#DataTypeFuncIRI

@AntiCompositeNumber @JoKalliauer @RazrFalcon
From my Commons talk page ( https://commons.wikimedia.org/wiki/User_talk:Glrx#fill=%22url('#gfuser')%22_allowed ) on 28 Feb 2020:

It comes from CSS creeping into SVG presentation attributes. The url() notation is CSS.
See https://svgwg.org/svg2-draft/painting.html#FillProperty that says the fill presentation property in SVG 2 may be of type <paint>.
See https://svgwg.org/svg2-draft/painting.html#SpecifyingPaint that says <paint> may be a CSS <url> value.
See https://www.w3.org/TR/css3-values/#url-value that says a <url> is url(<string>...).
See https://www.w3.org/TR/css3-values/#string-value that says a string may use single or double quotation marks
See https://www.w3.org/TR/css3-values/#urls that says a string inside url(...) may be written without quotation marks.
So these are legal SVG 2:

  • fill="url(#abc)"
  • fill="url('#abc')"
  • fill='url("#abc")'

In addition, the fill property may appear in CSS style statements in those variations.
The FuncIRI is allowed as <paint> in SVG 1.1, but the syntax does not explicitly allow quotation marks. The quotation marks may be allowed in CSS 2.x, but I have not checked that out. Maybe the example figure is not SVG 1.1.

It looks like the tokenizer in CSS 2.1 allows quotation marks for a URI:

  • "url("{w}{string}{w}")" {return URI;}
  • "url("{w}{url}{w}")" {return URI;}

because a {string} is something in single or double quotes. The second token grammar allows a URL without quotation marks.
See https://www.w3.org/TR/CSS21/grammar.html

It is the same in CSS 2.
See https://www.w3.org/TR/1998/REC-CSS2-19980512/grammar.html

Generally, SVG 1.1 incorporated a subset of CSS 2. Therefore one should be able to use style attributes with url() syntax

  • <circle cx="100" cy="100" r="20" style="fill:url('#idname')" />

If CSS url() syntax with quotation marks is allowed in style attributes, then it should be allowed in fill attributes.

@Glrx as mentioned here, it's not that simple. I guess I would have to add at least a minimal support.

@RazrFalcon This bug is very low priority; the old librsvg didn't do it right, so it will have almost no impact on WMF's SVG files.

As for issue 781, it seems to be out of scope.

<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
    <linearGradient id="lg">
        <stop offset="1" stop-color="green"/>
    </linearGradient>

    <linearGradient id=" lg">
        <stop offset="1" stop-color="yellow"/>
    </linearGradient>

    <linearGradient id="lg ">
        <stop offset="1" stop-color="blue"/>
    </linearGradient>

    <!-- first column -->
    <rect id="rect1"  x="70"  y="10"  width="20" height="20" fill="url('#lg')"/>
    <rect id="rect2"  x="70"  y="40"  width="20" height="20" fill='url("#lg")'/>
    <rect id="rect3"  x="70"  y="70"  width="20" height="20" fill="url('#lg ')"/>
    <rect id="rect4"  x="70"  y="100" width="20" height="20" fill="url(' #lg')"/>
    <rect id="rect5"  x="70"  y="130" width="20" height="20" fill="url(' #lg ')"/>
    <rect id="rect6"  x="70"  y="160" width="20" height="20" fill="url(' # lg ')"/>

    <!-- second column -->
    <rect id="rect7"  x="100" y="10"  width="20" height="20" fill="url('#lg  ')"/>
    <rect id="rect8"  x="100" y="40"  width="20" height="20" fill="url('#  lg')"/>
    <rect id="rect9"  x="100" y="70"  width="20" height="20" fill="url('# lg ')"/>

    <!-- image frame -->
    <rect id="frame" x="1" y="1" width="198" height="198" fill="none" stroke="black"/>
</svg>

The id="lg" is legal, but id=" lg" and id="lg " are not. An SVG <name> may not have whitespace.

In particular, E09 does not allow a space as start character (NameStartChar), and space is not allowed as a subsequent character (NameChar).

The CSS grammar allows whitespace ({w}) immediately after the opening paren and immediately before the close paren. It does not allow whitespace in the url production. I see no reason to process spaces within a {string} production.

Only the first 2 green squares follow the standard. The SVG agents may try doing something sensible to extend the standard, but the result is anything but standard.

@Glrx The problem with standard is that no one cares about it. People want to see the same results as in the browser or better. That's why resvg usually tries to mimic browsers and not standard.
And in general, there are too many things in SVG that are not defined at all or poorly defined. My tests suite has 48 tests where the correct result is basically unknown.

UPD: looks like in the past year the results are changed pretty drastically. I've added a new test output to the linked issue.

@RazrFalcon

If XML or SVG required strong type checking, then attributes such as id=" lg" or id="0lg" would raise exceptions Applications were sort of expected to validate XML input against a DTD and refuse to process bad input. That was a nice theory, but Java would take 6 seconds to validate an XML file, and that was just too high a penalty. So few applications complain about their input. I like it when one of my browsers throws an SVG syntax error.

I have no problem with sensible implementations. An application does not really need to validate identifiers. Modern languages will use any string as a unique hash table key, so pushing XML names with embedded spaces or initial digits is a sensible approach. The app-writer need not test for a valid name. The input file should have guaranteed good names. The identifiers are supposed to be unique, so I will not fault an application for getting confused by non-unique identifiers. The app-writer need not test for an existing key when he adds a key to a table. The input was supposed to guarantee unique names. So extended behavior that falls out from simple coding that relies on good input is reasonable. The programmer was saving effort.

Conversely, it is not reasonable to add lots of code in the hope that it will fix some bad input. If an application's code reasonably parses the url() construct, then that should be enough. If some extensions fall out of that parsing, that's OK, but it should never be something that any user should rely upon.

The SVG specification has many problems. It has XML namespaces, but it reinvents name spaces with the aria-* and data-* attributes. XML distinguishes upper and lower case; HTML does not. Yet SVG wants to copy HTML rules to build camelCase names. SVG adds unnecessary junk that has nothing to do with rendering an image. Even within rendering, SVG has a poor understanding of specifying the graphics state. There's even a poor understanding of typesetting: LTR and RTL require different tspans. CSS also raises its head. Where there is legitimate ambiguity in SVG, then that ambiguity should be resolved in either the spec or a living spec.

The cases above are not about ambiguity. They are about error. Get the two green squares right; everything else does not matter.