Created attachment 125265 [details] Pattern on patter in inner SVG SVG Pattern doesn't consider the transformation of the nearest viewport on calculating the size of the temp imageBuffer when referenced by another pattern. The attached example is a reproduction of http://srufaculty.sru.edu/david.dailey/svg/recent/sliderzoom.svg Note: the current pixelation does just occur if we use a inner SVG element with a viewBox.
Created attachment 125267 [details] Pattern on patter in inner SVG Added wrong example.
The culprit is SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem. But the description is longer: We try to create pattern tiles in the screen coordinate space to avoid pixelation. Therefor we take the RenderObject of the element where we want to apply the pattern. After that we walk up the DOM Tree (render tree in reality) and consider all transformations on the road. That is done by applying all transformations (including the viewBox and transform of the pattern) to a intermediate transform. We use this transform to map the drawing rect of the tile and get the size that a tile would need on the screen. This works almost all the time, almost. The attached example is different, since the patterns and the referenced object are in different viewports: <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="500" height="500" > <defs> <pattern id="P2" patternUnits="userSpaceOnUse" width="100%" height="100%"> <rect width="100%" height="100%" fill="url(#P1)"/> </pattern> <pattern id="P1" patternUnits="userSpaceOnUse" width="20" height="20"> <circle id="S1" r="10" cx="10" cy="10" stroke="black" fill="pink" stroke-width="2" /> </pattern> </defs> <svg viewBox="0 0 100 100" preserveAspectRatio="none"> <rect fill="url(#P2)" width="100%" height="100%"/> </svg> </svg> The last rect in the example above is what we see on the screen. This rect gets filled with pattern P2. P2 wants to get the tile size of the pattern. Therefor we take the object (the rect), and apply all transforms on the way up to the root. That means, we create a new AffineTransform, apply the transform of the rect (still identity matrix). After that we walk up the DOM and reach the inner SVG element. We apply the viewBox (similar to a transform) and walk up the DOM. We reach the root element and apply the transform of the root element. For P2 we get the correct size of the tile. But the rect in pattern P2 uses a pattern P1 as well. The new pattern will take this rect to calculate the transform. The problem is, that this rect is not in the viewport of the target element. Therefor we don't apply the transform of the inner SVG on the way up of the DOM. This ends up in the pixelation. We still need to consider the rect in the pattern, it's transform as well as the transform of the pattern. Afterwards we need the transform of the rect element, the transform of the inner SVG and at the end the root transform.
(In reply to comment #2) > The culprit is SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem. But the description is longer: The currentContentTransformation() is used to support nested masks with different view ports, maybe it can be used here as well? I'm not sure I fully understood your analysis, without tracing through the code on my own, so I'm rather guessing here.
Created attachment 460784 [details] Safari 15.5 differs from other browsers I am able to reproduce pixelation in attached test case using Safari 15.5 on macOS 12.4 and Safari Technical Preview 148. Other browser does not have pixelation as bad as Safari, Chrome Canary is not as sharp as Firefox Nightly but it is still better than Safari. Please refer to attached screenshot for all browser behavior. Thanks!
<rdar://problem/101934285>