gfx/skia/trunk/src/animator/SkParseSVGPath.cpp

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

michael@0 1
michael@0 2 /*
michael@0 3 * Copyright 2006 The Android Open Source Project
michael@0 4 *
michael@0 5 * Use of this source code is governed by a BSD-style license that can be
michael@0 6 * found in the LICENSE file.
michael@0 7 */
michael@0 8
michael@0 9
michael@0 10 #include <ctype.h>
michael@0 11 #include "SkDrawPath.h"
michael@0 12 #include "SkParse.h"
michael@0 13 #include "SkPoint.h"
michael@0 14 #include "SkUtils.h"
michael@0 15 #define QUADRATIC_APPROXIMATION 1
michael@0 16
michael@0 17 #if QUADRATIC_APPROXIMATION
michael@0 18 ////////////////////////////////////////////////////////////////////////////////////
michael@0 19 //functions to approximate a cubic using two quadratics
michael@0 20
michael@0 21 // midPt sets the first argument to be the midpoint of the other two
michael@0 22 // it is used by quadApprox
michael@0 23 static inline void midPt(SkPoint& dest,const SkPoint& a,const SkPoint& b)
michael@0 24 {
michael@0 25 dest.set(SkScalarAve(a.fX, b.fX),SkScalarAve(a.fY, b.fY));
michael@0 26 }
michael@0 27 // quadApprox - makes an approximation, which we hope is faster
michael@0 28 static void quadApprox(SkPath &fPath, const SkPoint &p0, const SkPoint &p1, const SkPoint &p2)
michael@0 29 {
michael@0 30 //divide the cubic up into two cubics, then convert them into quadratics
michael@0 31 //define our points
michael@0 32 SkPoint c,j,k,l,m,n,o,p,q, mid;
michael@0 33 fPath.getLastPt(&c);
michael@0 34 midPt(j, p0, c);
michael@0 35 midPt(k, p0, p1);
michael@0 36 midPt(l, p1, p2);
michael@0 37 midPt(o, j, k);
michael@0 38 midPt(p, k, l);
michael@0 39 midPt(q, o, p);
michael@0 40 //compute the first half
michael@0 41 m.set(SkScalarHalf(3*j.fX - c.fX), SkScalarHalf(3*j.fY - c.fY));
michael@0 42 n.set(SkScalarHalf(3*o.fX -q.fX), SkScalarHalf(3*o.fY - q.fY));
michael@0 43 midPt(mid,m,n);
michael@0 44 fPath.quadTo(mid,q);
michael@0 45 c = q;
michael@0 46 //compute the second half
michael@0 47 m.set(SkScalarHalf(3*p.fX - c.fX), SkScalarHalf(3*p.fY - c.fY));
michael@0 48 n.set(SkScalarHalf(3*l.fX -p2.fX),SkScalarHalf(3*l.fY -p2.fY));
michael@0 49 midPt(mid,m,n);
michael@0 50 fPath.quadTo(mid,p2);
michael@0 51 }
michael@0 52 #endif
michael@0 53
michael@0 54
michael@0 55 static inline bool is_between(int c, int min, int max)
michael@0 56 {
michael@0 57 return (unsigned)(c - min) <= (unsigned)(max - min);
michael@0 58 }
michael@0 59
michael@0 60 static inline bool is_ws(int c)
michael@0 61 {
michael@0 62 return is_between(c, 1, 32);
michael@0 63 }
michael@0 64
michael@0 65 static inline bool is_digit(int c)
michael@0 66 {
michael@0 67 return is_between(c, '0', '9');
michael@0 68 }
michael@0 69
michael@0 70 static inline bool is_sep(int c)
michael@0 71 {
michael@0 72 return is_ws(c) || c == ',';
michael@0 73 }
michael@0 74
michael@0 75 static const char* skip_ws(const char str[])
michael@0 76 {
michael@0 77 SkASSERT(str);
michael@0 78 while (is_ws(*str))
michael@0 79 str++;
michael@0 80 return str;
michael@0 81 }
michael@0 82
michael@0 83 static const char* skip_sep(const char str[])
michael@0 84 {
michael@0 85 SkASSERT(str);
michael@0 86 while (is_sep(*str))
michael@0 87 str++;
michael@0 88 return str;
michael@0 89 }
michael@0 90
michael@0 91 static const char* find_points(const char str[], SkPoint value[], int count,
michael@0 92 bool isRelative, SkPoint* relative)
michael@0 93 {
michael@0 94 str = SkParse::FindScalars(str, &value[0].fX, count * 2);
michael@0 95 if (isRelative) {
michael@0 96 for (int index = 0; index < count; index++) {
michael@0 97 value[index].fX += relative->fX;
michael@0 98 value[index].fY += relative->fY;
michael@0 99 }
michael@0 100 }
michael@0 101 return str;
michael@0 102 }
michael@0 103
michael@0 104 static const char* find_scalar(const char str[], SkScalar* value,
michael@0 105 bool isRelative, SkScalar relative)
michael@0 106 {
michael@0 107 str = SkParse::FindScalar(str, value);
michael@0 108 if (isRelative)
michael@0 109 *value += relative;
michael@0 110 return str;
michael@0 111 }
michael@0 112
michael@0 113 void SkDrawPath::parseSVG() {
michael@0 114 fPath.reset();
michael@0 115 const char* data = d.c_str();
michael@0 116 SkPoint f = {0, 0};
michael@0 117 SkPoint c = {0, 0};
michael@0 118 SkPoint lastc = {0, 0};
michael@0 119 SkPoint points[3];
michael@0 120 char op = '\0';
michael@0 121 char previousOp = '\0';
michael@0 122 bool relative = false;
michael@0 123 do {
michael@0 124 data = skip_ws(data);
michael@0 125 if (data[0] == '\0')
michael@0 126 break;
michael@0 127 char ch = data[0];
michael@0 128 if (is_digit(ch) || ch == '-' || ch == '+') {
michael@0 129 if (op == '\0')
michael@0 130 return;
michael@0 131 }
michael@0 132 else {
michael@0 133 op = ch;
michael@0 134 relative = false;
michael@0 135 if (islower(op)) {
michael@0 136 op = (char) toupper(op);
michael@0 137 relative = true;
michael@0 138 }
michael@0 139 data++;
michael@0 140 data = skip_sep(data);
michael@0 141 }
michael@0 142 switch (op) {
michael@0 143 case 'M':
michael@0 144 data = find_points(data, points, 1, relative, &c);
michael@0 145 fPath.moveTo(points[0]);
michael@0 146 op = 'L';
michael@0 147 c = points[0];
michael@0 148 break;
michael@0 149 case 'L':
michael@0 150 data = find_points(data, points, 1, relative, &c);
michael@0 151 fPath.lineTo(points[0]);
michael@0 152 c = points[0];
michael@0 153 break;
michael@0 154 case 'H': {
michael@0 155 SkScalar x;
michael@0 156 data = find_scalar(data, &x, relative, c.fX);
michael@0 157 fPath.lineTo(x, c.fY);
michael@0 158 c.fX = x;
michael@0 159 }
michael@0 160 break;
michael@0 161 case 'V': {
michael@0 162 SkScalar y;
michael@0 163 data = find_scalar(data, &y, relative, c.fY);
michael@0 164 fPath.lineTo(c.fX, y);
michael@0 165 c.fY = y;
michael@0 166 }
michael@0 167 break;
michael@0 168 case 'C':
michael@0 169 data = find_points(data, points, 3, relative, &c);
michael@0 170 goto cubicCommon;
michael@0 171 case 'S':
michael@0 172 data = find_points(data, &points[1], 2, relative, &c);
michael@0 173 points[0] = c;
michael@0 174 if (previousOp == 'C' || previousOp == 'S') {
michael@0 175 points[0].fX -= lastc.fX - c.fX;
michael@0 176 points[0].fY -= lastc.fY - c.fY;
michael@0 177 }
michael@0 178 cubicCommon:
michael@0 179 // if (data[0] == '\0')
michael@0 180 // return;
michael@0 181 #if QUADRATIC_APPROXIMATION
michael@0 182 quadApprox(fPath, points[0], points[1], points[2]);
michael@0 183 #else //this way just does a boring, slow old cubic
michael@0 184 fPath.cubicTo(points[0], points[1], points[2]);
michael@0 185 #endif
michael@0 186 //if we are using the quadApprox, lastc is what it would have been if we had used
michael@0 187 //cubicTo
michael@0 188 lastc = points[1];
michael@0 189 c = points[2];
michael@0 190 break;
michael@0 191 case 'Q': // Quadratic Bezier Curve
michael@0 192 data = find_points(data, points, 2, relative, &c);
michael@0 193 goto quadraticCommon;
michael@0 194 case 'T':
michael@0 195 data = find_points(data, &points[1], 1, relative, &c);
michael@0 196 points[0] = points[1];
michael@0 197 if (previousOp == 'Q' || previousOp == 'T') {
michael@0 198 points[0].fX = c.fX * 2 - lastc.fX;
michael@0 199 points[0].fY = c.fY * 2 - lastc.fY;
michael@0 200 }
michael@0 201 quadraticCommon:
michael@0 202 fPath.quadTo(points[0], points[1]);
michael@0 203 lastc = points[0];
michael@0 204 c = points[1];
michael@0 205 break;
michael@0 206 case 'Z':
michael@0 207 fPath.close();
michael@0 208 #if 0 // !!! still a bug?
michael@0 209 if (fPath.isEmpty() && (f.fX != 0 || f.fY != 0)) {
michael@0 210 c.fX -= SkScalar.Epsilon; // !!! enough?
michael@0 211 fPath.moveTo(c);
michael@0 212 fPath.lineTo(f);
michael@0 213 fPath.close();
michael@0 214 }
michael@0 215 #endif
michael@0 216 c = f;
michael@0 217 op = '\0';
michael@0 218 break;
michael@0 219 case '~': {
michael@0 220 SkPoint args[2];
michael@0 221 data = find_points(data, args, 2, false, NULL);
michael@0 222 fPath.moveTo(args[0].fX, args[0].fY);
michael@0 223 fPath.lineTo(args[1].fX, args[1].fY);
michael@0 224 }
michael@0 225 break;
michael@0 226 default:
michael@0 227 SkASSERT(0);
michael@0 228 return;
michael@0 229 }
michael@0 230 if (previousOp == 0)
michael@0 231 f = c;
michael@0 232 previousOp = op;
michael@0 233 } while (data[0] > 0);
michael@0 234 }

mercurial