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> {
730 Cmap13Iter::new(self.clone(), Some(limits))
731 }
732}
733
734#[derive(Clone)]
737pub struct Cmap13Iter<'a>(Cmap1213Iter<'a, ConstantMapGroup>);
738
739impl<'a> Cmap13Iter<'a> {
740 fn new(subtable: Cmap13<'a>, limits: Option<CmapIterLimits>) -> Self {
741 Self(Cmap1213Iter::new(subtable.groups(), limits))
742 }
743}
744
745impl Iterator for Cmap13Iter<'_> {
746 type Item = (u32, GlyphId);
747
748 fn next(&mut self) -> Option<Self::Item> {
749 self.0.next()
750 }
751}
752
753impl<'a> Cmap14<'a> {
754 pub fn map_variant(
756 &self,
757 codepoint: impl Into<u32>,
758 selector: impl Into<u32>,
759 ) -> Option<MapVariant> {
760 let codepoint = codepoint.into();
761 let selector = selector.into();
762 let selector_records = self.var_selector();
763 let selector_record = selector_records
766 .binary_search_by(|rec| {
767 let rec_selector: u32 = rec.var_selector().into();
768 rec_selector.cmp(&selector)
769 })
770 .ok()
771 .and_then(|idx| selector_records.get(idx))?;
772 if let Some(Ok(default_uvs)) = selector_record.default_uvs(self.offset_data()) {
777 use core::cmp::Ordering;
778 let found_default_uvs = default_uvs
779 .ranges()
780 .binary_search_by(|range| {
781 let start = range.start_unicode_value().into();
782 if codepoint < start {
783 Ordering::Greater
784 } else if codepoint > (start + range.additional_count() as u32) {
785 Ordering::Less
786 } else {
787 Ordering::Equal
788 }
789 })
790 .is_ok();
791 if found_default_uvs {
792 return Some(MapVariant::UseDefault);
793 }
794 }
795 let non_default_uvs = selector_record.non_default_uvs(self.offset_data())?.ok()?;
797 let mapping = non_default_uvs.uvs_mapping();
798 let ix = mapping
799 .binary_search_by(|map| {
800 let map_codepoint: u32 = map.unicode_value().into();
801 map_codepoint.cmp(&codepoint)
802 })
803 .ok()?;
804 Some(MapVariant::Variant(GlyphId::from(
805 mapping.get(ix)?.glyph_id(),
806 )))
807 }
808
809 pub fn iter(&self) -> Cmap14Iter<'a> {
816 Cmap14Iter::new(self.clone(), None)
817 }
818
819 pub fn iter_with_limits(&self, limits: CmapIterLimits) -> Cmap14Iter<'a> {
822 Cmap14Iter::new(self.clone(), Some(limits))
823 }
824
825 #[cfg(feature = "std")]
826 pub fn closure_glyphs(&self, unicodes: &IntSet<u32>, glyph_set: &mut IntSet<GlyphId>) {
827 for selector in self.var_selector() {
828 if !unicodes.contains(selector.var_selector().to_u32()) {
829 continue;
830 }
831 if let Some(non_default_uvs) = selector
832 .non_default_uvs(self.offset_data())
833 .transpose()
834 .ok()
835 .flatten()
836 {
837 glyph_set.extend(
838 non_default_uvs
839 .uvs_mapping()
840 .iter()
841 .filter(|m| unicodes.contains(m.unicode_value().to_u32()))
842 .map(|m| m.glyph_id().into()),
843 );
844 }
845 }
846 }
847}
848
849#[derive(Clone)]
852pub struct Cmap14Iter<'a> {
853 offset_data: FontData<'a>,
854 records: core::slice::Iter<'a, VariationSelector>,
855 cur_selector: Option<u32>,
856 default_uvs: Option<DefaultUvsIter<'a>>,
857 non_default_uvs: Option<NonDefaultUvsIter<'a>>,
858 default_uv_left: u32,
859 non_default_uv_left: u32,
860}
861
862impl<'a> Cmap14Iter<'a> {
863 fn new(subtable: Cmap14<'a>, limits: Option<CmapIterLimits>) -> Self {
864 let (default_uv_left, non_default_uv_left) = if let Some(limits) = limits {
865 (limits.max_char.saturating_add(1), limits.glyph_count)
866 } else {
867 (u32::MAX, u32::MAX)
868 };
869 Self {
870 offset_data: subtable.offset_data(),
871 records: subtable.var_selector().iter(),
872 cur_selector: None,
873 default_uvs: None,
874 non_default_uvs: None,
875 default_uv_left,
876 non_default_uv_left,
877 }
878 }
879
880 fn advance_selector(&mut self) -> Option<u32> {
881 loop {
882 let record = self.records.next()?;
883 let selector = record.var_selector().to_u32();
884 if let Some(cur_selector) = self.cur_selector {
891 if selector <= cur_selector {
892 continue;
893 }
894 }
895 self.cur_selector = Some(selector);
896 self.default_uvs = record
897 .default_uvs(self.offset_data)
898 .transpose()
899 .ok()
900 .flatten()
901 .map(DefaultUvsIter::new);
902 self.non_default_uvs = record
903 .non_default_uvs(self.offset_data)
904 .transpose()
905 .ok()
906 .flatten()
907 .map(NonDefaultUvsIter::new);
908 return Some(selector);
909 }
910 }
911}
912
913impl Iterator for Cmap14Iter<'_> {
914 type Item = (u32, u32, MapVariant);
915
916 fn next(&mut self) -> Option<Self::Item> {
917 loop {
918 let selector = if let Some(selector) = self.cur_selector {
919 selector
920 } else {
921 self.advance_selector()?
922 };
923 if let Some(default_uvs) = self.default_uvs.as_mut() {
924 if let Some(codepoint) = default_uvs.next() {
925 self.default_uv_left = self.default_uv_left.checked_sub(1)?;
926 return Some((codepoint, selector, MapVariant::UseDefault));
927 }
928 }
929 if let Some(non_default_uvs) = self.non_default_uvs.as_mut() {
930 if let Some((codepoint, variant)) = non_default_uvs.next() {
931 self.non_default_uv_left = self.non_default_uv_left.checked_sub(1)?;
932 return Some((codepoint, selector, MapVariant::Variant(variant.into())));
933 }
934 }
935 self.advance_selector()?;
936 }
937 }
938}
939
940#[derive(Clone)]
941struct DefaultUvsIter<'a> {
942 ranges: std::slice::Iter<'a, UnicodeRange>,
943 cur_range: Range<u32>,
944}
945
946impl<'a> DefaultUvsIter<'a> {
947 fn new(ranges: DefaultUvs<'a>) -> Self {
948 let mut ranges = ranges.ranges().iter();
949 let cur_range = if let Some(range) = ranges.next() {
950 let start: u32 = range.start_unicode_value().into();
951 let end = start + range.additional_count() as u32 + 1;
952 start..end
953 } else {
954 0..0
955 };
956 Self { ranges, cur_range }
957 }
958}
959
960impl Iterator for DefaultUvsIter<'_> {
961 type Item = u32;
962
963 fn next(&mut self) -> Option<Self::Item> {
964 loop {
965 if let Some(codepoint) = self.cur_range.next() {
966 return Some(codepoint);
967 }
968 let range = self.ranges.next()?;
969 let start: u32 = range.start_unicode_value().into();
970 let end = start + range.additional_count() as u32 + 1;
971 self.cur_range = start..end;
972 }
973 }
974}
975
976#[derive(Clone)]
977struct NonDefaultUvsIter<'a> {
978 iter: std::slice::Iter<'a, UvsMapping>,
979}
980
981impl<'a> NonDefaultUvsIter<'a> {
982 fn new(uvs: NonDefaultUvs<'a>) -> Self {
983 Self {
984 iter: uvs.uvs_mapping().iter(),
985 }
986 }
987}
988
989impl Iterator for NonDefaultUvsIter<'_> {
990 type Item = (u32, GlyphId16);
991
992 fn next(&mut self) -> Option<Self::Item> {
993 let mapping = self.iter.next()?;
994 let codepoint: u32 = mapping.unicode_value().into();
995 let glyph_id = GlyphId16::new(mapping.glyph_id());
996 Some((codepoint, glyph_id))
997 }
998}
999
1000#[cfg(test)]
1001mod tests {
1002 use super::*;
1003 use crate::{types::Uint24, FontRef, GlyphId, TableProvider};
1004 use font_test_data::{be_buffer, bebuffer::BeBuffer};
1005
1006 #[test]
1007 fn map_codepoints() {
1008 let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
1009 let cmap = font.cmap().unwrap();
1010 assert_eq!(cmap.map_codepoint('A'), Some(GlyphId::new(1)));
1011 assert_eq!(cmap.map_codepoint('À'), Some(GlyphId::new(2)));
1012 assert_eq!(cmap.map_codepoint('`'), Some(GlyphId::new(3)));
1013 assert_eq!(cmap.map_codepoint('B'), None);
1014
1015 let font = FontRef::new(font_test_data::SIMPLE_GLYF).unwrap();
1016 let cmap = font.cmap().unwrap();
1017 assert_eq!(cmap.map_codepoint(' '), Some(GlyphId::new(1)));
1018 assert_eq!(cmap.map_codepoint(0xE_u32), Some(GlyphId::new(2)));
1019 assert_eq!(cmap.map_codepoint('B'), None);
1020
1021 let cmap0_data = cmap0_data();
1022 let cmap = Cmap::read(FontData::new(cmap0_data.data())).unwrap();
1023
1024 assert_eq!(cmap.map_codepoint(0u8), Some(GlyphId::new(0)));
1025 assert_eq!(cmap.map_codepoint(b' '), Some(GlyphId::new(178)));
1026 assert_eq!(cmap.map_codepoint(b'r'), Some(GlyphId::new(193)));
1027 assert_eq!(cmap.map_codepoint(b'X'), Some(GlyphId::new(13)));
1028 assert_eq!(cmap.map_codepoint(255u8), Some(GlyphId::new(3)));
1029
1030 let cmap6_data = be_buffer! {
1031 0u16,
1033 1u16,
1035 1u16,
1037 0u16,
1039 12u32,
1041 6u16,
1043 32u16,
1045 0u16,
1047 32u16,
1049 5u16,
1051 [10u16, 15, 7, 20, 4]
1053 };
1054
1055 let cmap = Cmap::read(FontData::new(cmap6_data.data())).unwrap();
1056
1057 assert_eq!(cmap.map_codepoint(0u8), None);
1058 assert_eq!(cmap.map_codepoint(31u8), None);
1059 assert_eq!(cmap.map_codepoint(33u8), Some(GlyphId::new(15)));
1060 assert_eq!(cmap.map_codepoint(35u8), Some(GlyphId::new(20)));
1061 assert_eq!(cmap.map_codepoint(36u8), Some(GlyphId::new(4)));
1062 assert_eq!(cmap.map_codepoint(50u8), None);
1063 }
1064
1065 #[test]
1066 fn map_variants() {
1067 use super::MapVariant::*;
1068 let font = FontRef::new(font_test_data::CMAP14_FONT1).unwrap();
1069 let cmap = font.cmap().unwrap();
1070 let cmap14 = find_cmap14(&cmap).unwrap();
1071 let selector = '\u{e0100}';
1072 assert_eq!(cmap14.map_variant('a', selector), None);
1073 assert_eq!(cmap14.map_variant('\u{4e00}', selector), Some(UseDefault));
1074 assert_eq!(cmap14.map_variant('\u{4e06}', selector), Some(UseDefault));
1075 assert_eq!(
1076 cmap14.map_variant('\u{4e08}', selector),
1077 Some(Variant(GlyphId::new(25)))
1078 );
1079 assert_eq!(
1080 cmap14.map_variant('\u{4e09}', selector),
1081 Some(Variant(GlyphId::new(26)))
1082 );
1083 }
1084
1085 #[test]
1086 #[cfg(feature = "std")]
1087 fn cmap14_closure_glyphs() {
1088 let font = FontRef::new(font_test_data::CMAP14_FONT1).unwrap();
1089 let cmap = font.cmap().unwrap();
1090 let mut unicodes = IntSet::empty();
1091 unicodes.insert(0x4e08_u32);
1092 unicodes.insert(0xe0100_u32);
1093
1094 let mut glyph_set = IntSet::empty();
1095 glyph_set.insert(GlyphId::new(18));
1096 cmap.closure_glyphs(&unicodes, &mut glyph_set);
1097
1098 assert_eq!(glyph_set.len(), 2);
1099 assert!(glyph_set.contains(GlyphId::new(18)));
1100 assert!(glyph_set.contains(GlyphId::new(25)));
1101 }
1102
1103 #[test]
1104 fn cmap4_iter() {
1105 let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
1106 let cmap4 = find_cmap4(&font.cmap().unwrap()).unwrap();
1107 let mut count = 0;
1108 for (codepoint, glyph_id) in cmap4.iter() {
1109 assert_eq!(cmap4.map_codepoint(codepoint), Some(glyph_id));
1110 count += 1;
1111 }
1112 assert_eq!(count, 4);
1113 let font = FontRef::new(font_test_data::SIMPLE_GLYF).unwrap();
1114 let cmap4 = find_cmap4(&font.cmap().unwrap()).unwrap();
1115 let mut count = 0;
1116 for (codepoint, glyph_id) in cmap4.iter() {
1117 assert_eq!(cmap4.map_codepoint(codepoint), Some(glyph_id));
1118 count += 1;
1119 }
1120 assert_eq!(count, 3);
1121 }
1122
1123 #[test]
1124 fn cmap4_iter_explicit_notdef() {
1125 let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
1126 let cmap4 = find_cmap4(&font.cmap().unwrap()).unwrap();
1127 let mut notdef_count = 0;
1128 for (_, glyph_id) in cmap4.iter() {
1129 notdef_count += (glyph_id == GlyphId::NOTDEF) as i32;
1130 }
1131 assert!(notdef_count > 0);
1132 assert_eq!(cmap4.map_codepoint(0xFFFF_u32), Some(GlyphId::NOTDEF));
1133 }
1134
1135 #[test]
1139 fn cmap4_iter_sparse_range() {
1140 #[rustfmt::skip]
1141 let cmap4_data: &[u16] = &[
1142 4, 0, 0,
1144 4,
1146 0, 0, 0,
1148 262, 0xFFFF,
1150 0,
1152 259, 0xFFFF,
1154 0, 1,
1156 4, 0,
1158 236, 0, 0, 326,
1160 ];
1161 let mut buf = BeBuffer::new();
1162 for &word in cmap4_data {
1163 buf = buf.push(word);
1164 }
1165 let cmap4 = Cmap4::read(FontData::new(&buf)).unwrap();
1166 let mappings = cmap4
1167 .iter()
1168 .map(|(ch, gid)| (ch, gid.to_u32()))
1169 .collect::<Vec<_>>();
1170 assert_eq!(mappings, &[(259, 236), (262, 326), (65535, 0)]);
1171 }
1172
1173 #[test]
1180 fn cmap4_iter_overlapping_range_offset_segment() {
1181 #[rustfmt::skip]
1182 let cmap4_data: &[u16] = &[
1183 4, 0, 0,
1185 6,
1187 0, 0, 0,
1189 20, 25, 0xFFFF,
1191 0,
1193 10, 15, 0xFFFF,
1195 0, 0, 1,
1197 0, 8, 0,
1199 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
1201 ];
1202 let mut buf = BeBuffer::new();
1203 for &word in cmap4_data {
1204 buf = buf.push(word);
1205 }
1206 let cmap4 = Cmap4::read(FontData::new(&buf)).unwrap();
1207 let mappings = cmap4
1208 .iter()
1209 .map(|(ch, gid)| (ch, gid.to_u32()))
1210 .collect::<Vec<_>>();
1211
1212 assert_eq!(
1217 mappings,
1218 &[
1219 (10, 10),
1220 (11, 11),
1221 (12, 12),
1222 (13, 13),
1223 (14, 14),
1224 (15, 15),
1225 (16, 16),
1226 (17, 17),
1227 (18, 18),
1228 (19, 19),
1229 (20, 20),
1230 (21, 108),
1231 (22, 109),
1232 (23, 110),
1233 (24, 111),
1234 (25, 112),
1235 (65535, 0),
1236 ]
1237 );
1238 }
1239
1240 const CMAP6_PAIRS: &[(u32, u32)] = &[
1241 (0x1723, 1),
1242 (0x1724, 2),
1243 (0x1725, 3),
1244 (0x1726, 4),
1245 (0x1727, 5),
1246 ];
1247
1248 #[test]
1249 fn cmap6_map() {
1250 let font = FontRef::new(font_test_data::CMAP6).unwrap();
1251 let cmap = font.cmap().unwrap();
1252 let CmapSubtable::Format6(cmap6) = cmap.subtable(0).unwrap() else {
1253 panic!("should be a format 6 subtable");
1254 };
1255 for (ch, gid) in CMAP6_PAIRS {
1256 assert_eq!(cmap6.map_codepoint(*ch).unwrap().to_u32(), *gid);
1257 }
1258 assert!(cmap6.map_codepoint(CMAP6_PAIRS[0].0 - 1).is_none());
1260 assert!(cmap6
1261 .map_codepoint(CMAP6_PAIRS.last().copied().unwrap().0 + 1)
1262 .is_none());
1263 }
1264
1265 #[test]
1266 fn cmap6_iter() {
1267 let font = FontRef::new(font_test_data::CMAP6).unwrap();
1268 let cmap = font.cmap().unwrap();
1269 let CmapSubtable::Format6(cmap6) = cmap.subtable(0).unwrap() else {
1270 panic!("should be a format 6 subtable");
1271 };
1272 let pairs = cmap6
1273 .iter()
1274 .map(|(ch, gid)| (ch, gid.to_u32()))
1275 .collect::<Vec<_>>();
1276 assert_eq!(pairs, CMAP6_PAIRS);
1277 }
1278
1279 const CMAP10_PAIRS: &[(u32, u32)] = &[(0x109423, 26), (0x109424, 27), (0x109425, 32)];
1280
1281 #[test]
1282 fn cmap10_map() {
1283 let font = FontRef::new(font_test_data::CMAP10).unwrap();
1284 let cmap = font.cmap().unwrap();
1285 let CmapSubtable::Format10(cmap10) = cmap.subtable(0).unwrap() else {
1286 panic!("should be a format 10 subtable");
1287 };
1288 for (ch, gid) in CMAP10_PAIRS {
1289 assert_eq!(cmap10.map_codepoint(*ch).unwrap().to_u32(), *gid);
1290 }
1291 assert!(cmap10.map_codepoint(CMAP10_PAIRS[0].0 - 1).is_none());
1293 assert!(cmap10
1294 .map_codepoint(CMAP10_PAIRS.last().copied().unwrap().0 + 1)
1295 .is_none());
1296 }
1297
1298 #[test]
1299 fn cmap10_iter() {
1300 let font = FontRef::new(font_test_data::CMAP10).unwrap();
1301 let cmap = font.cmap().unwrap();
1302 let CmapSubtable::Format10(cmap10) = cmap.subtable(0).unwrap() else {
1303 panic!("should be a format 10 subtable");
1304 };
1305 let pairs = cmap10
1306 .iter()
1307 .map(|(ch, gid)| (ch, gid.to_u32()))
1308 .collect::<Vec<_>>();
1309 assert_eq!(pairs, CMAP10_PAIRS);
1310 }
1311
1312 #[test]
1313 fn cmap12_iter() {
1314 let font = FontRef::new(font_test_data::CMAP12_FONT1).unwrap();
1315 let cmap12 = find_cmap12(&font.cmap().unwrap()).unwrap();
1316 let mut count = 0;
1317 for (codepoint, glyph_id) in cmap12.iter() {
1318 assert_eq!(cmap12.map_codepoint(codepoint), Some(glyph_id));
1319 count += 1;
1320 }
1321 assert_eq!(count, 10);
1322 }
1323
1324 #[test]
1328 fn cmap12_iter_avoid_overflow() {
1329 let data = be_buffer! {
1331 12u16, 0u16, 0u32, 0u32, 2u32, [0xFFFFFFFA_u32, 0xFFFFFFFC, 0], [0xFFFFFFFB_u32, 0xFFFFFFFF, 0] };
1340 let cmap12 = Cmap12::read(data.data().into()).unwrap();
1341 let _ = cmap12.iter().count();
1342 }
1343
1344 #[test]
1348 fn cmap12_iter_avoid_timeout() {
1349 let cmap12_data = be_buffer! {
1351 12u16, 0u16, 0u32, 0u32, 1u32, [170u32, 1330926671, 328960] };
1359 let cmap12 = Cmap12::read(cmap12_data.data().into()).unwrap();
1360 assert!(
1361 cmap12.iter_with_limits(CmapIterLimits::default()).count() <= char::MAX as usize + 1
1362 );
1363 }
1364
1365 #[test]
1368 fn cmap12_iter_avoid_timeout2() {
1369 let cmap12_data = be_buffer! {
1370 12u16, 0u16, 0u32, 0u32, 3u32, [199u32, 16777271, 2],
1377 [262u32, 262, 3],
1378 [268u32, 268, 4]
1379 };
1380 let cmap12 = Cmap12::read(cmap12_data.data().into()).unwrap();
1381 const MAX_GLYPHS: u32 = 8;
1383 let limits = CmapIterLimits {
1384 glyph_count: MAX_GLYPHS,
1385 ..Default::default()
1386 };
1387 assert_eq!(cmap12.iter_with_limits(limits).count(), MAX_GLYPHS as usize);
1388 }
1389
1390 #[test]
1391 fn cmap12_iter_glyph_limit() {
1392 let font = FontRef::new(font_test_data::CMAP12_FONT1).unwrap();
1393 let cmap12 = find_cmap12(&font.cmap().unwrap()).unwrap();
1394 let mut limits = CmapIterLimits::default_for_font(&font);
1395 for glyph_count in 0..=11 {
1398 limits.glyph_count = glyph_count;
1399 assert_eq!(
1400 cmap12.iter_with_limits(limits).count(),
1401 (glyph_count as usize).saturating_sub(1)
1404 );
1405 }
1406 }
1407
1408 #[test]
1409 fn cmap12_iter_range_clamping() {
1410 let data = be_buffer! {
1411 12u16, 0u16, 0u32, 0u32, 2u32, [0u32, 16777215, 0], [255u32, 0xFFFFFFFF, 0] };
1420 let cmap12 = Cmap12::read(data.data().into()).unwrap();
1421 let ranges = cmap12
1422 .groups()
1423 .iter()
1424 .map(|group| (group.start_char_code(), group.end_char_code()))
1425 .collect::<Vec<_>>();
1426 assert_eq!(ranges, &[(0, 16777215), (255, u32::MAX)]);
1428 let limits = CmapIterLimits {
1430 glyph_count: u32::MAX,
1431 ..Default::default()
1432 };
1433 assert!(cmap12.iter_with_limits(limits).count() <= char::MAX as usize + 1);
1434 }
1435
1436 #[test]
1440 fn cmap12_iter_saturated_group_does_not_reset_range() {
1441 let data = be_buffer! {
1442 12u16, 0u16, 0u32, 0u32, 3u32, [10u32, 20, 0],
1449 [15u32, 40, 100],
1450 [18u32, 22, 0]
1451 };
1452 let cmap12 = Cmap12::read(data.data().into()).unwrap();
1453 let limits = CmapIterLimits {
1454 glyph_count: 50,
1455 ..Default::default()
1456 };
1457 let codepoints = cmap12
1458 .iter_with_limits(limits)
1459 .map(|(cp, _)| cp)
1460 .collect::<Vec<_>>();
1461 assert_eq!(codepoints, (10..=22).collect::<Vec<_>>());
1462 }
1463
1464 #[test]
1465 fn cmap12_iter_explicit_notdef() {
1466 let data = be_buffer! {
1467 12u16, 0u16, 0u32, 0u32, 1u32, [0_u32, 1_u32, 0] };
1475 let cmap12 = Cmap12::read(data.data().into()).unwrap();
1476 for (i, (codepoint, glyph_id)) in cmap12.iter().enumerate() {
1477 assert_eq!(codepoint as usize, i);
1478 assert_eq!(glyph_id.to_u32() as usize, i);
1479 }
1480 assert_eq!(cmap12.iter().next().unwrap().1, GlyphId::NOTDEF);
1481 }
1482
1483 fn cmap13_data() -> Vec<u8> {
1484 let data = be_buffer! {
1485 13u16, 0u16, 0u32, 0u32, 2u32, [0u32, 8, 20], [42u32, 46u32, 30] };
1494 data.to_vec()
1495 }
1496
1497 #[test]
1498 fn cmap13_map() {
1499 let data = cmap13_data();
1500 let cmap13 = Cmap13::read(FontData::new(&data)).unwrap();
1501 for ch in 0u32..=8 {
1502 assert_eq!(cmap13.map_codepoint(ch), Some(GlyphId::new(20)));
1503 }
1504 for ch in 9u32..42 {
1505 assert_eq!(cmap13.map_codepoint(ch), None);
1506 }
1507 for ch in 42u32..=46 {
1508 assert_eq!(cmap13.map_codepoint(ch), Some(GlyphId::new(30)));
1509 }
1510 for ch in 47u32..1024 {
1511 assert_eq!(cmap13.map_codepoint(ch), None);
1512 }
1513 }
1514
1515 #[test]
1516 fn cmap13_iter() {
1517 let data = cmap13_data();
1518 let cmap13 = Cmap13::read(FontData::new(&data)).unwrap();
1519 for (ch, gid) in cmap13.iter() {
1520 assert_eq!(cmap13.map_codepoint(ch), Some(gid));
1521 }
1522 }
1523
1524 #[test]
1525 fn cmap14_iter() {
1526 let font = FontRef::new(font_test_data::CMAP14_FONT1).unwrap();
1527 let cmap14 = find_cmap14(&font.cmap().unwrap()).unwrap();
1528 let mut count = 0;
1529 for (codepoint, selector, mapping) in cmap14.iter() {
1530 assert_eq!(cmap14.map_variant(codepoint, selector), Some(mapping));
1531 count += 1;
1532 }
1533 assert_eq!(count, 7);
1534 }
1535
1536 type DefaultUvs<'a> = &'a [(u32, u8)];
1538
1539 type NonDefaultUvs<'a> = &'a [(u32, u16)];
1541
1542 fn build_cmap14(records: &[(u32, Option<DefaultUvs>, Option<NonDefaultUvs>)]) -> BeBuffer {
1548 fn default_uvs_data(ranges: &[(u32, u8)]) -> BeBuffer {
1549 let mut bytes = BeBuffer::new();
1550 bytes = bytes.push(ranges.len() as u32);
1551 for &(start, additional_count) in ranges {
1552 bytes = bytes.push(Uint24::new(start));
1553 bytes = bytes.push(additional_count);
1554 }
1555 bytes
1556 }
1557 fn non_default_uvs_data(mappings: &[(u32, u16)]) -> BeBuffer {
1558 let mut bytes = BeBuffer::new();
1559 bytes = bytes.push(mappings.len() as u32);
1560 for &(codepoint, glyph_id) in mappings {
1561 bytes = bytes.push(Uint24::new(codepoint));
1562 bytes = bytes.push(glyph_id);
1563 }
1564 bytes
1565 }
1566 let mut data = BeBuffer::new();
1567 data = data.push(14u16);
1569 data = data.push_with_tag(0u32, "cmap14_length");
1571 data = data.push(records.len() as u32);
1573 let mut default_offset_tags = Vec::with_capacity(records.len());
1574 let mut non_default_offset_tags = Vec::with_capacity(records.len());
1575 for (i, (selector, default_ranges, non_default_mappings)) in records.iter().enumerate() {
1576 data = data.push(Uint24::new(*selector));
1578 if default_ranges.is_some() {
1580 let tag = format!("default_uvs_offset_{i}");
1581 data = data.push_with_tag(0u32, tag.as_str());
1582 default_offset_tags.push(Some(tag));
1583 } else {
1584 data = data.push(0u32);
1585 default_offset_tags.push(None);
1586 }
1587 if non_default_mappings.is_some() {
1589 let tag = format!("non_default_uvs_offset_{i}");
1590 data = data.push_with_tag(0u32, tag.as_str());
1591 non_default_offset_tags.push(Some(tag));
1592 } else {
1593 data = data.push(0u32);
1594 non_default_offset_tags.push(None);
1595 }
1596 }
1597 for (i, (_, default_ranges, _)) in records.iter().enumerate() {
1598 if let Some(ranges) = default_ranges {
1599 let table_offset = data.len() as u32;
1600 data.write_at(default_offset_tags[i].as_ref().unwrap(), table_offset);
1601 let bytes = default_uvs_data(ranges);
1603 data = data.extend(bytes.as_slice().iter().copied());
1604 }
1605 }
1606 for (i, (_, _, non_default_mappings)) in records.iter().enumerate() {
1607 if let Some(mappings) = non_default_mappings {
1608 let table_offset = data.len() as u32;
1609 data.write_at(non_default_offset_tags[i].as_ref().unwrap(), table_offset);
1610 let bytes = non_default_uvs_data(mappings);
1612 data = data.extend(bytes.as_slice().iter().copied());
1613 }
1614 }
1615 data.write_at("cmap14_length", data.len() as u32);
1616 data
1617 }
1618
1619 #[test]
1620 fn cmap14_iter_only_handles_monotone_selectors() {
1621 use super::MapVariant::*;
1622 let data = build_cmap14(&[
1623 (0xE100, Some(&[(0x4E00, 0)]), Some(&[(0x4E01, 7)])),
1624 (0xE100, None, Some(&[(0x4E02, 8)])),
1626 (0xE200, None, Some(&[(0x4E03, 9)])),
1627 (0xE100, None, Some(&[(0x4E03, 10)])),
1629 ]);
1630 let cmap14 = Cmap14::read(FontData::new(data.data())).unwrap();
1631 assert_eq!(
1632 cmap14.iter().collect::<Vec<_>>(),
1633 vec![
1634 (0x4E00, 0xE100, UseDefault),
1635 (0x4E01, 0xE100, Variant(GlyphId::new(7))),
1636 (0x4E03, 0xE200, Variant(GlyphId::new(9))),
1637 ]
1638 );
1639 }
1640
1641 #[test]
1642 fn cmap14_iter_limits_default_uvs_to_max_char() {
1643 use super::MapVariant::*;
1644 let data = build_cmap14(&[(0xE100, Some(&[(0x41, 2), (0x50, 0)]), None)]);
1645 let cmap14 = Cmap14::read(FontData::new(data.data())).unwrap();
1646 assert_eq!(
1647 cmap14
1648 .iter_with_limits(CmapIterLimits {
1649 max_char: 1,
1650 glyph_count: u32::MAX,
1651 })
1652 .collect::<Vec<_>>(),
1653 vec![(0x41, 0xE100, UseDefault), (0x42, 0xE100, UseDefault),]
1654 );
1655 }
1656
1657 #[test]
1658 fn cmap14_iter_limits_non_default_uvs_to_glyph_count() {
1659 use super::MapVariant::*;
1660 let data = build_cmap14(&[(
1661 0xE100,
1662 None,
1663 Some(&[(0x4E00, 10), (0x4E01, 11), (0x4E02, 12)]),
1664 )]);
1665 let cmap14 = Cmap14::read(FontData::new(data.data())).unwrap();
1666 assert_eq!(
1667 cmap14
1668 .iter_with_limits(CmapIterLimits {
1669 max_char: u32::MAX,
1670 glyph_count: 2,
1671 })
1672 .collect::<Vec<_>>(),
1673 vec![
1674 (0x4E00, 0xE100, Variant(GlyphId::new(10))),
1675 (0x4E01, 0xE100, Variant(GlyphId::new(11))),
1676 ]
1677 );
1678 }
1679
1680 fn find_cmap4<'a>(cmap: &Cmap<'a>) -> Option<Cmap4<'a>> {
1681 cmap.encoding_records()
1682 .iter()
1683 .filter_map(|record| record.subtable(cmap.offset_data()).ok())
1684 .find_map(|subtable| match subtable {
1685 CmapSubtable::Format4(cmap4) => Some(cmap4),
1686 _ => None,
1687 })
1688 }
1689
1690 fn find_cmap12<'a>(cmap: &Cmap<'a>) -> Option<Cmap12<'a>> {
1691 cmap.encoding_records()
1692 .iter()
1693 .filter_map(|record| record.subtable(cmap.offset_data()).ok())
1694 .find_map(|subtable| match subtable {
1695 CmapSubtable::Format12(cmap12) => Some(cmap12),
1696 _ => None,
1697 })
1698 }
1699
1700 fn find_cmap14<'a>(cmap: &Cmap<'a>) -> Option<Cmap14<'a>> {
1701 cmap.encoding_records()
1702 .iter()
1703 .filter_map(|record| record.subtable(cmap.offset_data()).ok())
1704 .find_map(|subtable| match subtable {
1705 CmapSubtable::Format14(cmap14) => Some(cmap14),
1706 _ => None,
1707 })
1708 }
1709
1710 #[test]
1715 fn cmap4_bad_data() {
1716 let buf = font_test_data::cmap::repetitive_cmap4();
1717 let cmap4 = Cmap4::read(FontData::new(buf.as_slice())).unwrap();
1718
1719 assert_eq!(
1721 (6..=64).collect::<Vec<_>>(),
1722 cmap4.iter().map(|(cp, _)| cp).collect::<Vec<_>>()
1723 );
1724 }
1725
1726 fn cmap0_data() -> BeBuffer {
1727 be_buffer! {
1728 0u16,
1730 1u16,
1732 1u16,
1734 0u16,
1736 12u32,
1738 0u16,
1740 274u16,
1742 0u16,
1744 [0u8, 249, 32, 2, 198, 23, 1, 4, 26, 36,
1746 171, 168, 69, 151, 208, 238, 226, 153, 161, 138,
1747 160, 130, 169, 223, 162, 207, 146, 227, 111, 248,
1748 163, 79, 178, 27, 50, 234, 213, 57, 45, 63,
1749 103, 186, 30, 105, 131, 118, 35, 140, 51, 211,
1750 75, 172, 56, 71, 137, 99, 22, 76, 61, 125,
1751 39, 8, 177, 117, 108, 97, 202, 92, 49, 134,
1752 93, 43, 80, 66, 84, 54, 180, 113, 11, 176,
1753 229, 48, 47, 17, 124, 40, 119, 21, 13, 133,
1754 181, 224, 33, 128, 44, 46, 38, 24, 65, 152,
1755 197, 225, 102, 251, 157, 126, 182, 242, 28, 184,
1756 90, 170, 201, 144, 193, 189, 250, 142, 77, 221,
1757 81, 164, 154, 60, 37, 200, 12, 53, 219, 89,
1758 31, 209, 188, 179, 253, 220, 127, 18, 19, 64,
1759 20, 141, 98, 173, 55, 194, 70, 107, 228, 104,
1760 10, 9, 15, 217, 255, 222, 196, 236, 67, 165,
1761 5, 143, 149, 100, 91, 95, 135, 235, 145, 204,
1762 72, 114, 246, 82, 245, 233, 106, 158, 185, 212,
1763 86, 243, 16, 195, 123, 190, 120, 187, 132, 139,
1764 192, 239, 110, 183, 240, 214, 166, 41, 59, 231,
1765 42, 94, 244, 83, 121, 25, 215, 96, 73, 87,
1766 174, 136, 62, 206, 156, 175, 230, 150, 116, 147,
1767 68, 122, 78, 112, 6, 167, 232, 254, 52, 34,
1768 191, 85, 241, 14, 216, 155, 29, 101, 115, 210,
1769 252, 218, 129, 247, 203, 159, 109, 74, 7, 58,
1770 237, 199, 88, 205, 148, 3]
1771 }
1772 }
1773
1774 #[test]
1775 fn best_subtable_full() {
1776 let font = FontRef::new(font_test_data::VORG).unwrap();
1777 let cmap = font.cmap().unwrap();
1778 let (index, record, _) = cmap.best_subtable().unwrap();
1779 assert_eq!(
1780 (index, record.platform_id(), record.encoding_id()),
1781 (3, PlatformId::Windows, WINDOWS_UNICODE_FULL_ENCODING)
1782 );
1783 }
1784
1785 #[test]
1786 fn best_subtable_bmp() {
1787 let font = FontRef::new(font_test_data::CMAP12_FONT1).unwrap();
1788 let cmap = font.cmap().unwrap();
1789 let (index, record, _) = cmap.best_subtable().unwrap();
1790 assert_eq!(
1791 (index, record.platform_id(), record.encoding_id()),
1792 (0, PlatformId::Windows, WINDOWS_UNICODE_BMP_ENCODING)
1793 );
1794 }
1795
1796 #[test]
1797 fn best_subtable_symbol() {
1798 let font = FontRef::new(font_test_data::CMAP4_SYMBOL_PUA).unwrap();
1799 let cmap = font.cmap().unwrap();
1800 let (index, record, _) = cmap.best_subtable().unwrap();
1801 assert!(record.is_symbol());
1802 assert_eq!(
1803 (index, record.platform_id(), record.encoding_id()),
1804 (0, PlatformId::Windows, WINDOWS_SYMBOL_ENCODING)
1805 );
1806 }
1807
1808 #[test]
1809 fn uvs_subtable() {
1810 let font = FontRef::new(font_test_data::CMAP14_FONT1).unwrap();
1811 let cmap = font.cmap().unwrap();
1812 let (index, _) = cmap.uvs_subtable().unwrap();
1813 assert_eq!(index, 0);
1814 }
1815}