1/*
2 * Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3 * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
4 * Copyright (C) 2005 Alexander Kellett <lypanov@kde.org>
5 * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
6 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB.  If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24#include "config.h"
25
26#include "core/svg/SVGMaskElement.h"
27
28#include "core/rendering/svg/RenderSVGResourceMasker.h"
29#include "core/svg/SVGElementInstance.h"
30
31namespace WebCore {
32
33// Animated property definitions
34DEFINE_ANIMATED_ENUMERATION(SVGMaskElement, SVGNames::maskUnitsAttr, MaskUnits, maskUnits, SVGUnitTypes::SVGUnitType)
35DEFINE_ANIMATED_ENUMERATION(SVGMaskElement, SVGNames::maskContentUnitsAttr, MaskContentUnits, maskContentUnits, SVGUnitTypes::SVGUnitType)
36DEFINE_ANIMATED_LENGTH(SVGMaskElement, SVGNames::xAttr, X, x)
37DEFINE_ANIMATED_LENGTH(SVGMaskElement, SVGNames::yAttr, Y, y)
38DEFINE_ANIMATED_LENGTH(SVGMaskElement, SVGNames::widthAttr, Width, width)
39DEFINE_ANIMATED_LENGTH(SVGMaskElement, SVGNames::heightAttr, Height, height)
40DEFINE_ANIMATED_BOOLEAN(SVGMaskElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
41
42BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGMaskElement)
43    REGISTER_LOCAL_ANIMATED_PROPERTY(maskUnits)
44    REGISTER_LOCAL_ANIMATED_PROPERTY(maskContentUnits)
45    REGISTER_LOCAL_ANIMATED_PROPERTY(x)
46    REGISTER_LOCAL_ANIMATED_PROPERTY(y)
47    REGISTER_LOCAL_ANIMATED_PROPERTY(width)
48    REGISTER_LOCAL_ANIMATED_PROPERTY(height)
49    REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired)
50    REGISTER_PARENT_ANIMATED_PROPERTIES(SVGElement)
51    REGISTER_PARENT_ANIMATED_PROPERTIES(SVGTests)
52END_REGISTER_ANIMATED_PROPERTIES
53
54inline SVGMaskElement::SVGMaskElement(Document& document)
55    : SVGElement(SVGNames::maskTag, document)
56    , m_maskUnits(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
57    , m_maskContentUnits(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE)
58    , m_x(LengthModeWidth, "-10%")
59    , m_y(LengthModeHeight, "-10%")
60    , m_width(LengthModeWidth, "120%")
61    , m_height(LengthModeHeight, "120%")
62{
63    // Spec: If the x/y attribute is not specified, the effect is as if a value of "-10%" were specified.
64    // Spec: If the width/height attribute is not specified, the effect is as if a value of "120%" were specified.
65    ScriptWrappable::init(this);
66    registerAnimatedPropertiesForSVGMaskElement();
67}
68
69PassRefPtr<SVGMaskElement> SVGMaskElement::create(Document& document)
70{
71    return adoptRef(new SVGMaskElement(document));
72}
73
74bool SVGMaskElement::isSupportedAttribute(const QualifiedName& attrName)
75{
76    DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
77    if (supportedAttributes.isEmpty()) {
78        SVGTests::addSupportedAttributes(supportedAttributes);
79        SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes);
80        supportedAttributes.add(SVGNames::maskUnitsAttr);
81        supportedAttributes.add(SVGNames::maskContentUnitsAttr);
82        supportedAttributes.add(SVGNames::xAttr);
83        supportedAttributes.add(SVGNames::yAttr);
84        supportedAttributes.add(SVGNames::widthAttr);
85        supportedAttributes.add(SVGNames::heightAttr);
86    }
87    return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
88}
89
90void SVGMaskElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
91{
92    SVGParsingError parseError = NoError;
93
94    if (!isSupportedAttribute(name))
95        SVGElement::parseAttribute(name, value);
96    else if (name == SVGNames::maskUnitsAttr) {
97        SVGUnitTypes::SVGUnitType propertyValue = SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::fromString(value);
98        if (propertyValue > 0)
99            setMaskUnitsBaseValue(propertyValue);
100        return;
101    } else if (name == SVGNames::maskContentUnitsAttr) {
102        SVGUnitTypes::SVGUnitType propertyValue = SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::fromString(value);
103        if (propertyValue > 0)
104            setMaskContentUnitsBaseValue(propertyValue);
105        return;
106    } else if (name == SVGNames::xAttr)
107        setXBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
108    else if (name == SVGNames::yAttr)
109        setYBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
110    else if (name == SVGNames::widthAttr)
111        setWidthBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
112    else if (name == SVGNames::heightAttr)
113        setHeightBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
114    else if (SVGTests::parseAttribute(name, value)
115             || SVGExternalResourcesRequired::parseAttribute(name, value)) {
116    } else
117        ASSERT_NOT_REACHED();
118
119    reportAttributeParsingError(parseError, name, value);
120}
121
122void SVGMaskElement::svgAttributeChanged(const QualifiedName& attrName)
123{
124    if (!isSupportedAttribute(attrName)) {
125        SVGElement::svgAttributeChanged(attrName);
126        return;
127    }
128
129    SVGElementInstance::InvalidationGuard invalidationGuard(this);
130
131    if (attrName == SVGNames::xAttr
132        || attrName == SVGNames::yAttr
133        || attrName == SVGNames::widthAttr
134        || attrName == SVGNames::heightAttr)
135        updateRelativeLengthsInformation();
136
137    RenderSVGResourceContainer* renderer = toRenderSVGResourceContainer(this->renderer());
138    if (renderer)
139        renderer->invalidateCacheAndMarkForLayout();
140}
141
142void SVGMaskElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
143{
144    SVGElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
145
146    if (changedByParser)
147        return;
148
149    if (RenderObject* object = renderer())
150        object->setNeedsLayout();
151}
152
153RenderObject* SVGMaskElement::createRenderer(RenderStyle*)
154{
155    return new RenderSVGResourceMasker(this);
156}
157
158bool SVGMaskElement::selfHasRelativeLengths() const
159{
160    return xCurrentValue().isRelative()
161        || yCurrentValue().isRelative()
162        || widthCurrentValue().isRelative()
163        || heightCurrentValue().isRelative();
164}
165
166}
167