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