• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
8 #include "SkCanvas.h"
9 #include "SkDOM.h"
10 #include "SkParsePath.h"
11 #include "SkString.h"
12 #include "SkSVGAttributeParser.h"
13 #include "SkSVGCircle.h"
14 #include "SkSVGClipPath.h"
15 #include "SkSVGDefs.h"
16 #include "SkSVGDOM.h"
17 #include "SkSVGEllipse.h"
18 #include "SkSVGG.h"
19 #include "SkSVGLine.h"
20 #include "SkSVGLinearGradient.h"
21 #include "SkSVGNode.h"
22 #include "SkSVGPath.h"
23 #include "SkSVGPoly.h"
24 #include "SkSVGRect.h"
25 #include "SkSVGRenderContext.h"
26 #include "SkSVGStop.h"
27 #include "SkSVGSVG.h"
28 #include "SkSVGTypes.h"
29 #include "SkSVGValue.h"
30 #include "SkTSearch.h"
31 
32 namespace {
33 
SetPaintAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)34 bool SetPaintAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
35                        const char* stringValue) {
36     SkSVGPaint paint;
37     SkSVGAttributeParser parser(stringValue);
38     if (!parser.parsePaint(&paint)) {
39         return false;
40     }
41 
42     node->setAttribute(attr, SkSVGPaintValue(paint));
43     return true;
44 }
45 
SetColorAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)46 bool SetColorAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
47                        const char* stringValue) {
48     SkSVGColorType color;
49     SkSVGAttributeParser parser(stringValue);
50     if (!parser.parseColor(&color)) {
51         return false;
52     }
53 
54     node->setAttribute(attr, SkSVGColorValue(color));
55     return true;
56 }
57 
SetIRIAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)58 bool SetIRIAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
59                       const char* stringValue) {
60     SkSVGStringType iri;
61     SkSVGAttributeParser parser(stringValue);
62     if (!parser.parseIRI(&iri)) {
63         return false;
64     }
65 
66     node->setAttribute(attr, SkSVGStringValue(iri));
67     return true;
68 }
69 
SetClipPathAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)70 bool SetClipPathAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
71                           const char* stringValue) {
72     SkSVGClip clip;
73     SkSVGAttributeParser parser(stringValue);
74     if (!parser.parseClipPath(&clip)) {
75         return false;
76     }
77 
78     node->setAttribute(attr, SkSVGClipValue(clip));
79     return true;
80 }
81 
82 
SetPathDataAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)83 bool SetPathDataAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
84                           const char* stringValue) {
85     SkPath path;
86     if (!SkParsePath::FromSVGString(stringValue, &path)) {
87         return false;
88     }
89 
90     node->setAttribute(attr, SkSVGPathValue(path));
91     return true;
92 }
93 
SetTransformAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)94 bool SetTransformAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
95                            const char* stringValue) {
96     SkSVGTransformType transform;
97     SkSVGAttributeParser parser(stringValue);
98     if (!parser.parseTransform(&transform)) {
99         return false;
100     }
101 
102     node->setAttribute(attr, SkSVGTransformValue(transform));
103     return true;
104 }
105 
SetLengthAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)106 bool SetLengthAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
107                         const char* stringValue) {
108     SkSVGLength length;
109     SkSVGAttributeParser parser(stringValue);
110     if (!parser.parseLength(&length)) {
111         return false;
112     }
113 
114     node->setAttribute(attr, SkSVGLengthValue(length));
115     return true;
116 }
117 
SetNumberAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)118 bool SetNumberAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
119                         const char* stringValue) {
120     SkSVGNumberType number;
121     SkSVGAttributeParser parser(stringValue);
122     if (!parser.parseNumber(&number)) {
123         return false;
124     }
125 
126     node->setAttribute(attr, SkSVGNumberValue(number));
127     return true;
128 }
129 
SetViewBoxAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)130 bool SetViewBoxAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
131                          const char* stringValue) {
132     SkSVGViewBoxType viewBox;
133     SkSVGAttributeParser parser(stringValue);
134     if (!parser.parseViewBox(&viewBox)) {
135         return false;
136     }
137 
138     node->setAttribute(attr, SkSVGViewBoxValue(viewBox));
139     return true;
140 }
141 
SetLineCapAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)142 bool SetLineCapAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
143                          const char* stringValue) {
144     SkSVGLineCap lineCap;
145     SkSVGAttributeParser parser(stringValue);
146     if (!parser.parseLineCap(&lineCap)) {
147         return false;
148     }
149 
150     node->setAttribute(attr, SkSVGLineCapValue(lineCap));
151     return true;
152 }
153 
SetLineJoinAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)154 bool SetLineJoinAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
155                           const char* stringValue) {
156     SkSVGLineJoin lineJoin;
157     SkSVGAttributeParser parser(stringValue);
158     if (!parser.parseLineJoin(&lineJoin)) {
159         return false;
160     }
161 
162     node->setAttribute(attr, SkSVGLineJoinValue(lineJoin));
163     return true;
164 }
165 
SetSpreadMethodAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)166 bool SetSpreadMethodAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
167                              const char* stringValue) {
168     SkSVGSpreadMethod spread;
169     SkSVGAttributeParser parser(stringValue);
170     if (!parser.parseSpreadMethod(&spread)) {
171         return false;
172     }
173 
174     node->setAttribute(attr, SkSVGSpreadMethodValue(spread));
175     return true;
176 }
177 
SetPointsAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)178 bool SetPointsAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
179                         const char* stringValue) {
180     SkSVGPointsType points;
181     SkSVGAttributeParser parser(stringValue);
182     if (!parser.parsePoints(&points)) {
183         return false;
184     }
185 
186     node->setAttribute(attr, SkSVGPointsValue(points));
187     return true;
188 }
189 
SetFillRuleAttribute(const sk_sp<SkSVGNode> & node,SkSVGAttribute attr,const char * stringValue)190 bool SetFillRuleAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
191                           const char* stringValue) {
192     SkSVGFillRule fillRule;
193     SkSVGAttributeParser parser(stringValue);
194     if (!parser.parseFillRule(&fillRule)) {
195         return false;
196     }
197 
198     node->setAttribute(attr, SkSVGFillRuleValue(fillRule));
199     return true;
200 }
201 
TrimmedString(const char * first,const char * last)202 SkString TrimmedString(const char* first, const char* last) {
203     SkASSERT(first);
204     SkASSERT(last);
205     SkASSERT(first <= last);
206 
207     while (first <= last && *first <= ' ') { first++; }
208     while (first <= last && *last  <= ' ') { last--; }
209 
210     SkASSERT(last - first + 1 >= 0);
211     return SkString(first, SkTo<size_t>(last - first + 1));
212 }
213 
214 // Breaks a "foo: bar; baz: ..." string into key:value pairs.
215 class StyleIterator {
216 public:
StyleIterator(const char * str)217     StyleIterator(const char* str) : fPos(str) { }
218 
next()219     std::tuple<SkString, SkString> next() {
220         SkString name, value;
221 
222         if (fPos) {
223             const char* sep = this->nextSeparator();
224             SkASSERT(*sep == ';' || *sep == '\0');
225 
226             const char* valueSep = strchr(fPos, ':');
227             if (valueSep && valueSep < sep) {
228                 name  = TrimmedString(fPos, valueSep - 1);
229                 value = TrimmedString(valueSep + 1, sep - 1);
230             }
231 
232             fPos = *sep ? sep + 1 : nullptr;
233         }
234 
235         return std::make_tuple(name, value);
236     }
237 
238 private:
nextSeparator() const239     const char* nextSeparator() const {
240         const char* sep = fPos;
241         while (*sep != ';' && *sep != '\0') {
242             sep++;
243         }
244         return sep;
245     }
246 
247     const char* fPos;
248 };
249 
250 void set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value);
251 
SetStyleAttributes(const sk_sp<SkSVGNode> & node,SkSVGAttribute,const char * stringValue)252 bool SetStyleAttributes(const sk_sp<SkSVGNode>& node, SkSVGAttribute,
253                         const char* stringValue) {
254 
255     SkString name, value;
256     StyleIterator iter(stringValue);
257     for (;;) {
258         std::tie(name, value) = iter.next();
259         if (name.isEmpty()) {
260             break;
261         }
262         set_string_attribute(node, name.c_str(), value.c_str());
263     }
264 
265     return true;
266 }
267 
268 template<typename T>
269 struct SortedDictionaryEntry {
270     const char* fKey;
271     const T     fValue;
272 };
273 
274 struct AttrParseInfo {
275     SkSVGAttribute fAttr;
276     bool (*fSetter)(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, const char* stringValue);
277 };
278 
279 SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
280     { "clip-path"        , { SkSVGAttribute::kClipPath         , SetClipPathAttribute     }},
281     { "cx"               , { SkSVGAttribute::kCx               , SetLengthAttribute       }},
282     { "cy"               , { SkSVGAttribute::kCy               , SetLengthAttribute       }},
283     { "d"                , { SkSVGAttribute::kD                , SetPathDataAttribute     }},
284     { "fill"             , { SkSVGAttribute::kFill             , SetPaintAttribute        }},
285     { "fill-opacity"     , { SkSVGAttribute::kFillOpacity      , SetNumberAttribute       }},
286     { "fill-rule"        , { SkSVGAttribute::kFillRule         , SetFillRuleAttribute     }},
287     { "gradientTransform", { SkSVGAttribute::kGradientTransform, SetTransformAttribute    }},
288     { "height"           , { SkSVGAttribute::kHeight           , SetLengthAttribute       }},
289     { "offset"           , { SkSVGAttribute::kOffset           , SetLengthAttribute       }},
290     { "opacity"          , { SkSVGAttribute::kOpacity          , SetNumberAttribute       }},
291     { "points"           , { SkSVGAttribute::kPoints           , SetPointsAttribute       }},
292     { "r"                , { SkSVGAttribute::kR                , SetLengthAttribute       }},
293     { "rx"               , { SkSVGAttribute::kRx               , SetLengthAttribute       }},
294     { "ry"               , { SkSVGAttribute::kRy               , SetLengthAttribute       }},
295     { "spreadMethod"     , { SkSVGAttribute::kSpreadMethod     , SetSpreadMethodAttribute }},
296     { "stop-color"       , { SkSVGAttribute::kStopColor        , SetColorAttribute        }},
297     { "stop-opacity"     , { SkSVGAttribute::kStopOpacity      , SetNumberAttribute       }},
298     { "stroke"           , { SkSVGAttribute::kStroke           , SetPaintAttribute        }},
299     { "stroke-linecap"   , { SkSVGAttribute::kStrokeLineCap    , SetLineCapAttribute      }},
300     { "stroke-linejoin"  , { SkSVGAttribute::kStrokeLineJoin   , SetLineJoinAttribute     }},
301     { "stroke-opacity"   , { SkSVGAttribute::kStrokeOpacity    , SetNumberAttribute       }},
302     { "stroke-width"     , { SkSVGAttribute::kStrokeWidth      , SetLengthAttribute       }},
303     { "style"            , { SkSVGAttribute::kUnknown          , SetStyleAttributes       }},
304     { "transform"        , { SkSVGAttribute::kTransform        , SetTransformAttribute    }},
305     { "viewBox"          , { SkSVGAttribute::kViewBox          , SetViewBoxAttribute      }},
306     { "width"            , { SkSVGAttribute::kWidth            , SetLengthAttribute       }},
307     { "x"                , { SkSVGAttribute::kX                , SetLengthAttribute       }},
308     { "x1"               , { SkSVGAttribute::kX1               , SetLengthAttribute       }},
309     { "x2"               , { SkSVGAttribute::kX2               , SetLengthAttribute       }},
310     { "xlink:href"       , { SkSVGAttribute::kHref             , SetIRIAttribute          }},
311     { "y"                , { SkSVGAttribute::kY                , SetLengthAttribute       }},
312     { "y1"               , { SkSVGAttribute::kY1               , SetLengthAttribute       }},
313     { "y2"               , { SkSVGAttribute::kY2               , SetLengthAttribute       }},
314 };
315 
316 SortedDictionaryEntry<sk_sp<SkSVGNode>(*)()> gTagFactories[] = {
__anon02daf3620202() 317     { "circle"        , []() -> sk_sp<SkSVGNode> { return SkSVGCircle::Make();         }},
__anon02daf3620302() 318     { "clipPath"      , []() -> sk_sp<SkSVGNode> { return SkSVGClipPath::Make();       }},
__anon02daf3620402() 319     { "defs"          , []() -> sk_sp<SkSVGNode> { return SkSVGDefs::Make();           }},
__anon02daf3620502() 320     { "ellipse"       , []() -> sk_sp<SkSVGNode> { return SkSVGEllipse::Make();        }},
__anon02daf3620602() 321     { "g"             , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make();              }},
__anon02daf3620702() 322     { "line"          , []() -> sk_sp<SkSVGNode> { return SkSVGLine::Make();           }},
__anon02daf3620802() 323     { "linearGradient", []() -> sk_sp<SkSVGNode> { return SkSVGLinearGradient::Make(); }},
__anon02daf3620902() 324     { "path"          , []() -> sk_sp<SkSVGNode> { return SkSVGPath::Make();           }},
__anon02daf3620a02() 325     { "polygon"       , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolygon();    }},
__anon02daf3620b02() 326     { "polyline"      , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolyline();   }},
__anon02daf3620c02() 327     { "rect"          , []() -> sk_sp<SkSVGNode> { return SkSVGRect::Make();           }},
__anon02daf3620d02() 328     { "stop"          , []() -> sk_sp<SkSVGNode> { return SkSVGStop::Make();           }},
__anon02daf3620e02() 329     { "svg"           , []() -> sk_sp<SkSVGNode> { return SkSVGSVG::Make();            }},
330 };
331 
332 struct ConstructionContext {
ConstructionContext__anon02daf3620111::ConstructionContext333     ConstructionContext(SkSVGIDMapper* mapper) : fParent(nullptr), fIDMapper(mapper) {}
ConstructionContext__anon02daf3620111::ConstructionContext334     ConstructionContext(const ConstructionContext& other, const sk_sp<SkSVGNode>& newParent)
335         : fParent(newParent.get()), fIDMapper(other.fIDMapper) {}
336 
337     const SkSVGNode* fParent;
338     SkSVGIDMapper*   fIDMapper;
339 };
340 
set_string_attribute(const sk_sp<SkSVGNode> & node,const char * name,const char * value)341 void set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value) {
342     const int attrIndex = SkStrSearch(&gAttributeParseInfo[0].fKey,
343                                       SkTo<int>(SK_ARRAY_COUNT(gAttributeParseInfo)),
344                                       name, sizeof(gAttributeParseInfo[0]));
345     if (attrIndex < 0) {
346 #if defined(SK_VERBOSE_SVG_PARSING)
347         SkDebugf("unhandled attribute: %s\n", name);
348 #endif
349         return;
350     }
351 
352     SkASSERT(SkTo<size_t>(attrIndex) < SK_ARRAY_COUNT(gAttributeParseInfo));
353     const auto& attrInfo = gAttributeParseInfo[attrIndex].fValue;
354     if (!attrInfo.fSetter(node, attrInfo.fAttr, value)) {
355 #if defined(SK_VERBOSE_SVG_PARSING)
356         SkDebugf("could not parse attribute: '%s=\"%s\"'\n", name, value);
357 #endif
358     }
359 }
360 
parse_node_attributes(const SkDOM & xmlDom,const SkDOM::Node * xmlNode,const sk_sp<SkSVGNode> & svgNode,SkSVGIDMapper * mapper)361 void parse_node_attributes(const SkDOM& xmlDom, const SkDOM::Node* xmlNode,
362                            const sk_sp<SkSVGNode>& svgNode, SkSVGIDMapper* mapper) {
363     const char* name, *value;
364     SkDOM::AttrIter attrIter(xmlDom, xmlNode);
365     while ((name = attrIter.next(&value))) {
366         // We're handling id attributes out of band for now.
367         if (!strcmp(name, "id")) {
368             mapper->set(SkString(value), svgNode);
369             continue;
370         }
371         set_string_attribute(svgNode, name, value);
372     }
373 }
374 
construct_svg_node(const SkDOM & dom,const ConstructionContext & ctx,const SkDOM::Node * xmlNode)375 sk_sp<SkSVGNode> construct_svg_node(const SkDOM& dom, const ConstructionContext& ctx,
376                                     const SkDOM::Node* xmlNode) {
377     const char* elem = dom.getName(xmlNode);
378     const SkDOM::Type elemType = dom.getType(xmlNode);
379 
380     if (elemType == SkDOM::kText_Type) {
381         SkASSERT(dom.countChildren(xmlNode) == 0);
382         // TODO: text handling
383         return nullptr;
384     }
385 
386     SkASSERT(elemType == SkDOM::kElement_Type);
387 
388     const int tagIndex = SkStrSearch(&gTagFactories[0].fKey,
389                                      SkTo<int>(SK_ARRAY_COUNT(gTagFactories)),
390                                      elem, sizeof(gTagFactories[0]));
391     if (tagIndex < 0) {
392 #if defined(SK_VERBOSE_SVG_PARSING)
393         SkDebugf("unhandled element: <%s>\n", elem);
394 #endif
395         return nullptr;
396     }
397 
398     SkASSERT(SkTo<size_t>(tagIndex) < SK_ARRAY_COUNT(gTagFactories));
399     sk_sp<SkSVGNode> node = gTagFactories[tagIndex].fValue();
400     parse_node_attributes(dom, xmlNode, node, ctx.fIDMapper);
401 
402     ConstructionContext localCtx(ctx, node);
403     for (auto* child = dom.getFirstChild(xmlNode, nullptr); child;
404          child = dom.getNextSibling(child)) {
405         sk_sp<SkSVGNode> childNode = construct_svg_node(dom, localCtx, child);
406         if (childNode) {
407             node->appendChild(std::move(childNode));
408         }
409     }
410 
411     return node;
412 }
413 
414 } // anonymous namespace
415 
SkSVGDOM()416 SkSVGDOM::SkSVGDOM()
417     : fContainerSize(SkSize::Make(0, 0)) {
418 }
419 
MakeFromDOM(const SkDOM & xmlDom)420 sk_sp<SkSVGDOM> SkSVGDOM::MakeFromDOM(const SkDOM& xmlDom) {
421     sk_sp<SkSVGDOM> dom = sk_make_sp<SkSVGDOM>();
422 
423     ConstructionContext ctx(&dom->fIDMapper);
424     dom->fRoot = construct_svg_node(xmlDom, ctx, xmlDom.getRootNode());
425 
426     // Reset the default container size to match the intrinsic SVG size.
427     dom->setContainerSize(dom->intrinsicSize());
428 
429     return dom;
430 }
431 
MakeFromStream(SkStream & svgStream)432 sk_sp<SkSVGDOM> SkSVGDOM::MakeFromStream(SkStream& svgStream) {
433     SkDOM xmlDom;
434     if (!xmlDom.build(svgStream)) {
435         return nullptr;
436     }
437 
438     return MakeFromDOM(xmlDom);
439 }
440 
render(SkCanvas * canvas) const441 void SkSVGDOM::render(SkCanvas* canvas) const {
442     if (fRoot) {
443         SkSVGRenderContext ctx(canvas,
444                                fIDMapper,
445                                SkSVGLengthContext(fContainerSize),
446                                SkSVGPresentationContext());
447         fRoot->render(ctx);
448     }
449 }
450 
intrinsicSize() const451 SkSize SkSVGDOM::intrinsicSize() const {
452     if (!fRoot || fRoot->tag() != SkSVGTag::kSvg) {
453         return SkSize::Make(0, 0);
454     }
455 
456     // Intrinsic sizes are never relative, so the viewport size is irrelevant.
457     const SkSVGLengthContext lctx(SkSize::Make(0, 0));
458     return static_cast<const SkSVGSVG*>(fRoot.get())->intrinsicSize(lctx);
459 }
460 
containerSize() const461 const SkSize& SkSVGDOM::containerSize() const {
462     return fContainerSize;
463 }
464 
setContainerSize(const SkSize & containerSize)465 void SkSVGDOM::setContainerSize(const SkSize& containerSize) {
466     // TODO: inval
467     fContainerSize = containerSize;
468 }
469 
setRoot(sk_sp<SkSVGNode> root)470 void SkSVGDOM::setRoot(sk_sp<SkSVGNode> root) {
471     fRoot = std::move(root);
472 }
473