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