diff options
Diffstat (limited to 'components/layout_2020/flow/construct.rs')
-rw-r--r-- | components/layout_2020/flow/construct.rs | 352 |
1 files changed, 196 insertions, 156 deletions
diff --git a/components/layout_2020/flow/construct.rs b/components/layout_2020/flow/construct.rs index 4acfc93ce92..de590c950d4 100644 --- a/components/layout_2020/flow/construct.rs +++ b/components/layout_2020/flow/construct.rs @@ -1,10 +1,27 @@ -use super::*; +/* 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 crate::dom_traversal::{BoxSlot, Contents, NodeExt, NonReplacedContents, TraversalHandler}; +use crate::element_data::LayoutBox; +use crate::flow::float::FloatBox; +use crate::flow::inline::{InlineBox, InlineFormattingContext, InlineLevelBox, TextRun}; +use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox}; +use crate::positioned::AbsolutelyPositionedBox; +use crate::style_ext::{DisplayGeneratingBox, DisplayInside, DisplayOutside}; +use crate::IndependentFormattingContext; +use rayon::iter::{IntoParallelIterator, ParallelIterator}; +use rayon_croissant::ParallelIteratorExt; +use servo_arc::Arc; +use std::convert::TryInto; +use style::context::SharedStyleContext; +use style::properties::ComputedValues; impl BlockFormattingContext { - pub fn construct<'a>( - context: &'a Context<'a>, - style: &'a Arc<ComputedValues>, - contents: NonReplacedContents, + pub fn construct<'dom>( + context: &SharedStyleContext<'_>, + style: &Arc<ComputedValues>, + contents: NonReplacedContents<impl NodeExt<'dom>>, ) -> Self { let (contents, contains_floats) = BlockContainer::construct(context, style, contents); Self { @@ -14,25 +31,25 @@ impl BlockFormattingContext { } } -enum IntermediateBlockLevelBox { +enum IntermediateBlockLevelBox<Node> { SameFormattingContextBlock { style: Arc<ComputedValues>, - contents: IntermediateBlockContainer, + contents: IntermediateBlockContainer<Node>, }, Independent { style: Arc<ComputedValues>, display_inside: DisplayInside, - contents: Contents, + contents: Contents<Node>, }, OutOfFlowAbsolutelyPositionedBox { style: Arc<ComputedValues>, display_inside: DisplayInside, - contents: Contents, + contents: Contents<Node>, }, OutOfFlowFloatBox { style: Arc<ComputedValues>, display_inside: DisplayInside, - contents: Contents, + contents: Contents<Node>, }, } @@ -43,18 +60,19 @@ enum IntermediateBlockLevelBox { /// of a given element. /// /// Deferring allows using rayon’s `into_par_iter`. -enum IntermediateBlockContainer { +enum IntermediateBlockContainer<Node> { InlineFormattingContext(InlineFormattingContext), - Deferred { contents: NonReplacedContents }, + Deferred { contents: NonReplacedContents<Node> }, } /// A builder for a block container. /// /// This builder starts from the first child of a given DOM node /// and does a preorder traversal of all of its inclusive siblings. -struct BlockContainerBuilder<'a> { - context: &'a Context<'a>, - block_container_style: &'a Arc<ComputedValues>, +struct BlockContainerBuilder<'dom, 'style, Node> { + context: &'style SharedStyleContext<'style>, + + block_container_style: &'style Arc<ComputedValues>, /// The list of block-level boxes of the final block container. /// @@ -69,7 +87,7 @@ struct BlockContainerBuilder<'a> { /// doesn't have a next sibling, we either reached the end of the container /// root or there are ongoing inline-level boxes /// (see `handle_block_level_element`). - block_level_boxes: Vec<(IntermediateBlockLevelBox, BoxSlot<'a>)>, + block_level_boxes: Vec<(IntermediateBlockLevelBox<Node>, BoxSlot<'dom>)>, /// The ongoing inline formatting context of the builder. /// @@ -104,10 +122,10 @@ struct BlockContainerBuilder<'a> { } impl BlockContainer { - pub fn construct<'a>( - context: &'a Context<'a>, - block_container_style: &'a Arc<ComputedValues>, - contents: NonReplacedContents, + pub fn construct<'dom, 'style>( + context: &SharedStyleContext<'style>, + block_container_style: &Arc<ComputedValues>, + contents: NonReplacedContents<impl NodeExt<'dom>>, ) -> (BlockContainer, ContainsFloats) { let mut builder = BlockContainerBuilder { context, @@ -134,7 +152,8 @@ impl BlockContainer { ); return (container, builder.contains_floats); } - builder.end_ongoing_inline_formatting_context(); + // FIXME + // builder.end_ongoing_inline_formatting_context(); } let mut contains_floats = builder.contains_floats; @@ -144,10 +163,11 @@ impl BlockContainer { .into_par_iter() .mapfold_reduce_into( &mut contains_floats, - |contains_floats, (intermediate, box_slot)| { + |contains_floats, (intermediate, box_slot): (IntermediateBlockLevelBox<_>, BoxSlot<'_>)| { let (block_level_box, box_contains_floats) = intermediate.finish(context); *contains_floats |= box_contains_floats; - box_slot.set(LayoutBox::BlockLevel(block_level_box.clone())); + // FIXME + // box_slot.set(LayoutBox::BlockLevel(block_level_box.clone())); block_level_box }, |left, right| *left |= right, @@ -158,13 +178,16 @@ impl BlockContainer { } } -impl<'a> TraversalHandler<'a> for BlockContainerBuilder<'a> { +impl<'dom, Node> TraversalHandler<Node> for BlockContainerBuilder<'dom, '_, Node> +where + Node: NodeExt<'dom>, +{ fn handle_element( &mut self, style: &Arc<ComputedValues>, display: DisplayGeneratingBox, - contents: Contents, - box_slot: BoxSlot<'a>, + contents: Contents<Node>, + box_slot: BoxSlot, ) { match display { DisplayGeneratingBox::OutsideInside { outside, inside } => match outside { @@ -172,27 +195,29 @@ impl<'a> TraversalHandler<'a> for BlockContainerBuilder<'a> { self.handle_inline_level_element(style, inside, contents), )), DisplayOutside::Block => { + // FIXME // Floats and abspos cause blockification, so they only happen in this case. // https://drafts.csswg.org/css2/visuren.html#dis-pos-flo - if style.box_.position.is_absolutely_positioned() { - self.handle_absolutely_positioned_element( - style.clone(), - inside, - contents, - box_slot, - ) - } else if style.box_.float.is_floating() { - self.handle_float_element(style.clone(), inside, contents, box_slot) - } else { - self.handle_block_level_element(style.clone(), inside, contents, box_slot) - } - } + // if style.box_.position.is_absolutely_positioned() { + // self.handle_absolutely_positioned_element( + // style.clone(), + // inside, + // contents, + // box_slot, + // ) + // } else if style.box_.float.is_floating() { + // self.handle_float_element(style.clone(), inside, contents, box_slot) + // } else { + // self.handle_block_level_element(style.clone(), inside, contents, box_slot) + // } + }, + DisplayOutside::None => panic!(":("), }, } } - fn handle_text(&mut self, input: &str, parent_style: &Arc<ComputedValues>) { - let (leading_whitespace, mut input) = self.handle_leading_whitespace(input); + fn handle_text(&mut self, input: String, parent_style: &Arc<ComputedValues>) { + let (leading_whitespace, mut input) = self.handle_leading_whitespace(&input); if leading_whitespace || !input.is_empty() { // This text node should be pushed either to the next ongoing // inline level box with the parent style of that inline level box @@ -256,7 +281,10 @@ impl<'a> TraversalHandler<'a> for BlockContainerBuilder<'a> { } } -impl<'a> BlockContainerBuilder<'a> { +impl<'dom, Node> BlockContainerBuilder<'dom, '_, Node> +where + Node: NodeExt<'dom>, +{ /// Returns: /// /// * Whether this text run has preserved (non-collapsible) leading whitespace @@ -273,19 +301,19 @@ impl<'a> BlockContainerBuilder<'a> { 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::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 text = text.trim_start_matches(|c: char| c.is_ascii_whitespace()); @@ -296,7 +324,7 @@ impl<'a> BlockContainerBuilder<'a> { &mut self, style: &Arc<ComputedValues>, display_inside: DisplayInside, - contents: Contents, + contents: Contents<Node>, ) -> Arc<InlineLevelBox> { let box_ = match contents.try_into() { Err(replaced) => Arc::new(InlineLevelBox::Atomic { @@ -322,97 +350,99 @@ impl<'a> BlockContainerBuilder<'a> { .expect("no ongoing inline level box found"); inline_box.last_fragment = true; Arc::new(InlineLevelBox::InlineBox(inline_box)) - } + }, DisplayInside::FlowRoot => { // a.k.a. `inline-block` unimplemented!() - } + }, + DisplayInside::None | DisplayInside::Contents => panic!(":("), }, }; self.current_inline_level_boxes().push(box_.clone()); box_ } - fn handle_block_level_element( - &mut self, - style: Arc<ComputedValues>, - display_inside: DisplayInside, - contents: Contents, - box_slot: BoxSlot<'a>, - ) { - // We just found a block level element, all ongoing inline level boxes - // need to be split around it. We iterate on the fragmented inline - // level box stack to take their contents and set their first_fragment - // field to false, for the fragmented inline level boxes that will - // come after the block level element. - let mut fragmented_inline_boxes = - self.ongoing_inline_boxes_stack - .iter_mut() - .rev() - .map(|ongoing| { - let fragmented = InlineBox { - style: ongoing.style.clone(), - first_fragment: ongoing.first_fragment, - // The fragmented boxes before the block level element - // are obviously not the last fragment. - last_fragment: false, - children: take(&mut ongoing.children), - }; - ongoing.first_fragment = false; - fragmented - }); - - if let Some(last) = fragmented_inline_boxes.next() { - // There were indeed some ongoing inline level boxes before - // the block, we accumulate them as a single inline level box - // to be pushed to the ongoing inline formatting context. - let mut fragmented_inline = InlineLevelBox::InlineBox(last); - for mut fragmented_parent_inline_box in fragmented_inline_boxes { - fragmented_parent_inline_box - .children - .push(Arc::new(fragmented_inline)); - fragmented_inline = InlineLevelBox::InlineBox(fragmented_parent_inline_box); - } - - self.ongoing_inline_formatting_context - .inline_level_boxes - .push(Arc::new(fragmented_inline)); - } - - // We found a block level element, so the ongoing inline formatting - // context needs to be ended. - self.end_ongoing_inline_formatting_context(); - - let intermediate_box = match contents.try_into() { - Ok(contents) => match display_inside { - DisplayInside::Flow => IntermediateBlockLevelBox::SameFormattingContextBlock { - style, - contents: IntermediateBlockContainer::Deferred { contents }, - }, - _ => IntermediateBlockLevelBox::Independent { - style, - display_inside, - contents: contents.into(), - }, - }, - Err(contents) => { - let contents = Contents::Replaced(contents); - IntermediateBlockLevelBox::Independent { - style, - display_inside, - contents, - } - } - }; - self.block_level_boxes.push((intermediate_box, box_slot)) - } + // FIXME + // fn handle_block_level_element( + // &mut self, + // style: Arc<ComputedValues>, + // display_inside: DisplayInside, + // contents: Contents, + // box_slot: BoxSlot<'a>, + // ) { + // // We just found a block level element, all ongoing inline level boxes + // // need to be split around it. We iterate on the fragmented inline + // // level box stack to take their contents and set their first_fragment + // // field to false, for the fragmented inline level boxes that will + // // come after the block level element. + // let mut fragmented_inline_boxes = + // self.ongoing_inline_boxes_stack + // .iter_mut() + // .rev() + // .map(|ongoing| { + // let fragmented = InlineBox { + // style: ongoing.style.clone(), + // first_fragment: ongoing.first_fragment, + // // The fragmented boxes before the block level element + // // are obviously not the last fragment. + // last_fragment: false, + // children: take(&mut ongoing.children), + // }; + // ongoing.first_fragment = false; + // fragmented + // }); + + // if let Some(last) = fragmented_inline_boxes.next() { + // // There were indeed some ongoing inline level boxes before + // // the block, we accumulate them as a single inline level box + // // to be pushed to the ongoing inline formatting context. + // let mut fragmented_inline = InlineLevelBox::InlineBox(last); + // for mut fragmented_parent_inline_box in fragmented_inline_boxes { + // fragmented_parent_inline_box + // .children + // .push(Arc::new(fragmented_inline)); + // fragmented_inline = InlineLevelBox::InlineBox(fragmented_parent_inline_box); + // } + + // self.ongoing_inline_formatting_context + // .inline_level_boxes + // .push(Arc::new(fragmented_inline)); + // } + + // // We found a block level element, so the ongoing inline formatting + // // context needs to be ended. + // self.end_ongoing_inline_formatting_context(); + + // let intermediate_box = match contents.try_into() { + // Ok(contents) => match display_inside { + // DisplayInside::Flow => IntermediateBlockLevelBox::SameFormattingContextBlock { + // style, + // contents: IntermediateBlockContainer::Deferred { contents }, + // }, + // _ => IntermediateBlockLevelBox::Independent { + // style, + // display_inside, + // contents: contents.into(), + // }, + // }, + // Err(contents) => { + // let contents = Contents::Replaced(contents); + // IntermediateBlockLevelBox::Independent { + // style, + // display_inside, + // contents, + // } + // } + // }; + // self.block_level_boxes.push((intermediate_box, box_slot)) + // } fn handle_absolutely_positioned_element( &mut self, style: Arc<ComputedValues>, display_inside: DisplayInside, - contents: Contents, - box_slot: BoxSlot<'a>, + contents: Contents<Node>, + box_slot: BoxSlot<'dom>, ) { if !self.has_ongoing_inline_formatting_context() { let box_ = IntermediateBlockLevelBox::OutOfFlowAbsolutelyPositionedBox { @@ -420,12 +450,12 @@ impl<'a> BlockContainerBuilder<'a> { contents, display_inside, }; - self.block_level_boxes.push((box_, box_slot)) + self.block_level_boxes.push((box_, box_slot)); } else { let box_ = Arc::new(InlineLevelBox::OutOfFlowAbsolutelyPositionedBox( AbsolutelyPositionedBox { contents: IndependentFormattingContext::construct( - self.context, + unimplemented!(), &style, display_inside, contents, @@ -442,8 +472,8 @@ impl<'a> BlockContainerBuilder<'a> { &mut self, style: Arc<ComputedValues>, display_inside: DisplayInside, - contents: Contents, - box_slot: BoxSlot<'a>, + contents: Contents<Node>, + box_slot: BoxSlot<'dom>, ) { self.contains_floats = ContainsFloats::Yes; @@ -485,20 +515,21 @@ impl<'a> BlockContainerBuilder<'a> { } let block_container_style = self.block_container_style; - let anonymous_style = self.anonymous_style.get_or_insert_with(|| { - // If parent_style is None, the parent is the document node, - // in which case anonymous inline boxes should inherit their - // styles from initial values. - ComputedValues::anonymous_inheriting_from(Some(block_container_style)) - }); - - let box_ = IntermediateBlockLevelBox::SameFormattingContextBlock { - style: anonymous_style.clone(), - contents: IntermediateBlockContainer::InlineFormattingContext(take( - &mut self.ongoing_inline_formatting_context, - )), - }; - self.block_level_boxes.push((box_, BoxSlot::dummy())) + // FIXME + // let anonymous_style = self.anonymous_style.get_or_insert_with(|| { + // // If parent_style is None, the parent is the document node, + // // in which case anonymous inline boxes should inherit their + // // styles from initial values. + // ComputedValues::anonymous_inheriting_from(Some(block_container_style)) + // }); + + // let box_ = IntermediateBlockLevelBox::SameFormattingContextBlock { + // style: anonymous_style.clone(), + // contents: IntermediateBlockContainer::InlineFormattingContext(take( + // &mut self.ongoing_inline_formatting_context, + // )), + // }; + // self.block_level_boxes.push((box_, BoxSlot::dummy())) } fn current_inline_level_boxes(&mut self) -> &mut Vec<Arc<InlineLevelBox>> { @@ -512,20 +543,26 @@ impl<'a> BlockContainerBuilder<'a> { !self .ongoing_inline_formatting_context .inline_level_boxes - .is_empty() - || !self.ongoing_inline_boxes_stack.is_empty() + .is_empty() || + !self.ongoing_inline_boxes_stack.is_empty() } } -impl IntermediateBlockLevelBox { - fn finish(self, context: &Context) -> (Arc<BlockLevelBox>, ContainsFloats) { +impl<'dom, Node> IntermediateBlockLevelBox<Node> +where + Node: NodeExt<'dom>, +{ + fn finish<'style>( + self, + context: &SharedStyleContext<'style>, + ) -> (Arc<BlockLevelBox>, ContainsFloats) { match self { IntermediateBlockLevelBox::SameFormattingContextBlock { style, contents } => { let (contents, contains_floats) = contents.finish(context, &style); let block_level_box = Arc::new(BlockLevelBox::SameFormattingContextBlock { contents, style }); (block_level_box, contains_floats) - } + }, IntermediateBlockLevelBox::Independent { style, display_inside, @@ -541,7 +578,7 @@ impl IntermediateBlockLevelBox { Arc::new(BlockLevelBox::Independent { style, contents }), ContainsFloats::No, ) - } + }, IntermediateBlockLevelBox::OutOfFlowAbsolutelyPositionedBox { style, display_inside, @@ -559,7 +596,7 @@ impl IntermediateBlockLevelBox { }, )); (block_level_box, ContainsFloats::No) - } + }, IntermediateBlockLevelBox::OutOfFlowFloatBox { style, display_inside, @@ -576,21 +613,24 @@ impl IntermediateBlockLevelBox { style, })); (block_level_box, ContainsFloats::Yes) - } + }, } } } -impl IntermediateBlockContainer { - fn finish( +impl<'dom, Node> IntermediateBlockContainer<Node> +where + Node: NodeExt<'dom>, +{ + fn finish<'style>( self, - context: &Context, + context: &SharedStyleContext<'style>, style: &Arc<ComputedValues>, ) -> (BlockContainer, ContainsFloats) { match self { IntermediateBlockContainer::Deferred { contents } => { BlockContainer::construct(context, style, contents) - } + }, IntermediateBlockContainer::InlineFormattingContext(ifc) => { // If that inline formatting context contained any float, those // were already taken into account during the first phase of @@ -599,13 +639,13 @@ impl IntermediateBlockContainer { BlockContainer::InlineFormattingContext(ifc), ContainsFloats::No, ) - } + }, } } } #[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub(in crate::layout) enum ContainsFloats { +pub(crate) enum ContainsFloats { No, Yes, } |