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 #if ENABLE(SVG)
     24 #include "SVGPathElement.h"
     25 
     26 #include "Attribute.h"
     27 #include "RenderSVGPath.h"
     28 #include "RenderSVGResource.h"
     29 #include "SVGNames.h"
     30 #include "SVGPathParserFactory.h"
     31 #include "SVGPathSegArc.h"
     32 #include "SVGPathSegClosePath.h"
     33 #include "SVGPathSegCurvetoCubic.h"
     34 #include "SVGPathSegCurvetoCubicSmooth.h"
     35 #include "SVGPathSegCurvetoQuadratic.h"
     36 #include "SVGPathSegCurvetoQuadraticSmooth.h"
     37 #include "SVGPathSegLineto.h"
     38 #include "SVGPathSegLinetoHorizontal.h"
     39 #include "SVGPathSegLinetoVertical.h"
     40 #include "SVGPathSegList.h"
     41 #include "SVGPathSegListBuilder.h"
     42 #include "SVGPathSegListPropertyTearOff.h"
     43 #include "SVGPathSegMoveto.h"
     44 #include "SVGSVGElement.h"
     45 
     46 namespace WebCore {
     47 
     48 // Animated property definitions
     49 DEFINE_ANIMATED_NUMBER(SVGPathElement, SVGNames::pathLengthAttr, PathLength, pathLength)
     50 DEFINE_ANIMATED_BOOLEAN(SVGPathElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
     51 
     52 inline SVGPathElement::SVGPathElement(const QualifiedName& tagName, Document* document)
     53     : SVGStyledTransformableElement(tagName, document)
     54     , m_pathByteStream(SVGPathByteStream::create())
     55     , m_pathSegList(PathSegUnalteredRole)
     56 {
     57 }
     58 
     59 PassRefPtr<SVGPathElement> SVGPathElement::create(const QualifiedName& tagName, Document* document)
     60 {
     61     return adoptRef(new SVGPathElement(tagName, document));
     62 }
     63 
     64 float SVGPathElement::getTotalLength()
     65 {
     66     // FIXME: this may wish to use the pathSegList instead of the pathdata if that's cheaper to build (or cached)
     67     Path path;
     68     toPathData(path);
     69     return path.length();
     70 }
     71 
     72 FloatPoint SVGPathElement::getPointAtLength(float length)
     73 {
     74     // FIXME: this may wish to use the pathSegList instead of the pathdata if that's cheaper to build (or cached)
     75     bool ok = false;
     76     Path path;
     77     toPathData(path);
     78     return path.pointAtLength(length, ok);
     79 }
     80 
     81 unsigned long SVGPathElement::getPathSegAtLength(float length)
     82 {
     83     SVGPathParserFactory* factory = SVGPathParserFactory::self();
     84     unsigned long pathSeg = 0;
     85     factory->getSVGPathSegAtLengthFromSVGPathByteStream(m_pathByteStream.get(), length, pathSeg);
     86     return pathSeg;
     87 }
     88 
     89 PassRefPtr<SVGPathSegClosePath> SVGPathElement::createSVGPathSegClosePath(SVGPathSegRole role)
     90 {
     91     return SVGPathSegClosePath::create(this, role);
     92 }
     93 
     94 PassRefPtr<SVGPathSegMovetoAbs> SVGPathElement::createSVGPathSegMovetoAbs(float x, float y, SVGPathSegRole role)
     95 {
     96     return SVGPathSegMovetoAbs::create(this, role, x, y);
     97 }
     98 
     99 PassRefPtr<SVGPathSegMovetoRel> SVGPathElement::createSVGPathSegMovetoRel(float x, float y, SVGPathSegRole role)
    100 {
    101     return SVGPathSegMovetoRel::create(this, role, x, y);
    102 }
    103 
    104 PassRefPtr<SVGPathSegLinetoAbs> SVGPathElement::createSVGPathSegLinetoAbs(float x, float y, SVGPathSegRole role)
    105 {
    106     return SVGPathSegLinetoAbs::create(this, role, x, y);
    107 }
    108 
    109 PassRefPtr<SVGPathSegLinetoRel> SVGPathElement::createSVGPathSegLinetoRel(float x, float y, SVGPathSegRole role)
    110 {
    111     return SVGPathSegLinetoRel::create(this, role, x, y);
    112 }
    113 
    114 PassRefPtr<SVGPathSegCurvetoCubicAbs> SVGPathElement::createSVGPathSegCurvetoCubicAbs(float x, float y, float x1, float y1, float x2, float y2, SVGPathSegRole role)
    115 {
    116     return SVGPathSegCurvetoCubicAbs::create(this, role, x, y, x1, y1, x2, y2);
    117 }
    118 
    119 PassRefPtr<SVGPathSegCurvetoCubicRel> SVGPathElement::createSVGPathSegCurvetoCubicRel(float x, float y, float x1, float y1, float x2, float y2, SVGPathSegRole role)
    120 {
    121     return SVGPathSegCurvetoCubicRel::create(this, role, x, y, x1, y1, x2, y2);
    122 }
    123 
    124 PassRefPtr<SVGPathSegCurvetoQuadraticAbs> SVGPathElement::createSVGPathSegCurvetoQuadraticAbs(float x, float y, float x1, float y1, SVGPathSegRole role)
    125 {
    126     return SVGPathSegCurvetoQuadraticAbs::create(this, role, x, y, x1, y1);
    127 }
    128 
    129 PassRefPtr<SVGPathSegCurvetoQuadraticRel> SVGPathElement::createSVGPathSegCurvetoQuadraticRel(float x, float y, float x1, float y1, SVGPathSegRole role)
    130 {
    131     return SVGPathSegCurvetoQuadraticRel::create(this, role, x, y, x1, y1);
    132 }
    133 
    134 PassRefPtr<SVGPathSegArcAbs> SVGPathElement::createSVGPathSegArcAbs(float x, float y, float r1, float r2, float angle, bool largeArcFlag, bool sweepFlag, SVGPathSegRole role)
    135 {
    136     return SVGPathSegArcAbs::create(this, role, x, y, r1, r2, angle, largeArcFlag, sweepFlag);
    137 }
    138 
    139 PassRefPtr<SVGPathSegArcRel> SVGPathElement::createSVGPathSegArcRel(float x, float y, float r1, float r2, float angle, bool largeArcFlag, bool sweepFlag, SVGPathSegRole role)
    140 {
    141     return SVGPathSegArcRel::create(this, role, x, y, r1, r2, angle, largeArcFlag, sweepFlag);
    142 }
    143 
    144 PassRefPtr<SVGPathSegLinetoHorizontalAbs> SVGPathElement::createSVGPathSegLinetoHorizontalAbs(float x, SVGPathSegRole role)
    145 {
    146     return SVGPathSegLinetoHorizontalAbs::create(this, role, x);
    147 }
    148 
    149 PassRefPtr<SVGPathSegLinetoHorizontalRel> SVGPathElement::createSVGPathSegLinetoHorizontalRel(float x, SVGPathSegRole role)
    150 {
    151     return SVGPathSegLinetoHorizontalRel::create(this, role, x);
    152 }
    153 
    154 PassRefPtr<SVGPathSegLinetoVerticalAbs> SVGPathElement::createSVGPathSegLinetoVerticalAbs(float y, SVGPathSegRole role)
    155 {
    156     return SVGPathSegLinetoVerticalAbs::create(this, role, y);
    157 }
    158 
    159 PassRefPtr<SVGPathSegLinetoVerticalRel> SVGPathElement::createSVGPathSegLinetoVerticalRel(float y, SVGPathSegRole role)
    160 {
    161     return SVGPathSegLinetoVerticalRel::create(this, role, y);
    162 }
    163 
    164 PassRefPtr<SVGPathSegCurvetoCubicSmoothAbs> SVGPathElement::createSVGPathSegCurvetoCubicSmoothAbs(float x, float y, float x2, float y2, SVGPathSegRole role)
    165 {
    166     return SVGPathSegCurvetoCubicSmoothAbs::create(this, role, x, y, x2, y2);
    167 }
    168 
    169 PassRefPtr<SVGPathSegCurvetoCubicSmoothRel> SVGPathElement::createSVGPathSegCurvetoCubicSmoothRel(float x, float y, float x2, float y2, SVGPathSegRole role)
    170 {
    171     return SVGPathSegCurvetoCubicSmoothRel::create(this, role, x, y, x2, y2);
    172 }
    173 
    174 PassRefPtr<SVGPathSegCurvetoQuadraticSmoothAbs> SVGPathElement::createSVGPathSegCurvetoQuadraticSmoothAbs(float x, float y, SVGPathSegRole role)
    175 {
    176     return SVGPathSegCurvetoQuadraticSmoothAbs::create(this, role, x, y);
    177 }
    178 
    179 PassRefPtr<SVGPathSegCurvetoQuadraticSmoothRel> SVGPathElement::createSVGPathSegCurvetoQuadraticSmoothRel(float x, float y, SVGPathSegRole role)
    180 {
    181     return SVGPathSegCurvetoQuadraticSmoothRel::create(this, role, x, y);
    182 }
    183 
    184 void SVGPathElement::parseMappedAttribute(Attribute* attr)
    185 {
    186     if (attr->name() == SVGNames::dAttr) {
    187         SVGPathParserFactory* factory = SVGPathParserFactory::self();
    188         if (!factory->buildSVGPathByteStreamFromString(attr->value(), m_pathByteStream, UnalteredParsing))
    189             document()->accessSVGExtensions()->reportError("Problem parsing d=\"" + attr->value() + "\"");
    190     } else if (attr->name() == SVGNames::pathLengthAttr) {
    191         setPathLengthBaseValue(attr->value().toFloat());
    192         if (pathLengthBaseValue() < 0.0f)
    193             document()->accessSVGExtensions()->reportError("A negative value for path attribute <pathLength> is not allowed");
    194     } else {
    195         if (SVGTests::parseMappedAttribute(attr))
    196             return;
    197         if (SVGLangSpace::parseMappedAttribute(attr))
    198             return;
    199         if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
    200             return;
    201         SVGStyledTransformableElement::parseMappedAttribute(attr);
    202     }
    203 }
    204 
    205 void SVGPathElement::svgAttributeChanged(const QualifiedName& attrName)
    206 {
    207     SVGStyledTransformableElement::svgAttributeChanged(attrName);
    208 
    209     if (SVGTests::handleAttributeChange(this, attrName))
    210         return;
    211 
    212     RenderSVGPath* renderer = static_cast<RenderSVGPath*>(this->renderer());
    213 
    214     if (attrName == SVGNames::dAttr) {
    215         if (m_animatablePathSegList) {
    216             SVGPathSegList newList(PathSegUnalteredRole);
    217             SVGPathParserFactory* factory = SVGPathParserFactory::self();
    218             factory->buildSVGPathSegListFromByteStream(m_pathByteStream.get(), this, newList, UnalteredParsing);
    219             m_pathSegList.value = newList;
    220         }
    221 
    222         if (!renderer)
    223             return;
    224 
    225         renderer->setNeedsPathUpdate();
    226         RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
    227         return;
    228     }
    229 
    230     if (!renderer)
    231         return;
    232 
    233     if (attrName == SVGNames::pathLengthAttr
    234         || SVGLangSpace::isKnownAttribute(attrName)
    235         || SVGExternalResourcesRequired::isKnownAttribute(attrName))
    236         RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
    237 }
    238 
    239 void SVGPathElement::synchronizeProperty(const QualifiedName& attrName)
    240 {
    241     SVGStyledTransformableElement::synchronizeProperty(attrName);
    242 
    243     if (attrName == anyQName()) {
    244         synchronizeD();
    245         synchronizePathLength();
    246         synchronizeExternalResourcesRequired();
    247         SVGTests::synchronizeProperties(this, attrName);
    248         return;
    249     }
    250 
    251     if (attrName == SVGNames::dAttr)
    252         synchronizeD();
    253     else if (attrName == SVGNames::pathLengthAttr)
    254         synchronizePathLength();
    255     else if (SVGExternalResourcesRequired::isKnownAttribute(attrName))
    256         synchronizeExternalResourcesRequired();
    257     else if (SVGTests::isKnownAttribute(attrName))
    258         SVGTests::synchronizeProperties(this, attrName);
    259 }
    260 
    261 void SVGPathElement::synchronizeD()
    262 {
    263     if (!m_pathSegList.shouldSynchronize)
    264         return;
    265 
    266     SVGAnimatedPropertySynchronizer<true>::synchronize(this, SVGNames::dAttr, m_pathSegList.value.valueAsString());
    267 }
    268 
    269 AttributeToPropertyTypeMap& SVGPathElement::attributeToPropertyTypeMap()
    270 {
    271     DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_attributeToPropertyTypeMap, ());
    272     return s_attributeToPropertyTypeMap;
    273 }
    274 
    275 void SVGPathElement::fillAttributeToPropertyTypeMap()
    276 {
    277     AttributeToPropertyTypeMap& attributeToPropertyTypeMap = this->attributeToPropertyTypeMap();
    278 
    279     SVGStyledTransformableElement::fillPassedAttributeToPropertyTypeMap(attributeToPropertyTypeMap);
    280     attributeToPropertyTypeMap.set(SVGNames::dAttr, AnimatedPath);
    281     attributeToPropertyTypeMap.set(SVGNames::pathLengthAttr, AnimatedNumber);
    282 }
    283 
    284 SVGPathSegListPropertyTearOff* SVGPathElement::pathSegList()
    285 {
    286     if (!m_animatablePathSegList) {
    287         m_pathSegList.shouldSynchronize = true;
    288 
    289         SVGPathParserFactory* factory = SVGPathParserFactory::self();
    290         factory->buildSVGPathSegListFromByteStream(m_pathByteStream.get(), this, m_pathSegList.value, UnalteredParsing);
    291 
    292         m_animatablePathSegList = SVGAnimatedProperty::lookupOrCreateWrapper<SVGAnimatedPathSegListPropertyTearOff, SVGPathSegList>
    293                                  (this, SVGNames::dAttr, SVGNames::dAttr.localName(), m_pathSegList.value);
    294     }
    295 
    296     return static_cast<SVGPathSegListPropertyTearOff*>(m_animatablePathSegList->baseVal(PathSegUnalteredRole));
    297 }
    298 
    299 SVGPathSegListPropertyTearOff* SVGPathElement::normalizedPathSegList()
    300 {
    301     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=15412 - Implement normalized path segment lists!
    302     return 0;
    303 }
    304 
    305 SVGPathSegListPropertyTearOff* SVGPathElement::animatedPathSegList()
    306 {
    307     if (!m_animatablePathSegList) {
    308         m_pathSegList.shouldSynchronize = true;
    309 
    310         SVGPathParserFactory* factory = SVGPathParserFactory::self();
    311         factory->buildSVGPathSegListFromByteStream(m_pathByteStream.get(), this, m_pathSegList.value, UnalteredParsing);
    312 
    313         m_animatablePathSegList = SVGAnimatedProperty::lookupOrCreateWrapper<SVGAnimatedPathSegListPropertyTearOff, SVGPathSegList>
    314                                  (this, SVGNames::dAttr, SVGNames::dAttr.localName(), m_pathSegList.value);
    315     }
    316 
    317     return static_cast<SVGPathSegListPropertyTearOff*>(m_animatablePathSegList->animVal(PathSegUnalteredRole));
    318 }
    319 
    320 SVGPathSegListPropertyTearOff* SVGPathElement::animatedNormalizedPathSegList()
    321 {
    322     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=15412 - Implement normalized path segment lists!
    323     return 0;
    324 }
    325 
    326 void SVGPathElement::toPathData(Path& path) const
    327 {
    328     ASSERT(path.isEmpty());
    329 
    330     SVGPathParserFactory* factory = SVGPathParserFactory::self();
    331     factory->buildPathFromByteStream(m_pathByteStream.get(), path);
    332 }
    333 
    334 void SVGPathElement::pathSegListChanged(SVGPathSegRole role)
    335 {
    336     SVGPathParserFactory* factory = SVGPathParserFactory::self();
    337 
    338     switch (role) {
    339     case PathSegNormalizedRole:
    340         // FIXME: https://bugs.webkit.org/show_bug.cgi?id=15412 - Implement normalized path segment lists!
    341         break;
    342     case PathSegUnalteredRole:
    343         m_pathByteStream->clear();
    344         factory->buildSVGPathByteStreamFromSVGPathSegList(m_pathSegList.value, m_pathByteStream, UnalteredParsing);
    345         break;
    346     case PathSegUndefinedRole:
    347         return;
    348     }
    349 
    350     invalidateSVGAttributes();
    351 
    352     RenderSVGPath* renderer = static_cast<RenderSVGPath*>(this->renderer());
    353     if (!renderer)
    354         return;
    355 
    356     renderer->setNeedsPathUpdate();
    357     RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
    358 }
    359 
    360 }
    361 
    362 #endif // ENABLE(SVG)
    363