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