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 }
11}
12
13#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
15pub struct CacheKey {
16 pub font_id: fontdb::ID,
18 pub glyph_id: u16,
20 pub font_size_bits: u32,
22 pub x_bin: SubpixelBin,
24 pub y_bin: SubpixelBin,
26 pub flags: CacheKeyFlags,
28}
29
30impl CacheKey {
31 pub fn new(
32 font_id: fontdb::ID,
33 glyph_id: u16,
34 font_size: f32,
35 pos: (f32, f32),
36 flags: CacheKeyFlags,
37 ) -> (Self, i32, i32) {
38 let (x, x_bin) = SubpixelBin::new(pos.0);
39 let (y, y_bin) = SubpixelBin::new(pos.1);
40 (
41 Self {
42 font_id,
43 glyph_id,
44 font_size_bits: font_size.to_bits(),
45 x_bin,
46 y_bin,
47 flags,
48 },
49 x,
50 y,
51 )
52 }
53}
54
55#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
57pub enum SubpixelBin {
58 Zero,
59 One,
60 Two,
61 Three,
62}
63
64impl SubpixelBin {
65 pub fn new(pos: f32) -> (i32, Self) {
66 let trunc = pos as i32;
67 let fract = pos - trunc as f32;
68
69 if pos.is_sign_negative() {
70 if fract > -0.125 {
71 (trunc, Self::Zero)
72 } else if fract > -0.375 {
73 (trunc - 1, Self::Three)
74 } else if fract > -0.625 {
75 (trunc - 1, Self::Two)
76 } else if fract > -0.875 {
77 (trunc - 1, Self::One)
78 } else {
79 (trunc - 1, Self::Zero)
80 }
81 } else {
82 #[allow(clippy::collapsible_else_if)]
83 if fract < 0.125 {
84 (trunc, Self::Zero)
85 } else if fract < 0.375 {
86 (trunc, Self::One)
87 } else if fract < 0.625 {
88 (trunc, Self::Two)
89 } else if fract < 0.875 {
90 (trunc, Self::Three)
91 } else {
92 (trunc + 1, Self::Zero)
93 }
94 }
95 }
96
97 pub fn as_float(&self) -> f32 {
98 match self {
99 Self::Zero => 0.0,
100 Self::One => 0.25,
101 Self::Two => 0.5,
102 Self::Three => 0.75,
103 }
104 }
105}
106
107#[test]
108fn test_subpixel_bins() {
109 assert_eq!(SubpixelBin::new(0.0), (0, SubpixelBin::Zero));
113 assert_eq!(SubpixelBin::new(0.124), (0, SubpixelBin::Zero));
114
115 assert_eq!(SubpixelBin::new(0.125), (0, SubpixelBin::One));
117 assert_eq!(SubpixelBin::new(0.25), (0, SubpixelBin::One));
118 assert_eq!(SubpixelBin::new(0.374), (0, SubpixelBin::One));
119
120 assert_eq!(SubpixelBin::new(0.375), (0, SubpixelBin::Two));
122 assert_eq!(SubpixelBin::new(0.5), (0, SubpixelBin::Two));
123 assert_eq!(SubpixelBin::new(0.624), (0, SubpixelBin::Two));
124
125 assert_eq!(SubpixelBin::new(0.625), (0, SubpixelBin::Three));
127 assert_eq!(SubpixelBin::new(0.75), (0, SubpixelBin::Three));
128 assert_eq!(SubpixelBin::new(0.874), (0, SubpixelBin::Three));
129
130 assert_eq!(SubpixelBin::new(0.875), (1, SubpixelBin::Zero));
132 assert_eq!(SubpixelBin::new(0.999), (1, SubpixelBin::Zero));
133 assert_eq!(SubpixelBin::new(1.0), (1, SubpixelBin::Zero));
134 assert_eq!(SubpixelBin::new(1.124), (1, SubpixelBin::Zero));
135
136 assert_eq!(SubpixelBin::new(-0.0), (0, SubpixelBin::Zero));
140 assert_eq!(SubpixelBin::new(-0.124), (0, SubpixelBin::Zero));
141
142 assert_eq!(SubpixelBin::new(-0.125), (-1, SubpixelBin::Three));
144 assert_eq!(SubpixelBin::new(-0.25), (-1, SubpixelBin::Three));
145 assert_eq!(SubpixelBin::new(-0.374), (-1, SubpixelBin::Three));
146
147 assert_eq!(SubpixelBin::new(-0.375), (-1, SubpixelBin::Two));
149 assert_eq!(SubpixelBin::new(-0.5), (-1, SubpixelBin::Two));
150 assert_eq!(SubpixelBin::new(-0.624), (-1, SubpixelBin::Two));
151
152 assert_eq!(SubpixelBin::new(-0.625), (-1, SubpixelBin::One));
154 assert_eq!(SubpixelBin::new(-0.75), (-1, SubpixelBin::One));
155 assert_eq!(SubpixelBin::new(-0.874), (-1, SubpixelBin::One));
156
157 assert_eq!(SubpixelBin::new(-0.875), (-1, SubpixelBin::Zero));
159 assert_eq!(SubpixelBin::new(-0.999), (-1, SubpixelBin::Zero));
160 assert_eq!(SubpixelBin::new(-1.0), (-1, SubpixelBin::Zero));
161 assert_eq!(SubpixelBin::new(-1.124), (-1, SubpixelBin::Zero));
162}