blob: cea1ae69fe58136b6d09dbdfcbd06d8eccb4d0d9 [file] [log] [blame]
fmalita6ceef3d2016-07-26 18:46:34 -07001/*
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 "SkCanvas.h"
9#include "SkDOM.h"
fmalita6ceef3d2016-07-26 18:46:34 -070010#include "SkParsePath.h"
fmalita58649cc2016-07-29 08:52:03 -070011#include "SkString.h"
fmalitabffc2562016-08-03 10:21:11 -070012#include "SkSVGAttributeParser.h"
fmalitadc4c2a92016-08-16 15:38:51 -070013#include "SkSVGCircle.h"
Florin Malitace8840e2016-12-08 09:26:47 -050014#include "SkSVGClipPath.h"
fmalita28d5b722016-09-12 17:06:47 -070015#include "SkSVGDefs.h"
fmalita6ceef3d2016-07-26 18:46:34 -070016#include "SkSVGDOM.h"
fmalitadc4c2a92016-08-16 15:38:51 -070017#include "SkSVGEllipse.h"
fmalita6ceef3d2016-07-26 18:46:34 -070018#include "SkSVGG.h"
fmalitad24ee142016-08-17 08:38:15 -070019#include "SkSVGLine.h"
fmalita28d5b722016-09-12 17:06:47 -070020#include "SkSVGLinearGradient.h"
fmalita6ceef3d2016-07-26 18:46:34 -070021#include "SkSVGNode.h"
22#include "SkSVGPath.h"
fmalita5b31f322016-08-12 12:15:33 -070023#include "SkSVGPoly.h"
fmalitabffc2562016-08-03 10:21:11 -070024#include "SkSVGRect.h"
25#include "SkSVGRenderContext.h"
fmalita28d5b722016-09-12 17:06:47 -070026#include "SkSVGStop.h"
fmalita6ceef3d2016-07-26 18:46:34 -070027#include "SkSVGSVG.h"
fmalitabffc2562016-08-03 10:21:11 -070028#include "SkSVGTypes.h"
fmalita6ceef3d2016-07-26 18:46:34 -070029#include "SkSVGValue.h"
30#include "SkTSearch.h"
31
32namespace {
33
fmalita6ceef3d2016-07-26 18:46:34 -070034bool SetPaintAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
35 const char* stringValue) {
fmalita2d961e02016-08-11 09:16:29 -070036 SkSVGPaint paint;
fmalitabffc2562016-08-03 10:21:11 -070037 SkSVGAttributeParser parser(stringValue);
fmalita2d961e02016-08-11 09:16:29 -070038 if (!parser.parsePaint(&paint)) {
fmalita28d5b722016-09-12 17:06:47 -070039 return false;
fmalitabffc2562016-08-03 10:21:11 -070040 }
41
fmalita2d961e02016-08-11 09:16:29 -070042 node->setAttribute(attr, SkSVGPaintValue(paint));
fmalita6ceef3d2016-07-26 18:46:34 -070043 return true;
44}
45
fmalita28d5b722016-09-12 17:06:47 -070046bool SetColorAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
47 const char* stringValue) {
48 SkSVGColorType color;
49 SkSVGAttributeParser parser(stringValue);
50 if (!parser.parseColor(&color)) {
51 return false;
52 }
53
54 node->setAttribute(attr, SkSVGColorValue(color));
55 return true;
56}
57
58bool SetIRIAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
59 const char* stringValue) {
60 SkSVGStringType iri;
61 SkSVGAttributeParser parser(stringValue);
62 if (!parser.parseIRI(&iri)) {
63 return false;
64 }
65
66 node->setAttribute(attr, SkSVGStringValue(iri));
67 return true;
68}
69
Florin Malitace8840e2016-12-08 09:26:47 -050070bool SetClipPathAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
71 const char* stringValue) {
72 SkSVGClip clip;
73 SkSVGAttributeParser parser(stringValue);
74 if (!parser.parseClipPath(&clip)) {
75 return false;
76 }
77
78 node->setAttribute(attr, SkSVGClipValue(clip));
79 return true;
80}
81
82
fmalita6ceef3d2016-07-26 18:46:34 -070083bool SetPathDataAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
84 const char* stringValue) {
85 SkPath path;
86 if (!SkParsePath::FromSVGString(stringValue, &path)) {
87 return false;
88 }
89
90 node->setAttribute(attr, SkSVGPathValue(path));
91 return true;
92}
93
94bool SetTransformAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
95 const char* stringValue) {
fmalitac97796b2016-08-08 12:58:57 -070096 SkSVGTransformType transform;
97 SkSVGAttributeParser parser(stringValue);
98 if (!parser.parseTransform(&transform)) {
99 return false;
100 }
101
102 node->setAttribute(attr, SkSVGTransformValue(transform));
fmalita6ceef3d2016-07-26 18:46:34 -0700103 return true;
104}
105
fmalitabffc2562016-08-03 10:21:11 -0700106bool SetLengthAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
107 const char* stringValue) {
108 SkSVGLength length;
109 SkSVGAttributeParser parser(stringValue);
110 if (!parser.parseLength(&length)) {
111 return false;
112 }
113
114 node->setAttribute(attr, SkSVGLengthValue(length));
115 return true;
116}
117
fmalita2d961e02016-08-11 09:16:29 -0700118bool SetNumberAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
119 const char* stringValue) {
120 SkSVGNumberType number;
121 SkSVGAttributeParser parser(stringValue);
122 if (!parser.parseNumber(&number)) {
123 return false;
124 }
125
126 node->setAttribute(attr, SkSVGNumberValue(number));
127 return true;
128}
129
fmalita397a5172016-08-08 11:38:55 -0700130bool SetViewBoxAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
131 const char* stringValue) {
132 SkSVGViewBoxType viewBox;
133 SkSVGAttributeParser parser(stringValue);
134 if (!parser.parseViewBox(&viewBox)) {
135 return false;
136 }
137
138 node->setAttribute(attr, SkSVGViewBoxValue(viewBox));
139 return true;
140}
141
fmalita2d961e02016-08-11 09:16:29 -0700142bool SetLineCapAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
143 const char* stringValue) {
144 SkSVGLineCap lineCap;
145 SkSVGAttributeParser parser(stringValue);
146 if (!parser.parseLineCap(&lineCap)) {
147 return false;
148 }
149
150 node->setAttribute(attr, SkSVGLineCapValue(lineCap));
151 return true;
152}
153
154bool SetLineJoinAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
155 const char* stringValue) {
156 SkSVGLineJoin lineJoin;
157 SkSVGAttributeParser parser(stringValue);
158 if (!parser.parseLineJoin(&lineJoin)) {
159 return false;
160 }
161
162 node->setAttribute(attr, SkSVGLineJoinValue(lineJoin));
163 return true;
164}
165
fmalitacecd6172016-09-13 12:56:11 -0700166bool SetSpreadMethodAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
167 const char* stringValue) {
168 SkSVGSpreadMethod spread;
169 SkSVGAttributeParser parser(stringValue);
170 if (!parser.parseSpreadMethod(&spread)) {
171 return false;
172 }
173
174 node->setAttribute(attr, SkSVGSpreadMethodValue(spread));
175 return true;
176}
177
fmalita5b31f322016-08-12 12:15:33 -0700178bool SetPointsAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
179 const char* stringValue) {
180 SkSVGPointsType points;
181 SkSVGAttributeParser parser(stringValue);
182 if (!parser.parsePoints(&points)) {
183 return false;
184 }
185
186 node->setAttribute(attr, SkSVGPointsValue(points));
187 return true;
188}
189
Florin Malitae932d4b2016-12-01 13:35:11 -0500190bool SetFillRuleAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
191 const char* stringValue) {
192 SkSVGFillRule fillRule;
193 SkSVGAttributeParser parser(stringValue);
194 if (!parser.parseFillRule(&fillRule)) {
195 return false;
196 }
197
198 node->setAttribute(attr, SkSVGFillRuleValue(fillRule));
199 return true;
200}
201
fmalita61f36b32016-08-08 13:58:50 -0700202SkString TrimmedString(const char* first, const char* last) {
203 SkASSERT(first);
204 SkASSERT(last);
205 SkASSERT(first <= last);
206
207 while (first <= last && *first <= ' ') { first++; }
208 while (first <= last && *last <= ' ') { last--; }
209
210 SkASSERT(last - first + 1 >= 0);
211 return SkString(first, SkTo<size_t>(last - first + 1));
212}
213
fmalita58649cc2016-07-29 08:52:03 -0700214// Breaks a "foo: bar; baz: ..." string into key:value pairs.
215class StyleIterator {
216public:
217 StyleIterator(const char* str) : fPos(str) { }
218
219 std::tuple<SkString, SkString> next() {
220 SkString name, value;
221
222 if (fPos) {
223 const char* sep = this->nextSeparator();
224 SkASSERT(*sep == ';' || *sep == '\0');
225
226 const char* valueSep = strchr(fPos, ':');
227 if (valueSep && valueSep < sep) {
fmalita61f36b32016-08-08 13:58:50 -0700228 name = TrimmedString(fPos, valueSep - 1);
229 value = TrimmedString(valueSep + 1, sep - 1);
fmalita58649cc2016-07-29 08:52:03 -0700230 }
231
232 fPos = *sep ? sep + 1 : nullptr;
233 }
234
235 return std::make_tuple(name, value);
236 }
237
238private:
239 const char* nextSeparator() const {
240 const char* sep = fPos;
241 while (*sep != ';' && *sep != '\0') {
242 sep++;
243 }
244 return sep;
245 }
246
247 const char* fPos;
248};
249
250void set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value);
251
252bool SetStyleAttributes(const sk_sp<SkSVGNode>& node, SkSVGAttribute,
253 const char* stringValue) {
254
255 SkString name, value;
256 StyleIterator iter(stringValue);
257 for (;;) {
258 std::tie(name, value) = iter.next();
259 if (name.isEmpty()) {
260 break;
261 }
262 set_string_attribute(node, name.c_str(), value.c_str());
263 }
264
265 return true;
266}
267
fmalita6ceef3d2016-07-26 18:46:34 -0700268template<typename T>
269struct SortedDictionaryEntry {
270 const char* fKey;
271 const T fValue;
272};
273
274struct AttrParseInfo {
275 SkSVGAttribute fAttr;
276 bool (*fSetter)(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, const char* stringValue);
277};
278
279SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
Florin Malitace8840e2016-12-08 09:26:47 -0500280 { "clip-path" , { SkSVGAttribute::kClipPath , SetClipPathAttribute }},
fmalitaceb93ab2016-09-13 13:59:05 -0700281 { "cx" , { SkSVGAttribute::kCx , SetLengthAttribute }},
282 { "cy" , { SkSVGAttribute::kCy , SetLengthAttribute }},
283 { "d" , { SkSVGAttribute::kD , SetPathDataAttribute }},
284 { "fill" , { SkSVGAttribute::kFill , SetPaintAttribute }},
285 { "fill-opacity" , { SkSVGAttribute::kFillOpacity , SetNumberAttribute }},
Florin Malitae932d4b2016-12-01 13:35:11 -0500286 { "fill-rule" , { SkSVGAttribute::kFillRule , SetFillRuleAttribute }},
fmalitaceb93ab2016-09-13 13:59:05 -0700287 { "gradientTransform", { SkSVGAttribute::kGradientTransform, SetTransformAttribute }},
288 { "height" , { SkSVGAttribute::kHeight , SetLengthAttribute }},
289 { "offset" , { SkSVGAttribute::kOffset , SetLengthAttribute }},
290 { "opacity" , { SkSVGAttribute::kOpacity , SetNumberAttribute }},
291 { "points" , { SkSVGAttribute::kPoints , SetPointsAttribute }},
292 { "r" , { SkSVGAttribute::kR , SetLengthAttribute }},
293 { "rx" , { SkSVGAttribute::kRx , SetLengthAttribute }},
294 { "ry" , { SkSVGAttribute::kRy , SetLengthAttribute }},
295 { "spreadMethod" , { SkSVGAttribute::kSpreadMethod , SetSpreadMethodAttribute }},
296 { "stop-color" , { SkSVGAttribute::kStopColor , SetColorAttribute }},
297 { "stop-opacity" , { SkSVGAttribute::kStopOpacity , SetNumberAttribute }},
298 { "stroke" , { SkSVGAttribute::kStroke , SetPaintAttribute }},
299 { "stroke-linecap" , { SkSVGAttribute::kStrokeLineCap , SetLineCapAttribute }},
300 { "stroke-linejoin" , { SkSVGAttribute::kStrokeLineJoin , SetLineJoinAttribute }},
301 { "stroke-opacity" , { SkSVGAttribute::kStrokeOpacity , SetNumberAttribute }},
302 { "stroke-width" , { SkSVGAttribute::kStrokeWidth , SetLengthAttribute }},
303 { "style" , { SkSVGAttribute::kUnknown , SetStyleAttributes }},
304 { "transform" , { SkSVGAttribute::kTransform , SetTransformAttribute }},
305 { "viewBox" , { SkSVGAttribute::kViewBox , SetViewBoxAttribute }},
306 { "width" , { SkSVGAttribute::kWidth , SetLengthAttribute }},
307 { "x" , { SkSVGAttribute::kX , SetLengthAttribute }},
308 { "x1" , { SkSVGAttribute::kX1 , SetLengthAttribute }},
309 { "x2" , { SkSVGAttribute::kX2 , SetLengthAttribute }},
310 { "xlink:href" , { SkSVGAttribute::kHref , SetIRIAttribute }},
311 { "y" , { SkSVGAttribute::kY , SetLengthAttribute }},
312 { "y1" , { SkSVGAttribute::kY1 , SetLengthAttribute }},
313 { "y2" , { SkSVGAttribute::kY2 , SetLengthAttribute }},
fmalita6ceef3d2016-07-26 18:46:34 -0700314};
315
316SortedDictionaryEntry<sk_sp<SkSVGNode>(*)()> gTagFactories[] = {
fmalita28d5b722016-09-12 17:06:47 -0700317 { "circle" , []() -> sk_sp<SkSVGNode> { return SkSVGCircle::Make(); }},
Florin Malitace8840e2016-12-08 09:26:47 -0500318 { "clipPath" , []() -> sk_sp<SkSVGNode> { return SkSVGClipPath::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700319 { "defs" , []() -> sk_sp<SkSVGNode> { return SkSVGDefs::Make(); }},
320 { "ellipse" , []() -> sk_sp<SkSVGNode> { return SkSVGEllipse::Make(); }},
321 { "g" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
322 { "line" , []() -> sk_sp<SkSVGNode> { return SkSVGLine::Make(); }},
323 { "linearGradient", []() -> sk_sp<SkSVGNode> { return SkSVGLinearGradient::Make(); }},
324 { "path" , []() -> sk_sp<SkSVGNode> { return SkSVGPath::Make(); }},
325 { "polygon" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolygon(); }},
326 { "polyline" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolyline(); }},
327 { "rect" , []() -> sk_sp<SkSVGNode> { return SkSVGRect::Make(); }},
328 { "stop" , []() -> sk_sp<SkSVGNode> { return SkSVGStop::Make(); }},
329 { "svg" , []() -> sk_sp<SkSVGNode> { return SkSVGSVG::Make(); }},
fmalita6ceef3d2016-07-26 18:46:34 -0700330};
331
332struct ConstructionContext {
fmalita28d5b722016-09-12 17:06:47 -0700333 ConstructionContext(SkSVGIDMapper* mapper) : fParent(nullptr), fIDMapper(mapper) {}
fmalita6ceef3d2016-07-26 18:46:34 -0700334 ConstructionContext(const ConstructionContext& other, const sk_sp<SkSVGNode>& newParent)
fmalita28d5b722016-09-12 17:06:47 -0700335 : fParent(newParent.get()), fIDMapper(other.fIDMapper) {}
fmalita6ceef3d2016-07-26 18:46:34 -0700336
337 const SkSVGNode* fParent;
fmalita28d5b722016-09-12 17:06:47 -0700338 SkSVGIDMapper* fIDMapper;
fmalita6ceef3d2016-07-26 18:46:34 -0700339};
340
fmalita58649cc2016-07-29 08:52:03 -0700341void set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value) {
342 const int attrIndex = SkStrSearch(&gAttributeParseInfo[0].fKey,
343 SkTo<int>(SK_ARRAY_COUNT(gAttributeParseInfo)),
344 name, sizeof(gAttributeParseInfo[0]));
345 if (attrIndex < 0) {
fmalitafea704e2016-08-10 16:25:32 -0700346#if defined(SK_VERBOSE_SVG_PARSING)
fmalita58649cc2016-07-29 08:52:03 -0700347 SkDebugf("unhandled attribute: %s\n", name);
fmalitafea704e2016-08-10 16:25:32 -0700348#endif
fmalita58649cc2016-07-29 08:52:03 -0700349 return;
350 }
351
352 SkASSERT(SkTo<size_t>(attrIndex) < SK_ARRAY_COUNT(gAttributeParseInfo));
353 const auto& attrInfo = gAttributeParseInfo[attrIndex].fValue;
354 if (!attrInfo.fSetter(node, attrInfo.fAttr, value)) {
fmalitafea704e2016-08-10 16:25:32 -0700355#if defined(SK_VERBOSE_SVG_PARSING)
fmalita58649cc2016-07-29 08:52:03 -0700356 SkDebugf("could not parse attribute: '%s=\"%s\"'\n", name, value);
fmalitafea704e2016-08-10 16:25:32 -0700357#endif
fmalita58649cc2016-07-29 08:52:03 -0700358 }
359}
360
fmalita6ceef3d2016-07-26 18:46:34 -0700361void parse_node_attributes(const SkDOM& xmlDom, const SkDOM::Node* xmlNode,
fmalita28d5b722016-09-12 17:06:47 -0700362 const sk_sp<SkSVGNode>& svgNode, SkSVGIDMapper* mapper) {
fmalita6ceef3d2016-07-26 18:46:34 -0700363 const char* name, *value;
364 SkDOM::AttrIter attrIter(xmlDom, xmlNode);
365 while ((name = attrIter.next(&value))) {
fmalita28d5b722016-09-12 17:06:47 -0700366 // We're handling id attributes out of band for now.
367 if (!strcmp(name, "id")) {
368 mapper->set(SkString(value), svgNode);
369 continue;
370 }
fmalita58649cc2016-07-29 08:52:03 -0700371 set_string_attribute(svgNode, name, value);
fmalita6ceef3d2016-07-26 18:46:34 -0700372 }
373}
374
375sk_sp<SkSVGNode> construct_svg_node(const SkDOM& dom, const ConstructionContext& ctx,
376 const SkDOM::Node* xmlNode) {
377 const char* elem = dom.getName(xmlNode);
378 const SkDOM::Type elemType = dom.getType(xmlNode);
379
380 if (elemType == SkDOM::kText_Type) {
381 SkASSERT(dom.countChildren(xmlNode) == 0);
382 // TODO: text handling
383 return nullptr;
384 }
385
386 SkASSERT(elemType == SkDOM::kElement_Type);
387
388 const int tagIndex = SkStrSearch(&gTagFactories[0].fKey,
389 SkTo<int>(SK_ARRAY_COUNT(gTagFactories)),
390 elem, sizeof(gTagFactories[0]));
391 if (tagIndex < 0) {
fmalitafea704e2016-08-10 16:25:32 -0700392#if defined(SK_VERBOSE_SVG_PARSING)
fmalita6ceef3d2016-07-26 18:46:34 -0700393 SkDebugf("unhandled element: <%s>\n", elem);
fmalitafea704e2016-08-10 16:25:32 -0700394#endif
fmalita6ceef3d2016-07-26 18:46:34 -0700395 return nullptr;
396 }
397
398 SkASSERT(SkTo<size_t>(tagIndex) < SK_ARRAY_COUNT(gTagFactories));
399 sk_sp<SkSVGNode> node = gTagFactories[tagIndex].fValue();
fmalita28d5b722016-09-12 17:06:47 -0700400 parse_node_attributes(dom, xmlNode, node, ctx.fIDMapper);
fmalita6ceef3d2016-07-26 18:46:34 -0700401
402 ConstructionContext localCtx(ctx, node);
403 for (auto* child = dom.getFirstChild(xmlNode, nullptr); child;
404 child = dom.getNextSibling(child)) {
405 sk_sp<SkSVGNode> childNode = construct_svg_node(dom, localCtx, child);
406 if (childNode) {
407 node->appendChild(std::move(childNode));
408 }
409 }
410
411 return node;
412}
413
414} // anonymous namespace
415
fmalitae1baa7c2016-09-14 12:04:30 -0700416SkSVGDOM::SkSVGDOM()
417 : fContainerSize(SkSize::Make(0, 0)) {
fmalita6ceef3d2016-07-26 18:46:34 -0700418}
419
fmalitae1baa7c2016-09-14 12:04:30 -0700420sk_sp<SkSVGDOM> SkSVGDOM::MakeFromDOM(const SkDOM& xmlDom) {
421 sk_sp<SkSVGDOM> dom = sk_make_sp<SkSVGDOM>();
fmalita6ceef3d2016-07-26 18:46:34 -0700422
fmalita28d5b722016-09-12 17:06:47 -0700423 ConstructionContext ctx(&dom->fIDMapper);
fmalita6ceef3d2016-07-26 18:46:34 -0700424 dom->fRoot = construct_svg_node(xmlDom, ctx, xmlDom.getRootNode());
425
fmalitae1baa7c2016-09-14 12:04:30 -0700426 // Reset the default container size to match the intrinsic SVG size.
427 dom->setContainerSize(dom->intrinsicSize());
428
fmalita6ceef3d2016-07-26 18:46:34 -0700429 return dom;
430}
431
fmalitae1baa7c2016-09-14 12:04:30 -0700432sk_sp<SkSVGDOM> SkSVGDOM::MakeFromStream(SkStream& svgStream) {
fmalita6ceef3d2016-07-26 18:46:34 -0700433 SkDOM xmlDom;
434 if (!xmlDom.build(svgStream)) {
435 return nullptr;
436 }
437
fmalitae1baa7c2016-09-14 12:04:30 -0700438 return MakeFromDOM(xmlDom);
fmalita6ceef3d2016-07-26 18:46:34 -0700439}
440
441void SkSVGDOM::render(SkCanvas* canvas) const {
442 if (fRoot) {
fmalita397a5172016-08-08 11:38:55 -0700443 SkSVGRenderContext ctx(canvas,
fmalita28d5b722016-09-12 17:06:47 -0700444 fIDMapper,
fmalita397a5172016-08-08 11:38:55 -0700445 SkSVGLengthContext(fContainerSize),
446 SkSVGPresentationContext());
447 fRoot->render(ctx);
fmalita6ceef3d2016-07-26 18:46:34 -0700448 }
449}
450
fmalitae1baa7c2016-09-14 12:04:30 -0700451SkSize SkSVGDOM::intrinsicSize() const {
452 if (!fRoot || fRoot->tag() != SkSVGTag::kSvg) {
453 return SkSize::Make(0, 0);
454 }
455
456 // Intrinsic sizes are never relative, so the viewport size is irrelevant.
457 const SkSVGLengthContext lctx(SkSize::Make(0, 0));
458 return static_cast<const SkSVGSVG*>(fRoot.get())->intrinsicSize(lctx);
459}
460
461const SkSize& SkSVGDOM::containerSize() const {
462 return fContainerSize;
463}
464
fmalita6ceef3d2016-07-26 18:46:34 -0700465void SkSVGDOM::setContainerSize(const SkSize& containerSize) {
466 // TODO: inval
467 fContainerSize = containerSize;
468}
fmalitaca39d712016-08-12 13:17:11 -0700469
470void SkSVGDOM::setRoot(sk_sp<SkSVGNode> root) {
471 fRoot = std::move(root);
472}