Bug 508819. Stop relying on getElementById returning anonymous nodes. r=gavin,dietrich,davidb
authorBoris Zbarsky <bzbarsky@mit.edu>
Mon, 10 Aug 2009 10:54:22 -0400
changeset 31286 2a3fd282e4725dd97763367b42365ad6fbf9dbfd
parent 31285 375b3e7328c7577ba2b3612a7fc9a49eb19682e7
child 31287 cf95f5eee70324c0ba8bc452b8d6bf34f14fccc7
push id8476
push userbzbarsky@mozilla.com
push dateMon, 10 Aug 2009 16:00:21 +0000
treeherdermozilla-central@1ddf399b4c26 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgavin, dietrich, davidb
bugs508819
milestone1.9.2a2pre
Bug 508819. Stop relying on getElementById returning anonymous nodes. r=gavin,dietrich,davidb
accessible/src/base/nsRelUtils.cpp
accessible/src/base/nsRelUtils.h
accessible/src/xul/nsXULTabAccessible.cpp
browser/components/sessionstore/src/nsSessionStore.js
toolkit/content/widgets/tabbox.xml
--- a/accessible/src/base/nsRelUtils.cpp
+++ b/accessible/src/base/nsRelUtils.cpp
@@ -37,16 +37,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsRelUtils.h"
 
 #include "nsAccessNode.h"
 
 #include "nsIDOMDocument.h"
 #include "nsIDOMElement.h"
+#include "nsIDOMDocumentXBL.h"
 
 #include "nsAutoPtr.h"
 #include "nsArrayUtils.h"
 
 already_AddRefed<nsIAccessible>
 nsRelUtils::GetRelatedAccessible(nsIAccessible *aAccessible,
                                  PRUint32 aRelationType)
 {
@@ -94,30 +95,42 @@ nsRelUtils::AddTargetFromContent(PRUint3
   nsCOMPtr<nsIAccessible> accessible;
   accService->GetAccessibleFor(node, getter_AddRefs(accessible));
   return AddTarget(aRelationType, aRelation, accessible);
 }
 
 nsresult
 nsRelUtils::AddTargetFromIDRefAttr(PRUint32 aRelationType,
                                    nsIAccessibleRelation **aRelation,
-                                   nsIContent *aContent, nsIAtom *aAttr)
+                                   nsIContent *aContent, nsIAtom *aAttr,
+                                   PRBool aMayBeAnon)
 {
   nsAutoString id;
   if (!aContent->GetAttr(kNameSpaceID_None, aAttr, id))
     return NS_OK_NO_RELATION_TARGET;
 
   nsCOMPtr<nsIDOMDocument> document =
     do_QueryInterface(aContent->GetOwnerDoc());
   NS_ASSERTION(document, "The given node is not in document!");
   if (!document)
     return NS_OK_NO_RELATION_TARGET;
 
   nsCOMPtr<nsIDOMElement> refElm;
-  document->GetElementById(id, getter_AddRefs(refElm));
+  if (aMayBeAnon && aContent->GetBindingParent()) {
+    nsCOMPtr<nsIDOMDocumentXBL> documentXBL(do_QueryInterface(document));
+    nsCOMPtr<nsIDOMElement> bindingParent =
+      do_QueryInterface(aContent->GetBindingParent());
+    documentXBL->GetAnonymousElementByAttribute(bindingParent,
+                                                NS_LITERAL_STRING("id"),
+                                                id,
+                                                getter_AddRefs(refElm));
+  }
+  else {
+    document->GetElementById(id, getter_AddRefs(refElm));
+  }
 
   nsCOMPtr<nsIContent> refContent(do_QueryInterface(refElm));
   return AddTargetFromContent(aRelationType, aRelation, refContent);
 }
 
 nsresult
 nsRelUtils::AddTargetFromIDRefsAttr(PRUint32 aRelationType,
                                     nsIAccessibleRelation **aRelation,
--- a/accessible/src/base/nsRelUtils.h
+++ b/accessible/src/base/nsRelUtils.h
@@ -92,20 +92,24 @@ public:
   /**
    * Create the relation if the given relation is null and add the target to it
    * pointed by IDRef attribute on the given node.
    *
    * @param  aRelationType  [in] relation type
    * @param  aRelation      [in, out] relation object
    * @param  aContent       [in] node having the given IDRef attribute
    * @param  aAttr          [in] IDRef attribute
+   * @param  aMayBeAnon     [in] true if the target may be anonymous; if so,
+   *                             we need to look for it under the binding
+   *                             parent of aContent.
    */
   static nsresult AddTargetFromIDRefAttr(PRUint32 aRelationType,
                                          nsIAccessibleRelation **aRelation,
-                                         nsIContent *aContent, nsIAtom *aAttr);
+                                         nsIContent *aContent, nsIAtom *aAttr,
+                                         PRBool aMayBeAnon = PR_FALSE);
 
   /**
    * Create the relation if the given relation is null and add the targets to it
    * that are pointed by IDRefs attribute on the given node.
    *
    * @param  aRelationType  [in] relation type
    * @param  aRelation      [in, out] relation object
    * @param  aContent       [in] node having the given IDRefs attribute
--- a/accessible/src/xul/nsXULTabAccessible.cpp
+++ b/accessible/src/xul/nsXULTabAccessible.cpp
@@ -144,17 +144,18 @@ nsXULTabAccessible::GetRelationByType(PR
   // Expose 'LABEL_FOR' relation on tab accessible for tabpanel accessible.
   // XXX: It makes sense to require the interface from xul:tab to get linked
   // tabpanel element.
   nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
 
   // Check whether tab and tabpanel are related by 'linkedPanel' attribute on
   // xul:tab element.
   rv = nsRelUtils::AddTargetFromIDRefAttr(aRelationType, aRelation, content,
-                                          nsAccessibilityAtoms::linkedPanel);
+                                          nsAccessibilityAtoms::linkedPanel,
+                                          PR_TRUE);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (rv != NS_OK_NO_RELATION_TARGET)
     return NS_OK;
 
   // If there is no 'linkedPanel' attribute on xul:tab element then we
   // assume tab and tabpanels are related 1 to 1. We follow algorithm from
   // the setter 'selectedIndex' of tabbox.xml#tabs binding.
--- a/browser/components/sessionstore/src/nsSessionStore.js
+++ b/browser/components/sessionstore/src/nsSessionStore.js
@@ -520,18 +520,23 @@ SessionStoreService.prototype = {
       case "DOMAutoComplete":
         this.onTabInput(aEvent.currentTarget.ownerDocument.defaultView, aEvent.currentTarget);
         break;
       case "scroll":
         this.onTabScroll(aEvent.currentTarget.ownerDocument.defaultView);
         break;
       case "TabOpen":
       case "TabClose":
-        var panelID = aEvent.originalTarget.linkedPanel;
-        var tabpanel = aEvent.originalTarget.ownerDocument.getElementById(panelID);
+        let target = aEvent.originalTarget;
+        let panelID = target.linkedPanel;
+        let ownerDoc = target.ownerDocument;
+        let bindingParent = ownerDoc.getBindingParent(target);
+        let tabpanel =
+          ownerDoc.getAnonymousElementByAttribute(bindingParent, "id",
+                                                  panelID);
         if (aEvent.type == "TabOpen") {
           this.onTabAdd(aEvent.currentTarget.ownerDocument.defaultView, tabpanel);
         }
         else {
           // aEvent.detail determines if the tab was closed by moving to a different window
           if (!aEvent.detail)
             this.onTabClose(aEvent.currentTarget.ownerDocument.defaultView, aEvent.originalTarget);
           this.onTabRemove(aEvent.currentTarget.ownerDocument.defaultView, tabpanel);
--- a/toolkit/content/widgets/tabbox.xml
+++ b/toolkit/content/widgets/tabbox.xml
@@ -344,17 +344,29 @@
 
             if (this._tabbox) {
               this._tabbox.setAttribute("selectedIndex", val);
               var tabpanels = this._tabbox.tabpanels;
               // This will cause an onselect event to fire for the tabpanel element.
               if (tabpanels) {
                 // find an id
                 let linkedPanelId = tab.linkedPanel;
-                let linkedPanel = linkedPanelId ? document.getElementById(linkedPanelId) : null;
+                let linkedPanel = null;
+                if (linkedPanelId) {
+                  let ownerDoc = tab.ownerDocument;
+                  let bindingParent = ownerDoc.getBindingParent(tab);
+                  if (bindingParent) {
+                    linkedPanel =
+                      ownerDoc.getAnonymousElementByAttribute(bindingParent,
+                                                              "id",
+                                                              linkedPanelId);
+                  }
+                  else
+                    linkedPanel = ownerDoc.getElementById(linkedPanelId);
+                }
                 if (linkedPanel)
                   tabpanels.selectedPanel = linkedPanel;
                 else
                   tabpanels.selectedIndex = val;
               }
             }
 
             if (!alreadySelected) {