blob: 5f16e3ee43b8282bfc1612d87ab476616a96478c [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"
Florin Malita7006e152020-11-10 15:24:59 -05009#include "include/core/SkFontMgr.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkString.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/private/SkTo.h"
12#include "include/utils/SkParsePath.h"
Florin Malitab3418102020-10-15 18:10:29 -040013#include "modules/svg/include/SkSVGAttributeParser.h"
14#include "modules/svg/include/SkSVGCircle.h"
15#include "modules/svg/include/SkSVGClipPath.h"
16#include "modules/svg/include/SkSVGDOM.h"
17#include "modules/svg/include/SkSVGDefs.h"
18#include "modules/svg/include/SkSVGEllipse.h"
Tyler Denniston70bb18d2020-11-06 12:07:53 -050019#include "modules/svg/include/SkSVGFeColorMatrix.h"
Tyler Dennistonb25caae2020-11-09 12:46:02 -050020#include "modules/svg/include/SkSVGFeComposite.h"
Tyler Dennistondada9602020-11-03 10:04:25 -050021#include "modules/svg/include/SkSVGFeTurbulence.h"
Tyler Dennistondf208a32020-10-30 16:01:54 -040022#include "modules/svg/include/SkSVGFilter.h"
Florin Malitab3418102020-10-15 18:10:29 -040023#include "modules/svg/include/SkSVGG.h"
24#include "modules/svg/include/SkSVGLine.h"
25#include "modules/svg/include/SkSVGLinearGradient.h"
26#include "modules/svg/include/SkSVGNode.h"
27#include "modules/svg/include/SkSVGPath.h"
28#include "modules/svg/include/SkSVGPattern.h"
29#include "modules/svg/include/SkSVGPoly.h"
30#include "modules/svg/include/SkSVGRadialGradient.h"
31#include "modules/svg/include/SkSVGRect.h"
32#include "modules/svg/include/SkSVGRenderContext.h"
33#include "modules/svg/include/SkSVGSVG.h"
34#include "modules/svg/include/SkSVGStop.h"
35#include "modules/svg/include/SkSVGText.h"
36#include "modules/svg/include/SkSVGTypes.h"
37#include "modules/svg/include/SkSVGUse.h"
38#include "modules/svg/include/SkSVGValue.h"
Ben Wagner8bd6e8f2019-05-15 09:28:52 -040039#include "src/core/SkTSearch.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050040#include "src/xml/SkDOM.h"
fmalita6ceef3d2016-07-26 18:46:34 -070041
42namespace {
43
fmalita28d5b722016-09-12 17:06:47 -070044bool SetColorAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
45 const char* stringValue) {
46 SkSVGColorType color;
47 SkSVGAttributeParser parser(stringValue);
48 if (!parser.parseColor(&color)) {
49 return false;
50 }
51
Florin Malitaf4403e72020-04-10 14:14:04 +000052 node->setAttribute(attr, SkSVGColorValue(color));
fmalita28d5b722016-09-12 17:06:47 -070053 return true;
54}
55
56bool SetIRIAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
57 const char* stringValue) {
Tyler Dennistona0a51462020-11-10 13:13:28 -050058 auto parseResult = SkSVGAttributeParser::parse<SkSVGIRI>(stringValue);
59 if (!parseResult.isValid()) {
fmalita28d5b722016-09-12 17:06:47 -070060 return false;
61 }
62
Tyler Dennistona0a51462020-11-10 13:13:28 -050063 node->setAttribute(attr, SkSVGStringValue(parseResult->fIRI));
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) {
Tyler Dennistona0a51462020-11-10 13:13:28 -050088 auto parseResult = SkSVGAttributeParser::parse<SkSVGTransformType>(stringValue);
89 if (!parseResult.isValid()) {
fmalitac97796b2016-08-08 12:58:57 -070090 return false;
91 }
92
Tyler Dennistona0a51462020-11-10 13:13:28 -050093 node->setAttribute(attr, SkSVGTransformValue(*parseResult));
fmalita6ceef3d2016-07-26 18:46:34 -070094 return true;
95}
96
fmalitabffc2562016-08-03 10:21:11 -070097bool SetLengthAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
98 const char* stringValue) {
Tyler Dennistona0a51462020-11-10 13:13:28 -050099 auto parseResult = SkSVGAttributeParser::parse<SkSVGLength>(stringValue);
100 if (!parseResult.isValid()) {
fmalitabffc2562016-08-03 10:21:11 -0700101 return false;
102 }
103
Tyler Dennistona0a51462020-11-10 13:13:28 -0500104 node->setAttribute(attr, SkSVGLengthValue(*parseResult));
fmalitabffc2562016-08-03 10:21:11 -0700105 return true;
106}
107
fmalita2d961e02016-08-11 09:16:29 -0700108bool SetNumberAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
109 const char* stringValue) {
110 SkSVGNumberType number;
111 SkSVGAttributeParser parser(stringValue);
112 if (!parser.parseNumber(&number)) {
113 return false;
114 }
115
Florin Malitaf4403e72020-04-10 14:14:04 +0000116 node->setAttribute(attr, SkSVGNumberValue(number));
fmalita2d961e02016-08-11 09:16:29 -0700117 return true;
118}
119
fmalita397a5172016-08-08 11:38:55 -0700120bool SetViewBoxAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
121 const char* stringValue) {
122 SkSVGViewBoxType viewBox;
123 SkSVGAttributeParser parser(stringValue);
124 if (!parser.parseViewBox(&viewBox)) {
125 return false;
126 }
127
Florin Malitaf4403e72020-04-10 14:14:04 +0000128 node->setAttribute(attr, SkSVGViewBoxValue(viewBox));
fmalita397a5172016-08-08 11:38:55 -0700129 return true;
130}
131
Tyler Denniston308c0722020-04-14 10:53:41 -0400132bool SetStopColorAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
133 const char* stringValue) {
134 SkSVGStopColor stopColor;
135 SkSVGAttributeParser parser(stringValue);
136 if (!parser.parseStopColor(&stopColor)) {
137 return false;
138 }
139
140 node->setAttribute(attr, SkSVGStopColorValue(stopColor));
141 return true;
142}
143
Tyler Denniston30e327e2020-10-29 16:29:22 -0400144bool SetObjectBoundingBoxUnitsAttribute(const sk_sp<SkSVGNode>& node,
145 SkSVGAttribute attr,
146 const char* stringValue) {
Tyler Dennistona0a51462020-11-10 13:13:28 -0500147 auto parseResult = SkSVGAttributeParser::parse<SkSVGObjectBoundingBoxUnits>(stringValue);
148 if (!parseResult.isValid()) {
Tyler Dennistonab76ab42020-10-21 15:08:45 -0400149 return false;
150 }
151
Tyler Dennistona0a51462020-11-10 13:13:28 -0500152 node->setAttribute(attr, SkSVGObjectBoundingBoxUnitsValue(*parseResult));
Tyler Dennistonab76ab42020-10-21 15:08:45 -0400153 return true;
154}
155
fmalita5b31f322016-08-12 12:15:33 -0700156bool SetPointsAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
157 const char* stringValue) {
158 SkSVGPointsType points;
159 SkSVGAttributeParser parser(stringValue);
160 if (!parser.parsePoints(&points)) {
161 return false;
162 }
163
Florin Malitaf4403e72020-04-10 14:14:04 +0000164 node->setAttribute(attr, SkSVGPointsValue(points));
fmalita5b31f322016-08-12 12:15:33 -0700165 return true;
166}
167
Tyler Dennistonb3cafbc2020-10-30 15:00:48 -0400168bool SetFilterAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
169 const char* stringValue) {
170 SkSVGFilterType filter;
171 SkSVGAttributeParser parser(stringValue);
172 if (!parser.parseFilter(&filter)) {
173 return false;
174 }
175
176 node->setAttribute(attr, SkSVGFilterValue(filter));
177 return true;
178}
179
Florin Malita385e7442020-10-21 16:55:46 -0400180bool SetPreserveAspectRatioAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
181 const char* stringValue) {
182 SkSVGPreserveAspectRatio par;
183 SkSVGAttributeParser parser(stringValue);
184 if (!parser.parsePreserveAspectRatio(&par)) {
185 return false;
186 }
187
188 node->setAttribute(attr, SkSVGPreserveAspectRatioValue(par));
189 return true;
190}
191
fmalita61f36b32016-08-08 13:58:50 -0700192SkString TrimmedString(const char* first, const char* last) {
193 SkASSERT(first);
194 SkASSERT(last);
195 SkASSERT(first <= last);
196
197 while (first <= last && *first <= ' ') { first++; }
198 while (first <= last && *last <= ' ') { last--; }
199
200 SkASSERT(last - first + 1 >= 0);
201 return SkString(first, SkTo<size_t>(last - first + 1));
202}
203
fmalita58649cc2016-07-29 08:52:03 -0700204// Breaks a "foo: bar; baz: ..." string into key:value pairs.
205class StyleIterator {
206public:
207 StyleIterator(const char* str) : fPos(str) { }
208
209 std::tuple<SkString, SkString> next() {
210 SkString name, value;
211
212 if (fPos) {
213 const char* sep = this->nextSeparator();
214 SkASSERT(*sep == ';' || *sep == '\0');
215
216 const char* valueSep = strchr(fPos, ':');
217 if (valueSep && valueSep < sep) {
fmalita61f36b32016-08-08 13:58:50 -0700218 name = TrimmedString(fPos, valueSep - 1);
219 value = TrimmedString(valueSep + 1, sep - 1);
fmalita58649cc2016-07-29 08:52:03 -0700220 }
221
222 fPos = *sep ? sep + 1 : nullptr;
223 }
224
225 return std::make_tuple(name, value);
226 }
227
228private:
229 const char* nextSeparator() const {
230 const char* sep = fPos;
231 while (*sep != ';' && *sep != '\0') {
232 sep++;
233 }
234 return sep;
235 }
236
237 const char* fPos;
238};
239
Tyler Freemanc9911522020-05-08 13:23:10 -0700240bool set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value);
fmalita58649cc2016-07-29 08:52:03 -0700241
242bool SetStyleAttributes(const sk_sp<SkSVGNode>& node, SkSVGAttribute,
243 const char* stringValue) {
244
245 SkString name, value;
246 StyleIterator iter(stringValue);
247 for (;;) {
248 std::tie(name, value) = iter.next();
249 if (name.isEmpty()) {
250 break;
251 }
252 set_string_attribute(node, name.c_str(), value.c_str());
253 }
254
255 return true;
256}
257
fmalita6ceef3d2016-07-26 18:46:34 -0700258template<typename T>
259struct SortedDictionaryEntry {
260 const char* fKey;
261 const T fValue;
262};
263
264struct AttrParseInfo {
265 SkSVGAttribute fAttr;
266 bool (*fSetter)(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, const char* stringValue);
267};
268
269SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
Florin Malita385e7442020-10-21 16:55:46 -0400270 { "color" , { SkSVGAttribute::kColor , SetColorAttribute }},
271 { "cx" , { SkSVGAttribute::kCx , SetLengthAttribute }},
272 { "cy" , { SkSVGAttribute::kCy , SetLengthAttribute }},
273 { "d" , { SkSVGAttribute::kD , SetPathDataAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400274 { "fill-opacity" , { SkSVGAttribute::kFillOpacity , SetNumberAttribute }},
Tyler Dennistonb3cafbc2020-10-30 15:00:48 -0400275 { "filter" , { SkSVGAttribute::kFilter , SetFilterAttribute }},
Tyler Dennistondf208a32020-10-30 16:01:54 -0400276 { "filterUnits" , { SkSVGAttribute::kFilterUnits ,
277 SetObjectBoundingBoxUnitsAttribute }},
Florin Malitacc6cc292017-10-09 16:05:30 -0400278 // focal point x & y
Florin Malita385e7442020-10-21 16:55:46 -0400279 { "fx" , { SkSVGAttribute::kFx , SetLengthAttribute }},
280 { "fy" , { SkSVGAttribute::kFy , SetLengthAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400281 { "height" , { SkSVGAttribute::kHeight , SetLengthAttribute }},
282 { "offset" , { SkSVGAttribute::kOffset , SetLengthAttribute }},
283 { "opacity" , { SkSVGAttribute::kOpacity , SetNumberAttribute }},
284 { "patternTransform" , { SkSVGAttribute::kPatternTransform , SetTransformAttribute }},
285 { "points" , { SkSVGAttribute::kPoints , SetPointsAttribute }},
286 { "preserveAspectRatio", { SkSVGAttribute::kPreserveAspectRatio,
287 SetPreserveAspectRatioAttribute }},
288 { "r" , { SkSVGAttribute::kR , SetLengthAttribute }},
289 { "rx" , { SkSVGAttribute::kRx , SetLengthAttribute }},
290 { "ry" , { SkSVGAttribute::kRy , SetLengthAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400291 { "stop-color" , { SkSVGAttribute::kStopColor , SetStopColorAttribute }},
292 { "stop-opacity" , { SkSVGAttribute::kStopOpacity , SetNumberAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400293 { "stroke-dashoffset" , { SkSVGAttribute::kStrokeDashOffset , SetLengthAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400294 { "stroke-miterlimit" , { SkSVGAttribute::kStrokeMiterLimit , SetNumberAttribute }},
295 { "stroke-opacity" , { SkSVGAttribute::kStrokeOpacity , SetNumberAttribute }},
296 { "stroke-width" , { SkSVGAttribute::kStrokeWidth , SetLengthAttribute }},
297 { "style" , { SkSVGAttribute::kUnknown , SetStyleAttributes }},
298 { "text" , { SkSVGAttribute::kText , SetStringAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400299 { "transform" , { SkSVGAttribute::kTransform , SetTransformAttribute }},
300 { "viewBox" , { SkSVGAttribute::kViewBox , SetViewBoxAttribute }},
Florin Malita385e7442020-10-21 16:55:46 -0400301 { "width" , { SkSVGAttribute::kWidth , SetLengthAttribute }},
302 { "x" , { SkSVGAttribute::kX , SetLengthAttribute }},
303 { "x1" , { SkSVGAttribute::kX1 , SetLengthAttribute }},
304 { "x2" , { SkSVGAttribute::kX2 , SetLengthAttribute }},
305 { "xlink:href" , { SkSVGAttribute::kHref , SetIRIAttribute }},
306 { "y" , { SkSVGAttribute::kY , SetLengthAttribute }},
307 { "y1" , { SkSVGAttribute::kY1 , SetLengthAttribute }},
308 { "y2" , { SkSVGAttribute::kY2 , SetLengthAttribute }},
fmalita6ceef3d2016-07-26 18:46:34 -0700309};
310
311SortedDictionaryEntry<sk_sp<SkSVGNode>(*)()> gTagFactories[] = {
Florin Malitaf6143ff2017-10-10 09:16:52 -0400312 { "a" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700313 { "circle" , []() -> sk_sp<SkSVGNode> { return SkSVGCircle::Make(); }},
Florin Malitace8840e2016-12-08 09:26:47 -0500314 { "clipPath" , []() -> sk_sp<SkSVGNode> { return SkSVGClipPath::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700315 { "defs" , []() -> sk_sp<SkSVGNode> { return SkSVGDefs::Make(); }},
316 { "ellipse" , []() -> sk_sp<SkSVGNode> { return SkSVGEllipse::Make(); }},
Tyler Denniston70bb18d2020-11-06 12:07:53 -0500317 { "feColorMatrix" , []() -> sk_sp<SkSVGNode> { return SkSVGFeColorMatrix::Make(); }},
Tyler Dennistonb25caae2020-11-09 12:46:02 -0500318 { "feComposite" , []() -> sk_sp<SkSVGNode> { return SkSVGFeComposite::Make(); }},
Tyler Dennistondada9602020-11-03 10:04:25 -0500319 { "feTurbulence" , []() -> sk_sp<SkSVGNode> { return SkSVGFeTurbulence::Make(); }},
Tyler Dennistondf208a32020-10-30 16:01:54 -0400320 { "filter" , []() -> sk_sp<SkSVGNode> { return SkSVGFilter::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700321 { "g" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
322 { "line" , []() -> sk_sp<SkSVGNode> { return SkSVGLine::Make(); }},
323 { "linearGradient", []() -> sk_sp<SkSVGNode> { return SkSVGLinearGradient::Make(); }},
324 { "path" , []() -> sk_sp<SkSVGNode> { return SkSVGPath::Make(); }},
Florin Malita1aa1bb62017-10-11 14:34:33 -0400325 { "pattern" , []() -> sk_sp<SkSVGNode> { return SkSVGPattern::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700326 { "polygon" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolygon(); }},
327 { "polyline" , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolyline(); }},
Florin Malitacc6cc292017-10-09 16:05:30 -0400328 { "radialGradient", []() -> sk_sp<SkSVGNode> { return SkSVGRadialGradient::Make(); }},
fmalita28d5b722016-09-12 17:06:47 -0700329 { "rect" , []() -> sk_sp<SkSVGNode> { return SkSVGRect::Make(); }},
330 { "stop" , []() -> sk_sp<SkSVGNode> { return SkSVGStop::Make(); }},
331 { "svg" , []() -> sk_sp<SkSVGNode> { return SkSVGSVG::Make(); }},
Xavier Phane29cdaf2020-03-26 16:15:14 +0000332 { "text" , []() -> sk_sp<SkSVGNode> { return SkSVGText::Make(); }},
Florin Malita6a69c052017-10-11 14:02:11 -0400333 { "use" , []() -> sk_sp<SkSVGNode> { return SkSVGUse::Make(); }},
fmalita6ceef3d2016-07-26 18:46:34 -0700334};
335
336struct ConstructionContext {
fmalita28d5b722016-09-12 17:06:47 -0700337 ConstructionContext(SkSVGIDMapper* mapper) : fParent(nullptr), fIDMapper(mapper) {}
fmalita6ceef3d2016-07-26 18:46:34 -0700338 ConstructionContext(const ConstructionContext& other, const sk_sp<SkSVGNode>& newParent)
fmalita28d5b722016-09-12 17:06:47 -0700339 : fParent(newParent.get()), fIDMapper(other.fIDMapper) {}
fmalita6ceef3d2016-07-26 18:46:34 -0700340
Florin Malita39fe8c82020-10-20 10:43:03 -0400341 SkSVGNode* fParent;
342 SkSVGIDMapper* fIDMapper;
fmalita6ceef3d2016-07-26 18:46:34 -0700343};
344
Tyler Freemanc9911522020-05-08 13:23:10 -0700345bool set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value) {
Tyler Denniston57154992020-11-04 16:08:30 -0500346 if (node->parseAndSetAttribute(name, value)) {
347 // Handled by new code path
348 return true;
349 }
350
fmalita58649cc2016-07-29 08:52:03 -0700351 const int attrIndex = SkStrSearch(&gAttributeParseInfo[0].fKey,
352 SkTo<int>(SK_ARRAY_COUNT(gAttributeParseInfo)),
353 name, sizeof(gAttributeParseInfo[0]));
354 if (attrIndex < 0) {
fmalitafea704e2016-08-10 16:25:32 -0700355#if defined(SK_VERBOSE_SVG_PARSING)
fmalita58649cc2016-07-29 08:52:03 -0700356 SkDebugf("unhandled attribute: %s\n", name);
fmalitafea704e2016-08-10 16:25:32 -0700357#endif
Tyler Freemanc9911522020-05-08 13:23:10 -0700358 return false;
fmalita58649cc2016-07-29 08:52:03 -0700359 }
360
361 SkASSERT(SkTo<size_t>(attrIndex) < SK_ARRAY_COUNT(gAttributeParseInfo));
362 const auto& attrInfo = gAttributeParseInfo[attrIndex].fValue;
363 if (!attrInfo.fSetter(node, attrInfo.fAttr, value)) {
fmalitafea704e2016-08-10 16:25:32 -0700364#if defined(SK_VERBOSE_SVG_PARSING)
fmalita58649cc2016-07-29 08:52:03 -0700365 SkDebugf("could not parse attribute: '%s=\"%s\"'\n", name, value);
fmalitafea704e2016-08-10 16:25:32 -0700366#endif
Tyler Freemanc9911522020-05-08 13:23:10 -0700367 return false;
fmalita58649cc2016-07-29 08:52:03 -0700368 }
Tyler Freemanc9911522020-05-08 13:23:10 -0700369
370 return true;
fmalita58649cc2016-07-29 08:52:03 -0700371}
372
fmalita6ceef3d2016-07-26 18:46:34 -0700373void parse_node_attributes(const SkDOM& xmlDom, const SkDOM::Node* xmlNode,
fmalita28d5b722016-09-12 17:06:47 -0700374 const sk_sp<SkSVGNode>& svgNode, SkSVGIDMapper* mapper) {
fmalita6ceef3d2016-07-26 18:46:34 -0700375 const char* name, *value;
376 SkDOM::AttrIter attrIter(xmlDom, xmlNode);
377 while ((name = attrIter.next(&value))) {
fmalita28d5b722016-09-12 17:06:47 -0700378 // We're handling id attributes out of band for now.
379 if (!strcmp(name, "id")) {
380 mapper->set(SkString(value), svgNode);
381 continue;
382 }
fmalita58649cc2016-07-29 08:52:03 -0700383 set_string_attribute(svgNode, name, value);
fmalita6ceef3d2016-07-26 18:46:34 -0700384 }
385}
386
387sk_sp<SkSVGNode> construct_svg_node(const SkDOM& dom, const ConstructionContext& ctx,
388 const SkDOM::Node* xmlNode) {
389 const char* elem = dom.getName(xmlNode);
390 const SkDOM::Type elemType = dom.getType(xmlNode);
391
392 if (elemType == SkDOM::kText_Type) {
393 SkASSERT(dom.countChildren(xmlNode) == 0);
Florin Malita39fe8c82020-10-20 10:43:03 -0400394 // TODO: add type conversion helper to SkSVGNode
395 if (ctx.fParent->tag() == SkSVGTag::kText) {
396 static_cast<SkSVGText*>(ctx.fParent)->setText(SkString(dom.getName(xmlNode)));
397 }
fmalita6ceef3d2016-07-26 18:46:34 -0700398 return nullptr;
399 }
400
401 SkASSERT(elemType == SkDOM::kElement_Type);
402
403 const int tagIndex = SkStrSearch(&gTagFactories[0].fKey,
404 SkTo<int>(SK_ARRAY_COUNT(gTagFactories)),
405 elem, sizeof(gTagFactories[0]));
406 if (tagIndex < 0) {
fmalitafea704e2016-08-10 16:25:32 -0700407#if defined(SK_VERBOSE_SVG_PARSING)
fmalita6ceef3d2016-07-26 18:46:34 -0700408 SkDebugf("unhandled element: <%s>\n", elem);
fmalitafea704e2016-08-10 16:25:32 -0700409#endif
fmalita6ceef3d2016-07-26 18:46:34 -0700410 return nullptr;
411 }
412
413 SkASSERT(SkTo<size_t>(tagIndex) < SK_ARRAY_COUNT(gTagFactories));
414 sk_sp<SkSVGNode> node = gTagFactories[tagIndex].fValue();
fmalita28d5b722016-09-12 17:06:47 -0700415 parse_node_attributes(dom, xmlNode, node, ctx.fIDMapper);
fmalita6ceef3d2016-07-26 18:46:34 -0700416
417 ConstructionContext localCtx(ctx, node);
418 for (auto* child = dom.getFirstChild(xmlNode, nullptr); child;
419 child = dom.getNextSibling(child)) {
420 sk_sp<SkSVGNode> childNode = construct_svg_node(dom, localCtx, child);
421 if (childNode) {
422 node->appendChild(std::move(childNode));
423 }
424 }
425
426 return node;
427}
428
429} // anonymous namespace
430
Florin Malita7006e152020-11-10 15:24:59 -0500431SkSVGDOM::Builder& SkSVGDOM::Builder::setFontManager(sk_sp<SkFontMgr> fmgr) {
432 fFontMgr = std::move(fmgr);
433 return *this;
fmalita6ceef3d2016-07-26 18:46:34 -0700434}
435
Florin Malita7006e152020-11-10 15:24:59 -0500436sk_sp<SkSVGDOM> SkSVGDOM::Builder::make(SkStream& str) const {
fmalita6ceef3d2016-07-26 18:46:34 -0700437 SkDOM xmlDom;
Florin Malita7006e152020-11-10 15:24:59 -0500438 if (!xmlDom.build(str)) {
fmalita6ceef3d2016-07-26 18:46:34 -0700439 return nullptr;
440 }
441
Florin Malita7006e152020-11-10 15:24:59 -0500442 SkSVGIDMapper mapper;
443 ConstructionContext ctx(&mapper);
444
445 auto root = construct_svg_node(xmlDom, ctx, xmlDom.getRootNode());
446 if (!root || root->tag() != SkSVGTag::kSvg) {
447 return nullptr;
448 }
449
450 return sk_sp<SkSVGDOM>(new SkSVGDOM(sk_sp<SkSVGSVG>(static_cast<SkSVGSVG*>(root.release())),
451 std::move(fFontMgr), std::move(mapper)));
fmalita6ceef3d2016-07-26 18:46:34 -0700452}
453
Florin Malita7006e152020-11-10 15:24:59 -0500454SkSVGDOM::SkSVGDOM(sk_sp<SkSVGSVG> root, sk_sp<SkFontMgr> fmgr, SkSVGIDMapper&& mapper)
455 : fRoot(std::move(root))
456 , fFontMgr(std::move(fmgr))
457 , fIDMapper(std::move(mapper))
458 , fContainerSize(fRoot->intrinsicSize(SkSVGLengthContext(SkSize::Make(0, 0))))
459{}
460
fmalita6ceef3d2016-07-26 18:46:34 -0700461void SkSVGDOM::render(SkCanvas* canvas) const {
462 if (fRoot) {
Florin Malitaebca0dd2017-09-09 09:39:07 -0400463 SkSVGLengthContext lctx(fContainerSize);
464 SkSVGPresentationContext pctx;
Florin Malita7006e152020-11-10 15:24:59 -0500465 fRoot->render(SkSVGRenderContext(canvas, fFontMgr, fIDMapper, lctx, pctx, nullptr));
fmalita6ceef3d2016-07-26 18:46:34 -0700466 }
467}
468
fmalitae1baa7c2016-09-14 12:04:30 -0700469const SkSize& SkSVGDOM::containerSize() const {
470 return fContainerSize;
471}
472
fmalita6ceef3d2016-07-26 18:46:34 -0700473void SkSVGDOM::setContainerSize(const SkSize& containerSize) {
474 // TODO: inval
475 fContainerSize = containerSize;
476}
fmalitaca39d712016-08-12 13:17:11 -0700477
Tyler Freemanc9911522020-05-08 13:23:10 -0700478sk_sp<SkSVGNode>* SkSVGDOM::findNodeById(const char* id) {
479 SkString idStr(id);
480 return this->fIDMapper.find(idStr);
481}
482
Tyler Freemanc9911522020-05-08 13:23:10 -0700483// TODO(fuego): move this to SkSVGNode or its own CU.
484bool SkSVGNode::setAttribute(const char* attributeName, const char* attributeValue) {
485 return set_string_attribute(sk_ref_sp(this), attributeName, attributeValue);
486}