use crate::og_card::canvas::{Canvas, Face, Point, Rgb};
const BACKGROUND: Rgb = [0x1b, 0x15, 0x19];
const TITLE: Rgb = [0xf1, 0xe4, 0xea];
const MUTED: Rgb = [0xa8, 0x91, 0x9d];
const ACCENT: Rgb = [0xf2, 0x8b, 0xb5];
const YARN: Rgb = [0xe2, 0x70, 0x9d];
const YARN_THREAD: Rgb = [0x7a, 0x20, 0x49];
const TEXT_LEFT: f32 = 550.0;
const TEXT_RIGHT: f32 = 1140.0;
const TITLE_BASELINE: f32 = 254.0;
const SUBTITLE_BASELINE: f32 = 316.0;
const DESCRIPTION_BASELINE: f32 = 396.0;
const DESCRIPTION_LINE_HEIGHT: f32 = 38.0;
/// favicon.svg's yarn ball, centred vertically with the text block
const YARN_ORIGIN: (f32, f32) = (160.0, 168.0);
const YARN_SCALE: f32 = 10.0;
const YARN_CIRCLE: ((f32, f32), f32) = ((15.0, 14.5), 13.0);
type Cubic = [Point; 4];
const fn line(from: Point, to: Point) -> Cubic {
[from, from, to, to]
}
const THREADS: [Cubic; 13] = [
[(4.6, 12.0), (4.4, 9.6), (5.0, 7.6), (6.1, 6.4)],
[(8.1, 11.6), (7.6, 8.1), (8.4, 5.1), (10.0, 3.6)],
[(11.6, 11.1), (11.1, 7.6), (11.7, 4.6), (13.1, 2.7)],
[(15.1, 10.5), (14.8, 7.6), (15.3, 5.1), (16.6, 3.1)],
[(18.6, 9.6), (18.3, 7.6), (18.7, 5.6), (19.6, 4.3)],
[(21.9, 8.1), (21.7, 6.9), (21.9, 5.9), (22.5, 5.3)],
[(3.1, 13.7), (9.0, 14.7), (17.0, 13.5), (24.6, 8.4)],
[(3.4, 17.3), (10.0, 18.3), (19.0, 16.3), (26.4, 10.9)],
[(6.1, 20.6), (12.0, 21.4), (20.0, 19.6), (26.6, 14.7)],
line((9.0, 23.6), (10.8, 24.9)),
line((12.8, 23.3), (15.0, 25.3)),
line((17.0, 22.1), (18.8, 23.9)),
line((21.2, 20.7), (22.5, 21.6)),
];
const THREAD_WIDTH: f32 = 1.6;
const TAIL: [Cubic; 2] = [
[(22.5, 24.5), (24.0, 27.3), (26.7, 28.5), (28.9, 27.3)],
[(28.9, 27.3), (30.4, 26.5), (30.5, 24.7), (29.3, 23.9)],
];
const TAIL_WIDTH: f32 = 2.6;
const CURVE_SEGMENTS: usize = 32;
fn stroke(c: &mut Canvas, curves: &[Cubic], width: f32, color: Rgb) {
let points: Vec<Point> = curves.iter().flat_map(flatten).collect();
let half = width * YARN_SCALE / 2.0;
let bounds = points.iter().fold(
((f32::MAX, f32::MAX), (f32::MIN, f32::MIN)),
|((x0, y0), (x1, y1)), &(x, y)| {
(
(x0.min(x - half), y0.min(y - half)),
(x1.max(x + half), y1.max(y + half)),
)
},
);
c.fill(bounds, color, |at| {
points
.windows(2)
.map(|pair| segment_distance(at, pair[0], pair[1]))
.fold(f32::MAX, f32::min)
- half
});
}
fn yarn(c: &mut Canvas) {
let ((cx, cy), r) = YARN_CIRCLE;
let (centre, radius) = (place((cx, cy)), r * YARN_SCALE);
c.fill(
(
(centre.0 - radius, centre.1 - radius),
(centre.0 + radius, centre.1 + radius),
),
YARN,
|(x, y)| (x - centre.0).hypot(y - centre.1) - radius,
);
for thread in &THREADS {
stroke(c, std::slice::from_ref(thread), THREAD_WIDTH, YARN_THREAD);
}
stroke(c, &TAIL, TAIL_WIDTH, YARN);
}
/// `*text*` spans take the accent colour. a line wider than the card shrinks to fit
fn text(c: &mut Canvas, line: &str, baseline: f32, size: f32, color: Rgb) {
let fallback = |ch: char| match Face::Wide.has(ch) {
true => None,
false => fallback_glyph(ch),
};
let advance = |ch: char, s: f32| -> f32 {
match fallback(ch) {
Some(fb) => fb.advance * (s / 26.0),
None => Face::Wide.width(s, ch.encode_utf8(&mut [0; 4])),
}
};
let width: f32 = line
.chars()
.filter(|&ch| ch != '*')
.map(|ch| advance(ch, size))
.sum();
let size = if width > TEXT_RIGHT - TEXT_LEFT {
size * (TEXT_RIGHT - TEXT_LEFT) / width
} else {
size
};
let mut pen = TEXT_LEFT;
for (index, span) in line.split('*').enumerate() {
let span_color = if index % 2 == 1 { ACCENT } else { color };
for ch in span.chars() {
let ch_color = if color == TITLE && ch == '.' {
ACCENT
} else {
span_color
};
let Some(fb) = fallback(ch) else {
pen = c.text(
Face::Wide,
size,
pen,
baseline,
ch.encode_utf8(&mut [0; 4]),
ch_color,
);
continue;
};
let left = pen.round() as i32 + fb.xmin;
let top = baseline.round() as i32 - fb.ymin - fb.height as i32;
for (row, ink) in fb.coverage.chunks(fb.width.max(1)).enumerate() {
for (column, &alpha) in ink.iter().enumerate() {
c.blend(
left + column as i32,
top + row as i32,
ch_color,
f32::from(alpha) / 255.0,
);
}
}
pen += advance(ch, size);
}
}
}
fn place((x, y): Point) -> Point {
(
YARN_ORIGIN.0 + x * YARN_SCALE,
YARN_ORIGIN.1 + y * YARN_SCALE,
)
}
fn flatten(curve: &Cubic) -> Vec<Point> {
let [p0, p1, p2, p3] = curve.map(place);
(0..=CURVE_SEGMENTS)
.map(|step| {
let t = step as f32 / CURVE_SEGMENTS as f32;
let u = 1.0 - t;
let (a, b, c, d) = (u * u * u, 3.0 * u * u * t, 3.0 * u * t * t, t * t * t);
(
a * p0.0 + b * p1.0 + c * p2.0 + d * p3.0,
a * p0.1 + b * p1.1 + c * p2.1 + d * p3.1,
)
})
.collect()
}
fn segment_distance((px, py): Point, (ax, ay): Point, (bx, by): Point) -> f32 {
let (dx, dy) = (bx - ax, by - ay);
let length = dx * dx + dy * dy;
let t = if length == 0.0 {
0.0
} else {
(((px - ax) * dx + (py - ay) * dy) / length).clamp(0.0, 1.0)
};
(px - ax - t * dx).hypot(py - ay - t * dy)
}
/// the 1200x630 card of og-dark.svg
pub fn render(title: &str, subtitle: &str, description: &str) -> anyhow::Result<Vec<u8>> {
let mut canvas = Canvas::exact(BACKGROUND);
yarn(&mut canvas);
text(&mut canvas, title, TITLE_BASELINE, 64.0, TITLE);
text(&mut canvas, subtitle, SUBTITLE_BASELINE, 34.0, MUTED);
for (index, line) in description.lines().enumerate() {
let baseline = DESCRIPTION_BASELINE + index as f32 * DESCRIPTION_LINE_HEIGHT;
text(&mut canvas, line, baseline, 26.0, MUTED);
}
canvas.png()
}
struct FallbackGlyph {
ch: char,
xmin: i32,
ymin: i32,
width: usize,
height: usize,
advance: f32,
coverage: &'static [u8],
}
const FALLBACK_GLYPHS: &[FallbackGlyph] = &[
FallbackGlyph {
ch: '\u{02ec}',
xmin: 4,
ymin: 0,
width: 8,
height: 5,
advance: 16.0,
coverage: &[
117, 170, 57, 0, 0, 120, 170, 52, 34, 241, 232, 29, 98, 255, 183, 1, 0, 96, 255, 217,
250, 231, 22, 0, 0, 0, 166, 255, 254, 75, 0, 0, 0, 0, 16, 119, 89, 0, 0, 0,
],
},
FallbackGlyph {
ch: '\u{02f6}',
xmin: 5,
ymin: 7,
width: 8,
height: 5,
advance: 16.0,
coverage: &[
0, 2, 68, 37, 0, 36, 68, 5, 0, 77, 255, 63, 0, 207, 199, 0, 0, 188, 202, 0, 67, 255,
76, 0, 43, 254, 84, 0, 180, 214, 2, 0, 127, 197, 3, 28, 219, 86, 0, 0,
],
},
FallbackGlyph {
ch: '\u{0aee}',
xmin: 1,
ymin: 0,
width: 11,
height: 16,
advance: 16.0,
coverage: &[
0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 145, 250, 119, 0, 0, 0, 0, 0, 0,
1, 147, 255, 240, 57, 0, 0, 0, 0, 0, 1, 149, 255, 240, 56, 0, 0, 0, 0, 0, 3, 160, 255,
239, 54, 0, 0, 0, 0, 0, 3, 162, 255, 239, 53, 0, 0, 0, 0, 0, 5, 171, 255, 235, 48, 0,
0, 0, 0, 0, 0, 156, 255, 235, 45, 0, 0, 0, 0, 0, 0, 73, 255, 240, 50, 0, 0, 0, 0, 0, 0,
0, 179, 255, 105, 0, 0, 0, 0, 0, 0, 0, 0, 220, 255, 38, 0, 0, 0, 0, 0, 0, 0, 0, 208,
255, 66, 0, 0, 0, 0, 0, 0, 0, 0, 134, 255, 190, 4, 0, 0, 0, 0, 0, 20, 0, 16, 222, 255,
202, 81, 33, 16, 53, 137, 243, 45, 0, 29, 192, 255, 255, 255, 255, 255, 255, 242, 78,
0, 0, 0, 58, 131, 167, 176, 153, 99, 16, 0,
],
},
FallbackGlyph {
ch: '\u{0e05}',
xmin: 1,
ymin: 0,
width: 12,
height: 14,
advance: 16.0,
coverage: &[
0, 0, 2, 84, 152, 36, 0, 32, 152, 122, 11, 0, 0, 12, 188, 255, 253, 250, 181, 248, 255,
255, 206, 14, 0, 162, 255, 168, 14, 128, 241, 146, 35, 192, 255, 139, 40, 253, 221, 10,
0, 0, 5, 0, 0, 61, 255, 206, 99, 255, 130, 0, 51, 192, 230, 157, 10, 45, 255, 223, 104,
255, 119, 22, 237, 219, 113, 246, 118, 46, 255, 223, 63, 255, 159, 124, 255, 139, 0,
207, 147, 46, 255, 223, 4, 236, 241, 217, 247, 238, 189, 253, 73, 46, 255, 223, 0, 150,
255, 255, 138, 79, 132, 70, 0, 46, 255, 223, 0, 58, 255, 255, 81, 0, 0, 0, 0, 46, 255,
223, 0, 4, 246, 255, 46, 0, 0, 0, 0, 46, 255, 223, 0, 0, 219, 255, 38, 0, 0, 0, 0, 46,
255, 223, 0, 0, 218, 255, 33, 0, 0, 0, 0, 46, 255, 223, 0, 0, 222, 255, 28, 0, 0, 0, 0,
46, 255, 223,
],
},
FallbackGlyph {
ch: '\u{10d0}',
xmin: 2,
ymin: 0,
width: 12,
height: 15,
advance: 16.0,
coverage: &[
0, 0, 0, 109, 136, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 159, 0, 0, 0, 0, 0, 0, 0,
0, 0, 95, 255, 246, 60, 0, 0, 0, 0, 0, 0, 0, 0, 3, 187, 255, 253, 165, 44, 0, 0, 0, 0,
0, 0, 0, 7, 144, 247, 255, 254, 131, 1, 0, 0, 0, 0, 0, 0, 0, 25, 151, 254, 255, 144, 0,
7, 101, 102, 35, 0, 0, 0, 0, 122, 255, 254, 47, 123, 255, 216, 8, 0, 0, 0, 0, 7, 236,
255, 128, 213, 255, 126, 0, 0, 0, 0, 0, 0, 195, 255, 159, 241, 255, 112, 0, 0, 0, 0, 0,
0, 200, 255, 152, 222, 255, 143, 0, 0, 0, 0, 0, 0, 232, 255, 122, 168, 255, 219, 5, 0,
0, 0, 0, 62, 255, 255, 59, 66, 255, 255, 166, 23, 0, 0, 56, 223, 255, 202, 0, 0, 134,
255, 255, 255, 231, 232, 255, 255, 225, 37, 0, 0, 0, 71, 176, 230, 250, 242, 206, 129,
18, 0, 0,
],
},
FallbackGlyph {
ch: '\u{1422}',
xmin: 1,
ymin: 8,
width: 10,
height: 13,
advance: 16.0,
coverage: &[
0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 8, 138, 219, 251, 255, 219, 118, 2, 0, 0, 173, 255,
222, 164, 168, 223, 255, 148, 0, 55, 255, 197, 6, 0, 0, 5, 192, 254, 35, 133, 255, 77,
0, 0, 0, 0, 76, 255, 114, 177, 255, 18, 0, 0, 0, 0, 30, 255, 158, 194, 248, 1, 0, 0, 0,
0, 13, 255, 175, 202, 235, 0, 0, 0, 0, 0, 1, 253, 185, 202, 235, 0, 0, 0, 0, 0, 0, 251,
185, 202, 235, 0, 0, 0, 0, 0, 0, 251, 185, 202, 235, 0, 0, 0, 0, 0, 0, 251, 185, 202,
235, 0, 0, 0, 0, 0, 0, 251, 185, 108, 125, 0, 0, 0, 0, 0, 0, 134, 99,
],
},
FallbackGlyph {
ch: '\u{1d17}',
xmin: 1,
ymin: -1,
width: 13,
height: 9,
advance: 16.0,
coverage: &[
5, 17, 17, 4, 0, 0, 0, 0, 0, 0, 10, 17, 15, 62, 255, 255, 66, 0, 0, 0, 0, 0, 0, 162,
255, 220, 44, 255, 255, 91, 0, 0, 0, 0, 0, 0, 186, 255, 203, 7, 249, 255, 128, 0, 0, 0,
0, 0, 0, 224, 255, 160, 0, 186, 255, 216, 3, 0, 0, 0, 0, 60, 255, 255, 90, 0, 76, 255,
255, 145, 3, 0, 0, 29, 215, 255, 227, 9, 0, 0, 157, 255, 255, 222, 164, 179, 245, 255,
248, 70, 0, 0, 0, 2, 121, 241, 255, 255, 255, 255, 209, 61, 0, 0, 0, 0, 0, 0, 6, 59,
84, 78, 39, 0, 0, 0, 0,
],
},
FallbackGlyph {
ch: '\u{1d54}',
xmin: 4,
ymin: 12,
width: 8,
height: 5,
advance: 16.0,
coverage: &[
0, 20, 106, 146, 134, 80, 2, 0, 34, 230, 223, 137, 157, 250, 171, 1, 167, 242, 22, 0,
0, 98, 255, 75, 222, 170, 0, 0, 0, 7, 253, 133, 133, 78, 0, 0, 0, 0, 126, 85,
],
},
FallbackGlyph {
ch: '\u{1d55}',
xmin: 4,
ymin: 8,
width: 8,
height: 5,
advance: 16.0,
coverage: &[
117, 68, 0, 0, 0, 0, 109, 76, 225, 166, 0, 0, 0, 4, 252, 137, 174, 237, 13, 0, 0, 84,
255, 85, 43, 239, 209, 116, 134, 243, 190, 4, 0, 31, 136, 178, 168, 105, 7, 0,
],
},
FallbackGlyph {
ch: '\u{208d}',
xmin: 6,
ymin: -2,
width: 4,
height: 14,
advance: 16.0,
coverage: &[
0, 0, 11, 11, 0, 15, 229, 88, 0, 151, 199, 1, 27, 249, 88, 0, 124, 246, 7, 0, 196, 190,
0, 0, 237, 155, 0, 0, 251, 143, 0, 0, 232, 160, 0, 0, 185, 201, 0, 0, 109, 251, 16, 0,
14, 240, 108, 0, 0, 127, 218, 5, 0, 7, 206, 100,
],
},
FallbackGlyph {
ch: '\u{208e}',
xmin: 6,
ymin: -2,
width: 4,
height: 14,
advance: 16.0,
coverage: &[
17, 5, 0, 0, 175, 159, 0, 0, 36, 251, 63, 0, 0, 177, 188, 0, 0, 86, 255, 37, 0, 25,
255, 107, 0, 0, 245, 146, 0, 0, 232, 162, 0, 1, 250, 141, 0, 36, 255, 96, 0, 100, 252,
26, 0, 197, 168, 0, 56, 250, 44, 0, 181, 131, 0, 0,
],
},
FallbackGlyph {
ch: '\u{2266}',
xmin: 1,
ymin: -3,
width: 14,
height: 18,
advance: 17.0,
coverage: &[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 94, 170, 119, 0, 0, 0, 0, 0, 0, 0, 32, 111, 187, 251,
255, 255, 130, 0, 0, 0, 0, 50, 130, 210, 255, 255, 255, 255, 228, 155, 51, 3, 60, 136,
218, 255, 255, 255, 252, 204, 128, 51, 1, 0, 0, 217, 255, 255, 255, 232, 160, 86, 17,
0, 0, 0, 0, 0, 0, 231, 255, 255, 223, 107, 31, 0, 0, 0, 0, 0, 0, 0, 0, 106, 193, 252,
255, 255, 255, 211, 137, 63, 4, 0, 0, 0, 0, 0, 0, 19, 94, 170, 243, 255, 255, 255, 244,
179, 102, 26, 0, 0, 0, 0, 0, 0, 12, 84, 164, 239, 255, 255, 255, 253, 112, 0, 0, 0, 0,
0, 0, 0, 0, 3, 60, 145, 227, 255, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 54, 59, 92,
102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 52, 231, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 130, 185, 204, 204, 204, 204, 204, 204,
204, 204, 204, 204, 204, 204, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 130, 231, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 130, 46, 51, 51, 51, 51, 51, 51, 51, 51, 51,
51, 51, 51, 26,
],
},
FallbackGlyph {
ch: '\u{2267}',
xmin: 1,
ymin: -3,
width: 14,
height: 18,
advance: 17.0,
coverage: &[
209, 162, 77, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, 255, 255, 238, 170, 94, 14, 0, 0,
0, 0, 0, 0, 0, 103, 184, 247, 255, 255, 255, 247, 178, 99, 21, 0, 0, 0, 0, 0, 0, 9, 68,
136, 215, 255, 255, 255, 253, 204, 128, 39, 0, 0, 0, 0, 0, 0, 0, 42, 116, 189, 249,
255, 255, 255, 117, 0, 0, 0, 0, 0, 0, 0, 3, 60, 148, 250, 255, 255, 130, 0, 0, 0, 0,
20, 91, 167, 237, 255, 255, 255, 237, 162, 52, 0, 43, 119, 187, 250, 255, 255, 255,
233, 162, 77, 6, 0, 0, 210, 255, 255, 255, 255, 212, 133, 52, 1, 0, 0, 0, 0, 0, 231,
253, 204, 128, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 92, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 52, 231, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 130, 185, 204, 204, 204, 204, 204,
204, 204, 204, 204, 204, 204, 204, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 130, 231, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 130, 46, 51, 51, 51, 51, 51, 51, 51, 51,
51, 51, 51, 51, 26,
],
},
FallbackGlyph {
ch: '\u{25e0}',
xmin: 0,
ymin: 6,
width: 16,
height: 9,
advance: 18.0,
coverage: &[
0, 0, 0, 0, 0, 36, 99, 133, 122, 84, 11, 0, 0, 0, 0, 0, 0, 0, 0, 42, 178, 253, 255,
255, 255, 255, 238, 134, 9, 0, 0, 0, 0, 0, 96, 245, 241, 140, 49, 9, 22, 74, 181, 255,
210, 38, 0, 0, 0, 78, 254, 197, 31, 0, 0, 0, 0, 0, 0, 82, 239, 222, 19, 0, 16, 240,
213, 12, 0, 0, 0, 0, 0, 0, 0, 0, 66, 251, 166, 0, 108, 255, 63, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 154, 250, 24, 184, 221, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, 255, 95, 215, 180,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 255, 125, 62, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 67, 39,
],
},
FallbackGlyph {
ch: '\u{25e1}',
xmin: 0,
ymin: -2,
width: 16,
height: 9,
advance: 18.0,
coverage: &[
164, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 186, 99, 199, 196, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 31, 255, 110, 154, 248, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104, 255, 64, 56,
255, 134, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 216, 220, 1, 0, 174, 253, 87, 0, 0, 0, 0, 0,
0, 0, 7, 172, 254, 84, 0, 0, 14, 209, 254, 147, 23, 0, 0, 0, 0, 56, 205, 255, 131, 0,
0, 0, 0, 10, 157, 255, 248, 179, 141, 152, 205, 255, 241, 89, 0, 0, 0, 0, 0, 0, 0, 48,
158, 223, 253, 246, 207, 118, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 0,
0, 0,
],
},
FallbackGlyph {
ch: '\u{2668}',
xmin: 0,
ymin: 0,
width: 16,
height: 16,
advance: 18.0,
coverage: &[
0, 0, 0, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 20, 78, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 47, 57, 0,
129, 7, 0, 0, 37, 32, 0, 0, 0, 0, 0, 0, 0, 139, 0, 0, 142, 0, 0, 4, 99, 0, 0, 0, 0, 0,
0, 0, 17, 137, 0, 10, 133, 0, 0, 106, 26, 0, 0, 0, 0, 0, 0, 0, 0, 157, 1, 4, 143, 0, 0,
143, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 139, 5, 151, 4, 0, 151, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2, 42, 87, 50, 135, 0, 106, 52, 2, 0, 0, 0, 0, 0, 3, 34, 5, 0, 61, 0, 123, 45, 5, 153,
32, 14, 26, 0, 0, 1, 95, 1, 0, 0, 0, 0, 12, 106, 0, 15, 130, 0, 26, 70, 0, 68, 89, 0,
0, 0, 0, 0, 0, 72, 0, 0, 85, 0, 0, 156, 1, 80, 158, 0, 0, 0, 0, 0, 0, 27, 0, 0, 33, 0,
17, 218, 4, 8, 206, 143, 10, 0, 0, 0, 0, 0, 0, 0, 0, 39, 201, 125, 0, 0, 18, 166, 237,
155, 96, 56, 39, 44, 66, 114, 184, 237, 107, 1, 0, 0, 0, 0, 32, 116, 173, 209, 226,
220, 199, 154, 91, 10, 0, 0, 0,
],
},
FallbackGlyph {
ch: '\u{2727}',
xmin: 0,
ymin: -1,
width: 15,
height: 16,
advance: 17.0,
coverage: &[
0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 117, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 185, 116, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 161, 220, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 239,
48, 134, 195, 9, 0, 0, 0, 0, 0, 0, 0, 0, 84, 238, 101, 0, 5, 179, 202, 34, 0, 0, 0, 6,
44, 101, 173, 173, 55, 0, 0, 0, 3, 104, 193, 148, 75, 33, 0, 7, 62, 155, 207, 93, 0, 0,
0, 14, 144, 213, 118, 38, 1, 0, 0, 0, 0, 49, 224, 137, 0, 16, 209, 171, 12, 0, 0, 0, 0,
0, 0, 0, 0, 27, 229, 67, 157, 168, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 174, 214, 9, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 175, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104,
19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 3, 0, 0, 0, 0, 0, 0, 0,
],
},
FallbackGlyph {
ch: '\u{273f}',
xmin: 0,
ymin: 0,
width: 16,
height: 15,
advance: 18.0,
coverage: &[
0, 0, 0, 0, 0, 0, 11, 65, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 226, 255, 255,
177, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, 255, 255, 255, 255, 107, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 243, 255, 255, 255, 255, 154, 0, 2, 0, 0, 0, 0, 78, 217, 245, 173, 223,
254, 219, 236, 255, 179, 214, 251, 187, 32, 0, 46, 250, 255, 255, 255, 190, 30, 0, 0,
75, 234, 255, 255, 255, 208, 1, 122, 255, 255, 255, 225, 14, 0, 0, 0, 0, 72, 255, 255,
255, 255, 33, 105, 255, 255, 255, 137, 0, 0, 0, 0, 0, 0, 225, 255, 255, 254, 17, 14,
219, 255, 255, 115, 0, 0, 0, 0, 0, 0, 203, 255, 255, 143, 0, 0, 16, 124, 210, 173, 0,
0, 0, 0, 0, 15, 243, 165, 88, 1, 0, 0, 0, 57, 250, 254, 80, 0, 0, 0, 4, 164, 255, 209,
7, 0, 0, 0, 0, 174, 255, 255, 253, 158, 96, 110, 201, 255, 255, 255, 83, 0, 0, 0, 0,
188, 255, 255, 255, 255, 242, 255, 255, 255, 255, 255, 98, 0, 0, 0, 0, 105, 255, 255,
255, 255, 118, 205, 255, 255, 255, 241, 28, 0, 0, 0, 0, 1, 122, 227, 229, 130, 3, 29,
179, 239, 204, 61, 0, 0, 0,
],
},
FallbackGlyph {
ch: '\u{3063}',
xmin: 4,
ymin: -1,
width: 17,
height: 14,
advance: 23.0,
coverage: &[
0, 0, 0, 0, 0, 0, 0, 0, 3, 22, 35, 25, 5, 0, 0, 0, 0, 0, 0, 5, 49, 100, 151, 202, 239,
255, 255, 255, 255, 246, 180, 63, 0, 0, 107, 203, 248, 255, 255, 255, 225, 178, 154,
131, 122, 145, 185, 250, 254, 115, 0, 121, 247, 189, 126, 73, 21, 0, 0, 0, 0, 0, 0, 0,
37, 214, 253, 51, 24, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 255, 156, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
225, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 254, 183, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 152, 255, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 120, 255,
203, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 173, 255, 221, 30, 0, 0, 0, 0, 0, 0, 0, 0,
11, 57, 115, 186, 254, 255, 180, 22, 0, 0, 0, 0, 0, 0, 1, 195, 246, 255, 255, 255, 251,
180, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120, 200, 164, 127, 74, 13, 0, 0, 0, 0, 0, 0,
],
},
FallbackGlyph {
ch: '\u{a4b3}',
xmin: 0,
ymin: -2,
width: 18,
height: 22,
advance: 20.0,
coverage: &[
76, 215, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 194,
152, 76, 104, 0, 0, 5, 68, 28, 0, 0, 0, 0, 0, 0, 36, 62, 0, 27, 152, 76, 104, 0, 0, 68,
251, 156, 0, 0, 0, 0, 0, 12, 221, 231, 0, 27, 152, 76, 104, 0, 0, 147, 150, 233, 2, 0,
0, 0, 0, 143, 149, 231, 0, 27, 152, 76, 104, 0, 0, 223, 47, 217, 57, 0, 0, 0, 52, 185,
65, 231, 0, 27, 152, 76, 104, 0, 48, 231, 1, 146, 135, 0, 0, 4, 200, 41, 65, 231, 0,
27, 152, 76, 104, 0, 127, 159, 0, 75, 213, 0, 0, 118, 137, 0, 65, 231, 0, 27, 152, 76,
104, 0, 203, 227, 204, 210, 255, 36, 0, 228, 182, 170, 192, 247, 170, 36, 152, 76, 104,
27, 250, 44, 34, 34, 188, 114, 0, 77, 85, 85, 128, 239, 85, 32, 152, 76, 104, 106, 196,
0, 0, 0, 111, 192, 0, 0, 0, 0, 65, 231, 0, 27, 152, 76, 104, 52, 50, 0, 0, 0, 21, 81,
0, 0, 0, 0, 22, 77, 0, 27, 152, 76, 104, 0, 142, 153, 153, 128, 35, 0, 0, 51, 155, 188,
171, 71, 0, 27, 152, 76, 104, 0, 237, 126, 88, 133, 238, 27, 0, 69, 101, 61, 93, 240,
59, 27, 152, 76, 104, 0, 237, 62, 0, 0, 217, 83, 0, 0, 0, 0, 0, 172, 123, 27, 152, 76,
104, 0, 237, 113, 74, 125, 224, 24, 0, 0, 4, 20, 66, 230, 60, 27, 152, 76, 104, 0, 237,
191, 170, 206, 158, 10, 0, 0, 47, 223, 249, 140, 1, 27, 152, 76, 104, 0, 237, 62, 0, 0,
183, 119, 0, 0, 0, 0, 18, 201, 109, 27, 152, 76, 104, 0, 237, 62, 0, 0, 136, 163, 0, 0,
0, 0, 0, 119, 176, 27, 152, 76, 104, 0, 237, 62, 0, 24, 204, 121, 0, 50, 7, 0, 11, 193,
136, 27, 152, 76, 104, 0, 237, 242, 241, 229, 150, 8, 0, 150, 242, 216, 242, 182, 15,
27, 152, 76, 144, 68, 68, 68, 68, 68, 68, 68, 68, 68, 79, 102, 84, 68, 68, 88, 152, 30,
102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 61,
],
},
FallbackGlyph {
ch: '\u{fecc}',
xmin: 0,
ymin: 0,
width: 16,
height: 9,
advance: 18.0,
coverage: &[
0, 0, 0, 0, 0, 0, 0, 0, 1, 18, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 193, 248, 255,
255, 205, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 223, 60, 5, 24, 217, 168, 0, 0, 0, 0, 0,
0, 0, 0, 0, 62, 175, 222, 31, 60, 234, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 155, 242,
247, 134, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 113, 244, 230, 120, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 30, 189, 226, 61, 74, 244, 60, 0, 0, 0, 0, 136, 136, 136, 145, 175, 244, 182, 19,
0, 0, 161, 251, 187, 147, 136, 82, 255, 255, 255, 250, 220, 117, 2, 0, 0, 0, 5, 120,
219, 252, 255, 153,
],
},
FallbackGlyph {
ch: '\u{ff61}',
xmin: 1,
ymin: -2,
width: 9,
height: 9,
advance: 16.0,
coverage: &[
0, 0, 0, 8, 20, 2, 0, 0, 0, 0, 13, 152, 248, 255, 230, 94, 0, 0, 2, 190, 249, 146, 109,
188, 255, 103, 0, 84, 255, 88, 0, 0, 1, 176, 241, 9, 137, 246, 3, 0, 0, 0, 82, 255, 50,
123, 254, 20, 0, 0, 0, 107, 255, 35, 38, 248, 174, 12, 0, 45, 230, 197, 0, 0, 102, 250,
243, 217, 252, 225, 38, 0, 0, 0, 48, 147, 168, 123, 15, 0, 0,
],
},
FallbackGlyph {
ch: '\u{ff65}',
xmin: 4,
ymin: 7,
width: 5,
height: 5,
advance: 16.0,
coverage: &[
14, 180, 246, 179, 13, 125, 255, 255, 255, 124, 141, 255, 255, 255, 140, 34, 229, 255,
229, 34, 0, 11, 52, 11, 0,
],
},
FallbackGlyph {
ch: '\u{ff89}',
xmin: 1,
ymin: 0,
width: 11,
height: 20,
advance: 16.0,
coverage: &[
0, 0, 0, 0, 0, 0, 0, 0, 142, 122, 21, 0, 0, 0, 0, 0, 0, 0, 0, 224, 255, 34, 0, 0, 0, 0,
0, 0, 0, 6, 252, 231, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 167, 0, 0, 0, 0, 0, 0, 0, 0,
110, 255, 101, 0, 0, 0, 0, 0, 0, 0, 0, 173, 255, 35, 0, 0, 0, 0, 0, 0, 0, 2, 234, 224,
0, 0, 0, 0, 0, 0, 0, 0, 62, 255, 157, 0, 0, 0, 0, 0, 0, 0, 0, 152, 255, 90, 0, 0, 0, 0,
0, 0, 0, 5, 236, 245, 12, 0, 0, 0, 0, 0, 0, 0, 84, 255, 165, 0, 0, 0, 0, 0, 0, 0, 1,
208, 255, 58, 0, 0, 0, 0, 0, 0, 0, 84, 255, 199, 0, 0, 0, 0, 0, 0, 0, 6, 213, 255, 67,
0, 0, 0, 0, 0, 0, 0, 142, 255, 175, 0, 0, 0, 0, 0, 0, 0, 73, 254, 239, 29, 0, 0, 0, 0,
0, 0, 55, 238, 254, 82, 0, 0, 0, 0, 0, 0, 63, 242, 255, 124, 0, 0, 0, 0, 0, 0, 0, 152,
255, 149, 1, 0, 0, 0, 0, 0, 0, 0, 8, 123, 1, 0, 0, 0, 0, 0, 0, 0, 0,
],
},
];
fn fallback_glyph(ch: char) -> Option<&'static FallbackGlyph> {
FALLBACK_GLYPHS.iter().find(|g| g.ch == ch)
}