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
bb5a82a7
Commit
bb5a82a7
authored
Mar 18, 2016
by
Kris Giesing
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Allow independent rendering pipelines
Fixes #2723
parent
e074af80
Changes
18
Show whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
274 additions
and
168 deletions
+274
-168
layout_bench.dart
packages/flutter/benchmark/stocks/layout_bench.dart
+1
-1
README.md
packages/flutter/lib/src/rendering/README.md
+2
-2
binding.dart
packages/flutter/lib/src/rendering/binding.dart
+9
-5
block.dart
packages/flutter/lib/src/rendering/block.dart
+2
-2
box.dart
packages/flutter/lib/src/rendering/box.dart
+3
-8
child_view.dart
packages/flutter/lib/src/rendering/child_view.dart
+2
-2
node.dart
packages/flutter/lib/src/rendering/node.dart
+14
-8
object.dart
packages/flutter/lib/src/rendering/object.dart
+129
-118
proxy_box.dart
packages/flutter/lib/src/rendering/proxy_box.dart
+2
-2
semantics.dart
packages/flutter/lib/src/rendering/semantics.dart
+7
-6
view.dart
packages/flutter/lib/src/rendering/view.dart
+1
-1
viewport.dart
packages/flutter/lib/src/rendering/viewport.dart
+2
-2
gesture_detector.dart
packages/flutter/lib/src/widgets/gesture_detector.dart
+5
-1
independent_layout_test.dart
packages/flutter/test/rendering/independent_layout_test.dart
+84
-0
rendering_tester.dart
packages/flutter/test/rendering/rendering_tester.dart
+4
-4
sprite_box.dart
packages/flutter_sprites/lib/src/sprite_box.dart
+2
-2
widget_tester.dart
packages/flutter_test/lib/src/widget_tester.dart
+4
-4
analyze.dart
packages/flutter_tools/lib/src/commands/analyze.dart
+1
-0
No files found.
packages/flutter/benchmark/stocks/layout_bench.dart
View file @
bb5a82a7
...
...
@@ -31,7 +31,7 @@ void main() {
for
(
int
i
=
0
;
i
<
_kNumberOfIterations
||
_kRunForever
;
++
i
)
{
renderView
.
configuration
=
(
i
%
2
==
0
)
?
big
:
small
;
RenderObject
.
flushLayout
();
WidgetFlutterBinding
.
instance
.
pipelineOwner
.
flushLayout
();
}
watch
.
stop
();
...
...
packages/flutter/lib/src/rendering/README.md
View file @
bb5a82a7
...
...
@@ -20,8 +20,8 @@ The last phase of a frame is the Semantics phase. This only occurs if
a semantics server has been installed, for example if the user is
using an accessibility tool.
Each frame, the semantics phase starts with a call to the
static
`
RenderObject
.flushSemantics()`
method from the
`Renderer`
binding's
Each frame, the semantics phase starts with a call to the
`
PipelineOwner
.flushSemantics()`
method from the
`Renderer`
binding's
`beginFrame()`
method.
Each node marked as needing semantics (which initially is just the
...
...
packages/flutter/lib/src/rendering/binding.dart
View file @
bb5a82a7
...
...
@@ -48,6 +48,10 @@ abstract class Renderer extends Object with Scheduler, Services
handleMetricsChanged
();
// configures renderView's metrics
}
/// The render tree's owner, which maintains dirty state for layout,
/// composite, paint, and accessibility semantics
final
PipelineOwner
pipelineOwner
=
new
PipelineOwner
();
/// The render tree that's attached to the output surface.
RenderView
get
renderView
=>
_renderView
;
RenderView
_renderView
;
...
...
@@ -58,7 +62,7 @@ abstract class Renderer extends Object with Scheduler, Services
if
(
_renderView
!=
null
)
_renderView
.
detach
();
_renderView
=
value
;
_renderView
.
attach
();
_renderView
.
attach
(
pipelineOwner
);
}
void
handleMetricsChanged
()
{
...
...
@@ -81,12 +85,12 @@ abstract class Renderer extends Object with Scheduler, Services
/// Pump the rendering pipeline to generate a frame.
void
beginFrame
()
{
assert
(
renderView
!=
null
);
RenderObject
.
flushLayout
();
RenderObject
.
flushCompositingBits
();
RenderObject
.
flushPaint
();
pipelineOwner
.
flushLayout
();
pipelineOwner
.
flushCompositingBits
();
pipelineOwner
.
flushPaint
();
renderView
.
compositeFrame
();
// this sends the bits to the GPU
if
(
SemanticsNode
.
hasListeners
)
{
RenderObject
.
flushSemantics
();
pipelineOwner
.
flushSemantics
();
SemanticsNode
.
sendSemanticsTree
();
}
}
...
...
packages/flutter/lib/src/rendering/block.dart
View file @
bb5a82a7
...
...
@@ -337,8 +337,8 @@ class RenderBlockViewport extends RenderBlockBase {
}
@override
void
attach
()
{
super
.
attach
();
void
attach
(
PipelineOwner
owner
)
{
super
.
attach
(
owner
);
_overlayPainter
?.
attach
(
this
);
}
...
...
packages/flutter/lib/src/rendering/box.dart
View file @
bb5a82a7
...
...
@@ -388,12 +388,7 @@ class BoxHitTestEntry extends HitTestEntry {
/// Parent data used by [RenderBox] and its subclasses.
class
BoxParentData
extends
ParentData
{
/// The offset at which to paint the child in the parent's coordinate system
Offset
get
offset
=>
_offset
;
Offset
_offset
=
Offset
.
zero
;
void
set
offset
(
Offset
value
)
{
assert
(
RenderObject
.
debugDoingLayout
);
_offset
=
value
;
}
Offset
offset
=
Offset
.
zero
;
@override
String
toString
()
=>
'offset=
$offset
'
;
...
...
@@ -556,9 +551,9 @@ abstract class RenderBox extends RenderObject {
assert
(!
_debugDoingBaseline
);
assert
(()
{
final
RenderObject
parent
=
this
.
parent
;
if
(
RenderObject
.
debugDoingLayout
)
if
(
owner
.
debugDoingLayout
)
return
(
RenderObject
.
debugActiveLayout
==
parent
)
&&
parent
.
debugDoingThisLayout
;
if
(
RenderObject
.
debugDoingPaint
)
if
(
owner
.
debugDoingPaint
)
return
((
RenderObject
.
debugActivePaint
==
parent
)
&&
parent
.
debugDoingThisPaint
)
||
((
RenderObject
.
debugActivePaint
==
this
)
&&
debugDoingThisPaint
);
assert
(
parent
==
this
.
parent
);
...
...
packages/flutter/lib/src/rendering/child_view.dart
View file @
bb5a82a7
...
...
@@ -171,8 +171,8 @@ class RenderChildView extends RenderBox {
}
@override
void
attach
()
{
super
.
attach
();
void
attach
(
PipelineOwner
owner
)
{
super
.
attach
(
owner
);
_child
?.
_attach
();
}
...
...
packages/flutter/lib/src/rendering/node.dart
View file @
bb5a82a7
...
...
@@ -51,7 +51,7 @@ class AbstractNode {
/// Call only from overrides of [redepthChildren]
void
redepthChild
(
AbstractNode
child
)
{
assert
(
child
.
_attached
==
_attached
);
assert
(
child
.
owner
==
owner
);
if
(
child
.
_depth
<=
_depth
)
{
child
.
_depth
=
_depth
+
1
;
child
.
redepthChildren
();
...
...
@@ -62,16 +62,21 @@ class AbstractNode {
/// redepthChild(child) for each child. Do not call directly.
void
redepthChildren
()
{
}
bool
_attached
=
false
;
Object
_owner
;
/// The owner for this node (null if unattached).
Object
get
owner
=>
_owner
;
/// Whether this node is in a tree whose root is attached to something.
bool
get
attached
=>
_
attached
;
bool
get
attached
=>
_
owner
!=
null
;
/// Mark this node as attached.
/// Mark this node as attached
to the given owner
.
///
/// Typically called only from the parent's attach(), and to mark the root of
/// a tree attached.
void
attach
()
{
_attached
=
true
;
void
attach
(
Object
owner
)
{
assert
(
owner
!=
null
);
assert
(
_owner
==
null
);
_owner
=
owner
;
}
/// Mark this node as detached.
...
...
@@ -79,7 +84,8 @@ class AbstractNode {
/// Typically called only from the parent's detach(), and to mark the root of
/// a tree detached.
void
detach
()
{
_attached
=
false
;
assert
(
_owner
!=
null
);
_owner
=
null
;
}
AbstractNode
_parent
;
...
...
@@ -99,7 +105,7 @@ class AbstractNode {
});
child
.
_parent
=
this
;
if
(
attached
)
child
.
attach
();
child
.
attach
(
_owner
);
redepthChild
(
child
);
}
...
...
packages/flutter/lib/src/rendering/object.dart
View file @
bb5a82a7
...
...
@@ -559,7 +559,8 @@ class _RootSemanticsFragment extends _InterestingSemanticsFragment {
assert
(
currentSemantics
==
null
);
assert
(
parentSemantics
==
null
);
owner
.
_semantics
??=
new
SemanticsNode
.
root
(
handler:
owner
is
SemanticActionHandler
?
owner
as
dynamic
:
null
handler:
owner
is
SemanticActionHandler
?
owner
as
dynamic
:
null
,
owner:
owner
.
owner
);
SemanticsNode
node
=
owner
.
_semantics
;
assert
(
MatrixUtils
.
matrixEquals
(
node
.
transform
,
new
Matrix4
.
identity
()));
...
...
@@ -671,6 +672,105 @@ class _ForkingSemanticsFragment extends _SemanticsFragment {
}
}
class
PipelineOwner
{
List
<
RenderObject
>
_nodesNeedingLayout
=
<
RenderObject
>[];
bool
_debugDoingLayout
=
false
;
bool
get
debugDoingLayout
=>
_debugDoingLayout
;
/// Update the layout information for all dirty render objects.
///
/// This function is one of the core stages of the rendering pipeline. Layout
/// information is cleaned prior to painting so that render objects will
/// appear on screen in their up-to-date locations.
///
/// See [FlutterBinding] for an example of how this function is used.
void
flushLayout
()
{
Timeline
.
startSync
(
'Layout'
);
_debugDoingLayout
=
true
;
try
{
// TODO(ianh): assert that we're not allowing previously dirty nodes to redirty themeselves
while
(
_nodesNeedingLayout
.
isNotEmpty
)
{
List
<
RenderObject
>
dirtyNodes
=
_nodesNeedingLayout
;
_nodesNeedingLayout
=
<
RenderObject
>[];
for
(
RenderObject
node
in
dirtyNodes
..
sort
((
RenderObject
a
,
RenderObject
b
)
=>
a
.
depth
-
b
.
depth
))
{
if
(
node
.
_needsLayout
&&
node
.
owner
==
this
)
node
.
_layoutWithoutResize
();
}
}
}
finally
{
_debugDoingLayout
=
false
;
Timeline
.
finishSync
();
}
}
List
<
RenderObject
>
_nodesNeedingCompositingBitsUpdate
=
<
RenderObject
>[];
/// Updates the [needsCompositing] bits.
///
/// Called as part of the rendering pipeline after [flushLayout] and before
/// [flushPaint].
void
flushCompositingBits
()
{
Timeline
.
startSync
(
'Compositing Bits'
);
_nodesNeedingCompositingBitsUpdate
.
sort
((
RenderObject
a
,
RenderObject
b
)
=>
a
.
depth
-
b
.
depth
);
for
(
RenderObject
node
in
_nodesNeedingCompositingBitsUpdate
)
{
if
(
node
.
owner
==
this
)
node
.
_updateCompositingBits
();
}
_nodesNeedingCompositingBitsUpdate
.
clear
();
Timeline
.
finishSync
();
}
List
<
RenderObject
>
_nodesNeedingPaint
=
<
RenderObject
>[];
bool
_debugDoingPaint
=
false
;
bool
get
debugDoingPaint
=>
_debugDoingPaint
;
/// Update the display lists for all render objects.
///
/// This function is one of the core stages of the rendering pipeline.
/// Painting occurs after layout and before the scene is recomposited so that
/// scene is composited with up-to-date display lists for every render object.
///
/// See [FlutterBinding] for an example of how this function is used.
void
flushPaint
()
{
Timeline
.
startSync
(
'Paint'
);
_debugDoingPaint
=
true
;
try
{
List
<
RenderObject
>
dirtyNodes
=
_nodesNeedingPaint
;
_nodesNeedingPaint
=
<
RenderObject
>[];
// Sort the dirty nodes in reverse order (deepest first).
for
(
RenderObject
node
in
dirtyNodes
..
sort
((
RenderObject
a
,
RenderObject
b
)
=>
b
.
depth
-
a
.
depth
))
{
assert
(
node
.
_needsPaint
);
if
(
node
.
owner
==
this
)
PaintingContext
.
repaintCompositedChild
(
node
);
};
assert
(
_nodesNeedingPaint
.
length
==
0
);
}
finally
{
_debugDoingPaint
=
false
;
Timeline
.
finishSync
();
}
}
bool
_semanticsEnabled
=
false
;
bool
_debugDoingSemantics
=
false
;
List
<
RenderObject
>
_nodesNeedingSemantics
=
<
RenderObject
>[];
void
flushSemantics
()
{
Timeline
.
startSync
(
'Semantics'
);
assert
(
_semanticsEnabled
);
assert
(()
{
_debugDoingSemantics
=
true
;
return
true
;
});
try
{
_nodesNeedingSemantics
.
sort
((
RenderObject
a
,
RenderObject
b
)
=>
a
.
depth
-
b
.
depth
);
for
(
RenderObject
node
in
_nodesNeedingSemantics
)
{
if
(
node
.
_needsSemanticsUpdate
&&
node
.
owner
==
this
)
node
.
_updateSemantics
();
}
}
finally
{
_nodesNeedingSemantics
.
clear
();
assert
(()
{
_debugDoingSemantics
=
false
;
return
true
;
});
Timeline
.
finishSync
();
}
}
}
/// An object in the render tree.
///
/// The [RenderObject] class hierarchy is the core of the rendering
...
...
@@ -811,8 +911,6 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
}
}
static
bool
_debugDoingLayout
=
false
;
static
bool
get
debugDoingLayout
=>
_debugDoingLayout
;
bool
_debugDoingThisResize
=
false
;
bool
get
debugDoingThisResize
=>
_debugDoingThisResize
;
bool
_debugDoingThisLayout
=
false
;
...
...
@@ -835,7 +933,9 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
}
}
static
List
<
RenderObject
>
_nodesNeedingLayout
=
<
RenderObject
>[];
@override
PipelineOwner
get
owner
=>
super
.
owner
;
bool
_needsLayout
=
true
;
/// Whether this render object's layout information is dirty.
bool
get
needsLayout
=>
_needsLayout
;
...
...
@@ -912,7 +1012,8 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
debugPrintStack
();
return
true
;
});
_nodesNeedingLayout
.
add
(
this
);
if
(
owner
!=
null
)
owner
.
_nodesNeedingLayout
.
add
(
this
);
Scheduler
.
instance
.
ensureVisualUpdate
();
}
}
...
...
@@ -936,41 +1037,16 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
void
scheduleInitialLayout
()
{
assert
(
attached
);
assert
(
parent
is
!
RenderObject
);
assert
(!
_debugDoingLayout
);
assert
(!
owner
.
_debugDoingLayout
);
assert
(
_relayoutSubtreeRoot
==
null
);
_relayoutSubtreeRoot
=
this
;
assert
(()
{
_debugCanParentUseSize
=
false
;
return
true
;
});
_nodesNeedingLayout
.
add
(
this
);
owner
.
_nodesNeedingLayout
.
add
(
this
);
}
/// Update the layout information for all dirty render objects.
///
/// This function is one of the core stages of the rendering pipeline. Layout
/// information is cleaned prior to painting so that render objects will
/// appear on screen in their up-to-date locations.
///
/// See [FlutterBinding] for an example of how this function is used.
static
void
flushLayout
()
{
Timeline
.
startSync
(
'Layout'
);
_debugDoingLayout
=
true
;
try
{
// TODO(ianh): assert that we're not allowing previously dirty nodes to redirty themeselves
while
(
_nodesNeedingLayout
.
isNotEmpty
)
{
List
<
RenderObject
>
dirtyNodes
=
_nodesNeedingLayout
;
_nodesNeedingLayout
=
<
RenderObject
>[];
for
(
RenderObject
node
in
dirtyNodes
..
sort
((
RenderObject
a
,
RenderObject
b
)
=>
a
.
depth
-
b
.
depth
))
{
if
(
node
.
_needsLayout
&&
node
.
attached
)
node
.
_layoutWithoutResize
();
}
}
}
finally
{
_debugDoingLayout
=
false
;
Timeline
.
finishSync
();
}
}
void
_layoutWithoutResize
()
{
assert
(
_relayoutSubtreeRoot
==
this
);
RenderObject
debugPreviousActiveLayout
;
...
...
@@ -1180,16 +1256,11 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
// PAINTING
static
bool
_debugDoingPaint
=
false
;
static
bool
get
debugDoingPaint
=>
_debugDoingPaint
;
bool
_debugDoingThisPaint
=
false
;
bool
get
debugDoingThisPaint
=>
_debugDoingThisPaint
;
static
RenderObject
_debugActivePaint
;
static
RenderObject
get
debugActivePaint
=>
_debugActivePaint
;
static
List
<
RenderObject
>
_nodesNeedingPaint
=
<
RenderObject
>[];
static
List
<
RenderObject
>
_nodesNeedingCompositingBitsUpdate
=
<
RenderObject
>[];
/// Whether this render object repaints separately from its parent.
///
/// Override this in subclasses to indicate that instances of your class ought
...
...
@@ -1260,22 +1331,8 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
return
true
;
});
// parent is fine (or there isn't one), but we are dirty
_nodesNeedingCompositingBitsUpdate
.
add
(
this
);
}
/// Updates the [needsCompositing] bits.
///
/// Called as part of the rendering pipeline after [flushLayout] and before
/// [flushPaint].
static
void
flushCompositingBits
()
{
Timeline
.
startSync
(
'Compositing Bits'
);
_nodesNeedingCompositingBitsUpdate
.
sort
((
RenderObject
a
,
RenderObject
b
)
=>
a
.
depth
-
b
.
depth
);
for
(
RenderObject
node
in
_nodesNeedingCompositingBitsUpdate
)
{
if
(
node
.
attached
)
node
.
_updateCompositingBits
();
}
_nodesNeedingCompositingBitsUpdate
.
clear
();
Timeline
.
finishSync
();
if
(
owner
!=
null
)
owner
.
_nodesNeedingCompositingBitsUpdate
.
add
(
this
);
}
bool
_needsCompositing
;
// initialised in the constructor
...
...
@@ -1319,7 +1376,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
/// This mechanism batches the painting work so that multiple sequential
/// writes are coalesced, removing redundant computation.
void
markNeedsPaint
()
{
assert
(
!
debugDoingPaint
);
assert
(
owner
==
null
||
!
owner
.
debugDoingPaint
);
if
(!
attached
)
return
;
// Don't try painting things that aren't in the hierarchy
if
(
_needsPaint
)
...
...
@@ -1334,7 +1391,8 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
// If we always have our own layer, then we can just repaint
// ourselves without involving any other nodes.
assert
(
_layer
!=
null
);
_nodesNeedingPaint
.
add
(
this
);
if
(
owner
!=
null
)
owner
.
_nodesNeedingPaint
.
add
(
this
);
Scheduler
.
instance
.
ensureVisualUpdate
();
}
else
if
(
parent
is
RenderObject
)
{
// We don't have our own layer; one of our ancestors will take
...
...
@@ -1353,32 +1411,6 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
}
}
/// Update the display lists for all render objects.
///
/// This function is one of the core stages of the rendering pipeline.
/// Painting occurs after layout and before the scene is recomposited so that
/// scene is composited with up-to-date display lists for every render object.
///
/// See [FlutterBinding] for an example of how this function is used.
static
void
flushPaint
()
{
Timeline
.
startSync
(
'Paint'
);
_debugDoingPaint
=
true
;
try
{
List
<
RenderObject
>
dirtyNodes
=
_nodesNeedingPaint
;
_nodesNeedingPaint
=
<
RenderObject
>[];
// Sort the dirty nodes in reverse order (deepest first).
for
(
RenderObject
node
in
dirtyNodes
..
sort
((
RenderObject
a
,
RenderObject
b
)
=>
b
.
depth
-
a
.
depth
))
{
assert
(
node
.
_needsPaint
);
if
(
node
.
attached
)
PaintingContext
.
repaintCompositedChild
(
node
);
};
assert
(
_nodesNeedingPaint
.
length
==
0
);
}
finally
{
_debugDoingPaint
=
false
;
Timeline
.
finishSync
();
}
}
/// Bootstrap the rendering pipeline by scheduling the very first paint.
///
/// Requires that this render object is attached, is the root of the render
...
...
@@ -1388,12 +1420,12 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
void
scheduleInitialPaint
(
ContainerLayer
rootLayer
)
{
assert
(
attached
);
assert
(
parent
is
!
RenderObject
);
assert
(!
_debugDoingPaint
);
assert
(!
owner
.
_debugDoingPaint
);
assert
(
isRepaintBoundary
);
assert
(
_layer
==
null
);
_layer
=
rootLayer
;
assert
(
_needsPaint
);
_nodesNeedingPaint
.
add
(
this
);
owner
.
_nodesNeedingPaint
.
add
(
this
);
}
void
_paintWithContext
(
PaintingContext
context
,
Offset
offset
)
{
assert
(!
_debugDoingThisPaint
);
...
...
@@ -1477,10 +1509,6 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
// SEMANTICS
static
bool
_semanticsEnabled
=
false
;
static
bool
_debugDoingSemantics
=
false
;
static
List
<
RenderObject
>
_nodesNeedingSemantics
=
<
RenderObject
>[];
/// Bootstrap the semantics reporting mechanism by marking this node
/// as needing a semantics update.
///
...
...
@@ -1491,32 +1519,15 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
void
scheduleInitialSemantics
()
{
assert
(
attached
);
assert
(
parent
is
!
RenderObject
);
assert
(!
_debugDoingSemantics
);
assert
(!
owner
.
_debugDoingSemantics
);
assert
(
_semantics
==
null
);
assert
(
_needsSemanticsUpdate
);
assert
(
_semanticsEnabled
==
false
);
_semanticsEnabled
=
true
;
_nodesNeedingSemantics
.
add
(
this
);
assert
(
owner
.
_semanticsEnabled
==
false
);
owner
.
_semanticsEnabled
=
true
;
owner
.
_nodesNeedingSemantics
.
add
(
this
);
Scheduler
.
instance
.
ensureVisualUpdate
();
}
static
void
flushSemantics
()
{
Timeline
.
startSync
(
'Semantics'
);
assert
(
_semanticsEnabled
);
assert
(()
{
_debugDoingSemantics
=
true
;
return
true
;
});
try
{
_nodesNeedingSemantics
.
sort
((
RenderObject
a
,
RenderObject
b
)
=>
a
.
depth
-
b
.
depth
);
for
(
RenderObject
node
in
_nodesNeedingSemantics
)
{
if
(
node
.
_needsSemanticsUpdate
)
node
.
_updateSemantics
();
}
}
finally
{
_nodesNeedingSemantics
.
clear
();
assert
(()
{
_debugDoingSemantics
=
false
;
return
true
;
});
Timeline
.
finishSync
();
}
}
/// Whether this RenderObject introduces a new box for accessibility purposes.
bool
get
hasSemantics
=>
false
;
...
...
@@ -1561,8 +1572,8 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
/// 'noGeometry: true' when the geometry did change, the semantic
/// tree will be out of date.
void
markNeedsSemanticsUpdate
({
bool
onlyChanges:
false
,
bool
noGeometry:
false
})
{
assert
(!
_debugDoingSemantics
);
if
(!
_semanticsEnabled
||
!
attach
ed
||
(
_needsSemanticsUpdate
&&
onlyChanges
&&
(
_needsSemanticsGeometryUpdate
||
noGeometry
)))
assert
(!
attached
||
!
owner
.
_debugDoingSemantics
);
if
(!
attached
||
!
owner
.
_semanticsEnabl
ed
||
(
_needsSemanticsUpdate
&&
onlyChanges
&&
(
_needsSemanticsGeometryUpdate
||
noGeometry
)))
return
;
if
(!
noGeometry
&&
(
_semantics
==
null
||
(
_semantics
.
hasChildren
&&
_semantics
.
wasAffectedByClip
)))
{
// Since the geometry might have changed, we need to make sure to reapply any clips.
...
...
@@ -1582,7 +1593,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
}
if
(!
node
.
_needsSemanticsUpdate
)
{
node
.
_needsSemanticsUpdate
=
true
;
_nodesNeedingSemantics
.
add
(
node
);
owner
.
_nodesNeedingSemantics
.
add
(
node
);
}
}
else
{
// The shape of the semantics tree around us may have changed.
...
...
@@ -1601,7 +1612,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
node
.
_semantics
?.
reset
();
if
(!
node
.
_needsSemanticsUpdate
)
{
node
.
_needsSemanticsUpdate
=
true
;
_nodesNeedingSemantics
.
add
(
node
);
owner
.
_nodesNeedingSemantics
.
add
(
node
);
}
}
}
...
...
@@ -1814,10 +1825,10 @@ abstract class RenderObjectWithChildMixin<ChildType extends RenderObject> implem
}
@override
void
attach
()
{
super
.
attach
();
void
attach
(
PipelineOwner
owner
)
{
super
.
attach
(
owner
);
if
(
_child
!=
null
)
_child
.
attach
();
_child
.
attach
(
owner
);
}
@override
...
...
@@ -2034,11 +2045,11 @@ abstract class ContainerRenderObjectMixin<ChildType extends RenderObject, Parent
}
@override
void
attach
()
{
super
.
attach
();
void
attach
(
PipelineOwner
owner
)
{
super
.
attach
(
owner
);
ChildType
child
=
_firstChild
;
while
(
child
!=
null
)
{
child
.
attach
();
child
.
attach
(
owner
);
final
ParentDataType
childParentData
=
child
.
parentData
;
child
=
childParentData
.
nextSibling
;
}
...
...
packages/flutter/lib/src/rendering/proxy_box.dart
View file @
bb5a82a7
...
...
@@ -1035,8 +1035,8 @@ class RenderDecoratedBox extends RenderProxyBox {
}
@override
void
attach
()
{
super
.
attach
();
void
attach
(
PipelineOwner
owner
)
{
super
.
attach
(
owner
);
_addListenerIfNeeded
();
}
...
...
packages/flutter/lib/src/rendering/semantics.dart
View file @
bb5a82a7
...
...
@@ -58,10 +58,11 @@ class SemanticsNode extends AbstractNode {
_actionHandler
=
handler
;
SemanticsNode
.
root
({
SemanticActionHandler
handler
SemanticActionHandler
handler
,
Object
owner
})
:
_id
=
0
,
_actionHandler
=
handler
{
attach
();
attach
(
owner
);
}
static
int
_lastIdentifier
=
0
;
...
...
@@ -265,8 +266,8 @@ class SemanticsNode extends AbstractNode {
static
Set
<
SemanticsNode
>
_detachedNodes
=
new
Set
<
SemanticsNode
>();
@override
void
attach
()
{
super
.
attach
();
void
attach
(
Object
owner
)
{
super
.
attach
(
owner
);
assert
(!
_nodes
.
containsKey
(
_id
));
_nodes
[
_id
]
=
this
;
_detachedNodes
.
remove
(
this
);
...
...
@@ -274,7 +275,7 @@ class SemanticsNode extends AbstractNode {
_inheritedMergeAllDescendantsIntoThisNode
=
parent
.
_shouldMergeAllDescendantsIntoThisNode
;
if
(
_children
!=
null
)
{
for
(
SemanticsNode
child
in
_children
)
child
.
attach
();
child
.
attach
(
owner
);
}
}
...
...
packages/flutter/lib/src/rendering/view.dart
View file @
bb5a82a7
...
...
@@ -33,7 +33,7 @@ class ViewConfiguration {
/// The root of the render tree.
///
/// The view represents the total output surface of the render tree and handles
/// bootstraping the rendering pipeline. The view has a unique child
/// bootstrap
p
ing the rendering pipeline. The view has a unique child
/// [RenderBox], which is required to fill the entire output surface.
class
RenderView
extends
RenderObject
with
RenderObjectWithChildMixin
<
RenderBox
>
{
RenderView
({
...
...
packages/flutter/lib/src/rendering/viewport.dart
View file @
bb5a82a7
...
...
@@ -168,8 +168,8 @@ class RenderViewportBase extends RenderBox implements HasMainAxis {
}
@override
void
attach
()
{
super
.
attach
();
void
attach
(
PipelineOwner
owner
)
{
super
.
attach
(
owner
);
_overlayPainter
?.
attach
(
this
);
}
...
...
packages/flutter/lib/src/widgets/gesture_detector.dart
View file @
bb5a82a7
...
...
@@ -335,7 +335,11 @@ class RawGestureDetectorState extends State<RawGestureDetector> {
/// the gesture detector should be enabled.
void
replaceGestureRecognizers
(
Map
<
Type
,
GestureRecognizerFactory
>
gestures
)
{
assert
(()
{
if
(!
RenderObject
.
debugDoingLayout
)
{
// TODO kgiesing This assert will trigger if the owner of the current
// tree is different from the owner assigned to the renderer instance.
// Once elements have a notion of owners this assertion can be written
// more clearly.
if
(!
Renderer
.
instance
.
pipelineOwner
.
debugDoingLayout
)
{
throw
new
FlutterError
(
'Unexpected call to replaceGestureRecognizers() method of RawGestureDetectorState.
\n
'
'The replaceGestureRecognizers() method can only be called during the layout phase. '
...
...
packages/flutter/test/rendering/independent_layout_test.dart
0 → 100644
View file @
bb5a82a7
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/material.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:test/test.dart'
;
import
'rendering_tester.dart'
;
class
TestLayout
{
TestLayout
()
{
// viewport incoming constraints are tight 800x600
// viewport is vertical by default
root
=
new
RenderViewport
(
child:
new
RenderCustomPaint
(
painter:
new
TestCallbackPainter
(
onPaint:
()
{
painted
=
true
;
}
),
child:
child
=
new
RenderConstrainedBox
(
additionalConstraints:
new
BoxConstraints
.
tightFor
(
height:
10.0
,
width:
10.0
)
)
)
);
}
RenderBox
root
;
RenderBox
child
;
bool
painted
=
false
;
}
void
main
(
)
{
test
(
'onscreen layout does not affect offscreen'
,
()
{
TestLayout
onscreen
=
new
TestLayout
();
TestLayout
offscreen
=
new
TestLayout
();
expect
(
onscreen
.
child
.
hasSize
,
isFalse
);
expect
(
onscreen
.
painted
,
isFalse
);
expect
(
offscreen
.
child
.
hasSize
,
isFalse
);
expect
(
offscreen
.
painted
,
isFalse
);
// Attach the offscreen to a custom render view and owner
RenderView
renderView
=
new
TestRenderView
();
PipelineOwner
pipelineOwner
=
new
PipelineOwner
();
renderView
.
attach
(
pipelineOwner
);
renderView
.
child
=
offscreen
.
root
;
renderView
.
scheduleInitialFrame
();
// Lay out the onscreen in the default binding
layout
(
onscreen
.
root
,
phase:
EnginePhase
.
layout
);
expect
(
onscreen
.
child
.
hasSize
,
isTrue
);
expect
(
onscreen
.
painted
,
isFalse
);
expect
(
onscreen
.
child
.
size
,
equals
(
const
Size
(
800.0
,
10.0
)));
// Make sure the offscreen didn't get laid out
expect
(
offscreen
.
child
.
hasSize
,
isFalse
);
expect
(
offscreen
.
painted
,
isFalse
);
// Now lay out the offscreen
pipelineOwner
.
flushLayout
();
expect
(
offscreen
.
child
.
hasSize
,
isTrue
);
expect
(
offscreen
.
painted
,
isFalse
);
});
test
(
'offscreen layout does not affect onscreen'
,
()
{
TestLayout
onscreen
=
new
TestLayout
();
TestLayout
offscreen
=
new
TestLayout
();
expect
(
onscreen
.
child
.
hasSize
,
isFalse
);
expect
(
onscreen
.
painted
,
isFalse
);
expect
(
offscreen
.
child
.
hasSize
,
isFalse
);
expect
(
offscreen
.
painted
,
isFalse
);
// Attach the offscreen to a custom render view and owner
RenderView
renderView
=
new
TestRenderView
();
PipelineOwner
pipelineOwner
=
new
PipelineOwner
();
renderView
.
attach
(
pipelineOwner
);
renderView
.
child
=
offscreen
.
root
;
renderView
.
scheduleInitialFrame
();
// Lay out the offscreen
pipelineOwner
.
flushLayout
();
expect
(
offscreen
.
child
.
hasSize
,
isTrue
);
expect
(
offscreen
.
painted
,
isFalse
);
// Make sure the onscreen didn't get laid out
expect
(
onscreen
.
child
.
hasSize
,
isFalse
);
expect
(
onscreen
.
painted
,
isFalse
);
// Now lay out the onscreen in the default binding
layout
(
onscreen
.
root
,
phase:
EnginePhase
.
layout
);
expect
(
onscreen
.
child
.
hasSize
,
isTrue
);
expect
(
onscreen
.
painted
,
isFalse
);
expect
(
onscreen
.
child
.
size
,
equals
(
const
Size
(
800.0
,
10.0
)));
});
}
packages/flutter/test/rendering/rendering_tester.dart
View file @
bb5a82a7
...
...
@@ -41,16 +41,16 @@ class TestRenderingFlutterBinding extends BindingBase with Scheduler, Services,
@override
void
beginFrame
()
{
RenderObject
.
flushLayout
();
pipelineOwner
.
flushLayout
();
if
(
phase
==
EnginePhase
.
layout
)
return
;
RenderObject
.
flushCompositingBits
();
pipelineOwner
.
flushCompositingBits
();
if
(
phase
==
EnginePhase
.
compositingBits
)
return
;
RenderObject
.
flushPaint
();
pipelineOwner
.
flushPaint
();
if
(
phase
==
EnginePhase
.
paint
)
return
;
render
er
.
render
View
.
compositeFrame
();
renderView
.
compositeFrame
();
}
}
...
...
packages/flutter_sprites/lib/src/sprite_box.dart
View file @
bb5a82a7
...
...
@@ -58,8 +58,8 @@ class SpriteBox extends RenderBox {
}
@override
void
attach
()
{
super
.
attach
();
void
attach
(
PipelineOwner
owner
)
{
super
.
attach
(
owner
);
_scheduleTick
();
}
...
...
packages/flutter_test/lib/src/widget_tester.dart
View file @
bb5a82a7
...
...
@@ -46,20 +46,20 @@ class _SteppedWidgetFlutterBinding extends WidgetFlutterBinding {
// Cloned from Renderer.beginFrame() but with early-exit semantics.
void
_beginFrame
()
{
assert
(
renderView
!=
null
);
RenderObject
.
flushLayout
();
pipelineOwner
.
flushLayout
();
if
(
phase
==
EnginePhase
.
layout
)
return
;
RenderObject
.
flushCompositingBits
();
pipelineOwner
.
flushCompositingBits
();
if
(
phase
==
EnginePhase
.
compositingBits
)
return
;
RenderObject
.
flushPaint
();
pipelineOwner
.
flushPaint
();
if
(
phase
==
EnginePhase
.
paint
)
return
;
renderView
.
compositeFrame
();
// this sends the bits to the GPU
if
(
phase
==
EnginePhase
.
composite
)
return
;
if
(
SemanticsNode
.
hasListeners
)
{
RenderObject
.
flushSemantics
();
pipelineOwner
.
flushSemantics
();
if
(
phase
==
EnginePhase
.
flushSemantics
)
return
;
SemanticsNode
.
sendSemanticsTree
();
...
...
packages/flutter_tools/lib/src/commands/analyze.dart
View file @
bb5a82a7
...
...
@@ -347,6 +347,7 @@ class AnalyzeCommand extends FlutterCommand {
new
RegExp
(
'^
\\
[(hint|error)
\\
] Unused import
\\
(
${mainFile.path}
,'
),
new
RegExp
(
r'^\[.+\] .+ \(.+/\.pub-cache/.+'
),
new
RegExp
(
'
\\
[warning
\\
] Missing concrete implementation of
\'
RenderObject
\\
.applyPaintTransform
\'
'
),
// https://github.com/dart-lang/sdk/issues/25232
new
RegExp
(
'
\\
[warning
\\
] Missing concrete implementation of
\'
AbstractNode
\\
.attach
\'
'
),
// https://github.com/dart-lang/sdk/issues/25232
new
RegExp
(
r'[0-9]+ (error|warning|hint|lint).+found\.'
),
new
RegExp
(
r'^$'
),
];
...
...
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