Home | History | Annotate | Download | only in svg
      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