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