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 "modules/svg/include/SkSVGXMLDOM.h"
56 #include "src/base/SkTSearch.h"
57 #include "src/core/SkTraceEvent.h"
58 #include "src/xml/SkDOM.h"
59
60 #include <stdint.h>
61 #include <array>
62 #include <cstring>
63 #include <tuple>
64 #include <utility>
65
66 namespace {
67
SetIRIAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)68 bool SetIRIAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
69 const char* stringValue) {
70 auto parseResult = SkSVGAttributeParser::parse<SkSVGIRI>(stringValue);
71 if (!parseResult.isValid()) {
72 return false;
73 }
74
75 node->setAttribute(attr, SkSVGStringValue(parseResult->iri()));
76 return true;
77 }
78
SetStringAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)79 bool SetStringAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
80 const char* stringValue) {
81 SkString str(stringValue, strlen(stringValue));
82 SkSVGStringType strType = SkSVGStringType(str);
83 node->setAttribute(attr, SkSVGStringValue(strType));
84 return true;
85 }
86
SetTransformAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)87 bool SetTransformAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
88 const char* stringValue) {
89 auto parseResult = SkSVGAttributeParser::parse<SkSVGTransformType>(stringValue);
90 if (!parseResult.isValid()) {
91 return false;
92 }
93
94 node->setAttribute(attr, SkSVGTransformValue(*parseResult));
95 return true;
96 }
97
SetLengthAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)98 bool SetLengthAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
99 const char* stringValue) {
100 auto parseResult = SkSVGAttributeParser::parse<SkSVGLength>(stringValue);
101 if (!parseResult.isValid()) {
102 return false;
103 }
104
105 node->setAttribute(attr, SkSVGLengthValue(*parseResult));
106 return true;
107 }
108
SetViewBoxAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)109 bool SetViewBoxAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
110 const char* stringValue) {
111 SkSVGViewBoxType viewBox;
112 SkSVGAttributeParser parser(stringValue);
113 if (!parser.parseViewBox(&viewBox)) {
114 return false;
115 }
116
117 node->setAttribute(attr, SkSVGViewBoxValue(viewBox));
118 return true;
119 }
120
SetObjectBoundingBoxUnitsAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)121 bool SetObjectBoundingBoxUnitsAttribute(const sk_sp<SkSVGNode>& node,
122 SkSVGAttribute attr,
123 const char* stringValue) {
124 auto parseResult = SkSVGAttributeParser::parse<SkSVGObjectBoundingBoxUnits>(stringValue);
125 if (!parseResult.isValid()) {
126 return false;
127 }
128
129 node->setAttribute(attr, SkSVGObjectBoundingBoxUnitsValue(*parseResult));
130 return true;
131 }
132
SetPreserveAspectRatioAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)133 bool SetPreserveAspectRatioAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
134 const char* stringValue) {
135 SkSVGPreserveAspectRatio par;
136 SkSVGAttributeParser parser(stringValue);
137 if (!parser.parsePreserveAspectRatio(&par)) {
138 return false;
139 }
140
141 node->setAttribute(attr, SkSVGPreserveAspectRatioValue(par));
142 return true;
143 }
144
TrimmedString(const char * first,const char * last)145 SkString TrimmedString(const char* first, const char* last) {
146 SkASSERT(first);
147 SkASSERT(last);
148 SkASSERT(first <= last);
149
150 while (first <= last && *first <= ' ') { first++; }
151 while (first <= last && *last <= ' ') { last--; }
152
153 SkASSERT(last - first + 1 >= 0);
154 return SkString(first, SkTo<size_t>(last - first + 1));
155 }
156
157 // Breaks a "foo: bar; baz: ..." string into key:value pairs.
158 class StyleIterator {
159 public:
StyleIterator(const char * str)160 StyleIterator(const char* str) : fPos(str) { }
161
next()162 std::tuple<SkString, SkString> next() {
163 SkString name, value;
164
165 if (fPos) {
166 const char* sep = this->nextSeparator();
167 SkASSERT(*sep == ';' || *sep == '\0');
168
169 const char* valueSep = strchr(fPos, ':');
170 if (valueSep && valueSep < sep) {
171 name = TrimmedString(fPos, valueSep - 1);
172 value = TrimmedString(valueSep + 1, sep - 1);
173 }
174
175 fPos = *sep ? sep + 1 : nullptr;
176 }
177
178 return std::make_tuple(name, value);
179 }
180
181 private:
nextSeparator() const182 const char* nextSeparator() const {
183 const char* sep = fPos;
184 while (*sep != ';' && *sep != '\0') {
185 sep++;
186 }
187 return sep;
188 }
189
190 const char* fPos;
191 };
192
193 bool set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value);
194
SetStyleAttributes(const sk_sp<SkSVGNode> & node,SkSVGAttribute,const char * stringValue)195 bool SetStyleAttributes(const sk_sp<SkSVGNode>& node, SkSVGAttribute,
196 const char* stringValue) {
197
198 SkString name, value;
199 StyleIterator iter(stringValue);
200 for (;;) {
201 std::tie(name, value) = iter.next();
202 if (name.isEmpty()) {
203 break;
204 }
205 set_string_attribute(node, name.c_str(), value.c_str());
206 }
207
208 return true;
209 }
210
211 template<typename T>
212 struct SortedDictionaryEntry {
213 const char* fKey;
214 const T fValue;
215 };
216
217 struct AttrParseInfo {
218 SkSVGAttribute fAttr;
219 bool (*fSetter)(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, const char* stringValue);
220 };
221
222 SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
223 { "cx" , { SkSVGAttribute::kCx , SetLengthAttribute }},
224 { "cy" , { SkSVGAttribute::kCy , SetLengthAttribute }},
225 { "filterUnits" , { SkSVGAttribute::kFilterUnits ,
226 SetObjectBoundingBoxUnitsAttribute }},
227 // focal point x & y
228 { "fx" , { SkSVGAttribute::kFx , SetLengthAttribute }},
229 { "fy" , { SkSVGAttribute::kFy , SetLengthAttribute }},
230 { "height" , { SkSVGAttribute::kHeight , SetLengthAttribute }},
231 { "preserveAspectRatio", { SkSVGAttribute::kPreserveAspectRatio,
232 SetPreserveAspectRatioAttribute }},
233 { "r" , { SkSVGAttribute::kR , SetLengthAttribute }},
234 { "rx" , { SkSVGAttribute::kRx , SetLengthAttribute }},
235 { "ry" , { SkSVGAttribute::kRy , SetLengthAttribute }},
236 { "style" , { SkSVGAttribute::kUnknown , SetStyleAttributes }},
237 { "text" , { SkSVGAttribute::kText , SetStringAttribute }},
238 { "transform" , { SkSVGAttribute::kTransform , SetTransformAttribute }},
239 { "viewBox" , { SkSVGAttribute::kViewBox , SetViewBoxAttribute }},
240 { "width" , { SkSVGAttribute::kWidth , SetLengthAttribute }},
241 { "x" , { SkSVGAttribute::kX , SetLengthAttribute }},
242 { "x1" , { SkSVGAttribute::kX1 , SetLengthAttribute }},
243 { "x2" , { SkSVGAttribute::kX2 , SetLengthAttribute }},
244 { "xlink:href" , { SkSVGAttribute::kHref , SetIRIAttribute }},
245 { "y" , { SkSVGAttribute::kY , SetLengthAttribute }},
246 { "y1" , { SkSVGAttribute::kY1 , SetLengthAttribute }},
247 { "y2" , { SkSVGAttribute::kY2 , SetLengthAttribute }},
248 };
249
250 SortedDictionaryEntry<sk_sp<SkSVGNode>(*)()> gTagFactories[] = {
__anon345a53eb0202() 251 { "a" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
__anon345a53eb0302() 252 { "circle" , []() -> sk_sp<SkSVGNode> { return SkSVGCircle::Make(); }},
__anon345a53eb0402() 253 { "clipPath" , []() -> sk_sp<SkSVGNode> { return SkSVGClipPath::Make(); }},
__anon345a53eb0502() 254 { "defs" , []() -> sk_sp<SkSVGNode> { return SkSVGDefs::Make(); }},
__anon345a53eb0602() 255 { "ellipse" , []() -> sk_sp<SkSVGNode> { return SkSVGEllipse::Make(); }},
__anon345a53eb0702() 256 { "feBlend" , []() -> sk_sp<SkSVGNode> { return SkSVGFeBlend::Make(); }},
__anon345a53eb0802() 257 { "feColorMatrix" , []() -> sk_sp<SkSVGNode> { return SkSVGFeColorMatrix::Make(); }},
__anon345a53eb0902() 258 { "feComponentTransfer", []() -> sk_sp<SkSVGNode> { return SkSVGFeComponentTransfer::Make(); }},
__anon345a53eb0a02() 259 { "feComposite" , []() -> sk_sp<SkSVGNode> { return SkSVGFeComposite::Make(); }},
__anon345a53eb0b02() 260 { "feDiffuseLighting" , []() -> sk_sp<SkSVGNode> { return SkSVGFeDiffuseLighting::Make(); }},
__anon345a53eb0c02() 261 { "feDisplacementMap" , []() -> sk_sp<SkSVGNode> { return SkSVGFeDisplacementMap::Make(); }},
__anon345a53eb0d02() 262 { "feDistantLight" , []() -> sk_sp<SkSVGNode> { return SkSVGFeDistantLight::Make(); }},
__anon345a53eb0e02() 263 { "feFlood" , []() -> sk_sp<SkSVGNode> { return SkSVGFeFlood::Make(); }},
__anon345a53eb0f02() 264 { "feFuncA" , []() -> sk_sp<SkSVGNode> { return SkSVGFeFunc::MakeFuncA(); }},
__anon345a53eb1002() 265 { "feFuncB" , []() -> sk_sp<SkSVGNode> { return SkSVGFeFunc::MakeFuncB(); }},
__anon345a53eb1102() 266 { "feFuncG" , []() -> sk_sp<SkSVGNode> { return SkSVGFeFunc::MakeFuncG(); }},
__anon345a53eb1202() 267 { "feFuncR" , []() -> sk_sp<SkSVGNode> { return SkSVGFeFunc::MakeFuncR(); }},
__anon345a53eb1302() 268 { "feGaussianBlur" , []() -> sk_sp<SkSVGNode> { return SkSVGFeGaussianBlur::Make(); }},
__anon345a53eb1402() 269 { "feImage" , []() -> sk_sp<SkSVGNode> { return SkSVGFeImage::Make(); }},
__anon345a53eb1502() 270 { "feMerge" , []() -> sk_sp<SkSVGNode> { return SkSVGFeMerge::Make(); }},
__anon345a53eb1602() 271 { "feMergeNode" , []() -> sk_sp<SkSVGNode> { return SkSVGFeMergeNode::Make(); }},
__anon345a53eb1702() 272 { "feMorphology" , []() -> sk_sp<SkSVGNode> { return SkSVGFeMorphology::Make(); }},
__anon345a53eb1802() 273 { "feOffset" , []() -> sk_sp<SkSVGNode> { return SkSVGFeOffset::Make(); }},
__anon345a53eb1902() 274 { "fePointLight" , []() -> sk_sp<SkSVGNode> { return SkSVGFePointLight::Make(); }},
__anon345a53eb1a02() 275 { "feSpecularLighting" , []() -> sk_sp<SkSVGNode> { return SkSVGFeSpecularLighting::Make(); }},
__anon345a53eb1b02() 276 { "feSpotLight" , []() -> sk_sp<SkSVGNode> { return SkSVGFeSpotLight::Make(); }},
__anon345a53eb1c02() 277 { "feTurbulence" , []() -> sk_sp<SkSVGNode> { return SkSVGFeTurbulence::Make(); }},
__anon345a53eb1d02() 278 { "filter" , []() -> sk_sp<SkSVGNode> { return SkSVGFilter::Make(); }},
__anon345a53eb1e02() 279 { "g" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
__anon345a53eb1f02() 280 { "image" , []() -> sk_sp<SkSVGNode> { return SkSVGImage::Make(); }},
__anon345a53eb2002() 281 { "line" , []() -> sk_sp<SkSVGNode> { return SkSVGLine::Make(); }},
__anon345a53eb2102() 282 { "linearGradient" , []() -> sk_sp<SkSVGNode> { return SkSVGLinearGradient::Make(); }},
__anon345a53eb2202() 283 { "mask" , []() -> sk_sp<SkSVGNode> { return SkSVGMask::Make(); }},
__anon345a53eb2302() 284 { "path" , []() -> sk_sp<SkSVGNode> { return SkSVGPath::Make(); }},
__anon345a53eb2402() 285 { "pattern" , []() -> sk_sp<SkSVGNode> { return SkSVGPattern::Make(); }},
__anon345a53eb2502() 286 { "polygon" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolygon(); }},
__anon345a53eb2602() 287 { "polyline" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolyline(); }},
__anon345a53eb2702() 288 { "radialGradient" , []() -> sk_sp<SkSVGNode> { return SkSVGRadialGradient::Make(); }},
__anon345a53eb2802() 289 { "rect" , []() -> sk_sp<SkSVGNode> { return SkSVGRect::Make(); }},
__anon345a53eb2902() 290 { "stop" , []() -> sk_sp<SkSVGNode> { return SkSVGStop::Make(); }},
291 // "svg" handled explicitly
__anon345a53eb2a02() 292 { "text" , []() -> sk_sp<SkSVGNode> { return SkSVGText::Make(); }},
__anon345a53eb2b02() 293 { "textPath" , []() -> sk_sp<SkSVGNode> { return SkSVGTextPath::Make(); }},
__anon345a53eb2c02() 294 { "tspan" , []() -> sk_sp<SkSVGNode> { return SkSVGTSpan::Make(); }},
__anon345a53eb2d02() 295 { "use" , []() -> sk_sp<SkSVGNode> { return SkSVGUse::Make(); }},
296 };
297
298 struct ConstructionContext {
ConstructionContext__anon345a53eb0111::ConstructionContext299 ConstructionContext(SkSVGIDMapper* mapper) : fParent(nullptr), fIDMapper(mapper) {}
ConstructionContext__anon345a53eb0111::ConstructionContext300 ConstructionContext(const ConstructionContext& other, const sk_sp<SkSVGNode>& newParent)
301 : fParent(newParent.get()), fIDMapper(other.fIDMapper) {}
302
303 SkSVGNode* fParent;
304 SkSVGIDMapper* fIDMapper;
305 };
306
set_string_attribute(const sk_sp<SkSVGNode> & node,const char * name,const char * value)307 bool set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value) {
308 if (node->parseAndSetAttribute(name, value)) {
309 // Handled by new code path
310 return true;
311 }
312
313 const int attrIndex = SkStrSearch(&gAttributeParseInfo[0].fKey,
314 SkTo<int>(std::size(gAttributeParseInfo)),
315 name, sizeof(gAttributeParseInfo[0]));
316 if (attrIndex < 0) {
317 #if defined(SK_VERBOSE_SVG_PARSING)
318 SkDebugf("unhandled attribute: %s\n", name);
319 #endif
320 return false;
321 }
322
323 SkASSERT(SkTo<size_t>(attrIndex) < std::size(gAttributeParseInfo));
324 const auto& attrInfo = gAttributeParseInfo[attrIndex].fValue;
325 if (!attrInfo.fSetter(node, attrInfo.fAttr, value)) {
326 #if defined(SK_VERBOSE_SVG_PARSING)
327 SkDebugf("could not parse attribute: '%s=\"%s\"'\n", name, value);
328 #endif
329 return false;
330 }
331
332 return true;
333 }
334
parse_node_attributes(const SkDOM & xmlDom,const SkDOM::Node * xmlNode,const sk_sp<SkSVGNode> & svgNode,SkSVGIDMapper * mapper)335 void parse_node_attributes(const SkDOM& xmlDom, const SkDOM::Node* xmlNode,
336 const sk_sp<SkSVGNode>& svgNode, SkSVGIDMapper* mapper) {
337 const char* name, *value;
338 SkDOM::AttrIter attrIter(xmlDom, xmlNode);
339 while ((name = attrIter.next(&value))) {
340 // We're handling id attributes out of band for now.
341 if (!strcmp(name, "id")) {
342 mapper->set(SkString(value), svgNode);
343 continue;
344 }
345 set_string_attribute(svgNode, name, value);
346 }
347 }
348
construct_svg_node(const SkDOM & dom,const ConstructionContext & ctx,const SkDOM::Node * xmlNode)349 sk_sp<SkSVGNode> construct_svg_node(const SkDOM& dom, const ConstructionContext& ctx,
350 const SkDOM::Node* xmlNode) {
351 const char* elem = dom.getName(xmlNode);
352 const SkDOM::Type elemType = dom.getType(xmlNode);
353
354 if (elemType == SkDOM::kText_Type) {
355 // Text literals require special handling.
356 SkASSERT(dom.countChildren(xmlNode) == 0);
357 auto txt = SkSVGTextLiteral::Make();
358 txt->setText(SkString(dom.getName(xmlNode)));
359 ctx.fParent->appendChild(std::move(txt));
360
361 return nullptr;
362 }
363
364 SkASSERT(elemType == SkDOM::kElement_Type);
365
366 auto make_node = [](const ConstructionContext& ctx, const char* elem) -> sk_sp<SkSVGNode> {
367 if (strcmp(elem, "svg") == 0) {
368 // Outermost SVG element must be tagged as such.
369 return SkSVGSVG::Make(ctx.fParent ? SkSVGSVG::Type::kInner
370 : SkSVGSVG::Type::kRoot);
371 }
372
373 const int tagIndex = SkStrSearch(&gTagFactories[0].fKey,
374 SkTo<int>(std::size(gTagFactories)),
375 elem, sizeof(gTagFactories[0]));
376 if (tagIndex < 0) {
377 #if defined(SK_VERBOSE_SVG_PARSING)
378 SkDebugf("unhandled element: <%s>\n", elem);
379 #endif
380 return nullptr;
381 }
382 SkASSERT(SkTo<size_t>(tagIndex) < std::size(gTagFactories));
383
384 return gTagFactories[tagIndex].fValue();
385 };
386
387 auto node = make_node(ctx, elem);
388 if (!node) {
389 return nullptr;
390 }
391
392 parse_node_attributes(dom, xmlNode, node, ctx.fIDMapper);
393
394 ConstructionContext localCtx(ctx, node);
395 for (auto* child = dom.getFirstChild(xmlNode, nullptr); child;
396 child = dom.getNextSibling(child)) {
397 sk_sp<SkSVGNode> childNode = construct_svg_node(dom, localCtx, child);
398 if (childNode) {
399 node->appendChild(std::move(childNode));
400 }
401 }
402
403 return node;
404 }
405
406 } // anonymous namespace
407
setFontManager(sk_sp<SkFontMgr> fmgr)408 SkSVGDOM::Builder& SkSVGDOM::Builder::setFontManager(sk_sp<SkFontMgr> fmgr) {
409 fFontMgr = std::move(fmgr);
410 return *this;
411 }
412
setResourceProvider(sk_sp<skresources::ResourceProvider> rp)413 SkSVGDOM::Builder& SkSVGDOM::Builder::setResourceProvider(sk_sp<skresources::ResourceProvider> rp) {
414 fResourceProvider = std::move(rp);
415 return *this;
416 }
417
setTextShapingFactory(sk_sp<SkShapers::Factory> f)418 SkSVGDOM::Builder& SkSVGDOM::Builder::setTextShapingFactory(sk_sp<SkShapers::Factory> f) {
419 fTextShapingFactory = f;
420 return *this;
421 }
422
make(SkStream & str) const423 sk_sp<SkSVGDOM> SkSVGDOM::Builder::make(SkStream& str) const {
424 TRACE_EVENT0("skia", TRACE_FUNC);
425 SkSVGXMLDOM xmlDom;
426 if (!xmlDom.build(str)) {
427 return nullptr;
428 }
429
430 SkSVGIDMapper mapper;
431 ConstructionContext ctx(&mapper);
432
433 auto root = construct_svg_node(xmlDom, ctx, xmlDom.getRootNode());
434 if (!root || root->tag() != SkSVGTag::kSvg) {
435 return nullptr;
436 }
437
438 class NullResourceProvider final : public skresources::ResourceProvider {
439 sk_sp<SkData> load(const char[], const char[]) const override { return nullptr; }
440 };
441
442 auto resource_provider = fResourceProvider ? fResourceProvider
443 : sk_make_sp<NullResourceProvider>();
444
445 auto factory = fTextShapingFactory ? fTextShapingFactory : SkShapers::Primitive::Factory();
446
447 return sk_sp<SkSVGDOM>(new SkSVGDOM(sk_sp<SkSVGSVG>(static_cast<SkSVGSVG*>(root.release())),
448 std::move(fFontMgr),
449 std::move(resource_provider),
450 std::move(mapper),
451 std::move(factory)));
452 }
453
454
make(SkStream & str,uint64_t svgColor) const455 sk_sp<SkSVGDOM> SkSVGDOM::Builder::make(SkStream& str, uint64_t svgColor) const {
456 TRACE_EVENT0("skia", TRACE_FUNC);
457 SkSVGXMLDOM xmlDom;
458 if (!xmlDom.build(str, svgColor)) {
459 return nullptr;
460 }
461
462 SkSVGIDMapper mapper;
463 ConstructionContext ctx(&mapper);
464
465 auto root = construct_svg_node(xmlDom, ctx, xmlDom.getRootNode());
466 if (!root || root->tag() != SkSVGTag::kSvg) {
467 return nullptr;
468 }
469
470 class NullResourceProvider final : public skresources::ResourceProvider {
471 sk_sp<SkData> load(const char[], const char[]) const override { return nullptr; }
472 };
473
474 auto resource_provider = fResourceProvider ? fResourceProvider
475 : sk_make_sp<NullResourceProvider>();
476
477 auto factory = fTextShapingFactory ? fTextShapingFactory : SkShapers::Primitive::Factory();
478
479 return sk_sp<SkSVGDOM>(new SkSVGDOM(sk_sp<SkSVGSVG>(static_cast<SkSVGSVG*>(root.release())),
480 std::move(fFontMgr),
481 std::move(resource_provider),
482 std::move(mapper),
483 std::move(factory)));
484 }
485
SkSVGDOM(sk_sp<SkSVGSVG> root,sk_sp<SkFontMgr> fmgr,sk_sp<skresources::ResourceProvider> rp,SkSVGIDMapper && mapper,sk_sp<SkShapers::Factory> fact)486 SkSVGDOM::SkSVGDOM(sk_sp<SkSVGSVG> root,
487 sk_sp<SkFontMgr> fmgr,
488 sk_sp<skresources::ResourceProvider> rp,
489 SkSVGIDMapper&& mapper,
490 sk_sp<SkShapers::Factory> fact)
491 : fRoot(std::move(root))
492 , fFontMgr(std::move(fmgr))
493 , fTextShapingFactory(std::move(fact))
494 , fResourceProvider(std::move(rp))
495 , fIDMapper(std::move(mapper))
496 , fSVGResizePercentage(DEFAULT_RESIZE_PERCENTAGE)
497 , fContainerSize(fRoot->intrinsicSize(SkSVGLengthContext(SkSize::Make(0, 0)))) {
498 SkASSERT(fResourceProvider);
499 SkASSERT(fTextShapingFactory);
500 }
501
render(SkCanvas * canvas) const502 void SkSVGDOM::render(SkCanvas* canvas) const {
503 TRACE_EVENT0("skia", TRACE_FUNC);
504 if (fRoot) {
505 SkSVGLengthContext lctx(fContainerSize, fSVGResizePercentage);
506 SkSVGPresentationContext pctx;
507 fRoot->render(SkSVGRenderContext(canvas,
508 fFontMgr,
509 fResourceProvider,
510 fIDMapper,
511 lctx,
512 pctx,
513 {nullptr, nullptr},
514 fTextShapingFactory));
515 }
516 }
517
renderNode(SkCanvas * canvas,SkSVGPresentationContext & pctx,const char * id) const518 void SkSVGDOM::renderNode(SkCanvas* canvas, SkSVGPresentationContext& pctx, const char* id) const {
519 TRACE_EVENT0("skia", TRACE_FUNC);
520
521 if (fRoot) {
522 SkSVGLengthContext lctx(fContainerSize);
523 fRoot->renderNode(SkSVGRenderContext(canvas,
524 fFontMgr,
525 fResourceProvider,
526 fIDMapper,
527 lctx,
528 pctx,
529 {nullptr, nullptr},
530 fTextShapingFactory),
531 SkSVGIRI(SkSVGIRI::Type::kLocal, SkSVGStringType(id)));
532 }
533 }
534
setResizePercentage(float resizePercentage)535 void SkSVGDOM::setResizePercentage(float resizePercentage)
536 {
537 fSVGResizePercentage *= resizePercentage / DEFAULT_RESIZE_PERCENTAGE;
538 fContainerSize.fWidth *= fSVGResizePercentage / DEFAULT_RESIZE_PERCENTAGE;
539 fContainerSize.fHeight *= fSVGResizePercentage / DEFAULT_RESIZE_PERCENTAGE;
540 }
541
containerSize() const542 const SkSize& SkSVGDOM::containerSize() const {
543 return fContainerSize;
544 }
545
setContainerSize(const SkSize & containerSize)546 void SkSVGDOM::setContainerSize(const SkSize& containerSize) {
547 // TODO: inval
548 fContainerSize = containerSize;
549 }
550
findNodeById(const char * id)551 sk_sp<SkSVGNode>* SkSVGDOM::findNodeById(const char* id) {
552 SkString idStr(id);
553 return this->fIDMapper.find(idStr);
554 }
555
556 // TODO(fuego): move this to SkSVGNode or its own CU.
setAttribute(const char * attributeName,const char * attributeValue)557 bool SkSVGNode::setAttribute(const char* attributeName, const char* attributeValue) {
558 return set_string_attribute(sk_ref_sp(this), attributeName, attributeValue);
559 }
560