aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBobby Holley <bobbyholley@gmail.com>2017-01-08 12:38:44 -0800
committerBobby Holley <bobbyholley@gmail.com>2017-01-09 11:51:37 -0800
commit4558efbca5c1ad3fe0b6b074415174c42ae1f75f (patch)
treeeecd03f6488da6a810f6543755c5c94a2ed09e78
parent92b9d70c3a28afd18f7cede0dcd135197e49c284 (diff)
downloadservo-4558efbca5c1ad3fe0b6b074415174c42ae1f75f.tar.gz
servo-4558efbca5c1ad3fe0b6b074415174c42ae1f75f.zip
Bug 1325734 - Explicitly track whether we're performing the initial style. r=emilio
-rw-r--r--components/style/context.rs52
-rw-r--r--components/style/traversal.rs12
2 files changed, 58 insertions, 6 deletions
diff --git a/components/style/context.rs b/components/style/context.rs
index ab5899e142f..66310c752c7 100644
--- a/components/style/context.rs
+++ b/components/style/context.rs
@@ -8,7 +8,8 @@
use animation::Animation;
use app_units::Au;
use bloom::StyleBloom;
-use dom::{OpaqueNode, TElement};
+use data::ElementData;
+use dom::{OpaqueNode, TNode, TElement};
use error_reporting::ParseErrorReporter;
use euclid::Size2D;
use matching::StyleSharingCandidateCache;
@@ -89,6 +90,18 @@ pub struct SharedStyleContext {
pub default_computed_values: Arc<ComputedValues>,
}
+/// Information about the current element being processed. We group this together
+/// into a single struct within ThreadLocalStyleContext so that we can instantiate
+/// and destroy it easily at the beginning and end of element processing.
+struct CurrentElementInfo {
+ /// The element being processed. Currently we use an OpaqueNode since we only
+ /// use this for identity checks, but we could use SendElement if there were
+ /// a good reason to.
+ element: OpaqueNode,
+ /// Whether the element is being styled for the first time.
+ is_initial_style: bool,
+}
+
/// A thread-local style context.
///
/// This context contains data that needs to be used during restyling, but is
@@ -102,17 +115,52 @@ 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>,
+ /// Information related to the current element, non-None during processing.
+ current_element_info: Option<CurrentElementInfo>,
}
impl<E: TElement> ThreadLocalStyleContext<E> {
- /// Create a new `ThreadLocalStyleContext` from a shared one.
+ /// Creates a new `ThreadLocalStyleContext` from a shared one.
pub fn new(shared: &SharedStyleContext) -> Self {
ThreadLocalStyleContext {
style_sharing_candidate_cache: StyleSharingCandidateCache::new(),
bloom_filter: StyleBloom::new(),
new_animations_sender: shared.local_context_creation_data.lock().unwrap().new_animations_sender.clone(),
+ current_element_info: None,
}
}
+
+ /// Notes when the style system starts traversing an element.
+ pub fn begin_element(&mut self, element: E, data: &ElementData) {
+ debug_assert!(self.current_element_info.is_none());
+ self.current_element_info = Some(CurrentElementInfo {
+ element: element.as_node().opaque(),
+ is_initial_style: data.is_unstyled_initial(),
+ });
+ }
+
+ /// Notes when the style system finishes traversing an element.
+ pub fn end_element(&mut self, element: E) {
+ debug_assert!(self.current_element_info.is_some());
+ debug_assert!(self.current_element_info.as_ref().unwrap().element ==
+ element.as_node().opaque());
+ self.current_element_info = None;
+ }
+
+ /// Returns true if the current element being traversed is being styled for
+ /// the first time.
+ ///
+ /// Panics if called while no element is being traversed.
+ pub fn is_initial_style(&self) -> bool {
+ self.current_element_info.as_ref().unwrap().is_initial_style
+ }
+}
+
+#[cfg(debug_assertions)]
+impl<E: TElement> Drop for ThreadLocalStyleContext<E> {
+ fn drop(&mut self) {
+ debug_assert!(self.current_element_info.is_none());
+ }
}
/// A `StyleContext` is just a simple container for a immutable reference to a
diff --git a/components/style/traversal.rs b/components/style/traversal.rs
index 8dd541fbd5b..8e7bf465682 100644
--- a/components/style/traversal.rs
+++ b/components/style/traversal.rs
@@ -195,7 +195,7 @@ pub trait DomTraversal<E: TElement> : Sync {
/// This may be called multiple times when processing an element, so we pass
/// a parameter to keep the logs tidy.
fn should_traverse_children(&self,
- _thread_local: &mut ThreadLocalStyleContext<E>,
+ thread_local: &mut ThreadLocalStyleContext<E>,
parent: E,
parent_data: &ElementData,
log: LogBehavior) -> bool
@@ -230,7 +230,7 @@ pub trait DomTraversal<E: TElement> : Sync {
// happens, we may just end up doing wasted work, since Gecko
// recursively drops Servo ElementData when the XBL insertion parent of
// an Element is changed.
- if cfg!(feature = "gecko") && parent_data.is_styled_initial() &&
+ if cfg!(feature = "gecko") && thread_local.is_initial_style() &&
parent_data.styles().primary.values.has_moz_binding() {
if log.allow() { debug!("Parent {:?} has XBL binding, deferring traversal", parent); }
return false;
@@ -246,8 +246,11 @@ pub trait DomTraversal<E: TElement> : Sync {
where F: FnMut(&mut Self::ThreadLocalContext, E::ConcreteNode)
{
// Check if we're allowed to traverse past this element.
- if !self.should_traverse_children(thread_local.borrow_mut(), parent,
- &parent.borrow_data().unwrap(), MayLog) {
+ let should_traverse =
+ self.should_traverse_children(thread_local.borrow_mut(), parent,
+ &parent.borrow_data().unwrap(), MayLog);
+ thread_local.borrow_mut().end_element(parent);
+ if !should_traverse {
return;
}
@@ -376,6 +379,7 @@ pub fn recalc_style_at<E, D>(traversal: &D,
where E: TElement,
D: DomTraversal<E>
{
+ context.thread_local.begin_element(element, &data);
debug_assert!(data.as_restyle().map_or(true, |r| r.snapshot.is_none()),
"Snapshots should be expanded by the caller");