diff options
Diffstat (limited to 'components/layout')
-rw-r--r-- | components/layout/display_list/stacking_context.rs | 4 | ||||
-rw-r--r-- | components/layout/flow/construct.rs | 7 | ||||
-rw-r--r-- | components/layout/flow/mod.rs | 31 | ||||
-rw-r--r-- | components/layout/flow/root.rs | 24 | ||||
-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 | ||||
-rw-r--r-- | components/layout/layout_impl.rs | 38 | ||||
-rw-r--r-- | components/layout/positioned.rs | 7 | ||||
-rw-r--r-- | components/layout/query.rs | 4 | ||||
-rw-r--r-- | components/layout/stylesheets/servo.css | 4 | ||||
-rw-r--r-- | components/layout/taffy/layout.rs | 9 | ||||
-rw-r--r-- | components/layout/taffy/mod.rs | 14 | ||||
-rw-r--r-- | components/layout/taffy/stylo_taffy/convert.rs | 78 | ||||
-rw-r--r-- | components/layout/taffy/stylo_taffy/wrapper.rs | 81 |
16 files changed, 261 insertions, 181 deletions
diff --git a/components/layout/display_list/stacking_context.rs b/components/layout/display_list/stacking_context.rs index 66d8421e5f7..17e8f2ef4fd 100644 --- a/components/layout/display_list/stacking_context.rs +++ b/components/layout/display_list/stacking_context.rs @@ -618,7 +618,7 @@ impl StackingContext { // If it’s larger, we also want to paint areas reachable after scrolling. let painting_area = fragment_tree .initial_containing_block - .union(&fragment_tree.scrollable_overflow) + .union(&fragment_tree.scrollable_overflow()) .to_webrender(); let background_color = @@ -1346,7 +1346,7 @@ impl BoxFragment { let position = self.style.get_box().position; // https://drafts.csswg.org/css2/#clipping // The clip property applies only to absolutely positioned elements - if position != ComputedPosition::Absolute && position != ComputedPosition::Fixed { + if !position.is_absolutely_positioned() { return None; } diff --git a/components/layout/flow/construct.rs b/components/layout/flow/construct.rs index cc3fe0e6f44..d8d6cd5c6ab 100644 --- a/components/layout/flow/construct.rs +++ b/components/layout/flow/construct.rs @@ -744,9 +744,14 @@ impl BlockLevelJob<'_> { self.propagated_data, false, /* is_list_item */ ); + // An outside ::marker must establish a BFC, and can't contain floats. + let block_formatting_context = BlockFormattingContext { + contents: block_container, + contains_floats: false, + }; ArcRefCell::new(BlockLevelBox::OutsideMarker(OutsideMarker { base: LayoutBoxBase::new(info.into(), info.style.clone()), - block_container, + block_formatting_context, list_item_style, })) }, diff --git a/components/layout/flow/mod.rs b/components/layout/flow/mod.rs index 4776b65771c..81343d81111 100644 --- a/components/layout/flow/mod.rs +++ b/components/layout/flow/mod.rs @@ -308,7 +308,7 @@ pub(crate) struct CollapsibleWithParentStartMargin(bool); pub(crate) struct OutsideMarker { pub list_item_style: Arc<ComputedValues>, pub base: LayoutBoxBase, - pub block_container: BlockContainer, + pub block_formatting_context: BlockFormattingContext, } impl OutsideMarker { @@ -317,8 +317,11 @@ impl OutsideMarker { layout_context: &LayoutContext, constraint_space: &ConstraintSpace, ) -> InlineContentSizesResult { - self.base - .inline_content_sizes(layout_context, constraint_space, &self.block_container) + self.base.inline_content_sizes( + layout_context, + constraint_space, + &self.block_formatting_context.contents, + ) } fn layout( @@ -326,8 +329,6 @@ impl OutsideMarker { layout_context: &LayoutContext<'_>, containing_block: &ContainingBlock<'_>, positioning_context: &mut PositioningContext, - sequential_layout_state: Option<&mut SequentialLayoutState>, - collapsible_with_parent_start_margin: Option<CollapsibleWithParentStartMargin>, ) -> Fragment { let constraint_space = ConstraintSpace::new_for_style_and_ratio( &self.base.style, @@ -342,17 +343,11 @@ impl OutsideMarker { style: &self.base.style, }; - // A ::marker can't have a stretch size (must be auto), so this doesn't matter. - // https://drafts.csswg.org/css-sizing-4/#stretch-fit-sizing - let ignore_block_margins_for_stretch = LogicalSides1D::new(false, false); - - let flow_layout = self.block_container.layout( + let flow_layout = self.block_formatting_context.layout( layout_context, positioning_context, &containing_block_for_children, - sequential_layout_state, - collapsible_with_parent_start_margin.unwrap_or(CollapsibleWithParentStartMargin(false)), - ignore_block_margins_for_stretch, + false, /* depends_on_block_constraints */ ); let max_inline_size = @@ -900,13 +895,9 @@ impl BlockLevelBox { BlockLevelBox::OutOfFlowFloatBox(float_box) => Fragment::Float(ArcRefCell::new( float_box.layout(layout_context, positioning_context, containing_block), )), - BlockLevelBox::OutsideMarker(outside_marker) => outside_marker.layout( - layout_context, - containing_block, - positioning_context, - sequential_layout_state, - collapsible_with_parent_start_margin, - ), + BlockLevelBox::OutsideMarker(outside_marker) => { + outside_marker.layout(layout_context, containing_block, positioning_context) + }, }; self.with_base(|base| base.set_fragment(fragment.clone())); diff --git a/components/layout/flow/root.rs b/components/layout/flow/root.rs index fb9884a4f01..fe98dbc3156 100644 --- a/components/layout/flow/root.rs +++ b/components/layout/flow/root.rs @@ -29,7 +29,7 @@ use crate::flow::inline::InlineItem; use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox}; use crate::formatting_contexts::IndependentFormattingContext; use crate::fragment_tree::FragmentTree; -use crate::geom::{LogicalVec2, PhysicalRect, PhysicalSize}; +use crate::geom::{LogicalVec2, PhysicalSize}; use crate::positioned::{AbsolutelyPositionedBox, PositioningContext}; use crate::replaced::ReplacedContents; use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside}; @@ -392,31 +392,9 @@ impl BoxTree { &mut root_fragments, ); - let scrollable_overflow = root_fragments - .iter() - .fold(PhysicalRect::zero(), |acc, child| { - let child_overflow = child.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) - }); - FragmentTree::new( layout_context, root_fragments, - scrollable_overflow, physical_containing_block, self.viewport_scroll_sensitivity, ) 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\ diff --git a/components/layout/layout_impl.rs b/components/layout/layout_impl.rs index 54edc215389..0fbc8395c35 100644 --- a/components/layout/layout_impl.rs +++ b/components/layout/layout_impl.rs @@ -8,6 +8,7 @@ use std::cell::{Cell, RefCell}; use std::collections::HashMap; use std::fmt::Debug; use std::process; +use std::rc::Rc; use std::sync::{Arc, LazyLock}; use app_units::Au; @@ -142,7 +143,7 @@ pub struct LayoutThread { box_tree: RefCell<Option<Arc<BoxTree>>>, /// The fragment tree. - fragment_tree: RefCell<Option<Arc<FragmentTree>>>, + fragment_tree: RefCell<Option<Rc<FragmentTree>>>, /// The [`StackingContextTree`] cached from previous layouts. stacking_context_tree: RefCell<Option<StackingContextTree>>, @@ -656,7 +657,7 @@ impl LayoutThread { &mut layout_context, viewport_changed, ); - + self.calculate_overflow(damage); self.build_stacking_context_tree(&reflow_request, damage); self.build_display_list(&reflow_request, &mut layout_context); @@ -773,8 +774,11 @@ impl LayoutThread { driver::traverse_dom(&recalc_style_traversal, token, rayon_pool).as_node(); let root_node = root_element.as_node(); - let damage = compute_damage_and_repair_style(layout_context.shared_context(), root_node); - if !viewport_changed && !damage.contains(RestyleDamage::REBUILD_BOX) { + let mut damage = + compute_damage_and_repair_style(layout_context.shared_context(), root_node); + if viewport_changed { + damage = RestyleDamage::REBUILD_BOX; + } else if !damage.contains(RestyleDamage::REBUILD_BOX) { layout_context.style_context.stylist.rule_tree().maybe_gc(); return damage; } @@ -802,15 +806,12 @@ impl LayoutThread { .unwrap() .layout(recalc_style_traversal.context(), viewport_size) }; - let fragment_tree = Arc::new(if let Some(pool) = rayon_pool { + let fragment_tree = Rc::new(if let Some(pool) = rayon_pool { pool.install(run_layout) } else { run_layout() }); - if self.debug.dump_flow_tree { - fragment_tree.print(); - } *self.fragment_tree.borrow_mut() = Some(fragment_tree); // The FragmentTree has been updated, so any existing StackingContext tree that layout @@ -837,6 +838,19 @@ impl LayoutThread { damage } + fn calculate_overflow(&self, damage: RestyleDamage) { + if !damage.contains(RestyleDamage::RECALCULATE_OVERFLOW) { + return; + } + + if let Some(fragment_tree) = &*self.fragment_tree.borrow() { + fragment_tree.calculate_scrollable_overflow(); + if self.debug.dump_flow_tree { + fragment_tree.print(); + } + } + } + fn build_stacking_context_tree(&self, reflow_request: &ReflowRequest, damage: RestyleDamage) { if !reflow_request.reflow_goal.needs_display_list() && !reflow_request.reflow_goal.needs_display() @@ -858,13 +872,19 @@ impl LayoutThread { viewport_size.height.to_f32_px(), ); + let scrollable_overflow = fragment_tree.scrollable_overflow(); + let scrollable_overflow = LayoutSize::from_untyped(Size2D::new( + scrollable_overflow.size.width.to_f32_px(), + scrollable_overflow.size.height.to_f32_px(), + )); + // Build the StackingContextTree. This turns the `FragmentTree` into a // tree of fragments in CSS painting order and also creates all // applicable spatial and clip nodes. *self.stacking_context_tree.borrow_mut() = Some(StackingContextTree::new( fragment_tree, viewport_size, - fragment_tree.scrollable_overflow(), + scrollable_overflow, self.id.into(), fragment_tree.viewport_scroll_sensitivity, self.first_reflow.get(), diff --git a/components/layout/positioned.rs b/components/layout/positioned.rs index 6280864d533..186fc78e3bf 100644 --- a/components/layout/positioned.rs +++ b/components/layout/positioned.rs @@ -305,10 +305,7 @@ impl PositioningContext { } pub(crate) fn push(&mut self, hoisted_box: HoistedAbsolutelyPositionedBox) { - debug_assert!(matches!( - hoisted_box.position(), - Position::Absolute | Position::Fixed - )); + debug_assert!(hoisted_box.position().is_absolutely_positioned()); self.absolutes.push(hoisted_box); } @@ -380,7 +377,7 @@ impl HoistedAbsolutelyPositionedBox { .context .style() .clone_position(); - assert!(position == Position::Fixed || position == Position::Absolute); + assert!(position.is_absolutely_positioned()); position } diff --git a/components/layout/query.rs b/components/layout/query.rs index ca9db9ceaf1..7f304ff2da1 100644 --- a/components/layout/query.rs +++ b/components/layout/query.rs @@ -3,7 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ //! Utilities for querying the layout, as needed by layout. -use std::sync::Arc; +use std::rc::Rc; use app_units::Au; use euclid::default::{Point2D, Rect}; @@ -80,7 +80,7 @@ pub fn process_client_rect_request(node: ServoLayoutNode<'_>) -> Rect<i32> { /// <https://drafts.csswg.org/cssom-view/#scrolling-area> pub fn process_node_scroll_area_request( requested_node: Option<ServoLayoutNode<'_>>, - fragment_tree: Option<Arc<FragmentTree>>, + fragment_tree: Option<Rc<FragmentTree>>, ) -> Rect<i32> { let Some(tree) = fragment_tree else { return Rect::zero(); diff --git a/components/layout/stylesheets/servo.css b/components/layout/stylesheets/servo.css index c025b19f364..cb206bbcd00 100644 --- a/components/layout/stylesheets/servo.css +++ b/components/layout/stylesheets/servo.css @@ -265,4 +265,8 @@ select { padding: 0 0.25em; /* Don't show a text cursor when hovering selected option */ cursor: default; +} + +slot { + display: contents; }
\ No newline at end of file diff --git a/components/layout/taffy/layout.rs b/components/layout/taffy/layout.rs index 61c4a0508e9..c5f66eee6d2 100644 --- a/components/layout/taffy/layout.rs +++ b/components/layout/taffy/layout.rs @@ -107,7 +107,7 @@ impl taffy::LayoutPartialTree for TaffyContainerContext<'_> { Self: 'a; fn get_core_container_style(&self, _node_id: taffy::NodeId) -> Self::CoreContainerStyle<'_> { - TaffyStyloStyle(self.style) + TaffyStyloStyle::new(self.style, false /* is_replaced */) } fn set_unrounded_layout(&mut self, node_id: taffy::NodeId, layout: &taffy::Layout) { @@ -311,7 +311,7 @@ impl taffy::LayoutGridContainer for TaffyContainerContext<'_> { &self, _node_id: taffy::prelude::NodeId, ) -> Self::GridContainerStyle<'_> { - TaffyStyloStyle(self.style) + TaffyStyloStyle::new(self.style, false /* is_replaced */) } fn get_grid_child_style( @@ -320,7 +320,10 @@ impl taffy::LayoutGridContainer for TaffyContainerContext<'_> { ) -> Self::GridItemStyle<'_> { let id = usize::from(child_node_id); let child = (*self.source_child_nodes[id]).borrow(); - TaffyStyloStyle(AtomicRef::map(child, |c| &*c.style)) + // TODO: account for non-replaced elements that are "compressible replaced" + let is_replaced = child.is_in_flow_replaced(); + let stylo_style = AtomicRef::map(child, |c| &*c.style); + TaffyStyloStyle::new(stylo_style, is_replaced) } fn set_detailed_grid_info( diff --git a/components/layout/taffy/mod.rs b/components/layout/taffy/mod.rs index 05fc09c5511..d34f36f249a 100644 --- a/components/layout/taffy/mod.rs +++ b/components/layout/taffy/mod.rs @@ -19,7 +19,9 @@ use crate::construct_modern::{ModernContainerBuilder, ModernItemKind}; use crate::context::LayoutContext; use crate::dom::LayoutBox; use crate::dom_traversal::{NodeAndStyleInfo, NonReplacedContents}; -use crate::formatting_contexts::IndependentFormattingContext; +use crate::formatting_contexts::{ + IndependentFormattingContext, IndependentFormattingContextContents, +}; use crate::fragment_tree::Fragment; use crate::positioned::{AbsolutelyPositionedBox, PositioningContext}; @@ -166,6 +168,16 @@ impl TaffyItemBox { .repair_style(context, node, new_style), } } + + fn is_in_flow_replaced(&self) -> bool { + match &self.taffy_level_box { + TaffyItemBoxInner::InFlowBox(fc) => match fc.contents { + IndependentFormattingContextContents::NonReplaced(_) => false, + IndependentFormattingContextContents::Replaced(_) => true, + }, + TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(_) => false, + } + } } /// Details from Taffy grid layout that will be stored diff --git a/components/layout/taffy/stylo_taffy/convert.rs b/components/layout/taffy/stylo_taffy/convert.rs index 5780be17c82..1b365cde6f6 100644 --- a/components/layout/taffy/stylo_taffy/convert.rs +++ b/components/layout/taffy/stylo_taffy/convert.rs @@ -7,6 +7,7 @@ mod stylo { pub(crate) use style::properties::generated::longhands::box_sizing::computed_value::T as BoxSizing; pub(crate) use style::properties::longhands::aspect_ratio::computed_value::T as AspectRatio; pub(crate) use style::properties::longhands::position::computed_value::T as Position; + pub(crate) use style::values::computed::length_percentage::Unpacked as UnpackedLengthPercentage; pub(crate) use style::values::computed::{LengthPercentage, Percentage}; pub(crate) use style::values::generics::NonNegative; pub(crate) use style::values::generics::length::{ @@ -32,15 +33,16 @@ mod stylo { pub(crate) use style::values::specified::GenericGridTemplateComponent; } +use taffy::MaxTrackSizingFunction; +use taffy::style_helpers::*; + #[inline] pub fn length_percentage(val: &stylo::LengthPercentage) -> taffy::LengthPercentage { - if let Some(length) = val.to_length() { - taffy::LengthPercentage::Length(length.px()) - } else if let Some(val) = val.to_percentage() { - taffy::LengthPercentage::Percent(val.0) - } else { + match val.unpack() { + stylo::UnpackedLengthPercentage::Length(len) => length(len.px()), + stylo::UnpackedLengthPercentage::Percentage(percentage) => percent(percentage.0), // TODO: Support calc - taffy::LengthPercentage::Percent(0.0) + stylo::UnpackedLengthPercentage::Calc(_) => percent(0.0), } } @@ -48,14 +50,14 @@ pub fn length_percentage(val: &stylo::LengthPercentage) -> taffy::LengthPercenta pub fn dimension(val: &stylo::Size) -> taffy::Dimension { match val { stylo::Size::LengthPercentage(val) => length_percentage(&val.0).into(), - stylo::Size::Auto => taffy::Dimension::Auto, + stylo::Size::Auto => taffy::Dimension::AUTO, // TODO: implement other values in Taffy - stylo::Size::MaxContent => taffy::Dimension::Auto, - stylo::Size::MinContent => taffy::Dimension::Auto, - stylo::Size::FitContent => taffy::Dimension::Auto, - stylo::Size::FitContentFunction(_) => taffy::Dimension::Auto, - stylo::Size::Stretch => taffy::Dimension::Auto, + stylo::Size::MaxContent => taffy::Dimension::AUTO, + stylo::Size::MinContent => taffy::Dimension::AUTO, + stylo::Size::FitContent => taffy::Dimension::AUTO, + stylo::Size::FitContentFunction(_) => taffy::Dimension::AUTO, + stylo::Size::Stretch => taffy::Dimension::AUTO, // Anchor positioning will be flagged off for time being stylo::Size::AnchorSizeFunction(_) => unreachable!(), @@ -67,14 +69,14 @@ pub fn dimension(val: &stylo::Size) -> taffy::Dimension { pub fn max_size_dimension(val: &stylo::MaxSize) -> taffy::Dimension { match val { stylo::MaxSize::LengthPercentage(val) => length_percentage(&val.0).into(), - stylo::MaxSize::None => taffy::Dimension::Auto, + stylo::MaxSize::None => taffy::Dimension::AUTO, // TODO: implement other values in Taffy - stylo::MaxSize::MaxContent => taffy::Dimension::Auto, - stylo::MaxSize::MinContent => taffy::Dimension::Auto, - stylo::MaxSize::FitContent => taffy::Dimension::Auto, - stylo::MaxSize::FitContentFunction(_) => taffy::Dimension::Auto, - stylo::MaxSize::Stretch => taffy::Dimension::Auto, + stylo::MaxSize::MaxContent => taffy::Dimension::AUTO, + stylo::MaxSize::MinContent => taffy::Dimension::AUTO, + stylo::MaxSize::FitContent => taffy::Dimension::AUTO, + stylo::MaxSize::FitContentFunction(_) => taffy::Dimension::AUTO, + stylo::MaxSize::Stretch => taffy::Dimension::AUTO, // Anchor positioning will be flagged off for time being stylo::MaxSize::AnchorSizeFunction(_) => unreachable!(), @@ -85,7 +87,7 @@ pub fn max_size_dimension(val: &stylo::MaxSize) -> taffy::Dimension { #[inline] pub fn margin(val: &stylo::MarginVal) -> taffy::LengthPercentageAuto { match val { - stylo::MarginVal::Auto => taffy::LengthPercentageAuto::Auto, + stylo::MarginVal::Auto => taffy::LengthPercentageAuto::AUTO, stylo::MarginVal::LengthPercentage(val) => length_percentage(val).into(), // Anchor positioning will be flagged off for time being @@ -97,7 +99,7 @@ pub fn margin(val: &stylo::MarginVal) -> taffy::LengthPercentageAuto { #[inline] pub fn inset(val: &stylo::InsetVal) -> taffy::LengthPercentageAuto { match val { - stylo::InsetVal::Auto => taffy::LengthPercentageAuto::Auto, + stylo::InsetVal::Auto => taffy::LengthPercentageAuto::AUTO, stylo::InsetVal::LengthPercentage(val) => length_percentage(val).into(), // Anchor positioning will be flagged off for time being @@ -214,7 +216,7 @@ pub fn gap(input: &stylo::Gap) -> taffy::LengthPercentage { match input { // For Flexbox and CSS Grid the "normal" value is 0px. This may need to be updated // if we ever implement multi-column layout. - stylo::Gap::Normal => taffy::LengthPercentage::Length(0.0), + stylo::Gap::Normal => taffy::LengthPercentage::ZERO, stylo::Gap::LengthPercentage(val) => length_percentage(&val.0), } } @@ -306,16 +308,18 @@ pub fn track_size( max: max_track(max), }, stylo::TrackSize::FitContent(limit) => taffy::MinMax { - min: taffy::MinTrackSizingFunction::Auto, - max: taffy::MaxTrackSizingFunction::FitContent(match limit { - stylo::TrackBreadth::Breadth(lp) => length_percentage(lp), + min: taffy::MinTrackSizingFunction::AUTO, + max: match limit { + stylo::TrackBreadth::Breadth(lp) => { + MaxTrackSizingFunction::fit_content(length_percentage(lp)) + }, // Are these valid? Taffy doesn't support this in any case stylo::TrackBreadth::Fr(_) => unreachable!(), stylo::TrackBreadth::Auto => unreachable!(), stylo::TrackBreadth::MinContent => unreachable!(), stylo::TrackBreadth::MaxContent => unreachable!(), - }), + }, }, } } @@ -325,13 +329,11 @@ pub fn min_track( input: &stylo::TrackBreadth<stylo::LengthPercentage>, ) -> taffy::MinTrackSizingFunction { match input { - stylo::TrackBreadth::Breadth(lp) => { - taffy::MinTrackSizingFunction::Fixed(length_percentage(lp)) - }, - stylo::TrackBreadth::Fr(_) => taffy::MinTrackSizingFunction::Auto, - stylo::TrackBreadth::Auto => taffy::MinTrackSizingFunction::Auto, - stylo::TrackBreadth::MinContent => taffy::MinTrackSizingFunction::MinContent, - stylo::TrackBreadth::MaxContent => taffy::MinTrackSizingFunction::MaxContent, + stylo::TrackBreadth::Breadth(lp) => length_percentage(lp).into(), + stylo::TrackBreadth::Fr(_) => taffy::MinTrackSizingFunction::AUTO, + stylo::TrackBreadth::Auto => taffy::MinTrackSizingFunction::AUTO, + stylo::TrackBreadth::MinContent => taffy::MinTrackSizingFunction::MIN_CONTENT, + stylo::TrackBreadth::MaxContent => taffy::MinTrackSizingFunction::MAX_CONTENT, } } @@ -340,12 +342,10 @@ pub fn max_track( input: &stylo::TrackBreadth<stylo::LengthPercentage>, ) -> taffy::MaxTrackSizingFunction { match input { - stylo::TrackBreadth::Breadth(lp) => { - taffy::MaxTrackSizingFunction::Fixed(length_percentage(lp)) - }, - stylo::TrackBreadth::Fr(val) => taffy::MaxTrackSizingFunction::Fraction(*val), - stylo::TrackBreadth::Auto => taffy::MaxTrackSizingFunction::Auto, - stylo::TrackBreadth::MinContent => taffy::MaxTrackSizingFunction::MinContent, - stylo::TrackBreadth::MaxContent => taffy::MaxTrackSizingFunction::MaxContent, + stylo::TrackBreadth::Breadth(lp) => length_percentage(lp).into(), + stylo::TrackBreadth::Fr(val) => fr(*val), + stylo::TrackBreadth::Auto => taffy::MaxTrackSizingFunction::AUTO, + stylo::TrackBreadth::MinContent => taffy::MaxTrackSizingFunction::MIN_CONTENT, + stylo::TrackBreadth::MaxContent => taffy::MaxTrackSizingFunction::MAX_CONTENT, } } diff --git a/components/layout/taffy/stylo_taffy/wrapper.rs b/components/layout/taffy/stylo_taffy/wrapper.rs index 35b19aa7838..22d02ffeb08 100644 --- a/components/layout/taffy/stylo_taffy/wrapper.rs +++ b/components/layout/taffy/stylo_taffy/wrapper.rs @@ -10,33 +10,44 @@ use super::convert; /// A wrapper struct for anything that Deref's to a [`ComputedValues`], which /// implements Taffy's layout traits and can used with Taffy's layout algorithms. -pub struct TaffyStyloStyle<T: Deref<Target = ComputedValues>>(pub T); +pub struct TaffyStyloStyle<T: Deref<Target = ComputedValues>> { + pub style: T, + pub is_compressible_replaced: bool, +} -impl<T: Deref<Target = ComputedValues>> From<T> for TaffyStyloStyle<T> { - fn from(value: T) -> Self { - Self(value) +impl<T: Deref<Target = ComputedValues>> TaffyStyloStyle<T> { + pub fn new(style: T, is_compressible_replaced: bool) -> Self { + Self { + style, + is_compressible_replaced, + } } } impl<T: Deref<Target = ComputedValues>> taffy::CoreStyle for TaffyStyloStyle<T> { #[inline] fn box_generation_mode(&self) -> taffy::BoxGenerationMode { - convert::box_generation_mode(self.0.get_box().display) + convert::box_generation_mode(self.style.get_box().display) } #[inline] fn is_block(&self) -> bool { - convert::is_block(self.0.get_box().display) + convert::is_block(self.style.get_box().display) + } + + #[inline] + fn is_compressible_replaced(&self) -> bool { + self.is_compressible_replaced } #[inline] fn box_sizing(&self) -> taffy::BoxSizing { - convert::box_sizing(self.0.get_position().box_sizing) + convert::box_sizing(self.style.get_position().box_sizing) } #[inline] fn overflow(&self) -> taffy::Point<taffy::Overflow> { - let box_styles = self.0.get_box(); + let box_styles = self.style.get_box(); taffy::Point { x: convert::overflow(box_styles.overflow_x), y: convert::overflow(box_styles.overflow_y), @@ -50,12 +61,12 @@ impl<T: Deref<Target = ComputedValues>> taffy::CoreStyle for TaffyStyloStyle<T> #[inline] fn position(&self) -> taffy::Position { - convert::position(self.0.get_box().position) + convert::position(self.style.get_box().position) } #[inline] fn inset(&self) -> taffy::Rect<taffy::LengthPercentageAuto> { - let position_styles = self.0.get_position(); + let position_styles = self.style.get_position(); taffy::Rect { left: convert::inset(&position_styles.left), right: convert::inset(&position_styles.right), @@ -66,7 +77,7 @@ impl<T: Deref<Target = ComputedValues>> taffy::CoreStyle for TaffyStyloStyle<T> #[inline] fn size(&self) -> taffy::Size<taffy::Dimension> { - let position_styles = self.0.get_position(); + let position_styles = self.style.get_position(); taffy::Size { width: convert::dimension(&position_styles.width), height: convert::dimension(&position_styles.height), @@ -75,7 +86,7 @@ impl<T: Deref<Target = ComputedValues>> taffy::CoreStyle for TaffyStyloStyle<T> #[inline] fn min_size(&self) -> taffy::Size<taffy::Dimension> { - let position_styles = self.0.get_position(); + let position_styles = self.style.get_position(); taffy::Size { width: convert::dimension(&position_styles.min_width), height: convert::dimension(&position_styles.min_height), @@ -84,7 +95,7 @@ impl<T: Deref<Target = ComputedValues>> taffy::CoreStyle for TaffyStyloStyle<T> #[inline] fn max_size(&self) -> taffy::Size<taffy::Dimension> { - let position_styles = self.0.get_position(); + let position_styles = self.style.get_position(); taffy::Size { width: convert::max_size_dimension(&position_styles.max_width), height: convert::max_size_dimension(&position_styles.max_height), @@ -93,12 +104,12 @@ impl<T: Deref<Target = ComputedValues>> taffy::CoreStyle for TaffyStyloStyle<T> #[inline] fn aspect_ratio(&self) -> Option<f32> { - convert::aspect_ratio(self.0.get_position().aspect_ratio) + convert::aspect_ratio(self.style.get_position().aspect_ratio) } #[inline] fn margin(&self) -> taffy::Rect<taffy::LengthPercentageAuto> { - let margin_styles = self.0.get_margin(); + let margin_styles = self.style.get_margin(); taffy::Rect { left: convert::margin(&margin_styles.margin_left), right: convert::margin(&margin_styles.margin_right), @@ -109,7 +120,7 @@ impl<T: Deref<Target = ComputedValues>> taffy::CoreStyle for TaffyStyloStyle<T> #[inline] fn padding(&self) -> taffy::Rect<taffy::LengthPercentage> { - let padding_styles = self.0.get_padding(); + let padding_styles = self.style.get_padding(); taffy::Rect { left: convert::length_percentage(&padding_styles.padding_left.0), right: convert::length_percentage(&padding_styles.padding_right.0), @@ -120,12 +131,12 @@ impl<T: Deref<Target = ComputedValues>> taffy::CoreStyle for TaffyStyloStyle<T> #[inline] fn border(&self) -> taffy::Rect<taffy::LengthPercentage> { - let border_styles = self.0.get_border(); + let border_styles = self.style.get_border(); taffy::Rect { - left: taffy::LengthPercentage::Length(border_styles.border_left_width.to_f32_px()), - right: taffy::LengthPercentage::Length(border_styles.border_right_width.to_f32_px()), - top: taffy::LengthPercentage::Length(border_styles.border_top_width.to_f32_px()), - bottom: taffy::LengthPercentage::Length(border_styles.border_bottom_width.to_f32_px()), + left: taffy::LengthPercentage::length(border_styles.border_left_width.to_f32_px()), + right: taffy::LengthPercentage::length(border_styles.border_right_width.to_f32_px()), + top: taffy::LengthPercentage::length(border_styles.border_top_width.to_f32_px()), + bottom: taffy::LengthPercentage::length(border_styles.border_bottom_width.to_f32_px()), } } } @@ -142,32 +153,32 @@ impl<T: Deref<Target = ComputedValues>> taffy::GridContainerStyle for TaffyStylo #[inline] fn grid_template_rows(&self) -> Self::TemplateTrackList<'_> { - convert::grid_template_tracks(&self.0.get_position().grid_template_rows) + convert::grid_template_tracks(&self.style.get_position().grid_template_rows) } #[inline] fn grid_template_columns(&self) -> Self::TemplateTrackList<'_> { - convert::grid_template_tracks(&self.0.get_position().grid_template_columns) + convert::grid_template_tracks(&self.style.get_position().grid_template_columns) } #[inline] fn grid_auto_rows(&self) -> Self::AutoTrackList<'_> { - convert::grid_auto_tracks(&self.0.get_position().grid_auto_rows) + convert::grid_auto_tracks(&self.style.get_position().grid_auto_rows) } #[inline] fn grid_auto_columns(&self) -> Self::AutoTrackList<'_> { - convert::grid_auto_tracks(&self.0.get_position().grid_auto_columns) + convert::grid_auto_tracks(&self.style.get_position().grid_auto_columns) } #[inline] fn grid_auto_flow(&self) -> taffy::GridAutoFlow { - convert::grid_auto_flow(self.0.get_position().grid_auto_flow) + convert::grid_auto_flow(self.style.get_position().grid_auto_flow) } #[inline] fn gap(&self) -> taffy::Size<taffy::LengthPercentage> { - let position_styles = self.0.get_position(); + let position_styles = self.style.get_position(); taffy::Size { width: convert::gap(&position_styles.column_gap), height: convert::gap(&position_styles.row_gap), @@ -176,29 +187,29 @@ impl<T: Deref<Target = ComputedValues>> taffy::GridContainerStyle for TaffyStylo #[inline] fn align_content(&self) -> Option<taffy::AlignContent> { - convert::content_alignment(self.0.get_position().align_content.0) + convert::content_alignment(self.style.get_position().align_content.0) } #[inline] fn justify_content(&self) -> Option<taffy::JustifyContent> { - convert::content_alignment(self.0.get_position().justify_content.0) + convert::content_alignment(self.style.get_position().justify_content.0) } #[inline] fn align_items(&self) -> Option<taffy::AlignItems> { - convert::item_alignment(self.0.get_position().align_items.0) + convert::item_alignment(self.style.get_position().align_items.0) } #[inline] fn justify_items(&self) -> Option<taffy::AlignItems> { - convert::item_alignment(self.0.get_position().justify_items.computed.0) + convert::item_alignment(self.style.get_position().justify_items.computed.0) } } impl<T: Deref<Target = ComputedValues>> taffy::GridItemStyle for TaffyStyloStyle<T> { #[inline] fn grid_row(&self) -> taffy::Line<taffy::GridPlacement> { - let position_styles = self.0.get_position(); + let position_styles = self.style.get_position(); taffy::Line { start: convert::grid_line(&position_styles.grid_row_start), end: convert::grid_line(&position_styles.grid_row_end), @@ -207,7 +218,7 @@ impl<T: Deref<Target = ComputedValues>> taffy::GridItemStyle for TaffyStyloStyle #[inline] fn grid_column(&self) -> taffy::Line<taffy::GridPlacement> { - let position_styles = self.0.get_position(); + let position_styles = self.style.get_position(); taffy::Line { start: convert::grid_line(&position_styles.grid_column_start), end: convert::grid_line(&position_styles.grid_column_end), @@ -216,11 +227,11 @@ impl<T: Deref<Target = ComputedValues>> taffy::GridItemStyle for TaffyStyloStyle #[inline] fn align_self(&self) -> Option<taffy::AlignSelf> { - convert::item_alignment(self.0.get_position().align_self.0.0) + convert::item_alignment(self.style.get_position().align_self.0.0) } #[inline] fn justify_self(&self) -> Option<taffy::AlignSelf> { - convert::item_alignment(self.0.get_position().justify_self.0.0) + convert::item_alignment(self.style.get_position().justify_self.0.0) } } |