laser_pdf/elements/
expand_to_preferred_height.rs1use crate::{utils::max_optional_size, *};
2
3pub struct ExpandToPreferredHeight<E: Element>(pub E);
4
5impl<E: Element> Element for ExpandToPreferredHeight<E> {
6 fn first_location_usage(&self, ctx: FirstLocationUsageCtx) -> FirstLocationUsage {
7 self.0.first_location_usage(ctx)
8 }
9
10 fn measure(&self, ctx: MeasureCtx) -> ElementSize {
11 self.0.measure(ctx)
12 }
13
14 fn draw(&self, ctx: DrawCtx) -> ElementSize {
15 let preferred_height = ctx.preferred_height;
16 let preferred_breaks = ctx
17 .breakable
18 .as_ref()
19 .map(|b| b.preferred_height_break_count)
20 .unwrap_or(0);
21
22 let size;
23 let height;
24
25 if let Some(breakable) = ctx.breakable {
26 let mut break_count = 0;
27
28 size = self.0.draw(DrawCtx {
29 pdf: ctx.pdf,
30 breakable: Some(BreakableDraw {
31 do_break: &mut |pdf, location_idx, _height| {
32 break_count = break_count.max(location_idx + 1);
33
34 (breakable.do_break)(
35 pdf,
36 location_idx,
37 if location_idx == 0 {
39 Some(ctx.first_height)
40 } else {
41 Some(breakable.full_height)
42 },
43 )
44 },
45 ..breakable
46 }),
47
48 ..ctx
49 });
50
51 match break_count.cmp(&preferred_breaks) {
52 std::cmp::Ordering::Less => {
53 for i in break_count..preferred_breaks {
56 (breakable.do_break)(
57 ctx.pdf,
58 i,
59 if i == 0 {
60 Some(ctx.first_height)
61 } else {
62 Some(breakable.full_height)
63 },
64 );
65 }
66
67 height = preferred_height;
68 }
69 std::cmp::Ordering::Equal => {
70 height = max_optional_size(size.height, preferred_height);
71 }
72 std::cmp::Ordering::Greater => {
73 height = size.height;
74 }
75 }
76 } else {
77 size = self.0.draw(ctx);
78 height = max_optional_size(size.height, preferred_height);
79 }
80
81 ElementSize { height, ..size }
82 }
83}
84#[cfg(test)]
85mod tests {
86 use super::*;
87 use crate::{
88 elements::text::Text, fonts::builtin::BuiltinFont, test_utils::binary_snapshots::*,
89 };
90 use insta::*;
91
92 #[test]
93 fn test_basic() {
94 let bytes = test_element_bytes(
95 TestElementParams {
96 preferred_height: Some(12.),
97 breakable: Some(TestElementParamsBreakable {
98 preferred_height_break_count: 7,
99 full_height: TestElementParams::DEFAULT_FULL_HEIGHT,
100 }),
101 ..TestElementParams::breakable()
102 },
103 |mut callback| {
104 let font = BuiltinFont::courier(callback.pdf());
105
106 let content = Text::basic(LOREM_IPSUM, &font, 32.);
107 let content = content.debug(1);
108
109 callback.call(&ExpandToPreferredHeight(content).debug(0));
110 },
111 );
112 assert_binary_snapshot!(".pdf", bytes);
113 }
114
115 #[test]
116 fn test_single_location_content() {
117 let bytes = test_element_bytes(
118 TestElementParams {
119 preferred_height: Some(32.),
120 breakable: Some(TestElementParamsBreakable {
121 preferred_height_break_count: 3,
122 full_height: TestElementParams::DEFAULT_FULL_HEIGHT,
123 }),
124 ..TestElementParams::breakable()
125 },
126 |mut callback| {
127 let font = BuiltinFont::courier(callback.pdf());
128
129 let content = Text::basic(LOREM_IPSUM, &font, 12.);
130 let content = content.debug(1);
131
132 callback.call(&ExpandToPreferredHeight(content).debug(0));
133 },
134 );
135 assert_binary_snapshot!(".pdf", bytes);
136 }
137
138 }