blob: 2beb445f2e7c408608ac559c201c07ff571fece2 [file] [log] [blame]
// Copyright 2014 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/LayoutBox.h"
#include "core/html/HTMLElement.h"
#include "core/layout/ImageQualityController.h"
#include "core/layout/LayoutTestHelper.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace blink {
class LayoutBoxTest : public RenderingTest {};
TEST_F(LayoutBoxTest, BackgroundObscuredInRect) {
setBodyInnerHTML(
"<style>.column { width: 295.4px; padding-left: 10.4px; } "
".white-background { background: red; position: relative; overflow: "
"hidden; border-radius: 1px; }"
".black-background { height: 100px; background: black; color: white; } "
"</style>"
"<div class='column'> <div> <div id='target' class='white-background'> "
"<div class='black-background'></div> </div> </div> </div>");
LayoutObject* layoutObject = getLayoutObjectByElementId("target");
ASSERT_TRUE(layoutObject);
ASSERT_TRUE(layoutObject->backgroundIsKnownToBeObscured());
}
TEST_F(LayoutBoxTest, BackgroundRect) {
setBodyInnerHTML(
"<style>div { position: absolute; width: 100px; height: 100px; padding: "
"10px; border: 10px solid black; overflow: scroll; }"
"#target1 { background: "
"url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUg) border-box, green "
"content-box;}"
"#target2 { background: "
"url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUg) content-box, green "
"local border-box;}"
"#target3 { background: "
"url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUg) content-box, rgba(0, "
"255, 0, 0.5) border-box;}"
"#target4 { background-image: "
"url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUg), none;"
" background-clip: content-box, border-box;"
" background-blend-mode: normal, multiply;"
" background-color: green; }"
"#target5 { background: none border-box, green content-box;}"
"#target6 { background: green content-box local; }"
"</style>"
"<div id='target1'></div>"
"<div id='target2'></div>"
"<div id='target3'></div>"
"<div id='target4'></div>"
"<div id='target5'></div>"
"<div id='target6'></div>");
// #target1's opaque background color only fills the content box but its
// translucent image extends to the borders.
LayoutBox* layoutBox = toLayoutBox(getLayoutObjectByElementId("target1"));
EXPECT_EQ(LayoutRect(20, 20, 100, 100),
layoutBox->backgroundRect(BackgroundKnownOpaqueRect));
EXPECT_EQ(LayoutRect(0, 0, 140, 140),
layoutBox->backgroundRect(BackgroundClipRect));
// #target2's background color is opaque but only fills the padding-box
// because it has local attachment. This eclipses the content-box image.
layoutBox = toLayoutBox(getLayoutObjectByElementId("target2"));
EXPECT_EQ(LayoutRect(10, 10, 120, 120),
layoutBox->backgroundRect(BackgroundKnownOpaqueRect));
EXPECT_EQ(LayoutRect(10, 10, 120, 120),
layoutBox->backgroundRect(BackgroundClipRect));
// #target3's background color is not opaque so we only have a clip rect.
layoutBox = toLayoutBox(getLayoutObjectByElementId("target3"));
EXPECT_TRUE(layoutBox->backgroundRect(BackgroundKnownOpaqueRect).isEmpty());
EXPECT_EQ(LayoutRect(0, 0, 140, 140),
layoutBox->backgroundRect(BackgroundClipRect));
// #target4's background color has a blend mode so it isn't opaque.
layoutBox = toLayoutBox(getLayoutObjectByElementId("target4"));
EXPECT_TRUE(layoutBox->backgroundRect(BackgroundKnownOpaqueRect).isEmpty());
EXPECT_EQ(LayoutRect(0, 0, 140, 140),
layoutBox->backgroundRect(BackgroundClipRect));
// #target5's solid background only covers the content-box but it has a "none"
// background covering the border box.
layoutBox = toLayoutBox(getLayoutObjectByElementId("target5"));
EXPECT_EQ(LayoutRect(20, 20, 100, 100),
layoutBox->backgroundRect(BackgroundKnownOpaqueRect));
EXPECT_EQ(LayoutRect(0, 0, 140, 140),
layoutBox->backgroundRect(BackgroundClipRect));
// Because it can scroll due to local attachment, the opaque local background
// in #target6 is treated as padding box for the clip rect, but remains the
// content box for the known opaque rect.
layoutBox = toLayoutBox(getLayoutObjectByElementId("target6"));
EXPECT_EQ(LayoutRect(20, 20, 100, 100),
layoutBox->backgroundRect(BackgroundKnownOpaqueRect));
EXPECT_EQ(LayoutRect(10, 10, 120, 120),
layoutBox->backgroundRect(BackgroundClipRect));
}
TEST_F(LayoutBoxTest, LocationContainer) {
setBodyInnerHTML(
"<div id='div'>"
" <b>Inline content<img id='img'></b>"
"</div>"
"<table id='table'>"
" <tbody id='tbody'>"
" <tr id='row'>"
" <td id='cell' style='width: 100px; height: 80px'></td>"
" </tr>"
" </tbody>"
"</table>");
const LayoutBox* body = document().body()->layoutBox();
const LayoutBox* div = toLayoutBox(getLayoutObjectByElementId("div"));
const LayoutBox* img = toLayoutBox(getLayoutObjectByElementId("img"));
const LayoutBox* table = toLayoutBox(getLayoutObjectByElementId("table"));
const LayoutBox* tbody = toLayoutBox(getLayoutObjectByElementId("tbody"));
const LayoutBox* row = toLayoutBox(getLayoutObjectByElementId("row"));
const LayoutBox* cell = toLayoutBox(getLayoutObjectByElementId("cell"));
EXPECT_EQ(body, div->locationContainer());
EXPECT_EQ(div, img->locationContainer());
EXPECT_EQ(body, table->locationContainer());
EXPECT_EQ(table, tbody->locationContainer());
EXPECT_EQ(tbody, row->locationContainer());
EXPECT_EQ(tbody, cell->locationContainer());
}
TEST_F(LayoutBoxTest, TopLeftLocationFlipped) {
setBodyInnerHTML(
"<div style='width: 600px; height: 200px; writing-mode: vertical-rl'>"
" <div id='box1' style='width: 100px'></div>"
" <div id='box2' style='width: 200px'></div>"
"</div>");
const LayoutBox* box1 = toLayoutBox(getLayoutObjectByElementId("box1"));
EXPECT_EQ(LayoutPoint(0, 0), box1->location());
EXPECT_EQ(LayoutPoint(500, 0), box1->physicalLocation());
const LayoutBox* box2 = toLayoutBox(getLayoutObjectByElementId("box2"));
EXPECT_EQ(LayoutPoint(100, 0), box2->location());
EXPECT_EQ(LayoutPoint(300, 0), box2->physicalLocation());
}
TEST_F(LayoutBoxTest, TableRowCellTopLeftLocationFlipped) {
setBodyInnerHTML(
"<div style='writing-mode: vertical-rl'>"
" <table style='border-spacing: 0'>"
" <thead><tr><td style='width: 50px'></td></tr></thead>"
" <tbody>"
" <tr id='row1'>"
" <td id='cell1' style='width: 100px; height: 80px'></td>"
" </tr>"
" <tr id='row2'>"
" <td id='cell2' style='width: 300px; height: 80px'></td>"
" </tr>"
" </tbody>"
" </table>"
"</div>");
// location and physicalLocation of a table row or a table cell should be
// relative to the containing section.
const LayoutBox* row1 = toLayoutBox(getLayoutObjectByElementId("row1"));
EXPECT_EQ(LayoutPoint(0, 0), row1->location());
EXPECT_EQ(LayoutPoint(300, 0), row1->physicalLocation());
const LayoutBox* cell1 = toLayoutBox(getLayoutObjectByElementId("cell1"));
EXPECT_EQ(LayoutPoint(0, 0), cell1->location());
EXPECT_EQ(LayoutPoint(300, 0), cell1->physicalLocation());
const LayoutBox* row2 = toLayoutBox(getLayoutObjectByElementId("row2"));
EXPECT_EQ(LayoutPoint(100, 0), row2->location());
EXPECT_EQ(LayoutPoint(0, 0), row2->physicalLocation());
const LayoutBox* cell2 = toLayoutBox(getLayoutObjectByElementId("cell2"));
EXPECT_EQ(LayoutPoint(100, 0), cell2->location());
EXPECT_EQ(LayoutPoint(0, 0), cell2->physicalLocation());
}
TEST_F(LayoutBoxTest, LocationContainerOfSVG) {
setBodyInnerHTML(
"<svg id='svg' style='writing-mode:vertical-rl' width='500' height='500'>"
" <foreignObject x='44' y='77' width='100' height='80' id='foreign'>"
" <div id='child' style='width: 33px; height: 55px'>"
" </div>"
" </foreignObject>"
"</svg>");
const LayoutBox* svgRoot = toLayoutBox(getLayoutObjectByElementId("svg"));
const LayoutBox* foreign = toLayoutBox(getLayoutObjectByElementId("foreign"));
const LayoutBox* child = toLayoutBox(getLayoutObjectByElementId("child"));
EXPECT_EQ(document().body()->layoutObject(), svgRoot->locationContainer());
// The foreign object's location is not affected by SVGRoot's writing-mode.
EXPECT_FALSE(foreign->locationContainer());
EXPECT_EQ(LayoutRect(44, 77, 100, 80), foreign->frameRect());
EXPECT_EQ(LayoutPoint(44, 77), foreign->physicalLocation());
// The writing mode style should be still be inherited.
EXPECT_TRUE(foreign->hasFlippedBlocksWritingMode());
// The child of the foreign object is affected by writing-mode.
EXPECT_EQ(foreign, child->locationContainer());
EXPECT_EQ(LayoutRect(0, 0, 33, 55), child->frameRect());
EXPECT_EQ(LayoutPoint(67, 0), child->physicalLocation());
EXPECT_TRUE(child->hasFlippedBlocksWritingMode());
}
} // namespace blink