diff options
Diffstat (limited to 'components/style/traversal.rs')
-rw-r--r-- | components/style/traversal.rs | 61 |
1 files changed, 57 insertions, 4 deletions
diff --git a/components/style/traversal.rs b/components/style/traversal.rs index 146069b1bc3..60df72ffeba 100644 --- a/components/style/traversal.rs +++ b/components/style/traversal.rs @@ -13,6 +13,7 @@ use restyle_hints::{HintComputationContext, RestyleHint}; use selector_parser::RestyleDamage; use sharing::StyleSharingBehavior; #[cfg(feature = "servo")] use servo_config::opts; +use smallvec::SmallVec; use std::borrow::BorrowMut; /// A per-traversal-level chunk of data. This is sent down by the traversal, and @@ -41,6 +42,8 @@ bitflags! { /// Traverse and update all elements with CSS animations since /// @keyframes rules may have changed const FOR_CSS_RULE_CHANGES = 0x08, + /// Only include user agent style sheets when selector matching. + const FOR_DEFAULT_STYLES = 0x10, } } @@ -64,6 +67,12 @@ impl TraversalFlags { pub fn for_css_rule_changes(&self) -> bool { self.contains(FOR_CSS_RULE_CHANGES) } + + /// Returns true if the traversal is to compute the default computed + /// styles for an element. + pub fn for_default_styles(&self) -> bool { + self.contains(FOR_DEFAULT_STYLES) + } } /// This structure exists to enforce that callers invoke pre_traverse, and also @@ -537,10 +546,13 @@ fn resolve_style_internal<E, F>(context: &mut StyleContext<E>, StyleSharingBehavior::Disallow); context.thread_local.end_element(element); - // Conservatively mark us as having dirty descendants, since there might - // be other unstyled siblings we miss when walking straight up the parent - // chain. - unsafe { element.note_descendants::<DirtyDescendants>() }; + if !context.shared.traversal_flags.for_default_styles() { + // Conservatively mark us as having dirty descendants, since there might + // be other unstyled siblings we miss when walking straight up the parent + // chain. No need to do this if we're computing default styles, since + // resolve_default_style will want the tree to be left as it is. + unsafe { element.note_descendants::<DirtyDescendants>() }; + } } // If we're display:none and none of our ancestors are, we're the root @@ -598,6 +610,47 @@ pub fn resolve_style<E, F, G, H>(context: &mut StyleContext<E>, element: E, } } +/// Manually resolve default styles for the given Element, which are the styles +/// only taking into account user agent and user cascade levels. The resolved +/// style is made available via a callback, and will be dropped by the time this +/// function returns. +pub fn resolve_default_style<E, F, G, H>(context: &mut StyleContext<E>, + element: E, + ensure_data: &F, + set_data: &G, + callback: H) + where E: TElement, + F: Fn(E), + G: Fn(E, Option<ElementData>) -> Option<ElementData>, + H: FnOnce(&ElementStyles) +{ + // Save and clear out element data from the element and its ancestors. + let mut old_data: SmallVec<[(E, Option<ElementData>); 8]> = SmallVec::new(); + { + let mut e = element; + loop { + old_data.push((e, set_data(e, None))); + match e.parent_element() { + Some(parent) => e = parent, + None => break, + } + } + } + + // Resolve styles up the tree. + resolve_style_internal(context, element, ensure_data); + + // Make them available for the scope of the callback. The callee may use the + // argument, or perform any other processing that requires the styles to exist + // on the Element. + callback(element.borrow_data().unwrap().styles()); + + // Swap the old element data back into the element and its ancestors. + for entry in old_data { + set_data(entry.0, entry.1); + } +} + /// Calculates the style for a single node. #[inline] #[allow(unsafe_code)] |