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 #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 50 namespace blink { 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 addToPropertyMap(m_pathLength); 58 addToPropertyMap(m_pathSegList); 59 } 60 61 DEFINE_NODE_FACTORY(SVGPathElement) 62 63 float SVGPathElement::getTotalLength() 64 { 65 float totalLength = 0; 66 getTotalLengthOfSVGPathByteStream(pathByteStream(), totalLength); 67 return totalLength; 68 } 69 70 PassRefPtr<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 77 unsigned SVGPathElement::getPathSegAtLength(float length) 78 { 79 unsigned pathSeg = 0; 80 getSVGPathSegAtLengthFromSVGPathByteStream(pathByteStream(), length, pathSeg); 81 return pathSeg; 82 } 83 84 PassRefPtr<SVGPathSegClosePath> SVGPathElement::createSVGPathSegClosePath() 85 { 86 return SVGPathSegClosePath::create(0); 87 } 88 89 PassRefPtr<SVGPathSegMovetoAbs> SVGPathElement::createSVGPathSegMovetoAbs(float x, float y) 90 { 91 return SVGPathSegMovetoAbs::create(0, x, y); 92 } 93 94 PassRefPtr<SVGPathSegMovetoRel> SVGPathElement::createSVGPathSegMovetoRel(float x, float y) 95 { 96 return SVGPathSegMovetoRel::create(0, x, y); 97 } 98 99 PassRefPtr<SVGPathSegLinetoAbs> SVGPathElement::createSVGPathSegLinetoAbs(float x, float y) 100 { 101 return SVGPathSegLinetoAbs::create(0, x, y); 102 } 103 104 PassRefPtr<SVGPathSegLinetoRel> SVGPathElement::createSVGPathSegLinetoRel(float x, float y) 105 { 106 return SVGPathSegLinetoRel::create(0, x, y); 107 } 108 109 PassRefPtr<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 114 PassRefPtr<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 119 PassRefPtr<SVGPathSegCurvetoQuadraticAbs> SVGPathElement::createSVGPathSegCurvetoQuadraticAbs(float x, float y, float x1, float y1) 120 { 121 return SVGPathSegCurvetoQuadraticAbs::create(0, x, y, x1, y1); 122 } 123 124 PassRefPtr<SVGPathSegCurvetoQuadraticRel> SVGPathElement::createSVGPathSegCurvetoQuadraticRel(float x, float y, float x1, float y1) 125 { 126 return SVGPathSegCurvetoQuadraticRel::create(0, x, y, x1, y1); 127 } 128 129 PassRefPtr<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 134 PassRefPtr<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 139 PassRefPtr<SVGPathSegLinetoHorizontalAbs> SVGPathElement::createSVGPathSegLinetoHorizontalAbs(float x) 140 { 141 return SVGPathSegLinetoHorizontalAbs::create(0, x); 142 } 143 144 PassRefPtr<SVGPathSegLinetoHorizontalRel> SVGPathElement::createSVGPathSegLinetoHorizontalRel(float x) 145 { 146 return SVGPathSegLinetoHorizontalRel::create(0, x); 147 } 148 149 PassRefPtr<SVGPathSegLinetoVerticalAbs> SVGPathElement::createSVGPathSegLinetoVerticalAbs(float y) 150 { 151 return SVGPathSegLinetoVerticalAbs::create(0, y); 152 } 153 154 PassRefPtr<SVGPathSegLinetoVerticalRel> SVGPathElement::createSVGPathSegLinetoVerticalRel(float y) 155 { 156 return SVGPathSegLinetoVerticalRel::create(0, y); 157 } 158 159 PassRefPtr<SVGPathSegCurvetoCubicSmoothAbs> SVGPathElement::createSVGPathSegCurvetoCubicSmoothAbs(float x, float y, float x2, float y2) 160 { 161 return SVGPathSegCurvetoCubicSmoothAbs::create(0, x, y, x2, y2); 162 } 163 164 PassRefPtr<SVGPathSegCurvetoCubicSmoothRel> SVGPathElement::createSVGPathSegCurvetoCubicSmoothRel(float x, float y, float x2, float y2) 165 { 166 return SVGPathSegCurvetoCubicSmoothRel::create(0, x, y, x2, y2); 167 } 168 169 PassRefPtr<SVGPathSegCurvetoQuadraticSmoothAbs> SVGPathElement::createSVGPathSegCurvetoQuadraticSmoothAbs(float x, float y) 170 { 171 return SVGPathSegCurvetoQuadraticSmoothAbs::create(0, x, y); 172 } 173 174 PassRefPtr<SVGPathSegCurvetoQuadraticSmoothRel> SVGPathElement::createSVGPathSegCurvetoQuadraticSmoothRel(float x, float y) 175 { 176 return SVGPathSegCurvetoQuadraticSmoothRel::create(0, x, y); 177 } 178 179 bool 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 189 void 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 211 void 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 233 void 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 246 Node::InsertionNotificationRequest SVGPathElement::insertedInto(ContainerNode* rootParent) 247 { 248 SVGGeometryElement::insertedInto(rootParent); 249 invalidateMPathDependencies(); 250 return InsertionDone; 251 } 252 253 void SVGPathElement::removedFrom(ContainerNode* rootParent) 254 { 255 SVGGeometryElement::removedFrom(rootParent); 256 invalidateMPathDependencies(); 257 } 258 259 void 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 273 FloatRect 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