Commit 498cfc67 authored by Michael Goderbauer's avatar Michael Goderbauer Committed by GitHub

(Update and) Integrate Rendering README into code (#10389)

* (Update and) Integrate Rendering README into code

* Add mising whitespace

* Review comments and other touch-ups
parent 0e976372
Flutter Rendering Layer
=======================
This document is intended to describe some of the core designs of the
Flutter rendering layer.
Layout
------
Paint
-----
Compositing
-----------
Semantics
---------
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
`PipelineOwner.flushSemantics()` method from the `Renderer` binding's
`beginFrame()` method.
Each node marked as needing semantics (which initially is just the
root node, as scheduled by `scheduleInitialSemantics()`), in depth
order, has its semantics updated by calling `_updateSemantics()`.
The `_updateSemantics()` method calls `_getSemantics()` to obtain an
`_InterestingSemanticsFragment`, and then calls `compile()` on that
fragment to obtain a `SemanticsNode` which becomes the value of the
`RenderObject`'s `_semantics` field. **This is essentially a two-pass
walk of the render tree. The first pass determines the shape of the
output tree, and the second creates the nodes of this tree and hooks
them together.** The second walk is a sparse walk; it only walks the
nodes that are interesting for the purpose of semantics.
`_getSemantics()` is the core function that walks the render tree to
obtain the semantics. It collects semantic annotators for this
`RenderObject`, then walks its children collecting
`_SemanticsFragment`s for them, and then returns an appropriate
`_SemanticsFragment` object that describes the `RenderObject`'s
semantics.
Semantic annotators are functions that, given a `SemanticsNode`, set
some flags or strings on the object. They are obtained from
`getSemanticsAnnotators()`. For example, here is how `RenderParagraph`
annotates the `SemanticsNode` with its text:
```dart
Iterable<SemanticsAnnotator> getSemanticsAnnotators() sync* {
yield (SemanticsNode node) {
node.label = text.toPlainText();
};
}
```
A `_SemanticsFragment` object is a node in a short-lived tree which is
used to create the final `SemanticsNode` tree that is sent to the
semantics server. These objects have a list of semantic annotators,
and a list of `_SemanticsFragment` children.
There are several `_SemanticsFragment` classes. The `_getSemantics()`
method picks its return value as follows:
* `_CleanSemanticsFragment` is used to represent a `RenderObject` that
has a `SemanticsNode` and which is in no way dirty. This class has
no children and no annotators, and when compiled, it returns the
`SemanticsNode` that the `RenderObject` already has.
* `_RootSemanticsFragment`* is used to represent the `RenderObject`
found at the top of the render tree. This class always compiles to a
`SemanticsNode` with ID 0.
* `_ConcreteSemanticsFragment`* is used to represent a `RenderObject`
that has `hasSemantics` set to true. It returns the `SemanticsNode`
for that `RenderObject`.
* `_ImplicitSemanticsFragment`* is used to represent a `RenderObject`
that does not have `hasSemantics` set to true, but which does have
some semantic annotators. When it is compiled, if the nearest
ancestor `_SemanticsFragment` that isn't also an
`_ImplicitSemanticsFragment` is a `_RootSemanticsFragment` or a
`_ConcreteSemanticsFragment`, then the `SemanticsNode` from that
object is reused. Otherwise, a new one is created.
* `_ForkingSemanticsFragment` is used to represent a `RenderObject`
that introduces no semantics of its own, but which has two or more
descendants that do introduce semantics (and which are not ancestors
or descendants of each other).
* For `RenderObject` nodes that introduce no semantics but which have
a (single) child that does, the `_SemanticsFragment` of the child is
returned.
* For `RenderObject` nodes that introduce no semantics and have no
descendants that introduce semantics, `null` is returned.
The classes marked with an asterisk * above are the
`_InterestingSemanticsFragment` classes.
When the `_SemanticsFragment` tree is then compiled, the
`SemanticsNode` objects are created (if necessary), the semantic
annotators are run on each `SemanticsNode`, the geometry (matrix,
size, and clip) is applied, and the children are updated.
As part of this, the code clears out the `_semantics` field of any
`RenderObject` that previously had a `SemanticsNode` but no longer
does. This is done as part of the first walk where possible, and as
part of the second otherwise.
......@@ -652,6 +652,12 @@ class _SemanticsGeometry {
}
}
/// Describes the shape of the semantic tree.
///
/// A [_SemanticsFragment] object is a node in a short-lived tree which is used
/// to create the final [SemanticsNode] tree that is sent to the semantics
/// server. These objects have a [SemanticsAnnotator], and a list of
/// [_SemanticsFragment] children.
abstract class _SemanticsFragment {
_SemanticsFragment({
@required RenderObject renderObjectOwner,
......@@ -689,9 +695,11 @@ abstract class _SemanticsFragment {
String toString() => '$runtimeType#$hashCode';
}
/// Represents a subtree that doesn't need updating, it already has a
/// SemanticsNode and isn't dirty. (We still update the matrix, since
/// that comes from the (dirty) ancestors.)
/// Represents a [RenderObject] which is in no way dirty.
///
/// This class has no children and no annotators, and when compiled, it returns
/// the [SemanticsNode] that the [RenderObject] already has. (We still update
/// the matrix, since that comes from the (dirty) ancestors.)
class _CleanSemanticsFragment extends _SemanticsFragment {
_CleanSemanticsFragment({
@required RenderObject renderObjectOwner
......@@ -750,6 +758,9 @@ abstract class _InterestingSemanticsFragment extends _SemanticsFragment {
_SemanticsGeometry createSemanticsGeometryForChild(_SemanticsGeometry geometry);
}
/// Represents the [RenderObject] found at the top of the render tree.
///
/// This class always compiles to a [SemanticsNode] with ID 0.
class _RootSemanticsFragment extends _InterestingSemanticsFragment {
_RootSemanticsFragment({
RenderObject renderObjectOwner,
......@@ -780,6 +791,9 @@ class _RootSemanticsFragment extends _InterestingSemanticsFragment {
}
}
/// Represents a RenderObject that has [isSemanticBoundary] set to `true`.
///
/// It returns the SemanticsNode for that [RenderObject].
class _ConcreteSemanticsFragment extends _InterestingSemanticsFragment {
_ConcreteSemanticsFragment({
RenderObject renderObjectOwner,
......@@ -808,6 +822,13 @@ class _ConcreteSemanticsFragment extends _InterestingSemanticsFragment {
}
}
/// Represents a RenderObject that does not have [isSemanticBoundary] set to
/// `true`, but which does have some semantic annotators.
///
/// When it is compiled, if the nearest ancestor [_SemanticsFragment] that isn't
/// also an [_ImplicitSemanticsFragment] is a [_RootSemanticsFragment] or a
/// [_ConcreteSemanticsFragment], then the [SemanticsNode] from that object is
/// reused. Otherwise, a new one is created.
class _ImplicitSemanticsFragment extends _InterestingSemanticsFragment {
_ImplicitSemanticsFragment({
RenderObject renderObjectOwner,
......@@ -851,6 +872,9 @@ class _ImplicitSemanticsFragment extends _InterestingSemanticsFragment {
}
}
/// Represents a [RenderObject] that introduces no semantics of its own, but
/// which has two or more descendants that do introduce semantics
/// (and which are not ancestors or descendants of each other).
class _ForkingSemanticsFragment extends _SemanticsFragment {
_ForkingSemanticsFragment({
RenderObject renderObjectOwner,
......@@ -1180,7 +1204,11 @@ class PipelineOwner {
bool _debugDoingSemantics = false;
final List<RenderObject> _nodesNeedingSemantics = <RenderObject>[];
/// Update the semantics for all render objects.
/// Update the semantics for render objects marked as needing a semantics
/// update.
///
/// Initially, only the root node, as scheduled by [scheduleInitialSemantics],
/// needs a semantics update.
///
/// This function is one of the core stages of the rendering pipeline. The
/// semantics are compiled after painting and only after
......@@ -2486,6 +2514,13 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
}
}
/// Updates the semantic information of the render object.
///
/// This is essentially a two-pass walk of the render tree. The first pass
/// determines the shape of the output tree (captured in
/// [_SemanticsFragment]s), and the second creates the nodes of this tree and
/// hooks them together. The second walk is a sparse walk; it only walks the
/// nodes that are interesting for the purpose of semantics.
void _updateSemantics() {
try {
assert(_needsSemanticsUpdate);
......@@ -2500,6 +2535,12 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
}
}
/// Core function that walks the render tree to obtain the semantics.
///
/// It collects semantic annotators for this RenderObject, then walks its
/// children collecting [_SemanticsFragments] for them, and then returns an
/// appropriate [_SemanticsFragment] object that describes the RenderObject's
/// semantics.
_SemanticsFragment _getSemanticsFragment() {
// early-exit if we're not dirty and have our own semantics
if (!_needsSemanticsUpdate && isSemanticBoundary) {
......@@ -2533,17 +2574,21 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
if (annotator != null)
return new _ImplicitSemanticsFragment(renderObjectOwner: this, annotator: annotator, children: children);
_semantics = null;
if (children == null)
if (children == null) {
// Introduces no semantics and has no descendants that introduce semantics.
return null;
}
if (children.length > 1)
return new _ForkingSemanticsFragment(renderObjectOwner: this, children: children);
assert(children.length == 1);
return children.single;
}
/// Called when collecting the semantics of this node. Subclasses
/// that have children that are not semantically relevant (e.g.
/// because they are invisible) should skip those children here.
/// Called when collecting the semantics of this node.
///
/// The implementation has to return the children in paint order skipping all
/// children that are not semantically relevant (e.g. because they are
/// invisible).
///
/// The default implementation mirrors the behavior of
/// [visitChildren()] (which is supposed to walk all the children).
......
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