diff options
Diffstat (limited to 'components/layout_2020/flow')
-rw-r--r-- | components/layout_2020/flow/construct.rs | 352 | ||||
-rw-r--r-- | components/layout_2020/flow/float.rs | 12 | ||||
-rw-r--r-- | components/layout_2020/flow/inline.rs | 160 | ||||
-rw-r--r-- | components/layout_2020/flow/mod.rs | 113 | ||||
-rw-r--r-- | components/layout_2020/flow/root.rs | 227 |
5 files changed, 437 insertions, 427 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, } diff --git a/components/layout_2020/flow/float.rs b/components/layout_2020/flow/float.rs index 1c06b5cf2da..31fec0b79c0 100644 --- a/components/layout_2020/flow/float.rs +++ b/components/layout_2020/flow/float.rs @@ -1,13 +1,19 @@ -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::IndependentFormattingContext; +use servo_arc::Arc; +use style::properties::ComputedValues; #[derive(Debug)] -pub(in crate::layout) struct FloatBox { +pub(crate) struct FloatBox { pub style: Arc<ComputedValues>, pub contents: IndependentFormattingContext, } /// Data kept during layout about the floats in a given block formatting context. -pub(in crate::layout) struct FloatContext { +pub(crate) struct FloatContext { // TODO } diff --git a/components/layout_2020/flow/inline.rs b/components/layout_2020/flow/inline.rs index 5c39bb9385b..59b822976ca 100644 --- a/components/layout_2020/flow/inline.rs +++ b/components/layout_2020/flow/inline.rs @@ -1,14 +1,27 @@ -use super::*; -use crate::fonts::BITSTREAM_VERA_SANS; -use crate::text::ShapedSegment; +/* 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::flow::float::FloatBox; +use crate::flow::FlowChildren; +use crate::fragments::{AnonymousFragment, BoxFragment, CollapsedBlockMargins, Fragment}; +use crate::geom::flow_relative::{Rect, Sides, Vec2}; +use crate::positioned::{AbsolutelyPositionedBox, AbsolutelyPositionedFragment}; +use crate::replaced::ReplacedContent; +use crate::style_ext::{ComputedValuesExt, Display, DisplayGeneratingBox, DisplayOutside}; +use crate::{relative_adjustement, take, ContainingBlock}; +use servo_arc::Arc; +use style::properties::ComputedValues; +use style::values::computed::Length; +use style::Zero; #[derive(Debug, Default)] -pub(in crate::layout) struct InlineFormattingContext { +pub(crate) struct InlineFormattingContext { pub(super) inline_level_boxes: Vec<Arc<InlineLevelBox>>, } #[derive(Debug)] -pub(in crate::layout) enum InlineLevelBox { +pub(crate) enum InlineLevelBox { InlineBox(InlineBox), TextRun(TextRun), OutOfFlowAbsolutelyPositionedBox(AbsolutelyPositionedBox), @@ -21,7 +34,7 @@ pub(in crate::layout) enum InlineLevelBox { } #[derive(Debug)] -pub(in crate::layout) struct InlineBox { +pub(crate) struct InlineBox { pub style: Arc<ComputedValues>, pub first_fragment: bool, pub last_fragment: bool, @@ -30,7 +43,7 @@ pub(in crate::layout) struct InlineBox { /// https://www.w3.org/TR/css-display-3/#css-text-run #[derive(Debug)] -pub(in crate::layout) struct TextRun { +pub(crate) struct TextRun { pub parent_style: Arc<ComputedValues>, pub text: String, } @@ -93,36 +106,40 @@ impl InlineFormattingContext { InlineLevelBox::InlineBox(inline) => { let partial = inline.start_layout(&mut ifc); ifc.partial_inline_boxes_stack.push(partial) - } + }, InlineLevelBox::TextRun(run) => run.layout(&mut ifc), InlineLevelBox::Atomic { style: _, contents } => { // FIXME match *contents {} - } + }, InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => { - let initial_start_corner = match box_.style.specified_display { - Display::GeneratingBox(DisplayGeneratingBox::OutsideInside { - outside, - inside: _, - }) => Vec2 { - inline: match outside { - DisplayOutside::Inline => ifc.inline_position, - DisplayOutside::Block => Length::zero(), + let initial_start_corner = + match Display::from(box_.style.get_box().original_display) { + Display::GeneratingBox(DisplayGeneratingBox::OutsideInside { + outside, + inside: _, + }) => Vec2 { + inline: match outside { + DisplayOutside::Inline => ifc.inline_position, + DisplayOutside::Block => Length::zero(), + DisplayOutside::None => unreachable!(":("), + }, + block: ifc.line_boxes.next_line_block_position, + }, + Display::Contents => { + panic!("display:contents does not generate an abspos box") }, - block: ifc.line_boxes.next_line_block_position, - }, - Display::Contents => { - panic!("display:contents does not generate an abspos box") - } - Display::None => panic!("display:none does not generate an abspos box"), - }; + Display::None => { + panic!("display:none does not generate an abspos box") + }, + }; absolutely_positioned_fragments .push(box_.layout(initial_start_corner, tree_rank)); - } + }, InlineLevelBox::OutOfFlowFloatBox(_box_) => { // TODO continue; - } + }, } } else // Reached the end of ifc.remaining_boxes @@ -180,7 +197,7 @@ impl InlineBox { let style = self.style.clone(); let cbis = ifc.containing_block.inline_size; let mut padding = style.padding().percentages_relative_to(cbis); - let mut border = style.border_width().percentages_relative_to(cbis); + let mut border = style.border_width(); let mut margin = style .margin() .percentages_relative_to(cbis) @@ -245,9 +262,9 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> { }; let last_fragment = self.last_box_tree_fragment && !at_line_break; if last_fragment { - *inline_position += fragment.padding.inline_end - + fragment.border.inline_end - + fragment.margin.inline_end; + *inline_position += fragment.padding.inline_end + + fragment.border.inline_end + + fragment.margin.inline_end; } else { fragment.padding.inline_end = Length::zero(); fragment.border.inline_end = Length::zero(); @@ -256,10 +273,10 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> { self.parent_nesting_level .max_block_size_of_fragments_so_far .max_assign( - fragment.content_rect.size.block - + fragment.padding.block_sum() - + fragment.border.block_sum() - + fragment.margin.block_sum(), + fragment.content_rect.size.block + + fragment.padding.block_sum() + + fragment.border.block_sum() + + fragment.margin.block_sum(), ); self.parent_nesting_level .fragments_so_far @@ -268,78 +285,7 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> { } impl TextRun { - fn layout(&self, ifc: &mut InlineFormattingContextState) { - let available = ifc.containing_block.inline_size - ifc.inline_position; - let mut chars = self.text.chars(); - loop { - let mut shaped = ShapedSegment::new_with_naive_shaping(BITSTREAM_VERA_SANS.clone()); - let mut last_break_opportunity = None; - loop { - let next = chars.next(); - if matches!(next, Some(' ') | None) { - let inline_size = self.parent_style.font.font_size * shaped.advance_width; - if inline_size > available { - if let Some((state, iter)) = last_break_opportunity.take() { - shaped.restore(&state); - chars = iter; - } - break; - } - } - if let Some(ch) = next { - if ch == ' ' { - last_break_opportunity = Some((shaped.save(), chars.clone())) - } - shaped.append_char(ch).unwrap() - } else { - break; - } - } - let inline_size = self.parent_style.font.font_size * shaped.advance_width; - // https://www.w3.org/TR/CSS2/visudet.html#propdef-line-height - // 'normal': - // “set the used value to a "reasonable" value based on the font of the element.” - let line_height = self.parent_style.font.font_size.0 * 1.2; - let content_rect = Rect { - start_corner: Vec2 { - block: Length::zero(), - inline: ifc.inline_position - ifc.current_nesting_level.inline_start, - }, - size: Vec2 { - block: line_height, - inline: inline_size, - }, - }; - ifc.inline_position += inline_size; - ifc.current_nesting_level - .max_block_size_of_fragments_so_far - .max_assign(line_height); - ifc.current_nesting_level - .fragments_so_far - .push(Fragment::Text(TextFragment { - parent_style: self.parent_style.clone(), - content_rect, - text: shaped, - })); - if chars.as_str().is_empty() { - break; - } else { - // New line - ifc.current_nesting_level.inline_start = Length::zero(); - let mut nesting_level = &mut ifc.current_nesting_level; - for partial in ifc.partial_inline_boxes_stack.iter_mut().rev() { - partial.finish_layout(nesting_level, &mut ifc.inline_position, true); - partial.start_corner.inline = Length::zero(); - partial.padding.inline_start = Length::zero(); - partial.border.inline_start = Length::zero(); - partial.margin.inline_start = Length::zero(); - partial.parent_nesting_level.inline_start = Length::zero(); - nesting_level = &mut partial.parent_nesting_level; - } - ifc.line_boxes - .finish_line(nesting_level, ifc.containing_block); - ifc.inline_position = Length::zero(); - } - } + fn layout(&self, _ifc: &mut InlineFormattingContextState) { + // TODO } } diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index a810dfb37fa..ae92f70822c 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -1,32 +1,46 @@ +/* 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/. */ + //! Flow layout, also known as block-and-inline layout. -use super::*; -use rayon::prelude::*; +use crate::flow::float::{FloatBox, FloatContext}; +use crate::flow::inline::InlineFormattingContext; +use crate::fragments::{ + AnonymousFragment, BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment, +}; +use crate::geom::flow_relative::{Rect, Vec2}; +use crate::positioned::{ + adjust_static_positions, AbsolutelyPositionedBox, AbsolutelyPositionedFragment, +}; +use crate::style_ext::{ComputedValuesExt, Position}; +use crate::{relative_adjustement, ContainingBlock, IndependentFormattingContext}; +use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use rayon_croissant::ParallelIteratorExt; +use servo_arc::Arc; +use style::properties::ComputedValues; +use style::values::computed::{Length, LengthOrAuto}; +use style::Zero; mod construct; mod float; -mod inline; +pub mod inline; mod root; -pub(super) use construct::*; -pub(super) use float::*; -pub(super) use inline::*; - #[derive(Debug)] -pub(super) struct BlockFormattingContext { +pub(crate) struct BlockFormattingContext { pub contents: BlockContainer, pub contains_floats: bool, } #[derive(Debug)] -pub(super) enum BlockContainer { +pub(crate) enum BlockContainer { BlockLevelBoxes(Vec<Arc<BlockLevelBox>>), InlineFormattingContext(InlineFormattingContext), } #[derive(Debug)] -pub(super) enum BlockLevelBox { +pub(crate) enum BlockLevelBox { SameFormattingContextBlock { style: Arc<ComputedValues>, contents: BlockContainer, @@ -98,7 +112,7 @@ impl BlockContainer { ), BlockContainer::InlineFormattingContext(ifc) => { ifc.layout(containing_block, tree_rank, absolutely_positioned_fragments) - } + }, } } } @@ -115,9 +129,9 @@ fn layout_block_level_children<'a>( match fragment { Fragment::Box(fragment) => { let fragment_block_margins = &fragment.block_margins_collapsed_with_children; - let fragment_block_size = fragment.padding.block_sum() - + fragment.border.block_sum() - + fragment.content_rect.size.block; + let fragment_block_size = fragment.padding.block_sum() + + fragment.border.block_sum() + + fragment.content_rect.size.block; if placement_state.next_in_flow_margin_collapses_with_parent_start_margin { assert_eq!(placement_state.current_margin.solve(), Length::zero()); @@ -136,8 +150,8 @@ fn layout_block_level_children<'a>( .current_margin .adjoin_assign(&fragment_block_margins.start); } - fragment.content_rect.start_corner.block += placement_state.current_margin.solve() - + placement_state.current_block_direction_position; + fragment.content_rect.start_corner.block += placement_state.current_margin.solve() + + placement_state.current_block_direction_position; if fragment_block_margins.collapsed_through { placement_state .current_margin @@ -147,7 +161,7 @@ fn layout_block_level_children<'a>( placement_state.current_block_direction_position += placement_state.current_margin.solve() + fragment_block_size; placement_state.current_margin = fragment_block_margins.end; - } + }, Fragment::Anonymous(fragment) => { // FIXME(nox): Margin collapsing for hypothetical boxes of // abspos elements is probably wrong. @@ -155,7 +169,7 @@ fn layout_block_level_children<'a>( assert_eq!(fragment.rect.size.block, Length::zero()); fragment.rect.start_corner.block += placement_state.current_block_direction_position; - } + }, _ => unreachable!(), } } @@ -261,12 +275,12 @@ impl BlockLevelBox { ) }, )) - } + }, BlockLevelBox::Independent { style, contents } => match contents.as_replaced() { Ok(replaced) => { // FIXME match *replaced {} - } + }, Err(contents) => Fragment::Box(layout_in_flow_non_replaced_block_level( containing_block, absolutely_positioned_fragments, @@ -280,11 +294,11 @@ impl BlockLevelBox { BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => { absolutely_positioned_fragments.push(box_.layout(Vec2::zero(), tree_rank)); Fragment::Anonymous(AnonymousFragment::no_op(containing_block.mode)) - } + }, BlockLevelBox::OutOfFlowFloatBox(_box_) => { // TODO Fragment::Anonymous(AnonymousFragment::no_op(containing_block.mode)) - } + }, } } } @@ -310,43 +324,40 @@ fn layout_in_flow_non_replaced_block_level<'a>( ) -> BoxFragment { let cbis = containing_block.inline_size; let padding = style.padding().percentages_relative_to(cbis); - let border = style.border_width().percentages_relative_to(cbis); + let border = style.border_width(); let mut computed_margin = style.margin().percentages_relative_to(cbis); let pb = &padding + &border; let box_size = style.box_size(); let inline_size = box_size.inline.percentage_relative_to(cbis); - if let LengthOrAuto::Length(is) = inline_size { + if let LengthOrAuto::LengthPercentage(is) = inline_size { let inline_margins = cbis - is - pb.inline_sum(); - use LengthOrAuto::*; match ( &mut computed_margin.inline_start, &mut computed_margin.inline_end, ) { - (s @ &mut Auto, e @ &mut Auto) => { - *s = Length(inline_margins / 2.); - *e = Length(inline_margins / 2.); - } - (s @ &mut Auto, _) => { - *s = Length(inline_margins); - } - (_, e @ &mut Auto) => { - *e = Length(inline_margins); - } + (s @ &mut LengthOrAuto::Auto, e @ &mut LengthOrAuto::Auto) => { + *s = LengthOrAuto::LengthPercentage(inline_margins / 2.); + *e = LengthOrAuto::LengthPercentage(inline_margins / 2.); + }, + (s @ &mut LengthOrAuto::Auto, _) => { + *s = LengthOrAuto::LengthPercentage(inline_margins); + }, + (_, e @ &mut LengthOrAuto::Auto) => { + *e = LengthOrAuto::LengthPercentage(inline_margins); + }, (_, e @ _) => { // Either the inline-end margin is auto, // or we’re over-constrained and we do as if it were. - *e = Length(inline_margins); - } + *e = LengthOrAuto::LengthPercentage(inline_margins); + }, } } let margin = computed_margin.auto_is(Length::zero); let mut block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin); let inline_size = inline_size.auto_is(|| cbis - pb.inline_sum() - margin.inline_sum()); - let block_size = match box_size.block { - LengthOrPercentageOrAuto::Length(l) => LengthOrAuto::Length(l), - LengthOrPercentageOrAuto::Percentage(p) => containing_block.block_size.map(|cbbs| cbbs * p), - LengthOrPercentageOrAuto::Auto => LengthOrAuto::Auto, - }; + let block_size = box_size + .block + .maybe_percentage_relative_to(containing_block.block_size.non_auto()); let containing_block_for_children = ContainingBlock { inline_size, block_size, @@ -358,11 +369,11 @@ fn layout_in_flow_non_replaced_block_level<'a>( "Mixed writing modes are not supported yet" ); let this_start_margin_can_collapse_with_children = CollapsibleWithParentStartMargin( - block_level_kind == BlockLevelKind::SameFormattingContextBlock - && pb.block_start == Length::zero(), + block_level_kind == BlockLevelKind::SameFormattingContextBlock && + pb.block_start == Length::zero(), ); - let this_end_margin_can_collapse_with_children = (block_level_kind, pb.block_end, block_size) - == ( + let this_end_margin_can_collapse_with_children = (block_level_kind, pb.block_end, block_size) == + ( BlockLevelKind::SameFormattingContextBlock, Length::zero(), LengthOrAuto::Auto, @@ -370,7 +381,7 @@ fn layout_in_flow_non_replaced_block_level<'a>( let mut nested_abspos = vec![]; let mut flow_children = layout_contents( &containing_block_for_children, - if style.box_.position.is_relatively_positioned() { + if style.get_box().position == Position::Relative { &mut nested_abspos } else { absolutely_positioned_fragments @@ -401,9 +412,9 @@ fn layout_in_flow_non_replaced_block_level<'a>( flow_children.block_size += flow_children.collapsible_margins_in_children.end.solve(); } block_margins_collapsed_with_children.collapsed_through = - this_start_margin_can_collapse_with_children.0 - && this_end_margin_can_collapse_with_children - && flow_children + this_start_margin_can_collapse_with_children.0 && + this_end_margin_can_collapse_with_children && + flow_children .collapsible_margins_in_children .collapsed_through; let relative_adjustement = relative_adjustement(style, inline_size, block_size); @@ -418,7 +429,7 @@ fn layout_in_flow_non_replaced_block_level<'a>( inline: inline_size, }, }; - if style.box_.position.is_relatively_positioned() { + if style.get_box().position == Position::Relative { AbsolutelyPositionedFragment::in_positioned_containing_block( &nested_abspos, &mut flow_children.fragments, diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs index 443969c2acb..08a23397506 100644 --- a/components/layout_2020/flow/root.rs +++ b/components/layout_2020/flow/root.rs @@ -1,122 +1,129 @@ +/* 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 super::*; -impl crate::dom::Document { - pub(crate) fn layout( - &self, - viewport: crate::primitives::Size<crate::primitives::CssPx>, - ) -> Vec<Fragment> { - BoxTreeRoot::construct(self).layout(viewport) - } -} +// FIXME +// impl crate::dom::Document { +// pub(crate) fn layout( +// &self, +// viewport: crate::geom::Size<crate::geom::CssPx>, +// ) -> Vec<Fragment> { +// BoxTreeRoot::construct(self).layout(viewport) +// } +// } struct BoxTreeRoot(BlockFormattingContext); -impl BoxTreeRoot { - pub fn construct(document: &dom::Document) -> Self { - let author_styles = &document.parse_stylesheets(); - let context = Context { - document, - author_styles, - }; - let root_element = document.root_element(); - let style = style_for_element(context.author_styles, context.document, root_element, None); - let (contains_floats, boxes) = construct_for_root_element(&context, root_element, style); - Self(BlockFormattingContext { - contains_floats: contains_floats == ContainsFloats::Yes, - contents: BlockContainer::BlockLevelBoxes(boxes), - }) - } -} +// FIXME +// impl BoxTreeRoot { +// pub fn construct(document: &dom::Document) -> Self { +// let author_styles = &document.parse_stylesheets(); +// let context = Context { +// document, +// author_styles, +// }; +// let root_element = document.root_element(); +// let style = style_for_element(context.author_styles, context.document, root_element, None); +// let (contains_floats, boxes) = construct_for_root_element(&context, root_element, style); +// Self(BlockFormattingContext { +// contains_floats: contains_floats == ContainsFloats::Yes, +// contents: BlockContainer::BlockLevelBoxes(boxes), +// }) +// } +// } -fn construct_for_root_element( - context: &Context, - root_element: dom::NodeId, - style: Arc<ComputedValues>, -) -> (ContainsFloats, Vec<Arc<BlockLevelBox>>) { - let replaced = ReplacedContent::for_element(root_element, context); +// fn construct_for_root_element( +// context: &Context, +// root_element: dom::NodeId, +// style: Arc<ComputedValues>, +// ) -> (ContainsFloats, Vec<Arc<BlockLevelBox>>) { +// let replaced = ReplacedContent::for_element(root_element, context); - let display_inside = match style.box_.display { - Display::None => return (ContainsFloats::No, Vec::new()), - Display::Contents if replaced.is_some() => { - // 'display: contents' computes to 'none' for replaced elements - return (ContainsFloats::No, Vec::new()); - } - // https://drafts.csswg.org/css-display-3/#transformations - Display::Contents => DisplayInside::Flow, - // The root element is blockified, ignore DisplayOutside - Display::GeneratingBox(DisplayGeneratingBox::OutsideInside { inside, .. }) => inside, - }; +// let display_inside = match style.box_.display { +// Display::None => return (ContainsFloats::No, Vec::new()), +// Display::Contents if replaced.is_some() => { +// // 'display: contents' computes to 'none' for replaced elements +// return (ContainsFloats::No, Vec::new()); +// } +// // https://drafts.csswg.org/css-display-3/#transformations +// Display::Contents => DisplayInside::Flow, +// // The root element is blockified, ignore DisplayOutside +// Display::GeneratingBox(DisplayGeneratingBox::OutsideInside { inside, .. }) => inside, +// }; - if let Some(replaced) = replaced { - let _box = match replaced {}; - #[allow(unreachable_code)] - { - return (ContainsFloats::No, vec![Arc::new(_box)]); - } - } +// if let Some(replaced) = replaced { +// let _box = match replaced {}; +// #[allow(unreachable_code)] +// { +// return (ContainsFloats::No, vec![Arc::new(_box)]); +// } +// } - let contents = IndependentFormattingContext::construct( - context, - &style, - display_inside, - Contents::OfElement(root_element), - ); - if style.box_.position.is_absolutely_positioned() { - ( - ContainsFloats::No, - vec![Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox( - AbsolutelyPositionedBox { style, contents }, - ))], - ) - } else if style.box_.float.is_floating() { - ( - ContainsFloats::Yes, - vec![Arc::new(BlockLevelBox::OutOfFlowFloatBox(FloatBox { - contents, - style, - }))], - ) - } else { - ( - ContainsFloats::No, - vec![Arc::new(BlockLevelBox::Independent { style, contents })], - ) - } -} +// let contents = IndependentFormattingContext::construct( +// context, +// &style, +// display_inside, +// Contents::OfElement(root_element), +// ); +// if style.box_.position.is_absolutely_positioned() { +// ( +// ContainsFloats::No, +// vec![Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox( +// AbsolutelyPositionedBox { style, contents }, +// ))], +// ) +// } else if style.box_.float.is_floating() { +// ( +// ContainsFloats::Yes, +// vec![Arc::new(BlockLevelBox::OutOfFlowFloatBox(FloatBox { +// contents, +// style, +// }))], +// ) +// } else { +// ( +// ContainsFloats::No, +// vec![Arc::new(BlockLevelBox::Independent { style, contents })], +// ) +// } +// } -impl BoxTreeRoot { - fn layout(&self, viewport: crate::primitives::Size<crate::primitives::CssPx>) -> Vec<Fragment> { - let initial_containing_block_size = Vec2 { - inline: Length { px: viewport.width }, - block: Length { - px: viewport.height, - }, - }; +// impl BoxTreeRoot { +// fn layout(&self, viewport: crate::geom::Size<crate::geom::CssPx>) -> Vec<Fragment> { +// let initial_containing_block_size = Vec2 { +// inline: Length { px: viewport.width }, +// block: Length { +// px: viewport.height, +// }, +// }; - let initial_containing_block = ContainingBlock { - inline_size: initial_containing_block_size.inline, - block_size: LengthOrAuto::Length(initial_containing_block_size.block), - // FIXME: use the document’s mode: - // https://drafts.csswg.org/css-writing-modes/#principal-flow - mode: (WritingMode::HorizontalTb, Direction::Ltr), - }; - let dummy_tree_rank = 0; - let mut absolutely_positioned_fragments = vec![]; - let mut flow_children = self.0.layout( - &initial_containing_block, - dummy_tree_rank, - &mut absolutely_positioned_fragments, - ); +// let initial_containing_block = ContainingBlock { +// inline_size: initial_containing_block_size.inline, +// block_size: LengthOrAuto::Length(initial_containing_block_size.block), +// // FIXME: use the document’s mode: +// // https://drafts.csswg.org/css-writing-modes/#principal-flow +// mode: (WritingMode::HorizontalTb, Direction::Ltr), +// }; +// let dummy_tree_rank = 0; +// let mut absolutely_positioned_fragments = vec![]; +// let mut fragments = self.0.layout( +// &initial_containing_block, +// &mut absolutely_positioned_fragments, +// dummy_tree_rank, +// &mut PlacementState::root(), +// ); - let initial_containing_block = DefiniteContainingBlock { - size: initial_containing_block_size, - mode: initial_containing_block.mode, - }; - flow_children.fragments.par_extend( - absolutely_positioned_fragments - .par_iter() - .map(|a| a.layout(&initial_containing_block)), - ); - flow_children.fragments - } -} +// let initial_containing_block = DefiniteContainingBlock { +// size: initial_containing_block_size, +// mode: initial_containing_block.mode, +// }; +// fragments.par_extend( +// absolutely_positioned_fragments +// .par_iter() +// .map(|a| a.layout(&initial_containing_block)), +// ); +// fragments +// } +// } |