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::{boxed::Box, 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 fn remaining_content_exceeds(
1486 spans: &[ShapeSpan],
1487 font_size: f32,
1488 span_index: usize,
1489 word_idx: usize,
1490 word_count: usize,
1491 starting_word_index: usize,
1492 direction: LayoutDirection,
1493 congruent: bool,
1494 start_span: usize,
1495 span_count: usize,
1496 threshold: f32,
1497 ) -> bool {
1498 let mut acc: f32 = 0.0;
1499
1500 let word_range: Box<dyn Iterator<Item = usize>> = match (direction, congruent) {
1502 (LayoutDirection::Forward, true) => Box::new(word_idx + 1..word_count),
1503 (LayoutDirection::Forward, false) => Box::new(0..word_idx),
1504 (LayoutDirection::Backward, true) => Box::new(starting_word_index..word_idx),
1505 (LayoutDirection::Backward, false) => Box::new(word_idx + 1..word_count),
1506 };
1507 for wi in word_range {
1508 acc += spans[span_index].words[wi].width(font_size);
1509 if acc > threshold {
1510 return true;
1511 }
1512 }
1513
1514 let span_range: Box<dyn Iterator<Item = usize>> = match direction {
1516 LayoutDirection::Forward => Box::new(span_index + 1..span_count),
1517 LayoutDirection::Backward => Box::new(start_span..span_index),
1518 };
1519 for si in span_range {
1520 for w in &spans[si].words {
1521 acc += w.width(font_size);
1522 if acc > threshold {
1523 return true;
1524 }
1525 }
1526 }
1527
1528 false
1529 }
1530
1531 #[inline]
1536 fn layout_spans(
1537 &self,
1538 current_visual_line: &mut VisualLine,
1539 font_size: f32,
1540 spans: &[ShapeSpan],
1541 start_opt: Option<SpanWordGlyphPos>,
1542 rtl: bool,
1543 width_opt: Option<f32>,
1544 ellipsize: Ellipsize,
1545 ellipsis_w: f32,
1546 direction: LayoutDirection,
1547 ) {
1548 let check_ellipsizing = matches!(ellipsize, Ellipsize::Start(_) | Ellipsize::End(_))
1549 && width_opt.is_some_and(|w| w > 0.0 && w.is_finite());
1550
1551 let max_width = width_opt.unwrap_or(f32::INFINITY);
1552 let span_count = spans.len();
1553
1554 let mut total_w: f32 = 0.0;
1555
1556 let start = if let Some(s) = start_opt {
1557 s
1558 } else {
1559 SpanWordGlyphPos::ZERO
1560 };
1561
1562 let span_indices: Vec<usize> = if matches!(direction, LayoutDirection::Forward) {
1563 (start.span..spans.len()).collect()
1564 } else {
1565 (start.span..spans.len()).rev().collect()
1566 };
1567
1568 'outer: for span_index in span_indices {
1569 let mut word_range_width = 0.;
1570 let mut number_of_blanks: u32 = 0;
1571
1572 let span = &spans[span_index];
1573 let word_count = span.words.len();
1574
1575 let starting_word_index = if span_index == start.span {
1576 start.word
1577 } else {
1578 0
1579 };
1580
1581 let congruent = rtl == span.level.is_rtl();
1582 let word_forward: bool = congruent == (direction == LayoutDirection::Forward);
1583
1584 let word_indices: Vec<usize> = match (direction, congruent, start_opt) {
1585 (LayoutDirection::Forward, true, _) => (starting_word_index..word_count).collect(),
1586 (LayoutDirection::Forward, false, Some(start)) => {
1587 if span_index == start.span {
1588 (0..start.word).rev().collect()
1589 } else {
1590 (0..word_count).rev().collect()
1591 }
1592 }
1593 (LayoutDirection::Forward, false, None) => (0..word_count).rev().collect(),
1594 (LayoutDirection::Backward, true, _) => {
1595 ((starting_word_index)..word_count).rev().collect()
1596 }
1597 (LayoutDirection::Backward, false, Some(start)) => {
1598 if span_index == start.span {
1599 if start.glyph > 0 {
1600 (0..(start.word + 1)).collect()
1601 } else {
1602 (0..(start.word)).collect()
1603 }
1604 } else {
1605 (0..word_count).collect()
1606 }
1607 }
1608 (LayoutDirection::Backward, false, None) => (0..span.words.len()).collect(),
1609 };
1610 for word_idx in word_indices {
1611 let word = &span.words[word_idx];
1612 let word_width = if span_index == start.span && word_idx == start.word {
1613 let (start_glyph_pos, end_glyph_pos) = Self::get_glyph_start_end(
1614 word, start, span_index, word_idx, direction, congruent,
1615 );
1616 let mut w = 0.;
1617 for glyph_idx in start_glyph_pos..end_glyph_pos {
1618 w += word.glyphs[glyph_idx].width(font_size);
1619 }
1620 w
1621 } else {
1622 word.width(font_size)
1623 };
1624
1625 let overflowing = {
1626 check_ellipsizing
1628 && (
1629 (total_w + word_range_width + word_width > max_width)
1631 || (Self::remaining_content_exceeds(
1632 spans,
1633 font_size,
1634 span_index,
1635 word_idx,
1636 word_count,
1637 starting_word_index,
1638 direction,
1639 congruent,
1640 start.span,
1641 span_count,
1642 ellipsis_w,
1643 ) && total_w + word_range_width + word_width + ellipsis_w
1644 > max_width)
1645 )
1646 };
1647
1648 if overflowing {
1649 let available = (max_width - ellipsis_w).max(0.0);
1651
1652 let (glyph_end, glyphs_w) = Self::fit_glyphs(
1653 word,
1654 font_size,
1655 start,
1656 span_index,
1657 word_idx,
1658 direction,
1659 congruent,
1660 total_w + word_range_width,
1661 available,
1662 word_forward,
1663 );
1664
1665 let (start_pos, end_pos) = if word_forward {
1666 if span_index == start.span {
1667 if !congruent {
1668 (WordGlyphPos::ZERO, WordGlyphPos::new(word_idx, glyph_end))
1669 } else {
1670 (
1671 start.word_glyph_pos(),
1672 WordGlyphPos::new(word_idx, glyph_end),
1673 )
1674 }
1675 } else {
1676 (WordGlyphPos::ZERO, WordGlyphPos::new(word_idx, glyph_end))
1677 }
1678 } else {
1679 let range_end = if span_index == start.span && !congruent {
1687 start.word_glyph_pos()
1688 } else {
1689 WordGlyphPos::new(span.words.len(), 0)
1690 };
1691 (WordGlyphPos::new(word_idx, glyph_end), range_end)
1692 };
1693 self.add_to_visual_line(
1694 current_visual_line,
1695 span_index,
1696 start_pos,
1697 end_pos,
1698 word_range_width + glyphs_w,
1699 number_of_blanks,
1700 );
1701
1702 current_visual_line.ellipsized = true;
1704 break 'outer;
1705 }
1706
1707 word_range_width += word_width;
1708 if word.blank {
1709 number_of_blanks += 1;
1710 }
1711
1712 if matches!(direction, LayoutDirection::Backward)
1714 && word_idx == start.word
1715 && span_index == start.span
1716 {
1717 let (start_pos, end_pos) = if word_forward {
1718 (WordGlyphPos::ZERO, start.word_glyph_pos())
1719 } else {
1720 (
1721 start.word_glyph_pos(),
1722 WordGlyphPos::new(span.words.len(), 0),
1723 )
1724 };
1725
1726 self.add_to_visual_line(
1727 current_visual_line,
1728 span_index,
1729 start_pos,
1730 end_pos,
1731 word_range_width,
1732 number_of_blanks,
1733 );
1734
1735 break 'outer;
1736 }
1737 }
1738
1739 total_w += word_range_width;
1742 let (start_pos, end_pos) = if congruent {
1743 if span_index == start.span {
1744 (
1745 start.word_glyph_pos(),
1746 WordGlyphPos::new(span.words.len(), 0),
1747 )
1748 } else {
1749 (WordGlyphPos::ZERO, WordGlyphPos::new(span.words.len(), 0))
1750 }
1751 } else if span_index == start.span {
1752 (WordGlyphPos::ZERO, start.word_glyph_pos())
1753 } else {
1754 (WordGlyphPos::ZERO, WordGlyphPos::new(span.words.len(), 0))
1755 };
1756
1757 self.add_to_visual_line(
1758 current_visual_line,
1759 span_index,
1760 start_pos,
1761 end_pos,
1762 word_range_width,
1763 number_of_blanks,
1764 );
1765 }
1766
1767 if matches!(direction, LayoutDirection::Backward) {
1768 current_visual_line.ranges.reverse();
1769 }
1770 }
1771
1772 fn layout_middle(
1773 &self,
1774 current_visual_line: &mut VisualLine,
1775 font_size: f32,
1776 spans: &[ShapeSpan],
1777 start_opt: Option<SpanWordGlyphPos>,
1778 rtl: bool,
1779 width: f32,
1780 ellipsize: Ellipsize,
1781 ellipsis_w: f32,
1782 ) {
1783 assert!(matches!(ellipsize, Ellipsize::Middle(_)));
1784
1785 {
1787 let mut test_line = VisualLine::default();
1788 self.layout_spans(
1789 &mut test_line,
1790 font_size,
1791 spans,
1792 start_opt,
1793 rtl,
1794 Some(width),
1795 Ellipsize::End(EllipsizeHeightLimit::Lines(1)),
1796 ellipsis_w,
1797 LayoutDirection::Forward,
1798 );
1799 if !test_line.ellipsized && test_line.w <= width {
1800 *current_visual_line = test_line;
1801 return;
1802 }
1803 }
1804
1805 let mut starting_line = VisualLine::default();
1806 self.layout_spans(
1807 &mut starting_line,
1808 font_size,
1809 spans,
1810 start_opt,
1811 rtl,
1812 Some(width / 2.0),
1813 Ellipsize::End(EllipsizeHeightLimit::Lines(1)),
1814 0., LayoutDirection::Forward,
1816 );
1817 let forward_pass_overflowed = starting_line.ellipsized;
1818 let end_range_opt = starting_line.ranges.last();
1819 match end_range_opt {
1820 Some(range) if forward_pass_overflowed => {
1821 let congruent = rtl == self.spans[range.span].level.is_rtl();
1822 let mut ending_line = VisualLine::default();
1824 let start = if congruent {
1825 SpanWordGlyphPos {
1826 span: range.span,
1827 word: range.end.word,
1828 glyph: range.end.glyph,
1829 }
1830 } else {
1831 SpanWordGlyphPos {
1832 span: range.span,
1833 word: range.start.word,
1834 glyph: range.start.glyph,
1835 }
1836 };
1837 self.layout_spans(
1838 &mut ending_line,
1839 font_size,
1840 spans,
1841 Some(start),
1842 rtl,
1843 Some((width - starting_line.w - ellipsis_w).max(0.0)),
1844 Ellipsize::Start(EllipsizeHeightLimit::Lines(1)),
1845 0., LayoutDirection::Backward,
1847 );
1848 let first_half_end = if spans[range.span].level.is_rtl() != rtl {
1850 SpanWordGlyphPos {
1851 span: range.span,
1852 word: range.start.word,
1853 glyph: range.start.glyph,
1854 }
1855 } else {
1856 SpanWordGlyphPos {
1857 span: range.span,
1858 word: range.end.word,
1859 glyph: range.end.glyph,
1860 }
1861 };
1862 let second_half_start = ending_line.ranges.first().map(|r| {
1863 if spans[r.span].level.is_rtl() != rtl {
1864 SpanWordGlyphPos {
1865 span: r.span,
1866 word: r.end.word,
1867 glyph: r.end.glyph,
1868 }
1869 } else {
1870 SpanWordGlyphPos {
1871 span: r.span,
1872 word: r.start.word,
1873 glyph: r.start.glyph,
1874 }
1875 }
1876 });
1877 let actually_ellipsized = match second_half_start {
1878 Some(shs) => shs != first_half_end,
1879 None => false, };
1881 if actually_ellipsized {
1883 let ellipsis_level = self.ellipsis_level_between(
1886 starting_line.ranges.last(),
1887 ending_line.ranges.first(),
1888 );
1889 starting_line
1890 .ranges
1891 .push(self.ellipsis_vlrange(ellipsis_level));
1892 starting_line.ranges.extend(ending_line.ranges);
1893 current_visual_line.ranges = starting_line.ranges;
1894 current_visual_line.ellipsized = true;
1895 current_visual_line.w = starting_line.w + ending_line.w + ellipsis_w;
1896 } else {
1897 self.layout_spans(
1898 current_visual_line,
1899 font_size,
1900 spans,
1901 start_opt,
1902 rtl,
1903 Some(width),
1904 Ellipsize::None,
1905 0., LayoutDirection::Backward,
1907 );
1908 return;
1909 }
1910 current_visual_line.spaces = starting_line.spaces + ending_line.spaces;
1911 }
1912 _ => {
1913 log::warn!("This should be unreachable!");
1915 current_visual_line.ranges = starting_line.ranges;
1916 current_visual_line.w = starting_line.w;
1917 current_visual_line.spaces = starting_line.spaces;
1918 }
1919 }
1920 }
1921
1922 fn get_span_words(&self, span_index: usize) -> &[ShapeWord] {
1924 if span_index == ELLIPSIS_SPAN {
1925 &self
1926 .ellipsis_span
1927 .as_ref()
1928 .expect("ellipsis_span not set")
1929 .words
1930 } else {
1931 &self.spans[span_index].words
1932 }
1933 }
1934
1935 fn byte_range_of_vlrange(&self, r: &VlRange) -> Option<(usize, usize)> {
1936 debug_assert_ne!(r.span, ELLIPSIS_SPAN);
1937 let words = self.get_span_words(r.span);
1938 let mut min_byte = usize::MAX;
1939 let mut max_byte = 0usize;
1940 let end_word = r.end.word + usize::from(r.end.glyph != 0);
1941 for (i, word) in words.iter().enumerate().take(end_word).skip(r.start.word) {
1942 let included_glyphs = match (i == r.start.word, i == r.end.word) {
1943 (false, false) => &word.glyphs[..],
1944 (true, false) => &word.glyphs[r.start.glyph..],
1945 (false, true) => &word.glyphs[..r.end.glyph],
1946 (true, true) => &word.glyphs[r.start.glyph..r.end.glyph],
1947 };
1948 for glyph in included_glyphs {
1949 min_byte = min_byte.min(glyph.start);
1950 max_byte = max_byte.max(glyph.end);
1951 }
1952 }
1953 if min_byte <= max_byte {
1954 Some((min_byte, max_byte))
1955 } else {
1956 None
1957 }
1958 }
1959
1960 fn compute_elided_byte_range(
1961 &self,
1962 visual_line: &VisualLine,
1963 line_len: usize,
1964 ) -> Option<(usize, usize)> {
1965 if !visual_line.ellipsized {
1966 return None;
1967 }
1968 let ellipsis_idx = visual_line
1970 .ranges
1971 .iter()
1972 .position(|r| r.span == ELLIPSIS_SPAN)?;
1973
1974 let before_end = (0..ellipsis_idx)
1976 .rev()
1977 .find_map(|i| self.byte_range_of_vlrange(&visual_line.ranges[i]))
1978 .map(|(_, end)| end)
1979 .unwrap_or(0);
1980
1981 let after_start = (ellipsis_idx + 1..visual_line.ranges.len())
1983 .find_map(|i| self.byte_range_of_vlrange(&visual_line.ranges[i]))
1984 .map(|(start, _)| start)
1985 .unwrap_or(line_len);
1986
1987 Some((before_end, after_start))
1988 }
1989
1990 fn max_byte_offset(&self) -> usize {
1993 self.spans
1994 .iter()
1995 .flat_map(|span| span.words.iter())
1996 .flat_map(|word| word.glyphs.iter())
1997 .map(|g| g.end)
1998 .max()
1999 .unwrap_or(0)
2000 }
2001
2002 fn ellipsis_w(&self, font_size: f32) -> f32 {
2004 self.ellipsis_span
2005 .as_ref()
2006 .map_or(0.0, |s| s.words.iter().map(|w| w.width(font_size)).sum())
2007 }
2008
2009 fn ellipsis_vlrange(&self, level: unicode_bidi::Level) -> VlRange {
2011 VlRange {
2012 span: ELLIPSIS_SPAN,
2013 start: WordGlyphPos::ZERO,
2014 end: WordGlyphPos::new(1, 0),
2015 level,
2016 }
2017 }
2018
2019 fn ellipsis_level_between(
2022 &self,
2023 before: Option<&VlRange>,
2024 after: Option<&VlRange>,
2025 ) -> unicode_bidi::Level {
2026 match (before, after) {
2027 (Some(a), Some(b)) if a.level == b.level => a.level,
2028 (Some(a), None) => a.level,
2029 (None, Some(b)) => b.level,
2030 _ => {
2031 if self.rtl {
2032 unicode_bidi::Level::rtl()
2033 } else {
2034 unicode_bidi::Level::ltr()
2035 }
2036 }
2037 }
2038 }
2039
2040 fn layout_line(
2041 &self,
2042 current_visual_line: &mut VisualLine,
2043 font_size: f32,
2044 spans: &[ShapeSpan],
2045 start_opt: Option<SpanWordGlyphPos>,
2046 rtl: bool,
2047 width_opt: Option<f32>,
2048 ellipsize: Ellipsize,
2049 ) {
2050 let ellipsis_w = self.ellipsis_w(font_size);
2051
2052 match (ellipsize, width_opt) {
2053 (Ellipsize::Start(_), Some(_)) => {
2054 self.layout_spans(
2055 current_visual_line,
2056 font_size,
2057 spans,
2058 start_opt,
2059 rtl,
2060 width_opt,
2061 ellipsize,
2062 ellipsis_w,
2063 LayoutDirection::Backward,
2064 );
2065 if current_visual_line.ellipsized {
2067 let level =
2068 self.ellipsis_level_between(None, current_visual_line.ranges.first());
2069 current_visual_line
2070 .ranges
2071 .insert(0, self.ellipsis_vlrange(level));
2072 current_visual_line.w += ellipsis_w;
2073 }
2074 }
2075 (Ellipsize::Middle(_), Some(width)) => {
2076 self.layout_middle(
2077 current_visual_line,
2078 font_size,
2079 spans,
2080 start_opt,
2081 rtl,
2082 width,
2083 ellipsize,
2084 ellipsis_w,
2085 );
2086 }
2087 _ => {
2088 self.layout_spans(
2089 current_visual_line,
2090 font_size,
2091 spans,
2092 start_opt,
2093 rtl,
2094 width_opt,
2095 ellipsize,
2096 ellipsis_w,
2097 LayoutDirection::Forward,
2098 );
2099 if current_visual_line.ellipsized {
2101 let level =
2102 self.ellipsis_level_between(current_visual_line.ranges.last(), None);
2103 current_visual_line
2104 .ranges
2105 .push(self.ellipsis_vlrange(level));
2106 current_visual_line.w += ellipsis_w;
2107 }
2108 }
2109 }
2110
2111 if current_visual_line.ellipsized {
2114 let line_len = self.max_byte_offset();
2115 current_visual_line.elided_byte_range =
2116 self.compute_elided_byte_range(current_visual_line, line_len);
2117 }
2118 }
2119
2120 pub fn layout_to_buffer(
2121 &self,
2122 scratch: &mut ShapeBuffer,
2123 font_size: f32,
2124 width_opt: Option<f32>,
2125 wrap: Wrap,
2126 ellipsize: Ellipsize,
2127 align: Option<Align>,
2128 layout_lines: &mut Vec<LayoutLine>,
2129 match_mono_width: Option<f32>,
2130 hinting: Hinting,
2131 ) {
2132 let mut visual_lines = mem::take(&mut scratch.visual_lines);
2136 let mut cached_visual_lines = mem::take(&mut scratch.cached_visual_lines);
2137 cached_visual_lines.clear();
2138 cached_visual_lines.extend(visual_lines.drain(..).map(|mut l| {
2139 l.clear();
2140 l
2141 }));
2142
2143 let mut cached_glyph_sets = mem::take(&mut scratch.glyph_sets);
2145 cached_glyph_sets.clear();
2146 cached_glyph_sets.extend(layout_lines.drain(..).rev().map(|mut v| {
2147 v.glyphs.clear();
2148 v.glyphs
2149 }));
2150
2151 let mut current_visual_line = cached_visual_lines.pop().unwrap_or_default();
2156
2157 if wrap == Wrap::None {
2158 self.layout_line(
2159 &mut current_visual_line,
2160 font_size,
2161 &self.spans,
2162 None,
2163 self.rtl,
2164 width_opt,
2165 ellipsize,
2166 );
2167 } else {
2168 let mut total_line_height = 0.0;
2169 let mut total_line_count = 0;
2170 let max_line_count_opt = match ellipsize {
2171 Ellipsize::Start(EllipsizeHeightLimit::Lines(lines))
2172 | Ellipsize::Middle(EllipsizeHeightLimit::Lines(lines))
2173 | Ellipsize::End(EllipsizeHeightLimit::Lines(lines)) => Some(lines.max(1)),
2174 _ => None,
2175 };
2176 let max_height_opt = match ellipsize {
2177 Ellipsize::Start(EllipsizeHeightLimit::Height(height))
2178 | Ellipsize::Middle(EllipsizeHeightLimit::Height(height))
2179 | Ellipsize::End(EllipsizeHeightLimit::Height(height)) => Some(height),
2180 _ => None,
2181 };
2182 let line_height = self
2183 .metrics_opt
2184 .map_or_else(|| font_size, |m| m.line_height);
2185
2186 let try_ellipsize_last_line = |total_line_count: usize,
2187 total_line_height: f32,
2188 current_visual_line: &mut VisualLine,
2189 font_size: f32,
2190 start_opt: Option<SpanWordGlyphPos>,
2191 width_opt: Option<f32>,
2192 ellipsize: Ellipsize|
2193 -> bool {
2194 if max_line_count_opt == Some(total_line_count + 1)
2196 || max_height_opt.is_some_and(|max_height| {
2197 total_line_height + line_height * 2.0 > max_height
2198 })
2199 {
2200 self.layout_line(
2201 current_visual_line,
2202 font_size,
2203 &self.spans,
2204 start_opt,
2205 self.rtl,
2206 width_opt,
2207 ellipsize,
2208 );
2209 return true;
2210 }
2211 false
2212 };
2213
2214 if !try_ellipsize_last_line(
2215 total_line_count,
2216 total_line_height,
2217 &mut current_visual_line,
2218 font_size,
2219 None,
2220 width_opt,
2221 ellipsize,
2222 ) {
2223 'outer: for (span_index, span) in self.spans.iter().enumerate() {
2224 let mut word_range_width = 0.;
2225 let mut width_before_last_blank = 0.;
2226 let mut number_of_blanks: u32 = 0;
2227
2228 if self.rtl != span.level.is_rtl() {
2230 let mut fitting_start = WordGlyphPos::new(span.words.len(), 0);
2232 for (i, word) in span.words.iter().enumerate().rev() {
2233 let word_width = word.width(font_size);
2234 if current_visual_line.w + (word_range_width + word_width)
2238 <= width_opt.unwrap_or(f32::INFINITY)
2239 || (word.blank
2242 && (current_visual_line.w + word_range_width) <= width_opt.unwrap_or(f32::INFINITY))
2243 {
2244 if word.blank {
2246 number_of_blanks += 1;
2247 width_before_last_blank = word_range_width;
2248 }
2249 word_range_width += word_width;
2250 } else if wrap == Wrap::Glyph
2251 || (wrap == Wrap::WordOrGlyph && word_width > width_opt.unwrap_or(f32::INFINITY))
2253 {
2254 if word_range_width > 0.
2256 && wrap == Wrap::WordOrGlyph
2257 && word_width > width_opt.unwrap_or(f32::INFINITY)
2258 {
2259 self.add_to_visual_line(
2260 &mut current_visual_line,
2261 span_index,
2262 WordGlyphPos::new(i + 1, 0),
2263 fitting_start,
2264 word_range_width,
2265 number_of_blanks,
2266 );
2267
2268 visual_lines.push(current_visual_line);
2269 current_visual_line =
2270 cached_visual_lines.pop().unwrap_or_default();
2271
2272 number_of_blanks = 0;
2273 word_range_width = 0.;
2274
2275 fitting_start = WordGlyphPos::new(i, 0);
2276 total_line_count += 1;
2277 total_line_height += line_height;
2278 if try_ellipsize_last_line(
2279 total_line_count,
2280 total_line_height,
2281 &mut current_visual_line,
2282 font_size,
2283 Some(SpanWordGlyphPos::with_wordglyph(
2284 span_index,
2285 fitting_start,
2286 )),
2287 width_opt,
2288 ellipsize,
2289 ) {
2290 break 'outer;
2291 }
2292 }
2293
2294 for (glyph_i, glyph) in word.glyphs.iter().enumerate().rev() {
2295 let glyph_width = glyph.width(font_size);
2296 if current_visual_line.w + (word_range_width + glyph_width)
2297 <= width_opt.unwrap_or(f32::INFINITY)
2298 {
2299 word_range_width += glyph_width;
2300 } else {
2301 self.add_to_visual_line(
2302 &mut current_visual_line,
2303 span_index,
2304 WordGlyphPos::new(i, glyph_i + 1),
2305 fitting_start,
2306 word_range_width,
2307 number_of_blanks,
2308 );
2309 visual_lines.push(current_visual_line);
2310 current_visual_line =
2311 cached_visual_lines.pop().unwrap_or_default();
2312
2313 number_of_blanks = 0;
2314 word_range_width = glyph_width;
2315 fitting_start = WordGlyphPos::new(i, glyph_i + 1);
2316 total_line_count += 1;
2317 total_line_height += line_height;
2318 if try_ellipsize_last_line(
2319 total_line_count,
2320 total_line_height,
2321 &mut current_visual_line,
2322 font_size,
2323 Some(SpanWordGlyphPos::with_wordglyph(
2324 span_index,
2325 fitting_start,
2326 )),
2327 width_opt,
2328 ellipsize,
2329 ) {
2330 break 'outer;
2331 }
2332 }
2333 }
2334 } else {
2335 if word_range_width > 0. {
2339 let trailing_blank = span
2342 .words
2343 .get(i + 1)
2344 .is_some_and(|previous_word| previous_word.blank);
2345
2346 if trailing_blank {
2347 number_of_blanks = number_of_blanks.saturating_sub(1);
2348 self.add_to_visual_line(
2349 &mut current_visual_line,
2350 span_index,
2351 WordGlyphPos::new(i + 2, 0),
2352 fitting_start,
2353 width_before_last_blank,
2354 number_of_blanks,
2355 );
2356 } else {
2357 self.add_to_visual_line(
2358 &mut current_visual_line,
2359 span_index,
2360 WordGlyphPos::new(i + 1, 0),
2361 fitting_start,
2362 word_range_width,
2363 number_of_blanks,
2364 );
2365 }
2366 }
2367
2368 if !current_visual_line.ranges.is_empty() {
2371 visual_lines.push(current_visual_line);
2372 current_visual_line =
2373 cached_visual_lines.pop().unwrap_or_default();
2374 number_of_blanks = 0;
2375 total_line_count += 1;
2376 total_line_height += line_height;
2377
2378 if try_ellipsize_last_line(
2379 total_line_count,
2380 total_line_height,
2381 &mut current_visual_line,
2382 font_size,
2383 Some(SpanWordGlyphPos::with_wordglyph(
2384 span_index,
2385 if word.blank {
2386 WordGlyphPos::new(i, 0)
2387 } else {
2388 WordGlyphPos::new(i + 1, 0)
2389 },
2390 )),
2391 width_opt,
2392 ellipsize,
2393 ) {
2394 break 'outer;
2395 }
2396 }
2397
2398 if word.blank {
2399 word_range_width = 0.;
2400 fitting_start = WordGlyphPos::new(i, 0);
2401 } else {
2402 word_range_width = word_width;
2403 fitting_start = WordGlyphPos::new(i + 1, 0);
2404 }
2405 }
2406 }
2407 self.add_to_visual_line(
2408 &mut current_visual_line,
2409 span_index,
2410 WordGlyphPos::new(0, 0),
2411 fitting_start,
2412 word_range_width,
2413 number_of_blanks,
2414 );
2415 } else {
2416 let mut fitting_start = WordGlyphPos::ZERO;
2418 for (i, word) in span.words.iter().enumerate() {
2419 let word_width = word.width(font_size);
2420 if current_visual_line.w + (word_range_width + word_width)
2421 <= width_opt.unwrap_or(f32::INFINITY)
2422 || (word.blank
2425 && (current_visual_line.w + word_range_width) <= width_opt.unwrap_or(f32::INFINITY))
2426 {
2427 if word.blank {
2429 number_of_blanks += 1;
2430 width_before_last_blank = word_range_width;
2431 }
2432 word_range_width += word_width;
2433 } else if wrap == Wrap::Glyph
2434 || (wrap == Wrap::WordOrGlyph && word_width > width_opt.unwrap_or(f32::INFINITY))
2436 {
2437 if word_range_width > 0.
2439 && wrap == Wrap::WordOrGlyph
2440 && word_width > width_opt.unwrap_or(f32::INFINITY)
2441 {
2442 self.add_to_visual_line(
2443 &mut current_visual_line,
2444 span_index,
2445 fitting_start,
2446 WordGlyphPos::new(i, 0),
2447 word_range_width,
2448 number_of_blanks,
2449 );
2450
2451 visual_lines.push(current_visual_line);
2452 current_visual_line =
2453 cached_visual_lines.pop().unwrap_or_default();
2454
2455 number_of_blanks = 0;
2456 word_range_width = 0.;
2457
2458 fitting_start = WordGlyphPos::new(i, 0);
2459 total_line_count += 1;
2460 total_line_height += line_height;
2461 if try_ellipsize_last_line(
2462 total_line_count,
2463 total_line_height,
2464 &mut current_visual_line,
2465 font_size,
2466 Some(SpanWordGlyphPos::with_wordglyph(
2467 span_index,
2468 fitting_start,
2469 )),
2470 width_opt,
2471 ellipsize,
2472 ) {
2473 break 'outer;
2474 }
2475 }
2476
2477 for (glyph_i, glyph) in word.glyphs.iter().enumerate() {
2478 let glyph_width = glyph.width(font_size);
2479 if current_visual_line.w + (word_range_width + glyph_width)
2480 <= width_opt.unwrap_or(f32::INFINITY)
2481 {
2482 word_range_width += glyph_width;
2483 } else {
2484 self.add_to_visual_line(
2485 &mut current_visual_line,
2486 span_index,
2487 fitting_start,
2488 WordGlyphPos::new(i, glyph_i),
2489 word_range_width,
2490 number_of_blanks,
2491 );
2492 visual_lines.push(current_visual_line);
2493 current_visual_line =
2494 cached_visual_lines.pop().unwrap_or_default();
2495
2496 number_of_blanks = 0;
2497 word_range_width = glyph_width;
2498 fitting_start = WordGlyphPos::new(i, glyph_i);
2499 total_line_count += 1;
2500 total_line_height += line_height;
2501 if try_ellipsize_last_line(
2502 total_line_count,
2503 total_line_height,
2504 &mut current_visual_line,
2505 font_size,
2506 Some(SpanWordGlyphPos::with_wordglyph(
2507 span_index,
2508 fitting_start,
2509 )),
2510 width_opt,
2511 ellipsize,
2512 ) {
2513 break 'outer;
2514 }
2515 }
2516 }
2517 } else {
2518 if word_range_width > 0. {
2522 let trailing_blank = i > 0 && span.words[i - 1].blank;
2525
2526 if trailing_blank {
2527 number_of_blanks = number_of_blanks.saturating_sub(1);
2528 self.add_to_visual_line(
2529 &mut current_visual_line,
2530 span_index,
2531 fitting_start,
2532 WordGlyphPos::new(i - 1, 0),
2533 width_before_last_blank,
2534 number_of_blanks,
2535 );
2536 } else {
2537 self.add_to_visual_line(
2538 &mut current_visual_line,
2539 span_index,
2540 fitting_start,
2541 WordGlyphPos::new(i, 0),
2542 word_range_width,
2543 number_of_blanks,
2544 );
2545 }
2546 }
2547
2548 if !current_visual_line.ranges.is_empty() {
2549 visual_lines.push(current_visual_line);
2550 current_visual_line =
2551 cached_visual_lines.pop().unwrap_or_default();
2552 number_of_blanks = 0;
2553 total_line_count += 1;
2554 total_line_height += line_height;
2555 if try_ellipsize_last_line(
2556 total_line_count,
2557 total_line_height,
2558 &mut current_visual_line,
2559 font_size,
2560 Some(SpanWordGlyphPos::with_wordglyph(
2561 span_index,
2562 if i > 0 && span.words[i - 1].blank {
2563 WordGlyphPos::new(i - 1, 0)
2564 } else {
2565 WordGlyphPos::new(i, 0)
2566 },
2567 )),
2568 width_opt,
2569 ellipsize,
2570 ) {
2571 break 'outer;
2572 }
2573 }
2574
2575 if word.blank {
2576 word_range_width = 0.;
2577 fitting_start = WordGlyphPos::new(i + 1, 0);
2578 } else {
2579 word_range_width = word_width;
2580 fitting_start = WordGlyphPos::new(i, 0);
2581 }
2582 }
2583 }
2584 self.add_to_visual_line(
2585 &mut current_visual_line,
2586 span_index,
2587 fitting_start,
2588 WordGlyphPos::new(span.words.len(), 0),
2589 word_range_width,
2590 number_of_blanks,
2591 );
2592 }
2593 }
2594 }
2595 }
2596
2597 if current_visual_line.ranges.is_empty() {
2598 current_visual_line.clear();
2599 cached_visual_lines.push(current_visual_line);
2600 } else {
2601 visual_lines.push(current_visual_line);
2602 }
2603
2604 let align = align.unwrap_or(if self.rtl { Align::Right } else { Align::Left });
2606
2607 let line_width = width_opt.unwrap_or_else(|| {
2608 let mut width: f32 = 0.0;
2609 for visual_line in &visual_lines {
2610 width = width.max(visual_line.w);
2611 }
2612 width
2613 });
2614
2615 let start_x = if self.rtl { line_width } else { 0.0 };
2616
2617 let number_of_visual_lines = visual_lines.len();
2618 for (index, visual_line) in visual_lines.iter().enumerate() {
2619 if visual_line.ranges.is_empty() {
2620 continue;
2621 }
2622
2623 let new_order = self.reorder(&visual_line.ranges);
2624
2625 let mut glyphs = cached_glyph_sets
2626 .pop()
2627 .unwrap_or_else(|| Vec::with_capacity(1));
2628 let mut x = start_x;
2629 let mut y = 0.;
2630 let mut max_ascent: f32 = 0.;
2631 let mut max_descent: f32 = 0.;
2632 let alignment_correction = match (align, self.rtl) {
2633 (Align::Left, true) => (line_width - visual_line.w).max(0.),
2634 (Align::Left, false) => 0.,
2635 (Align::Right, true) => 0.,
2636 (Align::Right, false) => (line_width - visual_line.w).max(0.),
2637 (Align::Center, _) => (line_width - visual_line.w).max(0.) / 2.0,
2638 (Align::End, _) => (line_width - visual_line.w).max(0.),
2639 (Align::Justified, _) => 0.,
2640 };
2641
2642 if self.rtl {
2643 x -= alignment_correction;
2644 } else {
2645 x += alignment_correction;
2646 }
2647
2648 if hinting == Hinting::Enabled {
2649 x = x.round();
2650 }
2651
2652 let justification_expansion = if matches!(align, Align::Justified)
2668 && visual_line.spaces > 0
2669 && index != number_of_visual_lines - 1
2671 {
2672 (line_width - visual_line.w) / visual_line.spaces as f32
2673 } else {
2674 0.
2675 };
2676
2677 let elided_byte_range = if visual_line.ellipsized {
2678 visual_line.elided_byte_range
2679 } else {
2680 None
2681 };
2682
2683 let process_range = |range: Range<usize>,
2684 x: &mut f32,
2685 y: &mut f32,
2686 glyphs: &mut Vec<LayoutGlyph>,
2687 max_ascent: &mut f32,
2688 max_descent: &mut f32| {
2689 for r in visual_line.ranges[range.clone()].iter() {
2690 let is_ellipsis = r.span == ELLIPSIS_SPAN;
2691 let span_words = self.get_span_words(r.span);
2692 for i in r.start.word..r.end.word + usize::from(r.end.glyph != 0) {
2694 let word = &span_words[i];
2695 let included_glyphs = match (i == r.start.word, i == r.end.word) {
2696 (false, false) => &word.glyphs[..],
2697 (true, false) => &word.glyphs[r.start.glyph..],
2698 (false, true) => &word.glyphs[..r.end.glyph],
2699 (true, true) => &word.glyphs[r.start.glyph..r.end.glyph],
2700 };
2701
2702 for glyph in included_glyphs {
2703 let font_size = glyph.metrics_opt.map_or(font_size, |x| x.font_size);
2705
2706 let match_mono_em_width = match_mono_width.map(|w| w / font_size);
2707
2708 let glyph_font_size = match (
2709 match_mono_em_width,
2710 glyph.font_monospace_em_width,
2711 ) {
2712 (Some(match_em_width), Some(glyph_em_width))
2713 if glyph_em_width != match_em_width =>
2714 {
2715 let glyph_to_match_factor = glyph_em_width / match_em_width;
2716 let glyph_font_size = math::roundf(glyph_to_match_factor)
2717 .max(1.0)
2718 / glyph_to_match_factor
2719 * font_size;
2720 log::trace!(
2721 "Adjusted glyph font size ({font_size} => {glyph_font_size})"
2722 );
2723 glyph_font_size
2724 }
2725 _ => font_size,
2726 };
2727
2728 let mut x_advance = glyph_font_size.mul_add(
2729 glyph.x_advance,
2730 if word.blank {
2731 justification_expansion
2732 } else {
2733 0.0
2734 },
2735 );
2736 if let Some(match_em_width) = match_mono_em_width {
2737 x_advance = ((x_advance / match_em_width).round()) * match_em_width;
2739 }
2740 if hinting == Hinting::Enabled {
2741 x_advance = x_advance.round();
2742 }
2743 if self.rtl {
2744 *x -= x_advance;
2745 }
2746 let y_advance = glyph_font_size * glyph.y_advance;
2747 let mut layout_glyph = glyph.layout(
2748 glyph_font_size,
2749 glyph.metrics_opt.map(|x| x.line_height),
2750 *x,
2751 *y,
2752 x_advance,
2753 r.level,
2754 );
2755 if is_ellipsis {
2760 if let Some((elided_start, elided_end)) = elided_byte_range {
2761 let boundary = if elided_start == 0 {
2767 elided_end
2768 } else {
2769 elided_start
2770 };
2771 layout_glyph.start = boundary;
2772 layout_glyph.end = boundary;
2773 }
2774 }
2775 glyphs.push(layout_glyph);
2776 if !self.rtl {
2777 *x += x_advance;
2778 }
2779 *y += y_advance;
2780 *max_ascent = max_ascent.max(glyph_font_size * glyph.ascent);
2781 *max_descent = max_descent.max(glyph_font_size * glyph.descent);
2782 }
2783 }
2784 }
2785 };
2786
2787 if self.rtl {
2788 for range in new_order.into_iter().rev() {
2789 process_range(
2790 range,
2791 &mut x,
2792 &mut y,
2793 &mut glyphs,
2794 &mut max_ascent,
2795 &mut max_descent,
2796 );
2797 }
2798 } else {
2799 for range in new_order {
2801 process_range(
2802 range,
2803 &mut x,
2804 &mut y,
2805 &mut glyphs,
2806 &mut max_ascent,
2807 &mut max_descent,
2808 );
2809 }
2810 }
2811
2812 let mut line_height_opt: Option<f32> = None;
2813 for glyph in &glyphs {
2814 if let Some(glyph_line_height) = glyph.line_height_opt {
2815 line_height_opt = line_height_opt
2816 .map_or(Some(glyph_line_height), |line_height| {
2817 Some(line_height.max(glyph_line_height))
2818 });
2819 }
2820 }
2821
2822 layout_lines.push(LayoutLine {
2823 w: if align != Align::Justified {
2824 visual_line.w
2825 } else if self.rtl {
2826 start_x - x
2827 } else {
2828 x
2829 },
2830 max_ascent,
2831 max_descent,
2832 line_height_opt,
2833 glyphs,
2834 });
2835 }
2836
2837 if layout_lines.is_empty() {
2839 layout_lines.push(LayoutLine {
2840 w: 0.0,
2841 max_ascent: 0.0,
2842 max_descent: 0.0,
2843 line_height_opt: self.metrics_opt.map(|x| x.line_height),
2844 glyphs: Vec::default(),
2845 });
2846 }
2847
2848 scratch.visual_lines = visual_lines;
2850 scratch.visual_lines.append(&mut cached_visual_lines);
2851 scratch.cached_visual_lines = cached_visual_lines;
2852 scratch.glyph_sets = cached_glyph_sets;
2853 }
2854}