diff options
Diffstat (limited to 'components')
-rw-r--r-- | components/layout_2020/flow/construct.rs | 52 | ||||
-rw-r--r-- | components/layout_2020/flow/mod.rs | 93 | ||||
-rw-r--r-- | components/layout_2020/lists.rs | 13 |
3 files changed, 141 insertions, 17 deletions
diff --git a/components/layout_2020/flow/construct.rs b/components/layout_2020/flow/construct.rs index d61804751b0..02595e2b3c6 100644 --- a/components/layout_2020/flow/construct.rs +++ b/components/layout_2020/flow/construct.rs @@ -13,10 +13,13 @@ use style::selector_parser::PseudoElement; use style::str::char_is_whitespace; use style::values::specified::text::TextDecorationLine; +use super::OutsideMarker; use crate::cell::ArcRefCell; use crate::context::LayoutContext; use crate::dom::{BoxSlot, LayoutBox, NodeExt}; -use crate::dom_traversal::{Contents, NodeAndStyleInfo, NonReplacedContents, TraversalHandler}; +use crate::dom_traversal::{ + Contents, NodeAndStyleInfo, NonReplacedContents, PseudoElementContentItem, TraversalHandler, +}; use crate::flow::float::FloatBox; use crate::flow::inline::{InlineBox, InlineFormattingContext, InlineLevelBox}; use crate::flow::text_run::TextRun; @@ -98,6 +101,9 @@ enum BlockLevelCreator { display_inside: DisplayInside, contents: Contents, }, + OutsideMarker { + contents: Vec<PseudoElementContentItem>, + }, AnonymousTable { table_block: ArcRefCell<BlockLevelBox>, }, @@ -195,17 +201,12 @@ impl BlockContainer { if is_list_item { if let Some(marker_contents) = crate::lists::make_marker(context, info) { - let _position = info.style.clone_list_style_position(); - // FIXME: implement support for `outside` and remove this: - let position = ListStylePosition::Inside; - match position { + match info.style.clone_list_style_position() { ListStylePosition::Inside => { builder.handle_list_item_marker_inside(info, marker_contents) }, ListStylePosition::Outside => { - // FIXME: implement layout for this case - // https://github.com/servo/servo/issues/27383 - // and enable `list-style-position` and the `list-style` shorthand in Stylo. + builder.handle_list_item_marker_outside(info, marker_contents) }, } } @@ -452,6 +453,18 @@ where ); } + fn handle_list_item_marker_outside( + &mut self, + info: &NodeAndStyleInfo<Node>, + contents: Vec<crate::dom_traversal::PseudoElementContentItem>, + ) { + self.block_level_boxes.push(BlockLevelJob { + info: info.clone(), + box_slot: BoxSlot::dummy(), + kind: BlockLevelCreator::OutsideMarker { contents }, + }); + } + fn handle_inline_level_element( &mut self, info: &NodeAndStyleInfo<Node>, @@ -768,6 +781,29 @@ where display_inside, contents, ))), + BlockLevelCreator::OutsideMarker { contents } => { + let marker_style = context + .shared_context() + .stylist + .style_for_anonymous::<Node::ConcreteElement>( + &context.shared_context().guards, + &PseudoElement::ServoLegacyText, // FIMXE: use `PseudoElement::Marker` when we add it + &info.style, + ); + let info = info.new_replacing_style(marker_style.clone()); + let contents = NonReplacedContents::OfPseudoElement(contents); + let block_container = BlockContainer::construct( + context, + &info, + contents, + TextDecorationLine::empty(), + false, /* is_list_item */ + ); + ArcRefCell::new(BlockLevelBox::OutsideMarker(OutsideMarker { + style: marker_style, + block_container, + })) + }, BlockLevelCreator::AnonymousTable { table_block } => table_block, }; self.box_slot diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 4067489219d..c04f85ae351 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -71,6 +71,10 @@ impl BlockContainer { #[derive(Debug, Serialize)] pub(crate) enum BlockLevelBox { + Independent(IndependentFormattingContext), + OutOfFlowAbsolutelyPositionedBox(ArcRefCell<AbsolutelyPositionedBox>), + OutOfFlowFloatBox(FloatBox), + OutsideMarker(OutsideMarker), SameFormattingContextBlock { base_fragment_info: BaseFragmentInfo, #[serde(skip_serializing)] @@ -78,9 +82,6 @@ pub(crate) enum BlockLevelBox { contents: BlockContainer, contains_floats: bool, }, - OutOfFlowAbsolutelyPositionedBox(ArcRefCell<AbsolutelyPositionedBox>), - OutOfFlowFloatBox(FloatBox), - Independent(IndependentFormattingContext), } impl BlockLevelBox { @@ -103,6 +104,7 @@ impl BlockLevelBox { BlockLevelBox::SameFormattingContextBlock { ref style, .. } => style, BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(_) | BlockLevelBox::OutOfFlowFloatBox(_) => return true, + BlockLevelBox::OutsideMarker(_) => return false, BlockLevelBox::Independent(ref context) => { // FIXME: If the element doesn't fit next to floats, it will get clearance. // In that case this should be returning false. @@ -205,6 +207,81 @@ struct FlowLayout { #[derive(Clone, Copy)] struct CollapsibleWithParentStartMargin(bool); +/// The contentes of a BlockContainer created to render a list marker +/// for a list that has `list-style-position: outside`. +#[derive(Debug, Serialize)] +pub(crate) struct OutsideMarker { + #[serde(skip_serializing)] + pub style: Arc<ComputedValues>, + pub block_container: BlockContainer, +} + +impl OutsideMarker { + fn layout( + &self, + layout_context: &LayoutContext<'_>, + containing_block: &ContainingBlock<'_>, + positioning_context: &mut PositioningContext, + sequential_layout_state: Option<&mut SequentialLayoutState>, + collapsible_with_parent_start_margin: Option<CollapsibleWithParentStartMargin>, + ) -> Fragment { + let content_sizes = self + .block_container + .inline_content_sizes(layout_context, containing_block.style.writing_mode); + let containing_block = ContainingBlock { + inline_size: content_sizes.max_content, + block_size: AuOrAuto::auto(), + style: &self.style, + }; + let flow_layout = self.block_container.layout( + layout_context, + positioning_context, + &containing_block, + sequential_layout_state, + collapsible_with_parent_start_margin.unwrap_or(CollapsibleWithParentStartMargin(false)), + ); + let max_inline_size = flow_layout.fragments.iter().fold( + Length::zero(), + |current_max, fragment| match fragment { + Fragment::Text(text) => current_max.max(text.rect.max_inline_position()), + Fragment::Image(image) => current_max.max(image.rect.max_inline_position()), + Fragment::Positioning(positioning) => { + current_max.max(positioning.rect.max_inline_position()) + }, + Fragment::Box(_) | + Fragment::Float(_) | + Fragment::AbsoluteOrFixedPositioned(_) | + Fragment::IFrame(_) => { + unreachable!("Found unexpected fragment type in outside list marker!"); + }, + }, + ); + + let content_rect = LogicalRect { + start_corner: LogicalVec2 { + inline: -max_inline_size, + block: Zero::zero(), + }, + size: LogicalVec2 { + inline: max_inline_size, + block: Zero::zero(), + }, + }; + + Fragment::Box(BoxFragment::new( + BaseFragmentInfo::anonymous(), + self.style.clone(), + flow_layout.fragments, + content_rect, + LogicalSides::zero(), + LogicalSides::zero(), + LogicalSides::zero(), + None, + CollapsedBlockMargins::zero(), + )) + } +} + impl BlockFormattingContext { pub(super) fn layout( &self, @@ -261,7 +338,8 @@ fn calculate_inline_content_size_for_block_level_boxes( ) -> ContentSizes { let get_box_info = |box_: &ArcRefCell<BlockLevelBox>| { match &mut *box_.borrow_mut() { - BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(_) => None, + BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(_) | + BlockLevelBox::OutsideMarker { .. } => None, BlockLevelBox::OutOfFlowFloatBox(ref mut float_box) => { let size = float_box .contents @@ -603,6 +681,13 @@ impl BlockLevelBox { positioning_context, containing_block, )), + BlockLevelBox::OutsideMarker(outside_marker) => outside_marker.layout( + layout_context, + containing_block, + positioning_context, + sequential_layout_state, + collapsible_with_parent_start_margin, + ), } } } diff --git a/components/layout_2020/lists.rs b/components/layout_2020/lists.rs index 6c71b5f34d0..b0e97ab02e3 100644 --- a/components/layout_2020/lists.rs +++ b/components/layout_2020/lists.rs @@ -55,11 +55,14 @@ where fn marker_string(style: &style_structs::List) -> Option<&'static str> { match style.list_style_type { ListStyleType::None => None, - ListStyleType::Disc => Some("• "), - ListStyleType::Circle => Some("◦ "), - ListStyleType::Square => Some("▪ "), - ListStyleType::DisclosureOpen => Some("▾ "), - ListStyleType::DisclosureClosed => Some("‣ "), + // TODO: Using non-breaking space here is a bit of a hack to give a bit of margin to outside + // markers, but really we should be setting `white-space: pre` on them instead. + // See https://github.com/w3c/csswg-drafts/issues/4891. + ListStyleType::Disc => Some("•\u{00a0}"), + ListStyleType::Circle => Some("◦\u{00a0}"), + ListStyleType::Square => Some("▪\u{00a0}"), + ListStyleType::DisclosureOpen => Some("▾\u{00a0}"), + ListStyleType::DisclosureClosed => Some("‣\u{00a0}"), ListStyleType::Decimal | ListStyleType::LowerAlpha | ListStyleType::UpperAlpha | |