• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/SkSVGTypes.h"
27 #include "experimental/svg/model/SkSVGUse.h"
28 #include "experimental/svg/model/SkSVGValue.h"
29 #include "experimental/svg/model/SkSVGXMLDOM.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 
36 namespace {
37 
SetPaintAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)38 bool SetPaintAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
39                        const char* stringValue) {
40     SkSVGPaint paint;
41     SkSVGAttributeParser parser(stringValue);
42     if (!parser.parsePaint(&paint)) {
43         return false;
44     }
45 
46     node->setAttribute(attr, SkSVGPaintValue(paint));
47     return true;
48 }
49 
SetColorAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)50 bool 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 
SetIRIAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)62 bool 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 
SetClipPathAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)74 bool 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 
SetPathDataAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)87 bool 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 
SetTransformAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)98 bool SetTransformAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
99                            const char* stringValue) {
100     SkSVGTransformType transform;
101     SkSVGAttributeParser parser(stringValue);
102     if (!parser.parseTransform(&transform)) {
103         return false;
104     }
105 
106     node->setAttribute(attr, SkSVGTransformValue(transform));
107     return true;
108 }
109 
SetLengthAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)110 bool 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 
SetNumberAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)122 bool 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 
SetViewBoxAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)134 bool 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 
SetLineCapAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)146 bool 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 
SetLineJoinAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)158 bool 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 
SetSpreadMethodAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)170 bool 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 
SetPointsAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)182 bool 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 
SetFillRuleAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)194 bool 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 
SetVisibilityAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)206 bool 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 
SetDashArrayAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)218 bool 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 
TrimmedString(const char * first,const char * last)230 SkString 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 
242 // Breaks a "foo: bar; baz: ..." string into key:value pairs.
243 class StyleIterator {
244 public:
StyleIterator(const char * str)245     StyleIterator(const char* str) : fPos(str) { }
246 
next()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) {
256                 name  = TrimmedString(fPos, valueSep - 1);
257                 value = TrimmedString(valueSep + 1, sep - 1);
258             }
259 
260             fPos = *sep ? sep + 1 : nullptr;
261         }
262 
263         return std::make_tuple(name, value);
264     }
265 
266 private:
nextSeparator() const267     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 
278 void set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value);
279 
SetStyleAttributes(const sk_sp<SkSVGNode> & node,SkSVGAttribute,const char * stringValue)280 bool 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 
296 template<typename T>
297 struct SortedDictionaryEntry {
298     const char* fKey;
299     const T     fValue;
300 };
301 
302 struct AttrParseInfo {
303     SkSVGAttribute fAttr;
304     bool (*fSetter)(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, const char* stringValue);
305 };
306 
307 SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
308     { "clip-path"        , { SkSVGAttribute::kClipPath         , SetClipPathAttribute     }},
309     { "clip-rule"        , { SkSVGAttribute::kClipRule         , SetFillRuleAttribute     }},
310     { "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       }},
315     { "fill-rule"        , { SkSVGAttribute::kFillRule         , SetFillRuleAttribute     }},
316     // focal point x & y
317     { "fx"               , { SkSVGAttribute::kFx               , SetLengthAttribute       }},
318     { "fy"               , { SkSVGAttribute::kFy               , SetLengthAttribute       }},
319     { "gradientTransform", { SkSVGAttribute::kGradientTransform, SetTransformAttribute    }},
320     { "height"           , { SkSVGAttribute::kHeight           , SetLengthAttribute       }},
321     { "offset"           , { SkSVGAttribute::kOffset           , SetLengthAttribute       }},
322     { "opacity"          , { SkSVGAttribute::kOpacity          , SetNumberAttribute       }},
323     { "patternTransform" , { SkSVGAttribute::kPatternTransform , SetTransformAttribute    }},
324     { "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        }},
332     { "stroke-dasharray" , { SkSVGAttribute::kStrokeDashArray  , SetDashArrayAttribute    }},
333     { "stroke-dashoffset", { SkSVGAttribute::kStrokeDashOffset , SetLengthAttribute       }},
334     { "stroke-linecap"   , { SkSVGAttribute::kStrokeLineCap    , SetLineCapAttribute      }},
335     { "stroke-linejoin"  , { SkSVGAttribute::kStrokeLineJoin   , SetLineJoinAttribute     }},
336     { "stroke-miterlimit", { SkSVGAttribute::kStrokeMiterLimit , SetNumberAttribute       }},
337     { "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      }},
342     { "visibility"       , { SkSVGAttribute::kVisibility       , SetVisibilityAttribute   }},
343     { "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       }},
351 };
352 
353 SortedDictionaryEntry<sk_sp<SkSVGNode>(*)()> gTagFactories[] = {
__anon232f9d4b0202() 354     { "a"             , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make();              }},
__anon232f9d4b0302() 355     { "circle"        , []() -> sk_sp<SkSVGNode> { return SkSVGCircle::Make();         }},
__anon232f9d4b0402() 356     { "clipPath"      , []() -> sk_sp<SkSVGNode> { return SkSVGClipPath::Make();       }},
__anon232f9d4b0502() 357     { "defs"          , []() -> sk_sp<SkSVGNode> { return SkSVGDefs::Make();           }},
__anon232f9d4b0602() 358     { "ellipse"       , []() -> sk_sp<SkSVGNode> { return SkSVGEllipse::Make();        }},
__anon232f9d4b0702() 359     { "g"             , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make();              }},
__anon232f9d4b0802() 360     { "line"          , []() -> sk_sp<SkSVGNode> { return SkSVGLine::Make();           }},
__anon232f9d4b0902() 361     { "linearGradient", []() -> sk_sp<SkSVGNode> { return SkSVGLinearGradient::Make(); }},
__anon232f9d4b0a02() 362     { "path"          , []() -> sk_sp<SkSVGNode> { return SkSVGPath::Make();           }},
__anon232f9d4b0b02() 363     { "pattern"       , []() -> sk_sp<SkSVGNode> { return SkSVGPattern::Make();        }},
__anon232f9d4b0c02() 364     { "polygon"       , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolygon();    }},
__anon232f9d4b0d02() 365     { "polyline"      , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolyline();   }},
__anon232f9d4b0e02() 366     { "radialGradient", []() -> sk_sp<SkSVGNode> { return SkSVGRadialGradient::Make(); }},
__anon232f9d4b0f02() 367     { "rect"          , []() -> sk_sp<SkSVGNode> { return SkSVGRect::Make();           }},
__anon232f9d4b1002() 368     { "stop"          , []() -> sk_sp<SkSVGNode> { return SkSVGStop::Make();           }},
__anon232f9d4b1102() 369     { "svg"           , []() -> sk_sp<SkSVGNode> { return SkSVGSVG::Make();            }},
__anon232f9d4b1202() 370     { "use"           , []() -> sk_sp<SkSVGNode> { return SkSVGUse::Make();            }},
371 };
372 
373 struct ConstructionContext {
ConstructionContext__anon232f9d4b0111::ConstructionContext374     ConstructionContext(SkSVGIDMapper* mapper) : fParent(nullptr), fIDMapper(mapper) {}
ConstructionContext__anon232f9d4b0111::ConstructionContext375     ConstructionContext(const ConstructionContext& other, const sk_sp<SkSVGNode>& newParent)
376         : fParent(newParent.get()), fIDMapper(other.fIDMapper) {}
377 
378     const SkSVGNode* fParent;
379     SkSVGIDMapper*   fIDMapper;
380 };
381 
set_string_attribute(const sk_sp<SkSVGNode> & node,const char * name,const char * value)382 void 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) {
387 #if defined(SK_VERBOSE_SVG_PARSING)
388         SkDebugf("unhandled attribute: %s\n", name);
389 #endif
390         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)) {
396 #if defined(SK_VERBOSE_SVG_PARSING)
397         SkDebugf("could not parse attribute: '%s=\"%s\"'\n", name, value);
398 #endif
399     }
400 }
401 
parse_node_attributes(const SkSVGXMLDOM & xmlDom,const SkDOM::Node * xmlNode,const sk_sp<SkSVGNode> & svgNode,SkSVGIDMapper * mapper)402 void parse_node_attributes(const SkSVGXMLDOM& xmlDom, const SkDOM::Node* xmlNode,
403                            const sk_sp<SkSVGNode>& svgNode, SkSVGIDMapper* mapper) {
404     const char* name, *value;
405     SkDOM::AttrIter attrIter(xmlDom, xmlNode);
406     while ((name = attrIter.next(&value))) {
407         // We're handling id attributes out of band for now.
408         if (!strcmp(name, "id")) {
409             mapper->set(SkString(value), svgNode);
410             continue;
411         }
412         set_string_attribute(svgNode, name, value);
413     }
414 }
415 
construct_svg_node(const SkSVGXMLDOM & dom,const ConstructionContext & ctx,const SkDOM::Node * xmlNode)416 sk_sp<SkSVGNode> construct_svg_node(const SkSVGXMLDOM& 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) {
433 #if defined(SK_VERBOSE_SVG_PARSING)
434         SkDebugf("unhandled element: <%s>\n", elem);
435 #endif
436         return nullptr;
437     }
438 
439     SkASSERT(SkTo<size_t>(tagIndex) < SK_ARRAY_COUNT(gTagFactories));
440     sk_sp<SkSVGNode> node = gTagFactories[tagIndex].fValue();
441     parse_node_attributes(dom, xmlNode, node, ctx.fIDMapper);
442 
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 
SkSVGDOM()457 SkSVGDOM::SkSVGDOM()
458     : fContainerSize(SkSize::Make(0, 0)) {
459 }
460 
MakeFromDOM(const SkSVGXMLDOM & xmlDom)461 sk_sp<SkSVGDOM> SkSVGDOM::MakeFromDOM(const SkSVGXMLDOM& xmlDom) {
462     sk_sp<SkSVGDOM> dom = sk_make_sp<SkSVGDOM>();
463 
464     ConstructionContext ctx(&dom->fIDMapper);
465     dom->fRoot = construct_svg_node(xmlDom, ctx, xmlDom.getRootNode());
466 
467     // Reset the default container size to match the intrinsic SVG size.
468     dom->setContainerSize(dom->intrinsicSize());
469 
470     return dom;
471 }
472 
MakeFromStream(SkStream & svgStream)473 sk_sp<SkSVGDOM> SkSVGDOM::MakeFromStream(SkStream& svgStream) {
474     SkSVGXMLDOM xmlDom;
475     if (!xmlDom.build(svgStream)) {
476         return nullptr;
477     }
478 
479     return MakeFromDOM(xmlDom);
480 }
481 
MakeFromStream(SkStream & svgStream,uint64_t svgColor)482 sk_sp<SkSVGDOM> SkSVGDOM::MakeFromStream(SkStream& svgStream, uint64_t svgColor) {
483     SkSVGXMLDOM xmlDom;
484     if (!xmlDom.build(svgStream, svgColor)) {
485         return nullptr;
486     }
487 
488     return MakeFromDOM(xmlDom);
489 }
490 
render(SkCanvas * canvas) const491 void SkSVGDOM::render(SkCanvas* canvas) const {
492     if (fRoot) {
493         SkSVGLengthContext       lctx(fContainerSize);
494         SkSVGPresentationContext pctx;
495         fRoot->render(SkSVGRenderContext(canvas, fIDMapper, lctx, pctx));
496     }
497 }
498 
intrinsicSize() const499 SkSize SkSVGDOM::intrinsicSize() const {
500     if (!fRoot || fRoot->tag() != SkSVGTag::kSvg) {
501         return SkSize::Make(0, 0);
502     }
503 
504     // Intrinsic sizes are never relative, so the viewport size is irrelevant.
505     const SkSVGLengthContext lctx(SkSize::Make(0, 0));
506     return static_cast<const SkSVGSVG*>(fRoot.get())->intrinsicSize(lctx);
507 }
508 
containerSize() const509 const SkSize& SkSVGDOM::containerSize() const {
510     return fContainerSize;
511 }
512 
setContainerSize(const SkSize & containerSize)513 void SkSVGDOM::setContainerSize(const SkSize& containerSize) {
514     // TODO: inval
515     fContainerSize = containerSize;
516 }
517 
setRoot(sk_sp<SkSVGNode> root)518 void SkSVGDOM::setRoot(sk_sp<SkSVGNode> root) {
519     fRoot = std::move(root);
520 }
521