Modified: trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp (245370 => 245371)
--- trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp 2019-05-16 02:51:12 UTC (rev 245370)
+++ trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp 2019-05-16 02:51:15 UTC (rev 245371)
@@ -113,6 +113,15 @@
size_t nextChildIndex { 0 };
};
+struct RenderLayerCompositor::OverlapExtent {
+ LayoutRect bounds;
+ bool extentComputed { false };
+ bool hasTransformAnimation { false };
+ bool animationCausesExtentUncertainty { false };
+
+ bool knownToBeHaveExtentUncertainty() const { return extentComputed && animationCausesExtentUncertainty; }
+};
+
struct RenderLayerCompositor::CompositingState {
CompositingState(RenderLayer* compAncestor, bool testOverlap = true)
: compositingAncestor(compAncestor)
@@ -144,16 +153,26 @@
return childState;
}
- void propagateStateFromChildren(const CompositingState& childState)
+ void updateWithDescendantStateAndLayer(const CompositingState& childState, const RenderLayer& layer, const OverlapExtent& layerExtent, bool isUnchangedSubtree = false)
{
// Subsequent layers in the parent stacking context also need to composite.
- subtreeIsCompositing |= childState.subtreeIsCompositing;
- fullPaintOrderTraversalRequired |= childState.fullPaintOrderTraversalRequired;
- }
+ subtreeIsCompositing |= childState.subtreeIsCompositing | layer.isComposited();
+ if (!isUnchangedSubtree)
+ fullPaintOrderTraversalRequired |= childState.fullPaintOrderTraversalRequired;
- void propagateStateFromChildrenForUnchangedSubtree(const CompositingState& childState)
- {
- subtreeIsCompositing |= childState.subtreeIsCompositing;
+ // Turn overlap testing off for later layers if it's already off, or if we have an animating transform.
+ // Note that if the layer clips its descendants, there's no reason to propagate the child animation to the parent layers. That's because
+ // we know for sure the animation is contained inside the clipping rectangle, which is already added to the overlap map.
+ auto canReenableOverlapTesting = [&layer]() {
+ return layer.isComposited() && RenderLayerCompositor::clipsCompositingDescendants(layer);
+ };
+ if ((!childState.testingOverlap && !canReenableOverlapTesting()) || layerExtent.knownToBeHaveExtentUncertainty())
+ testingOverlap = false;
+
+#if ENABLE(CSS_COMPOSITING)
+ if ((layer.isComposited() && layer.hasBlendMode()) || (layer.hasNotIsolatedCompositedBlendingDescendants() && !layer.isolatesCompositedBlending()))
+ hasNotIsolatedCompositedBlendingDescendants = true;
+#endif
}
RenderLayer* compositingAncestor;
@@ -251,15 +270,6 @@
layer.backing()->clearBackingSharingLayers();
}
-struct RenderLayerCompositor::OverlapExtent {
- LayoutRect bounds;
- bool extentComputed { false };
- bool hasTransformAnimation { false };
- bool animationCausesExtentUncertainty { false };
-
- bool knownToBeHaveExtentUncertainty() const { return extentComputed && animationCausesExtentUncertainty; }
-};
-
#if !LOG_DISABLED
static inline bool compositingLogEnabled()
{
@@ -899,37 +909,35 @@
// The children of this layer don't need to composite, unless there is
// a compositing layer among them, so start by inheriting the compositing
// ancestor with subtreeIsCompositing set to false.
- CompositingState childState = compositingState.stateForPaintOrderChildren(layer);
+ CompositingState currentState = compositingState.stateForPaintOrderChildren(layer);
- auto layerWillComposite = [&](bool postDescendants = false) {
+ auto layerWillComposite = [&] {
+ // This layer is going to be composited, so children can safely ignore the fact that there's an
+ // animation running behind this layer, meaning they can rely on the overlap map testing again.
+ currentState.testingOverlap = true;
// This layer now acts as the ancestor for kids.
- childState.compositingAncestor = &layer;
+ currentState.compositingAncestor = &layer;
overlapMap.pushCompositingContainer();
-
- if (postDescendants) {
- childState.subtreeIsCompositing = true;
- addToOverlapMapRecursive(overlapMap, layer);
- }
- // This layer is going to be composited, so children can safely ignore the fact that there's an
- // animation running behind this layer, meaning they can rely on the overlap map testing again.
- childState.testingOverlap = true;
willBeComposited = true;
layerPaintsIntoProvidedBacking = false;
};
+ auto layerWillCompositePostDescendants = [&] {
+ layerWillComposite();
+ currentState.subtreeIsCompositing = true;
+ addToOverlapMapRecursive(overlapMap, layer);
+ };
+
if (willBeComposited) {
- // Tell the parent it has compositing descendants.
- compositingState.subtreeIsCompositing = true;
-
layerWillComposite();
computeExtent(overlapMap, layer, layerExtent);
- childState.ancestorHasTransformAnimation |= layerExtent.hasTransformAnimation;
+ currentState.ancestorHasTransformAnimation |= layerExtent.hasTransformAnimation;
// Too hard to compute animated bounds if both us and some ancestor is animating transform.
layerExtent.animationCausesExtentUncertainty |= layerExtent.hasTransformAnimation && compositingState.ancestorHasTransformAnimation;
} else if (layerPaintsIntoProvidedBacking) {
- childState.backingSharingAncestor = &layer;
+ currentState.backingSharingAncestor = &layer;
overlapMap.pushCompositingContainer();
}
@@ -942,11 +950,11 @@
bool anyDescendantHas3DTransform = false;
for (auto* childLayer : layer.negativeZOrderLayers()) {
- computeCompositingRequirements(&layer, *childLayer, overlapMap, childState, backingSharingState, anyDescendantHas3DTransform);
+ computeCompositingRequirements(&layer, *childLayer, overlapMap, currentState, backingSharingState, anyDescendantHas3DTransform);
// If we have to make a layer for this child, make one now so we can have a contents layer
// (since we need to ensure that the -ve z-order child renders underneath our contents).
- if (!willBeComposited && childState.subtreeIsCompositing) {
+ if (!willBeComposited && currentState.subtreeIsCompositing) {
// make layer compositing
layer.setIndirectCompositingReason(RenderLayer::IndirectCompositingReason::BackgroundLayer);
layerWillComposite();
@@ -954,10 +962,10 @@
}
for (auto* childLayer : layer.normalFlowLayers())
- computeCompositingRequirements(&layer, *childLayer, overlapMap, childState, backingSharingState, anyDescendantHas3DTransform);
+ computeCompositingRequirements(&layer, *childLayer, overlapMap, currentState, backingSharingState, anyDescendantHas3DTransform);
for (auto* childLayer : layer.positiveZOrderLayers())
- computeCompositingRequirements(&layer, *childLayer, overlapMap, childState, backingSharingState, anyDescendantHas3DTransform);
+ computeCompositingRequirements(&layer, *childLayer, overlapMap, currentState, backingSharingState, anyDescendantHas3DTransform);
// If we just entered compositing mode, the root will have become composited (as long as accelerated compositing is enabled).
if (layer.isRenderViewLayer()) {
@@ -970,12 +978,12 @@
// compositing ancestor's backing, and so are still considered for overlap.
// FIXME: When layerExtent has taken animation bounds into account, we also know that the bounds
// include descendants, so we don't need to add them all to the overlap map.
- if (childState.compositingAncestor && !childState.compositingAncestor->isRenderViewLayer())
+ if (currentState.compositingAncestor && !currentState.compositingAncestor->isRenderViewLayer())
addToOverlapMap(overlapMap, layer, layerExtent);
#if ENABLE(CSS_COMPOSITING)
bool isolatedCompositedBlending = layer.isolatesCompositedBlending();
- layer.setHasNotIsolatedCompositedBlendingDescendants(childState.hasNotIsolatedCompositedBlendingDescendants);
+ layer.setHasNotIsolatedCompositedBlendingDescendants(currentState.hasNotIsolatedCompositedBlendingDescendants);
if (layer.isolatesCompositedBlending() != isolatedCompositedBlending) {
// isolatedCompositedBlending affects the result of clippedByAncestor().
layer.setChildrenNeedCompositingGeometryUpdate();
@@ -986,9 +994,9 @@
// Now check for reasons to become composited that depend on the state of descendant layers.
RenderLayer::IndirectCompositingReason indirectCompositingReason;
if (!willBeComposited && canBeComposited(layer)
- && requiresCompositingForIndirectReason(layer, compositingState.compositingAncestor, childState.subtreeIsCompositing, anyDescendantHas3DTransform, layerPaintsIntoProvidedBacking, indirectCompositingReason)) {
+ && requiresCompositingForIndirectReason(layer, compositingState.compositingAncestor, currentState.subtreeIsCompositing, anyDescendantHas3DTransform, layerPaintsIntoProvidedBacking, indirectCompositingReason)) {
layer.setIndirectCompositingReason(indirectCompositingReason);
- layerWillComposite(true);
+ layerWillCompositePostDescendants();
}
if (layer.reflectionLayer()) {
@@ -997,33 +1005,18 @@
}
// Set the flag to say that this layer has compositing children.
- layer.setHasCompositingDescendant(childState.subtreeIsCompositing);
+ layer.setHasCompositingDescendant(currentState.subtreeIsCompositing);
- // setHasCompositingDescendant() may have changed the answer to needsToBeComposited() when clipping, so test that again.
+ // setHasCompositingDescendant() may have changed the answer to needsToBeComposited() when clipping, so test that now.
bool isCompositedClippingLayer = canBeComposited(layer) && clipsCompositingDescendants(layer);
-
- // Turn overlap testing off for later layers if it's already off, or if we have an animating transform.
- // Note that if the layer clips its descendants, there's no reason to propagate the child animation to the parent layers. That's because
- // we know for sure the animation is contained inside the clipping rectangle, which is already added to the overlap map.
- if ((!childState.testingOverlap && !isCompositedClippingLayer) || layerExtent.knownToBeHaveExtentUncertainty())
- compositingState.testingOverlap = false;
-
if (isCompositedClippingLayer & !willBeComposited)
- layerWillComposite(true);
+ layerWillCompositePostDescendants();
-#if ENABLE(CSS_COMPOSITING)
- if ((willBeComposited && layer.hasBlendMode()) || (layer.hasNotIsolatedCompositedBlendingDescendants() && !layer.isolatesCompositedBlending()))
- compositingState.hasNotIsolatedCompositedBlendingDescendants = true;
-#endif
-
- if ((childState.compositingAncestor == &layer && !layer.isRenderViewLayer()) || childState.backingSharingAncestor == &layer)
- overlapMap.popCompositingContainer();
-
// If we're back at the root, and no other layers need to be composited, and the root layer itself doesn't need
// to be composited, then we can drop out of compositing mode altogether. However, don't drop out of compositing mode
// if there are composited layers that we didn't hit in our traversal (e.g. because of visibility:hidden).
RequiresCompositingData rootLayerQueryData;
- if (layer.isRenderViewLayer() && !childState.subtreeIsCompositing && !requiresCompositingLayer(layer, rootLayerQueryData) && !m_forceCompositingMode && !needsCompositingForContentOrOverlays()) {
+ if (layer.isRenderViewLayer() && !currentState.subtreeIsCompositing && !requiresCompositingLayer(layer, rootLayerQueryData) && !m_forceCompositingMode && !needsCompositingForContentOrOverlays()) {
// Don't drop out of compositing on iOS, because we may flash. See <rdar://problem/8348337>.
#if !PLATFORM(IOS_FAMILY)
enableCompositingMode(false);
@@ -1031,8 +1024,6 @@
#endif
}
- compositingState.propagateStateFromChildren(childState);
-
ASSERT(willBeComposited == needsToBeComposited(layer, queryData));
// Create or destroy backing here. However, we can't update geometry because layers above us may become composited
@@ -1045,12 +1036,9 @@
layer.setNeedsCompositingGeometryUpdateOnAncestors();
}
- backingSharingState.updateAfterDescendantTraversal(layer, compositingState.stackingContextAncestor);
-
+ // Update layer state bits.
if (layer.reflectionLayer() && updateLayerCompositingState(*layer.reflectionLayer(), queryData, CompositingChangeRepaintNow))
layer.setNeedsCompositingLayerConnection();
-
- descendantHas3DTransform |= anyDescendantHas3DTransform || layer.has3DTransform();
// FIXME: clarify needsCompositingPaintOrderChildrenUpdate. If a composited layer gets a new ancestor, it needs geometry computations.
if (layer.needsCompositingPaintOrderChildrenUpdate()) {
@@ -1059,6 +1047,16 @@
}
layer.clearCompositingRequirementsTraversalState();
+
+ // Compute state passed to the caller.
+ descendantHas3DTransform |= anyDescendantHas3DTransform || layer.has3DTransform();
+ compositingState.updateWithDescendantStateAndLayer(currentState, layer, layerExtent);
+
+ // Pop backing/overlap sharing state.
+ if ((willBeComposited && !layer.isRenderViewLayer()) || currentState.backingSharingAncestor == &layer)
+ overlapMap.popCompositingContainer();
+
+ backingSharingState.updateAfterDescendantTraversal(layer, compositingState.stackingContextAncestor);
overlapMap.geometryMap().popMappingsToAncestor(ancestorLayer);
LOG_WITH_STREAM(Compositing, stream << TextStream::Repeat(compositingState.depth * 2, ' ') << &layer << " computeCompositingRequirements - willBeComposited " << willBeComposited << " (backing provider candidate " << backingSharingState.backingProviderCandidate() << ")");
@@ -1095,21 +1093,18 @@
backingSharingState.appendSharingLayer(layer);
}
- CompositingState childState = compositingState.stateForPaintOrderChildren(layer);
+ CompositingState currentState = compositingState.stateForPaintOrderChildren(layer);
if (layerIsComposited) {
- // Tell the parent it has compositing descendants.
- compositingState.subtreeIsCompositing = true;
+ // This layer is going to be composited, so children can safely ignore the fact that there's an
+ // animation running behind this layer, meaning they can rely on the overlap map testing again.
+ currentState.testingOverlap = true;
// This layer now acts as the ancestor for kids.
- childState.compositingAncestor = &layer;
-
+ currentState.compositingAncestor = &layer;
overlapMap.pushCompositingContainer();
- // This layer is going to be composited, so children can safely ignore the fact that there's an
- // animation running behind this layer, meaning they can rely on the overlap map testing again.
- childState.testingOverlap = true;
computeExtent(overlapMap, layer, layerExtent);
- childState.ancestorHasTransformAnimation |= layerExtent.hasTransformAnimation;
+ currentState.ancestorHasTransformAnimation |= layerExtent.hasTransformAnimation;
// Too hard to compute animated bounds if both us and some ancestor is animating transform.
layerExtent.animationCausesExtentUncertainty |= layerExtent.hasTransformAnimation && compositingState.ancestorHasTransformAnimation;
}
@@ -1123,16 +1118,16 @@
bool anyDescendantHas3DTransform = false;
for (auto* childLayer : layer.negativeZOrderLayers()) {
- traverseUnchangedSubtree(&layer, *childLayer, overlapMap, childState, backingSharingState, anyDescendantHas3DTransform);
- if (childState.subtreeIsCompositing)
+ traverseUnchangedSubtree(&layer, *childLayer, overlapMap, currentState, backingSharingState, anyDescendantHas3DTransform);
+ if (currentState.subtreeIsCompositing)
ASSERT(layerIsComposited);
}
for (auto* childLayer : layer.normalFlowLayers())
- traverseUnchangedSubtree(&layer, *childLayer, overlapMap, childState, backingSharingState, anyDescendantHas3DTransform);
+ traverseUnchangedSubtree(&layer, *childLayer, overlapMap, currentState, backingSharingState, anyDescendantHas3DTransform);
for (auto* childLayer : layer.positiveZOrderLayers())
- traverseUnchangedSubtree(&layer, *childLayer, overlapMap, childState, backingSharingState, anyDescendantHas3DTransform);
+ traverseUnchangedSubtree(&layer, *childLayer, overlapMap, currentState, backingSharingState, anyDescendantHas3DTransform);
// All layers (even ones that aren't being composited) need to get added to
// the overlap map. Layers that do not composite will draw into their
@@ -1139,42 +1134,25 @@
// compositing ancestor's backing, and so are still considered for overlap.
// FIXME: When layerExtent has taken animation bounds into account, we also know that the bounds
// include descendants, so we don't need to add them all to the overlap map.
- if (childState.compositingAncestor && !childState.compositingAncestor->isRenderViewLayer())
+ if (currentState.compositingAncestor && !currentState.compositingAncestor->isRenderViewLayer())
addToOverlapMap(overlapMap, layer, layerExtent);
- compositingState.propagateStateFromChildrenForUnchangedSubtree(childState);
-
// Set the flag to say that this layer has compositing children.
- ASSERT(layer.hasCompositingDescendant() == childState.subtreeIsCompositing);
+ ASSERT(layer.hasCompositingDescendant() == currentState.subtreeIsCompositing);
+ ASSERT_IMPLIES(canBeComposited(layer) && clipsCompositingDescendants(layer), layerIsComposited);
- // setHasCompositingDescendant() may have changed the answer to needsToBeComposited() when clipping, so test that again.
- bool isCompositedClippingLayer = canBeComposited(layer) && clipsCompositingDescendants(layer);
+ descendantHas3DTransform |= anyDescendantHas3DTransform || layer.has3DTransform();
- // Turn overlap testing off for later layers if it's already off, or if we have an animating transform.
- // Note that if the layer clips its descendants, there's no reason to propagate the child animation to the parent layers. That's because
- // we know for sure the animation is contained inside the clipping rectangle, which is already added to the overlap map.
- if ((!childState.testingOverlap && !isCompositedClippingLayer) || layerExtent.knownToBeHaveExtentUncertainty())
- compositingState.testingOverlap = false;
-
- if (isCompositedClippingLayer)
- ASSERT(layerIsComposited);
+ ASSERT(!currentState.fullPaintOrderTraversalRequired);
+ compositingState.updateWithDescendantStateAndLayer(currentState, layer, layerExtent, true);
-#if ENABLE(CSS_COMPOSITING)
- if ((layerIsComposited && layer.hasBlendMode())
- || (layer.hasNotIsolatedCompositedBlendingDescendants() && !layer.isolatesCompositedBlending()))
- compositingState.hasNotIsolatedCompositedBlendingDescendants = true;
-#endif
-
- if ((childState.compositingAncestor == &layer && !layer.isRenderViewLayer()) || childState.backingSharingAncestor == &layer)
+ if ((layerIsComposited && !layer.isRenderViewLayer()) || currentState.backingSharingAncestor == &layer)
overlapMap.popCompositingContainer();
backingSharingState.updateAfterDescendantTraversal(layer, compositingState.stackingContextAncestor);
+ overlapMap.geometryMap().popMappingsToAncestor(ancestorLayer);
- descendantHas3DTransform |= anyDescendantHas3DTransform || layer.has3DTransform();
-
ASSERT(!layer.needsCompositingRequirementsTraversal());
-
- overlapMap.geometryMap().popMappingsToAncestor(ancestorLayer);
}
void RenderLayerCompositor::updateBackingAndHierarchy(RenderLayer& layer, Vector<Ref<GraphicsLayer>>& childLayersOfEnclosingLayer, ScrollingTreeState& scrollingTreeState, OptionSet<UpdateLevel> updateLevel, int depth)
@@ -1256,7 +1234,7 @@
LayerListMutationDetector mutationChecker(layer);
#endif
- auto appendForegroundLayerIfNecessary = [&] () {
+ auto appendForegroundLayerIfNecessary = [&] {
// If a negative z-order child is compositing, we get a foreground layer which needs to get parented.
if (layer.negativeZOrderLayers().size()) {
if (layerBacking && layerBacking->foregroundLayer())
@@ -2520,7 +2498,7 @@
// Return true if the given layer is a stacking context and has compositing child
// layers that it needs to clip. In this case we insert a clipping GraphicsLayer
// into the hierarchy between this layer and its children in the z-order hierarchy.
-bool RenderLayerCompositor::clipsCompositingDescendants(const RenderLayer& layer) const
+bool RenderLayerCompositor::clipsCompositingDescendants(const RenderLayer& layer)
{
return layer.hasCompositingDescendant() && layer.renderer().hasClipOrOverflowClip() && !layer.isolatesCompositedBlending();
}