xref: /aosp_15_r20/external/skia/modules/svg/src/SkSVGRect.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 "include/core/SkCanvas.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRRect.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "modules/svg/include/SkSVGAttributeParser.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "modules/svg/include/SkSVGRect.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "modules/svg/include/SkSVGRenderContext.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "modules/svg/src/SkSVGRectPriv.h"
15*c8dee2aaSAndroid Build Coastguard Worker 
16*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
17*c8dee2aaSAndroid Build Coastguard Worker #include <tuple>
18*c8dee2aaSAndroid Build Coastguard Worker 
19*c8dee2aaSAndroid Build Coastguard Worker class SkPaint;
20*c8dee2aaSAndroid Build Coastguard Worker enum class SkPathFillType;
21*c8dee2aaSAndroid Build Coastguard Worker 
ResolveOptionalRadii(const SkTLazy<SkSVGLength> & opt_rx,const SkTLazy<SkSVGLength> & opt_ry,const SkSVGLengthContext & lctx)22*c8dee2aaSAndroid Build Coastguard Worker std::tuple<float, float> ResolveOptionalRadii(const SkTLazy<SkSVGLength>& opt_rx,
23*c8dee2aaSAndroid Build Coastguard Worker                                               const SkTLazy<SkSVGLength>& opt_ry,
24*c8dee2aaSAndroid Build Coastguard Worker                                               const SkSVGLengthContext& lctx) {
25*c8dee2aaSAndroid Build Coastguard Worker     // https://www.w3.org/TR/SVG2/shapes.html#RectElement
26*c8dee2aaSAndroid Build Coastguard Worker     //
27*c8dee2aaSAndroid Build Coastguard Worker     // The used values for rx and ry are determined from the computed values by following these
28*c8dee2aaSAndroid Build Coastguard Worker     // steps in order:
29*c8dee2aaSAndroid Build Coastguard Worker     //
30*c8dee2aaSAndroid Build Coastguard Worker     // 1. If both rx and ry have a computed value of auto (since auto is the initial value for both
31*c8dee2aaSAndroid Build Coastguard Worker     //    properties, this will also occur if neither are specified by the author or if all
32*c8dee2aaSAndroid Build Coastguard Worker     //    author-supplied values are invalid), then the used value of both rx and ry is 0.
33*c8dee2aaSAndroid Build Coastguard Worker     //    (This will result in square corners.)
34*c8dee2aaSAndroid Build Coastguard Worker     // 2. Otherwise, convert specified values to absolute values as follows:
35*c8dee2aaSAndroid Build Coastguard Worker     //     1. If rx is set to a length value or a percentage, but ry is auto, calculate an absolute
36*c8dee2aaSAndroid Build Coastguard Worker     //        length equivalent for rx, resolving percentages against the used width of the
37*c8dee2aaSAndroid Build Coastguard Worker     //        rectangle; the absolute value for ry is the same.
38*c8dee2aaSAndroid Build Coastguard Worker     //     2. If ry is set to a length value or a percentage, but rx is auto, calculate the absolute
39*c8dee2aaSAndroid Build Coastguard Worker     //        length equivalent for ry, resolving percentages against the used height of the
40*c8dee2aaSAndroid Build Coastguard Worker     //        rectangle; the absolute value for rx is the same.
41*c8dee2aaSAndroid Build Coastguard Worker     //     3. If both rx and ry were set to lengths or percentages, absolute values are generated
42*c8dee2aaSAndroid Build Coastguard Worker     //        individually, resolving rx percentages against the used width, and resolving ry
43*c8dee2aaSAndroid Build Coastguard Worker     //        percentages against the used height.
44*c8dee2aaSAndroid Build Coastguard Worker     const float rx = opt_rx.isValid()
45*c8dee2aaSAndroid Build Coastguard Worker         ? lctx.resolve(*opt_rx, SkSVGLengthContext::LengthType::kHorizontal)
46*c8dee2aaSAndroid Build Coastguard Worker         : 0;
47*c8dee2aaSAndroid Build Coastguard Worker     const float ry = opt_ry.isValid()
48*c8dee2aaSAndroid Build Coastguard Worker         ? lctx.resolve(*opt_ry, SkSVGLengthContext::LengthType::kVertical)
49*c8dee2aaSAndroid Build Coastguard Worker         : 0;
50*c8dee2aaSAndroid Build Coastguard Worker 
51*c8dee2aaSAndroid Build Coastguard Worker     return std::make_tuple(opt_rx.isValid() ? rx : ry,
52*c8dee2aaSAndroid Build Coastguard Worker                            opt_ry.isValid() ? ry : rx);
53*c8dee2aaSAndroid Build Coastguard Worker }
54*c8dee2aaSAndroid Build Coastguard Worker 
SkSVGRect()55*c8dee2aaSAndroid Build Coastguard Worker SkSVGRect::SkSVGRect() : INHERITED(SkSVGTag::kRect) {}
56*c8dee2aaSAndroid Build Coastguard Worker 
parseAndSetAttribute(const char * n,const char * v)57*c8dee2aaSAndroid Build Coastguard Worker bool SkSVGRect::parseAndSetAttribute(const char* n, const char* v) {
58*c8dee2aaSAndroid Build Coastguard Worker     return INHERITED::parseAndSetAttribute(n, v) ||
59*c8dee2aaSAndroid Build Coastguard Worker            this->setX(SkSVGAttributeParser::parse<SkSVGLength>("x", n, v)) ||
60*c8dee2aaSAndroid Build Coastguard Worker            this->setY(SkSVGAttributeParser::parse<SkSVGLength>("y", n, v)) ||
61*c8dee2aaSAndroid Build Coastguard Worker            this->setWidth(SkSVGAttributeParser::parse<SkSVGLength>("width", n, v)) ||
62*c8dee2aaSAndroid Build Coastguard Worker            this->setHeight(SkSVGAttributeParser::parse<SkSVGLength>("height", n, v)) ||
63*c8dee2aaSAndroid Build Coastguard Worker            this->setRx(SkSVGAttributeParser::parse<SkSVGLength>("rx", n, v)) ||
64*c8dee2aaSAndroid Build Coastguard Worker            this->setRy(SkSVGAttributeParser::parse<SkSVGLength>("ry", n, v));
65*c8dee2aaSAndroid Build Coastguard Worker }
66*c8dee2aaSAndroid Build Coastguard Worker 
resolve(const SkSVGLengthContext & lctx) const67*c8dee2aaSAndroid Build Coastguard Worker SkRRect SkSVGRect::resolve(const SkSVGLengthContext& lctx) const {
68*c8dee2aaSAndroid Build Coastguard Worker     const auto rect = lctx.resolveRect(fX, fY, fWidth, fHeight);
69*c8dee2aaSAndroid Build Coastguard Worker     const auto [ rx, ry ] = ResolveOptionalRadii(fRx, fRy, lctx);
70*c8dee2aaSAndroid Build Coastguard Worker 
71*c8dee2aaSAndroid Build Coastguard Worker     // https://www.w3.org/TR/SVG2/shapes.html#RectElement
72*c8dee2aaSAndroid Build Coastguard Worker     // ...
73*c8dee2aaSAndroid Build Coastguard Worker     // 3. Finally, apply clamping to generate the used values:
74*c8dee2aaSAndroid Build Coastguard Worker     //     1. If the absolute rx (after the above steps) is greater than half of the used width,
75*c8dee2aaSAndroid Build Coastguard Worker     //        then the used value of rx is half of the used width.
76*c8dee2aaSAndroid Build Coastguard Worker     //     2. If the absolute ry (after the above steps) is greater than half of the used height,
77*c8dee2aaSAndroid Build Coastguard Worker     //        then the used value of ry is half of the used height.
78*c8dee2aaSAndroid Build Coastguard Worker     //     3. Otherwise, the used values of rx and ry are the absolute values computed previously.
79*c8dee2aaSAndroid Build Coastguard Worker 
80*c8dee2aaSAndroid Build Coastguard Worker     return SkRRect::MakeRectXY(rect,
81*c8dee2aaSAndroid Build Coastguard Worker                                std::min(rx, rect.width() / 2),
82*c8dee2aaSAndroid Build Coastguard Worker                                std::min(ry, rect.height() / 2));
83*c8dee2aaSAndroid Build Coastguard Worker }
84*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas,const SkSVGLengthContext & lctx,const SkPaint & paint,SkPathFillType) const85*c8dee2aaSAndroid Build Coastguard Worker void SkSVGRect::onDraw(SkCanvas* canvas, const SkSVGLengthContext& lctx,
86*c8dee2aaSAndroid Build Coastguard Worker                        const SkPaint& paint, SkPathFillType) const {
87*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawRRect(this->resolve(lctx), paint);
88*c8dee2aaSAndroid Build Coastguard Worker }
89*c8dee2aaSAndroid Build Coastguard Worker 
onAsPath(const SkSVGRenderContext & ctx) const90*c8dee2aaSAndroid Build Coastguard Worker SkPath SkSVGRect::onAsPath(const SkSVGRenderContext& ctx) const {
91*c8dee2aaSAndroid Build Coastguard Worker     SkPath path = SkPath::RRect(this->resolve(ctx.lengthContext()));
92*c8dee2aaSAndroid Build Coastguard Worker 
93*c8dee2aaSAndroid Build Coastguard Worker     this->mapToParent(&path);
94*c8dee2aaSAndroid Build Coastguard Worker 
95*c8dee2aaSAndroid Build Coastguard Worker     return path;
96*c8dee2aaSAndroid Build Coastguard Worker }
97*c8dee2aaSAndroid Build Coastguard Worker 
onObjectBoundingBox(const SkSVGRenderContext & ctx) const98*c8dee2aaSAndroid Build Coastguard Worker SkRect SkSVGRect::onObjectBoundingBox(const SkSVGRenderContext& ctx) const {
99*c8dee2aaSAndroid Build Coastguard Worker     return ctx.lengthContext().resolveRect(fX, fY, fWidth, fHeight);
100*c8dee2aaSAndroid Build Coastguard Worker }
101