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