Inline AbstractNode into SemanticsNode and Layer (#128467)
This commit is contained in:
parent
40bb615b0c
commit
16e6be8b39
@ -136,7 +136,7 @@ const String _flutterRenderingLibrary = 'package:flutter/rendering.dart';
|
|||||||
///
|
///
|
||||||
/// * [RenderView.compositeFrame], which implements this recomposition protocol
|
/// * [RenderView.compositeFrame], which implements this recomposition protocol
|
||||||
/// for painting [RenderObject] trees on the display.
|
/// for painting [RenderObject] trees on the display.
|
||||||
abstract class Layer extends AbstractNode with DiagnosticableTreeMixin {
|
abstract class Layer with DiagnosticableTreeMixin {
|
||||||
/// Creates an instance of Layer.
|
/// Creates an instance of Layer.
|
||||||
Layer() {
|
Layer() {
|
||||||
if (kFlutterMemoryAllocationsEnabled) {
|
if (kFlutterMemoryAllocationsEnabled) {
|
||||||
@ -344,8 +344,8 @@ abstract class Layer extends AbstractNode with DiagnosticableTreeMixin {
|
|||||||
///
|
///
|
||||||
/// Only subclasses of [ContainerLayer] can have children in the layer tree.
|
/// Only subclasses of [ContainerLayer] can have children in the layer tree.
|
||||||
/// All other layer classes are used for leaves in the layer tree.
|
/// All other layer classes are used for leaves in the layer tree.
|
||||||
@override
|
ContainerLayer? get parent => _parent;
|
||||||
ContainerLayer? get parent => super.parent as ContainerLayer?;
|
ContainerLayer? _parent;
|
||||||
|
|
||||||
// Whether this layer has any changes since its last call to [addToScene].
|
// Whether this layer has any changes since its last call to [addToScene].
|
||||||
//
|
//
|
||||||
@ -495,6 +495,71 @@ abstract class Layer extends AbstractNode with DiagnosticableTreeMixin {
|
|||||||
_needsAddToScene = _needsAddToScene || alwaysNeedsAddToScene;
|
_needsAddToScene = _needsAddToScene || alwaysNeedsAddToScene;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The owner for this node (null if unattached).
|
||||||
|
///
|
||||||
|
/// The entire subtree that this node belongs to will have the same owner.
|
||||||
|
Object? get owner => _owner;
|
||||||
|
Object? _owner;
|
||||||
|
|
||||||
|
/// Whether this node is in a tree whose root is attached to something.
|
||||||
|
///
|
||||||
|
/// This becomes true during the call to [attach].
|
||||||
|
///
|
||||||
|
/// This becomes false during the call to [detach].
|
||||||
|
bool get attached => _owner != null;
|
||||||
|
|
||||||
|
/// Mark this node as attached to the given owner.
|
||||||
|
///
|
||||||
|
/// Typically called only from the [parent]'s [attach] method, and by the
|
||||||
|
/// [owner] to mark the root of a tree as attached.
|
||||||
|
///
|
||||||
|
/// Subclasses with children should override this method to first call their
|
||||||
|
/// inherited [attach] method, and then [attach] all their children to the
|
||||||
|
/// same [owner].
|
||||||
|
///
|
||||||
|
/// Implementations of this method should start with a call to the inherited
|
||||||
|
/// method, as in `super.attach(owner)`.
|
||||||
|
@mustCallSuper
|
||||||
|
void attach(covariant Object owner) {
|
||||||
|
assert(_owner == null);
|
||||||
|
_owner = owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mark this node as detached.
|
||||||
|
///
|
||||||
|
/// Typically called only from the [parent]'s [detach], and by the [owner] to
|
||||||
|
/// mark the root of a tree as detached.
|
||||||
|
///
|
||||||
|
/// Subclasses with children should override this method to first call their
|
||||||
|
/// inherited [detach] method, and then [detach] all their children.
|
||||||
|
///
|
||||||
|
/// Implementations of this method should end with a call to the inherited
|
||||||
|
/// method, as in `super.detach()`.
|
||||||
|
@mustCallSuper
|
||||||
|
void detach() {
|
||||||
|
assert(_owner != null);
|
||||||
|
_owner = null;
|
||||||
|
assert(parent == null || attached == parent!.attached);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The depth of this node in the tree.
|
||||||
|
///
|
||||||
|
/// The depth of nodes in a tree monotonically increases as you traverse down
|
||||||
|
/// the tree.
|
||||||
|
int get depth => _depth;
|
||||||
|
int _depth = 0;
|
||||||
|
|
||||||
|
/// Adjust the [depth] of this node's children, if any.
|
||||||
|
///
|
||||||
|
/// Override this method in subclasses with child nodes to call
|
||||||
|
/// [ContainerLayer.redepthChild] for each child. Do not call this method
|
||||||
|
/// directly.
|
||||||
|
@protected
|
||||||
|
void redepthChildren() {
|
||||||
|
// ContainerLayer provides an implementation since its the only one that
|
||||||
|
// can actually have children.
|
||||||
|
}
|
||||||
|
|
||||||
/// This layer's next sibling in the parent layer's child list.
|
/// This layer's next sibling in the parent layer's child list.
|
||||||
Layer? get nextSibling => _nextSibling;
|
Layer? get nextSibling => _nextSibling;
|
||||||
Layer? _nextSibling;
|
Layer? _nextSibling;
|
||||||
@ -503,30 +568,6 @@ abstract class Layer extends AbstractNode with DiagnosticableTreeMixin {
|
|||||||
Layer? get previousSibling => _previousSibling;
|
Layer? get previousSibling => _previousSibling;
|
||||||
Layer? _previousSibling;
|
Layer? _previousSibling;
|
||||||
|
|
||||||
@override
|
|
||||||
void dropChild(Layer child) {
|
|
||||||
assert(!_debugMutationsLocked);
|
|
||||||
if (!alwaysNeedsAddToScene) {
|
|
||||||
markNeedsAddToScene();
|
|
||||||
}
|
|
||||||
if (child._compositionCallbackCount != 0) {
|
|
||||||
_updateSubtreeCompositionObserverCount(-child._compositionCallbackCount);
|
|
||||||
}
|
|
||||||
super.dropChild(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void adoptChild(Layer child) {
|
|
||||||
assert(!_debugMutationsLocked);
|
|
||||||
if (!alwaysNeedsAddToScene) {
|
|
||||||
markNeedsAddToScene();
|
|
||||||
}
|
|
||||||
if (child._compositionCallbackCount != 0) {
|
|
||||||
_updateSubtreeCompositionObserverCount(child._compositionCallbackCount);
|
|
||||||
}
|
|
||||||
super.adoptChild(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Removes this layer from its parent layer's child list.
|
/// Removes this layer from its parent layer's child list.
|
||||||
///
|
///
|
||||||
/// This has no effect if the layer's parent is already null.
|
/// This has no effect if the layer's parent is already null.
|
||||||
@ -1198,7 +1239,7 @@ class ContainerLayer extends Layer {
|
|||||||
assert(node != child); // indicates we are about to create a cycle
|
assert(node != child); // indicates we are about to create a cycle
|
||||||
return true;
|
return true;
|
||||||
}());
|
}());
|
||||||
adoptChild(child);
|
_adoptChild(child);
|
||||||
child._previousSibling = lastChild;
|
child._previousSibling = lastChild;
|
||||||
if (lastChild != null) {
|
if (lastChild != null) {
|
||||||
lastChild!._nextSibling = child;
|
lastChild!._nextSibling = child;
|
||||||
@ -1209,6 +1250,52 @@ class ContainerLayer extends Layer {
|
|||||||
assert(child.attached == attached);
|
assert(child.attached == attached);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _adoptChild(Layer child) {
|
||||||
|
assert(!_debugMutationsLocked);
|
||||||
|
if (!alwaysNeedsAddToScene) {
|
||||||
|
markNeedsAddToScene();
|
||||||
|
}
|
||||||
|
if (child._compositionCallbackCount != 0) {
|
||||||
|
_updateSubtreeCompositionObserverCount(child._compositionCallbackCount);
|
||||||
|
}
|
||||||
|
assert(child._parent == null);
|
||||||
|
assert(() {
|
||||||
|
Layer node = this;
|
||||||
|
while (node.parent != null) {
|
||||||
|
node = node.parent!;
|
||||||
|
}
|
||||||
|
assert(node != child); // indicates we are about to create a cycle
|
||||||
|
return true;
|
||||||
|
}());
|
||||||
|
child._parent = this;
|
||||||
|
if (attached) {
|
||||||
|
child.attach(_owner!);
|
||||||
|
}
|
||||||
|
redepthChild(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void redepthChildren() {
|
||||||
|
Layer? child = firstChild;
|
||||||
|
while (child != null) {
|
||||||
|
redepthChild(child);
|
||||||
|
child = child.nextSibling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adjust the [depth] of the given [child] to be greater than this node's own
|
||||||
|
/// [depth].
|
||||||
|
///
|
||||||
|
/// Only call this method from overrides of [redepthChildren].
|
||||||
|
@protected
|
||||||
|
void redepthChild(Layer child) {
|
||||||
|
assert(child.owner == owner);
|
||||||
|
if (child._depth <= _depth) {
|
||||||
|
child._depth = _depth + 1;
|
||||||
|
child.redepthChildren();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Implementation of [Layer.remove].
|
// Implementation of [Layer.remove].
|
||||||
void _removeChild(Layer child) {
|
void _removeChild(Layer child) {
|
||||||
assert(child.parent == this);
|
assert(child.parent == this);
|
||||||
@ -1235,11 +1322,27 @@ class ContainerLayer extends Layer {
|
|||||||
assert(lastChild == null || _debugUltimatePreviousSiblingOf(lastChild!, equals: firstChild));
|
assert(lastChild == null || _debugUltimatePreviousSiblingOf(lastChild!, equals: firstChild));
|
||||||
child._previousSibling = null;
|
child._previousSibling = null;
|
||||||
child._nextSibling = null;
|
child._nextSibling = null;
|
||||||
dropChild(child);
|
_dropChild(child);
|
||||||
child._parentHandle.layer = null;
|
child._parentHandle.layer = null;
|
||||||
assert(!child.attached);
|
assert(!child.attached);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _dropChild(Layer child) {
|
||||||
|
assert(!_debugMutationsLocked);
|
||||||
|
if (!alwaysNeedsAddToScene) {
|
||||||
|
markNeedsAddToScene();
|
||||||
|
}
|
||||||
|
if (child._compositionCallbackCount != 0) {
|
||||||
|
_updateSubtreeCompositionObserverCount(-child._compositionCallbackCount);
|
||||||
|
}
|
||||||
|
assert(child._parent == this);
|
||||||
|
assert(child.attached == attached);
|
||||||
|
child._parent = null;
|
||||||
|
if (attached) {
|
||||||
|
child.detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Removes all of this layer's children from its child list.
|
/// Removes all of this layer's children from its child list.
|
||||||
void removeAllChildren() {
|
void removeAllChildren() {
|
||||||
assert(!_debugMutationsLocked);
|
assert(!_debugMutationsLocked);
|
||||||
@ -1249,7 +1352,7 @@ class ContainerLayer extends Layer {
|
|||||||
child._previousSibling = null;
|
child._previousSibling = null;
|
||||||
child._nextSibling = null;
|
child._nextSibling = null;
|
||||||
assert(child.attached == attached);
|
assert(child.attached == attached);
|
||||||
dropChild(child);
|
_dropChild(child);
|
||||||
child._parentHandle.layer = null;
|
child._parentHandle.layer = null;
|
||||||
child = next;
|
child = next;
|
||||||
}
|
}
|
||||||
|
@ -1646,7 +1646,7 @@ void debugResetSemanticsIdCounter() {
|
|||||||
/// (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 with DiagnosticableTreeMixin {
|
class SemanticsNode 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
|
||||||
@ -1923,7 +1923,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
|||||||
if (child.parent == this) {
|
if (child.parent == this) {
|
||||||
// we might have already had our child stolen from us by
|
// we might have already had our child stolen from us by
|
||||||
// another node that is deeper in the tree.
|
// another node that is deeper in the tree.
|
||||||
dropChild(child);
|
_dropChild(child);
|
||||||
}
|
}
|
||||||
sawChange = true;
|
sawChange = true;
|
||||||
}
|
}
|
||||||
@ -1937,10 +1937,10 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
|||||||
// ancestors. In that case, we drop the child eagerly here.
|
// ancestors. In that case, we drop the child eagerly here.
|
||||||
// TODO(ianh): Find a way to assert that the same node didn't
|
// TODO(ianh): Find a way to assert that the same node didn't
|
||||||
// actually appear in the tree in two places.
|
// actually appear in the tree in two places.
|
||||||
child.parent?.dropChild(child);
|
child.parent?._dropChild(child);
|
||||||
}
|
}
|
||||||
assert(!child.attached);
|
assert(!child.attached);
|
||||||
adoptChild(child);
|
_adoptChild(child);
|
||||||
sawChange = true;
|
sawChange = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1998,22 +1998,73 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// AbstractNode OVERRIDES
|
/// The owner for this node (null if unattached).
|
||||||
|
///
|
||||||
|
/// The entire subtree that this node belongs to will have the same owner.
|
||||||
|
SemanticsOwner? get owner => _owner;
|
||||||
|
SemanticsOwner? _owner;
|
||||||
|
|
||||||
@override
|
/// Whether this node is in a tree whose root is attached to something.
|
||||||
SemanticsOwner? get owner => super.owner as SemanticsOwner?;
|
///
|
||||||
|
/// This becomes true during the call to [attach].
|
||||||
|
///
|
||||||
|
/// This becomes false during the call to [detach].
|
||||||
|
bool get attached => _owner != null;
|
||||||
|
|
||||||
@override
|
/// The parent of this node in the tree.
|
||||||
SemanticsNode? get parent => super.parent as SemanticsNode?;
|
SemanticsNode? get parent => _parent;
|
||||||
|
SemanticsNode? _parent;
|
||||||
|
|
||||||
@override
|
/// The depth of this node in the tree.
|
||||||
void redepthChildren() {
|
///
|
||||||
_children?.forEach(redepthChild);
|
/// The depth of nodes in a tree monotonically increases as you traverse down
|
||||||
|
/// the tree.
|
||||||
|
int get depth => _depth;
|
||||||
|
int _depth = 0;
|
||||||
|
|
||||||
|
void _redepthChild(SemanticsNode child) {
|
||||||
|
assert(child.owner == owner);
|
||||||
|
if (child._depth <= _depth) {
|
||||||
|
child._depth = _depth + 1;
|
||||||
|
child._redepthChildren();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
void _redepthChildren() {
|
||||||
|
_children?.forEach(_redepthChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _adoptChild(SemanticsNode child) {
|
||||||
|
assert(child._parent == null);
|
||||||
|
assert(() {
|
||||||
|
SemanticsNode node = this;
|
||||||
|
while (node.parent != null) {
|
||||||
|
node = node.parent!;
|
||||||
|
}
|
||||||
|
assert(node != child); // indicates we are about to create a cycle
|
||||||
|
return true;
|
||||||
|
}());
|
||||||
|
child._parent = this;
|
||||||
|
if (attached) {
|
||||||
|
child.attach(_owner!);
|
||||||
|
}
|
||||||
|
_redepthChild(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _dropChild(SemanticsNode child) {
|
||||||
|
assert(child._parent == this);
|
||||||
|
assert(child.attached == attached);
|
||||||
|
child._parent = null;
|
||||||
|
if (attached) {
|
||||||
|
child.detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mark this node as attached to the given owner.
|
||||||
|
@visibleForTesting
|
||||||
void attach(SemanticsOwner owner) {
|
void attach(SemanticsOwner owner) {
|
||||||
super.attach(owner);
|
assert(_owner == null);
|
||||||
|
_owner = owner;
|
||||||
while (owner._nodes.containsKey(id)) {
|
while (owner._nodes.containsKey(id)) {
|
||||||
// Ids may repeat if the Flutter has generated > 2^16 ids. We need to keep
|
// Ids may repeat if the Flutter has generated > 2^16 ids. We need to keep
|
||||||
// regenerating the id until we found an id that is not used.
|
// regenerating the id until we found an id that is not used.
|
||||||
@ -2032,14 +2083,16 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
/// Mark this node as detached.
|
||||||
|
@visibleForTesting
|
||||||
void detach() {
|
void detach() {
|
||||||
|
assert(_owner != null);
|
||||||
assert(owner!._nodes.containsKey(id));
|
assert(owner!._nodes.containsKey(id));
|
||||||
assert(!owner!._detachedNodes.contains(this));
|
assert(!owner!._detachedNodes.contains(this));
|
||||||
owner!._nodes.remove(id);
|
owner!._nodes.remove(id);
|
||||||
owner!._detachedNodes.add(this);
|
owner!._detachedNodes.add(this);
|
||||||
super.detach();
|
_owner = null;
|
||||||
assert(owner == null);
|
assert(parent == null || attached == parent!.attached);
|
||||||
if (_children != null) {
|
if (_children != null) {
|
||||||
for (final SemanticsNode child in _children!) {
|
for (final SemanticsNode child in _children!) {
|
||||||
// The list of children may be stale and may contain nodes that have
|
// The list of children may be stale and may contain nodes that have
|
||||||
|
@ -899,8 +899,7 @@ void main() {
|
|||||||
expect(() => layer.markNeedsAddToScene(), throwsAssertionError);
|
expect(() => layer.markNeedsAddToScene(), throwsAssertionError);
|
||||||
expect(() => layer.debugMarkClean(), throwsAssertionError);
|
expect(() => layer.debugMarkClean(), throwsAssertionError);
|
||||||
expect(() => layer.updateSubtreeNeedsAddToScene(), throwsAssertionError);
|
expect(() => layer.updateSubtreeNeedsAddToScene(), throwsAssertionError);
|
||||||
expect(() => layer.dropChild(ContainerLayer()), throwsAssertionError);
|
expect(() => layer.remove(), throwsAssertionError);
|
||||||
expect(() => layer.adoptChild(ContainerLayer()), throwsAssertionError);
|
|
||||||
expect(() => (layer as ContainerLayer).append(ContainerLayer()), throwsAssertionError);
|
expect(() => (layer as ContainerLayer).append(ContainerLayer()), throwsAssertionError);
|
||||||
expect(() => layer.engineLayer = null, throwsAssertionError);
|
expect(() => layer.engineLayer = null, throwsAssertionError);
|
||||||
compositedB1 = true;
|
compositedB1 = true;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user