• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/SVGPathElement.h"
24 
25 #include "core/rendering/svg/RenderSVGPath.h"
26 #include "core/rendering/svg/RenderSVGResource.h"
27 #include "core/svg/SVGMPathElement.h"
28 #include "core/svg/SVGPathSegArcAbs.h"
29 #include "core/svg/SVGPathSegArcRel.h"
30 #include "core/svg/SVGPathSegClosePath.h"
31 #include "core/svg/SVGPathSegCurvetoCubicAbs.h"
32 #include "core/svg/SVGPathSegCurvetoCubicRel.h"
33 #include "core/svg/SVGPathSegCurvetoCubicSmoothAbs.h"
34 #include "core/svg/SVGPathSegCurvetoCubicSmoothRel.h"
35 #include "core/svg/SVGPathSegCurvetoQuadraticAbs.h"
36 #include "core/svg/SVGPathSegCurvetoQuadraticRel.h"
37 #include "core/svg/SVGPathSegCurvetoQuadraticSmoothAbs.h"
38 #include "core/svg/SVGPathSegCurvetoQuadraticSmoothRel.h"
39 #include "core/svg/SVGPathSegLinetoAbs.h"
40 #include "core/svg/SVGPathSegLinetoHorizontalAbs.h"
41 #include "core/svg/SVGPathSegLinetoHorizontalRel.h"
42 #include "core/svg/SVGPathSegLinetoRel.h"
43 #include "core/svg/SVGPathSegLinetoVerticalAbs.h"
44 #include "core/svg/SVGPathSegLinetoVerticalRel.h"
45 #include "core/svg/SVGPathSegMovetoAbs.h"
46 #include "core/svg/SVGPathSegMovetoRel.h"
47 #include "core/svg/SVGPathUtilities.h"
48 #include "core/svg/SVGPointTearOff.h"
49 
50 namespace WebCore {
51 
SVGPathElement(Document & document)52 inline SVGPathElement::SVGPathElement(Document& document)
53     : SVGGeometryElement(SVGNames::pathTag, document)
54     , m_pathLength(SVGAnimatedNumber::create(this, SVGNames::pathLengthAttr, SVGNumber::create()))
55     , m_pathSegList(SVGAnimatedPath::create(this, SVGNames::dAttr))
56 {
57     ScriptWrappable::init(this);
58 
59     addToPropertyMap(m_pathLength);
60     addToPropertyMap(m_pathSegList);
61 }
62 
DEFINE_NODE_FACTORY(SVGPathElement)63 DEFINE_NODE_FACTORY(SVGPathElement)
64 
65 float SVGPathElement::getTotalLength()
66 {
67     float totalLength = 0;
68     getTotalLengthOfSVGPathByteStream(pathByteStream(), totalLength);
69     return totalLength;
70 }
71 
getPointAtLength(float length)72 PassRefPtr<SVGPointTearOff> SVGPathElement::getPointAtLength(float length)
73 {
74     FloatPoint point;
75     getPointAtLengthOfSVGPathByteStream(pathByteStream(), length, point);
76     return SVGPointTearOff::create(SVGPoint::create(point), 0, PropertyIsNotAnimVal);
77 }
78 
getPathSegAtLength(float length)79 unsigned SVGPathElement::getPathSegAtLength(float length)
80 {
81     unsigned pathSeg = 0;
82     getSVGPathSegAtLengthFromSVGPathByteStream(pathByteStream(), length, pathSeg);
83     return pathSeg;
84 }
85 
createSVGPathSegClosePath()86 PassRefPtr<SVGPathSegClosePath> SVGPathElement::createSVGPathSegClosePath()
87 {
88     return SVGPathSegClosePath::create(0, PathSegUndefinedRole);
89 }
90 
createSVGPathSegMovetoAbs(float x,float y)91 PassRefPtr<SVGPathSegMovetoAbs> SVGPathElement::createSVGPathSegMovetoAbs(float x, float y)
92 {
93     return SVGPathSegMovetoAbs::create(0, PathSegUndefinedRole, x, y);
94 }
95 
createSVGPathSegMovetoRel(float x,float y)96 PassRefPtr<SVGPathSegMovetoRel> SVGPathElement::createSVGPathSegMovetoRel(float x, float y)
97 {
98     return SVGPathSegMovetoRel::create(0, PathSegUndefinedRole, x, y);
99 }
100 
createSVGPathSegLinetoAbs(float x,float y)101 PassRefPtr<SVGPathSegLinetoAbs> SVGPathElement::createSVGPathSegLinetoAbs(float x, float y)
102 {
103     return SVGPathSegLinetoAbs::create(0, PathSegUndefinedRole, x, y);
104 }
105 
createSVGPathSegLinetoRel(float x,float y)106 PassRefPtr<SVGPathSegLinetoRel> SVGPathElement::createSVGPathSegLinetoRel(float x, float y)
107 {
108     return SVGPathSegLinetoRel::create(0, PathSegUndefinedRole, x, y);
109 }
110 
createSVGPathSegCurvetoCubicAbs(float x,float y,float x1,float y1,float x2,float y2)111 PassRefPtr<SVGPathSegCurvetoCubicAbs> SVGPathElement::createSVGPathSegCurvetoCubicAbs(float x, float y, float x1, float y1, float x2, float y2)
112 {
113     return SVGPathSegCurvetoCubicAbs::create(0, PathSegUndefinedRole, x, y, x1, y1, x2, y2);
114 }
115 
createSVGPathSegCurvetoCubicRel(float x,float y,float x1,float y1,float x2,float y2)116 PassRefPtr<SVGPathSegCurvetoCubicRel> SVGPathElement::createSVGPathSegCurvetoCubicRel(float x, float y, float x1, float y1, float x2, float y2)
117 {
118     return SVGPathSegCurvetoCubicRel::create(0, PathSegUndefinedRole, x, y, x1, y1, x2, y2);
119 }
120 
createSVGPathSegCurvetoQuadraticAbs(float x,float y,float x1,float y1)121 PassRefPtr<SVGPathSegCurvetoQuadraticAbs> SVGPathElement::createSVGPathSegCurvetoQuadraticAbs(float x, float y, float x1, float y1)
122 {
123     return SVGPathSegCurvetoQuadraticAbs::create(0, PathSegUndefinedRole, x, y, x1, y1);
124 }
125 
createSVGPathSegCurvetoQuadraticRel(float x,float y,float x1,float y1)126 PassRefPtr<SVGPathSegCurvetoQuadraticRel> SVGPathElement::createSVGPathSegCurvetoQuadraticRel(float x, float y, float x1, float y1)
127 {
128     return SVGPathSegCurvetoQuadraticRel::create(0, PathSegUndefinedRole, x, y, x1, y1);
129 }
130 
createSVGPathSegArcAbs(float x,float y,float r1,float r2,float angle,bool largeArcFlag,bool sweepFlag)131 PassRefPtr<SVGPathSegArcAbs> SVGPathElement::createSVGPathSegArcAbs(float x, float y, float r1, float r2, float angle, bool largeArcFlag, bool sweepFlag)
132 {
133     return SVGPathSegArcAbs::create(0, PathSegUndefinedRole, x, y, r1, r2, angle, largeArcFlag, sweepFlag);
134 }
135 
createSVGPathSegArcRel(float x,float y,float r1,float r2,float angle,bool largeArcFlag,bool sweepFlag)136 PassRefPtr<SVGPathSegArcRel> SVGPathElement::createSVGPathSegArcRel(float x, float y, float r1, float r2, float angle, bool largeArcFlag, bool sweepFlag)
137 {
138     return SVGPathSegArcRel::create(0, PathSegUndefinedRole, x, y, r1, r2, angle, largeArcFlag, sweepFlag);
139 }
140 
createSVGPathSegLinetoHorizontalAbs(float x)141 PassRefPtr<SVGPathSegLinetoHorizontalAbs> SVGPathElement::createSVGPathSegLinetoHorizontalAbs(float x)
142 {
143     return SVGPathSegLinetoHorizontalAbs::create(0, PathSegUndefinedRole, x);
144 }
145 
createSVGPathSegLinetoHorizontalRel(float x)146 PassRefPtr<SVGPathSegLinetoHorizontalRel> SVGPathElement::createSVGPathSegLinetoHorizontalRel(float x)
147 {
148     return SVGPathSegLinetoHorizontalRel::create(0, PathSegUndefinedRole, x);
149 }
150 
createSVGPathSegLinetoVerticalAbs(float y)151 PassRefPtr<SVGPathSegLinetoVerticalAbs> SVGPathElement::createSVGPathSegLinetoVerticalAbs(float y)
152 {
153     return SVGPathSegLinetoVerticalAbs::create(0, PathSegUndefinedRole, y);
154 }
155 
createSVGPathSegLinetoVerticalRel(float y)156 PassRefPtr<SVGPathSegLinetoVerticalRel> SVGPathElement::createSVGPathSegLinetoVerticalRel(float y)
157 {
158     return SVGPathSegLinetoVerticalRel::create(0, PathSegUndefinedRole, y);
159 }
160 
createSVGPathSegCurvetoCubicSmoothAbs(float x,float y,float x2,float y2)161 PassRefPtr<SVGPathSegCurvetoCubicSmoothAbs> SVGPathElement::createSVGPathSegCurvetoCubicSmoothAbs(float x, float y, float x2, float y2)
162 {
163     return SVGPathSegCurvetoCubicSmoothAbs::create(0, PathSegUndefinedRole, x, y, x2, y2);
164 }
165 
createSVGPathSegCurvetoCubicSmoothRel(float x,float y,float x2,float y2)166 PassRefPtr<SVGPathSegCurvetoCubicSmoothRel> SVGPathElement::createSVGPathSegCurvetoCubicSmoothRel(float x, float y, float x2, float y2)
167 {
168     return SVGPathSegCurvetoCubicSmoothRel::create(0, PathSegUndefinedRole, x, y, x2, y2);
169 }
170 
createSVGPathSegCurvetoQuadraticSmoothAbs(float x,float y)171 PassRefPtr<SVGPathSegCurvetoQuadraticSmoothAbs> SVGPathElement::createSVGPathSegCurvetoQuadraticSmoothAbs(float x, float y)
172 {
173     return SVGPathSegCurvetoQuadraticSmoothAbs::create(0, PathSegUndefinedRole, x, y);
174 }
175 
createSVGPathSegCurvetoQuadraticSmoothRel(float x,float y)176 PassRefPtr<SVGPathSegCurvetoQuadraticSmoothRel> SVGPathElement::createSVGPathSegCurvetoQuadraticSmoothRel(float x, float y)
177 {
178     return SVGPathSegCurvetoQuadraticSmoothRel::create(0, PathSegUndefinedRole, x, y);
179 }
180 
isSupportedAttribute(const QualifiedName & attrName)181 bool SVGPathElement::isSupportedAttribute(const QualifiedName& attrName)
182 {
183     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
184     if (supportedAttributes.isEmpty()) {
185         supportedAttributes.add(SVGNames::dAttr);
186         supportedAttributes.add(SVGNames::pathLengthAttr);
187     }
188     return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
189 }
190 
parseAttribute(const QualifiedName & name,const AtomicString & value)191 void SVGPathElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
192 {
193     if (!isSupportedAttribute(name)) {
194         SVGGeometryElement::parseAttribute(name, value);
195         return;
196     }
197 
198     SVGParsingError parseError = NoError;
199 
200     if (name == SVGNames::dAttr) {
201         m_pathSegList->setBaseValueAsString(value, parseError);
202     } else if (name == SVGNames::pathLengthAttr) {
203         m_pathLength->setBaseValueAsString(value, parseError);
204         if (parseError == NoError && m_pathLength->baseValue()->value() < 0)
205             document().accessSVGExtensions().reportError("A negative value for path attribute <pathLength> is not allowed");
206     } else {
207         ASSERT_NOT_REACHED();
208     }
209 
210     reportAttributeParsingError(parseError, name, value);
211 }
212 
svgAttributeChanged(const QualifiedName & attrName)213 void SVGPathElement::svgAttributeChanged(const QualifiedName& attrName)
214 {
215     if (!isSupportedAttribute(attrName)) {
216         SVGGeometryElement::svgAttributeChanged(attrName);
217         return;
218     }
219 
220     SVGElement::InvalidationGuard invalidationGuard(this);
221 
222     RenderSVGPath* renderer = toRenderSVGPath(this->renderer());
223 
224     if (attrName == SVGNames::dAttr) {
225         if (renderer)
226             renderer->setNeedsShapeUpdate();
227 
228         invalidateMPathDependencies();
229     }
230 
231     if (renderer)
232         RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
233 }
234 
invalidateMPathDependencies()235 void SVGPathElement::invalidateMPathDependencies()
236 {
237     // <mpath> can only reference <path> but this dependency is not handled in
238     // markForLayoutAndParentResourceInvalidation so we update any mpath dependencies manually.
239     if (SVGElementSet* dependencies = document().accessSVGExtensions().setOfElementsReferencingTarget(this)) {
240         SVGElementSet::iterator end = dependencies->end();
241         for (SVGElementSet::iterator it = dependencies->begin(); it != end; ++it) {
242             if (isSVGMPathElement(**it))
243                 toSVGMPathElement(*it)->targetPathChanged();
244         }
245     }
246 }
247 
insertedInto(ContainerNode * rootParent)248 Node::InsertionNotificationRequest SVGPathElement::insertedInto(ContainerNode* rootParent)
249 {
250     SVGGeometryElement::insertedInto(rootParent);
251     invalidateMPathDependencies();
252     return InsertionDone;
253 }
254 
removedFrom(ContainerNode * rootParent)255 void SVGPathElement::removedFrom(ContainerNode* rootParent)
256 {
257     SVGGeometryElement::removedFrom(rootParent);
258     invalidateMPathDependencies();
259 }
260 
pathSegListChanged(ListModification listModification)261 void SVGPathElement::pathSegListChanged(ListModification listModification)
262 {
263     m_pathSegList->baseValue()->clearByteStream();
264 
265     invalidateSVGAttributes();
266 
267     RenderSVGPath* renderer = toRenderSVGPath(this->renderer());
268     if (!renderer)
269         return;
270 
271     renderer->setNeedsShapeUpdate();
272     RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
273 }
274 
getBBox()275 FloatRect SVGPathElement::getBBox()
276 {
277     // By default, getBBox() returns objectBoundingBox but that will include
278     // markers so we override it to return just the path's bounding rect.
279 
280     document().updateLayoutIgnorePendingStylesheets();
281 
282     // FIXME: Eventually we should support getBBox for detached elements.
283     if (!renderer())
284         return FloatRect();
285 
286     RenderSVGPath* renderer = toRenderSVGPath(this->renderer());
287     return renderer->path().boundingRect();
288 }
289 
290 }
291