mirror of
https://github.com/servo/servo.git
synced 2025-08-09 07:25:35 +01:00
Auto merge of #15462 - bholley:accumulate_selector_flags, r=emilio
Accumulate parent elements that need selector bits set on the ThreadLocalStyleContext Discussion and review in https://bugzilla.mozilla.org/show_bug.cgi?id=1336646 <!-- 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/15462) <!-- Reviewable:end -->
This commit is contained in:
commit
cbfd446427
20 changed files with 333 additions and 210 deletions
|
@ -66,7 +66,7 @@ impl<E: TElement> StyleBloom<E> {
|
|||
|
||||
/// Push an element to the bloom filter, knowing that it's a child of the
|
||||
/// last element parent.
|
||||
fn push(&mut self, element: E) {
|
||||
pub fn push(&mut self, element: E) {
|
||||
if cfg!(debug_assertions) {
|
||||
if self.elements.is_empty() {
|
||||
assert!(element.parent_element().is_none());
|
||||
|
@ -86,12 +86,20 @@ impl<E: TElement> StyleBloom<E> {
|
|||
popped
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
/// Returns true if the bloom filter is empty.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.elements.is_empty()
|
||||
}
|
||||
|
||||
|
||||
/// Clears the bloom filter.
|
||||
pub fn clear(&mut self) {
|
||||
self.filter.clear();
|
||||
self.elements.clear();
|
||||
}
|
||||
|
||||
fn rebuild(&mut self, mut element: E) -> usize {
|
||||
/// Rebuilds the bloom filter up to the parent of the given element.
|
||||
pub fn rebuild(&mut self, mut element: E) -> usize {
|
||||
self.clear();
|
||||
|
||||
while let Some(parent) = element.parent_element() {
|
||||
|
|
|
@ -9,12 +9,14 @@ use animation::Animation;
|
|||
use app_units::Au;
|
||||
use bloom::StyleBloom;
|
||||
use data::ElementData;
|
||||
use dom::{OpaqueNode, TNode, TElement};
|
||||
use dom::{OpaqueNode, TNode, TElement, SendElement};
|
||||
use error_reporting::ParseErrorReporter;
|
||||
use euclid::Size2D;
|
||||
use matching::StyleSharingCandidateCache;
|
||||
use parking_lot::RwLock;
|
||||
use properties::ComputedValues;
|
||||
use selectors::matching::ElementSelectorFlags;
|
||||
use servo_config::opts;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::fmt;
|
||||
|
@ -22,6 +24,7 @@ use std::ops::Add;
|
|||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::mpsc::Sender;
|
||||
use stylist::Stylist;
|
||||
use thread_state;
|
||||
use timer::Timer;
|
||||
|
||||
/// This structure is used to create a local style context from a shared one.
|
||||
|
@ -160,7 +163,35 @@ lazy_static! {
|
|||
impl TraversalStatistics {
|
||||
/// Returns whether statistics dumping is enabled.
|
||||
pub fn should_dump() -> bool {
|
||||
*DUMP_STYLE_STATISTICS
|
||||
*DUMP_STYLE_STATISTICS || opts::get().style_sharing_stats
|
||||
}
|
||||
}
|
||||
|
||||
/// A task to be run in sequential mode on the parent (non-worker) thread. This
|
||||
/// is used by the style system to queue up work which is not safe to do during
|
||||
/// the parallel traversal.
|
||||
pub enum SequentialTask<E: TElement> {
|
||||
/// Sets selector flags. This is used when we need to set flags on an
|
||||
/// element that we don't have exclusive access to (i.e. the parent).
|
||||
SetSelectorFlags(SendElement<E>, ElementSelectorFlags),
|
||||
}
|
||||
|
||||
impl<E: TElement> SequentialTask<E> {
|
||||
/// Executes this task.
|
||||
pub fn execute(self) {
|
||||
use self::SequentialTask::*;
|
||||
debug_assert!(thread_state::get() == thread_state::LAYOUT);
|
||||
match self {
|
||||
SetSelectorFlags(el, flags) => {
|
||||
unsafe { el.set_selector_flags(flags) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a task to set the selector flags on an element.
|
||||
pub fn set_selector_flags(el: E, flags: ElementSelectorFlags) -> Self {
|
||||
use self::SequentialTask::*;
|
||||
SetSelectorFlags(unsafe { SendElement::new(el) }, flags)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,6 +208,10 @@ pub struct ThreadLocalStyleContext<E: TElement> {
|
|||
/// A channel on which new animations that have been triggered by style
|
||||
/// recalculation can be sent.
|
||||
pub new_animations_sender: Sender<Animation>,
|
||||
/// A set of tasks to be run (on the parent thread) in sequential mode after
|
||||
/// the rest of the styling is complete. This is useful for infrequently-needed
|
||||
/// non-threadsafe operations.
|
||||
pub tasks: Vec<SequentialTask<E>>,
|
||||
/// Statistics about the traversal.
|
||||
pub statistics: TraversalStatistics,
|
||||
/// Information related to the current element, non-None during processing.
|
||||
|
@ -190,6 +225,7 @@ impl<E: TElement> ThreadLocalStyleContext<E> {
|
|||
style_sharing_candidate_cache: StyleSharingCandidateCache::new(),
|
||||
bloom_filter: StyleBloom::new(),
|
||||
new_animations_sender: shared.local_context_creation_data.lock().unwrap().new_animations_sender.clone(),
|
||||
tasks: Vec::new(),
|
||||
statistics: TraversalStatistics::default(),
|
||||
current_element_info: None,
|
||||
}
|
||||
|
@ -221,10 +257,15 @@ impl<E: TElement> ThreadLocalStyleContext<E> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
impl<E: TElement> Drop for ThreadLocalStyleContext<E> {
|
||||
fn drop(&mut self) {
|
||||
debug_assert!(self.current_element_info.is_none());
|
||||
|
||||
// Execute any enqueued sequential tasks.
|
||||
debug_assert!(thread_state::get() == thread_state::LAYOUT);
|
||||
for task in self.tasks.drain(..) {
|
||||
task.execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ use element_state::ElementState;
|
|||
use parking_lot::RwLock;
|
||||
use properties::{ComputedValues, PropertyDeclarationBlock};
|
||||
use selector_parser::{ElementExt, PreExistingComputedValues, PseudoElement};
|
||||
use selectors::matching::ElementSelectorFlags;
|
||||
use sink::Push;
|
||||
use std::fmt;
|
||||
use std::fmt::Debug;
|
||||
|
@ -321,6 +322,19 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre
|
|||
/// blockification on this element. (This function exists so that Gecko
|
||||
/// native anonymous content can opt out of this style fixup.)
|
||||
fn skip_root_and_item_based_display_fixup(&self) -> bool;
|
||||
|
||||
/// Sets selector flags, which indicate what kinds of selectors may have
|
||||
/// matched on this element and therefore what kind of work may need to
|
||||
/// be performed when DOM state changes.
|
||||
///
|
||||
/// This is unsafe, like all the flag-setting methods, because it's only safe
|
||||
/// to call with exclusive access to the element. When setting flags on the
|
||||
/// parent during parallel traversal, we use SequentialTask to queue up the
|
||||
/// set to run after the threads join.
|
||||
unsafe fn set_selector_flags(&self, flags: ElementSelectorFlags);
|
||||
|
||||
/// Returns true if the element has all the specified selector flags.
|
||||
fn has_selector_flags(&self, flags: ElementSelectorFlags) -> bool;
|
||||
}
|
||||
|
||||
/// TNode and TElement aren't Send because we want to be careful and explicit
|
||||
|
|
|
@ -46,6 +46,7 @@ use properties::PropertyDeclarationBlock;
|
|||
use rule_tree::CascadeLevel as ServoCascadeLevel;
|
||||
use selector_parser::{ElementExt, Snapshot};
|
||||
use selectors::Element;
|
||||
use selectors::matching::ElementSelectorFlags;
|
||||
use selectors::parser::{AttrSelector, NamespaceConstraint};
|
||||
use servo_url::ServoUrl;
|
||||
use sink::Push;
|
||||
|
@ -379,6 +380,29 @@ lazy_static! {
|
|||
};
|
||||
}
|
||||
|
||||
/// Converts flags from the layout used by rust-selectors to the layout used
|
||||
/// by Gecko. We could align these and then do this without conditionals, but
|
||||
/// it's probably not worth the trouble.
|
||||
fn selector_flags_to_node_flags(flags: ElementSelectorFlags) -> u32 {
|
||||
use gecko_bindings::structs::*;
|
||||
use selectors::matching::*;
|
||||
let mut gecko_flags = 0u32;
|
||||
if flags.contains(HAS_SLOW_SELECTOR) {
|
||||
gecko_flags |= NODE_HAS_SLOW_SELECTOR as u32;
|
||||
}
|
||||
if flags.contains(HAS_SLOW_SELECTOR_LATER_SIBLINGS) {
|
||||
gecko_flags |= NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS as u32;
|
||||
}
|
||||
if flags.contains(HAS_EDGE_CHILD_SELECTOR) {
|
||||
gecko_flags |= NODE_HAS_EDGE_CHILD_SELECTOR as u32;
|
||||
}
|
||||
if flags.contains(HAS_EMPTY_SELECTOR) {
|
||||
gecko_flags |= NODE_HAS_EMPTY_SELECTOR as u32;
|
||||
}
|
||||
|
||||
gecko_flags
|
||||
}
|
||||
|
||||
impl<'le> TElement for GeckoElement<'le> {
|
||||
type ConcreteNode = GeckoNode<'le>;
|
||||
|
||||
|
@ -476,6 +500,16 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
// are NAC handles both cases.
|
||||
self.flags() & (NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE as u32) != 0
|
||||
}
|
||||
|
||||
unsafe fn set_selector_flags(&self, flags: ElementSelectorFlags) {
|
||||
debug_assert!(!flags.is_empty());
|
||||
self.set_flags(selector_flags_to_node_flags(flags));
|
||||
}
|
||||
|
||||
fn has_selector_flags(&self, flags: ElementSelectorFlags) -> bool {
|
||||
let node_flags = selector_flags_to_node_flags(flags);
|
||||
(self.flags() & node_flags) == node_flags
|
||||
}
|
||||
}
|
||||
|
||||
impl<'le> PartialEq for GeckoElement<'le> {
|
||||
|
|
|
@ -12,7 +12,7 @@ use animation::{self, Animation, PropertyAnimation};
|
|||
use atomic_refcell::AtomicRefMut;
|
||||
use cache::LRUCache;
|
||||
use cascade_info::CascadeInfo;
|
||||
use context::{SharedStyleContext, StyleContext};
|
||||
use context::{SequentialTask, SharedStyleContext, StyleContext};
|
||||
use data::{ComputedStyle, ElementData, ElementStyles, PseudoRuleNodes, PseudoStyles};
|
||||
use dom::{SendElement, TElement, TNode};
|
||||
use properties::{CascadeFlags, ComputedValues, SHAREABLE, SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP, cascade};
|
||||
|
@ -22,7 +22,8 @@ use rule_tree::{CascadeLevel, StrongRuleNode};
|
|||
use selector_parser::{PseudoElement, RestyleDamage, SelectorImpl};
|
||||
use selectors::MatchAttr;
|
||||
use selectors::bloom::BloomFilter;
|
||||
use selectors::matching::{AFFECTED_BY_PSEUDO_ELEMENTS, AFFECTED_BY_STYLE_ATTRIBUTE, MatchingReason, StyleRelations};
|
||||
use selectors::matching::{AFFECTED_BY_PSEUDO_ELEMENTS, AFFECTED_BY_STYLE_ATTRIBUTE};
|
||||
use selectors::matching::{ElementSelectorFlags, StyleRelations};
|
||||
use servo_config::opts;
|
||||
use sink::ForgetfulSink;
|
||||
use std::collections::HashMap;
|
||||
|
@ -577,8 +578,7 @@ impl<E: TElement> PrivateMatchMethods for E {}
|
|||
pub trait MatchMethods : TElement {
|
||||
/// Runs selector matching of this element, and returns the result.
|
||||
fn match_element(&self,
|
||||
context: &StyleContext<Self>,
|
||||
parent_bf: Option<&BloomFilter>)
|
||||
context: &mut StyleContext<Self>)
|
||||
-> MatchResults
|
||||
{
|
||||
let mut applicable_declarations =
|
||||
|
@ -587,16 +587,17 @@ pub trait MatchMethods : TElement {
|
|||
let stylist = &context.shared.stylist;
|
||||
let style_attribute = self.style_attribute();
|
||||
let animation_rules = self.get_animation_rules(None);
|
||||
let mut flags = ElementSelectorFlags::empty();
|
||||
|
||||
// Compute the primary rule node.
|
||||
let mut primary_relations =
|
||||
stylist.push_applicable_declarations(self,
|
||||
parent_bf,
|
||||
Some(context.thread_local.bloom_filter.filter()),
|
||||
style_attribute,
|
||||
animation_rules,
|
||||
None,
|
||||
&mut applicable_declarations,
|
||||
MatchingReason::ForStyling);
|
||||
&mut flags);
|
||||
let primary_rule_node = compute_rule_node(context, &mut applicable_declarations);
|
||||
|
||||
// Compute the pseudo rule nodes.
|
||||
|
@ -604,11 +605,12 @@ pub trait MatchMethods : TElement {
|
|||
SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| {
|
||||
debug_assert!(applicable_declarations.is_empty());
|
||||
let pseudo_animation_rules = self.get_animation_rules(Some(&pseudo));
|
||||
stylist.push_applicable_declarations(self, parent_bf, None,
|
||||
pseudo_animation_rules,
|
||||
stylist.push_applicable_declarations(self,
|
||||
Some(context.thread_local.bloom_filter.filter()),
|
||||
None, pseudo_animation_rules,
|
||||
Some(&pseudo),
|
||||
&mut applicable_declarations,
|
||||
MatchingReason::ForStyling);
|
||||
&mut flags);
|
||||
|
||||
if !applicable_declarations.is_empty() {
|
||||
let rule_node = compute_rule_node(context, &mut applicable_declarations);
|
||||
|
@ -621,6 +623,22 @@ pub trait MatchMethods : TElement {
|
|||
primary_relations |= AFFECTED_BY_PSEUDO_ELEMENTS;
|
||||
}
|
||||
|
||||
// Apply the selector flags.
|
||||
let self_flags = flags.for_self();
|
||||
if !self_flags.is_empty() {
|
||||
unsafe { self.set_selector_flags(self_flags); }
|
||||
}
|
||||
let parent_flags = flags.for_parent();
|
||||
if !parent_flags.is_empty() {
|
||||
if let Some(p) = self.parent_element() {
|
||||
// Avoid the overhead of the SequentialTask if the flags are already set.
|
||||
if !p.has_selector_flags(parent_flags) {
|
||||
let task = SequentialTask::set_selector_flags(p, parent_flags);
|
||||
context.thread_local.tasks.push(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MatchResults {
|
||||
primary: primary_rule_node,
|
||||
relations: primary_relations,
|
||||
|
|
|
@ -26,7 +26,6 @@ use context::TraversalStatistics;
|
|||
use dom::{OpaqueNode, SendNode, TElement, TNode};
|
||||
use rayon;
|
||||
use scoped_tls::ScopedTLS;
|
||||
use servo_config::opts;
|
||||
use std::borrow::Borrow;
|
||||
use traversal::{DomTraversal, PerLevelTraversalData, PreTraverseToken};
|
||||
|
||||
|
@ -75,7 +74,7 @@ pub fn traverse_dom<E, D>(traversal: &D,
|
|||
});
|
||||
|
||||
// Dump statistics to stdout if requested.
|
||||
if TraversalStatistics::should_dump() || opts::get().style_sharing_stats {
|
||||
if TraversalStatistics::should_dump() {
|
||||
let slots = unsafe { tls.unsafe_get() };
|
||||
let aggregate = slots.iter().fold(TraversalStatistics::default(), |acc, t| {
|
||||
match *t.borrow() {
|
||||
|
|
|
@ -15,7 +15,7 @@ use gecko_bindings::structs::nsRestyleHint;
|
|||
use heapsize::HeapSizeOf;
|
||||
use selector_parser::{AttrValue, NonTSPseudoClass, Snapshot, SelectorImpl};
|
||||
use selectors::{Element, MatchAttr};
|
||||
use selectors::matching::{MatchingReason, StyleRelations};
|
||||
use selectors::matching::{ElementSelectorFlags, StyleRelations};
|
||||
use selectors::matching::matches_complex_selector;
|
||||
use selectors::parser::{AttrSelector, Combinator, ComplexSelector, SimpleSelector};
|
||||
use std::clone::Clone;
|
||||
|
@ -524,14 +524,16 @@ impl DependencySet {
|
|||
(attrs_changed && dep.sensitivities.attrs),
|
||||
"Testing a known ineffective dependency?");
|
||||
if (attrs_changed || state_changes.intersects(dep.sensitivities.states)) && !hint.intersects(dep.hint) {
|
||||
// We can ignore the selector flags, since they would have already been set during
|
||||
// original matching for any element that might change its matching behavior here.
|
||||
let matched_then =
|
||||
matches_complex_selector(&dep.selector, snapshot, None,
|
||||
&mut StyleRelations::empty(),
|
||||
MatchingReason::Other);
|
||||
&mut ElementSelectorFlags::empty());
|
||||
let matches_now =
|
||||
matches_complex_selector(&dep.selector, element, None,
|
||||
&mut StyleRelations::empty(),
|
||||
MatchingReason::Other);
|
||||
&mut ElementSelectorFlags::empty());
|
||||
if matched_then != matches_now {
|
||||
hint.insert(dep.hint);
|
||||
}
|
||||
|
|
|
@ -18,12 +18,12 @@ use properties::{self, CascadeFlags, ComputedValues, INHERIT_ALL};
|
|||
use properties::PropertyDeclarationBlock;
|
||||
use restyle_hints::{RestyleHint, DependencySet};
|
||||
use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
|
||||
use selector_parser::{ElementExt, SelectorImpl, PseudoElement, Snapshot};
|
||||
use selector_parser::{SelectorImpl, PseudoElement, Snapshot};
|
||||
use selectors::Element;
|
||||
use selectors::bloom::BloomFilter;
|
||||
use selectors::matching::{AFFECTED_BY_ANIMATIONS, AFFECTED_BY_TRANSITIONS};
|
||||
use selectors::matching::{AFFECTED_BY_STYLE_ATTRIBUTE, AFFECTED_BY_PRESENTATIONAL_HINTS};
|
||||
use selectors::matching::{MatchingReason, StyleRelations, matches_complex_selector};
|
||||
use selectors::matching::{ElementSelectorFlags, StyleRelations, matches_complex_selector};
|
||||
use selectors::parser::{Selector, SimpleSelector, LocalName as LocalNameSelector, ComplexSelector};
|
||||
use sink::Push;
|
||||
use smallvec::VecLike;
|
||||
|
@ -34,6 +34,7 @@ use std::hash::Hash;
|
|||
use std::sync::Arc;
|
||||
use style_traits::viewport::ViewportConstraints;
|
||||
use stylesheets::{CssRule, Origin, StyleRule, Stylesheet, UserAgentStylesheets};
|
||||
use thread_state;
|
||||
use viewport::{self, MaybeNew, ViewportRule};
|
||||
|
||||
pub use ::fnv::FnvHashMap;
|
||||
|
@ -368,7 +369,7 @@ impl Stylist {
|
|||
parent: &Arc<ComputedValues>,
|
||||
default: &Arc<ComputedValues>)
|
||||
-> Option<ComputedStyle>
|
||||
where E: ElementExt +
|
||||
where E: TElement +
|
||||
fmt::Debug +
|
||||
PresentationalHintsSynthetizer
|
||||
{
|
||||
|
@ -379,13 +380,14 @@ impl Stylist {
|
|||
|
||||
let mut declarations = vec![];
|
||||
|
||||
let mut flags = ElementSelectorFlags::empty();
|
||||
self.push_applicable_declarations(element,
|
||||
None,
|
||||
None,
|
||||
AnimationRules(None, None),
|
||||
Some(pseudo),
|
||||
&mut declarations,
|
||||
MatchingReason::ForStyling);
|
||||
&mut flags);
|
||||
|
||||
let rule_node =
|
||||
self.rule_tree.insert_ordered_rules(
|
||||
|
@ -400,6 +402,28 @@ impl Stylist {
|
|||
Box::new(StdoutErrorReporter),
|
||||
CascadeFlags::empty());
|
||||
|
||||
// Apply the selector flags. We should be in sequential mode already,
|
||||
// so we can directly apply the parent flags.
|
||||
if cfg!(feature = "servo") {
|
||||
// Servo calls this function from the worker, but only for internal
|
||||
// pseudos, so we should never generate selector flags here.
|
||||
debug_assert!(flags.is_empty());
|
||||
} else {
|
||||
// Gecko calls this from sequential mode, so we can directly apply
|
||||
// the flags.
|
||||
debug_assert!(thread_state::get() == thread_state::LAYOUT);
|
||||
let self_flags = flags.for_self();
|
||||
if !self_flags.is_empty() {
|
||||
unsafe { element.set_selector_flags(self_flags); }
|
||||
}
|
||||
let parent_flags = flags.for_parent();
|
||||
if !parent_flags.is_empty() {
|
||||
if let Some(p) = element.parent_element() {
|
||||
unsafe { p.set_selector_flags(parent_flags); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(ComputedStyle::new(rule_node, Arc::new(computed)))
|
||||
}
|
||||
|
||||
|
@ -495,8 +519,8 @@ impl Stylist {
|
|||
animation_rules: AnimationRules,
|
||||
pseudo_element: Option<&PseudoElement>,
|
||||
applicable_declarations: &mut V,
|
||||
reason: MatchingReason) -> StyleRelations
|
||||
where E: ElementExt +
|
||||
flags: &mut ElementSelectorFlags) -> StyleRelations
|
||||
where E: TElement +
|
||||
fmt::Debug +
|
||||
PresentationalHintsSynthetizer,
|
||||
V: Push<ApplicableDeclarationBlock> + VecLike<ApplicableDeclarationBlock>
|
||||
|
@ -521,7 +545,7 @@ impl Stylist {
|
|||
parent_bf,
|
||||
applicable_declarations,
|
||||
&mut relations,
|
||||
reason,
|
||||
flags,
|
||||
CascadeLevel::UANormal);
|
||||
debug!("UA normal: {:?}", relations);
|
||||
|
||||
|
@ -545,14 +569,14 @@ impl Stylist {
|
|||
parent_bf,
|
||||
applicable_declarations,
|
||||
&mut relations,
|
||||
reason,
|
||||
flags,
|
||||
CascadeLevel::UserNormal);
|
||||
debug!("user normal: {:?}", relations);
|
||||
map.author.get_all_matching_rules(element,
|
||||
parent_bf,
|
||||
applicable_declarations,
|
||||
&mut relations,
|
||||
reason,
|
||||
flags,
|
||||
CascadeLevel::AuthorNormal);
|
||||
debug!("author normal: {:?}", relations);
|
||||
|
||||
|
@ -586,7 +610,7 @@ impl Stylist {
|
|||
parent_bf,
|
||||
applicable_declarations,
|
||||
&mut relations,
|
||||
reason,
|
||||
flags,
|
||||
CascadeLevel::AuthorImportant);
|
||||
|
||||
debug!("author important: {:?}", relations);
|
||||
|
@ -609,7 +633,7 @@ impl Stylist {
|
|||
parent_bf,
|
||||
applicable_declarations,
|
||||
&mut relations,
|
||||
reason,
|
||||
flags,
|
||||
CascadeLevel::UserImportant);
|
||||
|
||||
debug!("user important: {:?}", relations);
|
||||
|
@ -622,7 +646,7 @@ impl Stylist {
|
|||
parent_bf,
|
||||
applicable_declarations,
|
||||
&mut relations,
|
||||
reason,
|
||||
flags,
|
||||
CascadeLevel::UAImportant);
|
||||
|
||||
debug!("UA important: {:?}", relations);
|
||||
|
@ -663,7 +687,7 @@ impl Stylist {
|
|||
pub fn match_same_not_common_style_affecting_attributes_rules<E>(&self,
|
||||
element: &E,
|
||||
candidate: &E) -> bool
|
||||
where E: ElementExt,
|
||||
where E: TElement,
|
||||
{
|
||||
use selectors::matching::StyleRelations;
|
||||
use selectors::matching::matches_complex_selector;
|
||||
|
@ -678,11 +702,11 @@ impl Stylist {
|
|||
let element_matches =
|
||||
matches_complex_selector(&selector.complex_selector, element,
|
||||
None, &mut StyleRelations::empty(),
|
||||
MatchingReason::Other);
|
||||
&mut ElementSelectorFlags::empty());
|
||||
let candidate_matches =
|
||||
matches_complex_selector(&selector.complex_selector, candidate,
|
||||
None, &mut StyleRelations::empty(),
|
||||
MatchingReason::Other);
|
||||
&mut ElementSelectorFlags::empty());
|
||||
|
||||
if element_matches != candidate_matches {
|
||||
return false;
|
||||
|
@ -704,7 +728,7 @@ impl Stylist {
|
|||
pub fn match_same_sibling_affecting_rules<E>(&self,
|
||||
element: &E,
|
||||
candidate: &E) -> bool
|
||||
where E: ElementExt,
|
||||
where E: TElement,
|
||||
{
|
||||
use selectors::matching::StyleRelations;
|
||||
use selectors::matching::matches_complex_selector;
|
||||
|
@ -717,12 +741,12 @@ impl Stylist {
|
|||
let element_matches =
|
||||
matches_complex_selector(&selector.complex_selector, element,
|
||||
None, &mut StyleRelations::empty(),
|
||||
MatchingReason::Other);
|
||||
&mut ElementSelectorFlags::empty());
|
||||
|
||||
let candidate_matches =
|
||||
matches_complex_selector(&selector.complex_selector, candidate,
|
||||
None, &mut StyleRelations::empty(),
|
||||
MatchingReason::Other);
|
||||
&mut ElementSelectorFlags::empty());
|
||||
|
||||
if element_matches != candidate_matches {
|
||||
debug!("match_same_sibling_affecting_rules: Failure due to {:?}",
|
||||
|
@ -860,7 +884,7 @@ impl SelectorMap {
|
|||
parent_bf: Option<&BloomFilter>,
|
||||
matching_rules_list: &mut V,
|
||||
relations: &mut StyleRelations,
|
||||
reason: MatchingReason,
|
||||
flags: &mut ElementSelectorFlags,
|
||||
cascade_level: CascadeLevel)
|
||||
where E: Element<Impl=SelectorImpl>,
|
||||
V: VecLike<ApplicableDeclarationBlock>
|
||||
|
@ -878,7 +902,7 @@ impl SelectorMap {
|
|||
&id,
|
||||
matching_rules_list,
|
||||
relations,
|
||||
reason,
|
||||
flags,
|
||||
cascade_level)
|
||||
}
|
||||
|
||||
|
@ -889,7 +913,7 @@ impl SelectorMap {
|
|||
class,
|
||||
matching_rules_list,
|
||||
relations,
|
||||
reason,
|
||||
flags,
|
||||
cascade_level);
|
||||
});
|
||||
|
||||
|
@ -904,7 +928,7 @@ impl SelectorMap {
|
|||
element.get_local_name(),
|
||||
matching_rules_list,
|
||||
relations,
|
||||
reason,
|
||||
flags,
|
||||
cascade_level);
|
||||
|
||||
SelectorMap::get_matching_rules(element,
|
||||
|
@ -912,7 +936,7 @@ impl SelectorMap {
|
|||
&self.other_rules,
|
||||
matching_rules_list,
|
||||
relations,
|
||||
reason,
|
||||
flags,
|
||||
cascade_level);
|
||||
|
||||
// Sort only the rules we just added.
|
||||
|
@ -963,7 +987,7 @@ impl SelectorMap {
|
|||
key: &BorrowedStr,
|
||||
matching_rules: &mut Vector,
|
||||
relations: &mut StyleRelations,
|
||||
reason: MatchingReason,
|
||||
flags: &mut ElementSelectorFlags,
|
||||
cascade_level: CascadeLevel)
|
||||
where E: Element<Impl=SelectorImpl>,
|
||||
Str: Borrow<BorrowedStr> + Eq + Hash,
|
||||
|
@ -976,7 +1000,7 @@ impl SelectorMap {
|
|||
rules,
|
||||
matching_rules,
|
||||
relations,
|
||||
reason,
|
||||
flags,
|
||||
cascade_level)
|
||||
}
|
||||
}
|
||||
|
@ -987,7 +1011,7 @@ impl SelectorMap {
|
|||
rules: &[Rule],
|
||||
matching_rules: &mut V,
|
||||
relations: &mut StyleRelations,
|
||||
reason: MatchingReason,
|
||||
flags: &mut ElementSelectorFlags,
|
||||
cascade_level: CascadeLevel)
|
||||
where E: Element<Impl=SelectorImpl>,
|
||||
V: VecLike<ApplicableDeclarationBlock>
|
||||
|
@ -1002,7 +1026,7 @@ impl SelectorMap {
|
|||
};
|
||||
if any_declaration_for_importance &&
|
||||
matches_complex_selector(&*rule.selector, element, parent_bf,
|
||||
relations, reason) {
|
||||
relations, flags) {
|
||||
matching_rules.push(
|
||||
rule.to_applicable_declaration_block(cascade_level));
|
||||
}
|
||||
|
|
|
@ -312,7 +312,7 @@ pub trait DomTraversal<E: TElement> : Sync {
|
|||
}
|
||||
|
||||
/// Helper for the function below.
|
||||
fn resolve_style_internal<E, F>(context: &StyleContext<E>, element: E, ensure_data: &F)
|
||||
fn resolve_style_internal<E, F>(context: &mut StyleContext<E>, element: E, ensure_data: &F)
|
||||
-> Option<E>
|
||||
where E: TElement,
|
||||
F: Fn(E),
|
||||
|
@ -324,12 +324,22 @@ fn resolve_style_internal<E, F>(context: &StyleContext<E>, element: E, ensure_da
|
|||
// If the Element isn't styled, we need to compute its style.
|
||||
if data.get_styles().is_none() {
|
||||
// Compute the parent style if necessary.
|
||||
if let Some(parent) = element.parent_element() {
|
||||
display_none_root = resolve_style_internal(context, parent, ensure_data);
|
||||
let parent = element.parent_element();
|
||||
if let Some(p) = parent {
|
||||
display_none_root = resolve_style_internal(context, p, ensure_data);
|
||||
}
|
||||
|
||||
// Maintain the bloom filter. If it doesn't exist, we need to build it
|
||||
// from scratch. Otherwise we just need to push the parent.
|
||||
if context.thread_local.bloom_filter.is_empty() {
|
||||
context.thread_local.bloom_filter.rebuild(element);
|
||||
} else {
|
||||
context.thread_local.bloom_filter.push(parent.unwrap());
|
||||
context.thread_local.bloom_filter.assert_complete(element);
|
||||
}
|
||||
|
||||
// Compute our style.
|
||||
let match_results = element.match_element(context, None);
|
||||
let match_results = element.match_element(context);
|
||||
let shareable = match_results.primary_is_shareable();
|
||||
element.cascade_node(context, &mut data, element.parent_element(),
|
||||
match_results.primary,
|
||||
|
@ -355,13 +365,16 @@ fn resolve_style_internal<E, F>(context: &StyleContext<E>, element: E, ensure_da
|
|||
/// first styled Element, ignoring pending restyles. The resolved style is
|
||||
/// made available via a callback, and can be dropped by the time this function
|
||||
/// returns in the display:none subtree case.
|
||||
pub fn resolve_style<E, F, G, H>(context: &StyleContext<E>, element: E,
|
||||
pub fn resolve_style<E, F, G, H>(context: &mut StyleContext<E>, element: E,
|
||||
ensure_data: &F, clear_data: &G, callback: H)
|
||||
where E: TElement,
|
||||
F: Fn(E),
|
||||
G: Fn(E),
|
||||
H: FnOnce(&ElementStyles)
|
||||
{
|
||||
// Clear the bloom filter, just in case the caller is reusing TLS.
|
||||
context.thread_local.bloom_filter.clear();
|
||||
|
||||
// Resolve styles up the tree.
|
||||
let display_none_root = resolve_style_internal(context, element, ensure_data);
|
||||
|
||||
|
@ -499,8 +512,7 @@ fn compute_style<E, D>(_traversal: &D,
|
|||
// Perform the CSS selector matching.
|
||||
context.thread_local.statistics.elements_matched += 1;
|
||||
|
||||
let filter = context.thread_local.bloom_filter.filter();
|
||||
Some(element.match_element(context, Some(filter)))
|
||||
Some(element.match_element(context))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue