From 787fb3be7d048e7ca93ac29f67560aa3ec5fa973 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Tue, 31 May 2016 14:59:48 -0700 Subject: [PATCH] Simplify intrinsic dimension APIs (#4283) --- .../layers/rendering/src/sector_layout.dart | 34 +-- .../layers/rendering/src/solid_color_box.dart | 24 +- packages/flutter/lib/src/material/tabs.dart | 31 +-- packages/flutter/lib/src/rendering/block.dart | 76 ++---- packages/flutter/lib/src/rendering/box.dart | 222 ++++++++++++++---- .../lib/src/rendering/custom_layout.dart | 32 ++- .../lib/src/rendering/editable_line.dart | 22 +- packages/flutter/lib/src/rendering/error.dart | 18 +- packages/flutter/lib/src/rendering/flex.dart | 133 +++-------- packages/flutter/lib/src/rendering/flow.dart | 32 ++- packages/flutter/lib/src/rendering/grid.dart | 60 ++--- packages/flutter/lib/src/rendering/image.dart | 24 +- packages/flutter/lib/src/rendering/list.dart | 42 ++-- .../flutter/lib/src/rendering/overflow.dart | 12 - .../flutter/lib/src/rendering/paragraph.dart | 44 ++-- .../src/rendering/performance_overlay.dart | 16 +- .../flutter/lib/src/rendering/proxy_box.dart | 206 +++++++--------- .../lib/src/rendering/rotated_box.dart | 36 ++- .../lib/src/rendering/shifted_box.dart | 212 ++++++++--------- packages/flutter/lib/src/rendering/stack.dart | 71 ++---- packages/flutter/lib/src/rendering/table.dart | 29 +-- .../flutter/lib/src/rendering/viewport.dart | 73 ++++-- .../lib/src/widgets/layout_builder.dart | 46 ++-- .../flutter/lib/src/widgets/lazy_block.dart | 46 +--- .../test/rendering/aspect_ratio_test.dart | 97 +++++++- .../flutter/test/rendering/block_test.dart | 70 ------ .../flutter/test/rendering/flex_test.dart | 18 +- .../test/rendering/intrinsic_width_test.dart | 17 +- .../rendering/paragraph_intrinsics_test.dart | 68 ++++++ .../test/rendering/rendering_tester.dart | 28 ++- 30 files changed, 955 insertions(+), 884 deletions(-) delete mode 100644 packages/flutter/test/rendering/block_test.dart create mode 100644 packages/flutter/test/rendering/paragraph_intrinsics_test.dart diff --git a/examples/layers/rendering/src/sector_layout.dart b/examples/layers/rendering/src/sector_layout.dart index 6430809fdf..13fa439021 100644 --- a/examples/layers/rendering/src/sector_layout.dart +++ b/examples/layers/rendering/src/sector_layout.dart @@ -454,38 +454,42 @@ class RenderBoxToRenderSectorAdapter extends RenderBox with RenderObjectWithChil } @override - double getMinIntrinsicWidth(BoxConstraints constraints) { + double getMinIntrinsicWidth(double height) { if (child == null) - return super.getMinIntrinsicWidth(constraints); - return getIntrinsicDimensions(constraints).width; + return 0.0; + return getIntrinsicDimensions(height: height).width; } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { + double getMaxIntrinsicWidth(double height) { if (child == null) - return super.getMaxIntrinsicWidth(constraints); - return getIntrinsicDimensions(constraints).width; + return 0.0; + return getIntrinsicDimensions(height: height).width; } @override - double getMinIntrinsicHeight(BoxConstraints constraints) { + double getMinIntrinsicHeight(double width) { if (child == null) - return super.getMinIntrinsicHeight(constraints); - return getIntrinsicDimensions(constraints).height; + return 0.0; + return getIntrinsicDimensions(width: width).height; } @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { + double getMaxIntrinsicHeight(double width) { if (child == null) - return super.getMaxIntrinsicHeight(constraints); - return getIntrinsicDimensions(constraints).height; + return 0.0; + return getIntrinsicDimensions(width: width).height; } - Size getIntrinsicDimensions(BoxConstraints constraints) { + Size getIntrinsicDimensions({ + double width: double.INFINITY, + double height: double.INFINITY + }) { assert(child is RenderSector); assert(child.parentData is SectorParentData); - assert(constraints.maxWidth < double.INFINITY || constraints.maxHeight < double.INFINITY); - double maxChildDeltaRadius = math.min(constraints.maxWidth, constraints.maxHeight) / 2.0 - innerRadius; + assert(width != null); + assert(height != null); + double maxChildDeltaRadius = math.min(width, height) / 2.0 - innerRadius; SectorDimensions childDimensions = child.getIntrinsicDimensions(new SectorConstraints(maxDeltaRadius: maxChildDeltaRadius), innerRadius); double dimension = (innerRadius + childDimensions.deltaRadius) * 2.0; return constraints.constrain(new Size(dimension, dimension)); diff --git a/examples/layers/rendering/src/solid_color_box.dart b/examples/layers/rendering/src/solid_color_box.dart index 77dce23b8c..00b00ba412 100644 --- a/examples/layers/rendering/src/solid_color_box.dart +++ b/examples/layers/rendering/src/solid_color_box.dart @@ -14,31 +14,23 @@ class RenderSolidColorBox extends RenderDecoratedBox { super(decoration: new BoxDecoration(backgroundColor: backgroundColor)); @override - double getMinIntrinsicWidth(BoxConstraints constraints) { - return constraints.constrainHeight( - this.desiredSize == Size.infinite ? 0.0 : desiredSize.width - ); + double getMinIntrinsicWidth(double height) { + return desiredSize.width == double.INFINITY ? 0.0 : desiredSize.width; } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { - return constraints.constrainWidth( - this.desiredSize == Size.infinite ? 0.0 : desiredSize.width - ); + double getMaxIntrinsicWidth(double height) { + return desiredSize.width == double.INFINITY ? 0.0 : desiredSize.width; } @override - double getMinIntrinsicHeight(BoxConstraints constraints) { - return constraints.constrainHeight( - this.desiredSize == Size.infinite ? 0.0 : desiredSize.height - ); + double getMinIntrinsicHeight(double width) { + return desiredSize.height == double.INFINITY ? 0.0 : desiredSize.height; } @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { - return constraints.constrainHeight( - this.desiredSize == Size.infinite ? 0.0 : desiredSize.height - ); + double getMaxIntrinsicHeight(double width) { + return desiredSize.height == double.INFINITY ? 0.0 : desiredSize.height; } @override diff --git a/packages/flutter/lib/src/material/tabs.dart b/packages/flutter/lib/src/material/tabs.dart index 096c045957..d2f41889c1 100644 --- a/packages/flutter/lib/src/material/tabs.dart +++ b/packages/flutter/lib/src/material/tabs.dart @@ -100,47 +100,40 @@ class _RenderTabBar extends RenderBox with } @override - double getMinIntrinsicWidth(BoxConstraints constraints) { - BoxConstraints widthConstraints = - new BoxConstraints(maxWidth: constraints.maxWidth, maxHeight: constraints.maxHeight); - + double getMinIntrinsicWidth(double height) { double maxWidth = 0.0; RenderBox child = firstChild; while (child != null) { - maxWidth = math.max(maxWidth, child.getMinIntrinsicWidth(widthConstraints)); + maxWidth = math.max(maxWidth, child.getMinIntrinsicWidth(height)); final _TabBarParentData childParentData = child.parentData; child = childParentData.nextSibling; } - double width = isScrollable ? maxWidth : maxWidth * childCount; - return constraints.constrainWidth(width); + return isScrollable ? maxWidth : maxWidth * childCount; } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { - BoxConstraints widthConstraints = - new BoxConstraints(maxWidth: constraints.maxWidth, maxHeight: constraints.maxHeight); - + double getMaxIntrinsicWidth(double height) { double maxWidth = 0.0; + double totalWidth = 0.0; RenderBox child = firstChild; while (child != null) { - maxWidth = math.max(maxWidth, child.getMaxIntrinsicWidth(widthConstraints)); + double childWidth = child.getMaxIntrinsicWidth(height); + maxWidth = math.max(maxWidth, childWidth); + totalWidth += childWidth; final _TabBarParentData childParentData = child.parentData; child = childParentData.nextSibling; } - double width = isScrollable ? maxWidth : maxWidth * childCount; - return constraints.constrainWidth(width); + return isScrollable ? totalWidth : maxWidth * childCount; } double get _tabHeight => textAndIcons ? _kTextAndIconTabHeight : _kTabHeight; double get _tabBarHeight => _tabHeight + _kTabIndicatorHeight; - double _getIntrinsicHeight(BoxConstraints constraints) => constraints.constrainHeight(_tabBarHeight); + @override + double getMinIntrinsicHeight(double width) => _tabBarHeight; @override - double getMinIntrinsicHeight(BoxConstraints constraints) => _getIntrinsicHeight(constraints); - - @override - double getMaxIntrinsicHeight(BoxConstraints constraints) => _getIntrinsicHeight(constraints); + double getMaxIntrinsicHeight(double width) => _tabBarHeight; void layoutFixedWidthTabs() { double tabWidth = size.width / childCount; diff --git a/packages/flutter/lib/src/rendering/block.dart b/packages/flutter/lib/src/rendering/block.dart index 6512d5f613..59315662bf 100644 --- a/packages/flutter/lib/src/rendering/block.dart +++ b/packages/flutter/lib/src/rendering/block.dart @@ -10,8 +10,7 @@ import 'object.dart'; /// Parent data for use with [RenderBlockBase]. class BlockParentData extends ContainerBoxParentDataMixin { } -typedef double _ChildSizingFunction(RenderBox child, BoxConstraints constraints); -typedef double _Constrainer(double value); +typedef double _ChildSizingFunction(RenderBox child); /// Implements the block layout algorithm. /// @@ -158,102 +157,65 @@ class RenderBlock extends RenderBox description.add('mainAxis: $mainAxis'); } - double _getIntrinsicCrossAxis(BoxConstraints constraints, _ChildSizingFunction childSize, _Constrainer constrainer) { + double _getIntrinsicCrossAxis(_ChildSizingFunction childSize) { double extent = 0.0; - BoxConstraints innerConstraints; - switch (mainAxis) { - case Axis.horizontal: - innerConstraints = constraints.heightConstraints(); - break; - case Axis.vertical: - innerConstraints = constraints.widthConstraints(); - break; - } RenderBox child = firstChild; while (child != null) { - extent = math.max(extent, childSize(child, innerConstraints)); + extent = math.max(extent, childSize(child)); final BlockParentData childParentData = child.parentData; child = childParentData.nextSibling; } - return constrainer(extent); + return extent; } - double _getIntrinsicMainAxis(BoxConstraints constraints, _Constrainer constrainer) { + double _getIntrinsicMainAxis(_ChildSizingFunction childSize) { double extent = 0.0; - BoxConstraints innerConstraints = _getInnerConstraints(constraints); RenderBox child = firstChild; while (child != null) { - switch (mainAxis) { - case Axis.horizontal: - extent += child.getMaxIntrinsicWidth(innerConstraints); - break; - case Axis.vertical: - extent += child.getMinIntrinsicHeight(innerConstraints); - break; - } + extent += childSize(child); final BlockParentData childParentData = child.parentData; child = childParentData.nextSibling; } - return constrainer(extent); + return extent; } @override - double getMinIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); + double getMinIntrinsicWidth(double height) { switch (mainAxis) { case Axis.horizontal: - return _getIntrinsicMainAxis(constraints, constraints.constrainWidth); + return _getIntrinsicMainAxis((RenderBox child) => child.getMinIntrinsicWidth(height)); case Axis.vertical: - return _getIntrinsicCrossAxis( - constraints, - (RenderBox child, BoxConstraints innerConstraints) => child.getMinIntrinsicWidth(innerConstraints), - constraints.constrainWidth - ); + return _getIntrinsicCrossAxis((RenderBox child) => child.getMinIntrinsicWidth(height)); } } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); + double getMaxIntrinsicWidth(double height) { switch (mainAxis) { case Axis.horizontal: - return _getIntrinsicMainAxis(constraints, constraints.constrainWidth); + return _getIntrinsicMainAxis((RenderBox child) => child.getMaxIntrinsicWidth(height)); case Axis.vertical: - return _getIntrinsicCrossAxis( - constraints, - (RenderBox child, BoxConstraints innerConstraints) => child.getMaxIntrinsicWidth(innerConstraints), - constraints.constrainWidth - ); + return _getIntrinsicCrossAxis((RenderBox child) => child.getMaxIntrinsicWidth(height)); } } @override - double getMinIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); + double getMinIntrinsicHeight(double width) { switch (mainAxis) { case Axis.horizontal: - return _getIntrinsicCrossAxis( - constraints, - (RenderBox child, BoxConstraints innerConstraints) => child.getMinIntrinsicHeight(innerConstraints), - constraints.constrainHeight - ); + return _getIntrinsicMainAxis((RenderBox child) => child.getMinIntrinsicHeight(width)); case Axis.vertical: - return _getIntrinsicMainAxis(constraints, constraints.constrainHeight); + return _getIntrinsicCrossAxis((RenderBox child) => child.getMinIntrinsicHeight(width)); } } @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); + double getMaxIntrinsicHeight(double width) { switch (mainAxis) { case Axis.horizontal: - return _getIntrinsicCrossAxis( - constraints, - (RenderBox child, BoxConstraints innerConstraints) => child.getMaxIntrinsicHeight(innerConstraints), - constraints.constrainHeight - ); + return _getIntrinsicMainAxis((RenderBox child) => child.getMaxIntrinsicHeight(width)); case Axis.vertical: - return _getIntrinsicMainAxis(constraints, constraints.constrainHeight); + return _getIntrinsicCrossAxis((RenderBox child) => child.getMaxIntrinsicHeight(width)); } } diff --git a/packages/flutter/lib/src/rendering/box.dart b/packages/flutter/lib/src/rendering/box.dart index a7d46c2f25..077e34ee6b 100644 --- a/packages/flutter/lib/src/rendering/box.dart +++ b/packages/flutter/lib/src/rendering/box.dart @@ -83,6 +83,15 @@ class BoxConstraints extends Constraints { minHeight = height != null ? height : 0.0, maxHeight = height != null ? height : double.INFINITY; + /// Creates box constraints that require the given width or height, except if they are infinite. + const BoxConstraints.tightForFinite({ + double width: double.INFINITY, + double height: double.INFINITY + }): minWidth = width != double.INFINITY ? width : 0.0, + maxWidth = width != double.INFINITY ? width : double.INFINITY, + minHeight = height != double.INFINITY ? height : 0.0, + maxHeight = height != double.INFINITY ? height : double.INFINITY; + /// Creates box constraints that forbid sizes larger than the given size. BoxConstraints.loose(Size size) : minWidth = 0.0, @@ -486,44 +495,164 @@ abstract class RenderBox extends RenderObject { child.parentData = new BoxParentData(); } - /// Returns the minimum width that this box could be without failing to paint - /// its contents within itself. + /// Returns the minimum width that this box could be without failing to + /// correctly paint its contents within itself, without clipping. + /// + /// The height argument may give a specific height to assume. The given height + /// can be infinite, meaning that the intrinsic width in an unconstrained + /// environment is being requested. The given height should never be negative + /// or null. /// /// Override in subclasses that implement [performLayout]. - double getMinIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return constraints.constrainWidth(0.0); + /// + /// If the layout algorithm is independent of the context (e.g. it always + /// tries to be a particular size), or if the layout algorithm is + /// width-in-height-out, or if the layout algorithm uses both the incoming + /// width and height constraints (e.g. it always sizes itself to + /// [BoxConstraints.biggest]), then the `height` argument should be ignored. + /// + /// If the layout algorithm is strictly height-in-width-out, or is + /// height-in-width-out when the width is unconstrained, then the height + /// argument is the height to use. + /// + /// This function should never return a negative or infinite value. + /// + /// ## Examples + /// + /// ### Text + /// + /// Text is the canonical example of a width-in-height-out algorithm. The + /// `height` argument is therefore ignored. + /// + /// Consider the string "Hello World" The _maximum_ intrinsic width (as + /// returned from [getMaxIntrinsicWidth]) would be the width of the string + /// with no line breaks. + /// + /// The minimum intrinsic width would be the width of the widest word, "Hello" + /// or "World". If the text is rendered in an even narrower width, however, it + /// might still not overflow. For example, maybe the rendering would put a + /// line-break half-way through the words, as in "Hel⁞lo⁞Wor⁞ld". However, + /// this wouldn't be a _correct_ rendering, and [getMinIntrinsicWidth] is + /// supposed to render the minimum width that the box could be without failing + /// to _correctly_ paint the contents within itself. + /// + /// The minimum intrinsic _height_ for a given width smaller than the minimum + /// intrinsic width could therefore be greater than the minimum intrinsic + /// height for the minimum intrinsic width. + /// + /// ### Viewports (e.g. scrolling lists) + /// + /// Some render boxes are intended to clip their children. For example, the + /// render box for a scrolling list might always size itself to its parents' + /// size (or rather, to the maximum incoming constraints), regardless of the + /// children's sizes, and then clip the children and position them based on + /// the current scroll offset. + /// + /// The intrinsic dimensions in these cases still depend on the children, even + /// though the layout algorithm sizes the box in a way independent of the + /// children. It is the size that is needed to paint the box's contents (in + /// this case, the children) _without clipping_ that matters. + /// + /// In many cases, viewports do not have efficient access to all the children, + /// and therefore cannot actually return a valid answer. In this case, when + /// [RenderObject.debugCheckingIntrinsics] is false and asserts are enabled, + /// the intrinsic functions should throw; in other cases, they should return + /// 0.0. See [RenderVirtualViewport.debugThrowIfNotCheckingIntrinsics]. + /// + /// ### Aspect-ratio-driven boxes + /// + /// Some boxes always return a fixed size based on the constraints. For these + /// boxes, the intrinsic functions should return the appropriate size when the + /// incoming `height` or `width` argument is finite, treating that as a tight + /// constraint in the respective direction and treating the other direction's + /// constraints as unbounded. This is because the definitions of + /// [getMinIntrinsicWidth] and [getMinIntrinsicHeight] are in terms of what + /// the dimensions _could be_, and such boxes can only be one size in such + /// cases. + /// + /// When the incoming argument is not finite, then they should return the + /// actual intrinsic dimensions based on the contents, as any other box would. + double getMinIntrinsicWidth(double height) { + return 0.0; } /// Returns the smallest width beyond which increasing the width never - /// decreases the preferred height. + /// decreases the preferred height. The preferred height is the value that + /// would be returned by [getMinIntrinsicHeight] for that width. /// /// Override in subclasses that implement [performLayout]. - double getMaxIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return constraints.constrainWidth(0.0); + /// + /// If the layout algorithm is strictly height-in-width-out, or is + /// height-in-width-out when the width is unconstrained, then this should + /// return the same value as [getMinIntrinsicWidth] for the same height. + /// + /// Otherwise, the height argument should be ignored, and the returned value + /// should be equal to or bigger than the value returned by + /// [getMinIntrinsicWidth]. + /// + /// The value returned by this method might not match the size that the object + /// would actually take. For example, a [RenderBox] subclass that always + /// exactly sizes itself using [BoxConstraints.biggest] might well size itself + /// bigger than its max intrinsic size. + /// + /// This function should never return a negative or infinite value. + /// + /// See also examples in the definition of [getMinIntrinsicWidth]. + double getMaxIntrinsicWidth(double height) { + return 0.0; } - /// Return the minimum height that this box could be without failing to paint - /// its contents within itself. + /// Returns the minimum height that this box could be without failing to + /// correctly paint its contents within itself, without clipping. + /// + /// The width argument may give a specific width to assume. The given width + /// can be infinite, meaning that the intrinsic height in an unconstrained + /// environment is being requested. The given width should never be negative + /// or null. /// /// Override in subclasses that implement [performLayout]. - double getMinIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return constraints.constrainHeight(0.0); + /// + /// If the layout algorithm is independent of the context (e.g. it always + /// tries to be a particular size), or if the layout algorithm is + /// height-in-width-out, or if the layout algorithm uses both the incoming + /// height and width constraints (e.g. it always sizes itself to + /// [BoxConstraints.biggest]), then the `width` argument should be ignored. + /// + /// If the layout algorithm is strictly width-in-height-out, or is + /// width-in-height-out when the height is unconstrained, then the width + /// argument is the width to use. + /// + /// This function should never return a negative or infinite value. + /// + /// See also examples in the definition of [getMinIntrinsicWidth]. + double getMinIntrinsicHeight(double width) { + return 0.0; } /// Returns the smallest height beyond which increasing the height never - /// decreases the preferred width. - /// - /// If the layout algorithm used is width-in-height-out, i.e. the height - /// depends on the width and not vice versa, then this will return the same - /// as getMinIntrinsicHeight(). + /// decreases the preferred width. The preferred width is the value that + /// would be returned by [getMinIntrinsicWidth] for that height. /// /// Override in subclasses that implement [performLayout]. - double getMaxIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return constraints.constrainHeight(0.0); + /// + /// If the layout algorithm is strictly width-in-height-out, or is + /// width-in-height-out when the height is unconstrained, then this should + /// return the same value as [getMinIntrinsicHeight] for the same width. + /// + /// Otherwise, the width argument should be ignored, and the returned value + /// should be equal to or bigger than the value returned by + /// [getMinIntrinsicHeight]. + /// + /// The value returned by this method might not match the size that the object + /// would actually take. For example, a [RenderBox] subclass that always + /// exactly sizes itself using [BoxConstraints.biggest] might well size itself + /// bigger than its max intrinsic size. + /// + /// This function should never return a negative or infinite value. + /// + /// See also examples in the definition of [getMinIntrinsicWidth]. + double getMaxIntrinsicHeight(double width) { + return 0.0; } /// Whether this render object has undergone layout and has a [size]. @@ -766,40 +895,47 @@ abstract class RenderBox extends RenderObject { ); } if (_debugNeedsIntrinsicSizeCheck || debugCheckIntrinsicSizes) { - // verify that the intrinsics are also within the constraints + // verify that the intrinsics are sane assert(!RenderObject.debugCheckingIntrinsics); RenderObject.debugCheckingIntrinsics = true; - double intrinsic; StringBuffer failures = new StringBuffer(); int failureCount = 0; - intrinsic = getMinIntrinsicWidth(constraints); - if (intrinsic != constraints.constrainWidth(intrinsic)) { - failures.writeln(' * getMinIntrinsicWidth() -- returned: w=$intrinsic'); + + double testIntrinsic(double function(double extent), String name, double constraint) { + final double result = function(constraint); + if (result < 0) { + failures.writeln(' * $name($constraint) returned a negative value: $result'); + failureCount += 1; + } + if (!result.isFinite) { + failures.writeln(' * $name($constraint) returned a non-finite value: $result'); + failureCount += 1; + } + return result; + } + + final double minIntrinsicWidth = testIntrinsic(getMinIntrinsicWidth, 'getMinIntrinsicWidth', constraints.maxWidth); + final double maxIntrinsicWidth = testIntrinsic(getMaxIntrinsicWidth, 'getMaxIntrinsicWidth', constraints.maxWidth); + if (minIntrinsicWidth > maxIntrinsicWidth) { + failures.writeln(' * getMinIntrinsicWidth(${constraints.maxWidth}) returned a larger value ($minIntrinsicWidth) than getMaxIntrinsicWidth(${constraints.maxWidth}) ($maxIntrinsicWidth)'); failureCount += 1; } - intrinsic = getMaxIntrinsicWidth(constraints); - if (intrinsic != constraints.constrainWidth(intrinsic)) { - failures.writeln(' * getMaxIntrinsicWidth() -- returned: w=$intrinsic'); - failureCount += 1; - } - intrinsic = getMinIntrinsicHeight(constraints); - if (intrinsic != constraints.constrainHeight(intrinsic)) { - failures.writeln(' * getMinIntrinsicHeight() -- returned: h=$intrinsic'); - failureCount += 1; - } - intrinsic = getMaxIntrinsicHeight(constraints); - if (intrinsic != constraints.constrainHeight(intrinsic)) { - failures.writeln(' * getMaxIntrinsicHeight() -- returned: h=$intrinsic'); + final double minIntrinsicHeight = testIntrinsic(getMinIntrinsicHeight, 'getMinIntrinsicHeight', constraints.maxHeight); + final double maxIntrinsicHeight = testIntrinsic(getMaxIntrinsicHeight, 'getMaxIntrinsicHeight', constraints.maxHeight); + if (minIntrinsicHeight > maxIntrinsicHeight) { + failures.writeln(' * getMinIntrinsicHeight(${constraints.maxHeight}) returned a larger value ($minIntrinsicHeight) than getMaxIntrinsicHeight(${constraints.maxHeight}) ($maxIntrinsicHeight)'); failureCount += 1; } + + // TODO(ianh): Test that values are internally consistent in more ways than the above. + RenderObject.debugCheckingIntrinsics = false; _debugNeedsIntrinsicSizeCheck = false; if (failures.isNotEmpty) { assert(failureCount > 0); throw new FlutterError( - 'The intrinsic dimension methods of the $runtimeType class returned values that violate the given constraints.\n' - 'The constraints were: $constraints\n' - 'The following method${failureCount > 1 ? "s" : ""} returned values outside of those constraints:\n' + 'The intrinsic dimension methods of the $runtimeType class returned values that violate the intrinsic protocol contract.\n' + 'The following ${failureCount > 1 ? "failures" : "failure"} was detected:\n' '$failures' 'If you are not writing your own RenderBox subclass, then this is not\n' 'your fault. Contact support: https://github.com/flutter/flutter/issues/new' diff --git a/packages/flutter/lib/src/rendering/custom_layout.dart b/packages/flutter/lib/src/rendering/custom_layout.dart index a98f1a82a1..fca652ef54 100644 --- a/packages/flutter/lib/src/rendering/custom_layout.dart +++ b/packages/flutter/lib/src/rendering/custom_layout.dart @@ -239,24 +239,40 @@ class RenderCustomMultiChildLayoutBox extends RenderBox return constraints.constrain(_delegate.getSize(constraints)); } + // TODO(ianh): It's a bit dubious to be using the getSize function from the delegate to + // figure out the intrinsic dimensions. We really should either not support intrinsics, + // or we should expose intrinsic delegate callbacks and throw if they're not implemented. + @override - double getMinIntrinsicWidth(BoxConstraints constraints) { - return _getSize(constraints).width; + double getMinIntrinsicWidth(double height) { + final double width = _getSize(new BoxConstraints.tightForFinite(height: height)).width; + if (width.isFinite) + return width; + return 0.0; } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { - return _getSize(constraints).width; + double getMaxIntrinsicWidth(double height) { + final double width = _getSize(new BoxConstraints.tightForFinite(height: height)).width; + if (width.isFinite) + return width; + return 0.0; } @override - double getMinIntrinsicHeight(BoxConstraints constraints) { - return _getSize(constraints).height; + double getMinIntrinsicHeight(double width) { + final double height = _getSize(new BoxConstraints.tightForFinite(width: width)).height; + if (height.isFinite) + return height; + return 0.0; } @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { - return _getSize(constraints).height; + double getMaxIntrinsicHeight(double width) { + final double height = _getSize(new BoxConstraints.tightForFinite(width: width)).height; + if (height.isFinite) + return height; + return 0.0; } @override diff --git a/packages/flutter/lib/src/rendering/editable_line.dart b/packages/flutter/lib/src/rendering/editable_line.dart index 712e2f155f..204e4066bc 100644 --- a/packages/flutter/lib/src/rendering/editable_line.dart +++ b/packages/flutter/lib/src/rendering/editable_line.dart @@ -192,27 +192,13 @@ class RenderEditableLine extends RenderBox { } @override - double getMinIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return constraints.constrainWidth(0.0); + double getMinIntrinsicHeight(double width) { + return _preferredHeight; } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return constraints.constrainWidth(0.0); - } - - @override - double getMinIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return constraints.constrainHeight(_preferredHeight); - } - - @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return constraints.constrainHeight(_preferredHeight); + double getMaxIntrinsicHeight(double width) { + return _preferredHeight; } @override diff --git a/packages/flutter/lib/src/rendering/error.dart b/packages/flutter/lib/src/rendering/error.dart index f0f4f96fdc..b21d1d83d4 100644 --- a/packages/flutter/lib/src/rendering/error.dart +++ b/packages/flutter/lib/src/rendering/error.dart @@ -54,23 +54,13 @@ class RenderErrorBox extends RenderBox { ui.Paragraph _paragraph; @override - double getMinIntrinsicWidth(BoxConstraints constraints) { - return constraints.constrainWidth(0.0); + double getMaxIntrinsicWidth(double height) { + return _kMaxWidth; } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { - return constraints.constrainWidth(_kMaxWidth); - } - - @override - double getMinIntrinsicHeight(BoxConstraints constraints) { - return constraints.constrainHeight(0.0); - } - - @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { - return constraints.constrainHeight(_kMaxHeight); + double getMaxIntrinsicHeight(double width) { + return _kMaxHeight; } @override diff --git a/packages/flutter/lib/src/rendering/flex.dart b/packages/flutter/lib/src/rendering/flex.dart index 46a958bbbe..f32951aed6 100644 --- a/packages/flutter/lib/src/rendering/flex.dart +++ b/packages/flutter/lib/src/rendering/flex.dart @@ -71,7 +71,7 @@ enum CrossAxisAlignment { baseline, } -typedef double _ChildSizingFunction(RenderBox child, BoxConstraints constraints); +typedef double _ChildSizingFunction(RenderBox child, double extent); /// Implements the flex layout algorithm /// @@ -156,25 +156,15 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin 0) { - double flexFraction = childSize(child, childConstraints) / _getFlex(child); + double flexFraction = childSize(child, extent) / _getFlex(child); maxFlexFractionSoFar = math.max(maxFlexFractionSoFar, flexFraction); } else { - inflexibleSpace += childSize(child, childConstraints); + inflexibleSpace += childSize(child, extent); } final FlexParentData childParentData = child.parentData; child = childParentData.nextSibling; } - double mainSize = maxFlexFractionSoFar * totalFlex + inflexibleSpace; - - // Ensure that we don't violate the given constraints with our result - switch(_direction) { - case FlexDirection.horizontal: - return constraints.constrainWidth(mainSize); - case FlexDirection.vertical: - return constraints.constrainHeight(mainSize); - } + return maxFlexFractionSoFar * totalFlex + inflexibleSpace; } else { // INTRINSIC CROSS SIZE - // The spec wants us to perform layout into the given available main-axis - // space and return the cross size. That's too expensive, so instead we - // size inflexible children according to their max intrinsic size in the - // main direction and use those constraints to determine their max - // intrinsic size in the cross direction. We don't care if the caller - // asked for max or min -- the answer is always computed using the - // max size in the main direction. + // Intrinsic cross size is the max of the intrinsic cross sizes of the + // children, after the flexible children are fit into the available space, + // with the children sized using their max intrinsic dimensions. + // TODO(ianh): Support baseline alignment. - double availableMainSpace; - BoxConstraints childConstraints; - switch(_direction) { - case FlexDirection.horizontal: - childConstraints = new BoxConstraints(maxHeight: constraints.maxHeight); - availableMainSpace = constraints.maxWidth; - break; - case FlexDirection.vertical: - childConstraints = new BoxConstraints(maxWidth: constraints.maxWidth); - availableMainSpace = constraints.maxHeight; - break; - } - - // Get inflexible space using the max in the main direction + // Get inflexible space using the max intrinsic dimensions of fixed children in the main direction. + double availableMainSpace = extent; int totalFlex = 0; double inflexibleSpace = 0.0; double maxCrossSize = 0.0; @@ -236,16 +203,12 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin 0) { - double childMainSize = spacePerFlex * flex; - double crossSize; - switch (_direction) { - case FlexDirection.horizontal: - BoxConstraints childConstraints = - new BoxConstraints(minWidth: childMainSize, maxWidth: childMainSize); - crossSize = child.getMaxIntrinsicHeight(childConstraints); - break; - case FlexDirection.vertical: - BoxConstraints childConstraints = - new BoxConstraints(minHeight: childMainSize, maxHeight: childMainSize); - crossSize = child.getMaxIntrinsicWidth(childConstraints); - break; - } - maxCrossSize = math.max(maxCrossSize, crossSize); - } + if (flex > 0) + maxCrossSize = math.max(maxCrossSize, childSize(child, spacePerFlex * flex)); final FlexParentData childParentData = child.parentData; child = childParentData.nextSibling; } - // Ensure that we don't violate the given constraints with our result - switch(_direction) { - case FlexDirection.horizontal: - return constraints.constrainHeight(maxCrossSize); - case FlexDirection.vertical: - return constraints.constrainWidth(maxCrossSize); - } + return maxCrossSize; } } @override - double getMinIntrinsicWidth(BoxConstraints constraints) { + double getMinIntrinsicWidth(double height) { return _getIntrinsicSize( - constraints: constraints, sizingDirection: FlexDirection.horizontal, - childSize: (RenderBox child, BoxConstraints innerConstraints) => child.getMinIntrinsicWidth(innerConstraints) + extent: height, + childSize: (RenderBox child, double extent) => child.getMinIntrinsicWidth(extent) ); } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { + double getMaxIntrinsicWidth(double height) { return _getIntrinsicSize( - constraints: constraints, sizingDirection: FlexDirection.horizontal, - childSize: (RenderBox child, BoxConstraints innerConstraints) => child.getMaxIntrinsicWidth(innerConstraints) + extent: height, + childSize: (RenderBox child, double extent) => child.getMaxIntrinsicWidth(extent) ); } @override - double getMinIntrinsicHeight(BoxConstraints constraints) { + double getMinIntrinsicHeight(double width) { return _getIntrinsicSize( - constraints: constraints, sizingDirection: FlexDirection.vertical, - childSize: (RenderBox child, BoxConstraints innerConstraints) => child.getMinIntrinsicHeight(innerConstraints) + extent: width, + childSize: (RenderBox child, double extent) => child.getMinIntrinsicHeight(extent) ); } @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { + double getMaxIntrinsicHeight(double width) { return _getIntrinsicSize( - constraints: constraints, sizingDirection: FlexDirection.vertical, - childSize: (RenderBox child, BoxConstraints innerConstraints) => child.getMaxIntrinsicHeight(innerConstraints)); + extent: width, + childSize: (RenderBox child, double extent) => child.getMaxIntrinsicHeight(extent) + ); } @override @@ -352,8 +295,6 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin true; + // TODO(ianh): It's a bit dubious to be using the getSize function from the delegate to + // figure out the intrinsic dimensions. We really should either not support intrinsics, + // or we should expose intrinsic delegate callbacks and throw if they're not implemented. + @override - double getMinIntrinsicWidth(BoxConstraints constraints) { - return _getSize(constraints).width; + double getMinIntrinsicWidth(double height) { + final double width = _getSize(new BoxConstraints.tightForFinite(height: height)).width; + if (width.isFinite) + return width; + return 0.0; } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { - return _getSize(constraints).width; + double getMaxIntrinsicWidth(double height) { + final double width = _getSize(new BoxConstraints.tightForFinite(height: height)).width; + if (width.isFinite) + return width; + return 0.0; } @override - double getMinIntrinsicHeight(BoxConstraints constraints) { - return _getSize(constraints).height; + double getMinIntrinsicHeight(double width) { + final double height = _getSize(new BoxConstraints.tightForFinite(width: width)).height; + if (height.isFinite) + return height; + return 0.0; } @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { - return _getSize(constraints).height; + double getMaxIntrinsicHeight(double width) { + final double height = _getSize(new BoxConstraints.tightForFinite(width: width)).height; + if (height.isFinite) + return height; + return 0.0; } @override diff --git a/packages/flutter/lib/src/rendering/grid.dart b/packages/flutter/lib/src/rendering/grid.dart index e0b4c8e6f0..550f8d8642 100644 --- a/packages/flutter/lib/src/rendering/grid.dart +++ b/packages/flutter/lib/src/rendering/grid.dart @@ -181,26 +181,34 @@ abstract class GridDelegate { /// Returns the minimum width that this grid could be without failing to paint /// its contents within itself. - double getMinIntrinsicWidth(BoxConstraints constraints, int childCount) { - return constraints.constrainWidth(_getGridSize(constraints, childCount).width); + /// + /// For more details, see [RenderBox.getMinIntrinsicWidth]. + double getMinIntrinsicWidth(double height, int childCount) { + return _getGridSize(new BoxConstraints.tightForFinite(height: height), childCount).width; } /// Returns the smallest width beyond which increasing the width never /// decreases the preferred height. - double getMaxIntrinsicWidth(BoxConstraints constraints, int childCount) { - return constraints.constrainWidth(_getGridSize(constraints, childCount).width); + /// + /// For more details, see [RenderBox.getMaxIntrinsicWidth]. + double getMaxIntrinsicWidth(double height, int childCount) { + return _getGridSize(new BoxConstraints.tightForFinite(height: height), childCount).width; } /// Return the minimum height that this grid could be without failing to paint /// its contents within itself. - double getMinIntrinsicHeight(BoxConstraints constraints, int childCount) { - return constraints.constrainHeight(_getGridSize(constraints, childCount).height); + /// + /// For more details, see [RenderBox.getMinIntrinsicHeight]. + double getMinIntrinsicHeight(double width, int childCount) { + return _getGridSize(new BoxConstraints.tightForFinite(width: width), childCount).height; } /// Returns the smallest height beyond which increasing the height never /// decreases the preferred width. - double getMaxIntrinsicHeight(BoxConstraints constraints, int childCount) { - return constraints.constrainHeight(_getGridSize(constraints, childCount).height); + /// + /// For more details, see [RenderBox.getMaxIntrinsicHeight]. + double getMaxIntrinsicHeight(double width, int childCount) { + return _getGridSize(new BoxConstraints.tightForFinite(width: width), childCount).height; } } @@ -293,13 +301,13 @@ class FixedColumnCountGridDelegate extends GridDelegateWithInOrderChildPlacement } @override - double getMinIntrinsicWidth(BoxConstraints constraints, int childCount) { - return constraints.constrainWidth(0.0); + double getMinIntrinsicWidth(double height, int childCount) { + return 0.0; } @override - double getMaxIntrinsicWidth(BoxConstraints constraints, int childCount) { - return constraints.constrainWidth(0.0); + double getMaxIntrinsicWidth(double height, int childCount) { + return 0.0; } } @@ -359,13 +367,13 @@ class MaxTileWidthGridDelegate extends GridDelegateWithInOrderChildPlacement { } @override - double getMinIntrinsicWidth(BoxConstraints constraints, int childCount) { - return constraints.constrainWidth(0.0); + double getMinIntrinsicWidth(double height, int childCount) { + return 0.0; } @override - double getMaxIntrinsicWidth(BoxConstraints constraints, int childCount) { - return constraints.constrainWidth(maxTileWidth * childCount); + double getMaxIntrinsicWidth(double height, int childCount) { + return maxTileWidth * childCount; } } @@ -470,27 +478,23 @@ class RenderGrid extends RenderVirtualViewport { } @override - double getMinIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return _delegate.getMinIntrinsicWidth(constraints, virtualChildCount); + double getMinIntrinsicWidth(double height) { + return _delegate.getMinIntrinsicWidth(height, virtualChildCount); } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return _delegate.getMaxIntrinsicWidth(constraints, virtualChildCount); + double getMaxIntrinsicWidth(double height) { + return _delegate.getMaxIntrinsicWidth(height, virtualChildCount); } @override - double getMinIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return _delegate.getMinIntrinsicHeight(constraints, virtualChildCount); + double getMinIntrinsicHeight(double width) { + return _delegate.getMinIntrinsicHeight(width, virtualChildCount); } @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return _delegate.getMaxIntrinsicHeight(constraints, virtualChildCount); + double getMaxIntrinsicHeight(double width) { + return _delegate.getMaxIntrinsicHeight(width, virtualChildCount); } @override diff --git a/packages/flutter/lib/src/rendering/image.dart b/packages/flutter/lib/src/rendering/image.dart index 7a0091e13b..52d28e7c30 100644 --- a/packages/flutter/lib/src/rendering/image.dart +++ b/packages/flutter/lib/src/rendering/image.dart @@ -205,31 +205,27 @@ class RenderImage extends RenderBox { } @override - double getMinIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); + double getMinIntrinsicWidth(double height) { if (_width == null && _height == null) - return constraints.constrainWidth(0.0); - return _sizeForConstraints(constraints).width; + return 0.0; + return _sizeForConstraints(new BoxConstraints.tightForFinite(height: height)).width; } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return _sizeForConstraints(constraints).width; + double getMaxIntrinsicWidth(double height) { + return _sizeForConstraints(new BoxConstraints.tightForFinite(height: height)).width; } @override - double getMinIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); + double getMinIntrinsicHeight(double width) { if (_width == null && _height == null) - return constraints.constrainHeight(0.0); - return _sizeForConstraints(constraints).height; + return 0.0; + return _sizeForConstraints(new BoxConstraints.tightForFinite(width: width)).height; } @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return _sizeForConstraints(constraints).height; + double getMaxIntrinsicHeight(double width) { + return _sizeForConstraints(new BoxConstraints.tightForFinite(width: width)).height; } @override diff --git a/packages/flutter/lib/src/rendering/list.dart b/packages/flutter/lib/src/rendering/list.dart index 6fd129a48a..c53752d7d2 100644 --- a/packages/flutter/lib/src/rendering/list.dart +++ b/packages/flutter/lib/src/rendering/list.dart @@ -87,7 +87,7 @@ class RenderList extends RenderVirtualViewport { double get _preferredExtent { if (itemExtent == null) return double.INFINITY; - int count = virtualChildCount; + final int count = virtualChildCount; if (count == null) return double.INFINITY; double extent = itemExtent * count; @@ -96,44 +96,52 @@ class RenderList extends RenderVirtualViewport { return extent; } - double _getIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); + double _getIntrinsicWidth() { switch (mainAxis) { case Axis.vertical: - return constraints.constrainWidth(0.0); + assert(debugThrowIfNotCheckingIntrinsics()); + return 0.0; case Axis.horizontal: - return constraints.constrainWidth(_preferredExtent); + final double width = _preferredExtent; + if (width.isFinite) + return width; + assert(debugThrowIfNotCheckingIntrinsics()); + return 0.0; } } @override - double getMinIntrinsicWidth(BoxConstraints constraints) { - return _getIntrinsicWidth(constraints); + double getMinIntrinsicWidth(double height) { + return _getIntrinsicWidth(); } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { - return _getIntrinsicWidth(constraints); + double getMaxIntrinsicWidth(double height) { + return _getIntrinsicWidth(); } - double _getIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); + double _getIntrinsicHeight() { switch (mainAxis) { case Axis.vertical: - return constraints.constrainHeight(_preferredExtent); + final double height = _preferredExtent; + if (height.isFinite) + return height; + assert(debugThrowIfNotCheckingIntrinsics()); + return 0.0; case Axis.horizontal: - return constraints.constrainHeight(0.0); + assert(debugThrowIfNotCheckingIntrinsics()); + return 0.0; } } @override - double getMinIntrinsicHeight(BoxConstraints constraints) { - return _getIntrinsicHeight(constraints); + double getMinIntrinsicHeight(double width) { + return _getIntrinsicHeight(); } @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { - return _getIntrinsicHeight(constraints); + double getMaxIntrinsicHeight(double width) { + return _getIntrinsicHeight(); } @override diff --git a/packages/flutter/lib/src/rendering/overflow.dart b/packages/flutter/lib/src/rendering/overflow.dart index 5160f8338e..66a7e24860 100644 --- a/packages/flutter/lib/src/rendering/overflow.dart +++ b/packages/flutter/lib/src/rendering/overflow.dart @@ -14,18 +14,6 @@ class RenderOffStage extends RenderBox with RenderObjectWithChildMixin constraints.minWidth; - - @override - double getMaxIntrinsicWidth(BoxConstraints constraints) => constraints.minWidth; - - @override - double getMinIntrinsicHeight(BoxConstraints constraints) => constraints.minHeight; - - @override - double getMaxIntrinsicHeight(BoxConstraints constraints) => constraints.minHeight; - @override bool get sizedByParent => true; diff --git a/packages/flutter/lib/src/rendering/paragraph.dart b/packages/flutter/lib/src/rendering/paragraph.dart index f1c87345cf..1161ae0fc3 100644 --- a/packages/flutter/lib/src/rendering/paragraph.dart +++ b/packages/flutter/lib/src/rendering/paragraph.dart @@ -87,45 +87,43 @@ class RenderParagraph extends RenderBox { markNeedsPaint(); } - void _layoutText(BoxConstraints constraints) { - assert(constraints != null); - assert(constraints.debugAssertIsValid()); - _textPainter.layout(minWidth: constraints.minWidth, maxWidth: _softWrap ? constraints.maxWidth : double.INFINITY); + void _layoutText({ double minWidth: 0.0, double maxWidth: double.INFINITY }) { + _textPainter.layout(minWidth: minWidth, maxWidth: _softWrap ? maxWidth : double.INFINITY); } @override - double getMinIntrinsicWidth(BoxConstraints constraints) { - _layoutText(constraints); - return constraints.constrainWidth(_textPainter.minIntrinsicWidth); + double getMinIntrinsicWidth(double height) { + _layoutText(); + return _textPainter.minIntrinsicWidth; } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { - _layoutText(constraints); - return constraints.constrainWidth(_textPainter.maxIntrinsicWidth); + double getMaxIntrinsicWidth(double height) { + _layoutText(); + return _textPainter.maxIntrinsicWidth; } - double _getIntrinsicHeight(BoxConstraints constraints) { - _layoutText(constraints); - return constraints.constrainHeight(_textPainter.height); + double _getIntrinsicHeight(double width) { + _layoutText(minWidth: width, maxWidth: width); + return _textPainter.height; } @override - double getMinIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return _getIntrinsicHeight(constraints); + double getMinIntrinsicHeight(double width) { + return _getIntrinsicHeight(width); } @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return _getIntrinsicHeight(constraints); + double getMaxIntrinsicHeight(double width) { + return _getIntrinsicHeight(width); } @override double computeDistanceToActualBaseline(TextBaseline baseline) { assert(!needsLayout); - _layoutText(constraints); + assert(constraints != null); + assert(constraints.debugAssertIsValid()); + _layoutText(minWidth: constraints.minWidth, maxWidth: constraints.maxWidth); return _textPainter.computeDistanceToActualBaseline(baseline); } @@ -136,7 +134,7 @@ class RenderParagraph extends RenderBox { void handleEvent(PointerEvent event, BoxHitTestEntry entry) { if (event is! PointerDownEvent) return; - _layoutText(constraints); + _layoutText(minWidth: constraints.minWidth, maxWidth: constraints.maxWidth); Offset offset = entry.localPosition.toOffset(); TextPosition position = _textPainter.getPositionForOffset(offset); TextSpan span = _textPainter.text.getSpanForPosition(position); @@ -149,7 +147,7 @@ class RenderParagraph extends RenderBox { @override void performLayout() { - _layoutText(constraints); + _layoutText(minWidth: constraints.minWidth, maxWidth: constraints.maxWidth); size = constraints.constrain(_textPainter.size); final bool didOverflowWidth = size.width < _textPainter.width; @@ -200,7 +198,7 @@ class RenderParagraph extends RenderBox { // // If you remove this call, make sure that changing the textAlign still // works properly. - _layoutText(constraints); + _layoutText(minWidth: constraints.minWidth, maxWidth: constraints.maxWidth); final Canvas canvas = context.canvas; if (_hasVisualOverflow) { final Rect bounds = offset & size; diff --git a/packages/flutter/lib/src/rendering/performance_overlay.dart b/packages/flutter/lib/src/rendering/performance_overlay.dart index 7466b1f5ac..7bc7a31802 100644 --- a/packages/flutter/lib/src/rendering/performance_overlay.dart +++ b/packages/flutter/lib/src/rendering/performance_overlay.dart @@ -97,13 +97,13 @@ class RenderPerformanceOverlay extends RenderBox { bool get alwaysNeedsCompositing => true; @override - double getMinIntrinsicWidth(BoxConstraints constraints) { - return constraints.constrainWidth(0.0); + double getMinIntrinsicWidth(double height) { + return 0.0; } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { - return constraints.constrainWidth(0.0); + double getMaxIntrinsicWidth(double height) { + return 0.0; } double get _intrinsicHeight { @@ -119,13 +119,13 @@ class RenderPerformanceOverlay extends RenderBox { } @override - double getMinIntrinsicHeight(BoxConstraints constraints) { - return constraints.constrainHeight(_intrinsicHeight); + double getMinIntrinsicHeight(double width) { + return _intrinsicHeight; } @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { - return constraints.constrainHeight(_intrinsicHeight); + double getMaxIntrinsicHeight(double width) { + return _intrinsicHeight; } @override diff --git a/packages/flutter/lib/src/rendering/proxy_box.dart b/packages/flutter/lib/src/rendering/proxy_box.dart index 71577bcf6c..d2515ed158 100644 --- a/packages/flutter/lib/src/rendering/proxy_box.dart +++ b/packages/flutter/lib/src/rendering/proxy_box.dart @@ -42,35 +42,31 @@ class RenderProxyBox extends RenderBox with RenderObjectWithChildMixin quarterTurns % 2 == 1; @override - double getMinIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - if (child != null) - return _isVertical ? child.getMinIntrinsicHeight(constraints.flipped) : child.getMinIntrinsicWidth(constraints); - return super.getMinIntrinsicWidth(constraints); + double getMinIntrinsicWidth(double height) { + if (child == null) + return 0.0; + return _isVertical ? child.getMinIntrinsicHeight(height) : child.getMinIntrinsicWidth(height); } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - if (child != null) - return _isVertical ? child.getMaxIntrinsicHeight(constraints.flipped) : child.getMaxIntrinsicWidth(constraints); - return super.getMaxIntrinsicWidth(constraints); + double getMaxIntrinsicWidth(double height) { + if (child == null) + return 0.0; + return _isVertical ? child.getMaxIntrinsicHeight(height) : child.getMaxIntrinsicWidth(height); } @override - double getMinIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - if (child != null) - return _isVertical ? child.getMinIntrinsicWidth(constraints.flipped) : child.getMinIntrinsicHeight(constraints); - return super.getMinIntrinsicHeight(constraints); + double getMinIntrinsicHeight(double width) { + if (child == null) + return 0.0; + return _isVertical ? child.getMinIntrinsicWidth(width) : child.getMinIntrinsicHeight(width); } @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - if (child != null) - return _isVertical ? child.getMaxIntrinsicWidth(constraints.flipped) : child.getMaxIntrinsicHeight(constraints); - return super.getMaxIntrinsicHeight(constraints); + double getMaxIntrinsicHeight(double width) { + if (child == null) + return 0.0; + return _isVertical ? child.getMaxIntrinsicWidth(width) : child.getMaxIntrinsicHeight(width); } Matrix4 _paintTransform; diff --git a/packages/flutter/lib/src/rendering/shifted_box.dart b/packages/flutter/lib/src/rendering/shifted_box.dart index e210cd9778..f69fda7a11 100644 --- a/packages/flutter/lib/src/rendering/shifted_box.dart +++ b/packages/flutter/lib/src/rendering/shifted_box.dart @@ -17,35 +17,31 @@ abstract class RenderShiftedBox extends RenderBox with RenderObjectWithChildMixi } @override - double getMinIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); + double getMinIntrinsicWidth(double height) { if (child != null) - return child.getMinIntrinsicWidth(constraints); - return super.getMinIntrinsicWidth(constraints); + return child.getMinIntrinsicWidth(height); + return 0.0; } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); + double getMaxIntrinsicWidth(double height) { if (child != null) - return child.getMaxIntrinsicWidth(constraints); - return super.getMaxIntrinsicWidth(constraints); + return child.getMaxIntrinsicWidth(height); + return 0.0; } @override - double getMinIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); + double getMinIntrinsicHeight(double width) { if (child != null) - return child.getMinIntrinsicHeight(constraints); - return super.getMinIntrinsicHeight(constraints); + return child.getMinIntrinsicHeight(width); + return 0.0; } @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); + double getMaxIntrinsicHeight(double width) { if (child != null) - return child.getMaxIntrinsicHeight(constraints); - return super.getMaxIntrinsicHeight(constraints); + return child.getMaxIntrinsicHeight(width); + return 0.0; } @override @@ -115,39 +111,39 @@ class RenderPadding extends RenderShiftedBox { } @override - double getMinIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - double totalPadding = padding.left + padding.right; - if (child != null) - return constraints.constrainWidth(child.getMinIntrinsicWidth(constraints.deflate(padding)) + totalPadding); - return constraints.constrainWidth(totalPadding); + double getMinIntrinsicWidth(double height) { + final double totalHorizontalPadding = padding.left + padding.right; + final double totalVerticalPadding = padding.top + padding.bottom; + if (child != null) // next line relies on double.INFINITY absorption + return child.getMinIntrinsicWidth(height - totalVerticalPadding) + totalHorizontalPadding; + return totalHorizontalPadding; } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - double totalPadding = padding.left + padding.right; - if (child != null) - return constraints.constrainWidth(child.getMaxIntrinsicWidth(constraints.deflate(padding)) + totalPadding); - return constraints.constrainWidth(totalPadding); + double getMaxIntrinsicWidth(double height) { + final double totalHorizontalPadding = padding.left + padding.right; + final double totalVerticalPadding = padding.top + padding.bottom; + if (child != null) // next line relies on double.INFINITY absorption + return child.getMaxIntrinsicWidth(height - totalVerticalPadding) + totalHorizontalPadding; + return totalHorizontalPadding; } @override - double getMinIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - double totalPadding = padding.top + padding.bottom; - if (child != null) - return constraints.constrainHeight(child.getMinIntrinsicHeight(constraints.deflate(padding)) + totalPadding); - return constraints.constrainHeight(totalPadding); + double getMinIntrinsicHeight(double width) { + final double totalHorizontalPadding = padding.left + padding.right; + final double totalVerticalPadding = padding.top + padding.bottom; + if (child != null) // next line relies on double.INFINITY absorption + return child.getMinIntrinsicHeight(width - totalHorizontalPadding) + totalVerticalPadding; + return totalVerticalPadding; } @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - double totalPadding = padding.top + padding.bottom; - if (child != null) - return constraints.constrainHeight(child.getMaxIntrinsicHeight(constraints.deflate(padding)) + totalPadding); - return constraints.constrainHeight(totalPadding); + double getMaxIntrinsicHeight(double width) { + final double totalHorizontalPadding = padding.left + padding.right; + final double totalVerticalPadding = padding.top + padding.bottom; + if (child != null) // next line relies on double.INFINITY absorption + return child.getMaxIntrinsicHeight(width - totalHorizontalPadding) + totalVerticalPadding; + return totalVerticalPadding; } @override @@ -502,30 +498,6 @@ class RenderConstrainedOverflowBox extends RenderAligningShiftedBox { ); } - @override - double getMinIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return constraints.minWidth; - } - - @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return constraints.minWidth; - } - - @override - double getMinIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return constraints.minHeight; - } - - @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return constraints.minHeight; - } - @override bool get sizedByParent => true; @@ -579,27 +551,23 @@ class RenderSizedOverflowBox extends RenderAligningShiftedBox { } @override - double getMinIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return constraints.constrainWidth(_requestedSize.width); + double getMinIntrinsicWidth(double height) { + return _requestedSize.width; } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return constraints.constrainWidth(_requestedSize.width); + double getMaxIntrinsicWidth(double height) { + return _requestedSize.width; } @override - double getMinIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return constraints.constrainHeight(_requestedSize.height); + double getMinIntrinsicHeight(double width) { + return _requestedSize.height; } @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return constraints.constrainHeight(_requestedSize.height); + double getMaxIntrinsicHeight(double width) { + return _requestedSize.height; } @override @@ -699,35 +667,51 @@ class RenderFractionallySizedOverflowBox extends RenderAligningShiftedBox { } @override - double getMinIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - if (child != null) - return constraints.constrainWidth(child.getMinIntrinsicWidth(_getInnerConstraints(constraints))); - return constraints.constrainWidth(_getInnerConstraints(constraints).constrainWidth(0.0)); + double getMinIntrinsicWidth(double height) { + double result; + if (child == null) { + result = super.getMinIntrinsicWidth(height); + } else { // the following line relies on double.INFINITY absorption + result = child.getMinIntrinsicWidth(height * (_heightFactor ?? 1.0)); + } + assert(result.isFinite); + return result / (_widthFactor ?? 1.0); } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - if (child != null) - return constraints.constrainWidth(child.getMaxIntrinsicWidth(_getInnerConstraints(constraints))); - return constraints.constrainWidth(_getInnerConstraints(constraints).constrainWidth(0.0)); + double getMaxIntrinsicWidth(double height) { + double result; + if (child == null) { + result = super.getMaxIntrinsicWidth(height); + } else { // the following line relies on double.INFINITY absorption + result = child.getMaxIntrinsicWidth(height * (_heightFactor ?? 1.0)); + } + assert(result.isFinite); + return result / (_widthFactor ?? 1.0); } @override - double getMinIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - if (child != null) - return constraints.constrainHeight(child.getMinIntrinsicHeight(_getInnerConstraints(constraints))); - return constraints.constrainHeight(_getInnerConstraints(constraints).constrainHeight(0.0)); + double getMinIntrinsicHeight(double width) { + double result; + if (child == null) { + result = super.getMinIntrinsicHeight(width); + } else { // the following line relies on double.INFINITY absorption + result = child.getMinIntrinsicHeight(width * (_widthFactor ?? 1.0)); + } + assert(result.isFinite); + return result / (_heightFactor ?? 1.0); } @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - if (child != null) - return constraints.constrainHeight(child.getMaxIntrinsicHeight(_getInnerConstraints(constraints))); - return constraints.constrainHeight(_getInnerConstraints(constraints).constrainHeight(0.0)); + double getMaxIntrinsicHeight(double width) { + double result; + if (child == null) { + result = super.getMaxIntrinsicHeight(width); + } else { // the following line relies on double.INFINITY absorption + result = child.getMaxIntrinsicHeight(width * (_widthFactor ?? 1.0)); + } + assert(result.isFinite); + return result / (_heightFactor ?? 1.0); } @override @@ -797,28 +781,40 @@ class RenderCustomSingleChildLayoutBox extends RenderShiftedBox { return constraints.constrain(_delegate.getSize(constraints)); } + // TODO(ianh): It's a bit dubious to be using the getSize function from the delegate to + // figure out the intrinsic dimensions. We really should either not support intrinsics, + // or we should expose intrinsic delegate callbacks and throw if they're not implemented. + @override - double getMinIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return _getSize(constraints).width; + double getMinIntrinsicWidth(double height) { + final double width = _getSize(new BoxConstraints.tightForFinite(height: height)).width; + if (width.isFinite) + return width; + return 0.0; } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return _getSize(constraints).width; + double getMaxIntrinsicWidth(double height) { + final double width = _getSize(new BoxConstraints.tightForFinite(height: height)).width; + if (width.isFinite) + return width; + return 0.0; } @override - double getMinIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return _getSize(constraints).height; + double getMinIntrinsicHeight(double width) { + final double height = _getSize(new BoxConstraints.tightForFinite(width: width)).height; + if (height.isFinite) + return height; + return 0.0; } @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return _getSize(constraints).height; + double getMaxIntrinsicHeight(double width) { + final double height = _getSize(new BoxConstraints.tightForFinite(width: width)).height; + if (height.isFinite) + return height; + return 0.0; } @override diff --git a/packages/flutter/lib/src/rendering/stack.dart b/packages/flutter/lib/src/rendering/stack.dart index e45ea9d167..309ed24a18 100644 --- a/packages/flutter/lib/src/rendering/stack.dart +++ b/packages/flutter/lib/src/rendering/stack.dart @@ -224,78 +224,37 @@ abstract class RenderStackBase extends RenderBox } } - @override - double getMinIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - double width = constraints.minWidth; + double _getIntrinsicDimension(double mainChildSizeGetter(RenderBox child)) { + double extent = 0.0; RenderBox child = firstChild; while (child != null) { final StackParentData childParentData = child.parentData; if (!childParentData.isPositioned) - width = math.max(width, child.getMinIntrinsicWidth(constraints)); + extent = math.max(extent, mainChildSizeGetter(child)); assert(child.parentData == childParentData); child = childParentData.nextSibling; } - assert(width == constraints.constrainWidth(width)); - return width; + return extent; } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - bool hasNonPositionedChildren = false; - double width = constraints.minWidth; - RenderBox child = firstChild; - while (child != null) { - final StackParentData childParentData = child.parentData; - if (!childParentData.isPositioned) { - hasNonPositionedChildren = true; - width = math.max(width, child.getMaxIntrinsicWidth(constraints)); - } - assert(child.parentData == childParentData); - child = childParentData.nextSibling; - } - if (!hasNonPositionedChildren) - return constraints.constrainWidth(); - assert(width == constraints.constrainWidth(width)); - return width; + double getMinIntrinsicWidth(double height) { + return _getIntrinsicDimension((RenderBox child) => child.getMinIntrinsicWidth(height)); } @override - double getMinIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - double height = constraints.minHeight; - RenderBox child = firstChild; - while (child != null) { - final StackParentData childParentData = child.parentData; - if (!childParentData.isPositioned) - height = math.max(height, child.getMinIntrinsicHeight(constraints)); - assert(child.parentData == childParentData); - child = childParentData.nextSibling; - } - assert(height == constraints.constrainHeight(height)); - return height; + double getMaxIntrinsicWidth(double height) { + return _getIntrinsicDimension((RenderBox child) => child.getMaxIntrinsicWidth(height)); } @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - bool hasNonPositionedChildren = false; - double height = constraints.minHeight; - RenderBox child = firstChild; - while (child != null) { - final StackParentData childParentData = child.parentData; - if (!childParentData.isPositioned) { - hasNonPositionedChildren = true; - height = math.max(height, child.getMaxIntrinsicHeight(constraints)); - } - assert(child.parentData == childParentData); - child = childParentData.nextSibling; - } - if (!hasNonPositionedChildren) - return constraints.constrainHeight(); - assert(height == constraints.constrainHeight(height)); - return height; + double getMinIntrinsicHeight(double width) { + return _getIntrinsicDimension((RenderBox child) => child.getMinIntrinsicHeight(width)); + } + + @override + double getMaxIntrinsicHeight(double width) { + return _getIntrinsicDimension((RenderBox child) => child.getMaxIntrinsicHeight(width)); } @override diff --git a/packages/flutter/lib/src/rendering/table.dart b/packages/flutter/lib/src/rendering/table.dart index b298ac2709..ebf186a8c9 100644 --- a/packages/flutter/lib/src/rendering/table.dart +++ b/packages/flutter/lib/src/rendering/table.dart @@ -82,7 +82,7 @@ class IntrinsicColumnWidth extends TableColumnWidth { double minIntrinsicWidth(Iterable cells, double containerWidth) { double result = 0.0; for (RenderBox cell in cells) - result = math.max(result, cell.getMinIntrinsicWidth(const BoxConstraints())); + result = math.max(result, cell.getMinIntrinsicWidth(double.INFINITY)); return result; } @@ -90,7 +90,7 @@ class IntrinsicColumnWidth extends TableColumnWidth { double maxIntrinsicWidth(Iterable cells, double containerWidth) { double result = 0.0; for (RenderBox cell in cells) - result = math.max(result, cell.getMaxIntrinsicWidth(const BoxConstraints())); + result = math.max(result, cell.getMaxIntrinsicWidth(double.INFINITY)); return result; } @@ -689,36 +689,33 @@ class RenderTable extends RenderBox { } @override - double getMinIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); + double getMinIntrinsicWidth(double height) { assert(_children.length == rows * columns); double totalMinWidth = 0.0; for (int x = 0; x < columns; x += 1) { TableColumnWidth columnWidth = _columnWidths[x] ?? defaultColumnWidth; Iterable columnCells = column(x); - totalMinWidth += columnWidth.minIntrinsicWidth(columnCells, constraints.maxWidth); + totalMinWidth += columnWidth.minIntrinsicWidth(columnCells, double.INFINITY); } - return constraints.constrainWidth(totalMinWidth); + return totalMinWidth; } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); + double getMaxIntrinsicWidth(double height) { assert(_children.length == rows * columns); double totalMaxWidth = 0.0; for (int x = 0; x < columns; x += 1) { TableColumnWidth columnWidth = _columnWidths[x] ?? defaultColumnWidth; Iterable columnCells = column(x); - totalMaxWidth += columnWidth.maxIntrinsicWidth(columnCells, constraints.maxWidth); + totalMaxWidth += columnWidth.maxIntrinsicWidth(columnCells, double.INFINITY); } - return constraints.constrainWidth(totalMaxWidth); + return totalMaxWidth; } @override - double getMinIntrinsicHeight(BoxConstraints constraints) { + double getMinIntrinsicHeight(double width) { // winner of the 2016 world's most expensive intrinsic dimension function award // honorable mention, most likely to improve if taught about memoization award - assert(constraints.debugAssertIsValid()); assert(_children.length == rows * columns); final List widths = _computeColumnWidths(constraints); double rowTop = 0.0; @@ -728,16 +725,16 @@ class RenderTable extends RenderBox { final int xy = x + y * columns; RenderBox child = _children[xy]; if (child != null) - rowHeight = math.max(rowHeight, child.getMaxIntrinsicHeight(new BoxConstraints.tightFor(width: widths[x]))); + rowHeight = math.max(rowHeight, child.getMaxIntrinsicHeight(widths[x])); } rowTop += rowHeight; } - return constraints.constrainHeight(rowTop); + return rowTop; } @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { - return getMinIntrinsicHeight(constraints); + double getMaxIntrinsicHeight(double width) { + return getMinIntrinsicHeight(width); } double _baselineDistance; diff --git a/packages/flutter/lib/src/rendering/viewport.dart b/packages/flutter/lib/src/rendering/viewport.dart index 07f79db5b7..b2d31ea984 100644 --- a/packages/flutter/lib/src/rendering/viewport.dart +++ b/packages/flutter/lib/src/rendering/viewport.dart @@ -218,35 +218,31 @@ class RenderViewport extends RenderViewportBase with RenderObjectWithChildMixin< } @override - double getMinIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); + double getMinIntrinsicWidth(double height) { if (child != null) - return constraints.constrainWidth(child.getMinIntrinsicWidth(_getInnerConstraints(constraints))); - return super.getMinIntrinsicWidth(constraints); + return child.getMinIntrinsicWidth(height); + return 0.0; } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); + double getMaxIntrinsicWidth(double height) { if (child != null) - return constraints.constrainWidth(child.getMaxIntrinsicWidth(_getInnerConstraints(constraints))); - return super.getMaxIntrinsicWidth(constraints); + return child.getMaxIntrinsicWidth(height); + return 0.0; } @override - double getMinIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); + double getMinIntrinsicHeight(double width) { if (child != null) - return constraints.constrainHeight(child.getMinIntrinsicHeight(_getInnerConstraints(constraints))); - return super.getMinIntrinsicHeight(constraints); + return child.getMinIntrinsicHeight(width); + return 0.0; } @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); + double getMaxIntrinsicHeight(double width) { if (child != null) - return constraints.constrainHeight(child.getMaxIntrinsicHeight(_getInnerConstraints(constraints))); - return super.getMaxIntrinsicHeight(constraints); + return child.getMaxIntrinsicHeight(width); + return 0.0; } // We don't override computeDistanceToActualBaseline(), because we @@ -353,6 +349,51 @@ abstract class RenderVirtualViewport constraints.constrainWidth(); - - double getIntrinsicHeight(BoxConstraints constraints) => constraints.constrainHeight(); - - @override - double getMinIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return getIntrinsicWidth(constraints); + bool _debugThrowIfNotCheckingIntrinsics() { + assert(() { + if (!RenderObject.debugCheckingIntrinsics) { + throw new FlutterError( + 'LayoutBuilder does not support returning intrinsic dimensions.\n' + 'Calculating the intrinsic dimensions would require running the layout callback speculatively, ' + 'which might mutate the live render object tree.' + ); + } + return true; + }); + return true; } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return getIntrinsicWidth(constraints); + double getMinIntrinsicWidth(double height) { + assert(_debugThrowIfNotCheckingIntrinsics()); + return 0.0; } @override - double getMinIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return getIntrinsicHeight(constraints); + double getMaxIntrinsicWidth(double height) { + assert(_debugThrowIfNotCheckingIntrinsics()); + return 0.0; } @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return getIntrinsicHeight(constraints); + double getMinIntrinsicHeight(double width) { + assert(_debugThrowIfNotCheckingIntrinsics()); + return 0.0; + } + + @override + double getMaxIntrinsicHeight(double width) { + assert(_debugThrowIfNotCheckingIntrinsics()); + return 0.0; } @override @@ -85,7 +95,7 @@ class _RenderLayoutBuilder extends RenderBox with RenderObjectWithChildMixin { return true; } - double getIntrinsicWidth(BoxConstraints constraints) { - switch (mainAxis) { - case Axis.horizontal: - return constraints.constrainWidth(0.0); - case Axis.vertical: - assert(_debugThrowIfNotCheckingIntrinsics()); - return constraints.constrainWidth(0.0); - } + @override + double getMinIntrinsicWidth(double height) { + assert(_debugThrowIfNotCheckingIntrinsics()); + return 0.0; } @override - double getMinIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return getIntrinsicWidth(constraints); + double getMaxIntrinsicWidth(double height) { + assert(_debugThrowIfNotCheckingIntrinsics()); + return 0.0; } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return getIntrinsicWidth(constraints); - } - - double getIntrinsicHeight(BoxConstraints constraints) { - switch (mainAxis) { - case Axis.horizontal: - return constraints.constrainHeight(0.0); - case Axis.vertical: - assert(_debugThrowIfNotCheckingIntrinsics()); - return constraints.constrainHeight(0.0); - } + double getMinIntrinsicHeight(double width) { + assert(_debugThrowIfNotCheckingIntrinsics()); + return 0.0; } @override - double getMinIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return getIntrinsicHeight(constraints); - } - - @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { - assert(constraints.debugAssertIsValid()); - return getIntrinsicHeight(constraints); + double getMaxIntrinsicHeight(double width) { + assert(_debugThrowIfNotCheckingIntrinsics()); + return 0.0; } @override diff --git a/packages/flutter/test/rendering/aspect_ratio_test.dart b/packages/flutter/test/rendering/aspect_ratio_test.dart index 5bceff611b..d8f70de1bb 100644 --- a/packages/flutter/test/rendering/aspect_ratio_test.dart +++ b/packages/flutter/test/rendering/aspect_ratio_test.dart @@ -4,21 +4,96 @@ import 'package:flutter/rendering.dart'; import 'package:test/test.dart'; +import 'rendering_tester.dart'; void main() { - test('Intrinsic sizing', () { + test('Intrinsic sizing 2.0', () { RenderAspectRatio box = new RenderAspectRatio(aspectRatio: 2.0); - BoxConstraints constraints = new BoxConstraints.loose(new Size(200.0, 200.0)); - expect(box.getMinIntrinsicWidth(constraints), equals(0.0)); - expect(box.getMaxIntrinsicWidth(constraints), equals(200.0)); - expect(box.getMinIntrinsicHeight(constraints), equals(0.0)); - expect(box.getMaxIntrinsicHeight(constraints), equals(100.0)); + expect(box.getMinIntrinsicWidth(200.0), 400.0); + expect(box.getMinIntrinsicWidth(400.0), 800.0); - constraints = new BoxConstraints(maxHeight: 400.0); - expect(box.getMinIntrinsicWidth(constraints), equals(0.0)); - expect(box.getMaxIntrinsicWidth(constraints), equals(800.0)); - expect(box.getMinIntrinsicHeight(constraints), equals(0.0)); - expect(box.getMaxIntrinsicHeight(constraints), equals(400.0)); + expect(box.getMaxIntrinsicWidth(200.0), 400.0); + expect(box.getMaxIntrinsicWidth(400.0), 800.0); + + expect(box.getMinIntrinsicHeight(200.0), 100.0); + expect(box.getMinIntrinsicHeight(400.0), 200.0); + + expect(box.getMaxIntrinsicHeight(200.0), 100.0); + expect(box.getMaxIntrinsicHeight(400.0), 200.0); + + expect(box.getMinIntrinsicWidth(double.INFINITY), 0.0); + expect(box.getMaxIntrinsicWidth(double.INFINITY), 0.0); + expect(box.getMinIntrinsicHeight(double.INFINITY), 0.0); + expect(box.getMaxIntrinsicHeight(double.INFINITY), 0.0); + }); + + test('Intrinsic sizing 0.5', () { + RenderAspectRatio box = new RenderAspectRatio(aspectRatio: 0.5); + + expect(box.getMinIntrinsicWidth(200.0), 100.0); + expect(box.getMinIntrinsicWidth(400.0), 200.0); + + expect(box.getMaxIntrinsicWidth(200.0), 100.0); + expect(box.getMaxIntrinsicWidth(400.0), 200.0); + + expect(box.getMinIntrinsicHeight(200.0), 400.0); + expect(box.getMinIntrinsicHeight(400.0), 800.0); + + expect(box.getMaxIntrinsicHeight(200.0), 400.0); + expect(box.getMaxIntrinsicHeight(400.0), 800.0); + + expect(box.getMinIntrinsicWidth(double.INFINITY), 0.0); + expect(box.getMaxIntrinsicWidth(double.INFINITY), 0.0); + expect(box.getMinIntrinsicHeight(double.INFINITY), 0.0); + expect(box.getMaxIntrinsicHeight(double.INFINITY), 0.0); + }); + + test('Intrinsic sizing 2.0', () { + RenderAspectRatio box = new RenderAspectRatio( + aspectRatio: 2.0, + child: new RenderSizedBox(const Size(90.0, 70.0)) + ); + + expect(box.getMinIntrinsicWidth(200.0), 400.0); + expect(box.getMinIntrinsicWidth(400.0), 800.0); + + expect(box.getMaxIntrinsicWidth(200.0), 400.0); + expect(box.getMaxIntrinsicWidth(400.0), 800.0); + + expect(box.getMinIntrinsicHeight(200.0), 100.0); + expect(box.getMinIntrinsicHeight(400.0), 200.0); + + expect(box.getMaxIntrinsicHeight(200.0), 100.0); + expect(box.getMaxIntrinsicHeight(400.0), 200.0); + + expect(box.getMinIntrinsicWidth(double.INFINITY), 90.0); + expect(box.getMaxIntrinsicWidth(double.INFINITY), 90.0); + expect(box.getMinIntrinsicHeight(double.INFINITY), 70.0); + expect(box.getMaxIntrinsicHeight(double.INFINITY), 70.0); + }); + + test('Intrinsic sizing 0.5', () { + RenderAspectRatio box = new RenderAspectRatio( + aspectRatio: 0.5, + child: new RenderSizedBox(const Size(90.0, 70.0)) + ); + + expect(box.getMinIntrinsicWidth(200.0), 100.0); + expect(box.getMinIntrinsicWidth(400.0), 200.0); + + expect(box.getMaxIntrinsicWidth(200.0), 100.0); + expect(box.getMaxIntrinsicWidth(400.0), 200.0); + + expect(box.getMinIntrinsicHeight(200.0), 400.0); + expect(box.getMinIntrinsicHeight(400.0), 800.0); + + expect(box.getMaxIntrinsicHeight(200.0), 400.0); + expect(box.getMaxIntrinsicHeight(400.0), 800.0); + + expect(box.getMinIntrinsicWidth(double.INFINITY), 90.0); + expect(box.getMaxIntrinsicWidth(double.INFINITY), 90.0); + expect(box.getMinIntrinsicHeight(double.INFINITY), 70.0); + expect(box.getMaxIntrinsicHeight(double.INFINITY), 70.0); }); } diff --git a/packages/flutter/test/rendering/block_test.dart b/packages/flutter/test/rendering/block_test.dart deleted file mode 100644 index 5ac789f585..0000000000 --- a/packages/flutter/test/rendering/block_test.dart +++ /dev/null @@ -1,70 +0,0 @@ -// 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 'package:flutter/rendering.dart'; -import 'package:test/test.dart'; - -void main() { - test('block intrinsics', () { - RenderParagraph paragraph = new RenderParagraph( - new TextSpan( - style: new TextStyle(height: 1.0), - text: 'Hello World' - ) - ); - const BoxConstraints unconstrained = const BoxConstraints(); - double textWidth = paragraph.getMaxIntrinsicWidth(unconstrained); - double oneLineTextHeight = paragraph.getMinIntrinsicHeight(unconstrained); - final BoxConstraints constrained = new BoxConstraints(maxWidth: textWidth * 0.9); - double wrappedTextWidth = paragraph.getMinIntrinsicWidth(unconstrained); - double twoLinesTextHeight = paragraph.getMinIntrinsicHeight(constrained); - - // controls - expect(wrappedTextWidth, lessThan(textWidth)); - expect(paragraph.getMinIntrinsicWidth(unconstrained), equals(wrappedTextWidth)); - expect(paragraph.getMaxIntrinsicWidth(constrained), equals(constrained.maxWidth)); - - expect(oneLineTextHeight, lessThan(twoLinesTextHeight)); - expect(twoLinesTextHeight, lessThan(oneLineTextHeight * 3.0)); - expect(paragraph.getMaxIntrinsicHeight(unconstrained), equals(oneLineTextHeight)); - expect(paragraph.getMaxIntrinsicHeight(constrained), equals(twoLinesTextHeight)); - - // test setup - RenderBlock testBlock = new RenderBlock( - children: [ - paragraph, - ] - ); - final BoxConstraints empty = new BoxConstraints.tight(Size.zero); - - // vertical block - expect(testBlock.getMinIntrinsicWidth(unconstrained), equals(wrappedTextWidth)); - expect(testBlock.getMinIntrinsicWidth(constrained), equals(wrappedTextWidth)); - expect(testBlock.getMaxIntrinsicWidth(unconstrained), equals(textWidth)); - expect(testBlock.getMaxIntrinsicWidth(constrained), equals(constrained.maxWidth)); - expect(testBlock.getMinIntrinsicHeight(unconstrained), equals(oneLineTextHeight)); - expect(testBlock.getMinIntrinsicHeight(constrained), equals(twoLinesTextHeight)); - expect(testBlock.getMaxIntrinsicHeight(unconstrained), equals(oneLineTextHeight)); - expect(testBlock.getMaxIntrinsicHeight(constrained), equals(twoLinesTextHeight)); - expect(testBlock.getMinIntrinsicWidth(empty), equals(0.0)); - expect(testBlock.getMaxIntrinsicWidth(empty), equals(0.0)); - expect(testBlock.getMinIntrinsicHeight(empty), equals(0.0)); - expect(testBlock.getMaxIntrinsicHeight(empty), equals(0.0)); - - // horizontal block - testBlock.mainAxis = Axis.horizontal; - expect(testBlock.getMinIntrinsicWidth(unconstrained), equals(textWidth)); - expect(testBlock.getMinIntrinsicWidth(constrained), equals(constrained.maxWidth)); - expect(testBlock.getMaxIntrinsicWidth(unconstrained), equals(textWidth)); - expect(testBlock.getMaxIntrinsicWidth(constrained), equals(constrained.maxWidth)); - expect(testBlock.getMinIntrinsicHeight(unconstrained), equals(oneLineTextHeight)); - expect(testBlock.getMinIntrinsicHeight(constrained), equals(oneLineTextHeight)); - expect(testBlock.getMaxIntrinsicHeight(unconstrained), equals(oneLineTextHeight)); - expect(testBlock.getMaxIntrinsicHeight(constrained), equals(oneLineTextHeight)); - expect(testBlock.getMinIntrinsicWidth(empty), equals(0.0)); - expect(testBlock.getMaxIntrinsicWidth(empty), equals(0.0)); - expect(testBlock.getMinIntrinsicHeight(empty), equals(0.0)); - expect(testBlock.getMaxIntrinsicHeight(empty), equals(0.0)); - }); -} diff --git a/packages/flutter/test/rendering/flex_test.dart b/packages/flutter/test/rendering/flex_test.dart index c399f94ba0..62962d9195 100644 --- a/packages/flutter/test/rendering/flex_test.dart +++ b/packages/flutter/test/rendering/flex_test.dart @@ -35,10 +35,10 @@ void main() { BoxConstraints viewport = new BoxConstraints(maxHeight: 100.0, maxWidth: 100.0); layout(flex, constraints: viewport); expect(flexible.size.height, equals(0.0)); - expect(flex.getMinIntrinsicHeight(viewport), equals(100.0)); - expect(flex.getMaxIntrinsicHeight(viewport), equals(100.0)); - expect(flex.getMinIntrinsicWidth(viewport), equals(100.0)); - expect(flex.getMaxIntrinsicWidth(viewport), equals(100.0)); + expect(flex.getMinIntrinsicHeight(100.0), equals(200.0)); + expect(flex.getMaxIntrinsicHeight(100.0), equals(200.0)); + expect(flex.getMinIntrinsicWidth(100.0), equals(0.0)); + expect(flex.getMaxIntrinsicWidth(100.0), equals(0.0)); }); test('Horizontal Overflow', () { @@ -57,10 +57,10 @@ void main() { BoxConstraints viewport = new BoxConstraints(maxHeight: 100.0, maxWidth: 100.0); layout(flex, constraints: viewport); expect(flexible.size.width, equals(0.0)); - expect(flex.getMinIntrinsicHeight(viewport), equals(100.0)); - expect(flex.getMaxIntrinsicHeight(viewport), equals(100.0)); - expect(flex.getMinIntrinsicWidth(viewport), equals(100.0)); - expect(flex.getMaxIntrinsicWidth(viewport), equals(100.0)); + expect(flex.getMinIntrinsicHeight(100.0), equals(0.0)); + expect(flex.getMaxIntrinsicHeight(100.0), equals(0.0)); + expect(flex.getMinIntrinsicWidth(100.0), equals(200.0)); + expect(flex.getMaxIntrinsicWidth(100.0), equals(200.0)); }); test('Vertical Flipped Constraints', () { @@ -72,7 +72,7 @@ void main() { ); BoxConstraints viewport = new BoxConstraints(maxHeight: 200.0, maxWidth: 1000.0); layout(flex, constraints: viewport); - expect(flex.getMaxIntrinsicWidth(viewport) , equals(1000.0)); + expect(flex.getMaxIntrinsicWidth(200.0), equals(0.0)); }); // We can't right a horizontal version of the above test due to diff --git a/packages/flutter/test/rendering/intrinsic_width_test.dart b/packages/flutter/test/rendering/intrinsic_width_test.dart index c740e7c692..8cb35bdce6 100644 --- a/packages/flutter/test/rendering/intrinsic_width_test.dart +++ b/packages/flutter/test/rendering/intrinsic_width_test.dart @@ -7,29 +7,30 @@ import 'package:test/test.dart'; import 'rendering_tester.dart'; +// before using this, consider using RenderSizedBox from rendering_tester.dart class RenderTestBox extends RenderBox { RenderTestBox(this._intrinsicDimensions); final BoxConstraints _intrinsicDimensions; @override - double getMinIntrinsicWidth(BoxConstraints constraints) { - return constraints.constrainWidth(_intrinsicDimensions.minWidth); + double getMinIntrinsicWidth(double height) { + return _intrinsicDimensions.minWidth; } @override - double getMaxIntrinsicWidth(BoxConstraints constraints) { - return constraints.constrainWidth(_intrinsicDimensions.maxWidth); + double getMaxIntrinsicWidth(double height) { + return _intrinsicDimensions.maxWidth; } @override - double getMinIntrinsicHeight(BoxConstraints constraints) { - return constraints.constrainHeight(_intrinsicDimensions.minHeight); + double getMinIntrinsicHeight(double width) { + return _intrinsicDimensions.minHeight; } @override - double getMaxIntrinsicHeight(BoxConstraints constraints) { - return constraints.constrainHeight(_intrinsicDimensions.maxHeight); + double getMaxIntrinsicHeight(double width) { + return _intrinsicDimensions.maxHeight; } @override diff --git a/packages/flutter/test/rendering/paragraph_intrinsics_test.dart b/packages/flutter/test/rendering/paragraph_intrinsics_test.dart new file mode 100644 index 0000000000..0931e5faa7 --- /dev/null +++ b/packages/flutter/test/rendering/paragraph_intrinsics_test.dart @@ -0,0 +1,68 @@ +// 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 'package:flutter/rendering.dart'; +import 'package:test/test.dart'; + +void main() { + test('block and paragraph intrinsics', () { + final RenderParagraph paragraph = new RenderParagraph( + new TextSpan( + style: new TextStyle(height: 1.0), + text: 'Hello World' + ) + ); + final RenderBlock testBlock = new RenderBlock( + children: [ + paragraph, + ] + ); + + final double textWidth = paragraph.getMaxIntrinsicWidth(double.INFINITY); + final double oneLineTextHeight = paragraph.getMinIntrinsicHeight(double.INFINITY); + final double constrainedWidth = textWidth * 0.9; + final double wrappedTextWidth = paragraph.getMinIntrinsicWidth(double.INFINITY); + final double twoLinesTextHeight = paragraph.getMinIntrinsicHeight(constrainedWidth); + final double manyLinesTextHeight = paragraph.getMinIntrinsicHeight(0.0); + + // paragraph + expect(wrappedTextWidth, greaterThan(0.0)); + expect(wrappedTextWidth, lessThan(textWidth)); + expect(oneLineTextHeight, lessThan(twoLinesTextHeight)); + expect(twoLinesTextHeight, lessThan(oneLineTextHeight * 3.0)); + expect(manyLinesTextHeight, greaterThan(twoLinesTextHeight)); + expect(paragraph.getMaxIntrinsicHeight(double.INFINITY), equals(oneLineTextHeight)); + expect(paragraph.getMaxIntrinsicHeight(constrainedWidth), equals(twoLinesTextHeight)); + expect(paragraph.getMaxIntrinsicHeight(0.0), equals(manyLinesTextHeight)); + + // vertical block (same expectations) + expect(testBlock.getMinIntrinsicWidth(double.INFINITY), equals(wrappedTextWidth)); + expect(testBlock.getMaxIntrinsicWidth(double.INFINITY), equals(textWidth)); + expect(testBlock.getMinIntrinsicHeight(double.INFINITY), equals(oneLineTextHeight)); + expect(testBlock.getMinIntrinsicHeight(constrainedWidth), equals(twoLinesTextHeight)); + expect(testBlock.getMaxIntrinsicHeight(double.INFINITY), equals(oneLineTextHeight)); + expect(testBlock.getMaxIntrinsicHeight(constrainedWidth), equals(twoLinesTextHeight)); + expect(testBlock.getMinIntrinsicWidth(0.0), equals(wrappedTextWidth)); + expect(testBlock.getMaxIntrinsicWidth(0.0), equals(textWidth)); + expect(testBlock.getMinIntrinsicHeight(wrappedTextWidth), equals(twoLinesTextHeight)); + expect(testBlock.getMaxIntrinsicHeight(wrappedTextWidth), equals(twoLinesTextHeight)); + expect(testBlock.getMinIntrinsicHeight(0.0), equals(manyLinesTextHeight)); + expect(testBlock.getMaxIntrinsicHeight(0.0), equals(manyLinesTextHeight)); + + // horizontal block (same expectations again) + testBlock.mainAxis = Axis.horizontal; + expect(testBlock.getMinIntrinsicWidth(double.INFINITY), equals(wrappedTextWidth)); + expect(testBlock.getMaxIntrinsicWidth(double.INFINITY), equals(textWidth)); + expect(testBlock.getMinIntrinsicHeight(double.INFINITY), equals(oneLineTextHeight)); + expect(testBlock.getMinIntrinsicHeight(constrainedWidth), equals(twoLinesTextHeight)); + expect(testBlock.getMaxIntrinsicHeight(double.INFINITY), equals(oneLineTextHeight)); + expect(testBlock.getMaxIntrinsicHeight(constrainedWidth), equals(twoLinesTextHeight)); + expect(testBlock.getMinIntrinsicWidth(0.0), equals(wrappedTextWidth)); + expect(testBlock.getMaxIntrinsicWidth(0.0), equals(textWidth)); + expect(testBlock.getMinIntrinsicHeight(wrappedTextWidth), equals(twoLinesTextHeight)); + expect(testBlock.getMaxIntrinsicHeight(wrappedTextWidth), equals(twoLinesTextHeight)); + expect(testBlock.getMinIntrinsicHeight(0.0), equals(manyLinesTextHeight)); + expect(testBlock.getMaxIntrinsicHeight(0.0), equals(manyLinesTextHeight)); + }); +} diff --git a/packages/flutter/test/rendering/rendering_tester.dart b/packages/flutter/test/rendering/rendering_tester.dart index 15e60137d2..97a50be11f 100644 --- a/packages/flutter/test/rendering/rendering_tester.dart +++ b/packages/flutter/test/rendering/rendering_tester.dart @@ -91,7 +91,33 @@ class RenderSizedBox extends RenderBox { final Size _size; @override - void performLayout() { + double getMinIntrinsicWidth(double height) { + return _size.width; + } + + @override + double getMaxIntrinsicWidth(double height) { + return _size.width; + } + + @override + double getMinIntrinsicHeight(double width) { + return _size.height; + } + + @override + double getMaxIntrinsicHeight(double width) { + return _size.height; + } + + @override + bool get sizedByParent => true; + + @override + void performResize() { size = constraints.constrain(_size); } + + @override + void performLayout() { } }