1use std::mem::{align_of, size_of};
4
5use read_fonts::{
6 tables::glyf::PointFlags,
7 types::{F26Dot6, Fixed, Point},
8};
9
10use super::{super::Hinting, Outline};
11
12pub(crate) struct HarfBuzzOutlineMemory<'a> {
14 pub points: &'a mut [Point<f32>],
15 pub contours: &'a mut [u16],
16 pub flags: &'a mut [PointFlags],
17 pub deltas: &'a mut [Point<f32>],
18 pub iup_buffer: &'a mut [Point<f32>],
19 pub composite_deltas: &'a mut [Point<f32>],
20}
21
22impl<'a> HarfBuzzOutlineMemory<'a> {
23 pub(super) fn new(outline: &Outline, buf: &'a mut [u8]) -> Option<Self> {
24 let (points, buf) = alloc_slice(buf, outline.points)?;
25 let (contours, buf) = alloc_slice(buf, outline.contours)?;
26 let (flags, buf) = alloc_slice(buf, outline.points)?;
27 let (deltas, iup_buffer, composite_deltas, _buf) = if outline.has_variations {
29 let (deltas, buf) = alloc_slice(buf, outline.max_simple_points)?;
30 let (iup_buffer, buf) = alloc_slice(buf, outline.max_simple_points)?;
31 let (composite_deltas, buf) = alloc_slice(buf, outline.max_component_delta_stack)?;
32 (deltas, iup_buffer, composite_deltas, buf)
33 } else {
34 (
35 Default::default(),
36 Default::default(),
37 Default::default(),
38 buf,
39 )
40 };
41 Some(Self {
42 points,
43 contours,
44 flags,
45 deltas,
46 iup_buffer,
47 composite_deltas,
48 })
49 }
50}
51
52pub(crate) struct FreeTypeOutlineMemory<'a> {
54 pub unscaled: &'a mut [Point<i32>],
55 pub scaled: &'a mut [Point<F26Dot6>],
56 pub original_scaled: &'a mut [Point<F26Dot6>],
57 pub contours: &'a mut [u16],
58 pub flags: &'a mut [PointFlags],
59 pub deltas: &'a mut [Point<Fixed>],
60 pub iup_buffer: &'a mut [Point<Fixed>],
61 pub composite_deltas: &'a mut [Point<Fixed>],
62 pub stack: &'a mut [i32],
63 pub cvt: &'a mut [i32],
64 pub storage: &'a mut [i32],
65 pub twilight_scaled: &'a mut [Point<F26Dot6>],
66 pub twilight_original_scaled: &'a mut [Point<F26Dot6>],
67 pub twilight_flags: &'a mut [PointFlags],
68}
69
70impl<'a> FreeTypeOutlineMemory<'a> {
71 pub(super) fn new(outline: &Outline, buf: &'a mut [u8], hinting: Hinting) -> Option<Self> {
72 let hinted = outline.has_hinting && hinting == Hinting::Embedded;
73 let (scaled, buf) = alloc_slice(buf, outline.points)?;
74 let (unscaled, buf) = alloc_slice(buf, outline.max_other_points)?;
75 let (original_scaled, buf) = if hinted {
77 alloc_slice(buf, outline.max_other_points)?
78 } else {
79 (Default::default(), buf)
80 };
81 let (deltas, iup_buffer, composite_deltas, buf) = if outline.has_variations {
83 let (deltas, buf) = alloc_slice(buf, outline.max_simple_points)?;
84 let (iup_buffer, buf) = alloc_slice(buf, outline.max_simple_points)?;
85 let (composite_deltas, buf) = alloc_slice(buf, outline.max_component_delta_stack)?;
86 (deltas, iup_buffer, composite_deltas, buf)
87 } else {
88 (
89 Default::default(),
90 Default::default(),
91 Default::default(),
92 buf,
93 )
94 };
95 let (stack, buf) = if hinted {
97 alloc_slice(buf, outline.max_stack)?
98 } else {
99 (Default::default(), buf)
100 };
101 let (cvt, storage, buf) = if hinted {
103 let (cvt, buf) = alloc_slice(buf, outline.cvt_count)?;
104 let (storage, buf) = alloc_slice(buf, outline.storage_count)?;
105 (cvt, storage, buf)
106 } else {
107 (Default::default(), Default::default(), buf)
108 };
109 let (twilight_scaled, twilight_original_scaled, buf) = if hinted {
111 let (scaled, buf) = alloc_slice(buf, outline.max_twilight_points)?;
112 let (original_scaled, buf) = alloc_slice(buf, outline.max_twilight_points)?;
113 (scaled, original_scaled, buf)
114 } else {
115 (Default::default(), Default::default(), buf)
116 };
117 let (contours, buf) = alloc_slice(buf, outline.contours)?;
118 let (flags, buf) = alloc_slice(buf, outline.points)?;
119 let twilight_flags = if hinted {
121 alloc_slice(buf, outline.max_twilight_points)?.0
122 } else {
123 Default::default()
124 };
125 Some(Self {
126 unscaled,
127 scaled,
128 original_scaled,
129 contours,
130 flags,
131 deltas,
132 iup_buffer,
133 composite_deltas,
134 stack,
135 cvt,
136 storage,
137 twilight_scaled,
138 twilight_original_scaled,
139 twilight_flags,
140 })
141 }
142}
143
144fn alloc_slice<T>(buf: &mut [u8], len: usize) -> Option<(&mut [T], &mut [u8])>
149where
150 T: bytemuck::AnyBitPattern + bytemuck::NoUninit,
151{
152 if len == 0 {
153 return Some((Default::default(), buf));
154 }
155 let base_ptr = buf.as_ptr() as usize;
158 let aligned_ptr = align_up(base_ptr, align_of::<T>());
159 let aligned_offset = aligned_ptr - base_ptr;
160 let buf = buf.get_mut(aligned_offset..)?;
161 let len_in_bytes = len * size_of::<T>();
163 if len_in_bytes > buf.len() {
164 return None;
165 }
166 let (slice_buf, rest) = buf.split_at_mut(len_in_bytes);
167 let slice = bytemuck::try_cast_slice_mut(slice_buf).ok()?;
169 Some((slice, rest))
170}
171
172fn align_up(len: usize, alignment: usize) -> usize {
173 len + (len.wrapping_neg() & (alignment - 1))
174}
175
176#[cfg(test)]
177mod tests {
178 use super::*;
179
180 #[test]
181 fn unaligned_buffer() {
182 let mut buf = [0u8; 40];
183 let alignment = align_of::<i32>();
184 let addr = buf.as_ptr() as usize;
185 let mut unaligned_addr = addr;
186 if unaligned_addr % alignment == 0 {
188 unaligned_addr += 1;
189 }
190 let unaligned_offset = unaligned_addr - addr;
191 let unaligned = &mut buf[unaligned_offset..];
192 assert!(unaligned.as_ptr() as usize % alignment != 0);
193 let (slice, _) = alloc_slice::<i32>(unaligned, 8).unwrap();
194 assert_eq!(slice.as_ptr() as usize % alignment, 0);
195 }
196
197 #[test]
198 fn fail_unaligned_buffer() {
199 let mut buf = [0u8; 40];
200 let alignment = align_of::<i32>();
201 let addr = buf.as_ptr() as usize;
202 let mut unaligned_addr = addr;
203 if unaligned_addr % alignment == 0 {
205 unaligned_addr += 1;
206 }
207 let unaligned_offset = unaligned_addr - addr;
208 let unaligned = &mut buf[unaligned_offset..];
209 assert_eq!(alloc_slice::<i32>(unaligned, 16), None);
210 }
211
212 #[test]
213 fn outline_memory() {
214 let outline_info = Outline {
215 glyph: None,
216 glyph_id: Default::default(),
217 points: 10,
218 contours: 4,
219 max_simple_points: 4,
220 max_other_points: 4,
221 max_component_delta_stack: 4,
222 max_stack: 0,
223 cvt_count: 0,
224 storage_count: 0,
225 max_twilight_points: 0,
226 has_hinting: false,
227 has_variations: true,
228 has_overlaps: false,
229 };
230 let required_size = outline_info.required_buffer_size(Hinting::None);
231 let mut buf = vec![0u8; required_size];
232 let memory = FreeTypeOutlineMemory::new(&outline_info, &mut buf, Hinting::None).unwrap();
233 assert_eq!(memory.scaled.len(), outline_info.points);
234 assert_eq!(memory.unscaled.len(), outline_info.max_other_points);
235 assert_eq!(memory.original_scaled.len(), 0);
237 assert_eq!(memory.flags.len(), outline_info.points);
238 assert_eq!(memory.contours.len(), outline_info.contours);
239 assert_eq!(memory.deltas.len(), outline_info.max_simple_points);
240 assert_eq!(memory.iup_buffer.len(), outline_info.max_simple_points);
241 assert_eq!(
242 memory.composite_deltas.len(),
243 outline_info.max_component_delta_stack
244 );
245 }
246
247 #[test]
248 fn fail_outline_memory() {
249 let outline_info = Outline {
250 glyph: None,
251 glyph_id: Default::default(),
252 points: 10,
253 contours: 4,
254 max_simple_points: 4,
255 max_other_points: 4,
256 max_component_delta_stack: 4,
257 max_stack: 0,
258 cvt_count: 0,
259 storage_count: 0,
260 max_twilight_points: 0,
261 has_hinting: false,
262 has_variations: true,
263 has_overlaps: false,
264 };
265 let not_enough = outline_info.required_buffer_size(Hinting::None) - 5;
268 let mut buf = vec![0u8; not_enough];
269 assert!(FreeTypeOutlineMemory::new(&outline_info, &mut buf, Hinting::None).is_none());
270 }
271}