Make Layer.toImage() accept bounds rather than size (#17129)
It allows callers to account for things like shadows that paint
outside the bounds of the widget.
https://github.com/flutter/flutter/issues/16859
diff --git a/packages/flutter/lib/src/rendering/layer.dart b/packages/flutter/lib/src/rendering/layer.dart
index 031b532..aad6951 100644
--- a/packages/flutter/lib/src/rendering/layer.dart
+++ b/packages/flutter/lib/src/rendering/layer.dart
@@ -519,8 +519,9 @@
/// Capture an image of the current state of this layer and its children.
///
- /// The returned [ui.Image] has uncompressed raw RGBA bytes, in the
- /// dimensions [logicalSize] multiplied by the [pixelRatio].
+ /// The returned [ui.Image] has uncompressed raw RGBA bytes, will be offset
+ /// by the top-left corner of [bounds], and have dimensions equal to the size
+ /// of [bounds] multiplied by [pixelRatio].
///
/// The [pixelRatio] describes the scale between the logical pixels and the
/// size of the output image. It is independent of the
@@ -532,11 +533,12 @@
///
/// * [RenderRepaintBoundary.toImage] for a similar API at the render object level.
/// * [dart:ui.Scene.toImage] for more information about the image returned.
- Future<ui.Image> toImage(Size logicalSize, {double pixelRatio: 1.0}) async {
+ Future<ui.Image> toImage(Rect bounds, {double pixelRatio: 1.0}) async {
+ assert(bounds != null);
assert(pixelRatio != null);
final ui.SceneBuilder builder = new ui.SceneBuilder();
- final Matrix4 transform = new Matrix4.diagonal3Values(pixelRatio, pixelRatio, 1.0);
- transform.translate(-offset.dx, -offset.dy, 0.0);
+ final Matrix4 transform = new Matrix4.translationValues(bounds.left - offset.dx, bounds.top - offset.dy, 0.0);
+ transform.scale(pixelRatio, pixelRatio);
builder.pushTransform(transform.storage);
addToScene(builder, Offset.zero);
final ui.Scene scene = builder.build();
@@ -544,8 +546,8 @@
// Size is rounded up to the next pixel to make sure we don't clip off
// anything.
return await scene.toImage(
- (pixelRatio * logicalSize.width).ceil(),
- (pixelRatio * logicalSize.height).ceil(),
+ (pixelRatio * bounds.width).ceil(),
+ (pixelRatio * bounds.height).ceil(),
);
} finally {
scene.dispose();
diff --git a/packages/flutter/lib/src/rendering/proxy_box.dart b/packages/flutter/lib/src/rendering/proxy_box.dart
index 58bac8a..d67d1e8 100644
--- a/packages/flutter/lib/src/rendering/proxy_box.dart
+++ b/packages/flutter/lib/src/rendering/proxy_box.dart
@@ -2515,7 +2515,7 @@
/// * [dart:ui.Scene.toImage] for more information about the image returned.
Future<ui.Image> toImage({double pixelRatio: 1.0}) {
assert(!debugNeedsPaint);
- return layer.toImage(size, pixelRatio: pixelRatio);
+ return layer.toImage(Offset.zero & size, pixelRatio: pixelRatio);
}
diff --git a/packages/flutter/test/rendering/view_test.dart b/packages/flutter/test/rendering/view_test.dart
new file mode 100644
index 0000000..7da7bad
--- /dev/null
+++ b/packages/flutter/test/rendering/view_test.dart
@@ -0,0 +1,21 @@
+// Copyright 2018 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 'package:flutter/rendering.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+import 'rendering_tester.dart';
+
+void main() {
+ group('RenderView', () {
+ test('accounts for device pixel ratio in paintBounds', () {
+ layout(new RenderAspectRatio(aspectRatio: 1.0));
+ pumpFrame();
+ final Size logicalSize = renderer.renderView.configuration.size;
+ final double devicePixelRatio = renderer.renderView.configuration.devicePixelRatio;
+ final Size physicalSize = logicalSize * devicePixelRatio;
+ expect(renderer.renderView.paintBounds, Offset.zero & physicalSize);
+ });
+ });
+}
diff --git a/packages/flutter_test/lib/src/matchers.dart b/packages/flutter_test/lib/src/matchers.dart
index d4df942..3c5a085 100644
--- a/packages/flutter_test/lib/src/matchers.dart
+++ b/packages/flutter_test/lib/src/matchers.dart
@@ -1235,7 +1235,7 @@
}
assert(!renderObject.debugNeedsPaint);
final OffsetLayer layer = renderObject.layer;
- final Future<ui.Image> imageFuture = layer.toImage(element.size);
+ final Future<ui.Image> imageFuture = layer.toImage(renderObject.paintBounds);
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
return binding.runAsync<String>(() async {