Bug 891338 - Popup accessibility broken, r=tbsaunde, roc, f=marcoz, jamie
authorAlexander Surkov <surkov.alexander@gmail.com>
Mon, 22 Jul 2013 11:58:19 -0400
changeset 151753 b4b9e91729d369d62fd7651839cffc9cc24e6807
parent 151752 f155634c57b98af2c60a4fb813690fb667e295c6
child 151754 a51b7b6b60970c033a2841899bd6d3dc0c09a368
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstbsaunde, roc
bugs891338
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 891338 - Popup accessibility broken, r=tbsaunde, roc, f=marcoz, jamie
accessible/src/generic/DocAccessible.cpp
accessible/src/generic/DocAccessible.h
accessible/src/windows/msaa/AccessibleWrap.cpp
widget/windows/nsWindow.cpp
--- a/accessible/src/generic/DocAccessible.cpp
+++ b/accessible/src/generic/DocAccessible.cpp
@@ -1260,29 +1260,53 @@ DocAccessible::GetAccessibleByUniqueIDIn
     if (child)
       return child;
   }
 
   return nullptr;
 }
 
 Accessible*
-DocAccessible::GetAccessibleOrContainer(nsINode* aNode)
+DocAccessible::GetAccessibleOrContainer(nsINode* aNode) const
 {
   if (!aNode || !aNode->IsInDoc())
     return nullptr;
 
   nsINode* currNode = aNode;
   Accessible* accessible = nullptr;
   while (!(accessible = GetAccessible(currNode)) &&
          (currNode = currNode->GetParentNode()));
 
   return accessible;
 }
 
+Accessible*
+DocAccessible::GetAccessibleOrDescendant(nsINode* aNode) const
+{
+  Accessible* acc = GetAccessible(aNode);
+  if (acc)
+    return acc;
+
+  acc = GetContainerAccessible(aNode);
+  if (acc) {
+    uint32_t childCnt = acc->ChildCount();
+    for (uint32_t idx = 0; idx < childCnt; idx++) {
+      Accessible* child = acc->GetChildAt(idx);
+      for (nsIContent* elm = child->GetContent();
+           elm && elm != acc->GetContent();
+           elm = elm->GetFlattenedTreeParent()) {
+        if (elm == aNode)
+          return child;
+      }
+    }
+  }
+
+  return nullptr;
+}
+
 bool
 DocAccessible::BindToDocument(Accessible* aAccessible,
                               nsRoleMapEntry* aRoleMapEntry)
 {
   if (!aAccessible)
     return false;
 
   // Put into DOM node cache.
--- a/accessible/src/generic/DocAccessible.h
+++ b/accessible/src/generic/DocAccessible.h
@@ -237,27 +237,32 @@ public:
    * this and nested documents.
    */
   Accessible* GetAccessibleByUniqueIDInSubtree(void* aUniqueID);
 
   /**
    * Return an accessible for the given DOM node or container accessible if
    * the node is not accessible.
    */
-  Accessible* GetAccessibleOrContainer(nsINode* aNode);
+  Accessible* GetAccessibleOrContainer(nsINode* aNode) const;
 
   /**
    * Return a container accessible for the given DOM node.
    */
-  Accessible* GetContainerAccessible(nsINode* aNode)
+  Accessible* GetContainerAccessible(nsINode* aNode) const
   {
     return aNode ? GetAccessibleOrContainer(aNode->GetParentNode()) : nullptr;
   }
 
   /**
+   * Return an accessible for the given node or its first accessible descendant.
+   */
+  Accessible* GetAccessibleOrDescendant(nsINode* aNode) const;
+
+  /**
    * Return true if the given ID is referred by relation attribute.
    *
    * @note Different elements may share the same ID if they are hosted inside
    *       XBL bindings. Be careful the result of this method may be  senseless
    *       while it's called for XUL elements (where XBL is used widely).
    */
   bool IsDependentID(const nsAString& aID) const
     { return mDependentIDsHash.Get(aID, nullptr); }
--- a/accessible/src/windows/msaa/AccessibleWrap.cpp
+++ b/accessible/src/windows/msaa/AccessibleWrap.cpp
@@ -1821,34 +1821,32 @@ AccessibleWrap::GetXPAccessibleFor(const
   // If lVal negative then it is treated as child ID and we should look for
   // accessible through whole accessible subtree including subdocuments.
   // Otherwise we treat lVal as index in parent.
 
   if (aVarChild.lVal < 0) {
     // Convert child ID to unique ID.
     void* uniqueID = reinterpret_cast<void*>(-aVarChild.lVal);
 
-    // Document.
+    DocAccessible* document = Document();
+    Accessible* child =
+      document->GetAccessibleByUniqueIDInSubtree(uniqueID);
+
+    // If it is a document then just return an accessible.
     if (IsDoc())
-      return AsDoc()->GetAccessibleByUniqueIDInSubtree(uniqueID);
+      return child;
 
-    // ARIA document and menu popups.
-    if (ARIARole() == roles::DOCUMENT || IsMenuPopup()) {
-      DocAccessible* document = Document();
-      Accessible* child =
-        document->GetAccessibleByUniqueIDInSubtree(uniqueID);
+    // Otherwise check whether the accessible is a child (this path works for
+    // ARIA documents and popups).
+    Accessible* parent = child;
+    while (parent && parent != document) {
+      if (parent == this)
+        return child;
 
-      // Check whether the accessible for the given ID is a child.
-      Accessible* parent = child ? child->Parent() : nullptr;
-      while (parent && parent != document) {
-        if (parent == this)
-          return child;
-
-        parent = parent->Parent();
-      }
+      parent = parent->Parent();
     }
 
     return nullptr;
   }
 
   // Gecko child indices are 0-based in contrast to indices used in MSAA.
   return GetChildAt(aVarChild.lVal - 1);
 }
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -136,16 +136,21 @@
 #include "nsUXThemeConstants.h"
 #include "KeyboardLayout.h"
 #include "nsNativeDragTarget.h"
 #include <mmsystem.h> // needed for WIN32_LEAN_AND_MEAN
 #include <zmouse.h>
 #include <richedit.h>
 
 #if defined(ACCESSIBILITY)
+
+#ifdef DEBUG
+#include "mozilla/a11y/Logging.h"
+#endif
+
 #include "oleidl.h"
 #include <winuser.h>
 #include "nsAccessibilityService.h"
 #include "mozilla/a11y/DocAccessible.h"
 #include "mozilla/a11y/Platform.h"
 #if !defined(WINABLEAPI)
 #include <winable.h>
 #endif // !defined(WINABLEAPI)
@@ -6634,30 +6639,29 @@ nsWindow::NotifyIMEOfTextChange(uint32_t
 
 nsIMEUpdatePreference
 nsWindow::GetIMEUpdatePreference()
 {
   return IMEHandler::GetUpdatePreference();
 }
 
 #ifdef ACCESSIBILITY
-
-#ifdef DEBUG_WMGETOBJECT
+#ifdef DEBUG
 #define NS_LOG_WMGETOBJECT(aWnd, aHwnd, aAcc)                                  \
-  PR_LOG(gWindowsLog, PR_LOG_ALWAYS,                                           \
-         ("Get the window:\n  {\n     HWND: %d, parent HWND: %d, wndobj: %p,\n",\
-           aHwnd, ::GetParent(aHwnd), aWnd));                                  \
-  PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("     acc: %p", aAcc));                  \
-  if (aAcc) {                                                                  \
-    nsAutoString name;                                                         \
-    aAcc->Name(name);                                                          \
-    PR_LOG(gWindowsLog, PR_LOG_ALWAYS,                                         \
-           (", accname: %s", NS_ConvertUTF16toUTF8(name).get()));              \
-  }                                                                            \
-  PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("\n }\n"));
+  if (a11y::logging::IsEnabled(a11y::logging::ePlatforms)) {                   \
+    printf("Get the window:\n  {\n     HWND: %d, parent HWND: %d, wndobj: %p,\n",\
+           aHwnd, ::GetParent(aHwnd), aWnd);                                   \
+    printf("     acc: %p", aAcc);                                              \
+    if (aAcc) {                                                                \
+      nsAutoString name;                                                       \
+      aAcc->Name(name);                                                        \
+      printf(", accname: %s", NS_ConvertUTF16toUTF8(name).get());              \
+    }                                                                          \
+    printf("\n }\n");                                                          \
+  }
 
 #else
 #define NS_LOG_WMGETOBJECT(aWnd, aHwnd, aAcc)
 #endif
 
 a11y::Accessible*
 nsWindow::GetAccessible()
 {
@@ -6676,18 +6680,18 @@ nsWindow::GetAccessible()
     if (frame && nsLayoutUtils::IsPopup(frame)) {
       nsCOMPtr<nsIAccessibilityService> accService =
         services::GetAccessibilityService();
       if (accService) {
         a11y::DocAccessible* docAcc =
           GetAccService()->GetDocAccessible(frame->PresContext()->PresShell());
         if (docAcc) {
           NS_LOG_WMGETOBJECT(this, mWnd,
-                             docAcc->GetAccessible(frame->GetContent()));
-          return docAcc->GetAccessible(frame->GetContent());
+                             docAcc->GetAccessibleOrDescendant(frame->GetContent()));
+          return docAcc->GetAccessibleOrDescendant(frame->GetContent());
         }
       }
     }
   }
 
   // otherwise root document accessible.
   NS_LOG_WMGETOBJECT(this, mWnd, GetRootAccessible());
   return GetRootAccessible();