From 7f7ea2d5007117c1e877e94cebbe7fe9ee73e6ad Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Fri, 29 Jun 2018 14:42:36 -0700 Subject: [PATCH] Fix intrinsics for ConstrainedBox (#18935) --- packages/flutter/lib/src/rendering/box.dart | 46 ++++++ .../flutter/lib/src/rendering/proxy_box.dart | 12 +- .../test/widgets/constrained_box_test.dart | 135 ++++++++++++++++++ 3 files changed, 189 insertions(+), 4 deletions(-) create mode 100644 packages/flutter/test/widgets/constrained_box_test.dart diff --git a/packages/flutter/lib/src/rendering/box.dart b/packages/flutter/lib/src/rendering/box.dart index c5f6521192..2aa1e69b82 100644 --- a/packages/flutter/lib/src/rendering/box.dart +++ b/packages/flutter/lib/src/rendering/box.dart @@ -75,6 +75,10 @@ class _DebugSize extends Size { /// _expanding_ if it is tightly infinite (its minimum and maximum constraints /// are both infinite). See: [new BoxConstraints.expand]. /// +/// An axis whose _minimum_ constraint is infinite is just said to be _infinite_ +/// (since by definition the maximum constraint must also be infinite in that +/// case). See: [hasInfiniteWidth], [hasInfiniteHeight]. +/// /// A size is _constrained_ when it satisfies a [BoxConstraints] description. /// See: [constrain], [constrainWidth], [constrainHeight], /// [constrainDimensions], [constrainSizeAndAttemptToPreserveAspectRatio], @@ -346,11 +350,53 @@ class BoxConstraints extends Constraints { bool get isTight => hasTightWidth && hasTightHeight; /// Whether there is an upper bound on the maximum width. + /// + /// See also: + /// + /// * [hasBoundedHeight], the equivalent for the vertical axis. + /// * [hasInfiniteWidth], which describes whether the minimum width + /// constraint is infinite. bool get hasBoundedWidth => maxWidth < double.infinity; /// Whether there is an upper bound on the maximum height. + /// + /// See also: + /// + /// * [hasBoundedWidth], the equivalent for the horizontal axis. + /// * [hasInfiniteHeight], which describes whether the minimum height + /// constraint is infinite. bool get hasBoundedHeight => maxHeight < double.infinity; + /// Whether the width constraint is infinite. + /// + /// Such a constraint is used to indicate that a box should grow as large as + /// some other constraint (in this case, horizontally). If constraints are + /// infinite, then they must have other (non-infinite) constraints [enforce]d + /// upon them, or must be [tighten]ed, before they can be used to derive a + /// [Size] for a [RenderBox.size]. + /// + /// See also: + /// + /// * [hasInfiniteHeight], the equivalent for the vertical axis. + /// * [hasBoundedWidth], which describes whether the maximum width + /// constraint is finite. + bool get hasInfiniteWidth => minWidth >= double.infinity; + + /// Whether the height constraint is infinite. + /// + /// Such a constraint is used to indicate that a box should grow as large as + /// some other constraint (in this case, vertically). If constraints are + /// infinite, then they must have other (non-infinite) constraints [enforce]d + /// upon them, or must be [tighten]ed, before they can be used to derive a + /// [Size] for a [RenderBox.size]. + /// + /// See also: + /// + /// * [hasInfiniteWidth], the equivalent for the horizontal axis. + /// * [hasBoundedHeight], which describes whether the maximum height + /// constraint is finite. + bool get hasInfiniteHeight => minHeight >= double.infinity; + /// Whether the given size satisfies the constraints. bool isSatisfiedBy(Size size) { assert(debugAssertIsValid()); diff --git a/packages/flutter/lib/src/rendering/proxy_box.dart b/packages/flutter/lib/src/rendering/proxy_box.dart index f94e16fe7b..a58dca84a1 100644 --- a/packages/flutter/lib/src/rendering/proxy_box.dart +++ b/packages/flutter/lib/src/rendering/proxy_box.dart @@ -218,7 +218,8 @@ class RenderConstrainedBox extends RenderProxyBox { if (_additionalConstraints.hasBoundedWidth && _additionalConstraints.hasTightWidth) return _additionalConstraints.minWidth; final double width = super.computeMinIntrinsicWidth(height); - if (_additionalConstraints.hasBoundedWidth) + assert(width.isFinite); + if (!_additionalConstraints.hasInfiniteWidth) return _additionalConstraints.constrainWidth(width); return width; } @@ -228,7 +229,8 @@ class RenderConstrainedBox extends RenderProxyBox { if (_additionalConstraints.hasBoundedWidth && _additionalConstraints.hasTightWidth) return _additionalConstraints.minWidth; final double width = super.computeMaxIntrinsicWidth(height); - if (_additionalConstraints.hasBoundedWidth) + assert(width.isFinite); + if (!_additionalConstraints.hasInfiniteWidth) return _additionalConstraints.constrainWidth(width); return width; } @@ -238,7 +240,8 @@ class RenderConstrainedBox extends RenderProxyBox { if (_additionalConstraints.hasBoundedHeight && _additionalConstraints.hasTightHeight) return _additionalConstraints.minHeight; final double height = super.computeMinIntrinsicHeight(width); - if (_additionalConstraints.hasBoundedHeight) + assert(height.isFinite); + if (!_additionalConstraints.hasInfiniteHeight) return _additionalConstraints.constrainHeight(height); return height; } @@ -248,7 +251,8 @@ class RenderConstrainedBox extends RenderProxyBox { if (_additionalConstraints.hasBoundedHeight && _additionalConstraints.hasTightHeight) return _additionalConstraints.minHeight; final double height = super.computeMaxIntrinsicHeight(width); - if (_additionalConstraints.hasBoundedHeight) + assert(height.isFinite); + if (!_additionalConstraints.hasInfiniteHeight) return _additionalConstraints.constrainHeight(height); return height; } diff --git a/packages/flutter/test/widgets/constrained_box_test.dart b/packages/flutter/test/widgets/constrained_box_test.dart new file mode 100644 index 0000000000..6c8aadd917 --- /dev/null +++ b/packages/flutter/test/widgets/constrained_box_test.dart @@ -0,0 +1,135 @@ +// 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_test/flutter_test.dart'; +import 'package:flutter/widgets.dart'; + +void main() { + testWidgets('Placeholder intrinsics', (WidgetTester tester) async { + await tester.pumpWidget(const Placeholder()); + expect(tester.renderObject(find.byType(Placeholder)).getMinIntrinsicWidth(double.infinity), 0.0); + expect(tester.renderObject(find.byType(Placeholder)).getMaxIntrinsicWidth(double.infinity), 0.0); + expect(tester.renderObject(find.byType(Placeholder)).getMinIntrinsicHeight(double.infinity), 0.0); + expect(tester.renderObject(find.byType(Placeholder)).getMaxIntrinsicHeight(double.infinity), 0.0); + }); + + testWidgets('ConstrainedBox intrinsics - minHeight', (WidgetTester tester) async { + await tester.pumpWidget( + new ConstrainedBox( + constraints: const BoxConstraints( + minHeight: 20.0, + ), + child: const Placeholder(), + ), + ); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMinIntrinsicWidth(double.infinity), 0.0); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMaxIntrinsicWidth(double.infinity), 0.0); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMinIntrinsicHeight(double.infinity), 20.0); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMaxIntrinsicHeight(double.infinity), 20.0); + }); + + testWidgets('ConstrainedBox intrinsics - minWidth', (WidgetTester tester) async { + await tester.pumpWidget( + new ConstrainedBox( + constraints: const BoxConstraints( + minWidth: 20.0, + ), + child: const Placeholder(), + ), + ); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMinIntrinsicWidth(double.infinity), 20.0); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMaxIntrinsicWidth(double.infinity), 20.0); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMinIntrinsicHeight(double.infinity), 0.0); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMaxIntrinsicHeight(double.infinity), 0.0); + }); + + testWidgets('ConstrainedBox intrinsics - maxHeight', (WidgetTester tester) async { + await tester.pumpWidget( + new ConstrainedBox( + constraints: const BoxConstraints( + maxHeight: 20.0, + ), + child: const Placeholder(), + ), + ); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMinIntrinsicWidth(double.infinity), 0.0); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMaxIntrinsicWidth(double.infinity), 0.0); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMinIntrinsicHeight(double.infinity), 0.0); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMaxIntrinsicHeight(double.infinity), 0.0); + }); + + testWidgets('ConstrainedBox intrinsics - maxWidth', (WidgetTester tester) async { + await tester.pumpWidget( + new ConstrainedBox( + constraints: const BoxConstraints( + maxWidth: 20.0, + ), + child: const Placeholder(), + ), + ); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMinIntrinsicWidth(double.infinity), 0.0); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMaxIntrinsicWidth(double.infinity), 0.0); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMinIntrinsicHeight(double.infinity), 0.0); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMaxIntrinsicHeight(double.infinity), 0.0); + }); + + testWidgets('ConstrainedBox intrinsics - tight', (WidgetTester tester) async { + await tester.pumpWidget( + new ConstrainedBox( + constraints: const BoxConstraints.tightFor(width: 10.0, height: 30.0), + child: const Placeholder(), + ), + ); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMinIntrinsicWidth(double.infinity), 10.0); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMaxIntrinsicWidth(double.infinity), 10.0); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMinIntrinsicHeight(double.infinity), 30.0); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMaxIntrinsicHeight(double.infinity), 30.0); + }); + + + testWidgets('ConstrainedBox intrinsics - minHeight - with infinite width', (WidgetTester tester) async { + await tester.pumpWidget( + new ConstrainedBox( + constraints: const BoxConstraints( + minWidth: double.infinity, + minHeight: 20.0, + ), + child: const Placeholder(), + ), + ); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMinIntrinsicWidth(double.infinity), 0.0); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMaxIntrinsicWidth(double.infinity), 0.0); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMinIntrinsicHeight(double.infinity), 20.0); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMaxIntrinsicHeight(double.infinity), 20.0); + }); + + testWidgets('ConstrainedBox intrinsics - minWidth - with infinite height', (WidgetTester tester) async { + await tester.pumpWidget( + new ConstrainedBox( + constraints: const BoxConstraints( + minWidth: 20.0, + minHeight: double.infinity, + ), + child: const Placeholder(), + ), + ); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMinIntrinsicWidth(double.infinity), 20.0); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMaxIntrinsicWidth(double.infinity), 20.0); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMinIntrinsicHeight(double.infinity), 0.0); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMaxIntrinsicHeight(double.infinity), 0.0); + }); + + testWidgets('ConstrainedBox intrinsics - infinite', (WidgetTester tester) async { + await tester.pumpWidget( + new ConstrainedBox( + constraints: const BoxConstraints.tightFor(width: double.infinity, height: double.infinity), + child: const Placeholder(), + ), + ); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMinIntrinsicWidth(double.infinity), 0.0); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMaxIntrinsicWidth(double.infinity), 0.0); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMinIntrinsicHeight(double.infinity), 0.0); + expect(tester.renderObject(find.byType(ConstrainedBox)).getMaxIntrinsicHeight(double.infinity), 0.0); + }); +}