2 * Copyright 2012 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
12 static const SkScalar kWidth = 100.0f;
13 static const SkScalar kHeight = 100.0f;
15 static void test_inset(skiatest::Reporter* reporter) {
17 SkRect r = { 0, 0, 100, 100 };
20 rr.inset(-20, -20, &rr2);
21 REPORTER_ASSERT(reporter, rr2.isRect());
23 rr.inset(20, 20, &rr2);
24 REPORTER_ASSERT(reporter, rr2.isRect());
26 rr.inset(r.width()/2, r.height()/2, &rr2);
27 REPORTER_ASSERT(reporter, rr2.isEmpty());
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());
36 // Test out the basic API entry points
37 static void test_round_rect_basic(skiatest::Reporter* reporter) {
38 // Test out initialization methods
39 SkPoint zeroPt = { 0, 0 };
44 REPORTER_ASSERT(reporter, SkRRect::kEmpty_Type == empty.type());
45 REPORTER_ASSERT(reporter, empty.rect().isEmpty());
47 for (int i = 0; i < 4; ++i) {
48 REPORTER_ASSERT(reporter, zeroPt == empty.radii((SkRRect::Corner) i));
52 SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
57 REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr1.type());
58 REPORTER_ASSERT(reporter, rr1.rect() == rect);
60 for (int i = 0; i < 4; ++i) {
61 REPORTER_ASSERT(reporter, zeroPt == rr1.radii((SkRRect::Corner) i));
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());
72 SkPoint halfPoint = { SkScalarHalf(kWidth), SkScalarHalf(kHeight) };
76 REPORTER_ASSERT(reporter, SkRRect::kOval_Type == rr2.type());
77 REPORTER_ASSERT(reporter, rr2.rect() == rect);
79 for (int i = 0; i < 4; ++i) {
80 REPORTER_ASSERT(reporter,
81 rr2.radii((SkRRect::Corner) i).equalsWithinTolerance(halfPoint));
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());
95 rr3.setRectXY(rect, p.fX, p.fY);
97 REPORTER_ASSERT(reporter, SkRRect::kSimple_Type == rr3.type());
98 REPORTER_ASSERT(reporter, rr3.rect() == rect);
100 for (int i = 0; i < 4; ++i) {
101 REPORTER_ASSERT(reporter, p == rr3.radii((SkRRect::Corner) i));
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());
112 SkRect ninePatchRadii = { 10, 9, 8, 7 };
115 rr4.setNinePatch(rect, ninePatchRadii.fLeft, ninePatchRadii.fTop, ninePatchRadii.fRight,
116 ninePatchRadii.fBottom);
118 REPORTER_ASSERT(reporter, SkRRect::kNinePatch_Type == rr4.type());
119 REPORTER_ASSERT(reporter, rr4.rect() == rect);
122 ninePatchRadii.toQuad(rquad);
123 for (int i = 0; i < 4; ++i) {
124 REPORTER_ASSERT(reporter, rquad[i] == rr4.radii((SkRRect::Corner) i));
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());
132 SkPoint radii2[4] = { { 0, 0 }, { 0, 0 }, { 50, 50 }, { 20, 50 } };
135 rr5.setRectRadii(rect, radii2);
137 REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr5.type());
138 REPORTER_ASSERT(reporter, rr5.rect() == rect);
140 for (int i = 0; i < 4; ++i) {
141 REPORTER_ASSERT(reporter, radii2[i] == rr5.radii((SkRRect::Corner) i));
145 REPORTER_ASSERT(reporter, empty != rr3);
146 REPORTER_ASSERT(reporter, rr3 != rr4);
147 REPORTER_ASSERT(reporter, rr4 != rr5);
150 // Test out the cases when the RR degenerates to a rect
151 static void test_round_rect_rects(skiatest::Reporter* reporter) {
159 REPORTER_ASSERT(reporter, SkRRect::kEmpty_Type == empty.type());
161 REPORTER_ASSERT(reporter, 0 == r.fLeft && 0 == r.fTop && 0 == r.fRight && 0 == r.fBottom);
164 SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
166 rr1.setRectXY(rect, 0, 0);
168 REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr1.type());
170 REPORTER_ASSERT(reporter, rect == r);
173 SkPoint radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
176 rr2.setRectRadii(rect, radii);
178 REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr2.type());
180 REPORTER_ASSERT(reporter, rect == r);
183 SkPoint radii2[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } };
186 rr3.setRectRadii(rect, radii2);
187 REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr3.type());
190 // Test out the cases when the RR degenerates to an oval
191 static void test_round_rect_ovals(skiatest::Reporter* reporter) {
194 SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
196 rr1.setRectXY(rect, SkScalarHalf(kWidth), SkScalarHalf(kHeight));
198 REPORTER_ASSERT(reporter, SkRRect::kOval_Type == rr1.type());
200 REPORTER_ASSERT(reporter, oval == rect);
203 // Test out the non-degenerate RR cases
204 static void test_round_rect_general(skiatest::Reporter* reporter) {
206 SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
208 rr1.setRectXY(rect, 20, 20);
210 REPORTER_ASSERT(reporter, SkRRect::kSimple_Type == rr1.type());
213 SkPoint radii[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } };
216 rr2.setRectRadii(rect, radii);
218 REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr2.type());
221 // Test out questionable-parameter handling
222 static void test_round_rect_iffy_parameters(skiatest::Reporter* reporter) {
224 // When the radii exceed the base rect they are proportionally scaled down
226 SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
227 SkPoint radii[4] = { { 50, 100 }, { 100, 50 }, { 50, 100 }, { 100, 50 } };
230 rr1.setRectRadii(rect, radii);
232 REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr1.type());
234 const SkPoint& p = rr1.radii(SkRRect::kUpperLeft_Corner);
236 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.fX, 33.33333f));
237 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.fY, 66.66666f));
239 // Negative radii should be capped at zero
241 rr2.setRectXY(rect, -10, -20);
243 REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr2.type());
245 const SkPoint& p2 = rr2.radii(SkRRect::kUpperLeft_Corner);
247 REPORTER_ASSERT(reporter, 0.0f == p2.fX);
248 REPORTER_ASSERT(reporter, 0.0f == p2.fY);
251 // Move a small box from the start position by (stepX, stepY) 'numSteps' times
252 // testing for containment in 'rr' at each step.
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);
263 REPORTER_ASSERT(reporter, contains[i] == rr.contains(test));
270 // Exercise the RR's contains rect method
271 static void test_round_rect_contains_rect(skiatest::Reporter* reporter) {
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
281 SkRRect rrects[kNumRRects];
282 for (int i = 0; i < kNumRRects; ++i) {
283 rrects[i].setRectRadii(SkRect::MakeWH(40, 40), gRadii[i]);
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
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]));
305 // Now test non-trivial containment. For each compass
306 // point walk a 1x1 rect in from the edge of the bounding
308 static const int kNumSteps = 15;
309 bool answers[kNumRRects][8][kNumSteps] = {
310 // all the test rects are inside the degenerate rrect
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 },
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
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 },
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
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 },
351 // for the complex case the answer is different for each direction
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 },
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
385 // Called for a matrix that should cause SkRRect::transform to fail.
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());
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);
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)
415 // Called to test various transforms on a single SkRRect.
416 static void test_transform_helper(skiatest::Reporter* reporter, const SkRRect& orig) {
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);
425 // Skew and Perspective make transform fail.
428 matrix.setSkewX(SkIntToScalar(2));
429 assert_transform_failure(reporter, orig, matrix);
432 matrix.setSkewY(SkIntToScalar(3));
433 assert_transform_failure(reporter, orig, matrix);
436 matrix.setPerspX(SkScalarToPersp(SkIntToScalar(4)));
437 assert_transform_failure(reporter, orig, matrix);
440 matrix.setPerspY(SkScalarToPersp(SkIntToScalar(5)));
441 assert_transform_failure(reporter, orig, matrix);
445 matrix.setRotate(SkIntToScalar(90));
446 assert_transform_failure(reporter, orig, matrix);
447 matrix.setRotate(SkIntToScalar(37));
448 assert_transform_failure(reporter, orig, matrix);
450 // Translate will keep the rect moved, but otherwise the same.
452 SkScalar translateX = SkIntToScalar(32);
453 SkScalar translateY = SkIntToScalar(15);
454 matrix.setTranslateX(translateX);
455 matrix.setTranslateY(translateY);
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));
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);
468 // Keeping the translation, but adding skew will make transform fail.
469 matrix.setSkewY(SkIntToScalar(7));
470 assert_transform_failure(reporter, orig, matrix);
472 // Scaling in -x will flip the round rect horizontally.
474 matrix.setScaleX(SkIntToScalar(-1));
476 success = orig.transform(matrix, &dst);
477 REPORTER_ASSERT(reporter, success);
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);
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());
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);
498 // Scaling in -y will flip the round rect vertically.
500 matrix.setScaleY(SkIntToScalar(-1));
502 success = orig.transform(matrix, &dst);
503 REPORTER_ASSERT(reporter, success);
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);
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());
520 // Scaling in -x and -y will swap in both directions.
522 matrix.setScaleY(SkIntToScalar(-1));
523 matrix.setScaleX(SkIntToScalar(-1));
525 success = orig.transform(matrix, &dst);
526 REPORTER_ASSERT(reporter, success);
529 REPORTER_ASSERT(reporter, origUL == dstLR);
530 REPORTER_ASSERT(reporter, origUR == dstLL);
531 REPORTER_ASSERT(reporter, origLR == dstUL);
532 REPORTER_ASSERT(reporter, origLL == dstUR);
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());
540 // Scale in both directions.
541 SkScalar xScale = SkIntToScalar(3);
542 SkScalar yScale = 3.2f;
544 matrix.setScaleX(xScale);
545 matrix.setScaleY(yScale);
547 success = orig.transform(matrix, &dst);
548 REPORTER_ASSERT(reporter, success);
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)));
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)));
566 static void test_round_rect_transform(skiatest::Reporter* reporter) {
569 SkRect r = { 0, 0, kWidth, kHeight };
570 rrect.setRectXY(r, SkIntToScalar(4), SkIntToScalar(7));
571 test_transform_helper(reporter, rrect);
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);
585 // Test out the case where an oval already off in space is translated/scaled
586 // further off into space - yielding numerical issues when the rect & radii
587 // are transformed separatly
589 static void test_issue_2696(skiatest::Reporter* reporter) {
591 SkRect r = { 28443.8594f, 53.1428604f, 28446.7148f, 56.0000038f };
595 xform.setAll(2.44f, 0.0f, 485411.7f,
596 0.0f, 2.44f, -438.7f,
600 bool success = rrect.transform(xform, &dst);
601 REPORTER_ASSERT(reporter, success);
603 SkScalar halfWidth = SkScalarHalf(dst.width());
604 SkScalar halfHeight = SkScalarHalf(dst.height());
606 for (int i = 0; i < 4; ++i) {
607 REPORTER_ASSERT(reporter,
608 SkScalarNearlyEqual(dst.radii((SkRRect::Corner)i).fX, halfWidth));
609 REPORTER_ASSERT(reporter,
610 SkScalarNearlyEqual(dst.radii((SkRRect::Corner)i).fY, halfHeight));
614 DEF_TEST(RoundRect, reporter) {
615 test_round_rect_basic(reporter);
616 test_round_rect_rects(reporter);
617 test_round_rect_ovals(reporter);
618 test_round_rect_general(reporter);
619 test_round_rect_iffy_parameters(reporter);
620 test_inset(reporter);
621 test_round_rect_contains_rect(reporter);
622 test_round_rect_transform(reporter);
623 test_issue_2696(reporter);