diff options
Diffstat (limited to 'components/layout/fragment_tree')
-rw-r--r-- | components/layout/fragment_tree/box_fragment.rs | 44 | ||||
-rw-r--r-- | components/layout/fragment_tree/fragment.rs | 23 | ||||
-rw-r--r-- | components/layout/fragment_tree/fragment_tree.rs | 43 | ||||
-rw-r--r-- | components/layout/fragment_tree/positioning_fragment.rs | 31 |
4 files changed, 100 insertions, 41 deletions
diff --git a/components/layout/fragment_tree/box_fragment.rs b/components/layout/fragment_tree/box_fragment.rs index b7c3a2a3524..eb63038b7d7 100644 --- a/components/layout/fragment_tree/box_fragment.rs +++ b/components/layout/fragment_tree/box_fragment.rs @@ -89,7 +89,7 @@ pub(crate) struct BoxFragment { block_margins_collapsed_with_children: Option<Box<CollapsedBlockMargins>>, /// The scrollable overflow of this box fragment. - pub scrollable_overflow_from_children: PhysicalRect<Au>, + scrollable_overflow: Option<PhysicalRect<Au>>, /// The resolved box insets if this box is `position: sticky`. These are calculated /// during `StackingContextTree` construction because they rely on the size of the @@ -114,11 +114,6 @@ impl BoxFragment { margin: PhysicalSides<Au>, clearance: Option<Au>, ) -> BoxFragment { - let scrollable_overflow_from_children = - children.iter().fold(PhysicalRect::zero(), |acc, child| { - acc.union(&child.scrollable_overflow_for_parent()) - }); - BoxFragment { base: base_fragment_info.into(), style, @@ -131,7 +126,7 @@ impl BoxFragment { clearance, baselines: Baselines::default(), block_margins_collapsed_with_children: None, - scrollable_overflow_from_children, + scrollable_overflow: None, resolved_sticky_insets: AtomicRefCell::default(), background_mode: BackgroundMode::Normal, specific_layout_info: None, @@ -203,13 +198,23 @@ impl BoxFragment { /// Get the scrollable overflow for this [`BoxFragment`] relative to its /// containing block. pub fn scrollable_overflow(&self) -> PhysicalRect<Au> { + self.scrollable_overflow + .expect("Should only call `scrollable_overflow()` after calculating overflow") + } + + pub(crate) fn calculate_scrollable_overflow(&mut self) { + let scrollable_overflow_from_children = self + .children + .iter() + .fold(PhysicalRect::zero(), |acc, child| { + acc.union(&child.calculate_scrollable_overflow_for_parent()) + }); let physical_padding_rect = self.padding_rect(); let content_origin = self.content_rect.origin.to_vector(); - physical_padding_rect.union( - &self - .scrollable_overflow_from_children - .translate(content_origin), - ) + self.scrollable_overflow = Some( + physical_padding_rect + .union(&scrollable_overflow_from_children.translate(content_origin)), + ); } pub(crate) fn set_containing_block(&mut self, containing_block: &PhysicalRect<Au>) { @@ -275,7 +280,12 @@ impl BoxFragment { tree.end_level(); } - pub fn scrollable_overflow_for_parent(&self) -> PhysicalRect<Au> { + pub(crate) fn scrollable_overflow_for_parent(&self) -> PhysicalRect<Au> { + // TODO: Properly handle absolutely positioned fragments. + if self.style.get_box().position.is_absolutely_positioned() { + return PhysicalRect::zero(); + } + let mut overflow = self.border_rect(); if !self.style.establishes_scroll_container(self.base.flags) { // https://www.w3.org/TR/css-overflow-3/#scrollable @@ -328,7 +338,7 @@ impl BoxFragment { /// /// Return the clipped the scrollable overflow based on its scroll origin, determined by overflow direction. /// For an element, the clip rect is the padding rect and for viewport, it is the initial containing block. - pub fn clip_unreachable_scrollable_overflow_region( + pub(crate) fn clip_unreachable_scrollable_overflow_region( &self, scrollable_overflow: PhysicalRect<Au>, clipping_rect: PhysicalRect<Au>, @@ -362,7 +372,7 @@ impl BoxFragment { /// /// Return the clipped the scrollable overflow based on its scroll origin, determined by overflow direction. /// This will coincides with the scrollport if the fragment is a scroll container. - pub fn reachable_scrollable_overflow_region(&self) -> PhysicalRect<Au> { + pub(crate) fn reachable_scrollable_overflow_region(&self) -> PhysicalRect<Au> { self.clip_unreachable_scrollable_overflow_region( self.scrollable_overflow(), self.padding_rect(), @@ -421,9 +431,7 @@ impl BoxFragment { return convert_to_au_or_auto(PhysicalSides::new(top, right, bottom, left)); } - debug_assert!( - position == ComputedPosition::Fixed || position == ComputedPosition::Absolute - ); + debug_assert!(position.is_absolutely_positioned()); let margin_rect = self.margin_rect(); let (top, bottom) = match (&insets.top, &insets.bottom) { diff --git a/components/layout/fragment_tree/fragment.rs b/components/layout/fragment_tree/fragment.rs index c81fd59e36b..10338c78743 100644 --- a/components/layout/fragment_tree/fragment.rs +++ b/components/layout/fragment_tree/fragment.rs @@ -183,19 +183,36 @@ impl Fragment { } } - pub fn scrollable_overflow_for_parent(&self) -> PhysicalRect<Au> { + pub(crate) fn scrollable_overflow_for_parent(&self) -> PhysicalRect<Au> { match self { Fragment::Box(fragment) | Fragment::Float(fragment) => { - fragment.borrow().scrollable_overflow_for_parent() + return fragment.borrow().scrollable_overflow_for_parent(); }, Fragment::AbsoluteOrFixedPositioned(_) => PhysicalRect::zero(), - Fragment::Positioning(fragment) => fragment.borrow().scrollable_overflow, + Fragment::Positioning(fragment) => fragment.borrow().scrollable_overflow_for_parent(), Fragment::Text(fragment) => fragment.borrow().rect, Fragment::Image(fragment) => fragment.borrow().rect, Fragment::IFrame(fragment) => fragment.borrow().rect, } } + pub(crate) fn calculate_scrollable_overflow_for_parent(&self) -> PhysicalRect<Au> { + self.calculate_scrollable_overflow(); + self.scrollable_overflow_for_parent() + } + + pub(crate) fn calculate_scrollable_overflow(&self) { + match self { + Fragment::Box(fragment) | Fragment::Float(fragment) => { + fragment.borrow_mut().calculate_scrollable_overflow() + }, + Fragment::Positioning(fragment) => { + fragment.borrow_mut().calculate_scrollable_overflow() + }, + _ => {}, + } + } + pub(crate) fn cumulative_border_box_rect(&self) -> Option<PhysicalRect<Au>> { match self { Fragment::Box(fragment) | Fragment::Float(fragment) => { diff --git a/components/layout/fragment_tree/fragment_tree.rs b/components/layout/fragment_tree/fragment_tree.rs index ba03a72ac21..b59ace43aa6 100644 --- a/components/layout/fragment_tree/fragment_tree.rs +++ b/components/layout/fragment_tree/fragment_tree.rs @@ -2,14 +2,14 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +use std::cell::Cell; + use app_units::Au; use base::print_tree::PrintTree; use compositing_traits::display_list::AxesScrollSensitivity; -use euclid::default::Size2D; use fxhash::FxHashSet; use malloc_size_of_derive::MallocSizeOf; use style::animation::AnimationSetKey; -use webrender_api::units; use super::{BoxFragment, ContainingBlockManager, Fragment}; use crate::ArcRefCell; @@ -30,7 +30,7 @@ pub struct FragmentTree { /// The scrollable overflow rectangle for the entire tree /// <https://drafts.csswg.org/css-overflow/#scrollable> - pub(crate) scrollable_overflow: PhysicalRect<Au>, + scrollable_overflow: Cell<Option<PhysicalRect<Au>>>, /// The containing block used in the layout of this fragment tree. pub(crate) initial_containing_block: PhysicalRect<Au>, @@ -43,13 +43,12 @@ impl FragmentTree { pub(crate) fn new( layout_context: &LayoutContext, root_fragments: Vec<Fragment>, - scrollable_overflow: PhysicalRect<Au>, initial_containing_block: PhysicalRect<Au>, viewport_scroll_sensitivity: AxesScrollSensitivity, ) -> Self { let fragment_tree = Self { root_fragments, - scrollable_overflow, + scrollable_overflow: Cell::default(), initial_containing_block, viewport_scroll_sensitivity, }; @@ -97,11 +96,35 @@ impl FragmentTree { } } - pub fn scrollable_overflow(&self) -> units::LayoutSize { - units::LayoutSize::from_untyped(Size2D::new( - self.scrollable_overflow.size.width.to_f32_px(), - self.scrollable_overflow.size.height.to_f32_px(), - )) + pub(crate) fn scrollable_overflow(&self) -> PhysicalRect<Au> { + self.scrollable_overflow + .get() + .expect("Should only call `scrollable_overflow()` after calculating overflow") + } + + pub(crate) fn calculate_scrollable_overflow(&self) { + self.scrollable_overflow + .set(Some(self.root_fragments.iter().fold( + PhysicalRect::zero(), + |acc, child| { + let child_overflow = child.calculate_scrollable_overflow_for_parent(); + + // 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 = PhysicalRect::new( + euclid::Point2D::zero(), + euclid::Size2D::new( + child_overflow.size.width + child_overflow.origin.x, + child_overflow.size.height + child_overflow.origin.y, + ), + ); + acc.union(&child_overflow) + }, + ))); } pub(crate) fn find<T>( diff --git a/components/layout/fragment_tree/positioning_fragment.rs b/components/layout/fragment_tree/positioning_fragment.rs index e45a6137bff..5547a9d86a1 100644 --- a/components/layout/fragment_tree/positioning_fragment.rs +++ b/components/layout/fragment_tree/positioning_fragment.rs @@ -22,7 +22,7 @@ pub(crate) struct PositioningFragment { pub children: Vec<Fragment>, /// The scrollable overflow of this anonymous fragment's children. - pub scrollable_overflow: PhysicalRect<Au>, + scrollable_overflow: Option<PhysicalRect<Au>>, /// The style of the fragment. pub style: ServoArc<ComputedValues>, @@ -55,20 +55,12 @@ impl PositioningFragment { rect: PhysicalRect<Au>, children: Vec<Fragment>, ) -> ArcRefCell<Self> { - let content_origin = rect.origin; - let scrollable_overflow = children.iter().fold(PhysicalRect::zero(), |acc, child| { - acc.union( - &child - .scrollable_overflow_for_parent() - .translate(content_origin.to_vector()), - ) - }); ArcRefCell::new(PositioningFragment { base, style, rect, children, - scrollable_overflow, + scrollable_overflow: None, cumulative_containing_block_rect: PhysicalRect::zero(), }) } @@ -81,6 +73,25 @@ impl PositioningFragment { rect.translate(self.cumulative_containing_block_rect.origin.to_vector()) } + pub(crate) fn calculate_scrollable_overflow(&mut self) { + self.scrollable_overflow = Some(self.children.iter().fold( + PhysicalRect::zero(), + |acc, child| { + acc.union( + &child + .calculate_scrollable_overflow_for_parent() + .translate(self.rect.origin.to_vector()), + ) + }, + )); + } + + pub(crate) fn scrollable_overflow_for_parent(&self) -> PhysicalRect<Au> { + self.scrollable_overflow.expect( + "Should only call `scrollable_overflow_for_parent()` after calculating overflow", + ) + } + pub fn print(&self, tree: &mut PrintTree) { tree.new_level(format!( "PositioningFragment\ |