aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/style/data.rs4
-rw-r--r--components/style/parallel.rs32
-rw-r--r--components/style/sequential.rs19
-rw-r--r--components/style/traversal.rs28
-rw-r--r--ports/geckolib/traversal.rs16
5 files changed, 66 insertions, 33 deletions
diff --git a/components/style/data.rs b/components/style/data.rs
index 906848998fb..44920c72c98 100644
--- a/components/style/data.rs
+++ b/components/style/data.rs
@@ -37,13 +37,13 @@ impl PrivateStyleData {
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct DomParallelInfo {
/// The number of children that still need work done.
- pub children_count: AtomicIsize,
+ pub children_to_process: AtomicIsize,
}
impl DomParallelInfo {
pub fn new() -> DomParallelInfo {
DomParallelInfo {
- children_count: AtomicIsize::new(0),
+ children_to_process: AtomicIsize::new(0),
}
}
}
diff --git a/components/style/parallel.rs b/components/style/parallel.rs
index 0bc840f7492..889f7f0a15b 100644
--- a/components/style/parallel.rs
+++ b/components/style/parallel.rs
@@ -63,25 +63,34 @@ fn top_down_dom<N, C>(unsafe_nodes: UnsafeNodeList,
// Get a real layout node.
let node = unsafe { N::from_unsafe(&unsafe_node) };
+ if !context.should_process(node) {
+ continue;
+ }
+
// Perform the appropriate traversal.
context.process_preorder(node);
- let child_count = node.children_count();
+ // Possibly enqueue the children.
+ let mut children_to_process = 0isize;
+ for kid in node.children() {
+ context.pre_process_child_hook(node, kid);
+ if context.should_process(kid) {
+ children_to_process += 1;
+ discovered_child_nodes.push(kid.to_unsafe())
+ }
+ }
// Reset the count of children.
{
let data = node.mutate_data().unwrap();
- data.parallel.children_count.store(child_count as isize,
- Ordering::Relaxed);
+ data.parallel.children_to_process
+ .store(children_to_process,
+ Ordering::Relaxed);
}
- // Possibly enqueue the children.
- if child_count != 0 {
- for kid in node.children() {
- discovered_child_nodes.push(kid.to_unsafe())
- }
- } else {
- // If there were no more children, start walking back up.
+
+ // If there were no more children, start walking back up.
+ if children_to_process == 0 {
bottom_up_dom::<N, C>(unsafe_nodes.1, unsafe_node, proxy)
}
}
@@ -128,7 +137,7 @@ fn bottom_up_dom<N, C>(root: OpaqueNode,
if parent_data
.parallel
- .children_count
+ .children_to_process
.fetch_sub(1, Ordering::Relaxed) != 1 {
// Get out of here and find another node to work on.
break
@@ -138,4 +147,3 @@ fn bottom_up_dom<N, C>(root: OpaqueNode,
node = parent;
}
}
-
diff --git a/components/style/sequential.rs b/components/style/sequential.rs
index a5a9b519e57..56b8a563d27 100644
--- a/components/style/sequential.rs
+++ b/components/style/sequential.rs
@@ -9,20 +9,29 @@ use traversal::DomTraversalContext;
pub fn traverse_dom<N, C>(root: N,
shared: &C::SharedContext)
- where N: TNode,
- C: DomTraversalContext<N> {
+ where N: TNode,
+ C: DomTraversalContext<N>
+{
fn doit<'a, N, C>(context: &'a C, node: N)
- where N: TNode, C: DomTraversalContext<N> {
+ where N: TNode,
+ C: DomTraversalContext<N>
+ {
+ debug_assert!(context.should_process(node));
context.process_preorder(node);
for kid in node.children() {
- doit::<N, C>(context, kid);
+ context.pre_process_child_hook(node, kid);
+ if context.should_process(node) {
+ doit::<N, C>(context, kid);
+ }
}
context.process_postorder(node);
}
let context = C::new(shared, root.opaque());
- doit::<N, C>(&context, root);
+ if context.should_process(root) {
+ doit::<N, C>(&context, root);
+ }
}
diff --git a/components/style/traversal.rs b/components/style/traversal.rs
index 76f8539c72f..e4b1d8f11de 100644
--- a/components/style/traversal.rs
+++ b/components/style/traversal.rs
@@ -147,6 +147,12 @@ pub trait DomTraversalContext<N: TNode> {
fn process_preorder(&self, node: N);
/// Process `node` on the way up, after its children have been processed.
fn process_postorder(&self, node: N);
+
+ /// Returns if the node should be processed by the preorder traversal.
+ fn should_process(&self, _node: N) -> bool { true }
+
+ /// Do an action over the child before pushing him to the work queue.
+ fn pre_process_child_hook(&self, _parent: N, _kid: N) {}
}
/// Calculates the style for a single node.
@@ -245,21 +251,15 @@ pub fn recalc_style_at<'a, N, C>(context: &'a C,
put_thread_local_bloom_filter(bf, &unsafe_layout_node, context.shared_context());
// Mark the node as DIRTY_ON_VIEWPORT_SIZE_CHANGE is it uses viewport percentage units.
- match node.as_element() {
- Some(element) => {
- match *element.style_attribute() {
- Some(ref property_declaration_block) => {
- if property_declaration_block.declarations().any(|d| d.0.has_viewport_percentage()) {
- unsafe {
- node.set_dirty_on_viewport_size_changed();
- }
- node.set_descendants_dirty_on_viewport_size_changed();
- }
- },
- None => {}
+ if let Some(element) = node.as_element() {
+ if let Some(ref property_declaration_block) = *element.style_attribute() {
+ if property_declaration_block.declarations().any(|d| d.0.has_viewport_percentage()) {
+ unsafe {
+ node.set_dirty_on_viewport_size_changed();
+ }
+ node.set_descendants_dirty_on_viewport_size_changed();
}
- },
- None => {}
+ }
}
}
diff --git a/ports/geckolib/traversal.rs b/ports/geckolib/traversal.rs
index 87b63e83e15..6a3667e0b96 100644
--- a/ports/geckolib/traversal.rs
+++ b/ports/geckolib/traversal.rs
@@ -6,6 +6,7 @@ use context::StandaloneStyleContext;
use std::mem;
use style::context::SharedStyleContext;
use style::dom::OpaqueNode;
+use style::dom::TNode;
use style::traversal::{DomTraversalContext, recalc_style_at};
use wrapper::GeckoNode;
@@ -35,5 +36,20 @@ impl<'lc, 'ln> DomTraversalContext<GeckoNode<'ln>> for RecalcStyleOnly<'lc> {
recalc_style_at(&self.context, self.root, node);
}
+ fn should_process(&self, node: GeckoNode<'ln>) -> bool {
+ node.is_dirty() || node.has_dirty_descendants()
+ }
+
fn process_postorder(&self, _: GeckoNode<'ln>) {}
+
+ fn pre_process_child_hook(&self, parent: GeckoNode<'ln>, kid: GeckoNode<'ln>) {
+ // NOTE: At this point is completely safe to modify either the parent or
+ // the child, since we have exclusive access to them.
+ if parent.is_dirty() {
+ unsafe {
+ kid.set_dirty(true);
+ parent.set_dirty_descendants(true);
+ }
+ }
+ }
}