Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Static Public Member Functions | List of all members
SkRRectPriv Class Reference

#include <SkRRectPriv.h>

Static Public Member Functions

static bool IsCircle (const SkRRect &rr)
 
static SkVector GetSimpleRadii (const SkRRect &rr)
 
static bool IsSimpleCircular (const SkRRect &rr)
 
static bool IsNearlySimpleCircular (const SkRRect &rr, SkScalar tolerance=SK_ScalarNearlyZero)
 
static bool EqualRadii (const SkRRect &rr)
 
static const SkVectorGetRadiiArray (const SkRRect &rr)
 
static bool AllCornersCircular (const SkRRect &rr, SkScalar tolerance=SK_ScalarNearlyZero)
 
static bool ReadFromBuffer (SkRBuffer *buffer, SkRRect *rr)
 
static void WriteToBuffer (const SkRRect &rr, SkWBuffer *buffer)
 
static bool ContainsPoint (const SkRRect &rr, const SkPoint &p)
 
static SkRect InnerBounds (const SkRRect &rr)
 
static SkRRect ConservativeIntersect (const SkRRect &a, const SkRRect &b)
 

Detailed Description

Definition at line 16 of file SkRRectPriv.h.

Member Function Documentation

◆ AllCornersCircular()

bool SkRRectPriv::AllCornersCircular ( const SkRRect rr,
SkScalar  tolerance = SK_ScalarNearlyZero 
)
static

Definition at line 353 of file SkRRect.cpp.

353 {
354 return SkScalarNearlyEqual(rr.fRadii[0].fX, rr.fRadii[0].fY, tolerance) &&
355 SkScalarNearlyEqual(rr.fRadii[1].fX, rr.fRadii[1].fY, tolerance) &&
356 SkScalarNearlyEqual(rr.fRadii[2].fX, rr.fRadii[2].fY, tolerance) &&
357 SkScalarNearlyEqual(rr.fRadii[3].fX, rr.fRadii[3].fY, tolerance);
358}
static bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance=SK_ScalarNearlyZero)
Definition SkScalar.h:107
float fX
x-axis value
float fY
y-axis value

◆ ConservativeIntersect()

SkRRect SkRRectPriv::ConservativeIntersect ( const SkRRect a,
const SkRRect b 
)
static

Definition at line 812 of file SkRRect.cpp.

812 {
813 // Returns the coordinate of the rect matching the corner enum.
814 auto getCorner = [](const SkRect& r, SkRRect::Corner corner) -> SkPoint {
815 switch(corner) {
816 case SkRRect::kUpperLeft_Corner: return {r.fLeft, r.fTop};
817 case SkRRect::kUpperRight_Corner: return {r.fRight, r.fTop};
818 case SkRRect::kLowerLeft_Corner: return {r.fLeft, r.fBottom};
819 case SkRRect::kLowerRight_Corner: return {r.fRight, r.fBottom};
820 default: SkUNREACHABLE;
821 }
822 };
823 // Returns true if shape A's extreme point is contained within shape B's extreme point, relative
824 // to the 'corner' location. If the two shapes' corners have the same ellipse radii, this
825 // is sufficient for A's ellipse arc to be contained by B's ellipse arc.
826 auto insideCorner = [](SkRRect::Corner corner, const SkPoint& a, const SkPoint& b) {
827 switch(corner) {
828 case SkRRect::kUpperLeft_Corner: return a.fX >= b.fX && a.fY >= b.fY;
829 case SkRRect::kUpperRight_Corner: return a.fX <= b.fX && a.fY >= b.fY;
830 case SkRRect::kLowerRight_Corner: return a.fX <= b.fX && a.fY <= b.fY;
831 case SkRRect::kLowerLeft_Corner: return a.fX >= b.fX && a.fY <= b.fY;
832 default: SkUNREACHABLE;
833 }
834 };
835
836 auto getIntersectionRadii = [&](const SkRect& r, SkRRect::Corner corner, SkVector* radii) {
837 SkPoint test = getCorner(r, corner);
838 SkPoint aCorner = getCorner(a.rect(), corner);
839 SkPoint bCorner = getCorner(b.rect(), corner);
840
841 if (test == aCorner && test == bCorner) {
842 // The round rects share a corner anchor, so pick A or B such that its X and Y radii
843 // are both larger than the other rrect's, or return false if neither A or B has the max
844 // corner radii (this is more permissive than the single corner tests below).
845 SkVector aRadii = a.radii(corner);
846 SkVector bRadii = b.radii(corner);
847 if (aRadii.fX >= bRadii.fX && aRadii.fY >= bRadii.fY) {
848 *radii = aRadii;
849 return true;
850 } else if (bRadii.fX >= aRadii.fX && bRadii.fY >= aRadii.fY) {
851 *radii = bRadii;
852 return true;
853 } else {
854 return false;
855 }
856 } else if (test == aCorner) {
857 // Test that A's ellipse is contained by B. This is a non-trivial function to evaluate
858 // so we resrict it to when the corners have the same radii. If not, we use the more
859 // conservative test that the extreme point of A's bounding box is contained in B.
860 *radii = a.radii(corner);
861 if (*radii == b.radii(corner)) {
862 return insideCorner(corner, aCorner, bCorner); // A inside B
863 } else {
864 return b.checkCornerContainment(aCorner.fX, aCorner.fY);
865 }
866 } else if (test == bCorner) {
867 // Mirror of the above
868 *radii = b.radii(corner);
869 if (*radii == a.radii(corner)) {
870 return insideCorner(corner, bCorner, aCorner); // B inside A
871 } else {
872 return a.checkCornerContainment(bCorner.fX, bCorner.fY);
873 }
874 } else {
875 // This is a corner formed by two straight edges of A and B, so confirm that it is
876 // contained in both (if not, then the intersection can't be a round rect).
877 *radii = {0.f, 0.f};
878 return a.checkCornerContainment(test.fX, test.fY) &&
879 b.checkCornerContainment(test.fX, test.fY);
880 }
881 };
882
883 // We fill in the SkRRect directly. Since the rect and radii are either 0s or determined by
884 // valid existing SkRRects, we know we are finite.
885 SkRRect intersection;
886 if (!intersection.fRect.intersect(a.rect(), b.rect())) {
887 // Definitely no intersection
888 return SkRRect::MakeEmpty();
889 }
890
891 const SkRRect::Corner corners[] = {
896 };
897 // By definition, edges is contained in the bounds of 'a' and 'b', but now we need to consider
898 // the corners. If the bound's corner point is in both rrects, the corner radii will be 0s.
899 // If the bound's corner point matches a's edges and is inside 'b', we use a's radii.
900 // Same for b's radii. If any corner fails these conditions, we reject the intersection as an
901 // rrect. If after determining radii for all 4 corners, they would overlap, we also reject the
902 // intersection shape.
903 for (auto c : corners) {
904 if (!getIntersectionRadii(intersection.fRect, c, &intersection.fRadii[c])) {
905 return SkRRect::MakeEmpty(); // Resulting intersection is not a rrect
906 }
907 }
908
909 // Check for radius overlap along the four edges, since the earlier evaluation was only a
910 // one-sided corner check. If they aren't valid, a corner's radii doesn't fit within the rect.
911 // If the radii are scaled, the combination of radii from two adjacent corners doesn't fit.
912 // Normally for a regularly constructed SkRRect, we want this scaling, but in this case it means
913 // the intersection shape is definitively not a round rect.
914 if (!SkRRect::AreRectAndRadiiValid(intersection.fRect, intersection.fRadii) ||
915 intersection.scaleRadii()) {
916 return SkRRect::MakeEmpty();
917 }
918
919 // The intersection is an rrect of the given radii. Potentially all 4 corners could have
920 // been simplified to (0,0) radii, making the intersection a rectangle.
921 intersection.computeType();
922 return intersection;
923}
#define SkUNREACHABLE
Definition SkAssert.h:135
@ 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
static SkRRect MakeEmpty()
Definition SkRRect.h:142
static bool b
struct MyStruct a[10]
SkScalar fBottom
larger y-axis bounds
Definition extension.cpp:17
bool intersect(const SkRect &r)
Definition SkRect.cpp:114
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

◆ ContainsPoint()

static bool SkRRectPriv::ContainsPoint ( const SkRRect rr,
const SkPoint p 
)
inlinestatic

Definition at line 48 of file SkRRectPriv.h.

48 {
49 return rr.getBounds().contains(p.fX, p.fY) && rr.checkCornerContainment(p.fX, p.fY);
50 }
const SkRect & getBounds() const
Definition SkRRect.h:279
bool contains(SkScalar x, SkScalar y) const
Definition extension.cpp:19

◆ EqualRadii()

static bool SkRRectPriv::EqualRadii ( const SkRRect rr)
inlinestatic

Definition at line 35 of file SkRRectPriv.h.

35 {
37 }
static bool IsSimpleCircular(const SkRRect &rr)
Definition SkRRectPriv.h:27
static bool IsCircle(const SkRRect &rr)
Definition SkRRectPriv.h:18
bool isRect() const
Definition SkRRect.h:84

◆ GetRadiiArray()

static const SkVector * SkRRectPriv::GetRadiiArray ( const SkRRect rr)
inlinestatic

Definition at line 39 of file SkRRectPriv.h.

39{ return rr.fRadii; }

◆ GetSimpleRadii()

static SkVector SkRRectPriv::GetSimpleRadii ( const SkRRect rr)
inlinestatic

Definition at line 22 of file SkRRectPriv.h.

22 {
23 SkASSERT(!rr.isComplex());
24 return rr.fRadii[0];
25 }
#define SkASSERT(cond)
Definition SkAssert.h:116
bool isComplex() const
Definition SkRRect.h:88

◆ InnerBounds()

SkRect SkRRectPriv::InnerBounds ( const SkRRect rr)
static

Definition at line 750 of file SkRRect.cpp.

750 {
751 if (rr.isEmpty() || rr.isRect()) {
752 return rr.rect();
753 }
754
755 // We start with the outer bounds of the round rect and consider three subsets and take the
756 // one with maximum area. The first two are the horizontal and vertical rects inset from the
757 // corners, the third is the rect inscribed at the corner curves' maximal point. This forms
758 // the exact solution when all corners have the same radii (the radii do not have to be
759 // circular).
760 SkRect innerBounds = rr.getBounds();
765
766 // Select maximum inset per edge, which may move an adjacent corner of the inscribed
767 // rectangle off of the rounded-rect path, but that is acceptable given that the general
768 // equation for inscribed area is non-trivial to evaluate.
769 SkScalar leftShift = std::max(tl.fX, bl.fX);
770 SkScalar topShift = std::max(tl.fY, tr.fY);
771 SkScalar rightShift = std::max(tr.fX, br.fX);
772 SkScalar bottomShift = std::max(bl.fY, br.fY);
773
774 SkScalar dw = leftShift + rightShift;
775 SkScalar dh = topShift + bottomShift;
776
777 // Area removed by shifting left/right
778 SkScalar horizArea = (innerBounds.width() - dw) * innerBounds.height();
779 // And by shifting top/bottom
780 SkScalar vertArea = (innerBounds.height() - dh) * innerBounds.width();
781 // And by shifting all edges: just considering a corner ellipse, the maximum inscribed rect has
782 // a corner at sqrt(2)/2 * (rX, rY), so scale all corner shifts by (1 - sqrt(2)/2) to get the
783 // safe shift per edge (since the shifts already are the max radius for that edge).
784 // - We actually scale by a value slightly increased to make it so that the shifted corners are
785 // safely inside the curves, otherwise numerical stability can cause it to fail contains().
786 static constexpr SkScalar kScale = (1.f - SK_ScalarRoot2Over2) + 1e-5f;
787 SkScalar innerArea = (innerBounds.width() - kScale * dw) * (innerBounds.height() - kScale * dh);
788
789 if (horizArea > vertArea && horizArea > innerArea) {
790 // Cut off corners by insetting left and right
791 innerBounds.fLeft += leftShift;
792 innerBounds.fRight -= rightShift;
793 } else if (vertArea > innerArea) {
794 // Cut off corners by insetting top and bottom
795 innerBounds.fTop += topShift;
796 innerBounds.fBottom -= bottomShift;
797 } else if (innerArea > 0.f) {
798 // Inset on all sides, scaled to touch
799 innerBounds.fLeft += kScale * leftShift;
800 innerBounds.fRight -= kScale * rightShift;
801 innerBounds.fTop += kScale * topShift;
802 innerBounds.fBottom -= kScale * bottomShift;
803 } else {
804 // Inner region would collapse to empty
805 return SkRect::MakeEmpty();
806 }
807
808 SkASSERT(innerBounds.isSorted() && !innerBounds.isEmpty());
809 return innerBounds;
810}
#define SK_ScalarRoot2Over2
Definition SkScalar.h:23
const SkRect & rect() const
Definition SkRRect.h:264
SkVector radii(Corner corner) const
Definition SkRRect.h:271
bool isEmpty() const
Definition SkRRect.h:83
float SkScalar
Definition extension.cpp:12
static constexpr SkRect MakeEmpty()
Definition SkRect.h:595
constexpr float height() const
Definition SkRect.h:769
constexpr float width() const
Definition SkRect.h:762
bool isEmpty() const
Definition SkRect.h:693
bool isSorted() const
Definition SkRect.h:705
static constexpr int kScale

◆ IsCircle()

static bool SkRRectPriv::IsCircle ( const SkRRect rr)
inlinestatic

Definition at line 18 of file SkRRectPriv.h.

18 {
19 return rr.isOval() && SkScalarNearlyEqual(rr.fRadii[0].fX, rr.fRadii[0].fY);
20 }
bool isOval() const
Definition SkRRect.h:85

◆ IsNearlySimpleCircular()

bool SkRRectPriv::IsNearlySimpleCircular ( const SkRRect rr,
SkScalar  tolerance = SK_ScalarNearlyZero 
)
static

Definition at line 342 of file SkRRect.cpp.

342 {
343 SkScalar simpleRadius = rr.fRadii[0].fX;
344 return SkScalarNearlyEqual(simpleRadius, rr.fRadii[0].fY, tolerance) &&
345 SkScalarNearlyEqual(simpleRadius, rr.fRadii[1].fX, tolerance) &&
346 SkScalarNearlyEqual(simpleRadius, rr.fRadii[1].fY, tolerance) &&
347 SkScalarNearlyEqual(simpleRadius, rr.fRadii[2].fX, tolerance) &&
348 SkScalarNearlyEqual(simpleRadius, rr.fRadii[2].fY, tolerance) &&
349 SkScalarNearlyEqual(simpleRadius, rr.fRadii[3].fX, tolerance) &&
350 SkScalarNearlyEqual(simpleRadius, rr.fRadii[3].fY, tolerance);
351}

◆ IsSimpleCircular()

static bool SkRRectPriv::IsSimpleCircular ( const SkRRect rr)
inlinestatic

Definition at line 27 of file SkRRectPriv.h.

27 {
28 return rr.isSimple() && SkScalarNearlyEqual(rr.fRadii[0].fX, rr.fRadii[0].fY);
29 }
bool isSimple() const
Definition SkRRect.h:86

◆ ReadFromBuffer()

bool SkRRectPriv::ReadFromBuffer ( SkRBuffer buffer,
SkRRect rr 
)
static

Definition at line 623 of file SkRRect.cpp.

623 {
624 if (buffer->available() < SkRRect::kSizeInMemory) {
625 return false;
626 }
627 SkRRect storage;
628 return buffer->read(&storage, SkRRect::kSizeInMemory) &&
630}
size_t readFromMemory(const void *buffer, size_t length)
Definition SkRRect.cpp:610
static constexpr size_t kSizeInMemory
Definition SkRRect.h:422
static const uint8_t buffer[]

◆ WriteToBuffer()

void SkRRectPriv::WriteToBuffer ( const SkRRect rr,
SkWBuffer buffer 
)
static

Definition at line 605 of file SkRRect.cpp.

605 {
606 // Serialize only the rect and corners, but not the derived type tag.
607 buffer->write(&rr, SkRRect::kSizeInMemory);
608}

The documentation for this class was generated from the following files: