blob: 790d2f4d647f37b2770284ec2fd09cb07db8ec3a [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 Denniston70bb18d2020-11-06 12:07:53 -050018#include "modules/svg/include/SkSVGFeColorMatrix.h"
Tyler Dennistonb25caae2020-11-09 12:46:02 -050019#include "modules/svg/include/SkSVGFeComposite.h"
Tyler Dennistondada9602020-11-03 10:04:25 -050020#include "modules/svg/include/SkSVGFeTurbulence.h"
Tyler Dennistondf208a32020-10-30 16:01:54 -040021#include "modules/svg/include/SkSVGFilter.h"
Florin Malitab3418102020-10-15 18:10:29 -040022#include "modules/svg/include/SkSVGG.h"
23#include "modules/svg/include/SkSVGLine.h"
24#include "modules/svg/include/SkSVGLinearGradient.h"
25#include "modules/svg/include/SkSVGNode.h"
26#include "modules/svg/include/SkSVGPath.h"
27#include "modules/svg/include/SkSVGPattern.h"
28#include "modules/svg/include/SkSVGPoly.h"
29#include "modules/svg/include/SkSVGRadialGradient.h"
30#include "modules/svg/include/SkSVGRect.h"
31#include "modules/svg/include/SkSVGRenderContext.h"
32#include "modules/svg/include/SkSVGSVG.h"
33#include "modules/svg/include/SkSVGStop.h"
34#include "modules/svg/include/SkSVGText.h"
35#include "modules/svg/include/SkSVGTypes.h"
36#include "modules/svg/include/SkSVGUse.h"
37#include "modules/svg/include/SkSVGValue.h"
Ben Wagner8bd6e8f2019-05-15 09:28:52 -040038#include "src/core/SkTSearch.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050039#include "src/xml/SkDOM.h"
fmalita6ceef3d2016-07-26 18:46:34 -070040
41namespace {
42
fmalita28d5b722016-09-12 17:06:47 -070043bool SetColorAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
44 const char* stringValue) {
45 SkSVGColorType color;
46 SkSVGAttributeParser parser(stringValue);
47 if (!parser.parseColor(&color)) {
48 return false;
49 }
50
Florin Malitaf4403e72020-04-10 14:14:04 +000051 node->setAttribute(attr, SkSVGColorValue(color));
fmalita28d5b722016-09-12 17:06:47 -070052 return true;
53}
54
55bool SetIRIAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
56 const char* stringValue) {
57 SkSVGStringType iri;
58 SkSVGAttributeParser parser(stringValue);
59 if (!parser.parseIRI(&iri)) {
60 return false;
61 }
62
Florin Malitaf4403e72020-04-10 14:14:04 +000063 node->setAttribute(attr, SkSVGStringValue(iri));
fmalita28d5b722016-09-12 17:06:47 -070064 return true;
65}
66
fmalita6ceef3d2016-07-26 18:46:34 -070067bool SetPathDataAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
68 const char* stringValue) {
69 SkPath path;
70 if (!SkParsePath::FromSVGString(stringValue, &path)) {
71 return false;
72 }
73
Florin Malitaf4403e72020-04-10 14:14:04 +000074 node->setAttribute(attr, SkSVGPathValue(path));
fmalita6ceef3d2016-07-26 18:46:34 -070075 return true;
76}
77
Xavier Phane29cdaf2020-03-26 16:15:14 +000078bool SetStringAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
79 const char* stringValue) {
80 SkString str(stringValue, strlen(stringValue));
81 SkSVGStringType strType = SkSVGStringType(str);
Florin Malitaf4403e72020-04-10 14:14:04 +000082 node->setAttribute(attr, SkSVGStringValue(strType));
Xavier Phane29cdaf2020-03-26 16:15:14 +000083 return true;
84}
85
fmalita6ceef3d2016-07-26 18:46:34 -070086bool SetTransformAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
87 const char* stringValue) {
fmalitac97796b2016-08-08 12:58:57 -070088 SkSVGTransformType transform;
89 SkSVGAttributeParser parser(stringValue);
90 if (!parser.parseTransform(&transform)) {
91 return false;
92 }
93
Florin Malitaf4403e72020-04-10 14:14:04 +000094 node->setAttribute(attr, SkSVGTransformValue(transform));
fmalita6ceef3d2016-07-26 18:46:34 -070095 return true;
96}
97
fmalitabffc2562016-08-03 10:21:11 -070098bool SetLengthAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
99 const char* stringValue) {
100 SkSVGLength length;
101 SkSVGAttributeParser parser(stringValue);
102 if (!parser.parseLength(&length)) {
103 return false;
104 }
105
Florin Malitaf4403e72020-04-10 14:14:04 +0000106 node->setAttribute(attr, SkSVGLengthValue(length));
fmalitabffc2562016-08-03 10:21:11 -0700107 return true;
108}
109
fmalita2d961e02016-08-11 09:16:29 -0700110bool SetNumberAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
111 const char* stringValue) {
112 SkSVGNumberType number;
113 SkSVGAttributeParser parser(stringValue);
114 if (!parser.parseNumber(&number)) {
115 return false;
116 }
117
Florin Malitaf4403e72020-04-10 14:14:04 +0000118 node->setAttribute(attr, SkSVGNumberValue(number));
fmalita2d961e02016-08-11 09:16:29 -0700119 return true;
120}
121
fmalita397a5172016-08-08 11:38:55 -0700122bool SetViewBoxAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
123 const char* stringValue) {
124 SkSVGViewBoxType viewBox;
125 SkSVGAttributeParser parser(stringValue);
126 if (!parser.parseViewBox(&viewBox)) {
127 return false;
128 }
129
Florin Malitaf4403e72020-04-10 14:14:04 +0000130 node->setAttribute(attr, SkSVGViewBoxValue(viewBox));
fmalita397a5172016-08-08 11:38:55 -0700131 return true;
132}
133
fmalitacecd6172016-09-13 12:56:11 -0700134bool SetSpreadMethodAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
135 const char* stringValue) {
136 SkSVGSpreadMethod spread;
137 SkSVGAttributeParser parser(stringValue);
138 if (!parser.parseSpreadMethod(&spread)) {
139 return false;
140 }
141
Florin Malitaf4403e72020-04-10 14:14:04 +0000142 node->setAttribute(attr, SkSVGSpreadMethodValue(spread));
fmalitacecd6172016-09-13 12:56:11 -0700143 return true;
144}
145
Tyler Denniston308c0722020-04-14 10:53:41 -0400146bool SetStopColorAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
147 const char* stringValue) {
148 SkSVGStopColor stopColor;
149 SkSVGAttributeParser parser(stringValue);
150 if (!parser.parseStopColor(&stopColor)) {
151 return false;
152 }
153
154 node->setAttribute(attr, SkSVGStopColorValue(stopColor));
155 return true;
156}
157
Tyler Denniston30e327e2020-10-29 16:29:22 -0400158bool SetObjectBoundingBoxUnitsAttribute(const sk_sp<SkSVGNode>& node,
159 SkSVGAttribute attr,
160 const char* stringValue) {
161 SkSVGObjectBoundingBoxUnits objectBoundingBoxUnits;
Tyler Dennistonab76ab42020-10-21 15:08:45 -0400162 SkSVGAttributeParser parser(stringValue);
Tyler Denniston30e327e2020-10-29 16:29:22 -0400163 if (!parser.parseObjectBoundingBoxUnits(&objectBoundingBoxUnits)) {
Tyler Dennistonab76ab42020-10-21 15:08:45 -0400164 return false;
165 }
166
Tyler Denniston30e327e2020-10-29 16:29:22 -0400167 node->setAttribute(attr, SkSVGObjectBoundingBoxUnitsValue(objectBoundingBoxUnits));
Tyler Dennistonab76ab42020-10-21 15:08:45 -0400168 return true;
169}
170
fmalita5b31f322016-08-12 12:15:33 -0700171bool SetPointsAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
172 const char* stringValue) {
173 SkSVGPointsType points;
174 SkSVGAttributeParser parser(stringValue);
175 if (!parser.parsePoints(&points)) {
176 return false;
177 }
178
Florin Malitaf4403e72020-04-10 14:14:04 +0000179 node->setAttribute(attr, SkSVGPointsValue(points));
fmalita5b31f322016-08-12 12:15:33 -0700180 return true;
181}
182
Tyler Dennistonb3cafbc2020-10-30 15:00:48 -0400183bool SetFilterAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
184 const char* stringValue) {
185 SkSVGFilterType filter;
186 SkSVGAttributeParser parser(stringValue);
187 if (!parser.parseFilter(&filter)) {
188 return false;
189 }
190
191 node->setAttribute(attr, SkSVGFilterValue(filter));
192 return true;
193}
194
Florin Malita385e7442020-10-21 16:55:46 -0400195bool SetPreserveAspectRatioAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
196 const char* stringValue) {
197 SkSVGPreserveAspectRatio par;
198 SkSVGAttributeParser parser(stringValue);
199 if (!parser.parsePreserveAspectRatio(&par)) {
200 return false;
201 }
202
203 node->setAttribute(attr, SkSVGPreserveAspectRatioValue(par));
204 return true;
205}
206
fmalita61f36b32016-08-08 13:58:50 -0700207SkString TrimmedString(const char* first, const char* last) {
208 SkASSERT(first);
209 SkASSERT(last);
210 SkASSERT(first <= last);
211
212 while (first <= last && *first <= ' ') { first++; }
213 while (first <= last && *last <= ' ') { last--; }
214
215 SkASSERT(last - first + 1 >= 0);
216 return SkString(first, SkTo<size_t>(last - first + 1));
217}
218
fmalita58649cc2016-07-29 08:52:03 -0700219// Breaks a "foo: bar; baz: ..." string into key:value pairs.
220class StyleIterator {
221public:
222 StyleIterator(const char* str) : fPos(str) { }
223
224 std::tuple<SkString, SkString> next() {
225 SkString name, value;
226
227 if (fPos) {
228 const char* sep = this->nextSeparator();
229 SkASSERT(*sep == ';' || *sep == '\0');
230
231 const char* valueSep = strchr(fPos, ':');
232 if (valueSep && valueSep < sep) {
fmalita61f36b32016-08-08 13:58:50 -0700233 name = TrimmedString(fPos, valueSep - 1);
234 value = TrimmedString(valueSep + 1, sep - 1);
fmalita58649cc2016-07-29 08:52:03 -0700235 }
236
237 fPos = *sep ? sep + 1 : nullptr;
238 }
239
240 return std::make_tuple(name, value);
241 }
242
243private:
244 const char* nextSeparator() const {
245 const char* sep = fPos;
246 while (*sep != ';' && *sep != '\0') {
247 sep++;
248 }
249 return sep;
250 }
251
252 const char* fPos;
253};
254
Tyler Freemanc9911522020-05-08 13:23:10 -0700255bool set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value);
fmalita58649cc2016-07-29 08:52:03 -0700256
257bool SetStyleAttributes(const sk_sp<SkSVGNode>& node, SkSVGAttribute,
258 const char* stringValue) {
259
260 SkString name, value;
261 StyleIterator iter(stringValue);
262 for (;;) {
263 std::tie(name, value) = iter.next();
264 if (name.isEmpty()) {
265 break;
266 }
267 set_string_attribute(node, name.c_str(), value.c_str());
268 }
269
270 return true;
271}
272
fmalita6ceef3d2016-07-26 18:46:34 -0700273template<typename T>
274struct SortedDictionaryEntry {
275 const char* fKey;
276 const T fValue;
277};
278
279struct AttrParseInfo {
280 SkSVGAttribute fAttr;
281 bool (*fSetter)(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, const char* stringValue);
282};
283
284SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
Florin Malita385e7442020-10-21 16:55:46 -0400285 { "color" , { SkSVGAttribute::kColor , SetColorAttribute }},
286 { "cx" , { SkSVGAttribute::kCx , SetLengthAttribute }},
287 { "cy" , { SkSVGAttribute::kCy , SetLengthAttribute }},
288 { "d" , { SkSVGAttribute::kD , SetPathDataAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400289 { "fill-opacity" , { SkSVGAttribute::kFillOpacity , SetNumberAttribute }},
Tyler Dennistonb3cafbc2020-10-30 15:00:48 -0400290 { "filter" , { SkSVGAttribute::kFilter , SetFilterAttribute }},
Tyler Dennistondf208a32020-10-30 16:01:54 -0400291 { "filterUnits" , { SkSVGAttribute::kFilterUnits ,
292 SetObjectBoundingBoxUnitsAttribute }},
Florin Malitacc6cc292017-10-09 16:05:30 -0400293 // focal point x & y
Florin Malita385e7442020-10-21 16:55:46 -0400294 { "fx" , { SkSVGAttribute::kFx , SetLengthAttribute }},
295 { "fy" , { SkSVGAttribute::kFy , SetLengthAttribute }},
296 { "gradientTransform" , { SkSVGAttribute::kGradientTransform, SetTransformAttribute }},
Tyler Denniston30e327e2020-10-29 16:29:22 -0400297 { "gradientUnits" , { SkSVGAttribute::kGradientUnits ,
298 SetObjectBoundingBoxUnitsAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400299 { "height" , { SkSVGAttribute::kHeight , SetLengthAttribute }},
300 { "offset" , { SkSVGAttribute::kOffset , SetLengthAttribute }},
301 { "opacity" , { SkSVGAttribute::kOpacity , SetNumberAttribute }},
302 { "patternTransform" , { SkSVGAttribute::kPatternTransform , SetTransformAttribute }},
303 { "points" , { SkSVGAttribute::kPoints , SetPointsAttribute }},
304 { "preserveAspectRatio", { SkSVGAttribute::kPreserveAspectRatio,
305 SetPreserveAspectRatioAttribute }},
306 { "r" , { SkSVGAttribute::kR , SetLengthAttribute }},
307 { "rx" , { SkSVGAttribute::kRx , SetLengthAttribute }},
308 { "ry" , { SkSVGAttribute::kRy , SetLengthAttribute }},
309 { "spreadMethod" , { SkSVGAttribute::kSpreadMethod , SetSpreadMethodAttribute }},
310 { "stop-color" , { SkSVGAttribute::kStopColor , SetStopColorAttribute }},
311 { "stop-opacity" , { SkSVGAttribute::kStopOpacity , SetNumberAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400312 { "stroke-dashoffset" , { SkSVGAttribute::kStrokeDashOffset , SetLengthAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400313 { "stroke-miterlimit" , { SkSVGAttribute::kStrokeMiterLimit , SetNumberAttribute }},
314 { "stroke-opacity" , { SkSVGAttribute::kStrokeOpacity , SetNumberAttribute }},
315 { "stroke-width" , { SkSVGAttribute::kStrokeWidth , SetLengthAttribute }},
316 { "style" , { SkSVGAttribute::kUnknown , SetStyleAttributes }},
317 { "text" , { SkSVGAttribute::kText , SetStringAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400318 { "transform" , { SkSVGAttribute::kTransform , SetTransformAttribute }},
319 { "viewBox" , { SkSVGAttribute::kViewBox , SetViewBoxAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400320 { "width" , { SkSVGAttribute::kWidth , SetLengthAttribute }},
321 { "x" , { SkSVGAttribute::kX , SetLengthAttribute }},
322 { "x1" , { SkSVGAttribute::kX1 , SetLengthAttribute }},
323 { "x2" , { SkSVGAttribute::kX2 , SetLengthAttribute }},
324 { "xlink:href" , { SkSVGAttribute::kHref , SetIRIAttribute }},
325 { "y" , { SkSVGAttribute::kY , SetLengthAttribute }},
326 { "y1" , { SkSVGAttribute::kY1 , SetLengthAttribute }},
327 { "y2" , { SkSVGAttribute::kY2 , SetLengthAttribute }},
fmalita6ceef3d2016-07-26 18:46:34 -0700328};
329
330SortedDictionaryEntry<sk_sp<SkSVGNode>(*)()> gTagFactories[] = {
Florin Malitaf6143ff2017-10-10 09:16:52 -0400331 { "a" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700332 { "circle" , []() -> sk_sp<SkSVGNode> { return SkSVGCircle::Make(); }},
Florin Malitace8840e2016-12-08 09:26:47 -0500333 { "clipPath" , []() -> sk_sp<SkSVGNode> { return SkSVGClipPath::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700334 { "defs" , []() -> sk_sp<SkSVGNode> { return SkSVGDefs::Make(); }},
335 { "ellipse" , []() -> sk_sp<SkSVGNode> { return SkSVGEllipse::Make(); }},
Tyler Denniston70bb18d2020-11-06 12:07:53 -0500336 { "feColorMatrix" , []() -> sk_sp<SkSVGNode> { return SkSVGFeColorMatrix::Make(); }},
Tyler Dennistonb25caae2020-11-09 12:46:02 -0500337 { "feComposite" , []() -> sk_sp<SkSVGNode> { return SkSVGFeComposite::Make(); }},
Tyler Dennistondada9602020-11-03 10:04:25 -0500338 { "feTurbulence" , []() -> sk_sp<SkSVGNode> { return SkSVGFeTurbulence::Make(); }},
Tyler Dennistondf208a32020-10-30 16:01:54 -0400339 { "filter" , []() -> sk_sp<SkSVGNode> { return SkSVGFilter::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700340 { "g" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
341 { "line" , []() -> sk_sp<SkSVGNode> { return SkSVGLine::Make(); }},
342 { "linearGradient", []() -> sk_sp<SkSVGNode> { return SkSVGLinearGradient::Make(); }},
343 { "path" , []() -> sk_sp<SkSVGNode> { return SkSVGPath::Make(); }},
Florin Malita1aa1bb62017-10-11 14:34:33 -0400344 { "pattern" , []() -> sk_sp<SkSVGNode> { return SkSVGPattern::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700345 { "polygon" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolygon(); }},
346 { "polyline" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolyline(); }},
Florin Malitacc6cc292017-10-09 16:05:30 -0400347 { "radialGradient", []() -> sk_sp<SkSVGNode> { return SkSVGRadialGradient::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700348 { "rect" , []() -> sk_sp<SkSVGNode> { return SkSVGRect::Make(); }},
349 { "stop" , []() -> sk_sp<SkSVGNode> { return SkSVGStop::Make(); }},
350 { "svg" , []() -> sk_sp<SkSVGNode> { return SkSVGSVG::Make(); }},
Xavier Phane29cdaf2020-03-26 16:15:14 +0000351 { "text" , []() -> sk_sp<SkSVGNode> { return SkSVGText::Make(); }},
Florin Malita6a69c052017-10-11 14:02:11 -0400352 { "use" , []() -> sk_sp<SkSVGNode> { return SkSVGUse::Make(); }},
fmalita6ceef3d2016-07-26 18:46:34 -0700353};
354
355struct ConstructionContext {
fmalita28d5b722016-09-12 17:06:47 -0700356 ConstructionContext(SkSVGIDMapper* mapper) : fParent(nullptr), fIDMapper(mapper) {}
fmalita6ceef3d2016-07-26 18:46:34 -0700357 ConstructionContext(const ConstructionContext& other, const sk_sp<SkSVGNode>& newParent)
fmalita28d5b722016-09-12 17:06:47 -0700358 : fParent(newParent.get()), fIDMapper(other.fIDMapper) {}
fmalita6ceef3d2016-07-26 18:46:34 -0700359
Florin Malita39fe8c82020-10-20 10:43:03 -0400360 SkSVGNode* fParent;
361 SkSVGIDMapper* fIDMapper;
fmalita6ceef3d2016-07-26 18:46:34 -0700362};
363
Tyler Freemanc9911522020-05-08 13:23:10 -0700364bool set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value) {
Tyler Denniston57154992020-11-04 16:08:30 -0500365 if (node->parseAndSetAttribute(name, value)) {
366 // Handled by new code path
367 return true;
368 }
369
fmalita58649cc2016-07-29 08:52:03 -0700370 const int attrIndex = SkStrSearch(&gAttributeParseInfo[0].fKey,
371 SkTo<int>(SK_ARRAY_COUNT(gAttributeParseInfo)),
372 name, sizeof(gAttributeParseInfo[0]));
373 if (attrIndex < 0) {
fmalitafea704e2016-08-10 16:25:32 -0700374#if defined(SK_VERBOSE_SVG_PARSING)
fmalita58649cc2016-07-29 08:52:03 -0700375 SkDebugf("unhandled attribute: %s\n", name);
fmalitafea704e2016-08-10 16:25:32 -0700376#endif
Tyler Freemanc9911522020-05-08 13:23:10 -0700377 return false;
fmalita58649cc2016-07-29 08:52:03 -0700378 }
379
380 SkASSERT(SkTo<size_t>(attrIndex) < SK_ARRAY_COUNT(gAttributeParseInfo));
381 const auto& attrInfo = gAttributeParseInfo[attrIndex].fValue;
382 if (!attrInfo.fSetter(node, attrInfo.fAttr, value)) {
fmalitafea704e2016-08-10 16:25:32 -0700383#if defined(SK_VERBOSE_SVG_PARSING)
fmalita58649cc2016-07-29 08:52:03 -0700384 SkDebugf("could not parse attribute: '%s=\"%s\"'\n", name, value);
fmalitafea704e2016-08-10 16:25:32 -0700385#endif
Tyler Freemanc9911522020-05-08 13:23:10 -0700386 return false;
fmalita58649cc2016-07-29 08:52:03 -0700387 }
Tyler Freemanc9911522020-05-08 13:23:10 -0700388
389 return true;
fmalita58649cc2016-07-29 08:52:03 -0700390}
391
fmalita6ceef3d2016-07-26 18:46:34 -0700392void parse_node_attributes(const SkDOM& xmlDom, const SkDOM::Node* xmlNode,
fmalita28d5b722016-09-12 17:06:47 -0700393 const sk_sp<SkSVGNode>& svgNode, SkSVGIDMapper* mapper) {
fmalita6ceef3d2016-07-26 18:46:34 -0700394 const char* name, *value;
395 SkDOM::AttrIter attrIter(xmlDom, xmlNode);
396 while ((name = attrIter.next(&value))) {
fmalita28d5b722016-09-12 17:06:47 -0700397 // We're handling id attributes out of band for now.
398 if (!strcmp(name, "id")) {
399 mapper->set(SkString(value), svgNode);
400 continue;
401 }
fmalita58649cc2016-07-29 08:52:03 -0700402 set_string_attribute(svgNode, name, value);
fmalita6ceef3d2016-07-26 18:46:34 -0700403 }
404}
405
406sk_sp<SkSVGNode> construct_svg_node(const SkDOM& dom, const ConstructionContext& ctx,
407 const SkDOM::Node* xmlNode) {
408 const char* elem = dom.getName(xmlNode);
409 const SkDOM::Type elemType = dom.getType(xmlNode);
410
411 if (elemType == SkDOM::kText_Type) {
412 SkASSERT(dom.countChildren(xmlNode) == 0);
Florin Malita39fe8c82020-10-20 10:43:03 -0400413 // TODO: add type conversion helper to SkSVGNode
414 if (ctx.fParent->tag() == SkSVGTag::kText) {
415 static_cast<SkSVGText*>(ctx.fParent)->setText(SkString(dom.getName(xmlNode)));
416 }
fmalita6ceef3d2016-07-26 18:46:34 -0700417 return nullptr;
418 }
419
420 SkASSERT(elemType == SkDOM::kElement_Type);
421
422 const int tagIndex = SkStrSearch(&gTagFactories[0].fKey,
423 SkTo<int>(SK_ARRAY_COUNT(gTagFactories)),
424 elem, sizeof(gTagFactories[0]));
425 if (tagIndex < 0) {
fmalitafea704e2016-08-10 16:25:32 -0700426#if defined(SK_VERBOSE_SVG_PARSING)
fmalita6ceef3d2016-07-26 18:46:34 -0700427 SkDebugf("unhandled element: <%s>\n", elem);
fmalitafea704e2016-08-10 16:25:32 -0700428#endif
fmalita6ceef3d2016-07-26 18:46:34 -0700429 return nullptr;
430 }
431
432 SkASSERT(SkTo<size_t>(tagIndex) < SK_ARRAY_COUNT(gTagFactories));
433 sk_sp<SkSVGNode> node = gTagFactories[tagIndex].fValue();
fmalita28d5b722016-09-12 17:06:47 -0700434 parse_node_attributes(dom, xmlNode, node, ctx.fIDMapper);
fmalita6ceef3d2016-07-26 18:46:34 -0700435
436 ConstructionContext localCtx(ctx, node);
437 for (auto* child = dom.getFirstChild(xmlNode, nullptr); child;
438 child = dom.getNextSibling(child)) {
439 sk_sp<SkSVGNode> childNode = construct_svg_node(dom, localCtx, child);
440 if (childNode) {
441 node->appendChild(std::move(childNode));
442 }
443 }
444
445 return node;
446}
447
448} // anonymous namespace
449
fmalitae1baa7c2016-09-14 12:04:30 -0700450SkSVGDOM::SkSVGDOM()
451 : fContainerSize(SkSize::Make(0, 0)) {
fmalita6ceef3d2016-07-26 18:46:34 -0700452}
453
fmalitae1baa7c2016-09-14 12:04:30 -0700454sk_sp<SkSVGDOM> SkSVGDOM::MakeFromDOM(const SkDOM& xmlDom) {
455 sk_sp<SkSVGDOM> dom = sk_make_sp<SkSVGDOM>();
fmalita6ceef3d2016-07-26 18:46:34 -0700456
fmalita28d5b722016-09-12 17:06:47 -0700457 ConstructionContext ctx(&dom->fIDMapper);
fmalita6ceef3d2016-07-26 18:46:34 -0700458 dom->fRoot = construct_svg_node(xmlDom, ctx, xmlDom.getRootNode());
459
fmalitae1baa7c2016-09-14 12:04:30 -0700460 // Reset the default container size to match the intrinsic SVG size.
461 dom->setContainerSize(dom->intrinsicSize());
462
fmalita6ceef3d2016-07-26 18:46:34 -0700463 return dom;
464}
465
fmalitae1baa7c2016-09-14 12:04:30 -0700466sk_sp<SkSVGDOM> SkSVGDOM::MakeFromStream(SkStream& svgStream) {
fmalita6ceef3d2016-07-26 18:46:34 -0700467 SkDOM xmlDom;
468 if (!xmlDom.build(svgStream)) {
469 return nullptr;
470 }
471
fmalitae1baa7c2016-09-14 12:04:30 -0700472 return MakeFromDOM(xmlDom);
fmalita6ceef3d2016-07-26 18:46:34 -0700473}
474
475void SkSVGDOM::render(SkCanvas* canvas) const {
476 if (fRoot) {
Florin Malitaebca0dd2017-09-09 09:39:07 -0400477 SkSVGLengthContext lctx(fContainerSize);
478 SkSVGPresentationContext pctx;
Tyler Denniston53281c72020-10-22 15:54:24 -0400479 fRoot->render(SkSVGRenderContext(canvas, fIDMapper, lctx, pctx, nullptr));
fmalita6ceef3d2016-07-26 18:46:34 -0700480 }
481}
482
fmalitae1baa7c2016-09-14 12:04:30 -0700483SkSize SkSVGDOM::intrinsicSize() const {
484 if (!fRoot || fRoot->tag() != SkSVGTag::kSvg) {
485 return SkSize::Make(0, 0);
486 }
487
488 // Intrinsic sizes are never relative, so the viewport size is irrelevant.
489 const SkSVGLengthContext lctx(SkSize::Make(0, 0));
490 return static_cast<const SkSVGSVG*>(fRoot.get())->intrinsicSize(lctx);
491}
492
493const SkSize& SkSVGDOM::containerSize() const {
494 return fContainerSize;
495}
496
fmalita6ceef3d2016-07-26 18:46:34 -0700497void SkSVGDOM::setContainerSize(const SkSize& containerSize) {
498 // TODO: inval
499 fContainerSize = containerSize;
500}
fmalitaca39d712016-08-12 13:17:11 -0700501
Tyler Freemanc9911522020-05-08 13:23:10 -0700502sk_sp<SkSVGNode>* SkSVGDOM::findNodeById(const char* id) {
503 SkString idStr(id);
504 return this->fIDMapper.find(idStr);
505}
506
fmalitaca39d712016-08-12 13:17:11 -0700507void SkSVGDOM::setRoot(sk_sp<SkSVGNode> root) {
508 fRoot = std::move(root);
509}
Tyler Freemanc9911522020-05-08 13:23:10 -0700510
511// TODO(fuego): move this to SkSVGNode or its own CU.
512bool SkSVGNode::setAttribute(const char* attributeName, const char* attributeValue) {
513 return set_string_attribute(sk_ref_sp(this), attributeName, attributeValue);
514}