Flutter Engine
The Flutter Engine
Macros | Functions | Variables
RoundRectTest.cpp File Reference
#include "include/core/SkMatrix.h"
#include "include/core/SkPath.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRRect.h"
#include "include/core/SkRect.h"
#include "include/core/SkScalar.h"
#include "include/core/SkTypes.h"
#include "include/pathops/SkPathOps.h"
#include "src/base/SkRandom.h"
#include "src/core/SkPointPriv.h"
#include "src/core/SkRRectPriv.h"
#include "tests/Test.h"
#include <algorithm>
#include <array>
#include <cstddef>
#include <cstdint>

Go to the source code of this file.

Macros

#define GET_RADII
 

Functions

static void test_tricky_radii (skiatest::Reporter *reporter)
 
static void test_empty_crbug_458524 (skiatest::Reporter *reporter)
 
static void test_empty (skiatest::Reporter *reporter)
 
static void test_inset (skiatest::Reporter *reporter)
 
static void test_9patch_rrect (skiatest::Reporter *reporter, const SkRect &rect, SkScalar l, SkScalar t, SkScalar r, SkScalar b, bool checkRadii)
 
static void test_round_rect_basic (skiatest::Reporter *reporter)
 
static void test_round_rect_rects (skiatest::Reporter *reporter)
 
static void test_round_rect_ovals (skiatest::Reporter *reporter)
 
static void test_round_rect_general (skiatest::Reporter *reporter)
 
static void test_round_rect_iffy_parameters (skiatest::Reporter *reporter)
 
static void test_direction (skiatest::Reporter *reporter, const SkRRect &rr, SkScalar initX, int stepX, SkScalar initY, int stepY, int numSteps, const bool *contains)
 
static void test_round_rect_contains_rect (skiatest::Reporter *reporter)
 
static void assert_transform_failure (skiatest::Reporter *reporter, const SkRRect &orig, const SkMatrix &matrix)
 
static void test_transform_helper (skiatest::Reporter *reporter, const SkRRect &orig)
 
static void test_round_rect_transform (skiatest::Reporter *reporter)
 
static void test_issue_2696 (skiatest::Reporter *reporter)
 
void test_read_rrect (skiatest::Reporter *reporter, const SkRRect &rrect, bool shouldEqualSrc)
 
static void test_read (skiatest::Reporter *reporter)
 
static void test_inner_bounds (skiatest::Reporter *reporter)
 
static void test_conservative_intersection (skiatest::Reporter *reporter)
 
 DEF_TEST (RoundRect, reporter)
 
 DEF_TEST (RRect_fuzzer_regressions, r)
 

Variables

static const SkScalar kWidth = 100.0f
 
static const SkScalar kHeight = 100.0f
 

Macro Definition Documentation

◆ GET_RADII

#define GET_RADII
Value:
const SkVector& origUL = orig.radii(SkRRect::kUpperLeft_Corner); \
const SkVector& origUR = orig.radii(SkRRect::kUpperRight_Corner); \
const SkVector& origLR = orig.radii(SkRRect::kLowerRight_Corner); \
const SkVector& origLL = orig.radii(SkRRect::kLowerLeft_Corner); \
const SkVector& dstUL = dst.radii(SkRRect::kUpperLeft_Corner); \
const SkVector& dstUR = dst.radii(SkRRect::kUpperRight_Corner); \
const SkVector& dstLR = dst.radii(SkRRect::kLowerRight_Corner); \
const SkVector& dstLL = dst.radii(SkRRect::kLowerLeft_Corner)
@ kUpperLeft_Corner
index of top-left corner radii
Definition: SkRRect.h:252
@ kLowerRight_Corner
index of bottom-right corner radii
Definition: SkRRect.h:254
@ kUpperRight_Corner
index of top-right corner radii
Definition: SkRRect.h:253
@ kLowerLeft_Corner
index of bottom-left corner radii
Definition: SkRRect.h:255
dst
Definition: cp.py:12

Definition at line 546 of file RoundRectTest.cpp.

Function Documentation

◆ assert_transform_failure()

static void assert_transform_failure ( skiatest::Reporter reporter,
const SkRRect orig,
const SkMatrix matrix 
)
static

Definition at line 527 of file RoundRectTest.cpp.

528 {
529 // The test depends on the fact that the original is not empty.
530 SkASSERT(!orig.isEmpty());
531 SkRRect dst;
532 dst.setEmpty();
533
534 const SkRRect copyOfDst = dst;
535 const SkRRect copyOfOrig = orig;
536 bool success = orig.transform(matrix, &dst);
537 // This transform should fail.
538 REPORTER_ASSERT(reporter, !success);
539 // Since the transform failed, dst should be unchanged.
540 REPORTER_ASSERT(reporter, copyOfDst == dst);
541 // original should not be modified.
542 REPORTER_ASSERT(reporter, copyOfOrig == orig);
543 REPORTER_ASSERT(reporter, orig != dst);
544}
reporter
Definition: FontMgrTest.cpp:39
#define SkASSERT(cond)
Definition: SkAssert.h:116
#define REPORTER_ASSERT(r, cond,...)
Definition: Test.h:286
bool transform(const SkMatrix &matrix, SkRRect *dst) const
Definition: SkRRect.cpp:436
bool isEmpty() const
Definition: SkRRect.h:83
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258

◆ DEF_TEST() [1/2]

DEF_TEST ( RoundRect  ,
reporter   
)

Definition at line 1279 of file RoundRectTest.cpp.

1279 {
1295}
static void test_round_rect_rects(skiatest::Reporter *reporter)
static void test_round_rect_transform(skiatest::Reporter *reporter)
static void test_round_rect_ovals(skiatest::Reporter *reporter)
static void test_tricky_radii(skiatest::Reporter *reporter)
static void test_inset(skiatest::Reporter *reporter)
static void test_round_rect_basic(skiatest::Reporter *reporter)
static void test_round_rect_contains_rect(skiatest::Reporter *reporter)
static void test_issue_2696(skiatest::Reporter *reporter)
static void test_inner_bounds(skiatest::Reporter *reporter)
static void test_conservative_intersection(skiatest::Reporter *reporter)
static void test_round_rect_iffy_parameters(skiatest::Reporter *reporter)
static void test_read(skiatest::Reporter *reporter)
static void test_empty_crbug_458524(skiatest::Reporter *reporter)
static void test_round_rect_general(skiatest::Reporter *reporter)
static void test_empty(skiatest::Reporter *reporter)

◆ DEF_TEST() [2/2]

DEF_TEST ( RRect_fuzzer_regressions  ,
 
)

Definition at line 1297 of file RoundRectTest.cpp.

1297 {
1298 {
1299 unsigned char buf[] = {
1300 0x0a, 0x00, 0x00, 0xff, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f,
1301 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
1302 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
1303 0x7f, 0x7f, 0x7f, 0x02, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x02, 0x00
1304 };
1305 REPORTER_ASSERT(r, sizeof(buf) == SkRRect{}.readFromMemory(buf, sizeof(buf)));
1306 }
1307
1308 {
1309 unsigned char buf[] = {
1310 0x5d, 0xff, 0xff, 0x5d, 0x0a, 0x60, 0x0a, 0x0a, 0x0a, 0x7e, 0x0a, 0x5a,
1311 0x0a, 0x12, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a,
1312 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x00, 0x00, 0x00, 0x0a,
1313 0x0a, 0x0a, 0x0a, 0x26, 0x0a, 0x0a, 0x0a, 0x0a, 0xff, 0xff, 0x0a, 0x0a
1314 };
1315 REPORTER_ASSERT(r, sizeof(buf) == SkRRect{}.readFromMemory(buf, sizeof(buf)));
1316 }
1317
1318 {
1319 unsigned char buf[] = {
1320 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x04, 0xdd, 0xdd, 0x15,
1321 0xfe, 0x00, 0x00, 0x04, 0x05, 0x7e, 0x00, 0x00, 0x00, 0xff, 0x08, 0x04,
1322 0xff, 0xff, 0xfe, 0xfe, 0xff, 0x32, 0x32, 0x32, 0x32, 0x00, 0x32, 0x32,
1323 0x04, 0xdd, 0x3d, 0x1c, 0xfe, 0x89, 0x04, 0x0a, 0x0e, 0x05, 0x7e, 0x0a
1324 };
1325 REPORTER_ASSERT(r, sizeof(buf) == SkRRect{}.readFromMemory(buf, sizeof(buf)));
1326 }
1327}
size_t readFromMemory(const void *buffer, size_t length)
Definition: SkRRect.cpp:610

◆ test_9patch_rrect()

static void test_9patch_rrect ( skiatest::Reporter reporter,
const SkRect rect,
SkScalar  l,
SkScalar  t,
SkScalar  r,
SkScalar  b,
bool  checkRadii 
)
static

Definition at line 159 of file RoundRectTest.cpp.

162 {
163 SkRRect rr;
164 rr.setNinePatch(rect, l, t, r, b);
165
168
169 if (checkRadii) {
170 // This test doesn't hold if the radii will be rescaled by SkRRect
171 SkRect ninePatchRadii = { l, t, r, b };
172 SkPoint rquad[4];
173 ninePatchRadii.toQuad(rquad);
174 for (int i = 0; i < 4; ++i) {
176 }
177 }
178 SkRRect rr2; // construct the same RR using the most general set function
179 SkVector radii[4] = { { l, t }, { r, t }, { r, b }, { l, b } };
180 rr2.setRectRadii(rect, radii);
181 REPORTER_ASSERT(reporter, rr2 == rr && rr2.getType() == rr.getType());
182}
Type getType() const
Definition: SkRRect.h:76
const SkRect & rect() const
Definition: SkRRect.h:264
SkVector radii(Corner corner) const
Definition: SkRRect.h:271
@ kNinePatch_Type
non-zero width and height with axis-aligned radii
Definition: SkRRect.h:71
void setRectRadii(const SkRect &rect, const SkVector radii[4])
Definition: SkRRect.cpp:189
Type type() const
Definition: SkRRect.h:81
void setNinePatch(const SkRect &rect, SkScalar leftRad, SkScalar topRad, SkScalar rightRad, SkScalar bottomRad)
Definition: SkRRect.cpp:115
static bool b
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
void toQuad(SkPoint quad[4]) const
Definition: SkRect.cpp:50

◆ test_conservative_intersection()

static void test_conservative_intersection ( skiatest::Reporter reporter)
static

Definition at line 1179 of file RoundRectTest.cpp.

1179 {
1180 // Helper to inline making an inset round rect
1181 auto make_inset = [](const SkRRect& r, float dx, float dy) {
1182 SkRRect i = r;
1183 i.inset(dx, dy);
1184 return i;
1185 };
1186
1187 // A is a wide, short round rect
1188 SkRRect a = SkRRect::MakeRectXY({0.f, 4.f, 16.f, 12.f}, 2.f, 2.f);
1189 // B is a narrow, tall round rect
1190 SkRRect b = SkRRect::MakeRectXY({4.f, 0.f, 12.f, 16.f}, 3.f, 3.f);
1191 // NOTE: As positioned by default, A and B intersect as the rectangle {4, 4, 12, 12}.
1192 // There is a 2 px buffer between the corner curves of A and the vertical edges of B, and
1193 // a 1 px buffer between the corner curves of B and the horizontal edges of A. Since the shapes
1194 // form a symmetric rounded cross, we can easily test edge and corner combinations by simply
1195 // flipping signs and/or swapping x and y offsets.
1196
1197 // Successful intersection operations:
1198 // - for clarity these are formed by moving A around to intersect with B in different ways.
1199 // - the expected bounds of the round rect intersection is calculated automatically
1200 // in check_success, so all we have to specify are the expected corner radii
1201
1202 // A and B intersect as a rectangle
1203 verify_success(reporter, a, b, kRect, kRect, kRect, kRect);
1204 // Move A to intersect B on a vertical edge, preserving two corners of A inside B
1205 verify_success(reporter, a.makeOffset(6.f, 0.f), b, kA, kRect, kRect, kA);
1206 verify_success(reporter, a.makeOffset(-6.f, 0.f), b, kRect, kA, kA, kRect);
1207 // Move B to intersect A on a horizontal edge, preserving two corners of B inside A
1208 verify_success(reporter, a, b.makeOffset(0.f, 6.f), kB, kB, kRect, kRect);
1209 verify_success(reporter, a, b.makeOffset(0.f, -6.f), kRect, kRect, kB, kB);
1210 // Move A to intersect B on a corner, preserving one corner of A and one of B
1211 verify_success(reporter, a.makeOffset(-7.f, -8.f), b, kB, kRect, kA, kRect); // TL of B
1212 verify_success(reporter, a.makeOffset(7.f, -8.f), b, kRect, kB, kRect, kA); // TR of B
1213 verify_success(reporter, a.makeOffset(7.f, 8.f), b, kA, kRect, kB, kRect); // BR of B
1214 verify_success(reporter, a.makeOffset(-7.f, 8.f), b, kRect, kA, kRect, kB); // BL of B
1215 // An inset is contained inside the original (note that SkRRect::inset modifies radii too) so
1216 // is returned unmodified when intersected.
1217 verify_success(reporter, a, make_inset(a, 1.f, 1.f), kB, kB, kB, kB);
1218 verify_success(reporter, make_inset(b, 2.f, 2.f), b, kA, kA, kA, kA);
1219
1220 // A rectangle exactly matching the corners of the rrect bounds keeps the rrect radii,
1221 // regardless of whether or not it's the 1st or 2nd arg to ConservativeIntersect.
1222 SkRRect c = SkRRect::MakeRectXY({0.f, 0.f, 10.f, 10.f}, 2.f, 2.f);
1223 SkRRect cT = SkRRect::MakeRect({0.f, 0.f, 10.f, 5.f});
1224 verify_success(reporter, c, cT, kA, kA, kRect, kRect);
1225 verify_success(reporter, cT, c, kB, kB, kRect, kRect);
1226 SkRRect cB = SkRRect::MakeRect({0.f, 5.f, 10.f, 10.});
1227 verify_success(reporter, c, cB, kRect, kRect, kA, kA);
1228 verify_success(reporter, cB, c, kRect, kRect, kB, kB);
1229 SkRRect cL = SkRRect::MakeRect({0.f, 0.f, 5.f, 10.f});
1230 verify_success(reporter, c, cL, kA, kRect, kRect, kA);
1231 verify_success(reporter, cL, c, kB, kRect, kRect, kB);
1232 SkRRect cR = SkRRect::MakeRect({5.f, 0.f, 10.f, 10.f});
1233 verify_success(reporter, c, cR, kRect, kA, kA, kRect);
1234 verify_success(reporter, cR, c, kRect, kB, kB, kRect);
1235
1236 // Failed intersection operations:
1237
1238 // A and B's bounds do not intersect
1239 verify_failure(reporter, a.makeOffset(32.f, 0.f), b);
1240 // A and B's bounds intersect, but corner curves do not -> no intersection
1241 verify_failure(reporter, a.makeOffset(11.5f, -11.5f), b);
1242 // A is empty -> no intersection
1243 verify_failure(reporter, SkRRect::MakeEmpty(), b);
1244 // A is contained in B, but is too close to the corner curves for the conservative
1245 // approximations to construct a valid round rect intersection.
1246 verify_failure(reporter, make_inset(b, 0.3f, 0.3f), b);
1247 // A intersects a straight edge, but not far enough for B to contain A's corners
1248 verify_failure(reporter, a.makeOffset(2.5f, 0.f), b);
1249 verify_failure(reporter, a.makeOffset(-2.5f, 0.f), b);
1250 // And vice versa for B into A
1251 verify_failure(reporter, a, b.makeOffset(0.f, 1.5f));
1252 verify_failure(reporter, a, b.makeOffset(0.f, -1.5f));
1253 // A intersects a straight edge and part of B's corner
1254 verify_failure(reporter, a.makeOffset(5.f, -2.f), b);
1255 verify_failure(reporter, a.makeOffset(-5.f, -2.f), b);
1256 verify_failure(reporter, a.makeOffset(5.f, 2.f), b);
1257 verify_failure(reporter, a.makeOffset(-5.f, 2.f), b);
1258 // And vice versa
1259 verify_failure(reporter, a, b.makeOffset(3.f, -5.f));
1260 verify_failure(reporter, a, b.makeOffset(-3.f, -5.f));
1261 verify_failure(reporter, a, b.makeOffset(3.f, 5.f));
1262 verify_failure(reporter, a, b.makeOffset(-3.f, 5.f));
1263 // A intersects B on a corner, but the corner curves overlap each other
1264 verify_failure(reporter, a.makeOffset(8.f, 10.f), b);
1265 verify_failure(reporter, a.makeOffset(-8.f, 10.f), b);
1266 verify_failure(reporter, a.makeOffset(8.f, -10.f), b);
1267 verify_failure(reporter, a.makeOffset(-8.f, -10.f), b);
1268
1269 // Another variant of corners overlapping, this is two circles of radius r that overlap by r
1270 // pixels (e.g. the leftmost point of the right circle touches the center of the left circle).
1271 // The key difference with the above case is that the intersection of the circle bounds have
1272 // corners that are contained in both circles, but because it is only r wide, can not satisfy
1273 // all corners having radii = r.
1274 float r = 100.f;
1275 a = SkRRect::MakeOval(SkRect::MakeWH(2*r, 2*r));
1276 verify_failure(reporter, a, a.makeOffset(r, 0.f));
1277}
static SkRRect MakeOval(const SkRect &oval)
Definition: SkRRect.h:162
static SkRRect MakeRect(const SkRect &r)
Definition: SkRRect.h:149
static SkRRect MakeRectXY(const SkRect &rect, SkScalar xRad, SkScalar yRad)
Definition: SkRRect.h:180
static SkRRect MakeEmpty()
Definition: SkRRect.h:142
struct MyStruct a[10]
skia_private::AutoTArray< sk_sp< SkImageFilter > > filters TypedMatrix matrix TypedMatrix matrix SkScalar dx
Definition: SkRecords.h:208
const auto kB
const auto kA
constexpr std::array< std::array< float, 2 >, 2 > kRect
static constexpr SkRect MakeWH(float w, float h)
Definition: SkRect.h:609

◆ test_direction()

static void test_direction ( skiatest::Reporter reporter,
const SkRRect rr,
SkScalar  initX,
int  stepX,
SkScalar  initY,
int  stepY,
int  numSteps,
const bool *  contains 
)
static

Definition at line 394 of file RoundRectTest.cpp.

396 {
397 SkScalar x = initX, y = initY;
398 for (int i = 0; i < numSteps; ++i) {
400 stepX ? SkIntToScalar(stepX) : SK_Scalar1,
401 stepY ? SkIntToScalar(stepY) : SK_Scalar1);
402 test.sort();
403
405
406 x += stepX;
407 y += stepY;
408 }
409}
#define SK_Scalar1
Definition: SkScalar.h:18
#define SkIntToScalar(x)
Definition: SkScalar.h:57
bool contains(const SkRect &rect) const
Definition: SkRRect.cpp:360
float SkScalar
Definition: extension.cpp:12
double y
double x
constexpr bool contains(std::string_view str, std::string_view needle)
Definition: SkStringView.h:41
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition: SkRect.h:659

◆ test_empty()

static void test_empty ( skiatest::Reporter reporter)
static

Definition at line 66 of file RoundRectTest.cpp.

66 {
67 static const SkRect oooRects[] = { // out of order
68 { 100, 0, 0, 100 }, // ooo horizontal
69 { 0, 100, 100, 0 }, // ooo vertical
70 { 100, 100, 0, 0 }, // ooo both
71 };
72
73 static const SkRect emptyRects[] = {
74 { 100, 100, 100, 200 }, // empty horizontal
75 { 100, 100, 200, 100 }, // empty vertical
76 { 100, 100, 100, 100 }, // empty both
77 { 0, 0, 0, 0 } // setEmpty-empty
78 };
79
80 static const SkVector radii[4] = { { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 } };
81
82 SkRRect r;
83
84 for (size_t i = 0; i < std::size(oooRects); ++i) {
85 r.setRect(oooRects[i]);
87 REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
88
89 r.setOval(oooRects[i]);
91 REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
92
93 r.setRectXY(oooRects[i], 1, 2);
95 REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
96
97 r.setNinePatch(oooRects[i], 0, 1, 2, 3);
99 REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
100
101 r.setRectRadii(oooRects[i], radii);
103 REPORTER_ASSERT(reporter, r.rect() == oooRects[i].makeSorted());
104 }
105
106 for (size_t i = 0; i < std::size(emptyRects); ++i) {
107 r.setRect(emptyRects[i]);
109 REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
110
111 r.setOval(emptyRects[i]);
113 REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
114
115 r.setRectXY(emptyRects[i], 1, 2);
117 REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
118
119 r.setNinePatch(emptyRects[i], 0, 1, 2, 3);
121 REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
122
123 r.setRectRadii(emptyRects[i], radii);
125 REPORTER_ASSERT(reporter, r.rect() == emptyRects[i]);
126 }
127
128 r.setRect({SK_ScalarNaN, 10, 10, 20});
130 r.setRect({0, 10, 10, SK_ScalarInfinity});
132}
#define SK_ScalarNaN
Definition: SkScalar.h:28
#define SK_ScalarInfinity
Definition: SkScalar.h:26
void setOval(const SkRect &oval)
Definition: SkRRect.cpp:30
void setRectXY(const SkRect &rect, SkScalar xRad, SkScalar yRad)
Definition: SkRRect.cpp:52
void setRect(const SkRect &rect)
Definition: SkRRect.h:126
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
SkRect makeSorted() const
Definition: SkRect.h:1330

◆ test_empty_crbug_458524()

static void test_empty_crbug_458524 ( skiatest::Reporter reporter)
static

Definition at line 51 of file RoundRectTest.cpp.

51 {
52 SkRRect rr;
53 const SkRect bounds = { 3709, 3709, 3709 + 7402, 3709 + 29825 };
54 const SkScalar rad = 40;
55 rr.setRectXY(bounds, rad, rad);
56
57 SkRRect other;
59 matrix.setScale(0, 1);
60 rr.transform(matrix, &other);
62}
@ kEmpty_Type
zero width or height
Definition: SkRRect.h:67
Optional< SkRect > bounds
Definition: SkRecords.h:189

◆ test_inner_bounds()

static void test_inner_bounds ( skiatest::Reporter reporter)
static

Definition at line 1028 of file RoundRectTest.cpp.

1028 {
1029 // Because InnerBounds() insets the computed bounds slightly to correct for numerical inaccuracy
1030 // when finding the maximum inscribed point on a curve, we use a larger epsilon for comparing
1031 // expected areas.
1032 static constexpr SkScalar kEpsilon = 0.005f;
1033
1034 // Test that an empty rrect reports empty inner bounds
1036 // Test that a rect rrect reports itself as the inner bounds
1037 SkRect r = SkRect::MakeLTRB(0, 1, 2, 3);
1039 // Test that a circle rrect has an inner bounds area equal to 2*radius^2
1040 float radius = 5.f;
1042 2.f * radius)));
1044 2.f * radius * radius, kEpsilon));
1045
1046 float width = 20.f;
1047 float height = 25.f;
1049 // Test that a rrect with circular corners has an area equal to:
1050 float expectedArea =
1051 (2.f * radius * radius) + // area in the 4 circular corners
1052 (width-2.f*radius) * (height-2.f*radius) + // inner area excluding corners and edges
1053 SK_ScalarSqrt2 * radius * (width-2.f*radius) + // two horiz. rects between corners
1054 SK_ScalarSqrt2 * radius * (height-2.f*radius); // two vert. rects between corners
1055
1056 inner = SkRRectPriv::InnerBounds(SkRRect::MakeRectXY(r, radius, radius));
1057 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(inner.width() * inner.height(),
1058 expectedArea, kEpsilon));
1059
1060 // Test that a rrect with a small y radius but large x radius selects the horizontal interior
1061 SkRRect rr = SkRRect::MakeRectXY(r, 2.f * radius, 0.1f * radius);
1063 SkRect::MakeLTRB(0.f, 0.1f * radius, width, height - 0.1f * radius));
1064 // And vice versa with large y and small x radii
1065 rr = SkRRect::MakeRectXY(r, 0.1f * radius, 2.f * radius);
1067 SkRect::MakeLTRB(0.1f * radius, 0.f, width - 0.1f * radius, height));
1068
1069 // Test a variety of complex round rects produce a non-empty rect that is at least contained,
1070 // and larger than the inner area avoiding all corners.
1071 SkRandom rng;
1072 for (int i = 0; i < 1000; ++i) {
1073 float maxRadiusX = rng.nextRangeF(0.f, 40.f);
1074 float maxRadiusY = rng.nextRangeF(0.f, 40.f);
1075
1076 float innerWidth = rng.nextRangeF(0.f, 40.f);
1077 float innerHeight = rng.nextRangeF(0.f, 40.f);
1078
1079 SkVector radii[4] = {{rng.nextRangeF(0.f, maxRadiusX), rng.nextRangeF(0.f, maxRadiusY)},
1080 {rng.nextRangeF(0.f, maxRadiusX), rng.nextRangeF(0.f, maxRadiusY)},
1081 {rng.nextRangeF(0.f, maxRadiusX), rng.nextRangeF(0.f, maxRadiusY)},
1082 {rng.nextRangeF(0.f, maxRadiusX), rng.nextRangeF(0.f, maxRadiusY)}};
1083
1084 float maxLeft = std::max(radii[0].fX, radii[3].fX);
1085 float maxTop = std::max(radii[0].fY, radii[1].fY);
1086 float maxRight = std::max(radii[1].fX, radii[2].fX);
1087 float maxBottom = std::max(radii[2].fY, radii[3].fY);
1088
1089 SkRect outer = SkRect::MakeWH(maxLeft + maxRight + innerWidth,
1090 maxTop + maxBottom + innerHeight);
1091 rr.setRectRadii(outer, radii);
1092
1093 SkRect maxInner = SkRRectPriv::InnerBounds(rr);
1094 // Test upper limit on the size of 'maxInner'
1095 REPORTER_ASSERT(reporter, outer.contains(maxInner));
1096 REPORTER_ASSERT(reporter, rr.contains(maxInner));
1097
1098 // Test lower limit on the size of 'maxInner'
1099 inner = SkRect::MakeXYWH(maxLeft, maxTop, innerWidth, innerHeight);
1100 inner.inset(kEpsilon, kEpsilon);
1101
1102 if (inner.isSorted()) {
1103 REPORTER_ASSERT(reporter, maxInner.contains(inner));
1104 } else {
1105 // Flipped from the inset, just test two points of inner
1106 float midX = maxLeft + 0.5f * innerWidth;
1107 float midY = maxTop + 0.5f * innerHeight;
1108 REPORTER_ASSERT(reporter, maxInner.contains(midX, maxTop));
1109 REPORTER_ASSERT(reporter, maxInner.contains(midX, maxTop + innerHeight));
1110 REPORTER_ASSERT(reporter, maxInner.contains(maxLeft, midY));
1111 REPORTER_ASSERT(reporter, maxInner.contains(maxLeft + innerWidth, midY));
1112 }
1113 }
1114}
static constexpr double kEpsilon
static bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance=SK_ScalarNearlyZero)
Definition: SkScalar.h:107
#define SK_ScalarSqrt2
Definition: SkScalar.h:20
static SkRect InnerBounds(const SkRRect &rr)
Definition: SkRRect.cpp:750
float nextRangeF(float min, float max)
Definition: SkRandom.h:64
static float max(float r, float g, float b)
Definition: hsl.cpp:49
int32_t height
int32_t width
bool contains(SkScalar x, SkScalar y) const
Definition: extension.cpp:19
constexpr float height() const
Definition: SkRect.h:769
constexpr float width() const
Definition: SkRect.h:762
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition: SkRect.h:646

◆ test_inset()

static void test_inset ( skiatest::Reporter reporter)
static

Definition at line 137 of file RoundRectTest.cpp.

137 {
138 SkRRect rr, rr2;
139 SkRect r = { 0, 0, 100, 100 };
140
141 rr.setRect(r);
142 rr.inset(-20, -20, &rr2);
144
145 rr.inset(20, 20, &rr2);
147
148 rr.inset(r.width()/2, r.height()/2, &rr2);
150
151 rr.setRectXY(r, 20, 20);
152 rr.inset(19, 19, &rr2);
154 rr.inset(20, 20, &rr2);
156}
void inset(SkScalar dx, SkScalar dy, SkRRect *dst) const
Definition: SkRRect.cpp:562
bool isRect() const
Definition: SkRRect.h:84
bool isSimple() const
Definition: SkRRect.h:86

◆ test_issue_2696()

static void test_issue_2696 ( skiatest::Reporter reporter)
static

Definition at line 941 of file RoundRectTest.cpp.

941 {
943 SkRect r = { 28443.8594f, 53.1428604f, 28446.7148f, 56.0000038f };
944 rrect.setOval(r);
945
946 SkMatrix xform;
947 xform.setAll(2.44f, 0.0f, 485411.7f,
948 0.0f, 2.44f, -438.7f,
949 0.0f, 0.0f, 1.0f);
950 SkRRect dst;
951
952 bool success = rrect.transform(xform, &dst);
953 REPORTER_ASSERT(reporter, success);
954
955 SkScalar halfWidth = SkScalarHalf(dst.width());
956 SkScalar halfHeight = SkScalarHalf(dst.height());
957
958 for (int i = 0; i < 4; ++i) {
960 SkScalarNearlyEqual(dst.radii((SkRRect::Corner)i).fX, halfWidth));
962 SkScalarNearlyEqual(dst.radii((SkRRect::Corner)i).fY, halfHeight));
963 }
964}
#define SkScalarHalf(a)
Definition: SkScalar.h:75
SkMatrix & setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar persp0, SkScalar persp1, SkScalar persp2)
Definition: SkMatrix.h:562
SkRRect rrect
Definition: SkRecords.h:232

◆ test_read()

static void test_read ( skiatest::Reporter reporter)
static

Definition at line 980 of file RoundRectTest.cpp.

980 {
981 static const SkRect kRect = {10.f, 10.f, 20.f, 20.f};
982 static const SkRect kNaNRect = {10.f, 10.f, 20.f, SK_ScalarNaN};
983 static const SkRect kInfRect = {10.f, 10.f, SK_ScalarInfinity, 20.f};
985
988 // These get coerced to empty.
991
993 SkRect* innerRect = reinterpret_cast<SkRect*>(&rrect);
994 SkASSERT(*innerRect == kRect);
995 *innerRect = kInfRect;
997 *innerRect = kNaNRect;
999
1001 test_read_rrect(reporter, SkRRect::MakeOval(kInfRect), true);
1002 test_read_rrect(reporter, SkRRect::MakeOval(kNaNRect), true);
1004 *innerRect = kInfRect;
1006 *innerRect = kNaNRect;
1008
1010 // rrect should scale down the radii to make this legal
1012
1013 static const SkVector kRadii[4] = {{0.5f, 1.f}, {1.5f, 2.f}, {2.5f, 3.f}, {3.5f, 4.f}};
1014 rrect.setRectRadii(kRect, kRadii);
1016 SkScalar* innerRadius = reinterpret_cast<SkScalar*>(&rrect) + 6;
1017 SkASSERT(*innerRadius == 1.5f);
1018 *innerRadius = 400.f;
1020 *innerRadius = SK_ScalarInfinity;
1022 *innerRadius = SK_ScalarNaN;
1024 *innerRadius = -10.f;
1026}
void test_read_rrect(skiatest::Reporter *reporter, const SkRRect &rrect, bool shouldEqualSrc)

◆ test_read_rrect()

void test_read_rrect ( skiatest::Reporter reporter,
const SkRRect rrect,
bool  shouldEqualSrc 
)

Definition at line 966 of file RoundRectTest.cpp.

966 {
967 // It would be cleaner to call rrect.writeToMemory into a buffer. However, writeToMemory asserts
968 // that the rrect is valid and our caller may have fiddled with the internals of rrect to make
969 // it invalid.
970 const void* buffer = reinterpret_cast<const void*>(&rrect);
971 SkRRect deserialized;
972 size_t size = deserialized.readFromMemory(buffer, sizeof(SkRRect));
974 REPORTER_ASSERT(reporter, deserialized.isValid());
975 if (shouldEqualSrc) {
976 REPORTER_ASSERT(reporter, rrect == deserialized);
977 }
978}
static constexpr size_t kSizeInMemory
Definition: SkRRect.h:422
bool isValid() const
Definition: SkRRect.cpp:663
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126

◆ test_round_rect_basic()

static void test_round_rect_basic ( skiatest::Reporter reporter)
static

Definition at line 185 of file RoundRectTest.cpp.

185 {
186 // Test out initialization methods
187 SkPoint zeroPt = { 0, 0 };
189
190 empty.setEmpty();
191
193 REPORTER_ASSERT(reporter, empty.rect().isEmpty());
194
195 for (int i = 0; i < 4; ++i) {
196 REPORTER_ASSERT(reporter, zeroPt == empty.radii((SkRRect::Corner) i));
197 }
198
199 //----
201
202 SkRRect rr1;
203 rr1.setRect(rect);
204
207
208 for (int i = 0; i < 4; ++i) {
210 }
211 SkRRect rr1_2; // construct the same RR using the most general set function
212 SkVector rr1_2_radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
213 rr1_2.setRectRadii(rect, rr1_2_radii);
214 REPORTER_ASSERT(reporter, rr1_2 == rr1 && rr1_2.getType() == rr1.getType());
215 SkRRect rr1_3; // construct the same RR using the nine patch set function
216 rr1_3.setNinePatch(rect, 0, 0, 0, 0);
217 REPORTER_ASSERT(reporter, rr1_3 == rr1 && rr1_3.getType() == rr1.getType());
218
219 //----
221 SkRRect rr2;
222 rr2.setOval(rect);
223
226
227 for (int i = 0; i < 4; ++i) {
230 halfPoint));
231 }
232 SkRRect rr2_2; // construct the same RR using the most general set function
233 SkVector rr2_2_radii[4] = { { halfPoint.fX, halfPoint.fY }, { halfPoint.fX, halfPoint.fY },
234 { halfPoint.fX, halfPoint.fY }, { halfPoint.fX, halfPoint.fY } };
235 rr2_2.setRectRadii(rect, rr2_2_radii);
236 REPORTER_ASSERT(reporter, rr2_2 == rr2 && rr2_2.getType() == rr2.getType());
237 SkRRect rr2_3; // construct the same RR using the nine patch set function
238 rr2_3.setNinePatch(rect, halfPoint.fX, halfPoint.fY, halfPoint.fX, halfPoint.fY);
239 REPORTER_ASSERT(reporter, rr2_3 == rr2 && rr2_3.getType() == rr2.getType());
240
241 //----
242 SkPoint p = { 5, 5 };
243 SkRRect rr3;
244 rr3.setRectXY(rect, p.fX, p.fY);
245
248
249 for (int i = 0; i < 4; ++i) {
251 }
252 SkRRect rr3_2; // construct the same RR using the most general set function
253 SkVector rr3_2_radii[4] = { { 5, 5 }, { 5, 5 }, { 5, 5 }, { 5, 5 } };
254 rr3_2.setRectRadii(rect, rr3_2_radii);
255 REPORTER_ASSERT(reporter, rr3_2 == rr3 && rr3_2.getType() == rr3.getType());
256 SkRRect rr3_3; // construct the same RR using the nine patch set function
257 rr3_3.setNinePatch(rect, 5, 5, 5, 5);
258 REPORTER_ASSERT(reporter, rr3_3 == rr3 && rr3_3.getType() == rr3.getType());
259
260 //----
261 test_9patch_rrect(reporter, rect, 10, 9, 8, 7, true);
262
263 {
264 // Test out the rrect from skia:3466
265 SkRect rect2 = SkRect::MakeLTRB(0.358211994f, 0.755430222f, 0.872866154f, 0.806214333f);
266
268 rect2,
269 0.926942348f, 0.642850280f, 0.529063463f, 0.587844372f,
270 false);
271 }
272
273 //----
274 SkPoint radii2[4] = { { 0, 0 }, { 0, 0 }, { 50, 50 }, { 20, 50 } };
275
276 SkRRect rr5;
277 rr5.setRectRadii(rect, radii2);
278
281
282 for (int i = 0; i < 4; ++i) {
283 REPORTER_ASSERT(reporter, radii2[i] == rr5.radii((SkRRect::Corner) i));
284 }
285
286 // Test out == & !=
288 REPORTER_ASSERT(reporter, rr3 != rr5);
289}
static const SkScalar kHeight
static void test_9patch_rrect(skiatest::Reporter *reporter, const SkRect &rect, SkScalar l, SkScalar t, SkScalar r, SkScalar b, bool checkRadii)
static const SkScalar kWidth
static bool EqualsWithinTolerance(const SkPoint &p1, const SkPoint &p2)
Definition: SkPointPriv.h:54
@ kOval_Type
non-zero width and height filled with radii
Definition: SkRRect.h:69
@ kSimple_Type
non-zero width and height with equal radii
Definition: SkRRect.h:70
@ kRect_Type
non-zero width and height, and zeroed radii
Definition: SkRRect.h:68
@ kComplex_Type
non-zero width and height with arbitrary radii
Definition: SkRRect.h:72
EMSCRIPTEN_KEEPALIVE void empty()
float fX
x-axis value
Definition: SkPoint_impl.h:164
float fY
y-axis value
Definition: SkPoint_impl.h:165

◆ test_round_rect_contains_rect()

static void test_round_rect_contains_rect ( skiatest::Reporter reporter)
static

Definition at line 412 of file RoundRectTest.cpp.

412 {
413
414 static const int kNumRRects = 4;
415 static const SkVector gRadii[kNumRRects][4] = {
416 { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, // rect
417 { { 20, 20 }, { 20, 20 }, { 20, 20 }, { 20, 20 } }, // circle
418 { { 10, 10 }, { 10, 10 }, { 10, 10 }, { 10, 10 } }, // simple
419 { { 0, 0 }, { 20, 20 }, { 10, 10 }, { 30, 30 } } // complex
420 };
421
422 SkRRect rrects[kNumRRects];
423 for (int i = 0; i < kNumRRects; ++i) {
424 rrects[i].setRectRadii(SkRect::MakeWH(40, 40), gRadii[i]);
425 }
426
427 // First test easy outs - boxes that are obviously out on
428 // each corner and edge
429 static const SkRect easyOuts[] = {
430 { -5, -5, 5, 5 }, // NW
431 { 15, -5, 20, 5 }, // N
432 { 35, -5, 45, 5 }, // NE
433 { 35, 15, 45, 20 }, // E
434 { 35, 45, 35, 45 }, // SE
435 { 15, 35, 20, 45 }, // S
436 { -5, 35, 5, 45 }, // SW
437 { -5, 15, 5, 20 } // W
438 };
439
440 for (int i = 0; i < kNumRRects; ++i) {
441 for (size_t j = 0; j < std::size(easyOuts); ++j) {
442 REPORTER_ASSERT(reporter, !rrects[i].contains(easyOuts[j]));
443 }
444 }
445
446 // Now test non-trivial containment. For each compass
447 // point walk a 1x1 rect in from the edge of the bounding
448 // rect
449 static const int kNumSteps = 15;
450 bool answers[kNumRRects][8][kNumSteps] = {
451 // all the test rects are inside the degenerate rrect
452 {
453 // rect
454 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
455 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
456 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
457 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
458 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
459 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
460 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
461 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
462 },
463 // for the circle we expect 6 blocks to be out on the
464 // corners (then the rest in) and only the first block
465 // out on the vertical and horizontal axes (then
466 // the rest in)
467 {
468 // circle
469 { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
470 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
471 { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
472 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
473 { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
474 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
475 { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
476 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
477 },
478 // for the simple round rect we expect 3 out on
479 // the corners (then the rest in) and no blocks out
480 // on the vertical and horizontal axes
481 {
482 // simple RR
483 { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
484 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
485 { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
486 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
487 { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
488 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
489 { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
490 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
491 },
492 // for the complex case the answer is different for each direction
493 {
494 // complex RR
495 // all in for NW (rect) corner (same as rect case)
496 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
497 // only first block out for N (same as circle case)
498 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
499 // first 6 blocks out for NE (same as circle case)
500 { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
501 // only first block out for E (same as circle case)
502 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
503 // first 3 blocks out for SE (same as simple case)
504 { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
505 // first two blocks out for S
506 { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
507 // first 9 blocks out for SW
508 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1 },
509 // first two blocks out for W (same as S)
510 { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
511 }
512 };
513
514 for (int i = 0; i < kNumRRects; ++i) {
515 test_direction(reporter, rrects[i], 0, 1, 0, 1, kNumSteps, answers[i][0]); // NW
516 test_direction(reporter, rrects[i], 19.5f, 0, 0, 1, kNumSteps, answers[i][1]); // N
517 test_direction(reporter, rrects[i], 40, -1, 0, 1, kNumSteps, answers[i][2]); // NE
518 test_direction(reporter, rrects[i], 40, -1, 19.5f, 0, kNumSteps, answers[i][3]); // E
519 test_direction(reporter, rrects[i], 40, -1, 40, -1, kNumSteps, answers[i][4]); // SE
520 test_direction(reporter, rrects[i], 19.5f, 0, 40, -1, kNumSteps, answers[i][5]); // S
521 test_direction(reporter, rrects[i], 0, 1, 40, -1, kNumSteps, answers[i][6]); // SW
522 test_direction(reporter, rrects[i], 0, 1, 19.5f, 0, kNumSteps, answers[i][7]); // W
523 }
524}
static const double answers[][2]
static void test_direction(skiatest::Reporter *reporter, const SkRRect &rr, SkScalar initX, int stepX, SkScalar initY, int stepY, int numSteps, const bool *contains)

◆ test_round_rect_general()

static void test_round_rect_general ( skiatest::Reporter reporter)
static

Definition at line 345 of file RoundRectTest.cpp.

345 {
346 //----
348 SkRRect rr1;
349 rr1.setRectXY(rect, 20, 20);
350
352
353 //----
354 SkPoint radii[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } };
355
356 SkRRect rr2;
357 rr2.setRectRadii(rect, radii);
358
360}

◆ test_round_rect_iffy_parameters()

static void test_round_rect_iffy_parameters ( skiatest::Reporter reporter)
static

Definition at line 363 of file RoundRectTest.cpp.

363 {
364
365 // When the radii exceed the base rect they are proportionally scaled down
366 // to fit
368 SkPoint radii[4] = { { 50, 100 }, { 100, 50 }, { 50, 100 }, { 100, 50 } };
369
370 SkRRect rr1;
371 rr1.setRectRadii(rect, radii);
372
374
376
379
380 // Negative radii should be capped at zero
381 SkRRect rr2;
382 rr2.setRectXY(rect, -10, -20);
383
385
387
388 REPORTER_ASSERT(reporter, 0.0f == p2.fX);
389 REPORTER_ASSERT(reporter, 0.0f == p2.fY);
390}

◆ test_round_rect_ovals()

static void test_round_rect_ovals ( skiatest::Reporter reporter)
static

Definition at line 332 of file RoundRectTest.cpp.

332 {
333 //----
334 SkRect oval;
336 SkRRect rr1;
338
340 oval = rr1.rect();
342}
SkRect oval
Definition: SkRecords.h:249

◆ test_round_rect_rects()

static void test_round_rect_rects ( skiatest::Reporter reporter)
static

Definition at line 292 of file RoundRectTest.cpp.

292 {
293 SkRect r;
294
295 //----
297
298 empty.setEmpty();
299
301 r = empty.rect();
302 REPORTER_ASSERT(reporter, 0 == r.fLeft && 0 == r.fTop && 0 == r.fRight && 0 == r.fBottom);
303
304 //----
306 SkRRect rr1;
307 rr1.setRectXY(rect, 0, 0);
308
310 r = rr1.rect();
312
313 //----
314 SkPoint radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
315
316 SkRRect rr2;
317 rr2.setRectRadii(rect, radii);
318
320 r = rr2.rect();
322
323 //----
324 SkPoint radii2[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } };
325
326 SkRRect rr3;
327 rr3.setRectRadii(rect, radii2);
329}
SkScalar fBottom
larger y-axis bounds
Definition: extension.cpp:17
SkScalar fLeft
smaller x-axis bounds
Definition: extension.cpp:14
SkScalar fRight
larger x-axis bounds
Definition: extension.cpp:16
SkScalar fTop
smaller y-axis bounds
Definition: extension.cpp:15

◆ test_round_rect_transform()

static void test_round_rect_transform ( skiatest::Reporter reporter)
static

Definition at line 918 of file RoundRectTest.cpp.

918 {
920 {
921 SkRect r = { 0, 0, kWidth, kHeight };
924 }
925 {
926 SkRect r = { SkIntToScalar(5), SkIntToScalar(15),
927 SkIntToScalar(27), SkIntToScalar(34) };
928 SkVector radii[4] = { { 0, SkIntToScalar(1) },
929 { SkIntToScalar(2), SkIntToScalar(3) },
930 { SkIntToScalar(4), SkIntToScalar(5) },
931 { SkIntToScalar(6), SkIntToScalar(7) } };
932 rrect.setRectRadii(r, radii);
934 }
935}
static void test_transform_helper(skiatest::Reporter *reporter, const SkRRect &orig)

◆ test_transform_helper()

static void test_transform_helper ( skiatest::Reporter reporter,
const SkRRect orig 
)
static

Definition at line 557 of file RoundRectTest.cpp.

557 {
558 SkRRect dst;
559 dst.setEmpty();
560
561 // The identity matrix will duplicate the rrect.
562 bool success = orig.transform(SkMatrix::I(), &dst);
563 REPORTER_ASSERT(reporter, success);
564 REPORTER_ASSERT(reporter, orig == dst);
565
566 // Skew and Perspective make transform fail.
568 matrix.reset();
569 matrix.setSkewX(SkIntToScalar(2));
571
572 matrix.reset();
573 matrix.setSkewY(SkIntToScalar(3));
575
576 matrix.reset();
577 matrix.setPerspX(4);
579
580 matrix.reset();
581 matrix.setPerspY(5);
583
584 // Rotation fails.
585 matrix.reset();
586 matrix.setRotate(SkIntToScalar(37));
588
589 // Translate will keep the rect moved, but otherwise the same.
590 matrix.reset();
591 SkScalar translateX = SkIntToScalar(32);
592 SkScalar translateY = SkIntToScalar(15);
593 matrix.setTranslateX(translateX);
594 matrix.setTranslateY(translateY);
595 dst.setEmpty();
596 success = orig.transform(matrix, &dst);
597 REPORTER_ASSERT(reporter, success);
598 for (int i = 0; i < 4; ++i) {
600 orig.radii((SkRRect::Corner) i) == dst.radii((SkRRect::Corner) i));
601 }
602 REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
603 REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
604 REPORTER_ASSERT(reporter, dst.rect().left() == orig.rect().left() + translateX);
605 REPORTER_ASSERT(reporter, dst.rect().top() == orig.rect().top() + translateY);
606
607 // Keeping the translation, but adding skew will make transform fail.
608 matrix.setSkewY(SkIntToScalar(7));
610
611 // Scaling in -x will flip the round rect horizontally.
612 matrix.reset();
613 matrix.setScaleX(SkIntToScalar(-1));
614 dst.setEmpty();
615 success = orig.transform(matrix, &dst);
616 REPORTER_ASSERT(reporter, success);
617 {
618 GET_RADII;
619 // Radii have swapped in x.
620 REPORTER_ASSERT(reporter, origUL == dstUR);
621 REPORTER_ASSERT(reporter, origUR == dstUL);
622 REPORTER_ASSERT(reporter, origLR == dstLL);
623 REPORTER_ASSERT(reporter, origLL == dstLR);
624 }
625 // Width and height remain the same.
626 REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
627 REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
628 // Right and left have swapped (sort of)
629 REPORTER_ASSERT(reporter, orig.rect().right() == -dst.rect().left());
630 // Top has stayed the same.
631 REPORTER_ASSERT(reporter, orig.rect().top() == dst.rect().top());
632
633 // Keeping the scale, but adding a persp will make transform fail.
634 matrix.setPerspX(7);
636
637 // Scaling in -y will flip the round rect vertically.
638 matrix.reset();
639 matrix.setScaleY(SkIntToScalar(-1));
640 dst.setEmpty();
641 success = orig.transform(matrix, &dst);
642 REPORTER_ASSERT(reporter, success);
643 {
644 GET_RADII;
645 // Radii have swapped in y.
646 REPORTER_ASSERT(reporter, origUL == dstLL);
647 REPORTER_ASSERT(reporter, origUR == dstLR);
648 REPORTER_ASSERT(reporter, origLR == dstUR);
649 REPORTER_ASSERT(reporter, origLL == dstUL);
650 }
651 // Width and height remain the same.
652 REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
653 REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
654 // Top and bottom have swapped (sort of)
655 REPORTER_ASSERT(reporter, orig.rect().top() == -dst.rect().bottom());
656 // Left has stayed the same.
657 REPORTER_ASSERT(reporter, orig.rect().left() == dst.rect().left());
658
659 // Scaling in -x and -y will swap in both directions.
660 matrix.reset();
661 matrix.setScaleY(SkIntToScalar(-1));
662 matrix.setScaleX(SkIntToScalar(-1));
663 dst.setEmpty();
664 success = orig.transform(matrix, &dst);
665 REPORTER_ASSERT(reporter, success);
666 {
667 GET_RADII;
668 REPORTER_ASSERT(reporter, origUL == dstLR);
669 REPORTER_ASSERT(reporter, origUR == dstLL);
670 REPORTER_ASSERT(reporter, origLR == dstUL);
671 REPORTER_ASSERT(reporter, origLL == dstUR);
672 }
673 // Width and height remain the same.
674 REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
675 REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
676 REPORTER_ASSERT(reporter, orig.rect().top() == -dst.rect().bottom());
677 REPORTER_ASSERT(reporter, orig.rect().right() == -dst.rect().left());
678
679 // Scale in both directions.
680 SkScalar xScale = SkIntToScalar(3);
681 SkScalar yScale = 3.2f;
682 matrix.reset();
683 matrix.setScaleX(xScale);
684 matrix.setScaleY(yScale);
685 dst.setEmpty();
686 success = orig.transform(matrix, &dst);
687 REPORTER_ASSERT(reporter, success);
688 // Radii are scaled.
689 for (int i = 0; i < 4; ++i) {
691 orig.radii((SkRRect::Corner) i).fX * xScale));
693 orig.radii((SkRRect::Corner) i).fY * yScale));
694 }
696 orig.rect().width() * xScale));
698 orig.rect().height() * yScale));
700 orig.rect().left() * xScale));
702 orig.rect().top() * yScale));
703
704
705 // a-----b d-----a
706 // | | -> | |
707 // | | Rotate 90 | |
708 // d-----c c-----b
709 matrix.reset();
710 matrix.setRotate(SkIntToScalar(90));
711 dst.setEmpty();
712 success = orig.transform(matrix, &dst);
713 REPORTER_ASSERT(reporter, success);
714 {
715 GET_RADII;
716 // Radii have cycled clockwise and swapped their x and y axis.
717 REPORTER_ASSERT(reporter, dstUL.x() == origLL.y());
718 REPORTER_ASSERT(reporter, dstUL.y() == origLL.x());
719 REPORTER_ASSERT(reporter, dstUR.x() == origUL.y());
720 REPORTER_ASSERT(reporter, dstUR.y() == origUL.x());
721 REPORTER_ASSERT(reporter, dstLR.x() == origUR.y());
722 REPORTER_ASSERT(reporter, dstLR.y() == origUR.x());
723 REPORTER_ASSERT(reporter, dstLL.x() == origLR.y());
724 REPORTER_ASSERT(reporter, dstLL.y() == origLR.x());
725 }
726 // Width and height would get swapped.
727 REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
728 REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
729
730 // a-----b b-----a c-----b
731 // | | -> | | -> | |
732 // | | Flip X | | Rotate 90 | |
733 // d-----c c-----d d-----a
734 matrix.reset();
735 matrix.setRotate(SkIntToScalar(90));
736 matrix.postScale(SkIntToScalar(-1), SkIntToScalar(1));
737 dst.setEmpty();
738 success = orig.transform(matrix, &dst);
739 REPORTER_ASSERT(reporter, success);
740 {
741 GET_RADII;
742 REPORTER_ASSERT(reporter, dstUL.x() == origLR.y());
743 REPORTER_ASSERT(reporter, dstUL.y() == origLR.x());
744 REPORTER_ASSERT(reporter, dstUR.x() == origUR.y());
745 REPORTER_ASSERT(reporter, dstUR.y() == origUR.x());
746 REPORTER_ASSERT(reporter, dstLR.x() == origUL.y());
747 REPORTER_ASSERT(reporter, dstLR.y() == origUL.x());
748 REPORTER_ASSERT(reporter, dstLL.x() == origLL.y());
749 REPORTER_ASSERT(reporter, dstLL.y() == origLL.x());
750 }
751 // Width and height would get swapped.
752 REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
753 REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
754
755 // a-----b d-----a c-----b
756 // | | -> | | -> | |
757 // | | Rotate 90 | | Flip Y | |
758 // d-----c c-----b d-----a
759 //
760 // This is the same as Flip X and Rotate 90.
761 matrix.reset();
762 matrix.setScale(SkIntToScalar(1), SkIntToScalar(-1));
763 matrix.postRotate(SkIntToScalar(90));
764 SkRRect dst2;
765 dst2.setEmpty();
766 success = orig.transform(matrix, &dst2);
767 REPORTER_ASSERT(reporter, success);
768 REPORTER_ASSERT(reporter, dst == dst2);
769
770 // a-----b b-----c c-----b
771 // | | -> | | -> | |
772 // | | Rotate 270 | | Flip X | |
773 // d-----c a-----d d-----a
774 matrix.reset();
775 matrix.setScale(SkIntToScalar(-1), SkIntToScalar(1));
776 matrix.postRotate(SkIntToScalar(270));
777 dst2.setEmpty();
778 success = orig.transform(matrix, &dst2);
779 REPORTER_ASSERT(reporter, success);
780 REPORTER_ASSERT(reporter, dst == dst2);
781
782 // a-----b d-----c c-----b
783 // | | -> | | -> | |
784 // | | Flip Y | | Rotate 270 | |
785 // d-----c a-----b d-----a
786 matrix.reset();
787 matrix.setRotate(SkIntToScalar(270));
788 matrix.postScale(SkIntToScalar(1), SkIntToScalar(-1));
789 dst2.setEmpty();
790 success = orig.transform(matrix, &dst2);
791 REPORTER_ASSERT(reporter, success);
792 REPORTER_ASSERT(reporter, dst == dst2);
793
794 // a-----b d-----a a-----d
795 // | | -> | | -> | |
796 // | | Rotate 90 | | Flip X | |
797 // d-----c c-----b b-----c
798 matrix.reset();
799 matrix.setScale(SkIntToScalar(-1), SkIntToScalar(1));
800 matrix.postRotate(SkIntToScalar(90));
801 dst.setEmpty();
802 success = orig.transform(matrix, &dst);
803 REPORTER_ASSERT(reporter, success);
804 {
805 GET_RADII;
806 REPORTER_ASSERT(reporter, dstUL.x() == origUL.y());
807 REPORTER_ASSERT(reporter, dstUL.y() == origUL.x());
808 REPORTER_ASSERT(reporter, dstUR.x() == origLL.y());
809 REPORTER_ASSERT(reporter, dstUR.y() == origLL.x());
810 REPORTER_ASSERT(reporter, dstLR.x() == origLR.y());
811 REPORTER_ASSERT(reporter, dstLR.y() == origLR.x());
812 REPORTER_ASSERT(reporter, dstLL.x() == origUR.y());
813 REPORTER_ASSERT(reporter, dstLL.y() == origUR.x());
814 }
815 // Width and height would get swapped.
816 REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
817 REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
818
819 // a-----b d-----c a-----d
820 // | | -> | | -> | |
821 // | | Flip Y | | Rotate 90 | |
822 // d-----c a-----b b-----c
823 // This is the same as rotate 90 and flip x.
824 matrix.reset();
825 matrix.setRotate(SkIntToScalar(90));
826 matrix.postScale(SkIntToScalar(1), SkIntToScalar(-1));
827 dst2.setEmpty();
828 success = orig.transform(matrix, &dst2);
829 REPORTER_ASSERT(reporter, success);
830 REPORTER_ASSERT(reporter, dst == dst2);
831
832 // a-----b b-----a a-----d
833 // | | -> | | -> | |
834 // | | Flip X | | Rotate 270 | |
835 // d-----c c-----d b-----c
836 matrix.reset();
837 matrix.setRotate(SkIntToScalar(270));
838 matrix.postScale(SkIntToScalar(-1), SkIntToScalar(1));
839 dst2.setEmpty();
840 success = orig.transform(matrix, &dst2);
841 REPORTER_ASSERT(reporter, success);
842 REPORTER_ASSERT(reporter, dst == dst2);
843
844 // a-----b b-----c a-----d
845 // | | -> | | -> | |
846 // | | Rotate 270 | | Flip Y | |
847 // d-----c a-----d b-----c
848 matrix.reset();
849 matrix.setScale(SkIntToScalar(1), SkIntToScalar(-1));
850 matrix.postRotate(SkIntToScalar(270));
851 dst2.setEmpty();
852 success = orig.transform(matrix, &dst2);
853 REPORTER_ASSERT(reporter, success);
854 REPORTER_ASSERT(reporter, dst == dst2);
855
856
857 // a-----b b-----a c-----d b-----c
858 // | | -> | | -> | | -> | |
859 // | | Flip X | | Flip Y | | Rotate 90 | |
860 // d-----c c-----d b-----a a-----d
861 //
862 // This is the same as rotation by 270.
863 matrix.reset();
864 matrix.setRotate(SkIntToScalar(90));
865 matrix.postScale(SkIntToScalar(-1), SkIntToScalar(-1));
866 dst.setEmpty();
867 success = orig.transform(matrix, &dst);
868 REPORTER_ASSERT(reporter, success);
869 {
870 GET_RADII;
871 // Radii have cycled clockwise and swapped their x and y axis.
872 REPORTER_ASSERT(reporter, dstUL.x() == origUR.y());
873 REPORTER_ASSERT(reporter, dstUL.y() == origUR.x());
874 REPORTER_ASSERT(reporter, dstUR.x() == origLR.y());
875 REPORTER_ASSERT(reporter, dstUR.y() == origLR.x());
876 REPORTER_ASSERT(reporter, dstLR.x() == origLL.y());
877 REPORTER_ASSERT(reporter, dstLR.y() == origLL.x());
878 REPORTER_ASSERT(reporter, dstLL.x() == origUL.y());
879 REPORTER_ASSERT(reporter, dstLL.y() == origUL.x());
880 }
881 // Width and height would get swapped.
882 REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
883 REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
884
885 // a-----b b-----c
886 // | | -> | |
887 // | | Rotate 270 | |
888 // d-----c a-----d
889 //
890 dst2.setEmpty();
891 matrix.reset();
892 matrix.setRotate(SkIntToScalar(270));
893 success = orig.transform(matrix, &dst2);
894 REPORTER_ASSERT(reporter, success);
895 REPORTER_ASSERT(reporter, dst == dst2);
896
897 // a-----b b-----a c-----d d-----a
898 // | | -> | | -> | | -> | |
899 // | | Flip X | | Flip Y | | Rotate 270 | |
900 // d-----c c-----d b-----a c-----b
901 //
902 // This is the same as rotation by 90 degrees.
903 matrix.reset();
904 matrix.setRotate(SkIntToScalar(270));
905 matrix.postScale(SkIntToScalar(-1), SkIntToScalar(-1));
906 dst.setEmpty();
907 success = orig.transform(matrix, &dst);
908 REPORTER_ASSERT(reporter, success);
909
910 matrix.reset();
911 matrix.setRotate(SkIntToScalar(90));
912 dst2.setEmpty();
913 success = orig.transform(matrix, &dst2);
914 REPORTER_ASSERT(reporter, dst == dst2);
915
916}
#define GET_RADII
static void assert_transform_failure(skiatest::Reporter *reporter, const SkRRect &orig, const SkMatrix &matrix)
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
void setEmpty()
Definition: SkRRect.h:118
constexpr float left() const
Definition: SkRect.h:734
constexpr float top() const
Definition: SkRect.h:741
constexpr float right() const
Definition: SkRect.h:748

◆ test_tricky_radii()

static void test_tricky_radii ( skiatest::Reporter reporter)
static

Definition at line 26 of file RoundRectTest.cpp.

26 {
27 {
28 // crbug.com/458522
29 SkRRect rr;
30 const SkRect bounds = { 3709, 3709, 3709 + 7402, 3709 + 29825 };
31 const SkScalar rad = 12814;
32 const SkVector vec[] = { { rad, rad }, { 0, rad }, { rad, rad }, { 0, rad } };
33 rr.setRectRadii(bounds, vec);
34 }
35
36 {
37 // crbug.com//463920
38 SkRect r = SkRect::MakeLTRB(0, 0, 1009, 33554432.0);
39 SkVector radii[4] = {
40 { 13.0f, 8.0f }, { 170.0f, 2.0 }, { 256.0f, 33554432.0 }, { 110.0f, 5.0f }
41 };
42 SkRRect rr;
43 rr.setRectRadii(r, radii);
44
47 rr.height());
48 }
49}
SkScalar height() const
Definition: SkRRect.h:102

Variable Documentation

◆ kHeight

const SkScalar kHeight = 100.0f
static

Definition at line 135 of file RoundRectTest.cpp.

◆ kWidth

const SkScalar kWidth = 100.0f
static

Definition at line 134 of file RoundRectTest.cpp.