1use crate::{FontId, GlyphId, Pixels, PlatformTextSystem, Point, SharedString, Size, point, px};
2use collections::FxHashMap;
3use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
4use smallvec::SmallVec;
5use std::{
6 borrow::Borrow,
7 hash::{Hash, Hasher},
8 ops::Range,
9 sync::Arc,
10};
11
12use super::LineWrapper;
13
14/// A laid out and styled line of text
15#[derive(Default, Debug)]
16pub struct LineLayout {
17 /// The font size for this line
18 pub font_size: Pixels,
19 /// The width of the line
20 pub width: Pixels,
21 /// The ascent of the line
22 pub ascent: Pixels,
23 /// The descent of the line
24 pub descent: Pixels,
25 /// The shaped runs that make up this line
26 pub runs: Vec<ShapedRun>,
27 /// The length of the line in utf-8 bytes
28 pub len: usize,
29}
30
31/// A run of text that has been shaped .
32#[derive(Debug, Clone)]
33pub struct ShapedRun {
34 /// The font id for this run
35 pub font_id: FontId,
36 /// The glyphs that make up this run
37 pub glyphs: Vec<ShapedGlyph>,
38}
39
40/// A single glyph, ready to paint.
41#[derive(Clone, Debug)]
42pub struct ShapedGlyph {
43 /// The ID for this glyph, as determined by the text system.
44 pub id: GlyphId,
45
46 /// The position of this glyph in its containing line.
47 pub position: Point<Pixels>,
48
49 /// The index of this glyph in the original text.
50 pub index: usize,
51
52 /// Whether this glyph is an emoji
53 pub is_emoji: bool,
54}
55
56impl LineLayout {
57 /// The index for the character at the given x coordinate
58 pub fn index_for_x(&self, x: Pixels) -> Option<usize> {
59 if x >= self.width {
60 None
61 } else {
62 for run in self.runs.iter().rev() {
63 for glyph in run.glyphs.iter().rev() {
64 if glyph.position.x <= x {
65 return Some(glyph.index);
66 }
67 }
68 }
69 Some(0)
70 }
71 }
72
73 /// closest_index_for_x returns the character boundary closest to the given x coordinate
74 /// (e.g. to handle aligning up/down arrow keys)
75 pub fn closest_index_for_x(&self, x: Pixels) -> usize {
76 let mut prev_index = 0;
77 let mut prev_x = px(0.);
78
79 for run in self.runs.iter() {
80 for glyph in run.glyphs.iter() {
81 if glyph.position.x >= x {
82 if glyph.position.x - x < x - prev_x {
83 return glyph.index;
84 } else {
85 return prev_index;
86 }
87 }
88 prev_index = glyph.index;
89 prev_x = glyph.position.x;
90 }
91 }
92
93 if self.len == 1 {
94 if x > self.width / 2. {
95 return 1;
96 } else {
97 return 0;
98 }
99 }
100
101 self.len
102 }
103
104 /// The x position of the character at the given index
105 pub fn x_for_index(&self, index: usize) -> Pixels {
106 for run in &self.runs {
107 for glyph in &run.glyphs {
108 if glyph.index >= index {
109 return glyph.position.x;
110 }
111 }
112 }
113 self.width
114 }
115
116 /// The corresponding Font at the given index
117 pub fn font_id_for_index(&self, index: usize) -> Option<FontId> {
118 for run in &self.runs {
119 for glyph in &run.glyphs {
120 if glyph.index >= index {
121 return Some(run.font_id);
122 }
123 }
124 }
125 None
126 }
127
128 fn compute_wrap_boundaries(
129 &self,
130 text: &str,
131 wrap_width: Pixels,
132 max_lines: Option<usize>,
133 ) -> SmallVec<[WrapBoundary; 1]> {
134 let mut boundaries = SmallVec::new();
135 let mut first_non_whitespace_ix = None;
136 let mut last_candidate_ix = None;
137 let mut last_candidate_x = px(0.);
138 let mut last_boundary = WrapBoundary {
139 run_ix: 0,
140 glyph_ix: 0,
141 };
142 let mut last_boundary_x = px(0.);
143 let mut prev_ch = '\0';
144 let mut glyphs = self
145 .runs
146 .iter()
147 .enumerate()
148 .flat_map(move |(run_ix, run)| {
149 run.glyphs.iter().enumerate().map(move |(glyph_ix, glyph)| {
150 let character = text[glyph.index..].chars().next().unwrap();
151 (
152 WrapBoundary { run_ix, glyph_ix },
153 character,
154 glyph.position.x,
155 )
156 })
157 })
158 .peekable();
159
160 while let Some((boundary, ch, x)) = glyphs.next() {
161 if ch == '\n' {
162 continue;
163 }
164
165 // Here is very similar to `LineWrapper::wrap_line` to determine text wrapping,
166 // but there are some differences, so we have to duplicate the code here.
167 if LineWrapper::is_word_char(ch) {
168 if prev_ch == ' ' && ch != ' ' && first_non_whitespace_ix.is_some() {
169 last_candidate_ix = Some(boundary);
170 last_candidate_x = x;
171 }
172 } else {
173 if ch != ' ' && first_non_whitespace_ix.is_some() {
174 last_candidate_ix = Some(boundary);
175 last_candidate_x = x;
176 }
177 }
178
179 if ch != ' ' && first_non_whitespace_ix.is_none() {
180 first_non_whitespace_ix = Some(boundary);
181 }
182
183 let next_x = glyphs.peek().map_or(self.width, |(_, _, x)| *x);
184 let width = next_x - last_boundary_x;
185
186 if width > wrap_width && boundary > last_boundary {
187 // When used line_clamp, we should limit the number of lines.
188 if let Some(max_lines) = max_lines
189 && boundaries.len() >= max_lines - 1 {
190 break;
191 }
192
193 if let Some(last_candidate_ix) = last_candidate_ix.take() {
194 last_boundary = last_candidate_ix;
195 last_boundary_x = last_candidate_x;
196 } else {
197 last_boundary = boundary;
198 last_boundary_x = x;
199 }
200 boundaries.push(last_boundary);
201 }
202 prev_ch = ch;
203 }
204
205 boundaries
206 }
207}
208
209/// A line of text that has been wrapped to fit a given width
210#[derive(Default, Debug)]
211pub struct WrappedLineLayout {
212 /// The line layout, pre-wrapping.
213 pub unwrapped_layout: Arc<LineLayout>,
214
215 /// The boundaries at which the line was wrapped
216 pub wrap_boundaries: SmallVec<[WrapBoundary; 1]>,
217
218 /// The width of the line, if it was wrapped
219 pub wrap_width: Option<Pixels>,
220}
221
222/// A boundary at which a line was wrapped
223#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
224pub struct WrapBoundary {
225 /// The index in the run just before the line was wrapped
226 pub run_ix: usize,
227 /// The index of the glyph just before the line was wrapped
228 pub glyph_ix: usize,
229}
230
231impl WrappedLineLayout {
232 /// The length of the underlying text, in utf8 bytes.
233 #[allow(clippy::len_without_is_empty)]
234 pub fn len(&self) -> usize {
235 self.unwrapped_layout.len
236 }
237
238 /// The width of this line, in pixels, whether or not it was wrapped.
239 pub fn width(&self) -> Pixels {
240 self.wrap_width
241 .unwrap_or(Pixels::MAX)
242 .min(self.unwrapped_layout.width)
243 }
244
245 /// The size of the whole wrapped text, for the given line_height.
246 /// can span multiple lines if there are multiple wrap boundaries.
247 pub fn size(&self, line_height: Pixels) -> Size<Pixels> {
248 Size {
249 width: self.width(),
250 height: line_height * (self.wrap_boundaries.len() + 1),
251 }
252 }
253
254 /// The ascent of a line in this layout
255 pub fn ascent(&self) -> Pixels {
256 self.unwrapped_layout.ascent
257 }
258
259 /// The descent of a line in this layout
260 pub fn descent(&self) -> Pixels {
261 self.unwrapped_layout.descent
262 }
263
264 /// The wrap boundaries in this layout
265 pub fn wrap_boundaries(&self) -> &[WrapBoundary] {
266 &self.wrap_boundaries
267 }
268
269 /// The font size of this layout
270 pub fn font_size(&self) -> Pixels {
271 self.unwrapped_layout.font_size
272 }
273
274 /// The runs in this layout, sans wrapping
275 pub fn runs(&self) -> &[ShapedRun] {
276 &self.unwrapped_layout.runs
277 }
278
279 /// The index corresponding to a given position in this layout for the given line height.
280 ///
281 /// See also [`Self::closest_index_for_position`].
282 pub fn index_for_position(
283 &self,
284 position: Point<Pixels>,
285 line_height: Pixels,
286 ) -> Result<usize, usize> {
287 self._index_for_position(position, line_height, false)
288 }
289
290 /// The closest index to a given position in this layout for the given line height.
291 ///
292 /// Closest means the character boundary closest to the given position.
293 ///
294 /// See also [`LineLayout::closest_index_for_x`].
295 pub fn closest_index_for_position(
296 &self,
297 position: Point<Pixels>,
298 line_height: Pixels,
299 ) -> Result<usize, usize> {
300 self._index_for_position(position, line_height, true)
301 }
302
303 fn _index_for_position(
304 &self,
305 mut position: Point<Pixels>,
306 line_height: Pixels,
307 closest: bool,
308 ) -> Result<usize, usize> {
309 let wrapped_line_ix = (position.y / line_height) as usize;
310
311 let wrapped_line_start_index;
312 let wrapped_line_start_x;
313 if wrapped_line_ix > 0 {
314 let Some(line_start_boundary) = self.wrap_boundaries.get(wrapped_line_ix - 1) else {
315 return Err(0);
316 };
317 let run = &self.unwrapped_layout.runs[line_start_boundary.run_ix];
318 let glyph = &run.glyphs[line_start_boundary.glyph_ix];
319 wrapped_line_start_index = glyph.index;
320 wrapped_line_start_x = glyph.position.x;
321 } else {
322 wrapped_line_start_index = 0;
323 wrapped_line_start_x = Pixels::ZERO;
324 };
325
326 let wrapped_line_end_index;
327 let wrapped_line_end_x;
328 if wrapped_line_ix < self.wrap_boundaries.len() {
329 let next_wrap_boundary_ix = wrapped_line_ix;
330 let next_wrap_boundary = self.wrap_boundaries[next_wrap_boundary_ix];
331 let run = &self.unwrapped_layout.runs[next_wrap_boundary.run_ix];
332 let glyph = &run.glyphs[next_wrap_boundary.glyph_ix];
333 wrapped_line_end_index = glyph.index;
334 wrapped_line_end_x = glyph.position.x;
335 } else {
336 wrapped_line_end_index = self.unwrapped_layout.len;
337 wrapped_line_end_x = self.unwrapped_layout.width;
338 };
339
340 let mut position_in_unwrapped_line = position;
341 position_in_unwrapped_line.x += wrapped_line_start_x;
342 if position_in_unwrapped_line.x < wrapped_line_start_x {
343 Err(wrapped_line_start_index)
344 } else if position_in_unwrapped_line.x >= wrapped_line_end_x {
345 Err(wrapped_line_end_index)
346 } else {
347 if closest {
348 Ok(self
349 .unwrapped_layout
350 .closest_index_for_x(position_in_unwrapped_line.x))
351 } else {
352 Ok(self
353 .unwrapped_layout
354 .index_for_x(position_in_unwrapped_line.x)
355 .unwrap())
356 }
357 }
358 }
359
360 /// Returns the pixel position for the given byte index.
361 pub fn position_for_index(&self, index: usize, line_height: Pixels) -> Option<Point<Pixels>> {
362 let mut line_start_ix = 0;
363 let mut line_end_indices = self
364 .wrap_boundaries
365 .iter()
366 .map(|wrap_boundary| {
367 let run = &self.unwrapped_layout.runs[wrap_boundary.run_ix];
368 let glyph = &run.glyphs[wrap_boundary.glyph_ix];
369 glyph.index
370 })
371 .chain([self.len()])
372 .enumerate();
373 for (ix, line_end_ix) in line_end_indices {
374 let line_y = ix as f32 * line_height;
375 if index < line_start_ix {
376 break;
377 } else if index > line_end_ix {
378 line_start_ix = line_end_ix;
379 continue;
380 } else {
381 let line_start_x = self.unwrapped_layout.x_for_index(line_start_ix);
382 let x = self.unwrapped_layout.x_for_index(index) - line_start_x;
383 return Some(point(x, line_y));
384 }
385 }
386
387 None
388 }
389}
390
391pub(crate) struct LineLayoutCache {
392 previous_frame: Mutex<FrameCache>,
393 current_frame: RwLock<FrameCache>,
394 platform_text_system: Arc<dyn PlatformTextSystem>,
395}
396
397#[derive(Default)]
398struct FrameCache {
399 lines: FxHashMap<Arc<CacheKey>, Arc<LineLayout>>,
400 wrapped_lines: FxHashMap<Arc<CacheKey>, Arc<WrappedLineLayout>>,
401 used_lines: Vec<Arc<CacheKey>>,
402 used_wrapped_lines: Vec<Arc<CacheKey>>,
403}
404
405#[derive(Clone, Default)]
406pub(crate) struct LineLayoutIndex {
407 lines_index: usize,
408 wrapped_lines_index: usize,
409}
410
411impl LineLayoutCache {
412 pub fn new(platform_text_system: Arc<dyn PlatformTextSystem>) -> Self {
413 Self {
414 previous_frame: Mutex::default(),
415 current_frame: RwLock::default(),
416 platform_text_system,
417 }
418 }
419
420 pub fn layout_index(&self) -> LineLayoutIndex {
421 let frame = self.current_frame.read();
422 LineLayoutIndex {
423 lines_index: frame.used_lines.len(),
424 wrapped_lines_index: frame.used_wrapped_lines.len(),
425 }
426 }
427
428 pub fn reuse_layouts(&self, range: Range<LineLayoutIndex>) {
429 let mut previous_frame = &mut *self.previous_frame.lock();
430 let mut current_frame = &mut *self.current_frame.write();
431
432 for key in &previous_frame.used_lines[range.start.lines_index..range.end.lines_index] {
433 if let Some((key, line)) = previous_frame.lines.remove_entry(key) {
434 current_frame.lines.insert(key, line);
435 }
436 current_frame.used_lines.push(key.clone());
437 }
438
439 for key in &previous_frame.used_wrapped_lines
440 [range.start.wrapped_lines_index..range.end.wrapped_lines_index]
441 {
442 if let Some((key, line)) = previous_frame.wrapped_lines.remove_entry(key) {
443 current_frame.wrapped_lines.insert(key, line);
444 }
445 current_frame.used_wrapped_lines.push(key.clone());
446 }
447 }
448
449 pub fn truncate_layouts(&self, index: LineLayoutIndex) {
450 let mut current_frame = &mut *self.current_frame.write();
451 current_frame.used_lines.truncate(index.lines_index);
452 current_frame
453 .used_wrapped_lines
454 .truncate(index.wrapped_lines_index);
455 }
456
457 pub fn finish_frame(&self) {
458 let mut prev_frame = self.previous_frame.lock();
459 let mut curr_frame = self.current_frame.write();
460 std::mem::swap(&mut *prev_frame, &mut *curr_frame);
461 curr_frame.lines.clear();
462 curr_frame.wrapped_lines.clear();
463 curr_frame.used_lines.clear();
464 curr_frame.used_wrapped_lines.clear();
465 }
466
467 pub fn layout_wrapped_line<Text>(
468 &self,
469 text: Text,
470 font_size: Pixels,
471 runs: &[FontRun],
472 wrap_width: Option<Pixels>,
473 max_lines: Option<usize>,
474 ) -> Arc<WrappedLineLayout>
475 where
476 Text: AsRef<str>,
477 SharedString: From<Text>,
478 {
479 let key = &CacheKeyRef {
480 text: text.as_ref(),
481 font_size,
482 runs,
483 wrap_width,
484 force_width: None,
485 } as &dyn AsCacheKeyRef;
486
487 let current_frame = self.current_frame.upgradable_read();
488 if let Some(layout) = current_frame.wrapped_lines.get(key) {
489 return layout.clone();
490 }
491
492 let previous_frame_entry = self.previous_frame.lock().wrapped_lines.remove_entry(key);
493 if let Some((key, layout)) = previous_frame_entry {
494 let mut current_frame = RwLockUpgradableReadGuard::upgrade(current_frame);
495 current_frame
496 .wrapped_lines
497 .insert(key.clone(), layout.clone());
498 current_frame.used_wrapped_lines.push(key);
499 layout
500 } else {
501 drop(current_frame);
502 let text = SharedString::from(text);
503 let unwrapped_layout = self.layout_line::<&SharedString>(&text, font_size, runs);
504 let wrap_boundaries = if let Some(wrap_width) = wrap_width {
505 unwrapped_layout.compute_wrap_boundaries(text.as_ref(), wrap_width, max_lines)
506 } else {
507 SmallVec::new()
508 };
509 let layout = Arc::new(WrappedLineLayout {
510 unwrapped_layout,
511 wrap_boundaries,
512 wrap_width,
513 });
514 let key = Arc::new(CacheKey {
515 text,
516 font_size,
517 runs: SmallVec::from(runs),
518 wrap_width,
519 force_width: None,
520 });
521
522 let mut current_frame = self.current_frame.write();
523 current_frame
524 .wrapped_lines
525 .insert(key.clone(), layout.clone());
526 current_frame.used_wrapped_lines.push(key);
527
528 layout
529 }
530 }
531
532 pub fn layout_line<Text>(
533 &self,
534 text: Text,
535 font_size: Pixels,
536 runs: &[FontRun],
537 ) -> Arc<LineLayout>
538 where
539 Text: AsRef<str>,
540 SharedString: From<Text>,
541 {
542 self.layout_line_internal(text, font_size, runs, None)
543 }
544
545 pub fn layout_line_internal<Text>(
546 &self,
547 text: Text,
548 font_size: Pixels,
549 runs: &[FontRun],
550 force_width: Option<Pixels>,
551 ) -> Arc<LineLayout>
552 where
553 Text: AsRef<str>,
554 SharedString: From<Text>,
555 {
556 let key = &CacheKeyRef {
557 text: text.as_ref(),
558 font_size,
559 runs,
560 wrap_width: None,
561 force_width,
562 } as &dyn AsCacheKeyRef;
563
564 let current_frame = self.current_frame.upgradable_read();
565 if let Some(layout) = current_frame.lines.get(key) {
566 return layout.clone();
567 }
568
569 let mut current_frame = RwLockUpgradableReadGuard::upgrade(current_frame);
570 if let Some((key, layout)) = self.previous_frame.lock().lines.remove_entry(key) {
571 current_frame.lines.insert(key.clone(), layout.clone());
572 current_frame.used_lines.push(key);
573 layout
574 } else {
575 let text = SharedString::from(text);
576 let mut layout = self
577 .platform_text_system
578 .layout_line(&text, font_size, runs);
579
580 if let Some(force_width) = force_width {
581 let mut glyph_pos = 0;
582 for run in layout.runs.iter_mut() {
583 for glyph in run.glyphs.iter_mut() {
584 if (glyph.position.x - glyph_pos * force_width).abs() > px(1.) {
585 glyph.position.x = glyph_pos * force_width;
586 }
587 glyph_pos += 1;
588 }
589 }
590 }
591
592 let key = Arc::new(CacheKey {
593 text,
594 font_size,
595 runs: SmallVec::from(runs),
596 wrap_width: None,
597 force_width,
598 });
599 let layout = Arc::new(layout);
600 current_frame.lines.insert(key.clone(), layout.clone());
601 current_frame.used_lines.push(key);
602 layout
603 }
604 }
605}
606
607/// A run of text with a single font.
608#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
609pub struct FontRun {
610 pub(crate) len: usize,
611 pub(crate) font_id: FontId,
612}
613
614trait AsCacheKeyRef {
615 fn as_cache_key_ref(&self) -> CacheKeyRef<'_>;
616}
617
618#[derive(Clone, Debug, Eq)]
619struct CacheKey {
620 text: SharedString,
621 font_size: Pixels,
622 runs: SmallVec<[FontRun; 1]>,
623 wrap_width: Option<Pixels>,
624 force_width: Option<Pixels>,
625}
626
627#[derive(Copy, Clone, PartialEq, Eq, Hash)]
628struct CacheKeyRef<'a> {
629 text: &'a str,
630 font_size: Pixels,
631 runs: &'a [FontRun],
632 wrap_width: Option<Pixels>,
633 force_width: Option<Pixels>,
634}
635
636impl PartialEq for (dyn AsCacheKeyRef + '_) {
637 fn eq(&self, other: &dyn AsCacheKeyRef) -> bool {
638 self.as_cache_key_ref() == other.as_cache_key_ref()
639 }
640}
641
642impl Eq for (dyn AsCacheKeyRef + '_) {}
643
644impl Hash for (dyn AsCacheKeyRef + '_) {
645 fn hash<H: Hasher>(&self, state: &mut H) {
646 self.as_cache_key_ref().hash(state)
647 }
648}
649
650impl AsCacheKeyRef for CacheKey {
651 fn as_cache_key_ref(&self) -> CacheKeyRef<'_> {
652 CacheKeyRef {
653 text: &self.text,
654 font_size: self.font_size,
655 runs: self.runs.as_slice(),
656 wrap_width: self.wrap_width,
657 force_width: self.force_width,
658 }
659 }
660}
661
662impl PartialEq for CacheKey {
663 fn eq(&self, other: &Self) -> bool {
664 self.as_cache_key_ref().eq(&other.as_cache_key_ref())
665 }
666}
667
668impl Hash for CacheKey {
669 fn hash<H: Hasher>(&self, state: &mut H) {
670 self.as_cache_key_ref().hash(state);
671 }
672}
673
674impl<'a> Borrow<dyn AsCacheKeyRef + 'a> for Arc<CacheKey> {
675 fn borrow(&self) -> &(dyn AsCacheKeyRef + 'a) {
676 self.as_ref() as &dyn AsCacheKeyRef
677 }
678}
679
680impl AsCacheKeyRef for CacheKeyRef<'_> {
681 fn as_cache_key_ref(&self) -> CacheKeyRef<'_> {
682 *self
683 }
684}