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