mirror of
https://github.com/servo/servo.git
synced 2025-08-05 05:30:08 +01:00
Auto merge of #16135 - emilio:shorthand-reference-variable, r=upsuper
Shorthand with variable reference should not have extra whitespace after colon for serialization. This is https://github.com/servo/servo/pull/15422 + a manifest update. Fixes #15295. <!-- 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/16135) <!-- Reviewable:end -->
This commit is contained in:
commit
3a3f258f33
4 changed files with 136 additions and 56 deletions
|
@ -333,7 +333,9 @@ impl PropertyDeclarationBlock {
|
||||||
}
|
}
|
||||||
let iter = self.declarations.iter().map(get_declaration as fn(_) -> _);
|
let iter = self.declarations.iter().map(get_declaration as fn(_) -> _);
|
||||||
match shorthand.get_shorthand_appendable_value(iter) {
|
match shorthand.get_shorthand_appendable_value(iter) {
|
||||||
Some(AppendableValue::Css(css)) => dest.write_str(css),
|
Some(AppendableValue::Css { css, .. }) => {
|
||||||
|
dest.write_str(css)
|
||||||
|
},
|
||||||
Some(AppendableValue::DeclarationsForShorthand(_, decls)) => {
|
Some(AppendableValue::DeclarationsForShorthand(_, decls)) => {
|
||||||
shorthand.longhands_to_css(decls, dest)
|
shorthand.longhands_to_css(decls, dest)
|
||||||
}
|
}
|
||||||
|
@ -409,11 +411,13 @@ impl ToCss for PropertyDeclarationBlock {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Substep 1
|
// Substep 1:
|
||||||
/* Assuming that the PropertyDeclarationBlock contains no duplicate entries,
|
//
|
||||||
if the current_longhands length is equal to the properties length, it means
|
// Assuming that the PropertyDeclarationBlock contains no
|
||||||
that the properties that map to shorthand are present in longhands */
|
// duplicate entries, if the current_longhands length is
|
||||||
if current_longhands.is_empty() || current_longhands.len() != properties.len() {
|
// equal to the properties length, it means that the
|
||||||
|
// properties that map to shorthand are present in longhands
|
||||||
|
if current_longhands.len() != properties.len() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,36 +432,58 @@ impl ToCss for PropertyDeclarationBlock {
|
||||||
Importance::Normal
|
Importance::Normal
|
||||||
};
|
};
|
||||||
|
|
||||||
// Substep 5 - Let value be the result of invoking serialize a CSS
|
// Substep 5 - Let value be the result of invoking serialize
|
||||||
// value of current longhands.
|
// a CSS value of current longhands.
|
||||||
let mut value = String::new();
|
let appendable_value =
|
||||||
match shorthand.get_shorthand_appendable_value(current_longhands.iter().cloned()) {
|
match shorthand.get_shorthand_appendable_value(current_longhands.iter().cloned()) {
|
||||||
None => continue,
|
None => continue,
|
||||||
Some(appendable_value) => {
|
Some(appendable_value) => appendable_value,
|
||||||
try!(append_declaration_value(&mut value, appendable_value));
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Substep 6
|
// We avoid re-serializing if we're already an
|
||||||
if value.is_empty() {
|
// AppendableValue::Css.
|
||||||
continue
|
let mut value = String::new();
|
||||||
}
|
let value = match appendable_value {
|
||||||
|
AppendableValue::Css { css, with_variables } => {
|
||||||
|
debug_assert!(!css.is_empty());
|
||||||
|
AppendableValue::Css {
|
||||||
|
css: css,
|
||||||
|
with_variables: with_variables,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
other @ _ => {
|
||||||
|
append_declaration_value(&mut value, other)?;
|
||||||
|
|
||||||
|
// Substep 6
|
||||||
|
if value.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppendableValue::Css {
|
||||||
|
css: &value,
|
||||||
|
with_variables: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Substeps 7 and 8
|
// Substeps 7 and 8
|
||||||
try!(append_serialization::<W, Cloned<slice::Iter< _>>, _>(
|
append_serialization::<_, Cloned<slice::Iter< _>>, _>(
|
||||||
dest, &shorthand, AppendableValue::Css(&value), importance,
|
dest,
|
||||||
&mut is_first_serialization));
|
&shorthand,
|
||||||
|
value,
|
||||||
|
importance,
|
||||||
|
&mut is_first_serialization)?;
|
||||||
|
|
||||||
for current_longhand in current_longhands {
|
for current_longhand in ¤t_longhands {
|
||||||
// Substep 9
|
// Substep 9
|
||||||
already_serialized.push(current_longhand.id());
|
already_serialized.push(current_longhand.id());
|
||||||
let index_to_remove = longhands.iter().position(|l| l.0 == *current_longhand);
|
let index_to_remove = longhands.iter().position(|l| l.0 == **current_longhand);
|
||||||
if let Some(index) = index_to_remove {
|
if let Some(index) = index_to_remove {
|
||||||
// Substep 10
|
// Substep 10
|
||||||
longhands.remove(index);
|
longhands.remove(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3.3.4
|
// Step 3.3.4
|
||||||
|
@ -473,12 +499,12 @@ impl ToCss for PropertyDeclarationBlock {
|
||||||
// "error: unable to infer enough type information about `_`;
|
// "error: unable to infer enough type information about `_`;
|
||||||
// type annotations or generic parameter binding required [E0282]"
|
// type annotations or generic parameter binding required [E0282]"
|
||||||
// Use the same type as earlier call to reuse generated code.
|
// Use the same type as earlier call to reuse generated code.
|
||||||
try!(append_serialization::<W, Cloned<slice::Iter< &PropertyDeclaration>>, _>(
|
append_serialization::<_, Cloned<slice::Iter<_>>, _>(
|
||||||
dest,
|
dest,
|
||||||
&property,
|
&property,
|
||||||
AppendableValue::Declaration(declaration),
|
AppendableValue::Declaration(declaration),
|
||||||
importance,
|
importance,
|
||||||
&mut is_first_serialization));
|
&mut is_first_serialization)?;
|
||||||
|
|
||||||
// Step 3.3.8
|
// Step 3.3.8
|
||||||
already_serialized.push(property);
|
already_serialized.push(property);
|
||||||
|
@ -503,7 +529,12 @@ pub enum AppendableValue<'a, I>
|
||||||
DeclarationsForShorthand(ShorthandId, I),
|
DeclarationsForShorthand(ShorthandId, I),
|
||||||
/// A raw CSS string, coming for example from a property with CSS variables,
|
/// A raw CSS string, coming for example from a property with CSS variables,
|
||||||
/// or when storing a serialized shorthand value before appending directly.
|
/// or when storing a serialized shorthand value before appending directly.
|
||||||
Css(&'a str)
|
Css {
|
||||||
|
/// The raw CSS string.
|
||||||
|
css: &'a str,
|
||||||
|
/// Whether the original serialization contained variables or not.
|
||||||
|
with_variables: bool,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Potentially appends whitespace after the first (property: value;) pair.
|
/// Potentially appends whitespace after the first (property: value;) pair.
|
||||||
|
@ -513,12 +544,11 @@ fn handle_first_serialization<W>(dest: &mut W,
|
||||||
where W: fmt::Write,
|
where W: fmt::Write,
|
||||||
{
|
{
|
||||||
if !*is_first_serialization {
|
if !*is_first_serialization {
|
||||||
try!(write!(dest, " "));
|
dest.write_str(" ")
|
||||||
} else {
|
} else {
|
||||||
*is_first_serialization = false;
|
*is_first_serialization = false;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Append a given kind of appendable value to a serialization.
|
/// Append a given kind of appendable value to a serialization.
|
||||||
|
@ -529,18 +559,16 @@ pub fn append_declaration_value<'a, W, I>(dest: &mut W,
|
||||||
I: Iterator<Item=&'a PropertyDeclaration>,
|
I: Iterator<Item=&'a PropertyDeclaration>,
|
||||||
{
|
{
|
||||||
match appendable_value {
|
match appendable_value {
|
||||||
AppendableValue::Css(css) => {
|
AppendableValue::Css { css, .. } => {
|
||||||
try!(write!(dest, "{}", css))
|
dest.write_str(css)
|
||||||
},
|
},
|
||||||
AppendableValue::Declaration(decl) => {
|
AppendableValue::Declaration(decl) => {
|
||||||
try!(decl.to_css(dest));
|
decl.to_css(dest)
|
||||||
},
|
},
|
||||||
AppendableValue::DeclarationsForShorthand(shorthand, decls) => {
|
AppendableValue::DeclarationsForShorthand(shorthand, decls) => {
|
||||||
try!(shorthand.longhands_to_css(decls, dest));
|
shorthand.longhands_to_css(decls, dest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Append a given property and value pair to a serialization.
|
/// Append a given property and value pair to a serialization.
|
||||||
|
@ -560,28 +588,30 @@ pub fn append_serialization<'a, W, I, N>(dest: &mut W,
|
||||||
try!(dest.write_char(':'));
|
try!(dest.write_char(':'));
|
||||||
|
|
||||||
// for normal parsed values, add a space between key: and value
|
// for normal parsed values, add a space between key: and value
|
||||||
match &appendable_value {
|
match appendable_value {
|
||||||
&AppendableValue::Css(_) => {
|
AppendableValue::Declaration(decl) => {
|
||||||
try!(write!(dest, " "))
|
|
||||||
},
|
|
||||||
&AppendableValue::Declaration(decl) => {
|
|
||||||
if !decl.value_is_unparsed() {
|
if !decl.value_is_unparsed() {
|
||||||
// for normal parsed values, add a space between key: and value
|
// For normal parsed values, add a space between key: and value.
|
||||||
try!(write!(dest, " "));
|
dest.write_str(" ")?
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
AppendableValue::Css { with_variables, .. } => {
|
||||||
|
if !with_variables {
|
||||||
|
dest.write_str(" ")?
|
||||||
|
}
|
||||||
|
}
|
||||||
// Currently append_serialization is only called with a Css or
|
// Currently append_serialization is only called with a Css or
|
||||||
// a Declaration AppendableValue.
|
// a Declaration AppendableValue.
|
||||||
&AppendableValue::DeclarationsForShorthand(..) => unreachable!()
|
AppendableValue::DeclarationsForShorthand(..) => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
try!(append_declaration_value(dest, appendable_value));
|
try!(append_declaration_value(dest, appendable_value));
|
||||||
|
|
||||||
if importance.important() {
|
if importance.important() {
|
||||||
try!(write!(dest, " !important"));
|
try!(dest.write_str(" !important"));
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(dest, ";")
|
dest.write_char(';')
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A helper to parse the style attribute of an element, in order for this to be
|
/// A helper to parse the style attribute of an element, in order for this to be
|
||||||
|
|
|
@ -561,8 +561,8 @@ impl ShorthandId {
|
||||||
///
|
///
|
||||||
/// Returns the optional appendable value.
|
/// Returns the optional appendable value.
|
||||||
pub fn get_shorthand_appendable_value<'a, I>(self,
|
pub fn get_shorthand_appendable_value<'a, I>(self,
|
||||||
declarations: I)
|
declarations: I)
|
||||||
-> Option<AppendableValue<'a, I::IntoIter>>
|
-> Option<AppendableValue<'a, I::IntoIter>>
|
||||||
where I: IntoIterator<Item=&'a PropertyDeclaration>,
|
where I: IntoIterator<Item=&'a PropertyDeclaration>,
|
||||||
I::IntoIter: Clone,
|
I::IntoIter: Clone,
|
||||||
{
|
{
|
||||||
|
@ -580,15 +580,21 @@ impl ShorthandId {
|
||||||
// https://drafts.csswg.org/css-variables/#variables-in-shorthands
|
// https://drafts.csswg.org/css-variables/#variables-in-shorthands
|
||||||
if let Some(css) = first_declaration.with_variables_from_shorthand(self) {
|
if let Some(css) = first_declaration.with_variables_from_shorthand(self) {
|
||||||
if declarations2.all(|d| d.with_variables_from_shorthand(self) == Some(css)) {
|
if declarations2.all(|d| d.with_variables_from_shorthand(self) == Some(css)) {
|
||||||
return Some(AppendableValue::Css(css));
|
return Some(AppendableValue::Css {
|
||||||
}
|
css: css,
|
||||||
return None;
|
with_variables: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether they are all the same CSS-wide keyword.
|
// Check whether they are all the same CSS-wide keyword.
|
||||||
if let Some(keyword) = first_declaration.get_css_wide_keyword() {
|
if let Some(keyword) = first_declaration.get_css_wide_keyword() {
|
||||||
if declarations2.all(|d| d.get_css_wide_keyword() == Some(keyword)) {
|
if declarations2.all(|d| d.get_css_wide_keyword() == Some(keyword)) {
|
||||||
return Some(AppendableValue::Css(keyword.to_str()));
|
return Some(AppendableValue::Css {
|
||||||
|
css: keyword.to_str(),
|
||||||
|
with_variables: false,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -1191,10 +1197,10 @@ impl PropertyDeclaration {
|
||||||
/// the longhand declarations.
|
/// the longhand declarations.
|
||||||
pub fn may_serialize_as_part_of_shorthand(&self) -> bool {
|
pub fn may_serialize_as_part_of_shorthand(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
PropertyDeclaration::CSSWideKeyword(..) => false,
|
PropertyDeclaration::CSSWideKeyword(..) |
|
||||||
PropertyDeclaration::WithVariables(..) => false,
|
PropertyDeclaration::WithVariables(..) => false,
|
||||||
PropertyDeclaration::Custom(..) =>
|
PropertyDeclaration::Custom(..) =>
|
||||||
unreachable!("Serialize a custom property as part of shorthand?"),
|
unreachable!("Serializing a custom property as part of shorthand?"),
|
||||||
_ => true,
|
_ => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83640,6 +83640,12 @@
|
||||||
{}
|
{}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"cssom/serialize-variable-reference.html": [
|
||||||
|
[
|
||||||
|
"/cssom/serialize-variable-reference.html",
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
"cssom/shorthand-serialization.html": [
|
"cssom/shorthand-serialization.html": [
|
||||||
[
|
[
|
||||||
"/cssom/shorthand-serialization.html",
|
"/cssom/shorthand-serialization.html",
|
||||||
|
@ -159941,6 +159947,10 @@
|
||||||
"329fe02cb9e54b1a24a8f9dedcfcf5c0f61c7f24",
|
"329fe02cb9e54b1a24a8f9dedcfcf5c0f61c7f24",
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
|
"cssom/serialize-variable-reference.html": [
|
||||||
|
"5e83f084efc82184c3052a40bb4a061fd4a1336f",
|
||||||
|
"testharness"
|
||||||
|
],
|
||||||
"cssom/shorthand-serialization.html": [
|
"cssom/shorthand-serialization.html": [
|
||||||
"bd514834dbd48c267c16a4329af6fec7f6cbc081",
|
"bd514834dbd48c267c16a4329af6fec7f6cbc081",
|
||||||
"testharness"
|
"testharness"
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>CSSOM - Serialization with variable preserves original serialization.</title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<div id="longhand-whitespace" style="font-size: var(--a);"></div>
|
||||||
|
<div id="shorthand-whitespace" style="font: var(--a);"></div>
|
||||||
|
<div id="longhand" style="font-size:var(--a);"></div>
|
||||||
|
<div id="shorthand" style="font:var(--a);"></div>
|
||||||
|
<script>
|
||||||
|
test(function() {
|
||||||
|
var elem = document.getElementById('longhand-whitespace');
|
||||||
|
|
||||||
|
assert_equals(elem.style.cssText, 'font-size: var(--a);');
|
||||||
|
}, 'Longhand with variable preserves original serialization: with withespace')
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var elem = document.getElementById('shorthand-whitespace');
|
||||||
|
|
||||||
|
assert_equals(elem.style.cssText, 'font: var(--a);');
|
||||||
|
}, 'Shorthand with variable preserves original serialization: with withespace')
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var elem = document.getElementById('longhand');
|
||||||
|
|
||||||
|
assert_equals(elem.style.cssText, 'font-size:var(--a);');
|
||||||
|
}, 'Longhand with variable preserves original serialization: without withespace')
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var elem = document.getElementById('shorthand');
|
||||||
|
|
||||||
|
assert_equals(elem.style.cssText, 'font:var(--a);');
|
||||||
|
}, 'Shorthand with variable preserves original serialization: without withespace')
|
||||||
|
</script>
|
Loading…
Add table
Add a link
Reference in a new issue