[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
This commit is contained in:
fmalita 2016-07-29 08:52:03 -07:00 committed by Commit bot
parent 5abbb44f68
commit 58649ccc75
8 changed files with 93 additions and 31 deletions

View File

@ -12,10 +12,12 @@
#include "SkTLazy.h"
enum class SkSVGAttribute {
d,
fill,
stroke,
transform,
kD,
kFill,
kStroke,
kTransform,
kUnknown,
};
class SkSVGRenderContext;

View 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);
}
}

View 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;
};

View 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);
}

View File

@ -17,9 +17,9 @@ class SkSVGRenderContext;
class SkSVGValue;
enum class SkSVGTag {
g,
path,
svg
kG,
kPath,
kSvg
};
class SkSVGNode : public SkRefCnt {

View 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);
}

View File

@ -7,4 +7,4 @@
#include "SkSVGSVG.h"
SkSVGSVG::SkSVGSVG() : INHERITED(SkSVGTag::svg) { }
SkSVGSVG::SkSVGSVG() : INHERITED(SkSVGTag::kSvg) { }

View 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);
}