Unverified Commit 065c0fea authored by Michael Goderbauer's avatar Michael Goderbauer Committed by GitHub

Do not crash on LeaderLayer.applyTransform after retained rendering (#96144)

parent 02bf594f
...@@ -2234,7 +2234,7 @@ class LeaderLayer extends ContainerLayer { ...@@ -2234,7 +2234,7 @@ class LeaderLayer extends ContainerLayer {
void attach(Object owner) { void attach(Object owner) {
super.attach(owner); super.attach(owner);
assert(link._leader == null); assert(link._leader == null);
_lastOffset = null; assert(_debugSetLastOffset(null));
link._leader = this; link._leader = this;
} }
...@@ -2242,7 +2242,7 @@ class LeaderLayer extends ContainerLayer { ...@@ -2242,7 +2242,7 @@ class LeaderLayer extends ContainerLayer {
void detach() { void detach() {
assert(link._leader == this); assert(link._leader == this);
link._leader = null; link._leader = null;
_lastOffset = null; assert(_debugSetLastOffset(null));
super.detach(); super.detach();
} }
...@@ -2251,7 +2251,17 @@ class LeaderLayer extends ContainerLayer { ...@@ -2251,7 +2251,17 @@ class LeaderLayer extends ContainerLayer {
/// This is reset to null when the layer is attached or detached, to help /// This is reset to null when the layer is attached or detached, to help
/// catch cases where the follower layer ends up before the leader layer, but /// catch cases where the follower layer ends up before the leader layer, but
/// not every case can be detected. /// not every case can be detected.
Offset? _lastOffset; Offset? _debugLastOffset;
bool _debugSetLastOffset(Offset? offset) {
bool result = false;
assert(() {
_debugLastOffset = offset;
result = true;
return true;
}());
return result;
}
@override @override
bool findAnnotations<S extends Object>(AnnotationResult<S> result, Offset localPosition, { required bool onlyFirst }) { bool findAnnotations<S extends Object>(AnnotationResult<S> result, Offset localPosition, { required bool onlyFirst }) {
...@@ -2261,14 +2271,14 @@ class LeaderLayer extends ContainerLayer { ...@@ -2261,14 +2271,14 @@ class LeaderLayer extends ContainerLayer {
@override @override
void addToScene(ui.SceneBuilder builder) { void addToScene(ui.SceneBuilder builder) {
assert(offset != null); assert(offset != null);
_lastOffset = offset; assert(_debugSetLastOffset(offset));
if (_lastOffset != Offset.zero) if (offset != Offset.zero)
engineLayer = builder.pushTransform( engineLayer = builder.pushTransform(
Matrix4.translationValues(_lastOffset!.dx, _lastOffset!.dy, 0.0).storage, Matrix4.translationValues(offset.dx, offset.dy, 0.0).storage,
oldLayer: _engineLayer as ui.TransformEngineLayer?, oldLayer: _engineLayer as ui.TransformEngineLayer?,
); );
addChildrenToScene(builder); addChildrenToScene(builder);
if (_lastOffset != Offset.zero) if (offset != Offset.zero)
builder.pop(); builder.pop();
} }
...@@ -2281,9 +2291,8 @@ class LeaderLayer extends ContainerLayer { ...@@ -2281,9 +2291,8 @@ class LeaderLayer extends ContainerLayer {
/// children. /// children.
@override @override
void applyTransform(Layer? child, Matrix4 transform) { void applyTransform(Layer? child, Matrix4 transform) {
assert(_lastOffset != null); if (offset != Offset.zero)
if (_lastOffset != Offset.zero) transform.translate(offset.dx, offset.dy);
transform.translate(_lastOffset!.dx, _lastOffset!.dy);
} }
@override @override
...@@ -2499,7 +2508,7 @@ class FollowerLayer extends ContainerLayer { ...@@ -2499,7 +2508,7 @@ class FollowerLayer extends ContainerLayer {
'Linked LeaderLayer anchor is not in the same layer tree as the FollowerLayer.', 'Linked LeaderLayer anchor is not in the same layer tree as the FollowerLayer.',
); );
assert( assert(
leader._lastOffset != null, leader._debugLastOffset != null,
'LeaderLayer anchor must come before FollowerLayer in paint order, but the reverse was true.', 'LeaderLayer anchor must come before FollowerLayer in paint order, but the reverse was true.',
); );
......
...@@ -218,6 +218,36 @@ void main() { ...@@ -218,6 +218,36 @@ void main() {
expect(leaderLayer.debugSubtreeNeedsAddToScene, false); expect(leaderLayer.debugSubtreeNeedsAddToScene, false);
}); });
test('LeaderLayer.applyTransform can be called after retained rendering', () {
void expectTransform(RenderObject leader) {
final LeaderLayer leaderLayer = leader.debugLayer! as LeaderLayer;
final Matrix4 expected = Matrix4.identity()
..translate(leaderLayer.offset.dx, leaderLayer.offset.dy);
final Matrix4 transformed = Matrix4.identity();
leaderLayer.applyTransform(null, transformed);
expect(transformed, expected);
}
final LayerLink link = LayerLink();
late RenderLeaderLayer leader;
final RenderRepaintBoundary root = RenderRepaintBoundary(
child:RenderRepaintBoundary(
child: leader = RenderLeaderLayer(link: link),
),
);
layout(root, phase: EnginePhase.composite);
expectTransform(leader);
// Causes a repaint, but the LeaderLayer of RenderLeaderLayer will be added
// as retained and LeaderLayer.addChildrenToScene will not be called.
root.markNeedsPaint();
pumpFrame(phase: EnginePhase.composite);
// The LeaderLayer.applyTransform call shouldn't crash.
expectTransform(leader);
});
test('depthFirstIterateChildren', () { test('depthFirstIterateChildren', () {
final ContainerLayer a = ContainerLayer(); final ContainerLayer a = ContainerLayer();
final ContainerLayer b = ContainerLayer(); final ContainerLayer b = ContainerLayer();
......
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