bool SVGPathParser::parseArcToSegment() { 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 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); bool arcIsZeroLength = false; if (m_pathParsingMode == NormalizedParsing) { if (m_mode == RelativeCoordinates) arcIsZeroLength = targetPoint == FloatPoint::zero(); else arcIsZeroLength = targetPoint == m_currentPoint; } if (!rx || !ry || arcIsZeroLength) { if (m_pathParsingMode == NormalizedParsing) { if (m_mode == RelativeCoordinates) m_currentPoint += targetPoint; else m_currentPoint = targetPoint; m_consumer.lineTo(m_currentPoint, AbsoluteCoordinates); } else m_consumer.lineTo(targetPoint, m_mode); return true; } if (m_pathParsingMode == NormalizedParsing) { FloatPoint point1 = m_currentPoint; if (m_mode == RelativeCoordinates) targetPoint += m_currentPoint; m_currentPoint = targetPoint; return decomposeArcToCubic(angle, rx, ry, point1, targetPoint, largeArc, sweep); } m_consumer.arcTo(rx, ry, angle, largeArc, sweep, targetPoint, m_mode); return true; }
void SVGPathNormalizer::emitSegment(const PathSegmentData& segment) { PathSegmentData normSeg = segment; // Convert relative points to absolute points. switch (segment.command) { case PathSegCurveToQuadraticRel: normSeg.point1 += m_currentPoint; normSeg.targetPoint += m_currentPoint; break; case PathSegCurveToCubicRel: normSeg.point1 += m_currentPoint; /* fall through */ case PathSegCurveToCubicSmoothRel: normSeg.point2 += m_currentPoint; /* fall through */ case PathSegMoveToRel: case PathSegLineToRel: case PathSegLineToHorizontalRel: case PathSegLineToVerticalRel: case PathSegCurveToQuadraticSmoothRel: case PathSegArcRel: normSeg.targetPoint += m_currentPoint; break; case PathSegLineToHorizontalAbs: normSeg.targetPoint.setY(m_currentPoint.y()); break; case PathSegLineToVerticalAbs: normSeg.targetPoint.setX(m_currentPoint.x()); break; case PathSegClosePath: // Reset m_currentPoint for the next path. normSeg.targetPoint = m_subPathPoint; break; default: break; } // Update command verb, handle smooth segments and convert quadratic curve // segments to cubics. switch (segment.command) { case PathSegMoveToRel: case PathSegMoveToAbs: m_subPathPoint = normSeg.targetPoint; normSeg.command = PathSegMoveToAbs; break; case PathSegLineToRel: case PathSegLineToAbs: case PathSegLineToHorizontalRel: case PathSegLineToHorizontalAbs: case PathSegLineToVerticalRel: case PathSegLineToVerticalAbs: normSeg.command = PathSegLineToAbs; break; case PathSegClosePath: normSeg.command = PathSegClosePath; break; case PathSegCurveToCubicSmoothRel: case PathSegCurveToCubicSmoothAbs: if (!isCubicCommand(m_lastCommand)) normSeg.point1 = m_currentPoint; else normSeg.point1 = reflectedPoint(m_currentPoint, m_controlPoint); /* fall through */ case PathSegCurveToCubicRel: case PathSegCurveToCubicAbs: m_controlPoint = normSeg.point2; normSeg.command = PathSegCurveToCubicAbs; break; case PathSegCurveToQuadraticSmoothRel: case PathSegCurveToQuadraticSmoothAbs: if (!isQuadraticCommand(m_lastCommand)) normSeg.point1 = m_currentPoint; else normSeg.point1 = reflectedPoint(m_currentPoint, m_controlPoint); /* fall through */ case PathSegCurveToQuadraticRel: case PathSegCurveToQuadraticAbs: // Save the unmodified control point. m_controlPoint = normSeg.point1; normSeg.point1 = blendPoints(m_currentPoint, m_controlPoint); normSeg.point2 = blendPoints(normSeg.targetPoint, m_controlPoint); normSeg.command = PathSegCurveToCubicAbs; break; case PathSegArcRel: case PathSegArcAbs: if (!decomposeArcToCubic(m_currentPoint, normSeg)) { // On failure, emit a line segment to the target point. normSeg.command = PathSegLineToAbs; } else { // decomposeArcToCubic() has already emitted the normalized // segments, so set command to PathSegArcAbs, to skip any further // emit. normSeg.command = PathSegArcAbs; } break; default: ASSERT_NOT_REACHED(); } if (normSeg.command != PathSegArcAbs) m_consumer->emitSegment(normSeg); m_currentPoint = normSeg.targetPoint; if (!isCubicCommand(segment.command) && !isQuadraticCommand(segment.command)) m_controlPoint = m_currentPoint; m_lastCommand = segment.command; }