read_fonts/ps/cff/
fd_select.rs1use types::GlyphId;
4
5#[doc(inline)]
6pub use super::v1::{
7 FdSelect, FdSelectFormat0 as Format0, FdSelectFormat3 as Format3, FdSelectFormat4 as Format4,
8 FdSelectRange3 as Range3, FdSelectRange4 as Range4,
9};
10
11impl FdSelect<'_> {
12 pub fn font_index(&self, glyph_id: GlyphId) -> Option<u16> {
14 match self {
15 Self::Format0(fds) => fds
17 .fds()
18 .get(glyph_id.to_u32() as usize)
19 .map(|fd| *fd as u16),
20 Self::Format3(fds) => {
22 let ranges = fds.ranges();
23 let gid = glyph_id.to_u32();
24 let ix = match ranges.binary_search_by(|range| (range.first() as u32).cmp(&gid)) {
25 Ok(ix) => ix,
26 Err(ix) => ix.saturating_sub(1),
27 };
28 Some(ranges.get(ix)?.fd() as u16)
29 }
30 Self::Format4(fds) => {
32 let ranges = fds.ranges();
33 let gid = glyph_id.to_u32();
34 let ix = match ranges.binary_search_by(|range| range.first().cmp(&gid)) {
35 Ok(ix) => ix,
36 Err(ix) => ix.saturating_sub(1),
37 };
38 Some(ranges.get(ix)?.fd())
39 }
40 }
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use font_test_data::bebuffer::BeBuffer;
47
48 use super::{FdSelect, GlyphId};
49 use crate::FontRead;
50 use std::ops::Range;
51
52 #[test]
53 fn select_font_index() {
54 let map = &[
55 (0..10, 0),
56 (10..32, 4),
57 (32..34, 1),
58 (34..128, 12),
59 (128..1024, 2),
60 ];
61 for data in make_fd_selects(map) {
62 let fd_select = FdSelect::read(data.data().into()).unwrap();
63 for (range, font_index) in map {
64 for gid in range.clone() {
65 assert_eq!(
66 fd_select.font_index(GlyphId::from(gid)).unwrap() as u8,
67 *font_index
68 )
69 }
70 }
71 }
72 }
73
74 fn make_fd_selects(map: &[(Range<u16>, u8)]) -> [BeBuffer; 3] {
77 let glyph_count = map.last().unwrap().0.end;
78 let format0 = {
79 let mut buf = BeBuffer::new();
80 buf = buf.push(0u8);
81 let mut fds = vec![0u8; glyph_count as usize];
82 for (range, font_index) in map {
83 for gid in range.clone() {
84 fds[gid as usize] = *font_index;
85 }
86 }
87 buf = buf.extend(fds);
88 buf
89 };
90 let format3 = {
91 let mut buf = BeBuffer::new();
92 buf = buf.push(3u8);
93 buf = buf.push(map.len() as u16);
94 for (range, font_index) in map {
95 buf = buf.push(range.start);
96 buf = buf.push(*font_index);
97 }
98 buf = buf.push(glyph_count);
99 buf
100 };
101 let format4 = {
102 let mut buf = BeBuffer::new();
103 buf = buf.push(4u8);
104 buf = buf.push(map.len() as u32);
105 for (range, font_index) in map {
106 buf = buf.push(range.start as u32);
107 buf = buf.push(*font_index as u16);
108 }
109 buf = buf.push(glyph_count as u32);
110 buf
111 };
112 [format0, format3, format4]
113 }
114}