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