diff options
author | fmalita <fmalita@chromium.org> | 2016-08-08 12:58:57 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-08-08 12:58:57 -0700 |
commit | c97796b47b2f3e0ca8c04073c1576db21b58eedb (patch) | |
tree | f77603d9a868ee5f9cc2a9d54d67c2ea57a1ff07 /experimental/svg | |
parent | 9dcdc352c14eb95a833961b22682ed9900059dae (diff) |
[SVGDom] Improved transform parsing
Update 'transform' attribute parsing to a more robust, SkSVGAttributeParser-based implementation.
R=robertphillips@google.com,stephana@google.com
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2220933003
Review-Url: https://codereview.chromium.org/2220933003
Diffstat (limited to 'experimental/svg')
-rw-r--r-- | experimental/svg/model/SkSVGAttributeParser.cpp | 141 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGAttributeParser.h | 14 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGDOM.cpp | 56 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGTransformableNode.cpp | 6 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGTransformableNode.h | 4 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGTypes.h | 8 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGValue.h | 10 |
7 files changed, 177 insertions, 62 deletions
diff --git a/experimental/svg/model/SkSVGAttributeParser.cpp b/experimental/svg/model/SkSVGAttributeParser.cpp index 62ca4c8ab2..f973d385f5 100644 --- a/experimental/svg/model/SkSVGAttributeParser.cpp +++ b/experimental/svg/model/SkSVGAttributeParser.cpp @@ -211,3 +211,144 @@ bool SkSVGAttributeParser::parseViewBox(SkSVGViewBoxType* vb) { } return parsedValue && this->parseEOSToken(); } + +template <typename Func, typename T> +bool SkSVGAttributeParser::parseParenthesized(const char* prefix, Func f, T* result) { + this->parseWSToken(); + if (prefix && !this->parseExpectedStringToken(prefix)) { + return false; + } + this->parseWSToken(); + if (!this->parseExpectedStringToken("(")) { + return false; + } + this->parseWSToken(); + + if (!f(result)) { + return false; + } + this->parseWSToken(); + + return this->parseExpectedStringToken(")"); +} + +bool SkSVGAttributeParser::parseMatrixToken(SkMatrix* matrix) { + return this->parseParenthesized("matrix", [this](SkMatrix* m) -> bool { + SkScalar scalars[6]; + for (int i = 0; i < 6; ++i) { + if (!(this->parseScalarToken(scalars + i) && + (i > 4 || this->parseSepToken()))) { + return false; + } + } + + m->setAll(scalars[0], scalars[2], scalars[4], scalars[1], scalars[3], scalars[5], 0, 0, 1); + return true; + }, matrix); +} + +bool SkSVGAttributeParser::parseTranslateToken(SkMatrix* matrix) { + return this->parseParenthesized("translate", [this](SkMatrix* m) -> bool { + SkScalar tx, ty; + this->parseWSToken(); + if (!this->parseScalarToken(&tx)) { + return false; + } + + if (!(this->parseSepToken() && this->parseScalarToken(&ty))) { + ty = tx; + } + + m->setTranslate(tx, ty); + return true; + }, matrix); +} + +bool SkSVGAttributeParser::parseScaleToken(SkMatrix* matrix) { + return this->parseParenthesized("scale", [this](SkMatrix* m) -> bool { + SkScalar sx, sy; + if (!this->parseScalarToken(&sx)) { + return false; + } + + if (!(this->parseSepToken() && this->parseScalarToken(&sy))) { + sy = sx; + } + + m->setScale(sx, sy); + return true; + }, matrix); +} + +bool SkSVGAttributeParser::parseRotateToken(SkMatrix* matrix) { + return this->parseParenthesized("rotate", [this](SkMatrix* m) -> bool { + SkScalar angle; + if (!this->parseScalarToken(&angle)) { + return false; + } + + SkScalar cx = 0; + SkScalar cy = 0; + // optional [<cx> <cy>] + if (this->parseSepToken() && this->parseScalarToken(&cx)) { + if (!(this->parseSepToken() && this->parseScalarToken(&cy))) { + return false; + } + } + + m->setRotate(angle, cx, cy); + return true; + }, matrix); +} + +bool SkSVGAttributeParser::parseSkewXToken(SkMatrix* matrix) { + return this->parseParenthesized("skewX", [this](SkMatrix* m) -> bool { + SkScalar angle; + if (!this->parseScalarToken(&angle)) { + return false; + } + m->setSkewX(angle); + return true; + }, matrix); +} + +bool SkSVGAttributeParser::parseSkewYToken(SkMatrix* matrix) { + return this->parseParenthesized("skewY", [this](SkMatrix* m) -> bool { + SkScalar angle; + if (!this->parseScalarToken(&angle)) { + return false; + } + m->setSkewY(angle); + return true; + }, matrix); +} + +// https://www.w3.org/TR/SVG/coords.html#TransformAttribute +bool SkSVGAttributeParser::parseTransform(SkSVGTransformType* t) { + SkMatrix matrix = SkMatrix::I(); + + bool parsed = false; + while (true) { + SkMatrix m; + + if (!( this->parseMatrixToken(&m) + || this->parseTranslateToken(&m) + || this->parseScaleToken(&m) + || this->parseRotateToken(&m) + || this->parseSkewXToken(&m) + || this->parseSkewYToken(&m))) { + break; + } + + matrix.preConcat(m); + parsed = true; + } + + this->parseWSToken(); + if (!parsed || !this->parseEOSToken()) { + return false; + } + + *t = SkSVGTransformType(matrix); + return true; +} diff --git a/experimental/svg/model/SkSVGAttributeParser.h b/experimental/svg/model/SkSVGAttributeParser.h index cd50479fee..c616113d6b 100644 --- a/experimental/svg/model/SkSVGAttributeParser.h +++ b/experimental/svg/model/SkSVGAttributeParser.h @@ -18,6 +18,7 @@ public: bool parseNumber(SkSVGNumberType*); bool parseLength(SkSVGLength*); bool parseViewBox(SkSVGViewBoxType*); + bool parseTransform(SkSVGTransformType*); private: // Stack-only @@ -37,6 +38,19 @@ private: bool parseNamedColorToken(SkColor*); bool parseHexColorToken(SkColor*); + // Transform helpers + bool parseMatrixToken(SkMatrix*); + bool parseTranslateToken(SkMatrix*); + bool parseScaleToken(SkMatrix*); + bool parseRotateToken(SkMatrix*); + bool parseSkewXToken(SkMatrix*); + bool parseSkewYToken(SkMatrix*); + + // Parses a sequence of 'WS* <prefix> WS* (<nested>)', where the nested sequence + // is handled by the passed functor. + template <typename Func, typename T> + bool parseParenthesized(const char* prefix, Func, T* result); + // The current position in the input string. const char* fCurPos; diff --git a/experimental/svg/model/SkSVGDOM.cpp b/experimental/svg/model/SkSVGDOM.cpp index 13d67b9cfe..9b67484fbc 100644 --- a/experimental/svg/model/SkSVGDOM.cpp +++ b/experimental/svg/model/SkSVGDOM.cpp @@ -7,7 +7,6 @@ #include "SkCanvas.h" #include "SkDOM.h" -#include "SkParse.h" #include "SkParsePath.h" #include "SkString.h" #include "SkSVGAttributeParser.h" @@ -24,53 +23,6 @@ namespace { -const char* ParseScalarPair(const char* str, SkScalar v[2]) { - str = SkParse::FindScalar(str, v); - if (str) { - const char* second = SkParse::FindScalar(str, v + 1); - if (!second) { - v[1] = v[0]; - } else { - str = second; - } - } - - return str; -} - -SkMatrix ParseTransform(const char* str) { - SkMatrix m = SkMatrix::I(); - - // FIXME: real parser - if (!strncmp(str, "matrix(", 7)) { - SkScalar values[6]; - str = SkParse::FindScalars(str + 7, values, 6); - if (str) { - m.setAffine(values); - } - } else if (!strncmp(str, "scale(", 6)) { - SkScalar values[2]; - str = ParseScalarPair(str + 6, values); - if (str) { - m.setScale(values[0], values[1]); - } - } else if (!strncmp(str, "translate(", 10)) { - SkScalar values[2]; - str = ParseScalarPair(str + 10, values); - if (str) { - m.setTranslate(values[0], values[1]); - } - } else if (!strncmp(str, "rotate(", 7)) { - SkScalar value; - str = SkParse::FindScalar(str + 7, &value); - if (str) { - m.setRotate(value); - } - } - - return m; -} - bool SetPaintAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, const char* stringValue) { SkSVGColorType color; @@ -96,7 +48,13 @@ bool SetPathDataAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, bool SetTransformAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, const char* stringValue) { - node->setAttribute(attr, SkSVGTransformValue(ParseTransform(stringValue))); + SkSVGTransformType transform; + SkSVGAttributeParser parser(stringValue); + if (!parser.parseTransform(&transform)) { + return false; + } + + node->setAttribute(attr, SkSVGTransformValue(transform)); return true; } diff --git a/experimental/svg/model/SkSVGTransformableNode.cpp b/experimental/svg/model/SkSVGTransformableNode.cpp index 2686a4c542..8a095ac62a 100644 --- a/experimental/svg/model/SkSVGTransformableNode.cpp +++ b/experimental/svg/model/SkSVGTransformableNode.cpp @@ -12,13 +12,13 @@ SkSVGTransformableNode::SkSVGTransformableNode(SkSVGTag tag) : INHERITED(tag) - , fMatrix(SkMatrix::I()) { } + , fTransform(SkMatrix::I()) { } bool SkSVGTransformableNode::onPrepareToRender(SkSVGRenderContext* ctx) const { - if (!fMatrix.isIdentity()) { + if (!fTransform.value().isIdentity()) { ctx->canvas()->save(); - ctx->canvas()->concat(fMatrix); + ctx->canvas()->concat(fTransform); } return this->INHERITED::onPrepareToRender(ctx); diff --git a/experimental/svg/model/SkSVGTransformableNode.h b/experimental/svg/model/SkSVGTransformableNode.h index 475fafb44f..05644ac973 100644 --- a/experimental/svg/model/SkSVGTransformableNode.h +++ b/experimental/svg/model/SkSVGTransformableNode.h @@ -15,7 +15,7 @@ class SkSVGTransformableNode : public SkSVGNode { public: virtual ~SkSVGTransformableNode() = default; - void setTransform(const SkMatrix& m) { fMatrix = m; } + void setTransform(const SkSVGTransformType& t) { fTransform = t; } protected: SkSVGTransformableNode(SkSVGTag); @@ -26,7 +26,7 @@ protected: private: // FIXME: should be sparse - SkMatrix fMatrix; + SkSVGTransformType fTransform; typedef SkSVGNode INHERITED; }; diff --git a/experimental/svg/model/SkSVGTypes.h b/experimental/svg/model/SkSVGTypes.h index ab07d7b16c..b2e2db1076 100644 --- a/experimental/svg/model/SkSVGTypes.h +++ b/experimental/svg/model/SkSVGTypes.h @@ -9,6 +9,7 @@ #define SkSVGTypes_DEFINED #include "SkColor.h" +#include "SkMatrix.h" #include "SkRect.h" #include "SkScalar.h" #include "SkTypes.h" @@ -29,9 +30,10 @@ private: T fValue; }; -using SkSVGColorType = SkSVGPrimitiveTypeWrapper<SkColor >; -using SkSVGNumberType = SkSVGPrimitiveTypeWrapper<SkScalar>; -using SkSVGViewBoxType = SkSVGPrimitiveTypeWrapper<SkRect >; +using SkSVGColorType = SkSVGPrimitiveTypeWrapper<SkColor >; +using SkSVGNumberType = SkSVGPrimitiveTypeWrapper<SkScalar>; +using SkSVGViewBoxType = SkSVGPrimitiveTypeWrapper<SkRect >; +using SkSVGTransformType = SkSVGPrimitiveTypeWrapper<SkMatrix>; class SkSVGLength { public: diff --git a/experimental/svg/model/SkSVGValue.h b/experimental/svg/model/SkSVGValue.h index 77619c2241..00715e2a5b 100644 --- a/experimental/svg/model/SkSVGValue.h +++ b/experimental/svg/model/SkSVGValue.h @@ -61,10 +61,10 @@ private: typedef SkSVGValue INHERITED; }; -using SkSVGColorValue = SkSVGWrapperValue<SkSVGColorType , SkSVGValue::Type::kColor >; -using SkSVGLengthValue = SkSVGWrapperValue<SkSVGLength , SkSVGValue::Type::kLength >; -using SkSVGPathValue = SkSVGWrapperValue<SkPath , SkSVGValue::Type::kPath >; -using SkSVGTransformValue = SkSVGWrapperValue<SkMatrix , SkSVGValue::Type::kTransform>; -using SkSVGViewBoxValue = SkSVGWrapperValue<SkSVGViewBoxType, SkSVGValue::Type::kViewBox >; +using SkSVGColorValue = SkSVGWrapperValue<SkSVGColorType , SkSVGValue::Type::kColor >; +using SkSVGLengthValue = SkSVGWrapperValue<SkSVGLength , SkSVGValue::Type::kLength >; +using SkSVGPathValue = SkSVGWrapperValue<SkPath , SkSVGValue::Type::kPath >; +using SkSVGTransformValue = SkSVGWrapperValue<SkSVGTransformType, SkSVGValue::Type::kTransform>; +using SkSVGViewBoxValue = SkSVGWrapperValue<SkSVGViewBoxType , SkSVGValue::Type::kViewBox >; #endif // SkSVGValue_DEFINED |