Commit 62178a7f authored by Stefan Zager's avatar Stefan Zager Committed by Chromium LUCI CQ

Use consistent logic to detect iframe compositing state

CompositingRequirementsUpdater is responsible for setting
PaintLayerCompositor::compositing_, while GraphicsLayerTreeBuilder is
responsible for attaching PaintLayerCompositor::RootGraphicsLayer()
into the layer tree of its embedding document. The current code uses
slightly different logic in those two places to determine whether an
iframe is compositing, which may lead to inconsistent state when an
iframe is throttled. This CL make them use the same logic.

Bug: 1133662
Change-Id: I13276c0b0fb25921936d5319d4d983d720595557
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2606654
Commit-Queue: Stefan Zager <szager@chromium.org>
Reviewed-by: default avatarXianzhu Wang <wangxianzhu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#839677}
parent f795e6f1
...@@ -142,11 +142,15 @@ PaintLayerType LayoutEmbeddedContent::LayerTypeRequired() const { ...@@ -142,11 +142,15 @@ PaintLayerType LayoutEmbeddedContent::LayerTypeRequired() const {
return kForcedPaintLayer; return kForcedPaintLayer;
} }
bool LayoutEmbeddedContent::ContentDocumentIsCompositing() const { bool LayoutEmbeddedContent::ContentDocumentContainsGraphicsLayer() const {
NOT_DESTROYED(); NOT_DESTROYED();
// This method must use the same logic as GraphicsLayerTreeBuilder: if
// an iframe is throttled, we look for the existence of a root graphics layer,
// even if the compositing state information is stale.
if (PaintLayerCompositor* inner_compositor = if (PaintLayerCompositor* inner_compositor =
PaintLayerCompositor::FrameContentsCompositor(*this)) { PaintLayerCompositor::FrameContentsCompositor(*this)) {
return inner_compositor->StaleInCompositingMode(); DisableCompositingQueryAsserts compositing_disabler;
return inner_compositor->RootGraphicsLayer();
} }
return false; return false;
} }
......
...@@ -44,7 +44,7 @@ class CORE_EXPORT LayoutEmbeddedContent : public LayoutReplaced { ...@@ -44,7 +44,7 @@ class CORE_EXPORT LayoutEmbeddedContent : public LayoutReplaced {
explicit LayoutEmbeddedContent(HTMLFrameOwnerElement*); explicit LayoutEmbeddedContent(HTMLFrameOwnerElement*);
~LayoutEmbeddedContent() override; ~LayoutEmbeddedContent() override;
bool ContentDocumentIsCompositing() const; bool ContentDocumentContainsGraphicsLayer() const;
bool NodeAtPoint(HitTestResult&, bool NodeAtPoint(HitTestResult&,
const HitTestLocation&, const HitTestLocation&,
......
...@@ -395,7 +395,7 @@ void CompositingLayerAssigner::AssignLayersToBackingsInternal( ...@@ -395,7 +395,7 @@ void CompositingLayerAssigner::AssignLayersToBackingsInternal(
// squash layers painted after the iframe with layers painted before it. // squash layers painted after the iframe with layers painted before it.
if (layer->GetLayoutObject().IsLayoutEmbeddedContent() && if (layer->GetLayoutObject().IsLayoutEmbeddedContent() &&
To<LayoutEmbeddedContent>(layer->GetLayoutObject()) To<LayoutEmbeddedContent>(layer->GetLayoutObject())
.ContentDocumentIsCompositing()) { .ContentDocumentContainsGraphicsLayer()) {
squashing_state.have_assigned_backings_to_entire_squashing_layer_subtree = squashing_state.have_assigned_backings_to_entire_squashing_layer_subtree =
false; false;
} }
......
...@@ -378,7 +378,7 @@ void CompositingRequirementsUpdater::UpdateRecursive( ...@@ -378,7 +378,7 @@ void CompositingRequirementsUpdater::UpdateRecursive(
bool contains_composited_layer = bool contains_composited_layer =
(layer->GetLayoutObject().IsLayoutEmbeddedContent() && (layer->GetLayoutObject().IsLayoutEmbeddedContent() &&
To<LayoutEmbeddedContent>(layer->GetLayoutObject()) To<LayoutEmbeddedContent>(layer->GetLayoutObject())
.ContentDocumentIsCompositing()); .ContentDocumentContainsGraphicsLayer());
bool will_be_composited_or_squashed = bool will_be_composited_or_squashed =
can_be_composited && RequiresCompositingOrSquashing(reasons_to_composite); can_be_composited && RequiresCompositingOrSquashing(reasons_to_composite);
......
...@@ -5,9 +5,12 @@ ...@@ -5,9 +5,12 @@
#include "third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.h" #include "third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h" #include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h" #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h" #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
#include "third_party/blink/renderer/platform/graphics/graphics_layer.h" #include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
#include "third_party/blink/renderer/platform/testing/testing_platform_support.h" #include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
...@@ -222,4 +225,88 @@ TEST_F(CompositingRequirementsUpdaterTest, ...@@ -222,4 +225,88 @@ TEST_F(CompositingRequirementsUpdaterTest,
GetPaintLayerByElementId("3d-descendant")->GetCompositingReasons()); GetPaintLayerByElementId("3d-descendant")->GetCompositingReasons());
} }
class CompositingRequirementsUpdaterSimTest : public SimTest {
protected:
void SetUp() override {
SimTest::SetUp();
WebView().MainFrameViewWidget()->Resize(gfx::Size(800, 600));
}
};
TEST_F(CompositingRequirementsUpdaterSimTest,
StaleCompositingStateInThrottledFrame) {
SimRequest top_resource("https://example.com/top.html", "text/html");
SimRequest middle_resource("https://cross-origin.com/middle.html",
"text/html");
SimRequest bottom_resource("https://cross-origin.com/bottom.html",
"text/html");
LoadURL("https://example.com/top.html");
top_resource.Complete(R"HTML(
<div id='spacer'></div>
<iframe id='middle' src='https://cross-origin.com/middle.html'></iframe>
)HTML");
middle_resource.Complete(R"HTML(
<iframe id='bottom' src='bottom.html'></iframe>
)HTML");
bottom_resource.Complete(R"HTML(
<div id='composited' style='will-change:transform'>Hello, world!</div>
)HTML");
LocalFrame& middle_frame =
*To<LocalFrame>(GetDocument().GetFrame()->Tree().FirstChild());
LocalFrame& bottom_frame = *To<LocalFrame>(middle_frame.Tree().FirstChild());
middle_frame.View()->BeginLifecycleUpdates();
bottom_frame.View()->BeginLifecycleUpdates();
GetDocument().View()->UpdateAllLifecyclePhasesForTest();
ASSERT_FALSE(bottom_frame.View()->ShouldThrottleRenderingForTest());
LayoutEmbeddedContent* bottom_owner = bottom_frame.OwnerLayoutObject();
EXPECT_TRUE(bottom_owner->ContentDocumentContainsGraphicsLayer());
EXPECT_TRUE(bottom_owner->Layer()->HasCompositingDescendant());
// Move iframe offscreen to throttle it. Compositing status shouldn't change.
Element* spacer = GetDocument().getElementById("spacer");
spacer->setAttribute(html_names::kStyleAttr, "height:2000px");
GetDocument().View()->UpdateAllLifecyclePhasesForTest();
ASSERT_TRUE(middle_frame.View()->ShouldThrottleRenderingForTest());
ASSERT_TRUE(bottom_frame.View()->ShouldThrottleRenderingForTest());
EXPECT_TRUE(bottom_owner->ContentDocumentContainsGraphicsLayer());
EXPECT_TRUE(bottom_owner->Layer()->HasCompositingDescendant());
// Remove direct compositing reason from iframe content, but add
// position:relative so it still has a PaintLayer and won't force a
// compositing update.
Element* composited =
bottom_frame.GetDocument()->getElementById("composited");
composited->setAttribute(html_names::kStyleAttr, "position:relative");
// Force a lifecycle update up to pre-paint clean; compositing inputs will be
// updated, but not compositing assignments. This imitates what would happen
// if a new IntersectionObservation is created inside a throttled frame. This
// should not affect final compositing state.
GetDocument().View()->ForceUpdateViewportIntersections();
EXPECT_TRUE(bottom_owner->ContentDocumentContainsGraphicsLayer());
EXPECT_TRUE(bottom_owner->Layer()->HasCompositingDescendant());
// Force a full, throttled lifecycle update. Compositing state in the bottom
// frame will remain stale; compositing state in the middle frame will be
// based on the stale state of the iframe.
GetDocument().View()->UpdateAllLifecyclePhasesForTest();
EXPECT_TRUE(
middle_frame.ContentLayoutObject()->Layer()->GetCompositingReasons() |
CompositingReason::kRoot);
EXPECT_TRUE(bottom_owner->ContentDocumentContainsGraphicsLayer());
EXPECT_TRUE(bottom_owner->Layer()->HasCompositingDescendant());
// Move the iframe back on screen and run two lifecycle updates to unthrottle
// it and update compositing.
spacer->setAttribute(html_names::kStyleAttr, "");
GetDocument().View()->UpdateAllLifecyclePhasesForTest();
ASSERT_FALSE(middle_frame.View()->ShouldThrottleRenderingForTest());
ASSERT_FALSE(bottom_frame.View()->ShouldThrottleRenderingForTest());
GetDocument().View()->UpdateAllLifecyclePhasesForTest();
EXPECT_FALSE(bottom_owner->ContentDocumentContainsGraphicsLayer());
EXPECT_FALSE(bottom_owner->Layer()->HasCompositingDescendant());
}
} // namespace blink } // namespace blink
...@@ -221,6 +221,12 @@ void PaintLayerCompositor::UpdateAssignmentsIfNeededRecursiveInternal( ...@@ -221,6 +221,12 @@ void PaintLayerCompositor::UpdateAssignmentsIfNeededRecursiveInternal(
target_state, compositing_reasons_stats); target_state, compositing_reasons_stats);
if (child_compositor->root_layer_attachment_dirty_) if (child_compositor->root_layer_attachment_dirty_)
SetNeedsCompositingUpdate(kCompositingUpdateRebuildTree); SetNeedsCompositingUpdate(kCompositingUpdateRebuildTree);
#if DCHECK_IS_ON()
// Even if the child frame is throttled, this should be consistent.
DisableCompositingQueryAsserts query_assert_disabler;
DCHECK_EQ(child_compositor->InCompositingMode(),
(bool)child_compositor->RootGraphicsLayer());
#endif
} }
} }
......
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