[css-images][css-masking][paint] Ambiguities in handling url() #383

Open
tabatkins opened this Issue Aug 4, 2016 · 7 comments

Projects

None yet

3 participants

@tabatkins
World Wide Web Consortium member
tabatkins commented Aug 4, 2016 edited

Back in 2012, roc raised this issue about an ambiguity in handling url()s that might refer to an image or an SVG element reference: https://lists.w3.org/Archives/Public/www-svg/2012Oct/0019.html In particular, giving a url like "mask-image: url(foo.svg#bar)", do we load that as an SVG image with a fragment of #bar, or do we load it as an SVG document and retrieve the id=bar element (which might be a <mask> element)? This also infects all CSS-<image>-taking properties, if we let CSS refer to SVG paint servers.

There was a lot of discussion and seemingly consensus, but nothing ever got formally decided, and several of the affected specs (Images, Masking, etc) weren't edited to take this into account. Let's fix that! The conclusion seemed to be:

  1. url()s without a fragment are always interpreted as images.
  2. url()s with a fragment vary slightly based on property: CSS-defined properties default to interpreting it as an image, while SVG-defined properties default to interpreting it as an element reference. You can force the image interpretation by instead loading it with image(), and the element interpretation by loading it as element().

This means that background-image can only refer to a paint server by using element("foo.svg#bar"), while mask-image can only use an SVG Stack by using image("foo.svg#bar").

It also means that in our new attempt to define fill and stroke for CSS, it'll default fragment urls to being element references, as that's their current behavior in SVG.

Let's please put this 4-year-old issue to rest - I can do the edits to the necessary specs.

@tabatkins tabatkins self-assigned this Aug 4, 2016
@AmeliaBR
AmeliaBR commented Aug 10, 2016 edited

FYI:

I wrote up detailed URL-handling rules for SVG 2 as part of the overhaul of use-element handling. I tried to be consistent with CSS/FX specs (particularly Masking) to the extent that they had any guidance, but if you're adding new guidance you may want to review that section and make sure we're still consistent.

Key parts that are relevant to CSS:

  • If a property can only accept an image file reference, treat the URL as an image file. Any target fragment is used when rendering that image, but doesn't define a relevant document fragment.

  • If a property can accept either an image file or an element reference, and the referenced document can be parsed as a DOM, identify the targetted element to determine if it is a valid reference. If it is not, re-interpret the URL as an image file reference.

  • If a property can accept an element reference, and the URL does not have a target fragment, treat it as a reference to the root element when determining if it is a valid reference. This was based on a long-standing SVG feature request for <use> element references (to be able to use a separate SVG without editing it to add an id on the root element). If it is going to be a problem with CSS image properties, we may want to restrict that behavior.

  • External resources specified in style properties are fetched with CORS anonymous mode, so there shouldn't be security restrictions on whether the file is parsed as an SVG asset document or an SVG image.

I was only focusing on url() references, not on image() vs element(), and I was of course only focusing on SVG-defined properties.

I like the idea of using functions to clarify which way you want to interpret the reference. I'm slightly concerned about confusion with the other use of element(), to copy the rendered image data from an element in the current DOM. That's conceptually quite different from referencing an element that describes a graphical effect to apply.

I'm not too keen on having different rules for CSS-defined properties vs SVG-defined properties. That just seems like grounds for confusion. I realize there is a theoretical backwards-compatibility issue when allowing SVG paint servers as a CSS image type (a URL that would formerly be interpretted as an SVG image with :target styles now being interpretted as a paint server reference), but I think it is exceedingly rare in practice that :target styles are tied to a paint server element. The bigger concern would be whether there are substantial performance impacts from parsing the document to identify the element before deciding to treat it as an image: i.e., can implementations switch from "effects" mode to "image" mode without repeating the basic parsing & DOM construction?

@tabatkins
World Wide Web Consortium member

Hmm, so yeah, that's rather inconsistent with our earlier plans for CSS. :/ This is gonna need some discussion.

@astearns astearns removed the Agenda+ label Aug 24, 2016
@astearns

(removing label because this is already on the TPAC agenda)

@AmeliaBR

This is a big, long-term-strategy issue, so I appreciate that you're giving it extra thought. But FYI, we're aiming to get SVG 2 published as CR before TPAC, so requests to change anything normative will be a bit of a pain after that.

(Oh, and I won't be at TPAC myself, but do ping me if you have any questions about the SVG side.)

@tabatkins
World Wide Web Consortium member

After TPAC discussion:

  • I'm going to figure out precisely what properties are web-compat required to deal with this ambiguous syntax (where a url() can potentially be an image or a resource). I think it's just 'mask' and the 'marker-*' properties. (At least, that's the Chrome ones.)
  • For those required-ambiguous properties, we seem to want to go with the "fragment means resource, no-fragment means image" behavior; in particular, implementations do not want to load things twice.
  • We'll bind ourselves to not introduce ambiguity in the future; properties will be defined to have url() always be an image or ref, and you will have to switch behavior with image() or element(), as appropriate.

Extra detail: it looks like Chrome and Firefox do the split based on "local fragment" vs "otherwise". This means that external links, frag or no, are treated as image. Need more detail. /cc @birtles

@AmeliaBR

Re which properties currently have image-vs-element ambiguities:

Marker does not accept a plain image type, so there's no ambiguity there. Ambiguous URL properties I've noted that are currently supported in at least some browsers are mask and cursor; although we've deprecated the SVG <cursor> element, it's still supposed to be supported by user agents. The new SVG text layout also makes shape-inside and shape-subtract ambiguous.

In other words, mask should be the main focus for web compatibility issues. If no browsers currently support external file mask element references, that could be an argument for making special rules for same-document fragments. However, I think the more powerful argument is that mask-image is a new & still experimental property, that is not supported un-prefixed in any stable browsers, while mask with element references is well supported in SVG.

@AmeliaBR

By the way, one other detail I clarified in the SVG linking spec is that element references can be in any document that can be parsed as a DOM. I.e., you can link to an element in an HTML doc, not only an SVG doc. This is of course already supported in all the browsers for same-document references, but it was not defined for external references.

That shouldn't add too much confusion on this issue, but it means that in some cases there won't be a valid image interpretation of a file if the element reference interpretation fails.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment