diff --git a/engine/src/flutter/lib/ui/geometry.dart b/engine/src/flutter/lib/ui/geometry.dart index 371b925a94e..822beb25c0b 100644 --- a/engine/src/flutter/lib/ui/geometry.dart +++ b/engine/src/flutter/lib/ui/geometry.dart @@ -1416,12 +1416,16 @@ class RRect { return min; } - // Scales all radii so that on each side their sum will not pass the size of - // the width/height. - // - // Inspired from: - // https://github.com/google/skia/blob/master/src/core/SkRRect.cpp#L164 - RRect _scaleRadii() { + /// Scales all radii so that on each side their sum will not exceed the size + /// of the width/height. + /// + /// Skia already handles RRects with radii that are too large in this way. + /// Therefore, this method is only needed for RRect use cases that require + /// the appropriately scaled radii values. + /// + /// See the [Skia scaling implementation](https://github.com/google/skia/blob/master/src/core/SkRRect.cpp) + /// for more details. + RRect scaleRadii() { double scale = 1.0; scale = _getMin(scale, blRadiusY, tlRadiusY, height); scale = _getMin(scale, tlRadiusX, trRadiusX, width); @@ -1472,7 +1476,7 @@ class RRect { if (point.dx < left || point.dx >= right || point.dy < top || point.dy >= bottom) return false; // outside bounding box - final RRect scaled = _scaleRadii(); + final RRect scaled = scaleRadii(); double x; double y; diff --git a/engine/src/flutter/testing/dart/rrect_test.dart b/engine/src/flutter/testing/dart/rrect_test.dart index 6b4b75de4dd..7b1297e387f 100644 --- a/engine/src/flutter/testing/dart/rrect_test.dart +++ b/engine/src/flutter/testing/dart/rrect_test.dart @@ -44,4 +44,56 @@ void main() { expect(rrect.contains(const Offset(1.7, 1.97)), isTrue); expect(rrect.contains(const Offset(1.0, 1.99)), isTrue); }); + + test('RRect.scaleRadii() properly constrained radii should remain unchanged', () { + final RRect rrect = RRect.fromRectAndCorners( + const Rect.fromLTRB(1.0, 1.0, 2.0, 2.0), + topLeft: const Radius.circular(0.5), + topRight: const Radius.circular(0.25), + bottomRight: const Radius.elliptical(0.25, 0.75), + bottomLeft: Radius.zero, + ).scaleRadii(); + + // check sides + expect(rrect.left, 1.0); + expect(rrect.top, 1.0); + expect(rrect.right, 2.0); + expect(rrect.bottom, 2.0); + + // check corner radii + expect(rrect.tlRadiusX, 0.5); + expect(rrect.tlRadiusY, 0.5); + expect(rrect.trRadiusX, 0.25); + expect(rrect.trRadiusY, 0.25); + expect(rrect.blRadiusX, 0.0); + expect(rrect.blRadiusY, 0.0); + expect(rrect.brRadiusX, 0.25); + expect(rrect.brRadiusY, 0.75); + }); + + test('RRect.scaleRadii() sum of radii that exceed side length should properly scale', () { + final RRect rrect = RRect.fromRectAndCorners( + const Rect.fromLTRB(1.0, 1.0, 2.0, 2.0), + topLeft: const Radius.circular(5000.0), + topRight: const Radius.circular(2500.0), + bottomRight: const Radius.elliptical(2500.0, 7500.0), + bottomLeft: Radius.zero, + ).scaleRadii(); + + // check sides + expect(rrect.left, 1.0); + expect(rrect.top, 1.0); + expect(rrect.right, 2.0); + expect(rrect.bottom, 2.0); + + // check corner radii + expect(rrect.tlRadiusX, 0.5); + expect(rrect.tlRadiusY, 0.5); + expect(rrect.trRadiusX, 0.25); + expect(rrect.trRadiusY, 0.25); + expect(rrect.blRadiusX, 0.0); + expect(rrect.blRadiusY, 0.0); + expect(rrect.brRadiusX, 0.25); + expect(rrect.brRadiusY, 0.75); + }); }