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 self.ellipsis_span = None;
1269
1270 let mut spans = mem::take(&mut self.spans);
1271
1272 let mut cached_spans = mem::take(&mut font_system.shape_buffer.spans);
1274 cached_spans.clear();
1275 cached_spans.extend(spans.drain(..).rev());
1276
1277 let bidi = unicode_bidi::BidiInfo::new(line, None);
1278 let rtl = if bidi.paragraphs.is_empty() {
1279 false
1280 } else {
1281 bidi.paragraphs[0].level.is_rtl()
1282 };
1283
1284 log::trace!("Line {}: '{}'", if rtl { "RTL" } else { "LTR" }, line);
1285
1286 for para_info in &bidi.paragraphs {
1287 let line_rtl = para_info.level.is_rtl();
1288 assert_eq!(line_rtl, rtl);
1289
1290 let line_range = para_info.range.clone();
1291 let levels = Self::adjust_levels(&unicode_bidi::Paragraph::new(&bidi, para_info));
1292
1293 let mut start = line_range.start;
1296 let mut run_level = levels[start];
1297 spans.reserve(line_range.end - start + 1);
1298
1299 for (i, &new_level) in levels
1300 .iter()
1301 .enumerate()
1302 .take(line_range.end)
1303 .skip(start + 1)
1304 {
1305 if new_level != run_level {
1306 let mut span = cached_spans.pop().unwrap_or_else(ShapeSpan::empty);
1308 span.build(
1309 font_system,
1310 line,
1311 attrs_list,
1312 start..i,
1313 line_rtl,
1314 run_level,
1315 shaping,
1316 );
1317 spans.push(span);
1318 start = i;
1319 run_level = new_level;
1320 }
1321 }
1322 let mut span = cached_spans.pop().unwrap_or_else(ShapeSpan::empty);
1323 span.build(
1324 font_system,
1325 line,
1326 attrs_list,
1327 start..line_range.end,
1328 line_rtl,
1329 run_level,
1330 shaping,
1331 );
1332 spans.push(span);
1333 }
1334
1335 let mut x = 0.0;
1337 for span in &mut spans {
1338 for word in &mut span.words {
1339 for glyph in &mut word.glyphs {
1340 if line.get(glyph.start..glyph.end) == Some("\t") {
1341 let tab_x_advance = f32::from(tab_width) * glyph.x_advance;
1343 let tab_stop = (math::floorf(x / tab_x_advance) + 1.0) * tab_x_advance;
1344 glyph.x_advance = tab_stop - x;
1345 }
1346 x += glyph.x_advance;
1347 }
1348 }
1349 }
1350
1351 self.rtl = rtl;
1352 self.spans = spans;
1353 self.metrics_opt = attrs_list.defaults().metrics_opt.map(Into::into);
1354
1355 self.ellipsis_span.get_or_insert_with(|| {
1356 let attrs = if attrs_list.spans.is_empty() {
1357 attrs_list.defaults()
1358 } else {
1359 attrs_list.get_span(0) };
1363 let mut glyphs = shape_ellipsis(font_system, &attrs, shaping, rtl);
1364 if rtl {
1365 glyphs.reverse();
1366 }
1367 let word = ShapeWord {
1368 blank: false,
1369 glyphs,
1370 };
1371 let level = if rtl {
1374 unicode_bidi::Level::rtl()
1375 } else {
1376 unicode_bidi::Level::ltr()
1377 };
1378 ShapeSpan {
1379 level,
1380 words: vec![word],
1381 decoration_spans: Vec::new(),
1382 }
1383 });
1384
1385 font_system.shape_buffer.spans = cached_spans;
1387 }
1388
1389 fn adjust_levels(para: &unicode_bidi::Paragraph) -> Vec<unicode_bidi::Level> {
1391 use unicode_bidi::BidiClass::{B, BN, FSI, LRE, LRI, LRO, PDF, PDI, RLE, RLI, RLO, S, WS};
1392 let text = para.info.text;
1393 let levels = ¶.info.levels;
1394 let original_classes = ¶.info.original_classes;
1395
1396 let mut levels = levels.clone();
1397 let line_classes = &original_classes[..];
1398 let line_levels = &mut levels[..];
1399
1400 let mut reset_from: Option<usize> = Some(0);
1403 let mut reset_to: Option<usize> = None;
1404 for (i, c) in text.char_indices() {
1405 match line_classes[i] {
1406 RLE | LRE | RLO | LRO | PDF | BN => {}
1408 B | S => {
1410 assert_eq!(reset_to, None);
1411 reset_to = Some(i + c.len_utf8());
1412 if reset_from.is_none() {
1413 reset_from = Some(i);
1414 }
1415 }
1416 WS | FSI | LRI | RLI | PDI => {
1418 if reset_from.is_none() {
1419 reset_from = Some(i);
1420 }
1421 }
1422 _ => {
1423 reset_from = None;
1424 }
1425 }
1426 if let (Some(from), Some(to)) = (reset_from, reset_to) {
1427 for level in &mut line_levels[from..to] {
1428 *level = para.para.level;
1429 }
1430 reset_from = None;
1431 reset_to = None;
1432 }
1433 }
1434 if let Some(from) = reset_from {
1435 for level in &mut line_levels[from..] {
1436 *level = para.para.level;
1437 }
1438 }
1439 levels
1440 }
1441
1442 fn reorder(&self, line_range: &[VlRange]) -> Vec<Range<usize>> {
1444 let line: Vec<unicode_bidi::Level> = line_range.iter().map(|range| range.level).collect();
1445 let count = line.len();
1446 if count == 0 {
1447 return Vec::new();
1448 }
1449
1450 let mut elements: Vec<Range<usize>> = (0..count).map(|i| i..i + 1).collect();
1454
1455 let mut min_level = line[0];
1456 let mut max_level = line[0];
1457 for &level in &line[1..] {
1458 min_level = min(min_level, level);
1459 max_level = max(max_level, level);
1460 }
1461
1462 min_level = min_level.new_lowest_ge_rtl().expect("Level error");
1467
1468 while max_level >= min_level {
1469 let mut seq_start = 0;
1471 while seq_start < count {
1472 if line[elements[seq_start].start] < max_level {
1473 seq_start += 1;
1474 continue;
1475 }
1476
1477 let mut seq_end = seq_start + 1;
1479 while seq_end < count {
1480 if line[elements[seq_end].start] < max_level {
1481 break;
1482 }
1483 seq_end += 1;
1484 }
1485
1486 elements[seq_start..seq_end].reverse();
1488
1489 seq_start = seq_end;
1490 }
1491 max_level
1492 .lower(1)
1493 .expect("Lowering embedding level below zero");
1494 }
1495
1496 elements
1497 }
1498
1499 pub fn layout(
1500 &self,
1501 font_size: f32,
1502 width_opt: Option<f32>,
1503 wrap: Wrap,
1504 align: Option<Align>,
1505 match_mono_width: Option<f32>,
1506 hinting: Hinting,
1507 ) -> Vec<LayoutLine> {
1508 let mut lines = Vec::with_capacity(1);
1509 let mut scratch = ShapeBuffer::default();
1510 self.layout_to_buffer(
1511 &mut scratch,
1512 font_size,
1513 width_opt,
1514 wrap,
1515 Ellipsize::None,
1516 align,
1517 &mut lines,
1518 match_mono_width,
1519 hinting,
1520 );
1521 lines
1522 }
1523
1524 fn get_glyph_start_end(
1525 word: &ShapeWord,
1526 start: SpanWordGlyphPos,
1527 span_index: usize,
1528 word_idx: usize,
1529 _direction: LayoutDirection,
1530 congruent: bool,
1531 ) -> (usize, usize) {
1532 if span_index != start.span || word_idx != start.word {
1533 return (0, word.glyphs.len());
1534 }
1535 let (start_glyph_pos, end_glyph_pos) = if congruent {
1536 (start.glyph, word.glyphs.len())
1537 } else {
1538 (0, start.glyph)
1539 };
1540 (start_glyph_pos, end_glyph_pos)
1541 }
1542
1543 fn fit_glyphs(
1544 word: &ShapeWord,
1545 font_size: f32,
1546 start: SpanWordGlyphPos,
1547 span_index: usize,
1548 word_idx: usize,
1549 direction: LayoutDirection,
1550 congruent: bool,
1551 currently_used_width: f32,
1552 total_available_width: f32,
1553 forward: bool,
1554 ) -> (usize, f32) {
1555 let mut glyphs_w = 0.0;
1556 let (start_glyph_pos, end_glyph_pos) =
1557 Self::get_glyph_start_end(word, start, span_index, word_idx, direction, congruent);
1558
1559 if forward {
1560 let mut glyph_end = start_glyph_pos;
1561 for glyph_idx in start_glyph_pos..end_glyph_pos {
1562 let g_w = word.glyphs[glyph_idx].width(font_size);
1563 if currently_used_width + glyphs_w + g_w > total_available_width {
1564 break;
1565 }
1566 glyphs_w += g_w;
1567 glyph_end = glyph_idx + 1;
1568 }
1569 (glyph_end, glyphs_w)
1570 } else {
1571 let mut glyph_end = word.glyphs.len();
1572 for glyph_idx in (start_glyph_pos..end_glyph_pos).rev() {
1573 let g_w = word.glyphs[glyph_idx].width(font_size);
1574 if currently_used_width + glyphs_w + g_w > total_available_width {
1575 break;
1576 }
1577 glyphs_w += g_w;
1578 glyph_end = glyph_idx;
1579 }
1580 (glyph_end, glyphs_w)
1581 }
1582 }
1583
1584 #[inline]
1585 fn add_to_visual_line(
1586 &self,
1587 vl: &mut VisualLine,
1588 span_index: usize,
1589 start: WordGlyphPos,
1590 end: WordGlyphPos,
1591 width: f32,
1592 number_of_blanks: u32,
1593 ) {
1594 if end == start {
1595 return;
1596 }
1597
1598 vl.ranges.push(VlRange {
1599 span: span_index,
1600 start,
1601 end,
1602 level: self.spans[span_index].level,
1603 });
1604 vl.w += width;
1605 vl.spaces += number_of_blanks;
1606 }
1607
1608 fn remaining_content_exceeds(
1609 spans: &[ShapeSpan],
1610 font_size: f32,
1611 span_index: usize,
1612 word_idx: usize,
1613 word_count: usize,
1614 starting_word_index: usize,
1615 direction: LayoutDirection,
1616 congruent: bool,
1617 start_span: usize,
1618 span_count: usize,
1619 threshold: f32,
1620 ) -> bool {
1621 let mut acc: f32 = 0.0;
1622
1623 let word_range: Range<usize> = match (direction, congruent) {
1625 (LayoutDirection::Forward, true) => word_idx + 1..word_count,
1626 (LayoutDirection::Forward, false) => 0..word_idx,
1627 (LayoutDirection::Backward, true) => starting_word_index..word_idx,
1628 (LayoutDirection::Backward, false) => word_idx + 1..word_count,
1629 };
1630 for wi in word_range {
1631 acc += spans[span_index].words[wi].width(font_size);
1632 if acc > threshold {
1633 return true;
1634 }
1635 }
1636
1637 let span_range: Range<usize> = match direction {
1639 LayoutDirection::Forward => span_index + 1..span_count,
1640 LayoutDirection::Backward => start_span..span_index,
1641 };
1642 for si in span_range {
1643 for w in &spans[si].words {
1644 acc += w.width(font_size);
1645 if acc > threshold {
1646 return true;
1647 }
1648 }
1649 }
1650
1651 false
1652 }
1653
1654 #[inline]
1659 fn layout_spans(
1660 &self,
1661 current_visual_line: &mut VisualLine,
1662 font_size: f32,
1663 spans: &[ShapeSpan],
1664 start_opt: Option<SpanWordGlyphPos>,
1665 rtl: bool,
1666 width_opt: Option<f32>,
1667 ellipsize: Ellipsize,
1668 ellipsis_w: f32,
1669 direction: LayoutDirection,
1670 ) {
1671 let check_ellipsizing = matches!(ellipsize, Ellipsize::Start(_) | Ellipsize::End(_))
1672 && width_opt.is_some_and(|w| w.is_finite());
1673
1674 let max_width = width_opt.unwrap_or(f32::INFINITY);
1675 let span_count = spans.len();
1676
1677 let mut total_w: f32 = 0.0;
1678
1679 let start = if let Some(s) = start_opt {
1680 s
1681 } else {
1682 SpanWordGlyphPos::ZERO
1683 };
1684
1685 let span_indices: Vec<usize> = if matches!(direction, LayoutDirection::Forward) {
1686 (start.span..spans.len()).collect()
1687 } else {
1688 (start.span..spans.len()).rev().collect()
1689 };
1690
1691 'outer: for span_index in span_indices {
1692 let mut word_range_width = 0.;
1693 let mut number_of_blanks: u32 = 0;
1694
1695 let span = &spans[span_index];
1696 let word_count = span.words.len();
1697
1698 let starting_word_index = if span_index == start.span {
1699 start.word
1700 } else {
1701 0
1702 };
1703
1704 let congruent = rtl == span.level.is_rtl();
1705 let word_forward: bool = congruent == (direction == LayoutDirection::Forward);
1706
1707 let word_indices: Vec<usize> = match (direction, congruent, start_opt) {
1708 (LayoutDirection::Forward, true, _) => (starting_word_index..word_count).collect(),
1709 (LayoutDirection::Forward, false, Some(start)) => {
1710 if span_index == start.span {
1711 (0..start.word).rev().collect()
1712 } else {
1713 (0..word_count).rev().collect()
1714 }
1715 }
1716 (LayoutDirection::Forward, false, None) => (0..word_count).rev().collect(),
1717 (LayoutDirection::Backward, true, _) => {
1718 ((starting_word_index)..word_count).rev().collect()
1719 }
1720 (LayoutDirection::Backward, false, Some(start)) => {
1721 if span_index == start.span {
1722 if start.glyph > 0 {
1723 (0..(start.word + 1)).collect()
1724 } else {
1725 (0..(start.word)).collect()
1726 }
1727 } else {
1728 (0..word_count).collect()
1729 }
1730 }
1731 (LayoutDirection::Backward, false, None) => (0..span.words.len()).collect(),
1732 };
1733 for word_idx in word_indices {
1734 let word = &span.words[word_idx];
1735 let word_width = if span_index == start.span && word_idx == start.word {
1736 let (start_glyph_pos, end_glyph_pos) = Self::get_glyph_start_end(
1737 word, start, span_index, word_idx, direction, congruent,
1738 );
1739 let mut w = 0.;
1740 for glyph_idx in start_glyph_pos..end_glyph_pos {
1741 w += word.glyphs[glyph_idx].width(font_size);
1742 }
1743 w
1744 } else {
1745 word.width(font_size)
1746 };
1747
1748 let overflowing = {
1749 check_ellipsizing
1751 && (
1752 (total_w + word_range_width + word_width > max_width)
1754 || (Self::remaining_content_exceeds(
1755 spans,
1756 font_size,
1757 span_index,
1758 word_idx,
1759 word_count,
1760 starting_word_index,
1761 direction,
1762 congruent,
1763 start.span,
1764 span_count,
1765 ellipsis_w,
1766 ) && total_w + word_range_width + word_width + ellipsis_w
1767 > max_width)
1768 )
1769 };
1770
1771 if overflowing {
1772 let available = (max_width - ellipsis_w).max(0.0);
1774
1775 let (glyph_end, glyphs_w) = Self::fit_glyphs(
1776 word,
1777 font_size,
1778 start,
1779 span_index,
1780 word_idx,
1781 direction,
1782 congruent,
1783 total_w + word_range_width,
1784 available,
1785 word_forward,
1786 );
1787
1788 let (start_pos, end_pos) = if word_forward {
1789 if span_index == start.span {
1790 if !congruent {
1791 (WordGlyphPos::ZERO, WordGlyphPos::new(word_idx, glyph_end))
1792 } else {
1793 (
1794 start.word_glyph_pos(),
1795 WordGlyphPos::new(word_idx, glyph_end),
1796 )
1797 }
1798 } else {
1799 (WordGlyphPos::ZERO, WordGlyphPos::new(word_idx, glyph_end))
1800 }
1801 } else {
1802 let range_end = if span_index == start.span && !congruent {
1810 start.word_glyph_pos()
1811 } else {
1812 WordGlyphPos::new(span.words.len(), 0)
1813 };
1814 (WordGlyphPos::new(word_idx, glyph_end), range_end)
1815 };
1816 self.add_to_visual_line(
1817 current_visual_line,
1818 span_index,
1819 start_pos,
1820 end_pos,
1821 word_range_width + glyphs_w,
1822 number_of_blanks,
1823 );
1824
1825 current_visual_line.ellipsized = true;
1827 break 'outer;
1828 }
1829
1830 word_range_width += word_width;
1831 if word.blank {
1832 number_of_blanks += 1;
1833 }
1834
1835 if matches!(direction, LayoutDirection::Backward)
1837 && word_idx == start.word
1838 && span_index == start.span
1839 {
1840 let (start_pos, end_pos) = if word_forward {
1841 (WordGlyphPos::ZERO, start.word_glyph_pos())
1842 } else {
1843 (
1844 start.word_glyph_pos(),
1845 WordGlyphPos::new(span.words.len(), 0),
1846 )
1847 };
1848
1849 self.add_to_visual_line(
1850 current_visual_line,
1851 span_index,
1852 start_pos,
1853 end_pos,
1854 word_range_width,
1855 number_of_blanks,
1856 );
1857
1858 break 'outer;
1859 }
1860 }
1861
1862 total_w += word_range_width;
1865 let (start_pos, end_pos) = if congruent {
1866 if span_index == start.span {
1867 (
1868 start.word_glyph_pos(),
1869 WordGlyphPos::new(span.words.len(), 0),
1870 )
1871 } else {
1872 (WordGlyphPos::ZERO, WordGlyphPos::new(span.words.len(), 0))
1873 }
1874 } else if span_index == start.span {
1875 (WordGlyphPos::ZERO, start.word_glyph_pos())
1876 } else {
1877 (WordGlyphPos::ZERO, WordGlyphPos::new(span.words.len(), 0))
1878 };
1879
1880 self.add_to_visual_line(
1881 current_visual_line,
1882 span_index,
1883 start_pos,
1884 end_pos,
1885 word_range_width,
1886 number_of_blanks,
1887 );
1888 }
1889
1890 if matches!(direction, LayoutDirection::Backward) {
1891 current_visual_line.ranges.reverse();
1892 }
1893 }
1894
1895 fn layout_middle(
1896 &self,
1897 current_visual_line: &mut VisualLine,
1898 font_size: f32,
1899 spans: &[ShapeSpan],
1900 start_opt: Option<SpanWordGlyphPos>,
1901 rtl: bool,
1902 width: f32,
1903 ellipsize: Ellipsize,
1904 ellipsis_w: f32,
1905 ) {
1906 assert!(matches!(ellipsize, Ellipsize::Middle(_)));
1907
1908 {
1910 let mut test_line = VisualLine::default();
1911 self.layout_spans(
1912 &mut test_line,
1913 font_size,
1914 spans,
1915 start_opt,
1916 rtl,
1917 Some(width),
1918 Ellipsize::End(EllipsizeHeightLimit::Lines(1)),
1919 ellipsis_w,
1920 LayoutDirection::Forward,
1921 );
1922 if !test_line.ellipsized && test_line.w <= width {
1923 *current_visual_line = test_line;
1924 return;
1925 }
1926 }
1927
1928 let mut starting_line = VisualLine::default();
1929 self.layout_spans(
1930 &mut starting_line,
1931 font_size,
1932 spans,
1933 start_opt,
1934 rtl,
1935 Some(width / 2.0),
1936 Ellipsize::End(EllipsizeHeightLimit::Lines(1)),
1937 0., LayoutDirection::Forward,
1939 );
1940 let forward_pass_overflowed = starting_line.ellipsized;
1941 let end_range_opt = starting_line.ranges.last();
1942 match end_range_opt {
1943 Some(range) if forward_pass_overflowed => {
1944 let congruent = rtl == self.spans[range.span].level.is_rtl();
1945 let mut ending_line = VisualLine::default();
1947 let start = if congruent {
1948 SpanWordGlyphPos {
1949 span: range.span,
1950 word: range.end.word,
1951 glyph: range.end.glyph,
1952 }
1953 } else {
1954 SpanWordGlyphPos {
1955 span: range.span,
1956 word: range.start.word,
1957 glyph: range.start.glyph,
1958 }
1959 };
1960 self.layout_spans(
1961 &mut ending_line,
1962 font_size,
1963 spans,
1964 Some(start),
1965 rtl,
1966 Some((width - starting_line.w - ellipsis_w).max(0.0)),
1967 Ellipsize::Start(EllipsizeHeightLimit::Lines(1)),
1968 0., LayoutDirection::Backward,
1970 );
1971 let ellipsis_level = self.ellipsis_level_between(
1974 starting_line.ranges.last(),
1975 ending_line.ranges.first(),
1976 );
1977 starting_line
1978 .ranges
1979 .push(self.ellipsis_vlrange(ellipsis_level));
1980 starting_line.ranges.extend(ending_line.ranges);
1981 current_visual_line.ranges = starting_line.ranges;
1982 current_visual_line.ellipsized = true;
1983 current_visual_line.w = starting_line.w + ending_line.w + ellipsis_w;
1984 current_visual_line.spaces = starting_line.spaces + ending_line.spaces;
1985 }
1986 None if forward_pass_overflowed && width > ellipsis_w => {
1987 current_visual_line
1990 .ranges
1991 .push(self.ellipsis_vlrange(if self.rtl {
1992 unicode_bidi::Level::rtl()
1993 } else {
1994 unicode_bidi::Level::ltr()
1995 }));
1996 current_visual_line.ellipsized = true;
1997 current_visual_line.w = ellipsis_w;
1998 current_visual_line.spaces = 0;
1999 }
2000 _ => {
2001 current_visual_line.ranges = starting_line.ranges;
2003 current_visual_line.w = starting_line.w;
2004 current_visual_line.spaces = starting_line.spaces;
2005 current_visual_line.ellipsized = false;
2006 }
2007 }
2008 }
2009
2010 fn get_span_words(&self, span_index: usize) -> &[ShapeWord] {
2012 if span_index == ELLIPSIS_SPAN {
2013 &self
2014 .ellipsis_span
2015 .as_ref()
2016 .expect("ellipsis_span not set")
2017 .words
2018 } else {
2019 &self.spans[span_index].words
2020 }
2021 }
2022
2023 fn byte_range_of_vlrange(&self, r: &VlRange) -> Option<(usize, usize)> {
2024 debug_assert_ne!(r.span, ELLIPSIS_SPAN);
2025 let words = self.get_span_words(r.span);
2026 let mut min_byte = usize::MAX;
2027 let mut max_byte = 0usize;
2028 let end_word = r.end.word + usize::from(r.end.glyph != 0);
2029 for (i, word) in words.iter().enumerate().take(end_word).skip(r.start.word) {
2030 let included_glyphs = match (i == r.start.word, i == r.end.word) {
2031 (false, false) => &word.glyphs[..],
2032 (true, false) => &word.glyphs[r.start.glyph..],
2033 (false, true) => &word.glyphs[..r.end.glyph],
2034 (true, true) => &word.glyphs[r.start.glyph..r.end.glyph],
2035 };
2036 for glyph in included_glyphs {
2037 min_byte = min_byte.min(glyph.start);
2038 max_byte = max_byte.max(glyph.end);
2039 }
2040 }
2041 if min_byte <= max_byte {
2042 Some((min_byte, max_byte))
2043 } else {
2044 None
2045 }
2046 }
2047
2048 fn compute_elided_byte_range(
2049 &self,
2050 visual_line: &VisualLine,
2051 line_len: usize,
2052 ) -> Option<(usize, usize)> {
2053 if !visual_line.ellipsized {
2054 return None;
2055 }
2056 let ellipsis_idx = visual_line
2058 .ranges
2059 .iter()
2060 .position(|r| r.span == ELLIPSIS_SPAN)?;
2061
2062 let before_end = (0..ellipsis_idx)
2064 .rev()
2065 .find_map(|i| self.byte_range_of_vlrange(&visual_line.ranges[i]))
2066 .map(|(_, end)| end)
2067 .unwrap_or(0);
2068
2069 let after_start = (ellipsis_idx + 1..visual_line.ranges.len())
2071 .find_map(|i| self.byte_range_of_vlrange(&visual_line.ranges[i]))
2072 .map(|(start, _)| start)
2073 .unwrap_or(line_len);
2074
2075 Some((before_end, after_start))
2076 }
2077
2078 fn max_byte_offset(&self) -> usize {
2081 self.spans
2082 .iter()
2083 .flat_map(|span| span.words.iter())
2084 .flat_map(|word| word.glyphs.iter())
2085 .map(|g| g.end)
2086 .max()
2087 .unwrap_or(0)
2088 }
2089
2090 fn ellipsis_w(&self, font_size: f32) -> f32 {
2092 self.ellipsis_span
2093 .as_ref()
2094 .map_or(0.0, |s| s.words.iter().map(|w| w.width(font_size)).sum())
2095 }
2096
2097 fn ellipsis_vlrange(&self, level: unicode_bidi::Level) -> VlRange {
2099 VlRange {
2100 span: ELLIPSIS_SPAN,
2101 start: WordGlyphPos::ZERO,
2102 end: WordGlyphPos::new(1, 0),
2103 level,
2104 }
2105 }
2106
2107 fn ellipsis_level_between(
2110 &self,
2111 before: Option<&VlRange>,
2112 after: Option<&VlRange>,
2113 ) -> unicode_bidi::Level {
2114 match (before, after) {
2115 (Some(a), Some(b)) if a.level == b.level => a.level,
2116 (Some(a), None) => a.level,
2117 (None, Some(b)) => b.level,
2118 _ => {
2119 if self.rtl {
2120 unicode_bidi::Level::rtl()
2121 } else {
2122 unicode_bidi::Level::ltr()
2123 }
2124 }
2125 }
2126 }
2127
2128 fn layout_line(
2129 &self,
2130 current_visual_line: &mut VisualLine,
2131 font_size: f32,
2132 spans: &[ShapeSpan],
2133 start_opt: Option<SpanWordGlyphPos>,
2134 rtl: bool,
2135 width_opt: Option<f32>,
2136 ellipsize: Ellipsize,
2137 ) {
2138 let ellipsis_w = self.ellipsis_w(font_size);
2139
2140 match (ellipsize, width_opt) {
2141 (Ellipsize::Start(_), Some(_)) => {
2142 self.layout_spans(
2143 current_visual_line,
2144 font_size,
2145 spans,
2146 start_opt,
2147 rtl,
2148 width_opt,
2149 ellipsize,
2150 ellipsis_w,
2151 LayoutDirection::Backward,
2152 );
2153 if current_visual_line.ellipsized {
2155 let level =
2156 self.ellipsis_level_between(None, current_visual_line.ranges.first());
2157 current_visual_line
2158 .ranges
2159 .insert(0, self.ellipsis_vlrange(level));
2160 current_visual_line.w += ellipsis_w;
2161 }
2162 }
2163 (Ellipsize::Middle(_), Some(width)) => {
2164 self.layout_middle(
2165 current_visual_line,
2166 font_size,
2167 spans,
2168 start_opt,
2169 rtl,
2170 width,
2171 ellipsize,
2172 ellipsis_w,
2173 );
2174 }
2175 _ => {
2176 self.layout_spans(
2177 current_visual_line,
2178 font_size,
2179 spans,
2180 start_opt,
2181 rtl,
2182 width_opt,
2183 ellipsize,
2184 ellipsis_w,
2185 LayoutDirection::Forward,
2186 );
2187 if current_visual_line.ellipsized {
2189 let level =
2190 self.ellipsis_level_between(current_visual_line.ranges.last(), None);
2191 current_visual_line
2192 .ranges
2193 .push(self.ellipsis_vlrange(level));
2194 current_visual_line.w += ellipsis_w;
2195 }
2196 }
2197 }
2198
2199 if current_visual_line.ellipsized {
2202 let line_len = self.max_byte_offset();
2203 current_visual_line.elided_byte_range =
2204 self.compute_elided_byte_range(current_visual_line, line_len);
2205 }
2206 }
2207
2208 pub fn layout_to_buffer(
2209 &self,
2210 scratch: &mut ShapeBuffer,
2211 font_size: f32,
2212 width_opt: Option<f32>,
2213 wrap: Wrap,
2214 ellipsize: Ellipsize,
2215 align: Option<Align>,
2216 layout_lines: &mut Vec<LayoutLine>,
2217 match_mono_width: Option<f32>,
2218 hinting: Hinting,
2219 ) {
2220 let mut visual_lines = mem::take(&mut scratch.visual_lines);
2224 let mut cached_visual_lines = mem::take(&mut scratch.cached_visual_lines);
2225 cached_visual_lines.clear();
2226 cached_visual_lines.extend(visual_lines.drain(..).map(|mut l| {
2227 l.clear();
2228 l
2229 }));
2230
2231 let mut cached_glyph_sets = mem::take(&mut scratch.glyph_sets);
2233 cached_glyph_sets.clear();
2234 cached_glyph_sets.extend(layout_lines.drain(..).rev().map(|mut v| {
2235 v.glyphs.clear();
2236 v.glyphs
2237 }));
2238
2239 let mut current_visual_line = cached_visual_lines.pop().unwrap_or_default();
2244
2245 if wrap == Wrap::None {
2246 self.layout_line(
2247 &mut current_visual_line,
2248 font_size,
2249 &self.spans,
2250 None,
2251 self.rtl,
2252 width_opt,
2253 ellipsize,
2254 );
2255 } else {
2256 let mut total_line_height = 0.0;
2257 let mut total_line_count = 0;
2258 let max_line_count_opt = match ellipsize {
2259 Ellipsize::Start(EllipsizeHeightLimit::Lines(lines))
2260 | Ellipsize::Middle(EllipsizeHeightLimit::Lines(lines))
2261 | Ellipsize::End(EllipsizeHeightLimit::Lines(lines)) => Some(lines.max(1)),
2262 _ => None,
2263 };
2264 let max_height_opt = match ellipsize {
2265 Ellipsize::Start(EllipsizeHeightLimit::Height(height))
2266 | Ellipsize::Middle(EllipsizeHeightLimit::Height(height))
2267 | Ellipsize::End(EllipsizeHeightLimit::Height(height)) => Some(height),
2268 _ => None,
2269 };
2270 let line_height = self
2271 .metrics_opt
2272 .map_or_else(|| font_size, |m| m.line_height);
2273
2274 let try_ellipsize_last_line = |total_line_count: usize,
2275 total_line_height: f32,
2276 current_visual_line: &mut VisualLine,
2277 font_size: f32,
2278 start_opt: Option<SpanWordGlyphPos>,
2279 width_opt: Option<f32>,
2280 ellipsize: Ellipsize|
2281 -> bool {
2282 if max_line_count_opt == Some(total_line_count + 1)
2284 || max_height_opt.is_some_and(|max_height| {
2285 total_line_height + line_height * 2.0 > max_height
2286 })
2287 {
2288 self.layout_line(
2289 current_visual_line,
2290 font_size,
2291 &self.spans,
2292 start_opt,
2293 self.rtl,
2294 width_opt,
2295 ellipsize,
2296 );
2297 return true;
2298 }
2299 false
2300 };
2301
2302 if !try_ellipsize_last_line(
2303 total_line_count,
2304 total_line_height,
2305 &mut current_visual_line,
2306 font_size,
2307 None,
2308 width_opt,
2309 ellipsize,
2310 ) {
2311 'outer: for (span_index, span) in self.spans.iter().enumerate() {
2312 let mut word_range_width = 0.;
2313 let mut width_before_last_blank = 0.;
2314 let mut number_of_blanks: u32 = 0;
2315
2316 if self.rtl != span.level.is_rtl() {
2318 let mut fitting_start = WordGlyphPos::new(span.words.len(), 0);
2320 for (i, word) in span.words.iter().enumerate().rev() {
2321 let word_width = word.width(font_size);
2322 if current_visual_line.w + (word_range_width + word_width)
2326 <= width_opt.unwrap_or(f32::INFINITY)
2327 || (word.blank
2330 && (current_visual_line.w + word_range_width) <= width_opt.unwrap_or(f32::INFINITY))
2331 {
2332 if word.blank {
2334 number_of_blanks += 1;
2335 width_before_last_blank = word_range_width;
2336 }
2337 word_range_width += word_width;
2338 } else if wrap == Wrap::Glyph
2339 || (wrap == Wrap::WordOrGlyph && word_width > width_opt.unwrap_or(f32::INFINITY))
2341 {
2342 if word_range_width > 0.
2344 && wrap == Wrap::WordOrGlyph
2345 && word_width > width_opt.unwrap_or(f32::INFINITY)
2346 {
2347 self.add_to_visual_line(
2348 &mut current_visual_line,
2349 span_index,
2350 WordGlyphPos::new(i + 1, 0),
2351 fitting_start,
2352 word_range_width,
2353 number_of_blanks,
2354 );
2355
2356 visual_lines.push(current_visual_line);
2357 current_visual_line =
2358 cached_visual_lines.pop().unwrap_or_default();
2359
2360 number_of_blanks = 0;
2361 word_range_width = 0.;
2362
2363 fitting_start = WordGlyphPos::new(i, 0);
2364 total_line_count += 1;
2365 total_line_height += line_height;
2366 if try_ellipsize_last_line(
2367 total_line_count,
2368 total_line_height,
2369 &mut current_visual_line,
2370 font_size,
2371 Some(SpanWordGlyphPos::with_wordglyph(
2372 span_index,
2373 fitting_start,
2374 )),
2375 width_opt,
2376 ellipsize,
2377 ) {
2378 break 'outer;
2379 }
2380 }
2381
2382 for (glyph_i, glyph) in word.glyphs.iter().enumerate().rev() {
2383 let glyph_width = glyph.width(font_size);
2384 if current_visual_line.w + (word_range_width + glyph_width)
2385 <= width_opt.unwrap_or(f32::INFINITY)
2386 {
2387 word_range_width += glyph_width;
2388 } else {
2389 self.add_to_visual_line(
2390 &mut current_visual_line,
2391 span_index,
2392 WordGlyphPos::new(i, glyph_i + 1),
2393 fitting_start,
2394 word_range_width,
2395 number_of_blanks,
2396 );
2397 visual_lines.push(current_visual_line);
2398 current_visual_line =
2399 cached_visual_lines.pop().unwrap_or_default();
2400
2401 number_of_blanks = 0;
2402 word_range_width = glyph_width;
2403 fitting_start = WordGlyphPos::new(i, glyph_i + 1);
2404 total_line_count += 1;
2405 total_line_height += line_height;
2406 if try_ellipsize_last_line(
2407 total_line_count,
2408 total_line_height,
2409 &mut current_visual_line,
2410 font_size,
2411 Some(SpanWordGlyphPos::with_wordglyph(
2412 span_index,
2413 fitting_start,
2414 )),
2415 width_opt,
2416 ellipsize,
2417 ) {
2418 break 'outer;
2419 }
2420 }
2421 }
2422 } else {
2423 if word_range_width > 0. {
2427 let trailing_blank = span
2430 .words
2431 .get(i + 1)
2432 .is_some_and(|previous_word| previous_word.blank);
2433
2434 if trailing_blank {
2435 number_of_blanks = number_of_blanks.saturating_sub(1);
2436 self.add_to_visual_line(
2437 &mut current_visual_line,
2438 span_index,
2439 WordGlyphPos::new(i + 2, 0),
2440 fitting_start,
2441 width_before_last_blank,
2442 number_of_blanks,
2443 );
2444 } else {
2445 self.add_to_visual_line(
2446 &mut current_visual_line,
2447 span_index,
2448 WordGlyphPos::new(i + 1, 0),
2449 fitting_start,
2450 word_range_width,
2451 number_of_blanks,
2452 );
2453 }
2454 }
2455
2456 if !current_visual_line.ranges.is_empty() {
2459 visual_lines.push(current_visual_line);
2460 current_visual_line =
2461 cached_visual_lines.pop().unwrap_or_default();
2462 number_of_blanks = 0;
2463 total_line_count += 1;
2464 total_line_height += line_height;
2465
2466 if try_ellipsize_last_line(
2467 total_line_count,
2468 total_line_height,
2469 &mut current_visual_line,
2470 font_size,
2471 Some(SpanWordGlyphPos::with_wordglyph(
2472 span_index,
2473 if word.blank {
2474 WordGlyphPos::new(i, 0)
2475 } else {
2476 WordGlyphPos::new(i + 1, 0)
2477 },
2478 )),
2479 width_opt,
2480 ellipsize,
2481 ) {
2482 break 'outer;
2483 }
2484 }
2485
2486 if word.blank {
2487 word_range_width = 0.;
2488 fitting_start = WordGlyphPos::new(i, 0);
2489 } else {
2490 word_range_width = word_width;
2491 fitting_start = WordGlyphPos::new(i + 1, 0);
2492 }
2493 }
2494 }
2495 self.add_to_visual_line(
2496 &mut current_visual_line,
2497 span_index,
2498 WordGlyphPos::new(0, 0),
2499 fitting_start,
2500 word_range_width,
2501 number_of_blanks,
2502 );
2503 } else {
2504 let mut fitting_start = WordGlyphPos::ZERO;
2506 for (i, word) in span.words.iter().enumerate() {
2507 let word_width = word.width(font_size);
2508 if current_visual_line.w + (word_range_width + word_width)
2509 <= width_opt.unwrap_or(f32::INFINITY)
2510 || (word.blank
2513 && (current_visual_line.w + word_range_width) <= width_opt.unwrap_or(f32::INFINITY))
2514 {
2515 if word.blank {
2517 number_of_blanks += 1;
2518 width_before_last_blank = word_range_width;
2519 }
2520 word_range_width += word_width;
2521 } else if wrap == Wrap::Glyph
2522 || (wrap == Wrap::WordOrGlyph && word_width > width_opt.unwrap_or(f32::INFINITY))
2524 {
2525 if word_range_width > 0.
2527 && wrap == Wrap::WordOrGlyph
2528 && word_width > width_opt.unwrap_or(f32::INFINITY)
2529 {
2530 self.add_to_visual_line(
2531 &mut current_visual_line,
2532 span_index,
2533 fitting_start,
2534 WordGlyphPos::new(i, 0),
2535 word_range_width,
2536 number_of_blanks,
2537 );
2538
2539 visual_lines.push(current_visual_line);
2540 current_visual_line =
2541 cached_visual_lines.pop().unwrap_or_default();
2542
2543 number_of_blanks = 0;
2544 word_range_width = 0.;
2545
2546 fitting_start = WordGlyphPos::new(i, 0);
2547 total_line_count += 1;
2548 total_line_height += line_height;
2549 if try_ellipsize_last_line(
2550 total_line_count,
2551 total_line_height,
2552 &mut current_visual_line,
2553 font_size,
2554 Some(SpanWordGlyphPos::with_wordglyph(
2555 span_index,
2556 fitting_start,
2557 )),
2558 width_opt,
2559 ellipsize,
2560 ) {
2561 break 'outer;
2562 }
2563 }
2564
2565 for (glyph_i, glyph) in word.glyphs.iter().enumerate() {
2566 let glyph_width = glyph.width(font_size);
2567 if current_visual_line.w + (word_range_width + glyph_width)
2568 <= width_opt.unwrap_or(f32::INFINITY)
2569 {
2570 word_range_width += glyph_width;
2571 } else {
2572 self.add_to_visual_line(
2573 &mut current_visual_line,
2574 span_index,
2575 fitting_start,
2576 WordGlyphPos::new(i, glyph_i),
2577 word_range_width,
2578 number_of_blanks,
2579 );
2580 visual_lines.push(current_visual_line);
2581 current_visual_line =
2582 cached_visual_lines.pop().unwrap_or_default();
2583
2584 number_of_blanks = 0;
2585 word_range_width = glyph_width;
2586 fitting_start = WordGlyphPos::new(i, glyph_i);
2587 total_line_count += 1;
2588 total_line_height += line_height;
2589 if try_ellipsize_last_line(
2590 total_line_count,
2591 total_line_height,
2592 &mut current_visual_line,
2593 font_size,
2594 Some(SpanWordGlyphPos::with_wordglyph(
2595 span_index,
2596 fitting_start,
2597 )),
2598 width_opt,
2599 ellipsize,
2600 ) {
2601 break 'outer;
2602 }
2603 }
2604 }
2605 } else {
2606 if word_range_width > 0. {
2610 let trailing_blank = i > 0 && span.words[i - 1].blank;
2613
2614 if trailing_blank {
2615 number_of_blanks = number_of_blanks.saturating_sub(1);
2616 self.add_to_visual_line(
2617 &mut current_visual_line,
2618 span_index,
2619 fitting_start,
2620 WordGlyphPos::new(i - 1, 0),
2621 width_before_last_blank,
2622 number_of_blanks,
2623 );
2624 } else {
2625 self.add_to_visual_line(
2626 &mut current_visual_line,
2627 span_index,
2628 fitting_start,
2629 WordGlyphPos::new(i, 0),
2630 word_range_width,
2631 number_of_blanks,
2632 );
2633 }
2634 }
2635
2636 if !current_visual_line.ranges.is_empty() {
2637 visual_lines.push(current_visual_line);
2638 current_visual_line =
2639 cached_visual_lines.pop().unwrap_or_default();
2640 number_of_blanks = 0;
2641 total_line_count += 1;
2642 total_line_height += line_height;
2643 if try_ellipsize_last_line(
2644 total_line_count,
2645 total_line_height,
2646 &mut current_visual_line,
2647 font_size,
2648 Some(SpanWordGlyphPos::with_wordglyph(
2649 span_index,
2650 if i > 0 && span.words[i - 1].blank {
2651 WordGlyphPos::new(i - 1, 0)
2652 } else {
2653 WordGlyphPos::new(i, 0)
2654 },
2655 )),
2656 width_opt,
2657 ellipsize,
2658 ) {
2659 break 'outer;
2660 }
2661 }
2662
2663 if word.blank {
2664 word_range_width = 0.;
2665 fitting_start = WordGlyphPos::new(i + 1, 0);
2666 } else {
2667 word_range_width = word_width;
2668 fitting_start = WordGlyphPos::new(i, 0);
2669 }
2670 }
2671 }
2672 self.add_to_visual_line(
2673 &mut current_visual_line,
2674 span_index,
2675 fitting_start,
2676 WordGlyphPos::new(span.words.len(), 0),
2677 word_range_width,
2678 number_of_blanks,
2679 );
2680 }
2681 }
2682 }
2683 }
2684
2685 if current_visual_line.ranges.is_empty() {
2686 current_visual_line.clear();
2687 cached_visual_lines.push(current_visual_line);
2688 } else {
2689 visual_lines.push(current_visual_line);
2690 }
2691
2692 let align = align.unwrap_or(if self.rtl { Align::Right } else { Align::Left });
2694
2695 let line_width = width_opt.unwrap_or_else(|| {
2696 let mut width: f32 = 0.0;
2697 for visual_line in &visual_lines {
2698 width = width.max(visual_line.w);
2699 }
2700 width
2701 });
2702
2703 let start_x = if self.rtl { line_width } else { 0.0 };
2704
2705 let number_of_visual_lines = visual_lines.len();
2706 for (index, visual_line) in visual_lines.iter().enumerate() {
2707 if visual_line.ranges.is_empty() {
2708 continue;
2709 }
2710
2711 let new_order = self.reorder(&visual_line.ranges);
2712
2713 let mut glyphs = cached_glyph_sets
2714 .pop()
2715 .unwrap_or_else(|| Vec::with_capacity(1));
2716 let mut x = start_x;
2717 let mut y = 0.;
2718 let mut max_ascent: f32 = 0.;
2719 let mut max_descent: f32 = 0.;
2720 let alignment_correction = match (align, self.rtl) {
2721 (Align::Left, true) => (line_width - visual_line.w).max(0.),
2722 (Align::Left, false) => 0.,
2723 (Align::Right, true) => 0.,
2724 (Align::Right, false) => (line_width - visual_line.w).max(0.),
2725 (Align::Center, _) => (line_width - visual_line.w).max(0.) / 2.0,
2726 (Align::End, _) => (line_width - visual_line.w).max(0.),
2727 (Align::Justified, _) => 0.,
2728 };
2729
2730 if self.rtl {
2731 x -= alignment_correction;
2732 } else {
2733 x += alignment_correction;
2734 }
2735
2736 if hinting == Hinting::Enabled {
2737 x = x.round();
2738 }
2739
2740 let justification_expansion = if matches!(align, Align::Justified)
2756 && visual_line.spaces > 0
2757 && index != number_of_visual_lines - 1
2759 {
2760 (line_width - visual_line.w) / visual_line.spaces as f32
2761 } else {
2762 0.
2763 };
2764
2765 let elided_byte_range = if visual_line.ellipsized {
2766 visual_line.elided_byte_range
2767 } else {
2768 None
2769 };
2770
2771 let mut decorations: Vec<DecorationSpan> = Vec::new();
2772
2773 let process_range = |range: Range<usize>,
2774 x: &mut f32,
2775 y: &mut f32,
2776 glyphs: &mut Vec<LayoutGlyph>,
2777 decorations: &mut Vec<DecorationSpan>,
2778 max_ascent: &mut f32,
2779 max_descent: &mut f32| {
2780 for r in visual_line.ranges[range.clone()].iter() {
2781 let is_ellipsis = r.span == ELLIPSIS_SPAN;
2782 let span_words = self.get_span_words(r.span);
2783 let deco_spans: &[(Range<usize>, GlyphDecorationData)] = if is_ellipsis {
2784 &[]
2785 } else {
2786 &self.spans[r.span].decoration_spans
2787 };
2788 let mut deco_cursor: usize = 0;
2791 for i in r.start.word..r.end.word + usize::from(r.end.glyph != 0) {
2793 let word = &span_words[i];
2794 let included_glyphs = match (i == r.start.word, i == r.end.word) {
2795 (false, false) => &word.glyphs[..],
2796 (true, false) => &word.glyphs[r.start.glyph..],
2797 (false, true) => &word.glyphs[..r.end.glyph],
2798 (true, true) => &word.glyphs[r.start.glyph..r.end.glyph],
2799 };
2800
2801 for glyph in included_glyphs {
2802 let font_size = glyph.metrics_opt.map_or(font_size, |x| x.font_size);
2804
2805 let match_mono_em_width = match_mono_width.map(|w| w / font_size);
2806
2807 let glyph_font_size = match (
2808 match_mono_em_width,
2809 glyph.font_monospace_em_width,
2810 ) {
2811 (Some(match_em_width), Some(glyph_em_width))
2812 if glyph_em_width != match_em_width =>
2813 {
2814 let glyph_to_match_factor = glyph_em_width / match_em_width;
2815 let glyph_font_size = math::roundf(glyph_to_match_factor)
2816 .max(1.0)
2817 / glyph_to_match_factor
2818 * font_size;
2819 log::trace!(
2820 "Adjusted glyph font size ({font_size} => {glyph_font_size})"
2821 );
2822 glyph_font_size
2823 }
2824 _ => font_size,
2825 };
2826
2827 let mut x_advance = glyph_font_size.mul_add(
2828 glyph.x_advance,
2829 if word.blank {
2830 justification_expansion
2831 } else {
2832 0.0
2833 },
2834 );
2835 if let Some(match_em_width) = match_mono_em_width {
2836 x_advance = ((x_advance / match_em_width).round()) * match_em_width;
2838 }
2839 if hinting == Hinting::Enabled {
2840 x_advance = x_advance.round();
2841 }
2842 if self.rtl {
2843 *x -= x_advance;
2844 }
2845 let y_advance = glyph_font_size * glyph.y_advance;
2846 let mut layout_glyph = glyph.layout(
2847 glyph_font_size,
2848 glyph.metrics_opt.map(|x| x.line_height),
2849 *x,
2850 *y,
2851 x_advance,
2852 r.level,
2853 );
2854 if is_ellipsis {
2859 if let Some((elided_start, elided_end)) = elided_byte_range {
2860 let boundary = if elided_start == 0 {
2866 elided_end
2867 } else {
2868 elided_start
2869 };
2870 layout_glyph.start = boundary;
2871 layout_glyph.end = boundary;
2872 }
2873 }
2874 glyphs.push(layout_glyph);
2875
2876 if deco_cursor >= deco_spans.len()
2877 || glyph.start < deco_spans[deco_cursor].0.start
2878 {
2879 deco_cursor = 0;
2880 }
2881 while deco_cursor < deco_spans.len()
2882 && deco_spans[deco_cursor].0.end <= glyph.start
2883 {
2884 deco_cursor += 1;
2885 }
2886 let glyph_deco = deco_spans
2887 .get(deco_cursor)
2888 .filter(|(range, _)| glyph.start >= range.start);
2889 let glyph_idx = glyphs.len() - 1;
2890 let extends = matches!(
2891 (decorations.last(), &glyph_deco),
2892 (Some(span), Some((_, d))) if span.data == *d
2893 );
2894 if extends {
2895 if let Some(last) = decorations.last_mut() {
2896 last.glyph_range.end = glyph_idx + 1;
2897 }
2898 } else if let Some((_, d)) = glyph_deco {
2899 decorations.push(DecorationSpan {
2900 glyph_range: glyph_idx..glyph_idx + 1,
2901 data: d.clone(),
2902 color_opt: glyphs[glyph_idx].color_opt,
2903 font_size: glyphs[glyph_idx].font_size,
2904 });
2905 }
2906 if !self.rtl {
2907 *x += x_advance;
2908 }
2909 *y += y_advance;
2910 *max_ascent = max_ascent.max(glyph_font_size * glyph.ascent);
2911 *max_descent = max_descent.max(glyph_font_size * glyph.descent);
2912 }
2913 }
2914 }
2915 };
2916
2917 if self.rtl {
2918 for range in new_order.into_iter().rev() {
2919 process_range(
2920 range,
2921 &mut x,
2922 &mut y,
2923 &mut glyphs,
2924 &mut decorations,
2925 &mut max_ascent,
2926 &mut max_descent,
2927 );
2928 }
2929 } else {
2930 for range in new_order {
2932 process_range(
2933 range,
2934 &mut x,
2935 &mut y,
2936 &mut glyphs,
2937 &mut decorations,
2938 &mut max_ascent,
2939 &mut max_descent,
2940 );
2941 }
2942 }
2943
2944 let mut line_height_opt: Option<f32> = None;
2945 for glyph in &glyphs {
2946 if let Some(glyph_line_height) = glyph.line_height_opt {
2947 line_height_opt = line_height_opt
2948 .map_or(Some(glyph_line_height), |line_height| {
2949 Some(line_height.max(glyph_line_height))
2950 });
2951 }
2952 }
2953
2954 layout_lines.push(LayoutLine {
2955 w: if align != Align::Justified {
2956 visual_line.w
2957 } else if self.rtl {
2958 start_x - x
2959 } else {
2960 x
2961 },
2962 max_ascent,
2963 max_descent,
2964 line_height_opt,
2965 glyphs,
2966 decorations,
2967 });
2968 }
2969
2970 if layout_lines.is_empty() {
2972 layout_lines.push(LayoutLine {
2973 w: 0.0,
2974 max_ascent: 0.0,
2975 max_descent: 0.0,
2976 line_height_opt: self.metrics_opt.map(|x| x.line_height),
2977 glyphs: Vec::default(),
2978 decorations: Vec::new(),
2979 });
2980 }
2981
2982 scratch.visual_lines = visual_lines;
2984 scratch.visual_lines.append(&mut cached_visual_lines);
2985 scratch.cached_visual_lines = cached_visual_lines;
2986 scratch.glyph_sets = cached_glyph_sets;
2987 }
2988}