mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Only cascade at a priority level rules that have declarations of that priority.
This commit is contained in:
parent
16bbc2f26e
commit
a175c9981e
6 changed files with 99 additions and 36 deletions
|
@ -767,6 +767,7 @@ impl Element {
|
||||||
.position(|&(ref decl, _)| decl.matches(property));
|
.position(|&(ref decl, _)| decl.matches(property));
|
||||||
if let Some(index) = index {
|
if let Some(index) = index {
|
||||||
Arc::make_mut(&mut declarations.declarations).remove(index);
|
Arc::make_mut(&mut declarations.declarations).remove(index);
|
||||||
|
declarations.recalc_any();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -781,26 +782,30 @@ impl Element {
|
||||||
fn update(element: &Element, declarations: Vec<PropertyDeclaration>,
|
fn update(element: &Element, declarations: Vec<PropertyDeclaration>,
|
||||||
importance: Importance) {
|
importance: Importance) {
|
||||||
let mut inline_declarations = element.style_attribute().borrow_mut();
|
let mut inline_declarations = element.style_attribute().borrow_mut();
|
||||||
if let &mut Some(ref mut existing_declarations) = &mut *inline_declarations {
|
if let &mut Some(ref mut declaration_block) = &mut *inline_declarations {
|
||||||
// Usually, the reference count will be 1 here. But transitions could make it greater
|
{
|
||||||
// than that.
|
// Usually, the reference count will be 1 here. But transitions could make it greater
|
||||||
let existing_declarations = Arc::make_mut(&mut existing_declarations.declarations);
|
// than that.
|
||||||
|
let existing_declarations = Arc::make_mut(&mut declaration_block.declarations);
|
||||||
|
|
||||||
'outer: for incoming_declaration in declarations {
|
'outer: for incoming_declaration in declarations {
|
||||||
for existing_declaration in &mut *existing_declarations {
|
for existing_declaration in &mut *existing_declarations {
|
||||||
if existing_declaration.0.name() == incoming_declaration.name() {
|
if existing_declaration.0.name() == incoming_declaration.name() {
|
||||||
*existing_declaration = (incoming_declaration, importance);
|
*existing_declaration = (incoming_declaration, importance);
|
||||||
continue 'outer;
|
continue 'outer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
existing_declarations.push((incoming_declaration, importance));
|
||||||
}
|
}
|
||||||
existing_declarations.push((incoming_declaration, importance));
|
|
||||||
}
|
}
|
||||||
|
declaration_block.recalc_any();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
*inline_declarations = Some(PropertyDeclarationBlock {
|
*inline_declarations = Some(PropertyDeclarationBlock {
|
||||||
declarations: Arc::new(declarations.into_iter().map(|d| (d, importance)).collect()),
|
declarations: Arc::new(declarations.into_iter().map(|d| (d, importance)).collect()),
|
||||||
|
any_important: importance.important(),
|
||||||
|
any_normal: !importance.important(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -287,6 +287,28 @@ impl Importance {
|
||||||
pub struct PropertyDeclarationBlock {
|
pub struct PropertyDeclarationBlock {
|
||||||
#[cfg_attr(feature = "servo", ignore_heap_size_of = "#7038")]
|
#[cfg_attr(feature = "servo", ignore_heap_size_of = "#7038")]
|
||||||
pub declarations: Arc<Vec<(PropertyDeclaration, Importance)>>,
|
pub declarations: Arc<Vec<(PropertyDeclaration, Importance)>>,
|
||||||
|
|
||||||
|
/// Whether `self.declaration` contains at least one declaration with `Importance::Normal`
|
||||||
|
pub any_normal: bool,
|
||||||
|
|
||||||
|
/// Whether `self.declaration` contains at least one declaration with `Importance::Important`
|
||||||
|
pub any_important: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PropertyDeclarationBlock {
|
||||||
|
pub fn recalc_any(&mut self) {
|
||||||
|
let mut any_normal = false;
|
||||||
|
let mut any_important = false;
|
||||||
|
for &(_, importance) in &*self.declarations {
|
||||||
|
if importance.important() {
|
||||||
|
any_important = true
|
||||||
|
} else {
|
||||||
|
any_normal = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.any_normal = any_normal;
|
||||||
|
self.any_important = any_important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToCss for PropertyDeclarationBlock {
|
impl ToCss for PropertyDeclarationBlock {
|
||||||
|
@ -542,6 +564,8 @@ impl<'a, 'b> DeclarationParser for PropertyDeclarationParser<'a, 'b> {
|
||||||
pub fn parse_property_declaration_list(context: &ParserContext, input: &mut Parser)
|
pub fn parse_property_declaration_list(context: &ParserContext, input: &mut Parser)
|
||||||
-> PropertyDeclarationBlock {
|
-> PropertyDeclarationBlock {
|
||||||
let mut declarations = Vec::new();
|
let mut declarations = Vec::new();
|
||||||
|
let mut any_normal = false;
|
||||||
|
let mut any_important = false;
|
||||||
let parser = PropertyDeclarationParser {
|
let parser = PropertyDeclarationParser {
|
||||||
context: context,
|
context: context,
|
||||||
};
|
};
|
||||||
|
@ -549,6 +573,11 @@ pub fn parse_property_declaration_list(context: &ParserContext, input: &mut Pars
|
||||||
while let Some(declaration) = iter.next() {
|
while let Some(declaration) = iter.next() {
|
||||||
match declaration {
|
match declaration {
|
||||||
Ok((results, importance)) => {
|
Ok((results, importance)) => {
|
||||||
|
if importance.important() {
|
||||||
|
any_important = true
|
||||||
|
} else {
|
||||||
|
any_normal = true
|
||||||
|
}
|
||||||
declarations.extend(results.into_iter().map(|d| (d, importance)))
|
declarations.extend(results.into_iter().map(|d| (d, importance)))
|
||||||
}
|
}
|
||||||
Err(range) => {
|
Err(range) => {
|
||||||
|
@ -559,16 +588,24 @@ pub fn parse_property_declaration_list(context: &ParserContext, input: &mut Pars
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PropertyDeclarationBlock {
|
let (declarations, removed_any) = deduplicate_property_declarations(declarations);
|
||||||
declarations: Arc::new(deduplicate_property_declarations(declarations)),
|
let mut block = PropertyDeclarationBlock {
|
||||||
|
declarations: Arc::new(declarations),
|
||||||
|
any_normal: any_normal,
|
||||||
|
any_important: any_important,
|
||||||
|
};
|
||||||
|
if removed_any {
|
||||||
|
block.recalc_any();
|
||||||
}
|
}
|
||||||
|
block
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Only keep the "winning" declaration for any given property, by importance then source order.
|
/// Only keep the "winning" declaration for any given property, by importance then source order.
|
||||||
/// The input and output are in source order
|
/// The input and output are in source order
|
||||||
fn deduplicate_property_declarations(declarations: Vec<(PropertyDeclaration, Importance)>)
|
fn deduplicate_property_declarations(declarations: Vec<(PropertyDeclaration, Importance)>)
|
||||||
-> Vec<(PropertyDeclaration, Importance)> {
|
-> (Vec<(PropertyDeclaration, Importance)>, bool) {
|
||||||
|
let mut removed_any = false;
|
||||||
let mut deduplicated = Vec::new();
|
let mut deduplicated = Vec::new();
|
||||||
let mut seen_normal = PropertyBitField::new();
|
let mut seen_normal = PropertyBitField::new();
|
||||||
let mut seen_important = PropertyBitField::new();
|
let mut seen_important = PropertyBitField::new();
|
||||||
|
@ -581,17 +618,20 @@ fn deduplicate_property_declarations(declarations: Vec<(PropertyDeclaration, Imp
|
||||||
% if not property.derived_from:
|
% if not property.derived_from:
|
||||||
if importance.important() {
|
if importance.important() {
|
||||||
if seen_important.get_${property.ident}() {
|
if seen_important.get_${property.ident}() {
|
||||||
|
removed_any = true;
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if seen_normal.get_${property.ident}() {
|
if seen_normal.get_${property.ident}() {
|
||||||
remove_one(&mut deduplicated, |d| {
|
remove_one(&mut deduplicated, |d| {
|
||||||
matches!(d, &(PropertyDeclaration::${property.camel_case}(..), _))
|
matches!(d, &(PropertyDeclaration::${property.camel_case}(..), _))
|
||||||
})
|
});
|
||||||
|
removed_any = true;
|
||||||
}
|
}
|
||||||
seen_important.set_${property.ident}()
|
seen_important.set_${property.ident}()
|
||||||
} else {
|
} else {
|
||||||
if seen_normal.get_${property.ident}() ||
|
if seen_normal.get_${property.ident}() ||
|
||||||
seen_important.get_${property.ident}() {
|
seen_important.get_${property.ident}() {
|
||||||
|
removed_any = true;
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
seen_normal.set_${property.ident}()
|
seen_normal.set_${property.ident}()
|
||||||
|
@ -604,17 +644,20 @@ fn deduplicate_property_declarations(declarations: Vec<(PropertyDeclaration, Imp
|
||||||
PropertyDeclaration::Custom(ref name, _) => {
|
PropertyDeclaration::Custom(ref name, _) => {
|
||||||
if importance.important() {
|
if importance.important() {
|
||||||
if seen_custom_important.contains(name) {
|
if seen_custom_important.contains(name) {
|
||||||
|
removed_any = true;
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if seen_custom_normal.contains(name) {
|
if seen_custom_normal.contains(name) {
|
||||||
remove_one(&mut deduplicated, |d| {
|
remove_one(&mut deduplicated, |d| {
|
||||||
matches!(d, &(PropertyDeclaration::Custom(ref n, _), _) if n == name)
|
matches!(d, &(PropertyDeclaration::Custom(ref n, _), _) if n == name)
|
||||||
})
|
});
|
||||||
|
removed_any = true;
|
||||||
}
|
}
|
||||||
seen_custom_important.push(name.clone())
|
seen_custom_important.push(name.clone())
|
||||||
} else {
|
} else {
|
||||||
if seen_custom_normal.contains(name) ||
|
if seen_custom_normal.contains(name) ||
|
||||||
seen_custom_important.contains(name) {
|
seen_custom_important.contains(name) {
|
||||||
|
removed_any = true;
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
seen_custom_normal.push(name.clone())
|
seen_custom_normal.push(name.clone())
|
||||||
|
@ -624,7 +667,7 @@ fn deduplicate_property_declarations(declarations: Vec<(PropertyDeclaration, Imp
|
||||||
deduplicated.push((declaration, importance))
|
deduplicated.push((declaration, importance))
|
||||||
}
|
}
|
||||||
deduplicated.reverse();
|
deduplicated.reverse();
|
||||||
deduplicated
|
(deduplicated, removed_any)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -164,8 +164,8 @@ impl Stylist {
|
||||||
// Take apart the StyleRule into individual Rules and insert
|
// Take apart the StyleRule into individual Rules and insert
|
||||||
// them into the SelectorMap of that priority.
|
// them into the SelectorMap of that priority.
|
||||||
macro_rules! append(
|
macro_rules! append(
|
||||||
($style_rule: ident, $priority: ident, $importance: expr) => {
|
($style_rule: ident, $priority: ident, $importance: expr, $any: ident) => {
|
||||||
if !$style_rule.declarations.declarations.is_empty() {
|
if $style_rule.declarations.$any {
|
||||||
for selector in &$style_rule.selectors {
|
for selector in &$style_rule.selectors {
|
||||||
let map = if let Some(ref pseudo) = selector.pseudo_element {
|
let map = if let Some(ref pseudo) = selector.pseudo_element {
|
||||||
self.pseudos_map
|
self.pseudos_map
|
||||||
|
@ -193,8 +193,8 @@ impl Stylist {
|
||||||
for rule in stylesheet.effective_rules(&self.device) {
|
for rule in stylesheet.effective_rules(&self.device) {
|
||||||
match *rule {
|
match *rule {
|
||||||
CSSRule::Style(ref style_rule) => {
|
CSSRule::Style(ref style_rule) => {
|
||||||
append!(style_rule, normal, Importance::Normal);
|
append!(style_rule, normal, Importance::Normal, any_normal);
|
||||||
append!(style_rule, important, Importance::Important);
|
append!(style_rule, important, Importance::Important, any_important);
|
||||||
rules_source_order += 1;
|
rules_source_order += 1;
|
||||||
|
|
||||||
for selector in &style_rule.selectors {
|
for selector in &style_rule.selectors {
|
||||||
|
@ -396,12 +396,14 @@ impl Stylist {
|
||||||
|
|
||||||
// Step 4: Normal style attributes.
|
// Step 4: Normal style attributes.
|
||||||
if let Some(ref sa) = style_attribute {
|
if let Some(ref sa) = style_attribute {
|
||||||
relations |= AFFECTED_BY_STYLE_ATTRIBUTE;
|
if sa.any_normal {
|
||||||
Push::push(
|
relations |= AFFECTED_BY_STYLE_ATTRIBUTE;
|
||||||
applicable_declarations,
|
Push::push(
|
||||||
DeclarationBlock::from_declarations(
|
applicable_declarations,
|
||||||
sa.declarations.clone(),
|
DeclarationBlock::from_declarations(
|
||||||
Importance::Normal));
|
sa.declarations.clone(),
|
||||||
|
Importance::Normal));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("style attr: {:?}", relations);
|
debug!("style attr: {:?}", relations);
|
||||||
|
@ -416,11 +418,14 @@ impl Stylist {
|
||||||
|
|
||||||
// Step 6: `!important` style attributes.
|
// Step 6: `!important` style attributes.
|
||||||
if let Some(ref sa) = style_attribute {
|
if let Some(ref sa) = style_attribute {
|
||||||
Push::push(
|
if sa.any_important {
|
||||||
applicable_declarations,
|
relations |= AFFECTED_BY_STYLE_ATTRIBUTE;
|
||||||
DeclarationBlock::from_declarations(
|
Push::push(
|
||||||
sa.declarations.clone(),
|
applicable_declarations,
|
||||||
Importance::Important));
|
DeclarationBlock::from_declarations(
|
||||||
|
sa.declarations.clone(),
|
||||||
|
Importance::Important));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("style attr important: {:?}", relations);
|
debug!("style attr important: {:?}", relations);
|
||||||
|
|
|
@ -40,10 +40,10 @@ macro_rules! sizeof_checker (
|
||||||
// Update the sizes here
|
// Update the sizes here
|
||||||
sizeof_checker!(size_event_target, EventTarget, 40);
|
sizeof_checker!(size_event_target, EventTarget, 40);
|
||||||
sizeof_checker!(size_node, Node, 160);
|
sizeof_checker!(size_node, Node, 160);
|
||||||
sizeof_checker!(size_element, Element, 328);
|
sizeof_checker!(size_element, Element, 336);
|
||||||
sizeof_checker!(size_htmlelement, HTMLElement, 344);
|
sizeof_checker!(size_htmlelement, HTMLElement, 352);
|
||||||
sizeof_checker!(size_div, HTMLDivElement, 344);
|
sizeof_checker!(size_div, HTMLDivElement, 352);
|
||||||
sizeof_checker!(size_span, HTMLSpanElement, 344);
|
sizeof_checker!(size_span, HTMLSpanElement, 352);
|
||||||
sizeof_checker!(size_text, Text, 192);
|
sizeof_checker!(size_text, Text, 192);
|
||||||
sizeof_checker!(size_characterdata, CharacterData, 192);
|
sizeof_checker!(size_characterdata, CharacterData, 192);
|
||||||
sizeof_checker!(size_servothreadsafelayoutnode, ServoThreadSafeLayoutNode, 16);
|
sizeof_checker!(size_servothreadsafelayoutnode, ServoThreadSafeLayoutNode, 16);
|
||||||
|
|
|
@ -46,6 +46,8 @@ fn property_declaration_block_should_serialize_correctly() {
|
||||||
|
|
||||||
let block = PropertyDeclarationBlock {
|
let block = PropertyDeclarationBlock {
|
||||||
declarations: Arc::new(declarations),
|
declarations: Arc::new(declarations),
|
||||||
|
any_important: true,
|
||||||
|
any_normal: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
let css_string = block.to_css_string();
|
let css_string = block.to_css_string();
|
||||||
|
@ -62,6 +64,8 @@ mod shorthand_serialization {
|
||||||
pub fn shorthand_properties_to_string(properties: Vec<PropertyDeclaration>) -> String {
|
pub fn shorthand_properties_to_string(properties: Vec<PropertyDeclaration>) -> String {
|
||||||
let block = PropertyDeclarationBlock {
|
let block = PropertyDeclarationBlock {
|
||||||
declarations: Arc::new(properties.into_iter().map(|d| (d, Importance::Normal)).collect()),
|
declarations: Arc::new(properties.into_iter().map(|d| (d, Importance::Normal)).collect()),
|
||||||
|
any_important: false,
|
||||||
|
any_normal: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
block.to_css_string()
|
block.to_css_string()
|
||||||
|
|
|
@ -93,6 +93,8 @@ fn test_parse_stylesheet() {
|
||||||
longhands::display::SpecifiedValue::none)),
|
longhands::display::SpecifiedValue::none)),
|
||||||
Importance::Important),
|
Importance::Important),
|
||||||
]),
|
]),
|
||||||
|
any_normal: false,
|
||||||
|
any_important: true,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
CSSRule::Style(StyleRule {
|
CSSRule::Style(StyleRule {
|
||||||
|
@ -138,6 +140,8 @@ fn test_parse_stylesheet() {
|
||||||
longhands::display::SpecifiedValue::block)),
|
longhands::display::SpecifiedValue::block)),
|
||||||
Importance::Normal),
|
Importance::Normal),
|
||||||
]),
|
]),
|
||||||
|
any_normal: true,
|
||||||
|
any_important: false,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
CSSRule::Style(StyleRule {
|
CSSRule::Style(StyleRule {
|
||||||
|
@ -192,6 +196,8 @@ fn test_parse_stylesheet() {
|
||||||
(PropertyDeclaration::BackgroundClip(DeclaredValue::Initial),
|
(PropertyDeclaration::BackgroundClip(DeclaredValue::Initial),
|
||||||
Importance::Normal),
|
Importance::Normal),
|
||||||
]),
|
]),
|
||||||
|
any_normal: true,
|
||||||
|
any_important: false,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
CSSRule::Keyframes(KeyframesRule {
|
CSSRule::Keyframes(KeyframesRule {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue