Commit 787fb3be authored by Ian Hickson's avatar Ian Hickson Committed by Adam Barth

Simplify intrinsic dimension APIs (#4283)

parent 52cf2891
...@@ -454,38 +454,42 @@ class RenderBoxToRenderSectorAdapter extends RenderBox with RenderObjectWithChil ...@@ -454,38 +454,42 @@ class RenderBoxToRenderSectorAdapter extends RenderBox with RenderObjectWithChil
} }
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
if (child == null) if (child == null)
return super.getMinIntrinsicWidth(constraints); return 0.0;
return getIntrinsicDimensions(constraints).width; return getIntrinsicDimensions(height: height).width;
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
if (child == null) if (child == null)
return super.getMaxIntrinsicWidth(constraints); return 0.0;
return getIntrinsicDimensions(constraints).width; return getIntrinsicDimensions(height: height).width;
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
if (child == null) if (child == null)
return super.getMinIntrinsicHeight(constraints); return 0.0;
return getIntrinsicDimensions(constraints).height; return getIntrinsicDimensions(width: width).height;
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
if (child == null) if (child == null)
return super.getMaxIntrinsicHeight(constraints); return 0.0;
return getIntrinsicDimensions(constraints).height; 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 is RenderSector);
assert(child.parentData is SectorParentData); assert(child.parentData is SectorParentData);
assert(constraints.maxWidth < double.INFINITY || constraints.maxHeight < double.INFINITY); assert(width != null);
double maxChildDeltaRadius = math.min(constraints.maxWidth, constraints.maxHeight) / 2.0 - innerRadius; assert(height != null);
double maxChildDeltaRadius = math.min(width, height) / 2.0 - innerRadius;
SectorDimensions childDimensions = child.getIntrinsicDimensions(new SectorConstraints(maxDeltaRadius: maxChildDeltaRadius), innerRadius); SectorDimensions childDimensions = child.getIntrinsicDimensions(new SectorConstraints(maxDeltaRadius: maxChildDeltaRadius), innerRadius);
double dimension = (innerRadius + childDimensions.deltaRadius) * 2.0; double dimension = (innerRadius + childDimensions.deltaRadius) * 2.0;
return constraints.constrain(new Size(dimension, dimension)); return constraints.constrain(new Size(dimension, dimension));
......
...@@ -14,31 +14,23 @@ class RenderSolidColorBox extends RenderDecoratedBox { ...@@ -14,31 +14,23 @@ class RenderSolidColorBox extends RenderDecoratedBox {
super(decoration: new BoxDecoration(backgroundColor: backgroundColor)); super(decoration: new BoxDecoration(backgroundColor: backgroundColor));
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
return constraints.constrainHeight( return desiredSize.width == double.INFINITY ? 0.0 : desiredSize.width;
this.desiredSize == Size.infinite ? 0.0 : desiredSize.width
);
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
return constraints.constrainWidth( return desiredSize.width == double.INFINITY ? 0.0 : desiredSize.width;
this.desiredSize == Size.infinite ? 0.0 : desiredSize.width
);
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
return constraints.constrainHeight( return desiredSize.height == double.INFINITY ? 0.0 : desiredSize.height;
this.desiredSize == Size.infinite ? 0.0 : desiredSize.height
);
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
return constraints.constrainHeight( return desiredSize.height == double.INFINITY ? 0.0 : desiredSize.height;
this.desiredSize == Size.infinite ? 0.0 : desiredSize.height
);
} }
@override @override
......
...@@ -100,47 +100,40 @@ class _RenderTabBar extends RenderBox with ...@@ -100,47 +100,40 @@ class _RenderTabBar extends RenderBox with
} }
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
BoxConstraints widthConstraints =
new BoxConstraints(maxWidth: constraints.maxWidth, maxHeight: constraints.maxHeight);
double maxWidth = 0.0; double maxWidth = 0.0;
RenderBox child = firstChild; RenderBox child = firstChild;
while (child != null) { while (child != null) {
maxWidth = math.max(maxWidth, child.getMinIntrinsicWidth(widthConstraints)); maxWidth = math.max(maxWidth, child.getMinIntrinsicWidth(height));
final _TabBarParentData childParentData = child.parentData; final _TabBarParentData childParentData = child.parentData;
child = childParentData.nextSibling; child = childParentData.nextSibling;
} }
double width = isScrollable ? maxWidth : maxWidth * childCount; return isScrollable ? maxWidth : maxWidth * childCount;
return constraints.constrainWidth(width);
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
BoxConstraints widthConstraints =
new BoxConstraints(maxWidth: constraints.maxWidth, maxHeight: constraints.maxHeight);
double maxWidth = 0.0; double maxWidth = 0.0;
double totalWidth = 0.0;
RenderBox child = firstChild; RenderBox child = firstChild;
while (child != null) { 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; final _TabBarParentData childParentData = child.parentData;
child = childParentData.nextSibling; child = childParentData.nextSibling;
} }
double width = isScrollable ? maxWidth : maxWidth * childCount; return isScrollable ? totalWidth : maxWidth * childCount;
return constraints.constrainWidth(width);
} }
double get _tabHeight => textAndIcons ? _kTextAndIconTabHeight : _kTabHeight; double get _tabHeight => textAndIcons ? _kTextAndIconTabHeight : _kTabHeight;
double get _tabBarHeight => _tabHeight + _kTabIndicatorHeight; double get _tabBarHeight => _tabHeight + _kTabIndicatorHeight;
double _getIntrinsicHeight(BoxConstraints constraints) => constraints.constrainHeight(_tabBarHeight);
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) => _getIntrinsicHeight(constraints); double getMinIntrinsicHeight(double width) => _tabBarHeight;
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) => _getIntrinsicHeight(constraints); double getMaxIntrinsicHeight(double width) => _tabBarHeight;
void layoutFixedWidthTabs() { void layoutFixedWidthTabs() {
double tabWidth = size.width / childCount; double tabWidth = size.width / childCount;
......
...@@ -10,8 +10,7 @@ import 'object.dart'; ...@@ -10,8 +10,7 @@ import 'object.dart';
/// Parent data for use with [RenderBlockBase]. /// Parent data for use with [RenderBlockBase].
class BlockParentData extends ContainerBoxParentDataMixin<RenderBox> { } class BlockParentData extends ContainerBoxParentDataMixin<RenderBox> { }
typedef double _ChildSizingFunction(RenderBox child, BoxConstraints constraints); typedef double _ChildSizingFunction(RenderBox child);
typedef double _Constrainer(double value);
/// Implements the block layout algorithm. /// Implements the block layout algorithm.
/// ///
...@@ -158,102 +157,65 @@ class RenderBlock extends RenderBox ...@@ -158,102 +157,65 @@ class RenderBlock extends RenderBox
description.add('mainAxis: $mainAxis'); description.add('mainAxis: $mainAxis');
} }
double _getIntrinsicCrossAxis(BoxConstraints constraints, _ChildSizingFunction childSize, _Constrainer constrainer) { double _getIntrinsicCrossAxis(_ChildSizingFunction childSize) {
double extent = 0.0; 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; RenderBox child = firstChild;
while (child != null) { while (child != null) {
extent = math.max(extent, childSize(child, innerConstraints)); extent = math.max(extent, childSize(child));
final BlockParentData childParentData = child.parentData; final BlockParentData childParentData = child.parentData;
child = childParentData.nextSibling; child = childParentData.nextSibling;
} }
return constrainer(extent); return extent;
} }
double _getIntrinsicMainAxis(BoxConstraints constraints, _Constrainer constrainer) { double _getIntrinsicMainAxis(_ChildSizingFunction childSize) {
double extent = 0.0; double extent = 0.0;
BoxConstraints innerConstraints = _getInnerConstraints(constraints);
RenderBox child = firstChild; RenderBox child = firstChild;
while (child != null) { while (child != null) {
switch (mainAxis) { extent += childSize(child);
case Axis.horizontal:
extent += child.getMaxIntrinsicWidth(innerConstraints);
break;
case Axis.vertical:
extent += child.getMinIntrinsicHeight(innerConstraints);
break;
}
final BlockParentData childParentData = child.parentData; final BlockParentData childParentData = child.parentData;
child = childParentData.nextSibling; child = childParentData.nextSibling;
} }
return constrainer(extent); return extent;
} }
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid());
switch (mainAxis) { switch (mainAxis) {
case Axis.horizontal: case Axis.horizontal:
return _getIntrinsicMainAxis(constraints, constraints.constrainWidth); return _getIntrinsicMainAxis((RenderBox child) => child.getMinIntrinsicWidth(height));
case Axis.vertical: case Axis.vertical:
return _getIntrinsicCrossAxis( return _getIntrinsicCrossAxis((RenderBox child) => child.getMinIntrinsicWidth(height));
constraints,
(RenderBox child, BoxConstraints innerConstraints) => child.getMinIntrinsicWidth(innerConstraints),
constraints.constrainWidth
);
} }
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid());
switch (mainAxis) { switch (mainAxis) {
case Axis.horizontal: case Axis.horizontal:
return _getIntrinsicMainAxis(constraints, constraints.constrainWidth); return _getIntrinsicMainAxis((RenderBox child) => child.getMaxIntrinsicWidth(height));
case Axis.vertical: case Axis.vertical:
return _getIntrinsicCrossAxis( return _getIntrinsicCrossAxis((RenderBox child) => child.getMaxIntrinsicWidth(height));
constraints,
(RenderBox child, BoxConstraints innerConstraints) => child.getMaxIntrinsicWidth(innerConstraints),
constraints.constrainWidth
);
} }
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid());
switch (mainAxis) { switch (mainAxis) {
case Axis.horizontal: case Axis.horizontal:
return _getIntrinsicCrossAxis( return _getIntrinsicMainAxis((RenderBox child) => child.getMinIntrinsicHeight(width));
constraints,
(RenderBox child, BoxConstraints innerConstraints) => child.getMinIntrinsicHeight(innerConstraints),
constraints.constrainHeight
);
case Axis.vertical: case Axis.vertical:
return _getIntrinsicMainAxis(constraints, constraints.constrainHeight); return _getIntrinsicCrossAxis((RenderBox child) => child.getMinIntrinsicHeight(width));
} }
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid());
switch (mainAxis) { switch (mainAxis) {
case Axis.horizontal: case Axis.horizontal:
return _getIntrinsicCrossAxis( return _getIntrinsicMainAxis((RenderBox child) => child.getMaxIntrinsicHeight(width));
constraints,
(RenderBox child, BoxConstraints innerConstraints) => child.getMaxIntrinsicHeight(innerConstraints),
constraints.constrainHeight
);
case Axis.vertical: case Axis.vertical:
return _getIntrinsicMainAxis(constraints, constraints.constrainHeight); return _getIntrinsicCrossAxis((RenderBox child) => child.getMaxIntrinsicHeight(width));
} }
} }
......
...@@ -83,6 +83,15 @@ class BoxConstraints extends Constraints { ...@@ -83,6 +83,15 @@ class BoxConstraints extends Constraints {
minHeight = height != null ? height : 0.0, minHeight = height != null ? height : 0.0,
maxHeight = height != null ? height : double.INFINITY; 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. /// Creates box constraints that forbid sizes larger than the given size.
BoxConstraints.loose(Size size) BoxConstraints.loose(Size size)
: minWidth = 0.0, : minWidth = 0.0,
...@@ -486,44 +495,164 @@ abstract class RenderBox extends RenderObject { ...@@ -486,44 +495,164 @@ abstract class RenderBox extends RenderObject {
child.parentData = new BoxParentData(); child.parentData = new BoxParentData();
} }
/// Returns the minimum width that this box could be without failing to paint /// Returns the minimum width that this box could be without failing to
/// its contents within itself. /// 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]. /// Override in subclasses that implement [performLayout].
double getMinIntrinsicWidth(BoxConstraints constraints) { ///
assert(constraints.debugAssertIsValid()); /// If the layout algorithm is independent of the context (e.g. it always
return constraints.constrainWidth(0.0); /// 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 /// 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]. /// Override in subclasses that implement [performLayout].
double getMaxIntrinsicWidth(BoxConstraints constraints) { ///
assert(constraints.debugAssertIsValid()); /// If the layout algorithm is strictly height-in-width-out, or is
return constraints.constrainWidth(0.0); /// 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 /// Returns the minimum height that this box could be without failing to
/// its contents within itself. /// 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]. /// Override in subclasses that implement [performLayout].
double getMinIntrinsicHeight(BoxConstraints constraints) { ///
assert(constraints.debugAssertIsValid()); /// If the layout algorithm is independent of the context (e.g. it always
return constraints.constrainHeight(0.0); /// 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 /// Returns the smallest height beyond which increasing the height never
/// decreases the preferred width. /// decreases the preferred width. The preferred width is the value that
/// /// would be returned by [getMinIntrinsicWidth] for that height.
/// 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().
/// ///
/// Override in subclasses that implement [performLayout]. /// Override in subclasses that implement [performLayout].
double getMaxIntrinsicHeight(BoxConstraints constraints) { ///
assert(constraints.debugAssertIsValid()); /// If the layout algorithm is strictly width-in-height-out, or is
return constraints.constrainHeight(0.0); /// 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]. /// Whether this render object has undergone layout and has a [size].
...@@ -766,40 +895,47 @@ abstract class RenderBox extends RenderObject { ...@@ -766,40 +895,47 @@ abstract class RenderBox extends RenderObject {
); );
} }
if (_debugNeedsIntrinsicSizeCheck || debugCheckIntrinsicSizes) { if (_debugNeedsIntrinsicSizeCheck || debugCheckIntrinsicSizes) {
// verify that the intrinsics are also within the constraints // verify that the intrinsics are sane
assert(!RenderObject.debugCheckingIntrinsics); assert(!RenderObject.debugCheckingIntrinsics);
RenderObject.debugCheckingIntrinsics = true; RenderObject.debugCheckingIntrinsics = true;
double intrinsic;
StringBuffer failures = new StringBuffer(); StringBuffer failures = new StringBuffer();
int failureCount = 0; int failureCount = 0;
intrinsic = getMinIntrinsicWidth(constraints);
if (intrinsic != constraints.constrainWidth(intrinsic)) { double testIntrinsic(double function(double extent), String name, double constraint) {
failures.writeln(' * getMinIntrinsicWidth() -- returned: w=$intrinsic'); final double result = function(constraint);
failureCount += 1; if (result < 0) {
} failures.writeln(' * $name($constraint) returned a negative value: $result');
intrinsic = getMaxIntrinsicWidth(constraints); failureCount += 1;
if (intrinsic != constraints.constrainWidth(intrinsic)) { }
failures.writeln(' * getMaxIntrinsicWidth() -- returned: w=$intrinsic'); if (!result.isFinite) {
failureCount += 1; failures.writeln(' * $name($constraint) returned a non-finite value: $result');
failureCount += 1;
}
return result;
} }
intrinsic = getMinIntrinsicHeight(constraints);
if (intrinsic != constraints.constrainHeight(intrinsic)) { final double minIntrinsicWidth = testIntrinsic(getMinIntrinsicWidth, 'getMinIntrinsicWidth', constraints.maxWidth);
failures.writeln(' * getMinIntrinsicHeight() -- returned: h=$intrinsic'); 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; failureCount += 1;
} }
intrinsic = getMaxIntrinsicHeight(constraints); final double minIntrinsicHeight = testIntrinsic(getMinIntrinsicHeight, 'getMinIntrinsicHeight', constraints.maxHeight);
if (intrinsic != constraints.constrainHeight(intrinsic)) { final double maxIntrinsicHeight = testIntrinsic(getMaxIntrinsicHeight, 'getMaxIntrinsicHeight', constraints.maxHeight);
failures.writeln(' * getMaxIntrinsicHeight() -- returned: h=$intrinsic'); if (minIntrinsicHeight > maxIntrinsicHeight) {
failures.writeln(' * getMinIntrinsicHeight(${constraints.maxHeight}) returned a larger value ($minIntrinsicHeight) than getMaxIntrinsicHeight(${constraints.maxHeight}) ($maxIntrinsicHeight)');
failureCount += 1; failureCount += 1;
} }
// TODO(ianh): Test that values are internally consistent in more ways than the above.
RenderObject.debugCheckingIntrinsics = false; RenderObject.debugCheckingIntrinsics = false;
_debugNeedsIntrinsicSizeCheck = false; _debugNeedsIntrinsicSizeCheck = false;
if (failures.isNotEmpty) { if (failures.isNotEmpty) {
assert(failureCount > 0); assert(failureCount > 0);
throw new FlutterError( throw new FlutterError(
'The intrinsic dimension methods of the $runtimeType class returned values that violate the given constraints.\n' 'The intrinsic dimension methods of the $runtimeType class returned values that violate the intrinsic protocol contract.\n'
'The constraints were: $constraints\n' 'The following ${failureCount > 1 ? "failures" : "failure"} was detected:\n'
'The following method${failureCount > 1 ? "s" : ""} returned values outside of those constraints:\n'
'$failures' '$failures'
'If you are not writing your own RenderBox subclass, then this is not\n' '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' 'your fault. Contact support: https://github.com/flutter/flutter/issues/new'
......
...@@ -239,24 +239,40 @@ class RenderCustomMultiChildLayoutBox extends RenderBox ...@@ -239,24 +239,40 @@ class RenderCustomMultiChildLayoutBox extends RenderBox
return constraints.constrain(_delegate.getSize(constraints)); 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 @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
return _getSize(constraints).width; final double width = _getSize(new BoxConstraints.tightForFinite(height: height)).width;
if (width.isFinite)
return width;
return 0.0;
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
return _getSize(constraints).width; final double width = _getSize(new BoxConstraints.tightForFinite(height: height)).width;
if (width.isFinite)
return width;
return 0.0;
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
return _getSize(constraints).height; final double height = _getSize(new BoxConstraints.tightForFinite(width: width)).height;
if (height.isFinite)
return height;
return 0.0;
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
return _getSize(constraints).height; final double height = _getSize(new BoxConstraints.tightForFinite(width: width)).height;
if (height.isFinite)
return height;
return 0.0;
} }
@override @override
......
...@@ -192,27 +192,13 @@ class RenderEditableLine extends RenderBox { ...@@ -192,27 +192,13 @@ class RenderEditableLine extends RenderBox {
} }
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); return _preferredHeight;
return constraints.constrainWidth(0.0);
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); return _preferredHeight;
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);
} }
@override @override
......
...@@ -54,23 +54,13 @@ class RenderErrorBox extends RenderBox { ...@@ -54,23 +54,13 @@ class RenderErrorBox extends RenderBox {
ui.Paragraph _paragraph; ui.Paragraph _paragraph;
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
return constraints.constrainWidth(0.0); return _kMaxWidth;
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
return constraints.constrainWidth(_kMaxWidth); return _kMaxHeight;
}
@override
double getMinIntrinsicHeight(BoxConstraints constraints) {
return constraints.constrainHeight(0.0);
}
@override
double getMaxIntrinsicHeight(BoxConstraints constraints) {
return constraints.constrainHeight(_kMaxHeight);
} }
@override @override
......
...@@ -71,7 +71,7 @@ enum CrossAxisAlignment { ...@@ -71,7 +71,7 @@ enum CrossAxisAlignment {
baseline, baseline,
} }
typedef double _ChildSizingFunction(RenderBox child, BoxConstraints constraints); typedef double _ChildSizingFunction(RenderBox child, double extent);
/// Implements the flex layout algorithm /// Implements the flex layout algorithm
/// ///
...@@ -156,25 +156,15 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl ...@@ -156,25 +156,15 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
child.parentData = new FlexParentData(); child.parentData = new FlexParentData();
} }
double _getIntrinsicSize({ BoxConstraints constraints, double _getIntrinsicSize({
FlexDirection sizingDirection, FlexDirection sizingDirection,
_ChildSizingFunction childSize }) { double extent, // the extent in the direction that isn't the sizing direction
assert(constraints.debugAssertIsValid()); _ChildSizingFunction childSize // a method to find the size in the sizing direction
// http://www.w3.org/TR/2015/WD-css-flexbox-1-20150514/#intrinsic-sizes }) {
if (_direction == sizingDirection) { if (_direction == sizingDirection) {
// INTRINSIC MAIN SIZE // INTRINSIC MAIN SIZE
// Intrinsic main size is the smallest size the flex container can take // Intrinsic main size is the smallest size the flex container can take
// while maintaining the min/max-content contributions of its flex items. // while maintaining the min/max-content contributions of its flex items.
BoxConstraints childConstraints;
switch(_direction) {
case FlexDirection.horizontal:
childConstraints = new BoxConstraints(maxHeight: constraints.maxHeight);
break;
case FlexDirection.vertical:
childConstraints = new BoxConstraints(maxWidth: constraints.maxWidth);
break;
}
double totalFlex = 0.0; double totalFlex = 0.0;
double inflexibleSpace = 0.0; double inflexibleSpace = 0.0;
double maxFlexFractionSoFar = 0.0; double maxFlexFractionSoFar = 0.0;
...@@ -183,47 +173,24 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl ...@@ -183,47 +173,24 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
int flex = _getFlex(child); int flex = _getFlex(child);
totalFlex += flex; totalFlex += flex;
if (flex > 0) { if (flex > 0) {
double flexFraction = childSize(child, childConstraints) / _getFlex(child); double flexFraction = childSize(child, extent) / _getFlex(child);
maxFlexFractionSoFar = math.max(maxFlexFractionSoFar, flexFraction); maxFlexFractionSoFar = math.max(maxFlexFractionSoFar, flexFraction);
} else { } else {
inflexibleSpace += childSize(child, childConstraints); inflexibleSpace += childSize(child, extent);
} }
final FlexParentData childParentData = child.parentData; final FlexParentData childParentData = child.parentData;
child = childParentData.nextSibling; child = childParentData.nextSibling;
} }
double mainSize = maxFlexFractionSoFar * totalFlex + inflexibleSpace; return 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);
}
} else { } else {
// INTRINSIC CROSS SIZE // INTRINSIC CROSS SIZE
// The spec wants us to perform layout into the given available main-axis // Intrinsic cross size is the max of the intrinsic cross sizes of the
// space and return the cross size. That's too expensive, so instead we // children, after the flexible children are fit into the available space,
// size inflexible children according to their max intrinsic size in the // with the children sized using their max intrinsic dimensions.
// main direction and use those constraints to determine their max // TODO(ianh): Support baseline alignment.
// 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.
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; int totalFlex = 0;
double inflexibleSpace = 0.0; double inflexibleSpace = 0.0;
double maxCrossSize = 0.0; double maxCrossSize = 0.0;
...@@ -236,16 +203,12 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl ...@@ -236,16 +203,12 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
if (flex == 0) { if (flex == 0) {
switch (_direction) { switch (_direction) {
case FlexDirection.horizontal: case FlexDirection.horizontal:
mainSize = child.getMaxIntrinsicWidth(childConstraints); mainSize = child.getMaxIntrinsicWidth(double.INFINITY);
BoxConstraints widthConstraints = crossSize = childSize(child, mainSize);
new BoxConstraints(minWidth: mainSize, maxWidth: mainSize);
crossSize = child.getMaxIntrinsicHeight(widthConstraints);
break; break;
case FlexDirection.vertical: case FlexDirection.vertical:
mainSize = child.getMaxIntrinsicHeight(childConstraints); mainSize = child.getMaxIntrinsicHeight(double.INFINITY);
BoxConstraints heightConstraints = crossSize = childSize(child, mainSize);
new BoxConstraints(minWidth: mainSize, maxWidth: mainSize);
crossSize = child.getMaxIntrinsicWidth(heightConstraints);
break; break;
} }
inflexibleSpace += mainSize; inflexibleSpace += mainSize;
...@@ -255,79 +218,59 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl ...@@ -255,79 +218,59 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
child = childParentData.nextSibling; child = childParentData.nextSibling;
} }
// Determine the spacePerFlex by allocating the remaining available space // Determine the spacePerFlex by allocating the remaining available space.
// When you're overconstrained spacePerFlex can be negative. // When you're overconstrained spacePerFlex can be negative.
double spacePerFlex = math.max(0.0, double spacePerFlex = math.max(0.0,
(availableMainSpace - inflexibleSpace) / totalFlex); (availableMainSpace - inflexibleSpace) / totalFlex);
// Size remaining items, find the maximum cross size // Size remaining (flexible) items, find the maximum cross size.
child = firstChild; child = firstChild;
while (child != null) { while (child != null) {
int flex = _getFlex(child); int flex = _getFlex(child);
if (flex > 0) { if (flex > 0)
double childMainSize = spacePerFlex * flex; maxCrossSize = math.max(maxCrossSize, childSize(child, 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);
}
final FlexParentData childParentData = child.parentData; final FlexParentData childParentData = child.parentData;
child = childParentData.nextSibling; child = childParentData.nextSibling;
} }
// Ensure that we don't violate the given constraints with our result return maxCrossSize;
switch(_direction) {
case FlexDirection.horizontal:
return constraints.constrainHeight(maxCrossSize);
case FlexDirection.vertical:
return constraints.constrainWidth(maxCrossSize);
}
} }
} }
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
return _getIntrinsicSize( return _getIntrinsicSize(
constraints: constraints,
sizingDirection: FlexDirection.horizontal, sizingDirection: FlexDirection.horizontal,
childSize: (RenderBox child, BoxConstraints innerConstraints) => child.getMinIntrinsicWidth(innerConstraints) extent: height,
childSize: (RenderBox child, double extent) => child.getMinIntrinsicWidth(extent)
); );
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
return _getIntrinsicSize( return _getIntrinsicSize(
constraints: constraints,
sizingDirection: FlexDirection.horizontal, sizingDirection: FlexDirection.horizontal,
childSize: (RenderBox child, BoxConstraints innerConstraints) => child.getMaxIntrinsicWidth(innerConstraints) extent: height,
childSize: (RenderBox child, double extent) => child.getMaxIntrinsicWidth(extent)
); );
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
return _getIntrinsicSize( return _getIntrinsicSize(
constraints: constraints,
sizingDirection: FlexDirection.vertical, sizingDirection: FlexDirection.vertical,
childSize: (RenderBox child, BoxConstraints innerConstraints) => child.getMinIntrinsicHeight(innerConstraints) extent: width,
childSize: (RenderBox child, double extent) => child.getMinIntrinsicHeight(extent)
); );
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
return _getIntrinsicSize( return _getIntrinsicSize(
constraints: constraints,
sizingDirection: FlexDirection.vertical, sizingDirection: FlexDirection.vertical,
childSize: (RenderBox child, BoxConstraints innerConstraints) => child.getMaxIntrinsicHeight(innerConstraints)); extent: width,
childSize: (RenderBox child, double extent) => child.getMaxIntrinsicHeight(extent)
);
} }
@override @override
...@@ -352,8 +295,6 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl ...@@ -352,8 +295,6 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
@override @override
void performLayout() { void performLayout() {
// Originally based on http://www.w3.org/TR/css-flexbox-1/ Section 9.7 Resolving Flexible Lengths
// Determine used flex factor, size inflexible items, calculate free space. // Determine used flex factor, size inflexible items, calculate free space.
int totalFlex = 0; int totalFlex = 0;
int totalChildren = 0; int totalChildren = 0;
......
...@@ -240,24 +240,40 @@ class RenderFlow extends RenderBox ...@@ -240,24 +240,40 @@ class RenderFlow extends RenderBox
@override @override
bool get isRepaintBoundary => true; bool get isRepaintBoundary => 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 @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
return _getSize(constraints).width; final double width = _getSize(new BoxConstraints.tightForFinite(height: height)).width;
if (width.isFinite)
return width;
return 0.0;
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
return _getSize(constraints).width; final double width = _getSize(new BoxConstraints.tightForFinite(height: height)).width;
if (width.isFinite)
return width;
return 0.0;
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
return _getSize(constraints).height; final double height = _getSize(new BoxConstraints.tightForFinite(width: width)).height;
if (height.isFinite)
return height;
return 0.0;
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
return _getSize(constraints).height; final double height = _getSize(new BoxConstraints.tightForFinite(width: width)).height;
if (height.isFinite)
return height;
return 0.0;
} }
@override @override
......
...@@ -181,26 +181,34 @@ abstract class GridDelegate { ...@@ -181,26 +181,34 @@ abstract class GridDelegate {
/// Returns the minimum width that this grid could be without failing to paint /// Returns the minimum width that this grid could be without failing to paint
/// its contents within itself. /// 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 /// Returns the smallest width beyond which increasing the width never
/// decreases the preferred height. /// 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 /// Return the minimum height that this grid could be without failing to paint
/// its contents within itself. /// 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 /// Returns the smallest height beyond which increasing the height never
/// decreases the preferred width. /// 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 ...@@ -293,13 +301,13 @@ class FixedColumnCountGridDelegate extends GridDelegateWithInOrderChildPlacement
} }
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints, int childCount) { double getMinIntrinsicWidth(double height, int childCount) {
return constraints.constrainWidth(0.0); return 0.0;
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints, int childCount) { double getMaxIntrinsicWidth(double height, int childCount) {
return constraints.constrainWidth(0.0); return 0.0;
} }
} }
...@@ -359,13 +367,13 @@ class MaxTileWidthGridDelegate extends GridDelegateWithInOrderChildPlacement { ...@@ -359,13 +367,13 @@ class MaxTileWidthGridDelegate extends GridDelegateWithInOrderChildPlacement {
} }
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints, int childCount) { double getMinIntrinsicWidth(double height, int childCount) {
return constraints.constrainWidth(0.0); return 0.0;
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints, int childCount) { double getMaxIntrinsicWidth(double height, int childCount) {
return constraints.constrainWidth(maxTileWidth * childCount); return maxTileWidth * childCount;
} }
} }
...@@ -470,27 +478,23 @@ class RenderGrid extends RenderVirtualViewport<GridParentData> { ...@@ -470,27 +478,23 @@ class RenderGrid extends RenderVirtualViewport<GridParentData> {
} }
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid()); return _delegate.getMinIntrinsicWidth(height, virtualChildCount);
return _delegate.getMinIntrinsicWidth(constraints, virtualChildCount);
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid()); return _delegate.getMaxIntrinsicWidth(height, virtualChildCount);
return _delegate.getMaxIntrinsicWidth(constraints, virtualChildCount);
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); return _delegate.getMinIntrinsicHeight(width, virtualChildCount);
return _delegate.getMinIntrinsicHeight(constraints, virtualChildCount);
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); return _delegate.getMaxIntrinsicHeight(width, virtualChildCount);
return _delegate.getMaxIntrinsicHeight(constraints, virtualChildCount);
} }
@override @override
......
...@@ -205,31 +205,27 @@ class RenderImage extends RenderBox { ...@@ -205,31 +205,27 @@ class RenderImage extends RenderBox {
} }
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid());
if (_width == null && _height == null) if (_width == null && _height == null)
return constraints.constrainWidth(0.0); return 0.0;
return _sizeForConstraints(constraints).width; return _sizeForConstraints(new BoxConstraints.tightForFinite(height: height)).width;
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid()); return _sizeForConstraints(new BoxConstraints.tightForFinite(height: height)).width;
return _sizeForConstraints(constraints).width;
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid());
if (_width == null && _height == null) if (_width == null && _height == null)
return constraints.constrainHeight(0.0); return 0.0;
return _sizeForConstraints(constraints).height; return _sizeForConstraints(new BoxConstraints.tightForFinite(width: width)).height;
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); return _sizeForConstraints(new BoxConstraints.tightForFinite(width: width)).height;
return _sizeForConstraints(constraints).height;
} }
@override @override
......
...@@ -87,7 +87,7 @@ class RenderList extends RenderVirtualViewport<ListParentData> { ...@@ -87,7 +87,7 @@ class RenderList extends RenderVirtualViewport<ListParentData> {
double get _preferredExtent { double get _preferredExtent {
if (itemExtent == null) if (itemExtent == null)
return double.INFINITY; return double.INFINITY;
int count = virtualChildCount; final int count = virtualChildCount;
if (count == null) if (count == null)
return double.INFINITY; return double.INFINITY;
double extent = itemExtent * count; double extent = itemExtent * count;
...@@ -96,44 +96,52 @@ class RenderList extends RenderVirtualViewport<ListParentData> { ...@@ -96,44 +96,52 @@ class RenderList extends RenderVirtualViewport<ListParentData> {
return extent; return extent;
} }
double _getIntrinsicWidth(BoxConstraints constraints) { double _getIntrinsicWidth() {
assert(constraints.debugAssertIsValid());
switch (mainAxis) { switch (mainAxis) {
case Axis.vertical: case Axis.vertical:
return constraints.constrainWidth(0.0); assert(debugThrowIfNotCheckingIntrinsics());
return 0.0;
case Axis.horizontal: case Axis.horizontal:
return constraints.constrainWidth(_preferredExtent); final double width = _preferredExtent;
if (width.isFinite)
return width;
assert(debugThrowIfNotCheckingIntrinsics());
return 0.0;
} }
} }
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
return _getIntrinsicWidth(constraints); return _getIntrinsicWidth();
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
return _getIntrinsicWidth(constraints); return _getIntrinsicWidth();
} }
double _getIntrinsicHeight(BoxConstraints constraints) { double _getIntrinsicHeight() {
assert(constraints.debugAssertIsValid());
switch (mainAxis) { switch (mainAxis) {
case Axis.vertical: case Axis.vertical:
return constraints.constrainHeight(_preferredExtent); final double height = _preferredExtent;
if (height.isFinite)
return height;
assert(debugThrowIfNotCheckingIntrinsics());
return 0.0;
case Axis.horizontal: case Axis.horizontal:
return constraints.constrainHeight(0.0); assert(debugThrowIfNotCheckingIntrinsics());
return 0.0;
} }
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
return _getIntrinsicHeight(constraints); return _getIntrinsicHeight();
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
return _getIntrinsicHeight(constraints); return _getIntrinsicHeight();
} }
@override @override
......
...@@ -14,18 +14,6 @@ class RenderOffStage extends RenderBox with RenderObjectWithChildMixin<RenderBox ...@@ -14,18 +14,6 @@ class RenderOffStage extends RenderBox with RenderObjectWithChildMixin<RenderBox
this.child = child; this.child = child;
} }
@override
double getMinIntrinsicWidth(BoxConstraints constraints) => constraints.minWidth;
@override
double getMaxIntrinsicWidth(BoxConstraints constraints) => constraints.minWidth;
@override
double getMinIntrinsicHeight(BoxConstraints constraints) => constraints.minHeight;
@override
double getMaxIntrinsicHeight(BoxConstraints constraints) => constraints.minHeight;
@override @override
bool get sizedByParent => true; bool get sizedByParent => true;
......
...@@ -87,45 +87,43 @@ class RenderParagraph extends RenderBox { ...@@ -87,45 +87,43 @@ class RenderParagraph extends RenderBox {
markNeedsPaint(); markNeedsPaint();
} }
void _layoutText(BoxConstraints constraints) { void _layoutText({ double minWidth: 0.0, double maxWidth: double.INFINITY }) {
assert(constraints != null); _textPainter.layout(minWidth: minWidth, maxWidth: _softWrap ? maxWidth : double.INFINITY);
assert(constraints.debugAssertIsValid());
_textPainter.layout(minWidth: constraints.minWidth, maxWidth: _softWrap ? constraints.maxWidth : double.INFINITY);
} }
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
_layoutText(constraints); _layoutText();
return constraints.constrainWidth(_textPainter.minIntrinsicWidth); return _textPainter.minIntrinsicWidth;
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
_layoutText(constraints); _layoutText();
return constraints.constrainWidth(_textPainter.maxIntrinsicWidth); return _textPainter.maxIntrinsicWidth;
} }
double _getIntrinsicHeight(BoxConstraints constraints) { double _getIntrinsicHeight(double width) {
_layoutText(constraints); _layoutText(minWidth: width, maxWidth: width);
return constraints.constrainHeight(_textPainter.height); return _textPainter.height;
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); return _getIntrinsicHeight(width);
return _getIntrinsicHeight(constraints);
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); return _getIntrinsicHeight(width);
return _getIntrinsicHeight(constraints);
} }
@override @override
double computeDistanceToActualBaseline(TextBaseline baseline) { double computeDistanceToActualBaseline(TextBaseline baseline) {
assert(!needsLayout); assert(!needsLayout);
_layoutText(constraints); assert(constraints != null);
assert(constraints.debugAssertIsValid());
_layoutText(minWidth: constraints.minWidth, maxWidth: constraints.maxWidth);
return _textPainter.computeDistanceToActualBaseline(baseline); return _textPainter.computeDistanceToActualBaseline(baseline);
} }
...@@ -136,7 +134,7 @@ class RenderParagraph extends RenderBox { ...@@ -136,7 +134,7 @@ class RenderParagraph extends RenderBox {
void handleEvent(PointerEvent event, BoxHitTestEntry entry) { void handleEvent(PointerEvent event, BoxHitTestEntry entry) {
if (event is! PointerDownEvent) if (event is! PointerDownEvent)
return; return;
_layoutText(constraints); _layoutText(minWidth: constraints.minWidth, maxWidth: constraints.maxWidth);
Offset offset = entry.localPosition.toOffset(); Offset offset = entry.localPosition.toOffset();
TextPosition position = _textPainter.getPositionForOffset(offset); TextPosition position = _textPainter.getPositionForOffset(offset);
TextSpan span = _textPainter.text.getSpanForPosition(position); TextSpan span = _textPainter.text.getSpanForPosition(position);
...@@ -149,7 +147,7 @@ class RenderParagraph extends RenderBox { ...@@ -149,7 +147,7 @@ class RenderParagraph extends RenderBox {
@override @override
void performLayout() { void performLayout() {
_layoutText(constraints); _layoutText(minWidth: constraints.minWidth, maxWidth: constraints.maxWidth);
size = constraints.constrain(_textPainter.size); size = constraints.constrain(_textPainter.size);
final bool didOverflowWidth = size.width < _textPainter.width; final bool didOverflowWidth = size.width < _textPainter.width;
...@@ -200,7 +198,7 @@ class RenderParagraph extends RenderBox { ...@@ -200,7 +198,7 @@ class RenderParagraph extends RenderBox {
// //
// If you remove this call, make sure that changing the textAlign still // If you remove this call, make sure that changing the textAlign still
// works properly. // works properly.
_layoutText(constraints); _layoutText(minWidth: constraints.minWidth, maxWidth: constraints.maxWidth);
final Canvas canvas = context.canvas; final Canvas canvas = context.canvas;
if (_hasVisualOverflow) { if (_hasVisualOverflow) {
final Rect bounds = offset & size; final Rect bounds = offset & size;
......
...@@ -97,13 +97,13 @@ class RenderPerformanceOverlay extends RenderBox { ...@@ -97,13 +97,13 @@ class RenderPerformanceOverlay extends RenderBox {
bool get alwaysNeedsCompositing => true; bool get alwaysNeedsCompositing => true;
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
return constraints.constrainWidth(0.0); return 0.0;
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
return constraints.constrainWidth(0.0); return 0.0;
} }
double get _intrinsicHeight { double get _intrinsicHeight {
...@@ -119,13 +119,13 @@ class RenderPerformanceOverlay extends RenderBox { ...@@ -119,13 +119,13 @@ class RenderPerformanceOverlay extends RenderBox {
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
return constraints.constrainHeight(_intrinsicHeight); return _intrinsicHeight;
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
return constraints.constrainHeight(_intrinsicHeight); return _intrinsicHeight;
} }
@override @override
......
...@@ -42,35 +42,31 @@ class RenderProxyBox extends RenderBox with RenderObjectWithChildMixin<RenderBox ...@@ -42,35 +42,31 @@ class RenderProxyBox extends RenderBox with RenderObjectWithChildMixin<RenderBox
} }
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid());
if (child != null) if (child != null)
return child.getMinIntrinsicWidth(constraints); return child.getMinIntrinsicWidth(height);
return super.getMinIntrinsicWidth(constraints); return 0.0;
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid());
if (child != null) if (child != null)
return child.getMaxIntrinsicWidth(constraints); return child.getMaxIntrinsicWidth(height);
return super.getMaxIntrinsicWidth(constraints); return 0.0;
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid());
if (child != null) if (child != null)
return child.getMinIntrinsicHeight(constraints); return child.getMinIntrinsicHeight(width);
return super.getMinIntrinsicHeight(constraints); return 0.0;
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid());
if (child != null) if (child != null)
return child.getMaxIntrinsicHeight(constraints); return child.getMaxIntrinsicHeight(width);
return super.getMaxIntrinsicHeight(constraints); return 0.0;
} }
@override @override
...@@ -199,35 +195,35 @@ class RenderConstrainedBox extends RenderProxyBox { ...@@ -199,35 +195,35 @@ class RenderConstrainedBox extends RenderProxyBox {
} }
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid()); final double width = super.getMinIntrinsicWidth(height);
if (child != null) if (_additionalConstraints.hasBoundedWidth)
return child.getMinIntrinsicWidth(_additionalConstraints.enforce(constraints)); return _additionalConstraints.constrainWidth(width);
return _additionalConstraints.enforce(constraints).constrainWidth(0.0); return width;
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid()); final double width = super.getMaxIntrinsicWidth(height);
if (child != null) if (_additionalConstraints.hasBoundedWidth)
return child.getMaxIntrinsicWidth(_additionalConstraints.enforce(constraints)); return _additionalConstraints.constrainWidth(width);
return _additionalConstraints.enforce(constraints).constrainWidth(0.0); return width;
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); final double height = super.getMinIntrinsicHeight(width);
if (child != null) if (_additionalConstraints.hasBoundedHeight)
return child.getMinIntrinsicHeight(_additionalConstraints.enforce(constraints)); return _additionalConstraints.constrainHeight(height);
return _additionalConstraints.enforce(constraints).constrainHeight(0.0); return height;
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); final double height = super.getMaxIntrinsicHeight(width);
if (child != null) if (_additionalConstraints.hasBoundedHeight)
return child.getMaxIntrinsicHeight(_additionalConstraints.enforce(constraints)); return _additionalConstraints.constrainHeight(height);
return _additionalConstraints.enforce(constraints).constrainHeight(0.0); return height;
} }
@override @override
...@@ -309,38 +305,6 @@ class RenderLimitedBox extends RenderProxyBox { ...@@ -309,38 +305,6 @@ class RenderLimitedBox extends RenderProxyBox {
); );
} }
@override
double getMinIntrinsicWidth(BoxConstraints constraints) {
assert(constraints.debugAssertIsValid());
if (child != null)
return child.getMinIntrinsicWidth(_limitConstraints(constraints));
return _limitConstraints(constraints).constrainWidth(0.0);
}
@override
double getMaxIntrinsicWidth(BoxConstraints constraints) {
assert(constraints.debugAssertIsValid());
if (child != null)
return child.getMaxIntrinsicWidth(_limitConstraints(constraints));
return _limitConstraints(constraints).constrainWidth(0.0);
}
@override
double getMinIntrinsicHeight(BoxConstraints constraints) {
assert(constraints.debugAssertIsValid());
if (child != null)
return child.getMinIntrinsicHeight(_limitConstraints(constraints));
return _limitConstraints(constraints).constrainHeight(0.0);
}
@override
double getMaxIntrinsicHeight(BoxConstraints constraints) {
assert(constraints.debugAssertIsValid());
if (child != null)
return child.getMaxIntrinsicHeight(_limitConstraints(constraints));
return _limitConstraints(constraints).constrainHeight(0.0);
}
@override @override
void performLayout() { void performLayout() {
if (child != null) { if (child != null) {
...@@ -417,27 +381,39 @@ class RenderAspectRatio extends RenderProxyBox { ...@@ -417,27 +381,39 @@ class RenderAspectRatio extends RenderProxyBox {
} }
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid()); if (height.isFinite)
return constraints.minWidth; return height * _aspectRatio;
if (child != null)
return child.getMinIntrinsicWidth(height);
return 0.0;
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid()); if (height.isFinite)
return constraints.constrainWidth(constraints.maxHeight * aspectRatio); return height * _aspectRatio;
if (child != null)
return child.getMaxIntrinsicWidth(height);
return 0.0;
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); if (width.isFinite)
return constraints.minHeight; return width / _aspectRatio;
if (child != null)
return child.getMinIntrinsicHeight(width);
return 0.0;
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); if (width.isFinite)
return constraints.constrainHeight(constraints.maxWidth / aspectRatio); return width / _aspectRatio;
if (child != null)
return child.getMaxIntrinsicHeight(width);
return 0.0;
} }
Size _applyAspectRatio(BoxConstraints constraints) { Size _applyAspectRatio(BoxConstraints constraints) {
...@@ -563,53 +539,50 @@ class RenderIntrinsicWidth extends RenderProxyBox { ...@@ -563,53 +539,50 @@ class RenderIntrinsicWidth extends RenderProxyBox {
assert(child != null); assert(child != null);
if (constraints.hasTightWidth) if (constraints.hasTightWidth)
return constraints; return constraints;
double width = child.getMaxIntrinsicWidth(constraints); final double width = child.getMaxIntrinsicWidth(constraints.maxHeight);
assert(width == constraints.constrainWidth(width)); assert(width == constraints.constrainWidth(width));
return constraints.tighten(width: _applyStep(width, _stepWidth)); return constraints.tighten(width: _applyStep(width, _stepWidth));
} }
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid()); return getMaxIntrinsicWidth(height);
return getMaxIntrinsicWidth(constraints);
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid());
if (child == null) if (child == null)
return constraints.constrainWidth(0.0); return 0.0;
double childResult = child.getMaxIntrinsicWidth(constraints); double childResult = child.getMaxIntrinsicWidth(height);
assert(!childResult.isInfinite); assert(!childResult.isInfinite);
return constraints.constrainWidth(_applyStep(childResult, _stepWidth)); return _applyStep(childResult, _stepWidth);
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid());
if (child == null) if (child == null)
return constraints.constrainHeight(0.0); return 0.0;
double childResult = child.getMinIntrinsicHeight(_getInnerConstraints(constraints)); double childResult = child.getMinIntrinsicHeight(_getInnerConstraints(new BoxConstraints.tightForFinite(width: width)).maxWidth);
assert(!childResult.isInfinite); assert(childResult.isFinite);
return constraints.constrainHeight(_applyStep(childResult, _stepHeight)); return _applyStep(childResult, _stepHeight);
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid());
if (child == null) if (child == null)
return constraints.constrainHeight(0.0); return 0.0;
double childResult = child.getMaxIntrinsicHeight(_getInnerConstraints(constraints)); double childResult = child.getMaxIntrinsicHeight(_getInnerConstraints(new BoxConstraints.tightForFinite(width: width)).maxWidth);
assert(!childResult.isInfinite); assert(childResult.isFinite);
return constraints.constrainHeight(_applyStep(childResult, _stepHeight)); return _applyStep(childResult, _stepHeight);
} }
@override @override
void performLayout() { void performLayout() {
if (child != null) { if (child != null) {
BoxConstraints childConstraints = _getInnerConstraints(constraints); BoxConstraints childConstraints = _getInnerConstraints(constraints);
assert(childConstraints.hasTightWidth);
if (_stepHeight != null) if (_stepHeight != null)
childConstraints.tighten(height: getMaxIntrinsicHeight(childConstraints)); childConstraints.tighten(height: getMaxIntrinsicHeight(childConstraints.maxWidth));
child.layout(childConstraints, parentUsesSize: true); child.layout(childConstraints, parentUsesSize: true);
size = child.size; size = child.size;
} else { } else {
...@@ -642,39 +615,28 @@ class RenderIntrinsicHeight extends RenderProxyBox { ...@@ -642,39 +615,28 @@ class RenderIntrinsicHeight extends RenderProxyBox {
assert(child != null); assert(child != null);
if (constraints.hasTightHeight) if (constraints.hasTightHeight)
return constraints; return constraints;
double height = child.getMaxIntrinsicHeight(constraints); final double height = child.getMaxIntrinsicHeight(constraints.maxWidth);
assert(height == constraints.constrainHeight(height)); assert(height == constraints.constrainHeight(height));
return constraints.tighten(height: height); return constraints.tighten(height: height);
} }
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid());
if (child == null) if (child == null)
return constraints.constrainWidth(0.0); return 0.0;
return child.getMinIntrinsicWidth(_getInnerConstraints(constraints)); return child.getMinIntrinsicWidth(_getInnerConstraints(new BoxConstraints.tightForFinite(height: height)).maxHeight);
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid());
if (child == null) if (child == null)
return constraints.constrainWidth(0.0); return 0.0;
return child.getMaxIntrinsicWidth(_getInnerConstraints(constraints)); return child.getMaxIntrinsicWidth(_getInnerConstraints(new BoxConstraints.tightForFinite(height: height)).maxHeight);
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); return getMaxIntrinsicHeight(width);
return getMaxIntrinsicHeight(constraints);
}
@override
double getMaxIntrinsicHeight(BoxConstraints constraints) {
assert(constraints.debugAssertIsValid());
if (child == null)
return constraints.constrainHeight(0.0);
return child.getMaxIntrinsicHeight(constraints);
} }
@override @override
......
...@@ -43,35 +43,31 @@ class RenderRotatedBox extends RenderBox with RenderObjectWithChildMixin<RenderB ...@@ -43,35 +43,31 @@ class RenderRotatedBox extends RenderBox with RenderObjectWithChildMixin<RenderB
bool get _isVertical => quarterTurns % 2 == 1; bool get _isVertical => quarterTurns % 2 == 1;
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid()); if (child == null)
if (child != null) return 0.0;
return _isVertical ? child.getMinIntrinsicHeight(constraints.flipped) : child.getMinIntrinsicWidth(constraints); return _isVertical ? child.getMinIntrinsicHeight(height) : child.getMinIntrinsicWidth(height);
return super.getMinIntrinsicWidth(constraints);
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid()); if (child == null)
if (child != null) return 0.0;
return _isVertical ? child.getMaxIntrinsicHeight(constraints.flipped) : child.getMaxIntrinsicWidth(constraints); return _isVertical ? child.getMaxIntrinsicHeight(height) : child.getMaxIntrinsicWidth(height);
return super.getMaxIntrinsicWidth(constraints);
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); if (child == null)
if (child != null) return 0.0;
return _isVertical ? child.getMinIntrinsicWidth(constraints.flipped) : child.getMinIntrinsicHeight(constraints); return _isVertical ? child.getMinIntrinsicWidth(width) : child.getMinIntrinsicHeight(width);
return super.getMinIntrinsicHeight(constraints);
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); if (child == null)
if (child != null) return 0.0;
return _isVertical ? child.getMaxIntrinsicWidth(constraints.flipped) : child.getMaxIntrinsicHeight(constraints); return _isVertical ? child.getMaxIntrinsicWidth(width) : child.getMaxIntrinsicHeight(width);
return super.getMaxIntrinsicHeight(constraints);
} }
Matrix4 _paintTransform; Matrix4 _paintTransform;
......
...@@ -17,35 +17,31 @@ abstract class RenderShiftedBox extends RenderBox with RenderObjectWithChildMixi ...@@ -17,35 +17,31 @@ abstract class RenderShiftedBox extends RenderBox with RenderObjectWithChildMixi
} }
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid());
if (child != null) if (child != null)
return child.getMinIntrinsicWidth(constraints); return child.getMinIntrinsicWidth(height);
return super.getMinIntrinsicWidth(constraints); return 0.0;
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid());
if (child != null) if (child != null)
return child.getMaxIntrinsicWidth(constraints); return child.getMaxIntrinsicWidth(height);
return super.getMaxIntrinsicWidth(constraints); return 0.0;
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid());
if (child != null) if (child != null)
return child.getMinIntrinsicHeight(constraints); return child.getMinIntrinsicHeight(width);
return super.getMinIntrinsicHeight(constraints); return 0.0;
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid());
if (child != null) if (child != null)
return child.getMaxIntrinsicHeight(constraints); return child.getMaxIntrinsicHeight(width);
return super.getMaxIntrinsicHeight(constraints); return 0.0;
} }
@override @override
...@@ -115,39 +111,39 @@ class RenderPadding extends RenderShiftedBox { ...@@ -115,39 +111,39 @@ class RenderPadding extends RenderShiftedBox {
} }
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid()); final double totalHorizontalPadding = padding.left + padding.right;
double totalPadding = padding.left + padding.right; final double totalVerticalPadding = padding.top + padding.bottom;
if (child != null) if (child != null) // next line relies on double.INFINITY absorption
return constraints.constrainWidth(child.getMinIntrinsicWidth(constraints.deflate(padding)) + totalPadding); return child.getMinIntrinsicWidth(height - totalVerticalPadding) + totalHorizontalPadding;
return constraints.constrainWidth(totalPadding); return totalHorizontalPadding;
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid()); final double totalHorizontalPadding = padding.left + padding.right;
double totalPadding = padding.left + padding.right; final double totalVerticalPadding = padding.top + padding.bottom;
if (child != null) if (child != null) // next line relies on double.INFINITY absorption
return constraints.constrainWidth(child.getMaxIntrinsicWidth(constraints.deflate(padding)) + totalPadding); return child.getMaxIntrinsicWidth(height - totalVerticalPadding) + totalHorizontalPadding;
return constraints.constrainWidth(totalPadding); return totalHorizontalPadding;
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); final double totalHorizontalPadding = padding.left + padding.right;
double totalPadding = padding.top + padding.bottom; final double totalVerticalPadding = padding.top + padding.bottom;
if (child != null) if (child != null) // next line relies on double.INFINITY absorption
return constraints.constrainHeight(child.getMinIntrinsicHeight(constraints.deflate(padding)) + totalPadding); return child.getMinIntrinsicHeight(width - totalHorizontalPadding) + totalVerticalPadding;
return constraints.constrainHeight(totalPadding); return totalVerticalPadding;
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); final double totalHorizontalPadding = padding.left + padding.right;
double totalPadding = padding.top + padding.bottom; final double totalVerticalPadding = padding.top + padding.bottom;
if (child != null) if (child != null) // next line relies on double.INFINITY absorption
return constraints.constrainHeight(child.getMaxIntrinsicHeight(constraints.deflate(padding)) + totalPadding); return child.getMaxIntrinsicHeight(width - totalHorizontalPadding) + totalVerticalPadding;
return constraints.constrainHeight(totalPadding); return totalVerticalPadding;
} }
@override @override
...@@ -502,30 +498,6 @@ class RenderConstrainedOverflowBox extends RenderAligningShiftedBox { ...@@ -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 @override
bool get sizedByParent => true; bool get sizedByParent => true;
...@@ -579,27 +551,23 @@ class RenderSizedOverflowBox extends RenderAligningShiftedBox { ...@@ -579,27 +551,23 @@ class RenderSizedOverflowBox extends RenderAligningShiftedBox {
} }
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid()); return _requestedSize.width;
return constraints.constrainWidth(_requestedSize.width);
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid()); return _requestedSize.width;
return constraints.constrainWidth(_requestedSize.width);
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); return _requestedSize.height;
return constraints.constrainHeight(_requestedSize.height);
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); return _requestedSize.height;
return constraints.constrainHeight(_requestedSize.height);
} }
@override @override
...@@ -699,35 +667,51 @@ class RenderFractionallySizedOverflowBox extends RenderAligningShiftedBox { ...@@ -699,35 +667,51 @@ class RenderFractionallySizedOverflowBox extends RenderAligningShiftedBox {
} }
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid()); double result;
if (child != null) if (child == null) {
return constraints.constrainWidth(child.getMinIntrinsicWidth(_getInnerConstraints(constraints))); result = super.getMinIntrinsicWidth(height);
return constraints.constrainWidth(_getInnerConstraints(constraints).constrainWidth(0.0)); } 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 @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid()); double result;
if (child != null) if (child == null) {
return constraints.constrainWidth(child.getMaxIntrinsicWidth(_getInnerConstraints(constraints))); result = super.getMaxIntrinsicWidth(height);
return constraints.constrainWidth(_getInnerConstraints(constraints).constrainWidth(0.0)); } 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 @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); double result;
if (child != null) if (child == null) {
return constraints.constrainHeight(child.getMinIntrinsicHeight(_getInnerConstraints(constraints))); result = super.getMinIntrinsicHeight(width);
return constraints.constrainHeight(_getInnerConstraints(constraints).constrainHeight(0.0)); } 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 @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); double result;
if (child != null) if (child == null) {
return constraints.constrainHeight(child.getMaxIntrinsicHeight(_getInnerConstraints(constraints))); result = super.getMaxIntrinsicHeight(width);
return constraints.constrainHeight(_getInnerConstraints(constraints).constrainHeight(0.0)); } 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 @override
...@@ -797,28 +781,40 @@ class RenderCustomSingleChildLayoutBox extends RenderShiftedBox { ...@@ -797,28 +781,40 @@ class RenderCustomSingleChildLayoutBox extends RenderShiftedBox {
return constraints.constrain(_delegate.getSize(constraints)); 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 @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid()); final double width = _getSize(new BoxConstraints.tightForFinite(height: height)).width;
return _getSize(constraints).width; if (width.isFinite)
return width;
return 0.0;
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid()); final double width = _getSize(new BoxConstraints.tightForFinite(height: height)).width;
return _getSize(constraints).width; if (width.isFinite)
return width;
return 0.0;
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); final double height = _getSize(new BoxConstraints.tightForFinite(width: width)).height;
return _getSize(constraints).height; if (height.isFinite)
return height;
return 0.0;
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); final double height = _getSize(new BoxConstraints.tightForFinite(width: width)).height;
return _getSize(constraints).height; if (height.isFinite)
return height;
return 0.0;
} }
@override @override
......
...@@ -224,78 +224,37 @@ abstract class RenderStackBase extends RenderBox ...@@ -224,78 +224,37 @@ abstract class RenderStackBase extends RenderBox
} }
} }
@override double _getIntrinsicDimension(double mainChildSizeGetter(RenderBox child)) {
double getMinIntrinsicWidth(BoxConstraints constraints) { double extent = 0.0;
assert(constraints.debugAssertIsValid());
double width = constraints.minWidth;
RenderBox child = firstChild; RenderBox child = firstChild;
while (child != null) { while (child != null) {
final StackParentData childParentData = child.parentData; final StackParentData childParentData = child.parentData;
if (!childParentData.isPositioned) if (!childParentData.isPositioned)
width = math.max(width, child.getMinIntrinsicWidth(constraints)); extent = math.max(extent, mainChildSizeGetter(child));
assert(child.parentData == childParentData); assert(child.parentData == childParentData);
child = childParentData.nextSibling; child = childParentData.nextSibling;
} }
assert(width == constraints.constrainWidth(width)); return extent;
return width;
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid()); return _getIntrinsicDimension((RenderBox child) => child.getMinIntrinsicWidth(height));
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;
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid()); return _getIntrinsicDimension((RenderBox child) => child.getMaxIntrinsicWidth(height));
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;
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); return _getIntrinsicDimension((RenderBox child) => child.getMinIntrinsicHeight(width));
bool hasNonPositionedChildren = false; }
double height = constraints.minHeight;
RenderBox child = firstChild; @override
while (child != null) { double getMaxIntrinsicHeight(double width) {
final StackParentData childParentData = child.parentData; return _getIntrinsicDimension((RenderBox child) => child.getMaxIntrinsicHeight(width));
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;
} }
@override @override
......
...@@ -82,7 +82,7 @@ class IntrinsicColumnWidth extends TableColumnWidth { ...@@ -82,7 +82,7 @@ class IntrinsicColumnWidth extends TableColumnWidth {
double minIntrinsicWidth(Iterable<RenderBox> cells, double containerWidth) { double minIntrinsicWidth(Iterable<RenderBox> cells, double containerWidth) {
double result = 0.0; double result = 0.0;
for (RenderBox cell in cells) for (RenderBox cell in cells)
result = math.max(result, cell.getMinIntrinsicWidth(const BoxConstraints())); result = math.max(result, cell.getMinIntrinsicWidth(double.INFINITY));
return result; return result;
} }
...@@ -90,7 +90,7 @@ class IntrinsicColumnWidth extends TableColumnWidth { ...@@ -90,7 +90,7 @@ class IntrinsicColumnWidth extends TableColumnWidth {
double maxIntrinsicWidth(Iterable<RenderBox> cells, double containerWidth) { double maxIntrinsicWidth(Iterable<RenderBox> cells, double containerWidth) {
double result = 0.0; double result = 0.0;
for (RenderBox cell in cells) for (RenderBox cell in cells)
result = math.max(result, cell.getMaxIntrinsicWidth(const BoxConstraints())); result = math.max(result, cell.getMaxIntrinsicWidth(double.INFINITY));
return result; return result;
} }
...@@ -689,36 +689,33 @@ class RenderTable extends RenderBox { ...@@ -689,36 +689,33 @@ class RenderTable extends RenderBox {
} }
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid());
assert(_children.length == rows * columns); assert(_children.length == rows * columns);
double totalMinWidth = 0.0; double totalMinWidth = 0.0;
for (int x = 0; x < columns; x += 1) { for (int x = 0; x < columns; x += 1) {
TableColumnWidth columnWidth = _columnWidths[x] ?? defaultColumnWidth; TableColumnWidth columnWidth = _columnWidths[x] ?? defaultColumnWidth;
Iterable<RenderBox> columnCells = column(x); Iterable<RenderBox> columnCells = column(x);
totalMinWidth += columnWidth.minIntrinsicWidth(columnCells, constraints.maxWidth); totalMinWidth += columnWidth.minIntrinsicWidth(columnCells, double.INFINITY);
} }
return constraints.constrainWidth(totalMinWidth); return totalMinWidth;
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid());
assert(_children.length == rows * columns); assert(_children.length == rows * columns);
double totalMaxWidth = 0.0; double totalMaxWidth = 0.0;
for (int x = 0; x < columns; x += 1) { for (int x = 0; x < columns; x += 1) {
TableColumnWidth columnWidth = _columnWidths[x] ?? defaultColumnWidth; TableColumnWidth columnWidth = _columnWidths[x] ?? defaultColumnWidth;
Iterable<RenderBox> columnCells = column(x); Iterable<RenderBox> columnCells = column(x);
totalMaxWidth += columnWidth.maxIntrinsicWidth(columnCells, constraints.maxWidth); totalMaxWidth += columnWidth.maxIntrinsicWidth(columnCells, double.INFINITY);
} }
return constraints.constrainWidth(totalMaxWidth); return totalMaxWidth;
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
// winner of the 2016 world's most expensive intrinsic dimension function award // winner of the 2016 world's most expensive intrinsic dimension function award
// honorable mention, most likely to improve if taught about memoization award // honorable mention, most likely to improve if taught about memoization award
assert(constraints.debugAssertIsValid());
assert(_children.length == rows * columns); assert(_children.length == rows * columns);
final List<double> widths = _computeColumnWidths(constraints); final List<double> widths = _computeColumnWidths(constraints);
double rowTop = 0.0; double rowTop = 0.0;
...@@ -728,16 +725,16 @@ class RenderTable extends RenderBox { ...@@ -728,16 +725,16 @@ class RenderTable extends RenderBox {
final int xy = x + y * columns; final int xy = x + y * columns;
RenderBox child = _children[xy]; RenderBox child = _children[xy];
if (child != null) 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; rowTop += rowHeight;
} }
return constraints.constrainHeight(rowTop); return rowTop;
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
return getMinIntrinsicHeight(constraints); return getMinIntrinsicHeight(width);
} }
double _baselineDistance; double _baselineDistance;
......
...@@ -218,35 +218,31 @@ class RenderViewport extends RenderViewportBase with RenderObjectWithChildMixin< ...@@ -218,35 +218,31 @@ class RenderViewport extends RenderViewportBase with RenderObjectWithChildMixin<
} }
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid());
if (child != null) if (child != null)
return constraints.constrainWidth(child.getMinIntrinsicWidth(_getInnerConstraints(constraints))); return child.getMinIntrinsicWidth(height);
return super.getMinIntrinsicWidth(constraints); return 0.0;
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid());
if (child != null) if (child != null)
return constraints.constrainWidth(child.getMaxIntrinsicWidth(_getInnerConstraints(constraints))); return child.getMaxIntrinsicWidth(height);
return super.getMaxIntrinsicWidth(constraints); return 0.0;
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid());
if (child != null) if (child != null)
return constraints.constrainHeight(child.getMinIntrinsicHeight(_getInnerConstraints(constraints))); return child.getMinIntrinsicHeight(width);
return super.getMinIntrinsicHeight(constraints); return 0.0;
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid());
if (child != null) if (child != null)
return constraints.constrainHeight(child.getMaxIntrinsicHeight(_getInnerConstraints(constraints))); return child.getMaxIntrinsicHeight(width);
return super.getMaxIntrinsicHeight(constraints); return 0.0;
} }
// We don't override computeDistanceToActualBaseline(), because we // We don't override computeDistanceToActualBaseline(), because we
...@@ -353,6 +349,51 @@ abstract class RenderVirtualViewport<T extends ContainerBoxParentDataMixin<Rende ...@@ -353,6 +349,51 @@ abstract class RenderVirtualViewport<T extends ContainerBoxParentDataMixin<Rende
markNeedsLayout(); markNeedsLayout();
} }
/// Throws an exception if asserts are enabled, unless the
/// [RenderObject.debugCheckingIntrinsics] flag is set.
///
/// This is a convenience function for subclasses to call from their
/// intrinsic-sizing functions if they don't have a good way to generate the
/// numbers.
bool debugThrowIfNotCheckingIntrinsics() {
assert(() {
if (!RenderObject.debugCheckingIntrinsics) {
throw new FlutterError(
'RenderVirtualViewport does not support returning intrinsic dimensions.\n'
'Calculating the intrinsic dimensions would require walking the entire '
'child list, which cannot reliably and efficiently be done for render '
'objects that potentially generate their child list during layout.'
);
}
return true;
});
return true;
}
@override
double getMinIntrinsicWidth(double height) {
assert(debugThrowIfNotCheckingIntrinsics);
return 0.0;
}
@override
double getMaxIntrinsicWidth(double height) {
assert(debugThrowIfNotCheckingIntrinsics);
return 0.0;
}
@override
double getMinIntrinsicHeight(double width) {
assert(debugThrowIfNotCheckingIntrinsics);
return 0.0;
}
@override
double getMaxIntrinsicHeight(double width) {
assert(debugThrowIfNotCheckingIntrinsics);
return 0.0;
}
@override @override
bool hitTestChildren(HitTestResult result, { Point position }) { bool hitTestChildren(HitTestResult result, { Point position }) {
return defaultHitTestChildren(result, position: position + -_effectivePaintOffset); return defaultHitTestChildren(result, position: position + -_effectivePaintOffset);
......
...@@ -44,32 +44,42 @@ class _RenderLayoutBuilder extends RenderBox with RenderObjectWithChildMixin<Ren ...@@ -44,32 +44,42 @@ class _RenderLayoutBuilder extends RenderBox with RenderObjectWithChildMixin<Ren
markNeedsLayout(); markNeedsLayout();
} }
double getIntrinsicWidth(BoxConstraints constraints) => constraints.constrainWidth(); bool _debugThrowIfNotCheckingIntrinsics() {
assert(() {
double getIntrinsicHeight(BoxConstraints constraints) => constraints.constrainHeight(); 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 @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid()); assert(_debugThrowIfNotCheckingIntrinsics());
return getIntrinsicWidth(constraints); return 0.0;
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid()); assert(_debugThrowIfNotCheckingIntrinsics());
return getIntrinsicWidth(constraints); return 0.0;
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); assert(_debugThrowIfNotCheckingIntrinsics());
return getIntrinsicHeight(constraints); return 0.0;
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); assert(_debugThrowIfNotCheckingIntrinsics());
return getIntrinsicHeight(constraints); return 0.0;
} }
@override @override
...@@ -85,7 +95,7 @@ class _RenderLayoutBuilder extends RenderBox with RenderObjectWithChildMixin<Ren ...@@ -85,7 +95,7 @@ class _RenderLayoutBuilder extends RenderBox with RenderObjectWithChildMixin<Ren
if (callback != null) if (callback != null)
invokeLayoutCallback(callback); invokeLayoutCallback(callback);
if (child != null) if (child != null)
child.layout(constraints.loosen(), parentUsesSize: false); child.layout(constraints.loosen());
} }
@override @override
......
...@@ -368,48 +368,28 @@ class _RenderLazyBlock extends RenderVirtualViewport<_LazyBlockParentData> { ...@@ -368,48 +368,28 @@ class _RenderLazyBlock extends RenderVirtualViewport<_LazyBlockParentData> {
return true; 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 @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid()); assert(_debugThrowIfNotCheckingIntrinsics());
return getIntrinsicWidth(constraints); return 0.0;
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
assert(constraints.debugAssertIsValid()); assert(_debugThrowIfNotCheckingIntrinsics());
return getIntrinsicWidth(constraints); return 0.0;
}
double getIntrinsicHeight(BoxConstraints constraints) {
switch (mainAxis) {
case Axis.horizontal:
return constraints.constrainHeight(0.0);
case Axis.vertical:
assert(_debugThrowIfNotCheckingIntrinsics());
return constraints.constrainHeight(0.0);
}
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); assert(_debugThrowIfNotCheckingIntrinsics());
return getIntrinsicHeight(constraints); return 0.0;
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
assert(constraints.debugAssertIsValid()); assert(_debugThrowIfNotCheckingIntrinsics());
return getIntrinsicHeight(constraints); return 0.0;
} }
@override @override
......
...@@ -4,21 +4,96 @@ ...@@ -4,21 +4,96 @@
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'rendering_tester.dart';
void main() { void main() {
test('Intrinsic sizing', () { test('Intrinsic sizing 2.0', () {
RenderAspectRatio box = new RenderAspectRatio(aspectRatio: 2.0); RenderAspectRatio box = new RenderAspectRatio(aspectRatio: 2.0);
BoxConstraints constraints = new BoxConstraints.loose(new Size(200.0, 200.0)); expect(box.getMinIntrinsicWidth(200.0), 400.0);
expect(box.getMinIntrinsicWidth(constraints), equals(0.0)); expect(box.getMinIntrinsicWidth(400.0), 800.0);
expect(box.getMaxIntrinsicWidth(constraints), equals(200.0));
expect(box.getMinIntrinsicHeight(constraints), equals(0.0)); expect(box.getMaxIntrinsicWidth(200.0), 400.0);
expect(box.getMaxIntrinsicHeight(constraints), equals(100.0)); expect(box.getMaxIntrinsicWidth(400.0), 800.0);
constraints = new BoxConstraints(maxHeight: 400.0); expect(box.getMinIntrinsicHeight(200.0), 100.0);
expect(box.getMinIntrinsicWidth(constraints), equals(0.0)); expect(box.getMinIntrinsicHeight(400.0), 200.0);
expect(box.getMaxIntrinsicWidth(constraints), equals(800.0));
expect(box.getMinIntrinsicHeight(constraints), equals(0.0)); expect(box.getMaxIntrinsicHeight(200.0), 100.0);
expect(box.getMaxIntrinsicHeight(constraints), equals(400.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);
}); });
} }
// 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: <RenderBox>[
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));
});
}
...@@ -35,10 +35,10 @@ void main() { ...@@ -35,10 +35,10 @@ void main() {
BoxConstraints viewport = new BoxConstraints(maxHeight: 100.0, maxWidth: 100.0); BoxConstraints viewport = new BoxConstraints(maxHeight: 100.0, maxWidth: 100.0);
layout(flex, constraints: viewport); layout(flex, constraints: viewport);
expect(flexible.size.height, equals(0.0)); expect(flexible.size.height, equals(0.0));
expect(flex.getMinIntrinsicHeight(viewport), equals(100.0)); expect(flex.getMinIntrinsicHeight(100.0), equals(200.0));
expect(flex.getMaxIntrinsicHeight(viewport), equals(100.0)); expect(flex.getMaxIntrinsicHeight(100.0), equals(200.0));
expect(flex.getMinIntrinsicWidth(viewport), equals(100.0)); expect(flex.getMinIntrinsicWidth(100.0), equals(0.0));
expect(flex.getMaxIntrinsicWidth(viewport), equals(100.0)); expect(flex.getMaxIntrinsicWidth(100.0), equals(0.0));
}); });
test('Horizontal Overflow', () { test('Horizontal Overflow', () {
...@@ -57,10 +57,10 @@ void main() { ...@@ -57,10 +57,10 @@ void main() {
BoxConstraints viewport = new BoxConstraints(maxHeight: 100.0, maxWidth: 100.0); BoxConstraints viewport = new BoxConstraints(maxHeight: 100.0, maxWidth: 100.0);
layout(flex, constraints: viewport); layout(flex, constraints: viewport);
expect(flexible.size.width, equals(0.0)); expect(flexible.size.width, equals(0.0));
expect(flex.getMinIntrinsicHeight(viewport), equals(100.0)); expect(flex.getMinIntrinsicHeight(100.0), equals(0.0));
expect(flex.getMaxIntrinsicHeight(viewport), equals(100.0)); expect(flex.getMaxIntrinsicHeight(100.0), equals(0.0));
expect(flex.getMinIntrinsicWidth(viewport), equals(100.0)); expect(flex.getMinIntrinsicWidth(100.0), equals(200.0));
expect(flex.getMaxIntrinsicWidth(viewport), equals(100.0)); expect(flex.getMaxIntrinsicWidth(100.0), equals(200.0));
}); });
test('Vertical Flipped Constraints', () { test('Vertical Flipped Constraints', () {
...@@ -72,7 +72,7 @@ void main() { ...@@ -72,7 +72,7 @@ void main() {
); );
BoxConstraints viewport = new BoxConstraints(maxHeight: 200.0, maxWidth: 1000.0); BoxConstraints viewport = new BoxConstraints(maxHeight: 200.0, maxWidth: 1000.0);
layout(flex, constraints: viewport); 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 // We can't right a horizontal version of the above test due to
......
...@@ -7,29 +7,30 @@ import 'package:test/test.dart'; ...@@ -7,29 +7,30 @@ import 'package:test/test.dart';
import 'rendering_tester.dart'; import 'rendering_tester.dart';
// before using this, consider using RenderSizedBox from rendering_tester.dart
class RenderTestBox extends RenderBox { class RenderTestBox extends RenderBox {
RenderTestBox(this._intrinsicDimensions); RenderTestBox(this._intrinsicDimensions);
final BoxConstraints _intrinsicDimensions; final BoxConstraints _intrinsicDimensions;
@override @override
double getMinIntrinsicWidth(BoxConstraints constraints) { double getMinIntrinsicWidth(double height) {
return constraints.constrainWidth(_intrinsicDimensions.minWidth); return _intrinsicDimensions.minWidth;
} }
@override @override
double getMaxIntrinsicWidth(BoxConstraints constraints) { double getMaxIntrinsicWidth(double height) {
return constraints.constrainWidth(_intrinsicDimensions.maxWidth); return _intrinsicDimensions.maxWidth;
} }
@override @override
double getMinIntrinsicHeight(BoxConstraints constraints) { double getMinIntrinsicHeight(double width) {
return constraints.constrainHeight(_intrinsicDimensions.minHeight); return _intrinsicDimensions.minHeight;
} }
@override @override
double getMaxIntrinsicHeight(BoxConstraints constraints) { double getMaxIntrinsicHeight(double width) {
return constraints.constrainHeight(_intrinsicDimensions.maxHeight); return _intrinsicDimensions.maxHeight;
} }
@override @override
......
// 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: <RenderBox>[
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));
});
}
...@@ -91,7 +91,33 @@ class RenderSizedBox extends RenderBox { ...@@ -91,7 +91,33 @@ class RenderSizedBox extends RenderBox {
final Size _size; final Size _size;
@override @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); size = constraints.constrain(_size);
} }
@override
void performLayout() { }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment