Chromium Code Reviews| Index: sky/sdk/lib/framework/rendering/flex.dart |
| diff --git a/sky/sdk/lib/framework/rendering/flex.dart b/sky/sdk/lib/framework/rendering/flex.dart |
| index 683d94786872da404f9be4aeeda6b9016cd31b85..bc4e0ee621590cf4654c317cd283f57e66306894 100644 |
| --- a/sky/sdk/lib/framework/rendering/flex.dart |
| +++ b/sky/sdk/lib/framework/rendering/flex.dart |
| @@ -27,6 +27,8 @@ enum FlexJustifyContent { |
| spaceAround, |
| } |
| +typedef double ChildSizingFunction(RenderBox child, BoxConstraints constraints); |
|
abarth-chromium
2015/06/10 04:23:20
_ChildSizingFunction
The _ scopes the definition
jackson
2015/06/10 04:44:46
Acknowledged.
kulakowski
2015/06/10 16:07:14
Pedantry hopefully useful in the future: There is
|
| + |
| class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, FlexBoxParentData>, |
| RenderBoxContainerDefaultsMixin<RenderBox, FlexBoxParentData> { |
| // lays out RenderBox children using flexible layout |
| @@ -59,35 +61,170 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl |
| child.parentData = new FlexBoxParentData(); |
| } |
| - // We don't currently support this for RenderFlex |
| + double _getIntrinsicSize(BoxConstraints constraints, |
| + FlexDirection sizingDirection, |
| + ChildSizingFunction childSize) { |
| + // http://www.w3.org/TR/2015/WD-css-flexbox-1-20150514/#intrinsic-sizes |
| + if (_direction == sizingDirection) { |
| + // INTRINSIC MAIN SIZE |
| + // Intrinsic main size is the smallest size the flex container can take |
| + // 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 inflexibleSpace = 0.0; |
| + double maxFlexFractionSoFar = 0.0; |
| + RenderBox child = firstChild; |
| + while (child != null) { |
| + int flex = _getFlex(child); |
| + totalFlex += flex; |
| + if (flex > 0) { |
| + double flexFraction = childSize(child, childConstraints) / _getFlex(child); |
| + maxFlexFractionSoFar = math.max(maxFlexFractionSoFar, flexFraction); |
| + } else { |
| + inflexibleSpace += childSize(child, childConstraints); |
| + } |
| + child = child.parentData.nextSibling; |
| + } |
| + double mainSize = maxFlexFractionSoFar * totalFlex + inflexibleSpace; |
| + |
| + // Ensure that we don't violate the given constraints with our result |
| + switch(_direction) { |
| + case FlexDirection.horizontal: |
| + return constraints.constrainWidth(mainSize); |
| + case FlexDirection.vertical: |
| + return constraints.constrainHeight(mainSize); |
| + } |
| + } else { |
| + // INTRINSIC CROSS SIZE |
| + // The spec wants us to perform layout into the given available main-axis |
| + // space and return the cross size. That's too expensive, so instead we |
| + // size inflexible children according to their max intrinsic size in the |
| + // main direction and use those constraints to determine their max |
| + // intrinsic size in the cross direction. We don't care if the caller |
| + // asked for max or min -- the answer is always computed using the |
| + // max size in the main direction. |
| + |
| + double availableMainSpace; |
| + BoxConstraints childConstraints; |
| + switch(_direction) { |
| + case FlexDirection.horizontal: |
| + childConstraints = new BoxConstraints(maxWidth: constraints.maxWidth); |
| + availableMainSpace = innerConstraints.maxWidth; |
| + break; |
| + case FlexDirection.vertical: |
| + childConstraints = new BoxConstraints(maxHeight: constraints.maxHeight); |
| + availableMainSpace = innerConstraints.maxHeight; |
| + break; |
| + } |
| + |
| + // Get inflexible space using the max in the main direction |
| + int totalFlex = 0; |
| + double inflexibleSpace = 0.0; |
| + double maxCrossSize = 0.0; |
| + RenderBox child = firstChild; |
| + while (child != null) { |
| + int flex = _getFlex(child); |
| + totalFlex += flex; |
| + double mainSize; |
| + double crossSize; |
| + if (flex == 0) { |
| + switch (_direction) { |
| + case FlexDirection.horizontal: |
| + mainSize = child.getMaxIntrinsicWidth(childConstraints); |
| + BoxConstraints widthConstraints = |
| + new BoxConstraints(minWidth: mainSize, maxWidth: mainSize); |
| + crossSize = child.getMinIntrinsicHeight(widthConstraints); |
| + break; |
| + case FlexDirection.vertical: |
| + mainSize = child.getMaxIntrinsicHeight(childConstraints); |
| + BoxConstraints heightConstraints = |
| + new BoxConstraints(minWidth: mainSize, maxWidth: mainSize); |
| + crossSize = child.getMinIntrinsicWidth(heightConstraints); |
| + inflexibleSpace += mainSize; |
|
abarth-chromium
2015/06/10 04:23:20
Is this line missing from the other case?
jackson
2015/06/10 04:44:46
Acknowledged.
|
| + break; |
| + } |
| + inflexibleSpace += mainSize; |
|
abarth-chromium
2015/06/10 04:23:20
Wait, it seems like we're doing this twice in the
jackson
2015/06/10 04:44:46
Acknowledged.
|
| + maxCrossSize = math.max(maxCrossSize, crossSize); |
| + } |
| + child = child.parentData.nextSibling; |
| + } |
| + |
| + // Determine the spacePerFlex by allocating the remaining available space |
| + double spacePerFlex = (availableMainSpace - inflexibleSpace) / totalFlex; |
| + |
| + // Size remaining items, take the maximum |
| + child = firstChild; |
| + while (child != null) { |
| + int flex = _getFlex(child); |
| + if (flex > 0) { |
| + double childMainSize = spacePerFlex * flex; |
| + double crossSize; |
| + switch (_direction) { |
| + case FlexDirection.horizontal: |
| + BoxConstraints childConstraints = |
| + new BoxConstraints(minWidth: childMainSize, maxWidth: childMainSize); |
| + crossSize = child.getMaxIntrinsicHeight(childConstraints); |
|
abarth-chromium
2015/06/10 04:23:20
It's odd that we use getMaxIntrinsicHeight here bu
jackson
2015/06/10 04:44:46
Acknowledged.
|
| + maxCrossSize = math.max(maxCrossSize, crossSize); |
| + break; |
| + case FlexDirection.vertical: |
| + BoxConstraints childConstraints = |
| + new BoxConstraints(minHeight: childMainSize, maxHeight: childMainSize); |
| + crossSize = child.getMaxIntrinsicWidth(childConstraints); |
| + break; |
| + } |
| + maxCrossSize = math.max(maxCrossSize, crossSize); |
|
abarth-chromium
2015/06/10 04:23:20
Again, we seem to have the problem with this line
jackson
2015/06/10 04:44:46
Acknowledged.
|
| + } |
| + child = child.parentData.nextSibling; |
| + } |
| + |
| + // Ensure that we don't violate the given constraints with our result |
| + switch(_direction) { |
| + case FlexDirection.horizontal: |
| + return innerConstraints.constrainHeight(maxCrossSize); |
| + case FlexDirection.vertical: |
| + return innerConstraints.constrainWidth(maxCrossSize); |
| + } |
| + } |
| + } |
| + |
| double getMinIntrinsicWidth(BoxConstraints constraints) { |
| - assert(false); |
| - return constraints.constrainWidth(0.0); |
| + return _getIntrinsicSize( |
| + constraints, |
| + FlexDirection.horizontal, |
|
abarth-chromium
2015/06/10 04:23:20
Shouldn't we use the flex direction of the contain
jackson
2015/06/10 04:44:46
This argument (sizingDirection) is compared with t
abarth-chromium
2015/06/10 04:52:07
Ah, I see. I think it's fine this way. Another c
|
| + (c, innerConstraints) => c.getMinIntrinsicWidth(innerConstraints) |
| + ); |
| } |
| - // We don't currently support this for RenderFlex |
| double getMaxIntrinsicWidth(BoxConstraints constraints) { |
| - assert(false); |
| - return constraints.constrainWidth(0.0); |
| + return _getIntrinsicSize( |
| + constraints, |
| + FlexDirection.horizontal, |
|
abarth-chromium
2015/06/10 04:23:20
ditto
|
| + (c, innerConstraints) => c.getMaxIntrinsicWidth(innerConstraints) |
| + ); |
| } |
| - // We don't currently support this for RenderFlex |
| double getMinIntrinsicHeight(BoxConstraints constraints) { |
| - assert(false); |
| - return constraints.constrainHeight(0.0); |
| + return _getIntrinsicSize( |
| + constraints, |
| + FlexDirection.vertical, |
|
abarth-chromium
2015/06/10 04:23:20
ditto
|
| + (c, innerConstraints) => c.getMinIntrinsicHeight(innerConstraints) |
| + ); |
| } |
| - // We don't currently support this for RenderFlex |
| double getMaxIntrinsicHeight(BoxConstraints constraints) { |
| - assert(false); |
| - return constraints.constrainHeight(0.0); |
| - } |
| - |
| - bool get sizedByParent => true; |
| - void performResize() { |
| - size = constraints.constrain(new Size(constraints.maxWidth, constraints.maxHeight)); |
| - assert(size.height < double.INFINITY); |
| - assert(size.width < double.INFINITY); |
| + return _getIntrinsicSize( |
| + constraints, |
| + FlexDirection.vertical, |
|
abarth-chromium
2015/06/10 04:23:20
ditto
|
| + (c, innerConstraints) => c.getMaxIntrinsicHeight(innerConstraints)); |
| } |
| int _getFlex(RenderBox child) { |
| @@ -101,7 +238,9 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl |
| int totalFlex = 0; |
| int totalChildren = 0; |
| assert(constraints != null); |
| - double freeSpace = (_direction == FlexDirection.horizontal) ? constraints.maxWidth : constraints.maxHeight; |
| + final double mainSize = (_direction == FlexDirection.horizontal) ? constraints.maxWidth : constraints.maxHeight; |
| + double crossSize = 0.0; // This will be determined after laying out the children |
| + double freeSpace = mainSize; |
| RenderBox child = firstChild; |
| while (child != null) { |
| totalChildren++; |
| @@ -131,15 +270,19 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl |
| innerConstraints = new BoxConstraints(maxHeight: constraints.maxHeight, |
| minWidth: spaceForChild, |
| maxWidth: spaceForChild); |
| + child.layout(innerConstraints, parentUsesSize: true); |
| + usedSpace += child.size.width; |
| + crossSize = math.max(crossSize, child.size.height); |
| break; |
| case FlexDirection.vertical: |
| innerConstraints = new BoxConstraints(minHeight: spaceForChild, |
| maxHeight: spaceForChild, |
| maxWidth: constraints.maxWidth); |
| + child.layout(innerConstraints, parentUsesSize: true); |
| + usedSpace += child.size.height; |
| + crossSize = math.max(crossSize, child.size.width); |
| break; |
| } |
| - child.layout(innerConstraints, parentUsesSize: true); |
| - usedSpace += _direction == FlexDirection.horizontal ? child.size.width : child.size.height; |
| } |
| child = child.parentData.nextSibling; |
| } |
| @@ -172,6 +315,15 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl |
| break; |
| } |
| + switch (_direction) { |
| + case FlexDirection.horizontal: |
| + size = constraints.constrain(new Size(mainSize, crossSize)); |
| + break; |
| + case FlexDirection.vertical: |
| + size = constraints.constrain(new Size(crossSize, mainSize)); |
| + break; |
| + } |
| + |
| // Position elements. For now, center the flex items in the cross direction |
| double mainDimPosition = leadingSpace; |
| child = firstChild; |