svg-native-viewer icon indicating copy to clipboard operation
svg-native-viewer copied to clipboard

Fill or stroke attributes on a `use` element

Open moazin opened this issue 3 years ago • 6 comments

While I'm not exactly sure what the standard says on whether fill or stroke attributes on the use element are taken into account or not, according to this, they are taken into account if the "referred" element didn't have any such attribute applied.

SNV doesn't seem to take it into account at all.

Look at the following document as an example. The first one is the rendering by SNV and the second one is by Librsvg.

snv-four librsvg-four

Please, feel free to close this issue if this behavior isn't required by the standard.

moazin avatar Apr 26 '21 21:04 moazin

@moazin It is complicated and the behaviour may differ even between web browsers.

First, the fill property is an inherited property: https://www.w3.org/TR/SVG/painting.html#FillProperties If the value is not set, it inherits the value from the ancestor.

2nd, the use element in SVG 1.1 behaves like a copy operation. The behaviour is as if the <use> element gets replaced by a group and the referenced content copied into the use element.

With SVG2, the definition of <use> changed and now acts as a shadow root of an non-isolated shadow tree. This has been implemented by Firefox but by no other browser.

SVG Native is based on SVG2. So svg-native-viewer should behave similar to Firefox.

I believe for the most simple case, the behaviour should not differ:

<rect width="100" height="100" id="rect"/>
<use fill="green" xlink:href="#rect" x="100"/>

should probably show a black rect with a green rect right next to it. (There might be a difference between presentation attribute and property definition that I would need to check again.)

dirkschulze avatar Apr 29 '21 12:04 dirkschulze

Can you attach the source which produced the above images?

litherum avatar May 13 '21 22:05 litherum

@litherum Oh, I thought I had attached the SVG document as well, but seems like I didn't.

I guess this is the one:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink= "http://www.w3.org/1999/xlink" xmlns:svg="http://www.w3.org/2000/svg" viewBox=" 0 0 1000 1000">
  <rect x="500" y="500" width="100" height="100" id="myCircle"/>
  <use xlink:href="#myCircle" x="200" fill="red"/>
  <use xlink:href="#myCircle" y="200" fill="blue"/>
  <use xlink:href="#myCircle" x="-200" fill="green"/>
  <use xlink:href="#myCircle" y="-200" fill="yellow"/>
</svg>

moazin avatar May 14 '21 19:05 moazin

So I analyzed the problem a little bit and here are my thoughts.

SNV iterates through the XML tree first, parsing attributes, maintaining stacks and ultimately populates an object tree. This mechanism is designed in such a way that each draw-able element of this object tree is more or less independent and self-sufficient. In other words, all attributes such as transforms, stroking information, gradient information, etc is embedded within that element. This is not true for the Reference element though, which refers to another element that's to be rendered. This is simply done by calling TraverseTree on the referred element. Any attributes such as fillStyle or strokeStyle on the Reference object are simply ignored. graphicStyle is taken into account though. Given this situation, I'm not quite sure how to go about this.

moazin avatar May 24 '21 10:05 moazin

I would also like to point out that it's very important for this to be resolved. Almost every glyph of Trajan and a lot of glyphs of NotoColorEmoji have use elements with styling attributes like fill.

moazin avatar May 25 '21 11:05 moazin

Any updates about this issue ?

I found even the sample from Microsoft's SVG open type can not render on the svg-native-viewer (I tested using CoreGraphics port)

https://learn.microsoft.com/en-us/typography/opentype/spec/svg#example-2-glyph-specified-directly-in-expected-position

<svg id="glyph7" version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 1000 1000 1000">
  <defs>
    <linearGradient id="grad" x1="0%" y1="0%" x2="0%" y2="100%">
      <stop offset="0%" stop-color="darkblue" stop-opacity="1" />
      <stop offset="100%" stop-color="#00aab3" stop-opacity="1" />
    </linearGradient>
  </defs>
  <rect x="100" y="570" width="200" height="430" fill="url(#grad)" />
  <rect x="100" y="365" width="200" height="135" fill="darkblue" />
</svg>

I think this x1="0%" y1="0%" x2="0%" y2="100%" should be treated as actually x1=100 y1=570 x2=300 y2=1000, but not just x1=0 y1=0 x2=0 y2=1000

dreampiggy avatar Oct 13 '22 08:10 dreampiggy