• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/private/base/SkTPin.h"
9 #include "include/utils/SkParse.h"
10 #include "modules/svg/include/SkSVGAttributeParser.h"
11 #include "modules/svg/include/SkSVGTypes.h"
12 #include "src/base/SkUTF.h"
13 
14 namespace {
15 
16 // TODO: these should be shared with SkParse.cpp
17 
is_between(char c,char min,char max)18 inline bool is_between(char c, char min, char max) {
19     SkASSERT(min <= max);
20     return (unsigned)(c - min) <= (unsigned)(max - min);
21 }
22 
is_ws(char c)23 inline bool is_ws(char c) {
24     return is_between(c, 1, 32);
25 }
26 
is_sep(char c)27 inline bool is_sep(char c) {
28     return is_ws(c) || c == ',' || c == ';';
29 }
30 
is_nl(char c)31 inline bool is_nl(char c) {
32     return c == '\n' || c == '\r' || c == '\f';
33 }
34 
is_hex(char c)35 inline bool is_hex(char c) {
36     return is_between(c, 'a', 'f') ||
37            is_between(c, 'A', 'F') ||
38            is_between(c, '0', '9');
39 }
40 
41 }  // namespace
42 
SkSVGAttributeParser(const char attributeString[])43 SkSVGAttributeParser::SkSVGAttributeParser(const char attributeString[])
44     // TODO: need actual UTF-8 with length.
45     : fCurPos(attributeString), fEndPos(fCurPos + strlen(attributeString)) {}
46 
47 template <typename F>
advanceWhile(F f)48 inline bool SkSVGAttributeParser::advanceWhile(F f) {
49     auto initial = fCurPos;
50     while (fCurPos < fEndPos && f(*fCurPos)) {
51         fCurPos++;
52     }
53     return fCurPos != initial;
54 }
55 
matchStringToken(const char * token,const char ** newPos) const56 bool SkSVGAttributeParser::matchStringToken(const char* token, const char** newPos) const {
57     const char* c = fCurPos;
58 
59     while (c < fEndPos && *token && *c == *token) {
60         c++;
61         token++;
62     }
63 
64     if (*token) {
65         return false;
66     }
67 
68     if (newPos) {
69         *newPos = c;
70     }
71 
72     return true;
73 }
74 
parseEOSToken()75 bool SkSVGAttributeParser::parseEOSToken() {
76     return fCurPos == fEndPos;
77 }
78 
parseSepToken()79 bool SkSVGAttributeParser::parseSepToken() {
80     return this->advanceWhile(is_sep);
81 }
82 
parseWSToken()83 bool SkSVGAttributeParser::parseWSToken() {
84     return this->advanceWhile(is_ws);
85 }
86 
parseCommaWspToken()87 bool SkSVGAttributeParser::parseCommaWspToken() {
88     // comma-wsp:
89     //     (wsp+ comma? wsp*) | (comma wsp*)
90     return this->parseWSToken() || this->parseExpectedStringToken(",");
91 }
92 
parseExpectedStringToken(const char * expected)93 bool SkSVGAttributeParser::parseExpectedStringToken(const char* expected) {
94     const char* newPos;
95     if (!matchStringToken(expected, &newPos)) {
96         return false;
97     }
98 
99     fCurPos = newPos;
100     return true;
101 }
102 
parseScalarToken(SkScalar * res)103 bool SkSVGAttributeParser::parseScalarToken(SkScalar* res) {
104     if (const char* next = SkParse::FindScalar(fCurPos, res)) {
105         fCurPos = next;
106         return true;
107     }
108     return false;
109 }
110 
parseInt32Token(int32_t * res)111 bool SkSVGAttributeParser::parseInt32Token(int32_t* res) {
112     if (const char* next = SkParse::FindS32(fCurPos, res)) {
113         fCurPos = next;
114         return true;
115     }
116     return false;
117 }
118 
matchHexToken(const char ** newPos) const119 bool SkSVGAttributeParser::matchHexToken(const char** newPos) const {
120     *newPos = fCurPos;
121     while (*newPos < fEndPos && is_hex(**newPos)) { ++*newPos; }
122     return *newPos != fCurPos;
123 }
124 
parseEscape(SkUnichar * c)125 bool SkSVGAttributeParser::parseEscape(SkUnichar* c) {
126     // \(hexDigit{1,6}whitespace?|[^newline|hexDigit])
127     RestoreCurPos restoreCurPos(this);
128 
129     if (!this->parseExpectedStringToken("\\")) {
130         return false;
131     }
132     const char* hexEnd;
133     if (this->matchHexToken(&hexEnd)) {
134         if (hexEnd - fCurPos > 6) {
135             hexEnd = fCurPos + 6;
136         }
137         char hexString[7];
138         size_t hexSize = hexEnd - fCurPos;
139         memcpy(hexString, fCurPos, hexSize);
140         hexString[hexSize] = '\0';
141         uint32_t cp;
142         const char* hexFound = SkParse::FindHex(hexString, &cp);
143         if (!hexFound || cp < 1 || (0xD800 <= cp && cp <= 0xDFFF) || 0x10FFFF < cp) {
144             cp = 0xFFFD;
145         }
146         *c = cp;
147         fCurPos = hexEnd;
148         this->parseWSToken();
149     } else if (this->parseEOSToken() || is_nl(*fCurPos)) {
150         *c = 0xFFFD;
151         return false;
152     } else {
153         if ((*c = SkUTF::NextUTF8(&fCurPos, fEndPos)) < 0) {
154             return false;
155         }
156     }
157 
158     restoreCurPos.clear();
159     return true;
160 }
161 
parseIdentToken(SkString * ident)162 bool SkSVGAttributeParser::parseIdentToken(SkString* ident) {
163     // <ident-token>
164     // (--|-?([a-z|A-Z|_|non-ASCII]|escape))([a-z|A-Z|0-9|_|-|non-ASCII]|escape)?
165     RestoreCurPos restoreCurPos(this);
166 
167     SkUnichar c;
168     if (this->parseExpectedStringToken("--")) {
169         ident->append("--");
170     } else {
171         if (this->parseExpectedStringToken("-")) {
172             ident->append("-");
173         }
174         if (this->parseEscape(&c)) {
175             ident->appendUnichar(c);
176         } else {
177             if ((c = SkUTF::NextUTF8(&fCurPos, fEndPos)) < 0) {
178                 return false;
179             }
180             if ((c < 'a' || 'z' < c) &&
181                 (c < 'A' || 'Z' < c) &&
182                 (c != '_') &&
183                 (c < 0x80 || 0x10FFFF < c))
184             {
185                 return false;
186             }
187             ident->appendUnichar(c);
188         }
189     }
190     while (fCurPos < fEndPos) {
191         if (this->parseEscape(&c)) {
192             ident->appendUnichar(c);
193             continue;
194         }
195         const char* next = fCurPos;
196         if ((c = SkUTF::NextUTF8(&next, fEndPos)) < 0) {
197             break;
198         }
199         if ((c < 'a' || 'z' < c) &&
200             (c < 'A' || 'Z' < c) &&
201             (c < '0' || '9' < c) &&
202             (c != '_') &&
203             (c != '-') &&
204             (c < 0x80 || 0x10FFFF < c))
205         {
206             break;
207         }
208         ident->appendUnichar(c);
209         fCurPos = next;
210     }
211 
212     restoreCurPos.clear();
213     return true;
214 }
215 
parseLengthUnitToken(SkSVGLength::Unit * unit)216 bool SkSVGAttributeParser::parseLengthUnitToken(SkSVGLength::Unit* unit) {
217     static const struct {
218         const char*       fUnitName;
219         SkSVGLength::Unit fUnit;
220     } gUnitInfo[] = {
221         { "%" , SkSVGLength::Unit::kPercentage },
222         { "em", SkSVGLength::Unit::kEMS        },
223         { "ex", SkSVGLength::Unit::kEXS        },
224         { "px", SkSVGLength::Unit::kPX         },
225         { "cm", SkSVGLength::Unit::kCM         },
226         { "mm", SkSVGLength::Unit::kMM         },
227         { "in", SkSVGLength::Unit::kIN         },
228         { "pt", SkSVGLength::Unit::kPT         },
229         { "pc", SkSVGLength::Unit::kPC         },
230     };
231 
232     for (size_t i = 0; i < std::size(gUnitInfo); ++i) {
233         if (this->parseExpectedStringToken(gUnitInfo[i].fUnitName)) {
234             *unit = gUnitInfo[i].fUnit;
235             return true;
236         }
237     }
238     return false;
239 }
240 
241 // https://www.w3.org/TR/SVG11/types.html#DataTypeColor
parseNamedColorToken(SkColor * c)242 bool SkSVGAttributeParser::parseNamedColorToken(SkColor* c) {
243     RestoreCurPos restoreCurPos(this);
244 
245     SkString ident;
246     if (!this->parseIdentToken(&ident)) {
247         return false;
248     }
249     if (!SkParse::FindNamedColor(ident.c_str(), ident.size(), c)) {
250         return false;
251     }
252 
253     restoreCurPos.clear();
254     return true;
255 }
256 
parseHexColorToken(SkColor * c)257 bool SkSVGAttributeParser::parseHexColorToken(SkColor* c) {
258     RestoreCurPos restoreCurPos(this);
259 
260     const char* hexEnd;
261     if (!this->parseExpectedStringToken("#") || !this->matchHexToken(&hexEnd)) {
262         return false;
263     }
264 
265     uint32_t v;
266     SkString hexString(fCurPos, hexEnd - fCurPos);
267     SkParse::FindHex(hexString.c_str(), &v);
268 
269     switch (hexString.size()) {
270     case 6:
271         // matched #xxxxxxx
272         break;
273     case 3:
274         // matched '#xxx;
275         v = ((v << 12) & 0x00f00000) |
276             ((v <<  8) & 0x000ff000) |
277             ((v <<  4) & 0x00000ff0) |
278             ((v <<  0) & 0x0000000f);
279         break;
280     default:
281         return false;
282     }
283 
284     *c = v | 0xff000000;
285     fCurPos = hexEnd;
286 
287     restoreCurPos.clear();
288     return true;
289 }
290 
parseColorComponentIntegralToken(int32_t * c)291 bool SkSVGAttributeParser::parseColorComponentIntegralToken(int32_t* c) {
292     const char* p = SkParse::FindS32(fCurPos, c);
293     if (!p || *p == '.') {
294         // No value parsed, or fractional value.
295         return false;
296     }
297 
298     if (*p == '%') {
299         *c = SkScalarRoundToInt(*c * 255.0f / 100);
300         *c = SkTPin<int32_t>(*c, 0, 255);
301         p++;
302     }
303 
304     fCurPos = p;
305     return true;
306 }
307 
parseColorComponentFractionalToken(int32_t * c)308 bool SkSVGAttributeParser::parseColorComponentFractionalToken(int32_t* c) {
309     SkScalar s;
310     const char* p = SkParse::FindScalar(fCurPos, &s);
311     if (!p || *p != '%') {
312         // Floating point must be a percentage (CSS2 rgb-percent syntax).
313         return false;
314     }
315     p++;  // Skip '%'
316 
317     *c = SkScalarRoundToInt(s * 255.0f / 100);
318     *c = SkTPin<int32_t>(*c, 0, 255);
319     fCurPos = p;
320     return true;
321 }
322 
parseColorComponentScalarToken(int32_t * c)323 bool SkSVGAttributeParser::parseColorComponentScalarToken(int32_t* c) {
324     SkScalar s;
325     if (const char* p = SkParse::FindScalar(fCurPos, &s)) {
326         *c = SkScalarRoundToInt(s * 255.0f);
327         *c = SkTPin<int32_t>(*c, 0, 255);
328         fCurPos = p;
329         return true;
330     }
331     return false;
332 }
333 
parseColorComponentToken(int32_t * c)334 bool SkSVGAttributeParser::parseColorComponentToken(int32_t* c) {
335     return parseColorComponentIntegralToken(c) ||
336            parseColorComponentFractionalToken(c);
337 }
338 
parseRGBColorToken(SkColor * c)339 bool SkSVGAttributeParser::parseRGBColorToken(SkColor* c) {
340     return this->parseParenthesized("rgb", [this](SkColor* c) -> bool {
341         int32_t r, g, b;
342         if (this->parseColorComponentToken(&r) &&
343             this->parseSepToken() &&
344             this->parseColorComponentToken(&g) &&
345             this->parseSepToken() &&
346             this->parseColorComponentToken(&b)) {
347 
348             *c = SkColorSetRGB(static_cast<uint8_t>(r),
349                                static_cast<uint8_t>(g),
350                                static_cast<uint8_t>(b));
351             return true;
352         }
353         return false;
354     }, c);
355 }
356 
parseRGBAColorToken(SkColor * c)357 bool SkSVGAttributeParser::parseRGBAColorToken(SkColor* c) {
358     return this->parseParenthesized("rgba", [this](SkColor* c) -> bool {
359         int32_t r, g, b, a;
360         if (this->parseColorComponentToken(&r) &&
361             this->parseSepToken() &&
362             this->parseColorComponentToken(&g) &&
363             this->parseSepToken() &&
364             this->parseColorComponentToken(&b) &&
365             this->parseSepToken() &&
366             this->parseColorComponentScalarToken(&a)) {
367 
368             *c = SkColorSetARGB(static_cast<uint8_t>(a),
369                                 static_cast<uint8_t>(r),
370                                 static_cast<uint8_t>(g),
371                                 static_cast<uint8_t>(b));
372             return true;
373         }
374         return false;
375     }, c);
376 }
377 
parseColorToken(SkColor * c)378 bool SkSVGAttributeParser::parseColorToken(SkColor* c) {
379     return this->parseHexColorToken(c) ||
380            this->parseNamedColorToken(c) ||
381            this->parseRGBAColorToken(c) ||
382            this->parseRGBColorToken(c);
383 }
384 
parseSVGColorType(SkSVGColorType * color)385 bool SkSVGAttributeParser::parseSVGColorType(SkSVGColorType* color) {
386     SkColor c;
387     if (!this->parseColorToken(&c)) {
388         return false;
389     }
390     *color = SkSVGColorType(c);
391     return true;
392 }
393 
394 // https://www.w3.org/TR/SVG11/types.html#DataTypeColor
395 // And https://www.w3.org/TR/CSS2/syndata.html#color-units for the alternative
396 // forms supported by SVG (e.g. RGB percentages).
397 template <>
parse(SkSVGColorType * color)398 bool SkSVGAttributeParser::parse(SkSVGColorType* color) {
399     this->parseWSToken();
400     if (!this->parseSVGColorType(color)) {
401         return false;
402     }
403     this->parseWSToken();
404     return this->parseEOSToken();
405 }
406 
parseSVGColor(SkSVGColor * color,SkSVGColor::Vars && vars)407 bool SkSVGAttributeParser::parseSVGColor(SkSVGColor* color, SkSVGColor::Vars&& vars) {
408     static const constexpr int kVarsLimit = 32;
409 
410     if (SkSVGColorType c; this->parseSVGColorType(&c)) {
411         *color = SkSVGColor(c, std::move(vars));
412         return true;
413     }
414     if (this->parseExpectedStringToken("currentColor")) {
415         *color = SkSVGColor(SkSVGColor::Type::kCurrentColor, std::move(vars));
416         return true;
417     }
418     // https://drafts.csswg.org/css-variables/#using-variables
419     if (this->parseParenthesized("var", [this, &vars](SkSVGColor* colorResult) -> bool {
420             SkString ident;
421             if (!this->parseIdentToken(&ident) || ident.size() < 2 || !ident.startsWith("--")) {
422                 return false;
423             }
424             ident.remove(0, 2);
425             vars.push_back(std::move(ident));
426             this->parseWSToken();
427             if (!this->parseExpectedStringToken(",")) {
428                 *colorResult = SkSVGColor(SK_ColorBLACK, std::move(vars));
429                 return true;
430             }
431             this->parseWSToken();
432             if (this->matchStringToken(")")) {
433                 *colorResult = SkSVGColor(SK_ColorBLACK, std::move(vars));
434                 return true;
435             }
436             return vars.size() < kVarsLimit && this->parseSVGColor(colorResult, std::move(vars));
437         }, color))
438     {
439         return true;
440     }
441     return false;
442 }
443 
444 // https://www.w3.org/TR/SVG11/types.html#InterfaceSVGColor
445 template <>
parse(SkSVGColor * color)446 bool SkSVGAttributeParser::parse(SkSVGColor* color) {
447     this->parseWSToken();
448     if (!this->parseSVGColor(color, SkSVGColor::Vars())) {
449         return false;
450     }
451     this->parseWSToken();
452     return this->parseEOSToken();
453 }
454 
455 // https://www.w3.org/TR/SVG11/linking.html#IRIReference
456 template <>
parse(SkSVGIRI * iri)457 bool SkSVGAttributeParser::parse(SkSVGIRI* iri) {
458     // consume preceding whitespace
459     this->parseWSToken();
460 
461     SkSVGIRI::Type iriType;
462     if (this->parseExpectedStringToken("#")) {
463         iriType = SkSVGIRI::Type::kLocal;
464     } else if (this->matchStringToken("data:")) {
465         iriType = SkSVGIRI::Type::kDataURI;
466     } else {
467         iriType = SkSVGIRI::Type::kNonlocal;
468     }
469 
470     const auto* start = fCurPos;
471     if (!this->advanceWhile([](char c) -> bool { return c != ')'; })) {
472         return false;
473     }
474     *iri = SkSVGIRI(iriType, SkString(start, fCurPos - start));
475     return true;
476 }
477 
478 // https://www.w3.org/TR/SVG11/types.html#DataTypeFuncIRI
parseFuncIRI(SkSVGFuncIRI * iri)479 bool SkSVGAttributeParser::parseFuncIRI(SkSVGFuncIRI* iri) {
480     return this->parseParenthesized("url", [this](SkSVGFuncIRI* iriResult) -> bool {
481         SkSVGIRI iri;
482         if (this->parse(&iri)) {
483             *iriResult = SkSVGFuncIRI(std::move(iri));
484             return true;
485         }
486         return false;
487     }, iri);
488 }
489 
490 template <>
parse(SkSVGStringType * result)491 bool SkSVGAttributeParser::parse(SkSVGStringType* result) {
492     if (this->parseEOSToken()) {
493         return false;
494     }
495     *result = SkSVGStringType(fCurPos);
496     fCurPos += result->size();
497     return this->parseEOSToken();
498 }
499 
500 // https://www.w3.org/TR/SVG11/types.html#DataTypeNumber
501 template <>
parse(SkSVGNumberType * number)502 bool SkSVGAttributeParser::parse(SkSVGNumberType* number) {
503     // consume WS
504     this->parseWSToken();
505 
506     SkScalar s;
507     if (this->parseScalarToken(&s)) {
508         *number = SkSVGNumberType(s);
509         // consume trailing separators
510         this->parseSepToken();
511         return true;
512     }
513 
514     return false;
515 }
516 
517 // https://www.w3.org/TR/SVG11/types.html#DataTypeInteger
parseInteger(SkSVGIntegerType * number)518 bool SkSVGAttributeParser::parseInteger(SkSVGIntegerType* number) {
519     // consume WS
520     this->parseWSToken();
521 
522     // consume optional '+'
523     this->parseExpectedStringToken("+");
524 
525     SkSVGIntegerType i;
526     if (this->parseInt32Token(&i)) {
527         *number = SkSVGNumberType(i);
528         // consume trailing separators
529         this->parseSepToken();
530         return true;
531     }
532 
533     return false;
534 }
535 
536 // https://www.w3.org/TR/SVG11/types.html#DataTypeLength
537 template <>
parse(SkSVGLength * length)538 bool SkSVGAttributeParser::parse(SkSVGLength* length) {
539     SkScalar s;
540     SkSVGLength::Unit u = SkSVGLength::Unit::kNumber;
541 
542     if (this->parseScalarToken(&s) &&
543         (this->parseLengthUnitToken(&u) || this->parseSepToken() || this->parseEOSToken())) {
544         *length = SkSVGLength(s, u);
545         // consume trailing separators
546         this->parseSepToken();
547         return true;
548     }
549 
550     return false;
551 }
552 
553 // https://www.w3.org/TR/SVG11/coords.html#ViewBoxAttribute
parseViewBox(SkSVGViewBoxType * vb)554 bool SkSVGAttributeParser::parseViewBox(SkSVGViewBoxType* vb) {
555     SkScalar x, y, w, h;
556     this->parseWSToken();
557 
558     bool parsedValue = false;
559     if (this->parseScalarToken(&x) && this->parseSepToken() &&
560         this->parseScalarToken(&y) && this->parseSepToken() &&
561         this->parseScalarToken(&w) && this->parseSepToken() &&
562         this->parseScalarToken(&h)) {
563 
564         *vb = SkSVGViewBoxType(SkRect::MakeXYWH(x, y, w, h));
565         parsedValue = true;
566         // consume trailing whitespace
567         this->parseWSToken();
568     }
569     return parsedValue && this->parseEOSToken();
570 }
571 
572 template <typename Func, typename T>
parseParenthesized(const char * prefix,Func f,T * result)573 bool SkSVGAttributeParser::parseParenthesized(const char* prefix, Func f, T* result) {
574     RestoreCurPos restoreCurPos(this);
575 
576     this->parseWSToken();
577     if (prefix && !this->parseExpectedStringToken(prefix)) {
578         return false;
579     }
580     this->parseWSToken();
581     if (!this->parseExpectedStringToken("(")) {
582         return false;
583     }
584     this->parseWSToken();
585 
586     if (!f(result)) {
587         return false;
588     }
589 
590     this->parseWSToken();
591     if (!this->parseExpectedStringToken(")")) {
592         return false;
593     }
594 
595     restoreCurPos.clear();
596     return true;
597 }
598 
parseMatrixToken(SkMatrix * matrix)599 bool SkSVGAttributeParser::parseMatrixToken(SkMatrix* matrix) {
600     return this->parseParenthesized("matrix", [this](SkMatrix* m) -> bool {
601         SkScalar scalars[6];
602         for (int i = 0; i < 6; ++i) {
603             if (!(this->parseScalarToken(scalars + i) &&
604                   (i > 4 || this->parseSepToken()))) {
605                 return false;
606             }
607         }
608 
609         m->setAll(scalars[0], scalars[2], scalars[4], scalars[1], scalars[3], scalars[5], 0, 0, 1);
610         return true;
611     }, matrix);
612 }
613 
parseTranslateToken(SkMatrix * matrix)614 bool SkSVGAttributeParser::parseTranslateToken(SkMatrix* matrix) {
615     return this->parseParenthesized("translate", [this](SkMatrix* m) -> bool {
616         SkScalar tx = 0.0, ty = 0.0;
617         this->parseWSToken();
618         if (!this->parseScalarToken(&tx)) {
619             return false;
620         }
621 
622         if (!this->parseSepToken() || !this->parseScalarToken(&ty)) {
623             ty = 0.0;
624         }
625 
626         m->setTranslate(tx, ty);
627         return true;
628     }, matrix);
629 }
630 
parseScaleToken(SkMatrix * matrix)631 bool SkSVGAttributeParser::parseScaleToken(SkMatrix* matrix) {
632     return this->parseParenthesized("scale", [this](SkMatrix* m) -> bool {
633         SkScalar sx = 0.0, sy = 0.0;
634         if (!this->parseScalarToken(&sx)) {
635             return false;
636         }
637 
638         if (!(this->parseSepToken() && this->parseScalarToken(&sy))) {
639             sy = sx;
640         }
641 
642         m->setScale(sx, sy);
643         return true;
644     }, matrix);
645 }
646 
parseRotateToken(SkMatrix * matrix)647 bool SkSVGAttributeParser::parseRotateToken(SkMatrix* matrix) {
648     return this->parseParenthesized("rotate", [this](SkMatrix* m) -> bool {
649         SkScalar angle;
650         if (!this->parseScalarToken(&angle)) {
651             return false;
652         }
653 
654         SkScalar cx = 0;
655         SkScalar cy = 0;
656         // optional [<cx> <cy>]
657         if (this->parseSepToken() && this->parseScalarToken(&cx)) {
658             if (!(this->parseSepToken() && this->parseScalarToken(&cy))) {
659                 return false;
660             }
661         }
662 
663         m->setRotate(angle, cx, cy);
664         return true;
665     }, matrix);
666 }
667 
parseSkewXToken(SkMatrix * matrix)668 bool SkSVGAttributeParser::parseSkewXToken(SkMatrix* matrix) {
669     return this->parseParenthesized("skewX", [this](SkMatrix* m) -> bool {
670         SkScalar angle;
671         if (!this->parseScalarToken(&angle)) {
672             return false;
673         }
674         m->setSkewX(tanf(SkDegreesToRadians(angle)));
675         return true;
676     }, matrix);
677 }
678 
parseSkewYToken(SkMatrix * matrix)679 bool SkSVGAttributeParser::parseSkewYToken(SkMatrix* matrix) {
680     return this->parseParenthesized("skewY", [this](SkMatrix* m) -> bool {
681         SkScalar angle;
682         if (!this->parseScalarToken(&angle)) {
683             return false;
684         }
685         m->setSkewY(tanf(SkDegreesToRadians(angle)));
686         return true;
687     }, matrix);
688 }
689 
690 // https://www.w3.org/TR/SVG11/coords.html#TransformAttribute
691 template <>
parse(SkSVGTransformType * t)692 bool SkSVGAttributeParser::parse(SkSVGTransformType* t) {
693     SkMatrix matrix = SkMatrix::I();
694 
695     bool parsed = false;
696     while (true) {
697         SkMatrix m;
698 
699         if (!( this->parseMatrixToken(&m)
700             || this->parseTranslateToken(&m)
701             || this->parseScaleToken(&m)
702             || this->parseRotateToken(&m)
703             || this->parseSkewXToken(&m)
704             || this->parseSkewYToken(&m))) {
705             break;
706         }
707 
708         matrix.preConcat(m);
709         parsed = true;
710 
711         this->parseCommaWspToken();
712     }
713 
714     this->parseWSToken();
715     if (!parsed || !this->parseEOSToken()) {
716         return false;
717     }
718 
719     *t = SkSVGTransformType(matrix);
720     return true;
721 }
722 
723 // https://www.w3.org/TR/SVG11/painting.html#SpecifyingPaint
724 template <>
parse(SkSVGPaint * paint)725 bool SkSVGAttributeParser::parse(SkSVGPaint* paint) {
726     SkSVGColor c;
727     SkSVGFuncIRI iri;
728     bool parsedValue = false;
729 
730     this->parseWSToken();
731     if (this->parseSVGColor(&c, SkSVGColor::Vars())) {
732         *paint = SkSVGPaint(std::move(c));
733         parsedValue = true;
734     } else if (this->parseExpectedStringToken("none")) {
735         *paint = SkSVGPaint(SkSVGPaint::Type::kNone);
736         parsedValue = true;
737     } else if (this->parseFuncIRI(&iri)) {
738         // optional fallback color
739         this->parseWSToken();
740         this->parseSVGColor(&c, SkSVGColor::Vars());
741         *paint = SkSVGPaint(iri.iri(), std::move(c));
742         parsedValue = true;
743     }
744     this->parseWSToken();
745     return parsedValue && this->parseEOSToken();
746 }
747 
748 // https://www.w3.org/TR/SVG11/masking.html#ClipPathProperty
749 // https://www.w3.org/TR/SVG11/masking.html#MaskProperty
750 // https://www.w3.org/TR/SVG11/filters.html#FilterProperty
751 template <>
parse(SkSVGFuncIRI * firi)752 bool SkSVGAttributeParser::parse(SkSVGFuncIRI* firi) {
753     SkSVGStringType iri;
754     bool parsedValue = false;
755 
756     if (this->parseExpectedStringToken("none")) {
757         *firi = SkSVGFuncIRI();
758         parsedValue = true;
759     } else if (this->parseFuncIRI(firi)) {
760         parsedValue = true;
761     }
762 
763     return parsedValue && this->parseEOSToken();
764 }
765 
766 // https://www.w3.org/TR/SVG11/painting.html#StrokeLinecapProperty
767 template <>
parse(SkSVGLineCap * cap)768 bool SkSVGAttributeParser::parse(SkSVGLineCap* cap) {
769     static const struct {
770         SkSVGLineCap fType;
771         const char*        fName;
772     } gCapInfo[] = {
773         { SkSVGLineCap::kButt   , "butt"    },
774         { SkSVGLineCap::kRound  , "round"   },
775         { SkSVGLineCap::kSquare , "square"  },
776     };
777 
778     bool parsedValue = false;
779     for (size_t i = 0; i < std::size(gCapInfo); ++i) {
780         if (this->parseExpectedStringToken(gCapInfo[i].fName)) {
781             *cap = SkSVGLineCap(gCapInfo[i].fType);
782             parsedValue = true;
783             break;
784         }
785     }
786 
787     return parsedValue && this->parseEOSToken();
788 }
789 
790 // https://www.w3.org/TR/SVG11/painting.html#StrokeLinejoinProperty
791 template <>
parse(SkSVGLineJoin * join)792 bool SkSVGAttributeParser::parse(SkSVGLineJoin* join) {
793     static const struct {
794         SkSVGLineJoin::Type fType;
795         const char*         fName;
796     } gJoinInfo[] = {
797         { SkSVGLineJoin::Type::kMiter  , "miter"   },
798         { SkSVGLineJoin::Type::kRound  , "round"   },
799         { SkSVGLineJoin::Type::kBevel  , "bevel"   },
800         { SkSVGLineJoin::Type::kInherit, "inherit" },
801     };
802 
803     bool parsedValue = false;
804     for (size_t i = 0; i < std::size(gJoinInfo); ++i) {
805         if (this->parseExpectedStringToken(gJoinInfo[i].fName)) {
806             *join = SkSVGLineJoin(gJoinInfo[i].fType);
807             parsedValue = true;
808             break;
809         }
810     }
811 
812     return parsedValue && this->parseEOSToken();
813 }
814 
815 // https://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBoxUnits
816 template <>
parse(SkSVGObjectBoundingBoxUnits * objectBoundingBoxUnits)817 bool SkSVGAttributeParser::parse(SkSVGObjectBoundingBoxUnits* objectBoundingBoxUnits) {
818     bool parsedValue = false;
819     if (this->parseExpectedStringToken("userSpaceOnUse")) {
820         *objectBoundingBoxUnits =
821                 SkSVGObjectBoundingBoxUnits(SkSVGObjectBoundingBoxUnits::Type::kUserSpaceOnUse);
822         parsedValue = true;
823     } else if (this->parseExpectedStringToken("objectBoundingBox")) {
824         *objectBoundingBoxUnits =
825                 SkSVGObjectBoundingBoxUnits(SkSVGObjectBoundingBoxUnits::Type::kObjectBoundingBox);
826         parsedValue = true;
827     }
828     return parsedValue && this->parseEOSToken();
829 }
830 
831 // https://www.w3.org/TR/SVG11/shapes.html#PolygonElementPointsAttribute
832 template <>
parse(SkSVGPointsType * points)833 bool SkSVGAttributeParser::parse(SkSVGPointsType* points) {
834     SkSVGPointsType pts;
835 
836     // Skip initial wsp.
837     // list-of-points:
838     //     wsp* coordinate-pairs? wsp*
839     this->advanceWhile(is_ws);
840 
841     bool parsedValue = false;
842     for (;;) {
843         // Adjacent coordinate-pairs separated by comma-wsp.
844         // coordinate-pairs:
845         //     coordinate-pair
846         //     | coordinate-pair comma-wsp coordinate-pairs
847         if (parsedValue && !this->parseCommaWspToken()) {
848             break;
849         }
850 
851         SkScalar x, y;
852         if (!this->parseScalarToken(&x)) {
853             break;
854         }
855 
856         // Coordinate values separated by comma-wsp or '-'.
857         // coordinate-pair:
858         //     coordinate comma-wsp coordinate
859         //     | coordinate negative-coordinate
860         if (!this->parseCommaWspToken() && !this->parseEOSToken() && *fCurPos != '-') {
861             break;
862         }
863 
864         if (!this->parseScalarToken(&y)) {
865             break;
866         }
867 
868         pts.push_back(SkPoint::Make(x, y));
869         parsedValue = true;
870     }
871 
872     if (parsedValue && this->parseEOSToken()) {
873         *points = std::move(pts);
874         return true;
875     }
876 
877     return false;
878 }
879 
880 // https://www.w3.org/TR/SVG11/painting.html#FillRuleProperty
881 template <>
parse(SkSVGFillRule * fillRule)882 bool SkSVGAttributeParser::parse(SkSVGFillRule* fillRule) {
883     static const struct {
884         SkSVGFillRule::Type fType;
885         const char*         fName;
886     } gFillRuleInfo[] = {
887         { SkSVGFillRule::Type::kNonZero, "nonzero" },
888         { SkSVGFillRule::Type::kEvenOdd, "evenodd" },
889         { SkSVGFillRule::Type::kInherit, "inherit" },
890     };
891 
892     bool parsedValue = false;
893     for (size_t i = 0; i < std::size(gFillRuleInfo); ++i) {
894         if (this->parseExpectedStringToken(gFillRuleInfo[i].fName)) {
895             *fillRule = SkSVGFillRule(gFillRuleInfo[i].fType);
896             parsedValue = true;
897             break;
898         }
899     }
900 
901     return parsedValue && this->parseEOSToken();
902 }
903 
904 // https://www.w3.org/TR/SVG11/painting.html#VisibilityProperty
905 template <>
parse(SkSVGVisibility * visibility)906 bool SkSVGAttributeParser::parse(SkSVGVisibility* visibility) {
907     static const struct {
908         SkSVGVisibility::Type fType;
909         const char*           fName;
910     } gVisibilityInfo[] = {
911         { SkSVGVisibility::Type::kVisible , "visible"  },
912         { SkSVGVisibility::Type::kHidden  , "hidden"   },
913         { SkSVGVisibility::Type::kCollapse, "collapse" },
914         { SkSVGVisibility::Type::kInherit , "inherit"  },
915     };
916 
917     bool parsedValue = false;
918     for (const auto& parseInfo : gVisibilityInfo) {
919         if (this->parseExpectedStringToken(parseInfo.fName)) {
920             *visibility = SkSVGVisibility(parseInfo.fType);
921             parsedValue = true;
922             break;
923         }
924     }
925 
926     return parsedValue && this->parseEOSToken();
927 }
928 
929 // https://www.w3.org/TR/SVG11/painting.html#StrokeDasharrayProperty
930 template <>
parse(SkSVGDashArray * dashArray)931 bool SkSVGAttributeParser::parse(SkSVGDashArray* dashArray) {
932     bool parsedValue = false;
933     if (this->parseExpectedStringToken("none")) {
934         *dashArray = SkSVGDashArray(SkSVGDashArray::Type::kNone);
935         parsedValue = true;
936     } else if (this->parseExpectedStringToken("inherit")) {
937         *dashArray = SkSVGDashArray(SkSVGDashArray::Type::kInherit);
938         parsedValue = true;
939     } else {
940         std::vector<SkSVGLength> dashes;
941         for (;;) {
942             SkSVGLength dash;
943             // parseLength() also consumes trailing separators.
944             if (!this->parse(&dash)) {
945                 break;
946             }
947 
948             dashes.push_back(dash);
949             parsedValue = true;
950         }
951 
952         if (parsedValue) {
953             *dashArray = SkSVGDashArray(std::move(dashes));
954         }
955     }
956 
957     return parsedValue && this->parseEOSToken();
958 }
959 
960 // https://www.w3.org/TR/SVG11/text.html#FontFamilyProperty
961 template <>
parse(SkSVGFontFamily * family)962 bool SkSVGAttributeParser::parse(SkSVGFontFamily* family) {
963     bool parsedValue = false;
964     if (this->parseExpectedStringToken("inherit")) {
965         *family = SkSVGFontFamily();
966         parsedValue = true;
967     } else {
968         // The spec allows specifying a comma-separated list for explicit fallback order.
969         // For now, we only use the first entry and rely on the font manager to handle fallback.
970         const auto* comma = strchr(fCurPos, ',');
971         auto family_name = comma ? SkString(fCurPos, comma - fCurPos)
972                                  : SkString(fCurPos);
973         *family = SkSVGFontFamily(family_name.c_str());
974         fCurPos += strlen(fCurPos);
975         parsedValue = true;
976     }
977 
978     return parsedValue && this->parseEOSToken();
979 }
980 
981 // https://www.w3.org/TR/SVG11/text.html#FontSizeProperty
982 template <>
parse(SkSVGFontSize * size)983 bool SkSVGAttributeParser::parse(SkSVGFontSize* size) {
984     bool parsedValue = false;
985     if (this->parseExpectedStringToken("inherit")) {
986         *size = SkSVGFontSize();
987         parsedValue = true;
988     } else {
989         SkSVGLength length;
990         if (this->parse(&length)) {
991             *size = SkSVGFontSize(length);
992             parsedValue = true;
993         }
994     }
995 
996     return parsedValue && this->parseEOSToken();
997 }
998 
999 // https://www.w3.org/TR/SVG11/text.html#FontStyleProperty
1000 template <>
parse(SkSVGFontStyle * style)1001 bool SkSVGAttributeParser::parse(SkSVGFontStyle* style) {
1002     static constexpr std::tuple<const char*, SkSVGFontStyle::Type> gStyleMap[] = {
1003         { "normal" , SkSVGFontStyle::Type::kNormal  },
1004         { "italic" , SkSVGFontStyle::Type::kItalic  },
1005         { "oblique", SkSVGFontStyle::Type::kOblique },
1006         { "inherit", SkSVGFontStyle::Type::kInherit },
1007     };
1008 
1009     bool parsedValue = false;
1010     SkSVGFontStyle::Type type;
1011 
1012     if (this->parseEnumMap(gStyleMap, &type)) {
1013         *style = SkSVGFontStyle(type);
1014         parsedValue = true;
1015     }
1016 
1017     return parsedValue && this->parseEOSToken();
1018 }
1019 
1020 // https://www.w3.org/TR/SVG11/text.html#FontWeightProperty
1021 template <>
parse(SkSVGFontWeight * weight)1022 bool SkSVGAttributeParser::parse(SkSVGFontWeight* weight) {
1023     static constexpr std::tuple<const char*, SkSVGFontWeight::Type> gWeightMap[] = {
1024         { "normal" , SkSVGFontWeight::Type::kNormal  },
1025         { "bold"   , SkSVGFontWeight::Type::kBold    },
1026         { "bolder" , SkSVGFontWeight::Type::kBolder  },
1027         { "lighter", SkSVGFontWeight::Type::kLighter },
1028         { "100"    , SkSVGFontWeight::Type::k100     },
1029         { "200"    , SkSVGFontWeight::Type::k200     },
1030         { "300"    , SkSVGFontWeight::Type::k300     },
1031         { "400"    , SkSVGFontWeight::Type::k400     },
1032         { "500"    , SkSVGFontWeight::Type::k500     },
1033         { "600"    , SkSVGFontWeight::Type::k600     },
1034         { "700"    , SkSVGFontWeight::Type::k700     },
1035         { "800"    , SkSVGFontWeight::Type::k800     },
1036         { "900"    , SkSVGFontWeight::Type::k900     },
1037         { "inherit", SkSVGFontWeight::Type::kInherit },
1038     };
1039 
1040     bool parsedValue = false;
1041     SkSVGFontWeight::Type type;
1042 
1043     if (this->parseEnumMap(gWeightMap, &type)) {
1044         *weight = SkSVGFontWeight(type);
1045         parsedValue = true;
1046     }
1047 
1048     return parsedValue && this->parseEOSToken();
1049 }
1050 
1051 // https://www.w3.org/TR/SVG11/text.html#TextAnchorProperty
1052 template <>
parse(SkSVGTextAnchor * anchor)1053 bool SkSVGAttributeParser::parse(SkSVGTextAnchor* anchor) {
1054     static constexpr std::tuple<const char*, SkSVGTextAnchor::Type> gAnchorMap[] = {
1055         { "start"  , SkSVGTextAnchor::Type::kStart  },
1056         { "middle" , SkSVGTextAnchor::Type::kMiddle },
1057         { "end"    , SkSVGTextAnchor::Type::kEnd    },
1058         { "inherit", SkSVGTextAnchor::Type::kInherit},
1059     };
1060 
1061     bool parsedValue = false;
1062     SkSVGTextAnchor::Type type;
1063 
1064     if (this->parseEnumMap(gAnchorMap, &type)) {
1065         *anchor = SkSVGTextAnchor(type);
1066         parsedValue = true;
1067     }
1068 
1069     return parsedValue && this->parseEOSToken();
1070 }
1071 
1072 // https://www.w3.org/TR/SVG11/coords.html#PreserveAspectRatioAttribute
parsePreserveAspectRatio(SkSVGPreserveAspectRatio * par)1073 bool SkSVGAttributeParser::parsePreserveAspectRatio(SkSVGPreserveAspectRatio* par) {
1074     static constexpr std::tuple<const char*, SkSVGPreserveAspectRatio::Align> gAlignMap[] = {
1075         { "none"    , SkSVGPreserveAspectRatio::kNone     },
1076         { "xMinYMin", SkSVGPreserveAspectRatio::kXMinYMin },
1077         { "xMidYMin", SkSVGPreserveAspectRatio::kXMidYMin },
1078         { "xMaxYMin", SkSVGPreserveAspectRatio::kXMaxYMin },
1079         { "xMinYMid", SkSVGPreserveAspectRatio::kXMinYMid },
1080         { "xMidYMid", SkSVGPreserveAspectRatio::kXMidYMid },
1081         { "xMaxYMid", SkSVGPreserveAspectRatio::kXMaxYMid },
1082         { "xMinYMax", SkSVGPreserveAspectRatio::kXMinYMax },
1083         { "xMidYMax", SkSVGPreserveAspectRatio::kXMidYMax },
1084         { "xMaxYMax", SkSVGPreserveAspectRatio::kXMaxYMax },
1085     };
1086 
1087     static constexpr std::tuple<const char*, SkSVGPreserveAspectRatio::Scale> gScaleMap[] = {
1088         { "meet" , SkSVGPreserveAspectRatio::kMeet  },
1089         { "slice", SkSVGPreserveAspectRatio::kSlice },
1090     };
1091 
1092     bool parsedValue = false;
1093 
1094     // ignoring optional 'defer'
1095     this->parseExpectedStringToken("defer");
1096     this->parseWSToken();
1097 
1098     if (this->parseEnumMap(gAlignMap, &par->fAlign)) {
1099         parsedValue = true;
1100 
1101         // optional scaling selector
1102         this->parseWSToken();
1103         this->parseEnumMap(gScaleMap, &par->fScale);
1104     }
1105 
1106     return parsedValue && this->parseEOSToken();
1107 }
1108 
1109 template <>
parse(SkSVGPreserveAspectRatio * par)1110 bool SkSVGAttributeParser::parse(SkSVGPreserveAspectRatio* par) {
1111     return this->parsePreserveAspectRatio(par);
1112 }
1113 
1114 // https://www.w3.org/TR/SVG11/types.html#DataTypeCoordinates
1115 template <typename T>
parseList(std::vector<T> * vals)1116 bool SkSVGAttributeParser::parseList(std::vector<T>* vals) {
1117     SkASSERT(vals->empty());
1118 
1119     T v;
1120     for (;;) {
1121         if (!this->parse(&v)) {
1122             break;
1123         }
1124 
1125         vals->push_back(v);
1126 
1127         this->parseCommaWspToken();
1128     }
1129 
1130     return !vals->empty() && this->parseEOSToken();
1131 }
1132 
1133 template <>
parse(std::vector<SkSVGLength> * lengths)1134 bool SkSVGAttributeParser::parse(std::vector<SkSVGLength>* lengths) {
1135     return this->parseList(lengths);
1136 }
1137 
1138 template <>
parse(std::vector<SkSVGNumberType> * numbers)1139 bool SkSVGAttributeParser::parse(std::vector<SkSVGNumberType>* numbers) {
1140     return this->parseList(numbers);
1141 }
1142 
1143 template <>
parse(SkSVGColorspace * colorspace)1144 bool SkSVGAttributeParser::parse(SkSVGColorspace* colorspace) {
1145     static constexpr std::tuple<const char*, SkSVGColorspace> gColorspaceMap[] = {
1146         { "auto"     , SkSVGColorspace::kAuto      },
1147         { "sRGB"     , SkSVGColorspace::kSRGB      },
1148         { "linearRGB", SkSVGColorspace::kLinearRGB },
1149     };
1150 
1151     return this->parseEnumMap(gColorspaceMap, colorspace) && this->parseEOSToken();
1152 }
1153 
1154 // https://www.w3.org/TR/SVG11/painting.html#DisplayProperty
1155 template <>
parse(SkSVGDisplay * display)1156 bool SkSVGAttributeParser::parse(SkSVGDisplay* display) {
1157     static const struct {
1158         SkSVGDisplay fType;
1159         const char*  fName;
1160     } gDisplayInfo[] = {
1161         { SkSVGDisplay::kInline, "inline" },
1162         { SkSVGDisplay::kNone  , "none"   },
1163     };
1164 
1165     bool parsedValue = false;
1166     for (const auto& parseInfo : gDisplayInfo) {
1167         if (this->parseExpectedStringToken(parseInfo.fName)) {
1168             *display = SkSVGDisplay(parseInfo.fType);
1169             parsedValue = true;
1170             break;
1171         }
1172     }
1173 
1174     return parsedValue && this->parseEOSToken();
1175 }
1176