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