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 = group.range.end..next_group.range.end;
657 }
658 self.cur_group = Some(next_group);
659 }
660 }
661 }
662}
663
664impl<'a> Cmap12<'a> {
665 pub fn map_codepoint(&self, codepoint: impl Into<u32>) -> Option<GlyphId> {
667 cmap1213_map_codepoint(self.groups(), codepoint)
668 }
669
670 pub fn iter(&self) -> Cmap12Iter<'a> {
677 Cmap12Iter::new(self.clone(), None)
678 }
679
680 pub fn iter_with_limits(&self, limits: CmapIterLimits) -> Cmap12Iter<'a> {
683 Cmap12Iter::new(self.clone(), Some(limits))
684 }
685}
686
687#[derive(Clone)]
690pub struct Cmap12Iter<'a>(Cmap1213Iter<'a, SequentialMapGroup>);
691
692impl<'a> Cmap12Iter<'a> {
693 fn new(subtable: Cmap12<'a>, limits: Option<CmapIterLimits>) -> Self {
694 Self(Cmap1213Iter::new(subtable.groups(), limits))
695 }
696}
697
698impl Iterator for Cmap12Iter<'_> {
699 type Item = (u32, GlyphId);
700
701 fn next(&mut self) -> Option<Self::Item> {
702 self.0.next()
703 }
704}
705
706impl<'a> Cmap13<'a> {
707 pub fn map_codepoint(&self, codepoint: impl Into<u32>) -> Option<GlyphId> {
709 cmap1213_map_codepoint(self.groups(), codepoint)
710 }
711
712 pub fn iter(&self) -> Cmap13Iter<'a> {
719 Cmap13Iter::new(self.clone(), None)
720 }
721
722 pub fn iter_with_limits(&self, limits: CmapIterLimits) -> Cmap13Iter<'a> {
725 Cmap13Iter::new(self.clone(), Some(limits))
726 }
727}
728
729#[derive(Clone)]
732pub struct Cmap13Iter<'a>(Cmap1213Iter<'a, ConstantMapGroup>);
733
734impl<'a> Cmap13Iter<'a> {
735 fn new(subtable: Cmap13<'a>, limits: Option<CmapIterLimits>) -> Self {
736 Self(Cmap1213Iter::new(subtable.groups(), limits))
737 }
738}
739
740impl Iterator for Cmap13Iter<'_> {
741 type Item = (u32, GlyphId);
742
743 fn next(&mut self) -> Option<Self::Item> {
744 self.0.next()
745 }
746}
747
748impl<'a> Cmap14<'a> {
749 pub fn map_variant(
751 &self,
752 codepoint: impl Into<u32>,
753 selector: impl Into<u32>,
754 ) -> Option<MapVariant> {
755 let codepoint = codepoint.into();
756 let selector = selector.into();
757 let selector_records = self.var_selector();
758 let selector_record = selector_records
761 .binary_search_by(|rec| {
762 let rec_selector: u32 = rec.var_selector().into();
763 rec_selector.cmp(&selector)
764 })
765 .ok()
766 .and_then(|idx| selector_records.get(idx))?;
767 if let Some(Ok(default_uvs)) = selector_record.default_uvs(self.offset_data()) {
772 use core::cmp::Ordering;
773 let found_default_uvs = default_uvs
774 .ranges()
775 .binary_search_by(|range| {
776 let start = range.start_unicode_value().into();
777 if codepoint < start {
778 Ordering::Greater
779 } else if codepoint > (start + range.additional_count() as u32) {
780 Ordering::Less
781 } else {
782 Ordering::Equal
783 }
784 })
785 .is_ok();
786 if found_default_uvs {
787 return Some(MapVariant::UseDefault);
788 }
789 }
790 let non_default_uvs = selector_record.non_default_uvs(self.offset_data())?.ok()?;
792 let mapping = non_default_uvs.uvs_mapping();
793 let ix = mapping
794 .binary_search_by(|map| {
795 let map_codepoint: u32 = map.unicode_value().into();
796 map_codepoint.cmp(&codepoint)
797 })
798 .ok()?;
799 Some(MapVariant::Variant(GlyphId::from(
800 mapping.get(ix)?.glyph_id(),
801 )))
802 }
803
804 pub fn iter(&self) -> Cmap14Iter<'a> {
807 Cmap14Iter::new(self.clone())
808 }
809
810 fn selector(
811 &self,
812 index: usize,
813 ) -> (
814 Option<VariationSelector>,
815 Option<DefaultUvs<'a>>,
816 Option<NonDefaultUvs<'a>>,
817 ) {
818 let selector = self.var_selector().get(index).cloned();
819 let default_uvs = selector.as_ref().and_then(|selector| {
820 selector
821 .default_uvs(self.offset_data())
822 .transpose()
823 .ok()
824 .flatten()
825 });
826 let non_default_uvs = selector.as_ref().and_then(|selector| {
827 selector
828 .non_default_uvs(self.offset_data())
829 .transpose()
830 .ok()
831 .flatten()
832 });
833 (selector, default_uvs, non_default_uvs)
834 }
835
836 #[cfg(feature = "std")]
837 pub fn closure_glyphs(&self, unicodes: &IntSet<u32>, glyph_set: &mut IntSet<GlyphId>) {
838 for selector in self.var_selector() {
839 if !unicodes.contains(selector.var_selector().to_u32()) {
840 continue;
841 }
842 if let Some(non_default_uvs) = selector
843 .non_default_uvs(self.offset_data())
844 .transpose()
845 .ok()
846 .flatten()
847 {
848 glyph_set.extend(
849 non_default_uvs
850 .uvs_mapping()
851 .iter()
852 .filter(|m| unicodes.contains(m.unicode_value().to_u32()))
853 .map(|m| m.glyph_id().into()),
854 );
855 }
856 }
857 }
858}
859
860#[derive(Clone)]
863pub struct Cmap14Iter<'a> {
864 subtable: Cmap14<'a>,
865 selector_record: Option<VariationSelector>,
866 default_uvs: Option<DefaultUvsIter<'a>>,
867 non_default_uvs: Option<NonDefaultUvsIter<'a>>,
868 cur_selector_ix: usize,
869}
870
871impl<'a> Cmap14Iter<'a> {
872 fn new(subtable: Cmap14<'a>) -> Self {
873 let (selector_record, default_uvs, non_default_uvs) = subtable.selector(0);
874 Self {
875 subtable,
876 selector_record,
877 default_uvs: default_uvs.map(DefaultUvsIter::new),
878 non_default_uvs: non_default_uvs.map(NonDefaultUvsIter::new),
879 cur_selector_ix: 0,
880 }
881 }
882}
883
884impl Iterator for Cmap14Iter<'_> {
885 type Item = (u32, u32, MapVariant);
886
887 fn next(&mut self) -> Option<Self::Item> {
888 loop {
889 let selector_record = self.selector_record.as_ref()?;
890 let selector: u32 = selector_record.var_selector().into();
891 if let Some(default_uvs) = self.default_uvs.as_mut() {
892 if let Some(codepoint) = default_uvs.next() {
893 return Some((codepoint, selector, MapVariant::UseDefault));
894 }
895 }
896 if let Some(non_default_uvs) = self.non_default_uvs.as_mut() {
897 if let Some((codepoint, variant)) = non_default_uvs.next() {
898 return Some((codepoint, selector, MapVariant::Variant(variant.into())));
899 }
900 }
901 self.cur_selector_ix += 1;
902 let (selector_record, default_uvs, non_default_uvs) =
903 self.subtable.selector(self.cur_selector_ix);
904 self.selector_record = selector_record;
905 self.default_uvs = default_uvs.map(DefaultUvsIter::new);
906 self.non_default_uvs = non_default_uvs.map(NonDefaultUvsIter::new);
907 }
908 }
909}
910
911#[derive(Clone)]
912struct DefaultUvsIter<'a> {
913 ranges: std::slice::Iter<'a, UnicodeRange>,
914 cur_range: Range<u32>,
915}
916
917impl<'a> DefaultUvsIter<'a> {
918 fn new(ranges: DefaultUvs<'a>) -> Self {
919 let mut ranges = ranges.ranges().iter();
920 let cur_range = if let Some(range) = ranges.next() {
921 let start: u32 = range.start_unicode_value().into();
922 let end = start + range.additional_count() as u32 + 1;
923 start..end
924 } else {
925 0..0
926 };
927 Self { ranges, cur_range }
928 }
929}
930
931impl Iterator for DefaultUvsIter<'_> {
932 type Item = u32;
933
934 fn next(&mut self) -> Option<Self::Item> {
935 loop {
936 if let Some(codepoint) = self.cur_range.next() {
937 return Some(codepoint);
938 }
939 let range = self.ranges.next()?;
940 let start: u32 = range.start_unicode_value().into();
941 let end = start + range.additional_count() as u32 + 1;
942 self.cur_range = start..end;
943 }
944 }
945}
946
947#[derive(Clone)]
948struct NonDefaultUvsIter<'a> {
949 iter: std::slice::Iter<'a, UvsMapping>,
950}
951
952impl<'a> NonDefaultUvsIter<'a> {
953 fn new(uvs: NonDefaultUvs<'a>) -> Self {
954 Self {
955 iter: uvs.uvs_mapping().iter(),
956 }
957 }
958}
959
960impl Iterator for NonDefaultUvsIter<'_> {
961 type Item = (u32, GlyphId16);
962
963 fn next(&mut self) -> Option<Self::Item> {
964 let mapping = self.iter.next()?;
965 let codepoint: u32 = mapping.unicode_value().into();
966 let glyph_id = GlyphId16::new(mapping.glyph_id());
967 Some((codepoint, glyph_id))
968 }
969}
970
971#[cfg(test)]
972mod tests {
973 use font_test_data::{be_buffer, bebuffer::BeBuffer};
974
975 use super::*;
976 use crate::{FontRef, GlyphId, TableProvider};
977
978 #[test]
979 fn map_codepoints() {
980 let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
981 let cmap = font.cmap().unwrap();
982 assert_eq!(cmap.map_codepoint('A'), Some(GlyphId::new(1)));
983 assert_eq!(cmap.map_codepoint('À'), Some(GlyphId::new(2)));
984 assert_eq!(cmap.map_codepoint('`'), Some(GlyphId::new(3)));
985 assert_eq!(cmap.map_codepoint('B'), None);
986
987 let font = FontRef::new(font_test_data::SIMPLE_GLYF).unwrap();
988 let cmap = font.cmap().unwrap();
989 assert_eq!(cmap.map_codepoint(' '), Some(GlyphId::new(1)));
990 assert_eq!(cmap.map_codepoint(0xE_u32), Some(GlyphId::new(2)));
991 assert_eq!(cmap.map_codepoint('B'), None);
992
993 let cmap0_data = cmap0_data();
994 let cmap = Cmap::read(FontData::new(cmap0_data.data())).unwrap();
995
996 assert_eq!(cmap.map_codepoint(0u8), Some(GlyphId::new(0)));
997 assert_eq!(cmap.map_codepoint(b' '), Some(GlyphId::new(178)));
998 assert_eq!(cmap.map_codepoint(b'r'), Some(GlyphId::new(193)));
999 assert_eq!(cmap.map_codepoint(b'X'), Some(GlyphId::new(13)));
1000 assert_eq!(cmap.map_codepoint(255u8), Some(GlyphId::new(3)));
1001
1002 let cmap6_data = be_buffer! {
1003 0u16,
1005 1u16,
1007 1u16,
1009 0u16,
1011 12u32,
1013 6u16,
1015 32u16,
1017 0u16,
1019 32u16,
1021 5u16,
1023 [10u16, 15, 7, 20, 4]
1025 };
1026
1027 let cmap = Cmap::read(FontData::new(cmap6_data.data())).unwrap();
1028
1029 assert_eq!(cmap.map_codepoint(0u8), None);
1030 assert_eq!(cmap.map_codepoint(31u8), None);
1031 assert_eq!(cmap.map_codepoint(33u8), Some(GlyphId::new(15)));
1032 assert_eq!(cmap.map_codepoint(35u8), Some(GlyphId::new(20)));
1033 assert_eq!(cmap.map_codepoint(36u8), Some(GlyphId::new(4)));
1034 assert_eq!(cmap.map_codepoint(50u8), None);
1035 }
1036
1037 #[test]
1038 fn map_variants() {
1039 use super::MapVariant::*;
1040 let font = FontRef::new(font_test_data::CMAP14_FONT1).unwrap();
1041 let cmap = font.cmap().unwrap();
1042 let cmap14 = find_cmap14(&cmap).unwrap();
1043 let selector = '\u{e0100}';
1044 assert_eq!(cmap14.map_variant('a', selector), None);
1045 assert_eq!(cmap14.map_variant('\u{4e00}', selector), Some(UseDefault));
1046 assert_eq!(cmap14.map_variant('\u{4e06}', selector), Some(UseDefault));
1047 assert_eq!(
1048 cmap14.map_variant('\u{4e08}', selector),
1049 Some(Variant(GlyphId::new(25)))
1050 );
1051 assert_eq!(
1052 cmap14.map_variant('\u{4e09}', selector),
1053 Some(Variant(GlyphId::new(26)))
1054 );
1055 }
1056
1057 #[test]
1058 #[cfg(feature = "std")]
1059 fn cmap14_closure_glyphs() {
1060 let font = FontRef::new(font_test_data::CMAP14_FONT1).unwrap();
1061 let cmap = font.cmap().unwrap();
1062 let mut unicodes = IntSet::empty();
1063 unicodes.insert(0x4e08_u32);
1064 unicodes.insert(0xe0100_u32);
1065
1066 let mut glyph_set = IntSet::empty();
1067 glyph_set.insert(GlyphId::new(18));
1068 cmap.closure_glyphs(&unicodes, &mut glyph_set);
1069
1070 assert_eq!(glyph_set.len(), 2);
1071 assert!(glyph_set.contains(GlyphId::new(18)));
1072 assert!(glyph_set.contains(GlyphId::new(25)));
1073 }
1074
1075 #[test]
1076 fn cmap4_iter() {
1077 let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
1078 let cmap4 = find_cmap4(&font.cmap().unwrap()).unwrap();
1079 let mut count = 0;
1080 for (codepoint, glyph_id) in cmap4.iter() {
1081 assert_eq!(cmap4.map_codepoint(codepoint), Some(glyph_id));
1082 count += 1;
1083 }
1084 assert_eq!(count, 4);
1085 let font = FontRef::new(font_test_data::SIMPLE_GLYF).unwrap();
1086 let cmap4 = find_cmap4(&font.cmap().unwrap()).unwrap();
1087 let mut count = 0;
1088 for (codepoint, glyph_id) in cmap4.iter() {
1089 assert_eq!(cmap4.map_codepoint(codepoint), Some(glyph_id));
1090 count += 1;
1091 }
1092 assert_eq!(count, 3);
1093 }
1094
1095 #[test]
1096 fn cmap4_iter_explicit_notdef() {
1097 let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
1098 let cmap4 = find_cmap4(&font.cmap().unwrap()).unwrap();
1099 let mut notdef_count = 0;
1100 for (_, glyph_id) in cmap4.iter() {
1101 notdef_count += (glyph_id == GlyphId::NOTDEF) as i32;
1102 }
1103 assert!(notdef_count > 0);
1104 assert_eq!(cmap4.map_codepoint(0xFFFF_u32), Some(GlyphId::NOTDEF));
1105 }
1106
1107 #[test]
1111 fn cmap4_iter_sparse_range() {
1112 #[rustfmt::skip]
1113 let cmap4_data: &[u16] = &[
1114 4, 0, 0,
1116 4,
1118 0, 0, 0,
1120 262, 0xFFFF,
1122 0,
1124 259, 0xFFFF,
1126 0, 1,
1128 4, 0,
1130 236, 0, 0, 326,
1132 ];
1133 let mut buf = BeBuffer::new();
1134 for &word in cmap4_data {
1135 buf = buf.push(word);
1136 }
1137 let cmap4 = Cmap4::read(FontData::new(&buf)).unwrap();
1138 let mappings = cmap4
1139 .iter()
1140 .map(|(ch, gid)| (ch, gid.to_u32()))
1141 .collect::<Vec<_>>();
1142 assert_eq!(mappings, &[(259, 236), (262, 326), (65535, 0)]);
1143 }
1144
1145 #[test]
1152 fn cmap4_iter_overlapping_range_offset_segment() {
1153 #[rustfmt::skip]
1154 let cmap4_data: &[u16] = &[
1155 4, 0, 0,
1157 6,
1159 0, 0, 0,
1161 20, 25, 0xFFFF,
1163 0,
1165 10, 15, 0xFFFF,
1167 0, 0, 1,
1169 0, 8, 0,
1171 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
1173 ];
1174 let mut buf = BeBuffer::new();
1175 for &word in cmap4_data {
1176 buf = buf.push(word);
1177 }
1178 let cmap4 = Cmap4::read(FontData::new(&buf)).unwrap();
1179 let mappings = cmap4
1180 .iter()
1181 .map(|(ch, gid)| (ch, gid.to_u32()))
1182 .collect::<Vec<_>>();
1183
1184 assert_eq!(
1189 mappings,
1190 &[
1191 (10, 10),
1192 (11, 11),
1193 (12, 12),
1194 (13, 13),
1195 (14, 14),
1196 (15, 15),
1197 (16, 16),
1198 (17, 17),
1199 (18, 18),
1200 (19, 19),
1201 (20, 20),
1202 (21, 108),
1203 (22, 109),
1204 (23, 110),
1205 (24, 111),
1206 (25, 112),
1207 (65535, 0),
1208 ]
1209 );
1210 }
1211
1212 const CMAP6_PAIRS: &[(u32, u32)] = &[
1213 (0x1723, 1),
1214 (0x1724, 2),
1215 (0x1725, 3),
1216 (0x1726, 4),
1217 (0x1727, 5),
1218 ];
1219
1220 #[test]
1221 fn cmap6_map() {
1222 let font = FontRef::new(font_test_data::CMAP6).unwrap();
1223 let cmap = font.cmap().unwrap();
1224 let CmapSubtable::Format6(cmap6) = cmap.subtable(0).unwrap() else {
1225 panic!("should be a format 6 subtable");
1226 };
1227 for (ch, gid) in CMAP6_PAIRS {
1228 assert_eq!(cmap6.map_codepoint(*ch).unwrap().to_u32(), *gid);
1229 }
1230 assert!(cmap6.map_codepoint(CMAP6_PAIRS[0].0 - 1).is_none());
1232 assert!(cmap6
1233 .map_codepoint(CMAP6_PAIRS.last().copied().unwrap().0 + 1)
1234 .is_none());
1235 }
1236
1237 #[test]
1238 fn cmap6_iter() {
1239 let font = FontRef::new(font_test_data::CMAP6).unwrap();
1240 let cmap = font.cmap().unwrap();
1241 let CmapSubtable::Format6(cmap6) = cmap.subtable(0).unwrap() else {
1242 panic!("should be a format 6 subtable");
1243 };
1244 let pairs = cmap6
1245 .iter()
1246 .map(|(ch, gid)| (ch, gid.to_u32()))
1247 .collect::<Vec<_>>();
1248 assert_eq!(pairs, CMAP6_PAIRS);
1249 }
1250
1251 const CMAP10_PAIRS: &[(u32, u32)] = &[(0x109423, 26), (0x109424, 27), (0x109425, 32)];
1252
1253 #[test]
1254 fn cmap10_map() {
1255 let font = FontRef::new(font_test_data::CMAP10).unwrap();
1256 let cmap = font.cmap().unwrap();
1257 let CmapSubtable::Format10(cmap10) = cmap.subtable(0).unwrap() else {
1258 panic!("should be a format 10 subtable");
1259 };
1260 for (ch, gid) in CMAP10_PAIRS {
1261 assert_eq!(cmap10.map_codepoint(*ch).unwrap().to_u32(), *gid);
1262 }
1263 assert!(cmap10.map_codepoint(CMAP10_PAIRS[0].0 - 1).is_none());
1265 assert!(cmap10
1266 .map_codepoint(CMAP10_PAIRS.last().copied().unwrap().0 + 1)
1267 .is_none());
1268 }
1269
1270 #[test]
1271 fn cmap10_iter() {
1272 let font = FontRef::new(font_test_data::CMAP10).unwrap();
1273 let cmap = font.cmap().unwrap();
1274 let CmapSubtable::Format10(cmap10) = cmap.subtable(0).unwrap() else {
1275 panic!("should be a format 10 subtable");
1276 };
1277 let pairs = cmap10
1278 .iter()
1279 .map(|(ch, gid)| (ch, gid.to_u32()))
1280 .collect::<Vec<_>>();
1281 assert_eq!(pairs, CMAP10_PAIRS);
1282 }
1283
1284 #[test]
1285 fn cmap12_iter() {
1286 let font = FontRef::new(font_test_data::CMAP12_FONT1).unwrap();
1287 let cmap12 = find_cmap12(&font.cmap().unwrap()).unwrap();
1288 let mut count = 0;
1289 for (codepoint, glyph_id) in cmap12.iter() {
1290 assert_eq!(cmap12.map_codepoint(codepoint), Some(glyph_id));
1291 count += 1;
1292 }
1293 assert_eq!(count, 10);
1294 }
1295
1296 #[test]
1300 fn cmap12_iter_avoid_overflow() {
1301 let data = be_buffer! {
1303 12u16, 0u16, 0u32, 0u32, 2u32, [0xFFFFFFFA_u32, 0xFFFFFFFC, 0], [0xFFFFFFFB_u32, 0xFFFFFFFF, 0] };
1312 let cmap12 = Cmap12::read(data.data().into()).unwrap();
1313 let _ = cmap12.iter().count();
1314 }
1315
1316 #[test]
1320 fn cmap12_iter_avoid_timeout() {
1321 let cmap12_data = be_buffer! {
1323 12u16, 0u16, 0u32, 0u32, 1u32, [170u32, 1330926671, 328960] };
1331 let cmap12 = Cmap12::read(cmap12_data.data().into()).unwrap();
1332 assert!(
1333 cmap12.iter_with_limits(CmapIterLimits::default()).count() <= char::MAX as usize + 1
1334 );
1335 }
1336
1337 #[test]
1340 fn cmap12_iter_avoid_timeout2() {
1341 let cmap12_data = be_buffer! {
1342 12u16, 0u16, 0u32, 0u32, 3u32, [199u32, 16777271, 2],
1349 [262u32, 262, 3],
1350 [268u32, 268, 4]
1351 };
1352 let cmap12 = Cmap12::read(cmap12_data.data().into()).unwrap();
1353 const MAX_GLYPHS: u32 = 8;
1355 let limits = CmapIterLimits {
1356 glyph_count: MAX_GLYPHS,
1357 ..Default::default()
1358 };
1359 assert_eq!(cmap12.iter_with_limits(limits).count(), MAX_GLYPHS as usize);
1360 }
1361
1362 #[test]
1363 fn cmap12_iter_glyph_limit() {
1364 let font = FontRef::new(font_test_data::CMAP12_FONT1).unwrap();
1365 let cmap12 = find_cmap12(&font.cmap().unwrap()).unwrap();
1366 let mut limits = CmapIterLimits::default_for_font(&font);
1367 for glyph_count in 0..=11 {
1370 limits.glyph_count = glyph_count;
1371 assert_eq!(
1372 cmap12.iter_with_limits(limits).count(),
1373 (glyph_count as usize).saturating_sub(1)
1376 );
1377 }
1378 }
1379
1380 #[test]
1381 fn cmap12_iter_range_clamping() {
1382 let data = be_buffer! {
1383 12u16, 0u16, 0u32, 0u32, 2u32, [0u32, 16777215, 0], [255u32, 0xFFFFFFFF, 0] };
1392 let cmap12 = Cmap12::read(data.data().into()).unwrap();
1393 let ranges = cmap12
1394 .groups()
1395 .iter()
1396 .map(|group| (group.start_char_code(), group.end_char_code()))
1397 .collect::<Vec<_>>();
1398 assert_eq!(ranges, &[(0, 16777215), (255, u32::MAX)]);
1400 let limits = CmapIterLimits {
1402 glyph_count: u32::MAX,
1403 ..Default::default()
1404 };
1405 assert!(cmap12.iter_with_limits(limits).count() <= char::MAX as usize + 1);
1406 }
1407
1408 #[test]
1409 fn cmap12_iter_explicit_notdef() {
1410 let data = be_buffer! {
1411 12u16, 0u16, 0u32, 0u32, 1u32, [0_u32, 1_u32, 0] };
1419 let cmap12 = Cmap12::read(data.data().into()).unwrap();
1420 for (i, (codepoint, glyph_id)) in cmap12.iter().enumerate() {
1421 assert_eq!(codepoint as usize, i);
1422 assert_eq!(glyph_id.to_u32() as usize, i);
1423 }
1424 assert_eq!(cmap12.iter().next().unwrap().1, GlyphId::NOTDEF);
1425 }
1426
1427 fn cmap13_data() -> Vec<u8> {
1428 let data = be_buffer! {
1429 13u16, 0u16, 0u32, 0u32, 2u32, [0u32, 8, 20], [42u32, 46u32, 30] };
1438 data.to_vec()
1439 }
1440
1441 #[test]
1442 fn cmap13_map() {
1443 let data = cmap13_data();
1444 let cmap13 = Cmap13::read(FontData::new(&data)).unwrap();
1445 for ch in 0u32..=8 {
1446 assert_eq!(cmap13.map_codepoint(ch), Some(GlyphId::new(20)));
1447 }
1448 for ch in 9u32..42 {
1449 assert_eq!(cmap13.map_codepoint(ch), None);
1450 }
1451 for ch in 42u32..=46 {
1452 assert_eq!(cmap13.map_codepoint(ch), Some(GlyphId::new(30)));
1453 }
1454 for ch in 47u32..1024 {
1455 assert_eq!(cmap13.map_codepoint(ch), None);
1456 }
1457 }
1458
1459 #[test]
1460 fn cmap13_iter() {
1461 let data = cmap13_data();
1462 let cmap13 = Cmap13::read(FontData::new(&data)).unwrap();
1463 for (ch, gid) in cmap13.iter() {
1464 assert_eq!(cmap13.map_codepoint(ch), Some(gid));
1465 }
1466 }
1467
1468 #[test]
1469 fn cmap14_iter() {
1470 let font = FontRef::new(font_test_data::CMAP14_FONT1).unwrap();
1471 let cmap14 = find_cmap14(&font.cmap().unwrap()).unwrap();
1472 let mut count = 0;
1473 for (codepoint, selector, mapping) in cmap14.iter() {
1474 assert_eq!(cmap14.map_variant(codepoint, selector), Some(mapping));
1475 count += 1;
1476 }
1477 assert_eq!(count, 7);
1478 }
1479
1480 fn find_cmap4<'a>(cmap: &Cmap<'a>) -> Option<Cmap4<'a>> {
1481 cmap.encoding_records()
1482 .iter()
1483 .filter_map(|record| record.subtable(cmap.offset_data()).ok())
1484 .find_map(|subtable| match subtable {
1485 CmapSubtable::Format4(cmap4) => Some(cmap4),
1486 _ => None,
1487 })
1488 }
1489
1490 fn find_cmap12<'a>(cmap: &Cmap<'a>) -> Option<Cmap12<'a>> {
1491 cmap.encoding_records()
1492 .iter()
1493 .filter_map(|record| record.subtable(cmap.offset_data()).ok())
1494 .find_map(|subtable| match subtable {
1495 CmapSubtable::Format12(cmap12) => Some(cmap12),
1496 _ => None,
1497 })
1498 }
1499
1500 fn find_cmap14<'a>(cmap: &Cmap<'a>) -> Option<Cmap14<'a>> {
1501 cmap.encoding_records()
1502 .iter()
1503 .filter_map(|record| record.subtable(cmap.offset_data()).ok())
1504 .find_map(|subtable| match subtable {
1505 CmapSubtable::Format14(cmap14) => Some(cmap14),
1506 _ => None,
1507 })
1508 }
1509
1510 #[test]
1515 fn cmap4_bad_data() {
1516 let buf = font_test_data::cmap::repetitive_cmap4();
1517 let cmap4 = Cmap4::read(FontData::new(buf.as_slice())).unwrap();
1518
1519 assert_eq!(
1521 (6..=64).collect::<Vec<_>>(),
1522 cmap4.iter().map(|(cp, _)| cp).collect::<Vec<_>>()
1523 );
1524 }
1525
1526 fn cmap0_data() -> BeBuffer {
1527 be_buffer! {
1528 0u16,
1530 1u16,
1532 1u16,
1534 0u16,
1536 12u32,
1538 0u16,
1540 274u16,
1542 0u16,
1544 [0u8, 249, 32, 2, 198, 23, 1, 4, 26, 36,
1546 171, 168, 69, 151, 208, 238, 226, 153, 161, 138,
1547 160, 130, 169, 223, 162, 207, 146, 227, 111, 248,
1548 163, 79, 178, 27, 50, 234, 213, 57, 45, 63,
1549 103, 186, 30, 105, 131, 118, 35, 140, 51, 211,
1550 75, 172, 56, 71, 137, 99, 22, 76, 61, 125,
1551 39, 8, 177, 117, 108, 97, 202, 92, 49, 134,
1552 93, 43, 80, 66, 84, 54, 180, 113, 11, 176,
1553 229, 48, 47, 17, 124, 40, 119, 21, 13, 133,
1554 181, 224, 33, 128, 44, 46, 38, 24, 65, 152,
1555 197, 225, 102, 251, 157, 126, 182, 242, 28, 184,
1556 90, 170, 201, 144, 193, 189, 250, 142, 77, 221,
1557 81, 164, 154, 60, 37, 200, 12, 53, 219, 89,
1558 31, 209, 188, 179, 253, 220, 127, 18, 19, 64,
1559 20, 141, 98, 173, 55, 194, 70, 107, 228, 104,
1560 10, 9, 15, 217, 255, 222, 196, 236, 67, 165,
1561 5, 143, 149, 100, 91, 95, 135, 235, 145, 204,
1562 72, 114, 246, 82, 245, 233, 106, 158, 185, 212,
1563 86, 243, 16, 195, 123, 190, 120, 187, 132, 139,
1564 192, 239, 110, 183, 240, 214, 166, 41, 59, 231,
1565 42, 94, 244, 83, 121, 25, 215, 96, 73, 87,
1566 174, 136, 62, 206, 156, 175, 230, 150, 116, 147,
1567 68, 122, 78, 112, 6, 167, 232, 254, 52, 34,
1568 191, 85, 241, 14, 216, 155, 29, 101, 115, 210,
1569 252, 218, 129, 247, 203, 159, 109, 74, 7, 58,
1570 237, 199, 88, 205, 148, 3]
1571 }
1572 }
1573
1574 #[test]
1575 fn best_subtable_full() {
1576 let font = FontRef::new(font_test_data::VORG).unwrap();
1577 let cmap = font.cmap().unwrap();
1578 let (index, record, _) = cmap.best_subtable().unwrap();
1579 assert_eq!(
1580 (index, record.platform_id(), record.encoding_id()),
1581 (3, PlatformId::Windows, WINDOWS_UNICODE_FULL_ENCODING)
1582 );
1583 }
1584
1585 #[test]
1586 fn best_subtable_bmp() {
1587 let font = FontRef::new(font_test_data::CMAP12_FONT1).unwrap();
1588 let cmap = font.cmap().unwrap();
1589 let (index, record, _) = cmap.best_subtable().unwrap();
1590 assert_eq!(
1591 (index, record.platform_id(), record.encoding_id()),
1592 (0, PlatformId::Windows, WINDOWS_UNICODE_BMP_ENCODING)
1593 );
1594 }
1595
1596 #[test]
1597 fn best_subtable_symbol() {
1598 let font = FontRef::new(font_test_data::CMAP4_SYMBOL_PUA).unwrap();
1599 let cmap = font.cmap().unwrap();
1600 let (index, record, _) = cmap.best_subtable().unwrap();
1601 assert!(record.is_symbol());
1602 assert_eq!(
1603 (index, record.platform_id(), record.encoding_id()),
1604 (0, PlatformId::Windows, WINDOWS_SYMBOL_ENCODING)
1605 );
1606 }
1607
1608 #[test]
1609 fn uvs_subtable() {
1610 let font = FontRef::new(font_test_data::CMAP14_FONT1).unwrap();
1611 let cmap = font.cmap().unwrap();
1612 let (index, _) = cmap.uvs_subtable().unwrap();
1613 assert_eq!(index, 0);
1614 }
1615}