Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
e17a1858
Unverified
Commit
e17a1858
authored
Jan 08, 2022
by
chunhtai
Committed by
GitHub
Jan 08, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
LayerLink can temporary allow multiple leaders (#95977)
parent
db5c71f4
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
200 additions
and
5 deletions
+200
-5
layer.dart
packages/flutter/lib/src/rendering/layer.dart
+56
-5
layers_test.dart
packages/flutter/test/rendering/layers_test.dart
+12
-0
object_test.dart
packages/flutter/test/rendering/object_test.dart
+103
-0
rendering_tester.dart
packages/flutter/test/rendering/rendering_tester.dart
+29
-0
No files found.
packages/flutter/lib/src/rendering/layer.dart
View file @
e17a1858
...
...
@@ -7,6 +7,7 @@ import 'dart:ui' as ui;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/gestures.dart'
;
import
'package:flutter/painting.dart'
;
import
'package:flutter/scheduler.dart'
;
import
'package:vector_math/vector_math_64.dart'
;
import
'debug.dart'
;
...
...
@@ -2110,6 +2111,55 @@ class PhysicalModelLayer extends ContainerLayer {
class
LayerLink
{
LeaderLayer
?
_leader
;
void
_registerLeader
(
LeaderLayer
leader
)
{
assert
(
_leader
!=
leader
);
assert
((){
if
(
_leader
!=
null
)
{
_debugPreviousLeaders
??=
<
LeaderLayer
>{};
_debugPreviousLeaders
!.
add
(
_leader
!);
_debugScheduleLeadersCleanUpCheck
();
}
return
true
;
}());
_leader
=
leader
;
}
void
_unregisterLeader
(
LeaderLayer
leader
)
{
assert
(
_leader
!=
null
);
if
(
_leader
==
leader
)
{
_leader
=
null
;
}
else
{
assert
((){
_debugPreviousLeaders
!.
remove
(
leader
);
return
true
;
}());
}
}
/// Stores the previous leaders that were replaced by the current [_leader]
/// in the current frame.
///
/// These leaders need to give up their leaderships of this link by the end of
/// the current frame.
Set
<
LeaderLayer
>?
_debugPreviousLeaders
;
bool
_debugLeaderCheckScheduled
=
false
;
/// Schedules the check as post frame callback to make sure the
/// [_debugPreviousLeaders] is empty.
void
_debugScheduleLeadersCleanUpCheck
()
{
assert
(
_debugPreviousLeaders
!=
null
);
assert
(()
{
if
(
_debugLeaderCheckScheduled
)
return
true
;
_debugLeaderCheckScheduled
=
true
;
SchedulerBinding
.
instance
!.
addPostFrameCallback
((
Duration
timeStamp
)
{
_debugLeaderCheckScheduled
=
false
;
assert
(
_debugPreviousLeaders
!.
isEmpty
);
});
return
true
;
}());
}
int
_connectedFollowers
=
0
;
/// Whether a [LeaderLayer] is currently connected to this link.
...
...
@@ -2202,7 +2252,10 @@ class LeaderLayer extends ContainerLayer {
if
(
_link
==
value
)
{
return
;
}
_link
.
_leader
=
null
;
if
(
attached
)
{
_link
.
_unregisterLeader
(
this
);
value
.
_registerLeader
(
this
);
}
_link
=
value
;
}
...
...
@@ -2233,16 +2286,14 @@ class LeaderLayer extends ContainerLayer {
@override
void
attach
(
Object
owner
)
{
super
.
attach
(
owner
);
assert
(
link
.
_leader
==
null
);
assert
(
_debugSetLastOffset
(
null
));
link
.
_leader
=
this
;
_link
.
_registerLeader
(
this
)
;
}
@override
void
detach
()
{
assert
(
link
.
_leader
==
this
);
link
.
_leader
=
null
;
assert
(
_debugSetLastOffset
(
null
));
_link
.
_unregisterLeader
(
this
);
super
.
detach
();
}
...
...
packages/flutter/test/rendering/layers_test.dart
View file @
e17a1858
...
...
@@ -164,6 +164,18 @@ void main() {
expect
(
followerLayer
.
debugSubtreeNeedsAddToScene
,
true
);
});
test
(
'switching layer link of an attached leader layer should not crash'
,
()
{
final
LayerLink
link
=
LayerLink
();
final
LeaderLayer
leaderLayer
=
LeaderLayer
(
link:
link
);
final
RenderView
view
=
RenderView
(
configuration:
const
ViewConfiguration
(),
window:
window
);
leaderLayer
.
attach
(
view
);
final
LayerLink
link2
=
LayerLink
();
leaderLayer
.
link
=
link2
;
// This should not crash.
leaderLayer
.
detach
();
expect
(
leaderLayer
.
link
,
link2
);
});
test
(
'leader layers are always dirty when connected to follower layer'
,
()
{
final
ContainerLayer
root
=
ContainerLayer
()..
attach
(
Object
());
...
...
packages/flutter/test/rendering/object_test.dart
View file @
e17a1858
...
...
@@ -153,6 +153,76 @@ void main() {
expect
(
renderObject
.
toStringShort
(),
contains
(
'DISPOSED'
));
});
test
(
'Leader layer can switch to a different render object within one frame'
,
()
{
List
<
FlutterErrorDetails
?>?
caughtErrors
;
renderer
.
onErrors
=
()
{
caughtErrors
=
renderer
.
takeAllFlutterErrorDetails
().
toList
();
};
final
LayerLink
layerLink
=
LayerLink
();
// renderObject1 paints the leader layer first.
final
LeaderLayerRenderObject
renderObject1
=
LeaderLayerRenderObject
();
renderObject1
.
layerLink
=
layerLink
;
renderObject1
.
attach
(
renderer
.
pipelineOwner
);
final
OffsetLayer
rootLayer1
=
OffsetLayer
();
rootLayer1
.
attach
(
renderObject1
);
renderObject1
.
scheduleInitialPaint
(
rootLayer1
);
renderObject1
.
layout
(
const
BoxConstraints
.
tightForFinite
());
final
LeaderLayerRenderObject
renderObject2
=
LeaderLayerRenderObject
();
final
OffsetLayer
rootLayer2
=
OffsetLayer
();
rootLayer2
.
attach
(
renderObject2
);
renderObject2
.
attach
(
renderer
.
pipelineOwner
);
renderObject2
.
scheduleInitialPaint
(
rootLayer2
);
renderObject2
.
layout
(
const
BoxConstraints
.
tightForFinite
());
renderer
.
pumpCompleteFrame
();
// Swap the layer link to renderObject2 in the same frame
renderObject1
.
layerLink
=
null
;
renderObject1
.
markNeedsPaint
();
renderObject2
.
layerLink
=
layerLink
;
renderObject2
.
markNeedsPaint
();
renderer
.
pumpCompleteFrame
();
// Swap the layer link to renderObject1 in the same frame
renderObject1
.
layerLink
=
layerLink
;
renderObject1
.
markNeedsPaint
();
renderObject2
.
layerLink
=
null
;
renderObject2
.
markNeedsPaint
();
renderer
.
pumpCompleteFrame
();
renderer
.
onErrors
=
null
;
expect
(
caughtErrors
,
isNull
);
});
test
(
'Leader layer append to two render objects does crash'
,
()
{
List
<
FlutterErrorDetails
?>?
caughtErrors
;
renderer
.
onErrors
=
()
{
caughtErrors
=
renderer
.
takeAllFlutterErrorDetails
().
toList
();
};
final
LayerLink
layerLink
=
LayerLink
();
// renderObject1 paints the leader layer first.
final
LeaderLayerRenderObject
renderObject1
=
LeaderLayerRenderObject
();
renderObject1
.
layerLink
=
layerLink
;
renderObject1
.
attach
(
renderer
.
pipelineOwner
);
final
OffsetLayer
rootLayer1
=
OffsetLayer
();
rootLayer1
.
attach
(
renderObject1
);
renderObject1
.
scheduleInitialPaint
(
rootLayer1
);
renderObject1
.
layout
(
const
BoxConstraints
.
tightForFinite
());
final
LeaderLayerRenderObject
renderObject2
=
LeaderLayerRenderObject
();
renderObject2
.
layerLink
=
layerLink
;
final
OffsetLayer
rootLayer2
=
OffsetLayer
();
rootLayer2
.
attach
(
renderObject2
);
renderObject2
.
attach
(
renderer
.
pipelineOwner
);
renderObject2
.
scheduleInitialPaint
(
rootLayer2
);
renderObject2
.
layout
(
const
BoxConstraints
.
tightForFinite
());
renderer
.
pumpCompleteFrame
();
renderer
.
onErrors
=
null
;
expect
(
caughtErrors
!.
isNotEmpty
,
isTrue
);
});
test
(
'RenderObject.dispose null the layer on repaint boundaries'
,
()
{
final
TestRenderObject
renderObject
=
TestRenderObject
(
allowPaintBounds:
true
);
// Force a layer to get set.
...
...
@@ -255,6 +325,39 @@ class TestRenderObject extends RenderObject {
}
}
class
LeaderLayerRenderObject
extends
RenderObject
{
LeaderLayerRenderObject
();
LayerLink
?
layerLink
;
@override
bool
isRepaintBoundary
=
true
;
@override
void
debugAssertDoesMeetConstraints
()
{
}
@override
Rect
get
paintBounds
{
return
Rect
.
zero
;
}
@override
void
paint
(
PaintingContext
context
,
Offset
offset
)
{
if
(
layerLink
!=
null
)
{
context
.
pushLayer
(
LeaderLayer
(
link:
layerLink
!),
super
.
paint
,
offset
);
}
}
@override
void
performLayout
()
{
}
@override
void
performResize
()
{
}
@override
Rect
get
semanticBounds
=>
const
Rect
.
fromLTWH
(
0.0
,
0.0
,
10.0
,
20.0
);
}
class
TestThrowingRenderObject
extends
RenderObject
{
@override
void
performLayout
()
{
...
...
packages/flutter/test/rendering/rendering_tester.dart
View file @
e17a1858
...
...
@@ -82,6 +82,35 @@ class TestRenderingFlutterBinding extends BindingBase with SchedulerBinding, Ser
EnginePhase
phase
=
EnginePhase
.
composite
;
/// Pumps a frame and runs its entire life cycle.
///
/// This method runs all of the [SchedulerPhase]s in a frame, this is useful
/// to test [SchedulerPhase.postFrameCallbacks].
void
pumpCompleteFrame
()
{
final
FlutterExceptionHandler
?
oldErrorHandler
=
FlutterError
.
onError
;
FlutterError
.
onError
=
(
FlutterErrorDetails
details
)
{
_errors
.
add
(
details
);
};
try
{
renderer
.
handleBeginFrame
(
null
);
renderer
.
handleDrawFrame
();
}
finally
{
FlutterError
.
onError
=
oldErrorHandler
;
if
(
_errors
.
isNotEmpty
)
{
if
(
onErrors
!=
null
)
{
onErrors
!();
if
(
_errors
.
isNotEmpty
)
{
_errors
.
forEach
(
FlutterError
.
dumpErrorToConsole
);
fail
(
'There are more errors than the test inspected using TestRenderingFlutterBinding.takeFlutterErrorDetails.'
);
}
}
else
{
_errors
.
forEach
(
FlutterError
.
dumpErrorToConsole
);
fail
(
'Caught error while rendering frame. See preceding logs for details.'
);
}
}
}
}
@override
void
drawFrame
()
{
assert
(
phase
!=
EnginePhase
.
build
,
'rendering_tester does not support testing the build phase; use flutter_test instead'
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment