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#if ENABLE(SVG)
24#include "SVGEllipseElement.h"
25
26#include "Attribute.h"
27#include "FloatPoint.h"
28#include "RenderSVGPath.h"
29#include "RenderSVGResource.h"
30#include "SVGLength.h"
31#include "SVGNames.h"
32
33namespace WebCore {
34
35// Animated property definitions
36DEFINE_ANIMATED_LENGTH(SVGEllipseElement, SVGNames::cxAttr, Cx, cx)
37DEFINE_ANIMATED_LENGTH(SVGEllipseElement, SVGNames::cyAttr, Cy, cy)
38DEFINE_ANIMATED_LENGTH(SVGEllipseElement, SVGNames::rxAttr, Rx, rx)
39DEFINE_ANIMATED_LENGTH(SVGEllipseElement, SVGNames::ryAttr, Ry, ry)
40DEFINE_ANIMATED_BOOLEAN(SVGEllipseElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
41
42inline SVGEllipseElement::SVGEllipseElement(const QualifiedName& tagName, Document* document)
43    : SVGStyledTransformableElement(tagName, document)
44    , m_cx(LengthModeWidth)
45    , m_cy(LengthModeHeight)
46    , m_rx(LengthModeWidth)
47    , m_ry(LengthModeHeight)
48{
49}
50
51PassRefPtr<SVGEllipseElement> SVGEllipseElement::create(const QualifiedName& tagName, Document* document)
52{
53    return adoptRef(new SVGEllipseElement(tagName, document));
54}
55
56void SVGEllipseElement::parseMappedAttribute(Attribute* attr)
57{
58    if (attr->name() == SVGNames::cxAttr)
59        setCxBaseValue(SVGLength(LengthModeWidth, attr->value()));
60    else if (attr->name() == SVGNames::cyAttr)
61        setCyBaseValue(SVGLength(LengthModeHeight, attr->value()));
62    else if (attr->name() == SVGNames::rxAttr) {
63        setRxBaseValue(SVGLength(LengthModeWidth, attr->value()));
64        if (rxBaseValue().value(this) < 0.0)
65            document()->accessSVGExtensions()->reportError("A negative value for ellipse <rx> is not allowed");
66    } else if (attr->name() == SVGNames::ryAttr) {
67        setRyBaseValue(SVGLength(LengthModeHeight, attr->value()));
68        if (ryBaseValue().value(this) < 0.0)
69            document()->accessSVGExtensions()->reportError("A negative value for ellipse <ry> is not allowed");
70    } else {
71        if (SVGTests::parseMappedAttribute(attr))
72            return;
73        if (SVGLangSpace::parseMappedAttribute(attr))
74            return;
75        if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
76            return;
77        SVGStyledTransformableElement::parseMappedAttribute(attr);
78    }
79}
80
81void SVGEllipseElement::svgAttributeChanged(const QualifiedName& attrName)
82{
83    SVGStyledTransformableElement::svgAttributeChanged(attrName);
84
85    bool isLengthAttribute = attrName == SVGNames::cxAttr
86                          || attrName == SVGNames::cyAttr
87                          || attrName == SVGNames::rxAttr
88                          || attrName == SVGNames::ryAttr;
89
90    if (isLengthAttribute)
91        updateRelativeLengthsInformation();
92
93    if (SVGTests::handleAttributeChange(this, attrName))
94        return;
95
96    RenderSVGPath* renderer = static_cast<RenderSVGPath*>(this->renderer());
97    if (!renderer)
98        return;
99
100    if (isLengthAttribute) {
101        renderer->setNeedsPathUpdate();
102        RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
103        return;
104    }
105
106    if (SVGLangSpace::isKnownAttribute(attrName)
107        || SVGExternalResourcesRequired::isKnownAttribute(attrName))
108        RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
109}
110
111void SVGEllipseElement::synchronizeProperty(const QualifiedName& attrName)
112{
113    SVGStyledTransformableElement::synchronizeProperty(attrName);
114
115    if (attrName == anyQName()) {
116        synchronizeCx();
117        synchronizeCy();
118        synchronizeRx();
119        synchronizeRy();
120        synchronizeExternalResourcesRequired();
121        SVGTests::synchronizeProperties(this, attrName);
122        return;
123    }
124
125    if (attrName == SVGNames::cxAttr)
126        synchronizeCx();
127    else if (attrName == SVGNames::cyAttr)
128        synchronizeCy();
129    else if (attrName == SVGNames::rxAttr)
130        synchronizeRx();
131    else if (attrName == SVGNames::ryAttr)
132        synchronizeRy();
133    else if (SVGExternalResourcesRequired::isKnownAttribute(attrName))
134        synchronizeExternalResourcesRequired();
135    else if (SVGTests::isKnownAttribute(attrName))
136        SVGTests::synchronizeProperties(this, attrName);
137}
138
139AttributeToPropertyTypeMap& SVGEllipseElement::attributeToPropertyTypeMap()
140{
141    DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_attributeToPropertyTypeMap, ());
142    return s_attributeToPropertyTypeMap;
143}
144
145void SVGEllipseElement::fillAttributeToPropertyTypeMap()
146{
147    AttributeToPropertyTypeMap& attributeToPropertyTypeMap = this->attributeToPropertyTypeMap();
148
149    SVGStyledTransformableElement::fillPassedAttributeToPropertyTypeMap(attributeToPropertyTypeMap);
150    attributeToPropertyTypeMap.set(SVGNames::cxAttr, AnimatedLength);
151    attributeToPropertyTypeMap.set(SVGNames::cyAttr, AnimatedLength);
152    attributeToPropertyTypeMap.set(SVGNames::rxAttr, AnimatedLength);
153    attributeToPropertyTypeMap.set(SVGNames::ryAttr, AnimatedLength);
154}
155
156void SVGEllipseElement::toPathData(Path& path) const
157{
158    ASSERT(path.isEmpty());
159
160    float radiusX = rx().value(this);
161    if (radiusX <= 0)
162        return;
163
164    float radiusY = ry().value(this);
165    if (radiusY <= 0)
166        return;
167
168    path.addEllipse(FloatRect(cx().value(this) - radiusX, cy().value(this) - radiusY, radiusX * 2, radiusY * 2));
169}
170
171bool SVGEllipseElement::selfHasRelativeLengths() const
172{
173    return cx().isRelative()
174        || cy().isRelative()
175        || rx().isRelative()
176        || ry().isRelative();
177}
178
179}
180
181#endif // ENABLE(SVG)
182