layout: Allow non-absolutely-positioned elements with overflow: scroll

set to be scrolled.

This makes them establish stacking contexts, which is a CSS 2.1 spec
violation. However, we were already violating the spec here for
absolutely-positioned elements with `overflow: scroll`. It will probably
be easier to fix this spec violation once we either switch entirely to
WebRender or we have multiple layers per stacking context.

Closes #2742.
This commit is contained in:
Patrick Walton 2016-04-06 17:53:11 -07:00
parent 0b951f65b9
commit 1e884ddc69
4 changed files with 54 additions and 27 deletions

View file

@ -105,6 +105,10 @@ impl LayerId {
let LayerId(layer_type, id, _) = *self;
LayerId(layer_type, id, 0)
}
pub fn kind(&self) -> LayerType {
self.0
}
}
/// All layer-specific information that the painting task sends to the compositor other than the

View file

@ -1563,10 +1563,6 @@ impl BlockFlow {
}
pub fn has_scrolling_overflow(&self) -> bool {
if !self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) {
return false;
}
match (self.fragment.style().get_box().overflow_x,
self.fragment.style().get_box().overflow_y.0) {
(overflow_x::T::auto, _) | (overflow_x::T::scroll, _) |

View file

@ -1470,33 +1470,22 @@ impl FragmentDisplayListBuilding for Fragment {
// Clip according to the values of `overflow-x` and `overflow-y`.
//
// TODO(pcwalton): Support scrolling of non-absolutely-positioned elements.
// FIXME(pcwalton): This may be more complex than it needs to be, since it seems to be
// impossible with the computed value rules as they are to have `overflow-x: visible` with
// `overflow-y: <scrolling>` or vice versa!
match (self.style.get_box().overflow_x, is_absolutely_positioned) {
(overflow_x::T::hidden, _) |
(overflow_x::T::auto, false) |
(overflow_x::T::scroll, false) => {
let mut bounds = current_clip.bounding_rect();
let max_x = cmp::min(bounds.max_x(), overflow_clip_rect.max_x());
bounds.origin.x = cmp::max(bounds.origin.x, overflow_clip_rect.origin.x);
bounds.size.width = max_x - bounds.origin.x;
current_clip.intersect_rect(&bounds)
}
_ => {}
if let overflow_x::T::hidden = self.style.get_box().overflow_x {
let mut bounds = current_clip.bounding_rect();
let max_x = cmp::min(bounds.max_x(), overflow_clip_rect.max_x());
bounds.origin.x = cmp::max(bounds.origin.x, overflow_clip_rect.origin.x);
bounds.size.width = max_x - bounds.origin.x;
current_clip.intersect_rect(&bounds)
}
match (self.style.get_box().overflow_y.0, is_absolutely_positioned) {
(overflow_x::T::hidden, _) |
(overflow_x::T::auto, false) |
(overflow_x::T::scroll, false) => {
let mut bounds = current_clip.bounding_rect();
let max_y = cmp::min(bounds.max_y(), overflow_clip_rect.max_y());
bounds.origin.y = cmp::max(bounds.origin.y, overflow_clip_rect.origin.y);
bounds.size.height = max_y - bounds.origin.y;
current_clip.intersect_rect(&bounds)
}
_ => {}
if let overflow_x::T::hidden = self.style.get_box().overflow_y.0 {
let mut bounds = current_clip.bounding_rect();
let max_y = cmp::min(bounds.max_y(), overflow_clip_rect.max_y());
bounds.origin.y = cmp::max(bounds.origin.y, overflow_clip_rect.origin.y);
bounds.size.height = max_y - bounds.origin.y;
current_clip.intersect_rect(&bounds)
}
let border_radii = build_border_radius(stacking_relative_border_box,

View file

@ -0,0 +1,38 @@
<html>
<head>
<link rel=match href=overflow_simple_b.html>
<style>
#first {
height: 100px;
width: 100px;
overflow: scroll;
position: relative;
}
#second {
position: absolute;
height: 100px;
width: 90px;
top: 0;
left: 0;
background: green;
}
#third {
position: absolute;
height: 100px;
width: 110px;
top: 0;
left: 90px;
background: orange;
}
</style>
</head>
<body>
This element should be scrollable.
<div id="first">
<div id="second">
</div>
<div id="third">
</div>
</div>
</body>
</html>