Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkSVGAttributeParser.cpp
Go to the documentation of this file.
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
12#include "src/base/SkUTF.h"
13
14namespace {
15
16// TODO: these should be shared with SkParse.cpp
17
18inline bool is_between(char c, char min, char max) {
19 SkASSERT(min <= max);
20 return (unsigned)(c - min) <= (unsigned)(max - min);
21}
22
23inline bool is_ws(char c) {
24 return is_between(c, 1, 32);
25}
26
27inline bool is_sep(char c) {
28 return is_ws(c) || c == ',' || c == ';';
29}
30
31inline bool is_nl(char c) {
32 return c == '\n' || c == '\r' || c == '\f';
33}
34
35inline 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
43SkSVGAttributeParser::SkSVGAttributeParser(const char attributeString[])
44 // TODO: need actual UTF-8 with length.
45 : fCurPos(attributeString), fEndPos(fCurPos + strlen(attributeString)) {}
46
47template <typename F>
48inline bool SkSVGAttributeParser::advanceWhile(F f) {
49 auto initial = fCurPos;
50 while (fCurPos < fEndPos && f(*fCurPos)) {
51 fCurPos++;
52 }
53 return fCurPos != initial;
54}
55
56bool 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
75bool SkSVGAttributeParser::parseEOSToken() {
76 return fCurPos == fEndPos;
77}
78
79bool SkSVGAttributeParser::parseSepToken() {
80 return this->advanceWhile(is_sep);
81}
82
83bool SkSVGAttributeParser::parseWSToken() {
84 return this->advanceWhile(is_ws);
85}
86
87bool SkSVGAttributeParser::parseCommaWspToken() {
88 // comma-wsp:
89 // (wsp+ comma? wsp*) | (comma wsp*)
90 return this->parseWSToken() || this->parseExpectedStringToken(",");
91}
92
93bool 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
103bool 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
111bool 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
119bool SkSVGAttributeParser::matchHexToken(const char** newPos) const {
120 *newPos = fCurPos;
121 while (*newPos < fEndPos && is_hex(**newPos)) { ++*newPos; }
122 return *newPos != fCurPos;
123}
124
125bool 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
162bool 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
216bool SkSVGAttributeParser::parseLengthUnitToken(SkSVGLength::Unit* unit) {
217 static const struct {
218 const char* fUnitName;
219 SkSVGLength::Unit fUnit;
220 } gUnitInfo[] = {
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
242bool 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
257bool 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
291bool 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
308bool 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
323bool 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
334bool SkSVGAttributeParser::parseColorComponentToken(int32_t* c) {
335 return parseColorComponentIntegralToken(c) ||
336 parseColorComponentFractionalToken(c);
337}
338
339bool 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
357bool 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
378bool SkSVGAttributeParser::parseColorToken(SkColor* c) {
379 return this->parseHexColorToken(c) ||
380 this->parseNamedColorToken(c) ||
381 this->parseRGBAColorToken(c) ||
382 this->parseRGBColorToken(c);
383}
384
385bool 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).
397template <>
399 this->parseWSToken();
400 if (!this->parseSVGColorType(color)) {
401 return false;
402 }
403 this->parseWSToken();
404 return this->parseEOSToken();
405}
406
407bool 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")) {
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
445template <>
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
456template <>
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 {
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
479bool 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
490template <>
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
501template <>
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
519 // consume WS
520 this->parseWSToken();
521
522 // consume optional '+'
523 this->parseExpectedStringToken("+");
524
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
537template <>
539 SkScalar s;
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
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
565 parsedValue = true;
566 // consume trailing whitespace
567 this->parseWSToken();
568 }
569 return parsedValue && this->parseEOSToken();
570}
571
572template <typename Func, typename T>
573bool 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
599bool 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
614bool 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
631bool 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
647bool 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
668bool 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
679bool 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
691template <>
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
724template <>
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")) {
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
751template <>
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
767template <>
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
791template <>
793 static const struct {
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
816template <>
818 bool parsedValue = false;
819 if (this->parseExpectedStringToken("userSpaceOnUse")) {
820 *objectBoundingBoxUnits =
822 parsedValue = true;
823 } else if (this->parseExpectedStringToken("objectBoundingBox")) {
824 *objectBoundingBoxUnits =
826 parsedValue = true;
827 }
828 return parsedValue && this->parseEOSToken();
829}
830
831// https://www.w3.org/TR/SVG11/shapes.html#PolygonElementPointsAttribute
832template <>
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
881template <>
883 static const struct {
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
905template <>
907 static const struct {
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
930template <>
932 bool parsedValue = false;
933 if (this->parseExpectedStringToken("none")) {
935 parsedValue = true;
936 } else if (this->parseExpectedStringToken("inherit")) {
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
961template <>
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
982template <>
984 bool parsedValue = false;
985 if (this->parseExpectedStringToken("inherit")) {
986 *size = SkSVGFontSize();
987 parsedValue = true;
988 } else {
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
1000template <>
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;
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
1021template <>
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;
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
1052template <>
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;
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
1074 static constexpr std::tuple<const char*, SkSVGPreserveAspectRatio::Align> gAlignMap[] = {
1085 };
1086
1087 static constexpr std::tuple<const char*, SkSVGPreserveAspectRatio::Scale> gScaleMap[] = {
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
1109template <>
1113
1114// https://www.w3.org/TR/SVG11/types.html#DataTypeCoordinates
1115template <typename T>
1116bool 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
1133template <>
1134bool SkSVGAttributeParser::parse(std::vector<SkSVGLength>* lengths) {
1135 return this->parseList(lengths);
1136}
1137
1138template <>
1139bool SkSVGAttributeParser::parse(std::vector<SkSVGNumberType>* numbers) {
1140 return this->parseList(numbers);
1141}
1142
1143template <>
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
1155template <>
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}
const char * fName
static const int points[]
SkColor4f color
static float next(float f)
#define SkASSERT(cond)
Definition SkAssert.h:116
uint32_t SkColor
Definition SkColor.h:37
#define SkColorSetRGB(r, g, b)
Definition SkColor.h:57
static constexpr SkColor SkColorSetARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
Definition SkColor.h:49
constexpr SkColor SK_ColorBLACK
Definition SkColor.h:103
static bool is_ws(int c)
Definition SkParse.cpp:24
static bool is_sep(int c)
Definition SkParse.cpp:34
static bool is_hex(int c)
Definition SkParse.cpp:51
static bool is_between(int c, int min, int max)
Definition SkParse.cpp:19
SkSVGDisplay
Definition SkSVGTypes.h:726
SkSVGLineCap
Definition SkSVGTypes.h:288
SkRect SkSVGViewBoxType
Definition SkSVGTypes.h:29
SkColor SkSVGColorType
Definition SkSVGTypes.h:25
SkSVGColorspace
Definition SkSVGTypes.h:719
std::vector< SkPoint > SkSVGPointsType
Definition SkSVGTypes.h:31
SkString SkSVGStringType
Definition SkSVGTypes.h:28
SkMatrix SkSVGTransformType
Definition SkSVGTypes.h:30
SkScalar SkSVGNumberType
Definition SkSVGTypes.h:27
int SkSVGIntegerType
Definition SkSVGTypes.h:26
#define SkDegreesToRadians(degrees)
Definition SkScalar.h:77
#define SkScalarRoundToInt(x)
Definition SkScalar.h:37
int32_t SkUnichar
Definition SkTypes.h:175
static const SkMatrix & I()
static const char * FindScalar(const char str[], SkScalar *value)
Definition SkParse.cpp:216
static const char * FindHex(const char str[], uint32_t *value)
Definition SkParse.cpp:114
static const char * FindS32(const char str[], int32_t *value)
Definition SkParse.cpp:143
static const char * FindNamedColor(const char str[], size_t len, SkColor *color)
bool parsePreserveAspectRatio(SkSVGPreserveAspectRatio *)
bool parseInteger(SkSVGIntegerType *)
bool parseViewBox(SkSVGViewBoxType *)
bool parse(SkSVGIntegerType *v)
std::vector< SkString > Vars
Definition SkSVGTypes.h:184
const SkSVGIRI & iri() const
Definition SkSVGTypes.h:281
void appendUnichar(SkUnichar uni)
Definition SkString.h:207
bool startsWith(const char prefixStr[]) const
Definition SkString.h:140
void void void void void void void remove(size_t offset, size_t length)
Definition SkString.cpp:592
size_t size() const
Definition SkString.h:131
void append(const char text[])
Definition SkString.h:203
const char * c_str() const
Definition SkString.h:133
const Paint & paint
float SkScalar
Definition extension.cpp:12
static bool b
struct MyStruct s
struct MyStruct a[10]
GAsyncResult * result
static float max(float r, float g, float b)
Definition hsl.cpp:49
static float min(float r, float g, float b)
Definition hsl.cpp:48
size_t length
double y
double x
unsigned useCenter Optional< SkMatrix > matrix
Definition SkRecords.h:258
SK_SPI SkUnichar NextUTF8(const char **ptr, const char *end)
Definition SkUTF.cpp:118
SkScalar w
SkScalar h
#define T
Definition SkMD5.cpp:120
static constexpr SkPoint Make(float x, float y)
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition SkRect.h:659