summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Derek Sollenberger <djsollen@google.com> 2017-12-05 15:39:30 -0500
committer Derek Sollenberger <djsollen@google.com> 2017-12-05 15:39:30 -0500
commit12f9b0664219f4c8adf5013496feb5c718acbef5 (patch)
treef53520786e88ba405d6b19e2be616a352918fa77
parent1beccb0fc230d9e2030ad951d483fb0026ea2d49 (diff)
Update VectorDrawables to use Skia's drawArc implementation.
Using Skia enables drawArc to issue conic draw calls as well as fixes some of the issues around a scaled path containing a drawArc being reported as concave. Bug: 69622768 Test: hwui_unit_tests Change-Id: I4faab5403ec4ee34e1ad6fae256ae9ad3c6bb05b
-rw-r--r--libs/hwui/tests/unit/VectorDrawableTests.cpp45
-rw-r--r--libs/hwui/utils/VectorDrawableUtils.cpp140
2 files changed, 11 insertions, 174 deletions
diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp
index a92cbfdf6757..e7496f707318 100644
--- a/libs/hwui/tests/unit/VectorDrawableTests.cpp
+++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp
@@ -85,32 +85,8 @@ const static TestData sTestDataSet[] = {
outPath->rCubicTo(8.0, 8.0, 8.0, 8.0, 8.0, 8.0);
outPath->cubicTo(16.0, 16.0, 9.0, 9.0, 9.0, 9.0);
outPath->rCubicTo(0.0, 0.0, 9.0, 9.0, 9.0, 9.0);
- outPath->cubicTo(18.447775037328352, 20.404243860300607, 17.998389141249767,
- 22.8911717921705, 16.737515350332117, 24.986664170401575);
- outPath->cubicTo(15.476641559414468, 27.08215654863265, 13.489843598291483,
- 28.644011882390082, 11.155893964798905, 29.37447073281729);
- outPath->cubicTo(8.821944331306327, 30.1049295832445, 6.299226382436471,
- 29.954422532383525, 4.0686829203897235, 28.951642951534332);
- outPath->cubicTo(1.838139458342976, 27.94886337068514, 0.05113662931485696,
- 26.161860541657013, -0.9516429515343354, 23.931317079610267);
- outPath->cubicTo(-1.9544225323835278, 21.70077361756352, -2.1049295832444987,
- 19.178055668693663, -1.37447073281729, 16.844106035201087);
- outPath->cubicTo(-0.6440118823900814, 14.51015640170851, 0.9178434513673546,
- 12.523358440585524, 3.0133358295984305, 11.262484649667876);
- outPath->cubicTo(5.108828207829506, 10.001610858750228, 7.5957561396993984,
- 9.552224962671648, 10.000000000000005, 10.0);
- outPath->cubicTo(10.0, 7.348852265086975, 11.054287646850167, 4.803576729418881,
- 12.928932188134523, 2.9289321881345254);
- outPath->cubicTo(14.803576729418879, 1.0542876468501696, 17.348852265086972,
- 4.870079381441987E-16, 19.999999999999996, 0.0);
- outPath->cubicTo(22.65114773491302, -4.870079381441987E-16, 25.19642327058112,
- 1.0542876468501678, 27.071067811865476, 2.9289321881345227);
- outPath->cubicTo(28.94571235314983, 4.803576729418878, 30.0, 7.348852265086974, 30.0,
- 9.999999999999998);
- outPath->cubicTo(30.0, 12.651147734913023, 28.94571235314983, 15.19642327058112,
- 27.071067811865476, 17.071067811865476);
- outPath->cubicTo(25.19642327058112, 18.94571235314983, 22.651147734913028, 20.0,
- 20.000000000000004, 20.0);
+ outPath->arcTo(10.0, 10.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCW_Direction, 10.0, 10.0);
+ outPath->arcTo(10.0, 10.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCW_Direction, 20.0, 20.0);
}},
// Check box VectorDrawable path data
@@ -181,22 +157,7 @@ const static TestData sTestDataSet[] = {
},
[](SkPath* outPath) {
outPath->moveTo(300.0, 70.0);
- outPath->cubicTo(239.06697794203706, 70.13246340443499, 180.6164396449267,
- 94.47383115953485, 137.6004913602211, 137.6302781499585);
- outPath->cubicTo(94.58454307551551, 180.78672514038215, 70.43390412842275,
- 239.3163266242308, 70.50013586976587, 300.2494566687817);
- outPath->cubicTo(70.56636761110899, 361.1825867133326, 94.84418775550249,
- 419.65954850554147, 137.9538527586204, 462.72238058830936);
- outPath->cubicTo(181.06351776173827, 505.7852126710772, 239.5668339599056,
- 529.999456521097, 300.49999999999994, 529.999456521097);
- outPath->cubicTo(361.43316604009436, 529.999456521097, 419.93648223826176,
- 505.78521267107726, 463.0461472413797, 462.7223805883093);
- outPath->cubicTo(506.1558122444976, 419.65954850554135, 530.433632388891,
- 361.1825867133324, 530.4998641302341, 300.2494566687815);
- outPath->cubicTo(530.5660958715771, 239.31632662423056, 506.4154569244844,
- 180.7867251403819, 463.3995086397787, 137.6302781499583);
- outPath->cubicTo(420.383560355073, 94.47383115953468, 361.93302205796255,
- 70.13246340443492, 300.9999999999996, 70.00000000000003);
+ outPath->arcTo(230.0, 230.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCCW_Direction, 301.0, 70.0);
outPath->close();
outPath->moveTo(300.0, 70.0);
}},
diff --git a/libs/hwui/utils/VectorDrawableUtils.cpp b/libs/hwui/utils/VectorDrawableUtils.cpp
index 1931d646fa4a..6b8f3154dd36 100644
--- a/libs/hwui/utils/VectorDrawableUtils.cpp
+++ b/libs/hwui/utils/VectorDrawableUtils.cpp
@@ -96,132 +96,6 @@ void VectorDrawableUtils::interpolatePaths(PathData* outData, const PathData& fr
}
}
-/**
- * Converts an arc to cubic Bezier segments and records them in p.
- *
- * @param p The target for the cubic Bezier segments
- * @param cx The x coordinate center of the ellipse
- * @param cy The y coordinate center of the ellipse
- * @param a The radius of the ellipse in the horizontal direction
- * @param b The radius of the ellipse in the vertical direction
- * @param e1x E(eta1) x coordinate of the starting point of the arc
- * @param e1y E(eta2) y coordinate of the starting point of the arc
- * @param theta The angle that the ellipse bounding rectangle makes with horizontal plane
- * @param start The start angle of the arc on the ellipse
- * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse
- */
-static void arcToBezier(SkPath* p, double cx, double cy, double a, double b, double e1x, double e1y,
- double theta, double start, double sweep) {
- // Taken from equations at: http://spaceroots.org/documents/ellipse/node8.html
- // and http://www.spaceroots.org/documents/ellipse/node22.html
-
- // Maximum of 45 degrees per cubic Bezier segment
- int numSegments = ceil(fabs(sweep * 4 / M_PI));
-
- double eta1 = start;
- double cosTheta = cos(theta);
- double sinTheta = sin(theta);
- double cosEta1 = cos(eta1);
- double sinEta1 = sin(eta1);
- double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1);
- double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1);
-
- double anglePerSegment = sweep / numSegments;
- for (int i = 0; i < numSegments; i++) {
- double eta2 = eta1 + anglePerSegment;
- double sinEta2 = sin(eta2);
- double cosEta2 = cos(eta2);
- double e2x = cx + (a * cosTheta * cosEta2) - (b * sinTheta * sinEta2);
- double e2y = cy + (a * sinTheta * cosEta2) + (b * cosTheta * sinEta2);
- double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2;
- double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2;
- double tanDiff2 = tan((eta2 - eta1) / 2);
- double alpha = sin(eta2 - eta1) * (sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3;
- double q1x = e1x + alpha * ep1x;
- double q1y = e1y + alpha * ep1y;
- double q2x = e2x - alpha * ep2x;
- double q2y = e2y - alpha * ep2y;
-
- p->cubicTo((float)q1x, (float)q1y, (float)q2x, (float)q2y, (float)e2x, (float)e2y);
- eta1 = eta2;
- e1x = e2x;
- e1y = e2y;
- ep1x = ep2x;
- ep1y = ep2y;
- }
-}
-
-inline double toRadians(float theta) {
- return theta * M_PI / 180;
-}
-
-static void drawArc(SkPath* p, float x0, float y0, float x1, float y1, float a, float b,
- float theta, bool isMoreThanHalf, bool isPositiveArc) {
- /* Convert rotation angle from degrees to radians */
- double thetaD = toRadians(theta);
- /* Pre-compute rotation matrix entries */
- double cosTheta = cos(thetaD);
- double sinTheta = sin(thetaD);
- /* Transform (x0, y0) and (x1, y1) into unit space */
- /* using (inverse) rotation, followed by (inverse) scale */
- double x0p = (x0 * cosTheta + y0 * sinTheta) / a;
- double y0p = (-x0 * sinTheta + y0 * cosTheta) / b;
- double x1p = (x1 * cosTheta + y1 * sinTheta) / a;
- double y1p = (-x1 * sinTheta + y1 * cosTheta) / b;
-
- /* Compute differences and averages */
- double dx = x0p - x1p;
- double dy = y0p - y1p;
- double xm = (x0p + x1p) / 2;
- double ym = (y0p + y1p) / 2;
- /* Solve for intersecting unit circles */
- double dsq = dx * dx + dy * dy;
- if (dsq == 0.0) {
- VECTOR_DRAWABLE_LOGD("Points are coincident");
- return; /* Points are coincident */
- }
- double disc = 1.0 / dsq - 1.0 / 4.0;
- if (disc < 0.0) {
- VECTOR_DRAWABLE_LOGD("Points are too far apart %f", dsq);
- float adjust = (float)(sqrt(dsq) / 1.99999);
- drawArc(p, x0, y0, x1, y1, a * adjust, b * adjust, theta, isMoreThanHalf, isPositiveArc);
- return; /* Points are too far apart */
- }
- double s = sqrt(disc);
- double sdx = s * dx;
- double sdy = s * dy;
- double cx;
- double cy;
- if (isMoreThanHalf == isPositiveArc) {
- cx = xm - sdy;
- cy = ym + sdx;
- } else {
- cx = xm + sdy;
- cy = ym - sdx;
- }
-
- double eta0 = atan2((y0p - cy), (x0p - cx));
-
- double eta1 = atan2((y1p - cy), (x1p - cx));
-
- double sweep = (eta1 - eta0);
- if (isPositiveArc != (sweep >= 0)) {
- if (sweep > 0) {
- sweep -= 2 * M_PI;
- } else {
- sweep += 2 * M_PI;
- }
- }
-
- cx *= a;
- cy *= b;
- double tcx = cx;
- cx = cx * cosTheta - cy * sinTheta;
- cy = tcx * sinTheta + cy * cosTheta;
-
- arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep);
-}
-
// Use the given verb, and points in the range [start, end) to insert a command into the SkPath.
void PathResolver::addCommand(SkPath* outPath, char previousCmd, char cmd,
const std::vector<float>* points, size_t start, size_t end) {
@@ -424,18 +298,20 @@ void PathResolver::addCommand(SkPath* outPath, char previousCmd, char cmd,
break;
case 'a': // Draws an elliptical arc
// (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
- drawArc(outPath, currentX, currentY, points->at(k + 5) + currentX,
- points->at(k + 6) + currentY, points->at(k + 0), points->at(k + 1),
- points->at(k + 2), points->at(k + 3) != 0, points->at(k + 4) != 0);
+ outPath->arcTo(points->at(k + 0), points->at(k + 1), points->at(k + 2),
+ (SkPath::ArcSize) (points->at(k + 3) != 0),
+ (SkPath::Direction) (points->at(k + 4) == 0),
+ points->at(k + 5) + currentX, points->at(k + 6) + currentY);
currentX += points->at(k + 5);
currentY += points->at(k + 6);
ctrlPointX = currentX;
ctrlPointY = currentY;
break;
case 'A': // Draws an elliptical arc
- drawArc(outPath, currentX, currentY, points->at(k + 5), points->at(k + 6),
- points->at(k + 0), points->at(k + 1), points->at(k + 2),
- points->at(k + 3) != 0, points->at(k + 4) != 0);
+ outPath->arcTo(points->at(k + 0), points->at(k + 1), points->at(k + 2),
+ (SkPath::ArcSize) (points->at(k + 3) != 0),
+ (SkPath::Direction) (points->at(k + 4) == 0),
+ points->at(k + 5), points->at(k + 6));
currentX = points->at(k + 5);
currentY = points->at(k + 6);
ctrlPointX = currentX;