blob: e0fd73cdba8bd11bb3a152edf55471d1ee0cc40d [file] [log] [blame]
fmalita6ceef3d2016-07-26 18:46:34 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkCanvas.h"
Florin Malita7006e152020-11-10 15:24:59 -05009#include "include/core/SkFontMgr.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkString.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/private/SkTo.h"
12#include "include/utils/SkParsePath.h"
Florin Malitab3418102020-10-15 18:10:29 -040013#include "modules/svg/include/SkSVGAttributeParser.h"
14#include "modules/svg/include/SkSVGCircle.h"
15#include "modules/svg/include/SkSVGClipPath.h"
16#include "modules/svg/include/SkSVGDOM.h"
17#include "modules/svg/include/SkSVGDefs.h"
18#include "modules/svg/include/SkSVGEllipse.h"
Tyler Denniston70bb18d2020-11-06 12:07:53 -050019#include "modules/svg/include/SkSVGFeColorMatrix.h"
Tyler Dennistonb25caae2020-11-09 12:46:02 -050020#include "modules/svg/include/SkSVGFeComposite.h"
Tyler Denniston8ed04432020-12-10 15:51:04 -050021#include "modules/svg/include/SkSVGFeFlood.h"
Tyler Denniston187d8112021-01-12 09:34:23 -050022#include "modules/svg/include/SkSVGFeGaussianBlur.h"
Tyler Dennistondada9602020-11-03 10:04:25 -050023#include "modules/svg/include/SkSVGFeTurbulence.h"
Tyler Dennistondf208a32020-10-30 16:01:54 -040024#include "modules/svg/include/SkSVGFilter.h"
Florin Malitab3418102020-10-15 18:10:29 -040025#include "modules/svg/include/SkSVGG.h"
26#include "modules/svg/include/SkSVGLine.h"
27#include "modules/svg/include/SkSVGLinearGradient.h"
Florin Malita836c2ca2021-01-13 11:48:02 -050028#include "modules/svg/include/SkSVGMask.h"
Florin Malitab3418102020-10-15 18:10:29 -040029#include "modules/svg/include/SkSVGNode.h"
30#include "modules/svg/include/SkSVGPath.h"
31#include "modules/svg/include/SkSVGPattern.h"
32#include "modules/svg/include/SkSVGPoly.h"
33#include "modules/svg/include/SkSVGRadialGradient.h"
34#include "modules/svg/include/SkSVGRect.h"
35#include "modules/svg/include/SkSVGRenderContext.h"
36#include "modules/svg/include/SkSVGSVG.h"
37#include "modules/svg/include/SkSVGStop.h"
38#include "modules/svg/include/SkSVGText.h"
39#include "modules/svg/include/SkSVGTypes.h"
40#include "modules/svg/include/SkSVGUse.h"
41#include "modules/svg/include/SkSVGValue.h"
Ben Wagner8bd6e8f2019-05-15 09:28:52 -040042#include "src/core/SkTSearch.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050043#include "src/xml/SkDOM.h"
fmalita6ceef3d2016-07-26 18:46:34 -070044
45namespace {
46
fmalita28d5b722016-09-12 17:06:47 -070047bool SetIRIAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
48 const char* stringValue) {
Tyler Dennistona0a51462020-11-10 13:13:28 -050049 auto parseResult = SkSVGAttributeParser::parse<SkSVGIRI>(stringValue);
50 if (!parseResult.isValid()) {
fmalita28d5b722016-09-12 17:06:47 -070051 return false;
52 }
53
Tyler Dennistona0a51462020-11-10 13:13:28 -050054 node->setAttribute(attr, SkSVGStringValue(parseResult->fIRI));
fmalita28d5b722016-09-12 17:06:47 -070055 return true;
56}
57
fmalita6ceef3d2016-07-26 18:46:34 -070058bool SetPathDataAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
59 const char* stringValue) {
60 SkPath path;
61 if (!SkParsePath::FromSVGString(stringValue, &path)) {
62 return false;
63 }
64
Florin Malitaf4403e72020-04-10 14:14:04 +000065 node->setAttribute(attr, SkSVGPathValue(path));
fmalita6ceef3d2016-07-26 18:46:34 -070066 return true;
67}
68
Xavier Phane29cdaf2020-03-26 16:15:14 +000069bool SetStringAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
70 const char* stringValue) {
71 SkString str(stringValue, strlen(stringValue));
72 SkSVGStringType strType = SkSVGStringType(str);
Florin Malitaf4403e72020-04-10 14:14:04 +000073 node->setAttribute(attr, SkSVGStringValue(strType));
Xavier Phane29cdaf2020-03-26 16:15:14 +000074 return true;
75}
76
fmalita6ceef3d2016-07-26 18:46:34 -070077bool SetTransformAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
78 const char* stringValue) {
Tyler Dennistona0a51462020-11-10 13:13:28 -050079 auto parseResult = SkSVGAttributeParser::parse<SkSVGTransformType>(stringValue);
80 if (!parseResult.isValid()) {
fmalitac97796b2016-08-08 12:58:57 -070081 return false;
82 }
83
Tyler Dennistona0a51462020-11-10 13:13:28 -050084 node->setAttribute(attr, SkSVGTransformValue(*parseResult));
fmalita6ceef3d2016-07-26 18:46:34 -070085 return true;
86}
87
fmalitabffc2562016-08-03 10:21:11 -070088bool SetLengthAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
89 const char* stringValue) {
Tyler Dennistona0a51462020-11-10 13:13:28 -050090 auto parseResult = SkSVGAttributeParser::parse<SkSVGLength>(stringValue);
91 if (!parseResult.isValid()) {
fmalitabffc2562016-08-03 10:21:11 -070092 return false;
93 }
94
Tyler Dennistona0a51462020-11-10 13:13:28 -050095 node->setAttribute(attr, SkSVGLengthValue(*parseResult));
fmalitabffc2562016-08-03 10:21:11 -070096 return true;
97}
98
fmalita397a5172016-08-08 11:38:55 -070099bool SetViewBoxAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
100 const char* stringValue) {
101 SkSVGViewBoxType viewBox;
102 SkSVGAttributeParser parser(stringValue);
103 if (!parser.parseViewBox(&viewBox)) {
104 return false;
105 }
106
Florin Malitaf4403e72020-04-10 14:14:04 +0000107 node->setAttribute(attr, SkSVGViewBoxValue(viewBox));
fmalita397a5172016-08-08 11:38:55 -0700108 return true;
109}
110
Tyler Denniston30e327e2020-10-29 16:29:22 -0400111bool SetObjectBoundingBoxUnitsAttribute(const sk_sp<SkSVGNode>& node,
112 SkSVGAttribute attr,
113 const char* stringValue) {
Tyler Dennistona0a51462020-11-10 13:13:28 -0500114 auto parseResult = SkSVGAttributeParser::parse<SkSVGObjectBoundingBoxUnits>(stringValue);
115 if (!parseResult.isValid()) {
Tyler Dennistonab76ab42020-10-21 15:08:45 -0400116 return false;
117 }
118
Tyler Dennistona0a51462020-11-10 13:13:28 -0500119 node->setAttribute(attr, SkSVGObjectBoundingBoxUnitsValue(*parseResult));
Tyler Dennistonab76ab42020-10-21 15:08:45 -0400120 return true;
121}
122
fmalita5b31f322016-08-12 12:15:33 -0700123bool SetPointsAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
124 const char* stringValue) {
125 SkSVGPointsType points;
126 SkSVGAttributeParser parser(stringValue);
127 if (!parser.parsePoints(&points)) {
128 return false;
129 }
130
Florin Malitaf4403e72020-04-10 14:14:04 +0000131 node->setAttribute(attr, SkSVGPointsValue(points));
fmalita5b31f322016-08-12 12:15:33 -0700132 return true;
133}
134
Florin Malita385e7442020-10-21 16:55:46 -0400135bool SetPreserveAspectRatioAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
136 const char* stringValue) {
137 SkSVGPreserveAspectRatio par;
138 SkSVGAttributeParser parser(stringValue);
139 if (!parser.parsePreserveAspectRatio(&par)) {
140 return false;
141 }
142
143 node->setAttribute(attr, SkSVGPreserveAspectRatioValue(par));
144 return true;
145}
146
fmalita61f36b32016-08-08 13:58:50 -0700147SkString TrimmedString(const char* first, const char* last) {
148 SkASSERT(first);
149 SkASSERT(last);
150 SkASSERT(first <= last);
151
152 while (first <= last && *first <= ' ') { first++; }
153 while (first <= last && *last <= ' ') { last--; }
154
155 SkASSERT(last - first + 1 >= 0);
156 return SkString(first, SkTo<size_t>(last - first + 1));
157}
158
fmalita58649cc2016-07-29 08:52:03 -0700159// Breaks a "foo: bar; baz: ..." string into key:value pairs.
160class StyleIterator {
161public:
162 StyleIterator(const char* str) : fPos(str) { }
163
164 std::tuple<SkString, SkString> next() {
165 SkString name, value;
166
167 if (fPos) {
168 const char* sep = this->nextSeparator();
169 SkASSERT(*sep == ';' || *sep == '\0');
170
171 const char* valueSep = strchr(fPos, ':');
172 if (valueSep && valueSep < sep) {
fmalita61f36b32016-08-08 13:58:50 -0700173 name = TrimmedString(fPos, valueSep - 1);
174 value = TrimmedString(valueSep + 1, sep - 1);
fmalita58649cc2016-07-29 08:52:03 -0700175 }
176
177 fPos = *sep ? sep + 1 : nullptr;
178 }
179
180 return std::make_tuple(name, value);
181 }
182
183private:
184 const char* nextSeparator() const {
185 const char* sep = fPos;
186 while (*sep != ';' && *sep != '\0') {
187 sep++;
188 }
189 return sep;
190 }
191
192 const char* fPos;
193};
194
Tyler Freemanc9911522020-05-08 13:23:10 -0700195bool set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value);
fmalita58649cc2016-07-29 08:52:03 -0700196
197bool SetStyleAttributes(const sk_sp<SkSVGNode>& node, SkSVGAttribute,
198 const char* stringValue) {
199
200 SkString name, value;
201 StyleIterator iter(stringValue);
202 for (;;) {
203 std::tie(name, value) = iter.next();
204 if (name.isEmpty()) {
205 break;
206 }
207 set_string_attribute(node, name.c_str(), value.c_str());
208 }
209
210 return true;
211}
212
fmalita6ceef3d2016-07-26 18:46:34 -0700213template<typename T>
214struct SortedDictionaryEntry {
215 const char* fKey;
216 const T fValue;
217};
218
219struct AttrParseInfo {
220 SkSVGAttribute fAttr;
221 bool (*fSetter)(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, const char* stringValue);
222};
223
224SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
Florin Malita385e7442020-10-21 16:55:46 -0400225 { "cx" , { SkSVGAttribute::kCx , SetLengthAttribute }},
226 { "cy" , { SkSVGAttribute::kCy , SetLengthAttribute }},
227 { "d" , { SkSVGAttribute::kD , SetPathDataAttribute }},
Tyler Dennistondf208a32020-10-30 16:01:54 -0400228 { "filterUnits" , { SkSVGAttribute::kFilterUnits ,
229 SetObjectBoundingBoxUnitsAttribute }},
Florin Malitacc6cc292017-10-09 16:05:30 -0400230 // focal point x & y
Florin Malita385e7442020-10-21 16:55:46 -0400231 { "fx" , { SkSVGAttribute::kFx , SetLengthAttribute }},
232 { "fy" , { SkSVGAttribute::kFy , SetLengthAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400233 { "height" , { SkSVGAttribute::kHeight , SetLengthAttribute }},
234 { "offset" , { SkSVGAttribute::kOffset , SetLengthAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400235 { "patternTransform" , { SkSVGAttribute::kPatternTransform , SetTransformAttribute }},
236 { "points" , { SkSVGAttribute::kPoints , SetPointsAttribute }},
237 { "preserveAspectRatio", { SkSVGAttribute::kPreserveAspectRatio,
238 SetPreserveAspectRatioAttribute }},
239 { "r" , { SkSVGAttribute::kR , SetLengthAttribute }},
240 { "rx" , { SkSVGAttribute::kRx , SetLengthAttribute }},
241 { "ry" , { SkSVGAttribute::kRy , SetLengthAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400242 { "style" , { SkSVGAttribute::kUnknown , SetStyleAttributes }},
243 { "text" , { SkSVGAttribute::kText , SetStringAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400244 { "transform" , { SkSVGAttribute::kTransform , SetTransformAttribute }},
245 { "viewBox" , { SkSVGAttribute::kViewBox , SetViewBoxAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400246 { "width" , { SkSVGAttribute::kWidth , SetLengthAttribute }},
247 { "x" , { SkSVGAttribute::kX , SetLengthAttribute }},
248 { "x1" , { SkSVGAttribute::kX1 , SetLengthAttribute }},
249 { "x2" , { SkSVGAttribute::kX2 , SetLengthAttribute }},
250 { "xlink:href" , { SkSVGAttribute::kHref , SetIRIAttribute }},
251 { "y" , { SkSVGAttribute::kY , SetLengthAttribute }},
252 { "y1" , { SkSVGAttribute::kY1 , SetLengthAttribute }},
253 { "y2" , { SkSVGAttribute::kY2 , SetLengthAttribute }},
fmalita6ceef3d2016-07-26 18:46:34 -0700254};
255
256SortedDictionaryEntry<sk_sp<SkSVGNode>(*)()> gTagFactories[] = {
Florin Malitaf6143ff2017-10-10 09:16:52 -0400257 { "a" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700258 { "circle" , []() -> sk_sp<SkSVGNode> { return SkSVGCircle::Make(); }},
Florin Malitace8840e2016-12-08 09:26:47 -0500259 { "clipPath" , []() -> sk_sp<SkSVGNode> { return SkSVGClipPath::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700260 { "defs" , []() -> sk_sp<SkSVGNode> { return SkSVGDefs::Make(); }},
261 { "ellipse" , []() -> sk_sp<SkSVGNode> { return SkSVGEllipse::Make(); }},
Tyler Denniston70bb18d2020-11-06 12:07:53 -0500262 { "feColorMatrix" , []() -> sk_sp<SkSVGNode> { return SkSVGFeColorMatrix::Make(); }},
Tyler Dennistonb25caae2020-11-09 12:46:02 -0500263 { "feComposite" , []() -> sk_sp<SkSVGNode> { return SkSVGFeComposite::Make(); }},
Tyler Denniston8ed04432020-12-10 15:51:04 -0500264 { "feFlood" , []() -> sk_sp<SkSVGNode> { return SkSVGFeFlood::Make(); }},
Tyler Denniston187d8112021-01-12 09:34:23 -0500265 { "feGaussianBlur", []() -> sk_sp<SkSVGNode> { return SkSVGFeGaussianBlur::Make(); }},
Tyler Dennistondada9602020-11-03 10:04:25 -0500266 { "feTurbulence" , []() -> sk_sp<SkSVGNode> { return SkSVGFeTurbulence::Make(); }},
Tyler Dennistondf208a32020-10-30 16:01:54 -0400267 { "filter" , []() -> sk_sp<SkSVGNode> { return SkSVGFilter::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700268 { "g" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
269 { "line" , []() -> sk_sp<SkSVGNode> { return SkSVGLine::Make(); }},
270 { "linearGradient", []() -> sk_sp<SkSVGNode> { return SkSVGLinearGradient::Make(); }},
Florin Malita836c2ca2021-01-13 11:48:02 -0500271 { "mask" , []() -> sk_sp<SkSVGNode> { return SkSVGMask::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700272 { "path" , []() -> sk_sp<SkSVGNode> { return SkSVGPath::Make(); }},
Florin Malita1aa1bb62017-10-11 14:34:33 -0400273 { "pattern" , []() -> sk_sp<SkSVGNode> { return SkSVGPattern::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700274 { "polygon" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolygon(); }},
275 { "polyline" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolyline(); }},
Florin Malitacc6cc292017-10-09 16:05:30 -0400276 { "radialGradient", []() -> sk_sp<SkSVGNode> { return SkSVGRadialGradient::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700277 { "rect" , []() -> sk_sp<SkSVGNode> { return SkSVGRect::Make(); }},
278 { "stop" , []() -> sk_sp<SkSVGNode> { return SkSVGStop::Make(); }},
279 { "svg" , []() -> sk_sp<SkSVGNode> { return SkSVGSVG::Make(); }},
Xavier Phane29cdaf2020-03-26 16:15:14 +0000280 { "text" , []() -> sk_sp<SkSVGNode> { return SkSVGText::Make(); }},
Florin Malitafc0ea0a2021-01-12 13:27:01 -0500281 { "textPath" , []() -> sk_sp<SkSVGNode> { return SkSVGTextPath::Make(); }},
Florin Malita512ff752020-12-06 11:50:52 -0500282 { "tspan" , []() -> sk_sp<SkSVGNode> { return SkSVGTSpan::Make(); }},
Florin Malita6a69c052017-10-11 14:02:11 -0400283 { "use" , []() -> sk_sp<SkSVGNode> { return SkSVGUse::Make(); }},
fmalita6ceef3d2016-07-26 18:46:34 -0700284};
285
286struct ConstructionContext {
fmalita28d5b722016-09-12 17:06:47 -0700287 ConstructionContext(SkSVGIDMapper* mapper) : fParent(nullptr), fIDMapper(mapper) {}
fmalita6ceef3d2016-07-26 18:46:34 -0700288 ConstructionContext(const ConstructionContext& other, const sk_sp<SkSVGNode>& newParent)
fmalita28d5b722016-09-12 17:06:47 -0700289 : fParent(newParent.get()), fIDMapper(other.fIDMapper) {}
fmalita6ceef3d2016-07-26 18:46:34 -0700290
Florin Malita39fe8c82020-10-20 10:43:03 -0400291 SkSVGNode* fParent;
292 SkSVGIDMapper* fIDMapper;
fmalita6ceef3d2016-07-26 18:46:34 -0700293};
294
Tyler Freemanc9911522020-05-08 13:23:10 -0700295bool set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value) {
Tyler Denniston57154992020-11-04 16:08:30 -0500296 if (node->parseAndSetAttribute(name, value)) {
297 // Handled by new code path
298 return true;
299 }
300
fmalita58649cc2016-07-29 08:52:03 -0700301 const int attrIndex = SkStrSearch(&gAttributeParseInfo[0].fKey,
302 SkTo<int>(SK_ARRAY_COUNT(gAttributeParseInfo)),
303 name, sizeof(gAttributeParseInfo[0]));
304 if (attrIndex < 0) {
fmalitafea704e2016-08-10 16:25:32 -0700305#if defined(SK_VERBOSE_SVG_PARSING)
fmalita58649cc2016-07-29 08:52:03 -0700306 SkDebugf("unhandled attribute: %s\n", name);
fmalitafea704e2016-08-10 16:25:32 -0700307#endif
Tyler Freemanc9911522020-05-08 13:23:10 -0700308 return false;
fmalita58649cc2016-07-29 08:52:03 -0700309 }
310
311 SkASSERT(SkTo<size_t>(attrIndex) < SK_ARRAY_COUNT(gAttributeParseInfo));
312 const auto& attrInfo = gAttributeParseInfo[attrIndex].fValue;
313 if (!attrInfo.fSetter(node, attrInfo.fAttr, value)) {
fmalitafea704e2016-08-10 16:25:32 -0700314#if defined(SK_VERBOSE_SVG_PARSING)
fmalita58649cc2016-07-29 08:52:03 -0700315 SkDebugf("could not parse attribute: '%s=\"%s\"'\n", name, value);
fmalitafea704e2016-08-10 16:25:32 -0700316#endif
Tyler Freemanc9911522020-05-08 13:23:10 -0700317 return false;
fmalita58649cc2016-07-29 08:52:03 -0700318 }
Tyler Freemanc9911522020-05-08 13:23:10 -0700319
320 return true;
fmalita58649cc2016-07-29 08:52:03 -0700321}
322
fmalita6ceef3d2016-07-26 18:46:34 -0700323void parse_node_attributes(const SkDOM& xmlDom, const SkDOM::Node* xmlNode,
fmalita28d5b722016-09-12 17:06:47 -0700324 const sk_sp<SkSVGNode>& svgNode, SkSVGIDMapper* mapper) {
fmalita6ceef3d2016-07-26 18:46:34 -0700325 const char* name, *value;
326 SkDOM::AttrIter attrIter(xmlDom, xmlNode);
327 while ((name = attrIter.next(&value))) {
fmalita28d5b722016-09-12 17:06:47 -0700328 // We're handling id attributes out of band for now.
329 if (!strcmp(name, "id")) {
330 mapper->set(SkString(value), svgNode);
331 continue;
332 }
fmalita58649cc2016-07-29 08:52:03 -0700333 set_string_attribute(svgNode, name, value);
fmalita6ceef3d2016-07-26 18:46:34 -0700334 }
335}
336
337sk_sp<SkSVGNode> construct_svg_node(const SkDOM& dom, const ConstructionContext& ctx,
338 const SkDOM::Node* xmlNode) {
339 const char* elem = dom.getName(xmlNode);
340 const SkDOM::Type elemType = dom.getType(xmlNode);
341
342 if (elemType == SkDOM::kText_Type) {
Florin Malita512ff752020-12-06 11:50:52 -0500343 // Text literals require special handling.
fmalita6ceef3d2016-07-26 18:46:34 -0700344 SkASSERT(dom.countChildren(xmlNode) == 0);
Florin Malita512ff752020-12-06 11:50:52 -0500345 auto txt = SkSVGTextLiteral::Make();
346 txt->setText(SkString(dom.getName(xmlNode)));
347 ctx.fParent->appendChild(std::move(txt));
348
fmalita6ceef3d2016-07-26 18:46:34 -0700349 return nullptr;
350 }
351
352 SkASSERT(elemType == SkDOM::kElement_Type);
353
354 const int tagIndex = SkStrSearch(&gTagFactories[0].fKey,
355 SkTo<int>(SK_ARRAY_COUNT(gTagFactories)),
356 elem, sizeof(gTagFactories[0]));
357 if (tagIndex < 0) {
fmalitafea704e2016-08-10 16:25:32 -0700358#if defined(SK_VERBOSE_SVG_PARSING)
fmalita6ceef3d2016-07-26 18:46:34 -0700359 SkDebugf("unhandled element: <%s>\n", elem);
fmalitafea704e2016-08-10 16:25:32 -0700360#endif
fmalita6ceef3d2016-07-26 18:46:34 -0700361 return nullptr;
362 }
363
364 SkASSERT(SkTo<size_t>(tagIndex) < SK_ARRAY_COUNT(gTagFactories));
365 sk_sp<SkSVGNode> node = gTagFactories[tagIndex].fValue();
fmalita28d5b722016-09-12 17:06:47 -0700366 parse_node_attributes(dom, xmlNode, node, ctx.fIDMapper);
fmalita6ceef3d2016-07-26 18:46:34 -0700367
368 ConstructionContext localCtx(ctx, node);
369 for (auto* child = dom.getFirstChild(xmlNode, nullptr); child;
370 child = dom.getNextSibling(child)) {
371 sk_sp<SkSVGNode> childNode = construct_svg_node(dom, localCtx, child);
372 if (childNode) {
373 node->appendChild(std::move(childNode));
374 }
375 }
376
377 return node;
378}
379
380} // anonymous namespace
381
Florin Malita7006e152020-11-10 15:24:59 -0500382SkSVGDOM::Builder& SkSVGDOM::Builder::setFontManager(sk_sp<SkFontMgr> fmgr) {
383 fFontMgr = std::move(fmgr);
384 return *this;
fmalita6ceef3d2016-07-26 18:46:34 -0700385}
386
Florin Malita7006e152020-11-10 15:24:59 -0500387sk_sp<SkSVGDOM> SkSVGDOM::Builder::make(SkStream& str) const {
fmalita6ceef3d2016-07-26 18:46:34 -0700388 SkDOM xmlDom;
Florin Malita7006e152020-11-10 15:24:59 -0500389 if (!xmlDom.build(str)) {
fmalita6ceef3d2016-07-26 18:46:34 -0700390 return nullptr;
391 }
392
Florin Malita7006e152020-11-10 15:24:59 -0500393 SkSVGIDMapper mapper;
394 ConstructionContext ctx(&mapper);
395
396 auto root = construct_svg_node(xmlDom, ctx, xmlDom.getRootNode());
397 if (!root || root->tag() != SkSVGTag::kSvg) {
398 return nullptr;
399 }
400
401 return sk_sp<SkSVGDOM>(new SkSVGDOM(sk_sp<SkSVGSVG>(static_cast<SkSVGSVG*>(root.release())),
402 std::move(fFontMgr), std::move(mapper)));
fmalita6ceef3d2016-07-26 18:46:34 -0700403}
404
Florin Malita7006e152020-11-10 15:24:59 -0500405SkSVGDOM::SkSVGDOM(sk_sp<SkSVGSVG> root, sk_sp<SkFontMgr> fmgr, SkSVGIDMapper&& mapper)
406 : fRoot(std::move(root))
407 , fFontMgr(std::move(fmgr))
408 , fIDMapper(std::move(mapper))
409 , fContainerSize(fRoot->intrinsicSize(SkSVGLengthContext(SkSize::Make(0, 0))))
410{}
411
fmalita6ceef3d2016-07-26 18:46:34 -0700412void SkSVGDOM::render(SkCanvas* canvas) const {
413 if (fRoot) {
Florin Malitaebca0dd2017-09-09 09:39:07 -0400414 SkSVGLengthContext lctx(fContainerSize);
415 SkSVGPresentationContext pctx;
Florin Malitaadc68892020-12-15 10:52:26 -0500416 fRoot->render(SkSVGRenderContext(canvas, fFontMgr, fIDMapper, lctx, pctx, nullptr));
fmalita6ceef3d2016-07-26 18:46:34 -0700417 }
418}
419
fmalitae1baa7c2016-09-14 12:04:30 -0700420const SkSize& SkSVGDOM::containerSize() const {
421 return fContainerSize;
422}
423
fmalita6ceef3d2016-07-26 18:46:34 -0700424void SkSVGDOM::setContainerSize(const SkSize& containerSize) {
425 // TODO: inval
426 fContainerSize = containerSize;
427}
fmalitaca39d712016-08-12 13:17:11 -0700428
Tyler Freemanc9911522020-05-08 13:23:10 -0700429sk_sp<SkSVGNode>* SkSVGDOM::findNodeById(const char* id) {
430 SkString idStr(id);
431 return this->fIDMapper.find(idStr);
432}
433
Tyler Freemanc9911522020-05-08 13:23:10 -0700434// TODO(fuego): move this to SkSVGNode or its own CU.
435bool SkSVGNode::setAttribute(const char* attributeName, const char* attributeValue) {
436 return set_string_attribute(sk_ref_sp(this), attributeName, attributeValue);
437}