diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2020-03-18 06:14:20 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-18 06:14:20 -0400 |
commit | 5bf45b2622b7bfc194047ab602d27249f463d0da (patch) | |
tree | c3d15a51fadf5ae5ae89f21c1c346337f7e07273 | |
parent | 9fb83d81438d425e06d061f8ba0c4128c61fc1ac (diff) | |
parent | 0d6c60f03ed6829dc02fc16fb3e43482f0ab1ae7 (diff) | |
download | servo-5bf45b2622b7bfc194047ab602d27249f463d0da.tar.gz servo-5bf45b2622b7bfc194047ab602d27249f463d0da.zip |
Auto merge of #25957 - pcwalton:layout-2020-atomic-refcell, r=nox
Start using `AtomicRefCell` in layout 2020 as preparation for incremental layout
This makes `BlockLevelBox` and `InlineLevelBox` use `AtomicRefCell` for incremental layout, per @nox's suggestion in https://github.com/servo/servo/issues/25168.
As part of this, it reworks inline layout to use recursion, per https://github.com/servo/servo/issues/25950. LLVM should be able to optimize this into a loop (though I have not verified this).
r? @nox
-rw-r--r-- | Cargo.lock | 4 | ||||
-rw-r--r-- | components/layout_2020/Cargo.toml | 2 | ||||
-rw-r--r-- | components/layout_2020/cell.rs | 69 | ||||
-rw-r--r-- | components/layout_2020/dom_traversal.rs | 7 | ||||
-rw-r--r-- | components/layout_2020/element_data.rs | 13 | ||||
-rw-r--r-- | components/layout_2020/flow/construct.rs | 180 | ||||
-rw-r--r-- | components/layout_2020/flow/inline.rs | 94 | ||||
-rw-r--r-- | components/layout_2020/flow/mod.rs | 41 | ||||
-rw-r--r-- | components/layout_2020/flow/root.rs | 27 | ||||
-rw-r--r-- | components/layout_2020/formatting_contexts.rs | 4 | ||||
-rw-r--r-- | components/layout_2020/lib.rs | 2 | ||||
-rw-r--r-- | components/layout_2020/positioned.rs | 31 |
12 files changed, 309 insertions, 165 deletions
diff --git a/Cargo.lock b/Cargo.lock index 3002d5a7ac6..edbc3c83993 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -166,9 +166,9 @@ checksum = "3c86699c3f02778ec07158376991c8f783dd1f2f95c579ffaf0738dc984b2fe2" [[package]] name = "atomic_refcell" -version = "0.1.0" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb2dcb6e6d35f20276943cc04bb98e538b348d525a04ac79c10021561d202f21" +checksum = "3bc31dce067eab974c815a9deb95f6217806de7b53685d7fc31f8ccf3fb2539f" [[package]] name = "atty" diff --git a/components/layout_2020/Cargo.toml b/components/layout_2020/Cargo.toml index a4cbe4c4ea1..0d3e30dba53 100644 --- a/components/layout_2020/Cargo.toml +++ b/components/layout_2020/Cargo.toml @@ -14,7 +14,7 @@ doctest = false [dependencies] app_units = "0.7" -atomic_refcell = "0.1" +atomic_refcell = "0.1.6" canvas_traits = {path = "../canvas_traits"} cssparser = "0.27" embedder_traits = {path = "../embedder_traits"} diff --git a/components/layout_2020/cell.rs b/components/layout_2020/cell.rs new file mode 100644 index 00000000000..8aae377b24c --- /dev/null +++ b/components/layout_2020/cell.rs @@ -0,0 +1,69 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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 atomic_refcell::AtomicRefCell; +use serde::{Serialize, Serializer}; +use servo_arc::Arc; +use std::fmt; +use std::ops::Deref; + +pub(crate) struct ArcRefCell<T> { + value: Arc<AtomicRefCell<T>>, +} + +impl<T> ArcRefCell<T> { + pub fn new(value: T) -> Self { + Self { + value: Arc::new(AtomicRefCell::new(value)), + } + } +} + +impl<T> Clone for ArcRefCell<T> { + fn clone(&self) -> Self { + Self { + value: self.value.clone(), + } + } +} + +impl<T> Default for ArcRefCell<T> +where + T: Default, +{ + fn default() -> Self { + Self { + value: Arc::new(AtomicRefCell::new(Default::default())), + } + } +} + +impl<T> Deref for ArcRefCell<T> { + type Target = AtomicRefCell<T>; + + fn deref(&self) -> &Self::Target { + &self.value + } +} + +impl<T> fmt::Debug for ArcRefCell<T> +where + T: fmt::Debug, +{ + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + self.value.fmt(formatter) + } +} + +impl<T> Serialize for ArcRefCell<T> +where + T: Serialize, +{ + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + self.borrow().serialize(serializer) + } +} diff --git a/components/layout_2020/dom_traversal.rs b/components/layout_2020/dom_traversal.rs index 1a3a969919c..d60e779e665 100644 --- a/components/layout_2020/dom_traversal.rs +++ b/components/layout_2020/dom_traversal.rs @@ -2,13 +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 crate::cell::ArcRefCell; use crate::context::LayoutContext; use crate::element_data::{LayoutBox, LayoutDataForElement}; use crate::geom::PhysicalSize; use crate::replaced::{CanvasInfo, CanvasSource, ReplacedContent}; use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside, DisplayOutside}; use crate::wrapper::GetRawData; -use atomic_refcell::{AtomicRefCell, AtomicRefMut}; +use atomic_refcell::AtomicRefMut; use html5ever::LocalName; use net_traits::image::base::Image as NetImage; use script_layout_interface::wrapper_traits::{ @@ -317,12 +318,12 @@ where } pub struct BoxSlot<'dom> { - slot: Option<ServoArc<AtomicRefCell<Option<LayoutBox>>>>, + slot: Option<ArcRefCell<Option<LayoutBox>>>, marker: marker<&'dom ()>, } impl BoxSlot<'_> { - pub(crate) fn new(slot: ServoArc<AtomicRefCell<Option<LayoutBox>>>) -> Self { + pub(crate) fn new(slot: ArcRefCell<Option<LayoutBox>>) -> Self { *slot.borrow_mut() = None; let slot = Some(slot); Self { slot, marker } diff --git a/components/layout_2020/element_data.rs b/components/layout_2020/element_data.rs index ccd48ac04e3..7385b7d84f0 100644 --- a/components/layout_2020/element_data.rs +++ b/components/layout_2020/element_data.rs @@ -2,25 +2,24 @@ * 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 crate::cell::ArcRefCell; use crate::flow::inline::InlineLevelBox; use crate::flow::BlockLevelBox; -use atomic_refcell::AtomicRefCell; -use servo_arc::Arc; #[derive(Default)] pub struct LayoutDataForElement { - pub(super) self_box: Arc<AtomicRefCell<Option<LayoutBox>>>, + pub(super) self_box: ArcRefCell<Option<LayoutBox>>, pub(super) pseudo_elements: Option<Box<PseudoElementBoxes>>, } #[derive(Default)] pub(super) struct PseudoElementBoxes { - pub before: Arc<AtomicRefCell<Option<LayoutBox>>>, - pub after: Arc<AtomicRefCell<Option<LayoutBox>>>, + pub before: ArcRefCell<Option<LayoutBox>>, + pub after: ArcRefCell<Option<LayoutBox>>, } pub(super) enum LayoutBox { DisplayContents, - BlockLevel(Arc<BlockLevelBox>), - InlineLevel(Arc<InlineLevelBox>), + BlockLevel(ArcRefCell<BlockLevelBox>), + InlineLevel(ArcRefCell<InlineLevelBox>), } diff --git a/components/layout_2020/flow/construct.rs b/components/layout_2020/flow/construct.rs index cff3fa281a6..0bf0b5c83ad 100644 --- a/components/layout_2020/flow/construct.rs +++ b/components/layout_2020/flow/construct.rs @@ -2,6 +2,7 @@ * 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 crate::cell::ArcRefCell; use crate::context::LayoutContext; use crate::dom_traversal::{BoxSlot, Contents, NodeExt, NonReplacedContents, TraversalHandler}; use crate::element_data::LayoutBox; @@ -282,54 +283,48 @@ where // context with the parent style of that builder. let inlines = self.current_inline_level_boxes(); - fn last_text(inlines: &mut [Arc<InlineLevelBox>]) -> Option<&mut String> { - let last = inlines.last_mut()?; - if let InlineLevelBox::TextRun(_) = &**last { - // We never clone text run boxes, so the refcount is 1 and unwrap succeeds: - let last = Arc::get_mut(last).unwrap(); - if let InlineLevelBox::TextRun(TextRun { text, .. }) = last { - Some(text) - } else { - unreachable!() - } - } else { - None - } - } - let mut new_text_run_contents; let output; - if let Some(text) = last_text(inlines) { - // Append to the existing text run - new_text_run_contents = None; - output = text; - } else { - new_text_run_contents = Some(String::new()); - output = new_text_run_contents.as_mut().unwrap(); - } - if leading_whitespace { - output.push(' ') - } - loop { - if let Some(i) = input.bytes().position(|b| b.is_ascii_whitespace()) { - let (non_whitespace, rest) = input.split_at(i); - output.push_str(non_whitespace); - output.push(' '); - if let Some(i) = rest.bytes().position(|b| !b.is_ascii_whitespace()) { - input = &rest[i..]; + { + let mut last_box = inlines.last_mut().map(|last| last.borrow_mut()); + let last_text = last_box.as_mut().and_then(|last| match &mut **last { + InlineLevelBox::TextRun(last) => Some(&mut last.text), + _ => None, + }); + + if let Some(text) = last_text { + // Append to the existing text run + new_text_run_contents = None; + output = text; + } else { + new_text_run_contents = Some(String::new()); + output = new_text_run_contents.as_mut().unwrap(); + } + + if leading_whitespace { + output.push(' ') + } + loop { + if let Some(i) = input.bytes().position(|b| b.is_ascii_whitespace()) { + let (non_whitespace, rest) = input.split_at(i); + output.push_str(non_whitespace); + output.push(' '); + if let Some(i) = rest.bytes().position(|b| !b.is_ascii_whitespace()) { + input = &rest[i..]; + } else { + break; + } } else { + output.push_str(input); break; } - } else { - output.push_str(input); - break; } } if let Some(text) = new_text_run_contents { let parent_style = parent_style.clone(); - inlines.push(Arc::new(InlineLevelBox::TextRun(TextRun { + inlines.push(ArcRefCell::new(InlineLevelBox::TextRun(TextRun { tag: node.as_opaque(), parent_style, text, @@ -353,29 +348,53 @@ where if !text.starts_with(|c: char| c.is_ascii_whitespace()) { return (false, text); } - let mut inline_level_boxes = self.current_inline_level_boxes().iter().rev(); - let mut stack = Vec::new(); - let preserved = loop { - match inline_level_boxes.next().map(|b| &**b) { - Some(InlineLevelBox::TextRun(r)) => break !r.text.ends_with(' '), - Some(InlineLevelBox::Atomic { .. }) => break false, - Some(InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(_)) | - Some(InlineLevelBox::OutOfFlowFloatBox(_)) => {}, - Some(InlineLevelBox::InlineBox(b)) => { - stack.push(inline_level_boxes); - inline_level_boxes = b.children.iter().rev() - }, - None => { - if let Some(iter) = stack.pop() { - inline_level_boxes = iter - } else { - break false; // Paragraph start - } - }, - } + + let preserved = match whitespace_is_preserved(self.current_inline_level_boxes()) { + WhitespacePreservedResult::Unknown => { + // Paragraph start. + false + }, + WhitespacePreservedResult::NotPreserved => false, + WhitespacePreservedResult::Preserved => true, }; + let text = text.trim_start_matches(|c: char| c.is_ascii_whitespace()); - (preserved, text) + return (preserved, text); + + fn whitespace_is_preserved( + inline_level_boxes: &[ArcRefCell<InlineLevelBox>], + ) -> WhitespacePreservedResult { + for inline_level_box in inline_level_boxes.iter().rev() { + match *inline_level_box.borrow() { + InlineLevelBox::TextRun(ref r) => { + if r.text.ends_with(' ') { + return WhitespacePreservedResult::NotPreserved; + } + return WhitespacePreservedResult::Preserved; + }, + InlineLevelBox::Atomic { .. } => { + return WhitespacePreservedResult::NotPreserved; + }, + InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(_) | + InlineLevelBox::OutOfFlowFloatBox(_) => {}, + InlineLevelBox::InlineBox(ref b) => { + match whitespace_is_preserved(&b.children) { + WhitespacePreservedResult::Unknown => {}, + result => return result, + } + }, + } + } + + WhitespacePreservedResult::Unknown + } + + #[derive(Clone, Copy, PartialEq)] + enum WhitespacePreservedResult { + Preserved, + NotPreserved, + Unknown, + } } fn handle_inline_level_element( @@ -384,7 +403,7 @@ where style: &Arc<ComputedValues>, display_inside: DisplayInside, contents: Contents, - ) -> Arc<InlineLevelBox> { + ) -> ArcRefCell<InlineLevelBox> { let box_ = if display_inside == DisplayInside::Flow && !contents.is_replaced() { // We found un inline box. // Whatever happened before, all we need to do before recurring @@ -410,9 +429,9 @@ where .pop() .expect("no ongoing inline level box found"); inline_box.last_fragment = true; - Arc::new(InlineLevelBox::InlineBox(inline_box)) + ArcRefCell::new(InlineLevelBox::InlineBox(inline_box)) } else { - Arc::new(InlineLevelBox::Atomic( + ArcRefCell::new(InlineLevelBox::Atomic( IndependentFormattingContext::construct( self.context, node, @@ -466,13 +485,13 @@ where for mut fragmented_parent_inline_box in fragmented_inline_boxes { fragmented_parent_inline_box .children - .push(Arc::new(fragmented_inline)); + .push(ArcRefCell::new(fragmented_inline)); fragmented_inline = InlineLevelBox::InlineBox(fragmented_parent_inline_box); } self.ongoing_inline_formatting_context .inline_level_boxes - .push(Arc::new(fragmented_inline)); + .push(ArcRefCell::new(fragmented_inline)); } // We found a block level element, so the ongoing inline formatting @@ -525,7 +544,7 @@ where kind, }); } else { - let box_ = Arc::new(InlineLevelBox::OutOfFlowAbsolutelyPositionedBox( + let box_ = ArcRefCell::new(InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(Arc::new( AbsolutelyPositionedBox::construct( self.context, node, @@ -533,7 +552,7 @@ where display_inside, contents, ), - )); + ))); self.current_inline_level_boxes().push(box_.clone()); box_slot.set(LayoutBox::InlineLevel(box_)) } @@ -561,7 +580,7 @@ where kind, }); } else { - let box_ = Arc::new(InlineLevelBox::OutOfFlowFloatBox(FloatBox::construct( + let box_ = ArcRefCell::new(InlineLevelBox::OutOfFlowFloatBox(FloatBox::construct( self.context, node, style, @@ -610,7 +629,7 @@ where }); } - fn current_inline_level_boxes(&mut self) -> &mut Vec<Arc<InlineLevelBox>> { + fn current_inline_level_boxes(&mut self) -> &mut Vec<ArcRefCell<InlineLevelBox>> { match self.ongoing_inline_boxes_stack.last_mut() { Some(last) => &mut last.children, None => &mut self.ongoing_inline_formatting_context.inline_level_boxes, @@ -634,7 +653,7 @@ where self, context: &LayoutContext, max_assign_in_flow_outer_content_sizes_to: Option<&mut ContentSizes>, - ) -> (Arc<BlockLevelBox>, ContainsFloats) { + ) -> (ArcRefCell<BlockLevelBox>, ContainsFloats) { let node = self.node; let style = self.style; let (block_level_box, contains_floats) = match self.kind { @@ -651,7 +670,7 @@ where if let Some(to) = max_assign_in_flow_outer_content_sizes_to { to.max_assign(&box_content_sizes.outer_inline(&style)) } - let block_level_box = Arc::new(BlockLevelBox::SameFormattingContextBlock { + let block_level_box = ArcRefCell::new(BlockLevelBox::SameFormattingContextBlock { tag: node.as_opaque(), contents, style, @@ -678,7 +697,7 @@ where to.max_assign(&contents.content_sizes.outer_inline(&contents.style)) } ( - Arc::new(BlockLevelBox::Independent(contents)), + ArcRefCell::new(BlockLevelBox::Independent(contents)), ContainsFloats::No, ) }, @@ -686,22 +705,23 @@ where display_inside, contents, } => { - let block_level_box = Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox( - AbsolutelyPositionedBox::construct( - context, - node, - style, - display_inside, - contents, - ), - )); + let block_level_box = + ArcRefCell::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(Arc::new( + AbsolutelyPositionedBox::construct( + context, + node, + style, + display_inside, + contents, + ), + ))); (block_level_box, ContainsFloats::No) }, BlockLevelCreator::OutOfFlowFloatBox { display_inside, contents, } => { - let block_level_box = Arc::new(BlockLevelBox::OutOfFlowFloatBox( + let block_level_box = ArcRefCell::new(BlockLevelBox::OutOfFlowFloatBox( FloatBox::construct(context, node, style, display_inside, contents), )); (block_level_box, ContainsFloats::Yes) diff --git a/components/layout_2020/flow/inline.rs b/components/layout_2020/flow/inline.rs index bd8f5bc784f..f71187e1118 100644 --- a/components/layout_2020/flow/inline.rs +++ b/components/layout_2020/flow/inline.rs @@ -2,6 +2,7 @@ * 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 crate::cell::ArcRefCell; use crate::context::LayoutContext; use crate::flow::float::FloatBox; use crate::flow::FlowLayout; @@ -27,14 +28,14 @@ use webrender_api::FontInstanceKey; #[derive(Debug, Default, Serialize)] pub(crate) struct InlineFormattingContext { - pub(super) inline_level_boxes: Vec<Arc<InlineLevelBox>>, + pub(super) inline_level_boxes: Vec<ArcRefCell<InlineLevelBox>>, } #[derive(Debug, Serialize)] pub(crate) enum InlineLevelBox { InlineBox(InlineBox), TextRun(TextRun), - OutOfFlowAbsolutelyPositionedBox(AbsolutelyPositionedBox), + OutOfFlowAbsolutelyPositionedBox(Arc<AbsolutelyPositionedBox>), OutOfFlowFloatBox(FloatBox), Atomic(IndependentFormattingContext), } @@ -46,7 +47,7 @@ pub(crate) struct InlineBox { pub style: Arc<ComputedValues>, pub first_fragment: bool, pub last_fragment: bool, - pub children: Vec<Arc<InlineLevelBox>>, + pub children: Vec<ArcRefCell<InlineLevelBox>>, } /// https://www.w3.org/TR/css-display-3/#css-text-run @@ -59,7 +60,7 @@ pub(crate) struct TextRun { } struct InlineNestingLevelState<'box_tree> { - remaining_boxes: std::slice::Iter<'box_tree, Arc<InlineLevelBox>>, + remaining_boxes: InlineBoxChildIter<'box_tree>, fragments_so_far: Vec<Fragment>, inline_start: Length, max_block_size_of_fragments_so_far: Length, @@ -77,7 +78,7 @@ struct PartialInlineBoxFragment<'box_tree> { } struct InlineFormattingContextState<'box_tree, 'a, 'b> { - positioning_context: &'a mut PositioningContext<'box_tree>, + positioning_context: &'a mut PositioningContext, containing_block: &'b ContainingBlock<'b>, lines: Lines, inline_position: Length, @@ -105,10 +106,10 @@ impl InlineFormattingContext { fn traverse( &mut self, layout_context: &LayoutContext, - inline_level_boxes: &[Arc<InlineLevelBox>], + inline_level_boxes: &[ArcRefCell<InlineLevelBox>], ) { for inline_level_box in inline_level_boxes { - match &**inline_level_box { + match &*inline_level_box.borrow() { InlineLevelBox::InlineBox(inline_box) => { let padding = inline_box.style.padding(); let border = inline_box.style.border_width(); @@ -204,10 +205,10 @@ impl InlineFormattingContext { computation.paragraph } - pub(super) fn layout<'a>( - &'a self, + pub(super) fn layout( + &self, layout_context: &LayoutContext, - positioning_context: &mut PositioningContext<'a>, + positioning_context: &mut PositioningContext, containing_block: &ContainingBlock, tree_rank: usize, ) -> FlowLayout { @@ -221,7 +222,7 @@ impl InlineFormattingContext { }, inline_position: Length::zero(), current_nesting_level: InlineNestingLevelState { - remaining_boxes: self.inline_level_boxes.iter(), + remaining_boxes: InlineBoxChildIter::from_formatting_context(self), fragments_so_far: Vec::with_capacity(self.inline_level_boxes.len()), inline_start: Length::zero(), max_block_size_of_fragments_so_far: Length::zero(), @@ -229,9 +230,9 @@ impl InlineFormattingContext { }; loop { if let Some(child) = ifc.current_nesting_level.remaining_boxes.next() { - match &**child { + match &*child.borrow() { InlineLevelBox::InlineBox(inline) => { - let partial = inline.start_layout(&mut ifc); + let partial = inline.start_layout(child.clone(), &mut ifc); ifc.partial_inline_boxes_stack.push(partial) }, InlineLevelBox::TextRun(run) => run.layout(layout_context, &mut ifc), @@ -256,7 +257,8 @@ impl InlineFormattingContext { panic!("display:none does not generate an abspos box") }, }; - let hoisted_fragment = box_.to_hoisted(initial_start_corner, tree_rank); + let hoisted_fragment = + box_.clone().to_hoisted(initial_start_corner, tree_rank); let hoisted_fragment_id = hoisted_fragment.fragment_id; ifc.positioning_context.push(hoisted_fragment); ifc.lines @@ -364,7 +366,8 @@ impl Lines { impl InlineBox { fn start_layout<'box_tree>( - &'box_tree self, + &self, + this_inline_level_box: ArcRefCell<InlineLevelBox>, ifc: &mut InlineFormattingContextState<'box_tree, '_, '_>, ) -> PartialInlineBoxFragment<'box_tree> { let style = self.style.clone(); @@ -400,7 +403,9 @@ impl InlineBox { parent_nesting_level: std::mem::replace( &mut ifc.current_nesting_level, InlineNestingLevelState { - remaining_boxes: self.children.iter(), + remaining_boxes: InlineBoxChildIter::from_inline_level_box( + this_inline_level_box, + ), fragments_so_far: Vec::with_capacity(self.children.len()), inline_start: ifc.inline_position, max_block_size_of_fragments_so_far: Length::zero(), @@ -460,10 +465,10 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> { } } -fn layout_atomic<'box_tree>( +fn layout_atomic( layout_context: &LayoutContext, - ifc: &mut InlineFormattingContextState<'box_tree, '_, '_>, - atomic: &'box_tree IndependentFormattingContext, + ifc: &mut InlineFormattingContextState, + atomic: &IndependentFormattingContext, ) { let cbis = ifc.containing_block.inline_size; let padding = atomic.style.padding().percentages_relative_to(cbis); @@ -758,3 +763,54 @@ impl TextRun { } } } + +enum InlineBoxChildIter<'box_tree> { + InlineFormattingContext(std::slice::Iter<'box_tree, ArcRefCell<InlineLevelBox>>), + InlineBox { + inline_level_box: ArcRefCell<InlineLevelBox>, + child_index: usize, + }, +} + +impl<'box_tree> InlineBoxChildIter<'box_tree> { + fn from_formatting_context( + inline_formatting_context: &'box_tree InlineFormattingContext, + ) -> InlineBoxChildIter<'box_tree> { + InlineBoxChildIter::InlineFormattingContext( + inline_formatting_context.inline_level_boxes.iter(), + ) + } + + fn from_inline_level_box( + inline_level_box: ArcRefCell<InlineLevelBox>, + ) -> InlineBoxChildIter<'box_tree> { + InlineBoxChildIter::InlineBox { + inline_level_box, + child_index: 0, + } + } +} + +impl<'box_tree> Iterator for InlineBoxChildIter<'box_tree> { + type Item = ArcRefCell<InlineLevelBox>; + fn next(&mut self) -> Option<ArcRefCell<InlineLevelBox>> { + match *self { + InlineBoxChildIter::InlineFormattingContext(ref mut iter) => iter.next().cloned(), + InlineBoxChildIter::InlineBox { + ref inline_level_box, + ref mut child_index, + } => match *inline_level_box.borrow() { + InlineLevelBox::InlineBox(ref inline_box) => { + if *child_index >= inline_box.children.len() { + return None; + } + + let kid = inline_box.children[*child_index].clone(); + *child_index += 1; + Some(kid) + }, + _ => unreachable!(), + }, + } + } +} diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index e15947f52b0..6aab3ba2be6 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -4,6 +4,7 @@ //! Flow layout, also known as block-and-inline layout. +use crate::cell::ArcRefCell; use crate::context::LayoutContext; use crate::flow::float::{FloatBox, FloatContext}; use crate::flow::inline::InlineFormattingContext; @@ -38,7 +39,7 @@ pub(crate) struct BlockFormattingContext { #[derive(Debug, Serialize)] pub(crate) enum BlockContainer { - BlockLevelBoxes(Vec<Arc<BlockLevelBox>>), + BlockLevelBoxes(Vec<ArcRefCell<BlockLevelBox>>), InlineFormattingContext(InlineFormattingContext), } @@ -50,7 +51,7 @@ pub(crate) enum BlockLevelBox { style: Arc<ComputedValues>, contents: BlockContainer, }, - OutOfFlowAbsolutelyPositionedBox(AbsolutelyPositionedBox), + OutOfFlowAbsolutelyPositionedBox(Arc<AbsolutelyPositionedBox>), OutOfFlowFloatBox(FloatBox), Independent(IndependentFormattingContext), } @@ -65,10 +66,10 @@ struct FlowLayout { struct CollapsibleWithParentStartMargin(bool); impl BlockFormattingContext { - pub(super) fn layout<'a>( - &'a self, + pub(super) fn layout( + &self, layout_context: &LayoutContext, - positioning_context: &mut PositioningContext<'a>, + positioning_context: &mut PositioningContext, containing_block: &ContainingBlock, tree_rank: usize, ) -> IndependentLayout { @@ -101,10 +102,10 @@ impl BlockFormattingContext { } impl BlockContainer { - fn layout<'a>( - &'a self, + fn layout( + &self, layout_context: &LayoutContext, - positioning_context: &mut PositioningContext<'a>, + positioning_context: &mut PositioningContext, containing_block: &ContainingBlock, tree_rank: usize, float_context: Option<&mut FloatContext>, @@ -130,10 +131,10 @@ impl BlockContainer { } } -fn layout_block_level_children<'a>( +fn layout_block_level_children( layout_context: &LayoutContext, - positioning_context: &mut PositioningContext<'a>, - child_boxes: &'a [Arc<BlockLevelBox>], + positioning_context: &mut PositioningContext, + child_boxes: &[ArcRefCell<BlockLevelBox>], containing_block: &ContainingBlock, tree_rank: usize, mut float_context: Option<&mut FloatContext>, @@ -204,7 +205,7 @@ fn layout_block_level_children<'a>( .iter() .enumerate() .map(|(tree_rank, box_)| { - let mut fragment = box_.layout( + let mut fragment = box_.borrow().layout( layout_context, positioning_context, containing_block, @@ -224,7 +225,7 @@ fn layout_block_level_children<'a>( .mapfold_reduce_into( positioning_context, |positioning_context, (tree_rank, box_)| { - box_.layout( + box_.borrow().layout( layout_context, positioning_context, containing_block, @@ -256,10 +257,10 @@ fn layout_block_level_children<'a>( } impl BlockLevelBox { - fn layout<'a>( - &'a self, + fn layout( + &self, layout_context: &LayoutContext, - positioning_context: &mut PositioningContext<'a>, + positioning_context: &mut PositioningContext, containing_block: &ContainingBlock, tree_rank: usize, float_context: Option<&mut FloatContext>, @@ -314,7 +315,7 @@ impl BlockLevelBox { )) }, BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => { - let hoisted_fragment = box_.to_hoisted(Vec2::zero(), tree_rank); + let hoisted_fragment = box_.clone().to_hoisted(Vec2::zero(), tree_rank); let hoisted_fragment_id = hoisted_fragment.fragment_id.clone(); positioning_context.push(hoisted_fragment); Fragment::AbsoluteOrFixedPositioned(AbsoluteOrFixedPositionedFragment( @@ -338,13 +339,13 @@ enum NonReplacedContents<'a> { /// https://drafts.csswg.org/css2/visudet.html#blockwidth /// https://drafts.csswg.org/css2/visudet.html#normal-block -fn layout_in_flow_non_replaced_block_level<'a>( +fn layout_in_flow_non_replaced_block_level( layout_context: &LayoutContext, - positioning_context: &mut PositioningContext<'a>, + positioning_context: &mut PositioningContext, containing_block: &ContainingBlock, tag: OpaqueNode, style: &Arc<ComputedValues>, - block_level_kind: NonReplacedContents<'a>, + block_level_kind: NonReplacedContents, tree_rank: usize, float_context: Option<&mut FloatContext>, ) -> BoxFragment { diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs index 0b93701b01b..6a8be578630 100644 --- a/components/layout_2020/flow/root.rs +++ b/components/layout_2020/flow/root.rs @@ -2,6 +2,7 @@ * 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 crate::cell::ArcRefCell; use crate::context::LayoutContext; use crate::display_list::stacking_context::{ ContainingBlock, ContainingBlockInfo, StackingContext, StackingContextBuildMode, @@ -62,7 +63,7 @@ impl BoxTreeRoot { fn construct_for_root_element<'dom>( context: &LayoutContext, root_element: impl NodeExt<'dom>, -) -> (ContainsFloats, Vec<Arc<BlockLevelBox>>) { +) -> (ContainsFloats, Vec<ArcRefCell<BlockLevelBox>>) { let style = root_element.style(context); let replaced = ReplacedContent::for_element(root_element); let box_style = style.get_box(); @@ -83,27 +84,29 @@ fn construct_for_root_element<'dom>( if box_style.position.is_absolutely_positioned() { ( ContainsFloats::No, - vec![Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox( - AbsolutelyPositionedBox::construct( - context, - root_element, - style, - display_inside, - contents, - ), - ))], + vec![ArcRefCell::new( + BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(Arc::new( + AbsolutelyPositionedBox::construct( + context, + root_element, + style, + display_inside, + contents, + ), + )), + )], ) } else if box_style.float.is_floating() { ( ContainsFloats::Yes, - vec![Arc::new(BlockLevelBox::OutOfFlowFloatBox( + vec![ArcRefCell::new(BlockLevelBox::OutOfFlowFloatBox( FloatBox::construct(context, root_element, style, display_inside, contents), ))], ) } else { ( ContainsFloats::No, - vec![Arc::new(BlockLevelBox::Independent( + vec![ArcRefCell::new(BlockLevelBox::Independent( IndependentFormattingContext::construct( context, root_element, diff --git a/components/layout_2020/formatting_contexts.rs b/components/layout_2020/formatting_contexts.rs index e4baf169476..100ef4a7c4b 100644 --- a/components/layout_2020/formatting_contexts.rs +++ b/components/layout_2020/formatting_contexts.rs @@ -104,11 +104,11 @@ impl IndependentFormattingContext { } } -impl<'a> NonReplacedIFC<'a> { +impl NonReplacedIFC<'_> { pub fn layout( &self, layout_context: &LayoutContext, - positioning_context: &mut PositioningContext<'a>, + positioning_context: &mut PositioningContext, containing_block: &ContainingBlock, tree_rank: usize, ) -> IndependentLayout { diff --git a/components/layout_2020/lib.rs b/components/layout_2020/lib.rs index 610c5306f53..3fc093399ee 100644 --- a/components/layout_2020/lib.rs +++ b/components/layout_2020/lib.rs @@ -3,6 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #![deny(unsafe_code)] +#![feature(arbitrary_self_types)] #![feature(exact_size_is_empty)] #[macro_use] @@ -10,6 +11,7 @@ extern crate log; #[macro_use] extern crate serde; +mod cell; pub mod context; pub mod data; pub mod display_list; diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index b40a3b8b1ab..b909ae2d471 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -36,19 +36,18 @@ pub(crate) struct AbsolutelyPositionedBox { pub contents: IndependentFormattingContext, } -pub(crate) struct PositioningContext<'box_tree> { - for_nearest_positioned_ancestor: Option<Vec<HoistedAbsolutelyPositionedBox<'box_tree>>>, +pub(crate) struct PositioningContext { + for_nearest_positioned_ancestor: Option<Vec<HoistedAbsolutelyPositionedBox>>, // For nearest `containing block for all descendants` as defined by the CSS transforms // spec. // https://www.w3.org/TR/css-transforms-1/#containing-block-for-all-descendants - for_nearest_containing_block_for_all_descendants: - Vec<HoistedAbsolutelyPositionedBox<'box_tree>>, + for_nearest_containing_block_for_all_descendants: Vec<HoistedAbsolutelyPositionedBox>, } #[derive(Debug)] -pub(crate) struct HoistedAbsolutelyPositionedBox<'box_tree> { - absolutely_positioned_box: &'box_tree AbsolutelyPositionedBox, +pub(crate) struct HoistedAbsolutelyPositionedBox { + absolutely_positioned_box: Arc<AbsolutelyPositionedBox>, /// The rank of the child from which this absolutely positioned fragment /// came from, when doing the layout of a block container. Used to compute @@ -110,7 +109,7 @@ impl AbsolutelyPositionedBox { } pub(crate) fn to_hoisted( - &self, + self: Arc<Self>, initial_start_corner: Vec2<Length>, tree_rank: usize, ) -> HoistedAbsolutelyPositionedBox { @@ -150,7 +149,7 @@ impl AbsolutelyPositionedBox { } } -impl<'box_tree> PositioningContext<'box_tree> { +impl PositioningContext { pub(crate) fn new_for_containing_block_for_all_descendants() -> Self { Self { for_nearest_positioned_ancestor: None, @@ -220,9 +219,7 @@ impl<'box_tree> PositioningContext<'box_tree> { fn create_and_layout_positioned( layout_context: &LayoutContext, style: &ComputedValues, - for_nearest_containing_block_for_all_descendants: &mut Vec< - HoistedAbsolutelyPositionedBox<'box_tree>, - >, + for_nearest_containing_block_for_all_descendants: &mut Vec<HoistedAbsolutelyPositionedBox>, fragment_layout_fn: impl FnOnce(&mut Self) -> BoxFragment, ) -> BoxFragment { if style.establishes_containing_block_for_all_descendants() { @@ -296,7 +293,7 @@ impl<'box_tree> PositioningContext<'box_tree> { new_fragment } - pub(crate) fn push(&mut self, box_: HoistedAbsolutelyPositionedBox<'box_tree>) { + pub(crate) fn push(&mut self, box_: HoistedAbsolutelyPositionedBox) { if let Some(nearest) = &mut self.for_nearest_positioned_ancestor { match box_ .absolutely_positioned_box @@ -412,14 +409,12 @@ impl<'box_tree> PositioningContext<'box_tree> { } } -impl<'box_tree> HoistedAbsolutelyPositionedBox<'box_tree> { +impl HoistedAbsolutelyPositionedBox { pub(crate) fn layout_many( layout_context: &LayoutContext, boxes: &[Self], fragments: &mut Vec<Fragment>, - for_nearest_containing_block_for_all_descendants: &mut Vec< - HoistedAbsolutelyPositionedBox<'box_tree>, - >, + for_nearest_containing_block_for_all_descendants: &mut Vec<HoistedAbsolutelyPositionedBox>, containing_block: &DefiniteContainingBlock, ) { if layout_context.use_rayon { @@ -449,9 +444,7 @@ impl<'box_tree> HoistedAbsolutelyPositionedBox<'box_tree> { pub(crate) fn layout( &self, layout_context: &LayoutContext, - for_nearest_containing_block_for_all_descendants: &mut Vec< - HoistedAbsolutelyPositionedBox<'box_tree>, - >, + for_nearest_containing_block_for_all_descendants: &mut Vec<HoistedAbsolutelyPositionedBox>, containing_block: &DefiniteContainingBlock, ) -> BoxFragment { let style = &self.absolutely_positioned_box.contents.style; |