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 ShapePlanCache, 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 scratch: &mut ShapeBuffer,
44 glyphs: &mut Vec<ShapeGlyph>,
45 font_system: &mut FontSystem,
46 line: &str,
47 attrs_list: &AttrsList,
48 start_run: usize,
49 end_run: usize,
50 span_rtl: bool,
51 ) {
52 match self {
53 #[cfg(feature = "swash")]
54 Self::Basic => shape_skip(font_system, glyphs, line, attrs_list, start_run, end_run),
55 #[cfg(not(feature = "shape-run-cache"))]
56 Self::Advanced => shape_run(
57 scratch,
58 glyphs,
59 font_system,
60 line,
61 attrs_list,
62 start_run,
63 end_run,
64 span_rtl,
65 ),
66 #[cfg(feature = "shape-run-cache")]
67 Self::Advanced => shape_run_cached(
68 scratch,
69 glyphs,
70 font_system,
71 line,
72 attrs_list,
73 start_run,
74 end_run,
75 span_rtl,
76 ),
77 }
78 }
79}
80
81#[derive(Default)]
83pub struct ShapeBuffer {
84 rustybuzz_buffer: Option<rustybuzz::UnicodeBuffer>,
86
87 scripts: Vec<Script>,
89
90 visual_lines: Vec<VisualLine>,
92}
93
94impl fmt::Debug for ShapeBuffer {
95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96 f.pad("ShapeBuffer { .. }")
97 }
98}
99
100fn shape_fallback(
101 scratch: &mut ShapeBuffer,
102 glyphs: &mut Vec<ShapeGlyph>,
103 shape_plan_cache: &mut ShapePlanCache,
104 font: &Font,
105 line: &str,
106 attrs_list: &AttrsList,
107 start_run: usize,
108 end_run: usize,
109 span_rtl: bool,
110) -> Vec<usize> {
111 let run = &line[start_run..end_run];
112
113 let font_scale = font.rustybuzz().units_per_em() as f32;
114 let ascent = font.rustybuzz().ascender() as f32 / font_scale;
115 let descent = -font.rustybuzz().descender() as f32 / font_scale;
116
117 let mut buffer = scratch.rustybuzz_buffer.take().unwrap_or_default();
118 buffer.set_direction(if span_rtl {
119 rustybuzz::Direction::RightToLeft
120 } else {
121 rustybuzz::Direction::LeftToRight
122 });
123 buffer.push_str(run);
124 buffer.guess_segment_properties();
125
126 let rtl = matches!(buffer.direction(), rustybuzz::Direction::RightToLeft);
127 assert_eq!(rtl, span_rtl);
128
129 let shape_plan = shape_plan_cache.get(font, &buffer);
130 let glyph_buffer = rustybuzz::shape_with_plan(font.rustybuzz(), shape_plan, buffer);
131 let glyph_infos = glyph_buffer.glyph_infos();
132 let glyph_positions = glyph_buffer.glyph_positions();
133
134 let mut missing = Vec::new();
135 glyphs.reserve(glyph_infos.len());
136 let glyph_start = glyphs.len();
137 for (info, pos) in glyph_infos.iter().zip(glyph_positions.iter()) {
138 let x_advance = pos.x_advance as f32 / font_scale;
139 let y_advance = pos.y_advance as f32 / font_scale;
140 let x_offset = pos.x_offset as f32 / font_scale;
141 let y_offset = pos.y_offset as f32 / font_scale;
142
143 let start_glyph = start_run + info.cluster as usize;
144
145 if info.glyph_id == 0 {
146 missing.push(start_glyph);
147 }
148
149 let attrs = attrs_list.get_span(start_glyph);
150 glyphs.push(ShapeGlyph {
151 start: start_glyph,
152 end: end_run, x_advance,
154 y_advance,
155 x_offset,
156 y_offset,
157 ascent,
158 descent,
159 font_monospace_em_width: font.monospace_em_width(),
160 font_id: font.id(),
161 glyph_id: info.glyph_id.try_into().expect("failed to cast glyph ID"),
162 color_opt: attrs.color_opt,
164 metadata: attrs.metadata,
165 cache_key_flags: attrs.cache_key_flags,
166 });
167 }
168
169 if rtl {
171 for i in glyph_start + 1..glyphs.len() {
172 let next_start = glyphs[i - 1].start;
173 let next_end = glyphs[i - 1].end;
174 let prev = &mut glyphs[i];
175 if prev.start == next_start {
176 prev.end = next_end;
177 } else {
178 prev.end = next_start;
179 }
180 }
181 } else {
182 for i in (glyph_start + 1..glyphs.len()).rev() {
183 let next_start = glyphs[i].start;
184 let next_end = glyphs[i].end;
185 let prev = &mut glyphs[i - 1];
186 if prev.start == next_start {
187 prev.end = next_end;
188 } else {
189 prev.end = next_start;
190 }
191 }
192 }
193
194 scratch.rustybuzz_buffer = Some(glyph_buffer.clear());
196
197 missing
198}
199
200fn shape_run(
201 scratch: &mut ShapeBuffer,
202 glyphs: &mut Vec<ShapeGlyph>,
203 font_system: &mut FontSystem,
204 line: &str,
205 attrs_list: &AttrsList,
206 start_run: usize,
207 end_run: usize,
208 span_rtl: bool,
209) {
210 let mut scripts = {
212 let mut scripts = mem::take(&mut scratch.scripts);
213 scripts.clear();
214 scripts
215 };
216 for c in line[start_run..end_run].chars() {
217 match c.script() {
218 Script::Common | Script::Inherited | Script::Latin | Script::Unknown => (),
219 script => {
220 if !scripts.contains(&script) {
221 scripts.push(script);
222 }
223 }
224 }
225 }
226
227 log::trace!(" Run {:?}: '{}'", &scripts, &line[start_run..end_run],);
228
229 let attrs = attrs_list.get_span(start_run);
230
231 let fonts = font_system.get_font_matches(attrs);
232
233 let default_families = [&attrs.family];
234 let mut font_iter = FontFallbackIter::new(
235 font_system,
236 &fonts,
237 &default_families,
238 &scripts,
239 &line[start_run..end_run],
240 );
241
242 let font = font_iter.next().expect("no default font found");
243
244 let glyph_start = glyphs.len();
245 let mut missing = shape_fallback(
246 scratch,
247 glyphs,
248 font_iter.shape_plan_cache(),
249 &font,
250 line,
251 attrs_list,
252 start_run,
253 end_run,
254 span_rtl,
255 );
256
257 while !missing.is_empty() {
259 let font = match font_iter.next() {
260 Some(some) => some,
261 None => break,
262 };
263
264 log::trace!(
265 "Evaluating fallback with font '{}'",
266 font_iter.face_name(font.id())
267 );
268 let mut fb_glyphs = Vec::new();
269 let fb_missing = shape_fallback(
270 scratch,
271 &mut fb_glyphs,
272 font_iter.shape_plan_cache(),
273 &font,
274 line,
275 attrs_list,
276 start_run,
277 end_run,
278 span_rtl,
279 );
280
281 let mut fb_i = 0;
283 while fb_i < fb_glyphs.len() {
284 let start = fb_glyphs[fb_i].start;
285 let end = fb_glyphs[fb_i].end;
286
287 if !missing.contains(&start) || fb_missing.contains(&start) {
289 fb_i += 1;
290 continue;
291 }
292
293 let mut missing_i = 0;
294 while missing_i < missing.len() {
295 if missing[missing_i] >= start && missing[missing_i] < end {
296 missing.remove(missing_i);
298 } else {
299 missing_i += 1;
300 }
301 }
302
303 let mut i = glyph_start;
305 while i < glyphs.len() {
306 if glyphs[i].start >= start && glyphs[i].end <= end {
307 break;
308 } else {
309 i += 1;
310 }
311 }
312
313 while i < glyphs.len() {
315 if glyphs[i].start >= start && glyphs[i].end <= end {
316 let _glyph = glyphs.remove(i);
317 } else {
319 break;
320 }
321 }
322
323 while fb_i < fb_glyphs.len() {
324 if fb_glyphs[fb_i].start >= start && fb_glyphs[fb_i].end <= end {
325 let fb_glyph = fb_glyphs.remove(fb_i);
326 glyphs.insert(i, fb_glyph);
328 i += 1;
329 } else {
330 break;
331 }
332 }
333 }
334 }
335
336 font_iter.check_missing(&line[start_run..end_run]);
338
339 scratch.scripts = scripts;
347}
348
349#[cfg(feature = "shape-run-cache")]
350fn shape_run_cached(
351 scratch: &mut ShapeBuffer,
352 glyphs: &mut Vec<ShapeGlyph>,
353 font_system: &mut FontSystem,
354 line: &str,
355 attrs_list: &AttrsList,
356 start_run: usize,
357 end_run: usize,
358 span_rtl: bool,
359) {
360 use crate::{AttrsOwned, ShapeRunKey};
361
362 let run_range = start_run..end_run;
363 let mut key = ShapeRunKey {
364 text: line[run_range.clone()].to_string(),
365 default_attrs: AttrsOwned::new(attrs_list.defaults()),
366 attrs_spans: Vec::new(),
367 };
368 for (attrs_range, attrs) in attrs_list.spans.overlapping(&run_range) {
369 if attrs == &key.default_attrs {
370 continue;
372 }
373 let start = max(attrs_range.start, start_run)
374 .checked_sub(start_run)
375 .unwrap_or(0);
376 let end = min(attrs_range.end, end_run)
377 .checked_sub(start_run)
378 .unwrap_or(0);
379 if end > start {
380 let range = start..end;
381 key.attrs_spans.push((range, attrs.clone()));
382 }
383 }
384 if let Some(cache_glyphs) = font_system.shape_run_cache.get(&key) {
385 for mut glyph in cache_glyphs.iter().cloned() {
386 glyph.start += start_run;
388 glyph.end += start_run;
389 glyphs.push(glyph);
390 }
391 return;
392 }
393
394 let mut cache_glyphs = Vec::new();
396 shape_run(
397 scratch,
398 &mut cache_glyphs,
399 font_system,
400 line,
401 attrs_list,
402 start_run,
403 end_run,
404 span_rtl,
405 );
406 glyphs.extend_from_slice(&cache_glyphs);
407 for glyph in cache_glyphs.iter_mut() {
408 glyph.start -= start_run;
410 glyph.end -= start_run;
411 }
412 font_system.shape_run_cache.insert(key, cache_glyphs);
413}
414
415#[cfg(feature = "swash")]
416fn shape_skip(
417 font_system: &mut FontSystem,
418 glyphs: &mut Vec<ShapeGlyph>,
419 line: &str,
420 attrs_list: &AttrsList,
421 start_run: usize,
422 end_run: usize,
423) {
424 let attrs = attrs_list.get_span(start_run);
425 let fonts = font_system.get_font_matches(attrs);
426
427 let default_families = [&attrs.family];
428 let mut font_iter = FontFallbackIter::new(font_system, &fonts, &default_families, &[], "");
429
430 let font = font_iter.next().expect("no default font found");
431 let font_id = font.id();
432 let font_monospace_em_width = font.monospace_em_width();
433 let font = font.as_swash();
434
435 let charmap = font.charmap();
436 let metrics = font.metrics(&[]);
437 let glyph_metrics = font.glyph_metrics(&[]).scale(1.0);
438
439 let ascent = metrics.ascent / f32::from(metrics.units_per_em);
440 let descent = metrics.descent / f32::from(metrics.units_per_em);
441
442 glyphs.extend(
443 line[start_run..end_run]
444 .chars()
445 .enumerate()
446 .map(|(i, codepoint)| {
447 let glyph_id = charmap.map(codepoint);
448 let x_advance = glyph_metrics.advance_width(glyph_id);
449 let attrs = attrs_list.get_span(i);
450
451 ShapeGlyph {
452 start: i,
453 end: i + 1,
454 x_advance,
455 y_advance: 0.0,
456 x_offset: 0.0,
457 y_offset: 0.0,
458 ascent,
459 descent,
460 font_monospace_em_width,
461 font_id,
462 glyph_id,
463 color_opt: attrs.color_opt,
464 metadata: attrs.metadata,
465 cache_key_flags: attrs.cache_key_flags,
466 }
467 }),
468 );
469}
470
471#[derive(Clone, Debug)]
473pub struct ShapeGlyph {
474 pub start: usize,
475 pub end: usize,
476 pub x_advance: f32,
477 pub y_advance: f32,
478 pub x_offset: f32,
479 pub y_offset: f32,
480 pub ascent: f32,
481 pub descent: f32,
482 pub font_monospace_em_width: Option<f32>,
483 pub font_id: fontdb::ID,
484 pub glyph_id: u16,
485 pub color_opt: Option<Color>,
486 pub metadata: usize,
487 pub cache_key_flags: CacheKeyFlags,
488}
489
490impl ShapeGlyph {
491 fn layout(
492 &self,
493 font_size: f32,
494 x: f32,
495 y: f32,
496 w: f32,
497 level: unicode_bidi::Level,
498 ) -> LayoutGlyph {
499 LayoutGlyph {
500 start: self.start,
501 end: self.end,
502 font_size,
503 font_id: self.font_id,
504 glyph_id: self.glyph_id,
505 x,
506 y,
507 w,
508 level,
509 x_offset: self.x_offset,
510 y_offset: self.y_offset,
511 color_opt: self.color_opt,
512 metadata: self.metadata,
513 cache_key_flags: self.cache_key_flags,
514 }
515 }
516}
517
518#[derive(Clone, Debug)]
520pub struct ShapeWord {
521 pub blank: bool,
522 pub glyphs: Vec<ShapeGlyph>,
523 pub x_advance: f32,
524 pub y_advance: f32,
525}
526
527impl ShapeWord {
528 pub fn new(
529 font_system: &mut FontSystem,
530 line: &str,
531 attrs_list: &AttrsList,
532 word_range: Range<usize>,
533 level: unicode_bidi::Level,
534 blank: bool,
535 shaping: Shaping,
536 ) -> Self {
537 Self::new_in_buffer(
538 &mut ShapeBuffer::default(),
539 font_system,
540 line,
541 attrs_list,
542 word_range,
543 level,
544 blank,
545 shaping,
546 )
547 }
548
549 #[allow(clippy::too_many_arguments)]
551 pub fn new_in_buffer(
552 scratch: &mut ShapeBuffer,
553 font_system: &mut FontSystem,
554 line: &str,
555 attrs_list: &AttrsList,
556 word_range: Range<usize>,
557 level: unicode_bidi::Level,
558 blank: bool,
559 shaping: Shaping,
560 ) -> Self {
561 let word = &line[word_range.clone()];
562
563 log::trace!(
564 " Word{}: '{}'",
565 if blank { " BLANK" } else { "" },
566 word
567 );
568
569 let mut glyphs = Vec::new();
570 let span_rtl = level.is_rtl();
571
572 let mut start_run = word_range.start;
573 let mut attrs = attrs_list.defaults();
574 for (egc_i, _egc) in word.grapheme_indices(true) {
575 let start_egc = word_range.start + egc_i;
576 let attrs_egc = attrs_list.get_span(start_egc);
577 if !attrs.compatible(&attrs_egc) {
578 shaping.run(
579 scratch,
580 &mut glyphs,
581 font_system,
582 line,
583 attrs_list,
584 start_run,
585 start_egc,
586 span_rtl,
587 );
588
589 start_run = start_egc;
590 attrs = attrs_egc;
591 }
592 }
593 if start_run < word_range.end {
594 shaping.run(
595 scratch,
596 &mut glyphs,
597 font_system,
598 line,
599 attrs_list,
600 start_run,
601 word_range.end,
602 span_rtl,
603 );
604 }
605
606 let mut x_advance = 0.0;
607 let mut y_advance = 0.0;
608 for glyph in &glyphs {
609 x_advance += glyph.x_advance;
610 y_advance += glyph.y_advance;
611 }
612
613 Self {
614 blank,
615 glyphs,
616 x_advance,
617 y_advance,
618 }
619 }
620}
621
622#[derive(Clone, Debug)]
624pub struct ShapeSpan {
625 pub level: unicode_bidi::Level,
626 pub words: Vec<ShapeWord>,
627}
628
629impl ShapeSpan {
630 pub fn new(
631 font_system: &mut FontSystem,
632 line: &str,
633 attrs_list: &AttrsList,
634 span_range: Range<usize>,
635 line_rtl: bool,
636 level: unicode_bidi::Level,
637 shaping: Shaping,
638 ) -> Self {
639 Self::new_in_buffer(
640 &mut ShapeBuffer::default(),
641 font_system,
642 line,
643 attrs_list,
644 span_range,
645 line_rtl,
646 level,
647 shaping,
648 )
649 }
650
651 pub fn new_in_buffer(
653 scratch: &mut ShapeBuffer,
654 font_system: &mut FontSystem,
655 line: &str,
656 attrs_list: &AttrsList,
657 span_range: Range<usize>,
658 line_rtl: bool,
659 level: unicode_bidi::Level,
660 shaping: Shaping,
661 ) -> Self {
662 let span = &line[span_range.start..span_range.end];
663
664 log::trace!(
665 " Span {}: '{}'",
666 if level.is_rtl() { "RTL" } else { "LTR" },
667 span
668 );
669
670 let mut words = Vec::new();
671
672 let mut start_word = 0;
673 for (end_lb, _) in unicode_linebreak::linebreaks(span) {
674 let mut start_lb = end_lb;
675 for (i, c) in span[start_word..end_lb].char_indices().rev() {
676 if c.is_whitespace() {
681 start_lb = start_word + i;
682 } else {
683 break;
684 }
685 }
686 if start_word < start_lb {
687 words.push(ShapeWord::new_in_buffer(
688 scratch,
689 font_system,
690 line,
691 attrs_list,
692 (span_range.start + start_word)..(span_range.start + start_lb),
693 level,
694 false,
695 shaping,
696 ));
697 }
698 if start_lb < end_lb {
699 for (i, c) in span[start_lb..end_lb].char_indices() {
700 words.push(ShapeWord::new_in_buffer(
702 scratch,
703 font_system,
704 line,
705 attrs_list,
706 (span_range.start + start_lb + i)
707 ..(span_range.start + start_lb + i + c.len_utf8()),
708 level,
709 true,
710 shaping,
711 ));
712 }
713 }
714 start_word = end_lb;
715 }
716
717 if line_rtl {
719 for word in &mut words {
720 word.glyphs.reverse();
721 }
722 }
723
724 if line_rtl != level.is_rtl() {
726 words.reverse();
727 }
728
729 ShapeSpan { level, words }
730 }
731}
732
733#[derive(Clone, Debug)]
735pub struct ShapeLine {
736 pub rtl: bool,
737 pub spans: Vec<ShapeSpan>,
738}
739
740type VlRange = (usize, (usize, usize), (usize, usize));
742
743#[derive(Default)]
744struct VisualLine {
745 ranges: Vec<VlRange>,
746 spaces: u32,
747 w: f32,
748}
749
750impl ShapeLine {
751 pub fn new(
755 font_system: &mut FontSystem,
756 line: &str,
757 attrs_list: &AttrsList,
758 shaping: Shaping,
759 ) -> Self {
760 Self::new_in_buffer(
761 &mut ShapeBuffer::default(),
762 font_system,
763 line,
764 attrs_list,
765 shaping,
766 )
767 }
768
769 pub fn new_in_buffer(
776 scratch: &mut ShapeBuffer,
777 font_system: &mut FontSystem,
778 line: &str,
779 attrs_list: &AttrsList,
780 shaping: Shaping,
781 ) -> Self {
782 let mut spans = Vec::new();
783
784 let bidi = unicode_bidi::BidiInfo::new(line, None);
785 let rtl = if bidi.paragraphs.is_empty() {
786 false
787 } else {
788 bidi.paragraphs[0].level.is_rtl()
789 };
790
791 log::trace!("Line {}: '{}'", if rtl { "RTL" } else { "LTR" }, line);
792
793 for para_info in bidi.paragraphs.iter() {
794 let line_rtl = para_info.level.is_rtl();
795 assert_eq!(line_rtl, rtl);
796
797 let line_range = para_info.range.clone();
798 let levels = Self::adjust_levels(&unicode_bidi::Paragraph::new(&bidi, para_info));
799
800 let mut start = line_range.start;
803 let mut run_level = levels[start];
804 spans.reserve(line_range.end - start + 1);
805
806 for (i, &new_level) in levels
807 .iter()
808 .enumerate()
809 .take(line_range.end)
810 .skip(start + 1)
811 {
812 if new_level != run_level {
813 spans.push(ShapeSpan::new_in_buffer(
815 scratch,
816 font_system,
817 line,
818 attrs_list,
819 start..i,
820 line_rtl,
821 run_level,
822 shaping,
823 ));
824 start = i;
825 run_level = new_level;
826 }
827 }
828 spans.push(ShapeSpan::new_in_buffer(
829 scratch,
830 font_system,
831 line,
832 attrs_list,
833 start..line_range.end,
834 line_rtl,
835 run_level,
836 shaping,
837 ));
838 }
839
840 Self { rtl, spans }
841 }
842
843 fn adjust_levels(para: &unicode_bidi::Paragraph) -> Vec<unicode_bidi::Level> {
845 use unicode_bidi::BidiClass::*;
846 let text = para.info.text;
847 let levels = ¶.info.levels;
848 let original_classes = ¶.info.original_classes;
849
850 let mut levels = levels.clone();
851 let line_classes = &original_classes[..];
852 let line_levels = &mut levels[..];
853
854 let mut reset_from: Option<usize> = Some(0);
857 let mut reset_to: Option<usize> = None;
858 for (i, c) in text.char_indices() {
859 match line_classes[i] {
860 RLE | LRE | RLO | LRO | PDF | BN => {}
862 B | S => {
864 assert_eq!(reset_to, None);
865 reset_to = Some(i + c.len_utf8());
866 if reset_from.is_none() {
867 reset_from = Some(i);
868 }
869 }
870 WS | FSI | LRI | RLI | PDI => {
872 if reset_from.is_none() {
873 reset_from = Some(i);
874 }
875 }
876 _ => {
877 reset_from = None;
878 }
879 }
880 if let (Some(from), Some(to)) = (reset_from, reset_to) {
881 for level in &mut line_levels[from..to] {
882 *level = para.para.level;
883 }
884 reset_from = None;
885 reset_to = None;
886 }
887 }
888 if let Some(from) = reset_from {
889 for level in &mut line_levels[from..] {
890 *level = para.para.level;
891 }
892 }
893 levels
894 }
895
896 fn reorder(&self, line_range: &[VlRange]) -> Vec<Range<usize>> {
898 let line: Vec<unicode_bidi::Level> = line_range
899 .iter()
900 .map(|(span_index, _, _)| self.spans[*span_index].level)
901 .collect();
902 let mut runs = Vec::new();
904 let mut start = 0;
905 let mut run_level = line[start];
906 let mut min_level = run_level;
907 let mut max_level = run_level;
908
909 for (i, &new_level) in line.iter().enumerate().skip(start + 1) {
910 if new_level != run_level {
911 runs.push(start..i);
913 start = i;
914 run_level = new_level;
915 min_level = min(run_level, min_level);
916 max_level = max(run_level, max_level);
917 }
918 }
919 runs.push(start..line.len());
920
921 let run_count = runs.len();
922
923 min_level = min_level.new_lowest_ge_rtl().expect("Level error");
928
929 while max_level >= min_level {
930 let mut seq_start = 0;
932 while seq_start < run_count {
933 if line[runs[seq_start].start] < max_level {
934 seq_start += 1;
935 continue;
936 }
937
938 let mut seq_end = seq_start + 1;
940 while seq_end < run_count {
941 if line[runs[seq_end].start] < max_level {
942 break;
943 }
944 seq_end += 1;
945 }
946
947 runs[seq_start..seq_end].reverse();
949
950 seq_start = seq_end;
951 }
952 max_level
953 .lower(1)
954 .expect("Lowering embedding level below zero");
955 }
956
957 runs
958 }
959
960 pub fn layout(
961 &self,
962 font_size: f32,
963 line_width: f32,
964 wrap: Wrap,
965 align: Option<Align>,
966 match_mono_width: Option<f32>,
967 ) -> Vec<LayoutLine> {
968 let mut lines = Vec::with_capacity(1);
969 self.layout_to_buffer(
970 &mut ShapeBuffer::default(),
971 font_size,
972 line_width,
973 wrap,
974 align,
975 &mut lines,
976 match_mono_width,
977 );
978 lines
979 }
980
981 pub fn layout_to_buffer(
982 &self,
983 scratch: &mut ShapeBuffer,
984 font_size: f32,
985 line_width: f32,
986 wrap: Wrap,
987 align: Option<Align>,
988 layout_lines: &mut Vec<LayoutLine>,
989 match_mono_width: Option<f32>,
990 ) {
991 let mut visual_lines: Vec<VisualLine> = {
995 let mut visual_lines = mem::take(&mut scratch.visual_lines);
996 visual_lines.clear();
997 visual_lines
998 };
999
1000 fn add_to_visual_line(
1001 vl: &mut VisualLine,
1002 span_index: usize,
1003 start: (usize, usize),
1004 end: (usize, usize),
1005 width: f32,
1006 number_of_blanks: u32,
1007 ) {
1008 if end == start {
1009 return;
1010 }
1011
1012 vl.ranges.push((span_index, start, end));
1013 vl.w += width;
1014 vl.spaces += number_of_blanks;
1015 }
1016
1017 let mut current_visual_line = VisualLine::default();
1022
1023 if wrap == Wrap::None {
1024 for (span_index, span) in self.spans.iter().enumerate() {
1025 let mut word_range_width = 0.;
1026 let mut number_of_blanks: u32 = 0;
1027 for word in span.words.iter() {
1028 let word_width = font_size * word.x_advance;
1029 word_range_width += word_width;
1030 if word.blank {
1031 number_of_blanks += 1;
1032 }
1033 }
1034 add_to_visual_line(
1035 &mut current_visual_line,
1036 span_index,
1037 (0, 0),
1038 (span.words.len(), 0),
1039 word_range_width,
1040 number_of_blanks,
1041 );
1042 }
1043 } else {
1044 for (span_index, span) in self.spans.iter().enumerate() {
1045 let mut word_range_width = 0.;
1046 let mut width_before_last_blank = 0.;
1047 let mut number_of_blanks: u32 = 0;
1048
1049 if self.rtl != span.level.is_rtl() {
1051 let mut fitting_start = (span.words.len(), 0);
1053 for (i, word) in span.words.iter().enumerate().rev() {
1054 let word_width = font_size * word.x_advance;
1055
1056 if current_visual_line.w + (word_range_width + word_width)
1060 <= line_width
1061 || (word.blank
1064 && (current_visual_line.w + word_range_width) <= line_width)
1065 {
1066 if word.blank {
1068 number_of_blanks += 1;
1069 width_before_last_blank = word_range_width;
1070 }
1071 word_range_width += word_width;
1072 continue;
1073 } else if wrap == Wrap::Glyph
1074 || (wrap == Wrap::WordOrGlyph && word_width > line_width)
1076 {
1077 if word_range_width > 0.
1079 && wrap == Wrap::WordOrGlyph
1080 && word_width > line_width
1081 {
1082 add_to_visual_line(
1083 &mut current_visual_line,
1084 span_index,
1085 (i + 1, 0),
1086 fitting_start,
1087 word_range_width,
1088 number_of_blanks,
1089 );
1090
1091 visual_lines.push(current_visual_line);
1092 current_visual_line = VisualLine::default();
1093
1094 number_of_blanks = 0;
1095 word_range_width = 0.;
1096
1097 fitting_start = (i, 0);
1098 }
1099
1100 for (glyph_i, glyph) in word.glyphs.iter().enumerate().rev() {
1101 let glyph_width = font_size * glyph.x_advance;
1102 if current_visual_line.w + (word_range_width + glyph_width)
1103 <= line_width
1104 {
1105 word_range_width += glyph_width;
1106 continue;
1107 } else {
1108 add_to_visual_line(
1109 &mut current_visual_line,
1110 span_index,
1111 (i, glyph_i + 1),
1112 fitting_start,
1113 word_range_width,
1114 number_of_blanks,
1115 );
1116 visual_lines.push(current_visual_line);
1117 current_visual_line = VisualLine::default();
1118
1119 number_of_blanks = 0;
1120 word_range_width = glyph_width;
1121 fitting_start = (i, glyph_i + 1);
1122 }
1123 }
1124 } else {
1125 if word_range_width > 0. {
1129 let trailing_blank = span
1132 .words
1133 .get(i + 1)
1134 .map_or(false, |previous_word| previous_word.blank);
1135 if trailing_blank {
1136 number_of_blanks = number_of_blanks.saturating_sub(1);
1137 add_to_visual_line(
1138 &mut current_visual_line,
1139 span_index,
1140 (i + 2, 0),
1141 fitting_start,
1142 width_before_last_blank,
1143 number_of_blanks,
1144 );
1145 } else {
1146 add_to_visual_line(
1147 &mut current_visual_line,
1148 span_index,
1149 (i + 1, 0),
1150 fitting_start,
1151 word_range_width,
1152 number_of_blanks,
1153 );
1154 }
1155
1156 visual_lines.push(current_visual_line);
1157 current_visual_line = VisualLine::default();
1158 number_of_blanks = 0;
1159 }
1160
1161 if word.blank {
1162 word_range_width = 0.;
1163 fitting_start = (i, 0);
1164 } else {
1165 word_range_width = word_width;
1166 fitting_start = (i + 1, 0);
1167 }
1168 }
1169 }
1170 add_to_visual_line(
1171 &mut current_visual_line,
1172 span_index,
1173 (0, 0),
1174 fitting_start,
1175 word_range_width,
1176 number_of_blanks,
1177 );
1178 } else {
1179 let mut fitting_start = (0, 0);
1181 for (i, word) in span.words.iter().enumerate() {
1182 let word_width = font_size * word.x_advance;
1183 if current_visual_line.w + (word_range_width + word_width)
1184 <= line_width
1185 || (word.blank
1188 && (current_visual_line.w + word_range_width) <= line_width)
1189 {
1190 if word.blank {
1192 number_of_blanks += 1;
1193 width_before_last_blank = word_range_width;
1194 }
1195 word_range_width += word_width;
1196 continue;
1197 } else if wrap == Wrap::Glyph
1198 || (wrap == Wrap::WordOrGlyph && word_width > line_width)
1200 {
1201 if word_range_width > 0.
1203 && wrap == Wrap::WordOrGlyph
1204 && word_width > line_width
1205 {
1206 add_to_visual_line(
1207 &mut current_visual_line,
1208 span_index,
1209 fitting_start,
1210 (i, 0),
1211 word_range_width,
1212 number_of_blanks,
1213 );
1214
1215 visual_lines.push(current_visual_line);
1216 current_visual_line = VisualLine::default();
1217
1218 number_of_blanks = 0;
1219 word_range_width = 0.;
1220
1221 fitting_start = (i, 0);
1222 }
1223
1224 for (glyph_i, glyph) in word.glyphs.iter().enumerate() {
1225 let glyph_width = font_size * glyph.x_advance;
1226 if current_visual_line.w + (word_range_width + glyph_width)
1227 <= line_width
1228 {
1229 word_range_width += glyph_width;
1230 continue;
1231 } else {
1232 add_to_visual_line(
1233 &mut current_visual_line,
1234 span_index,
1235 fitting_start,
1236 (i, glyph_i),
1237 word_range_width,
1238 number_of_blanks,
1239 );
1240 visual_lines.push(current_visual_line);
1241 current_visual_line = VisualLine::default();
1242
1243 number_of_blanks = 0;
1244 word_range_width = glyph_width;
1245 fitting_start = (i, glyph_i);
1246 }
1247 }
1248 } else {
1249 if word_range_width > 0. {
1253 let trailing_blank = i > 0 && span.words[i - 1].blank;
1256
1257 if trailing_blank {
1258 number_of_blanks = number_of_blanks.saturating_sub(1);
1259 add_to_visual_line(
1260 &mut current_visual_line,
1261 span_index,
1262 fitting_start,
1263 (i - 1, 0),
1264 width_before_last_blank,
1265 number_of_blanks,
1266 );
1267 } else {
1268 add_to_visual_line(
1269 &mut current_visual_line,
1270 span_index,
1271 fitting_start,
1272 (i, 0),
1273 word_range_width,
1274 number_of_blanks,
1275 );
1276 }
1277
1278 visual_lines.push(current_visual_line);
1279 current_visual_line = VisualLine::default();
1280 number_of_blanks = 0;
1281 }
1282
1283 if word.blank {
1284 word_range_width = 0.;
1285 fitting_start = (i + 1, 0);
1286 } else {
1287 word_range_width = word_width;
1288 fitting_start = (i, 0);
1289 }
1290 }
1291 }
1292 add_to_visual_line(
1293 &mut current_visual_line,
1294 span_index,
1295 fitting_start,
1296 (span.words.len(), 0),
1297 word_range_width,
1298 number_of_blanks,
1299 );
1300 }
1301 }
1302 }
1303
1304 if !current_visual_line.ranges.is_empty() {
1305 visual_lines.push(current_visual_line);
1306 }
1307
1308 let align = align.unwrap_or({
1310 if self.rtl {
1311 Align::Right
1312 } else {
1313 Align::Left
1314 }
1315 });
1316
1317 let start_x = if self.rtl { line_width } else { 0.0 };
1318
1319 let number_of_visual_lines = visual_lines.len();
1320 for (index, visual_line) in visual_lines.iter().enumerate() {
1321 if visual_line.ranges.is_empty() {
1322 continue;
1323 }
1324 let new_order = self.reorder(&visual_line.ranges);
1325 let mut glyphs = Vec::with_capacity(1);
1326 let mut x = start_x;
1327 let mut y = 0.;
1328 let mut max_ascent: f32 = 0.;
1329 let mut max_descent: f32 = 0.;
1330 let alignment_correction = match (align, self.rtl) {
1331 (Align::Left, true) => line_width - visual_line.w,
1332 (Align::Left, false) => 0.,
1333 (Align::Right, true) => 0.,
1334 (Align::Right, false) => line_width - visual_line.w,
1335 (Align::Center, _) => (line_width - visual_line.w) / 2.0,
1336 (Align::End, _) => line_width - visual_line.w,
1337 (Align::Justified, _) => 0.,
1338 };
1339
1340 if self.rtl {
1341 x -= alignment_correction;
1342 } else {
1343 x += alignment_correction;
1344 }
1345
1346 let justification_expansion = if matches!(align, Align::Justified)
1362 && visual_line.spaces > 0
1363 && index != number_of_visual_lines - 1
1365 {
1366 (line_width - visual_line.w) / visual_line.spaces as f32
1367 } else {
1368 0.
1369 };
1370
1371 let mut process_range = |range: Range<usize>| {
1372 for &(span_index, (starting_word, starting_glyph), (ending_word, ending_glyph)) in
1373 visual_line.ranges[range.clone()].iter()
1374 {
1375 let span = &self.spans[span_index];
1376 for i in starting_word..ending_word + usize::from(ending_glyph != 0) {
1378 let word = &span.words[i];
1379 let included_glyphs = match (i == starting_word, i == ending_word) {
1380 (false, false) => &word.glyphs[..],
1381 (true, false) => &word.glyphs[starting_glyph..],
1382 (false, true) => &word.glyphs[..ending_glyph],
1383 (true, true) => &word.glyphs[starting_glyph..ending_glyph],
1384 };
1385
1386 let match_mono_em_width = match_mono_width.map(|w| w / font_size);
1387
1388 for glyph in included_glyphs {
1389 let glyph_font_size = match (
1390 match_mono_em_width,
1391 glyph.font_monospace_em_width,
1392 ) {
1393 (Some(match_em_width), Some(glyph_em_width))
1394 if glyph_em_width != match_em_width =>
1395 {
1396 let glyph_to_match_factor = glyph_em_width / match_em_width;
1397 let glyph_font_size = math::roundf(glyph_to_match_factor)
1398 .max(1.0)
1399 / glyph_to_match_factor
1400 * font_size;
1401 log::trace!("Adjusted glyph font size ({font_size} => {glyph_font_size})");
1402 glyph_font_size
1403 }
1404 _ => font_size,
1405 };
1406
1407 let x_advance = glyph_font_size * glyph.x_advance
1408 + if word.blank {
1409 justification_expansion
1410 } else {
1411 0.0
1412 };
1413 if self.rtl {
1414 x -= x_advance;
1415 }
1416 let y_advance = glyph_font_size * glyph.y_advance;
1417 glyphs.push(glyph.layout(glyph_font_size, x, y, x_advance, span.level));
1418 if !self.rtl {
1419 x += x_advance;
1420 }
1421 y += y_advance;
1422 max_ascent = max_ascent.max(glyph.ascent);
1423 max_descent = max_descent.max(glyph.descent);
1424 }
1425 }
1426 }
1427 };
1428
1429 if self.rtl {
1430 for range in new_order.into_iter().rev() {
1431 process_range(range);
1432 }
1433 } else {
1434 for range in new_order {
1436 process_range(range);
1437 }
1438 }
1439
1440 layout_lines.push(LayoutLine {
1441 w: if align != Align::Justified {
1442 visual_line.w
1443 } else if self.rtl {
1444 start_x - x
1445 } else {
1446 x
1447 },
1448 max_ascent: max_ascent * font_size,
1449 max_descent: max_descent * font_size,
1450 glyphs,
1451 });
1452 }
1453
1454 if layout_lines.is_empty() {
1456 layout_lines.push(LayoutLine {
1457 w: 0.0,
1458 max_ascent: 0.0,
1459 max_descent: 0.0,
1460 glyphs: Default::default(),
1461 });
1462 }
1463
1464 scratch.visual_lines = visual_lines;
1466 }
1467}