mirror of
https://github.com/servo/servo.git
synced 2025-06-28 02:53:48 +01:00
style: Always compute angle values to degrees.
This matches the spec, https://drafts.csswg.org/css-values/#angles, which says: > All <angle> units are compatible, and deg is their canonical unit. And https://drafts.csswg.org/css-values/#compat, which says: >When serializing computed values [...], compatible units [...] are converted into a single canonical unit. And also other implementations (Blink always serializes angles as degrees in computed style for example). Also allows us to get rid of quite a bit of code, and makes computed angle value representation just a number, which is nice. Differential Revision: https://phabricator.services.mozilla.com/D8619
This commit is contained in:
parent
11fedf18d9
commit
42def5a011
11 changed files with 142 additions and 209 deletions
|
@ -11,7 +11,7 @@
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use gecko::values::GeckoStyleCoordConvertible;
|
use gecko::values::GeckoStyleCoordConvertible;
|
||||||
use gecko_bindings::bindings;
|
use gecko_bindings::bindings;
|
||||||
use gecko_bindings::structs::{self, nsCSSUnit, nsStyleCoord_CalcValue};
|
use gecko_bindings::structs::{self, nsStyleCoord_CalcValue};
|
||||||
use gecko_bindings::structs::{nsresult, SheetType, nsStyleImage};
|
use gecko_bindings::structs::{nsresult, SheetType, nsStyleImage};
|
||||||
use gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
|
use gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
|
@ -128,35 +128,7 @@ impl From<nsStyleCoord_CalcValue> for NonNegativeLengthOrPercentageOrAuto {
|
||||||
|
|
||||||
impl From<Angle> for CoordDataValue {
|
impl From<Angle> for CoordDataValue {
|
||||||
fn from(reference: Angle) -> Self {
|
fn from(reference: Angle) -> Self {
|
||||||
match reference {
|
CoordDataValue::Degree(reference.degrees())
|
||||||
Angle::Deg(val) => CoordDataValue::Degree(val),
|
|
||||||
Angle::Grad(val) => CoordDataValue::Grad(val),
|
|
||||||
Angle::Rad(val) => CoordDataValue::Radian(val),
|
|
||||||
Angle::Turn(val) => CoordDataValue::Turn(val),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Angle {
|
|
||||||
/// Converts Angle struct into (value, unit) pair.
|
|
||||||
pub fn to_gecko_values(&self) -> (f32, nsCSSUnit) {
|
|
||||||
match *self {
|
|
||||||
Angle::Deg(val) => (val, nsCSSUnit::eCSSUnit_Degree),
|
|
||||||
Angle::Grad(val) => (val, nsCSSUnit::eCSSUnit_Grad),
|
|
||||||
Angle::Rad(val) => (val, nsCSSUnit::eCSSUnit_Radian),
|
|
||||||
Angle::Turn(val) => (val, nsCSSUnit::eCSSUnit_Turn),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts gecko (value, unit) pair into Angle struct
|
|
||||||
pub fn from_gecko_values(value: f32, unit: nsCSSUnit) -> Angle {
|
|
||||||
match unit {
|
|
||||||
nsCSSUnit::eCSSUnit_Degree => Angle::Deg(value),
|
|
||||||
nsCSSUnit::eCSSUnit_Grad => Angle::Grad(value),
|
|
||||||
nsCSSUnit::eCSSUnit_Radian => Angle::Rad(value),
|
|
||||||
nsCSSUnit::eCSSUnit_Turn => Angle::Turn(value),
|
|
||||||
_ => panic!("Unexpected unit for angle"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -325,10 +325,7 @@ impl GeckoStyleCoordConvertible for Angle {
|
||||||
|
|
||||||
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
||||||
match coord.as_value() {
|
match coord.as_value() {
|
||||||
CoordDataValue::Degree(val) => Some(Angle::Deg(val)),
|
CoordDataValue::Degree(val) => Some(Angle::from_degrees(val)),
|
||||||
CoordDataValue::Grad(val) => Some(Angle::Grad(val)),
|
|
||||||
CoordDataValue::Radian(val) => Some(Angle::Rad(val)),
|
|
||||||
CoordDataValue::Turn(val) => Some(Angle::Turn(val)),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -198,19 +198,19 @@ impl nsCSSValue {
|
||||||
|
|
||||||
/// Returns an `Angle` value from this `nsCSSValue`.
|
/// Returns an `Angle` value from this `nsCSSValue`.
|
||||||
///
|
///
|
||||||
/// Panics if the unit is not `eCSSUnit_Degree` `eCSSUnit_Grad`, `eCSSUnit_Turn`
|
/// Panics if the unit is not `eCSSUnit_Degree`.
|
||||||
/// or `eCSSUnit_Radian`.
|
#[inline]
|
||||||
pub fn get_angle(&self) -> Angle {
|
pub fn get_angle(&self) -> Angle {
|
||||||
Angle::from_gecko_values(self.float_unchecked(), self.mUnit)
|
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_Degree);
|
||||||
|
Angle::from_degrees(self.float_unchecked())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets Angle value to this nsCSSValue.
|
/// Sets Angle value to this nsCSSValue.
|
||||||
pub fn set_angle(&mut self, angle: Angle) {
|
pub fn set_angle(&mut self, angle: Angle) {
|
||||||
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_Null);
|
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_Null);
|
||||||
let (value, unit) = angle.to_gecko_values();
|
self.mUnit = nsCSSUnit::eCSSUnit_Degree;
|
||||||
self.mUnit = unit;
|
|
||||||
unsafe {
|
unsafe {
|
||||||
*self.mValue.mFloat.as_mut() = value;
|
*self.mValue.mFloat.as_mut() = angle.degrees();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -200,12 +200,6 @@ pub enum CoordDataValue {
|
||||||
Factor(f32),
|
Factor(f32),
|
||||||
/// eStyleUnit_Degree
|
/// eStyleUnit_Degree
|
||||||
Degree(f32),
|
Degree(f32),
|
||||||
/// eStyleUnit_Grad
|
|
||||||
Grad(f32),
|
|
||||||
/// eStyleUnit_Radian
|
|
||||||
Radian(f32),
|
|
||||||
/// eStyleUnit_Turn
|
|
||||||
Turn(f32),
|
|
||||||
/// eStyleUnit_FlexFraction
|
/// eStyleUnit_FlexFraction
|
||||||
FlexFraction(f32),
|
FlexFraction(f32),
|
||||||
/// eStyleUnit_Coord
|
/// eStyleUnit_Coord
|
||||||
|
@ -317,18 +311,6 @@ pub unsafe trait CoordDataMut: CoordData {
|
||||||
*unit = eStyleUnit_Degree;
|
*unit = eStyleUnit_Degree;
|
||||||
*union.mFloat.as_mut() = f;
|
*union.mFloat.as_mut() = f;
|
||||||
},
|
},
|
||||||
Grad(f) => {
|
|
||||||
*unit = eStyleUnit_Grad;
|
|
||||||
*union.mFloat.as_mut() = f;
|
|
||||||
},
|
|
||||||
Radian(f) => {
|
|
||||||
*unit = eStyleUnit_Radian;
|
|
||||||
*union.mFloat.as_mut() = f;
|
|
||||||
},
|
|
||||||
Turn(f) => {
|
|
||||||
*unit = eStyleUnit_Turn;
|
|
||||||
*union.mFloat.as_mut() = f;
|
|
||||||
},
|
|
||||||
FlexFraction(f) => {
|
FlexFraction(f) => {
|
||||||
*unit = eStyleUnit_FlexFraction;
|
*unit = eStyleUnit_FlexFraction;
|
||||||
*union.mFloat.as_mut() = f;
|
*union.mFloat.as_mut() = f;
|
||||||
|
@ -393,9 +375,6 @@ pub unsafe trait CoordData {
|
||||||
eStyleUnit_Percent => Percent(self.get_float()),
|
eStyleUnit_Percent => Percent(self.get_float()),
|
||||||
eStyleUnit_Factor => Factor(self.get_float()),
|
eStyleUnit_Factor => Factor(self.get_float()),
|
||||||
eStyleUnit_Degree => Degree(self.get_float()),
|
eStyleUnit_Degree => Degree(self.get_float()),
|
||||||
eStyleUnit_Grad => Grad(self.get_float()),
|
|
||||||
eStyleUnit_Radian => Radian(self.get_float()),
|
|
||||||
eStyleUnit_Turn => Turn(self.get_float()),
|
|
||||||
eStyleUnit_FlexFraction => FlexFraction(self.get_float()),
|
eStyleUnit_FlexFraction => FlexFraction(self.get_float()),
|
||||||
eStyleUnit_Coord => Coord(self.get_integer()),
|
eStyleUnit_Coord => Coord(self.get_integer()),
|
||||||
eStyleUnit_Integer => Integer(self.get_integer()),
|
eStyleUnit_Integer => Integer(self.get_integer()),
|
||||||
|
@ -413,9 +392,6 @@ pub unsafe trait CoordData {
|
||||||
self.unit() == eStyleUnit_Percent ||
|
self.unit() == eStyleUnit_Percent ||
|
||||||
self.unit() == eStyleUnit_Factor ||
|
self.unit() == eStyleUnit_Factor ||
|
||||||
self.unit() == eStyleUnit_Degree ||
|
self.unit() == eStyleUnit_Degree ||
|
||||||
self.unit() == eStyleUnit_Grad ||
|
|
||||||
self.unit() == eStyleUnit_Radian ||
|
|
||||||
self.unit() == eStyleUnit_Turn ||
|
|
||||||
self.unit() == eStyleUnit_FlexFraction
|
self.unit() == eStyleUnit_FlexFraction
|
||||||
);
|
);
|
||||||
*self.union().mFloat.as_ref()
|
*self.union().mFloat.as_ref()
|
||||||
|
|
|
@ -5,38 +5,41 @@
|
||||||
//! Computed angles.
|
//! Computed angles.
|
||||||
|
|
||||||
use num_traits::Zero;
|
use num_traits::Zero;
|
||||||
|
use std::fmt::{self, Write};
|
||||||
use std::{f32, f64};
|
use std::{f32, f64};
|
||||||
use std::f64::consts::PI;
|
use std::f64::consts::PI;
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
|
use style_traits::{CssWriter, ToCss};
|
||||||
use values::CSSFloat;
|
use values::CSSFloat;
|
||||||
use values::animated::{Animate, Procedure};
|
|
||||||
use values::distance::{ComputeSquaredDistance, SquaredDistance};
|
use values::distance::{ComputeSquaredDistance, SquaredDistance};
|
||||||
|
|
||||||
/// A computed angle.
|
/// A computed angle in degrees.
|
||||||
#[animate(fallback = "Self::animate_fallback")]
|
|
||||||
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
||||||
#[derive(
|
#[derive(Animate, Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, ToAnimatedZero)]
|
||||||
Animate, Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, ToAnimatedZero, ToCss,
|
pub struct Angle(CSSFloat);
|
||||||
)]
|
|
||||||
pub enum Angle {
|
impl ToCss for Angle {
|
||||||
/// An angle with degree unit.
|
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||||
#[css(dimension)]
|
where
|
||||||
Deg(CSSFloat),
|
W: Write,
|
||||||
/// An angle with gradian unit.
|
{
|
||||||
#[css(dimension)]
|
self.degrees().to_css(dest)?;
|
||||||
Grad(CSSFloat),
|
dest.write_str("deg")
|
||||||
/// An angle with radian unit.
|
}
|
||||||
#[css(dimension)]
|
|
||||||
Rad(CSSFloat),
|
|
||||||
/// An angle with turn unit.
|
|
||||||
#[css(dimension)]
|
|
||||||
Turn(CSSFloat),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const RAD_PER_DEG: f64 = PI / 180.0;
|
||||||
|
|
||||||
impl Angle {
|
impl Angle {
|
||||||
/// Creates a computed `Angle` value from a radian amount.
|
/// Creates a computed `Angle` value from a radian amount.
|
||||||
pub fn from_radians(radians: CSSFloat) -> Self {
|
pub fn from_radians(radians: CSSFloat) -> Self {
|
||||||
Angle::Rad(radians)
|
Angle(radians / RAD_PER_DEG as f32)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a computed `Angle` value from a degrees amount.
|
||||||
|
#[inline]
|
||||||
|
pub fn from_degrees(degrees: CSSFloat) -> Self {
|
||||||
|
Angle(degrees)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the amount of radians this angle represents.
|
/// Returns the amount of radians this angle represents.
|
||||||
|
@ -48,43 +51,18 @@ impl Angle {
|
||||||
/// Returns the amount of radians this angle represents as a `f64`.
|
/// Returns the amount of radians this angle represents as a `f64`.
|
||||||
///
|
///
|
||||||
/// Gecko stores angles as singles, but does this computation using doubles.
|
/// Gecko stores angles as singles, but does this computation using doubles.
|
||||||
/// See nsCSSValue::GetAngleValueInRadians.
|
///
|
||||||
/// This is significant enough to mess up rounding to the nearest
|
/// This is significant enough to mess up rounding to the nearest
|
||||||
/// quarter-turn for 225 degrees, for example.
|
/// quarter-turn for 225 degrees, for example.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn radians64(&self) -> f64 {
|
pub fn radians64(&self) -> f64 {
|
||||||
const RAD_PER_DEG: f64 = PI / 180.0;
|
self.0 as f64 * RAD_PER_DEG as f64
|
||||||
const RAD_PER_GRAD: f64 = PI / 200.0;
|
|
||||||
const RAD_PER_TURN: f64 = PI * 2.0;
|
|
||||||
|
|
||||||
let radians = match *self {
|
|
||||||
Angle::Deg(val) => val as f64 * RAD_PER_DEG,
|
|
||||||
Angle::Grad(val) => val as f64 * RAD_PER_GRAD,
|
|
||||||
Angle::Turn(val) => val as f64 * RAD_PER_TURN,
|
|
||||||
Angle::Rad(val) => val as f64,
|
|
||||||
};
|
|
||||||
radians.min(f64::MAX).max(f64::MIN)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the value in degrees.
|
/// Return the value in degrees.
|
||||||
pub fn degrees(&self) -> f32 {
|
|
||||||
use std::f32::consts::PI;
|
|
||||||
self.radians() * 360. / (2. * PI)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <https://drafts.csswg.org/css-transitions/#animtype-number>
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn animate_fallback(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
pub fn degrees(&self) -> CSSFloat {
|
||||||
Ok(Angle::from_radians(
|
self.0
|
||||||
self.radians().animate(&other.radians(), procedure)?,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRef<Angle> for Angle {
|
|
||||||
#[inline]
|
|
||||||
fn as_ref(&self) -> &Self {
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,27 +71,19 @@ impl Add for Angle {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn add(self, rhs: Self) -> Self {
|
fn add(self, rhs: Self) -> Self {
|
||||||
match (self, rhs) {
|
Angle(self.0 + rhs.0)
|
||||||
(Angle::Deg(x), Angle::Deg(y)) => Angle::Deg(x + y),
|
|
||||||
(Angle::Grad(x), Angle::Grad(y)) => Angle::Grad(x + y),
|
|
||||||
(Angle::Turn(x), Angle::Turn(y)) => Angle::Turn(x + y),
|
|
||||||
(Angle::Rad(x), Angle::Rad(y)) => Angle::Rad(x + y),
|
|
||||||
_ => Angle::from_radians(self.radians() + rhs.radians()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Zero for Angle {
|
impl Zero for Angle {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn zero() -> Self {
|
fn zero() -> Self {
|
||||||
Angle::from_radians(0.0)
|
Angle(0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_zero(&self) -> bool {
|
fn is_zero(&self) -> bool {
|
||||||
match *self {
|
self.0 == 0.
|
||||||
Angle::Deg(val) | Angle::Grad(val) | Angle::Turn(val) | Angle::Rad(val) => val == 0.,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +92,6 @@ impl ComputeSquaredDistance for Angle {
|
||||||
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
||||||
// Use the formula for calculating the distance between angles defined in SVG:
|
// Use the formula for calculating the distance between angles defined in SVG:
|
||||||
// https://www.w3.org/TR/SVG/animate.html#complexDistances
|
// https://www.w3.org/TR/SVG/animate.html#complexDistances
|
||||||
self.radians64()
|
self.radians64().compute_squared_distance(&other.radians64())
|
||||||
.compute_squared_distance(&other.radians64())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -866,7 +866,7 @@ impl ToAnimatedValue for FontStyleAngle {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
|
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
|
||||||
FontStyleAngle(Angle::Deg(
|
FontStyleAngle(Angle::from_degrees(
|
||||||
animated
|
animated
|
||||||
.degrees()
|
.degrees()
|
||||||
.min(specified::FONT_STYLE_OBLIQUE_MAX_ANGLE_DEGREES)
|
.min(specified::FONT_STYLE_OBLIQUE_MAX_ANGLE_DEGREES)
|
||||||
|
@ -899,7 +899,7 @@ impl FontStyle {
|
||||||
/// https://drafts.csswg.org/css-fonts-4/#valdef-font-style-oblique-angle
|
/// https://drafts.csswg.org/css-fonts-4/#valdef-font-style-oblique-angle
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn default_angle() -> FontStyleAngle {
|
pub fn default_angle() -> FontStyleAngle {
|
||||||
FontStyleAngle(Angle::Deg(
|
FontStyleAngle(Angle::from_degrees(
|
||||||
specified::DEFAULT_FONT_STYLE_OBLIQUE_ANGLE_DEGREES,
|
specified::DEFAULT_FONT_STYLE_OBLIQUE_ANGLE_DEGREES,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -919,7 +919,7 @@ impl FontStyle {
|
||||||
if italic {
|
if italic {
|
||||||
return generics::FontStyle::Italic;
|
return generics::FontStyle::Italic;
|
||||||
}
|
}
|
||||||
generics::FontStyle::Oblique(FontStyleAngle(Angle::Deg(angle)))
|
generics::FontStyle::Oblique(FontStyleAngle(Angle::from_degrees(angle)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ use num_traits::Zero;
|
||||||
use values::{computed, CSSFloat};
|
use values::{computed, CSSFloat};
|
||||||
use values::computed::length::Length as ComputedLength;
|
use values::computed::length::Length as ComputedLength;
|
||||||
use values::computed::length::LengthOrPercentage as ComputedLengthOrPercentage;
|
use values::computed::length::LengthOrPercentage as ComputedLengthOrPercentage;
|
||||||
|
use values::specified::angle::Angle as SpecifiedAngle;
|
||||||
use values::specified::length::Length as SpecifiedLength;
|
use values::specified::length::Length as SpecifiedLength;
|
||||||
use values::specified::length::LengthOrPercentage as SpecifiedLengthOrPercentage;
|
use values::specified::length::LengthOrPercentage as SpecifiedLengthOrPercentage;
|
||||||
|
|
||||||
|
@ -394,10 +395,30 @@ pub trait ToMatrix {
|
||||||
fn to_3d_matrix(&self, reference_box: Option<&Rect<Au>>) -> Result<Transform3D<f64>, ()>;
|
fn to_3d_matrix(&self, reference_box: Option<&Rect<Au>>) -> Result<Transform3D<f64>, ()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A little helper to deal with both specified and computed angles.
|
||||||
|
pub trait ToRadians {
|
||||||
|
/// Return the radians value as a 64-bit floating point value.
|
||||||
|
fn radians64(&self) -> f64;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToRadians for computed::angle::Angle {
|
||||||
|
#[inline]
|
||||||
|
fn radians64(&self) -> f64 {
|
||||||
|
computed::angle::Angle::radians64(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToRadians for SpecifiedAngle {
|
||||||
|
#[inline]
|
||||||
|
fn radians64(&self) -> f64 {
|
||||||
|
computed::angle::Angle::from_degrees(self.degrees()).radians64()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<Angle, Number, Length, Integer, LoP> ToMatrix
|
impl<Angle, Number, Length, Integer, LoP> ToMatrix
|
||||||
for TransformOperation<Angle, Number, Length, Integer, LoP>
|
for TransformOperation<Angle, Number, Length, Integer, LoP>
|
||||||
where
|
where
|
||||||
Angle: Copy + AsRef<computed::angle::Angle>,
|
Angle: ToRadians + Copy,
|
||||||
Number: Copy + Into<f32> + Into<f64>,
|
Number: Copy + Into<f32> + Into<f64>,
|
||||||
Length: ToAbsoluteLength,
|
Length: ToAbsoluteLength,
|
||||||
LoP: ToAbsoluteLength,
|
LoP: ToAbsoluteLength,
|
||||||
|
@ -426,7 +447,7 @@ where
|
||||||
let reference_height = reference_box.map(|v| v.size.height);
|
let reference_height = reference_box.map(|v| v.size.height);
|
||||||
let matrix = match *self {
|
let matrix = match *self {
|
||||||
Rotate3D(ax, ay, az, theta) => {
|
Rotate3D(ax, ay, az, theta) => {
|
||||||
let theta = TWO_PI - theta.as_ref().radians64();
|
let theta = TWO_PI - theta.radians64();
|
||||||
let (ax, ay, az, theta) =
|
let (ax, ay, az, theta) =
|
||||||
get_normalized_vector_and_angle(ax.into(), ay.into(), az.into(), theta);
|
get_normalized_vector_and_angle(ax.into(), ay.into(), az.into(), theta);
|
||||||
Transform3D::create_rotation(
|
Transform3D::create_rotation(
|
||||||
|
@ -437,15 +458,15 @@ where
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
RotateX(theta) => {
|
RotateX(theta) => {
|
||||||
let theta = euclid::Angle::radians(TWO_PI - theta.as_ref().radians64());
|
let theta = euclid::Angle::radians(TWO_PI - theta.radians64());
|
||||||
Transform3D::create_rotation(1., 0., 0., theta)
|
Transform3D::create_rotation(1., 0., 0., theta)
|
||||||
},
|
},
|
||||||
RotateY(theta) => {
|
RotateY(theta) => {
|
||||||
let theta = euclid::Angle::radians(TWO_PI - theta.as_ref().radians64());
|
let theta = euclid::Angle::radians(TWO_PI - theta.radians64());
|
||||||
Transform3D::create_rotation(0., 1., 0., theta)
|
Transform3D::create_rotation(0., 1., 0., theta)
|
||||||
},
|
},
|
||||||
RotateZ(theta) | Rotate(theta) => {
|
RotateZ(theta) | Rotate(theta) => {
|
||||||
let theta = euclid::Angle::radians(TWO_PI - theta.as_ref().radians64());
|
let theta = euclid::Angle::radians(TWO_PI - theta.radians64());
|
||||||
Transform3D::create_rotation(0., 0., 1., theta)
|
Transform3D::create_rotation(0., 0., 1., theta)
|
||||||
},
|
},
|
||||||
Perspective(ref d) => {
|
Perspective(ref d) => {
|
||||||
|
@ -479,16 +500,16 @@ where
|
||||||
Transform3D::create_translation(0., 0., z.to_pixel_length(None)? as f64)
|
Transform3D::create_translation(0., 0., z.to_pixel_length(None)? as f64)
|
||||||
},
|
},
|
||||||
Skew(theta_x, theta_y) => Transform3D::create_skew(
|
Skew(theta_x, theta_y) => Transform3D::create_skew(
|
||||||
euclid::Angle::radians(theta_x.as_ref().radians64()),
|
euclid::Angle::radians(theta_x.radians64()),
|
||||||
euclid::Angle::radians(theta_y.map_or(0., |a| a.as_ref().radians64())),
|
euclid::Angle::radians(theta_y.map_or(0., |a| a.radians64())),
|
||||||
),
|
),
|
||||||
SkewX(theta) => Transform3D::create_skew(
|
SkewX(theta) => Transform3D::create_skew(
|
||||||
euclid::Angle::radians(theta.as_ref().radians64()),
|
euclid::Angle::radians(theta.radians64()),
|
||||||
euclid::Angle::radians(0.),
|
euclid::Angle::radians(0.),
|
||||||
),
|
),
|
||||||
SkewY(theta) => Transform3D::create_skew(
|
SkewY(theta) => Transform3D::create_skew(
|
||||||
euclid::Angle::radians(0.),
|
euclid::Angle::radians(0.),
|
||||||
euclid::Angle::radians(theta.as_ref().radians64()),
|
euclid::Angle::radians(theta.radians64()),
|
||||||
),
|
),
|
||||||
Matrix3D(m) => m.into(),
|
Matrix3D(m) => m.into(),
|
||||||
Matrix(m) => m.into(),
|
Matrix(m) => m.into(),
|
||||||
|
|
|
@ -7,21 +7,53 @@
|
||||||
use cssparser::{Parser, Token};
|
use cssparser::{Parser, Token};
|
||||||
use parser::{Parse, ParserContext};
|
use parser::{Parse, ParserContext};
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
|
use std::f32::consts::PI;
|
||||||
use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, ToCss};
|
use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, ToCss};
|
||||||
use values::CSSFloat;
|
use values::CSSFloat;
|
||||||
use values::computed::{Context, ToComputedValue};
|
use values::computed::{Context, ToComputedValue};
|
||||||
use values::computed::angle::Angle as ComputedAngle;
|
use values::computed::angle::Angle as ComputedAngle;
|
||||||
use values::specified::calc::CalcNode;
|
use values::specified::calc::CalcNode;
|
||||||
|
|
||||||
/// A specified angle.
|
/// A specified angle dimension.
|
||||||
///
|
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, ToCss)]
|
||||||
/// Computed angles are essentially same as specified ones except for `calc()`
|
pub enum AngleDimension {
|
||||||
/// value serialization. Therefore we are storing a computed angle inside
|
/// An angle with degree unit.
|
||||||
/// to hold the actual value and its unit.
|
#[css(dimension)]
|
||||||
|
Deg(CSSFloat),
|
||||||
|
/// An angle with gradian unit.
|
||||||
|
#[css(dimension)]
|
||||||
|
Grad(CSSFloat),
|
||||||
|
/// An angle with radian unit.
|
||||||
|
#[css(dimension)]
|
||||||
|
Rad(CSSFloat),
|
||||||
|
/// An angle with turn unit.
|
||||||
|
#[css(dimension)]
|
||||||
|
Turn(CSSFloat),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AngleDimension {
|
||||||
|
/// Returns the amount of degrees this angle represents.
|
||||||
|
#[inline]
|
||||||
|
fn degrees(&self) -> CSSFloat {
|
||||||
|
const DEG_PER_RAD: f32 = 180.0 / PI;
|
||||||
|
const DEG_PER_TURN: f32 = 360.0;
|
||||||
|
const DEG_PER_GRAD: f32 = 180.0 / 200.0;
|
||||||
|
|
||||||
|
match *self {
|
||||||
|
AngleDimension::Deg(d) => d,
|
||||||
|
AngleDimension::Rad(rad) => rad * DEG_PER_RAD,
|
||||||
|
AngleDimension::Turn(turns) => turns * DEG_PER_TURN,
|
||||||
|
AngleDimension::Grad(gradians) => gradians * DEG_PER_GRAD,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A specified Angle value, which is just the angle dimension, plus whether it
|
||||||
|
/// was specified as `calc()` or not.
|
||||||
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
||||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq)]
|
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq)]
|
||||||
pub struct Angle {
|
pub struct Angle {
|
||||||
value: ComputedAngle,
|
value: AngleDimension,
|
||||||
was_calc: bool,
|
was_calc: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,22 +73,18 @@ impl ToCss for Angle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(emilio): Probably computed angles shouldn't preserve the unit and
|
|
||||||
// should serialize to degrees per:
|
|
||||||
//
|
|
||||||
// https://drafts.csswg.org/css-values/#compat
|
|
||||||
impl ToComputedValue for Angle {
|
impl ToComputedValue for Angle {
|
||||||
type ComputedValue = ComputedAngle;
|
type ComputedValue = ComputedAngle;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_computed_value(&self, _context: &Context) -> Self::ComputedValue {
|
fn to_computed_value(&self, _context: &Context) -> Self::ComputedValue {
|
||||||
self.value
|
ComputedAngle::from_degrees(self.degrees())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||||
Angle {
|
Angle {
|
||||||
value: *computed,
|
value: AngleDimension::Deg(computed.degrees()),
|
||||||
was_calc: false,
|
was_calc: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,35 +92,18 @@ impl ToComputedValue for Angle {
|
||||||
|
|
||||||
impl Angle {
|
impl Angle {
|
||||||
/// Creates an angle with the given value in degrees.
|
/// Creates an angle with the given value in degrees.
|
||||||
|
#[inline]
|
||||||
pub fn from_degrees(value: CSSFloat, was_calc: bool) -> Self {
|
pub fn from_degrees(value: CSSFloat, was_calc: bool) -> Self {
|
||||||
Angle {
|
Angle {
|
||||||
value: ComputedAngle::Deg(value),
|
value: AngleDimension::Deg(value),
|
||||||
was_calc,
|
was_calc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an angle with the given value in gradians.
|
/// Returns the value of the angle in degrees, mostly for `calc()`.
|
||||||
pub fn from_gradians(value: CSSFloat, was_calc: bool) -> Self {
|
#[inline]
|
||||||
Angle {
|
pub fn degrees(&self) -> CSSFloat {
|
||||||
value: ComputedAngle::Grad(value),
|
self.value.degrees()
|
||||||
was_calc,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an angle with the given value in turns.
|
|
||||||
pub fn from_turns(value: CSSFloat, was_calc: bool) -> Self {
|
|
||||||
Angle {
|
|
||||||
value: ComputedAngle::Turn(value),
|
|
||||||
was_calc,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an angle with the given value in radians.
|
|
||||||
pub fn from_radians(value: CSSFloat, was_calc: bool) -> Self {
|
|
||||||
Angle {
|
|
||||||
value: ComputedAngle::Rad(value),
|
|
||||||
was_calc,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether this specified angle came from a `calc()` expression.
|
/// Whether this specified angle came from a `calc()` expression.
|
||||||
|
@ -101,39 +112,21 @@ impl Angle {
|
||||||
self.was_calc
|
self.was_calc
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the amount of radians this angle represents.
|
|
||||||
#[inline]
|
|
||||||
pub fn radians(self) -> f32 {
|
|
||||||
self.value.radians()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the amount of degrees this angle represents.
|
|
||||||
#[inline]
|
|
||||||
pub fn degrees(self) -> f32 {
|
|
||||||
self.value.degrees()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `0deg`.
|
/// Returns `0deg`.
|
||||||
|
#[inline]
|
||||||
pub fn zero() -> Self {
|
pub fn zero() -> Self {
|
||||||
Self::from_degrees(0.0, false)
|
Self::from_degrees(0.0, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an `Angle` parsed from a `calc()` expression.
|
/// Returns an `Angle` parsed from a `calc()` expression.
|
||||||
pub fn from_calc(radians: CSSFloat) -> Self {
|
pub fn from_calc(degrees: CSSFloat) -> Self {
|
||||||
Angle {
|
Angle {
|
||||||
value: ComputedAngle::Rad(radians),
|
value: AngleDimension::Deg(degrees),
|
||||||
was_calc: true,
|
was_calc: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<ComputedAngle> for Angle {
|
|
||||||
#[inline]
|
|
||||||
fn as_ref(&self) -> &ComputedAngle {
|
|
||||||
&self.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Whether to allow parsing an unitless zero as a valid angle.
|
/// Whether to allow parsing an unitless zero as a valid angle.
|
||||||
///
|
///
|
||||||
/// This should always be `No`, except for exceptions like:
|
/// This should always be `No`, except for exceptions like:
|
||||||
|
@ -158,20 +151,26 @@ impl Parse for Angle {
|
||||||
|
|
||||||
impl Angle {
|
impl Angle {
|
||||||
/// Parse an `<angle>` value given a value and an unit.
|
/// Parse an `<angle>` value given a value and an unit.
|
||||||
pub fn parse_dimension(value: CSSFloat, unit: &str, from_calc: bool) -> Result<Angle, ()> {
|
pub fn parse_dimension(
|
||||||
let angle = match_ignore_ascii_case! { unit,
|
value: CSSFloat,
|
||||||
"deg" => Angle::from_degrees(value, from_calc),
|
unit: &str,
|
||||||
"grad" => Angle::from_gradians(value, from_calc),
|
was_calc: bool,
|
||||||
"turn" => Angle::from_turns(value, from_calc),
|
) -> Result<Angle, ()> {
|
||||||
"rad" => Angle::from_radians(value, from_calc),
|
let value = match_ignore_ascii_case! { unit,
|
||||||
|
"deg" => AngleDimension::Deg(value),
|
||||||
|
"grad" => AngleDimension::Grad(value),
|
||||||
|
"turn" => AngleDimension::Turn(value),
|
||||||
|
"rad" => AngleDimension::Rad(value),
|
||||||
_ => return Err(())
|
_ => return Err(())
|
||||||
};
|
};
|
||||||
Ok(angle)
|
|
||||||
|
Ok(Self { value, was_calc })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse an `<angle>` allowing unitless zero to represent a zero angle.
|
/// Parse an `<angle>` allowing unitless zero to represent a zero angle.
|
||||||
///
|
///
|
||||||
/// See the comment in `AllowUnitlessZeroAngle` for why.
|
/// See the comment in `AllowUnitlessZeroAngle` for why.
|
||||||
|
#[inline]
|
||||||
pub fn parse_with_unitless<'i, 't>(
|
pub fn parse_with_unitless<'i, 't>(
|
||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
|
|
|
@ -469,22 +469,22 @@ impl CalcNode {
|
||||||
CalcNode::Sub(ref a, ref b) => {
|
CalcNode::Sub(ref a, ref b) => {
|
||||||
let lhs = a.to_angle()?;
|
let lhs = a.to_angle()?;
|
||||||
let rhs = b.to_angle()?;
|
let rhs = b.to_angle()?;
|
||||||
Angle::from_calc(lhs.radians() - rhs.radians())
|
Angle::from_calc(lhs.degrees() - rhs.degrees())
|
||||||
},
|
},
|
||||||
CalcNode::Sum(ref a, ref b) => {
|
CalcNode::Sum(ref a, ref b) => {
|
||||||
let lhs = a.to_angle()?;
|
let lhs = a.to_angle()?;
|
||||||
let rhs = b.to_angle()?;
|
let rhs = b.to_angle()?;
|
||||||
Angle::from_calc(lhs.radians() + rhs.radians())
|
Angle::from_calc(lhs.degrees() + rhs.degrees())
|
||||||
},
|
},
|
||||||
CalcNode::Mul(ref a, ref b) => match a.to_angle() {
|
CalcNode::Mul(ref a, ref b) => match a.to_angle() {
|
||||||
Ok(lhs) => {
|
Ok(lhs) => {
|
||||||
let rhs = b.to_number()?;
|
let rhs = b.to_number()?;
|
||||||
Angle::from_calc(lhs.radians() * rhs)
|
Angle::from_calc(lhs.degrees() * rhs)
|
||||||
},
|
},
|
||||||
Err(..) => {
|
Err(..) => {
|
||||||
let lhs = a.to_number()?;
|
let lhs = a.to_number()?;
|
||||||
let rhs = b.to_angle()?;
|
let rhs = b.to_angle()?;
|
||||||
Angle::from_calc(lhs * rhs.radians())
|
Angle::from_calc(lhs * rhs.degrees())
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CalcNode::Div(ref a, ref b) => {
|
CalcNode::Div(ref a, ref b) => {
|
||||||
|
@ -493,7 +493,7 @@ impl CalcNode {
|
||||||
if rhs == 0. {
|
if rhs == 0. {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
Angle::from_calc(lhs.radians() / rhs)
|
Angle::from_calc(lhs.degrees() / rhs)
|
||||||
},
|
},
|
||||||
CalcNode::Number(..) |
|
CalcNode::Number(..) |
|
||||||
CalcNode::Length(..) |
|
CalcNode::Length(..) |
|
||||||
|
|
|
@ -301,7 +301,7 @@ impl SpecifiedFontStyle {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_angle(angle: &Angle) -> ComputedAngle {
|
fn compute_angle(angle: &Angle) -> ComputedAngle {
|
||||||
ComputedAngle::Deg(Self::compute_angle_degrees(angle))
|
ComputedAngle::from_degrees(Self::compute_angle_degrees(angle))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a suitable angle for font-style: oblique.
|
/// Parse a suitable angle for font-style: oblique.
|
||||||
|
|
|
@ -15,7 +15,6 @@ use selectors::parser::SelectorParseErrorKind;
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::f32::consts::PI;
|
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
use style_traits::{CssType, CssWriter, KeywordsCollectFn, ParseError};
|
use style_traits::{CssType, CssWriter, KeywordsCollectFn, ParseError};
|
||||||
use style_traits::{StyleParseErrorKind, SpecifiedValueInfo, ToCss};
|
use style_traits::{StyleParseErrorKind, SpecifiedValueInfo, ToCss};
|
||||||
|
@ -679,7 +678,7 @@ impl GradientKind {
|
||||||
impl generic::LineDirection for LineDirection {
|
impl generic::LineDirection for LineDirection {
|
||||||
fn points_downwards(&self, compat_mode: CompatMode) -> bool {
|
fn points_downwards(&self, compat_mode: CompatMode) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
LineDirection::Angle(ref angle) => angle.radians() == PI,
|
LineDirection::Angle(ref angle) => angle.degrees() == 180.0,
|
||||||
LineDirection::Vertical(Y::Bottom) if compat_mode == CompatMode::Modern => true,
|
LineDirection::Vertical(Y::Bottom) if compat_mode == CompatMode::Modern => true,
|
||||||
LineDirection::Vertical(Y::Top) if compat_mode != CompatMode::Modern => true,
|
LineDirection::Vertical(Y::Top) if compat_mode != CompatMode::Modern => true,
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue