1use std::borrow::Cow;
4use std::convert::{self, TryFrom};
5use std::rc::Rc;
6
7use bitflags::bitflags;
8use tinyvec::tiny_vec;
9
10use crate::big5::unicode_to_big5;
11use crate::binary::read::ReadScope;
12use crate::bitmap::cbdt::{self, CBDTTable, CBLCTable};
13use crate::bitmap::sbix::Sbix as SbixTable;
14use crate::bitmap::{BitDepth, BitmapGlyph};
15use crate::error::{ParseError, ShapingError};
16use crate::glyph_info::GlyphNames;
17use crate::gpos::Info;
18use crate::gsub::{Features, GlyphOrigin, RawGlyph, RawGlyphFlags};
19use crate::layout::{new_layout_cache, GDEFTable, LayoutCache, LayoutTable, GPOS, GSUB};
20use crate::macroman::char_to_macroman;
21use crate::scripts::preprocess_text;
22use crate::tables::cmap::{Cmap, CmapSubtable, EncodingId, EncodingRecord, PlatformId};
23use crate::tables::os2::Os2;
24use crate::tables::svg::SvgTable;
25use crate::tables::variable_fonts::fvar::{FvarAxisCount, FvarTable, Tuple, VariationAxisRecord};
26use crate::tables::{FontTableProvider, HeadTable, HheaTable, MaxpTable};
27use crate::unicode::{self, VariationSelector};
28use crate::variations::{AxisNamesError, NamedAxis};
29use crate::{glyph_info, tag, variations};
30use crate::{gpos, gsub, DOTTED_CIRCLE};
31
32#[derive(Copy, Clone, Debug, Eq, PartialEq)]
33pub enum Encoding {
34 Unicode = 1,
35 Symbol = 2,
36 AppleRoman = 3,
37 Big5 = 4,
38}
39
40#[derive(Copy, Clone, Eq, PartialEq, Debug)]
41pub enum OutlineFormat {
42 Glyf,
43 Cff,
44 Svg,
45 None,
46}
47
48enum LazyLoad<T> {
49 NotLoaded,
50 Loaded(Option<T>),
51}
52
53#[derive(Copy, Clone, Eq, PartialEq, Debug)]
54pub enum MatchingPresentation {
55 Required,
56 NotRequired,
57}
58
59struct GlyphCache(Option<(u16, VariationSelector)>);
65
66pub struct Font<T: FontTableProvider> {
68 pub font_table_provider: T,
69 cmap_table: Box<[u8]>,
70 pub maxp_table: MaxpTable,
71 hmtx_table: Box<[u8]>,
72 pub hhea_table: HheaTable,
73 vmtx_table: LazyLoad<Rc<[u8]>>,
74 vhea_table: LazyLoad<Rc<HheaTable>>,
75 cmap_subtable_offset: usize,
76 pub cmap_subtable_encoding: Encoding,
77 gdef_cache: LazyLoad<Rc<GDEFTable>>,
78 gsub_cache: LazyLoad<LayoutCache<GSUB>>,
79 gpos_cache: LazyLoad<LayoutCache<GPOS>>,
80 os2_us_first_char_index: LazyLoad<u16>,
81 glyph_cache: GlyphCache,
82 pub glyph_table_flags: GlyphTableFlags,
83 embedded_image_filter: GlyphTableFlags,
84 embedded_images: LazyLoad<Rc<Images>>,
85 axis_count: u16,
86}
87
88pub enum Images {
89 Embedded {
90 cblc: tables::CBLC,
91 cbdt: tables::CBDT,
92 },
93 Sbix(tables::Sbix),
94 Svg(tables::Svg),
95}
96
97mod tables {
98 use super::*;
99 use ouroboros::self_referencing;
100
101 #[self_referencing(pub_extras)]
102 pub struct CBLC {
103 data: Box<[u8]>,
104 #[borrows(data)]
105 #[not_covariant]
106 pub(crate) table: CBLCTable<'this>,
107 }
108
109 #[self_referencing(pub_extras)]
110 pub struct CBDT {
111 data: Box<[u8]>,
112 #[borrows(data)]
113 #[covariant]
114 pub(crate) table: CBDTTable<'this>,
115 }
116
117 #[self_referencing(pub_extras)]
118 pub struct Sbix {
119 data: Box<[u8]>,
120 #[borrows(data)]
121 #[not_covariant]
122 pub(crate) table: SbixTable<'this>,
123 }
124
125 #[self_referencing(pub_extras)]
126 pub struct Svg {
127 data: Box<[u8]>,
128 #[borrows(data)]
129 #[not_covariant]
130 pub(crate) table: SvgTable<'this>,
131 }
132}
133
134bitflags! {
135 pub struct GlyphTableFlags: u8 {
136 const GLYF = 1 << 0;
137 const CFF = 1 << 1;
138 const SVG = 1 << 2;
139 const SBIX = 1 << 3;
140 const CBDT = 1 << 4;
141 const EBDT = 1 << 5;
142 const CFF2 = 1 << 6;
143 }
144}
145
146const TABLE_TAG_FLAGS: &[(u32, GlyphTableFlags)] = &[
147 (tag::GLYF, GlyphTableFlags::GLYF),
148 (tag::CFF, GlyphTableFlags::CFF),
149 (tag::CFF2, GlyphTableFlags::CFF2),
150 (tag::SVG, GlyphTableFlags::SVG),
151 (tag::SBIX, GlyphTableFlags::SBIX),
152 (tag::CBDT, GlyphTableFlags::CBDT),
153 (tag::EBDT, GlyphTableFlags::EBDT),
154];
155
156impl<T: FontTableProvider> Font<T> {
157 pub fn new(provider: T) -> Result<Font<T>, ParseError> {
162 let cmap_table = read_and_box_table(&provider, tag::CMAP)?;
163
164 match charmap_info(&cmap_table)? {
165 Some((cmap_subtable_encoding, cmap_subtable_offset)) => {
166 let maxp_table =
167 ReadScope::new(&provider.read_table_data(tag::MAXP)?).read::<MaxpTable>()?;
168 let hmtx_table = read_and_box_table(&provider, tag::HMTX)?;
169 let hhea_table =
170 ReadScope::new(&provider.read_table_data(tag::HHEA)?).read::<HheaTable>()?;
171 let fvar_data = provider.table_data(tag::FVAR)?;
172 let fvar_axis_count = fvar_data
173 .as_deref()
174 .map(|data| ReadScope::new(data).read::<FvarAxisCount>())
175 .transpose()?
176 .unwrap_or(0);
177
178 let embedded_image_filter =
179 GlyphTableFlags::SVG | GlyphTableFlags::SBIX | GlyphTableFlags::CBDT;
180 let mut glyph_table_flags = GlyphTableFlags::empty();
181 for &(table, flag) in TABLE_TAG_FLAGS {
182 if provider.has_table(table) {
183 glyph_table_flags |= flag
184 }
185 }
186
187 Ok(Font {
188 font_table_provider: provider,
189 cmap_table,
190 maxp_table,
191 hmtx_table,
192 hhea_table,
193 vmtx_table: LazyLoad::NotLoaded,
194 vhea_table: LazyLoad::NotLoaded,
195 cmap_subtable_offset: usize::try_from(cmap_subtable_offset)?,
196 cmap_subtable_encoding,
197 gdef_cache: LazyLoad::NotLoaded,
198 gsub_cache: LazyLoad::NotLoaded,
199 gpos_cache: LazyLoad::NotLoaded,
200 os2_us_first_char_index: LazyLoad::NotLoaded,
201 glyph_cache: GlyphCache::new(),
202 glyph_table_flags,
203 embedded_image_filter,
204 embedded_images: LazyLoad::NotLoaded,
205 axis_count: fvar_axis_count,
206 })
207 }
208 None => Err(ParseError::UnsuitableCmap),
209 }
210 }
211
212 pub fn num_glyphs(&self) -> u16 {
214 self.maxp_table.num_glyphs
215 }
216
217 pub fn set_embedded_image_filter(&mut self, flags: GlyphTableFlags) {
225 self.embedded_image_filter = flags;
226 }
227
228 pub fn lookup_glyph_index(
230 &mut self,
231 ch: char,
232 match_presentation: MatchingPresentation,
233 variation_selector: Option<VariationSelector>,
234 ) -> (u16, VariationSelector) {
235 self.glyph_cache.get(ch).unwrap_or_else(|| {
236 let (glyph_index, used_variation) =
237 self.map_unicode_to_glyph(ch, match_presentation, variation_selector);
238 self.glyph_cache.put(ch, glyph_index, used_variation);
239 (glyph_index, used_variation)
240 })
241 }
242
243 pub fn shape(
308 &mut self,
309 mut glyphs: Vec<RawGlyph<()>>,
310 script_tag: u32,
311 opt_lang_tag: Option<u32>,
312 features: &Features,
313 tuple: Option<Tuple<'_>>,
314 kerning: bool,
315 ) -> Result<Vec<Info>, (ShapingError, Vec<Info>)> {
316 let mut err: Option<ShapingError> = None;
319 let opt_gsub_cache = check_set_err(self.gsub_cache(), &mut err);
320 let opt_gpos_cache = check_set_err(self.gpos_cache(), &mut err);
321 let opt_gdef_table = check_set_err(self.gdef_table(), &mut err);
322 let opt_gdef_table = opt_gdef_table.as_ref().map(Rc::as_ref);
323 let (dotted_circle_index, _) =
324 self.lookup_glyph_index(DOTTED_CIRCLE, MatchingPresentation::NotRequired, None);
325
326 let num_glyphs = self.num_glyphs();
328 if let Some(gsub_cache) = opt_gsub_cache {
329 let res = gsub::apply(
330 dotted_circle_index,
331 &gsub_cache,
332 opt_gdef_table,
333 script_tag,
334 opt_lang_tag,
335 features,
336 tuple,
337 num_glyphs,
338 &mut glyphs,
339 );
340 check_set_err(res, &mut err);
341 }
342
343 let mut infos = Info::init_from_glyphs(opt_gdef_table, glyphs);
345 if let Some(gpos_cache) = opt_gpos_cache {
346 let res = gpos::apply(
347 &gpos_cache,
348 opt_gdef_table,
349 kerning,
350 features,
351 tuple,
352 script_tag,
353 opt_lang_tag,
354 &mut infos,
355 );
356 check_set_err(res, &mut err);
357 } else {
358 gpos::apply_fallback(&mut infos);
359 }
360
361 match err {
362 Some(err) => Err((err, infos)),
363 None => Ok(infos),
364 }
365 }
366
367 pub fn map_glyphs(
380 &mut self,
381 text: &str,
382 script_tag: u32,
383 match_presentation: MatchingPresentation,
384 ) -> Vec<RawGlyph<()>> {
385 let mut chars = text.chars().collect();
386 preprocess_text(&mut chars, script_tag);
387
388 let mut glyphs = Vec::with_capacity(chars.len());
392 let mut chars_iter = chars.into_iter().peekable();
393 while let Some(ch) = chars_iter.next() {
394 match VariationSelector::try_from(ch) {
395 Ok(_) => {} Err(()) => {
397 let vs = chars_iter
398 .peek()
399 .and_then(|&next| VariationSelector::try_from(next).ok());
400 let (glyph_index, used_variation) =
401 self.lookup_glyph_index(ch, match_presentation, vs);
402 let glyph = RawGlyph {
403 unicodes: tiny_vec![[char; 1] => ch],
404 glyph_index,
405 liga_component_pos: 0,
406 glyph_origin: GlyphOrigin::Char(ch),
407 flags: RawGlyphFlags::empty(),
408 extra_data: (),
409 variation: Some(used_variation),
410 };
411 glyphs.push(glyph);
412 }
413 }
414 }
415 glyphs.shrink_to_fit();
416 glyphs
417 }
418
419 pub fn is_variable(&self) -> bool {
421 self.axis_count > 0
422 }
423
424 pub fn variation_axes(&self) -> Result<Vec<VariationAxisRecord>, ParseError> {
425 let table = self.font_table_provider.read_table_data(tag::FVAR)?;
426 let fvar = ReadScope::new(&table).read::<FvarTable<'_>>()?;
427 Ok(fvar.axes().collect())
428 }
429
430 fn map_glyph(&self, char_code: u32) -> u16 {
431 match ReadScope::new(self.cmap_subtable_data()).read::<CmapSubtable<'_>>() {
432 Ok(cmap_subtable) => match cmap_subtable.map_glyph(char_code) {
434 Ok(Some(glyph_index)) => glyph_index,
435 _ => 0,
436 },
437 Err(_err) => 0,
438 }
439 }
440
441 fn map_unicode_to_glyph(
442 &mut self,
443 ch: char,
444 match_presentation: MatchingPresentation,
445 variation_selector: Option<VariationSelector>,
446 ) -> (u16, VariationSelector) {
447 let used_selector = Self::resolve_default_presentation(ch, variation_selector);
448 let glyph_index = match self.cmap_subtable_encoding {
449 Encoding::Unicode => {
450 self.lookup_glyph_index_with_variation(ch as u32, match_presentation, used_selector)
451 }
452 Encoding::Symbol => {
453 let char_code = self.legacy_symbol_char_code(ch);
454 self.lookup_glyph_index_with_variation(char_code, match_presentation, used_selector)
455 }
456 Encoding::AppleRoman => match char_to_macroman(ch) {
457 Some(char_code) => self.lookup_glyph_index_with_variation(
458 u32::from(char_code),
459 match_presentation,
460 used_selector,
461 ),
462 None => {
463 let char_code = self.legacy_symbol_char_code(ch);
464 self.lookup_glyph_index_with_variation(
465 char_code,
466 match_presentation,
467 used_selector,
468 )
469 }
470 },
471 Encoding::Big5 => match unicode_to_big5(ch) {
472 Some(char_code) => self.lookup_glyph_index_with_variation(
473 u32::from(char_code),
474 match_presentation,
475 used_selector,
476 ),
477 None => 0,
478 },
479 };
480 (glyph_index, used_selector)
481 }
482
483 fn legacy_symbol_char_code(&mut self, ch: char) -> u32 {
492 let char_code0 = if ch < '\u{F000}' || ch > '\u{F0FF}' {
493 ch as u32
494 } else {
495 ch as u32 - 0xF000
496 };
497 let provider = &self.font_table_provider;
498 let first_char = if let Ok(Some(us_first_char_index)) =
499 self.os2_us_first_char_index.get_or_load(|| {
500 load_os2_table(provider)?
501 .map(|os2| Ok(os2.us_first_char_index))
502 .transpose()
503 }) {
504 u32::from(us_first_char_index)
505 } else {
506 0x20
507 };
508 (char_code0 + first_char) - 0x20 }
510
511 fn lookup_glyph_index_with_variation(
512 &mut self,
513 char_code: u32,
514 match_presentation: MatchingPresentation,
515 variation_selector: VariationSelector,
516 ) -> u16 {
517 if match_presentation == MatchingPresentation::Required {
518 if (variation_selector == VariationSelector::VS16 && self.has_embedded_images())
523 || (variation_selector == VariationSelector::VS15 && self.has_glyph_outlines())
524 {
525 self.map_glyph(char_code)
526 } else {
527 0
528 }
529 } else {
530 self.map_glyph(char_code)
531 }
532 }
533
534 fn resolve_default_presentation(
535 ch: char,
536 variation_selector: Option<VariationSelector>,
537 ) -> VariationSelector {
538 variation_selector.unwrap_or_else(|| {
539 if unicode::bool_prop_emoji_presentation(ch) {
541 VariationSelector::VS16
542 } else {
543 VariationSelector::VS15
544 }
545 })
546 }
547
548 pub fn glyph_names<'a>(&self, ids: &[u16]) -> Vec<Cow<'a, str>> {
549 let post = read_and_box_optional_table(&self.font_table_provider, tag::POST)
550 .ok()
551 .and_then(convert::identity);
552 let cmap = ReadScope::new(self.cmap_subtable_data())
553 .read::<CmapSubtable<'_>>()
554 .ok()
555 .map(|table| (self.cmap_subtable_encoding, table));
556 let glyph_namer = GlyphNames::new(&cmap, post);
557 glyph_namer.unique_glyph_names(ids)
558 }
559
560 pub fn axis_names<'a>(&self) -> Result<Vec<NamedAxis<'a>>, AxisNamesError> {
562 variations::axis_names(&self.font_table_provider)
563 }
564
565 pub fn lookup_glyph_image(
573 &mut self,
574 glyph_index: u16,
575 target_ppem: u16,
576 max_bit_depth: BitDepth,
577 ) -> Result<Option<BitmapGlyph>, ParseError> {
578 let embedded_bitmaps = match self.embedded_images()? {
579 Some(embedded_bitmaps) => embedded_bitmaps,
580 None => return Ok(None),
581 };
582 match embedded_bitmaps.as_ref() {
583 Images::Embedded { cblc, cbdt } => cblc.with_table(|cblc: &CBLCTable<'_>| {
584 let target_ppem = if target_ppem > u16::from(std::u8::MAX) {
585 std::u8::MAX
586 } else {
587 target_ppem as u8
588 };
589 let bitmap = match cblc.find_strike(glyph_index, target_ppem, max_bit_depth) {
590 Some(matching_strike) => {
591 let cbdt = cbdt.borrow_table();
592 cbdt::lookup(glyph_index, &matching_strike, cbdt)?.map(|bitmap| {
593 BitmapGlyph::try_from((&matching_strike.bitmap_size.inner, bitmap))
594 })
595 }
596 None => None,
597 };
598 bitmap.transpose()
599 }),
600 Images::Sbix(sbix) => {
601 self.lookup_sbix_glyph_bitmap(sbix, false, glyph_index, target_ppem, max_bit_depth)
602 }
603 Images::Svg(svg) => self.lookup_svg_glyph(svg, glyph_index),
604 }
605 }
606
607 fn lookup_sbix_glyph_bitmap(
612 &self,
613 sbix: &tables::Sbix,
614 dupe: bool,
615 glyph_index: u16,
616 target_ppem: u16,
617 max_bit_depth: BitDepth,
618 ) -> Result<Option<BitmapGlyph>, ParseError> {
619 sbix.with_table(|sbix_table: &SbixTable<'_>| {
620 match sbix_table.find_strike(glyph_index, target_ppem, max_bit_depth) {
621 Some(strike) => {
622 match strike.read_glyph(glyph_index)? {
623 Some(ref glyph) if glyph.graphic_type == tag::DUPE => {
624 if dupe {
629 Ok(None)
631 } else {
632 let dupe_glyph_index =
634 ReadScope::new(glyph.data).ctxt().read_u16be()?;
635 self.lookup_sbix_glyph_bitmap(
636 sbix,
637 true,
638 dupe_glyph_index,
639 target_ppem,
640 max_bit_depth,
641 )
642 }
643 }
644 Some(glyph) => Ok(Some(BitmapGlyph::from((strike, &glyph)))),
645 None => Ok(None),
646 }
647 }
648 None => Ok(None),
649 }
650 })
651 }
652
653 fn lookup_svg_glyph(
654 &self,
655 svg: &tables::Svg,
656 glyph_index: u16,
657 ) -> Result<Option<BitmapGlyph>, ParseError> {
658 svg.with_table(
659 |svg_table: &SvgTable<'_>| match svg_table.lookup_glyph(glyph_index)? {
660 Some(svg_record) => BitmapGlyph::try_from(&svg_record).map(Some),
661 None => Ok(None),
662 },
663 )
664 }
665
666 fn embedded_images(&mut self) -> Result<Option<Rc<Images>>, ParseError> {
667 let provider = &self.font_table_provider;
668 let num_glyphs = usize::from(self.maxp_table.num_glyphs);
669 let tables_to_check = self.glyph_table_flags & self.embedded_image_filter;
670 self.embedded_images.get_or_load(|| {
671 if tables_to_check.contains(GlyphTableFlags::SVG) {
672 let images = load_svg(provider).map(Images::Svg)?;
673 Ok(Some(Rc::new(images)))
674 } else if tables_to_check.contains(GlyphTableFlags::CBDT) {
675 let images = load_cblc_cbdt(provider, tag::CBLC, tag::CBDT)
676 .map(|(cblc, cbdt)| Images::Embedded { cblc, cbdt })?;
677 Ok(Some(Rc::new(images)))
678 } else if tables_to_check.contains(GlyphTableFlags::SBIX) {
679 let images = load_sbix(provider, num_glyphs).map(Images::Sbix)?;
680 Ok(Some(Rc::new(images)))
681 } else if tables_to_check.contains(GlyphTableFlags::EBDT) {
682 let images =
683 load_cblc_cbdt(provider, tag::EBLC, tag::EBDT).map(|(eblc, ebdt)| {
684 Images::Embedded {
685 cblc: eblc,
686 cbdt: ebdt,
687 }
688 })?;
689 Ok(Some(Rc::new(images)))
690 } else {
691 Ok(None)
692 }
693 })
694 }
695
696 pub fn has_embedded_images(&mut self) -> bool {
701 matches!(self.embedded_images(), Ok(Some(_)))
702 }
703
704 pub fn has_glyph_outlines(&self) -> bool {
708 self.glyph_table_flags
709 .intersects(GlyphTableFlags::GLYF | GlyphTableFlags::CFF | GlyphTableFlags::CFF2)
710 }
711
712 pub fn horizontal_advance(&mut self, glyph: u16) -> Option<u16> {
717 glyph_info::advance(&self.maxp_table, &self.hhea_table, &self.hmtx_table, glyph).ok()
718 }
719
720 pub fn vertical_advance(&mut self, glyph: u16) -> Option<u16> {
721 let provider = &self.font_table_provider;
722 let vmtx = self
723 .vmtx_table
724 .get_or_load(|| {
725 read_and_box_optional_table(provider, tag::VMTX).map(|ok| ok.map(Rc::from))
726 })
727 .ok()?;
728 let vhea = self.vhea_table().ok()?;
729
730 if let (Some(vhea), Some(vmtx_table)) = (vhea, vmtx) {
731 Some(glyph_info::advance(&self.maxp_table, &vhea, &vmtx_table, glyph).unwrap())
732 } else {
733 None
734 }
735 }
736
737 pub fn head_table(&self) -> Result<Option<HeadTable>, ParseError> {
738 self.font_table_provider
739 .table_data(tag::HEAD)?
740 .map(|data| ReadScope::new(&data).read::<HeadTable>())
741 .transpose()
742 }
743
744 pub fn os2_table(&self) -> Result<Option<Os2>, ParseError> {
745 load_os2_table(&self.font_table_provider)
746 }
747
748 pub fn gdef_table(&mut self) -> Result<Option<Rc<GDEFTable>>, ParseError> {
749 let provider = &self.font_table_provider;
750 self.gdef_cache.get_or_load(|| {
751 if let Some(gdef_data) = provider.table_data(tag::GDEF)? {
752 let gdef = ReadScope::new(&gdef_data).read::<GDEFTable>()?;
753 Ok(Some(Rc::new(gdef)))
754 } else {
755 Ok(None)
756 }
757 })
758 }
759
760 pub fn gsub_cache(&mut self) -> Result<Option<LayoutCache<GSUB>>, ParseError> {
761 let provider = &self.font_table_provider;
762 self.gsub_cache.get_or_load(|| {
763 if let Some(gsub_data) = provider.table_data(tag::GSUB)? {
764 let gsub = ReadScope::new(&gsub_data).read::<LayoutTable<GSUB>>()?;
765 let cache = new_layout_cache::<GSUB>(gsub);
766 Ok(Some(cache))
767 } else {
768 Ok(None)
769 }
770 })
771 }
772
773 pub fn gpos_cache(&mut self) -> Result<Option<LayoutCache<GPOS>>, ParseError> {
774 let provider = &self.font_table_provider;
775 self.gpos_cache.get_or_load(|| {
776 if let Some(gpos_data) = provider.table_data(tag::GPOS)? {
777 let gpos = ReadScope::new(&gpos_data).read::<LayoutTable<GPOS>>()?;
778 let cache = new_layout_cache::<GPOS>(gpos);
779 Ok(Some(cache))
780 } else {
781 Ok(None)
782 }
783 })
784 }
785
786 pub fn vhea_table(&mut self) -> Result<Option<Rc<HheaTable>>, ParseError> {
787 let provider = &self.font_table_provider;
788 self.vhea_table.get_or_load(|| {
789 if let Some(vhea_data) = provider.table_data(tag::VHEA)? {
790 let vhea = ReadScope::new(&vhea_data).read::<HheaTable>()?;
791 Ok(Some(Rc::new(vhea)))
792 } else {
793 Ok(None)
794 }
795 })
796 }
797
798 pub fn cmap_subtable_data(&self) -> &[u8] {
799 &self.cmap_table[self.cmap_subtable_offset..]
800 }
801}
802
803impl<T> LazyLoad<T> {
804 fn get_or_load(
809 &mut self,
810 do_load: impl FnOnce() -> Result<Option<T>, ParseError>,
811 ) -> Result<Option<T>, ParseError>
812 where
813 T: Clone,
814 {
815 match self {
816 LazyLoad::Loaded(Some(ref data)) => Ok(Some(data.clone())),
817 LazyLoad::Loaded(None) => Ok(None),
818 LazyLoad::NotLoaded => {
819 let data = do_load()?;
820 *self = LazyLoad::Loaded(data.clone());
821 Ok(data)
822 }
823 }
824 }
825}
826
827impl GlyphCache {
828 fn new() -> Self {
829 GlyphCache(None)
830 }
831
832 fn get(&self, ch: char) -> Option<(u16, VariationSelector)> {
833 if ch == DOTTED_CIRCLE {
834 self.0
835 } else {
836 None
837 }
838 }
839
840 fn put(&mut self, ch: char, glyph_index: u16, variation_selector: VariationSelector) {
841 if ch == DOTTED_CIRCLE {
842 match self.0 {
843 Some(_) => panic!("duplicate entry"),
844 None => self.0 = Some((glyph_index, variation_selector)),
845 }
846 }
847 }
848}
849
850fn read_and_box_table(
851 provider: &impl FontTableProvider,
852 tag: u32,
853) -> Result<Box<[u8]>, ParseError> {
854 provider
855 .read_table_data(tag)
856 .map(|table| Box::from(table.into_owned()))
857}
858
859fn read_and_box_optional_table(
860 provider: &impl FontTableProvider,
861 tag: u32,
862) -> Result<Option<Box<[u8]>>, ParseError> {
863 Ok(provider
864 .table_data(tag)?
865 .map(|table| Box::from(table.into_owned())))
866}
867
868fn load_os2_table(provider: &impl FontTableProvider) -> Result<Option<Os2>, ParseError> {
869 provider
870 .table_data(tag::OS_2)?
871 .map(|data| ReadScope::new(&data).read_dep::<Os2>(data.len()))
872 .transpose()
873}
874
875fn load_cblc_cbdt(
876 provider: &impl FontTableProvider,
877 bitmap_location_table_tag: u32,
878 bitmap_data_table_tag: u32,
879) -> Result<(tables::CBLC, tables::CBDT), ParseError> {
880 let cblc_data = read_and_box_table(provider, bitmap_location_table_tag)?;
881 let cbdt_data = read_and_box_table(provider, bitmap_data_table_tag)?;
882
883 let cblc = tables::CBLC::try_new(cblc_data, |data| {
884 ReadScope::new(data).read::<CBLCTable<'_>>()
885 })?;
886 let cbdt = tables::CBDT::try_new(cbdt_data, |data| {
887 ReadScope::new(data).read::<CBDTTable<'_>>()
888 })?;
889
890 Ok((cblc, cbdt))
891}
892
893fn load_sbix(
894 provider: &impl FontTableProvider,
895 num_glyphs: usize,
896) -> Result<tables::Sbix, ParseError> {
897 let sbix_data = read_and_box_table(provider, tag::SBIX)?;
898 tables::Sbix::try_new(sbix_data, |data| {
899 ReadScope::new(data).read_dep::<SbixTable<'_>>(num_glyphs)
900 })
901}
902
903fn load_svg(provider: &impl FontTableProvider) -> Result<tables::Svg, ParseError> {
904 let svg_data = read_and_box_table(provider, tag::SVG)?;
905 tables::Svg::try_new(svg_data, |data| ReadScope::new(data).read::<SvgTable<'_>>())
906}
907
908fn charmap_info(cmap_buf: &[u8]) -> Result<Option<(Encoding, u32)>, ParseError> {
909 let cmap = ReadScope::new(cmap_buf).read::<Cmap<'_>>()?;
910 Ok(find_good_cmap_subtable(&cmap)
911 .map(|(encoding, encoding_record)| (encoding, encoding_record.offset)))
912}
913
914pub fn read_cmap_subtable<'a>(
915 cmap: &Cmap<'a>,
916) -> Result<Option<(Encoding, CmapSubtable<'a>)>, ParseError> {
917 if let Some((encoding, encoding_record)) = find_good_cmap_subtable(cmap) {
918 let subtable = cmap
919 .scope
920 .offset(usize::try_from(encoding_record.offset)?)
921 .read::<CmapSubtable<'_>>()?;
922 Ok(Some((encoding, subtable)))
923 } else {
924 Ok(None)
925 }
926}
927
928pub fn find_good_cmap_subtable(cmap: &Cmap<'_>) -> Option<(Encoding, EncodingRecord)> {
929 if let Some(encoding_record) =
931 cmap.find_subtable(PlatformId::WINDOWS, EncodingId::WINDOWS_UNICODE_UCS4)
932 {
933 return Some((Encoding::Unicode, encoding_record));
934 }
935
936 if let Some(encoding_record) =
938 cmap.find_subtable(PlatformId::WINDOWS, EncodingId::WINDOWS_UNICODE_BMP_UCS2)
939 {
940 return Some((Encoding::Unicode, encoding_record));
941 }
942
943 if let Some(encoding_record) =
945 cmap.find_subtable(PlatformId::UNICODE, EncodingId::MACINTOSH_UNICODE_UCS4)
946 {
947 return Some((Encoding::Unicode, encoding_record));
948 }
949
950 if let Some(encoding_record) = cmap.find_subtable_for_platform(PlatformId::UNICODE) {
952 return Some((Encoding::Unicode, encoding_record));
953 }
954
955 if let Some(encoding_record) =
957 cmap.find_subtable(PlatformId::WINDOWS, EncodingId::WINDOWS_SYMBOL)
958 {
959 return Some((Encoding::Symbol, encoding_record));
960 }
961
962 if let Some(encoding_record) =
964 cmap.find_subtable(PlatformId::MACINTOSH, EncodingId::MACINTOSH_APPLE_ROMAN)
965 {
966 return Some((Encoding::AppleRoman, encoding_record));
967 }
968
969 if let Some(encoding_record) = cmap.find_subtable(PlatformId::WINDOWS, EncodingId::WINDOWS_BIG5)
971 {
972 return Some((Encoding::Big5, encoding_record));
973 }
974
975 None
976}
977
978fn check_set_err<T, E>(res: Result<T, E>, err: &mut Option<ShapingError>) -> T
981where
982 E: Into<ShapingError>,
983 T: Default,
984{
985 match res {
986 Ok(table) => table,
987 Err(e) => {
988 if err.is_none() {
989 *err = Some(e.into())
990 }
991 T::default()
992 }
993 }
994}
995
996#[cfg(test)]
997mod tests {
998 use super::*;
999 use crate::bitmap::{Bitmap, EncapsulatedBitmap};
1000 use crate::font_data::{DynamicFontTableProvider, FontData};
1001 use crate::tables::OpenTypeFont;
1002 use crate::tests::read_fixture;
1003 use std::error::Error;
1004
1005 #[test]
1006 fn test_glyph_names() {
1007 let font_buffer = read_fixture("tests/fonts/opentype/TwitterColorEmoji-SVGinOT.ttf");
1008 let opentype_file = ReadScope::new(&font_buffer)
1009 .read::<OpenTypeFont<'_>>()
1010 .unwrap();
1011 let font_table_provider = opentype_file
1012 .table_provider(0)
1013 .expect("error reading font file");
1014 let font = Font::new(Box::new(font_table_provider)).expect("error reading font data");
1015
1016 let names = font.glyph_names(&[0, 5, 45, 71, 1311, 3086]);
1017 assert_eq!(
1018 names,
1019 &[
1020 Cow::from(".notdef"),
1021 Cow::from("copyright"),
1022 Cow::from("uni25B6"),
1023 Cow::from("smileface"),
1024 Cow::from("u1FA95"),
1025 Cow::from("1f468-200d-1f33e")
1026 ]
1027 );
1028 }
1029
1030 #[test]
1031 fn test_glyph_names_post_v3() {
1032 let font_buffer = read_fixture("tests/fonts/opentype/Klei.otf");
1034 let opentype_file = ReadScope::new(&font_buffer)
1035 .read::<OpenTypeFont<'_>>()
1036 .unwrap();
1037 let font_table_provider = opentype_file
1038 .table_provider(0)
1039 .expect("error reading font file");
1040 let font = Font::new(Box::new(font_table_provider)).expect("error reading font data");
1041
1042 let names = font.glyph_names(&[0, 5, 45, 100, 763, 1000 ]);
1043 assert_eq!(
1044 names,
1045 &[
1046 Cow::from(".notdef"),
1047 Cow::from("dollar"),
1048 Cow::from("L"),
1049 Cow::from("yen"),
1050 Cow::from("uniFB00"),
1051 Cow::from("g1000") ]
1053 );
1054 }
1055
1056 #[test]
1057 fn test_lookup_sbix() {
1058 let font_buffer = read_fixture("tests/fonts/sbix/sbix-dupe.ttf");
1059 let opentype_file = ReadScope::new(&font_buffer)
1060 .read::<OpenTypeFont<'_>>()
1061 .unwrap();
1062 let font_table_provider = opentype_file
1063 .table_provider(0)
1064 .expect("error reading font file");
1065 let mut font = Font::new(Box::new(font_table_provider)).expect("error reading font data");
1066
1067 match font.lookup_glyph_image(1, 100, BitDepth::ThirtyTwo) {
1069 Ok(Some(BitmapGlyph {
1070 bitmap: Bitmap::Encapsulated(EncapsulatedBitmap { data, .. }),
1071 ..
1072 })) => {
1073 assert_eq!(data.len(), 224);
1074 }
1075 _ => panic!("Expected encapsulated bitmap, got something else."),
1076 }
1077
1078 match font.lookup_glyph_image(2, 100, BitDepth::ThirtyTwo) {
1081 Ok(Some(BitmapGlyph {
1082 bitmap: Bitmap::Encapsulated(EncapsulatedBitmap { data, .. }),
1083 ..
1084 })) => {
1085 assert_eq!(data.len(), 224);
1086 }
1087 _ => panic!("Expected encapsulated bitmap, got something else."),
1088 }
1089
1090 match font.lookup_glyph_image(3, 100, BitDepth::ThirtyTwo) {
1093 Ok(None) => {}
1094 _ => panic!("Expected Ok(None) got something else"),
1095 }
1096 }
1097
1098 #[test]
1101 fn table_provider_independent_of_font() {
1102 fn load_font<'a>(
1104 scope: ReadScope<'a>,
1105 ) -> Result<Font<DynamicFontTableProvider<'a>>, Box<dyn Error>> {
1106 let font_file = scope.read::<FontData<'_>>()?;
1107 let provider = font_file.table_provider(0)?;
1108 Font::new(provider).map_err(Box::from)
1109 }
1110
1111 let buffer =
1112 std::fs::read("tests/fonts/opentype/Klei.otf").expect("unable to read Klei.otf");
1113 let scope = ReadScope::new(&buffer);
1114 assert!(load_font(scope).is_ok());
1115 }
1116}