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 "modules/svg/include/SkSVGSVG.h"
9
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkMatrix.h"
12 #include "include/core/SkRect.h"
13 #include "modules/svg/include/SkSVGAttribute.h"
14 #include "modules/svg/include/SkSVGRenderContext.h"
15 #include "modules/svg/include/SkSVGValue.h"
16
renderNode(const SkSVGRenderContext & ctx,const SkSVGIRI & iri) const17 void SkSVGSVG::renderNode(const SkSVGRenderContext& ctx, const SkSVGIRI& iri) const {
18 SkSVGRenderContext localContext(ctx, this);
19 SkSVGRenderContext::BorrowedNode node = localContext.findNodeById(iri);
20 if (!node) {
21 return;
22 }
23
24 if (this->onPrepareToRender(&localContext)) {
25 if (this == node.get()) {
26 this->onRender(ctx);
27 } else {
28 node->render(localContext);
29 }
30 }
31 }
32
onPrepareToRender(SkSVGRenderContext * ctx) const33 bool SkSVGSVG::onPrepareToRender(SkSVGRenderContext* ctx) const {
34 // x/y are ignored for outermost svg elements
35 const auto x = fType == Type::kInner ? fX : SkSVGLength(0);
36 const auto y = fType == Type::kInner ? fY : SkSVGLength(0);
37
38 auto viewPortRect = ctx->lengthContext().resolveRect(x, y, fWidth, fHeight);
39 auto contentMatrix = SkMatrix::Translate(viewPortRect.x(), viewPortRect.y());
40 auto viewPort = SkSize::Make(viewPortRect.width(), viewPortRect.height());
41
42 if (fViewBox.isValid()) {
43 const SkRect& viewBox = *fViewBox;
44
45 // An empty viewbox disables rendering.
46 if (viewBox.isEmpty()) {
47 return false;
48 }
49
50 // A viewBox overrides the intrinsic viewport.
51 viewPort = SkSize::Make(viewBox.width(), viewBox.height());
52
53 contentMatrix.preConcat(ComputeViewboxMatrix(viewBox, viewPortRect, fPreserveAspectRatio));
54 }
55
56 if (!contentMatrix.isIdentity()) {
57 ctx->saveOnce();
58 ctx->canvas()->concat(contentMatrix);
59 }
60
61 if (viewPort != ctx->lengthContext().viewPort()) {
62 ctx->writableLengthContext()->setViewPort(viewPort);
63 }
64
65 return this->INHERITED::onPrepareToRender(ctx);
66 }
67
onSetAttribute(SkSVGAttribute attr,const SkSVGValue & v)68 void SkSVGSVG::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
69 switch (attr) {
70 case SkSVGAttribute::kX:
71 if (const auto* x = v.as<SkSVGLengthValue>()) {
72 this->setX(*x);
73 }
74 break;
75 case SkSVGAttribute::kY:
76 if (const auto* y = v.as<SkSVGLengthValue>()) {
77 this->setY(*y);
78 }
79 break;
80 case SkSVGAttribute::kWidth:
81 if (const auto* w = v.as<SkSVGLengthValue>()) {
82 this->setWidth(*w);
83 }
84 break;
85 case SkSVGAttribute::kHeight:
86 if (const auto* h = v.as<SkSVGLengthValue>()) {
87 this->setHeight(*h);
88 }
89 break;
90 case SkSVGAttribute::kViewBox:
91 if (const auto* vb = v.as<SkSVGViewBoxValue>()) {
92 this->setViewBox(*vb);
93 }
94 break;
95 case SkSVGAttribute::kPreserveAspectRatio:
96 if (const auto* par = v.as<SkSVGPreserveAspectRatioValue>()) {
97 this->setPreserveAspectRatio(*par);
98 }
99 break;
100 default:
101 this->INHERITED::onSetAttribute(attr, v);
102 }
103 }
104
105 // https://www.w3.org/TR/SVG11/coords.html#IntrinsicSizing
intrinsicSize(const SkSVGLengthContext & lctx) const106 SkSize SkSVGSVG::intrinsicSize(const SkSVGLengthContext& lctx) const {
107 // Percentage values do not provide an intrinsic size.
108 if (fWidth.unit() == SkSVGLength::Unit::kPercentage ||
109 fHeight.unit() == SkSVGLength::Unit::kPercentage) {
110 return SkSize::Make(0, 0);
111 }
112
113 return SkSize::Make(lctx.resolve(fWidth, SkSVGLengthContext::LengthType::kHorizontal),
114 lctx.resolve(fHeight, SkSVGLengthContext::LengthType::kVertical));
115 }
116