1bitflags::bitflags! {
4 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
6 #[repr(transparent)]
7 pub struct CacheKeyFlags: u32 {
8 const FAKE_ITALIC = 1;
10 const DISABLE_HINTING = 2;
12 const PIXEL_FONT = 4;
14 }
15}
16
17#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
19pub struct CacheKey {
20 pub font_id: fontdb::ID,
22 pub glyph_id: u16,
24 pub font_size_bits: u32,
26 pub x_bin: SubpixelBin,
28 pub y_bin: SubpixelBin,
30 pub font_weight: fontdb::Weight,
32 pub flags: CacheKeyFlags,
34}
35
36impl CacheKey {
37 pub fn new(
38 font_id: fontdb::ID,
39 glyph_id: u16,
40 font_size: f32,
41 pos: (f32, f32),
42 weight: fontdb::Weight,
43 flags: CacheKeyFlags,
44 ) -> (Self, i32, i32) {
45 let (x, x_bin) = SubpixelBin::new(pos.0);
46 let (y, y_bin) = SubpixelBin::new(pos.1);
47 (
48 Self {
49 font_id,
50 glyph_id,
51 font_size_bits: font_size.to_bits(),
52 x_bin,
53 y_bin,
54 flags,
55 font_weight: weight,
56 },
57 x,
58 y,
59 )
60 }
61}
62
63#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
65pub enum SubpixelBin {
66 Zero,
67 One,
68 Two,
69 Three,
70}
71
72impl SubpixelBin {
73 pub fn new(pos: f32) -> (i32, Self) {
74 let trunc = pos as i32;
75 let fract = pos - trunc as f32;
76
77 if pos.is_sign_negative() {
78 if fract > -0.125 {
79 (trunc, Self::Zero)
80 } else if fract > -0.375 {
81 (trunc - 1, Self::Three)
82 } else if fract > -0.625 {
83 (trunc - 1, Self::Two)
84 } else if fract > -0.875 {
85 (trunc - 1, Self::One)
86 } else {
87 (trunc - 1, Self::Zero)
88 }
89 } else {
90 #[allow(clippy::collapsible_else_if)]
91 if fract < 0.125 {
92 (trunc, Self::Zero)
93 } else if fract < 0.375 {
94 (trunc, Self::One)
95 } else if fract < 0.625 {
96 (trunc, Self::Two)
97 } else if fract < 0.875 {
98 (trunc, Self::Three)
99 } else {
100 (trunc + 1, Self::Zero)
101 }
102 }
103 }
104
105 pub const fn as_float(&self) -> f32 {
106 match self {
107 Self::Zero => 0.0,
108 Self::One => 0.25,
109 Self::Two => 0.5,
110 Self::Three => 0.75,
111 }
112 }
113}
114
115#[test]
116fn test_subpixel_bins() {
117 assert_eq!(SubpixelBin::new(0.0), (0, SubpixelBin::Zero));
121 assert_eq!(SubpixelBin::new(0.124), (0, SubpixelBin::Zero));
122
123 assert_eq!(SubpixelBin::new(0.125), (0, SubpixelBin::One));
125 assert_eq!(SubpixelBin::new(0.25), (0, SubpixelBin::One));
126 assert_eq!(SubpixelBin::new(0.374), (0, SubpixelBin::One));
127
128 assert_eq!(SubpixelBin::new(0.375), (0, SubpixelBin::Two));
130 assert_eq!(SubpixelBin::new(0.5), (0, SubpixelBin::Two));
131 assert_eq!(SubpixelBin::new(0.624), (0, SubpixelBin::Two));
132
133 assert_eq!(SubpixelBin::new(0.625), (0, SubpixelBin::Three));
135 assert_eq!(SubpixelBin::new(0.75), (0, SubpixelBin::Three));
136 assert_eq!(SubpixelBin::new(0.874), (0, SubpixelBin::Three));
137
138 assert_eq!(SubpixelBin::new(0.875), (1, SubpixelBin::Zero));
140 assert_eq!(SubpixelBin::new(0.999), (1, SubpixelBin::Zero));
141 assert_eq!(SubpixelBin::new(1.0), (1, SubpixelBin::Zero));
142 assert_eq!(SubpixelBin::new(1.124), (1, SubpixelBin::Zero));
143
144 assert_eq!(SubpixelBin::new(-0.0), (0, SubpixelBin::Zero));
148 assert_eq!(SubpixelBin::new(-0.124), (0, SubpixelBin::Zero));
149
150 assert_eq!(SubpixelBin::new(-0.125), (-1, SubpixelBin::Three));
152 assert_eq!(SubpixelBin::new(-0.25), (-1, SubpixelBin::Three));
153 assert_eq!(SubpixelBin::new(-0.374), (-1, SubpixelBin::Three));
154
155 assert_eq!(SubpixelBin::new(-0.375), (-1, SubpixelBin::Two));
157 assert_eq!(SubpixelBin::new(-0.5), (-1, SubpixelBin::Two));
158 assert_eq!(SubpixelBin::new(-0.624), (-1, SubpixelBin::Two));
159
160 assert_eq!(SubpixelBin::new(-0.625), (-1, SubpixelBin::One));
162 assert_eq!(SubpixelBin::new(-0.75), (-1, SubpixelBin::One));
163 assert_eq!(SubpixelBin::new(-0.874), (-1, SubpixelBin::One));
164
165 assert_eq!(SubpixelBin::new(-0.875), (-1, SubpixelBin::Zero));
167 assert_eq!(SubpixelBin::new(-0.999), (-1, SubpixelBin::Zero));
168 assert_eq!(SubpixelBin::new(-1.0), (-1, SubpixelBin::Zero));
169 assert_eq!(SubpixelBin::new(-1.124), (-1, SubpixelBin::Zero));
170}