floem_renderer/
swash.rs

1use cosmic_text::{CacheKey, CacheKeyFlags, SwashImage};
2use swash::{
3    scale::{Render, ScaleContext, Source, StrikeWith},
4    zeno::{Angle, Format, Transform, Vector},
5};
6
7use crate::text::FONT_SYSTEM;
8
9const IS_MACOS: bool = cfg!(target_os = "macos");
10
11pub struct SwashScaler {
12    context: ScaleContext,
13    font_embolden: f32,
14}
15
16impl Default for SwashScaler {
17    fn default() -> Self {
18        Self {
19            context: ScaleContext::new(),
20            font_embolden: 0.,
21        }
22    }
23}
24
25impl SwashScaler {
26    pub fn new(font_embolden: f32) -> Self {
27        Self {
28            context: ScaleContext::new(),
29            font_embolden,
30        }
31    }
32
33    pub fn get_image(&mut self, cache_key: CacheKey) -> Option<SwashImage> {
34        let font = match FONT_SYSTEM.lock().get_font(cache_key.font_id) {
35            Some(some) => some,
36            None => {
37                return None;
38            }
39        };
40
41        // Build the scaler
42        let mut scaler = self
43            .context
44            .builder(font.as_swash())
45            .size(f32::from_bits(cache_key.font_size_bits))
46            .hint(!IS_MACOS)
47            .build();
48
49        // Compute the fractional offset-- you'll likely want to quantize this
50        // in a real renderer
51        let offset = Vector::new(cache_key.x_bin.as_float(), cache_key.y_bin.as_float());
52
53        // Select our source order
54        Render::new(&[
55            // Color outline with the first palette
56            Source::ColorOutline(0),
57            // Color bitmap with best fit selection mode
58            Source::ColorBitmap(StrikeWith::BestFit),
59            // Standard scalable outline
60            Source::Outline,
61        ])
62        // Select a subpixel format
63        .format(Format::Alpha)
64        // Apply the fractional offset
65        .offset(offset)
66        .embolden(self.font_embolden)
67        .transform(if cache_key.flags.contains(CacheKeyFlags::FAKE_ITALIC) {
68            Some(Transform::skew(
69                Angle::from_degrees(14.0),
70                Angle::from_degrees(0.0),
71            ))
72        } else {
73            None
74        })
75        // Render the image
76        .render(&mut scaler, cache_key.glyph_id)
77    }
78}