1use std::hash::{Hash, Hasher};
2
3use cosmic_text::{Attrs, Buffer, LayoutGlyph, Metrics, Shaping, SubpixelBin, Wrap};
4
5use crate::{
6 Anchor, Error, Face, Pen, Placed, Placement, RasterKey, Representation, Span, Spot, TextEngine,
7 face_attrs, field_ppem, raster_flags, raster_key,
8};
9
10#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq)]
11pub enum Figures {
12 #[default]
13 Tabular,
14 TabularDigits,
15 Proportional,
16}
17
18#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq)]
19pub enum Ligatures {
20 #[default]
21 Kept,
22 Off,
23}
24
25#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq)]
26pub struct NumberForms {
27 pub figures: Figures,
28 pub ligatures: Ligatures,
29}
30
31#[derive(Clone, Copy, Debug, PartialEq)]
32pub(crate) struct Columns {
33 widest: f32,
34 solo: [f32; 10],
35}
36
37struct NumberGlyph {
38 spot: Spot,
39 advance: f32,
40 coverage: [RasterKey; 4],
41 msdf: RasterKey,
42}
43
44pub(crate) struct NumberFace {
45 pub(crate) stamp: u64,
46 pub(crate) bytes: u64,
47 chars: Vec<char>,
48 glyphs: Vec<Option<NumberGlyph>>,
49 kern: Vec<Option<f32>>,
50 columns: Option<Columns>,
51 line_y: f32,
52 height: f32,
53}
54
55fn pair_sequence(count: usize) -> Vec<usize> {
56 let mut next = vec![0usize; count];
57 let mut stack = vec![0usize];
58 let mut circuit = Vec::with_capacity(count * count + 1);
59 while let Some(&node) = stack.last() {
60 if next[node] < count {
61 stack.push(next[node]);
62 next[node] += 1;
63 } else {
64 circuit.push(node);
65 stack.pop();
66 }
67 }
68 circuit.reverse();
69 circuit
70}
71
72fn face_key(face: &Face, chars: &str, scale: f32, forms: NumberForms) -> u64 {
73 let mut hasher = std::collections::hash_map::DefaultHasher::new();
74 chars.hash(&mut hasher);
75 face.family.hash(&mut hasher);
76 face.size.to_bits().hash(&mut hasher);
77 face.line.to_bits().hash(&mut hasher);
78 face.weight.hash(&mut hasher);
79 face.italic.hash(&mut hasher);
80 face.spacing.to_bits().hash(&mut hasher);
81 scale.to_bits().hash(&mut hasher);
82 forms.hash(&mut hasher);
83 hasher.finish()
84}
85
86fn valid(face: &Face, color: [f32; 4], scale: f32) -> bool {
87 scale.is_finite()
88 && scale > 0.0
89 && face.size.is_finite()
90 && face.size > 0.0
91 && face.line.is_finite()
92 && face.line > 0.0
93 && face.spacing.is_finite()
94 && color.iter().all(|c| c.is_finite())
95}
96
97fn same_glyph(solo: Option<&LayoutGlyph>, glyph: &LayoutGlyph) -> bool {
98 solo.is_some_and(|solo| solo.glyph_id == glyph.glyph_id && solo.font_id == glyph.font_id)
99}
100
101fn single(glyphs: Vec<LayoutGlyph>) -> Option<LayoutGlyph> {
102 <[LayoutGlyph; 1]>::try_from(glyphs)
103 .ok()
104 .map(|[glyph]| glyph)
105}
106
107pub(crate) fn char_lines(chars: &[char]) -> String {
108 chars
109 .iter()
110 .map(|c| c.to_string())
111 .collect::<Vec<_>>()
112 .join("\n")
113}
114
115pub(crate) fn unique_chars(chars: &str) -> Vec<char> {
116 let mut set = Vec::new();
117 for c in chars.chars() {
118 if !set.contains(&c) {
119 set.push(c);
120 }
121 }
122 set
123}
124
125pub(crate) fn bin_keys(key: &RasterKey) -> [RasterKey; 4] {
126 [
127 SubpixelBin::Zero,
128 SubpixelBin::One,
129 SubpixelBin::Two,
130 SubpixelBin::Three,
131 ]
132 .map(|x_bin| RasterKey {
133 x_bin,
134 ..key.clone()
135 })
136}
137
138fn unwrapped(fonts: &mut cosmic_text::FontSystem, face: &Face, scale: f32) -> Buffer {
139 let mut buffer = Buffer::new(fonts, Metrics::new(face.size * scale, face.line * scale));
140 buffer.set_wrap(fonts, Wrap::None);
141 buffer.set_size(fonts, None, None);
142 buffer
143}
144
145fn shape_lines(
146 fonts: &mut cosmic_text::FontSystem,
147 buffer: &mut Buffer,
148 text: &str,
149 attrs: &Attrs,
150) -> Vec<(f32, f32, Vec<LayoutGlyph>)> {
151 buffer.set_text(fonts, text, attrs, Shaping::Advanced, None);
152 buffer.shape_until_scroll(fonts, false);
153 let mut lines = vec![(0.0, 0.0, Vec::new()); text.split('\n').count()];
154 for run in buffer.layout_runs() {
155 if let Some(line) = lines.get_mut(run.line_i) {
156 *line = (
157 run.line_y - run.line_top,
158 run.line_height,
159 run.glyphs.to_vec(),
160 );
161 }
162 }
163 lines
164}
165
166impl TextEngine {
167 pub fn place_number(
168 &mut self,
169 span: &Span,
170 chars: &str,
171 anchor: Anchor,
172 placement: &Placement,
173 ) -> Result<Placed, Error> {
174 self.place_number_with(span, chars, NumberForms::default(), anchor, placement)
175 }
176
177 pub fn place_number_with(
178 &mut self,
179 span: &Span,
180 chars: &str,
181 forms: NumberForms,
182 anchor: Anchor,
183 placement: &Placement,
184 ) -> Result<Placed, Error> {
185 if !valid(&span.face, span.color, placement.scale) {
186 return Err(Error::InvalidStyle);
187 }
188 let mut columns = None;
189 if !span.text.is_empty() && span.text.chars().all(|c| chars.contains(c)) {
190 let key = self.number_face(&span.face, chars, placement.scale, forms)?;
191 if let Some(face) = self.numbers.remove(&key) {
192 let indices = span
193 .text
194 .chars()
195 .filter_map(|c| face.chars.iter().position(|&known| known == c))
196 .collect::<Vec<_>>();
197 let placed = self.place_fast(&face, &indices, span.color, anchor, placement);
198 columns = face.columns;
199 self.numbers.insert(key, face);
200 if let Some(placed) = placed? {
201 self.shared.stats.fast += 1;
202 return Ok(placed);
203 }
204 }
205 } else if forms.figures != Figures::Proportional
206 && span.text.bytes().any(|b| b.is_ascii_digit())
207 {
208 columns = self
209 .number_face(&span.face, chars, placement.scale, forms)
210 .ok()
211 .and_then(|key| self.numbers[&key].columns);
212 }
213 let spans = std::slice::from_ref(span);
214 let key = self.layout_block(
215 spans,
216 None,
217 placement.scale,
218 Anchor::Start,
219 Some(forms),
220 columns,
221 )?;
222 let width = self.blocks[&key].width;
223 let placement = Placement {
224 origin: anchored(placement.origin, width, anchor),
225 ..*placement
226 };
227 self.place_block(key, spans, &placement)
228 }
229
230 pub fn cached_number_faces(&self) -> usize {
231 self.numbers.len()
232 }
233
234 pub fn ligating_pairs(
235 &mut self,
236 face: &Face,
237 chars: &str,
238 forms: NumberForms,
239 scale: f32,
240 ) -> Result<Vec<(char, char)>, Error> {
241 if !valid(face, [0.0; 4], scale) {
242 return Err(Error::InvalidStyle);
243 }
244 let key = self.number_face(face, chars, scale, forms)?;
245 let face = &self.numbers[&key];
246 let count = face.chars.len();
247 let mut pairs = Vec::new();
248 for i in 0..count {
249 for j in 0..count {
250 if face.glyphs[i].is_some()
251 && face.glyphs[j].is_some()
252 && face.kern[i * count + j].is_none()
253 {
254 pairs.push((face.chars[i], face.chars[j]));
255 }
256 }
257 }
258 Ok(pairs)
259 }
260
261 fn place_fast(
262 &mut self,
263 face: &NumberFace,
264 indices: &[usize],
265 color: [f32; 4],
266 anchor: Anchor,
267 placement: &Placement,
268 ) -> Result<Option<Placed>, Error> {
269 let count = face.chars.len();
270 if indices.iter().any(|&i| face.glyphs[i].is_none())
271 || indices
272 .windows(2)
273 .any(|pair| face.kern[pair[0] * count + pair[1]].is_none())
274 {
275 return Ok(None);
276 }
277 let mut pens = Vec::with_capacity(indices.len());
278 let mut x = 0.0f32;
279 for (at, &i) in indices.iter().enumerate() {
280 let glyph = face.glyphs[i].as_ref().unwrap();
281 pens.push(x + glyph.spot.x);
282 x += glyph.advance;
283 if let Some(&next) = indices.get(at + 1) {
284 x += if face.columns.is_some()
285 && (face.chars[i].is_ascii_digit() || face.chars[next].is_ascii_digit())
286 {
287 0.0
288 } else {
289 face.kern[i * count + next].unwrap_or_default()
290 };
291 }
292 }
293 let scale = placement.scale;
294 let placement = Placement {
295 origin: anchored(placement.origin, x / scale, anchor),
296 ..*placement
297 };
298 let mut quads = Vec::with_capacity(indices.len());
299 for (&i, pen_x) in indices.iter().zip(pens) {
300 let glyph = face.glyphs[i].as_ref().unwrap();
301 let spot = Spot {
302 x: pen_x,
303 color,
304 ..glyph.spot.clone()
305 };
306 let pen = Pen::new(&spot, &placement);
307 let key = match placement.representation {
308 Representation::Coverage => &glyph.coverage[pen.bin as usize],
309 Representation::Msdf => &glyph.msdf,
310 };
311 self.place_glyph(&spot, key, pen, &placement, &mut quads)?;
312 }
313 Ok(Some(Placed {
314 quads,
315 width: x / scale,
316 height: face.height / scale,
317 baseline: face.line_y / scale,
318 }))
319 }
320
321 pub(crate) fn column_shifts(
322 &mut self,
323 buffer: &Buffer,
324 columns: Columns,
325 face: &Face,
326 scale: f32,
327 forms: NumberForms,
328 ) -> (Vec<f32>, f32) {
329 let mut lines = Vec::new();
330 let mut wanted: Vec<char> = Vec::new();
331 for run in buffer.layout_runs() {
332 let glyphs = run
333 .glyphs
334 .iter()
335 .map(|glyph| {
336 let mut chars = run.text[glyph.start..glyph.end].chars();
337 let one = chars.next().filter(|_| chars.next().is_none());
338 (one, glyph.w, glyph.glyph_id, glyph.font_id)
339 })
340 .collect::<Vec<_>>();
341 for pair in glyphs.windows(2) {
342 if let (Some(c), Some(next)) = (pair[0].0, pair[1].0)
343 && !c.is_ascii_digit()
344 && next.is_ascii_digit()
345 && !wanted.contains(&c)
346 {
347 wanted.push(c);
348 }
349 }
350 lines.push((run.line_w, glyphs));
351 }
352 let mut solo = Vec::new();
353 if !wanted.is_empty() {
354 let attrs = face_attrs(face, scale, 0, Some(forms));
355 let mut alone = unwrapped(&mut self.fonts, face, scale);
356 let text = char_lines(&wanted);
357 solo = shape_lines(&mut self.fonts, &mut alone, &text, &attrs)
358 .into_iter()
359 .map(|(_, _, glyphs)| single(glyphs))
360 .collect();
361 }
362 let digit = |c: Option<char>| c.and_then(|c| c.to_digit(10)).map(|d| d as usize);
363 let mut shifts = Vec::new();
364 let mut width = 0.0f32;
365 for (line_w, glyphs) in lines {
366 let mut shift = 0.0f32;
367 for (at, &(c, w, glyph_id, font_id)) in glyphs.iter().enumerate() {
368 let next = glyphs.get(at + 1).and_then(|next| digit(next.0));
369 let target = match digit(c) {
370 Some(d) => {
371 shifts.push(shift + (columns.widest - columns.solo[d]) * 0.5);
372 columns.widest
373 }
374 None => {
375 shifts.push(shift);
376 c.filter(|_| next.is_some())
377 .and_then(|c| wanted.iter().position(|&known| known == c))
378 .and_then(|at| solo.get(at).and_then(Option::as_ref))
379 .filter(|alone| alone.glyph_id == glyph_id && alone.font_id == font_id)
380 .map_or(w, |alone| alone.w)
381 }
382 };
383 shift += target - w;
384 }
385 width = width.max(line_w + shift);
386 }
387 (shifts, width)
388 }
389
390 pub(crate) fn number_glyph_keys(
391 &mut self,
392 face: &Face,
393 chars: &str,
394 scale: f32,
395 forms: NumberForms,
396 representation: Representation,
397 ) -> Result<Vec<(Spot, Vec<RasterKey>)>, Error> {
398 if !valid(face, [0.0; 4], scale) {
399 return Err(Error::InvalidStyle);
400 }
401 let key = self.number_face(face, chars, scale, forms)?;
402 let face = &self.numbers[&key];
403 Ok(face
404 .glyphs
405 .iter()
406 .flatten()
407 .map(|glyph| {
408 let keys = match representation {
409 Representation::Coverage => glyph.coverage.to_vec(),
410 Representation::Msdf => vec![glyph.msdf.clone()],
411 };
412 (glyph.spot.clone(), keys)
413 })
414 .collect())
415 }
416
417 pub(crate) fn number_face(
418 &mut self,
419 face: &Face,
420 chars: &str,
421 scale: f32,
422 forms: NumberForms,
423 ) -> Result<u64, Error> {
424 let key = face_key(face, chars, scale, forms);
425 let stamp = self.stamp();
426 if let Some(found) = self.numbers.get_mut(&key) {
427 found.stamp = stamp;
428 return Ok(key);
429 }
430 self.shared.stats.shaped += 1;
431 let set = unique_chars(chars);
432 let count = set.len();
433 let mut solo_chars = set.clone();
434 for digit in '0'..='9' {
435 if !solo_chars.contains(&digit) {
436 solo_chars.push(digit);
437 }
438 }
439 let attrs = face_attrs(face, scale, 0, Some(forms));
440 let mut buffer = unwrapped(&mut self.fonts, face, scale);
441 let solo = char_lines(&solo_chars);
442 let lines = shape_lines(&mut self.fonts, &mut buffer, &solo, &attrs);
443 let (line_y, height) = lines
444 .iter()
445 .find(|line| line.1 > 0.0)
446 .map(|line| (line.0, line.1))
447 .ok_or(Error::UnsupportedGlyph)?;
448 let found = lines
449 .into_iter()
450 .map(|(_, _, glyphs)| single(glyphs))
451 .collect::<Vec<_>>();
452 let digits = ('0'..='9')
453 .map(|digit| {
454 solo_chars
455 .iter()
456 .position(|&c| c == digit)
457 .and_then(|at| found[at].as_ref())
458 .map(|glyph| glyph.w)
459 })
460 .collect::<Option<Vec<_>>>();
461 let columns = digits.and_then(|digits| {
462 let widest = digits.iter().copied().fold(0.0f32, f32::max);
463 (forms.figures != Figures::Proportional
464 && digits.iter().any(|&w| (w - widest).abs() > 1e-3))
465 .then(|| Columns {
466 widest,
467 solo: std::array::from_fn(|d| digits[d]),
468 })
469 });
470 let found = &found[..count];
471 let kern = self.pair_kerns(&mut buffer, &attrs, &set, found);
472 let mut glyphs = Vec::with_capacity(count);
473 for (i, glyph) in found.iter().enumerate() {
474 let Some(glyph) = glyph else {
475 glyphs.push(None);
476 continue;
477 };
478 let font = self
479 .fonts
480 .get_font(glyph.font_id, glyph.font_weight)
481 .ok_or(Error::UnsupportedGlyph)?;
482 let flags = raster_flags(
483 glyph.cache_key_flags,
484 face.italic,
485 self.fonts.db().face(glyph.font_id).map(|face| face.style),
486 );
487 let template = |ppem: f32, representation: Representation| RasterKey {
488 representation,
489 ..raster_key(
490 glyph.font_id,
491 glyph.glyph_id,
492 ppem,
493 glyph.font_weight,
494 glyph.font_size / scale,
495 flags,
496 font.as_swash(),
497 )
498 };
499 let coverage = template(glyph.font_size, Representation::Coverage);
500 let bins = bin_keys(&coverage);
501 let msdf = template(field_ppem(glyph.font_size), Representation::Msdf);
502 let column = columns.filter(|_| set[i].is_ascii_digit());
503 let pad = column.map_or(0.0, |columns| (columns.widest - glyph.w) * 0.5);
504 glyphs.push(Some(NumberGlyph {
505 spot: Spot {
506 font_id: glyph.font_id,
507 font_weight: glyph.font_weight,
508 glyph_id: glyph.glyph_id,
509 flags,
510 font_size: glyph.font_size,
511 x: glyph.x_offset * glyph.font_size + pad,
512 y: glyph.y - glyph.y_offset * glyph.font_size,
513 line_y,
514 line_index: 0,
515 color: [0.0; 4],
516 },
517 advance: column.map_or(glyph.w, |columns| columns.widest),
518 coverage: bins,
519 msdf,
520 }));
521 }
522 let bytes = (std::mem::size_of::<NumberFace>()
523 + count * std::mem::size_of::<char>()
524 + kern.len() * std::mem::size_of::<Option<f32>>()
525 + glyphs.len() * std::mem::size_of::<Option<NumberGlyph>>()
526 + glyphs
527 .iter()
528 .flatten()
529 .map(|glyph| {
530 glyph
531 .coverage
532 .iter()
533 .chain([&glyph.msdf])
534 .map(|key| key.font_id.capacity())
535 .sum::<usize>()
536 })
537 .sum::<usize>()) as u64;
538 self.numbers.insert(
539 key,
540 NumberFace {
541 stamp,
542 bytes,
543 chars: set,
544 glyphs,
545 kern,
546 columns,
547 line_y,
548 height,
549 },
550 );
551 Ok(key)
552 }
553
554 fn pair_kerns(
555 &mut self,
556 buffer: &mut Buffer,
557 attrs: &Attrs,
558 set: &[char],
559 solo: &[Option<LayoutGlyph>],
560 ) -> Vec<Option<f32>> {
561 let count = set.len();
562 let mut kern = vec![None; count * count];
563 if count == 0 {
564 return kern;
565 }
566 let order = pair_sequence(count);
567 let mut starts = Vec::with_capacity(order.len());
568 let mut sequence = String::new();
569 for &i in &order {
570 starts.push(sequence.len());
571 sequence.push(set[i]);
572 }
573 let laid = shape_lines(&mut self.fonts, buffer, &sequence, attrs);
574 let mut cover = vec![0u32; order.len()];
575 let mut x = vec![None; order.len()];
576 if let [(_, _, glyphs)] = laid.as_slice() {
577 for glyph in glyphs {
578 let Ok(first) = starts.binary_search(&glyph.start) else {
579 continue;
580 };
581 let last = starts.partition_point(|&start| start < glyph.end);
582 for slot in &mut cover[first..last.max(first + 1)] {
583 *slot += 1;
584 }
585 if last == first + 1 && same_glyph(solo[order[first]].as_ref(), glyph) {
586 x[first] = Some(glyph.x);
587 }
588 }
589 }
590 let clean = |at: usize| if cover[at] == 1 { x[at] } else { None };
591 let advance = |i: usize| solo[i].as_ref().map_or(0.0, |glyph| glyph.w);
592 let mut unresolved = Vec::new();
593 for (at, pair) in order.windows(2).enumerate() {
594 match (clean(at), clean(at + 1)) {
595 (Some(a), Some(b)) => {
596 kern[pair[0] * count + pair[1]] = Some(b - a - advance(pair[0]))
597 }
598 _ => unresolved.push((pair[0], pair[1])),
599 }
600 }
601 if unresolved.is_empty() {
602 return kern;
603 }
604 let text = unresolved
605 .iter()
606 .map(|&(i, j)| format!("{}{}", set[i], set[j]))
607 .collect::<Vec<_>>()
608 .join("\n");
609 let lines = shape_lines(&mut self.fonts, buffer, &text, attrs);
610 for (&(i, j), (_, _, glyphs)) in unresolved.iter().zip(lines) {
611 if let [a, b] = glyphs.as_slice()
612 && a.start == 0
613 && b.start == set[i].len_utf8()
614 && same_glyph(solo[i].as_ref(), a)
615 && same_glyph(solo[j].as_ref(), b)
616 {
617 kern[i * count + j] = Some(b.x - a.x - advance(i));
618 }
619 }
620 kern
621 }
622}
623
624pub(crate) fn anchored(origin: [f32; 2], width: f32, anchor: Anchor) -> [f32; 2] {
625 match anchor {
626 Anchor::Start => origin,
627 Anchor::Center => [origin[0] - width * 0.5, origin[1]],
628 Anchor::End => [origin[0] - width, origin[1]],
629 }
630}
631
632#[cfg(test)]
633mod tests {
634 use super::*;
635
636 #[test]
637 fn the_pair_sequence_holds_every_ordered_pair_once() {
638 let count = 17;
639 let order = pair_sequence(count);
640 assert_eq!(order.len(), count * count + 1);
641 let mut seen = vec![0; count * count];
642 for pair in order.windows(2) {
643 seen[pair[0] * count + pair[1]] += 1;
644 }
645 assert!(seen.iter().all(|&count| count == 1));
646 }
647}