1use crate::{px, EntityId, FontId, GlyphId, Pixels, PlatformTextSystem, Point, Size};
2use collections::{FxHashMap, FxHashSet};
3use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
4use smallvec::SmallVec;
5use std::{
6 borrow::Borrow,
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 view_stack: Mutex<Vec<EntityId>>,
240 previous_frame: Mutex<FxHashMap<CacheKey, Arc<LineLayout>>>,
241 current_frame: RwLock<FxHashMap<CacheKey, Arc<LineLayout>>>,
242 previous_frame_wrapped: Mutex<FxHashMap<CacheKey, Arc<WrappedLineLayout>>>,
243 current_frame_wrapped: RwLock<FxHashMap<CacheKey, Arc<WrappedLineLayout>>>,
244 platform_text_system: Arc<dyn PlatformTextSystem>,
245}
246
247impl LineLayoutCache {
248 pub fn new(platform_text_system: Arc<dyn PlatformTextSystem>) -> Self {
249 Self {
250 view_stack: Mutex::default(),
251 previous_frame: Mutex::default(),
252 current_frame: RwLock::default(),
253 previous_frame_wrapped: Mutex::default(),
254 current_frame_wrapped: RwLock::default(),
255 platform_text_system,
256 }
257 }
258
259 pub fn finish_frame(&self, reused_views: &FxHashSet<EntityId>) {
260 debug_assert_eq!(self.view_stack.lock().len(), 0);
261
262 let mut prev_frame = self.previous_frame.lock();
263 let mut curr_frame = self.current_frame.write();
264 for (key, layout) in prev_frame.drain() {
265 if key
266 .parent_view_id
267 .map_or(false, |view_id| reused_views.contains(&view_id))
268 {
269 curr_frame.insert(key, layout);
270 }
271 }
272 std::mem::swap(&mut *prev_frame, &mut *curr_frame);
273
274 let mut prev_frame_wrapped = self.previous_frame_wrapped.lock();
275 let mut curr_frame_wrapped = self.current_frame_wrapped.write();
276 for (key, layout) in prev_frame_wrapped.drain() {
277 if key
278 .parent_view_id
279 .map_or(false, |view_id| reused_views.contains(&view_id))
280 {
281 curr_frame_wrapped.insert(key, layout);
282 }
283 }
284 std::mem::swap(&mut *prev_frame_wrapped, &mut *curr_frame_wrapped);
285 }
286
287 pub fn with_view<R>(&self, view_id: EntityId, f: impl FnOnce() -> R) -> R {
288 self.view_stack.lock().push(view_id);
289 let result = f();
290 self.view_stack.lock().pop();
291 result
292 }
293
294 fn parent_view_id(&self) -> Option<EntityId> {
295 self.view_stack.lock().last().copied()
296 }
297
298 pub fn layout_wrapped_line(
299 &self,
300 text: &str,
301 font_size: Pixels,
302 runs: &[FontRun],
303 wrap_width: Option<Pixels>,
304 ) -> Arc<WrappedLineLayout> {
305 let key = &CacheKeyRef {
306 text,
307 font_size,
308 runs,
309 wrap_width,
310 parent_view_id: self.parent_view_id(),
311 } as &dyn AsCacheKeyRef;
312
313 let current_frame = self.current_frame_wrapped.upgradable_read();
314 if let Some(layout) = current_frame.get(key) {
315 return layout.clone();
316 }
317
318 let mut current_frame = RwLockUpgradableReadGuard::upgrade(current_frame);
319 if let Some((key, layout)) = self.previous_frame_wrapped.lock().remove_entry(key) {
320 current_frame.insert(key, layout.clone());
321 layout
322 } else {
323 let unwrapped_layout = self.layout_line(text, font_size, runs);
324 let wrap_boundaries = if let Some(wrap_width) = wrap_width {
325 unwrapped_layout.compute_wrap_boundaries(text.as_ref(), wrap_width)
326 } else {
327 SmallVec::new()
328 };
329 let layout = Arc::new(WrappedLineLayout {
330 unwrapped_layout,
331 wrap_boundaries,
332 wrap_width,
333 });
334 let key = CacheKey {
335 text: text.into(),
336 font_size,
337 runs: SmallVec::from(runs),
338 wrap_width,
339 parent_view_id: self.parent_view_id(),
340 };
341 current_frame.insert(key, layout.clone());
342 layout
343 }
344 }
345
346 pub fn layout_line(&self, text: &str, font_size: Pixels, runs: &[FontRun]) -> Arc<LineLayout> {
347 let key = &CacheKeyRef {
348 text,
349 font_size,
350 runs,
351 wrap_width: None,
352 parent_view_id: self.parent_view_id(),
353 } as &dyn AsCacheKeyRef;
354
355 let current_frame = self.current_frame.upgradable_read();
356 if let Some(layout) = current_frame.get(key) {
357 return layout.clone();
358 }
359
360 let mut current_frame = RwLockUpgradableReadGuard::upgrade(current_frame);
361 if let Some((key, layout)) = self.previous_frame.lock().remove_entry(key) {
362 current_frame.insert(key, layout.clone());
363 layout
364 } else {
365 let layout = Arc::new(self.platform_text_system.layout_line(text, font_size, runs));
366 let key = CacheKey {
367 text: text.into(),
368 font_size,
369 runs: SmallVec::from(runs),
370 wrap_width: None,
371 parent_view_id: self.parent_view_id(),
372 };
373 current_frame.insert(key, layout.clone());
374 layout
375 }
376 }
377}
378
379#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
380pub struct FontRun {
381 pub(crate) len: usize,
382 pub(crate) font_id: FontId,
383}
384
385trait AsCacheKeyRef {
386 fn as_cache_key_ref(&self) -> CacheKeyRef;
387}
388
389#[derive(Debug, Eq)]
390struct CacheKey {
391 text: String,
392 font_size: Pixels,
393 runs: SmallVec<[FontRun; 1]>,
394 wrap_width: Option<Pixels>,
395 parent_view_id: Option<EntityId>,
396}
397
398#[derive(Copy, Clone, PartialEq, Eq, Hash)]
399struct CacheKeyRef<'a> {
400 text: &'a str,
401 font_size: Pixels,
402 runs: &'a [FontRun],
403 wrap_width: Option<Pixels>,
404 parent_view_id: Option<EntityId>,
405}
406
407impl<'a> PartialEq for (dyn AsCacheKeyRef + 'a) {
408 fn eq(&self, other: &dyn AsCacheKeyRef) -> bool {
409 self.as_cache_key_ref() == other.as_cache_key_ref()
410 }
411}
412
413impl<'a> Eq for (dyn AsCacheKeyRef + 'a) {}
414
415impl<'a> Hash for (dyn AsCacheKeyRef + 'a) {
416 fn hash<H: Hasher>(&self, state: &mut H) {
417 self.as_cache_key_ref().hash(state)
418 }
419}
420
421impl AsCacheKeyRef for CacheKey {
422 fn as_cache_key_ref(&self) -> CacheKeyRef {
423 CacheKeyRef {
424 text: &self.text,
425 font_size: self.font_size,
426 runs: self.runs.as_slice(),
427 wrap_width: self.wrap_width,
428 parent_view_id: self.parent_view_id,
429 }
430 }
431}
432
433impl PartialEq for CacheKey {
434 fn eq(&self, other: &Self) -> bool {
435 self.as_cache_key_ref().eq(&other.as_cache_key_ref())
436 }
437}
438
439impl Hash for CacheKey {
440 fn hash<H: Hasher>(&self, state: &mut H) {
441 self.as_cache_key_ref().hash(state);
442 }
443}
444
445impl<'a> Borrow<dyn AsCacheKeyRef + 'a> for CacheKey {
446 fn borrow(&self) -> &(dyn AsCacheKeyRef + 'a) {
447 self as &dyn AsCacheKeyRef
448 }
449}
450
451impl<'a> AsCacheKeyRef for CacheKeyRef<'a> {
452 fn as_cache_key_ref(&self) -> CacheKeyRef {
453 *self
454 }
455}