blob: cc0800676a8052ef71f8f786090999c6621f9c94 [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 "core/paint/BlockPainter.h"
#include <gtest/gtest.h>
#include "core/frame/LocalFrameView.h"
#include "core/paint/PaintControllerPaintTest.h"
#include "platform/graphics/paint/DrawingDisplayItem.h"
#include "platform/graphics/paint/PaintChunk.h"
#include "platform/graphics/paint/ScrollHitTestDisplayItem.h"
namespace blink {
using BlockPainterTest = PaintControllerPaintTest;
INSTANTIATE_TEST_CASE_P(
All,
BlockPainterTest,
::testing::ValuesIn(kSlimmingPaintV2TestConfigurations));
TEST_P(BlockPainterTest, ScrollHitTestProperties) {
SetBodyInnerHTML(R"HTML(
<style>
::-webkit-scrollbar { display: none; }
body { margin: 0 }
#container { width: 200px; height: 200px;
overflow: scroll; background: blue; }
#child { width: 100px; height: 300px; background: green; }
</style>
<div id='container'>
<div id='child'></div>
</div>
)HTML");
auto& container = *GetLayoutObjectByElementId("container");
auto& child = *GetLayoutObjectByElementId("child");
// The scroll hit test should be after the container background but before the
// scrolled contents.
EXPECT_DISPLAY_LIST(RootPaintController().GetDisplayItemList(), 4,
TestDisplayItem(GetLayoutView(), kDocumentBackgroundType),
TestDisplayItem(container, kBackgroundType),
TestDisplayItem(container, kScrollHitTestType),
TestDisplayItem(child, kBackgroundType));
auto paint_chunks = RootPaintController().GetPaintArtifact().PaintChunks();
EXPECT_EQ(4u, paint_chunks.size());
const auto& root_chunk = RootPaintController().PaintChunks()[0];
EXPECT_EQ(GetLayoutView().Layer(), &root_chunk.id.client);
const auto& container_chunk = RootPaintController().PaintChunks()[1];
EXPECT_EQ(ToLayoutBoxModelObject(container).Layer(),
&container_chunk.id.client);
// The container's scroll hit test.
const auto& scroll_hit_test_chunk = RootPaintController().PaintChunks()[2];
EXPECT_EQ(&container, &scroll_hit_test_chunk.id.client);
EXPECT_EQ(kScrollHitTestType, scroll_hit_test_chunk.id.type);
// The scrolled contents.
const auto& contents_chunk = RootPaintController().PaintChunks()[3];
EXPECT_EQ(&container, &contents_chunk.id.client);
// The document should not scroll so there should be no scroll offset
// transform.
auto* root_transform = root_chunk.properties.property_tree_state.Transform();
EXPECT_EQ(nullptr, root_transform->ScrollNode());
// The container's background chunk should not scroll and therefore should use
// the root transform. Its local transform is actually a paint offset
// transform.
auto* container_transform =
container_chunk.properties.property_tree_state.Transform()->Parent();
EXPECT_EQ(root_transform, container_transform);
EXPECT_EQ(nullptr, container_transform->ScrollNode());
// The scroll hit test should not be scrolled and should not be clipped.
// Its local transform is actually a paint offset transform.
auto* scroll_hit_test_transform =
scroll_hit_test_chunk.properties.property_tree_state.Transform()
->Parent();
EXPECT_EQ(nullptr, scroll_hit_test_transform->ScrollNode());
EXPECT_EQ(root_transform, scroll_hit_test_transform);
auto* scroll_hit_test_clip =
scroll_hit_test_chunk.properties.property_tree_state.Clip();
EXPECT_EQ(FloatRect(0, 0, 800, 600), scroll_hit_test_clip->ClipRect().Rect());
// The scrolled contents should be scrolled and clipped.
auto* contents_transform =
contents_chunk.properties.property_tree_state.Transform();
auto* contents_scroll = contents_transform->ScrollNode();
EXPECT_EQ(IntRect(0, 0, 200, 300), contents_scroll->ContentsRect());
EXPECT_EQ(IntRect(0, 0, 200, 200), contents_scroll->ContainerRect());
auto* contents_clip = contents_chunk.properties.property_tree_state.Clip();
EXPECT_EQ(FloatRect(0, 0, 200, 200), contents_clip->ClipRect().Rect());
// The scroll hit test display item maintains a reference to a scroll offset
// translation node and the contents should be scrolled by this node.
const auto& scroll_hit_test_display_item =
static_cast<const ScrollHitTestDisplayItem&>(
RootPaintController()
.GetDisplayItemList()[scroll_hit_test_chunk.begin_index]);
EXPECT_EQ(contents_transform,
&scroll_hit_test_display_item.scroll_offset_node());
}
TEST_P(BlockPainterTest, FrameScrollHitTestProperties) {
SetBodyInnerHTML(R"HTML(
<style>
::-webkit-scrollbar { display: none; }
body { margin: 0; }
#child { width: 100px; height: 2000px; background: green; }
</style>
<div id='child'></div>
)HTML");
auto& html = *GetDocument().documentElement()->GetLayoutObject();
auto& child = *GetLayoutObjectByElementId("child");
// The scroll hit test should be after the document background but before the
// scrolled contents.
EXPECT_DISPLAY_LIST(RootPaintController().GetDisplayItemList(), 3,
TestDisplayItem(GetLayoutView(), kDocumentBackgroundType),
TestDisplayItem(GetLayoutView(), kScrollHitTestType),
TestDisplayItem(child, kBackgroundType));
auto paint_chunks = RootPaintController().GetPaintArtifact().PaintChunks();
EXPECT_EQ(3u, paint_chunks.size());
const auto& root_chunk = RootPaintController().PaintChunks()[0];
EXPECT_EQ(GetLayoutView().Layer(), &root_chunk.id.client);
const auto& scroll_hit_test_chunk = RootPaintController().PaintChunks()[1];
EXPECT_EQ(&GetLayoutView(), &scroll_hit_test_chunk.id.client);
EXPECT_EQ(kScrollHitTestType, scroll_hit_test_chunk.id.type);
// The scrolled contents.
const auto& contents_chunk = RootPaintController().PaintChunks()[2];
EXPECT_EQ(ToLayoutBoxModelObject(html).Layer(), &contents_chunk.id.client);
// The scroll hit test should not be scrolled and should not be clipped.
auto* scroll_hit_test_transform =
scroll_hit_test_chunk.properties.property_tree_state.Transform();
EXPECT_EQ(nullptr, scroll_hit_test_transform->ScrollNode());
auto* scroll_hit_test_clip =
scroll_hit_test_chunk.properties.property_tree_state.Clip();
EXPECT_EQ(LayoutRect::InfiniteIntRect(),
scroll_hit_test_clip->ClipRect().Rect());
// The scrolled contents should be scrolled and clipped.
auto* contents_transform =
contents_chunk.properties.property_tree_state.Transform();
auto* contents_scroll = contents_transform->ScrollNode();
EXPECT_EQ(IntRect(0, 0, 800, 2000), contents_scroll->ContentsRect());
EXPECT_EQ(IntRect(0, 0, 800, 600), contents_scroll->ContainerRect());
auto* contents_clip = contents_chunk.properties.property_tree_state.Clip();
EXPECT_EQ(FloatRect(0, 0, 800, 600), contents_clip->ClipRect().Rect());
// The scroll hit test display item maintains a reference to a scroll offset
// translation node and the contents should be scrolled by this node.
const auto& scroll_hit_test_display_item =
static_cast<const ScrollHitTestDisplayItem&>(
RootPaintController()
.GetDisplayItemList()[scroll_hit_test_chunk.begin_index]);
EXPECT_EQ(contents_transform,
&scroll_hit_test_display_item.scroll_offset_node());
}
} // namespace blink