Index: sky/sdk/lib/rendering/box.dart |
diff --git a/sky/sdk/lib/rendering/box.dart b/sky/sdk/lib/rendering/box.dart |
index e2a1a4e1b36b5a7272387f41017377c3495e8408..78f6d60c550876efa27ecb9ee961f348e13a14bb 100644 |
--- a/sky/sdk/lib/rendering/box.dart |
+++ b/sky/sdk/lib/rendering/box.dart |
@@ -1019,6 +1019,132 @@ class RenderBaseline extends RenderShiftedBox { |
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}baseline: ${baseline}\nbaselineType: ${baselineType}'; |
} |
+enum ViewportScrollDirection { horizontal, vertical, both } |
+ |
+class RenderViewport extends RenderBox with RenderObjectWithChildMixin<RenderBox> { |
+ |
+ RenderViewport({ |
+ RenderBox child, |
+ Offset scrollOffset, |
+ ViewportScrollDirection direction: ViewportScrollDirection.vertical |
+ }) : _scrollOffset = scrollOffset, |
+ _scrollDirection = direction { |
+ assert(_offsetIsSane(scrollOffset, direction)); |
+ this.child = child; |
+ } |
+ |
+ bool _offsetIsSane(Offset offset, ViewportScrollDirection direction) { |
+ switch (direction) { |
+ case ViewportScrollDirection.both: |
+ return true; |
+ case ViewportScrollDirection.horizontal: |
+ return offset.dy == 0.0; |
+ case ViewportScrollDirection.vertical: |
+ return offset.dx == 0.0; |
+ } |
+ } |
+ |
+ Offset _scrollOffset; |
+ Offset get scrollOffset => _scrollOffset; |
+ void set scrollOffset(Offset value) { |
+ if (value == _scrollOffset) |
+ return; |
+ assert(_offsetIsSane(value, scrollDirection)); |
+ _scrollOffset = value; |
+ markNeedsPaint(); |
+ } |
+ |
+ ViewportScrollDirection _scrollDirection; |
+ ViewportScrollDirection get scrollDirection => _scrollDirection; |
+ void set scrollDirection(ViewportScrollDirection value) { |
+ if (value == _scrollDirection) |
+ return; |
+ assert(_offsetIsSane(scrollOffset, value)); |
+ _scrollDirection = value; |
+ markNeedsLayout(); |
+ } |
+ |
+ BoxConstraints _getInnerConstraints(BoxConstraints constraints) { |
+ BoxConstraints innerConstraints; |
+ switch (scrollDirection) { |
+ case ViewportScrollDirection.both: |
+ innerConstraints = new BoxConstraints(); |
+ break; |
+ case ViewportScrollDirection.horizontal: |
+ innerConstraints = constraints.heightConstraints(); |
+ break; |
+ case ViewportScrollDirection.vertical: |
+ innerConstraints = constraints.widthConstraints(); |
+ break; |
+ } |
+ return innerConstraints; |
+ } |
+ |
+ double getMinIntrinsicWidth(BoxConstraints constraints) { |
+ if (child != null) |
+ return child.getMinIntrinsicWidth(_getInnerConstraints(constraints)); |
+ return super.getMinIntrinsicWidth(constraints); |
+ } |
+ |
+ double getMaxIntrinsicWidth(BoxConstraints constraints) { |
+ if (child != null) |
+ return child.getMaxIntrinsicWidth(_getInnerConstraints(constraints)); |
+ return super.getMaxIntrinsicWidth(constraints); |
+ } |
+ |
+ double getMinIntrinsicHeight(BoxConstraints constraints) { |
+ if (child != null) |
+ return child.getMinIntrinsicHeight(_getInnerConstraints(constraints)); |
+ return super.getMinIntrinsicHeight(constraints); |
+ } |
+ |
+ double getMaxIntrinsicHeight(BoxConstraints constraints) { |
+ if (child != null) |
+ return child.getMaxIntrinsicHeight(_getInnerConstraints(constraints)); |
+ return super.getMaxIntrinsicHeight(constraints); |
+ } |
+ |
+ // We don't override computeDistanceToActualBaseline(), because we |
+ // want the default behaviour (returning null). Otherwise, as you |
+ // scroll the RenderViewport, it would shift in its parent if the |
+ // parent was baseline-aligned, which makes no sense. |
+ |
+ void performLayout() { |
+ if (child != null) { |
+ child.layout(_getInnerConstraints(constraints), parentUsesSize: true); |
+ size = constraints.constrain(child.size); |
+ assert(child.parentData is BoxParentData); |
+ child.parentData.position = Point.origin; |
+ } else { |
+ performResize(); |
+ } |
+ } |
+ |
+ void paint(PaintingCanvas canvas, Offset offset) { |
+ if (child != null) { |
+ bool _needsClip = offset < Offset.zero || |
+ !(offset & size).contains(((offset - scrollOffset) & child.size).bottomRight); |
+ if (_needsClip) { |
+ canvas.save(); |
+ canvas.clipRect(offset & size); |
+ } |
+ canvas.paintChild(child, (offset - scrollOffset).toPoint()); |
+ if (_needsClip) |
+ canvas.restore(); |
+ } |
+ } |
+ |
+ void hitTestChildren(HitTestResult result, { Point position }) { |
+ if (child != null) { |
+ assert(child.parentData is BoxParentData); |
+ Rect childBounds = child.parentData.position & child.size; |
+ if (childBounds.contains(position + -scrollOffset)) |
+ child.hitTest(result, position: position + scrollOffset); |
+ } |
+ } |
+ |
+} |
+ |
class RenderImage extends RenderBox { |
RenderImage(sky.Image image, Size requestedSize) |