Commit dfbd8c6a authored by Adam Barth's avatar Adam Barth

Add debugDumpLayerTree to dump the layer tree

To help debugging issues with the layer tree.
parent fd1dd7fa
......@@ -107,7 +107,7 @@ class StockHomeState extends State<StockHome> {
),
new DrawerItem(
icon: 'device/dvr',
onPressed: () { debugDumpApp(); debugDumpRenderTree(); },
onPressed: () { debugDumpApp(); debugDumpRenderTree(); debugDumpLayerTree(); },
child: new Text('Dump App to Console')
),
new DrawerDivider(),
......
......@@ -292,3 +292,8 @@ class FlutterBinding extends HitTestTarget {
void debugDumpRenderTree() {
debugPrint(FlutterBinding.instance.renderView.toStringDeep());
}
/// Prints a textual representation of the entire layer tree
void debugDumpLayerTree() {
debugPrint(FlutterBinding.instance.renderView.layer.toStringDeep());
}
......@@ -6,6 +6,8 @@ import 'dart:ui' as ui;
import 'dart:async';
import 'dart:collection';
import 'package:vector_math/vector_math_64.dart';
/// Causes each RenderBox to paint a box around its bounds.
bool debugPaintSizeEnabled = false;
......@@ -36,6 +38,12 @@ int debugPaintPointersColorValue = 0x00BBBB;
/// The color to use when painting RenderError boxes in checked mode.
ui.Color debugErrorBoxColor = const ui.Color(0xFFFF0000);
List<String> debugDescribeTransform(Matrix4 transform) {
List<String> matrix = transform.toString().split('\n').map((String s) => ' $s').toList();
matrix.removeLast();
return matrix;
}
/// Prints a message to the console, which you can access using the "flutter"
/// tool's "logs" command ("flutter logs").
///
......
......@@ -7,6 +7,7 @@ import 'dart:ui' as ui;
import 'package:vector_math/vector_math_64.dart';
import 'basic_types.dart';
import 'debug.dart';
export 'basic_types.dart';
......@@ -66,6 +67,31 @@ abstract class Layer {
/// The layerOffset is the accumulated offset of this layer's parent from the
/// origin of the builder's coordinate system.
void addToScene(ui.SceneBuilder builder, Offset layerOffset);
String toString() => '$runtimeType';
dynamic debugOwner;
String toStringDeep([String prefixLineOne = '', String prefixOtherLines = '']) {
String result = '$prefixLineOne$this\n';
final String childrenDescription = debugDescribeChildren(prefixOtherLines);
final String settingsPrefix = childrenDescription != '' ? '$prefixOtherLines \u2502 ' : '$prefixOtherLines ';
List<String> settings = <String>[];
debugDescribeSettings(settings);
result += settings.map((String setting) => "$settingsPrefix$setting\n").join();
if (childrenDescription == '')
result += '$prefixOtherLines\n';
result += childrenDescription;
return result;
}
void debugDescribeSettings(List<String> settings) {
if (debugOwner != null)
settings.add('owner: $debugOwner');
settings.add('offset: $offset');
}
String debugDescribeChildren(String prefix) => '';
}
/// A composited layer containing a [Picture]
......@@ -88,6 +114,10 @@ class PictureLayer extends Layer {
builder.addPicture(offset + layerOffset, picture, paintBounds);
}
void debugDescribeSettings(List<String> settings) {
super.debugDescribeSettings(settings);
settings.add('paintBounds: $paintBounds');
}
}
/// A layer that indicates to the compositor that it should display
......@@ -113,7 +143,6 @@ class StatisticsLayer extends Layer {
builder.addStatistics(optionsMask, paintBounds.shift(layerOffset));
builder.setRasterizerTracingThreshold(rasterizerThreshold);
}
}
......@@ -210,6 +239,23 @@ class ContainerLayer extends Layer {
}
}
String debugDescribeChildren(String prefix) {
String result = '$prefix \u2502\n';
if (_firstChild != null) {
Layer child = _firstChild;
int count = 1;
while (child != _lastChild) {
result += '${child.toStringDeep("$prefix \u251C\u2500child $count: ", "$prefix \u2502")}';
count += 1;
child = child._nextSibling;
}
if (child != null) {
assert(child == _lastChild);
result += '${child.toStringDeep("$prefix \u2514\u2500child $count: ", "$prefix ")}';
}
}
return result;
}
}
/// A composite layer that clips its children using a rectangle
......@@ -227,6 +273,10 @@ class ClipRectLayer extends ContainerLayer {
builder.pop();
}
void debugDescribeSettings(List<String> settings) {
super.debugDescribeSettings(settings);
settings.add('clipRect: $clipRect');
}
}
/// A composite layer that clips its children using a rounded rectangle
......@@ -248,6 +298,11 @@ class ClipRRectLayer extends ContainerLayer {
builder.pop();
}
void debugDescribeSettings(List<String> settings) {
super.debugDescribeSettings(settings);
settings.add('bounds: $bounds');
settings.add('clipRRect: $clipRRect');
}
}
/// A composite layer that clips its children using a path
......@@ -269,6 +324,11 @@ class ClipPathLayer extends ContainerLayer {
builder.pop();
}
void debugDescribeSettings(List<String> settings) {
super.debugDescribeSettings(settings);
settings.add('bounds: $bounds');
settings.add('clipPath: $clipPath');
}
}
/// A composited layer that applies a transformation matrix to its children
......@@ -285,6 +345,12 @@ class TransformLayer extends ContainerLayer {
addChildrenToScene(builder, Offset.zero);
builder.pop();
}
void debugDescribeSettings(List<String> settings) {
super.debugDescribeSettings(settings);
settings.add('transform:');
settings.addAll(debugDescribeTransform(transform));
}
}
/// A composited layer that makes its children partially transparent
......@@ -306,4 +372,10 @@ class OpacityLayer extends ContainerLayer {
addChildrenToScene(builder, offset + layerOffset);
builder.pop();
}
void debugDescribeSettings(List<String> settings) {
super.debugDescribeSettings(settings);
settings.add('bounds: $bounds');
settings.add('alpha: $alpha');
}
}
......@@ -74,6 +74,10 @@ class PaintingContext {
assert(child.needsPaint);
child._layer ??= new ContainerLayer();
child._layer.removeAllChildren();
assert(() {
child._layer.debugOwner = child.debugOwner ?? child.runtimeType;
return true;
});
PaintingContext childContext = new PaintingContext._(child._layer, child.paintBounds);
child._paintWithContext(childContext, Offset.zero);
childContext._stopRecordingIfNeeded();
......@@ -104,6 +108,10 @@ class PaintingContext {
} else {
assert(child._layer != null);
child._layer.detach();
assert(() {
child._layer.debugOwner = child.debugOwner ?? child.runtimeType;
return true;
});
}
_appendLayer(child._layer, offset);
}
......@@ -435,7 +443,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 debugOwner = '';
dynamic debugOwner;
void _debugReportException(String method, dynamic exception, StackTrace stack) {
debugPrint('-- EXCEPTION --');
debugPrint('The following exception was raised during $method():');
......@@ -443,7 +451,7 @@ 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 (debugOwner != '')
if (debugOwner != null)
debugPrint('That RenderObject had the following owner:\n$debugOwner');
if (debugRenderingExceptionHandler != null)
debugRenderingExceptionHandler(this, method, exception, stack);
......@@ -1094,10 +1102,10 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
/// per string. Subclasses should override this to have their information
/// included in toStringDeep().
void debugDescribeSettings(List<String> settings) {
if (debugOwner != null)
settings.add('owner: $debugOwner');
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
......
......@@ -10,6 +10,7 @@ import 'package:flutter/gestures.dart';
import 'package:vector_math/vector_math_64.dart';
import 'box.dart';
import 'debug.dart';
import 'object.dart';
export 'package:flutter/src/painting/box_painter.dart';
......@@ -875,10 +876,8 @@ class RenderTransform extends RenderProxyBox {
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.addAll(debugDescribeTransform(_transform));
settings.add('origin: $origin');
settings.add('alignment: $alignment');
}
......
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