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