blob: 1ccd33787f5b3ddc2dea20a8cbd8b0a3442fd98a [file] [log] [blame]
// 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 "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
#include "third_party/blink/renderer/core/animation/animatable.h"
#include "third_party/blink/renderer/core/animation/animation.h"
#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
namespace blink {
namespace {
class PaintLayerCompositorTest : public RenderingTest {
public:
PaintLayerCompositorTest()
: RenderingTest(MakeGarbageCollected<SingleChildLocalFrameClient>()) {}
private:
void SetUp() override {
EnableCompositing();
RenderingTest::SetUp();
}
};
} // namespace
TEST_F(PaintLayerCompositorTest, AdvancingToCompositingInputsClean) {
SetBodyInnerHTML("<div id='box' style='position: relative'></div>");
PaintLayer* box_layer = GetPaintLayerByElementId("box");
ASSERT_TRUE(box_layer);
EXPECT_FALSE(box_layer->NeedsCompositingInputsUpdate());
box_layer->SetNeedsCompositingInputsUpdate();
GetDocument().View()->UpdateLifecycleToCompositingInputsClean(
DocumentUpdateReason::kTest);
EXPECT_EQ(DocumentLifecycle::kCompositingInputsClean,
GetDocument().Lifecycle().GetState());
EXPECT_FALSE(box_layer->NeedsCompositingInputsUpdate());
GetDocument().View()->SetNeedsLayout();
EXPECT_TRUE(GetDocument().View()->NeedsLayout());
}
TEST_F(PaintLayerCompositorTest,
CompositingInputsCleanDoesNotTriggerAnimations) {
SetBodyInnerHTML(R"HTML(
<style>@keyframes fadeOut { from { opacity: 1; } to { opacity: 0; } }
.animate { animation: fadeOut 2s; }</style>
<div id='box'></div>
<div id='otherBox'></div>
)HTML");
Element* box = GetDocument().getElementById("box");
Element* otherBox = GetDocument().getElementById("otherBox");
ASSERT_TRUE(box);
ASSERT_TRUE(otherBox);
box->setAttribute("class", "animate", ASSERT_NO_EXCEPTION);
// Update the lifecycle to CompositingInputsClean. This should not start the
// animation lifecycle.
GetDocument().View()->UpdateLifecycleToCompositingInputsClean(
DocumentUpdateReason::kTest);
EXPECT_EQ(DocumentLifecycle::kCompositingInputsClean,
GetDocument().Lifecycle().GetState());
otherBox->setAttribute("class", "animate", ASSERT_NO_EXCEPTION);
// Now run the rest of the lifecycle. Because both 'box' and 'otherBox' were
// given animations separated only by a lifecycle update to
// CompositingInputsClean, they should both be started in the same lifecycle
// and as such grouped together.
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(DocumentLifecycle::kPaintClean,
GetDocument().Lifecycle().GetState());
HeapVector<Member<Animation>> boxAnimations = box->getAnimations();
HeapVector<Member<Animation>> otherBoxAnimations = otherBox->getAnimations();
EXPECT_EQ(1ul, boxAnimations.size());
EXPECT_EQ(1ul, otherBoxAnimations.size());
EXPECT_EQ(boxAnimations.front()->CompositorGroup(),
otherBoxAnimations.front()->CompositorGroup());
}
TEST_F(PaintLayerCompositorTest, CompositingInputsUpdateStopsContainStrict) {
SetHtmlInnerHTML(R"HTML(
<style>
div {
position: relative;
}
#wrapper {
contain: strict;
}
</style>
<div id='wrapper'>
<div id='target'></div>
</div>
)HTML");
PaintLayer* wrapper = GetPaintLayerByElementId("wrapper");
PaintLayer* target = GetPaintLayerByElementId("target");
EXPECT_FALSE(wrapper->NeedsCompositingInputsUpdate());
EXPECT_FALSE(target->NeedsCompositingInputsUpdate());
target->SetNeedsCompositingInputsUpdate();
EXPECT_FALSE(wrapper->NeedsCompositingInputsUpdate());
EXPECT_TRUE(target->NeedsCompositingInputsUpdate());
GetDocument().View()->UpdateLifecycleToCompositingInputsClean(
DocumentUpdateReason::kTest);
EXPECT_EQ(DocumentLifecycle::kCompositingInputsClean,
GetDocument().Lifecycle().GetState());
EXPECT_FALSE(wrapper->NeedsCompositingInputsUpdate());
EXPECT_FALSE(target->NeedsCompositingInputsUpdate());
}
TEST_F(PaintLayerCompositorTest, SubframeRebuildGraphicsLayers) {
GetDocument().SetBaseURLOverride(KURL("http://test.com"));
SetBodyInnerHTML("<iframe src='http://test.com'></iframe>");
SetChildFrameHTML(
"<div id='target' style='will-change: opacity; opacity: 0.5'></div>");
UpdateAllLifecyclePhasesForTest();
auto* child_layout_view = ChildDocument().GetLayoutView();
auto* child_root_graphics_layer =
child_layout_view->Layer()->GraphicsLayerBacking(child_layout_view);
ASSERT_TRUE(child_root_graphics_layer);
EXPECT_EQ(GetLayoutView().Layer()->GraphicsLayerBacking(),
child_root_graphics_layer->Parent());
// This simulates that the subframe rebuilds GraphicsLayer tree, while the
// main frame doesn't have any compositing flags set. The root GraphicsLayer
// of the subframe should be hooked up in the GraphicsLayer tree correctly.
child_root_graphics_layer->RemoveFromParent();
child_layout_view->Compositor()->SetNeedsCompositingUpdate(
kCompositingUpdateRebuildTree);
GetLayoutView().Compositor()->UpdateAssignmentsIfNeededRecursive(
DocumentLifecycle::kCompositingAssignmentsClean);
ASSERT_EQ(
child_root_graphics_layer,
child_layout_view->Layer()->GraphicsLayerBacking(child_layout_view));
EXPECT_EQ(GetLayoutView().Layer()->GraphicsLayerBacking(),
child_root_graphics_layer->Parent());
}
} // namespace blink