From 8825d588c14ba6a72fdad4ec5ae67c7b4397daf1 Mon Sep 17 00:00:00 2001 From: Martin Robinson Date: Wed, 15 Jan 2020 13:48:25 +0100 Subject: [PATCH 1/4] Add initial support for scrollable overflow in layout_2020 This still isn't totally correct and non-root scrolling is not handled at all, but the root frame now scrolls. --- components/layout_2020/flow/inline.rs | 65 +++++++++++++------------ components/layout_2020/flow/mod.rs | 19 ++++---- components/layout_2020/flow/root.rs | 52 ++++++++++++++++++-- components/layout_2020/fragments.rs | 68 +++++++++++++++++++++++++++ components/layout_2020/geom.rs | 36 ++++++++++++++ components/layout_2020/positioned.rs | 20 ++++---- components/layout_thread_2020/lib.rs | 8 +++- 7 files changed, 212 insertions(+), 56 deletions(-) diff --git a/components/layout_2020/flow/inline.rs b/components/layout_2020/flow/inline.rs index 7c3fd9a29e3..ba9453a5b80 100644 --- a/components/layout_2020/flow/inline.rs +++ b/components/layout_2020/flow/inline.rs @@ -339,11 +339,12 @@ impl Lines { block: line_block_size, }; self.next_line_block_position += size.block; - self.fragments.push(Fragment::Anonymous(AnonymousFragment { - children: line_contents, - rect: Rect { start_corner, size }, - mode: containing_block.style.writing_mode, - })) + self.fragments + .push(Fragment::Anonymous(AnonymousFragment::new( + Rect { start_corner, size }, + line_contents, + containing_block.style.writing_mode, + ))) } } @@ -402,22 +403,24 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> { inline_position: &mut Length, at_line_break: bool, ) { - let mut fragment = BoxFragment { - tag: self.tag, - style: self.style.clone(), - children: std::mem::take(&mut nesting_level.fragments_so_far), - content_rect: Rect { - size: Vec2 { - inline: *inline_position - self.start_corner.inline, - block: nesting_level.max_block_size_of_fragments_so_far, - }, - start_corner: self.start_corner.clone(), + let content_rect = Rect { + size: Vec2 { + inline: *inline_position - self.start_corner.inline, + block: nesting_level.max_block_size_of_fragments_so_far, }, - padding: self.padding.clone(), - border: self.border.clone(), - margin: self.margin.clone(), - block_margins_collapsed_with_children: CollapsedBlockMargins::zero(), + start_corner: self.start_corner.clone(), }; + + let mut fragment = BoxFragment::new( + self.tag, + self.style.clone(), + std::mem::take(&mut nesting_level.fragments_so_far), + content_rect, + self.padding.clone(), + self.border.clone(), + self.margin.clone(), + CollapsedBlockMargins::zero(), + ); let last_fragment = self.last_box_tree_fragment && !at_line_break; if last_fragment { *inline_position += fragment.padding.inline_end + @@ -470,16 +473,16 @@ fn layout_atomic<'box_tree>( let size = replaced.used_size_as_if_inline_element(ifc.containing_block, &atomic.style); let fragments = replaced.make_fragments(&atomic.style, size.clone()); let content_rect = Rect { start_corner, size }; - BoxFragment { - tag: atomic.tag, - style: atomic.style.clone(), - children: fragments, + BoxFragment::new( + atomic.tag, + atomic.style.clone(), + fragments, content_rect, padding, border, margin, - block_margins_collapsed_with_children: CollapsedBlockMargins::zero(), - } + CollapsedBlockMargins::zero(), + ) }, Err(non_replaced) => { let box_size = atomic.style.box_size(); @@ -545,16 +548,16 @@ fn layout_atomic<'box_tree>( inline: inline_size, }, }; - BoxFragment { - tag: atomic.tag, - style: atomic.style.clone(), - children: independent_layout.fragments, + BoxFragment::new( + atomic.tag, + atomic.style.clone(), + independent_layout.fragments, content_rect, padding, border, margin, - block_margins_collapsed_with_children: CollapsedBlockMargins::zero(), - } + CollapsedBlockMargins::zero(), + ) }, }; diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index b7373baf55a..b047fee78df 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -495,16 +495,16 @@ fn layout_in_flow_non_replaced_block_level<'a>( inline: inline_size, }, }; - BoxFragment { + BoxFragment::new( tag, - style: style.clone(), - children: fragments, + style.clone(), + fragments, content_rect, padding, border, margin, block_margins_collapsed_with_children, - } + ) } /// https://drafts.csswg.org/css2/visudet.html#block-replaced-width @@ -545,16 +545,17 @@ fn layout_in_flow_replaced_block_level<'a>( }, size, }; - BoxFragment { + let block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin); + BoxFragment::new( tag, - style: style.clone(), - children: fragments, + style.clone(), + fragments, content_rect, padding, border, - block_margins_collapsed_with_children: CollapsedBlockMargins::from_margin(&margin), margin, - } + block_margins_collapsed_with_children, + ) } fn solve_inline_margins_for_in_flow_block_level( diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs index 14b1081c84a..5b801c1fd7a 100644 --- a/components/layout_2020/flow/root.rs +++ b/components/layout_2020/flow/root.rs @@ -11,12 +11,14 @@ use crate::formatting_contexts::IndependentFormattingContext; use crate::fragments::Fragment; use crate::geom; use crate::geom::flow_relative::Vec2; +use crate::geom::physical; use crate::positioned::AbsolutelyPositionedBox; use crate::positioned::PositioningContext; use crate::replaced::ReplacedContent; use crate::sizing::ContentSizesRequest; use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside}; use crate::DefiniteContainingBlock; +use euclid::Size2D; use gfx_traits::print_tree::PrintTree; use script_layout_interface::wrapper_traits::LayoutNode; use servo_arc::Arc; @@ -26,7 +28,14 @@ use style::Zero; use style_traits::CSSPixel; pub struct BoxTreeRoot(BlockFormattingContext); -pub struct FragmentTreeRoot(Vec); + +pub struct FragmentTreeRoot { + /// The children of the root of the fragment tree. + children: Vec, + + /// The scrollable overflow of the root of the fragment tree. + scrollable_overflow: physical::Rect, +} impl BoxTreeRoot { pub fn construct<'dom, Node>(context: &LayoutContext, root_element: Node) -> Self @@ -131,7 +140,35 @@ impl BoxTreeRoot { &mut independent_layout.fragments, ); - FragmentTreeRoot(independent_layout.fragments) + // FIXME(mrobinson, bug 25564): We should be using the containing block + // here to properly convert scrollable overflow to physical geometry. + let scrollable_overflow = + independent_layout + .fragments + .iter() + .fold(physical::Rect::zero(), |acc, child| { + let child_overflow = child.scrollable_overflow(); + + // https://drafts.csswg.org/css-overflow/#scrolling-direction + // We want to clip scrollable overflow on box-start and inline-start + // sides of the scroll container. + // + // FIXME(mrobinson, bug 25564): This should take into account writing + // mode. + let child_overflow = physical::Rect { + top_left: physical::Vec2::zero(), + size: physical::Vec2 { + x: child_overflow.size.x + child_overflow.top_left.x, + y: child_overflow.size.y + child_overflow.top_left.y, + }, + }; + acc.axis_aligned_bounding_box(&child_overflow) + }); + + FragmentTreeRoot { + children: independent_layout.fragments, + scrollable_overflow, + } } } @@ -151,15 +188,22 @@ impl FragmentTreeRoot { y: Length::new(viewport_size.height), }, }; - for fragment in &self.0 { + for fragment in &self.children { fragment.build_display_list(builder, &containing_block) } } pub fn print(&self) { let mut print_tree = PrintTree::new("Fragment Tree".to_string()); - for fragment in &self.0 { + for fragment in &self.children { fragment.print(&mut print_tree); } } + + pub fn scrollable_overflow(&self) -> webrender_api::units::LayoutSize { + webrender_api::units::LayoutSize::from_untyped(Size2D::new( + self.scrollable_overflow.size.x.px(), + self.scrollable_overflow.size.y.px(), + )) + } } diff --git a/components/layout_2020/fragments.rs b/components/layout_2020/fragments.rs index 1bef85d16a7..887b8c3b04a 100644 --- a/components/layout_2020/fragments.rs +++ b/components/layout_2020/fragments.rs @@ -3,6 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use crate::geom::flow_relative::{Rect, Sides, Vec2}; +use crate::geom::physical; use gfx::text::glyph::GlyphStore; use gfx_traits::print_tree::PrintTree; use servo_arc::Arc as ServoArc; @@ -36,6 +37,9 @@ pub(crate) struct BoxFragment { pub margin: Sides, pub block_margins_collapsed_with_children: CollapsedBlockMargins, + + /// The scrollable overflow of this box fragment. + pub scrollable_overflow: physical::Rect, } pub(crate) struct CollapsedBlockMargins { @@ -55,6 +59,9 @@ pub(crate) struct AnonymousFragment { pub rect: Rect, pub children: Vec, pub mode: WritingMode, + + /// The scrollable overflow of this anonymous fragment's children. + pub scrollable_overflow: physical::Rect, } pub(crate) struct TextFragment { @@ -90,6 +97,21 @@ impl Fragment { Fragment::Image(fragment) => fragment.print(tree), } } + + pub fn scrollable_overflow(&self) -> physical::Rect { + // FIXME(mrobinson, bug 25564): We should be using the containing block + // here to properly convert scrollable overflow to physical geometry. + match self { + Fragment::Box(fragment) => fragment.scrollable_overflow.clone(), + Fragment::Anonymous(fragment) => fragment.scrollable_overflow.clone(), + Fragment::Text(fragment) => fragment + .rect + .to_physical(fragment.parent_style.writing_mode, &physical::Rect::zero()), + Fragment::Image(fragment) => fragment + .rect + .to_physical(fragment.style.writing_mode, &physical::Rect::zero()), + } + } } impl AnonymousFragment { @@ -98,6 +120,21 @@ impl AnonymousFragment { children: vec![], rect: Rect::zero(), mode, + scrollable_overflow: physical::Rect::zero(), + } + } + + pub fn new(rect: Rect, children: Vec, mode: WritingMode) -> Self { + // FIXME(mrobinson, bug 25564): We should be using the containing block + // here to properly convert scrollable overflow to physical geometry. + let scrollable_overflow = children.iter().fold(physical::Rect::zero(), |acc, child| { + acc.axis_aligned_bounding_box(&child.scrollable_overflow()) + }); + AnonymousFragment { + rect, + children, + mode, + scrollable_overflow, } } @@ -116,6 +153,37 @@ impl AnonymousFragment { } impl BoxFragment { + pub fn new( + tag: OpaqueNode, + style: ServoArc, + children: Vec, + content_rect: Rect, + padding: Sides, + border: Sides, + margin: Sides, + block_margins_collapsed_with_children: CollapsedBlockMargins, + ) -> BoxFragment { + // FIXME(mrobinson, bug 25564): We should be using the containing block + // here to properly convert scrollable overflow to physical geometry. + let scrollable_overflow = children.iter().fold( + content_rect + .inflate(&border) + .to_physical(style.writing_mode, &physical::Rect::zero()), + |acc, child| acc.axis_aligned_bounding_box(&child.scrollable_overflow()), + ); + BoxFragment { + tag, + style, + children, + content_rect, + padding, + border, + margin, + block_margins_collapsed_with_children, + scrollable_overflow, + } + } + pub fn padding_rect(&self) -> Rect { self.content_rect.inflate(&self.padding) } diff --git a/components/layout_2020/geom.rs b/components/layout_2020/geom.rs index 166ba7a0494..918cbf47fd2 100644 --- a/components/layout_2020/geom.rs +++ b/components/layout_2020/geom.rs @@ -60,6 +60,15 @@ pub(crate) mod flow_relative { } } +impl physical::Vec2 { + pub fn zero() -> Self { + Self { + x: T::zero(), + y: T::zero(), + } + } +} + impl fmt::Debug for physical::Vec2 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Not using f.debug_struct on purpose here, to keep {:?} output somewhat compact @@ -387,6 +396,33 @@ impl physical::Rect { } } +impl physical::Rect { + pub fn axis_aligned_bounding_box(&self, other: &Self) -> Self { + let top_left = physical::Vec2 { + x: self.top_left.x.min(other.top_left.x), + y: self.top_left.y.min(other.top_left.y), + }; + + let bottom_corner_x = (self.top_left.x + self.size.x).max(other.top_left.x + other.size.x); + let bottom_corner_y = (self.top_left.y + self.size.y).max(other.top_left.y + other.size.y); + let size = physical::Vec2 { + x: bottom_corner_x - top_left.x, + y: bottom_corner_y - top_left.y, + }; + + Self { top_left, size } + } +} + +impl physical::Rect { + pub fn zero() -> Self { + Self { + top_left: physical::Vec2::zero(), + size: physical::Vec2::zero(), + } + } +} + impl From> for Rect { fn from(r: physical::Rect) -> Self { Rect { diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index b10b489bc1d..7b7d67bd122 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -290,11 +290,11 @@ impl<'box_tree> PositioningContext<'box_tree> { ); positioned_box_fragment .children - .push(Fragment::Anonymous(AnonymousFragment { + .push(Fragment::Anonymous(AnonymousFragment::new( + padding_rect, children, - rect: padding_rect, - mode: positioned_box_fragment.style.writing_mode, - })) + positioned_box_fragment.style.writing_mode, + ))) } } } @@ -470,16 +470,16 @@ impl<'box_tree> HoistedAbsolutelyPositionedBox<'box_tree> { size, }; - BoxFragment { - tag: self.absolutely_positioned_box.contents.tag, - style: style.clone(), - children: fragments, + BoxFragment::new( + self.absolutely_positioned_box.contents.tag, + style.clone(), + fragments, content_rect, padding, border, margin, - block_margins_collapsed_with_children: CollapsedBlockMargins::zero(), - } + CollapsedBlockMargins::zero(), + ) }) } } diff --git a/components/layout_thread_2020/lib.rs b/components/layout_thread_2020/lib.rs index 70233892d63..b221774390f 100644 --- a/components/layout_thread_2020/lib.rs +++ b/components/layout_thread_2020/lib.rs @@ -1374,12 +1374,16 @@ impl LayoutThread { document.will_paint(); } + let mut display_list = DisplayListBuilder::new( + self.id.to_webrender(), + context, + fragment_tree.scrollable_overflow(), + ); + let viewport_size = webrender_api::units::LayoutSize::from_untyped(Size2D::new( self.viewport_size.width.to_f32_px(), self.viewport_size.height.to_f32_px(), )); - let mut display_list = - DisplayListBuilder::new(self.id.to_webrender(), context, viewport_size); fragment_tree.build_display_list(&mut display_list, viewport_size); if self.dump_flow_tree { From 27e04008918acb939eeef74e1eb535d564b5f692 Mon Sep 17 00:00:00 2001 From: Martin Robinson Date: Mon, 20 Jan 2020 13:54:23 +0100 Subject: [PATCH 2/4] Fix an issue with `unset_boxes_in_subtree` in layout_2020 If the root node of the subtree doesn't have any boxes to unset, we should exit early instead of unsetting boxes on siblings of the root. This eliminates an infinite loop in this method, since the siblings of the root are not in the subtree. --- components/layout_2020/dom_traversal.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/layout_2020/dom_traversal.rs b/components/layout_2020/dom_traversal.rs index 5ccf8310d53..9d8f54f057e 100644 --- a/components/layout_2020/dom_traversal.rs +++ b/components/layout_2020/dom_traversal.rs @@ -426,8 +426,13 @@ where node = child; continue; } + } else if node == self { + // If this is the root of the subtree and we aren't descending + // into our children return now. + return; } } + let mut next_is_a_sibling_of = node; node = loop { if let Some(sibling) = next_is_a_sibling_of.next_sibling() { From 1cd772fe5f8583bdf22ae9cc264c4a1c37f1a088 Mon Sep 17 00:00:00 2001 From: Martin Robinson Date: Mon, 20 Jan 2020 13:57:54 +0100 Subject: [PATCH 3/4] Answer content box queries for layout_2020 for the root element This isn't correct yet, but it is necessary to give a value in order for scrolling from script to work. Later this should give an accurate content box response as well as work for non-root elements. --- components/layout_2020/flow/root.rs | 41 +++++++++++++++++++++++++++- components/layout_2020/query.rs | 12 ++++++-- components/layout_thread_2020/lib.rs | 13 +++++---- 3 files changed, 58 insertions(+), 8 deletions(-) diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs index 5b801c1fd7a..f6466e99844 100644 --- a/components/layout_2020/flow/root.rs +++ b/components/layout_2020/flow/root.rs @@ -18,7 +18,8 @@ use crate::replaced::ReplacedContent; use crate::sizing::ContentSizesRequest; use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside}; use crate::DefiniteContainingBlock; -use euclid::Size2D; +use app_units::Au; +use euclid::default::{Point2D, Rect, Size2D}; use gfx_traits::print_tree::PrintTree; use script_layout_interface::wrapper_traits::LayoutNode; use servo_arc::Arc; @@ -35,6 +36,9 @@ pub struct FragmentTreeRoot { /// The scrollable overflow of the root of the fragment tree. scrollable_overflow: physical::Rect, + + /// The axis-aligned bounding box of the border box of all child fragments + bounding_box_of_border_boxes: physical::Rect, } impl BoxTreeRoot { @@ -165,9 +169,32 @@ impl BoxTreeRoot { acc.axis_aligned_bounding_box(&child_overflow) }); + let containing_block = physical::Rect::zero(); + let bounding_box_of_border_boxes = + independent_layout + .fragments + .iter() + .fold(physical::Rect::zero(), |acc, child| { + acc.axis_aligned_bounding_box(&match child { + Fragment::Box(fragment) => fragment + .border_rect() + .to_physical(fragment.style.writing_mode, &containing_block), + Fragment::Anonymous(fragment) => { + fragment.rect.to_physical(fragment.mode, &containing_block) + }, + Fragment::Text(fragment) => fragment + .rect + .to_physical(fragment.parent_style.writing_mode, &containing_block), + Fragment::Image(fragment) => fragment + .rect + .to_physical(fragment.style.writing_mode, &containing_block), + }) + }); + FragmentTreeRoot { children: independent_layout.fragments, scrollable_overflow, + bounding_box_of_border_boxes, } } } @@ -206,4 +233,16 @@ impl FragmentTreeRoot { self.scrollable_overflow.size.y.px(), )) } + + pub fn bounding_box_of_border_boxes(&self) -> Rect { + let origin = Point2D::new( + Au::from_f32_px(self.bounding_box_of_border_boxes.top_left.x.px()), + Au::from_f32_px(self.bounding_box_of_border_boxes.top_left.y.px()), + ); + let size = Size2D::new( + Au::from_f32_px(self.bounding_box_of_border_boxes.size.x.px()), + Au::from_f32_px(self.bounding_box_of_border_boxes.size.y.px()), + ); + Rect::new(origin, size) + } } diff --git a/components/layout_2020/query.rs b/components/layout_2020/query.rs index 1317759b33b..0a7225c3b3c 100644 --- a/components/layout_2020/query.rs +++ b/components/layout_2020/query.rs @@ -5,6 +5,7 @@ //! Utilities for querying the layout, as needed by the layout thread. use crate::context::LayoutContext; +use crate::flow::FragmentTreeRoot; use app_units::Au; use euclid::default::{Point2D, Rect}; use euclid::Size2D; @@ -163,8 +164,15 @@ impl LayoutRPC for LayoutRPCImpl { } } -pub fn process_content_box_request(_requested_node: OpaqueNode) -> Option> { - None +pub fn process_content_box_request( + _requested_node: OpaqueNode, + fragment_tree_root: Option<&FragmentTreeRoot>, +) -> Option> { + let fragment_tree_root = match fragment_tree_root { + Some(fragment_tree_root) => fragment_tree_root, + None => return None, + }; + Some(fragment_tree_root.bounding_box_of_border_boxes()) } pub fn process_content_boxes_request(_requested_node: OpaqueNode) -> Vec> { diff --git a/components/layout_thread_2020/lib.rs b/components/layout_thread_2020/lib.rs index b221774390f..295cdabda4e 100644 --- a/components/layout_thread_2020/lib.rs +++ b/components/layout_thread_2020/lib.rs @@ -46,7 +46,7 @@ use layout::query::{ process_text_index_request, }; use layout::traversal::RecalcStyle; -use layout::BoxTreeRoot; +use layout::{BoxTreeRoot, FragmentTreeRoot}; use layout_traits::LayoutThreadFactory; use libc::c_void; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; @@ -172,10 +172,10 @@ pub struct LayoutThread { outstanding_web_fonts: Arc, /// The root of the box tree. - box_tree_root: RefCell>, + box_tree_root: RefCell>, /// The root of the fragment tree. - fragment_tree_root: RefCell>, + fragment_tree_root: RefCell>, /// The document-specific shared lock used for author-origin stylesheets document_shared_lock: Option, @@ -1218,7 +1218,10 @@ impl LayoutThread { match *reflow_goal { ReflowGoal::LayoutQuery(ref querymsg, _) => match querymsg { &QueryMsg::ContentBoxQuery(node) => { - rw_data.content_box_response = process_content_box_request(node); + rw_data.content_box_response = process_content_box_request( + node, + (&*self.fragment_tree_root.borrow()).as_ref(), + ); }, &QueryMsg::ContentBoxesQuery(node) => { rw_data.content_boxes_response = process_content_boxes_request(node); @@ -1355,7 +1358,7 @@ impl LayoutThread { fn perform_post_style_recalc_layout_passes( &self, - fragment_tree: &layout::FragmentTreeRoot, + fragment_tree: &FragmentTreeRoot, reflow_goal: &ReflowGoal, document: Option<&ServoLayoutDocument>, context: &mut LayoutContext, From e4a55d77555ec60ce37f8272cfe6ec7292b6af5f Mon Sep 17 00:00:00 2001 From: Martin Robinson Date: Mon, 20 Jan 2020 14:49:10 +0100 Subject: [PATCH 4/4] Add a workaround to root_scroll.html for #25559 This allows us to test initial root scrolling support in Layout 2020 and can hopefully be removed very soon. --- tests/wpt/mozilla/meta/MANIFEST.json | 4 ++-- tests/wpt/mozilla/tests/mozilla/scroll_root.html | 3 +++ tests/wpt/mozilla/tests/mozilla/scroll_root_ref.html | 7 +++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index 380ca0c7023..a683eeb8628 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -19368,11 +19368,11 @@ "testharness" ], "mozilla/scroll_root.html": [ - "b1a9cb590b0fcce9c883f99e17fa029a999b699b", + "5896eb3957da1eb85a26680053823d3f3bf9af49", "reftest" ], "mozilla/scroll_root_ref.html": [ - "6503ad5d5265c0698f61fc607e2e4e017b31cb6f", + "c7d4cfec7b9d9b5daf32841172721ddac3e4d071", "support" ], "mozilla/scroll_top_null_target.html": [ diff --git a/tests/wpt/mozilla/tests/mozilla/scroll_root.html b/tests/wpt/mozilla/tests/mozilla/scroll_root.html index b1a9cb590b0..5896eb3957d 100644 --- a/tests/wpt/mozilla/tests/mozilla/scroll_root.html +++ b/tests/wpt/mozilla/tests/mozilla/scroll_root.html @@ -7,6 +7,9 @@ diff --git a/tests/wpt/mozilla/tests/mozilla/scroll_root_ref.html b/tests/wpt/mozilla/tests/mozilla/scroll_root_ref.html index 6503ad5d526..c7d4cfec7b9 100644 --- a/tests/wpt/mozilla/tests/mozilla/scroll_root_ref.html +++ b/tests/wpt/mozilla/tests/mozilla/scroll_root_ref.html @@ -5,7 +5,14 @@ + + +
+