Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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

Definition at line 546 of file RoundRectTest.cpp.

556 {
557 SkRRect dst;
558 dst.setEmpty();
559
560 // The identity matrix will duplicate the rrect.
561 bool success = orig.transform(SkMatrix::I(), &dst);
562 REPORTER_ASSERT(reporter, success);
563 REPORTER_ASSERT(reporter, orig == dst);
564
565 // Skew and Perspective make transform fail.
567 matrix.reset();
568 matrix.setSkewX(SkIntToScalar(2));
569 assert_transform_failure(reporter, orig, matrix);
570
571 matrix.reset();
572 matrix.setSkewY(SkIntToScalar(3));
573 assert_transform_failure(reporter, orig, matrix);
574
575 matrix.reset();
576 matrix.setPerspX(4);
577 assert_transform_failure(reporter, orig, matrix);
578
579 matrix.reset();
580 matrix.setPerspY(5);
581 assert_transform_failure(reporter, orig, matrix);
582
583 // Rotation fails.
584 matrix.reset();
585 matrix.setRotate(SkIntToScalar(37));
586 assert_transform_failure(reporter, orig, matrix);
587
588 // Translate will keep the rect moved, but otherwise the same.
589 matrix.reset();
590 SkScalar translateX = SkIntToScalar(32);
591 SkScalar translateY = SkIntToScalar(15);
592 matrix.setTranslateX(translateX);
593 matrix.setTranslateY(translateY);
594 dst.setEmpty();
595 success = orig.transform(matrix, &dst);
596 REPORTER_ASSERT(reporter, success);
597 for (int i = 0; i < 4; ++i) {
599 orig.radii((SkRRect::Corner) i) == dst.radii((SkRRect::Corner) i));
600 }
601 REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
602 REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
603 REPORTER_ASSERT(reporter, dst.rect().left() == orig.rect().left() + translateX);
604 REPORTER_ASSERT(reporter, dst.rect().top() == orig.rect().top() + translateY);
605
606 // Keeping the translation, but adding skew will make transform fail.
607 matrix.setSkewY(SkIntToScalar(7));
608 assert_transform_failure(reporter, orig, matrix);
609
610 // Scaling in -x will flip the round rect horizontally.
611 matrix.reset();
612 matrix.setScaleX(SkIntToScalar(-1));
613 dst.setEmpty();
614 success = orig.transform(matrix, &dst);
615 REPORTER_ASSERT(reporter, success);
616 {
617 GET_RADII;
618 // Radii have swapped in x.
619 REPORTER_ASSERT(reporter, origUL == dstUR);
620 REPORTER_ASSERT(reporter, origUR == dstUL);
621 REPORTER_ASSERT(reporter, origLR == dstLL);
622 REPORTER_ASSERT(reporter, origLL == dstLR);
623 }
624 // Width and height remain the same.
625 REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
626 REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
627 // Right and left have swapped (sort of)
628 REPORTER_ASSERT(reporter, orig.rect().right() == -dst.rect().left());
629 // Top has stayed the same.
630 REPORTER_ASSERT(reporter, orig.rect().top() == dst.rect().top());
631
632 // Keeping the scale, but adding a persp will make transform fail.
633 matrix.setPerspX(7);
634 assert_transform_failure(reporter, orig, matrix);
635
636 // Scaling in -y will flip the round rect vertically.
637 matrix.reset();
638 matrix.setScaleY(SkIntToScalar(-1));
639 dst.setEmpty();
640 success = orig.transform(matrix, &dst);
641 REPORTER_ASSERT(reporter, success);
642 {
643 GET_RADII;
644 // Radii have swapped in y.
645 REPORTER_ASSERT(reporter, origUL == dstLL);
646 REPORTER_ASSERT(reporter, origUR == dstLR);
647 REPORTER_ASSERT(reporter, origLR == dstUR);
648 REPORTER_ASSERT(reporter, origLL == dstUL);
649 }
650 // Width and height remain the same.
651 REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
652 REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
653 // Top and bottom have swapped (sort of)
654 REPORTER_ASSERT(reporter, orig.rect().top() == -dst.rect().bottom());
655 // Left has stayed the same.
656 REPORTER_ASSERT(reporter, orig.rect().left() == dst.rect().left());
657
658 // Scaling in -x and -y will swap in both directions.
659 matrix.reset();
660 matrix.setScaleY(SkIntToScalar(-1));
661 matrix.setScaleX(SkIntToScalar(-1));
662 dst.setEmpty();
663 success = orig.transform(matrix, &dst);
664 REPORTER_ASSERT(reporter, success);
665 {
666 GET_RADII;
667 REPORTER_ASSERT(reporter, origUL == dstLR);
668 REPORTER_ASSERT(reporter, origUR == dstLL);
669 REPORTER_ASSERT(reporter, origLR == dstUL);
670 REPORTER_ASSERT(reporter, origLL == dstUR);
671 }
672 // Width and height remain the same.
673 REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().width());
674 REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().height());
675 REPORTER_ASSERT(reporter, orig.rect().top() == -dst.rect().bottom());
676 REPORTER_ASSERT(reporter, orig.rect().right() == -dst.rect().left());
677
678 // Scale in both directions.
679 SkScalar xScale = SkIntToScalar(3);
680 SkScalar yScale = 3.2f;
681 matrix.reset();
682 matrix.setScaleX(xScale);
683 matrix.setScaleY(yScale);
684 dst.setEmpty();
685 success = orig.transform(matrix, &dst);
686 REPORTER_ASSERT(reporter, success);
687 // Radii are scaled.
688 for (int i = 0; i < 4; ++i) {
690 orig.radii((SkRRect::Corner) i).fX * xScale));
692 orig.radii((SkRRect::Corner) i).fY * yScale));
693 }
695 orig.rect().width() * xScale));
697 orig.rect().height() * yScale));
699 orig.rect().left() * xScale));
701 orig.rect().top() * yScale));
702
703
704 // a-----b d-----a
705 // | | -> | |
706 // | | Rotate 90 | |
707 // d-----c c-----b
708 matrix.reset();
709 matrix.setRotate(SkIntToScalar(90));
710 dst.setEmpty();
711 success = orig.transform(matrix, &dst);
712 REPORTER_ASSERT(reporter, success);
713 {
714 GET_RADII;
715 // Radii have cycled clockwise and swapped their x and y axis.
716 REPORTER_ASSERT(reporter, dstUL.x() == origLL.y());
717 REPORTER_ASSERT(reporter, dstUL.y() == origLL.x());
718 REPORTER_ASSERT(reporter, dstUR.x() == origUL.y());
719 REPORTER_ASSERT(reporter, dstUR.y() == origUL.x());
720 REPORTER_ASSERT(reporter, dstLR.x() == origUR.y());
721 REPORTER_ASSERT(reporter, dstLR.y() == origUR.x());
722 REPORTER_ASSERT(reporter, dstLL.x() == origLR.y());
723 REPORTER_ASSERT(reporter, dstLL.y() == origLR.x());
724 }
725 // Width and height would get swapped.
726 REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
727 REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
728
729 // a-----b b-----a c-----b
730 // | | -> | | -> | |
731 // | | Flip X | | Rotate 90 | |
732 // d-----c c-----d d-----a
733 matrix.reset();
734 matrix.setRotate(SkIntToScalar(90));
735 matrix.postScale(SkIntToScalar(-1), SkIntToScalar(1));
736 dst.setEmpty();
737 success = orig.transform(matrix, &dst);
738 REPORTER_ASSERT(reporter, success);
739 {
740 GET_RADII;
741 REPORTER_ASSERT(reporter, dstUL.x() == origLR.y());
742 REPORTER_ASSERT(reporter, dstUL.y() == origLR.x());
743 REPORTER_ASSERT(reporter, dstUR.x() == origUR.y());
744 REPORTER_ASSERT(reporter, dstUR.y() == origUR.x());
745 REPORTER_ASSERT(reporter, dstLR.x() == origUL.y());
746 REPORTER_ASSERT(reporter, dstLR.y() == origUL.x());
747 REPORTER_ASSERT(reporter, dstLL.x() == origLL.y());
748 REPORTER_ASSERT(reporter, dstLL.y() == origLL.x());
749 }
750 // Width and height would get swapped.
751 REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
752 REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
753
754 // a-----b d-----a c-----b
755 // | | -> | | -> | |
756 // | | Rotate 90 | | Flip Y | |
757 // d-----c c-----b d-----a
758 //
759 // This is the same as Flip X and Rotate 90.
760 matrix.reset();
761 matrix.setScale(SkIntToScalar(1), SkIntToScalar(-1));
762 matrix.postRotate(SkIntToScalar(90));
763 SkRRect dst2;
764 dst2.setEmpty();
765 success = orig.transform(matrix, &dst2);
766 REPORTER_ASSERT(reporter, success);
767 REPORTER_ASSERT(reporter, dst == dst2);
768
769 // a-----b b-----c c-----b
770 // | | -> | | -> | |
771 // | | Rotate 270 | | Flip X | |
772 // d-----c a-----d d-----a
773 matrix.reset();
774 matrix.setScale(SkIntToScalar(-1), SkIntToScalar(1));
775 matrix.postRotate(SkIntToScalar(270));
776 dst2.setEmpty();
777 success = orig.transform(matrix, &dst2);
778 REPORTER_ASSERT(reporter, success);
779 REPORTER_ASSERT(reporter, dst == dst2);
780
781 // a-----b d-----c c-----b
782 // | | -> | | -> | |
783 // | | Flip Y | | Rotate 270 | |
784 // d-----c a-----b d-----a
785 matrix.reset();
786 matrix.setRotate(SkIntToScalar(270));
787 matrix.postScale(SkIntToScalar(1), SkIntToScalar(-1));
788 dst2.setEmpty();
789 success = orig.transform(matrix, &dst2);
790 REPORTER_ASSERT(reporter, success);
791 REPORTER_ASSERT(reporter, dst == dst2);
792
793 // a-----b d-----a a-----d
794 // | | -> | | -> | |
795 // | | Rotate 90 | | Flip X | |
796 // d-----c c-----b b-----c
797 matrix.reset();
798 matrix.setScale(SkIntToScalar(-1), SkIntToScalar(1));
799 matrix.postRotate(SkIntToScalar(90));
800 dst.setEmpty();
801 success = orig.transform(matrix, &dst);
802 REPORTER_ASSERT(reporter, success);
803 {
804 GET_RADII;
805 REPORTER_ASSERT(reporter, dstUL.x() == origUL.y());
806 REPORTER_ASSERT(reporter, dstUL.y() == origUL.x());
807 REPORTER_ASSERT(reporter, dstUR.x() == origLL.y());
808 REPORTER_ASSERT(reporter, dstUR.y() == origLL.x());
809 REPORTER_ASSERT(reporter, dstLR.x() == origLR.y());
810 REPORTER_ASSERT(reporter, dstLR.y() == origLR.x());
811 REPORTER_ASSERT(reporter, dstLL.x() == origUR.y());
812 REPORTER_ASSERT(reporter, dstLL.y() == origUR.x());
813 }
814 // Width and height would get swapped.
815 REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
816 REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
817
818 // a-----b d-----c a-----d
819 // | | -> | | -> | |
820 // | | Flip Y | | Rotate 90 | |
821 // d-----c a-----b b-----c
822 // This is the same as rotate 90 and flip x.
823 matrix.reset();
824 matrix.setRotate(SkIntToScalar(90));
825 matrix.postScale(SkIntToScalar(1), SkIntToScalar(-1));
826 dst2.setEmpty();
827 success = orig.transform(matrix, &dst2);
828 REPORTER_ASSERT(reporter, success);
829 REPORTER_ASSERT(reporter, dst == dst2);
830
831 // a-----b b-----a a-----d
832 // | | -> | | -> | |
833 // | | Flip X | | Rotate 270 | |
834 // d-----c c-----d b-----c
835 matrix.reset();
836 matrix.setRotate(SkIntToScalar(270));
837 matrix.postScale(SkIntToScalar(-1), SkIntToScalar(1));
838 dst2.setEmpty();
839 success = orig.transform(matrix, &dst2);
840 REPORTER_ASSERT(reporter, success);
841 REPORTER_ASSERT(reporter, dst == dst2);
842
843 // a-----b b-----c a-----d
844 // | | -> | | -> | |
845 // | | Rotate 270 | | Flip Y | |
846 // d-----c a-----d b-----c
847 matrix.reset();
848 matrix.setScale(SkIntToScalar(1), SkIntToScalar(-1));
849 matrix.postRotate(SkIntToScalar(270));
850 dst2.setEmpty();
851 success = orig.transform(matrix, &dst2);
852 REPORTER_ASSERT(reporter, success);
853 REPORTER_ASSERT(reporter, dst == dst2);
854
855
856 // a-----b b-----a c-----d b-----c
857 // | | -> | | -> | | -> | |
858 // | | Flip X | | Flip Y | | Rotate 90 | |
859 // d-----c c-----d b-----a a-----d
860 //
861 // This is the same as rotation by 270.
862 matrix.reset();
863 matrix.setRotate(SkIntToScalar(90));
864 matrix.postScale(SkIntToScalar(-1), SkIntToScalar(-1));
865 dst.setEmpty();
866 success = orig.transform(matrix, &dst);
867 REPORTER_ASSERT(reporter, success);
868 {
869 GET_RADII;
870 // Radii have cycled clockwise and swapped their x and y axis.
871 REPORTER_ASSERT(reporter, dstUL.x() == origUR.y());
872 REPORTER_ASSERT(reporter, dstUL.y() == origUR.x());
873 REPORTER_ASSERT(reporter, dstUR.x() == origLR.y());
874 REPORTER_ASSERT(reporter, dstUR.y() == origLR.x());
875 REPORTER_ASSERT(reporter, dstLR.x() == origLL.y());
876 REPORTER_ASSERT(reporter, dstLR.y() == origLL.x());
877 REPORTER_ASSERT(reporter, dstLL.x() == origUL.y());
878 REPORTER_ASSERT(reporter, dstLL.y() == origUL.x());
879 }
880 // Width and height would get swapped.
881 REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
882 REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
883
884 // a-----b b-----c
885 // | | -> | |
886 // | | Rotate 270 | |
887 // d-----c a-----d
888 //
889 dst2.setEmpty();
890 matrix.reset();
891 matrix.setRotate(SkIntToScalar(270));
892 success = orig.transform(matrix, &dst2);
893 REPORTER_ASSERT(reporter, success);
894 REPORTER_ASSERT(reporter, dst == dst2);
895
896 // a-----b b-----a c-----d d-----a
897 // | | -> | | -> | | -> | |
898 // | | Flip X | | Flip Y | | Rotate 270 | |
899 // d-----c c-----d b-----a c-----b
900 //
901 // This is the same as rotation by 90 degrees.
902 matrix.reset();
903 matrix.setRotate(SkIntToScalar(270));
904 matrix.postScale(SkIntToScalar(-1), SkIntToScalar(-1));
905 dst.setEmpty();
906 success = orig.transform(matrix, &dst);
907 REPORTER_ASSERT(reporter, success);
908
909 matrix.reset();
910 matrix.setRotate(SkIntToScalar(90));
911 dst2.setEmpty();
912 success = orig.transform(matrix, &dst2);
913 REPORTER_ASSERT(reporter, dst == dst2);
914
915}
916
919 {
920 SkRect r = { 0, 0, kWidth, kHeight };
923 }
924 {
925 SkRect r = { SkIntToScalar(5), SkIntToScalar(15),
926 SkIntToScalar(27), SkIntToScalar(34) };
927 SkVector radii[4] = { { 0, SkIntToScalar(1) },
928 { SkIntToScalar(2), SkIntToScalar(3) },
929 { SkIntToScalar(4), SkIntToScalar(5) },
930 { SkIntToScalar(6), SkIntToScalar(7) } };
931 rrect.setRectRadii(r, radii);
933 }
934}
935
936// Test out the case where an oval already off in space is translated/scaled
937// further off into space - yielding numerical issues when the rect & radii
938// are transformed separatly
939// BUG=skia:2696
942 SkRect r = { 28443.8594f, 53.1428604f, 28446.7148f, 56.0000038f };
943 rrect.setOval(r);
944
945 SkMatrix xform;
946 xform.setAll(2.44f, 0.0f, 485411.7f,
947 0.0f, 2.44f, -438.7f,
948 0.0f, 0.0f, 1.0f);
949 SkRRect dst;
950
951 bool success = rrect.transform(xform, &dst);
952 REPORTER_ASSERT(reporter, success);
953
954 SkScalar halfWidth = SkScalarHalf(dst.width());
955 SkScalar halfHeight = SkScalarHalf(dst.height());
956
957 for (int i = 0; i < 4; ++i) {
959 SkScalarNearlyEqual(dst.radii((SkRRect::Corner)i).fX, halfWidth));
961 SkScalarNearlyEqual(dst.radii((SkRRect::Corner)i).fY, halfHeight));
962 }
963}
964
965void test_read_rrect(skiatest::Reporter* reporter, const SkRRect& rrect, bool shouldEqualSrc) {
966 // It would be cleaner to call rrect.writeToMemory into a buffer. However, writeToMemory asserts
967 // that the rrect is valid and our caller may have fiddled with the internals of rrect to make
968 // it invalid.
969 const void* buffer = reinterpret_cast<const void*>(&rrect);
970 SkRRect deserialized;
971 size_t size = deserialized.readFromMemory(buffer, sizeof(SkRRect));
973 REPORTER_ASSERT(reporter, deserialized.isValid());
974 if (shouldEqualSrc) {
975 REPORTER_ASSERT(reporter, rrect == deserialized);
976 }
977}
978
980 static const SkRect kRect = {10.f, 10.f, 20.f, 20.f};
981 static const SkRect kNaNRect = {10.f, 10.f, 20.f, SK_ScalarNaN};
982 static const SkRect kInfRect = {10.f, 10.f, SK_ScalarInfinity, 20.f};
984
987 // These get coerced to empty.
990
992 SkRect* innerRect = reinterpret_cast<SkRect*>(&rrect);
993 SkASSERT(*innerRect == kRect);
994 *innerRect = kInfRect;
995 test_read_rrect(reporter, rrect, false);
996 *innerRect = kNaNRect;
997 test_read_rrect(reporter, rrect, false);
998
1000 test_read_rrect(reporter, SkRRect::MakeOval(kInfRect), true);
1001 test_read_rrect(reporter, SkRRect::MakeOval(kNaNRect), true);
1003 *innerRect = kInfRect;
1004 test_read_rrect(reporter, rrect, false);
1005 *innerRect = kNaNRect;
1006 test_read_rrect(reporter, rrect, false);
1007
1009 // rrect should scale down the radii to make this legal
1011
1012 static const SkVector kRadii[4] = {{0.5f, 1.f}, {1.5f, 2.f}, {2.5f, 3.f}, {3.5f, 4.f}};
1013 rrect.setRectRadii(kRect, kRadii);
1014 test_read_rrect(reporter, rrect, true);
1015 SkScalar* innerRadius = reinterpret_cast<SkScalar*>(&rrect) + 6;
1016 SkASSERT(*innerRadius == 1.5f);
1017 *innerRadius = 400.f;
1018 test_read_rrect(reporter, rrect, false);
1019 *innerRadius = SK_ScalarInfinity;
1020 test_read_rrect(reporter, rrect, false);
1021 *innerRadius = SK_ScalarNaN;
1022 test_read_rrect(reporter, rrect, false);
1023 *innerRadius = -10.f;
1024 test_read_rrect(reporter, rrect, false);
1025}
1026
1028 // Because InnerBounds() insets the computed bounds slightly to correct for numerical inaccuracy
1029 // when finding the maximum inscribed point on a curve, we use a larger epsilon for comparing
1030 // expected areas.
1031 static constexpr SkScalar kEpsilon = 0.005f;
1032
1033 // Test that an empty rrect reports empty inner bounds
1035 // Test that a rect rrect reports itself as the inner bounds
1036 SkRect r = SkRect::MakeLTRB(0, 1, 2, 3);
1038 // Test that a circle rrect has an inner bounds area equal to 2*radius^2
1039 float radius = 5.f;
1041 2.f * radius)));
1043 2.f * radius * radius, kEpsilon));
1044
1045 float width = 20.f;
1046 float height = 25.f;
1048 // Test that a rrect with circular corners has an area equal to:
1049 float expectedArea =
1050 (2.f * radius * radius) + // area in the 4 circular corners
1051 (width-2.f*radius) * (height-2.f*radius) + // inner area excluding corners and edges
1052 SK_ScalarSqrt2 * radius * (width-2.f*radius) + // two horiz. rects between corners
1053 SK_ScalarSqrt2 * radius * (height-2.f*radius); // two vert. rects between corners
1054
1055 inner = SkRRectPriv::InnerBounds(SkRRect::MakeRectXY(r, radius, radius));
1056 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(inner.width() * inner.height(),
1057 expectedArea, kEpsilon));
1058
1059 // Test that a rrect with a small y radius but large x radius selects the horizontal interior
1060 SkRRect rr = SkRRect::MakeRectXY(r, 2.f * radius, 0.1f * radius);
1062 SkRect::MakeLTRB(0.f, 0.1f * radius, width, height - 0.1f * radius));
1063 // And vice versa with large y and small x radii
1064 rr = SkRRect::MakeRectXY(r, 0.1f * radius, 2.f * radius);
1066 SkRect::MakeLTRB(0.1f * radius, 0.f, width - 0.1f * radius, height));
1067
1068 // Test a variety of complex round rects produce a non-empty rect that is at least contained,
1069 // and larger than the inner area avoiding all corners.
1070 SkRandom rng;
1071 for (int i = 0; i < 1000; ++i) {
1072 float maxRadiusX = rng.nextRangeF(0.f, 40.f);
1073 float maxRadiusY = rng.nextRangeF(0.f, 40.f);
1074
1075 float innerWidth = rng.nextRangeF(0.f, 40.f);
1076 float innerHeight = rng.nextRangeF(0.f, 40.f);
1077
1078 SkVector radii[4] = {{rng.nextRangeF(0.f, maxRadiusX), rng.nextRangeF(0.f, maxRadiusY)},
1079 {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
1083 float maxLeft = std::max(radii[0].fX, radii[3].fX);
1084 float maxTop = std::max(radii[0].fY, radii[1].fY);
1085 float maxRight = std::max(radii[1].fX, radii[2].fX);
1086 float maxBottom = std::max(radii[2].fY, radii[3].fY);
1087
1088 SkRect outer = SkRect::MakeWH(maxLeft + maxRight + innerWidth,
1089 maxTop + maxBottom + innerHeight);
1090 rr.setRectRadii(outer, radii);
1091
1092 SkRect maxInner = SkRRectPriv::InnerBounds(rr);
1093 // Test upper limit on the size of 'maxInner'
1094 REPORTER_ASSERT(reporter, outer.contains(maxInner));
1095 REPORTER_ASSERT(reporter, rr.contains(maxInner));
1096
1097 // Test lower limit on the size of 'maxInner'
1098 inner = SkRect::MakeXYWH(maxLeft, maxTop, innerWidth, innerHeight);
1099 inner.inset(kEpsilon, kEpsilon);
1100
1101 if (inner.isSorted()) {
1102 REPORTER_ASSERT(reporter, maxInner.contains(inner));
1103 } else {
1104 // Flipped from the inset, just test two points of inner
1105 float midX = maxLeft + 0.5f * innerWidth;
1106 float midY = maxTop + 0.5f * innerHeight;
1107 REPORTER_ASSERT(reporter, maxInner.contains(midX, maxTop));
1108 REPORTER_ASSERT(reporter, maxInner.contains(midX, maxTop + innerHeight));
1109 REPORTER_ASSERT(reporter, maxInner.contains(maxLeft, midY));
1110 REPORTER_ASSERT(reporter, maxInner.contains(maxLeft + innerWidth, midY));
1111 }
1112 }
1113}
1114
1115namespace {
1116 // Helper to test expected intersection, relying on the fact that all round rect intersections
1117 // will have their bounds equal to the intersection of the bounds of the input round rects, and
1118 // their corner radii will be a one of A's, B's, or rectangular.
1119 enum CornerChoice : uint8_t {
1120 kA, kB, kRect
1121 };
1122
1123 static void verify_success(skiatest::Reporter* reporter, const SkRRect& a, const SkRRect& b,
1124 CornerChoice tl, CornerChoice tr, CornerChoice br, CornerChoice bl) {
1125 static const SkRRect kRect = SkRRect::MakeEmpty(); // has (0,0) for all corners
1126
1127 // Compute expected round rect intersection given bounds of A and B, and the specified
1128 // corner choices for the 4 corners.
1129 SkRect expectedBounds;
1130 SkAssertResult(expectedBounds.intersect(a.rect(), b.rect()));
1131
1132 SkVector radii[4] = {
1133 (tl == kA ? a : (tl == kB ? b : kRect)).radii(SkRRect::kUpperLeft_Corner),
1134 (tr == kA ? a : (tr == kB ? b : kRect)).radii(SkRRect::kUpperRight_Corner),
1135 (br == kA ? a : (br == kB ? b : kRect)).radii(SkRRect::kLowerRight_Corner),
1136 (bl == kA ? a : (bl == kB ? b : kRect)).radii(SkRRect::kLowerLeft_Corner)
1137 };
1138 SkRRect expected;
1139 expected.setRectRadii(expectedBounds, radii);
1140
1142 // Intersections are commutative so ba and ab should be the same
1144
1145 // Intersection of the result with either A or B should remain the intersection
1148
1149 // Bounds of intersection round rect should equal intersection of bounds of a and b
1150 REPORTER_ASSERT(reporter, actual.rect() == expectedBounds);
1151
1152 // Use PathOps to confirm that the explicit round rect is correct.
1153 SkPath aPath, bPath, expectedPath;
1154 aPath.addRRect(a);
1155 bPath.addRRect(b);
1156 SkAssertResult(Op(aPath, bPath, kIntersect_SkPathOp, &expectedPath));
1157
1158 // The isRRect() heuristics in SkPath are based on having called addRRect(), so a path from
1159 // path ops that is a rounded rectangle will return false. However, if test XOR expected is
1160 // empty, then we know that the shapes were the same.
1161 SkPath testPath;
1162 testPath.addRRect(actual);
1163
1164 SkPath empty;
1165 SkAssertResult(Op(testPath, expectedPath, kXOR_SkPathOp, &empty));
1166 REPORTER_ASSERT(reporter, empty.isEmpty());
1167 }
1168
1169 static void verify_failure(skiatest::Reporter* reporter, const SkRRect& a, const SkRRect& b) {
1171 // Expected the intersection to fail (no intersection or complex intersection is not
1172 // disambiguated).
1173 REPORTER_ASSERT(reporter, intersection.isEmpty());
1175 }
1176} // namespace
1177
1179 // Helper to inline making an inset round rect
1180 auto make_inset = [](const SkRRect& r, float dx, float dy) {
1181 SkRRect i = r;
1182 i.inset(dx, dy);
1183 return i;
1184 };
1185
1186 // A is a wide, short round rect
1187 SkRRect a = SkRRect::MakeRectXY({0.f, 4.f, 16.f, 12.f}, 2.f, 2.f);
1188 // B is a narrow, tall round rect
1189 SkRRect b = SkRRect::MakeRectXY({4.f, 0.f, 12.f, 16.f}, 3.f, 3.f);
1190 // NOTE: As positioned by default, A and B intersect as the rectangle {4, 4, 12, 12}.
1191 // There is a 2 px buffer between the corner curves of A and the vertical edges of B, and
1192 // a 1 px buffer between the corner curves of B and the horizontal edges of A. Since the shapes
1193 // form a symmetric rounded cross, we can easily test edge and corner combinations by simply
1194 // flipping signs and/or swapping x and y offsets.
1195
1196 // Successful intersection operations:
1197 // - for clarity these are formed by moving A around to intersect with B in different ways.
1198 // - the expected bounds of the round rect intersection is calculated automatically
1199 // in check_success, so all we have to specify are the expected corner radii
1200
1201 // A and B intersect as a rectangle
1202 verify_success(reporter, a, b, kRect, kRect, kRect, kRect);
1203 // Move A to intersect B on a vertical edge, preserving two corners of A inside B
1204 verify_success(reporter, a.makeOffset(6.f, 0.f), b, kA, kRect, kRect, kA);
1205 verify_success(reporter, a.makeOffset(-6.f, 0.f), b, kRect, kA, kA, kRect);
1206 // Move B to intersect A on a horizontal edge, preserving two corners of B inside A
1207 verify_success(reporter, a, b.makeOffset(0.f, 6.f), kB, kB, kRect, kRect);
1208 verify_success(reporter, a, b.makeOffset(0.f, -6.f), kRect, kRect, kB, kB);
1209 // Move A to intersect B on a corner, preserving one corner of A and one of B
1210 verify_success(reporter, a.makeOffset(-7.f, -8.f), b, kB, kRect, kA, kRect); // TL of B
1211 verify_success(reporter, a.makeOffset(7.f, -8.f), b, kRect, kB, kRect, kA); // TR of B
1212 verify_success(reporter, a.makeOffset(7.f, 8.f), b, kA, kRect, kB, kRect); // BR of B
1213 verify_success(reporter, a.makeOffset(-7.f, 8.f), b, kRect, kA, kRect, kB); // BL of B
1214 // An inset is contained inside the original (note that SkRRect::inset modifies radii too) so
1215 // is returned unmodified when intersected.
1216 verify_success(reporter, a, make_inset(a, 1.f, 1.f), kB, kB, kB, kB);
1217 verify_success(reporter, make_inset(b, 2.f, 2.f), b, kA, kA, kA, kA);
1218
1219 // A rectangle exactly matching the corners of the rrect bounds keeps the rrect radii,
1220 // regardless of whether or not it's the 1st or 2nd arg to ConservativeIntersect.
1221 SkRRect c = SkRRect::MakeRectXY({0.f, 0.f, 10.f, 10.f}, 2.f, 2.f);
1222 SkRRect cT = SkRRect::MakeRect({0.f, 0.f, 10.f, 5.f});
1223 verify_success(reporter, c, cT, kA, kA, kRect, kRect);
1224 verify_success(reporter, cT, c, kB, kB, kRect, kRect);
1225 SkRRect cB = SkRRect::MakeRect({0.f, 5.f, 10.f, 10.});
1226 verify_success(reporter, c, cB, kRect, kRect, kA, kA);
1227 verify_success(reporter, cB, c, kRect, kRect, kB, kB);
1228 SkRRect cL = SkRRect::MakeRect({0.f, 0.f, 5.f, 10.f});
1229 verify_success(reporter, c, cL, kA, kRect, kRect, kA);
1230 verify_success(reporter, cL, c, kB, kRect, kRect, kB);
1231 SkRRect cR = SkRRect::MakeRect({5.f, 0.f, 10.f, 10.f});
1232 verify_success(reporter, c, cR, kRect, kA, kA, kRect);
1233 verify_success(reporter, cR, c, kRect, kB, kB, kRect);
1234
1235 // Failed intersection operations:
1236
1237 // A and B's bounds do not intersect
1238 verify_failure(reporter, a.makeOffset(32.f, 0.f), b);
1239 // A and B's bounds intersect, but corner curves do not -> no intersection
1240 verify_failure(reporter, a.makeOffset(11.5f, -11.5f), b);
1241 // A is empty -> no intersection
1242 verify_failure(reporter, SkRRect::MakeEmpty(), b);
1243 // A is contained in B, but is too close to the corner curves for the conservative
1244 // approximations to construct a valid round rect intersection.
1245 verify_failure(reporter, make_inset(b, 0.3f, 0.3f), b);
1246 // A intersects a straight edge, but not far enough for B to contain A's corners
1247 verify_failure(reporter, a.makeOffset(2.5f, 0.f), b);
1248 verify_failure(reporter, a.makeOffset(-2.5f, 0.f), b);
1249 // And vice versa for B into A
1250 verify_failure(reporter, a, b.makeOffset(0.f, 1.5f));
1251 verify_failure(reporter, a, b.makeOffset(0.f, -1.5f));
1252 // A intersects a straight edge and part of B's corner
1253 verify_failure(reporter, a.makeOffset(5.f, -2.f), b);
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 // And vice versa
1258 verify_failure(reporter, a, b.makeOffset(3.f, -5.f));
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 // A intersects B on a corner, but the corner curves overlap each other
1263 verify_failure(reporter, a.makeOffset(8.f, 10.f), b);
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
1268 // Another variant of corners overlapping, this is two circles of radius r that overlap by r
1269 // pixels (e.g. the leftmost point of the right circle touches the center of the left circle).
1270 // The key difference with the above case is that the intersection of the circle bounds have
1271 // corners that are contained in both circles, but because it is only r wide, can not satisfy
1272 // all corners having radii = r.
1273 float r = 100.f;
1274 a = SkRRect::MakeOval(SkRect::MakeWH(2*r, 2*r));
1275 verify_failure(reporter, a, a.makeOffset(r, 0.f));
1276}
1277
1278DEF_TEST(RoundRect, reporter) {
1294}
1295
1296DEF_TEST(RRect_fuzzer_regressions, r) {
1297 {
1298 unsigned char buf[] = {
1299 0x0a, 0x00, 0x00, 0xff, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f,
1300 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
1301 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
1302 0x7f, 0x7f, 0x7f, 0x02, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x02, 0x00
1303 };
1304 REPORTER_ASSERT(r, sizeof(buf) == SkRRect{}.readFromMemory(buf, sizeof(buf)));
1305 }
1306
1307 {
1308 unsigned char buf[] = {
1309 0x5d, 0xff, 0xff, 0x5d, 0x0a, 0x60, 0x0a, 0x0a, 0x0a, 0x7e, 0x0a, 0x5a,
1310 0x0a, 0x12, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a,
1311 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x00, 0x00, 0x00, 0x0a,
1312 0x0a, 0x0a, 0x0a, 0x26, 0x0a, 0x0a, 0x0a, 0x0a, 0xff, 0xff, 0x0a, 0x0a
1313 };
1314 REPORTER_ASSERT(r, sizeof(buf) == SkRRect{}.readFromMemory(buf, sizeof(buf)));
1315 }
1316
1317 {
1318 unsigned char buf[] = {
1319 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x04, 0xdd, 0xdd, 0x15,
1320 0xfe, 0x00, 0x00, 0x04, 0x05, 0x7e, 0x00, 0x00, 0x00, 0xff, 0x08, 0x04,
1321 0xff, 0xff, 0xfe, 0xfe, 0xff, 0x32, 0x32, 0x32, 0x32, 0x00, 0x32, 0x32,
1322 0x04, 0xdd, 0x3d, 0x1c, 0xfe, 0x89, 0x04, 0x0a, 0x0e, 0x05, 0x7e, 0x0a
1323 };
1324 REPORTER_ASSERT(r, sizeof(buf) == SkRRect{}.readFromMemory(buf, sizeof(buf)));
1325 }
1326}
reporter
static void test_round_rect_rects(skiatest::Reporter *reporter)
static void test_round_rect_transform(skiatest::Reporter *reporter)
static const SkScalar kHeight
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)
#define GET_RADII
static void test_round_rect_contains_rect(skiatest::Reporter *reporter)
static void test_issue_2696(skiatest::Reporter *reporter)
static const SkScalar kWidth
static void assert_transform_failure(skiatest::Reporter *reporter, const SkRRect &orig, const SkMatrix &matrix)
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_transform_helper(skiatest::Reporter *reporter, const SkRRect &orig)
void test_read_rrect(skiatest::Reporter *reporter, const SkRRect &rrect, bool shouldEqualSrc)
static void test_round_rect_general(skiatest::Reporter *reporter)
static void test_empty(skiatest::Reporter *reporter)
#define SkAssertResult(cond)
Definition SkAssert.h:123
#define SkASSERT(cond)
Definition SkAssert.h:116
static constexpr double kEpsilon
@ kIntersect_SkPathOp
intersect the two paths
Definition SkPathOps.h:24
@ kXOR_SkPathOp
exclusive-or the two paths
Definition SkPathOps.h:26
static bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance=SK_ScalarNearlyZero)
Definition SkScalar.h:107
#define SK_ScalarNaN
Definition SkScalar.h:28
#define SkScalarHalf(a)
Definition SkScalar.h:75
#define SkIntToScalar(x)
Definition SkScalar.h:57
#define SK_ScalarSqrt2
Definition SkScalar.h:20
#define SK_ScalarInfinity
Definition SkScalar.h:26
#define DEF_TEST(name, reporter)
Definition Test.h:312
#define REPORTER_ASSERT(r, cond,...)
Definition Test.h:286
constexpr SkRect kRect
SkMatrix & setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar persp0, SkScalar persp1, SkScalar persp2)
Definition SkMatrix.h:562
static const SkMatrix & I()
SkPath & addRRect(const SkRRect &rrect, SkPathDirection dir=SkPathDirection::kCW)
Definition SkPath.cpp:990
static SkRect InnerBounds(const SkRRect &rr)
Definition SkRRect.cpp:750
static SkRRect ConservativeIntersect(const SkRRect &a, const SkRRect &b)
Definition SkRRect.cpp:812
const SkRect & rect() const
Definition SkRRect.h:264
static SkRRect MakeOval(const SkRect &oval)
Definition SkRRect.h:162
void inset(SkScalar dx, SkScalar dy, SkRRect *dst) const
Definition SkRRect.cpp:562
void setEmpty()
Definition SkRRect.h:118
size_t readFromMemory(const void *buffer, size_t length)
Definition SkRRect.cpp:610
bool transform(const SkMatrix &matrix, SkRRect *dst) const
Definition SkRRect.cpp:436
static SkRRect MakeRect(const SkRect &r)
Definition SkRRect.h:149
void setOval(const SkRect &oval)
Definition SkRRect.cpp:30
static SkRRect MakeRectXY(const SkRect &rect, SkScalar xRad, SkScalar yRad)
Definition SkRRect.h:180
void setRectRadii(const SkRect &rect, const SkVector radii[4])
Definition SkRRect.cpp:189
bool contains(const SkRect &rect) const
Definition SkRRect.cpp:360
bool isEmpty() const
Definition SkRRect.h:83
void setRectXY(const SkRect &rect, SkScalar xRad, SkScalar yRad)
Definition SkRRect.cpp:52
static constexpr size_t kSizeInMemory
Definition SkRRect.h:422
bool isValid() const
Definition SkRRect.cpp:663
void setRect(const SkRect &rect)
Definition SkRRect.h:126
static SkRRect MakeEmpty()
Definition SkRRect.h:142
float nextRangeF(float min, float max)
Definition SkRandom.h:64
float SkScalar
Definition extension.cpp:12
static bool b
struct MyStruct a[10]
EMSCRIPTEN_KEEPALIVE void empty()
static const uint8_t buffer[]
unsigned useCenter Optional< SkMatrix > matrix
Definition SkRecords.h:258
SkRRect rrect
Definition SkRecords.h:232
skia_private::AutoTArray< sk_sp< SkImageFilter > > filters TypedMatrix matrix TypedMatrix matrix SkScalar dx
Definition SkRecords.h:208
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
dst
Definition cp.py:12
int32_t height
int32_t width
bool intersect(const SkRect &r)
Definition SkRect.cpp:114
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition SkRect.h:659
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 MakeWH(float w, float h)
Definition SkRect.h:609
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition SkRect.h:646

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}

◆ DEF_TEST() [1/2]

DEF_TEST ( RoundRect  ,
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}

◆ 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
167 REPORTER_ASSERT(reporter, rr.rect() == rect);
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) {
175 REPORTER_ASSERT(reporter, rquad[i] == rr.radii((SkRRect::Corner) 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
SkVector radii(Corner corner) const
Definition SkRRect.h:271
@ kNinePatch_Type
non-zero width and height with axis-aligned radii
Definition SkRRect.h:71
Type type() const
Definition SkRRect.h:81
void setNinePatch(const SkRect &rect, SkScalar leftRad, SkScalar topRad, SkScalar rightRad, SkScalar bottomRad)
Definition SkRRect.cpp:115
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}

◆ 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}
static bool contains(const SkRect &r, SkPoint p)
#define SK_Scalar1
Definition SkScalar.h:18
double y
double x

◆ 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}
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}

◆ 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}
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}

◆ 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;
996 test_read_rrect(reporter, rrect, false);
997 *innerRect = kNaNRect;
998 test_read_rrect(reporter, rrect, false);
999
1001 test_read_rrect(reporter, SkRRect::MakeOval(kInfRect), true);
1002 test_read_rrect(reporter, SkRRect::MakeOval(kNaNRect), true);
1004 *innerRect = kInfRect;
1005 test_read_rrect(reporter, rrect, false);
1006 *innerRect = kNaNRect;
1007 test_read_rrect(reporter, rrect, false);
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);
1015 test_read_rrect(reporter, rrect, true);
1016 SkScalar* innerRadius = reinterpret_cast<SkScalar*>(&rrect) + 6;
1017 SkASSERT(*innerRadius == 1.5f);
1018 *innerRadius = 400.f;
1019 test_read_rrect(reporter, rrect, false);
1020 *innerRadius = SK_ScalarInfinity;
1021 test_read_rrect(reporter, rrect, false);
1022 *innerRadius = SK_ScalarNaN;
1023 test_read_rrect(reporter, rrect, false);
1024 *innerRadius = -10.f;
1025 test_read_rrect(reporter, rrect, false);
1026}

◆ 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}

◆ 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
206 REPORTER_ASSERT(reporter, rr1.rect() == rect);
207
208 for (int i = 0; i < 4; ++i) {
209 REPORTER_ASSERT(reporter, zeroPt == rr1.radii((SkRRect::Corner) 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
225 REPORTER_ASSERT(reporter, rr2.rect() == rect);
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
247 REPORTER_ASSERT(reporter, rr3.rect() == rect);
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
280 REPORTER_ASSERT(reporter, rr5.rect() == rect);
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 void test_9patch_rrect(skiatest::Reporter *reporter, const SkRect &rect, SkScalar l, SkScalar t, SkScalar r, SkScalar b, bool checkRadii)
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
sk_sp< SkBlender > blender SkRect rect
Definition SkRecords.h:350
float fX
x-axis value
float fY
y-axis value

◆ 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();
341 REPORTER_ASSERT(reporter, oval == 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();
311 REPORTER_ASSERT(reporter, rect == r);
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();
321 REPORTER_ASSERT(reporter, rect == r);
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}

◆ 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));
570 assert_transform_failure(reporter, orig, matrix);
571
572 matrix.reset();
573 matrix.setSkewY(SkIntToScalar(3));
574 assert_transform_failure(reporter, orig, matrix);
575
576 matrix.reset();
577 matrix.setPerspX(4);
578 assert_transform_failure(reporter, orig, matrix);
579
580 matrix.reset();
581 matrix.setPerspY(5);
582 assert_transform_failure(reporter, orig, matrix);
583
584 // Rotation fails.
585 matrix.reset();
586 matrix.setRotate(SkIntToScalar(37));
587 assert_transform_failure(reporter, orig, matrix);
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));
609 assert_transform_failure(reporter, orig, matrix);
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);
635 assert_transform_failure(reporter, orig, matrix);
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}
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.