diff options
author | fmalita <fmalita@chromium.org> | 2016-08-03 10:21:11 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-08-03 10:21:11 -0700 |
commit | bffc2566872f99d378a1113d0a49ec9ee0d60b7a (patch) | |
tree | 3a7fab8b6206e99201b1ea817c95454f340260c8 /experimental/svg/model/SkSVGAttributeParser.cpp | |
parent | 9e3d3d8b363edcdd81a13b2be046152c6bb839cd (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.cpp | 194 |
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; +} |