mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Add some more docs to the rendering library
This commit is contained in:
parent
63101e49bc
commit
8601e237be
@ -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);
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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<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) {
|
||||
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<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);
|
||||
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);
|
||||
}
|
||||
|
||||
@ -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<RenderBox> {
|
||||
/// 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<Render
|
||||
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;
|
||||
|
||||
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>,
|
||||
RenderBoxContainerDefaultsMixin<RenderBox, StackParentData> {
|
||||
RenderStack({
|
||||
|
||||
@ -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<RenderBox> {
|
||||
RenderView({
|
||||
RenderBox child,
|
||||
@ -27,16 +37,20 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
|
||||
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<RenderBox>
|
||||
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<RenderBox>
|
||||
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 {
|
||||
|
||||
@ -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<RenderBox> {
|
||||
|
||||
RenderViewport({
|
||||
@ -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 _scrollOffset;
|
||||
void set scrollOffset(Offset value) {
|
||||
if (value == _scrollOffset)
|
||||
return;
|
||||
@ -43,8 +63,13 @@ class RenderViewport extends RenderBox with RenderObjectWithChildMixin<RenderBox
|
||||
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 _scrollDirection;
|
||||
void set scrollDirection(ScrollDirection value) {
|
||||
if (value == _scrollDirection)
|
||||
return;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user