aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout/css/matching.rs
diff options
context:
space:
mode:
authorBobby Holley <bobbyholley@gmail.com>2015-12-17 16:21:29 -0800
committerBobby Holley <bobbyholley@gmail.com>2015-12-29 12:07:07 -0800
commita05d7f1dfd8500d299007af99861cc86fada9386 (patch)
treeea956e5046b37168344bdff3ffc4274007d54ab6 /components/layout/css/matching.rs
parent47059d2d26f14f71e5b7212fa8bc01608eca11b5 (diff)
downloadservo-a05d7f1dfd8500d299007af99861cc86fada9386.tar.gz
servo-a05d7f1dfd8500d299007af99861cc86fada9386.zip
Hoist style-related context bits into style/.
We do a few things-here: * Hoist non-layout-dependent fields in SharedLayoutData and LocalLayoutData into style/. * Hoist parts of css/matching.rs into style/. * Hoist parts of layout/animation.rs into style/animation.rs. * Remove the duplicated-but-slightly-different definition of OpaqueNode.
Diffstat (limited to 'components/layout/css/matching.rs')
-rw-r--r--components/layout/css/matching.rs351
1 files changed, 12 insertions, 339 deletions
diff --git a/components/layout/css/matching.rs b/components/layout/css/matching.rs
index a9c07848309..e83899e2893 100644
--- a/components/layout/css/matching.rs
+++ b/components/layout/css/matching.rs
@@ -13,347 +13,19 @@ use incremental::{self, RestyleDamage};
use msg::ParseErrorReporter;
use script::layout_interface::Animation;
use selectors::bloom::BloomFilter;
-use selectors::matching::{CommonStyleAffectingAttributeMode, CommonStyleAffectingAttributes};
-use selectors::matching::{common_style_affecting_attributes, rare_style_affecting_attributes};
use selectors::parser::PseudoElement;
use selectors::{Element};
-use smallvec::SmallVec;
-use std::borrow::ToOwned;
-use std::hash::{Hash, Hasher};
use std::mem::transmute;
-use std::slice::Iter;
use std::sync::mpsc::Sender;
use std::sync::{Arc, Mutex};
-use string_cache::{Atom, Namespace};
use style::data::PrivateStyleData;
use style::dom::{TElement, TNode};
-use style::properties::{ComputedValues, PropertyDeclaration, cascade};
+use style::matching::{ApplicableDeclarations, ApplicableDeclarationsCache};
+use style::matching::{StyleSharingCandidate, StyleSharingCandidateCache};
+use style::properties::{ComputedValues, cascade};
use style::selector_matching::{DeclarationBlock, Stylist};
use util::arc_ptr_eq;
-use util::cache::{LRUCache, SimpleHashCache};
use util::opts;
-use util::vec::ForgetfulSink;
-
-pub struct ApplicableDeclarations {
- pub normal: SmallVec<[DeclarationBlock; 16]>,
- pub before: Vec<DeclarationBlock>,
- pub after: Vec<DeclarationBlock>,
-
- /// Whether the `normal` declarations are shareable with other nodes.
- pub normal_shareable: bool,
-}
-
-impl ApplicableDeclarations {
- pub fn new() -> ApplicableDeclarations {
- ApplicableDeclarations {
- normal: SmallVec::new(),
- before: Vec::new(),
- after: Vec::new(),
- normal_shareable: false,
- }
- }
-}
-
-#[derive(Clone)]
-pub struct ApplicableDeclarationsCacheEntry {
- pub declarations: Vec<DeclarationBlock>,
-}
-
-impl ApplicableDeclarationsCacheEntry {
- fn new(declarations: Vec<DeclarationBlock>) -> ApplicableDeclarationsCacheEntry {
- ApplicableDeclarationsCacheEntry {
- declarations: declarations,
- }
- }
-}
-
-impl PartialEq for ApplicableDeclarationsCacheEntry {
- fn eq(&self, other: &ApplicableDeclarationsCacheEntry) -> bool {
- let this_as_query = ApplicableDeclarationsCacheQuery::new(&*self.declarations);
- this_as_query.eq(other)
- }
-}
-impl Eq for ApplicableDeclarationsCacheEntry {}
-
-impl Hash for ApplicableDeclarationsCacheEntry {
- fn hash<H: Hasher>(&self, state: &mut H) {
- let tmp = ApplicableDeclarationsCacheQuery::new(&*self.declarations);
- tmp.hash(state);
- }
-}
-
-struct ApplicableDeclarationsCacheQuery<'a> {
- declarations: &'a [DeclarationBlock],
-}
-
-impl<'a> ApplicableDeclarationsCacheQuery<'a> {
- fn new(declarations: &'a [DeclarationBlock]) -> ApplicableDeclarationsCacheQuery<'a> {
- ApplicableDeclarationsCacheQuery {
- declarations: declarations,
- }
- }
-}
-
-impl<'a> PartialEq for ApplicableDeclarationsCacheQuery<'a> {
- fn eq(&self, other: &ApplicableDeclarationsCacheQuery<'a>) -> bool {
- if self.declarations.len() != other.declarations.len() {
- return false
- }
- for (this, other) in self.declarations.iter().zip(other.declarations) {
- if !arc_ptr_eq(&this.declarations, &other.declarations) {
- return false
- }
- }
- true
- }
-}
-impl<'a> Eq for ApplicableDeclarationsCacheQuery<'a> {}
-
-impl<'a> PartialEq<ApplicableDeclarationsCacheEntry> for ApplicableDeclarationsCacheQuery<'a> {
- fn eq(&self, other: &ApplicableDeclarationsCacheEntry) -> bool {
- let other_as_query = ApplicableDeclarationsCacheQuery::new(&other.declarations);
- self.eq(&other_as_query)
- }
-}
-
-impl<'a> Hash for ApplicableDeclarationsCacheQuery<'a> {
- fn hash<H: Hasher>(&self, state: &mut H) {
- for declaration in self.declarations {
- // Each declaration contians an Arc, which is a stable
- // pointer; we use that for hashing and equality.
- let ptr = &*declaration.declarations as *const Vec<PropertyDeclaration>;
- ptr.hash(state);
- }
- }
-}
-
-static APPLICABLE_DECLARATIONS_CACHE_SIZE: usize = 32;
-
-pub struct ApplicableDeclarationsCache {
- cache: SimpleHashCache<ApplicableDeclarationsCacheEntry, Arc<ComputedValues>>,
-}
-
-impl ApplicableDeclarationsCache {
- pub fn new() -> ApplicableDeclarationsCache {
- ApplicableDeclarationsCache {
- cache: SimpleHashCache::new(APPLICABLE_DECLARATIONS_CACHE_SIZE),
- }
- }
-
- fn find(&self, declarations: &[DeclarationBlock]) -> Option<Arc<ComputedValues>> {
- match self.cache.find(&ApplicableDeclarationsCacheQuery::new(declarations)) {
- None => None,
- Some(ref values) => Some((*values).clone()),
- }
- }
-
- fn insert(&mut self, declarations: Vec<DeclarationBlock>, style: Arc<ComputedValues>) {
- self.cache.insert(ApplicableDeclarationsCacheEntry::new(declarations), style)
- }
-
- pub fn evict_all(&mut self) {
- self.cache.evict_all();
- }
-}
-
-/// An LRU cache of the last few nodes seen, so that we can aggressively try to reuse their styles.
-pub struct StyleSharingCandidateCache {
- cache: LRUCache<StyleSharingCandidate, ()>,
-}
-
-fn create_common_style_affecting_attributes_from_element<'le, E: TElement<'le>>(element: &E)
- -> CommonStyleAffectingAttributes {
- let mut flags = CommonStyleAffectingAttributes::empty();
- for attribute_info in &common_style_affecting_attributes() {
- match attribute_info.mode {
- CommonStyleAffectingAttributeMode::IsPresent(flag) => {
- if element.get_attr(&ns!(), &attribute_info.atom).is_some() {
- flags.insert(flag)
- }
- }
- CommonStyleAffectingAttributeMode::IsEqual(target_value, flag) => {
- match element.get_attr(&ns!(), &attribute_info.atom) {
- Some(element_value) if element_value == target_value => {
- flags.insert(flag)
- }
- _ => {}
- }
- }
- }
- }
- flags
-}
-
-#[derive(Clone)]
-pub struct StyleSharingCandidate {
- pub style: Arc<ComputedValues>,
- pub parent_style: Arc<ComputedValues>,
- pub local_name: Atom,
- // FIXME(pcwalton): Should be a list of atoms instead.
- pub class: Option<String>,
- pub namespace: Namespace,
- pub common_style_affecting_attributes: CommonStyleAffectingAttributes,
- pub link: bool,
-}
-
-impl PartialEq for StyleSharingCandidate {
- fn eq(&self, other: &StyleSharingCandidate) -> bool {
- arc_ptr_eq(&self.style, &other.style) &&
- arc_ptr_eq(&self.parent_style, &other.parent_style) &&
- self.local_name == other.local_name &&
- self.class == other.class &&
- self.link == other.link &&
- self.namespace == other.namespace &&
- self.common_style_affecting_attributes == other.common_style_affecting_attributes
- }
-}
-
-impl StyleSharingCandidate {
- /// Attempts to create a style sharing candidate from this node. Returns
- /// the style sharing candidate or `None` if this node is ineligible for
- /// style sharing.
- fn new<'le, E: TElement<'le>>(element: &E) -> Option<StyleSharingCandidate> {
- let parent_element = match element.parent_element() {
- None => return None,
- Some(parent_element) => parent_element,
- };
-
- let style = unsafe {
- match element.as_node().borrow_data_unchecked() {
- None => return None,
- Some(data_ref) => {
- match (*data_ref).style {
- None => return None,
- Some(ref data) => (*data).clone(),
- }
- }
- }
- };
- let parent_style = unsafe {
- match parent_element.as_node().borrow_data_unchecked() {
- None => return None,
- Some(parent_data_ref) => {
- match (*parent_data_ref).style {
- None => return None,
- Some(ref data) => (*data).clone(),
- }
- }
- }
- };
-
- if element.style_attribute().is_some() {
- return None
- }
-
- Some(StyleSharingCandidate {
- style: style,
- parent_style: parent_style,
- local_name: element.get_local_name().clone(),
- class: element.get_attr(&ns!(), &atom!("class"))
- .map(|string| string.to_owned()),
- link: element.is_link(),
- namespace: (*element.get_namespace()).clone(),
- common_style_affecting_attributes:
- create_common_style_affecting_attributes_from_element::<'le, E>(&element)
- })
- }
-
- fn can_share_style_with<'a, E: TElement<'a>>(&self, element: &E) -> bool {
- if *element.get_local_name() != self.local_name {
- return false
- }
-
- // FIXME(pcwalton): Use `each_class` here instead of slow string comparison.
- match (&self.class, element.get_attr(&ns!(), &atom!("class"))) {
- (&None, Some(_)) | (&Some(_), None) => return false,
- (&Some(ref this_class), Some(element_class)) if
- element_class != &**this_class => {
- return false
- }
- (&Some(_), Some(_)) | (&None, None) => {}
- }
-
- if *element.get_namespace() != self.namespace {
- return false
- }
-
- let mut matching_rules = ForgetfulSink::new();
- element.synthesize_presentational_hints_for_legacy_attributes(&mut matching_rules);
- if !matching_rules.is_empty() {
- return false;
- }
-
- // FIXME(pcwalton): It's probably faster to iterate over all the element's attributes and
- // use the {common, rare}-style-affecting-attributes tables as lookup tables.
-
- for attribute_info in &common_style_affecting_attributes() {
- match attribute_info.mode {
- CommonStyleAffectingAttributeMode::IsPresent(flag) => {
- if self.common_style_affecting_attributes.contains(flag) !=
- element.get_attr(&ns!(), &attribute_info.atom).is_some() {
- return false
- }
- }
- CommonStyleAffectingAttributeMode::IsEqual(target_value, flag) => {
- match element.get_attr(&ns!(), &attribute_info.atom) {
- Some(ref element_value) if self.common_style_affecting_attributes
- .contains(flag) &&
- *element_value != target_value => {
- return false
- }
- Some(_) if !self.common_style_affecting_attributes.contains(flag) => {
- return false
- }
- None if self.common_style_affecting_attributes.contains(flag) => {
- return false
- }
- _ => {}
- }
- }
- }
- }
-
- for attribute_name in &rare_style_affecting_attributes() {
- if element.get_attr(&ns!(), attribute_name).is_some() {
- return false
- }
- }
-
- if element.is_link() != self.link {
- return false
- }
-
- // TODO(pcwalton): We don't support visited links yet, but when we do there will need to
- // be some logic here.
-
- true
- }
-}
-
-static STYLE_SHARING_CANDIDATE_CACHE_SIZE: usize = 40;
-
-impl StyleSharingCandidateCache {
- pub fn new() -> StyleSharingCandidateCache {
- StyleSharingCandidateCache {
- cache: LRUCache::new(STYLE_SHARING_CANDIDATE_CACHE_SIZE),
- }
- }
-
- pub fn iter(&self) -> Iter<(StyleSharingCandidate, ())> {
- self.cache.iter()
- }
-
- pub fn insert_if_possible<'le, E: TElement<'le>>(&mut self, element: &E) {
- match StyleSharingCandidate::new(element) {
- None => {}
- Some(candidate) => self.cache.insert(candidate, ())
- }
- }
-
- pub fn touch(&mut self, index: usize) {
- self.cache.touch(index)
- }
-}
/// The results of attempting to share a style.
pub enum StyleSharingResult {
@@ -454,22 +126,22 @@ impl<'ln, ConcreteNode> PrivateMatchMethods for ConcreteNode
None => None,
Some(ref style) => Some(&**style),
};
- let (the_style, is_cacheable) = cascade(layout_context.viewport_size,
+ let (the_style, is_cacheable) = cascade(layout_context.style_context.viewport_size,
applicable_declarations,
shareable,
Some(&***parent_style),
cached_computed_values,
- layout_context.error_reporter.clone());
+ layout_context.style_context.error_reporter.clone());
cacheable = cacheable && is_cacheable;
this_style = the_style
}
None => {
- let (the_style, is_cacheable) = cascade(layout_context.viewport_size,
+ let (the_style, is_cacheable) = cascade(layout_context.style_context.viewport_size,
applicable_declarations,
shareable,
None,
None,
- layout_context.error_reporter.clone());
+ layout_context.style_context.error_reporter.clone());
cacheable = cacheable && is_cacheable;
this_style = the_style
}
@@ -516,7 +188,7 @@ impl<'ln, ConcreteNode> PrivateMatchMethods for ConcreteNode
let this_opaque = self.opaque();
let had_animations_to_expire;
{
- let all_expired_animations = layout_context.expired_animations.read().unwrap();
+ let all_expired_animations = layout_context.style_context.expired_animations.read().unwrap();
let animations_to_expire = all_expired_animations.get(&this_opaque);
had_animations_to_expire = animations_to_expire.is_some();
if let Some(ref animations) = animations_to_expire {
@@ -527,17 +199,18 @@ impl<'ln, ConcreteNode> PrivateMatchMethods for ConcreteNode
}
if had_animations_to_expire {
- layout_context.expired_animations.write().unwrap().remove(&this_opaque);
+ layout_context.style_context.expired_animations.write().unwrap().remove(&this_opaque);
}
// Merge any running transitions into the current style, and cancel them.
- let had_running_animations = layout_context.running_animations
+ let had_running_animations = layout_context.style_context
+ .running_animations
.read()
.unwrap()
.get(&this_opaque)
.is_some();
if had_running_animations {
- let mut all_running_animations = layout_context.running_animations.write().unwrap();
+ let mut all_running_animations = layout_context.style_context.running_animations.write().unwrap();
for running_animation in all_running_animations.get(&this_opaque).unwrap() {
animation::update_style_for_animation(running_animation, style, None);
}