1 /* 2 * Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <zimmermann (at) kde.org> 3 * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis (at) 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 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 63 DEFINE_NODE_FACTORY(SVGPathElement) 64 65 float SVGPathElement::getTotalLength() 66 { 67 float totalLength = 0; 68 getTotalLengthOfSVGPathByteStream(pathByteStream(), totalLength); 69 return totalLength; 70 } 71 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 79 unsigned SVGPathElement::getPathSegAtLength(float length) 80 { 81 unsigned pathSeg = 0; 82 getSVGPathSegAtLengthFromSVGPathByteStream(pathByteStream(), length, pathSeg); 83 return pathSeg; 84 } 85 86 PassRefPtr<SVGPathSegClosePath> SVGPathElement::createSVGPathSegClosePath() 87 { 88 return SVGPathSegClosePath::create(0, PathSegUndefinedRole); 89 } 90 91 PassRefPtr<SVGPathSegMovetoAbs> SVGPathElement::createSVGPathSegMovetoAbs(float x, float y) 92 { 93 return SVGPathSegMovetoAbs::create(0, PathSegUndefinedRole, x, y); 94 } 95 96 PassRefPtr<SVGPathSegMovetoRel> SVGPathElement::createSVGPathSegMovetoRel(float x, float y) 97 { 98 return SVGPathSegMovetoRel::create(0, PathSegUndefinedRole, x, y); 99 } 100 101 PassRefPtr<SVGPathSegLinetoAbs> SVGPathElement::createSVGPathSegLinetoAbs(float x, float y) 102 { 103 return SVGPathSegLinetoAbs::create(0, PathSegUndefinedRole, x, y); 104 } 105 106 PassRefPtr<SVGPathSegLinetoRel> SVGPathElement::createSVGPathSegLinetoRel(float x, float y) 107 { 108 return SVGPathSegLinetoRel::create(0, PathSegUndefinedRole, x, y); 109 } 110 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 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 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 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 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 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 141 PassRefPtr<SVGPathSegLinetoHorizontalAbs> SVGPathElement::createSVGPathSegLinetoHorizontalAbs(float x) 142 { 143 return SVGPathSegLinetoHorizontalAbs::create(0, PathSegUndefinedRole, x); 144 } 145 146 PassRefPtr<SVGPathSegLinetoHorizontalRel> SVGPathElement::createSVGPathSegLinetoHorizontalRel(float x) 147 { 148 return SVGPathSegLinetoHorizontalRel::create(0, PathSegUndefinedRole, x); 149 } 150 151 PassRefPtr<SVGPathSegLinetoVerticalAbs> SVGPathElement::createSVGPathSegLinetoVerticalAbs(float y) 152 { 153 return SVGPathSegLinetoVerticalAbs::create(0, PathSegUndefinedRole, y); 154 } 155 156 PassRefPtr<SVGPathSegLinetoVerticalRel> SVGPathElement::createSVGPathSegLinetoVerticalRel(float y) 157 { 158 return SVGPathSegLinetoVerticalRel::create(0, PathSegUndefinedRole, y); 159 } 160 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 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 171 PassRefPtr<SVGPathSegCurvetoQuadraticSmoothAbs> SVGPathElement::createSVGPathSegCurvetoQuadraticSmoothAbs(float x, float y) 172 { 173 return SVGPathSegCurvetoQuadraticSmoothAbs::create(0, PathSegUndefinedRole, x, y); 174 } 175 176 PassRefPtr<SVGPathSegCurvetoQuadraticSmoothRel> SVGPathElement::createSVGPathSegCurvetoQuadraticSmoothRel(float x, float y) 177 { 178 return SVGPathSegCurvetoQuadraticSmoothRel::create(0, PathSegUndefinedRole, x, y); 179 } 180 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 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 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 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 248 Node::InsertionNotificationRequest SVGPathElement::insertedInto(ContainerNode* rootParent) 249 { 250 SVGGeometryElement::insertedInto(rootParent); 251 invalidateMPathDependencies(); 252 return InsertionDone; 253 } 254 255 void SVGPathElement::removedFrom(ContainerNode* rootParent) 256 { 257 SVGGeometryElement::removedFrom(rootParent); 258 invalidateMPathDependencies(); 259 } 260 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 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