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}