Changeset 226373 in webkit


Ignore:
Timestamp:
Jan 3, 2018 1:56:00 PM (6 years ago)
Author:
Simon Fraser
Message:

feLighting is broken with primitiveUnits="objectBoundingBox"
https://bugs.webkit.org/show_bug.cgi?id=181197

Reviewed by Tim Horton.
Source/WebCore:

With <filter primitiveUnits="objectBoundingBox"> we need to convert the coordinates
of fePointLights and feSpotLights into user space coordinates. Following
https://www.w3.org/TR/SVG/filters.html#FilterElementPrimitiveUnitsAttribute
this is done by treating them as fractions of the bounding box on the referencing
element, with treatment for z following https://www.w3.org/TR/SVG/coords.html#Units_viewport_percentage

To do this, store the bounds of the referencing elemenet on SVGFilterBuilder as
targetBoundingBox, and store the primitiveUnits type. Then do the conversion of lighting
coordinates in SVGFESpecularLightingElement::build() and SVGFEDiffuseLightingElement::build().

Remove SVGFELightElement::findLightSource(), since we need to be able to pass the SVGFilterBuilder
to the lightSource() function so hoist the code up.

Tests: svg/filters/feDiffuseLighting-fePointLight-primitiveUnits-objectBoundingBox-expected.svg

svg/filters/feDiffuseLighting-fePointLight-primitiveUnits-objectBoundingBox.svg
svg/filters/feDiffuseLighting-feSpotLight-primitiveUnits-objectBoundingBox-expected.svg
svg/filters/feDiffuseLighting-feSpotLight-primitiveUnits-objectBoundingBox.svg
svg/filters/feSpecularLighting-fePointLight-primitiveUnits-objectBoundingBox-expected.svg
svg/filters/feSpecularLighting-fePointLight-primitiveUnits-objectBoundingBox.svg

  • rendering/svg/RenderSVGResourceFilter.cpp:

(WebCore::RenderSVGResourceFilter::buildPrimitives const):

  • svg/SVGFEDiffuseLightingElement.cpp:

(WebCore::SVGFEDiffuseLightingElement::build):

  • svg/SVGFEDistantLightElement.cpp:

(WebCore::SVGFEDistantLightElement::lightSource const):

  • svg/SVGFEDistantLightElement.h:
  • svg/SVGFELightElement.cpp:

(WebCore::SVGFELightElement::findLightSource): Deleted.

  • svg/SVGFELightElement.h:
  • svg/SVGFEPointLightElement.cpp:

(WebCore::SVGFEPointLightElement::lightSource const):

  • svg/SVGFEPointLightElement.h:
  • svg/SVGFESpecularLightingElement.cpp:

(WebCore::SVGFESpecularLightingElement::build):

  • svg/SVGFESpotLightElement.cpp:

(WebCore::SVGFESpotLightElement::lightSource const):

  • svg/SVGFESpotLightElement.h:
  • svg/graphics/filters/SVGFilterBuilder.h:

(WebCore::SVGFilterBuilder::setTargetBoundingBox):
(WebCore::SVGFilterBuilder::targetBoundingBox const):
(WebCore::SVGFilterBuilder::primitiveUnits const):
(WebCore::SVGFilterBuilder::setPrimitiveUnits):

LayoutTests:

Ref tests with primitiveUnits=objectBoundingBox for feSpotLight and fePointLight.

  • svg/filters/feDiffuseLighting-fePointLight-primitiveUnits-objectBoundingBox-expected.svg: Added.
  • svg/filters/feDiffuseLighting-fePointLight-primitiveUnits-objectBoundingBox.svg: Added.
  • svg/filters/feDiffuseLighting-feSpotLight-primitiveUnits-objectBoundingBox-expected.svg: Added.
  • svg/filters/feDiffuseLighting-feSpotLight-primitiveUnits-objectBoundingBox.svg: Added.
  • svg/filters/feSpecularLighting-fePointLight-primitiveUnits-objectBoundingBox-expected.svg: Added.
  • svg/filters/feSpecularLighting-fePointLight-primitiveUnits-objectBoundingBox.svg: Added.
Location:
trunk
Files:
6 added
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r226372 r226373  
     12018-01-03  Simon Fraser  <simon.fraser@apple.com>
     2
     3        feLighting is broken with primitiveUnits="objectBoundingBox"
     4        https://bugs.webkit.org/show_bug.cgi?id=181197
     5
     6        Reviewed by Tim Horton.
     7       
     8        Ref tests with primitiveUnits=objectBoundingBox for feSpotLight and fePointLight.
     9
     10        * svg/filters/feDiffuseLighting-fePointLight-primitiveUnits-objectBoundingBox-expected.svg: Added.
     11        * svg/filters/feDiffuseLighting-fePointLight-primitiveUnits-objectBoundingBox.svg: Added.
     12        * svg/filters/feDiffuseLighting-feSpotLight-primitiveUnits-objectBoundingBox-expected.svg: Added.
     13        * svg/filters/feDiffuseLighting-feSpotLight-primitiveUnits-objectBoundingBox.svg: Added.
     14        * svg/filters/feSpecularLighting-fePointLight-primitiveUnits-objectBoundingBox-expected.svg: Added.
     15        * svg/filters/feSpecularLighting-fePointLight-primitiveUnits-objectBoundingBox.svg: Added.
     16
    1172018-01-03  Antti Koivisto  <antti@apple.com>
    218
  • trunk/Source/WebCore/ChangeLog

    r226372 r226373  
     12018-01-03  Simon Fraser  <simon.fraser@apple.com>
     2
     3        feLighting is broken with primitiveUnits="objectBoundingBox"
     4        https://bugs.webkit.org/show_bug.cgi?id=181197
     5
     6        Reviewed by Tim Horton.
     7
     8        With <filter primitiveUnits="objectBoundingBox"> we need to convert the coordinates
     9        of fePointLights and feSpotLights into user space coordinates. Following
     10        https://www.w3.org/TR/SVG/filters.html#FilterElementPrimitiveUnitsAttribute
     11        this is done by treating them as fractions of the bounding box on the referencing
     12        element, with treatment for z following https://www.w3.org/TR/SVG/coords.html#Units_viewport_percentage
     13       
     14        To do this, store the bounds of the referencing elemenet on SVGFilterBuilder as
     15        targetBoundingBox, and store the primitiveUnits type. Then do the conversion of lighting
     16        coordinates in SVGFESpecularLightingElement::build() and SVGFEDiffuseLightingElement::build().
     17
     18        Remove SVGFELightElement::findLightSource(), since we need to be able to pass the SVGFilterBuilder
     19        to the lightSource() function so hoist the code up.
     20
     21        Tests: svg/filters/feDiffuseLighting-fePointLight-primitiveUnits-objectBoundingBox-expected.svg
     22               svg/filters/feDiffuseLighting-fePointLight-primitiveUnits-objectBoundingBox.svg
     23               svg/filters/feDiffuseLighting-feSpotLight-primitiveUnits-objectBoundingBox-expected.svg
     24               svg/filters/feDiffuseLighting-feSpotLight-primitiveUnits-objectBoundingBox.svg
     25               svg/filters/feSpecularLighting-fePointLight-primitiveUnits-objectBoundingBox-expected.svg
     26               svg/filters/feSpecularLighting-fePointLight-primitiveUnits-objectBoundingBox.svg
     27
     28        * rendering/svg/RenderSVGResourceFilter.cpp:
     29        (WebCore::RenderSVGResourceFilter::buildPrimitives const):
     30        * svg/SVGFEDiffuseLightingElement.cpp:
     31        (WebCore::SVGFEDiffuseLightingElement::build):
     32        * svg/SVGFEDistantLightElement.cpp:
     33        (WebCore::SVGFEDistantLightElement::lightSource const):
     34        * svg/SVGFEDistantLightElement.h:
     35        * svg/SVGFELightElement.cpp:
     36        (WebCore::SVGFELightElement::findLightSource): Deleted.
     37        * svg/SVGFELightElement.h:
     38        * svg/SVGFEPointLightElement.cpp:
     39        (WebCore::SVGFEPointLightElement::lightSource const):
     40        * svg/SVGFEPointLightElement.h:
     41        * svg/SVGFESpecularLightingElement.cpp:
     42        (WebCore::SVGFESpecularLightingElement::build):
     43        * svg/SVGFESpotLightElement.cpp:
     44        (WebCore::SVGFESpotLightElement::lightSource const):
     45        * svg/SVGFESpotLightElement.h:
     46        * svg/graphics/filters/SVGFilterBuilder.h:
     47        (WebCore::SVGFilterBuilder::setTargetBoundingBox):
     48        (WebCore::SVGFilterBuilder::targetBoundingBox const):
     49        (WebCore::SVGFilterBuilder::primitiveUnits const):
     50        (WebCore::SVGFilterBuilder::setPrimitiveUnits):
     51
    1522018-01-03  Antti Koivisto  <antti@apple.com>
    253
  • trunk/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp

    r225797 r226373  
    9090    // Add effects to the builder
    9191    auto builder = std::make_unique<SVGFilterBuilder>(SourceGraphic::create(filter));
     92    builder->setPrimitiveUnits(filterElement().primitiveUnits());
     93    builder->setTargetBoundingBox(targetBoundingBox);
     94   
    9295    for (auto& element : childrenOfType<SVGFilterPrimitiveStandardAttributes>(filterElement())) {
    9396        RefPtr<FilterEffect> effect = element.build(builder.get(), filter);
  • trunk/Source/WebCore/svg/SVGFEDiffuseLightingElement.cpp

    r224615 r226373  
    178178        return nullptr;
    179179
    180     auto lightSource = SVGFELightElement::findLightSource(this);
    181     if (!lightSource)
     180    auto lightElement = makeRefPtr(SVGFELightElement::findLightElement(this));
     181    if (!lightElement)
    182182        return nullptr;
     183   
     184    auto lightSource = lightElement->lightSource(*filterBuilder);
    183185
    184186    RenderObject* renderer = this->renderer();
     
    188190    const Color& color = renderer->style().svgStyle().lightingColor();
    189191
    190     RefPtr<FilterEffect> effect = FEDiffuseLighting::create(filter, color, surfaceScale(), diffuseConstant(), kernelUnitLengthX(), kernelUnitLengthY(), lightSource.releaseNonNull());
     192    RefPtr<FilterEffect> effect = FEDiffuseLighting::create(filter, color, surfaceScale(), diffuseConstant(), kernelUnitLengthX(), kernelUnitLengthY(), WTFMove(lightSource));
    191193    effect->inputEffects().append(input1);
    192194    return effect;
  • trunk/Source/WebCore/svg/SVGFEDistantLightElement.cpp

    r183611 r226373  
    3737}
    3838
    39 Ref<LightSource> SVGFEDistantLightElement::lightSource() const
     39Ref<LightSource> SVGFEDistantLightElement::lightSource(SVGFilterBuilder&) const
    4040{
    4141    return DistantLightSource::create(azimuth(), elevation());
  • trunk/Source/WebCore/svg/SVGFEDistantLightElement.h

    r208668 r226373  
    3131    SVGFEDistantLightElement(const QualifiedName&, Document&);
    3232
    33     Ref<LightSource> lightSource() const override;
     33    Ref<LightSource> lightSource(SVGFilterBuilder&) const override;
    3434};
    3535
  • trunk/Source/WebCore/svg/SVGFELightElement.cpp

    r224615 r226373  
    7676    }
    7777    return nullptr;
    78 }
    79 
    80 RefPtr<LightSource> SVGFELightElement::findLightSource(const SVGElement* svgElement)
    81 {
    82     auto lightNode = makeRefPtr(findLightElement(svgElement));
    83     if (!lightNode)
    84         return 0;
    85     return lightNode->lightSource();
    8678}
    8779
  • trunk/Source/WebCore/svg/SVGFELightElement.h

    r208668 r226373  
    2828namespace WebCore {
    2929
     30class SVGFilterBuilder;
     31
    3032class SVGFELightElement : public SVGElement {
    3133public:
    32     virtual Ref<LightSource> lightSource() const = 0;
     34    virtual Ref<LightSource> lightSource(SVGFilterBuilder&) const = 0;
    3335    static SVGFELightElement* findLightElement(const SVGElement*);
    34     static RefPtr<LightSource> findLightSource(const SVGElement*);
    3536
    3637protected:
  • trunk/Source/WebCore/svg/SVGFEPointLightElement.cpp

    r183611 r226373  
    2020#include "config.h"
    2121#include "SVGFEPointLightElement.h"
     22
     23#include "GeometryUtilities.h"
     24#include "PointLightSource.h"
     25#include "SVGFilterBuilder.h"
    2226#include "SVGNames.h"
    23 
    24 #include "PointLightSource.h"
     27#include <wtf/MathExtras.h>
    2528
    2629namespace WebCore {
     
    3740}
    3841
    39 Ref<LightSource> SVGFEPointLightElement::lightSource() const
     42Ref<LightSource> SVGFEPointLightElement::lightSource(SVGFilterBuilder& builder) const
    4043{
    41     return PointLightSource::create(FloatPoint3D(x(), y(), z()));
     44    FloatPoint3D position;
     45    if (builder.primitiveUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
     46        FloatRect referenceBox = builder.targetBoundingBox();
     47       
     48        position.setX(referenceBox.x() + x() * referenceBox.width());
     49        position.setY(referenceBox.y() + y() * referenceBox.height());
     50
     51        // https://www.w3.org/TR/SVG/filters.html#fePointLightZAttribute and https://www.w3.org/TR/SVG/coords.html#Units_viewport_percentage
     52        position.setZ(z() * euclidianDistance(referenceBox.minXMinYCorner(), referenceBox.maxXMaxYCorner()) / sqrtOfTwoFloat);
     53    } else
     54        position = FloatPoint3D(x(), y(), z());
     55   
     56    return PointLightSource::create(position);
    4257}
    4358
  • trunk/Source/WebCore/svg/SVGFEPointLightElement.h

    r208668 r226373  
    3131    SVGFEPointLightElement(const QualifiedName&, Document&);
    3232
    33     Ref<LightSource> lightSource() const override;
     33    Ref<LightSource> lightSource(SVGFilterBuilder&) const override;
    3434};
    3535
  • trunk/Source/WebCore/svg/SVGFESpecularLightingElement.cpp

    r224615 r226373  
    189189        return nullptr;
    190190
    191     auto lightSource = SVGFELightElement::findLightSource(this);
    192     if (!lightSource)
     191    auto lightElement = makeRefPtr(SVGFELightElement::findLightElement(this));
     192    if (!lightElement)
    193193        return nullptr;
     194   
     195    auto lightSource = lightElement->lightSource(*filterBuilder);
    194196
    195197    RenderObject* renderer = this->renderer();
     
    199201    const Color& color = renderer->style().svgStyle().lightingColor();
    200202
    201     RefPtr<FilterEffect> effect = FESpecularLighting::create(filter, color, surfaceScale(), specularConstant(), specularExponent(), kernelUnitLengthX(), kernelUnitLengthY(), lightSource.releaseNonNull());
     203    RefPtr<FilterEffect> effect = FESpecularLighting::create(filter, color, surfaceScale(), specularConstant(), specularExponent(), kernelUnitLengthX(), kernelUnitLengthY(), WTFMove(lightSource));
    202204    effect->inputEffects().append(input1);
    203205    return effect;
  • trunk/Source/WebCore/svg/SVGFESpotLightElement.cpp

    r183611 r226373  
    2121#include "SVGFESpotLightElement.h"
    2222
     23#include "GeometryUtilities.h"
     24#include "SVGFilterBuilder.h"
    2325#include "SVGNames.h"
    2426#include "SpotLightSource.h"
     27#include <wtf/MathExtras.h>
    2528
    2629namespace WebCore {
     
    3740}
    3841
    39 Ref<LightSource> SVGFESpotLightElement::lightSource() const
     42Ref<LightSource> SVGFESpotLightElement::lightSource(SVGFilterBuilder& builder) const
    4043{
    41     FloatPoint3D pos(x(), y(), z());
    42     FloatPoint3D direction(pointsAtX(), pointsAtY(), pointsAtZ());
     44    FloatPoint3D position;
     45    FloatPoint3D pointsAt;
    4346
    44     return SpotLightSource::create(pos, direction, specularExponent(), limitingConeAngle());
     47    if (builder.primitiveUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
     48        FloatRect referenceBox = builder.targetBoundingBox();
     49       
     50        position.setX(referenceBox.x() + x() * referenceBox.width());
     51        position.setY(referenceBox.y() + y() * referenceBox.height());
     52        // https://www.w3.org/TR/SVG/filters.html#fePointLightZAttribute and https://www.w3.org/TR/SVG/coords.html#Units_viewport_percentage
     53        position.setZ(z() * euclidianDistance(referenceBox.minXMinYCorner(), referenceBox.maxXMaxYCorner()) / sqrtOfTwoFloat);
     54
     55        pointsAt.setX(referenceBox.x() + pointsAtX() * referenceBox.width());
     56        pointsAt.setY(referenceBox.y() + pointsAtY() * referenceBox.height());
     57        // https://www.w3.org/TR/SVG/filters.html#fePointLightZAttribute and https://www.w3.org/TR/SVG/coords.html#Units_viewport_percentage
     58        pointsAt.setZ(pointsAtZ() * euclidianDistance(referenceBox.minXMinYCorner(), referenceBox.maxXMaxYCorner()) / sqrtOfTwoFloat);
     59    } else {
     60        position = FloatPoint3D(x(), y(), z());
     61        pointsAt = FloatPoint3D(pointsAtX(), pointsAtY(), pointsAtZ());
     62    }
     63
     64    return SpotLightSource::create(position, pointsAt, specularExponent(), limitingConeAngle());
    4565}
    4666
  • trunk/Source/WebCore/svg/SVGFESpotLightElement.h

    r208668 r226373  
    3131    SVGFESpotLightElement(const QualifiedName&, Document&);
    3232
    33     Ref<LightSource> lightSource() const override;
     33    Ref<LightSource> lightSource(SVGFilterBuilder&) const override;
    3434};
    3535
  • trunk/Source/WebCore/svg/graphics/filters/SVGFilterBuilder.h

    r224615 r226373  
    2222
    2323#include "FilterEffect.h"
     24#include "SVGUnitTypes.h"
    2425#include <wtf/HashMap.h>
    2526#include <wtf/HashSet.h>
     
    3031
    3132class RenderObject;
     33class SVGFilterElement;
    3234
    3335class SVGFilterBuilder {
     
    3638
    3739    SVGFilterBuilder(RefPtr<FilterEffect> sourceGraphic);
     40
     41    void setTargetBoundingBox(const FloatRect& r) { m_targetBoundingBox = r; }
     42    FloatRect targetBoundingBox() const { return m_targetBoundingBox; }
     43   
     44    SVGUnitTypes::SVGUnitType primitiveUnits() const { return m_primitiveUnits; }
     45    void setPrimitiveUnits(SVGUnitTypes::SVGUnitType units) { m_primitiveUnits = units; }
    3846
    3947    void add(const AtomicString& id, RefPtr<FilterEffect>);
     
    7280
    7381    RefPtr<FilterEffect> m_lastEffect;
     82    FloatRect m_targetBoundingBox;
     83    SVGUnitTypes::SVGUnitType m_primitiveUnits { SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE };
    7484};
    7585   
Note: See TracChangeset for help on using the changeset viewer.