tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ratio.rs (3470B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
      4 
      5 //! `<ratio>` computed values.
      6 
      7 use crate::values::animated::{Animate, Procedure};
      8 use crate::values::computed::NonNegativeNumber;
      9 use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
     10 use crate::values::generics::ratio::Ratio as GenericRatio;
     11 use crate::values::generics::NonNegative;
     12 use crate::Zero;
     13 use std::cmp::Ordering;
     14 
     15 /// A computed <ratio> value.
     16 pub type Ratio = GenericRatio<NonNegativeNumber>;
     17 
     18 impl PartialOrd for Ratio {
     19    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
     20        f64::partial_cmp(
     21            &((self.0).0 as f64 * (other.1).0 as f64),
     22            &((self.1).0 as f64 * (other.0).0 as f64),
     23        )
     24    }
     25 }
     26 
     27 impl Ratio {
     28    /// Returns the f32 value by dividing the first value by the second one.
     29    #[inline]
     30    fn to_f32(&self) -> f32 {
     31        debug_assert!(!self.is_degenerate());
     32        (self.0).0 / (self.1).0
     33    }
     34    /// Returns a new Ratio.
     35    #[inline]
     36    pub fn new(a: f32, b: f32) -> Self {
     37        GenericRatio(a.into(), b.into())
     38    }
     39 }
     40 
     41 /// https://drafts.csswg.org/css-values/#combine-ratio
     42 impl Animate for Ratio {
     43    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
     44        // If either <ratio> is degenerate, the values cannot be interpolated.
     45        if self.is_degenerate() || other.is_degenerate() {
     46            return Err(());
     47        }
     48 
     49        // Addition of <ratio>s is not possible, and based on
     50        // https://drafts.csswg.org/css-values-4/#not-additive,
     51        // we simply use the first value as the result value.
     52        // Besides, the procedure for accumulation should be identical to addition here.
     53        if matches!(procedure, Procedure::Add | Procedure::Accumulate { .. }) {
     54            return Ok(self.clone());
     55        }
     56 
     57        // The interpolation of a <ratio> is defined by converting each <ratio> to a number by
     58        // dividing the first value by the second (so a ratio of 3 / 2 would become 1.5), taking
     59        // the logarithm of that result (so the 1.5 would become approximately 0.176), then
     60        // interpolating those values.
     61        //
     62        // The result during the interpolation is converted back to a <ratio> by inverting the
     63        // logarithm, then interpreting the result as a <ratio> with the result as the first value
     64        // and 1 as the second value.
     65        let start = self.to_f32().ln();
     66        let end = other.to_f32().ln();
     67        let e = std::f32::consts::E;
     68        let result = e.powf(start.animate(&end, procedure)?);
     69        // The range of the result is [0, inf), based on the easing function.
     70        if result.is_zero() || result.is_infinite() {
     71            return Err(());
     72        }
     73        Ok(GenericRatio(NonNegative(result), NonNegative(1.0)))
     74    }
     75 }
     76 
     77 impl ComputeSquaredDistance for Ratio {
     78    fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
     79        if self.is_degenerate() || other.is_degenerate() {
     80            return Err(());
     81        }
     82        // Use the distance of their logarithm values. (This is used by testing, so don't
     83        // need to care about the base. Here we use the same base as that in animate().)
     84        self.to_f32()
     85            .ln()
     86            .compute_squared_distance(&other.to_f32().ln())
     87    }
     88 }