blob: 5b4dc6626fe5222cf5fa47e750dd47b47453ebb8 [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"
Florin Malita1aa1bb62017-10-11 14:34:33 -040023#include "SkSVGPattern.h"
fmalita5b31f322016-08-12 12:15:33 -070024#include "SkSVGPoly.h"
Florin Malitacc6cc292017-10-09 16:05:30 -040025#include "SkSVGRadialGradient.h"
fmalitabffc2562016-08-03 10:21:11 -070026#include "SkSVGRect.h"
27#include "SkSVGRenderContext.h"
fmalita28d5b722016-09-12 17:06:47 -070028#include "SkSVGStop.h"
fmalita6ceef3d2016-07-26 18:46:34 -070029#include "SkSVGSVG.h"
fmalitabffc2562016-08-03 10:21:11 -070030#include "SkSVGTypes.h"
Florin Malita6a69c052017-10-11 14:02:11 -040031#include "SkSVGUse.h"
fmalita6ceef3d2016-07-26 18:46:34 -070032#include "SkSVGValue.h"
33#include "SkTSearch.h"
34
35namespace {
36
fmalita6ceef3d2016-07-26 18:46:34 -070037bool SetPaintAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
38 const char* stringValue) {
fmalita2d961e02016-08-11 09:16:29 -070039 SkSVGPaint paint;
fmalitabffc2562016-08-03 10:21:11 -070040 SkSVGAttributeParser parser(stringValue);
fmalita2d961e02016-08-11 09:16:29 -070041 if (!parser.parsePaint(&paint)) {
fmalita28d5b722016-09-12 17:06:47 -070042 return false;
fmalitabffc2562016-08-03 10:21:11 -070043 }
44
fmalita2d961e02016-08-11 09:16:29 -070045 node->setAttribute(attr, SkSVGPaintValue(paint));
fmalita6ceef3d2016-07-26 18:46:34 -070046 return true;
47}
48
fmalita28d5b722016-09-12 17:06:47 -070049bool SetColorAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
50 const char* stringValue) {
51 SkSVGColorType color;
52 SkSVGAttributeParser parser(stringValue);
53 if (!parser.parseColor(&color)) {
54 return false;
55 }
56
57 node->setAttribute(attr, SkSVGColorValue(color));
58 return true;
59}
60
61bool SetIRIAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
62 const char* stringValue) {
63 SkSVGStringType iri;
64 SkSVGAttributeParser parser(stringValue);
65 if (!parser.parseIRI(&iri)) {
66 return false;
67 }
68
69 node->setAttribute(attr, SkSVGStringValue(iri));
70 return true;
71}
72
Florin Malitace8840e2016-12-08 09:26:47 -050073bool SetClipPathAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
74 const char* stringValue) {
75 SkSVGClip clip;
76 SkSVGAttributeParser parser(stringValue);
77 if (!parser.parseClipPath(&clip)) {
78 return false;
79 }
80
81 node->setAttribute(attr, SkSVGClipValue(clip));
82 return true;
83}
84
85
fmalita6ceef3d2016-07-26 18:46:34 -070086bool SetPathDataAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
87 const char* stringValue) {
88 SkPath path;
89 if (!SkParsePath::FromSVGString(stringValue, &path)) {
90 return false;
91 }
92
93 node->setAttribute(attr, SkSVGPathValue(path));
94 return true;
95}
96
97bool SetTransformAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
98 const char* stringValue) {
fmalitac97796b2016-08-08 12:58:57 -070099 SkSVGTransformType transform;
100 SkSVGAttributeParser parser(stringValue);
101 if (!parser.parseTransform(&transform)) {
102 return false;
103 }
104
105 node->setAttribute(attr, SkSVGTransformValue(transform));
fmalita6ceef3d2016-07-26 18:46:34 -0700106 return true;
107}
108
fmalitabffc2562016-08-03 10:21:11 -0700109bool SetLengthAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
110 const char* stringValue) {
111 SkSVGLength length;
112 SkSVGAttributeParser parser(stringValue);
113 if (!parser.parseLength(&length)) {
114 return false;
115 }
116
117 node->setAttribute(attr, SkSVGLengthValue(length));
118 return true;
119}
120
fmalita2d961e02016-08-11 09:16:29 -0700121bool SetNumberAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
122 const char* stringValue) {
123 SkSVGNumberType number;
124 SkSVGAttributeParser parser(stringValue);
125 if (!parser.parseNumber(&number)) {
126 return false;
127 }
128
129 node->setAttribute(attr, SkSVGNumberValue(number));
130 return true;
131}
132
fmalita397a5172016-08-08 11:38:55 -0700133bool SetViewBoxAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
134 const char* stringValue) {
135 SkSVGViewBoxType viewBox;
136 SkSVGAttributeParser parser(stringValue);
137 if (!parser.parseViewBox(&viewBox)) {
138 return false;
139 }
140
141 node->setAttribute(attr, SkSVGViewBoxValue(viewBox));
142 return true;
143}
144
fmalita2d961e02016-08-11 09:16:29 -0700145bool SetLineCapAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
146 const char* stringValue) {
147 SkSVGLineCap lineCap;
148 SkSVGAttributeParser parser(stringValue);
149 if (!parser.parseLineCap(&lineCap)) {
150 return false;
151 }
152
153 node->setAttribute(attr, SkSVGLineCapValue(lineCap));
154 return true;
155}
156
157bool SetLineJoinAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
158 const char* stringValue) {
159 SkSVGLineJoin lineJoin;
160 SkSVGAttributeParser parser(stringValue);
161 if (!parser.parseLineJoin(&lineJoin)) {
162 return false;
163 }
164
165 node->setAttribute(attr, SkSVGLineJoinValue(lineJoin));
166 return true;
167}
168
fmalitacecd6172016-09-13 12:56:11 -0700169bool SetSpreadMethodAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
170 const char* stringValue) {
171 SkSVGSpreadMethod spread;
172 SkSVGAttributeParser parser(stringValue);
173 if (!parser.parseSpreadMethod(&spread)) {
174 return false;
175 }
176
177 node->setAttribute(attr, SkSVGSpreadMethodValue(spread));
178 return true;
179}
180
fmalita5b31f322016-08-12 12:15:33 -0700181bool SetPointsAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
182 const char* stringValue) {
183 SkSVGPointsType points;
184 SkSVGAttributeParser parser(stringValue);
185 if (!parser.parsePoints(&points)) {
186 return false;
187 }
188
189 node->setAttribute(attr, SkSVGPointsValue(points));
190 return true;
191}
192
Florin Malitae932d4b2016-12-01 13:35:11 -0500193bool SetFillRuleAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
194 const char* stringValue) {
195 SkSVGFillRule fillRule;
196 SkSVGAttributeParser parser(stringValue);
197 if (!parser.parseFillRule(&fillRule)) {
198 return false;
199 }
200
201 node->setAttribute(attr, SkSVGFillRuleValue(fillRule));
202 return true;
203}
204
Florin Malitaffe6ae42017-10-12 11:33:28 -0400205bool SetVisibilityAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
206 const char* stringValue) {
207 SkSVGVisibility visibility;
208 SkSVGAttributeParser parser(stringValue);
209 if (!parser.parseVisibility(&visibility)) {
210 return false;
211 }
212
213 node->setAttribute(attr, SkSVGVisibilityValue(visibility));
214 return true;
215}
216
Florin Malitaf543a602017-10-13 14:07:44 -0400217bool SetDashArrayAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
218 const char* stringValue) {
219 SkSVGDashArray dashArray;
220 SkSVGAttributeParser parser(stringValue);
221 if (!parser.parseDashArray(&dashArray)) {
222 return false;
223 }
224
225 node->setAttribute(attr, SkSVGDashArrayValue(dashArray));
226 return true;
227}
228
fmalita61f36b32016-08-08 13:58:50 -0700229SkString TrimmedString(const char* first, const char* last) {
230 SkASSERT(first);
231 SkASSERT(last);
232 SkASSERT(first <= last);
233
234 while (first <= last && *first <= ' ') { first++; }
235 while (first <= last && *last <= ' ') { last--; }
236
237 SkASSERT(last - first + 1 >= 0);
238 return SkString(first, SkTo<size_t>(last - first + 1));
239}
240
fmalita58649cc2016-07-29 08:52:03 -0700241// Breaks a "foo: bar; baz: ..." string into key:value pairs.
242class StyleIterator {
243public:
244 StyleIterator(const char* str) : fPos(str) { }
245
246 std::tuple<SkString, SkString> next() {
247 SkString name, value;
248
249 if (fPos) {
250 const char* sep = this->nextSeparator();
251 SkASSERT(*sep == ';' || *sep == '\0');
252
253 const char* valueSep = strchr(fPos, ':');
254 if (valueSep && valueSep < sep) {
fmalita61f36b32016-08-08 13:58:50 -0700255 name = TrimmedString(fPos, valueSep - 1);
256 value = TrimmedString(valueSep + 1, sep - 1);
fmalita58649cc2016-07-29 08:52:03 -0700257 }
258
259 fPos = *sep ? sep + 1 : nullptr;
260 }
261
262 return std::make_tuple(name, value);
263 }
264
265private:
266 const char* nextSeparator() const {
267 const char* sep = fPos;
268 while (*sep != ';' && *sep != '\0') {
269 sep++;
270 }
271 return sep;
272 }
273
274 const char* fPos;
275};
276
277void set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value);
278
279bool SetStyleAttributes(const sk_sp<SkSVGNode>& node, SkSVGAttribute,
280 const char* stringValue) {
281
282 SkString name, value;
283 StyleIterator iter(stringValue);
284 for (;;) {
285 std::tie(name, value) = iter.next();
286 if (name.isEmpty()) {
287 break;
288 }
289 set_string_attribute(node, name.c_str(), value.c_str());
290 }
291
292 return true;
293}
294
fmalita6ceef3d2016-07-26 18:46:34 -0700295template<typename T>
296struct SortedDictionaryEntry {
297 const char* fKey;
298 const T fValue;
299};
300
301struct AttrParseInfo {
302 SkSVGAttribute fAttr;
303 bool (*fSetter)(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, const char* stringValue);
304};
305
306SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
Florin Malitace8840e2016-12-08 09:26:47 -0500307 { "clip-path" , { SkSVGAttribute::kClipPath , SetClipPathAttribute }},
Florin Malita57a0edf2017-10-10 11:22:08 -0400308 { "clip-rule" , { SkSVGAttribute::kClipRule , SetFillRuleAttribute }},
fmalitaceb93ab2016-09-13 13:59:05 -0700309 { "cx" , { SkSVGAttribute::kCx , SetLengthAttribute }},
310 { "cy" , { SkSVGAttribute::kCy , SetLengthAttribute }},
311 { "d" , { SkSVGAttribute::kD , SetPathDataAttribute }},
312 { "fill" , { SkSVGAttribute::kFill , SetPaintAttribute }},
313 { "fill-opacity" , { SkSVGAttribute::kFillOpacity , SetNumberAttribute }},
Florin Malitae932d4b2016-12-01 13:35:11 -0500314 { "fill-rule" , { SkSVGAttribute::kFillRule , SetFillRuleAttribute }},
Florin Malitacc6cc292017-10-09 16:05:30 -0400315 // focal point x & y
316 { "fx" , { SkSVGAttribute::kFx , SetLengthAttribute }},
317 { "fy" , { SkSVGAttribute::kFy , SetLengthAttribute }},
fmalitaceb93ab2016-09-13 13:59:05 -0700318 { "gradientTransform", { SkSVGAttribute::kGradientTransform, SetTransformAttribute }},
319 { "height" , { SkSVGAttribute::kHeight , SetLengthAttribute }},
320 { "offset" , { SkSVGAttribute::kOffset , SetLengthAttribute }},
321 { "opacity" , { SkSVGAttribute::kOpacity , SetNumberAttribute }},
Florin Malita1aa1bb62017-10-11 14:34:33 -0400322 { "patternTransform" , { SkSVGAttribute::kPatternTransform , SetTransformAttribute }},
fmalitaceb93ab2016-09-13 13:59:05 -0700323 { "points" , { SkSVGAttribute::kPoints , SetPointsAttribute }},
324 { "r" , { SkSVGAttribute::kR , SetLengthAttribute }},
325 { "rx" , { SkSVGAttribute::kRx , SetLengthAttribute }},
326 { "ry" , { SkSVGAttribute::kRy , SetLengthAttribute }},
327 { "spreadMethod" , { SkSVGAttribute::kSpreadMethod , SetSpreadMethodAttribute }},
328 { "stop-color" , { SkSVGAttribute::kStopColor , SetColorAttribute }},
329 { "stop-opacity" , { SkSVGAttribute::kStopOpacity , SetNumberAttribute }},
330 { "stroke" , { SkSVGAttribute::kStroke , SetPaintAttribute }},
Florin Malitaf543a602017-10-13 14:07:44 -0400331 { "stroke-dasharray" , { SkSVGAttribute::kStrokeDashArray , SetDashArrayAttribute }},
Florin Malitae1dadd72017-10-13 18:18:32 -0400332 { "stroke-dashoffset", { SkSVGAttribute::kStrokeDashOffset , SetLengthAttribute }},
fmalitaceb93ab2016-09-13 13:59:05 -0700333 { "stroke-linecap" , { SkSVGAttribute::kStrokeLineCap , SetLineCapAttribute }},
334 { "stroke-linejoin" , { SkSVGAttribute::kStrokeLineJoin , SetLineJoinAttribute }},
Florin Malita4de426b2017-10-09 12:57:41 -0400335 { "stroke-miterlimit", { SkSVGAttribute::kStrokeMiterLimit , SetNumberAttribute }},
fmalitaceb93ab2016-09-13 13:59:05 -0700336 { "stroke-opacity" , { SkSVGAttribute::kStrokeOpacity , SetNumberAttribute }},
337 { "stroke-width" , { SkSVGAttribute::kStrokeWidth , SetLengthAttribute }},
338 { "style" , { SkSVGAttribute::kUnknown , SetStyleAttributes }},
339 { "transform" , { SkSVGAttribute::kTransform , SetTransformAttribute }},
340 { "viewBox" , { SkSVGAttribute::kViewBox , SetViewBoxAttribute }},
Florin Malitaffe6ae42017-10-12 11:33:28 -0400341 { "visibility" , { SkSVGAttribute::kVisibility , SetVisibilityAttribute }},
fmalitaceb93ab2016-09-13 13:59:05 -0700342 { "width" , { SkSVGAttribute::kWidth , SetLengthAttribute }},
343 { "x" , { SkSVGAttribute::kX , SetLengthAttribute }},
344 { "x1" , { SkSVGAttribute::kX1 , SetLengthAttribute }},
345 { "x2" , { SkSVGAttribute::kX2 , SetLengthAttribute }},
346 { "xlink:href" , { SkSVGAttribute::kHref , SetIRIAttribute }},
347 { "y" , { SkSVGAttribute::kY , SetLengthAttribute }},
348 { "y1" , { SkSVGAttribute::kY1 , SetLengthAttribute }},
349 { "y2" , { SkSVGAttribute::kY2 , SetLengthAttribute }},
fmalita6ceef3d2016-07-26 18:46:34 -0700350};
351
352SortedDictionaryEntry<sk_sp<SkSVGNode>(*)()> gTagFactories[] = {
Florin Malitaf6143ff2017-10-10 09:16:52 -0400353 { "a" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700354 { "circle" , []() -> sk_sp<SkSVGNode> { return SkSVGCircle::Make(); }},
Florin Malitace8840e2016-12-08 09:26:47 -0500355 { "clipPath" , []() -> sk_sp<SkSVGNode> { return SkSVGClipPath::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700356 { "defs" , []() -> sk_sp<SkSVGNode> { return SkSVGDefs::Make(); }},
357 { "ellipse" , []() -> sk_sp<SkSVGNode> { return SkSVGEllipse::Make(); }},
358 { "g" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
359 { "line" , []() -> sk_sp<SkSVGNode> { return SkSVGLine::Make(); }},
360 { "linearGradient", []() -> sk_sp<SkSVGNode> { return SkSVGLinearGradient::Make(); }},
361 { "path" , []() -> sk_sp<SkSVGNode> { return SkSVGPath::Make(); }},
Florin Malita1aa1bb62017-10-11 14:34:33 -0400362 { "pattern" , []() -> sk_sp<SkSVGNode> { return SkSVGPattern::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700363 { "polygon" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolygon(); }},
364 { "polyline" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolyline(); }},
Florin Malitacc6cc292017-10-09 16:05:30 -0400365 { "radialGradient", []() -> sk_sp<SkSVGNode> { return SkSVGRadialGradient::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700366 { "rect" , []() -> sk_sp<SkSVGNode> { return SkSVGRect::Make(); }},
367 { "stop" , []() -> sk_sp<SkSVGNode> { return SkSVGStop::Make(); }},
368 { "svg" , []() -> sk_sp<SkSVGNode> { return SkSVGSVG::Make(); }},
Florin Malita6a69c052017-10-11 14:02:11 -0400369 { "use" , []() -> sk_sp<SkSVGNode> { return SkSVGUse::Make(); }},
fmalita6ceef3d2016-07-26 18:46:34 -0700370};
371
372struct ConstructionContext {
fmalita28d5b722016-09-12 17:06:47 -0700373 ConstructionContext(SkSVGIDMapper* mapper) : fParent(nullptr), fIDMapper(mapper) {}
fmalita6ceef3d2016-07-26 18:46:34 -0700374 ConstructionContext(const ConstructionContext& other, const sk_sp<SkSVGNode>& newParent)
fmalita28d5b722016-09-12 17:06:47 -0700375 : fParent(newParent.get()), fIDMapper(other.fIDMapper) {}
fmalita6ceef3d2016-07-26 18:46:34 -0700376
377 const SkSVGNode* fParent;
fmalita28d5b722016-09-12 17:06:47 -0700378 SkSVGIDMapper* fIDMapper;
fmalita6ceef3d2016-07-26 18:46:34 -0700379};
380
fmalita58649cc2016-07-29 08:52:03 -0700381void set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value) {
382 const int attrIndex = SkStrSearch(&gAttributeParseInfo[0].fKey,
383 SkTo<int>(SK_ARRAY_COUNT(gAttributeParseInfo)),
384 name, sizeof(gAttributeParseInfo[0]));
385 if (attrIndex < 0) {
fmalitafea704e2016-08-10 16:25:32 -0700386#if defined(SK_VERBOSE_SVG_PARSING)
fmalita58649cc2016-07-29 08:52:03 -0700387 SkDebugf("unhandled attribute: %s\n", name);
fmalitafea704e2016-08-10 16:25:32 -0700388#endif
fmalita58649cc2016-07-29 08:52:03 -0700389 return;
390 }
391
392 SkASSERT(SkTo<size_t>(attrIndex) < SK_ARRAY_COUNT(gAttributeParseInfo));
393 const auto& attrInfo = gAttributeParseInfo[attrIndex].fValue;
394 if (!attrInfo.fSetter(node, attrInfo.fAttr, value)) {
fmalitafea704e2016-08-10 16:25:32 -0700395#if defined(SK_VERBOSE_SVG_PARSING)
fmalita58649cc2016-07-29 08:52:03 -0700396 SkDebugf("could not parse attribute: '%s=\"%s\"'\n", name, value);
fmalitafea704e2016-08-10 16:25:32 -0700397#endif
fmalita58649cc2016-07-29 08:52:03 -0700398 }
399}
400
fmalita6ceef3d2016-07-26 18:46:34 -0700401void parse_node_attributes(const SkDOM& xmlDom, const SkDOM::Node* xmlNode,
fmalita28d5b722016-09-12 17:06:47 -0700402 const sk_sp<SkSVGNode>& svgNode, SkSVGIDMapper* mapper) {
fmalita6ceef3d2016-07-26 18:46:34 -0700403 const char* name, *value;
404 SkDOM::AttrIter attrIter(xmlDom, xmlNode);
405 while ((name = attrIter.next(&value))) {
fmalita28d5b722016-09-12 17:06:47 -0700406 // We're handling id attributes out of band for now.
407 if (!strcmp(name, "id")) {
408 mapper->set(SkString(value), svgNode);
409 continue;
410 }
fmalita58649cc2016-07-29 08:52:03 -0700411 set_string_attribute(svgNode, name, value);
fmalita6ceef3d2016-07-26 18:46:34 -0700412 }
413}
414
415sk_sp<SkSVGNode> construct_svg_node(const SkDOM& dom, const ConstructionContext& ctx,
416 const SkDOM::Node* xmlNode) {
417 const char* elem = dom.getName(xmlNode);
418 const SkDOM::Type elemType = dom.getType(xmlNode);
419
420 if (elemType == SkDOM::kText_Type) {
421 SkASSERT(dom.countChildren(xmlNode) == 0);
422 // TODO: text handling
423 return nullptr;
424 }
425
426 SkASSERT(elemType == SkDOM::kElement_Type);
427
428 const int tagIndex = SkStrSearch(&gTagFactories[0].fKey,
429 SkTo<int>(SK_ARRAY_COUNT(gTagFactories)),
430 elem, sizeof(gTagFactories[0]));
431 if (tagIndex < 0) {
fmalitafea704e2016-08-10 16:25:32 -0700432#if defined(SK_VERBOSE_SVG_PARSING)
fmalita6ceef3d2016-07-26 18:46:34 -0700433 SkDebugf("unhandled element: <%s>\n", elem);
fmalitafea704e2016-08-10 16:25:32 -0700434#endif
fmalita6ceef3d2016-07-26 18:46:34 -0700435 return nullptr;
436 }
437
438 SkASSERT(SkTo<size_t>(tagIndex) < SK_ARRAY_COUNT(gTagFactories));
439 sk_sp<SkSVGNode> node = gTagFactories[tagIndex].fValue();
fmalita28d5b722016-09-12 17:06:47 -0700440 parse_node_attributes(dom, xmlNode, node, ctx.fIDMapper);
fmalita6ceef3d2016-07-26 18:46:34 -0700441
442 ConstructionContext localCtx(ctx, node);
443 for (auto* child = dom.getFirstChild(xmlNode, nullptr); child;
444 child = dom.getNextSibling(child)) {
445 sk_sp<SkSVGNode> childNode = construct_svg_node(dom, localCtx, child);
446 if (childNode) {
447 node->appendChild(std::move(childNode));
448 }
449 }
450
451 return node;
452}
453
454} // anonymous namespace
455
fmalitae1baa7c2016-09-14 12:04:30 -0700456SkSVGDOM::SkSVGDOM()
457 : fContainerSize(SkSize::Make(0, 0)) {
fmalita6ceef3d2016-07-26 18:46:34 -0700458}
459
fmalitae1baa7c2016-09-14 12:04:30 -0700460sk_sp<SkSVGDOM> SkSVGDOM::MakeFromDOM(const SkDOM& xmlDom) {
461 sk_sp<SkSVGDOM> dom = sk_make_sp<SkSVGDOM>();
fmalita6ceef3d2016-07-26 18:46:34 -0700462
fmalita28d5b722016-09-12 17:06:47 -0700463 ConstructionContext ctx(&dom->fIDMapper);
fmalita6ceef3d2016-07-26 18:46:34 -0700464 dom->fRoot = construct_svg_node(xmlDom, ctx, xmlDom.getRootNode());
465
fmalitae1baa7c2016-09-14 12:04:30 -0700466 // Reset the default container size to match the intrinsic SVG size.
467 dom->setContainerSize(dom->intrinsicSize());
468
fmalita6ceef3d2016-07-26 18:46:34 -0700469 return dom;
470}
471
fmalitae1baa7c2016-09-14 12:04:30 -0700472sk_sp<SkSVGDOM> SkSVGDOM::MakeFromStream(SkStream& svgStream) {
fmalita6ceef3d2016-07-26 18:46:34 -0700473 SkDOM xmlDom;
474 if (!xmlDom.build(svgStream)) {
475 return nullptr;
476 }
477
fmalitae1baa7c2016-09-14 12:04:30 -0700478 return MakeFromDOM(xmlDom);
fmalita6ceef3d2016-07-26 18:46:34 -0700479}
480
481void SkSVGDOM::render(SkCanvas* canvas) const {
482 if (fRoot) {
Florin Malitaebca0dd2017-09-09 09:39:07 -0400483 SkSVGLengthContext lctx(fContainerSize);
484 SkSVGPresentationContext pctx;
485 fRoot->render(SkSVGRenderContext(canvas, fIDMapper, lctx, pctx));
fmalita6ceef3d2016-07-26 18:46:34 -0700486 }
487}
488
fmalitae1baa7c2016-09-14 12:04:30 -0700489SkSize SkSVGDOM::intrinsicSize() const {
490 if (!fRoot || fRoot->tag() != SkSVGTag::kSvg) {
491 return SkSize::Make(0, 0);
492 }
493
494 // Intrinsic sizes are never relative, so the viewport size is irrelevant.
495 const SkSVGLengthContext lctx(SkSize::Make(0, 0));
496 return static_cast<const SkSVGSVG*>(fRoot.get())->intrinsicSize(lctx);
497}
498
499const SkSize& SkSVGDOM::containerSize() const {
500 return fContainerSize;
501}
502
fmalita6ceef3d2016-07-26 18:46:34 -0700503void SkSVGDOM::setContainerSize(const SkSize& containerSize) {
504 // TODO: inval
505 fContainerSize = containerSize;
506}
fmalitaca39d712016-08-12 13:17:11 -0700507
508void SkSVGDOM::setRoot(sk_sp<SkSVGNode> root) {
509 fRoot = std::move(root);
510}