Commit 6d389722 authored by Hixie's avatar Hixie

Get more debug info into the rendering layer

- change how we expose settings at the RenderObject layer so that it's
  easier to maintain.
- expose the Widget owner chain in the RenderObject layer debug output
- add debug info to RenderOpacity, RenderIgnorePointer, RenderListener
- make the output for text nodes prettier
parent 60fa30a6
......@@ -118,7 +118,10 @@ abstract class RenderBlockBase extends RenderBox with ContainerRenderObjectMixin
assert(!size.isInfinite);
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}direction: $direction\n';
void debugDescribeSettings(List<String> settings) {
super.debugDescribeSettings(settings);
settings.add('direction: $direction');
}
}
/// A block layout with a concrete set of children
......@@ -427,5 +430,8 @@ class RenderBlockViewport extends RenderBlockBase {
defaultHitTestChildren(result, position: position + new Offset(-startOffset, 0.0));
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}startOffset: $startOffset\n';
void debugDescribeSettings(List<String> settings) {
super.debugDescribeSettings(settings);
settings.add('startOffset: $startOffset');
}
}
......@@ -683,7 +683,10 @@ abstract class RenderBox extends RenderObject {
}
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}size: ${ hasSize ? size : "MISSING" }\n';
void debugDescribeSettings(List<String> settings) {
super.debugDescribeSettings(settings);
settings.add('size: ${ hasSize ? size : "MISSING" }');
}
}
/// A mixin that provides useful default behaviors for boxes with children
......
......@@ -597,6 +597,12 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
return header;
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}direction: $_direction\n${prefix}justifyContent: $_justifyContent\n${prefix}alignItems: $_alignItems\n${prefix}textBaseline: $_textBaseline\n';
void debugDescribeSettings(List<String> settings) {
super.debugDescribeSettings(settings);
settings.add('direction: $_direction');
settings.add('justifyContent: $_justifyContent');
settings.add('alignItems: $_alignItems');
settings.add('textBaseline: $_textBaseline');
}
}
......@@ -197,5 +197,9 @@ class RenderImage extends RenderBox {
);
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}width: $width\n${prefix}height: $height\n';
void debugDescribeSettings(List<String> settings) {
super.debugDescribeSettings(settings);
settings.add('width: $width');
settings.add('height: $height');
}
}
......@@ -475,7 +475,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
/// Override in subclasses with children and call the visitor for each child
void visitChildren(RenderObjectVisitor visitor) { }
dynamic debugExceptionContext = '';
dynamic debugOwner = '';
void _debugReportException(String method, dynamic exception, StackTrace stack) {
debugPrint('-- EXCEPTION --');
debugPrint('The following exception was raised during $method():');
......@@ -483,8 +483,8 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
debugPrint('Stack trace:');
debugPrint('$stack');
debugPrint('The following RenderObject was being processed when the exception was fired:\n${this}');
if (debugExceptionContext != '')
debugPrint('That RenderObject had the following exception context:\n$debugExceptionContext');
if (debugOwner != '')
debugPrint('That RenderObject had the following owner:\n$debugOwner');
if (debugRenderingExceptionHandler != null)
debugRenderingExceptionHandler(this, method, exception, stack);
}
......@@ -1134,20 +1134,25 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
String result = '$prefixLineOne$this\n';
final String childrenDescription = debugDescribeChildren(prefixOtherLines);
final String settingsPrefix = childrenDescription != '' ? '$prefixOtherLines \u2502 ' : '$prefixOtherLines ';
result += debugDescribeSettings(settingsPrefix);
if (childrenDescription != '')
result += '$prefixOtherLines \u2502\n';
else
List<String> settings = <String>[];
debugDescribeSettings(settings);
result += settings.map((String setting) => "$settingsPrefix$setting\n").join();
if (childrenDescription == '')
result += '$prefixOtherLines\n';
result += childrenDescription;
_debugActiveLayout = debugPreviousActiveLayout;
return result;
}
/// Returns a string describing the current node's fields, one field per line,
/// with each line prefixed by the prefix argument. Subclasses should override
/// this to have their information included in toStringDeep().
String debugDescribeSettings(String prefix) => '${prefix}parentData: $parentData\n${prefix}constraints: $constraints\n';
/// Returns a list of strings describing the current node's fields, one field
/// per string. Subclasses should override this to have their information
/// included in toStringDeep().
void debugDescribeSettings(List<String> settings) {
settings.add('parentData: $parentData');
settings.add('constraints: $constraints');
if (debugOwner != '')
settings.add('owner: $debugOwner');
}
/// Returns a string describing the current node's descendants. Each line of
/// the subtree in the output should be indented by the prefix argument.
......@@ -1194,7 +1199,7 @@ abstract class RenderObjectWithChildMixin<ChildType extends RenderObject> implem
}
String debugDescribeChildren(String prefix) {
if (child != null)
return '${child.toStringDeep("$prefix \u2514\u2500child: ", "$prefix ")}';
return '$prefix \u2502\n${child.toStringDeep('$prefix \u2514\u2500child: ', '$prefix ')}';
return '';
}
}
......@@ -1437,7 +1442,7 @@ abstract class ContainerRenderObjectMixin<ChildType extends RenderObject, Parent
}
String debugDescribeChildren(String prefix) {
String result = '';
String result = '$prefix \u2502\n';
if (_firstChild != null) {
ChildType child = _firstChild;
int count = 1;
......
......@@ -137,12 +137,12 @@ class RenderOverflowBox extends RenderBox with RenderObjectWithChildMixin<Render
context.paintChild(child, offset.toPoint());
}
String debugDescribeSettings(String prefix) {
return '${super.debugDescribeSettings(prefix)}' +
'${prefix}minWidth: ${minWidth ?? "use parent minWidth constraint"}\n' +
'${prefix}maxWidth: ${maxWidth ?? "use parent maxWidth constraint"}\n' +
'${prefix}minHeight: ${minHeight ?? "use parent minHeight constraint"}\n' +
'${prefix}maxHeight: ${maxHeight ?? "use parent maxHeight constraint"}\n';
void debugDescribeSettings(List<String> settings) {
super.debugDescribeSettings(settings);
settings.add('minWidth: ${minWidth ?? "use parent minWidth constraint"}');
settings.add('maxWidth: ${maxWidth ?? "use parent maxWidth constraint"}');
settings.add('minHeight: ${minHeight ?? "use parent minHeight constraint"}');
settings.add('maxHeight: ${maxHeight ?? "use parent maxHeight constraint"}');
}
}
......
......@@ -115,9 +115,10 @@ class RenderParagraph extends RenderBox {
// we should probably expose a way to do precise (inter-glpyh) hit testing
String debugDescribeSettings(String prefix) {
String result = '${super.debugDescribeSettings(prefix)}';
result += '${prefix}text:\n${text.toString("$prefix ")}\n';
return result;
String debugDescribeChildren(String prefix) {
return '$prefix \u2558\u2550\u2566\u2550\u2550 text \u2550\u2550\u2550\n'
'${text.toString("$prefix \u2551 ")}\n'
'$prefix \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n'
'$prefix\n';
}
}
......@@ -144,7 +144,10 @@ class RenderConstrainedBox extends RenderProxyBox {
}
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}additionalConstraints: $additionalConstraints\n';
void debugDescribeSettings(List<String> settings) {
super.debugDescribeSettings(settings);
settings.add('additionalConstraints: $additionalConstraints');
}
}
/// A render object that, for both width and height, imposes a tight constraint
......@@ -232,10 +235,10 @@ class RenderFractionallySizedBox extends RenderProxyBox {
}
}
String debugDescribeSettings(String prefix) {
return '${super.debugDescribeSettings(prefix)}' +
'${prefix}widthFactor: ${_widthFactor ?? "pass-through"}\n' +
'${prefix}heightFactor: ${_heightFactor ?? "pass-through"}\n';
void debugDescribeSettings(List<String> settings) {
super.debugDescribeSettings(settings);
settings.add('widthFactor: ${_widthFactor ?? "pass-through"}');
settings.add('heightFactor: ${_heightFactor ?? "pass-through"}');
}
}
......@@ -302,7 +305,10 @@ class RenderAspectRatio extends RenderProxyBox {
child.layout(new BoxConstraints.tight(size));
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}aspectRatio: $aspectRatio\n';
void debugDescribeSettings(List<String> settings) {
super.debugDescribeSettings(settings);
settings.add('aspectRatio: $aspectRatio');
}
}
/// Sizes its child to the child's intrinsic width
......@@ -397,8 +403,11 @@ class RenderIntrinsicWidth extends RenderProxyBox {
}
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}stepWidth: $stepWidth\n${prefix}stepHeight: $stepHeight\n';
void debugDescribeSettings(List<String> settings) {
super.debugDescribeSettings(settings);
settings.add('stepWidth: $stepWidth');
settings.add('stepHeight: $stepHeight');
}
}
/// Sizes its child to the child's intrinsic height
......@@ -500,6 +509,11 @@ class RenderOpacity extends RenderProxyBox {
context.paintChildWithOpacity(child, offset.toPoint(), null, a);
}
}
void debugDescribeSettings(List<String> settings) {
super.debugDescribeSettings(settings);
settings.add('opacity: ${opacity.toStringAsFixed(1)}');
}
}
class RenderShaderMask extends RenderProxyBox {
......@@ -702,7 +716,11 @@ class RenderDecoratedBox extends RenderProxyBox {
_painter.paint(context.canvas, offset & size);
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}decoration:\n${_painter.decoration.toString(prefix + " ")}\n';
void debugDescribeSettings(List<String> settings) {
super.debugDescribeSettings(settings);
settings.add('decoration:');
settings.addAll(_painter.decoration.toString(" ").split('\n'));
}
}
/// Applies a transformation before painting its child
......@@ -833,10 +851,14 @@ class RenderTransform extends RenderProxyBox {
transform.multiply(_effectiveTransform);
}
String debugDescribeSettings(String prefix) {
List<String> result = _transform.toString().split('\n').map((String s) => '$prefix $s\n').toList();
result.removeLast();
return '${super.debugDescribeSettings(prefix)}${prefix}transform matrix:\n${result.join()}\n${prefix}origin: $origin\n${prefix}alignment: $alignment\n';
void debugDescribeSettings(List<String> settings) {
super.debugDescribeSettings(settings);
List<String> matrix = _transform.toString().split('\n').map((String s) => ' $s').toList();
matrix.removeLast();
settings.add('transform matrix:');
settings.addAll(matrix);
settings.add('origin: $origin');
settings.add('alignment: $alignment');
}
}
......@@ -952,6 +974,22 @@ class RenderPointerListener extends RenderProxyBox {
if (onPointerCancel != null && event.type == 'pointercancel')
return onPointerCancel(event);
}
void debugDescribeSettings(List<String> settings) {
super.debugDescribeSettings(settings);
List<String> listeners = <String>[];
if (onPointerDown != null)
listeners.add('down');
if (onPointerMove != null)
listeners.add('move');
if (onPointerUp != null)
listeners.add('up');
if (onPointerCancel != null)
listeners.add('cancel');
if (listeners.isEmpty)
listeners.add('<none>');
settings.add('listeners: ${listeners.join(", ")}');
}
}
/// Is invisible during hit testing.
......@@ -968,6 +1006,11 @@ class RenderIgnorePointer extends RenderProxyBox {
bool hitTest(HitTestResult result, { Point position }) {
return ignoring ? false : super.hitTest(result, position: position);
}
void debugDescribeSettings(List<String> settings) {
super.debugDescribeSettings(settings);
settings.add('ignoring: $ignoring');
}
}
/// Holds opaque meta data in the render tree
......
......@@ -135,7 +135,10 @@ class RenderPadding extends RenderShiftedBox {
));
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}padding: $padding\n';
void debugDescribeSettings(List<String> settings) {
super.debugDescribeSettings(settings);
settings.add('padding: $padding');
}
}
enum ShrinkWrap {
......@@ -202,7 +205,10 @@ class RenderPositionedBox extends RenderShiftedBox {
}
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}alignment: $alignment\n';
void debugDescribeSettings(List<String> settings) {
super.debugDescribeSettings(settings);
settings.add('alignment: $alignment');
}
}
/// A delegate for computing the layout of a render object with a single child.
......@@ -315,5 +321,9 @@ class RenderBaseline extends RenderShiftedBox {
}
}
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}baseline: $baseline\nbaselineType: $baselineType';
void debugDescribeSettings(List<String> settings) {
super.debugDescribeSettings(settings);
settings.add('baseline: $baseline');
settings.add('baselineType: $baselineType');
}
}
......@@ -130,6 +130,10 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
Rect get paintBounds => Point.origin & size;
String debugDescribeSettings(String prefix) => '${prefix}window size: ${ui.window.size} (in device pixels)\n${prefix}device pixel ratio: ${ui.window.devicePixelRatio} (device pixels per logical pixel)\n${prefix}root constraints: $rootConstraints (in logical pixels)\n';
// call to ${super.debugDescribeSettings(prefix)} is omitted because the root superclasses don't include any interesting information for this class
void debugDescribeSettings(List<String> settings) {
// call to ${super.debugDescribeSettings(prefix)} is omitted because the root superclasses don't include any interesting information for this class
settings.add('window size: ${ui.window.size} (in device pixels)');
settings.add('device pixel ratio: ${ui.window.devicePixelRatio} (device pixels per logical pixel)');
settings.add('root constraints: $rootConstraints (in logical pixels)');
}
}
......@@ -829,6 +829,10 @@ abstract class Element<T extends Widget> implements BuildContext {
assert(false);
}
String toStringShort() {
return widget != null ? '${widget.toStringShort()}' : '[$runtimeType]';
}
String toString() {
final List<String> data = <String>[];
debugFillDescription(data);
......@@ -1240,7 +1244,9 @@ class InheritedElement extends ProxyElement<InheritedWidget> {
/// Base class for instantiations of RenderObjectWidget subclasses
abstract class RenderObjectElement<T extends RenderObjectWidget> extends BuildableElement<T> {
RenderObjectElement(T widget)
: _renderObject = widget.createRenderObject(), super(widget);
: _renderObject = widget.createRenderObject(), super(widget) {
assert(() { debugUpdateRenderObjectOwner(); return true; });
}
/// The underlying [RenderObject] for this element
RenderObject get renderObject => _renderObject;
......@@ -1279,10 +1285,23 @@ abstract class RenderObjectElement<T extends RenderObjectWidget> extends Buildab
T oldWidget = widget;
super.update(newWidget);
assert(widget == newWidget);
assert(() { debugUpdateRenderObjectOwner(); return true; });
widget.updateRenderObject(renderObject, oldWidget);
_dirty = false;
}
void debugUpdateRenderObjectOwner() {
List<String> chain = <String>[];
Element node = this;
while (chain.length < 4 && node != null) {
chain.add(node.toStringShort());
node = node._parent;
}
if (node != null)
chain.add('\u22EF');
_renderObject.debugOwner = chain.join(' \u2190 ');
}
void performRebuild() {
reinvokeBuilders();
_dirty = false;
......
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