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