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 shape_plan = rustybuzz::ShapePlan::new(
144 font.rustybuzz(),
145 buffer.direction(),
146 Some(buffer.script()),
147 buffer.language().as_ref(),
148 &[],
149 );
150 let glyph_buffer = rustybuzz::shape_with_plan(font.rustybuzz(), &shape_plan, buffer);
151 let glyph_infos = glyph_buffer.glyph_infos();
152 let glyph_positions = glyph_buffer.glyph_positions();
153
154 let mut missing = Vec::new();
155 glyphs.reserve(glyph_infos.len());
156 let glyph_start = glyphs.len();
157 for (info, pos) in glyph_infos.iter().zip(glyph_positions.iter()) {
158 let x_advance = pos.x_advance as f32 / font_scale;
159 let y_advance = pos.y_advance as f32 / font_scale;
160 let x_offset = pos.x_offset as f32 / font_scale;
161 let y_offset = pos.y_offset as f32 / font_scale;
162
163 let start_glyph = start_run + info.cluster as usize;
164
165 if info.glyph_id == 0 {
166 missing.push(start_glyph);
167 }
168
169 let attrs = attrs_list.get_span(start_glyph);
170 glyphs.push(ShapeGlyph {
171 start: start_glyph,
172 end: end_run, x_advance,
174 y_advance,
175 x_offset,
176 y_offset,
177 ascent,
178 descent,
179 font_monospace_em_width: font.monospace_em_width(),
180 font_id: font.id(),
181 glyph_id: info.glyph_id.try_into().expect("failed to cast glyph ID"),
182 color_opt: attrs.color_opt,
184 metadata: attrs.metadata,
185 cache_key_flags: attrs.cache_key_flags,
186 metrics_opt: attrs.metrics_opt.map(|x| x.into()),
187 });
188 }
189
190 if rtl {
192 for i in glyph_start + 1..glyphs.len() {
193 let next_start = glyphs[i - 1].start;
194 let next_end = glyphs[i - 1].end;
195 let prev = &mut glyphs[i];
196 if prev.start == next_start {
197 prev.end = next_end;
198 } else {
199 prev.end = next_start;
200 }
201 }
202 } else {
203 for i in (glyph_start + 1..glyphs.len()).rev() {
204 let next_start = glyphs[i].start;
205 let next_end = glyphs[i].end;
206 let prev = &mut glyphs[i - 1];
207 if prev.start == next_start {
208 prev.end = next_end;
209 } else {
210 prev.end = next_start;
211 }
212 }
213 }
214
215 scratch.rustybuzz_buffer = Some(glyph_buffer.clear());
217
218 missing
219}
220
221fn shape_run(
222 glyphs: &mut Vec<ShapeGlyph>,
223 font_system: &mut FontSystem,
224 line: &str,
225 attrs_list: &AttrsList,
226 start_run: usize,
227 end_run: usize,
228 span_rtl: bool,
229) {
230 let mut scripts = {
232 let mut scripts = mem::take(&mut font_system.shape_buffer.scripts);
233 scripts.clear();
234 scripts
235 };
236 for c in line[start_run..end_run].chars() {
237 match c.script() {
238 Script::Common | Script::Inherited | Script::Latin | Script::Unknown => (),
239 script => {
240 if !scripts.contains(&script) {
241 scripts.push(script);
242 }
243 }
244 }
245 }
246
247 log::trace!(" Run {:?}: '{}'", &scripts, &line[start_run..end_run],);
248
249 let attrs = attrs_list.get_span(start_run);
250
251 let fonts = font_system.get_font_matches(attrs);
252
253 let default_families = [&attrs.family];
254 let mut font_iter = FontFallbackIter::new(
255 font_system,
256 &fonts,
257 &default_families,
258 &scripts,
259 &line[start_run..end_run],
260 );
261
262 let font = font_iter.next().expect("no default font found");
263
264 let glyph_start = glyphs.len();
265 let mut missing = {
266 let scratch = font_iter.shape_caches();
267 shape_fallback(
268 scratch, glyphs, &font, line, attrs_list, start_run, end_run, span_rtl,
269 )
270 };
271
272 while !missing.is_empty() {
274 let font = match font_iter.next() {
275 Some(some) => some,
276 None => break,
277 };
278
279 log::trace!(
280 "Evaluating fallback with font '{}'",
281 font_iter.face_name(font.id())
282 );
283 let mut fb_glyphs = Vec::new();
284 let scratch = font_iter.shape_caches();
285 let fb_missing = shape_fallback(
286 scratch,
287 &mut fb_glyphs,
288 &font,
289 line,
290 attrs_list,
291 start_run,
292 end_run,
293 span_rtl,
294 );
295
296 let mut fb_i = 0;
298 while fb_i < fb_glyphs.len() {
299 let start = fb_glyphs[fb_i].start;
300 let end = fb_glyphs[fb_i].end;
301
302 if !missing.contains(&start) || fb_missing.contains(&start) {
304 fb_i += 1;
305 continue;
306 }
307
308 let mut missing_i = 0;
309 while missing_i < missing.len() {
310 if missing[missing_i] >= start && missing[missing_i] < end {
311 missing.remove(missing_i);
313 } else {
314 missing_i += 1;
315 }
316 }
317
318 let mut i = glyph_start;
320 while i < glyphs.len() {
321 if glyphs[i].start >= start && glyphs[i].end <= end {
322 break;
323 } else {
324 i += 1;
325 }
326 }
327
328 while i < glyphs.len() {
330 if glyphs[i].start >= start && glyphs[i].end <= end {
331 let _glyph = glyphs.remove(i);
332 } else {
334 break;
335 }
336 }
337
338 while fb_i < fb_glyphs.len() {
339 if fb_glyphs[fb_i].start >= start && fb_glyphs[fb_i].end <= end {
340 let fb_glyph = fb_glyphs.remove(fb_i);
341 glyphs.insert(i, fb_glyph);
343 i += 1;
344 } else {
345 break;
346 }
347 }
348 }
349 }
350
351 font_iter.check_missing(&line[start_run..end_run]);
353
354 font_system.shape_buffer.scripts = scripts;
362}
363
364#[cfg(feature = "shape-run-cache")]
365fn shape_run_cached(
366 glyphs: &mut Vec<ShapeGlyph>,
367 font_system: &mut FontSystem,
368 line: &str,
369 attrs_list: &AttrsList,
370 start_run: usize,
371 end_run: usize,
372 span_rtl: bool,
373) {
374 use crate::{AttrsOwned, ShapeRunKey};
375
376 let run_range = start_run..end_run;
377 let mut key = ShapeRunKey {
378 text: line[run_range.clone()].to_string(),
379 default_attrs: AttrsOwned::new(attrs_list.defaults()),
380 attrs_spans: Vec::new(),
381 };
382 for (attrs_range, attrs) in attrs_list.spans.overlapping(&run_range) {
383 if attrs == &key.default_attrs {
384 continue;
386 }
387 let start = max(attrs_range.start, start_run).saturating_sub(start_run);
388 let end = min(attrs_range.end, end_run).saturating_sub(start_run);
389 if end > start {
390 let range = start..end;
391 key.attrs_spans.push((range, attrs.clone()));
392 }
393 }
394 if let Some(cache_glyphs) = font_system.shape_run_cache.get(&key) {
395 for mut glyph in cache_glyphs.iter().cloned() {
396 glyph.start += start_run;
398 glyph.end += start_run;
399 glyphs.push(glyph);
400 }
401 return;
402 }
403
404 let mut cache_glyphs = Vec::new();
406 shape_run(
407 &mut cache_glyphs,
408 font_system,
409 line,
410 attrs_list,
411 start_run,
412 end_run,
413 span_rtl,
414 );
415 glyphs.extend_from_slice(&cache_glyphs);
416 for glyph in cache_glyphs.iter_mut() {
417 glyph.start -= start_run;
419 glyph.end -= start_run;
420 }
421 font_system.shape_run_cache.insert(key, cache_glyphs);
422}
423
424#[cfg(feature = "swash")]
425fn shape_skip(
426 font_system: &mut FontSystem,
427 glyphs: &mut Vec<ShapeGlyph>,
428 line: &str,
429 attrs_list: &AttrsList,
430 start_run: usize,
431 end_run: usize,
432) {
433 let attrs = attrs_list.get_span(start_run);
434 let fonts = font_system.get_font_matches(attrs);
435
436 let default_families = [&attrs.family];
437 let mut font_iter = FontFallbackIter::new(font_system, &fonts, &default_families, &[], "");
438
439 let font = font_iter.next().expect("no default font found");
440 let font_id = font.id();
441 let font_monospace_em_width = font.monospace_em_width();
442 let font = font.as_swash();
443
444 let charmap = font.charmap();
445 let metrics = font.metrics(&[]);
446 let glyph_metrics = font.glyph_metrics(&[]).scale(1.0);
447
448 let ascent = metrics.ascent / f32::from(metrics.units_per_em);
449 let descent = metrics.descent / f32::from(metrics.units_per_em);
450
451 glyphs.extend(
452 line[start_run..end_run]
453 .char_indices()
454 .map(|(chr_idx, codepoint)| {
455 let glyph_id = charmap.map(codepoint);
456 let x_advance = glyph_metrics.advance_width(glyph_id);
457 let attrs = attrs_list.get_span(start_run + chr_idx);
458
459 ShapeGlyph {
460 start: chr_idx + start_run,
461 end: chr_idx + start_run + codepoint.len_utf8(),
462 x_advance,
463 y_advance: 0.0,
464 x_offset: 0.0,
465 y_offset: 0.0,
466 ascent,
467 descent,
468 font_monospace_em_width,
469 font_id,
470 glyph_id,
471 color_opt: attrs.color_opt,
472 metadata: attrs.metadata,
473 cache_key_flags: attrs.cache_key_flags,
474 metrics_opt: attrs.metrics_opt.map(|x| x.into()),
475 }
476 }),
477 );
478}
479
480#[derive(Clone, Debug)]
482pub struct ShapeGlyph {
483 pub start: usize,
484 pub end: usize,
485 pub x_advance: f32,
486 pub y_advance: f32,
487 pub x_offset: f32,
488 pub y_offset: f32,
489 pub ascent: f32,
490 pub descent: f32,
491 pub font_monospace_em_width: Option<f32>,
492 pub font_id: fontdb::ID,
493 pub glyph_id: u16,
494 pub color_opt: Option<Color>,
495 pub metadata: usize,
496 pub cache_key_flags: CacheKeyFlags,
497 pub metrics_opt: Option<Metrics>,
498}
499
500impl ShapeGlyph {
501 fn layout(
502 &self,
503 font_size: f32,
504 line_height_opt: Option<f32>,
505 x: f32,
506 y: f32,
507 w: f32,
508 level: unicode_bidi::Level,
509 ) -> LayoutGlyph {
510 LayoutGlyph {
511 start: self.start,
512 end: self.end,
513 font_size,
514 line_height_opt,
515 font_id: self.font_id,
516 glyph_id: self.glyph_id,
517 x,
518 y,
519 w,
520 level,
521 x_offset: self.x_offset,
522 y_offset: self.y_offset,
523 color_opt: self.color_opt,
524 metadata: self.metadata,
525 cache_key_flags: self.cache_key_flags,
526 }
527 }
528
529 pub fn width(&self, font_size: f32) -> f32 {
532 self.metrics_opt.map_or(font_size, |x| x.font_size) * self.x_advance
533 }
534}
535
536#[derive(Clone, Debug)]
538pub struct ShapeWord {
539 pub blank: bool,
540 pub glyphs: Vec<ShapeGlyph>,
541}
542
543impl ShapeWord {
544 pub(crate) fn empty() -> Self {
548 Self {
549 blank: true,
550 glyphs: Vec::default(),
551 }
552 }
553
554 #[allow(clippy::too_many_arguments)]
556 pub fn new(
557 font_system: &mut FontSystem,
558 line: &str,
559 attrs_list: &AttrsList,
560 word_range: Range<usize>,
561 level: unicode_bidi::Level,
562 blank: bool,
563 shaping: Shaping,
564 ) -> Self {
565 let mut empty = Self::empty();
566 empty.build(
567 font_system,
568 line,
569 attrs_list,
570 word_range,
571 level,
572 blank,
573 shaping,
574 );
575 empty
576 }
577
578 #[allow(clippy::too_many_arguments)]
582 pub fn build(
583 &mut self,
584 font_system: &mut FontSystem,
585 line: &str,
586 attrs_list: &AttrsList,
587 word_range: Range<usize>,
588 level: unicode_bidi::Level,
589 blank: bool,
590 shaping: Shaping,
591 ) {
592 let word = &line[word_range.clone()];
593
594 log::trace!(
595 " Word{}: '{}'",
596 if blank { " BLANK" } else { "" },
597 word
598 );
599
600 let mut glyphs = mem::take(&mut self.glyphs);
601 glyphs.clear();
602
603 let span_rtl = level.is_rtl();
604
605 let mut start_run = word_range.start;
606 let mut attrs = attrs_list.defaults();
607 for (egc_i, _egc) in word.grapheme_indices(true) {
608 let start_egc = word_range.start + egc_i;
609 let attrs_egc = attrs_list.get_span(start_egc);
610 if !attrs.compatible(&attrs_egc) {
611 shaping.run(
612 &mut glyphs,
613 font_system,
614 line,
615 attrs_list,
616 start_run,
617 start_egc,
618 span_rtl,
619 );
620
621 start_run = start_egc;
622 attrs = attrs_egc;
623 }
624 }
625 if start_run < word_range.end {
626 shaping.run(
627 &mut glyphs,
628 font_system,
629 line,
630 attrs_list,
631 start_run,
632 word_range.end,
633 span_rtl,
634 );
635 }
636
637 self.blank = blank;
638 self.glyphs = glyphs;
639 }
640
641 pub fn width(&self, font_size: f32) -> f32 {
643 let mut width = 0.0;
644 for glyph in self.glyphs.iter() {
645 width += glyph.width(font_size);
646 }
647 width
648 }
649}
650
651#[derive(Clone, Debug)]
653pub struct ShapeSpan {
654 pub level: unicode_bidi::Level,
655 pub words: Vec<ShapeWord>,
656}
657
658impl ShapeSpan {
659 pub(crate) fn empty() -> Self {
663 Self {
664 level: unicode_bidi::Level::ltr(),
665 words: Vec::default(),
666 }
667 }
668
669 pub fn new(
671 font_system: &mut FontSystem,
672 line: &str,
673 attrs_list: &AttrsList,
674 span_range: Range<usize>,
675 line_rtl: bool,
676 level: unicode_bidi::Level,
677 shaping: Shaping,
678 ) -> Self {
679 let mut empty = Self::empty();
680 empty.build(
681 font_system,
682 line,
683 attrs_list,
684 span_range,
685 line_rtl,
686 level,
687 shaping,
688 );
689 empty
690 }
691
692 pub fn build(
696 &mut self,
697 font_system: &mut FontSystem,
698 line: &str,
699 attrs_list: &AttrsList,
700 span_range: Range<usize>,
701 line_rtl: bool,
702 level: unicode_bidi::Level,
703 shaping: Shaping,
704 ) {
705 let span = &line[span_range.start..span_range.end];
706
707 log::trace!(
708 " Span {}: '{}'",
709 if level.is_rtl() { "RTL" } else { "LTR" },
710 span
711 );
712
713 let mut words = mem::take(&mut self.words);
714
715 let mut cached_words = mem::take(&mut font_system.shape_buffer.words);
717 cached_words.clear();
718 if line_rtl != level.is_rtl() {
719 cached_words.append(&mut words);
721 } else {
722 cached_words.extend(words.drain(..).rev());
723 }
724
725 let mut start_word = 0;
726 for (end_lb, _) in unicode_linebreak::linebreaks(span) {
727 let mut start_lb = end_lb;
728 for (i, c) in span[start_word..end_lb].char_indices().rev() {
729 if c.is_whitespace() {
734 start_lb = start_word + i;
735 } else {
736 break;
737 }
738 }
739 if start_word < start_lb {
740 let mut word = cached_words.pop().unwrap_or_else(ShapeWord::empty);
741 word.build(
742 font_system,
743 line,
744 attrs_list,
745 (span_range.start + start_word)..(span_range.start + start_lb),
746 level,
747 false,
748 shaping,
749 );
750 words.push(word);
751 }
752 if start_lb < end_lb {
753 for (i, c) in span[start_lb..end_lb].char_indices() {
754 let mut word = cached_words.pop().unwrap_or_else(ShapeWord::empty);
756 word.build(
757 font_system,
758 line,
759 attrs_list,
760 (span_range.start + start_lb + i)
761 ..(span_range.start + start_lb + i + c.len_utf8()),
762 level,
763 true,
764 shaping,
765 );
766 words.push(word);
767 }
768 }
769 start_word = end_lb;
770 }
771
772 if line_rtl {
774 for word in &mut words {
775 word.glyphs.reverse();
776 }
777 }
778
779 if line_rtl != level.is_rtl() {
781 words.reverse();
782 }
783
784 self.level = level;
785 self.words = words;
786
787 font_system.shape_buffer.words = cached_words;
789 }
790}
791
792#[derive(Clone, Debug)]
794pub struct ShapeLine {
795 pub rtl: bool,
796 pub spans: Vec<ShapeSpan>,
797 pub metrics_opt: Option<Metrics>,
798}
799
800type VlRange = (usize, (usize, usize), (usize, usize));
802
803#[derive(Default)]
804struct VisualLine {
805 ranges: Vec<VlRange>,
806 spaces: u32,
807 w: f32,
808}
809
810impl VisualLine {
811 fn clear(&mut self) {
812 self.ranges.clear();
813 self.spaces = 0;
814 self.w = 0.;
815 }
816}
817
818impl ShapeLine {
819 pub(crate) fn empty() -> Self {
823 Self {
824 rtl: false,
825 spans: Vec::default(),
826 metrics_opt: None,
827 }
828 }
829
830 pub fn new(
837 font_system: &mut FontSystem,
838 line: &str,
839 attrs_list: &AttrsList,
840 shaping: Shaping,
841 tab_width: u16,
842 ) -> Self {
843 let mut empty = Self::empty();
844 empty.build(font_system, line, attrs_list, shaping, tab_width);
845 empty
846 }
847
848 pub fn build(
856 &mut self,
857 font_system: &mut FontSystem,
858 line: &str,
859 attrs_list: &AttrsList,
860 shaping: Shaping,
861 tab_width: u16,
862 ) {
863 let mut spans = mem::take(&mut self.spans);
864
865 let mut cached_spans = mem::take(&mut font_system.shape_buffer.spans);
867 cached_spans.clear();
868 cached_spans.extend(spans.drain(..).rev());
869
870 let bidi = unicode_bidi::BidiInfo::new(line, None);
871 let rtl = if bidi.paragraphs.is_empty() {
872 false
873 } else {
874 bidi.paragraphs[0].level.is_rtl()
875 };
876
877 log::trace!("Line {}: '{}'", if rtl { "RTL" } else { "LTR" }, line);
878
879 for para_info in bidi.paragraphs.iter() {
880 let line_rtl = para_info.level.is_rtl();
881 assert_eq!(line_rtl, rtl);
882
883 let line_range = para_info.range.clone();
884 let levels = Self::adjust_levels(&unicode_bidi::Paragraph::new(&bidi, para_info));
885
886 let mut start = line_range.start;
889 let mut run_level = levels[start];
890 spans.reserve(line_range.end - start + 1);
891
892 for (i, &new_level) in levels
893 .iter()
894 .enumerate()
895 .take(line_range.end)
896 .skip(start + 1)
897 {
898 if new_level != run_level {
899 let mut span = cached_spans.pop().unwrap_or_else(ShapeSpan::empty);
901 span.build(
902 font_system,
903 line,
904 attrs_list,
905 start..i,
906 line_rtl,
907 run_level,
908 shaping,
909 );
910 spans.push(span);
911 start = i;
912 run_level = new_level;
913 }
914 }
915 let mut span = cached_spans.pop().unwrap_or_else(ShapeSpan::empty);
916 span.build(
917 font_system,
918 line,
919 attrs_list,
920 start..line_range.end,
921 line_rtl,
922 run_level,
923 shaping,
924 );
925 spans.push(span);
926 }
927
928 let mut x = 0.0;
930 for span in spans.iter_mut() {
931 for word in span.words.iter_mut() {
932 for glyph in word.glyphs.iter_mut() {
933 if line.get(glyph.start..glyph.end) == Some("\t") {
934 let tab_x_advance = (tab_width as f32) * glyph.x_advance;
936 let tab_stop = (math::floorf(x / tab_x_advance) + 1.0) * tab_x_advance;
937 glyph.x_advance = tab_stop - x;
938 }
939 x += glyph.x_advance;
940 }
941 }
942 }
943
944 self.rtl = rtl;
945 self.spans = spans;
946 self.metrics_opt = attrs_list.defaults().metrics_opt.map(|x| x.into());
947
948 font_system.shape_buffer.spans = cached_spans;
950 }
951
952 fn adjust_levels(para: &unicode_bidi::Paragraph) -> Vec<unicode_bidi::Level> {
954 use unicode_bidi::BidiClass::*;
955 let text = para.info.text;
956 let levels = ¶.info.levels;
957 let original_classes = ¶.info.original_classes;
958
959 let mut levels = levels.clone();
960 let line_classes = &original_classes[..];
961 let line_levels = &mut levels[..];
962
963 let mut reset_from: Option<usize> = Some(0);
966 let mut reset_to: Option<usize> = None;
967 for (i, c) in text.char_indices() {
968 match line_classes[i] {
969 RLE | LRE | RLO | LRO | PDF | BN => {}
971 B | S => {
973 assert_eq!(reset_to, None);
974 reset_to = Some(i + c.len_utf8());
975 if reset_from.is_none() {
976 reset_from = Some(i);
977 }
978 }
979 WS | FSI | LRI | RLI | PDI => {
981 if reset_from.is_none() {
982 reset_from = Some(i);
983 }
984 }
985 _ => {
986 reset_from = None;
987 }
988 }
989 if let (Some(from), Some(to)) = (reset_from, reset_to) {
990 for level in &mut line_levels[from..to] {
991 *level = para.para.level;
992 }
993 reset_from = None;
994 reset_to = None;
995 }
996 }
997 if let Some(from) = reset_from {
998 for level in &mut line_levels[from..] {
999 *level = para.para.level;
1000 }
1001 }
1002 levels
1003 }
1004
1005 fn reorder(&self, line_range: &[VlRange]) -> Vec<Range<usize>> {
1007 let line: Vec<unicode_bidi::Level> = line_range
1008 .iter()
1009 .map(|(span_index, _, _)| self.spans[*span_index].level)
1010 .collect();
1011 let mut runs = Vec::new();
1013 let mut start = 0;
1014 let mut run_level = line[start];
1015 let mut min_level = run_level;
1016 let mut max_level = run_level;
1017
1018 for (i, &new_level) in line.iter().enumerate().skip(start + 1) {
1019 if new_level != run_level {
1020 runs.push(start..i);
1022 start = i;
1023 run_level = new_level;
1024 min_level = min(run_level, min_level);
1025 max_level = max(run_level, max_level);
1026 }
1027 }
1028 runs.push(start..line.len());
1029
1030 let run_count = runs.len();
1031
1032 min_level = min_level.new_lowest_ge_rtl().expect("Level error");
1037
1038 while max_level >= min_level {
1039 let mut seq_start = 0;
1041 while seq_start < run_count {
1042 if line[runs[seq_start].start] < max_level {
1043 seq_start += 1;
1044 continue;
1045 }
1046
1047 let mut seq_end = seq_start + 1;
1049 while seq_end < run_count {
1050 if line[runs[seq_end].start] < max_level {
1051 break;
1052 }
1053 seq_end += 1;
1054 }
1055
1056 runs[seq_start..seq_end].reverse();
1058
1059 seq_start = seq_end;
1060 }
1061 max_level
1062 .lower(1)
1063 .expect("Lowering embedding level below zero");
1064 }
1065
1066 runs
1067 }
1068
1069 pub fn layout(
1070 &self,
1071 font_size: f32,
1072 width_opt: Option<f32>,
1073 wrap: Wrap,
1074 align: Option<Align>,
1075 match_mono_width: Option<f32>,
1076 ) -> Vec<LayoutLine> {
1077 let mut lines = Vec::with_capacity(1);
1078 self.layout_to_buffer(
1079 &mut ShapeBuffer::default(),
1080 font_size,
1081 width_opt,
1082 wrap,
1083 align,
1084 &mut lines,
1085 match_mono_width,
1086 );
1087 lines
1088 }
1089
1090 pub fn layout_to_buffer(
1091 &self,
1092 scratch: &mut ShapeBuffer,
1093 font_size: f32,
1094 width_opt: Option<f32>,
1095 wrap: Wrap,
1096 align: Option<Align>,
1097 layout_lines: &mut Vec<LayoutLine>,
1098 match_mono_width: Option<f32>,
1099 ) {
1100 let mut visual_lines = mem::take(&mut scratch.visual_lines);
1104 let mut cached_visual_lines = mem::take(&mut scratch.cached_visual_lines);
1105 cached_visual_lines.clear();
1106 cached_visual_lines.extend(visual_lines.drain(..).map(|mut l| {
1107 l.clear();
1108 l
1109 }));
1110
1111 let mut cached_glyph_sets = mem::take(&mut scratch.glyph_sets);
1113 cached_glyph_sets.clear();
1114 cached_glyph_sets.extend(layout_lines.drain(..).rev().map(|mut v| {
1115 v.glyphs.clear();
1116 v.glyphs
1117 }));
1118
1119 fn add_to_visual_line(
1120 vl: &mut VisualLine,
1121 span_index: usize,
1122 start: (usize, usize),
1123 end: (usize, usize),
1124 width: f32,
1125 number_of_blanks: u32,
1126 ) {
1127 if end == start {
1128 return;
1129 }
1130
1131 vl.ranges.push((span_index, start, end));
1132 vl.w += width;
1133 vl.spaces += number_of_blanks;
1134 }
1135
1136 let mut current_visual_line = cached_visual_lines.pop().unwrap_or_default();
1141
1142 if wrap == Wrap::None {
1143 for (span_index, span) in self.spans.iter().enumerate() {
1144 let mut word_range_width = 0.;
1145 let mut number_of_blanks: u32 = 0;
1146 for word in span.words.iter() {
1147 let word_width = word.width(font_size);
1148 word_range_width += word_width;
1149 if word.blank {
1150 number_of_blanks += 1;
1151 }
1152 }
1153 add_to_visual_line(
1154 &mut current_visual_line,
1155 span_index,
1156 (0, 0),
1157 (span.words.len(), 0),
1158 word_range_width,
1159 number_of_blanks,
1160 );
1161 }
1162 } else {
1163 for (span_index, span) in self.spans.iter().enumerate() {
1164 let mut word_range_width = 0.;
1165 let mut width_before_last_blank = 0.;
1166 let mut number_of_blanks: u32 = 0;
1167
1168 if self.rtl != span.level.is_rtl() {
1170 let mut fitting_start = (span.words.len(), 0);
1172 for (i, word) in span.words.iter().enumerate().rev() {
1173 let word_width = word.width(font_size);
1174
1175 if current_visual_line.w + (word_range_width + word_width)
1179 <= width_opt.unwrap_or(f32::INFINITY)
1180 || (word.blank
1183 && (current_visual_line.w + word_range_width) <= width_opt.unwrap_or(f32::INFINITY))
1184 {
1185 if word.blank {
1187 number_of_blanks += 1;
1188 width_before_last_blank = word_range_width;
1189 }
1190 word_range_width += word_width;
1191 continue;
1192 } else if wrap == Wrap::Glyph
1193 || (wrap == Wrap::WordOrGlyph && word_width > width_opt.unwrap_or(f32::INFINITY))
1195 {
1196 if word_range_width > 0.
1198 && wrap == Wrap::WordOrGlyph
1199 && word_width > width_opt.unwrap_or(f32::INFINITY)
1200 {
1201 add_to_visual_line(
1202 &mut current_visual_line,
1203 span_index,
1204 (i + 1, 0),
1205 fitting_start,
1206 word_range_width,
1207 number_of_blanks,
1208 );
1209
1210 visual_lines.push(current_visual_line);
1211 current_visual_line = cached_visual_lines.pop().unwrap_or_default();
1212
1213 number_of_blanks = 0;
1214 word_range_width = 0.;
1215
1216 fitting_start = (i, 0);
1217 }
1218
1219 for (glyph_i, glyph) in word.glyphs.iter().enumerate().rev() {
1220 let glyph_width = glyph.width(font_size);
1221 if current_visual_line.w + (word_range_width + glyph_width)
1222 <= width_opt.unwrap_or(f32::INFINITY)
1223 {
1224 word_range_width += glyph_width;
1225 continue;
1226 } else {
1227 add_to_visual_line(
1228 &mut current_visual_line,
1229 span_index,
1230 (i, glyph_i + 1),
1231 fitting_start,
1232 word_range_width,
1233 number_of_blanks,
1234 );
1235 visual_lines.push(current_visual_line);
1236 current_visual_line =
1237 cached_visual_lines.pop().unwrap_or_default();
1238
1239 number_of_blanks = 0;
1240 word_range_width = glyph_width;
1241 fitting_start = (i, glyph_i + 1);
1242 }
1243 }
1244 } else {
1245 if word_range_width > 0. {
1249 let trailing_blank = span
1252 .words
1253 .get(i + 1)
1254 .is_some_and(|previous_word| previous_word.blank);
1255
1256 if trailing_blank {
1257 number_of_blanks = number_of_blanks.saturating_sub(1);
1258 add_to_visual_line(
1259 &mut current_visual_line,
1260 span_index,
1261 (i + 2, 0),
1262 fitting_start,
1263 width_before_last_blank,
1264 number_of_blanks,
1265 );
1266 } else {
1267 add_to_visual_line(
1268 &mut current_visual_line,
1269 span_index,
1270 (i + 1, 0),
1271 fitting_start,
1272 word_range_width,
1273 number_of_blanks,
1274 );
1275 }
1276
1277 visual_lines.push(current_visual_line);
1278 current_visual_line = cached_visual_lines.pop().unwrap_or_default();
1279 number_of_blanks = 0;
1280 }
1281
1282 if word.blank {
1283 word_range_width = 0.;
1284 fitting_start = (i, 0);
1285 } else {
1286 word_range_width = word_width;
1287 fitting_start = (i + 1, 0);
1288 }
1289 }
1290 }
1291 add_to_visual_line(
1292 &mut current_visual_line,
1293 span_index,
1294 (0, 0),
1295 fitting_start,
1296 word_range_width,
1297 number_of_blanks,
1298 );
1299 } else {
1300 let mut fitting_start = (0, 0);
1302 for (i, word) in span.words.iter().enumerate() {
1303 let word_width = word.width(font_size);
1304 if current_visual_line.w + (word_range_width + word_width)
1305 <= width_opt.unwrap_or(f32::INFINITY)
1306 || (word.blank
1309 && (current_visual_line.w + word_range_width) <= width_opt.unwrap_or(f32::INFINITY))
1310 {
1311 if word.blank {
1313 number_of_blanks += 1;
1314 width_before_last_blank = word_range_width;
1315 }
1316 word_range_width += word_width;
1317 continue;
1318 } else if wrap == Wrap::Glyph
1319 || (wrap == Wrap::WordOrGlyph && word_width > width_opt.unwrap_or(f32::INFINITY))
1321 {
1322 if word_range_width > 0.
1324 && wrap == Wrap::WordOrGlyph
1325 && word_width > width_opt.unwrap_or(f32::INFINITY)
1326 {
1327 add_to_visual_line(
1328 &mut current_visual_line,
1329 span_index,
1330 fitting_start,
1331 (i, 0),
1332 word_range_width,
1333 number_of_blanks,
1334 );
1335
1336 visual_lines.push(current_visual_line);
1337 current_visual_line = cached_visual_lines.pop().unwrap_or_default();
1338
1339 number_of_blanks = 0;
1340 word_range_width = 0.;
1341
1342 fitting_start = (i, 0);
1343 }
1344
1345 for (glyph_i, glyph) in word.glyphs.iter().enumerate() {
1346 let glyph_width = glyph.width(font_size);
1347 if current_visual_line.w + (word_range_width + glyph_width)
1348 <= width_opt.unwrap_or(f32::INFINITY)
1349 {
1350 word_range_width += glyph_width;
1351 continue;
1352 } else {
1353 add_to_visual_line(
1354 &mut current_visual_line,
1355 span_index,
1356 fitting_start,
1357 (i, glyph_i),
1358 word_range_width,
1359 number_of_blanks,
1360 );
1361 visual_lines.push(current_visual_line);
1362 current_visual_line =
1363 cached_visual_lines.pop().unwrap_or_default();
1364
1365 number_of_blanks = 0;
1366 word_range_width = glyph_width;
1367 fitting_start = (i, glyph_i);
1368 }
1369 }
1370 } else {
1371 if word_range_width > 0. {
1375 let trailing_blank = i > 0 && span.words[i - 1].blank;
1378
1379 if trailing_blank {
1380 number_of_blanks = number_of_blanks.saturating_sub(1);
1381 add_to_visual_line(
1382 &mut current_visual_line,
1383 span_index,
1384 fitting_start,
1385 (i - 1, 0),
1386 width_before_last_blank,
1387 number_of_blanks,
1388 );
1389 } else {
1390 add_to_visual_line(
1391 &mut current_visual_line,
1392 span_index,
1393 fitting_start,
1394 (i, 0),
1395 word_range_width,
1396 number_of_blanks,
1397 );
1398 }
1399
1400 visual_lines.push(current_visual_line);
1401 current_visual_line = cached_visual_lines.pop().unwrap_or_default();
1402 number_of_blanks = 0;
1403 }
1404
1405 if word.blank {
1406 word_range_width = 0.;
1407 fitting_start = (i + 1, 0);
1408 } else {
1409 word_range_width = word_width;
1410 fitting_start = (i, 0);
1411 }
1412 }
1413 }
1414 add_to_visual_line(
1415 &mut current_visual_line,
1416 span_index,
1417 fitting_start,
1418 (span.words.len(), 0),
1419 word_range_width,
1420 number_of_blanks,
1421 );
1422 }
1423 }
1424 }
1425
1426 if !current_visual_line.ranges.is_empty() {
1427 visual_lines.push(current_visual_line);
1428 } else {
1429 current_visual_line.clear();
1430 cached_visual_lines.push(current_visual_line);
1431 }
1432
1433 let align = align.unwrap_or({
1435 if self.rtl {
1436 Align::Right
1437 } else {
1438 Align::Left
1439 }
1440 });
1441
1442 let line_width = match width_opt {
1443 Some(width) => width,
1444 None => {
1445 let mut width: f32 = 0.0;
1446 for visual_line in visual_lines.iter() {
1447 width = width.max(visual_line.w);
1448 }
1449 width
1450 }
1451 };
1452
1453 let start_x = if self.rtl { line_width } else { 0.0 };
1454
1455 let number_of_visual_lines = visual_lines.len();
1456 for (index, visual_line) in visual_lines.iter().enumerate() {
1457 if visual_line.ranges.is_empty() {
1458 continue;
1459 }
1460 let new_order = self.reorder(&visual_line.ranges);
1461 let mut glyphs = cached_glyph_sets
1462 .pop()
1463 .unwrap_or_else(|| Vec::with_capacity(1));
1464 let mut x = start_x;
1465 let mut y = 0.;
1466 let mut max_ascent: f32 = 0.;
1467 let mut max_descent: f32 = 0.;
1468 let alignment_correction = match (align, self.rtl) {
1469 (Align::Left, true) => line_width - visual_line.w,
1470 (Align::Left, false) => 0.,
1471 (Align::Right, true) => 0.,
1472 (Align::Right, false) => line_width - visual_line.w,
1473 (Align::Center, _) => (line_width - visual_line.w) / 2.0,
1474 (Align::End, _) => line_width - visual_line.w,
1475 (Align::Justified, _) => 0.,
1476 };
1477
1478 if self.rtl {
1479 x -= alignment_correction;
1480 } else {
1481 x += alignment_correction;
1482 }
1483
1484 let justification_expansion = if matches!(align, Align::Justified)
1500 && visual_line.spaces > 0
1501 && index != number_of_visual_lines - 1
1503 {
1504 (line_width - visual_line.w) / visual_line.spaces as f32
1505 } else {
1506 0.
1507 };
1508
1509 let mut process_range = |range: Range<usize>| {
1510 for &(span_index, (starting_word, starting_glyph), (ending_word, ending_glyph)) in
1511 visual_line.ranges[range.clone()].iter()
1512 {
1513 let span = &self.spans[span_index];
1514 for i in starting_word..ending_word + usize::from(ending_glyph != 0) {
1516 let word = &span.words[i];
1517 let included_glyphs = match (i == starting_word, i == ending_word) {
1518 (false, false) => &word.glyphs[..],
1519 (true, false) => &word.glyphs[starting_glyph..],
1520 (false, true) => &word.glyphs[..ending_glyph],
1521 (true, true) => &word.glyphs[starting_glyph..ending_glyph],
1522 };
1523
1524 for glyph in included_glyphs {
1525 let font_size = glyph.metrics_opt.map_or(font_size, |x| x.font_size);
1527
1528 let match_mono_em_width = match_mono_width.map(|w| w / font_size);
1529
1530 let glyph_font_size = match (
1531 match_mono_em_width,
1532 glyph.font_monospace_em_width,
1533 ) {
1534 (Some(match_em_width), Some(glyph_em_width))
1535 if glyph_em_width != match_em_width =>
1536 {
1537 let glyph_to_match_factor = glyph_em_width / match_em_width;
1538 let glyph_font_size = math::roundf(glyph_to_match_factor)
1539 .max(1.0)
1540 / glyph_to_match_factor
1541 * font_size;
1542 log::trace!("Adjusted glyph font size ({font_size} => {glyph_font_size})");
1543 glyph_font_size
1544 }
1545 _ => font_size,
1546 };
1547
1548 let x_advance = glyph_font_size * glyph.x_advance
1549 + if word.blank {
1550 justification_expansion
1551 } else {
1552 0.0
1553 };
1554 if self.rtl {
1555 x -= x_advance;
1556 }
1557 let y_advance = glyph_font_size * glyph.y_advance;
1558 glyphs.push(glyph.layout(
1559 glyph_font_size,
1560 glyph.metrics_opt.map(|x| x.line_height),
1561 x,
1562 y,
1563 x_advance,
1564 span.level,
1565 ));
1566 if !self.rtl {
1567 x += x_advance;
1568 }
1569 y += y_advance;
1570 max_ascent = max_ascent.max(glyph_font_size * glyph.ascent);
1571 max_descent = max_descent.max(glyph_font_size * glyph.descent);
1572 }
1573 }
1574 }
1575 };
1576
1577 if self.rtl {
1578 for range in new_order.into_iter().rev() {
1579 process_range(range);
1580 }
1581 } else {
1582 for range in new_order {
1584 process_range(range);
1585 }
1586 }
1587
1588 let mut line_height_opt: Option<f32> = None;
1589 for glyph in glyphs.iter() {
1590 if let Some(glyph_line_height) = glyph.line_height_opt {
1591 line_height_opt = match line_height_opt {
1592 Some(line_height) => Some(line_height.max(glyph_line_height)),
1593 None => Some(glyph_line_height),
1594 };
1595 }
1596 }
1597
1598 layout_lines.push(LayoutLine {
1599 w: if align != Align::Justified {
1600 visual_line.w
1601 } else if self.rtl {
1602 start_x - x
1603 } else {
1604 x
1605 },
1606 max_ascent,
1607 max_descent,
1608 line_height_opt,
1609 glyphs,
1610 });
1611 }
1612
1613 if layout_lines.is_empty() {
1615 layout_lines.push(LayoutLine {
1616 w: 0.0,
1617 max_ascent: 0.0,
1618 max_descent: 0.0,
1619 line_height_opt: self.metrics_opt.map(|x| x.line_height),
1620 glyphs: Default::default(),
1621 });
1622 }
1623
1624 scratch.visual_lines = visual_lines;
1626 scratch.visual_lines.append(&mut cached_visual_lines);
1627 scratch.cached_visual_lines = cached_visual_lines;
1628 scratch.glyph_sets = cached_glyph_sets;
1629 }
1630}