diff --git a/examples/raw/render_paragraph.dart b/examples/raw/render_paragraph.dart index 6c20d91db37..519ce32a724 100644 --- a/examples/raw/render_paragraph.dart +++ b/examples/raw/render_paragraph.dart @@ -4,7 +4,10 @@ import 'dart:sky'; import 'package:sky/framework/app.dart'; -import 'package:sky/framework/layout2.dart'; +import 'package:sky/framework/rendering/render_box.dart'; +import 'package:sky/framework/rendering/render_node.dart'; +import 'package:sky/framework/rendering/render_flex.dart'; +import 'package:sky/framework/rendering/render_paragraph.dart'; class RenderSolidColor extends RenderDecoratedBox { final Size desiredSize; @@ -15,7 +18,7 @@ class RenderSolidColor extends RenderDecoratedBox { super(decoration: new BoxDecoration(backgroundColor: backgroundColor)); Size getIntrinsicDimensions(BoxConstraints constraints) { - return constraints.constrain(new Size(desiredWidth, desiredHeight)); + return constraints.constrain(desiredSize); } void performLayout() { diff --git a/examples/raw/sector-layout.dart b/examples/raw/sector_layout.dart similarity index 99% rename from examples/raw/sector-layout.dart rename to examples/raw/sector_layout.dart index c4c4627aba9..9e998a38970 100644 --- a/examples/raw/sector-layout.dart +++ b/examples/raw/sector_layout.dart @@ -5,7 +5,8 @@ import 'dart:math' as math; import 'dart:sky' as sky; import 'package:sky/framework/app.dart'; -import 'package:sky/framework/layout2.dart'; +import 'package:sky/framework/rendering/render_box.dart'; +import 'package:sky/framework/rendering/render_node.dart'; const double kTwoPi = 2 * math.PI; diff --git a/examples/raw/simple_render_tree.dart b/examples/raw/simple_render_tree.dart deleted file mode 100644 index 58d4e934e2e..00000000000 --- a/examples/raw/simple_render_tree.dart +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:sky' as sky; -import 'package:sky/framework/app.dart'; -import 'package:sky/framework/layout2.dart'; - -class RenderSolidColor extends RenderDecoratedBox { - final sky.Size desiredSize; - final int backgroundColor; - - RenderSolidColor(int backgroundColor, { this.desiredSize: const sky.Size.infinite() }) - : backgroundColor = backgroundColor, - super(decoration: new BoxDecoration(backgroundColor: backgroundColor)) { - } - - BoxDimensions getIntrinsicDimensions(BoxConstraints constraints) { - return new BoxDimensions.withConstraints(constraints, - width: desiredSize.width, - height: desiredSize.height); - } - - void performLayout() { - size = constraints.constrain(desiredSize); - } - - void handlePointer(sky.PointerEvent event) { - if (event.type == 'pointerdown') - decoration = new BoxDecoration(backgroundColor: 0xFFFF0000); - else if (event.type == 'pointerup') - decoration = new BoxDecoration(backgroundColor: backgroundColor); - } -} - -AppView app; - -void main() { - RenderFlex flexRoot = new RenderFlex(direction: FlexDirection.Vertical); - - RenderNode root = new RenderDecoratedBox( - decoration: new BoxDecoration(backgroundColor: 0xFF000000), - child: flexRoot - ); - - void addFlexChildSolidColor(RenderFlex parent, int backgroundColor, { int flex: 0 }) { - RenderNode child = new RenderSolidColor(backgroundColor); - parent.add(child); - child.parentData.flex = flex; - } - - // Yellow bar at top - addFlexChildSolidColor(flexRoot, 0xFFFFFF00, flex: 1); - - // Turquoise box - flexRoot.add(new RenderSolidColor(0x7700FFFF, desiredSize: new sky.Size(100.0, 100.0))); - - // Green and cyan render block with padding - var renderBlock = new RenderBlock(); - - renderBlock.add(new RenderSolidColor(0xFF00FF00, desiredSize: new sky.Size(100.0, 50.0))); - renderBlock.add(new RenderSolidColor(0x7700FFFF, desiredSize: new sky.Size(50.0, 100.0))); - - var renderDecoratedBlock = new RenderDecoratedBox( - decoration: new BoxDecoration(backgroundColor: 0xFFFFFFFF), - child: renderBlock - ); - - flexRoot.add(new RenderPadding(const EdgeDims(10.0, 10.0, 10.0, 10.0), renderDecoratedBlock)); - - var row = new RenderFlex(direction: FlexDirection.Horizontal); - - // Purple and blue cells - addFlexChildSolidColor(row, 0x77FF00FF, flex: 1); - addFlexChildSolidColor(row, 0xFF0000FF, flex: 2); - - var decoratedRow = new RenderDecoratedBox( - decoration: new BoxDecoration(backgroundColor: 0xFF333333), - child: row - ); - - flexRoot.add(decoratedRow); - decoratedRow.parentData.flex = 3; - - app = new AppView(root); - -} diff --git a/examples/raw/touch_demo.dart b/examples/raw/touch_demo.dart index e0d4e027b91..b90f86c8290 100644 --- a/examples/raw/touch_demo.dart +++ b/examples/raw/touch_demo.dart @@ -5,7 +5,8 @@ import 'dart:math'; import 'dart:sky'; import 'package:sky/framework/app.dart'; -import 'package:sky/framework/layout2.dart'; +import 'package:sky/framework/rendering/render_box.dart'; +import 'package:sky/framework/rendering/render_node.dart'; // Material design colors. :p List colors = [ diff --git a/examples/stocks2/lib/stock_app.dart b/examples/stocks2/lib/stock_app.dart index 00e4004598b..c9f8de28a2b 100644 --- a/examples/stocks2/lib/stock_app.dart +++ b/examples/stocks2/lib/stock_app.dart @@ -23,7 +23,6 @@ import 'stock_data.dart'; // import 'stock_menu.dart'; import 'dart:async'; -import 'package:sky/framework/layout2.dart'; enum StockMode { Optimistic, Pessimistic } diff --git a/examples/stocks2/lib/stock_arrow.dart b/examples/stocks2/lib/stock_arrow.dart index 9ae135dc0e3..677c323c48b 100644 --- a/examples/stocks2/lib/stock_arrow.dart +++ b/examples/stocks2/lib/stock_arrow.dart @@ -4,7 +4,6 @@ import 'dart:math'; import 'package:sky/framework/fn2.dart'; -import 'package:sky/framework/layout2.dart'; class StockArrow extends Component { static final Style _style = new Style(''' diff --git a/examples/stocks2/lib/stock_menu.dart b/examples/stocks2/lib/stock_menu.dart index ed022fefa2e..aadc3a3d8c6 100644 --- a/examples/stocks2/lib/stock_menu.dart +++ b/examples/stocks2/lib/stock_menu.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'package:sky/framework/fn2.dart'; -import 'package:sky/framework/layout2.dart'; import 'package:sky/framework/components2/popup_menu.dart'; import 'package:sky/framework/components2/checkbox.dart'; import 'package:sky/framework/theme/view_configuration.dart'; diff --git a/examples/stocks2/lib/stock_row.dart b/examples/stocks2/lib/stock_row.dart index a6faa3ea445..99fd8d815f9 100644 --- a/examples/stocks2/lib/stock_row.dart +++ b/examples/stocks2/lib/stock_row.dart @@ -4,7 +4,6 @@ import 'package:sky/framework/components2/ink_well.dart'; import 'package:sky/framework/fn2.dart'; -import 'package:sky/framework/layout2.dart'; import 'package:sky/framework/theme/typography.dart' as typography; import 'stock_arrow.dart'; import 'stock_data.dart'; diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn index e4b74fdcbe1..65d16e0326c 100644 --- a/sdk/BUILD.gn +++ b/sdk/BUILD.gn @@ -92,10 +92,14 @@ dart_pkg("sdk") { "lib/framework/fn.dart", "lib/framework/fn2.dart", "lib/framework/layout.dart", - "lib/framework/layout2.dart", "lib/framework/net/fetch.dart", "lib/framework/node.dart", "lib/framework/reflect.dart", + "lib/framework/rendering/render_block.dart", + "lib/framework/rendering/render_box.dart", + "lib/framework/rendering/render_flex.dart", + "lib/framework/rendering/render_node.dart", + "lib/framework/rendering/render_paragraph.dart", "lib/framework/shell.dart", "lib/framework/theme/colors.dart", "lib/framework/theme/shadows.dart", diff --git a/sdk/lib/framework/app.dart b/sdk/lib/framework/app.dart index cfaa57fec65..0cb8b9460a5 100644 --- a/sdk/lib/framework/app.dart +++ b/sdk/lib/framework/app.dart @@ -2,8 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'layout2.dart'; import 'dart:sky' as sky; +import 'rendering/render_box.dart'; +import 'rendering/render_node.dart'; class AppView { diff --git a/sdk/lib/framework/components2/checkbox.dart b/sdk/lib/framework/components2/checkbox.dart index 85e593b84cb..9df2ff1caea 100644 --- a/sdk/lib/framework/components2/checkbox.dart +++ b/sdk/lib/framework/components2/checkbox.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import '../fn2.dart'; -import '../layout2.dart'; import 'button_base.dart'; import 'dart:sky' as sky; diff --git a/sdk/lib/framework/components2/drawer_header.dart b/sdk/lib/framework/components2/drawer_header.dart index 7709047f1d5..c23eba6f45b 100644 --- a/sdk/lib/framework/components2/drawer_header.dart +++ b/sdk/lib/framework/components2/drawer_header.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import '../fn2.dart'; -import '../layout2.dart'; import '../theme/colors.dart'; import '../theme/view_configuration.dart'; diff --git a/sdk/lib/framework/components2/ink_splash.dart b/sdk/lib/framework/components2/ink_splash.dart index 652d45823d5..ff0c36b2413 100644 --- a/sdk/lib/framework/components2/ink_splash.dart +++ b/sdk/lib/framework/components2/ink_splash.dart @@ -8,7 +8,6 @@ import '../fn2.dart'; import '../theme/view_configuration.dart' as config; import 'dart:async'; import 'dart:math' as math; -import '../layout2.dart'; const double _kSplashConfirmedDuration = 350.0; const double _kSplashUnconfirmedDuration = config.kDefaultLongPressTimeout; diff --git a/sdk/lib/framework/components2/ink_well.dart b/sdk/lib/framework/components2/ink_well.dart index 1b492633b0f..fac4d5fbd1b 100644 --- a/sdk/lib/framework/components2/ink_well.dart +++ b/sdk/lib/framework/components2/ink_well.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import '../fn2.dart'; -import '../layout2.dart'; import 'dart:collection'; import 'dart:sky' as sky; import 'ink_splash.dart'; diff --git a/sdk/lib/framework/components2/input.dart b/sdk/lib/framework/components2/input.dart index d69e76e17b3..087bc14818f 100644 --- a/sdk/lib/framework/components2/input.dart +++ b/sdk/lib/framework/components2/input.dart @@ -6,7 +6,6 @@ import '../editing/editable_string.dart'; import '../editing/editable_text.dart'; import '../editing/keyboard.dart'; import '../fn2.dart'; -import '../layout2.dart'; import '../theme/colors.dart'; import '../theme/typography.dart' as typography; import 'dart:sky' as sky; diff --git a/sdk/lib/framework/components2/menu_item.dart b/sdk/lib/framework/components2/menu_item.dart index 9abae2764c1..99c8de22fd5 100644 --- a/sdk/lib/framework/components2/menu_item.dart +++ b/sdk/lib/framework/components2/menu_item.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import '../fn2.dart'; -import '../layout2.dart'; import 'button_base.dart'; import 'icon.dart'; import 'ink_well.dart'; diff --git a/sdk/lib/framework/components2/scaffold.dart b/sdk/lib/framework/components2/scaffold.dart index 114ea79e958..8d32bf0b91c 100644 --- a/sdk/lib/framework/components2/scaffold.dart +++ b/sdk/lib/framework/components2/scaffold.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import '../fn2.dart'; -import '../layout2.dart'; import '../theme/typography.dart' as typography; import 'dart:sky' as sky; diff --git a/sdk/lib/framework/components2/tool_bar.dart b/sdk/lib/framework/components2/tool_bar.dart index cbcd7957160..f0f3ee443b3 100644 --- a/sdk/lib/framework/components2/tool_bar.dart +++ b/sdk/lib/framework/components2/tool_bar.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import '../fn2.dart'; -import '../layout2.dart'; import '../theme/view_configuration.dart'; import 'material.dart'; diff --git a/sdk/lib/framework/fn2.dart b/sdk/lib/framework/fn2.dart index d9df598ed8f..5305e8765da 100644 --- a/sdk/lib/framework/fn2.dart +++ b/sdk/lib/framework/fn2.dart @@ -9,8 +9,12 @@ import 'dart:collection'; import 'dart:mirrors'; import 'dart:sky' as sky; import 'reflect.dart' as reflect; -import 'layout2.dart'; import 'app.dart'; +import 'rendering/render_block.dart'; +import 'rendering/render_box.dart'; +import 'rendering/render_flex.dart'; +import 'rendering/render_node.dart'; +import 'rendering/render_paragraph.dart'; // final sky.Tracing _tracing = sky.window.tracing; diff --git a/sdk/lib/framework/layout2.dart b/sdk/lib/framework/layout2.dart deleted file mode 100644 index c644c317484..00000000000 --- a/sdk/lib/framework/layout2.dart +++ /dev/null @@ -1,993 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'node.dart'; -import 'dart:sky' as sky; - -// ABSTRACT LAYOUT - -class ParentData { - void detach() { - detachSiblings(); - } - void detachSiblings() { } // workaround for lack of inter-class mixins in Dart - void merge(ParentData other) { - // override this in subclasses to merge in data from other into this - assert(other.runtimeType == this.runtimeType); - } -} - -const kLayoutDirections = 4; - -double clamp({double min: 0.0, double value: 0.0, double max: double.INFINITY}) { - assert(min != null); - assert(value != null); - assert(max != null); - - if (value > max) - value = max; - if (value < min) - value = min; - return value; -} - -class RenderNodeDisplayList extends sky.PictureRecorder { - RenderNodeDisplayList(double width, double height) : super(width, height); - void paintChild(RenderNode child, sky.Point position) { - save(); - translate(position.x, position.y); - child.paint(this); - restore(); - } -} - -abstract class RenderNode extends AbstractNode { - - // LAYOUT - - // parentData is only for use by the RenderNode that actually lays this - // node out, and any other nodes who happen to know exactly what - // kind of node that is. - ParentData parentData; - void setParentData(RenderNode child) { - // override this to setup .parentData correctly for your class - if (child.parentData is! ParentData) - child.parentData = new ParentData(); - } - - void adoptChild(RenderNode child) { // only for use by subclasses - // call this whenever you decide a node is a child - assert(child != null); - setParentData(child); - super.adoptChild(child); - } - void dropChild(RenderNode child) { // only for use by subclasses - assert(child != null); - assert(child.parentData != null); - child.parentData.detach(); - super.dropChild(child); - } - - static List _nodesNeedingLayout = new List(); - static bool _debugDoingLayout = false; - bool _needsLayout = true; - bool get needsLayout => _needsLayout; - RenderNode _relayoutSubtreeRoot; - dynamic _constraints; - dynamic get constraints => _constraints; - bool debugAncestorsAlreadyMarkedNeedsLayout() { - if (_relayoutSubtreeRoot == null) - 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); - assert(node.parent != null); - node = node.parent as RenderNode; - if (!node._needsLayout) - return false; - } - assert(node._relayoutSubtreeRoot == node); - return true; - } - void markNeedsLayout() { - assert(!_debugDoingLayout); - assert(!_debugDoingPaint); - if (_needsLayout) { - assert(debugAncestorsAlreadyMarkedNeedsLayout()); - return; - } - _needsLayout = true; - assert(_relayoutSubtreeRoot != null); - if (_relayoutSubtreeRoot != this) { - assert(parent is RenderNode); - parent.markNeedsLayout(); - } else { - _nodesNeedingLayout.add(this); - } - } - static void flushLayout() { - _debugDoingLayout = true; - List dirtyNodes = _nodesNeedingLayout; - _nodesNeedingLayout = new List(); - dirtyNodes..sort((a, b) => a.depth - b.depth)..forEach((node) { - if (node._needsLayout && node.attached) - node._doLayout(); - }); - _debugDoingLayout = false; - } - void _doLayout() { - try { - assert(_relayoutSubtreeRoot == this); - performLayout(); - } catch (e, stack) { - print('Exception raised during layout of ${this}: ${e}'); - print(stack); - return; - } - _needsLayout = false; - } - 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 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 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 - // new dimensions, rotate() is called with the old and new angles. - // The next time paint() is called, the coordinate space will have - // been rotated N quarter-turns clockwise, where: - // N = newAngle-oldAngle - // ...but the rendering is expected to remain the same, pixel for - // pixel, on the output device. Then, the layout() method or - // equivalent will be invoked. - - void rotate({ - int oldAngle, // 0..3 - int newAngle, // 0..3 - Duration time - }) { } - - - // PAINTING - - static bool _debugDoingPaint = false; - void markNeedsPaint() { - assert(!_debugDoingPaint); - // 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(); - } - void paint(RenderNodeDisplayList canvas) { } - - - // HIT TESTING - - void handlePointer(sky.PointerEvent event) { - // override this if you have a client, to hand it to the client - // override this if you want to do anything with the pointer event - } - - // RenderNode subclasses are expected to have a method like the - // following (with the signature being whatever passes for coordinates - // for this particular class): - // bool hitTest(HitTestResult result, { sky.Point position }) { - // // If (x,y) is not inside this node, then return false. (You - // // can assume that the given coordinate is inside your - // // dimensions. You only need to check this if you're an - // // irregular shape, e.g. if you have a hole.) - // // Otherwise: - // // For each child that intersects x,y, in z-order starting from the top, - // // call hitTest() for that child, passing it /result/, and the coordinates - // // converted to the child's coordinate origin, and stop at the first child - // // that returns true. - // // Then, add yourself to /result/, and return true. - // } - // You must not add yourself to /result/ if you return false. - -} - -class HitTestResult { - final List path = new List(); - - RenderNode get result => path.first; - - void add(RenderNode node) { - path.add(node); - } -} - - -// GENERIC MIXIN FOR RENDER NODES WITH ONE CHILD - -abstract class RenderNodeWithChildMixin { - ChildType _child; - ChildType get child => _child; - void set child (ChildType value) { - if (_child != null) - dropChild(_child); - _child = value; - if (_child != null) - adoptChild(_child); - markNeedsLayout(); - } -} - - -// GENERIC MIXIN FOR RENDER NODES WITH A LIST OF CHILDREN - -abstract class ContainerParentDataMixin { - ChildType previousSibling; - ChildType nextSibling; - void detachSiblings() { - if (previousSibling != null) { - assert(previousSibling.parentData is ContainerParentDataMixin); - assert(previousSibling != this); - assert(previousSibling.parentData.nextSibling == this); - previousSibling.parentData.nextSibling = nextSibling; - } - if (nextSibling != null) { - assert(nextSibling.parentData is ContainerParentDataMixin); - assert(nextSibling != this); - assert(nextSibling.parentData.previousSibling == this); - nextSibling.parentData.previousSibling = previousSibling; - } - previousSibling = null; - nextSibling = null; - } -} - -abstract class ContainerRenderNodeMixin> implements RenderNode { - // abstract class that has only InlineNode children - - bool _debugUltimatePreviousSiblingOf(ChildType child, { ChildType equals }) { - assert(child.parentData is ParentDataType); - while (child.parentData.previousSibling != null) { - assert(child.parentData.previousSibling != child); - child = child.parentData.previousSibling; - assert(child.parentData is ParentDataType); - } - return child == equals; - } - bool _debugUltimateNextSiblingOf(ChildType child, { ChildType equals }) { - assert(child.parentData is ParentDataType); - while (child.parentData.nextSibling != null) { - assert(child.parentData.nextSibling != child); - child = child.parentData.nextSibling; - assert(child.parentData is ParentDataType); - } - return child == equals; - } - - ChildType _firstChild; - ChildType _lastChild; - void add(ChildType child, { ChildType before }) { - assert(child != this); - assert(before != this); - assert(child != before); - assert(child != _firstChild); - assert(child != _lastChild); - adoptChild(child); - assert(child.parentData is ParentDataType); - assert(child.parentData.nextSibling == null); - assert(child.parentData.previousSibling == null); - if (before == null) { - // append at the end (_lastChild) - child.parentData.previousSibling = _lastChild; - if (_lastChild != null) { - assert(_lastChild.parentData is ParentDataType); - _lastChild.parentData.nextSibling = child; - } - _lastChild = child; - if (_firstChild == null) - _firstChild = child; - } else { - assert(_firstChild != null); - assert(_lastChild != null); - assert(_debugUltimatePreviousSiblingOf(before, equals: _firstChild)); - assert(_debugUltimateNextSiblingOf(before, equals: _lastChild)); - assert(before.parentData is ParentDataType); - if (before.parentData.previousSibling == null) { - // insert at the start (_firstChild); we'll end up with two or more children - assert(before == _firstChild); - child.parentData.nextSibling = before; - before.parentData.previousSibling = child; - _firstChild = child; - } else { - // insert in the middle; we'll end up with three or more children - // set up links from child to siblings - child.parentData.previousSibling = before.parentData.previousSibling; - child.parentData.nextSibling = before; - // set up links from siblings to child - assert(child.parentData.previousSibling.parentData is ParentDataType); - assert(child.parentData.nextSibling.parentData is ParentDataType); - child.parentData.previousSibling.parentData.nextSibling = child; - child.parentData.nextSibling.parentData.previousSibling = child; - assert(before.parentData.previousSibling == child); - } - } - markNeedsLayout(); - } - void remove(ChildType child) { - assert(child.parentData is ParentDataType); - assert(_debugUltimatePreviousSiblingOf(child, equals: _firstChild)); - assert(_debugUltimateNextSiblingOf(child, equals: _lastChild)); - if (child.parentData.previousSibling == null) { - assert(_firstChild == child); - _firstChild = child.parentData.nextSibling; - } else { - assert(child.parentData.previousSibling.parentData is ParentDataType); - child.parentData.previousSibling.parentData.nextSibling = child.parentData.nextSibling; - } - if (child.parentData.nextSibling == null) { - assert(_lastChild == child); - _lastChild = child.parentData.previousSibling; - } else { - assert(child.parentData.nextSibling.parentData is ParentDataType); - child.parentData.nextSibling.parentData.previousSibling = child.parentData.previousSibling; - } - child.parentData.previousSibling = null; - child.parentData.nextSibling = null; - dropChild(child); - markNeedsLayout(); - } - void redepthChildren() { - ChildType child = _firstChild; - while (child != null) { - redepthChild(child); - assert(child.parentData is ParentDataType); - child = child.parentData.nextSibling; - } - } - void attachChildren() { - ChildType child = _firstChild; - while (child != null) { - child.attach(); - assert(child.parentData is ParentDataType); - child = child.parentData.nextSibling; - } - } - void detachChildren() { - ChildType child = _firstChild; - while (child != null) { - child.detach(); - assert(child.parentData is ParentDataType); - child = child.parentData.nextSibling; - } - } - - ChildType get firstChild => _firstChild; - ChildType get lastChild => _lastChild; - ChildType childAfter(ChildType child) { - assert(child.parentData is ParentDataType); - return child.parentData.nextSibling; - } - -} - - -// GENERIC BOX RENDERING -// Anything that has a concept of x, y, width, height is going to derive from this - -class EdgeDims { - // used for e.g. padding - const EdgeDims(this.top, this.right, this.bottom, this.left); - final double top; - final double right; - final double bottom; - final double left; - operator ==(EdgeDims other) => (top == other.top) || - (right == other.right) || - (bottom == other.bottom) || - (left == other.left); -} - -class BoxConstraints { - const BoxConstraints({ - this.minWidth: 0.0, - this.maxWidth: double.INFINITY, - this.minHeight: 0.0, - this.maxHeight: double.INFINITY}); - - BoxConstraints.tight(sky.Size size) - : minWidth = size.width, - maxWidth = size.width, - minHeight = size.height, - maxHeight = size.height; - - BoxConstraints deflate(EdgeDims edges) { - assert(edges != null); - return new BoxConstraints( - minWidth: minWidth, - maxWidth: maxWidth - (edges.left + edges.right), - minHeight: minHeight, - maxHeight: maxHeight - (edges.top + edges.bottom) - ); - } - - final double minWidth; - final double maxWidth; - final double minHeight; - final double maxHeight; - - double constrainWidth(double width) { - return clamp(min: minWidth, max: maxWidth, value: width); - } - - double constrainHeight(double height) { - return clamp(min: minHeight, max: maxHeight, value: height); - } - - sky.Size constrain(sky.Size size) { - return new sky.Size(constrainWidth(size.width), constrainHeight(size.height)); - } - - bool get isInfinite => maxWidth >= double.INFINITY || maxHeight >= double.INFINITY; -} - -class BoxParentData extends ParentData { - sky.Point position = new sky.Point(0.0, 0.0); -} - -abstract class RenderBox extends RenderNode { - - void setParentData(RenderNode child) { - if (child.parentData is! BoxParentData) - child.parentData = new BoxParentData(); - } - - // override this to report what dimensions you would have if you - // were laid out with the given constraints this can walk the tree - // if it must, but it should be as cheap as possible; just get the - // dimensions and nothing else (e.g. don't calculate hypothetical - // child positions if they're not needed to determine dimensions) - sky.Size getIntrinsicDimensions(BoxConstraints constraints) { - return constraints.constrain(new sky.Size(0.0, 0.0)); - } - - BoxConstraints get constraints => super.constraints as BoxConstraints; - void performResize() { - // default behaviour for subclasses that have sizedByParent = true - size = constraints.constrain(new sky.Size(0.0, 0.0)); - assert(size.height < double.INFINITY); - assert(size.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, { sky.Point position }) { - hitTestChildren(result, position: position); - result.add(this); - return true; - } - void hitTestChildren(HitTestResult result, { sky.Point position }) { } - - sky.Size size = new sky.Size(0.0, 0.0); -} - -abstract class RenderProxyBox extends RenderBox with RenderNodeWithChildMixin { - RenderProxyBox(RenderBox child) { - this.child = child; - } - - sky.Size getIntrinsicDimensions(BoxConstraints constraints) { - if (child != null) - return child.getIntrinsicDimensions(constraints); - return super.getIntrinsicDimensions(constraints); - } - - void performLayout() { - if (child != null) { - child.layout(constraints, parentUsesSize: true); - size = child.size; - } else { - performResize(); - } - } - - void hitTestChildren(HitTestResult result, { sky.Point position }) { - if (child != null) - child.hitTest(result, position: position); - else - super.hitTestChildren(result, position: position); - } - - void paint(RenderNodeDisplayList canvas) { - if (child != null) - child.paint(canvas); - } -} - -class RenderSizedBox extends RenderProxyBox { - final sky.Size desiredSize; - - RenderSizedBox({ - RenderBox child, - this.desiredSize: const sky.Size.infinite() - }) : super(child); - - sky.Size getIntrinsicDimensions(BoxConstraints constraints) { - return constraints.constrain(desiredSize); - } - - void performLayout() { - size = constraints.constrain(desiredSize); - child.layout(new BoxConstraints.tight(size)); - } -} - -class RenderPadding extends RenderBox with RenderNodeWithChildMixin { - - RenderPadding(EdgeDims padding, RenderBox child) { - assert(padding != null); - this.padding = padding; - this.child = child; - } - - EdgeDims _padding; - EdgeDims get padding => _padding; - void set padding (EdgeDims value) { - assert(value != null); - if (_padding != value) { - _padding = value; - markNeedsLayout(); - } - } - - sky.Size getIntrinsicDimensions(BoxConstraints constraints) { - assert(padding != null); - constraints = constraints.deflate(padding); - if (child == null) - return super.getIntrinsicDimensions(constraints); - return child.getIntrinsicDimensions(constraints); - } - - void performLayout() { - assert(padding != null); - BoxConstraints innerConstraints = constraints.deflate(padding); - if (child == null) { - size = innerConstraints.constrain( - new sky.Size(padding.left + padding.right, padding.top + padding.bottom)); - return; - } - child.layout(innerConstraints, parentUsesSize: true); - assert(child.parentData is BoxParentData); - child.parentData.position = new sky.Point(padding.left, padding.top); - size = constraints.constrain(new sky.Size(padding.left + child.size.width + padding.right, - padding.top + child.size.height + padding.bottom)); - } - - void paint(RenderNodeDisplayList canvas) { - if (child != null) - canvas.paintChild(child, child.parentData.position); - } - - void hitTestChildren(HitTestResult result, { sky.Point position }) { - if (child != null) { - assert(child.parentData is BoxParentData); - sky.Rect childBounds = new sky.Rect.fromPointAndSize(child.parentData.position, child.size); - if (childBounds.contains(position)) { - child.hitTest(result, position: new sky.Point(position.x - child.parentData.position.x, - position.y - child.parentData.position.y)); - } - } - } - -} - -// This must be immutable, because we won't notice when it changes -class BoxDecoration { - const BoxDecoration({ - this.backgroundColor - }); - - final int backgroundColor; -} - -class RenderDecoratedBox extends RenderProxyBox { - - RenderDecoratedBox({ - BoxDecoration decoration, - RenderBox child - }) : _decoration = decoration, super(child); - - BoxDecoration _decoration; - BoxDecoration get decoration => _decoration; - void set decoration (BoxDecoration value) { - if (value == _decoration) - return; - _decoration = value; - markNeedsPaint(); - } - - void paint(RenderNodeDisplayList canvas) { - assert(size.width != null); - assert(size.height != null); - - if (_decoration == null) - return; - - if (_decoration.backgroundColor != null) { - sky.Paint paint = new sky.Paint()..color = _decoration.backgroundColor; - canvas.drawRect(new sky.Rect.fromLTRB(0.0, 0.0, size.width, size.height), paint); - } - super.paint(canvas); - } - -} - - -// 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 { - - RenderView({ - RenderBox child, - this.timeForRotation: const Duration(microseconds: 83333) - }) { - this.child = child; - } - - sky.Size _size = new sky.Size(0.0, 0.0); - double get width => _size.width; - double get height => _size.height; - - int _orientation; // 0..3 - int get orientation => _orientation; - Duration timeForRotation; - - 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; - } - _size = new sky.Size(constraints.width, constraints.height); - assert(_size.height < double.INFINITY); - assert(_size.width < double.INFINITY); - } - void performLayout() { - if (child != null) { - child.layout(new BoxConstraints.tight(_size)); - assert(child.size.width == width); - assert(child.size.height == height); - } - } - - void rotate({ int oldAngle, int newAngle, Duration time }) { - assert(false); // nobody tells the screen to rotate, the whole rotate() dance is started from our performResize() - } - - bool hitTest(HitTestResult result, { sky.Point position }) { - if (child != null) { - sky.Rect childBounds = new sky.Rect.fromSize(child.size); - if (childBounds.contains(position)) - child.hitTest(result, position: position); - } - result.add(this); - return true; - } - - void paint(RenderNodeDisplayList canvas) { - if (child != null) - canvas.paintChild(child, new sky.Point(0.0, 0.0)); - } - - void paintFrame() { - RenderNode._debugDoingPaint = true; - var canvas = new RenderNodeDisplayList(sky.view.width, sky.view.height); - paint(canvas); - sky.view.picture = canvas.endRecording(); - RenderNode._debugDoingPaint = false; - } - -} - -// DEFAULT BEHAVIORS FOR RENDERBOX CONTAINERS -abstract class RenderBoxContainerDefaultsMixin> implements ContainerRenderNodeMixin { - - void defaultHitTestChildren(HitTestResult result, { sky.Point position }) { - // the x, y parameters have the top left of the node's box as the origin - ChildType child = lastChild; - while (child != null) { - assert(child.parentData is BoxParentData); - sky.Rect childBounds = new sky.Rect.fromPointAndSize(child.parentData.position, child.size); - if (childBounds.contains(position)) { - if (child.hitTest(result, position: new sky.Point(position.x - child.parentData.position.x, - position.y - child.parentData.position.y))) - break; - } - child = child.parentData.previousSibling; - } - } - - void defaultPaint(RenderNodeDisplayList canvas) { - RenderBox child = firstChild; - while (child != null) { - assert(child.parentData is BoxParentData); - canvas.paintChild(child, child.parentData.position); - child = child.parentData.nextSibling; - } - } -} - -// BLOCK LAYOUT MANAGER - -class BlockParentData extends BoxParentData with ContainerParentDataMixin { } - -class RenderBlock extends RenderBox with ContainerRenderNodeMixin, - RenderBoxContainerDefaultsMixin { - // lays out RenderBox children in a vertical stack - // uses the maximum width provided by the parent - // sizes itself to the height of its child stack - - void setParentData(RenderBox child) { - if (child.parentData is! BlockParentData) - child.parentData = new BlockParentData(); - } - - // override this to report what dimensions you would have if you - // were laid out with the given constraints this can walk the tree - // if it must, but it should be as cheap as possible; just get the - // dimensions and nothing else (e.g. don't calculate hypothetical - // child positions if they're not needed to determine dimensions) - sky.Size getIntrinsicDimensions(BoxConstraints constraints) { - double height = 0.0; - double width = constraints.constrainWidth(constraints.maxWidth); - assert(width < double.INFINITY); - RenderBox child = firstChild; - BoxConstraints innerConstraints = new BoxConstraints(minWidth: width, - maxWidth: width); - while (child != null) { - height += child.getIntrinsicDimensions(innerConstraints).height; - assert(child.parentData is BlockParentData); - child = child.parentData.nextSibling; - } - - return new sky.Size(width, constraints.constrainHeight(height)); - } - - void performLayout() { - assert(constraints is BoxConstraints); - double width = constraints.constrainWidth(constraints.maxWidth); - double y = 0.0; - RenderBox child = firstChild; - while (child != null) { - child.layout(new BoxConstraints(minWidth: width, maxWidth: width), parentUsesSize: true); - assert(child.parentData is BlockParentData); - child.parentData.position = new sky.Point(0.0, y); - y += child.size.height; - child = child.parentData.nextSibling; - } - size = new sky.Size(width, constraints.constrainHeight(y)); - assert(size.width < double.INFINITY); - assert(size.height < double.INFINITY); - } - - void hitTestChildren(HitTestResult result, { sky.Point position }) { - defaultHitTestChildren(result, position: position); - } - - void paint(RenderNodeDisplayList canvas) { - defaultPaint(canvas); - } - -} - -// FLEXBOX LAYOUT MANAGER - -class FlexBoxParentData extends BoxParentData with ContainerParentDataMixin { - int flex; - void merge(FlexBoxParentData other) { - if (other.flex != null) - flex = other.flex; - super.merge(other); - } -} - -enum FlexDirection { Horizontal, Vertical } - -class RenderFlex extends RenderBox with ContainerRenderNodeMixin, - RenderBoxContainerDefaultsMixin { - // lays out RenderBox children using flexible layout - - RenderFlex({ - FlexDirection direction: FlexDirection.Horizontal - }) : _direction = direction; - - FlexDirection _direction; - FlexDirection get direction => _direction; - void set direction (FlexDirection value) { - if (_direction != value) { - _direction = value; - markNeedsLayout(); - } - } - - void setParentData(RenderBox child) { - if (child.parentData is! FlexBoxParentData) - child.parentData = new FlexBoxParentData(); - } - - bool get sizedByParent => true; - void performResize() { - size = _constraints.constrain(new sky.Size(_constraints.maxWidth, _constraints.maxHeight)); - assert(size.height < double.INFINITY); - assert(size.width < double.INFINITY); - } - - int _getFlex(RenderBox child) { - assert(child.parentData is FlexBoxParentData); - return child.parentData.flex != null ? child.parentData.flex : 0; - } - - 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; - RenderBox child = firstChild; - while (child != null) { - int flex = _getFlex(child); - if (flex > 0) { - totalFlex += child.parentData.flex; - } else { - BoxConstraints innerConstraints = new BoxConstraints(maxHeight: constraints.maxHeight, - maxWidth: constraints.maxWidth); - child.layout(innerConstraints, parentUsesSize: true); - freeSpace -= (_direction == FlexDirection.Horizontal) ? child.size.width : child.size.height; - } - child = child.parentData.nextSibling; - } - - // Steps 4-5. Distribute remaining space to flexible children. - double spacePerFlex = totalFlex > 0 ? (freeSpace / totalFlex) : 0.0; - double usedSpace = 0.0; - child = firstChild; - while (child != null) { - int flex = _getFlex(child); - if (flex > 0) { - double spaceForChild = spacePerFlex * flex; - BoxConstraints innerConstraints; - switch (_direction) { - case FlexDirection.Horizontal: - innerConstraints = new BoxConstraints(maxHeight: constraints.maxHeight, - minWidth: spaceForChild, - maxWidth: spaceForChild); - break; - case FlexDirection.Vertical: - innerConstraints = new BoxConstraints(minHeight: spaceForChild, - maxHeight: spaceForChild, - maxWidth: constraints.maxWidth); - break; - } - child.layout(innerConstraints, parentUsesSize: true); - } - - // For now, center the flex items in the cross direction - switch (_direction) { - case FlexDirection.Horizontal: - child.parentData.position = new sky.Point(usedSpace, size.height / 2.0 - child.size.height / 2.0); - usedSpace += child.size.width; - break; - case FlexDirection.Vertical: - child.parentData.position = new sky.Point(size.width / 2.0 - child.size.width / 2.0, usedSpace); - usedSpace += child.size.height; - break; - } - child = child.parentData.nextSibling; - } - } - - void hitTestChildren(HitTestResult result, { sky.Point position }) { - defaultHitTestChildren(result, position: position); - } - - void paint(RenderNodeDisplayList canvas) { - defaultPaint(canvas); - } -} - -class RenderInline extends RenderNode { - String data; - - RenderInline(this.data); -} - -class RenderParagraph extends RenderBox { - - RenderParagraph({ - String text, - int color - }) : _color = color { - _layoutRoot.rootElement = _document.createElement('p'); - this.text = text; - } - - final sky.Document _document = new sky.Document(); - final sky.LayoutRoot _layoutRoot = new sky.LayoutRoot(); - - String get text => (_layoutRoot.rootElement.firstChild as sky.Text).data; - void set text (String value) { - _layoutRoot.rootElement.setChild(_document.createText(value)); - markNeedsLayout(); - } - - int _color = 0xFF000000; - int get color => _color; - void set color (int value) { - if (_color != value) { - _color = value; - markNeedsPaint(); - } - } - - sky.Size getIntrinsicDimensions(BoxConstraints constraints) { - assert(false); - return null; - // we don't currently support this for RenderParagraph - } - - void performLayout() { - _layoutRoot.maxWidth = constraints.maxWidth; - _layoutRoot.minWidth = constraints.minWidth; - _layoutRoot.minHeight = constraints.minHeight; - _layoutRoot.maxHeight = constraints.maxHeight; - _layoutRoot.layout(); - size = constraints.constrain(new sky.Size(_layoutRoot.rootElement.width, _layoutRoot.rootElement.height)); - } - - void paint(RenderNodeDisplayList canvas) { - // _layoutRoot.rootElement.style['color'] = 'rgba(' + ...color... + ')'; - _layoutRoot.paint(canvas); - } - - // we should probably expose a way to do precise (inter-glpyh) hit testing - -} diff --git a/sdk/lib/framework/rendering/render_block.dart b/sdk/lib/framework/rendering/render_block.dart new file mode 100644 index 00000000000..065e2110fd6 --- /dev/null +++ b/sdk/lib/framework/rendering/render_block.dart @@ -0,0 +1,69 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:sky' as sky; +import 'render_box.dart'; +import 'render_node.dart'; + +class BlockParentData extends BoxParentData with ContainerParentDataMixin { } + +class RenderBlock extends RenderBox with ContainerRenderNodeMixin, + RenderBoxContainerDefaultsMixin { + // lays out RenderBox children in a vertical stack + // uses the maximum width provided by the parent + // sizes itself to the height of its child stack + + void setParentData(RenderBox child) { + if (child.parentData is! BlockParentData) + child.parentData = new BlockParentData(); + } + + // override this to report what dimensions you would have if you + // were laid out with the given constraints this can walk the tree + // if it must, but it should be as cheap as possible; just get the + // dimensions and nothing else (e.g. don't calculate hypothetical + // child positions if they're not needed to determine dimensions) + sky.Size getIntrinsicDimensions(BoxConstraints constraints) { + double height = 0.0; + double width = constraints.constrainWidth(constraints.maxWidth); + assert(width < double.INFINITY); + RenderBox child = firstChild; + BoxConstraints innerConstraints = new BoxConstraints(minWidth: width, + maxWidth: width); + while (child != null) { + height += child.getIntrinsicDimensions(innerConstraints).height; + assert(child.parentData is BlockParentData); + child = child.parentData.nextSibling; + } + + return new sky.Size(width, constraints.constrainHeight(height)); + } + + void performLayout() { + assert(constraints is BoxConstraints); + double width = constraints.constrainWidth(constraints.maxWidth); + double y = 0.0; + RenderBox child = firstChild; + while (child != null) { + child.layout(new BoxConstraints(minWidth: width, maxWidth: width), parentUsesSize: true); + assert(child.parentData is BlockParentData); + child.parentData.position = new sky.Point(0.0, y); + y += child.size.height; + child = child.parentData.nextSibling; + } + size = new sky.Size(width, constraints.constrainHeight(y)); + assert(size.width < double.INFINITY); + assert(size.height < double.INFINITY); + } + + void hitTestChildren(HitTestResult result, { sky.Point position }) { + defaultHitTestChildren(result, position: position); + } + + void paint(RenderNodeDisplayList canvas) { + defaultPaint(canvas); + } + +} + diff --git a/sdk/lib/framework/rendering/render_box.dart b/sdk/lib/framework/rendering/render_box.dart new file mode 100644 index 00000000000..a3d47124bd5 --- /dev/null +++ b/sdk/lib/framework/rendering/render_box.dart @@ -0,0 +1,369 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'render_node.dart'; +import 'dart:sky' as sky; + +// GENERIC BOX RENDERING +// Anything that has a concept of x, y, width, height is going to derive from this + +class EdgeDims { + // used for e.g. padding + const EdgeDims(this.top, this.right, this.bottom, this.left); + final double top; + final double right; + final double bottom; + final double left; + operator ==(EdgeDims other) => (top == other.top) || + (right == other.right) || + (bottom == other.bottom) || + (left == other.left); +} + +class BoxConstraints { + const BoxConstraints({ + this.minWidth: 0.0, + this.maxWidth: double.INFINITY, + this.minHeight: 0.0, + this.maxHeight: double.INFINITY}); + + BoxConstraints.tight(sky.Size size) + : minWidth = size.width, + maxWidth = size.width, + minHeight = size.height, + maxHeight = size.height; + + BoxConstraints deflate(EdgeDims edges) { + assert(edges != null); + return new BoxConstraints( + minWidth: minWidth, + maxWidth: maxWidth - (edges.left + edges.right), + minHeight: minHeight, + maxHeight: maxHeight - (edges.top + edges.bottom) + ); + } + + final double minWidth; + final double maxWidth; + final double minHeight; + final double maxHeight; + + double constrainWidth(double width) { + return clamp(min: minWidth, max: maxWidth, value: width); + } + + double constrainHeight(double height) { + return clamp(min: minHeight, max: maxHeight, value: height); + } + + sky.Size constrain(sky.Size size) { + return new sky.Size(constrainWidth(size.width), constrainHeight(size.height)); + } + + bool get isInfinite => maxWidth >= double.INFINITY || maxHeight >= double.INFINITY; +} + +class BoxParentData extends ParentData { + sky.Point position = new sky.Point(0.0, 0.0); +} + +abstract class RenderBox extends RenderNode { + + void setParentData(RenderNode child) { + if (child.parentData is! BoxParentData) + child.parentData = new BoxParentData(); + } + + // override this to report what dimensions you would have if you + // were laid out with the given constraints this can walk the tree + // if it must, but it should be as cheap as possible; just get the + // dimensions and nothing else (e.g. don't calculate hypothetical + // child positions if they're not needed to determine dimensions) + sky.Size getIntrinsicDimensions(BoxConstraints constraints) { + return constraints.constrain(new sky.Size(0.0, 0.0)); + } + + BoxConstraints get constraints => super.constraints as BoxConstraints; + void performResize() { + // default behaviour for subclasses that have sizedByParent = true + size = constraints.constrain(new sky.Size(0.0, 0.0)); + assert(size.height < double.INFINITY); + assert(size.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, { sky.Point position }) { + hitTestChildren(result, position: position); + result.add(this); + return true; + } + void hitTestChildren(HitTestResult result, { sky.Point position }) { } + + sky.Size size = new sky.Size(0.0, 0.0); +} + +abstract class RenderProxyBox extends RenderBox with RenderNodeWithChildMixin { + RenderProxyBox(RenderBox child) { + this.child = child; + } + + sky.Size getIntrinsicDimensions(BoxConstraints constraints) { + if (child != null) + return child.getIntrinsicDimensions(constraints); + return super.getIntrinsicDimensions(constraints); + } + + void performLayout() { + if (child != null) { + child.layout(constraints, parentUsesSize: true); + size = child.size; + } else { + performResize(); + } + } + + void hitTestChildren(HitTestResult result, { sky.Point position }) { + if (child != null) + child.hitTest(result, position: position); + else + super.hitTestChildren(result, position: position); + } + + void paint(RenderNodeDisplayList canvas) { + if (child != null) + child.paint(canvas); + } +} + +class RenderSizedBox extends RenderProxyBox { + final sky.Size desiredSize; + + RenderSizedBox({ + RenderBox child, + this.desiredSize: const sky.Size.infinite() + }) : super(child); + + sky.Size getIntrinsicDimensions(BoxConstraints constraints) { + return constraints.constrain(desiredSize); + } + + void performLayout() { + size = constraints.constrain(desiredSize); + child.layout(new BoxConstraints.tight(size)); + } +} + +class RenderPadding extends RenderBox with RenderNodeWithChildMixin { + + RenderPadding(EdgeDims padding, RenderBox child) { + assert(padding != null); + this.padding = padding; + this.child = child; + } + + EdgeDims _padding; + EdgeDims get padding => _padding; + void set padding (EdgeDims value) { + assert(value != null); + if (_padding != value) { + _padding = value; + markNeedsLayout(); + } + } + + sky.Size getIntrinsicDimensions(BoxConstraints constraints) { + assert(padding != null); + constraints = constraints.deflate(padding); + if (child == null) + return super.getIntrinsicDimensions(constraints); + return child.getIntrinsicDimensions(constraints); + } + + void performLayout() { + assert(padding != null); + BoxConstraints innerConstraints = constraints.deflate(padding); + if (child == null) { + size = innerConstraints.constrain( + new sky.Size(padding.left + padding.right, padding.top + padding.bottom)); + return; + } + child.layout(innerConstraints, parentUsesSize: true); + assert(child.parentData is BoxParentData); + child.parentData.position = new sky.Point(padding.left, padding.top); + size = constraints.constrain(new sky.Size(padding.left + child.size.width + padding.right, + padding.top + child.size.height + padding.bottom)); + } + + void paint(RenderNodeDisplayList canvas) { + if (child != null) + canvas.paintChild(child, child.parentData.position); + } + + void hitTestChildren(HitTestResult result, { sky.Point position }) { + if (child != null) { + assert(child.parentData is BoxParentData); + sky.Rect childBounds = new sky.Rect.fromPointAndSize(child.parentData.position, child.size); + if (childBounds.contains(position)) { + child.hitTest(result, position: new sky.Point(position.x - child.parentData.position.x, + position.y - child.parentData.position.y)); + } + } + } + +} + +// This must be immutable, because we won't notice when it changes +class BoxDecoration { + const BoxDecoration({ + this.backgroundColor + }); + + final int backgroundColor; +} + +class RenderDecoratedBox extends RenderProxyBox { + + RenderDecoratedBox({ + BoxDecoration decoration, + RenderBox child + }) : _decoration = decoration, super(child); + + BoxDecoration _decoration; + BoxDecoration get decoration => _decoration; + void set decoration (BoxDecoration value) { + if (value == _decoration) + return; + _decoration = value; + markNeedsPaint(); + } + + void paint(RenderNodeDisplayList canvas) { + assert(size.width != null); + assert(size.height != null); + + if (_decoration == null) + return; + + if (_decoration.backgroundColor != null) { + sky.Paint paint = new sky.Paint()..color = _decoration.backgroundColor; + canvas.drawRect(new sky.Rect.fromLTRB(0.0, 0.0, size.width, size.height), paint); + } + super.paint(canvas); + } + +} + + +// 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 { + + RenderView({ + RenderBox child, + this.timeForRotation: const Duration(microseconds: 83333) + }) { + this.child = child; + } + + sky.Size _size = new sky.Size(0.0, 0.0); + double get width => _size.width; + double get height => _size.height; + + int _orientation; // 0..3 + int get orientation => _orientation; + Duration timeForRotation; + + 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; + } + _size = new sky.Size(constraints.width, constraints.height); + assert(_size.height < double.INFINITY); + assert(_size.width < double.INFINITY); + } + void performLayout() { + if (child != null) { + child.layout(new BoxConstraints.tight(_size)); + assert(child.size.width == width); + assert(child.size.height == height); + } + } + + void rotate({ int oldAngle, int newAngle, Duration time }) { + assert(false); // nobody tells the screen to rotate, the whole rotate() dance is started from our performResize() + } + + bool hitTest(HitTestResult result, { sky.Point position }) { + if (child != null) { + sky.Rect childBounds = new sky.Rect.fromSize(child.size); + if (childBounds.contains(position)) + child.hitTest(result, position: position); + } + result.add(this); + return true; + } + + void paint(RenderNodeDisplayList canvas) { + if (child != null) + canvas.paintChild(child, new sky.Point(0.0, 0.0)); + } + + void paintFrame() { + RenderNode.debugDoingPaint = true; + var canvas = new RenderNodeDisplayList(sky.view.width, sky.view.height); + paint(canvas); + sky.view.picture = canvas.endRecording(); + RenderNode.debugDoingPaint = false; + } + +} + +// DEFAULT BEHAVIORS FOR RENDERBOX CONTAINERS +abstract class RenderBoxContainerDefaultsMixin> implements ContainerRenderNodeMixin { + + void defaultHitTestChildren(HitTestResult result, { sky.Point position }) { + // the x, y parameters have the top left of the node's box as the origin + ChildType child = lastChild; + while (child != null) { + assert(child.parentData is ParentDataType); + sky.Rect childBounds = new sky.Rect.fromPointAndSize(child.parentData.position, child.size); + if (childBounds.contains(position)) { + if (child.hitTest(result, position: new sky.Point(position.x - child.parentData.position.x, + position.y - child.parentData.position.y))) + break; + } + child = child.parentData.previousSibling; + } + } + + void defaultPaint(RenderNodeDisplayList canvas) { + RenderBox child = firstChild; + while (child != null) { + assert(child.parentData is ParentDataType); + canvas.paintChild(child, child.parentData.position); + child = child.parentData.nextSibling; + } + } +} diff --git a/sdk/lib/framework/rendering/render_flex.dart b/sdk/lib/framework/rendering/render_flex.dart new file mode 100644 index 00000000000..9e9d8ed0ad6 --- /dev/null +++ b/sdk/lib/framework/rendering/render_flex.dart @@ -0,0 +1,121 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:sky' as sky; +import 'render_node.dart'; +import 'render_box.dart'; +import 'render_node.dart'; + +class FlexBoxParentData extends BoxParentData with ContainerParentDataMixin { + int flex; + void merge(FlexBoxParentData other) { + if (other.flex != null) + flex = other.flex; + super.merge(other); + } +} + +enum FlexDirection { Horizontal, Vertical } + +class RenderFlex extends RenderBox with ContainerRenderNodeMixin, + RenderBoxContainerDefaultsMixin { + // lays out RenderBox children using flexible layout + + RenderFlex({ + FlexDirection direction: FlexDirection.Horizontal + }) : _direction = direction; + + FlexDirection _direction; + FlexDirection get direction => _direction; + void set direction (FlexDirection value) { + if (_direction != value) { + _direction = value; + markNeedsLayout(); + } + } + + void setParentData(RenderBox child) { + if (child.parentData is! FlexBoxParentData) + child.parentData = new FlexBoxParentData(); + } + + bool get sizedByParent => true; + void performResize() { + size = constraints.constrain(new sky.Size(constraints.maxWidth, constraints.maxHeight)); + assert(size.height < double.INFINITY); + assert(size.width < double.INFINITY); + } + + int _getFlex(RenderBox child) { + assert(child.parentData is FlexBoxParentData); + return child.parentData.flex != null ? child.parentData.flex : 0; + } + + 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; + RenderBox child = firstChild; + while (child != null) { + int flex = _getFlex(child); + if (flex > 0) { + totalFlex += child.parentData.flex; + } else { + BoxConstraints innerConstraints = new BoxConstraints(maxHeight: constraints.maxHeight, + maxWidth: constraints.maxWidth); + child.layout(innerConstraints, parentUsesSize: true); + freeSpace -= (_direction == FlexDirection.Horizontal) ? child.size.width : child.size.height; + } + child = child.parentData.nextSibling; + } + + // Steps 4-5. Distribute remaining space to flexible children. + double spacePerFlex = totalFlex > 0 ? (freeSpace / totalFlex) : 0.0; + double usedSpace = 0.0; + child = firstChild; + while (child != null) { + int flex = _getFlex(child); + if (flex > 0) { + double spaceForChild = spacePerFlex * flex; + BoxConstraints innerConstraints; + switch (_direction) { + case FlexDirection.Horizontal: + innerConstraints = new BoxConstraints(maxHeight: constraints.maxHeight, + minWidth: spaceForChild, + maxWidth: spaceForChild); + break; + case FlexDirection.Vertical: + innerConstraints = new BoxConstraints(minHeight: spaceForChild, + maxHeight: spaceForChild, + maxWidth: constraints.maxWidth); + break; + } + child.layout(innerConstraints, parentUsesSize: true); + } + + // For now, center the flex items in the cross direction + switch (_direction) { + case FlexDirection.Horizontal: + child.parentData.position = new sky.Point(usedSpace, size.height / 2.0 - child.size.height / 2.0); + usedSpace += child.size.width; + break; + case FlexDirection.Vertical: + child.parentData.position = new sky.Point(size.width / 2.0 - child.size.width / 2.0, usedSpace); + usedSpace += child.size.height; + break; + } + child = child.parentData.nextSibling; + } + } + + void hitTestChildren(HitTestResult result, { sky.Point position }) { + defaultHitTestChildren(result, position: position); + } + + void paint(RenderNodeDisplayList canvas) { + defaultPaint(canvas); + } +} diff --git a/sdk/lib/framework/rendering/render_node.dart b/sdk/lib/framework/rendering/render_node.dart new file mode 100644 index 00000000000..29863a84ffa --- /dev/null +++ b/sdk/lib/framework/rendering/render_node.dart @@ -0,0 +1,390 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import '../node.dart'; +import 'dart:sky' as sky; + +class ParentData { + void detach() { + detachSiblings(); + } + void detachSiblings() { } // workaround for lack of inter-class mixins in Dart + void merge(ParentData other) { + // override this in subclasses to merge in data from other into this + assert(other.runtimeType == this.runtimeType); + } +} + +const kLayoutDirections = 4; + +double clamp({double min: 0.0, double value: 0.0, double max: double.INFINITY}) { + assert(min != null); + assert(value != null); + assert(max != null); + + if (value > max) + value = max; + if (value < min) + value = min; + return value; +} + +class RenderNodeDisplayList extends sky.PictureRecorder { + RenderNodeDisplayList(double width, double height) : super(width, height); + void paintChild(RenderNode child, sky.Point position) { + save(); + translate(position.x, position.y); + child.paint(this); + restore(); + } +} + +abstract class RenderNode extends AbstractNode { + + // LAYOUT + + // parentData is only for use by the RenderNode that actually lays this + // node out, and any other nodes who happen to know exactly what + // kind of node that is. + ParentData parentData; + void setParentData(RenderNode child) { + // override this to setup .parentData correctly for your class + if (child.parentData is! ParentData) + child.parentData = new ParentData(); + } + + void adoptChild(RenderNode child) { // only for use by subclasses + // call this whenever you decide a node is a child + assert(child != null); + setParentData(child); + super.adoptChild(child); + } + void dropChild(RenderNode child) { // only for use by subclasses + assert(child != null); + assert(child.parentData != null); + child.parentData.detach(); + super.dropChild(child); + } + + static List _nodesNeedingLayout = new List(); + static bool _debugDoingLayout = false; + bool _needsLayout = true; + bool get needsLayout => _needsLayout; + RenderNode _relayoutSubtreeRoot; + dynamic _constraints; + dynamic get constraints => _constraints; + bool debugAncestorsAlreadyMarkedNeedsLayout() { + if (_relayoutSubtreeRoot == null) + 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); + assert(node.parent != null); + node = node.parent as RenderNode; + if (!node._needsLayout) + return false; + } + assert(node._relayoutSubtreeRoot == node); + return true; + } + void markNeedsLayout() { + assert(!_debugDoingLayout); + assert(!debugDoingPaint); + if (_needsLayout) { + assert(debugAncestorsAlreadyMarkedNeedsLayout()); + return; + } + _needsLayout = true; + assert(_relayoutSubtreeRoot != null); + if (_relayoutSubtreeRoot != this) { + assert(parent is RenderNode); + parent.markNeedsLayout(); + } else { + _nodesNeedingLayout.add(this); + } + } + static void flushLayout() { + _debugDoingLayout = true; + List dirtyNodes = _nodesNeedingLayout; + _nodesNeedingLayout = new List(); + dirtyNodes..sort((a, b) => a.depth - b.depth)..forEach((node) { + if (node._needsLayout && node.attached) + node._doLayout(); + }); + _debugDoingLayout = false; + } + void _doLayout() { + try { + assert(_relayoutSubtreeRoot == this); + performLayout(); + } catch (e, stack) { + print('Exception raised during layout of ${this}: ${e}'); + print(stack); + return; + } + _needsLayout = false; + } + 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 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 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 + // new dimensions, rotate() is called with the old and new angles. + // The next time paint() is called, the coordinate space will have + // been rotated N quarter-turns clockwise, where: + // N = newAngle-oldAngle + // ...but the rendering is expected to remain the same, pixel for + // pixel, on the output device. Then, the layout() method or + // equivalent will be invoked. + + void rotate({ + int oldAngle, // 0..3 + int newAngle, // 0..3 + Duration time + }) { } + + + // PAINTING + + static bool debugDoingPaint = false; + void markNeedsPaint() { + assert(!debugDoingPaint); + // 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(); + } + void paint(RenderNodeDisplayList canvas) { } + + + // HIT TESTING + + void handlePointer(sky.PointerEvent event) { + // override this if you have a client, to hand it to the client + // override this if you want to do anything with the pointer event + } + + // RenderNode subclasses are expected to have a method like the + // following (with the signature being whatever passes for coordinates + // for this particular class): + // bool hitTest(HitTestResult result, { sky.Point position }) { + // // If (x,y) is not inside this node, then return false. (You + // // can assume that the given coordinate is inside your + // // dimensions. You only need to check this if you're an + // // irregular shape, e.g. if you have a hole.) + // // Otherwise: + // // For each child that intersects x,y, in z-order starting from the top, + // // call hitTest() for that child, passing it /result/, and the coordinates + // // converted to the child's coordinate origin, and stop at the first child + // // that returns true. + // // Then, add yourself to /result/, and return true. + // } + // You must not add yourself to /result/ if you return false. + +} + +class HitTestResult { + final List path = new List(); + + RenderNode get result => path.first; + + void add(RenderNode node) { + path.add(node); + } +} + + +// GENERIC MIXIN FOR RENDER NODES WITH ONE CHILD + +abstract class RenderNodeWithChildMixin { + ChildType _child; + ChildType get child => _child; + void set child (ChildType value) { + if (_child != null) + dropChild(_child); + _child = value; + if (_child != null) + adoptChild(_child); + markNeedsLayout(); + } +} + + +// GENERIC MIXIN FOR RENDER NODES WITH A LIST OF CHILDREN + +abstract class ContainerParentDataMixin { + ChildType previousSibling; + ChildType nextSibling; + void detachSiblings() { + if (previousSibling != null) { + assert(previousSibling.parentData is ContainerParentDataMixin); + assert(previousSibling != this); + assert(previousSibling.parentData.nextSibling == this); + previousSibling.parentData.nextSibling = nextSibling; + } + if (nextSibling != null) { + assert(nextSibling.parentData is ContainerParentDataMixin); + assert(nextSibling != this); + assert(nextSibling.parentData.previousSibling == this); + nextSibling.parentData.previousSibling = previousSibling; + } + previousSibling = null; + nextSibling = null; + } +} + +abstract class ContainerRenderNodeMixin> implements RenderNode { + // abstract class that has only InlineNode children + + bool _debugUltimatePreviousSiblingOf(ChildType child, { ChildType equals }) { + assert(child.parentData is ParentDataType); + while (child.parentData.previousSibling != null) { + assert(child.parentData.previousSibling != child); + child = child.parentData.previousSibling; + assert(child.parentData is ParentDataType); + } + return child == equals; + } + bool _debugUltimateNextSiblingOf(ChildType child, { ChildType equals }) { + assert(child.parentData is ParentDataType); + while (child.parentData.nextSibling != null) { + assert(child.parentData.nextSibling != child); + child = child.parentData.nextSibling; + assert(child.parentData is ParentDataType); + } + return child == equals; + } + + ChildType _firstChild; + ChildType _lastChild; + void add(ChildType child, { ChildType before }) { + assert(child != this); + assert(before != this); + assert(child != before); + assert(child != _firstChild); + assert(child != _lastChild); + adoptChild(child); + assert(child.parentData is ParentDataType); + assert(child.parentData.nextSibling == null); + assert(child.parentData.previousSibling == null); + if (before == null) { + // append at the end (_lastChild) + child.parentData.previousSibling = _lastChild; + if (_lastChild != null) { + assert(_lastChild.parentData is ParentDataType); + _lastChild.parentData.nextSibling = child; + } + _lastChild = child; + if (_firstChild == null) + _firstChild = child; + } else { + assert(_firstChild != null); + assert(_lastChild != null); + assert(_debugUltimatePreviousSiblingOf(before, equals: _firstChild)); + assert(_debugUltimateNextSiblingOf(before, equals: _lastChild)); + assert(before.parentData is ParentDataType); + if (before.parentData.previousSibling == null) { + // insert at the start (_firstChild); we'll end up with two or more children + assert(before == _firstChild); + child.parentData.nextSibling = before; + before.parentData.previousSibling = child; + _firstChild = child; + } else { + // insert in the middle; we'll end up with three or more children + // set up links from child to siblings + child.parentData.previousSibling = before.parentData.previousSibling; + child.parentData.nextSibling = before; + // set up links from siblings to child + assert(child.parentData.previousSibling.parentData is ParentDataType); + assert(child.parentData.nextSibling.parentData is ParentDataType); + child.parentData.previousSibling.parentData.nextSibling = child; + child.parentData.nextSibling.parentData.previousSibling = child; + assert(before.parentData.previousSibling == child); + } + } + markNeedsLayout(); + } + void remove(ChildType child) { + assert(child.parentData is ParentDataType); + assert(_debugUltimatePreviousSiblingOf(child, equals: _firstChild)); + assert(_debugUltimateNextSiblingOf(child, equals: _lastChild)); + if (child.parentData.previousSibling == null) { + assert(_firstChild == child); + _firstChild = child.parentData.nextSibling; + } else { + assert(child.parentData.previousSibling.parentData is ParentDataType); + child.parentData.previousSibling.parentData.nextSibling = child.parentData.nextSibling; + } + if (child.parentData.nextSibling == null) { + assert(_lastChild == child); + _lastChild = child.parentData.previousSibling; + } else { + assert(child.parentData.nextSibling.parentData is ParentDataType); + child.parentData.nextSibling.parentData.previousSibling = child.parentData.previousSibling; + } + child.parentData.previousSibling = null; + child.parentData.nextSibling = null; + dropChild(child); + markNeedsLayout(); + } + void redepthChildren() { + ChildType child = _firstChild; + while (child != null) { + redepthChild(child); + assert(child.parentData is ParentDataType); + child = child.parentData.nextSibling; + } + } + void attachChildren() { + ChildType child = _firstChild; + while (child != null) { + child.attach(); + assert(child.parentData is ParentDataType); + child = child.parentData.nextSibling; + } + } + void detachChildren() { + ChildType child = _firstChild; + while (child != null) { + child.detach(); + assert(child.parentData is ParentDataType); + child = child.parentData.nextSibling; + } + } + + ChildType get firstChild => _firstChild; + ChildType get lastChild => _lastChild; + ChildType childAfter(ChildType child) { + assert(child.parentData is ParentDataType); + return child.parentData.nextSibling; + } +} diff --git a/sdk/lib/framework/rendering/render_paragraph.dart b/sdk/lib/framework/rendering/render_paragraph.dart new file mode 100644 index 00000000000..6580f84c7ee --- /dev/null +++ b/sdk/lib/framework/rendering/render_paragraph.dart @@ -0,0 +1,64 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:sky' as sky; +import 'render_box.dart'; +import 'render_node.dart'; + +class RenderInline extends RenderNode { + String data; + + RenderInline(this.data); +} + +class RenderParagraph extends RenderBox { + + RenderParagraph({ + String text, + int color + }) : _color = color { + _layoutRoot.rootElement = _document.createElement('p'); + this.text = text; + } + + final sky.Document _document = new sky.Document(); + final sky.LayoutRoot _layoutRoot = new sky.LayoutRoot(); + + String get text => (_layoutRoot.rootElement.firstChild as sky.Text).data; + void set text (String value) { + _layoutRoot.rootElement.setChild(_document.createText(value)); + markNeedsLayout(); + } + + int _color = 0xFF000000; + int get color => _color; + void set color (int value) { + if (_color != value) { + _color = value; + markNeedsPaint(); + } + } + + sky.Size getIntrinsicDimensions(BoxConstraints constraints) { + assert(false); + return null; + // we don't currently support this for RenderParagraph + } + + void performLayout() { + _layoutRoot.maxWidth = constraints.maxWidth; + _layoutRoot.minWidth = constraints.minWidth; + _layoutRoot.minHeight = constraints.minHeight; + _layoutRoot.maxHeight = constraints.maxHeight; + _layoutRoot.layout(); + size = constraints.constrain(new sky.Size(_layoutRoot.rootElement.width, _layoutRoot.rootElement.height)); + } + + void paint(RenderNodeDisplayList canvas) { + // _layoutRoot.rootElement.style['color'] = 'rgba(' + ...color... + ')'; + _layoutRoot.paint(canvas); + } + + // we should probably expose a way to do precise (inter-glpyh) hit testing +} diff --git a/tests/raw/render_box.dart b/tests/raw/render_box.dart index fafbbe50a38..6d04e8f2cae 100644 --- a/tests/raw/render_box.dart +++ b/tests/raw/render_box.dart @@ -5,7 +5,7 @@ import '../resources/third_party/unittest/unittest.dart'; import '../resources/unit.dart'; import 'dart:sky' as sky; -import 'package:sky/framework/layout2.dart'; +import 'package:sky/framework/rendering/render_box.dart'; void main() { initUnit(); diff --git a/tests/raw/render_flex.dart b/tests/raw/render_flex.dart index 97ea459c43d..5cc95895e2b 100644 --- a/tests/raw/render_flex.dart +++ b/tests/raw/render_flex.dart @@ -6,7 +6,9 @@ import '../resources/third_party/unittest/unittest.dart'; import '../resources/unit.dart'; import 'dart:sky' as sky; import 'package:sky/framework/app.dart'; -import 'package:sky/framework/layout2.dart'; +import 'package:sky/framework/rendering/render_block.dart'; +import 'package:sky/framework/rendering/render_box.dart'; +import 'package:sky/framework/rendering/render_flex.dart'; class RenderSolidColor extends RenderDecoratedBox { final sky.Size desiredSize; @@ -41,13 +43,13 @@ void main() { test("should flex", () { RenderFlex flexRoot = new RenderFlex(direction: FlexDirection.Vertical); - RenderNode root = new RenderDecoratedBox( + RenderDecoratedBox root = new RenderDecoratedBox( decoration: new BoxDecoration(backgroundColor: 0xFF000000), child: flexRoot ); void addFlexChildSolidColor(RenderFlex parent, int backgroundColor, { int flex: 0 }) { - RenderNode child = new RenderSolidColor(backgroundColor); + RenderSolidColor child = new RenderSolidColor(backgroundColor); parent.add(child); child.parentData.flex = flex; }