xref: /aosp_15_r20/external/skia/modules/svg/src/SkSVGDOM.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 "modules/svg/include/SkSVGDOM.h"
9 
10 #include "include/core/SkData.h"
11 #include "include/core/SkFontMgr.h"
12 #include "include/core/SkString.h"
13 #include "include/private/base/SkAssert.h"
14 #include "include/private/base/SkTo.h"
15 #include "modules/skshaper/include/SkShaper_factory.h"
16 #include "modules/svg/include/SkSVGAttribute.h"
17 #include "modules/svg/include/SkSVGAttributeParser.h"
18 #include "modules/svg/include/SkSVGCircle.h"
19 #include "modules/svg/include/SkSVGClipPath.h"
20 #include "modules/svg/include/SkSVGDefs.h"
21 #include "modules/svg/include/SkSVGEllipse.h"
22 #include "modules/svg/include/SkSVGFeBlend.h"
23 #include "modules/svg/include/SkSVGFeColorMatrix.h"
24 #include "modules/svg/include/SkSVGFeComponentTransfer.h"
25 #include "modules/svg/include/SkSVGFeComposite.h"
26 #include "modules/svg/include/SkSVGFeDisplacementMap.h"
27 #include "modules/svg/include/SkSVGFeFlood.h"
28 #include "modules/svg/include/SkSVGFeGaussianBlur.h"
29 #include "modules/svg/include/SkSVGFeImage.h"
30 #include "modules/svg/include/SkSVGFeLightSource.h"
31 #include "modules/svg/include/SkSVGFeLighting.h"
32 #include "modules/svg/include/SkSVGFeMerge.h"
33 #include "modules/svg/include/SkSVGFeMorphology.h"
34 #include "modules/svg/include/SkSVGFeOffset.h"
35 #include "modules/svg/include/SkSVGFeTurbulence.h"
36 #include "modules/svg/include/SkSVGFilter.h"
37 #include "modules/svg/include/SkSVGG.h"
38 #include "modules/svg/include/SkSVGImage.h"
39 #include "modules/svg/include/SkSVGLine.h"
40 #include "modules/svg/include/SkSVGLinearGradient.h"
41 #include "modules/svg/include/SkSVGMask.h"
42 #include "modules/svg/include/SkSVGNode.h"
43 #include "modules/svg/include/SkSVGPath.h"
44 #include "modules/svg/include/SkSVGPattern.h"
45 #include "modules/svg/include/SkSVGPoly.h"
46 #include "modules/svg/include/SkSVGRadialGradient.h"
47 #include "modules/svg/include/SkSVGRect.h"
48 #include "modules/svg/include/SkSVGRenderContext.h"
49 #include "modules/svg/include/SkSVGSVG.h"
50 #include "modules/svg/include/SkSVGStop.h"
51 #include "modules/svg/include/SkSVGText.h"
52 #include "modules/svg/include/SkSVGTypes.h"
53 #include "modules/svg/include/SkSVGUse.h"
54 #include "modules/svg/include/SkSVGValue.h"
55 #include "src/base/SkTSearch.h"
56 #include "src/core/SkTraceEvent.h"
57 #include "src/xml/SkDOM.h"
58 
59 #include <stdint.h>
60 #include <array>
61 #include <cstring>
62 #include <tuple>
63 #include <utility>
64 
65 namespace {
66 
SetIRIAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)67 bool SetIRIAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
68                       const char* stringValue) {
69     auto parseResult = SkSVGAttributeParser::parse<SkSVGIRI>(stringValue);
70     if (!parseResult.isValid()) {
71         return false;
72     }
73 
74     node->setAttribute(attr, SkSVGStringValue(parseResult->iri()));
75     return true;
76 }
77 
SetStringAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)78 bool SetStringAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
79                            const char* stringValue) {
80     SkString str(stringValue, strlen(stringValue));
81     SkSVGStringType strType = SkSVGStringType(str);
82     node->setAttribute(attr, SkSVGStringValue(strType));
83     return true;
84 }
85 
SetTransformAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)86 bool SetTransformAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
87                            const char* stringValue) {
88     auto parseResult = SkSVGAttributeParser::parse<SkSVGTransformType>(stringValue);
89     if (!parseResult.isValid()) {
90         return false;
91     }
92 
93     node->setAttribute(attr, SkSVGTransformValue(*parseResult));
94     return true;
95 }
96 
SetLengthAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)97 bool SetLengthAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
98                         const char* stringValue) {
99     auto parseResult = SkSVGAttributeParser::parse<SkSVGLength>(stringValue);
100     if (!parseResult.isValid()) {
101         return false;
102     }
103 
104     node->setAttribute(attr, SkSVGLengthValue(*parseResult));
105     return true;
106 }
107 
SetViewBoxAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)108 bool SetViewBoxAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
109                          const char* stringValue) {
110     SkSVGViewBoxType viewBox;
111     SkSVGAttributeParser parser(stringValue);
112     if (!parser.parseViewBox(&viewBox)) {
113         return false;
114     }
115 
116     node->setAttribute(attr, SkSVGViewBoxValue(viewBox));
117     return true;
118 }
119 
SetObjectBoundingBoxUnitsAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)120 bool SetObjectBoundingBoxUnitsAttribute(const sk_sp<SkSVGNode>& node,
121                                         SkSVGAttribute attr,
122                                         const char* stringValue) {
123     auto parseResult = SkSVGAttributeParser::parse<SkSVGObjectBoundingBoxUnits>(stringValue);
124     if (!parseResult.isValid()) {
125         return false;
126     }
127 
128     node->setAttribute(attr, SkSVGObjectBoundingBoxUnitsValue(*parseResult));
129     return true;
130 }
131 
SetPreserveAspectRatioAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)132 bool SetPreserveAspectRatioAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
133                                      const char* stringValue) {
134     SkSVGPreserveAspectRatio par;
135     SkSVGAttributeParser parser(stringValue);
136     if (!parser.parsePreserveAspectRatio(&par)) {
137         return false;
138     }
139 
140     node->setAttribute(attr, SkSVGPreserveAspectRatioValue(par));
141     return true;
142 }
143 
TrimmedString(const char * first,const char * last)144 SkString TrimmedString(const char* first, const char* last) {
145     SkASSERT(first);
146     SkASSERT(last);
147     SkASSERT(first <= last);
148 
149     while (first <= last && *first <= ' ') { first++; }
150     while (first <= last && *last  <= ' ') { last--; }
151 
152     SkASSERT(last - first + 1 >= 0);
153     return SkString(first, SkTo<size_t>(last - first + 1));
154 }
155 
156 // Breaks a "foo: bar; baz: ..." string into key:value pairs.
157 class StyleIterator {
158 public:
StyleIterator(const char * str)159     StyleIterator(const char* str) : fPos(str) { }
160 
next()161     std::tuple<SkString, SkString> next() {
162         SkString name, value;
163 
164         if (fPos) {
165             const char* sep = this->nextSeparator();
166             SkASSERT(*sep == ';' || *sep == '\0');
167 
168             const char* valueSep = strchr(fPos, ':');
169             if (valueSep && valueSep < sep) {
170                 name  = TrimmedString(fPos, valueSep - 1);
171                 value = TrimmedString(valueSep + 1, sep - 1);
172             }
173 
174             fPos = *sep ? sep + 1 : nullptr;
175         }
176 
177         return std::make_tuple(name, value);
178     }
179 
180 private:
nextSeparator() const181     const char* nextSeparator() const {
182         const char* sep = fPos;
183         while (*sep != ';' && *sep != '\0') {
184             sep++;
185         }
186         return sep;
187     }
188 
189     const char* fPos;
190 };
191 
192 bool set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value);
193 
SetStyleAttributes(const sk_sp<SkSVGNode> & node,SkSVGAttribute,const char * stringValue)194 bool SetStyleAttributes(const sk_sp<SkSVGNode>& node, SkSVGAttribute,
195                         const char* stringValue) {
196 
197     SkString name, value;
198     StyleIterator iter(stringValue);
199     for (;;) {
200         std::tie(name, value) = iter.next();
201         if (name.isEmpty()) {
202             break;
203         }
204         set_string_attribute(node, name.c_str(), value.c_str());
205     }
206 
207     return true;
208 }
209 
210 template<typename T>
211 struct SortedDictionaryEntry {
212     const char* fKey;
213     const T     fValue;
214 };
215 
216 struct AttrParseInfo {
217     SkSVGAttribute fAttr;
218     bool (*fSetter)(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, const char* stringValue);
219 };
220 
221 SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
222     { "cx"                 , { SkSVGAttribute::kCx               , SetLengthAttribute       }},
223     { "cy"                 , { SkSVGAttribute::kCy               , SetLengthAttribute       }},
224     { "filterUnits"        , { SkSVGAttribute::kFilterUnits      ,
225                                SetObjectBoundingBoxUnitsAttribute }},
226     // focal point x & y
227     { "fx"                 , { SkSVGAttribute::kFx               , SetLengthAttribute       }},
228     { "fy"                 , { SkSVGAttribute::kFy               , SetLengthAttribute       }},
229     { "height"             , { SkSVGAttribute::kHeight           , SetLengthAttribute       }},
230     { "preserveAspectRatio", { SkSVGAttribute::kPreserveAspectRatio,
231                                SetPreserveAspectRatioAttribute }},
232     { "r"                  , { SkSVGAttribute::kR                , SetLengthAttribute       }},
233     { "rx"                 , { SkSVGAttribute::kRx               , SetLengthAttribute       }},
234     { "ry"                 , { SkSVGAttribute::kRy               , SetLengthAttribute       }},
235     { "style"              , { SkSVGAttribute::kUnknown          , SetStyleAttributes       }},
236     { "text"               , { SkSVGAttribute::kText             , SetStringAttribute       }},
237     { "transform"          , { SkSVGAttribute::kTransform        , SetTransformAttribute    }},
238     { "viewBox"            , { SkSVGAttribute::kViewBox          , SetViewBoxAttribute      }},
239     { "width"              , { SkSVGAttribute::kWidth            , SetLengthAttribute       }},
240     { "x"                  , { SkSVGAttribute::kX                , SetLengthAttribute       }},
241     { "x1"                 , { SkSVGAttribute::kX1               , SetLengthAttribute       }},
242     { "x2"                 , { SkSVGAttribute::kX2               , SetLengthAttribute       }},
243     { "xlink:href"         , { SkSVGAttribute::kHref             , SetIRIAttribute          }},
244     { "y"                  , { SkSVGAttribute::kY                , SetLengthAttribute       }},
245     { "y1"                 , { SkSVGAttribute::kY1               , SetLengthAttribute       }},
246     { "y2"                 , { SkSVGAttribute::kY2               , SetLengthAttribute       }},
247 };
248 
249 SortedDictionaryEntry<sk_sp<SkSVGNode>(*)()> gTagFactories[] = {
__anonfb798c1b0202() 250     { "a"                  , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make();                   }},
__anonfb798c1b0302() 251     { "circle"             , []() -> sk_sp<SkSVGNode> { return SkSVGCircle::Make();              }},
__anonfb798c1b0402() 252     { "clipPath"           , []() -> sk_sp<SkSVGNode> { return SkSVGClipPath::Make();            }},
__anonfb798c1b0502() 253     { "defs"               , []() -> sk_sp<SkSVGNode> { return SkSVGDefs::Make();                }},
__anonfb798c1b0602() 254     { "ellipse"            , []() -> sk_sp<SkSVGNode> { return SkSVGEllipse::Make();             }},
__anonfb798c1b0702() 255     { "feBlend"            , []() -> sk_sp<SkSVGNode> { return SkSVGFeBlend::Make();             }},
__anonfb798c1b0802() 256     { "feColorMatrix"      , []() -> sk_sp<SkSVGNode> { return SkSVGFeColorMatrix::Make();       }},
__anonfb798c1b0902() 257     { "feComponentTransfer", []() -> sk_sp<SkSVGNode> { return SkSVGFeComponentTransfer::Make(); }},
__anonfb798c1b0a02() 258     { "feComposite"        , []() -> sk_sp<SkSVGNode> { return SkSVGFeComposite::Make();         }},
__anonfb798c1b0b02() 259     { "feDiffuseLighting"  , []() -> sk_sp<SkSVGNode> { return SkSVGFeDiffuseLighting::Make();   }},
__anonfb798c1b0c02() 260     { "feDisplacementMap"  , []() -> sk_sp<SkSVGNode> { return SkSVGFeDisplacementMap::Make();   }},
__anonfb798c1b0d02() 261     { "feDistantLight"     , []() -> sk_sp<SkSVGNode> { return SkSVGFeDistantLight::Make();      }},
__anonfb798c1b0e02() 262     { "feFlood"            , []() -> sk_sp<SkSVGNode> { return SkSVGFeFlood::Make();             }},
__anonfb798c1b0f02() 263     { "feFuncA"            , []() -> sk_sp<SkSVGNode> { return SkSVGFeFunc::MakeFuncA();         }},
__anonfb798c1b1002() 264     { "feFuncB"            , []() -> sk_sp<SkSVGNode> { return SkSVGFeFunc::MakeFuncB();         }},
__anonfb798c1b1102() 265     { "feFuncG"            , []() -> sk_sp<SkSVGNode> { return SkSVGFeFunc::MakeFuncG();         }},
__anonfb798c1b1202() 266     { "feFuncR"            , []() -> sk_sp<SkSVGNode> { return SkSVGFeFunc::MakeFuncR();         }},
__anonfb798c1b1302() 267     { "feGaussianBlur"     , []() -> sk_sp<SkSVGNode> { return SkSVGFeGaussianBlur::Make();      }},
__anonfb798c1b1402() 268     { "feImage"            , []() -> sk_sp<SkSVGNode> { return SkSVGFeImage::Make();             }},
__anonfb798c1b1502() 269     { "feMerge"            , []() -> sk_sp<SkSVGNode> { return SkSVGFeMerge::Make();             }},
__anonfb798c1b1602() 270     { "feMergeNode"        , []() -> sk_sp<SkSVGNode> { return SkSVGFeMergeNode::Make();         }},
__anonfb798c1b1702() 271     { "feMorphology"       , []() -> sk_sp<SkSVGNode> { return SkSVGFeMorphology::Make();        }},
__anonfb798c1b1802() 272     { "feOffset"           , []() -> sk_sp<SkSVGNode> { return SkSVGFeOffset::Make();            }},
__anonfb798c1b1902() 273     { "fePointLight"       , []() -> sk_sp<SkSVGNode> { return SkSVGFePointLight::Make();        }},
__anonfb798c1b1a02() 274     { "feSpecularLighting" , []() -> sk_sp<SkSVGNode> { return SkSVGFeSpecularLighting::Make();  }},
__anonfb798c1b1b02() 275     { "feSpotLight"        , []() -> sk_sp<SkSVGNode> { return SkSVGFeSpotLight::Make();         }},
__anonfb798c1b1c02() 276     { "feTurbulence"       , []() -> sk_sp<SkSVGNode> { return SkSVGFeTurbulence::Make();        }},
__anonfb798c1b1d02() 277     { "filter"             , []() -> sk_sp<SkSVGNode> { return SkSVGFilter::Make();              }},
__anonfb798c1b1e02() 278     { "g"                  , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make();                   }},
__anonfb798c1b1f02() 279     { "image"              , []() -> sk_sp<SkSVGNode> { return SkSVGImage::Make();               }},
__anonfb798c1b2002() 280     { "line"               , []() -> sk_sp<SkSVGNode> { return SkSVGLine::Make();                }},
__anonfb798c1b2102() 281     { "linearGradient"     , []() -> sk_sp<SkSVGNode> { return SkSVGLinearGradient::Make();      }},
__anonfb798c1b2202() 282     { "mask"               , []() -> sk_sp<SkSVGNode> { return SkSVGMask::Make();                }},
__anonfb798c1b2302() 283     { "path"               , []() -> sk_sp<SkSVGNode> { return SkSVGPath::Make();                }},
__anonfb798c1b2402() 284     { "pattern"            , []() -> sk_sp<SkSVGNode> { return SkSVGPattern::Make();             }},
__anonfb798c1b2502() 285     { "polygon"            , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolygon();         }},
__anonfb798c1b2602() 286     { "polyline"           , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolyline();        }},
__anonfb798c1b2702() 287     { "radialGradient"     , []() -> sk_sp<SkSVGNode> { return SkSVGRadialGradient::Make();      }},
__anonfb798c1b2802() 288     { "rect"               , []() -> sk_sp<SkSVGNode> { return SkSVGRect::Make();                }},
__anonfb798c1b2902() 289     { "stop"               , []() -> sk_sp<SkSVGNode> { return SkSVGStop::Make();                }},
290 //    "svg" handled explicitly
__anonfb798c1b2a02() 291     { "text"               , []() -> sk_sp<SkSVGNode> { return SkSVGText::Make();                }},
__anonfb798c1b2b02() 292     { "textPath"           , []() -> sk_sp<SkSVGNode> { return SkSVGTextPath::Make();            }},
__anonfb798c1b2c02() 293     { "tspan"              , []() -> sk_sp<SkSVGNode> { return SkSVGTSpan::Make();               }},
__anonfb798c1b2d02() 294     { "use"                , []() -> sk_sp<SkSVGNode> { return SkSVGUse::Make();                 }},
295 };
296 
297 struct ConstructionContext {
ConstructionContext__anonfb798c1b0111::ConstructionContext298     ConstructionContext(SkSVGIDMapper* mapper) : fParent(nullptr), fIDMapper(mapper) {}
ConstructionContext__anonfb798c1b0111::ConstructionContext299     ConstructionContext(const ConstructionContext& other, const sk_sp<SkSVGNode>& newParent)
300         : fParent(newParent.get()), fIDMapper(other.fIDMapper) {}
301 
302     SkSVGNode*     fParent;
303     SkSVGIDMapper* fIDMapper;
304 };
305 
set_string_attribute(const sk_sp<SkSVGNode> & node,const char * name,const char * value)306 bool set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value) {
307     if (node->parseAndSetAttribute(name, value)) {
308         // Handled by new code path
309         return true;
310     }
311 
312     const int attrIndex = SkStrSearch(&gAttributeParseInfo[0].fKey,
313                                       SkTo<int>(std::size(gAttributeParseInfo)),
314                                       name, sizeof(gAttributeParseInfo[0]));
315     if (attrIndex < 0) {
316 #if defined(SK_VERBOSE_SVG_PARSING)
317         SkDebugf("unhandled attribute: %s\n", name);
318 #endif
319         return false;
320     }
321 
322     SkASSERT(SkTo<size_t>(attrIndex) < std::size(gAttributeParseInfo));
323     const auto& attrInfo = gAttributeParseInfo[attrIndex].fValue;
324     if (!attrInfo.fSetter(node, attrInfo.fAttr, value)) {
325 #if defined(SK_VERBOSE_SVG_PARSING)
326         SkDebugf("could not parse attribute: '%s=\"%s\"'\n", name, value);
327 #endif
328         return false;
329     }
330 
331     return true;
332 }
333 
parse_node_attributes(const SkDOM & xmlDom,const SkDOM::Node * xmlNode,const sk_sp<SkSVGNode> & svgNode,SkSVGIDMapper * mapper)334 void parse_node_attributes(const SkDOM& xmlDom, const SkDOM::Node* xmlNode,
335                            const sk_sp<SkSVGNode>& svgNode, SkSVGIDMapper* mapper) {
336     const char* name, *value;
337     SkDOM::AttrIter attrIter(xmlDom, xmlNode);
338     while ((name = attrIter.next(&value))) {
339         // We're handling id attributes out of band for now.
340         if (!strcmp(name, "id")) {
341             mapper->set(SkString(value), svgNode);
342             continue;
343         }
344         set_string_attribute(svgNode, name, value);
345     }
346 }
347 
construct_svg_node(const SkDOM & dom,const ConstructionContext & ctx,const SkDOM::Node * xmlNode)348 sk_sp<SkSVGNode> construct_svg_node(const SkDOM& dom, const ConstructionContext& ctx,
349                                     const SkDOM::Node* xmlNode) {
350     const char* elem = dom.getName(xmlNode);
351     const SkDOM::Type elemType = dom.getType(xmlNode);
352 
353     if (elemType == SkDOM::kText_Type) {
354         // Text literals require special handling.
355         SkASSERT(dom.countChildren(xmlNode) == 0);
356         auto txt = SkSVGTextLiteral::Make();
357         txt->setText(SkString(dom.getName(xmlNode)));
358         ctx.fParent->appendChild(std::move(txt));
359 
360         return nullptr;
361     }
362 
363     SkASSERT(elemType == SkDOM::kElement_Type);
364 
365     auto make_node = [](const ConstructionContext& ctx, const char* elem) -> sk_sp<SkSVGNode> {
366         if (strcmp(elem, "svg") == 0) {
367             // Outermost SVG element must be tagged as such.
368             return SkSVGSVG::Make(ctx.fParent ? SkSVGSVG::Type::kInner
369                                               : SkSVGSVG::Type::kRoot);
370         }
371 
372         const int tagIndex = SkStrSearch(&gTagFactories[0].fKey,
373                                          SkTo<int>(std::size(gTagFactories)),
374                                          elem, sizeof(gTagFactories[0]));
375         if (tagIndex < 0) {
376 #if defined(SK_VERBOSE_SVG_PARSING)
377             SkDebugf("unhandled element: <%s>\n", elem);
378 #endif
379             return nullptr;
380         }
381         SkASSERT(SkTo<size_t>(tagIndex) < std::size(gTagFactories));
382 
383         return gTagFactories[tagIndex].fValue();
384     };
385 
386     auto node = make_node(ctx, elem);
387     if (!node) {
388         return nullptr;
389     }
390 
391     parse_node_attributes(dom, xmlNode, node, ctx.fIDMapper);
392 
393     ConstructionContext localCtx(ctx, node);
394     for (auto* child = dom.getFirstChild(xmlNode, nullptr); child;
395          child = dom.getNextSibling(child)) {
396         sk_sp<SkSVGNode> childNode = construct_svg_node(dom, localCtx, child);
397         if (childNode) {
398             node->appendChild(std::move(childNode));
399         }
400     }
401 
402     return node;
403 }
404 
405 } // anonymous namespace
406 
setFontManager(sk_sp<SkFontMgr> fmgr)407 SkSVGDOM::Builder& SkSVGDOM::Builder::setFontManager(sk_sp<SkFontMgr> fmgr) {
408     fFontMgr = std::move(fmgr);
409     return *this;
410 }
411 
setResourceProvider(sk_sp<skresources::ResourceProvider> rp)412 SkSVGDOM::Builder& SkSVGDOM::Builder::setResourceProvider(sk_sp<skresources::ResourceProvider> rp) {
413     fResourceProvider = std::move(rp);
414     return *this;
415 }
416 
setTextShapingFactory(sk_sp<SkShapers::Factory> f)417 SkSVGDOM::Builder& SkSVGDOM::Builder::setTextShapingFactory(sk_sp<SkShapers::Factory> f) {
418     fTextShapingFactory = f;
419     return *this;
420 }
421 
make(SkStream & str) const422 sk_sp<SkSVGDOM> SkSVGDOM::Builder::make(SkStream& str) const {
423     TRACE_EVENT0("skia", TRACE_FUNC);
424     SkDOM xmlDom;
425     if (!xmlDom.build(str)) {
426         return nullptr;
427     }
428 
429     SkSVGIDMapper mapper;
430     ConstructionContext ctx(&mapper);
431 
432     auto root = construct_svg_node(xmlDom, ctx, xmlDom.getRootNode());
433     if (!root || root->tag() != SkSVGTag::kSvg) {
434         return nullptr;
435     }
436 
437     class NullResourceProvider final : public skresources::ResourceProvider {
438         sk_sp<SkData> load(const char[], const char[]) const override { return nullptr; }
439     };
440 
441     auto resource_provider = fResourceProvider ? fResourceProvider
442                                                : sk_make_sp<NullResourceProvider>();
443 
444     auto factory = fTextShapingFactory ? fTextShapingFactory : SkShapers::Primitive::Factory();
445 
446     return sk_sp<SkSVGDOM>(new SkSVGDOM(sk_sp<SkSVGSVG>(static_cast<SkSVGSVG*>(root.release())),
447                                         std::move(fFontMgr),
448                                         std::move(resource_provider),
449                                         std::move(mapper),
450                                         std::move(factory)));
451 }
452 
SkSVGDOM(sk_sp<SkSVGSVG> root,sk_sp<SkFontMgr> fmgr,sk_sp<skresources::ResourceProvider> rp,SkSVGIDMapper && mapper,sk_sp<SkShapers::Factory> fact)453 SkSVGDOM::SkSVGDOM(sk_sp<SkSVGSVG> root,
454                    sk_sp<SkFontMgr> fmgr,
455                    sk_sp<skresources::ResourceProvider> rp,
456                    SkSVGIDMapper&& mapper,
457                    sk_sp<SkShapers::Factory> fact)
458         : fRoot(std::move(root))
459         , fFontMgr(std::move(fmgr))
460         , fTextShapingFactory(std::move(fact))
461         , fResourceProvider(std::move(rp))
462         , fIDMapper(std::move(mapper))
463         , fContainerSize(fRoot->intrinsicSize(SkSVGLengthContext(SkSize::Make(0, 0)))) {
464     SkASSERT(fResourceProvider);
465     SkASSERT(fTextShapingFactory);
466 }
467 
render(SkCanvas * canvas) const468 void SkSVGDOM::render(SkCanvas* canvas) const {
469     TRACE_EVENT0("skia", TRACE_FUNC);
470     if (fRoot) {
471         SkSVGLengthContext       lctx(fContainerSize);
472         SkSVGPresentationContext pctx;
473         fRoot->render(SkSVGRenderContext(canvas,
474                                          fFontMgr,
475                                          fResourceProvider,
476                                          fIDMapper,
477                                          lctx,
478                                          pctx,
479                                          {nullptr, nullptr},
480                                          fTextShapingFactory));
481     }
482 }
483 
renderNode(SkCanvas * canvas,SkSVGPresentationContext & pctx,const char * id) const484 void SkSVGDOM::renderNode(SkCanvas* canvas, SkSVGPresentationContext& pctx, const char* id) const {
485     TRACE_EVENT0("skia", TRACE_FUNC);
486 
487     if (fRoot) {
488         SkSVGLengthContext lctx(fContainerSize);
489         fRoot->renderNode(SkSVGRenderContext(canvas,
490                                              fFontMgr,
491                                              fResourceProvider,
492                                              fIDMapper,
493                                              lctx,
494                                              pctx,
495                                              {nullptr, nullptr},
496                                              fTextShapingFactory),
497                           SkSVGIRI(SkSVGIRI::Type::kLocal, SkSVGStringType(id)));
498     }
499 }
500 
containerSize() const501 const SkSize& SkSVGDOM::containerSize() const {
502     return fContainerSize;
503 }
504 
setContainerSize(const SkSize & containerSize)505 void SkSVGDOM::setContainerSize(const SkSize& containerSize) {
506     // TODO: inval
507     fContainerSize = containerSize;
508 }
509 
findNodeById(const char * id)510 sk_sp<SkSVGNode>* SkSVGDOM::findNodeById(const char* id) {
511     SkString idStr(id);
512     return this->fIDMapper.find(idStr);
513 }
514 
515 // TODO(fuego): move this to SkSVGNode or its own CU.
setAttribute(const char * attributeName,const char * attributeValue)516 bool SkSVGNode::setAttribute(const char* attributeName, const char* attributeValue) {
517     return set_string_attribute(sk_ref_sp(this), attributeName, attributeValue);
518 }
519