aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBobby Holley <bobbyholley@gmail.com>2016-10-30 20:45:29 -0700
committerBobby Holley <bobbyholley@gmail.com>2016-11-01 11:03:04 -0700
commit71b9004d861e3b381178e1c668bc78423e6d4bc1 (patch)
tree22671ab8097485a78273155747144e56a6ca99a6
parentb98bb241dc84196dde1c836ff965d7d77fdd458a (diff)
downloadservo-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.rs7
-rw-r--r--components/layout/wrapper.rs32
-rw-r--r--components/script/layout_wrapper.rs47
-rw-r--r--components/script_layout_interface/wrapper_traits.rs4
-rw-r--r--components/style/atomic_refcell.rs4
-rw-r--r--components/style/dom.rs45
-rw-r--r--components/style/gecko/traversal.rs2
-rw-r--r--components/style/gecko/wrapper.rs21
-rw-r--r--components/style/matching.rs13
-rw-r--r--components/style/traversal.rs54
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); }
}
}
}