/* 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 angles.
usecrate::derives::*; usecrate::parser::{Parse, ParserContext}; usecrate::typed_om::{NumericValue, ToTyped, TypedValue, UnitValue}; usecrate::values::computed::angle::Angle as ComputedAngle; usecrate::values::computed::{Context, ToComputedValue}; usecrate::values::specified::calc::{CalcNode, CalcNumeric, Leaf}; usecrate::values::tagged_numeric::{Extracted, NumericUnion, Unpacked}; usecrate::values::CSSFloat; usecrate::Zero; use cssparser::{match_ignore_ascii_case, Parser, Token}; use std::f32::consts::PI; use std::fmt::{self, Write}; use std::ops::Neg; use style_traits::{CssString, CssWriter, ParseError, SpecifiedValueInfo, ToCss}; use thin_vec::ThinVec;
/// Number of degrees per radian. const DEG_PER_RAD: f32 = 180.0 / PI; /// Number of degrees per turn. const DEG_PER_TURN: f32 = 360.0; /// Number of degrees per gradian. const DEG_PER_GRAD: f32 = 180.0 / 200.0;
/// The unit of a `<angle>` value. #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, ToShmem)] #[repr(u8)] pubenum AngleUnit { /// `deg`
Deg, /// `grad`
Grad, /// `rad`
Rad, /// `turn`
Turn,
}
impl AngleUnit { /// Returns the angle unit for the given string. #[inline] pubfn from_str(unit: &str) -> Result<Self, ()> {
Ok(match_ignore_ascii_case! { unit, "deg" => Self::Deg, "grad" => Self::Grad, "turn" => Self::Turn, "rad" => Self::Rad,
_ => return Err(())
})
}
/// Returns this unit as a string. #[inline] pubfn as_str(self) -> &'static str { matchself { Self::Deg => "deg", Self::Grad => "grad", Self::Rad => "rad", Self::Turn => "turn",
}
}
}
impl ToTyped for NoCalcAngle { fn to_typed(&self, dest: &mut ThinVec<TypedValue>) -> Result<(), ()> { let value = self.unitless_value(); let unit = CssString::from(self.unit());
dest.push(TypedValue::Numeric(NumericValue::Unit(UnitValue {
value,
unit,
})));
Ok(())
}
}
impl SpecifiedValueInfo for NoCalcAngle {}
impl NoCalcAngle { /// Creates an angle with the given unit and value. #[inline] pubfn new(unit: AngleUnit, value: CSSFloat) -> Self { Self { unit, value }
}
/// Creates an angle with the given value in degrees. #[inline] pubfn from_degrees(value: CSSFloat) -> Self { Self::new(AngleUnit::Deg, value)
}
/// Creates an angle with the given value in radians. #[inline] pubfn from_radians(value: CSSFloat) -> Self { Self::new(AngleUnit::Rad, value)
}
/// Returns the value of the angle in degrees. #[inline] pubfn degrees(&self) -> CSSFloat { matchself.unit {
AngleUnit::Deg => self.value,
AngleUnit::Rad => self.value * DEG_PER_RAD,
AngleUnit::Turn => self.value * DEG_PER_TURN,
AngleUnit::Grad => self.value * DEG_PER_GRAD,
}
}
/// Returns the value of the angle in radians. #[inline] pubfn radians(&self) -> CSSFloat { const RAD_PER_DEG: f32 = PI / 180.0; self.degrees() * RAD_PER_DEG
}
/// Returns the unit of the angle. #[inline] pubfn angle_unit(&self) -> AngleUnit { self.unit
}
/// Returns the unitless, raw value. #[inline] pubfn unitless_value(&self) -> CSSFloat { self.value
}
/// Returns the unit of the angle as a string. #[inline] pubfn unit(&self) -> &'static str { self.unit.as_str()
}
/// Return the canonical unit for this value. pubfn canonical_unit(&self) -> Option<&'static str> {
Some("deg")
}
/// Convert this value to the specified unit, if possible. pubfn to(&self, unit: &str) -> Result<Self, ()> { let degrees = self.degrees(); let unit = AngleUnit::from_str(unit)?; let divisor = match unit {
AngleUnit::Deg => 1.0,
AngleUnit::Grad => DEG_PER_GRAD,
AngleUnit::Turn => DEG_PER_TURN,
AngleUnit::Rad => DEG_PER_RAD,
};
Ok(Self::new(unit, degrees / divisor))
}
/// Parse an `<angle>` value given a value and a unit. pubfn parse_dimension(value: CSSFloat, unit: &str) -> Result<Self, ()> { let unit = AngleUnit::from_str(unit)?;
Ok(Self::new(unit, value))
}
}
impl Neg for NoCalcAngle { type Output = NoCalcAngle;
/// A specified `<angle>` value, either a plain value or a `calc()` expression. /// /// https://drafts.csswg.org/css-values/#angle-value #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)] pubstruct Angle(NumericUnion<AngleUnit, f32, CalcNumeric>);
impl Angle { /// Creates an angle from a non-calc `NoCalcAngle`. #[inline] pubfn new(angle: NoCalcAngle) -> Self { Self(NumericUnion::inline(angle.unit, angle.value))
}
/// Creates an angle from a calc() expression. #[inline] pubfn new_calc(calc: Box<CalcNumeric>) -> Self { Self(NumericUnion::boxed(calc))
}
/// Creates an angle with the given value in degrees. #[inline] pubfn from_degrees(value: CSSFloat) -> Self { Self::new(NoCalcAngle::from_degrees(value))
}
/// Returns true if this is a `calc()` expression. #[inline] pubfn is_calc(&self) -> bool { self.0.is_boxed()
}
/// Returns the inner non-calc angle, if this isn't a calc expression. #[inline] pubfn as_no_calc(&self) -> Option<NoCalcAngle> { matchself.0.unpack() {
Unpacked::Inline(unit, value) => Some(NoCalcAngle::new(unit, value)),
Unpacked::Boxed(_) => None,
}
}
/// Returns the angle in degrees if it can be resolved at parse time, or None for calc /// expressions that require computed context. Prefer `to_computed_value(context).degrees()` /// when an element context is available. #[inline] pubfn degrees(&self) -> Option<CSSFloat> { matchself.0.unpack() {
Unpacked::Inline(unit, value) => Some(NoCalcAngle::new(unit, value).degrees()),
Unpacked::Boxed(ref calc) => calc
.as_angle()
.map(|a| calc.clamping_mode.clamp(a.degrees())),
}
}
/// Parse an `<angle>` allowing unitless zero to represent a zero angle. /// /// See the comment in `AllowUnitlessZeroAngle` for why. #[inline] pubfn parse_with_unitless<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { Self::parse_internal(context, input, AllowUnitlessZeroAngle::Yes)
}
pub(super) fn parse_internal<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
allow_unitless_zero: AllowUnitlessZeroAngle,
) -> Result<Self, ParseError<'i>> { let location = input.current_source_location(); let t = input.next()?; let allow_unitless_zero = matches!(allow_unitless_zero, AllowUnitlessZeroAngle::Yes); match *t {
Token::Dimension {
value, ref unit, ..
} => match NoCalcAngle::parse_dimension(value, unit) {
Ok(angle) => Ok(Self::new(angle)),
Err(()) => { let t = t.clone();
Err(input.new_unexpected_token_error(t))
},
},
Token::Function(ref name) => { let function = CalcNode::math_function(context, name, location)?;
CalcNode::parse_angle(context, input, function)
.map(Box::new)
.map(Self::new_calc)
},
Token::Number { value, .. } if value == 0. && allow_unitless_zero => Ok(Angle::zero()), ref t => { let t = t.clone();
Err(input.new_unexpected_token_error(t))
},
}
}
}
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.