1mod paint;
4
5use super::parse_prelude::*;
6use super::var::item::*;
7use core::ops::Range;
8
9pub use paint::*;
10
11pub const COLR: Tag = Tag::new(b"COLR");
13
14#[derive(Copy, Clone)]
18pub struct Colr<'a> {
19 data: Buffer<'a>,
20 version: u16,
21}
22
23impl<'a> Colr<'a> {
24 pub fn new(data: &'a [u8]) -> Self {
27 let data = Buffer::new(data);
28 let version = data.read_or_default(0);
29 Self { data, version }
30 }
31
32 pub fn version(&self) -> u16 {
34 self.version
35 }
36
37 pub fn num_glyphs(&self) -> u16 {
39 self.data.read_u16(2).unwrap_or_default()
40 }
41
42 pub fn glyph(&self, index: u16) -> Option<Glyph<'a>> {
44 if index >= self.num_glyphs() {
45 return None;
46 }
47 let d = &self.data;
48 let offset = d.read_u32(4)? as usize + index as usize * 6;
49 let gid = d.read_u16(offset)?;
50 let first = d.read_u16(offset + 2)? as usize;
51 let offset = d.read_u32(8)? as usize + first * 4;
52 let len = d.read_u16(offset + 4)? as usize;
53 let layers = d.read_slice(offset, len)?;
54 Some(Glyph { gid, layers })
55 }
56
57 pub fn find_glyph(&self, gid: GlyphId) -> Option<Glyph<'a>> {
59 let d = &self.data;
60 let base_offset = d.read_u32(4)? as usize;
61 let mut lo = 0;
62 let mut hi = self.num_glyphs() as usize;
63 while lo < hi {
64 use core::cmp::Ordering::*;
65 let i = (lo + hi) / 2;
66 let offset = base_offset + i * 6;
67 let id = d.read_u16(offset)?;
68 match gid.cmp(&id) {
69 Less => hi = i,
70 Greater => lo = i + 1,
71 Equal => {
72 let first = d.read_u16(offset + 2)? as usize;
73 let offset = d.read_u32(8)? as usize + first * 4;
74 let len = d.read_u16(offset + 4)? as usize;
75 let layers = d.read_slice(offset, len)?;
76 return Some(Glyph { gid, layers });
77 }
78 }
79 }
80 None
81 }
82
83 pub fn glyphs(&self) -> impl Iterator<Item = Glyph<'a>> + 'a + Clone {
85 let copy = *self;
86 (0..self.num_glyphs()).filter_map(move |i| copy.glyph(i))
87 }
88
89 pub fn num_base_paints(&self) -> u32 {
91 if self.version < 1 {
92 return 0;
93 }
94 let base = self.data.read_u32(14).unwrap_or_default() as usize;
95 if base == 0 {
96 return 0;
97 }
98 self.data.read_u32(base).unwrap_or_default()
99 }
100
101 pub fn base_paint(&self, index: u32) -> Option<(GlyphId, Paint<'a>)> {
103 if self.version < 1 {
104 return None;
105 }
106 let index = index as usize;
107 let base = self.data.read_u32(14)? as usize;
108 let len = self.data.read_u32(base)? as usize;
109 if index >= len {
110 return None;
111 }
112 let record_base = base + 4 + index * 6;
113 let id = self.data.read_u16(record_base)?;
114 let paint_offset = base + self.data.read_u32(record_base + 2)? as usize;
115 Some((id, PaintRef::new(self.data, paint_offset as u32)?.get()?))
116 }
117
118 pub fn find_base_paint(&self, gid: GlyphId) -> Option<Paint<'a>> {
120 if self.version < 1 {
121 return None;
122 }
123 let base = self.data.read_u32(14)? as usize;
124 let len = self.data.read_u32(base)? as usize;
125 let mut lo = 0;
126 let mut hi = len;
127 while lo < hi {
128 use core::cmp::Ordering::*;
129 let i = (lo + hi) / 2;
130 let record_base = base + 4 + i * 6;
131 let id = self.data.read_u16(record_base)?;
132 match gid.cmp(&id) {
133 Less => hi = i,
134 Greater => lo = i + 1,
135 Equal => {
136 let paint_offset = base + self.data.read_u32(record_base + 2)? as usize;
137 return PaintRef::new(self.data, paint_offset as u32)?.get();
138 }
139 }
140 }
141 None
142 }
143
144 pub fn base_paints(&self) -> impl Iterator<Item = (GlyphId, Paint<'a>)> + 'a + Clone {
146 let copy = *self;
147 (0..self.num_base_paints()).filter_map(move |i| copy.base_paint(i))
148 }
149
150 pub fn num_paint_layers(&self) -> u32 {
152 if self.version < 1 {
153 return 0;
154 }
155 let base = self.data.read_u32(18).unwrap_or_default() as usize;
156 if base == 0 {
157 return 0;
158 }
159 self.data.read_u32(base).unwrap_or_default()
160 }
161
162 pub fn paint_layer(&self, index: u32) -> Option<Paint<'a>> {
164 if self.version < 1 {
165 return None;
166 }
167 let index = index as usize;
168 let base = self.data.read_u32(18)? as usize;
169 let len = self.data.read_u32(base)? as usize;
170 if index >= len {
171 return None;
172 }
173 let record_base = base + 4 + index * 4;
174 let paint_offset = base + self.data.read_u32(record_base)? as usize;
175 PaintRef::new(self.data, paint_offset as u32)?.get()
176 }
177
178 pub fn paint_layers(&self) -> impl Iterator<Item = Paint<'a>> + 'a + Clone {
180 let copy = *self;
181 (0..self.num_paint_layers()).filter_map(move |i| copy.paint_layer(i))
182 }
183
184 pub fn num_clip_boxes(&self) -> u32 {
186 if self.version < 1 {
187 return 0;
188 }
189 let base = self.data.read_u32(22).unwrap_or_default() as usize;
190 if base == 0 {
191 return 0;
192 }
193 self.data.read_u32(base + 1).unwrap_or_default()
194 }
195
196 pub fn clip_box(&self, index: u32) -> Option<(Range<GlyphId>, ClipBox)> {
199 if self.version < 1 {
200 return None;
201 }
202 let d = &self.data;
203 let base = d.read_u32(22)? as usize;
204 if base == 0 {
205 return None;
206 }
207 let len = d.read_u32(base + 1)? as usize;
208 let index = index as usize;
209 if index >= len {
210 return None;
211 }
212 let record_base = base + 5 + index * 7;
213 let start = d.read_u16(record_base)?;
214 let end = d.read_u16(record_base + 2)? + 1;
215 let offset = d.read_u24(record_base + 4)?;
216 if offset == 0 {
217 return None;
218 }
219 let clip_base = record_base + offset as usize;
220 let format = d.read_u8(clip_base)?;
221 let x_min = f2dot14_to_f32(d.read_i16(clip_base + 1)?);
222 let y_min = f2dot14_to_f32(d.read_i16(clip_base + 5)?);
223 let x_max = f2dot14_to_f32(d.read_i16(clip_base + 9)?);
224 let y_max = f2dot14_to_f32(d.read_i16(clip_base + 13)?);
225 let var_index = if format == 2 {
226 Some(d.read_u32(clip_base + 17)?)
227 } else {
228 None
229 };
230 Some((
231 start..end,
232 ClipBox {
233 x_min,
234 y_min,
235 x_max,
236 y_max,
237 var_index,
238 },
239 ))
240 }
241
242 pub fn find_clip_box(&self, gid: GlyphId) -> Option<ClipBox> {
244 if self.version < 1 {
245 return None;
246 }
247 let d = &self.data;
248 let base = d.read_u32(22)? as usize;
249 if base == 0 {
250 return None;
251 }
252 let len = d.read_u32(base + 1)? as usize;
253 let mut lo = 0;
254 let mut hi = len;
255 while lo < hi {
256 let i = (lo + hi) / 2;
257 let record_base = base + 5 + i * 7;
258 let start = d.read_u16(record_base)?;
259 if gid < start {
260 lo = i + 1;
261 } else if gid > d.read_u16(record_base + 2)? {
262 hi = i;
263 } else {
264 let offset = d.read_u24(record_base + 4)?;
265 if offset == 0 {
266 return None;
267 }
268 let clip_base = record_base + offset as usize;
269 let format = d.read_u8(clip_base)?;
270 let x_min = f2dot14_to_f32(d.read_i16(clip_base + 1)?);
271 let y_min = f2dot14_to_f32(d.read_i16(clip_base + 5)?);
272 let x_max = f2dot14_to_f32(d.read_i16(clip_base + 9)?);
273 let y_max = f2dot14_to_f32(d.read_i16(clip_base + 13)?);
274 let var_index = if format == 2 {
275 Some(d.read_u32(clip_base + 17)?)
276 } else {
277 None
278 };
279 return Some(ClipBox {
280 x_min,
281 y_min,
282 x_max,
283 y_max,
284 var_index,
285 });
286 }
287 }
288 None
289 }
290
291 pub fn clip_boxes(&self) -> impl Iterator<Item = (Range<GlyphId>, ClipBox)> + 'a + Clone {
293 let copy = *self;
294 (0..self.num_clip_boxes()).filter_map(move |i| copy.clip_box(i))
295 }
296
297 pub fn var_mapping(&self) -> Option<DeltaSetIndexMap<'a>> {
299 if self.version < 1 {
300 return None;
301 }
302 DeltaSetIndexMap::new(self.data, self.data.read_offset32(26, 0)?)
303 }
304
305 pub fn ivs(&self) -> Option<ItemVariationStore<'a>> {
307 if self.version < 1 {
308 return None;
309 }
310 ItemVariationStore::new(self.data, self.data.read_offset32(30, 0)?)
311 }
312}
313
314#[derive(Copy, Clone)]
316pub struct Glyph<'a> {
317 pub gid: GlyphId,
319 pub layers: Slice<'a, Layer>,
321}
322
323#[derive(Copy, Clone)]
325pub struct Layer {
326 pub gid: GlyphId,
328 pub palette_index: Option<u16>,
330}
331
332impl ReadData for Layer {
333 const SIZE: usize = 4;
334
335 unsafe fn read_data_unchecked(buf: &[u8], offset: usize) -> Self {
336 let gid = u16::read_data_unchecked(buf, offset);
337 let index = u16::read_data_unchecked(buf, offset + 2);
338 Self {
339 gid,
340 palette_index: if index == 0xFFFF { None } else { Some(index) },
341 }
342 }
343}
344
345fn fixed_to_f32(x: i32) -> f32 {
346 const SCALE: f32 = 1. / 65536.;
347 x as f32 * SCALE
348}
349
350fn f2dot14_to_f32(x: i16) -> f32 {
351 const SCALE: f32 = 1. / 65536.;
352 (x as i32 * 4) as f32 * SCALE
353}