Pixel difference in FEMorphology effect
[WebKit-https.git] / Source / WebCore / svg / SVGFEMorphologyElement.cpp
1 /*
2  * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #include "config.h"
21
22 #if ENABLE(SVG) && ENABLE(FILTERS)
23 #include "SVGFEMorphologyElement.h"
24
25 #include "Attribute.h"
26 #include "FilterEffect.h"
27 #include "SVGElementInstance.h"
28 #include "SVGFilterBuilder.h"
29 #include "SVGNames.h"
30 #include "SVGParserUtilities.h"
31
32 namespace WebCore {
33
34 // Animated property definitions
35 DEFINE_ANIMATED_STRING(SVGFEMorphologyElement, SVGNames::inAttr, In1, in1)
36 DEFINE_ANIMATED_ENUMERATION(SVGFEMorphologyElement, SVGNames::operatorAttr, _operator, _operator, MorphologyOperatorType)
37 DEFINE_ANIMATED_NUMBER_MULTIPLE_WRAPPERS(SVGFEMorphologyElement, SVGNames::radiusAttr, radiusXIdentifier(), RadiusX, radiusX)
38 DEFINE_ANIMATED_NUMBER_MULTIPLE_WRAPPERS(SVGFEMorphologyElement, SVGNames::radiusAttr, radiusYIdentifier(), RadiusY, radiusY)
39
40 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGFEMorphologyElement)
41     REGISTER_LOCAL_ANIMATED_PROPERTY(in1)
42     REGISTER_LOCAL_ANIMATED_PROPERTY(_operator)
43     REGISTER_LOCAL_ANIMATED_PROPERTY(radiusX)
44     REGISTER_LOCAL_ANIMATED_PROPERTY(radiusY)
45     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGFilterPrimitiveStandardAttributes)
46 END_REGISTER_ANIMATED_PROPERTIES
47
48 inline SVGFEMorphologyElement::SVGFEMorphologyElement(const QualifiedName& tagName, Document* document)
49     : SVGFilterPrimitiveStandardAttributes(tagName, document)
50     , m__operator(FEMORPHOLOGY_OPERATOR_ERODE)
51 {
52     ASSERT(hasTagName(SVGNames::feMorphologyTag));
53     registerAnimatedPropertiesForSVGFEMorphologyElement();
54 }
55
56 PassRefPtr<SVGFEMorphologyElement> SVGFEMorphologyElement::create(const QualifiedName& tagName, Document* document)
57 {
58     return adoptRef(new SVGFEMorphologyElement(tagName, document));
59 }
60
61 const AtomicString& SVGFEMorphologyElement::radiusXIdentifier()
62 {
63     DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGRadiusX"));
64     return s_identifier;
65 }
66
67 const AtomicString& SVGFEMorphologyElement::radiusYIdentifier()
68 {
69     DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGRadiusY"));
70     return s_identifier;
71 }
72
73 void SVGFEMorphologyElement::setRadius(float x, float y)
74 {
75     setRadiusXBaseValue(x);
76     setRadiusYBaseValue(y);
77     invalidate();
78 }
79
80 bool SVGFEMorphologyElement::isSupportedAttribute(const QualifiedName& attrName)
81 {
82     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
83     if (supportedAttributes.isEmpty()) {
84         supportedAttributes.add(SVGNames::inAttr);
85         supportedAttributes.add(SVGNames::operatorAttr);
86         supportedAttributes.add(SVGNames::radiusAttr);
87     }
88     return supportedAttributes.contains(attrName);
89 }
90
91 void SVGFEMorphologyElement::parseMappedAttribute(Attribute* attr)
92 {
93     if (!isSupportedAttribute(attr->name())) {
94         SVGFilterPrimitiveStandardAttributes::parseMappedAttribute(attr);
95         return;
96     }
97
98     const AtomicString& value = attr->value();
99     if (attr->name() == SVGNames::operatorAttr) {
100         MorphologyOperatorType propertyValue = SVGPropertyTraits<MorphologyOperatorType>::fromString(value);
101         if (propertyValue > 0)
102             set_operatorBaseValue(propertyValue);
103         return;
104     }
105
106     if (attr->name() == SVGNames::inAttr) {
107         setIn1BaseValue(value);
108         return;
109     }
110
111     if (attr->name() == SVGNames::radiusAttr) {
112         float x, y;
113         if (parseNumberOptionalNumber(value, x, y)) {
114             setRadiusXBaseValue(x);
115             setRadiusYBaseValue(y);
116         }
117         return;
118     }
119
120     ASSERT_NOT_REACHED();
121 }
122
123 bool SVGFEMorphologyElement::setFilterEffectAttribute(FilterEffect* effect, const QualifiedName& attrName)
124 {
125     FEMorphology* morphology = static_cast<FEMorphology*>(effect);
126     if (attrName == SVGNames::operatorAttr)
127         return morphology->setMorphologyOperator(_operator());
128     if (attrName == SVGNames::radiusAttr) {
129         // Both setRadius functions should be evaluated separately.
130         bool isRadiusXChanged = morphology->setRadiusX(radiusX());
131         bool isRadiusYChanged = morphology->setRadiusY(radiusY());
132         return isRadiusXChanged || isRadiusYChanged;
133     }
134
135     ASSERT_NOT_REACHED();
136     return false;
137 }
138
139 void SVGFEMorphologyElement::svgAttributeChanged(const QualifiedName& attrName)
140 {
141     if (!isSupportedAttribute(attrName)) {
142         SVGFilterPrimitiveStandardAttributes::svgAttributeChanged(attrName);
143         return;
144     }
145
146     SVGElementInstance::InvalidationGuard invalidationGuard(this);
147     
148     if (attrName == SVGNames::operatorAttr || attrName == SVGNames::radiusAttr) {
149         primitiveAttributeChanged(attrName);
150         return;
151     }
152
153     if (attrName == SVGNames::inAttr) {
154         invalidate();
155         return;
156     }
157
158     ASSERT_NOT_REACHED();
159 }
160
161 PassRefPtr<FilterEffect> SVGFEMorphologyElement::build(SVGFilterBuilder* filterBuilder, Filter* filter)
162 {
163     FilterEffect* input1 = filterBuilder->getEffectById(in1());
164     float xRadius = radiusX();
165     float yRadius = radiusY();
166
167     if (!input1)
168         return 0;
169
170     if (xRadius < 0 || yRadius < 0)
171         return 0;
172
173     RefPtr<FilterEffect> effect = FEMorphology::create(filter, _operator(), xRadius, yRadius);
174     effect->inputEffects().append(input1);
175     return effect.release();
176 }
177
178 } // namespace WebCore
179
180 #endif // ENABLE(SVG)