diff options
Diffstat (limited to 'libs/hwui/utils/VectorDrawableUtils.cpp')
-rw-r--r-- | libs/hwui/utils/VectorDrawableUtils.cpp | 504 |
1 files changed, 233 insertions, 271 deletions
diff --git a/libs/hwui/utils/VectorDrawableUtils.cpp b/libs/hwui/utils/VectorDrawableUtils.cpp index 6f0c96db4b1e..1931d646fa4a 100644 --- a/libs/hwui/utils/VectorDrawableUtils.cpp +++ b/libs/hwui/utils/VectorDrawableUtils.cpp @@ -32,8 +32,8 @@ public: float ctrlPointY = 0; float currentSegmentStartX = 0; float currentSegmentStartY = 0; - void addCommand(SkPath* outPath, char previousCmd, - char cmd, const std::vector<float>* points, size_t start, size_t end); + void addCommand(SkPath* outPath, char previousCmd, char cmd, const std::vector<float>* points, + size_t start, size_t end); }; bool VectorDrawableUtils::canMorph(const PathData& morphFrom, const PathData& morphTo) { @@ -42,8 +42,8 @@ bool VectorDrawableUtils::canMorph(const PathData& morphFrom, const PathData& mo } for (unsigned int i = 0; i < morphFrom.verbs.size(); i++) { - if (morphFrom.verbs[i] != morphTo.verbs[i] - || morphFrom.verbSizes[i] != morphTo.verbSizes[i]) { + if (morphFrom.verbs[i] != morphTo.verbs[i] || + morphFrom.verbSizes[i] != morphTo.verbSizes[i]) { return false; } } @@ -51,7 +51,7 @@ bool VectorDrawableUtils::canMorph(const PathData& morphFrom, const PathData& mo } bool VectorDrawableUtils::interpolatePathData(PathData* outData, const PathData& morphFrom, - const PathData& morphTo, float fraction) { + const PathData& morphTo, float fraction) { if (!canMorph(morphFrom, morphTo)) { return false; } @@ -59,9 +59,9 @@ bool VectorDrawableUtils::interpolatePathData(PathData* outData, const PathData& return true; } - /** - * Convert an array of PathVerb to Path. - */ +/** +* Convert an array of PathVerb to Path. +*/ void VectorDrawableUtils::verbsToPath(SkPath* outPath, const PathData& data) { PathResolver resolver; char previousCommand = 'm'; @@ -70,7 +70,7 @@ void VectorDrawableUtils::verbsToPath(SkPath* outPath, const PathData& data) { for (unsigned int i = 0; i < data.verbs.size(); i++) { size_t verbSize = data.verbSizes[i]; resolver.addCommand(outPath, previousCommand, data.verbs[i], &data.points, start, - start + verbSize); + start + verbSize); previousCommand = data.verbs[i]; start += verbSize; } @@ -85,8 +85,8 @@ void VectorDrawableUtils::verbsToPath(SkPath* outPath, const PathData& data) { * @param nodeTo The end value as a PathVerb * @param fraction The fraction to interpolate. */ -void VectorDrawableUtils::interpolatePaths(PathData* outData, - const PathData& from, const PathData& to, float fraction) { +void VectorDrawableUtils::interpolatePaths(PathData* outData, const PathData& from, + const PathData& to, float fraction) { outData->points.resize(from.points.size()); outData->verbSizes = from.verbSizes; outData->verbs = from.verbs; @@ -110,16 +110,8 @@ void VectorDrawableUtils::interpolatePaths(PathData* outData, * @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) { +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 @@ -144,19 +136,13 @@ static void arcToBezier(SkPath* p, 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 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); + p->cubicTo((float)q1x, (float)q1y, (float)q2x, (float)q2y, (float)e2x, (float)e2y); eta1 = eta2; e1x = e2x; e1y = e2y; @@ -165,19 +151,12 @@ static void arcToBezier(SkPath* p, } } -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) { +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 */ @@ -204,9 +183,8 @@ static void drawArc(SkPath* p, 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); + 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); @@ -244,248 +222,232 @@ static void drawArc(SkPath* p, 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) { - +void PathResolver::addCommand(SkPath* outPath, char previousCmd, char cmd, + const std::vector<float>* points, size_t start, size_t end) { int incr = 2; float reflectiveCtrlPointX; float reflectiveCtrlPointY; switch (cmd) { - case 'z': - case 'Z': - outPath->close(); - // Path is closed here, but we need to move the pen to the - // closed position. So we cache the segment's starting position, - // and restore it here. - currentX = currentSegmentStartX; - currentY = currentSegmentStartY; - ctrlPointX = currentSegmentStartX; - ctrlPointY = currentSegmentStartY; - outPath->moveTo(currentX, currentY); - break; - case 'm': - case 'M': - case 'l': - case 'L': - case 't': - case 'T': - incr = 2; - break; - case 'h': - case 'H': - case 'v': - case 'V': - incr = 1; - break; - case 'c': - case 'C': - incr = 6; - break; - case 's': - case 'S': - case 'q': - case 'Q': - incr = 4; - break; - case 'a': - case 'A': - incr = 7; - break; - } - - for (unsigned int k = start; k < end; k += incr) { - switch (cmd) { - case 'm': // moveto - Start a new sub-path (relative) - currentX += points->at(k + 0); - currentY += points->at(k + 1); - if (k > start) { - // According to the spec, if a moveto is followed by multiple - // pairs of coordinates, the subsequent pairs are treated as - // implicit lineto commands. - outPath->rLineTo(points->at(k + 0), points->at(k + 1)); - } else { - outPath->rMoveTo(points->at(k + 0), points->at(k + 1)); - currentSegmentStartX = currentX; - currentSegmentStartY = currentY; - } + case 'z': + case 'Z': + outPath->close(); + // Path is closed here, but we need to move the pen to the + // closed position. So we cache the segment's starting position, + // and restore it here. + currentX = currentSegmentStartX; + currentY = currentSegmentStartY; + ctrlPointX = currentSegmentStartX; + ctrlPointY = currentSegmentStartY; + outPath->moveTo(currentX, currentY); break; - case 'M': // moveto - Start a new sub-path - currentX = points->at(k + 0); - currentY = points->at(k + 1); - if (k > start) { - // According to the spec, if a moveto is followed by multiple - // pairs of coordinates, the subsequent pairs are treated as - // implicit lineto commands. - outPath->lineTo(points->at(k + 0), points->at(k + 1)); - } else { - outPath->moveTo(points->at(k + 0), points->at(k + 1)); - currentSegmentStartX = currentX; - currentSegmentStartY = currentY; - } - break; - case 'l': // lineto - Draw a line from the current point (relative) - outPath->rLineTo(points->at(k + 0), points->at(k + 1)); - currentX += points->at(k + 0); - currentY += points->at(k + 1); + case 'm': + case 'M': + case 'l': + case 'L': + case 't': + case 'T': + incr = 2; break; - case 'L': // lineto - Draw a line from the current point - outPath->lineTo(points->at(k + 0), points->at(k + 1)); - currentX = points->at(k + 0); - currentY = points->at(k + 1); + case 'h': + case 'H': + case 'v': + case 'V': + incr = 1; break; - case 'h': // horizontal lineto - Draws a horizontal line (relative) - outPath->rLineTo(points->at(k + 0), 0); - currentX += points->at(k + 0); + case 'c': + case 'C': + incr = 6; break; - case 'H': // horizontal lineto - Draws a horizontal line - outPath->lineTo(points->at(k + 0), currentY); - currentX = points->at(k + 0); + case 's': + case 'S': + case 'q': + case 'Q': + incr = 4; break; - case 'v': // vertical lineto - Draws a vertical line from the current point (r) - outPath->rLineTo(0, points->at(k + 0)); - currentY += points->at(k + 0); + case 'a': + case 'A': + incr = 7; break; - case 'V': // vertical lineto - Draws a vertical line from the current point - outPath->lineTo(currentX, points->at(k + 0)); - currentY = points->at(k + 0); - break; - case 'c': // curveto - Draws a cubic Bézier curve (relative) - outPath->rCubicTo(points->at(k + 0), points->at(k + 1), points->at(k + 2), points->at(k + 3), - points->at(k + 4), points->at(k + 5)); - - ctrlPointX = currentX + points->at(k + 2); - ctrlPointY = currentY + points->at(k + 3); - currentX += points->at(k + 4); - currentY += points->at(k + 5); + } - break; - case 'C': // curveto - Draws a cubic Bézier curve - outPath->cubicTo(points->at(k + 0), points->at(k + 1), points->at(k + 2), points->at(k + 3), - points->at(k + 4), points->at(k + 5)); - currentX = points->at(k + 4); - currentY = points->at(k + 5); - ctrlPointX = points->at(k + 2); - ctrlPointY = points->at(k + 3); - break; - case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp) - reflectiveCtrlPointX = 0; - reflectiveCtrlPointY = 0; - if (previousCmd == 'c' || previousCmd == 's' - || previousCmd == 'C' || previousCmd == 'S') { - reflectiveCtrlPointX = currentX - ctrlPointX; - reflectiveCtrlPointY = currentY - ctrlPointY; - } - outPath->rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, - points->at(k + 0), points->at(k + 1), - points->at(k + 2), points->at(k + 3)); - ctrlPointX = currentX + points->at(k + 0); - ctrlPointY = currentY + points->at(k + 1); - currentX += points->at(k + 2); - currentY += points->at(k + 3); - break; - case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp) - reflectiveCtrlPointX = currentX; - reflectiveCtrlPointY = currentY; - if (previousCmd == 'c' || previousCmd == 's' - || previousCmd == 'C' || previousCmd == 'S') { - reflectiveCtrlPointX = 2 * currentX - ctrlPointX; - reflectiveCtrlPointY = 2 * currentY - ctrlPointY; - } - outPath->cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, - points->at(k + 0), points->at(k + 1), points->at(k + 2), points->at(k + 3)); - ctrlPointX = points->at(k + 0); - ctrlPointY = points->at(k + 1); - currentX = points->at(k + 2); - currentY = points->at(k + 3); - break; - case 'q': // Draws a quadratic Bézier (relative) - outPath->rQuadTo(points->at(k + 0), points->at(k + 1), points->at(k + 2), points->at(k + 3)); - ctrlPointX = currentX + points->at(k + 0); - ctrlPointY = currentY + points->at(k + 1); - currentX += points->at(k + 2); - currentY += points->at(k + 3); - break; - case 'Q': // Draws a quadratic Bézier - outPath->quadTo(points->at(k + 0), points->at(k + 1), points->at(k + 2), points->at(k + 3)); - ctrlPointX = points->at(k + 0); - ctrlPointY = points->at(k + 1); - currentX = points->at(k + 2); - currentY = points->at(k + 3); - break; - case 't': // Draws a quadratic Bézier curve(reflective control point)(relative) - reflectiveCtrlPointX = 0; - reflectiveCtrlPointY = 0; - if (previousCmd == 'q' || previousCmd == 't' - || previousCmd == 'Q' || previousCmd == 'T') { - reflectiveCtrlPointX = currentX - ctrlPointX; - reflectiveCtrlPointY = currentY - ctrlPointY; - } - outPath->rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, - points->at(k + 0), points->at(k + 1)); - ctrlPointX = currentX + reflectiveCtrlPointX; - ctrlPointY = currentY + reflectiveCtrlPointY; - currentX += points->at(k + 0); - currentY += points->at(k + 1); - break; - case 'T': // Draws a quadratic Bézier curve (reflective control point) - reflectiveCtrlPointX = currentX; - reflectiveCtrlPointY = currentY; - if (previousCmd == 'q' || previousCmd == 't' - || previousCmd == 'Q' || previousCmd == 'T') { - reflectiveCtrlPointX = 2 * currentX - ctrlPointX; - reflectiveCtrlPointY = 2 * currentY - ctrlPointY; - } - outPath->quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, - points->at(k + 0), points->at(k + 1)); - ctrlPointX = reflectiveCtrlPointX; - ctrlPointY = reflectiveCtrlPointY; - currentX = points->at(k + 0); - currentY = points->at(k + 1); - 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); - 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); - currentX = points->at(k + 5); - currentY = points->at(k + 6); - ctrlPointX = currentX; - ctrlPointY = currentY; - break; - default: - LOG_ALWAYS_FATAL("Unsupported command: %c", cmd); - break; + for (unsigned int k = start; k < end; k += incr) { + switch (cmd) { + case 'm': // moveto - Start a new sub-path (relative) + currentX += points->at(k + 0); + currentY += points->at(k + 1); + if (k > start) { + // According to the spec, if a moveto is followed by multiple + // pairs of coordinates, the subsequent pairs are treated as + // implicit lineto commands. + outPath->rLineTo(points->at(k + 0), points->at(k + 1)); + } else { + outPath->rMoveTo(points->at(k + 0), points->at(k + 1)); + currentSegmentStartX = currentX; + currentSegmentStartY = currentY; + } + break; + case 'M': // moveto - Start a new sub-path + currentX = points->at(k + 0); + currentY = points->at(k + 1); + if (k > start) { + // According to the spec, if a moveto is followed by multiple + // pairs of coordinates, the subsequent pairs are treated as + // implicit lineto commands. + outPath->lineTo(points->at(k + 0), points->at(k + 1)); + } else { + outPath->moveTo(points->at(k + 0), points->at(k + 1)); + currentSegmentStartX = currentX; + currentSegmentStartY = currentY; + } + break; + case 'l': // lineto - Draw a line from the current point (relative) + outPath->rLineTo(points->at(k + 0), points->at(k + 1)); + currentX += points->at(k + 0); + currentY += points->at(k + 1); + break; + case 'L': // lineto - Draw a line from the current point + outPath->lineTo(points->at(k + 0), points->at(k + 1)); + currentX = points->at(k + 0); + currentY = points->at(k + 1); + break; + case 'h': // horizontal lineto - Draws a horizontal line (relative) + outPath->rLineTo(points->at(k + 0), 0); + currentX += points->at(k + 0); + break; + case 'H': // horizontal lineto - Draws a horizontal line + outPath->lineTo(points->at(k + 0), currentY); + currentX = points->at(k + 0); + break; + case 'v': // vertical lineto - Draws a vertical line from the current point (r) + outPath->rLineTo(0, points->at(k + 0)); + currentY += points->at(k + 0); + break; + case 'V': // vertical lineto - Draws a vertical line from the current point + outPath->lineTo(currentX, points->at(k + 0)); + currentY = points->at(k + 0); + break; + case 'c': // curveto - Draws a cubic Bézier curve (relative) + outPath->rCubicTo(points->at(k + 0), points->at(k + 1), points->at(k + 2), + points->at(k + 3), points->at(k + 4), points->at(k + 5)); + + ctrlPointX = currentX + points->at(k + 2); + ctrlPointY = currentY + points->at(k + 3); + currentX += points->at(k + 4); + currentY += points->at(k + 5); + + break; + case 'C': // curveto - Draws a cubic Bézier curve + outPath->cubicTo(points->at(k + 0), points->at(k + 1), points->at(k + 2), + points->at(k + 3), points->at(k + 4), points->at(k + 5)); + currentX = points->at(k + 4); + currentY = points->at(k + 5); + ctrlPointX = points->at(k + 2); + ctrlPointY = points->at(k + 3); + break; + case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp) + reflectiveCtrlPointX = 0; + reflectiveCtrlPointY = 0; + if (previousCmd == 'c' || previousCmd == 's' || previousCmd == 'C' || + previousCmd == 'S') { + reflectiveCtrlPointX = currentX - ctrlPointX; + reflectiveCtrlPointY = currentY - ctrlPointY; + } + outPath->rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, points->at(k + 0), + points->at(k + 1), points->at(k + 2), points->at(k + 3)); + ctrlPointX = currentX + points->at(k + 0); + ctrlPointY = currentY + points->at(k + 1); + currentX += points->at(k + 2); + currentY += points->at(k + 3); + break; + case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp) + reflectiveCtrlPointX = currentX; + reflectiveCtrlPointY = currentY; + if (previousCmd == 'c' || previousCmd == 's' || previousCmd == 'C' || + previousCmd == 'S') { + reflectiveCtrlPointX = 2 * currentX - ctrlPointX; + reflectiveCtrlPointY = 2 * currentY - ctrlPointY; + } + outPath->cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, points->at(k + 0), + points->at(k + 1), points->at(k + 2), points->at(k + 3)); + ctrlPointX = points->at(k + 0); + ctrlPointY = points->at(k + 1); + currentX = points->at(k + 2); + currentY = points->at(k + 3); + break; + case 'q': // Draws a quadratic Bézier (relative) + outPath->rQuadTo(points->at(k + 0), points->at(k + 1), points->at(k + 2), + points->at(k + 3)); + ctrlPointX = currentX + points->at(k + 0); + ctrlPointY = currentY + points->at(k + 1); + currentX += points->at(k + 2); + currentY += points->at(k + 3); + break; + case 'Q': // Draws a quadratic Bézier + outPath->quadTo(points->at(k + 0), points->at(k + 1), points->at(k + 2), + points->at(k + 3)); + ctrlPointX = points->at(k + 0); + ctrlPointY = points->at(k + 1); + currentX = points->at(k + 2); + currentY = points->at(k + 3); + break; + case 't': // Draws a quadratic Bézier curve(reflective control point)(relative) + reflectiveCtrlPointX = 0; + reflectiveCtrlPointY = 0; + if (previousCmd == 'q' || previousCmd == 't' || previousCmd == 'Q' || + previousCmd == 'T') { + reflectiveCtrlPointX = currentX - ctrlPointX; + reflectiveCtrlPointY = currentY - ctrlPointY; + } + outPath->rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, points->at(k + 0), + points->at(k + 1)); + ctrlPointX = currentX + reflectiveCtrlPointX; + ctrlPointY = currentY + reflectiveCtrlPointY; + currentX += points->at(k + 0); + currentY += points->at(k + 1); + break; + case 'T': // Draws a quadratic Bézier curve (reflective control point) + reflectiveCtrlPointX = currentX; + reflectiveCtrlPointY = currentY; + if (previousCmd == 'q' || previousCmd == 't' || previousCmd == 'Q' || + previousCmd == 'T') { + reflectiveCtrlPointX = 2 * currentX - ctrlPointX; + reflectiveCtrlPointY = 2 * currentY - ctrlPointY; + } + outPath->quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, points->at(k + 0), + points->at(k + 1)); + ctrlPointX = reflectiveCtrlPointX; + ctrlPointY = reflectiveCtrlPointY; + currentX = points->at(k + 0); + currentY = points->at(k + 1); + 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); + 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); + currentX = points->at(k + 5); + currentY = points->at(k + 6); + ctrlPointX = currentX; + ctrlPointY = currentY; + break; + default: + LOG_ALWAYS_FATAL("Unsupported command: %c", cmd); + break; } previousCmd = cmd; } } -} // namespace uirenderer -} // namespace android +} // namespace uirenderer +} // namespace android |