1 /*
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 "experimental/svg/model/SkSVGAttributeParser.h"
9 #include "experimental/svg/model/SkSVGCircle.h"
10 #include "experimental/svg/model/SkSVGClipPath.h"
11 #include "experimental/svg/model/SkSVGDOM.h"
12 #include "experimental/svg/model/SkSVGDefs.h"
13 #include "experimental/svg/model/SkSVGEllipse.h"
14 #include "experimental/svg/model/SkSVGG.h"
15 #include "experimental/svg/model/SkSVGLine.h"
16 #include "experimental/svg/model/SkSVGLinearGradient.h"
17 #include "experimental/svg/model/SkSVGNode.h"
18 #include "experimental/svg/model/SkSVGPath.h"
19 #include "experimental/svg/model/SkSVGPattern.h"
20 #include "experimental/svg/model/SkSVGPoly.h"
21 #include "experimental/svg/model/SkSVGRadialGradient.h"
22 #include "experimental/svg/model/SkSVGRect.h"
23 #include "experimental/svg/model/SkSVGRenderContext.h"
24 #include "experimental/svg/model/SkSVGSVG.h"
25 #include "experimental/svg/model/SkSVGStop.h"
26 #include "experimental/svg/model/SkSVGText.h"
27 #include "experimental/svg/model/SkSVGTypes.h"
28 #include "experimental/svg/model/SkSVGUse.h"
29 #include "experimental/svg/model/SkSVGValue.h"
30 #include "include/core/SkCanvas.h"
31 #include "include/core/SkString.h"
32 #include "include/private/SkTo.h"
33 #include "include/utils/SkParsePath.h"
34 #include "src/core/SkTSearch.h"
35 #include "src/xml/SkDOM.h"
36
37 namespace {
38
SetPaintAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)39 bool SetPaintAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
40 const char* stringValue) {
41 SkSVGPaint paint;
42 SkSVGAttributeParser parser(stringValue);
43 if (!parser.parsePaint(&paint)) {
44 return false;
45 }
46
47 node->setAttribute(attr, SkSVGPaintValue(paint));
48 return true;
49 }
50
SetColorAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)51 bool SetColorAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
52 const char* stringValue) {
53 SkSVGColorType color;
54 SkSVGAttributeParser parser(stringValue);
55 if (!parser.parseColor(&color)) {
56 return false;
57 }
58
59 node->setAttribute(attr, SkSVGColorValue(color));
60 return true;
61 }
62
SetIRIAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)63 bool SetIRIAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
64 const char* stringValue) {
65 SkSVGStringType iri;
66 SkSVGAttributeParser parser(stringValue);
67 if (!parser.parseIRI(&iri)) {
68 return false;
69 }
70
71 node->setAttribute(attr, SkSVGStringValue(iri));
72 return true;
73 }
74
SetClipPathAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)75 bool SetClipPathAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
76 const char* stringValue) {
77 SkSVGClip clip;
78 SkSVGAttributeParser parser(stringValue);
79 if (!parser.parseClipPath(&clip)) {
80 return false;
81 }
82
83 node->setAttribute(attr, SkSVGClipValue(clip));
84 return true;
85 }
86
87
SetPathDataAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)88 bool SetPathDataAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
89 const char* stringValue) {
90 SkPath path;
91 if (!SkParsePath::FromSVGString(stringValue, &path)) {
92 return false;
93 }
94
95 node->setAttribute(attr, SkSVGPathValue(path));
96 return true;
97 }
98
SetStringAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)99 bool SetStringAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
100 const char* stringValue) {
101 SkString str(stringValue, strlen(stringValue));
102 SkSVGStringType strType = SkSVGStringType(str);
103 node->setAttribute(attr, SkSVGStringValue(strType));
104 return true;
105 }
106
SetTransformAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)107 bool SetTransformAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
108 const char* stringValue) {
109 SkSVGTransformType transform;
110 SkSVGAttributeParser parser(stringValue);
111 if (!parser.parseTransform(&transform)) {
112 return false;
113 }
114
115 node->setAttribute(attr, SkSVGTransformValue(transform));
116 return true;
117 }
118
SetLengthAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)119 bool SetLengthAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
120 const char* stringValue) {
121 SkSVGLength length;
122 SkSVGAttributeParser parser(stringValue);
123 if (!parser.parseLength(&length)) {
124 return false;
125 }
126
127 node->setAttribute(attr, SkSVGLengthValue(length));
128 return true;
129 }
130
SetNumberAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)131 bool SetNumberAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
132 const char* stringValue) {
133 SkSVGNumberType number;
134 SkSVGAttributeParser parser(stringValue);
135 if (!parser.parseNumber(&number)) {
136 return false;
137 }
138
139 node->setAttribute(attr, SkSVGNumberValue(number));
140 return true;
141 }
142
SetViewBoxAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)143 bool SetViewBoxAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
144 const char* stringValue) {
145 SkSVGViewBoxType viewBox;
146 SkSVGAttributeParser parser(stringValue);
147 if (!parser.parseViewBox(&viewBox)) {
148 return false;
149 }
150
151 node->setAttribute(attr, SkSVGViewBoxValue(viewBox));
152 return true;
153 }
154
SetLineCapAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)155 bool SetLineCapAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
156 const char* stringValue) {
157 SkSVGLineCap lineCap;
158 SkSVGAttributeParser parser(stringValue);
159 if (!parser.parseLineCap(&lineCap)) {
160 return false;
161 }
162
163 node->setAttribute(attr, SkSVGLineCapValue(lineCap));
164 return true;
165 }
166
SetLineJoinAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)167 bool SetLineJoinAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
168 const char* stringValue) {
169 SkSVGLineJoin lineJoin;
170 SkSVGAttributeParser parser(stringValue);
171 if (!parser.parseLineJoin(&lineJoin)) {
172 return false;
173 }
174
175 node->setAttribute(attr, SkSVGLineJoinValue(lineJoin));
176 return true;
177 }
178
SetSpreadMethodAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)179 bool SetSpreadMethodAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
180 const char* stringValue) {
181 SkSVGSpreadMethod spread;
182 SkSVGAttributeParser parser(stringValue);
183 if (!parser.parseSpreadMethod(&spread)) {
184 return false;
185 }
186
187 node->setAttribute(attr, SkSVGSpreadMethodValue(spread));
188 return true;
189 }
190
SetPointsAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)191 bool SetPointsAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
192 const char* stringValue) {
193 SkSVGPointsType points;
194 SkSVGAttributeParser parser(stringValue);
195 if (!parser.parsePoints(&points)) {
196 return false;
197 }
198
199 node->setAttribute(attr, SkSVGPointsValue(points));
200 return true;
201 }
202
SetFillRuleAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)203 bool SetFillRuleAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
204 const char* stringValue) {
205 SkSVGFillRule fillRule;
206 SkSVGAttributeParser parser(stringValue);
207 if (!parser.parseFillRule(&fillRule)) {
208 return false;
209 }
210
211 node->setAttribute(attr, SkSVGFillRuleValue(fillRule));
212 return true;
213 }
214
SetVisibilityAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)215 bool SetVisibilityAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
216 const char* stringValue) {
217 SkSVGVisibility visibility;
218 SkSVGAttributeParser parser(stringValue);
219 if (!parser.parseVisibility(&visibility)) {
220 return false;
221 }
222
223 node->setAttribute(attr, SkSVGVisibilityValue(visibility));
224 return true;
225 }
226
SetDashArrayAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)227 bool SetDashArrayAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
228 const char* stringValue) {
229 SkSVGDashArray dashArray;
230 SkSVGAttributeParser parser(stringValue);
231 if (!parser.parseDashArray(&dashArray)) {
232 return false;
233 }
234
235 node->setAttribute(attr, SkSVGDashArrayValue(dashArray));
236 return true;
237 }
238
TrimmedString(const char * first,const char * last)239 SkString TrimmedString(const char* first, const char* last) {
240 SkASSERT(first);
241 SkASSERT(last);
242 SkASSERT(first <= last);
243
244 while (first <= last && *first <= ' ') { first++; }
245 while (first <= last && *last <= ' ') { last--; }
246
247 SkASSERT(last - first + 1 >= 0);
248 return SkString(first, SkTo<size_t>(last - first + 1));
249 }
250
251 // Breaks a "foo: bar; baz: ..." string into key:value pairs.
252 class StyleIterator {
253 public:
StyleIterator(const char * str)254 StyleIterator(const char* str) : fPos(str) { }
255
next()256 std::tuple<SkString, SkString> next() {
257 SkString name, value;
258
259 if (fPos) {
260 const char* sep = this->nextSeparator();
261 SkASSERT(*sep == ';' || *sep == '\0');
262
263 const char* valueSep = strchr(fPos, ':');
264 if (valueSep && valueSep < sep) {
265 name = TrimmedString(fPos, valueSep - 1);
266 value = TrimmedString(valueSep + 1, sep - 1);
267 }
268
269 fPos = *sep ? sep + 1 : nullptr;
270 }
271
272 return std::make_tuple(name, value);
273 }
274
275 private:
nextSeparator() const276 const char* nextSeparator() const {
277 const char* sep = fPos;
278 while (*sep != ';' && *sep != '\0') {
279 sep++;
280 }
281 return sep;
282 }
283
284 const char* fPos;
285 };
286
287 void set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value);
288
SetStyleAttributes(const sk_sp<SkSVGNode> & node,SkSVGAttribute,const char * stringValue)289 bool SetStyleAttributes(const sk_sp<SkSVGNode>& node, SkSVGAttribute,
290 const char* stringValue) {
291
292 SkString name, value;
293 StyleIterator iter(stringValue);
294 for (;;) {
295 std::tie(name, value) = iter.next();
296 if (name.isEmpty()) {
297 break;
298 }
299 set_string_attribute(node, name.c_str(), value.c_str());
300 }
301
302 return true;
303 }
304
305 template<typename T>
306 struct SortedDictionaryEntry {
307 const char* fKey;
308 const T fValue;
309 };
310
311 struct AttrParseInfo {
312 SkSVGAttribute fAttr;
313 bool (*fSetter)(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, const char* stringValue);
314 };
315
316 SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
317 { "clip-path" , { SkSVGAttribute::kClipPath , SetClipPathAttribute }},
318 { "clip-rule" , { SkSVGAttribute::kClipRule , SetFillRuleAttribute }},
319 { "cx" , { SkSVGAttribute::kCx , SetLengthAttribute }},
320 { "cy" , { SkSVGAttribute::kCy , SetLengthAttribute }},
321 { "d" , { SkSVGAttribute::kD , SetPathDataAttribute }},
322 { "fill" , { SkSVGAttribute::kFill , SetPaintAttribute }},
323 { "fill-opacity" , { SkSVGAttribute::kFillOpacity , SetNumberAttribute }},
324 { "fill-rule" , { SkSVGAttribute::kFillRule , SetFillRuleAttribute }},
325 { "font-family" , { SkSVGAttribute::kFontFamily , SetStringAttribute }},
326 { "font-size" , { SkSVGAttribute::kFontSize , SetLengthAttribute }},
327 // focal point x & y
328 { "fx" , { SkSVGAttribute::kFx , SetLengthAttribute }},
329 { "fy" , { SkSVGAttribute::kFy , SetLengthAttribute }},
330 { "gradientTransform", { SkSVGAttribute::kGradientTransform, SetTransformAttribute }},
331 { "height" , { SkSVGAttribute::kHeight , SetLengthAttribute }},
332 { "offset" , { SkSVGAttribute::kOffset , SetLengthAttribute }},
333 { "opacity" , { SkSVGAttribute::kOpacity , SetNumberAttribute }},
334 { "patternTransform" , { SkSVGAttribute::kPatternTransform , SetTransformAttribute }},
335 { "points" , { SkSVGAttribute::kPoints , SetPointsAttribute }},
336 { "r" , { SkSVGAttribute::kR , SetLengthAttribute }},
337 { "rx" , { SkSVGAttribute::kRx , SetLengthAttribute }},
338 { "ry" , { SkSVGAttribute::kRy , SetLengthAttribute }},
339 { "spreadMethod" , { SkSVGAttribute::kSpreadMethod , SetSpreadMethodAttribute }},
340 { "stop-color" , { SkSVGAttribute::kStopColor , SetColorAttribute }},
341 { "stop-opacity" , { SkSVGAttribute::kStopOpacity , SetNumberAttribute }},
342 { "stroke" , { SkSVGAttribute::kStroke , SetPaintAttribute }},
343 { "stroke-dasharray" , { SkSVGAttribute::kStrokeDashArray , SetDashArrayAttribute }},
344 { "stroke-dashoffset", { SkSVGAttribute::kStrokeDashOffset , SetLengthAttribute }},
345 { "stroke-linecap" , { SkSVGAttribute::kStrokeLineCap , SetLineCapAttribute }},
346 { "stroke-linejoin" , { SkSVGAttribute::kStrokeLineJoin , SetLineJoinAttribute }},
347 { "stroke-miterlimit", { SkSVGAttribute::kStrokeMiterLimit , SetNumberAttribute }},
348 { "stroke-opacity" , { SkSVGAttribute::kStrokeOpacity , SetNumberAttribute }},
349 { "stroke-width" , { SkSVGAttribute::kStrokeWidth , SetLengthAttribute }},
350 { "style" , { SkSVGAttribute::kUnknown , SetStyleAttributes }},
351 { "text" , { SkSVGAttribute::kText , SetStringAttribute }},
352 { "text-anchor" , { SkSVGAttribute::kTextAnchor , SetStringAttribute }},
353 { "transform" , { SkSVGAttribute::kTransform , SetTransformAttribute }},
354 { "viewBox" , { SkSVGAttribute::kViewBox , SetViewBoxAttribute }},
355 { "visibility" , { SkSVGAttribute::kVisibility , SetVisibilityAttribute }},
356 { "width" , { SkSVGAttribute::kWidth , SetLengthAttribute }},
357 { "x" , { SkSVGAttribute::kX , SetLengthAttribute }},
358 { "x1" , { SkSVGAttribute::kX1 , SetLengthAttribute }},
359 { "x2" , { SkSVGAttribute::kX2 , SetLengthAttribute }},
360 { "xlink:href" , { SkSVGAttribute::kHref , SetIRIAttribute }},
361 { "y" , { SkSVGAttribute::kY , SetLengthAttribute }},
362 { "y1" , { SkSVGAttribute::kY1 , SetLengthAttribute }},
363 { "y2" , { SkSVGAttribute::kY2 , SetLengthAttribute }},
364 };
365
366 SortedDictionaryEntry<sk_sp<SkSVGNode>(*)()> gTagFactories[] = {
__anon26f27ceb0202() 367 { "a" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
__anon26f27ceb0302() 368 { "circle" , []() -> sk_sp<SkSVGNode> { return SkSVGCircle::Make(); }},
__anon26f27ceb0402() 369 { "clipPath" , []() -> sk_sp<SkSVGNode> { return SkSVGClipPath::Make(); }},
__anon26f27ceb0502() 370 { "defs" , []() -> sk_sp<SkSVGNode> { return SkSVGDefs::Make(); }},
__anon26f27ceb0602() 371 { "ellipse" , []() -> sk_sp<SkSVGNode> { return SkSVGEllipse::Make(); }},
__anon26f27ceb0702() 372 { "g" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
__anon26f27ceb0802() 373 { "line" , []() -> sk_sp<SkSVGNode> { return SkSVGLine::Make(); }},
__anon26f27ceb0902() 374 { "linearGradient", []() -> sk_sp<SkSVGNode> { return SkSVGLinearGradient::Make(); }},
__anon26f27ceb0a02() 375 { "path" , []() -> sk_sp<SkSVGNode> { return SkSVGPath::Make(); }},
__anon26f27ceb0b02() 376 { "pattern" , []() -> sk_sp<SkSVGNode> { return SkSVGPattern::Make(); }},
__anon26f27ceb0c02() 377 { "polygon" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolygon(); }},
__anon26f27ceb0d02() 378 { "polyline" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolyline(); }},
__anon26f27ceb0e02() 379 { "radialGradient", []() -> sk_sp<SkSVGNode> { return SkSVGRadialGradient::Make(); }},
__anon26f27ceb0f02() 380 { "rect" , []() -> sk_sp<SkSVGNode> { return SkSVGRect::Make(); }},
__anon26f27ceb1002() 381 { "stop" , []() -> sk_sp<SkSVGNode> { return SkSVGStop::Make(); }},
__anon26f27ceb1102() 382 { "svg" , []() -> sk_sp<SkSVGNode> { return SkSVGSVG::Make(); }},
__anon26f27ceb1202() 383 { "text" , []() -> sk_sp<SkSVGNode> { return SkSVGText::Make(); }},
__anon26f27ceb1302() 384 { "use" , []() -> sk_sp<SkSVGNode> { return SkSVGUse::Make(); }},
385 };
386
387 struct ConstructionContext {
ConstructionContext__anon26f27ceb0111::ConstructionContext388 ConstructionContext(SkSVGIDMapper* mapper) : fParent(nullptr), fIDMapper(mapper) {}
ConstructionContext__anon26f27ceb0111::ConstructionContext389 ConstructionContext(const ConstructionContext& other, const sk_sp<SkSVGNode>& newParent)
390 : fParent(newParent.get()), fIDMapper(other.fIDMapper) {}
391
392 const SkSVGNode* fParent;
393 SkSVGIDMapper* fIDMapper;
394 };
395
set_string_attribute(const sk_sp<SkSVGNode> & node,const char * name,const char * value)396 void set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value) {
397 const int attrIndex = SkStrSearch(&gAttributeParseInfo[0].fKey,
398 SkTo<int>(SK_ARRAY_COUNT(gAttributeParseInfo)),
399 name, sizeof(gAttributeParseInfo[0]));
400 if (attrIndex < 0) {
401 #if defined(SK_VERBOSE_SVG_PARSING)
402 SkDebugf("unhandled attribute: %s\n", name);
403 #endif
404 return;
405 }
406
407 SkASSERT(SkTo<size_t>(attrIndex) < SK_ARRAY_COUNT(gAttributeParseInfo));
408 const auto& attrInfo = gAttributeParseInfo[attrIndex].fValue;
409 if (!attrInfo.fSetter(node, attrInfo.fAttr, value)) {
410 #if defined(SK_VERBOSE_SVG_PARSING)
411 SkDebugf("could not parse attribute: '%s=\"%s\"'\n", name, value);
412 #endif
413 }
414 }
415
parse_node_attributes(const SkDOM & xmlDom,const SkDOM::Node * xmlNode,const sk_sp<SkSVGNode> & svgNode,SkSVGIDMapper * mapper)416 void parse_node_attributes(const SkDOM& xmlDom, const SkDOM::Node* xmlNode,
417 const sk_sp<SkSVGNode>& svgNode, SkSVGIDMapper* mapper) {
418 const char* name, *value;
419 SkDOM::AttrIter attrIter(xmlDom, xmlNode);
420 while ((name = attrIter.next(&value))) {
421 // We're handling id attributes out of band for now.
422 if (!strcmp(name, "id")) {
423 mapper->set(SkString(value), svgNode);
424 continue;
425 }
426 set_string_attribute(svgNode, name, value);
427 }
428 }
429
construct_svg_node(const SkDOM & dom,const ConstructionContext & ctx,const SkDOM::Node * xmlNode)430 sk_sp<SkSVGNode> construct_svg_node(const SkDOM& dom, const ConstructionContext& ctx,
431 const SkDOM::Node* xmlNode) {
432 const char* elem = dom.getName(xmlNode);
433 const SkDOM::Type elemType = dom.getType(xmlNode);
434
435 if (elemType == SkDOM::kText_Type) {
436 SkASSERT(dom.countChildren(xmlNode) == 0);
437 // TODO: text handling
438 return nullptr;
439 }
440
441 SkASSERT(elemType == SkDOM::kElement_Type);
442
443 const int tagIndex = SkStrSearch(&gTagFactories[0].fKey,
444 SkTo<int>(SK_ARRAY_COUNT(gTagFactories)),
445 elem, sizeof(gTagFactories[0]));
446 if (tagIndex < 0) {
447 #if defined(SK_VERBOSE_SVG_PARSING)
448 SkDebugf("unhandled element: <%s>\n", elem);
449 #endif
450 return nullptr;
451 }
452
453 SkASSERT(SkTo<size_t>(tagIndex) < SK_ARRAY_COUNT(gTagFactories));
454 sk_sp<SkSVGNode> node = gTagFactories[tagIndex].fValue();
455 parse_node_attributes(dom, xmlNode, node, ctx.fIDMapper);
456
457 ConstructionContext localCtx(ctx, node);
458 for (auto* child = dom.getFirstChild(xmlNode, nullptr); child;
459 child = dom.getNextSibling(child)) {
460 sk_sp<SkSVGNode> childNode = construct_svg_node(dom, localCtx, child);
461 if (childNode) {
462 node->appendChild(std::move(childNode));
463 }
464 }
465
466 return node;
467 }
468
469 } // anonymous namespace
470
SkSVGDOM()471 SkSVGDOM::SkSVGDOM()
472 : fContainerSize(SkSize::Make(0, 0)) {
473 }
474
MakeFromDOM(const SkDOM & xmlDom)475 sk_sp<SkSVGDOM> SkSVGDOM::MakeFromDOM(const SkDOM& xmlDom) {
476 sk_sp<SkSVGDOM> dom = sk_make_sp<SkSVGDOM>();
477
478 ConstructionContext ctx(&dom->fIDMapper);
479 dom->fRoot = construct_svg_node(xmlDom, ctx, xmlDom.getRootNode());
480
481 // Reset the default container size to match the intrinsic SVG size.
482 dom->setContainerSize(dom->intrinsicSize());
483
484 return dom;
485 }
486
MakeFromStream(SkStream & svgStream)487 sk_sp<SkSVGDOM> SkSVGDOM::MakeFromStream(SkStream& svgStream) {
488 SkDOM xmlDom;
489 if (!xmlDom.build(svgStream)) {
490 return nullptr;
491 }
492
493 return MakeFromDOM(xmlDom);
494 }
495
render(SkCanvas * canvas) const496 void SkSVGDOM::render(SkCanvas* canvas) const {
497 if (fRoot) {
498 SkSVGLengthContext lctx(fContainerSize);
499 SkSVGPresentationContext pctx;
500 fRoot->render(SkSVGRenderContext(canvas, fIDMapper, lctx, pctx));
501 }
502 }
503
intrinsicSize() const504 SkSize SkSVGDOM::intrinsicSize() const {
505 if (!fRoot || fRoot->tag() != SkSVGTag::kSvg) {
506 return SkSize::Make(0, 0);
507 }
508
509 // Intrinsic sizes are never relative, so the viewport size is irrelevant.
510 const SkSVGLengthContext lctx(SkSize::Make(0, 0));
511 return static_cast<const SkSVGSVG*>(fRoot.get())->intrinsicSize(lctx);
512 }
513
containerSize() const514 const SkSize& SkSVGDOM::containerSize() const {
515 return fContainerSize;
516 }
517
setContainerSize(const SkSize & containerSize)518 void SkSVGDOM::setContainerSize(const SkSize& containerSize) {
519 // TODO: inval
520 fContainerSize = containerSize;
521 }
522
setRoot(sk_sp<SkSVGNode> root)523 void SkSVGDOM::setRoot(sk_sp<SkSVGNode> root) {
524 fRoot = std::move(root);
525 }
526