blob: 9886563803512ac60961f25e2138cfc3b0948f0a [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkCanvas.h"
9#include "include/core/SkString.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/private/SkTo.h"
11#include "include/utils/SkParsePath.h"
Florin Malitab3418102020-10-15 18:10:29 -040012#include "modules/svg/include/SkSVGAttributeParser.h"
13#include "modules/svg/include/SkSVGCircle.h"
14#include "modules/svg/include/SkSVGClipPath.h"
15#include "modules/svg/include/SkSVGDOM.h"
16#include "modules/svg/include/SkSVGDefs.h"
17#include "modules/svg/include/SkSVGEllipse.h"
18#include "modules/svg/include/SkSVGG.h"
19#include "modules/svg/include/SkSVGLine.h"
20#include "modules/svg/include/SkSVGLinearGradient.h"
21#include "modules/svg/include/SkSVGNode.h"
22#include "modules/svg/include/SkSVGPath.h"
23#include "modules/svg/include/SkSVGPattern.h"
24#include "modules/svg/include/SkSVGPoly.h"
25#include "modules/svg/include/SkSVGRadialGradient.h"
26#include "modules/svg/include/SkSVGRect.h"
27#include "modules/svg/include/SkSVGRenderContext.h"
28#include "modules/svg/include/SkSVGSVG.h"
29#include "modules/svg/include/SkSVGStop.h"
30#include "modules/svg/include/SkSVGText.h"
31#include "modules/svg/include/SkSVGTypes.h"
32#include "modules/svg/include/SkSVGUse.h"
33#include "modules/svg/include/SkSVGValue.h"
Ben Wagner8bd6e8f2019-05-15 09:28:52 -040034#include "src/core/SkTSearch.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050035#include "src/xml/SkDOM.h"
fmalita6ceef3d2016-07-26 18:46:34 -070036
37namespace {
38
fmalita6ceef3d2016-07-26 18:46:34 -070039bool SetPaintAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
40 const char* stringValue) {
fmalita2d961e02016-08-11 09:16:29 -070041 SkSVGPaint paint;
fmalitabffc2562016-08-03 10:21:11 -070042 SkSVGAttributeParser parser(stringValue);
fmalita2d961e02016-08-11 09:16:29 -070043 if (!parser.parsePaint(&paint)) {
fmalita28d5b722016-09-12 17:06:47 -070044 return false;
fmalitabffc2562016-08-03 10:21:11 -070045 }
46
Florin Malitaf4403e72020-04-10 14:14:04 +000047 node->setAttribute(attr, SkSVGPaintValue(paint));
fmalita6ceef3d2016-07-26 18:46:34 -070048 return true;
49}
50
fmalita28d5b722016-09-12 17:06:47 -070051bool SetColorAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
52 const char* stringValue) {
53 SkSVGColorType color;
54 SkSVGAttributeParser parser(stringValue);
55 if (!parser.parseColor(&color)) {
56 return false;
57 }
58
Florin Malitaf4403e72020-04-10 14:14:04 +000059 node->setAttribute(attr, SkSVGColorValue(color));
fmalita28d5b722016-09-12 17:06:47 -070060 return true;
61}
62
63bool SetIRIAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
64 const char* stringValue) {
65 SkSVGStringType iri;
66 SkSVGAttributeParser parser(stringValue);
67 if (!parser.parseIRI(&iri)) {
68 return false;
69 }
70
Florin Malitaf4403e72020-04-10 14:14:04 +000071 node->setAttribute(attr, SkSVGStringValue(iri));
fmalita28d5b722016-09-12 17:06:47 -070072 return true;
73}
74
Florin Malitace8840e2016-12-08 09:26:47 -050075bool SetClipPathAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
76 const char* stringValue) {
77 SkSVGClip clip;
78 SkSVGAttributeParser parser(stringValue);
79 if (!parser.parseClipPath(&clip)) {
80 return false;
81 }
82
Florin Malitaf4403e72020-04-10 14:14:04 +000083 node->setAttribute(attr, SkSVGClipValue(clip));
Florin Malitace8840e2016-12-08 09:26:47 -050084 return true;
85}
86
87
fmalita6ceef3d2016-07-26 18:46:34 -070088bool SetPathDataAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
89 const char* stringValue) {
90 SkPath path;
91 if (!SkParsePath::FromSVGString(stringValue, &path)) {
92 return false;
93 }
94
Florin Malitaf4403e72020-04-10 14:14:04 +000095 node->setAttribute(attr, SkSVGPathValue(path));
fmalita6ceef3d2016-07-26 18:46:34 -070096 return true;
97}
98
Xavier Phane29cdaf2020-03-26 16:15:14 +000099bool SetStringAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
100 const char* stringValue) {
101 SkString str(stringValue, strlen(stringValue));
102 SkSVGStringType strType = SkSVGStringType(str);
Florin Malitaf4403e72020-04-10 14:14:04 +0000103 node->setAttribute(attr, SkSVGStringValue(strType));
Xavier Phane29cdaf2020-03-26 16:15:14 +0000104 return true;
105}
106
fmalita6ceef3d2016-07-26 18:46:34 -0700107bool SetTransformAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
108 const char* stringValue) {
fmalitac97796b2016-08-08 12:58:57 -0700109 SkSVGTransformType transform;
110 SkSVGAttributeParser parser(stringValue);
111 if (!parser.parseTransform(&transform)) {
112 return false;
113 }
114
Florin Malitaf4403e72020-04-10 14:14:04 +0000115 node->setAttribute(attr, SkSVGTransformValue(transform));
fmalita6ceef3d2016-07-26 18:46:34 -0700116 return true;
117}
118
fmalitabffc2562016-08-03 10:21:11 -0700119bool SetLengthAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
120 const char* stringValue) {
121 SkSVGLength length;
122 SkSVGAttributeParser parser(stringValue);
123 if (!parser.parseLength(&length)) {
124 return false;
125 }
126
Florin Malitaf4403e72020-04-10 14:14:04 +0000127 node->setAttribute(attr, SkSVGLengthValue(length));
fmalitabffc2562016-08-03 10:21:11 -0700128 return true;
129}
130
fmalita2d961e02016-08-11 09:16:29 -0700131bool SetNumberAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
132 const char* stringValue) {
133 SkSVGNumberType number;
134 SkSVGAttributeParser parser(stringValue);
135 if (!parser.parseNumber(&number)) {
136 return false;
137 }
138
Florin Malitaf4403e72020-04-10 14:14:04 +0000139 node->setAttribute(attr, SkSVGNumberValue(number));
fmalita2d961e02016-08-11 09:16:29 -0700140 return true;
141}
142
fmalita397a5172016-08-08 11:38:55 -0700143bool SetViewBoxAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
144 const char* stringValue) {
145 SkSVGViewBoxType viewBox;
146 SkSVGAttributeParser parser(stringValue);
147 if (!parser.parseViewBox(&viewBox)) {
148 return false;
149 }
150
Florin Malitaf4403e72020-04-10 14:14:04 +0000151 node->setAttribute(attr, SkSVGViewBoxValue(viewBox));
fmalita397a5172016-08-08 11:38:55 -0700152 return true;
153}
154
fmalita2d961e02016-08-11 09:16:29 -0700155bool SetLineCapAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
156 const char* stringValue) {
157 SkSVGLineCap lineCap;
158 SkSVGAttributeParser parser(stringValue);
159 if (!parser.parseLineCap(&lineCap)) {
160 return false;
161 }
162
Florin Malitaf4403e72020-04-10 14:14:04 +0000163 node->setAttribute(attr, SkSVGLineCapValue(lineCap));
fmalita2d961e02016-08-11 09:16:29 -0700164 return true;
165}
166
167bool SetLineJoinAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
168 const char* stringValue) {
169 SkSVGLineJoin lineJoin;
170 SkSVGAttributeParser parser(stringValue);
171 if (!parser.parseLineJoin(&lineJoin)) {
172 return false;
173 }
174
Florin Malitaf4403e72020-04-10 14:14:04 +0000175 node->setAttribute(attr, SkSVGLineJoinValue(lineJoin));
fmalita2d961e02016-08-11 09:16:29 -0700176 return true;
177}
178
fmalitacecd6172016-09-13 12:56:11 -0700179bool SetSpreadMethodAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
180 const char* stringValue) {
181 SkSVGSpreadMethod spread;
182 SkSVGAttributeParser parser(stringValue);
183 if (!parser.parseSpreadMethod(&spread)) {
184 return false;
185 }
186
Florin Malitaf4403e72020-04-10 14:14:04 +0000187 node->setAttribute(attr, SkSVGSpreadMethodValue(spread));
fmalitacecd6172016-09-13 12:56:11 -0700188 return true;
189}
190
Tyler Denniston308c0722020-04-14 10:53:41 -0400191bool SetStopColorAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
192 const char* stringValue) {
193 SkSVGStopColor stopColor;
194 SkSVGAttributeParser parser(stringValue);
195 if (!parser.parseStopColor(&stopColor)) {
196 return false;
197 }
198
199 node->setAttribute(attr, SkSVGStopColorValue(stopColor));
200 return true;
201}
202
Tyler Denniston30e327e2020-10-29 16:29:22 -0400203bool SetObjectBoundingBoxUnitsAttribute(const sk_sp<SkSVGNode>& node,
204 SkSVGAttribute attr,
205 const char* stringValue) {
206 SkSVGObjectBoundingBoxUnits objectBoundingBoxUnits;
Tyler Dennistonab76ab42020-10-21 15:08:45 -0400207 SkSVGAttributeParser parser(stringValue);
Tyler Denniston30e327e2020-10-29 16:29:22 -0400208 if (!parser.parseObjectBoundingBoxUnits(&objectBoundingBoxUnits)) {
Tyler Dennistonab76ab42020-10-21 15:08:45 -0400209 return false;
210 }
211
Tyler Denniston30e327e2020-10-29 16:29:22 -0400212 node->setAttribute(attr, SkSVGObjectBoundingBoxUnitsValue(objectBoundingBoxUnits));
Tyler Dennistonab76ab42020-10-21 15:08:45 -0400213 return true;
214}
215
fmalita5b31f322016-08-12 12:15:33 -0700216bool SetPointsAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
217 const char* stringValue) {
218 SkSVGPointsType points;
219 SkSVGAttributeParser parser(stringValue);
220 if (!parser.parsePoints(&points)) {
221 return false;
222 }
223
Florin Malitaf4403e72020-04-10 14:14:04 +0000224 node->setAttribute(attr, SkSVGPointsValue(points));
fmalita5b31f322016-08-12 12:15:33 -0700225 return true;
226}
227
Florin Malitae932d4b2016-12-01 13:35:11 -0500228bool SetFillRuleAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
229 const char* stringValue) {
230 SkSVGFillRule fillRule;
231 SkSVGAttributeParser parser(stringValue);
232 if (!parser.parseFillRule(&fillRule)) {
233 return false;
234 }
235
Florin Malitaf4403e72020-04-10 14:14:04 +0000236 node->setAttribute(attr, SkSVGFillRuleValue(fillRule));
Florin Malitae932d4b2016-12-01 13:35:11 -0500237 return true;
238}
239
Tyler Dennistonb3cafbc2020-10-30 15:00:48 -0400240bool SetFilterAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
241 const char* stringValue) {
242 SkSVGFilterType filter;
243 SkSVGAttributeParser parser(stringValue);
244 if (!parser.parseFilter(&filter)) {
245 return false;
246 }
247
248 node->setAttribute(attr, SkSVGFilterValue(filter));
249 return true;
250}
251
Florin Malitaffe6ae42017-10-12 11:33:28 -0400252bool SetVisibilityAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
253 const char* stringValue) {
254 SkSVGVisibility visibility;
255 SkSVGAttributeParser parser(stringValue);
256 if (!parser.parseVisibility(&visibility)) {
257 return false;
258 }
259
Florin Malitaf4403e72020-04-10 14:14:04 +0000260 node->setAttribute(attr, SkSVGVisibilityValue(visibility));
Florin Malitaffe6ae42017-10-12 11:33:28 -0400261 return true;
262}
263
Florin Malitaf543a602017-10-13 14:07:44 -0400264bool SetDashArrayAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
265 const char* stringValue) {
266 SkSVGDashArray dashArray;
267 SkSVGAttributeParser parser(stringValue);
268 if (!parser.parseDashArray(&dashArray)) {
269 return false;
270 }
271
Florin Malitaf4403e72020-04-10 14:14:04 +0000272 node->setAttribute(attr, SkSVGDashArrayValue(dashArray));
Florin Malitaf543a602017-10-13 14:07:44 -0400273 return true;
274}
275
Florin Malita39fe8c82020-10-20 10:43:03 -0400276bool SetFontFamilyAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
277 const char* stringValue) {
278 SkSVGFontFamily family;
279 SkSVGAttributeParser parser(stringValue);
280 if (!parser.parseFontFamily(&family)) {
281 return false;
282 }
283
284 node->setAttribute(attr, SkSVGFontFamilyValue(family));
285 return true;
286}
287
288bool SetFontSizeAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
289 const char* stringValue) {
290 SkSVGFontSize size;
291 SkSVGAttributeParser parser(stringValue);
292 if (!parser.parseFontSize(&size)) {
293 return false;
294 }
295
296 node->setAttribute(attr, SkSVGFontSizeValue(size));
297 return true;
298}
299
300bool SetFontStyleAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
301 const char* stringValue) {
302 SkSVGFontStyle style;
303 SkSVGAttributeParser parser(stringValue);
304 if (!parser.parseFontStyle(&style)) {
305 return false;
306 }
307
308 node->setAttribute(attr, SkSVGFontStyleValue(style));
309 return true;
310}
311
312bool SetFontWeightAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
313 const char* stringValue) {
314 SkSVGFontWeight weight;
315 SkSVGAttributeParser parser(stringValue);
316 if (!parser.parseFontWeight(&weight)) {
317 return false;
318 }
319
320 node->setAttribute(attr, SkSVGFontWeightValue(weight));
321 return true;
322}
323
Florin Malita056385b2020-10-27 22:57:56 -0400324bool SetTextAnchorAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
325 const char* stringValue) {
326 SkSVGTextAnchor anchor;
327 SkSVGAttributeParser parser(stringValue);
328
329 if (!parser.parseTextAnchor(&anchor)) {
330 return false;
331 }
332
333 node->setAttribute(attr, SkSVGTextAnchorValue(anchor));
334 return true;
335}
336
Florin Malita385e7442020-10-21 16:55:46 -0400337bool SetPreserveAspectRatioAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
338 const char* stringValue) {
339 SkSVGPreserveAspectRatio par;
340 SkSVGAttributeParser parser(stringValue);
341 if (!parser.parsePreserveAspectRatio(&par)) {
342 return false;
343 }
344
345 node->setAttribute(attr, SkSVGPreserveAspectRatioValue(par));
346 return true;
347}
348
fmalita61f36b32016-08-08 13:58:50 -0700349SkString TrimmedString(const char* first, const char* last) {
350 SkASSERT(first);
351 SkASSERT(last);
352 SkASSERT(first <= last);
353
354 while (first <= last && *first <= ' ') { first++; }
355 while (first <= last && *last <= ' ') { last--; }
356
357 SkASSERT(last - first + 1 >= 0);
358 return SkString(first, SkTo<size_t>(last - first + 1));
359}
360
fmalita58649cc2016-07-29 08:52:03 -0700361// Breaks a "foo: bar; baz: ..." string into key:value pairs.
362class StyleIterator {
363public:
364 StyleIterator(const char* str) : fPos(str) { }
365
366 std::tuple<SkString, SkString> next() {
367 SkString name, value;
368
369 if (fPos) {
370 const char* sep = this->nextSeparator();
371 SkASSERT(*sep == ';' || *sep == '\0');
372
373 const char* valueSep = strchr(fPos, ':');
374 if (valueSep && valueSep < sep) {
fmalita61f36b32016-08-08 13:58:50 -0700375 name = TrimmedString(fPos, valueSep - 1);
376 value = TrimmedString(valueSep + 1, sep - 1);
fmalita58649cc2016-07-29 08:52:03 -0700377 }
378
379 fPos = *sep ? sep + 1 : nullptr;
380 }
381
382 return std::make_tuple(name, value);
383 }
384
385private:
386 const char* nextSeparator() const {
387 const char* sep = fPos;
388 while (*sep != ';' && *sep != '\0') {
389 sep++;
390 }
391 return sep;
392 }
393
394 const char* fPos;
395};
396
Tyler Freemanc9911522020-05-08 13:23:10 -0700397bool set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value);
fmalita58649cc2016-07-29 08:52:03 -0700398
399bool SetStyleAttributes(const sk_sp<SkSVGNode>& node, SkSVGAttribute,
400 const char* stringValue) {
401
402 SkString name, value;
403 StyleIterator iter(stringValue);
404 for (;;) {
405 std::tie(name, value) = iter.next();
406 if (name.isEmpty()) {
407 break;
408 }
409 set_string_attribute(node, name.c_str(), value.c_str());
410 }
411
412 return true;
413}
414
fmalita6ceef3d2016-07-26 18:46:34 -0700415template<typename T>
416struct SortedDictionaryEntry {
417 const char* fKey;
418 const T fValue;
419};
420
421struct AttrParseInfo {
422 SkSVGAttribute fAttr;
423 bool (*fSetter)(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, const char* stringValue);
424};
425
426SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
Florin Malita385e7442020-10-21 16:55:46 -0400427 { "clip-path" , { SkSVGAttribute::kClipPath , SetClipPathAttribute }},
428 { "clip-rule" , { SkSVGAttribute::kClipRule , SetFillRuleAttribute }},
429 { "color" , { SkSVGAttribute::kColor , SetColorAttribute }},
430 { "cx" , { SkSVGAttribute::kCx , SetLengthAttribute }},
431 { "cy" , { SkSVGAttribute::kCy , SetLengthAttribute }},
432 { "d" , { SkSVGAttribute::kD , SetPathDataAttribute }},
433 { "fill" , { SkSVGAttribute::kFill , SetPaintAttribute }},
434 { "fill-opacity" , { SkSVGAttribute::kFillOpacity , SetNumberAttribute }},
435 { "fill-rule" , { SkSVGAttribute::kFillRule , SetFillRuleAttribute }},
Tyler Dennistonb3cafbc2020-10-30 15:00:48 -0400436 { "filter" , { SkSVGAttribute::kFilter , SetFilterAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400437 { "font-family" , { SkSVGAttribute::kFontFamily , SetFontFamilyAttribute }},
438 { "font-size" , { SkSVGAttribute::kFontSize , SetFontSizeAttribute }},
439 { "font-style" , { SkSVGAttribute::kFontStyle , SetFontStyleAttribute }},
440 { "font-weight" , { SkSVGAttribute::kFontWeight , SetFontWeightAttribute }},
Florin Malitacc6cc292017-10-09 16:05:30 -0400441 // focal point x & y
Florin Malita385e7442020-10-21 16:55:46 -0400442 { "fx" , { SkSVGAttribute::kFx , SetLengthAttribute }},
443 { "fy" , { SkSVGAttribute::kFy , SetLengthAttribute }},
444 { "gradientTransform" , { SkSVGAttribute::kGradientTransform, SetTransformAttribute }},
Tyler Denniston30e327e2020-10-29 16:29:22 -0400445 { "gradientUnits" , { SkSVGAttribute::kGradientUnits ,
446 SetObjectBoundingBoxUnitsAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400447 { "height" , { SkSVGAttribute::kHeight , SetLengthAttribute }},
448 { "offset" , { SkSVGAttribute::kOffset , SetLengthAttribute }},
449 { "opacity" , { SkSVGAttribute::kOpacity , SetNumberAttribute }},
450 { "patternTransform" , { SkSVGAttribute::kPatternTransform , SetTransformAttribute }},
451 { "points" , { SkSVGAttribute::kPoints , SetPointsAttribute }},
452 { "preserveAspectRatio", { SkSVGAttribute::kPreserveAspectRatio,
453 SetPreserveAspectRatioAttribute }},
454 { "r" , { SkSVGAttribute::kR , SetLengthAttribute }},
455 { "rx" , { SkSVGAttribute::kRx , SetLengthAttribute }},
456 { "ry" , { SkSVGAttribute::kRy , SetLengthAttribute }},
457 { "spreadMethod" , { SkSVGAttribute::kSpreadMethod , SetSpreadMethodAttribute }},
458 { "stop-color" , { SkSVGAttribute::kStopColor , SetStopColorAttribute }},
459 { "stop-opacity" , { SkSVGAttribute::kStopOpacity , SetNumberAttribute }},
460 { "stroke" , { SkSVGAttribute::kStroke , SetPaintAttribute }},
461 { "stroke-dasharray" , { SkSVGAttribute::kStrokeDashArray , SetDashArrayAttribute }},
462 { "stroke-dashoffset" , { SkSVGAttribute::kStrokeDashOffset , SetLengthAttribute }},
463 { "stroke-linecap" , { SkSVGAttribute::kStrokeLineCap , SetLineCapAttribute }},
464 { "stroke-linejoin" , { SkSVGAttribute::kStrokeLineJoin , SetLineJoinAttribute }},
465 { "stroke-miterlimit" , { SkSVGAttribute::kStrokeMiterLimit , SetNumberAttribute }},
466 { "stroke-opacity" , { SkSVGAttribute::kStrokeOpacity , SetNumberAttribute }},
467 { "stroke-width" , { SkSVGAttribute::kStrokeWidth , SetLengthAttribute }},
468 { "style" , { SkSVGAttribute::kUnknown , SetStyleAttributes }},
469 { "text" , { SkSVGAttribute::kText , SetStringAttribute }},
Florin Malita056385b2020-10-27 22:57:56 -0400470 { "text-anchor" , { SkSVGAttribute::kTextAnchor , SetTextAnchorAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400471 { "transform" , { SkSVGAttribute::kTransform , SetTransformAttribute }},
472 { "viewBox" , { SkSVGAttribute::kViewBox , SetViewBoxAttribute }},
473 { "visibility" , { SkSVGAttribute::kVisibility , SetVisibilityAttribute }},
474 { "width" , { SkSVGAttribute::kWidth , SetLengthAttribute }},
475 { "x" , { SkSVGAttribute::kX , SetLengthAttribute }},
476 { "x1" , { SkSVGAttribute::kX1 , SetLengthAttribute }},
477 { "x2" , { SkSVGAttribute::kX2 , SetLengthAttribute }},
478 { "xlink:href" , { SkSVGAttribute::kHref , SetIRIAttribute }},
479 { "y" , { SkSVGAttribute::kY , SetLengthAttribute }},
480 { "y1" , { SkSVGAttribute::kY1 , SetLengthAttribute }},
481 { "y2" , { SkSVGAttribute::kY2 , SetLengthAttribute }},
fmalita6ceef3d2016-07-26 18:46:34 -0700482};
483
484SortedDictionaryEntry<sk_sp<SkSVGNode>(*)()> gTagFactories[] = {
Florin Malitaf6143ff2017-10-10 09:16:52 -0400485 { "a" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700486 { "circle" , []() -> sk_sp<SkSVGNode> { return SkSVGCircle::Make(); }},
Florin Malitace8840e2016-12-08 09:26:47 -0500487 { "clipPath" , []() -> sk_sp<SkSVGNode> { return SkSVGClipPath::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700488 { "defs" , []() -> sk_sp<SkSVGNode> { return SkSVGDefs::Make(); }},
489 { "ellipse" , []() -> sk_sp<SkSVGNode> { return SkSVGEllipse::Make(); }},
490 { "g" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
491 { "line" , []() -> sk_sp<SkSVGNode> { return SkSVGLine::Make(); }},
492 { "linearGradient", []() -> sk_sp<SkSVGNode> { return SkSVGLinearGradient::Make(); }},
493 { "path" , []() -> sk_sp<SkSVGNode> { return SkSVGPath::Make(); }},
Florin Malita1aa1bb62017-10-11 14:34:33 -0400494 { "pattern" , []() -> sk_sp<SkSVGNode> { return SkSVGPattern::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700495 { "polygon" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolygon(); }},
496 { "polyline" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolyline(); }},
Florin Malitacc6cc292017-10-09 16:05:30 -0400497 { "radialGradient", []() -> sk_sp<SkSVGNode> { return SkSVGRadialGradient::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700498 { "rect" , []() -> sk_sp<SkSVGNode> { return SkSVGRect::Make(); }},
499 { "stop" , []() -> sk_sp<SkSVGNode> { return SkSVGStop::Make(); }},
500 { "svg" , []() -> sk_sp<SkSVGNode> { return SkSVGSVG::Make(); }},
Xavier Phane29cdaf2020-03-26 16:15:14 +0000501 { "text" , []() -> sk_sp<SkSVGNode> { return SkSVGText::Make(); }},
Florin Malita6a69c052017-10-11 14:02:11 -0400502 { "use" , []() -> sk_sp<SkSVGNode> { return SkSVGUse::Make(); }},
fmalita6ceef3d2016-07-26 18:46:34 -0700503};
504
505struct ConstructionContext {
fmalita28d5b722016-09-12 17:06:47 -0700506 ConstructionContext(SkSVGIDMapper* mapper) : fParent(nullptr), fIDMapper(mapper) {}
fmalita6ceef3d2016-07-26 18:46:34 -0700507 ConstructionContext(const ConstructionContext& other, const sk_sp<SkSVGNode>& newParent)
fmalita28d5b722016-09-12 17:06:47 -0700508 : fParent(newParent.get()), fIDMapper(other.fIDMapper) {}
fmalita6ceef3d2016-07-26 18:46:34 -0700509
Florin Malita39fe8c82020-10-20 10:43:03 -0400510 SkSVGNode* fParent;
511 SkSVGIDMapper* fIDMapper;
fmalita6ceef3d2016-07-26 18:46:34 -0700512};
513
Tyler Freemanc9911522020-05-08 13:23:10 -0700514bool set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value) {
fmalita58649cc2016-07-29 08:52:03 -0700515 const int attrIndex = SkStrSearch(&gAttributeParseInfo[0].fKey,
516 SkTo<int>(SK_ARRAY_COUNT(gAttributeParseInfo)),
517 name, sizeof(gAttributeParseInfo[0]));
518 if (attrIndex < 0) {
fmalitafea704e2016-08-10 16:25:32 -0700519#if defined(SK_VERBOSE_SVG_PARSING)
fmalita58649cc2016-07-29 08:52:03 -0700520 SkDebugf("unhandled attribute: %s\n", name);
fmalitafea704e2016-08-10 16:25:32 -0700521#endif
Tyler Freemanc9911522020-05-08 13:23:10 -0700522 return false;
fmalita58649cc2016-07-29 08:52:03 -0700523 }
524
525 SkASSERT(SkTo<size_t>(attrIndex) < SK_ARRAY_COUNT(gAttributeParseInfo));
526 const auto& attrInfo = gAttributeParseInfo[attrIndex].fValue;
527 if (!attrInfo.fSetter(node, attrInfo.fAttr, value)) {
fmalitafea704e2016-08-10 16:25:32 -0700528#if defined(SK_VERBOSE_SVG_PARSING)
fmalita58649cc2016-07-29 08:52:03 -0700529 SkDebugf("could not parse attribute: '%s=\"%s\"'\n", name, value);
fmalitafea704e2016-08-10 16:25:32 -0700530#endif
Tyler Freemanc9911522020-05-08 13:23:10 -0700531 return false;
fmalita58649cc2016-07-29 08:52:03 -0700532 }
Tyler Freemanc9911522020-05-08 13:23:10 -0700533
534 return true;
fmalita58649cc2016-07-29 08:52:03 -0700535}
536
fmalita6ceef3d2016-07-26 18:46:34 -0700537void parse_node_attributes(const SkDOM& xmlDom, const SkDOM::Node* xmlNode,
fmalita28d5b722016-09-12 17:06:47 -0700538 const sk_sp<SkSVGNode>& svgNode, SkSVGIDMapper* mapper) {
fmalita6ceef3d2016-07-26 18:46:34 -0700539 const char* name, *value;
540 SkDOM::AttrIter attrIter(xmlDom, xmlNode);
541 while ((name = attrIter.next(&value))) {
fmalita28d5b722016-09-12 17:06:47 -0700542 // We're handling id attributes out of band for now.
543 if (!strcmp(name, "id")) {
544 mapper->set(SkString(value), svgNode);
545 continue;
546 }
fmalita58649cc2016-07-29 08:52:03 -0700547 set_string_attribute(svgNode, name, value);
fmalita6ceef3d2016-07-26 18:46:34 -0700548 }
549}
550
551sk_sp<SkSVGNode> construct_svg_node(const SkDOM& dom, const ConstructionContext& ctx,
552 const SkDOM::Node* xmlNode) {
553 const char* elem = dom.getName(xmlNode);
554 const SkDOM::Type elemType = dom.getType(xmlNode);
555
556 if (elemType == SkDOM::kText_Type) {
557 SkASSERT(dom.countChildren(xmlNode) == 0);
Florin Malita39fe8c82020-10-20 10:43:03 -0400558 // TODO: add type conversion helper to SkSVGNode
559 if (ctx.fParent->tag() == SkSVGTag::kText) {
560 static_cast<SkSVGText*>(ctx.fParent)->setText(SkString(dom.getName(xmlNode)));
561 }
fmalita6ceef3d2016-07-26 18:46:34 -0700562 return nullptr;
563 }
564
565 SkASSERT(elemType == SkDOM::kElement_Type);
566
567 const int tagIndex = SkStrSearch(&gTagFactories[0].fKey,
568 SkTo<int>(SK_ARRAY_COUNT(gTagFactories)),
569 elem, sizeof(gTagFactories[0]));
570 if (tagIndex < 0) {
fmalitafea704e2016-08-10 16:25:32 -0700571#if defined(SK_VERBOSE_SVG_PARSING)
fmalita6ceef3d2016-07-26 18:46:34 -0700572 SkDebugf("unhandled element: <%s>\n", elem);
fmalitafea704e2016-08-10 16:25:32 -0700573#endif
fmalita6ceef3d2016-07-26 18:46:34 -0700574 return nullptr;
575 }
576
577 SkASSERT(SkTo<size_t>(tagIndex) < SK_ARRAY_COUNT(gTagFactories));
578 sk_sp<SkSVGNode> node = gTagFactories[tagIndex].fValue();
fmalita28d5b722016-09-12 17:06:47 -0700579 parse_node_attributes(dom, xmlNode, node, ctx.fIDMapper);
fmalita6ceef3d2016-07-26 18:46:34 -0700580
581 ConstructionContext localCtx(ctx, node);
582 for (auto* child = dom.getFirstChild(xmlNode, nullptr); child;
583 child = dom.getNextSibling(child)) {
584 sk_sp<SkSVGNode> childNode = construct_svg_node(dom, localCtx, child);
585 if (childNode) {
586 node->appendChild(std::move(childNode));
587 }
588 }
589
590 return node;
591}
592
593} // anonymous namespace
594
fmalitae1baa7c2016-09-14 12:04:30 -0700595SkSVGDOM::SkSVGDOM()
596 : fContainerSize(SkSize::Make(0, 0)) {
fmalita6ceef3d2016-07-26 18:46:34 -0700597}
598
fmalitae1baa7c2016-09-14 12:04:30 -0700599sk_sp<SkSVGDOM> SkSVGDOM::MakeFromDOM(const SkDOM& xmlDom) {
600 sk_sp<SkSVGDOM> dom = sk_make_sp<SkSVGDOM>();
fmalita6ceef3d2016-07-26 18:46:34 -0700601
fmalita28d5b722016-09-12 17:06:47 -0700602 ConstructionContext ctx(&dom->fIDMapper);
fmalita6ceef3d2016-07-26 18:46:34 -0700603 dom->fRoot = construct_svg_node(xmlDom, ctx, xmlDom.getRootNode());
604
fmalitae1baa7c2016-09-14 12:04:30 -0700605 // Reset the default container size to match the intrinsic SVG size.
606 dom->setContainerSize(dom->intrinsicSize());
607
fmalita6ceef3d2016-07-26 18:46:34 -0700608 return dom;
609}
610
fmalitae1baa7c2016-09-14 12:04:30 -0700611sk_sp<SkSVGDOM> SkSVGDOM::MakeFromStream(SkStream& svgStream) {
fmalita6ceef3d2016-07-26 18:46:34 -0700612 SkDOM xmlDom;
613 if (!xmlDom.build(svgStream)) {
614 return nullptr;
615 }
616
fmalitae1baa7c2016-09-14 12:04:30 -0700617 return MakeFromDOM(xmlDom);
fmalita6ceef3d2016-07-26 18:46:34 -0700618}
619
620void SkSVGDOM::render(SkCanvas* canvas) const {
621 if (fRoot) {
Florin Malitaebca0dd2017-09-09 09:39:07 -0400622 SkSVGLengthContext lctx(fContainerSize);
623 SkSVGPresentationContext pctx;
Tyler Denniston53281c72020-10-22 15:54:24 -0400624 fRoot->render(SkSVGRenderContext(canvas, fIDMapper, lctx, pctx, nullptr));
fmalita6ceef3d2016-07-26 18:46:34 -0700625 }
626}
627
fmalitae1baa7c2016-09-14 12:04:30 -0700628SkSize SkSVGDOM::intrinsicSize() const {
629 if (!fRoot || fRoot->tag() != SkSVGTag::kSvg) {
630 return SkSize::Make(0, 0);
631 }
632
633 // Intrinsic sizes are never relative, so the viewport size is irrelevant.
634 const SkSVGLengthContext lctx(SkSize::Make(0, 0));
635 return static_cast<const SkSVGSVG*>(fRoot.get())->intrinsicSize(lctx);
636}
637
638const SkSize& SkSVGDOM::containerSize() const {
639 return fContainerSize;
640}
641
fmalita6ceef3d2016-07-26 18:46:34 -0700642void SkSVGDOM::setContainerSize(const SkSize& containerSize) {
643 // TODO: inval
644 fContainerSize = containerSize;
645}
fmalitaca39d712016-08-12 13:17:11 -0700646
Tyler Freemanc9911522020-05-08 13:23:10 -0700647sk_sp<SkSVGNode>* SkSVGDOM::findNodeById(const char* id) {
648 SkString idStr(id);
649 return this->fIDMapper.find(idStr);
650}
651
fmalitaca39d712016-08-12 13:17:11 -0700652void SkSVGDOM::setRoot(sk_sp<SkSVGNode> root) {
653 fRoot = std::move(root);
654}
Tyler Freemanc9911522020-05-08 13:23:10 -0700655
656// TODO(fuego): move this to SkSVGNode or its own CU.
657bool SkSVGNode::setAttribute(const char* attributeName, const char* attributeValue) {
658 return set_string_attribute(sk_ref_sp(this), attributeName, attributeValue);
659}