Home | History | Annotate | Download | only in model
      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 
     35 namespace {
     36 
     37 bool 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 
     49 bool 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 
     61 bool 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 
     73 bool 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 
     86 bool 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 
     97 bool 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 
    109 bool 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 
    121 bool 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 
    133 bool 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 
    145 bool 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 
    157 bool 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 
    169 bool 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 
    181 bool 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 
    193 bool 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 
    205 bool 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 
    217 bool 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 
    229 SkString 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.
    242 class StyleIterator {
    243 public:
    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 
    265 private:
    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 
    277 void set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value);
    278 
    279 bool 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 
    295 template<typename T>
    296 struct SortedDictionaryEntry {
    297     const char* fKey;
    298     const T     fValue;
    299 };
    300 
    301 struct AttrParseInfo {
    302     SkSVGAttribute fAttr;
    303     bool (*fSetter)(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, const char* stringValue);
    304 };
    305 
    306 SortedDictionaryEntry<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 
    352 SortedDictionaryEntry<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 
    372 struct 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 
    381 void 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 
    401 void 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 
    415 sk_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 
    456 SkSVGDOM::SkSVGDOM()
    457     : fContainerSize(SkSize::Make(0, 0)) {
    458 }
    459 
    460 sk_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 
    472 sk_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 
    481 void 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 
    489 SkSize 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 
    499 const SkSize& SkSVGDOM::containerSize() const {
    500     return fContainerSize;
    501 }
    502 
    503 void SkSVGDOM::setContainerSize(const SkSize& containerSize) {
    504     // TODO: inval
    505     fContainerSize = containerSize;
    506 }
    507 
    508 void SkSVGDOM::setRoot(sk_sp<SkSVGNode> root) {
    509     fRoot = std::move(root);
    510 }
    511