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 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB.  If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21#include "config.h"
22
23#include "core/svg/SVGPolyElement.h"
24
25#include "core/dom/Document.h"
26#include "core/rendering/svg/RenderSVGResource.h"
27#include "core/svg/SVGAnimatedPointList.h"
28#include "core/svg/SVGElementInstance.h"
29#include "core/svg/SVGParserUtilities.h"
30
31namespace WebCore {
32
33// Define custom animated property 'points'.
34const SVGPropertyInfo* SVGPolyElement::pointsPropertyInfo()
35{
36    static const SVGPropertyInfo* s_propertyInfo = 0;
37    if (!s_propertyInfo) {
38        s_propertyInfo = new SVGPropertyInfo(AnimatedPoints,
39                                             PropertyIsReadWrite,
40                                             SVGNames::pointsAttr,
41                                             SVGNames::pointsAttr.localName(),
42                                             &SVGPolyElement::synchronizePoints,
43                                             &SVGPolyElement::lookupOrCreatePointsWrapper);
44    }
45    return s_propertyInfo;
46}
47
48SVGPointList& SVGPolyElement::pointsCurrentValue()
49{
50    SVGAnimatedProperty* wrapper = SVGAnimatedProperty::lookupWrapper<SVGPolyElement, SVGAnimatedPointList>(this, pointsPropertyInfo());
51    if (wrapper && wrapper->isAnimating()) {
52        if (SVGListPropertyTearOff<SVGPointList>* ap = animatedPoints())
53            return ap->values();
54    }
55
56    return m_points.value;
57}
58
59// Animated property definitions
60DEFINE_ANIMATED_BOOLEAN(SVGPolyElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
61
62BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGPolyElement)
63    REGISTER_LOCAL_ANIMATED_PROPERTY(points)
64    REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired)
65    REGISTER_PARENT_ANIMATED_PROPERTIES(SVGGraphicsElement)
66END_REGISTER_ANIMATED_PROPERTIES
67
68SVGPolyElement::SVGPolyElement(const QualifiedName& tagName, Document& document)
69    : SVGGeometryElement(tagName, document)
70{
71    registerAnimatedPropertiesForSVGPolyElement();
72}
73
74bool SVGPolyElement::isSupportedAttribute(const QualifiedName& attrName)
75{
76    DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
77    if (supportedAttributes.isEmpty()) {
78        SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes);
79        supportedAttributes.add(SVGNames::pointsAttr);
80    }
81    return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
82}
83
84void SVGPolyElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
85{
86    if (!isSupportedAttribute(name)) {
87        SVGGeometryElement::parseAttribute(name, value);
88        return;
89    }
90
91    if (name == SVGNames::pointsAttr) {
92        SVGPointList newList;
93        if (!pointsListFromSVGData(newList, value))
94            document().accessSVGExtensions()->reportError("Problem parsing points=\"" + value + "\"");
95
96        if (SVGAnimatedProperty* wrapper = SVGAnimatedProperty::lookupWrapper<SVGPolyElement, SVGAnimatedPointList>(this, pointsPropertyInfo()))
97            static_cast<SVGAnimatedPointList*>(wrapper)->detachListWrappers(newList.size());
98
99        m_points.value = newList;
100        return;
101    }
102
103    if (SVGExternalResourcesRequired::parseAttribute(name, value))
104        return;
105
106    ASSERT_NOT_REACHED();
107}
108
109void SVGPolyElement::svgAttributeChanged(const QualifiedName& attrName)
110{
111    if (!isSupportedAttribute(attrName)) {
112        SVGGeometryElement::svgAttributeChanged(attrName);
113        return;
114    }
115
116    SVGElementInstance::InvalidationGuard invalidationGuard(this);
117
118    RenderSVGShape* renderer = toRenderSVGShape(this->renderer());
119    if (!renderer)
120        return;
121
122    if (attrName == SVGNames::pointsAttr) {
123        renderer->setNeedsShapeUpdate();
124        RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
125        return;
126    }
127
128    if (SVGExternalResourcesRequired::isKnownAttribute(attrName)) {
129        RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
130        return;
131    }
132
133    ASSERT_NOT_REACHED();
134}
135
136void SVGPolyElement::synchronizePoints(SVGElement* contextElement)
137{
138    ASSERT(contextElement);
139    SVGPolyElement* ownerType = toSVGPolyElement(contextElement);
140    if (!ownerType->m_points.shouldSynchronize)
141        return;
142    ownerType->m_points.synchronize(ownerType, pointsPropertyInfo()->attributeName, ownerType->m_points.value.valueAsString());
143}
144
145PassRefPtr<SVGAnimatedProperty> SVGPolyElement::lookupOrCreatePointsWrapper(SVGElement* contextElement)
146{
147    ASSERT(contextElement);
148    SVGPolyElement* ownerType = toSVGPolyElement(contextElement);
149    return SVGAnimatedProperty::lookupOrCreateWrapper<SVGPolyElement, SVGAnimatedPointList, SVGPointList>
150           (ownerType, pointsPropertyInfo(), ownerType->m_points.value);
151}
152
153SVGListPropertyTearOff<SVGPointList>* SVGPolyElement::points()
154{
155    m_points.shouldSynchronize = true;
156    return static_cast<SVGListPropertyTearOff<SVGPointList>*>(static_pointer_cast<SVGAnimatedPointList>(lookupOrCreatePointsWrapper(this))->baseVal());
157}
158
159SVGListPropertyTearOff<SVGPointList>* SVGPolyElement::animatedPoints()
160{
161    m_points.shouldSynchronize = true;
162    return static_cast<SVGListPropertyTearOff<SVGPointList>*>(static_pointer_cast<SVGAnimatedPointList>(lookupOrCreatePointsWrapper(this))->animVal());
163}
164
165}
166