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
|
||||
/// for painting [RenderObject] trees on the display.
|
||||
abstract class Layer extends AbstractNode with DiagnosticableTreeMixin {
|
||||
abstract class Layer with DiagnosticableTreeMixin {
|
||||
/// Creates an instance of Layer.
|
||||
Layer() {
|
||||
if (kFlutterMemoryAllocationsEnabled) {
|
||||
@ -344,8 +344,8 @@ abstract class Layer extends AbstractNode with DiagnosticableTreeMixin {
|
||||
///
|
||||
/// Only subclasses of [ContainerLayer] can have children in the layer tree.
|
||||
/// All other layer classes are used for leaves in the layer tree.
|
||||
@override
|
||||
ContainerLayer? get parent => super.parent as ContainerLayer?;
|
||||
ContainerLayer? get parent => _parent;
|
||||
ContainerLayer? _parent;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
/// 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.
|
||||
Layer? get nextSibling => _nextSibling;
|
||||
Layer? _nextSibling;
|
||||
@ -503,30 +568,6 @@ abstract class Layer extends AbstractNode with DiagnosticableTreeMixin {
|
||||
Layer? get previousSibling => _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.
|
||||
///
|
||||
/// 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
|
||||
return true;
|
||||
}());
|
||||
adoptChild(child);
|
||||
_adoptChild(child);
|
||||
child._previousSibling = lastChild;
|
||||
if (lastChild != null) {
|
||||
lastChild!._nextSibling = child;
|
||||
@ -1209,6 +1250,52 @@ class ContainerLayer extends Layer {
|
||||
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].
|
||||
void _removeChild(Layer child) {
|
||||
assert(child.parent == this);
|
||||
@ -1235,11 +1322,27 @@ class ContainerLayer extends Layer {
|
||||
assert(lastChild == null || _debugUltimatePreviousSiblingOf(lastChild!, equals: firstChild));
|
||||
child._previousSibling = null;
|
||||
child._nextSibling = null;
|
||||
dropChild(child);
|
||||
_dropChild(child);
|
||||
child._parentHandle.layer = null;
|
||||
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.
|
||||
void removeAllChildren() {
|
||||
assert(!_debugMutationsLocked);
|
||||
@ -1249,7 +1352,7 @@ class ContainerLayer extends Layer {
|
||||
child._previousSibling = null;
|
||||
child._nextSibling = null;
|
||||
assert(child.attached == attached);
|
||||
dropChild(child);
|
||||
_dropChild(child);
|
||||
child._parentHandle.layer = null;
|
||||
child = next;
|
||||
}
|
||||
|
@ -1646,7 +1646,7 @@ void debugResetSemanticsIdCounter() {
|
||||
/// (i.e., during [PipelineOwner.flushSemantics]), which happens after
|
||||
/// compositing. The semantics tree is then uploaded into the engine for use
|
||||
/// by assistive technology.
|
||||
class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
||||
class SemanticsNode with DiagnosticableTreeMixin {
|
||||
/// Creates a semantic 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) {
|
||||
// we might have already had our child stolen from us by
|
||||
// another node that is deeper in the tree.
|
||||
dropChild(child);
|
||||
_dropChild(child);
|
||||
}
|
||||
sawChange = true;
|
||||
}
|
||||
@ -1937,10 +1937,10 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
||||
// ancestors. In that case, we drop the child eagerly here.
|
||||
// TODO(ianh): Find a way to assert that the same node didn't
|
||||
// actually appear in the tree in two places.
|
||||
child.parent?.dropChild(child);
|
||||
child.parent?._dropChild(child);
|
||||
}
|
||||
assert(!child.attached);
|
||||
adoptChild(child);
|
||||
_adoptChild(child);
|
||||
sawChange = true;
|
||||
}
|
||||
}
|
||||
@ -1998,22 +1998,73 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
||||
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
|
||||
SemanticsOwner? get owner => super.owner as SemanticsOwner?;
|
||||
/// 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;
|
||||
|
||||
@override
|
||||
SemanticsNode? get parent => super.parent as SemanticsNode?;
|
||||
/// The parent of this node in the tree.
|
||||
SemanticsNode? get parent => _parent;
|
||||
SemanticsNode? _parent;
|
||||
|
||||
@override
|
||||
void redepthChildren() {
|
||||
_children?.forEach(redepthChild);
|
||||
/// 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;
|
||||
|
||||
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) {
|
||||
super.attach(owner);
|
||||
assert(_owner == null);
|
||||
_owner = owner;
|
||||
while (owner._nodes.containsKey(id)) {
|
||||
// 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.
|
||||
@ -2032,14 +2083,16 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
/// Mark this node as detached.
|
||||
@visibleForTesting
|
||||
void detach() {
|
||||
assert(_owner != null);
|
||||
assert(owner!._nodes.containsKey(id));
|
||||
assert(!owner!._detachedNodes.contains(this));
|
||||
owner!._nodes.remove(id);
|
||||
owner!._detachedNodes.add(this);
|
||||
super.detach();
|
||||
assert(owner == null);
|
||||
_owner = null;
|
||||
assert(parent == null || attached == parent!.attached);
|
||||
if (_children != null) {
|
||||
for (final SemanticsNode child in _children!) {
|
||||
// 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.debugMarkClean(), throwsAssertionError);
|
||||
expect(() => layer.updateSubtreeNeedsAddToScene(), throwsAssertionError);
|
||||
expect(() => layer.dropChild(ContainerLayer()), throwsAssertionError);
|
||||
expect(() => layer.adoptChild(ContainerLayer()), throwsAssertionError);
|
||||
expect(() => layer.remove(), throwsAssertionError);
|
||||
expect(() => (layer as ContainerLayer).append(ContainerLayer()), throwsAssertionError);
|
||||
expect(() => layer.engineLayer = null, throwsAssertionError);
|
||||
compositedB1 = true;
|
||||
|
Loading…
x
Reference in New Issue
Block a user