caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2015 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 | |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 8 | #include "include/core/SkMatrix.h" |
| 9 | #include "include/core/SkPath.h" |
| 10 | #include "include/core/SkRRect.h" |
| 11 | #include "src/core/SkPathPriv.h" |
| 12 | #include "tests/Test.h" |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 13 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 14 | static SkRRect path_contains_rrect(skiatest::Reporter* reporter, const SkPath& path, |
Mike Reed | 30bc527 | 2019-11-22 18:34:02 +0000 | [diff] [blame] | 15 | SkPathDirection* dir, unsigned* start) { |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 16 | SkRRect out; |
Mike Reed | 0c3137c | 2018-02-20 13:57:05 -0500 | [diff] [blame] | 17 | REPORTER_ASSERT(reporter, SkPathPriv::IsRRect(path, &out, dir, start)); |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 18 | SkPath recreatedPath; |
| 19 | recreatedPath.addRRect(out, *dir, *start); |
| 20 | REPORTER_ASSERT(reporter, path == recreatedPath); |
| 21 | // Test that rotations/mirrors of the rrect path are still rrect paths and the returned |
| 22 | // parameters for the transformed paths are correct. |
| 23 | static const SkMatrix kMatrices[] = { |
Mike Reed | 1f60733 | 2020-05-21 12:11:27 -0400 | [diff] [blame] | 24 | SkMatrix::Scale( 1, 1), |
| 25 | SkMatrix::Scale(-1, 1), |
| 26 | SkMatrix::Scale( 1, -1), |
| 27 | SkMatrix::Scale(-1, -1), |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 28 | }; |
| 29 | for (auto& m : kMatrices) { |
| 30 | SkPath xformed; |
| 31 | path.transform(m, &xformed); |
| 32 | SkRRect xrr = SkRRect::MakeRect(SkRect::MakeEmpty()); |
Mike Reed | 30bc527 | 2019-11-22 18:34:02 +0000 | [diff] [blame] | 33 | SkPathDirection xd = SkPathDirection::kCCW; |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 34 | unsigned xs = ~0U; |
Mike Reed | 0c3137c | 2018-02-20 13:57:05 -0500 | [diff] [blame] | 35 | REPORTER_ASSERT(reporter, SkPathPriv::IsRRect(xformed, &xrr, &xd, &xs)); |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 36 | recreatedPath.reset(); |
| 37 | recreatedPath.addRRect(xrr, xd, xs); |
| 38 | REPORTER_ASSERT(reporter, recreatedPath == xformed); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 39 | } |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 40 | return out; |
| 41 | } |
| 42 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 43 | static SkRRect inner_path_contains_rrect(skiatest::Reporter* reporter, const SkRRect& in, |
Mike Reed | 30bc527 | 2019-11-22 18:34:02 +0000 | [diff] [blame] | 44 | SkPathDirection dir, unsigned start) { |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 45 | switch (in.getType()) { |
| 46 | case SkRRect::kEmpty_Type: |
| 47 | case SkRRect::kRect_Type: |
| 48 | case SkRRect::kOval_Type: |
| 49 | return in; |
| 50 | default: |
| 51 | break; |
| 52 | } |
| 53 | SkPath path; |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 54 | path.addRRect(in, dir, start); |
Mike Reed | 30bc527 | 2019-11-22 18:34:02 +0000 | [diff] [blame] | 55 | SkPathDirection outDir; |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 56 | unsigned outStart; |
| 57 | SkRRect rrect = path_contains_rrect(reporter, path, &outDir, &outStart); |
| 58 | REPORTER_ASSERT(reporter, outDir == dir && outStart == start); |
| 59 | return rrect; |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 60 | } |
| 61 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 62 | static void path_contains_rrect_check(skiatest::Reporter* reporter, const SkRRect& in, |
Mike Reed | 30bc527 | 2019-11-22 18:34:02 +0000 | [diff] [blame] | 63 | SkPathDirection dir, unsigned start) { |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 64 | SkRRect out = inner_path_contains_rrect(reporter, in, dir, start); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 65 | if (in != out) { |
Tyler Denniston | 283dba5 | 2021-06-25 13:32:45 +0000 | [diff] [blame^] | 66 | SkDebugf(""); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 67 | } |
| 68 | REPORTER_ASSERT(reporter, in == out); |
| 69 | } |
| 70 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 71 | static void path_contains_rrect_nocheck(skiatest::Reporter* reporter, const SkRRect& in, |
Mike Reed | 30bc527 | 2019-11-22 18:34:02 +0000 | [diff] [blame] | 72 | SkPathDirection dir, unsigned start) { |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 73 | SkRRect out = inner_path_contains_rrect(reporter, in, dir, start); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 74 | if (in == out) { |
Tyler Denniston | 283dba5 | 2021-06-25 13:32:45 +0000 | [diff] [blame^] | 75 | SkDebugf(""); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 76 | } |
| 77 | } |
| 78 | |
| 79 | static void path_contains_rrect_check(skiatest::Reporter* reporter, const SkRect& r, |
Mike Reed | 30bc527 | 2019-11-22 18:34:02 +0000 | [diff] [blame] | 80 | SkVector v[4], SkPathDirection dir, unsigned start) { |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 81 | SkRRect rrect; |
| 82 | rrect.setRectRadii(r, v); |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 83 | path_contains_rrect_check(reporter, rrect, dir, start); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 84 | } |
| 85 | |
| 86 | class ForceIsRRect_Private { |
| 87 | public: |
Mike Reed | 30bc527 | 2019-11-22 18:34:02 +0000 | [diff] [blame] | 88 | ForceIsRRect_Private(SkPath* path, SkPathDirection dir, unsigned start) { |
| 89 | path->fPathRef->setIsRRect(true, dir == SkPathDirection::kCCW, start); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 90 | } |
| 91 | }; |
| 92 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 93 | static void force_path_contains_rrect(skiatest::Reporter* reporter, SkPath& path, |
Mike Reed | 30bc527 | 2019-11-22 18:34:02 +0000 | [diff] [blame] | 94 | SkPathDirection dir, unsigned start) { |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 95 | ForceIsRRect_Private force_rrect(&path, dir, start); |
Mike Reed | 30bc527 | 2019-11-22 18:34:02 +0000 | [diff] [blame] | 96 | SkPathDirection outDir; |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 97 | unsigned outStart; |
| 98 | path_contains_rrect(reporter, path, &outDir, &outStart); |
| 99 | REPORTER_ASSERT(reporter, outDir == dir && outStart == start); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 100 | } |
| 101 | |
| 102 | static void test_undetected_paths(skiatest::Reporter* reporter) { |
Kevin Lubick | be03ef1 | 2021-06-16 15:28:00 -0400 | [diff] [blame] | 103 | // We first get the exact conic weight used by SkPath for a circular arc. This |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 104 | // allows our local, hand-crafted, artisanal round rect paths below to exactly match the |
| 105 | // factory made corporate paths produced by SkPath. |
Kevin Lubick | be03ef1 | 2021-06-16 15:28:00 -0400 | [diff] [blame] | 106 | SkPath exactPath; |
| 107 | exactPath.addCircle(0, 0, 10); |
| 108 | REPORTER_ASSERT(reporter, SkPath::kMove_Verb == SkPathPriv::VerbData(exactPath)[0]); |
| 109 | REPORTER_ASSERT(reporter, SkPath::kConic_Verb == SkPathPriv::VerbData(exactPath)[1]); |
| 110 | const SkScalar weight = SkPathPriv::ConicWeightData(exactPath)[0]; |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 111 | |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 112 | SkPath path; |
| 113 | path.moveTo(0, 62.5f); |
| 114 | path.lineTo(0, 3.5f); |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 115 | path.conicTo(0, 0, 3.5f, 0, weight); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 116 | path.lineTo(196.5f, 0); |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 117 | path.conicTo(200, 0, 200, 3.5f, weight); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 118 | path.lineTo(200, 62.5f); |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 119 | path.conicTo(200, 66, 196.5f, 66, weight); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 120 | path.lineTo(3.5f, 66); |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 121 | path.conicTo(0, 66, 0, 62.5, weight); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 122 | path.close(); |
Mike Reed | 30bc527 | 2019-11-22 18:34:02 +0000 | [diff] [blame] | 123 | force_path_contains_rrect(reporter, path, SkPathDirection::kCW, 6); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 124 | |
| 125 | path.reset(); |
| 126 | path.moveTo(0, 81.5f); |
| 127 | path.lineTo(0, 3.5f); |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 128 | path.conicTo(0, 0, 3.5f, 0, weight); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 129 | path.lineTo(149.5, 0); |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 130 | path.conicTo(153, 0, 153, 3.5f, weight); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 131 | path.lineTo(153, 81.5f); |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 132 | path.conicTo(153, 85, 149.5f, 85, weight); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 133 | path.lineTo(3.5f, 85); |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 134 | path.conicTo(0, 85, 0, 81.5f, weight); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 135 | path.close(); |
Mike Reed | 30bc527 | 2019-11-22 18:34:02 +0000 | [diff] [blame] | 136 | force_path_contains_rrect(reporter, path, SkPathDirection::kCW, 6); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 137 | |
| 138 | path.reset(); |
| 139 | path.moveTo(14, 1189); |
| 140 | path.lineTo(14, 21); |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 141 | path.conicTo(14, 14, 21, 14, weight); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 142 | path.lineTo(1363, 14); |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 143 | path.conicTo(1370, 14, 1370, 21, weight); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 144 | path.lineTo(1370, 1189); |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 145 | path.conicTo(1370, 1196, 1363, 1196, weight); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 146 | path.lineTo(21, 1196); |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 147 | path.conicTo(14, 1196, 14, 1189, weight); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 148 | path.close(); |
Mike Reed | 30bc527 | 2019-11-22 18:34:02 +0000 | [diff] [blame] | 149 | force_path_contains_rrect(reporter, path, SkPathDirection::kCW, 6); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 150 | |
| 151 | path.reset(); |
| 152 | path.moveTo(14, 1743); |
| 153 | path.lineTo(14, 21); |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 154 | path.conicTo(14, 14, 21, 14, weight); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 155 | path.lineTo(1363, 14); |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 156 | path.conicTo(1370, 14, 1370, 21, weight); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 157 | path.lineTo(1370, 1743); |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 158 | path.conicTo(1370, 1750, 1363, 1750, weight); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 159 | path.lineTo(21, 1750); |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 160 | path.conicTo(14, 1750, 14, 1743, weight); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 161 | path.close(); |
Mike Reed | 30bc527 | 2019-11-22 18:34:02 +0000 | [diff] [blame] | 162 | force_path_contains_rrect(reporter, path, SkPathDirection::kCW, 6); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 163 | } |
| 164 | |
| 165 | static const SkScalar kWidth = 100.0f; |
| 166 | static const SkScalar kHeight = 100.0f; |
| 167 | |
| 168 | static void test_tricky_radii(skiatest::Reporter* reporter) { |
Mike Reed | 30bc527 | 2019-11-22 18:34:02 +0000 | [diff] [blame] | 169 | for (auto dir : {SkPathDirection::kCW, SkPathDirection::kCCW}) { |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 170 | for (int start = 0; start < 8; ++start) { |
| 171 | { |
| 172 | // crbug.com/458522 |
| 173 | SkRRect rr; |
| 174 | const SkRect bounds = { 3709, 3709, 3709 + 7402, 3709 + 29825 }; |
| 175 | const SkScalar rad = 12814; |
| 176 | const SkVector vec[] = { { rad, rad }, { 0, rad }, { rad, rad }, { 0, rad } }; |
| 177 | rr.setRectRadii(bounds, vec); |
| 178 | path_contains_rrect_check(reporter, rr, dir, start); |
| 179 | } |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 180 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 181 | { |
| 182 | // crbug.com//463920 |
| 183 | SkRect r = SkRect::MakeLTRB(0, 0, 1009, 33554432.0); |
| 184 | SkVector radii[4] = { |
| 185 | { 13.0f, 8.0f }, { 170.0f, 2.0 }, { 256.0f, 33554432.0 }, { 110.0f, 5.0f } |
| 186 | }; |
| 187 | SkRRect rr; |
| 188 | rr.setRectRadii(r, radii); |
| 189 | path_contains_rrect_nocheck(reporter, rr, dir, start); |
| 190 | } |
| 191 | } |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 192 | } |
| 193 | } |
| 194 | |
| 195 | static void test_empty_crbug_458524(skiatest::Reporter* reporter) { |
Mike Reed | 30bc527 | 2019-11-22 18:34:02 +0000 | [diff] [blame] | 196 | for (auto dir : {SkPathDirection::kCW, SkPathDirection::kCCW}) { |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 197 | for (int start = 0; start < 8; ++start) { |
| 198 | SkRRect rr; |
| 199 | const SkRect bounds = { 3709, 3709, 3709 + 7402, 3709 + 29825 }; |
| 200 | const SkScalar rad = 40; |
| 201 | rr.setRectXY(bounds, rad, rad); |
| 202 | path_contains_rrect_check(reporter, rr, dir, start); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 203 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 204 | SkRRect other; |
| 205 | SkMatrix matrix; |
| 206 | matrix.setScale(0, 1); |
| 207 | rr.transform(matrix, &other); |
| 208 | path_contains_rrect_check(reporter, rr, dir, start); |
| 209 | } |
| 210 | } |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 211 | } |
| 212 | |
| 213 | static void test_inset(skiatest::Reporter* reporter) { |
Mike Reed | 30bc527 | 2019-11-22 18:34:02 +0000 | [diff] [blame] | 214 | for (auto dir : {SkPathDirection::kCW, SkPathDirection::kCCW}) { |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 215 | for (int start = 0; start < 8; ++start) { |
| 216 | SkRRect rr, rr2; |
| 217 | SkRect r = { 0, 0, 100, 100 }; |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 218 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 219 | rr.setRect(r); |
| 220 | rr.inset(-20, -20, &rr2); |
| 221 | path_contains_rrect_check(reporter, rr, dir, start); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 222 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 223 | rr.inset(20, 20, &rr2); |
| 224 | path_contains_rrect_check(reporter, rr, dir, start); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 225 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 226 | rr.inset(r.width()/2, r.height()/2, &rr2); |
| 227 | path_contains_rrect_check(reporter, rr, dir, start); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 228 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 229 | rr.setRectXY(r, 20, 20); |
| 230 | rr.inset(19, 19, &rr2); |
| 231 | path_contains_rrect_check(reporter, rr, dir, start); |
| 232 | rr.inset(20, 20, &rr2); |
| 233 | path_contains_rrect_check(reporter, rr, dir, start); |
| 234 | } |
| 235 | } |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 236 | } |
| 237 | |
| 238 | |
| 239 | static void test_9patch_rrect(skiatest::Reporter* reporter, |
| 240 | const SkRect& rect, |
| 241 | SkScalar l, SkScalar t, SkScalar r, SkScalar b, |
| 242 | bool checkRadii) { |
Mike Reed | 30bc527 | 2019-11-22 18:34:02 +0000 | [diff] [blame] | 243 | for (auto dir : {SkPathDirection::kCW, SkPathDirection::kCCW}) { |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 244 | for (int start = 0; start < 8; ++start) { |
| 245 | SkRRect rr; |
| 246 | rr.setNinePatch(rect, l, t, r, b); |
| 247 | if (checkRadii) { |
| 248 | path_contains_rrect_check(reporter, rr, dir, start); |
| 249 | } else { |
| 250 | path_contains_rrect_nocheck(reporter, rr, dir, start); |
| 251 | } |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 252 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 253 | SkRRect rr2; // construct the same RR using the most general set function |
| 254 | SkVector radii[4] = { { l, t }, { r, t }, { r, b }, { l, b } }; |
| 255 | rr2.setRectRadii(rect, radii); |
| 256 | if (checkRadii) { |
| 257 | path_contains_rrect_check(reporter, rr, dir, start); |
| 258 | } else { |
| 259 | path_contains_rrect_nocheck(reporter, rr, dir, start); |
| 260 | } |
| 261 | } |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 262 | } |
| 263 | } |
| 264 | |
| 265 | // Test out the basic API entry points |
| 266 | static void test_round_rect_basic(skiatest::Reporter* reporter) { |
Mike Reed | 30bc527 | 2019-11-22 18:34:02 +0000 | [diff] [blame] | 267 | for (auto dir : {SkPathDirection::kCW, SkPathDirection::kCCW}) { |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 268 | for (int start = 0; start < 8; ++start) { |
| 269 | //---- |
| 270 | SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 271 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 272 | SkRRect rr1; |
| 273 | rr1.setRect(rect); |
| 274 | path_contains_rrect_check(reporter, rr1, dir, start); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 275 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 276 | SkRRect rr1_2; // construct the same RR using the most general set function |
| 277 | SkVector rr1_2_radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }; |
| 278 | rr1_2.setRectRadii(rect, rr1_2_radii); |
| 279 | path_contains_rrect_check(reporter, rr1_2, dir, start); |
| 280 | SkRRect rr1_3; // construct the same RR using the nine patch set function |
| 281 | rr1_3.setNinePatch(rect, 0, 0, 0, 0); |
| 282 | path_contains_rrect_check(reporter, rr1_2, dir, start); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 283 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 284 | //---- |
| 285 | SkPoint halfPoint = { SkScalarHalf(kWidth), SkScalarHalf(kHeight) }; |
| 286 | SkRRect rr2; |
| 287 | rr2.setOval(rect); |
| 288 | path_contains_rrect_check(reporter, rr2, dir, start); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 289 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 290 | SkRRect rr2_2; // construct the same RR using the most general set function |
| 291 | SkVector rr2_2_radii[4] = { { halfPoint.fX, halfPoint.fY }, |
| 292 | { halfPoint.fX, halfPoint.fY }, |
| 293 | { halfPoint.fX, halfPoint.fY }, |
| 294 | { halfPoint.fX, halfPoint.fY } }; |
| 295 | rr2_2.setRectRadii(rect, rr2_2_radii); |
| 296 | path_contains_rrect_check(reporter, rr2_2, dir, start); |
| 297 | SkRRect rr2_3; // construct the same RR using the nine patch set function |
| 298 | rr2_3.setNinePatch(rect, halfPoint.fX, halfPoint.fY, halfPoint.fX, halfPoint.fY); |
| 299 | path_contains_rrect_check(reporter, rr2_3, dir, start); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 300 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 301 | //---- |
| 302 | SkPoint p = { 5, 5 }; |
| 303 | SkRRect rr3; |
| 304 | rr3.setRectXY(rect, p.fX, p.fY); |
| 305 | path_contains_rrect_check(reporter, rr3, dir, start); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 306 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 307 | SkRRect rr3_2; // construct the same RR using the most general set function |
| 308 | SkVector rr3_2_radii[4] = { { 5, 5 }, { 5, 5 }, { 5, 5 }, { 5, 5 } }; |
| 309 | rr3_2.setRectRadii(rect, rr3_2_radii); |
| 310 | path_contains_rrect_check(reporter, rr3_2, dir, start); |
| 311 | SkRRect rr3_3; // construct the same RR using the nine patch set function |
| 312 | rr3_3.setNinePatch(rect, 5, 5, 5, 5); |
| 313 | path_contains_rrect_check(reporter, rr3_3, dir, start); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 314 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 315 | //---- |
| 316 | test_9patch_rrect(reporter, rect, 10, 9, 8, 7, true); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 317 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 318 | { |
| 319 | // Test out the rrect from skia:3466 |
| 320 | SkRect rect2 = SkRect::MakeLTRB(0.358211994f, 0.755430222f, 0.872866154f, |
| 321 | 0.806214333f); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 322 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 323 | test_9patch_rrect(reporter, |
| 324 | rect2, |
| 325 | 0.926942348f, 0.642850280f, 0.529063463f, 0.587844372f, |
| 326 | false); |
| 327 | } |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 328 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 329 | //---- |
| 330 | SkPoint radii2[4] = { { 0, 0 }, { 0, 0 }, { 50, 50 }, { 20, 50 } }; |
| 331 | |
| 332 | SkRRect rr5; |
| 333 | rr5.setRectRadii(rect, radii2); |
| 334 | path_contains_rrect_check(reporter, rr5, dir, start); |
| 335 | } |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 336 | } |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 337 | } |
| 338 | |
| 339 | // Test out the cases when the RR degenerates to a rect |
| 340 | static void test_round_rect_rects(skiatest::Reporter* reporter) { |
Mike Reed | 30bc527 | 2019-11-22 18:34:02 +0000 | [diff] [blame] | 341 | for (auto dir : {SkPathDirection::kCW, SkPathDirection::kCCW}) { |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 342 | for (int start = 0; start < 8; ++start) { |
| 343 | //---- |
| 344 | SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight); |
| 345 | SkRRect rr1; |
| 346 | rr1.setRectXY(rect, 0, 0); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 347 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 348 | path_contains_rrect_check(reporter, rr1, dir, start); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 349 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 350 | //---- |
| 351 | SkPoint radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }; |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 352 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 353 | SkRRect rr2; |
| 354 | rr2.setRectRadii(rect, radii); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 355 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 356 | path_contains_rrect_check(reporter, rr2, dir, start); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 357 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 358 | //---- |
| 359 | SkPoint radii2[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } }; |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 360 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 361 | SkRRect rr3; |
| 362 | rr3.setRectRadii(rect, radii2); |
| 363 | path_contains_rrect_check(reporter, rr3, dir, start); |
| 364 | } |
| 365 | } |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 366 | } |
| 367 | |
| 368 | // Test out the cases when the RR degenerates to an oval |
| 369 | static void test_round_rect_ovals(skiatest::Reporter* reporter) { |
Mike Reed | 30bc527 | 2019-11-22 18:34:02 +0000 | [diff] [blame] | 370 | for (auto dir : {SkPathDirection::kCW, SkPathDirection::kCCW}) { |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 371 | for (int start = 0; start < 8; ++start) { |
| 372 | //---- |
| 373 | SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight); |
| 374 | SkRRect rr1; |
| 375 | rr1.setRectXY(rect, SkScalarHalf(kWidth), SkScalarHalf(kHeight)); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 376 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 377 | path_contains_rrect_check(reporter, rr1, dir, start); |
| 378 | } |
| 379 | } |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 380 | } |
| 381 | |
| 382 | // Test out the non-degenerate RR cases |
| 383 | static void test_round_rect_general(skiatest::Reporter* reporter) { |
Mike Reed | 30bc527 | 2019-11-22 18:34:02 +0000 | [diff] [blame] | 384 | for (auto dir : {SkPathDirection::kCW, SkPathDirection::kCCW}) { |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 385 | for (int start = 0; start < 8; ++start) { |
| 386 | //---- |
| 387 | SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight); |
| 388 | SkRRect rr1; |
| 389 | rr1.setRectXY(rect, 20, 20); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 390 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 391 | path_contains_rrect_check(reporter, rr1, dir, start); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 392 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 393 | //---- |
| 394 | SkPoint radii[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } }; |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 395 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 396 | SkRRect rr2; |
| 397 | rr2.setRectRadii(rect, radii); |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 398 | |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 399 | path_contains_rrect_check(reporter, rr2, dir, start); |
| 400 | } |
| 401 | } |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 402 | } |
| 403 | |
| 404 | static void test_round_rect_iffy_parameters(skiatest::Reporter* reporter) { |
Mike Reed | 30bc527 | 2019-11-22 18:34:02 +0000 | [diff] [blame] | 405 | for (auto dir : {SkPathDirection::kCW, SkPathDirection::kCCW}) { |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 406 | for (int start = 0; start < 8; ++start) { |
| 407 | SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight); |
| 408 | SkPoint radii[4] = { { 50, 100 }, { 100, 50 }, { 50, 100 }, { 100, 50 } }; |
| 409 | SkRRect rr1; |
| 410 | rr1.setRectRadii(rect, radii); |
| 411 | path_contains_rrect_nocheck(reporter, rr1, dir, start); |
| 412 | } |
| 413 | } |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 414 | } |
| 415 | |
| 416 | static void set_radii(SkVector radii[4], int index, float rad) { |
| 417 | sk_bzero(radii, sizeof(SkVector) * 4); |
| 418 | radii[index].set(rad, rad); |
| 419 | } |
| 420 | |
| 421 | static void test_skbug_3239(skiatest::Reporter* reporter) { |
| 422 | const float min = SkBits2Float(0xcb7f16c8); /* -16717512.000000 */ |
| 423 | const float max = SkBits2Float(0x4b7f1c1d); /* 16718877.000000 */ |
| 424 | const float big = SkBits2Float(0x4b7f1bd7); /* 16718807.000000 */ |
| 425 | |
| 426 | const float rad = 33436320; |
| 427 | |
| 428 | const SkRect rectx = SkRect::MakeLTRB(min, min, max, big); |
| 429 | const SkRect recty = SkRect::MakeLTRB(min, min, big, max); |
| 430 | |
Mike Reed | 30bc527 | 2019-11-22 18:34:02 +0000 | [diff] [blame] | 431 | for (auto dir : {SkPathDirection::kCW, SkPathDirection::kCCW}) { |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 432 | for (int start = 0; start < 8; ++start) { |
| 433 | SkVector radii[4]; |
| 434 | for (int i = 0; i < 4; ++i) { |
| 435 | set_radii(radii, i, rad); |
| 436 | path_contains_rrect_check(reporter, rectx, radii, dir, start); |
| 437 | path_contains_rrect_check(reporter, recty, radii, dir, start); |
| 438 | } |
| 439 | } |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 440 | } |
| 441 | } |
| 442 | |
| 443 | static void test_mix(skiatest::Reporter* reporter) { |
Mike Reed | 30bc527 | 2019-11-22 18:34:02 +0000 | [diff] [blame] | 444 | for (auto dir : {SkPathDirection::kCW, SkPathDirection::kCCW}) { |
bsalomon | 78d58d1 | 2016-05-27 09:17:04 -0700 | [diff] [blame] | 445 | for (int start = 0; start < 8; ++start) { |
| 446 | // Test out mixed degenerate and non-degenerate geometry with Conics |
| 447 | const SkVector radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 100, 100 } }; |
| 448 | SkRect r = SkRect::MakeWH(100, 100); |
| 449 | SkRRect rr; |
| 450 | rr.setRectRadii(r, radii); |
| 451 | path_contains_rrect_check(reporter, rr, dir, start); |
| 452 | } |
| 453 | } |
caryclark | da707bf | 2015-11-19 14:47:43 -0800 | [diff] [blame] | 454 | } |
| 455 | |
| 456 | DEF_TEST(RoundRectInPath, reporter) { |
| 457 | test_tricky_radii(reporter); |
| 458 | test_empty_crbug_458524(reporter); |
| 459 | test_inset(reporter); |
| 460 | test_round_rect_basic(reporter); |
| 461 | test_round_rect_rects(reporter); |
| 462 | test_round_rect_ovals(reporter); |
| 463 | test_round_rect_general(reporter); |
| 464 | test_undetected_paths(reporter); |
| 465 | test_round_rect_iffy_parameters(reporter); |
| 466 | test_skbug_3239(reporter); |
| 467 | test_mix(reporter); |
| 468 | } |
Mike Reed | d72d6c5 | 2018-02-12 15:56:06 -0500 | [diff] [blame] | 469 | |
| 470 | DEF_TEST(RRect_fragile, reporter) { |
| 471 | SkRect rect = { |
| 472 | SkBits2Float(0x1f800000), // 0x003F0000 was the starter value that also fails |
| 473 | SkBits2Float(0x1400001C), |
| 474 | SkBits2Float(0x3F000004), |
| 475 | SkBits2Float(0x3F000004), |
| 476 | }; |
| 477 | |
| 478 | SkPoint radii[] = { |
| 479 | { SkBits2Float(0x00000001), SkBits2Float(0x00000001) }, |
| 480 | { SkBits2Float(0x00000020), SkBits2Float(0x00000001) }, |
| 481 | { SkBits2Float(0x00000000), SkBits2Float(0x00000000) }, |
| 482 | { SkBits2Float(0x3F000004), SkBits2Float(0x3F000004) }, |
| 483 | }; |
| 484 | |
| 485 | SkRRect rr; |
| 486 | // please don't assert |
| 487 | if (false) { // disable until we fix this |
| 488 | SkDebugf("%g 0x%08X\n", rect.fLeft, SkFloat2Bits(rect.fLeft)); |
| 489 | rr.setRectRadii(rect, radii); |
| 490 | } |
| 491 | } |
| 492 | |