style/values/computed/
angle.rs

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//! Computed angles.
6
7use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
8use crate::values::CSSFloat;
9use crate::Zero;
10use std::f64::consts::PI;
11use std::fmt::{self, Write};
12use std::{f32, f64};
13use std::ops::Neg;
14use style_traits::{CssWriter, ToCss};
15
16/// A computed angle in degrees.
17#[derive(
18    Add,
19    Animate,
20    Clone,
21    Copy,
22    Debug,
23    Deserialize,
24    MallocSizeOf,
25    PartialEq,
26    PartialOrd,
27    Serialize,
28    ToAnimatedZero,
29    ToResolvedValue,
30)]
31#[repr(C)]
32pub struct Angle(CSSFloat);
33
34impl ToCss for Angle {
35    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
36    where
37        W: Write,
38    {
39        self.degrees().to_css(dest)?;
40        dest.write_str("deg")
41    }
42}
43
44const RAD_PER_DEG: f64 = PI / 180.0;
45
46impl Angle {
47    /// Creates a computed `Angle` value from a radian amount.
48    pub fn from_radians(radians: CSSFloat) -> Self {
49        Angle(radians / RAD_PER_DEG as f32)
50    }
51
52    /// Creates a computed `Angle` value from a degrees amount.
53    #[inline]
54    pub fn from_degrees(degrees: CSSFloat) -> Self {
55        Angle(degrees)
56    }
57
58    /// Returns the amount of radians this angle represents.
59    #[inline]
60    pub fn radians(&self) -> CSSFloat {
61        self.radians64().min(f32::MAX as f64).max(f32::MIN as f64) as f32
62    }
63
64    /// Returns the amount of radians this angle represents as a `f64`.
65    ///
66    /// Gecko stores angles as singles, but does this computation using doubles.
67    ///
68    /// This is significant enough to mess up rounding to the nearest
69    /// quarter-turn for 225 degrees, for example.
70    #[inline]
71    pub fn radians64(&self) -> f64 {
72        self.0 as f64 * RAD_PER_DEG
73    }
74
75    /// Return the value in degrees.
76    #[inline]
77    pub fn degrees(&self) -> CSSFloat {
78        self.0
79    }
80}
81
82impl Zero for Angle {
83    #[inline]
84    fn zero() -> Self {
85        Angle(0.0)
86    }
87
88    #[inline]
89    fn is_zero(&self) -> bool {
90        self.0 == 0.
91    }
92}
93
94impl ComputeSquaredDistance for Angle {
95    #[inline]
96    fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
97        // Use the formula for calculating the distance between angles defined in SVG:
98        // https://www.w3.org/TR/SVG/animate.html#complexDistances
99        self.radians64()
100            .compute_squared_distance(&other.radians64())
101    }
102}
103
104impl Neg for Angle {
105    type Output = Angle;
106
107    #[inline]
108    fn neg(self) -> Angle {
109        Angle(-self.0)
110    }
111}