Merge pull request #2494 from collinjackson/update_engine

Update engine.version
diff --git a/packages/flutter/lib/src/painting/box_painter.dart b/packages/flutter/lib/src/painting/box_painter.dart
index d833a3e..440d9f9 100644
--- a/packages/flutter/lib/src/painting/box_painter.dart
+++ b/packages/flutter/lib/src/painting/box_painter.dart
@@ -492,8 +492,7 @@
   ImageFit fit,
   ImageRepeat repeat: ImageRepeat.noRepeat,
   Rect centerSlice,
-  double alignX,
-  double alignY
+  FractionalOffset alignment
 }) {
   assert(canvas != null);
   assert(image != null);
@@ -508,6 +507,7 @@
     outputSize -= sliceBorder;
     inputSize -= sliceBorder;
   }
+  Point sourcePosition = Point.origin;
   Size sourceSize;
   Size destinationSize;
   fit ??= centerSlice == null ? ImageFit.scaleDown : ImageFit.fill;
@@ -525,10 +525,13 @@
         destinationSize = new Size(outputSize.width, sourceSize.height * outputSize.width / sourceSize.width);
       break;
     case ImageFit.cover:
-      if (outputSize.width / outputSize.height > inputSize.width / inputSize.height)
+      if (outputSize.width / outputSize.height > inputSize.width / inputSize.height) {
         sourceSize = new Size(inputSize.width, inputSize.width * outputSize.height / outputSize.width);
-      else
+        sourcePosition = new Point(0.0, (inputSize.height - sourceSize.height) * (alignment?.dy ?? 0.5));
+      } else {
         sourceSize = new Size(inputSize.height * outputSize.width / outputSize.height, inputSize.height);
+        sourcePosition = new Point((inputSize.width - sourceSize.width) * (alignment?.dx ?? 0.5), 0.0);
+      }
       destinationSize = outputSize;
       break;
     case ImageFit.none:
@@ -566,8 +569,8 @@
     // to nearest-neighbor.
     paint.filterQuality = FilterQuality.low;
   }
-  double dx = (outputSize.width - destinationSize.width) * (alignX ?? 0.5);
-  double dy = (outputSize.height - destinationSize.height) * (alignY ?? 0.5);
+  double dx = (outputSize.width - destinationSize.width) * (alignment?.dx ?? 0.5);
+  double dy = (outputSize.height - destinationSize.height) * (alignment?.dy ?? 0.5);
   Point destinationPosition = rect.topLeft + new Offset(dx, dy);
   Rect destinationRect = destinationPosition & destinationSize;
   if (repeat != ImageRepeat.noRepeat) {
@@ -575,7 +578,7 @@
     canvas.clipRect(rect);
   }
   if (centerSlice == null) {
-    Rect sourceRect = Point.origin & sourceSize;
+    Rect sourceRect = sourcePosition & sourceSize;
     for (Rect tileRect in _generateImageTileRects(rect, destinationRect, repeat))
       canvas.drawImageRect(image, sourceRect, tileRect, paint);
   } else {
@@ -1035,8 +1038,7 @@
       rect: rect,
       image: image,
       colorFilter: backgroundImage.colorFilter,
-      alignX: backgroundImage.alignment?.dx,
-      alignY: backgroundImage.alignment?.dy,
+      alignment: backgroundImage.alignment,
       fit:  backgroundImage.fit,
       repeat: backgroundImage.repeat
     );
diff --git a/packages/flutter/lib/src/rendering/custom_layout.dart b/packages/flutter/lib/src/rendering/custom_layout.dart
index f6ae934..88c481f 100644
--- a/packages/flutter/lib/src/rendering/custom_layout.dart
+++ b/packages/flutter/lib/src/rendering/custom_layout.dart
@@ -249,13 +249,8 @@
     return _getSize(constraints).height;
   }
 
-  bool get sizedByParent => true;
-
-  void performResize() {
-    size = _getSize(constraints);
-  }
-
   void performLayout() {
+    size = _getSize(constraints);
     delegate._callPerformLayout(size, firstChild);
   }
 
diff --git a/packages/flutter/lib/src/rendering/image.dart b/packages/flutter/lib/src/rendering/image.dart
index e4306b7..8ac1bfb 100644
--- a/packages/flutter/lib/src/rendering/image.dart
+++ b/packages/flutter/lib/src/rendering/image.dart
@@ -242,8 +242,7 @@
       image: _image,
       colorFilter: _colorFilter,
       fit: _fit,
-      alignX: _alignment?.dx,
-      alignY: _alignment?.dy,
+      alignment: _alignment,
       centerSlice: _centerSlice,
       repeat: _repeat
     );
diff --git a/packages/flutter/test/painting/paint_image_test.dart b/packages/flutter/test/painting/paint_image_test.dart
new file mode 100644
index 0000000..078d30e
--- /dev/null
+++ b/packages/flutter/test/painting/paint_image_test.dart
@@ -0,0 +1,49 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:ui' as ui;
+
+import 'package:flutter/painting.dart';
+
+import 'package:test/test.dart';
+
+class TestImage implements ui.Image {
+  TestImage({ this.width, this.height });
+
+  final int width;
+  final int height;
+
+  void dispose() { }
+}
+
+class TestCanvas implements Canvas {
+  final List<Invocation> invocations = <Invocation>[];
+
+  void noSuchMethod(Invocation invocation) {
+    invocations.add(invocation);
+  }
+}
+
+void main() {
+  test("Cover and align", () {
+    TestImage image = new TestImage(width: 300, height: 300);
+    TestCanvas canvas = new TestCanvas();
+    paintImage(
+      canvas: canvas,
+      rect: new Rect.fromLTWH(50.0, 75.0, 200.0, 100.0),
+      image: image,
+      fit: ImageFit.cover,
+      alignment: new FractionalOffset(0.0, 0.5)
+    );
+
+    Invocation command = canvas.invocations.firstWhere((Invocation invocation) {
+      return invocation.memberName == #drawImageRect;
+    });
+
+    expect(command, isNotNull);
+    expect(command.positionalArguments[0], equals(image));
+    expect(command.positionalArguments[1], equals(new Rect.fromLTWH(0.0, 75.0, 300.0, 150.0)));
+    expect(command.positionalArguments[2], equals(new Rect.fromLTWH(50.0, 75.0, 200.0, 100.0)));
+  });
+}
diff --git a/packages/flutter/test/widget/custom_multi_child_layout_test.dart b/packages/flutter/test/widget/custom_multi_child_layout_test.dart
index 900ec4d..bf3e208 100644
--- a/packages/flutter/test/widget/custom_multi_child_layout_test.dart
+++ b/packages/flutter/test/widget/custom_multi_child_layout_test.dart
@@ -53,6 +53,19 @@
   );
 }
 
+class PreferredSizeDelegate extends MultiChildLayoutDelegate {
+  PreferredSizeDelegate({ this.preferredSize });
+
+  final Size preferredSize;
+
+  Size getSize(BoxConstraints constraints) => preferredSize;
+
+  void performLayout(Size size) { }
+
+  bool shouldRelayout(PreferredSizeDelegate oldDelegate) {
+    return preferredSize != oldDelegate.preferredSize;
+  }
+}
 
 void main() {
   test('Control test for CustomMultiChildLayout', () {
@@ -124,4 +137,30 @@
 
     });
   });
+
+  test('Loose constraints', () {
+    testWidgets((WidgetTester tester) {
+      Key key = new UniqueKey();
+      tester.pumpWidget(new Center(
+        child: new CustomMultiChildLayout(
+          key: key,
+          delegate: new PreferredSizeDelegate(preferredSize: new Size(300.0, 200.0))
+        )
+      ));
+
+      RenderBox box = tester.findElementByKey(key).renderObject;
+      expect(box.size.width, equals(300.0));
+      expect(box.size.height, equals(200.0));
+
+      tester.pumpWidget(new Center(
+        child: new CustomMultiChildLayout(
+          key: key,
+          delegate: new PreferredSizeDelegate(preferredSize: new Size(350.0, 250.0))
+        )
+      ));
+
+      expect(box.size.width, equals(350.0));
+      expect(box.size.height, equals(250.0));
+    });
+  });
 }