tor-browser

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

time.rs (5713B)


      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 //! Specified time values.
      6 
      7 use crate::derives::*;
      8 use crate::parser::{Parse, ParserContext};
      9 use crate::values::computed::time::Time as ComputedTime;
     10 use crate::values::computed::{Context, ToComputedValue};
     11 use crate::values::specified::calc::CalcNode;
     12 use crate::values::CSSFloat;
     13 use crate::Zero;
     14 use cssparser::{match_ignore_ascii_case, Parser, Token};
     15 use std::fmt::{self, Write};
     16 use style_traits::values::specified::AllowedNumericType;
     17 use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss};
     18 
     19 /// A time value according to CSS-VALUES § 6.2.
     20 #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToShmem)]
     21 pub struct Time {
     22    seconds: CSSFloat,
     23    unit: TimeUnit,
     24    calc_clamping_mode: Option<AllowedNumericType>,
     25 }
     26 
     27 /// A time unit.
     28 #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToShmem)]
     29 pub enum TimeUnit {
     30    /// `s`
     31    Second,
     32    /// `ms`
     33    Millisecond,
     34 }
     35 
     36 impl Time {
     37    /// Returns a time value that represents `seconds` seconds.
     38    pub fn from_seconds_with_calc_clamping_mode(
     39        seconds: CSSFloat,
     40        calc_clamping_mode: Option<AllowedNumericType>,
     41    ) -> Self {
     42        Time {
     43            seconds,
     44            unit: TimeUnit::Second,
     45            calc_clamping_mode,
     46        }
     47    }
     48 
     49    /// Returns a time value that represents `seconds` seconds.
     50    pub fn from_seconds(seconds: CSSFloat) -> Self {
     51        Self::from_seconds_with_calc_clamping_mode(seconds, None)
     52    }
     53 
     54    /// Returns the time in fractional seconds.
     55    pub fn seconds(self) -> CSSFloat {
     56        self.seconds
     57    }
     58 
     59    /// Returns the unit of the time.
     60    #[inline]
     61    pub fn unit(&self) -> &'static str {
     62        match self.unit {
     63            TimeUnit::Second => "s",
     64            TimeUnit::Millisecond => "ms",
     65        }
     66    }
     67 
     68    #[inline]
     69    fn unitless_value(&self) -> CSSFloat {
     70        match self.unit {
     71            TimeUnit::Second => self.seconds,
     72            TimeUnit::Millisecond => self.seconds * 1000.,
     73        }
     74    }
     75 
     76    /// Parses a time according to CSS-VALUES § 6.2.
     77    pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Time, ()> {
     78        let (seconds, unit) = match_ignore_ascii_case! { unit,
     79            "s" => (value, TimeUnit::Second),
     80            "ms" => (value / 1000.0, TimeUnit::Millisecond),
     81            _ => return Err(())
     82        };
     83 
     84        Ok(Time {
     85            seconds,
     86            unit,
     87            calc_clamping_mode: None,
     88        })
     89    }
     90 
     91    fn parse_with_clamping_mode<'i, 't>(
     92        context: &ParserContext,
     93        input: &mut Parser<'i, 't>,
     94        clamping_mode: AllowedNumericType,
     95    ) -> Result<Self, ParseError<'i>> {
     96        use style_traits::ParsingMode;
     97 
     98        let location = input.current_source_location();
     99        match *input.next()? {
    100            // Note that we generally pass ParserContext to is_ok() to check
    101            // that the ParserMode of the ParserContext allows all numeric
    102            // values for SMIL regardless of clamping_mode, but in this Time
    103            // value case, the value does not animate for SMIL at all, so we use
    104            // ParsingMode::DEFAULT directly.
    105            Token::Dimension {
    106                value, ref unit, ..
    107            } if clamping_mode.is_ok(ParsingMode::DEFAULT, value) => {
    108                Time::parse_dimension(value, unit)
    109                    .map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
    110            },
    111            Token::Function(ref name) => {
    112                let function = CalcNode::math_function(context, name, location)?;
    113                CalcNode::parse_time(context, input, clamping_mode, function)
    114            },
    115            ref t => return Err(location.new_unexpected_token_error(t.clone())),
    116        }
    117    }
    118 
    119    /// Parses a non-negative time value.
    120    pub fn parse_non_negative<'i, 't>(
    121        context: &ParserContext,
    122        input: &mut Parser<'i, 't>,
    123    ) -> Result<Self, ParseError<'i>> {
    124        Self::parse_with_clamping_mode(context, input, AllowedNumericType::NonNegative)
    125    }
    126 }
    127 
    128 impl Zero for Time {
    129    #[inline]
    130    fn zero() -> Self {
    131        Self::from_seconds(0.0)
    132    }
    133 
    134    #[inline]
    135    fn is_zero(&self) -> bool {
    136        // The unit doesn't matter, i.e. `s` and `ms` are the same for zero.
    137        self.seconds == 0.0 && self.calc_clamping_mode.is_none()
    138    }
    139 }
    140 
    141 impl ToComputedValue for Time {
    142    type ComputedValue = ComputedTime;
    143 
    144    fn to_computed_value(&self, _context: &Context) -> Self::ComputedValue {
    145        let seconds = self
    146            .calc_clamping_mode
    147            .map_or(self.seconds(), |mode| mode.clamp(self.seconds()));
    148 
    149        ComputedTime::from_seconds(crate::values::normalize(seconds))
    150    }
    151 
    152    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
    153        Time {
    154            seconds: computed.seconds(),
    155            unit: TimeUnit::Second,
    156            calc_clamping_mode: None,
    157        }
    158    }
    159 }
    160 
    161 impl Parse for Time {
    162    fn parse<'i, 't>(
    163        context: &ParserContext,
    164        input: &mut Parser<'i, 't>,
    165    ) -> Result<Self, ParseError<'i>> {
    166        Self::parse_with_clamping_mode(context, input, AllowedNumericType::All)
    167    }
    168 }
    169 
    170 impl ToCss for Time {
    171    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
    172    where
    173        W: Write,
    174    {
    175        crate::values::serialize_specified_dimension(
    176            self.unitless_value(),
    177            self.unit(),
    178            self.calc_clamping_mode.is_some(),
    179            dest,
    180        )
    181    }
    182 }
    183 
    184 impl SpecifiedValueInfo for Time {}