diff options
author | Bobby Holley <bobbyholley@gmail.com> | 2016-10-30 20:45:29 -0700 |
---|---|---|
committer | Bobby Holley <bobbyholley@gmail.com> | 2016-11-01 11:03:04 -0700 |
commit | 71b9004d861e3b381178e1c668bc78423e6d4bc1 (patch) | |
tree | 22671ab8097485a78273155747144e56a6ca99a6 | |
parent | b98bb241dc84196dde1c836ff965d7d77fdd458a (diff) | |
download | servo-71b9004d861e3b381178e1c668bc78423e6d4bc1.tar.gz servo-71b9004d861e3b381178e1c668bc78423e6d4bc1.zip |
Replace begin_styling with a centralized mechanism to set a node up for either styling or restyling.
We also make sure that an element never has an ElementData with ElementDataStyles::Uninitialized,
and eagerly call prepare_for_styling whenever an ElementData is instantiated.
MozReview-Commit-ID: 9YP6eSmdMt0
-rw-r--r-- | components/layout/traversal.rs | 7 | ||||
-rw-r--r-- | components/layout/wrapper.rs | 32 | ||||
-rw-r--r-- | components/script/layout_wrapper.rs | 47 | ||||
-rw-r--r-- | components/script_layout_interface/wrapper_traits.rs | 4 | ||||
-rw-r--r-- | components/style/atomic_refcell.rs | 4 | ||||
-rw-r--r-- | components/style/dom.rs | 45 | ||||
-rw-r--r-- | components/style/gecko/traversal.rs | 2 | ||||
-rw-r--r-- | components/style/gecko/wrapper.rs | 21 | ||||
-rw-r--r-- | components/style/matching.rs | 13 | ||||
-rw-r--r-- | components/style/traversal.rs | 54 |
10 files changed, 127 insertions, 102 deletions
diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index 49b8f1a32c6..d2ccad89d86 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -22,7 +22,7 @@ use style::traversal::{recalc_style_at, remove_from_bloom_filter}; use style::traversal::RestyleResult; use style::traversal::take_thread_local_bloom_filter; use util::opts; -use wrapper::{LayoutNodeHelpers, LayoutNodeLayoutData}; +use wrapper::{GetRawData, LayoutNodeHelpers, LayoutNodeLayoutData}; pub struct RecalcStyleAndConstructFlows<'lc> { context: LayoutContext<'lc>, @@ -131,9 +131,10 @@ impl<'lc, N> DomTraversalContext<N> for RecalcStyleAndConstructFlows<'lc> } } - fn ensure_element_data(element: &N::ConcreteElement) -> &AtomicRefCell<ElementData> { + #[allow(unsafe_code)] + unsafe fn ensure_element_data(element: &N::ConcreteElement) -> &AtomicRefCell<ElementData> { element.as_node().initialize_data(); - element.get_style_data().unwrap() + element.get_data().unwrap() } fn local_context(&self) -> &LocalStyleContext { diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 57bd44a5798..bc524395be2 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -33,10 +33,12 @@ use core::nonzero::NonZero; use data::{LayoutDataFlags, PersistentLayoutData}; use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutData}; -use script_layout_interface::wrapper_traits::{ThreadSafeLayoutElement, ThreadSafeLayoutNode}; +use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; use script_layout_interface::wrapper_traits::GetLayoutData; use style::atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; use style::computed_values::content::{self, ContentItem}; +use style::dom::TElement; +use style::traversal::prepare_for_styling; pub type NonOpaqueStyleAndLayoutData = AtomicRefCell<PersistentLayoutData>; @@ -62,12 +64,24 @@ impl<T: GetLayoutData> LayoutNodeLayoutData for T { } } +pub trait GetRawData { + fn get_raw_data(&self) -> Option<&NonOpaqueStyleAndLayoutData>; +} + +impl<T: GetLayoutData> GetRawData for T { + fn get_raw_data(&self) -> Option<&NonOpaqueStyleAndLayoutData> { + self.get_style_and_layout_data().map(|opaque| { + let container = *opaque.ptr as *mut NonOpaqueStyleAndLayoutData; + unsafe { &*container } + }) + } +} + pub trait LayoutNodeHelpers { fn initialize_data(&self); - fn get_raw_data(&self) -> Option<&NonOpaqueStyleAndLayoutData>; } -impl<T: GetLayoutData> LayoutNodeHelpers for T { +impl<T: LayoutNode> LayoutNodeHelpers for T { fn initialize_data(&self) { if self.get_raw_data().is_none() { let ptr: *mut NonOpaqueStyleAndLayoutData = @@ -75,16 +89,12 @@ impl<T: GetLayoutData> LayoutNodeHelpers for T { let opaque = OpaqueStyleAndLayoutData { ptr: unsafe { NonZero::new(ptr as *mut AtomicRefCell<PartialPersistentLayoutData>) } }; - self.init_style_and_layout_data(opaque); + unsafe { self.init_style_and_layout_data(opaque) }; + if let Some(el) = self.as_element() { + let _ = prepare_for_styling(el, el.get_data().unwrap()); + } }; } - - fn get_raw_data(&self) -> Option<&NonOpaqueStyleAndLayoutData> { - self.get_style_and_layout_data().map(|opaque| { - let container = *opaque.ptr as *mut NonOpaqueStyleAndLayoutData; - unsafe { &*container } - }) - } } pub trait ThreadSafeLayoutNodeHelpers { diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs index 8e3bbbb737b..2120f4ae5cc 100644 --- a/components/script/layout_wrapper.rs +++ b/components/script/layout_wrapper.rs @@ -56,7 +56,7 @@ use std::mem::transmute; use std::sync::Arc; use std::sync::atomic::Ordering; use string_cache::{Atom, Namespace}; -use style::atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; +use style::atomic_refcell::{AtomicRef, AtomicRefCell}; use style::attr::AttrValue; use style::computed_values::display; use style::context::SharedStyleContext; @@ -252,6 +252,10 @@ impl<'ln> LayoutNode for ServoLayoutNode<'ln> { self.script_type_id().into() } + unsafe fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData) { + self.get_jsmanaged().init_style_and_layout_data(data); + } + fn has_changed(&self) -> bool { unsafe { self.node.get_flag(HAS_CHANGED) } } @@ -269,42 +273,24 @@ impl<'ln> GetLayoutData for ServoLayoutNode<'ln> { self.get_jsmanaged().get_style_and_layout_data() } } - - fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData) { - unsafe { - self.get_jsmanaged().init_style_and_layout_data(data); - } - } } impl<'le> GetLayoutData for ServoLayoutElement<'le> { fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData> { self.as_node().get_style_and_layout_data() } - - fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData) { - self.as_node().init_style_and_layout_data(data) - } } impl<'ln> GetLayoutData for ServoThreadSafeLayoutNode<'ln> { fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData> { self.node.get_style_and_layout_data() } - - fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData) { - self.node.init_style_and_layout_data(data) - } } impl<'le> GetLayoutData for ServoThreadSafeLayoutElement<'le> { fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData> { self.element.as_node().get_style_and_layout_data() } - - fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData) { - self.element.as_node().init_style_and_layout_data(data) - } } impl<'ln> ServoLayoutNode<'ln> { @@ -506,20 +492,11 @@ impl<'le> TElement for ServoLayoutElement<'le> { old_value - 1 } - fn begin_styling(&self) -> AtomicRefMut<ElementData> { - let mut data = self.mutate_data().unwrap(); - data.gather_previous_styles(|| None); - data - } - fn borrow_data(&self) -> Option<AtomicRef<ElementData>> { - self.get_style_data().map(|d| d.borrow()) + self.get_data().map(|d| d.borrow()) } -} - -impl<'le> LayoutElement for ServoLayoutElement<'le> { - fn get_style_data(&self) -> Option<&AtomicRefCell<ElementData>> { + fn get_data(&self) -> Option<&AtomicRefCell<ElementData>> { unsafe { self.get_style_and_layout_data().map(|d| { let ppld: &AtomicRefCell<PartialPersistentLayoutData> = &**d.ptr; @@ -551,10 +528,6 @@ impl<'le> ServoLayoutElement<'le> { } } - fn mutate_data(&self) -> Option<AtomicRefMut<ElementData>> { - self.get_style_data().map(|d| d.borrow_mut()) - } - fn get_partial_layout_data(&self) -> Option<&AtomicRefCell<PartialPersistentLayoutData>> { unsafe { self.get_style_and_layout_data().map(|d| &**d.ptr) @@ -836,7 +809,7 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { // also not visible to script.) debug_assert!(self.is_text_node()); let parent = self.node.parent_node().unwrap().as_element().unwrap(); - let parent_data = parent.get_style_data().unwrap().borrow(); + let parent_data = parent.get_data().unwrap().borrow(); parent_data.current_styles().primary.clone() } @@ -1089,10 +1062,12 @@ impl<'le> ThreadSafeLayoutElement for ServoThreadSafeLayoutElement<'le> { } fn get_style_data(&self) -> Option<&AtomicRefCell<ElementData>> { - self.element.get_style_data() + self.element.get_data() } } +impl<'le> LayoutElement for ServoLayoutElement<'le> {} + /// This implementation of `::selectors::Element` is used for implementing lazy /// pseudo-elements. /// diff --git a/components/script_layout_interface/wrapper_traits.rs b/components/script_layout_interface/wrapper_traits.rs index 470685979b7..5f712046eea 100644 --- a/components/script_layout_interface/wrapper_traits.rs +++ b/components/script_layout_interface/wrapper_traits.rs @@ -73,7 +73,6 @@ impl<T> PseudoElementType<T> { /// Trait to abstract access to layout data across various data structures. pub trait GetLayoutData { fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData>; - fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData); } /// A wrapper so that layout can access only the methods that it should have access to. Layout must @@ -85,6 +84,8 @@ pub trait LayoutNode: GetLayoutData + TNode { /// Returns the type ID of this node. fn type_id(&self) -> LayoutNodeType; + unsafe fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData); + fn has_changed(&self) -> bool; unsafe fn clear_dirty_bits(&self); @@ -274,7 +275,6 @@ pub trait DangerousThreadSafeLayoutNode: ThreadSafeLayoutNode { } pub trait LayoutElement: Clone + Copy + Sized + Debug + GetLayoutData + TElement { - fn get_style_data(&self) -> Option<&AtomicRefCell<ElementData>>; } pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + Debug + diff --git a/components/style/atomic_refcell.rs b/components/style/atomic_refcell.rs index a45a682b638..409d669b595 100644 --- a/components/style/atomic_refcell.rs +++ b/components/style/atomic_refcell.rs @@ -27,10 +27,10 @@ impl<T> AtomicRefCell<T> { AtomicRefCell(RwLock::new(value)) } pub fn borrow(&self) -> AtomicRef<T> { - self.0.try_read().unwrap() + self.0.try_read().expect("already mutably borrowed") } pub fn borrow_mut(&self) -> AtomicRefMut<T> { - self.0.try_write().unwrap() + self.0.try_write().expect("already borrowed") } } diff --git a/components/style/dom.rs b/components/style/dom.rs index 7ab817ac2c6..46949946607 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -6,7 +6,7 @@ #![allow(unsafe_code)] -use atomic_refcell::{AtomicRef, AtomicRefMut}; +use atomic_refcell::{AtomicRef, AtomicRefCell}; use data::{ElementStyles, ElementData}; use element_state::ElementState; use parking_lot::RwLock; @@ -243,30 +243,43 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre Stop }; - match self.borrow_data() { - // No node data, no style on the frame. + let mut mode = match self.borrow_data() { + // No element data, no style on the frame. None if !self.frame_has_style() => Initial, - // No node data, style on the frame. + // No element data, style on the frame. None => mode_for_descendants, + // We have element data. Decide below. Some(d) => { - if d.restyle_data.is_some() || self.deprecated_dirty_bit_is_set() { - Restyle - } else { - debug_assert!(!self.frame_has_style()); // display:none etc + if d.has_current_styles() { + // The element has up-to-date style. + debug_assert!(!self.frame_has_style()); + debug_assert!(d.restyle_data.is_none()); mode_for_descendants + } else { + // The element needs processing. + if d.previous_styles().is_some() { + Restyle + } else { + Initial + } } }, + }; + + // Handle the deprecated dirty bit. This should go away soon. + if mode != Initial && self.deprecated_dirty_bit_is_set() { + mode = Restyle; } - } + mode - /// Sets up the appropriate data structures to style a node, returing a - /// mutable handle to the node data upon which further style calculations - /// can be performed. - fn begin_styling(&self) -> AtomicRefMut<ElementData>; + } /// Immutable borrows the ElementData. fn borrow_data(&self) -> Option<AtomicRef<ElementData>>; + /// Gets a reference to the ElementData container. + fn get_data(&self) -> Option<&AtomicRefCell<ElementData>>; + /// Properly marks nodes as dirty in response to restyle hints. fn note_restyle_hint<C: DomTraversalContext<Self::ConcreteNode>>(&self, hint: RestyleHint) { // Bail early if there's no restyling to do. @@ -285,13 +298,13 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre // Process hints. if hint.contains(RESTYLE_SELF) { - unsafe { C::ensure_element_data(self).borrow_mut().ensure_restyle_data(); } + unsafe { let _ = C::prepare_for_styling(self); } // XXX(emilio): For now, dirty implies dirty descendants if found. } else if hint.contains(RESTYLE_DESCENDANTS) { unsafe { self.set_dirty_descendants(); } let mut current = self.first_child_element(); while let Some(el) = current { - unsafe { C::ensure_element_data(&el).borrow_mut().ensure_restyle_data(); } + unsafe { let _ = C::prepare_for_styling(&el); } current = el.next_sibling_element(); } } @@ -299,7 +312,7 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre if hint.contains(RESTYLE_LATER_SIBLINGS) { let mut next = ::selectors::Element::next_sibling_element(self); while let Some(sib) = next { - unsafe { C::ensure_element_data(&sib).borrow_mut().ensure_restyle_data() }; + unsafe { let _ = C::prepare_for_styling(&sib); } next = ::selectors::Element::next_sibling_element(&sib); } } diff --git a/components/style/gecko/traversal.rs b/components/style/gecko/traversal.rs index 0825d83665f..4334cbeb6e0 100644 --- a/components/style/gecko/traversal.rs +++ b/components/style/gecko/traversal.rs @@ -55,7 +55,7 @@ impl<'lc, 'ln> DomTraversalContext<GeckoNode<'ln>> for RecalcStyleOnly<'lc> { } } - fn ensure_element_data<'a>(element: &'a GeckoElement<'ln>) -> &'a AtomicRefCell<ElementData> { + unsafe fn ensure_element_data<'a>(element: &'a GeckoElement<'ln>) -> &'a AtomicRefCell<ElementData> { element.ensure_data() } diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 045240565fb..d57d4ecd4a0 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -5,7 +5,7 @@ #![allow(unsafe_code)] -use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; +use atomic_refcell::{AtomicRef, AtomicRefCell}; use data::ElementData; use dom::{LayoutIterator, NodeInfo, TDocument, TElement, TNode, TRestyleDamage, UnsafeNode}; use dom::{OpaqueNode, PresentationalHintsSynthetizer}; @@ -337,12 +337,8 @@ impl<'le> GeckoElement<'le> { .get(pseudo).map(|c| c.clone())) } - fn get_node_data(&self) -> Option<&AtomicRefCell<ElementData>> { - unsafe { self.raw_node().mServoData.get().as_ref() } - } - pub fn ensure_data(&self) -> &AtomicRefCell<ElementData> { - match self.get_node_data() { + match self.get_data() { Some(x) => x, None => { let ptr = Box::into_raw(Box::new(AtomicRefCell::new(ElementData::new()))); @@ -431,7 +427,7 @@ impl<'le> TElement for GeckoElement<'le> { fn has_dirty_descendants(&self) -> bool { // Return true unconditionally if we're not yet styled. This is a hack // and should go away soon. - if self.get_node_data().is_none() { + if self.get_data().is_none() { return true; } self.flags() & (NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32) != 0 @@ -449,15 +445,14 @@ impl<'le> TElement for GeckoElement<'le> { panic!("Atomic child count not implemented in Gecko"); } - fn begin_styling(&self) -> AtomicRefMut<ElementData> { - let mut data = self.ensure_data().borrow_mut(); - data.gather_previous_styles(|| self.get_styles_from_frame()); - data + fn borrow_data(&self) -> Option<AtomicRef<ElementData>> { + self.get_data().map(|x| x.borrow()) } - fn borrow_data(&self) -> Option<AtomicRef<ElementData>> { - self.get_node_data().map(|x| x.borrow()) + fn get_data(&self) -> Option<&AtomicRefCell<ElementData>> { + unsafe { self.raw_node().mServoData.get().as_ref() } } + } impl<'le> PartialEq for GeckoElement<'le> { diff --git a/components/style/matching.rs b/components/style/matching.rs index a5216d14416..e90ff962a65 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -8,10 +8,11 @@ use animation; use arc_ptr_eq; +use atomic_refcell::AtomicRefMut; use cache::{LRUCache, SimpleHashCache}; use cascade_info::CascadeInfo; use context::{SharedStyleContext, StyleContext}; -use data::{ElementStyles, PseudoStyles}; +use data::{ElementData, ElementStyles, PseudoStyles}; use dom::{TElement, TNode, TRestyleDamage, UnsafeNode}; use properties::{CascadeFlags, ComputedValues, SHAREABLE, cascade}; use properties::longhands::display::computed_value as display; @@ -423,6 +424,7 @@ impl StyleSharingCandidateCache { pub fn insert_if_possible<E: TElement>(&mut self, element: &E, + style: &Arc<ComputedValues>, relations: StyleRelations) { use traversal::relations_are_shareable; @@ -441,9 +443,6 @@ impl StyleSharingCandidateCache { return; } - let data = element.borrow_data().unwrap(); - let style = &data.current_styles().primary; - let box_style = style.get_box(); if box_style.transition_property_count() > 0 { debug!("Failing to insert to the cache: transitions"); @@ -695,7 +694,8 @@ pub trait MatchMethods : TElement { unsafe fn share_style_if_possible(&self, style_sharing_candidate_cache: &mut StyleSharingCandidateCache, - shared_context: &SharedStyleContext) + shared_context: &SharedStyleContext, + data: &mut AtomicRefMut<ElementData>) -> StyleSharingResult<Self::ConcreteRestyleDamage> { if opts::get().disable_share_style_cache { return StyleSharingResult::CannotShare @@ -715,7 +715,6 @@ pub trait MatchMethods : TElement { match sharing_result { Ok(shared_style) => { // Yay, cache hit. Share the style. - let mut data = self.begin_styling(); // TODO: add the display: none optimisation here too! Even // better, factor it out/make it a bit more generic so Gecko @@ -855,6 +854,7 @@ pub trait MatchMethods : TElement { unsafe fn cascade_node<'a, Ctx>(&self, context: &Ctx, + mut data: AtomicRefMut<ElementData>, parent: Option<Self>, applicable_declarations: &ApplicableDeclarations) -> RestyleResult @@ -864,7 +864,6 @@ pub trait MatchMethods : TElement { let parent_data = parent.as_ref().map(|x| x.borrow_data().unwrap()); let parent_style = parent_data.as_ref().map(|x| &x.current_styles().primary); - let mut data = self.begin_styling(); let mut new_styles; let mut applicable_declarations_cache = diff --git a/components/style/traversal.rs b/components/style/traversal.rs index 5d5e5e6f418..38ed543d017 100644 --- a/components/style/traversal.rs +++ b/components/style/traversal.rs @@ -4,7 +4,7 @@ //! Traversing the DOM tree; the bloom filter. -use atomic_refcell::AtomicRefCell; +use atomic_refcell::{AtomicRefCell, AtomicRefMut}; use context::{LocalStyleContext, SharedStyleContext, StyleContext}; use data::ElementData; use dom::{OpaqueNode, StylingMode, TElement, TNode, UnsafeNode}; @@ -12,6 +12,7 @@ use matching::{ApplicableDeclarations, MatchMethods, StyleSharingResult}; use selectors::bloom::BloomFilter; use selectors::matching::StyleRelations; use std::cell::RefCell; +use std::mem; use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; use tid::tid; use util::opts; @@ -156,6 +157,18 @@ pub fn remove_from_bloom_filter<'a, N, C>(context: &C, root: OpaqueNode, node: N }; } +pub fn prepare_for_styling<E: TElement>(element: E, + data: &AtomicRefCell<ElementData>) + -> AtomicRefMut<ElementData> { + let mut d = data.borrow_mut(); + d.gather_previous_styles(|| element.get_styles_from_frame()); + if d.previous_styles().is_some() { + d.ensure_restyle_data(); + } + + d +} + pub trait DomTraversalContext<N: TNode> { type SharedContext: Sync + 'static; @@ -200,7 +213,17 @@ pub trait DomTraversalContext<N: TNode> { /// Ensures the existence of the ElementData, and returns it. This can't live /// on TNode because of the trait-based separation between Servo's script /// and layout crates. - fn ensure_element_data(element: &N::ConcreteElement) -> &AtomicRefCell<ElementData>; + /// + /// This is only safe to call in top-down traversal before processing the + /// children of |element|. + unsafe fn ensure_element_data(element: &N::ConcreteElement) -> &AtomicRefCell<ElementData>; + + /// Sets up the appropriate data structures to style or restyle a node, + /// returing a mutable handle to the node data upon which further style + /// calculations can be performed. + unsafe fn prepare_for_styling(element: &N::ConcreteElement) -> AtomicRefMut<ElementData> { + prepare_for_styling(*element, Self::ensure_element_data(element)) + } fn local_context(&self) -> &LocalStyleContext; } @@ -267,6 +290,7 @@ fn ensure_element_styled_internal<'a, E, C>(element: E, // probably not necessary since we're likely to be matching only a few // nodes, at best. let mut applicable_declarations = ApplicableDeclarations::new(); + let data = prepare_for_styling(element, element.get_data().unwrap()); let stylist = &context.shared_context().stylist; element.match_element(&**stylist, @@ -274,7 +298,7 @@ fn ensure_element_styled_internal<'a, E, C>(element: E, &mut applicable_declarations); unsafe { - element.cascade_node(context, parent, &applicable_declarations); + element.cascade_node(context, data, parent, &applicable_declarations); } } @@ -295,6 +319,8 @@ pub fn recalc_style_at<'a, E, C, D>(context: &'a C, let mode = element.styling_mode(); debug_assert!(mode != StylingMode::Stop, "Parent should not have enqueued us"); if mode != StylingMode::Traverse { + let mut data = unsafe { D::prepare_for_styling(&element) }; + // Check to see whether we can share a style with someone. let style_sharing_candidate_cache = &mut context.local_context().style_sharing_candidate_cache.borrow_mut(); @@ -302,7 +328,8 @@ pub fn recalc_style_at<'a, E, C, D>(context: &'a C, let sharing_result = if element.parent_element().is_none() { StyleSharingResult::CannotShare } else { - unsafe { element.share_style_if_possible(style_sharing_candidate_cache, context.shared_context()) } + unsafe { element.share_style_if_possible(style_sharing_candidate_cache, + context.shared_context(), &mut data) } }; // Otherwise, match and cascade selectors. @@ -334,14 +361,19 @@ pub fn recalc_style_at<'a, E, C, D>(context: &'a C, // Perform the CSS cascade. unsafe { - restyle_result = element.cascade_node(context, + restyle_result = element.cascade_node(context, data, element.parent_element(), &applicable_declarations); } // Add ourselves to the LRU cache. if let Some(element) = shareable_element { - style_sharing_candidate_cache.insert_if_possible(&element, relations); + style_sharing_candidate_cache.insert_if_possible(&element, + &element.borrow_data() + .unwrap() + .current_styles() + .primary, + relations); } } StyleSharingResult::StyleWasShared(index, damage, cached_restyle_result) => { @@ -350,6 +382,10 @@ pub fn recalc_style_at<'a, E, C, D>(context: &'a C, STYLE_SHARING_CACHE_HITS.fetch_add(1, Ordering::Relaxed); } style_sharing_candidate_cache.touch(index); + + // Drop the mutable borrow early, since Servo's set_restyle_damage also borrows. + mem::drop(data); + element.set_restyle_damage(damage); } } @@ -361,11 +397,7 @@ pub fn recalc_style_at<'a, E, C, D>(context: &'a C, if mode == StylingMode::Restyle && restyle_result == RestyleResult::Continue { for kid in element.as_node().children() { if let Some(kid) = kid.as_element() { - let mut data = D::ensure_element_data(&kid).borrow_mut(); - data.gather_previous_styles(|| kid.get_styles_from_frame()); - if data.previous_styles().is_some() { - data.ensure_restyle_data(); - } + unsafe { let _ = D::prepare_for_styling(&kid); } } } } |