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