TableFormattingContext.h 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /*
  2. * Copyright (c) 2020, Andreas Kling <andreas@ladybird.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/Forward.h>
  8. #include <LibWeb/Layout/FormattingContext.h>
  9. #include <LibWeb/Layout/TableGrid.h>
  10. #include <LibWeb/Layout/TableWrapper.h>
  11. namespace Web::Layout {
  12. enum class TableDimension {
  13. Row,
  14. Column
  15. };
  16. class TableFormattingContext final : public FormattingContext {
  17. public:
  18. explicit TableFormattingContext(LayoutState&, LayoutMode, Box const&, FormattingContext* parent);
  19. ~TableFormattingContext();
  20. void run_until_width_calculation(AvailableSpace const& available_space);
  21. virtual void run(AvailableSpace const&) override;
  22. virtual CSSPixels automatic_content_width() const override;
  23. virtual CSSPixels automatic_content_height() const override;
  24. StaticPositionRect calculate_static_position_rect(Box const&) const;
  25. Box const& table_box() const { return context_box(); }
  26. TableWrapper const& table_wrapper() const
  27. {
  28. return verify_cast<TableWrapper>(*table_box().containing_block());
  29. }
  30. static bool border_is_less_specific(const CSS::BorderData& a, const CSS::BorderData& b);
  31. virtual void parent_context_did_dimension_child_root_box() override;
  32. private:
  33. CSSPixels run_caption_layout(CSS::CaptionSide);
  34. CSSPixels compute_capmin();
  35. void compute_constrainedness();
  36. void compute_cell_measures();
  37. void compute_outer_content_sizes();
  38. template<class RowOrColumn>
  39. void initialize_table_measures();
  40. template<class RowOrColumn>
  41. void compute_table_measures();
  42. template<class RowOrColumn>
  43. void compute_intrinsic_percentage(size_t max_cell_span);
  44. void compute_table_width();
  45. void distribute_width_to_columns();
  46. void distribute_excess_width_to_columns(CSSPixels available_width);
  47. void distribute_excess_width_to_columns_fixed_mode(CSSPixels excess_width);
  48. void compute_table_height();
  49. void distribute_height_to_rows();
  50. void position_row_boxes();
  51. void position_cell_boxes();
  52. void border_conflict_resolution();
  53. CSSPixels border_spacing_horizontal() const;
  54. CSSPixels border_spacing_vertical() const;
  55. void finish_grid_initialization(TableGrid const&);
  56. CSSPixels compute_columns_total_used_width() const;
  57. void commit_candidate_column_widths(Vector<CSSPixels> const& candidate_widths);
  58. void assign_columns_width_linear_combination(Vector<CSSPixels> const& candidate_widths, CSSPixels available_width);
  59. template<class ColumnFilter, class BaseWidthGetter>
  60. bool distribute_excess_width_proportionally_to_base_width(CSSPixels excess_width, ColumnFilter column_filter, BaseWidthGetter base_width_getter);
  61. template<class ColumnFilter>
  62. bool distribute_excess_width_equally(CSSPixels excess_width, ColumnFilter column_filter);
  63. template<class ColumnFilter>
  64. bool distribute_excess_width_by_intrinsic_percentage(CSSPixels excess_width, ColumnFilter column_filter);
  65. bool use_fixed_mode_layout() const;
  66. CSSPixels m_table_height { 0 };
  67. CSSPixels m_automatic_content_height { 0 };
  68. Optional<AvailableSpace> m_available_space;
  69. struct Column {
  70. CSSPixels left_offset { 0 };
  71. CSSPixels min_size { 0 };
  72. CSSPixels max_size { 0 };
  73. CSSPixels used_width { 0 };
  74. bool has_intrinsic_percentage { false };
  75. double intrinsic_percentage { 0 };
  76. // Store whether the column is constrained: https://www.w3.org/TR/css-tables-3/#constrainedness
  77. bool is_constrained { false };
  78. // Store whether the column has originating cells, defined in https://www.w3.org/TR/css-tables-3/#terminology.
  79. bool has_originating_cells { false };
  80. };
  81. using Cell = TableGrid::Cell;
  82. using Row = TableGrid::Row;
  83. // Accessors to enable direction-agnostic table measurement.
  84. template<class RowOrColumn>
  85. static size_t cell_span(Cell const& cell);
  86. template<class RowOrColumn>
  87. static size_t cell_index(Cell const& cell);
  88. template<class RowOrColumn>
  89. static CSSPixels cell_min_size(Cell const& cell);
  90. template<class RowOrColumn>
  91. static CSSPixels cell_max_size(Cell const& cell);
  92. template<class RowOrColumn>
  93. static double cell_percentage_contribution(Cell const& cell);
  94. template<class RowOrColumn>
  95. static bool cell_has_intrinsic_percentage(Cell const& cell);
  96. template<class RowOrColumn>
  97. void initialize_intrinsic_percentages_from_rows_or_columns();
  98. template<class RowOrColumn>
  99. void initialize_intrinsic_percentages_from_cells();
  100. template<class RowOrColumn>
  101. CSSPixels border_spacing();
  102. template<class RowOrColumn>
  103. Vector<RowOrColumn>& table_rows_or_columns();
  104. CSSPixels compute_row_content_height(Cell const& cell) const;
  105. enum class ConflictingSide {
  106. Top,
  107. Bottom,
  108. Left,
  109. Right,
  110. };
  111. struct ConflictingEdge {
  112. GC::Ptr<Node const> element;
  113. Painting::PaintableBox::ConflictingElementKind element_kind;
  114. ConflictingSide side;
  115. Optional<size_t> row;
  116. Optional<size_t> column;
  117. };
  118. static TableFormattingContext::ConflictingEdge const& winning_conflicting_edge(TableFormattingContext::ConflictingEdge const& a, TableFormattingContext::ConflictingEdge const& b);
  119. static const CSS::BorderData& border_data_conflicting_edge(ConflictingEdge const& conflicting_edge);
  120. static Painting::PaintableBox::BorderDataWithElementKind const border_data_with_element_kind_from_conflicting_edge(ConflictingEdge const& conflicting_edge);
  121. class BorderConflictFinder {
  122. public:
  123. BorderConflictFinder(TableFormattingContext const* context);
  124. Vector<ConflictingEdge> conflicting_edges(Cell const&, ConflictingSide) const;
  125. private:
  126. void collect_conflicting_col_elements();
  127. void collect_conflicting_row_group_elements();
  128. void collect_cell_conflicting_edges(Vector<ConflictingEdge>&, Cell const&, ConflictingSide) const;
  129. void collect_row_conflicting_edges(Vector<ConflictingEdge>&, Cell const&, ConflictingSide) const;
  130. void collect_row_group_conflicting_edges(Vector<ConflictingEdge>&, Cell const&, ConflictingSide) const;
  131. void collect_column_group_conflicting_edges(Vector<ConflictingEdge>&, Cell const&, ConflictingSide) const;
  132. void collect_table_box_conflicting_edges(Vector<ConflictingEdge>&, Cell const&, ConflictingSide) const;
  133. GC::Ptr<Node const> get_col_element(size_t index) const
  134. {
  135. if (index >= m_col_elements_by_index.size())
  136. return {};
  137. return m_col_elements_by_index[index];
  138. }
  139. struct RowGroupInfo {
  140. GC::Ptr<Node const> row_group;
  141. size_t start_index;
  142. size_t row_count;
  143. };
  144. Vector<GC::Ptr<Node const>> m_col_elements_by_index;
  145. Vector<Optional<RowGroupInfo>> m_row_group_elements_by_index;
  146. TableFormattingContext const* m_context;
  147. };
  148. Vector<Cell> m_cells;
  149. Vector<Vector<Optional<Cell const&>>> m_cells_by_coordinate;
  150. Vector<Column> m_columns;
  151. Vector<Row> m_rows;
  152. };
  153. }