Bug 890775 - Not all xbl:children elements should be treated specially. r=peterv
authorBlake Kaplan <mrbkap@gmail.com>
Thu, 11 Jul 2013 17:52:49 -0400
changeset 138242 4c7d491276d9e5b5c8d47a1a07d65d0af2e6e0da
parent 138241 388733080b918958437912edc9a267859d04f177
child 138243 09cb9725492e968d364e3d82f83476da0e75c69b
push id24949
push userryanvm@gmail.com
push dateFri, 12 Jul 2013 17:29:41 +0000
treeherdermozilla-central@f2d3b5149d3a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv
bugs890775
milestone25.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 890775 - Not all xbl:children elements should be treated specially. r=peterv
content/base/public/nsIContent.h
content/base/src/ChildIterator.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsFrameManager.cpp
layout/style/nsCSSRuleProcessor.cpp
--- a/content/base/public/nsIContent.h
+++ b/content/base/public/nsIContent.h
@@ -28,18 +28,18 @@ struct IMEState;
 enum nsLinkState {
   eLinkState_Unvisited  = 1,
   eLinkState_Visited    = 2,
   eLinkState_NotLink    = 3 
 };
 
 // IID for the nsIContent interface
 #define NS_ICONTENT_IID \
-{ 0x8a8b4b1d, 0x72d8, 0x428e, \
- { 0x95, 0x75, 0xf9, 0x18, 0xba, 0xf6, 0x9e, 0xa1 } }
+{ 0Xf22c131c, 0Xc554, 0X4d06, \
+  { 0X81, 0Xac, 0X86, 0X64, 0X2f, 0X05, 0Xcc, 0X81 } }
 
 /**
  * A node of content in a document's content model. This interface
  * is supported by all content objects.
  */
 class nsIContent : public nsINode {
 public:
   typedef mozilla::widget::IMEState IMEState;
@@ -300,16 +300,22 @@ public:
     return IsInNamespace(kNameSpaceID_MathML);
   }
 
   inline bool IsMathML(nsIAtom* aTag) const
   {
     return mNodeInfo->Equals(aTag, kNameSpaceID_MathML);
   }
 
+  inline bool IsActiveChildrenElement() const
+  {
+    return mNodeInfo->Equals(nsGkAtoms::children, kNameSpaceID_XBL) &&
+           GetBindingParent();
+  }
+
   /**
    * Returns an atom holding the name of the attribute of type ID on
    * this content node (if applicable).  Returns null for non-element
    * content nodes.
    */
   virtual nsIAtom *GetIDAttributeName() const = 0;
 
   /**
--- a/content/base/src/ChildIterator.cpp
+++ b/content/base/src/ChildIterator.cpp
@@ -11,46 +11,45 @@ namespace mozilla {
 namespace dom {
 
 nsIContent*
 ExplicitChildIterator::GetNextChild()
 {
   // If we're already in the inserted-children array, look there first
   if (mIndexInInserted) {
     MOZ_ASSERT(mChild);
-    MOZ_ASSERT(mChild->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL));
+    MOZ_ASSERT(mChild->IsActiveChildrenElement());
     MOZ_ASSERT(!mDefaultChild);
 
     XBLChildrenElement* point = static_cast<XBLChildrenElement*>(mChild);
     if (mIndexInInserted < point->mInsertedChildren.Length()) {
       return point->mInsertedChildren[mIndexInInserted++];
     }
     mIndexInInserted = 0;
     mChild = mChild->GetNextSibling();
   } else if (mDefaultChild) {
     // If we're already in default content, check if there are more nodes there
     MOZ_ASSERT(mChild);
-    MOZ_ASSERT(mChild->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL));
+    MOZ_ASSERT(mChild->IsActiveChildrenElement());
 
     mDefaultChild = mDefaultChild->GetNextSibling();
     if (mDefaultChild) {
       return mDefaultChild;
     }
 
     mChild = mChild->GetNextSibling();
   } else if (mIsFirst) {  // at the beginning of the child list
     mChild = mParent->GetFirstChild();
     mIsFirst = false;
   } else if (mChild) { // in the middle of the child list
     mChild = mChild->GetNextSibling();
   }
 
   // Iterate until we find a non-<children>, or a <children> with content.
-  while (mChild &&
-         mChild->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
+  while (mChild && mChild->IsActiveChildrenElement()) {
     XBLChildrenElement* point = static_cast<XBLChildrenElement*>(mChild);
     if (!point->mInsertedChildren.IsEmpty()) {
       mIndexInInserted = 1;
       return point->mInsertedChildren[0];
     }
 
     mDefaultChild = mChild->GetFirstChild();
     if (mDefaultChild) {
@@ -80,16 +79,17 @@ FlattenedChildIterator::FlattenedChildIt
   // We set mXBLInvolved to true if either:
   // - The node we're iterating has a binding with content attached to it.
   // - The node is generated XBL content and has an <xbl:children> child.
   if (!mXBLInvolved && aParent->GetBindingParent()) {
     for (nsIContent* child = aParent->GetFirstChild();
          child;
          child = child->GetNextSibling()) {
       if (child->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
+        MOZ_ASSERT(child->GetBindingParent());
         mXBLInvolved = true;
         break;
       }
     }
   }
 }
 
 nsIContent* FlattenedChildIterator::Get()
@@ -126,18 +126,17 @@ nsIContent* FlattenedChildIterator::GetP
     return nullptr;
   } else if (mChild) { // in the middle of the child list
     mChild = mChild->GetPreviousSibling();
   } else { // at the end of the child list
     mChild = mParent->GetLastChild();
   }
 
   // Iterate until we find a non-<children>, or a <children> with content.
-  while (mChild &&
-         mChild->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
+  while (mChild && mChild->IsActiveChildrenElement()) {
     XBLChildrenElement* point = static_cast<XBLChildrenElement*>(mChild);
     if (!point->mInsertedChildren.IsEmpty()) {
       mIndexInInserted = point->InsertedChildrenLength();
       return point->mInsertedChildren[mIndexInInserted - 1];
     }
 
     mDefaultChild = mChild->GetLastChild();
     if (mDefaultChild) {
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -3513,17 +3513,17 @@ nsCSSFrameConstructor::ConstructFrameFro
 
   // Get the parent of the content and check if it is a XBL children element.
   // Push the children element as an ancestor here because it does
   // not have a frame and would not otherwise be pushed as an ancestor. It is
   // necessary to do so in order to correctly handle style resolution on
   // descendants.
   nsIContent* parent = content->GetParent();
   bool pushInsertionPoint = aState.mTreeMatchContext.mAncestorFilter.HasFilter() &&
-    parent && parent->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL);
+    parent && parent->IsActiveChildrenElement();
   TreeMatchContext::AutoAncestorPusher
     insertionPointPusher(pushInsertionPoint,
                          aState.mTreeMatchContext,
                          parent && parent->IsElement() ? parent->AsElement() : nullptr);
 
   // Push the content as a style ancestor now, so we don't have to do
   // it in our various full-constructor functions.  In particular,
   // since a number of full-constructor functions don't actually call
@@ -6506,17 +6506,17 @@ nsCSSFrameConstructor::ContentAppended(n
 
   }
 #endif // MOZ_XUL
 
   // Get the frame associated with the content
   nsIFrame* parentFrame = GetFrameFor(aContainer);
 
   // See comment in ContentRangeInserted for why this is necessary.
-  if (!parentFrame && !aContainer->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
+  if (!parentFrame && !aContainer->IsActiveChildrenElement()) {
     return NS_OK;
   }
 
   if (aAllowLazyConstruction &&
       MaybeConstructLazily(CONTENTAPPEND, aContainer, aFirstNewContent)) {
     return NS_OK;
   }
 
@@ -6929,17 +6929,17 @@ nsCSSFrameConstructor::ContentRangeInser
 
     return NS_OK;
   }
 
   nsIFrame* parentFrame = GetFrameFor(aContainer);
   // The xbl:children element won't have a frame, but default content can have the children as
   // a parent. While its uncommon to change the structure of the default content itself, a label,
   // for example, can be reframed by having its value attribute set or removed.
-  if (!parentFrame && !aContainer->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
+  if (!parentFrame && !aContainer->IsActiveChildrenElement()) {
     return NS_OK;
   }
 
   // Otherwise, we've got parent content. Find its frame.
   NS_ASSERTION(!parentFrame || parentFrame->GetContent() == aContainer, "New XBL code is possibly wrong!");
 
   if (aAllowLazyConstruction &&
       MaybeConstructLazily(CONTENTINSERT, aContainer, aStartChild)) {
--- a/layout/base/nsFrameManager.cpp
+++ b/layout/base/nsFrameManager.cpp
@@ -1374,18 +1374,17 @@ nsFrameManager::ReResolveStyleContext(ns
         NS_ASSERTION(!undisplayed->mStyle->GetPseudo(),
                      "Shouldn't have random pseudo style contexts in the "
                      "undisplayed map");
 
         // Get the parent of the undisplayed content and check if it is a XBL
         // children element. Push the children element as an ancestor here because it does
         // not have a frame and would not otherwise be pushed as an ancestor.
         nsIContent* parent = undisplayed->mContent->GetParent();
-        bool pushInsertionPoint = parent &&
-          parent->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL);
+        bool pushInsertionPoint = parent && parent->IsActiveChildrenElement();
         TreeMatchContext::AutoAncestorPusher
           insertionPointPusher(pushInsertionPoint,
                                aTreeMatchContext,
                                parent && parent->IsElement() ? parent->AsElement() : nullptr);
 
         nsRestyleHint thisChildHint = childRestyleHint;
         RestyleTracker::RestyleData undisplayedRestyleData;
         if (aRestyleTracker.GetRestyleData(undisplayed->mContent->AsElement(),
@@ -1544,18 +1543,17 @@ nsFrameManager::ReResolveStyleContext(ns
           if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
             // Get the parent of the child frame's content and check if it is a XBL
             // children element. Push the children element as an ancestor here because it does
             // not have a frame and would not otherwise be pushed as an ancestor.
 
             // Check if the frame has a content because |child| may be a nsPageFrame that does
             // not have a content.
             nsIContent* parent = child->GetContent() ? child->GetContent()->GetParent() : nullptr;
-            bool pushInsertionPoint = parent &&
-              parent->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL);
+            bool pushInsertionPoint = parent && parent->IsActiveChildrenElement();
             TreeMatchContext::AutoAncestorPusher
               insertionPointPusher(pushInsertionPoint, aTreeMatchContext,
                                    parent && parent->IsElement() ? parent->AsElement() : nullptr);
 
             // only do frames that are in flow
             if (nsGkAtoms::placeholderFrame == child->GetType()) { // placeholder
               // get out of flow frame and recur there
               nsIFrame* outOfFlowFrame =
@@ -1906,18 +1904,17 @@ nsFrameManagerBase::UndisplayedMap::GetE
   }
 
   // In the case of XBL default content, <xbl:children> elements do not get a
   // frame causing a mismatch between the content tree and the frame tree.
   // |GetEntryFor| is sometimes called with the content tree parent (which may
   // be a <xbl:children> element) but the parent in the frame tree would be the
   // insertion parent (parent of the <xbl:children> element). Here the children
   // elements are normalized to the insertion parent to correct for the mismatch.
-  if (parentContent &&
-      parentContent->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
+  if (parentContent && parentContent->IsActiveChildrenElement()) {
     parentContent = parentContent->GetParent();
     // Change the caller's pointer for the parent content to be the insertion parent.
     *aParentContent = parentContent;
   }
 
   PLHashNumber hashCode = NS_PTR_TO_INT32(parentContent);
   PLHashEntry** entry = PL_HashTableRawLookup(mTable, hashCode, parentContent);
   if (*entry) {
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -2307,19 +2307,17 @@ static bool SelectorMatchesTree(Element*
           // traverse further up the tree.
           aTreeMatchContext.PopStyleScopeForSelectorMatching(element);
         }
 
         // Compatibility hack: First try matching this selector as though the
         // <xbl:children> element wasn't in the tree to allow old selectors
         // were written before <xbl:children> participated in CSS selector
         // matching to work.
-        if (selector->mOperator == '>' &&
-            element->NodeInfo()->Equals(nsGkAtoms::children,
-                                        kNameSpaceID_XBL)) {
+        if (selector->mOperator == '>' && element->IsActiveChildrenElement()) {
           Element* styleScope = aTreeMatchContext.mCurrentStyleScope;
           if (SelectorMatchesTree(element, selector, aTreeMatchContext,
                                   aLookForRelevantLink)) {
             // It matched, don't try matching on the <xbl:children> element at
             // all.
             return true;
           }
           // We want to reset mCurrentStyleScope on aTreeMatchContext