1use std::fmt;
6use std::ops::Range;
7use std::sync::Arc;
8use std::vec::Vec;
9
10use app_units::Au;
11use euclid::default::Point2D;
12use euclid::num::Zero;
13use itertools::Either;
14use log::{debug, error};
15use malloc_size_of_derive::MallocSizeOf;
16use serde::{Deserialize, Serialize};
17
18use crate::{GlyphShapingResult, ShapedGlyph, ShapingOptions};
19
20#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
28pub struct GlyphEntry {
29 value: u32,
30}
31
32impl GlyphEntry {
33 fn new(value: u32) -> GlyphEntry {
34 GlyphEntry { value }
35 }
36
37 fn simple(id: GlyphId, advance: Au) -> GlyphEntry {
39 assert!(is_simple_glyph_id(id));
40 assert!(is_simple_advance(advance));
41
42 let id_mask = id;
43 let Au(advance) = advance;
44 let advance_mask = (advance as u32) << GLYPH_ADVANCE_SHIFT;
45
46 GlyphEntry::new(id_mask | advance_mask | FLAG_IS_SIMPLE_GLYPH)
47 }
48
49 fn complex(detailed_glyph_index: usize) -> GlyphEntry {
50 assert!(detailed_glyph_index as u32 <= u32::MAX >> 1);
51 GlyphEntry::new(detailed_glyph_index as u32)
52 }
53}
54
55pub(crate) type GlyphId = u32;
57
58const FLAG_CHAR_IS_WORD_SEPARATOR: u32 = 0x40000000;
61const FLAG_IS_SIMPLE_GLYPH: u32 = 0x80000000;
62
63const GLYPH_ADVANCE_MASK: u32 = 0x3FFF0000;
65const GLYPH_ADVANCE_SHIFT: u32 = 16;
66const GLYPH_ID_MASK: u32 = 0x0000FFFF;
67
68fn is_simple_glyph_id(id: GlyphId) -> bool {
75 (id & GLYPH_ID_MASK) == id
76}
77
78fn is_simple_advance(advance: Au) -> bool {
79 advance >= Au::zero() && {
80 let unsigned_au = advance.0 as u32;
81 (unsigned_au & (GLYPH_ADVANCE_MASK >> GLYPH_ADVANCE_SHIFT)) == unsigned_au
82 }
83}
84
85impl GlyphEntry {
88 #[inline(always)]
89 fn advance(&self) -> Au {
90 Au::new(((self.value & GLYPH_ADVANCE_MASK) >> GLYPH_ADVANCE_SHIFT) as i32)
91 }
92
93 #[inline]
94 fn id(&self) -> GlyphId {
95 self.value & GLYPH_ID_MASK
96 }
97
98 fn char_is_word_separator(&self) -> bool {
105 self.has_flag(FLAG_CHAR_IS_WORD_SEPARATOR)
106 }
107
108 #[inline(always)]
109 fn set_char_is_word_separator(&mut self) {
110 self.value |= FLAG_CHAR_IS_WORD_SEPARATOR;
111 }
112
113 fn detailed_glyph_index(&self) -> usize {
114 self.value as usize
115 }
116
117 #[inline(always)]
118 fn is_simple(&self) -> bool {
119 self.has_flag(FLAG_IS_SIMPLE_GLYPH)
120 }
121
122 #[inline(always)]
123 fn has_flag(&self, flag: u32) -> bool {
124 (self.value & flag) != 0
125 }
126}
127
128#[derive(Clone, Deserialize, MallocSizeOf, Serialize)]
129pub struct DetailedGlyphEntry {
130 id: u32,
132 advance: Au,
135 offset: Option<Point2D<Au>>,
137 character_count: usize,
140 is_word_separator: bool,
142}
143
144#[derive(Clone, Copy)]
147pub enum GlyphInfo<'a> {
148 Simple(&'a GlyphEntry),
149 Detail(&'a DetailedGlyphEntry),
150}
151
152impl GlyphInfo<'_> {
153 pub fn id(self) -> GlyphId {
154 match self {
155 GlyphInfo::Simple(entry) => entry.id(),
156 GlyphInfo::Detail(entry) => entry.id,
157 }
158 }
159
160 #[inline(always)]
161 pub fn advance(self) -> Au {
162 match self {
163 GlyphInfo::Simple(entry) => entry.advance(),
164 GlyphInfo::Detail(entry) => entry.advance,
165 }
166 }
167
168 #[inline]
169 pub fn offset(self) -> Option<Point2D<Au>> {
170 match self {
171 GlyphInfo::Simple(..) => None,
172 GlyphInfo::Detail(entry) => entry.offset,
173 }
174 }
175
176 #[inline]
177 pub fn char_is_word_separator(self) -> bool {
178 match self {
179 GlyphInfo::Simple(entry) => entry.char_is_word_separator(),
180 GlyphInfo::Detail(entry) => entry.is_word_separator,
181 }
182 }
183
184 #[inline]
188 pub fn character_count(self) -> usize {
189 match self {
190 GlyphInfo::Simple(..) => 1,
191 GlyphInfo::Detail(entry) => entry.character_count,
192 }
193 }
194}
195
196#[derive(Clone, Deserialize, MallocSizeOf, Serialize)]
215pub struct ShapedText {
216 glyphs: Vec<GlyphEntry>,
222
223 detailed_glyphs: Vec<DetailedGlyphEntry>,
226
227 total_advance: Au,
229
230 character_count: usize,
232
233 total_word_separators: usize,
236
237 is_rtl: bool,
240}
241
242impl ShapedText {
243 pub(crate) fn new(length: usize, is_rtl: bool) -> Self {
247 Self {
248 glyphs: Vec::with_capacity(length),
249 detailed_glyphs: Default::default(),
250 total_advance: Au::zero(),
251 character_count: 0,
252 total_word_separators: 0,
253 is_rtl,
254 }
255 }
256
257 pub(crate) fn with_shaped_glyph_data(
265 text: &str,
266 options: &ShapingOptions,
267 shaped_glyph_data: &impl GlyphShapingResult,
268 ) -> Self {
269 debug!(
270 "Shaped: '{text:?}: {:?}",
271 shaped_glyph_data.iter().collect::<Vec<_>>()
272 );
273
274 let shaped_run_is_rtl = shaped_glyph_data.is_rtl();
278 let mut characters = if !shaped_run_is_rtl {
279 Either::Left(text.char_indices())
280 } else {
281 Either::Right(text.char_indices().rev())
282 };
283
284 let mut previous_character_offset = None;
285 let mut glyph_store = ShapedText::new(shaped_glyph_data.len(), shaped_run_is_rtl);
286 if shaped_glyph_data.len() == 0 {
287 return glyph_store;
288 }
289
290 for mut shaped_glyph in shaped_glyph_data.iter() {
291 let glyph_cluster = shaped_glyph.string_byte_offset;
294
295 if let Some(previous_character_offset) = previous_character_offset &&
296 previous_character_offset == glyph_cluster
297 {
298 glyph_store.add_glyph_for_current_character(&shaped_glyph, options);
299 continue;
300 }
301
302 previous_character_offset = Some(glyph_cluster);
303 let mut characters_skipped = 0;
304 let Some(character) = characters.find_map(|(character_offset, character)| {
305 if glyph_cluster == character_offset {
306 Some(character)
307 } else {
308 characters_skipped += 1;
309 None
310 }
311 }) else {
312 error!("HarfBuzz shaping results extended past character count");
313 return glyph_store;
314 };
315
316 shaped_glyph.adjust_for_character(character, options);
317
318 if shaped_run_is_rtl {
322 glyph_store.add_glyph(character, &shaped_glyph);
323 }
324
325 for _ in 0..characters_skipped {
326 glyph_store.extend_previous_glyph_by_character()
327 }
328
329 if !shaped_run_is_rtl {
333 glyph_store.add_glyph(character, &shaped_glyph);
334 }
335 }
336
337 for (_, _) in characters {
339 glyph_store.extend_previous_glyph_by_character();
340 }
341
342 glyph_store
343 }
344
345 #[inline]
347 pub fn glyph_count(&self) -> usize {
348 self.glyphs.len()
349 }
350
351 pub fn character_count(&self) -> usize {
353 self.character_count
354 }
355
356 #[inline]
358 pub(crate) fn add_glyph(&mut self, character: char, glyph: &ShapedGlyph) {
359 if !glyph.can_be_simple_glyph() {
360 self.add_detailed_glyph(glyph, Some(character), 1);
361 return;
362 }
363
364 let mut simple_glyph_entry = GlyphEntry::simple(glyph.glyph_id, glyph.advance);
365 if character_is_word_separator(character) {
366 self.total_word_separators += 1;
367 simple_glyph_entry.set_char_is_word_separator();
368 }
369
370 self.character_count += 1;
371 self.total_advance += glyph.advance;
372 self.glyphs.push(simple_glyph_entry)
373 }
374
375 fn add_detailed_glyph(
376 &mut self,
377 shaped_glyph: &ShapedGlyph,
378 character: Option<char>,
379 character_count: usize,
380 ) {
381 let is_word_separator = character.is_some_and(character_is_word_separator);
382 if is_word_separator {
383 self.total_word_separators += 1;
384 }
385
386 self.character_count += character_count;
387 self.total_advance += shaped_glyph.advance;
388 self.detailed_glyphs.push(DetailedGlyphEntry {
389 id: shaped_glyph.glyph_id,
390 advance: shaped_glyph.advance,
391 offset: shaped_glyph.offset,
392 character_count,
393 is_word_separator,
394 });
395 self.glyphs
396 .push(GlyphEntry::complex(self.detailed_glyphs.len() - 1));
397 }
398
399 fn extend_previous_glyph_by_character(&mut self) {
400 let detailed_glyph_index = self.ensure_last_glyph_is_detailed();
401 let detailed_glyph = self
402 .detailed_glyphs
403 .get_mut(detailed_glyph_index)
404 .expect("GlyphEntry should have valid index to detailed glyph");
405 detailed_glyph.character_count += 1;
406 self.character_count += 1;
407 }
408
409 fn add_glyph_for_current_character(
410 &mut self,
411 shaped_glyph: &ShapedGlyph,
412 options: &ShapingOptions,
413 ) {
414 if let Some(letter_spacing) = options.letter_spacing &&
420 letter_spacing != Au::zero()
421 {
422 let last_glyph_index = self.ensure_last_glyph_is_detailed();
423 self.detailed_glyphs[last_glyph_index].advance -= letter_spacing;
424 }
425
426 self.add_detailed_glyph(shaped_glyph, None, 0);
429 }
430
431 fn ensure_last_glyph_is_detailed(&mut self) -> usize {
435 let last_glyph = self
436 .glyphs
437 .last_mut()
438 .expect("Should never call this before any glyphs have been added.");
439 if !last_glyph.is_simple() {
440 return last_glyph.detailed_glyph_index();
441 }
442
443 self.detailed_glyphs.push(DetailedGlyphEntry {
444 id: last_glyph.id(),
445 advance: last_glyph.advance(),
446 offset: Default::default(),
447 character_count: 1,
448 is_word_separator: last_glyph.char_is_word_separator(),
449 });
450
451 let detailed_glyph_index = self.detailed_glyphs.len() - 1;
452 *last_glyph = GlyphEntry::complex(detailed_glyph_index);
453 detailed_glyph_index
454 }
455
456 pub fn glyphs(&self) -> impl DoubleEndedIterator<Item = GlyphInfo<'_>> + use<'_> {
457 self.glyph_slice(0..self.glyphs.len())
458 }
459
460 fn glyph_slice(
461 &self,
462 glyph_range: Range<usize>,
463 ) -> impl DoubleEndedIterator<Item = GlyphInfo<'_>> + use<'_> {
464 self.glyphs[glyph_range].iter().map(|entry| {
465 if entry.is_simple() {
466 GlyphInfo::Simple(entry)
467 } else {
468 GlyphInfo::Detail(&self.detailed_glyphs[entry.detailed_glyph_index()])
469 }
470 })
471 }
472}
473
474impl ShapedGlyph {
475 fn can_be_simple_glyph(&self) -> bool {
476 is_simple_glyph_id(self.glyph_id) &&
477 is_simple_advance(self.advance) &&
478 self.offset
479 .is_none_or(|offset| offset == Default::default())
480 }
481
482 pub(crate) fn adjust_for_character(
485 &mut self,
486 character: char,
487 shaping_options: &ShapingOptions,
488 ) {
489 if let Some(letter_spacing) = shaping_options.letter_spacing_for_character(character) {
490 self.advance += letter_spacing;
491 };
492
493 if let Some(word_spacing) = shaping_options.word_spacing &&
498 (character == ' ' || character == '\u{a0}')
499 {
500 self.advance += word_spacing;
502 }
503 }
504}
505
506fn character_is_word_separator(character: char) -> bool {
507 let is_word_separator = matches!(
511 character,
512 ' ' |
513 '\u{00A0}' | '\u{1361}' | '\u{10100}' | '\u{10101}' | '\u{1039F}' | '\u{1091F}' );
520 is_word_separator
521}
522
523impl fmt::Debug for ShapedText {
524 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
525 writeln!(formatter, "ShapedText:")?;
526 for entry in self.glyphs.iter() {
527 if entry.is_simple() {
528 writeln!(
529 formatter,
530 " simple id={:?} advance={:?}",
531 entry.id(),
532 entry.advance()
533 )?;
534 continue;
535 } else {
536 let detailed_glyph = &self.detailed_glyphs[entry.detailed_glyph_index()];
537 writeln!(
538 formatter,
539 " detailed id={:?} advance={:?} characters={:?}",
540 detailed_glyph.id, detailed_glyph.advance, detailed_glyph.character_count,
541 )?;
542 }
543 }
544 Ok(())
545 }
546}
547
548#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
549pub enum ShapedTextSliceType {
550 Word,
552 WhiteSpace,
554 WordAndWhiteSpace,
558}
559
560#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
564pub struct ShapedTextSlice {
565 #[conditional_malloc_size_of]
567 shaped_text: Arc<ShapedText>,
568
569 glyph_range: Range<usize>,
571
572 total_advance: Au,
574
575 character_count: usize,
577
578 total_word_separators: usize,
581
582 slice_type: ShapedTextSliceType,
584}
585
586impl ShapedTextSlice {
587 #[inline]
589 pub fn glyph_count(&self) -> usize {
590 self.glyph_range.len()
591 }
592
593 #[inline]
597 pub fn character_count(&self) -> usize {
598 self.character_count
599 }
600
601 #[inline]
603 pub fn total_advance(&self) -> Au {
604 self.total_advance
605 }
606
607 #[inline]
609 pub fn total_word_separators(&self) -> usize {
610 self.total_word_separators
611 }
612
613 #[inline]
615 pub fn is_whitespace(&self) -> bool {
616 matches!(self.slice_type, ShapedTextSliceType::WhiteSpace)
617 }
618
619 #[inline]
621 pub fn ends_with_whitespace(&self) -> bool {
622 match self.slice_type {
623 ShapedTextSliceType::Word => false,
624 ShapedTextSliceType::WhiteSpace | ShapedTextSliceType::WordAndWhiteSpace => true,
625 }
626 }
627
628 pub fn glyphs(&self) -> impl DoubleEndedIterator<Item = GlyphInfo<'_>> + use<'_> {
630 self.shaped_text.glyph_slice(self.glyph_range.clone())
631 }
632}
633
634pub struct ShapedTextSlicer {
636 current_glyph_offset: usize,
637 current_character_offset: usize,
638 shaped_text: Arc<ShapedText>,
639}
640
641impl ShapedTextSlicer {
642 pub fn new(shaped_text: Arc<ShapedText>) -> Self {
643 let current_glyph_offset = if shaped_text.is_rtl {
644 shaped_text.glyph_count()
645 } else {
646 0
647 };
648
649 Self {
650 current_glyph_offset,
651 current_character_offset: 0,
652 shaped_text,
653 }
654 }
655
656 pub fn slice_until_character_offset(
661 &mut self,
662 desired_character_offset: usize,
663 slice_type: ShapedTextSliceType,
664 ) -> Option<Arc<ShapedTextSlice>> {
665 let mut glyph_count = 0;
666 let mut total_word_separators = 0;
667 let mut total_advance = Au::zero();
668 let original_character_offset = self.current_character_offset;
669
670 if self.current_character_offset >= desired_character_offset {
671 return None;
672 }
673
674 let iterator = if self.shaped_text.is_rtl {
679 Either::Left(
680 self.shaped_text
681 .glyph_slice(0..self.current_glyph_offset)
682 .rev(),
683 )
684 } else {
685 Either::Right(
686 self.shaped_text
687 .glyph_slice(self.current_glyph_offset..self.shaped_text.glyph_count()),
688 )
689 };
690
691 for glyph in iterator {
692 if self.current_character_offset >= desired_character_offset &&
695 glyph.character_count() > 0
696 {
697 break;
698 }
699
700 glyph_count += 1;
701 self.current_character_offset += glyph.character_count();
702 total_advance += glyph.advance();
703 if glyph.char_is_word_separator() {
704 total_word_separators += 1;
705 }
706 }
707
708 let (new_glyph_offset, glyph_range) = if self.shaped_text.is_rtl {
709 assert!(self.current_glyph_offset >= glyph_count);
710 let new_glyph_offset = self.current_glyph_offset - glyph_count;
711 (
712 new_glyph_offset,
713 new_glyph_offset..self.current_glyph_offset,
714 )
715 } else {
716 let new_glyph_offset = self.current_glyph_offset + glyph_count;
717 (
718 new_glyph_offset,
719 self.current_glyph_offset..new_glyph_offset,
720 )
721 };
722
723 if glyph_count == 0 {
724 return None;
725 }
726
727 self.current_glyph_offset = new_glyph_offset;
728 Some(Arc::new(ShapedTextSlice {
729 shaped_text: self.shaped_text.clone(),
730 glyph_range,
731 total_advance,
732 character_count: self.current_character_offset - original_character_offset,
733 total_word_separators,
734 slice_type,
735 }))
736 }
737}