diff --git a/examples/widgets/spinning_mixed.dart b/examples/widgets/spinning_mixed.dart index 2a2463bf55a..6d0b047c477 100644 --- a/examples/widgets/spinning_mixed.dart +++ b/examples/widgets/spinning_mixed.dart @@ -88,6 +88,6 @@ void main() { transformBox = new RenderTransform(child: flexRoot, transform: new Matrix4.identity()); RenderPadding root = new RenderPadding(padding: new EdgeDims.all(80.0), child: transformBox); - SkyBinding.instance.root = root; + SkyBinding.instance.renderView.child = root; scheduler.addPersistentFrameCallback(rotate); } diff --git a/packages/flutter/lib/src/rendering/layer.dart b/packages/flutter/lib/src/rendering/layer.dart index ea4a7551e4d..07faef74754 100644 --- a/packages/flutter/lib/src/rendering/layer.dart +++ b/packages/flutter/lib/src/rendering/layer.dart @@ -7,24 +7,36 @@ import 'dart:sky' show Point, Offset, Size, Rect, Color, Paint, Path; import 'package:vector_math/vector_math.dart'; +/// A composited layer +/// +/// During painting, the render tree generates a tree of composited layers that +/// are uploaded into the engine and displayed by the compositor. This class is +/// the base class for all composited layers. abstract class Layer { Layer({ this.offset: Offset.zero }); - Offset offset; // From parent, in parent's coordinate system. + /// Offset from parent in the parent's coordinate system. + Offset offset; - ContainerLayer _parent; + /// This layer's parent in the layer tree ContainerLayer get parent => _parent; + ContainerLayer _parent; - Layer _nextSibling; + /// This layer's next sibling in the parent layer's child list Layer get nextSibling => _nextSibling; + Layer _nextSibling; - Layer _previousSibling; + /// This layer's previous sibling in the parent layer's child list Layer get previousSibling => _previousSibling; + Layer _previousSibling; + /// Removes this layer from its parent layer's child list void detach() { if (_parent != null) - _parent.remove(this); + _parent._remove(this); } + + /// Replaces this layer with the given layer in the parent layer's child list void replaceWith(Layer newLayer) { assert(_parent != null); assert(newLayer._parent == null); @@ -46,14 +58,27 @@ abstract class Layer { _parent = null; } + /// Override this function to upload this layer to the engine + /// + /// The layerOffset is the accumulated offset of this layer's parent from the + /// origin of the builder's coordinate system. void addToScene(sky.SceneBuilder builder, Offset layerOffset); } +/// A composited layer containing a [Picture] class PictureLayer extends Layer { PictureLayer({ Offset offset: Offset.zero, this.paintBounds }) : super(offset: offset); + /// The rectangle in this layer's coodinate system that bounds the recording + /// + /// The paint bounds are used to decide how much graphics memory to allocate + /// when rasterizing this layer. Rect paintBounds; + + /// The picture recorded for this layer + /// + /// The picture's coodinate system matches this layer's coodinate system sky.Picture picture; void addToScene(sky.SceneBuilder builder, Offset layerOffset) { @@ -62,16 +87,17 @@ class PictureLayer extends Layer { } +/// A composited layer that has a list of children class ContainerLayer extends Layer { ContainerLayer({ Offset offset: Offset.zero }) : super(offset: offset); - // TODO(ianh): hide firstChild since nobody uses it - Layer _firstChild; + /// The first composited layer in this layer's child list Layer get firstChild => _firstChild; + Layer _firstChild; - // TODO(ianh): remove _lastChild since nobody uses it - Layer _lastChild; + /// The last composited layer in this layer's child list Layer get lastChild => _lastChild; + Layer _lastChild; bool _debugUltimatePreviousSiblingOf(Layer child, { Layer equals }) { while (child._previousSibling != null) { @@ -89,46 +115,24 @@ class ContainerLayer extends Layer { return child == equals; } - // TODO(ianh): Remove 'before' and rename the function to 'append' since nobody uses 'before' - void add(Layer child, { Layer before }) { + /// Adds the given layer to the end of this layer's child list + void append(Layer child) { assert(child != this); - assert(before != this); - assert(child != before); assert(child != _firstChild); assert(child != _lastChild); assert(child._parent == null); assert(child._nextSibling == null); assert(child._previousSibling == null); child._parent = this; - if (before == null) { - child._previousSibling = _lastChild; - if (_lastChild != null) - _lastChild._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)); - if (before._previousSibling == null) { - assert(before == _firstChild); - child._nextSibling = before; - before._previousSibling = child; - _firstChild = child; - } else { - child._previousSibling = before._previousSibling; - child._nextSibling = before; - child._previousSibling._nextSibling = child; - child._nextSibling._previousSibling = child; - assert(before._previousSibling == child); - } - } + child._previousSibling = _lastChild; + if (_lastChild != null) + _lastChild._nextSibling = child; + _lastChild = child; + if (_firstChild == null) + _firstChild = child; } - // TODO(ianh): Hide this function since only detach() uses it - void remove(Layer child) { + void _remove(Layer child) { assert(child._parent == this); assert(_debugUltimatePreviousSiblingOf(child, equals: _firstChild)); assert(_debugUltimateNextSiblingOf(child, equals: _lastChild)); @@ -149,6 +153,7 @@ class ContainerLayer extends Layer { child._parent = null; } + /// Removes all of this layer's children from its child list void removeAllChildren() { Layer child = _firstChild; while (child != null) { @@ -166,8 +171,9 @@ class ContainerLayer extends Layer { addChildrenToScene(builder, offset + layerOffset); } + /// Uploads all of this layer's children to the engine void addChildrenToScene(sky.SceneBuilder builder, Offset layerOffset) { - Layer child = firstChild; + Layer child = _firstChild; while (child != null) { child.addToScene(builder, layerOffset); child = child.nextSibling; @@ -176,11 +182,14 @@ class ContainerLayer extends Layer { } +/// A composite layer that clips its children using a rectangle class ClipRectLayer extends ContainerLayer { ClipRectLayer({ Offset offset: Offset.zero, this.clipRect }) : super(offset: offset); - // clipRect is _not_ affected by given offset + /// The rectangle to clip in the parent's coordinate system Rect clipRect; + // TODO(abarth): Why is the rectangle in the parent's coordinate system + // instead of in the coordinate system of this layer? void addToScene(sky.SceneBuilder builder, Offset layerOffset) { builder.pushClipRect(clipRect.shift(layerOffset)); @@ -190,12 +199,18 @@ class ClipRectLayer extends ContainerLayer { } +/// A composite layer that clips its children using a rounded rectangle class ClipRRectLayer extends ContainerLayer { ClipRRectLayer({ Offset offset: Offset.zero, this.bounds, this.clipRRect }) : super(offset: offset); - // bounds and clipRRect are _not_ affected by given offset + /// Unused Rect bounds; + // TODO(abarth): Remove. + + /// The rounded-rect to clip in the parent's coordinate system sky.RRect clipRRect; + // TODO(abarth): Why is the rounded-rect in the parent's coordinate system + // instead of in the coordinate system of this layer? void addToScene(sky.SceneBuilder builder, Offset layerOffset) { builder.pushClipRRect(clipRRect.shift(layerOffset), bounds.shift(layerOffset)); @@ -205,12 +220,18 @@ class ClipRRectLayer extends ContainerLayer { } +/// A composite layer that clips its children using a path class ClipPathLayer extends ContainerLayer { ClipPathLayer({ Offset offset: Offset.zero, this.bounds, this.clipPath }) : super(offset: offset); - // bounds and clipPath are _not_ affected by given offset + /// Unused Rect bounds; + // TODO(abarth): Remove. + + /// The path to clip in the parent's coordinate system Path clipPath; + // TODO(abarth): Why is the path in the parent's coordinate system instead of + // in the coordinate system of this layer? void addToScene(sky.SceneBuilder builder, Offset layerOffset) { builder.pushClipPath(clipPath.shift(layerOffset), bounds.shift(layerOffset)); @@ -220,9 +241,11 @@ class ClipPathLayer extends ContainerLayer { } +/// A composited layer that applies a transformation matrix to its children class TransformLayer extends ContainerLayer { TransformLayer({ Offset offset: Offset.zero, this.transform }) : super(offset: offset); + /// The matrix to apply Matrix4 transform; void addToScene(sky.SceneBuilder builder, Offset layerOffset) { @@ -234,11 +257,18 @@ class TransformLayer extends ContainerLayer { } } +/// A composited layer that makes its children partially transparent class OpacityLayer extends ContainerLayer { OpacityLayer({ Offset offset: Offset.zero, this.bounds, this.alpha }) : super(offset: offset); - // bounds is _not_ affected by given offset + /// Unused Rect bounds; + // TODO(abarth): Remove. + + /// The amount to multiply into the alpha channel + /// + /// The opacity is expressed as an integer from 0 to 255, where 0 is fully + /// transparent and 255 is fully opaque. int alpha; void addToScene(sky.SceneBuilder builder, Offset layerOffset) { @@ -248,6 +278,7 @@ class OpacityLayer extends ContainerLayer { } } +/// A composited layer that applies a color filter to its children class ColorFilterLayer extends ContainerLayer { ColorFilterLayer({ Offset offset: Offset.zero, @@ -256,9 +287,14 @@ class ColorFilterLayer extends ContainerLayer { this.transferMode }) : super(offset: offset); - // bounds is _not_ affected by given offset + /// Unused Rect bounds; + // TODO(abarth): Remove. + + /// The color to use as input to the color filter Color color; + + /// The transfer mode to use to combine [color] with the children's painting sky.TransferMode transferMode; void addToScene(sky.SceneBuilder builder, Offset layerOffset) { diff --git a/packages/flutter/lib/src/rendering/object.dart b/packages/flutter/lib/src/rendering/object.dart index 6fd819702fb..69ca265fb10 100644 --- a/packages/flutter/lib/src/rendering/object.dart +++ b/packages/flutter/lib/src/rendering/object.dart @@ -89,7 +89,7 @@ class PaintingContext { _currentLayer = new PictureLayer(paintBounds: paintBounds); _recorder = new sky.PictureRecorder(); _canvas = new PaintingCanvas(_recorder, paintBounds); - _containerLayer.add(_currentLayer); + _containerLayer.append(_currentLayer); } /// Stop recording draw operations into the current compositing layer @@ -162,7 +162,7 @@ class PaintingContext { canvas.restore(); } else { ClipRectLayer clipLayer = new ClipRectLayer(offset: childOffset, clipRect: clipRect); - _containerLayer.add(clipLayer); + _containerLayer.append(clipLayer); compositeChild(child, parentLayer: clipLayer); } } @@ -183,7 +183,7 @@ class PaintingContext { canvas.restore(); } else { ClipRRectLayer clipLayer = new ClipRRectLayer(offset: childOffset, bounds: bounds, clipRRect: clipRRect); - _containerLayer.add(clipLayer); + _containerLayer.append(clipLayer); compositeChild(child, parentLayer: clipLayer); } } @@ -205,7 +205,7 @@ class PaintingContext { canvas.restore(); } else { ClipPathLayer clipLayer = new ClipPathLayer(offset: childOffset, bounds: bounds, clipPath: clipPath); - _containerLayer.add(clipLayer); + _containerLayer.append(clipLayer); compositeChild(child, parentLayer: clipLayer); } } @@ -225,7 +225,7 @@ class PaintingContext { canvas.restore(); } else { TransformLayer transformLayer = new TransformLayer(offset: childOffset, transform: transform); - _containerLayer.add(transformLayer); + _containerLayer.append(transformLayer); compositeChild(child, parentLayer: transformLayer); } } @@ -258,7 +258,7 @@ class PaintingContext { offset: childOffset, bounds: bounds, alpha: alpha); - _containerLayer.add(paintLayer); + _containerLayer.append(paintLayer); compositeChild(child, parentLayer: paintLayer); } } @@ -295,7 +295,7 @@ class PaintingContext { bounds: bounds, color: color, transferMode: transferMode); - _containerLayer.add(paintLayer); + _containerLayer.append(paintLayer); compositeChild(child, parentLayer: paintLayer); } } @@ -345,7 +345,7 @@ class PaintingContext { child._layer.detach(); child._layer.offset = childOffset; } - parentLayer.add(child._layer); + parentLayer.append(child._layer); // Start a new layer for anything that remains of our own paint. _startRecording(originalLayer.paintBounds); diff --git a/packages/flutter/lib/src/rendering/paragraph.dart b/packages/flutter/lib/src/rendering/paragraph.dart index dfe038f86b3..12bd78be181 100644 --- a/packages/flutter/lib/src/rendering/paragraph.dart +++ b/packages/flutter/lib/src/rendering/paragraph.dart @@ -19,6 +19,7 @@ double _applyFloatingPointHack(double layoutValue) { return layoutValue.ceilToDouble(); } +/// A render object that displays a paragraph of text class RenderParagraph extends RenderBox { RenderParagraph(TextSpan text) : _textPainter = new TextPainter(text) { @@ -29,6 +30,7 @@ class RenderParagraph extends RenderBox { BoxConstraints _constraintsForCurrentLayout; // when null, we don't have a current layout + /// The text to display TextSpan get text => _textPainter.text; void set text(TextSpan value) { if (_textPainter.text == value) diff --git a/packages/flutter/lib/src/rendering/sky_binding.dart b/packages/flutter/lib/src/rendering/sky_binding.dart index bfa175d973e..ed9fa9197c7 100644 --- a/packages/flutter/lib/src/rendering/sky_binding.dart +++ b/packages/flutter/lib/src/rendering/sky_binding.dart @@ -23,19 +23,23 @@ int _hammingWeight(int value) { return weight; } -class PointerState { - PointerState({ this.result, this.lastPosition }); +class _PointerState { + _PointerState({ this.result, this.lastPosition }); HitTestResult result; Point lastPosition; } typedef void EventListener(sky.Event event); +/// A hit test entry used by [SkyBinding] class BindingHitTestEntry extends HitTestEntry { const BindingHitTestEntry(HitTestTarget target, this.result) : super(target); + + /// The result of the hit test final HitTestResult result; } +/// The glue between the render tree and the sky engine class SkyBinding extends HitTestTarget { SkyBinding({ RenderBox root: null, RenderView renderViewOverride }) { @@ -59,11 +63,13 @@ class SkyBinding extends HitTestTarget { assert(_instance == this); } - static SkyBinding _instance; // used to enforce that we're a singleton + /// The singleton instance of the binding static SkyBinding get instance => _instance; + static SkyBinding _instance; - RenderView _renderView; + /// The render tree that's attached to the output surface RenderView get renderView => _renderView; + RenderView _renderView; ViewConstraints _createConstraints() { return new ViewConstraints(size: new Size(sky.view.width, sky.view.height)); @@ -72,10 +78,7 @@ class SkyBinding extends HitTestTarget { _renderView.rootConstraints = _createConstraints(); } - RenderBox get root => _renderView.child; - void set root(RenderBox value) { - _renderView.child = value; - } + /// Pump the rendering pipeline to generate a frame for the given time stamp void beginFrame(double timeStamp) { RenderObject.flushLayout(); _renderView.updateCompositingBits(); @@ -84,8 +87,12 @@ class SkyBinding extends HitTestTarget { } final List _eventListeners = new List(); - void addEventListener(EventListener e) => _eventListeners.add(e); - bool removeEventListener(EventListener e) => _eventListeners.remove(e); + + /// Calls listener for every event that isn't localized to a given view coordinate + void addEventListener(EventListener listener) => _eventListeners.add(listener); + + /// Stops calling listener for every event that isn't localized to a given view coordinate + bool removeEventListener(EventListener listener) => _eventListeners.remove(listener); void _handleEvent(sky.Event event) { if (event is sky.PointerEvent) { @@ -98,19 +105,20 @@ class SkyBinding extends HitTestTarget { } } + /// A router that routes all pointer events received from the engine final PointerRouter pointerRouter = new PointerRouter(); - Map _stateForPointer = new Map(); + Map _stateForPointer = new Map(); - PointerState _createStateForPointer(sky.PointerEvent event, Point position) { + _PointerState _createStateForPointer(sky.PointerEvent event, Point position) { HitTestResult result = hitTest(position); - PointerState state = new PointerState(result: result, lastPosition: position); + _PointerState state = new _PointerState(result: result, lastPosition: position); _stateForPointer[event.pointer] = state; return state; } - PointerState _getOrCreateStateForPointer(event, position) { - PointerState state = _stateForPointer[event.pointer]; + _PointerState _getOrCreateStateForPointer(event, position) { + _PointerState state = _stateForPointer[event.pointer]; if (state == null) state = _createStateForPointer(event, position); return state; @@ -119,7 +127,7 @@ class SkyBinding extends HitTestTarget { EventDisposition _handlePointerEvent(sky.PointerEvent event) { Point position = new Point(event.x, event.y); - PointerState state = _getOrCreateStateForPointer(event, position); + _PointerState state = _getOrCreateStateForPointer(event, position); if (event.type == 'pointerup' || event.type == 'pointercancel') { if (_hammingWeight(event.buttons) <= 1) @@ -133,6 +141,7 @@ class SkyBinding extends HitTestTarget { return dispatchEvent(event, state.result); } + /// Determine which [HitTestTarget] objects are located at a given position HitTestResult hitTest(Point position) { HitTestResult result = new HitTestResult(); _renderView.hitTest(result, position: position); @@ -140,6 +149,7 @@ class SkyBinding extends HitTestTarget { return result; } + /// Dispatch the given event to the path of the given hit test result EventDisposition dispatchEvent(sky.Event event, HitTestResult result) { assert(result != null); EventDisposition disposition = EventDisposition.ignored; @@ -165,6 +175,7 @@ class SkyBinding extends HitTestTarget { String toString() => 'Render Tree:\n${_renderView}'; + /// Prints a textual representation of the entire render tree void debugDumpRenderTree() { toString().split('\n').forEach(print); } diff --git a/packages/flutter/lib/src/rendering/stack.dart b/packages/flutter/lib/src/rendering/stack.dart index 584e4d89025..0ea40b060c0 100644 --- a/packages/flutter/lib/src/rendering/stack.dart +++ b/packages/flutter/lib/src/rendering/stack.dart @@ -7,10 +7,18 @@ import 'dart:math' as math; import 'package:sky/src/rendering/box.dart'; import 'package:sky/src/rendering/object.dart'; +/// Parent data for use with [RenderStack] class StackParentData extends BoxParentData with ContainerParentDataMixin { + /// The offset of the child's top edge from the top of the stack double top; + + /// The offset of the child's right edge from the right of the stack double right; + + /// The offset of the child's bottom edge from the bottom of the stack double bottom; + + /// The offset of the child's left edge from the left of the stack double left; void merge(StackParentData other) { @@ -25,11 +33,38 @@ class StackParentData extends BoxParentData with ContainerParentDataMixin top != null || right != null || bottom != null || left != null; String toString() => '${super.toString()}; top=$top; right=$right; bottom=$bottom, left=$left'; } +/// Implements the stack layout algorithm +/// +/// In a stack layout, the children are positioned on top of each other in the +/// order in which they appear in the child list. First, the non-positioned +/// children (those with null values for top, right, bottom, and left) are +/// layed out and placed in the upper-left corner of the stack. The stack is +/// then sized to enclose all of the non-positioned children. If there are no +/// non-positioned children, the stack becomes as large as possible. +/// +/// Next, the positioned children are laid out. If a child has top and bottom +/// values that are both non-null, the child is given a fixed height determined +/// by deflating the width of the stack by the sum of the top and bottom values. +/// Similarly, if the child has rigth and left values that are both non-null, +/// the child is given a fixed width. Otherwise, the child is given unbounded +/// space in the non-fixed dimensions. +/// +/// Once the child is laid out, the stack positions the child according to the +/// top, right, bottom, and left offsets. For example, if the top value is 10.0, +/// the top edge of the child will be placed 10.0 pixels from the top edge of +/// the stack. If the child extends beyond the bounds of the stack, the stack +/// will clip the child's painting to the bounds of the stack. class RenderStack extends RenderBox with ContainerRenderObjectMixin, RenderBoxContainerDefaultsMixin { RenderStack({ diff --git a/packages/flutter/lib/src/rendering/view.dart b/packages/flutter/lib/src/rendering/view.dart index 943f0957f4b..f3473008965 100644 --- a/packages/flutter/lib/src/rendering/view.dart +++ b/packages/flutter/lib/src/rendering/view.dart @@ -10,15 +10,25 @@ import 'package:sky/src/rendering/object.dart'; import 'package:sky/src/rendering/box.dart'; import 'package:vector_math/vector_math.dart'; +/// The layout constraints for the root render object class ViewConstraints { const ViewConstraints({ this.size: Size.zero, this.orientation }); + + /// The size of the output surface final Size size; + + /// The orientation of the output surface (aspirational) final int orientation; } +/// The root of the render tree +/// +/// The view represents the total output surface of the render tree and handles +/// bootstraping the rendering pipeline. The view has a unique child +/// [RenderBox], which is required to fill the entire output surface. class RenderView extends RenderObject with RenderObjectWithChildMixin { RenderView({ RenderBox child, @@ -27,16 +37,20 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin this.child = child; } + /// The amount of time the screen rotation animation should last (aspirational) Duration timeForRotation; - Size _size = Size.zero; + /// The current layout size of the view Size get size => _size; + Size _size = Size.zero; - int _orientation; // 0..3 + /// The current orientation of the view (aspirational) int get orientation => _orientation; + int _orientation; // 0..3 - ViewConstraints _rootConstraints; + /// The constraints used for the root layout ViewConstraints get rootConstraints => _rootConstraints; + ViewConstraints _rootConstraints; void set rootConstraints(ViewConstraints value) { if (_rootConstraints == value) return; @@ -49,6 +63,7 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin return new Matrix4.diagonal3Values(devicePixelRatio, devicePixelRatio, 1.0); } + /// Bootstrap the rendering pipeline by scheduling the first frame void scheduleInitialFrame() { scheduleInitialLayout(); scheduleInitialPaint(new TransformLayer(transform: _logicalToDeviceTransform)); @@ -94,6 +109,9 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin context.paintChild(child, offset.toPoint()); } + /// Uploads the composited layer tree to the engine + /// + /// Actually causes the output of the rendering pipeline to appear on screen. void compositeFrame() { sky.tracing.begin('RenderView.compositeFrame'); try { diff --git a/packages/flutter/lib/src/rendering/viewport.dart b/packages/flutter/lib/src/rendering/viewport.dart index 96cc073aea3..c8b2c2bbb8d 100644 --- a/packages/flutter/lib/src/rendering/viewport.dart +++ b/packages/flutter/lib/src/rendering/viewport.dart @@ -8,8 +8,25 @@ import 'package:sky/src/rendering/object.dart'; import 'package:sky/src/rendering/box.dart'; import 'package:vector_math/vector_math.dart'; -enum ScrollDirection { horizontal, vertical, both } +/// The direction in which to scroll +enum ScrollDirection { + /// Scroll left and right + horizontal, + /// Scroll up and down + vertical, + + /// Scroll in all four cardinal directions + both +} + +/// A render object that's bigger on the inside +/// +/// A viewport is the core scrolling primitive in the render tree. The child of +/// a viewport can layout to a larger size than the viewport itself. If that +/// happens, only a portion of the child will be visible through the viewport. +/// The portiion of the child that is visible is controlled by the scroll +/// offset. class RenderViewport extends RenderBox with RenderObjectWithChildMixin { RenderViewport({ @@ -33,8 +50,11 @@ class RenderViewport extends RenderBox with RenderObjectWithChildMixin _scrollOffset; + Offset _scrollOffset; void set scrollOffset(Offset value) { if (value == _scrollOffset) return; @@ -43,8 +63,13 @@ class RenderViewport extends RenderBox with RenderObjectWithChildMixin _scrollDirection; + ScrollDirection _scrollDirection; void set scrollDirection(ScrollDirection value) { if (value == _scrollDirection) return;