tiny_skia_path/
floating_point.rs

1// Copyright 2006 The Android Open Source Project
2// Copyright 2020 Yevhenii Reizner
3//
4// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6
7use crate::scalar::Scalar;
8
9pub use strict_num::{FiniteF32, NonZeroPositiveF32, NormalizedF32};
10
11#[cfg(all(not(feature = "std"), feature = "no-std-float"))]
12use crate::NoStdFloat;
13
14pub(crate) const FLOAT_PI: f32 = 3.14159265;
15
16const MAX_I32_FITS_IN_F32: f32 = 2147483520.0;
17const MIN_I32_FITS_IN_F32: f32 = -MAX_I32_FITS_IN_F32;
18
19// TODO: is there an std alternative?
20/// Custom float to integer conversion routines.
21pub trait SaturateCast<T>: Sized {
22    /// Return the closest integer for the given float.
23    fn saturate_from(n: T) -> Self;
24}
25
26impl SaturateCast<f32> for i32 {
27    /// Return the closest integer for the given float.
28    ///
29    /// Returns MAX_I32_FITS_IN_F32 for NaN.
30    fn saturate_from(mut x: f32) -> Self {
31        x = if x < MAX_I32_FITS_IN_F32 {
32            x
33        } else {
34            MAX_I32_FITS_IN_F32
35        };
36        x = if x > MIN_I32_FITS_IN_F32 {
37            x
38        } else {
39            MIN_I32_FITS_IN_F32
40        };
41        x as i32
42    }
43}
44
45impl SaturateCast<f64> for i32 {
46    /// Return the closest integer for the given double.
47    ///
48    /// Returns i32::MAX for NaN.
49    fn saturate_from(mut x: f64) -> Self {
50        x = if x < i32::MAX as f64 {
51            x
52        } else {
53            i32::MAX as f64
54        };
55        x = if x > i32::MIN as f64 {
56            x
57        } else {
58            i32::MIN as f64
59        };
60        x as i32
61    }
62}
63
64/// Custom float to integer rounding routines.
65#[allow(missing_docs)]
66pub trait SaturateRound<T>: SaturateCast<T> {
67    fn saturate_floor(n: T) -> Self;
68    fn saturate_ceil(n: T) -> Self;
69    fn saturate_round(n: T) -> Self;
70}
71
72impl SaturateRound<f32> for i32 {
73    fn saturate_floor(x: f32) -> Self {
74        Self::saturate_from(x.floor())
75    }
76
77    fn saturate_ceil(x: f32) -> Self {
78        Self::saturate_from(x.ceil())
79    }
80
81    fn saturate_round(x: f32) -> Self {
82        Self::saturate_from(x.floor() + 0.5)
83    }
84}
85
86/// Return the float as a 2s compliment int. Just to be used to compare floats
87/// to each other or against positive float-bit-constants (like 0). This does
88/// not return the int equivalent of the float, just something cheaper for
89/// compares-only.
90pub(crate) fn f32_as_2s_compliment(x: f32) -> i32 {
91    sign_bit_to_2s_compliment(bytemuck::cast(x))
92}
93
94/// Convert a sign-bit int (i.e. float interpreted as int) into a 2s compliement
95/// int. This also converts -0 (0x80000000) to 0. Doing this to a float allows
96/// it to be compared using normal C operators (<, <=, etc.)
97fn sign_bit_to_2s_compliment(mut x: i32) -> i32 {
98    if x < 0 {
99        x &= 0x7FFFFFFF;
100        x = -x;
101    }
102
103    x
104}
105
106/// An immutable `f32` that is larger than 0 but less then 1.
107#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default, Debug)]
108#[repr(transparent)]
109pub struct NormalizedF32Exclusive(FiniteF32);
110
111impl NormalizedF32Exclusive {
112    /// Just a random, valid number.
113    pub const ANY: Self = Self::HALF;
114
115    /// A predefined 0.5 value.
116    pub const HALF: Self = NormalizedF32Exclusive(unsafe { FiniteF32::new_unchecked(0.5) });
117
118    /// Creates a `NormalizedF32Exclusive`.
119    pub fn new(n: f32) -> Option<Self> {
120        if n > 0.0 && n < 1.0 {
121            // `n` is guarantee to be finite after the bounds check.
122            FiniteF32::new(n).map(NormalizedF32Exclusive)
123        } else {
124            None
125        }
126    }
127
128    /// Creates a `NormalizedF32Exclusive` clamping the given value.
129    ///
130    /// Returns zero in case of NaN or infinity.
131    pub fn new_bounded(n: f32) -> Self {
132        let n = n.bound(f32::EPSILON, 1.0 - f32::EPSILON);
133        // `n` is guarantee to be finite after clamping.
134        debug_assert!(n.is_finite());
135        NormalizedF32Exclusive(unsafe { FiniteF32::new_unchecked(n) })
136    }
137
138    /// Returns the value as a primitive type.
139    pub fn get(self) -> f32 {
140        self.0.get()
141    }
142
143    /// Returns the value as a `FiniteF32`.
144    pub fn to_normalized(self) -> NormalizedF32 {
145        // NormalizedF32 is (0,1), while NormalizedF32 is [0,1], so it will always fit.
146        unsafe { NormalizedF32::new_unchecked(self.0.get()) }
147    }
148}