1extern crate alloc;
2use alloc::vec::Vec;
3
4use crate::math::Num;
5use crate::{Item, Line, ParagraphLayout};
6
7pub struct FirstFit<N> {
9 threshold: N,
10 allow_overflow: bool,
11}
12
13impl<N: Num> FirstFit<N> {
14 pub fn new() -> Self {
16 FirstFit {
17 threshold: N::from(1),
18 allow_overflow: false,
19 }
20 }
21
22 pub fn with_threshold(mut self, threshold: N) -> Self {
25 self.threshold = threshold;
26 self
27 }
28
29 pub fn allow_overflow(mut self, allow_overflow: bool) -> Self {
32 self.allow_overflow = allow_overflow;
33 self
34 }
35}
36
37impl<N: Num> Default for FirstFit<N> {
38 fn default() -> Self {
39 Self::new()
40 }
41}
42
43impl<Box, Glue, Penalty, N: Num> ParagraphLayout<Box, Glue, Penalty, N> for FirstFit<N> {
44 fn layout_paragraph(
45 &self,
46 items: &[Item<Box, Glue, Penalty, N>],
47 line_width: N,
48 ) -> Vec<Line<N>> {
49 let l = FirstFitLayout {
50 line_width,
51 threshold: self.threshold,
52 allow_overflow: self.allow_overflow,
53 width: N::from(0),
54 stretch: N::from(0),
55 shrink: N::from(0),
56 lines: Vec::new(),
57 };
58 l.layout_paragraph(items)
59 }
60}
61
62struct Break<N> {
63 width: N,
64 stretch: N,
65 shrink: N,
66 adjustment_ratio: N,
67 is_mandatory: bool,
68 at: usize,
69}
70
71struct FirstFitLayout<N: Num> {
72 line_width: N,
73
74 threshold: N,
75 allow_overflow: bool,
76
77 width: N,
78 stretch: N,
79 shrink: N,
80
81 lines: Vec<Line<N>>,
82}
83
84impl<N: Num> FirstFitLayout<N> {
85 fn break_at(&mut self, b: Break<N>) {
86 self.lines.push(Line {
87 break_at: b.at,
88 adjustment_ratio: b.adjustment_ratio,
89 });
90
91 self.width -= b.width;
92 self.stretch -= b.stretch;
93 self.shrink -= b.shrink;
94 }
95
96 fn layout_paragraph<Box, Glue, Penalty>(
97 mut self,
98 items: &[Item<Box, Glue, Penalty, N>],
99 ) -> Vec<Line<N>> {
100 let mut last_breakpoint: Option<Break<N>> = None;
101 for (b, item) in items.iter().enumerate() {
102 let (width, stretch, shrink, is_legal) =
103 item.is_legal_breakpoint((b != 0).then(|| &items[b - 1]));
104 if is_legal {
105 let adjustment_ratio =
106 item.adjustment_ratio(self.width, self.stretch, self.shrink, self.line_width);
107 if let Some(b) = last_breakpoint {
108 if adjustment_ratio < N::from(-1)
109 || adjustment_ratio > self.threshold
110 || b.is_mandatory
111 {
112 self.break_at(b);
113 }
114 }
115
116 let adjustment_ratio =
117 item.adjustment_ratio(self.width, self.stretch, self.shrink, self.line_width);
118
119 let adjustment_ratio = if adjustment_ratio < N::from(-1) {
120 if !self.allow_overflow {
121 return Vec::new();
122 }
123 N::from(0)
124 } else {
125 adjustment_ratio
126 };
127 if adjustment_ratio > self.threshold {
128 return Vec::new();
129 }
130
131 last_breakpoint = Some(Break {
132 width: self.width,
133 stretch: self.stretch,
134 shrink: self.shrink,
135 adjustment_ratio,
136 is_mandatory: item.is_mandatory_break(),
137 at: b,
138 });
139 }
140
141 self.width += width;
142 self.stretch += stretch;
143 self.shrink += shrink;
144 }
145 if let Some(b) = last_breakpoint {
146 self.break_at(b);
147 }
148
149 self.lines
150 }
151}