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 "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 
     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 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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:
    217     StyleIterator(const char* str) : fPos(str) { }
    218 
    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:
    239     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 
    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[] = {
    317     { "circle"        , []() -> sk_sp<SkSVGNode> { return SkSVGCircle::Make();         }},
    318     { "clipPath"      , []() -> sk_sp<SkSVGNode> { return SkSVGClipPath::Make();       }},
    319     { "defs"          , []() -> sk_sp<SkSVGNode> { return SkSVGDefs::Make();           }},
    320     { "ellipse"       , []() -> sk_sp<SkSVGNode> { return SkSVGEllipse::Make();        }},
    321     { "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();           }},
    325     { "polygon"       , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolygon();    }},
    326     { "polyline"      , []() -> sk_sp<SkSVGNode> { return SkSVGPoly::MakePolyline();   }},
    327     { "rect"          , []() -> sk_sp<SkSVGNode> { return SkSVGRect::Make();           }},
    328     { "stop"          , []() -> sk_sp<SkSVGNode> { return SkSVGStop::Make();           }},
    329     { "svg"           , []() -> sk_sp<SkSVGNode> { return SkSVGSVG::Make();            }},
    330 };
    331 
    332 struct ConstructionContext {
    333     ConstructionContext(SkSVGIDMapper* mapper) : fParent(nullptr), fIDMapper(mapper) {}
    334     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 
    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 
    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 
    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 
    416 SkSVGDOM::SkSVGDOM()
    417     : fContainerSize(SkSize::Make(0, 0)) {
    418 }
    419 
    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 
    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 
    441 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 
    451 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 
    461 const SkSize& SkSVGDOM::containerSize() const {
    462     return fContainerSize;
    463 }
    464 
    465 void SkSVGDOM::setContainerSize(const SkSize& containerSize) {
    466     // TODO: inval
    467     fContainerSize = containerSize;
    468 }
    469 
    470 void SkSVGDOM::setRoot(sk_sp<SkSVGNode> root) {
    471     fRoot = std::move(root);
    472 }
    473