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 pub fn index_for_position(
203 &self,
204 position: Point<Pixels>,
205 line_height: Pixels,
206 ) -> Option<usize> {
207 let wrapped_line_ix = (position.y / line_height) as usize;
208
209 let wrapped_line_start_x = if wrapped_line_ix > 0 {
210 let wrap_boundary_ix = wrapped_line_ix - 1;
211 let wrap_boundary = self.wrap_boundaries[wrap_boundary_ix];
212 let run = &self.unwrapped_layout.runs[wrap_boundary.run_ix];
213 run.glyphs[wrap_boundary.glyph_ix].position.x
214 } else {
215 Pixels::ZERO
216 };
217
218 let wrapped_line_end_x = if wrapped_line_ix < self.wrap_boundaries.len() {
219 let next_wrap_boundary_ix = wrapped_line_ix;
220 let next_wrap_boundary = self.wrap_boundaries[next_wrap_boundary_ix];
221 let run = &self.unwrapped_layout.runs[next_wrap_boundary.run_ix];
222 run.glyphs[next_wrap_boundary.glyph_ix].position.x
223 } else {
224 self.unwrapped_layout.width
225 };
226
227 let mut position_in_unwrapped_line = position;
228 position_in_unwrapped_line.x += wrapped_line_start_x;
229 if position_in_unwrapped_line.x > wrapped_line_end_x {
230 None
231 } else {
232 self.unwrapped_layout
233 .index_for_x(position_in_unwrapped_line.x)
234 }
235 }
236}
237
238pub(crate) struct LineLayoutCache {
239 previous_frame: Mutex<HashMap<CacheKey, Arc<LineLayout>>>,
240 current_frame: RwLock<HashMap<CacheKey, Arc<LineLayout>>>,
241 previous_frame_wrapped: Mutex<HashMap<CacheKey, Arc<WrappedLineLayout>>>,
242 current_frame_wrapped: RwLock<HashMap<CacheKey, Arc<WrappedLineLayout>>>,
243 platform_text_system: Arc<dyn PlatformTextSystem>,
244}
245
246impl LineLayoutCache {
247 pub fn new(platform_text_system: Arc<dyn PlatformTextSystem>) -> Self {
248 Self {
249 previous_frame: Mutex::default(),
250 current_frame: RwLock::default(),
251 previous_frame_wrapped: Mutex::default(),
252 current_frame_wrapped: RwLock::default(),
253 platform_text_system,
254 }
255 }
256
257 pub fn start_frame(&self) {
258 let mut prev_frame = self.previous_frame.lock();
259 let mut curr_frame = self.current_frame.write();
260 std::mem::swap(&mut *prev_frame, &mut *curr_frame);
261 curr_frame.clear();
262 }
263
264 pub fn layout_wrapped_line(
265 &self,
266 text: &str,
267 font_size: Pixels,
268 runs: &[FontRun],
269 wrap_width: Option<Pixels>,
270 ) -> Arc<WrappedLineLayout> {
271 let key = &CacheKeyRef {
272 text,
273 font_size,
274 runs,
275 wrap_width,
276 } as &dyn AsCacheKeyRef;
277
278 let current_frame = self.current_frame_wrapped.upgradable_read();
279 if let Some(layout) = current_frame.get(key) {
280 return layout.clone();
281 }
282
283 let mut current_frame = RwLockUpgradableReadGuard::upgrade(current_frame);
284 if let Some((key, layout)) = self.previous_frame_wrapped.lock().remove_entry(key) {
285 current_frame.insert(key, layout.clone());
286 layout
287 } else {
288 let unwrapped_layout = self.layout_line(text, font_size, runs);
289 let wrap_boundaries = if let Some(wrap_width) = wrap_width {
290 unwrapped_layout.compute_wrap_boundaries(text.as_ref(), wrap_width)
291 } else {
292 SmallVec::new()
293 };
294 let layout = Arc::new(WrappedLineLayout {
295 unwrapped_layout,
296 wrap_boundaries,
297 wrap_width,
298 });
299 let key = CacheKey {
300 text: text.into(),
301 font_size,
302 runs: SmallVec::from(runs),
303 wrap_width,
304 };
305 current_frame.insert(key, layout.clone());
306 layout
307 }
308 }
309
310 pub fn layout_line(&self, text: &str, font_size: Pixels, runs: &[FontRun]) -> Arc<LineLayout> {
311 let key = &CacheKeyRef {
312 text,
313 font_size,
314 runs,
315 wrap_width: None,
316 } as &dyn AsCacheKeyRef;
317
318 let current_frame = self.current_frame.upgradable_read();
319 if let Some(layout) = current_frame.get(key) {
320 return layout.clone();
321 }
322
323 let mut current_frame = RwLockUpgradableReadGuard::upgrade(current_frame);
324 if let Some((key, layout)) = self.previous_frame.lock().remove_entry(key) {
325 current_frame.insert(key, layout.clone());
326 layout
327 } else {
328 let layout = Arc::new(self.platform_text_system.layout_line(text, font_size, runs));
329 let key = CacheKey {
330 text: text.into(),
331 font_size,
332 runs: SmallVec::from(runs),
333 wrap_width: None,
334 };
335 current_frame.insert(key, layout.clone());
336 layout
337 }
338 }
339}
340
341#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
342pub struct FontRun {
343 pub(crate) len: usize,
344 pub(crate) font_id: FontId,
345}
346
347trait AsCacheKeyRef {
348 fn as_cache_key_ref(&self) -> CacheKeyRef;
349}
350
351#[derive(Eq)]
352struct CacheKey {
353 text: String,
354 font_size: Pixels,
355 runs: SmallVec<[FontRun; 1]>,
356 wrap_width: Option<Pixels>,
357}
358
359#[derive(Copy, Clone, PartialEq, Eq, Hash)]
360struct CacheKeyRef<'a> {
361 text: &'a str,
362 font_size: Pixels,
363 runs: &'a [FontRun],
364 wrap_width: Option<Pixels>,
365}
366
367impl<'a> PartialEq for (dyn AsCacheKeyRef + 'a) {
368 fn eq(&self, other: &dyn AsCacheKeyRef) -> bool {
369 self.as_cache_key_ref() == other.as_cache_key_ref()
370 }
371}
372
373impl<'a> Eq for (dyn AsCacheKeyRef + 'a) {}
374
375impl<'a> Hash for (dyn AsCacheKeyRef + 'a) {
376 fn hash<H: Hasher>(&self, state: &mut H) {
377 self.as_cache_key_ref().hash(state)
378 }
379}
380
381impl AsCacheKeyRef for CacheKey {
382 fn as_cache_key_ref(&self) -> CacheKeyRef {
383 CacheKeyRef {
384 text: &self.text,
385 font_size: self.font_size,
386 runs: self.runs.as_slice(),
387 wrap_width: self.wrap_width,
388 }
389 }
390}
391
392impl PartialEq for CacheKey {
393 fn eq(&self, other: &Self) -> bool {
394 self.as_cache_key_ref().eq(&other.as_cache_key_ref())
395 }
396}
397
398impl Hash for CacheKey {
399 fn hash<H: Hasher>(&self, state: &mut H) {
400 self.as_cache_key_ref().hash(state);
401 }
402}
403
404impl<'a> Borrow<dyn AsCacheKeyRef + 'a> for CacheKey {
405 fn borrow(&self) -> &(dyn AsCacheKeyRef + 'a) {
406 self as &dyn AsCacheKeyRef
407 }
408}
409
410impl<'a> AsCacheKeyRef for CacheKeyRef<'a> {
411 fn as_cache_key_ref(&self) -> CacheKeyRef {
412 *self
413 }
414}