diff --git a/packages/flutter/lib/src/rendering/proxy_box.dart b/packages/flutter/lib/src/rendering/proxy_box.dart index c1060cd9e4..fd756e6c10 100644 --- a/packages/flutter/lib/src/rendering/proxy_box.dart +++ b/packages/flutter/lib/src/rendering/proxy_box.dart @@ -530,20 +530,12 @@ class RenderIntrinsicWidth extends RenderProxyBox { } static double _applyStep(double input, double step) { + assert(input.isFinite); if (step == null) return input; return (input / step).ceil() * step; } - BoxConstraints _getInnerConstraints(BoxConstraints constraints) { - assert(child != null); - if (constraints.hasTightWidth) - return constraints; - final double width = child.getMaxIntrinsicWidth(constraints.maxHeight); - assert(width == constraints.constrainWidth(width)); - return constraints.tighten(width: _applyStep(width, _stepWidth)); - } - @override double getMinIntrinsicWidth(double height) { return getMaxIntrinsicWidth(height); @@ -553,36 +545,46 @@ class RenderIntrinsicWidth extends RenderProxyBox { double getMaxIntrinsicWidth(double height) { if (child == null) return 0.0; - double childResult = child.getMaxIntrinsicWidth(height); - assert(childResult.isFinite); - return _applyStep(childResult, _stepWidth); + final double width = child.getMaxIntrinsicWidth(height); + return _applyStep(width, _stepWidth); } @override double getMinIntrinsicHeight(double width) { if (child == null) return 0.0; - double childResult = child.getMinIntrinsicHeight(_getInnerConstraints(new BoxConstraints.tightForFinite(width: width)).maxWidth); - assert(childResult.isFinite); - return _applyStep(childResult, _stepHeight); + if (!width.isFinite) + width = getMaxIntrinsicWidth(double.INFINITY); + assert(width.isFinite); + final double height = child.getMinIntrinsicHeight(width); + return _applyStep(height, _stepHeight); } @override double getMaxIntrinsicHeight(double width) { if (child == null) return 0.0; - double childResult = child.getMaxIntrinsicHeight(_getInnerConstraints(new BoxConstraints.tightForFinite(width: width)).maxWidth); - assert(childResult.isFinite); - return _applyStep(childResult, _stepHeight); + if (!width.isFinite) + width = getMaxIntrinsicWidth(double.INFINITY); + assert(width.isFinite); + final double height = child.getMaxIntrinsicHeight(width); + return _applyStep(height, _stepHeight); } @override void performLayout() { if (child != null) { - BoxConstraints childConstraints = _getInnerConstraints(constraints); - assert(childConstraints.hasTightWidth); - if (_stepHeight != null) - childConstraints.tighten(height: getMaxIntrinsicHeight(childConstraints.maxWidth)); + BoxConstraints childConstraints = constraints; + if (!childConstraints.hasTightWidth) { + final double width = child.getMaxIntrinsicWidth(childConstraints.maxHeight); + assert(width.isFinite); + childConstraints = childConstraints.tighten(width: _applyStep(width, _stepWidth)); + } + if (_stepHeight != null) { + final double height = child.getMaxIntrinsicHeight(childConstraints.maxWidth); + assert(height.isFinite); + childConstraints = childConstraints.tighten(height: _applyStep(height, _stepHeight)); + } child.layout(childConstraints, parentUsesSize: true); size = child.size; } else { @@ -611,27 +613,24 @@ class RenderIntrinsicHeight extends RenderProxyBox { RenderBox child }) : super(child); - BoxConstraints _getInnerConstraints(BoxConstraints constraints) { - assert(child != null); - if (constraints.hasTightHeight) - return constraints; - final double height = child.getMaxIntrinsicHeight(constraints.maxWidth); - assert(height == constraints.constrainHeight(height)); - return constraints.tighten(height: height); - } - @override double getMinIntrinsicWidth(double height) { if (child == null) return 0.0; - return child.getMinIntrinsicWidth(_getInnerConstraints(new BoxConstraints.tightForFinite(height: height)).maxHeight); + if (!height.isFinite) + height = child.getMaxIntrinsicHeight(double.INFINITY); + assert(height.isFinite); + return child.getMinIntrinsicWidth(height); } @override double getMaxIntrinsicWidth(double height) { if (child == null) return 0.0; - return child.getMaxIntrinsicWidth(_getInnerConstraints(new BoxConstraints.tightForFinite(height: height)).maxHeight); + if (!height.isFinite) + height = child.getMaxIntrinsicHeight(double.INFINITY); + assert(height.isFinite); + return child.getMaxIntrinsicWidth(height); } @override @@ -642,7 +641,13 @@ class RenderIntrinsicHeight extends RenderProxyBox { @override void performLayout() { if (child != null) { - child.layout(_getInnerConstraints(constraints), parentUsesSize: true); + BoxConstraints childConstraints = constraints; + if (!childConstraints.hasTightHeight) { + final double height = child.getMaxIntrinsicHeight(childConstraints.maxWidth); + assert(height.isFinite); + childConstraints = childConstraints.tighten(height: height); + } + child.layout(childConstraints, parentUsesSize: true); size = child.size; } else { performResize(); diff --git a/packages/flutter/test/rendering/intrinsic_width_test.dart b/packages/flutter/test/rendering/intrinsic_width_test.dart index e15625fc0c..22add72414 100644 --- a/packages/flutter/test/rendering/intrinsic_width_test.dart +++ b/packages/flutter/test/rendering/intrinsic_width_test.dart @@ -46,7 +46,6 @@ class RenderTestBox extends RenderBox { void main() { test('Shrink-wrapping width', () { RenderBox child = new RenderTestBox(new BoxConstraints(minWidth: 10.0, maxWidth: 100.0, minHeight: 20.0, maxHeight: 200.0)); - RenderBox parent = new RenderIntrinsicWidth(child: child); layout(parent, constraints: new BoxConstraints( @@ -58,11 +57,135 @@ void main() { ); expect(parent.size.width, equals(100.0)); expect(parent.size.height, equals(110.0)); + + expect(parent.getMinIntrinsicWidth(0.0), equals(100.0)); + expect(parent.getMaxIntrinsicWidth(0.0), equals(100.0)); + expect(parent.getMinIntrinsicHeight(0.0), equals(20.0)); + expect(parent.getMaxIntrinsicHeight(0.0), equals(200.0)); + + expect(parent.getMinIntrinsicWidth(10.0), equals(100.0)); + expect(parent.getMaxIntrinsicWidth(10.0), equals(100.0)); + expect(parent.getMinIntrinsicHeight(10.0), equals(20.0)); + expect(parent.getMaxIntrinsicHeight(10.0), equals(200.0)); + + expect(parent.getMinIntrinsicWidth(80.0), equals(100.0)); + expect(parent.getMaxIntrinsicWidth(80.0), equals(100.0)); + expect(parent.getMinIntrinsicHeight(80.0), equals(20.0)); + expect(parent.getMaxIntrinsicHeight(80.0), equals(200.0)); + + expect(parent.getMinIntrinsicWidth(double.INFINITY), equals(100.0)); + expect(parent.getMaxIntrinsicWidth(double.INFINITY), equals(100.0)); + expect(parent.getMinIntrinsicHeight(double.INFINITY), equals(20.0)); + expect(parent.getMaxIntrinsicHeight(double.INFINITY), equals(200.0)); + }); + + test('Shrink-wrapping width (stepped width)', () { + RenderBox child = new RenderTestBox(new BoxConstraints(minWidth: 10.0, maxWidth: 100.0, minHeight: 20.0, maxHeight: 200.0)); + RenderBox parent = new RenderIntrinsicWidth(child: child, stepWidth: 47.0); + layout(parent, + constraints: new BoxConstraints( + minWidth: 5.0, + minHeight: 8.0, + maxWidth: 500.0, + maxHeight: 800.0 + ) + ); + expect(parent.size.width, equals(3.0 * 47.0)); + expect(parent.size.height, equals(110.0)); + + expect(parent.getMinIntrinsicWidth(0.0), equals(3.0 * 47.0)); + expect(parent.getMaxIntrinsicWidth(0.0), equals(3.0 * 47.0)); + expect(parent.getMinIntrinsicHeight(0.0), equals(20.0)); + expect(parent.getMaxIntrinsicHeight(0.0), equals(200.0)); + + expect(parent.getMinIntrinsicWidth(10.0), equals(3.0 * 47.0)); + expect(parent.getMaxIntrinsicWidth(10.0), equals(3.0 * 47.0)); + expect(parent.getMinIntrinsicHeight(10.0), equals(20.0)); + expect(parent.getMaxIntrinsicHeight(10.0), equals(200.0)); + + expect(parent.getMinIntrinsicWidth(80.0), equals(3.0 * 47.0)); + expect(parent.getMaxIntrinsicWidth(80.0), equals(3.0 * 47.0)); + expect(parent.getMinIntrinsicHeight(80.0), equals(20.0)); + expect(parent.getMaxIntrinsicHeight(80.0), equals(200.0)); + + expect(parent.getMinIntrinsicWidth(double.INFINITY), equals(3.0 * 47.0)); + expect(parent.getMaxIntrinsicWidth(double.INFINITY), equals(3.0 * 47.0)); + expect(parent.getMinIntrinsicHeight(double.INFINITY), equals(20.0)); + expect(parent.getMaxIntrinsicHeight(double.INFINITY), equals(200.0)); + }); + + test('Shrink-wrapping width (stepped height)', () { + RenderBox child = new RenderTestBox(new BoxConstraints(minWidth: 10.0, maxWidth: 100.0, minHeight: 20.0, maxHeight: 200.0)); + RenderBox parent = new RenderIntrinsicWidth(child: child, stepHeight: 47.0); + layout(parent, + constraints: new BoxConstraints( + minWidth: 5.0, + minHeight: 8.0, + maxWidth: 500.0, + maxHeight: 800.0 + ) + ); + expect(parent.size.width, equals(100.0)); + expect(parent.size.height, equals(235.0)); + + expect(parent.getMinIntrinsicWidth(0.0), equals(100.0)); + expect(parent.getMaxIntrinsicWidth(0.0), equals(100.0)); + expect(parent.getMinIntrinsicHeight(0.0), equals(1.0 * 47.0)); + expect(parent.getMaxIntrinsicHeight(0.0), equals(5.0 * 47.0)); + + expect(parent.getMinIntrinsicWidth(10.0), equals(100.0)); + expect(parent.getMaxIntrinsicWidth(10.0), equals(100.0)); + expect(parent.getMinIntrinsicHeight(10.0), equals(1.0 * 47.0)); + expect(parent.getMaxIntrinsicHeight(10.0), equals(5.0 * 47.0)); + + expect(parent.getMinIntrinsicWidth(80.0), equals(100.0)); + expect(parent.getMaxIntrinsicWidth(80.0), equals(100.0)); + expect(parent.getMinIntrinsicHeight(80.0), equals(1.0 * 47.0)); + expect(parent.getMaxIntrinsicHeight(80.0), equals(5.0 * 47.0)); + + expect(parent.getMinIntrinsicWidth(double.INFINITY), equals(100.0)); + expect(parent.getMaxIntrinsicWidth(double.INFINITY), equals(100.0)); + expect(parent.getMinIntrinsicHeight(double.INFINITY), equals(1.0 * 47.0)); + expect(parent.getMaxIntrinsicHeight(double.INFINITY), equals(5.0 * 47.0)); + }); + + test('Shrink-wrapping width (stepped everything)', () { + RenderBox child = new RenderTestBox(new BoxConstraints(minWidth: 10.0, maxWidth: 100.0, minHeight: 20.0, maxHeight: 200.0)); + RenderBox parent = new RenderIntrinsicWidth(child: child, stepHeight: 47.0, stepWidth: 37.0); + layout(parent, + constraints: new BoxConstraints( + minWidth: 5.0, + minHeight: 8.0, + maxWidth: 500.0, + maxHeight: 800.0 + ) + ); + expect(parent.size.width, equals(3.0 * 37.0)); + expect(parent.size.height, equals(235.0)); + + expect(parent.getMinIntrinsicWidth(0.0), equals(3.0 * 37.0)); + expect(parent.getMaxIntrinsicWidth(0.0), equals(3.0 * 37.0)); + expect(parent.getMinIntrinsicHeight(0.0), equals(1.0 * 47.0)); + expect(parent.getMaxIntrinsicHeight(0.0), equals(5.0 * 47.0)); + + expect(parent.getMinIntrinsicWidth(10.0), equals(3.0 * 37.0)); + expect(parent.getMaxIntrinsicWidth(10.0), equals(3.0 * 37.0)); + expect(parent.getMinIntrinsicHeight(10.0), equals(1.0 * 47.0)); + expect(parent.getMaxIntrinsicHeight(10.0), equals(5.0 * 47.0)); + + expect(parent.getMinIntrinsicWidth(80.0), equals(3.0 * 37.0)); + expect(parent.getMaxIntrinsicWidth(80.0), equals(3.0 * 37.0)); + expect(parent.getMinIntrinsicHeight(80.0), equals(1.0 * 47.0)); + expect(parent.getMaxIntrinsicHeight(80.0), equals(5.0 * 47.0)); + + expect(parent.getMinIntrinsicWidth(double.INFINITY), equals(3.0 * 37.0)); + expect(parent.getMaxIntrinsicWidth(double.INFINITY), equals(3.0 * 37.0)); + expect(parent.getMinIntrinsicHeight(double.INFINITY), equals(1.0 * 47.0)); + expect(parent.getMaxIntrinsicHeight(double.INFINITY), equals(5.0 * 47.0)); }); test('Shrink-wrapping height', () { RenderBox child = new RenderTestBox(new BoxConstraints(minWidth: 10.0, maxWidth: 100.0, minHeight: 20.0, maxHeight: 200.0)); - RenderBox parent = new RenderIntrinsicHeight(child: child); layout(parent, constraints: new BoxConstraints( @@ -74,6 +197,102 @@ void main() { ); expect(parent.size.width, equals(55.0)); expect(parent.size.height, equals(200.0)); + + expect(parent.getMinIntrinsicWidth(0.0), equals(10.0)); + expect(parent.getMaxIntrinsicWidth(0.0), equals(100.0)); + expect(parent.getMinIntrinsicHeight(0.0), equals(200.0)); + expect(parent.getMaxIntrinsicHeight(0.0), equals(200.0)); + + expect(parent.getMinIntrinsicWidth(10.0), equals(10.0)); + expect(parent.getMaxIntrinsicWidth(10.0), equals(100.0)); + expect(parent.getMinIntrinsicHeight(10.0), equals(200.0)); + expect(parent.getMaxIntrinsicHeight(10.0), equals(200.0)); + + expect(parent.getMinIntrinsicWidth(80.0), equals(10.0)); + expect(parent.getMaxIntrinsicWidth(80.0), equals(100.0)); + expect(parent.getMinIntrinsicHeight(80.0), equals(200.0)); + expect(parent.getMaxIntrinsicHeight(80.0), equals(200.0)); + + expect(parent.getMinIntrinsicWidth(double.INFINITY), equals(10.0)); + expect(parent.getMaxIntrinsicWidth(double.INFINITY), equals(100.0)); + expect(parent.getMinIntrinsicHeight(double.INFINITY), equals(200.0)); + expect(parent.getMaxIntrinsicHeight(double.INFINITY), equals(200.0)); + }); + + test('Padding and boring intrinsics', () { + RenderBox box = new RenderPadding( + padding: new EdgeInsets.all(15.0), + child: new RenderSizedBox(const Size(20.0, 20.0)) + ); + + expect(box.getMinIntrinsicWidth(0.0), 50.0); + expect(box.getMaxIntrinsicWidth(0.0), 50.0); + expect(box.getMinIntrinsicHeight(0.0), 50.0); + expect(box.getMaxIntrinsicHeight(0.0), 50.0); + + expect(box.getMinIntrinsicWidth(10.0), 50.0); + expect(box.getMaxIntrinsicWidth(10.0), 50.0); + expect(box.getMinIntrinsicHeight(10.0), 50.0); + expect(box.getMaxIntrinsicHeight(10.0), 50.0); + + expect(box.getMinIntrinsicWidth(80.0), 50.0); + expect(box.getMaxIntrinsicWidth(80.0), 50.0); + expect(box.getMinIntrinsicHeight(80.0), 50.0); + expect(box.getMaxIntrinsicHeight(80.0), 50.0); + + expect(box.getMinIntrinsicWidth(double.INFINITY), 50.0); + expect(box.getMaxIntrinsicWidth(double.INFINITY), 50.0); + expect(box.getMinIntrinsicHeight(double.INFINITY), 50.0); + expect(box.getMaxIntrinsicHeight(double.INFINITY), 50.0); + + // also a smoke test: + layout( + box, + constraints: new BoxConstraints( + minWidth: 10.0, + minHeight: 10.0, + maxWidth: 10.0, + maxHeight: 10.0 + ) + ); + }); + + test('Padding and interesting intrinsics', () { + RenderBox box = new RenderPadding( + padding: new EdgeInsets.all(15.0), + child: new RenderAspectRatio(aspectRatio: 1.0) + ); + + expect(box.getMinIntrinsicWidth(0.0), 30.0); + expect(box.getMaxIntrinsicWidth(0.0), 30.0); + expect(box.getMinIntrinsicHeight(0.0), 30.0); + expect(box.getMaxIntrinsicHeight(0.0), 30.0); + + expect(box.getMinIntrinsicWidth(10.0), 30.0); + expect(box.getMaxIntrinsicWidth(10.0), 30.0); + expect(box.getMinIntrinsicHeight(10.0), 30.0); + expect(box.getMaxIntrinsicHeight(10.0), 30.0); + + expect(box.getMinIntrinsicWidth(80.0), 80.0); + expect(box.getMaxIntrinsicWidth(80.0), 80.0); + expect(box.getMinIntrinsicHeight(80.0), 80.0); + expect(box.getMaxIntrinsicHeight(80.0), 80.0); + + expect(box.getMinIntrinsicWidth(double.INFINITY), 30.0); + expect(box.getMaxIntrinsicWidth(double.INFINITY), 30.0); + expect(box.getMinIntrinsicHeight(double.INFINITY), 30.0); + expect(box.getMaxIntrinsicHeight(double.INFINITY), 30.0); + + // also a smoke test: + layout( + box, + constraints: new BoxConstraints( + minWidth: 10.0, + minHeight: 10.0, + maxWidth: 10.0, + maxHeight: 10.0 + ) + ); }); test('Padding and boring intrinsics', () {