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