Skip to content

Commit

Permalink
stylo: Support other unit types in computed angle
Browse files Browse the repository at this point in the history
  • Loading branch information
canova committed May 1, 2017
1 parent 4483a76 commit f8710bc
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 79 deletions.
38 changes: 36 additions & 2 deletions components/style/gecko/conversions.rs
Expand Up @@ -12,11 +12,11 @@ use app_units::Au;
use gecko::values::{convert_rgba_to_nscolor, GeckoStyleCoordConvertible};
use gecko_bindings::bindings::{Gecko_CreateGradient, Gecko_SetGradientImageValue, Gecko_SetUrlImageValue};
use gecko_bindings::bindings::{Gecko_InitializeImageCropRect, Gecko_SetImageElement};
use gecko_bindings::structs::{nsStyleCoord_CalcValue, nsStyleImage};
use gecko_bindings::structs::{nsCSSUnit, nsStyleCoord_CalcValue, nsStyleImage};
use gecko_bindings::structs::{nsresult, SheetType};
use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordDataMut};
use stylesheets::{Origin, RulesMutateError};
use values::computed::{CalcLengthOrPercentage, Gradient, GradientItem, Image};
use values::computed::{Angle, CalcLengthOrPercentage, Gradient, GradientItem, Image};
use values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};

impl From<CalcLengthOrPercentage> for nsStyleCoord_CalcValue {
Expand Down Expand Up @@ -100,6 +100,40 @@ impl From<nsStyleCoord_CalcValue> for LengthOrPercentage {
}
}

impl From<Angle> for CoordDataValue {
fn from(reference: Angle) -> Self {
match reference {
Angle::Degree(val) => CoordDataValue::Degree(val),
Angle::Gradian(val) => CoordDataValue::Grad(val),
Angle::Radian(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::Degree(val) => (val, nsCSSUnit::eCSSUnit_Degree),
Angle::Gradian(val) => (val, nsCSSUnit::eCSSUnit_Grad),
Angle::Radian(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::Degree(value),
nsCSSUnit::eCSSUnit_Grad => Angle::Gradian(value),
nsCSSUnit::eCSSUnit_Radian => Angle::Radian(value),
nsCSSUnit::eCSSUnit_Turn => Angle::Turn(value),
_ => panic!("Unexpected unit {:?} for angle", unit),
}
}
}

impl nsStyleImage {
/// Set a given Servo `Image` value into this `nsStyleImage`.
pub fn set(&mut self, image: Image, cacheable: &mut bool) {
Expand Down
13 changes: 7 additions & 6 deletions components/style/gecko/values.rs
Expand Up @@ -249,15 +249,16 @@ impl<T: GeckoStyleCoordConvertible> GeckoStyleCoordConvertible for Option<T> {

impl GeckoStyleCoordConvertible for Angle {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
coord.set_value(CoordDataValue::Radian(self.radians()))
coord.set_value(CoordDataValue::from(*self));
}

fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
if let CoordDataValue::Radian(r) = coord.as_value() {
Some(Angle::from_radians(r))
// XXXManishearth should this handle Degree too?
} else {
None
match coord.as_value() {
CoordDataValue::Degree(val) => Some(Angle::Degree(val)),
CoordDataValue::Grad(val) => Some(Angle::Gradian(val)),
CoordDataValue::Radian(val) => Some(Angle::Radian(val)),
CoordDataValue::Turn(val) => Some(Angle::Turn(val)),
_ => None,
}
}
}
Expand Down
7 changes: 0 additions & 7 deletions components/style/gecko_bindings/bindings.rs
Expand Up @@ -1078,9 +1078,6 @@ extern "C" {
pub fn Gecko_CSSValue_GetAbsoluteLength(css_value: nsCSSValueBorrowed)
-> nscoord;
}
extern "C" {
pub fn Gecko_CSSValue_GetAngle(css_value: nsCSSValueBorrowed) -> f32;
}
extern "C" {
pub fn Gecko_CSSValue_GetKeyword(aCSSValue: nsCSSValueBorrowed)
-> nsCSSKeyword;
Expand Down Expand Up @@ -1114,10 +1111,6 @@ extern "C" {
pub fn Gecko_CSSValue_SetPercentage(css_value: nsCSSValueBorrowedMut,
percent: f32);
}
extern "C" {
pub fn Gecko_CSSValue_SetAngle(css_value: nsCSSValueBorrowedMut,
radians: f32);
}
extern "C" {
pub fn Gecko_CSSValue_SetCalc(css_value: nsCSSValueBorrowedMut,
calc: nsStyleCoord_CalcValue);
Expand Down
22 changes: 21 additions & 1 deletion components/style/gecko_bindings/sugar/ns_css_value.rs
Expand Up @@ -12,7 +12,7 @@ use gecko_string_cache::Atom;
use std::mem;
use std::ops::{Index, IndexMut};
use std::slice;
use values::computed::LengthOrPercentage;
use values::computed::{Angle, LengthOrPercentage};
use values::specified::url::SpecifiedUrl;

impl nsCSSValue {
Expand Down Expand Up @@ -173,6 +173,26 @@ impl nsCSSValue {
pub fn set_from<T: ToNsCssValue>(&mut self, value: &T) {
value.convert(self)
}

/// Returns an `Angle` value from this `nsCSSValue`.
///
/// Panics if the unit is not `eCSSUnit_Degree` `eCSSUnit_Grad`, `eCSSUnit_Turn`
/// or `eCSSUnit_Radian`.
pub fn get_angle(&self) -> Angle {
unsafe {
Angle::from_gecko_values(self.float_unchecked(), self.mUnit)
}
}

/// Sets Angle value to this nsCSSValue.
pub fn set_angle(&mut self, angle: Angle) {
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_Null);
let (value, unit) = angle.to_gecko_values();
self.mUnit = unit;
unsafe {
*self.mValue.mFloat.as_mut() = value;
}
}
}

impl Drop for nsCSSValue {
Expand Down
7 changes: 3 additions & 4 deletions components/style/properties/gecko.mako.rs
Expand Up @@ -1981,7 +1981,7 @@ fn static_assert() {
"length" : "bindings::Gecko_CSSValue_SetAbsoluteLength(%s, %s.0)",
"percentage" : "bindings::Gecko_CSSValue_SetPercentage(%s, %s)",
"lop" : "%s.set_lop(%s)",
"angle" : "bindings::Gecko_CSSValue_SetAngle(%s, %s.radians())",
"angle" : "%s.set_angle(%s)",
"number" : "bindings::Gecko_CSSValue_SetNumber(%s, %s)",
}
%>
Expand Down Expand Up @@ -2058,7 +2058,7 @@ fn static_assert() {
css_value_getters = {
"length" : "Au(bindings::Gecko_CSSValue_GetAbsoluteLength(%s))",
"lop" : "%s.get_lop()",
"angle" : "Angle::from_radians(bindings::Gecko_CSSValue_GetAngle(%s))",
"angle" : "%s.get_angle()",
"number" : "bindings::Gecko_CSSValue_GetNumber(%s)",
}
%>
Expand Down Expand Up @@ -2087,7 +2087,6 @@ fn static_assert() {
use properties::longhands::transform::computed_value;
use properties::longhands::transform::computed_value::ComputedMatrix;
use properties::longhands::transform::computed_value::ComputedOperation;
use values::computed::Angle;

if self.gecko.mSpecifiedTransform.mRawPtr.is_null() {
return computed_value::T(None);
Expand Down Expand Up @@ -3134,7 +3133,7 @@ fn static_assert() {
CoordDataValue::Factor(factor),
gecko_filter),
HueRotate(angle) => fill_filter(NS_STYLE_FILTER_HUE_ROTATE,
CoordDataValue::Radian(angle.radians()),
CoordDataValue::from(angle),
gecko_filter),
Invert(factor) => fill_filter(NS_STYLE_FILTER_INVERT,
CoordDataValue::Factor(factor),
Expand Down
38 changes: 30 additions & 8 deletions components/style/values/computed/mod.rs
Expand Up @@ -11,6 +11,8 @@ use media_queries::Device;
#[cfg(feature = "gecko")]
use properties;
use properties::{ComputedValues, StyleBuilder};
use std::f32;
use std::f32::consts::PI;
use std::fmt;
use style_traits::ToCss;
use super::{CSSFloat, CSSInteger, RGBA};
Expand Down Expand Up @@ -139,35 +141,55 @@ impl<T> ToComputedValue for T
/// A computed `<angle>` value.
#[derive(Clone, PartialEq, PartialOrd, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
pub struct Angle {
radians: CSSFloat,
pub enum Angle {
/// An angle with degree unit
Degree(CSSFloat),
/// An angle with gradian unit
Gradian(CSSFloat),
/// An angle with radian unit
Radian(CSSFloat),
/// An angle with turn unit
Turn(CSSFloat),
}

impl Angle {
/// Construct a computed `Angle` value from a radian amount.
pub fn from_radians(radians: CSSFloat) -> Self {
Angle {
radians: radians,
}
Angle::Radian(radians)
}

/// Return the amount of radians this angle represents.
#[inline]
pub fn radians(&self) -> CSSFloat {
self.radians
const RAD_PER_DEG: CSSFloat = PI / 180.0;
const RAD_PER_GRAD: CSSFloat = PI / 200.0;
const RAD_PER_TURN: CSSFloat = PI * 2.0;

let radians = match *self {
Angle::Degree(val) => val * RAD_PER_DEG,
Angle::Gradian(val) => val * RAD_PER_GRAD,
Angle::Turn(val) => val * RAD_PER_TURN,
Angle::Radian(val) => val,
};
radians.min(f32::MAX).max(f32::MIN)
}

/// Returns an angle that represents a rotation of zero radians.
pub fn zero() -> Self {
Self::from_radians(0.0)
Angle::Radian(0.0)
}
}

impl ToCss for Angle {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where W: fmt::Write,
{
write!(dest, "{}rad", self.radians())
match *self {
Angle::Degree(val) => write!(dest, "{}deg", val),
Angle::Gradian(val) => write!(dest, "{}grad", val),
Angle::Radian(val) => write!(dest, "{}rad", val),
Angle::Turn(val) => write!(dest, "{}turn", val),
}
}
}

Expand Down
67 changes: 16 additions & 51 deletions components/style/values/specified/mod.rs
Expand Up @@ -15,7 +15,6 @@ use self::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as GenericTrackS
use self::url::SpecifiedUrl;
use std::ascii::AsciiExt;
use std::f32;
use std::f32::consts::PI;
use std::fmt;
use std::ops::Mul;
use style_traits::ToCss;
Expand Down Expand Up @@ -300,45 +299,21 @@ impl Parse for BorderRadiusSize {
#[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
/// An angle consisting of a value and a unit.
///
/// Computed Angle is essentially same as specified angle except calc
/// value serialization. Therefore we are using computed Angle enum
/// to hold the value and unit type.
pub struct Angle {
value: CSSFloat,
unit: AngleUnit,
value: computed::Angle,
was_calc: bool,
}

#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
/// A unit used together with an angle.
pub enum AngleUnit {
/// Degrees, short name "deg".
Degree,
/// Gradians, short name "grad".
Gradian,
/// Radians, short name "rad".
Radian,
/// Turns, short name "turn".
Turn,
}

impl ToCss for AngleUnit {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
use self::AngleUnit::*;
dest.write_str(match *self {
Degree => "deg",
Gradian => "grad",
Radian => "rad",
Turn => "turn",
})
}
}

impl ToCss for Angle {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
if self.was_calc {
dest.write_str("calc(")?;
}
self.value.to_css(dest)?;
self.unit.to_css(dest)?;
if self.was_calc {
dest.write_str(")")?;
}
Expand All @@ -350,48 +325,39 @@ impl ToComputedValue for Angle {
type ComputedValue = computed::Angle;

fn to_computed_value(&self, _context: &Context) -> Self::ComputedValue {
computed::Angle::from_radians(self.radians())
self.value
}

fn from_computed_value(computed: &Self::ComputedValue) -> Self {
Angle::from_radians(computed.radians())
Angle {
value: *computed,
was_calc: false,
}
}
}

impl Angle {
/// Returns an angle with the given value in degrees.
pub fn from_degrees(value: CSSFloat) -> Self {
Angle { value: value, unit: AngleUnit::Degree, was_calc: false }
Angle { value: computed::Angle::Degree(value), was_calc: false }
}
/// Returns an angle with the given value in gradians.
pub fn from_gradians(value: CSSFloat) -> Self {
Angle { value: value, unit: AngleUnit::Gradian, was_calc: false }
Angle { value: computed::Angle::Gradian(value), was_calc: false }
}
/// Returns an angle with the given value in turns.
pub fn from_turns(value: CSSFloat) -> Self {
Angle { value: value, unit: AngleUnit::Turn, was_calc: false }
Angle { value: computed::Angle::Turn(value), was_calc: false }
}
/// Returns an angle with the given value in radians.
pub fn from_radians(value: CSSFloat) -> Self {
Angle { value: value, unit: AngleUnit::Radian, was_calc: false }
Angle { value: computed::Angle::Radian(value), was_calc: false }
}

#[inline]
#[allow(missing_docs)]
pub fn radians(self) -> f32 {
use self::AngleUnit::*;

const RAD_PER_DEG: CSSFloat = PI / 180.0;
const RAD_PER_GRAD: CSSFloat = PI / 200.0;
const RAD_PER_TURN: CSSFloat = PI * 2.0;

let radians = match self.unit {
Degree => self.value * RAD_PER_DEG,
Gradian => self.value * RAD_PER_GRAD,
Turn => self.value * RAD_PER_TURN,
Radian => self.value,
};
radians.min(f32::MAX).max(f32::MIN)
self.value.radians()
}

/// Returns an angle value that represents zero.
Expand All @@ -402,8 +368,7 @@ impl Angle {
/// Returns an `Angle` parsed from a `calc()` expression.
pub fn from_calc(radians: CSSFloat) -> Self {
Angle {
value: radians,
unit: AngleUnit::Radian,
value: computed::Angle::Radian(radians),
was_calc: true,
}
}
Expand Down

0 comments on commit f8710bc

Please sign in to comment.