Commit 141a6355 authored by Michael Goderbauer's avatar Michael Goderbauer Committed by GitHub

Performance improvements for semantics tree compilation (#12682)

* Without checking compatibility

* ++

* ++

* ++

* more docs
parent 3206fb63
......@@ -3086,7 +3086,6 @@ class RenderSemanticsGestureHandler extends RenderProxyBox {
_innerNode ??= new SemanticsNode(showOnScreen: showOnScreen);
_innerNode
..wasAffectedByClip = node.wasAffectedByClip
..isMergedIntoParent = node.isPartOfNodeMerging
..rect = Offset.zero & node.rect.size;
_annotatedNode = _innerNode;
......
......@@ -253,12 +253,11 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
}
}
/// Whether [rect] was affected by a clip from an ancestors.
/// The clip rect from an ancestor that was applied to this node.
///
/// If this is true it means that an ancestor imposed a clip on this
/// [SemanticsNode]. However, it does not mean that the clip had any effect
/// on the [rect] whatsoever.
bool wasAffectedByClip = false;
/// Expressed in the coordinate system of the node. May be null if no clip has
/// been applied.
Rect parentClipRect;
/// Whether the node is invisible.
///
......@@ -488,7 +487,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
return _label != config.label ||
_flags != config._flags ||
_textDirection != config.textDirection ||
_actionsAsBitMap(_actions) != _actionsAsBitMap(config._actions) ||
_actionsAsBits != config._actionsAsBits ||
_mergeAllDescendantsIntoThisNode != config.isMergingSemanticsOfDescendants;
}
......@@ -496,6 +495,8 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
Map<SemanticsAction, VoidCallback> _actions = _kEmptyConfig._actions;
int _actionsAsBits = _kEmptyConfig._actionsAsBits;
/// The [SemanticsTag]s this node is tagged with.
///
/// Tags are used during the construction of the semantics tree. They are not
......@@ -519,10 +520,6 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
TextDirection get textDirection => _textDirection;
TextDirection _textDirection = _kEmptyConfig.textDirection;
int _actionsAsBitMap(Map<SemanticsAction, VoidCallback> actions) {
return actions.keys.fold(0, (int prev, SemanticsAction action) => prev |= action.index);
}
bool _canPerformAction(SemanticsAction action) => _actions.containsKey(action);
static final SemanticsConfiguration _kEmptyConfig = new SemanticsConfiguration();
......@@ -539,6 +536,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
_flags = config._flags;
_textDirection = config.textDirection;
_actions = new Map<SemanticsAction, VoidCallback>.from(config._actions);
_actionsAsBits = config._actionsAsBits;
_mergeAllDescendantsIntoThisNode = config.isMergingSemanticsOfDescendants;
_replaceChildren(childrenInInversePaintOrder ?? const <SemanticsNode>[]);
}
......@@ -551,7 +549,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
/// returned data matches the data on this node.
SemanticsData getSemanticsData() {
int flags = _flags;
int actions = _actionsAsBitMap(_actions);
int actions = _actionsAsBits;
String label = _label;
TextDirection textDirection = _textDirection;
Set<SemanticsTag> mergedTags = tags == null ? null : new Set<SemanticsTag>.from(tags);
......@@ -560,7 +558,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
_visitDescendants((SemanticsNode node) {
assert(node.isMergedIntoParent);
flags |= node._flags;
actions |= _actionsAsBitMap(node._actions);
actions |= node._actionsAsBits;
textDirection ??= node._textDirection;
if (node.tags != null) {
mergedTags ??= new Set<SemanticsTag>();
......@@ -673,7 +671,6 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
}
properties.add(new DiagnosticsProperty<Rect>('rect', rect, description: description, showName: false));
}
properties.add(new FlagProperty('wasAffectedByClip', value: wasAffectedByClip, ifTrue: 'clipped'));
final List<String> actions = _actions.keys.map((SemanticsAction action) => describeEnum(action)).toList()..sort();
properties.add(new IterableProperty<String>('actions', actions, ifEmpty: null));
if (_hasFlag(SemanticsFlags.hasCheckedState))
......@@ -871,7 +868,7 @@ class SemanticsOwner extends ChangeNotifier {
return handler;
}
}
return node._canPerformAction(action) ? node._actions[action] : null;
return node._actions[action];
}
/// Asks the [SemanticsNode] at the given position to perform the given action.
......@@ -985,11 +982,14 @@ class SemanticsConfiguration {
/// * [addAction] to add an action.
final Map<SemanticsAction, VoidCallback> _actions = <SemanticsAction, VoidCallback>{};
int _actionsAsBits = 0;
/// Adds an `action` to the semantics tree.
///
/// Whenever the user performs `action` the provided `handler` is called.
void addAction(SemanticsAction action, VoidCallback handler) {
_actions[action] = handler;
_actionsAsBits |= action.index;
_hasBeenAnnotated = true;
}
......@@ -1083,7 +1083,7 @@ class SemanticsConfiguration {
bool isCompatibleWith(SemanticsConfiguration other) {
if (other == null || !other.hasBeenAnnotated || !hasBeenAnnotated)
return true;
if (_actions.keys.toSet().intersection(other._actions.keys.toSet()).isNotEmpty)
if (_actionsAsBits & other._actionsAsBits != 0)
return false;
if ((_flags & other._flags) != 0)
return false;
......@@ -1105,6 +1105,7 @@ class SemanticsConfiguration {
return;
_actions.addAll(other._actions);
_actionsAsBits |= other._actionsAsBits;
_flags |= other._flags;
textDirection ??= other.textDirection;
......@@ -1138,6 +1139,7 @@ class SemanticsConfiguration {
.._textDirection = _textDirection
.._label = _label
.._flags = _flags
.._actionsAsBits = _actionsAsBits
.._actions.addAll(_actions);
}
}
......@@ -40,12 +40,12 @@ void main() {
new TestSemantics.root(
children: <TestSemantics>[
new TestSemantics.rootChild(
id: 2,
id: 1,
label: 'I am text!\nMoar text!!1',
textDirection: TextDirection.ltr,
children: <TestSemantics>[
new TestSemantics(
id: 1,
id: 2,
label: 'Button',
textDirection: TextDirection.ltr,
actions: SemanticsAction.tap.index,
......
......@@ -95,7 +95,7 @@ void main() {
expect(semantics, hasSemantics(new TestSemantics.root(
children: <TestSemantics>[
new TestSemantics.rootChild(
id: 7,
id: 1,
rect: new Rect.fromLTWH(0.0, 0.0, 800.0, 56.0),
transform: null,
flags: SemanticsFlags.hasCheckedState.index | SemanticsFlags.isChecked.index,
......@@ -103,7 +103,7 @@ void main() {
label: 'aaa\nAAA',
),
new TestSemantics.rootChild(
id: 8,
id: 4,
rect: new Rect.fromLTWH(0.0, 0.0, 800.0, 56.0),
transform: new Matrix4.translationValues(0.0, 56.0, 0.0),
flags: SemanticsFlags.hasCheckedState.index | SemanticsFlags.isChecked.index,
......@@ -111,7 +111,7 @@ void main() {
label: 'bbb\nBBB',
),
new TestSemantics.rootChild(
id: 9,
id: 7,
rect: new Rect.fromLTWH(0.0, 0.0, 800.0, 56.0),
transform: new Matrix4.translationValues(0.0, 112.0, 0.0),
flags: SemanticsFlags.hasCheckedState.index,
......
......@@ -1011,11 +1011,11 @@ void main() {
final TestSemantics expectedSemantics = new TestSemantics.root(
children: <TestSemantics>[
new TestSemantics.rootChild(
id: 3,
id: 1,
rect: TestSemantics.fullScreen,
children: <TestSemantics>[
new TestSemantics(
id: 1,
id: 2,
actions: SemanticsAction.tap.index,
flags: SemanticsFlags.isSelected.index,
label: 'TAB #0\nTab 1 of 2',
......@@ -1023,7 +1023,7 @@ void main() {
transform: new Matrix4.translationValues(0.0, 276.0, 0.0),
),
new TestSemantics(
id: 2,
id: 3,
actions: SemanticsAction.tap.index,
label: 'TAB #1\nTab 2 of 2',
rect: new Rect.fromLTRB(0.0, 0.0, 108.0, kTextTabBarHeight),
......@@ -1261,11 +1261,11 @@ void main() {
final TestSemantics expectedSemantics = new TestSemantics.root(
children: <TestSemantics>[
new TestSemantics.rootChild(
id: 25,
id: 23,
rect: TestSemantics.fullScreen,
children: <TestSemantics>[
new TestSemantics(
id: 23,
id: 24,
actions: SemanticsAction.tap.index,
flags: SemanticsFlags.isSelected.index,
label: 'Semantics override 0\nTab 1 of 2',
......@@ -1273,7 +1273,7 @@ void main() {
transform: new Matrix4.translationValues(0.0, 276.0, 0.0),
),
new TestSemantics(
id: 24,
id: 25,
actions: SemanticsAction.tap.index,
label: 'Semantics override 1\nTab 2 of 2',
rect: new Rect.fromLTRB(0.0, 0.0, 108.0, kTextTabBarHeight),
......
......@@ -198,7 +198,7 @@ void main() {
expect(
minimalProperties.toStringDeep(minLevel: DiagnosticLevel.hidden),
'SemanticsNode#16(owner: null, isPartOfNodeMerging: false, Rect.fromLTRB(0.0, 0.0, 0.0, 0.0), wasAffectedByClip: false, actions: [], isSelected: false, label: "", isButton: false, textDirection: null)\n',
'SemanticsNode#16(owner: null, isPartOfNodeMerging: false, Rect.fromLTRB(0.0, 0.0, 0.0, 0.0), actions: [], isSelected: false, label: "", isButton: false, textDirection: null)\n',
);
final SemanticsConfiguration config = new SemanticsConfiguration()
......@@ -214,11 +214,10 @@ void main() {
final SemanticsNode allProperties = new SemanticsNode()
..rect = new Rect.fromLTWH(50.0, 10.0, 20.0, 30.0)
..transform = new Matrix4.translation(new Vector3(10.0, 10.0, 0.0))
..wasAffectedByClip = true
..updateWith(config: config, childrenInInversePaintOrder: null);
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], unchecked, selected, label: "Use all the properties", button, textDirection: rtl)\n',
'SemanticsNode#17(STALE, owner: null, leaf merge, Rect.fromLTRB(60.0, 20.0, 80.0, 50.0), actions: [longPress, scrollUp, showOnScreen], unchecked, selected, label: "Use all the properties", button, textDirection: rtl)\n',
);
expect(
allProperties.getSemanticsData().toString(),
......
......@@ -229,20 +229,20 @@ void main() {
new TestSemantics.root(
children: <TestSemantics>[
new TestSemantics.rootChild(
id: 8,
id: 5,
children: <TestSemantics>[
new TestSemantics(
id: 5,
id: 6,
flags: SemanticsFlags.isSelected.index,
label: 'node 1',
),
new TestSemantics(
id: 6,
id: 7,
flags: SemanticsFlags.isSelected.index,
label: 'node 2',
),
new TestSemantics(
id: 7,
id: 8,
flags: SemanticsFlags.isSelected.index,
label: 'node 3',
),
......
......@@ -104,11 +104,11 @@ void main() {
final TestSemantics expectedSemantics = new TestSemantics.root(
children: <TestSemantics>[
new TestSemantics.rootChild(
id: 2,
id: 1,
rect: TestSemantics.fullScreen,
children: <TestSemantics>[
new TestSemantics(
id: 1,
id: 2,
rect: TestSemantics.fullScreen,
actions: SemanticsAction.tap.index,
),
......
......@@ -53,17 +53,17 @@ void main() {
expect(semantics, hasSemantics(new TestSemantics.root(
children: <TestSemantics>[
new TestSemantics.rootChild(
id: 3,
id: 1,
rect: TestSemantics.fullScreen,
children: <TestSemantics>[
new TestSemantics(
id: 1,
id: 2,
label: 'child1',
rect: new Rect.fromLTRB(0.0, 0.0, 800.0, 10.0),
flags: SemanticsFlags.isSelected.index,
),
new TestSemantics(
id: 2,
id: 3,
label: 'child2',
rect: new Rect.fromLTRB(0.0, 0.0, 800.0, 10.0),
flags: SemanticsFlags.isSelected.index,
......@@ -107,7 +107,7 @@ void main() {
expect(semantics, hasSemantics(new TestSemantics.root(
children: <TestSemantics>[
new TestSemantics.rootChild(
id: 3,
id: 1,
label: 'child1',
rect: TestSemantics.fullScreen,
flags: SemanticsFlags.isSelected.index,
......@@ -149,7 +149,7 @@ void main() {
expect(semantics, hasSemantics(new TestSemantics.root(
children: <TestSemantics>[
new TestSemantics.rootChild(
id: 3,
id: 1,
rect: TestSemantics.fullScreen,
children: <TestSemantics>[
new TestSemantics(
......@@ -159,7 +159,7 @@ void main() {
flags: SemanticsFlags.isSelected.index,
),
new TestSemantics(
id: 2,
id: 3,
label: 'child2',
rect: new Rect.fromLTRB(0.0, 0.0, 800.0, 10.0),
flags: SemanticsFlags.isSelected.index,
......
......@@ -53,22 +53,22 @@ void main() {
new TestSemantics.root(
children: <TestSemantics>[
new TestSemantics.rootChild(
id: 3,
id: 1,
label: 'L1',
rect: TestSemantics.fullScreen,
),
new TestSemantics.rootChild(
id: 4,
id: 2,
label: 'L2',
rect: TestSemantics.fullScreen,
children: <TestSemantics>[
new TestSemantics(
id: 1,
id: 3,
flags: SemanticsFlags.hasCheckedState.index | SemanticsFlags.isChecked.index,
rect: TestSemantics.fullScreen,
),
new TestSemantics(
id: 2,
id: 4,
flags: SemanticsFlags.hasCheckedState.index,
rect: TestSemantics.fullScreen,
),
......@@ -113,12 +113,12 @@ void main() {
new TestSemantics.root(
children: <TestSemantics>[
new TestSemantics.rootChild(
id: 3,
id: 1,
label: 'L1',
rect: TestSemantics.fullScreen,
),
new TestSemantics.rootChild(
id: 4,
id: 2,
label: 'L2',
flags: SemanticsFlags.hasCheckedState.index | SemanticsFlags.isChecked.index,
rect: TestSemantics.fullScreen,
......@@ -158,7 +158,7 @@ void main() {
new TestSemantics.root(
children: <TestSemantics>[
new TestSemantics.rootChild(
id: 4,
id: 2,
label: 'L2',
flags: SemanticsFlags.hasCheckedState.index | SemanticsFlags.isChecked.index,
rect: TestSemantics.fullScreen,
......
......@@ -55,7 +55,7 @@ void main() {
new TestSemantics.root(
children: <TestSemantics>[
new TestSemantics.rootChild(
id: 3,
id: 1,
flags: SemanticsFlags.hasCheckedState.index | SemanticsFlags.isChecked.index,
label: label,
rect: TestSemantics.fullScreen,
......@@ -111,7 +111,7 @@ void main() {
new TestSemantics.root(
children: <TestSemantics>[
new TestSemantics.rootChild(
id: 3,
id: 1,
flags: SemanticsFlags.hasCheckedState.index | SemanticsFlags.isChecked.index,
label: label,
rect: TestSemantics.fullScreen,
......
......@@ -41,7 +41,7 @@ void main() {
new TestSemantics.root(
children: <TestSemantics>[
new TestSemantics.rootChild(
id: 3,
id: 1,
flags: SemanticsFlags.hasCheckedState.index | SemanticsFlags.isChecked.index,
label: 'label',
textDirection: TextDirection.ltr,
......@@ -79,7 +79,7 @@ void main() {
new TestSemantics.root(
children: <TestSemantics>[
new TestSemantics.rootChild(
id: 3,
id: 1,
flags: SemanticsFlags.hasCheckedState.index | SemanticsFlags.isChecked.index,
label: 'label',
textDirection: TextDirection.ltr,
......
......@@ -60,12 +60,6 @@ void main() {
ignoreTransform: true,
));
final SemanticsNode node1 = tester.renderObject(find.byWidget(const Text('1'))).debugSemantics;
final SemanticsNode node2 = tester.renderObject(find.byWidget(const Text('2'))).debugSemantics;
expect(node1.wasAffectedByClip, false);
expect(node2.wasAffectedByClip, true);
semantics.dispose();
});
......
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