Skip to main content

fop_layout/layout/table/
border.rs

1//! Border conflict resolution for the collapsed border model
2
3use super::types::{CollapsedBorder, TableLayout};
4
5impl TableLayout {
6    /// Resolve border conflicts for collapsed border model
7    ///
8    /// According to CSS2.1 Section 17.6.2, when two borders collapse:
9    /// 1. Hidden takes precedence over all other styles
10    /// 2. None has the lowest precedence
11    /// 3. Wider borders take precedence over narrower ones
12    /// 4. If widths are equal, style precedence is:
13    ///    double > solid > dashed > dotted > ridge > outset > groove > inset
14    /// 5. If width and style are equal, the border from the cell wins over
15    ///    the one from the row, which wins over the table
16    pub fn resolve_border_conflict(
17        &self,
18        border1: CollapsedBorder,
19        border2: CollapsedBorder,
20    ) -> CollapsedBorder {
21        use crate::area::BorderStyle;
22
23        // Rule 1: Hidden takes precedence
24        if matches!(border1.style, BorderStyle::Hidden) {
25            return border1;
26        }
27        if matches!(border2.style, BorderStyle::Hidden) {
28            return border2;
29        }
30
31        // Rule 2: None has lowest precedence
32        if matches!(border1.style, BorderStyle::None) && !matches!(border2.style, BorderStyle::None)
33        {
34            return border2;
35        }
36        if matches!(border2.style, BorderStyle::None) && !matches!(border1.style, BorderStyle::None)
37        {
38            return border1;
39        }
40        if matches!(border1.style, BorderStyle::None) && matches!(border2.style, BorderStyle::None)
41        {
42            return border1; // Both none, return either
43        }
44
45        // Rule 3: Wider border wins
46        if border1.width > border2.width {
47            return border1;
48        }
49        if border2.width > border1.width {
50            return border2;
51        }
52
53        // Rule 4: If widths are equal, compare styles
54        let style1_precedence = self.border_style_precedence(border1.style);
55        let style2_precedence = self.border_style_precedence(border2.style);
56
57        if style1_precedence > style2_precedence {
58            return border1;
59        }
60        if style2_precedence > style1_precedence {
61            return border2;
62        }
63
64        // Rule 5: If both width and style are equal, prefer border1
65        // (assuming border1 comes from a more specific element)
66        border1
67    }
68
69    /// Get border style precedence for conflict resolution
70    ///
71    /// Higher values have higher precedence.
72    fn border_style_precedence(&self, style: crate::area::BorderStyle) -> u8 {
73        use crate::area::BorderStyle;
74        match style {
75            BorderStyle::Hidden => 10, // Highest (but handled separately)
76            BorderStyle::Double => 9,
77            BorderStyle::Solid => 8,
78            BorderStyle::Dashed => 7,
79            BorderStyle::Dotted => 6,
80            BorderStyle::Ridge => 5,
81            BorderStyle::Outset => 4,
82            BorderStyle::Groove => 3,
83            BorderStyle::Inset => 2,
84            BorderStyle::None => 0, // Lowest (but handled separately)
85        }
86    }
87}