| Index: Source/core/svg/SVGPathParser.cpp
|
| diff --git a/Source/core/svg/SVGPathParser.cpp b/Source/core/svg/SVGPathParser.cpp
|
| index 859eb7454f115d9426d9722a022437005681226e..fc63a809e00d117e7605c2176e3347b68c9a2e48 100644
|
| --- a/Source/core/svg/SVGPathParser.cpp
|
| +++ b/Source/core/svg/SVGPathParser.cpp
|
| @@ -36,109 +36,85 @@ DEFINE_TRACE(SVGPathParser)
|
| visitor->trace(m_consumer);
|
| }
|
|
|
| -void SVGPathParser::parseClosePathSegment()
|
| +bool SVGPathParser::initialCommandIsMoveTo()
|
| {
|
| - // Reset m_currentPoint for the next path.
|
| - if (m_pathParsingMode == NormalizedParsing)
|
| - m_currentPoint = m_subPathPoint;
|
| - m_consumer->closePath();
|
| + // If the path is empty it is still valid, so return true.
|
| + if (!m_source->hasMoreData())
|
| + return true;
|
| +
|
| + SVGPathSegType command = m_source->peekSegmentType();
|
| + // Path must start with moveTo.
|
| + return command == PathSegMoveToAbs || command == PathSegMoveToRel;
|
| }
|
|
|
| -bool SVGPathParser::parseMoveToSegment()
|
| +void SVGPathParser::emitMoveToSegment(PathSegmentData& segment)
|
| {
|
| - FloatPoint targetPoint;
|
| - if (!m_source->parseMoveToSegment(targetPoint))
|
| - return false;
|
| -
|
| if (m_pathParsingMode == UnalteredParsing) {
|
| - m_consumer->moveTo(targetPoint, m_mode);
|
| - return true;
|
| + m_consumer->moveTo(segment.targetPoint, m_mode);
|
| + return;
|
| }
|
| if (m_mode == RelativeCoordinates)
|
| - m_currentPoint += targetPoint;
|
| + m_currentPoint += segment.targetPoint;
|
| else
|
| - m_currentPoint = targetPoint;
|
| + m_currentPoint = segment.targetPoint;
|
| m_subPathPoint = m_currentPoint;
|
| m_consumer->moveTo(m_currentPoint, AbsoluteCoordinates);
|
| - return true;
|
| }
|
|
|
| -bool SVGPathParser::parseLineToSegment()
|
| +void SVGPathParser::emitLineToSegment(PathSegmentData& segment)
|
| {
|
| - FloatPoint targetPoint;
|
| - if (!m_source->parseLineToSegment(targetPoint))
|
| - return false;
|
| -
|
| if (m_pathParsingMode == UnalteredParsing) {
|
| - m_consumer->lineTo(targetPoint, m_mode);
|
| - return true;
|
| + m_consumer->lineTo(segment.targetPoint, m_mode);
|
| + return;
|
| }
|
| if (m_mode == RelativeCoordinates)
|
| - m_currentPoint += targetPoint;
|
| + m_currentPoint += segment.targetPoint;
|
| else
|
| - m_currentPoint = targetPoint;
|
| + m_currentPoint = segment.targetPoint;
|
| m_consumer->lineTo(m_currentPoint, AbsoluteCoordinates);
|
| - return true;
|
| }
|
|
|
| -bool SVGPathParser::parseLineToHorizontalSegment()
|
| +void SVGPathParser::emitLineToHorizontalSegment(PathSegmentData& segment)
|
| {
|
| - float toX;
|
| - if (!m_source->parseLineToHorizontalSegment(toX))
|
| - return false;
|
| -
|
| if (m_pathParsingMode == UnalteredParsing) {
|
| - m_consumer->lineToHorizontal(toX, m_mode);
|
| - return true;
|
| + m_consumer->lineToHorizontal(segment.targetPoint.x(), m_mode);
|
| + return;
|
| }
|
| if (m_mode == RelativeCoordinates)
|
| - m_currentPoint.move(toX, 0);
|
| + m_currentPoint += segment.targetPoint;
|
| else
|
| - m_currentPoint.setX(toX);
|
| + m_currentPoint.setX(segment.targetPoint.x());
|
| m_consumer->lineTo(m_currentPoint, AbsoluteCoordinates);
|
| - return true;
|
| }
|
|
|
| -bool SVGPathParser::parseLineToVerticalSegment()
|
| +void SVGPathParser::emitLineToVerticalSegment(PathSegmentData& segment)
|
| {
|
| - float toY;
|
| - if (!m_source->parseLineToVerticalSegment(toY))
|
| - return false;
|
| -
|
| if (m_pathParsingMode == UnalteredParsing) {
|
| - m_consumer->lineToVertical(toY, m_mode);
|
| - return true;
|
| + m_consumer->lineToVertical(segment.targetPoint.y(), m_mode);
|
| + return;
|
| }
|
| if (m_mode == RelativeCoordinates)
|
| - m_currentPoint.move(0, toY);
|
| + m_currentPoint += segment.targetPoint;
|
| else
|
| - m_currentPoint.setY(toY);
|
| + m_currentPoint.setY(segment.targetPoint.y());
|
| m_consumer->lineTo(m_currentPoint, AbsoluteCoordinates);
|
| - return true;
|
| }
|
|
|
| -bool SVGPathParser::parseCurveToCubicSegment()
|
| +void SVGPathParser::emitCurveToCubicSegment(PathSegmentData& segment)
|
| {
|
| - FloatPoint point1;
|
| - FloatPoint point2;
|
| - FloatPoint targetPoint;
|
| - if (!m_source->parseCurveToCubicSegment(point1, point2, targetPoint))
|
| - return false;
|
| -
|
| if (m_pathParsingMode == UnalteredParsing) {
|
| - m_consumer->curveToCubic(point1, point2, targetPoint, m_mode);
|
| - return true;
|
| + m_consumer->curveToCubic(segment.point1, segment.point2, segment.targetPoint, m_mode);
|
| + return;
|
| }
|
| if (m_mode == RelativeCoordinates) {
|
| - point1 += m_currentPoint;
|
| - point2 += m_currentPoint;
|
| - targetPoint += m_currentPoint;
|
| + segment.point1 += m_currentPoint;
|
| + segment.point2 += m_currentPoint;
|
| + segment.targetPoint += m_currentPoint;
|
| }
|
| - m_consumer->curveToCubic(point1, point2, targetPoint, AbsoluteCoordinates);
|
| + m_consumer->curveToCubic(segment.point1, segment.point2, segment.targetPoint, AbsoluteCoordinates);
|
|
|
| - m_controlPoint = point2;
|
| - m_currentPoint = targetPoint;
|
| - return true;
|
| + m_controlPoint = segment.point2;
|
| + m_currentPoint = segment.targetPoint;
|
| }
|
|
|
| static FloatPoint reflectedPoint(const FloatPoint& reflectIn, const FloatPoint& pointToReflect)
|
| @@ -146,16 +122,11 @@ static FloatPoint reflectedPoint(const FloatPoint& reflectIn, const FloatPoint&
|
| return FloatPoint(2 * reflectIn.x() - pointToReflect.x(), 2 * reflectIn.y() - pointToReflect.y());
|
| }
|
|
|
| -bool SVGPathParser::parseCurveToCubicSmoothSegment()
|
| +void SVGPathParser::emitCurveToCubicSmoothSegment(PathSegmentData& segment)
|
| {
|
| - FloatPoint point2;
|
| - FloatPoint targetPoint;
|
| - if (!m_source->parseCurveToCubicSmoothSegment(point2, targetPoint))
|
| - return false;
|
| -
|
| if (m_pathParsingMode == UnalteredParsing) {
|
| - m_consumer->curveToCubicSmooth(point2, targetPoint, m_mode);
|
| - return true;
|
| + m_consumer->curveToCubicSmooth(segment.point2, segment.targetPoint, m_mode);
|
| + return;
|
| }
|
| if (m_lastCommand != PathSegCurveToCubicAbs
|
| && m_lastCommand != PathSegCurveToCubicRel
|
| @@ -165,15 +136,14 @@ bool SVGPathParser::parseCurveToCubicSmoothSegment()
|
|
|
| FloatPoint point1 = reflectedPoint(m_currentPoint, m_controlPoint);
|
| if (m_mode == RelativeCoordinates) {
|
| - point2 += m_currentPoint;
|
| - targetPoint += m_currentPoint;
|
| + segment.point2 += m_currentPoint;
|
| + segment.targetPoint += m_currentPoint;
|
| }
|
|
|
| - m_consumer->curveToCubic(point1, point2, targetPoint, AbsoluteCoordinates);
|
| + m_consumer->curveToCubic(point1, segment.point2, segment.targetPoint, AbsoluteCoordinates);
|
|
|
| - m_controlPoint = point2;
|
| - m_currentPoint = targetPoint;
|
| - return true;
|
| + m_controlPoint = segment.point2;
|
| + m_currentPoint = segment.targetPoint;
|
| }
|
|
|
| // Blend the points with a ratio (1/3):(2/3).
|
| @@ -183,41 +153,31 @@ static FloatPoint blendPoints(const FloatPoint& p1, const FloatPoint& p2)
|
| return FloatPoint((p1.x() + 2 * p2.x()) * oneOverThree, (p1.y() + 2 * p2.y()) * oneOverThree);
|
| }
|
|
|
| -bool SVGPathParser::parseCurveToQuadraticSegment()
|
| +void SVGPathParser::emitCurveToQuadraticSegment(PathSegmentData& segment)
|
| {
|
| - FloatPoint point1;
|
| - FloatPoint targetPoint;
|
| - if (!m_source->parseCurveToQuadraticSegment(point1, targetPoint))
|
| - return false;
|
| -
|
| if (m_pathParsingMode == UnalteredParsing) {
|
| - m_consumer->curveToQuadratic(point1, targetPoint, m_mode);
|
| - return true;
|
| + m_consumer->curveToQuadratic(segment.point1, segment.targetPoint, m_mode);
|
| + return;
|
| }
|
| - m_controlPoint = point1;
|
| + m_controlPoint = segment.point1;
|
|
|
| if (m_mode == RelativeCoordinates) {
|
| m_controlPoint += m_currentPoint;
|
| - targetPoint += m_currentPoint;
|
| + segment.targetPoint += m_currentPoint;
|
| }
|
| - point1 = blendPoints(m_currentPoint, m_controlPoint);
|
| - FloatPoint point2 = blendPoints(targetPoint, m_controlPoint);
|
| + segment.point1 = blendPoints(m_currentPoint, m_controlPoint);
|
| + FloatPoint point2 = blendPoints(segment.targetPoint, m_controlPoint);
|
|
|
| - m_consumer->curveToCubic(point1, point2, targetPoint, AbsoluteCoordinates);
|
| + m_consumer->curveToCubic(segment.point1, point2, segment.targetPoint, AbsoluteCoordinates);
|
|
|
| - m_currentPoint = targetPoint;
|
| - return true;
|
| + m_currentPoint = segment.targetPoint;
|
| }
|
|
|
| -bool SVGPathParser::parseCurveToQuadraticSmoothSegment()
|
| +void SVGPathParser::emitCurveToQuadraticSmoothSegment(PathSegmentData& segment)
|
| {
|
| - FloatPoint targetPoint;
|
| - if (!m_source->parseCurveToQuadraticSmoothSegment(targetPoint))
|
| - return false;
|
| -
|
| if (m_pathParsingMode == UnalteredParsing) {
|
| - m_consumer->curveToQuadraticSmooth(targetPoint, m_mode);
|
| - return true;
|
| + m_consumer->curveToQuadraticSmooth(segment.targetPoint, m_mode);
|
| + return;
|
| }
|
| if (m_lastCommand != PathSegCurveToQuadraticAbs
|
| && m_lastCommand != PathSegCurveToQuadraticRel
|
| @@ -226,53 +186,45 @@ bool SVGPathParser::parseCurveToQuadraticSmoothSegment()
|
| m_controlPoint = m_currentPoint;
|
|
|
| if (m_mode == RelativeCoordinates)
|
| - targetPoint += m_currentPoint;
|
| + segment.targetPoint += m_currentPoint;
|
|
|
| m_controlPoint = reflectedPoint(m_currentPoint, m_controlPoint);
|
| FloatPoint point1 = blendPoints(m_currentPoint, m_controlPoint);
|
| - FloatPoint point2 = blendPoints(targetPoint, m_controlPoint);
|
| + FloatPoint point2 = blendPoints(segment.targetPoint, m_controlPoint);
|
|
|
| - m_consumer->curveToCubic(point1, point2, targetPoint, AbsoluteCoordinates);
|
| + m_consumer->curveToCubic(point1, point2, segment.targetPoint, AbsoluteCoordinates);
|
|
|
| - m_currentPoint = targetPoint;
|
| - return true;
|
| + m_currentPoint = segment.targetPoint;
|
| }
|
|
|
| -bool SVGPathParser::parseArcToSegment()
|
| +void SVGPathParser::emitArcToSegment(PathSegmentData& segment)
|
| {
|
| - float rx;
|
| - float ry;
|
| - float angle;
|
| - bool largeArc;
|
| - bool sweep;
|
| - FloatPoint targetPoint;
|
| - if (!m_source->parseArcToSegment(rx, ry, angle, largeArc, sweep, targetPoint))
|
| - return false;
|
| -
|
| if (m_pathParsingMode == UnalteredParsing) {
|
| - m_consumer->arcTo(rx, ry, angle, largeArc, sweep, targetPoint, m_mode);
|
| - return true;
|
| + m_consumer->arcTo(segment.arcRadii().x(), segment.arcRadii().y(), segment.arcAngle(), segment.arcLarge, segment.arcSweep, segment.targetPoint, m_mode);
|
| + return;
|
| }
|
|
|
| // 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
|
| // If the current point and target point for the arc are identical, it should be treated as a zero length
|
| // path. This ensures continuity in animations.
|
| - rx = fabsf(rx);
|
| - ry = fabsf(ry);
|
| + float rx = fabsf(segment.arcRadii().x());
|
| + float ry = fabsf(segment.arcRadii().y());
|
|
|
| if (m_mode == RelativeCoordinates)
|
| - targetPoint += m_currentPoint;
|
| + segment.targetPoint += m_currentPoint;
|
|
|
| - if (!rx || !ry || targetPoint == m_currentPoint) {
|
| - m_consumer->lineTo(targetPoint, AbsoluteCoordinates);
|
| - m_currentPoint = targetPoint;
|
| - return true;
|
| + if (!rx || !ry || segment.targetPoint == m_currentPoint) {
|
| + m_consumer->lineTo(segment.targetPoint, AbsoluteCoordinates);
|
| + m_currentPoint = segment.targetPoint;
|
| + return;
|
| }
|
|
|
| + float angle = segment.arcAngle();
|
| FloatPoint point1 = m_currentPoint;
|
| - m_currentPoint = targetPoint;
|
| - return decomposeArcToCubic(angle, rx, ry, point1, targetPoint, largeArc, sweep);
|
| + m_currentPoint = segment.targetPoint;
|
| + if (!decomposeArcToCubic(angle, rx, ry, point1, segment.targetPoint, segment.arcLarge, segment.arcSweep))
|
| + m_consumer->lineTo(segment.targetPoint, AbsoluteCoordinates);
|
| }
|
|
|
| bool SVGPathParser::parsePathDataFromSource(PathParsingMode pathParsingMode, bool checkForInitialMoveTo)
|
| @@ -286,92 +238,76 @@ bool SVGPathParser::parsePathDataFromSource(PathParsingMode pathParsingMode, boo
|
| m_currentPoint = FloatPoint();
|
| m_subPathPoint = FloatPoint();
|
|
|
| - // Skip any leading spaces.
|
| - if (!m_source->moveToNextToken())
|
| - return true;
|
| + if (checkForInitialMoveTo && !initialCommandIsMoveTo())
|
| + return false;
|
|
|
| - SVGPathSegType command;
|
| - m_source->parseSVGSegmentType(command);
|
| m_lastCommand = PathSegUnknown;
|
| + while (m_source->hasMoreData()) {
|
| + PathSegmentData segment = m_source->parseSegment();
|
| + if (segment.command == PathSegUnknown)
|
| + return false;
|
|
|
| - // Path must start with moveto.
|
| - if (checkForInitialMoveTo && command != PathSegMoveToAbs && command != PathSegMoveToRel)
|
| - return false;
|
| -
|
| - while (true) {
|
| - // Skip spaces between command and first coordinate.
|
| - m_source->moveToNextToken();
|
| m_mode = AbsoluteCoordinates;
|
| - switch (command) {
|
| +
|
| + switch (segment.command) {
|
| case PathSegMoveToRel:
|
| m_mode = RelativeCoordinates;
|
| case PathSegMoveToAbs:
|
| - if (!parseMoveToSegment())
|
| - return false;
|
| + emitMoveToSegment(segment);
|
| break;
|
| case PathSegLineToRel:
|
| m_mode = RelativeCoordinates;
|
| case PathSegLineToAbs:
|
| - if (!parseLineToSegment())
|
| - return false;
|
| + emitLineToSegment(segment);
|
| break;
|
| case PathSegLineToHorizontalRel:
|
| m_mode = RelativeCoordinates;
|
| case PathSegLineToHorizontalAbs:
|
| - if (!parseLineToHorizontalSegment())
|
| - return false;
|
| + emitLineToHorizontalSegment(segment);
|
| break;
|
| case PathSegLineToVerticalRel:
|
| m_mode = RelativeCoordinates;
|
| case PathSegLineToVerticalAbs:
|
| - if (!parseLineToVerticalSegment())
|
| - return false;
|
| + emitLineToVerticalSegment(segment);
|
| break;
|
| case PathSegClosePath:
|
| - parseClosePathSegment();
|
| + m_consumer->closePath();
|
| + // Reset m_currentPoint for the next path.
|
| + if (m_pathParsingMode == NormalizedParsing)
|
| + m_currentPoint = m_subPathPoint;
|
| break;
|
| case PathSegCurveToCubicRel:
|
| m_mode = RelativeCoordinates;
|
| case PathSegCurveToCubicAbs:
|
| - if (!parseCurveToCubicSegment())
|
| - return false;
|
| + emitCurveToCubicSegment(segment);
|
| break;
|
| case PathSegCurveToCubicSmoothRel:
|
| m_mode = RelativeCoordinates;
|
| case PathSegCurveToCubicSmoothAbs:
|
| - if (!parseCurveToCubicSmoothSegment())
|
| - return false;
|
| + emitCurveToCubicSmoothSegment(segment);
|
| break;
|
| case PathSegCurveToQuadraticRel:
|
| m_mode = RelativeCoordinates;
|
| case PathSegCurveToQuadraticAbs:
|
| - if (!parseCurveToQuadraticSegment())
|
| - return false;
|
| + emitCurveToQuadraticSegment(segment);
|
| break;
|
| case PathSegCurveToQuadraticSmoothRel:
|
| m_mode = RelativeCoordinates;
|
| case PathSegCurveToQuadraticSmoothAbs:
|
| - if (!parseCurveToQuadraticSmoothSegment())
|
| - return false;
|
| + emitCurveToQuadraticSmoothSegment(segment);
|
| break;
|
| case PathSegArcRel:
|
| m_mode = RelativeCoordinates;
|
| case PathSegArcAbs:
|
| - if (!parseArcToSegment())
|
| - return false;
|
| + emitArcToSegment(segment);
|
| break;
|
| default:
|
| - return false;
|
| + ASSERT_NOT_REACHED();
|
| }
|
| if (!m_consumer->continueConsuming())
|
| return true;
|
|
|
| - m_lastCommand = command;
|
| -
|
| - if (!m_source->hasMoreData())
|
| - return true;
|
| -
|
| - command = m_source->nextCommand(command);
|
| + m_lastCommand = segment.command;
|
|
|
| if (m_lastCommand != PathSegCurveToCubicAbs
|
| && m_lastCommand != PathSegCurveToCubicRel
|
| @@ -383,10 +319,10 @@ bool SVGPathParser::parsePathDataFromSource(PathParsingMode pathParsingMode, boo
|
| && m_lastCommand != PathSegCurveToQuadraticSmoothRel)
|
| m_controlPoint = m_currentPoint;
|
|
|
| - m_consumer->incrementPathSegmentCount();
|
| + if (m_source->hasMoreData())
|
| + m_consumer->incrementPathSegmentCount();
|
| }
|
| -
|
| - return false;
|
| + return true;
|
| }
|
|
|
| // This works by converting the SVG arc to "simple" beziers.
|
|
|