Commit 8624b809 authored by chrishtr's avatar chrishtr Committed by Commit bot

Move computation of 3D descendants to the descendant-dependent flags walk.

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

Review-Url: https://codereview.chromium.org/2604973002
Cr-Commit-Position: refs/heads/master@{#440909}
parent a600d8d8
...@@ -138,6 +138,7 @@ Bug(none) compositing/geometry/fixed-position-transform-composited-page-scale.ht ...@@ -138,6 +138,7 @@ Bug(none) compositing/geometry/fixed-position-transform-composited-page-scale.ht
Bug(none) compositing/geometry/flipped-writing-mode.html [ Failure ] Bug(none) compositing/geometry/flipped-writing-mode.html [ Failure ]
Bug(none) compositing/geometry/foreground-layer.html [ Failure ] Bug(none) compositing/geometry/foreground-layer.html [ Failure ]
Bug(none) compositing/geometry/horizontal-scroll-composited.html [ Failure ] Bug(none) compositing/geometry/horizontal-scroll-composited.html [ Failure ]
Bug(none) compositing/geometry/layer-due-to-layer-children-deep.html [ Failure ]
Bug(none) compositing/geometry/layer-due-to-layer-children-deep-switch.html [ Failure ] Bug(none) compositing/geometry/layer-due-to-layer-children-deep-switch.html [ Failure ]
Bug(none) compositing/geometry/layer-due-to-layer-children-switch.html [ Failure ] Bug(none) compositing/geometry/layer-due-to-layer-children-switch.html [ Failure ]
Bug(none) compositing/geometry/layer-due-to-layer-children.html [ Failure ] Bug(none) compositing/geometry/layer-due-to-layer-children.html [ Failure ]
......
...@@ -730,7 +730,6 @@ bool CompositedLayerMapping::updateGraphicsLayerConfiguration() { ...@@ -730,7 +730,6 @@ bool CompositedLayerMapping::updateGraphicsLayerConfiguration() {
m_graphicsLayer->setHasWillChangeTransformHint( m_graphicsLayer->setHasWillChangeTransformHint(
style.hasWillChangeTransformHint()); style.hasWillChangeTransformHint());
m_owningLayer.update3DTransformedDescendantStatus();
if (style.preserves3D() && style.hasOpacity() && if (style.preserves3D() && style.hasOpacity() &&
m_owningLayer.has3DTransformedDescendant()) m_owningLayer.has3DTransformedDescendant())
UseCounter::count(layoutObject->document(), UseCounter::count(layoutObject->document(),
......
...@@ -138,7 +138,6 @@ PaintLayer::PaintLayer(LayoutBoxModelObject* layoutObject) ...@@ -138,7 +138,6 @@ PaintLayer::PaintLayer(LayoutBoxModelObject* layoutObject)
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
m_needsPositionUpdate(true), m_needsPositionUpdate(true),
#endif #endif
m_is3DTransformedDescendantDirty(true),
m_has3DTransformedDescendant(false), m_has3DTransformedDescendant(false),
m_containsDirtyOverlayScrollbars(false), m_containsDirtyOverlayScrollbars(false),
m_needsAncestorDependentCompositingInputsUpdate(true), m_needsAncestorDependentCompositingInputsUpdate(true),
...@@ -415,7 +414,7 @@ void PaintLayer::updateTransform(const ComputedStyle* oldStyle, ...@@ -415,7 +414,7 @@ void PaintLayer::updateTransform(const ComputedStyle* oldStyle,
updateTransformationMatrix(); updateTransformationMatrix();
if (had3DTransform != has3DTransform()) if (had3DTransform != has3DTransform())
dirty3DTransformedDescendantStatus(); markAncestorChainForDescendantDependentFlagsUpdate();
if (FrameView* frameView = layoutObject()->document().view()) if (FrameView* frameView = layoutObject()->document().view())
frameView->setNeedsUpdateWidgetGeometries(); frameView->setNeedsUpdateWidgetGeometries();
...@@ -743,49 +742,35 @@ void PaintLayer::updateDescendantDependentFlags() { ...@@ -743,49 +742,35 @@ void PaintLayer::updateDescendantDependentFlags() {
// this LayoutObject during the invalidateTreeIfNeeded walk. // this LayoutObject during the invalidateTreeIfNeeded walk.
m_layoutObject->setMayNeedPaintInvalidation(); m_layoutObject->setMayNeedPaintInvalidation();
} }
}
void PaintLayer::dirty3DTransformedDescendantStatus() {
PaintLayerStackingNode* stackingNode =
m_stackingNode->ancestorStackingContextNode();
if (!stackingNode)
return;
stackingNode->layer()->m_is3DTransformedDescendantDirty = true; update3DTransformedDescendantStatus();
// This propagates up through preserve-3d hierarchies to the enclosing
// flattening layer. Note that preserves3D() creates stacking context, so we
// can just run up the stacking containers.
while (stackingNode && stackingNode->layer()->preserves3D()) {
stackingNode->layer()->m_is3DTransformedDescendantDirty = true;
stackingNode = stackingNode->ancestorStackingContextNode();
}
} }
// Return true if this layer or any preserve-3d descendants have 3d. void PaintLayer::update3DTransformedDescendantStatus() {
bool PaintLayer::update3DTransformedDescendantStatus() { m_has3DTransformedDescendant = false;
if (m_is3DTransformedDescendantDirty) {
m_has3DTransformedDescendant = false;
m_stackingNode->updateZOrderLists(); m_stackingNode->updateZOrderLists();
// Transformed or preserve-3d descendants can only be in the z-order lists, // Transformed or preserve-3d descendants can only be in the z-order lists,
// not in the normal flow list, so we only need to check those. // not in the normal flow list, so we only need to check those.
PaintLayerStackingNodeIterator iterator( PaintLayerStackingNodeIterator iterator(
*m_stackingNode.get(), PositiveZOrderChildren | NegativeZOrderChildren); *m_stackingNode.get(), PositiveZOrderChildren | NegativeZOrderChildren);
while (PaintLayerStackingNode* node = iterator.next()) while (PaintLayerStackingNode* node = iterator.next()) {
m_has3DTransformedDescendant |= const PaintLayer& childLayer = *node->layer();
node->layer()->update3DTransformedDescendantStatus(); bool childHas3D = false;
// If the child lives in a 3d hierarchy, then the layer at the root of
m_is3DTransformedDescendantDirty = false; // that hierarchy needs the m_has3DTransformedDescendant set.
if (childLayer.preserves3D() && (childLayer.has3DTransform() ||
childLayer.has3DTransformedDescendant()))
childHas3D = true;
else if (childLayer.has3DTransform())
childHas3D = true;
if (childHas3D) {
m_has3DTransformedDescendant = true;
break;
}
} }
// If we live in a 3d hierarchy, then the layer at the root of that hierarchy
// needs the m_has3DTransformedDescendant set.
if (preserves3D())
return has3DTransform() || m_has3DTransformedDescendant;
return has3DTransform();
} }
void PaintLayer::updateLayerPosition() { void PaintLayer::updateLayerPosition() {
......
...@@ -967,11 +967,8 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient { ...@@ -967,11 +967,8 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
} }
void clearClipRectsCache() const { m_clipRectsCache.reset(); } void clearClipRectsCache() const { m_clipRectsCache.reset(); }
void dirty3DTransformedDescendantStatus();
// Both updates the status, and returns true if descendants of this have 3d.
bool update3DTransformedDescendantStatus();
bool has3DTransformedDescendant() const { bool has3DTransformedDescendant() const {
DCHECK(!m_is3DTransformedDescendantDirty); DCHECK(!m_needsDescendantDependentFlagsUpdate);
return m_has3DTransformedDescendant; return m_has3DTransformedDescendant;
} }
...@@ -982,6 +979,8 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient { ...@@ -982,6 +979,8 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
private: private:
void setNeedsCompositingInputsUpdateInternal(); void setNeedsCompositingInputsUpdateInternal();
void update3DTransformedDescendantStatus();
// Bounding box in the coordinates of this layer. // Bounding box in the coordinates of this layer.
LayoutRect logicalBoundingBox() const; LayoutRect logicalBoundingBox() const;
...@@ -1139,7 +1138,6 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient { ...@@ -1139,7 +1138,6 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
unsigned m_needsPositionUpdate : 1; unsigned m_needsPositionUpdate : 1;
#endif #endif
unsigned m_is3DTransformedDescendantDirty : 1;
// Set on a stacking context layer that has 3D descendants anywhere // Set on a stacking context layer that has 3D descendants anywhere
// in a preserves3D hierarchy. Hint to do 3D-aware hit testing. // in a preserves3D hierarchy. Hint to do 3D-aware hit testing.
unsigned m_has3DTransformedDescendant : 1; unsigned m_has3DTransformedDescendant : 1;
......
...@@ -290,6 +290,84 @@ TEST_P(PaintLayerTest, HasVisibleDescendant) { ...@@ -290,6 +290,84 @@ TEST_P(PaintLayerTest, HasVisibleDescendant) {
EXPECT_FALSE(invisible->hasDescendantWithClipPath()); EXPECT_FALSE(invisible->hasDescendantWithClipPath());
} }
TEST_P(PaintLayerTest, Has3DTransformedDescendant) {
enableCompositing();
setBodyInnerHTML(
"<div id='parent' style='position:relative; z-index: 0'>"
" <div id='child' style='transform: translateZ(1px)'>"
" </div>"
"</div>");
PaintLayer* parent =
toLayoutBoxModelObject(getLayoutObjectByElementId("parent"))->layer();
PaintLayer* child =
toLayoutBoxModelObject(getLayoutObjectByElementId("child"))->layer();
EXPECT_TRUE(parent->has3DTransformedDescendant());
EXPECT_FALSE(child->has3DTransformedDescendant());
}
TEST_P(PaintLayerTest, Has3DTransformedDescendantChangeStyle) {
enableCompositing();
setBodyInnerHTML(
"<div id='parent' style='position:relative; z-index: 0'>"
" <div id='child' style='position:relative '>"
" </div>"
"</div>");
PaintLayer* parent =
toLayoutBoxModelObject(getLayoutObjectByElementId("parent"))->layer();
PaintLayer* child =
toLayoutBoxModelObject(getLayoutObjectByElementId("child"))->layer();
EXPECT_FALSE(parent->has3DTransformedDescendant());
EXPECT_FALSE(child->has3DTransformedDescendant());
document().getElementById("child")->setAttribute(
HTMLNames::styleAttr, "transform: translateZ(1px)");
document().view()->updateAllLifecyclePhases();
EXPECT_TRUE(parent->has3DTransformedDescendant());
EXPECT_FALSE(child->has3DTransformedDescendant());
}
TEST_P(PaintLayerTest, Has3DTransformedDescendantNotStacking) {
enableCompositing();
setBodyInnerHTML(
"<div id='parent' style='position:relative;'>"
" <div id='child' style='transform: translateZ(1px)'>"
" </div>"
"</div>");
PaintLayer* parent =
toLayoutBoxModelObject(getLayoutObjectByElementId("parent"))->layer();
PaintLayer* child =
toLayoutBoxModelObject(getLayoutObjectByElementId("child"))->layer();
// |child| is not a stacking child of |parent|, so it has no 3D transformed
// descendant.
EXPECT_FALSE(parent->has3DTransformedDescendant());
EXPECT_FALSE(child->has3DTransformedDescendant());
}
TEST_P(PaintLayerTest, Has3DTransformedGrandchildWithPreserve3d) {
enableCompositing();
setBodyInnerHTML(
"<div id='parent' style='position:relative; z-index: 0'>"
" <div id='child' style='transform-style: preserve-3d'>"
" <div id='grandchild' style='transform: translateZ(1px)'>"
" </div>"
" </div>"
"</div>");
PaintLayer* parent =
toLayoutBoxModelObject(getLayoutObjectByElementId("parent"))->layer();
PaintLayer* child =
toLayoutBoxModelObject(getLayoutObjectByElementId("child"))->layer();
PaintLayer* grandchild =
toLayoutBoxModelObject(getLayoutObjectByElementId("grandchild"))->layer();
EXPECT_TRUE(parent->has3DTransformedDescendant());
EXPECT_TRUE(child->has3DTransformedDescendant());
EXPECT_FALSE(grandchild->has3DTransformedDescendant());
}
TEST_P(PaintLayerTest, DescendantDependentFlagsStopsAtThrottledFrames) { TEST_P(PaintLayerTest, DescendantDependentFlagsStopsAtThrottledFrames) {
enableCompositing(); enableCompositing();
setBodyInnerHTML( setBodyInnerHTML(
......
...@@ -301,30 +301,24 @@ void PaintPropertyTreeBuilder::updateTransformForNonRootSVG( ...@@ -301,30 +301,24 @@ void PaintPropertyTreeBuilder::updateTransformForNonRootSVG(
} }
} }
static CompositingReasons compositingReasonsForTransform( static CompositingReasons compositingReasonsForTransform(const LayoutBox& box) {
const LayoutObject& object) { const ComputedStyle& style = box.styleRef();
CompositingReasons compositingReasons = CompositingReasonNone; CompositingReasons compositingReasons = CompositingReasonNone;
if (CompositingReasonFinder::requiresCompositingForTransform(object)) if (CompositingReasonFinder::requiresCompositingForTransform(box))
compositingReasons |= CompositingReason3DTransform; compositingReasons |= CompositingReason3DTransform;
if (CompositingReasonFinder::requiresCompositingForTransformAnimation( if (CompositingReasonFinder::requiresCompositingForTransformAnimation(style))
object.styleRef()))
compositingReasons |= CompositingReasonActiveAnimation; compositingReasons |= CompositingReasonActiveAnimation;
if (object.styleRef().hasWillChangeCompositingHint() && if (style.hasWillChangeCompositingHint() &&
!object.styleRef().subtreeWillChangeContents()) !style.subtreeWillChangeContents())
compositingReasons |= CompositingReasonWillChangeCompositingHint; compositingReasons |= CompositingReasonWillChangeCompositingHint;
if (object.isBoxModelObject()) { if (box.hasLayer() && box.layer()->has3DTransformedDescendant()) {
const LayoutBoxModelObject* box = toLayoutBoxModelObject(&object); if (style.hasPerspective())
if (box->hasLayer()) { compositingReasons |= CompositingReasonPerspectiveWith3DDescendants;
// TODO(chrishtr): move this to the descendant-dependent flags recursion if (style.usedTransformStyle3D() == TransformStyle3DPreserve3D)
// PaintLayer::updateDescendantDependentFlags. compositingReasons |= CompositingReasonPreserve3DWith3DDescendants;
box->layer()->update3DTransformedDescendantStatus();
if (box->layer()->has3DTransformedDescendant())
compositingReasons |= CompositingReason3DTransform;
}
} }
return compositingReasons; return compositingReasons;
...@@ -353,36 +347,44 @@ void PaintPropertyTreeBuilder::updateTransform( ...@@ -353,36 +347,44 @@ void PaintPropertyTreeBuilder::updateTransform(
if (object.needsPaintPropertyUpdate() || context.forceSubtreeUpdate) { if (object.needsPaintPropertyUpdate() || context.forceSubtreeUpdate) {
const ComputedStyle& style = object.styleRef(); const ComputedStyle& style = object.styleRef();
CompositingReasons compositingReasons =
compositingReasonsForTransform(object);
// A transform node is allocated for transforms, preserves-3d and any // A transform node is allocated for transforms, preserves-3d and any
// direct compositing reason. The latter is required because this is the // direct compositing reason. The latter is required because this is the
// only way to represent compositing both an element and its stacking // only way to represent compositing both an element and its stacking
// descendants. // descendants.
if (object.isBox() && (style.hasTransform() || style.preserves3D() || bool hasTransform = false;
compositingReasons != CompositingReasonNone)) { if (object.isBox()) {
auto& box = toLayoutBox(object); auto& box = toLayoutBox(object);
TransformationMatrix matrix;
style.applyTransform(
matrix, box.size(), ComputedStyle::ExcludeTransformOrigin,
ComputedStyle::IncludeMotionPath,
ComputedStyle::IncludeIndependentTransformProperties);
// TODO(trchen): transform-style should only be respected if a PaintLayer
// is created.
// If a node with transform-style: preserve-3d does not exist in an
// existing rendering context, it establishes a new one.
unsigned renderingContextID = context.current.renderingContextID;
if (style.preserves3D() && !renderingContextID)
renderingContextID = PtrHash<const LayoutObject>::hash(&object);
auto& properties = object.getMutableForPainting().ensurePaintProperties(); CompositingReasons compositingReasons =
context.forceSubtreeUpdate |= properties.updateTransform( compositingReasonsForTransform(box);
context.current.transform, matrix, transformOrigin(box),
context.current.shouldFlattenInheritedTransform, renderingContextID, if (style.hasTransform() || style.preserves3D() ||
compositingReasons); compositingReasons != CompositingReasonNone) {
} else { TransformationMatrix matrix;
style.applyTransform(
matrix, box.size(), ComputedStyle::ExcludeTransformOrigin,
ComputedStyle::IncludeMotionPath,
ComputedStyle::IncludeIndependentTransformProperties);
// TODO(trchen): transform-style should only be respected if a
// PaintLayer
// is created.
// If a node with transform-style: preserve-3d does not exist in an
// existing rendering context, it establishes a new one.
unsigned renderingContextID = context.current.renderingContextID;
if (style.preserves3D() && !renderingContextID)
renderingContextID = PtrHash<const LayoutObject>::hash(&object);
auto& properties =
object.getMutableForPainting().ensurePaintProperties();
context.forceSubtreeUpdate |= properties.updateTransform(
context.current.transform, matrix, transformOrigin(box),
context.current.shouldFlattenInheritedTransform, renderingContextID,
compositingReasons);
hasTransform = true;
}
}
if (!hasTransform) {
if (auto* properties = object.getMutableForPainting().paintProperties()) if (auto* properties = object.getMutableForPainting().paintProperties())
context.forceSubtreeUpdate |= properties->clearTransform(); context.forceSubtreeUpdate |= properties->clearTransform();
} }
......
...@@ -347,6 +347,7 @@ TEST_P(PaintPropertyTreeBuilderTest, Transform) { ...@@ -347,6 +347,7 @@ TEST_P(PaintPropertyTreeBuilderTest, Transform) {
Element* transform = document().getElementById("transform"); Element* transform = document().getElementById("transform");
const ObjectPaintProperties* transformProperties = const ObjectPaintProperties* transformProperties =
transform->layoutObject()->paintProperties(); transform->layoutObject()->paintProperties();
EXPECT_EQ(TransformationMatrix().translate3d(123, 456, 789), EXPECT_EQ(TransformationMatrix().translate3d(123, 456, 789),
transformProperties->transform()->matrix()); transformProperties->transform()->matrix());
EXPECT_EQ(FloatPoint3D(200, 150, 0), EXPECT_EQ(FloatPoint3D(200, 150, 0),
...@@ -381,6 +382,43 @@ TEST_P(PaintPropertyTreeBuilderTest, Transform) { ...@@ -381,6 +382,43 @@ TEST_P(PaintPropertyTreeBuilderTest, Transform) {
transform->layoutObject()->paintProperties()->transform()->matrix()); transform->layoutObject()->paintProperties()->transform()->matrix());
} }
TEST_P(PaintPropertyTreeBuilderTest, Preserve3D3DTransformedDescendant) {
setBodyInnerHTML(
"<style> body { margin: 0 } </style>"
"<div id='preserve' style='transform-style: preserve-3d'>"
"<div id='transform' style='margin-left: 50px; margin-top: 100px;"
" width: 400px; height: 300px;"
" transform: translate3d(123px, 456px, 789px)'>"
"</div>"
"</div>");
Element* preserve = document().getElementById("preserve");
const ObjectPaintProperties* preserveProperties =
preserve->layoutObject()->paintProperties();
EXPECT_TRUE(preserveProperties->transform());
EXPECT_TRUE(preserveProperties->transform()->hasDirectCompositingReasons());
}
TEST_P(PaintPropertyTreeBuilderTest, Perspective3DTransformedDescendant) {
setBodyInnerHTML(
"<style> body { margin: 0 } </style>"
"<div id='perspective' style='perspective: 800px;'>"
"<div id='transform' style='margin-left: 50px; margin-top: 100px;"
" width: 400px; height: 300px;"
" transform: translate3d(123px, 456px, 789px)'>"
"</div>"
"</div>");
Element* perspective = document().getElementById("perspective");
const ObjectPaintProperties* perspectiveProperties =
perspective->layoutObject()->paintProperties();
EXPECT_TRUE(perspectiveProperties->transform());
EXPECT_TRUE(
perspectiveProperties->transform()->hasDirectCompositingReasons());
}
TEST_P(PaintPropertyTreeBuilderTest, TEST_P(PaintPropertyTreeBuilderTest,
TransformNodeWithActiveAnimationHasDirectCompositingReason) { TransformNodeWithActiveAnimationHasDirectCompositingReason) {
setBodyInnerHTML( setBodyInnerHTML(
......
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