blob: 2c3d1da4b567aaa66a3a38e51b118f904a09a741 [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 Dennistondf208a32020-10-30 16:01:54 -040018#include "modules/svg/include/SkSVGFilter.h"
Florin Malitab3418102020-10-15 18:10:29 -040019#include "modules/svg/include/SkSVGG.h"
20#include "modules/svg/include/SkSVGLine.h"
21#include "modules/svg/include/SkSVGLinearGradient.h"
22#include "modules/svg/include/SkSVGNode.h"
23#include "modules/svg/include/SkSVGPath.h"
24#include "modules/svg/include/SkSVGPattern.h"
25#include "modules/svg/include/SkSVGPoly.h"
26#include "modules/svg/include/SkSVGRadialGradient.h"
27#include "modules/svg/include/SkSVGRect.h"
28#include "modules/svg/include/SkSVGRenderContext.h"
29#include "modules/svg/include/SkSVGSVG.h"
30#include "modules/svg/include/SkSVGStop.h"
31#include "modules/svg/include/SkSVGText.h"
32#include "modules/svg/include/SkSVGTypes.h"
33#include "modules/svg/include/SkSVGUse.h"
34#include "modules/svg/include/SkSVGValue.h"
Ben Wagner8bd6e8f2019-05-15 09:28:52 -040035#include "src/core/SkTSearch.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050036#include "src/xml/SkDOM.h"
fmalita6ceef3d2016-07-26 18:46:34 -070037
38namespace {
39
fmalita6ceef3d2016-07-26 18:46:34 -070040bool SetPaintAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
41 const char* stringValue) {
fmalita2d961e02016-08-11 09:16:29 -070042 SkSVGPaint paint;
fmalitabffc2562016-08-03 10:21:11 -070043 SkSVGAttributeParser parser(stringValue);
fmalita2d961e02016-08-11 09:16:29 -070044 if (!parser.parsePaint(&paint)) {
fmalita28d5b722016-09-12 17:06:47 -070045 return false;
fmalitabffc2562016-08-03 10:21:11 -070046 }
47
Florin Malitaf4403e72020-04-10 14:14:04 +000048 node->setAttribute(attr, SkSVGPaintValue(paint));
fmalita6ceef3d2016-07-26 18:46:34 -070049 return true;
50}
51
fmalita28d5b722016-09-12 17:06:47 -070052bool SetColorAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
53 const char* stringValue) {
54 SkSVGColorType color;
55 SkSVGAttributeParser parser(stringValue);
56 if (!parser.parseColor(&color)) {
57 return false;
58 }
59
Florin Malitaf4403e72020-04-10 14:14:04 +000060 node->setAttribute(attr, SkSVGColorValue(color));
fmalita28d5b722016-09-12 17:06:47 -070061 return true;
62}
63
64bool SetIRIAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
65 const char* stringValue) {
66 SkSVGStringType iri;
67 SkSVGAttributeParser parser(stringValue);
68 if (!parser.parseIRI(&iri)) {
69 return false;
70 }
71
Florin Malitaf4403e72020-04-10 14:14:04 +000072 node->setAttribute(attr, SkSVGStringValue(iri));
fmalita28d5b722016-09-12 17:06:47 -070073 return true;
74}
75
Florin Malitace8840e2016-12-08 09:26:47 -050076bool SetClipPathAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
77 const char* stringValue) {
78 SkSVGClip clip;
79 SkSVGAttributeParser parser(stringValue);
80 if (!parser.parseClipPath(&clip)) {
81 return false;
82 }
83
Florin Malitaf4403e72020-04-10 14:14:04 +000084 node->setAttribute(attr, SkSVGClipValue(clip));
Florin Malitace8840e2016-12-08 09:26:47 -050085 return true;
86}
87
88
fmalita6ceef3d2016-07-26 18:46:34 -070089bool SetPathDataAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
90 const char* stringValue) {
91 SkPath path;
92 if (!SkParsePath::FromSVGString(stringValue, &path)) {
93 return false;
94 }
95
Florin Malitaf4403e72020-04-10 14:14:04 +000096 node->setAttribute(attr, SkSVGPathValue(path));
fmalita6ceef3d2016-07-26 18:46:34 -070097 return true;
98}
99
Xavier Phane29cdaf2020-03-26 16:15:14 +0000100bool SetStringAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
101 const char* stringValue) {
102 SkString str(stringValue, strlen(stringValue));
103 SkSVGStringType strType = SkSVGStringType(str);
Florin Malitaf4403e72020-04-10 14:14:04 +0000104 node->setAttribute(attr, SkSVGStringValue(strType));
Xavier Phane29cdaf2020-03-26 16:15:14 +0000105 return true;
106}
107
fmalita6ceef3d2016-07-26 18:46:34 -0700108bool SetTransformAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
109 const char* stringValue) {
fmalitac97796b2016-08-08 12:58:57 -0700110 SkSVGTransformType transform;
111 SkSVGAttributeParser parser(stringValue);
112 if (!parser.parseTransform(&transform)) {
113 return false;
114 }
115
Florin Malitaf4403e72020-04-10 14:14:04 +0000116 node->setAttribute(attr, SkSVGTransformValue(transform));
fmalita6ceef3d2016-07-26 18:46:34 -0700117 return true;
118}
119
fmalitabffc2562016-08-03 10:21:11 -0700120bool SetLengthAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
121 const char* stringValue) {
122 SkSVGLength length;
123 SkSVGAttributeParser parser(stringValue);
124 if (!parser.parseLength(&length)) {
125 return false;
126 }
127
Florin Malitaf4403e72020-04-10 14:14:04 +0000128 node->setAttribute(attr, SkSVGLengthValue(length));
fmalitabffc2562016-08-03 10:21:11 -0700129 return true;
130}
131
fmalita2d961e02016-08-11 09:16:29 -0700132bool SetNumberAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
133 const char* stringValue) {
134 SkSVGNumberType number;
135 SkSVGAttributeParser parser(stringValue);
136 if (!parser.parseNumber(&number)) {
137 return false;
138 }
139
Florin Malitaf4403e72020-04-10 14:14:04 +0000140 node->setAttribute(attr, SkSVGNumberValue(number));
fmalita2d961e02016-08-11 09:16:29 -0700141 return true;
142}
143
fmalita397a5172016-08-08 11:38:55 -0700144bool SetViewBoxAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
145 const char* stringValue) {
146 SkSVGViewBoxType viewBox;
147 SkSVGAttributeParser parser(stringValue);
148 if (!parser.parseViewBox(&viewBox)) {
149 return false;
150 }
151
Florin Malitaf4403e72020-04-10 14:14:04 +0000152 node->setAttribute(attr, SkSVGViewBoxValue(viewBox));
fmalita397a5172016-08-08 11:38:55 -0700153 return true;
154}
155
fmalita2d961e02016-08-11 09:16:29 -0700156bool SetLineCapAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
157 const char* stringValue) {
158 SkSVGLineCap lineCap;
159 SkSVGAttributeParser parser(stringValue);
160 if (!parser.parseLineCap(&lineCap)) {
161 return false;
162 }
163
Florin Malitaf4403e72020-04-10 14:14:04 +0000164 node->setAttribute(attr, SkSVGLineCapValue(lineCap));
fmalita2d961e02016-08-11 09:16:29 -0700165 return true;
166}
167
168bool SetLineJoinAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
169 const char* stringValue) {
170 SkSVGLineJoin lineJoin;
171 SkSVGAttributeParser parser(stringValue);
172 if (!parser.parseLineJoin(&lineJoin)) {
173 return false;
174 }
175
Florin Malitaf4403e72020-04-10 14:14:04 +0000176 node->setAttribute(attr, SkSVGLineJoinValue(lineJoin));
fmalita2d961e02016-08-11 09:16:29 -0700177 return true;
178}
179
fmalitacecd6172016-09-13 12:56:11 -0700180bool SetSpreadMethodAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
181 const char* stringValue) {
182 SkSVGSpreadMethod spread;
183 SkSVGAttributeParser parser(stringValue);
184 if (!parser.parseSpreadMethod(&spread)) {
185 return false;
186 }
187
Florin Malitaf4403e72020-04-10 14:14:04 +0000188 node->setAttribute(attr, SkSVGSpreadMethodValue(spread));
fmalitacecd6172016-09-13 12:56:11 -0700189 return true;
190}
191
Tyler Denniston308c0722020-04-14 10:53:41 -0400192bool SetStopColorAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
193 const char* stringValue) {
194 SkSVGStopColor stopColor;
195 SkSVGAttributeParser parser(stringValue);
196 if (!parser.parseStopColor(&stopColor)) {
197 return false;
198 }
199
200 node->setAttribute(attr, SkSVGStopColorValue(stopColor));
201 return true;
202}
203
Tyler Denniston30e327e2020-10-29 16:29:22 -0400204bool SetObjectBoundingBoxUnitsAttribute(const sk_sp<SkSVGNode>& node,
205 SkSVGAttribute attr,
206 const char* stringValue) {
207 SkSVGObjectBoundingBoxUnits objectBoundingBoxUnits;
Tyler Dennistonab76ab42020-10-21 15:08:45 -0400208 SkSVGAttributeParser parser(stringValue);
Tyler Denniston30e327e2020-10-29 16:29:22 -0400209 if (!parser.parseObjectBoundingBoxUnits(&objectBoundingBoxUnits)) {
Tyler Dennistonab76ab42020-10-21 15:08:45 -0400210 return false;
211 }
212
Tyler Denniston30e327e2020-10-29 16:29:22 -0400213 node->setAttribute(attr, SkSVGObjectBoundingBoxUnitsValue(objectBoundingBoxUnits));
Tyler Dennistonab76ab42020-10-21 15:08:45 -0400214 return true;
215}
216
fmalita5b31f322016-08-12 12:15:33 -0700217bool SetPointsAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
218 const char* stringValue) {
219 SkSVGPointsType points;
220 SkSVGAttributeParser parser(stringValue);
221 if (!parser.parsePoints(&points)) {
222 return false;
223 }
224
Florin Malitaf4403e72020-04-10 14:14:04 +0000225 node->setAttribute(attr, SkSVGPointsValue(points));
fmalita5b31f322016-08-12 12:15:33 -0700226 return true;
227}
228
Florin Malitae932d4b2016-12-01 13:35:11 -0500229bool SetFillRuleAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
230 const char* stringValue) {
231 SkSVGFillRule fillRule;
232 SkSVGAttributeParser parser(stringValue);
233 if (!parser.parseFillRule(&fillRule)) {
234 return false;
235 }
236
Florin Malitaf4403e72020-04-10 14:14:04 +0000237 node->setAttribute(attr, SkSVGFillRuleValue(fillRule));
Florin Malitae932d4b2016-12-01 13:35:11 -0500238 return true;
239}
240
Tyler Dennistonb3cafbc2020-10-30 15:00:48 -0400241bool SetFilterAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
242 const char* stringValue) {
243 SkSVGFilterType filter;
244 SkSVGAttributeParser parser(stringValue);
245 if (!parser.parseFilter(&filter)) {
246 return false;
247 }
248
249 node->setAttribute(attr, SkSVGFilterValue(filter));
250 return true;
251}
252
Florin Malitaffe6ae42017-10-12 11:33:28 -0400253bool SetVisibilityAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
254 const char* stringValue) {
255 SkSVGVisibility visibility;
256 SkSVGAttributeParser parser(stringValue);
257 if (!parser.parseVisibility(&visibility)) {
258 return false;
259 }
260
Florin Malitaf4403e72020-04-10 14:14:04 +0000261 node->setAttribute(attr, SkSVGVisibilityValue(visibility));
Florin Malitaffe6ae42017-10-12 11:33:28 -0400262 return true;
263}
264
Florin Malitaf543a602017-10-13 14:07:44 -0400265bool SetDashArrayAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
266 const char* stringValue) {
267 SkSVGDashArray dashArray;
268 SkSVGAttributeParser parser(stringValue);
269 if (!parser.parseDashArray(&dashArray)) {
270 return false;
271 }
272
Florin Malitaf4403e72020-04-10 14:14:04 +0000273 node->setAttribute(attr, SkSVGDashArrayValue(dashArray));
Florin Malitaf543a602017-10-13 14:07:44 -0400274 return true;
275}
276
Florin Malita39fe8c82020-10-20 10:43:03 -0400277bool SetFontFamilyAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
278 const char* stringValue) {
279 SkSVGFontFamily family;
280 SkSVGAttributeParser parser(stringValue);
281 if (!parser.parseFontFamily(&family)) {
282 return false;
283 }
284
285 node->setAttribute(attr, SkSVGFontFamilyValue(family));
286 return true;
287}
288
289bool SetFontSizeAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
290 const char* stringValue) {
291 SkSVGFontSize size;
292 SkSVGAttributeParser parser(stringValue);
293 if (!parser.parseFontSize(&size)) {
294 return false;
295 }
296
297 node->setAttribute(attr, SkSVGFontSizeValue(size));
298 return true;
299}
300
301bool SetFontStyleAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
302 const char* stringValue) {
303 SkSVGFontStyle style;
304 SkSVGAttributeParser parser(stringValue);
305 if (!parser.parseFontStyle(&style)) {
306 return false;
307 }
308
309 node->setAttribute(attr, SkSVGFontStyleValue(style));
310 return true;
311}
312
313bool SetFontWeightAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
314 const char* stringValue) {
315 SkSVGFontWeight weight;
316 SkSVGAttributeParser parser(stringValue);
317 if (!parser.parseFontWeight(&weight)) {
318 return false;
319 }
320
321 node->setAttribute(attr, SkSVGFontWeightValue(weight));
322 return true;
323}
324
Florin Malita056385b2020-10-27 22:57:56 -0400325bool SetTextAnchorAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
326 const char* stringValue) {
327 SkSVGTextAnchor anchor;
328 SkSVGAttributeParser parser(stringValue);
329
330 if (!parser.parseTextAnchor(&anchor)) {
331 return false;
332 }
333
334 node->setAttribute(attr, SkSVGTextAnchorValue(anchor));
335 return true;
336}
337
Florin Malita385e7442020-10-21 16:55:46 -0400338bool SetPreserveAspectRatioAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
339 const char* stringValue) {
340 SkSVGPreserveAspectRatio par;
341 SkSVGAttributeParser parser(stringValue);
342 if (!parser.parsePreserveAspectRatio(&par)) {
343 return false;
344 }
345
346 node->setAttribute(attr, SkSVGPreserveAspectRatioValue(par));
347 return true;
348}
349
fmalita61f36b32016-08-08 13:58:50 -0700350SkString TrimmedString(const char* first, const char* last) {
351 SkASSERT(first);
352 SkASSERT(last);
353 SkASSERT(first <= last);
354
355 while (first <= last && *first <= ' ') { first++; }
356 while (first <= last && *last <= ' ') { last--; }
357
358 SkASSERT(last - first + 1 >= 0);
359 return SkString(first, SkTo<size_t>(last - first + 1));
360}
361
fmalita58649cc2016-07-29 08:52:03 -0700362// Breaks a "foo: bar; baz: ..." string into key:value pairs.
363class StyleIterator {
364public:
365 StyleIterator(const char* str) : fPos(str) { }
366
367 std::tuple<SkString, SkString> next() {
368 SkString name, value;
369
370 if (fPos) {
371 const char* sep = this->nextSeparator();
372 SkASSERT(*sep == ';' || *sep == '\0');
373
374 const char* valueSep = strchr(fPos, ':');
375 if (valueSep && valueSep < sep) {
fmalita61f36b32016-08-08 13:58:50 -0700376 name = TrimmedString(fPos, valueSep - 1);
377 value = TrimmedString(valueSep + 1, sep - 1);
fmalita58649cc2016-07-29 08:52:03 -0700378 }
379
380 fPos = *sep ? sep + 1 : nullptr;
381 }
382
383 return std::make_tuple(name, value);
384 }
385
386private:
387 const char* nextSeparator() const {
388 const char* sep = fPos;
389 while (*sep != ';' && *sep != '\0') {
390 sep++;
391 }
392 return sep;
393 }
394
395 const char* fPos;
396};
397
Tyler Freemanc9911522020-05-08 13:23:10 -0700398bool set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value);
fmalita58649cc2016-07-29 08:52:03 -0700399
400bool SetStyleAttributes(const sk_sp<SkSVGNode>& node, SkSVGAttribute,
401 const char* stringValue) {
402
403 SkString name, value;
404 StyleIterator iter(stringValue);
405 for (;;) {
406 std::tie(name, value) = iter.next();
407 if (name.isEmpty()) {
408 break;
409 }
410 set_string_attribute(node, name.c_str(), value.c_str());
411 }
412
413 return true;
414}
415
fmalita6ceef3d2016-07-26 18:46:34 -0700416template<typename T>
417struct SortedDictionaryEntry {
418 const char* fKey;
419 const T fValue;
420};
421
422struct AttrParseInfo {
423 SkSVGAttribute fAttr;
424 bool (*fSetter)(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, const char* stringValue);
425};
426
427SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
Florin Malita385e7442020-10-21 16:55:46 -0400428 { "clip-path" , { SkSVGAttribute::kClipPath , SetClipPathAttribute }},
429 { "clip-rule" , { SkSVGAttribute::kClipRule , SetFillRuleAttribute }},
430 { "color" , { SkSVGAttribute::kColor , SetColorAttribute }},
431 { "cx" , { SkSVGAttribute::kCx , SetLengthAttribute }},
432 { "cy" , { SkSVGAttribute::kCy , SetLengthAttribute }},
433 { "d" , { SkSVGAttribute::kD , SetPathDataAttribute }},
434 { "fill" , { SkSVGAttribute::kFill , SetPaintAttribute }},
435 { "fill-opacity" , { SkSVGAttribute::kFillOpacity , SetNumberAttribute }},
436 { "fill-rule" , { SkSVGAttribute::kFillRule , SetFillRuleAttribute }},
Tyler Dennistonb3cafbc2020-10-30 15:00:48 -0400437 { "filter" , { SkSVGAttribute::kFilter , SetFilterAttribute }},
Tyler Dennistondf208a32020-10-30 16:01:54 -0400438 { "filterUnits" , { SkSVGAttribute::kFilterUnits ,
439 SetObjectBoundingBoxUnitsAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400440 { "font-family" , { SkSVGAttribute::kFontFamily , SetFontFamilyAttribute }},
441 { "font-size" , { SkSVGAttribute::kFontSize , SetFontSizeAttribute }},
442 { "font-style" , { SkSVGAttribute::kFontStyle , SetFontStyleAttribute }},
443 { "font-weight" , { SkSVGAttribute::kFontWeight , SetFontWeightAttribute }},
Florin Malitacc6cc292017-10-09 16:05:30 -0400444 // focal point x & y
Florin Malita385e7442020-10-21 16:55:46 -0400445 { "fx" , { SkSVGAttribute::kFx , SetLengthAttribute }},
446 { "fy" , { SkSVGAttribute::kFy , SetLengthAttribute }},
447 { "gradientTransform" , { SkSVGAttribute::kGradientTransform, SetTransformAttribute }},
Tyler Denniston30e327e2020-10-29 16:29:22 -0400448 { "gradientUnits" , { SkSVGAttribute::kGradientUnits ,
449 SetObjectBoundingBoxUnitsAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400450 { "height" , { SkSVGAttribute::kHeight , SetLengthAttribute }},
451 { "offset" , { SkSVGAttribute::kOffset , SetLengthAttribute }},
452 { "opacity" , { SkSVGAttribute::kOpacity , SetNumberAttribute }},
453 { "patternTransform" , { SkSVGAttribute::kPatternTransform , SetTransformAttribute }},
454 { "points" , { SkSVGAttribute::kPoints , SetPointsAttribute }},
455 { "preserveAspectRatio", { SkSVGAttribute::kPreserveAspectRatio,
456 SetPreserveAspectRatioAttribute }},
457 { "r" , { SkSVGAttribute::kR , SetLengthAttribute }},
458 { "rx" , { SkSVGAttribute::kRx , SetLengthAttribute }},
459 { "ry" , { SkSVGAttribute::kRy , SetLengthAttribute }},
460 { "spreadMethod" , { SkSVGAttribute::kSpreadMethod , SetSpreadMethodAttribute }},
461 { "stop-color" , { SkSVGAttribute::kStopColor , SetStopColorAttribute }},
462 { "stop-opacity" , { SkSVGAttribute::kStopOpacity , SetNumberAttribute }},
463 { "stroke" , { SkSVGAttribute::kStroke , SetPaintAttribute }},
464 { "stroke-dasharray" , { SkSVGAttribute::kStrokeDashArray , SetDashArrayAttribute }},
465 { "stroke-dashoffset" , { SkSVGAttribute::kStrokeDashOffset , SetLengthAttribute }},
466 { "stroke-linecap" , { SkSVGAttribute::kStrokeLineCap , SetLineCapAttribute }},
467 { "stroke-linejoin" , { SkSVGAttribute::kStrokeLineJoin , SetLineJoinAttribute }},
468 { "stroke-miterlimit" , { SkSVGAttribute::kStrokeMiterLimit , SetNumberAttribute }},
469 { "stroke-opacity" , { SkSVGAttribute::kStrokeOpacity , SetNumberAttribute }},
470 { "stroke-width" , { SkSVGAttribute::kStrokeWidth , SetLengthAttribute }},
471 { "style" , { SkSVGAttribute::kUnknown , SetStyleAttributes }},
472 { "text" , { SkSVGAttribute::kText , SetStringAttribute }},
Florin Malita056385b2020-10-27 22:57:56 -0400473 { "text-anchor" , { SkSVGAttribute::kTextAnchor , SetTextAnchorAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400474 { "transform" , { SkSVGAttribute::kTransform , SetTransformAttribute }},
475 { "viewBox" , { SkSVGAttribute::kViewBox , SetViewBoxAttribute }},
476 { "visibility" , { SkSVGAttribute::kVisibility , SetVisibilityAttribute }},
477 { "width" , { SkSVGAttribute::kWidth , SetLengthAttribute }},
478 { "x" , { SkSVGAttribute::kX , SetLengthAttribute }},
479 { "x1" , { SkSVGAttribute::kX1 , SetLengthAttribute }},
480 { "x2" , { SkSVGAttribute::kX2 , SetLengthAttribute }},
481 { "xlink:href" , { SkSVGAttribute::kHref , SetIRIAttribute }},
482 { "y" , { SkSVGAttribute::kY , SetLengthAttribute }},
483 { "y1" , { SkSVGAttribute::kY1 , SetLengthAttribute }},
484 { "y2" , { SkSVGAttribute::kY2 , SetLengthAttribute }},
fmalita6ceef3d2016-07-26 18:46:34 -0700485};
486
487SortedDictionaryEntry<sk_sp<SkSVGNode>(*)()> gTagFactories[] = {
Florin Malitaf6143ff2017-10-10 09:16:52 -0400488 { "a" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700489 { "circle" , []() -> sk_sp<SkSVGNode> { return SkSVGCircle::Make(); }},
Florin Malitace8840e2016-12-08 09:26:47 -0500490 { "clipPath" , []() -> sk_sp<SkSVGNode> { return SkSVGClipPath::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700491 { "defs" , []() -> sk_sp<SkSVGNode> { return SkSVGDefs::Make(); }},
492 { "ellipse" , []() -> sk_sp<SkSVGNode> { return SkSVGEllipse::Make(); }},
Tyler Dennistondf208a32020-10-30 16:01:54 -0400493 { "filter" , []() -> sk_sp<SkSVGNode> { return SkSVGFilter::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700494 { "g" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
495 { "line" , []() -> sk_sp<SkSVGNode> { return SkSVGLine::Make(); }},
496 { "linearGradient", []() -> sk_sp<SkSVGNode> { return SkSVGLinearGradient::Make(); }},
497 { "path" , []() -> sk_sp<SkSVGNode> { return SkSVGPath::Make(); }},
Florin Malita1aa1bb62017-10-11 14:34:33 -0400498 { "pattern" , []() -> sk_sp<SkSVGNode> { return SkSVGPattern::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700499 { "polygon" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolygon(); }},
500 { "polyline" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolyline(); }},
Florin Malitacc6cc292017-10-09 16:05:30 -0400501 { "radialGradient", []() -> sk_sp<SkSVGNode> { return SkSVGRadialGradient::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700502 { "rect" , []() -> sk_sp<SkSVGNode> { return SkSVGRect::Make(); }},
503 { "stop" , []() -> sk_sp<SkSVGNode> { return SkSVGStop::Make(); }},
504 { "svg" , []() -> sk_sp<SkSVGNode> { return SkSVGSVG::Make(); }},
Xavier Phane29cdaf2020-03-26 16:15:14 +0000505 { "text" , []() -> sk_sp<SkSVGNode> { return SkSVGText::Make(); }},
Florin Malita6a69c052017-10-11 14:02:11 -0400506 { "use" , []() -> sk_sp<SkSVGNode> { return SkSVGUse::Make(); }},
fmalita6ceef3d2016-07-26 18:46:34 -0700507};
508
509struct ConstructionContext {
fmalita28d5b722016-09-12 17:06:47 -0700510 ConstructionContext(SkSVGIDMapper* mapper) : fParent(nullptr), fIDMapper(mapper) {}
fmalita6ceef3d2016-07-26 18:46:34 -0700511 ConstructionContext(const ConstructionContext& other, const sk_sp<SkSVGNode>& newParent)
fmalita28d5b722016-09-12 17:06:47 -0700512 : fParent(newParent.get()), fIDMapper(other.fIDMapper) {}
fmalita6ceef3d2016-07-26 18:46:34 -0700513
Florin Malita39fe8c82020-10-20 10:43:03 -0400514 SkSVGNode* fParent;
515 SkSVGIDMapper* fIDMapper;
fmalita6ceef3d2016-07-26 18:46:34 -0700516};
517
Tyler Freemanc9911522020-05-08 13:23:10 -0700518bool set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value) {
fmalita58649cc2016-07-29 08:52:03 -0700519 const int attrIndex = SkStrSearch(&gAttributeParseInfo[0].fKey,
520 SkTo<int>(SK_ARRAY_COUNT(gAttributeParseInfo)),
521 name, sizeof(gAttributeParseInfo[0]));
522 if (attrIndex < 0) {
fmalitafea704e2016-08-10 16:25:32 -0700523#if defined(SK_VERBOSE_SVG_PARSING)
fmalita58649cc2016-07-29 08:52:03 -0700524 SkDebugf("unhandled attribute: %s\n", name);
fmalitafea704e2016-08-10 16:25:32 -0700525#endif
Tyler Freemanc9911522020-05-08 13:23:10 -0700526 return false;
fmalita58649cc2016-07-29 08:52:03 -0700527 }
528
529 SkASSERT(SkTo<size_t>(attrIndex) < SK_ARRAY_COUNT(gAttributeParseInfo));
530 const auto& attrInfo = gAttributeParseInfo[attrIndex].fValue;
531 if (!attrInfo.fSetter(node, attrInfo.fAttr, value)) {
fmalitafea704e2016-08-10 16:25:32 -0700532#if defined(SK_VERBOSE_SVG_PARSING)
fmalita58649cc2016-07-29 08:52:03 -0700533 SkDebugf("could not parse attribute: '%s=\"%s\"'\n", name, value);
fmalitafea704e2016-08-10 16:25:32 -0700534#endif
Tyler Freemanc9911522020-05-08 13:23:10 -0700535 return false;
fmalita58649cc2016-07-29 08:52:03 -0700536 }
Tyler Freemanc9911522020-05-08 13:23:10 -0700537
538 return true;
fmalita58649cc2016-07-29 08:52:03 -0700539}
540
fmalita6ceef3d2016-07-26 18:46:34 -0700541void parse_node_attributes(const SkDOM& xmlDom, const SkDOM::Node* xmlNode,
fmalita28d5b722016-09-12 17:06:47 -0700542 const sk_sp<SkSVGNode>& svgNode, SkSVGIDMapper* mapper) {
fmalita6ceef3d2016-07-26 18:46:34 -0700543 const char* name, *value;
544 SkDOM::AttrIter attrIter(xmlDom, xmlNode);
545 while ((name = attrIter.next(&value))) {
fmalita28d5b722016-09-12 17:06:47 -0700546 // We're handling id attributes out of band for now.
547 if (!strcmp(name, "id")) {
548 mapper->set(SkString(value), svgNode);
549 continue;
550 }
fmalita58649cc2016-07-29 08:52:03 -0700551 set_string_attribute(svgNode, name, value);
fmalita6ceef3d2016-07-26 18:46:34 -0700552 }
553}
554
555sk_sp<SkSVGNode> construct_svg_node(const SkDOM& dom, const ConstructionContext& ctx,
556 const SkDOM::Node* xmlNode) {
557 const char* elem = dom.getName(xmlNode);
558 const SkDOM::Type elemType = dom.getType(xmlNode);
559
560 if (elemType == SkDOM::kText_Type) {
561 SkASSERT(dom.countChildren(xmlNode) == 0);
Florin Malita39fe8c82020-10-20 10:43:03 -0400562 // TODO: add type conversion helper to SkSVGNode
563 if (ctx.fParent->tag() == SkSVGTag::kText) {
564 static_cast<SkSVGText*>(ctx.fParent)->setText(SkString(dom.getName(xmlNode)));
565 }
fmalita6ceef3d2016-07-26 18:46:34 -0700566 return nullptr;
567 }
568
569 SkASSERT(elemType == SkDOM::kElement_Type);
570
571 const int tagIndex = SkStrSearch(&gTagFactories[0].fKey,
572 SkTo<int>(SK_ARRAY_COUNT(gTagFactories)),
573 elem, sizeof(gTagFactories[0]));
574 if (tagIndex < 0) {
fmalitafea704e2016-08-10 16:25:32 -0700575#if defined(SK_VERBOSE_SVG_PARSING)
fmalita6ceef3d2016-07-26 18:46:34 -0700576 SkDebugf("unhandled element: <%s>\n", elem);
fmalitafea704e2016-08-10 16:25:32 -0700577#endif
fmalita6ceef3d2016-07-26 18:46:34 -0700578 return nullptr;
579 }
580
581 SkASSERT(SkTo<size_t>(tagIndex) < SK_ARRAY_COUNT(gTagFactories));
582 sk_sp<SkSVGNode> node = gTagFactories[tagIndex].fValue();
fmalita28d5b722016-09-12 17:06:47 -0700583 parse_node_attributes(dom, xmlNode, node, ctx.fIDMapper);
fmalita6ceef3d2016-07-26 18:46:34 -0700584
585 ConstructionContext localCtx(ctx, node);
586 for (auto* child = dom.getFirstChild(xmlNode, nullptr); child;
587 child = dom.getNextSibling(child)) {
588 sk_sp<SkSVGNode> childNode = construct_svg_node(dom, localCtx, child);
589 if (childNode) {
590 node->appendChild(std::move(childNode));
591 }
592 }
593
594 return node;
595}
596
597} // anonymous namespace
598
fmalitae1baa7c2016-09-14 12:04:30 -0700599SkSVGDOM::SkSVGDOM()
600 : fContainerSize(SkSize::Make(0, 0)) {
fmalita6ceef3d2016-07-26 18:46:34 -0700601}
602
fmalitae1baa7c2016-09-14 12:04:30 -0700603sk_sp<SkSVGDOM> SkSVGDOM::MakeFromDOM(const SkDOM& xmlDom) {
604 sk_sp<SkSVGDOM> dom = sk_make_sp<SkSVGDOM>();
fmalita6ceef3d2016-07-26 18:46:34 -0700605
fmalita28d5b722016-09-12 17:06:47 -0700606 ConstructionContext ctx(&dom->fIDMapper);
fmalita6ceef3d2016-07-26 18:46:34 -0700607 dom->fRoot = construct_svg_node(xmlDom, ctx, xmlDom.getRootNode());
608
fmalitae1baa7c2016-09-14 12:04:30 -0700609 // Reset the default container size to match the intrinsic SVG size.
610 dom->setContainerSize(dom->intrinsicSize());
611
fmalita6ceef3d2016-07-26 18:46:34 -0700612 return dom;
613}
614
fmalitae1baa7c2016-09-14 12:04:30 -0700615sk_sp<SkSVGDOM> SkSVGDOM::MakeFromStream(SkStream& svgStream) {
fmalita6ceef3d2016-07-26 18:46:34 -0700616 SkDOM xmlDom;
617 if (!xmlDom.build(svgStream)) {
618 return nullptr;
619 }
620
fmalitae1baa7c2016-09-14 12:04:30 -0700621 return MakeFromDOM(xmlDom);
fmalita6ceef3d2016-07-26 18:46:34 -0700622}
623
624void SkSVGDOM::render(SkCanvas* canvas) const {
625 if (fRoot) {
Florin Malitaebca0dd2017-09-09 09:39:07 -0400626 SkSVGLengthContext lctx(fContainerSize);
627 SkSVGPresentationContext pctx;
Tyler Denniston53281c72020-10-22 15:54:24 -0400628 fRoot->render(SkSVGRenderContext(canvas, fIDMapper, lctx, pctx, nullptr));
fmalita6ceef3d2016-07-26 18:46:34 -0700629 }
630}
631
fmalitae1baa7c2016-09-14 12:04:30 -0700632SkSize SkSVGDOM::intrinsicSize() const {
633 if (!fRoot || fRoot->tag() != SkSVGTag::kSvg) {
634 return SkSize::Make(0, 0);
635 }
636
637 // Intrinsic sizes are never relative, so the viewport size is irrelevant.
638 const SkSVGLengthContext lctx(SkSize::Make(0, 0));
639 return static_cast<const SkSVGSVG*>(fRoot.get())->intrinsicSize(lctx);
640}
641
642const SkSize& SkSVGDOM::containerSize() const {
643 return fContainerSize;
644}
645
fmalita6ceef3d2016-07-26 18:46:34 -0700646void SkSVGDOM::setContainerSize(const SkSize& containerSize) {
647 // TODO: inval
648 fContainerSize = containerSize;
649}
fmalitaca39d712016-08-12 13:17:11 -0700650
Tyler Freemanc9911522020-05-08 13:23:10 -0700651sk_sp<SkSVGNode>* SkSVGDOM::findNodeById(const char* id) {
652 SkString idStr(id);
653 return this->fIDMapper.find(idStr);
654}
655
fmalitaca39d712016-08-12 13:17:11 -0700656void SkSVGDOM::setRoot(sk_sp<SkSVGNode> root) {
657 fRoot = std::move(root);
658}
Tyler Freemanc9911522020-05-08 13:23:10 -0700659
660// TODO(fuego): move this to SkSVGNode or its own CU.
661bool SkSVGNode::setAttribute(const char* attributeName, const char* attributeValue) {
662 return set_string_attribute(sk_ref_sp(this), attributeName, attributeValue);
663}