1use crate::{px, FontId, GlyphId, Pixels, PlatformTextSystem, Point, Size};
2use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
3use smallvec::SmallVec;
4use std::{
5 borrow::Borrow,
6 collections::HashMap,
7 hash::{Hash, Hasher},
8 sync::Arc,
9};
10
11#[derive(Default, Debug)]
12pub struct LineLayout {
13 pub font_size: Pixels,
14 pub width: Pixels,
15 pub ascent: Pixels,
16 pub descent: Pixels,
17 pub runs: Vec<ShapedRun>,
18 pub len: usize,
19}
20
21#[derive(Debug)]
22pub struct ShapedRun {
23 pub font_id: FontId,
24 pub glyphs: SmallVec<[ShapedGlyph; 8]>,
25}
26
27#[derive(Clone, Debug)]
28pub struct ShapedGlyph {
29 pub id: GlyphId,
30 pub position: Point<Pixels>,
31 pub index: usize,
32 pub is_emoji: bool,
33}
34
35impl LineLayout {
36 pub fn index_for_x(&self, x: Pixels) -> Option<usize> {
37 if x >= self.width {
38 None
39 } else {
40 for run in self.runs.iter().rev() {
41 for glyph in run.glyphs.iter().rev() {
42 if glyph.position.x <= x {
43 return Some(glyph.index);
44 }
45 }
46 }
47 Some(0)
48 }
49 }
50
51 /// closest_index_for_x returns the character boundary closest to the given x coordinate
52 /// (e.g. to handle aligning up/down arrow keys)
53 pub fn closest_index_for_x(&self, x: Pixels) -> usize {
54 let mut prev_index = 0;
55 let mut prev_x = px(0.);
56
57 for run in self.runs.iter() {
58 for glyph in run.glyphs.iter() {
59 if glyph.position.x >= x {
60 if glyph.position.x - x < x - prev_x {
61 return glyph.index;
62 } else {
63 return prev_index;
64 }
65 }
66 prev_index = glyph.index;
67 prev_x = glyph.position.x;
68 }
69 }
70
71 self.len
72 }
73
74 pub fn x_for_index(&self, index: usize) -> Pixels {
75 for run in &self.runs {
76 for glyph in &run.glyphs {
77 if glyph.index >= index {
78 return glyph.position.x;
79 }
80 }
81 }
82 self.width
83 }
84
85 fn compute_wrap_boundaries(
86 &self,
87 text: &str,
88 wrap_width: Pixels,
89 ) -> SmallVec<[WrapBoundary; 1]> {
90 let mut boundaries = SmallVec::new();
91
92 let mut first_non_whitespace_ix = None;
93 let mut last_candidate_ix = None;
94 let mut last_candidate_x = px(0.);
95 let mut last_boundary = WrapBoundary {
96 run_ix: 0,
97 glyph_ix: 0,
98 };
99 let mut last_boundary_x = px(0.);
100 let mut prev_ch = '\0';
101 let mut glyphs = self
102 .runs
103 .iter()
104 .enumerate()
105 .flat_map(move |(run_ix, run)| {
106 run.glyphs.iter().enumerate().map(move |(glyph_ix, glyph)| {
107 let character = text[glyph.index..].chars().next().unwrap();
108 (
109 WrapBoundary { run_ix, glyph_ix },
110 character,
111 glyph.position.x,
112 )
113 })
114 })
115 .peekable();
116
117 while let Some((boundary, ch, x)) = glyphs.next() {
118 if ch == '\n' {
119 continue;
120 }
121
122 if prev_ch == ' ' && ch != ' ' && first_non_whitespace_ix.is_some() {
123 last_candidate_ix = Some(boundary);
124 last_candidate_x = x;
125 }
126
127 if ch != ' ' && first_non_whitespace_ix.is_none() {
128 first_non_whitespace_ix = Some(boundary);
129 }
130
131 let next_x = glyphs.peek().map_or(self.width, |(_, _, x)| *x);
132 let width = next_x - last_boundary_x;
133 if width > wrap_width && boundary > last_boundary {
134 if let Some(last_candidate_ix) = last_candidate_ix.take() {
135 last_boundary = last_candidate_ix;
136 last_boundary_x = last_candidate_x;
137 } else {
138 last_boundary = boundary;
139 last_boundary_x = x;
140 }
141
142 boundaries.push(last_boundary);
143 }
144 prev_ch = ch;
145 }
146
147 boundaries
148 }
149}
150
151#[derive(Default, Debug)]
152pub struct WrappedLineLayout {
153 pub unwrapped_layout: Arc<LineLayout>,
154 pub wrap_boundaries: SmallVec<[WrapBoundary; 1]>,
155 pub wrap_width: Option<Pixels>,
156}
157
158#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
159pub struct WrapBoundary {
160 pub run_ix: usize,
161 pub glyph_ix: usize,
162}
163
164impl WrappedLineLayout {
165 pub fn len(&self) -> usize {
166 self.unwrapped_layout.len
167 }
168
169 pub fn width(&self) -> Pixels {
170 self.wrap_width
171 .unwrap_or(Pixels::MAX)
172 .min(self.unwrapped_layout.width)
173 }
174
175 pub fn size(&self, line_height: Pixels) -> Size<Pixels> {
176 Size {
177 width: self.width(),
178 height: line_height * (self.wrap_boundaries.len() + 1),
179 }
180 }
181
182 pub fn ascent(&self) -> Pixels {
183 self.unwrapped_layout.ascent
184 }
185
186 pub fn descent(&self) -> Pixels {
187 self.unwrapped_layout.descent
188 }
189
190 pub fn wrap_boundaries(&self) -> &[WrapBoundary] {
191 &self.wrap_boundaries
192 }
193
194 pub fn font_size(&self) -> Pixels {
195 self.unwrapped_layout.font_size
196 }
197
198 pub fn runs(&self) -> &[ShapedRun] {
199 &self.unwrapped_layout.runs
200 }
201}
202
203pub(crate) struct LineLayoutCache {
204 previous_frame: Mutex<HashMap<CacheKey, Arc<LineLayout>>>,
205 current_frame: RwLock<HashMap<CacheKey, Arc<LineLayout>>>,
206 previous_frame_wrapped: Mutex<HashMap<CacheKey, Arc<WrappedLineLayout>>>,
207 current_frame_wrapped: RwLock<HashMap<CacheKey, Arc<WrappedLineLayout>>>,
208 platform_text_system: Arc<dyn PlatformTextSystem>,
209}
210
211impl LineLayoutCache {
212 pub fn new(platform_text_system: Arc<dyn PlatformTextSystem>) -> Self {
213 Self {
214 previous_frame: Mutex::default(),
215 current_frame: RwLock::default(),
216 previous_frame_wrapped: Mutex::default(),
217 current_frame_wrapped: RwLock::default(),
218 platform_text_system,
219 }
220 }
221
222 pub fn start_frame(&self) {
223 let mut prev_frame = self.previous_frame.lock();
224 let mut curr_frame = self.current_frame.write();
225 std::mem::swap(&mut *prev_frame, &mut *curr_frame);
226 curr_frame.clear();
227 }
228
229 pub fn layout_wrapped_line(
230 &self,
231 text: &str,
232 font_size: Pixels,
233 runs: &[FontRun],
234 wrap_width: Option<Pixels>,
235 ) -> Arc<WrappedLineLayout> {
236 let key = &CacheKeyRef {
237 text,
238 font_size,
239 runs,
240 wrap_width,
241 } as &dyn AsCacheKeyRef;
242
243 let current_frame = self.current_frame_wrapped.upgradable_read();
244 if let Some(layout) = current_frame.get(key) {
245 return layout.clone();
246 }
247
248 let mut current_frame = RwLockUpgradableReadGuard::upgrade(current_frame);
249 if let Some((key, layout)) = self.previous_frame_wrapped.lock().remove_entry(key) {
250 current_frame.insert(key, layout.clone());
251 layout
252 } else {
253 let unwrapped_layout = self.layout_line(text, font_size, runs);
254 let wrap_boundaries = if let Some(wrap_width) = wrap_width {
255 unwrapped_layout.compute_wrap_boundaries(text.as_ref(), wrap_width)
256 } else {
257 SmallVec::new()
258 };
259 let layout = Arc::new(WrappedLineLayout {
260 unwrapped_layout,
261 wrap_boundaries,
262 wrap_width,
263 });
264 let key = CacheKey {
265 text: text.into(),
266 font_size,
267 runs: SmallVec::from(runs),
268 wrap_width,
269 };
270 current_frame.insert(key, layout.clone());
271 layout
272 }
273 }
274
275 pub fn layout_line(&self, text: &str, font_size: Pixels, runs: &[FontRun]) -> Arc<LineLayout> {
276 let key = &CacheKeyRef {
277 text,
278 font_size,
279 runs,
280 wrap_width: None,
281 } as &dyn AsCacheKeyRef;
282
283 let current_frame = self.current_frame.upgradable_read();
284 if let Some(layout) = current_frame.get(key) {
285 return layout.clone();
286 }
287
288 let mut current_frame = RwLockUpgradableReadGuard::upgrade(current_frame);
289 if let Some((key, layout)) = self.previous_frame.lock().remove_entry(key) {
290 current_frame.insert(key, layout.clone());
291 layout
292 } else {
293 let layout = Arc::new(self.platform_text_system.layout_line(text, font_size, runs));
294 let key = CacheKey {
295 text: text.into(),
296 font_size,
297 runs: SmallVec::from(runs),
298 wrap_width: None,
299 };
300 current_frame.insert(key, layout.clone());
301 layout
302 }
303 }
304}
305
306#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
307pub struct FontRun {
308 pub(crate) len: usize,
309 pub(crate) font_id: FontId,
310}
311
312trait AsCacheKeyRef {
313 fn as_cache_key_ref(&self) -> CacheKeyRef;
314}
315
316#[derive(Eq)]
317struct CacheKey {
318 text: String,
319 font_size: Pixels,
320 runs: SmallVec<[FontRun; 1]>,
321 wrap_width: Option<Pixels>,
322}
323
324#[derive(Copy, Clone, PartialEq, Eq, Hash)]
325struct CacheKeyRef<'a> {
326 text: &'a str,
327 font_size: Pixels,
328 runs: &'a [FontRun],
329 wrap_width: Option<Pixels>,
330}
331
332impl<'a> PartialEq for (dyn AsCacheKeyRef + 'a) {
333 fn eq(&self, other: &dyn AsCacheKeyRef) -> bool {
334 self.as_cache_key_ref() == other.as_cache_key_ref()
335 }
336}
337
338impl<'a> Eq for (dyn AsCacheKeyRef + 'a) {}
339
340impl<'a> Hash for (dyn AsCacheKeyRef + 'a) {
341 fn hash<H: Hasher>(&self, state: &mut H) {
342 self.as_cache_key_ref().hash(state)
343 }
344}
345
346impl AsCacheKeyRef for CacheKey {
347 fn as_cache_key_ref(&self) -> CacheKeyRef {
348 CacheKeyRef {
349 text: &self.text,
350 font_size: self.font_size,
351 runs: self.runs.as_slice(),
352 wrap_width: self.wrap_width,
353 }
354 }
355}
356
357impl PartialEq for CacheKey {
358 fn eq(&self, other: &Self) -> bool {
359 self.as_cache_key_ref().eq(&other.as_cache_key_ref())
360 }
361}
362
363impl Hash for CacheKey {
364 fn hash<H: Hasher>(&self, state: &mut H) {
365 self.as_cache_key_ref().hash(state);
366 }
367}
368
369impl<'a> Borrow<dyn AsCacheKeyRef + 'a> for CacheKey {
370 fn borrow(&self) -> &(dyn AsCacheKeyRef + 'a) {
371 self as &dyn AsCacheKeyRef
372 }
373}
374
375impl<'a> AsCacheKeyRef for CacheKeyRef<'a> {
376 fn as_cache_key_ref(&self) -> CacheKeyRef {
377 *self
378 }
379}