diff --git a/components/layout_2020/flow/construct.rs b/components/layout_2020/flow/construct.rs index 559d57752df..23cc84a5f8b 100644 --- a/components/layout_2020/flow/construct.rs +++ b/components/layout_2020/flow/construct.rs @@ -9,7 +9,7 @@ use crate::flow::inline::{InlineBox, InlineFormattingContext, InlineLevelBox, Te use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox}; use crate::positioned::AbsolutelyPositionedBox; use crate::style_ext::{DisplayGeneratingBox, DisplayInside, DisplayOutside}; -use crate::IndependentFormattingContext; +use crate::{take, IndependentFormattingContext}; use rayon::iter::{IntoParallelIterator, ParallelIterator}; use rayon_croissant::ParallelIteratorExt; use servo_arc::Arc; @@ -152,8 +152,7 @@ impl BlockContainer { ); return (container, builder.contains_floats); } - // FIXME - // builder.end_ongoing_inline_formatting_context(); + builder.end_ongoing_inline_formatting_context(); } let mut contains_floats = builder.contains_floats; @@ -166,8 +165,7 @@ impl BlockContainer { |contains_floats, (intermediate, box_slot): (IntermediateBlockLevelBox<_>, BoxSlot<'_>)| { let (block_level_box, box_contains_floats) = intermediate.finish(context); *contains_floats |= box_contains_floats; - // FIXME - // box_slot.set(LayoutBox::BlockLevel(block_level_box.clone())); + box_slot.set(LayoutBox::BlockLevel(block_level_box.clone())); block_level_box }, |left, right| *left |= right, @@ -195,21 +193,21 @@ where self.handle_inline_level_element(style, inside, contents), )), DisplayOutside::Block => { - // FIXME + let box_style = style.get_box(); // 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 box_style.position.is_absolutely_positioned() { + self.handle_absolutely_positioned_element( + style.clone(), + inside, + contents, + box_slot, + ) + } else if box_style.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!(":("), }, @@ -362,80 +360,79 @@ where box_ } - // FIXME - // fn handle_block_level_element( - // &mut self, - // style: Arc, - // 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 - // }); + fn handle_block_level_element( + &mut self, + style: Arc, + display_inside: DisplayInside, + contents: Contents, + box_slot: BoxSlot<'dom>, + ) { + // 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); - // } + 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)); - // } + 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(); + // 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)) - // } + 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, diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs index 08a23397506..b1a43ae28be 100644 --- a/components/layout_2020/flow/root.rs +++ b/components/layout_2020/flow/root.rs @@ -2,7 +2,25 @@ * 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::*; +use crate::dom_traversal::{Contents, NodeExt}; +use crate::flow::construct::ContainsFloats; +use crate::flow::float::FloatBox; +use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox}; +use crate::fragments::Fragment; +use crate::geom; +use crate::geom::flow_relative::Vec2; +use crate::positioned::AbsolutelyPositionedBox; +use crate::replaced::ReplacedContent; +use crate::style_ext::{ + Direction, Display, DisplayGeneratingBox, DisplayInside, DisplayOutside, WritingMode, +}; +use crate::{ContainingBlock, DefiniteContainingBlock, IndependentFormattingContext}; +use rayon::iter::{IntoParallelRefIterator, ParallelExtend, ParallelIterator}; +use servo_arc::Arc; +use style::context::SharedStyleContext; +use style::properties::ComputedValues; +use style::values::computed::{Length, LengthOrAuto}; +use style_traits::CSSPixel; // FIXME // impl crate::dom::Document { @@ -16,114 +34,107 @@ use super::*; struct BoxTreeRoot(BlockFormattingContext); -// 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), -// }) -// } -// } +impl BoxTreeRoot { + pub fn construct<'dom>( + context: &SharedStyleContext<'_>, + root_element: impl NodeExt<'dom>, + ) -> Self { + let (contains_floats, boxes) = construct_for_root_element(&context, root_element); + 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, -// ) -> (ContainsFloats, Vec>) { -// let replaced = ReplacedContent::for_element(root_element, context); +fn construct_for_root_element<'dom>( + context: &SharedStyleContext<'_>, + root_element: impl NodeExt<'dom>, +) -> (ContainsFloats, Vec>) { + let style = root_element.style(context); + let replaced = ReplacedContent::for_element(root_element, context); + let box_style = style.get_box(); -// 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 Display::from(box_style.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 box_style.position.is_absolutely_positioned() { + ( + ContainsFloats::No, + vec![Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox( + AbsolutelyPositionedBox { style, contents }, + ))], + ) + } else if box_style.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::geom::Size) -> Vec { -// let initial_containing_block_size = Vec2 { -// inline: Length { px: viewport.width }, -// block: Length { -// px: viewport.height, -// }, -// }; +impl BoxTreeRoot { + fn layout(&self, viewport: geom::Size) -> Vec { + let initial_containing_block_size = Vec2 { + inline: Length::new(viewport.width), + block: Length::new(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 fragments = self.0.layout( -// &initial_containing_block, -// &mut absolutely_positioned_fragments, -// dummy_tree_rank, -// &mut PlacementState::root(), -// ); + let initial_containing_block = ContainingBlock { + inline_size: initial_containing_block_size.inline, + block_size: LengthOrAuto::LengthPercentage(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 = 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 -// } -// } + 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 + } +} diff --git a/components/style/properties/longhands/box.mako.rs b/components/style/properties/longhands/box.mako.rs index 4dcc43aec23..2fd69229878 100644 --- a/components/style/properties/longhands/box.mako.rs +++ b/components/style/properties/longhands/box.mako.rs @@ -42,15 +42,24 @@ ${helpers.single_keyword( spec="Internal (not web-exposed)", )} -${helpers.single_keyword( - "position", - "static absolute relative fixed" + (" sticky" if engine in ["gecko", "servo-2013"] else ""), - engines="gecko servo-2013 servo-2020", - animation_value_type="discrete", - flags="CREATES_STACKING_CONTEXT ABSPOS_CB", - spec="https://drafts.csswg.org/css-position/#position-property", - servo_restyle_damage="rebuild_and_reflow", -)} +<%helpers:single_keyword + name="position" + values="static absolute relative fixed ${'sticky' if engine in ['gecko', 'servo-2013'] else ''}" + engines="gecko servo-2013 servo-2020" + animation_value_type="discrete" + flags="CREATES_STACKING_CONTEXT ABSPOS_CB" + spec="https://drafts.csswg.org/css-position/#position-property" + servo_restyle_damage="rebuild_and_reflow" +> +impl computed_value::T { + pub fn is_absolutely_positioned(self) -> bool { + match self { + Self::Absolute | Self::Fixed => true, + _ => false, + } + } +} + ${helpers.predefined_type( "float", diff --git a/components/style/values/computed/box.rs b/components/style/values/computed/box.rs index 4cd16b1cd9e..d5adeb206a6 100644 --- a/components/style/values/computed/box.rs +++ b/components/style/values/computed/box.rs @@ -61,6 +61,13 @@ pub enum Float { None, } +impl Float { + /// Returns true if `self` is not `None`. + pub fn is_floating(self) -> bool { + self != Self::None + } +} + impl ToComputedValue for SpecifiedFloat { type ComputedValue = Float;