Bug 1309271 - Fire accessibility focus events from focused content elements when focus changes from chrome to content. r=surkov
authorJim Mathies <jmathies@mozilla.com>
Tue, 06 Jun 2017 06:09:01 -0500
changeset 410695 43d1e5140752e9b49ea18efe371065dc37e44270
parent 410694 028a9e5e1355fb2a099f32200c09fb2d9b7e8ec4
child 410696 7fe1ee54c97bcb6cf7a96b3ee05c1d6f5e23e766
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssurkov
bugs1309271
milestone55.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 1309271 - Fire accessibility focus events from focused content elements when focus changes from chrome to content. r=surkov MozReview-Commit-ID: 5Iu2TQ58kGa
accessible/base/FocusManager.cpp
accessible/ipc/other/DocAccessibleChild.cpp
accessible/ipc/other/DocAccessibleChild.h
accessible/ipc/other/PDocAccessible.ipdl
accessible/ipc/win/DocAccessibleChild.cpp
accessible/ipc/win/DocAccessibleChild.h
accessible/ipc/win/PDocAccessible.ipdl
--- a/accessible/base/FocusManager.cpp
+++ b/accessible/base/FocusManager.cpp
@@ -10,16 +10,17 @@
 #include "nsAccessibilityService.h"
 #include "nsAccUtils.h"
 #include "nsEventShell.h"
 #include "Role.h"
 
 #include "nsFocusManager.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/dom/Element.h"
+#include "mozilla/dom/TabParent.h"
 
 namespace mozilla {
 namespace a11y {
 
 FocusManager::FocusManager()
 {
 }
 
@@ -185,22 +186,44 @@ FocusManager::ActiveItemChanged(Accessib
     if (logging::IsEnabled(logging::eFocus))
       logging::ActiveWidget(widget);
 #endif
     if (!widget || !widget->IsActiveWidget() || !widget->AreItemsOperable())
       return;
   }
   mActiveItem = aItem;
 
+  // If mActiveItem is null, we might need to shift a11y focus to a remote
+  // element.
+  if (!mActiveItem && XRE_IsParentProcess()) {
+    nsFocusManager* domfm = nsFocusManager::GetFocusManager();
+    if (domfm) {
+      nsIContent* focusedElm = domfm->GetFocusedContent();
+      if (focusedElm) {
+        bool remote = EventStateManager::IsRemoteTarget(focusedElm);
+        if (remote) {
+          dom::TabParent* tab = dom::TabParent::GetFrom(focusedElm);
+          if (tab) {
+            a11y::DocAccessibleParent* dap = tab->GetTopLevelDocAccessible();
+            if (dap) {
+              Unused << dap->SendRestoreFocus();
+            }
+          }
+        }
+      }
+    }
+  }
+
   // If active item is changed then fire accessible focus event on it, otherwise
   // if there's no an active item then fire focus event to accessible having
   // DOM focus.
   Accessible* target = FocusedAccessible();
-  if (target)
+  if (target) {
     DispatchFocusEvent(target->Document(), target);
+  }
 }
 
 void
 FocusManager::ForceFocusEvent()
 {
   nsINode* focusedNode = FocusedDOMNode();
   if (focusedNode) {
     DocAccessible* document =
--- a/accessible/ipc/other/DocAccessibleChild.cpp
+++ b/accessible/ipc/other/DocAccessibleChild.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DocAccessibleChild.h"
 
+#include "nsAccessibilityService.h"
 #include "Accessible-inl.h"
 #include "ProxyAccessible.h"
 #include "Relation.h"
 #include "HyperTextAccessible-inl.h"
 #include "TextLeafAccessible.h"
 #include "ImageAccessible.h"
 #include "TableAccessible.h"
 #include "TableCellAccessible.h"
@@ -1998,10 +1999,17 @@ DocAccessibleChild::RecvDOMNodeID(const 
   nsIAtom* id = content->GetID();
   if (id) {
     id->ToString(*aDOMNodeID);
   }
 
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult
+DocAccessibleChild::RecvRestoreFocus()
+{
+  FocusMgr()->ForceFocusEvent();
+  return IPC_OK();
+}
+
 }
 }
--- a/accessible/ipc/other/DocAccessibleChild.h
+++ b/accessible/ipc/other/DocAccessibleChild.h
@@ -33,16 +33,18 @@ public:
     SetManager(aManager);
   }
 
   ~DocAccessibleChild()
   {
     MOZ_COUNT_DTOR_INHERITED(DocAccessibleChild, DocAccessibleChildBase);
   }
 
+  virtual mozilla::ipc::IPCResult RecvRestoreFocus() override;
+
   /*
    * Return the state for the accessible with given ID.
    */
   virtual mozilla::ipc::IPCResult RecvState(const uint64_t& aID, uint64_t* aState) override;
 
   /*
    * Return the native state for the accessible with given ID.
    */
--- a/accessible/ipc/other/PDocAccessible.ipdl
+++ b/accessible/ipc/other/PDocAccessible.ipdl
@@ -68,16 +68,22 @@ parent:
    * Tell the parent document to bind the existing document as a new child
    * document.
    */
   async BindChildDoc(PDocAccessible aChildDoc, uint64_t aID);
 
 child:
   async __delete__();
 
+  /*
+   * Called as a result of focus shifting from chrome to content
+   * elements through keyboard navigation.
+   */
+  async RestoreFocus();
+
   // Accessible
   nested(inside_sync) sync State(uint64_t aID) returns(uint64_t states);
   nested(inside_sync) sync NativeState(uint64_t aID) returns(uint64_t states);
   nested(inside_sync) sync Name(uint64_t aID) returns(nsString name);
   nested(inside_sync) sync Value(uint64_t aID) returns(nsString value);
   nested(inside_sync) sync Help(uint64_t aID) returns(nsString help);
   nested(inside_sync) sync Description(uint64_t aID) returns(nsString desc);
   nested(inside_sync) sync Attributes(uint64_t aID) returns(Attribute[] attributes);
--- a/accessible/ipc/win/DocAccessibleChild.cpp
+++ b/accessible/ipc/win/DocAccessibleChild.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DocAccessibleChild.h"
 
+#include "nsAccessibilityService.h"
 #include "Accessible-inl.h"
 #include "mozilla/a11y/PlatformChild.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "RootAccessible.h"
 
 namespace mozilla {
 namespace a11y {
 
@@ -302,11 +303,18 @@ DocAccessibleChild::SendBindChildDoc(Doc
     return DocAccessibleChildBase::SendBindChildDoc(aChildDoc, aNewParentID);
   }
 
   PushDeferredEvent(MakeUnique<SerializedBindChildDoc>(this, aChildDoc,
                                                        aNewParentID));
   return true;
 }
 
+ipc::IPCResult
+DocAccessibleChild::RecvRestoreFocus()
+{
+  FocusMgr()->ForceFocusEvent();
+  return IPC_OK();
+}
+
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/ipc/win/DocAccessibleChild.h
+++ b/accessible/ipc/win/DocAccessibleChild.h
@@ -23,20 +23,22 @@ class DocAccessibleChild : public DocAcc
 {
 public:
   DocAccessibleChild(DocAccessible* aDoc, IProtocol* aManager);
   ~DocAccessibleChild();
 
   virtual void Shutdown() override;
 
   virtual ipc::IPCResult
-  RecvParentCOMProxy(const IAccessibleHolder& aParentCOMProxy) override;
+    RecvParentCOMProxy(const IAccessibleHolder& aParentCOMProxy) override;
   virtual ipc::IPCResult
     RecvEmulatedWindow(const WindowsHandle& aEmulatedWindowHandle,
                        const IAccessibleHolder& aEmulatedWindowCOMProxy) override;
+  virtual ipc::IPCResult
+    RecvRestoreFocus() override;
 
   HWND GetNativeWindowHandle() const;
   IAccessible* GetEmulatedWindowIAccessible() const { return mEmulatedWindowProxy.get(); }
 
   IAccessible* GetParentIAccessible() const { return mParentProxy.get(); }
 
   bool SendEvent(const uint64_t& aID, const uint32_t& type);
   bool SendHideEvent(const uint64_t& aRootID, const bool& aFromUser);
--- a/accessible/ipc/win/PDocAccessible.ipdl
+++ b/accessible/ipc/win/PDocAccessible.ipdl
@@ -69,14 +69,19 @@ parent:
 
   sync GetWindowedPluginIAccessible(WindowsHandle aHwnd)
     returns (IAccessibleHolder aPluginCOMProxy);
 
 child:
   async ParentCOMProxy(IAccessibleHolder aParentCOMProxy);
   async EmulatedWindow(WindowsHandle aEmulatedWindowHandle,
                        IAccessibleHolder aEmulatedWindowCOMProxy);
+  /*
+   * Called as a result of focus shifting from chrome to content
+   * elements through keyboard navigation.
+   */
+  async RestoreFocus();
 
   async __delete__();
 };
 
 }
 }