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 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
255 class HitTestResult { | 255 class HitTestResult { |
256 final List<RenderNode> path = new List<RenderNode>(); | 256 final List<RenderNode> path = new List<RenderNode>(); |
257 | 257 |
258 RenderNode get result => path.first; | 258 RenderNode get result => path.first; |
259 | 259 |
260 void add(RenderNode node) { | 260 void add(RenderNode node) { |
261 path.add(node); | 261 path.add(node); |
262 } | 262 } |
263 } | 263 } |
264 | 264 |
265 | |
266 // GENERIC MIXIN FOR RENDER NODES WITH ONE CHILD | |
267 | |
265 abstract class RenderNodeWithChildMixin<ChildType extends RenderNode> { | 268 abstract class RenderNodeWithChildMixin<ChildType extends RenderNode> { |
266 ChildType _child; | 269 ChildType _child; |
267 ChildType get child => _child; | 270 ChildType get child => _child; |
268 void set child (ChildType value) { | 271 void set child (ChildType value) { |
269 if (_child != null) | 272 if (_child != null) |
270 dropChild(_child); | 273 dropChild(_child); |
271 _child = value; | 274 _child = value; |
272 if (_child != null) | 275 if (_child != null) |
273 adoptChild(_child); | 276 adoptChild(_child); |
274 markNeedsLayout(); | 277 markNeedsLayout(); |
275 } | 278 } |
276 } | 279 } |
277 | 280 |
278 // GENERIC MIXIN FOR RENDER NODES THAT TAKE A LIST OF CHILDREN | 281 |
282 // GENERIC MIXIN FOR RENDER NODES WITH A LIST OF CHILDREN | |
279 | 283 |
280 abstract class ContainerParentDataMixin<ChildType extends RenderNode> { | 284 abstract class ContainerParentDataMixin<ChildType extends RenderNode> { |
281 ChildType previousSibling; | 285 ChildType previousSibling; |
282 ChildType nextSibling; | 286 ChildType nextSibling; |
283 void detachSiblings() { | 287 void detachSiblings() { |
284 if (previousSibling != null) { | 288 if (previousSibling != null) { |
285 assert(previousSibling.parentData is ContainerParentDataMixin<ChildType>); | 289 assert(previousSibling.parentData is ContainerParentDataMixin<ChildType>); |
286 assert(previousSibling != this); | 290 assert(previousSibling != this); |
287 assert(previousSibling.parentData.nextSibling == this); | 291 assert(previousSibling.parentData.nextSibling == this); |
288 previousSibling.parentData.nextSibling = nextSibling; | 292 previousSibling.parentData.nextSibling = nextSibling; |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
423 assert(child.parentData is ParentDataType); | 427 assert(child.parentData is ParentDataType); |
424 return child.parentData.nextSibling; | 428 return child.parentData.nextSibling; |
425 } | 429 } |
426 | 430 |
427 } | 431 } |
428 | 432 |
429 | 433 |
430 // GENERIC BOX RENDERING | 434 // GENERIC BOX RENDERING |
431 // Anything that has a concept of x, y, width, height is going to derive from th is | 435 // Anything that has a concept of x, y, width, height is going to derive from th is |
432 | 436 |
437 class EdgeDims { | |
438 // used for e.g. padding | |
439 const EdgeDims(this.top, this.right, this.bottom, this.left); | |
440 final double top; | |
441 final double right; | |
442 final double bottom; | |
443 final double left; | |
444 operator ==(EdgeDims other) => (top == other.top) || | |
445 (right == other.right) || | |
446 (bottom == other.bottom) || | |
447 (left == other.left); | |
448 } | |
449 | |
433 class BoxConstraints { | 450 class BoxConstraints { |
434 const BoxConstraints({ | 451 const BoxConstraints({ |
435 this.minWidth: 0.0, | 452 this.minWidth: 0.0, |
436 this.maxWidth: double.INFINITY, | 453 this.maxWidth: double.INFINITY, |
437 this.minHeight: 0.0, | 454 this.minHeight: 0.0, |
438 this.maxHeight: double.INFINITY}); | 455 this.maxHeight: double.INFINITY}); |
439 | 456 |
440 const BoxConstraints.tight({ double width: 0.0, double height: 0.0 }) | 457 const BoxConstraints.tight({ double width: 0.0, double height: 0.0 }) |
441 : minWidth = width, | 458 : minWidth = width, |
442 maxWidth = width, | 459 maxWidth = width, |
443 minHeight = height, | 460 minHeight = height, |
444 maxHeight = height; | 461 maxHeight = height; |
445 | 462 |
463 BoxConstraints deflate(EdgeDims edges) { | |
464 assert(edges != null); | |
465 return new BoxConstraints( | |
466 minWidth: minWidth, | |
467 maxWidth: maxWidth - (edges.left + edges.right), | |
468 minHeight: minHeight, | |
469 maxHeight: maxHeight - (edges.top + edges.bottom) | |
470 ); | |
471 } | |
472 | |
446 final double minWidth; | 473 final double minWidth; |
447 final double maxWidth; | 474 final double maxWidth; |
448 final double minHeight; | 475 final double minHeight; |
449 final double maxHeight; | 476 final double maxHeight; |
450 | 477 |
451 double constrainWidth(double width) { | 478 double constrainWidth(double width) { |
452 return clamp(min: minWidth, max: maxWidth, value: width); | 479 return clamp(min: minWidth, max: maxWidth, value: width); |
453 } | 480 } |
454 | 481 |
455 double constrainHeight(double height) { | 482 double constrainHeight(double height) { |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
505 hitTestChildren(result, x: x, y: y); | 532 hitTestChildren(result, x: x, y: y); |
506 result.add(this); | 533 result.add(this); |
507 return true; | 534 return true; |
508 } | 535 } |
509 void hitTestChildren(HitTestResult result, { double x, double y }) { } | 536 void hitTestChildren(HitTestResult result, { double x, double y }) { } |
510 | 537 |
511 double width; | 538 double width; |
512 double height; | 539 double height; |
513 } | 540 } |
514 | 541 |
542 class RenderPadding extends RenderBox with RenderNodeWithChildMixin<RenderBox> { | |
543 | |
544 RenderPadding(EdgeDims padding, RenderBox child) { | |
545 assert(padding != null); | |
546 this.padding = padding; | |
547 this.child = child; | |
548 } | |
549 | |
550 EdgeDims _padding; | |
551 EdgeDims get padding => _padding; | |
552 void set padding (EdgeDims value) { | |
553 assert(value != null); | |
554 if (_padding != value) { | |
555 _padding = value; | |
556 markNeedsLayout(); | |
557 } | |
558 } | |
559 | |
560 BoxDimensions getIntrinsicDimensions(BoxConstraints constraints) { | |
561 assert(padding != null); | |
562 constraints = constraints.deflate(padding); | |
563 if (child == null) | |
564 return super.getIntrinsicDimensions(constraints); | |
565 return child.getIntrinsicDimensions(constraints); | |
566 } | |
567 | |
568 void layout(BoxConstraints constraints, { RenderNode relayoutSubtreeRoot }) { | |
569 assert(padding != null); | |
570 constraints = constraints.deflate(padding); | |
571 if (child == null) { | |
572 width = constraints.constrainWidth(padding.left + padding.right); | |
573 height = constraints.constrainHeight(padding.top + padding.bottom); | |
574 return; | |
575 } | |
576 if (relayoutSubtreeRoot != null) | |
577 saveRelayoutSubtreeRoot(relayoutSubtreeRoot); | |
578 else | |
579 relayoutSubtreeRoot = this; | |
580 child.layout(constraints, relayoutSubtreeRoot: relayoutSubtreeRoot); | |
581 assert(child.parentData is BoxParentData); | |
582 child.parentData.x = padding.left; | |
583 child.parentData.y = padding.top; | |
584 width = constraints.constrainWidth(padding.left + child.width + padding.righ t); | |
585 height = constraints.constrainHeight(padding.top + child.height + padding.bo ttom); | |
586 } | |
587 | |
588 void paint(RenderNodeDisplayList canvas) { | |
589 if (child != null) | |
590 canvas.paintChild(child, child.parentData.x, child.parentData.y); | |
591 } | |
abarth-chromium
2015/05/27 23:50:03
hitTestChildren?
| |
592 | |
593 } | |
594 | |
515 // This must be immutable, because we won't notice when it changes | 595 // This must be immutable, because we won't notice when it changes |
516 class BoxDecoration { | 596 class BoxDecoration { |
517 const BoxDecoration({ | 597 const BoxDecoration({ |
518 this.backgroundColor | 598 this.backgroundColor |
519 }); | 599 }); |
520 | 600 |
521 final int backgroundColor; | 601 final int backgroundColor; |
522 } | 602 } |
523 | 603 |
524 class RenderDecoratedBox extends RenderBox { | 604 class RenderDecoratedBox extends RenderBox { |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
606 _width = newWidth; | 686 _width = newWidth; |
607 _height = newHeight; | 687 _height = newHeight; |
608 relayout(); | 688 relayout(); |
609 } else { | 689 } else { |
610 layoutDone(); | 690 layoutDone(); |
611 } | 691 } |
612 } | 692 } |
613 | 693 |
614 void relayout() { | 694 void relayout() { |
615 if (child != null) { | 695 if (child != null) { |
616 child.layout(new BoxConstraints( | 696 child.layout(new BoxConstraints.tight(width: width, height: height)); |
617 minWidth: width, | |
618 maxWidth: width, | |
619 minHeight: height, | |
620 maxHeight: height | |
621 )); | |
622 assert(child.width == width); | 697 assert(child.width == width); |
623 assert(child.height == height); | 698 assert(child.height == height); |
624 } | 699 } |
625 layoutDone(); | 700 layoutDone(); |
626 } | 701 } |
627 | 702 |
628 void rotate({ int oldAngle, int newAngle, Duration time }) { | 703 void rotate({ int oldAngle, int newAngle, Duration time }) { |
629 assert(false); // nobody tells the screen to rotate, the whole rotate() danc e is started from our layout() | 704 assert(false); // nobody tells the screen to rotate, the whole rotate() danc e is started from our layout() |
630 } | 705 } |
631 | 706 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
677 while (child != null) { | 752 while (child != null) { |
678 assert(child.parentData is BoxParentData); | 753 assert(child.parentData is BoxParentData); |
679 canvas.paintChild(child, child.parentData.x, child.parentData.y); | 754 canvas.paintChild(child, child.parentData.x, child.parentData.y); |
680 child = child.parentData.nextSibling; | 755 child = child.parentData.nextSibling; |
681 } | 756 } |
682 } | 757 } |
683 } | 758 } |
684 | 759 |
685 // BLOCK LAYOUT MANAGER | 760 // BLOCK LAYOUT MANAGER |
686 | 761 |
687 class EdgeDims { | |
688 // used for e.g. padding | |
689 const EdgeDims(this.top, this.right, this.bottom, this.left); | |
690 final double top; | |
691 final double right; | |
692 final double bottom; | |
693 final double left; | |
694 operator ==(EdgeDims other) => (top == other.top) || | |
695 (right == other.right) || | |
696 (bottom == other.bottom) || | |
697 (left == other.left); | |
698 } | |
699 | |
700 class BlockParentData extends BoxParentData with ContainerParentDataMixin<Render Box> { } | 762 class BlockParentData extends BoxParentData with ContainerParentDataMixin<Render Box> { } |
701 | 763 |
702 class RenderBlock extends RenderDecoratedBox with ContainerRenderNodeMixin<Rende rBox, BlockParentData>, | 764 class RenderBlock extends RenderDecoratedBox with ContainerRenderNodeMixin<Rende rBox, BlockParentData>, |
703 RenderBoxContainerDefaultsMixi n<RenderBox, BlockParentData> { | 765 RenderBoxContainerDefaultsMixi n<RenderBox, BlockParentData> { |
704 // lays out RenderBox children in a vertical stack | 766 // lays out RenderBox children in a vertical stack |
705 // uses the maximum width provided by the parent | 767 // uses the maximum width provided by the parent |
706 // sizes itself to the height of its child stack | 768 // sizes itself to the height of its child stack |
707 | 769 |
708 RenderBlock({ | 770 RenderBlock({ |
709 BoxDecoration decoration, | 771 BoxDecoration decoration |
710 EdgeDims padding: const EdgeDims(0.0, 0.0, 0.0, 0.0) | 772 }) : super(decoration); |
711 }) : super(decoration), _padding = padding; | |
712 | |
713 EdgeDims _padding; | |
714 EdgeDims get padding => _padding; | |
715 void set padding (EdgeDims value) { | |
716 assert(value != null); | |
717 if (_padding != value) { | |
718 _padding = value; | |
719 markNeedsLayout(); | |
720 } | |
721 } | |
722 | 773 |
723 void setParentData(RenderBox child) { | 774 void setParentData(RenderBox child) { |
724 if (child.parentData is! BlockParentData) | 775 if (child.parentData is! BlockParentData) |
725 child.parentData = new BlockParentData(); | 776 child.parentData = new BlockParentData(); |
726 } | 777 } |
727 | 778 |
728 // override this to report what dimensions you would have if you | 779 // override this to report what dimensions you would have if you |
729 // were laid out with the given constraints this can walk the tree | 780 // were laid out with the given constraints this can walk the tree |
730 // if it must, but it should be as cheap as possible; just get the | 781 // if it must, but it should be as cheap as possible; just get the |
731 // dimensions and nothing else (e.g. don't calculate hypothetical | 782 // dimensions and nothing else (e.g. don't calculate hypothetical |
732 // child positions if they're not needed to determine dimensions) | 783 // child positions if they're not needed to determine dimensions) |
733 BoxDimensions getIntrinsicDimensions(BoxConstraints constraints) { | 784 BoxDimensions getIntrinsicDimensions(BoxConstraints constraints) { |
734 double outerHeight = _padding.top + _padding.bottom; | 785 double outerHeight = 0.0; |
735 double outerWidth = constraints.constrainWidth(constraints.maxWidth); | 786 double outerWidth = constraints.constrainWidth(constraints.maxWidth); |
736 assert(outerWidth < double.INFINITY); | 787 assert(outerWidth < double.INFINITY); |
737 double innerWidth = outerWidth - (_padding.left + _padding.right); | 788 double innerWidth = outerWidth; |
738 RenderBox child = firstChild; | 789 RenderBox child = firstChild; |
739 BoxConstraints innerConstraints = new BoxConstraints(minWidth: innerWidth, | 790 BoxConstraints innerConstraints = new BoxConstraints(minWidth: innerWidth, |
740 maxWidth: innerWidth); | 791 maxWidth: innerWidth); |
741 while (child != null) { | 792 while (child != null) { |
742 outerHeight += child.getIntrinsicDimensions(innerConstraints).height; | 793 outerHeight += child.getIntrinsicDimensions(innerConstraints).height; |
743 assert(child.parentData is BlockParentData); | 794 assert(child.parentData is BlockParentData); |
744 child = child.parentData.nextSibling; | 795 child = child.parentData.nextSibling; |
745 } | 796 } |
746 | 797 |
747 return new BoxDimensions(width: outerWidth, | 798 return new BoxDimensions(width: outerWidth, |
(...skipping 11 matching lines...) Expand all Loading... | |
759 _constraints = constraints; | 810 _constraints = constraints; |
760 internalLayout(relayoutSubtreeRoot); | 811 internalLayout(relayoutSubtreeRoot); |
761 } | 812 } |
762 | 813 |
763 void relayout() { | 814 void relayout() { |
764 internalLayout(this); | 815 internalLayout(this); |
765 } | 816 } |
766 | 817 |
767 void internalLayout(RenderNode relayoutSubtreeRoot) { | 818 void internalLayout(RenderNode relayoutSubtreeRoot) { |
768 assert(_constraints != null); | 819 assert(_constraints != null); |
769 double y = _padding.top; | 820 double y = 0.0; |
770 double innerWidth = width - (_padding.left + _padding.right); | 821 double innerWidth = width; |
771 RenderBox child = firstChild; | 822 RenderBox child = firstChild; |
772 while (child != null) { | 823 while (child != null) { |
773 child.layout(new BoxConstraints(minWidth: innerWidth, maxWidth: innerWidth ), | 824 child.layout(new BoxConstraints(minWidth: innerWidth, maxWidth: innerWidth ), |
774 relayoutSubtreeRoot: relayoutSubtreeRoot); | 825 relayoutSubtreeRoot: relayoutSubtreeRoot); |
775 assert(child.parentData is BlockParentData); | 826 assert(child.parentData is BlockParentData); |
776 child.parentData.x = _padding.left; | 827 child.parentData.x = 0.0; |
777 child.parentData.y = y; | 828 child.parentData.y = y; |
778 y += child.height; | 829 y += child.height; |
779 child = child.parentData.nextSibling; | 830 child = child.parentData.nextSibling; |
780 } | 831 } |
781 height = _constraints.constrainHeight(y + _padding.bottom); | 832 height = _constraints.constrainHeight(y); |
782 layoutDone(); | 833 layoutDone(); |
783 } | 834 } |
784 | 835 |
785 void hitTestChildren(HitTestResult result, { double x, double y }) { | 836 void hitTestChildren(HitTestResult result, { double x, double y }) { |
786 defaultHitTestChildren(result, x: x, y: y); | 837 defaultHitTestChildren(result, x: x, y: y); |
787 } | 838 } |
788 | 839 |
789 void paint(RenderNodeDisplayList canvas) { | 840 void paint(RenderNodeDisplayList canvas) { |
790 super.paint(canvas); | 841 super.paint(canvas); |
791 defaultPaint(canvas); | 842 defaultPaint(canvas); |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
917 | 968 |
918 void hitTestChildren(HitTestResult result, { double x, double y }) { | 969 void hitTestChildren(HitTestResult result, { double x, double y }) { |
919 defaultHitTestChildren(result, x: x, y: y); | 970 defaultHitTestChildren(result, x: x, y: y); |
920 } | 971 } |
921 | 972 |
922 void paint(RenderNodeDisplayList canvas) { | 973 void paint(RenderNodeDisplayList canvas) { |
923 super.paint(canvas); | 974 super.paint(canvas); |
924 defaultPaint(canvas); | 975 defaultPaint(canvas); |
925 } | 976 } |
926 } | 977 } |
OLD | NEW |