mirror of
https://github.com/servo/servo.git
synced 2025-08-16 10:55:34 +01:00
Auto merge of #12943 - servo:merged-declaration-block, r=emilio
Merge normal and important declarations in style rules Have a single Vec instead of two. Fix #3426 --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #3426. <!-- Either: --> - [x] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- 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/12943) <!-- Reviewable:end -->
This commit is contained in:
commit
f8b2be1ea4
24 changed files with 1022 additions and 356 deletions
|
@ -23,6 +23,7 @@ mod logical_geometry;
|
|||
mod media_queries;
|
||||
mod parsing;
|
||||
mod properties;
|
||||
mod selector_matching;
|
||||
mod str;
|
||||
mod stylesheets;
|
||||
mod value;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
pub use cssparser::ToCss;
|
||||
pub use std::sync::Arc;
|
||||
pub use style::computed_values::display::T::inline_block;
|
||||
pub use style::properties::{DeclaredValue, PropertyDeclaration, PropertyDeclarationBlock};
|
||||
pub use style::properties::{DeclaredValue, PropertyDeclaration, PropertyDeclarationBlock, Importance};
|
||||
pub use style::values::specified::{BorderStyle, CSSColor, Length};
|
||||
pub use style::values::specified::{LengthOrPercentage, LengthOrPercentageOrAuto, LengthOrPercentageOrAutoOrContent};
|
||||
pub use style::properties::longhands::outline_color::computed_value::T as ComputedColor;
|
||||
|
@ -18,39 +18,45 @@ fn property_declaration_block_should_serialize_correctly() {
|
|||
use style::properties::longhands::overflow_x::computed_value::T as OverflowXValue;
|
||||
use style::properties::longhands::overflow_y::computed_value::T as OverflowYContainer;
|
||||
|
||||
let mut normal = Vec::new();
|
||||
let mut important = Vec::new();
|
||||
let declarations = vec![
|
||||
(PropertyDeclaration::Width(
|
||||
DeclaredValue::Value(LengthOrPercentageOrAuto::Length(Length::from_px(70f32)))),
|
||||
Importance::Normal),
|
||||
|
||||
let length = DeclaredValue::Value(LengthOrPercentageOrAuto::Length(Length::from_px(70f32)));
|
||||
normal.push(PropertyDeclaration::Width(length));
|
||||
(PropertyDeclaration::MinHeight(
|
||||
DeclaredValue::Value(LengthOrPercentage::Length(Length::from_px(20f32)))),
|
||||
Importance::Normal),
|
||||
|
||||
let min_height = DeclaredValue::Value(LengthOrPercentage::Length(Length::from_px(20f32)));
|
||||
normal.push(PropertyDeclaration::MinHeight(min_height));
|
||||
(PropertyDeclaration::Height(
|
||||
DeclaredValue::Value(LengthOrPercentageOrAuto::Length(Length::from_px(20f32)))),
|
||||
Importance::Important),
|
||||
|
||||
let value = DeclaredValue::Value(inline_block);
|
||||
normal.push(PropertyDeclaration::Display(value));
|
||||
(PropertyDeclaration::Display(
|
||||
DeclaredValue::Value(inline_block)),
|
||||
Importance::Normal),
|
||||
|
||||
let overflow_x = DeclaredValue::Value(OverflowXValue::auto);
|
||||
normal.push(PropertyDeclaration::OverflowX(overflow_x));
|
||||
(PropertyDeclaration::OverflowX(
|
||||
DeclaredValue::Value(OverflowXValue::auto)),
|
||||
Importance::Normal),
|
||||
|
||||
let overflow_y = DeclaredValue::Value(OverflowYContainer(OverflowXValue::auto));
|
||||
normal.push(PropertyDeclaration::OverflowY(overflow_y));
|
||||
(PropertyDeclaration::OverflowY(
|
||||
DeclaredValue::Value(OverflowYContainer(OverflowXValue::auto))),
|
||||
Importance::Normal),
|
||||
];
|
||||
|
||||
let height = DeclaredValue::Value(LengthOrPercentageOrAuto::Length(Length::from_px(20f32)));
|
||||
important.push(PropertyDeclaration::Height(height));
|
||||
|
||||
normal.reverse();
|
||||
important.reverse();
|
||||
let block = PropertyDeclarationBlock {
|
||||
normal: Arc::new(normal),
|
||||
important: Arc::new(important)
|
||||
declarations: Arc::new(declarations),
|
||||
|
||||
// Incorrect, but not used here:
|
||||
normal_count: 0,
|
||||
important_count: 0,
|
||||
};
|
||||
|
||||
let css_string = block.to_css_string();
|
||||
|
||||
assert_eq!(
|
||||
css_string,
|
||||
"width: 70px; min-height: 20px; display: inline-block; overflow: auto; height: 20px !important;"
|
||||
"width: 70px; min-height: 20px; height: 20px !important; display: inline-block; overflow: auto;"
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -59,8 +65,11 @@ mod shorthand_serialization {
|
|||
|
||||
pub fn shorthand_properties_to_string(properties: Vec<PropertyDeclaration>) -> String {
|
||||
let block = PropertyDeclarationBlock {
|
||||
normal: Arc::new(properties),
|
||||
important: Arc::new(Vec::new())
|
||||
declarations: Arc::new(properties.into_iter().map(|d| (d, Importance::Normal)).collect()),
|
||||
|
||||
// Incorrect, but not used here:
|
||||
normal_count: 0,
|
||||
important_count: 0,
|
||||
};
|
||||
|
||||
block.to_css_string()
|
||||
|
|
103
tests/unit/style/selector_matching.rs
Normal file
103
tests/unit/style/selector_matching.rs
Normal file
|
@ -0,0 +1,103 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
|
||||
use cssparser::Parser;
|
||||
use selectors::parser::{LocalName, ParserContext, parse_selector_list};
|
||||
use std::sync::Arc;
|
||||
use string_cache::Atom;
|
||||
use style::properties::Importance;
|
||||
use style::selector_matching::{DeclarationBlock, Rule, SelectorMap};
|
||||
|
||||
/// Helper method to get some Rules from selector strings.
|
||||
/// Each sublist of the result contains the Rules for one StyleRule.
|
||||
fn get_mock_rules(css_selectors: &[&str]) -> Vec<Vec<Rule>> {
|
||||
css_selectors.iter().enumerate().map(|(i, selectors)| {
|
||||
let context = ParserContext::new();
|
||||
parse_selector_list(&context, &mut Parser::new(*selectors))
|
||||
.unwrap().into_iter().map(|s| {
|
||||
Rule {
|
||||
selector: s.complex_selector.clone(),
|
||||
declarations: DeclarationBlock {
|
||||
mixed_declarations: Arc::new(Vec::new()),
|
||||
importance: Importance::Normal,
|
||||
specificity: s.specificity,
|
||||
source_order: i,
|
||||
}
|
||||
}
|
||||
}).collect()
|
||||
}).collect()
|
||||
}
|
||||
|
||||
fn get_mock_map(selectors: &[&str]) -> SelectorMap {
|
||||
let mut map = SelectorMap::new();
|
||||
let selector_rules = get_mock_rules(selectors);
|
||||
|
||||
for rules in selector_rules.into_iter() {
|
||||
for rule in rules.into_iter() {
|
||||
map.insert(rule)
|
||||
}
|
||||
}
|
||||
|
||||
map
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rule_ordering_same_specificity() {
|
||||
let rules_list = get_mock_rules(&["a.intro", "img.sidebar"]);
|
||||
let a = &rules_list[0][0].declarations;
|
||||
let b = &rules_list[1][0].declarations;
|
||||
assert!((a.specificity, a.source_order) < ((b.specificity, b.source_order)),
|
||||
"The rule that comes later should win.");
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_get_id_name() {
|
||||
let rules_list = get_mock_rules(&[".intro", "#top"]);
|
||||
assert_eq!(SelectorMap::get_id_name(&rules_list[0][0]), None);
|
||||
assert_eq!(SelectorMap::get_id_name(&rules_list[1][0]), Some(Atom::from("top")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_class_name() {
|
||||
let rules_list = get_mock_rules(&[".intro.foo", "#top"]);
|
||||
assert_eq!(SelectorMap::get_class_name(&rules_list[0][0]), Some(Atom::from("intro")));
|
||||
assert_eq!(SelectorMap::get_class_name(&rules_list[1][0]), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_local_name() {
|
||||
let rules_list = get_mock_rules(&["img.foo", "#top", "IMG", "ImG"]);
|
||||
let check = |i: usize, names: Option<(&str, &str)>| {
|
||||
assert!(SelectorMap::get_local_name(&rules_list[i][0])
|
||||
== names.map(|(name, lower_name)| LocalName {
|
||||
name: Atom::from(name),
|
||||
lower_name: Atom::from(lower_name) }))
|
||||
};
|
||||
check(0, Some(("img", "img")));
|
||||
check(1, None);
|
||||
check(2, Some(("IMG", "img")));
|
||||
check(3, Some(("ImG", "img")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_insert() {
|
||||
let rules_list = get_mock_rules(&[".intro.foo", "#top"]);
|
||||
let mut selector_map = SelectorMap::new();
|
||||
selector_map.insert(rules_list[1][0].clone());
|
||||
assert_eq!(1, selector_map.id_hash.get(&atom!("top")).unwrap()[0].declarations.source_order);
|
||||
selector_map.insert(rules_list[0][0].clone());
|
||||
assert_eq!(0, selector_map.class_hash.get(&Atom::from("intro")).unwrap()[0].declarations.source_order);
|
||||
assert!(selector_map.class_hash.get(&Atom::from("foo")).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_universal_rules() {
|
||||
let map = get_mock_map(&["*|*", "#foo > *|*", ".klass", "#id"]);
|
||||
let mut decls = vec![];
|
||||
|
||||
map.get_universal_rules(&mut decls);
|
||||
|
||||
assert_eq!(decls.len(), 1);
|
||||
}
|
|
@ -13,6 +13,8 @@ use style::error_reporting::ParseErrorReporter;
|
|||
use style::keyframes::{Keyframe, KeyframeSelector, KeyframePercentage};
|
||||
use style::parser::ParserContextExtraData;
|
||||
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, DeclaredValue, longhands};
|
||||
use style::properties::Importance;
|
||||
use style::properties::longhands::animation_play_state;
|
||||
use style::stylesheets::{Stylesheet, CSSRule, StyleRule, KeyframesRule, Origin};
|
||||
use style::values::specified::{LengthOrPercentageOrAuto, Percentage};
|
||||
use url::Url;
|
||||
|
@ -22,17 +24,42 @@ fn test_parse_stylesheet() {
|
|||
let css = r"
|
||||
@namespace url(http://www.w3.org/1999/xhtml);
|
||||
/* FIXME: only if scripting is enabled */
|
||||
input[type=hidden i] { display: none !important; }
|
||||
html , body /**/ { display: block; }
|
||||
input[type=hidden i] {
|
||||
display: block !important;
|
||||
display: none !important;
|
||||
display: inline;
|
||||
--a: b !important;
|
||||
--a: inherit !important;
|
||||
--a: c;
|
||||
}
|
||||
html , body /**/ {
|
||||
display: none;
|
||||
display: block;
|
||||
}
|
||||
#d1 > .ok { background: blue; }
|
||||
@keyframes foo {
|
||||
from { width: 0% }
|
||||
to { width: 100%}
|
||||
to {
|
||||
width: 100%;
|
||||
width: 50% !important; /* !important not allowed here */
|
||||
animation-name: 'foo'; /* animation properties not allowed here */
|
||||
animation-play-state: running; /* … except animation-play-state */
|
||||
}
|
||||
}";
|
||||
let url = Url::parse("about::test").unwrap();
|
||||
let stylesheet = Stylesheet::from_str(css, url, Origin::UserAgent,
|
||||
Box::new(CSSErrorReporterTest),
|
||||
ParserContextExtraData::default());
|
||||
macro_rules! assert_eq {
|
||||
($left: expr, $right: expr) => {
|
||||
let left = $left;
|
||||
let right = $right;
|
||||
if left != right {
|
||||
panic!("{:#?} != {:#?}", left, right)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(stylesheet, Stylesheet {
|
||||
origin: Origin::UserAgent,
|
||||
media: None,
|
||||
|
@ -71,11 +98,15 @@ fn test_parse_stylesheet() {
|
|||
},
|
||||
],
|
||||
declarations: PropertyDeclarationBlock {
|
||||
normal: Arc::new(vec![]),
|
||||
important: Arc::new(vec![
|
||||
PropertyDeclaration::Display(DeclaredValue::Value(
|
||||
declarations: Arc::new(vec![
|
||||
(PropertyDeclaration::Display(DeclaredValue::Value(
|
||||
longhands::display::SpecifiedValue::none)),
|
||||
Importance::Important),
|
||||
(PropertyDeclaration::Custom(Atom::from("a"), DeclaredValue::Inherit),
|
||||
Importance::Important),
|
||||
]),
|
||||
normal_count: 0,
|
||||
important_count: 2,
|
||||
},
|
||||
}),
|
||||
CSSRule::Style(StyleRule {
|
||||
|
@ -116,11 +147,13 @@ fn test_parse_stylesheet() {
|
|||
},
|
||||
],
|
||||
declarations: PropertyDeclarationBlock {
|
||||
normal: Arc::new(vec![
|
||||
PropertyDeclaration::Display(DeclaredValue::Value(
|
||||
declarations: Arc::new(vec![
|
||||
(PropertyDeclaration::Display(DeclaredValue::Value(
|
||||
longhands::display::SpecifiedValue::block)),
|
||||
Importance::Normal),
|
||||
]),
|
||||
important: Arc::new(vec![]),
|
||||
normal_count: 1,
|
||||
important_count: 0,
|
||||
},
|
||||
}),
|
||||
CSSRule::Style(StyleRule {
|
||||
|
@ -150,24 +183,33 @@ fn test_parse_stylesheet() {
|
|||
},
|
||||
],
|
||||
declarations: PropertyDeclarationBlock {
|
||||
normal: Arc::new(vec![
|
||||
PropertyDeclaration::BackgroundClip(DeclaredValue::Initial),
|
||||
PropertyDeclaration::BackgroundOrigin(DeclaredValue::Initial),
|
||||
PropertyDeclaration::BackgroundSize(DeclaredValue::Initial),
|
||||
PropertyDeclaration::BackgroundImage(DeclaredValue::Initial),
|
||||
PropertyDeclaration::BackgroundAttachment(DeclaredValue::Initial),
|
||||
PropertyDeclaration::BackgroundRepeat(DeclaredValue::Initial),
|
||||
PropertyDeclaration::BackgroundPosition(DeclaredValue::Initial),
|
||||
PropertyDeclaration::BackgroundColor(DeclaredValue::Value(
|
||||
declarations: Arc::new(vec![
|
||||
(PropertyDeclaration::BackgroundColor(DeclaredValue::Value(
|
||||
longhands::background_color::SpecifiedValue {
|
||||
authored: Some("blue".to_owned()),
|
||||
parsed: cssparser::Color::RGBA(cssparser::RGBA {
|
||||
red: 0., green: 0., blue: 1., alpha: 1.
|
||||
}),
|
||||
}
|
||||
)),
|
||||
)),
|
||||
Importance::Normal),
|
||||
(PropertyDeclaration::BackgroundPosition(DeclaredValue::Initial),
|
||||
Importance::Normal),
|
||||
(PropertyDeclaration::BackgroundRepeat(DeclaredValue::Initial),
|
||||
Importance::Normal),
|
||||
(PropertyDeclaration::BackgroundAttachment(DeclaredValue::Initial),
|
||||
Importance::Normal),
|
||||
(PropertyDeclaration::BackgroundImage(DeclaredValue::Initial),
|
||||
Importance::Normal),
|
||||
(PropertyDeclaration::BackgroundSize(DeclaredValue::Initial),
|
||||
Importance::Normal),
|
||||
(PropertyDeclaration::BackgroundOrigin(DeclaredValue::Initial),
|
||||
Importance::Normal),
|
||||
(PropertyDeclaration::BackgroundClip(DeclaredValue::Initial),
|
||||
Importance::Normal),
|
||||
]),
|
||||
important: Arc::new(vec![]),
|
||||
normal_count: 8,
|
||||
important_count: 0,
|
||||
},
|
||||
}),
|
||||
CSSRule::Keyframes(KeyframesRule {
|
||||
|
@ -177,16 +219,22 @@ fn test_parse_stylesheet() {
|
|||
selector: KeyframeSelector::new_for_unit_testing(
|
||||
vec![KeyframePercentage::new(0.)]),
|
||||
declarations: Arc::new(vec![
|
||||
PropertyDeclaration::Width(DeclaredValue::Value(
|
||||
(PropertyDeclaration::Width(DeclaredValue::Value(
|
||||
LengthOrPercentageOrAuto::Percentage(Percentage(0.)))),
|
||||
Importance::Normal),
|
||||
]),
|
||||
},
|
||||
Keyframe {
|
||||
selector: KeyframeSelector::new_for_unit_testing(
|
||||
vec![KeyframePercentage::new(1.)]),
|
||||
declarations: Arc::new(vec![
|
||||
PropertyDeclaration::Width(DeclaredValue::Value(
|
||||
(PropertyDeclaration::Width(DeclaredValue::Value(
|
||||
LengthOrPercentageOrAuto::Percentage(Percentage(1.)))),
|
||||
Importance::Normal),
|
||||
(PropertyDeclaration::AnimationPlayState(DeclaredValue::Value(
|
||||
animation_play_state::SpecifiedValue(
|
||||
vec![animation_play_state::SingleSpecifiedValue::running]))),
|
||||
Importance::Normal),
|
||||
]),
|
||||
},
|
||||
]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue