aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout_2020/flow/inline
diff options
context:
space:
mode:
authorMartin Robinson <mrobinson@igalia.com>2024-06-19 10:51:10 +0200
committerGitHub <noreply@github.com>2024-06-19 08:51:10 +0000
commite74075255bfef3f55acdfb4866fc2e0a9f5a9583 (patch)
treef9b6face354deb3c7c227269d2ab709f77d6e0a3 /components/layout_2020/flow/inline
parent48035141966c907ee7cdd0cd73d55da0d3f866a0 (diff)
downloadservo-e74075255bfef3f55acdfb4866fc2e0a9f5a9583.tar.gz
servo-e74075255bfef3f55acdfb4866fc2e0a9f5a9583.zip
layout: Flatten inline box storage in InlineFormattingContexts (#32539)
This accomplishes two things: 1. Makes it easier to iterate through all inline formatting context items. 2. Will make it possible to easily move back and forth through the tree of inline boxes, in order to enable reordering and splitting inline boxes on lines -- necessary for BiDi. Co-authored-by: Rakhi Sharma <atbrakhi@igalia.com>
Diffstat (limited to 'components/layout_2020/flow/inline')
-rw-r--r--components/layout_2020/flow/inline/construct.rs169
-rw-r--r--components/layout_2020/flow/inline/mod.rs269
2 files changed, 201 insertions, 237 deletions
diff --git a/components/layout_2020/flow/inline/construct.rs b/components/layout_2020/flow/inline/construct.rs
index e3f4d8055a0..603a807a62e 100644
--- a/components/layout_2020/flow/inline/construct.rs
+++ b/components/layout_2020/flow/inline/construct.rs
@@ -11,7 +11,7 @@ use style::values::specified::text::TextTransformCase;
use unicode_segmentation::UnicodeSegmentation;
use super::text_run::TextRun;
-use super::{InlineBox, InlineFormattingContext, InlineLevelBox};
+use super::{InlineBox, InlineBoxIdentifier, InlineBoxes, InlineFormattingContext, InlineItem};
use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
use crate::dom::NodeExt;
@@ -22,7 +22,12 @@ use crate::positioned::AbsolutelyPositionedBox;
#[derive(Default)]
pub(crate) struct InlineFormattingContextBuilder {
+ /// The collection of text strings that make up this [`InlineFormattingContext`] under
+ /// construction.
pub text_segments: Vec<String>,
+
+ /// The current offset in the final text string of this [`InlineFormattingContext`],
+ /// used to properly set the text range of new [`InlineItem::TextRun`]s.
current_text_offset: usize,
/// Whether the last processed node ended with whitespace. This is used to
@@ -41,13 +46,13 @@ pub(crate) struct InlineFormattingContextBuilder {
/// Whether or not this inline formatting context will contain floats.
pub contains_floats: bool,
- /// Inline elements are direct descendants of the element that establishes
- /// the inline formatting context that this builder builds.
- pub root_inline_boxes: Vec<ArcRefCell<InlineLevelBox>>,
+ /// The current list of [`InlineItem`]s in this [`InlineFormattingContext`] under
+ /// construction. This is stored in a flat list to make it easy to access the last
+ /// item.
+ pub inline_items: Vec<ArcRefCell<InlineItem>>,
- /// Whether or not the inline formatting context under construction has any
- /// uncollapsible text content.
- pub has_uncollapsible_text_content: bool,
+ /// The current [`InlineBox`] tree of this [`InlineFormattingContext`] under construction.
+ pub inline_boxes: InlineBoxes,
/// The ongoing stack of inline boxes stack of the builder.
///
@@ -56,16 +61,12 @@ pub(crate) struct InlineFormattingContextBuilder {
/// which is why the code doesn't need to keep track of the actual
/// container root (see `handle_inline_level_element`).
///
- /// Whenever the end of a DOM element that represents an inline box is
- /// reached, the inline box at the top of this stack is complete and ready
- /// to be pushed to the children of the next last ongoing inline box
- /// the ongoing inline formatting context if the stack is now empty,
- /// which means we reached the end of a child of the actual
- /// container root (see `move_to_next_sibling`).
- ///
- /// When an inline box ends, it's removed from this stack and added to
- /// [`Self::root_inline_boxes`].
- inline_box_stack: Vec<InlineBox>,
+ /// When an inline box ends, it's removed from this stack.
+ inline_box_stack: Vec<InlineBoxIdentifier>,
+
+ /// Whether or not the inline formatting context under construction has any
+ /// uncollapsible text content.
+ pub has_uncollapsible_text_content: bool,
}
impl InlineFormattingContextBuilder {
@@ -93,44 +94,30 @@ impl InlineFormattingContextBuilder {
return false;
}
- fn inline_level_boxes_are_empty(boxes: &[ArcRefCell<InlineLevelBox>]) -> bool {
- boxes
- .iter()
- .all(|inline_level_box| inline_level_box_is_empty(&inline_level_box.borrow()))
- }
-
- fn inline_level_box_is_empty(inline_level_box: &InlineLevelBox) -> bool {
+ fn inline_level_box_is_empty(inline_level_box: &InlineItem) -> bool {
match inline_level_box {
- InlineLevelBox::InlineBox(_) => false,
+ InlineItem::StartInlineBox(_) => false,
+ InlineItem::EndInlineBox => false,
// Text content is handled by `self.has_uncollapsible_text` content above in order
// to avoid having to iterate through the character once again.
- InlineLevelBox::TextRun(_) => true,
- InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(_) => false,
- InlineLevelBox::OutOfFlowFloatBox(_) => false,
- InlineLevelBox::Atomic(_) => false,
+ InlineItem::TextRun(_) => true,
+ InlineItem::OutOfFlowAbsolutelyPositionedBox(_) => false,
+ InlineItem::OutOfFlowFloatBox(_) => false,
+ InlineItem::Atomic(_) => false,
}
}
- inline_level_boxes_are_empty(&self.root_inline_boxes)
- }
-
- // Retrieves the mutable reference of inline boxes either from the last
- // element of a stack or directly from the formatting context, depending on the situation.
- fn current_inline_level_boxes(&mut self) -> &mut Vec<ArcRefCell<InlineLevelBox>> {
- match self.inline_box_stack.last_mut() {
- Some(last) => &mut last.children,
- None => &mut self.root_inline_boxes,
- }
+ self.inline_items
+ .iter()
+ .all(|inline_level_box| inline_level_box_is_empty(&inline_level_box.borrow()))
}
pub(crate) fn push_atomic(
&mut self,
independent_formatting_context: IndependentFormattingContext,
- ) -> ArcRefCell<InlineLevelBox> {
- let inline_level_box =
- ArcRefCell::new(InlineLevelBox::Atomic(independent_formatting_context));
- self.current_inline_level_boxes()
- .push(inline_level_box.clone());
+ ) -> ArcRefCell<InlineItem> {
+ let inline_level_box = ArcRefCell::new(InlineItem::Atomic(independent_formatting_context));
+ self.inline_items.push(inline_level_box.clone());
// Push an object replacement character for this atomic, which will ensure that the line breaker
// inserts a line breaking opportunity here.
@@ -147,49 +134,43 @@ impl InlineFormattingContextBuilder {
pub(crate) fn push_absolutely_positioned_box(
&mut self,
absolutely_positioned_box: AbsolutelyPositionedBox,
- ) -> ArcRefCell<InlineLevelBox> {
+ ) -> ArcRefCell<InlineItem> {
let absolutely_positioned_box = ArcRefCell::new(absolutely_positioned_box);
- let inline_level_box = ArcRefCell::new(InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(
+ let inline_level_box = ArcRefCell::new(InlineItem::OutOfFlowAbsolutelyPositionedBox(
absolutely_positioned_box,
));
- self.current_inline_level_boxes()
- .push(inline_level_box.clone());
+ self.inline_items.push(inline_level_box.clone());
inline_level_box
}
- pub(crate) fn push_float_box(&mut self, float_box: FloatBox) -> ArcRefCell<InlineLevelBox> {
- let inline_level_box = ArcRefCell::new(InlineLevelBox::OutOfFlowFloatBox(float_box));
- self.current_inline_level_boxes()
- .push(inline_level_box.clone());
+ pub(crate) fn push_float_box(&mut self, float_box: FloatBox) -> ArcRefCell<InlineItem> {
+ let inline_level_box = ArcRefCell::new(InlineItem::OutOfFlowFloatBox(float_box));
+ self.inline_items.push(inline_level_box.clone());
self.contains_floats = true;
inline_level_box
}
- pub(crate) fn start_inline_box<'dom, Node: NodeExt<'dom>>(
- &mut self,
- info: &NodeAndStyleInfo<Node>,
- ) {
- self.inline_box_stack.push(InlineBox::new(info))
+ pub(crate) fn start_inline_box(&mut self, inline_box: InlineBox) {
+ let identifier = self.inline_boxes.start_inline_box(inline_box);
+ self.inline_items
+ .push(ArcRefCell::new(InlineItem::StartInlineBox(identifier)));
+ self.inline_box_stack.push(identifier);
}
- pub(crate) fn end_inline_box(&mut self) -> ArcRefCell<InlineLevelBox> {
- self.end_inline_box_internal(true)
+ pub(crate) fn end_inline_box(&mut self) -> ArcRefCell<InlineBox> {
+ let identifier = self.end_inline_box_internal();
+ let inline_level_box = self.inline_boxes.get(&identifier);
+ inline_level_box.borrow_mut().is_last_fragment = true;
+ inline_level_box
}
- fn end_inline_box_internal(&mut self, is_last_fragment: bool) -> ArcRefCell<InlineLevelBox> {
- let mut inline_box = self
- .inline_box_stack
+ fn end_inline_box_internal(&mut self) -> InlineBoxIdentifier {
+ self.inline_boxes.end_inline_box();
+ self.inline_items
+ .push(ArcRefCell::new(InlineItem::EndInlineBox));
+ self.inline_box_stack
.pop()
- .expect("no ongoing inline level box found");
-
- if is_last_fragment {
- inline_box.is_last_fragment = true;
- }
-
- let inline_box = ArcRefCell::new(InlineLevelBox::InlineBox(inline_box));
- self.current_inline_level_boxes().push(inline_box.clone());
-
- inline_box
+ .expect("Ended non-existent inline box")
}
pub(crate) fn push_text<'dom, Node: NodeExt<'dom>>(
@@ -251,19 +232,19 @@ impl InlineFormattingContextBuilder {
self.current_text_offset = new_range.end;
self.text_segments.push(new_text);
- let inlines = self.current_inline_level_boxes();
- if let Some(mut last_box) = inlines.last_mut().map(|last| last.borrow_mut()) {
- if let InlineLevelBox::TextRun(ref mut text_run) = *last_box {
+ if let Some(inline_item) = self.inline_items.last() {
+ if let InlineItem::TextRun(text_run) = &mut *inline_item.borrow_mut() {
text_run.text_range.end = new_range.end;
return;
}
}
- inlines.push(ArcRefCell::new(InlineLevelBox::TextRun(TextRun::new(
- info.into(),
- info.style.clone(),
- new_range,
- ))));
+ self.inline_items
+ .push(ArcRefCell::new(InlineItem::TextRun(TextRun::new(
+ info.into(),
+ info.style.clone(),
+ new_range,
+ ))));
}
pub(crate) fn split_around_block_and_finish(
@@ -280,27 +261,25 @@ impl InlineFormattingContextBuilder {
// context. It has the same inline box structure as this builder, except the boxes are
// marked as not being the first fragment. No inline content is carried over to this new
// builder.
- let mut inline_buidler_from_before_split = std::mem::replace(
- self,
- InlineFormattingContextBuilder {
- on_word_boundary: true,
- inline_box_stack: self
- .inline_box_stack
- .iter()
- .map(|inline_box| inline_box.split_around_block())
- .collect(),
- ..Default::default()
- },
- );
+ let mut new_builder = InlineFormattingContextBuilder::new();
+ for identifier in self.inline_box_stack.iter() {
+ new_builder.start_inline_box(
+ self.inline_boxes
+ .get(&identifier)
+ .borrow()
+ .split_around_block(),
+ );
+ }
+ let mut inline_builder_from_before_split = std::mem::replace(self, new_builder);
// End all ongoing inline boxes in the first builder, but ensure that they are not
// marked as the final fragments, so that they do not get inline end margin, borders,
// and padding.
- while !inline_buidler_from_before_split.inline_box_stack.is_empty() {
- inline_buidler_from_before_split.end_inline_box_internal(false);
+ while !inline_builder_from_before_split.inline_box_stack.is_empty() {
+ inline_builder_from_before_split.end_inline_box_internal();
}
- inline_buidler_from_before_split.finish(
+ inline_builder_from_before_split.finish(
layout_context,
text_decoration_line,
has_first_formatted_line,
diff --git a/components/layout_2020/flow/inline/mod.rs b/components/layout_2020/flow/inline/mod.rs
index 9b2fa77ab76..18aeb24734b 100644
--- a/components/layout_2020/flow/inline/mod.rs
+++ b/components/layout_2020/flow/inline/mod.rs
@@ -131,7 +131,15 @@ static FONT_SUPERSCRIPT_OFFSET_RATIO: f32 = 0.34;
#[derive(Debug, Serialize)]
pub(crate) struct InlineFormattingContext {
- pub(super) inline_level_boxes: Vec<ArcRefCell<InlineLevelBox>>,
+ /// All [`InlineItem`]s in this [`InlineFormattingContext`] stored in a flat array.
+ /// [`InlineItem::StartInlineBox`] and [`InlineItem::EndInlineBox`] allow representing
+ /// the tree of inline boxes within the formatting context, but a flat array allows
+ /// easy iteration through all inline items.
+ pub(super) inline_items: Vec<ArcRefCell<InlineItem>>,
+
+ /// The tree of inline boxes in this [`InlineFormattingContext`]. These are stored in
+ /// a flat array with each being given a [`InlineBoxIdentifier`].
+ pub(super) inline_boxes: InlineBoxes,
/// The text content of this inline formatting context.
pub(super) text_content: String,
@@ -159,8 +167,9 @@ pub(crate) struct FontKeyAndMetrics {
}
#[derive(Debug, Serialize)]
-pub(crate) enum InlineLevelBox {
- InlineBox(InlineBox),
+pub(crate) enum InlineItem {
+ StartInlineBox(InlineBoxIdentifier),
+ EndInlineBox,
TextRun(TextRun),
OutOfFlowAbsolutelyPositionedBox(ArcRefCell<AbsolutelyPositionedBox>),
OutOfFlowFloatBox(FloatBox),
@@ -172,9 +181,10 @@ pub(crate) struct InlineBox {
pub base_fragment_info: BaseFragmentInfo,
#[serde(skip_serializing)]
pub style: Arc<ComputedValues>,
+ /// The identifier of this inline box in the containing [`InlineFormattingContext`].
+ identifier: InlineBoxIdentifier,
pub is_first_fragment: bool,
pub is_last_fragment: bool,
- pub children: Vec<ArcRefCell<InlineLevelBox>>,
/// The index of the default font in the [`InlineFormattingContext`]'s font metrics store.
/// This is initialized during IFC shaping.
pub default_font_index: Option<usize>,
@@ -185,21 +195,19 @@ impl InlineBox {
Self {
base_fragment_info: info.into(),
style: info.style.clone(),
+ identifier: InlineBoxIdentifier::root(),
is_first_fragment: true,
is_last_fragment: false,
- children: vec![],
default_font_index: None,
}
}
pub(crate) fn split_around_block(&self) -> Self {
Self {
- base_fragment_info: self.base_fragment_info,
style: self.style.clone(),
is_first_fragment: false,
is_last_fragment: false,
- children: vec![],
- default_font_index: None,
+ ..*self
}
}
}
@@ -1570,11 +1578,6 @@ impl From<&InheritedText> for SegmentContentFlags {
}
}
-enum InlineFormattingContextIterItem<'a> {
- Item(&'a mut InlineLevelBox),
- EndInlineBox,
-}
-
impl InlineFormattingContext {
pub(super) fn new_with_builder(
builder: InlineFormattingContextBuilder,
@@ -1582,107 +1585,44 @@ impl InlineFormattingContext {
text_decoration_line: TextDecorationLine,
has_first_formatted_line: bool,
) -> Self {
- let mut inline_formatting_context = InlineFormattingContext {
- text_content: String::new(),
- inline_level_boxes: builder.root_inline_boxes,
- font_metrics: Vec::new(),
- text_decoration_line,
- has_first_formatted_line,
- contains_floats: builder.contains_floats,
- };
-
// This is to prevent a double borrow.
let text_content: String = builder.text_segments.into_iter().collect();
let mut font_metrics = Vec::new();
let mut new_linebreaker = LineBreaker::new(text_content.as_str());
- inline_formatting_context.foreach(|iter_item| match iter_item {
- InlineFormattingContextIterItem::Item(InlineLevelBox::TextRun(ref mut text_run)) => {
- text_run.segment_and_shape(
- &text_content,
- &layout_context.font_context,
- &mut new_linebreaker,
- &mut font_metrics,
- );
- },
- InlineFormattingContextIterItem::Item(InlineLevelBox::InlineBox(inline_box)) => {
- if let Some(font) = get_font_for_first_font_for_style(
- &inline_box.style,
- &layout_context.font_context,
- ) {
- inline_box.default_font_index = Some(add_or_get_font(&font, &mut font_metrics));
- }
- },
- InlineFormattingContextIterItem::Item(InlineLevelBox::Atomic(_)) => {},
- _ => {},
- });
-
- inline_formatting_context.text_content = text_content;
- inline_formatting_context.font_metrics = font_metrics;
-
- inline_formatting_context
- }
-
- fn foreach(&self, mut func: impl FnMut(InlineFormattingContextIterItem)) {
- // TODO(mrobinson): Using OwnedRef here we could maybe avoid the second borrow when
- // iterating through members of each inline box.
- struct InlineFormattingContextChildBoxIter {
- inline_level_box: ArcRefCell<InlineLevelBox>,
- next_child_index: usize,
- }
-
- impl InlineFormattingContextChildBoxIter {
- fn next(&mut self) -> Option<ArcRefCell<InlineLevelBox>> {
- let borrowed_item = self.inline_level_box.borrow();
- let inline_box = match *borrowed_item {
- InlineLevelBox::InlineBox(ref inline_box) => inline_box,
- _ => unreachable!(
- "InlineFormattingContextChildBoxIter created for non-InlineBox."
- ),
- };
-
- let item = inline_box.children.get(self.next_child_index).cloned();
- if item.is_some() {
- self.next_child_index += 1;
- }
- item
+ for item in builder.inline_items.iter() {
+ match &mut *item.borrow_mut() {
+ InlineItem::TextRun(ref mut text_run) => {
+ text_run.segment_and_shape(
+ &text_content,
+ &layout_context.font_context,
+ &mut new_linebreaker,
+ &mut font_metrics,
+ );
+ },
+ InlineItem::StartInlineBox(identifier) => {
+ let inline_box = builder.inline_boxes.get(identifier);
+ let inline_box = &mut *inline_box.borrow_mut();
+ if let Some(font) = get_font_for_first_font_for_style(
+ &inline_box.style,
+ &layout_context.font_context,
+ ) {
+ inline_box.default_font_index =
+ Some(add_or_get_font(&font, &mut font_metrics));
+ }
+ },
+ _ => {},
}
}
- let mut inline_box_iterator_stack: Vec<InlineFormattingContextChildBoxIter> = Vec::new();
- let mut root_iterator = self.inline_level_boxes.iter();
- loop {
- let mut item = None;
-
- // First try to get the next item in the current inline box.
- if !inline_box_iterator_stack.is_empty() {
- item = inline_box_iterator_stack
- .last_mut()
- .and_then(|iter| iter.next());
- if item.is_none() {
- func(InlineFormattingContextIterItem::EndInlineBox);
- inline_box_iterator_stack.pop();
- continue;
- }
- }
-
- // If there is no current inline box, then try to get the next item from the root of the IFC.
- item = item.or_else(|| root_iterator.next().cloned());
-
- // If there is no item left, we are done iterating.
- let item = match item {
- Some(item) => item,
- None => return,
- };
-
- let borrowed_item = &mut *item.borrow_mut();
- func(InlineFormattingContextIterItem::Item(borrowed_item));
- if matches!(borrowed_item, InlineLevelBox::InlineBox(_)) {
- inline_box_iterator_stack.push(InlineFormattingContextChildBoxIter {
- inline_level_box: item.clone(),
- next_child_index: 0,
- })
- }
+ InlineFormattingContext {
+ text_content,
+ inline_items: builder.inline_items,
+ inline_boxes: builder.inline_boxes,
+ font_metrics,
+ text_decoration_line,
+ has_first_formatted_line,
+ contains_floats: builder.contains_floats,
}
}
@@ -1764,35 +1704,35 @@ impl InlineFormattingContext {
// FIXME(mrobinson): Collapse margins in the containing block offsets as well??
}
- self.foreach(|item| match item {
- InlineFormattingContextIterItem::Item(item) => {
- // Any new box should flush a pending hard line break.
+ for item in self.inline_items.iter() {
+ let item = &mut *item.borrow_mut();
+
+ // Any new box should flush a pending hard line break.
+ if !matches!(item, InlineItem::EndInlineBox) {
ifc.possibly_flush_deferred_forced_line_break();
+ }
- match item {
- InlineLevelBox::InlineBox(ref inline_box) => {
- ifc.start_inline_box(inline_box);
- },
- InlineLevelBox::TextRun(ref run) => run.layout_into_line_items(&mut ifc),
- InlineLevelBox::Atomic(ref mut atomic_formatting_context) => {
- atomic_formatting_context.layout_into_line_items(layout_context, &mut ifc);
- },
- InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(ref positioned_box) => {
- ifc.push_line_item_to_unbreakable_segment(LineItem::AbsolutelyPositioned(
- AbsolutelyPositionedLineItem {
- absolutely_positioned_box: positioned_box.clone(),
- },
- ));
- },
- InlineLevelBox::OutOfFlowFloatBox(ref mut float_box) => {
- float_box.layout_into_line_items(layout_context, &mut ifc);
- },
- }
- },
- InlineFormattingContextIterItem::EndInlineBox => {
- ifc.finish_inline_box();
- },
- });
+ match item {
+ InlineItem::StartInlineBox(identifier) => {
+ ifc.start_inline_box(&*self.inline_boxes.get(identifier).borrow());
+ },
+ InlineItem::EndInlineBox => ifc.finish_inline_box(),
+ InlineItem::TextRun(run) => run.layout_into_line_items(&mut ifc),
+ InlineItem::Atomic(atomic_formatting_context) => {
+ atomic_formatting_context.layout_into_line_items(layout_context, &mut ifc);
+ },
+ InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
+ ifc.push_line_item_to_unbreakable_segment(LineItem::AbsolutelyPositioned(
+ AbsolutelyPositionedLineItem {
+ absolutely_positioned_box: positioned_box.clone(),
+ },
+ ));
+ },
+ InlineItem::OutOfFlowFloatBox(ref mut float_box) => {
+ float_box.layout_into_line_items(layout_context, &mut ifc);
+ },
+ }
+ }
ifc.finish_last_line();
@@ -2377,11 +2317,26 @@ struct ContentSizesComputation<'a> {
impl<'a> ContentSizesComputation<'a> {
fn traverse(mut self, inline_formatting_context: &InlineFormattingContext) -> ContentSizes {
- inline_formatting_context.foreach(|iter_item| match iter_item {
- InlineFormattingContextIterItem::Item(InlineLevelBox::InlineBox(inline_box)) => {
+ for inline_item in inline_formatting_context.inline_items.iter() {
+ self.process_item(&mut *inline_item.borrow_mut(), inline_formatting_context);
+ }
+
+ self.forced_line_break();
+ self.paragraph
+ }
+
+ fn process_item(
+ &mut self,
+ inline_item: &mut InlineItem,
+ inline_formatting_context: &InlineFormattingContext,
+ ) {
+ match inline_item {
+ InlineItem::StartInlineBox(identifier) => {
// For margins and paddings, a cyclic percentage is resolved against zero
// for determining intrinsic size contributions.
// https://drafts.csswg.org/css-sizing-3/#min-percentage-contribution
+ let inline_box = inline_formatting_context.inline_boxes.get(identifier);
+ let inline_box = inline_box.borrow();
let zero = Length::zero();
let padding = inline_box
.style
@@ -2406,14 +2361,14 @@ impl<'a> ContentSizesComputation<'a> {
self.ending_inline_pbm_stack.push(Length::zero());
}
},
- InlineFormattingContextIterItem::EndInlineBox => {
+ InlineItem::EndInlineBox => {
let length = self
.ending_inline_pbm_stack
.pop()
.unwrap_or_else(Length::zero);
self.add_length(length);
},
- InlineFormattingContextIterItem::Item(InlineLevelBox::TextRun(text_run)) => {
+ InlineItem::TextRun(text_run) => {
for segment in text_run.shaped_text.iter() {
// TODO: This should take account whether or not the first and last character prevent
// linebreaks after atomics as in layout.
@@ -2460,7 +2415,7 @@ impl<'a> ContentSizesComputation<'a> {
}
}
},
- InlineFormattingContextIterItem::Item(InlineLevelBox::Atomic(atomic)) => {
+ InlineItem::Atomic(atomic) => {
let outer = atomic.outer_inline_content_sizes(
self.layout_context,
self.containing_block_writing_mode,
@@ -2471,10 +2426,7 @@ impl<'a> ContentSizesComputation<'a> {
self.had_content_yet = true;
},
_ => {},
- });
-
- self.forced_line_break();
- self.paragraph
+ }
}
fn add_length(&mut self, l: Length) {
@@ -2522,3 +2474,36 @@ impl<'a> ContentSizesComputation<'a> {
.traverse(inline_formatting_context)
}
}
+
+#[derive(Debug, Default, Serialize)]
+pub(crate) struct InlineBoxes {
+ inline_boxes: Vec<ArcRefCell<InlineBox>>,
+}
+
+impl InlineBoxes {
+ pub(super) fn get(&self, identifier: &InlineBoxIdentifier) -> ArcRefCell<InlineBox> {
+ self.inline_boxes[identifier.index].clone()
+ }
+
+ pub(super) fn end_inline_box(&mut self) {}
+
+ pub(super) fn start_inline_box(&mut self, inline_box: InlineBox) -> InlineBoxIdentifier {
+ let identifier = InlineBoxIdentifier {
+ index: self.inline_boxes.len(),
+ };
+
+ self.inline_boxes.push(ArcRefCell::new(inline_box));
+ identifier
+ }
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Serialize)]
+pub(crate) struct InlineBoxIdentifier {
+ pub index: usize,
+}
+
+impl InlineBoxIdentifier {
+ fn root() -> Self {
+ InlineBoxIdentifier { index: 0 }
+ }
+}