Commit ce8f75da authored by Adam Barth's avatar Adam Barth

Merge pull request #684 from abarth/explode_box

Split box.dart into many files
parents 1418d271 50bfdedb
......@@ -9,6 +9,8 @@ import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/flex.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/paragraph.dart';
import 'package:sky/rendering/proxy_box.dart';
import 'package:sky/rendering/shifted_box.dart';
import 'package:sky/rendering/sky_binding.dart';
import 'solid_color_box.dart';
......
......@@ -9,6 +9,8 @@ import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/flex.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/paragraph.dart';
import 'package:sky/rendering/proxy_box.dart';
import 'package:sky/rendering/shifted_box.dart';
import 'package:sky/rendering/sky_binding.dart';
RenderBox getBox(double lh) {
......
......@@ -6,6 +6,8 @@ import 'dart:sky' as sky;
import 'package:sky/rendering/block.dart';
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/proxy_box.dart';
import 'package:sky/rendering/shifted_box.dart';
import 'package:sky/rendering/sky_binding.dart';
void main() {
......
......@@ -6,6 +6,8 @@ import 'dart:sky' as sky;
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/flex.dart';
import 'package:sky/rendering/proxy_box.dart';
import 'package:sky/rendering/shifted_box.dart';
import 'package:sky/rendering/sky_binding.dart';
class RenderSolidColor extends RenderDecoratedBox {
......
......@@ -8,10 +8,12 @@ import 'dart:math' as math;
import 'package:sky/mojo/activity.dart' as activity;
import 'package:sky/mojo/net/image_cache.dart' as image_cache;
import 'package:sky/painting/text_style.dart';
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/flex.dart';
import 'package:sky/rendering/image.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/paragraph.dart';
import 'package:sky/rendering/proxy_box.dart';
import 'package:sky/rendering/shifted_box.dart';
import 'package:sky/rendering/sky_binding.dart';
import 'solid_color_box.dart';
......
......@@ -5,10 +5,11 @@
import 'dart:sky';
import 'package:sky/painting/text_style.dart';
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/flex.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/paragraph.dart';
import 'package:sky/rendering/proxy_box.dart';
import 'package:sky/rendering/shifted_box.dart';
import 'package:sky/rendering/sky_binding.dart';
import 'solid_color_box.dart';
......
......@@ -5,11 +5,11 @@
import 'dart:sky';
import 'package:sky/painting/text_style.dart';
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/flex.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/paragraph.dart';
import 'package:sky/rendering/sky_binding.dart';
import 'package:sky/rendering/proxy_box.dart';
import 'solid_color_box.dart';
......
......@@ -7,6 +7,7 @@ import 'dart:sky' as sky;
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/proxy_box.dart';
import 'package:sky/rendering/sky_binding.dart';
const double kTwoPi = 2 * math.PI;
......
......@@ -4,7 +4,8 @@
import 'dart:sky';
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/proxy_box.dart';
import 'package:sky/rendering/shifted_box.dart';
import 'package:sky/rendering/sky_binding.dart';
import 'package:sky/theme/colors.dart';
import 'package:sky/theme/shadows.dart';
......
......@@ -3,11 +3,12 @@
// found in the LICENSE file.
import 'dart:sky';
import 'package:sky/rendering/box.dart';
import 'package:cassowary/cassowary.dart' as al;
import 'package:sky/rendering/auto_layout.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/proxy_box.dart';
import 'package:sky/rendering/sky_binding.dart';
import 'package:sky/rendering/auto_layout.dart';
import 'package:cassowary/cassowary.dart' as al;
void main() {
RenderDecoratedBox c1 = new RenderDecoratedBox(
......
......@@ -3,8 +3,10 @@
// found in the LICENSE file.
import 'dart:sky' as sky;
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/proxy_box.dart';
class RenderSolidColorBox extends RenderDecoratedBox {
final Size desiredSize;
......
......@@ -5,8 +5,9 @@
import 'dart:sky' as sky;
import 'package:sky/base/scheduler.dart';
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/flex.dart';
import 'package:sky/rendering/proxy_box.dart';
import 'package:sky/rendering/shifted_box.dart';
import 'package:sky/rendering/sky_binding.dart';
import 'package:vector_math/vector_math.dart';
......
......@@ -6,6 +6,7 @@ import 'dart:sky' as sky;
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/flex.dart';
import 'package:sky/rendering/proxy_box.dart';
import 'package:sky/rendering/sky_binding.dart';
import 'package:vector_math/vector_math.dart';
......
......@@ -9,7 +9,6 @@ import 'dart:sky' as sky;
import 'package:sky/editing/input.dart';
import 'package:sky/painting/text_style.dart';
import 'package:sky/rendering/box.dart';
import 'package:sky/theme/colors.dart' as colors;
import 'package:sky/theme/typography.dart' as typography;
import 'package:sky/widgets.dart';
......
......@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/flex.dart';
import 'package:sky/widgets/raised_button.dart';
import 'package:sky/widgets/basic.dart';
......
......@@ -8,7 +8,6 @@ import 'package:sky/animation/curves.dart';
import 'package:sky/base/lerp.dart';
import 'package:sky/painting/box_painter.dart';
import 'package:sky/painting/text_style.dart';
import 'package:sky/rendering/box.dart';
import 'package:sky/theme/colors.dart';
import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/block_viewport.dart';
......
......@@ -5,7 +5,6 @@
import 'package:mojo/mojo/url_response.mojom.dart';
import 'package:sky/mojo/net/fetch.dart';
import 'package:sky/mojo/shell.dart' as shell;
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/flex.dart';
import 'package:sky/theme/colors.dart' as colors;
import 'package:sky/widgets/basic.dart';
......
......@@ -5,12 +5,13 @@
import 'dart:sky' as sky;
import 'package:sky/base/scheduler.dart' as scheduler;
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/flex.dart';
import 'package:sky/rendering/proxy_box.dart';
import 'package:sky/rendering/shifted_box.dart';
import 'package:sky/rendering/sky_binding.dart';
import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/raised_button.dart';
import 'package:sky/widgets/framework.dart';
import 'package:sky/widgets/raised_button.dart';
import 'package:vector_math/vector_math.dart';
import '../rendering/solid_color_box.dart';
......
......@@ -8,11 +8,9 @@ import 'dart:sky' as sky;
import 'package:sky/base/debug.dart';
import 'package:sky/painting/box_painter.dart';
import 'package:sky/painting/text_style.dart';
import 'package:sky/rendering/layer.dart';
import 'package:sky/rendering/object.dart';
import 'package:vector_math/vector_math.dart';
export 'package:sky/painting/box_painter.dart';
export 'package:sky/painting/text_style.dart' show TextBaseline;
// GENERIC BOX RENDERING
......@@ -478,1265 +476,6 @@ abstract class RenderBox extends RenderObject {
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}size: ${size}\n';
}
class RenderProxyBox extends RenderBox with RenderObjectWithChildMixin<RenderBox> {
// ProxyBox assumes the child will be at 0,0 and will have the same size
RenderProxyBox([RenderBox child = null]) {
this.child = child;
}
double getMinIntrinsicWidth(BoxConstraints constraints) {
if (child != null)
return child.getMinIntrinsicWidth(constraints);
return super.getMinIntrinsicWidth(constraints);
}
double getMaxIntrinsicWidth(BoxConstraints constraints) {
if (child != null)
return child.getMaxIntrinsicWidth(constraints);
return super.getMaxIntrinsicWidth(constraints);
}
double getMinIntrinsicHeight(BoxConstraints constraints) {
if (child != null)
return child.getMinIntrinsicHeight(constraints);
return super.getMinIntrinsicHeight(constraints);
}
double getMaxIntrinsicHeight(BoxConstraints constraints) {
if (child != null)
return child.getMaxIntrinsicHeight(constraints);
return super.getMaxIntrinsicHeight(constraints);
}
double computeDistanceToActualBaseline(TextBaseline baseline) {
if (child != null)
return child.getDistanceToActualBaseline(baseline);
return super.computeDistanceToActualBaseline(baseline);
}
void performLayout() {
if (child != null) {
child.layout(constraints, parentUsesSize: true);
size = child.size;
} else {
performResize();
}
}
void hitTestChildren(HitTestResult result, { Point position }) {
if (child != null)
child.hitTest(result, position: position);
else
super.hitTestChildren(result, position: position);
}
void paint(PaintingContext context, Offset offset) {
if (child != null)
context.paintChild(child, offset.toPoint());
}
}
class RenderConstrainedBox extends RenderProxyBox {
RenderConstrainedBox({
RenderBox child,
BoxConstraints additionalConstraints
}) : super(child), _additionalConstraints = additionalConstraints {
assert(additionalConstraints != null);
}
BoxConstraints _additionalConstraints;
BoxConstraints get additionalConstraints => _additionalConstraints;
void set additionalConstraints (BoxConstraints value) {
assert(value != null);
if (_additionalConstraints == value)
return;
_additionalConstraints = value;
markNeedsLayout();
}
double getMinIntrinsicWidth(BoxConstraints constraints) {
if (child != null)
return child.getMinIntrinsicWidth(_additionalConstraints.apply(constraints));
return _additionalConstraints.apply(constraints).constrainWidth(0.0);
}
double getMaxIntrinsicWidth(BoxConstraints constraints) {
if (child != null)
return child.getMaxIntrinsicWidth(_additionalConstraints.apply(constraints));
return _additionalConstraints.apply(constraints).constrainWidth(0.0);
}
double getMinIntrinsicHeight(BoxConstraints constraints) {
if (child != null)
return child.getMinIntrinsicHeight(_additionalConstraints.apply(constraints));
return _additionalConstraints.apply(constraints).constrainHeight(0.0);
}
double getMaxIntrinsicHeight(BoxConstraints constraints) {
if (child != null)
return child.getMaxIntrinsicHeight(_additionalConstraints.apply(constraints));
return _additionalConstraints.apply(constraints).constrainHeight(0.0);
}
void performLayout() {
if (child != null) {
child.layout(_additionalConstraints.apply(constraints), parentUsesSize: true);
size = child.size;
} else {
size = _additionalConstraints.apply(constraints).constrain(Size.zero);
}
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}additionalConstraints: ${additionalConstraints}\n';
}
class RenderAspectRatio extends RenderProxyBox {
RenderAspectRatio({
RenderBox child,
double aspectRatio
}) : super(child), _aspectRatio = aspectRatio {
assert(_aspectRatio != null);
}
double _aspectRatio;
double get aspectRatio => _aspectRatio;
void set aspectRatio (double value) {
assert(value != null);
if (_aspectRatio == value)
return;
_aspectRatio = value;
markNeedsLayout();
}
double getMinIntrinsicHeight(BoxConstraints constraints) {
return _applyAspectRatio(constraints).height;
}
double getMaxIntrinsicHeight(BoxConstraints constraints) {
return _applyAspectRatio(constraints).height;
}
Size _applyAspectRatio(BoxConstraints constraints) {
double width = constraints.constrainWidth();
double height = constraints.constrainHeight(width / _aspectRatio);
return new Size(width, height);
}
bool get sizedByParent => true;
void performResize() {
size = _applyAspectRatio(constraints);
}
void performLayout() {
if (child != null)
child.layout(new BoxConstraints.tight(size));
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}aspectRatio: ${aspectRatio}\n';
}
class RenderShrinkWrapWidth extends RenderProxyBox {
// This class will attempt to size its child to the child's maximum
// intrinsic width, snapped to a multiple of the stepWidth, if one
// is provided, and given the provided constraints; and will then
// adopt the child's resulting dimensions.
// Note: laying out this class is relatively expensive. Avoid using
// it where possible.
RenderShrinkWrapWidth({
double stepWidth,
double stepHeight,
RenderBox child
}) : _stepWidth = stepWidth, _stepHeight = stepHeight, super(child);
double _stepWidth;
double get stepWidth => _stepWidth;
void set stepWidth(double value) {
if (value == _stepWidth)
return;
_stepWidth = value;
markNeedsLayout();
}
double _stepHeight;
double get stepHeight => _stepHeight;
void set stepHeight(double value) {
if (value == _stepHeight)
return;
_stepHeight = value;
markNeedsLayout();
}
static double applyStep(double input, double step) {
if (step == null)
return input;
return (input / step).ceil() * step;
}
BoxConstraints _getInnerConstraints(BoxConstraints constraints) {
if (constraints.hasTightWidth)
return constraints;
double width = child.getMaxIntrinsicWidth(constraints);
assert(width == constraints.constrainWidth(width));
return constraints.applyWidth(applyStep(width, _stepWidth));
}
double getMinIntrinsicWidth(BoxConstraints constraints) {
return getMaxIntrinsicWidth(constraints);
}
double getMaxIntrinsicWidth(BoxConstraints constraints) {
if (child == null)
return constraints.constrainWidth(0.0);
double childResult = child.getMaxIntrinsicWidth(constraints);
return constraints.constrainWidth(applyStep(childResult, _stepWidth));
}
double getMinIntrinsicHeight(BoxConstraints constraints) {
if (child == null)
return constraints.constrainWidth(0.0);
double childResult = child.getMinIntrinsicHeight(_getInnerConstraints(constraints));
return constraints.constrainHeight(applyStep(childResult, _stepHeight));
}
double getMaxIntrinsicHeight(BoxConstraints constraints) {
if (child == null)
return constraints.constrainWidth(0.0);
double childResult = child.getMaxIntrinsicHeight(_getInnerConstraints(constraints));
return constraints.constrainHeight(applyStep(childResult, _stepHeight));
}
void performLayout() {
if (child != null) {
BoxConstraints childConstraints = _getInnerConstraints(constraints);
if (_stepHeight != null)
childConstraints.applyHeight(getMaxIntrinsicHeight(childConstraints));
child.layout(childConstraints, parentUsesSize: true);
size = child.size;
} else {
performResize();
}
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}stepWidth: ${stepWidth}\n${prefix}stepHeight: ${stepHeight}\n';
}
class RenderOpacity extends RenderProxyBox {
RenderOpacity({ RenderBox child, double opacity })
: this._opacity = opacity, super(child) {
assert(opacity >= 0.0 && opacity <= 1.0);
}
double _opacity;
double get opacity => _opacity;
void set opacity (double value) {
assert(value != null);
assert(value >= 0.0 && value <= 1.0);
if (_opacity == value)
return;
_opacity = value;
_cachedPaint = null;
markNeedsPaint();
}
int get _alpha => (_opacity * 255).round();
Paint _cachedPaint;
Paint get _paint {
if (_cachedPaint == null) {
_cachedPaint = new Paint()
..color = new Color.fromARGB(_alpha, 0, 0, 0)
..setTransferMode(sky.TransferMode.srcOver)
..isAntiAlias = false;
}
return _cachedPaint;
}
void paint(PaintingContext context, Offset offset) {
if (child != null) {
int a = _alpha;
if (a == 0)
return;
if (a == 255) {
context.paintChild(child, offset.toPoint());
return;
}
context.canvas.saveLayer(null, _paint); // TODO(abarth): layerize
context.paintChild(child, offset.toPoint());
context.canvas.restore();
}
}
}
class RenderColorFilter extends RenderProxyBox {
RenderColorFilter({ RenderBox child, Color color, sky.TransferMode transferMode })
: _color = color, _transferMode = transferMode, super(child) {
}
Color _color;
Color get color => _color;
void set color (Color value) {
assert(value != null);
if (_color == value)
return;
_color = value;
_cachedPaint = null;
markNeedsPaint();
}
sky.TransferMode _transferMode;
sky.TransferMode get transferMode => _transferMode;
void set transferMode (sky.TransferMode value) {
assert(value != null);
if (_transferMode == value)
return;
_transferMode = value;
_cachedPaint = null;
markNeedsPaint();
}
Paint _cachedPaint;
Paint get _paint {
if (_cachedPaint == null) {
_cachedPaint = new Paint()
..setColorFilter(new sky.ColorFilter.mode(_color, _transferMode))
..isAntiAlias = false;
}
return _cachedPaint;
}
void paint(PaintingContext context, Offset offset) {
if (child != null) {
context.canvas.saveLayer(offset & size, _paint); // TODO(abarth): layerize
context.paintChild(child, offset.toPoint());
context.canvas.restore();
}
}
}
class RenderClipRect extends RenderProxyBox {
RenderClipRect({ RenderBox child }) : super(child);
void paint(PaintingContext context, Offset offset) {
if (child != null)
context.paintChildWithClip(child, offset.toPoint(), Offset.zero & size);
}
}
class RenderClipRRect extends RenderProxyBox {
RenderClipRRect({ RenderBox child, double xRadius, double yRadius })
: _xRadius = xRadius, _yRadius = yRadius, super(child) {
assert(_xRadius != null);
assert(_yRadius != null);
}
double _xRadius;
double get xRadius => _xRadius;
void set xRadius (double value) {
assert(value != null);
if (_xRadius == value)
return;
_xRadius = value;
markNeedsPaint();
}
double _yRadius;
double get yRadius => _yRadius;
void set yRadius (double value) {
assert(value != null);
if (_yRadius == value)
return;
_yRadius = value;
markNeedsPaint();
}
final Paint _paint = new Paint()..isAntiAlias = false;
void paint(PaintingContext context, Offset offset) {
if (child != null) {
Rect rect = offset & size;
context.canvas.saveLayer(rect, _paint); // TODO(abarth): layerize
sky.RRect rrect = new sky.RRect()..setRectXY(rect, xRadius, yRadius);
context.canvas.clipRRect(rrect);
context.paintChild(child, offset.toPoint());
context.canvas.restore();
}
}
}
class RenderClipOval extends RenderProxyBox {
RenderClipOval({ RenderBox child }) : super(child);
final Paint _paint = new Paint()..isAntiAlias = false;
Rect _cachedRect;
Path _cachedPath;
Path _getPath(Rect rect) {
if (rect != _cachedRect) {
_cachedRect = rect;
_cachedPath = new Path()..addOval(_cachedRect);
}
return _cachedPath;
}
void paint(PaintingContext context, Offset offset) {
if (child != null) {
Rect rect = offset & size;
context.canvas.saveLayer(rect, _paint); // TODO(abarth): layerize
context.canvas.clipPath(_getPath(rect));
context.paintChild(child, offset.toPoint());
context.canvas.restore();
}
}
}
abstract class RenderShiftedBox extends RenderBox with RenderObjectWithChildMixin<RenderBox> {
// Abstract class for one-child-layout render boxes
RenderShiftedBox(RenderBox child) {
this.child = child;
}
double getMinIntrinsicWidth(BoxConstraints constraints) {
if (child != null)
return child.getMinIntrinsicWidth(constraints);
return super.getMinIntrinsicWidth(constraints);
}
double getMaxIntrinsicWidth(BoxConstraints constraints) {
if (child != null)
return child.getMaxIntrinsicWidth(constraints);
return super.getMaxIntrinsicWidth(constraints);
}
double getMinIntrinsicHeight(BoxConstraints constraints) {
if (child != null)
return child.getMinIntrinsicHeight(constraints);
return super.getMinIntrinsicHeight(constraints);
}
double getMaxIntrinsicHeight(BoxConstraints constraints) {
if (child != null)
return child.getMaxIntrinsicHeight(constraints);
return super.getMaxIntrinsicHeight(constraints);
}
double computeDistanceToActualBaseline(TextBaseline baseline) {
double result;
if (child != null) {
assert(!needsLayout);
result = child.getDistanceToActualBaseline(baseline);
assert(child.parentData is BoxParentData);
if (result != null)
result += child.parentData.position.y;
} else {
result = super.computeDistanceToActualBaseline(baseline);
}
return result;
}
void paint(PaintingContext context, Offset offset) {
if (child != null)
context.paintChild(child, child.parentData.position + offset);
}
void hitTestChildren(HitTestResult result, { Point position }) {
if (child != null) {
assert(child.parentData is BoxParentData);
child.hitTest(result, position: new Point(position.x - child.parentData.position.x,
position.y - child.parentData.position.y));
}
}
}
class RenderPadding extends RenderShiftedBox {
RenderPadding({ EdgeDims padding, RenderBox child }) : super(child) {
assert(padding != null);
this.padding = padding;
}
EdgeDims _padding;
EdgeDims get padding => _padding;
void set padding (EdgeDims value) {
assert(value != null);
if (_padding == value)
return;
_padding = value;
markNeedsLayout();
}
double getMinIntrinsicWidth(BoxConstraints constraints) {
double totalPadding = padding.left + padding.right;
if (child != null)
return child.getMinIntrinsicWidth(constraints.deflate(padding)) + totalPadding;
return constraints.constrainWidth(totalPadding);
}
double getMaxIntrinsicWidth(BoxConstraints constraints) {
double totalPadding = padding.left + padding.right;
if (child != null)
return child.getMaxIntrinsicWidth(constraints.deflate(padding)) + totalPadding;
return constraints.constrainWidth(totalPadding);
}
double getMinIntrinsicHeight(BoxConstraints constraints) {
double totalPadding = padding.top + padding.bottom;
if (child != null)
return child.getMinIntrinsicHeight(constraints.deflate(padding)) + totalPadding;
return constraints.constrainHeight(totalPadding);
}
double getMaxIntrinsicHeight(BoxConstraints constraints) {
double totalPadding = padding.top + padding.bottom;
if (child != null)
return child.getMaxIntrinsicHeight(constraints.deflate(padding)) + totalPadding;
return constraints.constrainHeight(totalPadding);
}
void performLayout() {
assert(padding != null);
if (child == null) {
size = constraints.constrain(new Size(
padding.left + padding.right,
padding.top + padding.bottom
));
return;
}
BoxConstraints innerConstraints = constraints.deflate(padding);
child.layout(innerConstraints, parentUsesSize: true);
assert(child.parentData is BoxParentData);
child.parentData.position = new Point(padding.left, padding.top);
size = constraints.constrain(new Size(
padding.left + child.size.width + padding.right,
padding.top + child.size.height + padding.bottom
));
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}padding: ${padding}\n';
}
class RenderPositionedBox extends RenderShiftedBox {
// This box aligns a child box within itself. It's only useful for
// children that don't always size to fit their parent. For example,
// to align a box at the bottom right, you would pass this box a
// tight constraint that is bigger than the child's natural size,
// with horizontal and vertical set to 1.0.
RenderPositionedBox({
RenderBox child,
double horizontal: 0.5,
double vertical: 0.5
}) : _horizontal = horizontal,
_vertical = vertical,
super(child) {
assert(horizontal != null);
assert(vertical != null);
}
double _horizontal;
double get horizontal => _horizontal;
void set horizontal (double value) {
assert(value != null);
if (_horizontal == value)
return;
_horizontal = value;
markNeedsLayout();
}
double _vertical;
double get vertical => _vertical;
void set vertical (double value) {
assert(value != null);
if (_vertical == value)
return;
_vertical = value;
markNeedsLayout();
}
void performLayout() {
if (child != null) {
child.layout(constraints.loosen(), parentUsesSize: true);
size = constraints.constrain(child.size);
assert(child.parentData is BoxParentData);
Offset delta = size - child.size;
child.parentData.position = (delta.scale(horizontal, vertical)).toPoint();
} else {
performResize();
}
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}horizontal: ${horizontal}\n${prefix}vertical: ${vertical}\n';
}
class RenderBaseline extends RenderShiftedBox {
RenderBaseline({
RenderBox child,
double baseline,
TextBaseline baselineType
}) : _baseline = baseline,
_baselineType = baselineType,
super(child) {
assert(baseline != null);
assert(baselineType != null);
}
double _baseline;
double get baseline => _baseline;
void set baseline (double value) {
assert(value != null);
if (_baseline == value)
return;
_baseline = value;
markNeedsLayout();
}
TextBaseline _baselineType;
TextBaseline get baselineType => _baselineType;
void set baselineType (TextBaseline value) {
assert(value != null);
if (_baselineType == value)
return;
_baselineType = value;
markNeedsLayout();
}
void performLayout() {
if (child != null) {
child.layout(constraints.loosen(), parentUsesSize: true);
size = constraints.constrain(child.size);
assert(child.parentData is BoxParentData);
double delta = baseline - child.getDistanceToBaseline(baselineType);
child.parentData.position = new Point(0.0, delta);
} else {
performResize();
}
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}baseline: ${baseline}\nbaselineType: ${baselineType}';
}
enum ScrollDirection { horizontal, vertical, both }
class RenderViewport extends RenderBox with RenderObjectWithChildMixin<RenderBox> {
RenderViewport({
RenderBox child,
Offset scrollOffset,
ScrollDirection scrollDirection: ScrollDirection.vertical
}) : _scrollOffset = scrollOffset,
_scrollDirection = scrollDirection {
assert(_offsetIsSane(scrollOffset, scrollDirection));
this.child = child;
}
bool _offsetIsSane(Offset offset, ScrollDirection direction) {
switch (direction) {
case ScrollDirection.both:
return true;
case ScrollDirection.horizontal:
return offset.dy == 0.0;
case ScrollDirection.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();
}
ScrollDirection _scrollDirection;
ScrollDirection get scrollDirection => _scrollDirection;
void set scrollDirection(ScrollDirection value) {
if (value == _scrollDirection)
return;
assert(_offsetIsSane(scrollOffset, value));
_scrollDirection = value;
markNeedsLayout();
}
BoxConstraints _getInnerConstraints(BoxConstraints constraints) {
BoxConstraints innerConstraints;
switch (scrollDirection) {
case ScrollDirection.both:
innerConstraints = new BoxConstraints();
break;
case ScrollDirection.horizontal:
innerConstraints = constraints.heightConstraints();
break;
case ScrollDirection.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();
}
}
Offset get _scrollOffsetRoundedToIntegerDevicePixels {
double devicePixelRatio = sky.view.devicePixelRatio;
int dxInDevicePixels = (scrollOffset.dx * devicePixelRatio).round();
int dyInDevicePixels = (scrollOffset.dy * devicePixelRatio).round();
return new Offset(dxInDevicePixels / devicePixelRatio,
dyInDevicePixels / devicePixelRatio);
}
void paint(PaintingContext context, Offset offset) {
if (child != null) {
Offset roundedScrollOffset = _scrollOffsetRoundedToIntegerDevicePixels;
bool _needsClip = offset < Offset.zero ||
!(offset & size).contains(((offset - roundedScrollOffset) & child.size).bottomRight);
if (_needsClip) {
context.canvas.save();
context.canvas.clipRect(offset & size);
}
context.paintChild(child, (offset - roundedScrollOffset).toPoint());
if (_needsClip)
context.canvas.restore();
}
}
void applyPaintTransform(Matrix4 transform) {
super.applyPaintTransform(transform);
transform.translate(-scrollOffset.dx, -scrollOffset.dy);
}
void hitTestChildren(HitTestResult result, { Point position }) {
if (child != null) {
assert(child.parentData is BoxParentData);
Point transformed = position + _scrollOffsetRoundedToIntegerDevicePixels;
child.hitTest(result, position: transformed);
}
}
}
class RenderImage extends RenderBox {
RenderImage({
sky.Image image,
double width,
double height,
sky.ColorFilter colorFilter,
fit: ImageFit.scaleDown,
repeat: ImageRepeat.noRepeat
}) : _image = image,
_width = width,
_height = height,
_colorFilter = colorFilter,
_fit = fit,
_repeat = repeat;
sky.Image _image;
sky.Image get image => _image;
void set image (sky.Image value) {
if (value == _image)
return;
_image = value;
markNeedsPaint();
if (_width == null || _height == null)
markNeedsLayout();
}
double _width;
double get width => _width;
void set width (double value) {
if (value == _width)
return;
_width = value;
markNeedsLayout();
}
double _height;
double get height => _height;
void set height (double value) {
if (value == _height)
return;
_height = value;
markNeedsLayout();
}
sky.ColorFilter _colorFilter;
sky.ColorFilter get colorFilter => _colorFilter;
void set colorFilter (sky.ColorFilter value) {
if (value == _colorFilter)
return;
_colorFilter = value;
markNeedsPaint();
}
ImageFit _fit;
ImageFit get fit => _fit;
void set fit (ImageFit value) {
if (value == _fit)
return;
_fit = value;
markNeedsPaint();
}
ImageRepeat _repeat;
ImageRepeat get repeat => _repeat;
void set repeat (ImageRepeat value) {
if (value == _repeat)
return;
_repeat = value;
markNeedsPaint();
}
Size _sizeForConstraints(BoxConstraints constraints) {
// Folds the given |width| and |height| into |cosntraints| so they can all
// be treated uniformly.
constraints = new BoxConstraints.tightFor(
width: _width,
height: _height
).apply(constraints);
if (constraints.isTight || _image == null)
return constraints.smallest;
// This algorithm attempts to find a size for the RenderImage that fits in
// the given constraints and preserves the image's intrinisc aspect ratio.
// Its goals as follow:
//
// - The dimensions of the RenderImage fit within the constraints.
// - The aspect ratio of the RenderImage matches the instrinsic aspect
// ratio of the image.
// - The RenderImage's dimension are maximal subject to being smaller than
// the intrinsic size of the image.
double width = _image.width.toDouble();
double height = _image.height.toDouble();
assert(width > 0.0);
assert(height > 0.0);
double aspectRatio = width / height;
if (width > constraints.maxWidth) {
width = constraints.maxWidth;
height = width / aspectRatio;
}
if (height > constraints.maxHeight) {
height = constraints.maxHeight;
width = height * aspectRatio;
}
if (width < constraints.minWidth) {
width = constraints.minWidth;
height = width / aspectRatio;
}
if (height < constraints.minHeight) {
height = constraints.minHeight;
width = height * aspectRatio;
}
return constraints.constrain(new Size(width, height));
}
double getMinIntrinsicWidth(BoxConstraints constraints) {
if (_width == null && _height == null)
return constraints.constrainWidth(0.0);
return _sizeForConstraints(constraints).width;
}
double getMaxIntrinsicWidth(BoxConstraints constraints) {
return _sizeForConstraints(constraints).width;
}
double getMinIntrinsicHeight(BoxConstraints constraints) {
if (_width == null && _height == null)
return constraints.constrainHeight(0.0);
return _sizeForConstraints(constraints).height;
}
double getMaxIntrinsicHeight(BoxConstraints constraints) {
return _sizeForConstraints(constraints).height;
}
void performLayout() {
size = _sizeForConstraints(constraints);
}
void paint(PaintingContext context, Offset offset) {
if (_image == null)
return;
paintImage(
canvas: context.canvas,
rect: offset & size,
image: _image,
colorFilter: _colorFilter,
fit: _fit,
repeat: _repeat
);
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}width: ${width}\n${prefix}height: ${height}\n';
}
class RenderDecoratedBox extends RenderProxyBox {
RenderDecoratedBox({
BoxDecoration decoration,
RenderBox child
}) : _painter = new BoxPainter(decoration), super(child);
final BoxPainter _painter;
BoxDecoration get decoration => _painter.decoration;
void set decoration (BoxDecoration value) {
assert(value != null);
if (value == _painter.decoration)
return;
_removeBackgroundImageListenerIfNeeded();
_painter.decoration = value;
_addBackgroundImageListenerIfNeeded();
markNeedsPaint();
}
bool get _needsBackgroundImageListener {
return attached &&
_painter.decoration != null &&
_painter.decoration.backgroundImage != null;
}
void _addBackgroundImageListenerIfNeeded() {
if (_needsBackgroundImageListener)
_painter.decoration.backgroundImage.addChangeListener(markNeedsPaint);
}
void _removeBackgroundImageListenerIfNeeded() {
if (_needsBackgroundImageListener)
_painter.decoration.backgroundImage.removeChangeListener(markNeedsPaint);
}
void attach() {
super.attach();
_addBackgroundImageListenerIfNeeded();
}
void detach() {
_removeBackgroundImageListenerIfNeeded();
super.detach();
}
void paint(PaintingContext context, Offset offset) {
assert(size.width != null);
assert(size.height != null);
_painter.paint(context.canvas, offset & size);
super.paint(context, offset);
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}decoration:\n${_painter.decoration.toString(prefix + " ")}\n';
}
class RenderTransform extends RenderProxyBox {
RenderTransform({
Matrix4 transform,
RenderBox child
}) : super(child) {
assert(transform != null);
this.transform = transform;
}
Matrix4 _transform;
void set transform(Matrix4 value) {
assert(value != null);
if (_transform == value)
return;
_transform = new Matrix4.copy(value);
markNeedsPaint();
}
void setIdentity() {
_transform.setIdentity();
markNeedsPaint();
}
void rotateX(double radians) {
_transform.rotateX(radians);
markNeedsPaint();
}
void rotateY(double radians) {
_transform.rotateY(radians);
markNeedsPaint();
}
void rotateZ(double radians) {
_transform.rotateZ(radians);
markNeedsPaint();
}
void translate(x, [double y = 0.0, double z = 0.0]) {
_transform.translate(x, y, z);
markNeedsPaint();
}
void scale(x, [double y, double z]) {
_transform.scale(x, y, z);
markNeedsPaint();
}
bool hitTest(HitTestResult result, { Point position }) {
Matrix4 inverse = new Matrix4.zero();
// TODO(abarth): Check the determinant for degeneracy.
inverse.copyInverse(_transform);
Vector3 position3 = new Vector3(position.x, position.y, 0.0);
Vector3 transformed3 = inverse.transform3(position3);
Point transformed = new Point(transformed3.x, transformed3.y);
return super.hitTest(result, position: transformed);
}
void paint(PaintingContext context, Offset offset) {
context.canvas.save();
context.canvas.translate(offset.dx, offset.dy);
context.canvas.concat(_transform.storage);
super.paint(context, Offset.zero);
context.canvas.restore();
}
void applyPaintTransform(Matrix4 transform) {
super.applyPaintTransform(transform);
transform.multiply(_transform);
}
String debugDescribeSettings(String prefix) {
List<String> result = _transform.toString().split('\n').map((s) => '$prefix $s\n').toList();
result.removeLast();
return '${super.debugDescribeSettings(prefix)}${prefix}transform matrix:\n${result.join()}';
}
}
typedef void SizeChangedCallback(Size newSize);
class RenderSizeObserver extends RenderProxyBox {
RenderSizeObserver({
this.callback,
RenderBox child
}) : super(child) {
assert(callback != null);
}
SizeChangedCallback callback;
void performLayout() {
Size oldSize = size;
super.performLayout();
if (oldSize != size)
callback(size);
}
}
typedef void CustomPaintCallback(PaintingCanvas canvas, Size size);
class RenderCustomPaint extends RenderProxyBox {
RenderCustomPaint({
CustomPaintCallback callback,
RenderBox child
}) : super(child) {
assert(callback != null);
_callback = callback;
}
CustomPaintCallback _callback;
void set callback (CustomPaintCallback value) {
assert(value != null || !attached);
if (_callback == value)
return;
_callback = value;
markNeedsPaint();
}
void attach() {
assert(_callback != null);
super.attach();
}
void paint(PaintingContext context, Offset offset) {
assert(_callback != null);
context.canvas.translate(offset.dx, offset.dy);
_callback(context.canvas, size);
// TODO(abarth): We should translate back before calling super because in
// the future, super.paint might switch our compositing layer.
super.paint(context, Offset.zero);
context.canvas.translate(-offset.dx, -offset.dy);
}
}
// RENDER VIEW LAYOUT MANAGER
class ViewConstraints {
const ViewConstraints({
this.size: Size.zero,
this.orientation
});
final Size size;
final int orientation;
}
class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox> {
RenderView({
RenderBox child,
this.timeForRotation: const Duration(microseconds: 83333)
}) {
this.child = child;
}
Size _size = Size.zero;
Size get size => _size;
int _orientation; // 0..3
int get orientation => _orientation;
Duration timeForRotation;
ViewConstraints _rootConstraints;
ViewConstraints get rootConstraints => _rootConstraints;
void set rootConstraints(ViewConstraints value) {
if (_rootConstraints == value)
return;
_rootConstraints = value;
markNeedsLayout();
}
ContainerLayer _rootLayer;
// We never call layout() on this class, so this should never get
// checked. (This class is laid out using scheduleInitialLayout().)
bool debugDoesMeetConstraints() { assert(false); return false; }
void performResize() {
assert(false);
}
void performLayout() {
if (_rootConstraints.orientation != _orientation) {
if (_orientation != null && child != null)
child.rotate(oldAngle: _orientation, newAngle: _rootConstraints.orientation, time: timeForRotation);
_orientation = _rootConstraints.orientation;
}
_size = _rootConstraints.size;
assert(!_size.isInfinite);
if (child != null)
child.layout(new BoxConstraints.tight(_size));
}
void rotate({ int oldAngle, int newAngle, Duration time }) {
assert(false); // nobody tells the screen to rotate, the whole rotate() dance is started from our performResize()
}
bool hitTest(HitTestResult result, { Point position }) {
if (child != null) {
Rect childBounds = Point.origin & child.size;
if (childBounds.contains(position))
child.hitTest(result, position: position);
}
result.add(new HitTestEntry(this));
return true;
}
void paint(PaintingContext context, Offset offset) {
if (child != null)
context.paintChild(child, offset.toPoint());
}
void paintFrame() {
sky.tracing.begin('RenderView.paintFrame');
try {
final double devicePixelRatio = sky.view.devicePixelRatio;
Matrix4 transform = new Matrix4.diagonal3Values(devicePixelRatio, devicePixelRatio, 1.0);
_rootLayer = new TransformLayer(transform: transform);
PaintingContext context = new PaintingContext(Offset.zero, size);
_rootLayer.add(context.layer);
context.paintChild(child, Point.origin);
context.endRecording();
} finally {
sky.tracing.end('RenderView.paintFrame');
}
}
void compositeFrame() {
sky.tracing.begin('RenderView.compositeFrame');
try {
sky.PictureRecorder recorder = new sky.PictureRecorder();
sky.Canvas canvas = new sky.Canvas(recorder, Point.origin & (size * sky.view.devicePixelRatio));
_rootLayer.paint(canvas);
sky.view.picture = recorder.endRecording();
} finally {
sky.tracing.end('RenderView.compositeFrame');
}
}
Rect get paintBounds => Point.origin & size;
}
class RenderIgnorePointer extends RenderProxyBox {
RenderIgnorePointer({ RenderBox child }) : super(child);
bool hitTest(HitTestResult result, { Point position }) {
return false;
}
}
// HELPER METHODS FOR RENDERBOX CONTAINERS
abstract class RenderBoxContainerDefaultsMixin<ChildType extends RenderBox, ParentDataType extends ContainerParentDataMixin<ChildType>> implements ContainerRenderObjectMixin<ChildType, ParentDataType> {
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:sky' as sky;
import 'package:sky/painting/box_painter.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/box.dart';
class RenderImage extends RenderBox {
RenderImage({
sky.Image image,
double width,
double height,
sky.ColorFilter colorFilter,
fit: ImageFit.scaleDown,
repeat: ImageRepeat.noRepeat
}) : _image = image,
_width = width,
_height = height,
_colorFilter = colorFilter,
_fit = fit,
_repeat = repeat;
sky.Image _image;
sky.Image get image => _image;
void set image (sky.Image value) {
if (value == _image)
return;
_image = value;
markNeedsPaint();
if (_width == null || _height == null)
markNeedsLayout();
}
double _width;
double get width => _width;
void set width (double value) {
if (value == _width)
return;
_width = value;
markNeedsLayout();
}
double _height;
double get height => _height;
void set height (double value) {
if (value == _height)
return;
_height = value;
markNeedsLayout();
}
sky.ColorFilter _colorFilter;
sky.ColorFilter get colorFilter => _colorFilter;
void set colorFilter (sky.ColorFilter value) {
if (value == _colorFilter)
return;
_colorFilter = value;
markNeedsPaint();
}
ImageFit _fit;
ImageFit get fit => _fit;
void set fit (ImageFit value) {
if (value == _fit)
return;
_fit = value;
markNeedsPaint();
}
ImageRepeat _repeat;
ImageRepeat get repeat => _repeat;
void set repeat (ImageRepeat value) {
if (value == _repeat)
return;
_repeat = value;
markNeedsPaint();
}
Size _sizeForConstraints(BoxConstraints constraints) {
// Folds the given |width| and |height| into |cosntraints| so they can all
// be treated uniformly.
constraints = new BoxConstraints.tightFor(
width: _width,
height: _height
).apply(constraints);
if (constraints.isTight || _image == null)
return constraints.smallest;
// This algorithm attempts to find a size for the RenderImage that fits in
// the given constraints and preserves the image's intrinisc aspect ratio.
// Its goals as follow:
//
// - The dimensions of the RenderImage fit within the constraints.
// - The aspect ratio of the RenderImage matches the instrinsic aspect
// ratio of the image.
// - The RenderImage's dimension are maximal subject to being smaller than
// the intrinsic size of the image.
double width = _image.width.toDouble();
double height = _image.height.toDouble();
assert(width > 0.0);
assert(height > 0.0);
double aspectRatio = width / height;
if (width > constraints.maxWidth) {
width = constraints.maxWidth;
height = width / aspectRatio;
}
if (height > constraints.maxHeight) {
height = constraints.maxHeight;
width = height * aspectRatio;
}
if (width < constraints.minWidth) {
width = constraints.minWidth;
height = width / aspectRatio;
}
if (height < constraints.minHeight) {
height = constraints.minHeight;
width = height * aspectRatio;
}
return constraints.constrain(new Size(width, height));
}
double getMinIntrinsicWidth(BoxConstraints constraints) {
if (_width == null && _height == null)
return constraints.constrainWidth(0.0);
return _sizeForConstraints(constraints).width;
}
double getMaxIntrinsicWidth(BoxConstraints constraints) {
return _sizeForConstraints(constraints).width;
}
double getMinIntrinsicHeight(BoxConstraints constraints) {
if (_width == null && _height == null)
return constraints.constrainHeight(0.0);
return _sizeForConstraints(constraints).height;
}
double getMaxIntrinsicHeight(BoxConstraints constraints) {
return _sizeForConstraints(constraints).height;
}
void performLayout() {
size = _sizeForConstraints(constraints);
}
void paint(PaintingContext context, Offset offset) {
if (_image == null)
return;
paintImage(
canvas: context.canvas,
rect: offset & size,
image: _image,
colorFilter: _colorFilter,
fit: _fit,
repeat: _repeat
);
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}width: ${width}\n${prefix}height: ${height}\n';
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:sky' as sky;
import 'package:sky/painting/box_painter.dart';
import 'package:sky/painting/text_style.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/box.dart';
import 'package:vector_math/vector_math.dart';
export 'package:sky/painting/box_painter.dart';
class RenderProxyBox extends RenderBox with RenderObjectWithChildMixin<RenderBox> {
// ProxyBox assumes the child will be at 0,0 and will have the same size
RenderProxyBox([RenderBox child = null]) {
this.child = child;
}
double getMinIntrinsicWidth(BoxConstraints constraints) {
if (child != null)
return child.getMinIntrinsicWidth(constraints);
return super.getMinIntrinsicWidth(constraints);
}
double getMaxIntrinsicWidth(BoxConstraints constraints) {
if (child != null)
return child.getMaxIntrinsicWidth(constraints);
return super.getMaxIntrinsicWidth(constraints);
}
double getMinIntrinsicHeight(BoxConstraints constraints) {
if (child != null)
return child.getMinIntrinsicHeight(constraints);
return super.getMinIntrinsicHeight(constraints);
}
double getMaxIntrinsicHeight(BoxConstraints constraints) {
if (child != null)
return child.getMaxIntrinsicHeight(constraints);
return super.getMaxIntrinsicHeight(constraints);
}
double computeDistanceToActualBaseline(TextBaseline baseline) {
if (child != null)
return child.getDistanceToActualBaseline(baseline);
return super.computeDistanceToActualBaseline(baseline);
}
void performLayout() {
if (child != null) {
child.layout(constraints, parentUsesSize: true);
size = child.size;
} else {
performResize();
}
}
void hitTestChildren(HitTestResult result, { Point position }) {
if (child != null)
child.hitTest(result, position: position);
else
super.hitTestChildren(result, position: position);
}
void paint(PaintingContext context, Offset offset) {
if (child != null)
context.paintChild(child, offset.toPoint());
}
}
class RenderConstrainedBox extends RenderProxyBox {
RenderConstrainedBox({
RenderBox child,
BoxConstraints additionalConstraints
}) : super(child), _additionalConstraints = additionalConstraints {
assert(additionalConstraints != null);
}
BoxConstraints _additionalConstraints;
BoxConstraints get additionalConstraints => _additionalConstraints;
void set additionalConstraints (BoxConstraints value) {
assert(value != null);
if (_additionalConstraints == value)
return;
_additionalConstraints = value;
markNeedsLayout();
}
double getMinIntrinsicWidth(BoxConstraints constraints) {
if (child != null)
return child.getMinIntrinsicWidth(_additionalConstraints.apply(constraints));
return _additionalConstraints.apply(constraints).constrainWidth(0.0);
}
double getMaxIntrinsicWidth(BoxConstraints constraints) {
if (child != null)
return child.getMaxIntrinsicWidth(_additionalConstraints.apply(constraints));
return _additionalConstraints.apply(constraints).constrainWidth(0.0);
}
double getMinIntrinsicHeight(BoxConstraints constraints) {
if (child != null)
return child.getMinIntrinsicHeight(_additionalConstraints.apply(constraints));
return _additionalConstraints.apply(constraints).constrainHeight(0.0);
}
double getMaxIntrinsicHeight(BoxConstraints constraints) {
if (child != null)
return child.getMaxIntrinsicHeight(_additionalConstraints.apply(constraints));
return _additionalConstraints.apply(constraints).constrainHeight(0.0);
}
void performLayout() {
if (child != null) {
child.layout(_additionalConstraints.apply(constraints), parentUsesSize: true);
size = child.size;
} else {
size = _additionalConstraints.apply(constraints).constrain(Size.zero);
}
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}additionalConstraints: ${additionalConstraints}\n';
}
class RenderAspectRatio extends RenderProxyBox {
RenderAspectRatio({
RenderBox child,
double aspectRatio
}) : super(child), _aspectRatio = aspectRatio {
assert(_aspectRatio != null);
}
double _aspectRatio;
double get aspectRatio => _aspectRatio;
void set aspectRatio (double value) {
assert(value != null);
if (_aspectRatio == value)
return;
_aspectRatio = value;
markNeedsLayout();
}
double getMinIntrinsicHeight(BoxConstraints constraints) {
return _applyAspectRatio(constraints).height;
}
double getMaxIntrinsicHeight(BoxConstraints constraints) {
return _applyAspectRatio(constraints).height;
}
Size _applyAspectRatio(BoxConstraints constraints) {
double width = constraints.constrainWidth();
double height = constraints.constrainHeight(width / _aspectRatio);
return new Size(width, height);
}
bool get sizedByParent => true;
void performResize() {
size = _applyAspectRatio(constraints);
}
void performLayout() {
if (child != null)
child.layout(new BoxConstraints.tight(size));
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}aspectRatio: ${aspectRatio}\n';
}
class RenderShrinkWrapWidth extends RenderProxyBox {
// This class will attempt to size its child to the child's maximum
// intrinsic width, snapped to a multiple of the stepWidth, if one
// is provided, and given the provided constraints; and will then
// adopt the child's resulting dimensions.
// Note: laying out this class is relatively expensive. Avoid using
// it where possible.
RenderShrinkWrapWidth({
double stepWidth,
double stepHeight,
RenderBox child
}) : _stepWidth = stepWidth, _stepHeight = stepHeight, super(child);
double _stepWidth;
double get stepWidth => _stepWidth;
void set stepWidth(double value) {
if (value == _stepWidth)
return;
_stepWidth = value;
markNeedsLayout();
}
double _stepHeight;
double get stepHeight => _stepHeight;
void set stepHeight(double value) {
if (value == _stepHeight)
return;
_stepHeight = value;
markNeedsLayout();
}
static double applyStep(double input, double step) {
if (step == null)
return input;
return (input / step).ceil() * step;
}
BoxConstraints _getInnerConstraints(BoxConstraints constraints) {
if (constraints.hasTightWidth)
return constraints;
double width = child.getMaxIntrinsicWidth(constraints);
assert(width == constraints.constrainWidth(width));
return constraints.applyWidth(applyStep(width, _stepWidth));
}
double getMinIntrinsicWidth(BoxConstraints constraints) {
return getMaxIntrinsicWidth(constraints);
}
double getMaxIntrinsicWidth(BoxConstraints constraints) {
if (child == null)
return constraints.constrainWidth(0.0);
double childResult = child.getMaxIntrinsicWidth(constraints);
return constraints.constrainWidth(applyStep(childResult, _stepWidth));
}
double getMinIntrinsicHeight(BoxConstraints constraints) {
if (child == null)
return constraints.constrainWidth(0.0);
double childResult = child.getMinIntrinsicHeight(_getInnerConstraints(constraints));
return constraints.constrainHeight(applyStep(childResult, _stepHeight));
}
double getMaxIntrinsicHeight(BoxConstraints constraints) {
if (child == null)
return constraints.constrainWidth(0.0);
double childResult = child.getMaxIntrinsicHeight(_getInnerConstraints(constraints));
return constraints.constrainHeight(applyStep(childResult, _stepHeight));
}
void performLayout() {
if (child != null) {
BoxConstraints childConstraints = _getInnerConstraints(constraints);
if (_stepHeight != null)
childConstraints.applyHeight(getMaxIntrinsicHeight(childConstraints));
child.layout(childConstraints, parentUsesSize: true);
size = child.size;
} else {
performResize();
}
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}stepWidth: ${stepWidth}\n${prefix}stepHeight: ${stepHeight}\n';
}
class RenderOpacity extends RenderProxyBox {
RenderOpacity({ RenderBox child, double opacity })
: this._opacity = opacity, super(child) {
assert(opacity >= 0.0 && opacity <= 1.0);
}
double _opacity;
double get opacity => _opacity;
void set opacity (double value) {
assert(value != null);
assert(value >= 0.0 && value <= 1.0);
if (_opacity == value)
return;
_opacity = value;
_cachedPaint = null;
markNeedsPaint();
}
int get _alpha => (_opacity * 255).round();
Paint _cachedPaint;
Paint get _paint {
if (_cachedPaint == null) {
_cachedPaint = new Paint()
..color = new Color.fromARGB(_alpha, 0, 0, 0)
..setTransferMode(sky.TransferMode.srcOver)
..isAntiAlias = false;
}
return _cachedPaint;
}
void paint(PaintingContext context, Offset offset) {
if (child != null) {
int a = _alpha;
if (a == 0)
return;
if (a == 255) {
context.paintChild(child, offset.toPoint());
return;
}
context.canvas.saveLayer(null, _paint); // TODO(abarth): layerize
context.paintChild(child, offset.toPoint());
context.canvas.restore();
}
}
}
class RenderColorFilter extends RenderProxyBox {
RenderColorFilter({ RenderBox child, Color color, sky.TransferMode transferMode })
: _color = color, _transferMode = transferMode, super(child) {
}
Color _color;
Color get color => _color;
void set color (Color value) {
assert(value != null);
if (_color == value)
return;
_color = value;
_cachedPaint = null;
markNeedsPaint();
}
sky.TransferMode _transferMode;
sky.TransferMode get transferMode => _transferMode;
void set transferMode (sky.TransferMode value) {
assert(value != null);
if (_transferMode == value)
return;
_transferMode = value;
_cachedPaint = null;
markNeedsPaint();
}
Paint _cachedPaint;
Paint get _paint {
if (_cachedPaint == null) {
_cachedPaint = new Paint()
..setColorFilter(new sky.ColorFilter.mode(_color, _transferMode))
..isAntiAlias = false;
}
return _cachedPaint;
}
void paint(PaintingContext context, Offset offset) {
if (child != null) {
context.canvas.saveLayer(offset & size, _paint); // TODO(abarth): layerize
context.paintChild(child, offset.toPoint());
context.canvas.restore();
}
}
}
class RenderClipRect extends RenderProxyBox {
RenderClipRect({ RenderBox child }) : super(child);
void paint(PaintingContext context, Offset offset) {
if (child != null)
context.paintChildWithClip(child, offset.toPoint(), Offset.zero & size);
}
}
class RenderClipRRect extends RenderProxyBox {
RenderClipRRect({ RenderBox child, double xRadius, double yRadius })
: _xRadius = xRadius, _yRadius = yRadius, super(child) {
assert(_xRadius != null);
assert(_yRadius != null);
}
double _xRadius;
double get xRadius => _xRadius;
void set xRadius (double value) {
assert(value != null);
if (_xRadius == value)
return;
_xRadius = value;
markNeedsPaint();
}
double _yRadius;
double get yRadius => _yRadius;
void set yRadius (double value) {
assert(value != null);
if (_yRadius == value)
return;
_yRadius = value;
markNeedsPaint();
}
final Paint _paint = new Paint()..isAntiAlias = false;
void paint(PaintingContext context, Offset offset) {
if (child != null) {
Rect rect = offset & size;
context.canvas.saveLayer(rect, _paint); // TODO(abarth): layerize
sky.RRect rrect = new sky.RRect()..setRectXY(rect, xRadius, yRadius);
context.canvas.clipRRect(rrect);
context.paintChild(child, offset.toPoint());
context.canvas.restore();
}
}
}
class RenderClipOval extends RenderProxyBox {
RenderClipOval({ RenderBox child }) : super(child);
final Paint _paint = new Paint()..isAntiAlias = false;
Rect _cachedRect;
Path _cachedPath;
Path _getPath(Rect rect) {
if (rect != _cachedRect) {
_cachedRect = rect;
_cachedPath = new Path()..addOval(_cachedRect);
}
return _cachedPath;
}
void paint(PaintingContext context, Offset offset) {
if (child != null) {
Rect rect = offset & size;
context.canvas.saveLayer(rect, _paint); // TODO(abarth): layerize
context.canvas.clipPath(_getPath(rect));
context.paintChild(child, offset.toPoint());
context.canvas.restore();
}
}
}
class RenderDecoratedBox extends RenderProxyBox {
RenderDecoratedBox({
BoxDecoration decoration,
RenderBox child
}) : _painter = new BoxPainter(decoration), super(child);
final BoxPainter _painter;
BoxDecoration get decoration => _painter.decoration;
void set decoration (BoxDecoration value) {
assert(value != null);
if (value == _painter.decoration)
return;
_removeBackgroundImageListenerIfNeeded();
_painter.decoration = value;
_addBackgroundImageListenerIfNeeded();
markNeedsPaint();
}
bool get _needsBackgroundImageListener {
return attached &&
_painter.decoration != null &&
_painter.decoration.backgroundImage != null;
}
void _addBackgroundImageListenerIfNeeded() {
if (_needsBackgroundImageListener)
_painter.decoration.backgroundImage.addChangeListener(markNeedsPaint);
}
void _removeBackgroundImageListenerIfNeeded() {
if (_needsBackgroundImageListener)
_painter.decoration.backgroundImage.removeChangeListener(markNeedsPaint);
}
void attach() {
super.attach();
_addBackgroundImageListenerIfNeeded();
}
void detach() {
_removeBackgroundImageListenerIfNeeded();
super.detach();
}
void paint(PaintingContext context, Offset offset) {
assert(size.width != null);
assert(size.height != null);
_painter.paint(context.canvas, offset & size);
super.paint(context, offset);
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}decoration:\n${_painter.decoration.toString(prefix + " ")}\n';
}
class RenderTransform extends RenderProxyBox {
RenderTransform({
Matrix4 transform,
RenderBox child
}) : super(child) {
assert(transform != null);
this.transform = transform;
}
Matrix4 _transform;
void set transform(Matrix4 value) {
assert(value != null);
if (_transform == value)
return;
_transform = new Matrix4.copy(value);
markNeedsPaint();
}
void setIdentity() {
_transform.setIdentity();
markNeedsPaint();
}
void rotateX(double radians) {
_transform.rotateX(radians);
markNeedsPaint();
}
void rotateY(double radians) {
_transform.rotateY(radians);
markNeedsPaint();
}
void rotateZ(double radians) {
_transform.rotateZ(radians);
markNeedsPaint();
}
void translate(x, [double y = 0.0, double z = 0.0]) {
_transform.translate(x, y, z);
markNeedsPaint();
}
void scale(x, [double y, double z]) {
_transform.scale(x, y, z);
markNeedsPaint();
}
bool hitTest(HitTestResult result, { Point position }) {
Matrix4 inverse = new Matrix4.zero();
// TODO(abarth): Check the determinant for degeneracy.
inverse.copyInverse(_transform);
Vector3 position3 = new Vector3(position.x, position.y, 0.0);
Vector3 transformed3 = inverse.transform3(position3);
Point transformed = new Point(transformed3.x, transformed3.y);
return super.hitTest(result, position: transformed);
}
void paint(PaintingContext context, Offset offset) {
context.canvas.save();
context.canvas.translate(offset.dx, offset.dy);
context.canvas.concat(_transform.storage);
super.paint(context, Offset.zero);
context.canvas.restore();
}
void applyPaintTransform(Matrix4 transform) {
super.applyPaintTransform(transform);
transform.multiply(_transform);
}
String debugDescribeSettings(String prefix) {
List<String> result = _transform.toString().split('\n').map((s) => '$prefix $s\n').toList();
result.removeLast();
return '${super.debugDescribeSettings(prefix)}${prefix}transform matrix:\n${result.join()}';
}
}
typedef void SizeChangedCallback(Size newSize);
class RenderSizeObserver extends RenderProxyBox {
RenderSizeObserver({
this.callback,
RenderBox child
}) : super(child) {
assert(callback != null);
}
SizeChangedCallback callback;
void performLayout() {
Size oldSize = size;
super.performLayout();
if (oldSize != size)
callback(size);
}
}
typedef void CustomPaintCallback(PaintingCanvas canvas, Size size);
class RenderCustomPaint extends RenderProxyBox {
RenderCustomPaint({
CustomPaintCallback callback,
RenderBox child
}) : super(child) {
assert(callback != null);
_callback = callback;
}
CustomPaintCallback _callback;
void set callback (CustomPaintCallback value) {
assert(value != null || !attached);
if (_callback == value)
return;
_callback = value;
markNeedsPaint();
}
void attach() {
assert(_callback != null);
super.attach();
}
void paint(PaintingContext context, Offset offset) {
assert(_callback != null);
context.canvas.translate(offset.dx, offset.dy);
_callback(context.canvas, size);
// TODO(abarth): We should translate back before calling super because in
// the future, super.paint might switch our compositing layer.
super.paint(context, Offset.zero);
context.canvas.translate(-offset.dx, -offset.dy);
}
}
class RenderIgnorePointer extends RenderProxyBox {
RenderIgnorePointer({ RenderBox child }) : super(child);
bool hitTest(HitTestResult result, { Point position }) {
return false;
}
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:sky/painting/box_painter.dart';
import 'package:sky/painting/text_style.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/box.dart';
abstract class RenderShiftedBox extends RenderBox with RenderObjectWithChildMixin<RenderBox> {
// Abstract class for one-child-layout render boxes
RenderShiftedBox(RenderBox child) {
this.child = child;
}
double getMinIntrinsicWidth(BoxConstraints constraints) {
if (child != null)
return child.getMinIntrinsicWidth(constraints);
return super.getMinIntrinsicWidth(constraints);
}
double getMaxIntrinsicWidth(BoxConstraints constraints) {
if (child != null)
return child.getMaxIntrinsicWidth(constraints);
return super.getMaxIntrinsicWidth(constraints);
}
double getMinIntrinsicHeight(BoxConstraints constraints) {
if (child != null)
return child.getMinIntrinsicHeight(constraints);
return super.getMinIntrinsicHeight(constraints);
}
double getMaxIntrinsicHeight(BoxConstraints constraints) {
if (child != null)
return child.getMaxIntrinsicHeight(constraints);
return super.getMaxIntrinsicHeight(constraints);
}
double computeDistanceToActualBaseline(TextBaseline baseline) {
double result;
if (child != null) {
assert(!needsLayout);
result = child.getDistanceToActualBaseline(baseline);
assert(child.parentData is BoxParentData);
if (result != null)
result += child.parentData.position.y;
} else {
result = super.computeDistanceToActualBaseline(baseline);
}
return result;
}
void paint(PaintingContext context, Offset offset) {
if (child != null)
context.paintChild(child, child.parentData.position + offset);
}
void hitTestChildren(HitTestResult result, { Point position }) {
if (child != null) {
assert(child.parentData is BoxParentData);
child.hitTest(result, position: new Point(position.x - child.parentData.position.x,
position.y - child.parentData.position.y));
}
}
}
class RenderPadding extends RenderShiftedBox {
RenderPadding({ EdgeDims padding, RenderBox child }) : super(child) {
assert(padding != null);
this.padding = padding;
}
EdgeDims _padding;
EdgeDims get padding => _padding;
void set padding (EdgeDims value) {
assert(value != null);
if (_padding == value)
return;
_padding = value;
markNeedsLayout();
}
double getMinIntrinsicWidth(BoxConstraints constraints) {
double totalPadding = padding.left + padding.right;
if (child != null)
return child.getMinIntrinsicWidth(constraints.deflate(padding)) + totalPadding;
return constraints.constrainWidth(totalPadding);
}
double getMaxIntrinsicWidth(BoxConstraints constraints) {
double totalPadding = padding.left + padding.right;
if (child != null)
return child.getMaxIntrinsicWidth(constraints.deflate(padding)) + totalPadding;
return constraints.constrainWidth(totalPadding);
}
double getMinIntrinsicHeight(BoxConstraints constraints) {
double totalPadding = padding.top + padding.bottom;
if (child != null)
return child.getMinIntrinsicHeight(constraints.deflate(padding)) + totalPadding;
return constraints.constrainHeight(totalPadding);
}
double getMaxIntrinsicHeight(BoxConstraints constraints) {
double totalPadding = padding.top + padding.bottom;
if (child != null)
return child.getMaxIntrinsicHeight(constraints.deflate(padding)) + totalPadding;
return constraints.constrainHeight(totalPadding);
}
void performLayout() {
assert(padding != null);
if (child == null) {
size = constraints.constrain(new Size(
padding.left + padding.right,
padding.top + padding.bottom
));
return;
}
BoxConstraints innerConstraints = constraints.deflate(padding);
child.layout(innerConstraints, parentUsesSize: true);
assert(child.parentData is BoxParentData);
child.parentData.position = new Point(padding.left, padding.top);
size = constraints.constrain(new Size(
padding.left + child.size.width + padding.right,
padding.top + child.size.height + padding.bottom
));
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}padding: ${padding}\n';
}
class RenderPositionedBox extends RenderShiftedBox {
// This box aligns a child box within itself. It's only useful for
// children that don't always size to fit their parent. For example,
// to align a box at the bottom right, you would pass this box a
// tight constraint that is bigger than the child's natural size,
// with horizontal and vertical set to 1.0.
RenderPositionedBox({
RenderBox child,
double horizontal: 0.5,
double vertical: 0.5
}) : _horizontal = horizontal,
_vertical = vertical,
super(child) {
assert(horizontal != null);
assert(vertical != null);
}
double _horizontal;
double get horizontal => _horizontal;
void set horizontal (double value) {
assert(value != null);
if (_horizontal == value)
return;
_horizontal = value;
markNeedsLayout();
}
double _vertical;
double get vertical => _vertical;
void set vertical (double value) {
assert(value != null);
if (_vertical == value)
return;
_vertical = value;
markNeedsLayout();
}
void performLayout() {
if (child != null) {
child.layout(constraints.loosen(), parentUsesSize: true);
size = constraints.constrain(child.size);
assert(child.parentData is BoxParentData);
Offset delta = size - child.size;
child.parentData.position = (delta.scale(horizontal, vertical)).toPoint();
} else {
performResize();
}
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}horizontal: ${horizontal}\n${prefix}vertical: ${vertical}\n';
}
class RenderBaseline extends RenderShiftedBox {
RenderBaseline({
RenderBox child,
double baseline,
TextBaseline baselineType
}) : _baseline = baseline,
_baselineType = baselineType,
super(child) {
assert(baseline != null);
assert(baselineType != null);
}
double _baseline;
double get baseline => _baseline;
void set baseline (double value) {
assert(value != null);
if (_baseline == value)
return;
_baseline = value;
markNeedsLayout();
}
TextBaseline _baselineType;
TextBaseline get baselineType => _baselineType;
void set baselineType (TextBaseline value) {
assert(value != null);
if (_baselineType == value)
return;
_baselineType = value;
markNeedsLayout();
}
void performLayout() {
if (child != null) {
child.layout(constraints.loosen(), parentUsesSize: true);
size = constraints.constrain(child.size);
assert(child.parentData is BoxParentData);
double delta = baseline - child.getDistanceToBaseline(baselineType);
child.parentData.position = new Point(0.0, delta);
} else {
performResize();
}
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}baseline: ${baseline}\nbaselineType: ${baselineType}';
}
......@@ -4,10 +4,11 @@
import 'dart:sky' as sky;
import 'package:sky/base/scheduler.dart' as scheduler;
import 'package:sky/base/hit_test.dart';
import 'package:sky/base/scheduler.dart' as scheduler;
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/view.dart';
int _hammingWeight(int value) {
if (value == 0)
......
......@@ -9,6 +9,7 @@ import 'package:sky/animation/animation_performance.dart';
import 'package:sky/animation/curves.dart';
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/proxy_box.dart';
typedef void ValueChanged(bool value);
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:sky' as sky;
import 'package:sky/rendering/layer.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/box.dart';
import 'package:vector_math/vector_math.dart';
class ViewConstraints {
const ViewConstraints({
this.size: Size.zero,
this.orientation
});
final Size size;
final int orientation;
}
class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox> {
RenderView({
RenderBox child,
this.timeForRotation: const Duration(microseconds: 83333)
}) {
this.child = child;
}
Size _size = Size.zero;
Size get size => _size;
int _orientation; // 0..3
int get orientation => _orientation;
Duration timeForRotation;
ViewConstraints _rootConstraints;
ViewConstraints get rootConstraints => _rootConstraints;
void set rootConstraints(ViewConstraints value) {
if (_rootConstraints == value)
return;
_rootConstraints = value;
markNeedsLayout();
}
ContainerLayer _rootLayer;
// We never call layout() on this class, so this should never get
// checked. (This class is laid out using scheduleInitialLayout().)
bool debugDoesMeetConstraints() { assert(false); return false; }
void performResize() {
assert(false);
}
void performLayout() {
if (_rootConstraints.orientation != _orientation) {
if (_orientation != null && child != null)
child.rotate(oldAngle: _orientation, newAngle: _rootConstraints.orientation, time: timeForRotation);
_orientation = _rootConstraints.orientation;
}
_size = _rootConstraints.size;
assert(!_size.isInfinite);
if (child != null)
child.layout(new BoxConstraints.tight(_size));
}
void rotate({ int oldAngle, int newAngle, Duration time }) {
assert(false); // nobody tells the screen to rotate, the whole rotate() dance is started from our performResize()
}
bool hitTest(HitTestResult result, { Point position }) {
if (child != null) {
Rect childBounds = Point.origin & child.size;
if (childBounds.contains(position))
child.hitTest(result, position: position);
}
result.add(new HitTestEntry(this));
return true;
}
void paint(PaintingContext context, Offset offset) {
if (child != null)
context.paintChild(child, offset.toPoint());
}
void paintFrame() {
sky.tracing.begin('RenderView.paintFrame');
try {
final double devicePixelRatio = sky.view.devicePixelRatio;
Matrix4 transform = new Matrix4.diagonal3Values(devicePixelRatio, devicePixelRatio, 1.0);
_rootLayer = new TransformLayer(transform: transform);
PaintingContext context = new PaintingContext(Offset.zero, size);
_rootLayer.add(context.layer);
context.paintChild(child, Point.origin);
context.endRecording();
} finally {
sky.tracing.end('RenderView.paintFrame');
}
}
void compositeFrame() {
sky.tracing.begin('RenderView.compositeFrame');
try {
sky.PictureRecorder recorder = new sky.PictureRecorder();
sky.Canvas canvas = new sky.Canvas(recorder, Point.origin & (size * sky.view.devicePixelRatio));
_rootLayer.paint(canvas);
sky.view.picture = recorder.endRecording();
} finally {
sky.tracing.end('RenderView.compositeFrame');
}
}
Rect get paintBounds => Point.origin & size;
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:sky' as sky;
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/box.dart';
import 'package:vector_math/vector_math.dart';
enum ScrollDirection { horizontal, vertical, both }
class RenderViewport extends RenderBox with RenderObjectWithChildMixin<RenderBox> {
RenderViewport({
RenderBox child,
Offset scrollOffset,
ScrollDirection scrollDirection: ScrollDirection.vertical
}) : _scrollOffset = scrollOffset,
_scrollDirection = scrollDirection {
assert(_offsetIsSane(scrollOffset, scrollDirection));
this.child = child;
}
bool _offsetIsSane(Offset offset, ScrollDirection direction) {
switch (direction) {
case ScrollDirection.both:
return true;
case ScrollDirection.horizontal:
return offset.dy == 0.0;
case ScrollDirection.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();
}
ScrollDirection _scrollDirection;
ScrollDirection get scrollDirection => _scrollDirection;
void set scrollDirection(ScrollDirection value) {
if (value == _scrollDirection)
return;
assert(_offsetIsSane(scrollOffset, value));
_scrollDirection = value;
markNeedsLayout();
}
BoxConstraints _getInnerConstraints(BoxConstraints constraints) {
BoxConstraints innerConstraints;
switch (scrollDirection) {
case ScrollDirection.both:
innerConstraints = new BoxConstraints();
break;
case ScrollDirection.horizontal:
innerConstraints = constraints.heightConstraints();
break;
case ScrollDirection.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();
}
}
Offset get _scrollOffsetRoundedToIntegerDevicePixels {
double devicePixelRatio = sky.view.devicePixelRatio;
int dxInDevicePixels = (scrollOffset.dx * devicePixelRatio).round();
int dyInDevicePixels = (scrollOffset.dy * devicePixelRatio).round();
return new Offset(dxInDevicePixels / devicePixelRatio,
dyInDevicePixels / devicePixelRatio);
}
void paint(PaintingContext context, Offset offset) {
if (child != null) {
Offset roundedScrollOffset = _scrollOffsetRoundedToIntegerDevicePixels;
bool _needsClip = offset < Offset.zero ||
!(offset & size).contains(((offset - roundedScrollOffset) & child.size).bottomRight);
if (_needsClip) {
context.canvas.save();
context.canvas.clipRect(offset & size);
}
context.paintChild(child, (offset - roundedScrollOffset).toPoint());
if (_needsClip)
context.canvas.restore();
}
}
void applyPaintTransform(Matrix4 transform) {
super.applyPaintTransform(transform);
transform.translate(-scrollOffset.dx, -scrollOffset.dy);
}
void hitTestChildren(HitTestResult result, { Point position }) {
if (child != null) {
assert(child.parentData is BoxParentData);
Point transformed = position + _scrollOffsetRoundedToIntegerDevicePixels;
child.hitTest(result, position: transformed);
}
}
}
......@@ -14,18 +14,24 @@ import 'package:sky/painting/paragraph_painter.dart';
import 'package:sky/rendering/block.dart';
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/flex.dart';
import 'package:sky/rendering/image.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/paragraph.dart';
import 'package:sky/rendering/proxy_box.dart';
import 'package:sky/rendering/shifted_box.dart';
import 'package:sky/rendering/stack.dart';
import 'package:sky/rendering/viewport.dart';
import 'package:sky/widgets/default_text_style.dart';
import 'package:sky/widgets/framework.dart';
export 'package:sky/base/hit_test.dart' show EventDisposition, combineEventDispositions;
export 'package:sky/rendering/block.dart' show BlockDirection;
export 'package:sky/rendering/box.dart' show BackgroundImage, BoxConstraints, BoxDecoration, Border, BorderSide, EdgeDims, ScrollDirection;
export 'package:sky/rendering/box.dart' show BoxConstraints;
export 'package:sky/rendering/flex.dart' show FlexDirection, FlexJustifyContent, FlexAlignItems;
export 'package:sky/rendering/object.dart' show Point, Offset, Size, Rect, Color, Paint, Path;
export 'package:sky/rendering/proxy_box.dart' show BackgroundImage, BoxDecoration, BoxShadow, Border, BorderSide, EdgeDims;
export 'package:sky/rendering/toggleable.dart' show ValueChanged;
export 'package:sky/rendering/viewport.dart' show ScrollDirection;
export 'package:sky/widgets/framework.dart' show Key, GlobalKey, Widget, Component, StatefulComponent, App, runApp, Listener, ParentDataNode;
// PAINTING NODES
......
......@@ -12,6 +12,7 @@ import 'package:sky/mojo/activity.dart' as activity;
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/sky_binding.dart';
import 'package:sky/rendering/view.dart';
export 'package:sky/base/hit_test.dart' show EventDisposition, combineEventDispositions;
export 'package:sky/rendering/box.dart' show BoxConstraints, BoxDecoration, Border, BorderSide, EdgeDims;
......
......@@ -4,7 +4,6 @@
import 'dart:sky' as sky;
import 'package:sky/rendering/box.dart';
import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/icon.dart';
import 'package:sky/widgets/framework.dart';
......
......@@ -10,6 +10,7 @@ import 'package:sky/animation/animation_performance.dart';
import 'package:sky/animation/curves.dart';
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/proxy_box.dart';
import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/framework.dart';
......
......@@ -10,6 +10,7 @@ import 'package:sky/animation/animated_simulation.dart';
import 'package:sky/animation/animation_performance.dart';
import 'package:sky/animation/scroll_behavior.dart';
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/viewport.dart';
import 'package:sky/theme/view_configuration.dart' as config;
import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/block_viewport.dart';
......
......@@ -13,6 +13,7 @@ import 'package:sky/animation/scroll_behavior.dart';
import 'package:sky/painting/text_style.dart';
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/rendering/viewport.dart';
import 'package:sky/theme/colors.dart' as colors;
import 'package:sky/theme/typography.dart' as typography;
import 'package:sky/widgets/basic.dart';
......
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