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..75e5d12f38558868bc2b15dfa426b15c84d1740f |
--- /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[]) |
+ : fCurPos(attributeString) {} |
+ |
+template <typename F> |
+inline bool SkSVGAttributeParser::advanceWhile(F f) { |
+ auto initial = fCurPos; |
+ while (f(*fCurPos)) { |
+ fCurPos++; |
+ } |
+ return fCurPos != initial; |
+} |
+ |
+inline bool SkSVGAttributeParser::parseEOSToken() { |
+ return is_eos(*fCurPos); |
+} |
+ |
+inline bool SkSVGAttributeParser::parseSepToken() { |
+ return this->advanceWhile(is_sep); |
+} |
+ |
+inline bool SkSVGAttributeParser::parseWSToken() { |
+ return this->advanceWhile(is_ws); |
+} |
+ |
+inline bool SkSVGAttributeParser::parseExpectedStringToken(const char* expected) { |
+ const char* c = fCurPos; |
+ |
+ while (*c && *expected && *c == *expected) { |
+ c++; |
+ expected++; |
+ } |
+ |
+ if (*expected) { |
+ return false; |
+ } |
+ |
+ fCurPos = c; |
+ return true; |
+} |
+ |
+bool SkSVGAttributeParser::parseScalarToken(SkScalar* res) { |
+ if (const char* next = SkParse::FindScalar(fCurPos, res)) { |
+ fCurPos = next; |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+bool SkSVGAttributeParser::parseHexToken(uint32_t* res) { |
+ if (const char* next = SkParse::FindHex(fCurPos, res)) { |
+ fCurPos = next; |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+bool SkSVGAttributeParser::parseLengthUnitToken(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->parseExpectedStringToken(gUnitInfo[i].fUnitName)) { |
+ *unit = gUnitInfo[i].fUnit; |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
+bool SkSVGAttributeParser::parseNamedColorToken(SkColor* c) { |
+ if (const char* next = SkParse::FindNamedColor(fCurPos, strlen(fCurPos), c)) { |
+ fCurPos = next; |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+bool SkSVGAttributeParser::parseHexColorToken(SkColor* c) { |
+ uint32_t v; |
+ const char* initial = fCurPos; |
+ |
+ if (!this->parseExpectedStringToken("#") || !this->parseHexToken(&v)) { |
+ return false; |
+ } |
+ |
+ switch (fCurPos - 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->parseHexColorToken(&c) || this->parseNamedColorToken(&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->parseWSToken(); |
+ |
+ SkScalar s; |
+ if (this->parseScalarToken(&s)) { |
+ *number = SkSVGNumber(s); |
+ // consume trailing separators |
+ this->parseSepToken(); |
+ 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->parseScalarToken(&s) && |
+ (this->parseLengthUnitToken(&u) || this->parseSepToken() || this->parseEOSToken())) { |
+ *length = SkSVGLength(s, u); |
+ // consume trailing separators |
+ this->parseSepToken(); |
+ return true; |
+ } |
+ |
+ return false; |
+} |