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#include "SVGMaskElement.h"
26
27#include "Attribute.h"
28#include "RenderSVGResourceMasker.h"
29#include "SVGElementInstance.h"
30#include "SVGNames.h"
31#include "SVGRenderSupport.h"
32#include "SVGUnitTypes.h"
33#include "StyleResolver.h"
34#include <wtf/NeverDestroyed.h>
35
36namespace WebCore {
37
38// Animated property definitions
39DEFINE_ANIMATED_ENUMERATION(SVGMaskElement, SVGNames::maskUnitsAttr, MaskUnits, maskUnits, SVGUnitTypes::SVGUnitType)
40DEFINE_ANIMATED_ENUMERATION(SVGMaskElement, SVGNames::maskContentUnitsAttr, MaskContentUnits, maskContentUnits, SVGUnitTypes::SVGUnitType)
41DEFINE_ANIMATED_LENGTH(SVGMaskElement, SVGNames::xAttr, X, x)
42DEFINE_ANIMATED_LENGTH(SVGMaskElement, SVGNames::yAttr, Y, y)
43DEFINE_ANIMATED_LENGTH(SVGMaskElement, SVGNames::widthAttr, Width, width)
44DEFINE_ANIMATED_LENGTH(SVGMaskElement, SVGNames::heightAttr, Height, height)
45DEFINE_ANIMATED_BOOLEAN(SVGMaskElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
46
47BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGMaskElement)
48    REGISTER_LOCAL_ANIMATED_PROPERTY(maskUnits)
49    REGISTER_LOCAL_ANIMATED_PROPERTY(maskContentUnits)
50    REGISTER_LOCAL_ANIMATED_PROPERTY(x)
51    REGISTER_LOCAL_ANIMATED_PROPERTY(y)
52    REGISTER_LOCAL_ANIMATED_PROPERTY(width)
53    REGISTER_LOCAL_ANIMATED_PROPERTY(height)
54    REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired)
55    REGISTER_PARENT_ANIMATED_PROPERTIES(SVGElement)
56    REGISTER_PARENT_ANIMATED_PROPERTIES(SVGTests)
57END_REGISTER_ANIMATED_PROPERTIES
58
59inline SVGMaskElement::SVGMaskElement(const QualifiedName& tagName, Document& document)
60    : SVGElement(tagName, document)
61    , m_maskUnits(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
62    , m_maskContentUnits(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE)
63    , m_x(LengthModeWidth, "-10%")
64    , m_y(LengthModeHeight, "-10%")
65    , m_width(LengthModeWidth, "120%")
66    , m_height(LengthModeHeight, "120%")
67{
68    // Spec: If the x/y attribute is not specified, the effect is as if a value of "-10%" were specified.
69    // Spec: If the width/height attribute is not specified, the effect is as if a value of "120%" were specified.
70    ASSERT(hasTagName(SVGNames::maskTag));
71    registerAnimatedPropertiesForSVGMaskElement();
72}
73
74PassRefPtr<SVGMaskElement> SVGMaskElement::create(const QualifiedName& tagName, Document& document)
75{
76    return adoptRef(new SVGMaskElement(tagName, document));
77}
78
79bool SVGMaskElement::isSupportedAttribute(const QualifiedName& attrName)
80{
81    static NeverDestroyed<HashSet<QualifiedName>> supportedAttributes;
82    if (supportedAttributes.get().isEmpty()) {
83        SVGTests::addSupportedAttributes(supportedAttributes);
84        SVGLangSpace::addSupportedAttributes(supportedAttributes);
85        SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes);
86        supportedAttributes.get().add(SVGNames::maskUnitsAttr);
87        supportedAttributes.get().add(SVGNames::maskContentUnitsAttr);
88        supportedAttributes.get().add(SVGNames::xAttr);
89        supportedAttributes.get().add(SVGNames::yAttr);
90        supportedAttributes.get().add(SVGNames::widthAttr);
91        supportedAttributes.get().add(SVGNames::heightAttr);
92    }
93    return supportedAttributes.get().contains<SVGAttributeHashTranslator>(attrName);
94}
95
96void SVGMaskElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
97{
98    SVGParsingError parseError = NoError;
99
100    if (!isSupportedAttribute(name))
101        SVGElement::parseAttribute(name, value);
102    else if (name == SVGNames::maskUnitsAttr) {
103        SVGUnitTypes::SVGUnitType propertyValue = SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::fromString(value);
104        if (propertyValue > 0)
105            setMaskUnitsBaseValue(propertyValue);
106        return;
107    } else if (name == SVGNames::maskContentUnitsAttr) {
108        SVGUnitTypes::SVGUnitType propertyValue = SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::fromString(value);
109        if (propertyValue > 0)
110            setMaskContentUnitsBaseValue(propertyValue);
111        return;
112    } else if (name == SVGNames::xAttr)
113        setXBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
114    else if (name == SVGNames::yAttr)
115        setYBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
116    else if (name == SVGNames::widthAttr)
117        setWidthBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
118    else if (name == SVGNames::heightAttr)
119        setHeightBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
120    else if (SVGTests::parseAttribute(name, value)
121             || SVGLangSpace::parseAttribute(name, value)
122             || SVGExternalResourcesRequired::parseAttribute(name, value)) {
123    } else
124        ASSERT_NOT_REACHED();
125
126    reportAttributeParsingError(parseError, name, value);
127}
128
129void SVGMaskElement::svgAttributeChanged(const QualifiedName& attrName)
130{
131    if (!isSupportedAttribute(attrName)) {
132        SVGElement::svgAttributeChanged(attrName);
133        return;
134    }
135
136    SVGElementInstance::InvalidationGuard invalidationGuard(this);
137
138    if (attrName == SVGNames::xAttr
139        || attrName == SVGNames::yAttr
140        || attrName == SVGNames::widthAttr
141        || attrName == SVGNames::heightAttr)
142        updateRelativeLengthsInformation();
143
144    if (RenderObject* object = renderer())
145        object->setNeedsLayout();
146}
147
148void SVGMaskElement::childrenChanged(const ChildChange& change)
149{
150    SVGElement::childrenChanged(change);
151
152    if (change.source == ChildChangeSourceParser)
153        return;
154
155    if (RenderObject* object = renderer())
156        object->setNeedsLayout();
157}
158
159RenderPtr<RenderElement> SVGMaskElement::createElementRenderer(PassRef<RenderStyle> style)
160{
161    return createRenderer<RenderSVGResourceMasker>(*this, WTF::move(style));
162}
163
164bool SVGMaskElement::selfHasRelativeLengths() const
165{
166    return x().isRelative()
167        || y().isRelative()
168        || width().isRelative()
169        || height().isRelative();
170}
171
172}
173