blob: 3b4a69a0cbb28e4dd0809a70fd07a1a85d4603b2 [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"
Tyler Dennistondada9602020-11-03 10:04:25 -050018#include "modules/svg/include/SkSVGFeTurbulence.h"
Tyler Dennistondf208a32020-10-30 16:01:54 -040019#include "modules/svg/include/SkSVGFilter.h"
Florin Malitab3418102020-10-15 18:10:29 -040020#include "modules/svg/include/SkSVGG.h"
21#include "modules/svg/include/SkSVGLine.h"
22#include "modules/svg/include/SkSVGLinearGradient.h"
23#include "modules/svg/include/SkSVGNode.h"
24#include "modules/svg/include/SkSVGPath.h"
25#include "modules/svg/include/SkSVGPattern.h"
26#include "modules/svg/include/SkSVGPoly.h"
27#include "modules/svg/include/SkSVGRadialGradient.h"
28#include "modules/svg/include/SkSVGRect.h"
29#include "modules/svg/include/SkSVGRenderContext.h"
30#include "modules/svg/include/SkSVGSVG.h"
31#include "modules/svg/include/SkSVGStop.h"
32#include "modules/svg/include/SkSVGText.h"
33#include "modules/svg/include/SkSVGTypes.h"
34#include "modules/svg/include/SkSVGUse.h"
35#include "modules/svg/include/SkSVGValue.h"
Ben Wagner8bd6e8f2019-05-15 09:28:52 -040036#include "src/core/SkTSearch.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050037#include "src/xml/SkDOM.h"
fmalita6ceef3d2016-07-26 18:46:34 -070038
39namespace {
40
fmalita6ceef3d2016-07-26 18:46:34 -070041bool SetPaintAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
42 const char* stringValue) {
fmalita2d961e02016-08-11 09:16:29 -070043 SkSVGPaint paint;
fmalitabffc2562016-08-03 10:21:11 -070044 SkSVGAttributeParser parser(stringValue);
fmalita2d961e02016-08-11 09:16:29 -070045 if (!parser.parsePaint(&paint)) {
fmalita28d5b722016-09-12 17:06:47 -070046 return false;
fmalitabffc2562016-08-03 10:21:11 -070047 }
48
Florin Malitaf4403e72020-04-10 14:14:04 +000049 node->setAttribute(attr, SkSVGPaintValue(paint));
fmalita6ceef3d2016-07-26 18:46:34 -070050 return true;
51}
52
fmalita28d5b722016-09-12 17:06:47 -070053bool SetColorAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
54 const char* stringValue) {
55 SkSVGColorType color;
56 SkSVGAttributeParser parser(stringValue);
57 if (!parser.parseColor(&color)) {
58 return false;
59 }
60
Florin Malitaf4403e72020-04-10 14:14:04 +000061 node->setAttribute(attr, SkSVGColorValue(color));
fmalita28d5b722016-09-12 17:06:47 -070062 return true;
63}
64
65bool SetIRIAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
66 const char* stringValue) {
67 SkSVGStringType iri;
68 SkSVGAttributeParser parser(stringValue);
69 if (!parser.parseIRI(&iri)) {
70 return false;
71 }
72
Florin Malitaf4403e72020-04-10 14:14:04 +000073 node->setAttribute(attr, SkSVGStringValue(iri));
fmalita28d5b722016-09-12 17:06:47 -070074 return true;
75}
76
Florin Malitace8840e2016-12-08 09:26:47 -050077bool SetClipPathAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
78 const char* stringValue) {
79 SkSVGClip clip;
80 SkSVGAttributeParser parser(stringValue);
81 if (!parser.parseClipPath(&clip)) {
82 return false;
83 }
84
Florin Malitaf4403e72020-04-10 14:14:04 +000085 node->setAttribute(attr, SkSVGClipValue(clip));
Florin Malitace8840e2016-12-08 09:26:47 -050086 return true;
87}
88
89
fmalita6ceef3d2016-07-26 18:46:34 -070090bool SetPathDataAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
91 const char* stringValue) {
92 SkPath path;
93 if (!SkParsePath::FromSVGString(stringValue, &path)) {
94 return false;
95 }
96
Florin Malitaf4403e72020-04-10 14:14:04 +000097 node->setAttribute(attr, SkSVGPathValue(path));
fmalita6ceef3d2016-07-26 18:46:34 -070098 return true;
99}
100
Xavier Phane29cdaf2020-03-26 16:15:14 +0000101bool SetStringAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
102 const char* stringValue) {
103 SkString str(stringValue, strlen(stringValue));
104 SkSVGStringType strType = SkSVGStringType(str);
Florin Malitaf4403e72020-04-10 14:14:04 +0000105 node->setAttribute(attr, SkSVGStringValue(strType));
Xavier Phane29cdaf2020-03-26 16:15:14 +0000106 return true;
107}
108
fmalita6ceef3d2016-07-26 18:46:34 -0700109bool SetTransformAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
110 const char* stringValue) {
fmalitac97796b2016-08-08 12:58:57 -0700111 SkSVGTransformType transform;
112 SkSVGAttributeParser parser(stringValue);
113 if (!parser.parseTransform(&transform)) {
114 return false;
115 }
116
Florin Malitaf4403e72020-04-10 14:14:04 +0000117 node->setAttribute(attr, SkSVGTransformValue(transform));
fmalita6ceef3d2016-07-26 18:46:34 -0700118 return true;
119}
120
fmalitabffc2562016-08-03 10:21:11 -0700121bool SetLengthAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
122 const char* stringValue) {
123 SkSVGLength length;
124 SkSVGAttributeParser parser(stringValue);
125 if (!parser.parseLength(&length)) {
126 return false;
127 }
128
Florin Malitaf4403e72020-04-10 14:14:04 +0000129 node->setAttribute(attr, SkSVGLengthValue(length));
fmalitabffc2562016-08-03 10:21:11 -0700130 return true;
131}
132
fmalita2d961e02016-08-11 09:16:29 -0700133bool SetNumberAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
134 const char* stringValue) {
135 SkSVGNumberType number;
136 SkSVGAttributeParser parser(stringValue);
137 if (!parser.parseNumber(&number)) {
138 return false;
139 }
140
Florin Malitaf4403e72020-04-10 14:14:04 +0000141 node->setAttribute(attr, SkSVGNumberValue(number));
fmalita2d961e02016-08-11 09:16:29 -0700142 return true;
143}
144
Tyler Dennistondada9602020-11-03 10:04:25 -0500145bool SetIntegerAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
146 const char* stringValue) {
147 SkSVGIntegerType number;
148 SkSVGAttributeParser parser(stringValue);
149 if (!parser.parseInteger(&number)) {
150 return false;
151 }
152
153 node->setAttribute(attr, SkSVGIntegerValue(number));
154 return true;
155}
156
fmalita397a5172016-08-08 11:38:55 -0700157bool SetViewBoxAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
158 const char* stringValue) {
159 SkSVGViewBoxType viewBox;
160 SkSVGAttributeParser parser(stringValue);
161 if (!parser.parseViewBox(&viewBox)) {
162 return false;
163 }
164
Florin Malitaf4403e72020-04-10 14:14:04 +0000165 node->setAttribute(attr, SkSVGViewBoxValue(viewBox));
fmalita397a5172016-08-08 11:38:55 -0700166 return true;
167}
168
fmalita2d961e02016-08-11 09:16:29 -0700169bool SetLineCapAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
170 const char* stringValue) {
171 SkSVGLineCap lineCap;
172 SkSVGAttributeParser parser(stringValue);
173 if (!parser.parseLineCap(&lineCap)) {
174 return false;
175 }
176
Florin Malitaf4403e72020-04-10 14:14:04 +0000177 node->setAttribute(attr, SkSVGLineCapValue(lineCap));
fmalita2d961e02016-08-11 09:16:29 -0700178 return true;
179}
180
181bool SetLineJoinAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
182 const char* stringValue) {
183 SkSVGLineJoin lineJoin;
184 SkSVGAttributeParser parser(stringValue);
185 if (!parser.parseLineJoin(&lineJoin)) {
186 return false;
187 }
188
Florin Malitaf4403e72020-04-10 14:14:04 +0000189 node->setAttribute(attr, SkSVGLineJoinValue(lineJoin));
fmalita2d961e02016-08-11 09:16:29 -0700190 return true;
191}
192
fmalitacecd6172016-09-13 12:56:11 -0700193bool SetSpreadMethodAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
194 const char* stringValue) {
195 SkSVGSpreadMethod spread;
196 SkSVGAttributeParser parser(stringValue);
197 if (!parser.parseSpreadMethod(&spread)) {
198 return false;
199 }
200
Florin Malitaf4403e72020-04-10 14:14:04 +0000201 node->setAttribute(attr, SkSVGSpreadMethodValue(spread));
fmalitacecd6172016-09-13 12:56:11 -0700202 return true;
203}
204
Tyler Denniston308c0722020-04-14 10:53:41 -0400205bool SetStopColorAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
206 const char* stringValue) {
207 SkSVGStopColor stopColor;
208 SkSVGAttributeParser parser(stringValue);
209 if (!parser.parseStopColor(&stopColor)) {
210 return false;
211 }
212
213 node->setAttribute(attr, SkSVGStopColorValue(stopColor));
214 return true;
215}
216
Tyler Denniston30e327e2020-10-29 16:29:22 -0400217bool SetObjectBoundingBoxUnitsAttribute(const sk_sp<SkSVGNode>& node,
218 SkSVGAttribute attr,
219 const char* stringValue) {
220 SkSVGObjectBoundingBoxUnits objectBoundingBoxUnits;
Tyler Dennistonab76ab42020-10-21 15:08:45 -0400221 SkSVGAttributeParser parser(stringValue);
Tyler Denniston30e327e2020-10-29 16:29:22 -0400222 if (!parser.parseObjectBoundingBoxUnits(&objectBoundingBoxUnits)) {
Tyler Dennistonab76ab42020-10-21 15:08:45 -0400223 return false;
224 }
225
Tyler Denniston30e327e2020-10-29 16:29:22 -0400226 node->setAttribute(attr, SkSVGObjectBoundingBoxUnitsValue(objectBoundingBoxUnits));
Tyler Dennistonab76ab42020-10-21 15:08:45 -0400227 return true;
228}
229
fmalita5b31f322016-08-12 12:15:33 -0700230bool SetPointsAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
231 const char* stringValue) {
232 SkSVGPointsType points;
233 SkSVGAttributeParser parser(stringValue);
234 if (!parser.parsePoints(&points)) {
235 return false;
236 }
237
Florin Malitaf4403e72020-04-10 14:14:04 +0000238 node->setAttribute(attr, SkSVGPointsValue(points));
fmalita5b31f322016-08-12 12:15:33 -0700239 return true;
240}
241
Florin Malitae932d4b2016-12-01 13:35:11 -0500242bool SetFillRuleAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
243 const char* stringValue) {
244 SkSVGFillRule fillRule;
245 SkSVGAttributeParser parser(stringValue);
246 if (!parser.parseFillRule(&fillRule)) {
247 return false;
248 }
249
Florin Malitaf4403e72020-04-10 14:14:04 +0000250 node->setAttribute(attr, SkSVGFillRuleValue(fillRule));
Florin Malitae932d4b2016-12-01 13:35:11 -0500251 return true;
252}
253
Tyler Dennistonb3cafbc2020-10-30 15:00:48 -0400254bool SetFilterAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
255 const char* stringValue) {
256 SkSVGFilterType filter;
257 SkSVGAttributeParser parser(stringValue);
258 if (!parser.parseFilter(&filter)) {
259 return false;
260 }
261
262 node->setAttribute(attr, SkSVGFilterValue(filter));
263 return true;
264}
265
Florin Malitaffe6ae42017-10-12 11:33:28 -0400266bool SetVisibilityAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
267 const char* stringValue) {
268 SkSVGVisibility visibility;
269 SkSVGAttributeParser parser(stringValue);
270 if (!parser.parseVisibility(&visibility)) {
271 return false;
272 }
273
Florin Malitaf4403e72020-04-10 14:14:04 +0000274 node->setAttribute(attr, SkSVGVisibilityValue(visibility));
Florin Malitaffe6ae42017-10-12 11:33:28 -0400275 return true;
276}
277
Florin Malitaf543a602017-10-13 14:07:44 -0400278bool SetDashArrayAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
279 const char* stringValue) {
280 SkSVGDashArray dashArray;
281 SkSVGAttributeParser parser(stringValue);
282 if (!parser.parseDashArray(&dashArray)) {
283 return false;
284 }
285
Florin Malitaf4403e72020-04-10 14:14:04 +0000286 node->setAttribute(attr, SkSVGDashArrayValue(dashArray));
Florin Malitaf543a602017-10-13 14:07:44 -0400287 return true;
288}
289
Florin Malita39fe8c82020-10-20 10:43:03 -0400290bool SetFontFamilyAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
291 const char* stringValue) {
292 SkSVGFontFamily family;
293 SkSVGAttributeParser parser(stringValue);
294 if (!parser.parseFontFamily(&family)) {
295 return false;
296 }
297
298 node->setAttribute(attr, SkSVGFontFamilyValue(family));
299 return true;
300}
301
302bool SetFontSizeAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
303 const char* stringValue) {
304 SkSVGFontSize size;
305 SkSVGAttributeParser parser(stringValue);
306 if (!parser.parseFontSize(&size)) {
307 return false;
308 }
309
310 node->setAttribute(attr, SkSVGFontSizeValue(size));
311 return true;
312}
313
314bool SetFontStyleAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
315 const char* stringValue) {
316 SkSVGFontStyle style;
317 SkSVGAttributeParser parser(stringValue);
318 if (!parser.parseFontStyle(&style)) {
319 return false;
320 }
321
322 node->setAttribute(attr, SkSVGFontStyleValue(style));
323 return true;
324}
325
326bool SetFontWeightAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
327 const char* stringValue) {
328 SkSVGFontWeight weight;
329 SkSVGAttributeParser parser(stringValue);
330 if (!parser.parseFontWeight(&weight)) {
331 return false;
332 }
333
334 node->setAttribute(attr, SkSVGFontWeightValue(weight));
335 return true;
336}
337
Florin Malita056385b2020-10-27 22:57:56 -0400338bool SetTextAnchorAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
339 const char* stringValue) {
340 SkSVGTextAnchor anchor;
341 SkSVGAttributeParser parser(stringValue);
342
343 if (!parser.parseTextAnchor(&anchor)) {
344 return false;
345 }
346
347 node->setAttribute(attr, SkSVGTextAnchorValue(anchor));
348 return true;
349}
350
Florin Malita385e7442020-10-21 16:55:46 -0400351bool SetPreserveAspectRatioAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
352 const char* stringValue) {
353 SkSVGPreserveAspectRatio par;
354 SkSVGAttributeParser parser(stringValue);
355 if (!parser.parsePreserveAspectRatio(&par)) {
356 return false;
357 }
358
359 node->setAttribute(attr, SkSVGPreserveAspectRatioValue(par));
360 return true;
361}
362
Tyler Dennistondada9602020-11-03 10:04:25 -0500363bool SetFeTurbulenceBaseFrequencyAttribute(const sk_sp<SkSVGNode>& node,
364 SkSVGAttribute attr,
365 const char* stringValue) {
366 SkSVGFeTurbulenceBaseFrequency baseFreq;
367 SkSVGAttributeParser parser(stringValue);
368 if (!parser.parseFeTurbulenceBaseFrequency(&baseFreq)) {
369 return false;
370 }
371
372 node->setAttribute(attr, SkSVGFeTurbulenceBaseFrequencyValue(baseFreq));
373 return true;
374}
375
376bool SetFeTurbulenceTypeAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
377 const char* stringValue) {
378 SkSVGFeTurbulenceType type;
379 SkSVGAttributeParser parser(stringValue);
380 if (!parser.parseFeTurbulenceType(&type)) {
381 return false;
382 }
383
384 node->setAttribute(attr, SkSVGFeTurbulenceTypeValue(type));
385 return true;
386}
387
fmalita61f36b32016-08-08 13:58:50 -0700388SkString TrimmedString(const char* first, const char* last) {
389 SkASSERT(first);
390 SkASSERT(last);
391 SkASSERT(first <= last);
392
393 while (first <= last && *first <= ' ') { first++; }
394 while (first <= last && *last <= ' ') { last--; }
395
396 SkASSERT(last - first + 1 >= 0);
397 return SkString(first, SkTo<size_t>(last - first + 1));
398}
399
fmalita58649cc2016-07-29 08:52:03 -0700400// Breaks a "foo: bar; baz: ..." string into key:value pairs.
401class StyleIterator {
402public:
403 StyleIterator(const char* str) : fPos(str) { }
404
405 std::tuple<SkString, SkString> next() {
406 SkString name, value;
407
408 if (fPos) {
409 const char* sep = this->nextSeparator();
410 SkASSERT(*sep == ';' || *sep == '\0');
411
412 const char* valueSep = strchr(fPos, ':');
413 if (valueSep && valueSep < sep) {
fmalita61f36b32016-08-08 13:58:50 -0700414 name = TrimmedString(fPos, valueSep - 1);
415 value = TrimmedString(valueSep + 1, sep - 1);
fmalita58649cc2016-07-29 08:52:03 -0700416 }
417
418 fPos = *sep ? sep + 1 : nullptr;
419 }
420
421 return std::make_tuple(name, value);
422 }
423
424private:
425 const char* nextSeparator() const {
426 const char* sep = fPos;
427 while (*sep != ';' && *sep != '\0') {
428 sep++;
429 }
430 return sep;
431 }
432
433 const char* fPos;
434};
435
Tyler Freemanc9911522020-05-08 13:23:10 -0700436bool set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value);
fmalita58649cc2016-07-29 08:52:03 -0700437
438bool SetStyleAttributes(const sk_sp<SkSVGNode>& node, SkSVGAttribute,
439 const char* stringValue) {
440
441 SkString name, value;
442 StyleIterator iter(stringValue);
443 for (;;) {
444 std::tie(name, value) = iter.next();
445 if (name.isEmpty()) {
446 break;
447 }
448 set_string_attribute(node, name.c_str(), value.c_str());
449 }
450
451 return true;
452}
453
fmalita6ceef3d2016-07-26 18:46:34 -0700454template<typename T>
455struct SortedDictionaryEntry {
456 const char* fKey;
457 const T fValue;
458};
459
460struct AttrParseInfo {
461 SkSVGAttribute fAttr;
462 bool (*fSetter)(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, const char* stringValue);
463};
464
465SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
Tyler Dennistondada9602020-11-03 10:04:25 -0500466 { "baseFrequency" , { SkSVGAttribute::kFeTurbulenceBaseFrequency,
467 SetFeTurbulenceBaseFrequencyAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400468 { "clip-path" , { SkSVGAttribute::kClipPath , SetClipPathAttribute }},
469 { "clip-rule" , { SkSVGAttribute::kClipRule , SetFillRuleAttribute }},
470 { "color" , { SkSVGAttribute::kColor , SetColorAttribute }},
471 { "cx" , { SkSVGAttribute::kCx , SetLengthAttribute }},
472 { "cy" , { SkSVGAttribute::kCy , SetLengthAttribute }},
473 { "d" , { SkSVGAttribute::kD , SetPathDataAttribute }},
474 { "fill" , { SkSVGAttribute::kFill , SetPaintAttribute }},
475 { "fill-opacity" , { SkSVGAttribute::kFillOpacity , SetNumberAttribute }},
476 { "fill-rule" , { SkSVGAttribute::kFillRule , SetFillRuleAttribute }},
Tyler Dennistonb3cafbc2020-10-30 15:00:48 -0400477 { "filter" , { SkSVGAttribute::kFilter , SetFilterAttribute }},
Tyler Dennistondf208a32020-10-30 16:01:54 -0400478 { "filterUnits" , { SkSVGAttribute::kFilterUnits ,
479 SetObjectBoundingBoxUnitsAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400480 { "font-family" , { SkSVGAttribute::kFontFamily , SetFontFamilyAttribute }},
481 { "font-size" , { SkSVGAttribute::kFontSize , SetFontSizeAttribute }},
482 { "font-style" , { SkSVGAttribute::kFontStyle , SetFontStyleAttribute }},
483 { "font-weight" , { SkSVGAttribute::kFontWeight , SetFontWeightAttribute }},
Florin Malitacc6cc292017-10-09 16:05:30 -0400484 // focal point x & y
Florin Malita385e7442020-10-21 16:55:46 -0400485 { "fx" , { SkSVGAttribute::kFx , SetLengthAttribute }},
486 { "fy" , { SkSVGAttribute::kFy , SetLengthAttribute }},
487 { "gradientTransform" , { SkSVGAttribute::kGradientTransform, SetTransformAttribute }},
Tyler Denniston30e327e2020-10-29 16:29:22 -0400488 { "gradientUnits" , { SkSVGAttribute::kGradientUnits ,
489 SetObjectBoundingBoxUnitsAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400490 { "height" , { SkSVGAttribute::kHeight , SetLengthAttribute }},
Tyler Dennistondada9602020-11-03 10:04:25 -0500491 { "numOctaves" , { SkSVGAttribute::kFeTurbulenceNumOctaves,
492 SetIntegerAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400493 { "offset" , { SkSVGAttribute::kOffset , SetLengthAttribute }},
494 { "opacity" , { SkSVGAttribute::kOpacity , SetNumberAttribute }},
495 { "patternTransform" , { SkSVGAttribute::kPatternTransform , SetTransformAttribute }},
496 { "points" , { SkSVGAttribute::kPoints , SetPointsAttribute }},
497 { "preserveAspectRatio", { SkSVGAttribute::kPreserveAspectRatio,
498 SetPreserveAspectRatioAttribute }},
499 { "r" , { SkSVGAttribute::kR , SetLengthAttribute }},
500 { "rx" , { SkSVGAttribute::kRx , SetLengthAttribute }},
501 { "ry" , { SkSVGAttribute::kRy , SetLengthAttribute }},
Tyler Dennistondada9602020-11-03 10:04:25 -0500502 { "seed" , { SkSVGAttribute::kFeTurbulenceSeed , SetNumberAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400503 { "spreadMethod" , { SkSVGAttribute::kSpreadMethod , SetSpreadMethodAttribute }},
504 { "stop-color" , { SkSVGAttribute::kStopColor , SetStopColorAttribute }},
505 { "stop-opacity" , { SkSVGAttribute::kStopOpacity , SetNumberAttribute }},
506 { "stroke" , { SkSVGAttribute::kStroke , SetPaintAttribute }},
507 { "stroke-dasharray" , { SkSVGAttribute::kStrokeDashArray , SetDashArrayAttribute }},
508 { "stroke-dashoffset" , { SkSVGAttribute::kStrokeDashOffset , SetLengthAttribute }},
509 { "stroke-linecap" , { SkSVGAttribute::kStrokeLineCap , SetLineCapAttribute }},
510 { "stroke-linejoin" , { SkSVGAttribute::kStrokeLineJoin , SetLineJoinAttribute }},
511 { "stroke-miterlimit" , { SkSVGAttribute::kStrokeMiterLimit , SetNumberAttribute }},
512 { "stroke-opacity" , { SkSVGAttribute::kStrokeOpacity , SetNumberAttribute }},
513 { "stroke-width" , { SkSVGAttribute::kStrokeWidth , SetLengthAttribute }},
514 { "style" , { SkSVGAttribute::kUnknown , SetStyleAttributes }},
515 { "text" , { SkSVGAttribute::kText , SetStringAttribute }},
Florin Malita056385b2020-10-27 22:57:56 -0400516 { "text-anchor" , { SkSVGAttribute::kTextAnchor , SetTextAnchorAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400517 { "transform" , { SkSVGAttribute::kTransform , SetTransformAttribute }},
Tyler Dennistondada9602020-11-03 10:04:25 -0500518 { "type" , { SkSVGAttribute::kFeTurbulenceType ,
519 SetFeTurbulenceTypeAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400520 { "viewBox" , { SkSVGAttribute::kViewBox , SetViewBoxAttribute }},
521 { "visibility" , { SkSVGAttribute::kVisibility , SetVisibilityAttribute }},
522 { "width" , { SkSVGAttribute::kWidth , SetLengthAttribute }},
523 { "x" , { SkSVGAttribute::kX , SetLengthAttribute }},
524 { "x1" , { SkSVGAttribute::kX1 , SetLengthAttribute }},
525 { "x2" , { SkSVGAttribute::kX2 , SetLengthAttribute }},
526 { "xlink:href" , { SkSVGAttribute::kHref , SetIRIAttribute }},
527 { "y" , { SkSVGAttribute::kY , SetLengthAttribute }},
528 { "y1" , { SkSVGAttribute::kY1 , SetLengthAttribute }},
529 { "y2" , { SkSVGAttribute::kY2 , SetLengthAttribute }},
fmalita6ceef3d2016-07-26 18:46:34 -0700530};
531
532SortedDictionaryEntry<sk_sp<SkSVGNode>(*)()> gTagFactories[] = {
Florin Malitaf6143ff2017-10-10 09:16:52 -0400533 { "a" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700534 { "circle" , []() -> sk_sp<SkSVGNode> { return SkSVGCircle::Make(); }},
Florin Malitace8840e2016-12-08 09:26:47 -0500535 { "clipPath" , []() -> sk_sp<SkSVGNode> { return SkSVGClipPath::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700536 { "defs" , []() -> sk_sp<SkSVGNode> { return SkSVGDefs::Make(); }},
537 { "ellipse" , []() -> sk_sp<SkSVGNode> { return SkSVGEllipse::Make(); }},
Tyler Dennistondada9602020-11-03 10:04:25 -0500538 { "feTurbulence" , []() -> sk_sp<SkSVGNode> { return SkSVGFeTurbulence::Make(); }},
Tyler Dennistondf208a32020-10-30 16:01:54 -0400539 { "filter" , []() -> sk_sp<SkSVGNode> { return SkSVGFilter::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700540 { "g" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
541 { "line" , []() -> sk_sp<SkSVGNode> { return SkSVGLine::Make(); }},
542 { "linearGradient", []() -> sk_sp<SkSVGNode> { return SkSVGLinearGradient::Make(); }},
543 { "path" , []() -> sk_sp<SkSVGNode> { return SkSVGPath::Make(); }},
Florin Malita1aa1bb62017-10-11 14:34:33 -0400544 { "pattern" , []() -> sk_sp<SkSVGNode> { return SkSVGPattern::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700545 { "polygon" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolygon(); }},
546 { "polyline" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolyline(); }},
Florin Malitacc6cc292017-10-09 16:05:30 -0400547 { "radialGradient", []() -> sk_sp<SkSVGNode> { return SkSVGRadialGradient::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700548 { "rect" , []() -> sk_sp<SkSVGNode> { return SkSVGRect::Make(); }},
549 { "stop" , []() -> sk_sp<SkSVGNode> { return SkSVGStop::Make(); }},
550 { "svg" , []() -> sk_sp<SkSVGNode> { return SkSVGSVG::Make(); }},
Xavier Phane29cdaf2020-03-26 16:15:14 +0000551 { "text" , []() -> sk_sp<SkSVGNode> { return SkSVGText::Make(); }},
Florin Malita6a69c052017-10-11 14:02:11 -0400552 { "use" , []() -> sk_sp<SkSVGNode> { return SkSVGUse::Make(); }},
fmalita6ceef3d2016-07-26 18:46:34 -0700553};
554
555struct ConstructionContext {
fmalita28d5b722016-09-12 17:06:47 -0700556 ConstructionContext(SkSVGIDMapper* mapper) : fParent(nullptr), fIDMapper(mapper) {}
fmalita6ceef3d2016-07-26 18:46:34 -0700557 ConstructionContext(const ConstructionContext& other, const sk_sp<SkSVGNode>& newParent)
fmalita28d5b722016-09-12 17:06:47 -0700558 : fParent(newParent.get()), fIDMapper(other.fIDMapper) {}
fmalita6ceef3d2016-07-26 18:46:34 -0700559
Florin Malita39fe8c82020-10-20 10:43:03 -0400560 SkSVGNode* fParent;
561 SkSVGIDMapper* fIDMapper;
fmalita6ceef3d2016-07-26 18:46:34 -0700562};
563
Tyler Freemanc9911522020-05-08 13:23:10 -0700564bool set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value) {
fmalita58649cc2016-07-29 08:52:03 -0700565 const int attrIndex = SkStrSearch(&gAttributeParseInfo[0].fKey,
566 SkTo<int>(SK_ARRAY_COUNT(gAttributeParseInfo)),
567 name, sizeof(gAttributeParseInfo[0]));
568 if (attrIndex < 0) {
fmalitafea704e2016-08-10 16:25:32 -0700569#if defined(SK_VERBOSE_SVG_PARSING)
fmalita58649cc2016-07-29 08:52:03 -0700570 SkDebugf("unhandled attribute: %s\n", name);
fmalitafea704e2016-08-10 16:25:32 -0700571#endif
Tyler Freemanc9911522020-05-08 13:23:10 -0700572 return false;
fmalita58649cc2016-07-29 08:52:03 -0700573 }
574
575 SkASSERT(SkTo<size_t>(attrIndex) < SK_ARRAY_COUNT(gAttributeParseInfo));
576 const auto& attrInfo = gAttributeParseInfo[attrIndex].fValue;
577 if (!attrInfo.fSetter(node, attrInfo.fAttr, value)) {
fmalitafea704e2016-08-10 16:25:32 -0700578#if defined(SK_VERBOSE_SVG_PARSING)
fmalita58649cc2016-07-29 08:52:03 -0700579 SkDebugf("could not parse attribute: '%s=\"%s\"'\n", name, value);
fmalitafea704e2016-08-10 16:25:32 -0700580#endif
Tyler Freemanc9911522020-05-08 13:23:10 -0700581 return false;
fmalita58649cc2016-07-29 08:52:03 -0700582 }
Tyler Freemanc9911522020-05-08 13:23:10 -0700583
584 return true;
fmalita58649cc2016-07-29 08:52:03 -0700585}
586
fmalita6ceef3d2016-07-26 18:46:34 -0700587void parse_node_attributes(const SkDOM& xmlDom, const SkDOM::Node* xmlNode,
fmalita28d5b722016-09-12 17:06:47 -0700588 const sk_sp<SkSVGNode>& svgNode, SkSVGIDMapper* mapper) {
fmalita6ceef3d2016-07-26 18:46:34 -0700589 const char* name, *value;
590 SkDOM::AttrIter attrIter(xmlDom, xmlNode);
591 while ((name = attrIter.next(&value))) {
fmalita28d5b722016-09-12 17:06:47 -0700592 // We're handling id attributes out of band for now.
593 if (!strcmp(name, "id")) {
594 mapper->set(SkString(value), svgNode);
595 continue;
596 }
fmalita58649cc2016-07-29 08:52:03 -0700597 set_string_attribute(svgNode, name, value);
fmalita6ceef3d2016-07-26 18:46:34 -0700598 }
599}
600
601sk_sp<SkSVGNode> construct_svg_node(const SkDOM& dom, const ConstructionContext& ctx,
602 const SkDOM::Node* xmlNode) {
603 const char* elem = dom.getName(xmlNode);
604 const SkDOM::Type elemType = dom.getType(xmlNode);
605
606 if (elemType == SkDOM::kText_Type) {
607 SkASSERT(dom.countChildren(xmlNode) == 0);
Florin Malita39fe8c82020-10-20 10:43:03 -0400608 // TODO: add type conversion helper to SkSVGNode
609 if (ctx.fParent->tag() == SkSVGTag::kText) {
610 static_cast<SkSVGText*>(ctx.fParent)->setText(SkString(dom.getName(xmlNode)));
611 }
fmalita6ceef3d2016-07-26 18:46:34 -0700612 return nullptr;
613 }
614
615 SkASSERT(elemType == SkDOM::kElement_Type);
616
617 const int tagIndex = SkStrSearch(&gTagFactories[0].fKey,
618 SkTo<int>(SK_ARRAY_COUNT(gTagFactories)),
619 elem, sizeof(gTagFactories[0]));
620 if (tagIndex < 0) {
fmalitafea704e2016-08-10 16:25:32 -0700621#if defined(SK_VERBOSE_SVG_PARSING)
fmalita6ceef3d2016-07-26 18:46:34 -0700622 SkDebugf("unhandled element: <%s>\n", elem);
fmalitafea704e2016-08-10 16:25:32 -0700623#endif
fmalita6ceef3d2016-07-26 18:46:34 -0700624 return nullptr;
625 }
626
627 SkASSERT(SkTo<size_t>(tagIndex) < SK_ARRAY_COUNT(gTagFactories));
628 sk_sp<SkSVGNode> node = gTagFactories[tagIndex].fValue();
fmalita28d5b722016-09-12 17:06:47 -0700629 parse_node_attributes(dom, xmlNode, node, ctx.fIDMapper);
fmalita6ceef3d2016-07-26 18:46:34 -0700630
631 ConstructionContext localCtx(ctx, node);
632 for (auto* child = dom.getFirstChild(xmlNode, nullptr); child;
633 child = dom.getNextSibling(child)) {
634 sk_sp<SkSVGNode> childNode = construct_svg_node(dom, localCtx, child);
635 if (childNode) {
636 node->appendChild(std::move(childNode));
637 }
638 }
639
640 return node;
641}
642
643} // anonymous namespace
644
fmalitae1baa7c2016-09-14 12:04:30 -0700645SkSVGDOM::SkSVGDOM()
646 : fContainerSize(SkSize::Make(0, 0)) {
fmalita6ceef3d2016-07-26 18:46:34 -0700647}
648
fmalitae1baa7c2016-09-14 12:04:30 -0700649sk_sp<SkSVGDOM> SkSVGDOM::MakeFromDOM(const SkDOM& xmlDom) {
650 sk_sp<SkSVGDOM> dom = sk_make_sp<SkSVGDOM>();
fmalita6ceef3d2016-07-26 18:46:34 -0700651
fmalita28d5b722016-09-12 17:06:47 -0700652 ConstructionContext ctx(&dom->fIDMapper);
fmalita6ceef3d2016-07-26 18:46:34 -0700653 dom->fRoot = construct_svg_node(xmlDom, ctx, xmlDom.getRootNode());
654
fmalitae1baa7c2016-09-14 12:04:30 -0700655 // Reset the default container size to match the intrinsic SVG size.
656 dom->setContainerSize(dom->intrinsicSize());
657
fmalita6ceef3d2016-07-26 18:46:34 -0700658 return dom;
659}
660
fmalitae1baa7c2016-09-14 12:04:30 -0700661sk_sp<SkSVGDOM> SkSVGDOM::MakeFromStream(SkStream& svgStream) {
fmalita6ceef3d2016-07-26 18:46:34 -0700662 SkDOM xmlDom;
663 if (!xmlDom.build(svgStream)) {
664 return nullptr;
665 }
666
fmalitae1baa7c2016-09-14 12:04:30 -0700667 return MakeFromDOM(xmlDom);
fmalita6ceef3d2016-07-26 18:46:34 -0700668}
669
670void SkSVGDOM::render(SkCanvas* canvas) const {
671 if (fRoot) {
Florin Malitaebca0dd2017-09-09 09:39:07 -0400672 SkSVGLengthContext lctx(fContainerSize);
673 SkSVGPresentationContext pctx;
Tyler Denniston53281c72020-10-22 15:54:24 -0400674 fRoot->render(SkSVGRenderContext(canvas, fIDMapper, lctx, pctx, nullptr));
fmalita6ceef3d2016-07-26 18:46:34 -0700675 }
676}
677
fmalitae1baa7c2016-09-14 12:04:30 -0700678SkSize SkSVGDOM::intrinsicSize() const {
679 if (!fRoot || fRoot->tag() != SkSVGTag::kSvg) {
680 return SkSize::Make(0, 0);
681 }
682
683 // Intrinsic sizes are never relative, so the viewport size is irrelevant.
684 const SkSVGLengthContext lctx(SkSize::Make(0, 0));
685 return static_cast<const SkSVGSVG*>(fRoot.get())->intrinsicSize(lctx);
686}
687
688const SkSize& SkSVGDOM::containerSize() const {
689 return fContainerSize;
690}
691
fmalita6ceef3d2016-07-26 18:46:34 -0700692void SkSVGDOM::setContainerSize(const SkSize& containerSize) {
693 // TODO: inval
694 fContainerSize = containerSize;
695}
fmalitaca39d712016-08-12 13:17:11 -0700696
Tyler Freemanc9911522020-05-08 13:23:10 -0700697sk_sp<SkSVGNode>* SkSVGDOM::findNodeById(const char* id) {
698 SkString idStr(id);
699 return this->fIDMapper.find(idStr);
700}
701
fmalitaca39d712016-08-12 13:17:11 -0700702void SkSVGDOM::setRoot(sk_sp<SkSVGNode> root) {
703 fRoot = std::move(root);
704}
Tyler Freemanc9911522020-05-08 13:23:10 -0700705
706// TODO(fuego): move this to SkSVGNode or its own CU.
707bool SkSVGNode::setAttribute(const char* attributeName, const char* attributeValue) {
708 return set_string_attribute(sk_ref_sp(this), attributeName, attributeValue);
709}