Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1254)

Side by Side Diff: sky/sdk/lib/framework/rendering/flex.dart

Issue 1173493003: Extend Sky's RenderFlex with intrinsic sizes and compute cross-size height (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: fix bugs Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 import 'dart:math' as math; 5 import 'dart:math' as math;
6 import 'box.dart'; 6 import 'box.dart';
7 import 'object.dart'; 7 import 'object.dart';
8 8
9 class FlexBoxParentData extends BoxParentData with ContainerParentDataMixin<Rend erBox> { 9 class FlexBoxParentData extends BoxParentData with ContainerParentDataMixin<Rend erBox> {
10 int flex; 10 int flex;
11 11
12 void merge(FlexBoxParentData other) { 12 void merge(FlexBoxParentData other) {
13 if (other.flex != null) 13 if (other.flex != null)
14 flex = other.flex; 14 flex = other.flex;
15 super.merge(other); 15 super.merge(other);
16 } 16 }
17 17
18 String toString() => '${super.toString()}; flex=$flex'; 18 String toString() => '${super.toString()}; flex=$flex';
19 } 19 }
20 20
21 enum FlexDirection { horizontal, vertical } 21 enum FlexDirection { horizontal, vertical }
22 enum FlexJustifyContent { 22 enum FlexJustifyContent {
23 flexStart, 23 flexStart,
24 flexEnd, 24 flexEnd,
25 center, 25 center,
26 spaceBetween, 26 spaceBetween,
27 spaceAround, 27 spaceAround,
28 } 28 }
29 29
30 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
31
30 class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl exBoxParentData>, 32 class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl exBoxParentData>,
31 RenderBoxContainerDefaultsMixin<RenderBo x, FlexBoxParentData> { 33 RenderBoxContainerDefaultsMixin<RenderBo x, FlexBoxParentData> {
32 // lays out RenderBox children using flexible layout 34 // lays out RenderBox children using flexible layout
33 35
34 RenderFlex({ 36 RenderFlex({
35 FlexDirection direction: FlexDirection.horizontal, 37 FlexDirection direction: FlexDirection.horizontal,
36 FlexJustifyContent justifyContent: FlexJustifyContent.flexStart 38 FlexJustifyContent justifyContent: FlexJustifyContent.flexStart
37 }) : _direction = direction, _justifyContent = justifyContent; 39 }) : _direction = direction, _justifyContent = justifyContent;
38 40
39 FlexDirection _direction; 41 FlexDirection _direction;
(...skipping 12 matching lines...) Expand all
52 _justifyContent = value; 54 _justifyContent = value;
53 markNeedsLayout(); 55 markNeedsLayout();
54 } 56 }
55 } 57 }
56 58
57 void setParentData(RenderBox child) { 59 void setParentData(RenderBox child) {
58 if (child.parentData is! FlexBoxParentData) 60 if (child.parentData is! FlexBoxParentData)
59 child.parentData = new FlexBoxParentData(); 61 child.parentData = new FlexBoxParentData();
60 } 62 }
61 63
62 // We don't currently support this for RenderFlex 64 double _getIntrinsicSize(BoxConstraints constraints,
63 double getMinIntrinsicWidth(BoxConstraints constraints) { 65 FlexDirection sizingDirection,
64 assert(false); 66 ChildSizingFunction childSize) {
65 return constraints.constrainWidth(0.0); 67 // http://www.w3.org/TR/2015/WD-css-flexbox-1-20150514/#intrinsic-sizes
68 if (_direction == sizingDirection) {
69 // INTRINSIC MAIN SIZE
70 // Intrinsic main size is the smallest size the flex container can take
71 // while maintaining the min/max-content contributions of its flex items.
72 BoxConstraints childConstraints;
73 switch(_direction) {
74 case FlexDirection.horizontal:
75 childConstraints = new BoxConstraints(maxHeight: constraints.maxHeight );
76 break;
77 case FlexDirection.vertical:
78 childConstraints = new BoxConstraints(maxWidth: constraints.maxWidth);
79 break;
80 }
81
82 double totalFlex = 0.0;
83 double inflexibleSpace = 0.0;
84 double maxFlexFractionSoFar = 0.0;
85 RenderBox child = firstChild;
86 while (child != null) {
87 int flex = _getFlex(child);
88 totalFlex += flex;
89 if (flex > 0) {
90 double flexFraction = childSize(child, childConstraints) / _getFlex(ch ild);
91 maxFlexFractionSoFar = math.max(maxFlexFractionSoFar, flexFraction);
92 } else {
93 inflexibleSpace += childSize(child, childConstraints);
94 }
95 child = child.parentData.nextSibling;
96 }
97 double mainSize = maxFlexFractionSoFar * totalFlex + inflexibleSpace;
98
99 // Ensure that we don't violate the given constraints with our result
100 switch(_direction) {
101 case FlexDirection.horizontal:
102 return constraints.constrainWidth(mainSize);
103 case FlexDirection.vertical:
104 return constraints.constrainHeight(mainSize);
105 }
106 } else {
107 // INTRINSIC CROSS SIZE
108 // The spec wants us to perform layout into the given available main-axis
109 // space and return the cross size. That's too expensive, so instead we
110 // size inflexible children according to their max intrinsic size in the
111 // main direction and use those constraints to determine their max
112 // intrinsic size in the cross direction. We don't care if the caller
113 // asked for max or min -- the answer is always computed using the
114 // max size in the main direction.
115
116 double availableMainSpace;
117 BoxConstraints childConstraints;
118 switch(_direction) {
119 case FlexDirection.horizontal:
120 childConstraints = new BoxConstraints(maxWidth: constraints.maxWidth);
121 availableMainSpace = innerConstraints.maxWidth;
122 break;
123 case FlexDirection.vertical:
124 childConstraints = new BoxConstraints(maxHeight: constraints.maxHeight );
125 availableMainSpace = innerConstraints.maxHeight;
126 break;
127 }
128
129 // Get inflexible space using the max in the main direction
130 int totalFlex = 0;
131 double inflexibleSpace = 0.0;
132 double maxCrossSize = 0.0;
133 RenderBox child = firstChild;
134 while (child != null) {
135 int flex = _getFlex(child);
136 totalFlex += flex;
137 double mainSize;
138 double crossSize;
139 if (flex == 0) {
140 switch (_direction) {
141 case FlexDirection.horizontal:
142 mainSize = child.getMaxIntrinsicWidth(childConstraints);
143 BoxConstraints widthConstraints =
144 new BoxConstraints(minWidth: mainSize, maxWidth: mainSize);
145 crossSize = child.getMinIntrinsicHeight(widthConstraints);
146 break;
147 case FlexDirection.vertical:
148 mainSize = child.getMaxIntrinsicHeight(childConstraints);
149 BoxConstraints heightConstraints =
150 new BoxConstraints(minWidth: mainSize, maxWidth: mainSize);
151 crossSize = child.getMinIntrinsicWidth(heightConstraints);
152 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.
153 break;
154 }
155 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.
156 maxCrossSize = math.max(maxCrossSize, crossSize);
157 }
158 child = child.parentData.nextSibling;
159 }
160
161 // Determine the spacePerFlex by allocating the remaining available space
162 double spacePerFlex = (availableMainSpace - inflexibleSpace) / totalFlex;
163
164 // Size remaining items, take the maximum
165 child = firstChild;
166 while (child != null) {
167 int flex = _getFlex(child);
168 if (flex > 0) {
169 double childMainSize = spacePerFlex * flex;
170 double crossSize;
171 switch (_direction) {
172 case FlexDirection.horizontal:
173 BoxConstraints childConstraints =
174 new BoxConstraints(minWidth: childMainSize, maxWidth: childMainS ize);
175 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.
176 maxCrossSize = math.max(maxCrossSize, crossSize);
177 break;
178 case FlexDirection.vertical:
179 BoxConstraints childConstraints =
180 new BoxConstraints(minHeight: childMainSize, maxHeight: childMai nSize);
181 crossSize = child.getMaxIntrinsicWidth(childConstraints);
182 break;
183 }
184 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.
185 }
186 child = child.parentData.nextSibling;
187 }
188
189 // Ensure that we don't violate the given constraints with our result
190 switch(_direction) {
191 case FlexDirection.horizontal:
192 return innerConstraints.constrainHeight(maxCrossSize);
193 case FlexDirection.vertical:
194 return innerConstraints.constrainWidth(maxCrossSize);
195 }
196 }
66 } 197 }
67 198
68 // We don't currently support this for RenderFlex 199 double getMinIntrinsicWidth(BoxConstraints constraints) {
69 double getMaxIntrinsicWidth(BoxConstraints constraints) { 200 return _getIntrinsicSize(
70 assert(false); 201 constraints,
71 return constraints.constrainWidth(0.0); 202 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
203 (c, innerConstraints) => c.getMinIntrinsicWidth(innerConstraints)
204 );
72 } 205 }
73 206
74 // We don't currently support this for RenderFlex 207 double getMaxIntrinsicWidth(BoxConstraints constraints) {
75 double getMinIntrinsicHeight(BoxConstraints constraints) { 208 return _getIntrinsicSize(
76 assert(false); 209 constraints,
77 return constraints.constrainHeight(0.0); 210 FlexDirection.horizontal,
abarth-chromium 2015/06/10 04:23:20 ditto
211 (c, innerConstraints) => c.getMaxIntrinsicWidth(innerConstraints)
212 );
78 } 213 }
79 214
80 // We don't currently support this for RenderFlex 215 double getMinIntrinsicHeight(BoxConstraints constraints) {
81 double getMaxIntrinsicHeight(BoxConstraints constraints) { 216 return _getIntrinsicSize(
82 assert(false); 217 constraints,
83 return constraints.constrainHeight(0.0); 218 FlexDirection.vertical,
abarth-chromium 2015/06/10 04:23:20 ditto
219 (c, innerConstraints) => c.getMinIntrinsicHeight(innerConstraints)
220 );
84 } 221 }
85 222
86 bool get sizedByParent => true; 223 double getMaxIntrinsicHeight(BoxConstraints constraints) {
87 void performResize() { 224 return _getIntrinsicSize(
88 size = constraints.constrain(new Size(constraints.maxWidth, constraints.maxH eight)); 225 constraints,
89 assert(size.height < double.INFINITY); 226 FlexDirection.vertical,
abarth-chromium 2015/06/10 04:23:20 ditto
90 assert(size.width < double.INFINITY); 227 (c, innerConstraints) => c.getMaxIntrinsicHeight(innerConstraints));
91 } 228 }
92 229
93 int _getFlex(RenderBox child) { 230 int _getFlex(RenderBox child) {
94 assert(child.parentData is FlexBoxParentData); 231 assert(child.parentData is FlexBoxParentData);
95 return child.parentData.flex != null ? child.parentData.flex : 0; 232 return child.parentData.flex != null ? child.parentData.flex : 0;
96 } 233 }
97 234
98 void performLayout() { 235 void performLayout() {
99 // Based on http://www.w3.org/TR/css-flexbox-1/ Section 9.7 Resolving Flexib le Lengths 236 // Based on http://www.w3.org/TR/css-flexbox-1/ Section 9.7 Resolving Flexib le Lengths
100 // Steps 1-3. Determine used flex factor, size inflexible items, calculate f ree space 237 // Steps 1-3. Determine used flex factor, size inflexible items, calculate f ree space
101 int totalFlex = 0; 238 int totalFlex = 0;
102 int totalChildren = 0; 239 int totalChildren = 0;
103 assert(constraints != null); 240 assert(constraints != null);
104 double freeSpace = (_direction == FlexDirection.horizontal) ? constraints.ma xWidth : constraints.maxHeight; 241 final double mainSize = (_direction == FlexDirection.horizontal) ? constrain ts.maxWidth : constraints.maxHeight;
242 double crossSize = 0.0; // This will be determined after laying out the chi ldren
243 double freeSpace = mainSize;
105 RenderBox child = firstChild; 244 RenderBox child = firstChild;
106 while (child != null) { 245 while (child != null) {
107 totalChildren++; 246 totalChildren++;
108 int flex = _getFlex(child); 247 int flex = _getFlex(child);
109 if (flex > 0) { 248 if (flex > 0) {
110 totalFlex += child.parentData.flex; 249 totalFlex += child.parentData.flex;
111 } else { 250 } else {
112 BoxConstraints innerConstraints = new BoxConstraints(maxHeight: constrai nts.maxHeight, 251 BoxConstraints innerConstraints = new BoxConstraints(maxHeight: constrai nts.maxHeight,
113 maxWidth: constrain ts.maxWidth); 252 maxWidth: constrain ts.maxWidth);
114 child.layout(innerConstraints, parentUsesSize: true); 253 child.layout(innerConstraints, parentUsesSize: true);
115 freeSpace -= (_direction == FlexDirection.horizontal) ? child.size.width : child.size.height; 254 freeSpace -= (_direction == FlexDirection.horizontal) ? child.size.width : child.size.height;
116 } 255 }
117 child = child.parentData.nextSibling; 256 child = child.parentData.nextSibling;
118 } 257 }
119 258
120 // Steps 4-5. Distribute remaining space to flexible children. 259 // Steps 4-5. Distribute remaining space to flexible children.
121 double spacePerFlex = totalFlex > 0 ? (freeSpace / totalFlex) : 0.0; 260 double spacePerFlex = totalFlex > 0 ? (freeSpace / totalFlex) : 0.0;
122 double usedSpace = 0.0; 261 double usedSpace = 0.0;
123 child = firstChild; 262 child = firstChild;
124 while (child != null) { 263 while (child != null) {
125 int flex = _getFlex(child); 264 int flex = _getFlex(child);
126 if (flex > 0) { 265 if (flex > 0) {
127 double spaceForChild = spacePerFlex * flex; 266 double spaceForChild = spacePerFlex * flex;
128 BoxConstraints innerConstraints; 267 BoxConstraints innerConstraints;
129 switch (_direction) { 268 switch (_direction) {
130 case FlexDirection.horizontal: 269 case FlexDirection.horizontal:
131 innerConstraints = new BoxConstraints(maxHeight: constraints.maxHeig ht, 270 innerConstraints = new BoxConstraints(maxHeight: constraints.maxHeig ht,
132 minWidth: spaceForChild, 271 minWidth: spaceForChild,
133 maxWidth: spaceForChild); 272 maxWidth: spaceForChild);
273 child.layout(innerConstraints, parentUsesSize: true);
274 usedSpace += child.size.width;
275 crossSize = math.max(crossSize, child.size.height);
134 break; 276 break;
135 case FlexDirection.vertical: 277 case FlexDirection.vertical:
136 innerConstraints = new BoxConstraints(minHeight: spaceForChild, 278 innerConstraints = new BoxConstraints(minHeight: spaceForChild,
137 maxHeight: spaceForChild, 279 maxHeight: spaceForChild,
138 maxWidth: constraints.maxWidth ); 280 maxWidth: constraints.maxWidth );
281 child.layout(innerConstraints, parentUsesSize: true);
282 usedSpace += child.size.height;
283 crossSize = math.max(crossSize, child.size.width);
139 break; 284 break;
140 } 285 }
141 child.layout(innerConstraints, parentUsesSize: true);
142 usedSpace += _direction == FlexDirection.horizontal ? child.size.width : child.size.height;
143 } 286 }
144 child = child.parentData.nextSibling; 287 child = child.parentData.nextSibling;
145 } 288 }
146 289
147 // Section 8.2: Axis Alignment using the justify-content property 290 // Section 8.2: Axis Alignment using the justify-content property
148 double remainingSpace = math.max(0.0, freeSpace - usedSpace); 291 double remainingSpace = math.max(0.0, freeSpace - usedSpace);
149 double leadingSpace; 292 double leadingSpace;
150 double betweenSpace; 293 double betweenSpace;
151 child = firstChild; 294 child = firstChild;
152 switch (_justifyContent) { 295 switch (_justifyContent) {
(...skipping 12 matching lines...) Expand all
165 case FlexJustifyContent.spaceBetween: 308 case FlexJustifyContent.spaceBetween:
166 leadingSpace = 0.0; 309 leadingSpace = 0.0;
167 betweenSpace = totalChildren > 1 ? remainingSpace / (totalChildren - 1) : 0.0; 310 betweenSpace = totalChildren > 1 ? remainingSpace / (totalChildren - 1) : 0.0;
168 break; 311 break;
169 case FlexJustifyContent.spaceAround: 312 case FlexJustifyContent.spaceAround:
170 betweenSpace = totalChildren > 0 ? remainingSpace / totalChildren : 0.0; 313 betweenSpace = totalChildren > 0 ? remainingSpace / totalChildren : 0.0;
171 leadingSpace = betweenSpace / 2.0; 314 leadingSpace = betweenSpace / 2.0;
172 break; 315 break;
173 } 316 }
174 317
318 switch (_direction) {
319 case FlexDirection.horizontal:
320 size = constraints.constrain(new Size(mainSize, crossSize));
321 break;
322 case FlexDirection.vertical:
323 size = constraints.constrain(new Size(crossSize, mainSize));
324 break;
325 }
326
175 // Position elements. For now, center the flex items in the cross direction 327 // Position elements. For now, center the flex items in the cross direction
176 double mainDimPosition = leadingSpace; 328 double mainDimPosition = leadingSpace;
177 child = firstChild; 329 child = firstChild;
178 while (child != null) { 330 while (child != null) {
179 switch (_direction) { 331 switch (_direction) {
180 case FlexDirection.horizontal: 332 case FlexDirection.horizontal:
181 child.parentData.position = new Point(mainDimPosition, size.height / 2 .0 - child.size.height / 2.0); 333 child.parentData.position = new Point(mainDimPosition, size.height / 2 .0 - child.size.height / 2.0);
182 mainDimPosition += child.size.width; 334 mainDimPosition += child.size.width;
183 break; 335 break;
184 case FlexDirection.vertical: 336 case FlexDirection.vertical:
185 child.parentData.position = new Point(size.width / 2.0 - child.size.wi dth / 2.0, mainDimPosition); 337 child.parentData.position = new Point(size.width / 2.0 - child.size.wi dth / 2.0, mainDimPosition);
186 mainDimPosition += child.size.height; 338 mainDimPosition += child.size.height;
187 break; 339 break;
188 } 340 }
189 mainDimPosition += betweenSpace; 341 mainDimPosition += betweenSpace;
190 child = child.parentData.nextSibling; 342 child = child.parentData.nextSibling;
191 } 343 }
192 } 344 }
193 345
194 void hitTestChildren(HitTestResult result, { Point position }) { 346 void hitTestChildren(HitTestResult result, { Point position }) {
195 defaultHitTestChildren(result, position: position); 347 defaultHitTestChildren(result, position: position);
196 } 348 }
197 349
198 void paint(RenderObjectDisplayList canvas) { 350 void paint(RenderObjectDisplayList canvas) {
199 defaultPaint(canvas); 351 defaultPaint(canvas);
200 } 352 }
201 } 353 }
OLDNEW
« sky/sdk/lib/framework/rendering/box.dart ('K') | « sky/sdk/lib/framework/rendering/box.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698