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