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 for mut shaped_glyph in shaped_glyph_data.iter() {
287 let glyph_cluster = shaped_glyph.string_byte_offset;
290
291 if let Some(previous_character_offset) = previous_character_offset {
292 if previous_character_offset == glyph_cluster {
293 glyph_store.add_glyph_for_current_character(&shaped_glyph, options);
294 continue;
295 }
296 }
297
298 previous_character_offset = Some(glyph_cluster);
299 let mut characters_skipped = 0;
300 let Some(character) = characters.find_map(|(character_offset, character)| {
301 if glyph_cluster == character_offset {
302 Some(character)
303 } else {
304 characters_skipped += 1;
305 None
306 }
307 }) else {
308 error!("HarfBuzz shaping results extended past character count");
309 return glyph_store;
310 };
311
312 shaped_glyph.adjust_for_character(character, options);
313
314 if shaped_run_is_rtl {
318 glyph_store.add_glyph(character, &shaped_glyph);
319 }
320
321 for _ in 0..characters_skipped {
322 glyph_store.extend_previous_glyph_by_character()
323 }
324
325 if !shaped_run_is_rtl {
329 glyph_store.add_glyph(character, &shaped_glyph);
330 }
331 }
332
333 for (_, _) in characters {
335 glyph_store.extend_previous_glyph_by_character();
336 }
337
338 glyph_store
339 }
340
341 #[inline]
343 pub fn glyph_count(&self) -> usize {
344 self.glyphs.len()
345 }
346
347 #[inline]
349 pub(crate) fn add_glyph(&mut self, character: char, glyph: &ShapedGlyph) {
350 if !glyph.can_be_simple_glyph() {
351 self.add_detailed_glyph(glyph, Some(character), 1);
352 return;
353 }
354
355 let mut simple_glyph_entry = GlyphEntry::simple(glyph.glyph_id, glyph.advance);
356 if character_is_word_separator(character) {
357 self.total_word_separators += 1;
358 simple_glyph_entry.set_char_is_word_separator();
359 }
360
361 self.character_count += 1;
362 self.total_advance += glyph.advance;
363 self.glyphs.push(simple_glyph_entry)
364 }
365
366 fn add_detailed_glyph(
367 &mut self,
368 shaped_glyph: &ShapedGlyph,
369 character: Option<char>,
370 character_count: usize,
371 ) {
372 let is_word_separator = character.is_some_and(character_is_word_separator);
373 if is_word_separator {
374 self.total_word_separators += 1;
375 }
376
377 self.character_count += character_count;
378 self.total_advance += shaped_glyph.advance;
379 self.detailed_glyphs.push(DetailedGlyphEntry {
380 id: shaped_glyph.glyph_id,
381 advance: shaped_glyph.advance,
382 offset: shaped_glyph.offset,
383 character_count,
384 is_word_separator,
385 });
386 self.glyphs
387 .push(GlyphEntry::complex(self.detailed_glyphs.len() - 1));
388 }
389
390 fn extend_previous_glyph_by_character(&mut self) {
391 let detailed_glyph_index = self.ensure_last_glyph_is_detailed();
392 let detailed_glyph = self
393 .detailed_glyphs
394 .get_mut(detailed_glyph_index)
395 .expect("GlyphEntry should have valid index to detailed glyph");
396 detailed_glyph.character_count += 1;
397 self.character_count += 1;
398 }
399
400 fn add_glyph_for_current_character(
401 &mut self,
402 shaped_glyph: &ShapedGlyph,
403 options: &ShapingOptions,
404 ) {
405 if let Some(letter_spacing) = options.letter_spacing {
411 if letter_spacing != Au::zero() {
412 let last_glyph_index = self.ensure_last_glyph_is_detailed();
413 self.detailed_glyphs[last_glyph_index].advance -= letter_spacing;
414 }
415 }
416
417 self.add_detailed_glyph(shaped_glyph, None, 0);
420 }
421
422 fn ensure_last_glyph_is_detailed(&mut self) -> usize {
426 let last_glyph = self
427 .glyphs
428 .last_mut()
429 .expect("Should never call this before any glyphs have been added.");
430 if !last_glyph.is_simple() {
431 return last_glyph.detailed_glyph_index();
432 }
433
434 self.detailed_glyphs.push(DetailedGlyphEntry {
435 id: last_glyph.id(),
436 advance: last_glyph.advance(),
437 offset: Default::default(),
438 character_count: 1,
439 is_word_separator: last_glyph.char_is_word_separator(),
440 });
441
442 let detailed_glyph_index = self.detailed_glyphs.len() - 1;
443 *last_glyph = GlyphEntry::complex(detailed_glyph_index);
444 detailed_glyph_index
445 }
446
447 pub fn glyphs(&self) -> impl DoubleEndedIterator<Item = GlyphInfo<'_>> + use<'_> {
448 self.glyph_slice(0..self.glyphs.len())
449 }
450
451 fn glyph_slice(
452 &self,
453 glyph_range: Range<usize>,
454 ) -> impl DoubleEndedIterator<Item = GlyphInfo<'_>> + use<'_> {
455 self.glyphs[glyph_range].iter().map(|entry| {
456 if entry.is_simple() {
457 GlyphInfo::Simple(entry)
458 } else {
459 GlyphInfo::Detail(&self.detailed_glyphs[entry.detailed_glyph_index()])
460 }
461 })
462 }
463}
464
465impl ShapedGlyph {
466 fn can_be_simple_glyph(&self) -> bool {
467 is_simple_glyph_id(self.glyph_id) &&
468 is_simple_advance(self.advance) &&
469 self.offset
470 .is_none_or(|offset| offset == Default::default())
471 }
472
473 pub(crate) fn adjust_for_character(
476 &mut self,
477 character: char,
478 shaping_options: &ShapingOptions,
479 ) {
480 if let Some(letter_spacing) = shaping_options.letter_spacing_for_character(character) {
481 self.advance += letter_spacing;
482 };
483
484 if let Some(word_spacing) = shaping_options.word_spacing {
489 if character == ' ' || character == '\u{a0}' {
490 self.advance += word_spacing;
492 }
493 }
494 }
495}
496
497fn character_is_word_separator(character: char) -> bool {
498 let is_word_separator = matches!(
502 character,
503 ' ' |
504 '\u{00A0}' | '\u{1361}' | '\u{10100}' | '\u{10101}' | '\u{1039F}' | '\u{1091F}' );
511 is_word_separator
512}
513
514impl fmt::Debug for ShapedText {
515 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
516 writeln!(formatter, "ShapedText:")?;
517 for entry in self.glyphs.iter() {
518 if entry.is_simple() {
519 writeln!(
520 formatter,
521 " simple id={:?} advance={:?}",
522 entry.id(),
523 entry.advance()
524 )?;
525 continue;
526 } else {
527 let detailed_glyph = &self.detailed_glyphs[entry.detailed_glyph_index()];
528 writeln!(
529 formatter,
530 " detailed id={:?} advance={:?} characters={:?}",
531 detailed_glyph.id, detailed_glyph.advance, detailed_glyph.character_count,
532 )?;
533 }
534 }
535 Ok(())
536 }
537}
538
539#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
543pub struct ShapedTextSlice {
544 #[conditional_malloc_size_of]
546 shaped_text: Arc<ShapedText>,
547
548 glyph_range: Range<usize>,
550
551 total_advance: Au,
553
554 character_count: usize,
556
557 total_word_separators: usize,
560
561 is_whitespace: bool,
563
564 ends_with_whitespace: bool,
568}
569
570impl ShapedTextSlice {
571 #[inline]
573 pub fn shaped_text(&self) -> Arc<ShapedText> {
574 self.shaped_text.clone()
575 }
576
577 #[inline]
579 pub fn glyph_count(&self) -> usize {
580 self.glyph_range.len()
581 }
582
583 #[inline]
587 pub fn character_count(&self) -> usize {
588 self.character_count
589 }
590
591 #[inline]
593 pub fn total_advance(&self) -> Au {
594 self.total_advance
595 }
596
597 #[inline]
599 pub fn total_word_separators(&self) -> usize {
600 self.total_word_separators
601 }
602
603 #[inline]
605 pub fn is_whitespace(&self) -> bool {
606 self.is_whitespace
607 }
608
609 #[inline]
611 pub fn ends_with_whitespace(&self) -> bool {
612 self.ends_with_whitespace
613 }
614
615 pub fn glyphs(&self) -> impl DoubleEndedIterator<Item = GlyphInfo<'_>> + use<'_> {
617 self.shaped_text.glyph_slice(self.glyph_range.clone())
618 }
619}
620
621pub struct ShapedTextSlicer {
623 current_glyph_offset: usize,
624 shaped_text: Arc<ShapedText>,
625}
626
627impl ShapedTextSlicer {
628 pub fn new(shaped_text: Arc<ShapedText>) -> Self {
629 let current_glyph_offset = if shaped_text.is_rtl {
630 shaped_text.glyph_count()
631 } else {
632 0
633 };
634
635 Self {
636 current_glyph_offset,
637 shaped_text,
638 }
639 }
640
641 pub fn slice_for_character_count(
646 &mut self,
647 desired_character_count: usize,
648 is_whitespace: bool,
649 ends_with_whitespace: bool,
650 ) -> Arc<ShapedTextSlice> {
651 let mut glyph_count = 0;
652 let mut character_count = 0;
653 let mut total_word_separators = 0;
654 let mut total_advance = Au::zero();
655
656 let iterator = if self.shaped_text.is_rtl {
661 Either::Left(
662 self.shaped_text
663 .glyph_slice(0..self.current_glyph_offset)
664 .rev(),
665 )
666 } else {
667 Either::Right(
668 self.shaped_text
669 .glyph_slice(self.current_glyph_offset..self.shaped_text.glyph_count()),
670 )
671 };
672
673 for glyph in iterator {
674 let glyph_character_count = glyph.character_count();
679 if character_count + glyph_character_count > desired_character_count {
680 break;
681 }
682
683 glyph_count += 1;
684 character_count += glyph_character_count;
685 total_advance += glyph.advance();
686 if glyph.char_is_word_separator() {
687 total_word_separators += 1;
688 }
689 }
690
691 let (new_glyph_offset, glyph_range) = if self.shaped_text.is_rtl {
692 assert!(self.current_glyph_offset >= glyph_count);
693 let new_glyph_offset = self.current_glyph_offset - glyph_count;
694 (
695 new_glyph_offset,
696 new_glyph_offset..self.current_glyph_offset,
697 )
698 } else {
699 let new_glyph_offset = self.current_glyph_offset + glyph_count;
700 (
701 new_glyph_offset,
702 self.current_glyph_offset..new_glyph_offset,
703 )
704 };
705
706 self.current_glyph_offset = new_glyph_offset;
707 Arc::new(ShapedTextSlice {
708 shaped_text: self.shaped_text.clone(),
709 glyph_range,
710 total_advance,
711 character_count,
712 is_whitespace,
713 ends_with_whitespace,
714 total_word_separators,
715 })
716 }
717}