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; |
+} |