Commit 207b0c65 authored by Scott Violet's avatar Scott Violet Committed by Commit Bot

blink: makes scrollWidth/Height return overflow size

When 'overflow: clip' is set along a particular axis,
scrollWidth/Height should return the overflow size.

BUG=1087667
TEST=external/wpt/css/css-overflow/overflow-clip-scroll-size.html

Change-Id: I447d6249ca0234c491521d42b1139e415b78bcbc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2531117
Commit-Queue: Scott Violet <sky@chromium.org>
Reviewed-by: default avatarIan Kilpatrick <ikilpatrick@chromium.org>
Cr-Commit-Position: refs/heads/master@{#829929}
parent 511a1926
...@@ -546,8 +546,6 @@ void LayoutBlock::ComputeLayoutOverflow(LayoutUnit old_client_after_edge, ...@@ -546,8 +546,6 @@ void LayoutBlock::ComputeLayoutOverflow(LayoutUnit old_client_after_edge,
} }
} }
} }
ApplyOverflowClipToLayoutOverflowRect();
} }
void LayoutBlock::AddVisualOverflowFromBlockChildren() { void LayoutBlock::AddVisualOverflowFromBlockChildren() {
......
...@@ -7271,7 +7271,23 @@ LayoutRect LayoutBox::LayoutOverflowRectForPropagation( ...@@ -7271,7 +7271,23 @@ LayoutRect LayoutBox::LayoutOverflowRectForPropagation(
if (!ShouldApplyLayoutContainment() && if (!ShouldApplyLayoutContainment() &&
(!ShouldClipOverflowAlongBothAxis() || (!ShouldClipOverflowAlongBothAxis() ||
StyleRef().OverflowClipMargin() != LayoutUnit())) { StyleRef().OverflowClipMargin() != LayoutUnit())) {
rect.Unite(LayoutOverflowRect()); LayoutRect overflow = LayoutOverflowRect();
if (HasNonVisibleOverflow()) {
const OverflowClipAxes overflow_clip_axes = GetOverflowClipAxes();
const LayoutUnit overflow_clip_margin = StyleRef().OverflowClipMargin();
LayoutRect clip_rect = rect;
if (overflow_clip_margin != LayoutUnit()) {
// overflow_clip_margin should only be set if 'overflow' is 'clip' along
// both axis.
DCHECK_EQ(overflow_clip_axes, kOverflowClipBothAxis);
clip_rect.Contract(BorderBoxOutsets());
clip_rect.Inflate(overflow_clip_margin);
overflow.Intersect(clip_rect);
} else {
ApplyOverflowClip(overflow_clip_axes, clip_rect, overflow);
}
}
rect.Unite(overflow);
} }
bool has_transform = HasLayer() && Layer()->Transform(); bool has_transform = HasLayer() && Layer()->Transform();
...@@ -7784,32 +7800,6 @@ PhysicalRect LayoutBox::DebugRect() const { ...@@ -7784,32 +7800,6 @@ PhysicalRect LayoutBox::DebugRect() const {
return PhysicalRect(PhysicalLocation(), Size()); return PhysicalRect(PhysicalLocation(), Size());
} }
void LayoutBox::ApplyOverflowClipToLayoutOverflowRect() {
NOT_DESTROYED();
if (!HasNonVisibleOverflow() || IsScrollContainer() ||
!LayoutOverflowIsSet()) {
return;
}
const OverflowClipAxes overflow_clip_axes = GetOverflowClipAxes();
if (overflow_clip_axes == kNoOverflowClip)
return;
LayoutRect no_overflow_rect = NoOverflowRect();
LayoutRect overflow_rect = overflow_->layout_overflow->LayoutOverflowRect();
const LayoutUnit overflow_clip_margin = StyleRef().OverflowClipMargin();
if (overflow_clip_margin != LayoutUnit()) {
// overflow_clip_margin should only be set if 'overflow' is 'clip' along
// both axis.
DCHECK_EQ(overflow_clip_axes, kOverflowClipBothAxis);
no_overflow_rect.Inflate(overflow_clip_margin);
overflow_rect.Intersect(no_overflow_rect);
} else {
ApplyOverflowClip(overflow_clip_axes, no_overflow_rect, overflow_rect);
}
overflow_->layout_overflow->SetLayoutOverflow(overflow_rect);
}
OverflowClipAxes LayoutBox::ComputeOverflowClipAxes() const { OverflowClipAxes LayoutBox::ComputeOverflowClipAxes() const {
NOT_DESTROYED(); NOT_DESTROYED();
if (ShouldApplyPaintContainment() || HasControlClip()) if (ShouldApplyPaintContainment() || HasControlClip())
......
...@@ -2062,11 +2062,6 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject { ...@@ -2062,11 +2062,6 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
protected: protected:
~LayoutBox() override; ~LayoutBox() override;
// Applies 'overflow:clip' as necessary to the accumulated layout overflow.
// During layout overflow is accumulated, once all the overflow has been
// accumulated 'overflow:clip' is then applied.
void ApplyOverflowClipToLayoutOverflowRect();
virtual OverflowClipAxes ComputeOverflowClipAxes() const; virtual OverflowClipAxes ComputeOverflowClipAxes() const;
void WillBeDestroyed() override; void WillBeDestroyed() override;
......
...@@ -563,12 +563,14 @@ TEST_P(LayoutBoxTest, LayoutOverflowRectWithOverflowClipMargin) { ...@@ -563,12 +563,14 @@ TEST_P(LayoutBoxTest, LayoutOverflowRectWithOverflowClipMargin) {
LayoutBox* clip1 = GetLayoutBoxByElementId("clip1"); LayoutBox* clip1 = GetLayoutBoxByElementId("clip1");
EXPECT_FALSE(clip1->IsScrollContainer()); EXPECT_FALSE(clip1->IsScrollContainer());
EXPECT_TRUE(clip1->ShouldClipOverflowAlongBothAxis()); EXPECT_TRUE(clip1->ShouldClipOverflowAlongBothAxis());
EXPECT_EQ(LayoutRect(-4, -4, 108, 58), clip1->LayoutOverflowRect()); EXPECT_EQ(LayoutRect(-4, -4, 108, 58),
clip1->LayoutOverflowRectForPropagation(clip1->Parent()));
LayoutBox* clip2 = GetLayoutBoxByElementId("clip2"); LayoutBox* clip2 = GetLayoutBoxByElementId("clip2");
EXPECT_FALSE(clip2->IsScrollContainer()); EXPECT_FALSE(clip2->IsScrollContainer());
EXPECT_TRUE(clip2->ShouldClipOverflowAlongBothAxis()); EXPECT_TRUE(clip2->ShouldClipOverflowAlongBothAxis());
EXPECT_EQ(LayoutRect(-6, -5, 110, 65), clip2->LayoutOverflowRect()); EXPECT_EQ(LayoutRect(-6, -5, 110, 65),
clip2->LayoutOverflowRectForPropagation(clip2->Parent()));
} }
TEST_P(LayoutBoxTest, ContentsVisualOverflowPropagation) { TEST_P(LayoutBoxTest, ContentsVisualOverflowPropagation) {
......
...@@ -91,29 +91,6 @@ NGLayoutOverflowCalculator::NGLayoutOverflowCalculator( ...@@ -91,29 +91,6 @@ NGLayoutOverflowCalculator::NGLayoutOverflowCalculator(
const PhysicalRect NGLayoutOverflowCalculator::Result( const PhysicalRect NGLayoutOverflowCalculator::Result(
const base::Optional<PhysicalRect> inflow_bounds) { const base::Optional<PhysicalRect> inflow_bounds) {
// Adjust the layout-overflow if we have "overflow: clip" present.
if (!is_scroll_container_ && has_non_visible_overflow_) {
const OverflowClipAxes overflow_clip_axes = node_.GetOverflowClipAxes();
const LayoutUnit overflow_clip_margin = node_.Style().OverflowClipMargin();
if (overflow_clip_margin != LayoutUnit()) {
// overflow_clip_margin should only be set if 'overflow' is 'clip' along
// both axis.
DCHECK_EQ(overflow_clip_axes, kOverflowClipBothAxis);
PhysicalRect expanded_padding_rect = padding_rect_;
expanded_padding_rect.Inflate(overflow_clip_margin);
layout_overflow_.Intersect(expanded_padding_rect);
} else {
if (overflow_clip_axes & kOverflowClipX) {
layout_overflow_.offset.left = padding_rect_.offset.left;
layout_overflow_.size.width = padding_rect_.size.width;
}
if (overflow_clip_axes & kOverflowClipY) {
layout_overflow_.offset.top = padding_rect_.offset.top;
layout_overflow_.size.height = padding_rect_.size.height;
}
}
}
if (!inflow_bounds || !is_scroll_container_) if (!inflow_bounds || !is_scroll_container_)
return layout_overflow_; return layout_overflow_;
...@@ -281,14 +258,38 @@ PhysicalRect NGLayoutOverflowCalculator::LayoutOverflowForPropagation( ...@@ -281,14 +258,38 @@ PhysicalRect NGLayoutOverflowCalculator::LayoutOverflowForPropagation(
if (!child_fragment.IsCSSBox()) if (!child_fragment.IsCSSBox())
return child_fragment.LayoutOverflow(); return child_fragment.LayoutOverflow();
// Children with overflow clip (e.g. a scrollable child) don't propagate any
// layout overflow.
PhysicalRect overflow = {{}, child_fragment.Size()}; PhysicalRect overflow = {{}, child_fragment.Size()};
const auto& child_style = child_fragment.Style();
if (!child_fragment.ShouldApplyLayoutContainment() && if (!child_fragment.ShouldApplyLayoutContainment() &&
(!child_fragment.ShouldClipOverflowAlongBothAxis() || (!child_fragment.ShouldClipOverflowAlongBothAxis() ||
child_fragment.Style().OverflowClipMargin() != LayoutUnit()) && child_style.OverflowClipMargin() != LayoutUnit()) &&
!child_fragment.IsInlineBox()) !child_fragment.IsInlineBox()) {
overflow.UniteEvenIfEmpty(child_fragment.LayoutOverflow()); PhysicalRect child_overflow = child_fragment.LayoutOverflow();
if (child_fragment.HasNonVisibleOverflow()) {
const OverflowClipAxes overflow_clip_axes =
child_fragment.GetOverflowClipAxes();
const LayoutUnit overflow_clip_margin = child_style.OverflowClipMargin();
if (overflow_clip_margin != LayoutUnit()) {
// overflow_clip_margin should only be set if 'overflow' is 'clip' along
// both axis.
DCHECK_EQ(overflow_clip_axes, kOverflowClipBothAxis);
PhysicalRect child_padding_rect({}, child_fragment.Size());
child_padding_rect.Contract(child_fragment.Borders());
child_padding_rect.Inflate(overflow_clip_margin);
child_overflow.Intersect(child_padding_rect);
} else {
if (overflow_clip_axes & kOverflowClipX) {
child_overflow.offset.left = LayoutUnit();
child_overflow.size.width = child_fragment.Size().width;
}
if (overflow_clip_axes & kOverflowClipY) {
child_overflow.offset.top = LayoutUnit();
child_overflow.size.height = child_fragment.Size().height;
}
}
}
overflow.UniteEvenIfEmpty(child_overflow);
}
// Apply any transforms to the overflow. // Apply any transforms to the overflow.
if (base::Optional<TransformationMatrix> transform = if (base::Optional<TransformationMatrix> transform =
......
...@@ -198,6 +198,12 @@ class CORE_EXPORT NGPhysicalBoxFragment final ...@@ -198,6 +198,12 @@ class CORE_EXPORT NGPhysicalBoxFragment final
PhysicalRect ScrollableOverflow(TextHeightType height_type) const; PhysicalRect ScrollableOverflow(TextHeightType height_type) const;
PhysicalRect ScrollableOverflowFromChildren(TextHeightType height_type) const; PhysicalRect ScrollableOverflowFromChildren(TextHeightType height_type) const;
OverflowClipAxes GetOverflowClipAxes() const {
if (const auto* layout_object = GetLayoutObject())
return layout_object->GetOverflowClipAxes();
return kNoOverflowClip;
}
// TODO(layout-dev): These three methods delegate to legacy layout for now, // TODO(layout-dev): These three methods delegate to legacy layout for now,
// update them to use LayoutNG based overflow information from the fragment // update them to use LayoutNG based overflow information from the fragment
// and change them to use NG geometry types once LayoutNG supports overflow. // and change them to use NG geometry types once LayoutNG supports overflow.
......
...@@ -167,7 +167,6 @@ class BoxLayoutOverflowModel { ...@@ -167,7 +167,6 @@ class BoxLayoutOverflowModel {
BoxLayoutOverflowModel& operator=(const BoxLayoutOverflowModel&) = delete; BoxLayoutOverflowModel& operator=(const BoxLayoutOverflowModel&) = delete;
const LayoutRect& LayoutOverflowRect() const { return layout_overflow_; } const LayoutRect& LayoutOverflowRect() const { return layout_overflow_; }
void SetLayoutOverflow(const LayoutRect& rect) { layout_overflow_ = rect; }
void AddLayoutOverflow(const LayoutRect& rect) { void AddLayoutOverflow(const LayoutRect& rect) {
UniteLayoutOverflowRect(layout_overflow_, rect); UniteLayoutOverflowRect(layout_overflow_, rect);
} }
......
<!doctype html>
<meta charset="utf-8">
<title>overflow: scroll width/height should return overflow size</title>
<link rel="help" href="https://drafts.csswg.org/css-overflow/#valdef-overflow-clip">
<link rel="author" title="Scott Violet" href="mailto:sky@chromium.org">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
.parent {
width: 100px;
height: 101px;
}
.child {
width: 200px;
height: 201px;
}
.overflow_clip_and_border {
width: 100px;
height: 101px;
overflow: clip;
border-width: 2px;
border-style: solid;
}
</style>
<div id="parent-clip-both" class="parent" style="overflow: clip">
<div class="child"></div>
</div>
<div id="parent-clip-x" class="parent" style="overflow: clip-x">
<div class="child"></div>
</div>
<div id="parent-clip-y" class="parent" style="overflow: clip-y">
<div class="child"></div>
</div>
<div id="border-equal-clip" class="parent">
<div class="overflow_clip_and_border"
style="overflow-clip-margin: 2px">
<div class="child"></div>
</div>
</div>
<div id="border-smaller-clip" class="parent">
<div class="overflow_clip_and_border"
style="overflow-clip-margin: 3px">
<div class="child"></div>
</div>
</div>
<div id="border-greater-clip" class="parent">
<div class="overflow_clip_and_border"
style="overflow-clip-margin: 1px">
<div class="child"></div>
</div>
</div>
<script>
test(() => {
var pClipBoth = document.getElementById("parent-clip-both");
assert_equals(pClipBoth.scrollWidth, 200);
assert_equals(pClipBoth.scrollHeight, 201);
var pClipX = document.getElementById("parent-clip-x");
assert_equals(pClipX.scrollWidth, 200);
assert_equals(pClipX.scrollHeight, 201);
var pClipY = document.getElementById("parent-clip-y");
assert_equals(pClipY.scrollWidth, 200);
assert_equals(pClipY.scrollHeight, 201);
}, "scroll size should match that of size specified by overflow: clip");
test(() => {
assert_equals(document.getElementById("border-equal-clip").scrollWidth,
104);
assert_equals(document.getElementById("border-smaller-clip").scrollWidth,
105);
assert_equals(document.getElementById("border-greater-clip").scrollWidth,
104);
}, "scroll size should take into account border size and overflow-clip-margin");
</script>
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