[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:
parent
5abbb44f68
commit
58649ccc75
@ -12,10 +12,12 @@
|
||||
#include "SkTLazy.h"
|
||||
|
||||
enum class SkSVGAttribute {
|
||||
d,
|
||||
fill,
|
||||
stroke,
|
||||
transform,
|
||||
kD,
|
||||
kFill,
|
||||
kStroke,
|
||||
kTransform,
|
||||
|
||||
kUnknown,
|
||||
};
|
||||
|
||||
class SkSVGRenderContext;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -17,9 +17,9 @@ class SkSVGRenderContext;
|
||||
class SkSVGValue;
|
||||
|
||||
enum class SkSVGTag {
|
||||
g,
|
||||
path,
|
||||
svg
|
||||
kG,
|
||||
kPath,
|
||||
kSvg
|
||||
};
|
||||
|
||||
class SkSVGNode : public SkRefCnt {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -7,4 +7,4 @@
|
||||
|
||||
#include "SkSVGSVG.h"
|
||||
|
||||
SkSVGSVG::SkSVGSVG() : INHERITED(SkSVGTag::svg) { }
|
||||
SkSVGSVG::SkSVGSVG() : INHERITED(SkSVGTag::kSvg) { }
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user