Commit 7b256656 authored by fs's avatar fs Committed by Commit bot

Expose the SVG path normalizer in SVGPathParser.h

Rename the internal NormalizingConsumer to SVGPathNormalizer and move
the class declaration to SVGPathParser.h. This will allow simplifying
the "path processor" (SVGPathParser) a bit in later CLs.
Also modify the normalizer so that it normalizes into a new
PathSegmentData, to make it more "stackable" and reusable.

BUG=467592

Review URL: https://codereview.chromium.org/1472853005

Cr-Commit-Position: refs/heads/master@{#361199}
parent b37a3d86
...@@ -60,28 +60,6 @@ bool SVGPathParser::parsePath() ...@@ -60,28 +60,6 @@ bool SVGPathParser::parsePath()
return true; return true;
} }
class NormalizingConsumer {
STACK_ALLOCATED();
public:
NormalizingConsumer(SVGPathConsumer* consumer)
: m_consumer(consumer)
, m_lastCommand(PathSegUnknown)
{
ASSERT(m_consumer);
}
void emitSegment(PathSegmentData&);
private:
bool decomposeArcToCubic(const FloatPoint& currentPoint, const PathSegmentData&);
SVGPathConsumer* m_consumer;
FloatPoint m_controlPoint;
FloatPoint m_currentPoint;
FloatPoint m_subPathPoint;
SVGPathSegType m_lastCommand;
};
static FloatPoint reflectedPoint(const FloatPoint& reflectIn, const FloatPoint& pointToReflect) static FloatPoint reflectedPoint(const FloatPoint& reflectIn, const FloatPoint& pointToReflect)
{ {
return FloatPoint(2 * reflectIn.x() - pointToReflect.x(), 2 * reflectIn.y() - pointToReflect.y()); return FloatPoint(2 * reflectIn.x() - pointToReflect.x(), 2 * reflectIn.y() - pointToReflect.y());
...@@ -110,21 +88,21 @@ static inline bool isQuadraticCommand(SVGPathSegType command) ...@@ -110,21 +88,21 @@ static inline bool isQuadraticCommand(SVGPathSegType command)
|| command == PathSegCurveToQuadraticSmoothRel; || command == PathSegCurveToQuadraticSmoothRel;
} }
void NormalizingConsumer::emitSegment(PathSegmentData& segment) void SVGPathNormalizer::emitSegment(const PathSegmentData& segment)
{ {
SVGPathSegType originalCommand = segment.command; PathSegmentData normSeg = segment;
// Convert relative points to absolute points. // Convert relative points to absolute points.
switch (segment.command) { switch (segment.command) {
case PathSegCurveToQuadraticRel: case PathSegCurveToQuadraticRel:
segment.point1 += m_currentPoint; normSeg.point1 += m_currentPoint;
segment.targetPoint += m_currentPoint; normSeg.targetPoint += m_currentPoint;
break; break;
case PathSegCurveToCubicRel: case PathSegCurveToCubicRel:
segment.point1 += m_currentPoint; normSeg.point1 += m_currentPoint;
/* fall through */ /* fall through */
case PathSegCurveToCubicSmoothRel: case PathSegCurveToCubicSmoothRel:
segment.point2 += m_currentPoint; normSeg.point2 += m_currentPoint;
/* fall through */ /* fall through */
case PathSegMoveToRel: case PathSegMoveToRel:
case PathSegLineToRel: case PathSegLineToRel:
...@@ -132,17 +110,17 @@ void NormalizingConsumer::emitSegment(PathSegmentData& segment) ...@@ -132,17 +110,17 @@ void NormalizingConsumer::emitSegment(PathSegmentData& segment)
case PathSegLineToVerticalRel: case PathSegLineToVerticalRel:
case PathSegCurveToQuadraticSmoothRel: case PathSegCurveToQuadraticSmoothRel:
case PathSegArcRel: case PathSegArcRel:
segment.targetPoint += m_currentPoint; normSeg.targetPoint += m_currentPoint;
break; break;
case PathSegLineToHorizontalAbs: case PathSegLineToHorizontalAbs:
segment.targetPoint.setY(m_currentPoint.y()); normSeg.targetPoint.setY(m_currentPoint.y());
break; break;
case PathSegLineToVerticalAbs: case PathSegLineToVerticalAbs:
segment.targetPoint.setX(m_currentPoint.x()); normSeg.targetPoint.setX(m_currentPoint.x());
break; break;
case PathSegClosePath: case PathSegClosePath:
// Reset m_currentPoint for the next path. // Reset m_currentPoint for the next path.
segment.targetPoint = m_subPathPoint; normSeg.targetPoint = m_subPathPoint;
break; break;
default: default:
break; break;
...@@ -153,8 +131,8 @@ void NormalizingConsumer::emitSegment(PathSegmentData& segment) ...@@ -153,8 +131,8 @@ void NormalizingConsumer::emitSegment(PathSegmentData& segment)
switch (segment.command) { switch (segment.command) {
case PathSegMoveToRel: case PathSegMoveToRel:
case PathSegMoveToAbs: case PathSegMoveToAbs:
m_subPathPoint = segment.targetPoint; m_subPathPoint = normSeg.targetPoint;
segment.command = PathSegMoveToAbs; normSeg.command = PathSegMoveToAbs;
break; break;
case PathSegLineToRel: case PathSegLineToRel:
case PathSegLineToAbs: case PathSegLineToAbs:
...@@ -162,68 +140,69 @@ void NormalizingConsumer::emitSegment(PathSegmentData& segment) ...@@ -162,68 +140,69 @@ void NormalizingConsumer::emitSegment(PathSegmentData& segment)
case PathSegLineToHorizontalAbs: case PathSegLineToHorizontalAbs:
case PathSegLineToVerticalRel: case PathSegLineToVerticalRel:
case PathSegLineToVerticalAbs: case PathSegLineToVerticalAbs:
segment.command = PathSegLineToAbs; normSeg.command = PathSegLineToAbs;
break; break;
case PathSegClosePath: case PathSegClosePath:
normSeg.command = PathSegClosePath;
break; break;
case PathSegCurveToCubicSmoothRel: case PathSegCurveToCubicSmoothRel:
case PathSegCurveToCubicSmoothAbs: case PathSegCurveToCubicSmoothAbs:
if (!isCubicCommand(m_lastCommand)) if (!isCubicCommand(m_lastCommand))
segment.point1 = m_currentPoint; normSeg.point1 = m_currentPoint;
else else
segment.point1 = reflectedPoint(m_currentPoint, m_controlPoint); normSeg.point1 = reflectedPoint(m_currentPoint, m_controlPoint);
/* fall through */ /* fall through */
case PathSegCurveToCubicRel: case PathSegCurveToCubicRel:
case PathSegCurveToCubicAbs: case PathSegCurveToCubicAbs:
m_controlPoint = segment.point2; m_controlPoint = normSeg.point2;
segment.command = PathSegCurveToCubicAbs; normSeg.command = PathSegCurveToCubicAbs;
break; break;
case PathSegCurveToQuadraticSmoothRel: case PathSegCurveToQuadraticSmoothRel:
case PathSegCurveToQuadraticSmoothAbs: case PathSegCurveToQuadraticSmoothAbs:
if (!isQuadraticCommand(m_lastCommand)) if (!isQuadraticCommand(m_lastCommand))
segment.point1 = m_currentPoint; normSeg.point1 = m_currentPoint;
else else
segment.point1 = reflectedPoint(m_currentPoint, m_controlPoint); normSeg.point1 = reflectedPoint(m_currentPoint, m_controlPoint);
/* fall through */ /* fall through */
case PathSegCurveToQuadraticRel: case PathSegCurveToQuadraticRel:
case PathSegCurveToQuadraticAbs: case PathSegCurveToQuadraticAbs:
// Save the unmodified control point. // Save the unmodified control point.
m_controlPoint = segment.point1; m_controlPoint = normSeg.point1;
segment.point1 = blendPoints(m_currentPoint, m_controlPoint); normSeg.point1 = blendPoints(m_currentPoint, m_controlPoint);
segment.point2 = blendPoints(segment.targetPoint, m_controlPoint); normSeg.point2 = blendPoints(normSeg.targetPoint, m_controlPoint);
segment.command = PathSegCurveToCubicAbs; normSeg.command = PathSegCurveToCubicAbs;
break; break;
case PathSegArcRel: case PathSegArcRel:
case PathSegArcAbs: case PathSegArcAbs:
if (!decomposeArcToCubic(m_currentPoint, segment)) { if (!decomposeArcToCubic(m_currentPoint, normSeg)) {
// On failure, emit a line segment to the target point. // On failure, emit a line segment to the target point.
segment.command = PathSegLineToAbs; normSeg.command = PathSegLineToAbs;
} else { } else {
// decomposeArcToCubic() has already emitted the normalized // decomposeArcToCubic() has already emitted the normalized
// segments, so set command to PathSegArcAbs, to skip any further // segments, so set command to PathSegArcAbs, to skip any further
// emit. // emit.
segment.command = PathSegArcAbs; normSeg.command = PathSegArcAbs;
} }
break; break;
default: default:
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
if (segment.command != PathSegArcAbs) if (normSeg.command != PathSegArcAbs)
m_consumer->emitSegment(segment); m_consumer->emitSegment(normSeg);
m_currentPoint = segment.targetPoint; m_currentPoint = normSeg.targetPoint;
if (!isCubicCommand(originalCommand) && !isQuadraticCommand(originalCommand)) if (!isCubicCommand(segment.command) && !isQuadraticCommand(segment.command))
m_controlPoint = m_currentPoint; m_controlPoint = m_currentPoint;
m_lastCommand = originalCommand; m_lastCommand = segment.command;
} }
// This works by converting the SVG arc to "simple" beziers. // This works by converting the SVG arc to "simple" beziers.
// Partly adapted from Niko's code in kdelibs/kdecore/svgicons. // Partly adapted from Niko's code in kdelibs/kdecore/svgicons.
// See also SVG implementation notes: http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter // See also SVG implementation notes: http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
bool NormalizingConsumer::decomposeArcToCubic(const FloatPoint& currentPoint, const PathSegmentData& arcSegment) bool SVGPathNormalizer::decomposeArcToCubic(const FloatPoint& currentPoint, const PathSegmentData& arcSegment)
{ {
// If rx = 0 or ry = 0 then this arc is treated as a straight line segment (a "lineto") joining the endpoints. // If rx = 0 or ry = 0 then this arc is treated as a straight line segment (a "lineto") joining the endpoints.
// http://www.w3.org/TR/SVG/implnote.html#ArcOutOfRangeParameters // http://www.w3.org/TR/SVG/implnote.html#ArcOutOfRangeParameters
...@@ -327,7 +306,7 @@ bool NormalizingConsumer::decomposeArcToCubic(const FloatPoint& currentPoint, co ...@@ -327,7 +306,7 @@ bool NormalizingConsumer::decomposeArcToCubic(const FloatPoint& currentPoint, co
bool SVGPathParser::parseAndNormalizePath() bool SVGPathParser::parseAndNormalizePath()
{ {
NormalizingConsumer normalizer(m_consumer); SVGPathNormalizer normalizer(m_consumer);
while (m_source->hasMoreData()) { while (m_source->hasMoreData()) {
PathSegmentData segment = m_source->parseSegment(); PathSegmentData segment = m_source->parseSegment();
......
...@@ -70,6 +70,28 @@ private: ...@@ -70,6 +70,28 @@ private:
SVGPathConsumer* m_consumer; SVGPathConsumer* m_consumer;
}; };
class SVGPathNormalizer {
STACK_ALLOCATED();
public:
SVGPathNormalizer(SVGPathConsumer* consumer)
: m_consumer(consumer)
, m_lastCommand(PathSegUnknown)
{
ASSERT(m_consumer);
}
void emitSegment(const PathSegmentData&);
private:
bool decomposeArcToCubic(const FloatPoint& currentPoint, const PathSegmentData&);
SVGPathConsumer* m_consumer;
FloatPoint m_controlPoint;
FloatPoint m_currentPoint;
FloatPoint m_subPathPoint;
SVGPathSegType m_lastCommand;
};
} // namespace blink } // namespace blink
#endif // SVGPathParser_h #endif // SVGPathParser_h
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment