Skip to main content

max / balanced_breakfast

2.1 KB · 77 lines History Blame Raw
1 //! Page geometry and text-width estimation.
2 //!
3 //! We use approximate Helvetica metrics rather than pulling real AFM tables
4 //! or a font-shaping crate. The approximation slightly overcounts width so
5 //! we err on the side of shorter lines rather than clipping the right edge.
6
7 use printpdf::Mm;
8
9 pub(crate) const PAGE_W: Mm = Mm(148.0);
10 pub(crate) const PAGE_H: Mm = Mm(210.0);
11 pub(crate) const MARGIN: Mm = Mm(14.0);
12
13 pub(crate) const BODY_PT: f32 = 11.0;
14 pub(crate) const H1_PT: f32 = 20.0;
15 pub(crate) const H2_PT: f32 = 16.0;
16 pub(crate) const H3_PT: f32 = 13.0;
17 pub(crate) const MONO_PT: f32 = 10.0;
18
19 pub(crate) const LINE_GAP: f32 = 1.35;
20 pub(crate) const BLOCK_GAP_MM: f32 = 3.5;
21 pub(crate) const HEADING_GAP_MM: f32 = 5.5;
22 pub(crate) const LIST_INDENT_MM: f32 = 6.0;
23 pub(crate) const QUOTE_INDENT_MM: f32 = 5.0;
24
25 pub(crate) fn content_width_mm() -> f32 {
26 PAGE_W.0 - MARGIN.0 * 2.0
27 }
28
29 pub(crate) fn content_top_mm() -> f32 {
30 PAGE_H.0 - MARGIN.0
31 }
32
33 pub(crate) fn content_bottom_mm() -> f32 {
34 MARGIN.0
35 }
36
37 /// Approximate width in mm of `text` rendered in Helvetica at `pt`.
38 ///
39 /// Uses a per-family average advance width of 0.52em (bold slightly wider).
40 /// 1pt = 25.4/72 mm.
41 pub(crate) fn text_width_mm(text: &str, pt: f32, bold: bool, mono: bool) -> f32 {
42 let avg_em = if mono {
43 0.60
44 } else if bold {
45 0.56
46 } else {
47 0.52
48 };
49 let mm_per_pt = 25.4 / 72.0;
50 text.chars().count() as f32 * pt * avg_em * mm_per_pt
51 }
52
53 pub(crate) fn line_height_mm(pt: f32) -> f32 {
54 pt * LINE_GAP * 25.4 / 72.0
55 }
56
57 #[cfg(test)]
58 mod tests {
59 use super::*;
60
61 #[test]
62 fn width_grows_with_length_and_size() {
63 let a = text_width_mm("hello", BODY_PT, false, false);
64 let b = text_width_mm("hello world", BODY_PT, false, false);
65 let c = text_width_mm("hello", H1_PT, false, false);
66 assert!(b > a);
67 assert!(c > a);
68 }
69
70 #[test]
71 fn bold_wider_than_regular() {
72 let r = text_width_mm("hello", BODY_PT, false, false);
73 let b = text_width_mm("hello", BODY_PT, true, false);
74 assert!(b > r);
75 }
76 }
77