Chromium Code Reviews| Index: experimental/svg/model/SkSVGAttributeParser.cpp |
| diff --git a/experimental/svg/model/SkSVGAttributeParser.cpp b/experimental/svg/model/SkSVGAttributeParser.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..22e44d2219b9aa1e6d359568a929c955aa659673 |
| --- /dev/null |
| +++ b/experimental/svg/model/SkSVGAttributeParser.cpp |
| @@ -0,0 +1,194 @@ |
| +/* |
| + * Copyright 2016 Google Inc. |
| + * |
| + * Use of this source code is governed by a BSD-style license that can be |
| + * found in the LICENSE file. |
| + */ |
| + |
| +#include "SkParse.h" |
| +#include "SkSVGAttributeParser.h" |
| +#include "SkSVGTypes.h" |
| + |
| +namespace { |
| + |
| +// TODO: these should be shared with SkParse.cpp |
| + |
| +inline bool is_between(char c, char min, char max) { |
| + SkASSERT(min <= max); |
| + return (unsigned)(c - min) <= (unsigned)(max - min); |
| +} |
| + |
| +inline bool is_eos(char c) { |
| + return !c; |
| +} |
| + |
| +inline bool is_ws(char c) { |
| + return is_between(c, 1, 32); |
| +} |
| + |
| +inline bool is_sep(char c) { |
| + return is_ws(c) || c == ',' || c == ';'; |
| +} |
| + |
| +} // anonymous ns |
| + |
| +SkSVGAttributeParser::SkSVGAttributeParser(const char attributeString[]) |
| + : fChr(attributeString) {} |
| + |
| +template <typename F> |
| +inline bool SkSVGAttributeParser::advanceWhile(F f) { |
| + auto initial = fChr; |
| + while (f(*fChr)) { |
| + fChr++; |
| + } |
| + return fChr != initial; |
| +} |
| + |
| +inline bool SkSVGAttributeParser::parseEOSAtom() { |
| + return is_eos(*fChr); |
| +} |
| + |
| +inline bool SkSVGAttributeParser::parseSepAtom() { |
| + return this->advanceWhile(is_sep); |
| +} |
| + |
| +inline bool SkSVGAttributeParser::parseWSAtom() { |
| + return this->advanceWhile(is_ws); |
| +} |
| + |
|
robertphillips
2016/08/02 22:25:56
consumeExpectedToken ?
f(malita)
2016/08/03 16:50:51
Done (parseExpectedStringToken for consistency wit
|
| +inline bool SkSVGAttributeParser::parseStringAtom(const char* expected) { |
| + const char* c = fChr; |
| + |
| + while (*c && *expected && *c == *expected) { |
| + c++; |
| + expected++; |
| + } |
| + |
| + if (*expected) { |
| + return false; |
| + } |
| + |
| + fChr = c; |
| + return true; |
| +} |
| + |
| +bool SkSVGAttributeParser::parseScalarAtom(SkScalar* res) { |
| + if (const char* next = SkParse::FindScalar(fChr, res)) { |
| + fChr = next; |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| +bool SkSVGAttributeParser::parseHexAtom(uint32_t* res) { |
| + if (const char* next = SkParse::FindHex(fChr, res)) { |
| + fChr = next; |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| +bool SkSVGAttributeParser::parseLengthUnitAtom(SkSVGLength::Unit* unit) { |
| + static const struct { |
| + const char* fUnitName; |
| + SkSVGLength::Unit fUnit; |
| + } gUnitInfo[] = { |
| + { "%" , SkSVGLength::Unit::kPercentage }, |
| + { "em", SkSVGLength::Unit::kEMS }, |
| + { "ex", SkSVGLength::Unit::kEXS }, |
| + { "px", SkSVGLength::Unit::kPX }, |
| + { "cm", SkSVGLength::Unit::kCM }, |
| + { "mm", SkSVGLength::Unit::kMM }, |
| + { "in", SkSVGLength::Unit::kIN }, |
| + { "pt", SkSVGLength::Unit::kPT }, |
| + { "pc", SkSVGLength::Unit::kPC }, |
| + }; |
| + |
| + for (size_t i = 0; i < SK_ARRAY_COUNT(gUnitInfo); ++i) { |
| + if (this->parseStringAtom(gUnitInfo[i].fUnitName)) { |
| + *unit = gUnitInfo[i].fUnit; |
| + return true; |
| + } |
| + } |
| + return false; |
| +} |
| + |
| +bool SkSVGAttributeParser::parseNamedColorAtom(SkColor* c) { |
| + if (const char* next = SkParse::FindNamedColor(fChr, strlen(fChr), c)) { |
| + fChr = next; |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| +bool SkSVGAttributeParser::parseHexColorAtom(SkColor* c) { |
| + uint32_t v; |
| + const char* initial = fChr; |
| + |
| + if (!this->parseStringAtom("#") || !this->parseHexAtom(&v)) { |
| + return false; |
| + } |
| + |
| + switch (fChr - initial) { |
| + case 7: |
| + // matched #xxxxxxx |
| + break; |
| + case 4: |
| + // matched '#xxx; |
| + v = ((v << 12) & 0x00f00000) | |
| + ((v << 8) & 0x000ff000) | |
| + ((v << 4) & 0x00000ff0) | |
| + ((v << 0) & 0x0000000f); |
| + break; |
| + default: |
| + return false; |
| + } |
| + |
| + *c = v | 0xff000000; |
| + return true; |
| +} |
| + |
| +// https://www.w3.org/TR/SVG/types.html#DataTypeColor |
| +bool SkSVGAttributeParser::parseColor(SkSVGColor* color) { |
| + SkColor c; |
| + |
| + // TODO: rgb(...) |
| + if (this->parseHexColorAtom(&c) || this->parseNamedColorAtom(&c)) { |
| + *color = SkSVGColor(c); |
| + return true; |
| + } |
| + |
| + return false; |
| +} |
| + |
| +// https://www.w3.org/TR/SVG/types.html#DataTypeNumber |
| +bool SkSVGAttributeParser::parseNumber(SkSVGNumber* number) { |
| + // consume WS |
| + this->parseWSAtom(); |
| + |
| + SkScalar s; |
| + if (this->parseScalarAtom(&s)) { |
| + *number = SkSVGNumber(s); |
| + // consume trailing separators |
| + this->parseSepAtom(); |
| + return true; |
| + } |
| + |
| + return false; |
| +} |
| + |
| +// https://www.w3.org/TR/SVG/types.html#DataTypeLength |
| +bool SkSVGAttributeParser::parseLength(SkSVGLength* length) { |
| + SkScalar s; |
| + SkSVGLength::Unit u = SkSVGLength::Unit::kNumber; |
| + |
| + if (this->parseScalarAtom(&s) && |
| + (this->parseLengthUnitAtom(&u) || this->parseSepAtom() || this->parseEOSAtom())) { |
| + *length = SkSVGLength(s, u); |
| + // consume trailing separators |
| + this->parseSepAtom(); |
| + return true; |
| + } |
| + |
| + return false; |
| +} |