Commit ee930d68 authored by Xianzhu Wang's avatar Xianzhu Wang

Update core/paint/README.md and platform/graphics/paint/README.md

Remove out-dated docs about PaintInvalidationState and DisplayItemClient
cache generation.

Add new paint invalidation and raster invalidation.

Update docs about paint properties.

Cq-Include-Trybots: luci.chromium.try:linux_layout_tests_slimming_paint_v2;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: I46df3f3e98353fc9a66fc950430df0d8e416d394
Reviewed-on: https://chromium-review.googlesource.com/c/1281921Reviewed-by: default avatarChris Harrelson <chrishtr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#599856}
parent b1b1edba
...@@ -102,7 +102,9 @@ are treated in different ways during painting: ...@@ -102,7 +102,9 @@ are treated in different ways during painting:
concept. concept.
* Visual rect: the bounding box of all pixels that will be painted by a * Visual rect: the bounding box of all pixels that will be painted by a
display item client. [display item client](../../platform/graphics/paint/README.md#display-items).
It's in the space of the containing transform property node (see [Building
paint property trees](#building-paint-property-trees)).
* Isolation nodes/boundary: In certain situations, it is possible to put in * Isolation nodes/boundary: In certain situations, it is possible to put in
place a barrier that isolates a subtree from being affected by its place a barrier that isolates a subtree from being affected by its
...@@ -376,125 +378,7 @@ Layerization | PLC/CLM | PLC/CLM | ...@@ -376,125 +378,7 @@ Layerization | PLC/CLM | PLC/CLM |
cc property tree builder | on | off | off cc property tree builder | on | off | off
``` ```
## PaintInvalidation (Deprecated by [PrePaint](#PrePaint)) ## PrePaint
Paint invalidation marks anything that need to be painted differently from the
original cached painting.
Paint invalidation is a document cycle stage after compositing update and before
paint. During the previous stages, objects are marked for needing paint
invalidation checking if needed by style change, layout change, compositing
change, etc. In paint invalidation stage, we traverse the layout tree in
pre-order, crossing frame boundaries, for marked subtrees and objects and send
the following information to `GraphicsLayer`s and `PaintController`s:
* invalidated display item clients: must invalidate all display item clients
that will generate different display items.
* paint invalidation rects: must cover all areas that will generate different
pixels. They are generated based on visual rects of invalidated display item
clients.
### `PaintInvalidationState`
`PaintInvalidationState` is an optimization used during the paint invalidation
phase. Before the paint invalidation tree walk, a root `PaintInvalidationState`
is created for the root `LayoutView`. During the tree walk, one
`PaintInvalidationState` is created for each visited object based on the
`PaintInvalidationState` passed from the parent object. It tracks the following
information to provide O(1) complexity access to them if possible:
* Paint invalidation container: Since as indicated by the definitions in
[Glossaries](#other-glossaries), the paint invalidation container for
stacked objects can differ from normal objects, we have to track both
separately. Here is an example:
<div style="overflow: scroll">
<div id=A style="position: absolute"></div>
<div id=B></div>
</div>
If the scroller is composited (for high-DPI screens for example), it is the
paint invalidation container for div B, but not A.
* Paint offset and clip rect: if possible, `PaintInvalidationState`
accumulates paint offsets and overflow clipping rects from the paint
invalidation container to provide O(1) complexity to map a point or a rect
in current object's local space to paint invalidation container's space.
Because locations of objects are determined by their containing blocks, and
the containing block for absolute-position objects differs from
non-absolute, we track paint offsets and overflow clipping rects for
absolute-position objects separately.
In cases that accurate accumulation of paint offsets and clipping rects is
impossible, we will fall back to slow-path using
`LayoutObject::localToAncestorPoint()` or
`LayoutObject::mapToVisualRectInAncestorSpace()`. This includes the following
cases:
* An object has transform related property, is multi-column or has flipped
blocks writing-mode, causing we can't simply accumulate paint offset for
mapping a local rect to paint invalidation container;
* An object has has filter (including filter induced by reflection), which
needs to expand visual rect for descendants, because currently we don't
include and filter extents into visual overflow;
* For a fixed-position object we calculate its offset using
`LayoutObject::localToAncestorPoint()`, but map for its descendants in
fast-path if no other things prevent us from doing this;
* Because we track paint offset from the normal paint invalidation container
only, if we are going to use
`m_paintInvalidationContainerForStackedContents` and it's different from the
normal paint invalidation container, we have to force slow-path because the
accumulated paint offset is not usable;
* We also stop to track paint offset and clipping rect for absolute-position
objects when `m_paintInvalidationContainerForStackedContents` becomes
different from `m_paintInvalidationContainer`.
### Paint invalidation of texts
Texts are painted by `InlineTextBoxPainter` using `InlineTextBox` as display
item client. Text backgrounds and masks are painted by `InlineTextFlowPainter`
using `InlineFlowBox` as display item client. We should invalidate these display
item clients when their painting will change.
`LayoutInline`s and `LayoutText`s are marked for full paint invalidation if
needed when new style is set on them. During paint invalidation, we invalidate
the `InlineFlowBox`s directly contained by the `LayoutInline` in
`LayoutInline::InvalidateDisplayItemClients()` and `InlineTextBox`s contained by
the `LayoutText` in `LayoutText::InvalidateDisplayItemClients()`. We don't need
to traverse into the subtree of `InlineFlowBox`s in
`LayoutInline::InvalidateDisplayItemClients()` because the descendant
`InlineFlowBox`s and `InlineTextBox`s will be handled by their owning
`LayoutInline`s and `LayoutText`s, respectively, when changed style is propagated.
### Specialty of `::first-line`
`::first-line` pseudo style dynamically applies to all `InlineBox`'s in the
first line in the block having `::first-line` style. The actual applied style is
computed from the `::first-line` style and other applicable styles.
If the first line contains any `LayoutInline`, we compute the style from the
`::first-line` style and the style of the `LayoutInline` and apply the computed
style to the first line part of the `LayoutInline`. In Blink's style
implementation, the combined first line style of `LayoutInline` is identified
with `FIRST_LINE_INHERITED` pseudo ID.
The normal paint invalidation of texts doesn't work for first line because
* `ComputedStyle::VisualInvalidationDiff()` can't detect first line style
changes;
* The normal paint invalidation is based on whole LayoutObject's, not aware of
the first line.
We have a special path for first line style change: the style system informs the
layout system when the computed first-line style changes through
`LayoutObject::FirstLineStyleDidChange()`. When this happens, we invalidate all
`InlineBox`es in the first line.
## PrePaint (Slimming paint invalidation/v2 only)
[`PrePaintTreeWalk`](pre_paint_tree_walk.h) [`PrePaintTreeWalk`](pre_paint_tree_walk.h)
During `InPrePaint` document lifecycle state, this class is called to walk the During `InPrePaint` document lifecycle state, this class is called to walk the
...@@ -626,12 +510,82 @@ for a much more detail about multicolumn/pagination. ...@@ -626,12 +510,82 @@ for a much more detail about multicolumn/pagination.
### Paint invalidation ### Paint invalidation
[`PaintInvalidator`](paint_invalidator.h) [`PaintInvalidator`](paint_invalidator.h)
This class replaces [`PaintInvalidationState`] for SlimmingPaintInvalidation. Paint invalidator marks anything that need to be painted differently from the
The main difference is that in PaintInvalidator, visual rects and locations original cached painting.
are computed by `GeometryMapper`(../../platform/graphics/paint/geometry_mapper.h),
based on paint properties produced by `PaintPropertyTreeBuilder`. During the document lifecycle stages prior to PrePaint, objects are marked for
needing paint invalidation checking if needed by style change, layout change,
compositing change, etc. In PrePaint stage, we traverse the layout tree in
pre-order, crossing frame boundaries, for marked subtrees and objects and
invalidate display item clients that will generate different display items.
At the beginning of the PrePaint tree walk, a root `PaintInvalidatorContext`
is created for the root `LayoutView`. During the tree walk, one
`PaintInvalidatorContext` is created for each visited object based on the
`PaintInvalidatorContext` passed from the parent object. It tracks the following
information to provide O(1) complexity access to them if possible:
* Paint invalidation container (Slimming Paint v1 only): Since as indicated by
the definitions in [Glossaries](#other-glossaries), the paint invalidation
container for stacked objects can differ from normal objects, we have to
track both separately. Here is an example:
<div style="overflow: scroll">
<div id=A style="position: absolute"></div>
<div id=B></div>
</div>
If the scroller is composited (for high-DPI screens for example), it is the
paint invalidation container for div B, but not A.
* Painting layer: the layer which will initiate painting of the current
object. It's the same value as `LayoutObject::PaintingLayer()`.
`PaintInvalidator`[PaintInvalidator.h] initializes `PaintInvalidatorContext`
for the current object, then calls `LayoutObject::InvalidatePaint()` which
calls the object's paint invalidator (e.g. `BoxPaintInvalidator`) to complete
paint invalidation of the object.
#### Paint invalidation of text
Text is painted by `InlineTextBoxPainter` using `InlineTextBox` as display
item client. Text backgrounds and masks are painted by `InlineTextFlowPainter`
using `InlineFlowBox` as display item client. We should invalidate these display
item clients when their painting will change.
`LayoutInline`s and `LayoutText`s are marked for full paint invalidation if
needed when new style is set on them. During paint invalidation, we invalidate
the `InlineFlowBox`s directly contained by the `LayoutInline` in
`LayoutInline::InvalidateDisplayItemClients()` and `InlineTextBox`s contained by
the `LayoutText` in `LayoutText::InvalidateDisplayItemClients()`. We don't need
to traverse into the subtree of `InlineFlowBox`s in
`LayoutInline::InvalidateDisplayItemClients()` because the descendant
`InlineFlowBox`s and `InlineTextBox`s will be handled by their owning
`LayoutInline`s and `LayoutText`s, respectively, when changed style is
propagated.
#### Specialty of `::first-line`
`::first-line` pseudo style dynamically applies to all `InlineBox`'s in the
first line in the block having `::first-line` style. The actual applied style is
computed from the `::first-line` style and other applicable styles.
If the first line contains any `LayoutInline`, we compute the style from the
`::first-line` style and the style of the `LayoutInline` and apply the computed
style to the first line part of the `LayoutInline`. In Blink's style
implementation, the combined first line style of `LayoutInline` is identified
with `FIRST_LINE_INHERITED` pseudo ID.
The normal paint invalidation of texts doesn't work for first line because
* `ComputedStyle::VisualInvalidationDiff()` can't detect first line style
changes;
* The normal paint invalidation is based on whole LayoutObject's, not aware of
the first line.
TODO(wangxianzhu): Combine documentation of PaintInvalidation phase into here. We have a special path for first line style change: the style system informs the
layout system when the computed first-line style changes through
`LayoutObject::FirstLineStyleDidChange()`. When this happens, we invalidate all
`InlineBox`es in the first line.
## Paint ## Paint
......
...@@ -17,7 +17,7 @@ replaces. ...@@ -17,7 +17,7 @@ replaces.
## Paint artifact ## Paint artifact
The SPv2 [paint artifact](PaintArtifact.h) consists of a list of display items The SPv2 [paint artifact](paint_artifact.h) consists of a list of display items
in paint order (ideally mostly or all drawings), partitioned into *paint chunks* in paint order (ideally mostly or all drawings), partitioned into *paint chunks*
which define certain *paint properties* which affect how the content should be which define certain *paint properties* which affect how the content should be
drawn or composited. drawn or composited.
...@@ -31,38 +31,33 @@ chunk is associated with a transform node, whose matrix should be multiplied by ...@@ -31,38 +31,33 @@ chunk is associated with a transform node, whose matrix should be multiplied by
its ancestor transform nodes in order to compute the final transformation matrix its ancestor transform nodes in order to compute the final transformation matrix
to the screen. to the screen.
*** note See [`ObjectPaintProperties`](../../../core/paint/object_paint_properties.h) for
Support for all paint properties has yet to be implemented in SPv2. description of all paint properties that we create for a `LayoutObject`.
***
*** aside Paint properties are represented by four paint property trees (transform, clip,
TODO(jbroman): Explain the semantics of transforms, clips, scrolls and effects effect and scroll) each of which contains corresponding type of
as support for them is added to SPv2. [paint property nodes](paint_property_node.h). Each paint property node has a
*** pointer to the parent node. The parent node pointers link the paint property
nodes in a tree.
### Transforms ### Transforms
Each paint chunk is associated with a [transform node](TransformPaintPropertyNode.h), Each paint chunk is associated with a [transform node](transform_paint_property_node.h),
which defines the coordinate space in which the content should be painted. which defines the coordinate space in which the content should be painted.
Each transform node has: Each transform node has:
* a 4x4 [`TransformationMatrix`](../../transforms/TransformationMatrix.h) * a 4x4 [`TransformationMatrix`](../../transforms/transformation_matrix.h)
* a 3-dimensional transform origin, which defines the origin relative to which * a 3-dimensional transform origin, which defines the origin relative to which
the transformation matrix should be applied (e.g. a rotation applied with some the transformation matrix should be applied (e.g. a rotation applied with some
transform origin will rotate the plane about that point) transform origin will rotate the plane about that point)
* a pointer to the parent node, which defines the coordinate space relative to
which the above should be interpreted
* a boolean indicating whether the transform should be projected into the plane * a boolean indicating whether the transform should be projected into the plane
of its parent (i.e., whether the total transform inherited from its parent of its parent (i.e., whether the total transform inherited from its parent
should be flattened before this node's transform is applied and propagated to should be flattened before this node's transform is applied and propagated to
children) children)
* an integer rendering context ID; content whose transform nodes share a * an integer rendering context ID; content whose transform nodes share a
rendering context ID should sort together rendering context ID should sort together
* other fields, see [the header file](transform_paint_property_node.h)
The parent node pointers link the transform nodes in a hierarchy (the *transform
tree*), which defines how the transform for any painted content can be
determined.
***promo ***promo
The painting system may create transform nodes which don't affect the position The painting system may create transform nodes which don't affect the position
...@@ -80,60 +75,57 @@ imply any 3D sorting. ...@@ -80,60 +75,57 @@ imply any 3D sorting.
### Clips ### Clips
Each paint chunk is associated with a [clip node](ClipPaintPropertyNode.h), Each paint chunk is associated with a [clip node](clip_paint_property_node.h),
which defines the raster region that will be applied on the canvas when which defines the raster region that will be applied on the canvas when
the chunk is rastered. the chunk is rastered.
Each clip node has: Each clip node has:
* A float rect with (optionally) rounded corner radius. * A float rect with (optionally) rounded corner radius.
* An optional clip path if the clip is a clip path.
* An associated transform node, which the clip rect is based on. * An associated transform node, which the clip rect is based on.
The raster region defined by a node is the rounded rect transformed to the The raster region defined by a node is the rounded rect and/or clip path
root space, intersects with the raster region defined by its parent clip node transformed to the root space, intersects with the raster region defined by its
(if not root). parent clip node (if not root).
### Scrolling
Each paint chunk is associated with a [scroll node](ScrollPaintPropertyNode.h)
which defines information about how a subtree scrolls so threads other than the
main thread can perform scrolling. Scroll information includes:
* Which directions, if any, are scrollable by the user.
* A reference to a [transform node](TransformPaintPropertyNode.h) which contains
a 2d scroll offset.
* The extent that can be scrolled. For example, an overflow clip of size 7x9
with scrolling contents of size 7x13 can scroll 4px vertically and none
horizontally.
To ensure geometry operations are simple and only deal with transforms, the
scroll offset is stored as a 2d transform in the transform tree.
### Effects ### Effects
Each paint chunk is associated with an [effect node](EffectPaintPropertyNode.h), Each paint chunk is associated with an [effect node](effect_paint_property_node.h),
which defines the effect (opacity, transfer mode, filter, mask, etc.) that which defines the effect (opacity, transfer mode, filter, mask, etc.) that
should be applied to the content before or as it is composited into the content should be applied to the content before or as it is composited into the content
below. below.
Each effect node has: Each effect node has:
* a floating-point opacity (from 0 to 1, inclusive) * effects, including opacity, transfer mode, filter, mask, etc.
* a pointer to the parent node, which will be applied to the result of this * an optional associated clip node which clips the output of the effect when
effect before or as it is composited into its parent in the effect tree composited into the current backdrop.
* an associated transform node which defines the geometry space of some
geometry-related effects (e.g. some filters).
The paret node pointers link the effect nodes in a hierarchy (the *effect The hierarchy in the *effect tree* defines the dependencies between
tree*), which defines the dependencies between rasterization of different rasterization of different contents.
contents.
One can imagine each effect node as corresponding roughly to a bitmap that is One can imagine each effect node as corresponding roughly to a bitmap that is
drawn before being composited into another bitmap, though for implementation drawn before being composited into another bitmap, though for implementation
reasons this may not be how it is actually implemented. reasons this may not be how it is actually implemented.
*** aside ### Scrolling
TODO(jbroman): Explain the connection with the transform and clip trees, once it
exists, as well as effects other than opacity. Each paint chunk is associated with a [scroll node](scroll_paint_property_node.h)
*** which defines information about how a subtree scrolls so threads other than the
main thread can perform scrolling. Scroll information includes:
* Which directions, if any, are scrollable by the user.
* A reference to a [transform node](transform_paint_property_node.h) which contains
a 2d scroll offset.
* The extent that can be scrolled. For example, an overflow clip of size 7x9
with scrolling contents of size 7x13 can scroll 4px vertically and none
horizontally.
To ensure geometry operations are simple and only deal with transforms, the
scroll offset is stored as a 2d transform in the transform tree.
## Display items ## Display items
...@@ -177,13 +169,6 @@ in the compositor requires both property trees (scroll nodes) and a scrollable ...@@ -177,13 +169,6 @@ in the compositor requires both property trees (scroll nodes) and a scrollable
`cc::layer` in paint order. This should be associated with the scroll `cc::layer` in paint order. This should be associated with the scroll
translation paint property node as well as any overflow clip nodes. translation paint property node as well as any overflow clip nodes.
### Paired begin/end display items
*** aside
TODO(jbroman): Describe how these work, once we've worked out what happens to
them in SPv2.
***
## Paint controller ## Paint controller
Callers use `GraphicsContext` (via its drawing methods, and its Callers use `GraphicsContext` (via its drawing methods, and its
...@@ -212,50 +197,9 @@ and [Paint invalidation](../../../core/paint/README.md#paint-invalidation) for ...@@ -212,50 +197,9 @@ and [Paint invalidation](../../../core/paint/README.md#paint-invalidation) for
more details about how caching and invalidation are handled in blink core more details about how caching and invalidation are handled in blink core
module using `PaintController` API. module using `PaintController` API.
We use 'cache generation' which is a unique id of cache status in each
`DisplayItemClient` and `PaintController` to determine if the client is validly
cached by a `PaintController`.
A paint controller sets its cache generation to
`DisplayItemCacheGeneration::next()` at the end of each
`commitNewDisplayItems()`, and updates the cache generation of each client with
cached drawings by calling `DisplayItemClient::setDisplayItemsCached()`.
A display item is treated as validly cached in a paint controller if its cache
generation matches the paint controller's cache generation.
A cache generation value smaller than `kFirstValidGeneration` matches no
other cache generations thus is always treated as invalid. When a
`DisplayItemClient` is invalidated, we set its cache generation to one of
`PaintInvalidationReason` values which are smaller than `kFirstValidGeneration`.
When a `PaintController` is cleared (e.g. when the corresponding `GraphicsLayer`
is fully invalidated), we also invalidate its cache generation.
For now we use a uint32_t variable to store cache generation. Assuming there is
an animation in 60fps needing main-thread repaint, the cache generation will
overflow after 2^32/86400/60 = 828 days. The time may be shorter if there are
multiple animating `PaintController`s in the same process. When it overflows,
we may treat some object that is not cached as cached if the following
conditions are all met:
* the object was painted when the cache generation was *n*;
* the object has been neither painted nor invalidated since cache generation
*n*;
* when the cache generation wraps back to exact *n*, the object happens to be
painted again.
As the paint controller doesn't have cached display items for the object, there
will be corrupted painting or assertion failure. The chance is too low to be
concerned.
SPv1 only: If a display item is painted on multiple paint controllers, because
cache generations are unique, the client's cache generation matches the last
paint controller only. The client will be treated as invalid on other paint
controllers regardless if it's validly cached by these paint controllers.
The situation is very rare (about 0.07% clients were painted on multiple paint
controllers in a [Cluster Telemetry run](https://ct.skia.org/chromium_perf_runs)
(run 803) so the performance penalty is trivial.
## Paint artifact compositor ## Paint artifact compositor
The [`PaintArtifactCompositor`](PaintArtifactCompositor.h) is responsible for The [`PaintArtifactCompositor`](paint_artifact_compositor.h) is responsible for
consuming the `PaintArtifact` produced by the `PaintController`, and converting consuming the `PaintArtifact` produced by the `PaintController`, and converting
it into a form suitable for the compositor to consume. it into a form suitable for the compositor to consume.
...@@ -270,11 +214,65 @@ In the future we would like to explore moving to a single shared property tree ...@@ -270,11 +214,65 @@ In the future we would like to explore moving to a single shared property tree
representation across both cc and representation across both cc and
Blink. See [Web Page Geometries](https://goo.gl/MwVIto) for more. Blink. See [Web Page Geometries](https://goo.gl/MwVIto) for more.
## Raster invalidation
This is to mark which parts of the composited layers need to be re-rasterized to
reflect changes of painting, by comparing the current paint artifact against the
previous paint artifact. It's the last step of painting.
It's done in two levels:
* Paint chunk level (`RasterInvalidator`](raster_invalidator.h): matches each
paint chunk in the current paint artifact against the corresponding paint
chunk in the previous paint artifact, by matching their ids. There are
following cases:
* A new paint chunk doesn't match any old paint chunk (appearing): The bounds
of the new paint chunk in the composited layer will be fully raster
invalidated.
* An old paint chunk doesn't match any new paint chunk (disappearing): The
bounds of the old paint chunk in the composited layer will be fully raster
invalidated.
* A new paint chunk matches an old paint chunk:
* The new paint chunk is moved backward (reordering): this may expose other
chunks that was previously covered by it: Both of the old bounds and the
new bounds will be fully raster invalidated.
* Paint properties of the paint chunk changed:
* If only clip changed, the difference between the old bounds and
the new bounds will be raster invalidated (i.e. do incremental
invalidation).
* Otherwise, both of the old bounds and the new bounds will be fully
raster invalidated.
* Otherwise, check for changed display items within the paint chunk.
* Display item level (`DisplayItemRasterInvalidator`](display_item_raster_invalidator.h]:
This is executed when a new chunk matches an old chunk in-order and paint
properties didn't change. The algorithm checks changed display items within a
paint chunk.
* Similar to the paint chunk level, the visual rects (mapped to the space of
the composited layer) of appearing, disappearing, reordering display items
are fully raster invalidated.
* If a new paint chunk in-order matches an old paint chunk, if the display
item client has been [paint invalidated](../../../core/paint/README.md#paint-invalidation),
we will do full raster invalidation (which invalidates the old visual rect
and the new visual rect in the composted layer) or incremental raster
invalidation (which invalidates the difference between the old visual rect
and the new visual rect) according to the paint invalidation reason.
## Geometry routines ## Geometry routines
The [`GeometryMapper`](GeometryMapper.h) is responsible for efficiently computing The [`GeometryMapper`](geometry_mapper.h) is responsible for efficiently computing
visual and transformed rects of display items in the coordinate space of ancestor visual and transformed rects of display items in the coordinate space of ancestor
[`PropertyTreeState`](PropertyTreeState.h)s. [`PropertyTreeState`](property_tree_state.h)s.
The transformed rect of a display item in an ancestor `PropertyTreeState` is The transformed rect of a display item in an ancestor `PropertyTreeState` is
that rect, multiplied by the transforms between the display item's that rect, multiplied by the transforms between the display item's
......
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