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