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