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