Index: experimental/svg/model/SkSVGDOM.cpp |
diff --git a/experimental/svg/model/SkSVGDOM.cpp b/experimental/svg/model/SkSVGDOM.cpp |
index c123bc6bfb9092d563133d2eac9e0bafe976ec1b..d6e4f4c9bd6a4e2f8d6c0e080827cd942bdbe7a1 100644 |
--- a/experimental/svg/model/SkSVGDOM.cpp |
+++ b/experimental/svg/model/SkSVGDOM.cpp |
@@ -11,15 +11,18 @@ |
#include "SkString.h" |
#include "SkSVGAttributeParser.h" |
#include "SkSVGCircle.h" |
+#include "SkSVGDefs.h" |
#include "SkSVGDOM.h" |
#include "SkSVGEllipse.h" |
#include "SkSVGG.h" |
#include "SkSVGLine.h" |
+#include "SkSVGLinearGradient.h" |
#include "SkSVGNode.h" |
#include "SkSVGPath.h" |
#include "SkSVGPoly.h" |
#include "SkSVGRect.h" |
#include "SkSVGRenderContext.h" |
+#include "SkSVGStop.h" |
#include "SkSVGSVG.h" |
#include "SkSVGTypes.h" |
#include "SkSVGValue.h" |
@@ -32,17 +35,37 @@ bool SetPaintAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, |
SkSVGPaint paint; |
SkSVGAttributeParser parser(stringValue); |
if (!parser.parsePaint(&paint)) { |
- // Until we have paint server support, failing here will cause default/all-black rendering. |
- // It's better to just not draw for now. |
- paint = SkSVGPaint(SkSVGPaint::Type::kNone); |
- |
- // return false; |
+ return false; |
} |
node->setAttribute(attr, SkSVGPaintValue(paint)); |
return true; |
} |
+bool SetColorAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, |
+ const char* stringValue) { |
+ SkSVGColorType color; |
+ SkSVGAttributeParser parser(stringValue); |
+ if (!parser.parseColor(&color)) { |
+ return false; |
+ } |
+ |
+ node->setAttribute(attr, SkSVGColorValue(color)); |
+ return true; |
+} |
+ |
+bool SetIRIAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, |
+ const char* stringValue) { |
+ SkSVGStringType iri; |
+ SkSVGAttributeParser parser(stringValue); |
+ if (!parser.parseIRI(&iri)) { |
+ return false; |
+ } |
+ |
+ node->setAttribute(attr, SkSVGStringValue(iri)); |
+ return true; |
+} |
+ |
bool SetPathDataAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, |
const char* stringValue) { |
SkPath path; |
@@ -222,11 +245,14 @@ SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = { |
{ "fill" , { SkSVGAttribute::kFill , SetPaintAttribute }}, |
{ "fill-opacity" , { SkSVGAttribute::kFillOpacity , SetNumberAttribute }}, |
{ "height" , { SkSVGAttribute::kHeight , SetLengthAttribute }}, |
+ { "offset" , { SkSVGAttribute::kOffset , SetLengthAttribute }}, |
{ "opacity" , { SkSVGAttribute::kOpacity , SetNumberAttribute }}, |
{ "points" , { SkSVGAttribute::kPoints , SetPointsAttribute }}, |
{ "r" , { SkSVGAttribute::kR , SetLengthAttribute }}, |
{ "rx" , { SkSVGAttribute::kRx , SetLengthAttribute }}, |
{ "ry" , { SkSVGAttribute::kRy , SetLengthAttribute }}, |
+ { "stop-color" , { SkSVGAttribute::kStopColor , SetColorAttribute }}, |
+ { "stop-opacity" , { SkSVGAttribute::kStopOpacity , SetNumberAttribute }}, |
{ "stroke" , { SkSVGAttribute::kStroke , SetPaintAttribute }}, |
{ "stroke-linecap" , { SkSVGAttribute::kStrokeLineCap , SetLineCapAttribute }}, |
{ "stroke-linejoin", { SkSVGAttribute::kStrokeLineJoin, SetLineJoinAttribute }}, |
@@ -239,29 +265,34 @@ SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = { |
{ "x" , { SkSVGAttribute::kX , SetLengthAttribute }}, |
{ "x1" , { SkSVGAttribute::kX1 , SetLengthAttribute }}, |
{ "x2" , { SkSVGAttribute::kX2 , SetLengthAttribute }}, |
+ { "xlink:href" , { SkSVGAttribute::kHref , SetIRIAttribute }}, |
{ "y" , { SkSVGAttribute::kY , SetLengthAttribute }}, |
{ "y1" , { SkSVGAttribute::kY1 , SetLengthAttribute }}, |
{ "y2" , { SkSVGAttribute::kY2 , SetLengthAttribute }}, |
}; |
SortedDictionaryEntry<sk_sp<SkSVGNode>(*)()> gTagFactories[] = { |
- { "circle" , []() -> sk_sp<SkSVGNode> { return SkSVGCircle::Make(); }}, |
- { "ellipse" , []() -> sk_sp<SkSVGNode> { return SkSVGEllipse::Make(); }}, |
- { "g" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }}, |
- { "line" , []() -> sk_sp<SkSVGNode> { return SkSVGLine::Make(); }}, |
- { "path" , []() -> sk_sp<SkSVGNode> { return SkSVGPath::Make(); }}, |
- { "polygon" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolygon(); }}, |
- { "polyline", []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolyline(); }}, |
- { "rect" , []() -> sk_sp<SkSVGNode> { return SkSVGRect::Make(); }}, |
- { "svg" , []() -> sk_sp<SkSVGNode> { return SkSVGSVG::Make(); }}, |
+ { "circle" , []() -> sk_sp<SkSVGNode> { return SkSVGCircle::Make(); }}, |
+ { "defs" , []() -> sk_sp<SkSVGNode> { return SkSVGDefs::Make(); }}, |
+ { "ellipse" , []() -> sk_sp<SkSVGNode> { return SkSVGEllipse::Make(); }}, |
+ { "g" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }}, |
+ { "line" , []() -> sk_sp<SkSVGNode> { return SkSVGLine::Make(); }}, |
+ { "linearGradient", []() -> sk_sp<SkSVGNode> { return SkSVGLinearGradient::Make(); }}, |
+ { "path" , []() -> sk_sp<SkSVGNode> { return SkSVGPath::Make(); }}, |
+ { "polygon" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolygon(); }}, |
+ { "polyline" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolyline(); }}, |
+ { "rect" , []() -> sk_sp<SkSVGNode> { return SkSVGRect::Make(); }}, |
+ { "stop" , []() -> sk_sp<SkSVGNode> { return SkSVGStop::Make(); }}, |
+ { "svg" , []() -> sk_sp<SkSVGNode> { return SkSVGSVG::Make(); }}, |
}; |
struct ConstructionContext { |
- ConstructionContext() : fParent(nullptr) { } |
+ ConstructionContext(SkSVGIDMapper* mapper) : fParent(nullptr), fIDMapper(mapper) {} |
ConstructionContext(const ConstructionContext& other, const sk_sp<SkSVGNode>& newParent) |
- : fParent(newParent.get()) { } |
+ : fParent(newParent.get()), fIDMapper(other.fIDMapper) {} |
const SkSVGNode* fParent; |
+ SkSVGIDMapper* fIDMapper; |
}; |
void set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value) { |
@@ -285,10 +316,15 @@ void set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const |
} |
void parse_node_attributes(const SkDOM& xmlDom, const SkDOM::Node* xmlNode, |
- const sk_sp<SkSVGNode>& svgNode) { |
+ const sk_sp<SkSVGNode>& svgNode, SkSVGIDMapper* mapper) { |
const char* name, *value; |
SkDOM::AttrIter attrIter(xmlDom, xmlNode); |
while ((name = attrIter.next(&value))) { |
+ // We're handling id attributes out of band for now. |
+ if (!strcmp(name, "id")) { |
+ mapper->set(SkString(value), svgNode); |
+ continue; |
+ } |
set_string_attribute(svgNode, name, value); |
} |
} |
@@ -318,7 +354,7 @@ sk_sp<SkSVGNode> construct_svg_node(const SkDOM& dom, const ConstructionContext& |
SkASSERT(SkTo<size_t>(tagIndex) < SK_ARRAY_COUNT(gTagFactories)); |
sk_sp<SkSVGNode> node = gTagFactories[tagIndex].fValue(); |
- parse_node_attributes(dom, xmlNode, node); |
+ parse_node_attributes(dom, xmlNode, node, ctx.fIDMapper); |
ConstructionContext localCtx(ctx, node); |
for (auto* child = dom.getFirstChild(xmlNode, nullptr); child; |
@@ -341,7 +377,7 @@ SkSVGDOM::SkSVGDOM(const SkSize& containerSize) |
sk_sp<SkSVGDOM> SkSVGDOM::MakeFromDOM(const SkDOM& xmlDom, const SkSize& containerSize) { |
sk_sp<SkSVGDOM> dom = sk_make_sp<SkSVGDOM>(containerSize); |
- ConstructionContext ctx; |
+ ConstructionContext ctx(&dom->fIDMapper); |
dom->fRoot = construct_svg_node(xmlDom, ctx, xmlDom.getRootNode()); |
return dom; |
@@ -359,6 +395,7 @@ sk_sp<SkSVGDOM> SkSVGDOM::MakeFromStream(SkStream& svgStream, const SkSize& cont |
void SkSVGDOM::render(SkCanvas* canvas) const { |
if (fRoot) { |
SkSVGRenderContext ctx(canvas, |
+ fIDMapper, |
SkSVGLengthContext(fContainerSize), |
SkSVGPresentationContext()); |
fRoot->render(ctx); |