diff options
author | Martin Robinson <mrobinson@igalia.com> | 2024-03-13 10:17:09 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-13 09:17:09 +0000 |
commit | 716f4a006d3e2c3d920eea82caf82521d4e7f86c (patch) | |
tree | 08531efcb7eca0da4a4f792e41d59b3bf4123279 | |
parent | 03d64d0675d4d1878232829293e7fdacaec5844e (diff) | |
download | servo-716f4a006d3e2c3d920eea82caf82521d4e7f86c.tar.gz servo-716f4a006d3e2c3d920eea82caf82521d4e7f86c.zip |
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>
17 files changed, 82 insertions, 27 deletions
diff --git a/components/layout/display_list/webrender_helpers.rs b/components/layout/display_list/webrender_helpers.rs index 04d8d825e06..49002b6b7cd 100644 --- a/components/layout/display_list/webrender_helpers.rs +++ b/components/layout/display_list/webrender_helpers.rs @@ -121,7 +121,13 @@ impl DisplayList { let content_size = self.bounds().size; let mut state = ClipScrollState::new( &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, ); diff --git a/components/layout_2020/display_list/mod.rs b/components/layout_2020/display_list/mod.rs index 35a58be985a..d755faae1cd 100644 --- a/components/layout_2020/display_list/mod.rs +++ b/components/layout_2020/display_list/mod.rs @@ -25,7 +25,7 @@ use style::values::specified::ui::CursorKind; use style_traits::CSSPixel; use webrender_api::{self as wr, units, ClipChainId, ClipId, CommonItemProperties}; use wr::units::LayoutVector2D; -use wr::BoxShadowClipMode; +use wr::{BoxShadowClipMode, ScrollSensitivity}; use crate::context::LayoutContext; use crate::display_list::conversions::ToWebRender; @@ -77,6 +77,7 @@ impl DisplayList { content_size: units::LayoutSize, pipeline_id: wr::PipelineId, epoch: wr::Epoch, + root_scroll_sensitivity: ScrollSensitivity, ) -> Self { Self { wr: wr::DisplayListBuilder::new(pipeline_id), @@ -85,6 +86,7 @@ impl DisplayList { content_size, pipeline_id, epoch, + root_scroll_sensitivity, ), } } diff --git a/components/layout_2020/display_list/stacking_context.rs b/components/layout_2020/display_list/stacking_context.rs index 68be4cc312b..6dd10641d0a 100644 --- a/components/layout_2020/display_list/stacking_context.rs +++ b/components/layout_2020/display_list/stacking_context.rs @@ -32,7 +32,7 @@ use crate::cell::ArcRefCell; use crate::display_list::conversions::{FilterToWebRender, ToWebRender}; use crate::display_list::DisplayListBuilder; use crate::fragment_tree::{ - BoxFragment, ContainingBlockManager, Fragment, FragmentTree, PositioningFragment, + BoxFragment, ContainingBlockManager, Fragment, FragmentFlags, FragmentTree, PositioningFragment, }; use crate::geom::{PhysicalRect, PhysicalSides}; use crate::style_ext::ComputedValuesExt; @@ -1247,6 +1247,24 @@ impl BoxFragment { 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 external_id = wr::ExternalScrollId( tag.to_display_list_fragment_id(), diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs index b41d7b6b999..ebdf690aac7 100644 --- a/components/layout_2020/flow/root.rs +++ b/components/layout_2020/flow/root.rs @@ -3,14 +3,17 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 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 serde::Serialize; use servo_arc::Arc; use style::dom::OpaqueNode; use style::properties::ComputedValues; -use style::values::computed::Length; +use style::values::computed::{Length, Overflow}; use style_traits::CSSPixel; +use webrender_api::ScrollSensitivity; use crate::cell::ArcRefCell; use crate::context::LayoutContext; @@ -36,6 +39,9 @@ pub struct BoxTree { /// <https://drafts.csswg.org/css-backgrounds/#special-backgrounds> canvas_background: CanvasBackground, + + /// Whether or not the root element should be sensitive to scrolling input events. + sensitive_to_scroll_input: bool, } impl BoxTree { @@ -48,6 +54,35 @@ impl BoxTree { // Zero box for `:root { display: none }`, one for the root element otherwise. 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 contains_floats = contents.contains_floats(); Self { @@ -56,6 +91,7 @@ impl BoxTree { contains_floats, }, 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, )) }; + let root_box = ArcRefCell::new(root_box); root_element .element_box_slot() @@ -330,11 +367,18 @@ impl BoxTree { acc.union(&child_overflow) }); + let root_scroll_sensitivity = if self.sensitive_to_scroll_input { + ScrollSensitivity::ScriptAndInputEvents + } else { + ScrollSensitivity::Script + }; + FragmentTree { root_fragments, scrollable_overflow, initial_containing_block: physical_containing_block, canvas_background: self.canvas_background.clone(), + root_scroll_sensitivity, } } } diff --git a/components/layout_2020/fragment_tree/fragment_tree.rs b/components/layout_2020/fragment_tree/fragment_tree.rs index 4bce1e9b125..21e4911fe63 100644 --- a/components/layout_2020/fragment_tree/fragment_tree.rs +++ b/components/layout_2020/fragment_tree/fragment_tree.rs @@ -10,7 +10,7 @@ use serde::Serialize; use style::animation::AnimationSetKey; use style::dom::OpaqueNode; use style::values::computed::Length; -use webrender_api::units; +use webrender_api::{units, ScrollSensitivity}; use super::{ContainingBlockManager, Fragment, Tag}; use crate::cell::ArcRefCell; @@ -40,6 +40,9 @@ pub struct FragmentTree { /// <https://drafts.csswg.org/css-backgrounds/#special-backgrounds> #[serde(skip)] pub(crate) canvas_background: CanvasBackground, + + /// Whether or not the root element is sensitive to scroll input events. + pub root_scroll_sensitivity: ScrollSensitivity, } impl FragmentTree { diff --git a/components/layout_thread_2020/lib.rs b/components/layout_thread_2020/lib.rs index 5ab2ca653e3..8528128150a 100644 --- a/components/layout_thread_2020/lib.rs +++ b/components/layout_thread_2020/lib.rs @@ -1026,6 +1026,7 @@ impl LayoutThread { fragment_tree.scrollable_overflow(), self.id.to_webrender(), epoch.into(), + fragment_tree.root_scroll_sensitivity, ); // `dump_serialized_display_list` doesn't actually print anything. It sets up diff --git a/components/shared/script/compositor.rs b/components/shared/script/compositor.rs index d874cc871b2..55e76beb85c 100644 --- a/components/shared/script/compositor.rs +++ b/components/shared/script/compositor.rs @@ -252,6 +252,7 @@ impl CompositorDisplayListInfo { content_size: LayoutSize, pipeline_id: PipelineId, epoch: Epoch, + root_scroll_sensitivity: ScrollSensitivity, ) -> Self { let mut scroll_tree = ScrollTree::default(); let root_reference_frame_id = scroll_tree.add_scroll_tree_node( @@ -265,7 +266,7 @@ impl CompositorDisplayListInfo { Some(ScrollableNodeInfo { external_id: ExternalScrollId(0, pipeline_id), scrollable_size: content_size - viewport_size, - scroll_sensitivity: ScrollSensitivity::ScriptAndInputEvents, + scroll_sensitivity: root_scroll_sensitivity, offset: LayoutVector2D::zero(), }), ); diff --git a/tests/wpt/meta/css/CSS2/visufx/overflow-propagation-001a.html.ini b/tests/wpt/meta/css/CSS2/visufx/overflow-propagation-001a.html.ini deleted file mode 100644 index 81d6ac64849..00000000000 --- a/tests/wpt/meta/css/CSS2/visufx/overflow-propagation-001a.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[overflow-propagation-001a.html] - expected: FAIL diff --git a/tests/wpt/meta/css/CSS2/visufx/overflow-propagation-001b.html.ini b/tests/wpt/meta/css/CSS2/visufx/overflow-propagation-001b.html.ini deleted file mode 100644 index ca92af5f99d..00000000000 --- a/tests/wpt/meta/css/CSS2/visufx/overflow-propagation-001b.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[overflow-propagation-001b.html] - expected: FAIL diff --git a/tests/wpt/meta/css/CSS2/visufx/overflow-propagation-001c.html.ini b/tests/wpt/meta/css/CSS2/visufx/overflow-propagation-001c.html.ini deleted file mode 100644 index f62da303dbc..00000000000 --- a/tests/wpt/meta/css/CSS2/visufx/overflow-propagation-001c.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[overflow-propagation-001c.html] - expected: FAIL diff --git a/tests/wpt/meta/css/css-backgrounds/background-origin/origin-border-box.html.ini b/tests/wpt/meta/css/css-backgrounds/background-origin/origin-border-box.html.ini deleted file mode 100644 index 5cb526d200a..00000000000 --- a/tests/wpt/meta/css/css-backgrounds/background-origin/origin-border-box.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[origin-border-box.html] - expected: FAIL diff --git a/tests/wpt/meta/css/css-backgrounds/background-origin/origin-border-box_with_size.html.ini b/tests/wpt/meta/css/css-backgrounds/background-origin/origin-border-box_with_size.html.ini deleted file mode 100644 index 2b3c71c8ba0..00000000000 --- a/tests/wpt/meta/css/css-backgrounds/background-origin/origin-border-box_with_size.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[origin-border-box_with_size.html] - expected: FAIL diff --git a/tests/wpt/meta/css/css-backgrounds/background-origin/origin-content-box_with_size.html.ini b/tests/wpt/meta/css/css-backgrounds/background-origin/origin-content-box_with_size.html.ini deleted file mode 100644 index cd17a133995..00000000000 --- a/tests/wpt/meta/css/css-backgrounds/background-origin/origin-content-box_with_size.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[origin-content-box_with_size.html] - expected: FAIL diff --git a/tests/wpt/meta/css/css-backgrounds/background-origin/origin-padding-box_with_size.html.ini b/tests/wpt/meta/css/css-backgrounds/background-origin/origin-padding-box_with_size.html.ini deleted file mode 100644 index fd6e5b300fe..00000000000 --- a/tests/wpt/meta/css/css-backgrounds/background-origin/origin-padding-box_with_size.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[origin-padding-box_with_size.html] - expected: FAIL diff --git a/tests/wpt/meta/css/css-transforms/transform-inherit-001.html.ini b/tests/wpt/meta/css/css-transforms/transform-inherit-001.html.ini deleted file mode 100644 index 26ab9cab286..00000000000 --- a/tests/wpt/meta/css/css-transforms/transform-inherit-001.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[transform-inherit-001.html] - expected: FAIL diff --git a/tests/wpt/meta/css/css-transforms/transform-transformed-td-contains-fixed-position.html.ini b/tests/wpt/meta/css/css-transforms/transform-transformed-td-contains-fixed-position.html.ini deleted file mode 100644 index 9fce6a3d73d..00000000000 --- a/tests/wpt/meta/css/css-transforms/transform-transformed-td-contains-fixed-position.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[transform-transformed-td-contains-fixed-position.html] - expected: FAIL diff --git a/tests/wpt/meta/css/css-transforms/transform-transformed-th-contains-fixed-position.html.ini b/tests/wpt/meta/css/css-transforms/transform-transformed-th-contains-fixed-position.html.ini deleted file mode 100644 index dd64b75e741..00000000000 --- a/tests/wpt/meta/css/css-transforms/transform-transformed-th-contains-fixed-position.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[transform-transformed-th-contains-fixed-position.html] - expected: FAIL |