1use crate::conv::{DPU, to_u32, to_usize};
21use crate::display::RunSpecial;
22use crate::fonts::{self, FaceId};
23use crate::{Range, Vec2};
24use fontique::Script;
25use tinyvec::TinyVec;
26use unicode_bidi::Level;
27
28#[repr(transparent)]
30#[derive(Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Default, Debug)]
31pub struct GlyphId(pub u16);
32
33#[derive(Clone, Copy, Debug)]
35pub struct Glyph {
36 pub index: u32,
38 pub id: GlyphId,
40 pub position: Vec2,
42}
43
44#[derive(Clone, Copy, Debug, Default)]
45pub(crate) struct GlyphBreak {
46 pub index: u32,
48 pub gi: u32,
50 pub no_space_end: f32,
52}
53impl GlyphBreak {
54 pub(crate) fn new(index: u32) -> Self {
58 GlyphBreak {
59 index,
60 gi: u32::MAX,
61 no_space_end: f32::NAN,
62 }
63 }
64}
65
66#[derive(Clone, Copy, Debug, Default, PartialEq)]
67pub(crate) struct PartMetrics {
68 pub offset: f32,
70 pub len_no_space: f32,
72 pub len: f32,
74}
75
76#[derive(Clone, Debug)]
88pub(crate) struct GlyphRun {
89 pub range: Range,
91 pub dpem: f32,
93 pub dpu: DPU,
94
95 pub face_id: FaceId,
97 pub special: RunSpecial,
99 pub level: Level,
101 pub script: Script,
103
104 pub glyphs: Vec<Glyph>,
106 pub breaks: TinyVec<[GlyphBreak; 4]>,
111
112 pub no_space_end: f32,
116 pub caret: f32,
118}
119
120impl GlyphRun {
121 pub fn num_parts(&self) -> usize {
125 self.breaks.len() + 1
126 }
127
128 pub fn part_lengths(&self, range: std::ops::Range<usize>) -> PartMetrics {
133 assert!(range.start <= range.end);
135
136 let mut part = PartMetrics::default();
137 if self.level.is_ltr() {
138 if range.end > 0 {
139 part.len_no_space = self.no_space_end;
140 part.len = self.caret;
141 if range.end <= self.breaks.len() {
142 let b = self.breaks[range.end - 1];
143 part.len_no_space = b.no_space_end;
144 if to_usize(b.gi) < self.glyphs.len() {
145 part.len = self.glyphs[to_usize(b.gi)].position.0
146 }
147 }
148 }
149
150 if range.start > 0 {
151 let glyph = to_usize(self.breaks[range.start - 1].gi);
152 part.offset = self.glyphs[glyph].position.0;
153 part.len_no_space -= part.offset;
154 part.len -= part.offset;
155 }
156 } else {
157 if range.start <= self.breaks.len() {
158 part.len = self.caret;
159 if range.start > 0 {
160 let b = self.breaks.len() - range.start;
161 let gi = to_usize(self.breaks[b].gi);
162 if gi < self.glyphs.len() {
163 part.len = self.glyphs[gi].position.0;
164 }
165 }
166 part.len_no_space = part.len;
167 }
168 if range.end <= self.breaks.len() {
169 part.offset = self.caret;
170 if range.end == 0 {
171 part.len_no_space = 0.0;
172 } else {
173 let b = self.breaks.len() - range.end;
174 let b = self.breaks[b];
175 part.len_no_space -= b.no_space_end;
176 if to_usize(b.gi) < self.glyphs.len() {
177 part.offset = self.glyphs[to_usize(b.gi)].position.0;
178 }
179 }
180 part.len -= part.offset;
181 }
182 }
183
184 part
185 }
186
187 pub fn to_glyph_range(&self, range: std::ops::Range<usize>) -> Range {
189 let mut start = range.start;
190 let mut end = range.end;
191
192 let rtl = self.level.is_rtl();
193 if rtl {
194 let num_parts = self.num_parts();
195 start = num_parts - start;
196 end = num_parts - end;
197 }
198
199 let map = |part: usize| {
200 if part == 0 {
201 0
202 } else if part <= self.breaks.len() {
203 to_usize(self.breaks[part - 1].gi)
204 } else {
205 debug_assert_eq!(part, self.breaks.len() + 1);
206 self.glyphs.len()
207 }
208 };
209
210 let mut start = map(start);
211 let mut end = map(end);
212
213 if rtl {
214 std::mem::swap(&mut start, &mut end);
215 }
216
217 Range::from(start..end)
218 }
219}
220
221#[derive(Clone, Copy, Debug)]
222pub(crate) struct Input<'a> {
223 pub text: &'a str,
225 pub dpem: f32,
226 pub level: Level,
227 pub script: Script,
228}
229
230pub(crate) fn shape(
236 input: Input,
237 range: Range, face_id: FaceId,
239 mut breaks: TinyVec<[GlyphBreak; 4]>,
241 special: RunSpecial,
242) -> GlyphRun {
243 if input.level.is_rtl() {
254 breaks.reverse();
255 }
256
257 let mut glyphs = vec![];
258 let mut no_space_end = 0.0;
259 let mut caret = 0.0;
260
261 let face = fonts::library().get_face(face_id);
262 let dpu = face.dpu(input.dpem);
263 let sf = face.scale_by_dpu(dpu);
264
265 if input.dpem >= 0.0 {
266 #[cfg(feature = "rustybuzz")]
267 let r = shape_rustybuzz(input, range, face_id, &mut breaks);
268
269 #[cfg(not(feature = "rustybuzz"))]
270 let r = shape_simple(sf, input, range, &mut breaks);
271
272 glyphs = r.0;
273 no_space_end = r.1;
274 caret = r.2;
275 }
276
277 if input.level.is_rtl() {
278 let mut break_i = breaks.len().wrapping_sub(1);
280 let mut start_no_space = caret;
281 let mut last_id = None;
282 let side_bearing = |id: Option<GlyphId>| id.map(|id| sf.h_side_bearing(id)).unwrap_or(0.0);
283 for (gi, glyph) in glyphs.iter().enumerate().rev() {
284 if let Some(b) = breaks.get_mut(break_i)
285 && to_usize(b.gi) == gi
286 {
287 assert!(gi < glyphs.len());
288 b.gi = to_u32(gi) + 1;
289 b.no_space_end = start_no_space - side_bearing(last_id);
290 break_i = break_i.wrapping_sub(1);
291 }
292 if !input.text[to_usize(glyph.index)..]
293 .chars()
294 .next()
295 .map(|c| c.is_whitespace())
296 .unwrap_or(true)
297 {
298 last_id = Some(glyph.id);
299 start_no_space = glyph.position.0;
300 }
301 }
302 no_space_end = start_no_space - side_bearing(last_id);
303 }
304
305 GlyphRun {
306 range,
307 dpem: input.dpem,
308 dpu,
309 face_id,
310 special,
311 level: input.level,
312 script: input.script,
313
314 glyphs,
315 breaks,
316 no_space_end,
317 caret,
318 }
319}
320
321#[cfg(feature = "rustybuzz")]
323fn shape_rustybuzz(
324 input: Input<'_>,
325 range: Range,
326 face_id: FaceId,
327 breaks: &mut [GlyphBreak],
328) -> (Vec<Glyph>, f32, f32) {
329 let Input {
330 text,
331 dpem,
332 level,
333 script,
334 } = input;
335
336 let fonts = fonts::library();
337 let store = fonts.get_face_store(face_id);
338 let dpu = store.face_ref().dpu(dpem);
339 let face = store.rustybuzz();
340
341 let slice = &text[range];
345 let idx_offset = range.start;
346 let rtl = level.is_rtl();
347
348 let mut buffer = rustybuzz::UnicodeBuffer::new();
350 buffer.set_direction(match rtl {
351 false => rustybuzz::Direction::LeftToRight,
352 true => rustybuzz::Direction::RightToLeft,
353 });
354 buffer.push_str(slice);
355 let tag = ttf_parser::Tag(u32::from_be_bytes(script.0));
356 if let Some(script) = rustybuzz::Script::from_iso15924_tag(tag) {
357 buffer.set_script(script);
358 }
359 let features = [];
360
361 let output = rustybuzz::shape(face, &features, buffer);
362
363 let mut caret = 0.0;
364 let mut no_space_end = caret;
365 let mut break_i = 0;
366
367 let mut glyphs = Vec::with_capacity(output.len());
368
369 for (info, pos) in output
370 .glyph_infos()
371 .iter()
372 .zip(output.glyph_positions().iter())
373 {
374 let index = idx_offset + info.cluster;
375 assert!(info.glyph_id <= u16::MAX as u32, "failed to map glyph id");
376 let id = GlyphId(info.glyph_id as u16);
377
378 if breaks
379 .get(break_i)
380 .map(|b| b.index == index)
381 .unwrap_or(false)
382 {
383 breaks[break_i].gi = to_u32(glyphs.len());
384 breaks[break_i].no_space_end = no_space_end;
385 break_i += 1;
386 }
387
388 let position = Vec2(
389 caret + dpu.i32_to_px(pos.x_offset),
390 dpu.i32_to_px(pos.y_offset),
391 );
392 glyphs.push(Glyph {
393 index,
394 id,
395 position,
396 });
397
398 debug_assert_eq!(pos.y_advance, 0);
401 caret += dpu.i32_to_px(pos.x_advance);
402 if text[to_usize(index)..]
403 .chars()
404 .next()
405 .map(|c| !c.is_whitespace())
406 .unwrap()
407 {
408 no_space_end = caret;
409 }
410 }
411
412 (glyphs, no_space_end, caret)
413}
414
415#[cfg(not(feature = "rustybuzz"))]
417fn shape_simple(
418 sf: crate::fonts::ScaledFaceRef,
419 input: Input<'_>,
420 range: Range,
421 breaks: &mut [GlyphBreak],
422) -> (Vec<Glyph>, f32, f32) {
423 let Input { text, level, .. } = input;
424
425 use unicode_bidi_mirroring::get_mirrored;
426
427 let slice = &text[range];
428 let idx_offset = range.start;
429 let rtl = level.is_rtl();
430
431 let mut caret = 0.0;
432 let mut no_space_end = caret;
433 let mut prev_glyph_id: Option<GlyphId> = None;
434 let mut break_i = 0;
435
436 let mut glyphs = Vec::with_capacity(slice.len());
438 let mut iter = slice.char_indices();
439 let mut next_char_index = || match rtl {
440 false => iter.next(),
441 true => iter.next_back(),
442 };
443 while let Some((index, mut c)) = next_char_index() {
444 let index = idx_offset + to_u32(index);
445 if rtl && let Some(m) = get_mirrored(c) {
446 c = m;
447 }
448 let id = sf.face().glyph_index(c);
449
450 if breaks
451 .get(break_i)
452 .map(|b| b.index == index)
453 .unwrap_or(false)
454 {
455 breaks[break_i].gi = to_u32(glyphs.len());
456 breaks[break_i].no_space_end = no_space_end;
457 break_i += 1;
458 no_space_end = caret;
459 }
460
461 if let Some(prev) = prev_glyph_id
462 && let Some(kern) = sf.face().0.tables().kern
463 && let Some(adv) = kern
464 .subtables
465 .into_iter()
466 .filter(|st| st.horizontal && !st.variable)
467 .find_map(|st| st.glyphs_kerning(prev.into(), id.into()))
468 {
469 caret += sf.dpu().i16_to_px(adv);
470 }
471 prev_glyph_id = Some(id);
472
473 let position = Vec2(caret, 0.0);
474 let glyph = Glyph {
475 index,
476 id,
477 position,
478 };
479 glyphs.push(glyph);
480
481 caret += sf.h_advance(id);
482 if !c.is_whitespace() {
483 no_space_end = caret;
484 }
485 }
486
487 glyphs.shrink_to_fit();
488
489 (glyphs, no_space_end, caret)
490}