Wrapper for matrix image filters (#4567)

Fixes https://github.com/flutter/flutter/issues/14082
diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart
index 2ad6216..0965b57 100644
--- a/lib/ui/painting.dart
+++ b/lib/ui/painting.dart
@@ -1721,26 +1721,25 @@
 class ImageFilter extends NativeFieldWrapperClass2 {
   void _constructor() native 'ImageFilter_constructor';
 
-  /// A source filter containing an image.
-  // ImageFilter.image({ Image image }) {
-  //   _constructor();
-  //   _initImage(image);
-  // }
-  // void _initImage(Image image) native 'ImageFilter_initImage';
-
-  /// A source filter containing a picture.
-  // ImageFilter.picture({ Picture picture }) {
-  //   _constructor();
-  //   _initPicture(picture);
-  // }
-  // void _initPicture(Picture picture) native 'ImageFilter_initPicture';
-
   /// Creates an image filter that applies a Gaussian blur.
   ImageFilter.blur({ double sigmaX: 0.0, double sigmaY: 0.0 }) {
     _constructor();
     _initBlur(sigmaX, sigmaY);
   }
   void _initBlur(double sigmaX, double sigmaY) native 'ImageFilter_initBlur';
+
+  /// Creates an image filter that applies a matrix transformation.
+  ///
+  /// For example, applying a positive scale matrix (see [new Matrix4.diagonal3])
+  /// when used with [BackdropFilter] would magnify the background image.
+  ImageFilter.matrix(Float64List matrix4,
+                     { FilterQuality filterQuality: FilterQuality.low }) {
+    if (matrix4.length != 16)
+      throw new ArgumentError('"matrix4" must have 16 entries.');
+    _constructor();
+    _initMatrix(matrix4, filterQuality.index);
+  }
+  void _initMatrix(Float64List matrix4, int filterQuality) native 'ImageFilter_initMatrix';
 }
 
 /// Base class for objects such as [Gradient] and [ImageShader] which
diff --git a/lib/ui/painting/image_filter.cc b/lib/ui/painting/image_filter.cc
index 40b1628..299c8bb 100644
--- a/lib/ui/painting/image_filter.cc
+++ b/lib/ui/painting/image_filter.cc
@@ -4,6 +4,7 @@
 
 #include "flutter/lib/ui/painting/image_filter.h"
 
+#include "flutter/lib/ui/painting/matrix.h"
 #include "lib/tonic/converter/dart_converter.h"
 #include "lib/tonic/dart_args.h"
 #include "lib/tonic/dart_binding_macros.h"
@@ -11,6 +12,7 @@
 #include "third_party/skia/include/effects/SkBlurImageFilter.h"
 #include "third_party/skia/include/effects/SkImageSource.h"
 #include "third_party/skia/include/effects/SkPictureImageFilter.h"
+#include "third_party/skia/src/core/SkMatrixImageFilter.h"
 
 namespace blink {
 
@@ -23,7 +25,8 @@
 #define FOR_EACH_BINDING(V)   \
   V(ImageFilter, initImage)   \
   V(ImageFilter, initPicture) \
-  V(ImageFilter, initBlur)
+  V(ImageFilter, initBlur)    \
+  V(ImageFilter, initMatrix)
 
 FOR_EACH_BINDING(DART_NATIVE_CALLBACK)
 
@@ -54,4 +57,11 @@
                                     SkBlurImageFilter::kClamp_TileMode);
 }
 
+void ImageFilter::initMatrix(const tonic::Float64List& matrix4,
+                             int filterQuality) {
+  filter_ = SkMatrixImageFilter::Make(
+      ToSkMatrix(matrix4), static_cast<SkFilterQuality>(filterQuality),
+      nullptr);
+}
+
 }  // namespace blink
diff --git a/lib/ui/painting/image_filter.h b/lib/ui/painting/image_filter.h
index 9aec707..0c3afa5 100644
--- a/lib/ui/painting/image_filter.h
+++ b/lib/ui/painting/image_filter.h
@@ -8,6 +8,7 @@
 #include "flutter/lib/ui/painting/image.h"
 #include "flutter/lib/ui/painting/picture.h"
 #include "lib/tonic/dart_wrappable.h"
+#include "lib/tonic/typed_data/float64_list.h"
 #include "third_party/skia/include/core/SkImageFilter.h"
 
 namespace blink {
@@ -24,6 +25,7 @@
   void initImage(CanvasImage* image);
   void initPicture(Picture*);
   void initBlur(double sigma_x, double sigma_y);
+  void initMatrix(const tonic::Float64List& matrix4, int filter_quality);
 
   const sk_sp<SkImageFilter>& filter() { return filter_; }