1use skrifa::instance::{LocationRef, Size};
2use skrifa::outline::{DrawSettings, OutlinePen};
3use skrifa::MetadataProvider;
4use zeno::{Command, Format, Mask, Point};
5
6use crate::{Font, GlyphId};
7
8#[derive(Debug, Clone, PartialEq, Eq, Default)]
10pub struct GlyphBitmap {
11 pub width: u32,
13 pub height: u32,
15 pub left: i32,
17 pub top: i32,
19 pub coverage: Vec<u8>,
21}
22
23pub fn rasterize(font: &Font, glyph: GlyphId, px: f32, x_offset: f32) -> GlyphBitmap {
29 let Some(font_ref) = font.font_ref() else {
30 return GlyphBitmap::default();
31 };
32 let outlines = font_ref.outline_glyphs();
33 let Some(outline) = outlines.get(skrifa::GlyphId::new(glyph.0)) else {
34 return GlyphBitmap::default();
35 };
36
37 let mut pen = PathPen {
38 commands: Vec::new(),
39 dx: x_offset,
40 };
41 let settings = DrawSettings::unhinted(Size::new(px), LocationRef::default());
42 if outline.draw(settings, &mut pen).is_err() || pen.commands.is_empty() {
43 return GlyphBitmap::default();
44 }
45
46 let (coverage, placement) = Mask::new(&pen.commands[..]).format(Format::Alpha).render();
47 if placement.width == 0 || placement.height == 0 {
48 return GlyphBitmap::default();
49 }
50 GlyphBitmap {
51 width: placement.width,
52 height: placement.height,
53 left: placement.left,
54 top: placement.top,
55 coverage,
56 }
57}
58
59struct PathPen {
62 commands: Vec<Command>,
63 dx: f32,
64}
65
66impl PathPen {
67 fn point(&self, x: f32, y: f32) -> Point {
68 Point::new(x + self.dx, -y)
69 }
70}
71
72impl OutlinePen for PathPen {
73 fn move_to(&mut self, x: f32, y: f32) {
74 let p = self.point(x, y);
75 self.commands.push(Command::MoveTo(p));
76 }
77
78 fn line_to(&mut self, x: f32, y: f32) {
79 let p = self.point(x, y);
80 self.commands.push(Command::LineTo(p));
81 }
82
83 fn quad_to(&mut self, cx0: f32, cy0: f32, x: f32, y: f32) {
84 let (c, p) = (self.point(cx0, cy0), self.point(x, y));
85 self.commands.push(Command::QuadTo(c, p));
86 }
87
88 fn curve_to(&mut self, cx0: f32, cy0: f32, cx1: f32, cy1: f32, x: f32, y: f32) {
89 let (c0, c1, p) = (self.point(cx0, cy0), self.point(cx1, cy1), self.point(x, y));
90 self.commands.push(Command::CurveTo(c0, c1, p));
91 }
92
93 fn close(&mut self) {
94 self.commands.push(Command::Close);
95 }
96}