<feImage> doesn't work with local references when using primitiveUnits="objectBoundingBox"
https://bugs.webkit.org/show_bug.cgi?id=77205
Reviewed by Antti Koivisto.
Source/WebCore:
Consider following testcase:
<svg width="1000" height="500">
<defs>
<circle id="c" cx="50%" cy="50%" r="10%"/>
<filter id="f" filterUnits="userSpaceOnUse" x="0" y="0" width="100" height="100" primitiveUnits="objectBoundingBox">
<feImage xlink:href="#c"/>
</filter>
</defs>
<rect width="100" height="100" filter="url(#f)"/>
</svg>
The <svg> has a viewport of 1000x50. The <circle> in the <defs> element is resolved as <circle cx="500" cy="250" r="79"/>,
as the context for this element (looking at it isolated!) is the viewport of the <svg>. We then setup a 0x0 - 100x100 rect
in user space, which gets filtered, by a filter, also defined in user space (for simplicity), but with primitiveUnits="objectBoundingBox".
That means that the default subregion of the filter effect <feImage/> which has no inputs, is defined in the SVG 1.1 spec to be equal to
the filter region, which is 0x0-100x100 in user space. This <feImage/> is supposed to produce a 100x100 image, containing a circle in the
middle (aka. <circle cx="50" cy="50".../>), but it doesn't, as the <circle> it's trying to paint, is laid out at 500x250, and thus outside
the 100x100 sized image buffer.
So how to resolve this?
The RenderSVGShape thats owned by the <circle> generates its Path value by calling cx().value(lengthContext) and the SVGLengthContext here
resolves to the <svg>. That happens on _layout_. If we would want to change the SVGLengthContext in this case (what I originally planned!)
to carry a custom 100x100 viewport, we'd need to relayout. Unfortunately this is not an option, as this would mean that
SVGImageBufferTools::renderSubtreeToImageBuffer, would need to relayout its children first, but we produce the filter images when painting.
This is very dangerous and has just recently been fixed so that SVGImageBufferTools can ASSERT(!item->needsLayout()) when painting the
subtree to an image buffer.
The only sane solution I see, that does not require relayouts, is to make a map between the <circle> bounding box in user space (500x250
center point) to the filter primitive subregion space (here: 100x100 center point), and concat that transformation before painting the
subtree to the image buffer. Of course this approach only works if all values of the <circle> are relative. If someone uses
<circle id="c" cx="50%" cy="666"> the transformation that I'm looking for is undefined. We'd really need to create a new Path here, to
resolve only cx against the new viewport, and not cy.
Though in practice it turns out this is not a problem. All use cases of feImage + primitiveUnits="objectBoundingBox" link to elements
that are completely defined in percentual values, as this is really the only thing which makes sense - otherwise you can always switch
back to primtiveUnits="userSpaceOnUse". Anyhow, I'm going to fix all known wild-life test cases by my approach, and say we don't support
using mixed length units when referencing those elements from feImages with primitiveUnits="objectBoundingBox".
Adding lots of new testcases, trying all the different feImage modes.
Tests: svg/filters/feImage-filterUnits-objectBoundingBox-primitiveUnits-objectBoundingBox.svg
svg/filters/feImage-filterUnits-objectBoundingBox-primitiveUnits-userSpaceOnUse.svg
svg/filters/feImage-filterUnits-userSpaceOnUse-primitiveUnits-objectBoundingBox.svg
svg/filters/feImage-filterUnits-userSpaceOnUse-primitiveUnits-userSpaceOnUse.svg
svg/filters/feImage-position.svg
svg/filters/feImage-subregions-preseveAspectRatio-none-with-viewBox.svg
svg/filters/feImage-subregions-preseveAspectRatio-none.svg
svg/filters/feImage-subregions.svg
* rendering/svg/RenderSVGResourceFilterPrimitive.cpp:
(WebCore::RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion): Reverse logic, simplifying the code a bit. Remove FEImage special cases (absoluteSubregion).
* svg/SVGLengthContext.h: Make determineViewport() public, for use in FEImage.
* svg/graphics/filters/SVGFEImage.cpp:
(WebCore::FEImage::determineAbsolutePaintRect): Don't apply preserveAspectRatio transformation for local elements, it's not defined and breaks content.
(WebCore::FEImage::platformApplySoftware): Figure out the absolute subregion by utilizing filterPrimitiveSubregion() as FETurbulence does.
Map between filter primitive subregion and target object space for primitiveUnits="objectBoundingBox" support on SVG element references.
* svg/graphics/filters/SVGFEImage.h: Remove absoluteSubregion member & setter, it's no longer needed.
LayoutTests:
Add new test cases covering all combinations of filterUnits/primitiveUnits and <feImage>.
* platform/chromium/test_expectations.txt:
* platform/mac/svg/filters/feImage-filterUnits-objectBoundingBox-primitiveUnits-objectBoundingBox-expected.png: Added.
* platform/mac/svg/filters/feImage-filterUnits-objectBoundingBox-primitiveUnits-objectBoundingBox-expected.txt: Added.
* platform/mac/svg/filters/feImage-filterUnits-objectBoundingBox-primitiveUnits-userSpaceOnUse-expected.png: Added.
* platform/mac/svg/filters/feImage-filterUnits-objectBoundingBox-primitiveUnits-userSpaceOnUse-expected.txt: Added.
* platform/mac/svg/filters/feImage-filterUnits-userSpaceOnUse-primitiveUnits-objectBoundingBox-expected.png: Added.
* platform/mac/svg/filters/feImage-filterUnits-userSpaceOnUse-primitiveUnits-objectBoundingBox-expected.txt: Added.
* platform/mac/svg/filters/feImage-filterUnits-userSpaceOnUse-primitiveUnits-userSpaceOnUse-expected.png: Added.
* platform/mac/svg/filters/feImage-filterUnits-userSpaceOnUse-primitiveUnits-userSpaceOnUse-expected.txt: Added.
* platform/mac/svg/filters/feImage-position-expected.png: Added.
* platform/mac/svg/filters/feImage-position-expected.txt: Added.
* platform/mac/svg/filters/feImage-subregions-expected.png: Added.
* platform/mac/svg/filters/feImage-subregions-expected.txt: Added.
* platform/mac/svg/filters/feImage-subregions-preseveAspectRatio-none-expected.png: Added.
* platform/mac/svg/filters/feImage-subregions-preseveAspectRatio-none-expected.txt: Added.
* platform/mac/svg/filters/feImage-subregions-preseveAspectRatio-none-with-viewBox-expected.png: Added.
* platform/mac/svg/filters/feImage-subregions-preseveAspectRatio-none-with-viewBox-expected.txt: Added.
* svg/filters/feImage-filterUnits-objectBoundingBox-primitiveUnits-objectBoundingBox.svg: Added.
* svg/filters/feImage-filterUnits-objectBoundingBox-primitiveUnits-userSpaceOnUse.svg: Added.
* svg/filters/feImage-filterUnits-userSpaceOnUse-primitiveUnits-objectBoundingBox.svg: Added.
* svg/filters/feImage-filterUnits-userSpaceOnUse-primitiveUnits-userSpaceOnUse.svg: Added.
* svg/filters/feImage-position.svg: Added.
* svg/filters/feImage-subregions-preseveAspectRatio-none-with-viewBox.svg: Added.
* svg/filters/feImage-subregions-preseveAspectRatio-none.svg: Added.
* svg/filters/feImage-subregions.svg: Added.
* svg/filters/resources/green.png: Added.
Canonical link: https://commits.webkit.org/94091@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@106113 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2012-01-27 13:54:21 +00:00
|
|
|
<svg viewBox="0 0 800 600" width="400" height="500" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
|
|
<defs>
|
|
|
|
<title>Green rectangles should be within the red frames</title>
|
|
|
|
<rect id="rect" width="100" height="100" fill="green"/>
|
|
|
|
|
|
|
|
<filter id="filter1" >
|
|
|
|
<feImage preserveAspectRatio="none" x="0%" y="0%" width="100%" height="100%" xlink:href="#rect"/>
|
|
|
|
</filter>
|
|
|
|
|
|
|
|
<filter id="filter2" >
|
|
|
|
<feImage preserveAspectRatio="none" xlink:href="#rect"/>
|
|
|
|
</filter>
|
|
|
|
|
|
|
|
<filter id="filter3" >
|
|
|
|
<feImage preserveAspectRatio="none" x="0%" y="0%" width="100%" height="100%" xlink:href="resources/green.png"/>
|
|
|
|
</filter>
|
|
|
|
|
|
|
|
<filter id="filter4" >
|
|
|
|
<feImage preserveAspectRatio="none" xlink:href="resources/green.png"/>
|
|
|
|
</filter>
|
|
|
|
</defs>
|
|
|
|
|
|
|
|
<g transform="translate(50, 10)">
|
|
|
|
<rect width="400" height="200" fill="green" filter="url(#filter1)"/>
|
|
|
|
<g transform="translate(0, 250)">
|
|
|
|
<rect width="400" height="200" fill="green" filter="url(#filter2)"/>
|
|
|
|
</g>
|
|
|
|
</g>
|
|
|
|
|
|
|
|
<g transform="translate(250, 10)">
|
|
|
|
<rect width="400" height="200" fill="green" filter="url(#filter3)"/>
|
|
|
|
<g transform="translate(0, 250)">
|
|
|
|
<rect width="400" height="200" fill="green" filter="url(#filter4)"/>
|
|
|
|
</g>
|
|
|
|
</g>
|
|
|
|
|
|
|
|
<rect fill="none" stroke="red" x="50" y="10" width="100" height="100"/>
|
|
|
|
<rect fill="none" stroke="red" x="10" y="240" width="100" height="100"/>
|
|
|
|
<rect fill="none" stroke="red" x="250" y="10" width="440" height="220"/>
|
|
|
|
<rect fill="none" stroke="red" x="210" y="240" width="480" height="240"/>
|
|
|
|
|
|
|
|
</svg>
|
|
|
|
|