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