Bug 1421144: Fix IAccessible::accFocus on the root accessible for remote content. r?Surkov draft
authorJames Teh <jteh@mozilla.com>
Tue, 28 Nov 2017 04:15:56 +1000
changeset 707295 78fdecc0fa84b2e58f7fb5c51ed25d738b2e5363
parent 703549 da90245d47b17c750560dedb5cbe1973181166e3
child 742904 33a5c6faa0fafb07d27f43f8b749d1ea5f65f5bc
push id92076
push userbmo:jteh@mozilla.com
push dateTue, 05 Dec 2017 03:21:07 +0000
reviewersSurkov
bugs1421144
milestone59.0a1
Bug 1421144: Fix IAccessible::accFocus on the root accessible for remote content. r?Surkov The base implementation of accFocus can't handle the case when a remote document has focus and just returns no focus (VT_EMPTY). Override accFocus on the root accessible to try the accessible for the remote document in the active tab in this case. This fixes focus loss with NVDA when dismissing the System menu. MozReview-Commit-ID: 1jhAv08rDFU
accessible/windows/msaa/RootAccessibleWrap.cpp
accessible/windows/msaa/RootAccessibleWrap.h
--- a/accessible/windows/msaa/RootAccessibleWrap.cpp
+++ b/accessible/windows/msaa/RootAccessibleWrap.cpp
@@ -144,8 +144,57 @@ RootAccessibleWrap::accNavigate(
     return E_FAIL;
   }
 
   VariantInit(pvarEndUpAt);
   pvarEndUpAt->pdispVal = NativeAccessible(target);
   pvarEndUpAt->vt = VT_DISPATCH;
   return S_OK;
 }
+
+STDMETHODIMP
+RootAccessibleWrap::get_accFocus(
+      /* [retval][out] */ VARIANT __RPC_FAR *pvarChild)
+{
+  HRESULT hr = DocAccessibleWrap::get_accFocus(pvarChild);
+  if (FAILED(hr) || pvarChild->vt != VT_EMPTY) {
+    // We got a definite result (either failure or an accessible).
+    return hr;
+  }
+
+  // The base implementation reported no focus.
+  // Focus might be in a remote document.
+  // (The base implementation can't handle this.)
+  // Get the document in the active tab.
+  ProxyAccessible* docProxy = GetPrimaryRemoteTopLevelContentDoc();
+  if (!docProxy) {
+    return hr;
+  }
+  Accessible* docAcc = WrapperFor(docProxy);
+  if (!docAcc) {
+    return E_FAIL;
+  }
+  RefPtr<IDispatch> docDisp = NativeAccessible(docAcc);
+  if (!docDisp) {
+    return E_FAIL;
+  }
+  RefPtr<IAccessible> docIa;
+  hr = docDisp->QueryInterface(IID_IAccessible, (void**)getter_AddRefs(docIa));
+  MOZ_ASSERT(SUCCEEDED(hr));
+  MOZ_ASSERT(docIa);
+
+  // Ask this document for its focused descendant.
+  // We return this as is to the client except for CHILDID_SELF (see below).
+  hr = docIa->get_accFocus(pvarChild);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  if (pvarChild->vt == VT_I4 && pvarChild->lVal == CHILDID_SELF) {
+    // The document itself has focus.
+    // We're handling a call to accFocus on the root accessible,
+    // so replace CHILDID_SELF with the document accessible.
+    pvarChild->vt = VT_DISPATCH;
+    docDisp.forget(&pvarChild->pdispVal);
+  }
+
+  return S_OK;
+}
--- a/accessible/windows/msaa/RootAccessibleWrap.h
+++ b/accessible/windows/msaa/RootAccessibleWrap.h
@@ -38,16 +38,19 @@ public:
    */
   already_AddRefed<IUnknown> GetInternalUnknown();
 
   virtual /* [id] */ HRESULT STDMETHODCALLTYPE accNavigate(
     /* [in] */ long navDir,
     /* [optional][in] */ VARIANT varStart,
     /* [retval][out] */ VARIANT __RPC_FAR *pvarEndUpAt) override;
 
+  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accFocus(
+    /* [retval][out] */ VARIANT __RPC_FAR *pvarChild) override;
+
 private:
   // DECLARE_AGGREGATABLE declares the internal IUnknown methods as well as
   // mInternalUnknown.
   DECLARE_AGGREGATABLE(RootAccessibleWrap);
   IUnknown* mOuter;
 };
 
 } // namespace a11y