Handle importance when inserting into the rule tree.

This commit is contained in:
Bobby Holley 2017-05-10 17:05:52 +02:00
parent 48b5e5ebc4
commit e9d4110ad4
4 changed files with 141 additions and 143 deletions

View file

@ -10,6 +10,7 @@
use heapsize::HeapSizeOf;
use properties::{Importance, PropertyDeclarationBlock};
use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard};
use smallvec::SmallVec;
use std::io::{self, Write};
use std::ptr;
use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
@ -124,6 +125,96 @@ impl RuleTree {
self.dump(guards, &mut stdout);
}
/// Inserts the given rules, that must be in proper order by specifity, and
/// returns the corresponding rule node representing the last inserted one.
///
/// !important rules are detected and inserted into the appropriate position
/// in the rule tree. This allows selector matching to ignore importance,
/// while still maintaining the appropriate cascade order in the rule tree.
pub fn insert_ordered_rules_with_important<'a, I>(&self,
iter: I,
guards: &StylesheetGuards)
-> StrongRuleNode
where I: Iterator<Item=(StyleSource, CascadeLevel)>,
{
use self::CascadeLevel::*;
let mut current = self.root.clone();
let mut last_level = current.get().level;
let mut found_important = false;
let mut important_style_attr = None;
let mut important_author = SmallVec::<[StyleSource; 4]>::new();
let mut important_user = SmallVec::<[StyleSource; 4]>::new();
let mut important_ua = SmallVec::<[StyleSource; 4]>::new();
let mut transition = None;
for (source, level) in iter {
debug_assert!(last_level <= level, "Not really ordered");
debug_assert!(!level.is_important(), "Important levels handled internally");
let (any_normal, any_important) = {
let pdb = source.read(level.guard(guards));
(pdb.any_normal(), pdb.any_important())
};
if any_important {
found_important = true;
match level {
AuthorNormal => important_author.push(source.clone()),
UANormal => important_ua.push(source.clone()),
UserNormal => important_user.push(source.clone()),
StyleAttributeNormal => {
debug_assert!(important_style_attr.is_none());
important_style_attr = Some(source.clone());
},
_ => {},
};
}
if any_normal {
if matches!(level, Transitions) && found_important {
// There can be at most one transition, and it will come at
// the end of the iterator. Stash it and apply it after
// !important rules.
debug_assert!(transition.is_none());
transition = Some(source);
} else {
current = current.ensure_child(self.root.downgrade(), source, level);
}
}
last_level = level;
}
// Early-return in the common case of no !important declarations.
if !found_important {
return current;
}
//
// Insert important declarations, in order of increasing importance,
// followed by any transition rule.
//
for source in important_author.into_iter() {
current = current.ensure_child(self.root.downgrade(), source, AuthorImportant);
}
if let Some(source) = important_style_attr {
current = current.ensure_child(self.root.downgrade(), source, StyleAttributeImportant);
}
for source in important_user.into_iter() {
current = current.ensure_child(self.root.downgrade(), source, UserImportant);
}
for source in important_ua.into_iter() {
current = current.ensure_child(self.root.downgrade(), source, UAImportant);
}
if let Some(source) = transition {
current = current.ensure_child(self.root.downgrade(), source, Transitions);
}
current
}
/// Insert the given rules, that must be in proper order by specifity, and
/// return the corresponding rule node representing the last inserted one.
pub fn insert_ordered_rules<'a, I>(&self, iter: I) -> StrongRuleNode