1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2012 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "include/core/SkMatrix.h"
9cb93a386Sopenharmony_ci#include "include/core/SkRRect.h"
10cb93a386Sopenharmony_ci#include "include/pathops/SkPathOps.h"
11cb93a386Sopenharmony_ci#include "include/utils/SkRandom.h"
12cb93a386Sopenharmony_ci#include "src/core/SkPointPriv.h"
13cb93a386Sopenharmony_ci#include "src/core/SkRRectPriv.h"
14cb93a386Sopenharmony_ci#include "tests/Test.h"
15cb93a386Sopenharmony_ci
16cb93a386Sopenharmony_cistatic void test_tricky_radii(skiatest::Reporter* reporter) {
17cb93a386Sopenharmony_ci    {
18cb93a386Sopenharmony_ci        // crbug.com/458522
19cb93a386Sopenharmony_ci        SkRRect rr;
20cb93a386Sopenharmony_ci        const SkRect bounds = { 3709, 3709, 3709 + 7402, 3709 + 29825 };
21cb93a386Sopenharmony_ci        const SkScalar rad = 12814;
22cb93a386Sopenharmony_ci        const SkVector vec[] = { { rad, rad }, { 0, rad }, { rad, rad }, { 0, rad } };
23cb93a386Sopenharmony_ci        rr.setRectRadii(bounds, vec);
24cb93a386Sopenharmony_ci    }
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_ci    {
27cb93a386Sopenharmony_ci        // crbug.com//463920
28cb93a386Sopenharmony_ci        SkRect r = SkRect::MakeLTRB(0, 0, 1009, 33554432.0);
29cb93a386Sopenharmony_ci        SkVector radii[4] = {
30cb93a386Sopenharmony_ci            { 13.0f, 8.0f }, { 170.0f, 2.0 }, { 256.0f, 33554432.0 }, { 110.0f, 5.0f }
31cb93a386Sopenharmony_ci        };
32cb93a386Sopenharmony_ci        SkRRect rr;
33cb93a386Sopenharmony_ci        rr.setRectRadii(r, radii);
34cb93a386Sopenharmony_ci
35cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, (double) rr.radii(SkRRect::kUpperRight_Corner).fY +
36cb93a386Sopenharmony_ci                                  (double) rr.radii(SkRRect::kLowerRight_Corner).fY <=
37cb93a386Sopenharmony_ci                                  rr.height());
38cb93a386Sopenharmony_ci    }
39cb93a386Sopenharmony_ci}
40cb93a386Sopenharmony_ci
41cb93a386Sopenharmony_cistatic void test_empty_crbug_458524(skiatest::Reporter* reporter) {
42cb93a386Sopenharmony_ci    SkRRect rr;
43cb93a386Sopenharmony_ci    const SkRect bounds = { 3709, 3709, 3709 + 7402, 3709 + 29825 };
44cb93a386Sopenharmony_ci    const SkScalar rad = 40;
45cb93a386Sopenharmony_ci    rr.setRectXY(bounds, rad, rad);
46cb93a386Sopenharmony_ci
47cb93a386Sopenharmony_ci    SkRRect other;
48cb93a386Sopenharmony_ci    SkMatrix matrix;
49cb93a386Sopenharmony_ci    matrix.setScale(0, 1);
50cb93a386Sopenharmony_ci    rr.transform(matrix, &other);
51cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkRRect::kEmpty_Type == other.getType());
52cb93a386Sopenharmony_ci}
53cb93a386Sopenharmony_ci
54cb93a386Sopenharmony_ci// Test that all the SkRRect entry points correctly handle un-sorted and
55cb93a386Sopenharmony_ci// zero-sized input rects
56cb93a386Sopenharmony_cistatic void test_empty(skiatest::Reporter* reporter) {
57cb93a386Sopenharmony_ci    static const SkRect oooRects[] = {  // out of order
58cb93a386Sopenharmony_ci        { 100, 0, 0, 100 },  // ooo horizontal
59cb93a386Sopenharmony_ci        { 0, 100, 100, 0 },  // ooo vertical
60cb93a386Sopenharmony_ci        { 100, 100, 0, 0 },  // ooo both
61cb93a386Sopenharmony_ci    };
62cb93a386Sopenharmony_ci
63cb93a386Sopenharmony_ci    static const SkRect emptyRects[] = {
64cb93a386Sopenharmony_ci        { 100, 100, 100, 200 }, // empty horizontal
65cb93a386Sopenharmony_ci        { 100, 100, 200, 100 }, // empty vertical
66cb93a386Sopenharmony_ci        { 100, 100, 100, 100 }, // empty both
67cb93a386Sopenharmony_ci        { 0, 0, 0, 0 }          // setEmpty-empty
68cb93a386Sopenharmony_ci    };
69cb93a386Sopenharmony_ci
70cb93a386Sopenharmony_ci    static const SkVector radii[4] = { { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 } };
71cb93a386Sopenharmony_ci
72cb93a386Sopenharmony_ci    SkRRect r;
73cb93a386Sopenharmony_ci
74cb93a386Sopenharmony_ci    for (size_t i = 0; i < SK_ARRAY_COUNT(oooRects); ++i) {
75cb93a386Sopenharmony_ci        r.setRect(oooRects[i]);
76cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, !r.isEmpty());
77cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
78cb93a386Sopenharmony_ci
79cb93a386Sopenharmony_ci        r.setOval(oooRects[i]);
80cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, !r.isEmpty());
81cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
82cb93a386Sopenharmony_ci
83cb93a386Sopenharmony_ci        r.setRectXY(oooRects[i], 1, 2);
84cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, !r.isEmpty());
85cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
86cb93a386Sopenharmony_ci
87cb93a386Sopenharmony_ci        r.setNinePatch(oooRects[i], 0, 1, 2, 3);
88cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, !r.isEmpty());
89cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
90cb93a386Sopenharmony_ci
91cb93a386Sopenharmony_ci        r.setRectRadii(oooRects[i], radii);
92cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, !r.isEmpty());
93cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
94cb93a386Sopenharmony_ci    }
95cb93a386Sopenharmony_ci
96cb93a386Sopenharmony_ci    for (size_t i = 0; i < SK_ARRAY_COUNT(emptyRects); ++i) {
97cb93a386Sopenharmony_ci        r.setRect(emptyRects[i]);
98cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, r.isEmpty());
99cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
100cb93a386Sopenharmony_ci
101cb93a386Sopenharmony_ci        r.setOval(emptyRects[i]);
102cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, r.isEmpty());
103cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
104cb93a386Sopenharmony_ci
105cb93a386Sopenharmony_ci        r.setRectXY(emptyRects[i], 1, 2);
106cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, r.isEmpty());
107cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
108cb93a386Sopenharmony_ci
109cb93a386Sopenharmony_ci        r.setNinePatch(emptyRects[i], 0, 1, 2, 3);
110cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, r.isEmpty());
111cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
112cb93a386Sopenharmony_ci
113cb93a386Sopenharmony_ci        r.setRectRadii(emptyRects[i], radii);
114cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, r.isEmpty());
115cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
116cb93a386Sopenharmony_ci    }
117cb93a386Sopenharmony_ci
118cb93a386Sopenharmony_ci    r.setRect({SK_ScalarNaN, 10, 10, 20});
119cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, r == SkRRect::MakeEmpty());
120cb93a386Sopenharmony_ci    r.setRect({0, 10, 10, SK_ScalarInfinity});
121cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, r == SkRRect::MakeEmpty());
122cb93a386Sopenharmony_ci}
123cb93a386Sopenharmony_ci
124cb93a386Sopenharmony_cistatic const SkScalar kWidth = 100.0f;
125cb93a386Sopenharmony_cistatic const SkScalar kHeight = 100.0f;
126cb93a386Sopenharmony_ci
127cb93a386Sopenharmony_cistatic void test_inset(skiatest::Reporter* reporter) {
128cb93a386Sopenharmony_ci    SkRRect rr, rr2;
129cb93a386Sopenharmony_ci    SkRect r = { 0, 0, 100, 100 };
130cb93a386Sopenharmony_ci
131cb93a386Sopenharmony_ci    rr.setRect(r);
132cb93a386Sopenharmony_ci    rr.inset(-20, -20, &rr2);
133cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, rr2.isRect());
134cb93a386Sopenharmony_ci
135cb93a386Sopenharmony_ci    rr.inset(20, 20, &rr2);
136cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, rr2.isRect());
137cb93a386Sopenharmony_ci
138cb93a386Sopenharmony_ci    rr.inset(r.width()/2, r.height()/2, &rr2);
139cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, rr2.isEmpty());
140cb93a386Sopenharmony_ci
141cb93a386Sopenharmony_ci    rr.setRectXY(r, 20, 20);
142cb93a386Sopenharmony_ci    rr.inset(19, 19, &rr2);
143cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, rr2.isSimple());
144cb93a386Sopenharmony_ci    rr.inset(20, 20, &rr2);
145cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, rr2.isRect());
146cb93a386Sopenharmony_ci}
147cb93a386Sopenharmony_ci
148cb93a386Sopenharmony_ci
149cb93a386Sopenharmony_cistatic void test_9patch_rrect(skiatest::Reporter* reporter,
150cb93a386Sopenharmony_ci                              const SkRect& rect,
151cb93a386Sopenharmony_ci                              SkScalar l, SkScalar t, SkScalar r, SkScalar b,
152cb93a386Sopenharmony_ci                              bool checkRadii) {
153cb93a386Sopenharmony_ci    SkRRect rr;
154cb93a386Sopenharmony_ci    rr.setNinePatch(rect, l, t, r, b);
155cb93a386Sopenharmony_ci
156cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkRRect::kNinePatch_Type == rr.type());
157cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, rr.rect() == rect);
158cb93a386Sopenharmony_ci
159cb93a386Sopenharmony_ci    if (checkRadii) {
160cb93a386Sopenharmony_ci        // This test doesn't hold if the radii will be rescaled by SkRRect
161cb93a386Sopenharmony_ci        SkRect ninePatchRadii = { l, t, r, b };
162cb93a386Sopenharmony_ci        SkPoint rquad[4];
163cb93a386Sopenharmony_ci        ninePatchRadii.toQuad(rquad);
164cb93a386Sopenharmony_ci        for (int i = 0; i < 4; ++i) {
165cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, rquad[i] == rr.radii((SkRRect::Corner) i));
166cb93a386Sopenharmony_ci        }
167cb93a386Sopenharmony_ci    }
168cb93a386Sopenharmony_ci    SkRRect rr2; // construct the same RR using the most general set function
169cb93a386Sopenharmony_ci    SkVector radii[4] = { { l, t }, { r, t }, { r, b }, { l, b } };
170cb93a386Sopenharmony_ci    rr2.setRectRadii(rect, radii);
171cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, rr2 == rr && rr2.getType() == rr.getType());
172cb93a386Sopenharmony_ci}
173cb93a386Sopenharmony_ci
174cb93a386Sopenharmony_ci// Test out the basic API entry points
175cb93a386Sopenharmony_cistatic void test_round_rect_basic(skiatest::Reporter* reporter) {
176cb93a386Sopenharmony_ci    // Test out initialization methods
177cb93a386Sopenharmony_ci    SkPoint zeroPt = { 0, 0 };
178cb93a386Sopenharmony_ci    SkRRect empty;
179cb93a386Sopenharmony_ci
180cb93a386Sopenharmony_ci    empty.setEmpty();
181cb93a386Sopenharmony_ci
182cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkRRect::kEmpty_Type == empty.type());
183cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, empty.rect().isEmpty());
184cb93a386Sopenharmony_ci
185cb93a386Sopenharmony_ci    for (int i = 0; i < 4; ++i) {
186cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, zeroPt == empty.radii((SkRRect::Corner) i));
187cb93a386Sopenharmony_ci    }
188cb93a386Sopenharmony_ci
189cb93a386Sopenharmony_ci    //----
190cb93a386Sopenharmony_ci    SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
191cb93a386Sopenharmony_ci
192cb93a386Sopenharmony_ci    SkRRect rr1;
193cb93a386Sopenharmony_ci    rr1.setRect(rect);
194cb93a386Sopenharmony_ci
195cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr1.type());
196cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, rr1.rect() == rect);
197cb93a386Sopenharmony_ci
198cb93a386Sopenharmony_ci    for (int i = 0; i < 4; ++i) {
199cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, zeroPt == rr1.radii((SkRRect::Corner) i));
200cb93a386Sopenharmony_ci    }
201cb93a386Sopenharmony_ci    SkRRect rr1_2; // construct the same RR using the most general set function
202cb93a386Sopenharmony_ci    SkVector rr1_2_radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
203cb93a386Sopenharmony_ci    rr1_2.setRectRadii(rect, rr1_2_radii);
204cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, rr1_2 == rr1 && rr1_2.getType() == rr1.getType());
205cb93a386Sopenharmony_ci    SkRRect rr1_3;  // construct the same RR using the nine patch set function
206cb93a386Sopenharmony_ci    rr1_3.setNinePatch(rect, 0, 0, 0, 0);
207cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, rr1_3 == rr1 && rr1_3.getType() == rr1.getType());
208cb93a386Sopenharmony_ci
209cb93a386Sopenharmony_ci    //----
210cb93a386Sopenharmony_ci    SkPoint halfPoint = { SkScalarHalf(kWidth), SkScalarHalf(kHeight) };
211cb93a386Sopenharmony_ci    SkRRect rr2;
212cb93a386Sopenharmony_ci    rr2.setOval(rect);
213cb93a386Sopenharmony_ci
214cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkRRect::kOval_Type == rr2.type());
215cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, rr2.rect() == rect);
216cb93a386Sopenharmony_ci
217cb93a386Sopenharmony_ci    for (int i = 0; i < 4; ++i) {
218cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter,
219cb93a386Sopenharmony_ci                        SkPointPriv::EqualsWithinTolerance(rr2.radii((SkRRect::Corner) i),
220cb93a386Sopenharmony_ci                        halfPoint));
221cb93a386Sopenharmony_ci    }
222cb93a386Sopenharmony_ci    SkRRect rr2_2;  // construct the same RR using the most general set function
223cb93a386Sopenharmony_ci    SkVector rr2_2_radii[4] = { { halfPoint.fX, halfPoint.fY }, { halfPoint.fX, halfPoint.fY },
224cb93a386Sopenharmony_ci                                { halfPoint.fX, halfPoint.fY }, { halfPoint.fX, halfPoint.fY } };
225cb93a386Sopenharmony_ci    rr2_2.setRectRadii(rect, rr2_2_radii);
226cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, rr2_2 == rr2 && rr2_2.getType() == rr2.getType());
227cb93a386Sopenharmony_ci    SkRRect rr2_3;  // construct the same RR using the nine patch set function
228cb93a386Sopenharmony_ci    rr2_3.setNinePatch(rect, halfPoint.fX, halfPoint.fY, halfPoint.fX, halfPoint.fY);
229cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, rr2_3 == rr2 && rr2_3.getType() == rr2.getType());
230cb93a386Sopenharmony_ci
231cb93a386Sopenharmony_ci    //----
232cb93a386Sopenharmony_ci    SkPoint p = { 5, 5 };
233cb93a386Sopenharmony_ci    SkRRect rr3;
234cb93a386Sopenharmony_ci    rr3.setRectXY(rect, p.fX, p.fY);
235cb93a386Sopenharmony_ci
236cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkRRect::kSimple_Type == rr3.type());
237cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, rr3.rect() == rect);
238cb93a386Sopenharmony_ci
239cb93a386Sopenharmony_ci    for (int i = 0; i < 4; ++i) {
240cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, p == rr3.radii((SkRRect::Corner) i));
241cb93a386Sopenharmony_ci    }
242cb93a386Sopenharmony_ci    SkRRect rr3_2; // construct the same RR using the most general set function
243cb93a386Sopenharmony_ci    SkVector rr3_2_radii[4] = { { 5, 5 }, { 5, 5 }, { 5, 5 }, { 5, 5 } };
244cb93a386Sopenharmony_ci    rr3_2.setRectRadii(rect, rr3_2_radii);
245cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, rr3_2 == rr3 && rr3_2.getType() == rr3.getType());
246cb93a386Sopenharmony_ci    SkRRect rr3_3;  // construct the same RR using the nine patch set function
247cb93a386Sopenharmony_ci    rr3_3.setNinePatch(rect, 5, 5, 5, 5);
248cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, rr3_3 == rr3 && rr3_3.getType() == rr3.getType());
249cb93a386Sopenharmony_ci
250cb93a386Sopenharmony_ci    //----
251cb93a386Sopenharmony_ci    test_9patch_rrect(reporter, rect, 10, 9, 8, 7, true);
252cb93a386Sopenharmony_ci
253cb93a386Sopenharmony_ci    {
254cb93a386Sopenharmony_ci        // Test out the rrect from skia:3466
255cb93a386Sopenharmony_ci        SkRect rect2 = SkRect::MakeLTRB(0.358211994f, 0.755430222f, 0.872866154f, 0.806214333f);
256cb93a386Sopenharmony_ci
257cb93a386Sopenharmony_ci        test_9patch_rrect(reporter,
258cb93a386Sopenharmony_ci                          rect2,
259cb93a386Sopenharmony_ci                          0.926942348f, 0.642850280f, 0.529063463f, 0.587844372f,
260cb93a386Sopenharmony_ci                          false);
261cb93a386Sopenharmony_ci    }
262cb93a386Sopenharmony_ci
263cb93a386Sopenharmony_ci    //----
264cb93a386Sopenharmony_ci    SkPoint radii2[4] = { { 0, 0 }, { 0, 0 }, { 50, 50 }, { 20, 50 } };
265cb93a386Sopenharmony_ci
266cb93a386Sopenharmony_ci    SkRRect rr5;
267cb93a386Sopenharmony_ci    rr5.setRectRadii(rect, radii2);
268cb93a386Sopenharmony_ci
269cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr5.type());
270cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, rr5.rect() == rect);
271cb93a386Sopenharmony_ci
272cb93a386Sopenharmony_ci    for (int i = 0; i < 4; ++i) {
273cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, radii2[i] == rr5.radii((SkRRect::Corner) i));
274cb93a386Sopenharmony_ci    }
275cb93a386Sopenharmony_ci
276cb93a386Sopenharmony_ci    // Test out == & !=
277cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, empty != rr3);
278cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, rr3 != rr5);
279cb93a386Sopenharmony_ci}
280cb93a386Sopenharmony_ci
281cb93a386Sopenharmony_ci// Test out the cases when the RR degenerates to a rect
282cb93a386Sopenharmony_cistatic void test_round_rect_rects(skiatest::Reporter* reporter) {
283cb93a386Sopenharmony_ci    SkRect r;
284cb93a386Sopenharmony_ci
285cb93a386Sopenharmony_ci    //----
286cb93a386Sopenharmony_ci    SkRRect empty;
287cb93a386Sopenharmony_ci
288cb93a386Sopenharmony_ci    empty.setEmpty();
289cb93a386Sopenharmony_ci
290cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkRRect::kEmpty_Type == empty.type());
291cb93a386Sopenharmony_ci    r = empty.rect();
292cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, 0 == r.fLeft && 0 == r.fTop && 0 == r.fRight && 0 == r.fBottom);
293cb93a386Sopenharmony_ci
294cb93a386Sopenharmony_ci    //----
295cb93a386Sopenharmony_ci    SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
296cb93a386Sopenharmony_ci    SkRRect rr1;
297cb93a386Sopenharmony_ci    rr1.setRectXY(rect, 0, 0);
298cb93a386Sopenharmony_ci
299cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr1.type());
300cb93a386Sopenharmony_ci    r = rr1.rect();
301cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, rect == r);
302cb93a386Sopenharmony_ci
303cb93a386Sopenharmony_ci    //----
304cb93a386Sopenharmony_ci    SkPoint radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
305cb93a386Sopenharmony_ci
306cb93a386Sopenharmony_ci    SkRRect rr2;
307cb93a386Sopenharmony_ci    rr2.setRectRadii(rect, radii);
308cb93a386Sopenharmony_ci
309cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr2.type());
310cb93a386Sopenharmony_ci    r = rr2.rect();
311cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, rect == r);
312cb93a386Sopenharmony_ci
313cb93a386Sopenharmony_ci    //----
314cb93a386Sopenharmony_ci    SkPoint radii2[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } };
315cb93a386Sopenharmony_ci
316cb93a386Sopenharmony_ci    SkRRect rr3;
317cb93a386Sopenharmony_ci    rr3.setRectRadii(rect, radii2);
318cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr3.type());
319cb93a386Sopenharmony_ci}
320cb93a386Sopenharmony_ci
321cb93a386Sopenharmony_ci// Test out the cases when the RR degenerates to an oval
322cb93a386Sopenharmony_cistatic void test_round_rect_ovals(skiatest::Reporter* reporter) {
323cb93a386Sopenharmony_ci    //----
324cb93a386Sopenharmony_ci    SkRect oval;
325cb93a386Sopenharmony_ci    SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
326cb93a386Sopenharmony_ci    SkRRect rr1;
327cb93a386Sopenharmony_ci    rr1.setRectXY(rect, SkScalarHalf(kWidth), SkScalarHalf(kHeight));
328cb93a386Sopenharmony_ci
329cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkRRect::kOval_Type == rr1.type());
330cb93a386Sopenharmony_ci    oval = rr1.rect();
331cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, oval == rect);
332cb93a386Sopenharmony_ci}
333cb93a386Sopenharmony_ci
334cb93a386Sopenharmony_ci// Test out the non-degenerate RR cases
335cb93a386Sopenharmony_cistatic void test_round_rect_general(skiatest::Reporter* reporter) {
336cb93a386Sopenharmony_ci    //----
337cb93a386Sopenharmony_ci    SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
338cb93a386Sopenharmony_ci    SkRRect rr1;
339cb93a386Sopenharmony_ci    rr1.setRectXY(rect, 20, 20);
340cb93a386Sopenharmony_ci
341cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkRRect::kSimple_Type == rr1.type());
342cb93a386Sopenharmony_ci
343cb93a386Sopenharmony_ci    //----
344cb93a386Sopenharmony_ci    SkPoint radii[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } };
345cb93a386Sopenharmony_ci
346cb93a386Sopenharmony_ci    SkRRect rr2;
347cb93a386Sopenharmony_ci    rr2.setRectRadii(rect, radii);
348cb93a386Sopenharmony_ci
349cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr2.type());
350cb93a386Sopenharmony_ci}
351cb93a386Sopenharmony_ci
352cb93a386Sopenharmony_ci// Test out questionable-parameter handling
353cb93a386Sopenharmony_cistatic void test_round_rect_iffy_parameters(skiatest::Reporter* reporter) {
354cb93a386Sopenharmony_ci
355cb93a386Sopenharmony_ci    // When the radii exceed the base rect they are proportionally scaled down
356cb93a386Sopenharmony_ci    // to fit
357cb93a386Sopenharmony_ci    SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
358cb93a386Sopenharmony_ci    SkPoint radii[4] = { { 50, 100 }, { 100, 50 }, { 50, 100 }, { 100, 50 } };
359cb93a386Sopenharmony_ci
360cb93a386Sopenharmony_ci    SkRRect rr1;
361cb93a386Sopenharmony_ci    rr1.setRectRadii(rect, radii);
362cb93a386Sopenharmony_ci
363cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr1.type());
364cb93a386Sopenharmony_ci
365cb93a386Sopenharmony_ci    const SkPoint& p = rr1.radii(SkRRect::kUpperLeft_Corner);
366cb93a386Sopenharmony_ci
367cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.fX, 33.33333f));
368cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.fY, 66.66666f));
369cb93a386Sopenharmony_ci
370cb93a386Sopenharmony_ci    // Negative radii should be capped at zero
371cb93a386Sopenharmony_ci    SkRRect rr2;
372cb93a386Sopenharmony_ci    rr2.setRectXY(rect, -10, -20);
373cb93a386Sopenharmony_ci
374cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr2.type());
375cb93a386Sopenharmony_ci
376cb93a386Sopenharmony_ci    const SkPoint& p2 = rr2.radii(SkRRect::kUpperLeft_Corner);
377cb93a386Sopenharmony_ci
378cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, 0.0f == p2.fX);
379cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, 0.0f == p2.fY);
380cb93a386Sopenharmony_ci}
381cb93a386Sopenharmony_ci
382cb93a386Sopenharmony_ci// Move a small box from the start position by (stepX, stepY) 'numSteps' times
383cb93a386Sopenharmony_ci// testing for containment in 'rr' at each step.
384cb93a386Sopenharmony_cistatic void test_direction(skiatest::Reporter* reporter, const SkRRect &rr,
385cb93a386Sopenharmony_ci                           SkScalar initX, int stepX, SkScalar initY, int stepY,
386cb93a386Sopenharmony_ci                           int numSteps, const bool* contains) {
387cb93a386Sopenharmony_ci    SkScalar x = initX, y = initY;
388cb93a386Sopenharmony_ci    for (int i = 0; i < numSteps; ++i) {
389cb93a386Sopenharmony_ci        SkRect test = SkRect::MakeXYWH(x, y,
390cb93a386Sopenharmony_ci                                       stepX ? SkIntToScalar(stepX) : SK_Scalar1,
391cb93a386Sopenharmony_ci                                       stepY ? SkIntToScalar(stepY) : SK_Scalar1);
392cb93a386Sopenharmony_ci        test.sort();
393cb93a386Sopenharmony_ci
394cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, contains[i] == rr.contains(test));
395cb93a386Sopenharmony_ci
396cb93a386Sopenharmony_ci        x += stepX;
397cb93a386Sopenharmony_ci        y += stepY;
398cb93a386Sopenharmony_ci    }
399cb93a386Sopenharmony_ci}
400cb93a386Sopenharmony_ci
401cb93a386Sopenharmony_ci// Exercise the RR's contains rect method
402cb93a386Sopenharmony_cistatic void test_round_rect_contains_rect(skiatest::Reporter* reporter) {
403cb93a386Sopenharmony_ci
404cb93a386Sopenharmony_ci    static const int kNumRRects = 4;
405cb93a386Sopenharmony_ci    static const SkVector gRadii[kNumRRects][4] = {
406cb93a386Sopenharmony_ci        { {  0,  0 }, {  0,  0 }, {  0,  0 }, {  0,  0 } },  // rect
407cb93a386Sopenharmony_ci        { { 20, 20 }, { 20, 20 }, { 20, 20 }, { 20, 20 } },  // circle
408cb93a386Sopenharmony_ci        { { 10, 10 }, { 10, 10 }, { 10, 10 }, { 10, 10 } },  // simple
409cb93a386Sopenharmony_ci        { {  0,  0 }, { 20, 20 }, { 10, 10 }, { 30, 30 } }   // complex
410cb93a386Sopenharmony_ci    };
411cb93a386Sopenharmony_ci
412cb93a386Sopenharmony_ci    SkRRect rrects[kNumRRects];
413cb93a386Sopenharmony_ci    for (int i = 0; i < kNumRRects; ++i) {
414cb93a386Sopenharmony_ci        rrects[i].setRectRadii(SkRect::MakeWH(40, 40), gRadii[i]);
415cb93a386Sopenharmony_ci    }
416cb93a386Sopenharmony_ci
417cb93a386Sopenharmony_ci    // First test easy outs - boxes that are obviously out on
418cb93a386Sopenharmony_ci    // each corner and edge
419cb93a386Sopenharmony_ci    static const SkRect easyOuts[] = {
420cb93a386Sopenharmony_ci        { -5, -5,  5,  5 }, // NW
421cb93a386Sopenharmony_ci        { 15, -5, 20,  5 }, // N
422cb93a386Sopenharmony_ci        { 35, -5, 45,  5 }, // NE
423cb93a386Sopenharmony_ci        { 35, 15, 45, 20 }, // E
424cb93a386Sopenharmony_ci        { 35, 45, 35, 45 }, // SE
425cb93a386Sopenharmony_ci        { 15, 35, 20, 45 }, // S
426cb93a386Sopenharmony_ci        { -5, 35,  5, 45 }, // SW
427cb93a386Sopenharmony_ci        { -5, 15,  5, 20 }  // W
428cb93a386Sopenharmony_ci    };
429cb93a386Sopenharmony_ci
430cb93a386Sopenharmony_ci    for (int i = 0; i < kNumRRects; ++i) {
431cb93a386Sopenharmony_ci        for (size_t j = 0; j < SK_ARRAY_COUNT(easyOuts); ++j) {
432cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, !rrects[i].contains(easyOuts[j]));
433cb93a386Sopenharmony_ci        }
434cb93a386Sopenharmony_ci    }
435cb93a386Sopenharmony_ci
436cb93a386Sopenharmony_ci    // Now test non-trivial containment. For each compass
437cb93a386Sopenharmony_ci    // point walk a 1x1 rect in from the edge  of the bounding
438cb93a386Sopenharmony_ci    // rect
439cb93a386Sopenharmony_ci    static const int kNumSteps = 15;
440cb93a386Sopenharmony_ci    bool answers[kNumRRects][8][kNumSteps] = {
441cb93a386Sopenharmony_ci        // all the test rects are inside the degenerate rrect
442cb93a386Sopenharmony_ci        {
443cb93a386Sopenharmony_ci            // rect
444cb93a386Sopenharmony_ci            { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
445cb93a386Sopenharmony_ci            { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
446cb93a386Sopenharmony_ci            { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
447cb93a386Sopenharmony_ci            { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
448cb93a386Sopenharmony_ci            { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
449cb93a386Sopenharmony_ci            { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
450cb93a386Sopenharmony_ci            { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
451cb93a386Sopenharmony_ci            { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
452cb93a386Sopenharmony_ci        },
453cb93a386Sopenharmony_ci        // for the circle we expect 6 blocks to be out on the
454cb93a386Sopenharmony_ci        // corners (then the rest in) and only the first block
455cb93a386Sopenharmony_ci        // out on the vertical and horizontal axes (then
456cb93a386Sopenharmony_ci        // the rest in)
457cb93a386Sopenharmony_ci        {
458cb93a386Sopenharmony_ci            // circle
459cb93a386Sopenharmony_ci            { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
460cb93a386Sopenharmony_ci            { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
461cb93a386Sopenharmony_ci            { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
462cb93a386Sopenharmony_ci            { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
463cb93a386Sopenharmony_ci            { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
464cb93a386Sopenharmony_ci            { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
465cb93a386Sopenharmony_ci            { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
466cb93a386Sopenharmony_ci            { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
467cb93a386Sopenharmony_ci        },
468cb93a386Sopenharmony_ci        // for the simple round rect we expect 3 out on
469cb93a386Sopenharmony_ci        // the corners (then the rest in) and no blocks out
470cb93a386Sopenharmony_ci        // on the vertical and horizontal axes
471cb93a386Sopenharmony_ci        {
472cb93a386Sopenharmony_ci            // simple RR
473cb93a386Sopenharmony_ci            { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
474cb93a386Sopenharmony_ci            { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
475cb93a386Sopenharmony_ci            { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
476cb93a386Sopenharmony_ci            { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
477cb93a386Sopenharmony_ci            { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
478cb93a386Sopenharmony_ci            { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
479cb93a386Sopenharmony_ci            { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
480cb93a386Sopenharmony_ci            { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
481cb93a386Sopenharmony_ci        },
482cb93a386Sopenharmony_ci        // for the complex case the answer is different for each direction
483cb93a386Sopenharmony_ci        {
484cb93a386Sopenharmony_ci            // complex RR
485cb93a386Sopenharmony_ci            // all in for NW (rect) corner (same as rect case)
486cb93a386Sopenharmony_ci            { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
487cb93a386Sopenharmony_ci            // only first block out for N (same as circle case)
488cb93a386Sopenharmony_ci            { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
489cb93a386Sopenharmony_ci            // first 6 blocks out for NE (same as circle case)
490cb93a386Sopenharmony_ci            { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
491cb93a386Sopenharmony_ci            // only first block out for E (same as circle case)
492cb93a386Sopenharmony_ci            { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
493cb93a386Sopenharmony_ci            // first 3 blocks out for SE (same as simple case)
494cb93a386Sopenharmony_ci            { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
495cb93a386Sopenharmony_ci            // first two blocks out for S
496cb93a386Sopenharmony_ci            { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
497cb93a386Sopenharmony_ci            // first 9 blocks out for SW
498cb93a386Sopenharmony_ci            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1 },
499cb93a386Sopenharmony_ci            // first two blocks out for W (same as S)
500cb93a386Sopenharmony_ci            { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
501cb93a386Sopenharmony_ci         }
502cb93a386Sopenharmony_ci    };
503cb93a386Sopenharmony_ci
504cb93a386Sopenharmony_ci    for (int i = 0; i < kNumRRects; ++i) {
505cb93a386Sopenharmony_ci        test_direction(reporter, rrects[i],     0,  1,     0,  1, kNumSteps, answers[i][0]); // NW
506cb93a386Sopenharmony_ci        test_direction(reporter, rrects[i], 19.5f,  0,     0,  1, kNumSteps, answers[i][1]); // N
507cb93a386Sopenharmony_ci        test_direction(reporter, rrects[i],    40, -1,     0,  1, kNumSteps, answers[i][2]); // NE
508cb93a386Sopenharmony_ci        test_direction(reporter, rrects[i],    40, -1, 19.5f,  0, kNumSteps, answers[i][3]); // E
509cb93a386Sopenharmony_ci        test_direction(reporter, rrects[i],    40, -1,    40, -1, kNumSteps, answers[i][4]); // SE
510cb93a386Sopenharmony_ci        test_direction(reporter, rrects[i], 19.5f,  0,    40, -1, kNumSteps, answers[i][5]); // S
511cb93a386Sopenharmony_ci        test_direction(reporter, rrects[i],     0,  1,    40, -1, kNumSteps, answers[i][6]); // SW
512cb93a386Sopenharmony_ci        test_direction(reporter, rrects[i],     0,  1, 19.5f,  0, kNumSteps, answers[i][7]); // W
513cb93a386Sopenharmony_ci    }
514cb93a386Sopenharmony_ci}
515cb93a386Sopenharmony_ci
516cb93a386Sopenharmony_ci// Called for a matrix that should cause SkRRect::transform to fail.
517cb93a386Sopenharmony_cistatic void assert_transform_failure(skiatest::Reporter* reporter, const SkRRect& orig,
518cb93a386Sopenharmony_ci                                     const SkMatrix& matrix) {
519cb93a386Sopenharmony_ci    // The test depends on the fact that the original is not empty.
520cb93a386Sopenharmony_ci    SkASSERT(!orig.isEmpty());
521cb93a386Sopenharmony_ci    SkRRect dst;
522cb93a386Sopenharmony_ci    dst.setEmpty();
523cb93a386Sopenharmony_ci
524cb93a386Sopenharmony_ci    const SkRRect copyOfDst = dst;
525cb93a386Sopenharmony_ci    const SkRRect copyOfOrig = orig;
526cb93a386Sopenharmony_ci    bool success = orig.transform(matrix, &dst);
527cb93a386Sopenharmony_ci    // This transform should fail.
528cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, !success);
529cb93a386Sopenharmony_ci    // Since the transform failed, dst should be unchanged.
530cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, copyOfDst == dst);
531cb93a386Sopenharmony_ci    // original should not be modified.
532cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, copyOfOrig == orig);
533cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, orig != dst);
534cb93a386Sopenharmony_ci}
535cb93a386Sopenharmony_ci
536cb93a386Sopenharmony_ci#define GET_RADII                                                       \
537cb93a386Sopenharmony_ci    const SkVector& origUL = orig.radii(SkRRect::kUpperLeft_Corner);    \
538cb93a386Sopenharmony_ci    const SkVector& origUR = orig.radii(SkRRect::kUpperRight_Corner);   \
539cb93a386Sopenharmony_ci    const SkVector& origLR = orig.radii(SkRRect::kLowerRight_Corner);   \
540cb93a386Sopenharmony_ci    const SkVector& origLL = orig.radii(SkRRect::kLowerLeft_Corner);    \
541cb93a386Sopenharmony_ci    const SkVector& dstUL = dst.radii(SkRRect::kUpperLeft_Corner);      \
542cb93a386Sopenharmony_ci    const SkVector& dstUR = dst.radii(SkRRect::kUpperRight_Corner);     \
543cb93a386Sopenharmony_ci    const SkVector& dstLR = dst.radii(SkRRect::kLowerRight_Corner);     \
544cb93a386Sopenharmony_ci    const SkVector& dstLL = dst.radii(SkRRect::kLowerLeft_Corner)
545cb93a386Sopenharmony_ci
546cb93a386Sopenharmony_ci// Called to test various transforms on a single SkRRect.
547cb93a386Sopenharmony_cistatic void test_transform_helper(skiatest::Reporter* reporter, const SkRRect& orig) {
548cb93a386Sopenharmony_ci    SkRRect dst;
549cb93a386Sopenharmony_ci    dst.setEmpty();
550cb93a386Sopenharmony_ci
551cb93a386Sopenharmony_ci    // The identity matrix will duplicate the rrect.
552cb93a386Sopenharmony_ci    bool success = orig.transform(SkMatrix::I(), &dst);
553cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, success);
554cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, orig == dst);
555cb93a386Sopenharmony_ci
556cb93a386Sopenharmony_ci    // Skew and Perspective make transform fail.
557cb93a386Sopenharmony_ci    SkMatrix matrix;
558cb93a386Sopenharmony_ci    matrix.reset();
559cb93a386Sopenharmony_ci    matrix.setSkewX(SkIntToScalar(2));
560cb93a386Sopenharmony_ci    assert_transform_failure(reporter, orig, matrix);
561cb93a386Sopenharmony_ci
562cb93a386Sopenharmony_ci    matrix.reset();
563cb93a386Sopenharmony_ci    matrix.setSkewY(SkIntToScalar(3));
564cb93a386Sopenharmony_ci    assert_transform_failure(reporter, orig, matrix);
565cb93a386Sopenharmony_ci
566cb93a386Sopenharmony_ci    matrix.reset();
567cb93a386Sopenharmony_ci    matrix.setPerspX(4);
568cb93a386Sopenharmony_ci    assert_transform_failure(reporter, orig, matrix);
569cb93a386Sopenharmony_ci
570cb93a386Sopenharmony_ci    matrix.reset();
571cb93a386Sopenharmony_ci    matrix.setPerspY(5);
572cb93a386Sopenharmony_ci    assert_transform_failure(reporter, orig, matrix);
573cb93a386Sopenharmony_ci
574cb93a386Sopenharmony_ci    // Rotation fails.
575cb93a386Sopenharmony_ci    matrix.reset();
576cb93a386Sopenharmony_ci    matrix.setRotate(SkIntToScalar(37));
577cb93a386Sopenharmony_ci    assert_transform_failure(reporter, orig, matrix);
578cb93a386Sopenharmony_ci
579cb93a386Sopenharmony_ci    // Translate will keep the rect moved, but otherwise the same.
580cb93a386Sopenharmony_ci    matrix.reset();
581cb93a386Sopenharmony_ci    SkScalar translateX = SkIntToScalar(32);
582cb93a386Sopenharmony_ci    SkScalar translateY = SkIntToScalar(15);
583cb93a386Sopenharmony_ci    matrix.setTranslateX(translateX);
584cb93a386Sopenharmony_ci    matrix.setTranslateY(translateY);
585cb93a386Sopenharmony_ci    dst.setEmpty();
586cb93a386Sopenharmony_ci    success = orig.transform(matrix, &dst);
587cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, success);
588cb93a386Sopenharmony_ci    for (int i = 0; i < 4; ++i) {
589cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter,
590cb93a386Sopenharmony_ci                orig.radii((SkRRect::Corner) i) == dst.radii((SkRRect::Corner) i));
591cb93a386Sopenharmony_ci    }
592cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
593cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
594cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, dst.rect().left() == orig.rect().left() + translateX);
595cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, dst.rect().top() == orig.rect().top() + translateY);
596cb93a386Sopenharmony_ci
597cb93a386Sopenharmony_ci    // Keeping the translation, but adding skew will make transform fail.
598cb93a386Sopenharmony_ci    matrix.setSkewY(SkIntToScalar(7));
599cb93a386Sopenharmony_ci    assert_transform_failure(reporter, orig, matrix);
600cb93a386Sopenharmony_ci
601cb93a386Sopenharmony_ci    // Scaling in -x will flip the round rect horizontally.
602cb93a386Sopenharmony_ci    matrix.reset();
603cb93a386Sopenharmony_ci    matrix.setScaleX(SkIntToScalar(-1));
604cb93a386Sopenharmony_ci    dst.setEmpty();
605cb93a386Sopenharmony_ci    success = orig.transform(matrix, &dst);
606cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, success);
607cb93a386Sopenharmony_ci    {
608cb93a386Sopenharmony_ci        GET_RADII;
609cb93a386Sopenharmony_ci        // Radii have swapped in x.
610cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, origUL == dstUR);
611cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, origUR == dstUL);
612cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, origLR == dstLL);
613cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, origLL == dstLR);
614cb93a386Sopenharmony_ci    }
615cb93a386Sopenharmony_ci    // Width and height remain the same.
616cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
617cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
618cb93a386Sopenharmony_ci    // Right and left have swapped (sort of)
619cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, orig.rect().right() == -dst.rect().left());
620cb93a386Sopenharmony_ci    // Top has stayed the same.
621cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, orig.rect().top() == dst.rect().top());
622cb93a386Sopenharmony_ci
623cb93a386Sopenharmony_ci    // Keeping the scale, but adding a persp will make transform fail.
624cb93a386Sopenharmony_ci    matrix.setPerspX(7);
625cb93a386Sopenharmony_ci    assert_transform_failure(reporter, orig, matrix);
626cb93a386Sopenharmony_ci
627cb93a386Sopenharmony_ci    // Scaling in -y will flip the round rect vertically.
628cb93a386Sopenharmony_ci    matrix.reset();
629cb93a386Sopenharmony_ci    matrix.setScaleY(SkIntToScalar(-1));
630cb93a386Sopenharmony_ci    dst.setEmpty();
631cb93a386Sopenharmony_ci    success = orig.transform(matrix, &dst);
632cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, success);
633cb93a386Sopenharmony_ci    {
634cb93a386Sopenharmony_ci        GET_RADII;
635cb93a386Sopenharmony_ci        // Radii have swapped in y.
636cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, origUL == dstLL);
637cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, origUR == dstLR);
638cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, origLR == dstUR);
639cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, origLL == dstUL);
640cb93a386Sopenharmony_ci    }
641cb93a386Sopenharmony_ci    // Width and height remain the same.
642cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
643cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
644cb93a386Sopenharmony_ci    // Top and bottom have swapped (sort of)
645cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, orig.rect().top() == -dst.rect().bottom());
646cb93a386Sopenharmony_ci    // Left has stayed the same.
647cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, orig.rect().left() == dst.rect().left());
648cb93a386Sopenharmony_ci
649cb93a386Sopenharmony_ci    // Scaling in -x and -y will swap in both directions.
650cb93a386Sopenharmony_ci    matrix.reset();
651cb93a386Sopenharmony_ci    matrix.setScaleY(SkIntToScalar(-1));
652cb93a386Sopenharmony_ci    matrix.setScaleX(SkIntToScalar(-1));
653cb93a386Sopenharmony_ci    dst.setEmpty();
654cb93a386Sopenharmony_ci    success = orig.transform(matrix, &dst);
655cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, success);
656cb93a386Sopenharmony_ci    {
657cb93a386Sopenharmony_ci        GET_RADII;
658cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, origUL == dstLR);
659cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, origUR == dstLL);
660cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, origLR == dstUL);
661cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, origLL == dstUR);
662cb93a386Sopenharmony_ci    }
663cb93a386Sopenharmony_ci    // Width and height remain the same.
664cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
665cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
666cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, orig.rect().top() == -dst.rect().bottom());
667cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, orig.rect().right() == -dst.rect().left());
668cb93a386Sopenharmony_ci
669cb93a386Sopenharmony_ci    // Scale in both directions.
670cb93a386Sopenharmony_ci    SkScalar xScale = SkIntToScalar(3);
671cb93a386Sopenharmony_ci    SkScalar yScale = 3.2f;
672cb93a386Sopenharmony_ci    matrix.reset();
673cb93a386Sopenharmony_ci    matrix.setScaleX(xScale);
674cb93a386Sopenharmony_ci    matrix.setScaleY(yScale);
675cb93a386Sopenharmony_ci    dst.setEmpty();
676cb93a386Sopenharmony_ci    success = orig.transform(matrix, &dst);
677cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, success);
678cb93a386Sopenharmony_ci    // Radii are scaled.
679cb93a386Sopenharmony_ci    for (int i = 0; i < 4; ++i) {
680cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.radii((SkRRect::Corner) i).fX,
681cb93a386Sopenharmony_ci                                    orig.radii((SkRRect::Corner) i).fX * xScale));
682cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.radii((SkRRect::Corner) i).fY,
683cb93a386Sopenharmony_ci                                    orig.radii((SkRRect::Corner) i).fY * yScale));
684cb93a386Sopenharmony_ci    }
685cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().width(),
686cb93a386Sopenharmony_ci                                                  orig.rect().width() * xScale));
687cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().height(),
688cb93a386Sopenharmony_ci                                                  orig.rect().height() * yScale));
689cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().left(),
690cb93a386Sopenharmony_ci                                                  orig.rect().left() * xScale));
691cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().top(),
692cb93a386Sopenharmony_ci                                                  orig.rect().top() * yScale));
693cb93a386Sopenharmony_ci
694cb93a386Sopenharmony_ci
695cb93a386Sopenharmony_ci    //  a-----b            d-----a
696cb93a386Sopenharmony_ci    //  |     |     ->     |     |
697cb93a386Sopenharmony_ci    //  |     |  Rotate 90 |     |
698cb93a386Sopenharmony_ci    //  d-----c            c-----b
699cb93a386Sopenharmony_ci    matrix.reset();
700cb93a386Sopenharmony_ci    matrix.setRotate(SkIntToScalar(90));
701cb93a386Sopenharmony_ci    dst.setEmpty();
702cb93a386Sopenharmony_ci    success = orig.transform(matrix, &dst);
703cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, success);
704cb93a386Sopenharmony_ci    {
705cb93a386Sopenharmony_ci        GET_RADII;
706cb93a386Sopenharmony_ci        // Radii have cycled clockwise and swapped their x and y axis.
707cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstUL.x() == origLL.y());
708cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstUL.y() == origLL.x());
709cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstUR.x() == origUL.y());
710cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstUR.y() == origUL.x());
711cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstLR.x() == origUR.y());
712cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstLR.y() == origUR.x());
713cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstLL.x() == origLR.y());
714cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstLL.y() == origLR.x());
715cb93a386Sopenharmony_ci    }
716cb93a386Sopenharmony_ci    // Width and height would get swapped.
717cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
718cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
719cb93a386Sopenharmony_ci
720cb93a386Sopenharmony_ci    //  a-----b        b-----a           c-----b
721cb93a386Sopenharmony_ci    //  |     |   ->   |     |    ->     |     |
722cb93a386Sopenharmony_ci    //  |     | Flip X |     | Rotate 90 |     |
723cb93a386Sopenharmony_ci    //  d-----c        c-----d           d-----a
724cb93a386Sopenharmony_ci    matrix.reset();
725cb93a386Sopenharmony_ci    matrix.setRotate(SkIntToScalar(90));
726cb93a386Sopenharmony_ci    matrix.postScale(SkIntToScalar(-1), SkIntToScalar(1));
727cb93a386Sopenharmony_ci    dst.setEmpty();
728cb93a386Sopenharmony_ci    success = orig.transform(matrix, &dst);
729cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, success);
730cb93a386Sopenharmony_ci    {
731cb93a386Sopenharmony_ci        GET_RADII;
732cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstUL.x() == origLR.y());
733cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstUL.y() == origLR.x());
734cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstUR.x() == origUR.y());
735cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstUR.y() == origUR.x());
736cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstLR.x() == origUL.y());
737cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstLR.y() == origUL.x());
738cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstLL.x() == origLL.y());
739cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstLL.y() == origLL.x());
740cb93a386Sopenharmony_ci    }
741cb93a386Sopenharmony_ci    // Width and height would get swapped.
742cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
743cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
744cb93a386Sopenharmony_ci
745cb93a386Sopenharmony_ci    //  a-----b           d-----a        c-----b
746cb93a386Sopenharmony_ci    //  |     |    ->     |     |   ->   |     |
747cb93a386Sopenharmony_ci    //  |     | Rotate 90 |     | Flip Y |     |
748cb93a386Sopenharmony_ci    //  d-----c           c-----b        d-----a
749cb93a386Sopenharmony_ci    //
750cb93a386Sopenharmony_ci    // This is the same as Flip X and Rotate 90.
751cb93a386Sopenharmony_ci    matrix.reset();
752cb93a386Sopenharmony_ci    matrix.setScale(SkIntToScalar(1), SkIntToScalar(-1));
753cb93a386Sopenharmony_ci    matrix.postRotate(SkIntToScalar(90));
754cb93a386Sopenharmony_ci    SkRRect dst2;
755cb93a386Sopenharmony_ci    dst2.setEmpty();
756cb93a386Sopenharmony_ci    success = orig.transform(matrix, &dst2);
757cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, success);
758cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, dst == dst2);
759cb93a386Sopenharmony_ci
760cb93a386Sopenharmony_ci    //  a-----b            b-----c        c-----b
761cb93a386Sopenharmony_ci    //  |     |     ->     |     |   ->   |     |
762cb93a386Sopenharmony_ci    //  |     | Rotate 270 |     | Flip X |     |
763cb93a386Sopenharmony_ci    //  d-----c            a-----d        d-----a
764cb93a386Sopenharmony_ci    matrix.reset();
765cb93a386Sopenharmony_ci    matrix.setScale(SkIntToScalar(-1), SkIntToScalar(1));
766cb93a386Sopenharmony_ci    matrix.postRotate(SkIntToScalar(270));
767cb93a386Sopenharmony_ci    dst2.setEmpty();
768cb93a386Sopenharmony_ci    success = orig.transform(matrix, &dst2);
769cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, success);
770cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, dst == dst2);
771cb93a386Sopenharmony_ci
772cb93a386Sopenharmony_ci    //  a-----b        d-----c            c-----b
773cb93a386Sopenharmony_ci    //  |     |   ->   |     |     ->     |     |
774cb93a386Sopenharmony_ci    //  |     | Flip Y |     | Rotate 270 |     |
775cb93a386Sopenharmony_ci    //  d-----c        a-----b            d-----a
776cb93a386Sopenharmony_ci    matrix.reset();
777cb93a386Sopenharmony_ci    matrix.setRotate(SkIntToScalar(270));
778cb93a386Sopenharmony_ci    matrix.postScale(SkIntToScalar(1), SkIntToScalar(-1));
779cb93a386Sopenharmony_ci    dst2.setEmpty();
780cb93a386Sopenharmony_ci    success = orig.transform(matrix, &dst2);
781cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, success);
782cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, dst == dst2);
783cb93a386Sopenharmony_ci
784cb93a386Sopenharmony_ci    //  a-----b           d-----a        a-----d
785cb93a386Sopenharmony_ci    //  |     |    ->     |     |   ->   |     |
786cb93a386Sopenharmony_ci    //  |     | Rotate 90 |     | Flip X |     |
787cb93a386Sopenharmony_ci    //  d-----c           c-----b        b-----c
788cb93a386Sopenharmony_ci    matrix.reset();
789cb93a386Sopenharmony_ci    matrix.setScale(SkIntToScalar(-1), SkIntToScalar(1));
790cb93a386Sopenharmony_ci    matrix.postRotate(SkIntToScalar(90));
791cb93a386Sopenharmony_ci    dst.setEmpty();
792cb93a386Sopenharmony_ci    success = orig.transform(matrix, &dst);
793cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, success);
794cb93a386Sopenharmony_ci    {
795cb93a386Sopenharmony_ci        GET_RADII;
796cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstUL.x() == origUL.y());
797cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstUL.y() == origUL.x());
798cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstUR.x() == origLL.y());
799cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstUR.y() == origLL.x());
800cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstLR.x() == origLR.y());
801cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstLR.y() == origLR.x());
802cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstLL.x() == origUR.y());
803cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstLL.y() == origUR.x());
804cb93a386Sopenharmony_ci    }
805cb93a386Sopenharmony_ci    // Width and height would get swapped.
806cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
807cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
808cb93a386Sopenharmony_ci
809cb93a386Sopenharmony_ci    //  a-----b        d-----c           a-----d
810cb93a386Sopenharmony_ci    //  |     |   ->   |     |    ->     |     |
811cb93a386Sopenharmony_ci    //  |     | Flip Y |     | Rotate 90 |     |
812cb93a386Sopenharmony_ci    //  d-----c        a-----b           b-----c
813cb93a386Sopenharmony_ci    // This is the same as rotate 90 and flip x.
814cb93a386Sopenharmony_ci    matrix.reset();
815cb93a386Sopenharmony_ci    matrix.setRotate(SkIntToScalar(90));
816cb93a386Sopenharmony_ci    matrix.postScale(SkIntToScalar(1), SkIntToScalar(-1));
817cb93a386Sopenharmony_ci    dst2.setEmpty();
818cb93a386Sopenharmony_ci    success = orig.transform(matrix, &dst2);
819cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, success);
820cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, dst == dst2);
821cb93a386Sopenharmony_ci
822cb93a386Sopenharmony_ci    //  a-----b        b-----a            a-----d
823cb93a386Sopenharmony_ci    //  |     |   ->   |     |     ->     |     |
824cb93a386Sopenharmony_ci    //  |     | Flip X |     | Rotate 270 |     |
825cb93a386Sopenharmony_ci    //  d-----c        c-----d            b-----c
826cb93a386Sopenharmony_ci    matrix.reset();
827cb93a386Sopenharmony_ci    matrix.setRotate(SkIntToScalar(270));
828cb93a386Sopenharmony_ci    matrix.postScale(SkIntToScalar(-1), SkIntToScalar(1));
829cb93a386Sopenharmony_ci    dst2.setEmpty();
830cb93a386Sopenharmony_ci    success = orig.transform(matrix, &dst2);
831cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, success);
832cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, dst == dst2);
833cb93a386Sopenharmony_ci
834cb93a386Sopenharmony_ci    //  a-----b            b-----c        a-----d
835cb93a386Sopenharmony_ci    //  |     |     ->     |     |   ->   |     |
836cb93a386Sopenharmony_ci    //  |     | Rotate 270 |     | Flip Y |     |
837cb93a386Sopenharmony_ci    //  d-----c            a-----d        b-----c
838cb93a386Sopenharmony_ci    matrix.reset();
839cb93a386Sopenharmony_ci    matrix.setScale(SkIntToScalar(1), SkIntToScalar(-1));
840cb93a386Sopenharmony_ci    matrix.postRotate(SkIntToScalar(270));
841cb93a386Sopenharmony_ci    dst2.setEmpty();
842cb93a386Sopenharmony_ci    success = orig.transform(matrix, &dst2);
843cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, success);
844cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, dst == dst2);
845cb93a386Sopenharmony_ci
846cb93a386Sopenharmony_ci
847cb93a386Sopenharmony_ci    //  a-----b        b-----a        c-----d            b-----c
848cb93a386Sopenharmony_ci    //  |     |   ->   |     |   ->   |     |    ->      |     |
849cb93a386Sopenharmony_ci    //  |     | Flip X |     | Flip Y |     | Rotate 90  |     |
850cb93a386Sopenharmony_ci    //  d-----c        c-----d        b-----a            a-----d
851cb93a386Sopenharmony_ci    //
852cb93a386Sopenharmony_ci    // This is the same as rotation by 270.
853cb93a386Sopenharmony_ci    matrix.reset();
854cb93a386Sopenharmony_ci    matrix.setRotate(SkIntToScalar(90));
855cb93a386Sopenharmony_ci    matrix.postScale(SkIntToScalar(-1), SkIntToScalar(-1));
856cb93a386Sopenharmony_ci    dst.setEmpty();
857cb93a386Sopenharmony_ci    success = orig.transform(matrix, &dst);
858cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, success);
859cb93a386Sopenharmony_ci    {
860cb93a386Sopenharmony_ci        GET_RADII;
861cb93a386Sopenharmony_ci        // Radii have cycled clockwise and swapped their x and y axis.
862cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstUL.x() == origUR.y());
863cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstUL.y() == origUR.x());
864cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstUR.x() == origLR.y());
865cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstUR.y() == origLR.x());
866cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstLR.x() == origLL.y());
867cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstLR.y() == origLL.x());
868cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstLL.x() == origUL.y());
869cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, dstLL.y() == origUL.x());
870cb93a386Sopenharmony_ci    }
871cb93a386Sopenharmony_ci    // Width and height would get swapped.
872cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
873cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
874cb93a386Sopenharmony_ci
875cb93a386Sopenharmony_ci    //  a-----b             b-----c
876cb93a386Sopenharmony_ci    //  |     |     ->      |     |
877cb93a386Sopenharmony_ci    //  |     | Rotate 270  |     |
878cb93a386Sopenharmony_ci    //  d-----c             a-----d
879cb93a386Sopenharmony_ci    //
880cb93a386Sopenharmony_ci    dst2.setEmpty();
881cb93a386Sopenharmony_ci    matrix.reset();
882cb93a386Sopenharmony_ci    matrix.setRotate(SkIntToScalar(270));
883cb93a386Sopenharmony_ci    success = orig.transform(matrix, &dst2);
884cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, success);
885cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, dst == dst2);
886cb93a386Sopenharmony_ci
887cb93a386Sopenharmony_ci    //  a-----b        b-----a        c-----d             d-----a
888cb93a386Sopenharmony_ci    //  |     |   ->   |     |   ->   |     |     ->      |     |
889cb93a386Sopenharmony_ci    //  |     | Flip X |     | Flip Y |     | Rotate 270  |     |
890cb93a386Sopenharmony_ci    //  d-----c        c-----d        b-----a             c-----b
891cb93a386Sopenharmony_ci    //
892cb93a386Sopenharmony_ci    // This is the same as rotation by 90 degrees.
893cb93a386Sopenharmony_ci    matrix.reset();
894cb93a386Sopenharmony_ci    matrix.setRotate(SkIntToScalar(270));
895cb93a386Sopenharmony_ci    matrix.postScale(SkIntToScalar(-1), SkIntToScalar(-1));
896cb93a386Sopenharmony_ci    dst.setEmpty();
897cb93a386Sopenharmony_ci    success = orig.transform(matrix, &dst);
898cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, success);
899cb93a386Sopenharmony_ci
900cb93a386Sopenharmony_ci    matrix.reset();
901cb93a386Sopenharmony_ci    matrix.setRotate(SkIntToScalar(90));
902cb93a386Sopenharmony_ci    dst2.setEmpty();
903cb93a386Sopenharmony_ci    success = orig.transform(matrix, &dst2);
904cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, dst == dst2);
905cb93a386Sopenharmony_ci
906cb93a386Sopenharmony_ci}
907cb93a386Sopenharmony_ci
908cb93a386Sopenharmony_cistatic void test_round_rect_transform(skiatest::Reporter* reporter) {
909cb93a386Sopenharmony_ci    SkRRect rrect;
910cb93a386Sopenharmony_ci    {
911cb93a386Sopenharmony_ci        SkRect r = { 0, 0, kWidth, kHeight };
912cb93a386Sopenharmony_ci        rrect.setRectXY(r, SkIntToScalar(4), SkIntToScalar(7));
913cb93a386Sopenharmony_ci        test_transform_helper(reporter, rrect);
914cb93a386Sopenharmony_ci    }
915cb93a386Sopenharmony_ci    {
916cb93a386Sopenharmony_ci        SkRect r = { SkIntToScalar(5), SkIntToScalar(15),
917cb93a386Sopenharmony_ci                     SkIntToScalar(27), SkIntToScalar(34) };
918cb93a386Sopenharmony_ci        SkVector radii[4] = { { 0, SkIntToScalar(1) },
919cb93a386Sopenharmony_ci                              { SkIntToScalar(2), SkIntToScalar(3) },
920cb93a386Sopenharmony_ci                              { SkIntToScalar(4), SkIntToScalar(5) },
921cb93a386Sopenharmony_ci                              { SkIntToScalar(6), SkIntToScalar(7) } };
922cb93a386Sopenharmony_ci        rrect.setRectRadii(r, radii);
923cb93a386Sopenharmony_ci        test_transform_helper(reporter, rrect);
924cb93a386Sopenharmony_ci    }
925cb93a386Sopenharmony_ci}
926cb93a386Sopenharmony_ci
927cb93a386Sopenharmony_ci// Test out the case where an oval already off in space is translated/scaled
928cb93a386Sopenharmony_ci// further off into space - yielding numerical issues when the rect & radii
929cb93a386Sopenharmony_ci// are transformed separatly
930cb93a386Sopenharmony_ci// BUG=skia:2696
931cb93a386Sopenharmony_cistatic void test_issue_2696(skiatest::Reporter* reporter) {
932cb93a386Sopenharmony_ci    SkRRect rrect;
933cb93a386Sopenharmony_ci    SkRect r = { 28443.8594f, 53.1428604f, 28446.7148f, 56.0000038f };
934cb93a386Sopenharmony_ci    rrect.setOval(r);
935cb93a386Sopenharmony_ci
936cb93a386Sopenharmony_ci    SkMatrix xform;
937cb93a386Sopenharmony_ci    xform.setAll(2.44f,  0.0f, 485411.7f,
938cb93a386Sopenharmony_ci                 0.0f,  2.44f,   -438.7f,
939cb93a386Sopenharmony_ci                 0.0f,   0.0f,      1.0f);
940cb93a386Sopenharmony_ci    SkRRect dst;
941cb93a386Sopenharmony_ci
942cb93a386Sopenharmony_ci    bool success = rrect.transform(xform, &dst);
943cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, success);
944cb93a386Sopenharmony_ci
945cb93a386Sopenharmony_ci    SkScalar halfWidth = SkScalarHalf(dst.width());
946cb93a386Sopenharmony_ci    SkScalar halfHeight = SkScalarHalf(dst.height());
947cb93a386Sopenharmony_ci
948cb93a386Sopenharmony_ci    for (int i = 0; i < 4; ++i) {
949cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter,
950cb93a386Sopenharmony_ci                        SkScalarNearlyEqual(dst.radii((SkRRect::Corner)i).fX, halfWidth));
951cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter,
952cb93a386Sopenharmony_ci                        SkScalarNearlyEqual(dst.radii((SkRRect::Corner)i).fY, halfHeight));
953cb93a386Sopenharmony_ci    }
954cb93a386Sopenharmony_ci}
955cb93a386Sopenharmony_ci
956cb93a386Sopenharmony_civoid test_read_rrect(skiatest::Reporter* reporter, const SkRRect& rrect, bool shouldEqualSrc) {
957cb93a386Sopenharmony_ci    // It would be cleaner to call rrect.writeToMemory into a buffer. However, writeToMemory asserts
958cb93a386Sopenharmony_ci    // that the rrect is valid and our caller may have fiddled with the internals of rrect to make
959cb93a386Sopenharmony_ci    // it invalid.
960cb93a386Sopenharmony_ci    const void* buffer = reinterpret_cast<const void*>(&rrect);
961cb93a386Sopenharmony_ci    SkRRect deserialized;
962cb93a386Sopenharmony_ci    size_t size = deserialized.readFromMemory(buffer, sizeof(SkRRect));
963cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, size == SkRRect::kSizeInMemory);
964cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, deserialized.isValid());
965cb93a386Sopenharmony_ci    if (shouldEqualSrc) {
966cb93a386Sopenharmony_ci       REPORTER_ASSERT(reporter, rrect == deserialized);
967cb93a386Sopenharmony_ci    }
968cb93a386Sopenharmony_ci}
969cb93a386Sopenharmony_ci
970cb93a386Sopenharmony_cistatic void test_read(skiatest::Reporter* reporter) {
971cb93a386Sopenharmony_ci    static const SkRect kRect = {10.f, 10.f, 20.f, 20.f};
972cb93a386Sopenharmony_ci    static const SkRect kNaNRect = {10.f, 10.f, 20.f, SK_ScalarNaN};
973cb93a386Sopenharmony_ci    static const SkRect kInfRect = {10.f, 10.f, SK_ScalarInfinity, 20.f};
974cb93a386Sopenharmony_ci    SkRRect rrect;
975cb93a386Sopenharmony_ci
976cb93a386Sopenharmony_ci    test_read_rrect(reporter, SkRRect::MakeEmpty(), true);
977cb93a386Sopenharmony_ci    test_read_rrect(reporter, SkRRect::MakeRect(kRect), true);
978cb93a386Sopenharmony_ci    // These get coerced to empty.
979cb93a386Sopenharmony_ci    test_read_rrect(reporter, SkRRect::MakeRect(kInfRect), true);
980cb93a386Sopenharmony_ci    test_read_rrect(reporter, SkRRect::MakeRect(kNaNRect), true);
981cb93a386Sopenharmony_ci
982cb93a386Sopenharmony_ci    rrect.setRect(kRect);
983cb93a386Sopenharmony_ci    SkRect* innerRect = reinterpret_cast<SkRect*>(&rrect);
984cb93a386Sopenharmony_ci    SkASSERT(*innerRect == kRect);
985cb93a386Sopenharmony_ci    *innerRect = kInfRect;
986cb93a386Sopenharmony_ci    test_read_rrect(reporter, rrect, false);
987cb93a386Sopenharmony_ci    *innerRect = kNaNRect;
988cb93a386Sopenharmony_ci    test_read_rrect(reporter, rrect, false);
989cb93a386Sopenharmony_ci
990cb93a386Sopenharmony_ci    test_read_rrect(reporter, SkRRect::MakeOval(kRect), true);
991cb93a386Sopenharmony_ci    test_read_rrect(reporter, SkRRect::MakeOval(kInfRect), true);
992cb93a386Sopenharmony_ci    test_read_rrect(reporter, SkRRect::MakeOval(kNaNRect), true);
993cb93a386Sopenharmony_ci    rrect.setOval(kRect);
994cb93a386Sopenharmony_ci    *innerRect = kInfRect;
995cb93a386Sopenharmony_ci    test_read_rrect(reporter, rrect, false);
996cb93a386Sopenharmony_ci    *innerRect = kNaNRect;
997cb93a386Sopenharmony_ci    test_read_rrect(reporter, rrect, false);
998cb93a386Sopenharmony_ci
999cb93a386Sopenharmony_ci    test_read_rrect(reporter, SkRRect::MakeRectXY(kRect, 5.f, 5.f), true);
1000cb93a386Sopenharmony_ci    // rrect should scale down the radii to make this legal
1001cb93a386Sopenharmony_ci    test_read_rrect(reporter, SkRRect::MakeRectXY(kRect, 5.f, 400.f), true);
1002cb93a386Sopenharmony_ci
1003cb93a386Sopenharmony_ci    static const SkVector kRadii[4] = {{0.5f, 1.f}, {1.5f, 2.f}, {2.5f, 3.f}, {3.5f, 4.f}};
1004cb93a386Sopenharmony_ci    rrect.setRectRadii(kRect, kRadii);
1005cb93a386Sopenharmony_ci    test_read_rrect(reporter, rrect, true);
1006cb93a386Sopenharmony_ci    SkScalar* innerRadius = reinterpret_cast<SkScalar*>(&rrect) + 6;
1007cb93a386Sopenharmony_ci    SkASSERT(*innerRadius == 1.5f);
1008cb93a386Sopenharmony_ci    *innerRadius = 400.f;
1009cb93a386Sopenharmony_ci    test_read_rrect(reporter, rrect, false);
1010cb93a386Sopenharmony_ci    *innerRadius = SK_ScalarInfinity;
1011cb93a386Sopenharmony_ci    test_read_rrect(reporter, rrect, false);
1012cb93a386Sopenharmony_ci    *innerRadius = SK_ScalarNaN;
1013cb93a386Sopenharmony_ci    test_read_rrect(reporter, rrect, false);
1014cb93a386Sopenharmony_ci    *innerRadius = -10.f;
1015cb93a386Sopenharmony_ci    test_read_rrect(reporter, rrect, false);
1016cb93a386Sopenharmony_ci}
1017cb93a386Sopenharmony_ci
1018cb93a386Sopenharmony_cistatic void test_inner_bounds(skiatest::Reporter* reporter) {
1019cb93a386Sopenharmony_ci    // Because InnerBounds() insets the computed bounds slightly to correct for numerical inaccuracy
1020cb93a386Sopenharmony_ci    // when finding the maximum inscribed point on a curve, we use a larger epsilon for comparing
1021cb93a386Sopenharmony_ci    // expected areas.
1022cb93a386Sopenharmony_ci    static constexpr SkScalar kEpsilon = 0.005f;
1023cb93a386Sopenharmony_ci
1024cb93a386Sopenharmony_ci    // Test that an empty rrect reports empty inner bounds
1025cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkRRectPriv::InnerBounds(SkRRect::MakeEmpty()).isEmpty());
1026cb93a386Sopenharmony_ci    // Test that a rect rrect reports itself as the inner bounds
1027cb93a386Sopenharmony_ci    SkRect r = SkRect::MakeLTRB(0, 1, 2, 3);
1028cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkRRectPriv::InnerBounds(SkRRect::MakeRect(r)) == r);
1029cb93a386Sopenharmony_ci    // Test that a circle rrect has an inner bounds area equal to 2*radius^2
1030cb93a386Sopenharmony_ci    float radius = 5.f;
1031cb93a386Sopenharmony_ci    SkRect inner = SkRRectPriv::InnerBounds(SkRRect::MakeOval(SkRect::MakeWH(2.f * radius,
1032cb93a386Sopenharmony_ci                                                                             2.f * radius)));
1033cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(inner.width() * inner.height(),
1034cb93a386Sopenharmony_ci                                                  2.f * radius * radius, kEpsilon));
1035cb93a386Sopenharmony_ci
1036cb93a386Sopenharmony_ci    float width = 20.f;
1037cb93a386Sopenharmony_ci    float height = 25.f;
1038cb93a386Sopenharmony_ci    r = SkRect::MakeWH(width, height);
1039cb93a386Sopenharmony_ci    // Test that a rrect with circular corners has an area equal to:
1040cb93a386Sopenharmony_ci    float expectedArea =
1041cb93a386Sopenharmony_ci            (2.f * radius * radius) +                      // area in the 4 circular corners
1042cb93a386Sopenharmony_ci            (width-2.f*radius) * (height-2.f*radius) +     // inner area excluding corners and edges
1043cb93a386Sopenharmony_ci            SK_ScalarSqrt2 * radius * (width-2.f*radius) + // two horiz. rects between corners
1044cb93a386Sopenharmony_ci            SK_ScalarSqrt2 * radius * (height-2.f*radius); // two vert. rects between corners
1045cb93a386Sopenharmony_ci
1046cb93a386Sopenharmony_ci    inner = SkRRectPriv::InnerBounds(SkRRect::MakeRectXY(r, radius, radius));
1047cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkScalarNearlyEqual(inner.width() * inner.height(),
1048cb93a386Sopenharmony_ci                                                  expectedArea, kEpsilon));
1049cb93a386Sopenharmony_ci
1050cb93a386Sopenharmony_ci    // Test that a rrect with a small y radius but large x radius selects the horizontal interior
1051cb93a386Sopenharmony_ci    SkRRect rr = SkRRect::MakeRectXY(r, 2.f * radius, 0.1f * radius);
1052cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkRRectPriv::InnerBounds(rr) ==
1053cb93a386Sopenharmony_ci                              SkRect::MakeLTRB(0.f, 0.1f * radius, width, height - 0.1f * radius));
1054cb93a386Sopenharmony_ci    // And vice versa with large y and small x radii
1055cb93a386Sopenharmony_ci    rr = SkRRect::MakeRectXY(r, 0.1f * radius, 2.f * radius);
1056cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, SkRRectPriv::InnerBounds(rr) ==
1057cb93a386Sopenharmony_ci                              SkRect::MakeLTRB(0.1f * radius, 0.f, width - 0.1f * radius, height));
1058cb93a386Sopenharmony_ci
1059cb93a386Sopenharmony_ci    // Test a variety of complex round rects produce a non-empty rect that is at least contained,
1060cb93a386Sopenharmony_ci    // and larger than the inner area avoiding all corners.
1061cb93a386Sopenharmony_ci    SkRandom rng;
1062cb93a386Sopenharmony_ci    for (int i = 0; i < 1000; ++i) {
1063cb93a386Sopenharmony_ci        float maxRadiusX = rng.nextRangeF(0.f, 40.f);
1064cb93a386Sopenharmony_ci        float maxRadiusY = rng.nextRangeF(0.f, 40.f);
1065cb93a386Sopenharmony_ci
1066cb93a386Sopenharmony_ci        float innerWidth = rng.nextRangeF(0.f, 40.f);
1067cb93a386Sopenharmony_ci        float innerHeight = rng.nextRangeF(0.f, 40.f);
1068cb93a386Sopenharmony_ci
1069cb93a386Sopenharmony_ci        SkVector radii[4] = {{rng.nextRangeF(0.f, maxRadiusX), rng.nextRangeF(0.f, maxRadiusY)},
1070cb93a386Sopenharmony_ci                             {rng.nextRangeF(0.f, maxRadiusX), rng.nextRangeF(0.f, maxRadiusY)},
1071cb93a386Sopenharmony_ci                             {rng.nextRangeF(0.f, maxRadiusX), rng.nextRangeF(0.f, maxRadiusY)},
1072cb93a386Sopenharmony_ci                             {rng.nextRangeF(0.f, maxRadiusX), rng.nextRangeF(0.f, maxRadiusY)}};
1073cb93a386Sopenharmony_ci
1074cb93a386Sopenharmony_ci        float maxLeft   = std::max(radii[0].fX, radii[3].fX);
1075cb93a386Sopenharmony_ci        float maxTop    = std::max(radii[0].fY, radii[1].fY);
1076cb93a386Sopenharmony_ci        float maxRight  = std::max(radii[1].fX, radii[2].fX);
1077cb93a386Sopenharmony_ci        float maxBottom = std::max(radii[2].fY, radii[3].fY);
1078cb93a386Sopenharmony_ci
1079cb93a386Sopenharmony_ci        SkRect outer = SkRect::MakeWH(maxLeft + maxRight + innerWidth,
1080cb93a386Sopenharmony_ci                                      maxTop + maxBottom + innerHeight);
1081cb93a386Sopenharmony_ci        rr.setRectRadii(outer, radii);
1082cb93a386Sopenharmony_ci
1083cb93a386Sopenharmony_ci        SkRect maxInner = SkRRectPriv::InnerBounds(rr);
1084cb93a386Sopenharmony_ci        // Test upper limit on the size of 'maxInner'
1085cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, outer.contains(maxInner));
1086cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, rr.contains(maxInner));
1087cb93a386Sopenharmony_ci
1088cb93a386Sopenharmony_ci        // Test lower limit on the size of 'maxInner'
1089cb93a386Sopenharmony_ci        inner = SkRect::MakeXYWH(maxLeft, maxTop, innerWidth, innerHeight);
1090cb93a386Sopenharmony_ci        inner.inset(kEpsilon, kEpsilon);
1091cb93a386Sopenharmony_ci
1092cb93a386Sopenharmony_ci        if (inner.isSorted()) {
1093cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, maxInner.contains(inner));
1094cb93a386Sopenharmony_ci        } else {
1095cb93a386Sopenharmony_ci            // Flipped from the inset, just test two points of inner
1096cb93a386Sopenharmony_ci            float midX = maxLeft + 0.5f * innerWidth;
1097cb93a386Sopenharmony_ci            float midY = maxTop + 0.5f * innerHeight;
1098cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, maxInner.contains(midX, maxTop));
1099cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, maxInner.contains(midX, maxTop + innerHeight));
1100cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, maxInner.contains(maxLeft, midY));
1101cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, maxInner.contains(maxLeft + innerWidth, midY));
1102cb93a386Sopenharmony_ci        }
1103cb93a386Sopenharmony_ci    }
1104cb93a386Sopenharmony_ci}
1105cb93a386Sopenharmony_ci
1106cb93a386Sopenharmony_cinamespace {
1107cb93a386Sopenharmony_ci    // Helper to test expected intersection, relying on the fact that all round rect intersections
1108cb93a386Sopenharmony_ci    // will have their bounds equal to the intersection of the bounds of the input round rects, and
1109cb93a386Sopenharmony_ci    // their corner radii will be a one of A's, B's, or rectangular.
1110cb93a386Sopenharmony_ci    enum CornerChoice : uint8_t {
1111cb93a386Sopenharmony_ci        kA, kB, kRect
1112cb93a386Sopenharmony_ci    };
1113cb93a386Sopenharmony_ci
1114cb93a386Sopenharmony_ci    static void verify_success(skiatest::Reporter* reporter, const SkRRect& a, const SkRRect& b,
1115cb93a386Sopenharmony_ci                               CornerChoice tl, CornerChoice tr, CornerChoice br, CornerChoice bl) {
1116cb93a386Sopenharmony_ci        static const SkRRect kRect = SkRRect::MakeEmpty(); // has (0,0) for all corners
1117cb93a386Sopenharmony_ci
1118cb93a386Sopenharmony_ci        // Compute expected round rect intersection given bounds of A and B, and the specified
1119cb93a386Sopenharmony_ci        // corner choices for the 4 corners.
1120cb93a386Sopenharmony_ci        SkRect expectedBounds;
1121cb93a386Sopenharmony_ci        SkAssertResult(expectedBounds.intersect(a.rect(), b.rect()));
1122cb93a386Sopenharmony_ci
1123cb93a386Sopenharmony_ci        SkVector radii[4] = {
1124cb93a386Sopenharmony_ci            (tl == kA ? a : (tl == kB ? b : kRect)).radii(SkRRect::kUpperLeft_Corner),
1125cb93a386Sopenharmony_ci            (tr == kA ? a : (tr == kB ? b : kRect)).radii(SkRRect::kUpperRight_Corner),
1126cb93a386Sopenharmony_ci            (br == kA ? a : (br == kB ? b : kRect)).radii(SkRRect::kLowerRight_Corner),
1127cb93a386Sopenharmony_ci            (bl == kA ? a : (bl == kB ? b : kRect)).radii(SkRRect::kLowerLeft_Corner)
1128cb93a386Sopenharmony_ci        };
1129cb93a386Sopenharmony_ci        SkRRect expected;
1130cb93a386Sopenharmony_ci        expected.setRectRadii(expectedBounds, radii);
1131cb93a386Sopenharmony_ci
1132cb93a386Sopenharmony_ci        SkRRect actual = SkRRectPriv::ConservativeIntersect(a, b);
1133cb93a386Sopenharmony_ci        // Intersections are commutative so ba and ab should be the same
1134cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, actual == SkRRectPriv::ConservativeIntersect(b, a));
1135cb93a386Sopenharmony_ci
1136cb93a386Sopenharmony_ci        // Intersection of the result with either A or B should remain the intersection
1137cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, actual == SkRRectPriv::ConservativeIntersect(actual, a));
1138cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, actual == SkRRectPriv::ConservativeIntersect(actual, b));
1139cb93a386Sopenharmony_ci
1140cb93a386Sopenharmony_ci        // Bounds of intersection round rect should equal intersection of bounds of a and b
1141cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, actual.rect() == expectedBounds);
1142cb93a386Sopenharmony_ci
1143cb93a386Sopenharmony_ci        // Use PathOps to confirm that the explicit round rect is correct.
1144cb93a386Sopenharmony_ci        SkPath aPath, bPath, expectedPath;
1145cb93a386Sopenharmony_ci        aPath.addRRect(a);
1146cb93a386Sopenharmony_ci        bPath.addRRect(b);
1147cb93a386Sopenharmony_ci        SkAssertResult(Op(aPath, bPath, kIntersect_SkPathOp, &expectedPath));
1148cb93a386Sopenharmony_ci
1149cb93a386Sopenharmony_ci        // The isRRect() heuristics in SkPath are based on having called addRRect(), so a path from
1150cb93a386Sopenharmony_ci        // path ops that is a rounded rectangle will return false. However, if test XOR expected is
1151cb93a386Sopenharmony_ci        // empty, then we know that the shapes were the same.
1152cb93a386Sopenharmony_ci        SkPath testPath;
1153cb93a386Sopenharmony_ci        testPath.addRRect(actual);
1154cb93a386Sopenharmony_ci
1155cb93a386Sopenharmony_ci        SkPath empty;
1156cb93a386Sopenharmony_ci        SkAssertResult(Op(testPath, expectedPath, kXOR_SkPathOp, &empty));
1157cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, empty.isEmpty());
1158cb93a386Sopenharmony_ci    }
1159cb93a386Sopenharmony_ci
1160cb93a386Sopenharmony_ci    static void verify_failure(skiatest::Reporter* reporter, const SkRRect& a, const SkRRect& b) {
1161cb93a386Sopenharmony_ci        SkRRect intersection = SkRRectPriv::ConservativeIntersect(a, b);
1162cb93a386Sopenharmony_ci        // Expected the intersection to fail (no intersection or complex intersection is not
1163cb93a386Sopenharmony_ci        // disambiguated).
1164cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, intersection.isEmpty());
1165cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, SkRRectPriv::ConservativeIntersect(b, a).isEmpty());
1166cb93a386Sopenharmony_ci    }
1167cb93a386Sopenharmony_ci}  // namespace
1168cb93a386Sopenharmony_ci
1169cb93a386Sopenharmony_cistatic void test_conservative_intersection(skiatest::Reporter* reporter) {
1170cb93a386Sopenharmony_ci    // Helper to inline making an inset round rect
1171cb93a386Sopenharmony_ci    auto make_inset = [](const SkRRect& r, float dx, float dy) {
1172cb93a386Sopenharmony_ci        SkRRect i = r;
1173cb93a386Sopenharmony_ci        i.inset(dx, dy);
1174cb93a386Sopenharmony_ci        return i;
1175cb93a386Sopenharmony_ci    };
1176cb93a386Sopenharmony_ci
1177cb93a386Sopenharmony_ci    // A is a wide, short round rect
1178cb93a386Sopenharmony_ci    SkRRect a = SkRRect::MakeRectXY({0.f, 4.f, 16.f, 12.f}, 2.f, 2.f);
1179cb93a386Sopenharmony_ci    // B is a narrow, tall round rect
1180cb93a386Sopenharmony_ci    SkRRect b = SkRRect::MakeRectXY({4.f, 0.f, 12.f, 16.f}, 3.f, 3.f);
1181cb93a386Sopenharmony_ci    // NOTE: As positioned by default, A and B intersect as the rectangle {4, 4, 12, 12}.
1182cb93a386Sopenharmony_ci    // There is a 2 px buffer between the corner curves of A and the vertical edges of B, and
1183cb93a386Sopenharmony_ci    // a 1 px buffer between the corner curves of B and the horizontal edges of A. Since the shapes
1184cb93a386Sopenharmony_ci    // form a symmetric rounded cross, we can easily test edge and corner combinations by simply
1185cb93a386Sopenharmony_ci    // flipping signs and/or swapping x and y offsets.
1186cb93a386Sopenharmony_ci
1187cb93a386Sopenharmony_ci    // Successful intersection operations:
1188cb93a386Sopenharmony_ci    //  - for clarity these are formed by moving A around to intersect with B in different ways.
1189cb93a386Sopenharmony_ci    //  - the expected bounds of the round rect intersection is calculated automatically
1190cb93a386Sopenharmony_ci    //    in check_success, so all we have to specify are the expected corner radii
1191cb93a386Sopenharmony_ci
1192cb93a386Sopenharmony_ci    // A and B intersect as a rectangle
1193cb93a386Sopenharmony_ci    verify_success(reporter, a, b, kRect, kRect, kRect, kRect);
1194cb93a386Sopenharmony_ci    // Move A to intersect B on a vertical edge, preserving two corners of A inside B
1195cb93a386Sopenharmony_ci    verify_success(reporter, a.makeOffset(6.f, 0.f), b, kA, kRect, kRect, kA);
1196cb93a386Sopenharmony_ci    verify_success(reporter, a.makeOffset(-6.f, 0.f), b, kRect, kA, kA, kRect);
1197cb93a386Sopenharmony_ci    // Move B to intersect A on a horizontal edge, preserving two corners of B inside A
1198cb93a386Sopenharmony_ci    verify_success(reporter, a, b.makeOffset(0.f, 6.f), kB, kB, kRect, kRect);
1199cb93a386Sopenharmony_ci    verify_success(reporter, a, b.makeOffset(0.f, -6.f), kRect, kRect, kB, kB);
1200cb93a386Sopenharmony_ci    // Move A to intersect B on a corner, preserving one corner of A and one of B
1201cb93a386Sopenharmony_ci    verify_success(reporter, a.makeOffset(-7.f, -8.f), b, kB, kRect, kA, kRect); // TL of B
1202cb93a386Sopenharmony_ci    verify_success(reporter, a.makeOffset(7.f, -8.f), b, kRect, kB, kRect, kA);  // TR of B
1203cb93a386Sopenharmony_ci    verify_success(reporter, a.makeOffset(7.f, 8.f), b, kA, kRect, kB, kRect);   // BR of B
1204cb93a386Sopenharmony_ci    verify_success(reporter, a.makeOffset(-7.f, 8.f), b, kRect, kA, kRect, kB);  // BL of B
1205cb93a386Sopenharmony_ci    // An inset is contained inside the original (note that SkRRect::inset modifies radii too) so
1206cb93a386Sopenharmony_ci    // is returned unmodified when intersected.
1207cb93a386Sopenharmony_ci    verify_success(reporter, a, make_inset(a, 1.f, 1.f), kB, kB, kB, kB);
1208cb93a386Sopenharmony_ci    verify_success(reporter, make_inset(b, 2.f, 2.f), b, kA, kA, kA, kA);
1209cb93a386Sopenharmony_ci
1210cb93a386Sopenharmony_ci    // A rectangle exactly matching the corners of the rrect bounds keeps the rrect radii,
1211cb93a386Sopenharmony_ci    // regardless of whether or not it's the 1st or 2nd arg to ConservativeIntersect.
1212cb93a386Sopenharmony_ci    SkRRect c = SkRRect::MakeRectXY({0.f, 0.f, 10.f, 10.f}, 2.f, 2.f);
1213cb93a386Sopenharmony_ci    SkRRect cT = SkRRect::MakeRect({0.f, 0.f, 10.f, 5.f});
1214cb93a386Sopenharmony_ci    verify_success(reporter, c, cT, kA, kA, kRect, kRect);
1215cb93a386Sopenharmony_ci    verify_success(reporter, cT, c, kB, kB, kRect, kRect);
1216cb93a386Sopenharmony_ci    SkRRect cB = SkRRect::MakeRect({0.f, 5.f, 10.f, 10.});
1217cb93a386Sopenharmony_ci    verify_success(reporter, c, cB, kRect, kRect, kA, kA);
1218cb93a386Sopenharmony_ci    verify_success(reporter, cB, c, kRect, kRect, kB, kB);
1219cb93a386Sopenharmony_ci    SkRRect cL = SkRRect::MakeRect({0.f, 0.f, 5.f, 10.f});
1220cb93a386Sopenharmony_ci    verify_success(reporter, c, cL, kA, kRect, kRect, kA);
1221cb93a386Sopenharmony_ci    verify_success(reporter, cL, c, kB, kRect, kRect, kB);
1222cb93a386Sopenharmony_ci    SkRRect cR = SkRRect::MakeRect({5.f, 0.f, 10.f, 10.f});
1223cb93a386Sopenharmony_ci    verify_success(reporter, c, cR, kRect, kA, kA, kRect);
1224cb93a386Sopenharmony_ci    verify_success(reporter, cR, c, kRect, kB, kB, kRect);
1225cb93a386Sopenharmony_ci
1226cb93a386Sopenharmony_ci    // Failed intersection operations:
1227cb93a386Sopenharmony_ci
1228cb93a386Sopenharmony_ci    // A and B's bounds do not intersect
1229cb93a386Sopenharmony_ci    verify_failure(reporter, a.makeOffset(32.f, 0.f), b);
1230cb93a386Sopenharmony_ci    // A and B's bounds intersect, but corner curves do not -> no intersection
1231cb93a386Sopenharmony_ci    verify_failure(reporter, a.makeOffset(11.5f, -11.5f), b);
1232cb93a386Sopenharmony_ci    // A is empty -> no intersection
1233cb93a386Sopenharmony_ci    verify_failure(reporter, SkRRect::MakeEmpty(), b);
1234cb93a386Sopenharmony_ci    // A is contained in B, but is too close to the corner curves for the conservative
1235cb93a386Sopenharmony_ci    // approximations to construct a valid round rect intersection.
1236cb93a386Sopenharmony_ci    verify_failure(reporter, make_inset(b, 0.3f, 0.3f), b);
1237cb93a386Sopenharmony_ci    // A intersects a straight edge, but not far enough for B to contain A's corners
1238cb93a386Sopenharmony_ci    verify_failure(reporter, a.makeOffset(2.5f, 0.f), b);
1239cb93a386Sopenharmony_ci    verify_failure(reporter, a.makeOffset(-2.5f, 0.f), b);
1240cb93a386Sopenharmony_ci    // And vice versa for B into A
1241cb93a386Sopenharmony_ci    verify_failure(reporter, a, b.makeOffset(0.f, 1.5f));
1242cb93a386Sopenharmony_ci    verify_failure(reporter, a, b.makeOffset(0.f, -1.5f));
1243cb93a386Sopenharmony_ci    // A intersects a straight edge and part of B's corner
1244cb93a386Sopenharmony_ci    verify_failure(reporter, a.makeOffset(5.f, -2.f), b);
1245cb93a386Sopenharmony_ci    verify_failure(reporter, a.makeOffset(-5.f, -2.f), b);
1246cb93a386Sopenharmony_ci    verify_failure(reporter, a.makeOffset(5.f, 2.f), b);
1247cb93a386Sopenharmony_ci    verify_failure(reporter, a.makeOffset(-5.f, 2.f), b);
1248cb93a386Sopenharmony_ci    // And vice versa
1249cb93a386Sopenharmony_ci    verify_failure(reporter, a, b.makeOffset(3.f, -5.f));
1250cb93a386Sopenharmony_ci    verify_failure(reporter, a, b.makeOffset(-3.f, -5.f));
1251cb93a386Sopenharmony_ci    verify_failure(reporter, a, b.makeOffset(3.f, 5.f));
1252cb93a386Sopenharmony_ci    verify_failure(reporter, a, b.makeOffset(-3.f, 5.f));
1253cb93a386Sopenharmony_ci    // A intersects B on a corner, but the corner curves overlap each other
1254cb93a386Sopenharmony_ci    verify_failure(reporter, a.makeOffset(8.f, 10.f), b);
1255cb93a386Sopenharmony_ci    verify_failure(reporter, a.makeOffset(-8.f, 10.f), b);
1256cb93a386Sopenharmony_ci    verify_failure(reporter, a.makeOffset(8.f, -10.f), b);
1257cb93a386Sopenharmony_ci    verify_failure(reporter, a.makeOffset(-8.f, -10.f), b);
1258cb93a386Sopenharmony_ci
1259cb93a386Sopenharmony_ci    // Another variant of corners overlapping, this is two circles of radius r that overlap by r
1260cb93a386Sopenharmony_ci    // pixels (e.g. the leftmost point of the right circle touches the center of the left circle).
1261cb93a386Sopenharmony_ci    // The key difference with the above case is that the intersection of the circle bounds have
1262cb93a386Sopenharmony_ci    // corners that are contained in both circles, but because it is only r wide, can not satisfy
1263cb93a386Sopenharmony_ci    // all corners having radii = r.
1264cb93a386Sopenharmony_ci    float r = 100.f;
1265cb93a386Sopenharmony_ci    a = SkRRect::MakeOval(SkRect::MakeWH(2*r, 2*r));
1266cb93a386Sopenharmony_ci    verify_failure(reporter, a, a.makeOffset(r, 0.f));
1267cb93a386Sopenharmony_ci}
1268cb93a386Sopenharmony_ci
1269cb93a386Sopenharmony_ciDEF_TEST(RoundRect, reporter) {
1270cb93a386Sopenharmony_ci    test_round_rect_basic(reporter);
1271cb93a386Sopenharmony_ci    test_round_rect_rects(reporter);
1272cb93a386Sopenharmony_ci    test_round_rect_ovals(reporter);
1273cb93a386Sopenharmony_ci    test_round_rect_general(reporter);
1274cb93a386Sopenharmony_ci    test_round_rect_iffy_parameters(reporter);
1275cb93a386Sopenharmony_ci    test_inset(reporter);
1276cb93a386Sopenharmony_ci    test_round_rect_contains_rect(reporter);
1277cb93a386Sopenharmony_ci    test_round_rect_transform(reporter);
1278cb93a386Sopenharmony_ci    test_issue_2696(reporter);
1279cb93a386Sopenharmony_ci    test_tricky_radii(reporter);
1280cb93a386Sopenharmony_ci    test_empty_crbug_458524(reporter);
1281cb93a386Sopenharmony_ci    test_empty(reporter);
1282cb93a386Sopenharmony_ci    test_read(reporter);
1283cb93a386Sopenharmony_ci    test_inner_bounds(reporter);
1284cb93a386Sopenharmony_ci    test_conservative_intersection(reporter);
1285cb93a386Sopenharmony_ci}
1286cb93a386Sopenharmony_ci
1287cb93a386Sopenharmony_ciDEF_TEST(RRect_fuzzer_regressions, r) {
1288cb93a386Sopenharmony_ci    {
1289cb93a386Sopenharmony_ci        unsigned char buf[] = {
1290cb93a386Sopenharmony_ci            0x0a, 0x00, 0x00, 0xff, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f,
1291cb93a386Sopenharmony_ci            0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
1292cb93a386Sopenharmony_ci            0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
1293cb93a386Sopenharmony_ci            0x7f, 0x7f, 0x7f, 0x02, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x02, 0x00
1294cb93a386Sopenharmony_ci        };
1295cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, sizeof(buf) == SkRRect{}.readFromMemory(buf, sizeof(buf)));
1296cb93a386Sopenharmony_ci    }
1297cb93a386Sopenharmony_ci
1298cb93a386Sopenharmony_ci    {
1299cb93a386Sopenharmony_ci        unsigned char buf[] = {
1300cb93a386Sopenharmony_ci            0x5d, 0xff, 0xff, 0x5d, 0x0a, 0x60, 0x0a, 0x0a, 0x0a, 0x7e, 0x0a, 0x5a,
1301cb93a386Sopenharmony_ci            0x0a, 0x12, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a,
1302cb93a386Sopenharmony_ci            0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x00, 0x00, 0x00, 0x0a,
1303cb93a386Sopenharmony_ci            0x0a, 0x0a, 0x0a, 0x26, 0x0a, 0x0a, 0x0a, 0x0a, 0xff, 0xff, 0x0a, 0x0a
1304cb93a386Sopenharmony_ci        };
1305cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, sizeof(buf) == SkRRect{}.readFromMemory(buf, sizeof(buf)));
1306cb93a386Sopenharmony_ci    }
1307cb93a386Sopenharmony_ci
1308cb93a386Sopenharmony_ci    {
1309cb93a386Sopenharmony_ci        unsigned char buf[] = {
1310cb93a386Sopenharmony_ci            0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x04, 0xdd, 0xdd, 0x15,
1311cb93a386Sopenharmony_ci            0xfe, 0x00, 0x00, 0x04, 0x05, 0x7e, 0x00, 0x00, 0x00, 0xff, 0x08, 0x04,
1312cb93a386Sopenharmony_ci            0xff, 0xff, 0xfe, 0xfe, 0xff, 0x32, 0x32, 0x32, 0x32, 0x00, 0x32, 0x32,
1313cb93a386Sopenharmony_ci            0x04, 0xdd, 0x3d, 0x1c, 0xfe, 0x89, 0x04, 0x0a, 0x0e, 0x05, 0x7e, 0x0a
1314cb93a386Sopenharmony_ci        };
1315cb93a386Sopenharmony_ci        REPORTER_ASSERT(r, sizeof(buf) == SkRRect{}.readFromMemory(buf, sizeof(buf)));
1316cb93a386Sopenharmony_ci    }
1317cb93a386Sopenharmony_ci}
1318