Replace PassRef with Ref/Ref&& across the board.
[WebKit-https.git] / Source / WebCore / svg / SVGPathElement.cpp
index 598d207..34d6326 100644 (file)
  */
 
 #include "config.h"
-
-#if ENABLE(SVG)
 #include "SVGPathElement.h"
 
 #include "Attribute.h"
 #include "RenderSVGPath.h"
 #include "RenderSVGResource.h"
+#include "SVGElementInstance.h"
+#include "SVGMPathElement.h"
 #include "SVGNames.h"
-#include "SVGPathParserFactory.h"
-#include "SVGPathSegArc.h"
+#include "SVGPathSegArcAbs.h"
+#include "SVGPathSegArcRel.h"
 #include "SVGPathSegClosePath.h"
-#include "SVGPathSegCurvetoCubic.h"
-#include "SVGPathSegCurvetoCubicSmooth.h"
-#include "SVGPathSegCurvetoQuadratic.h"
-#include "SVGPathSegCurvetoQuadraticSmooth.h"
-#include "SVGPathSegLineto.h"
-#include "SVGPathSegLinetoHorizontal.h"
-#include "SVGPathSegLinetoVertical.h"
+#include "SVGPathSegCurvetoCubicAbs.h"
+#include "SVGPathSegCurvetoCubicRel.h"
+#include "SVGPathSegCurvetoCubicSmoothAbs.h"
+#include "SVGPathSegCurvetoCubicSmoothRel.h"
+#include "SVGPathSegCurvetoQuadraticAbs.h"
+#include "SVGPathSegCurvetoQuadraticRel.h"
+#include "SVGPathSegCurvetoQuadraticSmoothAbs.h"
+#include "SVGPathSegCurvetoQuadraticSmoothRel.h"
+#include "SVGPathSegLinetoAbs.h"
+#include "SVGPathSegLinetoHorizontalAbs.h"
+#include "SVGPathSegLinetoHorizontalRel.h"
+#include "SVGPathSegLinetoRel.h"
+#include "SVGPathSegLinetoVerticalAbs.h"
+#include "SVGPathSegLinetoVerticalRel.h"
 #include "SVGPathSegList.h"
 #include "SVGPathSegListBuilder.h"
 #include "SVGPathSegListPropertyTearOff.h"
-#include "SVGPathSegMoveto.h"
+#include "SVGPathSegMovetoAbs.h"
+#include "SVGPathSegMovetoRel.h"
+#include "SVGPathUtilities.h"
 #include "SVGSVGElement.h"
+#include <wtf/NeverDestroyed.h>
 
 namespace WebCore {
 
+// Define custom animated property 'd'.
+const SVGPropertyInfo* SVGPathElement::dPropertyInfo()
+{
+    static const SVGPropertyInfo* s_propertyInfo = 0;
+    if (!s_propertyInfo) {
+        s_propertyInfo = new SVGPropertyInfo(AnimatedPath,
+                                             PropertyIsReadWrite,
+                                             SVGNames::dAttr,
+                                             SVGNames::dAttr.localName(),
+                                             &SVGPathElement::synchronizeD,
+                                             &SVGPathElement::lookupOrCreateDWrapper);
+    }
+    return s_propertyInfo;
+}
+
 // Animated property definitions
 DEFINE_ANIMATED_NUMBER(SVGPathElement, SVGNames::pathLengthAttr, PathLength, pathLength)
 DEFINE_ANIMATED_BOOLEAN(SVGPathElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
 
-inline SVGPathElement::SVGPathElement(const QualifiedName& tagName, Document* document)
-    : SVGStyledTransformableElement(tagName, document)
-    , m_pathByteStream(SVGPathByteStream::create())
+BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGPathElement)
+    REGISTER_LOCAL_ANIMATED_PROPERTY(d)
+    REGISTER_LOCAL_ANIMATED_PROPERTY(pathLength)
+    REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired)
+    REGISTER_PARENT_ANIMATED_PROPERTIES(SVGGraphicsElement)
+END_REGISTER_ANIMATED_PROPERTIES
+
+inline SVGPathElement::SVGPathElement(const QualifiedName& tagName, Document& document)
+    : SVGGraphicsElement(tagName, document)
+    , m_pathByteStream(std::make_unique<SVGPathByteStream>())
     , m_pathSegList(PathSegUnalteredRole)
+    , m_isAnimValObserved(false)
 {
     ASSERT(hasTagName(SVGNames::pathTag));
+    registerAnimatedPropertiesForSVGPathElement();
 }
 
-PassRefPtr<SVGPathElement> SVGPathElement::create(const QualifiedName& tagName, Document* document)
+RefPtr<SVGPathElement> SVGPathElement::create(const QualifiedName& tagName, Document& document)
 {
     return adoptRef(new SVGPathElement(tagName, document));
 }
@@ -65,232 +99,248 @@ PassRefPtr<SVGPathElement> SVGPathElement::create(const QualifiedName& tagName,
 float SVGPathElement::getTotalLength()
 {
     float totalLength = 0;
-    SVGPathParserFactory::self()->getTotalLengthOfSVGPathByteStream(m_pathByteStream.get(), totalLength);
+    getTotalLengthOfSVGPathByteStream(pathByteStream(), totalLength);
     return totalLength;
 }
 
-FloatPoint SVGPathElement::getPointAtLength(float length)
+SVGPoint SVGPathElement::getPointAtLength(float length)
 {
-    FloatPoint point;
-    SVGPathParserFactory::self()->getPointAtLengthOfSVGPathByteStream(m_pathByteStream.get(), length, point);
+    SVGPoint point;
+    getPointAtLengthOfSVGPathByteStream(pathByteStream(), length, point);
     return point;
 }
 
-unsigned long SVGPathElement::getPathSegAtLength(float length)
+unsigned SVGPathElement::getPathSegAtLength(float length)
 {
-    unsigned long pathSeg = 0;
-    SVGPathParserFactory::self()->getSVGPathSegAtLengthFromSVGPathByteStream(m_pathByteStream.get(), length, pathSeg);
+    unsigned pathSeg = 0;
+    getSVGPathSegAtLengthFromSVGPathByteStream(pathByteStream(), length, pathSeg);
     return pathSeg;
 }
 
-PassRefPtr<SVGPathSegClosePath> SVGPathElement::createSVGPathSegClosePath(SVGPathSegRole role)
+RefPtr<SVGPathSegClosePath> SVGPathElement::createSVGPathSegClosePath(SVGPathSegRole role)
 {
     return SVGPathSegClosePath::create(this, role);
 }
 
-PassRefPtr<SVGPathSegMovetoAbs> SVGPathElement::createSVGPathSegMovetoAbs(float x, float y, SVGPathSegRole role)
+RefPtr<SVGPathSegMovetoAbs> SVGPathElement::createSVGPathSegMovetoAbs(float x, float y, SVGPathSegRole role)
 {
     return SVGPathSegMovetoAbs::create(this, role, x, y);
 }
 
-PassRefPtr<SVGPathSegMovetoRel> SVGPathElement::createSVGPathSegMovetoRel(float x, float y, SVGPathSegRole role)
+RefPtr<SVGPathSegMovetoRel> SVGPathElement::createSVGPathSegMovetoRel(float x, float y, SVGPathSegRole role)
 {
     return SVGPathSegMovetoRel::create(this, role, x, y);
 }
 
-PassRefPtr<SVGPathSegLinetoAbs> SVGPathElement::createSVGPathSegLinetoAbs(float x, float y, SVGPathSegRole role)
+RefPtr<SVGPathSegLinetoAbs> SVGPathElement::createSVGPathSegLinetoAbs(float x, float y, SVGPathSegRole role)
 {
     return SVGPathSegLinetoAbs::create(this, role, x, y);
 }
 
-PassRefPtr<SVGPathSegLinetoRel> SVGPathElement::createSVGPathSegLinetoRel(float x, float y, SVGPathSegRole role)
+RefPtr<SVGPathSegLinetoRel> SVGPathElement::createSVGPathSegLinetoRel(float x, float y, SVGPathSegRole role)
 {
     return SVGPathSegLinetoRel::create(this, role, x, y);
 }
 
-PassRefPtr<SVGPathSegCurvetoCubicAbs> SVGPathElement::createSVGPathSegCurvetoCubicAbs(float x, float y, float x1, float y1, float x2, float y2, SVGPathSegRole role)
+RefPtr<SVGPathSegCurvetoCubicAbs> SVGPathElement::createSVGPathSegCurvetoCubicAbs(float x, float y, float x1, float y1, float x2, float y2, SVGPathSegRole role)
 {
     return SVGPathSegCurvetoCubicAbs::create(this, role, x, y, x1, y1, x2, y2);
 }
 
-PassRefPtr<SVGPathSegCurvetoCubicRel> SVGPathElement::createSVGPathSegCurvetoCubicRel(float x, float y, float x1, float y1, float x2, float y2, SVGPathSegRole role)
+RefPtr<SVGPathSegCurvetoCubicRel> SVGPathElement::createSVGPathSegCurvetoCubicRel(float x, float y, float x1, float y1, float x2, float y2, SVGPathSegRole role)
 {
     return SVGPathSegCurvetoCubicRel::create(this, role, x, y, x1, y1, x2, y2);
 }
 
-PassRefPtr<SVGPathSegCurvetoQuadraticAbs> SVGPathElement::createSVGPathSegCurvetoQuadraticAbs(float x, float y, float x1, float y1, SVGPathSegRole role)
+RefPtr<SVGPathSegCurvetoQuadraticAbs> SVGPathElement::createSVGPathSegCurvetoQuadraticAbs(float x, float y, float x1, float y1, SVGPathSegRole role)
 {
     return SVGPathSegCurvetoQuadraticAbs::create(this, role, x, y, x1, y1);
 }
 
-PassRefPtr<SVGPathSegCurvetoQuadraticRel> SVGPathElement::createSVGPathSegCurvetoQuadraticRel(float x, float y, float x1, float y1, SVGPathSegRole role)
+RefPtr<SVGPathSegCurvetoQuadraticRel> SVGPathElement::createSVGPathSegCurvetoQuadraticRel(float x, float y, float x1, float y1, SVGPathSegRole role)
 {
     return SVGPathSegCurvetoQuadraticRel::create(this, role, x, y, x1, y1);
 }
 
-PassRefPtr<SVGPathSegArcAbs> SVGPathElement::createSVGPathSegArcAbs(float x, float y, float r1, float r2, float angle, bool largeArcFlag, bool sweepFlag, SVGPathSegRole role)
+RefPtr<SVGPathSegArcAbs> SVGPathElement::createSVGPathSegArcAbs(float x, float y, float r1, float r2, float angle, bool largeArcFlag, bool sweepFlag, SVGPathSegRole role)
 {
     return SVGPathSegArcAbs::create(this, role, x, y, r1, r2, angle, largeArcFlag, sweepFlag);
 }
 
-PassRefPtr<SVGPathSegArcRel> SVGPathElement::createSVGPathSegArcRel(float x, float y, float r1, float r2, float angle, bool largeArcFlag, bool sweepFlag, SVGPathSegRole role)
+RefPtr<SVGPathSegArcRel> SVGPathElement::createSVGPathSegArcRel(float x, float y, float r1, float r2, float angle, bool largeArcFlag, bool sweepFlag, SVGPathSegRole role)
 {
     return SVGPathSegArcRel::create(this, role, x, y, r1, r2, angle, largeArcFlag, sweepFlag);
 }
 
-PassRefPtr<SVGPathSegLinetoHorizontalAbs> SVGPathElement::createSVGPathSegLinetoHorizontalAbs(float x, SVGPathSegRole role)
+RefPtr<SVGPathSegLinetoHorizontalAbs> SVGPathElement::createSVGPathSegLinetoHorizontalAbs(float x, SVGPathSegRole role)
 {
     return SVGPathSegLinetoHorizontalAbs::create(this, role, x);
 }
 
-PassRefPtr<SVGPathSegLinetoHorizontalRel> SVGPathElement::createSVGPathSegLinetoHorizontalRel(float x, SVGPathSegRole role)
+RefPtr<SVGPathSegLinetoHorizontalRel> SVGPathElement::createSVGPathSegLinetoHorizontalRel(float x, SVGPathSegRole role)
 {
     return SVGPathSegLinetoHorizontalRel::create(this, role, x);
 }
 
-PassRefPtr<SVGPathSegLinetoVerticalAbs> SVGPathElement::createSVGPathSegLinetoVerticalAbs(float y, SVGPathSegRole role)
+RefPtr<SVGPathSegLinetoVerticalAbs> SVGPathElement::createSVGPathSegLinetoVerticalAbs(float y, SVGPathSegRole role)
 {
     return SVGPathSegLinetoVerticalAbs::create(this, role, y);
 }
 
-PassRefPtr<SVGPathSegLinetoVerticalRel> SVGPathElement::createSVGPathSegLinetoVerticalRel(float y, SVGPathSegRole role)
+RefPtr<SVGPathSegLinetoVerticalRel> SVGPathElement::createSVGPathSegLinetoVerticalRel(float y, SVGPathSegRole role)
 {
     return SVGPathSegLinetoVerticalRel::create(this, role, y);
 }
 
-PassRefPtr<SVGPathSegCurvetoCubicSmoothAbs> SVGPathElement::createSVGPathSegCurvetoCubicSmoothAbs(float x, float y, float x2, float y2, SVGPathSegRole role)
+RefPtr<SVGPathSegCurvetoCubicSmoothAbs> SVGPathElement::createSVGPathSegCurvetoCubicSmoothAbs(float x, float y, float x2, float y2, SVGPathSegRole role)
 {
     return SVGPathSegCurvetoCubicSmoothAbs::create(this, role, x, y, x2, y2);
 }
 
-PassRefPtr<SVGPathSegCurvetoCubicSmoothRel> SVGPathElement::createSVGPathSegCurvetoCubicSmoothRel(float x, float y, float x2, float y2, SVGPathSegRole role)
+RefPtr<SVGPathSegCurvetoCubicSmoothRel> SVGPathElement::createSVGPathSegCurvetoCubicSmoothRel(float x, float y, float x2, float y2, SVGPathSegRole role)
 {
     return SVGPathSegCurvetoCubicSmoothRel::create(this, role, x, y, x2, y2);
 }
 
-PassRefPtr<SVGPathSegCurvetoQuadraticSmoothAbs> SVGPathElement::createSVGPathSegCurvetoQuadraticSmoothAbs(float x, float y, SVGPathSegRole role)
+RefPtr<SVGPathSegCurvetoQuadraticSmoothAbs> SVGPathElement::createSVGPathSegCurvetoQuadraticSmoothAbs(float x, float y, SVGPathSegRole role)
 {
     return SVGPathSegCurvetoQuadraticSmoothAbs::create(this, role, x, y);
 }
 
-PassRefPtr<SVGPathSegCurvetoQuadraticSmoothRel> SVGPathElement::createSVGPathSegCurvetoQuadraticSmoothRel(float x, float y, SVGPathSegRole role)
+RefPtr<SVGPathSegCurvetoQuadraticSmoothRel> SVGPathElement::createSVGPathSegCurvetoQuadraticSmoothRel(float x, float y, SVGPathSegRole role)
 {
     return SVGPathSegCurvetoQuadraticSmoothRel::create(this, role, x, y);
 }
 
-void SVGPathElement::parseMappedAttribute(Attribute* attr)
-{
-    if (attr->name() == SVGNames::dAttr) {
-        SVGPathParserFactory* factory = SVGPathParserFactory::self();
-        if (!factory->buildSVGPathByteStreamFromString(attr->value(), m_pathByteStream, UnalteredParsing))
-            document()->accessSVGExtensions()->reportError("Problem parsing d=\"" + attr->value() + "\"");
-    } else if (attr->name() == SVGNames::pathLengthAttr) {
-        setPathLengthBaseValue(attr->value().toFloat());
-        if (pathLengthBaseValue() < 0.0f)
-            document()->accessSVGExtensions()->reportError("A negative value for path attribute <pathLength> is not allowed");
-    } else {
-        if (SVGTests::parseMappedAttribute(attr))
-            return;
-        if (SVGLangSpace::parseMappedAttribute(attr))
-            return;
-        if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
-            return;
-        SVGStyledTransformableElement::parseMappedAttribute(attr);
+bool SVGPathElement::isSupportedAttribute(const QualifiedName& attrName)
+{
+    static NeverDestroyed<HashSet<QualifiedName>> supportedAttributes;
+    if (supportedAttributes.get().isEmpty()) {
+        SVGLangSpace::addSupportedAttributes(supportedAttributes);
+        SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes);
+        supportedAttributes.get().add(SVGNames::dAttr);
+        supportedAttributes.get().add(SVGNames::pathLengthAttr);
     }
+    return supportedAttributes.get().contains<SVGAttributeHashTranslator>(attrName);
 }
 
-void SVGPathElement::svgAttributeChanged(const QualifiedName& attrName)
+void SVGPathElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
 {
-    SVGStyledTransformableElement::svgAttributeChanged(attrName);
+    if (!isSupportedAttribute(name)) {
+        SVGGraphicsElement::parseAttribute(name, value);
+        return;
+    }
+
+    if (name == SVGNames::dAttr) {
+        if (!buildSVGPathByteStreamFromString(value, m_pathByteStream.get(), UnalteredParsing))
+            document().accessSVGExtensions().reportError("Problem parsing d=\"" + value + "\"");
+        return;
+    }
+
+    if (name == SVGNames::pathLengthAttr) {
+        setPathLengthBaseValue(value.toFloat());
+        if (pathLengthBaseValue() < 0)
+            document().accessSVGExtensions().reportError("A negative value for path attribute <pathLength> is not allowed");
+        return;
+    }
+
+    if (SVGLangSpace::parseAttribute(name, value))
+        return;
+    if (SVGExternalResourcesRequired::parseAttribute(name, value))
+        return;
+
+    ASSERT_NOT_REACHED();
+}
 
-    if (SVGTests::handleAttributeChange(this, attrName))
+void SVGPathElement::svgAttributeChanged(const QualifiedName& attrName)
+{
+    if (!isSupportedAttribute(attrName)) {
+        SVGGraphicsElement::svgAttributeChanged(attrName);
         return;
+    }
+
+    SVGElementInstance::InvalidationGuard invalidationGuard(this);
 
-    RenderSVGPath* renderer = static_cast<RenderSVGPath*>(this->renderer());
+    RenderSVGPath* renderer = downcast<RenderSVGPath>(this->renderer());
 
     if (attrName == SVGNames::dAttr) {
-        if (m_animatablePathSegList) {
+        if (m_pathSegList.shouldSynchronize && !SVGAnimatedProperty::lookupWrapper<SVGPathElement, SVGAnimatedPathSegListPropertyTearOff>(this, dPropertyInfo())->isAnimating()) {
             SVGPathSegList newList(PathSegUnalteredRole);
-            SVGPathParserFactory* factory = SVGPathParserFactory::self();
-            factory->buildSVGPathSegListFromByteStream(m_pathByteStream.get(), this, newList, UnalteredParsing);
+            buildSVGPathSegListFromByteStream(m_pathByteStream.get(), this, newList, UnalteredParsing);
             m_pathSegList.value = newList;
         }
 
-        if (!renderer)
-            return;
+        if (renderer)
+            renderer->setNeedsShapeUpdate();
 
-        renderer->setNeedsPathUpdate();
-        RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
-        return;
+        invalidateMPathDependencies();
     }
 
-    if (!renderer)
-        return;
-
-    if (attrName == SVGNames::pathLengthAttr
-        || SVGLangSpace::isKnownAttribute(attrName)
-        || SVGExternalResourcesRequired::isKnownAttribute(attrName))
-        RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
+    if (renderer)
+        RenderSVGResource::markForLayoutAndParentResourceInvalidation(*renderer);
 }
 
-void SVGPathElement::synchronizeProperty(const QualifiedName& attrName)
+void SVGPathElement::invalidateMPathDependencies()
 {
-    SVGStyledTransformableElement::synchronizeProperty(attrName);
-
-    if (attrName == anyQName()) {
-        synchronizeD();
-        synchronizePathLength();
-        synchronizeExternalResourcesRequired();
-        SVGTests::synchronizeProperties(this, attrName);
-        return;
+    // <mpath> can only reference <path> but this dependency is not handled in
+    // markForLayoutAndParentResourceInvalidation so we update any mpath dependencies manually.
+    if (HashSet<SVGElement*>* dependencies = document().accessSVGExtensions().setOfElementsReferencingTarget(this)) {
+        for (auto* element : *dependencies) {
+            if (is<SVGMPathElement>(*element))
+                downcast<SVGMPathElement>(*element).targetPathChanged();
+        }
     }
-
-    if (attrName == SVGNames::dAttr)
-        synchronizeD();
-    else if (attrName == SVGNames::pathLengthAttr)
-        synchronizePathLength();
-    else if (SVGExternalResourcesRequired::isKnownAttribute(attrName))
-        synchronizeExternalResourcesRequired();
-    else if (SVGTests::isKnownAttribute(attrName))
-        SVGTests::synchronizeProperties(this, attrName);
 }
 
-void SVGPathElement::synchronizeD()
+Node::InsertionNotificationRequest SVGPathElement::insertedInto(ContainerNode& rootParent)
 {
-    if (!m_pathSegList.shouldSynchronize)
-        return;
-
-    SVGAnimatedPropertySynchronizer<true>::synchronize(this, SVGNames::dAttr, m_pathSegList.value.valueAsString());
+    SVGGraphicsElement::insertedInto(rootParent);
+    invalidateMPathDependencies();
+    return InsertionDone;
 }
 
-AttributeToPropertyTypeMap& SVGPathElement::attributeToPropertyTypeMap()
+void SVGPathElement::removedFrom(ContainerNode& rootParent)
 {
-    DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_attributeToPropertyTypeMap, ());
-    return s_attributeToPropertyTypeMap;
+    SVGGraphicsElement::removedFrom(rootParent);
+    invalidateMPathDependencies();
 }
 
-void SVGPathElement::fillAttributeToPropertyTypeMap()
+SVGPathByteStream* SVGPathElement::pathByteStream() const
 {
-    AttributeToPropertyTypeMap& attributeToPropertyTypeMap = this->attributeToPropertyTypeMap();
-
-    SVGStyledTransformableElement::fillPassedAttributeToPropertyTypeMap(attributeToPropertyTypeMap);
-    attributeToPropertyTypeMap.set(SVGNames::dAttr, AnimatedPath);
-    attributeToPropertyTypeMap.set(SVGNames::pathLengthAttr, AnimatedNumber);
+    SVGAnimatedProperty* property = SVGAnimatedProperty::lookupWrapper<SVGPathElement, SVGAnimatedPathSegListPropertyTearOff>(this, dPropertyInfo());
+    if (!property || !property->isAnimating())
+        return m_pathByteStream.get();
+    return static_cast<SVGAnimatedPathSegListPropertyTearOff*>(property)->animatedPathByteStream();
 }
 
-SVGPathSegListPropertyTearOff* SVGPathElement::pathSegList()
+PassRefPtr<SVGAnimatedProperty> SVGPathElement::lookupOrCreateDWrapper(SVGElement* contextElement)
 {
-    if (!m_animatablePathSegList) {
-        m_pathSegList.shouldSynchronize = true;
+    ASSERT(contextElement);
+    SVGPathElement& ownerType = downcast<SVGPathElement>(*contextElement);
 
-        SVGPathParserFactory* factory = SVGPathParserFactory::self();
-        factory->buildSVGPathSegListFromByteStream(m_pathByteStream.get(), this, m_pathSegList.value, UnalteredParsing);
+    if (SVGAnimatedProperty* property = SVGAnimatedProperty::lookupWrapper<SVGPathElement, SVGAnimatedPathSegListPropertyTearOff>(&ownerType, dPropertyInfo()))
+        return property;
 
-        m_animatablePathSegList = SVGAnimatedProperty::lookupOrCreateWrapper<SVGAnimatedPathSegListPropertyTearOff, SVGPathSegList>
-                                 (this, SVGNames::dAttr, SVGNames::dAttr.localName(), m_pathSegList.value);
-    }
+    // Build initial SVGPathSegList.
+    buildSVGPathSegListFromByteStream(ownerType.m_pathByteStream.get(), &ownerType, ownerType.m_pathSegList.value, UnalteredParsing);
+
+    return SVGAnimatedProperty::lookupOrCreateWrapper<SVGPathElement, SVGAnimatedPathSegListPropertyTearOff, SVGPathSegList>
+        (&ownerType, dPropertyInfo(), ownerType.m_pathSegList.value);
+}
+
+void SVGPathElement::synchronizeD(SVGElement* contextElement)
+{
+    ASSERT(contextElement);
+    SVGPathElement& ownerType = downcast<SVGPathElement>(*contextElement);
+    if (!ownerType.m_pathSegList.shouldSynchronize)
+        return;
+    ownerType.m_pathSegList.synchronize(&ownerType, dPropertyInfo()->attributeName, ownerType.m_pathSegList.value.valueAsString());
+}
 
-    return static_cast<SVGPathSegListPropertyTearOff*>(m_animatablePathSegList->baseVal(PathSegUnalteredRole));
+SVGPathSegListPropertyTearOff* SVGPathElement::pathSegList()
+{
+    m_pathSegList.shouldSynchronize = true;
+    return static_cast<SVGPathSegListPropertyTearOff*>(static_pointer_cast<SVGAnimatedPathSegListPropertyTearOff>(lookupOrCreateDWrapper(this))->baseVal());
 }
 
 SVGPathSegListPropertyTearOff* SVGPathElement::normalizedPathSegList()
@@ -301,17 +351,9 @@ SVGPathSegListPropertyTearOff* SVGPathElement::normalizedPathSegList()
 
 SVGPathSegListPropertyTearOff* SVGPathElement::animatedPathSegList()
 {
-    if (!m_animatablePathSegList) {
-        m_pathSegList.shouldSynchronize = true;
-
-        SVGPathParserFactory* factory = SVGPathParserFactory::self();
-        factory->buildSVGPathSegListFromByteStream(m_pathByteStream.get(), this, m_pathSegList.value, UnalteredParsing);
-
-        m_animatablePathSegList = SVGAnimatedProperty::lookupOrCreateWrapper<SVGAnimatedPathSegListPropertyTearOff, SVGPathSegList>
-                                 (this, SVGNames::dAttr, SVGNames::dAttr.localName(), m_pathSegList.value);
-    }
-
-    return static_cast<SVGPathSegListPropertyTearOff*>(m_animatablePathSegList->animVal(PathSegUnalteredRole));
+    m_pathSegList.shouldSynchronize = true;
+    m_isAnimValObserved = true;
+    return static_cast<SVGPathSegListPropertyTearOff*>(static_pointer_cast<SVGAnimatedPathSegListPropertyTearOff>(lookupOrCreateDWrapper(this))->animVal());
 }
 
 SVGPathSegListPropertyTearOff* SVGPathElement::animatedNormalizedPathSegList()
@@ -320,40 +362,51 @@ SVGPathSegListPropertyTearOff* SVGPathElement::animatedNormalizedPathSegList()
     return 0;
 }
 
-void SVGPathElement::toPathData(Path& path) const
-{
-    ASSERT(path.isEmpty());
-
-    SVGPathParserFactory* factory = SVGPathParserFactory::self();
-    factory->buildPathFromByteStream(m_pathByteStream.get(), path);
-}
-
-void SVGPathElement::pathSegListChanged(SVGPathSegRole role)
+void SVGPathElement::pathSegListChanged(SVGPathSegRole role, ListModification listModification)
 {
-    SVGPathParserFactory* factory = SVGPathParserFactory::self();
-
     switch (role) {
     case PathSegNormalizedRole:
         // FIXME: https://bugs.webkit.org/show_bug.cgi?id=15412 - Implement normalized path segment lists!
         break;
     case PathSegUnalteredRole:
-        m_pathByteStream->clear();
-        factory->buildSVGPathByteStreamFromSVGPathSegList(m_pathSegList.value, m_pathByteStream, UnalteredParsing);
+        if (listModification == ListModificationAppend) {
+            ASSERT(!m_pathSegList.value.isEmpty());
+            appendSVGPathByteStreamFromSVGPathSeg(m_pathSegList.value.last(), m_pathByteStream.get(), UnalteredParsing);
+        } else
+            buildSVGPathByteStreamFromSVGPathSegList(m_pathSegList.value, m_pathByteStream.get(), UnalteredParsing);
         break;
     case PathSegUndefinedRole:
         return;
     }
 
     invalidateSVGAttributes();
-
-    RenderSVGPath* renderer = static_cast<RenderSVGPath*>(this->renderer());
+    
+    RenderSVGPath* renderer = downcast<RenderSVGPath>(this->renderer());
     if (!renderer)
         return;
 
-    renderer->setNeedsPathUpdate();
-    RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
+    renderer->setNeedsShapeUpdate();
+    RenderSVGResource::markForLayoutAndParentResourceInvalidation(*renderer);
+}
+
+FloatRect SVGPathElement::getBBox(StyleUpdateStrategy styleUpdateStrategy)
+{
+    if (styleUpdateStrategy == AllowStyleUpdate)
+        document().updateLayoutIgnorePendingStylesheets();
+
+    RenderSVGPath* renderer = downcast<RenderSVGPath>(this->renderer());
+
+    // FIXME: Eventually we should support getBBox for detached elements.
+    if (!renderer)
+        return FloatRect();
+
+    return renderer->path().boundingRect();
 }
 
+RenderPtr<RenderElement> SVGPathElement::createElementRenderer(Ref<RenderStyle>&& style)
+{
+    // By default, any subclass is expected to do path-based drawing
+    return createRenderer<RenderSVGPath>(*this, WTF::move(style));
 }
 
-#endif // ENABLE(SVG)
+}