| OLD | NEW |
| 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 'node.dart'; | 5 import 'node.dart'; |
| 6 import 'dart:sky' as sky; | 6 import 'dart:sky' as sky; |
| 7 | 7 |
| 8 // ABSTRACT LAYOUT | 8 // ABSTRACT LAYOUT |
| 9 | 9 |
| 10 class ParentData { | 10 class ParentData { |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 67 assert(child.parentData != null); | 67 assert(child.parentData != null); |
| 68 child.parentData.detach(); | 68 child.parentData.detach(); |
| 69 super.dropChild(child); | 69 super.dropChild(child); |
| 70 } | 70 } |
| 71 | 71 |
| 72 static List<RenderNode> _nodesNeedingLayout = new List<RenderNode>(); | 72 static List<RenderNode> _nodesNeedingLayout = new List<RenderNode>(); |
| 73 static bool _debugDoingLayout = false; | 73 static bool _debugDoingLayout = false; |
| 74 bool _needsLayout = true; | 74 bool _needsLayout = true; |
| 75 bool get needsLayout => _needsLayout; | 75 bool get needsLayout => _needsLayout; |
| 76 RenderNode _relayoutSubtreeRoot; | 76 RenderNode _relayoutSubtreeRoot; |
| 77 void saveRelayoutSubtreeRoot(RenderNode relayoutSubtreeRoot) { | 77 dynamic _constraints; |
| 78 _relayoutSubtreeRoot = relayoutSubtreeRoot; | 78 dynamic get constraints => _constraints; |
| 79 assert(_relayoutSubtreeRoot == null || _relayoutSubtreeRoot._relayoutSubtree
Root == null); | |
| 80 assert(_relayoutSubtreeRoot == null || _relayoutSubtreeRoot == parent || (pa
rent is RenderNode && _relayoutSubtreeRoot == parent._relayoutSubtreeRoot)); | |
| 81 } | |
| 82 bool debugAncestorsAlreadyMarkedNeedsLayout() { | 79 bool debugAncestorsAlreadyMarkedNeedsLayout() { |
| 83 if (_relayoutSubtreeRoot == null) | 80 if (_relayoutSubtreeRoot == null) |
| 84 return true; | 81 return true; // we haven't yet done layout even once, so there's nothing f
or us to do |
| 85 RenderNode node = this; | 82 RenderNode node = this; |
| 86 while (node != _relayoutSubtreeRoot) { | 83 while (node != _relayoutSubtreeRoot) { |
| 87 assert(node._relayoutSubtreeRoot == _relayoutSubtreeRoot); | 84 assert(node._relayoutSubtreeRoot == _relayoutSubtreeRoot); |
| 88 assert(node.parent != null); | 85 assert(node.parent != null); |
| 89 node = node.parent as RenderNode; | 86 node = node.parent as RenderNode; |
| 90 if (!node._needsLayout) | 87 if (!node._needsLayout) |
| 91 return false; | 88 return false; |
| 92 } | 89 } |
| 93 assert(node._relayoutSubtreeRoot == null); | 90 assert(node._relayoutSubtreeRoot == node); |
| 94 return true; | 91 return true; |
| 95 } | 92 } |
| 96 void markNeedsLayout() { | 93 void markNeedsLayout() { |
| 97 assert(!_debugDoingLayout); | 94 assert(!_debugDoingLayout); |
| 98 assert(!_debugDoingPaint); | 95 assert(!_debugDoingPaint); |
| 99 if (_needsLayout) { | 96 if (_needsLayout) { |
| 100 assert(debugAncestorsAlreadyMarkedNeedsLayout()); | 97 assert(debugAncestorsAlreadyMarkedNeedsLayout()); |
| 101 return; | 98 return; |
| 102 } | 99 } |
| 103 _needsLayout = true; | 100 _needsLayout = true; |
| 104 if (_relayoutSubtreeRoot != null) { | 101 assert(_relayoutSubtreeRoot != null); |
| 102 if (_relayoutSubtreeRoot != this) { |
| 105 assert(parent is RenderNode); | 103 assert(parent is RenderNode); |
| 106 parent.markNeedsLayout(); | 104 parent.markNeedsLayout(); |
| 107 } else { | 105 } else { |
| 108 _nodesNeedingLayout.add(this); | 106 _nodesNeedingLayout.add(this); |
| 109 } | 107 } |
| 110 } | 108 } |
| 111 static void flushLayout() { | 109 static void flushLayout() { |
| 112 _debugDoingLayout = true; | 110 _debugDoingLayout = true; |
| 113 List<RenderNode> dirtyNodes = _nodesNeedingLayout; | 111 List<RenderNode> dirtyNodes = _nodesNeedingLayout; |
| 114 _nodesNeedingLayout = new List<RenderNode>(); | 112 _nodesNeedingLayout = new List<RenderNode>(); |
| 115 dirtyNodes..sort((a, b) => a.depth - b.depth)..forEach((node) { | 113 dirtyNodes..sort((a, b) => a.depth - b.depth)..forEach((node) { |
| 116 if (node._needsLayout && node.attached) | 114 if (node._needsLayout && node.attached) |
| 117 node._doLayout(); | 115 node._doLayout(); |
| 118 }); | 116 }); |
| 119 _debugDoingLayout = false; | 117 _debugDoingLayout = false; |
| 120 } | 118 } |
| 121 void _doLayout() { | 119 void _doLayout() { |
| 122 try { | 120 try { |
| 123 assert(_relayoutSubtreeRoot == null); | 121 assert(_relayoutSubtreeRoot == this); |
| 124 relayout(); | 122 performLayout(); |
| 125 } catch (e, stack) { | 123 } catch (e, stack) { |
| 126 print('Exception raised during layout of ${this}: ${e}'); | 124 print('Exception raised during layout of ${this}: ${e}'); |
| 127 print(stack); | 125 print(stack); |
| 128 return; | 126 return; |
| 129 } | 127 } |
| 130 assert(!_needsLayout); // check that the relayout() method marked us "not di
rty" | 128 assert(!_needsLayout); // check that the relayout() method marked us "not di
rty" |
| 131 } | 129 } |
| 132 /* // this method's signature is subclass-specific, but will exist in | 130 void layout(dynamic constraints, { bool parentUsesSize: false }) { |
| 133 // some form in all subclasses: | 131 RenderNode relayoutSubtreeRoot; |
| 134 void layout({arguments..., RenderNode relayoutSubtreeRoot}) { | 132 if (!parentUsesSize || sizedByParent || parent is! RenderNode) |
| 135 bool childArgumentsChanged = ...; // true if arguments we're going to pas
s to the children are different than last time, false otherwise | 133 relayoutSubtreeRoot = this; |
| 136 if (this node has an opinion about its size, e.g. because it autosizes ba
sed on kids, or has an intrinsic dimension) { | 134 else |
| 137 if (relayoutSubtreeRoot != null) { | 135 relayoutSubtreeRoot = parent._relayoutSubtreeRoot; |
| 138 saveRelayoutSubtreeRoot(relayoutSubtreeRoot); | 136 if (!needsLayout && constraints == _constraints && relayoutSubtreeRoot == _r
elayoutSubtreeRoot) |
| 139 // for each child, if we are going to size ourselves around them: | 137 return; |
| 140 if (child.needsLayout || childArgumentsChanged) | 138 _constraints = constraints; |
| 141 child.layout(... relayoutSubtreeRoot: relayoutSubtreeRoot); | 139 _relayoutSubtreeRoot = relayoutSubtreeRoot; |
| 142 width = ...; | 140 if (sizedByParent) |
| 143 height = ...; | 141 performResize(); |
| 144 } else { | 142 performLayout(); |
| 145 saveRelayoutSubtreeRoot(null); // you can skip this if there's no way
you would ever have called saveRelayoutSubtreeRoot() before | 143 _needsLayout = false; |
| 146 // we're the root of the relayout subtree | 144 markNeedsPaint(); |
| 147 // for each child, if we are going to size ourselves around them: | 145 } |
| 148 if (child.needsLayout || childArgumentsChanged) | 146 bool get sizedByParent => false; // return true if the constraints are the onl
y input to the sizing algorithm (in particular, child nodes have no impact) |
| 149 child.layout(... relayoutSubtreeRoot: this); | 147 void performResize(); // set the local dimensions, using only the constraints
(only called if sizedByParent is true) |
| 150 width = ...; | 148 void performLayout(); |
| 151 height = ...; | |
| 152 } | |
| 153 } else { | |
| 154 // we're sizing ourselves exclusively on input from the parent (argumen
ts to this function) | |
| 155 // ignore relayoutSubtreeRoot | |
| 156 saveRelayoutSubtreeRoot(null); // you can skip this if there's no way y
ou would ever have called saveRelayoutSubtreeRoot() before | |
| 157 width = ...; // based on input from arguments only | |
| 158 height = ...; // based on input from arguments only | |
| 159 } | |
| 160 // for each child whose size we'll ignore when deciding ours: | |
| 161 if (child.needsLayout || childArgumentsChanged) | |
| 162 child.layout(... relayoutSubtreeRoot: null); // or just omit relayoutSu
btreeRoot | |
| 163 layoutDone(); | |
| 164 return; | |
| 165 } | |
| 166 */ | |
| 167 void relayout() { | |
| 168 // Override this to perform relayout without your parent's | 149 // Override this to perform relayout without your parent's |
| 169 // involvement. | 150 // involvement. |
| 170 // | 151 // |
| 171 // This is what is called after the first layout(), if you mark | 152 // This is called during layout. If sizedByParent is true, then |
| 172 // yourself dirty and don't have a _relayoutSubtreeRoot set; in | 153 // performLayout() should not change your dimensions, only do that |
| 173 // other words, either if your parent doesn't care what size you | 154 // in performResize(). If sizedByParent is false, then set both |
| 174 // are (and thus didn't pass a relayoutSubtreeRoot to your | 155 // your dimensions and do your children's layout here. |
| 175 // layout() method) or if you sized yourself entirely based on | |
| 176 // what your parents told you, and not based on your children (and | |
| 177 // thus you never called saveRelayoutSubtreeRoot()). | |
| 178 // | 156 // |
| 179 // In the former case, you can resize yourself here at will. In | 157 // When calling layout() on your children, pass in |
| 180 // the latter case, just leave your dimensions unchanged. | 158 // "parentUsesSize: true" if your size or layout is dependent on |
| 181 // | 159 // your child's size. |
| 182 // If _relayoutSubtreeRoot is set (i.e. you called saveRelayout- | |
| 183 // SubtreeRoot() in your layout(), with a relayoutSubtreeRoot | |
| 184 // argument that was non-null), then if you mark yourself as dirty | |
| 185 // then we'll tell that subtree root instead, and the layout will | |
| 186 // occur via the layout() tree rather than starting from this | |
| 187 // relayout() method. | |
| 188 // | |
| 189 // when calling children's layout() methods, skip any children | |
| 190 // that have needsLayout == false unless the arguments you are | |
| 191 // passing in have changed since the last time | |
| 192 assert(_relayoutSubtreeRoot == null); | |
| 193 layoutDone(); | |
| 194 } | |
| 195 void layoutDone({bool needsPaint: true}) { | |
| 196 // make sure to call this at the end of your layout() or relayout() | |
| 197 _needsLayout = false; | |
| 198 if (needsPaint) | |
| 199 markNeedsPaint(); | |
| 200 } | |
| 201 | 160 |
| 202 // when the parent has rotated (e.g. when the screen has been turned | 161 // when the parent has rotated (e.g. when the screen has been turned |
| 203 // 90 degrees), immediately prior to layout() being called for the | 162 // 90 degrees), immediately prior to layout() being called for the |
| 204 // new dimensions, rotate() is called with the old and new angles. | 163 // new dimensions, rotate() is called with the old and new angles. |
| 205 // The next time paint() is called, the coordinate space will have | 164 // The next time paint() is called, the coordinate space will have |
| 206 // been rotated N quarter-turns clockwise, where: | 165 // been rotated N quarter-turns clockwise, where: |
| 207 // N = newAngle-oldAngle | 166 // N = newAngle-oldAngle |
| 208 // ...but the rendering is expected to remain the same, pixel for | 167 // ...but the rendering is expected to remain the same, pixel for |
| 209 // pixel, on the output device. Then, the layout() method or | 168 // pixel, on the output device. Then, the layout() method or |
| 210 // equivalent will be invoked. | 169 // equivalent will be invoked. |
| 211 | 170 |
| 212 void rotate({ | 171 void rotate({ |
| 213 int oldAngle, // 0..3 | 172 int oldAngle, // 0..3 |
| 214 int newAngle, // 0..3 | 173 int newAngle, // 0..3 |
| 215 Duration time | 174 Duration time |
| 216 }) { } | 175 }) { } |
| 217 | 176 |
| 218 | 177 |
| 219 // PAINTING | 178 // PAINTING |
| 220 | 179 |
| 221 static bool _debugDoingPaint = false; | 180 static bool _debugDoingPaint = false; |
| 222 void markNeedsPaint() { | 181 void markNeedsPaint() { |
| 223 assert(!_debugDoingPaint); | 182 assert(!_debugDoingPaint); |
| 224 // TODO(abarth): It's very redunant to call this for every node in the | 183 // TODO(abarth): It's very redundant to call this for every node in the |
| 225 // render tree during layout. We should instead compute a summary bit and | 184 // render tree during layout. We should instead compute a summary bit and |
| 226 // call it once at the end of layout. | 185 // call it once at the end of layout. |
| 227 sky.view.scheduleFrame(); | 186 sky.view.scheduleFrame(); |
| 228 } | 187 } |
| 229 void paint(RenderNodeDisplayList canvas) { } | 188 void paint(RenderNodeDisplayList canvas) { } |
| 230 | 189 |
| 231 | 190 |
| 232 // HIT TESTING | 191 // HIT TESTING |
| 233 | 192 |
| 234 void handlePointer(sky.PointerEvent event) { | 193 void handlePointer(sky.PointerEvent event) { |
| (...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 516 | 475 |
| 517 // override this to report what dimensions you would have if you | 476 // override this to report what dimensions you would have if you |
| 518 // were laid out with the given constraints this can walk the tree | 477 // were laid out with the given constraints this can walk the tree |
| 519 // if it must, but it should be as cheap as possible; just get the | 478 // if it must, but it should be as cheap as possible; just get the |
| 520 // dimensions and nothing else (e.g. don't calculate hypothetical | 479 // dimensions and nothing else (e.g. don't calculate hypothetical |
| 521 // child positions if they're not needed to determine dimensions) | 480 // child positions if they're not needed to determine dimensions) |
| 522 BoxDimensions getIntrinsicDimensions(BoxConstraints constraints) { | 481 BoxDimensions getIntrinsicDimensions(BoxConstraints constraints) { |
| 523 return new BoxDimensions.withConstraints(constraints); | 482 return new BoxDimensions.withConstraints(constraints); |
| 524 } | 483 } |
| 525 | 484 |
| 526 void layout(BoxConstraints constraints, { RenderNode relayoutSubtreeRoot }) { | 485 BoxConstraints get constraints => super.constraints as BoxConstraints; |
| 486 void performResize() { |
| 487 // default behaviour for subclasses that have sizedByParent = true |
| 527 width = constraints.constrainWidth(0.0); | 488 width = constraints.constrainWidth(0.0); |
| 528 height = constraints.constrainHeight(0.0); | 489 height = constraints.constrainHeight(0.0); |
| 529 layoutDone(); | 490 assert(height < double.INFINITY); |
| 491 assert(width < double.INFINITY); |
| 492 } |
| 493 void performLayout() { |
| 494 // descendants have to either override performLayout() to set both |
| 495 // width and height and lay out children, or, set sizedByParent to |
| 496 // true so that performResize()'s logic above does its thing. |
| 497 assert(sizedByParent); |
| 530 } | 498 } |
| 531 | 499 |
| 532 bool hitTest(HitTestResult result, { double x, double y }) { | 500 bool hitTest(HitTestResult result, { double x, double y }) { |
| 533 hitTestChildren(result, x: x, y: y); | 501 hitTestChildren(result, x: x, y: y); |
| 534 result.add(this); | 502 result.add(this); |
| 535 return true; | 503 return true; |
| 536 } | 504 } |
| 537 void hitTestChildren(HitTestResult result, { double x, double y }) { } | 505 void hitTestChildren(HitTestResult result, { double x, double y }) { } |
| 538 | 506 |
| 539 double width; | 507 double width; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 559 } | 527 } |
| 560 | 528 |
| 561 BoxDimensions getIntrinsicDimensions(BoxConstraints constraints) { | 529 BoxDimensions getIntrinsicDimensions(BoxConstraints constraints) { |
| 562 assert(padding != null); | 530 assert(padding != null); |
| 563 constraints = constraints.deflate(padding); | 531 constraints = constraints.deflate(padding); |
| 564 if (child == null) | 532 if (child == null) |
| 565 return super.getIntrinsicDimensions(constraints); | 533 return super.getIntrinsicDimensions(constraints); |
| 566 return child.getIntrinsicDimensions(constraints); | 534 return child.getIntrinsicDimensions(constraints); |
| 567 } | 535 } |
| 568 | 536 |
| 569 void layout(BoxConstraints constraints, { RenderNode relayoutSubtreeRoot }) { | 537 void performLayout() { |
| 570 assert(padding != null); | 538 assert(padding != null); |
| 571 constraints = constraints.deflate(padding); | 539 BoxConstraints innerConstraints = constraints.deflate(padding); |
| 572 if (child == null) { | 540 if (child == null) { |
| 573 width = constraints.constrainWidth(padding.left + padding.right); | 541 width = innerConstraints.constrainWidth(padding.left + padding.right); |
| 574 height = constraints.constrainHeight(padding.top + padding.bottom); | 542 height = innerConstraints.constrainHeight(padding.top + padding.bottom); |
| 575 return; | 543 return; |
| 576 } | 544 } |
| 577 if (relayoutSubtreeRoot != null) | 545 child.layout(innerConstraints, parentUsesSize: true); |
| 578 saveRelayoutSubtreeRoot(relayoutSubtreeRoot); | |
| 579 else | |
| 580 relayoutSubtreeRoot = this; | |
| 581 child.layout(constraints, relayoutSubtreeRoot: relayoutSubtreeRoot); | |
| 582 assert(child.parentData is BoxParentData); | 546 assert(child.parentData is BoxParentData); |
| 583 child.parentData.x = padding.left; | 547 child.parentData.x = padding.left; |
| 584 child.parentData.y = padding.top; | 548 child.parentData.y = padding.top; |
| 585 width = constraints.constrainWidth(padding.left + child.width + padding.righ
t); | 549 width = constraints.constrainWidth(padding.left + child.width + padding.righ
t); |
| 586 height = constraints.constrainHeight(padding.top + child.height + padding.bo
ttom); | 550 height = constraints.constrainHeight(padding.top + child.height + padding.bo
ttom); |
| 587 } | 551 } |
| 588 | 552 |
| 589 void paint(RenderNodeDisplayList canvas) { | 553 void paint(RenderNodeDisplayList canvas) { |
| 590 if (child != null) | 554 if (child != null) |
| 591 canvas.paintChild(child, child.parentData.x, child.parentData.y); | 555 canvas.paintChild(child, child.parentData.x, child.parentData.y); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 657 if (_decoration.backgroundColor != null) { | 621 if (_decoration.backgroundColor != null) { |
| 658 sky.Paint paint = new sky.Paint()..color = _decoration.backgroundColor; | 622 sky.Paint paint = new sky.Paint()..color = _decoration.backgroundColor; |
| 659 canvas.drawCircle(new sky.Rect()..setLTRB(0.0, 0.0, width, height), paint)
; | 623 canvas.drawCircle(new sky.Rect()..setLTRB(0.0, 0.0, width, height), paint)
; |
| 660 } | 624 } |
| 661 } | 625 } |
| 662 } | 626 } |
| 663 | 627 |
| 664 | 628 |
| 665 // RENDER VIEW LAYOUT MANAGER | 629 // RENDER VIEW LAYOUT MANAGER |
| 666 | 630 |
| 631 class ViewConstraints { |
| 632 |
| 633 const ViewConstraints({ |
| 634 this.width: 0.0, this.height: 0.0, this.orientation: null |
| 635 }); |
| 636 |
| 637 final double width; |
| 638 final double height; |
| 639 final int orientation; |
| 640 |
| 641 } |
| 642 |
| 667 class RenderView extends RenderNode with RenderNodeWithChildMixin<RenderBox> { | 643 class RenderView extends RenderNode with RenderNodeWithChildMixin<RenderBox> { |
| 668 | 644 |
| 669 RenderView({ | 645 RenderView({ |
| 670 RenderBox child, | 646 RenderBox child, |
| 671 this.timeForRotation: const Duration(microseconds: 83333) | 647 this.timeForRotation: const Duration(microseconds: 83333) |
| 672 }) { | 648 }) { |
| 673 this.child = child; | 649 this.child = child; |
| 674 } | 650 } |
| 675 | 651 |
| 676 double _width; | 652 double _width; |
| 677 double get width => _width; | 653 double get width => _width; |
| 678 double _height; | 654 double _height; |
| 679 double get height => _height; | 655 double get height => _height; |
| 680 | 656 |
| 681 int _orientation; // 0..3 | 657 int _orientation; // 0..3 |
| 682 int get orientation => _orientation; | 658 int get orientation => _orientation; |
| 683 Duration timeForRotation; | 659 Duration timeForRotation; |
| 684 | 660 |
| 685 void layout({ | 661 ViewConstraints get constraints => super.constraints as ViewConstraints; |
| 686 double newWidth, | 662 bool get sizedByParent => true; |
| 687 double newHeight, | 663 void performResize() { |
| 688 int newOrientation | 664 if (constraints.orientation != _orientation) { |
| 689 }) { | 665 if (_orientation != null && child != null) |
| 690 if (newOrientation != orientation) { | 666 child.rotate(oldAngle: _orientation, newAngle: constraints.orientation,
time: timeForRotation); |
| 691 if (orientation != null && child != null) | 667 _orientation = constraints.orientation; |
| 692 child.rotate(oldAngle: orientation, newAngle: newOrientation, time: time
ForRotation); | |
| 693 _orientation = newOrientation; | |
| 694 } | 668 } |
| 695 if ((newWidth != width) || (newHeight != height)) { | 669 _width = constraints.width; |
| 696 _width = newWidth; | 670 _height = constraints.height; |
| 697 _height = newHeight; | 671 assert(height < double.INFINITY); |
| 698 relayout(); | 672 assert(width < double.INFINITY); |
| 699 } else { | |
| 700 layoutDone(); | |
| 701 } | |
| 702 } | 673 } |
| 703 | 674 void performLayout() { |
| 704 void relayout() { | |
| 705 if (child != null) { | 675 if (child != null) { |
| 706 child.layout(new BoxConstraints.tight(width: width, height: height)); | 676 child.layout(new BoxConstraints.tight(width: width, height: height)); |
| 707 assert(child.width == width); | 677 assert(child.width == width); |
| 708 assert(child.height == height); | 678 assert(child.height == height); |
| 709 } | 679 } |
| 710 layoutDone(); | |
| 711 } | 680 } |
| 712 | 681 |
| 713 void rotate({ int oldAngle, int newAngle, Duration time }) { | 682 void rotate({ int oldAngle, int newAngle, Duration time }) { |
| 714 assert(false); // nobody tells the screen to rotate, the whole rotate() danc
e is started from our layout() | 683 assert(false); // nobody tells the screen to rotate, the whole rotate() danc
e is started from our performResize() |
| 715 } | 684 } |
| 716 | 685 |
| 717 bool hitTest(HitTestResult result, { double x, double y }) { | 686 bool hitTest(HitTestResult result, { double x, double y }) { |
| 718 if (child != null && x >= 0.0 && x < child.width && y >= 0.0 && y < child.he
ight) | 687 if (child != null && x >= 0.0 && x < child.width && y >= 0.0 && y < child.he
ight) |
| 719 child.hitTest(result, x: x, y: y); | 688 child.hitTest(result, x: x, y: y); |
| 720 result.add(this); | 689 result.add(this); |
| 721 return true; | 690 return true; |
| 722 } | 691 } |
| 723 | 692 |
| 724 void paint(RenderNodeDisplayList canvas) { | 693 void paint(RenderNodeDisplayList canvas) { |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 798 while (child != null) { | 767 while (child != null) { |
| 799 outerHeight += child.getIntrinsicDimensions(innerConstraints).height; | 768 outerHeight += child.getIntrinsicDimensions(innerConstraints).height; |
| 800 assert(child.parentData is BlockParentData); | 769 assert(child.parentData is BlockParentData); |
| 801 child = child.parentData.nextSibling; | 770 child = child.parentData.nextSibling; |
| 802 } | 771 } |
| 803 | 772 |
| 804 return new BoxDimensions(width: outerWidth, | 773 return new BoxDimensions(width: outerWidth, |
| 805 height: constraints.constrainHeight(outerHeight)); | 774 height: constraints.constrainHeight(outerHeight)); |
| 806 } | 775 } |
| 807 | 776 |
| 808 BoxConstraints _constraints; // value cached from parent for relayout call | 777 void performLayout() { |
| 809 void layout(BoxConstraints constraints, { RenderNode relayoutSubtreeRoot }) { | 778 assert(constraints is BoxConstraints); |
| 810 if (relayoutSubtreeRoot != null) | |
| 811 saveRelayoutSubtreeRoot(relayoutSubtreeRoot); | |
| 812 else | |
| 813 relayoutSubtreeRoot = this; | |
| 814 width = constraints.constrainWidth(constraints.maxWidth); | 779 width = constraints.constrainWidth(constraints.maxWidth); |
| 815 assert(width < double.INFINITY); | 780 assert(width < double.INFINITY); |
| 816 _constraints = constraints; | |
| 817 internalLayout(relayoutSubtreeRoot); | |
| 818 } | |
| 819 | |
| 820 void relayout() { | |
| 821 internalLayout(this); | |
| 822 } | |
| 823 | |
| 824 void internalLayout(RenderNode relayoutSubtreeRoot) { | |
| 825 assert(_constraints != null); | |
| 826 double y = 0.0; | 781 double y = 0.0; |
| 827 double innerWidth = width; | 782 double innerWidth = width; |
| 828 RenderBox child = firstChild; | 783 RenderBox child = firstChild; |
| 829 while (child != null) { | 784 while (child != null) { |
| 830 child.layout(new BoxConstraints(minWidth: innerWidth, maxWidth: innerWidth
), | 785 child.layout(new BoxConstraints(minWidth: innerWidth, maxWidth: innerWidth
), parentUsesSize: true); |
| 831 relayoutSubtreeRoot: relayoutSubtreeRoot); | |
| 832 assert(child.parentData is BlockParentData); | 786 assert(child.parentData is BlockParentData); |
| 833 child.parentData.x = 0.0; | 787 child.parentData.x = 0.0; |
| 834 child.parentData.y = y; | 788 child.parentData.y = y; |
| 835 y += child.height; | 789 y += child.height; |
| 836 child = child.parentData.nextSibling; | 790 child = child.parentData.nextSibling; |
| 837 } | 791 } |
| 838 height = _constraints.constrainHeight(y); | 792 height = constraints.constrainHeight(y); |
| 839 layoutDone(); | |
| 840 } | 793 } |
| 841 | 794 |
| 842 void hitTestChildren(HitTestResult result, { double x, double y }) { | 795 void hitTestChildren(HitTestResult result, { double x, double y }) { |
| 843 defaultHitTestChildren(result, x: x, y: y); | 796 defaultHitTestChildren(result, x: x, y: y); |
| 844 } | 797 } |
| 845 | 798 |
| 846 void paint(RenderNodeDisplayList canvas) { | 799 void paint(RenderNodeDisplayList canvas) { |
| 847 super.paint(canvas); | 800 super.paint(canvas); |
| 848 defaultPaint(canvas); | 801 defaultPaint(canvas); |
| 849 } | 802 } |
| (...skipping 29 matching lines...) Expand all Loading... |
| 879 _direction = value; | 832 _direction = value; |
| 880 markNeedsLayout(); | 833 markNeedsLayout(); |
| 881 } | 834 } |
| 882 } | 835 } |
| 883 | 836 |
| 884 void setParentData(RenderBox child) { | 837 void setParentData(RenderBox child) { |
| 885 if (child.parentData is! FlexBoxParentData) | 838 if (child.parentData is! FlexBoxParentData) |
| 886 child.parentData = new FlexBoxParentData(); | 839 child.parentData = new FlexBoxParentData(); |
| 887 } | 840 } |
| 888 | 841 |
| 889 BoxConstraints _constraints; // value cached from parent for relayout call | 842 bool get sizedByParent => true; |
| 890 void layout(BoxConstraints constraints, { RenderNode relayoutSubtreeRoot }) { | 843 void performResize() { |
| 891 if (relayoutSubtreeRoot != null) | |
| 892 saveRelayoutSubtreeRoot(relayoutSubtreeRoot); | |
| 893 else | |
| 894 relayoutSubtreeRoot = this; | |
| 895 _constraints = constraints; | |
| 896 width = _constraints.constrainWidth(_constraints.maxWidth); | 844 width = _constraints.constrainWidth(_constraints.maxWidth); |
| 897 height = _constraints.constrainHeight(_constraints.maxHeight); | 845 height = _constraints.constrainHeight(_constraints.maxHeight); |
| 898 assert(height < double.INFINITY); | 846 assert(height < double.INFINITY); |
| 899 assert(width < double.INFINITY); | 847 assert(width < double.INFINITY); |
| 900 internalLayout(relayoutSubtreeRoot); | |
| 901 } | |
| 902 | |
| 903 void relayout() { | |
| 904 internalLayout(this); | |
| 905 } | 848 } |
| 906 | 849 |
| 907 int _getFlex(RenderBox child) { | 850 int _getFlex(RenderBox child) { |
| 908 assert(child.parentData is FlexBoxParentData); | 851 assert(child.parentData is FlexBoxParentData); |
| 909 return child.parentData.flex != null ? child.parentData.flex : 0; | 852 return child.parentData.flex != null ? child.parentData.flex : 0; |
| 910 } | 853 } |
| 911 | 854 |
| 912 void internalLayout(RenderNode relayoutSubtreeRoot) { | 855 void performLayout() { |
| 913 // Based on http://www.w3.org/TR/css-flexbox-1/ Section 9.7 Resolving Flexib
le Lengths | 856 // Based on http://www.w3.org/TR/css-flexbox-1/ Section 9.7 Resolving Flexib
le Lengths |
| 914 // Steps 1-3. Determine used flex factor, size inflexible items, calculate f
ree space | 857 // Steps 1-3. Determine used flex factor, size inflexible items, calculate f
ree space |
| 915 int totalFlex = 0; | 858 int totalFlex = 0; |
| 916 assert(_constraints != null); | 859 assert(constraints != null); |
| 917 double freeSpace = (_direction == FlexDirection.Horizontal) ? _constraints.m
axWidth : _constraints.maxHeight; | 860 double freeSpace = (_direction == FlexDirection.Horizontal) ? constraints.ma
xWidth : constraints.maxHeight; |
| 918 RenderBox child = firstChild; | 861 RenderBox child = firstChild; |
| 919 while (child != null) { | 862 while (child != null) { |
| 920 int flex = _getFlex(child); | 863 int flex = _getFlex(child); |
| 921 if (flex > 0) { | 864 if (flex > 0) { |
| 922 totalFlex += child.parentData.flex; | 865 totalFlex += child.parentData.flex; |
| 923 } else { | 866 } else { |
| 924 BoxConstraints constraints = new BoxConstraints(maxHeight: _constraints.
maxHeight, | 867 BoxConstraints innerConstraints = new BoxConstraints(maxHeight: constrai
nts.maxHeight, |
| 925 maxWidth: _constraints.m
axWidth); | 868 maxWidth: constrain
ts.maxWidth); |
| 926 child.layout(constraints, | 869 child.layout(innerConstraints, parentUsesSize: true); |
| 927 relayoutSubtreeRoot: relayoutSubtreeRoot); | |
| 928 freeSpace -= (_direction == FlexDirection.Horizontal) ? child.width : ch
ild.height; | 870 freeSpace -= (_direction == FlexDirection.Horizontal) ? child.width : ch
ild.height; |
| 929 } | 871 } |
| 930 child = child.parentData.nextSibling; | 872 child = child.parentData.nextSibling; |
| 931 } | 873 } |
| 932 | 874 |
| 933 // Steps 4-5. Distribute remaining space to flexible children. | 875 // Steps 4-5. Distribute remaining space to flexible children. |
| 934 double spacePerFlex = totalFlex > 0 ? (freeSpace / totalFlex) : 0.0; | 876 double spacePerFlex = totalFlex > 0 ? (freeSpace / totalFlex) : 0.0; |
| 935 double usedSpace = 0.0; | 877 double usedSpace = 0.0; |
| 936 child = firstChild; | 878 child = firstChild; |
| 937 while (child != null) { | 879 while (child != null) { |
| 938 int flex = _getFlex(child); | 880 int flex = _getFlex(child); |
| 939 if (flex > 0) { | 881 if (flex > 0) { |
| 940 double spaceForChild = spacePerFlex * flex; | 882 double spaceForChild = spacePerFlex * flex; |
| 941 BoxConstraints constraints; | 883 BoxConstraints innerConstraints; |
| 942 switch (_direction) { | 884 switch (_direction) { |
| 943 case FlexDirection.Horizontal: | 885 case FlexDirection.Horizontal: |
| 944 constraints = new BoxConstraints(maxHeight: _constraints.maxHeight, | 886 innerConstraints = new BoxConstraints(maxHeight: constraints.maxHeig
ht, |
| 945 minWidth: spaceForChild, | 887 minWidth: spaceForChild, |
| 946 maxWidth: spaceForChild); | 888 maxWidth: spaceForChild); |
| 947 break; | 889 break; |
| 948 case FlexDirection.Vertical: | 890 case FlexDirection.Vertical: |
| 949 constraints = new BoxConstraints(minHeight: spaceForChild, | 891 innerConstraints = new BoxConstraints(minHeight: spaceForChild, |
| 950 maxHeight: spaceForChild, | 892 maxHeight: spaceForChild, |
| 951 maxWidth: _constraints.maxWidth); | 893 maxWidth: constraints.maxWidth
); |
| 952 break; | 894 break; |
| 953 } | 895 } |
| 954 child.layout(constraints, relayoutSubtreeRoot: relayoutSubtreeRoot); | 896 child.layout(innerConstraints, parentUsesSize: true); |
| 955 } | 897 } |
| 956 | 898 |
| 957 // For now, center the flex items in the cross direction | 899 // For now, center the flex items in the cross direction |
| 958 switch (_direction) { | 900 switch (_direction) { |
| 959 case FlexDirection.Horizontal: | 901 case FlexDirection.Horizontal: |
| 960 child.parentData.x = usedSpace; | 902 child.parentData.x = usedSpace; |
| 961 usedSpace += child.width; | 903 usedSpace += child.width; |
| 962 child.parentData.y = height / 2 - child.height / 2; | 904 child.parentData.y = height / 2.0 - child.height / 2.0; |
| 963 break; | 905 break; |
| 964 case FlexDirection.Vertical: | 906 case FlexDirection.Vertical: |
| 965 child.parentData.y = usedSpace; | 907 child.parentData.y = usedSpace; |
| 966 usedSpace += child.height; | 908 usedSpace += child.height; |
| 967 child.parentData.x = width / 2 - child.width / 2; | 909 child.parentData.x = width / 2.0 - child.width / 2.0; |
| 968 break; | 910 break; |
| 969 } | 911 } |
| 970 child = child.parentData.nextSibling; | 912 child = child.parentData.nextSibling; |
| 971 } | 913 } |
| 972 layoutDone(); | |
| 973 } | 914 } |
| 974 | 915 |
| 975 void hitTestChildren(HitTestResult result, { double x, double y }) { | 916 void hitTestChildren(HitTestResult result, { double x, double y }) { |
| 976 defaultHitTestChildren(result, x: x, y: y); | 917 defaultHitTestChildren(result, x: x, y: y); |
| 977 } | 918 } |
| 978 | 919 |
| 979 void paint(RenderNodeDisplayList canvas) { | 920 void paint(RenderNodeDisplayList canvas) { |
| 980 super.paint(canvas); | 921 super.paint(canvas); |
| 981 defaultPaint(canvas); | 922 defaultPaint(canvas); |
| 982 } | 923 } |
| 983 } | 924 } |
| OLD | NEW |