1#![allow(clippy::too_many_arguments)]
4
5use crate::fallback::FontFallbackIter;
6use crate::{
7 math, Align, Attrs, AttrsList, CacheKeyFlags, Color, DecorationMetrics, DecorationSpan,
8 Ellipsize, EllipsizeHeightLimit, Font, FontSystem, GlyphDecorationData, Hinting, LayoutGlyph,
9 LayoutLine, Metrics, Wrap,
10};
11#[cfg(not(feature = "std"))]
12use alloc::{format, vec, vec::Vec};
13
14use alloc::collections::VecDeque;
15use core::cmp::{max, min};
16use core::fmt;
17use core::mem;
18use core::ops::Range;
19
20#[cfg(not(feature = "std"))]
21use core_maths::CoreFloat;
22use fontdb::Style;
23use unicode_script::{Script, UnicodeScript};
24use unicode_segmentation::UnicodeSegmentation;
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
28pub enum Shaping {
29 #[cfg(feature = "swash")]
37 Basic,
38 Advanced,
44}
45
46impl Shaping {
47 fn run(
48 self,
49 glyphs: &mut Vec<ShapeGlyph>,
50 font_system: &mut FontSystem,
51 line: &str,
52 attrs_list: &AttrsList,
53 start_run: usize,
54 end_run: usize,
55 span_rtl: bool,
56 ) {
57 match self {
58 #[cfg(feature = "swash")]
59 Self::Basic => shape_skip(font_system, glyphs, line, attrs_list, start_run, end_run),
60 #[cfg(not(feature = "shape-run-cache"))]
61 Self::Advanced => shape_run(
62 glyphs,
63 font_system,
64 line,
65 attrs_list,
66 start_run,
67 end_run,
68 span_rtl,
69 ),
70 #[cfg(feature = "shape-run-cache")]
71 Self::Advanced => shape_run_cached(
72 glyphs,
73 font_system,
74 line,
75 attrs_list,
76 start_run,
77 end_run,
78 span_rtl,
79 ),
80 }
81 }
82}
83
84const NUM_SHAPE_PLANS: usize = 6;
85
86#[derive(Default)]
88pub struct ShapeBuffer {
89 shape_plan_cache: VecDeque<(fontdb::ID, harfrust::ShapePlan)>,
92
93 harfrust_buffer: Option<harfrust::UnicodeBuffer>,
95
96 scripts: Vec<Script>,
98
99 spans: Vec<ShapeSpan>,
101
102 words: Vec<ShapeWord>,
104
105 visual_lines: Vec<VisualLine>,
107 cached_visual_lines: Vec<VisualLine>,
108
109 glyph_sets: Vec<Vec<LayoutGlyph>>,
111}
112
113impl fmt::Debug for ShapeBuffer {
114 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115 f.pad("ShapeBuffer { .. }")
116 }
117}
118
119fn shape_fallback(
120 scratch: &mut ShapeBuffer,
121 glyphs: &mut Vec<ShapeGlyph>,
122 font: &Font,
123 line: &str,
124 attrs_list: &AttrsList,
125 start_run: usize,
126 end_run: usize,
127 span_rtl: bool,
128) -> Vec<usize> {
129 let run = &line[start_run..end_run];
130
131 let font_scale = font.metrics().units_per_em as f32;
132 let ascent = font.metrics().ascent / font_scale;
133 let descent = -font.metrics().descent / font_scale;
134
135 let mut buffer = scratch.harfrust_buffer.take().unwrap_or_default();
136 buffer.set_direction(if span_rtl {
137 harfrust::Direction::RightToLeft
138 } else {
139 harfrust::Direction::LeftToRight
140 });
141 if run.contains('\t') {
142 buffer.push_str(&run.replace('\t', " "));
147 } else {
148 buffer.push_str(run);
149 }
150 buffer.guess_segment_properties();
151
152 let rtl = matches!(buffer.direction(), harfrust::Direction::RightToLeft);
153 assert_eq!(rtl, span_rtl);
154
155 let attrs = attrs_list.get_span(start_run);
156 let mut rb_font_features = Vec::new();
157
158 for feature in &attrs.font_features.features {
160 rb_font_features.push(harfrust::Feature::new(
161 harfrust::Tag::new(feature.tag.as_bytes()),
162 feature.value,
163 0..usize::MAX,
164 ));
165 }
166
167 let language = buffer.language();
168 let key = harfrust::ShapePlanKey::new(Some(buffer.script()), buffer.direction())
169 .features(&rb_font_features)
170 .instance(Some(font.shaper_instance()))
171 .language(language.as_ref());
172
173 let shape_plan = match scratch
174 .shape_plan_cache
175 .iter()
176 .find(|(id, plan)| *id == font.id() && key.matches(plan))
177 {
178 Some((_font_id, plan)) => plan,
179 None => {
180 let plan = harfrust::ShapePlan::new(
181 font.shaper(),
182 buffer.direction(),
183 Some(buffer.script()),
184 buffer.language().as_ref(),
185 &rb_font_features,
186 );
187 if scratch.shape_plan_cache.len() >= NUM_SHAPE_PLANS {
188 scratch.shape_plan_cache.pop_front();
189 }
190 scratch.shape_plan_cache.push_back((font.id(), plan));
191 &scratch
192 .shape_plan_cache
193 .back()
194 .expect("we just pushed the shape plan")
195 .1
196 }
197 };
198
199 let glyph_buffer = font
200 .shaper()
201 .shape_with_plan(shape_plan, buffer, &rb_font_features);
202 let glyph_infos = glyph_buffer.glyph_infos();
203 let glyph_positions = glyph_buffer.glyph_positions();
204
205 let mut missing = Vec::new();
206 glyphs.reserve(glyph_infos.len());
207 let glyph_start = glyphs.len();
208 for (info, pos) in glyph_infos.iter().zip(glyph_positions.iter()) {
209 let start_glyph = start_run + info.cluster as usize;
210
211 if info.glyph_id == 0 {
212 missing.push(start_glyph);
213 }
214
215 let attrs = attrs_list.get_span(start_glyph);
216 let x_advance = pos.x_advance as f32 / font_scale
217 + attrs.letter_spacing_opt.map_or(0.0, |spacing| spacing.0);
218 let y_advance = pos.y_advance as f32 / font_scale;
219 let x_offset = pos.x_offset as f32 / font_scale;
220 let y_offset = pos.y_offset as f32 / font_scale;
221
222 glyphs.push(ShapeGlyph {
223 start: start_glyph,
224 end: end_run, x_advance,
226 y_advance,
227 x_offset,
228 y_offset,
229 ascent,
230 descent,
231 font_monospace_em_width: font.monospace_em_width(),
232 font_id: font.id(),
233 font_weight: attrs.weight,
234 glyph_id: info.glyph_id.try_into().expect("failed to cast glyph ID"),
235 color_opt: attrs.color_opt,
237 metadata: attrs.metadata,
238 cache_key_flags: override_fake_italic(attrs.cache_key_flags, font, &attrs),
239 metrics_opt: attrs.metrics_opt.map(Into::into),
240 });
241 }
242
243 if rtl {
245 for i in glyph_start + 1..glyphs.len() {
246 let next_start = glyphs[i - 1].start;
247 let next_end = glyphs[i - 1].end;
248 let prev = &mut glyphs[i];
249 if prev.start == next_start {
250 prev.end = next_end;
251 } else {
252 prev.end = next_start;
253 }
254 }
255 } else {
256 for i in (glyph_start + 1..glyphs.len()).rev() {
257 let next_start = glyphs[i].start;
258 let next_end = glyphs[i].end;
259 let prev = &mut glyphs[i - 1];
260 if prev.start == next_start {
261 prev.end = next_end;
262 } else {
263 prev.end = next_start;
264 }
265 }
266 }
267
268 scratch.harfrust_buffer = Some(glyph_buffer.clear());
270
271 missing
272}
273
274fn shape_run(
275 glyphs: &mut Vec<ShapeGlyph>,
276 font_system: &mut FontSystem,
277 line: &str,
278 attrs_list: &AttrsList,
279 start_run: usize,
280 end_run: usize,
281 span_rtl: bool,
282) {
283 let mut scripts = {
285 let mut scripts = mem::take(&mut font_system.shape_buffer.scripts);
286 scripts.clear();
287 scripts
288 };
289 for c in line[start_run..end_run].chars() {
290 match c.script() {
291 Script::Common | Script::Inherited | Script::Latin | Script::Unknown => (),
292 script => {
293 if !scripts.contains(&script) {
294 scripts.push(script);
295 }
296 }
297 }
298 }
299
300 log::trace!(" Run {:?}: '{}'", &scripts, &line[start_run..end_run],);
301
302 let attrs = attrs_list.get_span(start_run);
303
304 let fonts = font_system.get_font_matches(&attrs);
305
306 let default_families = [&attrs.family];
307 let mut font_iter = FontFallbackIter::new(
308 font_system,
309 &fonts,
310 &default_families,
311 &scripts,
312 &line[start_run..end_run],
313 attrs.weight,
314 );
315
316 let font = font_iter.next().expect("no default font found");
317
318 let glyph_start = glyphs.len();
319 let mut missing = {
320 let scratch = font_iter.shape_caches();
321 shape_fallback(
322 scratch, glyphs, &font, line, attrs_list, start_run, end_run, span_rtl,
323 )
324 };
325
326 while !missing.is_empty() {
328 let Some(font) = font_iter.next() else {
329 break;
330 };
331
332 log::trace!(
333 "Evaluating fallback with font '{}'",
334 font_iter.face_name(font.id())
335 );
336 let mut fb_glyphs = Vec::new();
337 let scratch = font_iter.shape_caches();
338 let fb_missing = shape_fallback(
339 scratch,
340 &mut fb_glyphs,
341 &font,
342 line,
343 attrs_list,
344 start_run,
345 end_run,
346 span_rtl,
347 );
348
349 let mut fb_i = 0;
351 while fb_i < fb_glyphs.len() {
352 let start = fb_glyphs[fb_i].start;
353 let end = fb_glyphs[fb_i].end;
354
355 if !missing.contains(&start) || fb_missing.contains(&start) {
357 fb_i += 1;
358 continue;
359 }
360
361 let mut missing_i = 0;
362 while missing_i < missing.len() {
363 if missing[missing_i] >= start && missing[missing_i] < end {
364 missing.remove(missing_i);
366 } else {
367 missing_i += 1;
368 }
369 }
370
371 let mut i = glyph_start;
373 while i < glyphs.len() {
374 if glyphs[i].start >= start && glyphs[i].end <= end {
375 break;
376 }
377 i += 1;
378 }
379
380 while i < glyphs.len() {
382 if glyphs[i].start >= start && glyphs[i].end <= end {
383 let _glyph = glyphs.remove(i);
384 } else {
386 break;
387 }
388 }
389
390 while fb_i < fb_glyphs.len() {
391 if fb_glyphs[fb_i].start >= start && fb_glyphs[fb_i].end <= end {
392 let fb_glyph = fb_glyphs.remove(fb_i);
393 glyphs.insert(i, fb_glyph);
395 i += 1;
396 } else {
397 break;
398 }
399 }
400 }
401 }
402
403 font_iter.check_missing(&line[start_run..end_run]);
405
406 font_system.shape_buffer.scripts = scripts;
414}
415
416#[cfg(feature = "shape-run-cache")]
417fn shape_run_cached(
418 glyphs: &mut Vec<ShapeGlyph>,
419 font_system: &mut FontSystem,
420 line: &str,
421 attrs_list: &AttrsList,
422 start_run: usize,
423 end_run: usize,
424 span_rtl: bool,
425) {
426 use crate::{AttrsOwned, ShapeRunKey};
427
428 let run_range = start_run..end_run;
429 let mut key = ShapeRunKey {
430 text: line[run_range.clone()].to_string(),
431 default_attrs: AttrsOwned::new(&attrs_list.defaults()),
432 attrs_spans: Vec::new(),
433 };
434 for (attrs_range, attrs) in attrs_list.spans.overlapping(&run_range) {
435 if attrs == &key.default_attrs {
436 continue;
438 }
439 let start = max(attrs_range.start, start_run).saturating_sub(start_run);
440 let end = min(attrs_range.end, end_run).saturating_sub(start_run);
441 if end > start {
442 let range = start..end;
443 key.attrs_spans.push((range, attrs.clone()));
444 }
445 }
446 if let Some(cache_glyphs) = font_system.shape_run_cache.get(&key) {
447 for mut glyph in cache_glyphs.iter().cloned() {
448 glyph.start += start_run;
450 glyph.end += start_run;
451 glyphs.push(glyph);
452 }
453 return;
454 }
455
456 let mut cache_glyphs = Vec::new();
458 shape_run(
459 &mut cache_glyphs,
460 font_system,
461 line,
462 attrs_list,
463 start_run,
464 end_run,
465 span_rtl,
466 );
467 glyphs.extend_from_slice(&cache_glyphs);
468 for glyph in cache_glyphs.iter_mut() {
469 glyph.start -= start_run;
471 glyph.end -= start_run;
472 }
473 font_system.shape_run_cache.insert(key, cache_glyphs);
474}
475
476#[cfg(feature = "swash")]
477fn shape_skip(
478 font_system: &mut FontSystem,
479 glyphs: &mut Vec<ShapeGlyph>,
480 line: &str,
481 attrs_list: &AttrsList,
482 start_run: usize,
483 end_run: usize,
484) {
485 let attrs = attrs_list.get_span(start_run);
486 let fonts = font_system.get_font_matches(&attrs);
487
488 let default_families = [&attrs.family];
489 let mut font_iter = FontFallbackIter::new(
490 font_system,
491 &fonts,
492 &default_families,
493 &[],
494 "",
495 attrs.weight,
496 );
497
498 let font = font_iter.next().expect("no default font found");
499 let font_id = font.id();
500 let font_monospace_em_width = font.monospace_em_width();
501 let swash_font = font.as_swash();
502
503 let charmap = swash_font.charmap();
504 let metrics = swash_font.metrics(&[]);
505 let glyph_metrics = swash_font.glyph_metrics(&[]).scale(1.0);
506
507 let ascent = metrics.ascent / f32::from(metrics.units_per_em);
508 let descent = metrics.descent / f32::from(metrics.units_per_em);
509
510 glyphs.extend(
511 line[start_run..end_run]
512 .char_indices()
513 .map(|(chr_idx, codepoint)| {
514 let glyph_id = charmap.map(codepoint);
515 let x_advance = glyph_metrics.advance_width(glyph_id)
516 + attrs.letter_spacing_opt.map_or(0.0, |spacing| spacing.0);
517 let attrs = attrs_list.get_span(start_run + chr_idx);
518
519 ShapeGlyph {
520 start: chr_idx + start_run,
521 end: chr_idx + start_run + codepoint.len_utf8(),
522 x_advance,
523 y_advance: 0.0,
524 x_offset: 0.0,
525 y_offset: 0.0,
526 ascent,
527 descent,
528 font_monospace_em_width,
529 font_id,
530 font_weight: attrs.weight,
531 glyph_id,
532 color_opt: attrs.color_opt,
533 metadata: attrs.metadata,
534 cache_key_flags: override_fake_italic(
535 attrs.cache_key_flags,
536 font.as_ref(),
537 &attrs,
538 ),
539 metrics_opt: attrs.metrics_opt.map(Into::into),
540 }
541 }),
542 );
543}
544
545fn override_fake_italic(
546 cache_key_flags: CacheKeyFlags,
547 font: &Font,
548 attrs: &Attrs,
549) -> CacheKeyFlags {
550 if !font.italic_or_oblique && (attrs.style == Style::Italic || attrs.style == Style::Oblique) {
551 cache_key_flags | CacheKeyFlags::FAKE_ITALIC
552 } else {
553 cache_key_flags
554 }
555}
556
557#[derive(Clone, Debug)]
559pub struct ShapeGlyph {
560 pub start: usize,
561 pub end: usize,
562 pub x_advance: f32,
563 pub y_advance: f32,
564 pub x_offset: f32,
565 pub y_offset: f32,
566 pub ascent: f32,
567 pub descent: f32,
568 pub font_monospace_em_width: Option<f32>,
569 pub font_id: fontdb::ID,
570 pub font_weight: fontdb::Weight,
571 pub glyph_id: u16,
572 pub color_opt: Option<Color>,
573 pub metadata: usize,
574 pub cache_key_flags: CacheKeyFlags,
575 pub metrics_opt: Option<Metrics>,
576}
577
578impl ShapeGlyph {
579 const fn layout(
580 &self,
581 font_size: f32,
582 line_height_opt: Option<f32>,
583 x: f32,
584 y: f32,
585 w: f32,
586 level: unicode_bidi::Level,
587 ) -> LayoutGlyph {
588 LayoutGlyph {
589 start: self.start,
590 end: self.end,
591 font_size,
592 line_height_opt,
593 font_id: self.font_id,
594 font_weight: self.font_weight,
595 glyph_id: self.glyph_id,
596 x,
597 y,
598 w,
599 level,
600 x_offset: self.x_offset,
601 y_offset: self.y_offset,
602 color_opt: self.color_opt,
603 metadata: self.metadata,
604 cache_key_flags: self.cache_key_flags,
605 }
606 }
607
608 pub fn width(&self, font_size: f32) -> f32 {
611 self.metrics_opt.map_or(font_size, |x| x.font_size) * self.x_advance
612 }
613}
614
615fn decoration_metrics(font: &Font) -> (DecorationMetrics, DecorationMetrics, f32) {
616 let metrics = font.metrics();
617 let upem = metrics.units_per_em as f32;
618 if upem == 0.0 {
619 return (
620 DecorationMetrics::default(),
621 DecorationMetrics::default(),
622 0.0,
623 );
624 }
625 (
626 DecorationMetrics {
627 offset: metrics.underline.map_or(-0.125, |d| d.offset / upem),
628 thickness: metrics.underline.map_or(1.0 / 14.0, |d| d.thickness / upem),
629 },
630 DecorationMetrics {
631 offset: metrics.strikeout.map_or(0.3, |d| d.offset / upem),
632 thickness: metrics.strikeout.map_or(1.0 / 14.0, |d| d.thickness / upem),
633 },
634 metrics.ascent / upem,
635 )
636}
637
638const ELLIPSIS_SPAN: usize = usize::MAX;
640
641fn shape_ellipsis(
642 font_system: &mut FontSystem,
643 attrs: &Attrs,
644 shaping: Shaping,
645 span_rtl: bool,
646) -> Vec<ShapeGlyph> {
647 let attrs_list = AttrsList::new(attrs);
648 let level = if span_rtl {
649 unicode_bidi::Level::rtl()
650 } else {
651 unicode_bidi::Level::ltr()
652 };
653 let word = ShapeWord::new(
654 font_system,
655 "\u{2026}", &attrs_list,
657 0.."\u{2026}".len(),
658 level,
659 false,
660 shaping,
661 );
662 let mut glyphs = word.glyphs;
663
664 if glyphs.is_empty() || glyphs.iter().all(|g| g.glyph_id == 0) {
666 let fallback = ShapeWord::new(
667 font_system,
668 "...",
669 &attrs_list,
670 0.."...".len(),
671 level,
672 false,
673 shaping,
674 );
675 glyphs = fallback.glyphs;
676 }
677 glyphs
678}
679
680#[derive(Clone, Debug)]
682pub struct ShapeWord {
683 pub blank: bool,
684 pub glyphs: Vec<ShapeGlyph>,
685}
686
687impl ShapeWord {
688 pub(crate) fn empty() -> Self {
692 Self {
693 blank: true,
694 glyphs: Vec::default(),
695 }
696 }
697
698 #[allow(clippy::too_many_arguments)]
700 pub fn new(
701 font_system: &mut FontSystem,
702 line: &str,
703 attrs_list: &AttrsList,
704 word_range: Range<usize>,
705 level: unicode_bidi::Level,
706 blank: bool,
707 shaping: Shaping,
708 ) -> Self {
709 let mut empty = Self::empty();
710 empty.build(
711 font_system,
712 line,
713 attrs_list,
714 word_range,
715 level,
716 blank,
717 shaping,
718 );
719 empty
720 }
721
722 #[allow(clippy::too_many_arguments)]
726 pub fn build(
727 &mut self,
728 font_system: &mut FontSystem,
729 line: &str,
730 attrs_list: &AttrsList,
731 word_range: Range<usize>,
732 level: unicode_bidi::Level,
733 blank: bool,
734 shaping: Shaping,
735 ) {
736 let word = &line[word_range.clone()];
737
738 log::trace!(
739 " Word{}: '{}'",
740 if blank { " BLANK" } else { "" },
741 word
742 );
743
744 let mut glyphs = mem::take(&mut self.glyphs);
745 glyphs.clear();
746
747 let span_rtl = level.is_rtl();
748
749 let is_simple_ascii =
751 word.is_ascii() && !word.chars().any(|c| c.is_ascii_control() && c != '\t');
752
753 if is_simple_ascii && !word.is_empty() && {
754 let attrs_start = attrs_list.get_span(word_range.start);
755 attrs_list.spans_iter().all(|(other_range, other_attrs)| {
756 word_range.end <= other_range.start
757 || other_range.end <= word_range.start
758 || attrs_start.compatible(&other_attrs.as_attrs())
759 })
760 } {
761 shaping.run(
762 &mut glyphs,
763 font_system,
764 line,
765 attrs_list,
766 word_range.start,
767 word_range.end,
768 span_rtl,
769 );
770 } else {
771 let mut start_run = word_range.start;
773 let mut attrs = attrs_list.defaults();
774 for (egc_i, _egc) in word.grapheme_indices(true) {
775 let start_egc = word_range.start + egc_i;
776 let attrs_egc = attrs_list.get_span(start_egc);
777 if !attrs.compatible(&attrs_egc) {
778 shaping.run(
779 &mut glyphs,
780 font_system,
781 line,
782 attrs_list,
783 start_run,
784 start_egc,
785 span_rtl,
786 );
787
788 start_run = start_egc;
789 attrs = attrs_egc;
790 }
791 }
792 if start_run < word_range.end {
793 shaping.run(
794 &mut glyphs,
795 font_system,
796 line,
797 attrs_list,
798 start_run,
799 word_range.end,
800 span_rtl,
801 );
802 }
803 }
804
805 self.blank = blank;
806 self.glyphs = glyphs;
807 }
808
809 pub fn width(&self, font_size: f32) -> f32 {
811 let mut width = 0.0;
812 for glyph in &self.glyphs {
813 width += glyph.width(font_size);
814 }
815 width
816 }
817}
818
819#[derive(Clone, Debug)]
821pub struct ShapeSpan {
822 pub level: unicode_bidi::Level,
823 pub words: Vec<ShapeWord>,
824 pub decoration_spans: Vec<(Range<usize>, GlyphDecorationData)>,
828}
829
830impl ShapeSpan {
831 pub(crate) fn empty() -> Self {
835 Self {
836 level: unicode_bidi::Level::ltr(),
837 words: Vec::default(),
838 decoration_spans: Vec::new(),
839 }
840 }
841
842 pub fn new(
844 font_system: &mut FontSystem,
845 line: &str,
846 attrs_list: &AttrsList,
847 span_range: Range<usize>,
848 line_rtl: bool,
849 level: unicode_bidi::Level,
850 shaping: Shaping,
851 ) -> Self {
852 let mut empty = Self::empty();
853 empty.build(
854 font_system,
855 line,
856 attrs_list,
857 span_range,
858 line_rtl,
859 level,
860 shaping,
861 );
862 empty
863 }
864
865 pub fn build(
869 &mut self,
870 font_system: &mut FontSystem,
871 line: &str,
872 attrs_list: &AttrsList,
873 span_range: Range<usize>,
874 line_rtl: bool,
875 level: unicode_bidi::Level,
876 shaping: Shaping,
877 ) {
878 let span = &line[span_range.start..span_range.end];
879
880 log::trace!(
881 " Span {}: '{}'",
882 if level.is_rtl() { "RTL" } else { "LTR" },
883 span
884 );
885
886 let mut words = mem::take(&mut self.words);
887
888 let mut cached_words = mem::take(&mut font_system.shape_buffer.words);
890 cached_words.clear();
891 if line_rtl != level.is_rtl() {
892 cached_words.append(&mut words);
894 } else {
895 cached_words.extend(words.drain(..).rev());
896 }
897
898 let mut start_word = 0;
899 for (end_lb, _) in unicode_linebreak::linebreaks(span) {
900 if end_lb > 0 && end_lb < span.len() {
902 let start_idx = span_range.start;
903 let pre_char = span[..end_lb].chars().last();
904 let post_char = span[end_lb..].chars().next();
905
906 if let (Some(c1), Some(c2)) = (pre_char, post_char) {
907 if c1.is_ascii_punctuation() && c2.is_ascii_punctuation() {
909 let probe_text = format!("{}{}", c1, c2);
910 let attrs = attrs_list.get_span(start_idx + end_lb);
911 let fonts = font_system.get_font_matches(&attrs);
912 let default_families = [&attrs.family];
913
914 let mut font_iter = FontFallbackIter::new(
915 font_system,
916 &fonts,
917 &default_families,
918 &[],
919 &probe_text,
920 attrs.weight,
921 );
922
923 if let Some(font) = font_iter.next() {
924 let mut glyphs = Vec::new();
925 let scratch = font_iter.shape_caches();
926 shape_fallback(
927 scratch,
928 &mut glyphs,
929 &font,
930 &probe_text,
931 attrs_list,
932 0,
933 probe_text.len(),
934 false,
935 );
936
937 if glyphs.len() < probe_text.chars().count() {
939 continue;
940 }
941
942 #[cfg(feature = "swash")]
946 if glyphs.len() == probe_text.chars().count() {
947 let charmap = font.as_swash().charmap();
948 let mut is_modified = false;
949 for (i, c) in probe_text.chars().enumerate() {
950 let std_id = charmap.map(c);
951 if glyphs[i].glyph_id != std_id {
952 is_modified = true;
953 break;
954 }
955 }
956
957 if is_modified {
958 continue;
960 }
961 }
962 }
963 }
964 }
965 }
966
967 let mut start_lb = end_lb;
968 for (i, c) in span[start_word..end_lb].char_indices().rev() {
969 if c.is_whitespace() {
974 start_lb = start_word + i;
975 } else {
976 break;
977 }
978 }
979 if start_word < start_lb {
980 let mut word = cached_words.pop().unwrap_or_else(ShapeWord::empty);
981 word.build(
982 font_system,
983 line,
984 attrs_list,
985 (span_range.start + start_word)..(span_range.start + start_lb),
986 level,
987 false,
988 shaping,
989 );
990 words.push(word);
991 }
992 if start_lb < end_lb {
993 for (i, c) in span[start_lb..end_lb].char_indices() {
994 let mut word = cached_words.pop().unwrap_or_else(ShapeWord::empty);
996 word.build(
997 font_system,
998 line,
999 attrs_list,
1000 (span_range.start + start_lb + i)
1001 ..(span_range.start + start_lb + i + c.len_utf8()),
1002 level,
1003 true,
1004 shaping,
1005 );
1006 words.push(word);
1007 }
1008 }
1009 start_word = end_lb;
1010 }
1011
1012 if line_rtl {
1014 for word in &mut words {
1015 word.glyphs.reverse();
1016 }
1017 }
1018
1019 if line_rtl != level.is_rtl() {
1021 words.reverse();
1022 }
1023
1024 self.level = level;
1025 self.words = words;
1026
1027 self.decoration_spans.clear();
1031
1032 let any_decoration = attrs_list.defaults().text_decoration.has_decoration()
1035 || attrs_list.spans_iter().any(|(range, attr_owned)| {
1036 let start = range.start.max(span_range.start);
1037 let end = range.end.min(span_range.end);
1038 start < end && attr_owned.as_attrs().text_decoration.has_decoration()
1039 });
1040
1041 if any_decoration {
1042 let primary_metrics = self
1044 .words
1045 .iter()
1046 .flat_map(|w| w.glyphs.first())
1047 .next()
1048 .and_then(|glyph| {
1049 font_system
1050 .get_font(glyph.font_id, glyph.font_weight)
1051 .map(|font| decoration_metrics(&font))
1052 });
1053
1054 if let Some((ul_metrics, st_metrics, ascent)) = primary_metrics {
1055 let mut covered_end = span_range.start;
1057
1058 for (range, attr_owned) in attrs_list.spans_iter() {
1059 let start = range.start.max(span_range.start);
1061 let end = range.end.min(span_range.end);
1062 if start >= end {
1063 continue;
1064 }
1065
1066 if covered_end < start {
1068 let default_attrs = attrs_list.defaults();
1069 if default_attrs.text_decoration.has_decoration() {
1070 self.decoration_spans.push((
1071 covered_end..start,
1072 GlyphDecorationData {
1073 text_decoration: default_attrs.text_decoration,
1074 underline_metrics: ul_metrics,
1075 strikethrough_metrics: st_metrics,
1076 ascent,
1077 },
1078 ));
1079 }
1080 }
1081 covered_end = end;
1082
1083 let attrs = attr_owned.as_attrs();
1084 if attrs.text_decoration.has_decoration() {
1085 self.decoration_spans.push((
1086 start..end,
1087 GlyphDecorationData {
1088 text_decoration: attrs.text_decoration,
1089 underline_metrics: ul_metrics,
1090 strikethrough_metrics: st_metrics,
1091 ascent,
1092 },
1093 ));
1094 }
1095 }
1096
1097 if covered_end < span_range.end {
1099 let default_attrs = attrs_list.defaults();
1100 if default_attrs.text_decoration.has_decoration() {
1101 self.decoration_spans.push((
1102 covered_end..span_range.end,
1103 GlyphDecorationData {
1104 text_decoration: default_attrs.text_decoration,
1105 underline_metrics: ul_metrics,
1106 strikethrough_metrics: st_metrics,
1107 ascent,
1108 },
1109 ));
1110 }
1111 }
1112 }
1113 }
1114
1115 font_system.shape_buffer.words = cached_words;
1117 }
1118}
1119
1120#[derive(Clone, Debug)]
1122pub struct ShapeLine {
1123 pub rtl: bool,
1124 pub spans: Vec<ShapeSpan>,
1125 pub metrics_opt: Option<Metrics>,
1126 ellipsis_span: Option<ShapeSpan>,
1127}
1128
1129#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
1130struct WordGlyphPos {
1131 word: usize,
1132 glyph: usize,
1133}
1134
1135impl WordGlyphPos {
1136 const ZERO: Self = Self { word: 0, glyph: 0 };
1137 fn new(word: usize, glyph: usize) -> Self {
1138 Self { word, glyph }
1139 }
1140}
1141
1142#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
1143struct SpanWordGlyphPos {
1144 span: usize,
1145 word: usize,
1146 glyph: usize,
1147}
1148
1149impl SpanWordGlyphPos {
1150 const ZERO: Self = Self {
1151 span: 0,
1152 word: 0,
1153 glyph: 0,
1154 };
1155 fn word_glyph_pos(&self) -> WordGlyphPos {
1156 WordGlyphPos {
1157 word: self.word,
1158 glyph: self.glyph,
1159 }
1160 }
1161 fn with_wordglyph(span: usize, wordglyph: WordGlyphPos) -> Self {
1162 Self {
1163 span,
1164 word: wordglyph.word,
1165 glyph: wordglyph.glyph,
1166 }
1167 }
1168}
1169
1170#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1173enum LayoutDirection {
1174 Forward,
1175 Backward,
1176}
1177
1178#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1180struct VlRange {
1181 span: usize,
1182 start: WordGlyphPos,
1183 end: WordGlyphPos,
1184 level: unicode_bidi::Level,
1185}
1186
1187impl Default for VlRange {
1188 fn default() -> Self {
1189 Self {
1190 span: Default::default(),
1191 start: Default::default(),
1192 end: Default::default(),
1193 level: unicode_bidi::Level::ltr(),
1194 }
1195 }
1196}
1197
1198#[derive(Default, Debug)]
1199struct VisualLine {
1200 ranges: Vec<VlRange>,
1201 spaces: u32,
1202 w: f32,
1203 ellipsized: bool,
1204 elided_byte_range: Option<(usize, usize)>,
1207}
1208
1209impl VisualLine {
1210 fn clear(&mut self) {
1211 self.ranges.clear();
1212 self.spaces = 0;
1213 self.w = 0.;
1214 self.ellipsized = false;
1215 self.elided_byte_range = None;
1216 }
1217}
1218
1219impl ShapeLine {
1220 pub(crate) fn empty() -> Self {
1224 Self {
1225 rtl: false,
1226 spans: Vec::default(),
1227 metrics_opt: None,
1228 ellipsis_span: None,
1229 }
1230 }
1231
1232 pub fn new(
1239 font_system: &mut FontSystem,
1240 line: &str,
1241 attrs_list: &AttrsList,
1242 shaping: Shaping,
1243 tab_width: u16,
1244 ) -> Self {
1245 let mut empty = Self::empty();
1246 empty.build(font_system, line, attrs_list, shaping, tab_width);
1247 empty
1248 }
1249
1250 pub fn build(
1258 &mut self,
1259 font_system: &mut FontSystem,
1260 line: &str,
1261 attrs_list: &AttrsList,
1262 shaping: Shaping,
1263 tab_width: u16,
1264 ) {
1265 let mut spans = mem::take(&mut self.spans);
1266
1267 let mut cached_spans = mem::take(&mut font_system.shape_buffer.spans);
1269 cached_spans.clear();
1270 cached_spans.extend(spans.drain(..).rev());
1271
1272 let bidi = unicode_bidi::BidiInfo::new(line, None);
1273 let rtl = if bidi.paragraphs.is_empty() {
1274 false
1275 } else {
1276 bidi.paragraphs[0].level.is_rtl()
1277 };
1278
1279 log::trace!("Line {}: '{}'", if rtl { "RTL" } else { "LTR" }, line);
1280
1281 for para_info in &bidi.paragraphs {
1282 let line_rtl = para_info.level.is_rtl();
1283 assert_eq!(line_rtl, rtl);
1284
1285 let line_range = para_info.range.clone();
1286 let levels = Self::adjust_levels(&unicode_bidi::Paragraph::new(&bidi, para_info));
1287
1288 let mut start = line_range.start;
1291 let mut run_level = levels[start];
1292 spans.reserve(line_range.end - start + 1);
1293
1294 for (i, &new_level) in levels
1295 .iter()
1296 .enumerate()
1297 .take(line_range.end)
1298 .skip(start + 1)
1299 {
1300 if new_level != run_level {
1301 let mut span = cached_spans.pop().unwrap_or_else(ShapeSpan::empty);
1303 span.build(
1304 font_system,
1305 line,
1306 attrs_list,
1307 start..i,
1308 line_rtl,
1309 run_level,
1310 shaping,
1311 );
1312 spans.push(span);
1313 start = i;
1314 run_level = new_level;
1315 }
1316 }
1317 let mut span = cached_spans.pop().unwrap_or_else(ShapeSpan::empty);
1318 span.build(
1319 font_system,
1320 line,
1321 attrs_list,
1322 start..line_range.end,
1323 line_rtl,
1324 run_level,
1325 shaping,
1326 );
1327 spans.push(span);
1328 }
1329
1330 let mut x = 0.0;
1332 for span in &mut spans {
1333 for word in &mut span.words {
1334 for glyph in &mut word.glyphs {
1335 if line.get(glyph.start..glyph.end) == Some("\t") {
1336 let tab_x_advance = f32::from(tab_width) * glyph.x_advance;
1338 let tab_stop = (math::floorf(x / tab_x_advance) + 1.0) * tab_x_advance;
1339 glyph.x_advance = tab_stop - x;
1340 }
1341 x += glyph.x_advance;
1342 }
1343 }
1344 }
1345
1346 self.rtl = rtl;
1347 self.spans = spans;
1348 self.metrics_opt = attrs_list.defaults().metrics_opt.map(Into::into);
1349
1350 self.ellipsis_span.get_or_insert_with(|| {
1351 let attrs = if attrs_list.spans.is_empty() {
1352 attrs_list.defaults()
1353 } else {
1354 attrs_list.get_span(0) };
1358 let mut glyphs = shape_ellipsis(font_system, &attrs, shaping, rtl);
1359 if rtl {
1360 glyphs.reverse();
1361 }
1362 let word = ShapeWord {
1363 blank: false,
1364 glyphs,
1365 };
1366 let level = if rtl {
1369 unicode_bidi::Level::rtl()
1370 } else {
1371 unicode_bidi::Level::ltr()
1372 };
1373 ShapeSpan {
1374 level,
1375 words: vec![word],
1376 decoration_spans: Vec::new(),
1377 }
1378 });
1379
1380 font_system.shape_buffer.spans = cached_spans;
1382 }
1383
1384 fn adjust_levels(para: &unicode_bidi::Paragraph) -> Vec<unicode_bidi::Level> {
1386 use unicode_bidi::BidiClass::{B, BN, FSI, LRE, LRI, LRO, PDF, PDI, RLE, RLI, RLO, S, WS};
1387 let text = para.info.text;
1388 let levels = ¶.info.levels;
1389 let original_classes = ¶.info.original_classes;
1390
1391 let mut levels = levels.clone();
1392 let line_classes = &original_classes[..];
1393 let line_levels = &mut levels[..];
1394
1395 let mut reset_from: Option<usize> = Some(0);
1398 let mut reset_to: Option<usize> = None;
1399 for (i, c) in text.char_indices() {
1400 match line_classes[i] {
1401 RLE | LRE | RLO | LRO | PDF | BN => {}
1403 B | S => {
1405 assert_eq!(reset_to, None);
1406 reset_to = Some(i + c.len_utf8());
1407 if reset_from.is_none() {
1408 reset_from = Some(i);
1409 }
1410 }
1411 WS | FSI | LRI | RLI | PDI => {
1413 if reset_from.is_none() {
1414 reset_from = Some(i);
1415 }
1416 }
1417 _ => {
1418 reset_from = None;
1419 }
1420 }
1421 if let (Some(from), Some(to)) = (reset_from, reset_to) {
1422 for level in &mut line_levels[from..to] {
1423 *level = para.para.level;
1424 }
1425 reset_from = None;
1426 reset_to = None;
1427 }
1428 }
1429 if let Some(from) = reset_from {
1430 for level in &mut line_levels[from..] {
1431 *level = para.para.level;
1432 }
1433 }
1434 levels
1435 }
1436
1437 fn reorder(&self, line_range: &[VlRange]) -> Vec<Range<usize>> {
1439 let line: Vec<unicode_bidi::Level> = line_range.iter().map(|range| range.level).collect();
1440 let count = line.len();
1441 if count == 0 {
1442 return Vec::new();
1443 }
1444
1445 let mut elements: Vec<Range<usize>> = (0..count).map(|i| i..i + 1).collect();
1449
1450 let mut min_level = line[0];
1451 let mut max_level = line[0];
1452 for &level in &line[1..] {
1453 min_level = min(min_level, level);
1454 max_level = max(max_level, level);
1455 }
1456
1457 min_level = min_level.new_lowest_ge_rtl().expect("Level error");
1462
1463 while max_level >= min_level {
1464 let mut seq_start = 0;
1466 while seq_start < count {
1467 if line[elements[seq_start].start] < max_level {
1468 seq_start += 1;
1469 continue;
1470 }
1471
1472 let mut seq_end = seq_start + 1;
1474 while seq_end < count {
1475 if line[elements[seq_end].start] < max_level {
1476 break;
1477 }
1478 seq_end += 1;
1479 }
1480
1481 elements[seq_start..seq_end].reverse();
1483
1484 seq_start = seq_end;
1485 }
1486 max_level
1487 .lower(1)
1488 .expect("Lowering embedding level below zero");
1489 }
1490
1491 elements
1492 }
1493
1494 pub fn layout(
1495 &self,
1496 font_size: f32,
1497 width_opt: Option<f32>,
1498 wrap: Wrap,
1499 align: Option<Align>,
1500 match_mono_width: Option<f32>,
1501 hinting: Hinting,
1502 ) -> Vec<LayoutLine> {
1503 let mut lines = Vec::with_capacity(1);
1504 let mut scratch = ShapeBuffer::default();
1505 self.layout_to_buffer(
1506 &mut scratch,
1507 font_size,
1508 width_opt,
1509 wrap,
1510 Ellipsize::None,
1511 align,
1512 &mut lines,
1513 match_mono_width,
1514 hinting,
1515 );
1516 lines
1517 }
1518
1519 fn get_glyph_start_end(
1520 word: &ShapeWord,
1521 start: SpanWordGlyphPos,
1522 span_index: usize,
1523 word_idx: usize,
1524 _direction: LayoutDirection,
1525 congruent: bool,
1526 ) -> (usize, usize) {
1527 if span_index != start.span || word_idx != start.word {
1528 return (0, word.glyphs.len());
1529 }
1530 let (start_glyph_pos, end_glyph_pos) = if congruent {
1531 (start.glyph, word.glyphs.len())
1532 } else {
1533 (0, start.glyph)
1534 };
1535 (start_glyph_pos, end_glyph_pos)
1536 }
1537
1538 fn fit_glyphs(
1539 word: &ShapeWord,
1540 font_size: f32,
1541 start: SpanWordGlyphPos,
1542 span_index: usize,
1543 word_idx: usize,
1544 direction: LayoutDirection,
1545 congruent: bool,
1546 currently_used_width: f32,
1547 total_available_width: f32,
1548 forward: bool,
1549 ) -> (usize, f32) {
1550 let mut glyphs_w = 0.0;
1551 let (start_glyph_pos, end_glyph_pos) =
1552 Self::get_glyph_start_end(word, start, span_index, word_idx, direction, congruent);
1553
1554 if forward {
1555 let mut glyph_end = start_glyph_pos;
1556 for glyph_idx in start_glyph_pos..end_glyph_pos {
1557 let g_w = word.glyphs[glyph_idx].width(font_size);
1558 if currently_used_width + glyphs_w + g_w > total_available_width {
1559 break;
1560 }
1561 glyphs_w += g_w;
1562 glyph_end = glyph_idx + 1;
1563 }
1564 (glyph_end, glyphs_w)
1565 } else {
1566 let mut glyph_end = word.glyphs.len();
1567 for glyph_idx in (start_glyph_pos..end_glyph_pos).rev() {
1568 let g_w = word.glyphs[glyph_idx].width(font_size);
1569 if currently_used_width + glyphs_w + g_w > total_available_width {
1570 break;
1571 }
1572 glyphs_w += g_w;
1573 glyph_end = glyph_idx;
1574 }
1575 (glyph_end, glyphs_w)
1576 }
1577 }
1578
1579 #[inline]
1580 fn add_to_visual_line(
1581 &self,
1582 vl: &mut VisualLine,
1583 span_index: usize,
1584 start: WordGlyphPos,
1585 end: WordGlyphPos,
1586 width: f32,
1587 number_of_blanks: u32,
1588 ) {
1589 if end == start {
1590 return;
1591 }
1592
1593 vl.ranges.push(VlRange {
1594 span: span_index,
1595 start,
1596 end,
1597 level: self.spans[span_index].level,
1598 });
1599 vl.w += width;
1600 vl.spaces += number_of_blanks;
1601 }
1602
1603 fn remaining_content_exceeds(
1604 spans: &[ShapeSpan],
1605 font_size: f32,
1606 span_index: usize,
1607 word_idx: usize,
1608 word_count: usize,
1609 starting_word_index: usize,
1610 direction: LayoutDirection,
1611 congruent: bool,
1612 start_span: usize,
1613 span_count: usize,
1614 threshold: f32,
1615 ) -> bool {
1616 let mut acc: f32 = 0.0;
1617
1618 let word_range: Range<usize> = match (direction, congruent) {
1620 (LayoutDirection::Forward, true) => word_idx + 1..word_count,
1621 (LayoutDirection::Forward, false) => 0..word_idx,
1622 (LayoutDirection::Backward, true) => starting_word_index..word_idx,
1623 (LayoutDirection::Backward, false) => word_idx + 1..word_count,
1624 };
1625 for wi in word_range {
1626 acc += spans[span_index].words[wi].width(font_size);
1627 if acc > threshold {
1628 return true;
1629 }
1630 }
1631
1632 let span_range: Range<usize> = match direction {
1634 LayoutDirection::Forward => span_index + 1..span_count,
1635 LayoutDirection::Backward => start_span..span_index,
1636 };
1637 for si in span_range {
1638 for w in &spans[si].words {
1639 acc += w.width(font_size);
1640 if acc > threshold {
1641 return true;
1642 }
1643 }
1644 }
1645
1646 false
1647 }
1648
1649 #[inline]
1654 fn layout_spans(
1655 &self,
1656 current_visual_line: &mut VisualLine,
1657 font_size: f32,
1658 spans: &[ShapeSpan],
1659 start_opt: Option<SpanWordGlyphPos>,
1660 rtl: bool,
1661 width_opt: Option<f32>,
1662 ellipsize: Ellipsize,
1663 ellipsis_w: f32,
1664 direction: LayoutDirection,
1665 ) {
1666 let check_ellipsizing = matches!(ellipsize, Ellipsize::Start(_) | Ellipsize::End(_))
1667 && width_opt.is_some_and(|w| w.is_finite());
1668
1669 let max_width = width_opt.unwrap_or(f32::INFINITY);
1670 let span_count = spans.len();
1671
1672 let mut total_w: f32 = 0.0;
1673
1674 let start = if let Some(s) = start_opt {
1675 s
1676 } else {
1677 SpanWordGlyphPos::ZERO
1678 };
1679
1680 let span_indices: Vec<usize> = if matches!(direction, LayoutDirection::Forward) {
1681 (start.span..spans.len()).collect()
1682 } else {
1683 (start.span..spans.len()).rev().collect()
1684 };
1685
1686 'outer: for span_index in span_indices {
1687 let mut word_range_width = 0.;
1688 let mut number_of_blanks: u32 = 0;
1689
1690 let span = &spans[span_index];
1691 let word_count = span.words.len();
1692
1693 let starting_word_index = if span_index == start.span {
1694 start.word
1695 } else {
1696 0
1697 };
1698
1699 let congruent = rtl == span.level.is_rtl();
1700 let word_forward: bool = congruent == (direction == LayoutDirection::Forward);
1701
1702 let word_indices: Vec<usize> = match (direction, congruent, start_opt) {
1703 (LayoutDirection::Forward, true, _) => (starting_word_index..word_count).collect(),
1704 (LayoutDirection::Forward, false, Some(start)) => {
1705 if span_index == start.span {
1706 (0..start.word).rev().collect()
1707 } else {
1708 (0..word_count).rev().collect()
1709 }
1710 }
1711 (LayoutDirection::Forward, false, None) => (0..word_count).rev().collect(),
1712 (LayoutDirection::Backward, true, _) => {
1713 ((starting_word_index)..word_count).rev().collect()
1714 }
1715 (LayoutDirection::Backward, false, Some(start)) => {
1716 if span_index == start.span {
1717 if start.glyph > 0 {
1718 (0..(start.word + 1)).collect()
1719 } else {
1720 (0..(start.word)).collect()
1721 }
1722 } else {
1723 (0..word_count).collect()
1724 }
1725 }
1726 (LayoutDirection::Backward, false, None) => (0..span.words.len()).collect(),
1727 };
1728 for word_idx in word_indices {
1729 let word = &span.words[word_idx];
1730 let word_width = if span_index == start.span && word_idx == start.word {
1731 let (start_glyph_pos, end_glyph_pos) = Self::get_glyph_start_end(
1732 word, start, span_index, word_idx, direction, congruent,
1733 );
1734 let mut w = 0.;
1735 for glyph_idx in start_glyph_pos..end_glyph_pos {
1736 w += word.glyphs[glyph_idx].width(font_size);
1737 }
1738 w
1739 } else {
1740 word.width(font_size)
1741 };
1742
1743 let overflowing = {
1744 check_ellipsizing
1746 && (
1747 (total_w + word_range_width + word_width > max_width)
1749 || (Self::remaining_content_exceeds(
1750 spans,
1751 font_size,
1752 span_index,
1753 word_idx,
1754 word_count,
1755 starting_word_index,
1756 direction,
1757 congruent,
1758 start.span,
1759 span_count,
1760 ellipsis_w,
1761 ) && total_w + word_range_width + word_width + ellipsis_w
1762 > max_width)
1763 )
1764 };
1765
1766 if overflowing {
1767 let available = (max_width - ellipsis_w).max(0.0);
1769
1770 let (glyph_end, glyphs_w) = Self::fit_glyphs(
1771 word,
1772 font_size,
1773 start,
1774 span_index,
1775 word_idx,
1776 direction,
1777 congruent,
1778 total_w + word_range_width,
1779 available,
1780 word_forward,
1781 );
1782
1783 let (start_pos, end_pos) = if word_forward {
1784 if span_index == start.span {
1785 if !congruent {
1786 (WordGlyphPos::ZERO, WordGlyphPos::new(word_idx, glyph_end))
1787 } else {
1788 (
1789 start.word_glyph_pos(),
1790 WordGlyphPos::new(word_idx, glyph_end),
1791 )
1792 }
1793 } else {
1794 (WordGlyphPos::ZERO, WordGlyphPos::new(word_idx, glyph_end))
1795 }
1796 } else {
1797 let range_end = if span_index == start.span && !congruent {
1805 start.word_glyph_pos()
1806 } else {
1807 WordGlyphPos::new(span.words.len(), 0)
1808 };
1809 (WordGlyphPos::new(word_idx, glyph_end), range_end)
1810 };
1811 self.add_to_visual_line(
1812 current_visual_line,
1813 span_index,
1814 start_pos,
1815 end_pos,
1816 word_range_width + glyphs_w,
1817 number_of_blanks,
1818 );
1819
1820 current_visual_line.ellipsized = true;
1822 break 'outer;
1823 }
1824
1825 word_range_width += word_width;
1826 if word.blank {
1827 number_of_blanks += 1;
1828 }
1829
1830 if matches!(direction, LayoutDirection::Backward)
1832 && word_idx == start.word
1833 && span_index == start.span
1834 {
1835 let (start_pos, end_pos) = if word_forward {
1836 (WordGlyphPos::ZERO, start.word_glyph_pos())
1837 } else {
1838 (
1839 start.word_glyph_pos(),
1840 WordGlyphPos::new(span.words.len(), 0),
1841 )
1842 };
1843
1844 self.add_to_visual_line(
1845 current_visual_line,
1846 span_index,
1847 start_pos,
1848 end_pos,
1849 word_range_width,
1850 number_of_blanks,
1851 );
1852
1853 break 'outer;
1854 }
1855 }
1856
1857 total_w += word_range_width;
1860 let (start_pos, end_pos) = if congruent {
1861 if span_index == start.span {
1862 (
1863 start.word_glyph_pos(),
1864 WordGlyphPos::new(span.words.len(), 0),
1865 )
1866 } else {
1867 (WordGlyphPos::ZERO, WordGlyphPos::new(span.words.len(), 0))
1868 }
1869 } else if span_index == start.span {
1870 (WordGlyphPos::ZERO, start.word_glyph_pos())
1871 } else {
1872 (WordGlyphPos::ZERO, WordGlyphPos::new(span.words.len(), 0))
1873 };
1874
1875 self.add_to_visual_line(
1876 current_visual_line,
1877 span_index,
1878 start_pos,
1879 end_pos,
1880 word_range_width,
1881 number_of_blanks,
1882 );
1883 }
1884
1885 if matches!(direction, LayoutDirection::Backward) {
1886 current_visual_line.ranges.reverse();
1887 }
1888 }
1889
1890 fn layout_middle(
1891 &self,
1892 current_visual_line: &mut VisualLine,
1893 font_size: f32,
1894 spans: &[ShapeSpan],
1895 start_opt: Option<SpanWordGlyphPos>,
1896 rtl: bool,
1897 width: f32,
1898 ellipsize: Ellipsize,
1899 ellipsis_w: f32,
1900 ) {
1901 assert!(matches!(ellipsize, Ellipsize::Middle(_)));
1902
1903 {
1905 let mut test_line = VisualLine::default();
1906 self.layout_spans(
1907 &mut test_line,
1908 font_size,
1909 spans,
1910 start_opt,
1911 rtl,
1912 Some(width),
1913 Ellipsize::End(EllipsizeHeightLimit::Lines(1)),
1914 ellipsis_w,
1915 LayoutDirection::Forward,
1916 );
1917 if !test_line.ellipsized && test_line.w <= width {
1918 *current_visual_line = test_line;
1919 return;
1920 }
1921 }
1922
1923 let mut starting_line = VisualLine::default();
1924 self.layout_spans(
1925 &mut starting_line,
1926 font_size,
1927 spans,
1928 start_opt,
1929 rtl,
1930 Some(width / 2.0),
1931 Ellipsize::End(EllipsizeHeightLimit::Lines(1)),
1932 0., LayoutDirection::Forward,
1934 );
1935 let forward_pass_overflowed = starting_line.ellipsized;
1936 let end_range_opt = starting_line.ranges.last();
1937 match end_range_opt {
1938 Some(range) if forward_pass_overflowed => {
1939 let congruent = rtl == self.spans[range.span].level.is_rtl();
1940 let mut ending_line = VisualLine::default();
1942 let start = if congruent {
1943 SpanWordGlyphPos {
1944 span: range.span,
1945 word: range.end.word,
1946 glyph: range.end.glyph,
1947 }
1948 } else {
1949 SpanWordGlyphPos {
1950 span: range.span,
1951 word: range.start.word,
1952 glyph: range.start.glyph,
1953 }
1954 };
1955 self.layout_spans(
1956 &mut ending_line,
1957 font_size,
1958 spans,
1959 Some(start),
1960 rtl,
1961 Some((width - starting_line.w - ellipsis_w).max(0.0)),
1962 Ellipsize::Start(EllipsizeHeightLimit::Lines(1)),
1963 0., LayoutDirection::Backward,
1965 );
1966 let ellipsis_level = self.ellipsis_level_between(
1969 starting_line.ranges.last(),
1970 ending_line.ranges.first(),
1971 );
1972 starting_line
1973 .ranges
1974 .push(self.ellipsis_vlrange(ellipsis_level));
1975 starting_line.ranges.extend(ending_line.ranges);
1976 current_visual_line.ranges = starting_line.ranges;
1977 current_visual_line.ellipsized = true;
1978 current_visual_line.w = starting_line.w + ending_line.w + ellipsis_w;
1979 current_visual_line.spaces = starting_line.spaces + ending_line.spaces;
1980 }
1981 None if forward_pass_overflowed && width > ellipsis_w => {
1982 current_visual_line
1985 .ranges
1986 .push(self.ellipsis_vlrange(if self.rtl {
1987 unicode_bidi::Level::rtl()
1988 } else {
1989 unicode_bidi::Level::ltr()
1990 }));
1991 current_visual_line.ellipsized = true;
1992 current_visual_line.w = ellipsis_w;
1993 current_visual_line.spaces = 0;
1994 }
1995 _ => {
1996 current_visual_line.ranges = starting_line.ranges;
1998 current_visual_line.w = starting_line.w;
1999 current_visual_line.spaces = starting_line.spaces;
2000 current_visual_line.ellipsized = false;
2001 }
2002 }
2003 }
2004
2005 fn get_span_words(&self, span_index: usize) -> &[ShapeWord] {
2007 if span_index == ELLIPSIS_SPAN {
2008 &self
2009 .ellipsis_span
2010 .as_ref()
2011 .expect("ellipsis_span not set")
2012 .words
2013 } else {
2014 &self.spans[span_index].words
2015 }
2016 }
2017
2018 fn byte_range_of_vlrange(&self, r: &VlRange) -> Option<(usize, usize)> {
2019 debug_assert_ne!(r.span, ELLIPSIS_SPAN);
2020 let words = self.get_span_words(r.span);
2021 let mut min_byte = usize::MAX;
2022 let mut max_byte = 0usize;
2023 let end_word = r.end.word + usize::from(r.end.glyph != 0);
2024 for (i, word) in words.iter().enumerate().take(end_word).skip(r.start.word) {
2025 let included_glyphs = match (i == r.start.word, i == r.end.word) {
2026 (false, false) => &word.glyphs[..],
2027 (true, false) => &word.glyphs[r.start.glyph..],
2028 (false, true) => &word.glyphs[..r.end.glyph],
2029 (true, true) => &word.glyphs[r.start.glyph..r.end.glyph],
2030 };
2031 for glyph in included_glyphs {
2032 min_byte = min_byte.min(glyph.start);
2033 max_byte = max_byte.max(glyph.end);
2034 }
2035 }
2036 if min_byte <= max_byte {
2037 Some((min_byte, max_byte))
2038 } else {
2039 None
2040 }
2041 }
2042
2043 fn compute_elided_byte_range(
2044 &self,
2045 visual_line: &VisualLine,
2046 line_len: usize,
2047 ) -> Option<(usize, usize)> {
2048 if !visual_line.ellipsized {
2049 return None;
2050 }
2051 let ellipsis_idx = visual_line
2053 .ranges
2054 .iter()
2055 .position(|r| r.span == ELLIPSIS_SPAN)?;
2056
2057 let before_end = (0..ellipsis_idx)
2059 .rev()
2060 .find_map(|i| self.byte_range_of_vlrange(&visual_line.ranges[i]))
2061 .map(|(_, end)| end)
2062 .unwrap_or(0);
2063
2064 let after_start = (ellipsis_idx + 1..visual_line.ranges.len())
2066 .find_map(|i| self.byte_range_of_vlrange(&visual_line.ranges[i]))
2067 .map(|(start, _)| start)
2068 .unwrap_or(line_len);
2069
2070 Some((before_end, after_start))
2071 }
2072
2073 fn max_byte_offset(&self) -> usize {
2076 self.spans
2077 .iter()
2078 .flat_map(|span| span.words.iter())
2079 .flat_map(|word| word.glyphs.iter())
2080 .map(|g| g.end)
2081 .max()
2082 .unwrap_or(0)
2083 }
2084
2085 fn ellipsis_w(&self, font_size: f32) -> f32 {
2087 self.ellipsis_span
2088 .as_ref()
2089 .map_or(0.0, |s| s.words.iter().map(|w| w.width(font_size)).sum())
2090 }
2091
2092 fn ellipsis_vlrange(&self, level: unicode_bidi::Level) -> VlRange {
2094 VlRange {
2095 span: ELLIPSIS_SPAN,
2096 start: WordGlyphPos::ZERO,
2097 end: WordGlyphPos::new(1, 0),
2098 level,
2099 }
2100 }
2101
2102 fn ellipsis_level_between(
2105 &self,
2106 before: Option<&VlRange>,
2107 after: Option<&VlRange>,
2108 ) -> unicode_bidi::Level {
2109 match (before, after) {
2110 (Some(a), Some(b)) if a.level == b.level => a.level,
2111 (Some(a), None) => a.level,
2112 (None, Some(b)) => b.level,
2113 _ => {
2114 if self.rtl {
2115 unicode_bidi::Level::rtl()
2116 } else {
2117 unicode_bidi::Level::ltr()
2118 }
2119 }
2120 }
2121 }
2122
2123 fn layout_line(
2124 &self,
2125 current_visual_line: &mut VisualLine,
2126 font_size: f32,
2127 spans: &[ShapeSpan],
2128 start_opt: Option<SpanWordGlyphPos>,
2129 rtl: bool,
2130 width_opt: Option<f32>,
2131 ellipsize: Ellipsize,
2132 ) {
2133 let ellipsis_w = self.ellipsis_w(font_size);
2134
2135 match (ellipsize, width_opt) {
2136 (Ellipsize::Start(_), Some(_)) => {
2137 self.layout_spans(
2138 current_visual_line,
2139 font_size,
2140 spans,
2141 start_opt,
2142 rtl,
2143 width_opt,
2144 ellipsize,
2145 ellipsis_w,
2146 LayoutDirection::Backward,
2147 );
2148 if current_visual_line.ellipsized {
2150 let level =
2151 self.ellipsis_level_between(None, current_visual_line.ranges.first());
2152 current_visual_line
2153 .ranges
2154 .insert(0, self.ellipsis_vlrange(level));
2155 current_visual_line.w += ellipsis_w;
2156 }
2157 }
2158 (Ellipsize::Middle(_), Some(width)) => {
2159 self.layout_middle(
2160 current_visual_line,
2161 font_size,
2162 spans,
2163 start_opt,
2164 rtl,
2165 width,
2166 ellipsize,
2167 ellipsis_w,
2168 );
2169 }
2170 _ => {
2171 self.layout_spans(
2172 current_visual_line,
2173 font_size,
2174 spans,
2175 start_opt,
2176 rtl,
2177 width_opt,
2178 ellipsize,
2179 ellipsis_w,
2180 LayoutDirection::Forward,
2181 );
2182 if current_visual_line.ellipsized {
2184 let level =
2185 self.ellipsis_level_between(current_visual_line.ranges.last(), None);
2186 current_visual_line
2187 .ranges
2188 .push(self.ellipsis_vlrange(level));
2189 current_visual_line.w += ellipsis_w;
2190 }
2191 }
2192 }
2193
2194 if current_visual_line.ellipsized {
2197 let line_len = self.max_byte_offset();
2198 current_visual_line.elided_byte_range =
2199 self.compute_elided_byte_range(current_visual_line, line_len);
2200 }
2201 }
2202
2203 pub fn layout_to_buffer(
2204 &self,
2205 scratch: &mut ShapeBuffer,
2206 font_size: f32,
2207 width_opt: Option<f32>,
2208 wrap: Wrap,
2209 ellipsize: Ellipsize,
2210 align: Option<Align>,
2211 layout_lines: &mut Vec<LayoutLine>,
2212 match_mono_width: Option<f32>,
2213 hinting: Hinting,
2214 ) {
2215 let mut visual_lines = mem::take(&mut scratch.visual_lines);
2219 let mut cached_visual_lines = mem::take(&mut scratch.cached_visual_lines);
2220 cached_visual_lines.clear();
2221 cached_visual_lines.extend(visual_lines.drain(..).map(|mut l| {
2222 l.clear();
2223 l
2224 }));
2225
2226 let mut cached_glyph_sets = mem::take(&mut scratch.glyph_sets);
2228 cached_glyph_sets.clear();
2229 cached_glyph_sets.extend(layout_lines.drain(..).rev().map(|mut v| {
2230 v.glyphs.clear();
2231 v.glyphs
2232 }));
2233
2234 let mut current_visual_line = cached_visual_lines.pop().unwrap_or_default();
2239
2240 if wrap == Wrap::None {
2241 self.layout_line(
2242 &mut current_visual_line,
2243 font_size,
2244 &self.spans,
2245 None,
2246 self.rtl,
2247 width_opt,
2248 ellipsize,
2249 );
2250 } else {
2251 let mut total_line_height = 0.0;
2252 let mut total_line_count = 0;
2253 let max_line_count_opt = match ellipsize {
2254 Ellipsize::Start(EllipsizeHeightLimit::Lines(lines))
2255 | Ellipsize::Middle(EllipsizeHeightLimit::Lines(lines))
2256 | Ellipsize::End(EllipsizeHeightLimit::Lines(lines)) => Some(lines.max(1)),
2257 _ => None,
2258 };
2259 let max_height_opt = match ellipsize {
2260 Ellipsize::Start(EllipsizeHeightLimit::Height(height))
2261 | Ellipsize::Middle(EllipsizeHeightLimit::Height(height))
2262 | Ellipsize::End(EllipsizeHeightLimit::Height(height)) => Some(height),
2263 _ => None,
2264 };
2265 let line_height = self
2266 .metrics_opt
2267 .map_or_else(|| font_size, |m| m.line_height);
2268
2269 let try_ellipsize_last_line = |total_line_count: usize,
2270 total_line_height: f32,
2271 current_visual_line: &mut VisualLine,
2272 font_size: f32,
2273 start_opt: Option<SpanWordGlyphPos>,
2274 width_opt: Option<f32>,
2275 ellipsize: Ellipsize|
2276 -> bool {
2277 if max_line_count_opt == Some(total_line_count + 1)
2279 || max_height_opt.is_some_and(|max_height| {
2280 total_line_height + line_height * 2.0 > max_height
2281 })
2282 {
2283 self.layout_line(
2284 current_visual_line,
2285 font_size,
2286 &self.spans,
2287 start_opt,
2288 self.rtl,
2289 width_opt,
2290 ellipsize,
2291 );
2292 return true;
2293 }
2294 false
2295 };
2296
2297 if !try_ellipsize_last_line(
2298 total_line_count,
2299 total_line_height,
2300 &mut current_visual_line,
2301 font_size,
2302 None,
2303 width_opt,
2304 ellipsize,
2305 ) {
2306 'outer: for (span_index, span) in self.spans.iter().enumerate() {
2307 let mut word_range_width = 0.;
2308 let mut width_before_last_blank = 0.;
2309 let mut number_of_blanks: u32 = 0;
2310
2311 if self.rtl != span.level.is_rtl() {
2313 let mut fitting_start = WordGlyphPos::new(span.words.len(), 0);
2315 for (i, word) in span.words.iter().enumerate().rev() {
2316 let word_width = word.width(font_size);
2317 if current_visual_line.w + (word_range_width + word_width)
2321 <= width_opt.unwrap_or(f32::INFINITY)
2322 || (word.blank
2325 && (current_visual_line.w + word_range_width) <= width_opt.unwrap_or(f32::INFINITY))
2326 {
2327 if word.blank {
2329 number_of_blanks += 1;
2330 width_before_last_blank = word_range_width;
2331 }
2332 word_range_width += word_width;
2333 } else if wrap == Wrap::Glyph
2334 || (wrap == Wrap::WordOrGlyph && word_width > width_opt.unwrap_or(f32::INFINITY))
2336 {
2337 if word_range_width > 0.
2339 && wrap == Wrap::WordOrGlyph
2340 && word_width > width_opt.unwrap_or(f32::INFINITY)
2341 {
2342 self.add_to_visual_line(
2343 &mut current_visual_line,
2344 span_index,
2345 WordGlyphPos::new(i + 1, 0),
2346 fitting_start,
2347 word_range_width,
2348 number_of_blanks,
2349 );
2350
2351 visual_lines.push(current_visual_line);
2352 current_visual_line =
2353 cached_visual_lines.pop().unwrap_or_default();
2354
2355 number_of_blanks = 0;
2356 word_range_width = 0.;
2357
2358 fitting_start = WordGlyphPos::new(i, 0);
2359 total_line_count += 1;
2360 total_line_height += line_height;
2361 if try_ellipsize_last_line(
2362 total_line_count,
2363 total_line_height,
2364 &mut current_visual_line,
2365 font_size,
2366 Some(SpanWordGlyphPos::with_wordglyph(
2367 span_index,
2368 fitting_start,
2369 )),
2370 width_opt,
2371 ellipsize,
2372 ) {
2373 break 'outer;
2374 }
2375 }
2376
2377 for (glyph_i, glyph) in word.glyphs.iter().enumerate().rev() {
2378 let glyph_width = glyph.width(font_size);
2379 if current_visual_line.w + (word_range_width + glyph_width)
2380 <= width_opt.unwrap_or(f32::INFINITY)
2381 {
2382 word_range_width += glyph_width;
2383 } else {
2384 self.add_to_visual_line(
2385 &mut current_visual_line,
2386 span_index,
2387 WordGlyphPos::new(i, glyph_i + 1),
2388 fitting_start,
2389 word_range_width,
2390 number_of_blanks,
2391 );
2392 visual_lines.push(current_visual_line);
2393 current_visual_line =
2394 cached_visual_lines.pop().unwrap_or_default();
2395
2396 number_of_blanks = 0;
2397 word_range_width = glyph_width;
2398 fitting_start = WordGlyphPos::new(i, glyph_i + 1);
2399 total_line_count += 1;
2400 total_line_height += line_height;
2401 if try_ellipsize_last_line(
2402 total_line_count,
2403 total_line_height,
2404 &mut current_visual_line,
2405 font_size,
2406 Some(SpanWordGlyphPos::with_wordglyph(
2407 span_index,
2408 fitting_start,
2409 )),
2410 width_opt,
2411 ellipsize,
2412 ) {
2413 break 'outer;
2414 }
2415 }
2416 }
2417 } else {
2418 if word_range_width > 0. {
2422 let trailing_blank = span
2425 .words
2426 .get(i + 1)
2427 .is_some_and(|previous_word| previous_word.blank);
2428
2429 if trailing_blank {
2430 number_of_blanks = number_of_blanks.saturating_sub(1);
2431 self.add_to_visual_line(
2432 &mut current_visual_line,
2433 span_index,
2434 WordGlyphPos::new(i + 2, 0),
2435 fitting_start,
2436 width_before_last_blank,
2437 number_of_blanks,
2438 );
2439 } else {
2440 self.add_to_visual_line(
2441 &mut current_visual_line,
2442 span_index,
2443 WordGlyphPos::new(i + 1, 0),
2444 fitting_start,
2445 word_range_width,
2446 number_of_blanks,
2447 );
2448 }
2449 }
2450
2451 if !current_visual_line.ranges.is_empty() {
2454 visual_lines.push(current_visual_line);
2455 current_visual_line =
2456 cached_visual_lines.pop().unwrap_or_default();
2457 number_of_blanks = 0;
2458 total_line_count += 1;
2459 total_line_height += line_height;
2460
2461 if try_ellipsize_last_line(
2462 total_line_count,
2463 total_line_height,
2464 &mut current_visual_line,
2465 font_size,
2466 Some(SpanWordGlyphPos::with_wordglyph(
2467 span_index,
2468 if word.blank {
2469 WordGlyphPos::new(i, 0)
2470 } else {
2471 WordGlyphPos::new(i + 1, 0)
2472 },
2473 )),
2474 width_opt,
2475 ellipsize,
2476 ) {
2477 break 'outer;
2478 }
2479 }
2480
2481 if word.blank {
2482 word_range_width = 0.;
2483 fitting_start = WordGlyphPos::new(i, 0);
2484 } else {
2485 word_range_width = word_width;
2486 fitting_start = WordGlyphPos::new(i + 1, 0);
2487 }
2488 }
2489 }
2490 self.add_to_visual_line(
2491 &mut current_visual_line,
2492 span_index,
2493 WordGlyphPos::new(0, 0),
2494 fitting_start,
2495 word_range_width,
2496 number_of_blanks,
2497 );
2498 } else {
2499 let mut fitting_start = WordGlyphPos::ZERO;
2501 for (i, word) in span.words.iter().enumerate() {
2502 let word_width = word.width(font_size);
2503 if current_visual_line.w + (word_range_width + word_width)
2504 <= width_opt.unwrap_or(f32::INFINITY)
2505 || (word.blank
2508 && (current_visual_line.w + word_range_width) <= width_opt.unwrap_or(f32::INFINITY))
2509 {
2510 if word.blank {
2512 number_of_blanks += 1;
2513 width_before_last_blank = word_range_width;
2514 }
2515 word_range_width += word_width;
2516 } else if wrap == Wrap::Glyph
2517 || (wrap == Wrap::WordOrGlyph && word_width > width_opt.unwrap_or(f32::INFINITY))
2519 {
2520 if word_range_width > 0.
2522 && wrap == Wrap::WordOrGlyph
2523 && word_width > width_opt.unwrap_or(f32::INFINITY)
2524 {
2525 self.add_to_visual_line(
2526 &mut current_visual_line,
2527 span_index,
2528 fitting_start,
2529 WordGlyphPos::new(i, 0),
2530 word_range_width,
2531 number_of_blanks,
2532 );
2533
2534 visual_lines.push(current_visual_line);
2535 current_visual_line =
2536 cached_visual_lines.pop().unwrap_or_default();
2537
2538 number_of_blanks = 0;
2539 word_range_width = 0.;
2540
2541 fitting_start = WordGlyphPos::new(i, 0);
2542 total_line_count += 1;
2543 total_line_height += line_height;
2544 if try_ellipsize_last_line(
2545 total_line_count,
2546 total_line_height,
2547 &mut current_visual_line,
2548 font_size,
2549 Some(SpanWordGlyphPos::with_wordglyph(
2550 span_index,
2551 fitting_start,
2552 )),
2553 width_opt,
2554 ellipsize,
2555 ) {
2556 break 'outer;
2557 }
2558 }
2559
2560 for (glyph_i, glyph) in word.glyphs.iter().enumerate() {
2561 let glyph_width = glyph.width(font_size);
2562 if current_visual_line.w + (word_range_width + glyph_width)
2563 <= width_opt.unwrap_or(f32::INFINITY)
2564 {
2565 word_range_width += glyph_width;
2566 } else {
2567 self.add_to_visual_line(
2568 &mut current_visual_line,
2569 span_index,
2570 fitting_start,
2571 WordGlyphPos::new(i, glyph_i),
2572 word_range_width,
2573 number_of_blanks,
2574 );
2575 visual_lines.push(current_visual_line);
2576 current_visual_line =
2577 cached_visual_lines.pop().unwrap_or_default();
2578
2579 number_of_blanks = 0;
2580 word_range_width = glyph_width;
2581 fitting_start = WordGlyphPos::new(i, glyph_i);
2582 total_line_count += 1;
2583 total_line_height += line_height;
2584 if try_ellipsize_last_line(
2585 total_line_count,
2586 total_line_height,
2587 &mut current_visual_line,
2588 font_size,
2589 Some(SpanWordGlyphPos::with_wordglyph(
2590 span_index,
2591 fitting_start,
2592 )),
2593 width_opt,
2594 ellipsize,
2595 ) {
2596 break 'outer;
2597 }
2598 }
2599 }
2600 } else {
2601 if word_range_width > 0. {
2605 let trailing_blank = i > 0 && span.words[i - 1].blank;
2608
2609 if trailing_blank {
2610 number_of_blanks = number_of_blanks.saturating_sub(1);
2611 self.add_to_visual_line(
2612 &mut current_visual_line,
2613 span_index,
2614 fitting_start,
2615 WordGlyphPos::new(i - 1, 0),
2616 width_before_last_blank,
2617 number_of_blanks,
2618 );
2619 } else {
2620 self.add_to_visual_line(
2621 &mut current_visual_line,
2622 span_index,
2623 fitting_start,
2624 WordGlyphPos::new(i, 0),
2625 word_range_width,
2626 number_of_blanks,
2627 );
2628 }
2629 }
2630
2631 if !current_visual_line.ranges.is_empty() {
2632 visual_lines.push(current_visual_line);
2633 current_visual_line =
2634 cached_visual_lines.pop().unwrap_or_default();
2635 number_of_blanks = 0;
2636 total_line_count += 1;
2637 total_line_height += line_height;
2638 if try_ellipsize_last_line(
2639 total_line_count,
2640 total_line_height,
2641 &mut current_visual_line,
2642 font_size,
2643 Some(SpanWordGlyphPos::with_wordglyph(
2644 span_index,
2645 if i > 0 && span.words[i - 1].blank {
2646 WordGlyphPos::new(i - 1, 0)
2647 } else {
2648 WordGlyphPos::new(i, 0)
2649 },
2650 )),
2651 width_opt,
2652 ellipsize,
2653 ) {
2654 break 'outer;
2655 }
2656 }
2657
2658 if word.blank {
2659 word_range_width = 0.;
2660 fitting_start = WordGlyphPos::new(i + 1, 0);
2661 } else {
2662 word_range_width = word_width;
2663 fitting_start = WordGlyphPos::new(i, 0);
2664 }
2665 }
2666 }
2667 self.add_to_visual_line(
2668 &mut current_visual_line,
2669 span_index,
2670 fitting_start,
2671 WordGlyphPos::new(span.words.len(), 0),
2672 word_range_width,
2673 number_of_blanks,
2674 );
2675 }
2676 }
2677 }
2678 }
2679
2680 if current_visual_line.ranges.is_empty() {
2681 current_visual_line.clear();
2682 cached_visual_lines.push(current_visual_line);
2683 } else {
2684 visual_lines.push(current_visual_line);
2685 }
2686
2687 let align = align.unwrap_or(if self.rtl { Align::Right } else { Align::Left });
2689
2690 let line_width = width_opt.unwrap_or_else(|| {
2691 let mut width: f32 = 0.0;
2692 for visual_line in &visual_lines {
2693 width = width.max(visual_line.w);
2694 }
2695 width
2696 });
2697
2698 let start_x = if self.rtl { line_width } else { 0.0 };
2699
2700 let number_of_visual_lines = visual_lines.len();
2701 for (index, visual_line) in visual_lines.iter().enumerate() {
2702 if visual_line.ranges.is_empty() {
2703 continue;
2704 }
2705
2706 let new_order = self.reorder(&visual_line.ranges);
2707
2708 let mut glyphs = cached_glyph_sets
2709 .pop()
2710 .unwrap_or_else(|| Vec::with_capacity(1));
2711 let mut x = start_x;
2712 let mut y = 0.;
2713 let mut max_ascent: f32 = 0.;
2714 let mut max_descent: f32 = 0.;
2715 let alignment_correction = match (align, self.rtl) {
2716 (Align::Left, true) => (line_width - visual_line.w).max(0.),
2717 (Align::Left, false) => 0.,
2718 (Align::Right, true) => 0.,
2719 (Align::Right, false) => (line_width - visual_line.w).max(0.),
2720 (Align::Center, _) => (line_width - visual_line.w).max(0.) / 2.0,
2721 (Align::End, _) => (line_width - visual_line.w).max(0.),
2722 (Align::Justified, _) => 0.,
2723 };
2724
2725 if self.rtl {
2726 x -= alignment_correction;
2727 } else {
2728 x += alignment_correction;
2729 }
2730
2731 if hinting == Hinting::Enabled {
2732 x = x.round();
2733 }
2734
2735 let justification_expansion = if matches!(align, Align::Justified)
2751 && visual_line.spaces > 0
2752 && index != number_of_visual_lines - 1
2754 {
2755 (line_width - visual_line.w) / visual_line.spaces as f32
2756 } else {
2757 0.
2758 };
2759
2760 let elided_byte_range = if visual_line.ellipsized {
2761 visual_line.elided_byte_range
2762 } else {
2763 None
2764 };
2765
2766 let mut decorations: Vec<DecorationSpan> = Vec::new();
2767
2768 let process_range = |range: Range<usize>,
2769 x: &mut f32,
2770 y: &mut f32,
2771 glyphs: &mut Vec<LayoutGlyph>,
2772 decorations: &mut Vec<DecorationSpan>,
2773 max_ascent: &mut f32,
2774 max_descent: &mut f32| {
2775 for r in visual_line.ranges[range.clone()].iter() {
2776 let is_ellipsis = r.span == ELLIPSIS_SPAN;
2777 let span_words = self.get_span_words(r.span);
2778 let deco_spans: &[(Range<usize>, GlyphDecorationData)] = if is_ellipsis {
2779 &[]
2780 } else {
2781 &self.spans[r.span].decoration_spans
2782 };
2783 let mut deco_cursor: usize = 0;
2786 for i in r.start.word..r.end.word + usize::from(r.end.glyph != 0) {
2788 let word = &span_words[i];
2789 let included_glyphs = match (i == r.start.word, i == r.end.word) {
2790 (false, false) => &word.glyphs[..],
2791 (true, false) => &word.glyphs[r.start.glyph..],
2792 (false, true) => &word.glyphs[..r.end.glyph],
2793 (true, true) => &word.glyphs[r.start.glyph..r.end.glyph],
2794 };
2795
2796 for glyph in included_glyphs {
2797 let font_size = glyph.metrics_opt.map_or(font_size, |x| x.font_size);
2799
2800 let match_mono_em_width = match_mono_width.map(|w| w / font_size);
2801
2802 let glyph_font_size = match (
2803 match_mono_em_width,
2804 glyph.font_monospace_em_width,
2805 ) {
2806 (Some(match_em_width), Some(glyph_em_width))
2807 if glyph_em_width != match_em_width =>
2808 {
2809 let glyph_to_match_factor = glyph_em_width / match_em_width;
2810 let glyph_font_size = math::roundf(glyph_to_match_factor)
2811 .max(1.0)
2812 / glyph_to_match_factor
2813 * font_size;
2814 log::trace!(
2815 "Adjusted glyph font size ({font_size} => {glyph_font_size})"
2816 );
2817 glyph_font_size
2818 }
2819 _ => font_size,
2820 };
2821
2822 let mut x_advance = glyph_font_size.mul_add(
2823 glyph.x_advance,
2824 if word.blank {
2825 justification_expansion
2826 } else {
2827 0.0
2828 },
2829 );
2830 if let Some(match_em_width) = match_mono_em_width {
2831 x_advance = ((x_advance / match_em_width).round()) * match_em_width;
2833 }
2834 if hinting == Hinting::Enabled {
2835 x_advance = x_advance.round();
2836 }
2837 if self.rtl {
2838 *x -= x_advance;
2839 }
2840 let y_advance = glyph_font_size * glyph.y_advance;
2841 let mut layout_glyph = glyph.layout(
2842 glyph_font_size,
2843 glyph.metrics_opt.map(|x| x.line_height),
2844 *x,
2845 *y,
2846 x_advance,
2847 r.level,
2848 );
2849 if is_ellipsis {
2854 if let Some((elided_start, elided_end)) = elided_byte_range {
2855 let boundary = if elided_start == 0 {
2861 elided_end
2862 } else {
2863 elided_start
2864 };
2865 layout_glyph.start = boundary;
2866 layout_glyph.end = boundary;
2867 }
2868 }
2869 glyphs.push(layout_glyph);
2870
2871 if deco_cursor >= deco_spans.len()
2872 || glyph.start < deco_spans[deco_cursor].0.start
2873 {
2874 deco_cursor = 0;
2875 }
2876 while deco_cursor < deco_spans.len()
2877 && deco_spans[deco_cursor].0.end <= glyph.start
2878 {
2879 deco_cursor += 1;
2880 }
2881 let glyph_deco = deco_spans
2882 .get(deco_cursor)
2883 .filter(|(range, _)| glyph.start >= range.start);
2884 let glyph_idx = glyphs.len() - 1;
2885 let extends = matches!(
2886 (decorations.last(), &glyph_deco),
2887 (Some(span), Some((_, d))) if span.data == *d
2888 );
2889 if extends {
2890 if let Some(last) = decorations.last_mut() {
2891 last.glyph_range.end = glyph_idx + 1;
2892 }
2893 } else if let Some((_, d)) = glyph_deco {
2894 decorations.push(DecorationSpan {
2895 glyph_range: glyph_idx..glyph_idx + 1,
2896 data: d.clone(),
2897 color_opt: glyphs[glyph_idx].color_opt,
2898 font_size: glyphs[glyph_idx].font_size,
2899 });
2900 }
2901 if !self.rtl {
2902 *x += x_advance;
2903 }
2904 *y += y_advance;
2905 *max_ascent = max_ascent.max(glyph_font_size * glyph.ascent);
2906 *max_descent = max_descent.max(glyph_font_size * glyph.descent);
2907 }
2908 }
2909 }
2910 };
2911
2912 if self.rtl {
2913 for range in new_order.into_iter().rev() {
2914 process_range(
2915 range,
2916 &mut x,
2917 &mut y,
2918 &mut glyphs,
2919 &mut decorations,
2920 &mut max_ascent,
2921 &mut max_descent,
2922 );
2923 }
2924 } else {
2925 for range in new_order {
2927 process_range(
2928 range,
2929 &mut x,
2930 &mut y,
2931 &mut glyphs,
2932 &mut decorations,
2933 &mut max_ascent,
2934 &mut max_descent,
2935 );
2936 }
2937 }
2938
2939 let mut line_height_opt: Option<f32> = None;
2940 for glyph in &glyphs {
2941 if let Some(glyph_line_height) = glyph.line_height_opt {
2942 line_height_opt = line_height_opt
2943 .map_or(Some(glyph_line_height), |line_height| {
2944 Some(line_height.max(glyph_line_height))
2945 });
2946 }
2947 }
2948
2949 layout_lines.push(LayoutLine {
2950 w: if align != Align::Justified {
2951 visual_line.w
2952 } else if self.rtl {
2953 start_x - x
2954 } else {
2955 x
2956 },
2957 max_ascent,
2958 max_descent,
2959 line_height_opt,
2960 glyphs,
2961 decorations,
2962 });
2963 }
2964
2965 if layout_lines.is_empty() {
2967 layout_lines.push(LayoutLine {
2968 w: 0.0,
2969 max_ascent: 0.0,
2970 max_descent: 0.0,
2971 line_height_opt: self.metrics_opt.map(|x| x.line_height),
2972 glyphs: Vec::default(),
2973 decorations: Vec::new(),
2974 });
2975 }
2976
2977 scratch.visual_lines = visual_lines;
2979 scratch.visual_lines.append(&mut cached_visual_lines);
2980 scratch.cached_visual_lines = cached_visual_lines;
2981 scratch.glyph_sets = cached_glyph_sets;
2982 }
2983}