Skip to content

Commit

Permalink
style: Make numbers keep track of whether they were specified as calc().
Browse files Browse the repository at this point in the history
  • Loading branch information
emilio committed Mar 27, 2017
1 parent c20bbb9 commit c7ce2ff
Show file tree
Hide file tree
Showing 9 changed files with 271 additions and 119 deletions.
3 changes: 2 additions & 1 deletion components/style/gecko_bindings/sugar/ns_timing_function.rs
Expand Up @@ -65,7 +65,8 @@ impl From<SpecifiedTimingFunction> for nsTimingFunction {
tf.set_as_step(nsTimingFunction_Type::StepEnd, steps);
},
SpecifiedTimingFunction::CubicBezier(p1, p2) => {
tf.set_as_cubic_bezier(p1, p2);
tf.set_as_cubic_bezier(Point2D::new(p1.x.value, p1.y.value),
Point2D::new(p2.x.value, p2.y.value));
},
SpecifiedTimingFunction::Keyword(keyword) => {
match keyword {
Expand Down
5 changes: 2 additions & 3 deletions components/style/properties/gecko.mako.rs
Expand Up @@ -1283,7 +1283,7 @@ fn static_assert() {
use properties::longhands::font_size_adjust::computed_value::T;
match v {
T::None => self.gecko.mFont.sizeAdjust = -1.0 as f32,
T::Number(n) => self.gecko.mFont.sizeAdjust = n.0 as f32,
T::Number(n) => self.gecko.mFont.sizeAdjust = n,
}
}

Expand All @@ -1293,11 +1293,10 @@ fn static_assert() {

pub fn clone_font_size_adjust(&self) -> longhands::font_size_adjust::computed_value::T {
use properties::longhands::font_size_adjust::computed_value::T;
use values::specified::Number;

match self.gecko.mFont.sizeAdjust {
-1.0 => T::None,
_ => T::Number(Number(self.gecko.mFont.sizeAdjust)),
_ => T::Number(self.gecko.mFont.sizeAdjust),
}
}

Expand Down
4 changes: 2 additions & 2 deletions components/style/properties/longhand/border.mako.rs
Expand Up @@ -223,7 +223,7 @@ ${helpers.single_keyword("-moz-float-edge", "content-box margin-box",

#[inline]
pub fn get_initial_specified_value() -> SpecifiedValue {
SpecifiedValue(vec![Either::Second(Number(0.0))])
SpecifiedValue(vec![Either::Second(Number::new(0.0))])
}

impl ToComputedValue for SpecifiedValue {
Expand Down Expand Up @@ -486,7 +486,7 @@ ${helpers.single_keyword("-moz-float-edge", "content-box margin-box",

#[inline]
pub fn get_initial_specified_value() -> SpecifiedValue {
SpecifiedValue(vec![SingleSpecifiedValue::Number(Number(1.0))])
SpecifiedValue(vec![SingleSpecifiedValue::Number(Number::new(1.0))])
}

impl ToComputedValue for SpecifiedValue {
Expand Down
187 changes: 140 additions & 47 deletions components/style/properties/longhand/box.mako.rs

Large diffs are not rendered by default.

58 changes: 47 additions & 11 deletions components/style/properties/longhand/font.mako.rs
Expand Up @@ -655,30 +655,65 @@ ${helpers.single_keyword("font-variant-caps",

<%helpers:longhand products="gecko" name="font-size-adjust" animatable="True"
spec="https://drafts.csswg.org/css-fonts/#propdef-font-size-adjust">
use std::fmt;
use style_traits::ToCss;
use values::HasViewportPercentage;
use values::computed::ComputedValueAsSpecified;
use values::specified::Number;

impl ComputedValueAsSpecified for SpecifiedValue {}
no_viewport_percentage!(SpecifiedValue);

#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum SpecifiedValue {
None,
Number(Number),
Number(specified::Number),
}

impl ToCss for SpecifiedValue {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where W: fmt::Write,
{
match *self {
SpecifiedValue::None => dest.write_str("none"),
SpecifiedValue::Number(number) => number.to_css(dest),
}
}
}

impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T;

fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
match *self {
SpecifiedValue::None => computed_value::T::None,
SpecifiedValue::Number(ref n) => computed_value::T::Number(n.to_computed_value(context)),
}
}

fn from_computed_value(computed: &computed_value::T) -> Self {
match *computed {
computed_value::T::None => SpecifiedValue::None,
computed_value::T::Number(ref v) => SpecifiedValue::Number(specified::Number::from_computed_value(v)),
}
}
}

pub mod computed_value {
use style_traits::ToCss;
use std::fmt;
use properties::animated_properties::Interpolate;
use values::specified::Number;
use std::fmt;
use style_traits::ToCss;
use values::CSSFloat;

pub use super::SpecifiedValue as T;
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum T {
None,
Number(CSSFloat),
}

impl ToCss for T {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where W: fmt::Write,
{
match *self {
T::None => dest.write_str("none"),
T::Number(number) => number.to_css(dest),
Expand All @@ -690,14 +725,15 @@ ${helpers.single_keyword("font-variant-caps",
fn interpolate(&self, other: &Self, time: f64) -> Result<Self, ()> {
match (*self, *other) {
(T::Number(ref number), T::Number(ref other)) =>
Ok(T::Number(Number(try!(number.0.interpolate(&other.0, time))))),
Ok(T::Number(try!(number.interpolate(other, time)))),
_ => Err(()),
}
}
}
}

#[inline] pub fn get_initial_value() -> computed_value::T {
#[inline]
pub fn get_initial_value() -> computed_value::T {
computed_value::T::None
}

Expand Down
42 changes: 22 additions & 20 deletions components/style/properties/longhand/inherited_text.mako.rs
Expand Up @@ -10,7 +10,7 @@
spec="https://drafts.csswg.org/css2/visudet.html#propdef-line-height">
use std::fmt;
use style_traits::ToCss;
use values::{CSSFloat, HasViewportPercentage};
use values::HasViewportPercentage;

impl HasViewportPercentage for SpecifiedValue {
fn has_viewport_percentage(&self) -> bool {
Expand All @@ -28,7 +28,7 @@
% if product == "gecko":
MozBlockHeight,
% endif
Number(CSSFloat),
Number(specified::Number),
LengthOrPercentage(specified::LengthOrPercentage),
}

Expand All @@ -40,7 +40,7 @@
SpecifiedValue::MozBlockHeight => dest.write_str("-moz-block-height"),
% endif
SpecifiedValue::LengthOrPercentage(ref value) => value.to_css(dest),
SpecifiedValue::Number(number) => write!(dest, "{}", number),
SpecifiedValue::Number(number) => number.to_css(dest),
}
}
}
Expand All @@ -52,24 +52,24 @@
// parsed as a plain Number rather than a Length (0px); this matches the behaviour
// of all major browsers
input.try(specified::Number::parse_non_negative)
.map(|n| SpecifiedValue::Number(n.0))
.or_else(|()| {
input.try(specified::LengthOrPercentage::parse_non_negative)
.map(SpecifiedValue::LengthOrPercentage)
.map(SpecifiedValue::Number)
.or_else(|()| {
match try!(input.next()) {
Token::Ident(ref value) if value.eq_ignore_ascii_case("normal") => {
Ok(SpecifiedValue::Normal)
}
% if product == "gecko":
Token::Ident(ref value) if value.eq_ignore_ascii_case("-moz-block-height") => {
Ok(SpecifiedValue::MozBlockHeight)
input.try(specified::LengthOrPercentage::parse_non_negative)
.map(SpecifiedValue::LengthOrPercentage)
.or_else(|()| {
match try!(input.next()) {
Token::Ident(ref value) if value.eq_ignore_ascii_case("normal") => {
Ok(SpecifiedValue::Normal)
}
% if product == "gecko":
Token::Ident(ref value) if value.eq_ignore_ascii_case("-moz-block-height") => {
Ok(SpecifiedValue::MozBlockHeight)
}
% endif
_ => Err(()),
}
% endif
_ => Err(()),
}
})
})
})
}
pub mod computed_value {
use app_units::Au;
Expand Down Expand Up @@ -116,7 +116,7 @@
% if product == "gecko":
SpecifiedValue::MozBlockHeight => computed_value::T::MozBlockHeight,
% endif
SpecifiedValue::Number(value) => computed_value::T::Number(value),
SpecifiedValue::Number(value) => computed_value::T::Number(value.to_computed_value(context)),
SpecifiedValue::LengthOrPercentage(ref value) => {
match *value {
specified::LengthOrPercentage::Length(ref value) =>
Expand Down Expand Up @@ -144,7 +144,9 @@
% if product == "gecko":
computed_value::T::MozBlockHeight => SpecifiedValue::MozBlockHeight,
% endif
computed_value::T::Number(value) => SpecifiedValue::Number(value),
computed_value::T::Number(ref value) => {
SpecifiedValue::Number(specified::Number::from_computed_value(value))
},
computed_value::T::Length(au) => {
SpecifiedValue::LengthOrPercentage(specified::LengthOrPercentage::Length(
ToComputedValue::from_computed_value(&au)
Expand Down
8 changes: 4 additions & 4 deletions components/style/properties/shorthand/position.mako.rs
Expand Up @@ -70,8 +70,8 @@

if input.try(|input| input.expect_ident_matching("none")).is_ok() {
return Ok(Longhands {
flex_grow: Number(0.0),
flex_shrink: Number(0.0),
flex_grow: Number::new(0.0),
flex_shrink: Number::new(0.0),
% if product == "gecko":
flex_basis: LengthOrPercentageOrAuto::Auto
% else:
Expand Down Expand Up @@ -105,8 +105,8 @@
return Err(())
}
Ok(Longhands {
flex_grow: grow.unwrap_or(Number(1.0)),
flex_shrink: shrink.unwrap_or(Number(1.0)),
flex_grow: grow.unwrap_or(Number::new(1.0)),
flex_shrink: shrink.unwrap_or(Number::new(1.0)),
% if product == "gecko":
flex_basis: basis.unwrap_or(LengthOrPercentageOrAuto::Length(NoCalcLength::zero()))
% else:
Expand Down
74 changes: 48 additions & 26 deletions components/style/values/specified/mod.rs
Expand Up @@ -219,17 +219,15 @@ pub fn parse_integer(input: &mut Parser) -> Result<CSSInteger, ()> {
}

#[allow(missing_docs)]
pub fn parse_number(input: &mut Parser) -> Result<f32, ()> {
pub fn parse_number(input: &mut Parser) -> Result<Number, ()> {
use std::f32;

match try!(input.next()) {
Token::Number(ref value) => {
use std::f32;
if value.value.is_finite() {
Ok(value.value)
} else if value.value.is_sign_positive() {
Ok(f32::MAX)
} else {
Ok(f32::MIN)
}
Ok(Number {
value: value.value.min(f32::MAX).max(f32::MIN),
was_calc: false,
})
},
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
let ast = try!(input.parse_nested_block(|i| CalcLengthOrPercentage::parse_sum(i, CalcUnit::Number)));
Expand All @@ -245,7 +243,12 @@ pub fn parse_number(input: &mut Parser) -> Result<f32, ()> {
}

match result {
Some(result) => Ok(result),
Some(result) => {
Ok(Number {
value: result.min(f32::MAX).max(f32::MIN),
was_calc: true,
})
},
_ => Err(())
}
}
Expand Down Expand Up @@ -525,24 +528,39 @@ impl ToCss for Time {
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct Number(pub CSSFloat);
pub struct Number {
/// The numeric value itself.
pub value: CSSFloat,
/// Whether this came from a `calc()` expression. This is needed for
/// serialization purposes, since `calc(1)` should still serialize to
/// `calc(1)`, not just `1`.
was_calc: bool,
}

no_viewport_percentage!(Number);

impl Parse for Number {
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
parse_number(input).map(Number)
parse_number(input)
}
}

impl Number {
fn parse_with_minimum(input: &mut Parser, min: CSSFloat) -> Result<Number, ()> {
match parse_number(input) {
Ok(value) if value >= min => Ok(Number(value)),
Ok(value) if value.value >= min => Ok(value),
_ => Err(()),
}
}

/// Returns a new number with the value `val`.
pub fn new(val: CSSFloat) -> Self {
Number {
value: val,
was_calc: false,
}
}

#[allow(missing_docs)]
pub fn parse_non_negative(input: &mut Parser) -> Result<Number, ()> {
Number::parse_with_minimum(input, 0.0)
Expand All @@ -558,17 +576,27 @@ impl ToComputedValue for Number {
type ComputedValue = CSSFloat;

#[inline]
fn to_computed_value(&self, _: &Context) -> CSSFloat { self.0 }
fn to_computed_value(&self, _: &Context) -> CSSFloat { self.value }

#[inline]
fn from_computed_value(computed: &CSSFloat) -> Self {
Number(*computed)
Number {
value: *computed,
was_calc: false,
}
}
}

impl ToCss for Number {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
self.0.to_css(dest)
if self.was_calc {
dest.write_str("calc(")?;
}
self.value.to_css(dest)?;
if self.was_calc {
dest.write_str(")")?;
}
Ok(())
}
}

Expand Down Expand Up @@ -606,7 +634,7 @@ impl ToCss for NumberOrPercentage {
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct Opacity(pub CSSFloat);
pub struct Opacity(Number);

no_viewport_percentage!(Opacity);

Expand All @@ -620,19 +648,13 @@ impl ToComputedValue for Opacity {
type ComputedValue = CSSFloat;

#[inline]
fn to_computed_value(&self, _: &Context) -> CSSFloat {
if self.0 < 0.0 {
0.0
} else if self.0 > 1.0 {
1.0
} else {
self.0
}
fn to_computed_value(&self, context: &Context) -> CSSFloat {
self.0.to_computed_value(context).min(1.0).max(0.0)
}

#[inline]
fn from_computed_value(computed: &CSSFloat) -> Self {
Opacity(*computed)
Opacity(Number::from_computed_value(computed))
}
}

Expand Down

0 comments on commit c7ce2ff

Please sign in to comment.