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