xref: /aosp_15_r20/external/skia/modules/svg/src/SkSVGSVG.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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