diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 9d576e3bd02..dc1d7b179eb 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -1097,12 +1097,16 @@ impl LayoutThread { .unwrap(); } if data.document_stylesheets.iter().any(|sheet| sheet.dirty_on_viewport_size_change) { - for node in node.traverse_preorder() { + let mut iter = node.traverse_preorder(); + + let mut next = iter.next(); + while let Some(node) = next { if node.needs_dirty_on_viewport_size_changed() { - node.dirty_self(); - node.dirty_descendants(); - // TODO(shinglyu): We can skip the traversal if the descendants were already - // dirtied + // NB: The dirty bit is propagated down the tree. + unsafe { node.set_dirty(true); } + next = iter.next_skipping_children(); + } else { + next = iter.next(); } } } @@ -1114,7 +1118,9 @@ impl LayoutThread { let needs_reflow = viewport_size_changed && !needs_dirtying; unsafe { if needs_dirtying { - LayoutThread::dirty_all_nodes(node); + // NB: The dirty flag is propagated down during the restyle + // process. + node.set_dirty(true); } } if needs_reflow { diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 0e5e360c6e1..2769b7503bc 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -1287,6 +1287,31 @@ impl TreeIterator { depth: 0, } } + + pub fn next_skipping_children(&mut self) -> Option> { + let current = match self.current.take() { + None => return None, + Some(current) => current, + }; + + self.next_skipping_children_impl(current) + } + + fn next_skipping_children_impl(&mut self, current: Root) -> Option> { + for ancestor in current.inclusive_ancestors() { + if self.depth == 0 { + break; + } + if let Some(next_sibling) = ancestor.GetNextSibling() { + self.current = Some(next_sibling); + return Some(current); + } + self.depth -= 1; + } + debug_assert!(self.depth == 0); + self.current = None; + Some(current) + } } impl Iterator for TreeIterator { @@ -1303,19 +1328,8 @@ impl Iterator for TreeIterator { self.depth += 1; return Some(current); }; - for ancestor in current.inclusive_ancestors() { - if self.depth == 0 { - break; - } - if let Some(next_sibling) = ancestor.GetNextSibling() { - self.current = Some(next_sibling); - return Some(current); - } - self.depth -= 1; - } - debug_assert!(self.depth == 0); - self.current = None; - Some(current) + + self.next_skipping_children_impl(current) } } diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs index df44774dd5a..bfd7a8273d9 100644 --- a/components/script/layout_wrapper.rs +++ b/components/script/layout_wrapper.rs @@ -199,15 +199,6 @@ impl<'ln> TNode for ServoLayoutNode<'ln> { self.node.set_flag(DIRTY_ON_VIEWPORT_SIZE_CHANGE, true); } - fn set_descendants_dirty_on_viewport_size_changed(&self) { - for ref child in self.children() { - unsafe { - child.set_dirty_on_viewport_size_changed(); - } - child.set_descendants_dirty_on_viewport_size_changed(); - } - } - fn can_be_fragmented(&self) -> bool { unsafe { self.node.get_flag(CAN_BE_FRAGMENTED) } } diff --git a/components/style/dom.rs b/components/style/dom.rs index 5c5f3905d8d..c694ca75732 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -111,33 +111,10 @@ pub trait TNode : Sized + Copy + Clone { unsafe fn set_dirty_descendants(&self, value: bool); - fn dirty_self(&self) { - unsafe { - self.set_dirty(true); - self.set_dirty_descendants(true); - } - } - - fn dirty_descendants(&self) { - for ref child in self.children() { - child.dirty_self(); - child.dirty_descendants(); - } - } - fn needs_dirty_on_viewport_size_changed(&self) -> bool; unsafe fn set_dirty_on_viewport_size_changed(&self); - fn set_descendants_dirty_on_viewport_size_changed(&self) { - for ref child in self.children() { - unsafe { - child.set_dirty_on_viewport_size_changed(); - } - child.set_descendants_dirty_on_viewport_size_changed(); - } - } - fn can_be_fragmented(&self) -> bool; unsafe fn set_can_be_fragmented(&self, value: bool); @@ -215,7 +192,7 @@ pub trait TElement : Sized + Copy + Clone + ElementExt + PresentationalHintsSynt fn attr_equals(&self, namespace: &Namespace, attr: &Atom, value: &Atom) -> bool; /// Properly marks nodes as dirty in response to restyle hints. - fn note_restyle_hint(&self, mut hint: RestyleHint) { + fn note_restyle_hint(&self, hint: RestyleHint) { // Bail early if there's no restyling to do. if hint.is_empty() { return; @@ -233,23 +210,21 @@ pub trait TElement : Sized + Copy + Clone + ElementExt + PresentationalHintsSynt // Process hints. if hint.contains(RESTYLE_SELF) { - node.dirty_self(); + unsafe { node.set_dirty(true); } + // XXX(emilio): For now, dirty implies dirty descendants if found. + } else if hint.contains(RESTYLE_DESCENDANTS) { + let mut current = node.first_child(); + while let Some(node) = current { + unsafe { node.set_dirty(true); } + current = node.next_sibling(); + } + } - // FIXME(bholley, #8438): We currently need to RESTYLE_DESCENDANTS in the - // RESTYLE_SELF case in order to make sure "inherit" style structs propagate - // properly. See the explanation in the github issue. - hint.insert(RESTYLE_DESCENDANTS); - } - if hint.contains(RESTYLE_DESCENDANTS) { - unsafe { node.set_dirty_descendants(true); } - node.dirty_descendants(); - } if hint.contains(RESTYLE_LATER_SIBLINGS) { let mut next = ::selectors::Element::next_sibling_element(self); while let Some(sib) = next { let sib_node = sib.as_node(); - sib_node.dirty_self(); - sib_node.dirty_descendants(); + unsafe { sib_node.set_dirty(true) }; next = ::selectors::Element::next_sibling_element(&sib); } } @@ -262,12 +237,16 @@ pub struct TreeIterator where ConcreteNode: TNode { impl TreeIterator where ConcreteNode: TNode { fn new(root: ConcreteNode) -> TreeIterator { - let mut stack = vec!(); + let mut stack = vec![]; stack.push(root); TreeIterator { stack: stack, } } + + pub fn next_skipping_children(&mut self) -> Option { + self.stack.pop() + } } impl Iterator for TreeIterator diff --git a/components/style/traversal.rs b/components/style/traversal.rs index c0d197896af..efdf96b0c35 100644 --- a/components/style/traversal.rs +++ b/components/style/traversal.rs @@ -268,16 +268,17 @@ pub fn recalc_style_at<'a, N, C>(context: &'a C, // NB: flow construction updates the bloom filter on the way up. 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. - 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(); + // Mark the node as DIRTY_ON_VIEWPORT_SIZE_CHANGE is it uses viewport + // percentage units. + if !node.needs_dirty_on_viewport_size_changed() { + 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(); } } } } -