Skip to main content

fop_layout/layout/table/
types.rs

1//! Table layout types: enums, structs for table, column, cell, and border data
2
3use crate::area::AreaId;
4use fop_types::Length;
5use std::fmt;
6
7/// Table layout algorithm mode
8///
9/// Corresponds to the XSL-FO table-layout property.
10/// - "auto": Column widths are determined by content (CSS2.1 auto table layout)
11/// - "fixed": Column widths are determined by explicit widths (default)
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
13pub enum TableLayoutMode {
14    /// Auto layout - column widths determined by content
15    /// Implements CSS2.1 automatic table layout algorithm
16    Auto,
17    /// Fixed layout - column widths from table-column or first row
18    /// Faster and more predictable than auto layout
19    #[default]
20    Fixed,
21}
22
23/// Border collapse model for tables
24///
25/// Corresponds to the CSS/XSL-FO border-collapse property.
26/// - "separate": Borders are drawn around each cell with spacing between them
27/// - "collapse": Adjacent cell borders are merged into a single border
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
29pub enum BorderCollapse {
30    /// Separate borders (default) - each cell has its own borders with spacing
31    #[default]
32    Separate,
33    /// Collapsed borders - adjacent borders merge with conflict resolution
34    Collapse,
35}
36
37impl fmt::Display for BorderCollapse {
38    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39        match self {
40            BorderCollapse::Separate => write!(f, "separate"),
41            BorderCollapse::Collapse => write!(f, "collapse"),
42        }
43    }
44}
45
46/// Column width specification
47#[derive(Debug, Clone, PartialEq)]
48pub enum ColumnWidth {
49    /// Fixed width
50    Fixed(Length),
51
52    /// Proportional width (e.g., 2* = 2 units)
53    Proportional(f64),
54
55    /// Auto width (calculated from content)
56    Auto,
57}
58
59/// Information about a table column
60///
61/// Used in auto layout algorithm to track column width constraints.
62#[derive(Debug, Clone)]
63pub struct ColumnInfo {
64    /// Column width specification
65    pub width_spec: ColumnWidth,
66
67    /// Computed width (after layout)
68    pub computed_width: Length,
69
70    /// Minimum content width
71    /// Smallest width that prevents content overflow
72    pub min_width: Length,
73
74    /// Maximum content width
75    /// Preferred width without any line breaking
76    pub max_width: Length,
77}
78
79impl ColumnInfo {
80    /// Create a new ColumnInfo with the given width specification
81    pub fn new(width_spec: ColumnWidth) -> Self {
82        Self {
83            width_spec,
84            computed_width: Length::ZERO,
85            min_width: Length::ZERO,
86            max_width: Length::ZERO,
87        }
88    }
89
90    /// Create a ColumnInfo with explicit min/max widths
91    pub fn with_widths(width_spec: ColumnWidth, min_width: Length, max_width: Length) -> Self {
92        Self {
93            width_spec,
94            computed_width: Length::ZERO,
95            min_width,
96            max_width,
97        }
98    }
99}
100
101/// A cell in the table grid
102#[derive(Debug, Clone)]
103pub struct GridCell {
104    /// Row index
105    pub row: usize,
106
107    /// Column index
108    pub col: usize,
109
110    /// Number of rows spanned
111    pub rowspan: usize,
112
113    /// Number of columns spanned
114    pub colspan: usize,
115
116    /// Content area ID
117    pub content_id: Option<AreaId>,
118}
119
120/// Collapsed border information for a cell edge
121///
122/// In the collapsed border model, adjacent cell borders merge into a single border.
123/// This structure stores the winning border after conflict resolution.
124#[derive(Debug, Clone, Copy)]
125pub struct CollapsedBorder {
126    /// Border width
127    pub width: Length,
128
129    /// Border color
130    pub color: fop_types::Color,
131
132    /// Border style
133    pub style: crate::area::BorderStyle,
134}
135
136impl CollapsedBorder {
137    /// Create a new collapsed border
138    pub fn new(width: Length, color: fop_types::Color, style: crate::area::BorderStyle) -> Self {
139        Self {
140            width,
141            color,
142            style,
143        }
144    }
145
146    /// Create a none/hidden border (no border)
147    pub fn none() -> Self {
148        Self {
149            width: Length::ZERO,
150            color: fop_types::Color::BLACK,
151            style: crate::area::BorderStyle::None,
152        }
153    }
154
155    /// Check if this border is visible
156    pub fn is_visible(&self) -> bool {
157        self.width > Length::ZERO
158            && !matches!(
159                self.style,
160                crate::area::BorderStyle::None | crate::area::BorderStyle::Hidden
161            )
162    }
163}
164
165/// Table layout engine
166pub struct TableLayout {
167    /// Available width for the table
168    pub(super) available_width: Length,
169
170    /// Border spacing (for separate border model)
171    pub(super) border_spacing: Length,
172
173    /// Table layout mode (auto or fixed)
174    pub(super) layout_mode: TableLayoutMode,
175
176    /// Border collapse model
177    pub(super) border_collapse: BorderCollapse,
178}
179
180impl TableLayout {
181    /// Create a new table layout engine
182    pub fn new(available_width: Length) -> Self {
183        Self {
184            available_width,
185            border_spacing: Length::from_pt(2.0),
186            layout_mode: TableLayoutMode::Fixed,
187            border_collapse: BorderCollapse::Separate,
188        }
189    }
190
191    /// Set border spacing
192    pub fn with_border_spacing(mut self, spacing: Length) -> Self {
193        self.border_spacing = spacing;
194        self
195    }
196
197    /// Set table layout mode
198    pub fn with_layout_mode(mut self, mode: TableLayoutMode) -> Self {
199        self.layout_mode = mode;
200        self
201    }
202
203    /// Set border collapse model
204    pub fn with_border_collapse(mut self, collapse: BorderCollapse) -> Self {
205        self.border_collapse = collapse;
206        self
207    }
208
209    /// Get the current table layout mode
210    pub fn layout_mode(&self) -> TableLayoutMode {
211        self.layout_mode
212    }
213
214    /// Get the current border collapse model
215    pub fn border_collapse(&self) -> BorderCollapse {
216        self.border_collapse
217    }
218}
219
220/// Collapsed borders for all four edges of a cell
221///
222/// Stores the winning border after conflict resolution for each edge.
223#[derive(Debug, Clone, Copy)]
224pub struct CellCollapsedBorders {
225    /// Top border
226    pub top: CollapsedBorder,
227    /// Right border
228    pub right: CollapsedBorder,
229    /// Bottom border
230    pub bottom: CollapsedBorder,
231    /// Left border
232    pub left: CollapsedBorder,
233}
234
235impl Default for CellCollapsedBorders {
236    fn default() -> Self {
237        Self {
238            top: CollapsedBorder::none(),
239            right: CollapsedBorder::none(),
240            bottom: CollapsedBorder::none(),
241            left: CollapsedBorder::none(),
242        }
243    }
244}