Commit 23f34f4e authored by chrishtr's avatar chrishtr Committed by Commit bot

Introduce FragmentData, and put ObjectPaintProperties into it

This is a step towards supporting multicol in SPv2.

BUG=648274
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:linux_layout_tests_slimming_paint_v2

Review-Url: https://codereview.chromium.org/2844803007
Cr-Commit-Position: refs/heads/master@{#468207}
parent 276cc56b
...@@ -1810,7 +1810,9 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver, ...@@ -1810,7 +1810,9 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// The following non-const functions for ObjectPaintProperties should only // The following non-const functions for ObjectPaintProperties should only
// be called from PaintPropertyTreeBuilder. // be called from PaintPropertyTreeBuilder.
ObjectPaintProperties& EnsurePaintProperties() { ObjectPaintProperties& EnsurePaintProperties() {
return layout_object_.EnsureRarePaintData().EnsurePaintProperties(); return layout_object_.EnsureRarePaintData()
.EnsureFragment()
.EnsurePaintProperties();
} }
ObjectPaintProperties* PaintProperties() { ObjectPaintProperties* PaintProperties() {
if (auto* paint_data = layout_object_.GetRarePaintData()) if (auto* paint_data = layout_object_.GetRarePaintData())
...@@ -1818,8 +1820,10 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver, ...@@ -1818,8 +1820,10 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
return nullptr; return nullptr;
} }
void ClearPaintProperties() { void ClearPaintProperties() {
if (auto* paint_data = layout_object_.GetRarePaintData()) if (auto* paint_data = layout_object_.GetRarePaintData()) {
paint_data->ClearPaintProperties(); if (auto* fragment = paint_data->Fragment())
fragment->ClearPaintProperties();
}
} }
// The following non-const functions for local border box properties should // The following non-const functions for local border box properties should
......
...@@ -56,6 +56,8 @@ blink_core_sources("paint") { ...@@ -56,6 +56,8 @@ blink_core_sources("paint") {
"FirstMeaningfulPaintDetector.h", "FirstMeaningfulPaintDetector.h",
"FloatClipRecorder.cpp", "FloatClipRecorder.cpp",
"FloatClipRecorder.h", "FloatClipRecorder.h",
"FragmentData.cpp",
"FragmentData.h",
"FramePainter.cpp", "FramePainter.cpp",
"FramePainter.h", "FramePainter.h",
"FrameSetPainter.cpp", "FrameSetPainter.cpp",
......
// Copyright 2017 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.
#include "core/paint/FragmentData.h"
#include "core/paint/ObjectPaintProperties.h"
namespace blink {
ObjectPaintProperties& FragmentData::EnsurePaintProperties() {
if (!paint_properties_)
paint_properties_ = ObjectPaintProperties::Create();
return *paint_properties_.get();
}
void FragmentData::ClearPaintProperties() {
paint_properties_.reset(nullptr);
}
} // namespace blink
// Copyright 2017 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.
#ifndef FragmentData_h
#define FragmentData_h
#include "core/paint/ObjectPaintProperties.h"
namespace blink {
class ObjectPaintProperties;
// Represents the data for a particular fragment of a LayoutObject.
// Only LayoutObjects with a self-painting PaintLayer may have more than one
// FragmentDeta, and even then only when they are inside of multicol.
// See README.md.
class CORE_EXPORT FragmentData {
public:
static std::unique_ptr<FragmentData> Create() {
return WTF::WrapUnique(new FragmentData());
}
ObjectPaintProperties* PaintProperties() const {
return paint_properties_.get();
}
ObjectPaintProperties& EnsurePaintProperties();
void ClearPaintProperties();
FragmentData* NextFragment() { return next_fragment_.get(); }
private:
// Holds references to the paint property nodes created by this object.
std::unique_ptr<ObjectPaintProperties> paint_properties_;
std::unique_ptr<FragmentData> next_fragment_;
};
} // namespace blink
#endif // FragmentData_h
...@@ -11,14 +11,14 @@ the following document lifecycle states: ...@@ -11,14 +11,14 @@ the following document lifecycle states:
### Stacked elements and stacking contexts ### Stacked elements and stacking contexts
This chapter is basically a clarification of [CSS 2.1 appendix E. Elaborate description This chapter is basically a clarification of [CSS 2.1 appendix E. Elaborate
of Stacking Contexts](http://www.w3.org/TR/CSS21/zindex.html). description of Stacking Contexts](http://www.w3.org/TR/CSS21/zindex.html).
Note: we use 'element' instead of 'object' in this chapter to keep consistency with Note: we use 'element' instead of 'object' in this chapter to keep consistency
the spec. We use 'object' in other places in this document. with the spec. We use 'object' in other places in this document.
According to the documentation, we can have the following types of elements that are According to the documentation, we can have the following types of elements that
treated in different ways during painting: are treated in different ways during painting:
* Stacked objects: objects that are z-ordered in stacking contexts, including: * Stacked objects: objects that are z-ordered in stacking contexts, including:
...@@ -30,27 +30,30 @@ treated in different ways during painting: ...@@ -30,27 +30,30 @@ treated in different ways during painting:
managed by real stacking contexts. They are positioned elements with managed by real stacking contexts. They are positioned elements with
`z-index: auto` (E.2.8 in the documentation). `z-index: auto` (E.2.8 in the documentation).
They must be managed by the enclosing stacking context as stacked elements They must be managed by the enclosing stacking context as stacked
because `z-index:auto` and `z-index:0` are considered equal for stacking elements because `z-index:auto` and `z-index:0` are considered equal for
context sorting and they may interleave by DOM order. stacking context sorting and they may interleave by DOM order.
The difference of a stacked element of this type from a real stacking context The difference of a stacked element of this type from a real stacking
is that it doesn't manage z-ordering of stacked descendants. These descendants context is that it doesn't manage z-ordering of stacked descendants.
are managed by the parent stacking context of this stacked element. These descendants are managed by the parent stacking context of this
stacked element.
"Stacked element" is not defined as a formal term in the documentation, but we found "Stacked element" is not defined as a formal term in the documentation, but
it convenient to use this term to refer to any elements participating z-index ordering we found it convenient to use this term to refer to any elements
in stacking contexts. participating z-index ordering in stacking contexts.
A stacked element is represented by a `PaintLayerStackingNode` associated with a A stacked element is represented by a `PaintLayerStackingNode` associated
`PaintLayer`. It's painted as self-painting `PaintLayer`s by `PaintLayerPainter` with a `PaintLayer`. It's painted as self-painting `PaintLayer`s by
by executing all of the steps of the painting algorithm explained in the documentation `PaintLayerPainter`
for the element. When painting a stacked element of the second type, we don't by executing all of the steps of the painting algorithm explained in the
paint its stacked descendants which are managed by the parent stacking context. documentation for the element. When painting a stacked element of the second
type, we don't paint its stacked descendants which are managed by the parent
stacking context.
* Non-stacked pseudo stacking contexts: elements that are not stacked, but paint * Non-stacked pseudo stacking contexts: elements that are not stacked, but
their descendants (excluding any stacked contents) as if they created stacking paint their descendants (excluding any stacked contents) as if they created
contexts. This includes stacking contexts. This includes
* inline blocks, inline tables, inline-level replaced elements * inline blocks, inline tables, inline-level replaced elements
(E.2.7.2.1.4 in the documentation) (E.2.7.2.1.4 in the documentation)
...@@ -59,52 +62,52 @@ treated in different ways during painting: ...@@ -59,52 +62,52 @@ treated in different ways during painting:
* [grid items](http://www.w3.org/TR/css-grid-1/#z-order) * [grid items](http://www.w3.org/TR/css-grid-1/#z-order)
* custom scrollbar parts * custom scrollbar parts
They are painted by `ObjectPainter::paintAllPhasesAtomically()` which executes They are painted by `ObjectPainter::paintAllPhasesAtomically()` which
all of the steps of the painting algorithm explained in the documentation, except executes all of the steps of the painting algorithm explained in the
ignores any descendants which are positioned or have non-auto z-index (which is documentation, except ignores any descendants which are positioned or have
achieved by skipping descendants with self-painting layers). non-auto z-index (which is achieved by skipping descendants with
self-painting layers).
* Other normal elements. * Other normal elements.
### Other glossaries ### Other glossaries
* Paint container: the parent of an object for painting, as defined by [CSS2.1 spec * Paint container: the parent of an object for painting, as defined by
for painting]((http://www.w3.org/TR/CSS21/zindex.html)). For regular objects, [CSS2.1 spec for painting]((http://www.w3.org/TR/CSS21/zindex.html)). For
this is the parent in the DOM. For stacked objects, it's the containing stacking regular objects, this is the parent in the DOM. For stacked objects, it's
context-inducing object. the containing stacking context-inducing object.
* Paint container chain: the chain of paint ancestors between an element and the * Paint container chain: the chain of paint ancestors between an element and
root of the page. the root of the page.
* Compositing container: an implementation detail of Blink, which uses * Compositing container: an implementation detail of Blink, which uses
`PaintLayer`s to represent some layout objects. It is the ancestor along the paint `PaintLayer`s to represent some layout objects. It is the ancestor along the
ancestor chain which has a PaintLayer. Implemented in paint ancestor chain which has a PaintLayer. Implemented in
`PaintLayer::compositingContainer()`. Think of it as skipping intermediate normal `PaintLayer::compositingContainer()`. Think of it as skipping intermediate
objects and going directly to the containing stacked object. normal objects and going directly to the containing stacked object.
* Compositing container chain: same as paint chain, but for compositing container. * Compositing container chain: same as paint chain, but for compositing
container.
* Paint invalidation container: the nearest object on the compositing container * Paint invalidation container: the nearest object on the compositing
chain which is composited. container chain which is composited.
* 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.
## Paint invalidation ## Paint invalidation
Paint invalidation marks anything that need to be painted differently from the original Paint invalidation marks anything that need to be painted differently from the
cached painting. original cached painting.
### Slimming paint v1 ### Slimming paint v1
Though described in this document, most of the actual paint invalidation code is under Paint invalidation is a document cycle stage after compositing update and before
`Source/core/layout`. paint. During the previous stages, objects are marked for needing paint
invalidation checking if needed by style change, layout change, compositing
Paint invalidation is a document cycle stage after compositing update and before paint. change, etc. In paint invalidation stage, we traverse the layout tree in
During the previous stages, objects are marked for needing paint invalidation checking pre-order, crossing frame boundaries, for marked subtrees and objects and send
if needed by style change, layout change, compositing change, etc. In paint invalidation stage, the following information to `GraphicsLayer`s and `PaintController`s:
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 * invalidated display item clients: must invalidate all display item clients
that will generate different display items. that will generate different display items.
...@@ -115,163 +118,214 @@ and objects and send the following information to `GraphicsLayer`s and `PaintCon ...@@ -115,163 +118,214 @@ and objects and send the following information to `GraphicsLayer`s and `PaintCon
#### `PaintInvalidationState` #### `PaintInvalidationState`
`PaintInvalidationState` is an optimization used during the paint invalidation phase. Before `PaintInvalidationState` is an optimization used during the paint invalidation
the paint invalidation tree walk, a root `PaintInvalidationState` is created for the root phase. Before the paint invalidation tree walk, a root `PaintInvalidationState`
`LayoutView`. During the tree walk, one `PaintInvalidationState` is created for each visited is created for the root `LayoutView`. During the tree walk, one
object based on the `PaintInvalidationState` passed from the parent object. `PaintInvalidationState` is created for each visited object based on the
It tracks the following information to provide O(1) complexity access to them if possible: `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), * Paint invalidation container: Since as indicated by the definitions in
the paint invalidation container for stacked objects can differ from normal objects, we [Glossaries](#Other glossaries), the paint invalidation container for
have to track both separately. Here is an example: stacked objects can differ from normal objects, we have to track both
separately. Here is an example:
<div style="overflow: scroll"> <div style="overflow: scroll">
<div id=A style="position: absolute"></div> <div id=A style="position: absolute"></div>
<div id=B></div> <div id=B></div>
</div> </div>
If the scroller is composited (for high-DPI screens for example), it is the paint invalidation If the scroller is composited (for high-DPI screens for example), it is the
container for div B, but not A. paint invalidation container for div B, but not A.
* Paint offset and clip rect: if possible, `PaintInvalidationState` accumulates paint offsets * Paint offset and clip rect: if possible, `PaintInvalidationState`
and overflow clipping rects from the paint invalidation container to provide O(1) complexity to accumulates paint offsets and overflow clipping rects from the paint
map a point or a rect in current object's local space to paint invalidation container's space. invalidation container to provide O(1) complexity to map a point or a rect
Because locations of objects are determined by their containing blocks, and the containing block in current object's local space to paint invalidation container's space.
for absolute-position objects differs from non-absolute, we track paint offsets and overflow Because locations of objects are determined by their containing blocks, and
clipping rects for absolute-position objects separately. 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, In cases that accurate accumulation of paint offsets and clipping rects is
we will fall back to slow-path using `LayoutObject::localToAncestorPoint()` or impossible, we will fall back to slow-path using
`LayoutObject::mapToVisualRectInAncestorSpace()`. This includes the following cases: `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, * An object has transform related property, is multi-column or has flipped
causing we can't simply accumulate paint offset for mapping a local rect to paint invalidation blocks writing-mode, causing we can't simply accumulate paint offset for
container; mapping a local rect to paint invalidation container;
* An object has has filter (including filter induced by reflection), which * An object has has filter (including filter induced by reflection), which
needs to expand visual rect for descendants, because currently we don't needs to expand visual rect for descendants, because currently we don't
include and filter extents into visual overflow; include and filter extents into visual overflow;
* For a fixed-position object we calculate its offset using `LayoutObject::localToAncestorPoint()`, * For a fixed-position object we calculate its offset using
but map for its descendants in fast-path if no other things prevent us from doing this; `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 * Because we track paint offset from the normal paint invalidation container
to use `m_paintInvalidationContainerForStackedContents` and it's different from the normal paint only, if we are going to use
invalidation container, we have to force slow-path because the accumulated paint offset is not `m_paintInvalidationContainerForStackedContents` and it's different from the
usable; 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 * We also stop to track paint offset and clipping rect for absolute-position
`m_paintInvalidationContainerForStackedContents` becomes different from `m_paintInvalidationContainer`. objects when `m_paintInvalidationContainerForStackedContents` becomes
different from `m_paintInvalidationContainer`.
### Paint invalidation of texts ### Paint invalidation of texts
Texts are painted by `InlineTextBoxPainter` using `InlineTextBox` as display item client. Texts are painted by `InlineTextBoxPainter` using `InlineTextBox` as display
Text backgrounds and masks are painted by `InlineTextFlowPainter` using `InlineFlowBox` item client. Text backgrounds and masks are painted by `InlineTextFlowPainter`
as display item client. We should invalidate these display item clients when their painting using `InlineFlowBox` as display item client. We should invalidate these display
will change. item clients when their painting will change.
`LayoutInline`s and `LayoutText`s are marked for full paint invalidation if needed when `LayoutInline`s and `LayoutText`s are marked for full paint invalidation if
new style is set on them. During paint invalidation, we invalidate the `InlineFlowBox`s needed when new style is set on them. During paint invalidation, we invalidate
directly contained by the `LayoutInline` in `LayoutInline::invalidateDisplayItemClients()` and the `InlineFlowBox`s directly contained by the `LayoutInline` in
`InlineTextBox`s contained by the `LayoutText` in `LayoutText::invalidateDisplayItemClients()`. `LayoutInline::invalidateDisplayItemClients()` and `InlineTextBox`s contained by
We don't need to traverse into the subtree of `InlineFlowBox`s in `LayoutInline::invalidateDisplayItemClients()` the `LayoutText` in `LayoutText::invalidateDisplayItemClients()`. We don't need
because the descendant `InlineFlowBox`s and `InlineTextBox`s will be handled by their to traverse into the subtree of `InlineFlowBox`s in
owning `LayoutInline`s and `LayoutText`s, respectively, when changed style is propagated. `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` ### Specialty of `::first-line`
`::first-line` pseudo style dynamically applies to all `InlineBox`'s in the first line in the `::first-line` pseudo style dynamically applies to all `InlineBox`'s in the
block having `::first-line` style. The actual applied style is computed from the `::first-line` first line in the block having `::first-line` style. The actual applied style is
style and other applicable styles. 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 If the first line contains any `LayoutInline`, we compute the style from the
and the style of the `LayoutInline` and apply the computed style to the first line part of the `::first-line` style and the style of the `LayoutInline` and apply the computed
`LayoutInline`. In blink's style implementation, the combined first line style of `LayoutInline` style to the first line part of the `LayoutInline`. In Blink's style
is identified with `FIRST_LINE_INHERITED` pseudo ID. 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 The normal paint invalidation of texts doesn't work for first line because
* `ComputedStyle::visualInvalidationDiff()` can't detect first line style changes; * `ComputedStyle::visualInvalidationDiff()` can't detect first line style
* The normal paint invalidation is based on whole LayoutObject's, not aware of the first line. 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 We have a special path for first line style change: the style system informs the
when the computed first-line style changes through `LayoutObject::firstLineStyleDidChange()`. layout system when the computed first-line style changes through
When this happens, we invalidate all `InlineBox`es in the first line. `LayoutObject::firstLineStyleDidChange()`. When this happens, we invalidate all
`InlineBox`es in the first line.
### Slimming paint v2 ### Slimming paint v2
TODO(wangxianzhu): add details TODO(wangxianzhu): add details
## [`PrePaintTreeWalk`](PrePaintTreeWalk.h) (Slimming paint v2 only) ## [`PrePaintTreeWalk`](PrePaintTreeWalk.h) (Slimming Paint invalidation/v2 only)
During `InPrePaint` document lifecycle state, this class is called to walk the
whole layout tree, beginning from the root FrameView, across frame boundaries.
We do the following during the tree walk:
### Building paint property trees
[`PaintPropertyTreeBuilder`](PaintPropertyTreeBuilder.h)
This class is responsible for building property trees
(see [the platform paint README file](../../platform/graphics/paint/README.md)).
Each `PaintLayer`'s `LayoutObject` has one or more `FragmentData` objects (see
below for more on fragments). Every `FragmentData` has an
`ObjectPaintProperties` object if any property nodes are induced by it. For
example, if the object has a transform, its `ObjectPaintProperties::Transform()`
field points at the `TransformPaintPropertyNode` representing that transform.
The `NeedsPaintPropertyUpdate`, `SubtreeNeedsPaintPropertyUpdate` and
`DescendantNeedsPaintPropertyUpdate` dirty bits on `LayoutObject` control how
much of the layout tree is traversed during each `PrePaintTreeWalk`.
During `InPrePaint` document lifecycle state, this class is called to walk the whole ### Fragments
layout tree, beginning from the root FrameView, across frame boundaries. We do the
following during the tree walk:
* Building paint property tree: creates paint property tree nodes for special In the absence of multicolumn/pagination, there is a 1:1 correspondence between
things in the layout tree, including but not limit to: overflow clip, transform, self-painting `PaintLayer`s and `FragmentData`. If there is
fixed-pos, animation, mask, filter, etc. Also sets direct compositing reasons to be multicolumn/pagination, there may be more `FragmentData`s.. If a `PaintLayer`
used later for compositing. has a property node, each of its fragments will have one. The parent of a
fragment's property node is the property node that belongs to the ancestor
`PaintLayer` which is part of the same column. For example, if there are 3
columns and both a parent and child `PaintLayer` have a transform, there will be
3 `FragmentData` objects for the parent, 3 for the child, each `FragmentData`
will have its own `TransformPaintPropertyNode`, and the child's ith fragment's
transform will point to the ith parent's transform.
* Paint invalidation: Not implemented yet. TODO(wangxianzhu): add details after See [`LayoutMultiColumnFlowThread.h`](../layout/LayoutMultiColumnFlowThread.h)
it's implemented. for a much more detail about multicolumn/pagination.
### Paint invalidation: `PaintInvalidator` implements a tree walk that
performs paint invalidation. TODO(wangxianzhu): expand on this.
### [`PaintPropertyTreeBuilder`](PaintPropertyTreeBuilder.h) (Slimming Paint invalidation only)
## Paint result caching ## Paint result caching
`PaintController` holds the previous painting result as a cache of display items. `PaintController` holds the previous painting result as a cache of display
If some painter would generate results same as those of the previous painting, items. If some painter would generate results same as those of the previous
we'll skip the painting and reuse the display items from cache. painting, we'll skip the painting and reuse the display items from cache.
### Display item caching ### Display item caching
When a painter would create a `DrawingDisplayItem` exactly the same as the display item When a painter would create a `DrawingDisplayItem` exactly the same as the
created in the previous painting, we'll reuse the previous one instead of repainting it. display item created in the previous painting, we'll reuse the previous one
instead of repainting it.
### Subsequence caching ### Subsequence caching
When possible, we enclose the display items that `PaintLayerPainter::paintContents()` generates When possible, we enclose the display items that
(including display items generated by sublayers) in a pair of `BeginSubsequence/EndSubsequence` `PaintLayerPainter::paintContents()` generates (including display items
display items. generated by sublayers) in a pair of `BeginSubsequence/EndSubsequence` display
items.
In a subsequence paint, if the layer would generate exactly the same display items, we'll get In a subsequence paint, if the layer would generate exactly the same display
the whole subsequence from the cache instead of repainting them. items, we'll get the whole subsequence from the cache instead of repainting
them.
There are many conditions affecting There are many conditions affecting
* whether we need to generate subsequence for a PaintLayer; * whether we need to generate subsequence for a PaintLayer;
* whether we can use cached subsequence for a PaintLayer. * whether we can use cached subsequence for a PaintLayer.
See `shouldCreateSubsequence()` and `shouldRepaintSubsequence()` in `PaintLayerPainter.cpp` for See `shouldCreateSubsequence()` and `shouldRepaintSubsequence()` in
the conditions. `PaintLayerPainter.cpp` for the conditions.
## Empty paint phase optimization ## Empty paint phase optimization
During painting, we walk the layout tree multiple times for multiple paint phases. Sometimes During painting, we walk the layout tree multiple times for multiple paint
a layer contain nothing needing a certain paint phase and we can skip tree walk for such phases. Sometimes a layer contain nothing needing a certain paint phase and we
empty phases. Now we have optimized `PaintPhaseDescendantBlockBackgroundsOnly`, can skip tree walk for such empty phases. Now we have optimized
`PaintPhaseDescendantOutlinesOnly` and `PaintPhaseFloat` for empty paint phases. `PaintPhaseDescendantBlockBackgroundsOnly`, `PaintPhaseDescendantOutlinesOnly`
and `PaintPhaseFloat` for empty paint phases.
During paint invalidation, we set the containing self-painting layer's `needsPaintPhaseXXX`
flag if the object has something needing to be painted in the paint phase. During paint invalidation, we set the containing self-painting layer's
`needsPaintPhaseXXX` flag if the object has something needing to be painted in
During painting, we check the flag before painting a paint phase and skip the tree walk if the paint phase.
the flag is not set.
During painting, we check the flag before painting a paint phase and skip the
It's hard to clear a `needsPaintPhaseXXX` flag when a layer no longer needs the paint phase, tree walk if the flag is not set.
so we never clear the flags. Instead, we use another set of flags (`previousPaintPhaseXXXWasEmpty`)
to record if a painting of a phase actually produced nothing. We'll skip the next It's hard to clear a `needsPaintPhaseXXX` flag when a layer no longer needs the
painting of the phase if the flag is set, regardless of the corresponding paint phase, so we never clear the flags. Instead, we use another set of flags
`needsPaintPhaseXXX` flag. We will clear the `previousPaintPhaseXXXWasEmpty` flags when (`previousPaintPhaseXXXWasEmpty`) to record if a painting of a phase actually
we paint with different clipping, scroll offset or interest rect from the previous paint. produced nothing. We'll skip the next painting of the phase if the flag is set,
regardless of the corresponding `needsPaintPhaseXXX` flag. We will clear the
We don't clear the `previousPaintPhaseXXXWasEmpty` flags when the layer is marked `needsRepaint`. `previousPaintPhaseXXXWasEmpty` flags when we paint with different clipping,
Instead we clear the flag when the corresponding `needsPaintPhaseXXX` is set. This ensures that scroll offset or interest rect from the previous paint.
we won't clear `previousPaintPhaseXXXWasEmpty` flags when unrelated things changed which won't
We don't clear the `previousPaintPhaseXXXWasEmpty` flags when the layer is
marked `needsRepaint`. Instead we clear the flag when the corresponding
`needsPaintPhaseXXX` is set. This ensures that we won't clear
`previousPaintPhaseXXXWasEmpty` flags when unrelated things changed which won't
cause the paint phases to become non-empty. cause the paint phases to become non-empty.
When layer structure changes, and we are not invalidate paint of the changed subtree, When layer structure changes, and we are not invalidate paint of the changed
we need to manually update the `needsPaintPhaseXXX` flags. For example, if an object changes subtree, we need to manually update the `needsPaintPhaseXXX` flags. For example,
style and creates a self-painting-layer, we copy the flags from its containing self-painting if an object changes style and creates a self-painting-layer, we copy the flags
layer to this layer, assuming that this layer needs all paint phases that its container from its containing self-painting layer to this layer, assuming that this layer
self-painting layer needs. needs all paint phases that its container self-painting layer needs.
We could update the `needsPaintPhaseXXX` flags in a separate tree walk, but that would regress We could update the `needsPaintPhaseXXX` flags in a separate tree walk, but that
performance of the first paint. For slimming paint v2, we can update the flags during the would regress performance of the first paint. For slimming paint v2, we can
pre-painting tree walk to simplify the logics. update the flags during the pre-painting tree walk to simplify the logics.
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#include "core/paint/RarePaintData.h" #include "core/paint/RarePaintData.h"
#include "core/paint/ObjectPaintProperties.h" #include "core/paint/FragmentData.h"
#include "core/paint/PaintLayer.h" #include "core/paint/PaintLayer.h"
namespace blink { namespace blink {
...@@ -17,14 +17,10 @@ void RarePaintData::SetLayer(std::unique_ptr<PaintLayer> layer) { ...@@ -17,14 +17,10 @@ void RarePaintData::SetLayer(std::unique_ptr<PaintLayer> layer) {
layer_ = std::move(layer); layer_ = std::move(layer);
}; };
ObjectPaintProperties& RarePaintData::EnsurePaintProperties() { FragmentData& RarePaintData::EnsureFragment() {
if (!paint_properties_) if (!fragment_data_)
paint_properties_ = ObjectPaintProperties::Create(); fragment_data_ = FragmentData::Create();
return *paint_properties_.get(); return *fragment_data_.get();
}
void RarePaintData::ClearPaintProperties() {
paint_properties_.reset(nullptr);
} }
void RarePaintData::ClearLocalBorderBoxProperties() { void RarePaintData::ClearLocalBorderBoxProperties() {
...@@ -41,13 +37,15 @@ void RarePaintData::SetLocalBorderBoxProperties(PropertyTreeState& state) { ...@@ -41,13 +37,15 @@ void RarePaintData::SetLocalBorderBoxProperties(PropertyTreeState& state) {
PropertyTreeState RarePaintData::ContentsProperties() const { PropertyTreeState RarePaintData::ContentsProperties() const {
DCHECK(local_border_box_properties_); DCHECK(local_border_box_properties_);
PropertyTreeState contents(*local_border_box_properties_); PropertyTreeState contents(*local_border_box_properties_);
if (paint_properties_) { if (fragment_data_) {
if (paint_properties_->ScrollTranslation()) if (auto* properties = fragment_data_->PaintProperties()) {
contents.SetTransform(paint_properties_->ScrollTranslation()); if (properties->ScrollTranslation())
if (paint_properties_->OverflowClip()) contents.SetTransform(properties->ScrollTranslation());
contents.SetClip(paint_properties_->OverflowClip()); if (properties->OverflowClip())
else if (paint_properties_->CssClip()) contents.SetClip(properties->OverflowClip());
contents.SetClip(paint_properties_->CssClip()); else if (properties->CssClip())
contents.SetClip(properties->CssClip());
}
} }
// TODO(chrishtr): cssClipFixedPosition needs to be handled somehow. // TODO(chrishtr): cssClipFixedPosition needs to be handled somehow.
......
...@@ -6,13 +6,13 @@ ...@@ -6,13 +6,13 @@
#define RarePaintData_h #define RarePaintData_h
#include "core/CoreExport.h" #include "core/CoreExport.h"
#include "core/paint/FragmentData.h"
#include "platform/wtf/Allocator.h" #include "platform/wtf/Allocator.h"
#include "platform/wtf/Noncopyable.h" #include "platform/wtf/Noncopyable.h"
namespace blink { namespace blink {
class PropertyTreeState; class PropertyTreeState;
class ObjectPaintProperties;
class PaintLayer; class PaintLayer;
// This is for paint-related data on LayoutObject that is not needed on all // This is for paint-related data on LayoutObject that is not needed on all
...@@ -28,11 +28,15 @@ class CORE_EXPORT RarePaintData { ...@@ -28,11 +28,15 @@ class CORE_EXPORT RarePaintData {
PaintLayer* Layer() { return layer_.get(); } PaintLayer* Layer() { return layer_.get(); }
void SetLayer(std::unique_ptr<PaintLayer>); void SetLayer(std::unique_ptr<PaintLayer>);
FragmentData* Fragment() const { return fragment_data_.get(); }
FragmentData& EnsureFragment();
ObjectPaintProperties* PaintProperties() const { ObjectPaintProperties* PaintProperties() const {
return paint_properties_.get(); if (fragment_data_)
return fragment_data_->PaintProperties();
return nullptr;
} }
ObjectPaintProperties& EnsurePaintProperties();
void ClearPaintProperties();
PropertyTreeState* LocalBorderBoxProperties() const { PropertyTreeState* LocalBorderBoxProperties() const {
return local_border_box_properties_.get(); return local_border_box_properties_.get();
...@@ -52,8 +56,7 @@ class CORE_EXPORT RarePaintData { ...@@ -52,8 +56,7 @@ class CORE_EXPORT RarePaintData {
// depending on the return value of LayoutBoxModelObject::layerTypeRequired(). // depending on the return value of LayoutBoxModelObject::layerTypeRequired().
std::unique_ptr<PaintLayer> layer_; std::unique_ptr<PaintLayer> layer_;
// Holds references to the paint property nodes created by this object. std::unique_ptr<FragmentData> fragment_data_;
std::unique_ptr<ObjectPaintProperties> paint_properties_;
// This is a complete set of property nodes that should be used as a // This is a complete set of property nodes that should be used as a
// starting point to paint a LayoutObject. This data is cached because some // starting point to paint a LayoutObject. This data is cached because some
......
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