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