blob: 758a3ede120387d7af34bbdaa02a29ab2656b60b [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
8#include "SkCanvas.h"
9#include "SkDOM.h"
fmalita6ceef3d2016-07-26 18:46:34 -070010#include "SkParsePath.h"
fmalitabffc2562016-08-03 10:21:11 -070011#include "SkSVGAttributeParser.h"
fmalitadc4c2a92016-08-16 15:38:51 -070012#include "SkSVGCircle.h"
Florin Malitace8840e2016-12-08 09:26:47 -050013#include "SkSVGClipPath.h"
Hal Canaryfdcfb8b2018-06-13 09:42:32 -040014#include "SkSVGDOM.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040015#include "SkSVGDefs.h"
fmalitadc4c2a92016-08-16 15:38:51 -070016#include "SkSVGEllipse.h"
fmalita6ceef3d2016-07-26 18:46:34 -070017#include "SkSVGG.h"
fmalitad24ee142016-08-17 08:38:15 -070018#include "SkSVGLine.h"
fmalita28d5b722016-09-12 17:06:47 -070019#include "SkSVGLinearGradient.h"
fmalita6ceef3d2016-07-26 18:46:34 -070020#include "SkSVGNode.h"
21#include "SkSVGPath.h"
Florin Malita1aa1bb62017-10-11 14:34:33 -040022#include "SkSVGPattern.h"
fmalita5b31f322016-08-12 12:15:33 -070023#include "SkSVGPoly.h"
Florin Malitacc6cc292017-10-09 16:05:30 -040024#include "SkSVGRadialGradient.h"
fmalitabffc2562016-08-03 10:21:11 -070025#include "SkSVGRect.h"
26#include "SkSVGRenderContext.h"
Hal Canaryfdcfb8b2018-06-13 09:42:32 -040027#include "SkSVGSVG.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040028#include "SkSVGStop.h"
fmalitabffc2562016-08-03 10:21:11 -070029#include "SkSVGTypes.h"
Florin Malita6a69c052017-10-11 14:02:11 -040030#include "SkSVGUse.h"
fmalita6ceef3d2016-07-26 18:46:34 -070031#include "SkSVGValue.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040032#include "SkString.h"
fmalita6ceef3d2016-07-26 18:46:34 -070033#include "SkTSearch.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040034#include "SkTo.h"
fmalita6ceef3d2016-07-26 18:46:34 -070035
36namespace {
37
fmalita6ceef3d2016-07-26 18:46:34 -070038bool SetPaintAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
39 const char* stringValue) {
fmalita2d961e02016-08-11 09:16:29 -070040 SkSVGPaint paint;
fmalitabffc2562016-08-03 10:21:11 -070041 SkSVGAttributeParser parser(stringValue);
fmalita2d961e02016-08-11 09:16:29 -070042 if (!parser.parsePaint(&paint)) {
fmalita28d5b722016-09-12 17:06:47 -070043 return false;
fmalitabffc2562016-08-03 10:21:11 -070044 }
45
fmalita2d961e02016-08-11 09:16:29 -070046 node->setAttribute(attr, SkSVGPaintValue(paint));
fmalita6ceef3d2016-07-26 18:46:34 -070047 return true;
48}
49
fmalita28d5b722016-09-12 17:06:47 -070050bool SetColorAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
51 const char* stringValue) {
52 SkSVGColorType color;
53 SkSVGAttributeParser parser(stringValue);
54 if (!parser.parseColor(&color)) {
55 return false;
56 }
57
58 node->setAttribute(attr, SkSVGColorValue(color));
59 return true;
60}
61
62bool SetIRIAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
63 const char* stringValue) {
64 SkSVGStringType iri;
65 SkSVGAttributeParser parser(stringValue);
66 if (!parser.parseIRI(&iri)) {
67 return false;
68 }
69
70 node->setAttribute(attr, SkSVGStringValue(iri));
71 return true;
72}
73
Florin Malitace8840e2016-12-08 09:26:47 -050074bool SetClipPathAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
75 const char* stringValue) {
76 SkSVGClip clip;
77 SkSVGAttributeParser parser(stringValue);
78 if (!parser.parseClipPath(&clip)) {
79 return false;
80 }
81
82 node->setAttribute(attr, SkSVGClipValue(clip));
83 return true;
84}
85
86
fmalita6ceef3d2016-07-26 18:46:34 -070087bool SetPathDataAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
88 const char* stringValue) {
89 SkPath path;
90 if (!SkParsePath::FromSVGString(stringValue, &path)) {
91 return false;
92 }
93
94 node->setAttribute(attr, SkSVGPathValue(path));
95 return true;
96}
97
98bool SetTransformAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
99 const char* stringValue) {
fmalitac97796b2016-08-08 12:58:57 -0700100 SkSVGTransformType transform;
101 SkSVGAttributeParser parser(stringValue);
102 if (!parser.parseTransform(&transform)) {
103 return false;
104 }
105
106 node->setAttribute(attr, SkSVGTransformValue(transform));
fmalita6ceef3d2016-07-26 18:46:34 -0700107 return true;
108}
109
fmalitabffc2562016-08-03 10:21:11 -0700110bool SetLengthAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
111 const char* stringValue) {
112 SkSVGLength length;
113 SkSVGAttributeParser parser(stringValue);
114 if (!parser.parseLength(&length)) {
115 return false;
116 }
117
118 node->setAttribute(attr, SkSVGLengthValue(length));
119 return true;
120}
121
fmalita2d961e02016-08-11 09:16:29 -0700122bool SetNumberAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
123 const char* stringValue) {
124 SkSVGNumberType number;
125 SkSVGAttributeParser parser(stringValue);
126 if (!parser.parseNumber(&number)) {
127 return false;
128 }
129
130 node->setAttribute(attr, SkSVGNumberValue(number));
131 return true;
132}
133
fmalita397a5172016-08-08 11:38:55 -0700134bool SetViewBoxAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
135 const char* stringValue) {
136 SkSVGViewBoxType viewBox;
137 SkSVGAttributeParser parser(stringValue);
138 if (!parser.parseViewBox(&viewBox)) {
139 return false;
140 }
141
142 node->setAttribute(attr, SkSVGViewBoxValue(viewBox));
143 return true;
144}
145
fmalita2d961e02016-08-11 09:16:29 -0700146bool SetLineCapAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
147 const char* stringValue) {
148 SkSVGLineCap lineCap;
149 SkSVGAttributeParser parser(stringValue);
150 if (!parser.parseLineCap(&lineCap)) {
151 return false;
152 }
153
154 node->setAttribute(attr, SkSVGLineCapValue(lineCap));
155 return true;
156}
157
158bool SetLineJoinAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
159 const char* stringValue) {
160 SkSVGLineJoin lineJoin;
161 SkSVGAttributeParser parser(stringValue);
162 if (!parser.parseLineJoin(&lineJoin)) {
163 return false;
164 }
165
166 node->setAttribute(attr, SkSVGLineJoinValue(lineJoin));
167 return true;
168}
169
fmalitacecd6172016-09-13 12:56:11 -0700170bool SetSpreadMethodAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
171 const char* stringValue) {
172 SkSVGSpreadMethod spread;
173 SkSVGAttributeParser parser(stringValue);
174 if (!parser.parseSpreadMethod(&spread)) {
175 return false;
176 }
177
178 node->setAttribute(attr, SkSVGSpreadMethodValue(spread));
179 return true;
180}
181
fmalita5b31f322016-08-12 12:15:33 -0700182bool SetPointsAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
183 const char* stringValue) {
184 SkSVGPointsType points;
185 SkSVGAttributeParser parser(stringValue);
186 if (!parser.parsePoints(&points)) {
187 return false;
188 }
189
190 node->setAttribute(attr, SkSVGPointsValue(points));
191 return true;
192}
193
Florin Malitae932d4b2016-12-01 13:35:11 -0500194bool SetFillRuleAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
195 const char* stringValue) {
196 SkSVGFillRule fillRule;
197 SkSVGAttributeParser parser(stringValue);
198 if (!parser.parseFillRule(&fillRule)) {
199 return false;
200 }
201
202 node->setAttribute(attr, SkSVGFillRuleValue(fillRule));
203 return true;
204}
205
Florin Malitaffe6ae42017-10-12 11:33:28 -0400206bool SetVisibilityAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
207 const char* stringValue) {
208 SkSVGVisibility visibility;
209 SkSVGAttributeParser parser(stringValue);
210 if (!parser.parseVisibility(&visibility)) {
211 return false;
212 }
213
214 node->setAttribute(attr, SkSVGVisibilityValue(visibility));
215 return true;
216}
217
Florin Malitaf543a602017-10-13 14:07:44 -0400218bool SetDashArrayAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
219 const char* stringValue) {
220 SkSVGDashArray dashArray;
221 SkSVGAttributeParser parser(stringValue);
222 if (!parser.parseDashArray(&dashArray)) {
223 return false;
224 }
225
226 node->setAttribute(attr, SkSVGDashArrayValue(dashArray));
227 return true;
228}
229
fmalita61f36b32016-08-08 13:58:50 -0700230SkString TrimmedString(const char* first, const char* last) {
231 SkASSERT(first);
232 SkASSERT(last);
233 SkASSERT(first <= last);
234
235 while (first <= last && *first <= ' ') { first++; }
236 while (first <= last && *last <= ' ') { last--; }
237
238 SkASSERT(last - first + 1 >= 0);
239 return SkString(first, SkTo<size_t>(last - first + 1));
240}
241
fmalita58649cc2016-07-29 08:52:03 -0700242// Breaks a "foo: bar; baz: ..." string into key:value pairs.
243class StyleIterator {
244public:
245 StyleIterator(const char* str) : fPos(str) { }
246
247 std::tuple<SkString, SkString> next() {
248 SkString name, value;
249
250 if (fPos) {
251 const char* sep = this->nextSeparator();
252 SkASSERT(*sep == ';' || *sep == '\0');
253
254 const char* valueSep = strchr(fPos, ':');
255 if (valueSep && valueSep < sep) {
fmalita61f36b32016-08-08 13:58:50 -0700256 name = TrimmedString(fPos, valueSep - 1);
257 value = TrimmedString(valueSep + 1, sep - 1);
fmalita58649cc2016-07-29 08:52:03 -0700258 }
259
260 fPos = *sep ? sep + 1 : nullptr;
261 }
262
263 return std::make_tuple(name, value);
264 }
265
266private:
267 const char* nextSeparator() const {
268 const char* sep = fPos;
269 while (*sep != ';' && *sep != '\0') {
270 sep++;
271 }
272 return sep;
273 }
274
275 const char* fPos;
276};
277
278void set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value);
279
280bool SetStyleAttributes(const sk_sp<SkSVGNode>& node, SkSVGAttribute,
281 const char* stringValue) {
282
283 SkString name, value;
284 StyleIterator iter(stringValue);
285 for (;;) {
286 std::tie(name, value) = iter.next();
287 if (name.isEmpty()) {
288 break;
289 }
290 set_string_attribute(node, name.c_str(), value.c_str());
291 }
292
293 return true;
294}
295
fmalita6ceef3d2016-07-26 18:46:34 -0700296template<typename T>
297struct SortedDictionaryEntry {
298 const char* fKey;
299 const T fValue;
300};
301
302struct AttrParseInfo {
303 SkSVGAttribute fAttr;
304 bool (*fSetter)(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, const char* stringValue);
305};
306
307SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
Florin Malitace8840e2016-12-08 09:26:47 -0500308 { "clip-path" , { SkSVGAttribute::kClipPath , SetClipPathAttribute }},
Florin Malita57a0edf2017-10-10 11:22:08 -0400309 { "clip-rule" , { SkSVGAttribute::kClipRule , SetFillRuleAttribute }},
fmalitaceb93ab2016-09-13 13:59:05 -0700310 { "cx" , { SkSVGAttribute::kCx , SetLengthAttribute }},
311 { "cy" , { SkSVGAttribute::kCy , SetLengthAttribute }},
312 { "d" , { SkSVGAttribute::kD , SetPathDataAttribute }},
313 { "fill" , { SkSVGAttribute::kFill , SetPaintAttribute }},
314 { "fill-opacity" , { SkSVGAttribute::kFillOpacity , SetNumberAttribute }},
Florin Malitae932d4b2016-12-01 13:35:11 -0500315 { "fill-rule" , { SkSVGAttribute::kFillRule , SetFillRuleAttribute }},
Florin Malitacc6cc292017-10-09 16:05:30 -0400316 // focal point x & y
317 { "fx" , { SkSVGAttribute::kFx , SetLengthAttribute }},
318 { "fy" , { SkSVGAttribute::kFy , SetLengthAttribute }},
fmalitaceb93ab2016-09-13 13:59:05 -0700319 { "gradientTransform", { SkSVGAttribute::kGradientTransform, SetTransformAttribute }},
320 { "height" , { SkSVGAttribute::kHeight , SetLengthAttribute }},
321 { "offset" , { SkSVGAttribute::kOffset , SetLengthAttribute }},
322 { "opacity" , { SkSVGAttribute::kOpacity , SetNumberAttribute }},
Florin Malita1aa1bb62017-10-11 14:34:33 -0400323 { "patternTransform" , { SkSVGAttribute::kPatternTransform , SetTransformAttribute }},
fmalitaceb93ab2016-09-13 13:59:05 -0700324 { "points" , { SkSVGAttribute::kPoints , SetPointsAttribute }},
325 { "r" , { SkSVGAttribute::kR , SetLengthAttribute }},
326 { "rx" , { SkSVGAttribute::kRx , SetLengthAttribute }},
327 { "ry" , { SkSVGAttribute::kRy , SetLengthAttribute }},
328 { "spreadMethod" , { SkSVGAttribute::kSpreadMethod , SetSpreadMethodAttribute }},
329 { "stop-color" , { SkSVGAttribute::kStopColor , SetColorAttribute }},
330 { "stop-opacity" , { SkSVGAttribute::kStopOpacity , SetNumberAttribute }},
331 { "stroke" , { SkSVGAttribute::kStroke , SetPaintAttribute }},
Florin Malitaf543a602017-10-13 14:07:44 -0400332 { "stroke-dasharray" , { SkSVGAttribute::kStrokeDashArray , SetDashArrayAttribute }},
Florin Malitae1dadd72017-10-13 18:18:32 -0400333 { "stroke-dashoffset", { SkSVGAttribute::kStrokeDashOffset , SetLengthAttribute }},
fmalitaceb93ab2016-09-13 13:59:05 -0700334 { "stroke-linecap" , { SkSVGAttribute::kStrokeLineCap , SetLineCapAttribute }},
335 { "stroke-linejoin" , { SkSVGAttribute::kStrokeLineJoin , SetLineJoinAttribute }},
Florin Malita4de426b2017-10-09 12:57:41 -0400336 { "stroke-miterlimit", { SkSVGAttribute::kStrokeMiterLimit , SetNumberAttribute }},
fmalitaceb93ab2016-09-13 13:59:05 -0700337 { "stroke-opacity" , { SkSVGAttribute::kStrokeOpacity , SetNumberAttribute }},
338 { "stroke-width" , { SkSVGAttribute::kStrokeWidth , SetLengthAttribute }},
339 { "style" , { SkSVGAttribute::kUnknown , SetStyleAttributes }},
340 { "transform" , { SkSVGAttribute::kTransform , SetTransformAttribute }},
341 { "viewBox" , { SkSVGAttribute::kViewBox , SetViewBoxAttribute }},
Florin Malitaffe6ae42017-10-12 11:33:28 -0400342 { "visibility" , { SkSVGAttribute::kVisibility , SetVisibilityAttribute }},
fmalitaceb93ab2016-09-13 13:59:05 -0700343 { "width" , { SkSVGAttribute::kWidth , SetLengthAttribute }},
344 { "x" , { SkSVGAttribute::kX , SetLengthAttribute }},
345 { "x1" , { SkSVGAttribute::kX1 , SetLengthAttribute }},
346 { "x2" , { SkSVGAttribute::kX2 , SetLengthAttribute }},
347 { "xlink:href" , { SkSVGAttribute::kHref , SetIRIAttribute }},
348 { "y" , { SkSVGAttribute::kY , SetLengthAttribute }},
349 { "y1" , { SkSVGAttribute::kY1 , SetLengthAttribute }},
350 { "y2" , { SkSVGAttribute::kY2 , SetLengthAttribute }},
fmalita6ceef3d2016-07-26 18:46:34 -0700351};
352
353SortedDictionaryEntry<sk_sp<SkSVGNode>(*)()> gTagFactories[] = {
Florin Malitaf6143ff2017-10-10 09:16:52 -0400354 { "a" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700355 { "circle" , []() -> sk_sp<SkSVGNode> { return SkSVGCircle::Make(); }},
Florin Malitace8840e2016-12-08 09:26:47 -0500356 { "clipPath" , []() -> sk_sp<SkSVGNode> { return SkSVGClipPath::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700357 { "defs" , []() -> sk_sp<SkSVGNode> { return SkSVGDefs::Make(); }},
358 { "ellipse" , []() -> sk_sp<SkSVGNode> { return SkSVGEllipse::Make(); }},
359 { "g" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
360 { "line" , []() -> sk_sp<SkSVGNode> { return SkSVGLine::Make(); }},
361 { "linearGradient", []() -> sk_sp<SkSVGNode> { return SkSVGLinearGradient::Make(); }},
362 { "path" , []() -> sk_sp<SkSVGNode> { return SkSVGPath::Make(); }},
Florin Malita1aa1bb62017-10-11 14:34:33 -0400363 { "pattern" , []() -> sk_sp<SkSVGNode> { return SkSVGPattern::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700364 { "polygon" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolygon(); }},
365 { "polyline" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolyline(); }},
Florin Malitacc6cc292017-10-09 16:05:30 -0400366 { "radialGradient", []() -> sk_sp<SkSVGNode> { return SkSVGRadialGradient::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700367 { "rect" , []() -> sk_sp<SkSVGNode> { return SkSVGRect::Make(); }},
368 { "stop" , []() -> sk_sp<SkSVGNode> { return SkSVGStop::Make(); }},
369 { "svg" , []() -> sk_sp<SkSVGNode> { return SkSVGSVG::Make(); }},
Florin Malita6a69c052017-10-11 14:02:11 -0400370 { "use" , []() -> sk_sp<SkSVGNode> { return SkSVGUse::Make(); }},
fmalita6ceef3d2016-07-26 18:46:34 -0700371};
372
373struct ConstructionContext {
fmalita28d5b722016-09-12 17:06:47 -0700374 ConstructionContext(SkSVGIDMapper* mapper) : fParent(nullptr), fIDMapper(mapper) {}
fmalita6ceef3d2016-07-26 18:46:34 -0700375 ConstructionContext(const ConstructionContext& other, const sk_sp<SkSVGNode>& newParent)
fmalita28d5b722016-09-12 17:06:47 -0700376 : fParent(newParent.get()), fIDMapper(other.fIDMapper) {}
fmalita6ceef3d2016-07-26 18:46:34 -0700377
378 const SkSVGNode* fParent;
fmalita28d5b722016-09-12 17:06:47 -0700379 SkSVGIDMapper* fIDMapper;
fmalita6ceef3d2016-07-26 18:46:34 -0700380};
381
fmalita58649cc2016-07-29 08:52:03 -0700382void set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value) {
383 const int attrIndex = SkStrSearch(&gAttributeParseInfo[0].fKey,
384 SkTo<int>(SK_ARRAY_COUNT(gAttributeParseInfo)),
385 name, sizeof(gAttributeParseInfo[0]));
386 if (attrIndex < 0) {
fmalitafea704e2016-08-10 16:25:32 -0700387#if defined(SK_VERBOSE_SVG_PARSING)
fmalita58649cc2016-07-29 08:52:03 -0700388 SkDebugf("unhandled attribute: %s\n", name);
fmalitafea704e2016-08-10 16:25:32 -0700389#endif
fmalita58649cc2016-07-29 08:52:03 -0700390 return;
391 }
392
393 SkASSERT(SkTo<size_t>(attrIndex) < SK_ARRAY_COUNT(gAttributeParseInfo));
394 const auto& attrInfo = gAttributeParseInfo[attrIndex].fValue;
395 if (!attrInfo.fSetter(node, attrInfo.fAttr, value)) {
fmalitafea704e2016-08-10 16:25:32 -0700396#if defined(SK_VERBOSE_SVG_PARSING)
fmalita58649cc2016-07-29 08:52:03 -0700397 SkDebugf("could not parse attribute: '%s=\"%s\"'\n", name, value);
fmalitafea704e2016-08-10 16:25:32 -0700398#endif
fmalita58649cc2016-07-29 08:52:03 -0700399 }
400}
401
fmalita6ceef3d2016-07-26 18:46:34 -0700402void parse_node_attributes(const SkDOM& xmlDom, const SkDOM::Node* xmlNode,
fmalita28d5b722016-09-12 17:06:47 -0700403 const sk_sp<SkSVGNode>& svgNode, SkSVGIDMapper* mapper) {
fmalita6ceef3d2016-07-26 18:46:34 -0700404 const char* name, *value;
405 SkDOM::AttrIter attrIter(xmlDom, xmlNode);
406 while ((name = attrIter.next(&value))) {
fmalita28d5b722016-09-12 17:06:47 -0700407 // We're handling id attributes out of band for now.
408 if (!strcmp(name, "id")) {
409 mapper->set(SkString(value), svgNode);
410 continue;
411 }
fmalita58649cc2016-07-29 08:52:03 -0700412 set_string_attribute(svgNode, name, value);
fmalita6ceef3d2016-07-26 18:46:34 -0700413 }
414}
415
416sk_sp<SkSVGNode> construct_svg_node(const SkDOM& dom, const ConstructionContext& ctx,
417 const SkDOM::Node* xmlNode) {
418 const char* elem = dom.getName(xmlNode);
419 const SkDOM::Type elemType = dom.getType(xmlNode);
420
421 if (elemType == SkDOM::kText_Type) {
422 SkASSERT(dom.countChildren(xmlNode) == 0);
423 // TODO: text handling
424 return nullptr;
425 }
426
427 SkASSERT(elemType == SkDOM::kElement_Type);
428
429 const int tagIndex = SkStrSearch(&gTagFactories[0].fKey,
430 SkTo<int>(SK_ARRAY_COUNT(gTagFactories)),
431 elem, sizeof(gTagFactories[0]));
432 if (tagIndex < 0) {
fmalitafea704e2016-08-10 16:25:32 -0700433#if defined(SK_VERBOSE_SVG_PARSING)
fmalita6ceef3d2016-07-26 18:46:34 -0700434 SkDebugf("unhandled element: <%s>\n", elem);
fmalitafea704e2016-08-10 16:25:32 -0700435#endif
fmalita6ceef3d2016-07-26 18:46:34 -0700436 return nullptr;
437 }
438
439 SkASSERT(SkTo<size_t>(tagIndex) < SK_ARRAY_COUNT(gTagFactories));
440 sk_sp<SkSVGNode> node = gTagFactories[tagIndex].fValue();
fmalita28d5b722016-09-12 17:06:47 -0700441 parse_node_attributes(dom, xmlNode, node, ctx.fIDMapper);
fmalita6ceef3d2016-07-26 18:46:34 -0700442
443 ConstructionContext localCtx(ctx, node);
444 for (auto* child = dom.getFirstChild(xmlNode, nullptr); child;
445 child = dom.getNextSibling(child)) {
446 sk_sp<SkSVGNode> childNode = construct_svg_node(dom, localCtx, child);
447 if (childNode) {
448 node->appendChild(std::move(childNode));
449 }
450 }
451
452 return node;
453}
454
455} // anonymous namespace
456
fmalitae1baa7c2016-09-14 12:04:30 -0700457SkSVGDOM::SkSVGDOM()
458 : fContainerSize(SkSize::Make(0, 0)) {
fmalita6ceef3d2016-07-26 18:46:34 -0700459}
460
fmalitae1baa7c2016-09-14 12:04:30 -0700461sk_sp<SkSVGDOM> SkSVGDOM::MakeFromDOM(const SkDOM& xmlDom) {
462 sk_sp<SkSVGDOM> dom = sk_make_sp<SkSVGDOM>();
fmalita6ceef3d2016-07-26 18:46:34 -0700463
fmalita28d5b722016-09-12 17:06:47 -0700464 ConstructionContext ctx(&dom->fIDMapper);
fmalita6ceef3d2016-07-26 18:46:34 -0700465 dom->fRoot = construct_svg_node(xmlDom, ctx, xmlDom.getRootNode());
466
fmalitae1baa7c2016-09-14 12:04:30 -0700467 // Reset the default container size to match the intrinsic SVG size.
468 dom->setContainerSize(dom->intrinsicSize());
469
fmalita6ceef3d2016-07-26 18:46:34 -0700470 return dom;
471}
472
fmalitae1baa7c2016-09-14 12:04:30 -0700473sk_sp<SkSVGDOM> SkSVGDOM::MakeFromStream(SkStream& svgStream) {
fmalita6ceef3d2016-07-26 18:46:34 -0700474 SkDOM xmlDom;
475 if (!xmlDom.build(svgStream)) {
476 return nullptr;
477 }
478
fmalitae1baa7c2016-09-14 12:04:30 -0700479 return MakeFromDOM(xmlDom);
fmalita6ceef3d2016-07-26 18:46:34 -0700480}
481
482void SkSVGDOM::render(SkCanvas* canvas) const {
483 if (fRoot) {
Florin Malitaebca0dd2017-09-09 09:39:07 -0400484 SkSVGLengthContext lctx(fContainerSize);
485 SkSVGPresentationContext pctx;
486 fRoot->render(SkSVGRenderContext(canvas, fIDMapper, lctx, pctx));
fmalita6ceef3d2016-07-26 18:46:34 -0700487 }
488}
489
fmalitae1baa7c2016-09-14 12:04:30 -0700490SkSize SkSVGDOM::intrinsicSize() const {
491 if (!fRoot || fRoot->tag() != SkSVGTag::kSvg) {
492 return SkSize::Make(0, 0);
493 }
494
495 // Intrinsic sizes are never relative, so the viewport size is irrelevant.
496 const SkSVGLengthContext lctx(SkSize::Make(0, 0));
497 return static_cast<const SkSVGSVG*>(fRoot.get())->intrinsicSize(lctx);
498}
499
500const SkSize& SkSVGDOM::containerSize() const {
501 return fContainerSize;
502}
503
fmalita6ceef3d2016-07-26 18:46:34 -0700504void SkSVGDOM::setContainerSize(const SkSize& containerSize) {
505 // TODO: inval
506 fContainerSize = containerSize;
507}
fmalitaca39d712016-08-12 13:17:11 -0700508
509void SkSVGDOM::setRoot(sk_sp<SkSVGNode> root) {
510 fRoot = std::move(root);
511}