mirror of
https://github.com/servo/servo.git
synced 2025-08-04 05:00:08 +01:00
Handle values as valid in single transition shorthand even if the transition-property is 'none'.
A single transition value that includes 'none' for transition-property is valid, so we should store whole specified values (if it's valid). Whereas, the spec [1] clearly says for the case where there are multiple entries; If there is more than one <single-transition> in the shorthand, and any of the transitions has none as the <single-transition-property>, then the declaration is invalid. 'none 2s linear 2s' is a test case for the former, '1s width, 2s none' is a test case for the latter. Note that with this patch, 'transition: none' is serialized as 'none 0s ease 0s' instead of 'none' but it matches Gecko. [1] https://drafts.csswg.org/css-transitions/#single-transition MozReview-Commit-ID: 3o3z5GFyMqh
This commit is contained in:
parent
42873abe84
commit
aad63f241c
1 changed files with 54 additions and 27 deletions
|
@ -92,9 +92,12 @@ macro_rules! try_parse_one {
|
||||||
pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
|
pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
|
||||||
-> Result<Longhands, ParseError<'i>> {
|
-> Result<Longhands, ParseError<'i>> {
|
||||||
struct SingleTransition {
|
struct SingleTransition {
|
||||||
% for prop in "property duration timing_function delay".split():
|
% for prop in "duration timing_function delay".split():
|
||||||
transition_${prop}: transition_${prop}::SingleSpecifiedValue,
|
transition_${prop}: transition_${prop}::SingleSpecifiedValue,
|
||||||
% endfor
|
% endfor
|
||||||
|
// Unlike other properties, transition-property uses an Option<> to
|
||||||
|
// represent 'none' as `None`.
|
||||||
|
transition_property: Option<transition_property::SingleSpecifiedValue>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_one_transition<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
|
fn parse_one_transition<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
|
||||||
|
@ -112,7 +115,17 @@ macro_rules! try_parse_one {
|
||||||
try_parse_one!(context, input, delay, transition_delay);
|
try_parse_one!(context, input, delay, transition_delay);
|
||||||
// Must check 'transition-property' after 'transition-timing-function' since
|
// Must check 'transition-property' after 'transition-timing-function' since
|
||||||
// 'transition-property' accepts any keyword.
|
// 'transition-property' accepts any keyword.
|
||||||
try_parse_one!(input, property, transition_property);
|
if property.is_none() {
|
||||||
|
if let Ok(value) = input.try(|i| transition_property::SingleSpecifiedValue::parse(i)) {
|
||||||
|
property = Some(Some(value));
|
||||||
|
continue;
|
||||||
|
} else if input.try(|i| i.expect_ident_matching("none")).is_ok() {
|
||||||
|
// 'none' is not a valid value for <single-transition-property>,
|
||||||
|
// so it's not acceptable in the function above.
|
||||||
|
property = Some(None);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
parsed -= 1;
|
parsed -= 1;
|
||||||
break
|
break
|
||||||
|
@ -120,10 +133,12 @@ macro_rules! try_parse_one {
|
||||||
|
|
||||||
if parsed != 0 {
|
if parsed != 0 {
|
||||||
Ok(SingleTransition {
|
Ok(SingleTransition {
|
||||||
% for prop in "property duration timing_function delay".split():
|
% for prop in "duration timing_function delay".split():
|
||||||
transition_${prop}: ${prop}.unwrap_or_else(transition_${prop}::single_value
|
transition_${prop}: ${prop}.unwrap_or_else(transition_${prop}::single_value
|
||||||
::get_initial_specified_value),
|
::get_initial_specified_value),
|
||||||
% endfor
|
% endfor
|
||||||
|
transition_property: property.unwrap_or(
|
||||||
|
Some(transition_property::single_value::get_initial_specified_value())),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(StyleParseError::UnspecifiedError.into())
|
Err(StyleParseError::UnspecifiedError.into())
|
||||||
|
@ -134,20 +149,20 @@ macro_rules! try_parse_one {
|
||||||
let mut ${prop}s = Vec::new();
|
let mut ${prop}s = Vec::new();
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
if input.try(|input| input.expect_ident_matching("none")).is_err() {
|
let results = input.parse_comma_separated(|i| parse_one_transition(context, i))?;
|
||||||
let results = input.parse_comma_separated(|i| parse_one_transition(context, i))?;
|
let multiple_items = results.len() >= 2;
|
||||||
for result in results {
|
for result in results {
|
||||||
% for prop in "property duration timing_function delay".split():
|
if let Some(value) = result.transition_property {
|
||||||
${prop}s.push(result.transition_${prop});
|
propertys.push(value);
|
||||||
% endfor
|
} else if multiple_items {
|
||||||
|
// If there is more than one item, and any of transitions has 'none',
|
||||||
|
// then it's invalid. Othersize, leave propertys to be empty (which
|
||||||
|
// means "transition-property: none");
|
||||||
|
return Err(StyleParseError::UnspecifiedError.into());
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// `transition: none` is a valid syntax, and we keep transition_property empty because |none| is not
|
|
||||||
// a valid TransitionProperty.
|
|
||||||
// durations, delays, and timing_functions are not allowed as empty, so before we convert them into
|
|
||||||
// longhand properties, we need to put initial values for none transition.
|
|
||||||
% for prop in "duration timing_function delay".split():
|
% for prop in "duration timing_function delay".split():
|
||||||
${prop}s.push(transition_${prop}::single_value::get_initial_specified_value());
|
${prop}s.push(result.transition_${prop});
|
||||||
% endfor
|
% endfor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,25 +175,37 @@ macro_rules! try_parse_one {
|
||||||
|
|
||||||
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
impl<'a> ToCss for LonghandsToSerialize<'a> {
|
||||||
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 {
|
||||||
let len = self.transition_property.0.len();
|
let property_len = self.transition_property.0.len();
|
||||||
// There should be at least one declared value
|
|
||||||
if len == 0 {
|
// There are two cases that we can do shorthand serialization:
|
||||||
return Ok(());
|
// * when all value lists have the same length, or
|
||||||
|
// * when transition-property is none, and other value lists have exactly one item.
|
||||||
|
if property_len == 0 {
|
||||||
|
% for name in "duration delay timing_function".split():
|
||||||
|
if self.transition_${name}.0.len() != 1 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
% endfor
|
||||||
|
} else {
|
||||||
|
% for name in "duration delay timing_function".split():
|
||||||
|
if self.transition_${name}.0.len() != property_len {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
% endfor
|
||||||
}
|
}
|
||||||
|
|
||||||
// If any value list length is differs then we don't do a shorthand serialization
|
// Representative length.
|
||||||
// either.
|
let len = self.transition_duration.0.len();
|
||||||
% for name in "property duration delay timing_function".split():
|
|
||||||
if len != self.transition_${name}.0.len() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
% endfor
|
|
||||||
|
|
||||||
for i in 0..len {
|
for i in 0..len {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
dest.write_str(", ")?;
|
dest.write_str(", ")?;
|
||||||
}
|
}
|
||||||
self.transition_property.0[i].to_css(dest)?;
|
if property_len == 0 {
|
||||||
|
dest.write_str("none")?;
|
||||||
|
} else {
|
||||||
|
self.transition_property.0[i].to_css(dest)?;
|
||||||
|
}
|
||||||
% for name in "duration timing_function delay".split():
|
% for name in "duration timing_function delay".split():
|
||||||
dest.write_str(" ")?;
|
dest.write_str(" ")?;
|
||||||
self.transition_${name}.0[i].to_css(dest)?;
|
self.transition_${name}.0[i].to_css(dest)?;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue