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
32namespace WebCore {
33
34// Animated property definitions
35DEFINE_ANIMATED_STRING(SVGFEMorphologyElement, SVGNames::inAttr, In1, in1)
36DEFINE_ANIMATED_ENUMERATION(SVGFEMorphologyElement, SVGNames::operatorAttr, _operator, _operator, MorphologyOperatorType)
37DEFINE_ANIMATED_NUMBER_MULTIPLE_WRAPPERS(SVGFEMorphologyElement, SVGNames::radiusAttr, radiusXIdentifier(), RadiusX, radiusX)
38DEFINE_ANIMATED_NUMBER_MULTIPLE_WRAPPERS(SVGFEMorphologyElement, SVGNames::radiusAttr, radiusYIdentifier(), RadiusY, radiusY)
39
40BEGIN_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)
46END_REGISTER_ANIMATED_PROPERTIES
47
48inline 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
56PassRefPtr<SVGFEMorphologyElement> SVGFEMorphologyElement::create(const QualifiedName& tagName, Document* document)
57{
58    return adoptRef(new SVGFEMorphologyElement(tagName, document));
59}
60
61const AtomicString& SVGFEMorphologyElement::radiusXIdentifier()
62{
63    DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGRadiusX", AtomicString::ConstructFromLiteral));
64    return s_identifier;
65}
66
67const AtomicString& SVGFEMorphologyElement::radiusYIdentifier()
68{
69    DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGRadiusY", AtomicString::ConstructFromLiteral));
70    return s_identifier;
71}
72
73void SVGFEMorphologyElement::setRadius(float x, float y)
74{
75    setRadiusXBaseValue(x);
76    setRadiusYBaseValue(y);
77    invalidate();
78}
79
80bool 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<QualifiedName, SVGAttributeHashTranslator>(attrName);
89}
90
91void SVGFEMorphologyElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
92{
93    if (!isSupportedAttribute(name)) {
94        SVGFilterPrimitiveStandardAttributes::parseAttribute(name, value);
95        return;
96    }
97
98    if (name == SVGNames::operatorAttr) {
99        MorphologyOperatorType propertyValue = SVGPropertyTraits<MorphologyOperatorType>::fromString(value);
100        if (propertyValue > 0)
101            set_operatorBaseValue(propertyValue);
102        return;
103    }
104
105    if (name == SVGNames::inAttr) {
106        setIn1BaseValue(value);
107        return;
108    }
109
110    if (name == SVGNames::radiusAttr) {
111        float x, y;
112        if (parseNumberOptionalNumber(value, x, y)) {
113            setRadiusXBaseValue(x);
114            setRadiusYBaseValue(y);
115        }
116        return;
117    }
118
119    ASSERT_NOT_REACHED();
120}
121
122bool SVGFEMorphologyElement::setFilterEffectAttribute(FilterEffect* effect, const QualifiedName& attrName)
123{
124    FEMorphology* morphology = static_cast<FEMorphology*>(effect);
125    if (attrName == SVGNames::operatorAttr)
126        return morphology->setMorphologyOperator(_operator());
127    if (attrName == SVGNames::radiusAttr) {
128        // Both setRadius functions should be evaluated separately.
129        bool isRadiusXChanged = morphology->setRadiusX(radiusX());
130        bool isRadiusYChanged = morphology->setRadiusY(radiusY());
131        return isRadiusXChanged || isRadiusYChanged;
132    }
133
134    ASSERT_NOT_REACHED();
135    return false;
136}
137
138void SVGFEMorphologyElement::svgAttributeChanged(const QualifiedName& attrName)
139{
140    if (!isSupportedAttribute(attrName)) {
141        SVGFilterPrimitiveStandardAttributes::svgAttributeChanged(attrName);
142        return;
143    }
144
145    SVGElementInstance::InvalidationGuard invalidationGuard(this);
146
147    if (attrName == SVGNames::operatorAttr || attrName == SVGNames::radiusAttr) {
148        primitiveAttributeChanged(attrName);
149        return;
150    }
151
152    if (attrName == SVGNames::inAttr) {
153        invalidate();
154        return;
155    }
156
157    ASSERT_NOT_REACHED();
158}
159
160PassRefPtr<FilterEffect> SVGFEMorphologyElement::build(SVGFilterBuilder* filterBuilder, Filter* filter)
161{
162    FilterEffect* input1 = filterBuilder->getEffectById(in1());
163    float xRadius = radiusX();
164    float yRadius = radiusY();
165
166    if (!input1)
167        return 0;
168
169    if (xRadius < 0 || yRadius < 0)
170        return 0;
171
172    RefPtr<FilterEffect> effect = FEMorphology::create(filter, _operator(), xRadius, yRadius);
173    effect->inputEffects().append(input1);
174    return effect.release();
175}
176
177} // namespace WebCore
178
179#endif // ENABLE(SVG)
180