From 7ade924683c22f1f990c4b9fa09ef1b38dc6b027 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 13 Mar 2020 11:15:45 +0100 Subject: [PATCH 1/8] Update atomic_refcell Required for Debug impl on AtomicRefCell. --- Cargo.lock | 4 ++-- components/layout_2020/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 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"} From c3932185ec649c3063096ca0c545b62c3ddbfd5b Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 13 Mar 2020 12:22:32 +0100 Subject: [PATCH 2/8] Make AbsolutelyPositionedBox be 'static --- components/layout_2020/flow/construct.rs | 8 ++--- components/layout_2020/flow/inline.rs | 10 +++--- components/layout_2020/flow/mod.rs | 32 +++++++++---------- components/layout_2020/flow/root.rs | 4 +-- components/layout_2020/formatting_contexts.rs | 4 +-- components/layout_2020/lib.rs | 1 + components/layout_2020/positioned.rs | 31 +++++++----------- 7 files changed, 42 insertions(+), 48 deletions(-) diff --git a/components/layout_2020/flow/construct.rs b/components/layout_2020/flow/construct.rs index cff3fa281a6..6eee3675a8e 100644 --- a/components/layout_2020/flow/construct.rs +++ b/components/layout_2020/flow/construct.rs @@ -525,7 +525,7 @@ where kind, }); } else { - let box_ = Arc::new(InlineLevelBox::OutOfFlowAbsolutelyPositionedBox( + let box_ = Arc::new(InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(Arc::new( AbsolutelyPositionedBox::construct( self.context, node, @@ -533,7 +533,7 @@ where display_inside, contents, ), - )); + ))); self.current_inline_level_boxes().push(box_.clone()); box_slot.set(LayoutBox::InlineLevel(box_)) } @@ -687,13 +687,13 @@ where contents, } => { let block_level_box = Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox( - AbsolutelyPositionedBox::construct( + Arc::new(AbsolutelyPositionedBox::construct( context, node, style, display_inside, contents, - ), + )), )); (block_level_box, ContainsFloats::No) }, diff --git a/components/layout_2020/flow/inline.rs b/components/layout_2020/flow/inline.rs index bd8f5bc784f..8e1587568c0 100644 --- a/components/layout_2020/flow/inline.rs +++ b/components/layout_2020/flow/inline.rs @@ -34,7 +34,7 @@ pub(crate) struct InlineFormattingContext { pub(crate) enum InlineLevelBox { InlineBox(InlineBox), TextRun(TextRun), - OutOfFlowAbsolutelyPositionedBox(AbsolutelyPositionedBox), + OutOfFlowAbsolutelyPositionedBox(Arc), OutOfFlowFloatBox(FloatBox), Atomic(IndependentFormattingContext), } @@ -77,7 +77,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, @@ -204,10 +204,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 { diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index e15947f52b0..1f6d6db49df 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -50,7 +50,7 @@ pub(crate) enum BlockLevelBox { style: Arc, contents: BlockContainer, }, - OutOfFlowAbsolutelyPositionedBox(AbsolutelyPositionedBox), + OutOfFlowAbsolutelyPositionedBox(Arc), OutOfFlowFloatBox(FloatBox), Independent(IndependentFormattingContext), } @@ -65,10 +65,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 +101,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 +130,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], + positioning_context: &mut PositioningContext, + child_boxes: &[Arc], containing_block: &ContainingBlock, tree_rank: usize, mut float_context: Option<&mut FloatContext>, @@ -256,10 +256,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>, @@ -338,13 +338,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, - 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..63ca58ead1d 100644 --- a/components/layout_2020/flow/root.rs +++ b/components/layout_2020/flow/root.rs @@ -84,13 +84,13 @@ fn construct_for_root_element<'dom>( ( ContainsFloats::No, vec![Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox( - AbsolutelyPositionedBox::construct( + Arc::new(AbsolutelyPositionedBox::construct( context, root_element, style, display_inside, contents, - ), + )), ))], ) } else if box_style.float.is_floating() { 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..c7d260f0f89 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] 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>>, +pub(crate) struct PositioningContext { + for_nearest_positioned_ancestor: Option>, // 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>, + for_nearest_containing_block_for_all_descendants: Vec, } #[derive(Debug)] -pub(crate) struct HoistedAbsolutelyPositionedBox<'box_tree> { - absolutely_positioned_box: &'box_tree AbsolutelyPositionedBox, +pub(crate) struct HoistedAbsolutelyPositionedBox { + absolutely_positioned_box: Arc, /// 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, initial_start_corner: Vec2, 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, 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, - for_nearest_containing_block_for_all_descendants: &mut Vec< - HoistedAbsolutelyPositionedBox<'box_tree>, - >, + for_nearest_containing_block_for_all_descendants: &mut Vec, 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, containing_block: &DefiniteContainingBlock, ) -> BoxFragment { let style = &self.absolutely_positioned_box.contents.style; From 2ff776b241f847bff9053e08a8004b6c7edc48b0 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 13 Mar 2020 19:45:54 -0700 Subject: [PATCH 3/8] Add an `ArcRefCell` type --- components/layout_2020/cell.rs | 58 ++++++++++++++++++++++++++++++++++ components/layout_2020/lib.rs | 1 + 2 files changed, 59 insertions(+) create mode 100644 components/layout_2020/cell.rs diff --git a/components/layout_2020/cell.rs b/components/layout_2020/cell.rs new file mode 100644 index 00000000000..e12201e4b28 --- /dev/null +++ b/components/layout_2020/cell.rs @@ -0,0 +1,58 @@ +/* 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 { + value: Arc>, +} + +impl ArcRefCell { + pub fn new(value: T) -> Self { + Self { + value: Arc::new(AtomicRefCell::new(value)), + } + } +} + +impl Clone for ArcRefCell { + fn clone(&self) -> Self { + Self { + value: self.value.clone(), + } + } +} + +impl Deref for ArcRefCell { + type Target = AtomicRefCell; + + fn deref(&self) -> &Self::Target { + &self.value + } +} + +impl fmt::Debug for ArcRefCell +where + T: fmt::Debug, +{ + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + self.value.fmt(formatter) + } +} + +impl Serialize for ArcRefCell +where + T: Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.borrow().serialize(serializer) + } +} diff --git a/components/layout_2020/lib.rs b/components/layout_2020/lib.rs index c7d260f0f89..3fc093399ee 100644 --- a/components/layout_2020/lib.rs +++ b/components/layout_2020/lib.rs @@ -11,6 +11,7 @@ extern crate log; #[macro_use] extern crate serde; +mod cell; pub mod context; pub mod data; pub mod display_list; From 9cb824e77ca1cea699358971f7568e869c1c4664 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 13 Mar 2020 19:47:00 -0700 Subject: [PATCH 4/8] Wrap `BlockLevelBox` and `InlineLevelBox` with `AtomicRefCell` --- components/layout_2020/element_data.rs | 5 +- components/layout_2020/flow/construct.rs | 144 +++++++++++------------ components/layout_2020/flow/inline.rs | 13 +- components/layout_2020/flow/mod.rs | 9 +- components/layout_2020/flow/root.rs | 25 ++-- 5 files changed, 101 insertions(+), 95 deletions(-) diff --git a/components/layout_2020/element_data.rs b/components/layout_2020/element_data.rs index ccd48ac04e3..e8afab10bc7 100644 --- a/components/layout_2020/element_data.rs +++ b/components/layout_2020/element_data.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::flow::inline::InlineLevelBox; use crate::flow::BlockLevelBox; use atomic_refcell::AtomicRefCell; @@ -21,6 +22,6 @@ pub(super) struct PseudoElementBoxes { pub(super) enum LayoutBox { DisplayContents, - BlockLevel(Arc), - InlineLevel(Arc), + BlockLevel(ArcRefCell), + InlineLevel(ArcRefCell), } diff --git a/components/layout_2020/flow/construct.rs b/components/layout_2020/flow/construct.rs index 6eee3675a8e..89a54d08840 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]) -> 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, @@ -356,23 +351,27 @@ where 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)) => { + let inline_box = match inline_level_boxes.next() { + Some(box_) => box_, + None => match stack.pop() { + Some(iter) => { + inline_level_boxes = iter; + continue; + }, + None => break false, + }, + };{ + match &*inline_box.borrow() { + InlineLevelBox::TextRun(r) => break !r.text.ends_with(' '), + InlineLevelBox::Atomic { .. } => break false, + InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(_) | + InlineLevelBox::OutOfFlowFloatBox(_) => {}, + 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 text = text.trim_start_matches(|c: char| c.is_ascii_whitespace()); (preserved, text) @@ -384,7 +383,7 @@ where style: &Arc, display_inside: DisplayInside, contents: Contents, - ) -> Arc { + ) -> ArcRefCell { 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 +409,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 +465,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 +524,7 @@ where kind, }); } else { - let box_ = Arc::new(InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(Arc::new( + let box_ = ArcRefCell::new(InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(Arc::new( AbsolutelyPositionedBox::construct( self.context, node, @@ -561,7 +560,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 +609,7 @@ where }); } - fn current_inline_level_boxes(&mut self) -> &mut Vec> { + fn current_inline_level_boxes(&mut self) -> &mut Vec> { 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 +633,7 @@ where self, context: &LayoutContext, max_assign_in_flow_outer_content_sizes_to: Option<&mut ContentSizes>, - ) -> (Arc, ContainsFloats) { + ) -> (ArcRefCell, ContainsFloats) { let node = self.node; let style = self.style; let (block_level_box, contains_floats) = match self.kind { @@ -651,7 +650,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 +677,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 +685,23 @@ where display_inside, contents, } => { - let block_level_box = Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox( - Arc::new(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 8e1587568c0..0d1f2199597 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,7 +28,7 @@ use webrender_api::FontInstanceKey; #[derive(Debug, Default, Serialize)] pub(crate) struct InlineFormattingContext { - pub(super) inline_level_boxes: Vec>, + pub(super) inline_level_boxes: Vec>, } #[derive(Debug, Serialize)] @@ -46,7 +47,7 @@ pub(crate) struct InlineBox { pub style: Arc, pub first_fragment: bool, pub last_fragment: bool, - pub children: Vec>, + pub children: Vec>, } /// 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>, + remaining_boxes: std::slice::Iter<'box_tree, ArcRefCell>, fragments_so_far: Vec, inline_start: Length, max_block_size_of_fragments_so_far: Length, @@ -105,10 +106,10 @@ impl InlineFormattingContext { fn traverse( &mut self, layout_context: &LayoutContext, - inline_level_boxes: &[Arc], + inline_level_boxes: &[ArcRefCell], ) { 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(); @@ -229,7 +230,7 @@ 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); ifc.partial_inline_boxes_stack.push(partial) diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 1f6d6db49df..fa0ed0b7c00 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>), + BlockLevelBoxes(Vec>), InlineFormattingContext(InlineFormattingContext), } @@ -133,7 +134,7 @@ impl BlockContainer { fn layout_block_level_children( layout_context: &LayoutContext, positioning_context: &mut PositioningContext, - child_boxes: &[Arc], + child_boxes: &[ArcRefCell], containing_block: &ContainingBlock, tree_rank: usize, mut float_context: Option<&mut FloatContext>, @@ -204,7 +205,7 @@ fn layout_block_level_children( .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( .mapfold_reduce_into( positioning_context, |positioning_context, (tree_rank, box_)| { - box_.layout( + box_.borrow().layout( layout_context, positioning_context, containing_block, diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs index 63ca58ead1d..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>) { +) -> (ContainsFloats, Vec>) { 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( - Arc::new(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, From 5b3f27746529c746231d1d1ddef83b5c4e0b2160 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 13 Mar 2020 19:29:32 -0700 Subject: [PATCH 5/8] Implement `Default` for `ArcRefCell` --- components/layout_2020/cell.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/components/layout_2020/cell.rs b/components/layout_2020/cell.rs index e12201e4b28..8aae377b24c 100644 --- a/components/layout_2020/cell.rs +++ b/components/layout_2020/cell.rs @@ -28,6 +28,17 @@ impl Clone for ArcRefCell { } } +impl Default for ArcRefCell +where + T: Default, +{ + fn default() -> Self { + Self { + value: Arc::new(AtomicRefCell::new(Default::default())), + } + } +} + impl Deref for ArcRefCell { type Target = AtomicRefCell; From 1d9f669cf0b19de339692729b4c49971aa338147 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 13 Mar 2020 19:30:08 -0700 Subject: [PATCH 6/8] Switch some uses of `Arc>` over to `ArcRefCell` --- components/layout_2020/dom_traversal.rs | 7 ++++--- components/layout_2020/element_data.rs | 8 +++----- 2 files changed, 7 insertions(+), 8 deletions(-) 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>>>, + slot: Option>>, marker: marker<&'dom ()>, } impl BoxSlot<'_> { - pub(crate) fn new(slot: ServoArc>>) -> Self { + pub(crate) fn new(slot: ArcRefCell>) -> 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 e8afab10bc7..7385b7d84f0 100644 --- a/components/layout_2020/element_data.rs +++ b/components/layout_2020/element_data.rs @@ -5,19 +5,17 @@ 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>>, + pub(super) self_box: ArcRefCell>, pub(super) pseudo_elements: Option>, } #[derive(Default)] pub(super) struct PseudoElementBoxes { - pub before: Arc>>, - pub after: Arc>>, + pub before: ArcRefCell>, + pub after: ArcRefCell>, } pub(super) enum LayoutBox { From 42058681a5d04ca4203bac4fc8c60547a8fed2f8 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 13 Mar 2020 19:30:43 -0700 Subject: [PATCH 7/8] Switch the standard slice iterator in inline layout to a custom one in order to avoid lifetime problems --- components/layout_2020/flow/inline.rs | 73 +++++++++++++++++++++++---- components/layout_2020/flow/mod.rs | 2 +- 2 files changed, 65 insertions(+), 10 deletions(-) diff --git a/components/layout_2020/flow/inline.rs b/components/layout_2020/flow/inline.rs index 0d1f2199597..f71187e1118 100644 --- a/components/layout_2020/flow/inline.rs +++ b/components/layout_2020/flow/inline.rs @@ -60,7 +60,7 @@ pub(crate) struct TextRun { } struct InlineNestingLevelState<'box_tree> { - remaining_boxes: std::slice::Iter<'box_tree, ArcRefCell>, + remaining_boxes: InlineBoxChildIter<'box_tree>, fragments_so_far: Vec, inline_start: Length, max_block_size_of_fragments_so_far: Length, @@ -222,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(), @@ -232,7 +232,7 @@ impl InlineFormattingContext { if let Some(child) = ifc.current_nesting_level.remaining_boxes.next() { 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), @@ -257,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 @@ -365,7 +366,8 @@ impl Lines { impl InlineBox { fn start_layout<'box_tree>( - &'box_tree self, + &self, + this_inline_level_box: ArcRefCell, ifc: &mut InlineFormattingContextState<'box_tree, '_, '_>, ) -> PartialInlineBoxFragment<'box_tree> { let style = self.style.clone(); @@ -401,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(), @@ -461,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); @@ -759,3 +763,54 @@ impl TextRun { } } } + +enum InlineBoxChildIter<'box_tree> { + InlineFormattingContext(std::slice::Iter<'box_tree, ArcRefCell>), + InlineBox { + inline_level_box: ArcRefCell, + 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, + ) -> InlineBoxChildIter<'box_tree> { + InlineBoxChildIter::InlineBox { + inline_level_box, + child_index: 0, + } + } +} + +impl<'box_tree> Iterator for InlineBoxChildIter<'box_tree> { + type Item = ArcRefCell; + fn next(&mut self) -> Option> { + 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 fa0ed0b7c00..6aab3ba2be6 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -315,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( From 0d6c60f03ed6829dc02fc16fb3e43482f0ab1ae7 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 13 Mar 2020 19:32:24 -0700 Subject: [PATCH 8/8] Make whitespace preservation computation recursive in order to fix lifetime issues --- components/layout_2020/flow/construct.rs | 70 +++++++++++++++--------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/components/layout_2020/flow/construct.rs b/components/layout_2020/flow/construct.rs index 89a54d08840..0bf0b5c83ad 100644 --- a/components/layout_2020/flow/construct.rs +++ b/components/layout_2020/flow/construct.rs @@ -348,33 +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 { - let inline_box = match inline_level_boxes.next() { - Some(box_) => box_, - None => match stack.pop() { - Some(iter) => { - inline_level_boxes = iter; - continue; - }, - None => break false, - }, - };{ - match &*inline_box.borrow() { - InlineLevelBox::TextRun(r) => break !r.text.ends_with(' '), - InlineLevelBox::Atomic { .. } => break false, - InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(_) | - InlineLevelBox::OutOfFlowFloatBox(_) => {}, - InlineLevelBox::InlineBox(b) => { - stack.push(inline_level_boxes); - inline_level_boxes = b.children.iter().rev() - }, - };} - () + + 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], + ) -> 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(