Skip to main content

laser_pdf/test_utils/
build_element.rs

1use crate::*;
2
3pub struct BuildElementReturnToken(());
4
5// Is just here to ensure the callback can't be used more than once.
6pub struct BuildElementCallback<'a>(&'a mut dyn FnMut(&dyn Element));
7
8impl<'a> BuildElementCallback<'a> {
9    pub fn call(self, element: impl Element) -> BuildElementReturnToken {
10        self.0(&element);
11        BuildElementReturnToken(())
12    }
13}
14
15pub struct BreakableDraw {
16    pub full_height: f32,
17    pub preferred_height_break_count: u32,
18}
19
20pub enum Pass {
21    FirstLocationUsage {
22        full_height: f32,
23    },
24    Measure {
25        full_height: Option<f32>,
26    },
27    Draw {
28        preferred_height: Option<f32>,
29        breakable: Option<BreakableDraw>,
30    },
31}
32
33pub struct BuildElementCtx {
34    pub width: WidthConstraint,
35    pub first_height: f32,
36    pub pass: Pass,
37}
38
39impl BuildElementCtx {
40    pub fn is_breakable(&self) -> bool {
41        match self.pass {
42            Pass::FirstLocationUsage { .. } => true,
43            Pass::Measure { full_height } => full_height.is_some(),
44            Pass::Draw { ref breakable, .. } => breakable.is_some(),
45        }
46    }
47}
48
49pub struct BuildElement<F: Fn(BuildElementCtx, BuildElementCallback) -> BuildElementReturnToken>(
50    pub F,
51);
52
53impl<F: Fn(BuildElementCtx, BuildElementCallback) -> BuildElementReturnToken> Element
54    for BuildElement<F>
55{
56    fn first_location_usage(&self, ctx: FirstLocationUsageCtx) -> FirstLocationUsage {
57        let mut ret = FirstLocationUsage::NoneHeight;
58
59        let build_ctx = BuildElementCtx {
60            width: ctx.width,
61            first_height: ctx.first_height,
62            pass: Pass::FirstLocationUsage {
63                full_height: ctx.full_height,
64            },
65        };
66
67        let mut ctx = Some(ctx);
68
69        (self.0)(
70            build_ctx,
71            BuildElementCallback(&mut |e| ret = e.first_location_usage(ctx.take().unwrap())),
72        );
73        ret
74    }
75
76    fn measure(&self, ctx: MeasureCtx) -> ElementSize {
77        let mut ret = ElementSize {
78            width: None,
79            height: None,
80        };
81
82        let build_ctx = BuildElementCtx {
83            width: ctx.width,
84            first_height: ctx.first_height,
85            pass: Pass::Measure {
86                full_height: ctx.breakable.as_ref().map(|b| b.full_height),
87            },
88        };
89
90        let mut ctx = Some(ctx);
91
92        (self.0)(
93            build_ctx,
94            BuildElementCallback(&mut |e| ret = e.measure(ctx.take().unwrap())),
95        );
96        ret
97    }
98
99    fn draw(&self, ctx: DrawCtx) -> ElementSize {
100        let mut ret = ElementSize {
101            width: None,
102            height: None,
103        };
104
105        let build_ctx = BuildElementCtx {
106            width: ctx.width,
107            first_height: ctx.first_height,
108            pass: Pass::Draw {
109                preferred_height: ctx.preferred_height,
110                breakable: ctx.breakable.as_ref().map(|b| BreakableDraw {
111                    full_height: b.full_height,
112                    preferred_height_break_count: b.preferred_height_break_count,
113                }),
114            },
115        };
116
117        let mut ctx = Some(ctx);
118
119        (self.0)(
120            build_ctx,
121            BuildElementCallback(&mut |e| ret = e.draw(ctx.take().unwrap())),
122        );
123        ret
124    }
125}