1use std::ops::Range;
4
5use super::{BlendState, Error, Number, Stack, StringId};
6use crate::{types::Fixed, Cursor, ReadError};
7
8#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
13pub enum Operator {
14 Version,
15 Notice,
16 FullName,
17 FamilyName,
18 Weight,
19 FontBbox,
20 CharstringsOffset,
21 PrivateDictRange,
22 VariationStoreOffset,
23 Copyright,
24 IsFixedPitch,
25 ItalicAngle,
26 UnderlinePosition,
27 UnderlineThickness,
28 PaintType,
29 CharstringType,
30 FontMatrix,
31 StrokeWidth,
32 FdArrayOffset,
33 FdSelectOffset,
34 BlueValues,
35 OtherBlues,
36 FamilyBlues,
37 FamilyOtherBlues,
38 SubrsOffset,
39 VariationStoreIndex,
40 BlueScale,
41 BlueShift,
42 BlueFuzz,
43 LanguageGroup,
44 ExpansionFactor,
45 Encoding,
46 Charset,
47 UniqueId,
48 Xuid,
49 SyntheticBase,
50 PostScript,
51 BaseFontName,
52 BaseFontBlend,
53 Ros,
54 CidFontVersion,
55 CidFontRevision,
56 CidFontType,
57 CidCount,
58 UidBase,
59 FontName,
60 StdHw,
61 StdVw,
62 DefaultWidthX,
63 NominalWidthX,
64 Blend,
65 StemSnapH,
66 StemSnapV,
67 ForceBold,
68 InitialRandomSeed,
69}
70
71impl Operator {
72 fn from_opcode(opcode: u8) -> Option<Self> {
73 use Operator::*;
74 Some(match opcode {
75 0 => Version,
77 1 => Notice,
78 2 => FullName,
79 3 => FamilyName,
80 4 => Weight,
81 5 => FontBbox,
82 13 => UniqueId,
83 14 => Xuid,
84 15 => Charset,
85 16 => Encoding,
86 17 => CharstringsOffset,
87 18 => PrivateDictRange,
88 24 => VariationStoreOffset,
89 6 => BlueValues,
91 7 => OtherBlues,
92 8 => FamilyBlues,
93 9 => FamilyOtherBlues,
94 10 => StdHw,
95 11 => StdVw,
96 19 => SubrsOffset,
97 20 => DefaultWidthX,
98 21 => NominalWidthX,
99 22 => VariationStoreIndex,
100 23 => Blend,
101 _ => return None,
103 })
104 }
105
106 fn from_extended_opcode(opcode: u8) -> Option<Self> {
107 use Operator::*;
108 Some(match opcode {
109 0 => Copyright,
111 1 => IsFixedPitch,
112 2 => ItalicAngle,
113 3 => UnderlinePosition,
114 4 => UnderlineThickness,
115 5 => PaintType,
116 6 => CharstringType,
117 7 => FontMatrix,
118 8 => StrokeWidth,
119 20 => SyntheticBase,
120 21 => PostScript,
121 22 => BaseFontName,
122 23 => BaseFontBlend,
123 30 => Ros,
124 31 => CidFontVersion,
125 32 => CidFontRevision,
126 33 => CidFontType,
127 34 => CidCount,
128 35 => UidBase,
129 36 => FdArrayOffset,
130 37 => FdSelectOffset,
131 38 => FontName,
132 9 => BlueScale,
134 10 => BlueShift,
135 11 => BlueFuzz,
136 12 => StemSnapH,
137 13 => StemSnapV,
138 14 => ForceBold,
139 17 => LanguageGroup,
140 18 => ExpansionFactor,
141 19 => InitialRandomSeed,
142 _ => return None,
143 })
144 }
145}
146
147#[derive(Copy, Clone, PartialEq, Eq, Debug)]
149pub enum Token {
150 Operator(Operator),
152 Operand(Number, Option<BcdComponents>),
156}
157
158impl From<Operator> for Token {
159 fn from(value: Operator) -> Self {
160 Self::Operator(value)
161 }
162}
163
164impl<T> From<T> for Token
165where
166 T: Into<Number>,
167{
168 fn from(value: T) -> Self {
169 Self::Operand(value.into(), None)
170 }
171}
172
173pub fn tokens(dict_data: &[u8]) -> impl Iterator<Item = Result<Token, Error>> + '_ + Clone {
179 let mut cursor = crate::FontData::new(dict_data).cursor();
180 std::iter::from_fn(move || {
181 if cursor.remaining_bytes() == 0 {
182 None
183 } else {
184 Some(parse_token(&mut cursor))
185 }
186 })
187}
188
189fn parse_token(cursor: &mut Cursor) -> Result<Token, Error> {
190 const ESCAPE: u8 = 12;
192 let b0 = cursor.read::<u8>()?;
193 Ok(if b0 == ESCAPE {
194 let b1 = cursor.read::<u8>()?;
195 Token::Operator(Operator::from_extended_opcode(b1).ok_or(Error::InvalidDictOperator(b1))?)
196 } else {
197 match b0 {
199 28 | 29 | 32..=254 => Token::Operand(parse_int(cursor, b0)?.into(), None),
200 30 => {
201 let components = BcdComponents::parse(cursor)?;
202 Token::Operand(components.value(false).into(), Some(components))
203 }
204 _ => Token::Operator(Operator::from_opcode(b0).ok_or(Error::InvalidDictOperator(b0))?),
205 }
206 })
207}
208
209fn parse_fixed_dynamic(cursor: &mut Cursor) -> Result<(Fixed, i32), Error> {
213 let b0 = cursor.read::<u8>()?;
214 match b0 {
215 30 => Ok(BcdComponents::parse(cursor)?.dynamically_scaled_value()),
216 28 | 29 | 32..=254 => {
217 let num = parse_int(cursor, b0)?;
218 let mut int_len = 10;
219 if num > BCD_INTEGER_LIMIT {
220 for (i, power_ten) in BCD_POWER_TENS.iter().enumerate().skip(5) {
221 if num < *power_ten {
222 int_len = i;
223 break;
224 }
225 }
226 let scaling = if (num - BCD_POWER_TENS[int_len - 5]) > BCD_INTEGER_LIMIT {
227 int_len - 4
228 } else {
229 int_len - 5
230 };
231 Ok((
232 Fixed::from_bits(num) / Fixed::from_bits(BCD_POWER_TENS[scaling]),
233 scaling as i32,
234 ))
235 } else {
236 Ok((Fixed::from_bits(num << 16), 0))
237 }
238 }
239 _ => Err(Error::InvalidNumber),
240 }
241}
242
243#[derive(Clone, PartialEq, Eq, Debug)]
245pub enum Entry {
246 Version(StringId),
247 Notice(StringId),
248 FullName(StringId),
249 FamilyName(StringId),
250 Weight(StringId),
251 FontBbox([Fixed; 4]),
252 CharstringsOffset(usize),
253 PrivateDictRange(Range<usize>),
254 VariationStoreOffset(usize),
255 Copyright(StringId),
256 IsFixedPitch(bool),
257 ItalicAngle(Fixed),
258 UnderlinePosition(Fixed),
259 UnderlineThickness(Fixed),
260 PaintType(i32),
261 CharstringType(i32),
262 FontMatrix([Fixed; 6]),
263 StrokeWidth(Fixed),
264 FdArrayOffset(usize),
265 FdSelectOffset(usize),
266 BlueValues(Blues),
267 OtherBlues(Blues),
268 FamilyBlues(Blues),
269 FamilyOtherBlues(Blues),
270 SubrsOffset(usize),
271 VariationStoreIndex(u16),
272 BlueScale(Fixed),
273 BlueShift(Fixed),
274 BlueFuzz(Fixed),
275 LanguageGroup(i32),
276 ExpansionFactor(Fixed),
277 Encoding(usize),
278 Charset(usize),
279 UniqueId(i32),
280 Xuid,
281 SyntheticBase(i32),
282 PostScript(StringId),
283 BaseFontName(StringId),
284 BaseFontBlend,
285 Ros {
286 registry: StringId,
287 ordering: StringId,
288 supplement: Fixed,
289 },
290 CidFontVersion(Fixed),
291 CidFontRevision(Fixed),
292 CidFontType(i32),
293 CidCount(u32),
294 UidBase(i32),
295 FontName(StringId),
296 StdHw(Fixed),
297 StdVw(Fixed),
298 DefaultWidthX(Fixed),
299 NominalWidthX(Fixed),
300 StemSnapH(StemSnaps),
301 StemSnapV(StemSnaps),
302 ForceBold(bool),
303 InitialRandomSeed(i32),
304}
305
306pub fn entries<'a>(
315 dict_data: &'a [u8],
316 mut blend_state: Option<BlendState<'a>>,
317) -> impl Iterator<Item = Result<Entry, Error>> + 'a {
318 let mut stack = Stack::new();
319 let mut last_bcd_components = None;
320 let mut cursor = crate::FontData::new(dict_data).cursor();
321 let mut cursor_pos = 0;
322 std::iter::from_fn(move || loop {
323 if cursor.remaining_bytes() == 0 {
324 return None;
325 }
326 let token = match parse_token(&mut cursor) {
327 Ok(token) => token,
328 Err(e) => return Some(Err(e)),
329 };
330 match token {
331 Token::Operand(number, bcd_components) => {
332 last_bcd_components = bcd_components;
333 match stack.push(number) {
334 Ok(_) => continue,
335 Err(e) => return Some(Err(e)),
336 }
337 }
338 Token::Operator(op) => {
339 if op == Operator::Blend || op == Operator::VariationStoreIndex {
340 let state = match blend_state.as_mut() {
341 Some(state) => state,
342 None => return Some(Err(Error::MissingBlendState)),
343 };
344 if op == Operator::VariationStoreIndex {
345 match stack
346 .get_i32(0)
347 .and_then(|ix| state.set_store_index(ix as u16))
348 {
349 Ok(_) => {}
350 Err(e) => return Some(Err(e)),
351 }
352 }
353 if op == Operator::Blend {
354 match stack.apply_blend(state) {
355 Ok(_) => continue,
356 Err(e) => return Some(Err(e)),
357 }
358 }
359 }
360 if op == Operator::BlueScale {
361 if let Some(bcd_components) = last_bcd_components.take() {
366 stack.pop_fixed().ok()?;
370 stack.push(bcd_components.value(true)).ok()?;
371 }
372 }
373 if op == Operator::FontMatrix {
374 stack.clear();
379 last_bcd_components = None;
380 let mut cursor = crate::FontData::new(dict_data).cursor();
382 cursor.advance_by(cursor_pos);
383 if let Some((matrix, _upem)) = parse_font_matrix(&mut cursor) {
384 return Some(Ok(Entry::FontMatrix(matrix)));
387 }
388 continue;
389 }
390 last_bcd_components = None;
391 let entry = parse_entry(op, &mut stack);
392 stack.clear();
393 cursor_pos = cursor.position().unwrap_or_default();
394 return Some(entry);
395 }
396 }
397 })
398}
399
400fn parse_entry(op: Operator, stack: &mut Stack) -> Result<Entry, Error> {
401 use Operator::*;
402 Ok(match op {
403 Version => Entry::Version(stack.pop_i32()?.into()),
404 Notice => Entry::Notice(stack.pop_i32()?.into()),
405 FullName => Entry::FullName(stack.pop_i32()?.into()),
406 FamilyName => Entry::FamilyName(stack.pop_i32()?.into()),
407 Weight => Entry::Weight(stack.pop_i32()?.into()),
408 FontBbox => Entry::FontBbox([
409 stack.get_fixed(0)?,
410 stack.get_fixed(1)?,
411 stack.get_fixed(2)?,
412 stack.get_fixed(3)?,
413 ]),
414 CharstringsOffset => Entry::CharstringsOffset(stack.pop_i32()? as usize),
415 PrivateDictRange => {
416 let len = stack.get_i32(0)? as usize;
417 let start = stack.get_i32(1)? as usize;
418 let end = start.checked_add(len).ok_or(ReadError::OutOfBounds)?;
419 Entry::PrivateDictRange(start..end)
420 }
421 VariationStoreOffset => Entry::VariationStoreOffset(stack.pop_i32()? as usize),
422 Copyright => Entry::Copyright(stack.pop_i32()?.into()),
423 IsFixedPitch => Entry::IsFixedPitch(stack.pop_i32()? != 0),
424 ItalicAngle => Entry::ItalicAngle(stack.pop_fixed()?),
425 UnderlinePosition => Entry::UnderlinePosition(stack.pop_fixed()?),
426 UnderlineThickness => Entry::UnderlineThickness(stack.pop_fixed()?),
427 PaintType => Entry::PaintType(stack.pop_i32()?),
428 CharstringType => Entry::CharstringType(stack.pop_i32()?),
429 FontMatrix => unreachable!(),
430 StrokeWidth => Entry::StrokeWidth(stack.pop_fixed()?),
431 FdArrayOffset => Entry::FdArrayOffset(stack.pop_i32()? as usize),
432 FdSelectOffset => Entry::FdSelectOffset(stack.pop_i32()? as usize),
433 BlueValues => {
434 stack.apply_delta_prefix_sum();
435 Entry::BlueValues(Blues::new(stack.fixed_values()))
436 }
437 OtherBlues => {
438 stack.apply_delta_prefix_sum();
439 Entry::OtherBlues(Blues::new(stack.fixed_values()))
440 }
441 FamilyBlues => {
442 stack.apply_delta_prefix_sum();
443 Entry::FamilyBlues(Blues::new(stack.fixed_values()))
444 }
445 FamilyOtherBlues => {
446 stack.apply_delta_prefix_sum();
447 Entry::FamilyOtherBlues(Blues::new(stack.fixed_values()))
448 }
449 SubrsOffset => Entry::SubrsOffset(stack.pop_i32()? as usize),
450 VariationStoreIndex => Entry::VariationStoreIndex(stack.pop_i32()? as u16),
451 BlueScale => Entry::BlueScale(stack.pop_fixed()?),
452 BlueShift => Entry::BlueShift(stack.pop_fixed()?),
453 BlueFuzz => Entry::BlueFuzz(stack.pop_fixed()?),
454 LanguageGroup => Entry::LanguageGroup(stack.pop_i32()?),
455 ExpansionFactor => Entry::ExpansionFactor(stack.pop_fixed()?),
456 Encoding => Entry::Encoding(stack.pop_i32()? as usize),
457 Charset => Entry::Charset(stack.pop_i32()? as usize),
458 UniqueId => Entry::UniqueId(stack.pop_i32()?),
459 Xuid => Entry::Xuid,
460 SyntheticBase => Entry::SyntheticBase(stack.pop_i32()?),
461 PostScript => Entry::PostScript(stack.pop_i32()?.into()),
462 BaseFontName => Entry::BaseFontName(stack.pop_i32()?.into()),
463 BaseFontBlend => Entry::BaseFontBlend,
464 Ros => Entry::Ros {
465 registry: stack.get_i32(0)?.into(),
466 ordering: stack.get_i32(1)?.into(),
467 supplement: stack.get_fixed(2)?,
468 },
469 CidFontVersion => Entry::CidFontVersion(stack.pop_fixed()?),
470 CidFontRevision => Entry::CidFontRevision(stack.pop_fixed()?),
471 CidFontType => Entry::CidFontType(stack.pop_i32()?),
472 CidCount => Entry::CidCount(stack.pop_i32()? as u32),
473 UidBase => Entry::UidBase(stack.pop_i32()?),
474 FontName => Entry::FontName(stack.pop_i32()?.into()),
475 StdHw => Entry::StdHw(stack.pop_fixed()?),
476 StdVw => Entry::StdVw(stack.pop_fixed()?),
477 DefaultWidthX => Entry::DefaultWidthX(stack.pop_fixed()?),
478 NominalWidthX => Entry::NominalWidthX(stack.pop_fixed()?),
479 StemSnapH => {
480 stack.apply_delta_prefix_sum();
481 Entry::StemSnapH(StemSnaps::new(stack.fixed_values()))
482 }
483 StemSnapV => {
484 stack.apply_delta_prefix_sum();
485 Entry::StemSnapV(StemSnaps::new(stack.fixed_values()))
486 }
487 ForceBold => Entry::ForceBold(stack.pop_i32()? != 0),
488 InitialRandomSeed => Entry::InitialRandomSeed(stack.pop_i32()?),
489 Blend => unreachable!(),
491 })
492}
493
494fn parse_font_matrix(cursor: &mut Cursor) -> Option<([Fixed; 6], i32)> {
498 let mut values = [Fixed::ZERO; 6];
499 let mut scalings = [0i32; 6];
500 let mut max_scaling = i32::MIN;
501 let mut min_scaling = i32::MAX;
502 for (value, scaling) in values.iter_mut().zip(&mut scalings) {
503 let (v, s) = parse_fixed_dynamic(cursor).ok()?;
504 if v != Fixed::ZERO {
505 max_scaling = max_scaling.max(s);
506 min_scaling = min_scaling.min(s);
507 }
508 *value = v;
509 *scaling = s;
510 }
511 if !(-9..=0).contains(&max_scaling)
512 || (max_scaling - min_scaling < 0)
513 || (max_scaling - min_scaling) > 9
514 {
515 return None;
516 }
517 for (value, scaling) in values.iter_mut().zip(scalings) {
518 if *value == Fixed::ZERO {
519 continue;
520 }
521 let divisor = BCD_POWER_TENS[(max_scaling - scaling) as usize];
522 let half_divisor = divisor >> 1;
523 if *value < Fixed::ZERO {
524 if i32::MIN + half_divisor < value.to_bits() {
525 *value = Fixed::from_bits((value.to_bits() - half_divisor) / divisor);
526 } else {
527 *value = Fixed::from_bits(i32::MIN / divisor);
528 }
529 } else if i32::MAX - half_divisor > value.to_bits() {
530 *value = Fixed::from_bits((value.to_bits() + half_divisor) / divisor);
531 } else {
532 *value = Fixed::from_bits(i32::MAX / divisor);
533 }
534 }
535 if is_degenerate(&values) {
537 return None;
538 }
539 let mut upem = BCD_POWER_TENS[(-max_scaling) as usize];
540 let factor = if values[3] != Fixed::ZERO {
543 values[3].abs()
544 } else {
545 values[1].abs()
547 };
548 if factor != Fixed::ONE {
549 upem = (Fixed::from_bits(upem) / factor).to_bits();
550 for value in &mut values {
551 *value /= factor;
552 }
553 }
554 for offset in values[4..6].iter_mut() {
556 *offset = Fixed::from_bits(offset.to_bits() >> 16);
557 }
558 Some((values, upem))
559}
560
561fn is_degenerate(matrix: &[Fixed; 6]) -> bool {
564 let [mut xx, mut yx, mut xy, mut yy, ..] = matrix.map(|x| x.to_bits() as i64);
565 let val = xx.abs() | yx.abs() | xy.abs() | yy.abs();
566 if val == 0 || val > 0x7FFFFFFF {
567 return true;
568 }
569 let msb = 32 - (val as i32).leading_zeros() - 1;
571 let shift = msb as i32 - 12;
572 if shift > 0 {
573 xx >>= shift;
574 xy >>= shift;
575 yx >>= shift;
576 yy >>= shift;
577 }
578 let temp1 = 32 * (xx * yy - xy * yx).abs();
579 let temp2 = (xx * xx) + (xy * xy) + (yx * yx) + (yy * yy);
580 if temp1 <= temp2 {
581 return true;
582 }
583 false
584}
585
586const MAX_BLUE_VALUES: usize = 7;
588
589#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
594pub struct Blues {
595 values: [(Fixed, Fixed); MAX_BLUE_VALUES],
596 len: u32,
597}
598
599impl Blues {
600 pub fn new(values: impl Iterator<Item = Fixed>) -> Self {
601 let mut blues = Self::default();
602 let mut stash = Fixed::ZERO;
603 for (i, value) in values.take(MAX_BLUE_VALUES * 2).enumerate() {
604 if (i & 1) == 0 {
605 stash = value;
606 } else {
607 blues.values[i / 2] = (stash, value);
608 blues.len += 1;
609 }
610 }
611 blues
612 }
613
614 pub fn values(&self) -> &[(Fixed, Fixed)] {
615 &self.values[..self.len as usize]
616 }
617}
618
619const MAX_STEM_SNAPS: usize = 12;
623
624#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
628pub struct StemSnaps {
629 values: [Fixed; MAX_STEM_SNAPS],
630 len: u32,
631}
632
633impl StemSnaps {
634 fn new(values: impl Iterator<Item = Fixed>) -> Self {
635 let mut snaps = Self::default();
636 for (value, target_value) in values.take(MAX_STEM_SNAPS).zip(&mut snaps.values) {
637 *target_value = value;
638 snaps.len += 1;
639 }
640 snaps
641 }
642
643 pub fn values(&self) -> &[Fixed] {
644 &self.values[..self.len as usize]
645 }
646}
647
648#[inline]
649pub(crate) fn parse_int(cursor: &mut Cursor, b0: u8) -> Result<i32, Error> {
650 Ok(match b0 {
659 32..=246 => b0 as i32 - 139,
660 247..=250 => (b0 as i32 - 247) * 256 + cursor.read::<u8>()? as i32 + 108,
661 251..=254 => -(b0 as i32 - 251) * 256 - cursor.read::<u8>()? as i32 - 108,
662 28 => cursor.read::<i16>()? as i32,
663 29 => cursor.read::<i32>()?,
664 _ => {
665 return Err(Error::InvalidNumber);
666 }
667 })
668}
669
670const BCD_OVERFLOW: Fixed = Fixed::from_bits(0x7FFFFFFF);
675const BCD_UNDERFLOW: Fixed = Fixed::ZERO;
677const BCD_NUMBER_LIMIT: i32 = 0xCCCCCCC;
680const BCD_INTEGER_LIMIT: i32 = 0x7FFF;
682
683const BCD_POWER_TENS: [i32; 10] = [
685 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000,
686];
687
688#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
691pub struct BcdComponents {
692 error: Option<Fixed>,
696 number: i32,
697 sign: i32,
698 exponent: i32,
699 exponent_add: i32,
700 integer_len: i32,
701 fraction_len: i32,
702}
703
704impl BcdComponents {
705 fn parse(cursor: &mut Cursor) -> Result<Self, Error> {
708 enum Phase {
709 Integer,
710 Fraction,
711 Exponent,
712 }
713 let mut phase = Phase::Integer;
714 let mut sign = 1i32;
715 let mut exponent_sign = 1i32;
716 let mut number = 0i32;
717 let mut exponent = 0i32;
718 let mut exponent_add = 0i32;
719 let mut integer_len = 0;
720 let mut fraction_len = 0;
721 'outer: loop {
732 let b = cursor.read::<u8>()?;
733 for nibble in [(b >> 4) & 0xF, b & 0xF] {
734 match phase {
735 Phase::Integer => match nibble {
736 0x0..=0x9 => {
737 if number >= BCD_NUMBER_LIMIT {
738 exponent_add += 1;
739 } else if nibble != 0 || number != 0 {
740 number = number * 10 + nibble as i32;
741 integer_len += 1;
742 }
743 }
744 0xE => sign = -1,
745 0xA => {
746 phase = Phase::Fraction;
747 }
748 0xB => {
749 phase = Phase::Exponent;
750 }
751 0xC => {
752 phase = Phase::Exponent;
753 exponent_sign = -1;
754 }
755 _ => break 'outer,
756 },
757 Phase::Fraction => match nibble {
758 0x0..=0x9 => {
759 if nibble == 0 && number == 0 {
760 exponent_add -= 1;
761 } else if number < BCD_NUMBER_LIMIT && fraction_len < 9 {
762 number = number * 10 + nibble as i32;
763 fraction_len += 1;
764 }
765 }
766 0xB => {
767 phase = Phase::Exponent;
768 }
769 0xC => {
770 phase = Phase::Exponent;
771 exponent_sign = -1;
772 }
773 _ => break 'outer,
774 },
775 Phase::Exponent => {
776 match nibble {
777 0x0..=0x9 => {
778 if exponent > 1000 {
780 return if exponent_sign == -1 {
781 Ok(BCD_UNDERFLOW.into())
782 } else {
783 Ok(BCD_OVERFLOW.into())
784 };
785 } else {
786 exponent = exponent * 10 + nibble as i32;
787 }
788 }
789 _ => break 'outer,
790 }
791 }
792 }
793 }
794 }
795 exponent *= exponent_sign;
796 Ok(Self {
797 error: None,
798 number,
799 sign,
800 exponent,
801 exponent_add,
802 integer_len,
803 fraction_len,
804 })
805 }
806
807 pub fn value(&self, scale_by_1000: bool) -> Fixed {
811 if let Some(error) = self.error {
812 return error;
813 }
814 let mut number = self.number;
815 if number == 0 {
816 return Fixed::ZERO;
817 }
818 let mut exponent = self.exponent;
819 let mut integer_len = self.integer_len;
820 let mut fraction_len = self.fraction_len;
821 if scale_by_1000 {
822 exponent += 3 + self.exponent_add;
823 } else {
824 exponent += self.exponent_add;
825 }
826 integer_len += exponent;
827 fraction_len -= exponent;
828 if integer_len > 5 {
829 return BCD_OVERFLOW;
830 }
831 if integer_len < -5 {
832 return BCD_UNDERFLOW;
833 }
834 if integer_len < 0 {
836 number /= BCD_POWER_TENS[(-integer_len) as usize];
837 fraction_len += integer_len;
838 }
839 if fraction_len == 10 {
841 number /= 10;
842 fraction_len -= 1;
843 }
844 let mut result = if fraction_len > 0 {
846 let b = BCD_POWER_TENS[fraction_len as usize];
847 if number / b > BCD_INTEGER_LIMIT {
848 0
849 } else {
850 (Fixed::from_bits(number) / Fixed::from_bits(b)).to_bits()
851 }
852 } else {
853 number = number.wrapping_mul(BCD_POWER_TENS[-fraction_len as usize]);
854 if number > BCD_INTEGER_LIMIT {
855 return BCD_OVERFLOW;
856 } else {
857 number << 16
858 }
859 };
860 if scale_by_1000 {
861 result = (Fixed::from_bits(result) / Fixed::from_i32(1000)).to_bits();
865 }
866 Fixed::from_bits(result * self.sign)
867 }
868
869 fn dynamically_scaled_value(&self) -> (Fixed, i32) {
876 if let Some(error) = self.error {
877 return (error, 0);
878 }
879 let mut number = self.number;
880 if number == 0 {
881 return (Fixed::ZERO, 0);
882 }
883 let mut exponent = self.exponent;
884 let integer_len = self.integer_len;
885 let mut fraction_len = self.fraction_len;
886 exponent += self.exponent_add;
887 fraction_len += integer_len;
888 exponent += integer_len;
889 let mut result = Fixed::ONE;
890 let mut scaling = 0;
891 if fraction_len <= 5 {
892 if number > BCD_INTEGER_LIMIT {
893 result = Fixed::from_bits(number) / Fixed::from_bits(10);
894 scaling = exponent - fraction_len + 1;
895 } else {
896 if exponent > 0 {
897 let new_fraction_len = exponent.min(5);
899 let shift = new_fraction_len - fraction_len;
900 if shift > 0 {
901 exponent -= new_fraction_len;
902 number *= BCD_POWER_TENS[shift as usize];
903 if number > BCD_INTEGER_LIMIT {
904 number /= 10;
905 exponent += 1;
906 }
907 } else {
908 exponent -= fraction_len;
909 }
910 } else {
911 exponent -= fraction_len;
912 }
913 result = Fixed::from_bits(number << 16);
914 scaling = exponent;
915 }
916 } else if (number / BCD_POWER_TENS[fraction_len as usize - 5]) > BCD_INTEGER_LIMIT {
917 result = Fixed::from_bits(number)
918 / Fixed::from_bits(BCD_POWER_TENS[fraction_len as usize - 4]);
919 scaling = exponent - 4;
920 }
921 (Fixed::from_bits(result.to_bits() * self.sign), scaling)
922 }
923}
924
925impl From<Fixed> for BcdComponents {
926 fn from(value: Fixed) -> Self {
927 Self {
928 error: Some(value),
929 ..Default::default()
930 }
931 }
932}
933
934#[cfg(test)]
935mod tests {
936 use font_test_data::bebuffer::BeBuffer;
937
938 use super::*;
939 use crate::{
940 tables::variations::ItemVariationStore, types::F2Dot14, FontData, FontRead, FontRef,
941 TableProvider,
942 };
943
944 #[test]
945 fn int_operands() {
946 let empty = FontData::new(&[]);
948 let min_byte = FontData::new(&[0]);
949 let max_byte = FontData::new(&[255]);
950 assert_eq!(parse_int(&mut empty.cursor(), 32).unwrap(), -107);
952 assert_eq!(parse_int(&mut empty.cursor(), 246).unwrap(), 107);
953 assert_eq!(parse_int(&mut min_byte.cursor(), 247).unwrap(), 108);
955 assert_eq!(parse_int(&mut max_byte.cursor(), 250).unwrap(), 1131);
956 assert_eq!(parse_int(&mut min_byte.cursor(), 251).unwrap(), -108);
958 assert_eq!(parse_int(&mut max_byte.cursor(), 254).unwrap(), -1131);
959 }
960
961 #[test]
962 fn binary_coded_decimal_operands() {
963 let bytes = FontData::new(&[0xe2, 0xa2, 0x5f]);
972 assert_eq!(
973 BcdComponents::parse(&mut bytes.cursor())
974 .unwrap()
975 .value(false),
976 Fixed::from_f64(-2.25)
977 );
978 let bytes = FontData::new(&[0x0a, 0x14, 0x05, 0x41, 0xc3, 0xff]);
979 assert_eq!(
980 BcdComponents::parse(&mut bytes.cursor())
981 .unwrap()
982 .value(false),
983 Fixed::from_f64(0.140541E-3)
984 );
985 let bytes = FontData::new(&[0x37, 0x5c, 0x4f]);
989 assert_eq!(
990 BcdComponents::parse(&mut bytes.cursor())
991 .unwrap()
992 .value(false),
993 Fixed::from_f64(0.0370025634765625)
994 );
995 }
996
997 #[test]
998 fn scaled_binary_coded_decimal_operands() {
999 let bytes = FontData::new(&[0xA, 0x06, 0x25, 0xf]);
1002 assert_eq!(
1003 BcdComponents::parse(&mut bytes.cursor())
1004 .unwrap()
1005 .value(true),
1006 Fixed::from_f64(0.0625)
1007 );
1008 let bytes = FontData::new(&[0x37, 0x5c, 0x4f]);
1011 assert_eq!(
1012 BcdComponents::parse(&mut bytes.cursor())
1013 .unwrap()
1014 .value(true),
1015 Fixed::from_f64(0.037506103515625)
1016 );
1017 }
1018
1019 #[test]
1020 fn example_top_dict_tokens() {
1021 use Operator::*;
1022 let top_dict_data = &font_test_data::cff2::EXAMPLE[5..12];
1023 let tokens: Vec<_> = tokens(top_dict_data).map(|entry| entry.unwrap()).collect();
1024 let expected: &[Token] = &[
1025 68.into(),
1026 FdArrayOffset.into(),
1027 56.into(),
1028 CharstringsOffset.into(),
1029 16.into(),
1030 VariationStoreOffset.into(),
1031 ];
1032 assert_eq!(&tokens, expected);
1033 }
1034
1035 #[test]
1036 fn example_top_dict_entries() {
1037 use Entry::*;
1038 let top_dict_data = &font_test_data::cff2::EXAMPLE[0x5..=0xB];
1039 let entries: Vec<_> = entries(top_dict_data, None)
1040 .map(|entry| entry.unwrap())
1041 .collect();
1042 let expected: &[Entry] = &[
1043 FdArrayOffset(68),
1044 CharstringsOffset(56),
1045 VariationStoreOffset(16),
1046 ];
1047 assert_eq!(&entries, expected);
1048 }
1049
1050 #[test]
1051 fn example_private_dict_entries() {
1052 use Entry::*;
1053 let private_dict_data = &font_test_data::cff2::EXAMPLE[0x4f..=0xc0];
1054 let store =
1055 ItemVariationStore::read(FontData::new(&font_test_data::cff2::EXAMPLE[18..])).unwrap();
1056 let coords = &[F2Dot14::from_f32(0.0)];
1057 let blend_state = BlendState::new(store, coords, 0).unwrap();
1058 let entries: Vec<_> = entries(private_dict_data, Some(blend_state))
1059 .map(|entry| entry.unwrap())
1060 .collect();
1061 fn make_blues(values: &[f64]) -> Blues {
1062 Blues::new(values.iter().copied().map(Fixed::from_f64))
1063 }
1064 fn make_stem_snaps(values: &[f64]) -> StemSnaps {
1065 StemSnaps::new(values.iter().copied().map(Fixed::from_f64))
1066 }
1067 let expected: &[Entry] = &[
1068 BlueValues(make_blues(&[
1069 -20.0, 0.0, 472.0, 490.0, 525.0, 540.0, 645.0, 660.0, 670.0, 690.0, 730.0, 750.0,
1070 ])),
1071 OtherBlues(make_blues(&[-250.0, -240.0])),
1072 FamilyBlues(make_blues(&[
1073 -20.0, 0.0, 473.0, 491.0, 525.0, 540.0, 644.0, 659.0, 669.0, 689.0, 729.0, 749.0,
1074 ])),
1075 FamilyOtherBlues(make_blues(&[-249.0, -239.0])),
1076 BlueScale(Fixed::from_f64(0.037506103515625)),
1077 BlueFuzz(Fixed::ZERO),
1078 StdHw(Fixed::from_f64(55.0)),
1079 StdVw(Fixed::from_f64(80.0)),
1080 StemSnapH(make_stem_snaps(&[40.0, 55.0])),
1081 StemSnapV(make_stem_snaps(&[80.0, 90.0])),
1082 SubrsOffset(114),
1083 ];
1084 assert_eq!(&entries, expected);
1085 }
1086
1087 #[test]
1088 fn noto_serif_display_top_dict_entries() {
1089 use Entry::*;
1090 let top_dict_data = FontRef::new(font_test_data::NOTO_SERIF_DISPLAY_TRIMMED)
1091 .unwrap()
1092 .cff()
1093 .unwrap()
1094 .top_dicts()
1095 .get(0)
1096 .unwrap();
1097 let entries: Vec<_> = entries(top_dict_data, None)
1098 .map(|entry| entry.unwrap())
1099 .collect();
1100 let expected = &[
1101 Version(StringId::new(391)),
1102 Notice(StringId::new(392)),
1103 Copyright(StringId::new(393)),
1104 FullName(StringId::new(394)),
1105 FamilyName(StringId::new(395)),
1106 FontBbox([-693.0, -470.0, 2797.0, 1048.0].map(Fixed::from_f64)),
1107 Charset(517),
1108 PrivateDictRange(549..587),
1109 CharstringsOffset(521),
1110 ];
1111 assert_eq!(&entries, expected);
1112 }
1113
1114 #[test]
1119 fn private_dict_range_avoid_overflow() {
1120 let private_dict = BeBuffer::new()
1123 .push(29u8) .push(-1i32) .push(29u8) .push(-1i32) .push(18u8) .to_vec();
1129 let _ = entries(&private_dict, None).count();
1131 }
1132
1133 #[test]
1134 fn dynamically_scaled_binary_coded_decimal_operands() {
1135 let bytes = FontData::new(&[0xA, 0x06, 0x25, 0xf]);
1137 assert_eq!(
1138 BcdComponents::parse(&mut bytes.cursor())
1139 .unwrap()
1140 .dynamically_scaled_value(),
1141 (Fixed::from_f64(6250.0), -5)
1142 );
1143 let bytes = FontData::new(&[0x37, 0x5c, 0x4f]);
1145 assert_eq!(
1146 BcdComponents::parse(&mut bytes.cursor())
1147 .unwrap()
1148 .dynamically_scaled_value(),
1149 (Fixed::from_f64(375.0), -4)
1150 );
1151 }
1152
1153 #[test]
1155 fn blue_scale_fraction_length_of_0() {
1156 let bytes = FontData::new(&[0x37, 0xC3, 0xFF]);
1158 assert_eq!(
1159 BcdComponents::parse(&mut bytes.cursor())
1160 .unwrap()
1161 .value(true),
1162 Fixed::from_f64(0.0370025634765625)
1163 );
1164 }
1165
1166 #[test]
1167 fn read_font_matrix() {
1168 let dict_data = [
1169 30u8, 10, 0, 31, 139, 30, 10, 0, 1, 103, 255, 30, 10, 0, 31, 139, 139, 12, 7,
1170 ];
1171 let Entry::FontMatrix(matrix) = entries(&dict_data, None).next().unwrap().unwrap() else {
1172 panic!("This was totally a font matrix");
1173 };
1174 assert_eq!(
1177 matrix,
1178 [
1179 Fixed::ONE,
1180 Fixed::ZERO,
1181 Fixed::from_f64(0.167007446289062),
1182 Fixed::ONE,
1183 Fixed::ZERO,
1184 Fixed::ZERO,
1185 ]
1186 );
1187 }
1188
1189 #[test]
1190 fn parse_degenerate_font_matrix() {
1191 let dict_data = [
1192 30u8, 0x0F, 30, 0x0F, 30, 0x0F, 30, 0x0F, 30, 0x0F, 30, 0x0F, 12, 7,
1193 ];
1194 assert!(entries(&dict_data, None).next().is_none());
1196 }
1197
1198 #[test]
1200 fn degenerate_matrix_check_doesnt_overflow() {
1201 let matrix = [
1203 Fixed::from_bits(639999672),
1204 Fixed::ZERO,
1205 Fixed::ZERO,
1206 Fixed::from_bits(639999672),
1207 Fixed::ZERO,
1208 Fixed::ZERO,
1209 ];
1210 is_degenerate(&matrix);
1212 is_degenerate(&[Fixed::MAX; 6]);
1214 is_degenerate(&[Fixed::MIN; 6]);
1216 }
1217}