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