From 58649ccc75c033ea4e0c9a664b4ed178816a50c6 Mon Sep 17 00:00:00 2001 From: fmalita Date: Fri, 29 Jul 2016 08:52:03 -0700 Subject: [PATCH] [SVGDom] Parse style attributes Dispatch style-encoded (style="foo: bar; ...") attributes via normal attribute setters. R=reed@google.com,robertphillips@google.com GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2193663002 Review-Url: https://codereview.chromium.org/2193663002 --- experimental/svg/model/SkSVGAttribute.h | 10 ++- experimental/svg/model/SkSVGDOM.cpp | 94 +++++++++++++++++++---- experimental/svg/model/SkSVGG.h | 2 +- experimental/svg/model/SkSVGNode.cpp | 4 +- experimental/svg/model/SkSVGNode.h | 6 +- experimental/svg/model/SkSVGPath.cpp | 4 +- experimental/svg/model/SkSVGSVG.cpp | 2 +- experimental/svg/model/SkSVGTransformableNode.cpp | 2 +- 8 files changed, 93 insertions(+), 31 deletions(-) diff --git a/experimental/svg/model/SkSVGAttribute.h b/experimental/svg/model/SkSVGAttribute.h index 50989f1..83a3552 100644 --- a/experimental/svg/model/SkSVGAttribute.h +++ b/experimental/svg/model/SkSVGAttribute.h @@ -12,10 +12,12 @@ #include "SkTLazy.h" enum class SkSVGAttribute { - d, - fill, - stroke, - transform, + kD, + kFill, + kStroke, + kTransform, + + kUnknown, }; class SkSVGRenderContext; diff --git a/experimental/svg/model/SkSVGDOM.cpp b/experimental/svg/model/SkSVGDOM.cpp index 6f782c3..4e2f898 100644 --- a/experimental/svg/model/SkSVGDOM.cpp +++ b/experimental/svg/model/SkSVGDOM.cpp @@ -9,6 +9,7 @@ #include "SkDOM.h" #include "SkParse.h" #include "SkParsePath.h" +#include "SkString.h" #include "SkSVGDOM.h" #include "SkSVGG.h" #include "SkSVGNode.h" @@ -118,6 +119,60 @@ bool SetTransformAttribute(const sk_sp& node, SkSVGAttribute attr, return true; } +// Breaks a "foo: bar; baz: ..." string into key:value pairs. +class StyleIterator { +public: + StyleIterator(const char* str) : fPos(str) { } + + std::tuple next() { + SkString name, value; + + if (fPos) { + const char* sep = this->nextSeparator(); + SkASSERT(*sep == ';' || *sep == '\0'); + + const char* valueSep = strchr(fPos, ':'); + if (valueSep && valueSep < sep) { + name.set(fPos, valueSep - fPos); + value.set(valueSep + 1, sep - valueSep - 1); + } + + fPos = *sep ? sep + 1 : nullptr; + } + + return std::make_tuple(name, value); + } + +private: + const char* nextSeparator() const { + const char* sep = fPos; + while (*sep != ';' && *sep != '\0') { + sep++; + } + return sep; + } + + const char* fPos; +}; + +void set_string_attribute(const sk_sp& node, const char* name, const char* value); + +bool SetStyleAttributes(const sk_sp& node, SkSVGAttribute, + const char* stringValue) { + + SkString name, value; + StyleIterator iter(stringValue); + for (;;) { + std::tie(name, value) = iter.next(); + if (name.isEmpty()) { + break; + } + set_string_attribute(node, name.c_str(), value.c_str()); + } + + return true; +} + template struct SortedDictionaryEntry { const char* fKey; @@ -130,10 +185,11 @@ struct AttrParseInfo { }; SortedDictionaryEntry gAttributeParseInfo[] = { - { "d", { SkSVGAttribute::d, SetPathDataAttribute }}, - { "fill", { SkSVGAttribute::fill, SetPaintAttribute }}, - { "stroke", { SkSVGAttribute::stroke, SetPaintAttribute }}, - { "transform", { SkSVGAttribute::transform, SetTransformAttribute }}, + { "d", { SkSVGAttribute::kD, SetPathDataAttribute }}, + { "fill", { SkSVGAttribute::kFill, SetPaintAttribute }}, + { "stroke", { SkSVGAttribute::kStroke, SetPaintAttribute }}, + { "style", { SkSVGAttribute::kUnknown, SetStyleAttributes }}, + { "transform", { SkSVGAttribute::kTransform, SetTransformAttribute }}, }; SortedDictionaryEntry(*)()> gTagFactories[] = { @@ -150,24 +206,28 @@ struct ConstructionContext { const SkSVGNode* fParent; }; +void set_string_attribute(const sk_sp& node, const char* name, const char* value) { + const int attrIndex = SkStrSearch(&gAttributeParseInfo[0].fKey, + SkTo(SK_ARRAY_COUNT(gAttributeParseInfo)), + name, sizeof(gAttributeParseInfo[0])); + if (attrIndex < 0) { + SkDebugf("unhandled attribute: %s\n", name); + return; + } + + SkASSERT(SkTo(attrIndex) < SK_ARRAY_COUNT(gAttributeParseInfo)); + const auto& attrInfo = gAttributeParseInfo[attrIndex].fValue; + if (!attrInfo.fSetter(node, attrInfo.fAttr, value)) { + SkDebugf("could not parse attribute: '%s=\"%s\"'\n", name, value); + } +} + void parse_node_attributes(const SkDOM& xmlDom, const SkDOM::Node* xmlNode, const sk_sp& svgNode) { const char* name, *value; SkDOM::AttrIter attrIter(xmlDom, xmlNode); while ((name = attrIter.next(&value))) { - const int attrIndex = SkStrSearch(&gAttributeParseInfo[0].fKey, - SkTo(SK_ARRAY_COUNT(gAttributeParseInfo)), - name, sizeof(gAttributeParseInfo[0])); - if (attrIndex < 0) { - SkDebugf("unhandled attribute: %s\n", name); - continue; - } - - SkASSERT(SkTo(attrIndex) < SK_ARRAY_COUNT(gAttributeParseInfo)); - const auto& attrInfo = gAttributeParseInfo[attrIndex].fValue; - if (!attrInfo.fSetter(svgNode, attrInfo.fAttr, value)) { - SkDebugf("could not parse attribute: '%s=\"%s\"'\n", name, value); - } + set_string_attribute(svgNode, name, value); } } diff --git a/experimental/svg/model/SkSVGG.h b/experimental/svg/model/SkSVGG.h index eaaf822..b8229c0 100644 --- a/experimental/svg/model/SkSVGG.h +++ b/experimental/svg/model/SkSVGG.h @@ -17,7 +17,7 @@ public: static sk_sp Make() { return sk_sp(new SkSVGG()); } private: - SkSVGG() : INHERITED(SkSVGTag::g) { } + SkSVGG() : INHERITED(SkSVGTag::kG) { } typedef SkSVGContainer INHERITED; }; diff --git a/experimental/svg/model/SkSVGNode.cpp b/experimental/svg/model/SkSVGNode.cpp index 2b89179..58e0ad4 100644 --- a/experimental/svg/model/SkSVGNode.cpp +++ b/experimental/svg/model/SkSVGNode.cpp @@ -40,12 +40,12 @@ void SkSVGNode::setAttribute(SkSVGAttribute attr, const SkSVGValue& v) { void SkSVGNode::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) { switch (attr) { - case SkSVGAttribute::fill: + case SkSVGAttribute::kFill: if (const SkSVGColorValue* color = v.as()) { fPresentationAttributes.setFill(*color); } break; - case SkSVGAttribute::stroke: + case SkSVGAttribute::kStroke: if (const SkSVGColorValue* color = v.as()) { fPresentationAttributes.setStroke(*color); } diff --git a/experimental/svg/model/SkSVGNode.h b/experimental/svg/model/SkSVGNode.h index de18014..407e69a 100644 --- a/experimental/svg/model/SkSVGNode.h +++ b/experimental/svg/model/SkSVGNode.h @@ -17,9 +17,9 @@ class SkSVGRenderContext; class SkSVGValue; enum class SkSVGTag { - g, - path, - svg + kG, + kPath, + kSvg }; class SkSVGNode : public SkRefCnt { diff --git a/experimental/svg/model/SkSVGPath.cpp b/experimental/svg/model/SkSVGPath.cpp index ba5e3d6..7d90594 100644 --- a/experimental/svg/model/SkSVGPath.cpp +++ b/experimental/svg/model/SkSVGPath.cpp @@ -11,7 +11,7 @@ #include "SkSVGRenderContext.h" #include "SkSVGValue.h" -SkSVGPath::SkSVGPath() : INHERITED(SkSVGTag::path) { } +SkSVGPath::SkSVGPath() : INHERITED(SkSVGTag::kPath) { } void SkSVGPath::doRender(SkCanvas* canvas, const SkPaint* paint) const { if (paint) { @@ -26,7 +26,7 @@ void SkSVGPath::onRender(SkCanvas* canvas, const SkSVGRenderContext& ctx) const void SkSVGPath::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) { switch (attr) { - case SkSVGAttribute::d: + case SkSVGAttribute::kD: if (const auto* path = v.as()) { this->setPath(*path); } diff --git a/experimental/svg/model/SkSVGSVG.cpp b/experimental/svg/model/SkSVGSVG.cpp index feae0d7..aeccc70 100644 --- a/experimental/svg/model/SkSVGSVG.cpp +++ b/experimental/svg/model/SkSVGSVG.cpp @@ -7,4 +7,4 @@ #include "SkSVGSVG.h" -SkSVGSVG::SkSVGSVG() : INHERITED(SkSVGTag::svg) { } +SkSVGSVG::SkSVGSVG() : INHERITED(SkSVGTag::kSvg) { } diff --git a/experimental/svg/model/SkSVGTransformableNode.cpp b/experimental/svg/model/SkSVGTransformableNode.cpp index 1af89d8..3636754 100644 --- a/experimental/svg/model/SkSVGTransformableNode.cpp +++ b/experimental/svg/model/SkSVGTransformableNode.cpp @@ -14,7 +14,7 @@ SkSVGTransformableNode::SkSVGTransformableNode(SkSVGTag tag) void SkSVGTransformableNode::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) { switch (attr) { - case SkSVGAttribute::transform: + case SkSVGAttribute::kTransform: if (const auto* transform = v.as()) { this->setTransform(*transform); } -- 2.7.4