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::{
10 Arc,
11 atomic::{AtomicU64, AtomicUsize, Ordering},
12 },
13};
14
15use super::LineWrapper;
16
17#[derive(Default, Debug)]
19pub struct LineLayout {
20 pub font_size: Pixels,
22 pub width: Pixels,
24 pub ascent: Pixels,
26 pub descent: Pixels,
28 pub runs: Vec<ShapedRun>,
30 pub len: usize,
32}
33
34#[derive(Debug, Clone)]
36pub struct ShapedRun {
37 pub font_id: FontId,
39 pub glyphs: Vec<ShapedGlyph>,
41}
42
43#[derive(Clone, Debug)]
45pub struct ShapedGlyph {
46 pub id: GlyphId,
48
49 pub position: Point<Pixels>,
51
52 pub index: usize,
54
55 pub is_emoji: bool,
57}
58
59impl LineLayout {
60 pub fn index_for_x(&self, x: Pixels) -> Option<usize> {
62 if x >= self.width {
63 None
64 } else {
65 for run in self.runs.iter().rev() {
66 for glyph in run.glyphs.iter().rev() {
67 if glyph.position.x <= x {
68 return Some(glyph.index);
69 }
70 }
71 }
72 Some(0)
73 }
74 }
75
76 pub fn closest_index_for_x(&self, x: Pixels) -> usize {
79 let mut prev_index = 0;
80 let mut prev_x = px(0.);
81
82 for run in self.runs.iter() {
83 for glyph in run.glyphs.iter() {
84 if glyph.position.x >= x {
85 if glyph.position.x - x < x - prev_x {
86 return glyph.index;
87 } else {
88 return prev_index;
89 }
90 }
91 prev_index = glyph.index;
92 prev_x = glyph.position.x;
93 }
94 }
95
96 if self.len == 1 {
97 if x > self.width / 2. {
98 return 1;
99 } else {
100 return 0;
101 }
102 }
103
104 self.len
105 }
106
107 pub fn x_for_index(&self, index: usize) -> Pixels {
109 for run in &self.runs {
110 for glyph in &run.glyphs {
111 if glyph.index >= index {
112 return glyph.position.x;
113 }
114 }
115 }
116 self.width
117 }
118
119 pub fn font_id_for_index(&self, index: usize) -> Option<FontId> {
121 for run in &self.runs {
122 for glyph in &run.glyphs {
123 if glyph.index >= index {
124 return Some(run.font_id);
125 }
126 }
127 }
128 None
129 }
130
131 pub fn split_at(&self, byte_index: usize) -> (LineLayout, LineLayout) {
139 let x_offset = self.x_for_index(byte_index);
140
141 let mut left_runs = Vec::new();
143 let mut right_runs = Vec::new();
144
145 for run in &self.runs {
146 let split_pos = run.glyphs.partition_point(|g| g.index < byte_index);
147
148 if split_pos > 0 {
149 left_runs.push(ShapedRun {
150 font_id: run.font_id,
151 glyphs: run.glyphs[..split_pos].to_vec(),
152 });
153 }
154
155 if split_pos < run.glyphs.len() {
156 let right_glyphs = run.glyphs[split_pos..]
157 .iter()
158 .map(|g| ShapedGlyph {
159 id: g.id,
160 position: point(g.position.x - x_offset, g.position.y),
161 index: g.index - byte_index,
162 is_emoji: g.is_emoji,
163 })
164 .collect();
165 right_runs.push(ShapedRun {
166 font_id: run.font_id,
167 glyphs: right_glyphs,
168 });
169 }
170 }
171
172 let left = LineLayout {
173 font_size: self.font_size,
174 width: x_offset,
175 ascent: self.ascent,
176 descent: self.descent,
177 runs: left_runs,
178 len: byte_index,
179 };
180
181 let right = LineLayout {
182 font_size: self.font_size,
183 width: self.width - x_offset,
184 ascent: self.ascent,
185 descent: self.descent,
186 runs: right_runs,
187 len: self.len - byte_index,
188 };
189
190 (left, right)
191 }
192
193 fn compute_wrap_boundaries(
194 &self,
195 text: &str,
196 wrap_width: Pixels,
197 max_lines: Option<usize>,
198 ) -> SmallVec<[WrapBoundary; 1]> {
199 let mut boundaries = SmallVec::new();
200 let mut first_non_whitespace_ix = None;
201 let mut last_candidate_ix = None;
202 let mut last_candidate_x = px(0.);
203 let mut last_boundary = WrapBoundary {
204 run_ix: 0,
205 glyph_ix: 0,
206 };
207 let mut last_boundary_x = px(0.);
208 let mut prev_ch = '\0';
209 let mut glyphs = self
210 .runs
211 .iter()
212 .enumerate()
213 .flat_map(move |(run_ix, run)| {
214 run.glyphs.iter().enumerate().map(move |(glyph_ix, glyph)| {
215 let character = text[glyph.index..].chars().next().unwrap();
216 (
217 WrapBoundary { run_ix, glyph_ix },
218 character,
219 glyph.position.x,
220 )
221 })
222 })
223 .peekable();
224
225 while let Some((boundary, ch, x)) = glyphs.next() {
226 if ch == '\n' {
227 continue;
228 }
229
230 if LineWrapper::is_word_char(ch) {
233 if prev_ch == ' ' && ch != ' ' && first_non_whitespace_ix.is_some() {
234 last_candidate_ix = Some(boundary);
235 last_candidate_x = x;
236 }
237 } else {
238 if ch != ' ' && first_non_whitespace_ix.is_some() {
239 last_candidate_ix = Some(boundary);
240 last_candidate_x = x;
241 }
242 }
243
244 if ch != ' ' && first_non_whitespace_ix.is_none() {
245 first_non_whitespace_ix = Some(boundary);
246 }
247
248 let next_x = glyphs.peek().map_or(self.width, |(_, _, x)| *x);
249 let width = next_x - last_boundary_x;
250
251 if width > wrap_width && boundary > last_boundary {
252 if let Some(max_lines) = max_lines
254 && boundaries.len() >= max_lines.saturating_sub(1)
255 {
256 break;
257 }
258
259 if let Some(last_candidate_ix) = last_candidate_ix.take() {
260 last_boundary = last_candidate_ix;
261 last_boundary_x = last_candidate_x;
262 } else {
263 last_boundary = boundary;
264 last_boundary_x = x;
265 }
266 boundaries.push(last_boundary);
267 }
268 prev_ch = ch;
269 }
270
271 boundaries
272 }
273}
274
275#[derive(Default, Debug)]
277pub struct WrappedLineLayout {
278 pub unwrapped_layout: Arc<LineLayout>,
280
281 pub wrap_boundaries: SmallVec<[WrapBoundary; 1]>,
283
284 pub wrap_width: Option<Pixels>,
286}
287
288#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
290pub struct WrapBoundary {
291 pub run_ix: usize,
293 pub glyph_ix: usize,
295}
296
297impl WrappedLineLayout {
298 #[allow(clippy::len_without_is_empty)]
300 pub fn len(&self) -> usize {
301 self.unwrapped_layout.len
302 }
303
304 pub fn width(&self) -> Pixels {
306 self.wrap_width
307 .unwrap_or(Pixels::MAX)
308 .min(self.unwrapped_layout.width)
309 }
310
311 pub fn size(&self, line_height: Pixels) -> Size<Pixels> {
314 Size {
315 width: self.width(),
316 height: line_height * (self.wrap_boundaries.len() + 1),
317 }
318 }
319
320 pub fn ascent(&self) -> Pixels {
322 self.unwrapped_layout.ascent
323 }
324
325 pub fn descent(&self) -> Pixels {
327 self.unwrapped_layout.descent
328 }
329
330 pub fn wrap_boundaries(&self) -> &[WrapBoundary] {
332 &self.wrap_boundaries
333 }
334
335 pub fn font_size(&self) -> Pixels {
337 self.unwrapped_layout.font_size
338 }
339
340 pub fn runs(&self) -> &[ShapedRun] {
342 &self.unwrapped_layout.runs
343 }
344
345 pub fn index_for_position(
349 &self,
350 position: Point<Pixels>,
351 line_height: Pixels,
352 ) -> Result<usize, usize> {
353 self._index_for_position(position, line_height, false)
354 }
355
356 pub fn closest_index_for_position(
362 &self,
363 position: Point<Pixels>,
364 line_height: Pixels,
365 ) -> Result<usize, usize> {
366 self._index_for_position(position, line_height, true)
367 }
368
369 fn _index_for_position(
370 &self,
371 mut position: Point<Pixels>,
372 line_height: Pixels,
373 closest: bool,
374 ) -> Result<usize, usize> {
375 let wrapped_line_ix = (position.y / line_height) as usize;
376
377 let wrapped_line_start_index;
378 let wrapped_line_start_x;
379 if wrapped_line_ix > 0 {
380 let Some(line_start_boundary) = self.wrap_boundaries.get(wrapped_line_ix - 1) else {
381 return Err(0);
382 };
383 let run = &self.unwrapped_layout.runs[line_start_boundary.run_ix];
384 let glyph = &run.glyphs[line_start_boundary.glyph_ix];
385 wrapped_line_start_index = glyph.index;
386 wrapped_line_start_x = glyph.position.x;
387 } else {
388 wrapped_line_start_index = 0;
389 wrapped_line_start_x = Pixels::ZERO;
390 };
391
392 let wrapped_line_end_index;
393 let wrapped_line_end_x;
394 if wrapped_line_ix < self.wrap_boundaries.len() {
395 let next_wrap_boundary_ix = wrapped_line_ix;
396 let next_wrap_boundary = self.wrap_boundaries[next_wrap_boundary_ix];
397 let run = &self.unwrapped_layout.runs[next_wrap_boundary.run_ix];
398 let glyph = &run.glyphs[next_wrap_boundary.glyph_ix];
399 wrapped_line_end_index = glyph.index;
400 wrapped_line_end_x = glyph.position.x;
401 } else {
402 wrapped_line_end_index = self.unwrapped_layout.len;
403 wrapped_line_end_x = self.unwrapped_layout.width;
404 };
405
406 let mut position_in_unwrapped_line = position;
407 position_in_unwrapped_line.x += wrapped_line_start_x;
408 if position_in_unwrapped_line.x < wrapped_line_start_x {
409 Err(wrapped_line_start_index)
410 } else if position_in_unwrapped_line.x >= wrapped_line_end_x {
411 Err(wrapped_line_end_index)
412 } else {
413 if closest {
414 Ok(self
415 .unwrapped_layout
416 .closest_index_for_x(position_in_unwrapped_line.x))
417 } else {
418 self.unwrapped_layout
421 .index_for_x(position_in_unwrapped_line.x)
422 .ok_or(wrapped_line_end_index)
423 }
424 }
425 }
426
427 pub fn position_for_index(&self, index: usize, line_height: Pixels) -> Option<Point<Pixels>> {
429 let mut line_start_ix = 0;
430 let mut line_end_indices = self
431 .wrap_boundaries
432 .iter()
433 .map(|wrap_boundary| {
434 let run = &self.unwrapped_layout.runs[wrap_boundary.run_ix];
435 let glyph = &run.glyphs[wrap_boundary.glyph_ix];
436 glyph.index
437 })
438 .chain([self.len()])
439 .enumerate();
440 for (ix, line_end_ix) in line_end_indices {
441 let line_y = ix as f32 * line_height;
442 if index < line_start_ix {
443 break;
444 } else if index > line_end_ix {
445 line_start_ix = line_end_ix;
446 continue;
447 } else {
448 let line_start_x = self.unwrapped_layout.x_for_index(line_start_ix);
449 let x = self.unwrapped_layout.x_for_index(index) - line_start_x;
450 return Some(point(x, line_y));
451 }
452 }
453
454 None
455 }
456}
457
458struct GlobalCacheEntry<T> {
459 value: T,
460 last_access: AtomicU64,
461}
462
463pub(crate) struct GlobalLineLayoutCache {
464 max_entries: usize,
465 low_watermark: usize,
466 lines: RwLock<FxHashMap<Arc<CacheKey>, GlobalCacheEntry<Arc<LineLayout>>>>,
467 wrapped_lines: RwLock<FxHashMap<Arc<CacheKey>, GlobalCacheEntry<Arc<WrappedLineLayout>>>>,
468 access_counter: AtomicU64,
469}
470
471impl GlobalLineLayoutCache {
472 pub fn new(max_entries: usize, low_watermark: usize) -> Self {
473 let max_entries = max_entries.max(1);
474 let low_watermark = low_watermark.min(max_entries.saturating_sub(1));
477 Self {
478 max_entries,
479 low_watermark,
480 lines: RwLock::new(FxHashMap::default()),
481 wrapped_lines: RwLock::new(FxHashMap::default()),
482 access_counter: AtomicU64::new(0),
483 }
484 }
485
486 #[cfg(test)]
487 pub(crate) fn budget_for_test(&self) -> (usize, usize) {
488 (self.max_entries, self.low_watermark)
489 }
490
491 pub fn clear(&self) {
498 self.lines.write().clear();
499 self.wrapped_lines.write().clear();
500 }
501
502 pub fn entry_counts(&self) -> (usize, usize) {
504 (self.lines.read().len(), self.wrapped_lines.read().len())
505 }
506
507 fn get_line(&self, key: &dyn AsCacheKeyRef) -> Option<Arc<LineLayout>> {
508 let lines = self.lines.read();
509 if let Some(entry) = lines.get(key) {
510 entry.last_access.store(
512 self.access_counter.fetch_add(1, Ordering::Relaxed),
513 Ordering::Relaxed,
514 );
515 Some(entry.value.clone())
516 } else {
517 None
518 }
519 }
520
521 fn insert_line(&self, key: Arc<CacheKey>, layout: Arc<LineLayout>) {
522 let mut lines = self.lines.write();
523 if lines.len() >= self.max_entries {
524 Self::evict_to_watermark(&mut lines, self.low_watermark);
525 }
526 lines.insert(
527 key,
528 GlobalCacheEntry {
529 value: layout,
530 last_access: AtomicU64::new(self.access_counter.fetch_add(1, Ordering::Relaxed)),
531 },
532 );
533 }
534
535 fn get_wrapped_line(&self, key: &dyn AsCacheKeyRef) -> Option<Arc<WrappedLineLayout>> {
536 let wrapped = self.wrapped_lines.read();
537 if let Some(entry) = wrapped.get(key) {
538 entry.last_access.store(
539 self.access_counter.fetch_add(1, Ordering::Relaxed),
540 Ordering::Relaxed,
541 );
542 Some(entry.value.clone())
543 } else {
544 None
545 }
546 }
547
548 fn insert_wrapped_line(&self, key: Arc<CacheKey>, layout: Arc<WrappedLineLayout>) {
549 let mut wrapped = self.wrapped_lines.write();
550 if wrapped.len() >= self.max_entries {
551 Self::evict_to_watermark(&mut wrapped, self.low_watermark);
552 }
553 wrapped.insert(
554 key,
555 GlobalCacheEntry {
556 value: layout,
557 last_access: AtomicU64::new(self.access_counter.fetch_add(1, Ordering::Relaxed)),
558 },
559 );
560 }
561
562 fn evict_to_watermark<V>(
564 map: &mut FxHashMap<Arc<CacheKey>, GlobalCacheEntry<V>>,
565 target_size: usize,
566 ) {
567 if map.len() <= target_size {
568 return;
569 }
570 let to_remove = map.len() - target_size;
571 let mut entries: Vec<_> = map
572 .iter()
573 .map(|(k, entry)| (k.clone(), entry.last_access.load(Ordering::Relaxed)))
574 .collect();
575 entries.sort_by_key(|(_, access)| *access);
576 for (key, _) in entries.into_iter().take(to_remove) {
577 map.remove(&key);
578 }
579 }
580}
581
582pub(crate) struct LineLayoutCache {
583 previous_frame: Mutex<FrameCache>,
584 current_frame: RwLock<FrameCache>,
585 platform_text_system: Arc<dyn PlatformTextSystem>,
586 global_cache: Arc<GlobalLineLayoutCache>,
587 font_generation: Arc<AtomicUsize>,
589 cached_font_generation: AtomicUsize,
591}
592
593#[derive(Default)]
594struct FrameCache {
595 lines: FxHashMap<Arc<CacheKey>, Arc<LineLayout>>,
596 wrapped_lines: FxHashMap<Arc<CacheKey>, Arc<WrappedLineLayout>>,
597 used_lines: Vec<Arc<CacheKey>>,
598 used_wrapped_lines: Vec<Arc<CacheKey>>,
599}
600
601#[derive(Clone, Default)]
602pub(crate) struct LineLayoutIndex {
603 font_generation: usize,
604 lines_index: usize,
605 wrapped_lines_index: usize,
606}
607
608impl LineLayoutCache {
609 pub fn new(
610 platform_text_system: Arc<dyn PlatformTextSystem>,
611 global_cache: Arc<GlobalLineLayoutCache>,
612 font_generation: Arc<AtomicUsize>,
613 ) -> Self {
614 let cached_font_generation = font_generation.load(Ordering::Acquire);
615 Self {
616 previous_frame: Mutex::default(),
617 current_frame: RwLock::default(),
618 platform_text_system,
619 global_cache,
620 font_generation,
621 cached_font_generation: AtomicUsize::new(cached_font_generation),
622 }
623 }
624
625 pub fn layout_index(&self) -> LineLayoutIndex {
626 let font_generation = self.clear_if_font_generation_changed();
627 let frame = self.current_frame.read();
628 LineLayoutIndex {
629 font_generation,
630 lines_index: frame.used_lines.len(),
631 wrapped_lines_index: frame.used_wrapped_lines.len(),
632 }
633 }
634
635 pub fn reuse_layouts(&self, range: Range<LineLayoutIndex>) {
636 let font_generation = self.clear_if_font_generation_changed();
637 if range.start.font_generation != font_generation
638 || range.end.font_generation != font_generation
639 {
640 return;
641 }
642 let mut current_frame = &mut *self.current_frame.write();
643 let mut previous_frame = &mut *self.previous_frame.lock();
644
645 for key in &previous_frame.used_lines[range.start.lines_index..range.end.lines_index] {
646 if let Some((key, line)) = previous_frame.lines.remove_entry(key) {
647 current_frame.lines.insert(key, line);
648 }
649 current_frame.used_lines.push(key.clone());
650 }
651
652 for key in &previous_frame.used_wrapped_lines
653 [range.start.wrapped_lines_index..range.end.wrapped_lines_index]
654 {
655 if let Some((key, line)) = previous_frame.wrapped_lines.remove_entry(key) {
656 current_frame.wrapped_lines.insert(key, line);
657 }
658 current_frame.used_wrapped_lines.push(key.clone());
659 }
660 }
661
662 pub fn truncate_layouts(&self, index: LineLayoutIndex) {
663 let font_generation = self.clear_if_font_generation_changed();
664 if index.font_generation != font_generation {
665 return;
666 }
667 let mut current_frame = &mut *self.current_frame.write();
668 current_frame.used_lines.truncate(index.lines_index);
669 current_frame
670 .used_wrapped_lines
671 .truncate(index.wrapped_lines_index);
672 }
673
674 pub fn finish_frame(&self) {
675 let _font_generation = self.clear_if_font_generation_changed();
676 let mut curr_frame = self.current_frame.write();
677 let mut prev_frame = self.previous_frame.lock();
678 std::mem::swap(&mut *prev_frame, &mut *curr_frame);
679 curr_frame.lines.clear();
680 curr_frame.wrapped_lines.clear();
681 curr_frame.used_lines.clear();
682 curr_frame.used_wrapped_lines.clear();
683 }
684
685 pub fn layout_wrapped_line<Text>(
686 &self,
687 text: Text,
688 font_size: Pixels,
689 runs: &[FontRun],
690 wrap_width: Option<Pixels>,
691 max_lines: Option<usize>,
692 ) -> Arc<WrappedLineLayout>
693 where
694 Text: AsRef<str>,
695 SharedString: From<Text>,
696 {
697 let _font_generation = self.clear_if_font_generation_changed();
698 let key = &CacheKeyRef {
699 text: text.as_ref(),
700 font_size,
701 runs,
702 wrap_width,
703 force_width: None,
704 letter_spacing: None,
705 } as &dyn AsCacheKeyRef;
706
707 let current_frame = self.current_frame.upgradable_read();
708 if let Some(layout) = current_frame.wrapped_lines.get(key) {
709 return layout.clone();
710 }
711
712 let previous_frame_entry = self.previous_frame.lock().wrapped_lines.remove_entry(key);
713 if let Some((key, layout)) = previous_frame_entry {
714 let mut current_frame = RwLockUpgradableReadGuard::upgrade(current_frame);
715 current_frame
716 .wrapped_lines
717 .insert(key.clone(), layout.clone());
718 current_frame.used_wrapped_lines.push(key);
719 layout
720 } else {
721 if let Some(layout) = self.global_cache.get_wrapped_line(key) {
723 let mut current_frame = RwLockUpgradableReadGuard::upgrade(current_frame);
724 let key = Arc::new(CacheKey {
725 text: SharedString::from(text),
726 font_size,
727 runs: SmallVec::from(runs),
728 wrap_width,
729 force_width: None,
730 letter_spacing: None,
731 });
732 current_frame
733 .wrapped_lines
734 .insert(key.clone(), layout.clone());
735 current_frame.used_wrapped_lines.push(key);
736 return layout;
737 }
738
739 drop(current_frame);
740 let text = SharedString::from(text);
741 let unwrapped_layout = self.layout_line::<&SharedString>(&text, font_size, runs, None);
742 let wrap_boundaries = if let Some(wrap_width) = wrap_width {
743 unwrapped_layout.compute_wrap_boundaries(text.as_ref(), wrap_width, max_lines)
744 } else {
745 SmallVec::new()
746 };
747 let layout = Arc::new(WrappedLineLayout {
748 unwrapped_layout,
749 wrap_boundaries,
750 wrap_width,
751 });
752 let key = Arc::new(CacheKey {
753 text,
754 font_size,
755 runs: SmallVec::from(runs),
756 wrap_width,
757 force_width: None,
758 letter_spacing: None,
759 });
760
761 let mut current_frame = self.current_frame.write();
762 current_frame
763 .wrapped_lines
764 .insert(key.clone(), layout.clone());
765 current_frame.used_wrapped_lines.push(key.clone());
766 self.global_cache.insert_wrapped_line(key, layout.clone());
767
768 layout
769 }
770 }
771
772 pub fn layout_line<Text>(
773 &self,
774 text: Text,
775 font_size: Pixels,
776 runs: &[FontRun],
777 force_width: Option<Pixels>,
778 ) -> Arc<LineLayout>
779 where
780 Text: AsRef<str>,
781 SharedString: From<Text>,
782 {
783 self.layout_line_with_spacing(text, font_size, runs, force_width, None)
784 }
785
786 pub fn layout_line_with_spacing<Text>(
787 &self,
788 text: Text,
789 font_size: Pixels,
790 runs: &[FontRun],
791 force_width: Option<Pixels>,
792 letter_spacing: Option<Pixels>,
793 ) -> Arc<LineLayout>
794 where
795 Text: AsRef<str>,
796 SharedString: From<Text>,
797 {
798 let _font_generation = self.clear_if_font_generation_changed();
799 let key = &CacheKeyRef {
800 text: text.as_ref(),
801 font_size,
802 runs,
803 wrap_width: None,
804 force_width,
805 letter_spacing,
806 } as &dyn AsCacheKeyRef;
807
808 let current_frame = self.current_frame.upgradable_read();
809 if let Some(layout) = current_frame.lines.get(key) {
810 return layout.clone();
811 }
812
813 let mut current_frame = RwLockUpgradableReadGuard::upgrade(current_frame);
814 if let Some((key, layout)) = self.previous_frame.lock().lines.remove_entry(key) {
815 current_frame.lines.insert(key.clone(), layout.clone());
816 current_frame.used_lines.push(key);
817 return layout;
818 }
819
820 if let Some(layout) = self.global_cache.get_line(key) {
822 let key = Arc::new(CacheKey {
823 text: SharedString::from(text),
824 font_size,
825 runs: SmallVec::from(runs),
826 wrap_width: None,
827 force_width,
828 letter_spacing,
829 });
830 current_frame.lines.insert(key.clone(), layout.clone());
831 current_frame.used_lines.push(key);
832 return layout;
833 }
834
835 let text = SharedString::from(text);
836 let mut layout = self
837 .platform_text_system
838 .layout_line(&text, font_size, runs);
839
840 if let Some(force_width) = force_width {
841 apply_force_width_to_layout(&mut layout, force_width);
842 }
843
844 if let Some(spacing) = letter_spacing {
845 apply_letter_spacing_to_layout(&mut layout, spacing, force_width);
846 }
847
848 let key = Arc::new(CacheKey {
849 text,
850 font_size,
851 runs: SmallVec::from(runs),
852 wrap_width: None,
853 force_width,
854 letter_spacing,
855 });
856 let layout = Arc::new(layout);
857 current_frame.lines.insert(key.clone(), layout.clone());
858 current_frame.used_lines.push(key.clone());
859 self.global_cache.insert_line(key, layout.clone());
860 layout
861 }
862
863 fn clear_if_font_generation_changed(&self) -> usize {
864 let font_generation = self.font_generation.load(Ordering::Acquire);
865 if self.cached_font_generation.load(Ordering::Acquire) == font_generation {
866 return font_generation;
867 }
868
869 let mut current_frame = self.current_frame.write();
870 if self.cached_font_generation.load(Ordering::Acquire) == font_generation {
871 return font_generation;
872 }
873
874 *current_frame = FrameCache::default();
875 *self.previous_frame.lock() = FrameCache::default();
876 self.global_cache.clear();
880 self.cached_font_generation
881 .store(font_generation, Ordering::Release);
882 font_generation
883 }
884}
885
886fn apply_force_width_to_layout(layout: &mut LineLayout, force_width: Pixels) {
889 let mut glyph_pos: usize = 0;
890 let mut last_base_shaped_x = px(f32::NEG_INFINITY);
891 let mut last_base_actual_x = px(0.);
892
893 for run in layout.runs.iter_mut() {
894 for glyph in run.glyphs.iter_mut() {
895 let shaped_x = glyph.position.x;
896
897 if shaped_x > last_base_shaped_x + force_width * 0.5 {
898 let forced_x = glyph_pos * force_width;
899 if (shaped_x - forced_x).abs() > px(1.) {
900 glyph.position.x = forced_x;
901 }
902 last_base_shaped_x = shaped_x;
903 last_base_actual_x = glyph.position.x;
904 glyph_pos += 1;
905 } else {
906 glyph.position.x = last_base_actual_x + (shaped_x - last_base_shaped_x);
907 }
908 }
909 }
910}
911
912fn apply_letter_spacing_to_layout(
913 layout: &mut LineLayout,
914 spacing: Pixels,
915 force_width: Option<Pixels>,
916) {
917 let glyph_count = if let Some(force_width) = force_width {
918 let mut base_glyph_count: usize = 0;
919 let mut last_base_x = px(f32::NEG_INFINITY);
920 let mut last_base_spacing = px(0.);
921
922 for run in layout.runs.iter_mut() {
923 for glyph in run.glyphs.iter_mut() {
924 let x = glyph.position.x;
925
926 if x > last_base_x + force_width * 0.5 {
927 last_base_spacing = spacing * base_glyph_count as f32;
928 glyph.position.x = x + last_base_spacing;
929 last_base_x = x;
930 base_glyph_count += 1;
931 } else {
932 glyph.position.x = x + last_base_spacing;
933 }
934 }
935 }
936
937 base_glyph_count
938 } else {
939 let mut glyph_count: usize = 0;
940 for run in layout.runs.iter_mut() {
941 for glyph in run.glyphs.iter_mut() {
942 glyph.position.x = glyph.position.x + spacing * glyph_count as f32;
943 glyph_count += 1;
944 }
945 }
946
947 glyph_count
948 };
949
950 if glyph_count > 1 {
951 layout.width = layout.width + spacing * (glyph_count - 1) as f32;
952 }
953}
954
955#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
957#[allow(missing_docs)]
958pub struct FontRun {
959 pub len: usize,
960 pub font_id: FontId,
961}
962
963trait AsCacheKeyRef {
964 fn as_cache_key_ref(&self) -> CacheKeyRef<'_>;
965}
966
967#[derive(Clone, Debug, Eq)]
968struct CacheKey {
969 text: SharedString,
970 font_size: Pixels,
971 runs: SmallVec<[FontRun; 1]>,
972 wrap_width: Option<Pixels>,
973 force_width: Option<Pixels>,
974 letter_spacing: Option<Pixels>,
975}
976
977#[derive(Copy, Clone, PartialEq, Eq, Hash)]
978struct CacheKeyRef<'a> {
979 text: &'a str,
980 font_size: Pixels,
981 runs: &'a [FontRun],
982 wrap_width: Option<Pixels>,
983 force_width: Option<Pixels>,
984 letter_spacing: Option<Pixels>,
985}
986
987impl PartialEq for dyn AsCacheKeyRef + '_ {
988 fn eq(&self, other: &dyn AsCacheKeyRef) -> bool {
989 self.as_cache_key_ref() == other.as_cache_key_ref()
990 }
991}
992
993impl Eq for dyn AsCacheKeyRef + '_ {}
994
995impl Hash for dyn AsCacheKeyRef + '_ {
996 fn hash<H: Hasher>(&self, state: &mut H) {
997 self.as_cache_key_ref().hash(state)
998 }
999}
1000
1001impl AsCacheKeyRef for CacheKey {
1002 fn as_cache_key_ref(&self) -> CacheKeyRef<'_> {
1003 CacheKeyRef {
1004 text: &self.text,
1005 font_size: self.font_size,
1006 runs: self.runs.as_slice(),
1007 wrap_width: self.wrap_width,
1008 force_width: self.force_width,
1009 letter_spacing: self.letter_spacing,
1010 }
1011 }
1012}
1013
1014impl PartialEq for CacheKey {
1015 fn eq(&self, other: &Self) -> bool {
1016 self.as_cache_key_ref().eq(&other.as_cache_key_ref())
1017 }
1018}
1019
1020impl Hash for CacheKey {
1021 fn hash<H: Hasher>(&self, state: &mut H) {
1022 self.as_cache_key_ref().hash(state);
1023 }
1024}
1025
1026impl<'a> Borrow<dyn AsCacheKeyRef + 'a> for Arc<CacheKey> {
1027 fn borrow(&self) -> &(dyn AsCacheKeyRef + 'a) {
1028 self.as_ref() as &dyn AsCacheKeyRef
1029 }
1030}
1031
1032impl AsCacheKeyRef for CacheKeyRef<'_> {
1033 fn as_cache_key_ref(&self) -> CacheKeyRef<'_> {
1034 *self
1035 }
1036}
1037
1038#[cfg(test)]
1039mod tests {
1040 use super::*;
1041 use crate::GlyphId;
1042
1043 fn glyph_at(x: f32, index: usize) -> ShapedGlyph {
1044 ShapedGlyph {
1045 id: GlyphId(0),
1046 position: point(px(x), px(0.)),
1047 index,
1048 is_emoji: false,
1049 }
1050 }
1051
1052 fn make_layout(glyphs: Vec<ShapedGlyph>) -> LineLayout {
1053 LineLayout {
1054 font_size: px(16.),
1055 width: px(100.),
1056 ascent: px(12.),
1057 descent: px(4.),
1058 runs: vec![ShapedRun {
1059 font_id: FontId(0),
1060 glyphs,
1061 }],
1062 len: 0,
1063 }
1064 }
1065
1066 fn glyph_x_positions(layout: &LineLayout) -> Vec<f32> {
1067 layout.runs[0]
1068 .glyphs
1069 .iter()
1070 .map(|glyph| f32::from(glyph.position.x))
1071 .collect()
1072 }
1073
1074 fn make_global_cache_key(text: &str) -> Arc<CacheKey> {
1075 Arc::new(CacheKey {
1076 text: SharedString::from(text.to_owned()),
1077 font_size: px(16.),
1078 runs: SmallVec::new(),
1079 wrap_width: None,
1080 force_width: None,
1081 letter_spacing: None,
1082 })
1083 }
1084
1085 #[test]
1086 fn test_global_layout_cache_clear_drops_all_entries() {
1087 let cache = GlobalLineLayoutCache::new(64, 32);
1088 let layout = Arc::new(make_layout(vec![glyph_at(0., 0)]));
1089 cache.insert_line(make_global_cache_key("hello"), layout.clone());
1090 cache.insert_line(make_global_cache_key("world"), layout);
1091
1092 assert_eq!(cache.entry_counts(), (2, 0));
1093
1094 cache.clear();
1095
1096 assert_eq!(cache.entry_counts(), (0, 0));
1097 }
1098
1099 #[test]
1100 fn test_split_at_partitions_glyphs_and_rebases_suffix() {
1101 let layout = LineLayout {
1102 font_size: px(16.),
1103 width: px(30.),
1104 ascent: px(12.),
1105 descent: px(4.),
1106 runs: vec![ShapedRun {
1107 font_id: FontId(0),
1108 glyphs: vec![glyph_at(0., 0), glyph_at(10., 1), glyph_at(20., 2)],
1109 }],
1110 len: 3,
1111 };
1112
1113 let (left, right) = layout.split_at(1);
1114
1115 assert_eq!(left.len, 1);
1116 assert_eq!(left.width, px(10.));
1117 assert_eq!(left.font_size, layout.font_size);
1118 assert_eq!(left.ascent, layout.ascent);
1119 assert_eq!(left.descent, layout.descent);
1120 assert_eq!(glyph_x_positions(&left), vec![0.]);
1121 assert_eq!(left.runs[0].glyphs[0].index, 0);
1122
1123 assert_eq!(right.len, 2);
1124 assert_eq!(right.width, px(20.));
1125 assert_eq!(glyph_x_positions(&right), vec![0., 10.]);
1126 assert_eq!(
1127 right.runs[0]
1128 .glyphs
1129 .iter()
1130 .map(|glyph| glyph.index)
1131 .collect::<Vec<_>>(),
1132 vec![0, 1]
1133 );
1134 }
1135
1136 #[test]
1137 fn test_split_at_mid_run_and_empty_sides() {
1138 let layout = LineLayout {
1139 font_size: px(16.),
1140 width: px(20.),
1141 ascent: px(12.),
1142 descent: px(4.),
1143 runs: vec![
1144 ShapedRun {
1145 font_id: FontId(0),
1146 glyphs: vec![glyph_at(0., 0), glyph_at(8., 1)],
1147 },
1148 ShapedRun {
1149 font_id: FontId(1),
1150 glyphs: vec![glyph_at(16., 2)],
1151 },
1152 ],
1153 len: 3,
1154 };
1155
1156 let (left, right) = layout.split_at(2);
1157 assert_eq!(left.runs.len(), 1);
1158 assert_eq!(left.runs[0].glyphs.len(), 2);
1159 assert_eq!(right.runs.len(), 1);
1160 assert_eq!(right.runs[0].font_id, FontId(1));
1161 assert_eq!(glyph_x_positions(&right), vec![0.]);
1162
1163 let (empty_left, all_right) = layout.split_at(0);
1164 assert!(empty_left.runs.is_empty());
1165 assert_eq!(empty_left.width, px(0.));
1166 assert_eq!(all_right.len, 3);
1167 assert_eq!(all_right.runs.len(), 2);
1168
1169 let (all_left, empty_right) = layout.split_at(3);
1170 assert_eq!(all_left.runs.len(), 2);
1171 assert!(empty_right.runs.is_empty());
1172 assert_eq!(empty_right.width, px(0.));
1173 }
1174
1175 #[test]
1176 fn test_force_width_latin_unchanged() {
1177 let cell_width = px(8.);
1178 let mut layout = make_layout(vec![glyph_at(0., 0), glyph_at(8., 1), glyph_at(16., 2)]);
1179
1180 apply_force_width_to_layout(&mut layout, cell_width);
1181
1182 assert_eq!(glyph_x_positions(&layout), vec![0., 8., 16.]);
1183 }
1184
1185 #[test]
1186 fn test_force_width_combining_marks_not_advanced() {
1187 let cell_width = px(8.);
1188 let mut layout = make_layout(vec![glyph_at(0., 0), glyph_at(0., 3)]);
1189
1190 apply_force_width_to_layout(&mut layout, cell_width);
1191
1192 assert_eq!(glyph_x_positions(&layout), vec![0., 0.]);
1193 }
1194
1195 #[test]
1196 fn test_force_width_base_after_combining_mark() {
1197 let cell_width = px(8.);
1198 let mut layout = make_layout(vec![glyph_at(0., 0), glyph_at(0., 3), glyph_at(8., 6)]);
1199
1200 apply_force_width_to_layout(&mut layout, cell_width);
1201
1202 assert_eq!(glyph_x_positions(&layout), vec![0., 0., 8.]);
1203 }
1204
1205 #[test]
1206 fn test_force_width_multiple_combining_marks() {
1207 let cell_width = px(8.);
1208 let mut layout = make_layout(vec![
1209 glyph_at(0., 0),
1210 glyph_at(0., 3),
1211 glyph_at(0., 6),
1212 glyph_at(8., 9),
1213 ]);
1214
1215 apply_force_width_to_layout(&mut layout, cell_width);
1216
1217 assert_eq!(glyph_x_positions(&layout), vec![0., 0., 0., 8.]);
1218 }
1219
1220 #[test]
1221 fn test_force_width_corrects_drifted_base_positions() {
1222 let cell_width = px(8.);
1223 let mut layout = make_layout(vec![glyph_at(0.5, 0), glyph_at(10.2, 1), glyph_at(19.8, 2)]);
1224
1225 apply_force_width_to_layout(&mut layout, cell_width);
1226
1227 assert_eq!(glyph_x_positions(&layout), vec![0.5, 8., 16.]);
1228 }
1229
1230 #[test]
1231 fn test_force_width_combining_mark_after_within_tolerance_base() {
1232 let cell_width = px(8.);
1233 let mut layout = make_layout(vec![glyph_at(0.5, 0), glyph_at(0.5, 3)]);
1234
1235 apply_force_width_to_layout(&mut layout, cell_width);
1236
1237 assert_eq!(glyph_x_positions(&layout), vec![0.5, 0.5]);
1238 }
1239
1240 #[test]
1241 fn test_force_width_with_letter_spacing_keeps_combining_marks_anchored() {
1242 let cell_width = px(8.);
1243 let mut layout = make_layout(vec![glyph_at(0., 0), glyph_at(0., 3), glyph_at(8., 6)]);
1244
1245 apply_force_width_to_layout(&mut layout, cell_width);
1246 apply_letter_spacing_to_layout(&mut layout, px(1.), Some(cell_width));
1247
1248 assert_eq!(glyph_x_positions(&layout), vec![0., 0., 9.]);
1249 assert_eq!(layout.width, px(101.));
1250 }
1251}