| Index: third_party/WebKit/Source/core/svg/SVGPathBuilder.cpp
|
| diff --git a/third_party/WebKit/Source/core/svg/SVGPathBuilder.cpp b/third_party/WebKit/Source/core/svg/SVGPathBuilder.cpp
|
| index acbce1d157bfbfd9be74f0a519449046e57aff21..4810645af5cfd3c417cb612c7967caccf478c9d3 100644
|
| --- a/third_party/WebKit/Source/core/svg/SVGPathBuilder.cpp
|
| +++ b/third_party/WebKit/Source/core/svg/SVGPathBuilder.cpp
|
| @@ -23,29 +23,194 @@
|
|
|
| #include "core/svg/SVGPathBuilder.h"
|
|
|
| -#include "core/svg/SVGPathData.h"
|
| #include "platform/graphics/Path.h"
|
|
|
| namespace blink {
|
|
|
| +FloatPoint SVGPathBuilder::smoothControl(bool isCompatibleSegment) const
|
| +{
|
| + // The control point is assumed to be the reflection of the control point on
|
| + // the previous command relative to the current point. If there is no previous
|
| + // command or if the previous command was not a [quad/cubic], assume the control
|
| + // point is coincident with the current point.
|
| + // [https://www.w3.org/TR/SVG/paths.html#PathDataCubicBezierCommands]
|
| + // [https://www.w3.org/TR/SVG/paths.html#PathDataQuadraticBezierCommands]
|
| + FloatPoint controlPoint = m_currentPoint;
|
| + if (isCompatibleSegment)
|
| + controlPoint += m_currentPoint - m_lastControlPoint;
|
| +
|
| + return controlPoint;
|
| +}
|
| +
|
| +void SVGPathBuilder::emitClose()
|
| +{
|
| + m_path.closeSubpath();
|
| +
|
| + // At the end of the [closepath] command, the new current
|
| + // point is set to the initial point of the current subpath.
|
| + // [https://www.w3.org/TR/SVG/paths.html#PathDataClosePathCommand]
|
| + m_currentPoint = m_subpathPoint;
|
| +}
|
| +
|
| +void SVGPathBuilder::emitMoveTo(const FloatPoint& p)
|
| +{
|
| + m_path.moveTo(p);
|
| +
|
| + // If a "closepath" is followed immediately by a "moveto", then
|
| + // the "moveto" identifies the start point of the next subpath.
|
| + // [https://www.w3.org/TR/SVG/paths.html#PathDataClosePathCommand]
|
| + if (m_lastCommand == PathSegClosePath)
|
| + m_subpathPoint = p;
|
| +
|
| + m_currentPoint = p;
|
| +}
|
| +
|
| +void SVGPathBuilder::emitLineTo(const FloatPoint& p)
|
| +{
|
| + m_path.addLineTo(p);
|
| + m_currentPoint = p;
|
| +}
|
| +
|
| +void SVGPathBuilder::emitQuadTo(const FloatPoint& c0, const FloatPoint& p)
|
| +{
|
| + m_path.addQuadCurveTo(c0, p);
|
| + m_lastControlPoint = c0;
|
| + m_currentPoint = p;
|
| +}
|
| +
|
| +void SVGPathBuilder::emitSmoothQuadTo(const FloatPoint& p)
|
| +{
|
| + bool lastWasQuadratic = m_lastCommand == PathSegCurveToQuadraticAbs
|
| + || m_lastCommand == PathSegCurveToQuadraticRel
|
| + || m_lastCommand == PathSegCurveToQuadraticSmoothAbs
|
| + || m_lastCommand == PathSegCurveToQuadraticSmoothRel;
|
| +
|
| + emitQuadTo(smoothControl(lastWasQuadratic), p);
|
| +}
|
| +
|
| +void SVGPathBuilder::emitCubicTo(const FloatPoint& c0, const FloatPoint& c1, const FloatPoint& p)
|
| +{
|
| + m_path.addBezierCurveTo(c0, c1, p);
|
| + m_lastControlPoint = c1;
|
| + m_currentPoint = p;
|
| +}
|
| +
|
| +void SVGPathBuilder::emitSmoothCubicTo(const FloatPoint& c1, const FloatPoint& p)
|
| +{
|
| + bool lastWasCubic = m_lastCommand == PathSegCurveToCubicAbs
|
| + || m_lastCommand == PathSegCurveToCubicRel
|
| + || m_lastCommand == PathSegCurveToCubicSmoothAbs
|
| + || m_lastCommand == PathSegCurveToCubicSmoothRel;
|
| +
|
| + emitCubicTo(smoothControl(lastWasCubic), c1, p);
|
| +}
|
| +
|
| +void SVGPathBuilder::emitArcTo(const FloatPoint& p, const FloatSize& r, float rotate,
|
| + bool largeArc, bool sweep)
|
| +{
|
| + m_path.addArcTo(p, r, rotate, largeArc, sweep);
|
| + m_currentPoint = p;
|
| +}
|
| +
|
| void SVGPathBuilder::emitSegment(const PathSegmentData& segment)
|
| {
|
| switch (segment.command) {
|
| + case PathSegClosePath:
|
| + emitClose();
|
| + break;
|
| case PathSegMoveToAbs:
|
| - m_path.moveTo(segment.targetPoint);
|
| + emitMoveTo(
|
| + segment.targetPoint);
|
| + break;
|
| + case PathSegMoveToRel:
|
| + emitMoveTo(
|
| + m_currentPoint + segment.targetPoint);
|
| break;
|
| case PathSegLineToAbs:
|
| - m_path.addLineTo(segment.targetPoint);
|
| + emitLineTo(
|
| + segment.targetPoint);
|
| break;
|
| - case PathSegClosePath:
|
| - m_path.closeSubpath();
|
| + case PathSegLineToRel:
|
| + emitLineTo(
|
| + m_currentPoint + segment.targetPoint);
|
| + break;
|
| + case PathSegLineToHorizontalAbs:
|
| + emitLineTo(
|
| + FloatPoint(segment.targetPoint.x(), m_currentPoint.y()));
|
| + break;
|
| + case PathSegLineToHorizontalRel:
|
| + emitLineTo(
|
| + m_currentPoint + FloatSize(segment.targetPoint.x(), 0));
|
| + break;
|
| + case PathSegLineToVerticalAbs:
|
| + emitLineTo(
|
| + FloatPoint(m_currentPoint.x(), segment.targetPoint.y()));
|
| + break;
|
| + case PathSegLineToVerticalRel:
|
| + emitLineTo(
|
| + m_currentPoint + FloatSize(0, segment.targetPoint.y()));
|
| + break;
|
| + case PathSegCurveToQuadraticAbs:
|
| + emitQuadTo(
|
| + segment.point1,
|
| + segment.targetPoint);
|
| + break;
|
| + case PathSegCurveToQuadraticRel:
|
| + emitQuadTo(
|
| + m_currentPoint + segment.point1,
|
| + m_currentPoint + segment.targetPoint);
|
| + break;
|
| + case PathSegCurveToQuadraticSmoothAbs:
|
| + emitSmoothQuadTo(
|
| + segment.targetPoint);
|
| + break;
|
| + case PathSegCurveToQuadraticSmoothRel:
|
| + emitSmoothQuadTo(
|
| + m_currentPoint + segment.targetPoint);
|
| break;
|
| case PathSegCurveToCubicAbs:
|
| - m_path.addBezierCurveTo(segment.point1, segment.point2, segment.targetPoint);
|
| + emitCubicTo(
|
| + segment.point1,
|
| + segment.point2,
|
| + segment.targetPoint);
|
| + break;
|
| + case PathSegCurveToCubicRel:
|
| + emitCubicTo(
|
| + m_currentPoint + segment.point1,
|
| + m_currentPoint + segment.point2,
|
| + m_currentPoint + segment.targetPoint);
|
| + break;
|
| + case PathSegCurveToCubicSmoothAbs:
|
| + emitSmoothCubicTo(
|
| + segment.point2,
|
| + segment.targetPoint);
|
| + break;
|
| + case PathSegCurveToCubicSmoothRel:
|
| + emitSmoothCubicTo(
|
| + m_currentPoint + segment.point2,
|
| + m_currentPoint + segment.targetPoint);
|
| + break;
|
| + case PathSegArcAbs:
|
| + emitArcTo(
|
| + segment.targetPoint,
|
| + toFloatSize(segment.arcRadii()),
|
| + segment.arcAngle(),
|
| + segment.largeArcFlag(),
|
| + segment.sweepFlag());
|
| + break;
|
| + case PathSegArcRel:
|
| + emitArcTo(
|
| + m_currentPoint + segment.targetPoint,
|
| + toFloatSize(segment.arcRadii()),
|
| + segment.arcAngle(),
|
| + segment.largeArcFlag(),
|
| + segment.sweepFlag());
|
| break;
|
| default:
|
| ASSERT_NOT_REACHED();
|
| }
|
| +
|
| + m_lastCommand = segment.command;
|
| }
|
|
|
| }
|
|
|