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

Unified Diff: sky/sdk/lib/framework/layout2.dart

Issue 1161983004: Refactor layout/relayout into a single method. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 7 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « sky/sdk/lib/framework/fn2.dart ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sky/sdk/lib/framework/layout2.dart
diff --git a/sky/sdk/lib/framework/layout2.dart b/sky/sdk/lib/framework/layout2.dart
index e7e0b6d9a17a0523c52429a29db24b62d12629d2..98a929bc1f27bffee425dd4a0493cac81875e199 100644
--- a/sky/sdk/lib/framework/layout2.dart
+++ b/sky/sdk/lib/framework/layout2.dart
@@ -74,14 +74,11 @@ abstract class RenderNode extends AbstractNode {
bool _needsLayout = true;
bool get needsLayout => _needsLayout;
RenderNode _relayoutSubtreeRoot;
- void saveRelayoutSubtreeRoot(RenderNode relayoutSubtreeRoot) {
- _relayoutSubtreeRoot = relayoutSubtreeRoot;
- assert(_relayoutSubtreeRoot == null || _relayoutSubtreeRoot._relayoutSubtreeRoot == null);
- assert(_relayoutSubtreeRoot == null || _relayoutSubtreeRoot == parent || (parent is RenderNode && _relayoutSubtreeRoot == parent._relayoutSubtreeRoot));
- }
+ dynamic _constraints;
+ dynamic get constraints => _constraints;
bool debugAncestorsAlreadyMarkedNeedsLayout() {
if (_relayoutSubtreeRoot == null)
- return true;
+ return true; // we haven't yet done layout even once, so there's nothing for us to do
RenderNode node = this;
while (node != _relayoutSubtreeRoot) {
assert(node._relayoutSubtreeRoot == _relayoutSubtreeRoot);
@@ -90,7 +87,7 @@ abstract class RenderNode extends AbstractNode {
if (!node._needsLayout)
return false;
}
- assert(node._relayoutSubtreeRoot == null);
+ assert(node._relayoutSubtreeRoot == node);
return true;
}
void markNeedsLayout() {
@@ -101,7 +98,8 @@ abstract class RenderNode extends AbstractNode {
return;
}
_needsLayout = true;
- if (_relayoutSubtreeRoot != null) {
+ assert(_relayoutSubtreeRoot != null);
+ if (_relayoutSubtreeRoot != this) {
assert(parent is RenderNode);
parent.markNeedsLayout();
} else {
@@ -120,8 +118,8 @@ abstract class RenderNode extends AbstractNode {
}
void _doLayout() {
try {
- assert(_relayoutSubtreeRoot == null);
- relayout();
+ assert(_relayoutSubtreeRoot == this);
+ performLayout();
} catch (e, stack) {
print('Exception raised during layout of ${this}: ${e}');
print(stack);
@@ -129,75 +127,36 @@ abstract class RenderNode extends AbstractNode {
}
assert(!_needsLayout); // check that the relayout() method marked us "not dirty"
}
- /* // this method's signature is subclass-specific, but will exist in
- // some form in all subclasses:
- void layout({arguments..., RenderNode relayoutSubtreeRoot}) {
- bool childArgumentsChanged = ...; // true if arguments we're going to pass to the children are different than last time, false otherwise
- if (this node has an opinion about its size, e.g. because it autosizes based on kids, or has an intrinsic dimension) {
- if (relayoutSubtreeRoot != null) {
- saveRelayoutSubtreeRoot(relayoutSubtreeRoot);
- // for each child, if we are going to size ourselves around them:
- if (child.needsLayout || childArgumentsChanged)
- child.layout(... relayoutSubtreeRoot: relayoutSubtreeRoot);
- width = ...;
- height = ...;
- } else {
- saveRelayoutSubtreeRoot(null); // you can skip this if there's no way you would ever have called saveRelayoutSubtreeRoot() before
- // we're the root of the relayout subtree
- // for each child, if we are going to size ourselves around them:
- if (child.needsLayout || childArgumentsChanged)
- child.layout(... relayoutSubtreeRoot: this);
- width = ...;
- height = ...;
- }
- } else {
- // we're sizing ourselves exclusively on input from the parent (arguments to this function)
- // ignore relayoutSubtreeRoot
- saveRelayoutSubtreeRoot(null); // you can skip this if there's no way you would ever have called saveRelayoutSubtreeRoot() before
- width = ...; // based on input from arguments only
- height = ...; // based on input from arguments only
- }
- // for each child whose size we'll ignore when deciding ours:
- if (child.needsLayout || childArgumentsChanged)
- child.layout(... relayoutSubtreeRoot: null); // or just omit relayoutSubtreeRoot
- layoutDone();
- return;
- }
- */
- void relayout() {
+ void layout(dynamic constraints, { bool parentUsesSize: false }) {
+ RenderNode relayoutSubtreeRoot;
+ if (!parentUsesSize || sizedByParent || parent is! RenderNode)
+ relayoutSubtreeRoot = this;
+ else
+ relayoutSubtreeRoot = parent._relayoutSubtreeRoot;
+ if (!needsLayout && constraints == _constraints && relayoutSubtreeRoot == _relayoutSubtreeRoot)
+ return;
+ _constraints = constraints;
+ _relayoutSubtreeRoot = relayoutSubtreeRoot;
+ if (sizedByParent)
+ performResize();
+ performLayout();
+ _needsLayout = false;
+ markNeedsPaint();
+ }
+ bool get sizedByParent => false; // return true if the constraints are the only input to the sizing algorithm (in particular, child nodes have no impact)
+ void performResize(); // set the local dimensions, using only the constraints (only called if sizedByParent is true)
+ void performLayout();
// Override this to perform relayout without your parent's
// involvement.
//
- // This is what is called after the first layout(), if you mark
- // yourself dirty and don't have a _relayoutSubtreeRoot set; in
- // other words, either if your parent doesn't care what size you
- // are (and thus didn't pass a relayoutSubtreeRoot to your
- // layout() method) or if you sized yourself entirely based on
- // what your parents told you, and not based on your children (and
- // thus you never called saveRelayoutSubtreeRoot()).
- //
- // In the former case, you can resize yourself here at will. In
- // the latter case, just leave your dimensions unchanged.
- //
- // If _relayoutSubtreeRoot is set (i.e. you called saveRelayout-
- // SubtreeRoot() in your layout(), with a relayoutSubtreeRoot
- // argument that was non-null), then if you mark yourself as dirty
- // then we'll tell that subtree root instead, and the layout will
- // occur via the layout() tree rather than starting from this
- // relayout() method.
+ // This is called during layout. If sizedByParent is true, then
+ // performLayout() should not change your dimensions, only do that
+ // in performResize(). If sizedByParent is false, then set both
+ // your dimensions and do your children's layout here.
//
- // when calling children's layout() methods, skip any children
- // that have needsLayout == false unless the arguments you are
- // passing in have changed since the last time
- assert(_relayoutSubtreeRoot == null);
- layoutDone();
- }
- void layoutDone({bool needsPaint: true}) {
- // make sure to call this at the end of your layout() or relayout()
- _needsLayout = false;
- if (needsPaint)
- markNeedsPaint();
- }
+ // When calling layout() on your children, pass in
+ // "parentUsesSize: true" if your size or layout is dependent on
+ // your child's size.
// when the parent has rotated (e.g. when the screen has been turned
// 90 degrees), immediately prior to layout() being called for the
@@ -221,7 +180,7 @@ abstract class RenderNode extends AbstractNode {
static bool _debugDoingPaint = false;
void markNeedsPaint() {
assert(!_debugDoingPaint);
- // TODO(abarth): It's very redunant to call this for every node in the
+ // TODO(abarth): It's very redundant to call this for every node in the
// render tree during layout. We should instead compute a summary bit and
// call it once at the end of layout.
sky.view.scheduleFrame();
@@ -523,10 +482,19 @@ abstract class RenderBox extends RenderNode {
return new BoxDimensions.withConstraints(constraints);
}
- void layout(BoxConstraints constraints, { RenderNode relayoutSubtreeRoot }) {
+ BoxConstraints get constraints => super.constraints as BoxConstraints;
+ void performResize() {
+ // default behaviour for subclasses that have sizedByParent = true
width = constraints.constrainWidth(0.0);
height = constraints.constrainHeight(0.0);
- layoutDone();
+ assert(height < double.INFINITY);
+ assert(width < double.INFINITY);
+ }
+ void performLayout() {
+ // descendants have to either override performLayout() to set both
+ // width and height and lay out children, or, set sizedByParent to
+ // true so that performResize()'s logic above does its thing.
+ assert(sizedByParent);
}
bool hitTest(HitTestResult result, { double x, double y }) {
@@ -566,19 +534,15 @@ class RenderPadding extends RenderBox with RenderNodeWithChildMixin<RenderBox> {
return child.getIntrinsicDimensions(constraints);
}
- void layout(BoxConstraints constraints, { RenderNode relayoutSubtreeRoot }) {
+ void performLayout() {
assert(padding != null);
- constraints = constraints.deflate(padding);
+ BoxConstraints innerConstraints = constraints.deflate(padding);
if (child == null) {
- width = constraints.constrainWidth(padding.left + padding.right);
- height = constraints.constrainHeight(padding.top + padding.bottom);
+ width = innerConstraints.constrainWidth(padding.left + padding.right);
+ height = innerConstraints.constrainHeight(padding.top + padding.bottom);
return;
}
- if (relayoutSubtreeRoot != null)
- saveRelayoutSubtreeRoot(relayoutSubtreeRoot);
- else
- relayoutSubtreeRoot = this;
- child.layout(constraints, relayoutSubtreeRoot: relayoutSubtreeRoot);
+ child.layout(innerConstraints, parentUsesSize: true);
assert(child.parentData is BoxParentData);
child.parentData.x = padding.left;
child.parentData.y = padding.top;
@@ -664,6 +628,18 @@ class RenderDecoratedCircle extends RenderDecoratedBox with RenderNodeWithChildM
// RENDER VIEW LAYOUT MANAGER
+class ViewConstraints {
+
+ const ViewConstraints({
+ this.width: 0.0, this.height: 0.0, this.orientation: null
+ });
+
+ final double width;
+ final double height;
+ final int orientation;
+
+}
+
class RenderView extends RenderNode with RenderNodeWithChildMixin<RenderBox> {
RenderView({
@@ -682,36 +658,29 @@ class RenderView extends RenderNode with RenderNodeWithChildMixin<RenderBox> {
int get orientation => _orientation;
Duration timeForRotation;
- void layout({
- double newWidth,
- double newHeight,
- int newOrientation
- }) {
- if (newOrientation != orientation) {
- if (orientation != null && child != null)
- child.rotate(oldAngle: orientation, newAngle: newOrientation, time: timeForRotation);
- _orientation = newOrientation;
- }
- if ((newWidth != width) || (newHeight != height)) {
- _width = newWidth;
- _height = newHeight;
- relayout();
- } else {
- layoutDone();
+ ViewConstraints get constraints => super.constraints as ViewConstraints;
+ bool get sizedByParent => true;
+ void performResize() {
+ if (constraints.orientation != _orientation) {
+ if (_orientation != null && child != null)
+ child.rotate(oldAngle: _orientation, newAngle: constraints.orientation, time: timeForRotation);
+ _orientation = constraints.orientation;
}
+ _width = constraints.width;
+ _height = constraints.height;
+ assert(height < double.INFINITY);
+ assert(width < double.INFINITY);
}
-
- void relayout() {
+ void performLayout() {
if (child != null) {
child.layout(new BoxConstraints.tight(width: width, height: height));
assert(child.width == width);
assert(child.height == height);
}
- layoutDone();
}
void rotate({ int oldAngle, int newAngle, Duration time }) {
- assert(false); // nobody tells the screen to rotate, the whole rotate() dance is started from our layout()
+ assert(false); // nobody tells the screen to rotate, the whole rotate() dance is started from our performResize()
}
bool hitTest(HitTestResult result, { double x, double y }) {
@@ -805,38 +774,22 @@ class RenderBlock extends RenderDecoratedBox with ContainerRenderNodeMixin<Rende
height: constraints.constrainHeight(outerHeight));
}
- BoxConstraints _constraints; // value cached from parent for relayout call
- void layout(BoxConstraints constraints, { RenderNode relayoutSubtreeRoot }) {
- if (relayoutSubtreeRoot != null)
- saveRelayoutSubtreeRoot(relayoutSubtreeRoot);
- else
- relayoutSubtreeRoot = this;
+ void performLayout() {
+ assert(constraints is BoxConstraints);
width = constraints.constrainWidth(constraints.maxWidth);
assert(width < double.INFINITY);
- _constraints = constraints;
- internalLayout(relayoutSubtreeRoot);
- }
-
- void relayout() {
- internalLayout(this);
- }
-
- void internalLayout(RenderNode relayoutSubtreeRoot) {
- assert(_constraints != null);
double y = 0.0;
double innerWidth = width;
RenderBox child = firstChild;
while (child != null) {
- child.layout(new BoxConstraints(minWidth: innerWidth, maxWidth: innerWidth),
- relayoutSubtreeRoot: relayoutSubtreeRoot);
+ child.layout(new BoxConstraints(minWidth: innerWidth, maxWidth: innerWidth), parentUsesSize: true);
assert(child.parentData is BlockParentData);
child.parentData.x = 0.0;
child.parentData.y = y;
y += child.height;
child = child.parentData.nextSibling;
}
- height = _constraints.constrainHeight(y);
- layoutDone();
+ height = constraints.constrainHeight(y);
}
void hitTestChildren(HitTestResult result, { double x, double y }) {
@@ -886,22 +839,12 @@ class RenderFlex extends RenderDecoratedBox with ContainerRenderNodeMixin<Render
child.parentData = new FlexBoxParentData();
}
- BoxConstraints _constraints; // value cached from parent for relayout call
- void layout(BoxConstraints constraints, { RenderNode relayoutSubtreeRoot }) {
- if (relayoutSubtreeRoot != null)
- saveRelayoutSubtreeRoot(relayoutSubtreeRoot);
- else
- relayoutSubtreeRoot = this;
- _constraints = constraints;
+ bool get sizedByParent => true;
+ void performResize() {
width = _constraints.constrainWidth(_constraints.maxWidth);
height = _constraints.constrainHeight(_constraints.maxHeight);
assert(height < double.INFINITY);
assert(width < double.INFINITY);
- internalLayout(relayoutSubtreeRoot);
- }
-
- void relayout() {
- internalLayout(this);
}
int _getFlex(RenderBox child) {
@@ -909,22 +852,21 @@ class RenderFlex extends RenderDecoratedBox with ContainerRenderNodeMixin<Render
return child.parentData.flex != null ? child.parentData.flex : 0;
}
- void internalLayout(RenderNode relayoutSubtreeRoot) {
+ void performLayout() {
// Based on http://www.w3.org/TR/css-flexbox-1/ Section 9.7 Resolving Flexible Lengths
// Steps 1-3. Determine used flex factor, size inflexible items, calculate free space
int totalFlex = 0;
- assert(_constraints != null);
- double freeSpace = (_direction == FlexDirection.Horizontal) ? _constraints.maxWidth : _constraints.maxHeight;
+ assert(constraints != null);
+ double freeSpace = (_direction == FlexDirection.Horizontal) ? constraints.maxWidth : constraints.maxHeight;
RenderBox child = firstChild;
while (child != null) {
int flex = _getFlex(child);
if (flex > 0) {
totalFlex += child.parentData.flex;
} else {
- BoxConstraints constraints = new BoxConstraints(maxHeight: _constraints.maxHeight,
- maxWidth: _constraints.maxWidth);
- child.layout(constraints,
- relayoutSubtreeRoot: relayoutSubtreeRoot);
+ BoxConstraints innerConstraints = new BoxConstraints(maxHeight: constraints.maxHeight,
+ maxWidth: constraints.maxWidth);
+ child.layout(innerConstraints, parentUsesSize: true);
freeSpace -= (_direction == FlexDirection.Horizontal) ? child.width : child.height;
}
child = child.parentData.nextSibling;
@@ -938,20 +880,20 @@ class RenderFlex extends RenderDecoratedBox with ContainerRenderNodeMixin<Render
int flex = _getFlex(child);
if (flex > 0) {
double spaceForChild = spacePerFlex * flex;
- BoxConstraints constraints;
+ BoxConstraints innerConstraints;
switch (_direction) {
case FlexDirection.Horizontal:
- constraints = new BoxConstraints(maxHeight: _constraints.maxHeight,
- minWidth: spaceForChild,
- maxWidth: spaceForChild);
+ innerConstraints = new BoxConstraints(maxHeight: constraints.maxHeight,
+ minWidth: spaceForChild,
+ maxWidth: spaceForChild);
break;
case FlexDirection.Vertical:
- constraints = new BoxConstraints(minHeight: spaceForChild,
- maxHeight: spaceForChild,
- maxWidth: _constraints.maxWidth);
+ innerConstraints = new BoxConstraints(minHeight: spaceForChild,
+ maxHeight: spaceForChild,
+ maxWidth: constraints.maxWidth);
break;
}
- child.layout(constraints, relayoutSubtreeRoot: relayoutSubtreeRoot);
+ child.layout(innerConstraints, parentUsesSize: true);
}
// For now, center the flex items in the cross direction
@@ -959,17 +901,16 @@ class RenderFlex extends RenderDecoratedBox with ContainerRenderNodeMixin<Render
case FlexDirection.Horizontal:
child.parentData.x = usedSpace;
usedSpace += child.width;
- child.parentData.y = height / 2 - child.height / 2;
+ child.parentData.y = height / 2.0 - child.height / 2.0;
break;
case FlexDirection.Vertical:
child.parentData.y = usedSpace;
usedSpace += child.height;
- child.parentData.x = width / 2 - child.width / 2;
+ child.parentData.x = width / 2.0 - child.width / 2.0;
break;
}
child = child.parentData.nextSibling;
}
- layoutDone();
}
void hitTestChildren(HitTestResult result, { double x, double y }) {
« no previous file with comments | « sky/sdk/lib/framework/fn2.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698