| 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..151689d251608d562de53be9416adc3b983e6512 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);
|
| +
|
| class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, FlexBoxParentData>,
|
| RenderBoxContainerDefaultsMixin<RenderBox, FlexBoxParentData> {
|
| // lays out RenderBox children using flexible layout
|
| @@ -59,35 +61,168 @@ 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.getMaxIntrinsicHeight(widthConstraints);
|
| + break;
|
| + case FlexDirection.vertical:
|
| + mainSize = child.getMaxIntrinsicHeight(childConstraints);
|
| + BoxConstraints heightConstraints =
|
| + new BoxConstraints(minWidth: mainSize, maxWidth: mainSize);
|
| + crossSize = child.getMaxIntrinsicWidth(heightConstraints);
|
| + break;
|
| + }
|
| + inflexibleSpace += mainSize;
|
| + 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, find the maximum cross size
|
| + 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);
|
| + break;
|
| + case FlexDirection.vertical:
|
| + BoxConstraints childConstraints =
|
| + new BoxConstraints(minHeight: childMainSize, maxHeight: childMainSize);
|
| + crossSize = child.getMaxIntrinsicWidth(childConstraints);
|
| + break;
|
| + }
|
| + maxCrossSize = math.max(maxCrossSize, crossSize);
|
| + }
|
| + 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: constraints,
|
| + sizingDirection: FlexDirection.horizontal,
|
| + childSize: (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: constraints,
|
| + sizingDirection: FlexDirection.horizontal,
|
| + childSize: (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: constraints,
|
| + sizingDirection: FlexDirection.vertical,
|
| + childSize: (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: constraints,
|
| + sizingDirection: FlexDirection.vertical,
|
| + childSize: (c, innerConstraints) => c.getMaxIntrinsicHeight(innerConstraints));
|
| }
|
|
|
| int _getFlex(RenderBox child) {
|
| @@ -101,7 +236,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 +268,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 +313,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;
|
|
|