swash/internal/
mod.rs
1#![allow(dead_code)]
4
5pub mod fixed;
6
7pub mod aat;
8pub mod at;
9pub mod cmap;
10pub mod glyf;
11pub mod head;
12pub mod var;
13pub mod vorg;
14pub mod xmtx;
15
16mod parse;
17
18pub use parse::*;
19
20use head::*;
21
22pub type RawTag = u32;
23
24pub const fn raw_tag(bytes: &[u8; 4]) -> RawTag {
26 (bytes[0] as u32) << 24 | (bytes[1] as u32) << 16 | (bytes[2] as u32) << 8 | bytes[3] as u32
27}
28
29pub mod raw_data {
32 use super::{raw_tag, Bytes, RawTag};
33
34 const OTTO: RawTag = raw_tag(b"OTTO");
35 const TTCF: RawTag = raw_tag(b"ttcf");
36 const FONT: RawTag = 0x10000;
37 const TRUE: RawTag = raw_tag(b"true");
38
39 pub fn is_collection(data: &[u8]) -> bool {
41 Bytes::new(data).read_u32(0) == Some(TTCF)
42 }
43
44 pub fn is_font(data: &[u8], offset: u32) -> bool {
46 let tag = Bytes::new(data).read_u32(offset as usize).unwrap_or(0);
47 tag == FONT || tag == OTTO || tag == TRUE
48 }
49
50 pub fn count(data: &[u8]) -> u32 {
52 if is_collection(data) {
53 Bytes::new(data).read_u32(8).unwrap_or(0)
54 } else if is_font(data, 0) {
55 1
56 } else {
57 0
58 }
59 }
60
61 pub fn offset(data: &[u8], index: u32) -> Option<u32> {
63 if index >= count(data) {
64 return None;
65 }
66 if is_font(data, 0) {
67 Some(0)
68 } else {
69 Bytes::new(data).read_u32(12 + index as usize * 4)
70 }
71 }
72}
73
74pub trait RawFont<'a>: Sized {
76 fn data(&self) -> &'a [u8];
78
79 fn offset(&self) -> u32;
81
82 #[cfg(feature = "std")]
83 fn dump_tables(&self) -> Option<()> {
84 let base = self.offset() as usize;
85 let b = Bytes::new(self.data());
86 let len = b.read_u16(base.checked_add(4)?)? as usize;
87 let record_base = base.checked_add(12)?;
88 let reclen = 16usize;
89 for i in 0..len {
90 let recbase = reclen.checked_mul(i)?.checked_add(record_base)?;
91 let mut s = b.stream_at(recbase)?;
92 let table_tag = s.read_u32()?;
93 let tb = table_tag.to_be_bytes();
94 println!("{}", core::str::from_utf8(&tb).unwrap_or("??"));
95 }
96 Some(())
97 }
98
99 fn table_range(&self, tag: RawTag) -> Option<(u32, u32)> {
101 let base = self.offset() as usize;
102 let b = Bytes::new(self.data());
103 let len = b.read_u16(base.checked_add(4)?)? as usize;
104 let record_base = base.checked_add(12)?;
105 let reclen = 16usize;
106 let mut l = 0;
107 let mut h = len;
108 while l < h {
109 use core::cmp::Ordering::*;
110 let i = (l + h) / 2;
111 let recbase = reclen.checked_mul(i)?.checked_add(record_base)?;
112 let mut s = b.stream_at(recbase)?;
113 let table_tag = s.read_u32()?;
114 match tag.cmp(&table_tag) {
115 Less => h = i,
116 Greater => l = i + 1,
117 Equal => {
118 s.skip(4)?;
119 let start = s.read_u32()?;
120 let len = s.read_u32()?;
121 let end = start.checked_add(len)?;
122 return Some((start, end));
123 }
124 }
125 }
126 None
127 }
128
129 fn table_offset(&self, tag: RawTag) -> u32 {
131 self.table_range(tag).map(|r| r.0).unwrap_or(0)
132 }
133
134 fn table_data(&self, tag: RawTag) -> Option<&'a [u8]> {
136 let r = self.table_range(tag)?;
137 self.data().get(r.0 as usize..r.1 as usize)
138 }
139
140 fn head(&self) -> Option<Head<'a>> {
142 Head::from_font(self)
143 }
144
145 fn os2(&self) -> Option<Os2<'a>> {
147 Os2::from_font(self)
148 }
149
150 fn post(&self) -> Option<Post<'a>> {
152 Post::from_font(self)
153 }
154
155 fn maxp(&self) -> Option<Maxp<'a>> {
157 Maxp::from_font(self)
158 }
159
160 fn hhea(&self) -> Option<Hhea<'a>> {
162 Hhea::from_font(self)
163 }
164 fn vhea(&self) -> Option<Vhea<'a>> {
166 Vhea::from_font(self)
167 }
168}
169
170impl<'a, T> RawFont<'a> for &T
171where
172 T: RawFont<'a>,
173{
174 fn data(&self) -> &'a [u8] {
175 (*self).data()
176 }
177
178 fn offset(&self) -> u32 {
179 (*self).offset()
180 }
181}