OutlineInputBorder adjusts for borderRadius that is too large (#34515)

* Implement OutlineInputBorder BorderRadius scaling via RRect.scaleRadii

* Add regression test to test for border scaling
diff --git a/packages/flutter/lib/src/material/input_border.dart b/packages/flutter/lib/src/material/input_border.dart
index fa1866c..251033b 100644
--- a/packages/flutter/lib/src/material/input_border.dart
+++ b/packages/flutter/lib/src/material/input_border.dart
@@ -385,63 +385,68 @@
   }
 
   Path _gapBorderPath(Canvas canvas, RRect center, double start, double extent) {
+    // When the corner radii on any side add up to be greater than the
+    // given height, each radius has to be scaled to not exceed the
+    // size of the width/height of the RRect.
+    final RRect scaledRRect = center.scaleRadii();
+
     final Rect tlCorner = Rect.fromLTWH(
-      center.left,
-      center.top,
-      center.tlRadiusX * 2.0,
-      center.tlRadiusY * 2.0,
+      scaledRRect.left,
+      scaledRRect.top,
+      scaledRRect.tlRadiusX * 2.0,
+      scaledRRect.tlRadiusY * 2.0,
     );
     final Rect trCorner = Rect.fromLTWH(
-      center.right - center.trRadiusX * 2.0,
-      center.top,
-      center.trRadiusX * 2.0,
-      center.trRadiusY * 2.0,
+      scaledRRect.right - scaledRRect.trRadiusX * 2.0,
+      scaledRRect.top,
+      scaledRRect.trRadiusX * 2.0,
+      scaledRRect.trRadiusY * 2.0,
     );
     final Rect brCorner = Rect.fromLTWH(
-      center.right - center.brRadiusX * 2.0,
-      center.bottom - center.brRadiusY * 2.0,
-      center.brRadiusX * 2.0,
-      center.brRadiusY * 2.0,
+      scaledRRect.right - scaledRRect.brRadiusX * 2.0,
+      scaledRRect.bottom - scaledRRect.brRadiusY * 2.0,
+      scaledRRect.brRadiusX * 2.0,
+      scaledRRect.brRadiusY * 2.0,
     );
     final Rect blCorner = Rect.fromLTWH(
-      center.left,
-      center.bottom - center.brRadiusY * 2.0,
-      center.blRadiusX * 2.0,
-      center.blRadiusY * 2.0,
+      scaledRRect.left,
+      scaledRRect.bottom - scaledRRect.blRadiusY * 2.0,
+      scaledRRect.blRadiusX * 2.0,
+      scaledRRect.blRadiusX * 2.0,
     );
 
     const double cornerArcSweep = math.pi / 2.0;
-    final double tlCornerArcSweep = start < center.tlRadiusX
-      ? math.asin((start / center.tlRadiusX).clamp(-1.0, 1.0))
+    final double tlCornerArcSweep = start < scaledRRect.tlRadiusX
+      ? math.asin((start / scaledRRect.tlRadiusX).clamp(-1.0, 1.0))
       : math.pi / 2.0;
 
     final Path path = Path()
       ..addArc(tlCorner, math.pi, tlCornerArcSweep)
-      ..moveTo(center.left + center.tlRadiusX, center.top);
+      ..moveTo(scaledRRect.left + scaledRRect.tlRadiusX, scaledRRect.top);
 
-    if (start > center.tlRadiusX)
-      path.lineTo(center.left + start, center.top);
+    if (start > scaledRRect.tlRadiusX)
+      path.lineTo(scaledRRect.left + start, scaledRRect.top);
 
     const double trCornerArcStart = (3 * math.pi) / 2.0;
     const double trCornerArcSweep = cornerArcSweep;
-    if (start + extent < center.width - center.trRadiusX) {
+    if (start + extent < scaledRRect.width - scaledRRect.trRadiusX) {
       path
         ..relativeMoveTo(extent, 0.0)
-        ..lineTo(center.right - center.trRadiusX, center.top)
+        ..lineTo(scaledRRect.right - scaledRRect.trRadiusX, scaledRRect.top)
         ..addArc(trCorner, trCornerArcStart, trCornerArcSweep);
-    } else if (start + extent < center.width) {
-      final double dx = center.width - (start + extent);
-      final double sweep = math.acos(dx / center.trRadiusX);
+    } else if (start + extent < scaledRRect.width) {
+      final double dx = scaledRRect.width - (start + extent);
+      final double sweep = math.acos(dx / scaledRRect.trRadiusX);
       path.addArc(trCorner, trCornerArcStart + sweep, trCornerArcSweep - sweep);
     }
 
     return path
-      ..moveTo(center.right, center.top + center.trRadiusY)
-      ..lineTo(center.right, center.bottom - center.brRadiusY)
+      ..moveTo(scaledRRect.right, scaledRRect.top + scaledRRect.trRadiusY)
+      ..lineTo(scaledRRect.right, scaledRRect.bottom - scaledRRect.brRadiusY)
       ..addArc(brCorner, 0.0, cornerArcSweep)
-      ..lineTo(center.left + center.blRadiusX, center.bottom)
+      ..lineTo(scaledRRect.left + scaledRRect.blRadiusX, scaledRRect.bottom)
       ..addArc(blCorner, math.pi / 2.0, cornerArcSweep)
-      ..lineTo(center.left, center.top + center.trRadiusY);
+      ..lineTo(scaledRRect.left, scaledRRect.top + scaledRRect.tlRadiusY);
   }
 
   /// Draw a rounded rectangle around [rect] using [borderRadius].
diff --git a/packages/flutter/test/material/input_decorator_test.dart b/packages/flutter/test/material/input_decorator_test.dart
index 86ca4cc..0a15dc7 100644
--- a/packages/flutter/test/material/input_decorator_test.dart
+++ b/packages/flutter/test/material/input_decorator_test.dart
@@ -3170,6 +3170,110 @@
     expect(getBorder(tester), disabledBorder);
   });
 
+  testWidgets('OutlineInputBorder borders scale down to fit when large values are passed in', (WidgetTester tester) async {
+    // This is a regression test for https://github.com/flutter/flutter/issues/34327
+    const double largerBorderRadius = 200.0;
+    const double smallerBorderRadius = 100.0;
+
+    // Overall height for this InputDecorator is 56dps:
+    //   12 - top padding
+    //   12 - floating label (ahem font size 16dps * 0.75 = 12)
+    //    4 - floating label / input text gap
+    //   16 - input text (ahem font size 16dps)
+    //   12 - bottom padding
+    const double inputDecoratorHeight = 56.0;
+    const double inputDecoratorWidth = 800.0;
+
+    await tester.pumpWidget(
+      buildInputDecorator(
+        decoration: const InputDecoration(
+          filled: true,
+          fillColor: Color(0xFF00FF00),
+          labelText: 'label text',
+          border: OutlineInputBorder(
+            borderRadius: BorderRadius.only(
+              // Intentionally large values that are larger than the InputDecorator
+              topLeft: Radius.circular(smallerBorderRadius),
+              bottomLeft: Radius.circular(smallerBorderRadius),
+              topRight: Radius.circular(largerBorderRadius),
+              bottomRight: Radius.circular(largerBorderRadius),
+            ),
+          ),
+        ),
+      ),
+    );
+
+    // Skia determines the scale based on the ratios of radii to the total
+    // height or width allowed. In this case, it is the right side of the
+    // border, which have two corners with largerBorderRadius that add up
+    // to be 400.0.
+    const double denominator = largerBorderRadius * 2.0;
+
+    const double largerBorderRadiusScaled = largerBorderRadius / denominator * inputDecoratorHeight;
+    const double smallerBorderRadiusScaled = smallerBorderRadius / denominator * inputDecoratorHeight;
+
+    expect(findBorderPainter(), paints
+      ..save()
+      ..path(
+        style: PaintingStyle.fill,
+        color: const Color(0xFF00FF00),
+        includes: const <Offset>[
+          // The border should draw along the four edges of the
+          // InputDecorator.
+
+          // Top center
+          Offset(inputDecoratorWidth / 2.0, 0.0),
+          // Bottom center
+          Offset(inputDecoratorWidth / 2.0, inputDecoratorHeight),
+          // Left center
+          Offset(0.0, inputDecoratorHeight / 2.0),
+          // Right center
+          Offset(inputDecoratorWidth, inputDecoratorHeight / 2.0),
+
+          // The border path should contain points where each rounded corner
+          // ends.
+
+          // Bottom-right arc
+          Offset(inputDecoratorWidth, inputDecoratorHeight - largerBorderRadiusScaled),
+          Offset(inputDecoratorWidth - largerBorderRadiusScaled, inputDecoratorHeight),
+          // Top-right arc
+          Offset(inputDecoratorWidth,0.0 + largerBorderRadiusScaled),
+          Offset(inputDecoratorWidth - largerBorderRadiusScaled, 0.0),
+          // Bottom-left arc
+          Offset(0.0, inputDecoratorHeight - smallerBorderRadiusScaled),
+          Offset(0.0 + smallerBorderRadiusScaled, inputDecoratorHeight),
+          // Top-left arc
+          Offset(0.0,0.0 + smallerBorderRadiusScaled),
+          Offset(0.0 + smallerBorderRadiusScaled, 0.0),
+        ],
+        excludes: const <Offset>[
+          // The border should not contain the corner points, since the border
+          // is rounded.
+
+          // Top-left
+          Offset(0.0, 0.0),
+          // Top-right
+          Offset(inputDecoratorWidth, 0.0),
+          // Bottom-left
+          Offset(0.0, inputDecoratorHeight),
+          // Bottom-right
+          Offset(inputDecoratorWidth, inputDecoratorHeight),
+
+          // Corners with larger border ratio should not contain points outside
+          // of the larger radius.
+
+          // Bottom-right arc
+          Offset(inputDecoratorWidth, inputDecoratorHeight - smallerBorderRadiusScaled),
+          Offset(inputDecoratorWidth - smallerBorderRadiusScaled, inputDecoratorWidth),
+          // Top-left arc
+          Offset(inputDecoratorWidth, 0.0 + smallerBorderRadiusScaled),
+          Offset(inputDecoratorWidth - smallerBorderRadiusScaled, 0.0),
+        ],
+      )
+      ..restore()
+    );
+  });
+
   testWidgets('OutlineInputBorder radius carries over when lerping', (WidgetTester tester) async {
     // This is a regression test for https://github.com/flutter/flutter/issues/23982
     const Key key = Key('textField');