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
883e2dc2
Unverified
Commit
883e2dc2
authored
Oct 25, 2018
by
liyuqian
Committed by
GitHub
Oct 25, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Maintain dirtiness and use retained engine layers (#23434)
For #21756
parent
628e8ec0
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
440 additions
and
73 deletions
+440
-73
layer.dart
packages/flutter/lib/src/rendering/layer.dart
+359
-64
object.dart
packages/flutter/lib/src/rendering/object.dart
+2
-1
view.dart
packages/flutter/lib/src/rendering/view.dart
+1
-2
widget_inspector.dart
packages/flutter/lib/src/widgets/widget_inspector.dart
+9
-6
layers_test.dart
packages/flutter/test/rendering/layers_test.dart
+69
-0
No files found.
packages/flutter/lib/src/rendering/layer.dart
View file @
883e2dc2
...
...
@@ -4,7 +4,7 @@
import
'dart:async'
;
import
'dart:collection'
;
import
'dart:ui'
as
ui
show
Image
,
ImageFilter
,
Picture
,
Scene
,
SceneBuilder
;
import
'dart:ui'
as
ui
show
EngineLayer
,
Image
,
ImageFilter
,
Picture
,
Scene
,
SceneBuilder
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/painting.dart'
;
...
...
@@ -41,6 +41,59 @@ abstract class Layer extends AbstractNode with DiagnosticableTreeMixin {
@override
ContainerLayer
get
parent
=>
super
.
parent
;
// Whether this layer has any changes since its last call to [addToScene].
//
// Initialized to true as a new layer has never called [addToScene].
bool
_needsAddToScene
=
true
;
/// Mark that this layer has changed and [addToScene] needs to be called.
@protected
void
markNeedsAddToScene
()
{
_needsAddToScene
=
true
;
}
/// Mark that this layer is in sync with engine.
///
/// This is only for debug and test purpose only.
@visibleForTesting
void
debugMarkClean
()
{
assert
((){
_needsAddToScene
=
false
;
return
true
;
}());
}
/// Subclasses may override this to true to disable retained rendering.
@protected
bool
get
alwaysNeedsAddToScene
=>
false
;
bool
_subtreeNeedsAddToScene
;
/// Whether any layer in the subtree needs [addToScene].
///
/// This is for debug and test purpose only. It only becomes valid after
/// calling [updateSubtreeNeedsAddToScene].
@visibleForTesting
bool
get
debugSubtreeNeedsAddToScene
{
bool
result
;
assert
((){
result
=
_subtreeNeedsAddToScene
;
return
true
;
}());
return
result
;
}
ui
.
EngineLayer
_engineLayer
;
/// Traverse the layer tree and compute if any subtree needs [addToScene].
///
/// A subtree needs [addToScene] if any of its layer needs [addToScene].
/// The [ContainerLayer] will override this to respect its children.
@protected
void
updateSubtreeNeedsAddToScene
()
{
_subtreeNeedsAddToScene
=
_needsAddToScene
||
alwaysNeedsAddToScene
;
}
/// This layer's next sibling in the parent layer's child list.
Layer
get
nextSibling
=>
_nextSibling
;
Layer
_nextSibling
;
...
...
@@ -49,6 +102,18 @@ abstract class Layer extends AbstractNode with DiagnosticableTreeMixin {
Layer
get
previousSibling
=>
_previousSibling
;
Layer
_previousSibling
;
@override
void
dropChild
(
AbstractNode
child
)
{
markNeedsAddToScene
();
super
.
dropChild
(
child
);
}
@override
void
adoptChild
(
AbstractNode
child
)
{
markNeedsAddToScene
();
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.
...
...
@@ -104,7 +169,29 @@ abstract class Layer extends AbstractNode with DiagnosticableTreeMixin {
S
find
<
S
>(
Offset
regionOffset
);
/// Override this method to upload this layer to the engine.
void
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
]);
///
/// Return the engine layer for retained rendering. When there's no
/// corresponding engine layer, null is returned.
@protected
ui
.
EngineLayer
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
]);
void
_addToSceneWithRetainedRendering
(
ui
.
SceneBuilder
builder
)
{
// There can't be a loop by adding a retained layer subtree whose
// _subtreeNeedsAddToScene is false.
//
// Proof by contradiction:
//
// If we introduce a loop, this retained layer must be appended to one of
// its descendent layers, say A. That means the child structure of A has
// changed so A's _needsAddToScene is true. This contradicts
// _subtreeNeedsAddToScene being false.
if
(!
_subtreeNeedsAddToScene
&&
_engineLayer
!=
null
)
{
builder
.
addRetained
(
_engineLayer
);
return
;
}
_engineLayer
=
addToScene
(
builder
);
_needsAddToScene
=
false
;
}
/// The object responsible for creating this layer.
///
...
...
@@ -144,7 +231,12 @@ class PictureLayer extends Layer {
///
/// The scene must be explicitly recomposited after this property is changed
/// (as described at [Layer]).
ui
.
Picture
picture
;
ui
.
Picture
get
picture
=>
_picture
;
ui
.
Picture
_picture
;
set
picture
(
ui
.
Picture
picture
)
{
_needsAddToScene
=
true
;
_picture
=
picture
;
}
/// Hints that the painting in this layer is complex and would benefit from
/// caching.
...
...
@@ -154,7 +246,14 @@ class PictureLayer extends Layer {
///
/// The scene must be explicitly recomposited after this property is changed
/// (as described at [Layer]).
bool
isComplexHint
=
false
;
bool
get
isComplexHint
=>
_isComplexHint
;
bool
_isComplexHint
=
false
;
set
isComplexHint
(
bool
value
)
{
if
(
value
!=
_isComplexHint
)
{
_isComplexHint
=
value
;
markNeedsAddToScene
();
}
}
/// Hints that the painting in this layer is likely to change next frame.
///
...
...
@@ -165,11 +264,19 @@ class PictureLayer extends Layer {
///
/// The scene must be explicitly recomposited after this property is changed
/// (as described at [Layer]).
bool
willChangeHint
=
false
;
bool
get
willChangeHint
=>
_willChangeHint
;
bool
_willChangeHint
=
false
;
set
willChangeHint
(
bool
value
)
{
if
(
value
!=
_willChangeHint
)
{
_willChangeHint
=
value
;
markNeedsAddToScene
();
}
}
@override
void
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
ui
.
EngineLayer
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
builder
.
addPicture
(
layerOffset
,
picture
,
isComplexHint:
isComplexHint
,
willChangeHint:
willChangeHint
);
return
null
;
// this does not return an engine layer yet.
}
@override
...
...
@@ -234,7 +341,7 @@ class TextureLayer extends Layer {
final
bool
freeze
;
@override
void
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
ui
.
EngineLayer
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
final
Rect
shiftedRect
=
rect
.
shift
(
layerOffset
);
builder
.
addTexture
(
textureId
,
...
...
@@ -243,6 +350,7 @@ class TextureLayer extends Layer {
height:
shiftedRect
.
height
,
freeze:
freeze
,
);
return
null
;
// this does not return an engine layer yet.
}
@override
...
...
@@ -256,18 +364,25 @@ class TextureLayer extends Layer {
class
PerformanceOverlayLayer
extends
Layer
{
/// Creates a layer that displays a performance overlay.
PerformanceOverlayLayer
({
@required
this
.
overlayRect
,
@required
Rect
overlayRect
,
@required
this
.
optionsMask
,
@required
this
.
rasterizerThreshold
,
@required
this
.
checkerboardRasterCacheImages
,
@required
this
.
checkerboardOffscreenLayers
,
});
})
:
_overlayRect
=
overlayRect
;
/// The rectangle in this layer's coordinate system that the overlay should occupy.
///
/// The scene must be explicitly recomposited after this property is changed
/// (as described at [Layer]).
Rect
overlayRect
;
Rect
get
overlayRect
=>
_overlayRect
;
Rect
_overlayRect
;
set
overlayRect
(
Rect
value
)
{
if
(
value
!=
_overlayRect
)
{
_overlayRect
=
value
;
markNeedsAddToScene
();
}
}
/// The mask is created by shifting 1 by the index of the specific
/// [PerformanceOverlayOption] to enable.
...
...
@@ -302,12 +417,13 @@ class PerformanceOverlayLayer extends Layer {
final
bool
checkerboardOffscreenLayers
;
@override
void
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
ui
.
EngineLayer
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
assert
(
optionsMask
!=
null
);
builder
.
addPerformanceOverlay
(
optionsMask
,
overlayRect
.
shift
(
layerOffset
));
builder
.
setRasterizerTracingThreshold
(
rasterizerThreshold
);
builder
.
setCheckerboardRasterCacheImages
(
checkerboardRasterCacheImages
);
builder
.
setCheckerboardOffscreenLayers
(
checkerboardOffscreenLayers
);
return
null
;
// this does not return an engine layer yet.
}
@override
...
...
@@ -348,6 +464,17 @@ class ContainerLayer extends Layer {
return
child
==
equals
;
}
@override
void
updateSubtreeNeedsAddToScene
()
{
super
.
updateSubtreeNeedsAddToScene
();
Layer
child
=
firstChild
;
while
(
child
!=
null
)
{
child
.
updateSubtreeNeedsAddToScene
();
_subtreeNeedsAddToScene
=
_subtreeNeedsAddToScene
||
child
.
_subtreeNeedsAddToScene
;
child
=
child
.
nextSibling
;
}
}
@override
S
find
<
S
>(
Offset
regionOffset
)
{
Layer
current
=
lastChild
;
...
...
@@ -451,8 +578,9 @@ class ContainerLayer extends Layer {
}
@override
void
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
ui
.
EngineLayer
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
addChildrenToScene
(
builder
,
layerOffset
);
return
null
;
// ContainerLayer does not have a corresponding engine layer
}
/// Uploads all of this layer's children to the engine.
...
...
@@ -465,7 +593,11 @@ class ContainerLayer extends Layer {
void
addChildrenToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
childOffset
=
Offset
.
zero
])
{
Layer
child
=
firstChild
;
while
(
child
!=
null
)
{
if
(
childOffset
==
Offset
.
zero
)
{
child
.
_addToSceneWithRetainedRendering
(
builder
);
}
else
{
child
.
addToScene
(
builder
,
childOffset
);
}
child
=
child
.
nextSibling
;
}
}
...
...
@@ -540,7 +672,7 @@ class OffsetLayer extends ContainerLayer {
///
/// By default, [offset] is zero. It must be non-null before the compositing
/// phase of the pipeline.
OffsetLayer
({
this
.
offset
=
Offset
.
zero
})
;
OffsetLayer
({
Offset
offset
=
Offset
.
zero
})
:
_offset
=
offset
;
/// Offset from parent in the parent's coordinate system.
///
...
...
@@ -549,7 +681,14 @@ class OffsetLayer extends ContainerLayer {
///
/// The [offset] property must be non-null before the compositing phase of the
/// pipeline.
Offset
offset
;
Offset
get
offset
=>
_offset
;
Offset
_offset
;
set
offset
(
Offset
value
)
{
if
(
value
!=
_offset
)
{
markNeedsAddToScene
();
}
_offset
=
value
;
}
@override
S
find
<
S
>(
Offset
regionOffset
)
{
...
...
@@ -563,16 +702,25 @@ class OffsetLayer extends ContainerLayer {
transform
.
multiply
(
Matrix4
.
translationValues
(
offset
.
dx
,
offset
.
dy
,
0.0
));
}
/// Consider this layer as the root and build a scene (a tree of layers)
/// in the engine.
ui
.
Scene
buildScene
(
ui
.
SceneBuilder
builder
)
{
updateSubtreeNeedsAddToScene
();
addToScene
(
builder
);
return
builder
.
build
();
}
@override
void
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
ui
.
EngineLayer
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
// Skia has a fast path for concatenating scale/translation only matrices.
// Hence pushing a translation-only transform layer should be fast. For
// retained rendering, we don't want to push the offset down to each leaf
// node. Otherwise, changing an offset layer on the very high level could
// cascade the change to too many leaves.
builder
.
pushOffset
(
layerOffset
.
dx
+
offset
.
dx
,
layerOffset
.
dy
+
offset
.
dy
);
final
ui
.
EngineLayer
engineLayer
=
builder
.
pushOffset
(
layerOffset
.
dx
+
offset
.
dx
,
layerOffset
.
dy
+
offset
.
dy
);
addChildrenToScene
(
builder
);
builder
.
pop
();
return
engineLayer
;
}
@override
...
...
@@ -608,8 +756,7 @@ class OffsetLayer extends ContainerLayer {
);
transform
.
scale
(
pixelRatio
,
pixelRatio
);
builder
.
pushTransform
(
transform
.
storage
);
addToScene
(
builder
);
final
ui
.
Scene
scene
=
builder
.
build
();
final
ui
.
Scene
scene
=
buildScene
(
builder
);
try
{
// Size is rounded up to the next pixel to make sure we don't clip off
// anything.
...
...
@@ -633,14 +780,22 @@ class ClipRectLayer extends ContainerLayer {
///
/// The [clipRect] property must be non-null before the compositing phase of
/// the pipeline.
ClipRectLayer
({
this
.
clipRect
,
Clip
clipBehavior
=
Clip
.
hardEdge
})
:
_clipBehavior
=
clipBehavior
,
assert
(
clipBehavior
!=
null
),
assert
(
clipBehavior
!=
Clip
.
none
);
ClipRectLayer
({
@required
Rect
clipRect
,
Clip
clipBehavior
=
Clip
.
hardEdge
})
:
_clipRect
=
clipRect
,
_clipBehavior
=
clipBehavior
,
assert
(
clipBehavior
!=
null
),
assert
(
clipBehavior
!=
Clip
.
none
);
/// The rectangle to clip in the parent's coordinate system.
///
/// The scene must be explicitly recomposited after this property is changed
/// (as described at [Layer]).
Rect
clipRect
;
Rect
get
clipRect
=>
_clipRect
;
Rect
_clipRect
;
set
clipRect
(
Rect
value
)
{
if
(
value
!=
_clipRect
)
{
_clipRect
=
value
;
markNeedsAddToScene
();
}
}
/// {@template flutter.clipper.clipBehavior}
/// Controls how to clip (default to [Clip.antiAlias]).
...
...
@@ -652,7 +807,10 @@ class ClipRectLayer extends ContainerLayer {
set
clipBehavior
(
Clip
value
)
{
assert
(
value
!=
null
);
assert
(
value
!=
Clip
.
none
);
if
(
value
!=
_clipBehavior
)
{
_clipBehavior
=
value
;
markNeedsAddToScene
();
}
}
@override
...
...
@@ -663,7 +821,7 @@ class ClipRectLayer extends ContainerLayer {
}
@override
void
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
ui
.
EngineLayer
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
bool
enabled
=
true
;
assert
(()
{
enabled
=
!
debugDisableClipLayers
;
...
...
@@ -674,6 +832,7 @@ class ClipRectLayer extends ContainerLayer {
addChildrenToScene
(
builder
,
layerOffset
);
if
(
enabled
)
builder
.
pop
();
return
null
;
// this does not return an engine layer yet.
}
@override
...
...
@@ -693,14 +852,22 @@ class ClipRRectLayer extends ContainerLayer {
///
/// The [clipRRect] property must be non-null before the compositing phase of
/// the pipeline.
ClipRRectLayer
({
this
.
clipRRect
,
Clip
clipBehavior
=
Clip
.
antiAlias
})
:
_clipBehavior
=
clipBehavior
,
assert
(
clipBehavior
!=
null
),
assert
(
clipBehavior
!=
Clip
.
none
);
ClipRRectLayer
({
@required
RRect
clipRRect
,
Clip
clipBehavior
=
Clip
.
antiAlias
})
:
_clipRRect
=
clipRRect
,
_clipBehavior
=
clipBehavior
,
assert
(
clipBehavior
!=
null
),
assert
(
clipBehavior
!=
Clip
.
none
);
/// The rounded-rect to clip in the parent's coordinate system.
///
/// The scene must be explicitly recomposited after this property is changed
/// (as described at [Layer]).
RRect
clipRRect
;
RRect
get
clipRRect
=>
_clipRRect
;
RRect
_clipRRect
;
set
clipRRect
(
RRect
value
)
{
if
(
value
!=
_clipRRect
)
{
_clipRRect
=
value
;
markNeedsAddToScene
();
}
}
/// {@macro flutter.clipper.clipBehavior}
Clip
get
clipBehavior
=>
_clipBehavior
;
...
...
@@ -708,7 +875,10 @@ class ClipRRectLayer extends ContainerLayer {
set
clipBehavior
(
Clip
value
)
{
assert
(
value
!=
null
);
assert
(
value
!=
Clip
.
none
);
if
(
value
!=
_clipBehavior
)
{
_clipBehavior
=
value
;
markNeedsAddToScene
();
}
}
@override
...
...
@@ -719,7 +889,7 @@ class ClipRRectLayer extends ContainerLayer {
}
@override
void
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
ui
.
EngineLayer
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
bool
enabled
=
true
;
assert
(()
{
enabled
=
!
debugDisableClipLayers
;
...
...
@@ -730,6 +900,7 @@ class ClipRRectLayer extends ContainerLayer {
addChildrenToScene
(
builder
,
layerOffset
);
if
(
enabled
)
builder
.
pop
();
return
null
;
// this does not return an engine layer yet.
}
@override
...
...
@@ -749,14 +920,22 @@ class ClipPathLayer extends ContainerLayer {
///
/// The [clipPath] property must be non-null before the compositing phase of
/// the pipeline.
ClipPathLayer
({
this
.
clipPath
,
Clip
clipBehavior
=
Clip
.
antiAlias
})
:
_clipBehavior
=
clipBehavior
,
assert
(
clipBehavior
!=
null
),
assert
(
clipBehavior
!=
Clip
.
none
);
ClipPathLayer
({
@required
Path
clipPath
,
Clip
clipBehavior
=
Clip
.
antiAlias
})
:
_clipPath
=
clipPath
,
_clipBehavior
=
clipBehavior
,
assert
(
clipBehavior
!=
null
),
assert
(
clipBehavior
!=
Clip
.
none
);
/// The path to clip in the parent's coordinate system.
///
/// The scene must be explicitly recomposited after this property is changed
/// (as described at [Layer]).
Path
clipPath
;
Path
get
clipPath
=>
_clipPath
;
Path
_clipPath
;
set
clipPath
(
Path
value
)
{
if
(
value
!=
_clipPath
)
{
_clipPath
=
value
;
markNeedsAddToScene
();
}
}
/// {@macro flutter.clipper.clipBehavior}
Clip
get
clipBehavior
=>
_clipBehavior
;
...
...
@@ -764,7 +943,10 @@ class ClipPathLayer extends ContainerLayer {
set
clipBehavior
(
Clip
value
)
{
assert
(
value
!=
null
);
assert
(
value
!=
Clip
.
none
);
if
(
value
!=
_clipBehavior
)
{
_clipBehavior
=
value
;
markNeedsAddToScene
();
}
}
@override
...
...
@@ -775,7 +957,7 @@ class ClipPathLayer extends ContainerLayer {
}
@override
void
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
ui
.
EngineLayer
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
bool
enabled
=
true
;
assert
(()
{
enabled
=
!
debugDisableClipLayers
;
...
...
@@ -786,6 +968,7 @@ class ClipPathLayer extends ContainerLayer {
addChildrenToScene
(
builder
,
layerOffset
);
if
(
enabled
)
builder
.
pop
();
return
null
;
// this does not return an engine layer yet.
}
}
...
...
@@ -826,7 +1009,7 @@ class TransformLayer extends OffsetLayer {
bool
_inverseDirty
=
true
;
@override
void
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
ui
.
EngineLayer
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
_lastEffectiveTransform
=
transform
;
final
Offset
totalOffset
=
offset
+
layerOffset
;
if
(
totalOffset
!=
Offset
.
zero
)
{
...
...
@@ -836,6 +1019,7 @@ class TransformLayer extends OffsetLayer {
builder
.
pushTransform
(
_lastEffectiveTransform
.
storage
);
addChildrenToScene
(
builder
);
builder
.
pop
();
return
null
;
// this does not return an engine layer yet.
}
@override
...
...
@@ -875,7 +1059,8 @@ class OpacityLayer extends ContainerLayer {
///
/// The [alpha] property must be non-null before the compositing phase of
/// the pipeline.
OpacityLayer
({
this
.
alpha
});
OpacityLayer
({
@required
int
alpha
,
Offset
offset
=
Offset
.
zero
})
:
_alpha
=
alpha
,
_offset
=
offset
;
/// The amount to multiply into the alpha channel.
///
...
...
@@ -884,20 +1069,38 @@ class OpacityLayer extends ContainerLayer {
///
/// The scene must be explicitly recomposited after this property is changed
/// (as described at [Layer]).
int
alpha
;
int
get
alpha
=>
_alpha
;
int
_alpha
;
set
alpha
(
int
value
)
{
if
(
value
!=
_alpha
)
{
_alpha
=
value
;
markNeedsAddToScene
();
}
}
/// Offset from parent in the parent's coordinate system.
Offset
get
offset
=>
_offset
;
Offset
_offset
;
set
offset
(
Offset
value
)
{
if
(
value
!=
_offset
)
{
_offset
=
value
;
markNeedsAddToScene
();
}
}
@override
void
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
ui
.
EngineLayer
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
bool
enabled
=
true
;
assert
(()
{
enabled
=
!
debugDisableOpacityLayers
;
return
true
;
}());
if
(
enabled
)
builder
.
pushOpacity
(
alpha
);
addChildrenToScene
(
builder
,
layerOffset
);
builder
.
pushOpacity
(
alpha
,
offset:
offset
+
layerOffset
);
addChildrenToScene
(
builder
);
if
(
enabled
)
builder
.
pop
();
return
null
;
// this does not return an engine layer yet.
}
@override
...
...
@@ -913,31 +1116,54 @@ class ShaderMaskLayer extends ContainerLayer {
///
/// The [shader], [maskRect], and [blendMode] properties must be non-null
/// before the compositing phase of the pipeline.
ShaderMaskLayer
({
this
.
shader
,
this
.
maskRect
,
this
.
blendMode
});
ShaderMaskLayer
({
@required
Shader
shader
,
@required
Rect
maskRect
,
@required
BlendMode
blendMode
})
:
_shader
=
shader
,
_maskRect
=
maskRect
,
_blendMode
=
blendMode
;
/// The shader to apply to the children.
///
/// The scene must be explicitly recomposited after this property is changed
/// (as described at [Layer]).
Shader
shader
;
Shader
get
shader
=>
_shader
;
Shader
_shader
;
set
shader
(
Shader
value
)
{
if
(
value
!=
_shader
)
{
_shader
=
value
;
markNeedsAddToScene
();
}
}
/// The size of the shader.
///
/// The scene must be explicitly recomposited after this property is changed
/// (as described at [Layer]).
Rect
maskRect
;
Rect
get
maskRect
=>
_maskRect
;
Rect
_maskRect
;
set
maskRect
(
Rect
value
)
{
if
(
value
!=
_maskRect
)
{
_maskRect
=
value
;
markNeedsAddToScene
();
}
}
/// The blend mode to apply when blending the shader with the children.
///
/// The scene must be explicitly recomposited after this property is changed
/// (as described at [Layer]).
BlendMode
blendMode
;
BlendMode
get
blendMode
=>
_blendMode
;
BlendMode
_blendMode
;
set
blendMode
(
BlendMode
value
)
{
if
(
value
!=
_blendMode
)
{
_blendMode
=
value
;
markNeedsAddToScene
();
}
}
@override
void
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
ui
.
EngineLayer
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
builder
.
pushShaderMask
(
shader
,
maskRect
.
shift
(
layerOffset
),
blendMode
);
addChildrenToScene
(
builder
,
layerOffset
);
builder
.
pop
();
return
null
;
// this does not return an engine layer yet.
}
@override
...
...
@@ -955,19 +1181,27 @@ class BackdropFilterLayer extends ContainerLayer {
///
/// The [filter] property must be non-null before the compositing phase of the
/// pipeline.
BackdropFilterLayer
({
this
.
filter
})
;
BackdropFilterLayer
({
@required
ui
.
ImageFilter
filter
})
:
_filter
=
filter
;
/// The filter to apply to the existing contents of the scene.
///
/// The scene must be explicitly recomposited after this property is changed
/// (as described at [Layer]).
ui
.
ImageFilter
filter
;
ui
.
ImageFilter
get
filter
=>
_filter
;
ui
.
ImageFilter
_filter
;
set
filter
(
ui
.
ImageFilter
value
)
{
if
(
value
!=
_filter
)
{
_filter
=
value
;
markNeedsAddToScene
();
}
}
@override
void
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
ui
.
EngineLayer
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
builder
.
pushBackdropFilter
(
filter
);
addChildrenToScene
(
builder
,
layerOffset
);
builder
.
pop
();
return
null
;
// this does not return an engine layer yet.
}
}
...
...
@@ -986,25 +1220,44 @@ class PhysicalModelLayer extends ContainerLayer {
///
/// The [clipPath], [elevation], and [color] arguments must not be null.
PhysicalModelLayer
({
@required
this
.
clipPath
,
this
.
clipBehavior
=
Clip
.
none
,
@required
this
.
elevation
,
@required
this
.
color
,
@required
this
.
shadowColor
,
@required
Path
clipPath
,
Clip
clipBehavior
=
Clip
.
none
,
@required
double
elevation
,
@required
Color
color
,
@required
Color
shadowColor
,
})
:
assert
(
clipPath
!=
null
),
assert
(
clipBehavior
!=
null
),
assert
(
elevation
!=
null
),
assert
(
color
!=
null
),
assert
(
shadowColor
!=
null
);
assert
(
shadowColor
!=
null
),
_clipPath
=
clipPath
,
_clipBehavior
=
clipBehavior
,
_elevation
=
elevation
,
_color
=
color
,
_shadowColor
=
shadowColor
;
/// The path to clip in the parent's coordinate system.
///
/// The scene must be explicitly recomposited after this property is changed
/// (as described at [Layer]).
Path
clipPath
;
Path
get
clipPath
=>
_clipPath
;
Path
_clipPath
;
set
clipPath
(
Path
value
)
{
if
(
value
!=
_clipPath
)
{
_clipPath
=
value
;
markNeedsAddToScene
();
}
}
/// {@macro flutter.widgets.Clip}
Clip
clipBehavior
;
Clip
get
clipBehavior
=>
_clipBehavior
;
Clip
_clipBehavior
;
set
clipBehavior
(
Clip
value
)
{
if
(
value
!=
_clipBehavior
)
{
_clipBehavior
=
value
;
markNeedsAddToScene
();
}
}
/// The z-coordinate at which to place this physical object.
///
...
...
@@ -1016,16 +1269,37 @@ class PhysicalModelLayer extends ContainerLayer {
/// flag is set. For this reason, this property will often be set to zero in
/// tests even if the layer should be raised. To verify the actual value,
/// consider setting [debugDisableShadows] to false in your test.
double
elevation
;
double
get
elevation
=>
_elevation
;
double
_elevation
;
set
elevation
(
double
value
)
{
if
(
value
!=
_elevation
)
{
_elevation
=
value
;
markNeedsAddToScene
();
}
}
/// The background color.
///
/// The scene must be explicitly recomposited after this property is changed
/// (as described at [Layer]).
Color
color
;
Color
get
color
=>
_color
;
Color
_color
;
set
color
(
Color
value
)
{
if
(
value
!=
_color
)
{
_color
=
value
;
markNeedsAddToScene
();
}
}
/// The shadow color.
Color
shadowColor
;
Color
get
shadowColor
=>
_shadowColor
;
Color
_shadowColor
;
set
shadowColor
(
Color
value
)
{
if
(
value
!=
_shadowColor
)
{
_shadowColor
=
value
;
markNeedsAddToScene
();
}
}
@override
S
find
<
S
>(
Offset
regionOffset
)
{
...
...
@@ -1035,14 +1309,15 @@ class PhysicalModelLayer extends ContainerLayer {
}
@override
void
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
ui
.
EngineLayer
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
ui
.
EngineLayer
engineLayer
;
bool
enabled
=
true
;
assert
(()
{
enabled
=
!
debugDisablePhysicalShapeLayers
;
return
true
;
}());
if
(
enabled
)
{
builder
.
pushPhysicalShape
(
engineLayer
=
builder
.
pushPhysicalShape
(
path:
clipPath
.
shift
(
layerOffset
),
elevation:
elevation
,
color:
color
,
...
...
@@ -1053,6 +1328,7 @@ class PhysicalModelLayer extends ContainerLayer {
addChildrenToScene
(
builder
,
layerOffset
);
if
(
enabled
)
builder
.
pop
();
return
engineLayer
;
}
@override
...
...
@@ -1115,6 +1391,10 @@ class LeaderLayer extends ContainerLayer {
/// pipeline.
Offset
offset
;
/// {@macro flutter.leaderFollower.alwaysNeedsAddToScene}
@override
bool
get
alwaysNeedsAddToScene
=>
true
;
@override
void
attach
(
Object
owner
)
{
super
.
attach
(
owner
);
...
...
@@ -1144,7 +1424,7 @@ class LeaderLayer extends ContainerLayer {
}
@override
void
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
ui
.
EngineLayer
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
assert
(
offset
!=
null
);
_lastOffset
=
offset
+
layerOffset
;
if
(
_lastOffset
!=
Offset
.
zero
)
...
...
@@ -1152,6 +1432,7 @@ class LeaderLayer extends ContainerLayer {
addChildrenToScene
(
builder
);
if
(
_lastOffset
!=
Offset
.
zero
)
builder
.
pop
();
return
null
;
// this does not have an engine layer.
}
/// Applies the transform that would be applied when compositing the given
...
...
@@ -1347,15 +1628,28 @@ class FollowerLayer extends ContainerLayer {
_inverseDirty
=
true
;
}
/// {@template flutter.leaderFollower.alwaysNeedsAddToScene}
/// This disables retained rendering for Leader/FollowerLayer.
///
/// A FollowerLayer copies changes from a LeaderLayer that could be anywhere
/// in the Layer tree, and that LeaderLayer could change without notifying the
/// FollowerLayer. Therefore we have to always call a FollowerLayer's
/// [addToScene]. In order to call FollowerLayer's [addToScene], LeaderLayer's
/// [addToScene] must be called first so LeaderLayer must also be considered
/// as [alwaysNeedsAddToScene].
/// {@endtemplate}
@override
bool
get
alwaysNeedsAddToScene
=>
true
;
@override
void
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
ui
.
EngineLayer
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
assert
(
link
!=
null
);
assert
(
showWhenUnlinked
!=
null
);
if
(
link
.
leader
==
null
&&
!
showWhenUnlinked
)
{
_lastTransform
=
null
;
_lastOffset
=
null
;
_inverseDirty
=
true
;
return
;
return
null
;
// this does not have an engine layer.
}
_establishTransform
();
if
(
_lastTransform
!=
null
)
{
...
...
@@ -1371,6 +1665,7 @@ class FollowerLayer extends ContainerLayer {
builder
.
pop
();
}
_inverseDirty
=
true
;
return
null
;
// this does not have an engine layer.
}
@override
...
...
packages/flutter/lib/src/rendering/object.dart
View file @
883e2dc2
...
...
@@ -198,6 +198,7 @@ class PaintingContext extends ClipContext {
return
true
;
}());
}
assert
(
child
.
_layer
!=
null
);
child
.
_layer
.
offset
=
offset
;
appendLayer
(
child
.
_layer
);
}
...
...
@@ -488,7 +489,7 @@ class PaintingContext extends ClipContext {
/// ancestor render objects that this render object will include a composited
/// layer, which, for example, causes them to use composited clips.
void
pushOpacity
(
Offset
offset
,
int
alpha
,
PaintingContextCallback
painter
)
{
pushLayer
(
OpacityLayer
(
alpha:
alpha
),
painter
,
offset
);
pushLayer
(
OpacityLayer
(
alpha:
alpha
,
offset:
offset
),
painter
,
Offset
.
zero
);
}
@override
...
...
packages/flutter/lib/src/rendering/view.dart
View file @
883e2dc2
...
...
@@ -192,8 +192,7 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
Timeline
.
startSync
(
'Compositing'
,
arguments:
timelineWhitelistArguments
);
try
{
final
ui
.
SceneBuilder
builder
=
ui
.
SceneBuilder
();
layer
.
addToScene
(
builder
);
final
ui
.
Scene
scene
=
builder
.
build
();
final
ui
.
Scene
scene
=
layer
.
buildScene
(
builder
);
if
(
automaticSystemUiAdjustment
)
_updateSystemChrome
();
ui
.
window
.
render
(
scene
);
...
...
packages/flutter/lib/src/widgets/widget_inspector.dart
View file @
883e2dc2
...
...
@@ -12,6 +12,7 @@ import 'dart:ui' as ui
show
window
,
ClipOp
,
EngineLayer
,
Image
,
ImageByteFormat
,
Paragraph
,
...
...
@@ -54,8 +55,8 @@ class _ProxyLayer extends Layer {
final
Layer
_layer
;
@override
void
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
_layer
.
addToScene
(
builder
,
layerOffset
);
ui
.
EngineLayer
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
return
_layer
.
addToScene
(
builder
,
layerOffset
);
}
@override
...
...
@@ -312,8 +313,9 @@ Rect _calculateSubtreeBounds(RenderObject object) {
/// screenshots render to the scene in the local coordinate system of the layer.
class
_ScreenshotContainerLayer
extends
OffsetLayer
{
@override
void
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
ui
.
EngineLayer
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
addChildrenToScene
(
builder
,
layerOffset
);
return
null
;
// this does not have an engine layer.
}
}
...
...
@@ -588,7 +590,7 @@ class _ScreenshotPaintingContext extends PaintingContext {
// We must build the regular scene before we can build the screenshot
// scene as building the screenshot scene assumes addToScene has already
// been called successfully for all layers in the regular scene.
repaintBoundary
.
layer
.
addTo
Scene
(
ui
.
SceneBuilder
());
repaintBoundary
.
layer
.
build
Scene
(
ui
.
SceneBuilder
());
return
data
.
containerLayer
.
toImage
(
renderBounds
,
pixelRatio:
pixelRatio
);
}
...
...
@@ -2226,9 +2228,9 @@ class _InspectorOverlayLayer extends Layer {
double
_textPainterMaxWidth
;
@override
void
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
ui
.
EngineLayer
addToScene
(
ui
.
SceneBuilder
builder
,
[
Offset
layerOffset
=
Offset
.
zero
])
{
if
(!
selection
.
active
)
return
;
return
null
;
final
RenderObject
selected
=
selection
.
current
;
final
List
<
_TransformedRect
>
candidates
=
<
_TransformedRect
>[];
...
...
@@ -2251,6 +2253,7 @@ class _InspectorOverlayLayer extends Layer {
_picture
=
_buildPicture
(
state
);
}
builder
.
addPicture
(
layerOffset
,
_picture
);
return
null
;
// this does not have an engine layer.
}
ui
.
Picture
_buildPicture
(
_InspectorOverlayRenderState
state
)
{
...
...
packages/flutter/test/rendering/layers_test.dart
View file @
883e2dc2
...
...
@@ -40,4 +40,73 @@ void main() {
expect
(
boundary
.
layer
,
isNotNull
);
expect
(
boundary
.
layer
.
attached
,
isTrue
);
// this time it did again!
});
test
(
'layer subtree dirtiness is correctly computed'
,
()
{
final
ContainerLayer
a
=
ContainerLayer
();
final
ContainerLayer
b
=
ContainerLayer
();
final
ContainerLayer
c
=
ContainerLayer
();
final
ContainerLayer
d
=
ContainerLayer
();
final
ContainerLayer
e
=
ContainerLayer
();
final
ContainerLayer
f
=
ContainerLayer
();
final
ContainerLayer
g
=
ContainerLayer
();
final
PictureLayer
h
=
PictureLayer
(
Rect
.
zero
);
final
PictureLayer
i
=
PictureLayer
(
Rect
.
zero
);
final
PictureLayer
j
=
PictureLayer
(
Rect
.
zero
);
// The tree is like the following where b and j are dirty:
// a____
// / \
// (x)b___ c
// / \ \ |
// d e f g
// / \ |
// h i j(x)
a
.
append
(
b
);
a
.
append
(
c
);
b
.
append
(
d
);
b
.
append
(
e
);
b
.
append
(
f
);
d
.
append
(
h
);
d
.
append
(
i
);
c
.
append
(
g
);
g
.
append
(
j
);
a
.
debugMarkClean
();
b
.
markNeedsAddToScene
();
// ignore: invalid_use_of_protected_member
c
.
debugMarkClean
();
d
.
debugMarkClean
();
e
.
debugMarkClean
();
f
.
debugMarkClean
();
g
.
debugMarkClean
();
h
.
debugMarkClean
();
i
.
debugMarkClean
();
j
.
markNeedsAddToScene
();
// ignore: invalid_use_of_protected_member
a
.
updateSubtreeNeedsAddToScene
();
expect
(
a
.
debugSubtreeNeedsAddToScene
,
true
);
expect
(
b
.
debugSubtreeNeedsAddToScene
,
true
);
expect
(
c
.
debugSubtreeNeedsAddToScene
,
true
);
expect
(
g
.
debugSubtreeNeedsAddToScene
,
true
);
expect
(
j
.
debugSubtreeNeedsAddToScene
,
true
);
expect
(
d
.
debugSubtreeNeedsAddToScene
,
false
);
expect
(
e
.
debugSubtreeNeedsAddToScene
,
false
);
expect
(
f
.
debugSubtreeNeedsAddToScene
,
false
);
expect
(
h
.
debugSubtreeNeedsAddToScene
,
false
);
expect
(
i
.
debugSubtreeNeedsAddToScene
,
false
);
});
test
(
'leader and follower layers are always dirty'
,
()
{
final
LayerLink
link
=
LayerLink
();
final
LeaderLayer
leaderLayer
=
LeaderLayer
(
link:
link
);
final
FollowerLayer
followerLayer
=
FollowerLayer
(
link:
link
);
leaderLayer
.
debugMarkClean
();
followerLayer
.
debugMarkClean
();
leaderLayer
.
updateSubtreeNeedsAddToScene
();
followerLayer
.
updateSubtreeNeedsAddToScene
();
expect
(
leaderLayer
.
debugSubtreeNeedsAddToScene
,
true
);
expect
(
followerLayer
.
debugSubtreeNeedsAddToScene
,
true
);
});
}
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