xref: /aosp_15_r20/external/skia/tests/ClipCubicTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2011 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/SkBitmap.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkFloatBits.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkCubicClipper.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "tests/Test.h"
24*c8dee2aaSAndroid Build Coastguard Worker 
25*c8dee2aaSAndroid Build Coastguard Worker // Currently the supersampler blitter uses int16_t for its index into an array
26*c8dee2aaSAndroid Build Coastguard Worker // the width of the clip. Test that we don't crash/assert if we try to draw
27*c8dee2aaSAndroid Build Coastguard Worker // with a device/clip that is larger.
test_giantClip()28*c8dee2aaSAndroid Build Coastguard Worker static void test_giantClip() {
29*c8dee2aaSAndroid Build Coastguard Worker     SkBitmap bm;
30*c8dee2aaSAndroid Build Coastguard Worker     bm.allocN32Pixels(64919, 1);
31*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas canvas(bm);
32*c8dee2aaSAndroid Build Coastguard Worker     canvas.clear(SK_ColorTRANSPARENT);
33*c8dee2aaSAndroid Build Coastguard Worker 
34*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
35*c8dee2aaSAndroid Build Coastguard Worker     paint.setAntiAlias(true);
36*c8dee2aaSAndroid Build Coastguard Worker     canvas.drawPath(SkPath::Polygon({{0,0}, {1,0}, {33,1}}, false), paint);
37*c8dee2aaSAndroid Build Coastguard Worker }
38*c8dee2aaSAndroid Build Coastguard Worker 
PrintCurve(const char * name,const SkPoint crv[4])39*c8dee2aaSAndroid Build Coastguard Worker static void PrintCurve(const char *name, const SkPoint crv[4]) {
40*c8dee2aaSAndroid Build Coastguard Worker     SkDebugf("%s: %.10g, %.10g, %.10g, %.10g, %.10g, %.10g, %.10g, %.10g\n",
41*c8dee2aaSAndroid Build Coastguard Worker             name,
42*c8dee2aaSAndroid Build Coastguard Worker             (float)crv[0].fX, (float)crv[0].fY,
43*c8dee2aaSAndroid Build Coastguard Worker             (float)crv[1].fX, (float)crv[1].fY,
44*c8dee2aaSAndroid Build Coastguard Worker             (float)crv[2].fX, (float)crv[2].fY,
45*c8dee2aaSAndroid Build Coastguard Worker             (float)crv[3].fX, (float)crv[3].fY);
46*c8dee2aaSAndroid Build Coastguard Worker 
47*c8dee2aaSAndroid Build Coastguard Worker }
48*c8dee2aaSAndroid Build Coastguard Worker 
49*c8dee2aaSAndroid Build Coastguard Worker 
CurvesAreEqual(const SkPoint c0[4],const SkPoint c1[4],float tol)50*c8dee2aaSAndroid Build Coastguard Worker static bool CurvesAreEqual(const SkPoint c0[4],
51*c8dee2aaSAndroid Build Coastguard Worker                            const SkPoint c1[4],
52*c8dee2aaSAndroid Build Coastguard Worker                            float tol) {
53*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < 4; i++) {
54*c8dee2aaSAndroid Build Coastguard Worker         if (SkScalarAbs(c0[i].fX - c1[i].fX) > tol ||
55*c8dee2aaSAndroid Build Coastguard Worker             SkScalarAbs(c0[i].fY - c1[i].fY) > tol
56*c8dee2aaSAndroid Build Coastguard Worker         ) {
57*c8dee2aaSAndroid Build Coastguard Worker             PrintCurve("c0", c0);
58*c8dee2aaSAndroid Build Coastguard Worker             PrintCurve("c1", c1);
59*c8dee2aaSAndroid Build Coastguard Worker             return false;
60*c8dee2aaSAndroid Build Coastguard Worker         }
61*c8dee2aaSAndroid Build Coastguard Worker     }
62*c8dee2aaSAndroid Build Coastguard Worker     return true;
63*c8dee2aaSAndroid Build Coastguard Worker }
64*c8dee2aaSAndroid Build Coastguard Worker 
65*c8dee2aaSAndroid Build Coastguard Worker 
SetCurve(float x0,float y0,float x1,float y1,float x2,float y2,float x3,float y3,SkPoint crv[4])66*c8dee2aaSAndroid Build Coastguard Worker static SkPoint* SetCurve(float x0, float y0,
67*c8dee2aaSAndroid Build Coastguard Worker                          float x1, float y1,
68*c8dee2aaSAndroid Build Coastguard Worker                          float x2, float y2,
69*c8dee2aaSAndroid Build Coastguard Worker                          float x3, float y3,
70*c8dee2aaSAndroid Build Coastguard Worker                          SkPoint crv[4]) {
71*c8dee2aaSAndroid Build Coastguard Worker     crv[0].fX = x0;   crv[0].fY = y0;
72*c8dee2aaSAndroid Build Coastguard Worker     crv[1].fX = x1;   crv[1].fY = y1;
73*c8dee2aaSAndroid Build Coastguard Worker     crv[2].fX = x2;   crv[2].fY = y2;
74*c8dee2aaSAndroid Build Coastguard Worker     crv[3].fX = x3;   crv[3].fY = y3;
75*c8dee2aaSAndroid Build Coastguard Worker     return crv;
76*c8dee2aaSAndroid Build Coastguard Worker }
77*c8dee2aaSAndroid Build Coastguard Worker 
78*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(ClipCubic,reporter)79*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(ClipCubic, reporter) {
80*c8dee2aaSAndroid Build Coastguard Worker     static SkPoint crv[4] = {
81*c8dee2aaSAndroid Build Coastguard Worker         { SkIntToScalar(0), SkIntToScalar(0)  },
82*c8dee2aaSAndroid Build Coastguard Worker         { SkIntToScalar(2), SkIntToScalar(3)  },
83*c8dee2aaSAndroid Build Coastguard Worker         { SkIntToScalar(1), SkIntToScalar(10) },
84*c8dee2aaSAndroid Build Coastguard Worker         { SkIntToScalar(4), SkIntToScalar(12) }
85*c8dee2aaSAndroid Build Coastguard Worker     };
86*c8dee2aaSAndroid Build Coastguard Worker 
87*c8dee2aaSAndroid Build Coastguard Worker     SkCubicClipper clipper;
88*c8dee2aaSAndroid Build Coastguard Worker     SkPoint clipped[4], shouldbe[4];
89*c8dee2aaSAndroid Build Coastguard Worker     SkIRect clipRect;
90*c8dee2aaSAndroid Build Coastguard Worker     bool success;
91*c8dee2aaSAndroid Build Coastguard Worker     const float tol = 1e-4f;
92*c8dee2aaSAndroid Build Coastguard Worker 
93*c8dee2aaSAndroid Build Coastguard Worker     // Test no clip, with plenty of room.
94*c8dee2aaSAndroid Build Coastguard Worker     clipRect.setLTRB(-2, -2, 6, 14);
95*c8dee2aaSAndroid Build Coastguard Worker     clipper.setClip(clipRect);
96*c8dee2aaSAndroid Build Coastguard Worker     success = clipper.clipCubic(crv, clipped);
97*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, success == true);
98*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
99*c8dee2aaSAndroid Build Coastguard Worker         0, 0, 2, 3, 1, 10, 4, 12, shouldbe), tol));
100*c8dee2aaSAndroid Build Coastguard Worker 
101*c8dee2aaSAndroid Build Coastguard Worker     // Test no clip, touching first point.
102*c8dee2aaSAndroid Build Coastguard Worker     clipRect.setLTRB(-2, 0, 6, 14);
103*c8dee2aaSAndroid Build Coastguard Worker     clipper.setClip(clipRect);
104*c8dee2aaSAndroid Build Coastguard Worker     success = clipper.clipCubic(crv, clipped);
105*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, success == true);
106*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
107*c8dee2aaSAndroid Build Coastguard Worker         0, 0, 2, 3, 1, 10, 4, 12, shouldbe), tol));
108*c8dee2aaSAndroid Build Coastguard Worker 
109*c8dee2aaSAndroid Build Coastguard Worker     // Test no clip, touching last point.
110*c8dee2aaSAndroid Build Coastguard Worker     clipRect.setLTRB(-2, -2, 6, 12);
111*c8dee2aaSAndroid Build Coastguard Worker     clipper.setClip(clipRect);
112*c8dee2aaSAndroid Build Coastguard Worker     success = clipper.clipCubic(crv, clipped);
113*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, success == true);
114*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
115*c8dee2aaSAndroid Build Coastguard Worker         0, 0, 2, 3, 1, 10, 4, 12, shouldbe), tol));
116*c8dee2aaSAndroid Build Coastguard Worker 
117*c8dee2aaSAndroid Build Coastguard Worker     // Test all clip.
118*c8dee2aaSAndroid Build Coastguard Worker     clipRect.setLTRB(-2, 14, 6, 20);
119*c8dee2aaSAndroid Build Coastguard Worker     clipper.setClip(clipRect);
120*c8dee2aaSAndroid Build Coastguard Worker     success = clipper.clipCubic(crv, clipped);
121*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, success == false);
122*c8dee2aaSAndroid Build Coastguard Worker 
123*c8dee2aaSAndroid Build Coastguard Worker     // Test clip at 1.
124*c8dee2aaSAndroid Build Coastguard Worker     clipRect.setLTRB(-2, 1, 6, 14);
125*c8dee2aaSAndroid Build Coastguard Worker     clipper.setClip(clipRect);
126*c8dee2aaSAndroid Build Coastguard Worker     success = clipper.clipCubic(crv, clipped);
127*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, success == true);
128*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
129*c8dee2aaSAndroid Build Coastguard Worker         0.5126125216f, 1,
130*c8dee2aaSAndroid Build Coastguard Worker         1.841195941f,  4.337081432f,
131*c8dee2aaSAndroid Build Coastguard Worker         1.297019958f,  10.19801331f,
132*c8dee2aaSAndroid Build Coastguard Worker         4,            12,
133*c8dee2aaSAndroid Build Coastguard Worker         shouldbe), tol));
134*c8dee2aaSAndroid Build Coastguard Worker 
135*c8dee2aaSAndroid Build Coastguard Worker     // Test clip at 2.
136*c8dee2aaSAndroid Build Coastguard Worker     clipRect.setLTRB(-2, 2, 6, 14);
137*c8dee2aaSAndroid Build Coastguard Worker     clipper.setClip(clipRect);
138*c8dee2aaSAndroid Build Coastguard Worker     success = clipper.clipCubic(crv, clipped);
139*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, success == true);
140*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
141*c8dee2aaSAndroid Build Coastguard Worker         00.8412352204f, 2,
142*c8dee2aaSAndroid Build Coastguard Worker         1.767683744f,   5.400758266f,
143*c8dee2aaSAndroid Build Coastguard Worker         1.55052948f,    10.36701965f,
144*c8dee2aaSAndroid Build Coastguard Worker         4,             12,
145*c8dee2aaSAndroid Build Coastguard Worker         shouldbe), tol));
146*c8dee2aaSAndroid Build Coastguard Worker 
147*c8dee2aaSAndroid Build Coastguard Worker     // Test clip at 11.
148*c8dee2aaSAndroid Build Coastguard Worker     clipRect.setLTRB(-2, -2, 6, 11);
149*c8dee2aaSAndroid Build Coastguard Worker     clipper.setClip(clipRect);
150*c8dee2aaSAndroid Build Coastguard Worker     success = clipper.clipCubic(crv, clipped);
151*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, success == true);
152*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
153*c8dee2aaSAndroid Build Coastguard Worker         0,           0,
154*c8dee2aaSAndroid Build Coastguard Worker         1.742904663f, 2.614356995f,
155*c8dee2aaSAndroid Build Coastguard Worker         1.207521796f, 8.266430855f,
156*c8dee2aaSAndroid Build Coastguard Worker         3.026495695f, 11,
157*c8dee2aaSAndroid Build Coastguard Worker         shouldbe), tol));
158*c8dee2aaSAndroid Build Coastguard Worker 
159*c8dee2aaSAndroid Build Coastguard Worker     // Test clip at 10.
160*c8dee2aaSAndroid Build Coastguard Worker     clipRect.setLTRB(-2, -2, 6, 10);
161*c8dee2aaSAndroid Build Coastguard Worker     clipper.setClip(clipRect);
162*c8dee2aaSAndroid Build Coastguard Worker     success = clipper.clipCubic(crv, clipped);
163*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, success == true);
164*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, CurvesAreEqual(clipped, SetCurve(
165*c8dee2aaSAndroid Build Coastguard Worker         0,           0,
166*c8dee2aaSAndroid Build Coastguard Worker         1.551193237f, 2.326789856f,
167*c8dee2aaSAndroid Build Coastguard Worker         1.297736168f, 7.059780121f,
168*c8dee2aaSAndroid Build Coastguard Worker         2.505550385f, 10,
169*c8dee2aaSAndroid Build Coastguard Worker         shouldbe), tol));
170*c8dee2aaSAndroid Build Coastguard Worker 
171*c8dee2aaSAndroid Build Coastguard Worker     test_giantClip();
172*c8dee2aaSAndroid Build Coastguard Worker }
173*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(test_fuzz_crbug_698714,reporter)174*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(test_fuzz_crbug_698714, reporter) {
175*c8dee2aaSAndroid Build Coastguard Worker     auto surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(500, 500)));
176*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas* canvas = surface->getCanvas();
177*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
178*c8dee2aaSAndroid Build Coastguard Worker     paint.setAntiAlias(true);
179*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
180*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000));  // 0,0
181*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x43434343), SkBits2Float(0x43430143));  //195.263f, 195.005f
182*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x43434343), SkBits2Float(0x43434343));  //195.263f, 195.263f
183*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xb5434343), SkBits2Float(0x434300be));  //-7.2741e-07f, 195.003f
184*c8dee2aaSAndroid Build Coastguard Worker     // 195.263f, 195.263f, -1.16387e-05f, 3.58641e-38f, 3.85088e-29f,1.86082e-39f
185*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(SkBits2Float(0x43434343), SkBits2Float(0x43434341),
186*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0xb74343bd), SkBits2Float(0x01434343),
187*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0x10434343), SkBits2Float(0x00144332));
188*c8dee2aaSAndroid Build Coastguard Worker     // 4.11823e-38f, 195.263f, 195.263f, 195.263f, -7.2741e-07f, 195.263f
189*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(SkBits2Float(0x016037c0), SkBits2Float(0x43434343),
190*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0x43434343), SkBits2Float(0x43434343),
191*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0xb5434343), SkBits2Float(0x43434343));
192*c8dee2aaSAndroid Build Coastguard Worker     // 195.263f, 195.263f, -1.16387e-05f, 3.58641e-38f, 195.263f, -2
193*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(SkBits2Float(0x43434344), SkBits2Float(0x43434341),
194*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0xb74343bd), SkBits2Float(0x01434343),
195*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0x43434343), SkBits2Float(0xc0000014));
196*c8dee2aaSAndroid Build Coastguard Worker     // -5.87228e+06f, 3.7773e-07f, 3.60231e-13f, -6.64511e+06f,2.77692e-15f, 2.48803e-15f
197*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(SkBits2Float(0xcab33535), SkBits2Float(0x34cacaca),
198*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0x2acacaca), SkBits2Float(0xcacacae3),
199*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0x27481927), SkBits2Float(0x27334805));
200*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xb5434343), SkBits2Float(0x43434343));  //-7.2741e-07f, 195.263f
201*c8dee2aaSAndroid Build Coastguard Worker     // 195.263f, 195.263f, -1.16387e-05f, 195.212f, 195.263f, -2
202*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(SkBits2Float(0x43434343), SkBits2Float(0x43434341),
203*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0xb74343b9), SkBits2Float(0x43433643),
204*c8dee2aaSAndroid Build Coastguard Worker             SkBits2Float(0x43434343), SkBits2Float(0xc0000014));
205*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0xc7004343), SkBits2Float(0x27480527));  //-32835.3f, 2.77584e-15f
206*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000));  // 0,0
207*c8dee2aaSAndroid Build Coastguard Worker     path.close();
208*c8dee2aaSAndroid Build Coastguard Worker     canvas->clipRect({0, 0, 65, 202});
209*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawPath(path, paint);
210*c8dee2aaSAndroid Build Coastguard Worker }
211*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(cubic_scan_error_crbug_844457_and_845489,reporter)212*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(cubic_scan_error_crbug_844457_and_845489, reporter) {
213*c8dee2aaSAndroid Build Coastguard Worker     auto surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(100, 100)));
214*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas* canvas = surface->getCanvas();
215*c8dee2aaSAndroid Build Coastguard Worker     SkPaint p;
216*c8dee2aaSAndroid Build Coastguard Worker 
217*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
218*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(-30/64.0, -31/64.0);
219*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(-31/64.0, -31/64,-31/64.0, -31/64,-31/64.0, 100);
220*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(100, 100);
221*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawPath(path, p);
222*c8dee2aaSAndroid Build Coastguard Worker 
223*c8dee2aaSAndroid Build Coastguard Worker     // May need to define SK_RASTERIZE_EVEN_ROUNDING to trigger the need for this test
224*c8dee2aaSAndroid Build Coastguard Worker     path.reset();
225*c8dee2aaSAndroid Build Coastguard Worker     path.moveTo(-30/64.0f,             -31/64.0f + 1/256.0f);
226*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(-31/64.0f + 1/256.0f, -31/64.0f + 1/256.0f,
227*c8dee2aaSAndroid Build Coastguard Worker                  -31/64.0f + 1/256.0f, -31/64.0f + 1/256.0f,
228*c8dee2aaSAndroid Build Coastguard Worker                  -31/64.0f + 1/256.0f, 100);
229*c8dee2aaSAndroid Build Coastguard Worker     path.lineTo(100, 100);
230*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawPath(path, p);
231*c8dee2aaSAndroid Build Coastguard Worker }
232