1804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu/* 2804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * Copyright (C) 2015 The Android Open Source Project 3804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * 4804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * Licensed under the Apache License, Version 2.0 (the "License"); 5804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * you may not use this file except in compliance with the License. 6804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * You may obtain a copy of the License at 7804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * 8804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * http://www.apache.org/licenses/LICENSE-2.0 9804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * 10804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * Unless required by applicable law or agreed to in writing, software 11804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * distributed under the License is distributed on an "AS IS" BASIS, 12804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * See the License for the specific language governing permissions and 14804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * limitations under the License. 15804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu */ 16804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 17804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu#include "VectorDrawableUtils.h" 18804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 19804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu#include "PathParser.h" 20804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 21804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu#include <math.h> 22804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu#include <utils/Log.h> 23804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 24804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liunamespace android { 25804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liunamespace uirenderer { 26804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 27804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liuclass PathResolver { 28804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liupublic: 29804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu float currentX = 0; 30804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu float currentY = 0; 31804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu float ctrlPointX = 0; 32804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu float ctrlPointY = 0; 33804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu float currentSegmentStartX = 0; 34804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu float currentSegmentStartY = 0; 35804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu void addCommand(SkPath* outPath, char previousCmd, 36804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu char cmd, const std::vector<float>* points, size_t start, size_t end); 37804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu}; 38804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 39804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liubool VectorDrawableUtils::canMorph(const PathData& morphFrom, const PathData& morphTo) { 40804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu if (morphFrom.verbs.size() != morphTo.verbs.size()) { 41804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu return false; 42804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } 43804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 44804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu for (unsigned int i = 0; i < morphFrom.verbs.size(); i++) { 45804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu if (morphFrom.verbs[i] != morphTo.verbs[i] 46804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu || morphFrom.verbSizes[i] != morphTo.verbSizes[i]) { 47804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu return false; 48804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } 49804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } 50804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu return true; 51804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu} 52804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 53804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liubool VectorDrawableUtils::interpolatePathData(PathData* outData, const PathData& morphFrom, 54804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu const PathData& morphTo, float fraction) { 55804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu if (!canMorph(morphFrom, morphTo)) { 56804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu return false; 57804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } 58804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu interpolatePaths(outData, morphFrom, morphTo, fraction); 59804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu return true; 60804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu} 61804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 62804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu /** 63804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * Convert an array of PathVerb to Path. 64804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu */ 65804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liuvoid VectorDrawableUtils::verbsToPath(SkPath* outPath, const PathData& data) { 66804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu PathResolver resolver; 67804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu char previousCommand = 'm'; 68804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu size_t start = 0; 69804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu outPath->reset(); 70804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu for (unsigned int i = 0; i < data.verbs.size(); i++) { 71804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu size_t verbSize = data.verbSizes[i]; 72804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu resolver.addCommand(outPath, previousCommand, data.verbs[i], &data.points, start, 73804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu start + verbSize); 74804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu previousCommand = data.verbs[i]; 75804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu start += verbSize; 76804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } 77804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu} 78804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 79804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu/** 80804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * The current PathVerb will be interpolated between the 81804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * <code>nodeFrom</code> and <code>nodeTo</code> according to the 82804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * <code>fraction</code>. 83804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * 84804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * @param nodeFrom The start value as a PathVerb. 85804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * @param nodeTo The end value as a PathVerb 86804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * @param fraction The fraction to interpolate. 87804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu */ 88804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liuvoid VectorDrawableUtils::interpolatePaths(PathData* outData, 89804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu const PathData& from, const PathData& to, float fraction) { 90804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu outData->points.resize(from.points.size()); 91804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu outData->verbSizes = from.verbSizes; 92804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu outData->verbs = from.verbs; 93804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 94804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu for (size_t i = 0; i < from.points.size(); i++) { 95804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu outData->points[i] = from.points[i] * (1 - fraction) + to.points[i] * fraction; 96804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } 97804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu} 98804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 99804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu/** 100804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * Converts an arc to cubic Bezier segments and records them in p. 101804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * 102804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * @param p The target for the cubic Bezier segments 103804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * @param cx The x coordinate center of the ellipse 104804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * @param cy The y coordinate center of the ellipse 105804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * @param a The radius of the ellipse in the horizontal direction 106804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * @param b The radius of the ellipse in the vertical direction 107804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * @param e1x E(eta1) x coordinate of the starting point of the arc 108804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * @param e1y E(eta2) y coordinate of the starting point of the arc 109804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * @param theta The angle that the ellipse bounding rectangle makes with horizontal plane 110804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * @param start The start angle of the arc on the ellipse 111804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse 112804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu */ 113804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liustatic void arcToBezier(SkPath* p, 114804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double cx, 115804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double cy, 116804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double a, 117804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double b, 118804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double e1x, 119804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double e1y, 120804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double theta, 121804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double start, 122804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double sweep) { 123804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu // Taken from equations at: http://spaceroots.org/documents/ellipse/node8.html 124804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu // and http://www.spaceroots.org/documents/ellipse/node22.html 125804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 126804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu // Maximum of 45 degrees per cubic Bezier segment 127804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu int numSegments = ceil(fabs(sweep * 4 / M_PI)); 128804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 129804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double eta1 = start; 130804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double cosTheta = cos(theta); 131804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double sinTheta = sin(theta); 132804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double cosEta1 = cos(eta1); 133804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double sinEta1 = sin(eta1); 134804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1); 135804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1); 136804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 137804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double anglePerSegment = sweep / numSegments; 138804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu for (int i = 0; i < numSegments; i++) { 139804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double eta2 = eta1 + anglePerSegment; 140804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double sinEta2 = sin(eta2); 141804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double cosEta2 = cos(eta2); 142804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double e2x = cx + (a * cosTheta * cosEta2) - (b * sinTheta * sinEta2); 143804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double e2y = cy + (a * sinTheta * cosEta2) + (b * cosTheta * sinEta2); 144804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2; 145804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2; 146804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double tanDiff2 = tan((eta2 - eta1) / 2); 147804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double alpha = 148804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu sin(eta2 - eta1) * (sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3; 149804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double q1x = e1x + alpha * ep1x; 150804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double q1y = e1y + alpha * ep1y; 151804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double q2x = e2x - alpha * ep2x; 152804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double q2y = e2y - alpha * ep2y; 153804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 154804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu p->cubicTo((float) q1x, 155804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu (float) q1y, 156804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu (float) q2x, 157804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu (float) q2y, 158804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu (float) e2x, 159804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu (float) e2y); 160804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu eta1 = eta2; 161804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu e1x = e2x; 162804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu e1y = e2y; 163804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ep1x = ep2x; 164804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ep1y = ep2y; 165804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } 166804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu} 167804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 168804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liuinline double toRadians(float theta) { return theta * M_PI / 180;} 169804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 170804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liustatic void drawArc(SkPath* p, 171804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu float x0, 172804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu float y0, 173804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu float x1, 174804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu float y1, 175804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu float a, 176804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu float b, 177804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu float theta, 178804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu bool isMoreThanHalf, 179804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu bool isPositiveArc) { 180804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 181804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu /* Convert rotation angle from degrees to radians */ 182804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double thetaD = toRadians(theta); 183804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu /* Pre-compute rotation matrix entries */ 184804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double cosTheta = cos(thetaD); 185804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double sinTheta = sin(thetaD); 186804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu /* Transform (x0, y0) and (x1, y1) into unit space */ 187804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu /* using (inverse) rotation, followed by (inverse) scale */ 188804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double x0p = (x0 * cosTheta + y0 * sinTheta) / a; 189804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double y0p = (-x0 * sinTheta + y0 * cosTheta) / b; 190804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double x1p = (x1 * cosTheta + y1 * sinTheta) / a; 191804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double y1p = (-x1 * sinTheta + y1 * cosTheta) / b; 192804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 193804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu /* Compute differences and averages */ 194804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double dx = x0p - x1p; 195804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double dy = y0p - y1p; 196804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double xm = (x0p + x1p) / 2; 197804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double ym = (y0p + y1p) / 2; 198804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu /* Solve for intersecting unit circles */ 199804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double dsq = dx * dx + dy * dy; 200804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu if (dsq == 0.0) { 20185d99528b23b5575d97f614fe25f839d19740abcTeng-Hui Zhu VECTOR_DRAWABLE_LOGD("Points are coincident"); 202804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu return; /* Points are coincident */ 203804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } 204804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double disc = 1.0 / dsq - 1.0 / 4.0; 205804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu if (disc < 0.0) { 20685d99528b23b5575d97f614fe25f839d19740abcTeng-Hui Zhu VECTOR_DRAWABLE_LOGD("Points are too far apart %f", dsq); 207804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu float adjust = (float) (sqrt(dsq) / 1.99999); 208804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu drawArc(p, x0, y0, x1, y1, a * adjust, 209804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu b * adjust, theta, isMoreThanHalf, isPositiveArc); 210804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu return; /* Points are too far apart */ 211804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } 212804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double s = sqrt(disc); 213804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double sdx = s * dx; 214804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double sdy = s * dy; 215804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double cx; 216804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double cy; 217804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu if (isMoreThanHalf == isPositiveArc) { 218804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu cx = xm - sdy; 219804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu cy = ym + sdx; 220804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } else { 221804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu cx = xm + sdy; 222804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu cy = ym - sdx; 223804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } 224804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 225804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double eta0 = atan2((y0p - cy), (x0p - cx)); 226804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 227804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double eta1 = atan2((y1p - cy), (x1p - cx)); 228804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 229804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double sweep = (eta1 - eta0); 230804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu if (isPositiveArc != (sweep >= 0)) { 231804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu if (sweep > 0) { 232804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu sweep -= 2 * M_PI; 233804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } else { 234804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu sweep += 2 * M_PI; 235804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } 236804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } 237804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 238804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu cx *= a; 239804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu cy *= b; 240804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu double tcx = cx; 241804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu cx = cx * cosTheta - cy * sinTheta; 242804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu cy = tcx * sinTheta + cy * cosTheta; 243804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 244804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep); 245804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu} 246804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 247804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 248804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 249804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu// Use the given verb, and points in the range [start, end) to insert a command into the SkPath. 250804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liuvoid PathResolver::addCommand(SkPath* outPath, char previousCmd, 251804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu char cmd, const std::vector<float>* points, size_t start, size_t end) { 252804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 253804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu int incr = 2; 254804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu float reflectiveCtrlPointX; 255804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu float reflectiveCtrlPointY; 256804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 257804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu switch (cmd) { 258804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'z': 259804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'Z': 260804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu outPath->close(); 261804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu // Path is closed here, but we need to move the pen to the 262804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu // closed position. So we cache the segment's starting position, 263804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu // and restore it here. 264804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentX = currentSegmentStartX; 265804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentY = currentSegmentStartY; 266804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ctrlPointX = currentSegmentStartX; 267804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ctrlPointY = currentSegmentStartY; 268804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu outPath->moveTo(currentX, currentY); 269804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu break; 270804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'm': 271804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'M': 272804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'l': 273804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'L': 274804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 't': 275804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'T': 276804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu incr = 2; 277804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu break; 278804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'h': 279804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'H': 280804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'v': 281804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'V': 282804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu incr = 1; 283804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu break; 284804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'c': 285804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'C': 286804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu incr = 6; 287804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu break; 288804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 's': 289804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'S': 290804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'q': 291804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'Q': 292804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu incr = 4; 293804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu break; 294804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'a': 295804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'A': 296804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu incr = 7; 297804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu break; 298804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } 299804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 300804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu for (unsigned int k = start; k < end; k += incr) { 301804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu switch (cmd) { 302804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'm': // moveto - Start a new sub-path (relative) 303804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentX += points->at(k + 0); 304804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentY += points->at(k + 1); 305804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu if (k > start) { 306804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu // According to the spec, if a moveto is followed by multiple 307804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu // pairs of coordinates, the subsequent pairs are treated as 308804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu // implicit lineto commands. 309804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu outPath->rLineTo(points->at(k + 0), points->at(k + 1)); 310804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } else { 311804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu outPath->rMoveTo(points->at(k + 0), points->at(k + 1)); 312804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentSegmentStartX = currentX; 313804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentSegmentStartY = currentY; 314804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } 315804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu break; 316804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'M': // moveto - Start a new sub-path 317804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentX = points->at(k + 0); 318804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentY = points->at(k + 1); 319804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu if (k > start) { 320804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu // According to the spec, if a moveto is followed by multiple 321804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu // pairs of coordinates, the subsequent pairs are treated as 322804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu // implicit lineto commands. 323804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu outPath->lineTo(points->at(k + 0), points->at(k + 1)); 324804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } else { 325804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu outPath->moveTo(points->at(k + 0), points->at(k + 1)); 326804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentSegmentStartX = currentX; 327804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentSegmentStartY = currentY; 328804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } 329804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu break; 330804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'l': // lineto - Draw a line from the current point (relative) 331804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu outPath->rLineTo(points->at(k + 0), points->at(k + 1)); 332804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentX += points->at(k + 0); 333804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentY += points->at(k + 1); 334804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu break; 335804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'L': // lineto - Draw a line from the current point 336804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu outPath->lineTo(points->at(k + 0), points->at(k + 1)); 337804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentX = points->at(k + 0); 338804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentY = points->at(k + 1); 339804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu break; 340804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'h': // horizontal lineto - Draws a horizontal line (relative) 341804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu outPath->rLineTo(points->at(k + 0), 0); 342804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentX += points->at(k + 0); 343804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu break; 344804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'H': // horizontal lineto - Draws a horizontal line 345804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu outPath->lineTo(points->at(k + 0), currentY); 346804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentX = points->at(k + 0); 347804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu break; 348804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'v': // vertical lineto - Draws a vertical line from the current point (r) 349804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu outPath->rLineTo(0, points->at(k + 0)); 350804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentY += points->at(k + 0); 351804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu break; 352804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'V': // vertical lineto - Draws a vertical line from the current point 353804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu outPath->lineTo(currentX, points->at(k + 0)); 354804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentY = points->at(k + 0); 355804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu break; 356804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'c': // curveto - Draws a cubic Bézier curve (relative) 357804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu outPath->rCubicTo(points->at(k + 0), points->at(k + 1), points->at(k + 2), points->at(k + 3), 358804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu points->at(k + 4), points->at(k + 5)); 359804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 360804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ctrlPointX = currentX + points->at(k + 2); 361804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ctrlPointY = currentY + points->at(k + 3); 362804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentX += points->at(k + 4); 363804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentY += points->at(k + 5); 364804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 365804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu break; 366804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'C': // curveto - Draws a cubic Bézier curve 367804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu outPath->cubicTo(points->at(k + 0), points->at(k + 1), points->at(k + 2), points->at(k + 3), 368804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu points->at(k + 4), points->at(k + 5)); 369804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentX = points->at(k + 4); 370804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentY = points->at(k + 5); 371804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ctrlPointX = points->at(k + 2); 372804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ctrlPointY = points->at(k + 3); 373804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu break; 374804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp) 375804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu reflectiveCtrlPointX = 0; 376804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu reflectiveCtrlPointY = 0; 377804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu if (previousCmd == 'c' || previousCmd == 's' 378804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu || previousCmd == 'C' || previousCmd == 'S') { 379804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu reflectiveCtrlPointX = currentX - ctrlPointX; 380804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu reflectiveCtrlPointY = currentY - ctrlPointY; 381804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } 382804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu outPath->rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, 383804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu points->at(k + 0), points->at(k + 1), 384804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu points->at(k + 2), points->at(k + 3)); 385804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ctrlPointX = currentX + points->at(k + 0); 386804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ctrlPointY = currentY + points->at(k + 1); 387804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentX += points->at(k + 2); 388804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentY += points->at(k + 3); 389804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu break; 390804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp) 391804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu reflectiveCtrlPointX = currentX; 392804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu reflectiveCtrlPointY = currentY; 393804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu if (previousCmd == 'c' || previousCmd == 's' 394804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu || previousCmd == 'C' || previousCmd == 'S') { 395804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu reflectiveCtrlPointX = 2 * currentX - ctrlPointX; 396804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu reflectiveCtrlPointY = 2 * currentY - ctrlPointY; 397804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } 398804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu outPath->cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, 399804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu points->at(k + 0), points->at(k + 1), points->at(k + 2), points->at(k + 3)); 400804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ctrlPointX = points->at(k + 0); 401804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ctrlPointY = points->at(k + 1); 402804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentX = points->at(k + 2); 403804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentY = points->at(k + 3); 404804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu break; 405804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'q': // Draws a quadratic Bézier (relative) 406804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu outPath->rQuadTo(points->at(k + 0), points->at(k + 1), points->at(k + 2), points->at(k + 3)); 407804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ctrlPointX = currentX + points->at(k + 0); 408804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ctrlPointY = currentY + points->at(k + 1); 409804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentX += points->at(k + 2); 410804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentY += points->at(k + 3); 411804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu break; 412804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'Q': // Draws a quadratic Bézier 413804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu outPath->quadTo(points->at(k + 0), points->at(k + 1), points->at(k + 2), points->at(k + 3)); 414804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ctrlPointX = points->at(k + 0); 415804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ctrlPointY = points->at(k + 1); 416804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentX = points->at(k + 2); 417804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentY = points->at(k + 3); 418804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu break; 419804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 't': // Draws a quadratic Bézier curve(reflective control point)(relative) 420804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu reflectiveCtrlPointX = 0; 421804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu reflectiveCtrlPointY = 0; 422804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu if (previousCmd == 'q' || previousCmd == 't' 423804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu || previousCmd == 'Q' || previousCmd == 'T') { 424804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu reflectiveCtrlPointX = currentX - ctrlPointX; 425804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu reflectiveCtrlPointY = currentY - ctrlPointY; 426804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } 427804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu outPath->rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, 428804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu points->at(k + 0), points->at(k + 1)); 429804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ctrlPointX = currentX + reflectiveCtrlPointX; 430804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ctrlPointY = currentY + reflectiveCtrlPointY; 431804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentX += points->at(k + 0); 432804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentY += points->at(k + 1); 433804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu break; 434804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'T': // Draws a quadratic Bézier curve (reflective control point) 435804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu reflectiveCtrlPointX = currentX; 436804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu reflectiveCtrlPointY = currentY; 437804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu if (previousCmd == 'q' || previousCmd == 't' 438804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu || previousCmd == 'Q' || previousCmd == 'T') { 439804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu reflectiveCtrlPointX = 2 * currentX - ctrlPointX; 440804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu reflectiveCtrlPointY = 2 * currentY - ctrlPointY; 441804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } 442804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu outPath->quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, 443804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu points->at(k + 0), points->at(k + 1)); 444804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ctrlPointX = reflectiveCtrlPointX; 445804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ctrlPointY = reflectiveCtrlPointY; 446804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentX = points->at(k + 0); 447804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentY = points->at(k + 1); 448804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu break; 449804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'a': // Draws an elliptical arc 450804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu // (rx ry x-axis-rotation large-arc-flag sweep-flag x y) 451804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu drawArc(outPath, 452804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentX, 453804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentY, 454804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu points->at(k + 5) + currentX, 455804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu points->at(k + 6) + currentY, 456804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu points->at(k + 0), 457804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu points->at(k + 1), 458804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu points->at(k + 2), 459804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu points->at(k + 3) != 0, 460804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu points->at(k + 4) != 0); 461804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentX += points->at(k + 5); 462804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentY += points->at(k + 6); 463804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ctrlPointX = currentX; 464804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ctrlPointY = currentY; 465804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu break; 466804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu case 'A': // Draws an elliptical arc 467804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu drawArc(outPath, 468804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentX, 469804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentY, 470804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu points->at(k + 5), 471804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu points->at(k + 6), 472804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu points->at(k + 0), 473804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu points->at(k + 1), 474804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu points->at(k + 2), 475804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu points->at(k + 3) != 0, 476804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu points->at(k + 4) != 0); 477804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentX = points->at(k + 5); 478804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu currentY = points->at(k + 6); 479804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ctrlPointX = currentX; 480804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu ctrlPointY = currentY; 481804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu break; 482804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu default: 483804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu LOG_ALWAYS_FATAL("Unsupported command: %c", cmd); 484804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu break; 485804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } 486804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu previousCmd = cmd; 487804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu } 488804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu} 489804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu 490804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu} // namespace uirenderer 491804618d0863a5d8ad1b08a846bd5319be864a1cbDoris Liu} // namespace android 492