• 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 "include/core/SkMatrix.h"
9 #include "include/core/SkRRect.h"
10 #include "src/core/SkPointPriv.h"
11 #include "tests/Test.h"
12 
test_tricky_radii(skiatest::Reporter * reporter)13 static void test_tricky_radii(skiatest::Reporter* reporter) {
14     {
15         // crbug.com/458522
16         SkRRect rr;
17         const SkRect bounds = { 3709, 3709, 3709 + 7402, 3709 + 29825 };
18         const SkScalar rad = 12814;
19         const SkVector vec[] = { { rad, rad }, { 0, rad }, { rad, rad }, { 0, rad } };
20         rr.setRectRadii(bounds, vec);
21     }
22 
23     {
24         // crbug.com//463920
25         SkRect r = SkRect::MakeLTRB(0, 0, 1009, 33554432.0);
26         SkVector radii[4] = {
27             { 13.0f, 8.0f }, { 170.0f, 2.0 }, { 256.0f, 33554432.0 }, { 110.0f, 5.0f }
28         };
29         SkRRect rr;
30         rr.setRectRadii(r, radii);
31 
32         REPORTER_ASSERT(reporter, (double) rr.radii(SkRRect::kUpperRight_Corner).fY +
33                                   (double) rr.radii(SkRRect::kLowerRight_Corner).fY <=
34                                   rr.height());
35     }
36 }
37 
test_empty_crbug_458524(skiatest::Reporter * reporter)38 static void test_empty_crbug_458524(skiatest::Reporter* reporter) {
39     SkRRect rr;
40     const SkRect bounds = { 3709, 3709, 3709 + 7402, 3709 + 29825 };
41     const SkScalar rad = 40;
42     rr.setRectXY(bounds, rad, rad);
43 
44     SkRRect other;
45     SkMatrix matrix;
46     matrix.setScale(0, 1);
47     rr.transform(matrix, &other);
48     REPORTER_ASSERT(reporter, SkRRect::kEmpty_Type == other.getType());
49 }
50 
51 // Test that all the SkRRect entry points correctly handle un-sorted and
52 // zero-sized input rects
test_empty(skiatest::Reporter * reporter)53 static void test_empty(skiatest::Reporter* reporter) {
54     static const SkRect oooRects[] = {  // out of order
55         { 100, 0, 0, 100 },  // ooo horizontal
56         { 0, 100, 100, 0 },  // ooo vertical
57         { 100, 100, 0, 0 },  // ooo both
58     };
59 
60     static const SkRect emptyRects[] = {
61         { 100, 100, 100, 200 }, // empty horizontal
62         { 100, 100, 200, 100 }, // empty vertical
63         { 100, 100, 100, 100 }, // empty both
64         { 0, 0, 0, 0 }          // setEmpty-empty
65     };
66 
67     static const SkVector radii[4] = { { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 } };
68 
69     SkRRect r;
70 
71     for (size_t i = 0; i < SK_ARRAY_COUNT(oooRects); ++i) {
72         r.setRect(oooRects[i]);
73         REPORTER_ASSERT(reporter, !r.isEmpty());
74         REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
75 
76         r.setOval(oooRects[i]);
77         REPORTER_ASSERT(reporter, !r.isEmpty());
78         REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
79 
80         r.setRectXY(oooRects[i], 1, 2);
81         REPORTER_ASSERT(reporter, !r.isEmpty());
82         REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
83 
84         r.setNinePatch(oooRects[i], 0, 1, 2, 3);
85         REPORTER_ASSERT(reporter, !r.isEmpty());
86         REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
87 
88         r.setRectRadii(oooRects[i], radii);
89         REPORTER_ASSERT(reporter, !r.isEmpty());
90         REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
91     }
92 
93     for (size_t i = 0; i < SK_ARRAY_COUNT(emptyRects); ++i) {
94         r.setRect(emptyRects[i]);
95         REPORTER_ASSERT(reporter, r.isEmpty());
96         REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
97 
98         r.setOval(emptyRects[i]);
99         REPORTER_ASSERT(reporter, r.isEmpty());
100         REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
101 
102         r.setRectXY(emptyRects[i], 1, 2);
103         REPORTER_ASSERT(reporter, r.isEmpty());
104         REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
105 
106         r.setNinePatch(emptyRects[i], 0, 1, 2, 3);
107         REPORTER_ASSERT(reporter, r.isEmpty());
108         REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
109 
110         r.setRectRadii(emptyRects[i], radii);
111         REPORTER_ASSERT(reporter, r.isEmpty());
112         REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
113     }
114 
115     r.setRect({SK_ScalarNaN, 10, 10, 20});
116     REPORTER_ASSERT(reporter, r == SkRRect::MakeEmpty());
117     r.setRect({0, 10, 10, SK_ScalarInfinity});
118     REPORTER_ASSERT(reporter, r == SkRRect::MakeEmpty());
119 }
120 
121 static const SkScalar kWidth = 100.0f;
122 static const SkScalar kHeight = 100.0f;
123 
test_inset(skiatest::Reporter * reporter)124 static void test_inset(skiatest::Reporter* reporter) {
125     SkRRect rr, rr2;
126     SkRect r = { 0, 0, 100, 100 };
127 
128     rr.setRect(r);
129     rr.inset(-20, -20, &rr2);
130     REPORTER_ASSERT(reporter, rr2.isRect());
131 
132     rr.inset(20, 20, &rr2);
133     REPORTER_ASSERT(reporter, rr2.isRect());
134 
135     rr.inset(r.width()/2, r.height()/2, &rr2);
136     REPORTER_ASSERT(reporter, rr2.isEmpty());
137 
138     rr.setRectXY(r, 20, 20);
139     rr.inset(19, 19, &rr2);
140     REPORTER_ASSERT(reporter, rr2.isSimple());
141     rr.inset(20, 20, &rr2);
142     REPORTER_ASSERT(reporter, rr2.isRect());
143 }
144 
145 
test_9patch_rrect(skiatest::Reporter * reporter,const SkRect & rect,SkScalar l,SkScalar t,SkScalar r,SkScalar b,bool checkRadii)146 static void test_9patch_rrect(skiatest::Reporter* reporter,
147                               const SkRect& rect,
148                               SkScalar l, SkScalar t, SkScalar r, SkScalar b,
149                               bool checkRadii) {
150     SkRRect rr;
151     rr.setNinePatch(rect, l, t, r, b);
152 
153     REPORTER_ASSERT(reporter, SkRRect::kNinePatch_Type == rr.type());
154     REPORTER_ASSERT(reporter, rr.rect() == rect);
155 
156     if (checkRadii) {
157         // This test doesn't hold if the radii will be rescaled by SkRRect
158         SkRect ninePatchRadii = { l, t, r, b };
159         SkPoint rquad[4];
160         ninePatchRadii.toQuad(rquad);
161         for (int i = 0; i < 4; ++i) {
162             REPORTER_ASSERT(reporter, rquad[i] == rr.radii((SkRRect::Corner) i));
163         }
164     }
165     SkRRect rr2; // construct the same RR using the most general set function
166     SkVector radii[4] = { { l, t }, { r, t }, { r, b }, { l, b } };
167     rr2.setRectRadii(rect, radii);
168     REPORTER_ASSERT(reporter, rr2 == rr && rr2.getType() == rr.getType());
169 }
170 
171 // Test out the basic API entry points
test_round_rect_basic(skiatest::Reporter * reporter)172 static void test_round_rect_basic(skiatest::Reporter* reporter) {
173     // Test out initialization methods
174     SkPoint zeroPt = { 0, 0 };
175     SkRRect empty;
176 
177     empty.setEmpty();
178 
179     REPORTER_ASSERT(reporter, SkRRect::kEmpty_Type == empty.type());
180     REPORTER_ASSERT(reporter, empty.rect().isEmpty());
181 
182     for (int i = 0; i < 4; ++i) {
183         REPORTER_ASSERT(reporter, zeroPt == empty.radii((SkRRect::Corner) i));
184     }
185 
186     //----
187     SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
188 
189     SkRRect rr1;
190     rr1.setRect(rect);
191 
192     REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr1.type());
193     REPORTER_ASSERT(reporter, rr1.rect() == rect);
194 
195     for (int i = 0; i < 4; ++i) {
196         REPORTER_ASSERT(reporter, zeroPt == rr1.radii((SkRRect::Corner) i));
197     }
198     SkRRect rr1_2; // construct the same RR using the most general set function
199     SkVector rr1_2_radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
200     rr1_2.setRectRadii(rect, rr1_2_radii);
201     REPORTER_ASSERT(reporter, rr1_2 == rr1 && rr1_2.getType() == rr1.getType());
202     SkRRect rr1_3;  // construct the same RR using the nine patch set function
203     rr1_3.setNinePatch(rect, 0, 0, 0, 0);
204     REPORTER_ASSERT(reporter, rr1_3 == rr1 && rr1_3.getType() == rr1.getType());
205 
206     //----
207     SkPoint halfPoint = { SkScalarHalf(kWidth), SkScalarHalf(kHeight) };
208     SkRRect rr2;
209     rr2.setOval(rect);
210 
211     REPORTER_ASSERT(reporter, SkRRect::kOval_Type == rr2.type());
212     REPORTER_ASSERT(reporter, rr2.rect() == rect);
213 
214     for (int i = 0; i < 4; ++i) {
215         REPORTER_ASSERT(reporter,
216                         SkPointPriv::EqualsWithinTolerance(rr2.radii((SkRRect::Corner) i),
217                         halfPoint));
218     }
219     SkRRect rr2_2;  // construct the same RR using the most general set function
220     SkVector rr2_2_radii[4] = { { halfPoint.fX, halfPoint.fY }, { halfPoint.fX, halfPoint.fY },
221                                 { halfPoint.fX, halfPoint.fY }, { halfPoint.fX, halfPoint.fY } };
222     rr2_2.setRectRadii(rect, rr2_2_radii);
223     REPORTER_ASSERT(reporter, rr2_2 == rr2 && rr2_2.getType() == rr2.getType());
224     SkRRect rr2_3;  // construct the same RR using the nine patch set function
225     rr2_3.setNinePatch(rect, halfPoint.fX, halfPoint.fY, halfPoint.fX, halfPoint.fY);
226     REPORTER_ASSERT(reporter, rr2_3 == rr2 && rr2_3.getType() == rr2.getType());
227 
228     //----
229     SkPoint p = { 5, 5 };
230     SkRRect rr3;
231     rr3.setRectXY(rect, p.fX, p.fY);
232 
233     REPORTER_ASSERT(reporter, SkRRect::kSimple_Type == rr3.type());
234     REPORTER_ASSERT(reporter, rr3.rect() == rect);
235 
236     for (int i = 0; i < 4; ++i) {
237         REPORTER_ASSERT(reporter, p == rr3.radii((SkRRect::Corner) i));
238     }
239     SkRRect rr3_2; // construct the same RR using the most general set function
240     SkVector rr3_2_radii[4] = { { 5, 5 }, { 5, 5 }, { 5, 5 }, { 5, 5 } };
241     rr3_2.setRectRadii(rect, rr3_2_radii);
242     REPORTER_ASSERT(reporter, rr3_2 == rr3 && rr3_2.getType() == rr3.getType());
243     SkRRect rr3_3;  // construct the same RR using the nine patch set function
244     rr3_3.setNinePatch(rect, 5, 5, 5, 5);
245     REPORTER_ASSERT(reporter, rr3_3 == rr3 && rr3_3.getType() == rr3.getType());
246 
247     //----
248     test_9patch_rrect(reporter, rect, 10, 9, 8, 7, true);
249 
250     {
251         // Test out the rrect from skia:3466
252         SkRect rect2 = SkRect::MakeLTRB(0.358211994f, 0.755430222f, 0.872866154f, 0.806214333f);
253 
254         test_9patch_rrect(reporter,
255                           rect2,
256                           0.926942348f, 0.642850280f, 0.529063463f, 0.587844372f,
257                           false);
258     }
259 
260     //----
261     SkPoint radii2[4] = { { 0, 0 }, { 0, 0 }, { 50, 50 }, { 20, 50 } };
262 
263     SkRRect rr5;
264     rr5.setRectRadii(rect, radii2);
265 
266     REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr5.type());
267     REPORTER_ASSERT(reporter, rr5.rect() == rect);
268 
269     for (int i = 0; i < 4; ++i) {
270         REPORTER_ASSERT(reporter, radii2[i] == rr5.radii((SkRRect::Corner) i));
271     }
272 
273     // Test out == & !=
274     REPORTER_ASSERT(reporter, empty != rr3);
275     REPORTER_ASSERT(reporter, rr3 != rr5);
276 }
277 
278 // Test out the cases when the RR degenerates to a rect
test_round_rect_rects(skiatest::Reporter * reporter)279 static void test_round_rect_rects(skiatest::Reporter* reporter) {
280     SkRect r;
281 
282     //----
283     SkRRect empty;
284 
285     empty.setEmpty();
286 
287     REPORTER_ASSERT(reporter, SkRRect::kEmpty_Type == empty.type());
288     r = empty.rect();
289     REPORTER_ASSERT(reporter, 0 == r.fLeft && 0 == r.fTop && 0 == r.fRight && 0 == r.fBottom);
290 
291     //----
292     SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
293     SkRRect rr1;
294     rr1.setRectXY(rect, 0, 0);
295 
296     REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr1.type());
297     r = rr1.rect();
298     REPORTER_ASSERT(reporter, rect == r);
299 
300     //----
301     SkPoint radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
302 
303     SkRRect rr2;
304     rr2.setRectRadii(rect, radii);
305 
306     REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr2.type());
307     r = rr2.rect();
308     REPORTER_ASSERT(reporter, rect == r);
309 
310     //----
311     SkPoint radii2[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } };
312 
313     SkRRect rr3;
314     rr3.setRectRadii(rect, radii2);
315     REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr3.type());
316 }
317 
318 // Test out the cases when the RR degenerates to an oval
test_round_rect_ovals(skiatest::Reporter * reporter)319 static void test_round_rect_ovals(skiatest::Reporter* reporter) {
320     //----
321     SkRect oval;
322     SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
323     SkRRect rr1;
324     rr1.setRectXY(rect, SkScalarHalf(kWidth), SkScalarHalf(kHeight));
325 
326     REPORTER_ASSERT(reporter, SkRRect::kOval_Type == rr1.type());
327     oval = rr1.rect();
328     REPORTER_ASSERT(reporter, oval == rect);
329 }
330 
331 // Test out the non-degenerate RR cases
test_round_rect_general(skiatest::Reporter * reporter)332 static void test_round_rect_general(skiatest::Reporter* reporter) {
333     //----
334     SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
335     SkRRect rr1;
336     rr1.setRectXY(rect, 20, 20);
337 
338     REPORTER_ASSERT(reporter, SkRRect::kSimple_Type == rr1.type());
339 
340     //----
341     SkPoint radii[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } };
342 
343     SkRRect rr2;
344     rr2.setRectRadii(rect, radii);
345 
346     REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr2.type());
347 }
348 
349 // Test out questionable-parameter handling
test_round_rect_iffy_parameters(skiatest::Reporter * reporter)350 static void test_round_rect_iffy_parameters(skiatest::Reporter* reporter) {
351 
352     // When the radii exceed the base rect they are proportionally scaled down
353     // to fit
354     SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
355     SkPoint radii[4] = { { 50, 100 }, { 100, 50 }, { 50, 100 }, { 100, 50 } };
356 
357     SkRRect rr1;
358     rr1.setRectRadii(rect, radii);
359 
360     REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr1.type());
361 
362     const SkPoint& p = rr1.radii(SkRRect::kUpperLeft_Corner);
363 
364     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.fX, 33.33333f));
365     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(p.fY, 66.66666f));
366 
367     // Negative radii should be capped at zero
368     SkRRect rr2;
369     rr2.setRectXY(rect, -10, -20);
370 
371     REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr2.type());
372 
373     const SkPoint& p2 = rr2.radii(SkRRect::kUpperLeft_Corner);
374 
375     REPORTER_ASSERT(reporter, 0.0f == p2.fX);
376     REPORTER_ASSERT(reporter, 0.0f == p2.fY);
377 }
378 
379 // Move a small box from the start position by (stepX, stepY) 'numSteps' times
380 // 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)381 static void test_direction(skiatest::Reporter* reporter, const SkRRect &rr,
382                            SkScalar initX, int stepX, SkScalar initY, int stepY,
383                            int numSteps, const bool* contains) {
384     SkScalar x = initX, y = initY;
385     for (int i = 0; i < numSteps; ++i) {
386         SkRect test = SkRect::MakeXYWH(x, y,
387                                        stepX ? SkIntToScalar(stepX) : SK_Scalar1,
388                                        stepY ? SkIntToScalar(stepY) : SK_Scalar1);
389         test.sort();
390 
391         REPORTER_ASSERT(reporter, contains[i] == rr.contains(test));
392 
393         x += stepX;
394         y += stepY;
395     }
396 }
397 
398 // Exercise the RR's contains rect method
test_round_rect_contains_rect(skiatest::Reporter * reporter)399 static void test_round_rect_contains_rect(skiatest::Reporter* reporter) {
400 
401     static const int kNumRRects = 4;
402     static const SkVector gRadii[kNumRRects][4] = {
403         { {  0,  0 }, {  0,  0 }, {  0,  0 }, {  0,  0 } },  // rect
404         { { 20, 20 }, { 20, 20 }, { 20, 20 }, { 20, 20 } },  // circle
405         { { 10, 10 }, { 10, 10 }, { 10, 10 }, { 10, 10 } },  // simple
406         { {  0,  0 }, { 20, 20 }, { 10, 10 }, { 30, 30 } }   // complex
407     };
408 
409     SkRRect rrects[kNumRRects];
410     for (int i = 0; i < kNumRRects; ++i) {
411         rrects[i].setRectRadii(SkRect::MakeWH(40, 40), gRadii[i]);
412     }
413 
414     // First test easy outs - boxes that are obviously out on
415     // each corner and edge
416     static const SkRect easyOuts[] = {
417         { -5, -5,  5,  5 }, // NW
418         { 15, -5, 20,  5 }, // N
419         { 35, -5, 45,  5 }, // NE
420         { 35, 15, 45, 20 }, // E
421         { 35, 45, 35, 45 }, // SE
422         { 15, 35, 20, 45 }, // S
423         { -5, 35,  5, 45 }, // SW
424         { -5, 15,  5, 20 }  // W
425     };
426 
427     for (int i = 0; i < kNumRRects; ++i) {
428         for (size_t j = 0; j < SK_ARRAY_COUNT(easyOuts); ++j) {
429             REPORTER_ASSERT(reporter, !rrects[i].contains(easyOuts[j]));
430         }
431     }
432 
433     // Now test non-trivial containment. For each compass
434     // point walk a 1x1 rect in from the edge  of the bounding
435     // rect
436     static const int kNumSteps = 15;
437     bool answers[kNumRRects][8][kNumSteps] = {
438         // all the test rects are inside the degenerate rrect
439         {
440             // rect
441             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
442             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
443             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
444             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
445             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
446             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
447             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
448             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
449         },
450         // for the circle we expect 6 blocks to be out on the
451         // corners (then the rest in) and only the first block
452         // out on the vertical and horizontal axes (then
453         // the rest in)
454         {
455             // circle
456             { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
457             { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
458             { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
459             { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
460             { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
461             { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
462             { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
463             { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
464         },
465         // for the simple round rect we expect 3 out on
466         // the corners (then the rest in) and no blocks out
467         // on the vertical and horizontal axes
468         {
469             // simple RR
470             { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
471             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
472             { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
473             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
474             { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
475             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
476             { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
477             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
478         },
479         // for the complex case the answer is different for each direction
480         {
481             // complex RR
482             // all in for NW (rect) corner (same as rect case)
483             { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
484             // only first block out for N (same as circle case)
485             { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
486             // first 6 blocks out for NE (same as circle case)
487             { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
488             // only first block out for E (same as circle case)
489             { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
490             // first 3 blocks out for SE (same as simple case)
491             { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
492             // first two blocks out for S
493             { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
494             // first 9 blocks out for SW
495             { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1 },
496             // first two blocks out for W (same as S)
497             { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
498          }
499     };
500 
501     for (int i = 0; i < kNumRRects; ++i) {
502         test_direction(reporter, rrects[i],     0,  1,     0,  1, kNumSteps, answers[i][0]); // NW
503         test_direction(reporter, rrects[i], 19.5f,  0,     0,  1, kNumSteps, answers[i][1]); // N
504         test_direction(reporter, rrects[i],    40, -1,     0,  1, kNumSteps, answers[i][2]); // NE
505         test_direction(reporter, rrects[i],    40, -1, 19.5f,  0, kNumSteps, answers[i][3]); // E
506         test_direction(reporter, rrects[i],    40, -1,    40, -1, kNumSteps, answers[i][4]); // SE
507         test_direction(reporter, rrects[i], 19.5f,  0,    40, -1, kNumSteps, answers[i][5]); // S
508         test_direction(reporter, rrects[i],     0,  1,    40, -1, kNumSteps, answers[i][6]); // SW
509         test_direction(reporter, rrects[i],     0,  1, 19.5f,  0, kNumSteps, answers[i][7]); // W
510     }
511 }
512 
513 // Called for a matrix that should cause SkRRect::transform to fail.
assert_transform_failure(skiatest::Reporter * reporter,const SkRRect & orig,const SkMatrix & matrix)514 static void assert_transform_failure(skiatest::Reporter* reporter, const SkRRect& orig,
515                                      const SkMatrix& matrix) {
516     // The test depends on the fact that the original is not empty.
517     SkASSERT(!orig.isEmpty());
518     SkRRect dst;
519     dst.setEmpty();
520 
521     const SkRRect copyOfDst = dst;
522     const SkRRect copyOfOrig = orig;
523     bool success = orig.transform(matrix, &dst);
524     // This transform should fail.
525     REPORTER_ASSERT(reporter, !success);
526     // Since the transform failed, dst should be unchanged.
527     REPORTER_ASSERT(reporter, copyOfDst == dst);
528     // original should not be modified.
529     REPORTER_ASSERT(reporter, copyOfOrig == orig);
530     REPORTER_ASSERT(reporter, orig != dst);
531 }
532 
533 #define GET_RADII                                                       \
534     const SkVector& origUL = orig.radii(SkRRect::kUpperLeft_Corner);    \
535     const SkVector& origUR = orig.radii(SkRRect::kUpperRight_Corner);   \
536     const SkVector& origLR = orig.radii(SkRRect::kLowerRight_Corner);   \
537     const SkVector& origLL = orig.radii(SkRRect::kLowerLeft_Corner);    \
538     const SkVector& dstUL = dst.radii(SkRRect::kUpperLeft_Corner);      \
539     const SkVector& dstUR = dst.radii(SkRRect::kUpperRight_Corner);     \
540     const SkVector& dstLR = dst.radii(SkRRect::kLowerRight_Corner);     \
541     const SkVector& dstLL = dst.radii(SkRRect::kLowerLeft_Corner)
542 
543 // Called to test various transforms on a single SkRRect.
test_transform_helper(skiatest::Reporter * reporter,const SkRRect & orig)544 static void test_transform_helper(skiatest::Reporter* reporter, const SkRRect& orig) {
545     SkRRect dst;
546     dst.setEmpty();
547 
548     // The identity matrix will duplicate the rrect.
549     bool success = orig.transform(SkMatrix::I(), &dst);
550     REPORTER_ASSERT(reporter, success);
551     REPORTER_ASSERT(reporter, orig == dst);
552 
553     // Skew and Perspective make transform fail.
554     SkMatrix matrix;
555     matrix.reset();
556     matrix.setSkewX(SkIntToScalar(2));
557     assert_transform_failure(reporter, orig, matrix);
558 
559     matrix.reset();
560     matrix.setSkewY(SkIntToScalar(3));
561     assert_transform_failure(reporter, orig, matrix);
562 
563     matrix.reset();
564     matrix.setPerspX(4);
565     assert_transform_failure(reporter, orig, matrix);
566 
567     matrix.reset();
568     matrix.setPerspY(5);
569     assert_transform_failure(reporter, orig, matrix);
570 
571     // Rotation fails.
572     matrix.reset();
573     matrix.setRotate(SkIntToScalar(37));
574     assert_transform_failure(reporter, orig, matrix);
575 
576     // Translate will keep the rect moved, but otherwise the same.
577     matrix.reset();
578     SkScalar translateX = SkIntToScalar(32);
579     SkScalar translateY = SkIntToScalar(15);
580     matrix.setTranslateX(translateX);
581     matrix.setTranslateY(translateY);
582     dst.setEmpty();
583     success = orig.transform(matrix, &dst);
584     REPORTER_ASSERT(reporter, success);
585     for (int i = 0; i < 4; ++i) {
586         REPORTER_ASSERT(reporter,
587                 orig.radii((SkRRect::Corner) i) == dst.radii((SkRRect::Corner) i));
588     }
589     REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
590     REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
591     REPORTER_ASSERT(reporter, dst.rect().left() == orig.rect().left() + translateX);
592     REPORTER_ASSERT(reporter, dst.rect().top() == orig.rect().top() + translateY);
593 
594     // Keeping the translation, but adding skew will make transform fail.
595     matrix.setSkewY(SkIntToScalar(7));
596     assert_transform_failure(reporter, orig, matrix);
597 
598     // Scaling in -x will flip the round rect horizontally.
599     matrix.reset();
600     matrix.setScaleX(SkIntToScalar(-1));
601     dst.setEmpty();
602     success = orig.transform(matrix, &dst);
603     REPORTER_ASSERT(reporter, success);
604     {
605         GET_RADII;
606         // Radii have swapped in x.
607         REPORTER_ASSERT(reporter, origUL == dstUR);
608         REPORTER_ASSERT(reporter, origUR == dstUL);
609         REPORTER_ASSERT(reporter, origLR == dstLL);
610         REPORTER_ASSERT(reporter, origLL == dstLR);
611     }
612     // Width and height remain the same.
613     REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
614     REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
615     // Right and left have swapped (sort of)
616     REPORTER_ASSERT(reporter, orig.rect().right() == -dst.rect().left());
617     // Top has stayed the same.
618     REPORTER_ASSERT(reporter, orig.rect().top() == dst.rect().top());
619 
620     // Keeping the scale, but adding a persp will make transform fail.
621     matrix.setPerspX(7);
622     assert_transform_failure(reporter, orig, matrix);
623 
624     // Scaling in -y will flip the round rect vertically.
625     matrix.reset();
626     matrix.setScaleY(SkIntToScalar(-1));
627     dst.setEmpty();
628     success = orig.transform(matrix, &dst);
629     REPORTER_ASSERT(reporter, success);
630     {
631         GET_RADII;
632         // Radii have swapped in y.
633         REPORTER_ASSERT(reporter, origUL == dstLL);
634         REPORTER_ASSERT(reporter, origUR == dstLR);
635         REPORTER_ASSERT(reporter, origLR == dstUR);
636         REPORTER_ASSERT(reporter, origLL == dstUL);
637     }
638     // Width and height remain the same.
639     REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
640     REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
641     // Top and bottom have swapped (sort of)
642     REPORTER_ASSERT(reporter, orig.rect().top() == -dst.rect().bottom());
643     // Left has stayed the same.
644     REPORTER_ASSERT(reporter, orig.rect().left() == dst.rect().left());
645 
646     // Scaling in -x and -y will swap in both directions.
647     matrix.reset();
648     matrix.setScaleY(SkIntToScalar(-1));
649     matrix.setScaleX(SkIntToScalar(-1));
650     dst.setEmpty();
651     success = orig.transform(matrix, &dst);
652     REPORTER_ASSERT(reporter, success);
653     {
654         GET_RADII;
655         REPORTER_ASSERT(reporter, origUL == dstLR);
656         REPORTER_ASSERT(reporter, origUR == dstLL);
657         REPORTER_ASSERT(reporter, origLR == dstUL);
658         REPORTER_ASSERT(reporter, origLL == dstUR);
659     }
660     // Width and height remain the same.
661     REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
662     REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
663     REPORTER_ASSERT(reporter, orig.rect().top() == -dst.rect().bottom());
664     REPORTER_ASSERT(reporter, orig.rect().right() == -dst.rect().left());
665 
666     // Scale in both directions.
667     SkScalar xScale = SkIntToScalar(3);
668     SkScalar yScale = 3.2f;
669     matrix.reset();
670     matrix.setScaleX(xScale);
671     matrix.setScaleY(yScale);
672     dst.setEmpty();
673     success = orig.transform(matrix, &dst);
674     REPORTER_ASSERT(reporter, success);
675     // Radii are scaled.
676     for (int i = 0; i < 4; ++i) {
677         REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.radii((SkRRect::Corner) i).fX,
678                                     orig.radii((SkRRect::Corner) i).fX * xScale));
679         REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.radii((SkRRect::Corner) i).fY,
680                                     orig.radii((SkRRect::Corner) i).fY * yScale));
681     }
682     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().width(),
683                                                   orig.rect().width() * xScale));
684     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().height(),
685                                                   orig.rect().height() * yScale));
686     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().left(),
687                                                   orig.rect().left() * xScale));
688     REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().top(),
689                                                   orig.rect().top() * yScale));
690 
691 
692     //  a-----b            d-----a
693     //  |     |     ->     |     |
694     //  |     |  Rotate 90 |     |
695     //  d-----c            c-----b
696     matrix.reset();
697     matrix.setRotate(SkIntToScalar(90));
698     dst.setEmpty();
699     success = orig.transform(matrix, &dst);
700     REPORTER_ASSERT(reporter, success);
701     {
702         GET_RADII;
703         // Radii have cycled clockwise and swapped their x and y axis.
704         REPORTER_ASSERT(reporter, dstUL.x() == origLL.y());
705         REPORTER_ASSERT(reporter, dstUL.y() == origLL.x());
706         REPORTER_ASSERT(reporter, dstUR.x() == origUL.y());
707         REPORTER_ASSERT(reporter, dstUR.y() == origUL.x());
708         REPORTER_ASSERT(reporter, dstLR.x() == origUR.y());
709         REPORTER_ASSERT(reporter, dstLR.y() == origUR.x());
710         REPORTER_ASSERT(reporter, dstLL.x() == origLR.y());
711         REPORTER_ASSERT(reporter, dstLL.y() == origLR.x());
712     }
713     // Width and height would get swapped.
714     REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
715     REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
716 
717     //  a-----b        b-----a           c-----b
718     //  |     |   ->   |     |    ->     |     |
719     //  |     | Flip X |     | Rotate 90 |     |
720     //  d-----c        c-----d           d-----a
721     matrix.reset();
722     matrix.setRotate(SkIntToScalar(90));
723     matrix.postScale(SkIntToScalar(-1), SkIntToScalar(1));
724     dst.setEmpty();
725     success = orig.transform(matrix, &dst);
726     REPORTER_ASSERT(reporter, success);
727     {
728         GET_RADII;
729         REPORTER_ASSERT(reporter, dstUL.x() == origLR.y());
730         REPORTER_ASSERT(reporter, dstUL.y() == origLR.x());
731         REPORTER_ASSERT(reporter, dstUR.x() == origUR.y());
732         REPORTER_ASSERT(reporter, dstUR.y() == origUR.x());
733         REPORTER_ASSERT(reporter, dstLR.x() == origUL.y());
734         REPORTER_ASSERT(reporter, dstLR.y() == origUL.x());
735         REPORTER_ASSERT(reporter, dstLL.x() == origLL.y());
736         REPORTER_ASSERT(reporter, dstLL.y() == origLL.x());
737     }
738     // Width and height would get swapped.
739     REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
740     REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
741 
742     //  a-----b           d-----a        c-----b
743     //  |     |    ->     |     |   ->   |     |
744     //  |     | Rotate 90 |     | Flip Y |     |
745     //  d-----c           c-----b        d-----a
746     //
747     // This is the same as Flip X and Rotate 90.
748     matrix.reset();
749     matrix.setScale(SkIntToScalar(1), SkIntToScalar(-1));
750     matrix.postRotate(SkIntToScalar(90));
751     SkRRect dst2;
752     dst2.setEmpty();
753     success = orig.transform(matrix, &dst2);
754     REPORTER_ASSERT(reporter, success);
755     REPORTER_ASSERT(reporter, dst == dst2);
756 
757     //  a-----b            b-----c        c-----b
758     //  |     |     ->     |     |   ->   |     |
759     //  |     | Rotate 270 |     | Flip X |     |
760     //  d-----c            a-----d        d-----a
761     matrix.reset();
762     matrix.setScale(SkIntToScalar(-1), SkIntToScalar(1));
763     matrix.postRotate(SkIntToScalar(270));
764     dst2.setEmpty();
765     success = orig.transform(matrix, &dst2);
766     REPORTER_ASSERT(reporter, success);
767     REPORTER_ASSERT(reporter, dst == dst2);
768 
769     //  a-----b        d-----c            c-----b
770     //  |     |   ->   |     |     ->     |     |
771     //  |     | Flip Y |     | Rotate 270 |     |
772     //  d-----c        a-----b            d-----a
773     matrix.reset();
774     matrix.setRotate(SkIntToScalar(270));
775     matrix.postScale(SkIntToScalar(1), SkIntToScalar(-1));
776     dst2.setEmpty();
777     success = orig.transform(matrix, &dst2);
778     REPORTER_ASSERT(reporter, success);
779     REPORTER_ASSERT(reporter, dst == dst2);
780 
781     //  a-----b           d-----a        a-----d
782     //  |     |    ->     |     |   ->   |     |
783     //  |     | Rotate 90 |     | Flip X |     |
784     //  d-----c           c-----b        b-----c
785     matrix.reset();
786     matrix.setScale(SkIntToScalar(-1), SkIntToScalar(1));
787     matrix.postRotate(SkIntToScalar(90));
788     dst.setEmpty();
789     success = orig.transform(matrix, &dst);
790     REPORTER_ASSERT(reporter, success);
791     {
792         GET_RADII;
793         REPORTER_ASSERT(reporter, dstUL.x() == origUL.y());
794         REPORTER_ASSERT(reporter, dstUL.y() == origUL.x());
795         REPORTER_ASSERT(reporter, dstUR.x() == origLL.y());
796         REPORTER_ASSERT(reporter, dstUR.y() == origLL.x());
797         REPORTER_ASSERT(reporter, dstLR.x() == origLR.y());
798         REPORTER_ASSERT(reporter, dstLR.y() == origLR.x());
799         REPORTER_ASSERT(reporter, dstLL.x() == origUR.y());
800         REPORTER_ASSERT(reporter, dstLL.y() == origUR.x());
801     }
802     // Width and height would get swapped.
803     REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
804     REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
805 
806     //  a-----b        d-----c           a-----d
807     //  |     |   ->   |     |    ->     |     |
808     //  |     | Flip Y |     | Rotate 90 |     |
809     //  d-----c        a-----b           b-----c
810     // This is the same as rotate 90 and flip x.
811     matrix.reset();
812     matrix.setRotate(SkIntToScalar(90));
813     matrix.postScale(SkIntToScalar(1), SkIntToScalar(-1));
814     dst2.setEmpty();
815     success = orig.transform(matrix, &dst2);
816     REPORTER_ASSERT(reporter, success);
817     REPORTER_ASSERT(reporter, dst == dst2);
818 
819     //  a-----b        b-----a            a-----d
820     //  |     |   ->   |     |     ->     |     |
821     //  |     | Flip X |     | Rotate 270 |     |
822     //  d-----c        c-----d            b-----c
823     matrix.reset();
824     matrix.setRotate(SkIntToScalar(270));
825     matrix.postScale(SkIntToScalar(-1), SkIntToScalar(1));
826     dst2.setEmpty();
827     success = orig.transform(matrix, &dst2);
828     REPORTER_ASSERT(reporter, success);
829     REPORTER_ASSERT(reporter, dst == dst2);
830 
831     //  a-----b            b-----c        a-----d
832     //  |     |     ->     |     |   ->   |     |
833     //  |     | Rotate 270 |     | Flip Y |     |
834     //  d-----c            a-----d        b-----c
835     matrix.reset();
836     matrix.setScale(SkIntToScalar(1), SkIntToScalar(-1));
837     matrix.postRotate(SkIntToScalar(270));
838     dst2.setEmpty();
839     success = orig.transform(matrix, &dst2);
840     REPORTER_ASSERT(reporter, success);
841     REPORTER_ASSERT(reporter, dst == dst2);
842 
843 
844     //  a-----b        b-----a        c-----d            b-----c
845     //  |     |   ->   |     |   ->   |     |    ->      |     |
846     //  |     | Flip X |     | Flip Y |     | Rotate 90  |     |
847     //  d-----c        c-----d        b-----a            a-----d
848     //
849     // This is the same as rotation by 270.
850     matrix.reset();
851     matrix.setRotate(SkIntToScalar(90));
852     matrix.postScale(SkIntToScalar(-1), SkIntToScalar(-1));
853     dst.setEmpty();
854     success = orig.transform(matrix, &dst);
855     REPORTER_ASSERT(reporter, success);
856     {
857         GET_RADII;
858         // Radii have cycled clockwise and swapped their x and y axis.
859         REPORTER_ASSERT(reporter, dstUL.x() == origUR.y());
860         REPORTER_ASSERT(reporter, dstUL.y() == origUR.x());
861         REPORTER_ASSERT(reporter, dstUR.x() == origLR.y());
862         REPORTER_ASSERT(reporter, dstUR.y() == origLR.x());
863         REPORTER_ASSERT(reporter, dstLR.x() == origLL.y());
864         REPORTER_ASSERT(reporter, dstLR.y() == origLL.x());
865         REPORTER_ASSERT(reporter, dstLL.x() == origUL.y());
866         REPORTER_ASSERT(reporter, dstLL.y() == origUL.x());
867     }
868     // Width and height would get swapped.
869     REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
870     REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
871 
872     //  a-----b             b-----c
873     //  |     |     ->      |     |
874     //  |     | Rotate 270  |     |
875     //  d-----c             a-----d
876     //
877     dst2.setEmpty();
878     matrix.reset();
879     matrix.setRotate(SkIntToScalar(270));
880     success = orig.transform(matrix, &dst2);
881     REPORTER_ASSERT(reporter, success);
882     REPORTER_ASSERT(reporter, dst == dst2);
883 
884     //  a-----b        b-----a        c-----d             d-----a
885     //  |     |   ->   |     |   ->   |     |     ->      |     |
886     //  |     | Flip X |     | Flip Y |     | Rotate 270  |     |
887     //  d-----c        c-----d        b-----a             c-----b
888     //
889     // This is the same as rotation by 90 degrees.
890     matrix.reset();
891     matrix.setRotate(SkIntToScalar(270));
892     matrix.postScale(SkIntToScalar(-1), SkIntToScalar(-1));
893     dst.setEmpty();
894     success = orig.transform(matrix, &dst);
895     REPORTER_ASSERT(reporter, success);
896 
897     matrix.reset();
898     matrix.setRotate(SkIntToScalar(90));
899     dst2.setEmpty();
900     success = orig.transform(matrix, &dst2);
901     REPORTER_ASSERT(reporter, dst == dst2);
902 
903 }
904 
test_round_rect_transform(skiatest::Reporter * reporter)905 static void test_round_rect_transform(skiatest::Reporter* reporter) {
906     SkRRect rrect;
907     {
908         SkRect r = { 0, 0, kWidth, kHeight };
909         rrect.setRectXY(r, SkIntToScalar(4), SkIntToScalar(7));
910         test_transform_helper(reporter, rrect);
911     }
912     {
913         SkRect r = { SkIntToScalar(5), SkIntToScalar(15),
914                      SkIntToScalar(27), SkIntToScalar(34) };
915         SkVector radii[4] = { { 0, SkIntToScalar(1) },
916                               { SkIntToScalar(2), SkIntToScalar(3) },
917                               { SkIntToScalar(4), SkIntToScalar(5) },
918                               { SkIntToScalar(6), SkIntToScalar(7) } };
919         rrect.setRectRadii(r, radii);
920         test_transform_helper(reporter, rrect);
921     }
922 }
923 
924 // Test out the case where an oval already off in space is translated/scaled
925 // further off into space - yielding numerical issues when the rect & radii
926 // are transformed separatly
927 // BUG=skia:2696
test_issue_2696(skiatest::Reporter * reporter)928 static void test_issue_2696(skiatest::Reporter* reporter) {
929     SkRRect rrect;
930     SkRect r = { 28443.8594f, 53.1428604f, 28446.7148f, 56.0000038f };
931     rrect.setOval(r);
932 
933     SkMatrix xform;
934     xform.setAll(2.44f,  0.0f, 485411.7f,
935                  0.0f,  2.44f,   -438.7f,
936                  0.0f,   0.0f,      1.0f);
937     SkRRect dst;
938 
939     bool success = rrect.transform(xform, &dst);
940     REPORTER_ASSERT(reporter, success);
941 
942     SkScalar halfWidth = SkScalarHalf(dst.width());
943     SkScalar halfHeight = SkScalarHalf(dst.height());
944 
945     for (int i = 0; i < 4; ++i) {
946         REPORTER_ASSERT(reporter,
947                         SkScalarNearlyEqual(dst.radii((SkRRect::Corner)i).fX, halfWidth));
948         REPORTER_ASSERT(reporter,
949                         SkScalarNearlyEqual(dst.radii((SkRRect::Corner)i).fY, halfHeight));
950     }
951 }
952 
test_read_rrect(skiatest::Reporter * reporter,const SkRRect & rrect,bool shouldEqualSrc)953 void test_read_rrect(skiatest::Reporter* reporter, const SkRRect& rrect, bool shouldEqualSrc) {
954     // It would be cleaner to call rrect.writeToMemory into a buffer. However, writeToMemory asserts
955     // that the rrect is valid and our caller may have fiddled with the internals of rrect to make
956     // it invalid.
957     const void* buffer = reinterpret_cast<const void*>(&rrect);
958     SkRRect deserialized;
959     size_t size = deserialized.readFromMemory(buffer, sizeof(SkRRect));
960     REPORTER_ASSERT(reporter, size == SkRRect::kSizeInMemory);
961     REPORTER_ASSERT(reporter, deserialized.isValid());
962     if (shouldEqualSrc) {
963        REPORTER_ASSERT(reporter, rrect == deserialized);
964     }
965 }
966 
test_read(skiatest::Reporter * reporter)967 static void test_read(skiatest::Reporter* reporter) {
968     static const SkRect kRect = {10.f, 10.f, 20.f, 20.f};
969     static const SkRect kNaNRect = {10.f, 10.f, 20.f, SK_ScalarNaN};
970     static const SkRect kInfRect = {10.f, 10.f, SK_ScalarInfinity, 20.f};
971     SkRRect rrect;
972 
973     test_read_rrect(reporter, SkRRect::MakeEmpty(), true);
974     test_read_rrect(reporter, SkRRect::MakeRect(kRect), true);
975     // These get coerced to empty.
976     test_read_rrect(reporter, SkRRect::MakeRect(kInfRect), true);
977     test_read_rrect(reporter, SkRRect::MakeRect(kNaNRect), true);
978 
979     rrect.setRect(kRect);
980     SkRect* innerRect = reinterpret_cast<SkRect*>(&rrect);
981     SkASSERT(*innerRect == kRect);
982     *innerRect = kInfRect;
983     test_read_rrect(reporter, rrect, false);
984     *innerRect = kNaNRect;
985     test_read_rrect(reporter, rrect, false);
986 
987     test_read_rrect(reporter, SkRRect::MakeOval(kRect), true);
988     test_read_rrect(reporter, SkRRect::MakeOval(kInfRect), true);
989     test_read_rrect(reporter, SkRRect::MakeOval(kNaNRect), true);
990     rrect.setOval(kRect);
991     *innerRect = kInfRect;
992     test_read_rrect(reporter, rrect, false);
993     *innerRect = kNaNRect;
994     test_read_rrect(reporter, rrect, false);
995 
996     test_read_rrect(reporter, SkRRect::MakeRectXY(kRect, 5.f, 5.f), true);
997     // rrect should scale down the radii to make this legal
998     test_read_rrect(reporter, SkRRect::MakeRectXY(kRect, 5.f, 400.f), true);
999 
1000     static const SkVector kRadii[4] = {{0.5f, 1.f}, {1.5f, 2.f}, {2.5f, 3.f}, {3.5f, 4.f}};
1001     rrect.setRectRadii(kRect, kRadii);
1002     test_read_rrect(reporter, rrect, true);
1003     SkScalar* innerRadius = reinterpret_cast<SkScalar*>(&rrect) + 6;
1004     SkASSERT(*innerRadius == 1.5f);
1005     *innerRadius = 400.f;
1006     test_read_rrect(reporter, rrect, false);
1007     *innerRadius = SK_ScalarInfinity;
1008     test_read_rrect(reporter, rrect, false);
1009     *innerRadius = SK_ScalarNaN;
1010     test_read_rrect(reporter, rrect, false);
1011     *innerRadius = -10.f;
1012     test_read_rrect(reporter, rrect, false);
1013 }
1014 
DEF_TEST(RoundRect,reporter)1015 DEF_TEST(RoundRect, reporter) {
1016     test_round_rect_basic(reporter);
1017     test_round_rect_rects(reporter);
1018     test_round_rect_ovals(reporter);
1019     test_round_rect_general(reporter);
1020     test_round_rect_iffy_parameters(reporter);
1021     test_inset(reporter);
1022     test_round_rect_contains_rect(reporter);
1023     test_round_rect_transform(reporter);
1024     test_issue_2696(reporter);
1025     test_tricky_radii(reporter);
1026     test_empty_crbug_458524(reporter);
1027     test_empty(reporter);
1028     test_read(reporter);
1029 }
1030