Add debugDumpLayerTree to dump the layer tree
To help debugging issues with the layer tree.
This commit is contained in:
@@ -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');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user