1use super::{raw_tag, Bytes, RawFont, RawTag};
4
5pub const HEAD: RawTag = raw_tag(b"head");
6pub const OS_2: RawTag = raw_tag(b"OS/2");
7pub const POST: RawTag = raw_tag(b"post");
8pub const MAXP: RawTag = raw_tag(b"maxp");
9pub const HHEA: RawTag = raw_tag(b"hhea");
10pub const VHEA: RawTag = raw_tag(b"vhea");
11
12#[derive(Copy, Clone)]
14pub struct Head<'a>(Bytes<'a>);
15
16impl<'a> Head<'a> {
17 pub const MAGIC: u32 = 0x5F0F3CF5;
19
20 pub fn new(data: &'a [u8]) -> Self {
22 Self(Bytes::new(data))
23 }
24
25 pub fn from_font(font: impl RawFont<'a>) -> Option<Self> {
28 Some(Self::new(font.table_data(HEAD)?))
29 }
30
31 pub fn data(&self) -> &'a [u8] {
33 self.0.data()
34 }
35
36 pub fn major_version(&self) -> u16 {
38 self.0.read(0).unwrap_or(0)
39 }
40
41 pub fn minor_version(&self) -> u16 {
43 self.0.read(2).unwrap_or(0)
44 }
45
46 pub fn revision(&self) -> u32 {
48 self.0.read(4).unwrap_or(0)
49 }
50
51 pub fn checksum_adjustment(&self) -> u32 {
53 self.0.read(8).unwrap_or(0)
54 }
55
56 pub fn magic(&self) -> u32 {
58 self.0.read(12).unwrap_or(0)
59 }
60
61 pub fn flags(&self) -> u16 {
73 self.0.read(16).unwrap_or(0)
74 }
75
76 pub fn units_per_em(&self) -> u16 {
78 self.0.read(18).unwrap_or(0)
79 }
80
81 pub fn created(&self) -> u64 {
83 self.0.read(20).unwrap_or(0)
84 }
85
86 pub fn modified(&self) -> u64 {
88 self.0.read(28).unwrap_or(0)
89 }
90
91 pub fn bounds(&self) -> [(i16, i16); 2] {
93 [
94 (
95 self.0.read_or_default::<i16>(36),
96 self.0.read_or_default::<i16>(38),
97 ),
98 (
99 self.0.read_or_default::<i16>(40),
100 self.0.read_or_default::<i16>(42),
101 ),
102 ]
103 }
104
105 pub fn mac_style(&self) -> u16 {
115 self.0.read(44).unwrap_or(0)
116 }
117
118 pub fn lowest_recommended_ppem(&self) -> u16 {
120 self.0.read(46).unwrap_or(0)
121 }
122
123 pub fn direction_hint(&self) -> u16 {
126 self.0.read(48).unwrap_or(0)
127 }
128
129 pub fn index_to_location_format(&self) -> u16 {
133 self.0.read(50).unwrap_or(0)
134 }
135
136 pub fn glyph_data_format(&self) -> i16 {
138 self.0.read(52).unwrap_or(0)
139 }
140}
141
142#[derive(Copy, Clone)]
144pub struct Os2<'a>(Bytes<'a>);
145
146impl<'a> Os2<'a> {
147 pub fn new(data: &'a [u8]) -> Self {
149 Self(Bytes::new(data))
150 }
151
152 pub fn from_font(font: impl RawFont<'a>) -> Option<Self> {
155 Some(Self::new(font.table_data(OS_2)?))
156 }
157
158 pub fn data(&self) -> &'a [u8] {
160 self.0.data()
161 }
162
163 pub fn version(&self) -> u16 {
165 self.0.read(0).unwrap_or(0)
166 }
167
168 pub fn average_char_width(&self) -> i16 {
171 self.0.read(2).unwrap_or(0)
172 }
173
174 pub fn weight_class(&self) -> i16 {
186 self.0.read(4).unwrap_or(0)
187 }
188
189 pub fn width_class(&self) -> i16 {
201 self.0.read(6).unwrap_or(0)
202 }
203
204 pub fn type_flags(&self) -> i16 {
212 self.0.read(8).unwrap_or(0)
213 }
214
215 pub fn subscript(&self) -> [(i32, i32); 2] {
217 [
218 (
219 self.0.read::<i16>(14).unwrap_or(0) as i32,
220 self.0.read::<i16>(16).unwrap_or(0) as i32,
221 ),
222 (
223 self.0.read::<i16>(10).unwrap_or(0) as i32,
224 self.0.read::<i16>(12).unwrap_or(0) as i32,
225 ),
226 ]
227 }
228
229 pub fn superscript(&self) -> [(i32, i32); 2] {
231 [
232 (
233 self.0.read::<i16>(22).unwrap_or(0) as i32,
234 self.0.read::<i16>(24).unwrap_or(0) as i32,
235 ),
236 (
237 self.0.read::<i16>(18).unwrap_or(0) as i32,
238 self.0.read::<i16>(20).unwrap_or(0) as i32,
239 ),
240 ]
241 }
242
243 pub fn strikeout_position(&self) -> i16 {
246 self.0.read(28).unwrap_or(0)
247 }
248
249 pub fn strikeout_size(&self) -> i16 {
251 self.0.read(26).unwrap_or(0)
252 }
253
254 pub fn family_class(&self) -> i16 {
257 self.0.read(30).unwrap_or(0)
258 }
259
260 pub fn panose(&self) -> &'a [u8] {
263 self.0
264 .read_bytes(32, 10)
265 .unwrap_or(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
266 }
267
268 pub fn unicode_range(&self) -> (u32, u32, u32, u32) {
271 (
272 self.0.read::<u32>(42).unwrap_or(0),
273 self.0.read::<u32>(46).unwrap_or(0),
274 self.0.read::<u32>(50).unwrap_or(0),
275 self.0.read::<u32>(54).unwrap_or(0),
276 )
277 }
278
279 pub fn vendor_id(&self) -> &'a str {
281 core::str::from_utf8(self.0.read_bytes(58, 4).unwrap_or(b"none")).unwrap_or("none")
282 }
283
284 pub fn selection_flags(&self) -> Flags {
298 Flags(self.0.read(62).unwrap_or(0))
299 }
300
301 pub fn char_range(&self) -> (u16, u16) {
304 (
305 self.0.read::<u16>(64).unwrap_or(0),
306 self.0.read::<u16>(66).unwrap_or(0),
307 )
308 }
309
310 pub fn typographic_ascender(&self) -> i16 {
312 self.0.read(68).unwrap_or(0)
313 }
314
315 pub fn typographic_descender(&self) -> i16 {
317 self.0.read(70).unwrap_or(0)
318 }
319
320 pub fn typographic_line_gap(&self) -> i16 {
322 self.0.read(72).unwrap_or(0)
323 }
324
325 pub fn win_ascent(&self) -> u16 {
328 self.0.read(74).unwrap_or(0)
329 }
330
331 pub fn win_descent(&self) -> u16 {
334 self.0.read(76).unwrap_or(0)
335 }
336
337 pub fn code_page_range(&self) -> (u32, u32) {
340 if self.version() < 1 {
341 return (0, 0);
342 }
343 (
344 self.0.read::<u32>(78).unwrap_or(0),
345 self.0.read::<u32>(82).unwrap_or(0),
346 )
347 }
348
349 pub fn x_height(&self) -> i16 {
352 if self.version() < 2 {
353 return 0;
354 }
355 self.0.read(86).unwrap_or(0)
356 }
357
358 pub fn cap_height(&self) -> i16 {
361 if self.version() < 2 {
362 return 0;
363 }
364 self.0.read(88).unwrap_or(0)
365 }
366
367 pub fn default_char(&self) -> u16 {
371 if self.version() < 2 {
372 return 0;
373 }
374 self.0.read(90).unwrap_or(0)
375 }
376
377 pub fn break_char(&self) -> u16 {
380 if self.version() < 2 {
381 return 0;
382 }
383 self.0.read(92).unwrap_or(0)
384 }
385
386 pub fn max_context(&self) -> u16 {
389 if self.version() < 2 {
390 return 0;
391 }
392 self.0.read(94).unwrap_or(0)
393 }
394
395 pub fn lower_optical_point_size(&self) -> u16 {
398 if self.version() < 5 {
399 return 0;
400 }
401 self.0.read(96).unwrap_or(0)
402 }
403
404 pub fn upper_optical_point_size(&self) -> u16 {
407 if self.version() < 5 {
408 return 0;
409 }
410 self.0.read(98).unwrap_or(0)
411 }
412}
413
414#[derive(Copy, Clone)]
416pub struct Flags(pub u16);
417
418impl Flags {
419 pub fn italic(self) -> bool {
421 self.bit(0)
422 }
423
424 pub fn underscore(self) -> bool {
426 self.bit(1)
427 }
428
429 pub fn negative(self) -> bool {
431 self.bit(2)
432 }
433
434 pub fn outlined(self) -> bool {
436 self.bit(3)
437 }
438
439 pub fn strikeout(self) -> bool {
441 self.bit(4)
442 }
443
444 pub fn bold(self) -> bool {
446 self.bit(5)
447 }
448
449 pub fn regular(self) -> bool {
451 self.bit(6)
452 }
453
454 pub fn use_typographic_metrics(self) -> bool {
456 self.bit(7)
457 }
458
459 pub fn wws_names(self) -> bool {
461 self.bit(8)
462 }
463
464 pub fn oblique(self) -> bool {
466 self.bit(9)
467 }
468
469 fn bit(self, bit: u16) -> bool {
470 self.0 & 1 << bit != 0
471 }
472}
473
474#[derive(Copy, Clone)]
476pub struct Post<'a>(Bytes<'a>);
477
478impl<'a> Post<'a> {
479 pub fn new(data: &'a [u8]) -> Self {
481 Self(Bytes::new(data))
482 }
483
484 pub fn from_font(font: impl RawFont<'a>) -> Option<Self> {
487 Some(Self::new(font.table_data(POST)?))
488 }
489
490 pub fn data(&self) -> &'a [u8] {
492 self.0.data()
493 }
494
495 pub fn version(&self) -> u32 {
497 self.0.read(0).unwrap_or(0)
498 }
499
500 pub fn italic_angle(&self) -> u32 {
502 self.0.read(4).unwrap_or(0)
503 }
504
505 pub fn underline_position(&self) -> i16 {
508 self.0.read(8).unwrap_or(0)
509 }
510
511 pub fn underline_size(&self) -> i16 {
513 self.0.read(10).unwrap_or(0)
514 }
515
516 pub fn is_fixed_pitch(&self) -> bool {
518 self.0.read::<u32>(12).unwrap_or(0) != 0
519 }
520
521 pub fn has_names(&self) -> bool {
524 let v = self.version();
525 v == 0x10000 || v == 0x20000
526 }
527
528 pub fn name(&self, glyph_id: u16) -> Option<&'a str> {
530 if !self.has_names() {
531 return None;
532 }
533 let v = self.version();
534 if v == 0x10000 {
535 if glyph_id >= 258 {
536 return None;
537 }
538 return Some(DEFAULT_GLYPH_NAMES[glyph_id as usize]);
539 } else if v == 0x20000 {
540 let b = &self.0;
541 let count = b.read::<u16>(32)?;
542 if glyph_id >= count {
543 return None;
544 }
545 let mut index = b.read::<u16>(34 + glyph_id as usize * 2)? as usize;
546 if index < 258 {
547 return Some(DEFAULT_GLYPH_NAMES[index]);
548 }
549 index -= 258;
550 let mut base = 34 + count as usize * 2;
551 for _ in 0..index {
552 let len = b.read::<u8>(base)? as usize;
553 base += len + 1;
554 }
555 let len = b.read::<u8>(base)? as usize;
556 base += 1;
557 let bytes = b.read_bytes(base, len)?;
558 return core::str::from_utf8(bytes).ok();
559 }
560 None
561 }
562}
563
564#[derive(Copy, Clone)]
566pub struct Maxp<'a>(Bytes<'a>);
567
568impl<'a> Maxp<'a> {
569 pub fn new(data: &'a [u8]) -> Self {
571 Self(Bytes::new(data))
572 }
573
574 pub fn from_font(font: impl RawFont<'a>) -> Option<Self> {
577 Some(Self::new(font.table_data(MAXP)?))
578 }
579
580 pub fn data(&self) -> &'a [u8] {
582 self.0.data()
583 }
584
585 pub fn version(&self) -> u32 {
589 self.0.read(0).unwrap_or(0)
590 }
591
592 pub fn glyph_count(&self) -> u16 {
594 self.0.read(4).unwrap_or(0)
595 }
596
597 pub fn is_truetype(&self) -> bool {
600 self.version() == 0x00010000
601 }
602
603 pub fn max_points(&self) -> u16 {
605 self.0.read(6).unwrap_or(0)
606 }
607
608 pub fn max_contours(&self) -> u16 {
610 self.0.read(8).unwrap_or(0)
611 }
612
613 pub fn max_composite_points(&self) -> u16 {
615 self.0.read(10).unwrap_or(0)
616 }
617
618 pub fn max_composite_contours(&self) -> u16 {
620 self.0.read(12).unwrap_or(0)
621 }
622
623 pub fn max_zones(&self) -> u16 {
625 self.0.read(14).unwrap_or(0)
626 }
627
628 pub fn max_twilight_points(&self) -> u16 {
630 self.0.read(16).unwrap_or(0)
631 }
632
633 pub fn max_storage(&self) -> u16 {
635 self.0.read(18).unwrap_or(0)
636 }
637
638 pub fn max_function_definitions(&self) -> u16 {
640 self.0.read(20).unwrap_or(0)
641 }
642
643 pub fn max_instruction_definitions(&self) -> u16 {
645 self.0.read(22).unwrap_or(0)
646 }
647
648 pub fn max_stack_depth(&self) -> u16 {
650 self.0.read(24).unwrap_or(0)
651 }
652
653 pub fn max_instructions_size(&self) -> u16 {
655 self.0.read(26).unwrap_or(0)
656 }
657
658 pub fn max_component_elements(&self) -> u16 {
660 self.0.read(28).unwrap_or(0)
661 }
662
663 pub fn max_component_depth(&self) -> u16 {
665 self.0.read(30).unwrap_or(0)
666 }
667}
668
669#[derive(Copy, Clone)]
671pub struct Hhea<'a>(Bytes<'a>);
672
673impl<'a> Hhea<'a> {
674 pub fn new(data: &'a [u8]) -> Self {
676 Self(Bytes::new(data))
677 }
678
679 pub fn from_font(font: impl RawFont<'a>) -> Option<Self> {
682 Some(Self::new(font.table_data(HHEA)?))
683 }
684
685 pub fn data(&self) -> &'a [u8] {
687 self.0.data()
688 }
689
690 pub fn major_version(&self) -> u16 {
692 self.0.read(0).unwrap_or(0)
693 }
694
695 pub fn minor_version(&self) -> u16 {
697 self.0.read(2).unwrap_or(0)
698 }
699
700 pub fn ascender(&self) -> i16 {
702 self.0.read(4).unwrap_or(0)
703 }
704
705 pub fn descender(&self) -> i16 {
707 self.0.read(6).unwrap_or(0)
708 }
709
710 pub fn line_gap(&self) -> i16 {
712 self.0.read(8).unwrap_or(0)
713 }
714
715 pub fn max_advance(&self) -> u16 {
717 self.0.read(10).unwrap_or(0)
718 }
719
720 pub fn min_lsb(&self) -> i16 {
722 self.0.read(12).unwrap_or(0)
723 }
724
725 pub fn min_rsb(&self) -> i16 {
727 self.0.read(14).unwrap_or(0)
728 }
729
730 pub fn max_extent(&self) -> i16 {
732 self.0.read(16).unwrap_or(0)
733 }
734
735 pub fn caret_slope(&self) -> (i16, i16) {
737 (self.0.read(18).unwrap_or(0), self.0.read(20).unwrap_or(0))
738 }
739
740 pub fn caret_offset(&self) -> i16 {
743 self.0.read(22).unwrap_or(0)
744 }
745
746 pub fn metric_data_format(&self) -> i16 {
748 self.0.read(32).unwrap_or(0)
749 }
750
751 pub fn num_long_metrics(&self) -> u16 {
754 self.0.read(34).unwrap_or(0)
755 }
756}
757
758#[derive(Copy, Clone)]
760pub struct Vhea<'a>(Bytes<'a>);
761
762impl<'a> Vhea<'a> {
763 pub fn new(data: &'a [u8]) -> Self {
765 Self(Bytes::new(data))
766 }
767
768 pub fn from_font(font: impl RawFont<'a>) -> Option<Self> {
771 Some(Self::new(font.table_data(VHEA)?))
772 }
773
774 pub fn data(&self) -> &'a [u8] {
776 self.0.data()
777 }
778
779 pub fn major_version(&self) -> u16 {
781 self.0.read(0).unwrap_or(0)
782 }
783
784 pub fn minor_version(&self) -> u16 {
786 self.0.read(2).unwrap_or(0)
787 }
788
789 pub fn ascender(&self) -> i16 {
792 self.0.read(4).unwrap_or(0)
793 }
794
795 pub fn descender(&self) -> i16 {
798 self.0.read(6).unwrap_or(0)
799 }
800
801 pub fn line_gap(&self) -> i16 {
803 self.0.read(8).unwrap_or(0)
804 }
805
806 pub fn max_advance(&self) -> u16 {
808 self.0.read(10).unwrap_or(0)
809 }
810
811 pub fn min_tsb(&self) -> i16 {
813 self.0.read(12).unwrap_or(0)
814 }
815
816 pub fn min_bsb(&self) -> i16 {
818 self.0.read(14).unwrap_or(0)
819 }
820
821 pub fn max_extent(&self) -> i16 {
823 self.0.read(16).unwrap_or(0)
824 }
825
826 pub fn caret_slope(&self) -> (i16, i16) {
828 (self.0.read(18).unwrap_or(0), self.0.read(20).unwrap_or(0))
829 }
830
831 pub fn caret_offset(&self) -> i16 {
834 self.0.read(22).unwrap_or(0)
835 }
836
837 pub fn metric_data_format(&self) -> i16 {
839 self.0.read(32).unwrap_or(0)
840 }
841
842 pub fn num_long_metrics(&self) -> u16 {
845 self.0.read(34).unwrap_or(0)
846 }
847}
848
849#[rustfmt::skip]
850const DEFAULT_GLYPH_NAMES: [&'static str; 258] = [
851 ".notdef", ".null", "nonmarkingreturn", "space", "exclam", "quotedbl", "numbersign", "dollar",
852 "percent", "ampersand", "quotesingle", "parenleft", "parenright", "asterisk", "plus", "comma",
853 "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven",
854 "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", "A", "B",
855 "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U",
856 "V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum",
857 "underscore", "grave", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
858 "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright",
859 "asciitilde", "Adieresis", "Aring", "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis",
860 "aacute", "agrave", "acircumflex", "adieresis", "atilde", "aring", "ccedilla", "eacute",
861 "egrave", "ecircumflex", "edieresis", "iacute", "igrave", "icircumflex", "idieresis", "ntilde",
862 "oacute", "ograve", "ocircumflex", "odieresis", "otilde", "uacute", "ugrave", "ucircumflex",
863 "udieresis", "dagger", "degree", "cent", "sterling", "section", "bullet", "paragraph",
864 "germandbls", "registered", "copyright", "trademark", "acute", "dieresis", "notequal", "AE",
865 "Oslash", "infinity", "plusminus", "lessequal", "greaterequal", "yen", "mu", "partialdiff",
866 "summation", "product", "pi", "integral", "ordfeminine", "ordmasculine", "Omega", "ae",
867 "oslash", "questiondown", "exclamdown", "logicalnot", "radical", "florin", "approxequal",
868 "Delta", "guillemotleft", "guillemotright", "ellipsis", "nonbreakingspace", "Agrave", "Atilde",
869 "Otilde", "OE", "oe", "endash", "emdash", "quotedblleft", "quotedblright", "quoteleft",
870 "quoteright", "divide", "lozenge", "ydieresis", "Ydieresis", "fraction", "currency",
871 "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl", "periodcentered", "quotesinglbase",
872 "quotedblbase", "perthousand", "Acircumflex", "Ecircumflex", "Aacute", "Edieresis", "Egrave",
873 "Iacute", "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex", "apple", "Ograve",
874 "Uacute", "Ucircumflex", "Ugrave", "dotlessi", "circumflex", "tilde", "macron", "breve",
875 "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek", "caron", "Lslash", "lslash",
876 "Scaron", "scaron", "Zcaron", "zcaron", "brokenbar", "Eth", "eth", "Yacute", "yacute", "Thorn",
877 "thorn", "minus", "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf",
878 "onequarter", "threequarters", "franc", "Gbreve", "gbreve", "Idotaccent", "Scedilla",
879 "scedilla", "Cacute", "cacute", "Ccaron", "ccaron", "dcroat",
880];