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