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], i32),
264 StrokeWidth(Fixed),
265 FdArrayOffset(usize),
266 FdSelectOffset(usize),
267 BlueValues(Blues),
268 OtherBlues(Blues),
269 FamilyBlues(Blues),
270 FamilyOtherBlues(Blues),
271 SubrsOffset(usize),
272 VariationStoreIndex(u16),
273 BlueScale(Fixed),
274 BlueShift(Fixed),
275 BlueFuzz(Fixed),
276 LanguageGroup(i32),
277 ExpansionFactor(Fixed),
278 Encoding(usize),
279 Charset(usize),
280 UniqueId(i32),
281 Xuid,
282 SyntheticBase(i32),
283 PostScript(StringId),
284 BaseFontName(StringId),
285 BaseFontBlend,
286 Ros {
287 registry: StringId,
288 ordering: StringId,
289 supplement: Fixed,
290 },
291 CidFontVersion(Fixed),
292 CidFontRevision(Fixed),
293 CidFontType(i32),
294 CidCount(u32),
295 UidBase(i32),
296 FontName(StringId),
297 StdHw(Fixed),
298 StdVw(Fixed),
299 DefaultWidthX(Fixed),
300 NominalWidthX(Fixed),
301 StemSnapH(StemSnaps),
302 StemSnapV(StemSnaps),
303 ForceBold(bool),
304 InitialRandomSeed(i32),
305}
306
307pub fn entries<'a>(
316 dict_data: &'a [u8],
317 mut blend_state: Option<BlendState<'a>>,
318) -> impl Iterator<Item = Result<Entry, Error>> + 'a {
319 let mut stack = Stack::new();
320 let mut last_bcd_components = None;
321 let mut cursor = crate::FontData::new(dict_data).cursor();
322 let mut cursor_pos = 0;
323 std::iter::from_fn(move || loop {
324 if cursor.remaining_bytes() == 0 {
325 return None;
326 }
327 let token = match parse_token(&mut cursor) {
328 Ok(token) => token,
329 Err(e) => return Some(Err(e)),
330 };
331 match token {
332 Token::Operand(number, bcd_components) => {
333 last_bcd_components = bcd_components;
334 match stack.push(number) {
335 Ok(_) => continue,
336 Err(e) => return Some(Err(e)),
337 }
338 }
339 Token::Operator(op) => {
340 if op == Operator::Blend || op == Operator::VariationStoreIndex {
341 let state = match blend_state.as_mut() {
342 Some(state) => state,
343 None => return Some(Err(Error::MissingBlendState)),
344 };
345 if op == Operator::VariationStoreIndex {
346 match stack
347 .get_i32(0)
348 .and_then(|ix| state.set_store_index(ix as u16))
349 {
350 Ok(_) => {}
351 Err(e) => return Some(Err(e)),
352 }
353 }
354 if op == Operator::Blend {
355 match stack.apply_blend(state) {
356 Ok(_) => continue,
357 Err(e) => return Some(Err(e)),
358 }
359 }
360 }
361 if op == Operator::BlueScale {
362 if let Some(bcd_components) = last_bcd_components.take() {
367 stack.pop_fixed().ok()?;
371 stack.push(bcd_components.value(true)).ok()?;
372 }
373 }
374 if op == Operator::FontMatrix {
375 stack.clear();
380 last_bcd_components = None;
381 let mut cursor = crate::FontData::new(dict_data).cursor();
383 cursor.advance_by(cursor_pos);
384 if let Some((matrix, upem)) = parse_font_matrix(&mut cursor) {
385 return Some(Ok(Entry::FontMatrix(matrix, upem)));
386 }
387 continue;
388 }
389 last_bcd_components = None;
390 let entry = parse_entry(op, &mut stack);
391 stack.clear();
392 cursor_pos = cursor.position().unwrap_or_default();
393 return Some(entry);
394 }
395 }
396 })
397}
398
399fn parse_entry(op: Operator, stack: &mut Stack) -> Result<Entry, Error> {
400 use Operator::*;
401 Ok(match op {
402 Version => Entry::Version(stack.pop_i32()?.into()),
403 Notice => Entry::Notice(stack.pop_i32()?.into()),
404 FullName => Entry::FullName(stack.pop_i32()?.into()),
405 FamilyName => Entry::FamilyName(stack.pop_i32()?.into()),
406 Weight => Entry::Weight(stack.pop_i32()?.into()),
407 FontBbox => Entry::FontBbox([
408 stack.get_fixed(0)?,
409 stack.get_fixed(1)?,
410 stack.get_fixed(2)?,
411 stack.get_fixed(3)?,
412 ]),
413 CharstringsOffset => Entry::CharstringsOffset(stack.pop_i32()? as usize),
414 PrivateDictRange => {
415 let len = stack.get_i32(0)? as usize;
416 let start = stack.get_i32(1)? as usize;
417 let end = start.checked_add(len).ok_or(ReadError::OutOfBounds)?;
418 Entry::PrivateDictRange(start..end)
419 }
420 VariationStoreOffset => Entry::VariationStoreOffset(stack.pop_i32()? as usize),
421 Copyright => Entry::Copyright(stack.pop_i32()?.into()),
422 IsFixedPitch => Entry::IsFixedPitch(stack.pop_i32()? != 0),
423 ItalicAngle => Entry::ItalicAngle(stack.pop_fixed()?),
424 UnderlinePosition => Entry::UnderlinePosition(stack.pop_fixed()?),
425 UnderlineThickness => Entry::UnderlineThickness(stack.pop_fixed()?),
426 PaintType => Entry::PaintType(stack.pop_i32()?),
427 CharstringType => Entry::CharstringType(stack.pop_i32()?),
428 FontMatrix => unreachable!(),
429 StrokeWidth => Entry::StrokeWidth(stack.pop_fixed()?),
430 FdArrayOffset => Entry::FdArrayOffset(stack.pop_i32()? as usize),
431 FdSelectOffset => Entry::FdSelectOffset(stack.pop_i32()? as usize),
432 BlueValues => {
433 stack.apply_delta_prefix_sum();
434 Entry::BlueValues(Blues::new(stack.fixed_values()))
435 }
436 OtherBlues => {
437 stack.apply_delta_prefix_sum();
438 Entry::OtherBlues(Blues::new(stack.fixed_values()))
439 }
440 FamilyBlues => {
441 stack.apply_delta_prefix_sum();
442 Entry::FamilyBlues(Blues::new(stack.fixed_values()))
443 }
444 FamilyOtherBlues => {
445 stack.apply_delta_prefix_sum();
446 Entry::FamilyOtherBlues(Blues::new(stack.fixed_values()))
447 }
448 SubrsOffset => Entry::SubrsOffset(stack.pop_i32()? as usize),
449 VariationStoreIndex => Entry::VariationStoreIndex(stack.pop_i32()? as u16),
450 BlueScale => Entry::BlueScale(stack.pop_fixed()?),
451 BlueShift => Entry::BlueShift(stack.pop_fixed()?),
452 BlueFuzz => Entry::BlueFuzz(stack.pop_fixed()?),
453 LanguageGroup => Entry::LanguageGroup(stack.pop_i32()?),
454 ExpansionFactor => Entry::ExpansionFactor(stack.pop_fixed()?),
455 Encoding => Entry::Encoding(stack.pop_i32()? as usize),
456 Charset => Entry::Charset(stack.pop_i32()? as usize),
457 UniqueId => Entry::UniqueId(stack.pop_i32()?),
458 Xuid => Entry::Xuid,
459 SyntheticBase => Entry::SyntheticBase(stack.pop_i32()?),
460 PostScript => Entry::PostScript(stack.pop_i32()?.into()),
461 BaseFontName => Entry::BaseFontName(stack.pop_i32()?.into()),
462 BaseFontBlend => Entry::BaseFontBlend,
463 Ros => Entry::Ros {
464 registry: stack.get_i32(0)?.into(),
465 ordering: stack.get_i32(1)?.into(),
466 supplement: stack.get_fixed(2)?,
467 },
468 CidFontVersion => Entry::CidFontVersion(stack.pop_fixed()?),
469 CidFontRevision => Entry::CidFontRevision(stack.pop_fixed()?),
470 CidFontType => Entry::CidFontType(stack.pop_i32()?),
471 CidCount => Entry::CidCount(stack.pop_i32()? as u32),
472 UidBase => Entry::UidBase(stack.pop_i32()?),
473 FontName => Entry::FontName(stack.pop_i32()?.into()),
474 StdHw => Entry::StdHw(stack.pop_fixed()?),
475 StdVw => Entry::StdVw(stack.pop_fixed()?),
476 DefaultWidthX => Entry::DefaultWidthX(stack.pop_fixed()?),
477 NominalWidthX => Entry::NominalWidthX(stack.pop_fixed()?),
478 StemSnapH => {
479 stack.apply_delta_prefix_sum();
480 Entry::StemSnapH(StemSnaps::new(stack.fixed_values()))
481 }
482 StemSnapV => {
483 stack.apply_delta_prefix_sum();
484 Entry::StemSnapV(StemSnaps::new(stack.fixed_values()))
485 }
486 ForceBold => Entry::ForceBold(stack.pop_i32()? != 0),
487 InitialRandomSeed => Entry::InitialRandomSeed(stack.pop_i32()?),
488 Blend => unreachable!(),
490 })
491}
492
493fn parse_font_matrix(cursor: &mut Cursor) -> Option<([Fixed; 6], i32)> {
497 let mut values = [Fixed::ZERO; 6];
498 let mut scalings = [0i32; 6];
499 let mut max_scaling = i32::MIN;
500 let mut min_scaling = i32::MAX;
501 for (value, scaling) in values.iter_mut().zip(&mut scalings) {
502 let (v, s) = parse_fixed_dynamic(cursor).ok()?;
503 if v != Fixed::ZERO {
504 max_scaling = max_scaling.max(s);
505 min_scaling = min_scaling.min(s);
506 }
507 *value = v;
508 *scaling = s;
509 }
510 if !(-9..=0).contains(&max_scaling)
511 || (max_scaling - min_scaling < 0)
512 || (max_scaling - min_scaling) > 9
513 {
514 return None;
515 }
516 for (value, scaling) in values.iter_mut().zip(scalings) {
517 if *value == Fixed::ZERO {
518 continue;
519 }
520 let divisor = BCD_POWER_TENS[(max_scaling - scaling) as usize];
521 let half_divisor = divisor >> 1;
522 if *value < Fixed::ZERO {
523 if i32::MIN + half_divisor < value.to_bits() {
524 *value = Fixed::from_bits((value.to_bits() - half_divisor) / divisor);
525 } else {
526 *value = Fixed::from_bits(i32::MIN / divisor);
527 }
528 } else if i32::MAX - half_divisor > value.to_bits() {
529 *value = Fixed::from_bits((value.to_bits() + half_divisor) / divisor);
530 } else {
531 *value = Fixed::from_bits(i32::MAX / divisor);
532 }
533 }
534 if is_degenerate(&values) {
536 return None;
537 }
538 let upem = BCD_POWER_TENS[(-max_scaling) as usize];
539 Some((values, upem))
540}
541
542pub fn normalize_font_matrix(mut matrix: [Fixed; 6], mut scaled_upem: i32) -> ([Fixed; 6], i32) {
545 let factor = if matrix[3] != Fixed::ZERO {
547 matrix[3].abs()
548 } else {
549 matrix[1].abs()
551 };
552 if factor != Fixed::ONE {
553 scaled_upem = (Fixed::from_bits(scaled_upem) / factor).to_bits();
554 for value in &mut matrix {
555 *value /= factor;
556 }
557 }
558 for offset in matrix[4..6].iter_mut() {
560 *offset = Fixed::from_bits(offset.to_bits() >> 16);
561 }
562 (matrix, scaled_upem)
563}
564
565fn is_degenerate(matrix: &[Fixed; 6]) -> bool {
568 let [mut xx, mut yx, mut xy, mut yy, ..] = matrix.map(|x| x.to_bits() as i64);
569 let val = xx.abs() | yx.abs() | xy.abs() | yy.abs();
570 if val == 0 || val > 0x7FFFFFFF {
571 return true;
572 }
573 let msb = 32 - (val as i32).leading_zeros() - 1;
575 let shift = msb as i32 - 12;
576 if shift > 0 {
577 xx >>= shift;
578 xy >>= shift;
579 yx >>= shift;
580 yy >>= shift;
581 }
582 let temp1 = 32 * (xx * yy - xy * yx).abs();
583 let temp2 = (xx * xx) + (xy * xy) + (yx * yx) + (yy * yy);
584 if temp1 <= temp2 {
585 return true;
586 }
587 false
588}
589
590const MAX_BLUE_VALUES: usize = 7;
592
593#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
598pub struct Blues {
599 values: [(Fixed, Fixed); MAX_BLUE_VALUES],
600 len: u32,
601}
602
603impl Blues {
604 pub fn new(values: impl Iterator<Item = Fixed>) -> Self {
605 let mut blues = Self::default();
606 let mut stash = Fixed::ZERO;
607 for (i, value) in values.take(MAX_BLUE_VALUES * 2).enumerate() {
608 if (i & 1) == 0 {
609 stash = value;
610 } else {
611 blues.values[i / 2] = (stash, value);
612 blues.len += 1;
613 }
614 }
615 blues
616 }
617
618 pub fn values(&self) -> &[(Fixed, Fixed)] {
619 &self.values[..self.len as usize]
620 }
621}
622
623const MAX_STEM_SNAPS: usize = 12;
627
628#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
632pub struct StemSnaps {
633 values: [Fixed; MAX_STEM_SNAPS],
634 len: u32,
635}
636
637impl StemSnaps {
638 fn new(values: impl Iterator<Item = Fixed>) -> Self {
639 let mut snaps = Self::default();
640 for (value, target_value) in values.take(MAX_STEM_SNAPS).zip(&mut snaps.values) {
641 *target_value = value;
642 snaps.len += 1;
643 }
644 snaps
645 }
646
647 pub fn values(&self) -> &[Fixed] {
648 &self.values[..self.len as usize]
649 }
650}
651
652#[inline]
653pub(crate) fn parse_int(cursor: &mut Cursor, b0: u8) -> Result<i32, Error> {
654 Ok(match b0 {
663 32..=246 => b0 as i32 - 139,
664 247..=250 => (b0 as i32 - 247) * 256 + cursor.read::<u8>()? as i32 + 108,
665 251..=254 => -(b0 as i32 - 251) * 256 - cursor.read::<u8>()? as i32 - 108,
666 28 => cursor.read::<i16>()? as i32,
667 29 => cursor.read::<i32>()?,
668 _ => {
669 return Err(Error::InvalidNumber);
670 }
671 })
672}
673
674const BCD_OVERFLOW: Fixed = Fixed::from_bits(0x7FFFFFFF);
679const BCD_UNDERFLOW: Fixed = Fixed::ZERO;
681const BCD_NUMBER_LIMIT: i32 = 0xCCCCCCC;
684const BCD_INTEGER_LIMIT: i32 = 0x7FFF;
686
687const BCD_POWER_TENS: [i32; 10] = [
689 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000,
690];
691
692#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
695pub struct BcdComponents {
696 error: Option<Fixed>,
700 number: i32,
701 sign: i32,
702 exponent: i32,
703 exponent_add: i32,
704 integer_len: i32,
705 fraction_len: i32,
706}
707
708impl BcdComponents {
709 fn parse(cursor: &mut Cursor) -> Result<Self, Error> {
712 enum Phase {
713 Integer,
714 Fraction,
715 Exponent,
716 }
717 let mut phase = Phase::Integer;
718 let mut sign = 1i32;
719 let mut exponent_sign = 1i32;
720 let mut number = 0i32;
721 let mut exponent = 0i32;
722 let mut exponent_add = 0i32;
723 let mut integer_len = 0;
724 let mut fraction_len = 0;
725 'outer: loop {
736 let b = cursor.read::<u8>()?;
737 for nibble in [(b >> 4) & 0xF, b & 0xF] {
738 match phase {
739 Phase::Integer => match nibble {
740 0x0..=0x9 => {
741 if number >= BCD_NUMBER_LIMIT {
742 exponent_add += 1;
743 } else if nibble != 0 || number != 0 {
744 number = number * 10 + nibble as i32;
745 integer_len += 1;
746 }
747 }
748 0xE => sign = -1,
749 0xA => {
750 phase = Phase::Fraction;
751 }
752 0xB => {
753 phase = Phase::Exponent;
754 }
755 0xC => {
756 phase = Phase::Exponent;
757 exponent_sign = -1;
758 }
759 _ => break 'outer,
760 },
761 Phase::Fraction => match nibble {
762 0x0..=0x9 => {
763 if nibble == 0 && number == 0 {
764 exponent_add -= 1;
765 } else if number < BCD_NUMBER_LIMIT && fraction_len < 9 {
766 number = number * 10 + nibble as i32;
767 fraction_len += 1;
768 }
769 }
770 0xB => {
771 phase = Phase::Exponent;
772 }
773 0xC => {
774 phase = Phase::Exponent;
775 exponent_sign = -1;
776 }
777 _ => break 'outer,
778 },
779 Phase::Exponent => {
780 match nibble {
781 0x0..=0x9 => {
782 if exponent > 1000 {
784 return if exponent_sign == -1 {
785 Ok(BCD_UNDERFLOW.into())
786 } else {
787 Ok(BCD_OVERFLOW.into())
788 };
789 } else {
790 exponent = exponent * 10 + nibble as i32;
791 }
792 }
793 _ => break 'outer,
794 }
795 }
796 }
797 }
798 }
799 exponent *= exponent_sign;
800 Ok(Self {
801 error: None,
802 number,
803 sign,
804 exponent,
805 exponent_add,
806 integer_len,
807 fraction_len,
808 })
809 }
810
811 pub fn value(&self, scale_by_1000: bool) -> Fixed {
815 if let Some(error) = self.error {
816 return error;
817 }
818 let mut number = self.number;
819 if number == 0 {
820 return Fixed::ZERO;
821 }
822 let mut exponent = self.exponent;
823 let mut integer_len = self.integer_len;
824 let mut fraction_len = self.fraction_len;
825 if scale_by_1000 {
826 exponent += 3 + self.exponent_add;
827 } else {
828 exponent += self.exponent_add;
829 }
830 integer_len += exponent;
831 fraction_len -= exponent;
832 if integer_len > 5 {
833 return BCD_OVERFLOW;
834 }
835 if integer_len < -5 {
836 return BCD_UNDERFLOW;
837 }
838 if integer_len < 0 {
840 number /= BCD_POWER_TENS[(-integer_len) as usize];
841 fraction_len += integer_len;
842 }
843 if fraction_len == 10 {
845 number /= 10;
846 fraction_len -= 1;
847 }
848 let mut result = if fraction_len > 0 {
850 let b = BCD_POWER_TENS[fraction_len as usize];
851 if number / b > BCD_INTEGER_LIMIT {
852 0
853 } else {
854 (Fixed::from_bits(number) / Fixed::from_bits(b)).to_bits()
855 }
856 } else {
857 number = number.wrapping_mul(BCD_POWER_TENS[-fraction_len as usize]);
858 if number > BCD_INTEGER_LIMIT {
859 return BCD_OVERFLOW;
860 } else {
861 number << 16
862 }
863 };
864 if scale_by_1000 {
865 result = (Fixed::from_bits(result) / Fixed::from_i32(1000)).to_bits();
869 }
870 Fixed::from_bits(result * self.sign)
871 }
872
873 fn dynamically_scaled_value(&self) -> (Fixed, i32) {
880 if let Some(error) = self.error {
881 return (error, 0);
882 }
883 let mut number = self.number;
884 if number == 0 {
885 return (Fixed::ZERO, 0);
886 }
887 let mut exponent = self.exponent;
888 let integer_len = self.integer_len;
889 let mut fraction_len = self.fraction_len;
890 exponent += self.exponent_add;
891 fraction_len += integer_len;
892 exponent += integer_len;
893 let result;
894 let scaling;
895 if fraction_len <= 5 {
896 if number > BCD_INTEGER_LIMIT {
897 result = Fixed::from_bits(number) / Fixed::from_bits(10);
898 scaling = exponent - fraction_len + 1;
899 } else {
900 if exponent > 0 {
901 let new_fraction_len = exponent.min(5);
903 let shift = new_fraction_len - fraction_len;
904 if shift > 0 {
905 exponent -= new_fraction_len;
906 number *= BCD_POWER_TENS[shift as usize];
907 if number > BCD_INTEGER_LIMIT {
908 number /= 10;
909 exponent += 1;
910 }
911 } else {
912 exponent -= fraction_len;
913 }
914 } else {
915 exponent -= fraction_len;
916 }
917 result = Fixed::from_bits(number << 16);
918 scaling = exponent;
919 }
920 } else if (number / BCD_POWER_TENS[fraction_len as usize - 5]) > BCD_INTEGER_LIMIT {
921 result = Fixed::from_bits(number)
922 / Fixed::from_bits(BCD_POWER_TENS[fraction_len as usize - 4]);
923 scaling = exponent - 4;
924 } else {
925 result = Fixed::from_bits(number)
926 / Fixed::from_bits(BCD_POWER_TENS[fraction_len as usize - 5]);
927 scaling = exponent - 5;
928 }
929 (Fixed::from_bits(result.to_bits() * self.sign), scaling)
930 }
931}
932
933impl From<Fixed> for BcdComponents {
934 fn from(value: Fixed) -> Self {
935 Self {
936 error: Some(value),
937 ..Default::default()
938 }
939 }
940}
941
942#[cfg(test)]
943mod tests {
944 use font_test_data::bebuffer::BeBuffer;
945
946 use super::*;
947 use crate::{
948 tables::variations::ItemVariationStore, types::F2Dot14, FontData, FontRead, FontRef,
949 TableProvider,
950 };
951
952 #[test]
953 fn int_operands() {
954 let empty = FontData::new(&[]);
956 let min_byte = FontData::new(&[0]);
957 let max_byte = FontData::new(&[255]);
958 assert_eq!(parse_int(&mut empty.cursor(), 32).unwrap(), -107);
960 assert_eq!(parse_int(&mut empty.cursor(), 246).unwrap(), 107);
961 assert_eq!(parse_int(&mut min_byte.cursor(), 247).unwrap(), 108);
963 assert_eq!(parse_int(&mut max_byte.cursor(), 250).unwrap(), 1131);
964 assert_eq!(parse_int(&mut min_byte.cursor(), 251).unwrap(), -108);
966 assert_eq!(parse_int(&mut max_byte.cursor(), 254).unwrap(), -1131);
967 }
968
969 #[test]
970 fn binary_coded_decimal_operands() {
971 let bytes = FontData::new(&[0xe2, 0xa2, 0x5f]);
980 assert_eq!(
981 BcdComponents::parse(&mut bytes.cursor())
982 .unwrap()
983 .value(false),
984 Fixed::from_f64(-2.25)
985 );
986 let bytes = FontData::new(&[0x0a, 0x14, 0x05, 0x41, 0xc3, 0xff]);
987 assert_eq!(
988 BcdComponents::parse(&mut bytes.cursor())
989 .unwrap()
990 .value(false),
991 Fixed::from_f64(0.140541E-3)
992 );
993 let bytes = FontData::new(&[0x37, 0x5c, 0x4f]);
997 assert_eq!(
998 BcdComponents::parse(&mut bytes.cursor())
999 .unwrap()
1000 .value(false),
1001 Fixed::from_f64(0.0370025634765625)
1002 );
1003 }
1004
1005 #[test]
1006 fn scaled_binary_coded_decimal_operands() {
1007 let bytes = FontData::new(&[0xA, 0x06, 0x25, 0xf]);
1010 assert_eq!(
1011 BcdComponents::parse(&mut bytes.cursor())
1012 .unwrap()
1013 .value(true),
1014 Fixed::from_f64(0.0625)
1015 );
1016 let bytes = FontData::new(&[0x37, 0x5c, 0x4f]);
1019 assert_eq!(
1020 BcdComponents::parse(&mut bytes.cursor())
1021 .unwrap()
1022 .value(true),
1023 Fixed::from_f64(0.037506103515625)
1024 );
1025 }
1026
1027 #[test]
1028 fn example_top_dict_tokens() {
1029 use Operator::*;
1030 let top_dict_data = &font_test_data::cff2::EXAMPLE[5..12];
1031 let tokens: Vec<_> = tokens(top_dict_data).map(|entry| entry.unwrap()).collect();
1032 let expected: &[Token] = &[
1033 68.into(),
1034 FdArrayOffset.into(),
1035 56.into(),
1036 CharstringsOffset.into(),
1037 16.into(),
1038 VariationStoreOffset.into(),
1039 ];
1040 assert_eq!(&tokens, expected);
1041 }
1042
1043 #[test]
1044 fn example_top_dict_entries() {
1045 use Entry::*;
1046 let top_dict_data = &font_test_data::cff2::EXAMPLE[0x5..=0xB];
1047 let entries: Vec<_> = entries(top_dict_data, None)
1048 .map(|entry| entry.unwrap())
1049 .collect();
1050 let expected: &[Entry] = &[
1051 FdArrayOffset(68),
1052 CharstringsOffset(56),
1053 VariationStoreOffset(16),
1054 ];
1055 assert_eq!(&entries, expected);
1056 }
1057
1058 #[test]
1059 fn example_private_dict_entries() {
1060 use Entry::*;
1061 let private_dict_data = &font_test_data::cff2::EXAMPLE[0x4f..=0xc0];
1062 let store =
1063 ItemVariationStore::read(FontData::new(&font_test_data::cff2::EXAMPLE[18..])).unwrap();
1064 let coords = &[F2Dot14::from_f32(0.0)];
1065 let blend_state = BlendState::new(store, coords, 0).unwrap();
1066 let entries: Vec<_> = entries(private_dict_data, Some(blend_state))
1067 .map(|entry| entry.unwrap())
1068 .collect();
1069 fn make_blues(values: &[f64]) -> Blues {
1070 Blues::new(values.iter().copied().map(Fixed::from_f64))
1071 }
1072 fn make_stem_snaps(values: &[f64]) -> StemSnaps {
1073 StemSnaps::new(values.iter().copied().map(Fixed::from_f64))
1074 }
1075 let expected: &[Entry] = &[
1076 BlueValues(make_blues(&[
1077 -20.0, 0.0, 472.0, 490.0, 525.0, 540.0, 645.0, 660.0, 670.0, 690.0, 730.0, 750.0,
1078 ])),
1079 OtherBlues(make_blues(&[-250.0, -240.0])),
1080 FamilyBlues(make_blues(&[
1081 -20.0, 0.0, 473.0, 491.0, 525.0, 540.0, 644.0, 659.0, 669.0, 689.0, 729.0, 749.0,
1082 ])),
1083 FamilyOtherBlues(make_blues(&[-249.0, -239.0])),
1084 BlueScale(Fixed::from_f64(0.037506103515625)),
1085 BlueFuzz(Fixed::ZERO),
1086 StdHw(Fixed::from_f64(55.0)),
1087 StdVw(Fixed::from_f64(80.0)),
1088 StemSnapH(make_stem_snaps(&[40.0, 55.0])),
1089 StemSnapV(make_stem_snaps(&[80.0, 90.0])),
1090 SubrsOffset(114),
1091 ];
1092 assert_eq!(&entries, expected);
1093 }
1094
1095 #[test]
1096 fn noto_serif_display_top_dict_entries() {
1097 use Entry::*;
1098 let top_dict_data = FontRef::new(font_test_data::NOTO_SERIF_DISPLAY_TRIMMED)
1099 .unwrap()
1100 .cff()
1101 .unwrap()
1102 .top_dicts()
1103 .get(0)
1104 .unwrap();
1105 let entries: Vec<_> = entries(top_dict_data, None)
1106 .map(|entry| entry.unwrap())
1107 .collect();
1108 let expected = &[
1109 Version(StringId::new(391)),
1110 Notice(StringId::new(392)),
1111 Copyright(StringId::new(393)),
1112 FullName(StringId::new(394)),
1113 FamilyName(StringId::new(395)),
1114 FontBbox([-693.0, -470.0, 2797.0, 1048.0].map(Fixed::from_f64)),
1115 Charset(517),
1116 PrivateDictRange(549..587),
1117 CharstringsOffset(521),
1118 ];
1119 assert_eq!(&entries, expected);
1120 }
1121
1122 #[test]
1127 fn private_dict_range_avoid_overflow() {
1128 let private_dict = BeBuffer::new()
1131 .push(29u8) .push(-1i32) .push(29u8) .push(-1i32) .push(18u8) .to_vec();
1137 let _ = entries(&private_dict, None).count();
1139 }
1140
1141 #[test]
1142 fn dynamically_scaled_binary_coded_decimal_operands() {
1143 let bytes = FontData::new(&[0xA, 0x06, 0x25, 0xf]);
1145 assert_eq!(
1146 BcdComponents::parse(&mut bytes.cursor())
1147 .unwrap()
1148 .dynamically_scaled_value(),
1149 (Fixed::from_f64(6250.0), -5)
1150 );
1151 let bytes = FontData::new(&[0x37, 0x5c, 0x4f]);
1153 assert_eq!(
1154 BcdComponents::parse(&mut bytes.cursor())
1155 .unwrap()
1156 .dynamically_scaled_value(),
1157 (Fixed::from_f64(375.0), -4)
1158 );
1159 let bytes = FontData::new(&[0xa0, 0x1, 0x95, 0x31, 0x25, 0xff]);
1161 assert_eq!(
1162 BcdComponents::parse(&mut bytes.cursor())
1163 .unwrap()
1164 .dynamically_scaled_value(),
1165 (Fixed::from_bits(1280000000), -7)
1166 );
1167 }
1168
1169 #[test]
1171 fn blue_scale_fraction_length_of_0() {
1172 let bytes = FontData::new(&[0x37, 0xC3, 0xFF]);
1174 assert_eq!(
1175 BcdComponents::parse(&mut bytes.cursor())
1176 .unwrap()
1177 .value(true),
1178 Fixed::from_f64(0.0370025634765625)
1179 );
1180 }
1181
1182 #[test]
1183 fn read_font_matrix() {
1184 let dict_data = [
1185 30u8, 10, 0, 31, 139, 30, 10, 0, 1, 103, 255, 30, 10, 0, 31, 139, 139, 12, 7,
1186 ];
1187 let Entry::FontMatrix(matrix, _) = entries(&dict_data, None).next().unwrap().unwrap()
1188 else {
1189 panic!("This was totally a font matrix");
1190 };
1191 assert_eq!(
1194 matrix,
1195 [
1196 Fixed::ONE,
1197 Fixed::ZERO,
1198 Fixed::from_f64(0.167007446289062),
1199 Fixed::ONE,
1200 Fixed::ZERO,
1201 Fixed::ZERO,
1202 ]
1203 );
1204 }
1205
1206 #[test]
1207 fn parse_degenerate_font_matrix() {
1208 let dict_data = [
1209 30u8, 0x0F, 30, 0x0F, 30, 0x0F, 30, 0x0F, 30, 0x0F, 30, 0x0F, 12, 7,
1210 ];
1211 assert!(entries(&dict_data, None).next().is_none());
1213 }
1214
1215 #[test]
1217 fn degenerate_matrix_check_doesnt_overflow() {
1218 let matrix = [
1220 Fixed::from_bits(639999672),
1221 Fixed::ZERO,
1222 Fixed::ZERO,
1223 Fixed::from_bits(639999672),
1224 Fixed::ZERO,
1225 Fixed::ZERO,
1226 ];
1227 is_degenerate(&matrix);
1229 is_degenerate(&[Fixed::MAX; 6]);
1231 is_degenerate(&[Fixed::MIN; 6]);
1233 }
1234
1235 #[test]
1236 fn normalize_matrix() {
1237 let matrix = [65536, 0, 0, 32768, 0, 0].map(Fixed::from_bits);
1240 let (normalized, scale) = normalize_font_matrix(matrix, 1);
1241 let expected_normalized = [131072, 0, 0, 65536, 0, 0].map(Fixed::from_bits);
1242 assert_eq!(normalized, expected_normalized);
1243 assert_eq!(scale, 2);
1244 }
1245}