mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
layout: Propagate overflow values from <body>
to root element (#31618)
The specification gives instructions for how these values should be propagated. The other big changs here is that they aren't applied to the `<body>`. Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
03d64d0675
commit
716f4a006d
17 changed files with 82 additions and 27 deletions
|
@ -121,7 +121,13 @@ impl DisplayList {
|
||||||
let content_size = self.bounds().size;
|
let content_size = self.bounds().size;
|
||||||
let mut state = ClipScrollState::new(
|
let mut state = ClipScrollState::new(
|
||||||
&mut self.clip_scroll_nodes,
|
&mut self.clip_scroll_nodes,
|
||||||
CompositorDisplayListInfo::new(viewport_size, content_size, webrender_pipeline, epoch),
|
CompositorDisplayListInfo::new(
|
||||||
|
viewport_size,
|
||||||
|
content_size,
|
||||||
|
webrender_pipeline,
|
||||||
|
epoch,
|
||||||
|
webrender_api::ScrollSensitivity::ScriptAndInputEvents,
|
||||||
|
),
|
||||||
&mut builder,
|
&mut builder,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ use style::values::specified::ui::CursorKind;
|
||||||
use style_traits::CSSPixel;
|
use style_traits::CSSPixel;
|
||||||
use webrender_api::{self as wr, units, ClipChainId, ClipId, CommonItemProperties};
|
use webrender_api::{self as wr, units, ClipChainId, ClipId, CommonItemProperties};
|
||||||
use wr::units::LayoutVector2D;
|
use wr::units::LayoutVector2D;
|
||||||
use wr::BoxShadowClipMode;
|
use wr::{BoxShadowClipMode, ScrollSensitivity};
|
||||||
|
|
||||||
use crate::context::LayoutContext;
|
use crate::context::LayoutContext;
|
||||||
use crate::display_list::conversions::ToWebRender;
|
use crate::display_list::conversions::ToWebRender;
|
||||||
|
@ -77,6 +77,7 @@ impl DisplayList {
|
||||||
content_size: units::LayoutSize,
|
content_size: units::LayoutSize,
|
||||||
pipeline_id: wr::PipelineId,
|
pipeline_id: wr::PipelineId,
|
||||||
epoch: wr::Epoch,
|
epoch: wr::Epoch,
|
||||||
|
root_scroll_sensitivity: ScrollSensitivity,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
wr: wr::DisplayListBuilder::new(pipeline_id),
|
wr: wr::DisplayListBuilder::new(pipeline_id),
|
||||||
|
@ -85,6 +86,7 @@ impl DisplayList {
|
||||||
content_size,
|
content_size,
|
||||||
pipeline_id,
|
pipeline_id,
|
||||||
epoch,
|
epoch,
|
||||||
|
root_scroll_sensitivity,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ use crate::cell::ArcRefCell;
|
||||||
use crate::display_list::conversions::{FilterToWebRender, ToWebRender};
|
use crate::display_list::conversions::{FilterToWebRender, ToWebRender};
|
||||||
use crate::display_list::DisplayListBuilder;
|
use crate::display_list::DisplayListBuilder;
|
||||||
use crate::fragment_tree::{
|
use crate::fragment_tree::{
|
||||||
BoxFragment, ContainingBlockManager, Fragment, FragmentTree, PositioningFragment,
|
BoxFragment, ContainingBlockManager, Fragment, FragmentFlags, FragmentTree, PositioningFragment,
|
||||||
};
|
};
|
||||||
use crate::geom::{PhysicalRect, PhysicalSides};
|
use crate::geom::{PhysicalRect, PhysicalSides};
|
||||||
use crate::style_ext::ComputedValuesExt;
|
use crate::style_ext::ComputedValuesExt;
|
||||||
|
@ -1247,6 +1247,24 @@ impl BoxFragment {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// From https://drafts.csswg.org/css-overflow/#propdef-overflow:
|
||||||
|
// > UAs must apply the overflow-* values set on the root element to the viewport when the
|
||||||
|
// > root element’s display value is not none. However, when the root element is an [HTML]
|
||||||
|
// > html element (including XML syntax for HTML) whose overflow value is visible (in both
|
||||||
|
// > axes), and that element has as a child a body element whose display value is also not
|
||||||
|
// > none, user agents must instead apply the overflow-* values of the first such child
|
||||||
|
// > element to the viewport. The element from which the value is propagated must then have a
|
||||||
|
// > used overflow value of visible.
|
||||||
|
//
|
||||||
|
// TODO: This should only happen when the `display` value is actually propagated.
|
||||||
|
if self
|
||||||
|
.base
|
||||||
|
.flags
|
||||||
|
.contains(FragmentFlags::IS_BODY_ELEMENT_OF_HTML_ELEMENT_ROOT)
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let tag = self.base.tag?;
|
let tag = self.base.tag?;
|
||||||
let external_id = wr::ExternalScrollId(
|
let external_id = wr::ExternalScrollId(
|
||||||
tag.to_display_list_fragment_id(),
|
tag.to_display_list_fragment_id(),
|
||||||
|
|
|
@ -3,14 +3,17 @@
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use atomic_refcell::AtomicRef;
|
use atomic_refcell::AtomicRef;
|
||||||
use script_layout_interface::wrapper_traits::LayoutNode;
|
use script_layout_interface::wrapper_traits::{
|
||||||
|
LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
|
||||||
|
};
|
||||||
use script_layout_interface::{LayoutElementType, LayoutNodeType};
|
use script_layout_interface::{LayoutElementType, LayoutNodeType};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use servo_arc::Arc;
|
use servo_arc::Arc;
|
||||||
use style::dom::OpaqueNode;
|
use style::dom::OpaqueNode;
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
use style::values::computed::Length;
|
use style::values::computed::{Length, Overflow};
|
||||||
use style_traits::CSSPixel;
|
use style_traits::CSSPixel;
|
||||||
|
use webrender_api::ScrollSensitivity;
|
||||||
|
|
||||||
use crate::cell::ArcRefCell;
|
use crate::cell::ArcRefCell;
|
||||||
use crate::context::LayoutContext;
|
use crate::context::LayoutContext;
|
||||||
|
@ -36,6 +39,9 @@ pub struct BoxTree {
|
||||||
|
|
||||||
/// <https://drafts.csswg.org/css-backgrounds/#special-backgrounds>
|
/// <https://drafts.csswg.org/css-backgrounds/#special-backgrounds>
|
||||||
canvas_background: CanvasBackground,
|
canvas_background: CanvasBackground,
|
||||||
|
|
||||||
|
/// Whether or not the root element should be sensitive to scrolling input events.
|
||||||
|
sensitive_to_scroll_input: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BoxTree {
|
impl BoxTree {
|
||||||
|
@ -48,6 +54,35 @@ impl BoxTree {
|
||||||
// Zero box for `:root { display: none }`, one for the root element otherwise.
|
// Zero box for `:root { display: none }`, one for the root element otherwise.
|
||||||
assert!(boxes.len() <= 1);
|
assert!(boxes.len() <= 1);
|
||||||
|
|
||||||
|
// From https://drafts.csswg.org/css-overflow/#propdef-overflow:
|
||||||
|
// > UAs must apply the overflow-* values set on the root element to the viewport when the
|
||||||
|
// > root element’s display value is not none. However, when the root element is an [HTML]
|
||||||
|
// > html element (including XML syntax for HTML) whose overflow value is visible (in both
|
||||||
|
// > axes), and that element has as a child a body element whose display value is also not
|
||||||
|
// > none, user agents must instead apply the overflow-* values of the first such child
|
||||||
|
// > element to the viewport. The element from which the value is propagated must then have a
|
||||||
|
// > used overflow value of visible.
|
||||||
|
//
|
||||||
|
// TODO: This should handle when different overflow is set multiple axes, which requires the
|
||||||
|
// compositor scroll tree to allow setting a value per axis.
|
||||||
|
let root_style = root_element.style(context);
|
||||||
|
let mut root_overflow = root_style.get_box().overflow_y;
|
||||||
|
if root_overflow == Overflow::Visible && !root_style.get_box().display.is_none() {
|
||||||
|
for child in iter_child_nodes(root_element) {
|
||||||
|
if !child.to_threadsafe().as_element().map_or(false, |element| {
|
||||||
|
element.is_body_element_of_html_element_root()
|
||||||
|
}) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let style = child.style(context);
|
||||||
|
if !style.get_box().display.is_none() {
|
||||||
|
root_overflow = style.get_box().overflow_y;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let contents = BlockContainer::BlockLevelBoxes(boxes);
|
let contents = BlockContainer::BlockLevelBoxes(boxes);
|
||||||
let contains_floats = contents.contains_floats();
|
let contains_floats = contents.contains_floats();
|
||||||
Self {
|
Self {
|
||||||
|
@ -56,6 +91,7 @@ impl BoxTree {
|
||||||
contains_floats,
|
contains_floats,
|
||||||
},
|
},
|
||||||
canvas_background: CanvasBackground::for_root_element(context, root_element),
|
canvas_background: CanvasBackground::for_root_element(context, root_element),
|
||||||
|
sensitive_to_scroll_input: root_overflow != Overflow::Hidden,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,6 +288,7 @@ fn construct_for_root_element<'dom>(
|
||||||
propagated_text_decoration_line,
|
propagated_text_decoration_line,
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
|
|
||||||
let root_box = ArcRefCell::new(root_box);
|
let root_box = ArcRefCell::new(root_box);
|
||||||
root_element
|
root_element
|
||||||
.element_box_slot()
|
.element_box_slot()
|
||||||
|
@ -330,11 +367,18 @@ impl BoxTree {
|
||||||
acc.union(&child_overflow)
|
acc.union(&child_overflow)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let root_scroll_sensitivity = if self.sensitive_to_scroll_input {
|
||||||
|
ScrollSensitivity::ScriptAndInputEvents
|
||||||
|
} else {
|
||||||
|
ScrollSensitivity::Script
|
||||||
|
};
|
||||||
|
|
||||||
FragmentTree {
|
FragmentTree {
|
||||||
root_fragments,
|
root_fragments,
|
||||||
scrollable_overflow,
|
scrollable_overflow,
|
||||||
initial_containing_block: physical_containing_block,
|
initial_containing_block: physical_containing_block,
|
||||||
canvas_background: self.canvas_background.clone(),
|
canvas_background: self.canvas_background.clone(),
|
||||||
|
root_scroll_sensitivity,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use serde::Serialize;
|
||||||
use style::animation::AnimationSetKey;
|
use style::animation::AnimationSetKey;
|
||||||
use style::dom::OpaqueNode;
|
use style::dom::OpaqueNode;
|
||||||
use style::values::computed::Length;
|
use style::values::computed::Length;
|
||||||
use webrender_api::units;
|
use webrender_api::{units, ScrollSensitivity};
|
||||||
|
|
||||||
use super::{ContainingBlockManager, Fragment, Tag};
|
use super::{ContainingBlockManager, Fragment, Tag};
|
||||||
use crate::cell::ArcRefCell;
|
use crate::cell::ArcRefCell;
|
||||||
|
@ -40,6 +40,9 @@ pub struct FragmentTree {
|
||||||
/// <https://drafts.csswg.org/css-backgrounds/#special-backgrounds>
|
/// <https://drafts.csswg.org/css-backgrounds/#special-backgrounds>
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub(crate) canvas_background: CanvasBackground,
|
pub(crate) canvas_background: CanvasBackground,
|
||||||
|
|
||||||
|
/// Whether or not the root element is sensitive to scroll input events.
|
||||||
|
pub root_scroll_sensitivity: ScrollSensitivity,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FragmentTree {
|
impl FragmentTree {
|
||||||
|
|
|
@ -1026,6 +1026,7 @@ impl LayoutThread {
|
||||||
fragment_tree.scrollable_overflow(),
|
fragment_tree.scrollable_overflow(),
|
||||||
self.id.to_webrender(),
|
self.id.to_webrender(),
|
||||||
epoch.into(),
|
epoch.into(),
|
||||||
|
fragment_tree.root_scroll_sensitivity,
|
||||||
);
|
);
|
||||||
|
|
||||||
// `dump_serialized_display_list` doesn't actually print anything. It sets up
|
// `dump_serialized_display_list` doesn't actually print anything. It sets up
|
||||||
|
|
|
@ -252,6 +252,7 @@ impl CompositorDisplayListInfo {
|
||||||
content_size: LayoutSize,
|
content_size: LayoutSize,
|
||||||
pipeline_id: PipelineId,
|
pipeline_id: PipelineId,
|
||||||
epoch: Epoch,
|
epoch: Epoch,
|
||||||
|
root_scroll_sensitivity: ScrollSensitivity,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut scroll_tree = ScrollTree::default();
|
let mut scroll_tree = ScrollTree::default();
|
||||||
let root_reference_frame_id = scroll_tree.add_scroll_tree_node(
|
let root_reference_frame_id = scroll_tree.add_scroll_tree_node(
|
||||||
|
@ -265,7 +266,7 @@ impl CompositorDisplayListInfo {
|
||||||
Some(ScrollableNodeInfo {
|
Some(ScrollableNodeInfo {
|
||||||
external_id: ExternalScrollId(0, pipeline_id),
|
external_id: ExternalScrollId(0, pipeline_id),
|
||||||
scrollable_size: content_size - viewport_size,
|
scrollable_size: content_size - viewport_size,
|
||||||
scroll_sensitivity: ScrollSensitivity::ScriptAndInputEvents,
|
scroll_sensitivity: root_scroll_sensitivity,
|
||||||
offset: LayoutVector2D::zero(),
|
offset: LayoutVector2D::zero(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
[overflow-propagation-001a.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[overflow-propagation-001b.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[overflow-propagation-001c.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[origin-border-box.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[origin-border-box_with_size.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[origin-content-box_with_size.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[origin-padding-box_with_size.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[transform-inherit-001.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[transform-transformed-td-contains-fixed-position.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[transform-transformed-th-contains-fixed-position.html]
|
|
||||||
expected: FAIL
|
|
Loading…
Add table
Add a link
Reference in a new issue