Skip to main content

sequoia_layout/
ctx.rs

1//! Text measurement context used during layout.
2
3use sequoia_core::Size;
4use sequoia_text::{
5    ElideMode, FontStyle, FontWeight, LetterSpacing, RichAlign, TextSpan, TextSystem, WrapMode,
6};
7
8/// Borrowed text system used by layout code to shape and measure text.
9///
10/// Measurements are not cached here; the underlying [`TextSystem`] owns any
11/// caching that may occur.
12pub struct LayoutCtx<'a> {
13    text: &'a mut TextSystem,
14    default_font_size: f32,
15}
16
17impl<'a> LayoutCtx<'a> {
18    /// Creates a context that borrows `text` and uses `default_font_size` for
19    /// callers that do not specify a size.
20    pub fn new(text: &'a mut TextSystem, default_font_size: f32) -> Self {
21        Self {
22            text,
23            default_font_size,
24        }
25    }
26
27    /// Returns the default font size for this layout pass.
28    pub fn default_font_size(&self) -> f32 {
29        self.default_font_size
30    }
31
32    /// Measures the width of a single line of text.
33    pub fn text_width(&mut self, text: &str, size: f32) -> f32 {
34        self.text.text_width(text, size)
35    }
36
37    /// Measures the width of a single line using the given font weight.
38    pub fn text_width_weighted(&mut self, text: &str, size: f32, weight: FontWeight) -> f32 {
39        self.text.text_width_weighted(text, size, weight)
40    }
41
42    /// Measures the width of a single line with letter spacing.
43    pub fn text_width_spaced(&mut self, text: &str, size: f32, spacing: LetterSpacing) -> f32 {
44        self.text.text_width_spaced(text, size, spacing)
45    }
46
47    /// Measures the width of a single line with weight and letter spacing.
48    pub fn text_width_weighted_spaced(
49        &mut self,
50        text: &str,
51        size: f32,
52        weight: FontWeight,
53        spacing: LetterSpacing,
54    ) -> f32 {
55        self.text
56            .text_width_weighted_spaced(text, size, weight, spacing)
57    }
58
59    /// Measures the width of a single line with weight, spacing, family, and
60    /// style.
61    pub fn text_width_styled_spaced(
62        &mut self,
63        text: &str,
64        size: f32,
65        weight: FontWeight,
66        spacing: LetterSpacing,
67        family: Option<&str>,
68        style: FontStyle,
69    ) -> f32 {
70        self.text
71            .text_width_styled_spaced(text, size, weight, spacing, family, style)
72    }
73
74    /// Returns caret positions along a single line of text.
75    pub fn caret_positions(&mut self, text: &str, size: f32, weight: FontWeight) -> Vec<f32> {
76        self.text.caret_positions(text, size, weight)
77    }
78
79    /// Returns caret positions along a single line with letter spacing.
80    pub fn caret_positions_spaced(
81        &mut self,
82        text: &str,
83        size: f32,
84        weight: FontWeight,
85        spacing: LetterSpacing,
86    ) -> Vec<f32> {
87        self.text
88            .caret_positions_spaced(text, size, weight, spacing)
89    }
90
91    /// Measures wrapped text within `width`, returning its size.
92    pub fn text_wrapped_size(
93        &mut self,
94        text: &str,
95        size: f32,
96        weight: FontWeight,
97        width: f32,
98        mode: WrapMode,
99    ) -> Size {
100        self.text_wrapped_size_spaced(text, size, weight, width, mode, 0.0)
101    }
102
103    /// Measures wrapped text within `width` with letter spacing.
104    pub fn text_wrapped_size_spaced(
105        &mut self,
106        text: &str,
107        size: f32,
108        weight: FontWeight,
109        width: f32,
110        mode: WrapMode,
111        spacing: LetterSpacing,
112    ) -> Size {
113        let shaped = self
114            .text
115            .shape_wrapped_spaced(text, size, weight, width, mode, spacing);
116        Size::new(shaped.width(), shaped.height())
117    }
118
119    /// Measures wrapped text with weight, spacing, family, and style.
120    pub fn text_wrapped_size_styled_spaced(
121        &mut self,
122        text: &str,
123        size: f32,
124        weight: FontWeight,
125        width: f32,
126        mode: WrapMode,
127        spacing: LetterSpacing,
128        family: Option<&str>,
129        style: FontStyle,
130    ) -> Size {
131        let shaped = self
132            .text
133            .shape_wrapped_styled_spaced(text, size, weight, width, mode, spacing, family, style);
134        Size::new(shaped.width(), shaped.height())
135    }
136
137    /// Measures text elided to `max_width` with the given elision mode.
138    pub fn text_elided_size(
139        &mut self,
140        text: &str,
141        size: f32,
142        weight: FontWeight,
143        max_width: f32,
144        mode: ElideMode,
145    ) -> Size {
146        self.text_elided_size_spaced(text, size, weight, max_width, mode, 0.0)
147    }
148
149    /// Measures elided text with letter spacing.
150    pub fn text_elided_size_spaced(
151        &mut self,
152        text: &str,
153        size: f32,
154        weight: FontWeight,
155        max_width: f32,
156        mode: ElideMode,
157        spacing: LetterSpacing,
158    ) -> Size {
159        let shown = self
160            .text
161            .elide_spaced(text, size, weight, max_width, mode, spacing);
162        let w = self
163            .text
164            .text_width_weighted_spaced(&shown, size, weight, spacing)
165            .min(max_width.max(0.0));
166        Size::new(w, Self::text_line_height(size))
167    }
168
169    /// Measures elided text with weight, spacing, family, and style.
170    pub fn text_elided_size_styled_spaced(
171        &mut self,
172        text: &str,
173        size: f32,
174        weight: FontWeight,
175        max_width: f32,
176        mode: ElideMode,
177        spacing: LetterSpacing,
178        family: Option<&str>,
179        style: FontStyle,
180    ) -> Size {
181        let shown = self
182            .text
183            .elide_styled_spaced(text, size, weight, max_width, mode, spacing, family, style);
184        let w = self
185            .text
186            .text_width_styled_spaced(&shown, size, weight, spacing, family, style)
187            .min(max_width.max(0.0));
188        Size::new(w, Self::text_line_height(size))
189    }
190
191    /// Returns the line height used for a font size.
192    pub fn text_line_height(size: f32) -> f32 {
193        size * 1.35
194    }
195
196    /// Measures rich text spans, returning their shaped size.
197    pub fn rich_size(
198        &mut self,
199        spans: &[TextSpan],
200        size: f32,
201        width: f32,
202        mode: WrapMode,
203        spacing: LetterSpacing,
204        align: RichAlign,
205    ) -> Size {
206        self.text
207            .shape_rich_full(spans, size, width, mode, spacing, align)
208            .size()
209    }
210}