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
30namespace blink {
31
32inline SVGMaskElement::SVGMaskElement(Document& document)
33    : SVGElement(SVGNames::maskTag, document)
34    , SVGTests(this)
35    , m_x(SVGAnimatedLength::create(this, SVGNames::xAttr, SVGLength::create(LengthModeWidth), AllowNegativeLengths))
36    , m_y(SVGAnimatedLength::create(this, SVGNames::yAttr, SVGLength::create(LengthModeHeight), AllowNegativeLengths))
37    , m_width(SVGAnimatedLength::create(this, SVGNames::widthAttr, SVGLength::create(LengthModeWidth), ForbidNegativeLengths))
38    , m_height(SVGAnimatedLength::create(this, SVGNames::heightAttr, SVGLength::create(LengthModeHeight), ForbidNegativeLengths))
39    , m_maskUnits(SVGAnimatedEnumeration<SVGUnitTypes::SVGUnitType>::create(this, SVGNames::maskUnitsAttr, SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX))
40    , m_maskContentUnits(SVGAnimatedEnumeration<SVGUnitTypes::SVGUnitType>::create(this, SVGNames::maskContentUnitsAttr, SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE))
41{
42    // Spec: If the x/y attribute is not specified, the effect is as if a value of "-10%" were specified.
43    m_x->setDefaultValueAsString("-10%");
44    m_y->setDefaultValueAsString("-10%");
45
46    // Spec: If the width/height attribute is not specified, the effect is as if a value of "120%" were specified.
47    m_width->setDefaultValueAsString("120%");
48    m_height->setDefaultValueAsString("120%");
49
50    addToPropertyMap(m_x);
51    addToPropertyMap(m_y);
52    addToPropertyMap(m_width);
53    addToPropertyMap(m_height);
54    addToPropertyMap(m_maskUnits);
55    addToPropertyMap(m_maskContentUnits);
56}
57
58DEFINE_NODE_FACTORY(SVGMaskElement)
59
60bool SVGMaskElement::isSupportedAttribute(const QualifiedName& attrName)
61{
62    DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
63    if (supportedAttributes.isEmpty()) {
64        SVGTests::addSupportedAttributes(supportedAttributes);
65        supportedAttributes.add(SVGNames::maskUnitsAttr);
66        supportedAttributes.add(SVGNames::maskContentUnitsAttr);
67        supportedAttributes.add(SVGNames::xAttr);
68        supportedAttributes.add(SVGNames::yAttr);
69        supportedAttributes.add(SVGNames::widthAttr);
70        supportedAttributes.add(SVGNames::heightAttr);
71    }
72    return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
73}
74
75void SVGMaskElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
76{
77    SVGParsingError parseError = NoError;
78
79    if (!isSupportedAttribute(name))
80        SVGElement::parseAttribute(name, value);
81    else if (name == SVGNames::maskUnitsAttr)
82        m_maskUnits->setBaseValueAsString(value, parseError);
83    else if (name == SVGNames::maskContentUnitsAttr)
84        m_maskContentUnits->setBaseValueAsString(value, parseError);
85    else if (name == SVGNames::xAttr)
86        m_x->setBaseValueAsString(value, parseError);
87    else if (name == SVGNames::yAttr)
88        m_y->setBaseValueAsString(value, parseError);
89    else if (name == SVGNames::widthAttr)
90        m_width->setBaseValueAsString(value, parseError);
91    else if (name == SVGNames::heightAttr)
92        m_height->setBaseValueAsString(value, parseError);
93    else if (SVGTests::parseAttribute(name, value)) {
94    } else
95        ASSERT_NOT_REACHED();
96
97    reportAttributeParsingError(parseError, name, value);
98}
99
100void SVGMaskElement::svgAttributeChanged(const QualifiedName& attrName)
101{
102    if (!isSupportedAttribute(attrName)) {
103        SVGElement::svgAttributeChanged(attrName);
104        return;
105    }
106
107    SVGElement::InvalidationGuard invalidationGuard(this);
108
109    if (attrName == SVGNames::xAttr
110        || attrName == SVGNames::yAttr
111        || attrName == SVGNames::widthAttr
112        || attrName == SVGNames::heightAttr)
113        updateRelativeLengthsInformation();
114
115    RenderSVGResourceContainer* renderer = toRenderSVGResourceContainer(this->renderer());
116    if (renderer)
117        renderer->invalidateCacheAndMarkForLayout();
118}
119
120void SVGMaskElement::childrenChanged(const ChildrenChange& change)
121{
122    SVGElement::childrenChanged(change);
123
124    if (change.byParser)
125        return;
126
127    if (RenderObject* object = renderer())
128        object->setNeedsLayoutAndFullPaintInvalidation();
129}
130
131RenderObject* SVGMaskElement::createRenderer(RenderStyle*)
132{
133    return new RenderSVGResourceMasker(this);
134}
135
136bool SVGMaskElement::selfHasRelativeLengths() const
137{
138    return m_x->currentValue()->isRelative()
139        || m_y->currentValue()->isRelative()
140        || m_width->currentValue()->isRelative()
141        || m_height->currentValue()->isRelative();
142}
143
144} // namespace blink
145