1#![allow(clippy::too_many_arguments)]
4
5#[cfg(not(feature = "std"))]
6use alloc::vec::Vec;
7use core::cmp::{max, min};
8use core::fmt;
9use core::mem;
10use core::ops::Range;
11use unicode_script::{Script, UnicodeScript};
12use unicode_segmentation::UnicodeSegmentation;
13
14use crate::fallback::FontFallbackIter;
15use crate::{
16 math, Align, AttrsList, CacheKeyFlags, Color, Font, FontSystem, LayoutGlyph, LayoutLine,
17 Metrics, Wrap,
18};
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
22pub enum Shaping {
23 #[cfg(feature = "swash")]
31 Basic,
32 Advanced,
38}
39
40impl Shaping {
41 fn run(
42 self,
43 glyphs: &mut Vec<ShapeGlyph>,
44 font_system: &mut FontSystem,
45 line: &str,
46 attrs_list: &AttrsList,
47 start_run: usize,
48 end_run: usize,
49 span_rtl: bool,
50 ) {
51 match self {
52 #[cfg(feature = "swash")]
53 Self::Basic => shape_skip(font_system, glyphs, line, attrs_list, start_run, end_run),
54 #[cfg(not(feature = "shape-run-cache"))]
55 Self::Advanced => shape_run(
56 glyphs,
57 font_system,
58 line,
59 attrs_list,
60 start_run,
61 end_run,
62 span_rtl,
63 ),
64 #[cfg(feature = "shape-run-cache")]
65 Self::Advanced => shape_run_cached(
66 glyphs,
67 font_system,
68 line,
69 attrs_list,
70 start_run,
71 end_run,
72 span_rtl,
73 ),
74 }
75 }
76}
77
78#[derive(Default)]
80pub struct ShapeBuffer {
81 rustybuzz_buffer: Option<rustybuzz::UnicodeBuffer>,
83
84 scripts: Vec<Script>,
86
87 spans: Vec<ShapeSpan>,
89
90 words: Vec<ShapeWord>,
92
93 visual_lines: Vec<VisualLine>,
95 cached_visual_lines: Vec<VisualLine>,
96
97 glyph_sets: Vec<Vec<LayoutGlyph>>,
99}
100
101impl fmt::Debug for ShapeBuffer {
102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103 f.pad("ShapeBuffer { .. }")
104 }
105}
106
107fn shape_fallback(
108 scratch: &mut ShapeBuffer,
109 glyphs: &mut Vec<ShapeGlyph>,
110 font: &Font,
111 line: &str,
112 attrs_list: &AttrsList,
113 start_run: usize,
114 end_run: usize,
115 span_rtl: bool,
116) -> Vec<usize> {
117 let run = &line[start_run..end_run];
118
119 let font_scale = font.rustybuzz().units_per_em() as f32;
120 let ascent = font.rustybuzz().ascender() as f32 / font_scale;
121 let descent = -font.rustybuzz().descender() as f32 / font_scale;
122
123 let mut buffer = scratch.rustybuzz_buffer.take().unwrap_or_default();
124 buffer.set_direction(if span_rtl {
125 rustybuzz::Direction::RightToLeft
126 } else {
127 rustybuzz::Direction::LeftToRight
128 });
129 if run.contains('\t') {
130 buffer.push_str(&run.replace('\t', " "));
135 } else {
136 buffer.push_str(run);
137 }
138 buffer.guess_segment_properties();
139
140 let rtl = matches!(buffer.direction(), rustybuzz::Direction::RightToLeft);
141 assert_eq!(rtl, span_rtl);
142
143 let _attrs = attrs_list.get_span(start_run);
144 let rb_font_features = vec![
158 rustybuzz::Feature::new(rustybuzz::ttf_parser::Tag::from_bytes(b"liga"), 0, 0..usize::MAX),
159 rustybuzz::Feature::new(rustybuzz::ttf_parser::Tag::from_bytes(b"clig"), 0, 0..usize::MAX),
160 rustybuzz::Feature::new(rustybuzz::ttf_parser::Tag::from_bytes(b"dlig"), 0, 0..usize::MAX),
161 rustybuzz::Feature::new(rustybuzz::ttf_parser::Tag::from_bytes(b"rlig"), 0, 0..usize::MAX),
162 ];
163
164 let shape_plan = rustybuzz::ShapePlan::new(
165 font.rustybuzz(),
166 buffer.direction(),
167 Some(buffer.script()),
168 buffer.language().as_ref(),
169 &rb_font_features,
170 );
171 let glyph_buffer = rustybuzz::shape_with_plan(font.rustybuzz(), &shape_plan, buffer);
172 let glyph_infos = glyph_buffer.glyph_infos();
173 let glyph_positions = glyph_buffer.glyph_positions();
174
175 let mut missing = Vec::new();
176 glyphs.reserve(glyph_infos.len());
177 let glyph_start = glyphs.len();
178 for (info, pos) in glyph_infos.iter().zip(glyph_positions.iter()) {
179 let start_glyph = start_run + info.cluster as usize;
180
181 if info.glyph_id == 0 {
182 missing.push(start_glyph);
183 }
184
185 let attrs = attrs_list.get_span(start_glyph);
186 let x_advance = pos.x_advance as f32 / font_scale
187 + attrs.letter_spacing_opt.map_or(0.0, |spacing| spacing.0);
188 let y_advance = pos.y_advance as f32 / font_scale;
189 let x_offset = pos.x_offset as f32 / font_scale;
190 let y_offset = pos.y_offset as f32 / font_scale;
191
192 glyphs.push(ShapeGlyph {
193 start: start_glyph,
194 end: end_run, x_advance,
196 y_advance,
197 x_offset,
198 y_offset,
199 ascent,
200 descent,
201 font_monospace_em_width: font.monospace_em_width(),
202 font_id: font.id(),
203 glyph_id: info.glyph_id.try_into().expect("failed to cast glyph ID"),
204 color_opt: attrs.color_opt,
206 metadata: attrs.metadata,
207 cache_key_flags: attrs.cache_key_flags,
208 metrics_opt: attrs.metrics_opt.map(|x| x.into()),
209 });
210 }
211
212 if rtl {
214 for i in glyph_start + 1..glyphs.len() {
215 let next_start = glyphs[i - 1].start;
216 let next_end = glyphs[i - 1].end;
217 let prev = &mut glyphs[i];
218 if prev.start == next_start {
219 prev.end = next_end;
220 } else {
221 prev.end = next_start;
222 }
223 }
224 } else {
225 for i in (glyph_start + 1..glyphs.len()).rev() {
226 let next_start = glyphs[i].start;
227 let next_end = glyphs[i].end;
228 let prev = &mut glyphs[i - 1];
229 if prev.start == next_start {
230 prev.end = next_end;
231 } else {
232 prev.end = next_start;
233 }
234 }
235 }
236
237 scratch.rustybuzz_buffer = Some(glyph_buffer.clear());
239
240 missing
241}
242
243fn shape_run(
244 glyphs: &mut Vec<ShapeGlyph>,
245 font_system: &mut FontSystem,
246 line: &str,
247 attrs_list: &AttrsList,
248 start_run: usize,
249 end_run: usize,
250 span_rtl: bool,
251) {
252 let mut scripts = {
254 let mut scripts = mem::take(&mut font_system.shape_buffer.scripts);
255 scripts.clear();
256 scripts
257 };
258 for c in line[start_run..end_run].chars() {
259 match c.script() {
260 Script::Common | Script::Inherited | Script::Latin | Script::Unknown => (),
261 script => {
262 if !scripts.contains(&script) {
263 scripts.push(script);
264 }
265 }
266 }
267 }
268
269 log::trace!(" Run {:?}: '{}'", &scripts, &line[start_run..end_run],);
270
271 let attrs = attrs_list.get_span(start_run);
272
273 let fonts = font_system.get_font_matches(&attrs);
274
275 let default_families = [&attrs.family];
276 let mut font_iter = FontFallbackIter::new(
277 font_system,
278 &fonts,
279 &default_families,
280 &scripts,
281 &line[start_run..end_run],
282 );
283
284 let font = font_iter.next().expect("no default font found");
285
286 let glyph_start = glyphs.len();
287 let mut missing = {
288 let scratch = font_iter.shape_caches();
289 shape_fallback(
290 scratch, glyphs, &font, line, attrs_list, start_run, end_run, span_rtl,
291 )
292 };
293
294 while !missing.is_empty() {
296 let font = match font_iter.next() {
297 Some(some) => some,
298 None => break,
299 };
300
301 log::trace!(
302 "Evaluating fallback with font '{}'",
303 font_iter.face_name(font.id())
304 );
305 let mut fb_glyphs = Vec::new();
306 let scratch = font_iter.shape_caches();
307 let fb_missing = shape_fallback(
308 scratch,
309 &mut fb_glyphs,
310 &font,
311 line,
312 attrs_list,
313 start_run,
314 end_run,
315 span_rtl,
316 );
317
318 let mut fb_i = 0;
320 while fb_i < fb_glyphs.len() {
321 let start = fb_glyphs[fb_i].start;
322 let end = fb_glyphs[fb_i].end;
323
324 if !missing.contains(&start) || fb_missing.contains(&start) {
326 fb_i += 1;
327 continue;
328 }
329
330 let mut missing_i = 0;
331 while missing_i < missing.len() {
332 if missing[missing_i] >= start && missing[missing_i] < end {
333 missing.remove(missing_i);
335 } else {
336 missing_i += 1;
337 }
338 }
339
340 let mut i = glyph_start;
342 while i < glyphs.len() {
343 if glyphs[i].start >= start && glyphs[i].end <= end {
344 break;
345 } else {
346 i += 1;
347 }
348 }
349
350 while i < glyphs.len() {
352 if glyphs[i].start >= start && glyphs[i].end <= end {
353 let _glyph = glyphs.remove(i);
354 } else {
356 break;
357 }
358 }
359
360 while fb_i < fb_glyphs.len() {
361 if fb_glyphs[fb_i].start >= start && fb_glyphs[fb_i].end <= end {
362 let fb_glyph = fb_glyphs.remove(fb_i);
363 glyphs.insert(i, fb_glyph);
365 i += 1;
366 } else {
367 break;
368 }
369 }
370 }
371 }
372
373 font_iter.check_missing(&line[start_run..end_run]);
375
376 font_system.shape_buffer.scripts = scripts;
384}
385
386#[cfg(feature = "shape-run-cache")]
387fn shape_run_cached(
388 glyphs: &mut Vec<ShapeGlyph>,
389 font_system: &mut FontSystem,
390 line: &str,
391 attrs_list: &AttrsList,
392 start_run: usize,
393 end_run: usize,
394 span_rtl: bool,
395) {
396 use crate::{AttrsOwned, ShapeRunKey};
397
398 let run_range = start_run..end_run;
399 let mut key = ShapeRunKey {
400 text: line[run_range.clone()].to_string(),
401 default_attrs: AttrsOwned::new(&attrs_list.defaults()),
402 attrs_spans: Vec::new(),
403 };
404 for (attrs_range, attrs) in attrs_list.spans.overlapping(&run_range) {
405 if attrs == &key.default_attrs {
406 continue;
408 }
409 let start = max(attrs_range.start, start_run).saturating_sub(start_run);
410 let end = min(attrs_range.end, end_run).saturating_sub(start_run);
411 if end > start {
412 let range = start..end;
413 key.attrs_spans.push((range, attrs.clone()));
414 }
415 }
416 if let Some(cache_glyphs) = font_system.shape_run_cache.get(&key) {
417 for mut glyph in cache_glyphs.iter().cloned() {
418 glyph.start += start_run;
420 glyph.end += start_run;
421 glyphs.push(glyph);
422 }
423 return;
424 }
425
426 let mut cache_glyphs = Vec::new();
428 shape_run(
429 &mut cache_glyphs,
430 font_system,
431 line,
432 attrs_list,
433 start_run,
434 end_run,
435 span_rtl,
436 );
437 glyphs.extend_from_slice(&cache_glyphs);
438 for glyph in cache_glyphs.iter_mut() {
439 glyph.start -= start_run;
441 glyph.end -= start_run;
442 }
443 font_system.shape_run_cache.insert(key, cache_glyphs);
444}
445
446#[cfg(feature = "swash")]
447fn shape_skip(
448 font_system: &mut FontSystem,
449 glyphs: &mut Vec<ShapeGlyph>,
450 line: &str,
451 attrs_list: &AttrsList,
452 start_run: usize,
453 end_run: usize,
454) {
455 let attrs = attrs_list.get_span(start_run);
456 let fonts = font_system.get_font_matches(&attrs);
457
458 let default_families = [&attrs.family];
459 let mut font_iter = FontFallbackIter::new(font_system, &fonts, &default_families, &[], "");
460
461 let font = font_iter.next().expect("no default font found");
462 let font_id = font.id();
463 let font_monospace_em_width = font.monospace_em_width();
464 let font = font.as_swash();
465
466 let charmap = font.charmap();
467 let metrics = font.metrics(&[]);
468 let glyph_metrics = font.glyph_metrics(&[]).scale(1.0);
469
470 let ascent = metrics.ascent / f32::from(metrics.units_per_em);
471 let descent = metrics.descent / f32::from(metrics.units_per_em);
472
473 glyphs.extend(
474 line[start_run..end_run]
475 .char_indices()
476 .map(|(chr_idx, codepoint)| {
477 let glyph_id = charmap.map(codepoint);
478 let x_advance = glyph_metrics.advance_width(glyph_id)
479 + attrs.letter_spacing_opt.map_or(0.0, |spacing| spacing.0);
480 let attrs = attrs_list.get_span(start_run + chr_idx);
481
482 ShapeGlyph {
483 start: chr_idx + start_run,
484 end: chr_idx + start_run + codepoint.len_utf8(),
485 x_advance,
486 y_advance: 0.0,
487 x_offset: 0.0,
488 y_offset: 0.0,
489 ascent,
490 descent,
491 font_monospace_em_width,
492 font_id,
493 glyph_id,
494 color_opt: attrs.color_opt,
495 metadata: attrs.metadata,
496 cache_key_flags: attrs.cache_key_flags,
497 metrics_opt: attrs.metrics_opt.map(|x| x.into()),
498 }
499 }),
500 );
501}
502
503#[derive(Clone, Debug)]
505pub struct ShapeGlyph {
506 pub start: usize,
507 pub end: usize,
508 pub x_advance: f32,
509 pub y_advance: f32,
510 pub x_offset: f32,
511 pub y_offset: f32,
512 pub ascent: f32,
513 pub descent: f32,
514 pub font_monospace_em_width: Option<f32>,
515 pub font_id: fontdb::ID,
516 pub glyph_id: u16,
517 pub color_opt: Option<Color>,
518 pub metadata: usize,
519 pub cache_key_flags: CacheKeyFlags,
520 pub metrics_opt: Option<Metrics>,
521}
522
523impl ShapeGlyph {
524 fn layout(
525 &self,
526 font_size: f32,
527 line_height_opt: Option<f32>,
528 x: f32,
529 y: f32,
530 w: f32,
531 level: unicode_bidi::Level,
532 ) -> LayoutGlyph {
533 LayoutGlyph {
534 start: self.start,
535 end: self.end,
536 font_size,
537 line_height_opt,
538 font_id: self.font_id,
539 glyph_id: self.glyph_id,
540 x,
541 y,
542 w,
543 level,
544 x_offset: self.x_offset,
545 y_offset: self.y_offset,
546 color_opt: self.color_opt,
547 metadata: self.metadata,
548 cache_key_flags: self.cache_key_flags,
549 }
550 }
551
552 pub fn width(&self, font_size: f32) -> f32 {
555 self.metrics_opt.map_or(font_size, |x| x.font_size) * self.x_advance
556 }
557}
558
559#[derive(Clone, Debug)]
561pub struct ShapeWord {
562 pub blank: bool,
563 pub glyphs: Vec<ShapeGlyph>,
564}
565
566impl ShapeWord {
567 pub(crate) fn empty() -> Self {
571 Self {
572 blank: true,
573 glyphs: Vec::default(),
574 }
575 }
576
577 #[allow(clippy::too_many_arguments)]
579 pub fn new(
580 font_system: &mut FontSystem,
581 line: &str,
582 attrs_list: &AttrsList,
583 word_range: Range<usize>,
584 level: unicode_bidi::Level,
585 blank: bool,
586 shaping: Shaping,
587 ) -> Self {
588 let mut empty = Self::empty();
589 empty.build(
590 font_system,
591 line,
592 attrs_list,
593 word_range,
594 level,
595 blank,
596 shaping,
597 );
598 empty
599 }
600
601 #[allow(clippy::too_many_arguments)]
605 pub fn build(
606 &mut self,
607 font_system: &mut FontSystem,
608 line: &str,
609 attrs_list: &AttrsList,
610 word_range: Range<usize>,
611 level: unicode_bidi::Level,
612 blank: bool,
613 shaping: Shaping,
614 ) {
615 let word = &line[word_range.clone()];
616
617 log::trace!(
618 " Word{}: '{}'",
619 if blank { " BLANK" } else { "" },
620 word
621 );
622
623 let mut glyphs = mem::take(&mut self.glyphs);
624 glyphs.clear();
625
626 let span_rtl = level.is_rtl();
627
628 let mut start_run = word_range.start;
629 let mut attrs = attrs_list.defaults();
630 for (egc_i, _egc) in word.grapheme_indices(true) {
631 let start_egc = word_range.start + egc_i;
632 let attrs_egc = attrs_list.get_span(start_egc);
633 if !attrs.compatible(&attrs_egc) {
634 shaping.run(
635 &mut glyphs,
636 font_system,
637 line,
638 attrs_list,
639 start_run,
640 start_egc,
641 span_rtl,
642 );
643
644 start_run = start_egc;
645 attrs = attrs_egc;
646 }
647 }
648 if start_run < word_range.end {
649 shaping.run(
650 &mut glyphs,
651 font_system,
652 line,
653 attrs_list,
654 start_run,
655 word_range.end,
656 span_rtl,
657 );
658 }
659
660 self.blank = blank;
661 self.glyphs = glyphs;
662 }
663
664 pub fn width(&self, font_size: f32) -> f32 {
666 let mut width = 0.0;
667 for glyph in self.glyphs.iter() {
668 width += glyph.width(font_size);
669 }
670 width
671 }
672}
673
674#[derive(Clone, Debug)]
676pub struct ShapeSpan {
677 pub level: unicode_bidi::Level,
678 pub words: Vec<ShapeWord>,
679}
680
681impl ShapeSpan {
682 pub(crate) fn empty() -> Self {
686 Self {
687 level: unicode_bidi::Level::ltr(),
688 words: Vec::default(),
689 }
690 }
691
692 pub fn new(
694 font_system: &mut FontSystem,
695 line: &str,
696 attrs_list: &AttrsList,
697 span_range: Range<usize>,
698 line_rtl: bool,
699 level: unicode_bidi::Level,
700 shaping: Shaping,
701 ) -> Self {
702 let mut empty = Self::empty();
703 empty.build(
704 font_system,
705 line,
706 attrs_list,
707 span_range,
708 line_rtl,
709 level,
710 shaping,
711 );
712 empty
713 }
714
715 pub fn build(
719 &mut self,
720 font_system: &mut FontSystem,
721 line: &str,
722 attrs_list: &AttrsList,
723 span_range: Range<usize>,
724 line_rtl: bool,
725 level: unicode_bidi::Level,
726 shaping: Shaping,
727 ) {
728 let span = &line[span_range.start..span_range.end];
729
730 log::trace!(
731 " Span {}: '{}'",
732 if level.is_rtl() { "RTL" } else { "LTR" },
733 span
734 );
735
736 let mut words = mem::take(&mut self.words);
737
738 let mut cached_words = mem::take(&mut font_system.shape_buffer.words);
740 cached_words.clear();
741 if line_rtl != level.is_rtl() {
742 cached_words.append(&mut words);
744 } else {
745 cached_words.extend(words.drain(..).rev());
746 }
747
748 let mut start_word = 0;
749 for (end_lb, _) in unicode_linebreak::linebreaks(span) {
750 let mut start_lb = end_lb;
751 for (i, c) in span[start_word..end_lb].char_indices().rev() {
752 if c.is_whitespace() {
757 start_lb = start_word + i;
758 } else {
759 break;
760 }
761 }
762 if start_word < start_lb {
763 let mut word = cached_words.pop().unwrap_or_else(ShapeWord::empty);
764 word.build(
765 font_system,
766 line,
767 attrs_list,
768 (span_range.start + start_word)..(span_range.start + start_lb),
769 level,
770 false,
771 shaping,
772 );
773 words.push(word);
774 }
775 if start_lb < end_lb {
776 for (i, c) in span[start_lb..end_lb].char_indices() {
777 let mut word = cached_words.pop().unwrap_or_else(ShapeWord::empty);
779 word.build(
780 font_system,
781 line,
782 attrs_list,
783 (span_range.start + start_lb + i)
784 ..(span_range.start + start_lb + i + c.len_utf8()),
785 level,
786 true,
787 shaping,
788 );
789 words.push(word);
790 }
791 }
792 start_word = end_lb;
793 }
794
795 if line_rtl {
797 for word in &mut words {
798 word.glyphs.reverse();
799 }
800 }
801
802 if line_rtl != level.is_rtl() {
804 words.reverse();
805 }
806
807 self.level = level;
808 self.words = words;
809
810 font_system.shape_buffer.words = cached_words;
812 }
813}
814
815#[derive(Clone, Debug)]
817pub struct ShapeLine {
818 pub rtl: bool,
819 pub spans: Vec<ShapeSpan>,
820 pub metrics_opt: Option<Metrics>,
821}
822
823type VlRange = (usize, (usize, usize), (usize, usize));
825
826#[derive(Default)]
827struct VisualLine {
828 ranges: Vec<VlRange>,
829 spaces: u32,
830 w: f32,
831}
832
833impl VisualLine {
834 fn clear(&mut self) {
835 self.ranges.clear();
836 self.spaces = 0;
837 self.w = 0.;
838 }
839}
840
841impl ShapeLine {
842 pub(crate) fn empty() -> Self {
846 Self {
847 rtl: false,
848 spans: Vec::default(),
849 metrics_opt: None,
850 }
851 }
852
853 pub fn new(
860 font_system: &mut FontSystem,
861 line: &str,
862 attrs_list: &AttrsList,
863 shaping: Shaping,
864 tab_width: u16,
865 ) -> Self {
866 let mut empty = Self::empty();
867 empty.build(font_system, line, attrs_list, shaping, tab_width);
868 empty
869 }
870
871 pub fn build(
879 &mut self,
880 font_system: &mut FontSystem,
881 line: &str,
882 attrs_list: &AttrsList,
883 shaping: Shaping,
884 tab_width: u16,
885 ) {
886 let mut spans = mem::take(&mut self.spans);
887
888 let mut cached_spans = mem::take(&mut font_system.shape_buffer.spans);
890 cached_spans.clear();
891 cached_spans.extend(spans.drain(..).rev());
892
893 let bidi = unicode_bidi::BidiInfo::new(line, None);
894 let rtl = if bidi.paragraphs.is_empty() {
895 false
896 } else {
897 bidi.paragraphs[0].level.is_rtl()
898 };
899
900 log::trace!("Line {}: '{}'", if rtl { "RTL" } else { "LTR" }, line);
901
902 for para_info in bidi.paragraphs.iter() {
903 let line_rtl = para_info.level.is_rtl();
904 assert_eq!(line_rtl, rtl);
905
906 let line_range = para_info.range.clone();
907 let levels = Self::adjust_levels(&unicode_bidi::Paragraph::new(&bidi, para_info));
908
909 let mut start = line_range.start;
912 let mut run_level = levels[start];
913 spans.reserve(line_range.end - start + 1);
914
915 for (i, &new_level) in levels
916 .iter()
917 .enumerate()
918 .take(line_range.end)
919 .skip(start + 1)
920 {
921 if new_level != run_level {
922 let mut span = cached_spans.pop().unwrap_or_else(ShapeSpan::empty);
924 span.build(
925 font_system,
926 line,
927 attrs_list,
928 start..i,
929 line_rtl,
930 run_level,
931 shaping,
932 );
933 spans.push(span);
934 start = i;
935 run_level = new_level;
936 }
937 }
938 let mut span = cached_spans.pop().unwrap_or_else(ShapeSpan::empty);
939 span.build(
940 font_system,
941 line,
942 attrs_list,
943 start..line_range.end,
944 line_rtl,
945 run_level,
946 shaping,
947 );
948 spans.push(span);
949 }
950
951 let mut x = 0.0;
953 for span in spans.iter_mut() {
954 for word in span.words.iter_mut() {
955 for glyph in word.glyphs.iter_mut() {
956 if line.get(glyph.start..glyph.end) == Some("\t") {
957 let tab_x_advance = (tab_width as f32) * glyph.x_advance;
959 let tab_stop = (math::floorf(x / tab_x_advance) + 1.0) * tab_x_advance;
960 glyph.x_advance = tab_stop - x;
961 }
962 x += glyph.x_advance;
963 }
964 }
965 }
966
967 self.rtl = rtl;
968 self.spans = spans;
969 self.metrics_opt = attrs_list.defaults().metrics_opt.map(|x| x.into());
970
971 font_system.shape_buffer.spans = cached_spans;
973 }
974
975 fn adjust_levels(para: &unicode_bidi::Paragraph) -> Vec<unicode_bidi::Level> {
977 use unicode_bidi::BidiClass::*;
978 let text = para.info.text;
979 let levels = ¶.info.levels;
980 let original_classes = ¶.info.original_classes;
981
982 let mut levels = levels.clone();
983 let line_classes = &original_classes[..];
984 let line_levels = &mut levels[..];
985
986 let mut reset_from: Option<usize> = Some(0);
989 let mut reset_to: Option<usize> = None;
990 for (i, c) in text.char_indices() {
991 match line_classes[i] {
992 RLE | LRE | RLO | LRO | PDF | BN => {}
994 B | S => {
996 assert_eq!(reset_to, None);
997 reset_to = Some(i + c.len_utf8());
998 if reset_from.is_none() {
999 reset_from = Some(i);
1000 }
1001 }
1002 WS | FSI | LRI | RLI | PDI => {
1004 if reset_from.is_none() {
1005 reset_from = Some(i);
1006 }
1007 }
1008 _ => {
1009 reset_from = None;
1010 }
1011 }
1012 if let (Some(from), Some(to)) = (reset_from, reset_to) {
1013 for level in &mut line_levels[from..to] {
1014 *level = para.para.level;
1015 }
1016 reset_from = None;
1017 reset_to = None;
1018 }
1019 }
1020 if let Some(from) = reset_from {
1021 for level in &mut line_levels[from..] {
1022 *level = para.para.level;
1023 }
1024 }
1025 levels
1026 }
1027
1028 fn reorder(&self, line_range: &[VlRange]) -> Vec<Range<usize>> {
1030 let line: Vec<unicode_bidi::Level> = line_range
1031 .iter()
1032 .map(|(span_index, _, _)| self.spans[*span_index].level)
1033 .collect();
1034 let mut runs = Vec::new();
1036 let mut start = 0;
1037 let mut run_level = line[start];
1038 let mut min_level = run_level;
1039 let mut max_level = run_level;
1040
1041 for (i, &new_level) in line.iter().enumerate().skip(start + 1) {
1042 if new_level != run_level {
1043 runs.push(start..i);
1045 start = i;
1046 run_level = new_level;
1047 min_level = min(run_level, min_level);
1048 max_level = max(run_level, max_level);
1049 }
1050 }
1051 runs.push(start..line.len());
1052
1053 let run_count = runs.len();
1054
1055 min_level = min_level.new_lowest_ge_rtl().expect("Level error");
1060
1061 while max_level >= min_level {
1062 let mut seq_start = 0;
1064 while seq_start < run_count {
1065 if line[runs[seq_start].start] < max_level {
1066 seq_start += 1;
1067 continue;
1068 }
1069
1070 let mut seq_end = seq_start + 1;
1072 while seq_end < run_count {
1073 if line[runs[seq_end].start] < max_level {
1074 break;
1075 }
1076 seq_end += 1;
1077 }
1078
1079 runs[seq_start..seq_end].reverse();
1081
1082 seq_start = seq_end;
1083 }
1084 max_level
1085 .lower(1)
1086 .expect("Lowering embedding level below zero");
1087 }
1088
1089 runs
1090 }
1091
1092 pub fn layout(
1093 &self,
1094 font_size: f32,
1095 width_opt: Option<f32>,
1096 wrap: Wrap,
1097 align: Option<Align>,
1098 match_mono_width: Option<f32>,
1099 ) -> Vec<LayoutLine> {
1100 let mut lines = Vec::with_capacity(1);
1101 self.layout_to_buffer(
1102 &mut ShapeBuffer::default(),
1103 font_size,
1104 width_opt,
1105 wrap,
1106 align,
1107 &mut lines,
1108 match_mono_width,
1109 );
1110 lines
1111 }
1112
1113 pub fn layout_to_buffer(
1114 &self,
1115 scratch: &mut ShapeBuffer,
1116 font_size: f32,
1117 width_opt: Option<f32>,
1118 wrap: Wrap,
1119 align: Option<Align>,
1120 layout_lines: &mut Vec<LayoutLine>,
1121 match_mono_width: Option<f32>,
1122 ) {
1123 let mut visual_lines = mem::take(&mut scratch.visual_lines);
1127 let mut cached_visual_lines = mem::take(&mut scratch.cached_visual_lines);
1128 cached_visual_lines.clear();
1129 cached_visual_lines.extend(visual_lines.drain(..).map(|mut l| {
1130 l.clear();
1131 l
1132 }));
1133
1134 let mut cached_glyph_sets = mem::take(&mut scratch.glyph_sets);
1136 cached_glyph_sets.clear();
1137 cached_glyph_sets.extend(layout_lines.drain(..).rev().map(|mut v| {
1138 v.glyphs.clear();
1139 v.glyphs
1140 }));
1141
1142 fn add_to_visual_line(
1143 vl: &mut VisualLine,
1144 span_index: usize,
1145 start: (usize, usize),
1146 end: (usize, usize),
1147 width: f32,
1148 number_of_blanks: u32,
1149 ) {
1150 if end == start {
1151 return;
1152 }
1153
1154 vl.ranges.push((span_index, start, end));
1155 vl.w += width;
1156 vl.spaces += number_of_blanks;
1157 }
1158
1159 let mut current_visual_line = cached_visual_lines.pop().unwrap_or_default();
1164
1165 if wrap == Wrap::None {
1166 for (span_index, span) in self.spans.iter().enumerate() {
1167 let mut word_range_width = 0.;
1168 let mut number_of_blanks: u32 = 0;
1169 for word in span.words.iter() {
1170 let word_width = word.width(font_size);
1171 word_range_width += word_width;
1172 if word.blank {
1173 number_of_blanks += 1;
1174 }
1175 }
1176 add_to_visual_line(
1177 &mut current_visual_line,
1178 span_index,
1179 (0, 0),
1180 (span.words.len(), 0),
1181 word_range_width,
1182 number_of_blanks,
1183 );
1184 }
1185 } else {
1186 for (span_index, span) in self.spans.iter().enumerate() {
1187 let mut word_range_width = 0.;
1188 let mut width_before_last_blank = 0.;
1189 let mut number_of_blanks: u32 = 0;
1190
1191 if self.rtl != span.level.is_rtl() {
1193 let mut fitting_start = (span.words.len(), 0);
1195 for (i, word) in span.words.iter().enumerate().rev() {
1196 let word_width = word.width(font_size);
1197
1198 if current_visual_line.w + (word_range_width + word_width)
1202 <= width_opt.unwrap_or(f32::INFINITY)
1203 || (word.blank
1206 && (current_visual_line.w + word_range_width) <= width_opt.unwrap_or(f32::INFINITY))
1207 {
1208 if word.blank {
1210 number_of_blanks += 1;
1211 width_before_last_blank = word_range_width;
1212 }
1213 word_range_width += word_width;
1214 continue;
1215 } else if wrap == Wrap::Glyph
1216 || (wrap == Wrap::WordOrGlyph && word_width > width_opt.unwrap_or(f32::INFINITY))
1218 {
1219 if word_range_width > 0.
1221 && wrap == Wrap::WordOrGlyph
1222 && word_width > width_opt.unwrap_or(f32::INFINITY)
1223 {
1224 add_to_visual_line(
1225 &mut current_visual_line,
1226 span_index,
1227 (i + 1, 0),
1228 fitting_start,
1229 word_range_width,
1230 number_of_blanks,
1231 );
1232
1233 visual_lines.push(current_visual_line);
1234 current_visual_line = cached_visual_lines.pop().unwrap_or_default();
1235
1236 number_of_blanks = 0;
1237 word_range_width = 0.;
1238
1239 fitting_start = (i, 0);
1240 }
1241
1242 for (glyph_i, glyph) in word.glyphs.iter().enumerate().rev() {
1243 let glyph_width = glyph.width(font_size);
1244 if current_visual_line.w + (word_range_width + glyph_width)
1245 <= width_opt.unwrap_or(f32::INFINITY)
1246 {
1247 word_range_width += glyph_width;
1248 continue;
1249 } else {
1250 add_to_visual_line(
1251 &mut current_visual_line,
1252 span_index,
1253 (i, glyph_i + 1),
1254 fitting_start,
1255 word_range_width,
1256 number_of_blanks,
1257 );
1258 visual_lines.push(current_visual_line);
1259 current_visual_line =
1260 cached_visual_lines.pop().unwrap_or_default();
1261
1262 number_of_blanks = 0;
1263 word_range_width = glyph_width;
1264 fitting_start = (i, glyph_i + 1);
1265 }
1266 }
1267 } else {
1268 if word_range_width > 0. {
1272 let trailing_blank = span
1275 .words
1276 .get(i + 1)
1277 .is_some_and(|previous_word| previous_word.blank);
1278
1279 if trailing_blank {
1280 number_of_blanks = number_of_blanks.saturating_sub(1);
1281 add_to_visual_line(
1282 &mut current_visual_line,
1283 span_index,
1284 (i + 2, 0),
1285 fitting_start,
1286 width_before_last_blank,
1287 number_of_blanks,
1288 );
1289 } else {
1290 add_to_visual_line(
1291 &mut current_visual_line,
1292 span_index,
1293 (i + 1, 0),
1294 fitting_start,
1295 word_range_width,
1296 number_of_blanks,
1297 );
1298 }
1299
1300 visual_lines.push(current_visual_line);
1301 current_visual_line = cached_visual_lines.pop().unwrap_or_default();
1302 number_of_blanks = 0;
1303 }
1304
1305 if word.blank {
1306 word_range_width = 0.;
1307 fitting_start = (i, 0);
1308 } else {
1309 word_range_width = word_width;
1310 fitting_start = (i + 1, 0);
1311 }
1312 }
1313 }
1314 add_to_visual_line(
1315 &mut current_visual_line,
1316 span_index,
1317 (0, 0),
1318 fitting_start,
1319 word_range_width,
1320 number_of_blanks,
1321 );
1322 } else {
1323 let mut fitting_start = (0, 0);
1325 for (i, word) in span.words.iter().enumerate() {
1326 let word_width = word.width(font_size);
1327 if current_visual_line.w + (word_range_width + word_width)
1328 <= width_opt.unwrap_or(f32::INFINITY)
1329 || (word.blank
1332 && (current_visual_line.w + word_range_width) <= width_opt.unwrap_or(f32::INFINITY))
1333 {
1334 if word.blank {
1336 number_of_blanks += 1;
1337 width_before_last_blank = word_range_width;
1338 }
1339 word_range_width += word_width;
1340 continue;
1341 } else if wrap == Wrap::Glyph
1342 || (wrap == Wrap::WordOrGlyph && word_width > width_opt.unwrap_or(f32::INFINITY))
1344 {
1345 if word_range_width > 0.
1347 && wrap == Wrap::WordOrGlyph
1348 && word_width > width_opt.unwrap_or(f32::INFINITY)
1349 {
1350 add_to_visual_line(
1351 &mut current_visual_line,
1352 span_index,
1353 fitting_start,
1354 (i, 0),
1355 word_range_width,
1356 number_of_blanks,
1357 );
1358
1359 visual_lines.push(current_visual_line);
1360 current_visual_line = cached_visual_lines.pop().unwrap_or_default();
1361
1362 number_of_blanks = 0;
1363 word_range_width = 0.;
1364
1365 fitting_start = (i, 0);
1366 }
1367
1368 for (glyph_i, glyph) in word.glyphs.iter().enumerate() {
1369 let glyph_width = glyph.width(font_size);
1370 if current_visual_line.w + (word_range_width + glyph_width)
1371 <= width_opt.unwrap_or(f32::INFINITY)
1372 {
1373 word_range_width += glyph_width;
1374 continue;
1375 } else {
1376 add_to_visual_line(
1377 &mut current_visual_line,
1378 span_index,
1379 fitting_start,
1380 (i, glyph_i),
1381 word_range_width,
1382 number_of_blanks,
1383 );
1384 visual_lines.push(current_visual_line);
1385 current_visual_line =
1386 cached_visual_lines.pop().unwrap_or_default();
1387
1388 number_of_blanks = 0;
1389 word_range_width = glyph_width;
1390 fitting_start = (i, glyph_i);
1391 }
1392 }
1393 } else {
1394 if word_range_width > 0. {
1398 let trailing_blank = i > 0 && span.words[i - 1].blank;
1401
1402 if trailing_blank {
1403 number_of_blanks = number_of_blanks.saturating_sub(1);
1404 add_to_visual_line(
1405 &mut current_visual_line,
1406 span_index,
1407 fitting_start,
1408 (i - 1, 0),
1409 width_before_last_blank,
1410 number_of_blanks,
1411 );
1412 } else {
1413 add_to_visual_line(
1414 &mut current_visual_line,
1415 span_index,
1416 fitting_start,
1417 (i, 0),
1418 word_range_width,
1419 number_of_blanks,
1420 );
1421 }
1422
1423 visual_lines.push(current_visual_line);
1424 current_visual_line = cached_visual_lines.pop().unwrap_or_default();
1425 number_of_blanks = 0;
1426 }
1427
1428 if word.blank {
1429 word_range_width = 0.;
1430 fitting_start = (i + 1, 0);
1431 } else {
1432 word_range_width = word_width;
1433 fitting_start = (i, 0);
1434 }
1435 }
1436 }
1437 add_to_visual_line(
1438 &mut current_visual_line,
1439 span_index,
1440 fitting_start,
1441 (span.words.len(), 0),
1442 word_range_width,
1443 number_of_blanks,
1444 );
1445 }
1446 }
1447 }
1448
1449 if !current_visual_line.ranges.is_empty() {
1450 visual_lines.push(current_visual_line);
1451 } else {
1452 current_visual_line.clear();
1453 cached_visual_lines.push(current_visual_line);
1454 }
1455
1456 let align = align.unwrap_or({
1458 if self.rtl {
1459 Align::Right
1460 } else {
1461 Align::Left
1462 }
1463 });
1464
1465 let line_width = match width_opt {
1466 Some(width) => width,
1467 None => {
1468 let mut width: f32 = 0.0;
1469 for visual_line in visual_lines.iter() {
1470 width = width.max(visual_line.w);
1471 }
1472 width
1473 }
1474 };
1475
1476 let start_x = if self.rtl { line_width } else { 0.0 };
1477
1478 let number_of_visual_lines = visual_lines.len();
1479 for (index, visual_line) in visual_lines.iter().enumerate() {
1480 if visual_line.ranges.is_empty() {
1481 continue;
1482 }
1483 let new_order = self.reorder(&visual_line.ranges);
1484 let mut glyphs = cached_glyph_sets
1485 .pop()
1486 .unwrap_or_else(|| Vec::with_capacity(1));
1487 let mut x = start_x;
1488 let mut y = 0.;
1489 let mut max_ascent: f32 = 0.;
1490 let mut max_descent: f32 = 0.;
1491 let alignment_correction = match (align, self.rtl) {
1492 (Align::Left, true) => line_width - visual_line.w,
1493 (Align::Left, false) => 0.,
1494 (Align::Right, true) => 0.,
1495 (Align::Right, false) => line_width - visual_line.w,
1496 (Align::Center, _) => (line_width - visual_line.w) / 2.0,
1497 (Align::End, _) => line_width - visual_line.w,
1498 (Align::Justified, _) => 0.,
1499 };
1500
1501 if self.rtl {
1502 x -= alignment_correction;
1503 } else {
1504 x += alignment_correction;
1505 }
1506
1507 let justification_expansion = if matches!(align, Align::Justified)
1523 && visual_line.spaces > 0
1524 && index != number_of_visual_lines - 1
1526 {
1527 (line_width - visual_line.w) / visual_line.spaces as f32
1528 } else {
1529 0.
1530 };
1531
1532 let mut process_range = |range: Range<usize>| {
1533 for &(span_index, (starting_word, starting_glyph), (ending_word, ending_glyph)) in
1534 visual_line.ranges[range.clone()].iter()
1535 {
1536 let span = &self.spans[span_index];
1537 for i in starting_word..ending_word + usize::from(ending_glyph != 0) {
1539 let word = &span.words[i];
1540 let included_glyphs = match (i == starting_word, i == ending_word) {
1541 (false, false) => &word.glyphs[..],
1542 (true, false) => &word.glyphs[starting_glyph..],
1543 (false, true) => &word.glyphs[..ending_glyph],
1544 (true, true) => &word.glyphs[starting_glyph..ending_glyph],
1545 };
1546
1547 for glyph in included_glyphs {
1548 let font_size = glyph.metrics_opt.map_or(font_size, |x| x.font_size);
1550
1551 let match_mono_em_width = match_mono_width.map(|w| w / font_size);
1552
1553 let glyph_font_size = match (
1554 match_mono_em_width,
1555 glyph.font_monospace_em_width,
1556 ) {
1557 (Some(match_em_width), Some(glyph_em_width))
1558 if glyph_em_width != match_em_width =>
1559 {
1560 let glyph_to_match_factor = glyph_em_width / match_em_width;
1561 let glyph_font_size = math::roundf(glyph_to_match_factor)
1562 .max(1.0)
1563 / glyph_to_match_factor
1564 * font_size;
1565 log::trace!("Adjusted glyph font size ({font_size} => {glyph_font_size})");
1566 glyph_font_size
1567 }
1568 _ => font_size,
1569 };
1570
1571 let mut x_advance = glyph_font_size * glyph.x_advance
1572 + if word.blank {
1573 justification_expansion
1574 } else {
1575 0.0
1576 };
1577 x_advance = x_advance.round();
1578 if self.rtl {
1579 x -= x_advance;
1580 }
1581 let y_advance = glyph_font_size * glyph.y_advance;
1582 glyphs.push(glyph.layout(
1583 glyph_font_size,
1584 glyph.metrics_opt.map(|x| x.line_height),
1585 x,
1586 y,
1587 x_advance,
1588 span.level,
1589 ));
1590 if !self.rtl {
1591 x += x_advance;
1592 }
1593 y += y_advance;
1594 max_ascent = max_ascent.max(glyph_font_size * glyph.ascent);
1595 max_descent = max_descent.max(glyph_font_size * glyph.descent);
1596 }
1597 }
1598 }
1599 };
1600
1601 if self.rtl {
1602 for range in new_order.into_iter().rev() {
1603 process_range(range);
1604 }
1605 } else {
1606 for range in new_order {
1608 process_range(range);
1609 }
1610 }
1611
1612 let mut line_height_opt: Option<f32> = None;
1613 for glyph in glyphs.iter() {
1614 if let Some(glyph_line_height) = glyph.line_height_opt {
1615 line_height_opt = match line_height_opt {
1616 Some(line_height) => Some(line_height.max(glyph_line_height)),
1617 None => Some(glyph_line_height),
1618 };
1619 }
1620 }
1621
1622 layout_lines.push(LayoutLine {
1623 w: if align != Align::Justified {
1624 visual_line.w
1625 } else if self.rtl {
1626 start_x - x
1627 } else {
1628 x
1629 },
1630 max_ascent,
1631 max_descent,
1632 line_height_opt,
1633 glyphs,
1634 });
1635 }
1636
1637 if layout_lines.is_empty() {
1639 layout_lines.push(LayoutLine {
1640 w: 0.0,
1641 max_ascent: 0.0,
1642 max_descent: 0.0,
1643 line_height_opt: self.metrics_opt.map(|x| x.line_height),
1644 glyphs: Default::default(),
1645 });
1646 }
1647
1648 scratch.visual_lines = visual_lines;
1650 scratch.visual_lines.append(&mut cached_visual_lines);
1651 scratch.cached_visual_lines = cached_visual_lines;
1652 scratch.glyph_sets = cached_glyph_sets;
1653 }
1654}