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 #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