vendor servo commit b49eb6f56664e5e8db326466726ccf3b58397168 draft
authorVCS Sync <vcs-sync@mozilla.com>
Fri, 30 Dec 2016 03:56:18 +0000
changeset 458232 0963c6194a1b75a9320b0c7fa38f2f7a60602a77
parent 458231 d71ce3e0b43df32e8479322512c47ed457b54ef4
child 458233 1a07d21e2b3c995341e5c5c56c100cf5de6d83ca
push id40933
push userbmo:slyu@mozilla.com
push dateTue, 10 Jan 2017 06:53:24 +0000
milestone53.0a1
vendor servo commit b49eb6f56664e5e8db326466726ccf3b58397168
servo/components/script/layout_wrapper.rs
servo/components/style/dom.rs
servo/components/style/gecko/wrapper.rs
servo/components/style/gecko_bindings/bindings.rs
servo/components/style/traversal.rs
--- a/servo/components/script/layout_wrapper.rs
+++ b/servo/components/script/layout_wrapper.rs
@@ -194,16 +194,20 @@ impl<'ln> TNode for ServoLayoutNode<'ln>
         self.node.set_flag(CAN_BE_FRAGMENTED, value)
     }
 
     fn parent_node(&self) -> Option<ServoLayoutNode<'ln>> {
         unsafe {
             self.node.parent_node_ref().map(|node| self.new_with_this_lifetime(&node))
         }
     }
+
+    fn is_in_doc(&self) -> bool {
+        unsafe { (*self.node.unsafe_get()).is_in_doc() }
+    }
 }
 
 pub struct ServoChildrenIterator<'a> {
     current: Option<ServoLayoutNode<'a>>,
 }
 
 impl<'a> Iterator for ServoChildrenIterator<'a> {
     type Item = ServoLayoutNode<'a>;
--- a/servo/components/style/dom.rs
+++ b/servo/components/style/dom.rs
@@ -94,16 +94,18 @@ pub trait TNode : Sized + Copy + Clone +
 
     unsafe fn set_dirty_on_viewport_size_changed(&self);
 
     fn can_be_fragmented(&self) -> bool;
 
     unsafe fn set_can_be_fragmented(&self, value: bool);
 
     fn parent_node(&self) -> Option<Self>;
+
+    fn is_in_doc(&self) -> bool;
 }
 
 /// Wrapper to output the ElementData along with the node when formatting for
 /// Debug.
 pub struct ShowData<N: TNode>(pub N);
 impl<N: TNode> Debug for ShowData<N> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         fmt_with_data(f, self.0)
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -152,16 +152,20 @@ impl<'ln> TNode for GeckoNode<'ln> {
         // FIXME(SimonSapin): Servo uses this to implement CSS multicol / fragmentation
         // Maybe this isn’t useful for Gecko?
     }
 
     fn parent_node(&self) -> Option<Self> {
         unsafe { bindings::Gecko_GetParentNode(self.0).map(GeckoNode) }
     }
 
+    fn is_in_doc(&self) -> bool {
+        unsafe { bindings::Gecko_IsInDocument(self.0) }
+    }
+
     fn needs_dirty_on_viewport_size_changed(&self) -> bool {
         // Gecko's node doesn't have the DIRTY_ON_VIEWPORT_SIZE_CHANGE flag,
         // so we force them to be dirtied on viewport size change, regardless if
         // they use viewport percentage size or not.
         // TODO(shinglyu): implement this in Gecko: https://github.com/servo/servo/pull/11890
         true
     }
 
--- a/servo/components/style/gecko_bindings/bindings.rs
+++ b/servo/components/style/gecko_bindings/bindings.rs
@@ -263,16 +263,19 @@ extern "C" {
 }
 extern "C" {
     pub fn Gecko_ChildrenCount(node: RawGeckoNodeBorrowed) -> u32;
 }
 extern "C" {
     pub fn Gecko_NodeIsElement(node: RawGeckoNodeBorrowed) -> bool;
 }
 extern "C" {
+    pub fn Gecko_IsInDocument(node: RawGeckoNodeBorrowed) -> bool;
+}
+extern "C" {
     pub fn Gecko_GetParentNode(node: RawGeckoNodeBorrowed)
      -> RawGeckoNodeBorrowedOrNull;
 }
 extern "C" {
     pub fn Gecko_GetFirstChild(node: RawGeckoNodeBorrowed)
      -> RawGeckoNodeBorrowedOrNull;
 }
 extern "C" {
--- a/servo/components/style/traversal.rs
+++ b/servo/components/style/traversal.rs
@@ -319,26 +319,33 @@ pub fn resolve_style<E, F, G, H>(context
     // Resolve styles up the tree.
     let display_none_root = resolve_style_internal(context, element, ensure_data);
 
     // Make them available for the scope of the callback. The callee may use the
     // argument, or perform any other processing that requires the styles to exist
     // on the Element.
     callback(element.borrow_data().unwrap().styles());
 
-    // Clear any styles in display:none subtrees to leave the tree in a valid state.
-    if let Some(root) = display_none_root {
+    // Clear any styles in display:none subtrees or subtrees not in the document,
+    // to leave the tree in a valid state.  For display:none subtrees, we leave
+    // the styles on the display:none root, but for subtrees not in the document,
+    // we clear styles all the way up to the root of the disconnected subtree.
+    let in_doc = element.as_node().is_in_doc();
+    if !in_doc || display_none_root.is_some() {
         let mut curr = element;
         loop {
             unsafe { curr.unset_dirty_descendants(); }
-            if curr == root {
+            if in_doc && curr == display_none_root.unwrap() {
                 break;
             }
             clear_data(curr);
-            curr = curr.parent_element().unwrap();
+            curr = match curr.parent_element() {
+                Some(parent) => parent,
+                None => break,
+            };
         }
     }
 }
 
 /// Calculates the style for a single node.
 #[inline]
 #[allow(unsafe_code)]
 pub fn recalc_style_at<E, D>(traversal: &D,