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