diff options
author | fmalita <fmalita@chromium.org> | 2016-01-25 15:16:47 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-01-25 23:17:33 +0000 |
commit | 7003bed16de3861e47d6bb0287ba4d6bffcfea04 (patch) | |
tree | 2f17cb95c20e25d50a7b32c33d434f5062a268b6 | |
parent | bf571b6dcf58bd8a28fdd5e15b4428e5c2a0b44f (diff) | |
download | chromium_src-7003bed16de3861e47d6bb0287ba4d6bffcfea04.zip chromium_src-7003bed16de3861e47d6bb0287ba4d6bffcfea04.tar.gz chromium_src-7003bed16de3861e47d6bb0287ba4d6bffcfea04.tar.bz2 |
[SVG] Paint unnormalized paths
The SkPath API supports all SVG path verbs, so there's no need to
normalize paths when converting to the Skia representation.
Switch buildPathFromString() and buildPathFromByteStream() to unaltered
parsing, and expand SVGPathBuilder to handle the full path vocabulary.
This yields a more natural verb conversion (arcTo, in particular, is no
longer decomposed into cubics), with correctness and perf implications.
BUG=453040
R=fs@opera.com,caryclark@google.com
Review URL: https://codereview.chromium.org/1623073003
Cr-Commit-Position: refs/heads/master@{#371345}
7 files changed, 235 insertions, 14 deletions
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 8b501ae..e747e0e 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations @@ -131,7 +131,8 @@ crbug.com/463358 [ Mac Linux Debug ] fast/backgrounds/transformed-body-html-back crbug.com/463358 [ Mac Linux Debug ] css3/masking/clip-path-polygon-nonzero.html [ Failure ] crbug.com/463358 [ Mac Linux ] fast/transforms/transformed-caret.html [ Pass Failure ] crbug.com/463358 [ Mac Linux Debug ] fast/backgrounds/transformed-body-background.html [ Failure ] -crbug.com/463358 [ Mac Linux Debug ] svg/W3C-SVG-1.1/paths-data-02-t.svg [ Failure ] +# TODO(fmalita): Re-enable after https://codereview.chromium.org/1623073003/ +# crbug.com/463358 [ Mac Linux Debug ] svg/W3C-SVG-1.1/paths-data-02-t.svg [ Failure ] crbug.com/463358 [ Mac Linux Debug ] css3/masking/clip-path-polygon.html [ Failure ] crbug.com/267206 [ Mac ] virtual/rootlayerscrolls/fast/scrolling/scrollbar-tickmarks-hittest.html [ Timeout ] @@ -1250,8 +1251,6 @@ crbug.com/521730 [ Win10 ] media/track/track-cue-rendering-vertical.html [ Failu crbug.com/521730 [ Win10 ] fast/css/line-height-determined-by-primary-font.html [ Failure ] crbug.com/521730 [ Win10 ] fast/forms/month/month-appearance-l10n.html [ Failure ] crbug.com/521730 [ Win10 ] fast/forms/month/month-appearance-pseudo-elements.html [ Failure ] -# TODO(fmalita): re-enable after http://crrev.com/1410733003 -# crbug.com/521730 [ Win10 ] fast/forms/search/search-appearance-basic.html [ Failure ] crbug.com/521730 [ Win10 ] fast/inline/justify-emphasis-inline-box.html [ Failure ] crbug.com/521730 [ Win10 ] fast/ruby/nested-ruby.html [ Failure ] crbug.com/521730 [ Win10 ] fast/text-autosizing/display-type-change.html [ Failure ] @@ -1442,7 +1441,6 @@ crbug.com/568778 [ XP ] media/video-overlay-cast-light-rendering.html [ Failure crbug.com/568778 [ XP ] media/video-transformed.html [ Failure ] crbug.com/568778 [ XP ] svg/wicd/test-rightsizing-a.xhtml [ Failure ] crbug.com/568778 [ XP ] svg/zoom/page/zoom-hixie-mixed-009.xml [ Failure ] -crbug.com/568778 [ XP ] svg/zoom/page/zoom-img-preserveAspectRatio-support-1.html [ Failure ] crbug.com/568778 [ XP ] svg/zoom/page/zoom-replaced-intrinsic-ratio-001.htm [ Failure ] crbug.com/568778 [ XP ] svg/zoom/page/zoom-svg-through-object-with-auto-size.html [ Failure ] crbug.com/568778 [ XP ] svg/zoom/page/zoom-svg-through-object-with-huge-size.xhtml [ Failure ] @@ -1553,6 +1551,29 @@ crbug.com/568559 [ Android Linux Win ] fast/text/international/bidi-menulist.htm crbug.com/568559 [ Android Linux Win ] fast/text/international/pop-up-button-text-alignment-and-direction.html [ NeedsRebaseline ] crbug.com/568559 [ Android Linux Win ] fast/forms/select-popup/popup-menu-appearance-texttransform.html [ NeedsRebaseline ] +# https://codereview.chromium.org/1623073003/ +crbug.com/453040 svg/W3C-SVG-1.1/animate-elem-37-t.svg [ NeedsRebaseline ] +crbug.com/453040 svg/W3C-SVG-1.1/animate-elem-40-t.svg [ NeedsRebaseline ] +crbug.com/453040 svg/W3C-SVG-1.1/animate-elem-83-t.svg [ NeedsRebaseline ] +crbug.com/453040 svg/W3C-SVG-1.1/coords-viewattr-03-b.svg [ NeedsRebaseline ] +crbug.com/453040 svg/W3C-SVG-1.1/extend-namespace-01-f.svg [ NeedsRebaseline ] +crbug.com/453040 svg/W3C-SVG-1.1/fonts-elem-03-b.svg [ NeedsRebaseline ] +crbug.com/453040 svg/W3C-SVG-1.1/fonts-elem-04-b.svg [ NeedsRebaseline ] +crbug.com/453040 svg/W3C-SVG-1.1/fonts-elem-07-b.svg [ NeedsRebaseline ] +crbug.com/453040 svg/W3C-SVG-1.1/painting-marker-03-f.svg [ NeedsRebaseline ] +crbug.com/453040 svg/W3C-SVG-1.1/paths-data-02-t.svg [ NeedsRebaseline ] +crbug.com/453040 svg/W3C-SVG-1.1/paths-data-03-f.svg [ NeedsRebaseline ] +crbug.com/453040 svg/as-background-image/background-image-preserveaspectRatio-support.html [ NeedsRebaseline ] +crbug.com/453040 svg/as-background-image/svg-as-background-6.html [ NeedsRebaseline ] +crbug.com/453040 svg/as-image/img-preserveAspectRatio-support-1.html [ NeedsRebaseline ] +crbug.com/453040 svg/carto.net/tabgroup.svg [ NeedsRebaseline ] +crbug.com/453040 svg/custom/control-points-for-S-and-T.svg [ NeedsRebaseline ] +crbug.com/453040 svg/custom/relative-sized-inner-svg.xhtml [ NeedsRebaseline ] +crbug.com/453040 svg/custom/relative-sized-use-on-symbol.xhtml [ NeedsRebaseline ] +crbug.com/453040 svg/custom/relative-sized-use-without-attributes-on-symbol.xhtml [ NeedsRebaseline ] +crbug.com/453040 svg/custom/use-on-symbol-inside-pattern.svg [ NeedsRebaseline ] +crbug.com/453040 svg/zoom/page/zoom-img-preserveAspectRatio-support-1.html [ NeedsRebaseline ] + crbug.com/569950 svg/batik/filters/feTile.svg [ NeedsRebaseline ] crbug.com/569950 svg/filters/feTile.svg [ NeedsRebaseline ] diff --git a/third_party/WebKit/Source/core/layout/svg/SVGMarkerData.h b/third_party/WebKit/Source/core/layout/svg/SVGMarkerData.h index 878c45b..5dec45f 100644 --- a/third_party/WebKit/Source/core/layout/svg/SVGMarkerData.h +++ b/third_party/WebKit/Source/core/layout/svg/SVGMarkerData.h @@ -137,7 +137,8 @@ private: switch (element->type) { case PathElementAddQuadCurveToPoint: - // FIXME: https://bugs.webkit.org/show_bug.cgi?id=33115 (PathElementAddQuadCurveToPoint not handled for <marker>) + m_inslopePoints[0] = points[0]; + m_inslopePoints[1] = points[1]; m_origin = points[1]; break; case PathElementAddCurveToPoint: diff --git a/third_party/WebKit/Source/core/svg/SVGPathBuilder.cpp b/third_party/WebKit/Source/core/svg/SVGPathBuilder.cpp index 32e47dd..0fcd338 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; } } // namespace blink diff --git a/third_party/WebKit/Source/core/svg/SVGPathBuilder.h b/third_party/WebKit/Source/core/svg/SVGPathBuilder.h index 6cbe279..522bee4 100644 --- a/third_party/WebKit/Source/core/svg/SVGPathBuilder.h +++ b/third_party/WebKit/Source/core/svg/SVGPathBuilder.h @@ -25,19 +25,42 @@ #define SVGPathBuilder_h #include "core/svg/SVGPathConsumer.h" +#include "core/svg/SVGPathData.h" +#include "platform/geometry/FloatPoint.h" namespace blink { +class FloatSize; class Path; class SVGPathBuilder final : public SVGPathConsumer { public: - SVGPathBuilder(Path& path) : m_path(path) { } + SVGPathBuilder(Path& path) + : m_path(path) + // Starting in ClosePath state ensures correct handling of the first moveTo. + , m_lastCommand(PathSegClosePath) + { } private: void emitSegment(const PathSegmentData&) override; + void emitClose(); + void emitMoveTo(const FloatPoint&); + void emitLineTo(const FloatPoint&); + void emitQuadTo(const FloatPoint&, const FloatPoint&); + void emitSmoothQuadTo(const FloatPoint&); + void emitCubicTo(const FloatPoint&, const FloatPoint&, const FloatPoint&); + void emitSmoothCubicTo(const FloatPoint&, const FloatPoint&); + void emitArcTo(const FloatPoint&, const FloatSize&, float, bool largeArc, bool sweep); + + FloatPoint smoothControl(bool isSmooth) const; + Path& m_path; + + SVGPathSegType m_lastCommand; + FloatPoint m_subpathPoint; + FloatPoint m_currentPoint; + FloatPoint m_lastControlPoint; }; } // namespace blink diff --git a/third_party/WebKit/Source/core/svg/SVGPathUtilities.cpp b/third_party/WebKit/Source/core/svg/SVGPathUtilities.cpp index a4b9ddb..259bf0e 100644 --- a/third_party/WebKit/Source/core/svg/SVGPathUtilities.cpp +++ b/third_party/WebKit/Source/core/svg/SVGPathUtilities.cpp @@ -36,7 +36,7 @@ bool buildPathFromString(const String& d, Path& result) SVGPathBuilder builder(result); SVGPathStringSource source(d); SVGPathParser parser(&source, &builder); - return parser.parsePathDataFromSource(NormalizedParsing); + return parser.parsePathDataFromSource(UnalteredParsing); } bool buildPathFromByteStream(const SVGPathByteStream& stream, Path& result) @@ -47,7 +47,7 @@ bool buildPathFromByteStream(const SVGPathByteStream& stream, Path& result) SVGPathBuilder builder(result); SVGPathByteStreamSource source(stream); SVGPathParser parser(&source, &builder); - return parser.parsePathDataFromSource(NormalizedParsing); + return parser.parsePathDataFromSource(UnalteredParsing); } String buildStringFromByteStream(const SVGPathByteStream& stream) diff --git a/third_party/WebKit/Source/platform/graphics/Path.cpp b/third_party/WebKit/Source/platform/graphics/Path.cpp index c54308e..f18b2f2 100644 --- a/third_party/WebKit/Source/platform/graphics/Path.cpp +++ b/third_party/WebKit/Source/platform/graphics/Path.cpp @@ -331,6 +331,16 @@ void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius) m_path.arcTo(p1.data(), p2.data(), WebCoreFloatToSkScalar(radius)); } +void Path::addArcTo(const FloatPoint& p, const FloatSize& r, float xRotate, bool largeArc, bool sweep) +{ + m_path.arcTo( + WebCoreFloatToSkScalar(r.width()), WebCoreFloatToSkScalar(r.height()), + WebCoreFloatToSkScalar(xRotate), + largeArc ? SkPath::kLarge_ArcSize : SkPath::kSmall_ArcSize, + sweep ? SkPath::kCW_Direction : SkPath::kCCW_Direction, + WebCoreFloatToSkScalar(p.x()), WebCoreFloatToSkScalar(p.y())); +} + void Path::closeSubpath() { m_path.close(); diff --git a/third_party/WebKit/Source/platform/graphics/Path.h b/third_party/WebKit/Source/platform/graphics/Path.h index f2a4f72..c46b5ac 100644 --- a/third_party/WebKit/Source/platform/graphics/Path.h +++ b/third_party/WebKit/Source/platform/graphics/Path.h @@ -122,6 +122,7 @@ public: void addQuadCurveTo(const FloatPoint& controlPoint, const FloatPoint& endPoint); void addBezierCurveTo(const FloatPoint& controlPoint1, const FloatPoint& controlPoint2, const FloatPoint& endPoint); void addArcTo(const FloatPoint&, const FloatPoint&, float radius); + void addArcTo(const FloatPoint&, const FloatSize& r, float xRotate, bool largeArc, bool sweep); void closeSubpath(); void addArc(const FloatPoint&, float radius, float startAngle, float endAngle, bool anticlockwise); |