Commit 0229711b authored by Jacob Richman's avatar Jacob Richman Committed by GitHub

Refactor SemanticsData and SemanticsNode to use Diagnosticable. (#11957)

* Refactor SemanticsData and SemanticsNode to use Diagnosticable.

* Switch toStringDeep to take named parameters.
parent ff90ba5b
...@@ -679,7 +679,7 @@ abstract class DiagnosticsNode { ...@@ -679,7 +679,7 @@ abstract class DiagnosticsNode {
String toString({ TextTreeConfiguration parentConfiguration }) { String toString({ TextTreeConfiguration parentConfiguration }) {
assert(style != null); assert(style != null);
if (style == DiagnosticsTreeStyle.singleLine) if (style == DiagnosticsTreeStyle.singleLine)
return toStringDeep('', '', parentConfiguration); return toStringDeep(parentConfiguration: parentConfiguration);
final String description = toDescription(parentConfiguration: parentConfiguration); final String description = toDescription(parentConfiguration: parentConfiguration);
...@@ -736,7 +736,11 @@ abstract class DiagnosticsNode { ...@@ -736,7 +736,11 @@ abstract class DiagnosticsNode {
/// * [toString], for a brief description of the [value] but not its children. /// * [toString], for a brief description of the [value] but not its children.
/// * [toStringShallow], for a detailed description of the [value] but not its /// * [toStringShallow], for a detailed description of the [value] but not its
/// children. /// children.
String toStringDeep([String prefixLineOne = '', String prefixOtherLines, TextTreeConfiguration parentConfiguration]) { String toStringDeep({
String prefixLineOne: '',
String prefixOtherLines,
TextTreeConfiguration parentConfiguration,
}) {
prefixOtherLines ??= prefixLineOne; prefixOtherLines ??= prefixLineOne;
final List<DiagnosticsNode> children = getChildren(); final List<DiagnosticsNode> children = getChildren();
...@@ -796,9 +800,9 @@ abstract class DiagnosticsNode { ...@@ -796,9 +800,9 @@ abstract class DiagnosticsNode {
if (property.style != DiagnosticsTreeStyle.singleLine) { if (property.style != DiagnosticsTreeStyle.singleLine) {
final TextTreeConfiguration propertyStyle = property.textTreeConfiguration; final TextTreeConfiguration propertyStyle = property.textTreeConfiguration;
builder.writeRaw(property.toStringDeep( builder.writeRaw(property.toStringDeep(
'${builder.prefixOtherLines}${propertyStyle.prefixLineOne}', prefixLineOne: '${builder.prefixOtherLines}${propertyStyle.prefixLineOne}',
'${builder.prefixOtherLines}${propertyStyle.linkCharacter}${propertyStyle.prefixOtherLines}', prefixOtherLines: '${builder.prefixOtherLines}${propertyStyle.linkCharacter}${propertyStyle.prefixOtherLines}',
config, parentConfiguration: config,
)); ));
continue; continue;
} }
...@@ -850,9 +854,9 @@ abstract class DiagnosticsNode { ...@@ -850,9 +854,9 @@ abstract class DiagnosticsNode {
if (i == children.length - 1) { if (i == children.length - 1) {
final String lastChildPrefixLineOne = '$prefixChildren${childConfig.prefixLastChildLineOne}'; final String lastChildPrefixLineOne = '$prefixChildren${childConfig.prefixLastChildLineOne}';
builder.writeRawLine(child.toStringDeep( builder.writeRawLine(child.toStringDeep(
lastChildPrefixLineOne, prefixLineOne: lastChildPrefixLineOne,
'$prefixChildren${childConfig.childLinkSpace}${childConfig.prefixOtherLines}', prefixOtherLines: '$prefixChildren${childConfig.childLinkSpace}${childConfig.prefixOtherLines}',
config, parentConfiguration: config,
)); ));
if (childConfig.footer.isNotEmpty) if (childConfig.footer.isNotEmpty)
builder.writeRaw('$prefixChildren${childConfig.childLinkSpace}${childConfig.footer}'); builder.writeRaw('$prefixChildren${childConfig.childLinkSpace}${childConfig.footer}');
...@@ -860,7 +864,7 @@ abstract class DiagnosticsNode { ...@@ -860,7 +864,7 @@ abstract class DiagnosticsNode {
final TextTreeConfiguration nextChildStyle = _childTextConfiguration(children[i + 1], config); final TextTreeConfiguration nextChildStyle = _childTextConfiguration(children[i + 1], config);
final String childPrefixLineOne = '$prefixChildren${childConfig.prefixLineOne}'; final String childPrefixLineOne = '$prefixChildren${childConfig.prefixLineOne}';
final String childPrefixOtherLines ='$prefixChildren${nextChildStyle.linkCharacter}${childConfig.prefixOtherLines}'; final String childPrefixOtherLines ='$prefixChildren${nextChildStyle.linkCharacter}${childConfig.prefixOtherLines}';
builder.writeRawLine(child.toStringDeep(childPrefixLineOne, childPrefixOtherLines)); builder.writeRawLine(child.toStringDeep(prefixLineOne: childPrefixLineOne, prefixOtherLines: childPrefixOtherLines));
if (childConfig.footer.isNotEmpty) if (childConfig.footer.isNotEmpty)
builder.writeRaw('$prefixChildren${nextChildStyle.linkCharacter}${childConfig.footer}'); builder.writeRaw('$prefixChildren${nextChildStyle.linkCharacter}${childConfig.footer}');
} }
...@@ -1249,16 +1253,18 @@ class IterableProperty<T> extends DiagnosticsProperty<Iterable<T>> { ...@@ -1249,16 +1253,18 @@ class IterableProperty<T> extends DiagnosticsProperty<Iterable<T>> {
/// value with 0 elements would, confusingly, be displayed as the empty /// value with 0 elements would, confusingly, be displayed as the empty
/// string. It defaults to the string `[]`. /// string. It defaults to the string `[]`.
/// ///
/// The [style] and [hidden] arguments must also not be null. /// The [style], [hidden], and [showName] arguments must also not be null.
IterableProperty(String name, Iterable<T> value, { IterableProperty(String name, Iterable<T> value, {
Object defaultValue: kNoDefaultValue, Object defaultValue: kNoDefaultValue,
String ifNull, String ifNull,
String ifEmpty: '[]', String ifEmpty: '[]',
DiagnosticsTreeStyle style: DiagnosticsTreeStyle.singleLine, DiagnosticsTreeStyle style: DiagnosticsTreeStyle.singleLine,
bool hidden: false, bool hidden: false,
bool showName: true,
}) : assert(ifEmpty != null), }) : assert(ifEmpty != null),
assert(style != null), assert(style != null),
assert(hidden != null), assert(hidden != null),
assert(showName != null),
super( super(
name, name,
value, value,
...@@ -1267,6 +1273,7 @@ class IterableProperty<T> extends DiagnosticsProperty<Iterable<T>> { ...@@ -1267,6 +1273,7 @@ class IterableProperty<T> extends DiagnosticsProperty<Iterable<T>> {
ifEmpty: ifEmpty, ifEmpty: ifEmpty,
style: style, style: style,
hidden: hidden, hidden: hidden,
showName: showName,
); );
@override @override
...@@ -1634,14 +1641,19 @@ class DiagnosticsProperty<T> extends DiagnosticsNode { ...@@ -1634,14 +1641,19 @@ class DiagnosticsProperty<T> extends DiagnosticsNode {
List<DiagnosticsNode> getChildren() => <DiagnosticsNode>[]; List<DiagnosticsNode> getChildren() => <DiagnosticsNode>[];
} }
/// [DiagnosticsNode] for an instance of [Diagnosticable]. /// [DiagnosticsNode] that lazily calls the associated [Diagnosticable] [value]
class _DiagnosticableNode<T extends Diagnosticable> extends DiagnosticsNode { /// to implement [getChildren] and [getProperties].
_DiagnosticableNode({ class DiagnosticableNode<T extends Diagnosticable> extends DiagnosticsNode {
/// Create a diagnostics describing a [Diagnosticable] value.
///
/// The [value] argument must not be null.
DiagnosticableNode({
String name, String name,
@required this.value, @required this.value,
@required DiagnosticsTreeStyle style, @required DiagnosticsTreeStyle style,
String emptyBodyDescription, String emptyBodyDescription,
}) : super( }) : assert(value != null),
super(
name: name, name: name,
style: style, style: style,
); );
...@@ -1683,7 +1695,7 @@ class _DiagnosticableNode<T extends Diagnosticable> extends DiagnosticsNode { ...@@ -1683,7 +1695,7 @@ class _DiagnosticableNode<T extends Diagnosticable> extends DiagnosticsNode {
} }
/// [DiagnosticsNode] for an instance of [DiagnosticableTree]. /// [DiagnosticsNode] for an instance of [DiagnosticableTree].
class _DiagnosticableTreeNode extends _DiagnosticableNode<DiagnosticableTree> { class _DiagnosticableTreeNode extends DiagnosticableNode<DiagnosticableTree> {
_DiagnosticableTreeNode({ _DiagnosticableTreeNode({
String name, String name,
@required DiagnosticableTree value, @required DiagnosticableTree value,
...@@ -1841,7 +1853,7 @@ abstract class Diagnosticable { ...@@ -1841,7 +1853,7 @@ abstract class Diagnosticable {
/// relationship between the parent and the node. For example, pass /// relationship between the parent and the node. For example, pass
/// [DiagnosticsTreeStyle.offstage] to indicate that a node is offstage. /// [DiagnosticsTreeStyle.offstage] to indicate that a node is offstage.
DiagnosticsNode toDiagnosticsNode({ String name, DiagnosticsTreeStyle style }) { DiagnosticsNode toDiagnosticsNode({ String name, DiagnosticsTreeStyle style }) {
return new _DiagnosticableNode<Diagnosticable>( return new DiagnosticableNode<Diagnosticable>(
name: name, name: name,
value: this, value: this,
style: style, style: style,
...@@ -2110,8 +2122,8 @@ abstract class DiagnosticableTree extends Diagnosticable { ...@@ -2110,8 +2122,8 @@ abstract class DiagnosticableTree extends Diagnosticable {
/// * [toString], for a brief description of the object but not its children. /// * [toString], for a brief description of the object but not its children.
/// * [toStringShallow], for a detailed description of the object but not its /// * [toStringShallow], for a detailed description of the object but not its
/// children. /// children.
String toStringDeep([String prefixLineOne = '', String prefixOtherLines]) { String toStringDeep({ String prefixLineOne: '', String prefixOtherLines }) {
return toDiagnosticsNode().toStringDeep(prefixLineOne, prefixOtherLines); return toDiagnosticsNode().toStringDeep(prefixLineOne: prefixLineOne, prefixOtherLines: prefixOtherLines);
} }
@override @override
...@@ -2176,8 +2188,8 @@ abstract class DiagnosticableTreeMixin implements DiagnosticableTree { ...@@ -2176,8 +2188,8 @@ abstract class DiagnosticableTreeMixin implements DiagnosticableTree {
} }
@override @override
String toStringDeep([String prefixLineOne = '', String prefixOtherLines]) { String toStringDeep({ String prefixLineOne: '', String prefixOtherLines }) {
return toDiagnosticsNode().toStringDeep(prefixLineOne, prefixOtherLines); return toDiagnosticsNode().toStringDeep(prefixLineOne: prefixLineOne, prefixOtherLines: prefixOtherLines);
} }
@override @override
......
...@@ -271,7 +271,7 @@ class TextSpan extends DiagnosticableTree { ...@@ -271,7 +271,7 @@ class TextSpan extends DiagnosticableTree {
'TextSpan contains a null child.\n' 'TextSpan contains a null child.\n'
'A TextSpan object with a non-null child list should not have any nulls in its child list.\n' 'A TextSpan object with a non-null child list should not have any nulls in its child list.\n'
'The full text in question was:\n' 'The full text in question was:\n'
'${toStringDeep(' ')}' '${toStringDeep(prefixLineOne: ' ')}'
); );
} }
return true; return true;
......
...@@ -329,7 +329,7 @@ void debugDumpLayerTree() { ...@@ -329,7 +329,7 @@ void debugDumpLayerTree() {
/// The order in which the children of a [SemanticsNode] will be printed is /// The order in which the children of a [SemanticsNode] will be printed is
/// controlled by the [childOrder] parameter. /// controlled by the [childOrder] parameter.
void debugDumpSemanticsTree(DebugSemanticsDumpOrder childOrder) { void debugDumpSemanticsTree(DebugSemanticsDumpOrder childOrder) {
debugPrint(RendererBinding.instance?.renderView?.debugSemantics?.toStringDeep(childOrder) ?? 'Semantics not collected.'); debugPrint(RendererBinding.instance?.renderView?.debugSemantics?.toStringDeep(childOrder: childOrder) ?? 'Semantics not collected.');
} }
/// A concrete binding for applications that use the Rendering framework /// A concrete binding for applications that use the Rendering framework
......
...@@ -145,11 +145,15 @@ List<String> debugDescribeTransform(Matrix4 transform) { ...@@ -145,11 +145,15 @@ List<String> debugDescribeTransform(Matrix4 transform) {
/// Property which handles [Matrix4] that represent transforms. /// Property which handles [Matrix4] that represent transforms.
class TransformProperty extends DiagnosticsProperty<Matrix4> { class TransformProperty extends DiagnosticsProperty<Matrix4> {
/// Create a diagnostics property for [Matrix4] objects. /// Create a diagnostics property for [Matrix4] objects.
///
/// The [showName] argument must not be null.
TransformProperty(String name, Matrix4 value, { TransformProperty(String name, Matrix4 value, {
bool showName: true,
Object defaultValue: kNoDefaultValue, Object defaultValue: kNoDefaultValue,
}) : super( }) : assert(showName != null), super(
name, name,
value, value,
showName: showName,
defaultValue: defaultValue, defaultValue: defaultValue,
); );
......
...@@ -2839,11 +2839,11 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im ...@@ -2839,11 +2839,11 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
/// If the prefix argument is provided, then every line in the output /// If the prefix argument is provided, then every line in the output
/// will be prefixed by that string. /// will be prefixed by that string.
@override @override
String toStringDeep([String prefixLineOne = '', String prefixOtherLines = '']) { String toStringDeep({ String prefixLineOne: '', String prefixOtherLines: '' }) {
final RenderObject debugPreviousActiveLayout = _debugActiveLayout; final RenderObject debugPreviousActiveLayout = _debugActiveLayout;
_debugActiveLayout = null; _debugActiveLayout = null;
final String result = super.toStringDeep(prefixLineOne, prefixOtherLines); final String result = super.toStringDeep(prefixLineOne: prefixLineOne, prefixOtherLines: prefixOtherLines);
_debugActiveLayout = debugPreviousActiveLayout; _debugActiveLayout = debugPreviousActiveLayout;
return result; return result;
......
...@@ -91,7 +91,7 @@ class SemanticsTag { ...@@ -91,7 +91,7 @@ class SemanticsTag {
/// ///
/// Typically obtained from [SemanticsNode.getSemanticsData]. /// Typically obtained from [SemanticsNode.getSemanticsData].
@immutable @immutable
class SemanticsData { class SemanticsData extends Diagnosticable {
/// Creates a semantics data object. /// Creates a semantics data object.
/// ///
/// The [flags], [actions], [label], and [Rect] arguments must not be null. /// The [flags], [actions], [label], and [Rect] arguments must not be null.
...@@ -146,25 +146,28 @@ class SemanticsData { ...@@ -146,25 +146,28 @@ class SemanticsData {
bool hasAction(SemanticsAction action) => (actions & action.index) != 0; bool hasAction(SemanticsAction action) => (actions & action.index) != 0;
@override @override
String toString() { String toStringShort() => '$runtimeType';
final StringBuffer buffer = new StringBuffer();
buffer.write('$runtimeType($rect'); @override
if (transform != null) void debugFillProperties(DiagnosticPropertiesBuilder properties) {
buffer.write('; $transform'); super.debugFillProperties(properties);
properties.add(new DiagnosticsProperty<Rect>('rect', rect, showName: false));
properties.add(new TransformProperty('transform', transform, showName: false, defaultValue: null));
final List<String> actionSummary = <String>[];
for (SemanticsAction action in SemanticsAction.values.values) { for (SemanticsAction action in SemanticsAction.values.values) {
if ((actions & action.index) != 0) if ((actions & action.index) != 0)
buffer.write('; $action'); actionSummary.add(describeEnum(action));
} }
properties.add(new IterableProperty<String>('actions', actionSummary, hidden: actionSummary.isEmpty));
final List<String> flagSummary = <String>[];
for (SemanticsFlags flag in SemanticsFlags.values.values) { for (SemanticsFlags flag in SemanticsFlags.values.values) {
if ((flags & flag.index) != 0) if ((flags & flag.index) != 0)
buffer.write('; $flag'); flagSummary.add(describeEnum(flag));
} }
if (label.isNotEmpty) properties.add(new IterableProperty<String>('flags', flagSummary, hidden: flagSummary.isEmpty));
buffer.write('; "$label"'); properties.add(new StringProperty('label', label, defaultValue: ''));
if (textDirection != null) properties.add(new EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
buffer.write('; $textDirection');
buffer.write(')');
return buffer.toString();
} }
@override @override
...@@ -185,13 +188,36 @@ class SemanticsData { ...@@ -185,13 +188,36 @@ class SemanticsData {
int get hashCode => hashValues(flags, actions, label, textDirection, rect, tags, transform); int get hashCode => hashValues(flags, actions, label, textDirection, rect, tags, transform);
} }
class _SemanticsDiagnosticableNode extends DiagnosticableNode<SemanticsNode> {
_SemanticsDiagnosticableNode({
String name,
@required SemanticsNode value,
@required DiagnosticsTreeStyle style,
@required this.childOrder,
}) : super(
name: name,
value: value,
style: style,
);
final DebugSemanticsDumpOrder childOrder;
@override
List<DiagnosticsNode> getChildren() {
if (value != null)
return value.debugDescribeChildren(childOrder: childOrder);
return const <DiagnosticsNode>[];
}
}
/// A node that represents some semantic data. /// A node that represents some semantic data.
/// ///
/// The semantics tree is maintained during the semantics phase of the pipeline /// The semantics tree is maintained during the semantics phase of the pipeline
/// (i.e., during [PipelineOwner.flushSemantics]), which happens after /// (i.e., during [PipelineOwner.flushSemantics]), which happens after
/// compositing. The semantics tree is then uploaded into the engine for use /// compositing. The semantics tree is then uploaded into the engine for use
/// by assistive technology. /// by assistive technology.
class SemanticsNode extends AbstractNode { class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
/// Creates a semantic node. /// Creates a semantic node.
/// ///
/// Each semantic node has a unique identifier that is assigned when the node /// Each semantic node has a unique identifier that is assigned when the node
...@@ -211,7 +237,7 @@ class SemanticsNode extends AbstractNode { ...@@ -211,7 +237,7 @@ class SemanticsNode extends AbstractNode {
VoidCallback showOnScreen, VoidCallback showOnScreen,
SemanticsOwner owner, SemanticsOwner owner,
}) : id = 0, }) : id = 0,
_showOnScreen = showOnScreen, _showOnScreen = showOnScreen,
_actionHandler = handler { _actionHandler = handler {
attach(owner); attach(owner);
} }
...@@ -722,77 +748,87 @@ class SemanticsNode extends AbstractNode { ...@@ -722,77 +748,87 @@ class SemanticsNode extends AbstractNode {
} }
@override @override
String toString() { String toStringShort() => '$runtimeType#$id';
final StringBuffer buffer = new StringBuffer();
buffer.write('$runtimeType($id'); @override
if (_dirty) void debugFillProperties(DiagnosticPropertiesBuilder properties) {
buffer.write(' (${ owner != null && owner._dirtyNodes.contains(this) ? "dirty" : "STALE; owner=$owner" })'); bool hideOwner = true;
if (_shouldMergeAllDescendantsIntoThisNode) if (_dirty) {
buffer.write(' (leaf merge)'); final bool inDirtyNodes = owner != null && owner._dirtyNodes.contains(this);
properties.add(new FlagProperty('inDirtyNodes', value: inDirtyNodes, ifTrue: 'dirty', ifFalse: 'STALE'));
hideOwner = inDirtyNodes;
}
properties.add(new DiagnosticsProperty<SemanticsOwner>('owner', owner, hidden: hideOwner));
properties.add(new FlagProperty('shouldMergeAllDescendantsIntoThisNode', value: _shouldMergeAllDescendantsIntoThisNode, ifTrue: 'leaf merge'));
final Offset offset = transform != null ? MatrixUtils.getAsTranslation(transform) : null; final Offset offset = transform != null ? MatrixUtils.getAsTranslation(transform) : null;
if (offset != null) { if (offset != null) {
buffer.write('; ${rect.shift(offset)}'); properties.add(new DiagnosticsProperty<Rect>('rect', rect.shift(offset), showName: false));
} else { } else {
final double scale = transform != null ? MatrixUtils.getAsScale(transform) : null; final double scale = transform != null ? MatrixUtils.getAsScale(transform) : null;
String description;
if (scale != null) { if (scale != null) {
buffer.write('; $rect scaled by ${scale.toStringAsFixed(1)}x'); description = '$rect scaled by ${scale.toStringAsFixed(1)}x';
} else if (transform != null && !MatrixUtils.isIdentity(transform)) { } else if (transform != null && !MatrixUtils.isIdentity(transform)) {
final String matrix = transform.toString().split('\n').take(4).map((String line) => line.substring(4)).join('; '); final String matrix = transform.toString().split('\n').take(4).map((String line) => line.substring(4)).join('; ');
buffer.write('; $rect with transform [$matrix]'); description = '$rect with transform [$matrix]';
} else {
buffer.write('; $rect');
} }
properties.add(new DiagnosticsProperty<Rect>('rect', rect, description: description, showName: false));
} }
if (wasAffectedByClip) properties.add(new FlagProperty('wasAffectedByClip', value: wasAffectedByClip, ifTrue: 'clipped'));
buffer.write(' (clipped)'); final List<String> actions = <String>[];
for (SemanticsAction action in SemanticsAction.values.values) { for (SemanticsAction action in SemanticsAction.values.values) {
if ((_actions & action.index) != 0) if ((_actions & action.index) != 0)
buffer.write('; $action'); actions.add(describeEnum(action));
} }
for (SemanticsTag tag in _tags) properties.add(new IterableProperty<String>('actions', actions, hidden: actions.isEmpty));
buffer.write('; $tag'); properties.add(new IterableProperty<SemanticsTag>('tags', _tags, hidden: _tags.isEmpty));
if (hasCheckedState) { if (hasCheckedState)
if (isChecked) properties.add(new FlagProperty('isChecked', value: isChecked, ifTrue: 'checked', ifFalse: 'unchecked'));
buffer.write('; checked'); properties.add(new FlagProperty('isSelected', value: isSelected, ifTrue: 'selected'));
else properties.add(new StringProperty('label', label, defaultValue: ''));
buffer.write('; unchecked'); properties.add(new EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
}
if (isSelected)
buffer.write('; selected');
if (label.isNotEmpty)
buffer.write('; "$label"');
if (textDirection != null)
buffer.write('; $textDirection');
buffer.write(')');
return buffer.toString();
} }
/// Returns a string representation of this node and its descendants. /// Returns a string representation of this node and its descendants.
/// ///
/// The order in which the children of the [SemanticsNode] will be printed is /// The order in which the children of the [SemanticsNode] will be printed is
/// controlled by the [childOrder] parameter. /// controlled by the [childOrder] parameter.
String toStringDeep(DebugSemanticsDumpOrder childOrder, [ @override
String prefixLineOne = '', String toStringDeep({
String prefixOtherLines = '' String prefixLineOne: '',
]) { String prefixOtherLines,
DebugSemanticsDumpOrder childOrder: DebugSemanticsDumpOrder.traversal,
}) {
assert(childOrder != null); assert(childOrder != null);
final StringBuffer result = new StringBuffer() return toDiagnosticsNode(childOrder: childOrder).toStringDeep(prefixLineOne: prefixLineOne, prefixOtherLines: prefixOtherLines);
..write(prefixLineOne) }
..write(this)
..write('\n'); @override
if (_children != null && _children.isNotEmpty) { DiagnosticsNode toDiagnosticsNode({
final List<SemanticsNode> childrenInOrder = _getChildrenInOrder(childOrder); String name,
for (int index = 0; index < childrenInOrder.length - 1; index += 1) { DiagnosticsTreeStyle style: DiagnosticsTreeStyle.dense,
final SemanticsNode child = childrenInOrder[index]; DebugSemanticsDumpOrder childOrder: DebugSemanticsDumpOrder.traversal,
result.write(child.toStringDeep(childOrder, "$prefixOtherLines \u251C", "$prefixOtherLines \u2502")); }) {
} return new _SemanticsDiagnosticableNode(
result.write(childrenInOrder.last.toStringDeep(childOrder, "$prefixOtherLines \u2514", "$prefixOtherLines ")); name: name,
} value: this,
return result.toString(); style: style,
childOrder: childOrder,
);
}
@override
List<DiagnosticsNode> debugDescribeChildren({ DebugSemanticsDumpOrder childOrder: DebugSemanticsDumpOrder.inverseHitTest }) {
return _getChildrenInOrder(childOrder)
.map<DiagnosticsNode>((SemanticsNode node) => node.toDiagnosticsNode(childOrder: childOrder))
.toList();
} }
Iterable<SemanticsNode> _getChildrenInOrder(DebugSemanticsDumpOrder childOrder) { Iterable<SemanticsNode> _getChildrenInOrder(DebugSemanticsDumpOrder childOrder) {
assert(childOrder != null); assert(childOrder != null);
if (_children == null)
return const <SemanticsNode>[];
switch(childOrder) { switch(childOrder) {
case DebugSemanticsDumpOrder.traversal: case DebugSemanticsDumpOrder.traversal:
return new List<SemanticsNode>.from(_children)..sort(_geometryComparator); return new List<SemanticsNode>.from(_children)..sort(_geometryComparator);
......
...@@ -456,6 +456,6 @@ class FocusManager { ...@@ -456,6 +456,6 @@ class FocusManager {
final String indent = ' '; final String indent = ' ';
return '${describeIdentity(this)}$status\n' return '${describeIdentity(this)}$status\n'
'${indent}currentFocus: $_currentFocus\n' '${indent}currentFocus: $_currentFocus\n'
'${rootScope.toStringDeep(indent, indent)}'; '${rootScope.toStringDeep(prefixLineOne: indent, prefixOtherLines: indent)}';
} }
} }
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'package:vector_math/vector_math_64.dart';
import 'rendering_tester.dart'; import 'rendering_tester.dart';
...@@ -94,8 +95,8 @@ void main() { ...@@ -94,8 +95,8 @@ void main() {
}); });
test('toStringDeep() does not throw with transform == null', () { test('toStringDeep() does not throw with transform == null', () {
final SemanticsNode child2 = new SemanticsNode();
final SemanticsNode child1 = new SemanticsNode(); final SemanticsNode child1 = new SemanticsNode();
final SemanticsNode child2 = new SemanticsNode();
final SemanticsNode root = new SemanticsNode(); final SemanticsNode root = new SemanticsNode();
root.addChildren(<SemanticsNode>[child1, child2]); root.addChildren(<SemanticsNode>[child1, child2]);
root.finalizeChildren(); root.finalizeChildren();
...@@ -104,10 +105,106 @@ void main() { ...@@ -104,10 +105,106 @@ void main() {
expect(child1.transform, isNull); expect(child1.transform, isNull);
expect(child2.transform, isNull); expect(child2.transform, isNull);
expect(root.toStringDeep(DebugSemanticsDumpOrder.traversal), expect(
'SemanticsNode(8 (STALE; owner=null); Rect.fromLTRB(0.0, 0.0, 0.0, 0.0))\n' root.toStringDeep(childOrder: DebugSemanticsDumpOrder.traversal),
' ├SemanticsNode(7; Rect.fromLTRB(0.0, 0.0, 0.0, 0.0))\n' 'SemanticsNode#8(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 0.0, 0.0))\n'
' └SemanticsNode(6; Rect.fromLTRB(0.0, 0.0, 0.0, 0.0))\n' '├SemanticsNode#6(Rect.fromLTRB(0.0, 0.0, 0.0, 0.0))\n'
'└SemanticsNode#7(Rect.fromLTRB(0.0, 0.0, 0.0, 0.0))\n',
);
});
test('toStringDeep respects childOrder parameter', () {
final SemanticsNode child1 = new SemanticsNode()
..rect = new Rect.fromLTRB(20.0, 20.0, 20.0, 20.0);
final SemanticsNode child2 = new SemanticsNode()
..rect = new Rect.fromLTRB(10.0, 10.0, 10.0, 10.0);
final SemanticsNode root = new SemanticsNode();
root.addChildren(<SemanticsNode>[child1, child2]);
root.finalizeChildren();
expect(
root.toStringDeep(childOrder: DebugSemanticsDumpOrder.traversal),
'SemanticsNode#11(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 0.0, 0.0))\n'
'├SemanticsNode#10(STALE, owner: null, Rect.fromLTRB(10.0, 10.0, 10.0, 10.0))\n'
'└SemanticsNode#9(STALE, owner: null, Rect.fromLTRB(20.0, 20.0, 20.0, 20.0))\n',
);
expect(
root.toStringDeep(childOrder: DebugSemanticsDumpOrder.inverseHitTest),
'SemanticsNode#11(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 0.0, 0.0))\n'
'├SemanticsNode#9(STALE, owner: null, Rect.fromLTRB(20.0, 20.0, 20.0, 20.0))\n'
'└SemanticsNode#10(STALE, owner: null, Rect.fromLTRB(10.0, 10.0, 10.0, 10.0))\n',
);
final SemanticsNode child3 = new SemanticsNode()
..rect = new Rect.fromLTRB(0.0, 0.0, 0.0, 0.0);
child3.addChildren(<SemanticsNode>[
new SemanticsNode()..rect = new Rect.fromLTRB(20.0, 0.0, 20.0, 0.0),
new SemanticsNode(),
]);
child3.finalizeChildren();
final SemanticsNode rootComplex = new SemanticsNode();
rootComplex.addChildren(<SemanticsNode>[child1, child2, child3]);
rootComplex.finalizeChildren();
expect(
rootComplex.toStringDeep(childOrder: DebugSemanticsDumpOrder.traversal),
'SemanticsNode#15(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 0.0, 0.0))\n'
'├SemanticsNode#12(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 0.0, 0.0))\n'
'│├SemanticsNode#14(Rect.fromLTRB(0.0, 0.0, 0.0, 0.0))\n'
'│└SemanticsNode#13(STALE, owner: null, Rect.fromLTRB(20.0, 0.0, 20.0, 0.0))\n'
'├SemanticsNode#10(STALE, owner: null, Rect.fromLTRB(10.0, 10.0, 10.0, 10.0))\n'
'└SemanticsNode#9(STALE, owner: null, Rect.fromLTRB(20.0, 20.0, 20.0, 20.0))\n',
);
expect(
rootComplex.toStringDeep(childOrder: DebugSemanticsDumpOrder.inverseHitTest),
'SemanticsNode#15(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 0.0, 0.0))\n'
'├SemanticsNode#9(STALE, owner: null, Rect.fromLTRB(20.0, 20.0, 20.0, 20.0))\n'
'├SemanticsNode#10(STALE, owner: null, Rect.fromLTRB(10.0, 10.0, 10.0, 10.0))\n'
'└SemanticsNode#12(STALE, owner: null, Rect.fromLTRB(0.0, 0.0, 0.0, 0.0))\n'
' ├SemanticsNode#13(STALE, owner: null, Rect.fromLTRB(20.0, 0.0, 20.0, 0.0))\n'
' └SemanticsNode#14(Rect.fromLTRB(0.0, 0.0, 0.0, 0.0))\n',
);
});
test('debug properties', () {
expect(
new SemanticsNode().toStringDeep(),
'SemanticsNode#16(Rect.fromLTRB(0.0, 0.0, 0.0, 0.0))\n',
);
final SemanticsNode allProperties = new SemanticsNode()
..rect = new Rect.fromLTWH(50.0, 10.0, 20.0, 30.0)
..mergeAllDescendantsIntoThisNode = true
..transform = new Matrix4.translation(new Vector3(10.0, 10.0, 0.0))
..wasAffectedByClip = true
..addAction(SemanticsAction.scrollUp)
..addAction(SemanticsAction.longPress)
..addAction(SemanticsAction.showOnScreen)
..isChecked = false
..isSelected = true
..label = "Use all the properties"
..textDirection = TextDirection.rtl;
expect(
allProperties.toStringDeep(),
'SemanticsNode#17(STALE, owner: null, leaf merge, Rect.fromLTRB(60.0, 20.0, 80.0, 50.0), clipped, actions: [longPress, scrollUp, showOnScreen], selected, label: "Use all the properties", textDirection: rtl)\n',
);
expect(
allProperties.getSemanticsData().toString(),
'SemanticsData(Rect.fromLTRB(50.0, 10.0, 70.0, 40.0), [1.0,0.0,0.0,10.0; 0.0,1.0,0.0,10.0; 0.0,0.0,1.0,0.0; 0.0,0.0,0.0,1.0], actions: [longPress, scrollUp, showOnScreen], flags: [isSelected], label: "Use all the properties", textDirection: rtl)',
);
final SemanticsNode scaled = new SemanticsNode()
..rect = new Rect.fromLTWH(50.0, 10.0, 20.0, 30.0)
..transform = new Matrix4.diagonal3(new Vector3(10.0, 10.0, 1.0));
expect(
scaled.toStringDeep(),
'SemanticsNode#18(STALE, owner: null, Rect.fromLTRB(50.0, 10.0, 70.0, 40.0) scaled by 10.0x)\n',
);
expect(
scaled.getSemanticsData().toString(),
'SemanticsData(Rect.fromLTRB(50.0, 10.0, 70.0, 40.0), [10.0,0.0,0.0,0.0; 0.0,10.0,0.0,0.0; 0.0,0.0,1.0,0.0; 0.0,0.0,0.0,1.0])',
); );
}); });
......
...@@ -507,7 +507,7 @@ class _HasGoodToStringDeep extends Matcher { ...@@ -507,7 +507,7 @@ class _HasGoodToStringDeep extends Matcher {
final String prefixOtherLines = 'PREFIX_OTHER_LINES_'; final String prefixOtherLines = 'PREFIX_OTHER_LINES_';
final List<String> prefixIssues = <String>[]; final List<String> prefixIssues = <String>[];
String descriptionWithPrefixes = String descriptionWithPrefixes =
object.toStringDeep(prefixLineOne, prefixOtherLines); object.toStringDeep(prefixLineOne: prefixLineOne, prefixOtherLines: prefixOtherLines);
if (descriptionWithPrefixes.endsWith('\n')) { if (descriptionWithPrefixes.endsWith('\n')) {
// Trim off trailing \n as the remaining calculations assume // Trim off trailing \n as the remaining calculations assume
// the description does not end with a trailing \n. // the description does not end with a trailing \n.
...@@ -532,7 +532,7 @@ class _HasGoodToStringDeep extends Matcher { ...@@ -532,7 +532,7 @@ class _HasGoodToStringDeep extends Matcher {
if (prefixIssues.isNotEmpty) { if (prefixIssues.isNotEmpty) {
errorDescription.writeln( errorDescription.writeln(
'Bad toStringDeep("$prefixLineOne", "$prefixOtherLines"):'); 'Bad toStringDeep(prefixLineOne: "$prefixLineOne", prefixOtherLines: "$prefixOtherLines"):');
errorDescription.writeln(descriptionWithPrefixes); errorDescription.writeln(descriptionWithPrefixes);
errorDescription.writeAll(prefixIssues, '\n'); errorDescription.writeAll(prefixIssues, '\n');
} }
......
...@@ -26,7 +26,7 @@ class _MockToStringDeep { ...@@ -26,7 +26,7 @@ class _MockToStringDeep {
/// line break. /// line break.
List<String> _lines; List<String> _lines;
String toStringDeep([String prefixLineOne="", String prefixOtherLines=""]) { String toStringDeep({ String prefixLineOne: "", String prefixOtherLines: "" }) {
final StringBuffer sb = new StringBuffer(); final StringBuffer sb = new StringBuffer();
if (_lines.isNotEmpty) if (_lines.isNotEmpty)
sb.write('$prefixLineOne${_lines.first}'); sb.write('$prefixLineOne${_lines.first}');
......
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