1include!("../../generated/generated_cmap.rs");
4
5#[cfg(feature = "std")]
6use crate::collections::IntSet;
7use crate::{FontRef, TableProvider};
8use std::ops::Range;
9
10const WINDOWS_SYMBOL_ENCODING: u16 = 0;
12const WINDOWS_UNICODE_BMP_ENCODING: u16 = 1;
13const WINDOWS_UNICODE_FULL_ENCODING: u16 = 10;
14
15const UNICODE_1_0_ENCODING: u16 = 0;
17const UNICODE_1_1_ENCODING: u16 = 1;
18const UNICODE_ISO_ENCODING: u16 = 2;
19const UNICODE_2_0_BMP_ENCODING: u16 = 3;
20const UNICODE_2_0_FULL_ENCODING: u16 = 4;
21const UNICODE_FULL_ENCODING: u16 = 6;
22
23#[derive(Copy, Clone, PartialEq, Eq, Debug)]
25pub enum MapVariant {
26 UseDefault,
29 Variant(GlyphId),
32}
33
34impl<'a> Cmap<'a> {
35 pub fn map_codepoint(&self, codepoint: impl Into<u32>) -> Option<GlyphId> {
44 let codepoint = codepoint.into();
45 for record in self.encoding_records() {
46 if let Ok(subtable) = record.subtable(self.offset_data()) {
47 if let Some(gid) = subtable.map_codepoint(codepoint) {
48 return Some(gid);
49 }
50 }
51 }
52 None
53 }
54
55 pub fn best_subtable(&self) -> Option<(u16, EncodingRecord, CmapSubtable<'a>)> {
64 let offset_data = self.offset_data();
67 let records = self.encoding_records();
68 let find = |platform_id, encoding_id| {
69 for (index, record) in records.iter().enumerate() {
70 if record.platform_id() != platform_id || record.encoding_id() != encoding_id {
71 continue;
72 }
73 if let Ok(subtable) = record.subtable(offset_data) {
74 match subtable {
75 CmapSubtable::Format0(_)
76 | CmapSubtable::Format4(_)
77 | CmapSubtable::Format6(_)
78 | CmapSubtable::Format10(_)
79 | CmapSubtable::Format12(_)
80 | CmapSubtable::Format13(_) => {
81 return Some((index as u16, *record, subtable))
82 }
83 _ => {}
84 }
85 }
86 }
87 None
88 };
89 find(PlatformId::Windows, WINDOWS_SYMBOL_ENCODING)
93 .or_else(|| find(PlatformId::Windows, WINDOWS_UNICODE_FULL_ENCODING))
95 .or_else(|| find(PlatformId::Unicode, UNICODE_FULL_ENCODING))
96 .or_else(|| find(PlatformId::Unicode, UNICODE_2_0_FULL_ENCODING))
97 .or_else(|| find(PlatformId::Windows, WINDOWS_UNICODE_BMP_ENCODING))
99 .or_else(|| find(PlatformId::Unicode, UNICODE_2_0_BMP_ENCODING))
100 .or_else(|| find(PlatformId::Unicode, UNICODE_ISO_ENCODING))
101 .or_else(|| find(PlatformId::Unicode, UNICODE_1_1_ENCODING))
102 .or_else(|| find(PlatformId::Unicode, UNICODE_1_0_ENCODING))
103 .or_else(|| find(PlatformId::Macintosh, 0))
105 }
106
107 pub fn uvs_subtable(&self) -> Option<(u16, Cmap14<'a>)> {
113 let offset_data = self.offset_data();
114 for (index, record) in self.encoding_records().iter().enumerate() {
115 if let Ok(CmapSubtable::Format14(cmap14)) = record.subtable(offset_data) {
116 return Some((index as u16, cmap14));
117 };
118 }
119 None
120 }
121
122 pub fn subtable(&self, index: u16) -> Result<CmapSubtable<'a>, ReadError> {
124 self.encoding_records()
125 .get(index as usize)
126 .ok_or(ReadError::OutOfBounds)
127 .and_then(|encoding| encoding.subtable(self.offset_data()))
128 }
129
130 #[cfg(feature = "std")]
131 pub fn closure_glyphs(&self, unicodes: &IntSet<u32>, glyph_set: &mut IntSet<GlyphId>) {
132 for record in self.encoding_records() {
133 if let Ok(subtable) = record.subtable(self.offset_data()) {
134 match subtable {
135 CmapSubtable::Format14(format14) => {
136 format14.closure_glyphs(unicodes, glyph_set);
137 return;
138 }
139 _ => {
140 continue;
141 }
142 }
143 }
144 }
145 }
146}
147
148impl EncodingRecord {
149 pub fn is_symbol(&self) -> bool {
150 self.platform_id() == PlatformId::Windows && self.encoding_id() == WINDOWS_SYMBOL_ENCODING
151 }
152
153 pub fn is_mac_roman(&self) -> bool {
154 self.platform_id() == PlatformId::Macintosh && self.encoding_id() == 0
155 }
156}
157
158impl<'a> CmapSubtable<'a> {
159 pub fn language(&self) -> u32 {
160 match self {
161 Self::Format0(item) => item.language() as u32,
162 Self::Format2(item) => item.language() as u32,
163 Self::Format4(item) => item.language() as u32,
164 Self::Format6(item) => item.language() as u32,
165 Self::Format10(item) => item.language(),
166 Self::Format12(item) => item.language(),
167 Self::Format13(item) => item.language(),
168 _ => 0,
169 }
170 }
171
172 #[inline]
175 pub fn map_codepoint(&self, codepoint: impl Into<u32>) -> Option<GlyphId> {
176 match self {
177 Self::Format0(item) => item.map_codepoint(codepoint),
178 Self::Format4(item) => item.map_codepoint(codepoint),
179 Self::Format6(item) => item.map_codepoint(codepoint),
180 Self::Format10(item) => item.map_codepoint(codepoint),
181 Self::Format12(item) => item.map_codepoint(codepoint),
182 Self::Format13(item) => item.map_codepoint(codepoint),
183 _ => None,
184 }
185 }
186
187 pub fn iter(&self) -> CmapSubtableIter<'a> {
194 let limits = CmapIterLimits {
195 max_char: u32::MAX,
196 glyph_count: u32::MAX,
197 };
198 self.iter_with_limits(limits)
199 }
200
201 pub fn iter_with_limits(&self, limits: CmapIterLimits) -> CmapSubtableIter<'a> {
204 match self {
205 Self::Format4(item) => CmapSubtableIter::Format4(item.iter()),
206 Self::Format6(item) => CmapSubtableIter::Format6(item.iter()),
207 Self::Format10(item) => CmapSubtableIter::Format10(item.iter()),
208 Self::Format12(item) => CmapSubtableIter::Format12(item.iter_with_limits(limits)),
209 Self::Format13(item) => CmapSubtableIter::Format13(item.iter_with_limits(limits)),
210 _ => CmapSubtableIter::None,
211 }
212 }
213}
214
215#[derive(Clone)]
218#[non_exhaustive]
219pub enum CmapSubtableIter<'a> {
220 None,
221 Format4(Cmap4Iter<'a>),
222 Format6(Cmap6Iter<'a>),
223 Format10(Cmap10Iter<'a>),
224 Format12(Cmap12Iter<'a>),
225 Format13(Cmap13Iter<'a>),
226}
227
228impl Iterator for CmapSubtableIter<'_> {
229 type Item = (u32, GlyphId);
230
231 #[inline]
232 fn next(&mut self) -> Option<Self::Item> {
233 match self {
234 Self::None => None,
235 Self::Format4(iter) => iter.next(),
236 Self::Format6(iter) => iter.next(),
237 Self::Format10(iter) => iter.next(),
238 Self::Format12(iter) => iter.next(),
239 Self::Format13(iter) => iter.next(),
240 }
241 }
242}
243
244impl Cmap0<'_> {
245 pub fn map_codepoint(&self, codepoint: impl Into<u32>) -> Option<GlyphId> {
246 let codepoint = codepoint.into();
247
248 self.glyph_id_array()
249 .get(codepoint as usize)
250 .map(|g| GlyphId::new(*g as u32))
251 }
252}
253
254impl<'a> Cmap4<'a> {
255 pub fn map_codepoint(&self, codepoint: impl Into<u32>) -> Option<GlyphId> {
257 let codepoint = codepoint.into();
258 if codepoint > 0xFFFF {
259 return None;
260 }
261 let codepoint = codepoint as u16;
262 let mut lo = 0;
263 let mut hi = self.seg_count_x2() as usize / 2;
264 let start_codes = self.start_code();
265 let end_codes = self.end_code();
266 while lo < hi {
267 let i = (lo + hi) / 2;
268 let start_code = start_codes.get(i)?.get();
269 if codepoint < start_code {
270 hi = i;
271 } else if codepoint > end_codes.get(i)?.get() {
272 lo = i + 1;
273 } else {
274 return self.lookup_glyph_id(codepoint, i, start_code);
275 }
276 }
277 None
278 }
279
280 pub fn iter(&self) -> Cmap4Iter<'a> {
283 Cmap4Iter::new(self.clone())
284 }
285
286 fn lookup_glyph_id(&self, codepoint: u16, index: usize, start_code: u16) -> Option<GlyphId> {
290 let deltas = self.id_delta();
291 let range_offsets = self.id_range_offsets();
292 let delta = deltas.get(index)?.get() as i32;
293 let range_offset = range_offsets.get(index)?.get() as usize;
294 if range_offset == 0 {
295 return Some(GlyphId::from((codepoint as i32 + delta) as u16));
296 }
297 let mut offset = range_offset / 2 + (codepoint - start_code) as usize;
298 offset = offset.saturating_sub(range_offsets.len() - index);
299 let gid = self.glyph_id_array().get(offset)?.get();
300 (gid != 0).then_some(GlyphId::from((gid as i32 + delta) as u16))
301 }
302
303 fn code_range(&self, index: usize) -> Option<Range<u32>> {
305 let start = self.start_code().get(index)?.get() as u32;
308 let end = self.end_code().get(index)?.get() as u32;
309 Some(start..end + 1)
311 }
312}
313
314#[derive(Clone)]
317pub struct Cmap4Iter<'a> {
318 subtable: Cmap4<'a>,
319 cur_range: Range<u32>,
320 cur_start_code: u16,
321 cur_range_ix: usize,
322}
323
324impl<'a> Cmap4Iter<'a> {
325 fn new(subtable: Cmap4<'a>) -> Self {
326 let cur_range = subtable.code_range(0).unwrap_or_default();
327 let cur_start_code = cur_range.start as u16;
328 Self {
329 subtable,
330 cur_range,
331 cur_start_code,
332 cur_range_ix: 0,
333 }
334 }
335}
336
337impl Iterator for Cmap4Iter<'_> {
338 type Item = (u32, GlyphId);
339
340 fn next(&mut self) -> Option<Self::Item> {
341 loop {
342 if let Some(codepoint) = self.cur_range.next() {
343 let Some(glyph_id) = self.subtable.lookup_glyph_id(
344 codepoint as u16,
345 self.cur_range_ix,
346 self.cur_start_code,
347 ) else {
348 continue;
349 };
350 return Some((codepoint, glyph_id));
351 } else {
352 self.cur_range_ix += 1;
353 let next_range = self.subtable.code_range(self.cur_range_ix)?;
354 let start_code = next_range.start as u16;
364 self.cur_range = next_range.start.max(self.cur_range.end)
365 ..next_range.end.max(self.cur_range.end);
366 self.cur_start_code = start_code;
367 }
368 }
369 }
370}
371
372impl<'a> Cmap6<'a> {
373 pub fn map_codepoint(&self, codepoint: impl Into<u32>) -> Option<GlyphId> {
374 let codepoint = codepoint.into();
375
376 let first = self.first_code() as u32;
377 let idx = codepoint.checked_sub(first)?;
378 self.glyph_id_array()
379 .get(idx as usize)
380 .map(|g| GlyphId::new(g.get() as u32))
381 }
382
383 pub fn iter(&self) -> Cmap6Iter<'a> {
386 Cmap6Iter {
387 first: self.first_code() as u32,
388 glyph_ids: self.glyph_id_array(),
389 pos: 0,
390 }
391 }
392}
393
394#[derive(Clone)]
397pub struct Cmap6Iter<'a> {
398 first: u32,
399 glyph_ids: &'a [BigEndian<u16>],
400 pos: u32,
401}
402
403impl Iterator for Cmap6Iter<'_> {
404 type Item = (u32, GlyphId);
405
406 fn next(&mut self) -> Option<Self::Item> {
407 let gid = self.glyph_ids.get(self.pos as usize)?.get().into();
408 let codepoint = self.first + self.pos;
409 self.pos += 1;
410 Some((codepoint, gid))
411 }
412}
413
414impl<'a> Cmap10<'a> {
415 pub fn map_codepoint(&self, codepoint: impl Into<u32>) -> Option<GlyphId> {
416 let codepoint = codepoint.into();
417 let idx = codepoint.checked_sub(self.start_char_code())?;
418 self.glyph_id_array()
419 .get(idx as usize)
420 .map(|g| GlyphId::new(g.get() as u32))
421 }
422
423 pub fn iter(&self) -> Cmap10Iter<'a> {
426 Cmap10Iter {
427 first: self.start_char_code(),
428 glyph_ids: self.glyph_id_array(),
429 pos: 0,
430 }
431 }
432}
433
434#[derive(Clone)]
437pub struct Cmap10Iter<'a> {
438 first: u32,
439 glyph_ids: &'a [BigEndian<u16>],
440 pos: u32,
441}
442
443impl Iterator for Cmap10Iter<'_> {
444 type Item = (u32, GlyphId);
445
446 fn next(&mut self) -> Option<Self::Item> {
447 let gid = self.glyph_ids.get(self.pos as usize)?.get().into();
448 let codepoint = self.first + self.pos;
449 self.pos += 1;
450 Some((codepoint, gid))
451 }
452}
453
454trait AnyMapGroup {
456 const IS_CONSTANT: bool;
457
458 fn start_char_code(&self) -> u32;
459 fn end_char_code(&self) -> u32;
460 fn ref_glyph_id(&self) -> u32;
463
464 fn compute_glyph_id(codepoint: u32, start_char_code: u32, ref_glyph_id: u32) -> GlyphId {
465 if Self::IS_CONSTANT {
466 GlyphId::new(ref_glyph_id)
467 } else {
468 GlyphId::new(ref_glyph_id.wrapping_add(codepoint.wrapping_sub(start_char_code)))
469 }
470 }
471}
472
473impl AnyMapGroup for ConstantMapGroup {
474 const IS_CONSTANT: bool = true;
475
476 fn start_char_code(&self) -> u32 {
477 self.start_char_code()
478 }
479
480 fn end_char_code(&self) -> u32 {
481 self.end_char_code()
482 }
483
484 fn ref_glyph_id(&self) -> u32 {
485 self.glyph_id()
486 }
487}
488
489impl AnyMapGroup for SequentialMapGroup {
490 const IS_CONSTANT: bool = false;
491
492 fn start_char_code(&self) -> u32 {
493 self.start_char_code()
494 }
495
496 fn end_char_code(&self) -> u32 {
497 self.end_char_code()
498 }
499
500 fn ref_glyph_id(&self) -> u32 {
501 self.start_glyph_id()
502 }
503}
504
505fn cmap1213_map_codepoint<T: AnyMapGroup>(
507 groups: &[T],
508 codepoint: impl Into<u32>,
509) -> Option<GlyphId> {
510 let codepoint = codepoint.into();
511 let mut lo = 0;
512 let mut hi = groups.len();
513 while lo < hi {
514 let i = (lo + hi) / 2;
515 let group = groups.get(i)?;
516 if codepoint < group.start_char_code() {
517 hi = i;
518 } else if codepoint > group.end_char_code() {
519 lo = i + 1;
520 } else {
521 return Some(T::compute_glyph_id(
522 codepoint,
523 group.start_char_code(),
524 group.ref_glyph_id(),
525 ));
526 }
527 }
528 None
529}
530
531#[derive(Copy, Clone, Debug)]
533pub struct CmapIterLimits {
534 pub max_char: u32,
536 pub glyph_count: u32,
538}
539
540impl CmapIterLimits {
541 pub fn default_for_font(font: &FontRef) -> Self {
547 let glyph_count = font
548 .maxp()
549 .map(|maxp| maxp.num_glyphs())
550 .unwrap_or(u16::MAX) as u32;
551 Self {
552 max_char: char::MAX as u32,
555 glyph_count,
556 }
557 }
558}
559
560impl Default for CmapIterLimits {
561 fn default() -> Self {
562 Self {
563 max_char: char::MAX as u32,
564 glyph_count: u16::MAX as u32,
566 }
567 }
568}
569
570#[derive(Clone, Debug)]
572struct Cmap1213IterGroup {
573 range: Range<u64>,
574 start_code: u32,
575 ref_glyph_id: u32,
576}
577
578fn cmap1213_iter_group<T: AnyMapGroup>(
580 groups: &[T],
581 index: usize,
582 limits: &Option<CmapIterLimits>,
583) -> Option<Cmap1213IterGroup> {
584 let group = groups.get(index)?;
585 let start_code = group.start_char_code();
586 let end_code = group.end_char_code() as u64 + 1;
589 let start_glyph_id = group.ref_glyph_id();
590 let end_code = if let Some(limits) = limits {
591 if T::IS_CONSTANT {
594 end_code.min(limits.max_char as u64)
595 } else {
596 (limits.glyph_count as u64)
597 .saturating_sub(start_glyph_id as u64)
598 .saturating_add(start_code as u64)
599 .min(end_code.min(limits.max_char as u64))
600 }
601 } else {
602 end_code
603 };
604 Some(Cmap1213IterGroup {
605 range: start_code as u64..end_code,
606 start_code,
607 ref_glyph_id: start_glyph_id,
608 })
609}
610
611#[derive(Clone)]
613struct Cmap1213Iter<'a, T> {
614 groups: &'a [T],
615 cur_group: Option<Cmap1213IterGroup>,
616 cur_group_ix: usize,
617 limits: Option<CmapIterLimits>,
618}
619
620impl<'a, T> Cmap1213Iter<'a, T>
621where
622 T: AnyMapGroup,
623{
624 fn new(groups: &'a [T], limits: Option<CmapIterLimits>) -> Self {
625 let cur_group = cmap1213_iter_group(groups, 0, &limits);
626 Self {
627 groups,
628 cur_group,
629 cur_group_ix: 0,
630 limits,
631 }
632 }
633}
634
635impl<T> Iterator for Cmap1213Iter<'_, T>
636where
637 T: AnyMapGroup,
638{
639 type Item = (u32, GlyphId);
640
641 fn next(&mut self) -> Option<Self::Item> {
642 loop {
643 let group = self.cur_group.as_mut()?;
644 if let Some(codepoint) = group.range.next() {
645 let codepoint = codepoint as u32;
646 let glyph_id = T::compute_glyph_id(codepoint, group.start_code, group.ref_glyph_id);
647 return Some((codepoint, glyph_id));
648 } else {
649 self.cur_group_ix += 1;
650 let mut next_group =
651 cmap1213_iter_group(self.groups, self.cur_group_ix, &self.limits)?;
652 if next_group.range.start < group.range.end {
656 next_group.range.start = group.range.end;
657 }
658 next_group.range.end = next_group.range.end.max(group.range.end);
659 self.cur_group = Some(next_group);
660 }
661 }
662 }
663}
664
665impl<'a> Cmap12<'a> {
666 pub fn map_codepoint(&self, codepoint: impl Into<u32>) -> Option<GlyphId> {
668 cmap1213_map_codepoint(self.groups(), codepoint)
669 }
670
671 pub fn iter(&self) -> Cmap12Iter<'a> {
678 Cmap12Iter::new(self.clone(), None)
679 }
680
681 pub fn iter_with_limits(&self, limits: CmapIterLimits) -> Cmap12Iter<'a> {
684 Cmap12Iter::new(self.clone(), Some(limits))
685 }
686}
687
688#[derive(Clone)]
691pub struct Cmap12Iter<'a>(Cmap1213Iter<'a, SequentialMapGroup>);
692
693impl<'a> Cmap12Iter<'a> {
694 fn new(subtable: Cmap12<'a>, limits: Option<CmapIterLimits>) -> Self {
695 Self(Cmap1213Iter::new(subtable.groups(), limits))
696 }
697}
698
699impl Iterator for Cmap12Iter<'_> {
700 type Item = (u32, GlyphId);
701
702 fn next(&mut self) -> Option<Self::Item> {
703 self.0.next()
704 }
705}
706
707impl<'a> Cmap13<'a> {
708 pub fn map_codepoint(&self, codepoint: impl Into<u32>) -> Option<GlyphId> {
710 cmap1213_map_codepoint(self.groups(), codepoint)
711 }
712
713 pub fn iter(&self) -> Cmap13Iter<'a> {
720 Cmap13Iter::new(self.clone(), None)
721 }
722
723 pub fn iter_with_limits(&self, limits: CmapIterLimits) -> Cmap13Iter<'a> {
726 Cmap13Iter::new(self.clone(), Some(limits))
727 }
728}
729
730#[derive(Clone)]
733pub struct Cmap13Iter<'a>(Cmap1213Iter<'a, ConstantMapGroup>);
734
735impl<'a> Cmap13Iter<'a> {
736 fn new(subtable: Cmap13<'a>, limits: Option<CmapIterLimits>) -> Self {
737 Self(Cmap1213Iter::new(subtable.groups(), limits))
738 }
739}
740
741impl Iterator for Cmap13Iter<'_> {
742 type Item = (u32, GlyphId);
743
744 fn next(&mut self) -> Option<Self::Item> {
745 self.0.next()
746 }
747}
748
749impl<'a> Cmap14<'a> {
750 pub fn map_variant(
752 &self,
753 codepoint: impl Into<u32>,
754 selector: impl Into<u32>,
755 ) -> Option<MapVariant> {
756 let codepoint = codepoint.into();
757 let selector = selector.into();
758 let selector_records = self.var_selector();
759 let selector_record = selector_records
762 .binary_search_by(|rec| {
763 let rec_selector: u32 = rec.var_selector().into();
764 rec_selector.cmp(&selector)
765 })
766 .ok()
767 .and_then(|idx| selector_records.get(idx))?;
768 if let Some(Ok(default_uvs)) = selector_record.default_uvs(self.offset_data()) {
773 use core::cmp::Ordering;
774 let found_default_uvs = default_uvs
775 .ranges()
776 .binary_search_by(|range| {
777 let start = range.start_unicode_value().into();
778 if codepoint < start {
779 Ordering::Greater
780 } else if codepoint > (start + range.additional_count() as u32) {
781 Ordering::Less
782 } else {
783 Ordering::Equal
784 }
785 })
786 .is_ok();
787 if found_default_uvs {
788 return Some(MapVariant::UseDefault);
789 }
790 }
791 let non_default_uvs = selector_record.non_default_uvs(self.offset_data())?.ok()?;
793 let mapping = non_default_uvs.uvs_mapping();
794 let ix = mapping
795 .binary_search_by(|map| {
796 let map_codepoint: u32 = map.unicode_value().into();
797 map_codepoint.cmp(&codepoint)
798 })
799 .ok()?;
800 Some(MapVariant::Variant(GlyphId::from(
801 mapping.get(ix)?.glyph_id(),
802 )))
803 }
804
805 pub fn iter(&self) -> Cmap14Iter<'a> {
808 Cmap14Iter::new(self.clone())
809 }
810
811 fn selector(
812 &self,
813 index: usize,
814 ) -> (
815 Option<VariationSelector>,
816 Option<DefaultUvs<'a>>,
817 Option<NonDefaultUvs<'a>>,
818 ) {
819 let selector = self.var_selector().get(index).cloned();
820 let default_uvs = selector.as_ref().and_then(|selector| {
821 selector
822 .default_uvs(self.offset_data())
823 .transpose()
824 .ok()
825 .flatten()
826 });
827 let non_default_uvs = selector.as_ref().and_then(|selector| {
828 selector
829 .non_default_uvs(self.offset_data())
830 .transpose()
831 .ok()
832 .flatten()
833 });
834 (selector, default_uvs, non_default_uvs)
835 }
836
837 #[cfg(feature = "std")]
838 pub fn closure_glyphs(&self, unicodes: &IntSet<u32>, glyph_set: &mut IntSet<GlyphId>) {
839 for selector in self.var_selector() {
840 if !unicodes.contains(selector.var_selector().to_u32()) {
841 continue;
842 }
843 if let Some(non_default_uvs) = selector
844 .non_default_uvs(self.offset_data())
845 .transpose()
846 .ok()
847 .flatten()
848 {
849 glyph_set.extend(
850 non_default_uvs
851 .uvs_mapping()
852 .iter()
853 .filter(|m| unicodes.contains(m.unicode_value().to_u32()))
854 .map(|m| m.glyph_id().into()),
855 );
856 }
857 }
858 }
859}
860
861#[derive(Clone)]
864pub struct Cmap14Iter<'a> {
865 subtable: Cmap14<'a>,
866 selector_record: Option<VariationSelector>,
867 default_uvs: Option<DefaultUvsIter<'a>>,
868 non_default_uvs: Option<NonDefaultUvsIter<'a>>,
869 cur_selector_ix: usize,
870}
871
872impl<'a> Cmap14Iter<'a> {
873 fn new(subtable: Cmap14<'a>) -> Self {
874 let (selector_record, default_uvs, non_default_uvs) = subtable.selector(0);
875 Self {
876 subtable,
877 selector_record,
878 default_uvs: default_uvs.map(DefaultUvsIter::new),
879 non_default_uvs: non_default_uvs.map(NonDefaultUvsIter::new),
880 cur_selector_ix: 0,
881 }
882 }
883}
884
885impl Iterator for Cmap14Iter<'_> {
886 type Item = (u32, u32, MapVariant);
887
888 fn next(&mut self) -> Option<Self::Item> {
889 loop {
890 let selector_record = self.selector_record.as_ref()?;
891 let selector: u32 = selector_record.var_selector().into();
892 if let Some(default_uvs) = self.default_uvs.as_mut() {
893 if let Some(codepoint) = default_uvs.next() {
894 return Some((codepoint, selector, MapVariant::UseDefault));
895 }
896 }
897 if let Some(non_default_uvs) = self.non_default_uvs.as_mut() {
898 if let Some((codepoint, variant)) = non_default_uvs.next() {
899 return Some((codepoint, selector, MapVariant::Variant(variant.into())));
900 }
901 }
902 self.cur_selector_ix += 1;
903 let (selector_record, default_uvs, non_default_uvs) =
904 self.subtable.selector(self.cur_selector_ix);
905 self.selector_record = selector_record;
906 self.default_uvs = default_uvs.map(DefaultUvsIter::new);
907 self.non_default_uvs = non_default_uvs.map(NonDefaultUvsIter::new);
908 }
909 }
910}
911
912#[derive(Clone)]
913struct DefaultUvsIter<'a> {
914 ranges: std::slice::Iter<'a, UnicodeRange>,
915 cur_range: Range<u32>,
916}
917
918impl<'a> DefaultUvsIter<'a> {
919 fn new(ranges: DefaultUvs<'a>) -> Self {
920 let mut ranges = ranges.ranges().iter();
921 let cur_range = if let Some(range) = ranges.next() {
922 let start: u32 = range.start_unicode_value().into();
923 let end = start + range.additional_count() as u32 + 1;
924 start..end
925 } else {
926 0..0
927 };
928 Self { ranges, cur_range }
929 }
930}
931
932impl Iterator for DefaultUvsIter<'_> {
933 type Item = u32;
934
935 fn next(&mut self) -> Option<Self::Item> {
936 loop {
937 if let Some(codepoint) = self.cur_range.next() {
938 return Some(codepoint);
939 }
940 let range = self.ranges.next()?;
941 let start: u32 = range.start_unicode_value().into();
942 let end = start + range.additional_count() as u32 + 1;
943 self.cur_range = start..end;
944 }
945 }
946}
947
948#[derive(Clone)]
949struct NonDefaultUvsIter<'a> {
950 iter: std::slice::Iter<'a, UvsMapping>,
951}
952
953impl<'a> NonDefaultUvsIter<'a> {
954 fn new(uvs: NonDefaultUvs<'a>) -> Self {
955 Self {
956 iter: uvs.uvs_mapping().iter(),
957 }
958 }
959}
960
961impl Iterator for NonDefaultUvsIter<'_> {
962 type Item = (u32, GlyphId16);
963
964 fn next(&mut self) -> Option<Self::Item> {
965 let mapping = self.iter.next()?;
966 let codepoint: u32 = mapping.unicode_value().into();
967 let glyph_id = GlyphId16::new(mapping.glyph_id());
968 Some((codepoint, glyph_id))
969 }
970}
971
972#[cfg(test)]
973mod tests {
974 use font_test_data::{be_buffer, bebuffer::BeBuffer};
975
976 use super::*;
977 use crate::{FontRef, GlyphId, TableProvider};
978
979 #[test]
980 fn map_codepoints() {
981 let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
982 let cmap = font.cmap().unwrap();
983 assert_eq!(cmap.map_codepoint('A'), Some(GlyphId::new(1)));
984 assert_eq!(cmap.map_codepoint('À'), Some(GlyphId::new(2)));
985 assert_eq!(cmap.map_codepoint('`'), Some(GlyphId::new(3)));
986 assert_eq!(cmap.map_codepoint('B'), None);
987
988 let font = FontRef::new(font_test_data::SIMPLE_GLYF).unwrap();
989 let cmap = font.cmap().unwrap();
990 assert_eq!(cmap.map_codepoint(' '), Some(GlyphId::new(1)));
991 assert_eq!(cmap.map_codepoint(0xE_u32), Some(GlyphId::new(2)));
992 assert_eq!(cmap.map_codepoint('B'), None);
993
994 let cmap0_data = cmap0_data();
995 let cmap = Cmap::read(FontData::new(cmap0_data.data())).unwrap();
996
997 assert_eq!(cmap.map_codepoint(0u8), Some(GlyphId::new(0)));
998 assert_eq!(cmap.map_codepoint(b' '), Some(GlyphId::new(178)));
999 assert_eq!(cmap.map_codepoint(b'r'), Some(GlyphId::new(193)));
1000 assert_eq!(cmap.map_codepoint(b'X'), Some(GlyphId::new(13)));
1001 assert_eq!(cmap.map_codepoint(255u8), Some(GlyphId::new(3)));
1002
1003 let cmap6_data = be_buffer! {
1004 0u16,
1006 1u16,
1008 1u16,
1010 0u16,
1012 12u32,
1014 6u16,
1016 32u16,
1018 0u16,
1020 32u16,
1022 5u16,
1024 [10u16, 15, 7, 20, 4]
1026 };
1027
1028 let cmap = Cmap::read(FontData::new(cmap6_data.data())).unwrap();
1029
1030 assert_eq!(cmap.map_codepoint(0u8), None);
1031 assert_eq!(cmap.map_codepoint(31u8), None);
1032 assert_eq!(cmap.map_codepoint(33u8), Some(GlyphId::new(15)));
1033 assert_eq!(cmap.map_codepoint(35u8), Some(GlyphId::new(20)));
1034 assert_eq!(cmap.map_codepoint(36u8), Some(GlyphId::new(4)));
1035 assert_eq!(cmap.map_codepoint(50u8), None);
1036 }
1037
1038 #[test]
1039 fn map_variants() {
1040 use super::MapVariant::*;
1041 let font = FontRef::new(font_test_data::CMAP14_FONT1).unwrap();
1042 let cmap = font.cmap().unwrap();
1043 let cmap14 = find_cmap14(&cmap).unwrap();
1044 let selector = '\u{e0100}';
1045 assert_eq!(cmap14.map_variant('a', selector), None);
1046 assert_eq!(cmap14.map_variant('\u{4e00}', selector), Some(UseDefault));
1047 assert_eq!(cmap14.map_variant('\u{4e06}', selector), Some(UseDefault));
1048 assert_eq!(
1049 cmap14.map_variant('\u{4e08}', selector),
1050 Some(Variant(GlyphId::new(25)))
1051 );
1052 assert_eq!(
1053 cmap14.map_variant('\u{4e09}', selector),
1054 Some(Variant(GlyphId::new(26)))
1055 );
1056 }
1057
1058 #[test]
1059 #[cfg(feature = "std")]
1060 fn cmap14_closure_glyphs() {
1061 let font = FontRef::new(font_test_data::CMAP14_FONT1).unwrap();
1062 let cmap = font.cmap().unwrap();
1063 let mut unicodes = IntSet::empty();
1064 unicodes.insert(0x4e08_u32);
1065 unicodes.insert(0xe0100_u32);
1066
1067 let mut glyph_set = IntSet::empty();
1068 glyph_set.insert(GlyphId::new(18));
1069 cmap.closure_glyphs(&unicodes, &mut glyph_set);
1070
1071 assert_eq!(glyph_set.len(), 2);
1072 assert!(glyph_set.contains(GlyphId::new(18)));
1073 assert!(glyph_set.contains(GlyphId::new(25)));
1074 }
1075
1076 #[test]
1077 fn cmap4_iter() {
1078 let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
1079 let cmap4 = find_cmap4(&font.cmap().unwrap()).unwrap();
1080 let mut count = 0;
1081 for (codepoint, glyph_id) in cmap4.iter() {
1082 assert_eq!(cmap4.map_codepoint(codepoint), Some(glyph_id));
1083 count += 1;
1084 }
1085 assert_eq!(count, 4);
1086 let font = FontRef::new(font_test_data::SIMPLE_GLYF).unwrap();
1087 let cmap4 = find_cmap4(&font.cmap().unwrap()).unwrap();
1088 let mut count = 0;
1089 for (codepoint, glyph_id) in cmap4.iter() {
1090 assert_eq!(cmap4.map_codepoint(codepoint), Some(glyph_id));
1091 count += 1;
1092 }
1093 assert_eq!(count, 3);
1094 }
1095
1096 #[test]
1097 fn cmap4_iter_explicit_notdef() {
1098 let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
1099 let cmap4 = find_cmap4(&font.cmap().unwrap()).unwrap();
1100 let mut notdef_count = 0;
1101 for (_, glyph_id) in cmap4.iter() {
1102 notdef_count += (glyph_id == GlyphId::NOTDEF) as i32;
1103 }
1104 assert!(notdef_count > 0);
1105 assert_eq!(cmap4.map_codepoint(0xFFFF_u32), Some(GlyphId::NOTDEF));
1106 }
1107
1108 #[test]
1112 fn cmap4_iter_sparse_range() {
1113 #[rustfmt::skip]
1114 let cmap4_data: &[u16] = &[
1115 4, 0, 0,
1117 4,
1119 0, 0, 0,
1121 262, 0xFFFF,
1123 0,
1125 259, 0xFFFF,
1127 0, 1,
1129 4, 0,
1131 236, 0, 0, 326,
1133 ];
1134 let mut buf = BeBuffer::new();
1135 for &word in cmap4_data {
1136 buf = buf.push(word);
1137 }
1138 let cmap4 = Cmap4::read(FontData::new(&buf)).unwrap();
1139 let mappings = cmap4
1140 .iter()
1141 .map(|(ch, gid)| (ch, gid.to_u32()))
1142 .collect::<Vec<_>>();
1143 assert_eq!(mappings, &[(259, 236), (262, 326), (65535, 0)]);
1144 }
1145
1146 #[test]
1153 fn cmap4_iter_overlapping_range_offset_segment() {
1154 #[rustfmt::skip]
1155 let cmap4_data: &[u16] = &[
1156 4, 0, 0,
1158 6,
1160 0, 0, 0,
1162 20, 25, 0xFFFF,
1164 0,
1166 10, 15, 0xFFFF,
1168 0, 0, 1,
1170 0, 8, 0,
1172 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
1174 ];
1175 let mut buf = BeBuffer::new();
1176 for &word in cmap4_data {
1177 buf = buf.push(word);
1178 }
1179 let cmap4 = Cmap4::read(FontData::new(&buf)).unwrap();
1180 let mappings = cmap4
1181 .iter()
1182 .map(|(ch, gid)| (ch, gid.to_u32()))
1183 .collect::<Vec<_>>();
1184
1185 assert_eq!(
1190 mappings,
1191 &[
1192 (10, 10),
1193 (11, 11),
1194 (12, 12),
1195 (13, 13),
1196 (14, 14),
1197 (15, 15),
1198 (16, 16),
1199 (17, 17),
1200 (18, 18),
1201 (19, 19),
1202 (20, 20),
1203 (21, 108),
1204 (22, 109),
1205 (23, 110),
1206 (24, 111),
1207 (25, 112),
1208 (65535, 0),
1209 ]
1210 );
1211 }
1212
1213 const CMAP6_PAIRS: &[(u32, u32)] = &[
1214 (0x1723, 1),
1215 (0x1724, 2),
1216 (0x1725, 3),
1217 (0x1726, 4),
1218 (0x1727, 5),
1219 ];
1220
1221 #[test]
1222 fn cmap6_map() {
1223 let font = FontRef::new(font_test_data::CMAP6).unwrap();
1224 let cmap = font.cmap().unwrap();
1225 let CmapSubtable::Format6(cmap6) = cmap.subtable(0).unwrap() else {
1226 panic!("should be a format 6 subtable");
1227 };
1228 for (ch, gid) in CMAP6_PAIRS {
1229 assert_eq!(cmap6.map_codepoint(*ch).unwrap().to_u32(), *gid);
1230 }
1231 assert!(cmap6.map_codepoint(CMAP6_PAIRS[0].0 - 1).is_none());
1233 assert!(cmap6
1234 .map_codepoint(CMAP6_PAIRS.last().copied().unwrap().0 + 1)
1235 .is_none());
1236 }
1237
1238 #[test]
1239 fn cmap6_iter() {
1240 let font = FontRef::new(font_test_data::CMAP6).unwrap();
1241 let cmap = font.cmap().unwrap();
1242 let CmapSubtable::Format6(cmap6) = cmap.subtable(0).unwrap() else {
1243 panic!("should be a format 6 subtable");
1244 };
1245 let pairs = cmap6
1246 .iter()
1247 .map(|(ch, gid)| (ch, gid.to_u32()))
1248 .collect::<Vec<_>>();
1249 assert_eq!(pairs, CMAP6_PAIRS);
1250 }
1251
1252 const CMAP10_PAIRS: &[(u32, u32)] = &[(0x109423, 26), (0x109424, 27), (0x109425, 32)];
1253
1254 #[test]
1255 fn cmap10_map() {
1256 let font = FontRef::new(font_test_data::CMAP10).unwrap();
1257 let cmap = font.cmap().unwrap();
1258 let CmapSubtable::Format10(cmap10) = cmap.subtable(0).unwrap() else {
1259 panic!("should be a format 10 subtable");
1260 };
1261 for (ch, gid) in CMAP10_PAIRS {
1262 assert_eq!(cmap10.map_codepoint(*ch).unwrap().to_u32(), *gid);
1263 }
1264 assert!(cmap10.map_codepoint(CMAP10_PAIRS[0].0 - 1).is_none());
1266 assert!(cmap10
1267 .map_codepoint(CMAP10_PAIRS.last().copied().unwrap().0 + 1)
1268 .is_none());
1269 }
1270
1271 #[test]
1272 fn cmap10_iter() {
1273 let font = FontRef::new(font_test_data::CMAP10).unwrap();
1274 let cmap = font.cmap().unwrap();
1275 let CmapSubtable::Format10(cmap10) = cmap.subtable(0).unwrap() else {
1276 panic!("should be a format 10 subtable");
1277 };
1278 let pairs = cmap10
1279 .iter()
1280 .map(|(ch, gid)| (ch, gid.to_u32()))
1281 .collect::<Vec<_>>();
1282 assert_eq!(pairs, CMAP10_PAIRS);
1283 }
1284
1285 #[test]
1286 fn cmap12_iter() {
1287 let font = FontRef::new(font_test_data::CMAP12_FONT1).unwrap();
1288 let cmap12 = find_cmap12(&font.cmap().unwrap()).unwrap();
1289 let mut count = 0;
1290 for (codepoint, glyph_id) in cmap12.iter() {
1291 assert_eq!(cmap12.map_codepoint(codepoint), Some(glyph_id));
1292 count += 1;
1293 }
1294 assert_eq!(count, 10);
1295 }
1296
1297 #[test]
1301 fn cmap12_iter_avoid_overflow() {
1302 let data = be_buffer! {
1304 12u16, 0u16, 0u32, 0u32, 2u32, [0xFFFFFFFA_u32, 0xFFFFFFFC, 0], [0xFFFFFFFB_u32, 0xFFFFFFFF, 0] };
1313 let cmap12 = Cmap12::read(data.data().into()).unwrap();
1314 let _ = cmap12.iter().count();
1315 }
1316
1317 #[test]
1321 fn cmap12_iter_avoid_timeout() {
1322 let cmap12_data = be_buffer! {
1324 12u16, 0u16, 0u32, 0u32, 1u32, [170u32, 1330926671, 328960] };
1332 let cmap12 = Cmap12::read(cmap12_data.data().into()).unwrap();
1333 assert!(
1334 cmap12.iter_with_limits(CmapIterLimits::default()).count() <= char::MAX as usize + 1
1335 );
1336 }
1337
1338 #[test]
1341 fn cmap12_iter_avoid_timeout2() {
1342 let cmap12_data = be_buffer! {
1343 12u16, 0u16, 0u32, 0u32, 3u32, [199u32, 16777271, 2],
1350 [262u32, 262, 3],
1351 [268u32, 268, 4]
1352 };
1353 let cmap12 = Cmap12::read(cmap12_data.data().into()).unwrap();
1354 const MAX_GLYPHS: u32 = 8;
1356 let limits = CmapIterLimits {
1357 glyph_count: MAX_GLYPHS,
1358 ..Default::default()
1359 };
1360 assert_eq!(cmap12.iter_with_limits(limits).count(), MAX_GLYPHS as usize);
1361 }
1362
1363 #[test]
1364 fn cmap12_iter_glyph_limit() {
1365 let font = FontRef::new(font_test_data::CMAP12_FONT1).unwrap();
1366 let cmap12 = find_cmap12(&font.cmap().unwrap()).unwrap();
1367 let mut limits = CmapIterLimits::default_for_font(&font);
1368 for glyph_count in 0..=11 {
1371 limits.glyph_count = glyph_count;
1372 assert_eq!(
1373 cmap12.iter_with_limits(limits).count(),
1374 (glyph_count as usize).saturating_sub(1)
1377 );
1378 }
1379 }
1380
1381 #[test]
1382 fn cmap12_iter_range_clamping() {
1383 let data = be_buffer! {
1384 12u16, 0u16, 0u32, 0u32, 2u32, [0u32, 16777215, 0], [255u32, 0xFFFFFFFF, 0] };
1393 let cmap12 = Cmap12::read(data.data().into()).unwrap();
1394 let ranges = cmap12
1395 .groups()
1396 .iter()
1397 .map(|group| (group.start_char_code(), group.end_char_code()))
1398 .collect::<Vec<_>>();
1399 assert_eq!(ranges, &[(0, 16777215), (255, u32::MAX)]);
1401 let limits = CmapIterLimits {
1403 glyph_count: u32::MAX,
1404 ..Default::default()
1405 };
1406 assert!(cmap12.iter_with_limits(limits).count() <= char::MAX as usize + 1);
1407 }
1408
1409 #[test]
1413 fn cmap12_iter_saturated_group_does_not_reset_range() {
1414 let data = be_buffer! {
1415 12u16, 0u16, 0u32, 0u32, 3u32, [10u32, 20, 0],
1422 [15u32, 40, 100],
1423 [18u32, 22, 0]
1424 };
1425 let cmap12 = Cmap12::read(data.data().into()).unwrap();
1426 let limits = CmapIterLimits {
1427 glyph_count: 50,
1428 ..Default::default()
1429 };
1430 let codepoints = cmap12
1431 .iter_with_limits(limits)
1432 .map(|(cp, _)| cp)
1433 .collect::<Vec<_>>();
1434 assert_eq!(codepoints, (10..=22).collect::<Vec<_>>());
1435 }
1436
1437 #[test]
1438 fn cmap12_iter_explicit_notdef() {
1439 let data = be_buffer! {
1440 12u16, 0u16, 0u32, 0u32, 1u32, [0_u32, 1_u32, 0] };
1448 let cmap12 = Cmap12::read(data.data().into()).unwrap();
1449 for (i, (codepoint, glyph_id)) in cmap12.iter().enumerate() {
1450 assert_eq!(codepoint as usize, i);
1451 assert_eq!(glyph_id.to_u32() as usize, i);
1452 }
1453 assert_eq!(cmap12.iter().next().unwrap().1, GlyphId::NOTDEF);
1454 }
1455
1456 fn cmap13_data() -> Vec<u8> {
1457 let data = be_buffer! {
1458 13u16, 0u16, 0u32, 0u32, 2u32, [0u32, 8, 20], [42u32, 46u32, 30] };
1467 data.to_vec()
1468 }
1469
1470 #[test]
1471 fn cmap13_map() {
1472 let data = cmap13_data();
1473 let cmap13 = Cmap13::read(FontData::new(&data)).unwrap();
1474 for ch in 0u32..=8 {
1475 assert_eq!(cmap13.map_codepoint(ch), Some(GlyphId::new(20)));
1476 }
1477 for ch in 9u32..42 {
1478 assert_eq!(cmap13.map_codepoint(ch), None);
1479 }
1480 for ch in 42u32..=46 {
1481 assert_eq!(cmap13.map_codepoint(ch), Some(GlyphId::new(30)));
1482 }
1483 for ch in 47u32..1024 {
1484 assert_eq!(cmap13.map_codepoint(ch), None);
1485 }
1486 }
1487
1488 #[test]
1489 fn cmap13_iter() {
1490 let data = cmap13_data();
1491 let cmap13 = Cmap13::read(FontData::new(&data)).unwrap();
1492 for (ch, gid) in cmap13.iter() {
1493 assert_eq!(cmap13.map_codepoint(ch), Some(gid));
1494 }
1495 }
1496
1497 #[test]
1498 fn cmap14_iter() {
1499 let font = FontRef::new(font_test_data::CMAP14_FONT1).unwrap();
1500 let cmap14 = find_cmap14(&font.cmap().unwrap()).unwrap();
1501 let mut count = 0;
1502 for (codepoint, selector, mapping) in cmap14.iter() {
1503 assert_eq!(cmap14.map_variant(codepoint, selector), Some(mapping));
1504 count += 1;
1505 }
1506 assert_eq!(count, 7);
1507 }
1508
1509 fn find_cmap4<'a>(cmap: &Cmap<'a>) -> Option<Cmap4<'a>> {
1510 cmap.encoding_records()
1511 .iter()
1512 .filter_map(|record| record.subtable(cmap.offset_data()).ok())
1513 .find_map(|subtable| match subtable {
1514 CmapSubtable::Format4(cmap4) => Some(cmap4),
1515 _ => None,
1516 })
1517 }
1518
1519 fn find_cmap12<'a>(cmap: &Cmap<'a>) -> Option<Cmap12<'a>> {
1520 cmap.encoding_records()
1521 .iter()
1522 .filter_map(|record| record.subtable(cmap.offset_data()).ok())
1523 .find_map(|subtable| match subtable {
1524 CmapSubtable::Format12(cmap12) => Some(cmap12),
1525 _ => None,
1526 })
1527 }
1528
1529 fn find_cmap14<'a>(cmap: &Cmap<'a>) -> Option<Cmap14<'a>> {
1530 cmap.encoding_records()
1531 .iter()
1532 .filter_map(|record| record.subtable(cmap.offset_data()).ok())
1533 .find_map(|subtable| match subtable {
1534 CmapSubtable::Format14(cmap14) => Some(cmap14),
1535 _ => None,
1536 })
1537 }
1538
1539 #[test]
1544 fn cmap4_bad_data() {
1545 let buf = font_test_data::cmap::repetitive_cmap4();
1546 let cmap4 = Cmap4::read(FontData::new(buf.as_slice())).unwrap();
1547
1548 assert_eq!(
1550 (6..=64).collect::<Vec<_>>(),
1551 cmap4.iter().map(|(cp, _)| cp).collect::<Vec<_>>()
1552 );
1553 }
1554
1555 fn cmap0_data() -> BeBuffer {
1556 be_buffer! {
1557 0u16,
1559 1u16,
1561 1u16,
1563 0u16,
1565 12u32,
1567 0u16,
1569 274u16,
1571 0u16,
1573 [0u8, 249, 32, 2, 198, 23, 1, 4, 26, 36,
1575 171, 168, 69, 151, 208, 238, 226, 153, 161, 138,
1576 160, 130, 169, 223, 162, 207, 146, 227, 111, 248,
1577 163, 79, 178, 27, 50, 234, 213, 57, 45, 63,
1578 103, 186, 30, 105, 131, 118, 35, 140, 51, 211,
1579 75, 172, 56, 71, 137, 99, 22, 76, 61, 125,
1580 39, 8, 177, 117, 108, 97, 202, 92, 49, 134,
1581 93, 43, 80, 66, 84, 54, 180, 113, 11, 176,
1582 229, 48, 47, 17, 124, 40, 119, 21, 13, 133,
1583 181, 224, 33, 128, 44, 46, 38, 24, 65, 152,
1584 197, 225, 102, 251, 157, 126, 182, 242, 28, 184,
1585 90, 170, 201, 144, 193, 189, 250, 142, 77, 221,
1586 81, 164, 154, 60, 37, 200, 12, 53, 219, 89,
1587 31, 209, 188, 179, 253, 220, 127, 18, 19, 64,
1588 20, 141, 98, 173, 55, 194, 70, 107, 228, 104,
1589 10, 9, 15, 217, 255, 222, 196, 236, 67, 165,
1590 5, 143, 149, 100, 91, 95, 135, 235, 145, 204,
1591 72, 114, 246, 82, 245, 233, 106, 158, 185, 212,
1592 86, 243, 16, 195, 123, 190, 120, 187, 132, 139,
1593 192, 239, 110, 183, 240, 214, 166, 41, 59, 231,
1594 42, 94, 244, 83, 121, 25, 215, 96, 73, 87,
1595 174, 136, 62, 206, 156, 175, 230, 150, 116, 147,
1596 68, 122, 78, 112, 6, 167, 232, 254, 52, 34,
1597 191, 85, 241, 14, 216, 155, 29, 101, 115, 210,
1598 252, 218, 129, 247, 203, 159, 109, 74, 7, 58,
1599 237, 199, 88, 205, 148, 3]
1600 }
1601 }
1602
1603 #[test]
1604 fn best_subtable_full() {
1605 let font = FontRef::new(font_test_data::VORG).unwrap();
1606 let cmap = font.cmap().unwrap();
1607 let (index, record, _) = cmap.best_subtable().unwrap();
1608 assert_eq!(
1609 (index, record.platform_id(), record.encoding_id()),
1610 (3, PlatformId::Windows, WINDOWS_UNICODE_FULL_ENCODING)
1611 );
1612 }
1613
1614 #[test]
1615 fn best_subtable_bmp() {
1616 let font = FontRef::new(font_test_data::CMAP12_FONT1).unwrap();
1617 let cmap = font.cmap().unwrap();
1618 let (index, record, _) = cmap.best_subtable().unwrap();
1619 assert_eq!(
1620 (index, record.platform_id(), record.encoding_id()),
1621 (0, PlatformId::Windows, WINDOWS_UNICODE_BMP_ENCODING)
1622 );
1623 }
1624
1625 #[test]
1626 fn best_subtable_symbol() {
1627 let font = FontRef::new(font_test_data::CMAP4_SYMBOL_PUA).unwrap();
1628 let cmap = font.cmap().unwrap();
1629 let (index, record, _) = cmap.best_subtable().unwrap();
1630 assert!(record.is_symbol());
1631 assert_eq!(
1632 (index, record.platform_id(), record.encoding_id()),
1633 (0, PlatformId::Windows, WINDOWS_SYMBOL_ENCODING)
1634 );
1635 }
1636
1637 #[test]
1638 fn uvs_subtable() {
1639 let font = FontRef::new(font_test_data::CMAP14_FONT1).unwrap();
1640 let cmap = font.cmap().unwrap();
1641 let (index, _) = cmap.uvs_subtable().unwrap();
1642 assert_eq!(index, 0);
1643 }
1644}