Flutter Engine
The Flutter Engine
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
Definition: SkPoint_impl.h:164
float fY
y-axis value
Definition: SkPoint_impl.h:165

◆ 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 float max(float r, float g, float b)
Definition: hsl.cpp:49
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

◆ 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
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126

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