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