2011-05-20 Dirk Schulze <krit@webkit.org>
authorkrit@webkit.org <krit@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 20 May 2011 19:04:52 +0000 (19:04 +0000)
committerkrit@webkit.org <krit@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 20 May 2011 19:04:52 +0000 (19:04 +0000)
        Reviewed by Darin Adler.

        SVGPathSegList needs better getTotalLength, getSegmentAtLength path traversal code
        https://bugs.webkit.org/show_bug.cgi?id=12047

        Right now SVGPathElement::getTotalLength and SVGPathElement::getPointAtLength use toPathData()
        to transform a SVGPathByteStream to a Path. This Path gets traversed to find the searched value.
        With this patch both functions use the SVGPathByteStream directly together with the existing
        traversing code in SVG. This avoids the intermediate transforming to a platform path and gives
        platform independent results.
        The traversal code in SVG needed to be extended to support all PathTraversalActions.

        No new tests added. The existing tests cover the changes.

        * svg/SVGPathElement.cpp:
        (WebCore::SVGPathElement::getTotalLength):
        (WebCore::SVGPathElement::getPointAtLength):
        * svg/SVGPathParserFactory.cpp:
        (WebCore::SVGPathParserFactory::getTotalLengthOfSVGPathByteStream):
        (WebCore::SVGPathParserFactory::getPointAtLengthOfSVGPathByteStream):
        * svg/SVGPathParserFactory.h:
        * svg/SVGPathTraversalStateBuilder.cpp:
        (WebCore::SVGPathTraversalStateBuilder::continueConsuming):
        (WebCore::SVGPathTraversalStateBuilder::totalLength):
        (WebCore::SVGPathTraversalStateBuilder::currentPoint):
        * svg/SVGPathTraversalStateBuilder.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@86973 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/svg/SVGPathElement.cpp
Source/WebCore/svg/SVGPathParserFactory.cpp
Source/WebCore/svg/SVGPathParserFactory.h
Source/WebCore/svg/SVGPathTraversalStateBuilder.cpp
Source/WebCore/svg/SVGPathTraversalStateBuilder.h

index b0a3f74..ffadee3 100644 (file)
@@ -1,3 +1,32 @@
+2011-05-20  Dirk Schulze  <krit@webkit.org>
+
+        Reviewed by Darin Adler.
+
+        SVGPathSegList needs better getTotalLength, getSegmentAtLength path traversal code
+        https://bugs.webkit.org/show_bug.cgi?id=12047
+
+        Right now SVGPathElement::getTotalLength and SVGPathElement::getPointAtLength use toPathData()
+        to transform a SVGPathByteStream to a Path. This Path gets traversed to find the searched value.
+        With this patch both functions use the SVGPathByteStream directly together with the existing
+        traversing code in SVG. This avoids the intermediate transforming to a platform path and gives
+        platform independent results.
+        The traversal code in SVG needed to be extended to support all PathTraversalActions.
+
+        No new tests added. The existing tests cover the changes.
+
+        * svg/SVGPathElement.cpp:
+        (WebCore::SVGPathElement::getTotalLength):
+        (WebCore::SVGPathElement::getPointAtLength):
+        * svg/SVGPathParserFactory.cpp:
+        (WebCore::SVGPathParserFactory::getTotalLengthOfSVGPathByteStream):
+        (WebCore::SVGPathParserFactory::getPointAtLengthOfSVGPathByteStream):
+        * svg/SVGPathParserFactory.h:
+        * svg/SVGPathTraversalStateBuilder.cpp:
+        (WebCore::SVGPathTraversalStateBuilder::continueConsuming):
+        (WebCore::SVGPathTraversalStateBuilder::totalLength):
+        (WebCore::SVGPathTraversalStateBuilder::currentPoint):
+        * svg/SVGPathTraversalStateBuilder.h:
+
 2011-05-20  Mark Pilgrim  <pilgrim@chromium.org>
 
         Reviewed by Tony Chang.
index 3ae08d6..598d207 100644 (file)
@@ -64,26 +64,22 @@ PassRefPtr<SVGPathElement> SVGPathElement::create(const QualifiedName& tagName,
 
 float SVGPathElement::getTotalLength()
 {
-    // FIXME: this may wish to use the pathSegList instead of the pathdata if that's cheaper to build (or cached)
-    Path path;
-    toPathData(path);
-    return path.length();
+    float totalLength = 0;
+    SVGPathParserFactory::self()->getTotalLengthOfSVGPathByteStream(m_pathByteStream.get(), totalLength);
+    return totalLength;
 }
 
 FloatPoint SVGPathElement::getPointAtLength(float length)
 {
-    // FIXME: this may wish to use the pathSegList instead of the pathdata if that's cheaper to build (or cached)
-    bool ok = false;
-    Path path;
-    toPathData(path);
-    return path.pointAtLength(length, ok);
+    FloatPoint point;
+    SVGPathParserFactory::self()->getPointAtLengthOfSVGPathByteStream(m_pathByteStream.get(), length, point);
+    return point;
 }
 
 unsigned long SVGPathElement::getPathSegAtLength(float length)
 {
-    SVGPathParserFactory* factory = SVGPathParserFactory::self();
     unsigned long pathSeg = 0;
-    factory->getSVGPathSegAtLengthFromSVGPathByteStream(m_pathByteStream.get(), length, pathSeg);
+    SVGPathParserFactory::self()->getSVGPathSegAtLengthFromSVGPathByteStream(m_pathByteStream.get(), length, pathSeg);
     return pathSeg;
 }
 
index deb0307..b0db9c5 100644 (file)
@@ -267,6 +267,40 @@ bool SVGPathParserFactory::getSVGPathSegAtLengthFromSVGPathByteStream(SVGPathByt
     return ok;
 }
 
+bool SVGPathParserFactory::getTotalLengthOfSVGPathByteStream(SVGPathByteStream* stream, float& totalLength)
+{
+    ASSERT(stream);
+    if (stream->isEmpty())
+        return false;
+    
+    PathTraversalState traversalState(PathTraversalState::TraversalTotalLength);
+    SVGPathTraversalStateBuilder* builder = globalSVGPathTraversalStateBuilder(traversalState, 0);
+    
+    OwnPtr<SVGPathByteStreamSource> source = SVGPathByteStreamSource::create(stream);
+    SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
+    bool ok = parser->parsePathDataFromSource(NormalizedParsing);
+    totalLength = builder->totalLength();
+    parser->cleanup();
+    return ok;
+}
+
+bool SVGPathParserFactory::getPointAtLengthOfSVGPathByteStream(SVGPathByteStream* stream, float length, FloatPoint& point)
+{
+    ASSERT(stream);
+    if (stream->isEmpty())
+        return false;
+    
+    PathTraversalState traversalState(PathTraversalState::TraversalPointAtLength);
+    SVGPathTraversalStateBuilder* builder = globalSVGPathTraversalStateBuilder(traversalState, length);
+    
+    OwnPtr<SVGPathByteStreamSource> source = SVGPathByteStreamSource::create(stream);
+    SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
+    bool ok = parser->parsePathDataFromSource(NormalizedParsing);
+    point = builder->currentPoint();
+    parser->cleanup();
+    return ok;
+}
+
 }
 
 #endif
index 895e65a..894e24e 100644 (file)
@@ -54,6 +54,8 @@ public:
 
     bool buildAnimatedSVGPathByteStream(SVGPathByteStream*, SVGPathByteStream*, OwnPtr<SVGPathByteStream>&, float);
     bool getSVGPathSegAtLengthFromSVGPathByteStream(SVGPathByteStream*, float length, unsigned long& pathSeg);
+    bool getTotalLengthOfSVGPathByteStream(SVGPathByteStream*, float& totalLength);
+    bool getPointAtLengthOfSVGPathByteStream(SVGPathByteStream*, float length, FloatPoint&);
 
 private:
     SVGPathParserFactory();
index a4ef2fb..314e335 100644 (file)
@@ -65,9 +65,26 @@ void SVGPathTraversalStateBuilder::setDesiredLength(float desiredLength)
 
 bool SVGPathTraversalStateBuilder::continueConsuming()
 {
-    ASSERT(m_traversalState);
-    ASSERT(m_traversalState->m_action == PathTraversalState::TraversalSegmentAtLength);
-    return m_traversalState->m_totalLength < m_traversalState->m_desiredLength;
+    ASSERT(m_traversalState);    
+    if (m_traversalState->m_action == PathTraversalState::TraversalSegmentAtLength
+        && m_traversalState->m_totalLength >= m_traversalState->m_desiredLength)
+        m_traversalState->m_success = true;
+    
+    if ((m_traversalState->m_action == PathTraversalState::TraversalPointAtLength
+         || m_traversalState->m_action == PathTraversalState::TraversalNormalAngleAtLength)
+        && m_traversalState->m_totalLength >= m_traversalState->m_desiredLength) {
+        FloatSize change = m_traversalState->m_current - m_traversalState->m_previous;
+        float slope = atan2f(change.height(), change.width());
+        if (m_traversalState->m_action == PathTraversalState::TraversalPointAtLength) {
+            float offset = m_traversalState->m_desiredLength - m_traversalState->m_totalLength;
+            m_traversalState->m_current.move(offset * cosf(slope), offset * sinf(slope));
+        } else
+            m_traversalState->m_normalAngle = rad2deg(slope);
+        m_traversalState->m_success = true;
+    }
+    m_traversalState->m_previous = m_traversalState->m_current;
+
+    return !m_traversalState->m_success;
 }
 
 void SVGPathTraversalStateBuilder::incrementPathSegmentCount()
@@ -82,6 +99,18 @@ unsigned long SVGPathTraversalStateBuilder::pathSegmentIndex()
     return m_traversalState->m_segmentIndex;
 }
 
+float SVGPathTraversalStateBuilder::totalLength()
+{
+    ASSERT(m_traversalState);
+    return m_traversalState->m_totalLength;
+}
+
+FloatPoint SVGPathTraversalStateBuilder::currentPoint()
+{
+    ASSERT(m_traversalState);
+    return m_traversalState->m_current;
+}
+
 }
 
 #endif // ENABLE(SVG)
index a5f3f79..8e8b22b 100644 (file)
@@ -33,6 +33,9 @@ public:
     SVGPathTraversalStateBuilder();
 
     unsigned long pathSegmentIndex();
+    float totalLength();
+    FloatPoint currentPoint();
+
     void setCurrentTraversalState(PathTraversalState* traversalState) { m_traversalState = traversalState; }
     void setDesiredLength(float);
     virtual void incrementPathSegmentCount();