public static RoundedRectKeypoints CalculateRoundedCornersRectangleWinUI()

in src/Avalonia.Base/Media/GeometryBuilder.cs [206:429]


        public static RoundedRectKeypoints CalculateRoundedCornersRectangleWinUI(
            Rect outerBounds,
            Thickness borderThickness,
            CornerRadius cornerRadius,
            BackgroundSizing sizing)
        {
            // This was initially derived from WinUI:
            //  - CGeometryBuilder::CalculateRoundedCornersRectangle
            //    https://github.com/microsoft/microsoft-ui-xaml/blob/93742a178db8f625ba9299f62c21f656e0b195ad/dxaml/xcp/core/core/elements/geometry.cpp#L862-L869
            //
            // It has been modified to accept a BackgroundSizing parameter directly as well
            // as to support BackgroundSizing.CenterBorder.
            //
            // Keep in mind:
            //   > In Xaml, the corner radius is defined to be the middle of the stroke
            //   > (i.e. half the border thickness extends to either side).

            bool fOuter;
            Rect boundRect = outerBounds;

            if (sizing == BackgroundSizing.InnerBorderEdge)
            {
                boundRect = outerBounds.Deflate(borderThickness);
                fOuter = false;
            }
            else if (sizing == BackgroundSizing.OuterBorderEdge)
            {
                fOuter = true;
            }
            else // CenterBorder
            {
                // This is a trick to support a 3rd state (CenterBorder) using the same WinUI-based algorithm.
                // The WinUI algorithm only supports the fOuter = True|False parameter.
                boundRect = outerBounds.Deflate(borderThickness * 0.5);
                fOuter = false;
            }

            // Start of WinUI converted code
            // WinUI's Point struct fields can be modified directly, Avalonia's Point is read-only.
            // Therefore, we will use doubles for calculation so multiple Point structs aren't
            // required during calculations -- everything can be done with these double variables.
            double fLeftTop;
            double fLeftBottom;
            double fTopLeft;
            double fTopRight;
            double fRightTop;
            double fRightBottom;
            double fBottomLeft;
            double fBottomRight;

            double left;
            double right;
            double top;
            double bottom;

            // If the caller wants to take the border into account
            // initialize the borders variables
            if (borderThickness != default)
            {
                left = 0.5 * borderThickness.Left;
                right = 0.5 * borderThickness.Right;
                top = 0.5 * borderThickness.Top;
                bottom = 0.5 * borderThickness.Bottom;
            }
            else
            {
                left = 0.0;
                right = 0.0;
                top = 0.0;
                bottom = 0.0;
            }

            // The following if/else block initializes the variables
            // of which the points of the path will be created
            // In case of outer, add the border - if any.
            // Otherwise (inner rectangle) subtract the border - if any
            if (fOuter)
            {
                if (MathUtilities.AreClose(cornerRadius.TopLeft, 0.0, Epsilon))
                {
                    fLeftTop = 0.0;
                    fTopLeft = 0.0;
                }
                else
                {
                    fLeftTop = cornerRadius.TopLeft + left;
                    fTopLeft = cornerRadius.TopLeft + top;
                }

                if (MathUtilities.AreClose(cornerRadius.TopRight, 0.0, Epsilon))
                {
                    fTopRight = 0.0;
                    fRightTop = 0.0;
                }
                else
                {
                    fTopRight = cornerRadius.TopRight + top;
                    fRightTop = cornerRadius.TopRight + right;
                }

                if (MathUtilities.AreClose(cornerRadius.BottomRight, 0.0, Epsilon))
                {
                    fRightBottom = 0.0;
                    fBottomRight = 0.0;
                }
                else
                {
                    fRightBottom = cornerRadius.BottomRight + right;
                    fBottomRight = cornerRadius.BottomRight + bottom;
                }

                if (MathUtilities.AreClose(cornerRadius.BottomLeft, 0.0, Epsilon))
                {
                    fBottomLeft = 0.0;
                    fLeftBottom = 0.0;
                }
                else
                {
                    fBottomLeft = cornerRadius.BottomLeft + bottom;
                    fLeftBottom = cornerRadius.BottomLeft + left;
                }
            }
            else
            {
                fLeftTop = Math.Max(0.0, cornerRadius.TopLeft - left);
                fTopLeft = Math.Max(0.0, cornerRadius.TopLeft - top);
                fTopRight = Math.Max(0.0, cornerRadius.TopRight - top);
                fRightTop = Math.Max(0.0, cornerRadius.TopRight - right);
                fRightBottom = Math.Max(0.0, cornerRadius.BottomRight - right);
                fBottomRight = Math.Max(0.0, cornerRadius.BottomRight - bottom);
                fBottomLeft = Math.Max(0.0, cornerRadius.BottomLeft - bottom);
                fLeftBottom = Math.Max(0.0, cornerRadius.BottomLeft - left);
            }

            double topLeftX = fLeftTop;
            double topLeftY = 0;

            double topRightX = boundRect.Width - fRightTop;
            double topRightY = 0;

            double rightTopX = boundRect.Width;
            double rightTopY = fTopRight;

            double rightBottomX = boundRect.Width;
            double rightBottomY = boundRect.Height - fBottomRight;

            double bottomRightX = boundRect.Width - fRightBottom;
            double bottomRightY = boundRect.Height;

            double bottomLeftX = fLeftBottom;
            double bottomLeftY = boundRect.Height;

            double leftBottomX = 0;
            double leftBottomY = boundRect.Height - fBottomLeft;

            double leftTopX = 0;
            double leftTopY = fTopLeft;

            // check keypoints for overlap and resolve by partitioning radii according to
            // the percentage of each one.

            // top edge
            if (topLeftX > topRightX)
            {
                double v = (fLeftTop) / (fLeftTop + fRightTop) * boundRect.Width;
                topLeftX = v;
                topRightX = v;
            }
            // right edge
            if (rightTopY > rightBottomY)
            {
                double v = (fTopRight) / (fTopRight + fBottomRight) * boundRect.Height;
                rightTopY = v;
                rightBottomY = v;
            }
            // bottom edge
            if (bottomRightX < bottomLeftX)
            {
                double v = (fLeftBottom) / (fLeftBottom + fRightBottom) * boundRect.Width;
                bottomRightX = v;
                bottomLeftX = v;
            }
            // left edge
            if (leftBottomY < leftTopY)
            {
                double v = (fTopLeft) / (fTopLeft + fBottomLeft) * boundRect.Height;
                leftBottomY = v;
                leftTopY = v;
            }

            // The above code does all calculations without taking into consideration X/Y absolute position.
            // In WinUI, this is compensated for in DrawRoundedCornersRectangle(); however, we do this here directly
            // when the final keypoints are being created.
            var keypoints = new RoundedRectKeypoints();
            keypoints.TopLeft = new Point(
                boundRect.X + topLeftX,
                boundRect.Y + topLeftY);
            keypoints.TopRight = new Point(
                boundRect.X + topRightX,
                boundRect.Y + topRightY);

            keypoints.RightTop = new Point(
                boundRect.X + rightTopX,
                boundRect.Y + rightTopY);
            keypoints.RightBottom = new Point(
                boundRect.X + rightBottomX,
                boundRect.Y + rightBottomY);

            keypoints.BottomRight = new Point(
                boundRect.X + bottomRightX,
                boundRect.Y + bottomRightY);
            keypoints.BottomLeft = new Point(
                boundRect.X + bottomLeftX,
                boundRect.Y + bottomLeftY);

            keypoints.LeftBottom = new Point(
                boundRect.X + leftBottomX,
                boundRect.Y + leftBottomY);
            keypoints.LeftTop = new Point(
                boundRect.X + leftTopX,
                boundRect.Y + leftTopY);

            return keypoints;
        }