Bug 567636 - replace GetAccessibleInParentChain on GetContainerAccessible, r=marcoz, sr=neil
authorAlexander Surkov <surkov.alexander@gmail.com>
Tue, 25 May 2010 17:40:39 +0900
changeset 42800 6d27d066e6856e8a4250ad0a8497388ababdb184
parent 42799 537743b069d0c4291cf5981e82cad897f54aa92e
child 42801 1817cd496b3bf37fa36c589cb761760ae0a246ff
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmarcoz, neil
bugs567636
milestone1.9.3a5pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
Bug 567636 - replace GetAccessibleInParentChain on GetContainerAccessible, r=marcoz, sr=neil
accessible/public/nsIAccessibleDocument.idl
accessible/src/base/nsAccessNode.cpp
accessible/src/base/nsAccessibilityService.cpp
accessible/src/base/nsAccessibilityService.h
accessible/src/base/nsAccessible.cpp
accessible/src/base/nsDocAccessible.cpp
--- a/accessible/public/nsIAccessibleDocument.idl
+++ b/accessible/public/nsIAccessibleDocument.idl
@@ -53,17 +53,17 @@ interface nsIDOMWindow;
  * You can QueryInterface to nsIAccessibleDocument from
  * the nsIAccessible or nsIAccessNode for the root node
  * of a document. You can also get one from 
  * nsIAccessNode::GetAccessibleDocument() or 
  * nsIAccessibleEvent::GetAccessibleDocument()
  *
  * @status UNDER_REVIEW
  */
-[scriptable, uuid(471909e7-0ea4-4ce0-bf31-a1372b2b285c)]
+[scriptable, uuid(03c6ce8a-aa40-4484-9282-e6579c56e054)]
 interface nsIAccessibleDocument : nsISupports
 {
   /**
    * The URL of the document
    */
   readonly attribute AString URL;
 
   /**
@@ -96,21 +96,9 @@ interface nsIAccessibleDocument : nsISup
    */
   AString getNameSpaceURIForID(in short nameSpaceID);
 
   /**
    * The window handle for the OS window the document is being displayed in.
    * For example, in Windows you can static cast it to an HWND.
    */
   [noscript] readonly attribute voidPtr windowHandle;
-
-  /**
-   * Returns the first accessible parent of a DOM node.
-   * Guaranteed not to return nsnull if the DOM node is in a document.
-   * @param aDOMNode The DOM node we need an accessible for.
-   * @param aCanCreate Can accessibles be created or must it be the first 
-   *                   cached accessible in the parent chain?
-   * @return An first nsIAccessible found by crawling up the DOM node
-   *         to the document root.
-   */
-  nsIAccessible getAccessibleInParentChain(in nsIDOMNode aDOMNode,
-                                           in boolean aCanCreate);
 };
--- a/accessible/src/base/nsAccessNode.cpp
+++ b/accessible/src/base/nsAccessNode.cpp
@@ -176,23 +176,20 @@ nsAccessNode::Init()
     return NS_ERROR_OUT_OF_MEMORY;
 
   // Make sure an ancestor in real content is cached
   // so that nsDocAccessible::RefreshNodes() can find the anonymous subtree to release when
   // the root node goes away
   nsCOMPtr<nsIContent> content = do_QueryInterface(mDOMNode);
   if (content && content->IsInAnonymousSubtree()) {
     // Specific examples of where this is used: <input type="file"> and <xul:findbar>
-    nsCOMPtr<nsIAccessible> parentAccessible;
-    docAcc->GetAccessibleInParentChain(mDOMNode, PR_TRUE,
-                                       getter_AddRefs(parentAccessible));
-    if (parentAccessible) {
-      PRInt32 childCountUnused;
-      parentAccessible->GetChildCount(&childCountUnused);
-    }
+    nsAccessible *parent = GetAccService()->GetContainerAccessible(mDOMNode,
+                                                                   PR_TRUE);
+    if (parent)
+      parent->EnsureChildren();
   }
 
 #ifdef DEBUG_A11Y
   mIsInitialized = PR_TRUE;
 #endif
 
   return NS_OK;
 }
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -263,33 +263,30 @@ nsAccessibilityService::NotifyOfAnchorJu
 {
   nsIDocument *document = aTarget->GetCurrentDoc();
   nsCOMPtr<nsIDOMNode> documentNode(do_QueryInterface(document));
   if (!documentNode)
     return;
 
   nsCOMPtr<nsIDOMNode> targetNode(do_QueryInterface(aTarget));
 
-  nsCOMPtr<nsIAccessible> targetAcc;
-  GetAccessibleFor(targetNode, getter_AddRefs(targetAcc));
+  nsAccessible *targetAcc = GetAccessible(targetNode);
 
   // Getting the targetAcc above will have ensured accessible doc creation.
   // XXX Bug 561683
   nsRefPtr<nsDocAccessible> accessibleDoc =
     nsAccessNode::GetDocAccessibleFor(documentNode);
   if (!accessibleDoc)
     return;
 
   // If the jump target is not accessible then fire an event for nearest
   // accessible in parent chain.
   if (!targetAcc) {
-        accessibleDoc->GetAccessibleInParentChain(targetNode, PR_TRUE,
-                                                  getter_AddRefs(targetAcc));
-        nsCOMPtr<nsIAccessNode> accNode = do_QueryInterface(targetAcc);
-        accNode->GetDOMNode(getter_AddRefs(targetNode));
+    targetAcc = GetContainerAccessible(targetNode, PR_TRUE);
+    targetNode = targetAcc->GetDOMNode();
   }
 
   NS_ASSERTION(targetNode,
       "No accessible in parent chain!? Expect at least a document accessible.");
   if (!targetNode)
     return;
 
   // XXX note in rare cases the node could go away before we flush the queue,
@@ -1240,16 +1237,62 @@ nsAccessibilityService::GetAccessibleInW
     return nsnull;
 
   nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(aWeakShell));
   nsRefPtr<nsAccessible> accessible = GetAccessible(aNode, presShell,
                                                     aWeakShell);
   return accessible;
 }
 
+nsAccessible *
+nsAccessibilityService::GetContainerAccessible(nsIDOMNode *aNode,
+                                               PRBool aCanCreate)
+{
+  if (!aNode)
+    return nsnull;
+
+  nsCOMPtr<nsINode> currNode(do_QueryInterface(aNode));
+  nsIDocument *document = currNode->GetCurrentDoc();
+  if (!document)
+    return nsnull;
+
+  nsIPresShell *presShell = document->GetPrimaryShell();
+  if (!presShell)
+    return nsnull;
+
+  nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(presShell));
+
+  nsAccessible *accessible = nsnull;
+  while (!accessible && (currNode = currNode->GetNodeParent())) {
+    nsCOMPtr<nsIDOMNode> currDOMNode(do_QueryInterface(currNode));
+
+    nsCOMPtr<nsIDOMNode> relevantDOMNode;
+    GetAccService()->GetRelevantContentNodeFor(currDOMNode,
+                                               getter_AddRefs(relevantDOMNode));
+    if (relevantDOMNode) {
+      currNode = do_QueryInterface(relevantDOMNode);
+      currDOMNode.swap(relevantDOMNode);
+    }
+
+    if (aCanCreate) {
+      accessible =
+        GetAccService()->GetAccessibleInWeakShell(currDOMNode, weakShell);
+
+    } else {
+      // Only return cached accessible, don't create anything.
+      nsRefPtr<nsAccessible> cachedAcc =
+        do_QueryObject(GetCachedAccessNode(currDOMNode, weakShell));
+
+      accessible = cachedAcc;
+    }
+  }
+
+  return accessible;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessibilityService private
 
 PRBool
 nsAccessibilityService::InitAccessible(nsAccessible *aAccessible,
                                        nsRoleMapEntry *aRoleMapEntry)
 {
   if (!aAccessible)
--- a/accessible/src/base/nsAccessibilityService.h
+++ b/accessible/src/base/nsAccessibilityService.h
@@ -182,16 +182,25 @@ public:
    * 
    * @param aNode       [in] the given node.
    * @param aPresShell  [in] the presentation shell of the given node.
    */
   nsAccessible *GetAccessibleInWeakShell(nsIDOMNode *aNode,
                                          nsIWeakReference *aPresShell);
 
   /**
+   * Return the first accessible parent of a DOM node.
+   *
+   * @param aDOMNode    [in] the DOM node to get an accessible for
+   * @param aCanCreate  [in] specifies if accessible can be created if it didn't
+   *                     exist
+   */
+  nsAccessible *GetContainerAccessible(nsIDOMNode *aNode, PRBool aCanCreate);
+
+  /**
    * Return an access node for the DOM node in the given presentation shell if
    * the access node already exists, otherwise null.
    *
    * @param  aNode       [in] the DOM node to get an access node for
    * @param  aPresShell  [in] the presentation shell which contains layout info
    *                       for the DOM node
    */
   nsAccessNode* GetCachedAccessNode(nsIDOMNode *aNode,
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -854,23 +854,21 @@ nsAccessible::GetChildAtPoint(PRInt32 aX
   nsCOMPtr<nsIDOMNode> relevantNode;
   GetAccService()->GetRelevantContentNodeFor(node,
                                              getter_AddRefs(relevantNode));
   if (!relevantNode) {
     NS_IF_ADDREF(*aChild = fallbackAnswer);
     return NS_OK;
   }
 
-  nsCOMPtr<nsIAccessible> accessible;
-  GetAccService()->GetAccessibleFor(relevantNode, getter_AddRefs(accessible));
+  nsAccessible *accessible = GetAccService()->GetAccessible(relevantNode);
   if (!accessible) {
     // No accessible for the node with the point, so find the first
     // accessible in the DOM parent chain
-    accDocument->GetAccessibleInParentChain(relevantNode, PR_TRUE,
-                                            getter_AddRefs(accessible));
+    accessible = GetAccService()->GetContainerAccessible(relevantNode, PR_TRUE);
     if (!accessible) {
       NS_IF_ADDREF(*aChild = fallbackAnswer);
       return NS_OK;
     }
   }
 
   if (accessible == this) {
     // Manually walk through accessible children and see if the are within this
@@ -2820,37 +2818,36 @@ nsAccessible*
 nsAccessible::GetParent()
 {
   if (IsDefunct())
     return nsnull;
 
   if (mParent)
     return mParent;
 
+#ifdef DEBUG
   nsDocAccessible *docAccessible = GetDocAccessible();
   NS_ASSERTION(docAccessible, "No document accessible for valid accessible!");
-
-  if (!docAccessible)
+#endif
+
+  nsAccessible *parent = GetAccService()->GetContainerAccessible(mDOMNode,
+                                                                 PR_TRUE);
+  NS_ASSERTION(parent, "No accessible parent for valid accessible!");
+  if (!parent)
     return nsnull;
 
-  nsCOMPtr<nsIAccessible> parent;
-  docAccessible->GetAccessibleInParentChain(mDOMNode, PR_TRUE,
-                                            getter_AddRefs(parent));
-
-  nsRefPtr<nsAccessible> parentAcc = do_QueryObject(parent);
-
 #ifdef DEBUG
-  NS_ASSERTION(!parentAcc->IsDefunct(), "Defunct parent!");
-
-  parentAcc->EnsureChildren();
+  NS_ASSERTION(!parent->IsDefunct(), "Defunct parent!");
+
+  parent->EnsureChildren();
   if (parent != mParent)
     NS_WARNING("Bad accessible tree!");
 #endif
 
-  return parentAcc;
+  return parent;
 }
 
 nsAccessible*
 nsAccessible::GetChildAt(PRUint32 aIndex)
 {
   if (EnsureChildren())
     return nsnull;
 
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -1450,19 +1450,19 @@ nsDocAccessible::FireTextChangeEventForT
   if (!mIsContentLoaded || !mDocument) {
     return;
   }
 
   nsCOMPtr<nsIDOMNode> node(do_QueryInterface(aContent));
   if (!node)
     return;
 
-  nsCOMPtr<nsIAccessible> accessible;
-  nsresult rv = GetAccessibleInParentChain(node, PR_TRUE, getter_AddRefs(accessible));
-  if (NS_FAILED(rv) || !accessible)
+  nsAccessible *accessible = GetAccService()->GetContainerAccessible(node,
+                                                                     PR_TRUE);
+  if (!accessible)
     return;
 
   nsRefPtr<nsHyperTextAccessible> textAccessible(do_QueryObject(accessible));
   if (!textAccessible)
     return;
 
   PRInt32 start = aInfo->mChangeStart;
 
@@ -1474,18 +1474,18 @@ nsDocAccessible::FireTextChangeEventForT
     aInfo->mChangeEnd - start; // text has been removed
 
   if (length > 0) {
     PRUint32 renderedStartOffset, renderedEndOffset;
     nsIFrame* frame = aContent->GetPrimaryFrame();
     if (!frame)
       return;
 
-    rv = textAccessible->ContentToRenderedOffset(frame, start,
-                                                 &renderedStartOffset);
+    nsresult rv = textAccessible->ContentToRenderedOffset(frame, start,
+                                                          &renderedStartOffset);
     if (NS_FAILED(rv))
       return;
 
     rv = textAccessible->ContentToRenderedOffset(frame, start + length,
                                                  &renderedEndOffset);
     if (NS_FAILED(rv))
       return;
 
@@ -1601,18 +1601,19 @@ nsDocAccessible::FireDelayedAccessibleEv
     mEventQueue->Push(aEvent);
 
   return NS_OK;
 }
 
 void
 nsDocAccessible::ProcessPendingEvent(nsAccEvent *aEvent)
 {  
-  nsCOMPtr<nsIAccessible> accessible;
-  aEvent->GetAccessible(getter_AddRefs(accessible));
+  nsCOMPtr<nsIAccessible> acc;
+  aEvent->GetAccessible(getter_AddRefs(acc));
+  nsRefPtr<nsAccessible> accessible(do_QueryObject(acc));
 
   nsCOMPtr<nsIDOMNode> domNode;
   aEvent->GetDOMNode(getter_AddRefs(domNode));
 
   PRUint32 eventType = aEvent->GetEventType();
   EIsFromUserInput isFromUserInput =
     aEvent->IsFromUserInput() ? eFromUserInput : eNoUserInput;
 
@@ -1640,32 +1641,30 @@ nsDocAccessible::ProcessPendingEvent(nsA
         return;
       }
       gLastFocusedFrameType = newFrameType;
     }
   }
 
   if (eventType == nsIAccessibleEvent::EVENT_SHOW) {
 
-    nsCOMPtr<nsIAccessible> containerAccessible;
+    nsAccessible *containerAccessible = nsnull;
     if (accessible)
-      accessible->GetParent(getter_AddRefs(containerAccessible));
+      containerAccessible = accessible->GetParent();
 
     if (!containerAccessible) {
-      GetAccessibleInParentChain(domNode, PR_TRUE,
-                                 getter_AddRefs(containerAccessible));
+      containerAccessible = GetAccService()->GetContainerAccessible(domNode,
+                                                                    PR_TRUE);
       if (!containerAccessible)
         containerAccessible = this;
     }
 
     if (isAsync) {
       // For asynch show, delayed invalidatation of parent's children
-      nsRefPtr<nsAccessible> containerAcc = do_QueryObject(containerAccessible);
-      if (containerAcc)
-        containerAcc->InvalidateChildren();
+      containerAccessible->InvalidateChildren();
 
       // Some show events in the subtree may have been removed to 
       // avoid firing redundant events. But, we still need to make sure any
       // accessibles parenting those shown nodes lose their child references.
       InvalidateChildrenInSubtree(domNode);
     }
 
     // Also fire text changes if the node being created could affect the text in an nsIAccessibleText parent.
@@ -1695,17 +1694,17 @@ nsDocAccessible::ProcessPendingEvent(nsA
     if (eventType == nsIAccessibleEvent::EVENT_INTERNAL_LOAD) {
       nsRefPtr<nsDocAccessible> docAcc = do_QueryObject(accessible);
       NS_ASSERTION(docAcc, "No doc accessible for doc load event");
 
       if (docAcc)
         docAcc->FireDocLoadEvents(nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE);
     }
     else if (eventType == nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED) {
-      nsCOMPtr<nsIAccessibleText> accessibleText = do_QueryInterface(accessible);
+      nsCOMPtr<nsIAccessibleText> accessibleText = do_QueryObject(accessible);
       PRInt32 caretOffset;
       if (accessibleText && NS_SUCCEEDED(accessibleText->GetCaretOffset(&caretOffset))) {
 #ifdef DEBUG_A11Y
         PRUnichar chAtOffset;
         accessibleText->GetCharacterAtOffset(caretOffset, &chAtOffset);
         printf("\nCaret moved to %d with char %c", caretOffset, chAtOffset);
 #endif
 #ifdef DEBUG_CARET
@@ -1910,24 +1909,23 @@ nsDocAccessible::InvalidateCacheSubtree(
 
     nsIEventStateManager *esm = presShell->GetPresContext()->EventStateManager();
     NS_ENSURE_TRUE(esm,);
 
     if (!esm->IsHandlingUserInputExternal()) {
       // Changes during page load, but not caused by user input
       // Just invalidate accessible hierarchy and return,
       // otherwise the page load time slows down way too much
-      nsCOMPtr<nsIAccessible> containerAccessible;
-      GetAccessibleInParentChain(childNode, PR_FALSE, getter_AddRefs(containerAccessible));
+      nsAccessible *containerAccessible =
+        GetAccService()->GetContainerAccessible(childNode, PR_FALSE);
       if (!containerAccessible) {
         containerAccessible = this;
       }
 
-      nsRefPtr<nsAccessible> containerAcc = do_QueryObject(containerAccessible);
-      containerAcc->InvalidateChildren();
+      containerAccessible->InvalidateChildren();
       return;
     }     
     // else: user input, so we must fall through and for full handling,
     // e.g. fire the mutation events. Note: user input could cause DOM_CREATE
     // during page load if user typed into an input field or contentEditable area
   }
 
   // Update last change state information
@@ -1947,18 +1945,18 @@ nsDocAccessible::InvalidateCacheSubtree(
   else if (aChangeType == nsIAccessibilityService::NODE_APPEND)
     printf("[Create %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
   else if (aChangeType == nsIAccessibilityService::NODE_REMOVE)
     printf("[Destroy  %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
   else if (aChangeType == nsIAccessibilityService::NODE_SIGNIFICANT_CHANGE)
     printf("[Type change %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
 #endif
 
-  nsCOMPtr<nsIAccessible> containerAccessible;
-  GetAccessibleInParentChain(childNode, PR_TRUE, getter_AddRefs(containerAccessible));
+  nsAccessible *containerAccessible =
+    GetAccService()->GetContainerAccessible(childNode, PR_TRUE);
   if (!containerAccessible) {
     containerAccessible = this;
   }
 
   if (!isShowing) {
     // Fire EVENT_HIDE.
     if (isHiding) {
       nsCOMPtr<nsIContent> content(do_QueryInterface(childNode));
@@ -2008,20 +2006,17 @@ nsDocAccessible::InvalidateCacheSubtree(
   // We will use this accessible to fire the accessible mutation event.
   // We're guaranteed success, because we will eventually end up at the doc accessible,
   // and there is always one of those.
 
   if (aChild && !isHiding) {
     if (!isAsynch) {
       // DOM already updated with new objects -- invalidate parent's children now
       // For asynch we must wait until layout updates before we invalidate the children
-      nsRefPtr<nsAccessible> containerAcc = do_QueryObject(containerAccessible);
-      if (containerAcc)
-        containerAcc->InvalidateChildren();
-
+      containerAccessible->InvalidateChildren();
     }
 
     // Fire EVENT_SHOW, EVENT_MENUPOPUP_START for newly visible content.
 
     // Fire after a short timer, because we want to make sure the view has been
     // updated to make this accessible content visible. If we don't wait,
     // the assistive technology may receive the event and then retrieve
     // nsIAccessibleStates::STATE_INVISIBLE for the event's accessible object.
@@ -2078,55 +2073,16 @@ nsDocAccessible::InvalidateCacheSubtree(
     new nsAccReorderEvent(containerAccessible, isAsynch,
                           isUnconditionalEvent,
                           aChild ? childNode.get() : nsnull);
   NS_ENSURE_TRUE(reorderEvent,);
 
   FireDelayedAccessibleEvent(reorderEvent);
 }
 
-// nsIAccessibleDocument method
-NS_IMETHODIMP
-nsDocAccessible::GetAccessibleInParentChain(nsIDOMNode *aNode,
-                                            PRBool aCanCreate,
-                                            nsIAccessible **aAccessible)
-{
-  // Find accessible in parent chain of DOM nodes, or return null
-  *aAccessible = nsnull;
-  nsCOMPtr<nsIDOMNode> currentNode(aNode), parentNode;
-  nsCOMPtr<nsIAccessNode> accessNode;
-
-  do {
-    currentNode->GetParentNode(getter_AddRefs(parentNode));
-    currentNode = parentNode;
-    if (!currentNode) {
-      NS_ADDREF_THIS();
-      *aAccessible = this;
-      break;
-    }
-
-    nsCOMPtr<nsIDOMNode> relevantNode;
-    if (NS_SUCCEEDED(GetAccService()->GetRelevantContentNodeFor(currentNode, getter_AddRefs(relevantNode))) && relevantNode) {
-      currentNode = relevantNode;
-    }
-    if (aCanCreate) {
-      nsAccessible *accessible =
-        GetAccService()->GetAccessibleInWeakShell(currentNode, mWeakShell);
-      NS_IF_ADDREF(*aAccessible = accessible);
-    }
-    else { // Only return cached accessibles, don't create anything
-      nsAccessNode* accessNode = GetCachedAccessNode(currentNode);
-      if (accessNode)
-        CallQueryInterface(accessNode, aAccessible);
-    }
-  } while (!*aAccessible);
-
-  return NS_OK;
-}
-
 nsresult
 nsDocAccessible::FireShowHideEvents(nsIDOMNode *aDOMNode,
                                     PRBool aAvoidOnThisNode,
                                     PRUint32 aEventType,
                                     EEventFiringType aDelayedOrNormal,
                                     PRBool aIsAsyncChange,
                                     EIsFromUserInput aIsFromUserInput)
 {