Skip to content
Permalink
Browse files

Auto merge of #18352 - jdm:serialize-fun, r=emilio

Make serialization match Gecko in a few corner cases

This addresses the testcases from https://bugzilla.mozilla.org/show_bug.cgi?id=1345218. Gecko differs from the specification by doing the following:
* reusing longhands that have previously been serialized in order to serialize shorthands
* immediately breaking out of the shorthand loop for the current property as soon as a shorthand is successfully serialized

w3c/csswg-drafts#1774 is filed to track ways that the standard could be made more clear on these points.

---
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix [bug 1345218](https://bugzilla.mozilla.org/show_bug.cgi?id=1345218).
- [X] There are tests for these changes

<!-- 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/18352)
<!-- Reviewable:end -->
  • Loading branch information...
bors-servo committed Sep 13, 2017
2 parents 2c576e5 + 5b83bea commit e50341d4a91beded42bdcdf37bfb8a7e53070234
@@ -657,10 +657,6 @@ impl ToCss for PropertyDeclarationBlock {

if is_system_font {
for (longhand, importance) in self.declaration_importance_iter() {
if already_serialized.contains(longhand.id()) {
continue;
}

if longhand.get_system().is_some() || longhand.is_default_line_height() {
current_longhands.push(longhand);
if found_system.is_none() {
@@ -673,10 +669,6 @@ impl ToCss for PropertyDeclarationBlock {
}
} else {
for (longhand, importance) in self.declaration_importance_iter() {
if already_serialized.contains(longhand.id()) {
continue;
}

if longhand.id().is_longhand_of(shorthand) {
current_longhands.push(longhand);
if importance.important() {
@@ -771,6 +763,13 @@ impl ToCss for PropertyDeclarationBlock {
// Substep 9
already_serialized.insert(current_longhand.id());
}

// FIXME(https://github.com/w3c/csswg-drafts/issues/1774)
// The specification does not include an instruction to abort
// the shorthand loop at this point, but doing so both matches
// Gecko and makes sense since shorthands are checked in
// preferred order.
break;
}
}

@@ -476,15 +476,28 @@ impl LonghandId {
// algorithms and what not, I guess.
<%
longhand_to_shorthand_map = {}
num_sub_properties = {}
for shorthand in data.shorthands:
num_sub_properties[shorthand.camel_case] = len(shorthand.sub_properties)
for sub_property in shorthand.sub_properties:
if sub_property.ident not in longhand_to_shorthand_map:
longhand_to_shorthand_map[sub_property.ident] = []

longhand_to_shorthand_map[sub_property.ident].append(shorthand.camel_case)

def preferred_order(x, y):
# Since we want properties in order from most subproperties to least,
# reverse the arguments to cmp from the expected order.
result = cmp(num_sub_properties.get(y, 0), num_sub_properties.get(x, 0))
if result:
return result
# Fall back to lexicographic comparison.
return cmp(x, y)

# Sort the lists of shorthand properties according to preferred order:
# https://drafts.csswg.org/cssom/#concept-shorthands-preferred-order
for shorthand_list in longhand_to_shorthand_map.itervalues():
shorthand_list.sort()
shorthand_list.sort(cmp=preferred_order)
%>

// based on lookup results for each longhand, create result arrays
@@ -341,6 +341,53 @@ mod shorthand_serialization {
mod border_shorthands {
use super::*;

#[test]
fn border_top_and_color() {
let mut properties = Vec::new();
properties.push(PropertyDeclaration::BorderTopWidth(BorderSideWidth::Length(Length::from_px(1.))));
properties.push(PropertyDeclaration::BorderTopStyle(BorderStyle::solid));
let c = Color::Numeric {
parsed: RGBA::new(255, 0, 0, 255),
authored: Some("green".to_string().into_boxed_str())
};
properties.push(PropertyDeclaration::BorderTopColor(c));
let c = Color::Numeric {
parsed: RGBA::new(0, 255, 0, 255),
authored: Some("red".to_string().into_boxed_str())
};
properties.push(PropertyDeclaration::BorderTopColor(c.clone()));
properties.push(PropertyDeclaration::BorderBottomColor(c.clone()));
properties.push(PropertyDeclaration::BorderLeftColor(c.clone()));
properties.push(PropertyDeclaration::BorderRightColor(c.clone()));

let serialization = shorthand_properties_to_string(properties);
assert_eq!(serialization, "border-top: 1px solid red; border-color: red;");
}

#[test]
fn border_color_and_top() {
let mut properties = Vec::new();
let c = Color::Numeric {
parsed: RGBA::new(0, 255, 0, 255),
authored: Some("red".to_string().into_boxed_str())
};
properties.push(PropertyDeclaration::BorderTopColor(c.clone()));
properties.push(PropertyDeclaration::BorderBottomColor(c.clone()));
properties.push(PropertyDeclaration::BorderLeftColor(c.clone()));
properties.push(PropertyDeclaration::BorderRightColor(c.clone()));

properties.push(PropertyDeclaration::BorderTopWidth(BorderSideWidth::Length(Length::from_px(1.))));
properties.push(PropertyDeclaration::BorderTopStyle(BorderStyle::solid));
let c = Color::Numeric {
parsed: RGBA::new(255, 0, 0, 255),
authored: Some("green".to_string().into_boxed_str())
};
properties.push(PropertyDeclaration::BorderTopColor(c));

let serialization = shorthand_properties_to_string(properties);
assert_eq!(serialization, "border-color: green red red; border-top: 1px solid green;");
}

// we can use border-top as a base to test out the different combinations
// but afterwards, we only need to to one test per "directional border shorthand"

0 comments on commit e50341d

Please sign in to comment.
You can’t perform that action at this time.