1mod feature;
4mod lookup_flag;
5mod script;
6
7use core::cmp::Ordering;
8
9pub use lookup_flag::LookupFlag;
10pub use script::{ScriptTags, SelectedScript, UNICODE_TO_NEW_OPENTYPE_SCRIPT_TAGS};
11
12use super::variations::DeltaSetIndex;
13
14#[cfg(feature = "std")]
15use crate::collections::IntSet;
16
17#[cfg(test)]
18#[path = "../tests/layout.rs"]
19mod spec_tests;
20
21include!("../../generated/generated_layout.rs");
22
23impl<'a, T: FontRead<'a>> Lookup<'a, T> {
24 pub fn get_subtable(&self, offset: Offset16) -> Result<T, ReadError> {
25 self.resolve_offset(offset)
26 }
27
28 #[cfg(feature = "experimental_traverse")]
29 fn traverse_lookup_flag(&self) -> traversal::FieldType<'a> {
30 self.lookup_flag().to_bits().into()
31 }
32}
33
34pub trait ExtensionLookup<'a, T: FontRead<'a>>: FontRead<'a> {
39 fn extension(&self) -> Result<T, ReadError>;
40}
41
42pub enum Subtables<'a, T: FontRead<'a>, Ext: ExtensionLookup<'a, T>> {
47 Subtable(ArrayOfOffsets<'a, T>),
48 Extension(ArrayOfOffsets<'a, Ext>),
49}
50
51impl<'a, T: FontRead<'a> + 'a, Ext: ExtensionLookup<'a, T> + 'a> Subtables<'a, T, Ext> {
52 pub(crate) fn new(offsets: &'a [BigEndian<Offset16>], data: FontData<'a>) -> Self {
54 Subtables::Subtable(ArrayOfOffsets::new(offsets, data, ()))
55 }
56
57 pub(crate) fn new_ext(offsets: &'a [BigEndian<Offset16>], data: FontData<'a>) -> Self {
59 Subtables::Extension(ArrayOfOffsets::new(offsets, data, ()))
60 }
61
62 pub fn len(&self) -> usize {
64 match self {
65 Subtables::Subtable(inner) => inner.len(),
66 Subtables::Extension(inner) => inner.len(),
67 }
68 }
69
70 pub fn is_empty(&self) -> bool {
71 self.len() == 0
72 }
73
74 pub fn get(&self, idx: usize) -> Result<T, ReadError> {
76 match self {
77 Subtables::Subtable(inner) => inner.get(idx),
78 Subtables::Extension(inner) => inner.get(idx).and_then(|ext| ext.extension()),
79 }
80 }
81
82 pub fn iter(&self) -> impl Iterator<Item = Result<T, ReadError>> + 'a {
84 let (left, right) = match self {
85 Subtables::Subtable(inner) => (Some(inner.iter()), None),
86 Subtables::Extension(inner) => (
87 None,
88 Some(inner.iter().map(|ext| ext.and_then(|ext| ext.extension()))),
89 ),
90 };
91 left.into_iter()
92 .flatten()
93 .chain(right.into_iter().flatten())
94 }
95}
96
97pub enum FeatureParams<'a> {
99 StylisticSet(StylisticSetParams<'a>),
100 Size(SizeParams<'a>),
101 CharacterVariant(CharacterVariantParams<'a>),
102}
103
104impl ReadArgs for FeatureParams<'_> {
105 type Args = Tag;
106}
107
108impl<'a> FontReadWithArgs<'a> for FeatureParams<'a> {
109 fn read_with_args(bytes: FontData<'a>, args: &Tag) -> Result<FeatureParams<'a>, ReadError> {
110 match *args {
111 t if t == Tag::new(b"size") => SizeParams::read(bytes).map(Self::Size),
112 t if &t.to_raw()[..2] == b"ss" => {
114 StylisticSetParams::read(bytes).map(Self::StylisticSet)
115 }
116 t if &t.to_raw()[..2] == b"cv" => {
117 CharacterVariantParams::read(bytes).map(Self::CharacterVariant)
118 }
119 _ => Err(ReadError::InvalidFormat(0xdead)),
122 }
123 }
124}
125
126#[cfg(feature = "experimental_traverse")]
127impl<'a> SomeTable<'a> for FeatureParams<'a> {
128 fn type_name(&self) -> &str {
129 match self {
130 FeatureParams::StylisticSet(table) => table.type_name(),
131 FeatureParams::Size(table) => table.type_name(),
132 FeatureParams::CharacterVariant(table) => table.type_name(),
133 }
134 }
135
136 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
137 match self {
138 FeatureParams::StylisticSet(table) => table.get_field(idx),
139 FeatureParams::Size(table) => table.get_field(idx),
140 FeatureParams::CharacterVariant(table) => table.get_field(idx),
141 }
142 }
143}
144
145impl FeatureTableSubstitutionRecord {
146 pub fn alternate_feature<'a>(&self, data: FontData<'a>) -> Result<Feature<'a>, ReadError> {
147 self.alternate_feature_offset()
148 .resolve_with_args(data, &Tag::new(b"NULL"))
149 }
150}
151
152impl<'a> CoverageTable<'a> {
153 pub fn iter(&self) -> impl Iterator<Item = GlyphId16> + 'a {
154 let (iter1, iter2) = match self {
156 CoverageTable::Format1(t) => (Some(t.glyph_array().iter().map(|g| g.get())), None),
157 CoverageTable::Format2(t) => {
158 let iter = t.range_records().iter().flat_map(RangeRecord::iter);
159 (None, Some(iter))
160 }
161 };
162
163 iter1
164 .into_iter()
165 .flatten()
166 .chain(iter2.into_iter().flatten())
167 }
168
169 pub fn get(&self, gid: impl Into<GlyphId>) -> Option<u16> {
171 match self {
172 CoverageTable::Format1(sub) => sub.get(gid),
173 CoverageTable::Format2(sub) => sub.get(gid),
174 }
175 }
176
177 #[cfg(feature = "std")]
179 pub fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
180 match self {
181 CoverageTable::Format1(sub) => sub.intersects(glyphs),
182 CoverageTable::Format2(sub) => sub.intersects(glyphs),
183 }
184 }
185}
186
187impl CoverageFormat1<'_> {
188 pub fn get(&self, gid: impl Into<GlyphId>) -> Option<u16> {
190 let gid16: GlyphId16 = gid.into().try_into().ok()?;
191 let be_glyph: BigEndian<GlyphId16> = gid16.into();
192 self.glyph_array()
193 .binary_search(&be_glyph)
194 .ok()
195 .map(|idx| idx as _)
196 }
197
198 #[cfg(feature = "std")]
200 pub fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
201 let glyph_count = self.glyph_count() as u32;
202 let num_bits = 32 - glyph_count.leading_zeros();
203 if glyph_count > (glyphs.len() as u32) * num_bits / 2 {
204 glyphs.iter().any(|g| self.get(g).is_some())
205 } else {
206 self.glyph_array()
207 .iter()
208 .any(|g| glyphs.contains(GlyphId::from(g.get())))
209 }
210 }
211}
212
213impl CoverageFormat2<'_> {
214 pub fn get(&self, gid: impl Into<GlyphId>) -> Option<u16> {
216 let gid: GlyphId16 = gid.into().try_into().ok()?;
217 self.range_records()
218 .binary_search_by(|rec| {
219 if rec.end_glyph_id() < gid {
220 Ordering::Less
221 } else if rec.start_glyph_id() > gid {
222 Ordering::Greater
223 } else {
224 Ordering::Equal
225 }
226 })
227 .ok()
228 .map(|idx| {
229 let rec = &self.range_records()[idx];
230 rec.start_coverage_index() + gid.to_u16() - rec.start_glyph_id().to_u16()
231 })
232 }
233
234 #[cfg(feature = "std")]
236 pub fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
237 let range_count = self.range_count() as u32;
238 let num_bits = 32 - range_count.leading_zeros();
239 if range_count > (glyphs.len() as u32) * num_bits / 2 {
240 glyphs.iter().any(|g| self.get(g).is_some())
241 } else {
242 self.range_records()
243 .iter()
244 .any(|record| record.intersects(glyphs))
245 }
246 }
247}
248
249impl RangeRecord {
250 fn iter(&self) -> impl Iterator<Item = GlyphId16> + '_ {
251 (self.start_glyph_id().to_u16()..=self.end_glyph_id().to_u16()).map(GlyphId16::new)
252 }
253
254 #[cfg(feature = "std")]
256 pub fn intersects(&self, glyphs: &IntSet<GlyphId>) -> bool {
257 glyphs.intersects_range(
258 GlyphId::from(self.start_glyph_id())..=GlyphId::from(self.end_glyph_id()),
259 )
260 }
261}
262
263impl DeltaFormat {
264 pub(crate) fn value_count(self, start_size: u16, end_size: u16) -> usize {
265 let range_len = end_size.saturating_add(1).saturating_sub(start_size) as usize;
266 let val_per_word = match self {
267 DeltaFormat::Local2BitDeltas => 8,
268 DeltaFormat::Local4BitDeltas => 4,
269 DeltaFormat::Local8BitDeltas => 2,
270 _ => return 0,
271 };
272
273 let count = range_len / val_per_word;
274 let extra = (range_len % val_per_word).min(1);
275 count + extra
276 }
277}
278
279impl From<DeltaFormat> for i64 {
282 fn from(value: DeltaFormat) -> Self {
283 value as u16 as _
284 }
285}
286
287impl<'a> ClassDefFormat1<'a> {
288 pub fn get(&self, gid: GlyphId16) -> u16 {
290 if gid < self.start_glyph_id() {
291 return 0;
292 }
293 let idx = gid.to_u16() - self.start_glyph_id().to_u16();
294 self.class_value_array()
295 .get(idx as usize)
296 .map(|x| x.get())
297 .unwrap_or(0)
298 }
299
300 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + 'a {
302 let start = self.start_glyph_id();
303 self.class_value_array()
304 .iter()
305 .enumerate()
306 .map(move |(i, val)| {
307 let gid = start.to_u16().saturating_add(i as u16);
308 (GlyphId16::new(gid), val.get())
309 })
310 }
311}
312
313impl<'a> ClassDefFormat2<'a> {
314 pub fn get(&self, gid: GlyphId16) -> u16 {
316 let records = self.class_range_records();
317 let ix = match records.binary_search_by(|rec| rec.start_glyph_id().cmp(&gid)) {
318 Ok(ix) => ix,
319 Err(ix) => ix.saturating_sub(1),
320 };
321 if let Some(record) = records.get(ix) {
322 if (record.start_glyph_id()..=record.end_glyph_id()).contains(&gid) {
323 return record.class();
324 }
325 }
326 0
327 }
328
329 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + 'a {
331 self.class_range_records().iter().flat_map(|range| {
332 let start = range.start_glyph_id().to_u16();
333 let end = range.end_glyph_id().to_u16();
334 (start..=end).map(|gid| (GlyphId16::new(gid), range.class()))
335 })
336 }
337}
338
339impl ClassDef<'_> {
340 pub fn get(&self, gid: GlyphId16) -> u16 {
342 match self {
343 ClassDef::Format1(table) => table.get(gid),
344 ClassDef::Format2(table) => table.get(gid),
345 }
346 }
347
348 pub fn iter(&self) -> impl Iterator<Item = (GlyphId16, u16)> + '_ {
352 let (one, two) = match self {
353 ClassDef::Format1(inner) => (Some(inner.iter()), None),
354 ClassDef::Format2(inner) => (None, Some(inner.iter())),
355 };
356 one.into_iter().flatten().chain(two.into_iter().flatten())
357 }
358}
359
360impl<'a> Device<'a> {
361 pub fn iter(&self) -> impl Iterator<Item = i8> + 'a {
363 let format = self.delta_format();
364 let mut n = (self.end_size() - self.start_size()) as usize + 1;
365 let deltas_per_word = match format {
366 DeltaFormat::Local2BitDeltas => 8,
367 DeltaFormat::Local4BitDeltas => 4,
368 DeltaFormat::Local8BitDeltas => 2,
369 _ => 0,
370 };
371
372 self.delta_value().iter().flat_map(move |val| {
373 let iter = iter_packed_values(val.get(), format, n);
374 n = n.saturating_sub(deltas_per_word);
375 iter
376 })
377 }
378}
379
380fn iter_packed_values(raw: u16, format: DeltaFormat, n: usize) -> impl Iterator<Item = i8> {
381 let mut decoded = [None; 8];
382 let (mask, sign_mask, bits) = match format {
383 DeltaFormat::Local2BitDeltas => (0b11, 0b10, 2usize),
384 DeltaFormat::Local4BitDeltas => (0b1111, 0b1000, 4),
385 DeltaFormat::Local8BitDeltas => (0b1111_1111, 0b1000_0000, 8),
386 _ => (0, 0, 0),
387 };
388
389 let max_per_word = 16 / bits;
390 #[allow(clippy::needless_range_loop)] for i in 0..n.min(max_per_word) {
392 let mask = mask << ((16 - bits) - i * bits);
393 let val = (raw & mask) >> ((16 - bits) - i * bits);
394 let sign = val & sign_mask != 0;
395
396 let val = if sign {
397 -((((!val) & mask) + 1) as i8)
399 } else {
400 val as i8
401 };
402 decoded[i] = Some(val)
403 }
404 decoded.into_iter().flatten()
405}
406
407impl From<VariationIndex<'_>> for DeltaSetIndex {
408 fn from(src: VariationIndex) -> DeltaSetIndex {
409 DeltaSetIndex {
410 outer: src.delta_set_outer_index(),
411 inner: src.delta_set_inner_index(),
412 }
413 }
414}
415
416#[derive(Clone)]
422pub struct TaggedElement<T> {
423 pub tag: Tag,
424 pub element: T,
425}
426
427impl<T> TaggedElement<T> {
428 pub fn new(tag: Tag, element: T) -> Self {
429 Self { tag, element }
430 }
431}
432
433impl<T> std::ops::Deref for TaggedElement<T> {
434 type Target = T;
435
436 fn deref(&self) -> &Self::Target {
437 &self.element
438 }
439}
440
441#[cfg(test)]
442mod tests {
443 use super::*;
444
445 #[test]
446 fn coverage_get_format1() {
447 const COV1_DATA: FontData = FontData::new(&[0, 1, 0, 5, 0, 1, 0, 7, 0, 13, 0, 27, 0, 44]);
449
450 let coverage = CoverageFormat1::read(COV1_DATA).unwrap();
451 assert_eq!(coverage.get(GlyphId::new(1)), Some(0));
452 assert_eq!(coverage.get(GlyphId::new(2)), None);
453 assert_eq!(coverage.get(GlyphId::new(7)), Some(1));
454 assert_eq!(coverage.get(GlyphId::new(27)), Some(3));
455 assert_eq!(coverage.get(GlyphId::new(45)), None);
456 }
457
458 #[test]
459 fn coverage_get_format2() {
460 const COV2_DATA: FontData =
462 FontData::new(&[0, 2, 0, 2, 0, 5, 0, 9, 0, 0, 0, 30, 0, 39, 0, 5]);
463 let coverage = CoverageFormat2::read(COV2_DATA).unwrap();
464 assert_eq!(coverage.get(GlyphId::new(2)), None);
465 assert_eq!(coverage.get(GlyphId::new(7)), Some(2));
466 assert_eq!(coverage.get(GlyphId::new(9)), Some(4));
467 assert_eq!(coverage.get(GlyphId::new(10)), None);
468 assert_eq!(coverage.get(GlyphId::new(32)), Some(7));
469 assert_eq!(coverage.get(GlyphId::new(39)), Some(14));
470 assert_eq!(coverage.get(GlyphId::new(40)), None);
471 }
472
473 #[test]
474 fn classdef_get_format2() {
475 let classdef = ClassDef::read(FontData::new(
476 font_test_data::gdef::MARKATTACHCLASSDEF_TABLE,
477 ))
478 .unwrap();
479 assert!(matches!(classdef, ClassDef::Format2(..)));
480 let gid_class_pairs = [
481 (616, 1),
482 (617, 1),
483 (618, 1),
484 (624, 1),
485 (625, 1),
486 (626, 1),
487 (652, 2),
488 (653, 2),
489 (654, 2),
490 (655, 2),
491 (661, 2),
492 ];
493 for (gid, class) in gid_class_pairs {
494 assert_eq!(classdef.get(GlyphId16::new(gid)), class);
495 }
496 for (gid, class) in classdef.iter() {
497 assert_eq!(classdef.get(gid), class);
498 }
499 }
500
501 #[test]
502 fn delta_decode() {
503 assert_eq!(
505 iter_packed_values(0x123f, DeltaFormat::Local4BitDeltas, 4).collect::<Vec<_>>(),
506 &[1, 2, 3, -1]
507 );
508
509 assert_eq!(
510 iter_packed_values(0x5540, DeltaFormat::Local2BitDeltas, 5).collect::<Vec<_>>(),
511 &[1, 1, 1, 1, 1]
512 );
513 }
514
515 #[test]
516 fn delta_decode_all() {
517 let bytes: &[u8] = &[0, 7, 0, 13, 0, 3, 1, 244, 30, 245, 101, 8, 42, 0];
519 let device = Device::read(bytes.into()).unwrap();
520 assert_eq!(
521 device.iter().collect::<Vec<_>>(),
522 &[1i8, -12, 30, -11, 101, 8, 42]
523 );
524 }
525}