aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
Diffstat (limited to 'components')
-rw-r--r--components/layout_2020/flow/construct.rs52
-rw-r--r--components/layout_2020/flow/mod.rs93
-rw-r--r--components/layout_2020/lists.rs13
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 |