Bug 376887. If document gets painted before being fully loaded, and gets focused, the accessible tree is often incorrectly truncated. r=surkov
authoraaronleventhal@moonset.net
Fri, 04 May 2007 08:15:00 -0700
changeset 1087 e5037f732350df0d34d15aafc1de216ccc2f1145
parent 1086 671b01724b587b1528899bf16c27f683c3b50ca0
child 1088 c07e8f48c02f7af76f6fd1f859b54a24dd8ee01c
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)
reviewerssurkov
bugs376887
milestone1.9a5pre
Bug 376887. If document gets painted before being fully loaded, and gets focused, the accessible tree is often incorrectly truncated. r=surkov
accessible/public/nsIAccessibleDocument.idl
accessible/src/base/nsAccessible.cpp
accessible/src/base/nsDocAccessible.cpp
accessible/src/base/nsRootAccessible.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(DD22939F-B470-4a56-9B80-8C7BA4031334)]
+[scriptable, uuid(60f8b190-63c4-4919-ac92-a7a8212fc813)]
 interface nsIAccessibleDocument : nsISupports
 {
   /**
    * The URL of the document
    */
   readonly attribute AString URL;
 
   /**
@@ -115,13 +115,15 @@ interface nsIAccessibleDocument : nsISup
    * @return The nsIAccessNode cached for this particular unique ID.
    */
   [noscript] nsIAccessNode getCachedAccessNode(in voidPtr aUniqueID);
 
   /**
    * 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);
+  nsIAccessible getAccessibleInParentChain(in nsIDOMNode aDOMNode, in boolean aCanCreate);
 };
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -590,17 +590,17 @@ NS_IMETHODIMP nsAccessible::GetParent(ns
   nsresult rv = GetCachedParent(aParent);
   if (NS_FAILED(rv) || *aParent) {
     return rv;
   }
 
   nsCOMPtr<nsIAccessibleDocument> docAccessible(GetDocAccessible());
   NS_ENSURE_TRUE(docAccessible, NS_ERROR_FAILURE);
 
-  return docAccessible->GetAccessibleInParentChain(mDOMNode, aParent);
+  return docAccessible->GetAccessibleInParentChain(mDOMNode, PR_TRUE, aParent);
 }
 
 NS_IMETHODIMP nsAccessible::GetCachedParent(nsIAccessible **  aParent)
 {
   *aParent = nsnull;
   if (!mWeakShell) {
     // This node has been shut down
     return NS_ERROR_FAILURE;
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -209,16 +209,19 @@ nsDocAccessible::GetState(PRUint32 *aSta
     // XXX Need to invent better check to see if doc is focusable,
     // which it should be if it is scrollable. A XUL document could be focusable.
     // See bug 376803.
     *aState |= nsIAccessibleStates::STATE_FOCUSABLE;
   }
 
   if (!mIsContentLoaded) {
     *aState |= nsIAccessibleStates::STATE_BUSY;
+    if (aExtraState) {
+      *aExtraState |= nsIAccessibleStates::EXT_STATE_STALE;
+    }
   }
  
   nsIFrame* frame = GetFrame();
   while (frame != nsnull && !frame->HasView()) {
     frame = frame->GetParent();
   }
  
   if (frame != nsnull) {
@@ -1360,19 +1363,20 @@ NS_IMETHODIMP nsDocAccessible::Invalidat
   // Invalidate cache subtree
   // We have to check for accessibles for each dom node by traversing DOM tree
   // instead of just the accessible tree, although that would be faster
   // Otherwise we might miss the nsAccessNode's that are not nsAccessible's.
 
   NS_ENSURE_TRUE(mDOMNode, NS_ERROR_FAILURE);
   nsCOMPtr<nsIDOMNode> childNode = aChild ? do_QueryInterface(aChild) : mDOMNode;
   if (!IsNodeRelevant(childNode)) {
-    return NS_OK;  // Don't fire event unless it's for an attached accessible
+    return NS_OK;  // Don't fire event unless it can be for an attached accessible
   }
-  if (!mIsContentLoaded && mAccessNodeCache.Count() <= 1) {
+  if (!mIsContentLoaded && mAccessNodeCache.Count() <= 1 &&
+      mAccChildCount == eChildCountUninitialized) {
     return NS_OK; // Still loading and nothing to invalidate yet
   }
 
   nsCOMPtr<nsIAccessNode> childAccessNode;
   GetCachedAccessNode(childNode, getter_AddRefs(childAccessNode));
   nsCOMPtr<nsIAccessible> childAccessible = do_QueryInterface(childAccessNode);
   if (!childAccessible && mIsContentLoaded && aChangeEventType != nsIAccessibleEvent::EVENT_HIDE) {
     // If not about to hide it, make sure there's an accessible so we can fire an
@@ -1425,18 +1429,18 @@ NS_IMETHODIMP nsDocAccessible::Invalidat
     nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem(do_QueryInterface(container));
     NS_ENSURE_TRUE(docShellTreeItem, NS_ERROR_FAILURE);
     nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
     docShellTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
     if (sameTypeRoot == docShellTreeItem) {
       containerAccessible = this;  // At the root of UI or content
     }
   }
-  if (!containerAccessible && privateChildAccessible) {
-    GetAccessibleInParentChain(childNode, getter_AddRefs(containerAccessible));
+  if (!containerAccessible) {
+    GetAccessibleInParentChain(childNode, mIsContentLoaded, getter_AddRefs(containerAccessible));
   }
   nsCOMPtr<nsPIAccessible> privateContainerAccessible =
     do_QueryInterface(containerAccessible);
   if (privateContainerAccessible) {
     privateContainerAccessible->InvalidateChildren();
   }
 
   if (!mIsContentLoaded) {
@@ -1487,17 +1491,17 @@ NS_IMETHODIMP nsDocAccessible::Invalidat
       ancestor = ancestor->GetParent();
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDocAccessible::GetAccessibleInParentChain(nsIDOMNode *aNode,
+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;
 
   nsIAccessibilityService *accService = GetAccService();
@@ -1512,17 +1516,22 @@ nsDocAccessible::GetAccessibleInParentCh
       break;
     }
 
     nsCOMPtr<nsIDOMNode> relevantNode;
     if (NS_SUCCEEDED(accService->GetRelevantContentNodeFor(currentNode, getter_AddRefs(relevantNode))) && relevantNode) {
       currentNode = relevantNode;
     }
 
-    accService->GetAccessibleInWeakShell(currentNode, mWeakShell, aAccessible);
+    if (aCanCreate) {
+      accService->GetAccessibleInWeakShell(currentNode, mWeakShell, aAccessible);
+    }
+    else {
+      accService->GetCachedAccessible(currentNode, mWeakShell, aAccessible);
+    }
   } while (!*aAccessible);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocAccessible::FireToolkitEvent(PRUint32 aEvent, nsIAccessible *aTarget,
                                   void * aData)
--- a/accessible/src/base/nsRootAccessible.cpp
+++ b/accessible/src/base/nsRootAccessible.cpp
@@ -812,17 +812,17 @@ nsresult nsRootAccessible::HandleEventWi
       if (Role(containerAccessible) == nsIAccessibleRole::ROLE_MENUBAR) {
         nsCOMPtr<nsPIAccessNode> menuBarAccessNode(do_QueryInterface(containerAccessible));
         NS_ENSURE_TRUE(menuBarAccessNode, NS_ERROR_FAILURE);
         nsCOMPtr<nsIMenuParent> menuParent = do_QueryInterface(menuBarAccessNode->GetFrame());
         NS_ENSURE_TRUE(menuParent, NS_ERROR_FAILURE);
         PRBool isActive;
         menuParent->GetIsActive(isActive);
         if (!isActive) {
-          // It is a top level menuitem. Only fire focus event the menu bar
+          // It is a top level menuitem. Only fire a focus event when the menu bar
           // is active.
           return NS_OK;
         }
       } else {
         // It is not top level menuitem
         // Only fire focus event if it is not inside collapsed popup
         if (State(containerAccessible) & nsIAccessibleStates::STATE_COLLAPSED)
           return NS_OK;