/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! Specified numbers and integers.
usecrate::derives::*; usecrate::parser::{Parse, ParserContext}; usecrate::typed_om::{ToTyped, TypedValue}; usecrate::values::computed::transform::DirectionVector; usecrate::values::computed::{Context, ToComputedValue}; usecrate::values::generics::transform::IsParallelTo; usecrate::values::generics::{GreaterThanOrEqualToOne, NonNegative}; usecrate::values::specified::calc::{CalcNode, CalcNumeric, Leaf}; usecrate::values::specified::{NoCalcPercentage, Percentage}; usecrate::values::tagged_numeric::{NumericUnion, Unpacked, UnpackedMut}; usecrate::values::{serialize_number, CSSFloat, CSSInteger}; usecrate::{One, Zero}; use cssparser::{Parser, Token}; use std::fmt::{self, Write}; use style_traits::values::specified::AllowedNumericType; use style_traits::{CssWriter, ParseError, ParsingMode, SpecifiedValueInfo, ToCss}; use thin_vec::ThinVec;
/// Parse a `<number>` value, with a given clamping mode. pubfn parse_number_with_clamping_mode<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
clamping_mode: AllowedNumericType,
) -> Result<Number, ParseError<'i>> { let location = input.current_source_location();
Ok(Number(match *input.next()? {
Token::Number { value, .. } if clamping_mode.is_ok(context.parsing_mode, value) => {
NumericUnion::inline((), value)
},
Token::Function(ref name) => { let function = CalcNode::math_function(context, name, location)?; let number = CalcNode::parse_number(context, input, clamping_mode, function)?;
NumericUnion::boxed(Box::new(number))
}, ref t => return Err(location.new_unexpected_token_error(t.clone())),
}))
}
/// Parse an `<integer>` value, with a given clamping mode. pubfn parse_integer_with_clamping_mode<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
clamping_mode: AllowedNumericType,
) -> Result<Integer, ParseError<'i>> { let location = input.current_source_location();
Ok(Integer(match *input.next()? {
Token::Number {
int_value: Some(v), ..
} if clamping_mode.is_ok(context.parsing_mode, v as f32) => NumericUnion::inline((), v),
Token::Function(ref name) => { let function = CalcNode::math_function(context, name, location)?; let calc = CalcNode::parse_number(context, input, clamping_mode, function)?;
NumericUnion::boxed(Box::new(calc))
}, ref t => return Err(location.new_unexpected_token_error(t.clone())),
}))
}
impl NoCalcNumber { /// Returns a new literal number with the value `val`. #[inline] pubfn new(val: CSSFloat) -> Self { Self(val)
}
/// Returns the raw, underlying value of this number. #[inline] pubfn value(&self) -> f32 { self.0
}
/// Returns the numeric value, clamped if needed. #[inline] pubfn get(&self) -> f32 { crate::values::normalize(self.0).min(f32::MAX).max(f32::MIN)
}
/// Returns the unit string for a number value. pubfn unit(&self) -> &'static str { "number"
}
/// Returns the canonical unit for a number value (none). pubfn canonical_unit(&self) -> Option<&'static str> {
None
}
/// Converts to the given unit, only succeeding if the unit is "number". pubfn to(&self, unit: &str) -> Result<Self, ()> { if !unit.eq_ignore_ascii_case("number") { return Err(());
}
Ok(self.clone())
}
}
impl PartialOrd<Number> for Number { fn partial_cmp(&self, other: &Number) -> Option<std::cmp::Ordering> { self.get().partial_cmp(&other.get())
}
}
impl Number { /// Returns a new number with the value `val`. #[inline] pubfn new(val: CSSFloat) -> Self { Self(NumericUnion::inline((), val))
}
/// Returns a new number with the value `val`. #[inline] pubfn new_calc(val: Box<CalcNumeric>) -> Self { Self(NumericUnion::boxed(val))
}
/// Returns this number as a percentage. pubfn to_percentage(&self) -> Option<Percentage> {
Some(matchself.0.unpack() {
Unpacked::Inline((), n) => Percentage::new(n),
Unpacked::Boxed(ref calc) => { let n = calc.as_number()?.get();
Percentage::new_calc(Box::new(
calc.with_leaf_node(Leaf::Percentage(NoCalcPercentage::new(n))),
))
},
})
}
/// Returns the value if this is a plain (non-calc) number, or None otherwise. /// Use `resolve()` to also handle resolvable calc expressions, or `to_computed_value()` /// when computed context is available. #[inline] pubfn get(&self) -> Option<f32> { matchself.0.unpack() {
Unpacked::Inline((), f) => Some(NoCalcNumber(f).get()),
Unpacked::Boxed(..) => None,
}
}
/// Returns the value if it can be resolved at parse time, including resolvable calc /// expressions. Returns None for calc expressions that require computed-value context. pubfn resolve(&self) -> Option<f32> { matchself.0.unpack() {
Unpacked::Inline((), f) => Some(NoCalcNumber(f).get()),
Unpacked::Boxed(ref calc) => calc.as_number().map(|n| n.get()),
}
}
impl IsParallelTo for (Number, Number, Number) { fn is_parallel_to(&self, vector: &DirectionVector) -> bool { use euclid::approxeq::ApproxEq; // If a and b is parallel, the angle between them is 0deg, so // a x b = |a|*|b|*sin(0)*n = 0 * n, |a x b| == 0. match (self.0.get(), self.1.get(), self.2.get()) {
(Some(x), Some(y), Some(z)) => DirectionVector::new(x, y, z)
.cross(*vector)
.square_length()
.approx_eq(&0.0f32),
_ => false,
}
}
}
impl SpecifiedValueInfo for Number {}
impl Zero for Number { #[inline] fn zero() -> Self { Self::new(0.)
}
// Returns true if this number was a non-calc 0. #[inline] fn is_zero(&self) -> bool { self.get() == Some(0.)
}
}
/// A Number which is >= 0.0. pubtype NonNegativeNumber = NonNegative<Number>;
impl One for NonNegativeNumber { #[inline] fn one() -> Self {
NonNegativeNumber::new(1.0)
}
// Returns true if this number was a non-calc 1. #[inline] fn is_one(&self) -> bool { self.get() == Some(1.)
}
}
impl NonNegativeNumber { /// Returns a new non-negative number with the value `val`. pubfn new(val: CSSFloat) -> Self {
NonNegative(Number::new(val.max(0.)))
}
/// An Integer which is >= 0. For calc expressions that couldn't be resolved at parse time, /// this value is clamped to 0 at computed-value time. pubtype NonNegativeInteger = NonNegative<Integer>;
/// A specified `<integer>`, either a simple integer value, a resolved calc expression, /// or a full calc expression tree that cannot be computed at parse time. /// Note that a calc expression may not actually be an integer; it will be rounded /// at computed-value time. /// /// <https://drafts.csswg.org/css-values/#integers> #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)] pubstruct Integer(NumericUnion<(), i32, CalcNumeric>);
impl Zero for Integer { #[inline] fn zero() -> Self { Self::new(0)
}
// Returns true if this integer was a non-calc 0. #[inline] fn is_zero(&self) -> bool { self.get() == Some(0)
}
}
impl One for Integer { #[inline] fn one() -> Self { Self::new(1)
}
// Returns true if this integer was a non-calc 1. #[inline] fn is_one(&self) -> bool { self.get() == Some(1)
}
}
impl PartialEq<i32> for Integer { fn eq(&self, value: &i32) -> bool { self.get().is_some_and(|v| v == *value)
}
}
impl Integer { /// Trivially constructs a new `Integer` value. pubfn new(val: CSSInteger) -> Self { Self(NumericUnion::inline((), val))
}
/// Returns the value if this is a plain (non-calc) integer, or None otherwise. /// Use `resolve()` to also handle resolvable calc expressions, or `to_computed_value()` /// when computed context is available. pubfn get(&self) -> Option<CSSInteger> { matchself.0.unpack() {
Unpacked::Inline((), v) => Some(v),
Unpacked::Boxed(..) => None,
}
}
/// Returns the value if it can be resolved at parse time, including resolvable calc /// expressions. Returns None for calc expressions that require computed-value context. pubfn resolve(&self) -> Option<CSSInteger> {
Some(matchself.0.unpack() {
Unpacked::Inline((), v) => v,
Unpacked::Boxed(ref calc) => { let value = calc.as_number()?.get();
(value + 0.5).floor() as CSSInteger
},
})
}
/// Makes sure this number matches the clamping, or errors otherwise. pubfn ensure_clamping_mode(&mutself, clamping_mode: AllowedNumericType) -> Result<(), ()> { matchself.0.unpack_mut() {
UnpackedMut::Inline(_, i) => { if !clamping_mode.is_ok(ParsingMode::DEFAULT, *i as f32) { return Err(());
}
},
UnpackedMut::Boxed(refmut calc) => {
calc.clamping_mode = clamping_mode;
},
}
Ok(())
}
}
/// An Integer which is >= 1. For calc expressions that couldn't be resolved at parse time, /// this value is clamped to 1 at computed-value time. pubtype PositiveInteger = GreaterThanOrEqualToOne<Integer>;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.