Replace arcTo with three functions for it's overloads.

I found this to be about 15% faster on a benchmark designed to stress these functions.

https://github.com/flutter/flutter/issues/61305

Change-Id: I9dc2a8396e54c55464bb71562de0c07c853e829c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/303024
Reviewed-by: Kevin Lubick <kjlubick@google.com>
Commit-Queue: Nathaniel Nifong <nifong@google.com>
This commit is contained in:
Nathaniel Nifong 2020-07-15 16:46:17 -04:00 committed by Skia Commit-Bot
parent 89883ca559
commit d0c9d0cb7f
6 changed files with 76 additions and 22 deletions

View File

@ -22,6 +22,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
and when passed into CanvasKit will be used w/o copying the data (just like
`Malloc.toTypedArray`).
- `SkM44.setupCamera` to return a 4x4 matrix which sets up a perspective view from a camera.
- `SkPath.arcToOval`, `SkPath.arcToTangent`, and `SkPath.arcToRotated` to replace the three
overloads of `SkPath.arcTo`. https://github.com/flutter/flutter/issues/61305
### Changed
- In all places where color arrays are accepted (gradient makers, drawAtlas, and MakeSkVertices),
@ -39,6 +41,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Deprecated
- `CanvasKit.MakePathFromCmds` has been renamed to `CanvasKit.SkPath.MakeFromCmds`. The alias
will be removed in an upcoming release.
- `SkPath.arcTo` Separated into three functions.
## [0.16.2] - 2020-06-05

View File

@ -244,13 +244,12 @@ void ApplyAddRoundRect(SkPath& path, SkScalar left, SkScalar top,
ccw ? SkPathDirection::kCCW : SkPathDirection::kCW);
}
void ApplyArcTo(SkPath& p, SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
void ApplyArcToTangent(SkPath& p, SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
SkScalar radius) {
p.arcTo(x1, y1, x2, y2, radius);
}
void ApplyArcToAngle(SkPath& p, SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo) {
void ApplyArcToOval(SkPath& p, SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo) {
p.arcTo(oval, startAngle, sweepAngle, forceMoveTo);
}
@ -1470,9 +1469,9 @@ EMSCRIPTEN_BINDINGS(Skia) {
// interface.js has 4 overloads of addRoundRect
.function("_addRoundRect", &ApplyAddRoundRect)
.function("_addVerbsPointsWeights", &PathAddVerbsPointsWeights)
.function("_arcTo", &ApplyArcTo)
.function("_arcTo", &ApplyArcToAngle)
.function("_arcTo", &ApplyArcToArcSize)
.function("_arcToOval", &ApplyArcToOval)
.function("_arcToRotated", &ApplyArcToArcSize)
.function("_arcToTangent", ApplyArcToTangent)
.function("_close", &ApplyClose)
.function("_conicTo", &ApplyConicTo)
.function("countPoints", &SkPath::countPoints)

View File

@ -468,6 +468,9 @@ var CanvasKit = {
_addVerbsPointsWeights: function() {},
_arc: function() {},
_arcTo: function() {},
_arcToOval: function() {},
_arcToTangent: function() {},
_arcToRotated: function() {},
_close: function() {},
_conicTo: function() {},
_cubicTo: function() {},
@ -880,6 +883,9 @@ CanvasKit.SkPath.prototype.addRoundRect = function() {};
CanvasKit.SkPath.prototype.addVerbsPointsWeights = function() {};
CanvasKit.SkPath.prototype.arc = function() {};
CanvasKit.SkPath.prototype.arcTo = function() {};
CanvasKit.SkPath.prototype.arcToOval = function() {};
CanvasKit.SkPath.prototype.arcToTangent = function() {};
CanvasKit.SkPath.prototype.arcToRotated = function() {};
CanvasKit.SkPath.prototype.close = function() {};
CanvasKit.SkPath.prototype.conicTo = function() {};
CanvasKit.SkPath.prototype.cubicTo = function() {};

View File

@ -16,7 +16,7 @@ function arcTo(skpath, x1, y1, x2, y2, radius) {
if (skpath.isEmpty()) {
skpath.moveTo(x1, y1);
}
skpath.arcTo(x1, y1, x2, y2, radius);
skpath.arcToTangent(x1, y1, x2, y2, radius);
}
function bezierCurveTo(skpath, cp1x, cp1y, cp2x, cp2y, x, y) {
@ -50,11 +50,11 @@ function _ellipseHelper(skpath, x, y, radiusX, radiusY, startAngle, endAngle) {
// draws nothing.
if (almostEqual(Math.abs(sweepDegrees), 360)) {
var halfSweep = sweepDegrees/2;
skpath.arcTo(oval, startDegrees, halfSweep, false);
skpath.arcTo(oval, startDegrees + halfSweep, halfSweep, false);
skpath.arcToOval(oval, startDegrees, halfSweep, false);
skpath.arcToOval(oval, startDegrees + halfSweep, halfSweep, false);
return;
}
skpath.arcTo(oval, startDegrees, sweepDegrees, false);
skpath.arcToOval(oval, startDegrees, sweepDegrees, false);
}
function ellipse(skpath, x, y, radiusX, radiusY, rotation,

View File

@ -737,6 +737,7 @@ CanvasKit.onRuntimeInitialized = function() {
return this;
};
// Deprecated, use one of the three variants below depending on how many args you were calling it with.
CanvasKit.SkPath.prototype.arcTo = function() {
// takes 4, 5 or 7 args
// - 5 x1, y1, x2, y2, radius
@ -744,11 +745,11 @@ CanvasKit.onRuntimeInitialized = function() {
// - 7 rx, ry, xAxisRotate, useSmallArc, isCCW, x, y
var args = arguments;
if (args.length === 5) {
this._arcTo(args[0], args[1], args[2], args[3], args[4]);
this._arcToTangent(args[0], args[1], args[2], args[3], args[4]);
} else if (args.length === 4) {
this._arcTo(args[0], args[1], args[2], args[3]);
this._arcToOval(args[0], args[1], args[2], args[3]);
} else if (args.length === 7) {
this._arcTo(args[0], args[1], args[2], !!args[3], !!args[4], args[5], args[6]);
this._arcToRotated(args[0], args[1], args[2], !!args[3], !!args[4], args[5], args[6]);
} else {
throw 'Invalid args for arcTo. Expected 4, 5, or 7, got '+ args.length;
}
@ -756,6 +757,52 @@ CanvasKit.onRuntimeInitialized = function() {
return this;
};
// Appends arc to SkPath. Arc added is part of ellipse
// bounded by oval, from startAngle through sweepAngle. Both startAngle and
// sweepAngle are measured in degrees, where zero degrees is aligned with the
// positive x-axis, and positive sweeps extends arc clockwise.
CanvasKit.SkPath.prototype.arcToOval = function(oval, startAngle, sweepAngle, forceMoveTo) {
this._arcToOval(oval, startAngle, sweepAngle, forceMoveTo);
return this;
};
// Appends arc to SkPath. Arc is implemented by one or more conics weighted to
// describe part of oval with radii (rx, ry) rotated by xAxisRotate degrees. Arc
// curves from last SkPath SkPoint to (x, y), choosing one of four possible routes:
// clockwise or counterclockwise, and smaller or larger.
// Arc sweep is always less than 360 degrees. arcTo() appends line to (x, y) if
// either radii are zero, or if last SkPath SkPoint equals (x, y). arcTo() scales radii
// (rx, ry) to fit last SkPath SkPoint and (x, y) if both are greater than zero but
// too small.
// arcToRotated() appends up to four conic curves.
// arcToRotated() implements the functionality of SVG arc, although SVG sweep-flag value
// is opposite the integer value of sweep; SVG sweep-flag uses 1 for clockwise,
// while kCW_Direction cast to int is zero.
CanvasKit.SkPath.prototype.arcToRotated = function(rx, ry, xAxisRotate, useSmallArc, isCCW, x, y) {
this._arcToRotated(rx, ry, xAxisRotate, !!useSmallArc, !!isCCW, x, y);
return this;
};
// Appends arc to SkPath, after appending line if needed. Arc is implemented by conic
// weighted to describe part of circle. Arc is contained by tangent from
// last SkPath point to (x1, y1), and tangent from (x1, y1) to (x2, y2). Arc
// is part of circle sized to radius, positioned so it touches both tangent lines.
// If last Path Point does not start Arc, arcTo appends connecting Line to Path.
// The length of Vector from (x1, y1) to (x2, y2) does not affect Arc.
// Arc sweep is always less than 180 degrees. If radius is zero, or if
// tangents are nearly parallel, arcTo appends Line from last Path Point to (x1, y1).
// arcToTangent appends at most one Line and one conic.
// arcToTangent implements the functionality of PostScript arct and HTML Canvas arcTo.
CanvasKit.SkPath.prototype.arcToTangent = function(x1, y1, x2, y2, radius) {
this._arcToTangent(x1, y1, x2, y2, radius);
return this;
};
CanvasKit.SkPath.prototype.close = function() {
this._close();
return this;

View File

@ -37,7 +37,7 @@ describe('Path Behavior', () => {
path.lineTo(36, 148);
path.moveTo(150, 180);
path.arcTo(150, 100, 50, 200, 20);
path.arcToTangent(150, 100, 50, 200, 20);
path.lineTo(160, 160);
path.moveTo(20, 120);
@ -263,15 +263,14 @@ describe('Path Behavior', () => {
canvas.clear(CanvasKit.WHITE);
const path = new CanvasKit.SkPath();
//path.moveTo(5, 5);
// takes 4, 5 or 7 args
// - 5 x1, y1, x2, y2, radius
path.arcTo(40, 0, 40, 40, 40);
// - 4 oval (as Rect), startAngle, sweepAngle, forceMoveTo
path.arcTo(CanvasKit.LTRBRect(90, 10, 120, 200), 30, 300, true);
// - 7 rx, ry, xAxisRotate, useSmallArc, isCCW, x, y
// - x1, y1, x2, y2, radius
path.arcToTangent(40, 0, 40, 40, 40);
// - oval (as Rect), startAngle, sweepAngle, forceMoveTo
path.arcToOval(CanvasKit.LTRBRect(90, 10, 120, 200), 30, 300, true);
// - rx, ry, xAxisRotate, useSmallArc, isCCW, x, y
path.moveTo(5, 105);
path.arcTo(24, 24, 45, true, false, 82, 156);
path.arcToRotated(24, 24, 45, true, false, 82, 156);
canvas.drawPath(path, paint);