• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2012 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkMatrix.h"
9 #include "SkRRect.h"
10 #include "Test.h"
11 
12 static const SkScalar kWidth = 100.0f;
13 static const SkScalar kHeight = 100.0f;
14 
test_inset(skiatest::Reporter * reporter)15 static void test_inset(skiatest::Reporter* reporter) {
16     SkRRect rr, rr2;
17     SkRect r = { 0, 0, 100, 100 };
18 
19     rr.setRect(r);
20     rr.inset(-20, -20, &rr2);
21     REPORTER_ASSERT(reporter, rr2.isRect());
22 
23     rr.inset(20, 20, &rr2);
24     REPORTER_ASSERT(reporter, rr2.isRect());
25 
26     rr.inset(r.width()/2, r.height()/2, &rr2);
27     REPORTER_ASSERT(reporter, rr2.isEmpty());
28 
29     rr.setRectXY(r, 20, 20);
30     rr.inset(19, 19, &rr2);
31     REPORTER_ASSERT(reporter, rr2.isSimple());
32     rr.inset(20, 20, &rr2);
33     REPORTER_ASSERT(reporter, rr2.isRect());
34 }
35 
36 // Test out the basic API entry points
test_round_rect_basic(skiatest::Reporter * reporter)37 static void test_round_rect_basic(skiatest::Reporter* reporter) {
38     // Test out initialization methods
39     SkPoint zeroPt = { 0, 0 };
40     SkRRect empty;
41 
42     empty.setEmpty();
43 
44     REPORTER_ASSERT(reporter, SkRRect::kEmpty_Type == empty.type());
45     REPORTER_ASSERT(reporter, empty.rect().isEmpty());
46 
47     for (int i = 0; i < 4; ++i) {
48         REPORTER_ASSERT(reporter, zeroPt == empty.radii((SkRRect::Corner) i));
49     }
50 
51     //----
52     SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
53 
54     SkRRect rr1;
55     rr1.setRect(rect);
56 
57     REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr1.type());
58     REPORTER_ASSERT(reporter, rr1.rect() == rect);
59 
60     for (int i = 0; i < 4; ++i) {
61         REPORTER_ASSERT(reporter, zeroPt == rr1.radii((SkRRect::Corner) i));
62     }
63     SkRRect rr1_2; // construct the same RR using the most general set function
64     SkVector rr1_2_radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
65     rr1_2.setRectRadii(rect, rr1_2_radii);
66     REPORTER_ASSERT(reporter, rr1_2 == rr1 && rr1_2.getType() == rr1.getType());
67     SkRRect rr1_3;  // construct the same RR using the nine patch set function
68     rr1_3.setNinePatch(rect, 0, 0, 0, 0);
69     REPORTER_ASSERT(reporter, rr1_3 == rr1 && rr1_3.getType() == rr1.getType());
70 
71     //----
72     SkPoint halfPoint = { SkScalarHalf(kWidth), SkScalarHalf(kHeight) };
73     SkRRect rr2;
74     rr2.setOval(rect);
75 
76     REPORTER_ASSERT(reporter, SkRRect::kOval_Type == rr2.type());
77     REPORTER_ASSERT(reporter, rr2.rect() == rect);
78 
79     for (int i = 0; i < 4; ++i) {
80         REPORTER_ASSERT(reporter,
81                         rr2.radii((SkRRect::Corner) i).equalsWithinTolerance(halfPoint));
82     }
83     SkRRect rr2_2;  // construct the same RR using the most general set function
84     SkVector rr2_2_radii[4] = { { halfPoint.fX, halfPoint.fY }, { halfPoint.fX, halfPoint.fY },
85                                 { halfPoint.fX, halfPoint.fY }, { halfPoint.fX, halfPoint.fY } };
86     rr2_2.setRectRadii(rect, rr2_2_radii);
87     REPORTER_ASSERT(reporter, rr2_2 == rr2 && rr2_2.getType() == rr2.getType());
88     SkRRect rr2_3;  // construct the same RR using the nine patch set function
89     rr2_3.setNinePatch(rect, halfPoint.fX, halfPoint.fY, halfPoint.fX, halfPoint.fY);
90     REPORTER_ASSERT(reporter, rr2_3 == rr2 && rr2_3.getType() == rr2.getType());
91 
92     //----
93     SkPoint p = { 5, 5 };
94     SkRRect rr3;
95     rr3.setRectXY(rect, p.fX, p.fY);
96 
97     REPORTER_ASSERT(reporter, SkRRect::kSimple_Type == rr3.type());
98     REPORTER_ASSERT(reporter, rr3.rect() == rect);
99 
100     for (int i = 0; i < 4; ++i) {
101         REPORTER_ASSERT(reporter, p == rr3.radii((SkRRect::Corner) i));
102     }
103     SkRRect rr3_2; // construct the same RR using the most general set function
104     SkVector rr3_2_radii[4] = { { 5, 5 }, { 5, 5 }, { 5, 5 }, { 5, 5 } };
105     rr3_2.setRectRadii(rect, rr3_2_radii);
106     REPORTER_ASSERT(reporter, rr3_2 == rr3 && rr3_2.getType() == rr3.getType());
107     SkRRect rr3_3;  // construct the same RR using the nine patch set function
108     rr3_3.setNinePatch(rect, 5, 5, 5, 5);
109     REPORTER_ASSERT(reporter, rr3_3 == rr3 && rr3_3.getType() == rr3.getType());
110 
111     //----
112     SkRect ninePatchRadii = { 10, 9, 8, 7 };
113 
114     SkRRect rr4;
115     rr4.setNinePatch(rect, ninePatchRadii.fLeft, ninePatchRadii.fTop, ninePatchRadii.fRight,
116                      ninePatchRadii.fBottom);
117 
118     REPORTER_ASSERT(reporter, SkRRect::kNinePatch_Type == rr4.type());
119     REPORTER_ASSERT(reporter, rr4.rect() == rect);
120 
121     SkPoint rquad[4];
122     ninePatchRadii.toQuad(rquad);
123     for (int i = 0; i < 4; ++i) {
124         REPORTER_ASSERT(reporter, rquad[i] == rr4.radii((SkRRect::Corner) i));
125     }
126     SkRRect rr4_2; // construct the same RR using the most general set function
127     SkVector rr4_2_radii[4] = { { 10, 9 }, { 8, 9 }, {8, 7 }, { 10, 7 } };
128     rr4_2.setRectRadii(rect, rr4_2_radii);
129     REPORTER_ASSERT(reporter, rr4_2 == rr4 && rr4_2.getType() == rr4.getType());
130 
131     //----
132     SkPoint radii2[4] = { { 0, 0 }, { 0, 0 }, { 50, 50 }, { 20, 50 } };
133 
134     SkRRect rr5;
135     rr5.setRectRadii(rect, radii2);
136 
137     REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr5.type());
138     REPORTER_ASSERT(reporter, rr5.rect() == rect);
139 
140     for (int i = 0; i < 4; ++i) {
141         REPORTER_ASSERT(reporter, radii2[i] == rr5.radii((SkRRect::Corner) i));
142     }
143 
144     // Test out == & !=
145     REPORTER_ASSERT(reporter, empty != rr3);
146     REPORTER_ASSERT(reporter, rr3 != rr4);
147     REPORTER_ASSERT(reporter, rr4 != rr5);
148 }
149 
150 // Test out the cases when the RR degenerates to a rect
test_round_rect_rects(skiatest::Reporter * reporter)151 static void test_round_rect_rects(skiatest::Reporter* reporter) {
152     SkRect r;
153 
154     //----
155     SkRRect empty;
156 
157     empty.setEmpty();
158 
159     REPORTER_ASSERT(reporter, SkRRect::kEmpty_Type == empty.type());
160     r = empty.rect();
161     REPORTER_ASSERT(reporter, 0 == r.fLeft && 0 == r.fTop && 0 == r.fRight && 0 == r.fBottom);
162 
163     //----
164     SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
165     SkRRect rr1;
166     rr1.setRectXY(rect, 0, 0);
167 
168     REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr1.type());
169     r = rr1.rect();
170     REPORTER_ASSERT(reporter, rect == r);
171 
172     //----
173     SkPoint radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
174 
175     SkRRect rr2;
176     rr2.setRectRadii(rect, radii);
177 
178     REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr2.type());
179     r = rr2.rect();
180     REPORTER_ASSERT(reporter, rect == r);
181 
182     //----
183     SkPoint radii2[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } };
184 
185     SkRRect rr3;
186     rr3.setRectRadii(rect, radii2);
187     REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr3.type());
188 }
189 
190 // Test out the cases when the RR degenerates to an oval
test_round_rect_ovals(skiatest::Reporter * reporter)191 static void test_round_rect_ovals(skiatest::Reporter* reporter) {
192     //----
193     SkRect oval;
194     SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
195     SkRRect rr1;
196     rr1.setRectXY(rect, SkScalarHalf(kWidth), SkScalarHalf(kHeight));
197 
198     REPORTER_ASSERT(reporter, SkRRect::kOval_Type == rr1.type());
199     oval = rr1.rect();
200     REPORTER_ASSERT(reporter, oval == rect);
201 }
202 
203 // Test out the non-degenerate RR cases
test_round_rect_general(skiatest::Reporter * reporter)204 static void test_round_rect_general(skiatest::Reporter* reporter) {
205     //----
206     SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
207     SkRRect rr1;
208     rr1.setRectXY(rect, 20, 20);
209 
210     REPORTER_ASSERT(reporter, SkRRect::kSimple_Type == rr1.type());
211 
212     //----
213     SkPoint radii[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } };
214 
215     SkRRect rr2;
216     rr2.setRectRadii(rect, radii);
217 
218     REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr2.type());
219 }
220 
221 // Test out questionable-parameter handling
test_round_rect_iffy_parameters(skiatest::Reporter * reporter)222 static void test_round_rect_iffy_parameters(skiatest::Reporter* reporter) {
223 
224     // When the radii exceed the base rect they are proportionally scaled down
225     // to fit
226     SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
227     SkPoint radii[4] = { { 50, 100 }, { 100, 50 }, { 50, 100 }, { 100, 50 } };
228 
229     SkRRect rr1;
230     rr1.setRectRadii(rect, radii);
231 
232     REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr1.type());
233 
234     const SkPoint& p = rr1.radii(SkRRect::kUpperLeft_Corner);
235 
236     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.fX, 33.33333f));
237     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.fY, 66.66666f));
238 
239     // Negative radii should be capped at zero
240     SkRRect rr2;
241     rr2.setRectXY(rect, -10, -20);
242 
243     REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr2.type());
244 
245     const SkPoint& p2 = rr2.radii(SkRRect::kUpperLeft_Corner);
246 
247     REPORTER_ASSERT(reporter, 0.0f == p2.fX);
248     REPORTER_ASSERT(reporter, 0.0f == p2.fY);
249 }
250 
251 // Move a small box from the start position by (stepX, stepY) 'numSteps' times
252 // 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)253 static void test_direction(skiatest::Reporter* reporter, const SkRRect &rr,
254                            SkScalar initX, int stepX, SkScalar initY, int stepY,
255                            int numSteps, const bool* contains) {
256     SkScalar x = initX, y = initY;
257     for (int i = 0; i < numSteps; ++i) {
258         SkRect test = SkRect::MakeXYWH(x, y,
259                                        stepX ? SkIntToScalar(stepX) : SK_Scalar1,
260                                        stepY ? SkIntToScalar(stepY) : SK_Scalar1);
261         test.sort();
262 
263         REPORTER_ASSERT(reporter, contains[i] == rr.contains(test));
264 
265         x += stepX;
266         y += stepY;
267     }
268 }
269 
270 // Exercise the RR's contains rect method
test_round_rect_contains_rect(skiatest::Reporter * reporter)271 static void test_round_rect_contains_rect(skiatest::Reporter* reporter) {
272 
273     static const int kNumRRects = 4;
274     static const SkVector gRadii[kNumRRects][4] = {
275         { {  0,  0 }, {  0,  0 }, {  0,  0 }, {  0,  0 } },  // rect
276         { { 20, 20 }, { 20, 20 }, { 20, 20 }, { 20, 20 } },  // circle
277         { { 10, 10 }, { 10, 10 }, { 10, 10 }, { 10, 10 } },  // simple
278         { {  0,  0 }, { 20, 20 }, { 10, 10 }, { 30, 30 } }   // complex
279     };
280 
281     SkRRect rrects[kNumRRects];
282     for (int i = 0; i < kNumRRects; ++i) {
283         rrects[i].setRectRadii(SkRect::MakeWH(40, 40), gRadii[i]);
284     }
285 
286     // First test easy outs - boxes that are obviously out on
287     // each corner and edge
288     static const SkRect easyOuts[] = {
289         { -5, -5,  5,  5 }, // NW
290         { 15, -5, 20,  5 }, // N
291         { 35, -5, 45,  5 }, // NE
292         { 35, 15, 45, 20 }, // E
293         { 35, 45, 35, 45 }, // SE
294         { 15, 35, 20, 45 }, // S
295         { -5, 35,  5, 45 }, // SW
296         { -5, 15,  5, 20 }  // W
297     };
298 
299     for (int i = 0; i < kNumRRects; ++i) {
300         for (size_t j = 0; j < SK_ARRAY_COUNT(easyOuts); ++j) {
301             REPORTER_ASSERT(reporter, !rrects[i].contains(easyOuts[j]));
302         }
303     }
304 
305     // Now test non-trivial containment. For each compass
306     // point walk a 1x1 rect in from the edge  of the bounding
307     // rect
308     static const int kNumSteps = 15;
309     bool answers[kNumRRects][8][kNumSteps] = {
310         // all the test rects are inside the degenerate rrect
311         {
312             // rect
313             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
314             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
315             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
316             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
317             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
318             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
319             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
320             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
321         },
322         // for the circle we expect 6 blocks to be out on the
323         // corners (then the rest in) and only the first block
324         // out on the vertical and horizontal axes (then
325         // the rest in)
326         {
327             // circle
328             { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
329             { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
330             { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
331             { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
332             { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
333             { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
334             { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
335             { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
336         },
337         // for the simple round rect we expect 3 out on
338         // the corners (then the rest in) and no blocks out
339         // on the vertical and horizontal axes
340         {
341             // simple RR
342             { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
343             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
344             { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
345             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
346             { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
347             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
348             { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
349             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
350         },
351         // for the complex case the answer is different for each direction
352         {
353             // complex RR
354             // all in for NW (rect) corner (same as rect case)
355             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
356             // only first block out for N (same as circle case)
357             { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
358             // first 6 blocks out for NE (same as circle case)
359             { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
360             // only first block out for E (same as circle case)
361             { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
362             // first 3 blocks out for SE (same as simple case)
363             { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
364             // first two blocks out for S
365             { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
366             // first 9 blocks out for SW
367             { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1 },
368             // first two blocks out for W (same as S)
369             { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
370          }
371     };
372 
373     for (int i = 0; i < kNumRRects; ++i) {
374         test_direction(reporter, rrects[i],     0,  1,     0,  1, kNumSteps, answers[i][0]); // NW
375         test_direction(reporter, rrects[i], 19.5f,  0,     0,  1, kNumSteps, answers[i][1]); // N
376         test_direction(reporter, rrects[i],    40, -1,     0,  1, kNumSteps, answers[i][2]); // NE
377         test_direction(reporter, rrects[i],    40, -1, 19.5f,  0, kNumSteps, answers[i][3]); // E
378         test_direction(reporter, rrects[i],    40, -1,    40, -1, kNumSteps, answers[i][4]); // SE
379         test_direction(reporter, rrects[i], 19.5f,  0,    40, -1, kNumSteps, answers[i][5]); // S
380         test_direction(reporter, rrects[i],     0,  1,    40, -1, kNumSteps, answers[i][6]); // SW
381         test_direction(reporter, rrects[i],     0,  1, 19.5f,  0, kNumSteps, answers[i][7]); // W
382     }
383 }
384 
385 // Called for a matrix that should cause SkRRect::transform to fail.
assert_transform_failure(skiatest::Reporter * reporter,const SkRRect & orig,const SkMatrix & matrix)386 static void assert_transform_failure(skiatest::Reporter* reporter, const SkRRect& orig,
387                                      const SkMatrix& matrix) {
388     // The test depends on the fact that the original is not empty.
389     SkASSERT(!orig.isEmpty());
390     SkRRect dst;
391     dst.setEmpty();
392 
393     const SkRRect copyOfDst = dst;
394     const SkRRect copyOfOrig = orig;
395     bool success = orig.transform(matrix, &dst);
396     // This transform should fail.
397     REPORTER_ASSERT(reporter, !success);
398     // Since the transform failed, dst should be unchanged.
399     REPORTER_ASSERT(reporter, copyOfDst == dst);
400     // original should not be modified.
401     REPORTER_ASSERT(reporter, copyOfOrig == orig);
402     REPORTER_ASSERT(reporter, orig != dst);
403 }
404 
405 #define GET_RADII                                                       \
406     const SkVector& origUL = orig.radii(SkRRect::kUpperLeft_Corner);    \
407     const SkVector& origUR = orig.radii(SkRRect::kUpperRight_Corner);   \
408     const SkVector& origLR = orig.radii(SkRRect::kLowerRight_Corner);   \
409     const SkVector& origLL = orig.radii(SkRRect::kLowerLeft_Corner);    \
410     const SkVector& dstUL = dst.radii(SkRRect::kUpperLeft_Corner);      \
411     const SkVector& dstUR = dst.radii(SkRRect::kUpperRight_Corner);     \
412     const SkVector& dstLR = dst.radii(SkRRect::kLowerRight_Corner);     \
413     const SkVector& dstLL = dst.radii(SkRRect::kLowerLeft_Corner)
414 
415 // Called to test various transforms on a single SkRRect.
test_transform_helper(skiatest::Reporter * reporter,const SkRRect & orig)416 static void test_transform_helper(skiatest::Reporter* reporter, const SkRRect& orig) {
417     SkRRect dst;
418     dst.setEmpty();
419 
420     // The identity matrix will duplicate the rrect.
421     bool success = orig.transform(SkMatrix::I(), &dst);
422     REPORTER_ASSERT(reporter, success);
423     REPORTER_ASSERT(reporter, orig == dst);
424 
425     // Skew and Perspective make transform fail.
426     SkMatrix matrix;
427     matrix.reset();
428     matrix.setSkewX(SkIntToScalar(2));
429     assert_transform_failure(reporter, orig, matrix);
430 
431     matrix.reset();
432     matrix.setSkewY(SkIntToScalar(3));
433     assert_transform_failure(reporter, orig, matrix);
434 
435     matrix.reset();
436     matrix.setPerspX(SkScalarToPersp(SkIntToScalar(4)));
437     assert_transform_failure(reporter, orig, matrix);
438 
439     matrix.reset();
440     matrix.setPerspY(SkScalarToPersp(SkIntToScalar(5)));
441     assert_transform_failure(reporter, orig, matrix);
442 
443     // Rotation fails.
444     matrix.reset();
445     matrix.setRotate(SkIntToScalar(90));
446     assert_transform_failure(reporter, orig, matrix);
447     matrix.setRotate(SkIntToScalar(37));
448     assert_transform_failure(reporter, orig, matrix);
449 
450     // Translate will keep the rect moved, but otherwise the same.
451     matrix.reset();
452     SkScalar translateX = SkIntToScalar(32);
453     SkScalar translateY = SkIntToScalar(15);
454     matrix.setTranslateX(translateX);
455     matrix.setTranslateY(translateY);
456     dst.setEmpty();
457     success = orig.transform(matrix, &dst);
458     REPORTER_ASSERT(reporter, success);
459     for (int i = 0; i < 4; ++i) {
460         REPORTER_ASSERT(reporter,
461                 orig.radii((SkRRect::Corner) i) == dst.radii((SkRRect::Corner) i));
462     }
463     REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
464     REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
465     REPORTER_ASSERT(reporter, dst.rect().left() == orig.rect().left() + translateX);
466     REPORTER_ASSERT(reporter, dst.rect().top() == orig.rect().top() + translateY);
467 
468     // Keeping the translation, but adding skew will make transform fail.
469     matrix.setSkewY(SkIntToScalar(7));
470     assert_transform_failure(reporter, orig, matrix);
471 
472     // Scaling in -x will flip the round rect horizontally.
473     matrix.reset();
474     matrix.setScaleX(SkIntToScalar(-1));
475     dst.setEmpty();
476     success = orig.transform(matrix, &dst);
477     REPORTER_ASSERT(reporter, success);
478     {
479         GET_RADII;
480         // Radii have swapped in x.
481         REPORTER_ASSERT(reporter, origUL == dstUR);
482         REPORTER_ASSERT(reporter, origUR == dstUL);
483         REPORTER_ASSERT(reporter, origLR == dstLL);
484         REPORTER_ASSERT(reporter, origLL == dstLR);
485     }
486     // Width and height remain the same.
487     REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
488     REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
489     // Right and left have swapped (sort of)
490     REPORTER_ASSERT(reporter, orig.rect().right() == -dst.rect().left());
491     // Top has stayed the same.
492     REPORTER_ASSERT(reporter, orig.rect().top() == dst.rect().top());
493 
494     // Keeping the scale, but adding a persp will make transform fail.
495     matrix.setPerspX(SkScalarToPersp(SkIntToScalar(7)));
496     assert_transform_failure(reporter, orig, matrix);
497 
498     // Scaling in -y will flip the round rect vertically.
499     matrix.reset();
500     matrix.setScaleY(SkIntToScalar(-1));
501     dst.setEmpty();
502     success = orig.transform(matrix, &dst);
503     REPORTER_ASSERT(reporter, success);
504     {
505         GET_RADII;
506         // Radii have swapped in y.
507         REPORTER_ASSERT(reporter, origUL == dstLL);
508         REPORTER_ASSERT(reporter, origUR == dstLR);
509         REPORTER_ASSERT(reporter, origLR == dstUR);
510         REPORTER_ASSERT(reporter, origLL == dstUL);
511     }
512     // Width and height remain the same.
513     REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
514     REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
515     // Top and bottom have swapped (sort of)
516     REPORTER_ASSERT(reporter, orig.rect().top() == -dst.rect().bottom());
517     // Left has stayed the same.
518     REPORTER_ASSERT(reporter, orig.rect().left() == dst.rect().left());
519 
520     // Scaling in -x and -y will swap in both directions.
521     matrix.reset();
522     matrix.setScaleY(SkIntToScalar(-1));
523     matrix.setScaleX(SkIntToScalar(-1));
524     dst.setEmpty();
525     success = orig.transform(matrix, &dst);
526     REPORTER_ASSERT(reporter, success);
527     {
528         GET_RADII;
529         REPORTER_ASSERT(reporter, origUL == dstLR);
530         REPORTER_ASSERT(reporter, origUR == dstLL);
531         REPORTER_ASSERT(reporter, origLR == dstUL);
532         REPORTER_ASSERT(reporter, origLL == dstUR);
533     }
534     // Width and height remain the same.
535     REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
536     REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
537     REPORTER_ASSERT(reporter, orig.rect().top() == -dst.rect().bottom());
538     REPORTER_ASSERT(reporter, orig.rect().right() == -dst.rect().left());
539 
540     // Scale in both directions.
541     SkScalar xScale = SkIntToScalar(3);
542     SkScalar yScale = 3.2f;
543     matrix.reset();
544     matrix.setScaleX(xScale);
545     matrix.setScaleY(yScale);
546     dst.setEmpty();
547     success = orig.transform(matrix, &dst);
548     REPORTER_ASSERT(reporter, success);
549     // Radii are scaled.
550     for (int i = 0; i < 4; ++i) {
551         REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.radii((SkRRect::Corner) i).fX,
552                                     SkScalarMul(orig.radii((SkRRect::Corner) i).fX, xScale)));
553         REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.radii((SkRRect::Corner) i).fY,
554                                     SkScalarMul(orig.radii((SkRRect::Corner) i).fY, yScale)));
555     }
556     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().width(),
557                                                   SkScalarMul(orig.rect().width(), xScale)));
558     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().height(),
559                                                   SkScalarMul(orig.rect().height(), yScale)));
560     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().left(),
561                                                   SkScalarMul(orig.rect().left(), xScale)));
562     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().top(),
563                                                   SkScalarMul(orig.rect().top(), yScale)));
564 }
565 
test_round_rect_transform(skiatest::Reporter * reporter)566 static void test_round_rect_transform(skiatest::Reporter* reporter) {
567     SkRRect rrect;
568     {
569         SkRect r = { 0, 0, kWidth, kHeight };
570         rrect.setRectXY(r, SkIntToScalar(4), SkIntToScalar(7));
571         test_transform_helper(reporter, rrect);
572     }
573     {
574         SkRect r = { SkIntToScalar(5), SkIntToScalar(15),
575                      SkIntToScalar(27), SkIntToScalar(34) };
576         SkVector radii[4] = { { 0, SkIntToScalar(1) },
577                               { SkIntToScalar(2), SkIntToScalar(3) },
578                               { SkIntToScalar(4), SkIntToScalar(5) },
579                               { SkIntToScalar(6), SkIntToScalar(7) } };
580         rrect.setRectRadii(r, radii);
581         test_transform_helper(reporter, rrect);
582     }
583 }
584 
DEF_TEST(RoundRect,reporter)585 DEF_TEST(RoundRect, reporter) {
586     test_round_rect_basic(reporter);
587     test_round_rect_rects(reporter);
588     test_round_rect_ovals(reporter);
589     test_round_rect_general(reporter);
590     test_round_rect_iffy_parameters(reporter);
591     test_inset(reporter);
592     test_round_rect_contains_rect(reporter);
593     test_round_rect_transform(reporter);
594 }
595