Skip to content
Permalink
Browse files
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:


Canonical link: https://commits.webkit.org/76576@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@86973 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
dirkschulze committed May 20, 2011
1 parent 9ae9bb8 commit 39aee7cd78744121458c97c54023d97bba108e35
@@ -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.
@@ -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;
}

@@ -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
@@ -54,6 +54,8 @@ class SVGPathParserFactory {

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();
@@ -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)
@@ -33,6 +33,9 @@ class SVGPathTraversalStateBuilder : public SVGPathConsumer {
SVGPathTraversalStateBuilder();

unsigned long pathSegmentIndex();
float totalLength();
FloatPoint currentPoint();

void setCurrentTraversalState(PathTraversalState* traversalState) { m_traversalState = traversalState; }
void setDesiredLength(float);
virtual void incrementPathSegmentCount();

0 comments on commit 39aee7c

Please sign in to comment.