1/*
2 * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
3 * Copyright (C) 2004, 2005, 2006 Rob Buis <buis@kde.org>
4 * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB.  If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22#include "config.h"
23
24#if ENABLE(SVG) && ENABLE(FILTERS)
25#include "SVGFilterPrimitiveStandardAttributes.h"
26
27#include "Attribute.h"
28#include "FilterEffect.h"
29#include "RenderSVGResourceFilterPrimitive.h"
30#include "SVGElementInstance.h"
31#include "SVGFilterBuilder.h"
32#include "SVGLength.h"
33#include "SVGNames.h"
34#include "SVGStyledElement.h"
35#include "SVGUnitTypes.h"
36
37namespace WebCore {
38
39// Animated property definitions
40DEFINE_ANIMATED_LENGTH(SVGFilterPrimitiveStandardAttributes, SVGNames::xAttr, X, x)
41DEFINE_ANIMATED_LENGTH(SVGFilterPrimitiveStandardAttributes, SVGNames::yAttr, Y, y)
42DEFINE_ANIMATED_LENGTH(SVGFilterPrimitiveStandardAttributes, SVGNames::widthAttr, Width, width)
43DEFINE_ANIMATED_LENGTH(SVGFilterPrimitiveStandardAttributes, SVGNames::heightAttr, Height, height)
44DEFINE_ANIMATED_STRING(SVGFilterPrimitiveStandardAttributes, SVGNames::resultAttr, Result, result)
45
46BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGFilterPrimitiveStandardAttributes)
47    REGISTER_LOCAL_ANIMATED_PROPERTY(x)
48    REGISTER_LOCAL_ANIMATED_PROPERTY(y)
49    REGISTER_LOCAL_ANIMATED_PROPERTY(width)
50    REGISTER_LOCAL_ANIMATED_PROPERTY(height)
51    REGISTER_LOCAL_ANIMATED_PROPERTY(result)
52    REGISTER_PARENT_ANIMATED_PROPERTIES(SVGStyledElement)
53END_REGISTER_ANIMATED_PROPERTIES
54
55SVGFilterPrimitiveStandardAttributes::SVGFilterPrimitiveStandardAttributes(const QualifiedName& tagName, Document* document)
56    : SVGStyledElement(tagName, document)
57    , m_x(LengthModeWidth, "0%")
58    , m_y(LengthModeHeight, "0%")
59    , m_width(LengthModeWidth, "100%")
60    , m_height(LengthModeHeight, "100%")
61{
62    // Spec: If the x/y attribute is not specified, the effect is as if a value of "0%" were specified.
63    // Spec: If the width/height attribute is not specified, the effect is as if a value of "100%" were specified.
64    registerAnimatedPropertiesForSVGFilterPrimitiveStandardAttributes();
65}
66
67bool SVGFilterPrimitiveStandardAttributes::isSupportedAttribute(const QualifiedName& attrName)
68{
69    DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
70    if (supportedAttributes.isEmpty()) {
71        supportedAttributes.add(SVGNames::xAttr);
72        supportedAttributes.add(SVGNames::yAttr);
73        supportedAttributes.add(SVGNames::widthAttr);
74        supportedAttributes.add(SVGNames::heightAttr);
75        supportedAttributes.add(SVGNames::resultAttr);
76    }
77    return supportedAttributes.contains<QualifiedName, SVGAttributeHashTranslator>(attrName);
78}
79
80void SVGFilterPrimitiveStandardAttributes::parseAttribute(const QualifiedName& name, const AtomicString& value)
81{
82    SVGParsingError parseError = NoError;
83
84    if (!isSupportedAttribute(name))
85        SVGStyledElement::parseAttribute(name, value);
86    else if (name == SVGNames::xAttr)
87        setXBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
88    else if (name == SVGNames::yAttr)
89        setYBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
90    else if (name == SVGNames::widthAttr)
91        setWidthBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
92    else if (name == SVGNames::heightAttr)
93        setHeightBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
94    else if (name == SVGNames::resultAttr)
95        setResultBaseValue(value);
96    else
97        ASSERT_NOT_REACHED();
98
99    reportAttributeParsingError(parseError, name, value);
100}
101
102bool SVGFilterPrimitiveStandardAttributes::setFilterEffectAttribute(FilterEffect*, const QualifiedName&)
103{
104    // When all filters support this method, it will be changed to a pure virtual method.
105    ASSERT_NOT_REACHED();
106    return false;
107}
108
109void SVGFilterPrimitiveStandardAttributes::svgAttributeChanged(const QualifiedName& attrName)
110{
111    if (!isSupportedAttribute(attrName)) {
112        SVGStyledElement::svgAttributeChanged(attrName);
113        return;
114    }
115
116    SVGElementInstance::InvalidationGuard invalidationGuard(this);
117    invalidate();
118}
119
120void SVGFilterPrimitiveStandardAttributes::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
121{
122    SVGStyledElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
123
124    if (!changedByParser)
125        invalidate();
126}
127
128void SVGFilterPrimitiveStandardAttributes::setStandardAttributes(FilterEffect* filterEffect) const
129{
130    ASSERT(filterEffect);
131    if (!filterEffect)
132        return;
133
134    if (hasAttribute(SVGNames::xAttr))
135        filterEffect->setHasX(true);
136    if (hasAttribute(SVGNames::yAttr))
137        filterEffect->setHasY(true);
138    if (hasAttribute(SVGNames::widthAttr))
139        filterEffect->setHasWidth(true);
140    if (hasAttribute(SVGNames::heightAttr))
141        filterEffect->setHasHeight(true);
142}
143
144RenderObject* SVGFilterPrimitiveStandardAttributes::createRenderer(RenderArena* arena, RenderStyle*)
145{
146    return new (arena) RenderSVGResourceFilterPrimitive(this);
147}
148
149bool SVGFilterPrimitiveStandardAttributes::rendererIsNeeded(const NodeRenderingContext& context)
150{
151    if (parentNode() && (parentNode()->hasTagName(SVGNames::filterTag)))
152        return SVGStyledElement::rendererIsNeeded(context);
153
154    return false;
155}
156
157void invalidateFilterPrimitiveParent(SVGElement* element)
158{
159    if (!element)
160        return;
161
162    ContainerNode* parent = element->parentNode();
163
164    if (!parent)
165        return;
166
167    RenderObject* renderer = parent->renderer();
168    if (!renderer || !renderer->isSVGResourceFilterPrimitive())
169        return;
170
171    RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer, false);
172}
173
174}
175
176#endif // ENABLE(SVG)
177