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