Commit 8601e237 authored by Adam Barth's avatar Adam Barth

Add some more docs to the rendering library

parent 63101e49
...@@ -88,6 +88,6 @@ void main() { ...@@ -88,6 +88,6 @@ void main() {
transformBox = new RenderTransform(child: flexRoot, transform: new Matrix4.identity()); transformBox = new RenderTransform(child: flexRoot, transform: new Matrix4.identity());
RenderPadding root = new RenderPadding(padding: new EdgeDims.all(80.0), child: transformBox); RenderPadding root = new RenderPadding(padding: new EdgeDims.all(80.0), child: transformBox);
SkyBinding.instance.root = root; SkyBinding.instance.renderView.child = root;
scheduler.addPersistentFrameCallback(rotate); scheduler.addPersistentFrameCallback(rotate);
} }
...@@ -7,24 +7,36 @@ import 'dart:sky' show Point, Offset, Size, Rect, Color, Paint, Path; ...@@ -7,24 +7,36 @@ import 'dart:sky' show Point, Offset, Size, Rect, Color, Paint, Path;
import 'package:vector_math/vector_math.dart'; 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 { abstract class Layer {
Layer({ this.offset: Offset.zero }); 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 get parent => _parent;
ContainerLayer _parent;
Layer _nextSibling; /// This layer's next sibling in the parent layer's child list
Layer get nextSibling => _nextSibling; 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 get previousSibling => _previousSibling;
Layer _previousSibling;
/// Removes this layer from its parent layer's child list
void detach() { void detach() {
if (_parent != null) 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) { void replaceWith(Layer newLayer) {
assert(_parent != null); assert(_parent != null);
assert(newLayer._parent == null); assert(newLayer._parent == null);
...@@ -46,14 +58,27 @@ abstract class Layer { ...@@ -46,14 +58,27 @@ abstract class Layer {
_parent = null; _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); void addToScene(sky.SceneBuilder builder, Offset layerOffset);
} }
/// A composited layer containing a [Picture]
class PictureLayer extends Layer { class PictureLayer extends Layer {
PictureLayer({ Offset offset: Offset.zero, this.paintBounds }) PictureLayer({ Offset offset: Offset.zero, this.paintBounds })
: super(offset: offset); : 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; Rect paintBounds;
/// The picture recorded for this layer
///
/// The picture's coodinate system matches this layer's coodinate system
sky.Picture picture; sky.Picture picture;
void addToScene(sky.SceneBuilder builder, Offset layerOffset) { void addToScene(sky.SceneBuilder builder, Offset layerOffset) {
...@@ -62,16 +87,17 @@ class PictureLayer extends Layer { ...@@ -62,16 +87,17 @@ class PictureLayer extends Layer {
} }
/// A composited layer that has a list of children
class ContainerLayer extends Layer { class ContainerLayer extends Layer {
ContainerLayer({ Offset offset: Offset.zero }) : super(offset: offset); ContainerLayer({ Offset offset: Offset.zero }) : super(offset: offset);
// TODO(ianh): hide firstChild since nobody uses it /// The first composited layer in this layer's child list
Layer _firstChild;
Layer get firstChild => _firstChild; Layer get firstChild => _firstChild;
Layer _firstChild;
// TODO(ianh): remove _lastChild since nobody uses it /// The last composited layer in this layer's child list
Layer _lastChild;
Layer get lastChild => _lastChild; Layer get lastChild => _lastChild;
Layer _lastChild;
bool _debugUltimatePreviousSiblingOf(Layer child, { Layer equals }) { bool _debugUltimatePreviousSiblingOf(Layer child, { Layer equals }) {
while (child._previousSibling != null) { while (child._previousSibling != null) {
...@@ -89,46 +115,24 @@ class ContainerLayer extends Layer { ...@@ -89,46 +115,24 @@ class ContainerLayer extends Layer {
return child == equals; return child == equals;
} }
// TODO(ianh): Remove 'before' and rename the function to 'append' since nobody uses 'before' /// Adds the given layer to the end of this layer's child list
void add(Layer child, { Layer before }) { void append(Layer child) {
assert(child != this); assert(child != this);
assert(before != this);
assert(child != before);
assert(child != _firstChild); assert(child != _firstChild);
assert(child != _lastChild); assert(child != _lastChild);
assert(child._parent == null); assert(child._parent == null);
assert(child._nextSibling == null); assert(child._nextSibling == null);
assert(child._previousSibling == null); assert(child._previousSibling == null);
child._parent = this; child._parent = this;
if (before == null) { child._previousSibling = _lastChild;
child._previousSibling = _lastChild; if (_lastChild != null)
if (_lastChild != null) _lastChild._nextSibling = child;
_lastChild._nextSibling = child; _lastChild = child;
_lastChild = child; if (_firstChild == null)
if (_firstChild == null) _firstChild = child;
_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);
}
}
} }
// TODO(ianh): Hide this function since only detach() uses it void _remove(Layer child) {
void remove(Layer child) {
assert(child._parent == this); assert(child._parent == this);
assert(_debugUltimatePreviousSiblingOf(child, equals: _firstChild)); assert(_debugUltimatePreviousSiblingOf(child, equals: _firstChild));
assert(_debugUltimateNextSiblingOf(child, equals: _lastChild)); assert(_debugUltimateNextSiblingOf(child, equals: _lastChild));
...@@ -149,6 +153,7 @@ class ContainerLayer extends Layer { ...@@ -149,6 +153,7 @@ class ContainerLayer extends Layer {
child._parent = null; child._parent = null;
} }
/// Removes all of this layer's children from its child list
void removeAllChildren() { void removeAllChildren() {
Layer child = _firstChild; Layer child = _firstChild;
while (child != null) { while (child != null) {
...@@ -166,8 +171,9 @@ class ContainerLayer extends Layer { ...@@ -166,8 +171,9 @@ class ContainerLayer extends Layer {
addChildrenToScene(builder, offset + layerOffset); addChildrenToScene(builder, offset + layerOffset);
} }
/// Uploads all of this layer's children to the engine
void addChildrenToScene(sky.SceneBuilder builder, Offset layerOffset) { void addChildrenToScene(sky.SceneBuilder builder, Offset layerOffset) {
Layer child = firstChild; Layer child = _firstChild;
while (child != null) { while (child != null) {
child.addToScene(builder, layerOffset); child.addToScene(builder, layerOffset);
child = child.nextSibling; child = child.nextSibling;
...@@ -176,11 +182,14 @@ class ContainerLayer extends Layer { ...@@ -176,11 +182,14 @@ class ContainerLayer extends Layer {
} }
/// A composite layer that clips its children using a rectangle
class ClipRectLayer extends ContainerLayer { class ClipRectLayer extends ContainerLayer {
ClipRectLayer({ Offset offset: Offset.zero, this.clipRect }) : super(offset: offset); 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; 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) { void addToScene(sky.SceneBuilder builder, Offset layerOffset) {
builder.pushClipRect(clipRect.shift(layerOffset)); builder.pushClipRect(clipRect.shift(layerOffset));
...@@ -190,12 +199,18 @@ class ClipRectLayer extends ContainerLayer { ...@@ -190,12 +199,18 @@ class ClipRectLayer extends ContainerLayer {
} }
/// A composite layer that clips its children using a rounded rectangle
class ClipRRectLayer extends ContainerLayer { class ClipRRectLayer extends ContainerLayer {
ClipRRectLayer({ Offset offset: Offset.zero, this.bounds, this.clipRRect }) : super(offset: offset); ClipRRectLayer({ Offset offset: Offset.zero, this.bounds, this.clipRRect }) : super(offset: offset);
// bounds and clipRRect are _not_ affected by given offset /// Unused
Rect bounds; Rect bounds;
// TODO(abarth): Remove.
/// The rounded-rect to clip in the parent's coordinate system
sky.RRect clipRRect; 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) { void addToScene(sky.SceneBuilder builder, Offset layerOffset) {
builder.pushClipRRect(clipRRect.shift(layerOffset), bounds.shift(layerOffset)); builder.pushClipRRect(clipRRect.shift(layerOffset), bounds.shift(layerOffset));
...@@ -205,12 +220,18 @@ class ClipRRectLayer extends ContainerLayer { ...@@ -205,12 +220,18 @@ class ClipRRectLayer extends ContainerLayer {
} }
/// A composite layer that clips its children using a path
class ClipPathLayer extends ContainerLayer { class ClipPathLayer extends ContainerLayer {
ClipPathLayer({ Offset offset: Offset.zero, this.bounds, this.clipPath }) : super(offset: offset); ClipPathLayer({ Offset offset: Offset.zero, this.bounds, this.clipPath }) : super(offset: offset);
// bounds and clipPath are _not_ affected by given offset /// Unused
Rect bounds; Rect bounds;
// TODO(abarth): Remove.
/// The path to clip in the parent's coordinate system
Path clipPath; 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) { void addToScene(sky.SceneBuilder builder, Offset layerOffset) {
builder.pushClipPath(clipPath.shift(layerOffset), bounds.shift(layerOffset)); builder.pushClipPath(clipPath.shift(layerOffset), bounds.shift(layerOffset));
...@@ -220,9 +241,11 @@ class ClipPathLayer extends ContainerLayer { ...@@ -220,9 +241,11 @@ class ClipPathLayer extends ContainerLayer {
} }
/// A composited layer that applies a transformation matrix to its children
class TransformLayer extends ContainerLayer { class TransformLayer extends ContainerLayer {
TransformLayer({ Offset offset: Offset.zero, this.transform }) : super(offset: offset); TransformLayer({ Offset offset: Offset.zero, this.transform }) : super(offset: offset);
/// The matrix to apply
Matrix4 transform; Matrix4 transform;
void addToScene(sky.SceneBuilder builder, Offset layerOffset) { void addToScene(sky.SceneBuilder builder, Offset layerOffset) {
...@@ -234,11 +257,18 @@ class TransformLayer extends ContainerLayer { ...@@ -234,11 +257,18 @@ class TransformLayer extends ContainerLayer {
} }
} }
/// A composited layer that makes its children partially transparent
class OpacityLayer extends ContainerLayer { class OpacityLayer extends ContainerLayer {
OpacityLayer({ Offset offset: Offset.zero, this.bounds, this.alpha }) : super(offset: offset); OpacityLayer({ Offset offset: Offset.zero, this.bounds, this.alpha }) : super(offset: offset);
// bounds is _not_ affected by given offset /// Unused
Rect bounds; 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; int alpha;
void addToScene(sky.SceneBuilder builder, Offset layerOffset) { void addToScene(sky.SceneBuilder builder, Offset layerOffset) {
...@@ -248,6 +278,7 @@ class OpacityLayer extends ContainerLayer { ...@@ -248,6 +278,7 @@ class OpacityLayer extends ContainerLayer {
} }
} }
/// A composited layer that applies a color filter to its children
class ColorFilterLayer extends ContainerLayer { class ColorFilterLayer extends ContainerLayer {
ColorFilterLayer({ ColorFilterLayer({
Offset offset: Offset.zero, Offset offset: Offset.zero,
...@@ -256,9 +287,14 @@ class ColorFilterLayer extends ContainerLayer { ...@@ -256,9 +287,14 @@ class ColorFilterLayer extends ContainerLayer {
this.transferMode this.transferMode
}) : super(offset: offset); }) : super(offset: offset);
// bounds is _not_ affected by given offset /// Unused
Rect bounds; Rect bounds;
// TODO(abarth): Remove.
/// The color to use as input to the color filter
Color color; Color color;
/// The transfer mode to use to combine [color] with the children's painting
sky.TransferMode transferMode; sky.TransferMode transferMode;
void addToScene(sky.SceneBuilder builder, Offset layerOffset) { void addToScene(sky.SceneBuilder builder, Offset layerOffset) {
......
...@@ -89,7 +89,7 @@ class PaintingContext { ...@@ -89,7 +89,7 @@ class PaintingContext {
_currentLayer = new PictureLayer(paintBounds: paintBounds); _currentLayer = new PictureLayer(paintBounds: paintBounds);
_recorder = new sky.PictureRecorder(); _recorder = new sky.PictureRecorder();
_canvas = new PaintingCanvas(_recorder, paintBounds); _canvas = new PaintingCanvas(_recorder, paintBounds);
_containerLayer.add(_currentLayer); _containerLayer.append(_currentLayer);
} }
/// Stop recording draw operations into the current compositing layer /// Stop recording draw operations into the current compositing layer
...@@ -162,7 +162,7 @@ class PaintingContext { ...@@ -162,7 +162,7 @@ class PaintingContext {
canvas.restore(); canvas.restore();
} else { } else {
ClipRectLayer clipLayer = new ClipRectLayer(offset: childOffset, clipRect: clipRect); ClipRectLayer clipLayer = new ClipRectLayer(offset: childOffset, clipRect: clipRect);
_containerLayer.add(clipLayer); _containerLayer.append(clipLayer);
compositeChild(child, parentLayer: clipLayer); compositeChild(child, parentLayer: clipLayer);
} }
} }
...@@ -183,7 +183,7 @@ class PaintingContext { ...@@ -183,7 +183,7 @@ class PaintingContext {
canvas.restore(); canvas.restore();
} else { } else {
ClipRRectLayer clipLayer = new ClipRRectLayer(offset: childOffset, bounds: bounds, clipRRect: clipRRect); ClipRRectLayer clipLayer = new ClipRRectLayer(offset: childOffset, bounds: bounds, clipRRect: clipRRect);
_containerLayer.add(clipLayer); _containerLayer.append(clipLayer);
compositeChild(child, parentLayer: clipLayer); compositeChild(child, parentLayer: clipLayer);
} }
} }
...@@ -205,7 +205,7 @@ class PaintingContext { ...@@ -205,7 +205,7 @@ class PaintingContext {
canvas.restore(); canvas.restore();
} else { } else {
ClipPathLayer clipLayer = new ClipPathLayer(offset: childOffset, bounds: bounds, clipPath: clipPath); ClipPathLayer clipLayer = new ClipPathLayer(offset: childOffset, bounds: bounds, clipPath: clipPath);
_containerLayer.add(clipLayer); _containerLayer.append(clipLayer);
compositeChild(child, parentLayer: clipLayer); compositeChild(child, parentLayer: clipLayer);
} }
} }
...@@ -225,7 +225,7 @@ class PaintingContext { ...@@ -225,7 +225,7 @@ class PaintingContext {
canvas.restore(); canvas.restore();
} else { } else {
TransformLayer transformLayer = new TransformLayer(offset: childOffset, transform: transform); TransformLayer transformLayer = new TransformLayer(offset: childOffset, transform: transform);
_containerLayer.add(transformLayer); _containerLayer.append(transformLayer);
compositeChild(child, parentLayer: transformLayer); compositeChild(child, parentLayer: transformLayer);
} }
} }
...@@ -258,7 +258,7 @@ class PaintingContext { ...@@ -258,7 +258,7 @@ class PaintingContext {
offset: childOffset, offset: childOffset,
bounds: bounds, bounds: bounds,
alpha: alpha); alpha: alpha);
_containerLayer.add(paintLayer); _containerLayer.append(paintLayer);
compositeChild(child, parentLayer: paintLayer); compositeChild(child, parentLayer: paintLayer);
} }
} }
...@@ -295,7 +295,7 @@ class PaintingContext { ...@@ -295,7 +295,7 @@ class PaintingContext {
bounds: bounds, bounds: bounds,
color: color, color: color,
transferMode: transferMode); transferMode: transferMode);
_containerLayer.add(paintLayer); _containerLayer.append(paintLayer);
compositeChild(child, parentLayer: paintLayer); compositeChild(child, parentLayer: paintLayer);
} }
} }
...@@ -345,7 +345,7 @@ class PaintingContext { ...@@ -345,7 +345,7 @@ class PaintingContext {
child._layer.detach(); child._layer.detach();
child._layer.offset = childOffset; child._layer.offset = childOffset;
} }
parentLayer.add(child._layer); parentLayer.append(child._layer);
// Start a new layer for anything that remains of our own paint. // Start a new layer for anything that remains of our own paint.
_startRecording(originalLayer.paintBounds); _startRecording(originalLayer.paintBounds);
......
...@@ -19,6 +19,7 @@ double _applyFloatingPointHack(double layoutValue) { ...@@ -19,6 +19,7 @@ double _applyFloatingPointHack(double layoutValue) {
return layoutValue.ceilToDouble(); return layoutValue.ceilToDouble();
} }
/// A render object that displays a paragraph of text
class RenderParagraph extends RenderBox { class RenderParagraph extends RenderBox {
RenderParagraph(TextSpan text) : _textPainter = new TextPainter(text) { RenderParagraph(TextSpan text) : _textPainter = new TextPainter(text) {
...@@ -29,6 +30,7 @@ class RenderParagraph extends RenderBox { ...@@ -29,6 +30,7 @@ class RenderParagraph extends RenderBox {
BoxConstraints _constraintsForCurrentLayout; // when null, we don't have a current layout BoxConstraints _constraintsForCurrentLayout; // when null, we don't have a current layout
/// The text to display
TextSpan get text => _textPainter.text; TextSpan get text => _textPainter.text;
void set text(TextSpan value) { void set text(TextSpan value) {
if (_textPainter.text == value) if (_textPainter.text == value)
......
...@@ -23,19 +23,23 @@ int _hammingWeight(int value) { ...@@ -23,19 +23,23 @@ int _hammingWeight(int value) {
return weight; return weight;
} }
class PointerState { class _PointerState {
PointerState({ this.result, this.lastPosition }); _PointerState({ this.result, this.lastPosition });
HitTestResult result; HitTestResult result;
Point lastPosition; Point lastPosition;
} }
typedef void EventListener(sky.Event event); typedef void EventListener(sky.Event event);
/// A hit test entry used by [SkyBinding]
class BindingHitTestEntry extends HitTestEntry { class BindingHitTestEntry extends HitTestEntry {
const BindingHitTestEntry(HitTestTarget target, this.result) : super(target); const BindingHitTestEntry(HitTestTarget target, this.result) : super(target);
/// The result of the hit test
final HitTestResult result; final HitTestResult result;
} }
/// The glue between the render tree and the sky engine
class SkyBinding extends HitTestTarget { class SkyBinding extends HitTestTarget {
SkyBinding({ RenderBox root: null, RenderView renderViewOverride }) { SkyBinding({ RenderBox root: null, RenderView renderViewOverride }) {
...@@ -59,11 +63,13 @@ class SkyBinding extends HitTestTarget { ...@@ -59,11 +63,13 @@ class SkyBinding extends HitTestTarget {
assert(_instance == this); 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 get instance => _instance;
static SkyBinding _instance;
RenderView _renderView; /// The render tree that's attached to the output surface
RenderView get renderView => _renderView; RenderView get renderView => _renderView;
RenderView _renderView;
ViewConstraints _createConstraints() { ViewConstraints _createConstraints() {
return new ViewConstraints(size: new Size(sky.view.width, sky.view.height)); return new ViewConstraints(size: new Size(sky.view.width, sky.view.height));
...@@ -72,10 +78,7 @@ class SkyBinding extends HitTestTarget { ...@@ -72,10 +78,7 @@ class SkyBinding extends HitTestTarget {
_renderView.rootConstraints = _createConstraints(); _renderView.rootConstraints = _createConstraints();
} }
RenderBox get root => _renderView.child; /// Pump the rendering pipeline to generate a frame for the given time stamp
void set root(RenderBox value) {
_renderView.child = value;
}
void beginFrame(double timeStamp) { void beginFrame(double timeStamp) {
RenderObject.flushLayout(); RenderObject.flushLayout();
_renderView.updateCompositingBits(); _renderView.updateCompositingBits();
...@@ -84,8 +87,12 @@ class SkyBinding extends HitTestTarget { ...@@ -84,8 +87,12 @@ class SkyBinding extends HitTestTarget {
} }
final List<EventListener> _eventListeners = new List<EventListener>(); final List<EventListener> _eventListeners = new List<EventListener>();
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) { void _handleEvent(sky.Event event) {
if (event is sky.PointerEvent) { if (event is sky.PointerEvent) {
...@@ -98,19 +105,20 @@ class SkyBinding extends HitTestTarget { ...@@ -98,19 +105,20 @@ class SkyBinding extends HitTestTarget {
} }
} }
/// A router that routes all pointer events received from the engine
final PointerRouter pointerRouter = new PointerRouter(); final PointerRouter pointerRouter = new PointerRouter();
Map<int, PointerState> _stateForPointer = new Map<int, PointerState>(); Map<int, _PointerState> _stateForPointer = new Map<int, _PointerState>();
PointerState _createStateForPointer(sky.PointerEvent event, Point position) { _PointerState _createStateForPointer(sky.PointerEvent event, Point position) {
HitTestResult result = hitTest(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; _stateForPointer[event.pointer] = state;
return state; return state;
} }
PointerState _getOrCreateStateForPointer(event, position) { _PointerState _getOrCreateStateForPointer(event, position) {
PointerState state = _stateForPointer[event.pointer]; _PointerState state = _stateForPointer[event.pointer];
if (state == null) if (state == null)
state = _createStateForPointer(event, position); state = _createStateForPointer(event, position);
return state; return state;
...@@ -119,7 +127,7 @@ class SkyBinding extends HitTestTarget { ...@@ -119,7 +127,7 @@ class SkyBinding extends HitTestTarget {
EventDisposition _handlePointerEvent(sky.PointerEvent event) { EventDisposition _handlePointerEvent(sky.PointerEvent event) {
Point position = new Point(event.x, event.y); 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 (event.type == 'pointerup' || event.type == 'pointercancel') {
if (_hammingWeight(event.buttons) <= 1) if (_hammingWeight(event.buttons) <= 1)
...@@ -133,6 +141,7 @@ class SkyBinding extends HitTestTarget { ...@@ -133,6 +141,7 @@ class SkyBinding extends HitTestTarget {
return dispatchEvent(event, state.result); return dispatchEvent(event, state.result);
} }
/// Determine which [HitTestTarget] objects are located at a given position
HitTestResult hitTest(Point position) { HitTestResult hitTest(Point position) {
HitTestResult result = new HitTestResult(); HitTestResult result = new HitTestResult();
_renderView.hitTest(result, position: position); _renderView.hitTest(result, position: position);
...@@ -140,6 +149,7 @@ class SkyBinding extends HitTestTarget { ...@@ -140,6 +149,7 @@ class SkyBinding extends HitTestTarget {
return result; return result;
} }
/// Dispatch the given event to the path of the given hit test result
EventDisposition dispatchEvent(sky.Event event, HitTestResult result) { EventDisposition dispatchEvent(sky.Event event, HitTestResult result) {
assert(result != null); assert(result != null);
EventDisposition disposition = EventDisposition.ignored; EventDisposition disposition = EventDisposition.ignored;
...@@ -165,6 +175,7 @@ class SkyBinding extends HitTestTarget { ...@@ -165,6 +175,7 @@ class SkyBinding extends HitTestTarget {
String toString() => 'Render Tree:\n${_renderView}'; String toString() => 'Render Tree:\n${_renderView}';
/// Prints a textual representation of the entire render tree
void debugDumpRenderTree() { void debugDumpRenderTree() {
toString().split('\n').forEach(print); toString().split('\n').forEach(print);
} }
......
...@@ -7,10 +7,18 @@ import 'dart:math' as math; ...@@ -7,10 +7,18 @@ import 'dart:math' as math;
import 'package:sky/src/rendering/box.dart'; import 'package:sky/src/rendering/box.dart';
import 'package:sky/src/rendering/object.dart'; import 'package:sky/src/rendering/object.dart';
/// Parent data for use with [RenderStack]
class StackParentData extends BoxParentData with ContainerParentDataMixin<RenderBox> { class StackParentData extends BoxParentData with ContainerParentDataMixin<RenderBox> {
/// The offset of the child's top edge from the top of the stack
double top; double top;
/// The offset of the child's right edge from the right of the stack
double right; double right;
/// The offset of the child's bottom edge from the bottom of the stack
double bottom; double bottom;
/// The offset of the child's left edge from the left of the stack
double left; double left;
void merge(StackParentData other) { void merge(StackParentData other) {
...@@ -25,11 +33,38 @@ class StackParentData extends BoxParentData with ContainerParentDataMixin<Render ...@@ -25,11 +33,38 @@ class StackParentData extends BoxParentData with ContainerParentDataMixin<Render
super.merge(other); super.merge(other);
} }
/// Whether this child is considered positioned
///
/// A child is positioned if any of the top, right, bottom, or left offsets
/// are non-null. Positioned children do not factor into determining the size
/// of the stack but are instead placed relative to the non-positioned
/// children in the stack.
bool get isPositioned => top != null || right != null || bottom != null || left != null; bool get isPositioned => top != null || right != null || bottom != null || left != null;
String toString() => '${super.toString()}; top=$top; right=$right; bottom=$bottom, left=$left'; 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<RenderBox, StackParentData>, class RenderStack extends RenderBox with ContainerRenderObjectMixin<RenderBox, StackParentData>,
RenderBoxContainerDefaultsMixin<RenderBox, StackParentData> { RenderBoxContainerDefaultsMixin<RenderBox, StackParentData> {
RenderStack({ RenderStack({
......
...@@ -10,15 +10,25 @@ import 'package:sky/src/rendering/object.dart'; ...@@ -10,15 +10,25 @@ import 'package:sky/src/rendering/object.dart';
import 'package:sky/src/rendering/box.dart'; import 'package:sky/src/rendering/box.dart';
import 'package:vector_math/vector_math.dart'; import 'package:vector_math/vector_math.dart';
/// The layout constraints for the root render object
class ViewConstraints { class ViewConstraints {
const ViewConstraints({ const ViewConstraints({
this.size: Size.zero, this.size: Size.zero,
this.orientation this.orientation
}); });
/// The size of the output surface
final Size size; final Size size;
/// The orientation of the output surface (aspirational)
final int orientation; 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<RenderBox> { class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox> {
RenderView({ RenderView({
RenderBox child, RenderBox child,
...@@ -27,16 +37,20 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox> ...@@ -27,16 +37,20 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
this.child = child; this.child = child;
} }
/// The amount of time the screen rotation animation should last (aspirational)
Duration timeForRotation; Duration timeForRotation;
Size _size = Size.zero; /// The current layout size of the view
Size get size => _size; Size get size => _size;
Size _size = Size.zero;
int _orientation; // 0..3 /// The current orientation of the view (aspirational)
int get orientation => _orientation; int get orientation => _orientation;
int _orientation; // 0..3
ViewConstraints _rootConstraints; /// The constraints used for the root layout
ViewConstraints get rootConstraints => _rootConstraints; ViewConstraints get rootConstraints => _rootConstraints;
ViewConstraints _rootConstraints;
void set rootConstraints(ViewConstraints value) { void set rootConstraints(ViewConstraints value) {
if (_rootConstraints == value) if (_rootConstraints == value)
return; return;
...@@ -49,6 +63,7 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox> ...@@ -49,6 +63,7 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
return new Matrix4.diagonal3Values(devicePixelRatio, devicePixelRatio, 1.0); return new Matrix4.diagonal3Values(devicePixelRatio, devicePixelRatio, 1.0);
} }
/// Bootstrap the rendering pipeline by scheduling the first frame
void scheduleInitialFrame() { void scheduleInitialFrame() {
scheduleInitialLayout(); scheduleInitialLayout();
scheduleInitialPaint(new TransformLayer(transform: _logicalToDeviceTransform)); scheduleInitialPaint(new TransformLayer(transform: _logicalToDeviceTransform));
...@@ -94,6 +109,9 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox> ...@@ -94,6 +109,9 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
context.paintChild(child, offset.toPoint()); 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() { void compositeFrame() {
sky.tracing.begin('RenderView.compositeFrame'); sky.tracing.begin('RenderView.compositeFrame');
try { try {
......
...@@ -8,8 +8,25 @@ import 'package:sky/src/rendering/object.dart'; ...@@ -8,8 +8,25 @@ import 'package:sky/src/rendering/object.dart';
import 'package:sky/src/rendering/box.dart'; import 'package:sky/src/rendering/box.dart';
import 'package:vector_math/vector_math.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<RenderBox> { class RenderViewport extends RenderBox with RenderObjectWithChildMixin<RenderBox> {
RenderViewport({ RenderViewport({
...@@ -33,8 +50,11 @@ class RenderViewport extends RenderBox with RenderObjectWithChildMixin<RenderBox ...@@ -33,8 +50,11 @@ class RenderViewport extends RenderBox with RenderObjectWithChildMixin<RenderBox
} }
} }
Offset _scrollOffset; /// The offset at which to paint the child
///
/// The offset can be non-zero only in the [scrollDirection].
Offset get scrollOffset => _scrollOffset; Offset get scrollOffset => _scrollOffset;
Offset _scrollOffset;
void set scrollOffset(Offset value) { void set scrollOffset(Offset value) {
if (value == _scrollOffset) if (value == _scrollOffset)
return; return;
...@@ -43,8 +63,13 @@ class RenderViewport extends RenderBox with RenderObjectWithChildMixin<RenderBox ...@@ -43,8 +63,13 @@ class RenderViewport extends RenderBox with RenderObjectWithChildMixin<RenderBox
markNeedsPaint(); markNeedsPaint();
} }
ScrollDirection _scrollDirection; /// In which direction the child is permitted to be larger than the viewport
///
/// If the viewport is scrollable in a particular direction (e.g., vertically),
/// the child is given layout constraints that are fully unconstrainted in
/// that direction (e.g., the child can be as tall as it wants).
ScrollDirection get scrollDirection => _scrollDirection; ScrollDirection get scrollDirection => _scrollDirection;
ScrollDirection _scrollDirection;
void set scrollDirection(ScrollDirection value) { void set scrollDirection(ScrollDirection value) {
if (value == _scrollDirection) if (value == _scrollDirection)
return; return;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment