1use layout_api::LayoutNode;
6use rayon::iter::{IntoParallelIterator, ParallelIterator};
7use servo_arc::Arc;
8use style::properties::ComputedValues;
9use style::properties::longhands::list_style_position::computed_value::T as ListStylePosition;
10use style::selector_parser::PseudoElement;
11use style::str::char_is_whitespace;
12use style::values::specified::box_::DisplayOutside as StyloDisplayOutside;
13
14use super::OutsideMarker;
15use super::inline::construct::InlineFormattingContextBuilder;
16use super::inline::inline_box::InlineBox;
17use super::inline::{InlineFormattingContext, SharedInlineStyles};
18use crate::PropagatedBoxTreeData;
19use crate::cell::ArcRefCell;
20use crate::context::LayoutContext;
21use crate::dom::{BoxSlot, LayoutBox, NodeExt};
22use crate::dom_traversal::{
23 BoxTreeString, Contents, NodeAndStyleInfo, NonReplacedContents, PseudoElementContentItem,
24 TraversalHandler,
25};
26use crate::flow::float::FloatBox;
27use crate::flow::same_formatting_context_block::SameFormattingContextBlock;
28use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox};
29use crate::formatting_contexts::{
30 IndependentFormattingContext, IndependentFormattingContextContents,
31};
32use crate::fragment_tree::FragmentFlags;
33use crate::layout_box_base::LayoutBoxBase;
34use crate::positioned::AbsolutelyPositionedBox;
35use crate::style_ext::{ComputedValuesExt, DisplayGeneratingBox, DisplayInside, DisplayOutside};
36use crate::table::{AnonymousTableContent, AnonymousTableContentElement, Table};
37
38impl BlockFormattingContext {
39 pub(crate) fn construct(
40 context: &LayoutContext,
41 info: &NodeAndStyleInfo<'_>,
42 contents: NonReplacedContents,
43 propagated_data: PropagatedBoxTreeData,
44 is_list_item: bool,
45 ) -> Self {
46 Self::from_block_container(BlockContainer::construct(
47 context,
48 info,
49 contents,
50 propagated_data,
51 is_list_item,
52 ))
53 }
54
55 pub(crate) fn from_block_container(contents: BlockContainer) -> Self {
56 let contains_floats = contents.contains_floats();
57 Self {
58 contents,
59 contains_floats,
60 }
61 }
62}
63
64struct BlockLevelJob<'dom> {
65 info: NodeAndStyleInfo<'dom>,
66 box_slot: BoxSlot<'dom>,
67 propagated_data: PropagatedBoxTreeData,
68 kind: BlockLevelCreator,
69}
70
71pub(crate) enum BlockLevelCreator {
72 SameFormattingContextBlock(IntermediateBlockContainer),
73 Independent {
74 display_inside: DisplayInside,
75 contents: Contents,
76 },
77 OutOfFlowAbsolutelyPositionedBox {
78 display_inside: DisplayInside,
79 contents: Contents,
80 },
81 OutOfFlowFloatBox {
82 display_inside: DisplayInside,
83 contents: Contents,
84 },
85 OutsideMarker {
86 list_item_style: Arc<ComputedValues>,
87 contents: Vec<PseudoElementContentItem>,
88 },
89 AnonymousTable {
90 table_block: ArcRefCell<BlockLevelBox>,
91 },
92}
93
94impl BlockLevelCreator {
95 pub(crate) fn new_for_inflow_block_level_element<'dom>(
96 info: &NodeAndStyleInfo<'dom>,
97 display_inside: DisplayInside,
98 contents: Contents,
99 propagated_data: PropagatedBoxTreeData,
100 ) -> Self {
101 match contents {
102 Contents::NonReplaced(contents) => match display_inside {
103 DisplayInside::Flow { is_list_item }
104 if !info.style.establishes_block_formatting_context(
109 FragmentFlags::empty()
110 ) =>
111 {
112 Self::SameFormattingContextBlock(
113 IntermediateBlockContainer::Deferred {
114 contents,
115 propagated_data,
116 is_list_item,
117 },
118 )
119 },
120 _ => Self::Independent {
121 display_inside,
122 contents: Contents::NonReplaced(contents),
123 },
124 },
125 Contents::Replaced(_) | Contents::Widget(_) => Self::Independent {
126 display_inside,
127 contents,
128 },
129 }
130 }
131}
132
133pub(crate) enum IntermediateBlockContainer {
141 InlineFormattingContext(BlockContainer),
142 Deferred {
143 contents: NonReplacedContents,
144 propagated_data: PropagatedBoxTreeData,
145 is_list_item: bool,
146 },
147}
148
149pub(crate) struct BlockContainerBuilder<'dom, 'style> {
154 context: &'style LayoutContext<'style>,
155
156 info: &'style NodeAndStyleInfo<'dom>,
159
160 block_level_boxes: Vec<BlockLevelJob<'dom>>,
174
175 have_already_seen_first_formatted_line: bool,
180
181 propagated_data: PropagatedBoxTreeData,
183
184 inline_formatting_context_builder: Option<InlineFormattingContextBuilder>,
189
190 anonymous_box_info: Option<NodeAndStyleInfo<'dom>>,
193
194 anonymous_table_content: Vec<AnonymousTableContent<'dom>>,
198
199 display_contents_shared_styles: Vec<SharedInlineStyles>,
203}
204
205impl BlockContainer {
206 pub fn construct(
207 context: &LayoutContext,
208 info: &NodeAndStyleInfo<'_>,
209 contents: NonReplacedContents,
210 propagated_data: PropagatedBoxTreeData,
211 is_list_item: bool,
212 ) -> BlockContainer {
213 let mut builder = BlockContainerBuilder::new(context, info, propagated_data);
214
215 if is_list_item &&
216 let Some((marker_info, marker_contents)) = crate::lists::make_marker(context, info)
217 {
218 match marker_info.style.get_list_style_position() {
219 ListStylePosition::Inside => {
220 builder.handle_list_item_marker_inside(&marker_info, marker_contents)
221 },
222 ListStylePosition::Outside => builder.handle_list_item_marker_outside(
223 &marker_info,
224 marker_contents,
225 info.style.clone(),
226 ),
227 }
228 }
229
230 contents.traverse(context, info, &mut builder);
231 builder.finish()
232 }
233}
234
235impl<'dom, 'style> BlockContainerBuilder<'dom, 'style> {
236 pub(crate) fn new(
237 context: &'style LayoutContext,
238 info: &'style NodeAndStyleInfo<'dom>,
239 propagated_data: PropagatedBoxTreeData,
240 ) -> Self {
241 BlockContainerBuilder {
242 context,
243 info,
244 block_level_boxes: Vec::new(),
245 propagated_data,
246 have_already_seen_first_formatted_line: false,
247 anonymous_box_info: None,
248 anonymous_table_content: Vec::new(),
249 inline_formatting_context_builder: None,
250 display_contents_shared_styles: Vec::new(),
251 }
252 }
253
254 fn currently_processing_inline_box(&self) -> bool {
255 self.inline_formatting_context_builder
256 .as_ref()
257 .is_some_and(InlineFormattingContextBuilder::currently_processing_inline_box)
258 }
259
260 fn ensure_inline_formatting_context_builder(&mut self) -> &mut InlineFormattingContextBuilder {
261 self.inline_formatting_context_builder
262 .get_or_insert_with(|| {
263 let should_process_first_letter = !self.have_already_seen_first_formatted_line;
265 let mut builder = InlineFormattingContextBuilder::new(
266 self.info,
267 self.context,
268 should_process_first_letter,
269 );
270 for shared_inline_styles in self.display_contents_shared_styles.iter() {
271 builder.enter_display_contents(shared_inline_styles.clone());
272 }
273 builder
274 })
275 }
276
277 fn finish_ongoing_inline_formatting_context(&mut self) -> Option<InlineFormattingContext> {
278 self.inline_formatting_context_builder.take()?.finish(
279 self.context,
280 !self.have_already_seen_first_formatted_line,
281 self.info.node.is_single_line_text_input(),
282 self.info.style.to_bidi_level(),
283 )
284 }
285
286 pub(crate) fn finish(mut self) -> BlockContainer {
287 debug_assert!(!self.currently_processing_inline_box());
288
289 self.finish_anonymous_table_if_needed();
290
291 if let Some(inline_formatting_context) = self.finish_ongoing_inline_formatting_context() {
292 if self.block_level_boxes.is_empty() {
296 return BlockContainer::InlineFormattingContext(inline_formatting_context);
297 }
298 self.push_block_level_job_for_inline_formatting_context(inline_formatting_context);
299 }
300
301 let context = self.context;
302 let block_level_boxes = if self
303 .context
304 .should_parallelize(self.block_level_boxes.len())
305 {
306 self.block_level_boxes
307 .into_par_iter()
308 .map(|block_level_job| block_level_job.finish(context))
309 .collect()
310 } else {
311 self.block_level_boxes
312 .into_iter()
313 .map(|block_level_job| block_level_job.finish(context))
314 .collect()
315 };
316
317 BlockContainer::BlockLevelBoxes(block_level_boxes)
318 }
319
320 fn finish_anonymous_table_if_needed(&mut self) {
321 if self.anonymous_table_content.is_empty() {
322 return;
323 }
324
325 let inline_table = self.currently_processing_inline_box();
333
334 let mut contents: Vec<AnonymousTableContent<'dom>> =
335 std::mem::take(&mut self.anonymous_table_content);
336 let last_element_index = contents
337 .iter()
338 .rposition(|content| matches!(content, AnonymousTableContent::Element { .. }))
339 .expect("Anonymous table contents should include some table-level element");
340 let trailing_contents = contents.split_off(last_element_index + 1);
341
342 let (table_info, ifc) = Table::construct_anonymous(
343 self.context,
344 self,
345 self.info,
346 contents,
347 self.propagated_data,
348 );
349
350 if inline_table {
351 self.ensure_inline_formatting_context_builder()
352 .push_atomic(|| ArcRefCell::new(ifc), None);
353 } else {
354 let table_block = ArcRefCell::new(BlockLevelBox::Independent(ifc));
355
356 if let Some(inline_formatting_context) = self.finish_ongoing_inline_formatting_context()
357 {
358 self.push_block_level_job_for_inline_formatting_context(inline_formatting_context);
359 }
360
361 let box_slot = table_info.node.box_slot();
362 self.block_level_boxes.push(BlockLevelJob {
363 info: table_info,
364 box_slot,
365 kind: BlockLevelCreator::AnonymousTable { table_block },
366 propagated_data: self.propagated_data,
367 });
368 }
369
370 for content in trailing_contents {
380 match content {
381 AnonymousTableContent::Text(info, text) => self.handle_text(&info, text),
382 AnonymousTableContent::EnterDisplayContents(styles) => {
383 self.enter_display_contents(styles)
384 },
385 AnonymousTableContent::LeaveDisplayContents => self.leave_display_contents(),
386 AnonymousTableContent::Element { .. } => {
387 unreachable!("All elements were placed inside the table")
388 },
389 }
390 }
391 }
392}
393
394impl<'dom> TraversalHandler<'dom> for BlockContainerBuilder<'dom, '_> {
395 fn handle_element(
396 &mut self,
397 info: &NodeAndStyleInfo<'dom>,
398 display: DisplayGeneratingBox,
399 contents: Contents,
400 box_slot: BoxSlot<'dom>,
401 ) {
402 match display {
403 DisplayGeneratingBox::OutsideInside { outside, inside } => {
404 self.finish_anonymous_table_if_needed();
405
406 match outside {
407 DisplayOutside::Inline => {
408 self.handle_inline_level_element(info, inside, contents, box_slot)
409 },
410 DisplayOutside::Block => {
411 let box_style = info.style.get_box();
412 if box_style.position.is_absolutely_positioned() {
415 self.handle_absolutely_positioned_element(
416 info, inside, contents, box_slot,
417 )
418 } else if box_style.float.is_floating() {
419 self.handle_float_element(info, inside, contents, box_slot)
420 } else {
421 self.handle_block_level_element(info, inside, contents, box_slot)
422 }
423 },
424 };
425 },
426 DisplayGeneratingBox::LayoutInternal(_) => {
427 self.anonymous_table_content
428 .push(AnonymousTableContent::Element(Box::new(
429 AnonymousTableContentElement {
430 info: info.clone(),
431 display,
432 contents,
433 box_slot,
434 },
435 )));
436 },
437 }
438 }
439
440 fn handle_text(&mut self, info: &NodeAndStyleInfo<'dom>, text: BoxTreeString<'dom>) {
441 if text.is_empty() && !info.node.text_node_needs_caret_placeholder() {
442 return;
443 }
444
445 if !self.anonymous_table_content.is_empty() && text.chars().all(char_is_whitespace) {
449 self.anonymous_table_content
450 .push(AnonymousTableContent::Text(info.clone(), text));
451 return;
452 } else {
453 self.finish_anonymous_table_if_needed();
454 }
455
456 self.ensure_inline_formatting_context_builder();
457 self.inline_formatting_context_builder
458 .as_mut()
459 .expect("Should be guaranteed by line above")
460 .push_text_with_possible_first_letter(text, info, self.info, self.context);
461 }
462
463 fn enter_display_contents(&mut self, styles: SharedInlineStyles) {
464 if !self.anonymous_table_content.is_empty() {
465 self.anonymous_table_content
466 .push(AnonymousTableContent::EnterDisplayContents(styles));
467 return;
468 }
469 self.display_contents_shared_styles.push(styles.clone());
470 if let Some(builder) = self.inline_formatting_context_builder.as_mut() {
471 builder.enter_display_contents(styles);
472 }
473 }
474
475 fn leave_display_contents(&mut self) {
476 if !self.anonymous_table_content.is_empty() {
477 self.anonymous_table_content
478 .push(AnonymousTableContent::LeaveDisplayContents);
479 return;
480 }
481 self.display_contents_shared_styles.pop();
482 if let Some(builder) = self.inline_formatting_context_builder.as_mut() {
483 builder.leave_display_contents();
484 }
485 }
486}
487
488impl<'dom> BlockContainerBuilder<'dom, '_> {
489 fn handle_list_item_marker_inside(
490 &mut self,
491 marker_info: &NodeAndStyleInfo<'dom>,
492 contents: Vec<crate::dom_traversal::PseudoElementContentItem>,
493 ) {
494 let box_slot = marker_info.node.box_slot();
495 self.handle_inline_level_element(
496 marker_info,
497 DisplayInside::Flow {
498 is_list_item: false,
499 },
500 Contents::for_pseudo_element(contents),
501 box_slot,
502 );
503 }
504
505 fn handle_list_item_marker_outside(
506 &mut self,
507 marker_info: &NodeAndStyleInfo<'dom>,
508 contents: Vec<crate::dom_traversal::PseudoElementContentItem>,
509 list_item_style: Arc<ComputedValues>,
510 ) {
511 let box_slot = marker_info.node.box_slot();
512 self.block_level_boxes.push(BlockLevelJob {
513 info: marker_info.clone(),
514 box_slot,
515 kind: BlockLevelCreator::OutsideMarker {
516 contents,
517 list_item_style,
518 },
519 propagated_data: self.propagated_data,
520 });
521 }
522
523 fn handle_inline_level_element(
524 &mut self,
525 info: &NodeAndStyleInfo<'dom>,
526 display_inside: DisplayInside,
527 contents: Contents,
528 box_slot: BoxSlot<'dom>,
529 ) {
530 let context = self.context;
531 let old_layout_box = box_slot.take_layout_box();
532 let (is_list_item, non_replaced_contents) = match (display_inside, contents) {
533 (
534 DisplayInside::Flow { is_list_item },
535 Contents::NonReplaced(non_replaced_contents),
536 ) => (is_list_item, non_replaced_contents),
537 (_, contents) => {
538 let propagated_data = self.propagated_data;
540
541 let construction_callback = || {
542 ArcRefCell::new(IndependentFormattingContext::construct(
543 context,
544 info,
545 display_inside,
546 contents,
547 propagated_data,
548 ))
549 };
550
551 let atomic = self
552 .ensure_inline_formatting_context_builder()
553 .push_atomic(construction_callback, old_layout_box);
554 box_slot.set(LayoutBox::InlineLevel(atomic));
555 return;
556 },
557 };
558
559 let inline_builder = self.ensure_inline_formatting_context_builder();
562 let inline_item = inline_builder.start_inline_box(
563 || ArcRefCell::new(InlineBox::new(info, context)),
564 old_layout_box,
565 );
566 box_slot.set(LayoutBox::InlineLevel(inline_item));
567
568 if info.node.is_html_wbr_element() {
569 inline_builder.push_soft_wrap_opportunity();
570 }
571
572 if is_list_item &&
573 let Some((marker_info, marker_contents)) =
574 crate::lists::make_marker(self.context, info)
575 {
576 self.handle_list_item_marker_inside(&marker_info, marker_contents)
580 }
581
582 non_replaced_contents.traverse(self.context, info, self);
583
584 self.finish_anonymous_table_if_needed();
585
586 self.inline_formatting_context_builder
587 .as_mut()
588 .expect("Should be building an InlineFormattingContext")
589 .end_inline_box();
590 }
591
592 fn handle_block_level_element(
593 &mut self,
594 info: &NodeAndStyleInfo<'dom>,
595 display_inside: DisplayInside,
596 contents: Contents,
597 box_slot: BoxSlot<'dom>,
598 ) {
599 let propagated_data = self.propagated_data;
600 let kind = BlockLevelCreator::new_for_inflow_block_level_element(
601 info,
602 display_inside,
603 contents,
604 propagated_data,
605 );
606 let job = BlockLevelJob {
607 info: info.clone(),
608 box_slot,
609 kind,
610 propagated_data,
611 };
612 if let Some(builder) = self.inline_formatting_context_builder.as_mut() {
613 if builder.currently_processing_inline_box() {
614 builder.push_block_level_box(job.finish(self.context));
615 return;
616 }
617 if let Some(context) = self.finish_ongoing_inline_formatting_context() {
618 self.push_block_level_job_for_inline_formatting_context(context);
619 }
620 }
621 self.block_level_boxes.push(job);
622
623 self.have_already_seen_first_formatted_line = true;
626 }
627
628 fn handle_absolutely_positioned_element(
629 &mut self,
630 info: &NodeAndStyleInfo<'dom>,
631 display_inside: DisplayInside,
632 contents: Contents,
633 box_slot: BoxSlot<'dom>,
634 ) {
635 let needs_inline_builder =
641 info.style.get_box().original_display.outside() == StyloDisplayOutside::Inline;
642 if needs_inline_builder {
643 self.ensure_inline_formatting_context_builder();
644 }
645 let inline_builder = self
646 .inline_formatting_context_builder
647 .as_mut()
648 .filter(|builder| needs_inline_builder || !builder.is_empty);
649 if let Some(inline_builder) = inline_builder {
650 let constructor = || {
651 ArcRefCell::new(AbsolutelyPositionedBox::construct(
652 self.context,
653 info,
654 display_inside,
655 contents,
656 ))
657 };
658 let old_layout_box = box_slot.take_layout_box();
659 let inline_level_box =
660 inline_builder.push_absolutely_positioned_box(constructor, old_layout_box);
661 box_slot.set(LayoutBox::InlineLevel(inline_level_box));
662 return;
663 }
664
665 let kind = BlockLevelCreator::OutOfFlowAbsolutelyPositionedBox {
666 contents,
667 display_inside,
668 };
669 self.block_level_boxes.push(BlockLevelJob {
670 info: info.clone(),
671 box_slot,
672 kind,
673 propagated_data: self.propagated_data,
674 });
675 }
676
677 fn handle_float_element(
678 &mut self,
679 info: &NodeAndStyleInfo<'dom>,
680 display_inside: DisplayInside,
681 contents: Contents,
682 box_slot: BoxSlot<'dom>,
683 ) {
684 if let Some(builder) = self.inline_formatting_context_builder.as_mut() &&
685 !builder.is_empty
686 {
687 let constructor = || {
688 ArcRefCell::new(FloatBox::construct(
689 self.context,
690 info,
691 display_inside,
692 contents,
693 self.propagated_data,
694 ))
695 };
696 let old_layout_box = box_slot.take_layout_box();
697 let inline_level_box = builder.push_float_box(constructor, old_layout_box);
698 box_slot.set(LayoutBox::InlineLevel(inline_level_box));
699 return;
700 }
701
702 let kind = BlockLevelCreator::OutOfFlowFloatBox {
703 contents,
704 display_inside,
705 };
706 self.block_level_boxes.push(BlockLevelJob {
707 info: info.clone(),
708 box_slot,
709 kind,
710 propagated_data: self.propagated_data,
711 });
712 }
713
714 fn push_block_level_job_for_inline_formatting_context(
715 &mut self,
716 inline_formatting_context: InlineFormattingContext,
717 ) {
718 let layout_context = self.context;
719 let anonymous_info = self
720 .anonymous_box_info
721 .get_or_insert_with(|| {
722 self.info
723 .with_pseudo_element(layout_context, PseudoElement::ServoAnonymousBox)
724 .expect("Should never fail to create anonymous box")
725 })
726 .clone();
727
728 let box_slot = anonymous_info.node.box_slot();
729 self.block_level_boxes.push(BlockLevelJob {
730 info: anonymous_info,
731 box_slot,
732 kind: BlockLevelCreator::SameFormattingContextBlock(
733 IntermediateBlockContainer::InlineFormattingContext(
734 BlockContainer::InlineFormattingContext(inline_formatting_context),
735 ),
736 ),
737 propagated_data: self.propagated_data,
738 });
739
740 self.have_already_seen_first_formatted_line = true;
741 }
742}
743
744impl BlockLevelJob<'_> {
745 fn finish(self, context: &LayoutContext) -> ArcRefCell<BlockLevelBox> {
746 let info = &self.info;
747
748 if let Some(block_level_box) = match &*self.box_slot.slot.borrow() {
751 Some(LayoutBox::BlockLevel(block_level_box)) => Some(block_level_box.clone()),
752 _ => None,
753 } {
754 return block_level_box;
755 }
756
757 let block_level_box = match self.kind {
758 BlockLevelCreator::SameFormattingContextBlock(intermediate_block_container) => {
759 let contents = intermediate_block_container.finish(context, info);
760 let contains_floats = contents.contains_floats();
761
762 let base = LayoutBoxBase::new(info.into(), info.style.clone());
763 base.set_subtree_size(contents.subtree_size() + 1);
764
765 ArcRefCell::new(BlockLevelBox::SameFormattingContextBlock(
766 SameFormattingContextBlock::new(base, contents, contains_floats),
767 ))
768 },
769 BlockLevelCreator::Independent {
770 display_inside,
771 contents,
772 } => {
773 let context = IndependentFormattingContext::construct(
774 context,
775 info,
776 display_inside,
777 contents,
778 self.propagated_data,
779 );
780 ArcRefCell::new(BlockLevelBox::Independent(context))
781 },
782 BlockLevelCreator::OutOfFlowAbsolutelyPositionedBox {
783 display_inside,
784 contents,
785 } => ArcRefCell::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(
786 ArcRefCell::new(AbsolutelyPositionedBox::construct(
787 context,
788 info,
789 display_inside,
790 contents,
791 )),
792 )),
793 BlockLevelCreator::OutOfFlowFloatBox {
794 display_inside,
795 contents,
796 } => ArcRefCell::new(BlockLevelBox::OutOfFlowFloatBox(FloatBox::construct(
797 context,
798 info,
799 display_inside,
800 contents,
801 self.propagated_data,
802 ))),
803 BlockLevelCreator::OutsideMarker {
804 contents,
805 list_item_style,
806 } => {
807 let contents = NonReplacedContents::OfPseudoElement(contents);
808 let block_container = BlockContainer::construct(
809 context,
810 info,
811 contents,
812 self.propagated_data,
813 false, );
815 let block_formatting_context = BlockFormattingContext {
817 contents: block_container,
818 contains_floats: false,
819 };
820 ArcRefCell::new(BlockLevelBox::OutsideMarker(OutsideMarker {
821 context: IndependentFormattingContext::new(
822 LayoutBoxBase::new(info.into(), info.style.clone()),
823 IndependentFormattingContextContents::Flow(block_formatting_context),
824 self.propagated_data,
825 ),
826 list_item_style,
827 }))
828 },
829 BlockLevelCreator::AnonymousTable { table_block } => table_block,
830 };
831 self.box_slot
832 .set(LayoutBox::BlockLevel(block_level_box.clone()));
833 block_level_box
834 }
835}
836
837impl IntermediateBlockContainer {
838 fn finish(self, context: &LayoutContext, info: &NodeAndStyleInfo<'_>) -> BlockContainer {
839 match self {
840 IntermediateBlockContainer::Deferred {
841 contents,
842 propagated_data,
843 is_list_item,
844 } => BlockContainer::construct(context, info, contents, propagated_data, is_list_item),
845 IntermediateBlockContainer::InlineFormattingContext(block_container) => block_container,
846 }
847 }
848}