diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs index dd647070d7a..c8996f1c1b4 100644 --- a/components/layout_2020/flow/root.rs +++ b/components/layout_2020/flow/root.rs @@ -10,7 +10,7 @@ use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox}; use crate::formatting_contexts::IndependentFormattingContext; use crate::fragments::Fragment; use crate::geom::flow_relative::Vec2; -use crate::geom::PhysicalRect; +use crate::geom::{PhysicalPoint, PhysicalRect, PhysicalSize}; use crate::positioned::AbsolutelyPositionedBox; use crate::positioned::PositioningContext; use crate::replaced::ReplacedContent; @@ -22,7 +22,8 @@ use euclid::default::{Point2D, Rect, Size2D}; use gfx_traits::print_tree::PrintTree; use script_layout_interface::wrapper_traits::LayoutNode; use servo_arc::Arc; -use style::properties::ComputedValues; +use style::dom::OpaqueNode; +use style::properties::{style_structs, ComputedValues}; use style::values::computed::Length; use style_traits::CSSPixel; @@ -35,8 +36,8 @@ pub struct FragmentTreeRoot { /// The scrollable overflow of the root of the fragment tree. scrollable_overflow: PhysicalRect, - /// The axis-aligned bounding box of the border box of all child fragments - bounding_box_of_border_boxes: PhysicalRect, + /// The containing block used in the layout of this fragment tree. + initial_containing_block: PhysicalRect, } impl BoxTreeRoot { @@ -117,13 +118,18 @@ impl BoxTreeRoot { viewport: euclid::Size2D, ) -> FragmentTreeRoot { let style = ComputedValues::initial_values(); + + // FIXME: use the document’s mode: + // https://drafts.csswg.org/css-writing-modes/#principal-flow + let physical_containing_block = PhysicalRect::new( + PhysicalPoint::zero(), + PhysicalSize::new(Length::new(viewport.width), Length::new(viewport.height)), + ); let initial_containing_block = DefiniteContainingBlock { size: Vec2 { - inline: Length::new(viewport.width), - block: Length::new(viewport.height), + inline: physical_containing_block.size.width, + block: physical_containing_block.size.height, }, - // FIXME: use the document’s mode: - // https://drafts.csswg.org/css-writing-modes/#principal-flow style, }; @@ -142,8 +148,6 @@ impl BoxTreeRoot { &mut 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 @@ -167,51 +171,18 @@ impl BoxTreeRoot { acc.union(&child_overflow) }); - let containing_block = PhysicalRect::zero(); - let bounding_box_of_border_boxes = - independent_layout - .fragments - .iter() - .fold(PhysicalRect::zero(), |acc, child| { - acc.union(&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, + initial_containing_block: physical_containing_block, } } } impl FragmentTreeRoot { - pub fn build_display_list( - &self, - builder: &mut crate::display_list::DisplayListBuilder, - viewport_size: webrender_api::units::LayoutSize, - ) { - let containing_block = PhysicalRect::new( - euclid::Point2D::zero(), - euclid::Size2D::new( - Length::new(viewport_size.width), - Length::new(viewport_size.height), - ), - ); + pub fn build_display_list(&self, builder: &mut crate::display_list::DisplayListBuilder) { for fragment in &self.children { - fragment.build_display_list(builder, &containing_block) + fragment.build_display_list(builder, &self.initial_containing_block) } } @@ -229,15 +200,132 @@ impl FragmentTreeRoot { )) } - pub fn bounding_box_of_border_boxes(&self) -> Rect { - let origin = Point2D::new( - Au::from_f32_px(self.bounding_box_of_border_boxes.origin.x.px()), - Au::from_f32_px(self.bounding_box_of_border_boxes.origin.y.px()), - ); - let size = Size2D::new( - Au::from_f32_px(self.bounding_box_of_border_boxes.size.width.px()), - Au::from_f32_px(self.bounding_box_of_border_boxes.size.height.px()), - ); - Rect::new(origin, size) + fn iterate_through_fragments(&self, process_func: &mut F) + where + F: FnMut(&Fragment, &PhysicalRect) -> bool, + { + fn do_iteration( + fragment: &Fragment, + containing_block: &PhysicalRect, + process_func: &mut M, + ) -> bool + where + M: FnMut(&Fragment, &PhysicalRect) -> bool, + { + if !process_func(fragment, containing_block) { + return false; + } + + match fragment { + Fragment::Box(fragment) => { + let new_containing_block = fragment + .content_rect + .to_physical(fragment.style.writing_mode, containing_block) + .translate(containing_block.origin.to_vector()); + for child in &fragment.children { + do_iteration(child, &new_containing_block, process_func); + } + }, + Fragment::Anonymous(fragment) => { + let new_containing_block = fragment + .rect + .to_physical(fragment.mode, containing_block) + .translate(containing_block.origin.to_vector()); + for child in &fragment.children { + do_iteration(child, &new_containing_block, process_func); + } + }, + _ => {}, + } + + true + } + + for child in &self.children { + if !do_iteration(child, &self.initial_containing_block, process_func) { + break; + } + } + } + + pub fn get_content_box_for_node(&self, requested_node: OpaqueNode) -> Rect { + let mut rect = PhysicalRect::zero(); + let mut process = |fragment: &Fragment, containing_block: &PhysicalRect| { + let fragment_relative_rect = match fragment { + Fragment::Box(fragment) if fragment.tag == requested_node => fragment + .border_rect() + .to_physical(fragment.style.writing_mode, &containing_block), + Fragment::Text(fragment) if fragment.tag == requested_node => fragment + .rect + .to_physical(fragment.parent_style.writing_mode, &containing_block), + Fragment::Box(_) | + Fragment::Text(_) | + Fragment::Image(_) | + Fragment::Anonymous(_) => return true, + }; + + rect = fragment_relative_rect + .translate(containing_block.origin.to_vector()) + .union(&rect); + return true; + }; + + self.iterate_through_fragments(&mut process); + + Rect::new( + Point2D::new( + Au::from_f32_px(rect.origin.x.px()), + Au::from_f32_px(rect.origin.y.px()), + ), + Size2D::new( + Au::from_f32_px(rect.size.width.px()), + Au::from_f32_px(rect.size.height.px()), + ), + ) + } + + pub fn get_border_dimensions_for_node(&self, requested_node: OpaqueNode) -> Rect { + let mut border_dimensions = Rect::zero(); + let mut process = |fragment: &Fragment, containing_block: &PhysicalRect| { + let (style, padding_rect) = match fragment { + Fragment::Box(fragment) if fragment.tag == requested_node => { + (&fragment.style, fragment.padding_rect()) + }, + Fragment::Box(_) | + Fragment::Text(_) | + Fragment::Image(_) | + Fragment::Anonymous(_) => return true, + }; + + // https://drafts.csswg.org/cssom-view/#dom-element-clienttop + // " If the element has no associated CSS layout box or if the + // CSS layout box is inline, return zero." For this check we + // also explicitly ignore the list item portion of the display + // style. + let display = &style.get_box().display; + if display.inside() == style::values::specified::box_::DisplayInside::Flow && + display.outside() == style::values::specified::box_::DisplayOutside::Inline + { + return false; + } + + let style_structs::Border { + border_top_width: top_width, + border_left_width: left_width, + .. + } = *style.get_border(); + + let padding_rect = padding_rect.to_physical(style.writing_mode, &containing_block); + border_dimensions.size.width = padding_rect.size.width.px() as i32; + border_dimensions.size.height = padding_rect.size.height.px() as i32; + border_dimensions.origin.y = top_width.px() as i32; + border_dimensions.origin.x = left_width.px() as i32; + + false + }; + + self.iterate_through_fragments(&mut process); + + border_dimensions } } diff --git a/components/layout_2020/query.rs b/components/layout_2020/query.rs index 0a7225c3b3c..d281bb57a91 100644 --- a/components/layout_2020/query.rs +++ b/components/layout_2020/query.rs @@ -165,22 +165,31 @@ impl LayoutRPC for LayoutRPCImpl { } pub fn process_content_box_request( - _requested_node: OpaqueNode, + 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()) + + Some(fragment_tree_root.get_content_box_for_node(requested_node)) } pub fn process_content_boxes_request(_requested_node: OpaqueNode) -> Vec> { vec![] } -pub fn process_node_geometry_request(_requested_node: OpaqueNode) -> Rect { - Rect::zero() +pub fn process_node_geometry_request( + requested_node: OpaqueNode, + fragment_tree_root: Option<&FragmentTreeRoot>, +) -> Rect { + let fragment_tree_root = match fragment_tree_root { + Some(fragment_tree_root) => fragment_tree_root, + None => return Rect::zero(), + }; + + fragment_tree_root.get_border_dimensions_for_node(requested_node) } pub fn process_node_scroll_id_request( diff --git a/components/layout_thread_2020/lib.rs b/components/layout_thread_2020/lib.rs index 0cc910d9c71..97d19762528 100644 --- a/components/layout_thread_2020/lib.rs +++ b/components/layout_thread_2020/lib.rs @@ -1234,7 +1234,10 @@ impl LayoutThread { rw_data.text_index_response = process_text_index_request(node, point_in_node); }, &QueryMsg::ClientRectQuery(node) => { - rw_data.client_rect_response = process_node_geometry_request(node); + rw_data.client_rect_response = process_node_geometry_request( + node, + (&*self.fragment_tree_root.borrow()).as_ref(), + ); }, &QueryMsg::NodeScrollGeometryQuery(node) => { rw_data.scroll_area_response = process_node_scroll_area_request(node); @@ -1383,11 +1386,7 @@ impl LayoutThread { 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(), - )); - fragment_tree.build_display_list(&mut display_list, viewport_size); + fragment_tree.build_display_list(&mut display_list); if self.dump_flow_tree { fragment_tree.print(); @@ -1408,6 +1407,10 @@ impl LayoutThread { self.paint_time_metrics .maybe_observe_paint_time(self, epoch, display_list.is_contentful); + 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(), + )); self.webrender_api.send_display_list( self.webrender_document, epoch, diff --git a/tests/wpt/metadata-layout-2020/css/cssom-view/cssom-getBoundingClientRect-002.html.ini b/tests/wpt/metadata-layout-2020/css/cssom-view/cssom-getBoundingClientRect-002.html.ini deleted file mode 100644 index b91f2ed318f..00000000000 --- a/tests/wpt/metadata-layout-2020/css/cssom-view/cssom-getBoundingClientRect-002.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[cssom-getBoundingClientRect-002.html] - [getBoundingClientRect on a newly-created Element not yet inserted into the DOM should return an all-zeroes DOMRect] - expected: FAIL - diff --git a/tests/wpt/metadata-layout-2020/css/cssom-view/cssom-getBoundingClientRect-vertical-rl.html.ini b/tests/wpt/metadata-layout-2020/css/cssom-view/cssom-getBoundingClientRect-vertical-rl.html.ini deleted file mode 100644 index 87cc807c420..00000000000 --- a/tests/wpt/metadata-layout-2020/css/cssom-view/cssom-getBoundingClientRect-vertical-rl.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[cssom-getBoundingClientRect-vertical-rl.html] - expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/cssom-view/elementFromPoint-001.html.ini b/tests/wpt/metadata-layout-2020/css/cssom-view/elementFromPoint-001.html.ini deleted file mode 100644 index e38782d8c85..00000000000 --- a/tests/wpt/metadata-layout-2020/css/cssom-view/elementFromPoint-001.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[elementFromPoint-001.html] - [CSSOM View - 5 - extensions to the Document interface] - expected: FAIL - diff --git a/tests/wpt/metadata-layout-2020/css/cssom-view/elementFromPoint.html.ini b/tests/wpt/metadata-layout-2020/css/cssom-view/elementFromPoint.html.ini index b131edcd3b4..ea278b420d8 100644 --- a/tests/wpt/metadata-layout-2020/css/cssom-view/elementFromPoint.html.ini +++ b/tests/wpt/metadata-layout-2020/css/cssom-view/elementFromPoint.html.ini @@ -1,7 +1,4 @@ [elementFromPoint.html] - [Fieldsets] - expected: FAIL - [SVG element at x,y] expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/cssom-view/elementsFromPoint-invalid-cases.html.ini b/tests/wpt/metadata-layout-2020/css/cssom-view/elementsFromPoint-invalid-cases.html.ini deleted file mode 100644 index 23f053f4f4a..00000000000 --- a/tests/wpt/metadata-layout-2020/css/cssom-view/elementsFromPoint-invalid-cases.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[elementsFromPoint-invalid-cases.html] - [The root element is the last element returned for valid queries] - expected: FAIL - diff --git a/tests/wpt/metadata-layout-2020/css/cssom-view/negativeMargins.html.ini b/tests/wpt/metadata-layout-2020/css/cssom-view/negativeMargins.html.ini index febf21daa0e..37835a4fced 100644 --- a/tests/wpt/metadata-layout-2020/css/cssom-view/negativeMargins.html.ini +++ b/tests/wpt/metadata-layout-2020/css/cssom-view/negativeMargins.html.ini @@ -1,7 +1,4 @@ [negativeMargins.html] - [cssom-view - elementFromPoint and elementsFromPoint dealing with negative margins] - expected: FAIL - [cssom-view - elementFromPoint and elementsFromPoint dealing with negative margins 1] expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/cssom-view/scroll-behavior-smooth.html.ini b/tests/wpt/metadata-layout-2020/css/cssom-view/scroll-behavior-smooth.html.ini index 48839ce2b8c..e1a609649d6 100644 --- a/tests/wpt/metadata-layout-2020/css/cssom-view/scroll-behavior-smooth.html.ini +++ b/tests/wpt/metadata-layout-2020/css/cssom-view/scroll-behavior-smooth.html.ini @@ -1,11 +1,5 @@ [scroll-behavior-smooth.html] expected: ERROR - [Smooth scrolling while doing history navigation.] - expected: FAIL - - [Instant scrolling while doing history navigation.] - expected: FAIL - [scroll-behavior: smooth on DIV element] expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/cssom-view/scrollLeftTop.html.ini b/tests/wpt/metadata-layout-2020/css/cssom-view/scrollLeftTop.html.ini new file mode 100644 index 00000000000..384599d83f8 --- /dev/null +++ b/tests/wpt/metadata-layout-2020/css/cssom-view/scrollLeftTop.html.ini @@ -0,0 +1,19 @@ +[scrollLeftTop.html] + [writing-mode:vertical-lr; direction:ltr] + expected: FAIL + + [writing-mode:vertical-rl; direction:rtl] + expected: FAIL + + [writing-mode:vertical-lr; direction:rtl] + expected: FAIL + + [writing-mode:vertical-rl; direction:ltr] + expected: FAIL + + [writing-mode:horizontal-tb; direction:ltr] + expected: FAIL + + [writing-mode:horizontal-tb; direction:rtl] + expected: FAIL + diff --git a/tests/wpt/metadata-layout-2020/css/cssom-view/scrollWidthHeight.xht.ini b/tests/wpt/metadata-layout-2020/css/cssom-view/scrollWidthHeight.xht.ini index ca8c98c0610..e906d552b32 100644 --- a/tests/wpt/metadata-layout-2020/css/cssom-view/scrollWidthHeight.xht.ini +++ b/tests/wpt/metadata-layout-2020/css/cssom-view/scrollWidthHeight.xht.ini @@ -1,28 +1,10 @@ [scrollWidthHeight.xht] - [elemSimple.clientWidth is the width of the padding edge] - expected: FAIL - [elemSimple.scrollWidth is its clientWidth] expected: FAIL [elemNestedOverflow.scrollWidth is the width of its scrolled contents (ignoring padding, since we overflowed)] expected: FAIL - [elemNestedOverflow.clientWidth is the height of the padding edge] - expected: FAIL - - [elemOverflow.clientWidth is the width of the padding edge] - expected: FAIL - - [elemSimple.clientHeight is the height of the padding edge] - expected: FAIL - - [elemOverflow.clientHeight is the height of the padding edge] - expected: FAIL - - [elemNestedOverflow.clientHeight is the height of the padding edge] - expected: FAIL - [elemSimple.scrollHeight is its clientHeight] expected: FAIL diff --git a/tests/wpt/metadata-layout-2020/css/cssom-view/scrollWidthHeightWhenNotScrollable.xht.ini b/tests/wpt/metadata-layout-2020/css/cssom-view/scrollWidthHeightWhenNotScrollable.xht.ini index 676434c78c0..c18dde2c9a6 100644 --- a/tests/wpt/metadata-layout-2020/css/cssom-view/scrollWidthHeightWhenNotScrollable.xht.ini +++ b/tests/wpt/metadata-layout-2020/css/cssom-view/scrollWidthHeightWhenNotScrollable.xht.ini @@ -1,20 +1,19 @@ [scrollWidthHeightWhenNotScrollable.xht] - expected: ERROR - [elemSimple.clientWidth is the width of the padding edge] - expected: FAIL - [elemSimple.scrollWidth is its clientWidth] expected: FAIL - [elemSimple.clientHeight is the height of the padding edge] - expected: FAIL - - [elemOverflow.clientHeight is the height of the padding edge] - expected: FAIL - [elemSimple.scrollHeight is its clientHeight] expected: FAIL [elemOverflow.scrollHeight is the height of its scrolled contents (ignoring padding, since we overflowed)] expected: FAIL + [elemNestedOverflow.scrollWidth is the width of its scrolled contents (ignoring padding, since we overflowed)] + expected: FAIL + + [elemNestedOverflow.scrollHeight is the height of its scrolled contents (ignoring padding, since we overflowed)] + expected: FAIL + + [elemOverflow.scrollHeight is the width of its scrolled contents (ignoring padding, since we overflowed)] + expected: FAIL + diff --git a/tests/wpt/metadata-layout-2020/css/cssom-view/scrolling-quirks-vs-nonquirks.html.ini b/tests/wpt/metadata-layout-2020/css/cssom-view/scrolling-quirks-vs-nonquirks.html.ini index c366ff10d49..1965a409bbe 100644 --- a/tests/wpt/metadata-layout-2020/css/cssom-view/scrolling-quirks-vs-nonquirks.html.ini +++ b/tests/wpt/metadata-layout-2020/css/cssom-view/scrolling-quirks-vs-nonquirks.html.ini @@ -29,15 +29,9 @@ [scrollWidth/scrollHeight on the root element in non-quirks mode] expected: FAIL - [clientWidth/clientHeight of the content in non-quirks mode] - expected: FAIL - [scroll() on the HTML body element in quirks mode] expected: FAIL - [clientWidth/clientHeight of the content in quirks mode] - expected: FAIL - [scrollingElement in quirks mode] expected: FAIL diff --git a/tests/wpt/mozilla/meta-layout-2020/css/flex-item-assign-inline-size.html.ini b/tests/wpt/mozilla/meta-layout-2020/css/flex-item-assign-inline-size.html.ini deleted file mode 100644 index b665ed510ac..00000000000 --- a/tests/wpt/mozilla/meta-layout-2020/css/flex-item-assign-inline-size.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[flex-item-assign-inline-size.html] - [Test inline size against percentage] - expected: FAIL - diff --git a/tests/wpt/mozilla/meta-layout-2020/css/word-break-keep-all-008.htm.ini b/tests/wpt/mozilla/meta-layout-2020/css/word-break-keep-all-008.htm.ini new file mode 100644 index 00000000000..5fc598e287f --- /dev/null +++ b/tests/wpt/mozilla/meta-layout-2020/css/word-break-keep-all-008.htm.ini @@ -0,0 +1,2 @@ +[word-break-keep-all-008.htm] + expected: FAIL diff --git a/tests/wpt/mozilla/meta-layout-2020/mozilla/client-top-left-height-width.html.ini b/tests/wpt/mozilla/meta-layout-2020/mozilla/client-top-left-height-width.html.ini deleted file mode 100644 index 5e6a532d15e..00000000000 --- a/tests/wpt/mozilla/meta-layout-2020/mozilla/client-top-left-height-width.html.ini +++ /dev/null @@ -1,19 +0,0 @@ -[client-top-left-height-width.html] - [Block without border and padding] - expected: FAIL - - [Rotated block] - expected: FAIL - - [Absolutely positioned block] - expected: FAIL - - [Block without border] - expected: FAIL - - [Block with border] - expected: FAIL - - [Inline block] - expected: FAIL - diff --git a/tests/wpt/mozilla/meta-layout-2020/mozilla/empty_clientrect.html.ini b/tests/wpt/mozilla/meta-layout-2020/mozilla/empty_clientrect.html.ini deleted file mode 100644 index 8f7281833fb..00000000000 --- a/tests/wpt/mozilla/meta-layout-2020/mozilla/empty_clientrect.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[empty_clientrect.html] - [empty_clientrect] - expected: FAIL - diff --git a/tests/wpt/mozilla/meta-layout-2020/mozilla/getBoundingClientRect.html.ini b/tests/wpt/mozilla/meta-layout-2020/mozilla/getBoundingClientRect.html.ini deleted file mode 100644 index 543f61cd5ae..00000000000 --- a/tests/wpt/mozilla/meta-layout-2020/mozilla/getBoundingClientRect.html.ini +++ /dev/null @@ -1,7 +0,0 @@ -[getBoundingClientRect.html] - [getBoundingClientRect 1] - expected: FAIL - - [getBoundingClientRect] - expected: FAIL - diff --git a/tests/wpt/mozilla/meta-layout-2020/mozilla/img_width_height.html.ini b/tests/wpt/mozilla/meta-layout-2020/mozilla/img_width_height.html.ini deleted file mode 100644 index 395f6667235..00000000000 --- a/tests/wpt/mozilla/meta-layout-2020/mozilla/img_width_height.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[img_width_height.html] - [img_width_height] - expected: FAIL - diff --git a/tests/wpt/mozilla/meta-layout-2020/mozilla/mime_sniffing_font_context.html.ini b/tests/wpt/mozilla/meta-layout-2020/mozilla/mime_sniffing_font_context.html.ini deleted file mode 100644 index 3921d030cd0..00000000000 --- a/tests/wpt/mozilla/meta-layout-2020/mozilla/mime_sniffing_font_context.html.ini +++ /dev/null @@ -1,11 +0,0 @@ -[mime_sniffing_font_context.html] - expected: TIMEOUT - [Sniffed font with xml is not loaded] - expected: TIMEOUT - - [Sniffed font with xhtml+xml is not loaded] - expected: TIMEOUT - - [Sniffed font is loaded and applied] - expected: TIMEOUT -