@@ -1164,6 +1164,18 @@ class RSuperellipse extends _RRectLike<RSuperellipse> {
11641164 @override
11651165 final bool _uniformRadii;
11661166
1167+ static (double , double ) _normalizeEmptyToZero (double inputX, double inputY) {
1168+ return (inputX > 0 && inputY > 0 ) ? (inputX, inputY) : (0 , 0 );
1169+ }
1170+
1171+ static double _adjustScale (double radius1, double radius2, double dimension, double scale) {
1172+ assert (radius1 >= 0.0 && radius2 >= 0.0 && dimension > 0.0 );
1173+ if (radius1 + radius2 > dimension) {
1174+ return math.min (scale, dimension / (radius1 + radius2));
1175+ }
1176+ return scale;
1177+ }
1178+
11671179 /// (Web only) Returns a [Path] for this shape and an [Offset] for its
11681180 /// placement.
11691181 ///
@@ -1180,9 +1192,9 @@ class RSuperellipse extends _RRectLike<RSuperellipse> {
11801192 /// `path` and the `offset` to the `addPath` method.
11811193 (Path , Offset ) toPathOffset () {
11821194 if (_uniformRadii) {
1183- return (_RSuperellipseCache .instance.get (width, height, tlRadius ), center);
1195+ return (_RSuperellipseCache .instance.get (width, height, _scaledUniformRadii () ), center);
11841196 } else {
1185- return (_RSuperellipsePathBuilder .exact (this ).path, Offset .zero);
1197+ return (_RSuperellipsePathBuilder .exact (_toScaledRadii () ).path, Offset .zero);
11861198 }
11871199 }
11881200
@@ -1211,6 +1223,81 @@ class RSuperellipse extends _RRectLike<RSuperellipse> {
12111223 );
12121224 }
12131225
1226+ /// Returns a [RSuperellipse] whose corner radii are scaled based on this one,
1227+ /// ensuring that the sum of the corner radii on each side does not exceed the
1228+ /// width or height of the given bounds.
1229+ ///
1230+ /// See the [Skia scaling
1231+ /// implementation](https://github.com/google/skia/blob/main/src/core/SkRRect.cpp)
1232+ /// for more details.
1233+ RSuperellipse _toScaledRadii () {
1234+ if (! (width > 0 && height > 0 )) {
1235+ return RSuperellipse .fromLTRBXY (left, top, right, bottom, 0.0 , 0.0 );
1236+ }
1237+
1238+ // If any corner is flat or has a negative value, normalize it to zeros
1239+ // We do this first so that the unnecessary non-flat part of that radius
1240+ // does not contribute to the global scaling below.
1241+ final (double tlRadiusX, double tlRadiusY) = _normalizeEmptyToZero (
1242+ this .tlRadiusX,
1243+ this .tlRadiusY,
1244+ );
1245+ final (double trRadiusX, double trRadiusY) = _normalizeEmptyToZero (
1246+ this .trRadiusX,
1247+ this .trRadiusY,
1248+ );
1249+ final (double blRadiusX, double blRadiusY) = _normalizeEmptyToZero (
1250+ this .blRadiusX,
1251+ this .blRadiusY,
1252+ );
1253+ final (double brRadiusX, double brRadiusY) = _normalizeEmptyToZero (
1254+ this .brRadiusX,
1255+ this .brRadiusY,
1256+ );
1257+
1258+ // Now determine a global scale to apply to all of the radii to ensure
1259+ // that none of the adjacent pairs of radius values sum to larger than
1260+ // the corresponding dimension of the rectangle.
1261+ double scale = 1.0 ;
1262+ scale = _adjustScale (tlRadiusX, trRadiusX, width, scale);
1263+ scale = _adjustScale (blRadiusX, brRadiusX, width, scale);
1264+ scale = _adjustScale (tlRadiusY, blRadiusY, height, scale);
1265+ scale = _adjustScale (trRadiusY, brRadiusY, height, scale);
1266+ if (scale < 1.0 ) {
1267+ return _create (
1268+ left: left,
1269+ top: top,
1270+ right: right,
1271+ bottom: bottom,
1272+ tlRadiusX: tlRadiusX * scale,
1273+ tlRadiusY: tlRadiusY * scale,
1274+ trRadiusX: trRadiusX * scale,
1275+ trRadiusY: trRadiusY * scale,
1276+ brRadiusX: brRadiusX * scale,
1277+ brRadiusY: brRadiusY * scale,
1278+ blRadiusX: blRadiusX * scale,
1279+ blRadiusY: blRadiusY * scale,
1280+ uniformRadii: _uniformRadii,
1281+ );
1282+ } else {
1283+ return this ;
1284+ }
1285+ }
1286+
1287+ // A variation of `_toScaledRadii` that deals with uniform radii and returns a
1288+ // `Radius`.
1289+ Radius _scaledUniformRadii () {
1290+ assert (_uniformRadii);
1291+ if (! (width > 0 && height > 0 )) {
1292+ return Radius .zero;
1293+ }
1294+ final (double radiusX, double radiusY) = _normalizeEmptyToZero (tlRadiusX, tlRadiusY);
1295+ double scale = 1.0 ;
1296+ scale = _adjustScale (radiusX, radiusX, width, scale);
1297+ scale = _adjustScale (radiusY, radiusY, height, scale);
1298+ return Radius .elliptical (radiusX * scale, radiusY * scale);
1299+ }
1300+
12141301 static const RSuperellipse zero = RSuperellipse ._raw ();
12151302
12161303 bool contains (Offset point) {
0 commit comments