[SVGDom] Parse style attributes
authorfmalita <fmalita@chromium.org>
Fri, 29 Jul 2016 15:52:03 +0000 (08:52 -0700)
committerCommit bot <commit-bot@chromium.org>
Fri, 29 Jul 2016 15:52:03 +0000 (08:52 -0700)
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
experimental/svg/model/SkSVGDOM.cpp
experimental/svg/model/SkSVGG.h
experimental/svg/model/SkSVGNode.cpp
experimental/svg/model/SkSVGNode.h
experimental/svg/model/SkSVGPath.cpp
experimental/svg/model/SkSVGSVG.cpp
experimental/svg/model/SkSVGTransformableNode.cpp

index 50989f1..83a3552 100644 (file)
 #include "SkTLazy.h"
 
 enum class SkSVGAttribute {
-    d,
-    fill,
-    stroke,
-    transform,
+    kD,
+    kFill,
+    kStroke,
+    kTransform,
+
+    kUnknown,
 };
 
 class SkSVGRenderContext;
index 6f782c3..4e2f898 100644 (file)
@@ -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<SkSVGNode>& 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<SkString, SkString> 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<SkSVGNode>& node, const char* name, const char* value);
+
+bool SetStyleAttributes(const sk_sp<SkSVGNode>& 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<typename T>
 struct SortedDictionaryEntry {
     const char* fKey;
@@ -130,10 +185,11 @@ struct AttrParseInfo {
 };
 
 SortedDictionaryEntry<AttrParseInfo> 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<sk_sp<SkSVGNode>(*)()> gTagFactories[] = {
@@ -150,24 +206,28 @@ struct ConstructionContext {
     const SkSVGNode* fParent;
 };
 
+void set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value) {
+    const int attrIndex = SkStrSearch(&gAttributeParseInfo[0].fKey,
+                                      SkTo<int>(SK_ARRAY_COUNT(gAttributeParseInfo)),
+                                      name, sizeof(gAttributeParseInfo[0]));
+    if (attrIndex < 0) {
+        SkDebugf("unhandled attribute: %s\n", name);
+        return;
+    }
+
+    SkASSERT(SkTo<size_t>(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<SkSVGNode>& svgNode) {
     const char* name, *value;
     SkDOM::AttrIter attrIter(xmlDom, xmlNode);
     while ((name = attrIter.next(&value))) {
-        const int attrIndex = SkStrSearch(&gAttributeParseInfo[0].fKey,
-                                          SkTo<int>(SK_ARRAY_COUNT(gAttributeParseInfo)),
-                                          name, sizeof(gAttributeParseInfo[0]));
-        if (attrIndex < 0) {
-            SkDebugf("unhandled attribute: %s\n", name);
-            continue;
-        }
-
-        SkASSERT(SkTo<size_t>(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);
     }
 }
 
index eaaf822..b8229c0 100644 (file)
@@ -17,7 +17,7 @@ public:
     static sk_sp<SkSVGG> Make() { return sk_sp<SkSVGG>(new SkSVGG()); }
 
 private:
-    SkSVGG() : INHERITED(SkSVGTag::g) { }
+    SkSVGG() : INHERITED(SkSVGTag::kG) { }
 
     typedef SkSVGContainer INHERITED;
 };
index 2b89179..58e0ad4 100644 (file)
@@ -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<SkSVGColorValue>()) {
             fPresentationAttributes.setFill(*color);
         }
         break;
-    case SkSVGAttribute::stroke:
+    case SkSVGAttribute::kStroke:
         if (const SkSVGColorValue* color = v.as<SkSVGColorValue>()) {
             fPresentationAttributes.setStroke(*color);
         }
index de18014..407e69a 100644 (file)
@@ -17,9 +17,9 @@ class SkSVGRenderContext;
 class SkSVGValue;
 
 enum class SkSVGTag {
-    g,
-    path,
-    svg
+    kG,
+    kPath,
+    kSvg
 };
 
 class SkSVGNode : public SkRefCnt {
index ba5e3d6..7d90594 100644 (file)
@@ -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<SkSVGPathValue>()) {
             this->setPath(*path);
         }
index feae0d7..aeccc70 100644 (file)
@@ -7,4 +7,4 @@
 
 #include "SkSVGSVG.h"
 
-SkSVGSVG::SkSVGSVG() : INHERITED(SkSVGTag::svg) { }
+SkSVGSVG::SkSVGSVG() : INHERITED(SkSVGTag::kSvg) { }
index 1af89d8..3636754 100644 (file)
@@ -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<SkSVGTransformValue>()) {
             this->setTransform(*transform);
         }