OLD | NEW |
| (Empty) |
1 #include <ctype.h> | |
2 #include "SkPath.h" | |
3 #include "SkParse.h" | |
4 #include "SkPoint.h" | |
5 #include "SkUtils.h" | |
6 #define QUADRATIC_APPROXIMATION 0 | |
7 | |
8 const char logoStr[] = | |
9 "<path fill=\"#0081C6\"" | |
10 "d=\"M440.51,289.479c1.623,1.342,5.01,4.164,5.01,9.531c0,5.223-2.965,7.697-5
.93,10.024" | |
11 "c-0.918,0.916-1.977,1.907-1.977,3.462c0,1.551,1.059,2.397,1.834,3.035l2.545
,1.973c3.105,2.613,5.928,5.016,5.928,9.889" | |
12 "c0,6.635-6.426,13.341-18.566,13.341c-10.238,0-15.178-4.87-15.178-10.097c0-2
.543,1.268-6.139,5.438-8.613" | |
13 "c4.373-2.682,10.307-3.033,13.482-3.249c-0.99-1.271-2.119-2.61-2.119-4.798c0
-1.199,0.355-1.907,0.707-2.754" | |
14 "c-0.779,0.07-1.553,0.141-2.26,0.141c-7.482,0-11.719-5.579-11.719-11.082c0-3
.247,1.484-6.851,4.518-9.461" | |
15 "c4.025-3.318,8.824-3.883,12.639-3.883h14.541l-4.518,2.541H440.51z" | |
16 "M435.494,320.826c-0.562-0.072-0.916-0.072-1.619-0.072" | |
17 "c-0.637,0-4.451,0.143-7.416,1.132c-1.553,0.564-6.07,2.257-6.07,7.271c0,5.01
3,4.873,8.615,12.426,8.615" | |
18 "c6.775,0,10.379-3.253,10.379-7.624C443.193,326.54,440.863,324.64,435.494,32
0.826z" | |
19 "M437.543,307.412" | |
20 "c1.623-1.627,1.764-3.883,1.764-5.154c0-5.083-3.035-12.99-8.893-12.99c-1.838
,0-3.812,0.918-4.945,2.331" | |
21 "c-1.199,1.483-1.551,3.387-1.551,5.225c0,4.729,2.754,12.565,8.826,12.565C434
.508,309.389,436.41,308.543,437.543,307.412z\"/>" | |
22 "<path fill=\"#FFD200\"" | |
23 "d=\"M396.064,319.696c-11.206,0-17.198-8.739-17.198-16.636c0-9.233,7.542-17.
126,18.258-17.126" | |
24 "c10.357,0,16.844,8.104,16.844,16.635C413.969,310.884,407.557,319.696,396.06
4,319.696z" | |
25 "M404.873,313.987" | |
26 "c1.695-2.257,2.119-5.074,2.119-7.826c0-6.202-2.961-18.042-11.701-18.042c-2.
326,0-4.652,0.918-6.342,2.399" | |
27 "c-2.749,2.465-3.245,5.566-3.245,8.599c0,6.977,3.454,18.463,11.984,18.463C40
0.436,317.58,403.256,316.242,404.873,313.987z\"/>" | |
28 "<path fill=\"#ED174F\"" | |
29 "d=\"M357.861,319.696c-11.207,0-17.199-8.739-17.199-16.636c0-9.233,7.544-17.
126,18.258-17.126" | |
30 "c10.359,0,16.845,8.104,16.845,16.635C375.764,310.884,369.351,319.696,357.86
1,319.696z" | |
31 "M366.671,313.987" | |
32 "c1.693-2.257,2.116-5.074,2.116-7.826c0-6.202-2.961-18.042-11.701-18.042c-2.
325,0-4.652,0.918-6.344,2.399" | |
33 "c-2.749,2.465-3.241,5.566-3.241,8.599c0,6.977,3.452,18.463,11.983,18.463C36
2.234,317.58,365.053,316.242,366.671,313.987z\"/>" | |
34 "<path fill=\"#0081C6\"" | |
35 "d=\"M335.278,318.591l-10.135,2.339c-4.111,0.638-7.795,1.204-11.69,1.204" | |
36 "c-19.56,0-26.998-14.386-26.998-25.654c0-13.746,10.558-26.498,28.629-26.498c
3.827,0,7.51,0.564,10.839,1.486" | |
37 "c5.316,1.488,7.796,3.331,9.355,4.394l-5.883,5.599l-2.479,0.565l1.771-2.837c
-2.408-2.336-6.805-6.658-15.164-6.658" | |
38 "c-11.196,0-19.63,8.507-19.63,20.906c0,13.319,9.638,25.861,25.084,25.861c4.5
39,0,6.874-0.918,9-1.771v-11.407l-10.698,0.566" | |
39 "l5.667-3.047h15.023l-1.841,1.77c-0.5,0.424-0.567,0.57-0.71,1.133c-0.073,0.6
4-0.141,2.695-0.141,3.403V318.591z\"/>" | |
40 "<path fill=\"#49A942\"" | |
41 "d=\"M462.908,316.552c-2.342-0.214-2.832-0.638-2.832-3.401v-0.782v-39.327c0.
014-0.153,0.025-0.31,0.041-0.457" | |
42 "c0.283-2.479,0.992-2.903,3.189-4.182h-10.135l-5.316,2.552h5.418v0.032l-0.00
4-0.024v41.406v2.341" | |
43 "c0,1.416-0.281,1.629-1.912,3.753H463.9l2.623-1.557C465.318,316.763,464.113,
316.692,462.908,316.552z\"/>" | |
44 "<path fill=\"#ED174F\"" | |
45 "d=\"M491.742,317.203c-0.771,0.422-1.547,0.916-2.318,1.268c-2.326,1.055-4.71
9,1.336-6.83,1.336" | |
46 "c-2.25,0-5.77-0.143-9.361-2.744c-4.992-3.521-7.176-9.572-7.176-14.851c0-10.
906,8.869-16.255,16.115-16.255" | |
47 "c2.533,0,5.141,0.633,7.252,1.972c3.516,2.318,4.43,5.344,4.922,6.963l-16.535
,6.688l-5.422,0.422" | |
48 "c1.758,8.938,7.812,14.145,14.498,14.145c3.59,0,6.193-1.266,8.586-2.461L491.
742,317.203z" | |
49 "M485.129,296.229" | |
50 "c1.336-0.493,2.039-0.914,2.039-1.899c0-2.812-3.166-6.053-6.967-6.053c-2.818
,0-8.094,2.183-8.094,9.783" | |
51 "c0,1.197,0.141,2.464,0.213,3.73L485.129,296.229z\"/>" | |
52 "<path fill=\"#77787B\"" | |
53 "d=\"M498.535,286.439v4.643h-0.564v-4.643h-1.537v-0.482h3.637v0.482H498.535z
\"/>" | |
54 "<path fill=\"#77787B\"" | |
55 "d=\"M504.863,291.082v-4.687h-0.023l-1.432,4.687h-0.439l-1.443-4.687h-0.02v4
.687h-0.512v-5.125h0.877" | |
56 "l1.307,4.143h0.018l1.285-4.143h0.891v5.125H504.863z\"/>" | |
57 ; | |
58 | |
59 size_t logoStrLen = sizeof(logoStr); | |
60 | |
61 #if QUADRATIC_APPROXIMATION | |
62 ////////////////////////////////////////////////////////////////////////////////
//// | |
63 //functions to approximate a cubic using two quadratics | |
64 | |
65 // midPt sets the first argument to be the midpoint of the other two | |
66 // it is used by quadApprox | |
67 static inline void midPt(SkPoint& dest,const SkPoint& a,const SkPoint& b) | |
68 { | |
69 dest.set(SkScalarAve(a.fX, b.fX),SkScalarAve(a.fY, b.fY)); | |
70 } | |
71 // quadApprox - makes an approximation, which we hope is faster | |
72 static void quadApprox(SkPath &fPath, const SkPoint &p0, const SkPoint &p1, cons
t SkPoint &p2) | |
73 { | |
74 //divide the cubic up into two cubics, then convert them into quadratics | |
75 //define our points | |
76 SkPoint c,j,k,l,m,n,o,p,q, mid; | |
77 fPath.getLastPt(&c); | |
78 midPt(j, p0, c); | |
79 midPt(k, p0, p1); | |
80 midPt(l, p1, p2); | |
81 midPt(o, j, k); | |
82 midPt(p, k, l); | |
83 midPt(q, o, p); | |
84 //compute the first half | |
85 m.set(SkScalarHalf(3*j.fX - c.fX), SkScalarHalf(3*j.fY - c.fY)); | |
86 n.set(SkScalarHalf(3*o.fX -q.fX), SkScalarHalf(3*o.fY - q.fY)); | |
87 midPt(mid,m,n); | |
88 fPath.quadTo(mid,q); | |
89 c = q; | |
90 //compute the second half | |
91 m.set(SkScalarHalf(3*p.fX - c.fX), SkScalarHalf(3*p.fY - c.fY)); | |
92 n.set(SkScalarHalf(3*l.fX -p2.fX),SkScalarHalf(3*l.fY -p2.fY)); | |
93 midPt(mid,m,n); | |
94 fPath.quadTo(mid,p2); | |
95 } | |
96 #endif | |
97 | |
98 | |
99 static inline bool is_between(int c, int min, int max) | |
100 { | |
101 return (unsigned)(c - min) <= (unsigned)(max - min); | |
102 } | |
103 | |
104 static inline bool is_ws(int c) | |
105 { | |
106 return is_between(c, 1, 32); | |
107 } | |
108 | |
109 static inline bool is_digit(int c) | |
110 { | |
111 return is_between(c, '0', '9'); | |
112 } | |
113 | |
114 static inline bool is_sep(int c) | |
115 { | |
116 return is_ws(c) || c == ','; | |
117 } | |
118 | |
119 static const char* skip_ws(const char str[]) | |
120 { | |
121 SkASSERT(str); | |
122 while (is_ws(*str)) | |
123 str++; | |
124 return str; | |
125 } | |
126 | |
127 static const char* skip_sep(const char str[]) | |
128 { | |
129 SkASSERT(str); | |
130 while (is_sep(*str)) | |
131 str++; | |
132 return str; | |
133 } | |
134 | |
135 static const char* find_points(const char str[], SkPoint value[], int count, | |
136 bool isRelative, SkPoint* relative) | |
137 { | |
138 str = SkParse::FindScalars(str, &value[0].fX, count * 2); | |
139 if (isRelative) { | |
140 for (int index = 0; index < count; index++) { | |
141 value[index].fX += relative->fX; | |
142 value[index].fY += relative->fY; | |
143 } | |
144 } | |
145 return str; | |
146 } | |
147 | |
148 static const char* find_scalar(const char str[], SkScalar* value, | |
149 bool isRelative, SkScalar relative) | |
150 { | |
151 str = SkParse::FindScalar(str, value); | |
152 if (isRelative) | |
153 *value += relative; | |
154 return str; | |
155 } | |
156 | |
157 static void showPathContour(SkPath::Iter& iter) { | |
158 uint8_t verb; | |
159 SkPoint pts[4]; | |
160 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { | |
161 switch (verb) { | |
162 case SkPath::kMove_Verb: | |
163 SkDebugf("path.moveTo(%1.9gf,%1.9gf);\n", pts[0].fX, pts[0].fY); | |
164 continue; | |
165 case SkPath::kLine_Verb: | |
166 SkDebugf("path.lineTo(%1.9gf,%1.9gf);\n", pts[1].fX, pts[1].fY); | |
167 break; | |
168 case SkPath::kQuad_Verb: | |
169 SkDebugf("path.quadTo(%1.9gf,%1.9gf, %1.9gf,%1.9gf);\n", | |
170 pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY); | |
171 break; | |
172 case SkPath::kCubic_Verb: | |
173 SkDebugf("path.cubicTo(%1.9gf,%1.9gf, %1.9gf,%1.9gf, %1.9gf,%1.9
gf);\n", | |
174 pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY, pts[3].fX, pts[3
].fY); | |
175 break; | |
176 case SkPath::kClose_Verb: | |
177 SkDebugf("path.close();\n"); | |
178 break; | |
179 default: | |
180 SkDEBUGFAIL("bad verb"); | |
181 return; | |
182 } | |
183 } | |
184 } | |
185 | |
186 static void showPath(const SkPath& path) { | |
187 SkPath::Iter iter(path, true); | |
188 int rectCount = path.isRectContours() ? path.rectContours(NULL, NULL) : 0; | |
189 if (rectCount > 0) { | |
190 SkTDArray<SkRect> rects; | |
191 SkTDArray<SkPath::Direction> directions; | |
192 rects.setCount(rectCount); | |
193 directions.setCount(rectCount); | |
194 path.rectContours(rects.begin(), directions.begin()); | |
195 for (int contour = 0; contour < rectCount; ++contour) { | |
196 const SkRect& rect = rects[contour]; | |
197 SkDebugf("path.addRect(%1.9g, %1.9g, %1.9g, %1.9g, %s);\n", rect.fLe
ft, rect.fTop, | |
198 rect.fRight, rect.fBottom, directions[contour] == SkPath::kC
CW_Direction | |
199 ? "SkPath::kCCW_Direction" : "SkPath::kCW_Direction"); | |
200 } | |
201 return; | |
202 } | |
203 iter.setPath(path, true); | |
204 showPathContour(iter); | |
205 } | |
206 | |
207 static const char* parsePath(const char* data) { | |
208 SkPath fPath; | |
209 SkPoint f = {0, 0}; | |
210 SkPoint c = {0, 0}; | |
211 SkPoint lastc = {0, 0}; | |
212 SkPoint points[3]; | |
213 char op = '\0'; | |
214 char previousOp = '\0'; | |
215 bool relative = false; | |
216 do { | |
217 data = skip_ws(data); | |
218 if (data[0] == '\0') | |
219 break; | |
220 char ch = data[0]; | |
221 if (is_digit(ch) || ch == '-' || ch == '+') { | |
222 if (op == '\0') { | |
223 SkASSERT(0); | |
224 return 0; | |
225 } | |
226 } | |
227 else { | |
228 op = ch; | |
229 relative = false; | |
230 if (islower(op)) { | |
231 op = (char) toupper(op); | |
232 relative = true; | |
233 } | |
234 data++; | |
235 data = skip_sep(data); | |
236 } | |
237 switch (op) { | |
238 case 'M': | |
239 data = find_points(data, points, 1, relative, &c); | |
240 fPath.moveTo(points[0]); | |
241 op = 'L'; | |
242 c = points[0]; | |
243 break; | |
244 case 'L': | |
245 data = find_points(data, points, 1, relative, &c); | |
246 fPath.lineTo(points[0]); | |
247 c = points[0]; | |
248 break; | |
249 case 'H': { | |
250 SkScalar x; | |
251 data = find_scalar(data, &x, relative, c.fX); | |
252 fPath.lineTo(x, c.fY); | |
253 c.fX = x; | |
254 } | |
255 break; | |
256 case 'V': { | |
257 SkScalar y; | |
258 data = find_scalar(data, &y, relative, c.fY); | |
259 fPath.lineTo(c.fX, y); | |
260 c.fY = y; | |
261 } | |
262 break; | |
263 case 'C': | |
264 data = find_points(data, points, 3, relative, &c); | |
265 goto cubicCommon; | |
266 case 'S': | |
267 data = find_points(data, &points[1], 2, relative, &c); | |
268 points[0] = c; | |
269 if (previousOp == 'C' || previousOp == 'S') { | |
270 points[0].fX -= lastc.fX - c.fX; | |
271 points[0].fY -= lastc.fY - c.fY; | |
272 } | |
273 cubicCommon: | |
274 // if (data[0] == '\0') | |
275 // return; | |
276 #if QUADRATIC_APPROXIMATION | |
277 quadApprox(fPath, points[0], points[1], points[2]); | |
278 #else //this way just does a boring, slow old cubic | |
279 fPath.cubicTo(points[0], points[1], points[2]); | |
280 #endif | |
281 //if we are using the quadApprox, lastc is what it would have been if we
had used | |
282 //cubicTo | |
283 lastc = points[1]; | |
284 c = points[2]; | |
285 break; | |
286 case 'Q': // Quadratic Bezier Curve | |
287 data = find_points(data, points, 2, relative, &c); | |
288 goto quadraticCommon; | |
289 case 'T': | |
290 data = find_points(data, &points[1], 1, relative, &c); | |
291 points[0] = points[1]; | |
292 if (previousOp == 'Q' || previousOp == 'T') { | |
293 points[0].fX = c.fX * 2 - lastc.fX; | |
294 points[0].fY = c.fY * 2 - lastc.fY; | |
295 } | |
296 quadraticCommon: | |
297 fPath.quadTo(points[0], points[1]); | |
298 lastc = points[0]; | |
299 c = points[1]; | |
300 break; | |
301 case 'Z': | |
302 fPath.close(); | |
303 #if 0 // !!! still a bug? | |
304 if (fPath.isEmpty() && (f.fX != 0 || f.fY != 0)) { | |
305 c.fX -= SkScalar.Epsilon; // !!! enough? | |
306 fPath.moveTo(c); | |
307 fPath.lineTo(f); | |
308 fPath.close(); | |
309 } | |
310 #endif | |
311 c = f; | |
312 op = '\0'; | |
313 break; | |
314 case '~': { | |
315 SkPoint args[2]; | |
316 data = find_points(data, args, 2, false, NULL); | |
317 fPath.moveTo(args[0].fX, args[0].fY); | |
318 fPath.lineTo(args[1].fX, args[1].fY); | |
319 } | |
320 break; | |
321 default: | |
322 SkASSERT(0); | |
323 return 0; | |
324 } | |
325 if (previousOp == 0) | |
326 f = c; | |
327 previousOp = op; | |
328 } while (data[0] != '"'); | |
329 showPath(fPath); | |
330 return data; | |
331 } | |
332 | |
333 const char pathPrefix[] = "<path fill=\""; | |
334 | |
335 void parseSVG(); | |
336 void parseSVG() { | |
337 const char* data = logoStr; | |
338 const char* dataEnd = logoStr + logoStrLen - 1; | |
339 while (data < dataEnd) { | |
340 SkASSERT(strncmp(data, pathPrefix, sizeof(pathPrefix) - 1) == 0); | |
341 data += sizeof(pathPrefix) - 1; | |
342 SkDebugf("paint.setColor(0xFF%c%c%c%c%c%c);\n", data[1], data[2], data[3
], data[4], | |
343 data[5], data[6]); | |
344 data += 8; | |
345 SkASSERT(strncmp(data, "d=\"", 3) == 0); | |
346 data += 3; | |
347 SkDebugf("path.reset();\n"); | |
348 data = parsePath(data); | |
349 SkDebugf("canvas->drawPath(path, paint);\n"); | |
350 SkASSERT(strncmp(data, "\"/>", 3) == 0); | |
351 data += 3; | |
352 } | |
353 } | |
OLD | NEW |