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

Side by Side Diff: sky/sdk/lib/framework/layout2.dart

Issue 1143153011: Refactor padding out of RenderBlock. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: fix hit testing 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
« no previous file with comments | « sky/examples/raw/simple_render_tree.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 '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 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
233 233
234 void handlePointer(sky.PointerEvent event) { 234 void handlePointer(sky.PointerEvent event) {
235 // override this if you have a client, to hand it to the client 235 // override this if you have a client, to hand it to the client
236 // override this if you want to do anything with the pointer event 236 // override this if you want to do anything with the pointer event
237 } 237 }
238 238
239 // RenderNode subclasses are expected to have a method like the 239 // RenderNode subclasses are expected to have a method like the
240 // following (with the signature being whatever passes for coordinates 240 // following (with the signature being whatever passes for coordinates
241 // for this particular class): 241 // for this particular class):
242 // bool hitTest(HitTestResult result, { double x, double y }) { 242 // bool hitTest(HitTestResult result, { double x, double y }) {
243 // // If (x,y) is not inside this node, then return false. 243 // // If (x,y) is not inside this node, then return false. (You
244 // // can assume that the given coordinate is inside your
245 // // dimensions. You only need to check this if you're an
246 // // irregular shape, e.g. if you have a hole.)
244 // // Otherwise: 247 // // Otherwise:
245 // // For each child that intersects x,y, in z-order starting from the top, 248 // // For each child that intersects x,y, in z-order starting from the top,
246 // // call hitTest() for that child, passing it /result/, and the coordinate s 249 // // call hitTest() for that child, passing it /result/, and the coordinate s
247 // // converted to the child's coordinate origin, and stop at the first chil d 250 // // converted to the child's coordinate origin, and stop at the first chil d
248 // // that returns true. 251 // // that returns true.
249 // // Then, add yourself to /result/, and return true. 252 // // Then, add yourself to /result/, and return true.
250 // } 253 // }
251 // You must not add yourself to /result/ if you return false. 254 // You must not add yourself to /result/ if you return false.
252 255
253 } 256 }
254 257
255 class HitTestResult { 258 class HitTestResult {
256 final List<RenderNode> path = new List<RenderNode>(); 259 final List<RenderNode> path = new List<RenderNode>();
257 260
258 RenderNode get result => path.first; 261 RenderNode get result => path.first;
259 262
260 void add(RenderNode node) { 263 void add(RenderNode node) {
261 path.add(node); 264 path.add(node);
262 } 265 }
263 } 266 }
264 267
268
269 // GENERIC MIXIN FOR RENDER NODES WITH ONE CHILD
270
265 abstract class RenderNodeWithChildMixin<ChildType extends RenderNode> { 271 abstract class RenderNodeWithChildMixin<ChildType extends RenderNode> {
266 ChildType _child; 272 ChildType _child;
267 ChildType get child => _child; 273 ChildType get child => _child;
268 void set child (ChildType value) { 274 void set child (ChildType value) {
269 if (_child != null) 275 if (_child != null)
270 dropChild(_child); 276 dropChild(_child);
271 _child = value; 277 _child = value;
272 if (_child != null) 278 if (_child != null)
273 adoptChild(_child); 279 adoptChild(_child);
274 markNeedsLayout(); 280 markNeedsLayout();
275 } 281 }
276 } 282 }
277 283
278 // GENERIC MIXIN FOR RENDER NODES THAT TAKE A LIST OF CHILDREN 284
285 // GENERIC MIXIN FOR RENDER NODES WITH A LIST OF CHILDREN
279 286
280 abstract class ContainerParentDataMixin<ChildType extends RenderNode> { 287 abstract class ContainerParentDataMixin<ChildType extends RenderNode> {
281 ChildType previousSibling; 288 ChildType previousSibling;
282 ChildType nextSibling; 289 ChildType nextSibling;
283 void detachSiblings() { 290 void detachSiblings() {
284 if (previousSibling != null) { 291 if (previousSibling != null) {
285 assert(previousSibling.parentData is ContainerParentDataMixin<ChildType>); 292 assert(previousSibling.parentData is ContainerParentDataMixin<ChildType>);
286 assert(previousSibling != this); 293 assert(previousSibling != this);
287 assert(previousSibling.parentData.nextSibling == this); 294 assert(previousSibling.parentData.nextSibling == this);
288 previousSibling.parentData.nextSibling = nextSibling; 295 previousSibling.parentData.nextSibling = nextSibling;
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
423 assert(child.parentData is ParentDataType); 430 assert(child.parentData is ParentDataType);
424 return child.parentData.nextSibling; 431 return child.parentData.nextSibling;
425 } 432 }
426 433
427 } 434 }
428 435
429 436
430 // GENERIC BOX RENDERING 437 // GENERIC BOX RENDERING
431 // Anything that has a concept of x, y, width, height is going to derive from th is 438 // Anything that has a concept of x, y, width, height is going to derive from th is
432 439
440 class EdgeDims {
441 // used for e.g. padding
442 const EdgeDims(this.top, this.right, this.bottom, this.left);
443 final double top;
444 final double right;
445 final double bottom;
446 final double left;
447 operator ==(EdgeDims other) => (top == other.top) ||
448 (right == other.right) ||
449 (bottom == other.bottom) ||
450 (left == other.left);
451 }
452
433 class BoxConstraints { 453 class BoxConstraints {
434 const BoxConstraints({ 454 const BoxConstraints({
435 this.minWidth: 0.0, 455 this.minWidth: 0.0,
436 this.maxWidth: double.INFINITY, 456 this.maxWidth: double.INFINITY,
437 this.minHeight: 0.0, 457 this.minHeight: 0.0,
438 this.maxHeight: double.INFINITY}); 458 this.maxHeight: double.INFINITY});
439 459
440 const BoxConstraints.tight({ double width: 0.0, double height: 0.0 }) 460 const BoxConstraints.tight({ double width: 0.0, double height: 0.0 })
441 : minWidth = width, 461 : minWidth = width,
442 maxWidth = width, 462 maxWidth = width,
443 minHeight = height, 463 minHeight = height,
444 maxHeight = height; 464 maxHeight = height;
445 465
466 BoxConstraints deflate(EdgeDims edges) {
467 assert(edges != null);
468 return new BoxConstraints(
469 minWidth: minWidth,
470 maxWidth: maxWidth - (edges.left + edges.right),
471 minHeight: minHeight,
472 maxHeight: maxHeight - (edges.top + edges.bottom)
473 );
474 }
475
446 final double minWidth; 476 final double minWidth;
447 final double maxWidth; 477 final double maxWidth;
448 final double minHeight; 478 final double minHeight;
449 final double maxHeight; 479 final double maxHeight;
450 480
451 double constrainWidth(double width) { 481 double constrainWidth(double width) {
452 return clamp(min: minWidth, max: maxWidth, value: width); 482 return clamp(min: minWidth, max: maxWidth, value: width);
453 } 483 }
454 484
455 double constrainHeight(double height) { 485 double constrainHeight(double height) {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
493 return new BoxDimensions.withConstraints(constraints); 523 return new BoxDimensions.withConstraints(constraints);
494 } 524 }
495 525
496 void layout(BoxConstraints constraints, { RenderNode relayoutSubtreeRoot }) { 526 void layout(BoxConstraints constraints, { RenderNode relayoutSubtreeRoot }) {
497 width = constraints.constrainWidth(0.0); 527 width = constraints.constrainWidth(0.0);
498 height = constraints.constrainHeight(0.0); 528 height = constraints.constrainHeight(0.0);
499 layoutDone(); 529 layoutDone();
500 } 530 }
501 531
502 bool hitTest(HitTestResult result, { double x, double y }) { 532 bool hitTest(HitTestResult result, { double x, double y }) {
503 if (x < 0.0 || x >= width || y < 0.0 || y >= height)
504 return false;
505 hitTestChildren(result, x: x, y: y); 533 hitTestChildren(result, x: x, y: y);
506 result.add(this); 534 result.add(this);
507 return true; 535 return true;
508 } 536 }
509 void hitTestChildren(HitTestResult result, { double x, double y }) { } 537 void hitTestChildren(HitTestResult result, { double x, double y }) { }
510 538
511 double width; 539 double width;
512 double height; 540 double height;
513 } 541 }
514 542
543 class RenderPadding extends RenderBox with RenderNodeWithChildMixin<RenderBox> {
544
545 RenderPadding(EdgeDims padding, RenderBox child) {
546 assert(padding != null);
547 this.padding = padding;
548 this.child = child;
549 }
550
551 EdgeDims _padding;
552 EdgeDims get padding => _padding;
553 void set padding (EdgeDims value) {
554 assert(value != null);
555 if (_padding != value) {
556 _padding = value;
557 markNeedsLayout();
558 }
559 }
560
561 BoxDimensions getIntrinsicDimensions(BoxConstraints constraints) {
562 assert(padding != null);
563 constraints = constraints.deflate(padding);
564 if (child == null)
565 return super.getIntrinsicDimensions(constraints);
566 return child.getIntrinsicDimensions(constraints);
567 }
568
569 void layout(BoxConstraints constraints, { RenderNode relayoutSubtreeRoot }) {
570 assert(padding != null);
571 constraints = constraints.deflate(padding);
572 if (child == null) {
573 width = constraints.constrainWidth(padding.left + padding.right);
574 height = constraints.constrainHeight(padding.top + padding.bottom);
575 return;
576 }
577 if (relayoutSubtreeRoot != null)
578 saveRelayoutSubtreeRoot(relayoutSubtreeRoot);
579 else
580 relayoutSubtreeRoot = this;
581 child.layout(constraints, relayoutSubtreeRoot: relayoutSubtreeRoot);
582 assert(child.parentData is BoxParentData);
583 child.parentData.x = padding.left;
584 child.parentData.y = padding.top;
585 width = constraints.constrainWidth(padding.left + child.width + padding.righ t);
586 height = constraints.constrainHeight(padding.top + child.height + padding.bo ttom);
587 }
588
589 void paint(RenderNodeDisplayList canvas) {
590 if (child != null)
591 canvas.paintChild(child, child.parentData.x, child.parentData.y);
592 }
593
594 void hitTestChildren(HitTestResult result, { double x, double y }) {
595 if (child != null) {
596 assert(child.parentData is BoxParentData);
597 if ((x >= child.parentData.x) && (x < child.parentData.x + child.width) &&
598 (y >= child.parentData.y) && (y < child.parentData.y + child.height))
599 child.hitTest(result, x: x+child.parentData.x, y: y+child.parentData.y);
600 }
601 }
602
603 }
604
515 // This must be immutable, because we won't notice when it changes 605 // This must be immutable, because we won't notice when it changes
516 class BoxDecoration { 606 class BoxDecoration {
517 const BoxDecoration({ 607 const BoxDecoration({
518 this.backgroundColor 608 this.backgroundColor
519 }); 609 });
520 610
521 final int backgroundColor; 611 final int backgroundColor;
522 } 612 }
523 613
524 class RenderDecoratedBox extends RenderBox { 614 class RenderDecoratedBox extends RenderBox {
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
606 _width = newWidth; 696 _width = newWidth;
607 _height = newHeight; 697 _height = newHeight;
608 relayout(); 698 relayout();
609 } else { 699 } else {
610 layoutDone(); 700 layoutDone();
611 } 701 }
612 } 702 }
613 703
614 void relayout() { 704 void relayout() {
615 if (child != null) { 705 if (child != null) {
616 child.layout(new BoxConstraints( 706 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); 707 assert(child.width == width);
623 assert(child.height == height); 708 assert(child.height == height);
624 } 709 }
625 layoutDone(); 710 layoutDone();
626 } 711 }
627 712
628 void rotate({ int oldAngle, int newAngle, Duration time }) { 713 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() 714 assert(false); // nobody tells the screen to rotate, the whole rotate() danc e is started from our layout()
630 } 715 }
631 716
632 bool hitTest(HitTestResult result, { double x, double y }) { 717 bool hitTest(HitTestResult result, { double x, double y }) {
633 if (x < 0.0 || x >= width || y < 0.0 || y >= height) 718 if (child != null && x >= 0.0 && x < child.width && y >= 0.0 && y < child.he ight)
634 return false; 719 child.hitTest(result, x: x, y: y);
635 if (child != null) {
636 if (x >= 0.0 && x < child.width && y >= 0.0 && y < child.height)
637 child.hitTest(result, x: x, y: y);
638 }
639 result.add(this); 720 result.add(this);
640 return true; 721 return true;
641 } 722 }
642 723
643 void paint(RenderNodeDisplayList canvas) { 724 void paint(RenderNodeDisplayList canvas) {
644 if (child != null) 725 if (child != null)
645 canvas.paintChild(child, 0.0, 0.0); 726 canvas.paintChild(child, 0.0, 0.0);
646 } 727 }
647 728
648 void paintFrame() { 729 void paintFrame() {
(...skipping 28 matching lines...) Expand all
677 while (child != null) { 758 while (child != null) {
678 assert(child.parentData is BoxParentData); 759 assert(child.parentData is BoxParentData);
679 canvas.paintChild(child, child.parentData.x, child.parentData.y); 760 canvas.paintChild(child, child.parentData.x, child.parentData.y);
680 child = child.parentData.nextSibling; 761 child = child.parentData.nextSibling;
681 } 762 }
682 } 763 }
683 } 764 }
684 765
685 // BLOCK LAYOUT MANAGER 766 // BLOCK LAYOUT MANAGER
686 767
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> { } 768 class BlockParentData extends BoxParentData with ContainerParentDataMixin<Render Box> { }
701 769
702 class RenderBlock extends RenderDecoratedBox with ContainerRenderNodeMixin<Rende rBox, BlockParentData>, 770 class RenderBlock extends RenderDecoratedBox with ContainerRenderNodeMixin<Rende rBox, BlockParentData>,
703 RenderBoxContainerDefaultsMixi n<RenderBox, BlockParentData> { 771 RenderBoxContainerDefaultsMixi n<RenderBox, BlockParentData> {
704 // lays out RenderBox children in a vertical stack 772 // lays out RenderBox children in a vertical stack
705 // uses the maximum width provided by the parent 773 // uses the maximum width provided by the parent
706 // sizes itself to the height of its child stack 774 // sizes itself to the height of its child stack
707 775
708 RenderBlock({ 776 RenderBlock({
709 BoxDecoration decoration, 777 BoxDecoration decoration
710 EdgeDims padding: const EdgeDims(0.0, 0.0, 0.0, 0.0) 778 }) : 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 779
723 void setParentData(RenderBox child) { 780 void setParentData(RenderBox child) {
724 if (child.parentData is! BlockParentData) 781 if (child.parentData is! BlockParentData)
725 child.parentData = new BlockParentData(); 782 child.parentData = new BlockParentData();
726 } 783 }
727 784
728 // override this to report what dimensions you would have if you 785 // override this to report what dimensions you would have if you
729 // were laid out with the given constraints this can walk the tree 786 // 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 787 // 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 788 // dimensions and nothing else (e.g. don't calculate hypothetical
732 // child positions if they're not needed to determine dimensions) 789 // child positions if they're not needed to determine dimensions)
733 BoxDimensions getIntrinsicDimensions(BoxConstraints constraints) { 790 BoxDimensions getIntrinsicDimensions(BoxConstraints constraints) {
734 double outerHeight = _padding.top + _padding.bottom; 791 double outerHeight = 0.0;
735 double outerWidth = constraints.constrainWidth(constraints.maxWidth); 792 double outerWidth = constraints.constrainWidth(constraints.maxWidth);
736 assert(outerWidth < double.INFINITY); 793 assert(outerWidth < double.INFINITY);
737 double innerWidth = outerWidth - (_padding.left + _padding.right); 794 double innerWidth = outerWidth;
738 RenderBox child = firstChild; 795 RenderBox child = firstChild;
739 BoxConstraints innerConstraints = new BoxConstraints(minWidth: innerWidth, 796 BoxConstraints innerConstraints = new BoxConstraints(minWidth: innerWidth,
740 maxWidth: innerWidth); 797 maxWidth: innerWidth);
741 while (child != null) { 798 while (child != null) {
742 outerHeight += child.getIntrinsicDimensions(innerConstraints).height; 799 outerHeight += child.getIntrinsicDimensions(innerConstraints).height;
743 assert(child.parentData is BlockParentData); 800 assert(child.parentData is BlockParentData);
744 child = child.parentData.nextSibling; 801 child = child.parentData.nextSibling;
745 } 802 }
746 803
747 return new BoxDimensions(width: outerWidth, 804 return new BoxDimensions(width: outerWidth,
(...skipping 11 matching lines...) Expand all
759 _constraints = constraints; 816 _constraints = constraints;
760 internalLayout(relayoutSubtreeRoot); 817 internalLayout(relayoutSubtreeRoot);
761 } 818 }
762 819
763 void relayout() { 820 void relayout() {
764 internalLayout(this); 821 internalLayout(this);
765 } 822 }
766 823
767 void internalLayout(RenderNode relayoutSubtreeRoot) { 824 void internalLayout(RenderNode relayoutSubtreeRoot) {
768 assert(_constraints != null); 825 assert(_constraints != null);
769 double y = _padding.top; 826 double y = 0.0;
770 double innerWidth = width - (_padding.left + _padding.right); 827 double innerWidth = width;
771 RenderBox child = firstChild; 828 RenderBox child = firstChild;
772 while (child != null) { 829 while (child != null) {
773 child.layout(new BoxConstraints(minWidth: innerWidth, maxWidth: innerWidth ), 830 child.layout(new BoxConstraints(minWidth: innerWidth, maxWidth: innerWidth ),
774 relayoutSubtreeRoot: relayoutSubtreeRoot); 831 relayoutSubtreeRoot: relayoutSubtreeRoot);
775 assert(child.parentData is BlockParentData); 832 assert(child.parentData is BlockParentData);
776 child.parentData.x = _padding.left; 833 child.parentData.x = 0.0;
777 child.parentData.y = y; 834 child.parentData.y = y;
778 y += child.height; 835 y += child.height;
779 child = child.parentData.nextSibling; 836 child = child.parentData.nextSibling;
780 } 837 }
781 height = _constraints.constrainHeight(y + _padding.bottom); 838 height = _constraints.constrainHeight(y);
782 layoutDone(); 839 layoutDone();
783 } 840 }
784 841
785 void hitTestChildren(HitTestResult result, { double x, double y }) { 842 void hitTestChildren(HitTestResult result, { double x, double y }) {
786 defaultHitTestChildren(result, x: x, y: y); 843 defaultHitTestChildren(result, x: x, y: y);
787 } 844 }
788 845
789 void paint(RenderNodeDisplayList canvas) { 846 void paint(RenderNodeDisplayList canvas) {
790 super.paint(canvas); 847 super.paint(canvas);
791 defaultPaint(canvas); 848 defaultPaint(canvas);
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
917 974
918 void hitTestChildren(HitTestResult result, { double x, double y }) { 975 void hitTestChildren(HitTestResult result, { double x, double y }) {
919 defaultHitTestChildren(result, x: x, y: y); 976 defaultHitTestChildren(result, x: x, y: y);
920 } 977 }
921 978
922 void paint(RenderNodeDisplayList canvas) { 979 void paint(RenderNodeDisplayList canvas) {
923 super.paint(canvas); 980 super.paint(canvas);
924 defaultPaint(canvas); 981 defaultPaint(canvas);
925 } 982 }
926 } 983 }
OLDNEW
« no previous file with comments | « sky/examples/raw/simple_render_tree.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698