xref: /aosp_15_r20/external/skia/tests/PathOpsTightBoundsTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2013 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 #include "include/core/SkBitmap.h"
8 #include "include/core/SkCanvas.h"
9 #include "include/core/SkColor.h"
10 #include "include/core/SkPaint.h"
11 #include "include/core/SkPath.h"
12 #include "include/core/SkRect.h"
13 #include "include/pathops/SkPathOps.h"
14 #include "include/private/base/SkTDArray.h"
15 #include "src/base/SkRandom.h"
16 #include "tests/PathOpsExtendedTest.h"
17 #include "tests/PathOpsThreadedCommon.h"
18 #include "tests/Test.h"
19 
20 #include <algorithm>
21 #include <cstdint>
22 
testTightBoundsLines(PathOpsThreadState * data)23 static void testTightBoundsLines(PathOpsThreadState* data) {
24     SkRandom ran;
25     for (int index = 0; index < 1000; ++index) {
26         SkPath path;
27         int contourCount = ran.nextRangeU(1, 10);
28         for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
29             int lineCount = ran.nextRangeU(1, 10);
30             path.moveTo(ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000));
31             for (int lIndex = 0; lIndex < lineCount; ++lIndex) {
32                 path.lineTo(ran.nextRangeF(-1000, 1000), ran.nextRangeF(-1000, 1000));
33             }
34             if (ran.nextBool()) {
35                 path.close();
36             }
37         }
38         SkRect classicBounds = path.getBounds();
39         SkRect tightBounds;
40         REPORTER_ASSERT(data->fReporter, TightBounds(path, &tightBounds));
41         REPORTER_ASSERT(data->fReporter, classicBounds == tightBounds);
42     }
43 }
44 
DEF_TEST(PathOpsTightBoundsLines,reporter)45 DEF_TEST(PathOpsTightBoundsLines, reporter) {
46     initializeTests(reporter, "tightBoundsLines");
47     PathOpsThreadedTestRunner testRunner(reporter);
48     int outerCount = reporter->allowExtendedTest() ? 100 : 1;
49     for (int index = 0; index < outerCount; ++index) {
50         for (int idx2 = 0; idx2 < 10; ++idx2) {
51             *testRunner.fRunnables.append() =
52                     new PathOpsThreadedRunnable(&testTightBoundsLines, 0, 0, 0, 0, &testRunner);
53         }
54     }
55     testRunner.render();
56 }
57 
testTightBoundsQuads(PathOpsThreadState * data)58 static void testTightBoundsQuads(PathOpsThreadState* data) {
59     SkRandom ran;
60     const int bitWidth = 32;
61     const int bitHeight = 32;
62     const float pathMin = 1;
63     const float pathMax = (float) (bitHeight - 2);
64     SkBitmap& bits = *data->fBitmap;
65     if (bits.width() == 0) {
66         bits.allocN32Pixels(bitWidth, bitHeight);
67     }
68     SkCanvas canvas(bits);
69     SkPaint paint;
70     for (int index = 0; index < 100; ++index) {
71         SkPath path;
72         int contourCount = ran.nextRangeU(1, 10);
73         for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
74             int lineCount = ran.nextRangeU(1, 10);
75             path.moveTo(ran.nextRangeF(1, pathMax), ran.nextRangeF(pathMin, pathMax));
76             for (int lIndex = 0; lIndex < lineCount; ++lIndex) {
77                 if (ran.nextBool()) {
78                     path.lineTo(ran.nextRangeF(pathMin, pathMax), ran.nextRangeF(pathMin, pathMax));
79                 } else {
80                     path.quadTo(ran.nextRangeF(pathMin, pathMax), ran.nextRangeF(pathMin, pathMax),
81                             ran.nextRangeF(pathMin, pathMax), ran.nextRangeF(pathMin, pathMax));
82                 }
83             }
84             if (ran.nextBool()) {
85                 path.close();
86             }
87         }
88         SkRect classicBounds = path.getBounds();
89         SkRect tightBounds;
90         REPORTER_ASSERT(data->fReporter, TightBounds(path, &tightBounds));
91         REPORTER_ASSERT(data->fReporter, classicBounds.contains(tightBounds));
92         canvas.drawColor(SK_ColorWHITE);
93         canvas.drawPath(path, paint);
94         SkIRect bitsWritten = {31, 31, 0, 0};
95         for (int y = 0; y < bitHeight; ++y) {
96             uint32_t* addr1 = data->fBitmap->getAddr32(0, y);
97             bool lineWritten = false;
98             for (int x = 0; x < bitWidth; ++x) {
99                 if (addr1[x] == (uint32_t) -1) {
100                     continue;
101                 }
102                 lineWritten = true;
103                 bitsWritten.fLeft = std::min(bitsWritten.fLeft, x);
104                 bitsWritten.fRight = std::max(bitsWritten.fRight, x);
105             }
106             if (!lineWritten) {
107                 continue;
108             }
109             bitsWritten.fTop = std::min(bitsWritten.fTop, y);
110             bitsWritten.fBottom = std::max(bitsWritten.fBottom, y);
111         }
112         if (!bitsWritten.isEmpty()) {
113             SkIRect tightOut;
114             tightBounds.roundOut(&tightOut);
115             REPORTER_ASSERT(data->fReporter, tightOut.contains(bitsWritten));
116         }
117     }
118 }
119 
DEF_TEST(PathOpsTightBoundsQuads,reporter)120 DEF_TEST(PathOpsTightBoundsQuads, reporter) {
121     initializeTests(reporter, "tightBoundsQuads");
122     PathOpsThreadedTestRunner testRunner(reporter);
123     int outerCount = reporter->allowExtendedTest() ? 100 : 1;
124     for (int index = 0; index < outerCount; ++index) {
125         for (int idx2 = 0; idx2 < 10; ++idx2) {
126             *testRunner.fRunnables.append() =
127                     new PathOpsThreadedRunnable(&testTightBoundsQuads, 0, 0, 0, 0, &testRunner);
128         }
129     }
130     testRunner.render();
131 }
132 
DEF_TEST(PathOpsTightBoundsMove,reporter)133 DEF_TEST(PathOpsTightBoundsMove, reporter) {
134     SkPath path;
135     path.moveTo(10, 10);
136     path.close();
137     path.moveTo(20, 20);
138     path.lineTo(20, 20);
139     path.close();
140     path.moveTo(15, 15);
141     path.lineTo(15, 15);
142     path.close();
143     const SkRect& bounds = path.getBounds();
144     SkRect tight;
145     REPORTER_ASSERT(reporter, TightBounds(path, &tight));
146     REPORTER_ASSERT(reporter, bounds == tight);
147 }
148 
DEF_TEST(PathOpsTightBoundsMoveOne,reporter)149 DEF_TEST(PathOpsTightBoundsMoveOne, reporter) {
150     SkPath path;
151     path.moveTo(20, 20);
152     const SkRect& bounds = path.getBounds();
153     SkRect tight;
154     REPORTER_ASSERT(reporter, TightBounds(path, &tight));
155     REPORTER_ASSERT(reporter, bounds == tight);
156 }
157 
DEF_TEST(PathOpsTightBoundsMoveTwo,reporter)158 DEF_TEST(PathOpsTightBoundsMoveTwo, reporter) {
159     SkPath path;
160     path.moveTo(20, 20);
161     path.moveTo(40, 40);
162     const SkRect& bounds = path.getBounds();
163     SkRect tight;
164     REPORTER_ASSERT(reporter, TightBounds(path, &tight));
165     REPORTER_ASSERT(reporter, bounds == tight);
166 }
167 
DEF_TEST(PathOpsTightBoundsTiny,reporter)168 DEF_TEST(PathOpsTightBoundsTiny, reporter) {
169     SkPath path;
170     path.moveTo(1, 1);
171     path.quadTo(1.000001f, 1, 1, 1);
172     const SkRect& bounds = path.getBounds();
173     SkRect tight;
174     REPORTER_ASSERT(reporter, TightBounds(path, &tight));
175     SkRect moveBounds = {1, 1, 1, 1};
176     REPORTER_ASSERT(reporter, bounds != tight);
177     REPORTER_ASSERT(reporter, moveBounds == tight);
178 }
179 
DEF_TEST(PathOpsTightBoundsWellBehaved,reporter)180 DEF_TEST(PathOpsTightBoundsWellBehaved, reporter) {
181     SkPath path;
182     path.moveTo(1, 1);
183     path.quadTo(2, 3, 4, 5);
184     const SkRect& bounds = path.getBounds();
185     SkRect tight;
186     REPORTER_ASSERT(reporter, TightBounds(path, &tight));
187     REPORTER_ASSERT(reporter, bounds == tight);
188 }
189 
DEF_TEST(PathOpsTightBoundsIllBehaved,reporter)190 DEF_TEST(PathOpsTightBoundsIllBehaved, reporter) {
191     SkPath path;
192     path.moveTo(1, 1);
193     path.quadTo(4, 3, 2, 2);
194     const SkRect& bounds = path.getBounds();
195     SkRect tight;
196     REPORTER_ASSERT(reporter, TightBounds(path, &tight));
197     REPORTER_ASSERT(reporter, bounds != tight);
198 }
199 
DEF_TEST(PathOpsTightBoundsIllBehavedScaled,reporter)200 DEF_TEST(PathOpsTightBoundsIllBehavedScaled, reporter) {
201     SkPath path;
202     path.moveTo(0, 0);
203     path.quadTo(1048578, 1048577, 1048576, 1048576);
204     const SkRect& bounds = path.getBounds();
205     SkRect tight;
206     REPORTER_ASSERT(reporter, TightBounds(path, &tight));
207     REPORTER_ASSERT(reporter, bounds != tight);
208     REPORTER_ASSERT(reporter, tight.right() == 1048576);
209     REPORTER_ASSERT(reporter, tight.bottom() == 1048576);
210 }
211