diff --git a/components/layout_2020/dom_traversal.rs b/components/layout_2020/dom_traversal.rs index 0e9e18a739e..c1ac55c2bfb 100644 --- a/components/layout_2020/dom_traversal.rs +++ b/components/layout_2020/dom_traversal.rs @@ -6,13 +6,15 @@ use crate::element_data::{LayoutBox, LayoutDataForElement}; use crate::replaced::ReplacedContent; use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside, DisplayOutside}; use crate::wrapper::GetRawData; -use atomic_refcell::AtomicRefMut; +use atomic_refcell::{AtomicRefCell, AtomicRefMut}; use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode}; use servo_arc::Arc; use std::convert::TryInto; +use std::marker::PhantomData as marker; use style::context::SharedStyleContext; use style::dom::TNode; use style::properties::ComputedValues; +use style::selector_parser::PseudoElement; #[derive(Clone, Copy)] pub(super) enum WhichPseudoElement { @@ -43,7 +45,10 @@ pub(super) enum PseudoElementContentItem { Replaced(ReplacedContent), } -pub(super) trait TraversalHandler { +pub(super) trait TraversalHandler<'dom, Node> +where + Node: 'dom, +{ fn handle_text(&mut self, text: String, parent_style: &Arc); /// Or pseudo-element @@ -52,14 +57,14 @@ pub(super) trait TraversalHandler { style: &Arc, display: DisplayGeneratingBox, contents: Contents, - box_slot: BoxSlot, + box_slot: BoxSlot<'dom>, ); } fn traverse_children_of<'dom, Node>( parent_element: Node, context: &SharedStyleContext, - handler: &mut impl TraversalHandler, + handler: &mut impl TraversalHandler<'dom, Node>, ) where Node: NodeExt<'dom>, { @@ -81,7 +86,7 @@ fn traverse_children_of<'dom, Node>( fn traverse_element<'dom, Node>( element: Node, context: &SharedStyleContext, - handler: &mut impl TraversalHandler, + handler: &mut impl TraversalHandler<'dom, Node>, ) where Node: NodeExt<'dom>, { @@ -94,7 +99,7 @@ fn traverse_element<'dom, Node>( // element.unset_boxes_in_subtree() } else { - element.layout_data_mut().self_box = Some(LayoutBox::DisplayContents); + *element.layout_data_mut().self_box.borrow_mut() = Some(LayoutBox::DisplayContents); traverse_children_of(element, context, handler) } }, @@ -116,7 +121,7 @@ fn traverse_pseudo_element<'dom, Node>( which: WhichPseudoElement, element: Node, context: &SharedStyleContext, - handler: &mut impl TraversalHandler, + handler: &mut impl TraversalHandler<'dom, Node>, ) where Node: NodeExt<'dom>, { @@ -126,7 +131,7 @@ fn traverse_pseudo_element<'dom, Node>( Display::Contents => { element.unset_pseudo_element_box(which); let items = generate_pseudo_element_content(&style, element, context); - traverse_pseudo_element_contents(&style, items, handler); + traverse_pseudo_element_contents(&style, context, handler, items); }, Display::GeneratingBox(display) => { let items = generate_pseudo_element_content(&style, element, context); @@ -140,33 +145,42 @@ fn traverse_pseudo_element<'dom, Node>( fn traverse_pseudo_element_contents<'dom, Node>( pseudo_element_style: &Arc, + context: &SharedStyleContext, + handler: &mut impl TraversalHandler<'dom, Node>, items: Vec, - handler: &mut impl TraversalHandler, ) where - Node: 'dom, + Node: NodeExt<'dom>, { - // let mut anonymous_style = None; + let mut anonymous_style = None; for item in items { match item { PseudoElementContentItem::Text(text) => handler.handle_text(text, pseudo_element_style), PseudoElementContentItem::Replaced(contents) => { - // FIXME - // let item_style = anonymous_style.get_or_insert_with(|| { - // ComputedValues::anonymous_inheriting_from(Some(pseudo_element_style)) - // }); - // let display_inline = DisplayGeneratingBox::OutsideInside { - // outside: DisplayOutside::Inline, - // inside: DisplayInside::Flow, - // }; - // // `display` is not inherited, so we get the initial value - // debug_assert!(item_style.box_.display == Display::GeneratingBox(display_inline)); - // handler.handle_element( - // item_style, - // display_inline, - // Contents::Replaced(contents), - // // We don’t keep pointers to boxes generated by contents of pseudo-elements - // BoxSlot::dummy(), - // ) + let item_style = anonymous_style.get_or_insert_with(|| { + context + .stylist + .style_for_anonymous::( + &context.guards, + &PseudoElement::ServoText, + &pseudo_element_style, + ) + }); + let display_inline = DisplayGeneratingBox::OutsideInside { + outside: DisplayOutside::Inline, + inside: DisplayInside::Flow, + }; + // `display` is not inherited, so we get the initial value + debug_assert!( + Display::from(item_style.get_box().display) == + Display::GeneratingBox(display_inline) + ); + handler.handle_element( + item_style, + display_inline, + Contents::Replaced(contents), + // We don’t keep pointers to boxes generated by contents of pseudo-elements + BoxSlot::dummy(), + ) }, } } @@ -201,12 +215,12 @@ where self, inherited_style: &Arc, context: &SharedStyleContext, - handler: &mut impl TraversalHandler, + handler: &mut impl TraversalHandler<'dom, Node>, ) { match self { NonReplacedContents::OfElement(node) => traverse_children_of(node, context, handler), NonReplacedContents::OfPseudoElement(items) => { - traverse_pseudo_element_contents(inherited_style, items, handler) + traverse_pseudo_element_contents(inherited_style, context, handler, items) }, } } @@ -239,22 +253,25 @@ where } pub(super) struct BoxSlot<'dom> { - slot: Option>>, + slot: Option>>>, + marker: marker<&'dom ()>, } -impl<'dom> BoxSlot<'dom> { - pub fn new(mut slot: AtomicRefMut<'dom, Option>) -> Self { - *slot = None; - Self { slot: Some(slot) } +impl BoxSlot<'_> { + pub fn new(slot: Arc>>) -> Self { + *slot.borrow_mut() = None; + let slot = Some(slot); + Self { slot, marker } } pub fn dummy() -> Self { - Self { slot: None } + let slot = None; + Self { slot, marker } } pub fn set(mut self, box_: LayoutBox) { if let Some(slot) = &mut self.slot { - **slot = Some(box_) + *slot.borrow_mut() = Some(box_); } } } @@ -262,12 +279,12 @@ impl<'dom> BoxSlot<'dom> { impl Drop for BoxSlot<'_> { fn drop(&mut self) { if let Some(slot) = &mut self.slot { - assert!(slot.is_some(), "failed to set a layout box") + assert!(slot.borrow().is_some(), "failed to set a layout box"); } } } -pub(crate) trait NodeExt<'dom>: 'dom + Copy + Send + Sync { +pub(crate) trait NodeExt<'dom>: 'dom + Copy + LayoutNode + Send + Sync { fn is_element(self) -> bool; fn as_text(self) -> Option; fn first_child(self) -> Option; @@ -276,15 +293,15 @@ pub(crate) trait NodeExt<'dom>: 'dom + Copy + Send + Sync { fn style(self, context: &SharedStyleContext) -> Arc; fn layout_data_mut(&self) -> AtomicRefMut; - fn element_box_slot(&self) -> BoxSlot; - fn pseudo_element_box_slot(&self, which: WhichPseudoElement) -> BoxSlot; + fn element_box_slot(&self) -> BoxSlot<'dom>; + fn pseudo_element_box_slot(&self, which: WhichPseudoElement) -> BoxSlot<'dom>; fn unset_pseudo_element_box(self, which: WhichPseudoElement); fn unset_boxes_in_subtree(self); } impl<'dom, T> NodeExt<'dom> for T where - T: 'dom + LayoutNode + Send + Sync, + T: 'dom + Copy + LayoutNode + Send + Sync, { fn is_element(self) -> bool { self.to_threadsafe().as_element().is_some() @@ -320,27 +337,25 @@ where .unwrap() } - fn element_box_slot(&self) -> BoxSlot { - BoxSlot::new(AtomicRefMut::map(self.layout_data_mut(), |data| { - &mut data.self_box - })) + fn element_box_slot(&self) -> BoxSlot<'dom> { + BoxSlot::new(self.layout_data_mut().self_box.clone()) } - fn pseudo_element_box_slot(&self, which: WhichPseudoElement) -> BoxSlot { - BoxSlot::new(AtomicRefMut::map(self.layout_data_mut(), |data| { - let pseudos = data.pseudo_elements.get_or_insert_with(Default::default); - match which { - WhichPseudoElement::Before => &mut pseudos.before, - WhichPseudoElement::After => &mut pseudos.after, - } - })) + fn pseudo_element_box_slot(&self, which: WhichPseudoElement) -> BoxSlot<'dom> { + let mut data = self.layout_data_mut(); + let pseudos = data.pseudo_elements.get_or_insert_with(Default::default); + let cell = match which { + WhichPseudoElement::Before => &mut pseudos.before, + WhichPseudoElement::After => &mut pseudos.after, + }; + BoxSlot::new(cell.clone()) } fn unset_pseudo_element_box(self, which: WhichPseudoElement) { if let Some(pseudos) = &mut self.layout_data_mut().pseudo_elements { match which { - WhichPseudoElement::Before => pseudos.before = None, - WhichPseudoElement::After => pseudos.after = None, + WhichPseudoElement::Before => *pseudos.before.borrow_mut() = None, + WhichPseudoElement::After => *pseudos.after.borrow_mut() = None, } } } @@ -352,7 +367,8 @@ where let traverse_children = { let mut layout_data = node.layout_data_mut(); layout_data.pseudo_elements = None; - layout_data.self_box.take().is_some() + let self_box = layout_data.self_box.borrow_mut().take(); + self_box.is_some() }; if traverse_children { // Only descend into children if we removed a box. diff --git a/components/layout_2020/element_data.rs b/components/layout_2020/element_data.rs index 17c27e1bfcd..fdf611a76c7 100644 --- a/components/layout_2020/element_data.rs +++ b/components/layout_2020/element_data.rs @@ -4,18 +4,19 @@ use crate::flow::inline::InlineLevelBox; use crate::flow::BlockLevelBox; +use atomic_refcell::AtomicRefCell; use servo_arc::Arc; #[derive(Default)] pub(crate) struct LayoutDataForElement { - pub(super) self_box: Option, + pub(super) self_box: Arc>>, pub(super) pseudo_elements: Option>, } #[derive(Default)] pub(super) struct PseudoElementBoxes { - pub before: Option, - pub after: Option, + pub before: Arc>>, + pub after: Arc>>, } pub(super) enum LayoutBox { diff --git a/components/layout_2020/flow/construct.rs b/components/layout_2020/flow/construct.rs index de590c950d4..6b2027a8794 100644 --- a/components/layout_2020/flow/construct.rs +++ b/components/layout_2020/flow/construct.rs @@ -9,13 +9,14 @@ 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; use std::convert::TryInto; use style::context::SharedStyleContext; use style::properties::ComputedValues; +use style::selector_parser::PseudoElement; impl BlockFormattingContext { pub fn construct<'dom>( @@ -152,8 +153,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 +166,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, @@ -178,7 +177,7 @@ impl BlockContainer { } } -impl<'dom, Node> TraversalHandler for BlockContainerBuilder<'dom, '_, Node> +impl<'dom, Node> TraversalHandler<'dom, Node> for BlockContainerBuilder<'dom, '_, Node> where Node: NodeExt<'dom>, { @@ -187,7 +186,7 @@ where style: &Arc, display: DisplayGeneratingBox, contents: Contents, - box_slot: BoxSlot, + box_slot: BoxSlot<'dom>, ) { match display { DisplayGeneratingBox::OutsideInside { outside, inside } => match outside { @@ -195,21 +194,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 +361,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, @@ -514,22 +512,25 @@ where return; } + let context = self.context; let block_container_style = self.block_container_style; - // 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 anonymous_style = self.anonymous_style.get_or_insert_with(|| { + context + .stylist + .style_for_anonymous::( + &context.guards, + &PseudoElement::ServoText, + &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())) + 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> { 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;