blob: b809285b0197ebbfd5d53af93cae3c3e3918197a [file] [log] [blame]
// Copyright 2015 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/layout/LayoutObject.h"
#include "core/frame/LocalFrameView.h"
#include "core/layout/LayoutTestHelper.h"
#include "core/layout/LayoutView.h"
#include "platform/json/JSONValues.h"
#include "platform/testing/RuntimeEnabledFeaturesTestHelpers.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace blink {
class LayoutObjectTest : public RenderingTest {
public:
LayoutObjectTest() : RenderingTest(EmptyLocalFrameClient::Create()) {}
};
TEST_F(LayoutObjectTest, LayoutDecoratedNameCalledWithPositionedObject) {
SetBodyInnerHTML("<div id='div' style='position: fixed'>test</div>");
Element* div = GetDocument().getElementById(AtomicString("div"));
DCHECK(div);
LayoutObject* obj = div->GetLayoutObject();
DCHECK(obj);
EXPECT_STREQ("LayoutBlockFlow (positioned)",
obj->DecoratedName().Ascii().data());
}
// Some display checks.
TEST_F(LayoutObjectTest, DisplayNoneCreateObject) {
SetBodyInnerHTML("<div style='display:none'></div>");
EXPECT_EQ(nullptr, GetDocument().body()->firstChild()->GetLayoutObject());
}
TEST_F(LayoutObjectTest, DisplayBlockCreateObject) {
SetBodyInnerHTML("<foo style='display:block'></foo>");
LayoutObject* layout_object =
GetDocument().body()->firstChild()->GetLayoutObject();
EXPECT_NE(nullptr, layout_object);
EXPECT_TRUE(layout_object->IsLayoutBlockFlow());
EXPECT_FALSE(layout_object->IsInline());
}
TEST_F(LayoutObjectTest, DisplayInlineBlockCreateObject) {
SetBodyInnerHTML("<foo style='display:inline-block'></foo>");
LayoutObject* layout_object =
GetDocument().body()->firstChild()->GetLayoutObject();
EXPECT_NE(nullptr, layout_object);
EXPECT_TRUE(layout_object->IsLayoutBlockFlow());
EXPECT_TRUE(layout_object->IsInline());
}
// Containing block test.
TEST_F(LayoutObjectTest, ContainingBlockLayoutViewShouldBeNull) {
EXPECT_EQ(nullptr, GetLayoutView().ContainingBlock());
}
TEST_F(LayoutObjectTest, ContainingBlockBodyShouldBeDocumentElement) {
EXPECT_EQ(GetDocument().body()->GetLayoutObject()->ContainingBlock(),
GetDocument().documentElement()->GetLayoutObject());
}
TEST_F(LayoutObjectTest, ContainingBlockDocumentElementShouldBeLayoutView) {
EXPECT_EQ(
GetDocument().documentElement()->GetLayoutObject()->ContainingBlock(),
GetLayoutView());
}
TEST_F(LayoutObjectTest, ContainingBlockStaticLayoutObjectShouldBeParent) {
SetBodyInnerHTML("<foo style='position:static'></foo>");
LayoutObject* body_layout_object = GetDocument().body()->GetLayoutObject();
LayoutObject* layout_object = body_layout_object->SlowFirstChild();
EXPECT_EQ(layout_object->ContainingBlock(), body_layout_object);
}
TEST_F(LayoutObjectTest,
ContainingBlockAbsoluteLayoutObjectShouldBeLayoutView) {
SetBodyInnerHTML("<foo style='position:absolute'></foo>");
LayoutObject* layout_object =
GetDocument().body()->GetLayoutObject()->SlowFirstChild();
EXPECT_EQ(layout_object->ContainingBlock(), GetLayoutView());
}
TEST_F(
LayoutObjectTest,
ContainingBlockAbsoluteLayoutObjectShouldBeNonStaticallyPositionedBlockAncestor) {
SetBodyInnerHTML(
"<div style='position:relative'><bar "
"style='position:absolute'></bar></div>");
LayoutObject* containing_blocklayout_object =
GetDocument().body()->GetLayoutObject()->SlowFirstChild();
LayoutObject* layout_object = containing_blocklayout_object->SlowFirstChild();
EXPECT_EQ(layout_object->ContainingBlock(), containing_blocklayout_object);
}
TEST_F(
LayoutObjectTest,
ContainingBlockAbsoluteLayoutObjectShouldNotBeNonStaticallyPositionedInlineAncestor) {
SetBodyInnerHTML(
"<span style='position:relative'><bar "
"style='position:absolute'></bar></span>");
LayoutObject* body_layout_object = GetDocument().body()->GetLayoutObject();
LayoutObject* layout_object =
body_layout_object->SlowFirstChild()->SlowFirstChild();
// Sanity check: Make sure we don't generate anonymous objects.
EXPECT_EQ(nullptr, body_layout_object->SlowFirstChild()->NextSibling());
EXPECT_EQ(nullptr, layout_object->SlowFirstChild());
EXPECT_EQ(nullptr, layout_object->NextSibling());
EXPECT_EQ(layout_object->ContainingBlock(), body_layout_object);
}
TEST_F(LayoutObjectTest, PaintingLayerOfOverflowClipLayerUnderColumnSpanAll) {
SetBodyInnerHTML(
"<div id='columns' style='columns: 3'>"
" <div style='column-span: all'>"
" <div id='overflow-clip-layer' style='height: 100px; overflow: "
"hidden'></div>"
" </div>"
"</div>");
LayoutObject* overflow_clip_object =
GetLayoutObjectByElementId("overflow-clip-layer");
LayoutBlock* columns = ToLayoutBlock(GetLayoutObjectByElementId("columns"));
EXPECT_EQ(columns->Layer(), overflow_clip_object->PaintingLayer());
}
TEST_F(LayoutObjectTest, FloatUnderBlock) {
SetBodyInnerHTML(
"<div id='layered-div' style='position: absolute'>"
" <div id='container'>"
" <div id='floating' style='float: left'>FLOAT</div>"
" </div>"
"</div>");
LayoutBoxModelObject* layered_div =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("layered-div"));
LayoutBoxModelObject* container =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("container"));
LayoutObject* floating = GetLayoutObjectByElementId("floating");
EXPECT_EQ(layered_div->Layer(), layered_div->PaintingLayer());
EXPECT_EQ(layered_div->Layer(), floating->PaintingLayer());
EXPECT_EQ(container, floating->Container());
EXPECT_EQ(container, floating->ContainingBlock());
}
TEST_F(LayoutObjectTest, FloatUnderInline) {
SetBodyInnerHTML(
"<div id='layered-div' style='position: absolute'>"
" <div id='container'>"
" <span id='layered-span' style='position: relative'>"
" <div id='floating' style='float: left'>FLOAT</div>"
" </span>"
" </div>"
"</div>");
LayoutBoxModelObject* layered_div =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("layered-div"));
LayoutBoxModelObject* container =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("container"));
LayoutBoxModelObject* layered_span =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("layered-span"));
LayoutObject* floating = GetLayoutObjectByElementId("floating");
EXPECT_EQ(layered_div->Layer(), layered_div->PaintingLayer());
EXPECT_EQ(layered_span->Layer(), layered_span->PaintingLayer());
EXPECT_EQ(layered_div->Layer(), floating->PaintingLayer());
EXPECT_EQ(container, floating->Container());
EXPECT_EQ(container, floating->ContainingBlock());
LayoutObject::AncestorSkipInfo skip_info(layered_span);
EXPECT_EQ(container, floating->Container(&skip_info));
EXPECT_TRUE(skip_info.AncestorSkipped());
skip_info = LayoutObject::AncestorSkipInfo(container);
EXPECT_EQ(container, floating->Container(&skip_info));
EXPECT_FALSE(skip_info.AncestorSkipped());
}
TEST_F(LayoutObjectTest, MutableForPaintingClearPaintFlags) {
LayoutObject* object = GetDocument().body()->GetLayoutObject();
object->SetShouldDoFullPaintInvalidation();
EXPECT_TRUE(object->ShouldDoFullPaintInvalidation());
EXPECT_TRUE(object->NeedsPaintOffsetAndVisualRectUpdate());
object->SetMayNeedPaintInvalidation();
EXPECT_TRUE(object->MayNeedPaintInvalidation());
object->SetMayNeedPaintInvalidationSubtree();
EXPECT_TRUE(object->MayNeedPaintInvalidationSubtree());
object->SetMayNeedPaintInvalidationAnimatedBackgroundImage();
EXPECT_TRUE(object->MayNeedPaintInvalidationAnimatedBackgroundImage());
object->SetShouldInvalidateSelection();
EXPECT_TRUE(object->ShouldInvalidateSelection());
object->SetBackgroundChangedSinceLastPaintInvalidation();
EXPECT_TRUE(object->BackgroundChangedSinceLastPaintInvalidation());
object->SetNeedsPaintPropertyUpdate();
EXPECT_TRUE(object->NeedsPaintPropertyUpdate());
EXPECT_TRUE(object->Parent()->DescendantNeedsPaintPropertyUpdate());
object->bitfields_.SetDescendantNeedsPaintPropertyUpdate(true);
EXPECT_TRUE(object->DescendantNeedsPaintPropertyUpdate());
GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kInPrePaint);
object->GetMutableForPainting().ClearPaintFlags();
EXPECT_FALSE(object->ShouldDoFullPaintInvalidation());
EXPECT_FALSE(object->MayNeedPaintInvalidation());
EXPECT_FALSE(object->MayNeedPaintInvalidationSubtree());
EXPECT_FALSE(object->MayNeedPaintInvalidationAnimatedBackgroundImage());
EXPECT_FALSE(object->ShouldInvalidateSelection());
EXPECT_FALSE(object->BackgroundChangedSinceLastPaintInvalidation());
EXPECT_FALSE(object->NeedsPaintPropertyUpdate());
EXPECT_FALSE(object->DescendantNeedsPaintPropertyUpdate());
}
TEST_F(LayoutObjectTest, SubtreeNeedsPaintPropertyUpdate) {
LayoutObject* object = GetDocument().body()->GetLayoutObject();
object->SetSubtreeNeedsPaintPropertyUpdate();
EXPECT_TRUE(object->SubtreeNeedsPaintPropertyUpdate());
EXPECT_TRUE(object->NeedsPaintPropertyUpdate());
EXPECT_TRUE(object->Parent()->DescendantNeedsPaintPropertyUpdate());
GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kInPrePaint);
object->GetMutableForPainting().ClearPaintFlags();
EXPECT_FALSE(object->SubtreeNeedsPaintPropertyUpdate());
EXPECT_FALSE(object->NeedsPaintPropertyUpdate());
}
TEST_F(LayoutObjectTest, NeedsPaintOffsetAndVisualRectUpdate) {
LayoutObject* object = GetDocument().body()->GetLayoutObject();
LayoutObject* parent = object->Parent();
object->SetShouldDoFullPaintInvalidation();
EXPECT_TRUE(object->ShouldDoFullPaintInvalidation());
EXPECT_TRUE(object->NeedsPaintOffsetAndVisualRectUpdate());
EXPECT_TRUE(parent->MayNeedPaintInvalidation());
EXPECT_TRUE(parent->NeedsPaintOffsetAndVisualRectUpdate());
object->ClearPaintInvalidationFlags();
EXPECT_FALSE(object->ShouldDoFullPaintInvalidation());
EXPECT_FALSE(object->NeedsPaintOffsetAndVisualRectUpdate());
parent->ClearPaintInvalidationFlags();
EXPECT_FALSE(parent->MayNeedPaintInvalidation());
EXPECT_FALSE(parent->NeedsPaintOffsetAndVisualRectUpdate());
object->SetMayNeedPaintInvalidation();
EXPECT_TRUE(object->MayNeedPaintInvalidation());
EXPECT_TRUE(object->NeedsPaintOffsetAndVisualRectUpdate());
EXPECT_TRUE(parent->MayNeedPaintInvalidation());
EXPECT_TRUE(parent->NeedsPaintOffsetAndVisualRectUpdate());
object->ClearPaintInvalidationFlags();
EXPECT_FALSE(object->MayNeedPaintInvalidation());
EXPECT_FALSE(object->NeedsPaintOffsetAndVisualRectUpdate());
parent->ClearPaintInvalidationFlags();
EXPECT_FALSE(parent->MayNeedPaintInvalidation());
EXPECT_FALSE(parent->NeedsPaintOffsetAndVisualRectUpdate());
object->SetShouldDoFullPaintInvalidationWithoutGeometryChange();
EXPECT_TRUE(object->ShouldDoFullPaintInvalidation());
EXPECT_FALSE(object->NeedsPaintOffsetAndVisualRectUpdate());
EXPECT_TRUE(parent->MayNeedPaintInvalidation());
EXPECT_FALSE(parent->NeedsPaintOffsetAndVisualRectUpdate());
object->SetMayNeedPaintInvalidation();
EXPECT_TRUE(object->NeedsPaintOffsetAndVisualRectUpdate());
EXPECT_TRUE(parent->NeedsPaintOffsetAndVisualRectUpdate());
object->ClearPaintInvalidationFlags();
EXPECT_FALSE(object->MayNeedPaintInvalidation());
EXPECT_FALSE(object->NeedsPaintOffsetAndVisualRectUpdate());
parent->ClearPaintInvalidationFlags();
EXPECT_FALSE(parent->MayNeedPaintInvalidation());
EXPECT_FALSE(parent->NeedsPaintOffsetAndVisualRectUpdate());
object->SetMayNeedPaintInvalidationWithoutGeometryChange();
EXPECT_TRUE(object->MayNeedPaintInvalidation());
EXPECT_FALSE(object->NeedsPaintOffsetAndVisualRectUpdate());
EXPECT_TRUE(parent->MayNeedPaintInvalidation());
EXPECT_FALSE(parent->NeedsPaintOffsetAndVisualRectUpdate());
object->SetMayNeedPaintInvalidation();
EXPECT_TRUE(object->NeedsPaintOffsetAndVisualRectUpdate());
EXPECT_TRUE(parent->NeedsPaintOffsetAndVisualRectUpdate());
object->ClearPaintInvalidationFlags();
EXPECT_FALSE(object->MayNeedPaintInvalidation());
EXPECT_FALSE(object->NeedsPaintOffsetAndVisualRectUpdate());
parent->ClearPaintInvalidationFlags();
EXPECT_FALSE(parent->MayNeedPaintInvalidation());
EXPECT_FALSE(parent->NeedsPaintOffsetAndVisualRectUpdate());
}
} // namespace blink