blob: a3e38e1463c16c0c85c3c94210bf09f207f483cf [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 Dennistona25e1a32021-01-15 12:38:29 -050019#include "modules/svg/include/SkSVGFeBlend.h"
Tyler Denniston70bb18d2020-11-06 12:07:53 -050020#include "modules/svg/include/SkSVGFeColorMatrix.h"
Tyler Dennistonb25caae2020-11-09 12:46:02 -050021#include "modules/svg/include/SkSVGFeComposite.h"
Tyler Dennistonf005c8a2021-01-25 12:56:13 -050022#include "modules/svg/include/SkSVGFeDisplacementMap.h"
Tyler Denniston8ed04432020-12-10 15:51:04 -050023#include "modules/svg/include/SkSVGFeFlood.h"
Tyler Denniston187d8112021-01-12 09:34:23 -050024#include "modules/svg/include/SkSVGFeGaussianBlur.h"
Tyler Denniston32b30892021-01-26 14:36:32 -050025#include "modules/svg/include/SkSVGFeLightSource.h"
Tyler Denniston8eedcd22021-01-27 09:18:06 -050026#include "modules/svg/include/SkSVGFeLighting.h"
Tyler Denniston4c89481be2021-01-20 09:41:22 -050027#include "modules/svg/include/SkSVGFeMorphology.h"
Tyler Denniston5878ece2021-01-15 09:17:55 -050028#include "modules/svg/include/SkSVGFeOffset.h"
Tyler Dennistondada9602020-11-03 10:04:25 -050029#include "modules/svg/include/SkSVGFeTurbulence.h"
Tyler Dennistondf208a32020-10-30 16:01:54 -040030#include "modules/svg/include/SkSVGFilter.h"
Florin Malitab3418102020-10-15 18:10:29 -040031#include "modules/svg/include/SkSVGG.h"
Tyler Denniston8ca46262021-02-02 16:16:21 -050032#include "modules/svg/include/SkSVGImage.h"
Florin Malitab3418102020-10-15 18:10:29 -040033#include "modules/svg/include/SkSVGLine.h"
34#include "modules/svg/include/SkSVGLinearGradient.h"
Florin Malita836c2ca2021-01-13 11:48:02 -050035#include "modules/svg/include/SkSVGMask.h"
Florin Malitab3418102020-10-15 18:10:29 -040036#include "modules/svg/include/SkSVGNode.h"
37#include "modules/svg/include/SkSVGPath.h"
38#include "modules/svg/include/SkSVGPattern.h"
39#include "modules/svg/include/SkSVGPoly.h"
40#include "modules/svg/include/SkSVGRadialGradient.h"
41#include "modules/svg/include/SkSVGRect.h"
42#include "modules/svg/include/SkSVGRenderContext.h"
43#include "modules/svg/include/SkSVGSVG.h"
44#include "modules/svg/include/SkSVGStop.h"
45#include "modules/svg/include/SkSVGText.h"
46#include "modules/svg/include/SkSVGTypes.h"
47#include "modules/svg/include/SkSVGUse.h"
48#include "modules/svg/include/SkSVGValue.h"
Ben Wagner8bd6e8f2019-05-15 09:28:52 -040049#include "src/core/SkTSearch.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050050#include "src/xml/SkDOM.h"
fmalita6ceef3d2016-07-26 18:46:34 -070051
52namespace {
53
fmalita28d5b722016-09-12 17:06:47 -070054bool SetIRIAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
55 const char* stringValue) {
Tyler Dennistona0a51462020-11-10 13:13:28 -050056 auto parseResult = SkSVGAttributeParser::parse<SkSVGIRI>(stringValue);
57 if (!parseResult.isValid()) {
fmalita28d5b722016-09-12 17:06:47 -070058 return false;
59 }
60
Tyler Dennistone71f5472021-01-27 13:30:59 -050061 node->setAttribute(attr, SkSVGStringValue(parseResult->iri()));
fmalita28d5b722016-09-12 17:06:47 -070062 return true;
63}
64
fmalita6ceef3d2016-07-26 18:46:34 -070065bool SetPathDataAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
66 const char* stringValue) {
67 SkPath path;
68 if (!SkParsePath::FromSVGString(stringValue, &path)) {
69 return false;
70 }
71
Florin Malitaf4403e72020-04-10 14:14:04 +000072 node->setAttribute(attr, SkSVGPathValue(path));
fmalita6ceef3d2016-07-26 18:46:34 -070073 return true;
74}
75
Xavier Phane29cdaf2020-03-26 16:15:14 +000076bool SetStringAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
77 const char* stringValue) {
78 SkString str(stringValue, strlen(stringValue));
79 SkSVGStringType strType = SkSVGStringType(str);
Florin Malitaf4403e72020-04-10 14:14:04 +000080 node->setAttribute(attr, SkSVGStringValue(strType));
Xavier Phane29cdaf2020-03-26 16:15:14 +000081 return true;
82}
83
fmalita6ceef3d2016-07-26 18:46:34 -070084bool SetTransformAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
85 const char* stringValue) {
Tyler Dennistona0a51462020-11-10 13:13:28 -050086 auto parseResult = SkSVGAttributeParser::parse<SkSVGTransformType>(stringValue);
87 if (!parseResult.isValid()) {
fmalitac97796b2016-08-08 12:58:57 -070088 return false;
89 }
90
Tyler Dennistona0a51462020-11-10 13:13:28 -050091 node->setAttribute(attr, SkSVGTransformValue(*parseResult));
fmalita6ceef3d2016-07-26 18:46:34 -070092 return true;
93}
94
fmalitabffc2562016-08-03 10:21:11 -070095bool SetLengthAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
96 const char* stringValue) {
Tyler Dennistona0a51462020-11-10 13:13:28 -050097 auto parseResult = SkSVGAttributeParser::parse<SkSVGLength>(stringValue);
98 if (!parseResult.isValid()) {
fmalitabffc2562016-08-03 10:21:11 -070099 return false;
100 }
101
Tyler Dennistona0a51462020-11-10 13:13:28 -0500102 node->setAttribute(attr, SkSVGLengthValue(*parseResult));
fmalitabffc2562016-08-03 10:21:11 -0700103 return true;
104}
105
fmalita397a5172016-08-08 11:38:55 -0700106bool SetViewBoxAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
107 const char* stringValue) {
108 SkSVGViewBoxType viewBox;
109 SkSVGAttributeParser parser(stringValue);
110 if (!parser.parseViewBox(&viewBox)) {
111 return false;
112 }
113
Florin Malitaf4403e72020-04-10 14:14:04 +0000114 node->setAttribute(attr, SkSVGViewBoxValue(viewBox));
fmalita397a5172016-08-08 11:38:55 -0700115 return true;
116}
117
Tyler Denniston30e327e2020-10-29 16:29:22 -0400118bool SetObjectBoundingBoxUnitsAttribute(const sk_sp<SkSVGNode>& node,
119 SkSVGAttribute attr,
120 const char* stringValue) {
Tyler Dennistona0a51462020-11-10 13:13:28 -0500121 auto parseResult = SkSVGAttributeParser::parse<SkSVGObjectBoundingBoxUnits>(stringValue);
122 if (!parseResult.isValid()) {
Tyler Dennistonab76ab42020-10-21 15:08:45 -0400123 return false;
124 }
125
Tyler Dennistona0a51462020-11-10 13:13:28 -0500126 node->setAttribute(attr, SkSVGObjectBoundingBoxUnitsValue(*parseResult));
Tyler Dennistonab76ab42020-10-21 15:08:45 -0400127 return true;
128}
129
fmalita5b31f322016-08-12 12:15:33 -0700130bool SetPointsAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
131 const char* stringValue) {
132 SkSVGPointsType points;
133 SkSVGAttributeParser parser(stringValue);
134 if (!parser.parsePoints(&points)) {
135 return false;
136 }
137
Florin Malitaf4403e72020-04-10 14:14:04 +0000138 node->setAttribute(attr, SkSVGPointsValue(points));
fmalita5b31f322016-08-12 12:15:33 -0700139 return true;
140}
141
Florin Malita385e7442020-10-21 16:55:46 -0400142bool SetPreserveAspectRatioAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
143 const char* stringValue) {
144 SkSVGPreserveAspectRatio par;
145 SkSVGAttributeParser parser(stringValue);
146 if (!parser.parsePreserveAspectRatio(&par)) {
147 return false;
148 }
149
150 node->setAttribute(attr, SkSVGPreserveAspectRatioValue(par));
151 return true;
152}
153
fmalita61f36b32016-08-08 13:58:50 -0700154SkString TrimmedString(const char* first, const char* last) {
155 SkASSERT(first);
156 SkASSERT(last);
157 SkASSERT(first <= last);
158
159 while (first <= last && *first <= ' ') { first++; }
160 while (first <= last && *last <= ' ') { last--; }
161
162 SkASSERT(last - first + 1 >= 0);
163 return SkString(first, SkTo<size_t>(last - first + 1));
164}
165
fmalita58649cc2016-07-29 08:52:03 -0700166// Breaks a "foo: bar; baz: ..." string into key:value pairs.
167class StyleIterator {
168public:
169 StyleIterator(const char* str) : fPos(str) { }
170
171 std::tuple<SkString, SkString> next() {
172 SkString name, value;
173
174 if (fPos) {
175 const char* sep = this->nextSeparator();
176 SkASSERT(*sep == ';' || *sep == '\0');
177
178 const char* valueSep = strchr(fPos, ':');
179 if (valueSep && valueSep < sep) {
fmalita61f36b32016-08-08 13:58:50 -0700180 name = TrimmedString(fPos, valueSep - 1);
181 value = TrimmedString(valueSep + 1, sep - 1);
fmalita58649cc2016-07-29 08:52:03 -0700182 }
183
184 fPos = *sep ? sep + 1 : nullptr;
185 }
186
187 return std::make_tuple(name, value);
188 }
189
190private:
191 const char* nextSeparator() const {
192 const char* sep = fPos;
193 while (*sep != ';' && *sep != '\0') {
194 sep++;
195 }
196 return sep;
197 }
198
199 const char* fPos;
200};
201
Tyler Freemanc9911522020-05-08 13:23:10 -0700202bool set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value);
fmalita58649cc2016-07-29 08:52:03 -0700203
204bool SetStyleAttributes(const sk_sp<SkSVGNode>& node, SkSVGAttribute,
205 const char* stringValue) {
206
207 SkString name, value;
208 StyleIterator iter(stringValue);
209 for (;;) {
210 std::tie(name, value) = iter.next();
211 if (name.isEmpty()) {
212 break;
213 }
214 set_string_attribute(node, name.c_str(), value.c_str());
215 }
216
217 return true;
218}
219
fmalita6ceef3d2016-07-26 18:46:34 -0700220template<typename T>
221struct SortedDictionaryEntry {
222 const char* fKey;
223 const T fValue;
224};
225
226struct AttrParseInfo {
227 SkSVGAttribute fAttr;
228 bool (*fSetter)(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, const char* stringValue);
229};
230
231SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
Florin Malita385e7442020-10-21 16:55:46 -0400232 { "cx" , { SkSVGAttribute::kCx , SetLengthAttribute }},
233 { "cy" , { SkSVGAttribute::kCy , SetLengthAttribute }},
234 { "d" , { SkSVGAttribute::kD , SetPathDataAttribute }},
Tyler Dennistondf208a32020-10-30 16:01:54 -0400235 { "filterUnits" , { SkSVGAttribute::kFilterUnits ,
236 SetObjectBoundingBoxUnitsAttribute }},
Florin Malitacc6cc292017-10-09 16:05:30 -0400237 // focal point x & y
Florin Malita385e7442020-10-21 16:55:46 -0400238 { "fx" , { SkSVGAttribute::kFx , SetLengthAttribute }},
239 { "fy" , { SkSVGAttribute::kFy , SetLengthAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400240 { "height" , { SkSVGAttribute::kHeight , SetLengthAttribute }},
241 { "offset" , { SkSVGAttribute::kOffset , SetLengthAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400242 { "patternTransform" , { SkSVGAttribute::kPatternTransform , SetTransformAttribute }},
243 { "points" , { SkSVGAttribute::kPoints , SetPointsAttribute }},
244 { "preserveAspectRatio", { SkSVGAttribute::kPreserveAspectRatio,
245 SetPreserveAspectRatioAttribute }},
246 { "r" , { SkSVGAttribute::kR , SetLengthAttribute }},
247 { "rx" , { SkSVGAttribute::kRx , SetLengthAttribute }},
248 { "ry" , { SkSVGAttribute::kRy , SetLengthAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400249 { "style" , { SkSVGAttribute::kUnknown , SetStyleAttributes }},
250 { "text" , { SkSVGAttribute::kText , SetStringAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400251 { "transform" , { SkSVGAttribute::kTransform , SetTransformAttribute }},
252 { "viewBox" , { SkSVGAttribute::kViewBox , SetViewBoxAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400253 { "width" , { SkSVGAttribute::kWidth , SetLengthAttribute }},
254 { "x" , { SkSVGAttribute::kX , SetLengthAttribute }},
255 { "x1" , { SkSVGAttribute::kX1 , SetLengthAttribute }},
256 { "x2" , { SkSVGAttribute::kX2 , SetLengthAttribute }},
257 { "xlink:href" , { SkSVGAttribute::kHref , SetIRIAttribute }},
258 { "y" , { SkSVGAttribute::kY , SetLengthAttribute }},
259 { "y1" , { SkSVGAttribute::kY1 , SetLengthAttribute }},
260 { "y2" , { SkSVGAttribute::kY2 , SetLengthAttribute }},
fmalita6ceef3d2016-07-26 18:46:34 -0700261};
262
263SortedDictionaryEntry<sk_sp<SkSVGNode>(*)()> gTagFactories[] = {
Tyler Denniston8eedcd22021-01-27 09:18:06 -0500264 { "a" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
265 { "circle" , []() -> sk_sp<SkSVGNode> { return SkSVGCircle::Make(); }},
266 { "clipPath" , []() -> sk_sp<SkSVGNode> { return SkSVGClipPath::Make(); }},
267 { "defs" , []() -> sk_sp<SkSVGNode> { return SkSVGDefs::Make(); }},
268 { "ellipse" , []() -> sk_sp<SkSVGNode> { return SkSVGEllipse::Make(); }},
269 { "feBlend" , []() -> sk_sp<SkSVGNode> { return SkSVGFeBlend::Make(); }},
270 { "feColorMatrix" , []() -> sk_sp<SkSVGNode> { return SkSVGFeColorMatrix::Make(); }},
271 { "feComposite" , []() -> sk_sp<SkSVGNode> { return SkSVGFeComposite::Make(); }},
272 { "feDisplacementMap" , []() -> sk_sp<SkSVGNode> { return SkSVGFeDisplacementMap::Make(); }},
273 { "feDistantLight" , []() -> sk_sp<SkSVGNode> { return SkSVGFeDistantLight::Make(); }},
274 { "feFlood" , []() -> sk_sp<SkSVGNode> { return SkSVGFeFlood::Make(); }},
275 { "feGaussianBlur" , []() -> sk_sp<SkSVGNode> { return SkSVGFeGaussianBlur::Make(); }},
276 { "feMorphology" , []() -> sk_sp<SkSVGNode> { return SkSVGFeMorphology::Make(); }},
277 { "feOffset" , []() -> sk_sp<SkSVGNode> { return SkSVGFeOffset::Make(); }},
278 { "fePointLight" , []() -> sk_sp<SkSVGNode> { return SkSVGFePointLight::Make(); }},
279 { "feSpecularLighting", []() -> sk_sp<SkSVGNode> { return SkSVGFeSpecularLighting::Make(); }},
280 { "feSpotLight" , []() -> sk_sp<SkSVGNode> { return SkSVGFeSpotLight::Make(); }},
281 { "feTurbulence" , []() -> sk_sp<SkSVGNode> { return SkSVGFeTurbulence::Make(); }},
282 { "filter" , []() -> sk_sp<SkSVGNode> { return SkSVGFilter::Make(); }},
283 { "g" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
Tyler Denniston8ca46262021-02-02 16:16:21 -0500284 { "image" , []() -> sk_sp<SkSVGNode> { return SkSVGImage::Make(); }},
Tyler Denniston8eedcd22021-01-27 09:18:06 -0500285 { "line" , []() -> sk_sp<SkSVGNode> { return SkSVGLine::Make(); }},
286 { "linearGradient" , []() -> sk_sp<SkSVGNode> { return SkSVGLinearGradient::Make(); }},
287 { "mask" , []() -> sk_sp<SkSVGNode> { return SkSVGMask::Make(); }},
288 { "path" , []() -> sk_sp<SkSVGNode> { return SkSVGPath::Make(); }},
289 { "pattern" , []() -> sk_sp<SkSVGNode> { return SkSVGPattern::Make(); }},
290 { "polygon" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolygon(); }},
291 { "polyline" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolyline(); }},
292 { "radialGradient" , []() -> sk_sp<SkSVGNode> { return SkSVGRadialGradient::Make(); }},
293 { "rect" , []() -> sk_sp<SkSVGNode> { return SkSVGRect::Make(); }},
294 { "stop" , []() -> sk_sp<SkSVGNode> { return SkSVGStop::Make(); }},
Florin Malitacdeabca2021-01-20 13:21:20 -0500295// "svg" handled explicitly
Tyler Denniston8eedcd22021-01-27 09:18:06 -0500296 { "text" , []() -> sk_sp<SkSVGNode> { return SkSVGText::Make(); }},
297 { "textPath" , []() -> sk_sp<SkSVGNode> { return SkSVGTextPath::Make(); }},
298 { "tspan" , []() -> sk_sp<SkSVGNode> { return SkSVGTSpan::Make(); }},
299 { "use" , []() -> sk_sp<SkSVGNode> { return SkSVGUse::Make(); }},
fmalita6ceef3d2016-07-26 18:46:34 -0700300};
301
302struct ConstructionContext {
fmalita28d5b722016-09-12 17:06:47 -0700303 ConstructionContext(SkSVGIDMapper* mapper) : fParent(nullptr), fIDMapper(mapper) {}
fmalita6ceef3d2016-07-26 18:46:34 -0700304 ConstructionContext(const ConstructionContext& other, const sk_sp<SkSVGNode>& newParent)
fmalita28d5b722016-09-12 17:06:47 -0700305 : fParent(newParent.get()), fIDMapper(other.fIDMapper) {}
fmalita6ceef3d2016-07-26 18:46:34 -0700306
Florin Malita39fe8c82020-10-20 10:43:03 -0400307 SkSVGNode* fParent;
308 SkSVGIDMapper* fIDMapper;
fmalita6ceef3d2016-07-26 18:46:34 -0700309};
310
Tyler Freemanc9911522020-05-08 13:23:10 -0700311bool set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value) {
Tyler Denniston57154992020-11-04 16:08:30 -0500312 if (node->parseAndSetAttribute(name, value)) {
313 // Handled by new code path
314 return true;
315 }
316
fmalita58649cc2016-07-29 08:52:03 -0700317 const int attrIndex = SkStrSearch(&gAttributeParseInfo[0].fKey,
318 SkTo<int>(SK_ARRAY_COUNT(gAttributeParseInfo)),
319 name, sizeof(gAttributeParseInfo[0]));
320 if (attrIndex < 0) {
fmalitafea704e2016-08-10 16:25:32 -0700321#if defined(SK_VERBOSE_SVG_PARSING)
fmalita58649cc2016-07-29 08:52:03 -0700322 SkDebugf("unhandled attribute: %s\n", name);
fmalitafea704e2016-08-10 16:25:32 -0700323#endif
Tyler Freemanc9911522020-05-08 13:23:10 -0700324 return false;
fmalita58649cc2016-07-29 08:52:03 -0700325 }
326
327 SkASSERT(SkTo<size_t>(attrIndex) < SK_ARRAY_COUNT(gAttributeParseInfo));
328 const auto& attrInfo = gAttributeParseInfo[attrIndex].fValue;
329 if (!attrInfo.fSetter(node, attrInfo.fAttr, value)) {
fmalitafea704e2016-08-10 16:25:32 -0700330#if defined(SK_VERBOSE_SVG_PARSING)
fmalita58649cc2016-07-29 08:52:03 -0700331 SkDebugf("could not parse attribute: '%s=\"%s\"'\n", name, value);
fmalitafea704e2016-08-10 16:25:32 -0700332#endif
Tyler Freemanc9911522020-05-08 13:23:10 -0700333 return false;
fmalita58649cc2016-07-29 08:52:03 -0700334 }
Tyler Freemanc9911522020-05-08 13:23:10 -0700335
336 return true;
fmalita58649cc2016-07-29 08:52:03 -0700337}
338
fmalita6ceef3d2016-07-26 18:46:34 -0700339void parse_node_attributes(const SkDOM& xmlDom, const SkDOM::Node* xmlNode,
fmalita28d5b722016-09-12 17:06:47 -0700340 const sk_sp<SkSVGNode>& svgNode, SkSVGIDMapper* mapper) {
fmalita6ceef3d2016-07-26 18:46:34 -0700341 const char* name, *value;
342 SkDOM::AttrIter attrIter(xmlDom, xmlNode);
343 while ((name = attrIter.next(&value))) {
fmalita28d5b722016-09-12 17:06:47 -0700344 // We're handling id attributes out of band for now.
345 if (!strcmp(name, "id")) {
346 mapper->set(SkString(value), svgNode);
347 continue;
348 }
fmalita58649cc2016-07-29 08:52:03 -0700349 set_string_attribute(svgNode, name, value);
fmalita6ceef3d2016-07-26 18:46:34 -0700350 }
351}
352
353sk_sp<SkSVGNode> construct_svg_node(const SkDOM& dom, const ConstructionContext& ctx,
354 const SkDOM::Node* xmlNode) {
355 const char* elem = dom.getName(xmlNode);
356 const SkDOM::Type elemType = dom.getType(xmlNode);
357
358 if (elemType == SkDOM::kText_Type) {
Florin Malita512ff752020-12-06 11:50:52 -0500359 // Text literals require special handling.
fmalita6ceef3d2016-07-26 18:46:34 -0700360 SkASSERT(dom.countChildren(xmlNode) == 0);
Florin Malita512ff752020-12-06 11:50:52 -0500361 auto txt = SkSVGTextLiteral::Make();
362 txt->setText(SkString(dom.getName(xmlNode)));
363 ctx.fParent->appendChild(std::move(txt));
364
fmalita6ceef3d2016-07-26 18:46:34 -0700365 return nullptr;
366 }
367
368 SkASSERT(elemType == SkDOM::kElement_Type);
369
Florin Malitacdeabca2021-01-20 13:21:20 -0500370 auto make_node = [](const ConstructionContext& ctx, const char* elem) -> sk_sp<SkSVGNode> {
371 if (strcmp(elem, "svg") == 0) {
372 // Outermost SVG element must be tagged as such.
373 return SkSVGSVG::Make(ctx.fParent ? SkSVGSVG::Type::kInner
374 : SkSVGSVG::Type::kRoot);
375 }
376
377 const int tagIndex = SkStrSearch(&gTagFactories[0].fKey,
378 SkTo<int>(SK_ARRAY_COUNT(gTagFactories)),
379 elem, sizeof(gTagFactories[0]));
380 if (tagIndex < 0) {
fmalitafea704e2016-08-10 16:25:32 -0700381#if defined(SK_VERBOSE_SVG_PARSING)
Florin Malitacdeabca2021-01-20 13:21:20 -0500382 SkDebugf("unhandled element: <%s>\n", elem);
fmalitafea704e2016-08-10 16:25:32 -0700383#endif
Florin Malitacdeabca2021-01-20 13:21:20 -0500384 return nullptr;
385 }
386 SkASSERT(SkTo<size_t>(tagIndex) < SK_ARRAY_COUNT(gTagFactories));
387
388 return gTagFactories[tagIndex].fValue();
389 };
390
391 auto node = make_node(ctx, elem);
392 if (!node) {
fmalita6ceef3d2016-07-26 18:46:34 -0700393 return nullptr;
394 }
395
fmalita28d5b722016-09-12 17:06:47 -0700396 parse_node_attributes(dom, xmlNode, node, ctx.fIDMapper);
fmalita6ceef3d2016-07-26 18:46:34 -0700397
398 ConstructionContext localCtx(ctx, node);
399 for (auto* child = dom.getFirstChild(xmlNode, nullptr); child;
400 child = dom.getNextSibling(child)) {
401 sk_sp<SkSVGNode> childNode = construct_svg_node(dom, localCtx, child);
402 if (childNode) {
403 node->appendChild(std::move(childNode));
404 }
405 }
406
407 return node;
408}
409
410} // anonymous namespace
411
Florin Malita7006e152020-11-10 15:24:59 -0500412SkSVGDOM::Builder& SkSVGDOM::Builder::setFontManager(sk_sp<SkFontMgr> fmgr) {
413 fFontMgr = std::move(fmgr);
414 return *this;
fmalita6ceef3d2016-07-26 18:46:34 -0700415}
416
Florin Malita24df67d2021-01-26 18:45:34 -0500417SkSVGDOM::Builder& SkSVGDOM::Builder::setResourceProvider(sk_sp<skresources::ResourceProvider> rp) {
418 fResourceProvider = std::move(rp);
419 return *this;
420}
421
Florin Malita7006e152020-11-10 15:24:59 -0500422sk_sp<SkSVGDOM> SkSVGDOM::Builder::make(SkStream& str) const {
fmalita6ceef3d2016-07-26 18:46:34 -0700423 SkDOM xmlDom;
Florin Malita7006e152020-11-10 15:24:59 -0500424 if (!xmlDom.build(str)) {
fmalita6ceef3d2016-07-26 18:46:34 -0700425 return nullptr;
426 }
427
Florin Malita7006e152020-11-10 15:24:59 -0500428 SkSVGIDMapper mapper;
429 ConstructionContext ctx(&mapper);
430
431 auto root = construct_svg_node(xmlDom, ctx, xmlDom.getRootNode());
432 if (!root || root->tag() != SkSVGTag::kSvg) {
433 return nullptr;
434 }
435
Florin Malita24df67d2021-01-26 18:45:34 -0500436 class NullResourceProvider final : public skresources::ResourceProvider {
437 sk_sp<SkData> load(const char[], const char[]) const override { return nullptr; }
438 };
439
440 auto resource_provider = fResourceProvider ? fResourceProvider
441 : sk_make_sp<NullResourceProvider>();
442
Florin Malita7006e152020-11-10 15:24:59 -0500443 return sk_sp<SkSVGDOM>(new SkSVGDOM(sk_sp<SkSVGSVG>(static_cast<SkSVGSVG*>(root.release())),
Florin Malita24df67d2021-01-26 18:45:34 -0500444 std::move(fFontMgr), std::move(resource_provider),
445 std::move(mapper)));
fmalita6ceef3d2016-07-26 18:46:34 -0700446}
447
Florin Malita24df67d2021-01-26 18:45:34 -0500448SkSVGDOM::SkSVGDOM(sk_sp<SkSVGSVG> root, sk_sp<SkFontMgr> fmgr,
449 sk_sp<skresources::ResourceProvider> rp, SkSVGIDMapper&& mapper)
Florin Malita7006e152020-11-10 15:24:59 -0500450 : fRoot(std::move(root))
451 , fFontMgr(std::move(fmgr))
Florin Malita24df67d2021-01-26 18:45:34 -0500452 , fResourceProvider(std::move(rp))
Florin Malita7006e152020-11-10 15:24:59 -0500453 , fIDMapper(std::move(mapper))
454 , fContainerSize(fRoot->intrinsicSize(SkSVGLengthContext(SkSize::Make(0, 0))))
Florin Malita24df67d2021-01-26 18:45:34 -0500455{
456 SkASSERT(fResourceProvider);
457}
Florin Malita7006e152020-11-10 15:24:59 -0500458
fmalita6ceef3d2016-07-26 18:46:34 -0700459void SkSVGDOM::render(SkCanvas* canvas) const {
460 if (fRoot) {
Florin Malitaebca0dd2017-09-09 09:39:07 -0400461 SkSVGLengthContext lctx(fContainerSize);
462 SkSVGPresentationContext pctx;
Florin Malita24df67d2021-01-26 18:45:34 -0500463 fRoot->render(SkSVGRenderContext(canvas, fFontMgr, fResourceProvider, fIDMapper, lctx, pctx,
464 nullptr));
fmalita6ceef3d2016-07-26 18:46:34 -0700465 }
466}
467
fmalitae1baa7c2016-09-14 12:04:30 -0700468const SkSize& SkSVGDOM::containerSize() const {
469 return fContainerSize;
470}
471
fmalita6ceef3d2016-07-26 18:46:34 -0700472void SkSVGDOM::setContainerSize(const SkSize& containerSize) {
473 // TODO: inval
474 fContainerSize = containerSize;
475}
fmalitaca39d712016-08-12 13:17:11 -0700476
Tyler Freemanc9911522020-05-08 13:23:10 -0700477sk_sp<SkSVGNode>* SkSVGDOM::findNodeById(const char* id) {
478 SkString idStr(id);
479 return this->fIDMapper.find(idStr);
480}
481
Tyler Freemanc9911522020-05-08 13:23:10 -0700482// TODO(fuego): move this to SkSVGNode or its own CU.
483bool SkSVGNode::setAttribute(const char* attributeName, const char* attributeValue) {
484 return set_string_attribute(sk_ref_sp(this), attributeName, attributeValue);
485}