1use std::fmt::Write;
6
7pub trait FontFormat: Sized {
9 const DEFAULT_FILE_EXTENSION: &'static str;
10 type Error: std::error::Error + 'static;
11
12 fn parse(b: &[u8]) -> Result<Self, Self::Error>;
14}
15
16#[derive(Default, PartialEq, Eq, Debug, Copy, Clone, PartialOrd, Ord, Hash)]
26#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
27pub struct Scaled(pub i32);
28
29impl Scaled {
30 pub const ZERO: Scaled = Scaled(0);
32
33 pub const ONE: Scaled = Scaled(1 << 16);
35
36 pub const TWO: Scaled = Scaled(1 << 17);
38
39 pub const MAX_DIMEN: Scaled = Scaled((1 << 30) - 1);
45
46 pub fn from_integer(i: i32) -> Result<Scaled, OverflowError> {
51 if i >= (1 << 14) || i <= -(1 << 14) {
52 Err(OverflowError {})
53 } else {
54 Ok(Scaled(Scaled::ONE.0 * i))
55 }
56 }
57
58 pub fn from_decimal_digits(digits: &[u8]) -> Scaled {
62 let mut a = 0;
63 for d in digits.iter().rev() {
64 a = (a + (*d as i32) * Scaled::TWO.0) / 10
65 }
66 Scaled((a + 1) / 2)
67 }
68
69 pub fn new(
73 integer_part: i32,
74 fractional_part: Scaled,
75 scaled_unit: ScaledUnit,
76 ) -> Result<Scaled, OverflowError> {
77 if scaled_unit == ScaledUnit::ScaledPoint {
78 return if integer_part > Scaled::MAX_DIMEN.0 {
79 Err(OverflowError)
80 } else {
81 Ok(Scaled(integer_part))
83 };
84 }
85 let (n, d) = scaled_unit.conversion_fraction();
86 let (Scaled(i), Scaled(remainder)) = Scaled(integer_part).xn_over_d(n, d)?;
88 let f =
89 fractional_part.nx_plus_y(n, Scaled::from_integer(remainder).expect("remainder<d<=7200<2^13, so a valid scaled number"))
90 .expect("fractional_part<2^16, remainder<2^16*d, so nx_plus_y<2^16(n+d). Each (n,d) makes this <2^30")
91 / d;
92 let integer_part = Scaled::from_integer(i + f.integer_part())?;
93 Ok(integer_part + f.fractional_part())
94 }
95
96 pub fn xn_over_d(&self, n: i32, d: i32) -> Result<(Scaled, Scaled), OverflowError> {
107 debug_assert!(n <= 0o200000);
108 debug_assert!(d <= 0o200000);
109 let mut b: i64 = self.0.into();
110 b *= n as i64; let remainder: i32 = (b % (d as i64)).try_into().expect("d<=2^16 so b%d<2^16");
112 b /= d as i64;
113 if b < -(Scaled::MAX_DIMEN.0 as i64) || b > Scaled::MAX_DIMEN.0 as i64 {
114 return Err(OverflowError {});
115 }
116 let b: i32 = b.try_into().expect("b in (-2^30, +2^30)");
117 Ok((Scaled(b), Scaled(remainder)))
118 }
119
120 pub fn nx_plus_y(self, mut n: i32, y: Scaled) -> Result<Scaled, OverflowError> {
122 let max_answer = Scaled::MAX_DIMEN;
123 if n == 0 {
124 return Ok(y);
125 }
126 let mut x = self;
127 if n < 0 {
128 n = -n;
129 x = -x;
130 }
131 if x <= (max_answer - y) / n && -x <= (max_answer + y) / n {
132 Ok(x * n + y)
133 } else {
134 Err(OverflowError {})
135 }
136 }
137
138 pub fn parse_from_string(s: &str) -> Result<Scaled, String> {
143 if s.len() < 3 {
144 return Err(format!(
145 "invalid dimension {s:?}: expected <number><unit> (e.g. 100pt)"
146 ));
147 }
148 let (value_str, unit_str) = s.split_at(s.len() - 2);
149 let unit = ScaledUnit::parse(unit_str)
150 .ok_or_else(|| format!("invalid unit {unit_str:?} in dimension {s:?}"))?;
151 let (int_str, frac_str) = match value_str.find('.') {
152 Some(pos) => (&value_str[..pos], &value_str[pos + 1..]),
153 None => (value_str, ""),
154 };
155 let integer_part: i32 = int_str
156 .parse()
157 .map_err(|_| format!("invalid number {int_str:?} in dimension {s:?}"))?;
158 let frac_digits: Vec<u8> = frac_str.chars().map(|c| c as u8 - b'0').collect();
159 if frac_digits.iter().any(|&d| d > 9) {
160 return Err(format!(
161 "invalid fractional part {frac_str:?} in dimension {s:?}"
162 ));
163 }
164 let fractional_part = Scaled::from_decimal_digits(&frac_digits);
165 Scaled::new(integer_part, fractional_part, unit)
166 .map_err(|_| format!("dimension {s:?} is out of range"))
167 }
168
169 pub fn integer_part(self) -> i32 {
170 self.0 / Scaled::ONE.0
171 }
172
173 pub fn fractional_part(self) -> Scaled {
174 self % Scaled::ONE.0
175 }
176
177 pub fn abs(self) -> Scaled {
178 Scaled(self.0.abs())
179 }
180
181 pub fn wrapping_add(self, rhs: Scaled) -> Self {
182 Scaled(self.0.wrapping_add(rhs.0))
183 }
184 pub fn checked_add(self, rhs: Scaled) -> Option<Self> {
185 Some(Scaled(self.0.checked_add(rhs.0)?))
186 }
187 pub fn wrapping_mul(self, rhs: i32) -> Self {
188 Scaled(self.0.wrapping_mul(rhs))
189 }
190 pub fn checked_mul(self, rhs: i32) -> Option<Self> {
191 self.nx_plus_y(rhs, Scaled::ZERO).ok()
194 }
195 pub fn checked_div(self, rhs: i32) -> Option<Self> {
196 Some(Scaled(self.0.checked_div(rhs)?))
197 }
198 pub fn display_no_units(self) -> impl std::fmt::Display {
200 struct D {
201 s: Scaled,
202 }
203 impl std::fmt::Display for D {
204 fn fmt(&self, fm: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
205 if self.s.0 < 0 {
206 write!(fm, "-")?;
207 }
208 write!(fm, "{}.", self.s.integer_part().abs())?;
209 let mut f = self.s.fractional_part().abs() * 10 + Scaled(5);
211 let mut delta = Scaled(10);
212 loop {
213 if delta > Scaled::ONE {
214 f += Scaled(0o100000 - 50000);
216 }
217 fm.write_char(
218 char::from_digit(f.integer_part().try_into().unwrap(), 10).unwrap(),
219 )?;
220 f = f.fractional_part() * 10;
221 delta = delta * 10;
222 if f <= delta {
223 break;
224 }
225 }
226 Ok(())
227 }
228 }
229 D { s: self }
230 }
231}
232
233#[derive(Debug)]
234pub struct OverflowError;
235
236impl std::fmt::Display for Scaled {
237 fn fmt(&self, fm: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
238 write!(fm, "{}", self.display_no_units())?;
240 write!(fm, "pt")?;
242 Ok(())
243 }
244}
245
246impl std::iter::Sum for Scaled {
247 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
248 Self(iter.map(|s| s.0).sum())
249 }
250}
251
252impl std::ops::Add<Scaled> for Scaled {
253 type Output = Scaled;
254 fn add(self, rhs: Scaled) -> Self::Output {
255 Scaled(self.0 + rhs.0)
256 }
257}
258
259impl std::ops::AddAssign<Scaled> for Scaled {
260 fn add_assign(&mut self, rhs: Scaled) {
261 self.0 += rhs.0;
262 }
263}
264
265impl std::ops::Sub<Scaled> for Scaled {
266 type Output = Scaled;
267 fn sub(self, rhs: Scaled) -> Self::Output {
268 Scaled(self.0 - rhs.0)
269 }
270}
271
272impl std::ops::SubAssign<Scaled> for Scaled {
273 fn sub_assign(&mut self, rhs: Scaled) {
274 self.0 -= rhs.0;
275 }
276}
277
278impl std::ops::Mul<i32> for Scaled {
279 type Output = Scaled;
280 fn mul(self, rhs: i32) -> Self::Output {
281 Scaled(self.0 * rhs)
282 }
283}
284
285impl std::ops::Div<i32> for Scaled {
286 type Output = Scaled;
287 fn div(self, rhs: i32) -> Self::Output {
288 Scaled(self.0 / rhs)
289 }
290}
291
292impl std::ops::DivAssign<i32> for Scaled {
293 fn div_assign(&mut self, rhs: i32) {
294 self.0 = self.0 / rhs
295 }
296}
297
298impl std::ops::Rem<i32> for Scaled {
299 type Output = Scaled;
300 fn rem(self, rhs: i32) -> Self::Output {
301 Scaled(self.0 % rhs)
302 }
303}
304
305impl std::ops::Neg for Scaled {
306 type Output = Scaled;
307 fn neg(self) -> Self::Output {
308 Scaled(-self.0)
309 }
310}
311
312#[derive(Debug, Clone, Copy, PartialEq, Eq)]
316pub enum ScaledUnit {
317 Point,
318 Pica,
319 Inch,
320 BigPoint,
321 Centimeter,
322 Millimeter,
323 DidotPoint,
324 Cicero,
325 ScaledPoint,
326}
327
328impl ScaledUnit {
329 pub fn parse(s: &str) -> Option<Self> {
334 use ScaledUnit::*;
335 Some(match s {
336 "pt" => Point,
337 "pc" => Pica,
338 "in" => Inch,
339 "bp" => BigPoint,
340 "cm" => Centimeter,
341 "mm" => Millimeter,
342 "dd" => DidotPoint,
343 "cc" => Cicero,
344 "sp" => ScaledPoint,
345 _ => return None,
346 })
347 }
348
349 pub fn conversion_fraction(&self) -> (i32, i32) {
357 use ScaledUnit::*;
358 match self {
359 Point => (1, 1),
360 Pica => (12, 1),
361 Inch => (7227, 100),
362 BigPoint => (7227, 7200),
363 Centimeter => (7227, 254),
364 Millimeter => (7227, 2540),
365 DidotPoint => (1238, 1157),
366 Cicero => (14856, 1157),
367 ScaledPoint => (1, 1 << 16),
368 }
369 }
370}
371
372#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
383#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
384pub struct Glue {
385 pub width: Scaled,
386 pub stretch: Scaled,
387 pub stretch_order: GlueOrder,
388 pub shrink: Scaled,
389 pub shrink_order: GlueOrder,
390}
391
392impl Glue {
393 pub const ZERO: Glue = Glue {
394 width: Scaled::ZERO,
395 stretch: Scaled::ZERO,
396 stretch_order: GlueOrder::Normal,
397 shrink: Scaled::ZERO,
398 shrink_order: GlueOrder::Normal,
399 };
400 pub fn is_zero(&self) -> bool {
401 self.width == Scaled::ZERO && self.stretch == Scaled::ZERO && self.shrink == Scaled::ZERO
402 }
403}
404
405impl std::ops::Mul<i32> for Glue {
406 type Output = Glue;
407 fn mul(self, rhs: i32) -> Self::Output {
408 Glue {
409 width: self.width * rhs,
410 stretch: self.stretch * rhs,
411 stretch_order: self.stretch_order,
412 shrink: self.shrink * rhs,
413 shrink_order: self.shrink_order,
414 }
415 }
416}
417
418impl Glue {
419 pub fn wrapping_add(self, rhs: Glue) -> Self {
421 use std::cmp::Ordering::*;
422 Glue {
423 width: self.width.wrapping_add(rhs.width),
424 stretch: match self.stretch_order.cmp(&rhs.stretch_order) {
425 Less => rhs.stretch,
426 Equal => self.stretch.wrapping_add(rhs.stretch),
427 Greater => self.stretch,
428 },
429 stretch_order: self.stretch_order.max(rhs.stretch_order),
430 shrink: match self.shrink_order.cmp(&rhs.shrink_order) {
431 Less => rhs.shrink,
432 Equal => self.shrink.wrapping_add(rhs.shrink),
433 Greater => self.shrink,
434 },
435 shrink_order: self.shrink_order.max(rhs.shrink_order),
436 }
437 }
438 pub fn checked_add(self, rhs: Glue) -> Option<Self> {
439 use std::cmp::Ordering::*;
440 Some(Glue {
441 width: self.width.checked_add(rhs.width)?,
442 stretch: match self.stretch_order.cmp(&rhs.stretch_order) {
443 Less => rhs.stretch,
444 Equal => self.stretch.checked_add(rhs.stretch)?,
445 Greater => self.stretch,
446 },
447 stretch_order: self.stretch_order.max(rhs.stretch_order),
448 shrink: match self.shrink_order.cmp(&rhs.shrink_order) {
449 Less => rhs.shrink,
450 Equal => self.shrink.checked_add(rhs.shrink)?,
451 Greater => self.shrink,
452 },
453 shrink_order: self.shrink_order.max(rhs.shrink_order),
454 })
455 }
456 pub fn checked_mul(self, rhs: i32) -> Option<Self> {
457 Some(Glue {
458 width: self.width.checked_mul(rhs)?,
459 stretch: self.stretch.checked_mul(rhs)?,
460 stretch_order: self.stretch_order,
461 shrink: self.shrink.checked_mul(rhs)?,
462 shrink_order: self.shrink_order,
463 })
464 }
465 pub fn wrapping_mul(self, rhs: i32) -> Self {
466 Glue {
467 width: self.width.wrapping_mul(rhs),
468 stretch: self.stretch.wrapping_mul(rhs),
469 stretch_order: self.stretch_order,
470 shrink: self.shrink.wrapping_mul(rhs),
471 shrink_order: self.shrink_order,
472 }
473 }
474 pub fn checked_div(self, rhs: i32) -> Option<Self> {
475 Some(Glue {
476 width: self.width.checked_div(rhs)?,
477 stretch: self.stretch.checked_div(rhs)?,
478 stretch_order: self.stretch_order,
479 shrink: self.shrink.checked_div(rhs)?,
480 shrink_order: self.shrink_order,
481 })
482 }
483}
484
485impl std::fmt::Display for Glue {
486 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
488 write!(f, "{}", self.width)?;
489 if self.stretch != Scaled::ZERO {
490 write!(f, " plus ")?;
491 write!(f, "{}", self.stretch.display_no_units())?;
492 write!(f, "{}", self.stretch_order)?;
493 }
494 if self.shrink != Scaled::ZERO {
495 write!(f, " minus ")?;
496 write!(f, "{}", self.shrink.display_no_units())?;
497 write!(f, "{}", self.shrink_order)?;
498 }
499 Ok(())
500 }
501}
502
503#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, PartialOrd, Ord)]
516#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
517pub enum GlueOrder {
518 #[default]
519 Normal,
520 Fil,
521 Fill,
522 Filll,
523}
524
525impl GlueOrder {
526 pub fn parse(s: &str) -> Option<Self> {
528 use GlueOrder::*;
529 Some(match s {
530 "fil" => Fil,
531 "fill" => Fill,
532 "filll" => Filll,
533 _ => return None,
534 })
535 }
536 pub fn inf_str(&self) -> Option<&'static str> {
537 use GlueOrder::*;
538 match self {
539 Normal => None,
540 Fil => Some("fil"),
541 Fill => Some("fill"),
542 Filll => Some("filll"),
543 }
544 }
545 pub fn next(&self) -> Option<Self> {
547 use GlueOrder::*;
548 match self {
549 Normal => Some(Fil),
550 Fil => Some(Fill),
551 Fill => Some(Filll),
552 Filll => None,
553 }
554 }
555}
556
557impl std::fmt::Display for GlueOrder {
558 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
559 write!(f, "{}", self.inf_str().unwrap_or("pt"))
560 }
561}
562
563#[cfg(test)]
564mod tests {
565 use super::*;
566
567 #[test]
568 fn type_sizes() {
569 assert_eq!(16, std::mem::size_of::<Glue>());
570 }
571
572 macro_rules! parse_from_string_tests {
573 ( $( $name:ident : $input:expr => $expected:expr, )* ) => {
574 $(
575 #[test]
576 fn $name() {
577 assert_eq!(Scaled::parse_from_string($input), $expected);
578 }
579 )*
580 };
581 }
582
583 parse_from_string_tests! {
584 integer_pt: "100pt" => Ok(Scaled::new(100, Scaled::ZERO, ScaledUnit::Point).unwrap()),
586 integer_pc: "6pc" => Ok(Scaled::new(6, Scaled::ZERO, ScaledUnit::Pica).unwrap()),
587 integer_in: "2in" => Ok(Scaled::new(2, Scaled::ZERO, ScaledUnit::Inch).unwrap()),
588 integer_bp: "72bp" => Ok(Scaled::new(72, Scaled::ZERO, ScaledUnit::BigPoint).unwrap()),
589 integer_cm: "10cm" => Ok(Scaled::new(10, Scaled::ZERO, ScaledUnit::Centimeter).unwrap()),
590 integer_mm: "25mm" => Ok(Scaled::new(25, Scaled::ZERO, ScaledUnit::Millimeter).unwrap()),
591 integer_dd: "10dd" => Ok(Scaled::new(10, Scaled::ZERO, ScaledUnit::DidotPoint).unwrap()),
592 integer_cc: "3cc" => Ok(Scaled::new(3, Scaled::ZERO, ScaledUnit::Cicero).unwrap()),
593 integer_sp: "65536sp" => Ok(Scaled(65536)),
594 fractional_pt: "72.27pt" => Ok(Scaled::new(72, Scaled::from_decimal_digits(&[2, 7]), ScaledUnit::Point).unwrap()),
596 fractional_in: "6.5in" => Ok(Scaled::new(6, Scaled::from_decimal_digits(&[5]), ScaledUnit::Inch).unwrap()),
597 zero_pt: "0pt" => Ok(Scaled::ZERO),
599 empty: "" => Err("invalid dimension \"\": expected <number><unit> (e.g. 100pt)".to_string()),
601 bad_unit: "10xx" => Err("invalid unit \"xx\" in dimension \"10xx\"".to_string()),
602 bad_number: "abpt" => Err("invalid number \"ab\" in dimension \"abpt\"".to_string()),
603 bad_fraction: "1.xpt" => Err("invalid fractional part \"x\" in dimension \"1.xpt\"".to_string()),
604 }
605
606 #[test]
607 fn print_smallest_scaled() {
608 assert_eq!("-32768.0pt", format!("{}", Scaled(i32::MIN)));
609 }
610
611 #[test]
612 fn glue_order_ordering() {
613 assert!(GlueOrder::Normal < GlueOrder::Fil);
614 assert!(GlueOrder::Fil < GlueOrder::Fill);
615 assert!(GlueOrder::Fill < GlueOrder::Filll);
616 }
617}