1use std::iter::repeat_n;
6
7use atomic_refcell::AtomicRef;
8use layout_api::LayoutNode;
9use log::warn;
10use servo_arc::Arc;
11use style::properties::ComputedValues;
12use style::properties::style_structs::Font;
13use style::selector_parser::PseudoElement;
14use style::str::char_is_whitespace;
15
16use super::{
17 Table, TableCaption, TableLevelBox, TableSlot, TableSlotCell, TableSlotCoordinates,
18 TableSlotOffset, TableTrack, TableTrackGroup, TableTrackGroupType,
19};
20use crate::cell::ArcRefCell;
21use crate::context::LayoutContext;
22use crate::dom::{BoxSlot, LayoutBox, NodeExt};
23use crate::dom_traversal::{
24 BoxTreeString, Contents, NodeAndStyleInfo, NonReplacedContents, TraversalHandler,
25};
26use crate::flow::inline::SharedInlineStyles;
27use crate::flow::{BlockContainerBuilder, BlockFormattingContext};
28use crate::formatting_contexts::{
29 IndependentFormattingContext, IndependentFormattingContextContents,
30};
31use crate::fragment_tree::BaseFragmentInfo;
32use crate::layout_box_base::LayoutBoxBase;
33use crate::style_ext::{DisplayGeneratingBox, DisplayLayoutInternal};
34use crate::{PropagatedBoxTreeData, SharedStyle};
35
36#[derive(Debug)]
38pub(super) struct ResolvedSlotAndLocation<'a> {
39 pub cell: AtomicRef<'a, TableSlotCell>,
40 pub coords: TableSlotCoordinates,
41}
42
43impl ResolvedSlotAndLocation<'_> {
44 fn covers_cell_at(&self, coords: TableSlotCoordinates) -> bool {
45 let covered_in_x =
46 coords.x >= self.coords.x && coords.x < self.coords.x + self.cell.colspan;
47 let covered_in_y = coords.y >= self.coords.y &&
48 (self.cell.rowspan == 0 || coords.y < self.coords.y + self.cell.rowspan);
49 covered_in_x && covered_in_y
50 }
51}
52
53pub(crate) struct AnonymousTableContentElement<'dom> {
54 pub(crate) info: NodeAndStyleInfo<'dom>,
55 pub(crate) display: DisplayGeneratingBox,
56 pub(crate) contents: Contents,
57 pub(crate) box_slot: BoxSlot<'dom>,
58}
59
60pub(crate) enum AnonymousTableContent<'dom> {
61 Text(NodeAndStyleInfo<'dom>, BoxTreeString<'dom>),
62 EnterDisplayContents(SharedInlineStyles),
63 LeaveDisplayContents,
64 Element(Box<AnonymousTableContentElement<'dom>>),
65}
66
67impl AnonymousTableContent<'_> {
68 fn is_whitespace_only(&self) -> bool {
69 match self {
70 Self::Element { .. } => false,
71 Self::Text(_, text) => text.chars().all(char_is_whitespace),
72 Self::EnterDisplayContents(_) | Self::LeaveDisplayContents => true,
73 }
74 }
75
76 fn remove_whitespace_only(contents: &mut Vec<Self>) -> bool {
79 if !contents.iter().all(Self::is_whitespace_only) {
80 return false;
81 }
82 let mut enter_display_contents = vec![];
83 for content in contents.drain(..) {
84 match content {
85 AnonymousTableContent::EnterDisplayContents(_) => {
86 enter_display_contents.push(content);
87 },
88 AnonymousTableContent::LeaveDisplayContents => {
89 enter_display_contents.pop();
90 },
91 _ => {},
92 }
93 }
94 std::mem::swap(contents, &mut enter_display_contents);
95 true
96 }
97}
98
99impl Table {
100 pub(crate) fn construct(
101 context: &LayoutContext,
102 info: &NodeAndStyleInfo,
103 grid_style: Arc<ComputedValues>,
104 contents: NonReplacedContents,
105 propagated_data: PropagatedBoxTreeData,
106 ) -> Self {
107 let mut traversal = TableBuilderTraversal::new(context, info, grid_style, propagated_data);
108 contents.traverse(context, info, &mut traversal);
109 traversal.finish()
110 }
111
112 pub(crate) fn construct_anonymous<'dom>(
113 context: &LayoutContext,
114 parent: &mut impl TraversalHandler<'dom>,
115 parent_info: &NodeAndStyleInfo<'dom>,
116 contents: Vec<AnonymousTableContent<'dom>>,
117 propagated_data: PropagatedBoxTreeData,
118 ) -> (NodeAndStyleInfo<'dom>, IndependentFormattingContext) {
119 let table_info = parent_info
120 .with_pseudo_element(context, PseudoElement::ServoAnonymousTable)
121 .expect("Should never fail to create anonymous table info.");
122 let table_style = table_info.style.clone();
123 let mut table_builder =
124 TableBuilderTraversal::new(context, &table_info, table_style.clone(), propagated_data);
125
126 for content in contents {
127 match content {
128 AnonymousTableContent::Element(element) => {
129 table_builder.handle_element(
130 &element.info,
131 element.display,
132 element.contents,
133 element.box_slot,
134 );
135 },
136 AnonymousTableContent::Text(..) => {
137 },
141 AnonymousTableContent::EnterDisplayContents(styles) => {
145 parent.enter_display_contents(styles)
146 },
147 AnonymousTableContent::LeaveDisplayContents => parent.leave_display_contents(),
148 }
149 }
150
151 let mut table = table_builder.finish();
152 table.anonymous = true;
153
154 let ifc = IndependentFormattingContext::new(
155 LayoutBoxBase::new((&table_info).into(), table_style),
156 IndependentFormattingContextContents::Table(table),
157 propagated_data,
158 );
159
160 (table_info, ifc)
161 }
162
163 fn push_new_slot_to_last_row(&mut self, slot: TableSlot) {
165 let last_row = match self.slots.last_mut() {
166 Some(row) => row,
167 None => {
168 unreachable!("Should have some rows before calling `push_new_slot_to_last_row`")
169 },
170 };
171
172 self.size.width = self.size.width.max(last_row.len() + 1);
173 last_row.push(slot);
174 }
175
176 pub(super) fn resolve_slot_at(
182 &self,
183 coords: TableSlotCoordinates,
184 ) -> Vec<ResolvedSlotAndLocation<'_>> {
185 let slot = self.get_slot(coords);
186 match slot {
187 Some(TableSlot::Cell(cell)) => vec![ResolvedSlotAndLocation {
188 cell: cell.borrow(),
189 coords,
190 }],
191 Some(TableSlot::Spanned(offsets)) => offsets
192 .iter()
193 .flat_map(|offset| self.resolve_slot_at(coords - *offset))
194 .collect(),
195 Some(TableSlot::Empty) | None => {
196 warn!("Tried to resolve an empty or nonexistant slot!");
197 vec![]
198 },
199 }
200 }
201}
202
203impl TableSlot {
204 pub fn push_spanned(&mut self, new_offset: TableSlotOffset) {
206 match *self {
207 TableSlot::Cell { .. } => {
208 panic!(
209 "Should never have a table model error with an originating cell slot overlapping a spanned slot"
210 )
211 },
212 TableSlot::Spanned(ref mut vec) => vec.insert(0, new_offset),
213 TableSlot::Empty => {
214 panic!("Should never have a table model error with an empty slot");
215 },
216 }
217 }
218}
219
220pub struct TableBuilder {
221 table: Table,
223
224 pub incoming_rowspans: Vec<isize>,
234}
235
236impl TableBuilder {
237 pub(super) fn new(
238 style: Arc<ComputedValues>,
239 grid_style: Arc<ComputedValues>,
240 base_fragment_info: BaseFragmentInfo,
241 percentage_columns_allowed_for_inline_content_sizes: bool,
242 ) -> Self {
243 Self {
244 table: Table::new(
245 style,
246 grid_style,
247 base_fragment_info,
248 percentage_columns_allowed_for_inline_content_sizes,
249 ),
250 incoming_rowspans: Vec::new(),
251 }
252 }
253
254 pub fn new_for_tests() -> Self {
255 let testing_style =
256 ComputedValues::initial_values_with_font_override(Font::initial_values());
257 Self::new(
258 testing_style.clone(),
259 testing_style,
260 BaseFragmentInfo::anonymous(),
261 true, )
263 }
264
265 pub fn last_row_index_in_row_group_at_row_n(&self, n: usize) -> usize {
266 for row_group in self.table.row_groups.iter() {
270 let row_group = row_group.borrow();
271 if row_group.track_range.start > n {
272 return row_group.track_range.start - 1;
273 }
274 }
275 self.table.size.height - 1
276 }
277
278 pub fn finish(mut self) -> Table {
279 self.adjust_table_geometry_for_columns_and_colgroups();
280 self.do_missing_cells_fixup();
281 self.reorder_first_thead_and_tfoot();
282 self.do_final_rowspan_calculation();
283 self.table
284 }
285
286 fn do_missing_cells_fixup(&mut self) {
289 for row in self.table.slots.iter_mut() {
290 row.resize_with(self.table.size.width, || TableSlot::Empty);
291 }
292 }
293
294 fn adjust_table_geometry_for_columns_and_colgroups(&mut self) {
300 if self.table.rows.is_empty() && self.table.row_groups.is_empty() {
301 self.table.columns.clear();
302 self.table.column_groups.clear();
303 } else {
304 self.table.size.width = self.table.size.width.max(self.table.columns.len());
305 }
306 }
307
308 fn reorder_first_thead_and_tfoot(&mut self) {
313 let mut thead_index = None;
314 let mut tfoot_index = None;
315 for (row_group_index, row_group) in self.table.row_groups.iter().enumerate() {
316 let row_group = row_group.borrow();
317 if thead_index.is_none() && row_group.group_type == TableTrackGroupType::HeaderGroup {
318 thead_index = Some(row_group_index);
319 }
320 if tfoot_index.is_none() && row_group.group_type == TableTrackGroupType::FooterGroup {
321 tfoot_index = Some(row_group_index);
322 }
323 if thead_index.is_some() && tfoot_index.is_some() {
324 break;
325 }
326 }
327
328 if let Some(thead_index) = thead_index {
329 self.move_row_group_to_front(thead_index)
330 }
331
332 if let Some(mut tfoot_index) = tfoot_index {
333 if thead_index.unwrap_or(0) > tfoot_index {
336 tfoot_index += 1;
337 }
338 self.move_row_group_to_end(tfoot_index)
339 }
340 }
341
342 fn regenerate_track_ranges(&mut self) {
343 let mut current_row_group_index = None;
345 for (row_index, row) in self.table.rows.iter().enumerate() {
346 let row = row.borrow();
347 if current_row_group_index == row.group_index {
348 continue;
349 }
350
351 if let Some(current_group_index) = current_row_group_index {
353 self.table.row_groups[current_group_index]
354 .borrow_mut()
355 .track_range
356 .end = row_index;
357 }
358
359 current_row_group_index = row.group_index;
361 if let Some(current_group_index) = current_row_group_index {
362 self.table.row_groups[current_group_index]
363 .borrow_mut()
364 .track_range
365 .start = row_index;
366 }
367 }
368
369 if let Some(current_group_index) = current_row_group_index {
371 self.table.row_groups[current_group_index]
372 .borrow_mut()
373 .track_range
374 .end = self.table.rows.len();
375 }
376 }
377
378 fn move_row_group_to_front(&mut self, index_to_move: usize) {
379 if index_to_move > 0 {
381 let removed_row_group = self.table.row_groups.remove(index_to_move);
382 self.table.row_groups.insert(0, removed_row_group);
383
384 for row in self.table.rows.iter_mut() {
385 let mut row = row.borrow_mut();
386 match row.group_index.as_mut() {
387 Some(group_index) if *group_index < index_to_move => *group_index += 1,
388 Some(group_index) if *group_index == index_to_move => *group_index = 0,
389 _ => {},
390 }
391 }
392 }
393
394 let row_range = self.table.row_groups[0].borrow().track_range.clone();
395 if row_range.start > 0 {
396 let removed_slots: Vec<Vec<TableSlot>> = self
398 .table
399 .slots
400 .splice(row_range.clone(), std::iter::empty())
401 .collect();
402 self.table.slots.splice(0..0, removed_slots);
403
404 let removed_rows: Vec<_> = self
406 .table
407 .rows
408 .splice(row_range, std::iter::empty())
409 .collect();
410 self.table.rows.splice(0..0, removed_rows);
411
412 self.regenerate_track_ranges();
415 }
416 }
417
418 fn move_row_group_to_end(&mut self, index_to_move: usize) {
419 let last_row_group_index = self.table.row_groups.len() - 1;
420
421 if index_to_move < last_row_group_index {
423 let removed_row_group = self.table.row_groups.remove(index_to_move);
424 self.table.row_groups.push(removed_row_group);
425
426 for row in self.table.rows.iter_mut() {
427 let mut row = row.borrow_mut();
428 match row.group_index.as_mut() {
429 Some(group_index) if *group_index > index_to_move => *group_index -= 1,
430 Some(group_index) if *group_index == index_to_move => {
431 *group_index = last_row_group_index
432 },
433 _ => {},
434 }
435 }
436 }
437
438 let row_range = self.table.row_groups[last_row_group_index]
439 .borrow()
440 .track_range
441 .clone();
442 if row_range.end < self.table.rows.len() {
443 let removed_slots: Vec<Vec<TableSlot>> = self
445 .table
446 .slots
447 .splice(row_range.clone(), std::iter::empty())
448 .collect();
449 self.table.slots.extend(removed_slots);
450
451 let removed_rows: Vec<_> = self
453 .table
454 .rows
455 .splice(row_range, std::iter::empty())
456 .collect();
457 self.table.rows.extend(removed_rows);
458
459 self.regenerate_track_ranges();
460 }
461 }
462
463 fn do_final_rowspan_calculation(&mut self) {
467 for row_index in 0..self.table.size.height {
468 let last_row_index_in_group = self.last_row_index_in_row_group_at_row_n(row_index);
469 for cell in self.table.slots[row_index].iter_mut() {
470 if let TableSlot::Cell(cell) = cell {
471 let mut cell = cell.borrow_mut();
472 if cell.rowspan == 1 {
473 continue;
474 }
475 let rowspan_to_end_of_group = last_row_index_in_group - row_index + 1;
476 if cell.rowspan == 0 {
477 cell.rowspan = rowspan_to_end_of_group;
478 } else {
479 cell.rowspan = cell.rowspan.min(rowspan_to_end_of_group);
480 }
481 }
482 }
483 }
484 }
485
486 fn current_y(&self) -> Option<usize> {
487 self.table.slots.len().checked_sub(1)
488 }
489
490 fn current_x(&self) -> Option<usize> {
491 Some(self.table.slots[self.current_y()?].len())
492 }
493
494 fn current_coords(&self) -> Option<TableSlotCoordinates> {
495 Some(TableSlotCoordinates::new(
496 self.current_x()?,
497 self.current_y()?,
498 ))
499 }
500
501 pub fn start_row(&mut self) {
502 self.table.slots.push(Vec::new());
503 self.table.size.height += 1;
504 self.create_slots_for_cells_above_with_rowspan(true);
505 }
506
507 pub fn end_row(&mut self) {
508 let current_x = self
514 .current_x()
515 .expect("Should have rows before calling `end_row`");
516 for i in (current_x..self.incoming_rowspans.len()).rev() {
517 if self.incoming_rowspans[i] == 0 {
518 self.incoming_rowspans.pop();
519 } else {
520 break;
521 }
522 }
523
524 self.create_slots_for_cells_above_with_rowspan(false);
525 }
526
527 fn create_spanned_slot_based_on_cell_above(
533 &self,
534 target_coords: TableSlotCoordinates,
535 ) -> Option<TableSlot> {
536 let y_above = self.current_y()?.checked_sub(1)?;
537 let coords_for_slot_above = TableSlotCoordinates::new(target_coords.x, y_above);
538 let slots_covering_slot_above = self.table.resolve_slot_at(coords_for_slot_above);
539
540 let coords_of_slots_that_cover_target: Vec<_> = slots_covering_slot_above
541 .into_iter()
542 .filter(|slot| slot.covers_cell_at(target_coords))
543 .map(|slot| target_coords - slot.coords)
544 .collect();
545
546 if coords_of_slots_that_cover_target.is_empty() {
547 None
548 } else {
549 Some(TableSlot::Spanned(coords_of_slots_that_cover_target))
550 }
551 }
552
553 fn create_slots_for_cells_above_with_rowspan(&mut self, stop_at_cell_opportunity: bool) {
563 let mut current_coords = self
564 .current_coords()
565 .expect("Should have rows before calling `create_slots_for_cells_above_with_rowspan`");
566 while let Some(span) = self.incoming_rowspans.get_mut(current_coords.x) {
567 if *span == 0 && stop_at_cell_opportunity {
570 break;
571 }
572
573 let new_cell = if *span != 0 {
574 *span -= 1;
575 self.create_spanned_slot_based_on_cell_above(current_coords)
576 .expect(
577 "Nonzero incoming rowspan cannot occur without a cell spanning this slot",
578 )
579 } else {
580 TableSlot::Empty
581 };
582
583 self.table.push_new_slot_to_last_row(new_cell);
584 current_coords.x += 1;
585 }
586 debug_assert_eq!(Some(current_coords), self.current_coords());
587 }
588
589 pub fn add_cell(&mut self, cell: ArcRefCell<TableSlotCell>) {
593 let current_coords = self
596 .current_coords()
597 .expect("Should have rows before calling `add_cell`");
598
599 let (colspan, rowspan) = {
600 let cell = cell.borrow();
601 (cell.colspan, cell.rowspan)
602 };
603
604 if self.incoming_rowspans.len() < current_coords.x + colspan {
605 self.incoming_rowspans
606 .resize(current_coords.x + colspan, 0isize);
607 }
608
609 debug_assert_eq!(
610 self.incoming_rowspans[current_coords.x], 0,
611 "Added a cell in a position that also had an incoming rowspan!"
612 );
613
614 let outgoing_rowspan = rowspan as isize - 1;
616 self.table.push_new_slot_to_last_row(TableSlot::Cell(cell));
617 self.incoming_rowspans[current_coords.x] = outgoing_rowspan;
618
619 for colspan_offset in 1..colspan {
621 let current_x_plus_colspan_offset = current_coords.x + colspan_offset;
622 let new_offset = TableSlotOffset::new(colspan_offset, 0);
623 let incoming_rowspan = &mut self.incoming_rowspans[current_x_plus_colspan_offset];
624 let new_slot = if *incoming_rowspan == 0 {
625 *incoming_rowspan = outgoing_rowspan;
626 TableSlot::new_spanned(new_offset)
627 } else {
628 if *incoming_rowspan > 0 {
641 *incoming_rowspan = std::cmp::max(*incoming_rowspan - 1, outgoing_rowspan);
642 }
643
644 let coords_of_spanned_cell =
646 TableSlotCoordinates::new(current_x_plus_colspan_offset, current_coords.y);
647 let mut incoming_slot = self
648 .create_spanned_slot_based_on_cell_above(coords_of_spanned_cell)
649 .expect(
650 "Nonzero incoming rowspan cannot occur without a cell spanning this slot",
651 );
652 incoming_slot.push_spanned(new_offset);
653 incoming_slot
654 };
655 self.table.push_new_slot_to_last_row(new_slot);
656 }
657
658 debug_assert_eq!(
659 Some(TableSlotCoordinates::new(
660 current_coords.x + colspan,
661 current_coords.y
662 )),
663 self.current_coords(),
664 "Must have produced `colspan` slot entries!"
665 );
666 self.create_slots_for_cells_above_with_rowspan(true);
667 }
668}
669
670pub(crate) struct TableBuilderTraversal<'style, 'dom> {
671 context: &'style LayoutContext<'style>,
672 info: &'style NodeAndStyleInfo<'dom>,
673
674 current_propagated_data: PropagatedBoxTreeData,
677
678 builder: TableBuilder,
681
682 current_anonymous_row_content: Vec<AnonymousTableContent<'dom>>,
683
684 current_row_group_index: Option<usize>,
686}
687
688impl<'style, 'dom> TableBuilderTraversal<'style, 'dom> {
689 pub(crate) fn new(
690 context: &'style LayoutContext<'style>,
691 info: &'style NodeAndStyleInfo<'dom>,
692 grid_style: Arc<ComputedValues>,
693 propagated_data: PropagatedBoxTreeData,
694 ) -> Self {
695 TableBuilderTraversal {
696 context,
697 info,
698 current_propagated_data: propagated_data,
699 builder: TableBuilder::new(
700 info.style.clone(),
701 grid_style,
702 info.into(),
703 propagated_data.allow_percentage_column_in_tables,
704 ),
705 current_anonymous_row_content: Vec::new(),
706 current_row_group_index: None,
707 }
708 }
709
710 pub(crate) fn finish(mut self) -> Table {
711 self.finish_anonymous_row_if_needed();
712 self.builder.finish()
713 }
714
715 fn finish_anonymous_row_if_needed(&mut self) {
716 if AnonymousTableContent::remove_whitespace_only(&mut self.current_anonymous_row_content) {
717 return;
718 }
719 let row_content = std::mem::take(&mut self.current_anonymous_row_content);
720 let anonymous_info = self
721 .info
722 .with_pseudo_element(self.context, PseudoElement::ServoAnonymousTableRow)
723 .expect("Should never fail to create anonymous row info.");
724 let mut row_builder =
725 TableRowBuilder::new(self, &anonymous_info, self.current_propagated_data);
726
727 let mut enter_display_contents = vec![];
728 for cell_content in row_content {
729 match cell_content {
730 AnonymousTableContent::Element(element) => {
731 row_builder.handle_element(
732 &element.info,
733 element.display,
734 element.contents,
735 element.box_slot,
736 );
737 },
738 AnonymousTableContent::Text(info, text) => {
739 row_builder.handle_text(&info, text);
740 },
741 AnonymousTableContent::EnterDisplayContents(ref styles) => {
742 row_builder.enter_display_contents(styles.clone());
743 enter_display_contents.push(cell_content);
744 },
745 AnonymousTableContent::LeaveDisplayContents => {
746 row_builder.leave_display_contents();
747 enter_display_contents.pop();
748 },
749 }
750 }
751 row_builder.finish();
752 self.current_anonymous_row_content = enter_display_contents;
753
754 let style = anonymous_info.style.clone();
755 let table_row = ArcRefCell::new(TableTrack {
756 base: LayoutBoxBase::new((&anonymous_info).into(), style.clone()),
757 group_index: self.current_row_group_index,
758 is_anonymous: true,
759 shared_background_style: SharedStyle::new(style),
760 });
761 self.push_table_row(table_row.clone());
762
763 anonymous_info
764 .node
765 .box_slot()
766 .set(LayoutBox::TableLevelBox(TableLevelBox::Track(table_row)))
767 }
768
769 fn push_table_row(&mut self, table_track: ArcRefCell<TableTrack>) {
770 self.builder.table.rows.push(table_track);
771
772 let last_row = self.builder.table.rows.len();
773 if let Some(index) = self.current_row_group_index {
774 let row_group = &mut self.builder.table.row_groups[index];
775 row_group.borrow_mut().track_range.end = last_row;
776 }
777 }
778}
779
780impl<'dom> TraversalHandler<'dom> for TableBuilderTraversal<'_, 'dom> {
781 fn handle_text(&mut self, info: &NodeAndStyleInfo<'dom>, text: BoxTreeString<'dom>) {
782 self.current_anonymous_row_content
783 .push(AnonymousTableContent::Text(info.clone(), text));
784 }
785
786 fn enter_display_contents(&mut self, styles: SharedInlineStyles) {
787 self.current_anonymous_row_content
788 .push(AnonymousTableContent::EnterDisplayContents(styles));
789 }
790
791 fn leave_display_contents(&mut self) {
792 self.current_anonymous_row_content
793 .push(AnonymousTableContent::LeaveDisplayContents);
794 }
795
796 fn handle_element(
798 &mut self,
799 info: &NodeAndStyleInfo<'dom>,
800 display: DisplayGeneratingBox,
801 contents: Contents,
802 box_slot: BoxSlot<'dom>,
803 ) {
804 match display {
805 DisplayGeneratingBox::LayoutInternal(internal) => match internal {
806 DisplayLayoutInternal::TableRowGroup |
807 DisplayLayoutInternal::TableFooterGroup |
808 DisplayLayoutInternal::TableHeaderGroup => {
809 self.finish_anonymous_row_if_needed();
810 self.builder.incoming_rowspans.clear();
811
812 let next_row_index = self.builder.table.rows.len();
813 let row_group = ArcRefCell::new(TableTrackGroup {
814 base: LayoutBoxBase::new(info.into(), info.style.clone()),
815 group_type: internal.into(),
816 track_range: next_row_index..next_row_index,
817 shared_background_style: SharedStyle::new(info.style.clone()),
818 });
819 self.builder.table.row_groups.push(row_group.clone());
820
821 let new_row_group_index = self.builder.table.row_groups.len() - 1;
822 let context = self.context;
823 let mut row_group_builder = TableRowGroupBuilder::new(
824 self,
825 info,
826 self.current_propagated_data,
827 new_row_group_index,
828 );
829
830 contents
831 .non_replaced_contents()
832 .expect("Replaced should not have a LayoutInternal display type.")
833 .traverse(context, info, &mut row_group_builder);
834
835 row_group_builder.finish();
836
837 box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::TrackGroup(
838 row_group,
839 )));
840 },
841 DisplayLayoutInternal::TableRow => {
842 self.finish_anonymous_row_if_needed();
843
844 let context = self.context;
845 let mut row_builder =
846 TableRowBuilder::new(self, info, self.current_propagated_data);
847
848 contents
849 .non_replaced_contents()
850 .expect("Replaced should not have a LayoutInternal display type.")
851 .traverse(context, info, &mut row_builder);
852 row_builder.finish();
853
854 let row = ArcRefCell::new(TableTrack {
855 base: LayoutBoxBase::new(info.into(), info.style.clone()),
856 group_index: self.current_row_group_index,
857 is_anonymous: false,
858 shared_background_style: SharedStyle::new(info.style.clone()),
859 });
860 self.push_table_row(row.clone());
861 box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::Track(row)));
862 },
863 DisplayLayoutInternal::TableColumn => {
864 let old_box = box_slot.take_layout_box();
865 let old_column = old_box.and_then(|layout_box| match layout_box {
866 LayoutBox::TableLevelBox(TableLevelBox::Track(column)) => Some(column),
867 _ => None,
868 });
869 let column = add_column(
870 &mut self.builder.table.columns,
871 info,
872 None, false, old_column,
875 );
876 box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::Track(column)));
877 },
878 DisplayLayoutInternal::TableColumnGroup => {
879 let column_group_index = self.builder.table.column_groups.len();
880 let mut column_group_builder = TableColumnGroupBuilder {
881 column_group_index,
882 columns: Vec::new(),
883 };
884
885 contents
886 .non_replaced_contents()
887 .expect("Replaced should not have a LayoutInternal display type.")
888 .traverse(self.context, info, &mut column_group_builder);
889
890 let first_column = self.builder.table.columns.len();
891 if column_group_builder.columns.is_empty() {
892 add_column(
893 &mut self.builder.table.columns,
894 info,
895 Some(column_group_index),
896 true, None,
898 );
899 } else {
900 self.builder
901 .table
902 .columns
903 .extend(column_group_builder.columns);
904 }
905
906 let column_group = ArcRefCell::new(TableTrackGroup {
907 base: LayoutBoxBase::new(info.into(), info.style.clone()),
908 group_type: internal.into(),
909 track_range: first_column..self.builder.table.columns.len(),
910 shared_background_style: SharedStyle::new(info.style.clone()),
911 });
912 self.builder.table.column_groups.push(column_group.clone());
913 box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::TrackGroup(
914 column_group,
915 )));
916 },
917 DisplayLayoutInternal::TableCaption => {
918 let old_box = box_slot.take_layout_box();
919 let old_caption = old_box.and_then(|layout_box| match layout_box {
920 LayoutBox::TableLevelBox(TableLevelBox::Caption(caption)) => Some(caption),
921 _ => None,
922 });
923
924 let caption = old_caption.unwrap_or_else(|| {
925 let non_replaced_contents = contents
926 .non_replaced_contents()
927 .expect("Replaced should not have a LayoutInternal display type.");
928 let contents = IndependentFormattingContextContents::Flow(
929 BlockFormattingContext::construct(
930 self.context,
931 info,
932 non_replaced_contents,
933 self.current_propagated_data,
934 false, ),
936 );
937 let base = LayoutBoxBase::new(info.into(), info.style.clone());
938 ArcRefCell::new(TableCaption {
939 context: IndependentFormattingContext::new(
940 base,
941 contents,
942 self.current_propagated_data,
943 ),
944 })
945 });
946
947 self.builder.table.captions.push(caption.clone());
948 box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::Caption(caption)));
949 },
950 DisplayLayoutInternal::TableCell => {
951 self.current_anonymous_row_content
952 .push(AnonymousTableContent::Element(Box::new(
953 AnonymousTableContentElement {
954 info: info.clone(),
955 display,
956 contents,
957 box_slot,
958 },
959 )));
960 },
961 },
962 _ => {
963 self.current_anonymous_row_content
964 .push(AnonymousTableContent::Element(Box::new(
965 AnonymousTableContentElement {
966 info: info.clone(),
967 display,
968 contents,
969 box_slot,
970 },
971 )));
972 },
973 }
974 }
975}
976
977struct TableRowGroupBuilder<'style, 'builder, 'dom, 'a> {
978 table_traversal: &'builder mut TableBuilderTraversal<'style, 'dom>,
979 info: &'a NodeAndStyleInfo<'dom>,
980 propagated_data: PropagatedBoxTreeData,
981 current_anonymous_row_content: Vec<AnonymousTableContent<'dom>>,
982}
983
984impl<'style, 'builder, 'dom, 'a> TableRowGroupBuilder<'style, 'builder, 'dom, 'a> {
985 fn new(
986 table_traversal: &'builder mut TableBuilderTraversal<'style, 'dom>,
987 info: &'a NodeAndStyleInfo<'dom>,
988 propagated_data: PropagatedBoxTreeData,
989 row_group_index: usize,
990 ) -> Self {
991 debug_assert!(table_traversal.current_row_group_index.is_none());
993 table_traversal.current_row_group_index = Some(row_group_index);
994
995 Self {
996 table_traversal,
997 info,
998 propagated_data,
999 current_anonymous_row_content: Vec::new(),
1000 }
1001 }
1002
1003 fn finish(mut self) {
1004 self.finish_anonymous_row_if_needed();
1005 self.table_traversal.current_row_group_index = None;
1006 self.table_traversal.builder.incoming_rowspans.clear();
1007 }
1008
1009 fn finish_anonymous_row_if_needed(&mut self) {
1010 if AnonymousTableContent::remove_whitespace_only(&mut self.current_anonymous_row_content) {
1011 return;
1012 }
1013
1014 let row_content = std::mem::take(&mut self.current_anonymous_row_content);
1015 let anonymous_info = self
1016 .info
1017 .with_pseudo_element(
1018 self.table_traversal.context,
1019 PseudoElement::ServoAnonymousTableRow,
1020 )
1021 .expect("Should never fail to create anonymous row info.");
1022
1023 let mut row_builder =
1024 TableRowBuilder::new(self.table_traversal, &anonymous_info, self.propagated_data);
1025
1026 let mut enter_display_contents = vec![];
1027 for cell_content in row_content {
1028 match cell_content {
1029 AnonymousTableContent::Element(element) => {
1030 row_builder.handle_element(
1031 &element.info,
1032 element.display,
1033 element.contents,
1034 element.box_slot,
1035 );
1036 },
1037 AnonymousTableContent::Text(info, text) => {
1038 row_builder.handle_text(&info, text);
1039 },
1040 AnonymousTableContent::EnterDisplayContents(ref styles) => {
1041 row_builder.enter_display_contents(styles.clone());
1042 enter_display_contents.push(cell_content);
1043 },
1044 AnonymousTableContent::LeaveDisplayContents => {
1045 row_builder.leave_display_contents();
1046 enter_display_contents.pop();
1047 },
1048 }
1049 }
1050 self.current_anonymous_row_content = enter_display_contents;
1051
1052 row_builder.finish();
1053
1054 let style = anonymous_info.style.clone();
1055 let table_row = ArcRefCell::new(TableTrack {
1056 base: LayoutBoxBase::new((&anonymous_info).into(), style.clone()),
1057 group_index: self.table_traversal.current_row_group_index,
1058 is_anonymous: true,
1059 shared_background_style: SharedStyle::new(style),
1060 });
1061 self.table_traversal.push_table_row(table_row.clone());
1062
1063 anonymous_info
1064 .node
1065 .box_slot()
1066 .set(LayoutBox::TableLevelBox(TableLevelBox::Track(table_row)));
1067 }
1068}
1069
1070impl<'dom> TraversalHandler<'dom> for TableRowGroupBuilder<'_, '_, 'dom, '_> {
1071 fn handle_text(&mut self, info: &NodeAndStyleInfo<'dom>, text: BoxTreeString<'dom>) {
1072 self.current_anonymous_row_content
1073 .push(AnonymousTableContent::Text(info.clone(), text));
1074 }
1075
1076 fn enter_display_contents(&mut self, styles: SharedInlineStyles) {
1077 self.current_anonymous_row_content
1078 .push(AnonymousTableContent::EnterDisplayContents(styles));
1079 }
1080
1081 fn leave_display_contents(&mut self) {
1082 self.current_anonymous_row_content
1083 .push(AnonymousTableContent::LeaveDisplayContents);
1084 }
1085
1086 fn handle_element(
1087 &mut self,
1088 info: &NodeAndStyleInfo<'dom>,
1089 display: DisplayGeneratingBox,
1090 contents: Contents,
1091 box_slot: BoxSlot<'dom>,
1092 ) {
1093 match display {
1094 DisplayGeneratingBox::LayoutInternal(DisplayLayoutInternal::TableRow) => {
1095 self.finish_anonymous_row_if_needed();
1096
1097 let context = self.table_traversal.context;
1098 let mut row_builder =
1099 TableRowBuilder::new(self.table_traversal, info, self.propagated_data);
1100
1101 contents
1102 .non_replaced_contents()
1103 .expect("Replaced should not have a LayoutInternal display type.")
1104 .traverse(context, info, &mut row_builder);
1105 row_builder.finish();
1106
1107 let row = ArcRefCell::new(TableTrack {
1108 base: LayoutBoxBase::new(info.into(), info.style.clone()),
1109 group_index: self.table_traversal.current_row_group_index,
1110 is_anonymous: false,
1111 shared_background_style: SharedStyle::new(info.style.clone()),
1112 });
1113 self.table_traversal.push_table_row(row.clone());
1114 box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::Track(row)));
1115 },
1116
1117 _ => {
1118 self.current_anonymous_row_content
1119 .push(AnonymousTableContent::Element(Box::new(
1120 AnonymousTableContentElement {
1121 info: info.clone(),
1122 display,
1123 contents,
1124 box_slot,
1125 },
1126 )));
1127 },
1128 }
1129 }
1130}
1131
1132struct TableRowBuilder<'style, 'builder, 'dom, 'a> {
1133 table_traversal: &'builder mut TableBuilderTraversal<'style, 'dom>,
1134
1135 info: &'a NodeAndStyleInfo<'dom>,
1138
1139 current_anonymous_cell_content: Vec<AnonymousTableContent<'dom>>,
1140
1141 propagated_data: PropagatedBoxTreeData,
1143}
1144
1145impl<'style, 'builder, 'dom, 'a> TableRowBuilder<'style, 'builder, 'dom, 'a> {
1146 fn new(
1147 table_traversal: &'builder mut TableBuilderTraversal<'style, 'dom>,
1148 info: &'a NodeAndStyleInfo<'dom>,
1149 propagated_data: PropagatedBoxTreeData,
1150 ) -> Self {
1151 table_traversal.builder.start_row();
1152
1153 TableRowBuilder {
1154 table_traversal,
1155 info,
1156 current_anonymous_cell_content: Vec::new(),
1157 propagated_data,
1158 }
1159 }
1160
1161 fn finish(mut self) {
1162 self.finish_current_anonymous_cell_if_needed();
1163 self.table_traversal.builder.end_row();
1164 }
1165
1166 fn finish_current_anonymous_cell_if_needed(&mut self) {
1167 if AnonymousTableContent::remove_whitespace_only(&mut self.current_anonymous_cell_content) {
1168 return;
1169 }
1170
1171 let context = self.table_traversal.context;
1172 let anonymous_info = self
1173 .info
1174 .with_pseudo_element(context, PseudoElement::ServoAnonymousTableCell)
1175 .expect("Should never fail to create anonymous table cell info");
1176 let propagated_data = self.propagated_data.disallowing_percentage_table_columns();
1177 let mut builder = BlockContainerBuilder::new(context, &anonymous_info, propagated_data);
1178
1179 let mut enter_display_contents = vec![];
1180 for cell_content in self.current_anonymous_cell_content.drain(..) {
1181 match cell_content {
1182 AnonymousTableContent::Element(element) => {
1183 builder.handle_element(
1184 &element.info,
1185 element.display,
1186 element.contents,
1187 element.box_slot,
1188 );
1189 },
1190 AnonymousTableContent::Text(info, text) => {
1191 builder.handle_text(&info, text);
1192 },
1193 AnonymousTableContent::EnterDisplayContents(ref styles) => {
1194 builder.enter_display_contents(styles.clone());
1195 enter_display_contents.push(cell_content);
1196 },
1197 AnonymousTableContent::LeaveDisplayContents => {
1198 builder.leave_display_contents();
1199 enter_display_contents.pop();
1200 },
1201 }
1202 }
1203 self.current_anonymous_cell_content = enter_display_contents;
1204
1205 let block_container = builder.finish();
1206 let new_table_cell = ArcRefCell::new(TableSlotCell {
1207 context: IndependentFormattingContext::new(
1208 LayoutBoxBase::new(BaseFragmentInfo::anonymous(), anonymous_info.style),
1209 IndependentFormattingContextContents::Flow(
1210 BlockFormattingContext::from_block_container(block_container),
1211 ),
1212 propagated_data,
1213 ),
1214 colspan: 1,
1215 rowspan: 1,
1216 });
1217 self.table_traversal
1218 .builder
1219 .add_cell(new_table_cell.clone());
1220
1221 anonymous_info
1222 .node
1223 .box_slot()
1224 .set(LayoutBox::TableLevelBox(TableLevelBox::Cell(
1225 new_table_cell,
1226 )));
1227 }
1228}
1229
1230impl<'dom> TraversalHandler<'dom> for TableRowBuilder<'_, '_, 'dom, '_> {
1231 fn handle_text(&mut self, info: &NodeAndStyleInfo<'dom>, text: BoxTreeString<'dom>) {
1232 self.current_anonymous_cell_content
1233 .push(AnonymousTableContent::Text(info.clone(), text));
1234 }
1235
1236 fn enter_display_contents(&mut self, styles: SharedInlineStyles) {
1237 self.current_anonymous_cell_content
1238 .push(AnonymousTableContent::EnterDisplayContents(styles));
1239 }
1240
1241 fn leave_display_contents(&mut self) {
1242 self.current_anonymous_cell_content
1243 .push(AnonymousTableContent::LeaveDisplayContents);
1244 }
1245
1246 fn handle_element(
1248 &mut self,
1249 info: &NodeAndStyleInfo<'dom>,
1250 display: DisplayGeneratingBox,
1251 contents: Contents,
1252 box_slot: BoxSlot<'dom>,
1253 ) {
1254 match display {
1255 DisplayGeneratingBox::LayoutInternal(internal) => match internal {
1256 DisplayLayoutInternal::TableCell => {
1257 self.finish_current_anonymous_cell_if_needed();
1258
1259 let old_box = box_slot.take_layout_box();
1260 let old_cell = old_box.and_then(|layout_box| match layout_box {
1261 LayoutBox::TableLevelBox(TableLevelBox::Cell(cell)) => Some(cell),
1262 _ => None,
1263 });
1264
1265 let cell = old_cell.unwrap_or_else(|| {
1266 let (rowspan, colspan) = if info.pseudo_element_chain().is_empty() {
1269 let rowspan = info.node.table_rowspan().unwrap_or(1) as usize;
1270 let colspan = info.node.table_colspan().unwrap_or(1) as usize;
1271
1272 assert!((1..=1000).contains(&colspan));
1275 assert!((0..=65534).contains(&rowspan));
1276
1277 (rowspan, colspan)
1278 } else {
1279 (1, 1)
1280 };
1281
1282 let propagated_data =
1283 self.propagated_data.disallowing_percentage_table_columns();
1284 let non_replaced_contents = contents
1285 .non_replaced_contents()
1286 .expect("Replaced should not have a LayoutInternal display type.");
1287
1288 let contents = BlockFormattingContext::construct(
1289 self.table_traversal.context,
1290 info,
1291 non_replaced_contents,
1292 propagated_data,
1293 false, );
1295
1296 ArcRefCell::new(TableSlotCell {
1297 context: IndependentFormattingContext::new(
1298 LayoutBoxBase::new(info.into(), info.style.clone()),
1299 IndependentFormattingContextContents::Flow(contents),
1300 propagated_data,
1301 ),
1302 colspan,
1303 rowspan,
1304 })
1305 });
1306
1307 self.table_traversal.builder.add_cell(cell.clone());
1308 box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::Cell(cell)));
1309 },
1310 _ => {
1311 self.current_anonymous_cell_content
1313 .push(AnonymousTableContent::Element(Box::new(
1314 AnonymousTableContentElement {
1315 info: info.clone(),
1316 display,
1317 contents,
1318 box_slot,
1319 },
1320 )));
1321 },
1322 },
1323 _ => {
1324 self.current_anonymous_cell_content
1325 .push(AnonymousTableContent::Element(Box::new(
1326 AnonymousTableContentElement {
1327 info: info.clone(),
1328 display,
1329 contents,
1330 box_slot,
1331 },
1332 )));
1333 },
1334 }
1335 }
1336}
1337
1338struct TableColumnGroupBuilder {
1339 column_group_index: usize,
1340 columns: Vec<ArcRefCell<TableTrack>>,
1341}
1342
1343impl<'dom> TraversalHandler<'dom> for TableColumnGroupBuilder {
1344 fn handle_text(&mut self, _info: &NodeAndStyleInfo<'dom>, _text: BoxTreeString<'dom>) {}
1345 fn enter_display_contents(&mut self, _: SharedInlineStyles) {}
1346 fn leave_display_contents(&mut self) {}
1347 fn handle_element(
1348 &mut self,
1349 info: &NodeAndStyleInfo<'dom>,
1350 display: DisplayGeneratingBox,
1351 _contents: Contents,
1352 box_slot: BoxSlot<'dom>,
1353 ) {
1354 if !matches!(
1355 display,
1356 DisplayGeneratingBox::LayoutInternal(DisplayLayoutInternal::TableColumn)
1357 ) {
1358 ::std::mem::forget(box_slot);
1361 return;
1362 }
1363 let old_box = box_slot.take_layout_box();
1364 let old_column = old_box.and_then(|layout_box| match layout_box {
1365 LayoutBox::TableLevelBox(TableLevelBox::Track(column)) => Some(column),
1366 _ => None,
1367 });
1368 let column = add_column(
1369 &mut self.columns,
1370 info,
1371 Some(self.column_group_index),
1372 false, old_column,
1374 );
1375 box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::Track(column)));
1376 }
1377}
1378
1379impl From<DisplayLayoutInternal> for TableTrackGroupType {
1380 fn from(value: DisplayLayoutInternal) -> Self {
1381 match value {
1382 DisplayLayoutInternal::TableColumnGroup => TableTrackGroupType::ColumnGroup,
1383 DisplayLayoutInternal::TableFooterGroup => TableTrackGroupType::FooterGroup,
1384 DisplayLayoutInternal::TableHeaderGroup => TableTrackGroupType::HeaderGroup,
1385 DisplayLayoutInternal::TableRowGroup => TableTrackGroupType::RowGroup,
1386 _ => unreachable!(),
1387 }
1388 }
1389}
1390
1391fn add_column(
1392 collection: &mut Vec<ArcRefCell<TableTrack>>,
1393 column_info: &NodeAndStyleInfo,
1394 group_index: Option<usize>,
1395 is_anonymous: bool,
1396 old_column: Option<ArcRefCell<TableTrack>>,
1397) -> ArcRefCell<TableTrack> {
1398 let span = if column_info.pseudo_element_chain().is_empty() {
1399 column_info.node.table_span().unwrap_or(1)
1400 } else {
1401 1
1402 };
1403
1404 assert!((1..=1000).contains(&span));
1406
1407 let column = match old_column {
1408 Some(column) => {
1409 column.borrow_mut().group_index = group_index;
1410 column
1411 },
1412 None => ArcRefCell::new(TableTrack {
1413 base: LayoutBoxBase::new(column_info.into(), column_info.style.clone()),
1414 group_index,
1415 is_anonymous,
1416 shared_background_style: SharedStyle::new(column_info.style.clone()),
1417 }),
1418 };
1419 collection.extend(repeat_n(column.clone(), span as usize));
1420 column
1421}