InputDecorator should clip fill color to its border (#15795)

diff --git a/packages/flutter/lib/src/material/input_decorator.dart b/packages/flutter/lib/src/material/input_decorator.dart
index a5798dc..1038c97 100644
--- a/packages/flutter/lib/src/material/input_decorator.dart
+++ b/packages/flutter/lib/src/material/input_decorator.dart
@@ -68,6 +68,7 @@
     this.gapAnimation,
     this.gap,
     this.textDirection,
+    this.fillColor,
   }) : super(repaint: repaint);
 
   final Animation<double> borderAnimation;
@@ -75,12 +76,25 @@
   final Animation<double> gapAnimation;
   final _InputBorderGap gap;
   final TextDirection textDirection;
+  final Color fillColor;
 
   @override
   void paint(Canvas canvas, Size size) {
-    border.evaluate(borderAnimation).paint(
+    final InputBorder borderValue = border.evaluate(borderAnimation);
+    final Rect canvasRect = Offset.zero & size;
+
+    if (fillColor.alpha > 0) {
+      canvas.drawPath(
+        borderValue.getOuterPath(canvasRect, textDirection: textDirection),
+        new Paint()
+          ..color = fillColor
+          ..style = PaintingStyle.fill,
+      );
+    }
+
+    borderValue.paint(
       canvas,
-      Offset.zero & size,
+      canvasRect,
       gapStart: gap.start,
       gapExtent: gap.extent,
       gapPercentage: gapAnimation.value,
@@ -108,14 +122,17 @@
     @required this.border,
     @required this.gap,
     @required this.gapAnimation,
+    @required this.fillColor,
     this.child,
   }) : assert(border != null),
        assert(gap != null),
+       assert(fillColor != null),
        super(key: key);
 
   final InputBorder border;
   final _InputBorderGap gap;
   final Animation<double> gapAnimation;
+  final Color fillColor;
   final Widget child;
 
   @override
@@ -174,6 +191,7 @@
         gapAnimation: widget.gapAnimation,
         gap: widget.gap,
         textDirection: Directionality.of(context),
+        fillColor: widget.fillColor,
       ),
       child: widget.child,
     );
@@ -1518,15 +1536,16 @@
       ),
     );
 
-    final Widget containerFill = new DecoratedBox(
-      decoration: new BoxDecoration(color: _getFillColor(themeData)),
-    );
-    final Widget container = border == null ? containerFill : new _BorderContainer(
-      border: border,
-      gap: _borderGap,
-      gapAnimation: _floatingLabelController.view,
-      child: containerFill,
-    );
+    final Widget container = border == null
+      ? new DecoratedBox(
+          decoration: new BoxDecoration(color: _getFillColor(themeData))
+        )
+      : new _BorderContainer(
+          border: border,
+          gap: _borderGap,
+          gapAnimation: _floatingLabelController.view,
+          fillColor: _getFillColor(themeData),
+        );
 
     final TextStyle inlineLabelStyle = inlineStyle.merge(decoration.labelStyle);
     final Widget label = decoration.labelText == null ? null : new _Shaker(
diff --git a/packages/flutter/test/material/input_decorator_test.dart b/packages/flutter/test/material/input_decorator_test.dart
index cbc5d5c..d088675 100644
--- a/packages/flutter/test/material/input_decorator_test.dart
+++ b/packages/flutter/test/material/input_decorator_test.dart
@@ -6,6 +6,8 @@
 import 'package:flutter/rendering.dart';
 import 'package:flutter_test/flutter_test.dart';
 
+import '../rendering/mock_canvas.dart';
+
 Widget buildInputDecorator({
   InputDecoration decoration: const InputDecoration(),
   InputDecorationTheme inputDecorationTheme,
@@ -1188,4 +1190,44 @@
     expect(decoration.fillColor, Colors.blue);
     expect(decoration.border, const OutlineInputBorder());
   });
+
+  testWidgets('InputDecorator fillColor is clipped by border', (WidgetTester tester) async {
+    // This is a regression test for https://github.com/flutter/flutter/issues/15742
+
+    await tester.pumpWidget(
+      buildInputDecorator(
+        // isEmpty: false (default)
+        // isFocused: false (default)
+        decoration: new InputDecoration(
+          filled: true,
+          fillColor: const Color(0xFF00FF00),
+          border: new OutlineInputBorder(
+            borderRadius: new BorderRadius.circular(12.0),
+          ),
+        ),
+      ),
+    );
+
+    final RenderBox box = tester.renderObject(find.byType(InputDecorator));
+
+    // Fill is the border's outer path, a rounded rectangle
+    expect(box, paints..path(
+      style: PaintingStyle.fill,
+      color: const Color(0xFF00FF00),
+      includes: <Offset>[const Offset(800.0/2.0, 56/2.0)],
+      excludes: <Offset>[
+        const Offset(1.0, 6.0), // outside the rounded corner, top left
+        const Offset(800.0 - 1.0, 6.0), // top right
+        const Offset(1.0, 56.0 - 6.0), // bottom left
+        const Offset(800 - 1.0, 56.0 - 6.0), // bottom right
+      ],
+    ));
+
+    // Border outline. The rrect is the -center- of the 1.0 stroked outline.
+    expect(box, paints..rrect(
+      style: PaintingStyle.stroke,
+      strokeWidth: 1.0,
+      rrect: new RRect.fromLTRBR(0.5, 0.5, 799.5, 55.5, const Radius.circular(11.5)),
+    ));
+  });
 }