5 #include "gtest/gtest.h"
12 #define CHECK_POINT_WITH_OFFSET(rr, p, outward_offset) \
13 EXPECT_TRUE(rr.Contains(p)); \
14 EXPECT_FALSE(rr.Contains(p + outward_offset));
22 class SpyPathReceiver :
public PathReceiver {
25 using LineSegment = std::function<void(
const Point&)>;
29 void SpyLineTo(LineSegment line_to) { line_to_ = std::move(line_to); }
31 void SpyCubicTo(CubicSegment cubic_to) { cubic_to_ = std::move(cubic_to); }
34 void MoveTo(
const Point& p2,
bool will_be_closed)
override {}
42 void QuadTo(
const Point& cp,
const Point& p2)
override {}
46 cubic_to_(cp1, cp2, p2);
50 void Close()
override {}
54 CubicSegment cubic_to_;
61 TEST(RoundSuperellipseTest, EmptyDeclaration) {
65 EXPECT_FALSE(rse.
IsRect());
66 EXPECT_FALSE(rse.
IsOval());
88 TEST(RoundSuperellipseTest, DefaultConstructor) {
92 EXPECT_FALSE(rse.
IsRect());
93 EXPECT_FALSE(rse.
IsOval());
103 TEST(RoundSuperellipseTest, EmptyRectConstruction) {
108 EXPECT_FALSE(rse.
IsRect());
109 EXPECT_FALSE(rse.
IsOval());
119 TEST(RoundSuperellipseTest, RectConstructor) {
124 EXPECT_TRUE(rse.
IsRect());
125 EXPECT_FALSE(rse.
IsOval());
135 TEST(RoundSuperellipseTest, InvertedRectConstruction) {
140 EXPECT_TRUE(rse.
IsRect());
141 EXPECT_FALSE(rse.
IsOval());
151 TEST(RoundSuperellipseTest, EmptyOvalConstruction) {
156 EXPECT_FALSE(rse.
IsRect());
157 EXPECT_FALSE(rse.
IsOval());
167 TEST(RoundSuperellipseTest, OvalConstructor) {
172 EXPECT_FALSE(rse.
IsRect());
173 EXPECT_TRUE(rse.
IsOval());
183 TEST(RoundSuperellipseTest, InvertedOvalConstruction) {
188 EXPECT_FALSE(rse.
IsRect());
189 EXPECT_TRUE(rse.
IsOval());
199 TEST(RoundSuperellipseTest, RectRadiusConstructor) {
204 EXPECT_FALSE(rse.
IsRect());
205 EXPECT_FALSE(rse.
IsOval());
215 TEST(RoundSuperellipseTest, RectXYConstructor) {
220 EXPECT_FALSE(rse.
IsRect());
221 EXPECT_FALSE(rse.
IsOval());
231 TEST(RoundSuperellipseTest, RectSizeConstructor) {
236 EXPECT_FALSE(rse.
IsRect());
237 EXPECT_FALSE(rse.
IsOval());
247 TEST(RoundSuperellipseTest, RectRadiiConstructor) {
251 .top_left =
Size(1.0, 1.5),
252 .top_right =
Size(2.0, 2.5f),
253 .bottom_left =
Size(3.0, 3.5f),
254 .bottom_right =
Size(4.0, 4.5f),
258 EXPECT_FALSE(rse.
IsRect());
259 EXPECT_FALSE(rse.
IsOval());
269 TEST(RoundSuperellipseTest, RectRadiiOverflowWidthConstructor) {
273 .top_left =
Size(1.0f, 2.0f),
274 .top_right =
Size(3.0f, 4.0f),
275 .bottom_left =
Size(5.0f, 6.0f),
276 .bottom_right =
Size(7.0f, 8.0f),
283 EXPECT_FALSE(rse.
IsRect());
284 EXPECT_FALSE(rse.
IsOval());
294 TEST(RoundSuperellipseTest, RectRadiiOverflowHeightConstructor) {
298 .top_left =
Size(1.0f, 2.0f),
299 .top_right =
Size(3.0f, 4.0f),
300 .bottom_left =
Size(5.0f, 6.0f),
301 .bottom_right =
Size(7.0f, 8.0f),
308 EXPECT_FALSE(rse.
IsRect());
309 EXPECT_FALSE(rse.
IsOval());
319 TEST(RoundSuperellipseTest, Shift) {
323 .top_left =
Size(1.0f, 2.0f),
324 .top_right =
Size(3.0f, 4.0f),
325 .bottom_left =
Size(5.0f, 6.0f),
326 .bottom_right =
Size(7.0f, 8.0f),
330 EXPECT_FALSE(shifted.IsEmpty());
331 EXPECT_FALSE(shifted.IsRect());
332 EXPECT_FALSE(shifted.IsOval());
333 EXPECT_TRUE(shifted.IsFinite());
334 EXPECT_FALSE(shifted.GetBounds().IsEmpty());
335 EXPECT_EQ(shifted.GetBounds(),
Rect::MakeLTRB(15.0f, 16.0f, 45.0f, 46.0f));
336 EXPECT_EQ(shifted.GetRadii().top_left,
Size(1.0f, 2.0f));
337 EXPECT_EQ(shifted.GetRadii().top_right,
Size(3.0f, 4.0f));
338 EXPECT_EQ(shifted.GetRadii().bottom_left,
Size(5.0f, 6.0f));
339 EXPECT_EQ(shifted.GetRadii().bottom_right,
Size(7.0f, 8.0f));
344 .top_left =
Size(1.0f, 2.0f),
345 .top_right =
Size(3.0f, 4.0f),
346 .bottom_left =
Size(5.0f, 6.0f),
347 .bottom_right =
Size(7.0f, 8.0f),
351 TEST(RoundSuperellipseTest, ExpandScalar) {
355 .top_left =
Size(1.0f, 2.0f),
356 .top_right =
Size(3.0f, 4.0f),
357 .bottom_left =
Size(5.0f, 6.0f),
358 .bottom_right =
Size(7.0f, 8.0f),
362 EXPECT_FALSE(expanded.IsEmpty());
363 EXPECT_FALSE(expanded.IsRect());
364 EXPECT_FALSE(expanded.IsOval());
365 EXPECT_TRUE(expanded.IsFinite());
366 EXPECT_FALSE(expanded.GetBounds().IsEmpty());
367 EXPECT_EQ(expanded.GetBounds(),
Rect::MakeLTRB(5.0f, 5.0f, 45.0f, 45.0f));
368 EXPECT_EQ(expanded.GetRadii().top_left,
Size(1.0f, 2.0f));
369 EXPECT_EQ(expanded.GetRadii().top_right,
Size(3.0f, 4.0f));
370 EXPECT_EQ(expanded.GetRadii().bottom_left,
Size(5.0f, 6.0f));
371 EXPECT_EQ(expanded.GetRadii().bottom_right,
Size(7.0f, 8.0f));
376 .top_left =
Size(1.0f, 2.0f),
377 .top_right =
Size(3.0f, 4.0f),
378 .bottom_left =
Size(5.0f, 6.0f),
379 .bottom_right =
Size(7.0f, 8.0f),
383 TEST(RoundSuperellipseTest, ExpandTwoScalars) {
387 .top_left =
Size(1.0f, 2.0f),
388 .top_right =
Size(3.0f, 4.0f),
389 .bottom_left =
Size(5.0f, 6.0f),
390 .bottom_right =
Size(7.0f, 8.0f),
394 EXPECT_FALSE(expanded.IsEmpty());
395 EXPECT_FALSE(expanded.IsRect());
396 EXPECT_FALSE(expanded.IsOval());
397 EXPECT_TRUE(expanded.IsFinite());
398 EXPECT_FALSE(expanded.GetBounds().IsEmpty());
399 EXPECT_EQ(expanded.GetBounds(),
Rect::MakeLTRB(5.0f, 4.0f, 45.0f, 46.0f));
400 EXPECT_EQ(expanded.GetRadii().top_left,
Size(1.0f, 2.0f));
401 EXPECT_EQ(expanded.GetRadii().top_right,
Size(3.0f, 4.0f));
402 EXPECT_EQ(expanded.GetRadii().bottom_left,
Size(5.0f, 6.0f));
403 EXPECT_EQ(expanded.GetRadii().bottom_right,
Size(7.0f, 8.0f));
408 .top_left =
Size(1.0f, 2.0f),
409 .top_right =
Size(3.0f, 4.0f),
410 .bottom_left =
Size(5.0f, 6.0f),
411 .bottom_right =
Size(7.0f, 8.0f),
415 TEST(RoundSuperellipseTest, ExpandFourScalars) {
419 .top_left =
Size(1.0f, 2.0f),
420 .top_right =
Size(3.0f, 4.0f),
421 .bottom_left =
Size(5.0f, 6.0f),
422 .bottom_right =
Size(7.0f, 8.0f),
426 EXPECT_FALSE(expanded.IsEmpty());
427 EXPECT_FALSE(expanded.IsRect());
428 EXPECT_FALSE(expanded.IsOval());
429 EXPECT_TRUE(expanded.IsFinite());
430 EXPECT_FALSE(expanded.GetBounds().IsEmpty());
431 EXPECT_EQ(expanded.GetBounds(),
Rect::MakeLTRB(5.0f, 4.0f, 47.0f, 48.0f));
432 EXPECT_EQ(expanded.GetRadii().top_left,
Size(1.0f, 2.0f));
433 EXPECT_EQ(expanded.GetRadii().top_right,
Size(3.0f, 4.0f));
434 EXPECT_EQ(expanded.GetRadii().bottom_left,
Size(5.0f, 6.0f));
435 EXPECT_EQ(expanded.GetRadii().bottom_right,
Size(7.0f, 8.0f));
440 .top_left =
Size(1.0f, 2.0f),
441 .top_right =
Size(3.0f, 4.0f),
442 .bottom_left =
Size(5.0f, 6.0f),
443 .bottom_right =
Size(7.0f, 8.0f),
447 TEST(RoundSuperellipseTest, ContractScalar) {
451 .top_left =
Size(1.0f, 2.0f),
452 .top_right =
Size(3.0f, 4.0f),
453 .bottom_left =
Size(5.0f, 6.0f),
454 .bottom_right =
Size(7.0f, 8.0f),
458 EXPECT_FALSE(expanded.IsEmpty());
459 EXPECT_FALSE(expanded.IsRect());
460 EXPECT_FALSE(expanded.IsOval());
461 EXPECT_TRUE(expanded.IsFinite());
462 EXPECT_FALSE(expanded.GetBounds().IsEmpty());
463 EXPECT_EQ(expanded.GetBounds(),
Rect::MakeLTRB(12.0f, 12.0f, 38.0f, 38.0f));
464 EXPECT_EQ(expanded.GetRadii().top_left,
Size(1.0f, 2.0f));
465 EXPECT_EQ(expanded.GetRadii().top_right,
Size(3.0f, 4.0f));
466 EXPECT_EQ(expanded.GetRadii().bottom_left,
Size(5.0f, 6.0f));
467 EXPECT_EQ(expanded.GetRadii().bottom_right,
Size(7.0f, 8.0f));
472 .top_left =
Size(1.0f, 2.0f),
473 .top_right =
Size(3.0f, 4.0f),
474 .bottom_left =
Size(5.0f, 6.0f),
475 .bottom_right =
Size(7.0f, 8.0f),
479 TEST(RoundSuperellipseTest, ContractTwoScalars) {
483 .top_left =
Size(1.0f, 2.0f),
484 .top_right =
Size(3.0f, 4.0f),
485 .bottom_left =
Size(5.0f, 6.0f),
486 .bottom_right =
Size(7.0f, 8.0f),
490 EXPECT_FALSE(expanded.IsEmpty());
491 EXPECT_FALSE(expanded.IsRect());
492 EXPECT_FALSE(expanded.IsOval());
493 EXPECT_TRUE(expanded.IsFinite());
494 EXPECT_FALSE(expanded.GetBounds().IsEmpty());
495 EXPECT_EQ(expanded.GetBounds(),
Rect::MakeLTRB(11.0f, 12.0f, 39.0f, 38.0f));
496 EXPECT_EQ(expanded.GetRadii().top_left,
Size(1.0f, 2.0f));
497 EXPECT_EQ(expanded.GetRadii().top_right,
Size(3.0f, 4.0f));
498 EXPECT_EQ(expanded.GetRadii().bottom_left,
Size(5.0f, 6.0f));
499 EXPECT_EQ(expanded.GetRadii().bottom_right,
Size(7.0f, 8.0f));
504 .top_left =
Size(1.0f, 2.0f),
505 .top_right =
Size(3.0f, 4.0f),
506 .bottom_left =
Size(5.0f, 6.0f),
507 .bottom_right =
Size(7.0f, 8.0f),
511 TEST(RoundSuperellipseTest, ContractFourScalars) {
515 .top_left =
Size(1.0f, 2.0f),
516 .top_right =
Size(3.0f, 4.0f),
517 .bottom_left =
Size(5.0f, 6.0f),
518 .bottom_right =
Size(7.0f, 8.0f),
522 EXPECT_FALSE(expanded.IsEmpty());
523 EXPECT_FALSE(expanded.IsRect());
524 EXPECT_FALSE(expanded.IsOval());
525 EXPECT_TRUE(expanded.IsFinite());
526 EXPECT_FALSE(expanded.GetBounds().IsEmpty());
527 EXPECT_EQ(expanded.GetBounds(),
Rect::MakeLTRB(11.0f, 11.5f, 38.0f, 37.5f));
528 EXPECT_EQ(expanded.GetRadii().top_left,
Size(1.0f, 2.0f));
529 EXPECT_EQ(expanded.GetRadii().top_right,
Size(3.0f, 4.0f));
530 EXPECT_EQ(expanded.GetRadii().bottom_left,
Size(5.0f, 6.0f));
531 EXPECT_EQ(expanded.GetRadii().bottom_right,
Size(7.0f, 8.0f));
536 .top_left =
Size(1.0f, 2.0f),
537 .top_right =
Size(3.0f, 4.0f),
538 .bottom_left =
Size(5.0f, 6.0f),
539 .bottom_right =
Size(7.0f, 8.0f),
543 TEST(RoundSuperellipseTest, ContractAndRequireRadiiAdjustment) {
547 .top_left =
Size(1.0f, 2.0f),
548 .top_right =
Size(3.0f, 4.0f),
549 .bottom_left =
Size(5.0f, 6.0f),
550 .bottom_right =
Size(7.0f, 8.0f),
558 EXPECT_FALSE(expanded.IsEmpty());
559 EXPECT_FALSE(expanded.IsRect());
560 EXPECT_FALSE(expanded.IsOval());
561 EXPECT_TRUE(expanded.IsFinite());
562 EXPECT_FALSE(expanded.GetBounds().IsEmpty());
563 EXPECT_EQ(expanded.GetBounds(),
Rect::MakeLTRB(22.0f, 22.0f, 28.0f, 28.0f));
564 EXPECT_EQ(expanded.GetRadii().top_left,
Size(0.5f, 1.0f));
565 EXPECT_EQ(expanded.GetRadii().top_right,
Size(1.5f, 2.0f));
566 EXPECT_EQ(expanded.GetRadii().bottom_left,
Size(2.5f, 3.0f));
567 EXPECT_EQ(expanded.GetRadii().bottom_right,
Size(3.5f, 4.0f));
574 .top_left =
Size(1.0f, 2.0f),
575 .top_right =
Size(3.0f, 4.0f),
576 .bottom_left =
Size(5.0f, 6.0f),
577 .bottom_right =
Size(7.0f, 8.0f),
586 .top_left =
Size(0.5f, 1.0f),
587 .top_right =
Size(1.5f, 2.0f),
588 .bottom_left =
Size(2.5f, 3.0f),
589 .bottom_right =
Size(3.5f, 4.0f),
593 TEST(RoundSuperellipseTest, NoCornerRoundSuperellipseContains) {
600 EXPECT_TRUE(no_corners.Contains({-50, -50}));
603 EXPECT_TRUE(no_corners.Contains({-50, 49.99}));
604 EXPECT_TRUE(no_corners.Contains({49.99, -50}));
605 EXPECT_TRUE(no_corners.Contains({49.99, 49.99}));
606 EXPECT_FALSE(no_corners.Contains({-50.01, -50}));
607 EXPECT_FALSE(no_corners.Contains({-50, -50.01}));
608 EXPECT_FALSE(no_corners.Contains({-50.01, 50}));
609 EXPECT_FALSE(no_corners.Contains({-50, 50.01}));
610 EXPECT_FALSE(no_corners.Contains({50.01, -50}));
611 EXPECT_FALSE(no_corners.Contains({50, -50.01}));
612 EXPECT_FALSE(no_corners.Contains({50.01, 50}));
613 EXPECT_FALSE(no_corners.Contains({50, 50.01}));
616 TEST(RoundSuperellipseTest, TinyCornerContains) {
623 EXPECT_FALSE(tiny_corners.Contains({-50, -50}));
624 EXPECT_FALSE(tiny_corners.Contains({-50, 50}));
625 EXPECT_FALSE(tiny_corners.Contains({50, -50}));
626 EXPECT_FALSE(tiny_corners.Contains({50, 50}));
629 TEST(RoundSuperellipseTest, UniformSquareContains) {
634 #define CHECK_POINT_AND_MIRRORS(p) \
635 CHECK_POINT_WITH_OFFSET(rr, (p), Point(0.02, 0.02)); \
636 CHECK_POINT_WITH_OFFSET(rr, (p) * Point(1, -1), Point(0.02, -0.02)); \
637 CHECK_POINT_WITH_OFFSET(rr, (p) * Point(-1, 1), Point(-0.02, 0.02)); \
638 CHECK_POINT_WITH_OFFSET(rr, (p) * Point(-1, -1), Point(-0.02, -0.02));
647 #undef CHECK_POINT_AND_MIRRORS
650 TEST(RoundSuperellipseTest, UniformEllipticalContains) {
655 #define CHECK_POINT_AND_MIRRORS(p) \
656 CHECK_POINT_WITH_OFFSET(rr, (p), Point(0.02, 0.02)); \
657 CHECK_POINT_WITH_OFFSET(rr, (p) * Point(1, -1), Point(0.02, -0.02)); \
658 CHECK_POINT_WITH_OFFSET(rr, (p) * Point(-1, 1), Point(-0.02, 0.02)); \
659 CHECK_POINT_WITH_OFFSET(rr, (p) * Point(-1, -1), Point(-0.02, -0.02));
668 #undef CHECK_POINT_AND_MIRRORS
671 TEST(RoundSuperellipseTest, UniformRectangularContains) {
678 #define CHECK_POINT_AND_MIRRORS(p) \
679 CHECK_POINT_WITH_OFFSET(rr, (p - center) * Point(1, 1) + center, \
680 Point(0.02, 0.02)); \
681 CHECK_POINT_WITH_OFFSET(rr, (p - center) * Point(1, -1) + center, \
682 Point(0.02, -0.02)); \
683 CHECK_POINT_WITH_OFFSET(rr, (p - center) * Point(-1, 1) + center, \
684 Point(-0.02, 0.02)); \
685 CHECK_POINT_WITH_OFFSET(rr, (p - center) * Point(-1, -1) + center, \
686 Point(-0.02, -0.02));
698 #undef CHECK_POINT_AND_MIRRORS
701 TEST(RoundSuperellipseTest, SlimDiagonalContains) {
707 .top_left =
Size(1.0, 1.0),
708 .top_right =
Size(99.0, 99.0),
709 .bottom_left =
Size(99.0, 99.0),
710 .bottom_right =
Size(1.0, 1.0),
713 EXPECT_TRUE(rr.Contains(
Point{0, 0}));
714 EXPECT_FALSE(rr.Contains(
Point{-49.999, -49.999}));
715 EXPECT_FALSE(rr.Contains(
Point{-49.999, 49.999}));
716 EXPECT_FALSE(rr.Contains(
Point{49.999, 49.999}));
717 EXPECT_FALSE(rr.Contains(
Point{49.999, -49.999}));
724 #define CHECK_DIAGONAL_POINTS(p) \
725 CHECK_POINT_WITH_OFFSET(rr, (p), Point(0.02, -0.02)); \
726 CHECK_POINT_WITH_OFFSET(rr, (p) * Point(-1, -1), Point(-0.02, 0.02));
735 #undef CHECK_POINT_AND_MIRRORS
738 TEST(RoundSuperellipseTest, PointsOutsideOfSharpCorner) {
746 .top_left =
Size(0.0, 0.0),
747 .top_right =
Size(3.0, 3.0),
748 .bottom_left =
Size(0.0, 0.0),
749 .bottom_right =
Size(3.0, 3.0),
752 EXPECT_FALSE(rr.Contains(
Point{147.0, 14.0}));
756 PathForRectangularRseWithShapeCornersShouldBeWithinBounds) {
767 .top_left =
Size(14.0, 14.0),
768 .top_right =
Size(14.0, 14.0),
769 .bottom_left =
Size(0.0, 0.0),
770 .bottom_right =
Size(0.0, 0.0),
772 SpyPathReceiver receiver;
775 receiver.SpyCubicTo([&](
const Point& cp1,
const Point& cp2,
const Point& p2) {
TEST(AllocationSizeTest, CanCreateTypedAllocations)
void MoveTo(PathBuilder *builder, Scalar x, Scalar y)
void LineTo(PathBuilder *builder, Scalar x, Scalar y)
void CubicTo(PathBuilder *builder, Scalar x1, Scalar y1, Scalar x2, Scalar y2, Scalar x3, Scalar y3)
void Close(PathBuilder *builder)
#define CHECK_DIAGONAL_POINTS(p)
#define CHECK_POINT_WITH_OFFSET(rr, p, outward_offset)
#define CHECK_POINT_AND_MIRRORS(p)
constexpr const RoundingRadii & GetRadii() const
static RoundSuperellipse MakeRectRadii(const Rect &rect, const RoundingRadii &radii)
constexpr bool IsOval() const
constexpr bool IsFinite() const
constexpr bool IsEmpty() const
RoundSuperellipse Expand(Scalar left, Scalar top, Scalar right, Scalar bottom) const
Returns a round rectangle with expanded edges. Negative expansion results in shrinking.
constexpr bool IsRect() const
static RoundSuperellipse MakeOval(const Rect &rect)
RoundSuperellipse Shift(Scalar dx, Scalar dy) const
Returns a new round rectangle translated by the given offset.
static RoundSuperellipse MakeRect(const Rect &rect)
static RoundSuperellipse MakeRectRadius(const Rect &rect, Scalar radius)
constexpr const Rect & GetBounds() const
static RoundSuperellipse MakeRectXY(const Rect &rect, Scalar x_radius, Scalar y_radius)
static RoundSuperellipseParam MakeBoundsRadii(const Rect &bounds, const RoundingRadii &radii)
void Dispatch(PathReceiver &receiver) const
constexpr static RoundingRadii MakeRadii(Size radii)
constexpr auto GetBottom() const
constexpr bool ContainsInclusive(const TPoint< Type > &p) const
Returns true iff the provided point |p| is inside the closed-range interior of this rectangle.
constexpr auto GetTop() const
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
constexpr auto GetLeft() const
constexpr auto GetRight() const
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
constexpr Point GetCenter() const
Get the center point as a |Point|.
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)