mirror of
https://github.com/servo/servo.git
synced 2025-08-04 21:20:23 +01:00
Auto merge of #16144 - emilio:number-calc, r=heycam
style: Make numbers keep track of whether they were specified as calc(). Fixes #15960 <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/16144) <!-- Reviewable:end -->
This commit is contained in:
commit
b6bc49225e
28 changed files with 778 additions and 319 deletions
|
@ -200,7 +200,7 @@ impl ToFilterOps for filter::T {
|
||||||
Filter::Brightness(amount) => result.push(webrender_traits::FilterOp::Brightness(amount)),
|
Filter::Brightness(amount) => result.push(webrender_traits::FilterOp::Brightness(amount)),
|
||||||
Filter::Contrast(amount) => result.push(webrender_traits::FilterOp::Contrast(amount)),
|
Filter::Contrast(amount) => result.push(webrender_traits::FilterOp::Contrast(amount)),
|
||||||
Filter::Grayscale(amount) => result.push(webrender_traits::FilterOp::Grayscale(amount)),
|
Filter::Grayscale(amount) => result.push(webrender_traits::FilterOp::Grayscale(amount)),
|
||||||
Filter::HueRotate(angle) => result.push(webrender_traits::FilterOp::HueRotate(angle.0)),
|
Filter::HueRotate(angle) => result.push(webrender_traits::FilterOp::HueRotate(angle.radians())),
|
||||||
Filter::Invert(amount) => result.push(webrender_traits::FilterOp::Invert(amount)),
|
Filter::Invert(amount) => result.push(webrender_traits::FilterOp::Invert(amount)),
|
||||||
Filter::Opacity(amount) => result.push(webrender_traits::FilterOp::Opacity(amount.into())),
|
Filter::Opacity(amount) => result.push(webrender_traits::FilterOp::Opacity(amount.into())),
|
||||||
Filter::Saturate(amount) => result.push(webrender_traits::FilterOp::Saturate(amount)),
|
Filter::Saturate(amount) => result.push(webrender_traits::FilterOp::Saturate(amount)),
|
||||||
|
|
|
@ -496,8 +496,8 @@ impl LayoutElementHelpers for LayoutJS<Element> {
|
||||||
shared_lock,
|
shared_lock,
|
||||||
PropertyDeclaration::BorderSpacing(
|
PropertyDeclaration::BorderSpacing(
|
||||||
Box::new(border_spacing::SpecifiedValue {
|
Box::new(border_spacing::SpecifiedValue {
|
||||||
horizontal: width_value.clone(),
|
horizontal: width_value,
|
||||||
vertical: width_value,
|
vertical: None,
|
||||||
}))));
|
}))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -343,7 +343,7 @@ impl PropertyAnimation {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn does_animate(&self) -> bool {
|
fn does_animate(&self) -> bool {
|
||||||
self.property.does_animate() && self.duration != Time(0.0)
|
self.property.does_animate() && self.duration.seconds() != 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether this animation has the same end value as another one.
|
/// Whether this animation has the same end value as another one.
|
||||||
|
@ -681,7 +681,7 @@ pub fn update_style_for_animation(context: &SharedStyleContext,
|
||||||
transition_property, name);
|
transition_property, name);
|
||||||
match PropertyAnimation::from_transition_property(*transition_property,
|
match PropertyAnimation::from_transition_property(*transition_property,
|
||||||
timing_function,
|
timing_function,
|
||||||
Time(relative_duration as f32),
|
Time::from_seconds(relative_duration as f32),
|
||||||
&from_style,
|
&from_style,
|
||||||
&target_style) {
|
&target_style) {
|
||||||
Some(property_animation) => {
|
Some(property_animation) => {
|
||||||
|
|
|
@ -59,13 +59,16 @@ impl From<SpecifiedTimingFunction> for nsTimingFunction {
|
||||||
|
|
||||||
match function {
|
match function {
|
||||||
SpecifiedTimingFunction::Steps(steps, StartEnd::Start) => {
|
SpecifiedTimingFunction::Steps(steps, StartEnd::Start) => {
|
||||||
tf.set_as_step(nsTimingFunction_Type::StepStart, steps);
|
debug_assert!(steps.value() >= 0);
|
||||||
|
tf.set_as_step(nsTimingFunction_Type::StepStart, steps.value() as u32);
|
||||||
},
|
},
|
||||||
SpecifiedTimingFunction::Steps(steps, StartEnd::End) => {
|
SpecifiedTimingFunction::Steps(steps, StartEnd::End) => {
|
||||||
tf.set_as_step(nsTimingFunction_Type::StepEnd, steps);
|
debug_assert!(steps.value() >= 0);
|
||||||
|
tf.set_as_step(nsTimingFunction_Type::StepEnd, steps.value() as u32);
|
||||||
},
|
},
|
||||||
SpecifiedTimingFunction::CubicBezier(p1, p2) => {
|
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) => {
|
SpecifiedTimingFunction::Keyword(keyword) => {
|
||||||
match keyword {
|
match keyword {
|
||||||
|
|
|
@ -1283,7 +1283,7 @@ fn static_assert() {
|
||||||
use properties::longhands::font_size_adjust::computed_value::T;
|
use properties::longhands::font_size_adjust::computed_value::T;
|
||||||
match v {
|
match v {
|
||||||
T::None => self.gecko.mFont.sizeAdjust = -1.0 as f32,
|
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1293,11 +1293,10 @@ fn static_assert() {
|
||||||
|
|
||||||
pub fn clone_font_size_adjust(&self) -> longhands::font_size_adjust::computed_value::T {
|
pub fn clone_font_size_adjust(&self) -> longhands::font_size_adjust::computed_value::T {
|
||||||
use properties::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 {
|
match self.gecko.mFont.sizeAdjust {
|
||||||
-1.0 => T::None,
|
-1.0 => T::None,
|
||||||
_ => T::Number(Number(self.gecko.mFont.sizeAdjust)),
|
_ => T::Number(self.gecko.mFont.sizeAdjust),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1356,8 +1355,8 @@ fn static_assert() {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn ${type}_${ident}_at(&self, index: usize)
|
pub fn ${type}_${ident}_at(&self, index: usize)
|
||||||
-> longhands::${type}_${ident}::computed_value::SingleComputedValue {
|
-> longhands::${type}_${ident}::computed_value::SingleComputedValue {
|
||||||
use values::specified::Time;
|
use values::computed::Time;
|
||||||
Time(self.gecko.m${type.capitalize()}s[index].m${gecko_ffi_name} / 1000.)
|
Time::from_seconds(self.gecko.m${type.capitalize()}s[index].m${gecko_ffi_name} / 1000.)
|
||||||
}
|
}
|
||||||
${impl_animation_or_transition_count(type, ident, gecko_ffi_name)}
|
${impl_animation_or_transition_count(type, ident, gecko_ffi_name)}
|
||||||
${impl_copy_animation_or_transition_value(type, ident, gecko_ffi_name)}
|
${impl_copy_animation_or_transition_value(type, ident, gecko_ffi_name)}
|
||||||
|
@ -1665,7 +1664,7 @@ fn static_assert() {
|
||||||
"length" : "bindings::Gecko_CSSValue_SetAbsoluteLength(%s, %s.0)",
|
"length" : "bindings::Gecko_CSSValue_SetAbsoluteLength(%s, %s.0)",
|
||||||
"percentage" : "bindings::Gecko_CSSValue_SetPercentage(%s, %s)",
|
"percentage" : "bindings::Gecko_CSSValue_SetPercentage(%s, %s)",
|
||||||
"lop" : "%s.set_lop(%s)",
|
"lop" : "%s.set_lop(%s)",
|
||||||
"angle" : "bindings::Gecko_CSSValue_SetAngle(%s, %s.0)",
|
"angle" : "bindings::Gecko_CSSValue_SetAngle(%s, %s.radians())",
|
||||||
"number" : "bindings::Gecko_CSSValue_SetNumber(%s, %s)",
|
"number" : "bindings::Gecko_CSSValue_SetNumber(%s, %s)",
|
||||||
}
|
}
|
||||||
%>
|
%>
|
||||||
|
@ -1739,7 +1738,7 @@ fn static_assert() {
|
||||||
css_value_getters = {
|
css_value_getters = {
|
||||||
"length" : "Au(bindings::Gecko_CSSValue_GetAbsoluteLength(%s))",
|
"length" : "Au(bindings::Gecko_CSSValue_GetAbsoluteLength(%s))",
|
||||||
"lop" : "%s.get_lop()",
|
"lop" : "%s.get_lop()",
|
||||||
"angle" : "Angle(bindings::Gecko_CSSValue_GetAngle(%s))",
|
"angle" : "Angle::from_radians(bindings::Gecko_CSSValue_GetAngle(%s))",
|
||||||
"number" : "bindings::Gecko_CSSValue_GetNumber(%s)",
|
"number" : "bindings::Gecko_CSSValue_GetNumber(%s)",
|
||||||
}
|
}
|
||||||
%>
|
%>
|
||||||
|
|
|
@ -19,8 +19,10 @@
|
||||||
#[inline] pub fn get_initial_specified_value() -> SpecifiedValue { ${initial_specified_value} }
|
#[inline] pub fn get_initial_specified_value() -> SpecifiedValue { ${initial_specified_value} }
|
||||||
% endif
|
% endif
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
#[inline] pub fn parse(context: &ParserContext, input: &mut Parser)
|
#[inline]
|
||||||
-> Result<SpecifiedValue, ()> {
|
pub fn parse(context: &ParserContext,
|
||||||
|
input: &mut Parser)
|
||||||
|
-> Result<SpecifiedValue, ()> {
|
||||||
% if needs_context:
|
% if needs_context:
|
||||||
specified::${type}::${parse_method}(context, input)
|
specified::${type}::${parse_method}(context, input)
|
||||||
% else:
|
% else:
|
||||||
|
|
|
@ -36,7 +36,6 @@ use values::computed::{CalcLengthOrPercentage, Context, LengthOrPercentage};
|
||||||
use values::computed::{MaxLength, MinLength};
|
use values::computed::{MaxLength, MinLength};
|
||||||
use values::computed::position::{HorizontalPosition, Position, VerticalPosition};
|
use values::computed::position::{HorizontalPosition, Position, VerticalPosition};
|
||||||
use values::computed::ToComputedValue;
|
use values::computed::ToComputedValue;
|
||||||
use values::specified::Angle as SpecifiedAngle;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -455,7 +454,7 @@ impl Interpolate for i32 {
|
||||||
impl Interpolate for Angle {
|
impl Interpolate for Angle {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn interpolate(&self, other: &Angle, progress: f64) -> Result<Self, ()> {
|
fn interpolate(&self, other: &Angle, progress: f64) -> Result<Self, ()> {
|
||||||
self.radians().interpolate(&other.radians(), progress).map(Angle)
|
self.radians().interpolate(&other.radians(), progress).map(Angle::from_radians)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -952,7 +951,7 @@ fn build_identity_transform_list(list: &[TransformOperation]) -> Vec<TransformOp
|
||||||
result.push(TransformOperation::Matrix(identity));
|
result.push(TransformOperation::Matrix(identity));
|
||||||
}
|
}
|
||||||
TransformOperation::Skew(..) => {
|
TransformOperation::Skew(..) => {
|
||||||
result.push(TransformOperation::Skew(Angle(0.0), Angle(0.0)));
|
result.push(TransformOperation::Skew(Angle::zero(), Angle::zero()))
|
||||||
}
|
}
|
||||||
TransformOperation::Translate(..) => {
|
TransformOperation::Translate(..) => {
|
||||||
result.push(TransformOperation::Translate(LengthOrPercentage::zero(),
|
result.push(TransformOperation::Translate(LengthOrPercentage::zero(),
|
||||||
|
@ -963,7 +962,7 @@ fn build_identity_transform_list(list: &[TransformOperation]) -> Vec<TransformOp
|
||||||
result.push(TransformOperation::Scale(1.0, 1.0, 1.0));
|
result.push(TransformOperation::Scale(1.0, 1.0, 1.0));
|
||||||
}
|
}
|
||||||
TransformOperation::Rotate(..) => {
|
TransformOperation::Rotate(..) => {
|
||||||
result.push(TransformOperation::Rotate(0.0, 0.0, 1.0, Angle(0.0)));
|
result.push(TransformOperation::Rotate(0.0, 0.0, 1.0, Angle::zero()));
|
||||||
}
|
}
|
||||||
TransformOperation::Perspective(..) => {
|
TransformOperation::Perspective(..) => {
|
||||||
// http://dev.w3.org/csswg/css-transforms/#identity-transform-function
|
// http://dev.w3.org/csswg/css-transforms/#identity-transform-function
|
||||||
|
@ -1052,7 +1051,7 @@ fn interpolate_transform_list(from_list: &[TransformOperation],
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://drafts.csswg.org/css-transforms/#Rotate3dDefined
|
/// https://drafts.csswg.org/css-transforms/#Rotate3dDefined
|
||||||
fn rotate_to_matrix(x: f32, y: f32, z: f32, a: SpecifiedAngle) -> ComputedMatrix {
|
fn rotate_to_matrix(x: f32, y: f32, z: f32, a: Angle) -> ComputedMatrix {
|
||||||
let half_rad = a.radians() / 2.0;
|
let half_rad = a.radians() / 2.0;
|
||||||
let sc = (half_rad).sin() * (half_rad).cos();
|
let sc = (half_rad).sin() * (half_rad).cos();
|
||||||
let sq = (half_rad).sin().powi(2);
|
let sq = (half_rad).sin().powi(2);
|
||||||
|
|
|
@ -223,7 +223,7 @@ ${helpers.single_keyword("-moz-float-edge", "content-box margin-box",
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_initial_specified_value() -> SpecifiedValue {
|
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 {
|
impl ToComputedValue for SpecifiedValue {
|
||||||
|
@ -486,7 +486,7 @@ ${helpers.single_keyword("-moz-float-edge", "content-box margin-box",
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_initial_specified_value() -> SpecifiedValue {
|
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 {
|
impl ToComputedValue for SpecifiedValue {
|
||||||
|
|
|
@ -419,13 +419,13 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_initial_value() -> Time {
|
pub fn get_initial_value() -> computed_value::T {
|
||||||
Time(0.0)
|
computed_value::T::zero()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_initial_specified_value() -> SpecifiedValue {
|
pub fn get_initial_specified_value() -> SpecifiedValue {
|
||||||
SpecifiedValue(0.0)
|
Time::zero()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
|
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
|
||||||
|
@ -440,7 +440,7 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
|
||||||
extra_prefixes="moz webkit"
|
extra_prefixes="moz webkit"
|
||||||
spec="https://drafts.csswg.org/css-transitions/#propdef-transition-timing-function">
|
spec="https://drafts.csswg.org/css-transitions/#propdef-transition-timing-function">
|
||||||
use self::computed_value::StartEnd;
|
use self::computed_value::StartEnd;
|
||||||
|
use values::specified::Number;
|
||||||
use euclid::point::{Point2D, TypedPoint2D};
|
use euclid::point::{Point2D, TypedPoint2D};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
@ -450,31 +450,31 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn ease() -> computed_value::T {
|
fn ease() -> computed_value::T {
|
||||||
computed_value::T::CubicBezier(TypedPoint2D::new(0.25, 0.1),
|
computed_value::T::CubicBezier(TypedPoint2D::new(0.25, 0.1),
|
||||||
TypedPoint2D::new(0.25, 1.0))
|
TypedPoint2D::new(0.25, 1.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn linear() -> computed_value::T {
|
fn linear() -> computed_value::T {
|
||||||
computed_value::T::CubicBezier(TypedPoint2D::new(0.0, 0.0),
|
computed_value::T::CubicBezier(TypedPoint2D::new(0.0, 0.0),
|
||||||
TypedPoint2D::new(1.0, 1.0))
|
TypedPoint2D::new(1.0, 1.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn ease_in() -> computed_value::T {
|
fn ease_in() -> computed_value::T {
|
||||||
computed_value::T::CubicBezier(TypedPoint2D::new(0.42, 0.0),
|
computed_value::T::CubicBezier(TypedPoint2D::new(0.42, 0.0),
|
||||||
TypedPoint2D::new(1.0, 1.0))
|
TypedPoint2D::new(1.0, 1.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn ease_out() -> computed_value::T {
|
fn ease_out() -> computed_value::T {
|
||||||
computed_value::T::CubicBezier(TypedPoint2D::new(0.0, 0.0),
|
computed_value::T::CubicBezier(TypedPoint2D::new(0.0, 0.0),
|
||||||
TypedPoint2D::new(0.58, 1.0))
|
TypedPoint2D::new(0.58, 1.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn ease_in_out() -> computed_value::T {
|
fn ease_in_out() -> computed_value::T {
|
||||||
computed_value::T::CubicBezier(TypedPoint2D::new(0.42, 0.0),
|
computed_value::T::CubicBezier(TypedPoint2D::new(0.42, 0.0),
|
||||||
TypedPoint2D::new(0.58, 1.0))
|
TypedPoint2D::new(0.58, 1.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
static STEP_START: computed_value::T =
|
static STEP_START: computed_value::T =
|
||||||
|
@ -487,6 +487,7 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
|
||||||
use parser::{Parse, ParserContext};
|
use parser::{Parse, ParserContext};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
|
use values::specified;
|
||||||
|
|
||||||
pub use super::parse;
|
pub use super::parse;
|
||||||
|
|
||||||
|
@ -498,7 +499,9 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToCss for T {
|
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 {
|
match *self {
|
||||||
T::CubicBezier(p1, p2) => {
|
T::CubicBezier(p1, p2) => {
|
||||||
try!(dest.write_str("cubic-bezier("));
|
try!(dest.write_str("cubic-bezier("));
|
||||||
|
@ -512,7 +515,7 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
|
||||||
dest.write_str(")")
|
dest.write_str(")")
|
||||||
}
|
}
|
||||||
T::Steps(steps, start_end) => {
|
T::Steps(steps, start_end) => {
|
||||||
super::serialize_steps(dest, steps, start_end)
|
super::serialize_steps(dest, specified::Integer::new(steps as i32), start_end)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -526,7 +529,9 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToCss for StartEnd {
|
impl ToCss for StartEnd {
|
||||||
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 {
|
match *self {
|
||||||
StartEnd::Start => dest.write_str("start"),
|
StartEnd::Start => dest.write_str("start"),
|
||||||
StartEnd::End => dest.write_str("end"),
|
StartEnd::End => dest.write_str("end"),
|
||||||
|
@ -547,8 +552,8 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
pub enum SpecifiedValue {
|
pub enum SpecifiedValue {
|
||||||
CubicBezier(Point2D<f32>, Point2D<f32>),
|
CubicBezier(Point2D<Number>, Point2D<Number>),
|
||||||
Steps(u32, StartEnd),
|
Steps(specified::Integer, StartEnd),
|
||||||
Keyword(FunctionKeyword),
|
Keyword(FunctionKeyword),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -557,7 +562,8 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
|
||||||
if let Ok(function_name) = input.try(|input| input.expect_function()) {
|
if let Ok(function_name) = input.try(|input| input.expect_function()) {
|
||||||
return match_ignore_ascii_case! { &function_name,
|
return match_ignore_ascii_case! { &function_name,
|
||||||
"cubic-bezier" => {
|
"cubic-bezier" => {
|
||||||
let (mut p1x, mut p1y, mut p2x, mut p2y) = (0.0, 0.0, 0.0, 0.0);
|
let (mut p1x, mut p1y, mut p2x, mut p2y) =
|
||||||
|
(Number::new(0.0), Number::new(0.0), Number::new(0.0), Number::new(0.0));
|
||||||
try!(input.parse_nested_block(|input| {
|
try!(input.parse_nested_block(|input| {
|
||||||
p1x = try!(specified::parse_number(input));
|
p1x = try!(specified::parse_number(input));
|
||||||
try!(input.expect_comma());
|
try!(input.expect_comma());
|
||||||
|
@ -568,7 +574,8 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
|
||||||
p2y = try!(specified::parse_number(input));
|
p2y = try!(specified::parse_number(input));
|
||||||
Ok(())
|
Ok(())
|
||||||
}));
|
}));
|
||||||
if p1x < 0.0 || p1x > 1.0 || p2x < 0.0 || p2x > 1.0 {
|
if p1x.value < 0.0 || p1x.value > 1.0 ||
|
||||||
|
p2x.value < 0.0 || p2x.value > 1.0 {
|
||||||
return Err(())
|
return Err(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -576,10 +583,10 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
|
||||||
Ok(SpecifiedValue::CubicBezier(p1, p2))
|
Ok(SpecifiedValue::CubicBezier(p1, p2))
|
||||||
},
|
},
|
||||||
"steps" => {
|
"steps" => {
|
||||||
let (mut step_count, mut start_end) = (0, StartEnd::End);
|
let (mut step_count, mut start_end) = (specified::Integer::new(0), StartEnd::End);
|
||||||
try!(input.parse_nested_block(|input| {
|
try!(input.parse_nested_block(|input| {
|
||||||
step_count = try!(specified::parse_integer(input));
|
step_count = try!(specified::parse_integer(input));
|
||||||
if step_count < 1 {
|
if step_count.value() < 1 {
|
||||||
return Err(())
|
return Err(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -593,7 +600,7 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}));
|
}));
|
||||||
Ok(SpecifiedValue::Steps(step_count as u32, start_end))
|
Ok(SpecifiedValue::Steps(step_count, start_end))
|
||||||
},
|
},
|
||||||
_ => Err(())
|
_ => Err(())
|
||||||
}
|
}
|
||||||
|
@ -602,8 +609,11 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_steps<W>(dest: &mut W, steps: u32,
|
fn serialize_steps<W>(dest: &mut W,
|
||||||
start_end: StartEnd) -> fmt::Result where W: fmt::Write {
|
steps: specified::Integer,
|
||||||
|
start_end: StartEnd) -> fmt::Result
|
||||||
|
where W: fmt::Write,
|
||||||
|
{
|
||||||
try!(dest.write_str("steps("));
|
try!(dest.write_str("steps("));
|
||||||
try!(steps.to_css(dest));
|
try!(steps.to_css(dest));
|
||||||
if let StartEnd::Start = start_end {
|
if let StartEnd::Start = start_end {
|
||||||
|
@ -633,10 +643,10 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
|
||||||
SpecifiedValue::Keyword(keyword) => {
|
SpecifiedValue::Keyword(keyword) => {
|
||||||
match keyword {
|
match keyword {
|
||||||
FunctionKeyword::StepStart => {
|
FunctionKeyword::StepStart => {
|
||||||
serialize_steps(dest, 1, StartEnd::Start)
|
serialize_steps(dest, specified::Integer::new(1), StartEnd::Start)
|
||||||
},
|
},
|
||||||
FunctionKeyword::StepEnd => {
|
FunctionKeyword::StepEnd => {
|
||||||
serialize_steps(dest, 1, StartEnd::End)
|
serialize_steps(dest, specified::Integer::new(1), StartEnd::End)
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
keyword.to_css(dest)
|
keyword.to_css(dest)
|
||||||
|
@ -651,13 +661,15 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
|
||||||
type ComputedValue = computed_value::T;
|
type ComputedValue = computed_value::T;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_computed_value(&self, _context: &Context) -> computed_value::T {
|
fn to_computed_value(&self, context: &Context) -> computed_value::T {
|
||||||
match *self {
|
match *self {
|
||||||
SpecifiedValue::CubicBezier(p1, p2) => {
|
SpecifiedValue::CubicBezier(p1, p2) => {
|
||||||
computed_value::T::CubicBezier(p1, p2)
|
computed_value::T::CubicBezier(
|
||||||
|
Point2D::new(p1.x.to_computed_value(context), p1.y.to_computed_value(context)),
|
||||||
|
Point2D::new(p2.x.to_computed_value(context), p2.y.to_computed_value(context)))
|
||||||
},
|
},
|
||||||
SpecifiedValue::Steps(count, start_end) => {
|
SpecifiedValue::Steps(count, start_end) => {
|
||||||
computed_value::T::Steps(count, start_end)
|
computed_value::T::Steps(count.to_computed_value(context) as u32, start_end)
|
||||||
},
|
},
|
||||||
SpecifiedValue::Keyword(keyword) => {
|
SpecifiedValue::Keyword(keyword) => {
|
||||||
match keyword {
|
match keyword {
|
||||||
|
@ -676,10 +688,15 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
|
||||||
fn from_computed_value(computed: &computed_value::T) -> Self {
|
fn from_computed_value(computed: &computed_value::T) -> Self {
|
||||||
match *computed {
|
match *computed {
|
||||||
computed_value::T::CubicBezier(p1, p2) => {
|
computed_value::T::CubicBezier(p1, p2) => {
|
||||||
SpecifiedValue::CubicBezier(p1, p2)
|
SpecifiedValue::CubicBezier(
|
||||||
|
Point2D::new(Number::from_computed_value(&p1.x),
|
||||||
|
Number::from_computed_value(&p1.y)),
|
||||||
|
Point2D::new(Number::from_computed_value(&p2.x),
|
||||||
|
Number::from_computed_value(&p2.y)))
|
||||||
},
|
},
|
||||||
computed_value::T::Steps(count, start_end) => {
|
computed_value::T::Steps(count, start_end) => {
|
||||||
SpecifiedValue::Steps(count, start_end)
|
let int_count = count as i32;
|
||||||
|
SpecifiedValue::Steps(specified::Integer::from_computed_value(&int_count), start_end)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1083,6 +1100,7 @@ ${helpers.predefined_type("scroll-snap-coordinate",
|
||||||
fixpos_cb="True"
|
fixpos_cb="True"
|
||||||
spec="https://drafts.csswg.org/css-transforms/#propdef-transform">
|
spec="https://drafts.csswg.org/css-transforms/#propdef-transform">
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
|
use values::specified::Number;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
use values::CSSFloat;
|
use values::CSSFloat;
|
||||||
use values::HasViewportPercentage;
|
use values::HasViewportPercentage;
|
||||||
|
@ -1131,7 +1149,60 @@ ${helpers.predefined_type("scroll-snap-coordinate",
|
||||||
pub struct T(pub Option<Vec<ComputedOperation>>);
|
pub struct T(pub Option<Vec<ComputedOperation>>);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use self::computed_value::ComputedMatrix as SpecifiedMatrix;
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
|
pub struct SpecifiedMatrix {
|
||||||
|
pub m11: Number, pub m12: Number, pub m13: Number, pub m14: Number,
|
||||||
|
pub m21: Number, pub m22: Number, pub m23: Number, pub m24: Number,
|
||||||
|
pub m31: Number, pub m32: Number, pub m33: Number, pub m34: Number,
|
||||||
|
pub m41: Number, pub m42: Number, pub m43: Number, pub m44: Number,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToComputedValue for SpecifiedMatrix {
|
||||||
|
type ComputedValue = computed_value::ComputedMatrix;
|
||||||
|
|
||||||
|
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||||
|
computed_value::ComputedMatrix {
|
||||||
|
m11: self.m11.to_computed_value(context),
|
||||||
|
m12: self.m12.to_computed_value(context),
|
||||||
|
m13: self.m13.to_computed_value(context),
|
||||||
|
m14: self.m14.to_computed_value(context),
|
||||||
|
m21: self.m21.to_computed_value(context),
|
||||||
|
m22: self.m22.to_computed_value(context),
|
||||||
|
m23: self.m23.to_computed_value(context),
|
||||||
|
m24: self.m24.to_computed_value(context),
|
||||||
|
m31: self.m31.to_computed_value(context),
|
||||||
|
m32: self.m32.to_computed_value(context),
|
||||||
|
m33: self.m33.to_computed_value(context),
|
||||||
|
m34: self.m34.to_computed_value(context),
|
||||||
|
m41: self.m41.to_computed_value(context),
|
||||||
|
m42: self.m42.to_computed_value(context),
|
||||||
|
m43: self.m43.to_computed_value(context),
|
||||||
|
m44: self.m44.to_computed_value(context),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||||
|
SpecifiedMatrix {
|
||||||
|
m11: Number::from_computed_value(&computed.m11),
|
||||||
|
m12: Number::from_computed_value(&computed.m12),
|
||||||
|
m13: Number::from_computed_value(&computed.m13),
|
||||||
|
m14: Number::from_computed_value(&computed.m14),
|
||||||
|
m21: Number::from_computed_value(&computed.m21),
|
||||||
|
m22: Number::from_computed_value(&computed.m22),
|
||||||
|
m23: Number::from_computed_value(&computed.m23),
|
||||||
|
m24: Number::from_computed_value(&computed.m24),
|
||||||
|
m31: Number::from_computed_value(&computed.m31),
|
||||||
|
m32: Number::from_computed_value(&computed.m32),
|
||||||
|
m33: Number::from_computed_value(&computed.m33),
|
||||||
|
m34: Number::from_computed_value(&computed.m34),
|
||||||
|
m41: Number::from_computed_value(&computed.m41),
|
||||||
|
m42: Number::from_computed_value(&computed.m42),
|
||||||
|
m43: Number::from_computed_value(&computed.m43),
|
||||||
|
m44: Number::from_computed_value(&computed.m44),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_two_lengths_or_percentages(context: &ParserContext, input: &mut Parser)
|
fn parse_two_lengths_or_percentages(context: &ParserContext, input: &mut Parser)
|
||||||
-> Result<(specified::LengthOrPercentage,
|
-> Result<(specified::LengthOrPercentage,
|
||||||
|
@ -1144,7 +1215,7 @@ ${helpers.predefined_type("scroll-snap-coordinate",
|
||||||
Ok((first, second))
|
Ok((first, second))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_two_floats(input: &mut Parser) -> Result<(CSSFloat,CSSFloat),()> {
|
fn parse_two_numbers(input: &mut Parser) -> Result<(Number, Number), ()> {
|
||||||
let first = try!(specified::parse_number(input));
|
let first = try!(specified::parse_number(input));
|
||||||
let second = input.try(|input| {
|
let second = input.try(|input| {
|
||||||
try!(input.expect_comma());
|
try!(input.expect_comma());
|
||||||
|
@ -1159,7 +1230,7 @@ ${helpers.predefined_type("scroll-snap-coordinate",
|
||||||
let second = input.try(|input| {
|
let second = input.try(|input| {
|
||||||
try!(input.expect_comma());
|
try!(input.expect_comma());
|
||||||
specified::Angle::parse(context, input)
|
specified::Angle::parse(context, input)
|
||||||
}).unwrap_or(specified::Angle(0.0));
|
}).unwrap_or(specified::Angle::zero());
|
||||||
Ok((first, second))
|
Ok((first, second))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1182,8 +1253,8 @@ ${helpers.predefined_type("scroll-snap-coordinate",
|
||||||
specified::LengthOrPercentage,
|
specified::LengthOrPercentage,
|
||||||
specified::LengthOrPercentage,
|
specified::LengthOrPercentage,
|
||||||
specified::Length),
|
specified::Length),
|
||||||
Scale(CSSFloat, CSSFloat, CSSFloat),
|
Scale(Number, Number, Number),
|
||||||
Rotate(CSSFloat, CSSFloat, CSSFloat, specified::Angle),
|
Rotate(Number, Number, Number, specified::Angle),
|
||||||
Perspective(specified::Length),
|
Perspective(specified::Length),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1323,31 +1394,29 @@ ${helpers.predefined_type("scroll-snap-coordinate",
|
||||||
if values.len() != 6 {
|
if values.len() != 6 {
|
||||||
return Err(())
|
return Err(())
|
||||||
}
|
}
|
||||||
result.push(SpecifiedOperation::Matrix(
|
let matrix = SpecifiedMatrix {
|
||||||
SpecifiedMatrix {
|
m11: values[0], m12: values[1], m13: Number::new(0.0), m14: Number::new(0.0),
|
||||||
m11: values[0], m12: values[1], m13: 0.0, m14: 0.0,
|
m21: values[2], m22: values[3], m23: Number::new(0.0), m24: Number::new(0.0),
|
||||||
m21: values[2], m22: values[3], m23: 0.0, m24: 0.0,
|
m31: Number::new(0.0), m32: Number::new(0.0), m33: Number::new(1.0), m34: Number::new(0.0),
|
||||||
m31: 0.0, m32: 0.0, m33: 1.0, m34: 0.0,
|
m41: values[4], m42: values[5], m43: Number::new(0.0), m44: Number::new(1.0),
|
||||||
m41: values[4], m42: values[5], m43: 0.0, m44: 1.0
|
};
|
||||||
}));
|
result.push(SpecifiedOperation::Matrix(matrix));
|
||||||
Ok(())
|
Ok(())
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
"matrix3d" => {
|
"matrix3d" => {
|
||||||
try!(input.parse_nested_block(|input| {
|
try!(input.parse_nested_block(|input| {
|
||||||
let values = try!(input.parse_comma_separated(|input| {
|
let values = try!(input.parse_comma_separated(specified::parse_number));
|
||||||
specified::parse_number(input)
|
|
||||||
}));
|
|
||||||
if values.len() != 16 {
|
if values.len() != 16 {
|
||||||
return Err(())
|
return Err(())
|
||||||
}
|
}
|
||||||
result.push(SpecifiedOperation::Matrix(
|
result.push(SpecifiedOperation::Matrix(
|
||||||
SpecifiedMatrix {
|
SpecifiedMatrix {
|
||||||
m11: values[ 0], m12: values[ 1], m13: values[ 2], m14: values[ 3],
|
m11: values[ 0], m12: values[ 1], m13: values[ 2], m14: values[ 3],
|
||||||
m21: values[ 4], m22: values[ 5], m23: values[ 6], m24: values[ 7],
|
m21: values[ 4], m22: values[ 5], m23: values[ 6], m24: values[ 7],
|
||||||
m31: values[ 8], m32: values[ 9], m33: values[10], m34: values[11],
|
m31: values[ 8], m32: values[ 9], m33: values[10], m34: values[11],
|
||||||
m41: values[12], m42: values[13], m43: values[14], m44: values[15]
|
m41: values[12], m42: values[13], m43: values[14], m44: values[15]
|
||||||
}));
|
}));
|
||||||
Ok(())
|
Ok(())
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
|
@ -1412,29 +1481,37 @@ ${helpers.predefined_type("scroll-snap-coordinate",
|
||||||
},
|
},
|
||||||
"scale" => {
|
"scale" => {
|
||||||
try!(input.parse_nested_block(|input| {
|
try!(input.parse_nested_block(|input| {
|
||||||
let (sx, sy) = try!(parse_two_floats(input));
|
let (sx, sy) = try!(parse_two_numbers(input));
|
||||||
result.push(SpecifiedOperation::Scale(sx, sy, 1.0));
|
result.push(SpecifiedOperation::Scale(sx,
|
||||||
|
sy,
|
||||||
|
Number::new(1.0)));
|
||||||
Ok(())
|
Ok(())
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
"scalex" => {
|
"scalex" => {
|
||||||
try!(input.parse_nested_block(|input| {
|
try!(input.parse_nested_block(|input| {
|
||||||
let sx = try!(specified::parse_number(input));
|
let sx = try!(specified::parse_number(input));
|
||||||
result.push(SpecifiedOperation::Scale(sx, 1.0, 1.0));
|
result.push(SpecifiedOperation::Scale(sx,
|
||||||
|
Number::new(1.0),
|
||||||
|
Number::new(1.0)));
|
||||||
Ok(())
|
Ok(())
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
"scaley" => {
|
"scaley" => {
|
||||||
try!(input.parse_nested_block(|input| {
|
try!(input.parse_nested_block(|input| {
|
||||||
let sy = try!(specified::parse_number(input));
|
let sy = try!(specified::parse_number(input));
|
||||||
result.push(SpecifiedOperation::Scale(1.0, sy, 1.0));
|
result.push(SpecifiedOperation::Scale(Number::new(1.0),
|
||||||
|
sy,
|
||||||
|
Number::new(1.0)));
|
||||||
Ok(())
|
Ok(())
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
"scalez" => {
|
"scalez" => {
|
||||||
try!(input.parse_nested_block(|input| {
|
try!(input.parse_nested_block(|input| {
|
||||||
let sz = try!(specified::parse_number(input));
|
let sz = try!(specified::parse_number(input));
|
||||||
result.push(SpecifiedOperation::Scale(1.0, 1.0, sz));
|
result.push(SpecifiedOperation::Scale(Number::new(1.0),
|
||||||
|
Number::new(1.0),
|
||||||
|
sz));
|
||||||
Ok(())
|
Ok(())
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
|
@ -1452,28 +1529,40 @@ ${helpers.predefined_type("scroll-snap-coordinate",
|
||||||
"rotate" => {
|
"rotate" => {
|
||||||
try!(input.parse_nested_block(|input| {
|
try!(input.parse_nested_block(|input| {
|
||||||
let theta = try!(specified::Angle::parse(context,input));
|
let theta = try!(specified::Angle::parse(context,input));
|
||||||
result.push(SpecifiedOperation::Rotate(0.0, 0.0, 1.0, theta));
|
result.push(SpecifiedOperation::Rotate(Number::new(0.0),
|
||||||
|
Number::new(0.0),
|
||||||
|
Number::new(1.0),
|
||||||
|
theta));
|
||||||
Ok(())
|
Ok(())
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
"rotatex" => {
|
"rotatex" => {
|
||||||
try!(input.parse_nested_block(|input| {
|
try!(input.parse_nested_block(|input| {
|
||||||
let theta = try!(specified::Angle::parse(context,input));
|
let theta = try!(specified::Angle::parse(context,input));
|
||||||
result.push(SpecifiedOperation::Rotate(1.0, 0.0, 0.0, theta));
|
result.push(SpecifiedOperation::Rotate(Number::new(1.0),
|
||||||
|
Number::new(0.0),
|
||||||
|
Number::new(0.0),
|
||||||
|
theta));
|
||||||
Ok(())
|
Ok(())
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
"rotatey" => {
|
"rotatey" => {
|
||||||
try!(input.parse_nested_block(|input| {
|
try!(input.parse_nested_block(|input| {
|
||||||
let theta = try!(specified::Angle::parse(context,input));
|
let theta = try!(specified::Angle::parse(context,input));
|
||||||
result.push(SpecifiedOperation::Rotate(0.0, 1.0, 0.0, theta));
|
result.push(SpecifiedOperation::Rotate(Number::new(0.0),
|
||||||
|
Number::new(1.0),
|
||||||
|
Number::new(0.0),
|
||||||
|
theta));
|
||||||
Ok(())
|
Ok(())
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
"rotatez" => {
|
"rotatez" => {
|
||||||
try!(input.parse_nested_block(|input| {
|
try!(input.parse_nested_block(|input| {
|
||||||
let theta = try!(specified::Angle::parse(context,input));
|
let theta = try!(specified::Angle::parse(context,input));
|
||||||
result.push(SpecifiedOperation::Rotate(0.0, 0.0, 1.0, theta));
|
result.push(SpecifiedOperation::Rotate(Number::new(0.0),
|
||||||
|
Number::new(0.0),
|
||||||
|
Number::new(1.0),
|
||||||
|
theta));
|
||||||
Ok(())
|
Ok(())
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
|
@ -1501,14 +1590,14 @@ ${helpers.predefined_type("scroll-snap-coordinate",
|
||||||
"skewx" => {
|
"skewx" => {
|
||||||
try!(input.parse_nested_block(|input| {
|
try!(input.parse_nested_block(|input| {
|
||||||
let theta_x = try!(specified::Angle::parse(context,input));
|
let theta_x = try!(specified::Angle::parse(context,input));
|
||||||
result.push(SpecifiedOperation::Skew(theta_x, specified::Angle(0.0)));
|
result.push(SpecifiedOperation::Skew(theta_x, specified::Angle::zero()));
|
||||||
Ok(())
|
Ok(())
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
"skewy" => {
|
"skewy" => {
|
||||||
try!(input.parse_nested_block(|input| {
|
try!(input.parse_nested_block(|input| {
|
||||||
let theta_y = try!(specified::Angle::parse(context,input));
|
let theta_y = try!(specified::Angle::parse(context,input));
|
||||||
result.push(SpecifiedOperation::Skew(specified::Angle(0.0), theta_y));
|
result.push(SpecifiedOperation::Skew(specified::Angle::zero(), theta_y));
|
||||||
Ok(())
|
Ok(())
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
|
@ -1543,7 +1632,7 @@ ${helpers.predefined_type("scroll-snap-coordinate",
|
||||||
for operation in &self.0 {
|
for operation in &self.0 {
|
||||||
match *operation {
|
match *operation {
|
||||||
SpecifiedOperation::Matrix(ref matrix) => {
|
SpecifiedOperation::Matrix(ref matrix) => {
|
||||||
result.push(computed_value::ComputedOperation::Matrix(*matrix));
|
result.push(computed_value::ComputedOperation::Matrix(matrix.to_computed_value(context)));
|
||||||
}
|
}
|
||||||
SpecifiedOperation::Translate(_, ref tx, ref ty, ref tz) => {
|
SpecifiedOperation::Translate(_, ref tx, ref ty, ref tz) => {
|
||||||
result.push(computed_value::ComputedOperation::Translate(tx.to_computed_value(context),
|
result.push(computed_value::ComputedOperation::Translate(tx.to_computed_value(context),
|
||||||
|
@ -1551,14 +1640,22 @@ ${helpers.predefined_type("scroll-snap-coordinate",
|
||||||
tz.to_computed_value(context)));
|
tz.to_computed_value(context)));
|
||||||
}
|
}
|
||||||
SpecifiedOperation::Scale(sx, sy, sz) => {
|
SpecifiedOperation::Scale(sx, sy, sz) => {
|
||||||
|
let sx = sx.to_computed_value(context);
|
||||||
|
let sy = sy.to_computed_value(context);
|
||||||
|
let sz = sz.to_computed_value(context);
|
||||||
result.push(computed_value::ComputedOperation::Scale(sx, sy, sz));
|
result.push(computed_value::ComputedOperation::Scale(sx, sy, sz));
|
||||||
}
|
}
|
||||||
SpecifiedOperation::Rotate(ax, ay, az, theta) => {
|
SpecifiedOperation::Rotate(ax, ay, az, theta) => {
|
||||||
|
let ax = ax.to_computed_value(context);
|
||||||
|
let ay = ay.to_computed_value(context);
|
||||||
|
let az = az.to_computed_value(context);
|
||||||
|
let theta = theta.to_computed_value(context);
|
||||||
let len = (ax * ax + ay * ay + az * az).sqrt();
|
let len = (ax * ax + ay * ay + az * az).sqrt();
|
||||||
result.push(computed_value::ComputedOperation::Rotate(ax / len, ay / len, az / len, theta));
|
result.push(computed_value::ComputedOperation::Rotate(ax / len, ay / len, az / len, theta));
|
||||||
}
|
}
|
||||||
SpecifiedOperation::Skew(theta_x, theta_y) => {
|
SpecifiedOperation::Skew(theta_x, theta_y) => {
|
||||||
result.push(computed_value::ComputedOperation::Skew(theta_x, theta_y));
|
result.push(computed_value::ComputedOperation::Skew(theta_x.to_computed_value(context),
|
||||||
|
theta_y.to_computed_value(context)));
|
||||||
}
|
}
|
||||||
SpecifiedOperation::Perspective(ref d) => {
|
SpecifiedOperation::Perspective(ref d) => {
|
||||||
result.push(computed_value::ComputedOperation::Perspective(d.to_computed_value(context)));
|
result.push(computed_value::ComputedOperation::Perspective(d.to_computed_value(context)));
|
||||||
|
@ -1572,11 +1669,11 @@ ${helpers.predefined_type("scroll-snap-coordinate",
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_computed_value(computed: &computed_value::T) -> Self {
|
fn from_computed_value(computed: &computed_value::T) -> Self {
|
||||||
SpecifiedValue(computed.0.as_ref().map(|computed| {
|
SpecifiedValue(computed.0.as_ref().map(|computed| {
|
||||||
let mut result = vec!();
|
let mut result = vec![];
|
||||||
for operation in computed {
|
for operation in computed {
|
||||||
match *operation {
|
match *operation {
|
||||||
computed_value::ComputedOperation::Matrix(ref matrix) => {
|
computed_value::ComputedOperation::Matrix(ref matrix) => {
|
||||||
result.push(SpecifiedOperation::Matrix(*matrix));
|
result.push(SpecifiedOperation::Matrix(SpecifiedMatrix::from_computed_value(matrix)));
|
||||||
}
|
}
|
||||||
computed_value::ComputedOperation::Translate(ref tx, ref ty, ref tz) => {
|
computed_value::ComputedOperation::Translate(ref tx, ref ty, ref tz) => {
|
||||||
// XXXManishearth we lose information here; perhaps we should try to
|
// XXXManishearth we lose information here; perhaps we should try to
|
||||||
|
@ -1586,14 +1683,23 @@ ${helpers.predefined_type("scroll-snap-coordinate",
|
||||||
ToComputedValue::from_computed_value(ty),
|
ToComputedValue::from_computed_value(ty),
|
||||||
ToComputedValue::from_computed_value(tz)));
|
ToComputedValue::from_computed_value(tz)));
|
||||||
}
|
}
|
||||||
computed_value::ComputedOperation::Scale(sx, sy, sz) => {
|
computed_value::ComputedOperation::Scale(ref sx, ref sy, ref sz) => {
|
||||||
result.push(SpecifiedOperation::Scale(sx, sy, sz));
|
result.push(SpecifiedOperation::Scale(
|
||||||
|
Number::from_computed_value(sx),
|
||||||
|
Number::from_computed_value(sy),
|
||||||
|
Number::from_computed_value(sz)));
|
||||||
}
|
}
|
||||||
computed_value::ComputedOperation::Rotate(ax, ay, az, theta) => {
|
computed_value::ComputedOperation::Rotate(ref ax, ref ay, ref az, ref theta) => {
|
||||||
result.push(SpecifiedOperation::Rotate(ax, ay, az, theta));
|
result.push(SpecifiedOperation::Rotate(
|
||||||
|
Number::from_computed_value(ax),
|
||||||
|
Number::from_computed_value(ay),
|
||||||
|
Number::from_computed_value(az),
|
||||||
|
specified::Angle::from_computed_value(theta)));
|
||||||
}
|
}
|
||||||
computed_value::ComputedOperation::Skew(theta_x, theta_y) => {
|
computed_value::ComputedOperation::Skew(ref theta_x, ref theta_y) => {
|
||||||
result.push(SpecifiedOperation::Skew(theta_x, theta_y));
|
result.push(SpecifiedOperation::Skew(
|
||||||
|
specified::Angle::from_computed_value(theta_x),
|
||||||
|
specified::Angle::from_computed_value(theta_y)))
|
||||||
}
|
}
|
||||||
computed_value::ComputedOperation::Perspective(ref d) => {
|
computed_value::ComputedOperation::Perspective(ref d) => {
|
||||||
result.push(SpecifiedOperation::Perspective(
|
result.push(SpecifiedOperation::Perspective(
|
||||||
|
|
|
@ -246,17 +246,59 @@
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
use super::content;
|
use super::content;
|
||||||
use values::HasViewportPercentage;
|
use values::HasViewportPercentage;
|
||||||
use values::computed::ComputedValueAsSpecified;
|
|
||||||
|
|
||||||
use cssparser::{Token, serialize_identifier};
|
use cssparser::{Token, serialize_identifier};
|
||||||
use std::borrow::{Cow, ToOwned};
|
use std::borrow::{Cow, ToOwned};
|
||||||
|
|
||||||
pub use self::computed_value::T as SpecifiedValue;
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct SpecifiedValue(pub Vec<(String, specified::Integer)>);
|
||||||
|
|
||||||
pub mod computed_value {
|
pub mod computed_value {
|
||||||
|
use std::fmt;
|
||||||
|
use style_traits::ToCss;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
pub struct T(pub Vec<(String,i32)>);
|
pub struct T(pub Vec<(String, i32)>);
|
||||||
|
|
||||||
|
impl ToCss for T {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
|
||||||
|
where W: fmt::Write,
|
||||||
|
{
|
||||||
|
use cssparser::serialize_identifier;
|
||||||
|
if self.0.is_empty() {
|
||||||
|
return dest.write_str("none")
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut first = true;
|
||||||
|
for pair in &self.0 {
|
||||||
|
if !first {
|
||||||
|
try!(dest.write_str(" "));
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
try!(serialize_identifier(&pair.0, dest));
|
||||||
|
try!(dest.write_str(" "));
|
||||||
|
try!(pair.1.to_css(dest));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToComputedValue for SpecifiedValue {
|
||||||
|
type ComputedValue = computed_value::T;
|
||||||
|
|
||||||
|
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||||
|
computed_value::T(self.0.iter().map(|entry| {
|
||||||
|
(entry.0.clone(), entry.1.to_computed_value(context))
|
||||||
|
}).collect::<Vec<_>>())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||||
|
SpecifiedValue(computed.0.iter().map(|entry| {
|
||||||
|
(entry.0.clone(), specified::Integer::from_computed_value(&entry.1))
|
||||||
|
}).collect::<Vec<_>>())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -264,15 +306,15 @@
|
||||||
computed_value::T(Vec::new())
|
computed_value::T(Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComputedValueAsSpecified for SpecifiedValue {}
|
|
||||||
no_viewport_percentage!(SpecifiedValue);
|
no_viewport_percentage!(SpecifiedValue);
|
||||||
|
|
||||||
impl ToCss for SpecifiedValue {
|
impl ToCss for SpecifiedValue {
|
||||||
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,
|
||||||
|
{
|
||||||
if self.0.is_empty() {
|
if self.0.is_empty() {
|
||||||
return dest.write_str("none");
|
return dest.write_str("none");
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
for pair in &self.0 {
|
for pair in &self.0 {
|
||||||
if !first {
|
if !first {
|
||||||
|
@ -280,18 +322,19 @@
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
try!(serialize_identifier(&pair.0, dest));
|
try!(serialize_identifier(&pair.0, dest));
|
||||||
try!(write!(dest, " {}", pair.1));
|
try!(dest.write_str(" "));
|
||||||
|
try!(pair.1.to_css(dest));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
|
pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
|
||||||
parse_common(1, input)
|
parse_common(1, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_common(default_value: i32, input: &mut Parser) -> Result<SpecifiedValue,()> {
|
pub fn parse_common(default_value: i32, input: &mut Parser) -> Result<SpecifiedValue, ()> {
|
||||||
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
|
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
|
||||||
return Ok(SpecifiedValue(Vec::new()))
|
return Ok(SpecifiedValue(Vec::new()))
|
||||||
}
|
}
|
||||||
|
@ -307,7 +350,7 @@
|
||||||
return Err(())
|
return Err(())
|
||||||
}
|
}
|
||||||
let counter_delta =
|
let counter_delta =
|
||||||
input.try(|input| specified::parse_integer(input)).unwrap_or(default_value);
|
input.try(|input| specified::parse_integer(input)).unwrap_or(specified::Integer::new(default_value));
|
||||||
counters.push((counter_name, counter_delta))
|
counters.push((counter_name, counter_delta))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,7 +365,7 @@
|
||||||
<%helpers:longhand name="counter-reset" animatable="False"
|
<%helpers:longhand name="counter-reset" animatable="False"
|
||||||
spec="https://drafts.csswg.org/css-lists-3/#propdef-counter-reset">
|
spec="https://drafts.csswg.org/css-lists-3/#propdef-counter-reset">
|
||||||
pub use super::counter_increment::{SpecifiedValue, computed_value, get_initial_value};
|
pub use super::counter_increment::{SpecifiedValue, computed_value, get_initial_value};
|
||||||
use super::counter_increment::{parse_common};
|
use super::counter_increment::parse_common;
|
||||||
|
|
||||||
pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
|
pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
|
||||||
parse_common(0, input)
|
parse_common(0, input)
|
||||||
|
|
|
@ -655,30 +655,65 @@ ${helpers.single_keyword("font-variant-caps",
|
||||||
|
|
||||||
<%helpers:longhand products="gecko" name="font-size-adjust" animatable="True"
|
<%helpers:longhand products="gecko" name="font-size-adjust" animatable="True"
|
||||||
spec="https://drafts.csswg.org/css-fonts/#propdef-font-size-adjust">
|
spec="https://drafts.csswg.org/css-fonts/#propdef-font-size-adjust">
|
||||||
|
use std::fmt;
|
||||||
|
use style_traits::ToCss;
|
||||||
use values::HasViewportPercentage;
|
use values::HasViewportPercentage;
|
||||||
use values::computed::ComputedValueAsSpecified;
|
|
||||||
use values::specified::Number;
|
|
||||||
|
|
||||||
impl ComputedValueAsSpecified for SpecifiedValue {}
|
|
||||||
no_viewport_percentage!(SpecifiedValue);
|
no_viewport_percentage!(SpecifiedValue);
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
pub enum SpecifiedValue {
|
pub enum SpecifiedValue {
|
||||||
None,
|
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 {
|
pub mod computed_value {
|
||||||
use style_traits::ToCss;
|
|
||||||
use std::fmt;
|
|
||||||
use properties::animated_properties::Interpolate;
|
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 {
|
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 {
|
match *self {
|
||||||
T::None => dest.write_str("none"),
|
T::None => dest.write_str("none"),
|
||||||
T::Number(number) => number.to_css(dest),
|
T::Number(number) => number.to_css(dest),
|
||||||
|
@ -690,14 +725,15 @@ ${helpers.single_keyword("font-variant-caps",
|
||||||
fn interpolate(&self, other: &Self, time: f64) -> Result<Self, ()> {
|
fn interpolate(&self, other: &Self, time: f64) -> Result<Self, ()> {
|
||||||
match (*self, *other) {
|
match (*self, *other) {
|
||||||
(T::Number(ref number), T::Number(ref 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(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline] pub fn get_initial_value() -> computed_value::T {
|
#[inline]
|
||||||
|
pub fn get_initial_value() -> computed_value::T {
|
||||||
computed_value::T::None
|
computed_value::T::None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,7 @@ ${helpers.single_keyword("image-rendering",
|
||||||
|
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
use values::CSSFloat;
|
use values::CSSFloat;
|
||||||
const TWO_PI: CSSFloat = 2.0*PI;
|
const TWO_PI: CSSFloat = 2.0 * PI;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Copy, Debug)]
|
#[derive(Clone, PartialEq, Copy, Debug)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
@ -125,7 +125,7 @@ ${helpers.single_keyword("image-rendering",
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod computed_value {
|
pub mod computed_value {
|
||||||
use values::specified::Angle;
|
use values::computed::Angle;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Copy, Debug)]
|
#[derive(Clone, PartialEq, Copy, Debug)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
@ -135,36 +135,35 @@ ${helpers.single_keyword("image-rendering",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const INITIAL_ANGLE: Angle = Angle(0.0);
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_initial_value() -> computed_value::T {
|
pub fn get_initial_value() -> computed_value::T {
|
||||||
computed_value::T::AngleWithFlipped(INITIAL_ANGLE, false)
|
computed_value::T::AngleWithFlipped(computed::Angle::zero(), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// According to CSS Content Module Level 3:
|
// According to CSS Content Module Level 3:
|
||||||
// The computed value of the property is calculated by rounding the specified angle
|
// The computed value of the property is calculated by rounding the specified angle
|
||||||
// to the nearest quarter-turn, rounding away from 0, then moduloing the value by 1 turn.
|
// to the nearest quarter-turn, rounding away from 0, then moduloing the value by 1 turn.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn normalize_angle(angle: &Angle) -> Angle {
|
fn normalize_angle(angle: &computed::Angle) -> computed::Angle {
|
||||||
let radians = angle.radians();
|
let radians = angle.radians();
|
||||||
let rounded_quarter_turns = (4.0 * radians / TWO_PI).round();
|
let rounded_quarter_turns = (4.0 * radians / TWO_PI).round();
|
||||||
let normalized_quarter_turns = (rounded_quarter_turns % 4.0 + 4.0) % 4.0;
|
let normalized_quarter_turns = (rounded_quarter_turns % 4.0 + 4.0) % 4.0;
|
||||||
let normalized_radians = normalized_quarter_turns/4.0 * TWO_PI;
|
let normalized_radians = normalized_quarter_turns/4.0 * TWO_PI;
|
||||||
Angle::from_radians(normalized_radians)
|
computed::Angle::from_radians(normalized_radians)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToComputedValue for SpecifiedValue {
|
impl ToComputedValue for SpecifiedValue {
|
||||||
type ComputedValue = computed_value::T;
|
type ComputedValue = computed_value::T;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_computed_value(&self, _: &Context) -> computed_value::T {
|
fn to_computed_value(&self, context: &Context) -> computed_value::T {
|
||||||
if let Some(ref angle) = self.angle {
|
if let Some(ref angle) = self.angle {
|
||||||
let normalized_angle = normalize_angle(angle);
|
let angle = angle.to_computed_value(context);
|
||||||
|
let normalized_angle = normalize_angle(&angle);
|
||||||
computed_value::T::AngleWithFlipped(normalized_angle, self.flipped)
|
computed_value::T::AngleWithFlipped(normalized_angle, self.flipped)
|
||||||
} else {
|
} else {
|
||||||
if self.flipped {
|
if self.flipped {
|
||||||
computed_value::T::AngleWithFlipped(INITIAL_ANGLE, true)
|
computed_value::T::AngleWithFlipped(computed::Angle::zero(), true)
|
||||||
} else {
|
} else {
|
||||||
computed_value::T::FromImage
|
computed_value::T::FromImage
|
||||||
}
|
}
|
||||||
|
@ -175,8 +174,12 @@ ${helpers.single_keyword("image-rendering",
|
||||||
fn from_computed_value(computed: &computed_value::T) -> Self {
|
fn from_computed_value(computed: &computed_value::T) -> Self {
|
||||||
match *computed {
|
match *computed {
|
||||||
computed_value::T::FromImage => SpecifiedValue { angle: None, flipped: false },
|
computed_value::T::FromImage => SpecifiedValue { angle: None, flipped: false },
|
||||||
computed_value::T::AngleWithFlipped(angle, flipped) =>
|
computed_value::T::AngleWithFlipped(ref angle, flipped) => {
|
||||||
SpecifiedValue { angle: Some(angle), flipped: flipped },
|
SpecifiedValue {
|
||||||
|
angle: Some(Angle::from_computed_value(angle)),
|
||||||
|
flipped: flipped,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,7 +208,7 @@ ${helpers.single_keyword("image-rendering",
|
||||||
let angle = input.try(|input| Angle::parse(context, input)).ok();
|
let angle = input.try(|input| Angle::parse(context, input)).ok();
|
||||||
let flipped = input.try(|input| input.expect_ident_matching("flip")).is_ok();
|
let flipped = input.try(|input| input.expect_ident_matching("flip")).is_ok();
|
||||||
let explicit_angle = if angle.is_none() && !flipped {
|
let explicit_angle = if angle.is_none() && !flipped {
|
||||||
Some(INITIAL_ANGLE)
|
Some(Angle::zero())
|
||||||
} else {
|
} else {
|
||||||
angle
|
angle
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
<%namespace name="helpers" file="/helpers.mako.rs" />
|
<%namespace name="helpers" file="/helpers.mako.rs" />
|
||||||
|
|
||||||
<% data.new_style_struct("InheritedTable", inherited=True, gecko_name="TableBorder") %>
|
<% data.new_style_struct("InheritedTable", inherited=True, gecko_name="TableBorder") %>
|
||||||
|
|
||||||
|
@ -52,7 +52,8 @@ ${helpers.single_keyword("caption-side", "top bottom",
|
||||||
|
|
||||||
impl HasViewportPercentage for SpecifiedValue {
|
impl HasViewportPercentage for SpecifiedValue {
|
||||||
fn has_viewport_percentage(&self) -> bool {
|
fn has_viewport_percentage(&self) -> bool {
|
||||||
return self.horizontal.has_viewport_percentage() || self.vertical.has_viewport_percentage()
|
self.horizontal.has_viewport_percentage() ||
|
||||||
|
self.vertical.as_ref().map_or(false, |v| v.has_viewport_percentage())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +61,7 @@ ${helpers.single_keyword("caption-side", "top bottom",
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
pub struct SpecifiedValue {
|
pub struct SpecifiedValue {
|
||||||
pub horizontal: specified::Length,
|
pub horizontal: specified::Length,
|
||||||
pub vertical: specified::Length,
|
pub vertical: Option<specified::Length>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -72,10 +73,15 @@ ${helpers.single_keyword("caption-side", "top bottom",
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToCss for SpecifiedValue {
|
impl ToCss for SpecifiedValue {
|
||||||
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,
|
||||||
|
{
|
||||||
try!(self.horizontal.to_css(dest));
|
try!(self.horizontal.to_css(dest));
|
||||||
try!(dest.write_str(" "));
|
if let Some(vertical) = self.vertical.as_ref() {
|
||||||
self.vertical.to_css(dest)
|
try!(dest.write_str(" "));
|
||||||
|
vertical.to_css(dest)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,9 +98,10 @@ ${helpers.single_keyword("caption-side", "top bottom",
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_computed_value(&self, context: &Context) -> computed_value::T {
|
fn to_computed_value(&self, context: &Context) -> computed_value::T {
|
||||||
|
let horizontal = self.horizontal.to_computed_value(context);
|
||||||
computed_value::T {
|
computed_value::T {
|
||||||
horizontal: self.horizontal.to_computed_value(context),
|
horizontal: horizontal,
|
||||||
vertical: self.vertical.to_computed_value(context),
|
vertical: self.vertical.as_ref().map_or(horizontal, |v| v.to_computed_value(context)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +109,7 @@ ${helpers.single_keyword("caption-side", "top bottom",
|
||||||
fn from_computed_value(computed: &computed_value::T) -> Self {
|
fn from_computed_value(computed: &computed_value::T) -> Self {
|
||||||
SpecifiedValue {
|
SpecifiedValue {
|
||||||
horizontal: ToComputedValue::from_computed_value(&computed.horizontal),
|
horizontal: ToComputedValue::from_computed_value(&computed.horizontal),
|
||||||
vertical: ToComputedValue::from_computed_value(&computed.vertical),
|
vertical: Some(ToComputedValue::from_computed_value(&computed.vertical)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,17 +130,17 @@ ${helpers.single_keyword("caption-side", "top bottom",
|
||||||
(None, None) => Err(()),
|
(None, None) => Err(()),
|
||||||
(Some(length), None) => {
|
(Some(length), None) => {
|
||||||
Ok(SpecifiedValue {
|
Ok(SpecifiedValue {
|
||||||
horizontal: length.clone(),
|
horizontal: length,
|
||||||
vertical: length,
|
vertical: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
(Some(horizontal), Some(vertical)) => {
|
(Some(horizontal), Some(vertical)) => {
|
||||||
Ok(SpecifiedValue {
|
Ok(SpecifiedValue {
|
||||||
horizontal: horizontal,
|
horizontal: horizontal,
|
||||||
vertical: vertical,
|
vertical: Some(vertical),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
(None, Some(_)) => panic!("shouldn't happen"),
|
(None, Some(_)) => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</%helpers:longhand>
|
</%helpers:longhand>
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
spec="https://drafts.csswg.org/css2/visudet.html#propdef-line-height">
|
spec="https://drafts.csswg.org/css2/visudet.html#propdef-line-height">
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
use values::{CSSFloat, HasViewportPercentage};
|
use values::HasViewportPercentage;
|
||||||
|
|
||||||
impl HasViewportPercentage for SpecifiedValue {
|
impl HasViewportPercentage for SpecifiedValue {
|
||||||
fn has_viewport_percentage(&self) -> bool {
|
fn has_viewport_percentage(&self) -> bool {
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
% if product == "gecko":
|
% if product == "gecko":
|
||||||
MozBlockHeight,
|
MozBlockHeight,
|
||||||
% endif
|
% endif
|
||||||
Number(CSSFloat),
|
Number(specified::Number),
|
||||||
LengthOrPercentage(specified::LengthOrPercentage),
|
LengthOrPercentage(specified::LengthOrPercentage),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@
|
||||||
SpecifiedValue::MozBlockHeight => dest.write_str("-moz-block-height"),
|
SpecifiedValue::MozBlockHeight => dest.write_str("-moz-block-height"),
|
||||||
% endif
|
% endif
|
||||||
SpecifiedValue::LengthOrPercentage(ref value) => value.to_css(dest),
|
SpecifiedValue::LengthOrPercentage(ref value) => value.to_css(dest),
|
||||||
SpecifiedValue::Number(number) => write!(dest, "{}", number),
|
SpecifiedValue::Number(number) => number.to_css(dest),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,24 +52,24 @@
|
||||||
// parsed as a plain Number rather than a Length (0px); this matches the behaviour
|
// parsed as a plain Number rather than a Length (0px); this matches the behaviour
|
||||||
// of all major browsers
|
// of all major browsers
|
||||||
input.try(specified::Number::parse_non_negative)
|
input.try(specified::Number::parse_non_negative)
|
||||||
.map(|n| SpecifiedValue::Number(n.0))
|
.map(SpecifiedValue::Number)
|
||||||
.or_else(|()| {
|
|
||||||
input.try(specified::LengthOrPercentage::parse_non_negative)
|
|
||||||
.map(SpecifiedValue::LengthOrPercentage)
|
|
||||||
.or_else(|()| {
|
.or_else(|()| {
|
||||||
match try!(input.next()) {
|
input.try(specified::LengthOrPercentage::parse_non_negative)
|
||||||
Token::Ident(ref value) if value.eq_ignore_ascii_case("normal") => {
|
.map(SpecifiedValue::LengthOrPercentage)
|
||||||
Ok(SpecifiedValue::Normal)
|
.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(()),
|
||||||
}
|
}
|
||||||
% if product == "gecko":
|
})
|
||||||
Token::Ident(ref value) if value.eq_ignore_ascii_case("-moz-block-height") => {
|
|
||||||
Ok(SpecifiedValue::MozBlockHeight)
|
|
||||||
}
|
|
||||||
% endif
|
|
||||||
_ => Err(()),
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
})
|
|
||||||
}
|
}
|
||||||
pub mod computed_value {
|
pub mod computed_value {
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
|
@ -116,7 +116,7 @@
|
||||||
% if product == "gecko":
|
% if product == "gecko":
|
||||||
SpecifiedValue::MozBlockHeight => computed_value::T::MozBlockHeight,
|
SpecifiedValue::MozBlockHeight => computed_value::T::MozBlockHeight,
|
||||||
% endif
|
% 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) => {
|
SpecifiedValue::LengthOrPercentage(ref value) => {
|
||||||
match *value {
|
match *value {
|
||||||
specified::LengthOrPercentage::Length(ref value) =>
|
specified::LengthOrPercentage::Length(ref value) =>
|
||||||
|
@ -144,7 +144,9 @@
|
||||||
% if product == "gecko":
|
% if product == "gecko":
|
||||||
computed_value::T::MozBlockHeight => SpecifiedValue::MozBlockHeight,
|
computed_value::T::MozBlockHeight => SpecifiedValue::MozBlockHeight,
|
||||||
% endif
|
% 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) => {
|
computed_value::T::Length(au) => {
|
||||||
SpecifiedValue::LengthOrPercentage(specified::LengthOrPercentage::Length(
|
SpecifiedValue::LengthOrPercentage(specified::LengthOrPercentage::Length(
|
||||||
ToComputedValue::from_computed_value(&au)
|
ToComputedValue::from_computed_value(&au)
|
||||||
|
|
|
@ -130,27 +130,9 @@ ${helpers.predefined_type("flex-shrink", "Number",
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-flexbox/#propdef-order
|
// https://drafts.csswg.org/css-flexbox/#propdef-order
|
||||||
<%helpers:longhand name="order" animatable="True" extra_prefixes="webkit"
|
${helpers.predefined_type("order", "Integer", "0",
|
||||||
spec="https://drafts.csswg.org/css-flexbox/#order-property">
|
animatable=True,
|
||||||
use values::computed::ComputedValueAsSpecified;
|
spec="https://drafts.csswg.org/css-flexbox/#order-property")}
|
||||||
|
|
||||||
impl ComputedValueAsSpecified for SpecifiedValue {}
|
|
||||||
|
|
||||||
pub type SpecifiedValue = computed_value::T;
|
|
||||||
|
|
||||||
pub mod computed_value {
|
|
||||||
pub type T = i32;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn get_initial_value() -> computed_value::T {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
|
|
||||||
specified::parse_integer(input)
|
|
||||||
}
|
|
||||||
</%helpers:longhand>
|
|
||||||
|
|
||||||
// FIXME: Gecko doesn't support content value yet.
|
// FIXME: Gecko doesn't support content value yet.
|
||||||
// FIXME: This property should be animatable.
|
// FIXME: This property should be animatable.
|
||||||
|
|
|
@ -70,8 +70,8 @@
|
||||||
|
|
||||||
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
|
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
|
||||||
return Ok(Longhands {
|
return Ok(Longhands {
|
||||||
flex_grow: Number(0.0),
|
flex_grow: Number::new(0.0),
|
||||||
flex_shrink: Number(0.0),
|
flex_shrink: Number::new(0.0),
|
||||||
% if product == "gecko":
|
% if product == "gecko":
|
||||||
flex_basis: LengthOrPercentageOrAuto::Auto
|
flex_basis: LengthOrPercentageOrAuto::Auto
|
||||||
% else:
|
% else:
|
||||||
|
@ -105,8 +105,8 @@
|
||||||
return Err(())
|
return Err(())
|
||||||
}
|
}
|
||||||
Ok(Longhands {
|
Ok(Longhands {
|
||||||
flex_grow: grow.unwrap_or(Number(1.0)),
|
flex_grow: grow.unwrap_or(Number::new(1.0)),
|
||||||
flex_shrink: shrink.unwrap_or(Number(1.0)),
|
flex_shrink: shrink.unwrap_or(Number::new(1.0)),
|
||||||
% if product == "gecko":
|
% if product == "gecko":
|
||||||
flex_basis: basis.unwrap_or(LengthOrPercentageOrAuto::Length(NoCalcLength::zero()))
|
flex_basis: basis.unwrap_or(LengthOrPercentageOrAuto::Length(NoCalcLength::zero()))
|
||||||
% else:
|
% else:
|
||||||
|
|
|
@ -537,27 +537,27 @@ impl ToComputedValue for specified::AngleOrCorner {
|
||||||
type ComputedValue = AngleOrCorner;
|
type ComputedValue = AngleOrCorner;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_computed_value(&self, _: &Context) -> AngleOrCorner {
|
fn to_computed_value(&self, context: &Context) -> AngleOrCorner {
|
||||||
match *self {
|
match *self {
|
||||||
specified::AngleOrCorner::None => {
|
specified::AngleOrCorner::None => {
|
||||||
AngleOrCorner::Angle(Angle(PI))
|
AngleOrCorner::Angle(Angle::from_radians(PI))
|
||||||
},
|
},
|
||||||
specified::AngleOrCorner::Angle(angle) => {
|
specified::AngleOrCorner::Angle(angle) => {
|
||||||
AngleOrCorner::Angle(angle)
|
AngleOrCorner::Angle(angle.to_computed_value(context))
|
||||||
},
|
},
|
||||||
specified::AngleOrCorner::Corner(horizontal, vertical) => {
|
specified::AngleOrCorner::Corner(horizontal, vertical) => {
|
||||||
match (horizontal, vertical) {
|
match (horizontal, vertical) {
|
||||||
(None, Some(VerticalDirection::Top)) => {
|
(None, Some(VerticalDirection::Top)) => {
|
||||||
AngleOrCorner::Angle(Angle(0.0))
|
AngleOrCorner::Angle(Angle::from_radians(0.0))
|
||||||
},
|
},
|
||||||
(Some(HorizontalDirection::Right), None) => {
|
(Some(HorizontalDirection::Right), None) => {
|
||||||
AngleOrCorner::Angle(Angle(PI * 0.5))
|
AngleOrCorner::Angle(Angle::from_radians(PI * 0.5))
|
||||||
},
|
},
|
||||||
(None, Some(VerticalDirection::Bottom)) => {
|
(None, Some(VerticalDirection::Bottom)) => {
|
||||||
AngleOrCorner::Angle(Angle(PI))
|
AngleOrCorner::Angle(Angle::from_radians(PI))
|
||||||
},
|
},
|
||||||
(Some(HorizontalDirection::Left), None) => {
|
(Some(HorizontalDirection::Left), None) => {
|
||||||
AngleOrCorner::Angle(Angle(PI * 1.5))
|
AngleOrCorner::Angle(Angle::from_radians(PI * 1.5))
|
||||||
},
|
},
|
||||||
(Some(horizontal), Some(vertical)) => {
|
(Some(horizontal), Some(vertical)) => {
|
||||||
AngleOrCorner::Corner(horizontal, vertical)
|
AngleOrCorner::Corner(horizontal, vertical)
|
||||||
|
@ -573,8 +573,8 @@ impl ToComputedValue for specified::AngleOrCorner {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_computed_value(computed: &AngleOrCorner) -> Self {
|
fn from_computed_value(computed: &AngleOrCorner) -> Self {
|
||||||
match *computed {
|
match *computed {
|
||||||
AngleOrCorner::Angle(angle) => {
|
AngleOrCorner::Angle(ref angle) => {
|
||||||
specified::AngleOrCorner::Angle(angle)
|
specified::AngleOrCorner::Angle(specified::Angle::from_computed_value(angle))
|
||||||
},
|
},
|
||||||
AngleOrCorner::Corner(horizontal, vertical) => {
|
AngleOrCorner::Corner(horizontal, vertical) => {
|
||||||
specified::AngleOrCorner::Corner(Some(horizontal), Some(vertical))
|
specified::AngleOrCorner::Corner(Some(horizontal), Some(vertical))
|
||||||
|
|
|
@ -20,7 +20,7 @@ pub use self::image::{LengthOrKeyword, LengthOrPercentageOrKeyword};
|
||||||
pub use super::{Auto, Either, None_};
|
pub use super::{Auto, Either, None_};
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub use super::specified::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
|
pub use super::specified::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
|
||||||
pub use super::specified::{Angle, BorderStyle, GridLine, Percentage, Time, UrlOrNone};
|
pub use super::specified::{BorderStyle, GridLine, Percentage, UrlOrNone};
|
||||||
pub use super::specified::url::SpecifiedUrl;
|
pub use super::specified::url::SpecifiedUrl;
|
||||||
pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto};
|
pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||||
pub use self::length::{LengthOrPercentageOrAutoOrContent, LengthOrPercentageOrNone, LengthOrNone};
|
pub use self::length::{LengthOrPercentageOrAutoOrContent, LengthOrPercentageOrNone, LengthOrNone};
|
||||||
|
@ -114,6 +114,76 @@ 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,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Angle {
|
||||||
|
/// Construct a computed `Angle` value from a radian amount.
|
||||||
|
pub fn from_radians(radians: CSSFloat) -> Self {
|
||||||
|
Angle {
|
||||||
|
radians: radians,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the amount of radians this angle represents.
|
||||||
|
#[inline]
|
||||||
|
pub fn radians(&self) -> CSSFloat {
|
||||||
|
self.radians
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an angle that represents a rotation of zero radians.
|
||||||
|
pub fn zero() -> Self {
|
||||||
|
Self::from_radians(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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A computed `<time>` value.
|
||||||
|
#[derive(Clone, PartialEq, PartialOrd, Copy, Debug)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
|
||||||
|
pub struct Time {
|
||||||
|
seconds: CSSFloat,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Time {
|
||||||
|
/// Construct a computed `Time` value from a seconds amount.
|
||||||
|
pub fn from_seconds(seconds: CSSFloat) -> Self {
|
||||||
|
Time {
|
||||||
|
seconds: seconds,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct a computed `Time` value that represents zero seconds.
|
||||||
|
pub fn zero() -> Self {
|
||||||
|
Self::from_seconds(0.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the amount of seconds this time represents.
|
||||||
|
#[inline]
|
||||||
|
pub fn seconds(&self) -> CSSFloat {
|
||||||
|
self.seconds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToCss for Time {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
|
||||||
|
where W: fmt::Write,
|
||||||
|
{
|
||||||
|
write!(dest, "{}s", self.seconds())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ToComputedValue for specified::Color {
|
impl ToComputedValue for specified::Color {
|
||||||
type ComputedValue = RGBA;
|
type ComputedValue = RGBA;
|
||||||
|
|
||||||
|
|
|
@ -507,8 +507,8 @@ pub struct CalcProductNode {
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub enum CalcValueNode {
|
pub enum CalcValueNode {
|
||||||
Length(NoCalcLength),
|
Length(NoCalcLength),
|
||||||
Angle(Angle),
|
Angle(CSSFloat),
|
||||||
Time(Time),
|
Time(CSSFloat),
|
||||||
Percentage(CSSFloat),
|
Percentage(CSSFloat),
|
||||||
Number(CSSFloat),
|
Number(CSSFloat),
|
||||||
Sum(Box<CalcSumNode>),
|
Sum(Box<CalcSumNode>),
|
||||||
|
@ -615,10 +615,14 @@ impl CalcLengthOrPercentage {
|
||||||
NoCalcLength::parse_dimension(value.value, unit).map(CalcValueNode::Length)
|
NoCalcLength::parse_dimension(value.value, unit).map(CalcValueNode::Length)
|
||||||
}
|
}
|
||||||
(Token::Dimension(ref value, ref unit), CalcUnit::Angle) => {
|
(Token::Dimension(ref value, ref unit), CalcUnit::Angle) => {
|
||||||
Angle::parse_dimension(value.value, unit).map(CalcValueNode::Angle)
|
Angle::parse_dimension(value.value, unit).map(|angle| {
|
||||||
|
CalcValueNode::Angle(angle.radians())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
(Token::Dimension(ref value, ref unit), CalcUnit::Time) => {
|
(Token::Dimension(ref value, ref unit), CalcUnit::Time) => {
|
||||||
Time::parse_dimension(value.value, unit).map(CalcValueNode::Time)
|
Time::parse_dimension(value.value, unit).map(|time| {
|
||||||
|
CalcValueNode::Time(time.seconds())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
(Token::Percentage(ref value), CalcUnit::LengthOrPercentage) =>
|
(Token::Percentage(ref value), CalcUnit::LengthOrPercentage) =>
|
||||||
Ok(CalcValueNode::Percentage(value.unit_value)),
|
Ok(CalcValueNode::Percentage(value.unit_value)),
|
||||||
|
@ -802,14 +806,14 @@ impl CalcLengthOrPercentage {
|
||||||
|
|
||||||
for value in simplified {
|
for value in simplified {
|
||||||
match value {
|
match value {
|
||||||
SimplifiedValueNode::Time(Time(val)) =>
|
SimplifiedValueNode::Time(val) =>
|
||||||
time = Some(time.unwrap_or(0.) + val),
|
time = Some(time.unwrap_or(0.) + val),
|
||||||
_ => return Err(()),
|
_ => return Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match time {
|
match time {
|
||||||
Some(time) => Ok(Time(time)),
|
Some(time) => Ok(Time::from_calc(time)),
|
||||||
_ => Err(())
|
_ => Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -831,16 +835,23 @@ impl CalcLengthOrPercentage {
|
||||||
|
|
||||||
for value in simplified {
|
for value in simplified {
|
||||||
match value {
|
match value {
|
||||||
SimplifiedValueNode::Angle(Angle(val)) =>
|
SimplifiedValueNode::Angle(val) => {
|
||||||
angle = Some(angle.unwrap_or(0.) + val),
|
angle = Some(angle.unwrap_or(0.) + val)
|
||||||
SimplifiedValueNode::Number(val) => number = Some(number.unwrap_or(0.) + val),
|
}
|
||||||
|
// TODO(emilio): This `Number` logic looks fishy.
|
||||||
|
//
|
||||||
|
// In particular, this allows calc(2 - 2) to parse as an
|
||||||
|
// `Angle`, which doesn't seem desired to me.
|
||||||
|
SimplifiedValueNode::Number(val) => {
|
||||||
|
number = Some(number.unwrap_or(0.) + val)
|
||||||
|
}
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match (angle, number) {
|
match (angle, number) {
|
||||||
(Some(angle), None) => Ok(Angle(angle)),
|
(Some(angle), None) => Ok(Angle::from_calc(angle)),
|
||||||
(None, Some(value)) if value == 0. => Ok(Angle(0.)),
|
(None, Some(value)) if value == 0. => Ok(Angle::from_calc(0.)),
|
||||||
_ => Err(())
|
_ => Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -899,12 +910,24 @@ impl ToCss for CalcLengthOrPercentage {
|
||||||
/// A percentage value.
|
/// A percentage value.
|
||||||
///
|
///
|
||||||
/// [0 .. 100%] maps to [0.0 .. 1.0]
|
/// [0 .. 100%] maps to [0.0 .. 1.0]
|
||||||
|
///
|
||||||
|
/// FIXME(emilio): There's no standard property that requires a `<percentage>`
|
||||||
|
/// without requiring also a `<length>`. If such a property existed, we'd need
|
||||||
|
/// to add special handling for `calc()` and percentages in here in the same way
|
||||||
|
/// as for `Angle` and `Time`, but the lack of this this is otherwise
|
||||||
|
/// undistinguishable (we handle it correctly from `CalcLengthOrPercentage`).
|
||||||
|
///
|
||||||
|
/// As of today, only `-moz-image-rect` supports percentages without length.
|
||||||
|
/// This is not a regression, and that's a non-standard extension anyway, so I'm
|
||||||
|
/// not implementing it for now.
|
||||||
#[derive(Clone, PartialEq, Copy, Debug)]
|
#[derive(Clone, PartialEq, Copy, Debug)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
pub struct Percentage(pub CSSFloat);
|
pub struct Percentage(pub CSSFloat);
|
||||||
|
|
||||||
impl ToCss for Percentage {
|
impl ToCss for Percentage {
|
||||||
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,
|
||||||
|
{
|
||||||
write!(dest, "{}%", self.0 * 100.)
|
write!(dest, "{}%", self.0 * 100.)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ use std::fmt;
|
||||||
use std::ops::Mul;
|
use std::ops::Mul;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
use super::{Auto, CSSFloat, CSSInteger, HasViewportPercentage, Either, None_};
|
use super::{Auto, CSSFloat, CSSInteger, HasViewportPercentage, Either, None_};
|
||||||
use super::computed::{ComputedValueAsSpecified, Context};
|
use super::computed::{self, Context};
|
||||||
use super::computed::{Shadow as ComputedShadow, ToComputedValue};
|
use super::computed::{Shadow as ComputedShadow, ToComputedValue};
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
|
@ -166,8 +166,8 @@ impl<'a> Mul<CSSFloat> for &'a SimplifiedSumNode {
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub enum SimplifiedValueNode {
|
pub enum SimplifiedValueNode {
|
||||||
Length(NoCalcLength),
|
Length(NoCalcLength),
|
||||||
Angle(Angle),
|
Angle(CSSFloat),
|
||||||
Time(Time),
|
Time(CSSFloat),
|
||||||
Percentage(CSSFloat),
|
Percentage(CSSFloat),
|
||||||
Number(CSSFloat),
|
Number(CSSFloat),
|
||||||
Sum(Box<SimplifiedSumNode>),
|
Sum(Box<SimplifiedSumNode>),
|
||||||
|
@ -179,25 +179,37 @@ impl<'a> Mul<CSSFloat> for &'a SimplifiedValueNode {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mul(self, scalar: CSSFloat) -> SimplifiedValueNode {
|
fn mul(self, scalar: CSSFloat) -> SimplifiedValueNode {
|
||||||
match *self {
|
match *self {
|
||||||
SimplifiedValueNode::Length(ref l) => SimplifiedValueNode::Length(l.clone() * scalar),
|
SimplifiedValueNode::Length(ref l) => {
|
||||||
SimplifiedValueNode::Percentage(p) => SimplifiedValueNode::Percentage(p * scalar),
|
SimplifiedValueNode::Length(l.clone() * scalar)
|
||||||
SimplifiedValueNode::Angle(Angle(a)) => SimplifiedValueNode::Angle(Angle(a * scalar)),
|
},
|
||||||
SimplifiedValueNode::Time(Time(t)) => SimplifiedValueNode::Time(Time(t * scalar)),
|
SimplifiedValueNode::Percentage(p) => {
|
||||||
SimplifiedValueNode::Number(n) => SimplifiedValueNode::Number(n * scalar),
|
SimplifiedValueNode::Percentage(p * scalar)
|
||||||
|
},
|
||||||
|
SimplifiedValueNode::Angle(a) => {
|
||||||
|
SimplifiedValueNode::Angle(a * scalar)
|
||||||
|
},
|
||||||
|
SimplifiedValueNode::Time(t) => {
|
||||||
|
SimplifiedValueNode::Time(t * scalar)
|
||||||
|
},
|
||||||
|
SimplifiedValueNode::Number(n) => {
|
||||||
|
SimplifiedValueNode::Number(n * scalar)
|
||||||
|
},
|
||||||
SimplifiedValueNode::Sum(ref s) => {
|
SimplifiedValueNode::Sum(ref s) => {
|
||||||
let sum = &**s * scalar;
|
let sum = &**s * scalar;
|
||||||
SimplifiedValueNode::Sum(Box::new(sum))
|
SimplifiedValueNode::Sum(Box::new(sum))
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub fn parse_integer(input: &mut Parser) -> Result<CSSInteger, ()> {
|
pub fn parse_integer(input: &mut Parser) -> Result<Integer, ()> {
|
||||||
match try!(input.next()) {
|
match try!(input.next()) {
|
||||||
Token::Number(ref value) => value.int_value.ok_or(()),
|
Token::Number(ref value) => value.int_value.ok_or(()).map(Integer::new),
|
||||||
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
|
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
|
||||||
let ast = try!(input.parse_nested_block(|i| CalcLengthOrPercentage::parse_sum(i, CalcUnit::Integer)));
|
let ast = try!(input.parse_nested_block(|i| {
|
||||||
|
CalcLengthOrPercentage::parse_sum(i, CalcUnit::Integer)
|
||||||
|
}));
|
||||||
|
|
||||||
let mut result = None;
|
let mut result = None;
|
||||||
|
|
||||||
|
@ -210,7 +222,7 @@ pub fn parse_integer(input: &mut Parser) -> Result<CSSInteger, ()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Some(result) => Ok(result),
|
Some(result) => Ok(Integer::from_calc(result)),
|
||||||
_ => Err(())
|
_ => Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,17 +231,15 @@ pub fn parse_integer(input: &mut Parser) -> Result<CSSInteger, ()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
#[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()) {
|
match try!(input.next()) {
|
||||||
Token::Number(ref value) => {
|
Token::Number(ref value) => {
|
||||||
use std::f32;
|
Ok(Number {
|
||||||
if value.value.is_finite() {
|
value: value.value.min(f32::MAX).max(f32::MIN),
|
||||||
Ok(value.value)
|
was_calc: false,
|
||||||
} else if value.value.is_sign_positive() {
|
})
|
||||||
Ok(f32::MAX)
|
|
||||||
} else {
|
|
||||||
Ok(f32::MIN)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
|
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)));
|
let ast = try!(input.parse_nested_block(|i| CalcLengthOrPercentage::parse_sum(i, CalcUnit::Number)));
|
||||||
|
@ -245,7 +255,12 @@ pub fn parse_number(input: &mut Parser) -> Result<f32, ()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Some(result) => Ok(result),
|
Some(result) => {
|
||||||
|
Ok(Number {
|
||||||
|
value: result.min(f32::MAX).max(f32::MIN),
|
||||||
|
was_calc: true,
|
||||||
|
})
|
||||||
|
},
|
||||||
_ => Err(())
|
_ => Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -299,11 +314,36 @@ impl ToCss for BorderRadiusSize {
|
||||||
#[derive(Clone, PartialEq, PartialOrd, Copy, Debug)]
|
#[derive(Clone, PartialEq, PartialOrd, Copy, Debug)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
|
||||||
/// An angle, normalized to radians.
|
/// An angle, normalized to radians.
|
||||||
pub struct Angle(pub CSSFloat);
|
pub struct Angle {
|
||||||
|
radians: CSSFloat,
|
||||||
|
was_calc: bool,
|
||||||
|
}
|
||||||
|
|
||||||
impl ToCss for Angle {
|
impl ToCss for Angle {
|
||||||
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 {
|
||||||
write!(dest, "{}rad", self.0)
|
if self.was_calc {
|
||||||
|
dest.write_str("calc(")?;
|
||||||
|
}
|
||||||
|
write!(dest, "{}rad", self.radians)?;
|
||||||
|
if self.was_calc {
|
||||||
|
dest.write_str(")")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToComputedValue for Angle {
|
||||||
|
type ComputedValue = computed::Angle;
|
||||||
|
|
||||||
|
fn to_computed_value(&self, _context: &Context) -> Self::ComputedValue {
|
||||||
|
computed::Angle::from_radians(self.radians())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||||
|
Angle {
|
||||||
|
radians: computed.radians(),
|
||||||
|
was_calc: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,13 +351,29 @@ impl Angle {
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub fn radians(self) -> f32 {
|
pub fn radians(self) -> f32 {
|
||||||
self.0
|
self.radians
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an angle value that represents zero radians.
|
||||||
|
pub fn zero() -> Self {
|
||||||
|
Self::from_radians(0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub fn from_radians(r: f32) -> Self {
|
pub fn from_radians(r: f32) -> Self {
|
||||||
Angle(r)
|
Angle {
|
||||||
|
radians: r,
|
||||||
|
was_calc: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an `Angle` parsed from a `calc()` expression.
|
||||||
|
pub fn from_calc(radians: CSSFloat) -> Self {
|
||||||
|
Angle {
|
||||||
|
radians: radians,
|
||||||
|
was_calc: true,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,7 +386,7 @@ impl Parse for Angle {
|
||||||
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||||
match try!(input.next()) {
|
match try!(input.next()) {
|
||||||
Token::Dimension(ref value, ref unit) => Angle::parse_dimension(value.value, unit),
|
Token::Dimension(ref value, ref unit) => Angle::parse_dimension(value.value, unit),
|
||||||
Token::Number(ref value) if value.value == 0. => Ok(Angle(0.)),
|
Token::Number(ref value) if value.value == 0. => Ok(Angle::zero()),
|
||||||
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
|
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
|
||||||
input.parse_nested_block(CalcLengthOrPercentage::parse_angle)
|
input.parse_nested_block(CalcLengthOrPercentage::parse_angle)
|
||||||
},
|
},
|
||||||
|
@ -342,13 +398,18 @@ impl Parse for Angle {
|
||||||
impl Angle {
|
impl Angle {
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Angle, ()> {
|
pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Angle, ()> {
|
||||||
match_ignore_ascii_case! { unit,
|
let radians = match_ignore_ascii_case! { unit,
|
||||||
"deg" => Ok(Angle(value * RAD_PER_DEG)),
|
"deg" => value * RAD_PER_DEG,
|
||||||
"grad" => Ok(Angle(value * RAD_PER_GRAD)),
|
"grad" => value * RAD_PER_GRAD,
|
||||||
"turn" => Ok(Angle(value * RAD_PER_TURN)),
|
"turn" => value * RAD_PER_TURN,
|
||||||
"rad" => Ok(Angle(value)),
|
"rad" => value,
|
||||||
_ => Err(())
|
_ => return Err(())
|
||||||
}
|
};
|
||||||
|
|
||||||
|
Ok(Angle {
|
||||||
|
radians: radians,
|
||||||
|
was_calc: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,28 +540,67 @@ impl BorderStyle {
|
||||||
/// A time in seconds according to CSS-VALUES § 6.2.
|
/// A time in seconds according to CSS-VALUES § 6.2.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
pub struct Time(pub CSSFloat);
|
pub struct Time {
|
||||||
|
seconds: CSSFloat,
|
||||||
|
was_calc: bool,
|
||||||
|
}
|
||||||
|
|
||||||
impl Time {
|
impl Time {
|
||||||
|
/// Return a `<time>` value that represents `seconds` seconds.
|
||||||
|
pub fn from_seconds(seconds: CSSFloat) -> Self {
|
||||||
|
Time {
|
||||||
|
seconds: seconds,
|
||||||
|
was_calc: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a time that represents a duration of zero.
|
||||||
|
pub fn zero() -> Self {
|
||||||
|
Self::from_seconds(0.0)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the time in fractional seconds.
|
/// Returns the time in fractional seconds.
|
||||||
pub fn seconds(self) -> f32 {
|
pub fn seconds(self) -> CSSFloat {
|
||||||
let Time(seconds) = self;
|
self.seconds
|
||||||
seconds
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses a time according to CSS-VALUES § 6.2.
|
/// Parses a time according to CSS-VALUES § 6.2.
|
||||||
fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Time, ()> {
|
fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Time, ()> {
|
||||||
if unit.eq_ignore_ascii_case("s") {
|
let seconds = match_ignore_ascii_case! { unit,
|
||||||
Ok(Time(value))
|
"s" => value,
|
||||||
} else if unit.eq_ignore_ascii_case("ms") {
|
"ms" => value / 1000.0,
|
||||||
Ok(Time(value / 1000.0))
|
_ => return Err(()),
|
||||||
} else {
|
};
|
||||||
Err(())
|
|
||||||
|
Ok(Time {
|
||||||
|
seconds: seconds,
|
||||||
|
was_calc: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a `Time` value from a CSS `calc()` expression.
|
||||||
|
pub fn from_calc(seconds: CSSFloat) -> Self {
|
||||||
|
Time {
|
||||||
|
seconds: seconds,
|
||||||
|
was_calc: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComputedValueAsSpecified for Time {}
|
impl ToComputedValue for Time {
|
||||||
|
type ComputedValue = computed::Time;
|
||||||
|
|
||||||
|
fn to_computed_value(&self, _context: &Context) -> Self::ComputedValue {
|
||||||
|
computed::Time::from_seconds(self.seconds())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||||
|
Time {
|
||||||
|
seconds: computed.seconds(),
|
||||||
|
was_calc: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Parse for Time {
|
impl Parse for Time {
|
||||||
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||||
|
@ -518,31 +618,53 @@ impl Parse for Time {
|
||||||
|
|
||||||
impl ToCss for Time {
|
impl ToCss for Time {
|
||||||
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 {
|
||||||
write!(dest, "{}s", self.0)
|
if self.was_calc {
|
||||||
|
dest.write_str("calc(")?;
|
||||||
|
}
|
||||||
|
write!(dest, "{}s", self.seconds)?;
|
||||||
|
if self.was_calc {
|
||||||
|
dest.write_str(")")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
#[allow(missing_docs)]
|
#[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);
|
no_viewport_percentage!(Number);
|
||||||
|
|
||||||
impl Parse for Number {
|
impl Parse for Number {
|
||||||
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||||
parse_number(input).map(Number)
|
parse_number(input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Number {
|
impl Number {
|
||||||
fn parse_with_minimum(input: &mut Parser, min: CSSFloat) -> Result<Number, ()> {
|
fn parse_with_minimum(input: &mut Parser, min: CSSFloat) -> Result<Number, ()> {
|
||||||
match parse_number(input) {
|
match parse_number(input) {
|
||||||
Ok(value) if value >= min => Ok(Number(value)),
|
Ok(value) if value.value >= min => Ok(value),
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a new number with the value `val`.
|
||||||
|
pub fn new(val: CSSFloat) -> Self {
|
||||||
|
Number {
|
||||||
|
value: val,
|
||||||
|
was_calc: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub fn parse_non_negative(input: &mut Parser) -> Result<Number, ()> {
|
pub fn parse_non_negative(input: &mut Parser) -> Result<Number, ()> {
|
||||||
Number::parse_with_minimum(input, 0.0)
|
Number::parse_with_minimum(input, 0.0)
|
||||||
|
@ -558,17 +680,29 @@ impl ToComputedValue for Number {
|
||||||
type ComputedValue = CSSFloat;
|
type ComputedValue = CSSFloat;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_computed_value(&self, _: &Context) -> CSSFloat { self.0 }
|
fn to_computed_value(&self, _: &Context) -> CSSFloat { self.value }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_computed_value(computed: &CSSFloat) -> Self {
|
fn from_computed_value(computed: &CSSFloat) -> Self {
|
||||||
Number(*computed)
|
Number {
|
||||||
|
value: *computed,
|
||||||
|
was_calc: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToCss for Number {
|
impl ToCss for Number {
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
|
||||||
self.0.to_css(dest)
|
where W: fmt::Write,
|
||||||
|
{
|
||||||
|
if self.was_calc {
|
||||||
|
dest.write_str("calc(")?;
|
||||||
|
}
|
||||||
|
self.value.to_css(dest)?;
|
||||||
|
if self.was_calc {
|
||||||
|
dest.write_str(")")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -606,7 +740,7 @@ impl ToCss for NumberOrPercentage {
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub struct Opacity(pub CSSFloat);
|
pub struct Opacity(Number);
|
||||||
|
|
||||||
no_viewport_percentage!(Opacity);
|
no_viewport_percentage!(Opacity);
|
||||||
|
|
||||||
|
@ -620,19 +754,13 @@ impl ToComputedValue for Opacity {
|
||||||
type ComputedValue = CSSFloat;
|
type ComputedValue = CSSFloat;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_computed_value(&self, _: &Context) -> CSSFloat {
|
fn to_computed_value(&self, context: &Context) -> CSSFloat {
|
||||||
if self.0 < 0.0 {
|
self.0.to_computed_value(context).min(1.0).max(0.0)
|
||||||
0.0
|
|
||||||
} else if self.0 > 1.0 {
|
|
||||||
1.0
|
|
||||||
} else {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_computed_value(computed: &CSSFloat) -> Self {
|
fn from_computed_value(computed: &CSSFloat) -> Self {
|
||||||
Opacity(*computed)
|
Opacity(Number::from_computed_value(computed))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -645,21 +773,47 @@ impl ToCss for Opacity {
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub struct Integer(pub CSSInteger);
|
pub struct Integer {
|
||||||
|
value: CSSInteger,
|
||||||
|
was_calc: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Integer {
|
||||||
|
/// Trivially constructs a new `Integer` value.
|
||||||
|
pub fn new(val: CSSInteger) -> Self {
|
||||||
|
Integer {
|
||||||
|
value: val,
|
||||||
|
was_calc: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the integer value associated with this value.
|
||||||
|
pub fn value(&self) -> CSSInteger {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trivially constructs a new integer value from a `calc()` expression.
|
||||||
|
pub fn from_calc(val: CSSInteger) -> Self {
|
||||||
|
Integer {
|
||||||
|
value: val,
|
||||||
|
was_calc: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
no_viewport_percentage!(Integer);
|
no_viewport_percentage!(Integer);
|
||||||
|
|
||||||
impl Parse for Integer {
|
impl Parse for Integer {
|
||||||
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||||
parse_integer(input).map(Integer)
|
parse_integer(input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Integer {
|
impl Integer {
|
||||||
fn parse_with_minimum(input: &mut Parser, min: i32) -> Result<Integer, ()> {
|
fn parse_with_minimum(input: &mut Parser, min: i32) -> Result<Integer, ()> {
|
||||||
match parse_integer(input) {
|
match parse_integer(input) {
|
||||||
Ok(value) if value < min => Err(()),
|
Ok(value) if value.value() >= min => Ok(value),
|
||||||
value => value.map(Integer),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -678,17 +832,26 @@ impl ToComputedValue for Integer {
|
||||||
type ComputedValue = i32;
|
type ComputedValue = i32;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_computed_value(&self, _: &Context) -> i32 { self.0 }
|
fn to_computed_value(&self, _: &Context) -> i32 { self.value }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_computed_value(computed: &i32) -> Self {
|
fn from_computed_value(computed: &i32) -> Self {
|
||||||
Integer(*computed)
|
Integer::new(*computed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToCss for Integer {
|
impl ToCss for Integer {
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
|
||||||
write!(dest, "{}", self.0)
|
where W: fmt::Write,
|
||||||
|
{
|
||||||
|
if self.was_calc {
|
||||||
|
dest.write_str("calc(")?;
|
||||||
|
}
|
||||||
|
write!(dest, "{}", self.value)?;
|
||||||
|
if self.was_calc {
|
||||||
|
dest.write_str(")")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -697,9 +860,11 @@ pub type IntegerOrAuto = Either<Integer, Auto>;
|
||||||
|
|
||||||
impl IntegerOrAuto {
|
impl IntegerOrAuto {
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub fn parse_positive(context: &ParserContext, input: &mut Parser) -> Result<IntegerOrAuto, ()> {
|
pub fn parse_positive(context: &ParserContext,
|
||||||
|
input: &mut Parser)
|
||||||
|
-> Result<IntegerOrAuto, ()> {
|
||||||
match IntegerOrAuto::parse(context, input) {
|
match IntegerOrAuto::parse(context, input) {
|
||||||
Ok(Either::First(Integer(value))) if value <= 0 => Err(()),
|
Ok(Either::First(integer)) if integer.value() <= 0 => Err(()),
|
||||||
result => result,
|
result => result,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1202,7 +1202,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(declarations:
|
||||||
BorderSpacing => Box::new(
|
BorderSpacing => Box::new(
|
||||||
BorderSpacing {
|
BorderSpacing {
|
||||||
horizontal: nocalc.into(),
|
horizontal: nocalc.into(),
|
||||||
vertical: nocalc.into(),
|
vertical: None,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
|
@ -55,7 +55,7 @@ fn test_linear_gradient() {
|
||||||
font_metrics_provider: None,
|
font_metrics_provider: None,
|
||||||
};
|
};
|
||||||
assert_eq!(specified::AngleOrCorner::None.to_computed_value(&specified_context),
|
assert_eq!(specified::AngleOrCorner::None.to_computed_value(&specified_context),
|
||||||
computed::AngleOrCorner::Angle(Angle(PI)));
|
computed::AngleOrCorner::Angle(Angle::from_radians(PI)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -573,15 +573,14 @@ mod shorthand_serialization {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn flex_should_serialize_all_available_properties() {
|
fn flex_should_serialize_all_available_properties() {
|
||||||
use style::values::specified::Number as NumberContainer;
|
use style::values::specified::{Number, Percentage};
|
||||||
use style::values::specified::Percentage as PercentageContainer;
|
|
||||||
|
|
||||||
let mut properties = Vec::new();
|
let mut properties = Vec::new();
|
||||||
|
|
||||||
let grow = NumberContainer(2f32);
|
let grow = Number::new(2f32);
|
||||||
let shrink = NumberContainer(3f32);
|
let shrink = Number::new(3f32);
|
||||||
let basis =
|
let basis =
|
||||||
LengthOrPercentageOrAutoOrContent::Percentage(PercentageContainer(0.5f32));
|
LengthOrPercentageOrAutoOrContent::Percentage(Percentage(0.5f32));
|
||||||
|
|
||||||
properties.push(PropertyDeclaration::FlexGrow(grow));
|
properties.push(PropertyDeclaration::FlexGrow(grow));
|
||||||
properties.push(PropertyDeclaration::FlexShrink(shrink));
|
properties.push(PropertyDeclaration::FlexShrink(shrink));
|
||||||
|
@ -1174,13 +1173,14 @@ mod shorthand_serialization {
|
||||||
mod counter_increment {
|
mod counter_increment {
|
||||||
pub use super::*;
|
pub use super::*;
|
||||||
pub use style::properties::longhands::counter_increment::SpecifiedValue as CounterIncrement;
|
pub use style::properties::longhands::counter_increment::SpecifiedValue as CounterIncrement;
|
||||||
|
use style::values::specified::Integer;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn counter_increment_with_properties_should_serialize_correctly() {
|
fn counter_increment_with_properties_should_serialize_correctly() {
|
||||||
let mut properties = Vec::new();
|
let mut properties = Vec::new();
|
||||||
|
|
||||||
properties.push(("counter1".to_owned(), 1));
|
properties.push(("counter1".to_owned(), Integer::new(1)));
|
||||||
properties.push(("counter2".to_owned(), -4));
|
properties.push(("counter2".to_owned(), Integer::new(-4)));
|
||||||
|
|
||||||
let counter_increment = CounterIncrement(properties);
|
let counter_increment = CounterIncrement(properties);
|
||||||
let counter_increment_css = "counter1 1 counter2 -4";
|
let counter_increment_css = "counter1 1 counter2 -4";
|
||||||
|
|
|
@ -1,13 +1,5 @@
|
||||||
[serialize-values.html]
|
[serialize-values.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
[border-spacing: 0px]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[border-spacing: 1px]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[border-spacing: .1em]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[content: url("http://localhost/")]
|
[content: url("http://localhost/")]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
|
@ -11057,6 +11057,12 @@
|
||||||
{}
|
{}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"css/calc-number-serialization.html": [
|
||||||
|
[
|
||||||
|
"/_mozilla/css/calc-number-serialization.html",
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
"css/empty-keyframes.html": [
|
"css/empty-keyframes.html": [
|
||||||
[
|
[
|
||||||
"/_mozilla/css/empty-keyframes.html",
|
"/_mozilla/css/empty-keyframes.html",
|
||||||
|
@ -20700,6 +20706,10 @@
|
||||||
"94dc4aac4c546a74add074be0d3e604c8b196888",
|
"94dc4aac4c546a74add074be0d3e604c8b196888",
|
||||||
"reftest"
|
"reftest"
|
||||||
],
|
],
|
||||||
|
"css/calc-number-serialization.html": [
|
||||||
|
"b9e77c824d0c96e51d51fb8f1e923d3ab67be027",
|
||||||
|
"testharness"
|
||||||
|
],
|
||||||
"css/canvas_as_block_element_a.html": [
|
"css/canvas_as_block_element_a.html": [
|
||||||
"668d93da2dab9722998cc7c5785c20e2ab9a1ced",
|
"668d93da2dab9722998cc7c5785c20e2ab9a1ced",
|
||||||
"reftest"
|
"reftest"
|
||||||
|
@ -25113,7 +25123,7 @@
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"mozilla/calc.html": [
|
"mozilla/calc.html": [
|
||||||
"c333be7c567aebd1ed2f763d0ed644165ae8bd3b",
|
"c239c441c90e4d4ed94458eae5b2defabb47e984",
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
"mozilla/canvas.initial.reset.2dstate.html": [
|
"mozilla/canvas.initial.reset.2dstate.html": [
|
||||||
|
|
|
@ -1,14 +1,3 @@
|
||||||
[calc.html]
|
[calc.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
[calc for border-width]
|
prefs: [layout.column-count.enabled:true,layout.column-width.enabled:true,layout.column-gap.enabled:true]
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[calc for column-width]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[calc for column-gap]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[calc for column-count]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
18
tests/wpt/mozilla/tests/css/calc-number-serialization.html
Normal file
18
tests/wpt/mozilla/tests/css/calc-number-serialization.html
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>CSS test: Calc expressions with numbers should still serialize as calc()</title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<div id="test"></div>
|
||||||
|
<script>
|
||||||
|
var div = document.querySelector('#test');
|
||||||
|
test(function() {
|
||||||
|
div.style.lineHeight = "calc(1)";
|
||||||
|
assert_equals(div.style.lineHeight, "calc(1)");
|
||||||
|
}, "calc of an integer expression should be preserved");
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
div.style.lineHeight = "calc(1 + 3)";
|
||||||
|
assert_equals(div.style.lineHeight, "calc(4)");
|
||||||
|
}, "expressions on calc() should be simplified");
|
||||||
|
</script>
|
|
@ -6,6 +6,10 @@
|
||||||
#outer {
|
#outer {
|
||||||
width: 1000px;
|
width: 1000px;
|
||||||
}
|
}
|
||||||
|
#inner {
|
||||||
|
border-style: solid; /* So used border == computed border */
|
||||||
|
outline-style: solid; /* So used outline-width == computed outline-width */
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -76,7 +80,9 @@ var lengthProperties = [
|
||||||
lengthProperties.forEach(function(prop) {
|
lengthProperties.forEach(function(prop) {
|
||||||
test(function() {
|
test(function() {
|
||||||
div.style.setProperty(prop, 'calc(1px)');
|
div.style.setProperty(prop, 'calc(1px)');
|
||||||
assert_equals(div.style.getPropertyValue(prop), 'calc(1px)');
|
assert_equals(div.style.getPropertyValue(prop), 'calc(1px)', div.style.getPropertyValue(prop));
|
||||||
|
let computed = getComputedStyle(div).getPropertyValue(prop);
|
||||||
|
assert_equals(computed, '1px', prop + ': expected 1px, got ' + computed);
|
||||||
}, 'calc for ' + prop);
|
}, 'calc for ' + prop);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -112,12 +118,14 @@ var timeProperties = [
|
||||||
timeProperties.forEach(function(prop) {
|
timeProperties.forEach(function(prop) {
|
||||||
test(function() {
|
test(function() {
|
||||||
div.style.setProperty(prop, 'calc(1s)');
|
div.style.setProperty(prop, 'calc(1s)');
|
||||||
assert_equals(div.style.getPropertyValue(prop), '1s');
|
assert_equals(div.style.getPropertyValue(prop), 'calc(1s)');
|
||||||
|
assert_equals(getComputedStyle(div).getPropertyValue(prop), '1s');
|
||||||
}, 'calc for ' + prop);
|
}, 'calc for ' + prop);
|
||||||
});
|
});
|
||||||
|
|
||||||
var numberProperties = [
|
var numberProperties = [
|
||||||
'z-index',
|
'z-index',
|
||||||
|
'order',
|
||||||
'column-count',
|
'column-count',
|
||||||
'opacity',
|
'opacity',
|
||||||
];
|
];
|
||||||
|
@ -125,13 +133,14 @@ var numberProperties = [
|
||||||
numberProperties.forEach(function(prop) {
|
numberProperties.forEach(function(prop) {
|
||||||
test(function() {
|
test(function() {
|
||||||
div.style.setProperty(prop, 'calc(1)');
|
div.style.setProperty(prop, 'calc(1)');
|
||||||
assert_equals(div.style.getPropertyValue(prop), '1');
|
assert_equals(div.style.getPropertyValue(prop), 'calc(1)');
|
||||||
|
assert_equals(getComputedStyle(div).getPropertyValue(prop), '1');
|
||||||
}, 'calc for ' + prop);
|
}, 'calc for ' + prop);
|
||||||
});
|
});
|
||||||
|
|
||||||
var otherProperties = [
|
var otherProperties = [
|
||||||
['border-width', 'calc(1px)', '1px 1px 1px 1px'],
|
['border-width', 'calc(1px)', 'calc(1px)'],
|
||||||
['border-spacing', 'calc(1px)', 'calc(1px) calc(1px)'],
|
['border-spacing', 'calc(1px)', 'calc(1px)'],
|
||||||
['transform-origin', 'calc(1px + 0%)', 'calc(1px + 0%) 50% 0px'],
|
['transform-origin', 'calc(1px + 0%)', 'calc(1px + 0%) 50% 0px'],
|
||||||
['perspective-origin', 'calc(1px + 0%)', 'calc(1px + 0%) 50%'],
|
['perspective-origin', 'calc(1px + 0%)', 'calc(1px + 0%) 50%'],
|
||||||
['background-size', 'calc(1px + 0%)', 'calc(1px + 0%) auto'],
|
['background-size', 'calc(1px + 0%)', 'calc(1px + 0%) auto'],
|
||||||
|
@ -140,6 +149,7 @@ var otherProperties = [
|
||||||
['border-bottom-left-radius', 'calc(1px + 0%)', 'calc(1px + 0%) calc(1px + 0%)'],
|
['border-bottom-left-radius', 'calc(1px + 0%)', 'calc(1px + 0%) calc(1px + 0%)'],
|
||||||
['border-top-right-radius', 'calc(1px + 0%)', 'calc(1px + 0%) calc(1px + 0%)'],
|
['border-top-right-radius', 'calc(1px + 0%)', 'calc(1px + 0%) calc(1px + 0%)'],
|
||||||
['border-bottom-right-radius', 'calc(1px + 0%)', 'calc(1px + 0%) calc(1px + 0%)'],
|
['border-bottom-right-radius', 'calc(1px + 0%)', 'calc(1px + 0%) calc(1px + 0%)'],
|
||||||
|
['counter-increment', 'foo calc(1 + 1)', 'foo calc(2)'],
|
||||||
];
|
];
|
||||||
|
|
||||||
otherProperties.forEach(function(testcase) {
|
otherProperties.forEach(function(testcase) {
|
||||||
|
@ -150,7 +160,7 @@ otherProperties.forEach(function(testcase) {
|
||||||
});
|
});
|
||||||
|
|
||||||
/* TODO: test these:
|
/* TODO: test these:
|
||||||
counter-increment, counter-reset,
|
counter-reset,
|
||||||
color, box-shadow, clip, text-shadow, transform
|
color, box-shadow, clip, text-shadow, transform
|
||||||
transition-timing-function
|
transition-timing-function
|
||||||
angles
|
angles
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue