Added a filterQuality parameter to images. (#23329)

* Added a filterQuality parameter to images.

* Removed this break by accident.

* Modified the test case to check the filterQuality

* Update packages/flutter/lib/src/rendering/image.dart

Co-Authored-By: namanix <namanix@gmail.com>

* Update packages/flutter/lib/src/rendering/image.dart

Co-Authored-By: namanix <namanix@gmail.com>

* Update packages/flutter/lib/src/rendering/image.dart

Co-Authored-By: namanix <namanix@gmail.com>

* Update packages/flutter/lib/src/widgets/image.dart

Co-Authored-By: namanix <namanix@gmail.com>

* Update packages/flutter/lib/src/widgets/image.dart

Co-Authored-By: namanix <namanix@gmail.com>

* Update packages/flutter/lib/src/rendering/image.dart

Co-Authored-By: namanix <namanix@gmail.com>

* Update packages/flutter/lib/src/rendering/image.dart

Co-Authored-By: namanix <namanix@gmail.com>

* Added documentation for the new parameter and corrected some space issue's
diff --git a/packages/flutter/lib/src/painting/decoration_image.dart b/packages/flutter/lib/src/painting/decoration_image.dart
index fa0a4c8..18462ea 100644
--- a/packages/flutter/lib/src/painting/decoration_image.dart
+++ b/packages/flutter/lib/src/painting/decoration_image.dart
@@ -261,6 +261,7 @@
       centerSlice: _details.centerSlice,
       repeat: _details.repeat,
       flipHorizontally: flipHorizontally,
+      filterQuality: FilterQuality.low
     );
 
     if (clipPath != null)
@@ -347,7 +348,12 @@
 ///    invert will be applied after it. This is primarily used for implementing
 ///    smart invert on iOS.
 ///
-/// The `canvas`, `rect`, `image`, `scale`, `alignment`, `repeat`, and `flipHorizontally`
+///  * `filterQuality`: Use this to change the quality when scaling an image.
+///     Use the [FilterQuality.low] quality setting to scale the image, which corresponds to
+///     bilinear interpolation, rather than the default [FilterQuality.none] which corresponds
+///     to nearest-neighbor.
+///
+/// The `canvas`, `rect`, `image`, `scale`, `alignment`, `repeat`, `flipHorizontally` and `filterQuality`
 /// arguments must not be null.
 ///
 /// See also:
@@ -367,6 +373,7 @@
   ImageRepeat repeat = ImageRepeat.noRepeat,
   bool flipHorizontally = false,
   bool invertColors = false,
+  FilterQuality filterQuality = FilterQuality.low
 }) {
   assert(canvas != null);
   assert(image != null);
@@ -407,10 +414,7 @@
   if (colorFilter != null)
     paint.colorFilter = colorFilter;
   if (sourceSize != destinationSize) {
-    // Use the "low" quality setting to scale the image, which corresponds to
-    // bilinear interpolation, rather than the default "none" which corresponds
-    // to nearest-neighbor.
-    paint.filterQuality = FilterQuality.low;
+    paint.filterQuality = filterQuality;
   }
   paint.invertColors = invertColors;
   final double halfWidthDelta = (outputSize.width - destinationSize.width) / 2.0;
diff --git a/packages/flutter/lib/src/rendering/image.dart b/packages/flutter/lib/src/rendering/image.dart
index 6844002..6f12dfa 100644
--- a/packages/flutter/lib/src/rendering/image.dart
+++ b/packages/flutter/lib/src/rendering/image.dart
@@ -21,7 +21,7 @@
 class RenderImage extends RenderBox {
   /// Creates a render box that displays an image.
   ///
-  /// The [scale], [alignment], [repeat], and [matchTextDirection] arguments
+  /// The [scale], [alignment], [repeat], [matchTextDirection] and [filterQuality] arguments
   /// must not be null. The [textDirection] argument must not be null if
   /// [alignment] will need resolving or if [matchTextDirection] is true.
   RenderImage({
@@ -37,10 +37,12 @@
     Rect centerSlice,
     bool matchTextDirection = false,
     TextDirection textDirection,
-    bool invertColors = false
+    bool invertColors = false,
+    FilterQuality filterQuality = FilterQuality.low
   }) : assert(scale != null),
        assert(repeat != null),
        assert(alignment != null),
+       assert(filterQuality != null),
        assert(matchTextDirection != null),
        _image = image,
        _width = width,
@@ -54,7 +56,8 @@
        _centerSlice = centerSlice,
        _matchTextDirection = matchTextDirection,
        _invertColors = invertColors,
-       _textDirection = textDirection {
+       _textDirection = textDirection,
+       _filterQuality = filterQuality {
     _updateColorFilter();
   }
 
@@ -145,6 +148,21 @@
     markNeedsPaint();
   }
 
+  /// Used to set the filterQuality of the image
+  /// Use the [FilterQuality.low] quality setting to scale the image, which corresponds to
+  /// bilinear interpolation, rather than the default [FilterQuality.none] which corresponds
+  /// to nearest-neighbor.
+  FilterQuality get filterQuality => _filterQuality;
+  FilterQuality _filterQuality;
+  set filterQuality(FilterQuality value) {
+    assert(value != null);
+    if(value == _filterQuality)
+      return;
+    _filterQuality = value;
+    markNeedsPaint();
+  }
+
+
   /// Used to combine [color] with this image.
   ///
   /// The default is [BlendMode.srcIn]. In terms of the blend mode, [color] is
@@ -348,6 +366,7 @@
       repeat: _repeat,
       flipHorizontally: _flipHorizontally,
       invertColors: invertColors,
+      filterQuality: _filterQuality
     );
   }
 
@@ -367,5 +386,6 @@
     properties.add(FlagProperty('matchTextDirection', value: matchTextDirection, ifTrue: 'match text direction'));
     properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
     properties.add(DiagnosticsProperty<bool>('invertColors', invertColors));
+    properties.add(EnumProperty<FilterQuality>('filterQuality', filterQuality));
   }
 }
diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart
index f08f66f..12410f3 100644
--- a/packages/flutter/lib/src/widgets/basic.dart
+++ b/packages/flutter/lib/src/widgets/basic.dart
@@ -4498,7 +4498,7 @@
 class RawImage extends LeafRenderObjectWidget {
   /// Creates a widget that displays an image.
   ///
-  /// The [scale], [alignment], [repeat], and [matchTextDirection] arguments must
+  /// The [scale], [alignment], [repeat], [matchTextDirection] and [filterQuality] arguments must
   /// not be null.
   const RawImage({
     Key key,
@@ -4514,6 +4514,7 @@
     this.centerSlice,
     this.matchTextDirection = false,
     this.invertColors = false,
+    this.filterQuality = FilterQuality.low,
   }) : assert(scale != null),
        assert(alignment != null),
        assert(repeat != null),
@@ -4543,6 +4544,12 @@
   /// If non-null, this color is blended with each image pixel using [colorBlendMode].
   final Color color;
 
+  /// Used to set the filterQuality of the image
+  /// Use the "low" quality setting to scale the image, which corresponds to
+  /// bilinear interpolation, rather than the default "none" which corresponds
+  /// to nearest-neighbor.
+  final FilterQuality filterQuality;
+
   /// Used to combine [color] with this image.
   ///
   /// The default is [BlendMode.srcIn]. In terms of the blend mode, [color] is
@@ -4643,6 +4650,7 @@
       matchTextDirection: matchTextDirection,
       textDirection: matchTextDirection || alignment is! Alignment ? Directionality.of(context) : null,
       invertColors: invertColors,
+      filterQuality: filterQuality,
     );
   }
 
@@ -4661,7 +4669,8 @@
       ..centerSlice = centerSlice
       ..matchTextDirection = matchTextDirection
       ..textDirection = matchTextDirection || alignment is! Alignment ? Directionality.of(context) : null
-      ..invertColors = invertColors;
+      ..invertColors = invertColors
+      ..filterQuality = filterQuality;
   }
 
   @override
@@ -4679,6 +4688,7 @@
     properties.add(DiagnosticsProperty<Rect>('centerSlice', centerSlice, defaultValue: null));
     properties.add(FlagProperty('matchTextDirection', value: matchTextDirection, ifTrue: 'match text direction'));
     properties.add(DiagnosticsProperty<bool>('invertColors', invertColors));
+    properties.add(EnumProperty<FilterQuality>('filterQuality', filterQuality));
   }
 }
 
diff --git a/packages/flutter/lib/src/widgets/image.dart b/packages/flutter/lib/src/widgets/image.dart
index 6901b7e..b6c2a9a 100644
--- a/packages/flutter/lib/src/widgets/image.dart
+++ b/packages/flutter/lib/src/widgets/image.dart
@@ -21,6 +21,7 @@
   AssetImage,
   ExactAssetImage,
   FileImage,
+  FilterQuality,
   ImageConfiguration,
   ImageInfo,
   ImageStream,
@@ -143,6 +144,11 @@
   /// Otherwise, the image dimensions will change as the image is loaded, which
   /// will result in ugly layout changes.
   ///
+  /// Use [filterQuality] to change the quality when scaling an image.
+  /// Use the [FilterQuality.low] quality setting to scale the image,
+  /// which corresponds to bilinear interpolation, rather than the default
+  /// [FilterQuality.none] which corresponds to nearest-neighbor.
+  ///
   /// If [excludeFromSemantics] is true, then [semanticLabel] will be ignored.
   const Image({
     Key key,
@@ -159,9 +165,11 @@
     this.centerSlice,
     this.matchTextDirection = false,
     this.gaplessPlayback = false,
+    this.filterQuality = FilterQuality.low,
   }) : assert(image != null),
        assert(alignment != null),
        assert(repeat != null),
+       assert(filterQuality != null),
        assert(matchTextDirection != null),
        super(key: key);
 
@@ -179,6 +187,11 @@
   /// An optional [headers] argument can be used to send custom HTTP headers
   /// with the image request.
   ///
+  /// Use [filterQuality] to change the quality when scaling an image.
+  /// Use the [FilterQuality.low] quality setting to scale the image,
+  /// which corresponds to bilinear interpolation, rather than the default
+  /// [FilterQuality.none] which corresponds to nearest-neighbor.
+  ///
   /// If [excludeFromSemantics] is true, then [semanticLabel] will be ignored.
   Image.network(String src, {
     Key key,
@@ -195,6 +208,7 @@
     this.centerSlice,
     this.matchTextDirection = false,
     this.gaplessPlayback = false,
+    this.filterQuality = FilterQuality.low,
     Map<String, String> headers,
   }) : image = NetworkImage(src, scale: scale, headers: headers),
        assert(alignment != null),
@@ -214,6 +228,11 @@
   /// On Android, this may require the
   /// `android.permission.READ_EXTERNAL_STORAGE` permission.
   ///
+  /// Use [filterQuality] to change the quality when scaling an image.
+  /// Use the [FilterQuality.low] quality setting to scale the image,
+  /// which corresponds to bilinear interpolation, rather than the default
+  /// [FilterQuality.none] which corresponds to nearest-neighbor.
+  ///
   /// If [excludeFromSemantics] is true, then [semanticLabel] will be ignored.
   Image.file(File file, {
     Key key,
@@ -230,9 +249,11 @@
     this.centerSlice,
     this.matchTextDirection = false,
     this.gaplessPlayback = false,
+    this.filterQuality = FilterQuality.low,
   }) : image = FileImage(file, scale: scale),
        assert(alignment != null),
        assert(repeat != null),
+       assert(filterQuality != null),
        assert(matchTextDirection != null),
        super(key: key);
 
@@ -272,6 +293,11 @@
   /// Otherwise, the image dimensions will change as the image is loaded, which
   /// will result in ugly layout changes.
   ///
+  /// Use [filterQuality] to change the quality when scaling an image.
+  /// Use the [FilterQuality.low] quality setting to scale the image,
+  /// which corresponds to bilinear interpolation, rather than the default
+  /// [FilterQuality.none] which corresponds to nearest-neighbor.
+  ///
   /// ## Sample code
   ///
   /// Suppose that the project's `pubspec.yaml` file contains the following:
@@ -370,6 +396,7 @@
     this.matchTextDirection = false,
     this.gaplessPlayback = false,
     String package,
+    this.filterQuality = FilterQuality.low,
   }) : image = scale != null
          ? ExactAssetImage(name, bundle: bundle, scale: scale, package: package)
          : AssetImage(name, bundle: bundle, package: package),
@@ -387,6 +414,11 @@
   /// Otherwise, the image dimensions will change as the image is loaded, which
   /// will result in ugly layout changes.
   ///
+  /// Use [filterQuality] to change the quality when scaling an image.
+  /// Use the [FilterQuality.low] quality setting to scale the image,
+  /// which corresponds to bilinear interpolation, rather than the default
+  /// [FilterQuality.none] which corresponds to nearest-neighbor.
+  ///
   /// If [excludeFromSemantics] is true, then [semanticLabel] will be ignored.
   Image.memory(Uint8List bytes, {
     Key key,
@@ -403,6 +435,7 @@
     this.centerSlice,
     this.matchTextDirection = false,
     this.gaplessPlayback = false,
+    this.filterQuality = FilterQuality.low,
   }) : image = MemoryImage(bytes, scale: scale),
        assert(alignment != null),
        assert(repeat != null),
@@ -439,6 +472,12 @@
   /// If non-null, this color is blended with each image pixel using [colorBlendMode].
   final Color color;
 
+  /// Used to set the filterQuality of the image
+  /// Use the "low" quality setting to scale the image, which corresponds to
+  /// bilinear interpolation, rather than the default "none" which corresponds
+  /// to nearest-neighbor.
+  final FilterQuality filterQuality;
+
   /// Used to combine [color] with this image.
   ///
   /// The default is [BlendMode.srcIn]. In terms of the blend mode, [color] is
@@ -545,6 +584,7 @@
     properties.add(FlagProperty('matchTextDirection', value: matchTextDirection, ifTrue: 'match text direction'));
     properties.add(StringProperty('semanticLabel', semanticLabel, defaultValue: null));
     properties.add(DiagnosticsProperty<bool>('this.excludeFromSemantics', excludeFromSemantics));
+    properties.add(EnumProperty<FilterQuality>('filterQuality', filterQuality));
   }
 }
 
@@ -651,6 +691,7 @@
       centerSlice: widget.centerSlice,
       matchTextDirection: widget.matchTextDirection,
       invertColors: _invertColors,
+      filterQuality: widget.filterQuality,
     );
     if (widget.excludeFromSemantics)
       return image;
diff --git a/packages/flutter/test/rendering/image_test.dart b/packages/flutter/test/rendering/image_test.dart
index 1426262..fef1f8d 100644
--- a/packages/flutter/test/rendering/image_test.dart
+++ b/packages/flutter/test/rendering/image_test.dart
@@ -93,6 +93,7 @@
         '   image: [10×10]\n'
         '   alignment: center\n'
         '   invertColors: false\n'
+        '   filterQuality: low\n'
       ),
     );