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 #[inline]
353 pub(crate) fn add_glyph(&mut self, character: char, glyph: &ShapedGlyph) {
354 if !glyph.can_be_simple_glyph() {
355 self.add_detailed_glyph(glyph, Some(character), 1);
356 return;
357 }
358
359 let mut simple_glyph_entry = GlyphEntry::simple(glyph.glyph_id, glyph.advance);
360 if character_is_word_separator(character) {
361 self.total_word_separators += 1;
362 simple_glyph_entry.set_char_is_word_separator();
363 }
364
365 self.character_count += 1;
366 self.total_advance += glyph.advance;
367 self.glyphs.push(simple_glyph_entry)
368 }
369
370 fn add_detailed_glyph(
371 &mut self,
372 shaped_glyph: &ShapedGlyph,
373 character: Option<char>,
374 character_count: usize,
375 ) {
376 let is_word_separator = character.is_some_and(character_is_word_separator);
377 if is_word_separator {
378 self.total_word_separators += 1;
379 }
380
381 self.character_count += character_count;
382 self.total_advance += shaped_glyph.advance;
383 self.detailed_glyphs.push(DetailedGlyphEntry {
384 id: shaped_glyph.glyph_id,
385 advance: shaped_glyph.advance,
386 offset: shaped_glyph.offset,
387 character_count,
388 is_word_separator,
389 });
390 self.glyphs
391 .push(GlyphEntry::complex(self.detailed_glyphs.len() - 1));
392 }
393
394 fn extend_previous_glyph_by_character(&mut self) {
395 let detailed_glyph_index = self.ensure_last_glyph_is_detailed();
396 let detailed_glyph = self
397 .detailed_glyphs
398 .get_mut(detailed_glyph_index)
399 .expect("GlyphEntry should have valid index to detailed glyph");
400 detailed_glyph.character_count += 1;
401 self.character_count += 1;
402 }
403
404 fn add_glyph_for_current_character(
405 &mut self,
406 shaped_glyph: &ShapedGlyph,
407 options: &ShapingOptions,
408 ) {
409 if let Some(letter_spacing) = options.letter_spacing &&
415 letter_spacing != Au::zero()
416 {
417 let last_glyph_index = self.ensure_last_glyph_is_detailed();
418 self.detailed_glyphs[last_glyph_index].advance -= letter_spacing;
419 }
420
421 self.add_detailed_glyph(shaped_glyph, None, 0);
424 }
425
426 fn ensure_last_glyph_is_detailed(&mut self) -> usize {
430 let last_glyph = self
431 .glyphs
432 .last_mut()
433 .expect("Should never call this before any glyphs have been added.");
434 if !last_glyph.is_simple() {
435 return last_glyph.detailed_glyph_index();
436 }
437
438 self.detailed_glyphs.push(DetailedGlyphEntry {
439 id: last_glyph.id(),
440 advance: last_glyph.advance(),
441 offset: Default::default(),
442 character_count: 1,
443 is_word_separator: last_glyph.char_is_word_separator(),
444 });
445
446 let detailed_glyph_index = self.detailed_glyphs.len() - 1;
447 *last_glyph = GlyphEntry::complex(detailed_glyph_index);
448 detailed_glyph_index
449 }
450
451 pub fn glyphs(&self) -> impl DoubleEndedIterator<Item = GlyphInfo<'_>> + use<'_> {
452 self.glyph_slice(0..self.glyphs.len())
453 }
454
455 fn glyph_slice(
456 &self,
457 glyph_range: Range<usize>,
458 ) -> impl DoubleEndedIterator<Item = GlyphInfo<'_>> + use<'_> {
459 self.glyphs[glyph_range].iter().map(|entry| {
460 if entry.is_simple() {
461 GlyphInfo::Simple(entry)
462 } else {
463 GlyphInfo::Detail(&self.detailed_glyphs[entry.detailed_glyph_index()])
464 }
465 })
466 }
467}
468
469impl ShapedGlyph {
470 fn can_be_simple_glyph(&self) -> bool {
471 is_simple_glyph_id(self.glyph_id) &&
472 is_simple_advance(self.advance) &&
473 self.offset
474 .is_none_or(|offset| offset == Default::default())
475 }
476
477 pub(crate) fn adjust_for_character(
480 &mut self,
481 character: char,
482 shaping_options: &ShapingOptions,
483 ) {
484 if let Some(letter_spacing) = shaping_options.letter_spacing_for_character(character) {
485 self.advance += letter_spacing;
486 };
487
488 if let Some(word_spacing) = shaping_options.word_spacing &&
493 (character == ' ' || character == '\u{a0}')
494 {
495 self.advance += word_spacing;
497 }
498 }
499}
500
501fn character_is_word_separator(character: char) -> bool {
502 let is_word_separator = matches!(
506 character,
507 ' ' |
508 '\u{00A0}' | '\u{1361}' | '\u{10100}' | '\u{10101}' | '\u{1039F}' | '\u{1091F}' );
515 is_word_separator
516}
517
518impl fmt::Debug for ShapedText {
519 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
520 writeln!(formatter, "ShapedText:")?;
521 for entry in self.glyphs.iter() {
522 if entry.is_simple() {
523 writeln!(
524 formatter,
525 " simple id={:?} advance={:?}",
526 entry.id(),
527 entry.advance()
528 )?;
529 continue;
530 } else {
531 let detailed_glyph = &self.detailed_glyphs[entry.detailed_glyph_index()];
532 writeln!(
533 formatter,
534 " detailed id={:?} advance={:?} characters={:?}",
535 detailed_glyph.id, detailed_glyph.advance, detailed_glyph.character_count,
536 )?;
537 }
538 }
539 Ok(())
540 }
541}
542
543#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
547pub struct ShapedTextSlice {
548 #[conditional_malloc_size_of]
550 shaped_text: Arc<ShapedText>,
551
552 glyph_range: Range<usize>,
554
555 total_advance: Au,
557
558 character_count: usize,
560
561 total_word_separators: usize,
564
565 is_whitespace: bool,
567
568 ends_with_whitespace: bool,
572}
573
574impl ShapedTextSlice {
575 #[inline]
577 pub fn shaped_text(&self) -> Arc<ShapedText> {
578 self.shaped_text.clone()
579 }
580
581 #[inline]
583 pub fn glyph_count(&self) -> usize {
584 self.glyph_range.len()
585 }
586
587 #[inline]
591 pub fn character_count(&self) -> usize {
592 self.character_count
593 }
594
595 #[inline]
597 pub fn total_advance(&self) -> Au {
598 self.total_advance
599 }
600
601 #[inline]
603 pub fn total_word_separators(&self) -> usize {
604 self.total_word_separators
605 }
606
607 #[inline]
609 pub fn is_whitespace(&self) -> bool {
610 self.is_whitespace
611 }
612
613 #[inline]
615 pub fn ends_with_whitespace(&self) -> bool {
616 self.ends_with_whitespace
617 }
618
619 pub fn glyphs(&self) -> impl DoubleEndedIterator<Item = GlyphInfo<'_>> + use<'_> {
621 self.shaped_text.glyph_slice(self.glyph_range.clone())
622 }
623}
624
625pub struct ShapedTextSlicer {
627 current_glyph_offset: usize,
628 shaped_text: Arc<ShapedText>,
629}
630
631impl ShapedTextSlicer {
632 pub fn new(shaped_text: Arc<ShapedText>) -> Self {
633 let current_glyph_offset = if shaped_text.is_rtl {
634 shaped_text.glyph_count()
635 } else {
636 0
637 };
638
639 Self {
640 current_glyph_offset,
641 shaped_text,
642 }
643 }
644
645 pub fn slice_for_character_count(
650 &mut self,
651 desired_character_count: usize,
652 is_whitespace: bool,
653 ends_with_whitespace: bool,
654 ) -> Arc<ShapedTextSlice> {
655 let mut glyph_count = 0;
656 let mut character_count = 0;
657 let mut total_word_separators = 0;
658 let mut total_advance = Au::zero();
659
660 let iterator = if self.shaped_text.is_rtl {
665 Either::Left(
666 self.shaped_text
667 .glyph_slice(0..self.current_glyph_offset)
668 .rev(),
669 )
670 } else {
671 Either::Right(
672 self.shaped_text
673 .glyph_slice(self.current_glyph_offset..self.shaped_text.glyph_count()),
674 )
675 };
676
677 for glyph in iterator {
678 let glyph_character_count = glyph.character_count();
683 if character_count + glyph_character_count > desired_character_count {
684 break;
685 }
686
687 glyph_count += 1;
688 character_count += glyph_character_count;
689 total_advance += glyph.advance();
690 if glyph.char_is_word_separator() {
691 total_word_separators += 1;
692 }
693 }
694
695 let (new_glyph_offset, glyph_range) = if self.shaped_text.is_rtl {
696 assert!(self.current_glyph_offset >= glyph_count);
697 let new_glyph_offset = self.current_glyph_offset - glyph_count;
698 (
699 new_glyph_offset,
700 new_glyph_offset..self.current_glyph_offset,
701 )
702 } else {
703 let new_glyph_offset = self.current_glyph_offset + glyph_count;
704 (
705 new_glyph_offset,
706 self.current_glyph_offset..new_glyph_offset,
707 )
708 };
709
710 self.current_glyph_offset = new_glyph_offset;
711 Arc::new(ShapedTextSlice {
712 shaped_text: self.shaped_text.clone(),
713 glyph_range,
714 total_advance,
715 character_count,
716 is_whitespace,
717 ends_with_whitespace,
718 total_word_separators,
719 })
720 }
721}