1pub mod cmap;
4pub mod glyf;
5pub mod loca;
6pub mod os2;
7pub mod svg;
8pub mod variable_fonts;
9
10use std::borrow::Cow;
11use std::convert::TryFrom;
12use std::fmt::{self, Formatter};
13
14use bitflags::bitflags;
15use encoding_rs::Encoding;
16
17use crate::binary::read::{
18 CheckIndex, ReadArray, ReadArrayCow, ReadBinary, ReadBinaryDep, ReadCtxt, ReadFrom, ReadScope,
19 ReadUnchecked,
20};
21use crate::binary::write::{Placeholder, WriteBinary, WriteContext};
22use crate::binary::{I16Be, I32Be, I64Be, U16Be, U32Be};
23use crate::error::{ParseError, WriteError};
24use crate::tag;
25use crate::{size, SafeFrom};
26
27pub const CFF_MAGIC: u32 = tag::OTTO;
29
30pub const TTF_MAGIC: u32 = 0x00010000;
34
35pub const TRUE_MAGIC: u32 = tag::TRUE;
37
38pub const TTCF_MAGIC: u32 = tag::TTCF;
40
41#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
46pub struct Fixed(i32);
47
48type LongDateTime = i64;
52
53pub trait FontTableProvider {
54 fn table_data(&self, tag: u32) -> Result<Option<Cow<'_, [u8]>>, ParseError>;
56
57 fn has_table(&self, tag: u32) -> bool;
58
59 fn read_table_data(&self, tag: u32) -> Result<Cow<'_, [u8]>, ParseError> {
60 self.table_data(tag)?.ok_or(ParseError::MissingValue)
61 }
62
63 fn table_tags(&self) -> Option<Vec<u32>>;
67}
68
69pub trait SfntVersion {
70 fn sfnt_version(&self) -> u32;
71}
72
73#[repr(transparent)]
77#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
78pub struct F2Dot14(i16);
79
80#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
84pub enum IndexToLocFormat {
85 Short,
87 Long,
89}
90
91#[derive(Clone)]
92pub struct OpenTypeFont<'a> {
93 pub scope: ReadScope<'a>,
94 pub data: OpenTypeData<'a>,
95}
96
97#[derive(Clone)]
99pub enum OpenTypeData<'a> {
100 Single(OffsetTable<'a>),
101 Collection(TTCHeader<'a>),
102}
103
104#[derive(Clone)]
106pub struct TTCHeader<'a> {
107 pub major_version: u16,
108 pub minor_version: u16,
109 pub offset_tables: ReadArray<'a, U32Be>,
110 }
112
113#[derive(Clone)]
117pub struct OffsetTable<'a> {
118 pub sfnt_version: u32,
119 pub search_range: u16,
120 pub entry_selector: u16,
121 pub range_shift: u16,
122 pub table_records: ReadArray<'a, TableRecord>,
123}
124
125pub struct OffsetTableFontProvider<'a> {
126 scope: ReadScope<'a>,
127 offset_table: OffsetTable<'a>,
128}
129
130#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Hash)]
134pub struct TableRecord {
135 pub table_tag: u32,
136 pub checksum: u32,
137 pub offset: u32,
138 pub length: u32,
139}
140
141#[derive(Debug, Clone, PartialEq, PartialOrd, Hash)]
145pub struct HeadTable {
146 pub major_version: u16,
147 pub minor_version: u16,
148 pub font_revision: Fixed,
149 pub check_sum_adjustment: u32,
150 pub magic_number: u32,
151 pub flags: u16,
152 pub units_per_em: u16,
153 pub created: LongDateTime,
154 pub modified: LongDateTime,
155 pub x_min: i16,
156 pub y_min: i16,
157 pub x_max: i16,
158 pub y_max: i16,
159 pub mac_style: MacStyle,
160 pub lowest_rec_ppem: u16,
161 pub font_direction_hint: i16,
162 pub index_to_loc_format: IndexToLocFormat,
163 pub glyph_data_format: i16,
164}
165
166bitflags! {
167 pub struct MacStyle: u16 {
169 const BOLD = 1 << 0;
170 const ITALIC = 1 << 1;
171 const UNDERLINE = 1 << 2;
172 const OUTLINE = 1 << 3;
173 const SHADOW = 1 << 4;
174 const CONDENSED = 1 << 5;
175 const EXTENDED = 1 << 6;
176 }
178}
179
180#[derive(Debug, Clone, PartialEq, PartialOrd, Hash)]
188pub struct HheaTable {
189 pub ascender: i16,
190 pub descender: i16,
191 pub line_gap: i16,
192 pub advance_width_max: u16,
193 pub min_left_side_bearing: i16,
194 pub min_right_side_bearing: i16,
195 pub x_max_extent: i16,
196 pub caret_slope_rise: i16,
197 pub caret_slope_run: i16,
198 pub caret_offset: i16,
199 pub num_h_metrics: u16,
200}
201
202#[derive(Debug)]
208pub struct HmtxTable<'a> {
209 pub h_metrics: ReadArrayCow<'a, LongHorMetric>,
210 pub left_side_bearings: ReadArrayCow<'a, I16Be>,
211}
212
213#[derive(Debug, PartialEq, Copy, Clone)]
219pub struct LongHorMetric {
220 pub advance_width: u16,
221 pub lsb: i16,
222}
223
224#[derive(Debug, Clone, PartialEq, PartialOrd, Hash)]
232pub struct MaxpTable {
233 pub num_glyphs: u16,
234 pub version1_sub_table: Option<MaxpVersion1SubTable>,
236}
237
238#[derive(Debug, Clone, PartialEq, PartialOrd, Hash)]
239pub struct MaxpVersion1SubTable {
240 pub max_points: u16,
242 pub max_contours: u16,
244 pub max_composite_points: u16,
246 pub max_composite_contours: u16,
248 pub max_zones: u16,
251 pub max_twilight_points: u16,
253 pub max_storage: u16,
255 pub max_function_defs: u16,
257 pub max_instruction_defs: u16,
259 pub max_stack_elements: u16,
262 pub max_size_of_instructions: u16,
264 pub max_component_elements: u16,
266 pub max_component_depth: u16,
268}
269
270pub struct NameTable<'a> {
274 pub string_storage: ReadScope<'a>,
275 pub name_records: ReadArray<'a, NameRecord>,
276 pub opt_langtag_records: Option<ReadArray<'a, LangTagRecord>>,
281}
282
283#[derive(Debug)]
285pub struct NameRecord {
286 pub platform_id: u16,
287 pub encoding_id: u16,
288 pub language_id: u16,
289 pub name_id: u16,
290 pub length: u16,
291 pub offset: u16,
292}
293
294pub struct LangTagRecord {
296 pub length: u16,
297 pub offset: u16,
298}
299
300pub struct CvtTable<'a> {
304 pub values: ReadArrayCow<'a, I16Be>,
305}
306
307impl<'a> OpenTypeFont<'a> {
308 pub fn table_provider(&self, index: usize) -> Result<OffsetTableFontProvider<'a>, ParseError> {
309 self.offset_table(index)
310 .map(|offset_table| OffsetTableFontProvider {
311 offset_table: offset_table.into_owned(),
312 scope: self.scope,
313 })
314 }
315
316 pub fn offset_table<'b>(
317 &'b self,
318 index: usize,
319 ) -> Result<Cow<'b, OffsetTable<'a>>, ParseError> {
320 match &self.data {
321 OpenTypeData::Single(offset_table) => Ok(Cow::Borrowed(offset_table)),
322 OpenTypeData::Collection(ttc) => {
323 ttc.offset_tables.check_index(index)?;
324 let offset = usize::try_from(ttc.offset_tables.get_item(index))?;
325 let offset_table = self.scope.offset(offset).read::<OffsetTable<'_>>()?;
326 Ok(Cow::Owned(offset_table))
327 }
328 }
329 }
330}
331
332impl<'b> ReadBinary for OpenTypeFont<'b> {
333 type HostType<'a> = OpenTypeFont<'a>;
334
335 fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self::HostType<'a>, ParseError> {
336 let scope = ctxt.scope();
337 let mut peek = ctxt.clone();
338 let magic = peek.read_u32be()?;
339 match magic {
340 TTF_MAGIC | TRUE_MAGIC | CFF_MAGIC => {
341 let offset_table = ctxt.read::<OffsetTable<'_>>()?;
342 let font = OpenTypeData::Single(offset_table);
343 Ok(OpenTypeFont { scope, data: font })
344 }
345 TTCF_MAGIC => {
346 let ttc_header = ctxt.read::<TTCHeader<'_>>()?;
347 let font = OpenTypeData::Collection(ttc_header);
348 Ok(OpenTypeFont { scope, data: font })
349 }
350 _ => Err(ParseError::BadVersion),
351 }
352 }
353}
354
355impl<'b> ReadBinary for TTCHeader<'b> {
356 type HostType<'a> = TTCHeader<'a>;
357
358 fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self::HostType<'a>, ParseError> {
359 let ttc_tag = ctxt.read_u32be()?;
360 match ttc_tag {
361 TTCF_MAGIC => {
362 let major_version = ctxt.read_u16be()?;
363 let minor_version = ctxt.read_u16be()?;
364 ctxt.check(major_version == 1 || major_version == 2)?;
365 let num_fonts = usize::try_from(ctxt.read_u32be()?)?;
366 let offset_tables = ctxt.read_array::<U32Be>(num_fonts)?;
367 Ok(TTCHeader {
369 major_version,
370 minor_version,
371 offset_tables,
372 })
373 }
374 _ => Err(ParseError::BadVersion),
375 }
376 }
377}
378
379impl<'b> ReadBinary for OffsetTable<'b> {
380 type HostType<'a> = OffsetTable<'a>;
381
382 fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self::HostType<'a>, ParseError> {
383 let sfnt_version = ctxt.read_u32be()?;
384 match sfnt_version {
385 TTF_MAGIC | TRUE_MAGIC | CFF_MAGIC => {
386 let num_tables = ctxt.read_u16be()?;
387 let search_range = ctxt.read_u16be()?;
388 let entry_selector = ctxt.read_u16be()?;
389 let range_shift = ctxt.read_u16be()?;
390 let table_records = ctxt.read_array::<TableRecord>(usize::from(num_tables))?;
391 Ok(OffsetTable {
392 sfnt_version,
393 search_range,
394 entry_selector,
395 range_shift,
396 table_records,
397 })
398 }
399 _ => Err(ParseError::BadVersion),
400 }
401 }
402}
403
404impl<'a> FontTableProvider for OffsetTableFontProvider<'a> {
405 fn table_data(&self, tag: u32) -> Result<Option<Cow<'_, [u8]>>, ParseError> {
406 self.offset_table
407 .read_table(&self.scope, tag)
408 .map(|scope| scope.map(|scope| Cow::Borrowed(scope.data())))
409 }
410
411 fn has_table(&self, tag: u32) -> bool {
412 self.offset_table.find_table_record(tag).is_some()
413 }
414
415 fn table_tags(&self) -> Option<Vec<u32>> {
416 Some(
417 self.offset_table
418 .table_records
419 .iter()
420 .map(|rec| rec.table_tag)
421 .collect(),
422 )
423 }
424}
425
426impl<'a> SfntVersion for OffsetTableFontProvider<'a> {
427 fn sfnt_version(&self) -> u32 {
428 self.offset_table.sfnt_version
429 }
430}
431
432impl ReadFrom for TableRecord {
433 type ReadType = ((U32Be, U32Be), (U32Be, U32Be));
434 fn read_from(((table_tag, checksum), (offset, length)): ((u32, u32), (u32, u32))) -> Self {
435 TableRecord {
436 table_tag,
437 checksum,
438 offset,
439 length,
440 }
441 }
442}
443
444impl WriteBinary<&Self> for TableRecord {
445 type Output = ();
446
447 fn write<C: WriteContext>(ctxt: &mut C, table: &TableRecord) -> Result<(), WriteError> {
448 U32Be::write(ctxt, table.table_tag)?;
449 U32Be::write(ctxt, table.checksum)?;
450 U32Be::write(ctxt, table.offset)?;
451 U32Be::write(ctxt, table.length)?;
452
453 Ok(())
454 }
455}
456
457impl<'a> OffsetTable<'a> {
458 pub fn find_table_record(&self, tag: u32) -> Option<TableRecord> {
459 self.table_records
460 .iter()
461 .find(|table_record| table_record.table_tag == tag)
462 }
463
464 pub fn read_table(
465 &self,
466 scope: &ReadScope<'a>,
467 tag: u32,
468 ) -> Result<Option<ReadScope<'a>>, ParseError> {
469 if let Some(table_record) = self.find_table_record(tag) {
470 let table = table_record.read_table(scope)?;
471 Ok(Some(table))
472 } else {
473 Ok(None)
474 }
475 }
476}
477
478impl TableRecord {
479 pub const SIZE: usize = 4 * size::U32;
480
481 pub fn read_table<'a>(&self, scope: &ReadScope<'a>) -> Result<ReadScope<'a>, ParseError> {
482 let offset = usize::try_from(self.offset)?;
483 let length = usize::try_from(self.length)?;
484 scope.offset_length(offset, length)
485 }
486}
487
488impl ReadBinary for HeadTable {
489 type HostType<'a> = Self;
490
491 fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self, ParseError> {
492 let major_version = ctxt.read::<U16Be>()?;
493 let minor_version = ctxt.read::<U16Be>()?;
494 let font_revision = ctxt.read::<Fixed>()?;
495 let check_sum_adjustment = ctxt.read::<U32Be>()?;
496 let magic_number = ctxt.read::<U32Be>()?;
497 ctxt.check(magic_number == 0x5F0F3CF5)?;
498 let flags = ctxt.read::<U16Be>()?;
499 let units_per_em = ctxt.read::<U16Be>()?;
500 let created = ctxt.read::<I64Be>()?;
501 let modified = ctxt.read::<I64Be>()?;
502 let x_min = ctxt.read::<I16Be>()?;
503 let y_min = ctxt.read::<I16Be>()?;
504 let x_max = ctxt.read::<I16Be>()?;
505 let y_max = ctxt.read::<I16Be>()?;
506 let mac_style = ctxt.read::<U16Be>().map(MacStyle::from_bits_truncate)?;
507 let lowest_rec_ppem = ctxt.read::<U16Be>()?;
508 let font_direction_hint = ctxt.read::<I16Be>()?;
509 let index_to_loc_format = ctxt.read::<IndexToLocFormat>()?;
510 let glyph_data_format = ctxt.read::<I16Be>()?;
511
512 Ok(HeadTable {
513 major_version,
514 minor_version,
515 font_revision,
516 check_sum_adjustment,
517 magic_number,
518 flags,
519 units_per_em,
520 created,
521 modified,
522 x_min,
523 y_min,
524 x_max,
525 y_max,
526 mac_style,
527 lowest_rec_ppem,
528 font_direction_hint,
529 index_to_loc_format,
530 glyph_data_format,
531 })
532 }
533}
534
535impl WriteBinary<&Self> for HeadTable {
536 type Output = Placeholder<U32Be, u32>;
537
538 fn write<C: WriteContext>(ctxt: &mut C, table: &HeadTable) -> Result<Self::Output, WriteError> {
544 U16Be::write(ctxt, table.major_version)?;
545 U16Be::write(ctxt, table.minor_version)?;
546 Fixed::write(ctxt, table.font_revision)?;
547 let check_sum_adjustment = ctxt.placeholder()?;
548 U32Be::write(ctxt, table.magic_number)?;
549 U16Be::write(ctxt, table.flags)?;
550 U16Be::write(ctxt, table.units_per_em)?;
551 I64Be::write(ctxt, table.created)?;
552 I64Be::write(ctxt, table.modified)?;
553 I16Be::write(ctxt, table.x_min)?;
554 I16Be::write(ctxt, table.y_min)?;
555 I16Be::write(ctxt, table.x_max)?;
556 I16Be::write(ctxt, table.y_max)?;
557 U16Be::write(ctxt, table.mac_style.bits())?;
558 U16Be::write(ctxt, table.lowest_rec_ppem)?;
559 I16Be::write(ctxt, table.font_direction_hint)?;
560 IndexToLocFormat::write(ctxt, table.index_to_loc_format)?;
561 I16Be::write(ctxt, table.glyph_data_format)?;
562
563 Ok(check_sum_adjustment)
564 }
565}
566
567impl HeadTable {
568 pub fn is_bold(&self) -> bool {
579 self.mac_style.contains(MacStyle::BOLD)
580 }
581
582 pub fn is_italic(&self) -> bool {
583 self.mac_style.contains(MacStyle::ITALIC)
584 }
585}
586
587impl ReadBinary for HheaTable {
588 type HostType<'a> = Self;
589
590 fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self, ParseError> {
591 let major_version = ctxt.read_u16be()?;
592 let _minor_version = ctxt.read_u16be()?;
593 ctxt.check(major_version == 1)?;
594 let ascender = ctxt.read_i16be()?;
595 let descender = ctxt.read_i16be()?;
596 let line_gap = ctxt.read_i16be()?;
597 let advance_width_max = ctxt.read_u16be()?;
598 let min_left_side_bearing = ctxt.read_i16be()?;
599 let min_right_side_bearing = ctxt.read_i16be()?;
600 let x_max_extent = ctxt.read_i16be()?;
601 let caret_slope_rise = ctxt.read_i16be()?;
602 let caret_slope_run = ctxt.read_i16be()?;
603 let caret_offset = ctxt.read_i16be()?;
604 let _reserved1 = ctxt.read_i16be()?;
605 let _reserved2 = ctxt.read_i16be()?;
606 let _reserved3 = ctxt.read_i16be()?;
607 let _reserved4 = ctxt.read_i16be()?;
608 let metric_data_format = ctxt.read_i16be()?;
609 ctxt.check(metric_data_format == 0)?;
610 let num_h_metrics = ctxt.read_u16be()?;
611
612 Ok(HheaTable {
613 ascender,
614 descender,
615 line_gap,
616 advance_width_max,
617 min_left_side_bearing,
618 min_right_side_bearing,
619 x_max_extent,
620 caret_slope_rise,
621 caret_slope_run,
622 caret_offset,
623 num_h_metrics,
624 })
625 }
626}
627
628impl WriteBinary<&Self> for HheaTable {
629 type Output = ();
630
631 fn write<C: WriteContext>(ctxt: &mut C, table: &HheaTable) -> Result<(), WriteError> {
632 U16Be::write(ctxt, 1u16)?; U16Be::write(ctxt, 0u16)?; I16Be::write(ctxt, table.ascender)?;
636 I16Be::write(ctxt, table.descender)?;
637 I16Be::write(ctxt, table.line_gap)?;
638 U16Be::write(ctxt, table.advance_width_max)?;
639 I16Be::write(ctxt, table.min_left_side_bearing)?;
640 I16Be::write(ctxt, table.min_right_side_bearing)?;
641 I16Be::write(ctxt, table.x_max_extent)?;
642 I16Be::write(ctxt, table.caret_slope_rise)?;
643 I16Be::write(ctxt, table.caret_slope_run)?;
644 I16Be::write(ctxt, table.caret_offset)?;
645
646 I16Be::write(ctxt, 0i16)?; I16Be::write(ctxt, 0i16)?; I16Be::write(ctxt, 0i16)?; I16Be::write(ctxt, 0i16)?; I16Be::write(ctxt, 0i16)?; U16Be::write(ctxt, table.num_h_metrics)?;
654
655 Ok(())
656 }
657}
658
659impl<'b> ReadBinaryDep for HmtxTable<'b> {
660 type Args<'a> = (usize, usize); type HostType<'a> = HmtxTable<'a>;
662
663 fn read_dep<'a>(
664 ctxt: &mut ReadCtxt<'a>,
665 (num_glyphs, num_h_metrics): (usize, usize),
666 ) -> Result<Self::HostType<'a>, ParseError> {
667 let h_metrics = ctxt.read_array::<LongHorMetric>(num_h_metrics)?;
668 let left_side_bearings =
669 ctxt.read_array::<I16Be>(num_glyphs.saturating_sub(num_h_metrics))?;
670 Ok(HmtxTable {
671 h_metrics: ReadArrayCow::Borrowed(h_metrics),
672 left_side_bearings: ReadArrayCow::Borrowed(left_side_bearings),
673 })
674 }
675}
676
677impl<'a> WriteBinary<&Self> for HmtxTable<'a> {
678 type Output = ();
679
680 fn write<C: WriteContext>(ctxt: &mut C, table: &HmtxTable<'a>) -> Result<(), WriteError> {
681 ReadArrayCow::write(ctxt, &table.h_metrics)?;
682 ReadArrayCow::write(ctxt, &table.left_side_bearings)?;
683
684 Ok(())
685 }
686}
687
688impl<'a> HmtxTable<'a> {
689 pub fn horizontal_advance(&self, glyph_id: u16) -> Result<u16, ParseError> {
691 if self.h_metrics.is_empty() {
692 return Err(ParseError::BadIndex);
693 }
694
695 let glyph_id = usize::from(glyph_id);
698 let num_h_metrics = self.h_metrics.len();
699 let metric = if glyph_id < num_h_metrics {
700 self.h_metrics.read_item(glyph_id)
701 } else {
702 self.h_metrics.read_item(num_h_metrics - 1)
707 };
708 metric.map(|metric| metric.advance_width)
709 }
710
711 pub fn metric(&self, glyph_id: u16) -> Result<LongHorMetric, ParseError> {
713 if self.h_metrics.is_empty() {
714 return Err(ParseError::BadIndex);
715 }
716
717 let glyph_id = usize::from(glyph_id);
718 let num_h_metrics = self.h_metrics.len();
719 if glyph_id < num_h_metrics {
720 self.h_metrics.read_item(glyph_id)
721 } else {
722 let mut metric = self.h_metrics.read_item(num_h_metrics - 1)?;
729 let lsb_index = glyph_id - num_h_metrics;
730 metric.lsb = self
731 .left_side_bearings
732 .check_index(lsb_index)
733 .and_then(|_| self.left_side_bearings.read_item(lsb_index))?;
734 Ok(metric)
735 }
736 }
737}
738
739impl ReadFrom for LongHorMetric {
740 type ReadType = (U16Be, I16Be);
741 fn read_from((advance_width, lsb): (u16, i16)) -> Self {
742 LongHorMetric { advance_width, lsb }
743 }
744}
745
746impl WriteBinary for LongHorMetric {
747 type Output = ();
748
749 fn write<C: WriteContext>(ctxt: &mut C, metric: LongHorMetric) -> Result<(), WriteError> {
750 U16Be::write(ctxt, metric.advance_width)?;
751 I16Be::write(ctxt, metric.lsb)?;
752
753 Ok(())
754 }
755}
756
757impl ReadBinary for MaxpTable {
758 type HostType<'a> = Self;
759
760 fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self, ParseError> {
761 let version = ctxt.read_u32be()?;
762 let num_glyphs = ctxt.read_u16be()?;
763 let sub_table = if version == 0x00010000 {
764 Some(ctxt.read::<MaxpVersion1SubTable>()?)
765 } else {
766 None
767 };
768 Ok(MaxpTable {
769 num_glyphs,
770 version1_sub_table: sub_table,
771 })
772 }
773}
774
775impl WriteBinary<&Self> for MaxpTable {
776 type Output = ();
777
778 fn write<C: WriteContext>(ctxt: &mut C, table: &MaxpTable) -> Result<(), WriteError> {
779 if let Some(sub_table) = &table.version1_sub_table {
780 U32Be::write(ctxt, 0x00010000u32)?; U16Be::write(ctxt, table.num_glyphs)?;
782 MaxpVersion1SubTable::write(ctxt, sub_table)?;
783 } else {
784 U32Be::write(ctxt, 0x00005000u32)?; U16Be::write(ctxt, table.num_glyphs)?;
786 }
787 Ok(())
788 }
789}
790
791impl ReadBinary for MaxpVersion1SubTable {
792 type HostType<'a> = Self;
793
794 fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self, ParseError> {
795 let max_points = ctxt.read_u16be()?;
796 let max_contours = ctxt.read_u16be()?;
797 let max_composite_points = ctxt.read_u16be()?;
798 let max_composite_contours = ctxt.read_u16be()?;
799 let max_zones = ctxt.read_u16be()?;
800 let max_twilight_points = ctxt.read_u16be()?;
801 let max_storage = ctxt.read_u16be()?;
802 let max_function_defs = ctxt.read_u16be()?;
803 let max_instruction_defs = ctxt.read_u16be()?;
804 let max_stack_elements = ctxt.read_u16be()?;
805 let max_size_of_instructions = ctxt.read_u16be()?;
806 let max_component_elements = ctxt.read_u16be()?;
807 let max_component_depth = ctxt.read_u16be()?;
808
809 Ok(MaxpVersion1SubTable {
810 max_points,
811 max_contours,
812 max_composite_points,
813 max_composite_contours,
814 max_zones,
815 max_twilight_points,
816 max_storage,
817 max_function_defs,
818 max_instruction_defs,
819 max_stack_elements,
820 max_size_of_instructions,
821 max_component_elements,
822 max_component_depth,
823 })
824 }
825}
826
827impl WriteBinary<&Self> for MaxpVersion1SubTable {
828 type Output = ();
829
830 fn write<C: WriteContext>(
831 ctxt: &mut C,
832 table: &MaxpVersion1SubTable,
833 ) -> Result<(), WriteError> {
834 U16Be::write(ctxt, table.max_points)?;
835 U16Be::write(ctxt, table.max_contours)?;
836 U16Be::write(ctxt, table.max_composite_points)?;
837 U16Be::write(ctxt, table.max_composite_contours)?;
838 U16Be::write(ctxt, table.max_zones)?;
839 U16Be::write(ctxt, table.max_twilight_points)?;
840 U16Be::write(ctxt, table.max_storage)?;
841 U16Be::write(ctxt, table.max_function_defs)?;
842 U16Be::write(ctxt, table.max_instruction_defs)?;
843 U16Be::write(ctxt, table.max_stack_elements)?;
844 U16Be::write(ctxt, table.max_size_of_instructions)?;
845 U16Be::write(ctxt, table.max_component_elements)?;
846 U16Be::write(ctxt, table.max_component_depth)?;
847
848 Ok(())
849 }
850}
851
852impl NameTable<'_> {
853 pub const COPYRIGHT_NOTICE: u16 = 0;
854 pub const FONT_FAMILY_NAME: u16 = 1;
855 pub const FONT_SUBFAMILY_NAME: u16 = 2;
856 pub const UNIQUE_FONT_IDENTIFIER: u16 = 3;
857 pub const FULL_FONT_NAME: u16 = 4;
858 pub const VERSION_STRING: u16 = 5;
859 pub const POSTSCRIPT_NAME: u16 = 6;
860 pub const TRADEMARK: u16 = 7;
861 pub const MANUFACTURER_NAME: u16 = 8;
862 pub const DESIGNER: u16 = 9;
863 pub const DESCRIPTION: u16 = 10;
864 pub const URL_VENDOR: u16 = 11;
865 pub const URL_DESIGNER: u16 = 12;
866 pub const LICENSE_DESCRIPTION: u16 = 13;
867 pub const LICENSE_INFO_URL: u16 = 14;
868 pub const TYPOGRAPHIC_FAMILY_NAME: u16 = 16;
869 pub const TYPOGRAPHIC_SUBFAMILY_NAME: u16 = 17;
870 pub const COMPATIBLE_FULL: u16 = 18; pub const SAMPLE_TEXT: u16 = 19;
872 pub const POSTSCRIPT_CID_FINDFONT_NAME: u16 = 20;
873 pub const WWS_FAMILY_NAME: u16 = 21; pub const WWS_SUBFAMILY_NAME: u16 = 22;
875 pub const LIGHT_BACKGROUND_PALETTE: u16 = 23;
876 pub const DARK_BACKGROUND_PALETTE: u16 = 24;
877 pub const VARIATIONS_POSTSCRIPT_NAME_PREFIX: u16 = 25;
878
879 pub fn string_for_id(&self, name_id: u16) -> Option<String> {
887 self.name_records
888 .iter()
889 .find_map(|record| {
890 if record.name_id != name_id {
891 return None;
892 }
893 match (record.platform_id, record.encoding_id, record.language_id) {
895 (0, _, _) => Some((record, encoding_rs::UTF_16BE)),
897 (
900 3,
901 1,
902 0x0C09 | 0x2809 | 0x1009 | 0x2409 | 0x4009 | 0x1809 | 0x2009 | 0x4409
903 | 0x1409 | 0x3409 | 0x4809 | 0x1C09 | 0x2C09 | 0x0809 | 0x0409 | 0x3009,
904 ) => Some((record, encoding_rs::UTF_16BE)),
905 (
908 3,
909 10,
910 0x0C09 | 0x2809 | 0x1009 | 0x2409 | 0x4009 | 0x1809 | 0x2009 | 0x4409
911 | 0x1409 | 0x3409 | 0x4809 | 0x1C09 | 0x2C09 | 0x0809 | 0x0409 | 0x3009,
912 ) => Some((record, encoding_rs::UTF_16BE)),
913 (1, 0, 0) => Some((record, encoding_rs::MACINTOSH)),
915 _ => None,
916 }
917 })
918 .and_then(|(record, encoding)| {
919 let offset = usize::from(record.offset);
920 let length = usize::from(record.length);
921 let name_data = self
922 .string_storage
923 .offset_length(offset, length)
924 .ok()?
925 .data();
926 Some(decode(encoding, name_data))
927 })
928 }
929}
930
931pub(crate) fn decode(encoding: &'static Encoding, data: &[u8]) -> String {
932 let mut decoder = encoding.new_decoder();
933 let size = decoder.max_utf8_buffer_length(data.len()).unwrap();
934 let mut s = String::with_capacity(size);
935 let (_res, _read, _repl) = decoder.decode_to_string(data, &mut s, true);
936 s
937}
938
939fn utf16be_encode(string: &str) -> Vec<u8> {
940 string
941 .encode_utf16()
942 .flat_map(|codeunit| codeunit.to_be_bytes())
943 .collect()
944}
945
946impl<'b> ReadBinary for NameTable<'b> {
947 type HostType<'a> = NameTable<'a>;
948
949 fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self::HostType<'a>, ParseError> {
950 let scope = ctxt.scope();
951
952 let format = ctxt.read_u16be()?;
953 ctxt.check(format <= 1)?;
954 let count = usize::from(ctxt.read_u16be()?);
955 let string_offset = usize::from(ctxt.read_u16be()?);
956 let string_storage = scope.offset(string_offset);
957 let name_records = ctxt.read_array::<NameRecord>(count)?;
958 let opt_langtag_records = if format > 0 {
959 let langtag_count = usize::from(ctxt.read_u16be()?);
960 let langtag_records = ctxt.read_array::<LangTagRecord>(langtag_count)?;
961 Some(langtag_records)
962 } else {
963 None
964 };
965
966 Ok(NameTable {
967 string_storage,
968 name_records,
969 opt_langtag_records,
970 })
971 }
972}
973
974impl<'a> WriteBinary<&Self> for NameTable<'a> {
975 type Output = ();
976
977 fn write<C: WriteContext>(ctxt: &mut C, name: &NameTable<'a>) -> Result<(), WriteError> {
978 let format = name.opt_langtag_records.as_ref().map_or(0u16, |_| 1);
979 U16Be::write(ctxt, format)?;
980 U16Be::write(ctxt, u16::try_from(name.name_records.len())?)?; let string_offset = ctxt.placeholder::<U16Be, _>()?;
982 <&ReadArray<'a, _>>::write(ctxt, &name.name_records)?;
983
984 if let Some(lang_tag_records) = &name.opt_langtag_records {
985 U16Be::write(ctxt, u16::try_from(lang_tag_records.len())?)?; <&ReadArray<'a, _>>::write(ctxt, lang_tag_records)?;
987 }
988
989 ctxt.write_placeholder(string_offset, u16::try_from(ctxt.bytes_written())?)?;
990 ctxt.write_bytes(name.string_storage.data())?;
991
992 Ok(())
993 }
994}
995
996impl ReadFrom for NameRecord {
997 type ReadType = ((U16Be, U16Be, U16Be), (U16Be, U16Be, U16Be));
998 fn read_from(
999 ((platform_id, encoding_id, language_id), (name_id, length, offset)): (
1000 (u16, u16, u16),
1001 (u16, u16, u16),
1002 ),
1003 ) -> Self {
1004 NameRecord {
1005 platform_id,
1006 encoding_id,
1007 language_id,
1008 name_id,
1009 length,
1010 offset,
1011 }
1012 }
1013}
1014
1015impl WriteBinary for NameRecord {
1016 type Output = ();
1017
1018 fn write<C: WriteContext>(ctxt: &mut C, record: NameRecord) -> Result<(), WriteError> {
1019 U16Be::write(ctxt, record.platform_id)?;
1020 U16Be::write(ctxt, record.encoding_id)?;
1021 U16Be::write(ctxt, record.language_id)?;
1022 U16Be::write(ctxt, record.name_id)?;
1023 U16Be::write(ctxt, record.length)?;
1024 U16Be::write(ctxt, record.offset)?;
1025
1026 Ok(())
1027 }
1028}
1029
1030impl ReadFrom for LangTagRecord {
1031 type ReadType = (U16Be, U16Be);
1032 fn read_from((length, offset): (u16, u16)) -> Self {
1033 LangTagRecord { length, offset }
1034 }
1035}
1036
1037impl WriteBinary for LangTagRecord {
1038 type Output = ();
1039
1040 fn write<C: WriteContext>(ctxt: &mut C, record: LangTagRecord) -> Result<(), WriteError> {
1041 U16Be::write(ctxt, record.length)?;
1042 U16Be::write(ctxt, record.offset)?;
1043
1044 Ok(())
1045 }
1046}
1047
1048impl ReadBinaryDep for CvtTable<'_> {
1049 type Args<'a> = u32;
1050 type HostType<'a> = CvtTable<'a>;
1051
1052 fn read_dep<'a>(
1053 ctxt: &mut ReadCtxt<'a>,
1054 length: u32,
1055 ) -> Result<Self::HostType<'a>, ParseError> {
1056 let length = usize::safe_from(length);
1057 ctxt.check(length % I16Be::SIZE == 0)?;
1062 let n = length / I16Be::SIZE;
1063 let values = ctxt.read_array(n)?;
1064 Ok(CvtTable {
1065 values: ReadArrayCow::Borrowed(values),
1066 })
1067 }
1068}
1069
1070impl WriteBinary<&Self> for CvtTable<'_> {
1071 type Output = ();
1072
1073 fn write<C: WriteContext>(ctxt: &mut C, table: &Self) -> Result<(), WriteError> {
1074 ReadArrayCow::write(ctxt, &table.values)
1075 }
1076}
1077
1078impl ReadFrom for F2Dot14 {
1079 type ReadType = I16Be;
1080
1081 fn read_from(value: i16) -> Self {
1082 F2Dot14(value)
1083 }
1084}
1085
1086impl WriteBinary for F2Dot14 {
1087 type Output = ();
1088
1089 fn write<C: WriteContext>(ctxt: &mut C, val: Self) -> Result<(), WriteError> {
1090 I16Be::write(ctxt, val.0)
1091 }
1092}
1093
1094impl ReadBinary for IndexToLocFormat {
1095 type HostType<'a> = Self;
1096
1097 fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self, ParseError> {
1098 let index_to_loc_format = ctxt.read_i16be()?;
1099
1100 match index_to_loc_format {
1101 0 => Ok(IndexToLocFormat::Short),
1102 1 => Ok(IndexToLocFormat::Long),
1103 _ => Err(ParseError::BadValue),
1104 }
1105 }
1106}
1107
1108impl WriteBinary for IndexToLocFormat {
1109 type Output = ();
1110
1111 fn write<C: WriteContext>(ctxt: &mut C, index_to_loc_format: Self) -> Result<(), WriteError> {
1112 match index_to_loc_format {
1113 IndexToLocFormat::Short => I16Be::write(ctxt, 0i16),
1114 IndexToLocFormat::Long => I16Be::write(ctxt, 1i16),
1115 }
1116 }
1117}
1118
1119impl Fixed {
1120 pub const fn from_raw(value: i32) -> Fixed {
1122 Fixed(value)
1123 }
1124
1125 pub fn raw_value(&self) -> i32 {
1126 self.0
1127 }
1128
1129 pub fn abs(&self) -> Fixed {
1130 Fixed(self.0.abs())
1131 }
1132}
1133
1134impl std::ops::Add for Fixed {
1135 type Output = Self;
1136
1137 fn add(self, rhs: Self) -> Self::Output {
1138 Fixed(self.0.wrapping_add(rhs.0))
1139 }
1140}
1141
1142impl std::ops::Sub for Fixed {
1143 type Output = Self;
1144
1145 fn sub(self, rhs: Self) -> Self::Output {
1146 Fixed(self.0.wrapping_sub(rhs.0))
1147 }
1148}
1149
1150impl std::ops::Mul for Fixed {
1151 type Output = Self;
1152
1153 fn mul(self, rhs: Self) -> Self::Output {
1154 let a = i64::from(self.0);
1155 let b = i64::from(rhs.0);
1156 Fixed(((a * b) >> 16) as i32)
1157 }
1158}
1159
1160impl std::ops::Div for Fixed {
1161 type Output = Self;
1162
1163 fn div(self, rhs: Self) -> Self::Output {
1164 let a = i64::from(self.0);
1165 let b = i64::from(rhs.0);
1166 if b == 0 {
1167 return Fixed(0x7FFFFFFF);
1170 }
1171
1172 Fixed(((a << 16) / b) as i32)
1173 }
1174}
1175
1176impl std::ops::Neg for Fixed {
1177 type Output = Self;
1178
1179 fn neg(self) -> Self::Output {
1180 Fixed(-self.0)
1181 }
1182}
1183
1184impl fmt::Debug for Fixed {
1185 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1186 f.debug_tuple("Fixed").field(&f32::from(*self)).finish()
1187 }
1188}
1189
1190impl ReadFrom for Fixed {
1191 type ReadType = I32Be;
1192
1193 fn read_from(value: i32) -> Self {
1194 Fixed(value)
1195 }
1196}
1197
1198impl WriteBinary for Fixed {
1199 type Output = ();
1200
1201 fn write<C: WriteContext>(ctxt: &mut C, val: Self) -> Result<(), WriteError> {
1202 I32Be::write(ctxt, val.0)
1203 }
1204}
1205
1206impl From<Fixed> for f32 {
1207 fn from(value: Fixed) -> f32 {
1208 (f64::from(value.0) / 65536.0) as f32
1209 }
1210}
1211
1212impl From<f32> for Fixed {
1221 fn from(value: f32) -> Self {
1222 let sign = value.signum() as i32;
1223 let value = value.abs();
1224 let fract = (value.fract() * 65536.0).round() as i32;
1225 let int = value.trunc() as i32;
1226 Fixed::from_raw(((int << 16) | fract) * sign)
1227 }
1228}
1229
1230impl From<f64> for Fixed {
1231 fn from(value: f64) -> Self {
1232 let sign = value.signum() as i32;
1233 let value = value.abs();
1234 let fract = (value.fract() * 65536.0).round() as i32;
1235 let int = value.trunc() as i32;
1236 Fixed::from_raw(((int << 16) | fract) * sign)
1237 }
1238}
1239
1240impl From<i32> for Fixed {
1241 fn from(value: i32) -> Self {
1242 Fixed::from_raw(value << 16)
1243 }
1244}
1245
1246impl From<F2Dot14> for Fixed {
1247 fn from(fixed: F2Dot14) -> Self {
1248 Fixed(i32::from(fixed.0) << 2)
1249 }
1250}
1251
1252impl F2Dot14 {
1253 pub fn from_raw(value: i16) -> Self {
1254 F2Dot14(value)
1255 }
1256
1257 pub fn raw_value(&self) -> i16 {
1258 self.0
1259 }
1260}
1261
1262impl std::ops::Add for F2Dot14 {
1263 type Output = Self;
1264
1265 fn add(self, rhs: Self) -> Self::Output {
1266 F2Dot14(self.0.wrapping_add(rhs.0))
1267 }
1268}
1269
1270impl std::ops::Sub for F2Dot14 {
1271 type Output = Self;
1272
1273 fn sub(self, rhs: Self) -> Self::Output {
1274 F2Dot14(self.0.wrapping_sub(rhs.0))
1275 }
1276}
1277
1278impl std::ops::Mul for F2Dot14 {
1279 type Output = Self;
1280
1281 fn mul(self, rhs: Self) -> Self::Output {
1282 let a = i32::from(self.0);
1283 let b = i32::from(rhs.0);
1284 F2Dot14(((a * b) >> 14) as i16)
1285 }
1286}
1287
1288impl std::ops::Div for F2Dot14 {
1289 type Output = Self;
1290
1291 fn div(self, rhs: Self) -> Self::Output {
1292 let a = i32::from(self.0);
1293 let b = i32::from(rhs.0);
1294 if b == 0 {
1295 return F2Dot14(0x7FFF);
1297 }
1298
1299 F2Dot14(((a << 14) / b) as i16)
1300 }
1301}
1302
1303impl std::ops::Neg for F2Dot14 {
1304 type Output = Self;
1305
1306 fn neg(self) -> Self::Output {
1307 F2Dot14(-self.0)
1308 }
1309}
1310
1311impl fmt::Debug for F2Dot14 {
1312 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1313 f.debug_tuple("F2Dot14").field(&f32::from(*self)).finish()
1314 }
1315}
1316
1317impl From<Fixed> for F2Dot14 {
1318 fn from(fixed: Fixed) -> Self {
1319 F2Dot14(((fixed.0 + 2) >> 2) as i16)
1323 }
1324}
1325
1326impl From<f32> for F2Dot14 {
1327 fn from(value: f32) -> Self {
1328 let sign = value.signum() as i16;
1329 let value = value.abs();
1330 let fract = (value.fract() * 16384.0).round() as i16;
1331 let int = value.trunc() as i16;
1332 F2Dot14::from_raw(((int << 14) | fract).wrapping_mul(sign))
1333 }
1334}
1335
1336impl From<i16> for F2Dot14 {
1337 fn from(value: i16) -> Self {
1338 F2Dot14::from_raw(value << 14)
1339 }
1340}
1341
1342impl From<F2Dot14> for f32 {
1343 fn from(value: F2Dot14) -> Self {
1344 f32::from(value.0) / 16384.
1345 }
1346}
1347
1348impl<T: FontTableProvider> FontTableProvider for Box<T> {
1349 fn table_data(&self, tag: u32) -> Result<Option<Cow<'_, [u8]>>, ParseError> {
1350 self.as_ref().table_data(tag)
1351 }
1352
1353 fn has_table(&self, tag: u32) -> bool {
1354 self.as_ref().has_table(tag)
1355 }
1356
1357 fn table_tags(&self) -> Option<Vec<u32>> {
1358 self.as_ref().table_tags()
1359 }
1360}
1361
1362impl<T: SfntVersion> SfntVersion for Box<T> {
1363 fn sfnt_version(&self) -> u32 {
1364 self.as_ref().sfnt_version()
1365 }
1366}
1367
1368pub mod owned {
1369 use std::borrow::Cow;
1372 use std::convert::TryFrom;
1373
1374 use super::utf16be_encode;
1375 use crate::binary::write::{Placeholder, WriteBinary, WriteContext};
1376 use crate::binary::U16Be;
1377 use crate::error::{ParseError, WriteError};
1378
1379 pub struct NameTable<'a> {
1385 pub name_records: Vec<NameRecord<'a>>,
1386 pub langtag_records: Vec<Cow<'a, [u8]>>,
1388 }
1389
1390 pub struct NameRecord<'a> {
1392 pub platform_id: u16,
1393 pub encoding_id: u16,
1394 pub language_id: u16,
1395 pub name_id: u16,
1396 pub string: Cow<'a, [u8]>,
1397 }
1398
1399 impl<'a> NameTable<'a> {
1400 pub fn replace_entries(&mut self, name_id: u16, string: &str) {
1402 self.remove_entries(name_id);
1403 let replacement = NameRecord {
1404 platform_id: 0, encoding_id: 4, language_id: 0,
1407 name_id,
1408 string: Cow::from(utf16be_encode(string)),
1409 };
1410 self.name_records.push(replacement);
1411 }
1412
1413 pub fn remove_entries(&mut self, name_id: u16) {
1414 self.name_records.retain(|record| record.name_id != name_id);
1415 }
1416 }
1417
1418 impl<'a> TryFrom<&super::NameTable<'a>> for NameTable<'a> {
1419 type Error = ParseError;
1420
1421 fn try_from(name: &super::NameTable<'a>) -> Result<NameTable<'a>, ParseError> {
1422 let name_records = name
1423 .name_records
1424 .iter()
1425 .map(|record| {
1426 let string = name
1427 .string_storage
1428 .offset_length(usize::from(record.offset), usize::from(record.length))
1429 .map(|scope| Cow::from(scope.data()))?;
1430 Ok(NameRecord {
1431 platform_id: record.platform_id,
1432 encoding_id: record.encoding_id,
1433 language_id: record.language_id,
1434 name_id: record.name_id,
1435 string,
1436 })
1437 })
1438 .collect::<Result<Vec<_>, ParseError>>()?;
1439 let langtag_records = name
1440 .opt_langtag_records
1441 .as_ref()
1442 .map(|langtag_records| {
1443 langtag_records
1444 .iter()
1445 .map(|record| {
1446 name.string_storage
1447 .offset_length(
1448 usize::from(record.offset),
1449 usize::from(record.length),
1450 )
1451 .map(|scope| Cow::from(scope.data()))
1452 })
1453 .collect::<Result<Vec<_>, _>>()
1454 })
1455 .transpose()?
1456 .unwrap_or_else(Vec::new);
1457
1458 Ok(NameTable {
1459 name_records,
1460 langtag_records,
1461 })
1462 }
1463 }
1464
1465 impl<'a> WriteBinary<&Self> for NameTable<'a> {
1466 type Output = ();
1467
1468 fn write<C: WriteContext>(ctxt: &mut C, name: &NameTable<'a>) -> Result<(), WriteError> {
1469 let format = if name.langtag_records.is_empty() {
1470 0u16
1471 } else {
1472 1
1473 };
1474 U16Be::write(ctxt, format)?;
1475 U16Be::write(ctxt, u16::try_from(name.name_records.len())?)?; let string_offset = ctxt.placeholder::<U16Be, _>()?;
1477 let name_record_offsets = name
1478 .name_records
1479 .iter()
1480 .map(|record| NameRecord::write(ctxt, record))
1481 .collect::<Result<Vec<_>, _>>()?;
1482
1483 if !name.langtag_records.is_empty() {
1484 U16Be::write(ctxt, u16::try_from(name.langtag_records.len())?)?;
1486 }
1487 let langtag_record_offsets = name
1488 .langtag_records
1489 .iter()
1490 .map(|record| {
1491 U16Be::write(ctxt, u16::try_from(record.len())?)?;
1492 ctxt.placeholder::<U16Be, _>()
1493 })
1494 .collect::<Result<Vec<_>, _>>()?;
1495
1496 let string_start = ctxt.bytes_written();
1497 ctxt.write_placeholder(string_offset, u16::try_from(string_start)?)?;
1498
1499 let lang_tags = name.langtag_records.iter().zip(langtag_record_offsets);
1501 let records = name
1502 .name_records
1503 .iter()
1504 .map(|rec| &rec.string)
1505 .zip(name_record_offsets)
1506 .chain(lang_tags);
1507
1508 for (string, placeholder) in records {
1509 ctxt.write_placeholder(
1510 placeholder,
1511 u16::try_from(ctxt.bytes_written() - string_start)?,
1512 )?;
1513 ctxt.write_bytes(string)?;
1514 }
1515
1516 Ok(())
1517 }
1518 }
1519
1520 impl<'a> WriteBinary<&Self> for NameRecord<'a> {
1521 type Output = Placeholder<U16Be, u16>;
1522
1523 fn write<C: WriteContext>(ctxt: &mut C, record: &Self) -> Result<Self::Output, WriteError> {
1524 U16Be::write(ctxt, record.platform_id)?;
1525 U16Be::write(ctxt, record.encoding_id)?;
1526 U16Be::write(ctxt, record.language_id)?;
1527 U16Be::write(ctxt, record.name_id)?;
1528 U16Be::write(ctxt, u16::try_from(record.string.len())?)?;
1529 let offset = ctxt.placeholder()?;
1530 Ok(offset)
1531 }
1532 }
1533}
1534
1535#[cfg(test)]
1536mod tests {
1537 use super::{
1538 owned, F2Dot14, Fixed, HeadTable, HmtxTable, NameTable, OpenTypeData, OpenTypeFont,
1539 };
1540 use crate::assert_close;
1541 use crate::binary::read::ReadScope;
1542 use crate::binary::write::{WriteBinary, WriteBuffer, WriteContext};
1543 use crate::tests::{assert_close, assert_f2dot14_close, assert_fixed_close, read_fixture};
1544 use std::convert::TryFrom;
1545
1546 const NAME_DATA: &[u8] = include_bytes!("../tests/fonts/opentype/name.bin");
1547
1548 #[test]
1549 fn test_write_head_table() {
1550 let head_data = include_bytes!("../tests/fonts/opentype/head.bin");
1552 let head = ReadScope::new(head_data).read::<HeadTable>().unwrap();
1553 let checksum_adjustment = head.check_sum_adjustment;
1554
1555 let mut ctxt = WriteBuffer::new();
1556 let placeholder = HeadTable::write(&mut ctxt, &head).unwrap();
1557 ctxt.write_placeholder(placeholder, checksum_adjustment)
1558 .unwrap();
1559
1560 assert_eq!(ctxt.bytes(), &head_data[..]);
1561 }
1562
1563 #[test]
1564 fn test_write_hmtx_table() {
1565 let hmtx_data = include_bytes!("../tests/fonts/opentype/hmtx.bin");
1567 let num_glyphs = 1264;
1568 let num_h_metrics = 1264;
1569 let hmtx = ReadScope::new(hmtx_data)
1570 .read_dep::<HmtxTable<'_>>((num_glyphs, num_h_metrics))
1571 .unwrap();
1572
1573 let mut ctxt = WriteBuffer::new();
1574 HmtxTable::write(&mut ctxt, &hmtx).unwrap();
1575
1576 assert_eq!(ctxt.bytes(), &hmtx_data[..]);
1577 }
1578
1579 #[test]
1580 fn test_write_name_table() {
1581 let name = ReadScope::new(NAME_DATA).read::<NameTable<'_>>().unwrap();
1583
1584 let mut ctxt = WriteBuffer::new();
1585 NameTable::write(&mut ctxt, &name).unwrap();
1586
1587 assert_eq!(ctxt.bytes(), &NAME_DATA[..]);
1588 }
1589
1590 #[test]
1591 fn roundtrip_owned_name_table() {
1592 let name = ReadScope::new(NAME_DATA).read::<NameTable<'_>>().unwrap();
1594 let owned = owned::NameTable::try_from(&name).unwrap();
1595
1596 let mut ctxt = WriteBuffer::new();
1597 owned::NameTable::write(&mut ctxt, &owned).unwrap();
1598
1599 assert_eq!(ctxt.bytes(), &NAME_DATA[..]);
1600 }
1601
1602 #[test]
1603 fn f32_from_f2dot14() {
1604 assert_close(f32::from(F2Dot14(0x7fff)), 1.999939);
1606 assert_close(f32::from(F2Dot14(0x7000)), 1.75);
1607 assert_close(f32::from(F2Dot14(0x0001)), 0.000061);
1608 assert_close(f32::from(F2Dot14(0x0000)), 0.0);
1609 assert_close(f32::from(F2Dot14(-1 )), -0.000061);
1610 assert_close(f32::from(F2Dot14(-32768 )), -2.0);
1611 }
1612
1613 #[test]
1614 fn f2dot14_from_f32() {
1615 assert_eq!(F2Dot14::from(1.999939), F2Dot14::from_raw(0x7fff));
1617 assert_eq!(F2Dot14::from(1.75), F2Dot14::from_raw(0x7000));
1618 assert_eq!(F2Dot14::from(0.000061), F2Dot14::from_raw(0x0001));
1619 assert_eq!(F2Dot14::from(0.0), F2Dot14::from_raw(0x0000));
1620 assert_eq!(F2Dot14::from(-0.000061), F2Dot14::from_raw(-1 ));
1621 assert_close!(f32::from(F2Dot14::from(-1.4)), -1.4, 1. / 16384.);
1622 assert_eq!(F2Dot14::from(-2.0), F2Dot14::from_raw(-32768 ));
1623 }
1624
1625 #[test]
1626 fn f2dot14_from_fixed() {
1627 assert_eq!(
1629 F2Dot14::from(Fixed::from(1.999939)),
1630 F2Dot14::from_raw(0x7fff)
1631 );
1632 assert_eq!(F2Dot14::from(Fixed::from(1.75)), F2Dot14::from_raw(0x7000));
1633 assert_eq!(
1634 F2Dot14::from(Fixed::from(0.000061)),
1635 F2Dot14::from_raw(0x0001)
1636 );
1637 assert_eq!(F2Dot14::from(Fixed::from(0.0)), F2Dot14::from_raw(0x0000));
1638 assert_eq!(
1639 F2Dot14::from(Fixed::from(-0.000061)),
1640 F2Dot14::from_raw(-1 )
1641 );
1642 assert_eq!(
1643 F2Dot14::from(Fixed::from(-2.0)),
1644 F2Dot14::from_raw(-32768 )
1645 );
1646 }
1647
1648 #[test]
1649 fn f32_from_fixed() {
1650 assert_close(f32::from(Fixed(0x7fff_0000)), 32767.);
1651 assert_close(f32::from(Fixed(0x7000_0001)), 28672.0001);
1652 assert_close(f32::from(Fixed(0x0001_0000)), 1.0);
1653 assert_close(f32::from(Fixed(0x0000_0000)), 0.0);
1654 assert_close(
1655 f32::from(Fixed(i32::from_be_bytes([0xff; 4]))),
1656 -0.000015259,
1657 );
1658 assert_close(f32::from(Fixed(0x7fff_ffff)), 32768.0);
1659 }
1660
1661 #[test]
1662 fn fixed_from_f32() {
1663 assert_eq!(Fixed::from(32767.0_f32), Fixed(0x7fff_0000));
1664 assert_eq!(Fixed::from(28672.0001_f32), Fixed(0x7000_0000));
1665 assert_eq!(Fixed::from(1.0_f32), Fixed(0x0001_0000));
1666 assert_eq!(Fixed::from(-1.0_f32), Fixed(-65536));
1667 assert_eq!(Fixed::from(0.0_f32), Fixed(0x0000_0000));
1668 assert_eq!(Fixed::from(0.000015259_f32), Fixed(1));
1669 assert_eq!(Fixed::from(32768.0_f32), Fixed(-0x8000_0000));
1670 assert_eq!(Fixed::from(1.23_f32), Fixed(0x0001_3ae1));
1671 assert_close!(f32::from(Fixed::from(-1.4_f32)), -1.4, 1. / 65536.);
1672 }
1673
1674 #[test]
1675 fn fixed_from_i32() {
1676 assert_eq!(Fixed::from(32767), Fixed(0x7fff_0000));
1677 assert_eq!(Fixed::from(28672), Fixed(0x7000_0000));
1678 assert_eq!(Fixed::from(1), Fixed(0x0001_0000));
1679 assert_eq!(Fixed::from(0), Fixed(0x0000_0000));
1680 assert_eq!(Fixed::from(-0), Fixed(0));
1681 assert_eq!(Fixed::from(32768), Fixed(-0x8000_0000));
1682 }
1683
1684 #[test]
1685 fn fixed_from_f2dot14() {
1686 assert_eq!(Fixed::from(F2Dot14::from(0.5)), Fixed(0x0000_8000));
1687 }
1688
1689 #[test]
1690 fn fixed_add() {
1691 assert_eq!(Fixed(10) + Fixed(20), Fixed(30));
1692 assert_fixed_close(Fixed::from(0.1) + Fixed::from(0.2), 0.3);
1693 assert_fixed_close(Fixed::from(-0.1) + Fixed::from(0.4), 0.3);
1694 assert_eq!(Fixed(i32::MAX) + Fixed(1), Fixed(-0x80000000)); }
1696
1697 #[test]
1698 fn fixed_sub() {
1699 assert_eq!(Fixed(10) - Fixed(20), Fixed(-10));
1700 assert_fixed_close(Fixed::from(0.1) - Fixed::from(0.2), -0.1);
1701 assert_fixed_close(Fixed::from(-0.1) - Fixed::from(0.4), -0.5);
1702 assert_eq!(Fixed(i32::MIN) - Fixed(1), Fixed(0x7fffffff)); }
1704
1705 #[test]
1706 fn fixed_mul() {
1707 assert_eq!(Fixed(0x2_0000) * Fixed(0x4_0000), Fixed(0x8_0000));
1708 assert_fixed_close(Fixed::from(0.1) * Fixed::from(0.2), 0.02);
1709 assert_fixed_close(Fixed::from(-0.1) * Fixed::from(0.4), -0.04);
1710 }
1711
1712 #[test]
1713 fn fixed_div() {
1714 assert_eq!(Fixed(0x4_0000) / Fixed(0x2_0000), Fixed(0x2_0000));
1715 assert_fixed_close(Fixed::from(0.1) / Fixed::from(0.2), 0.5);
1716 assert_fixed_close(Fixed::from(-0.1) / Fixed::from(0.4), -0.25);
1717 assert_eq!(Fixed(0x4_0000) / Fixed(0), Fixed(0x7FFFFFFF)); }
1719
1720 #[test]
1721 fn fixed_neg() {
1722 assert_eq!(-Fixed(0x4_0000), Fixed(-0x4_0000));
1723 assert_fixed_close(-Fixed::from(0.1), -0.1);
1724 assert_fixed_close(-Fixed::from(-0.25), 0.25);
1725 assert_eq!(-Fixed(0x7FFFFFFF), Fixed(-0x7FFFFFFF));
1726 }
1727
1728 #[test]
1729 fn fixed_abs() {
1730 assert_fixed_close(Fixed::from(-1.0).abs(), 1.0);
1731 assert_fixed_close(Fixed::from(1.0).abs(), 1.0);
1732 assert_eq!(Fixed(-0x7FFFFFFF).abs(), Fixed(0x7FFFFFFF));
1733 }
1734
1735 #[test]
1736 fn f2dot14_add() {
1737 assert_eq!(Fixed(10) + Fixed(20), Fixed(30));
1738 assert_f2dot14_close(F2Dot14::from(0.1) + F2Dot14::from(0.2), 0.3);
1739 assert_f2dot14_close(F2Dot14::from(-0.1) + F2Dot14::from(0.4), 0.3);
1740 assert_eq!(F2Dot14(i16::MAX) + F2Dot14(1), F2Dot14(-0x8000)); }
1742
1743 #[test]
1744 fn f2dot14_sub() {
1745 assert_eq!(F2Dot14(10) - F2Dot14(20), F2Dot14(-10));
1746 assert_f2dot14_close(F2Dot14::from(0.1) - F2Dot14::from(0.2), -0.1);
1747 assert_f2dot14_close(F2Dot14::from(-0.1) - F2Dot14::from(0.4), -0.5);
1748 assert_eq!(F2Dot14(i16::MIN) - F2Dot14(1), F2Dot14(0x7fff)); }
1750
1751 #[test]
1752 fn f2dot14_mul() {
1753 assert_f2dot14_close(F2Dot14::from(0.1) * F2Dot14::from(0.2), 0.02);
1754 assert_f2dot14_close(F2Dot14::from(-0.1) * F2Dot14::from(0.4), -0.04);
1755 }
1756
1757 #[test]
1758 fn f2dot14_div() {
1759 assert_f2dot14_close(F2Dot14::from(0.1) / F2Dot14::from(0.2), 0.5);
1760 assert_f2dot14_close(F2Dot14::from(-0.1) / F2Dot14::from(0.4), -0.25);
1761 assert_eq!(F2Dot14(0x4_000) / F2Dot14(0), F2Dot14(0x7FFF)); }
1763
1764 #[test]
1765 fn f2dot14_neg() {
1766 assert_eq!(-F2Dot14(0x1_000), F2Dot14(-0x1_000));
1767 assert_f2dot14_close(-F2Dot14::from(0.1), -0.1);
1768 assert_f2dot14_close(-F2Dot14::from(-0.25), 0.25);
1769 assert_eq!(-F2Dot14(0x7FFF), F2Dot14(-0x7FFF));
1770 }
1771
1772 #[test]
1773 fn read_true_magic() {
1774 let buffer = read_fixture("tests/fonts/variable/Zycon.ttf");
1775 let fontfile = ReadScope::new(&buffer)
1776 .read::<OpenTypeFont<'_>>()
1777 .expect("error reading OpenTypeFile");
1778 let offset_table = match fontfile.data {
1779 OpenTypeData::Single(font) => font,
1780 OpenTypeData::Collection(_) => unreachable!(),
1781 };
1782 assert_eq!(offset_table.table_records.len(), 12);
1783 }
1784}