Skip to main content

cranpose_text/
shaped_glyphs.rs

1use std::ops::{Deref, Range};
2
3use crate::glyph_id::GlyphId;
4
5// The top bit of a glyph's id: whether a line break before its cluster
6// changes the shapes on either side of it. No font format numbers glyphs
7// past 24 bits.
8const UNSAFE_TO_BREAK: u32 = 1 << 31;
9
10/// A glyph shaping placed: its id, the text offset of its cluster and how
11/// far it moves the pen. Where it draws from the pen stands apart, in
12/// [`ShapedGlyphs`], since most glyphs draw at the pen.
13#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
14pub struct ShapedGlyph {
15    id: u32,
16    /// The byte offset in the text of the cluster the glyph belongs to.
17    pub cluster: u32,
18    /// How far the glyph moves the pen.
19    pub advance: i32,
20}
21
22/// How far right of the pen and up from the baseline a glyph draws, in
23/// design units.
24#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
25pub struct GlyphOffset {
26    /// How far right of the pen.
27    pub x: i32,
28    /// How far up from the baseline.
29    pub y: i32,
30}
31
32// Whether a line break before a glyph's cluster keeps the shapes on either
33// side of it.
34#[derive(Clone, Copy)]
35pub(crate) enum BreakBefore {
36    Safe,
37    Unsafe,
38}
39
40/// Glyphs in the order shaping placed them, with where each draws from the
41/// pen.
42#[derive(Clone, Debug, Default, PartialEq)]
43pub struct ShapedGlyphs {
44    glyphs: Vec<ShapedGlyph>,
45    // Where the first glyphs draw from the pen, up to the last one that
46    // draws off it; the glyphs past them draw at the pen, as in most text.
47    offsets: Vec<GlyphOffset>,
48}
49
50impl ShapedGlyph {
51    pub(crate) fn new(id: GlyphId, cluster: u32, advance: i32, before: BreakBefore) -> Self {
52        let flag = match before {
53            BreakBefore::Safe => 0,
54            BreakBefore::Unsafe => UNSAFE_TO_BREAK,
55        };
56        Self {
57            id: id.0 | flag,
58            cluster,
59            advance,
60        }
61    }
62
63    // The glyph in the cluster at `cluster`.
64    pub(crate) fn in_cluster(self, cluster: u32) -> Self {
65        Self { cluster, ..self }
66    }
67
68    /// The glyph.
69    pub fn id(&self) -> GlyphId {
70        GlyphId(self.id & !UNSAFE_TO_BREAK)
71    }
72
73    /// Whether a line break before this glyph's cluster changes the shapes
74    /// on either side of it.
75    pub fn unsafe_to_break(&self) -> bool {
76        self.id & UNSAFE_TO_BREAK != 0
77    }
78
79    /// The byte offset in the text of the cluster the glyph belongs to.
80    pub fn text_offset(&self) -> usize {
81        usize::try_from(self.cluster).unwrap_or(usize::MAX)
82    }
83}
84
85impl ShapedGlyphs {
86    /// Where glyph `index` draws from the pen.
87    pub fn offset(&self, index: usize) -> GlyphOffset {
88        self.offsets.get(index).copied().unwrap_or_default()
89    }
90
91    // Where the first glyphs draw from the pen; the glyphs past them draw at
92    // the pen.
93    pub(crate) fn offsets(&self) -> &[GlyphOffset] {
94        &self.offsets
95    }
96
97    pub(crate) fn glyphs_mut(&mut self) -> &mut [ShapedGlyph] {
98        &mut self.glyphs
99    }
100
101    // Adds `glyph`, drawn at `offset` from the pen.
102    pub(crate) fn push(&mut self, glyph: ShapedGlyph, offset: GlyphOffset) {
103        if offset != GlyphOffset::default() {
104            self.offsets
105                .resize(self.glyphs.len(), GlyphOffset::default());
106            self.offsets.push(offset);
107        }
108        self.glyphs.push(glyph);
109    }
110
111    // Adds `glyphs`, the first drawn at `offsets` from the pen and the rest
112    // at the pen.
113    pub(crate) fn extend_from_slice(&mut self, glyphs: &[ShapedGlyph], offsets: &[GlyphOffset]) {
114        self.add_offsets(offsets);
115        self.glyphs.extend_from_slice(glyphs);
116    }
117
118    // Adds `glyphs`, the first drawn at `offsets` from the pen and the rest
119    // at the pen.
120    pub(crate) fn extend(
121        &mut self,
122        glyphs: impl Iterator<Item = ShapedGlyph>,
123        offsets: &[GlyphOffset],
124    ) {
125        self.add_offsets(offsets);
126        self.glyphs.extend(glyphs);
127    }
128
129    // Adds the `glyphs` of a word that starts at `start`, whose clusters
130    // count from the word's start, drawn at `offsets` as `extend_from_slice`
131    // draws them.
132    pub(crate) fn extend_from_word(
133        &mut self,
134        glyphs: &[ShapedGlyph],
135        offsets: &[GlyphOffset],
136        start: u32,
137    ) {
138        self.add_offsets(offsets);
139        self.glyphs.extend(
140            glyphs
141                .iter()
142                .map(|glyph| glyph.in_cluster(glyph.cluster + start)),
143        );
144    }
145
146    // Adds the offsets of glyphs about to be added.
147    fn add_offsets(&mut self, offsets: &[GlyphOffset]) {
148        if !offsets.is_empty() {
149            self.offsets
150                .resize(self.glyphs.len(), GlyphOffset::default());
151            self.offsets.extend_from_slice(offsets);
152        }
153    }
154
155    pub(crate) fn truncate(&mut self, len: usize) {
156        self.glyphs.truncate(len);
157        self.offsets.truncate(len);
158    }
159
160    pub(crate) fn clear(&mut self) {
161        self.glyphs.clear();
162        self.offsets.clear();
163    }
164
165    pub(crate) fn reserve(&mut self, additional: usize) {
166        self.glyphs.reserve(additional);
167    }
168
169    pub(crate) fn capacity(&self) -> usize {
170        self.glyphs.capacity()
171    }
172
173    // Reverses the order of the glyphs of `range`.
174    pub(crate) fn reverse(&mut self, range: Range<usize>) {
175        if self.offsets.len() > range.start {
176            let len = self.offsets.len().max(range.end);
177            self.offsets.resize(len, GlyphOffset::default());
178            self.offsets[range.clone()].reverse();
179        }
180        self.glyphs[range].reverse();
181    }
182}
183
184impl Deref for ShapedGlyphs {
185    type Target = [ShapedGlyph];
186
187    fn deref(&self) -> &[ShapedGlyph] {
188        &self.glyphs
189    }
190}