aboutsummaryrefslogtreecommitdiffhomepage
path: root/experimental/svg/model/SkSVGAttributeParser.cpp
diff options
context:
space:
mode:
authorGravatar fmalita <fmalita@chromium.org>2016-08-03 10:21:11 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-08-03 10:21:11 -0700
commitbffc2566872f99d378a1113d0a49ec9ee0d60b7a (patch)
tree3a7fab8b6206e99201b1ea817c95454f340260c8 /experimental/svg/model/SkSVGAttributeParser.cpp
parent9e3d3d8b363edcdd81a13b2be046152c6bb839cd (diff)
[SVGDom] Initial SVGLength support
Mostly plumb new length types, but also introduce a stateful parser, rect shape and named color support. R=reed@google.com,robertphillips@google.com,stephana@google.com GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2202053002 Review-Url: https://codereview.chromium.org/2202053002
Diffstat (limited to 'experimental/svg/model/SkSVGAttributeParser.cpp')
-rw-r--r--experimental/svg/model/SkSVGAttributeParser.cpp194
1 files changed, 194 insertions, 0 deletions
diff --git a/experimental/svg/model/SkSVGAttributeParser.cpp b/experimental/svg/model/SkSVGAttributeParser.cpp
new file mode 100644
index 0000000000..75e5d12f38
--- /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;
+}