Bug 1268544: Integrate remote COM objects into a11y code; r=tbsaunde
authorAaron Klotz <aklotz@mozilla.com>
Thu, 18 Aug 2016 09:49:13 -0600
changeset 310155 ff58e1a5f48351b9a19c5cb7be11594447c91545
parent 310154 8c550a7e9c2adb445010ff404613cc5979bc6fc6
child 310156 ce6e2c41d939f533272a6356efc6c64b69c8f3a4
push id31532
push userryanvm@gmail.com
push dateFri, 19 Aug 2016 13:59:01 +0000
treeherderautoland@4f1e241f75a2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstbsaunde
bugs1268544
milestone51.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 1268544: Integrate remote COM objects into a11y code; r=tbsaunde MozReview-Commit-ID: ctPgegQ83a
accessible/base/DocManager.cpp
accessible/base/NotificationController.cpp
accessible/base/Platform.h
accessible/base/moz.build
accessible/ipc/DocAccessibleParent.cpp
accessible/ipc/win/DocAccessibleChild.cpp
accessible/ipc/win/PlatformChild.cpp
accessible/ipc/win/PlatformChild.h
accessible/ipc/win/moz.build
accessible/windows/msaa/DocAccessibleWrap.cpp
accessible/windows/msaa/DocAccessibleWrap.h
accessible/windows/msaa/Platform.cpp
--- a/accessible/base/DocManager.cpp
+++ b/accessible/base/DocManager.cpp
@@ -510,16 +510,21 @@ DocManager::CreateDocOrRootAccessible(ns
         // XXX We may need to handle the case that we don't have a tab child
         // differently.  It may be that this will cause us to fail to notify
         // the parent process about important accessible documents.
         if (tabChild) {
           DocAccessibleChild* ipcDoc = new DocAccessibleChild(docAcc);
           docAcc->SetIPCDoc(ipcDoc);
           static_cast<TabChild*>(tabChild.get())->
             SendPDocAccessibleConstructor(ipcDoc, nullptr, 0);
+
+#if defined(XP_WIN)
+          IAccessibleHolder holder(CreateHolderFromAccessible(docAcc));
+          ipcDoc->SendCOMProxy(holder);
+#endif
         }
       }
     }
   } else {
     parentDocAcc->BindChildDocument(docAcc);
   }
 
 #ifdef A11Y_LOG
--- a/accessible/base/NotificationController.cpp
+++ b/accessible/base/NotificationController.cpp
@@ -415,16 +415,20 @@ NotificationController::WillRefresh(mozi
 
       ipcDoc = new DocAccessibleChild(childDoc);
       childDoc->SetIPCDoc(ipcDoc);
       nsCOMPtr<nsITabChild> tabChild =
         do_GetInterface(mDocument->DocumentNode()->GetDocShell());
       if (tabChild) {
         static_cast<TabChild*>(tabChild.get())->
           SendPDocAccessibleConstructor(ipcDoc, parentIPCDoc, id);
+#if defined(XP_WIN)
+        IAccessibleHolder holder(CreateHolderFromAccessible(childDoc));
+        ipcDoc->SendCOMProxy(holder);
+#endif
       }
     }
   }
 
   mObservingState = eRefreshObserving;
   if (!mDocument)
     return;
 
--- a/accessible/base/Platform.h
+++ b/accessible/base/Platform.h
@@ -1,14 +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/. */
 
+#ifndef mozilla_a11y_Platform_h
+#define mozilla_a11y_Platform_h
+
 #include <stdint.h>
 
 class nsString;
 
 namespace mozilla {
 namespace a11y {
 
 class ProxyAccessible;
@@ -77,8 +80,9 @@ void ProxyTextChangeEvent(ProxyAccessibl
                           bool aFromUser);
 void ProxyShowHideEvent(ProxyAccessible* aTarget, ProxyAccessible* aParent,
                         bool aInsert, bool aFromUser);
 void ProxySelectionEvent(ProxyAccessible* aTarget, ProxyAccessible* aWidget,
                          uint32_t aType);
 } // namespace a11y
 } // namespace mozilla
 
+#endif // mozilla_a11y_Platform_h
--- a/accessible/base/moz.build
+++ b/accessible/base/moz.build
@@ -58,16 +58,28 @@ if CONFIG['A11Y_LOG']:
     UNIFIED_SOURCES += [
         'Logging.cpp',
     ]
 
 LOCAL_INCLUDES += [
     '/accessible/generic',
     '/accessible/html',
     '/accessible/ipc',
+]
+
+if CONFIG['OS_ARCH'] == 'WINNT':
+    LOCAL_INCLUDES += [
+        '/accessible/ipc/win',
+    ]
+else:
+    LOCAL_INCLUDES += [
+        '/accessible/ipc/other',
+    ]
+
+LOCAL_INCLUDES += [
     '/accessible/xpcom',
     '/accessible/xul',
     '/dom/base',
     '/dom/xbl',
     '/ipc/chromium/src',
     '/layout/generic',
     '/layout/style',
     '/layout/svg',
--- a/accessible/ipc/DocAccessibleParent.cpp
+++ b/accessible/ipc/DocAccessibleParent.cpp
@@ -477,17 +477,16 @@ DocAccessibleParent::GetXPCAccessible(Pr
 bool
 DocAccessibleParent::RecvCOMProxy(const IAccessibleHolder& aCOMProxy,
                                   IAccessibleHolder* aParentCOMProxy)
 {
   RefPtr<IAccessible> ptr(aCOMProxy.Get());
   SetCOMInterface(ptr);
 
   Accessible* outerDoc = OuterDocOfRemoteBrowser();
-  MOZ_ASSERT(outerDoc);
   IAccessible* rawNative = nullptr;
   if (outerDoc) {
     outerDoc->GetNativeInterface((void**) &rawNative);
   }
 
   aParentCOMProxy->Set(IAccessibleHolder::COMPtrType(rawNative));
   return true;
 }
--- a/accessible/ipc/win/DocAccessibleChild.cpp
+++ b/accessible/ipc/win/DocAccessibleChild.cpp
@@ -2,35 +2,42 @@
 /* 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 "Accessible-inl.h"
+#include "mozilla/a11y/PlatformChild.h"
+#include "mozilla/ClearOnShutdown.h"
 
 namespace mozilla {
 namespace a11y {
 
+static StaticAutoPtr<PlatformChild> sPlatformChild;
+
 DocAccessibleChild::DocAccessibleChild(DocAccessible* aDoc)
   : DocAccessibleChildBase(aDoc)
 {
   MOZ_COUNT_CTOR_INHERITED(DocAccessibleChild, DocAccessibleChildBase);
+  if (!sPlatformChild) {
+    sPlatformChild = new PlatformChild();
+    ClearOnShutdown(&sPlatformChild, ShutdownPhase::Shutdown);
+  }
 }
 
 DocAccessibleChild::~DocAccessibleChild()
 {
   MOZ_COUNT_DTOR_INHERITED(DocAccessibleChild, DocAccessibleChildBase);
 }
 
 void
 DocAccessibleChild::SendCOMProxy(const IAccessibleHolder& aProxy)
 {
   IAccessibleHolder parentProxy;
   PDocAccessibleChild::SendCOMProxy(aProxy, &parentProxy);
   mParentProxy.reset(parentProxy.Release());
-  MOZ_ASSERT(mParentProxy);
 }
 
 } // namespace a11y
 } // namespace mozilla
 
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/win/PlatformChild.cpp
@@ -0,0 +1,49 @@
+/* -*- 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 "mozilla/a11y/PlatformChild.h"
+#include "mozilla/mscom/EnsureMTA.h"
+#include "mozilla/mscom/InterceptorLog.h"
+
+#include "Accessible2.h"
+
+namespace mozilla {
+namespace a11y {
+
+/**
+ * Unfortunately the COM interceptor does not intrinsically handle array
+ * outparams. Instead we manually define the relevant metadata here, and
+ * register it in a call to mozilla::mscom::RegisterArrayData.
+ * @see mozilla::mscom::ArrayData
+ */
+static const mozilla::mscom::ArrayData sPlatformChildArrayData[] = {
+  {IID_IEnumVARIANT, 3, 1, VT_DISPATCH, IID_IDispatch, 2},
+  {IID_IAccessible2, 30, 1, VT_UNKNOWN | VT_BYREF, IID_IAccessibleRelation, 2},
+  {IID_IAccessibleRelation, 7, 1, VT_UNKNOWN | VT_BYREF, IID_IUnknown, 2}
+};
+
+// Type libraries are thread-neutral, so we can register those from any
+// apartment. OTOH, proxies must be registered from within the apartment where
+// we intend to instantiate them. Therefore RegisterProxy() must be called
+// via EnsureMTA.
+PlatformChild::PlatformChild()
+  : mAccTypelib(mozilla::mscom::RegisterTypelib(L"oleacc.dll",
+        mozilla::mscom::RegistrationFlags::eUseSystemDirectory))
+  , mMiscTypelib(mozilla::mscom::RegisterTypelib(L"Accessible.tlb"))
+{
+  mozilla::mscom::InterceptorLog::Init();
+  mozilla::mscom::RegisterArrayData(sPlatformChildArrayData);
+
+  UniquePtr<mozilla::mscom::RegisteredProxy> ia2Proxy;
+  mozilla::mscom::EnsureMTA([&ia2Proxy]() -> void {
+    ia2Proxy = Move(mozilla::mscom::RegisterProxy(L"ia2marshal.dll"));
+  });
+  mIA2Proxy = Move(ia2Proxy);
+}
+
+} // namespace a11y
+} // namespace mozilla
+
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/win/PlatformChild.h
@@ -0,0 +1,35 @@
+/* -*- 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/. */
+
+#ifndef mozilla_a11y_PlatformChild_h
+#define mozilla_a11y_PlatformChild_h
+
+#include "mozilla/mscom/Registration.h"
+
+namespace mozilla {
+namespace a11y {
+
+class PlatformChild
+{
+public:
+  PlatformChild();
+
+  PlatformChild(PlatformChild&) = delete;
+  PlatformChild(PlatformChild&&) = delete;
+  PlatformChild& operator=(PlatformChild&) = delete;
+  PlatformChild& operator=(PlatformChild&&) = delete;
+
+private:
+  UniquePtr<mozilla::mscom::RegisteredProxy> mIA2Proxy;
+  UniquePtr<mozilla::mscom::RegisteredProxy> mAccTypelib;
+  UniquePtr<mozilla::mscom::RegisteredProxy> mMiscTypelib;
+};
+
+} // namespace mozilla
+} // namespace a11y
+
+#endif // mozilla_a11y_PlatformChild_h
+
--- a/accessible/ipc/win/moz.build
+++ b/accessible/ipc/win/moz.build
@@ -7,22 +7,24 @@
 IPDL_SOURCES += ['PDocAccessible.ipdl']
 
 # with --disable-accessibility we need to compile PDocAccessible.ipdl, but not
 # the C++.
 if CONFIG['ACCESSIBILITY']:
     EXPORTS.mozilla.a11y += [
         'COMPtrTypes.h',
         'DocAccessibleChild.h',
+        'PlatformChild.h',
         'ProxyAccessible.h'
     ]
 
     SOURCES += [
         'COMPtrTypes.cpp',
         'DocAccessibleChild.cpp',
+        'PlatformChild.cpp',
         'ProxyAccessible.cpp',
     ]
 
     LOCAL_INCLUDES += [
         '/accessible/base',
         '/accessible/generic',
         '/accessible/windows/ia2',
         '/accessible/windows/msaa',
--- a/accessible/windows/msaa/DocAccessibleWrap.cpp
+++ b/accessible/windows/msaa/DocAccessibleWrap.cpp
@@ -2,16 +2,17 @@
 /* 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 "DocAccessibleWrap.h"
 
 #include "Compatibility.h"
+#include "DocAccessibleChild.h"
 #include "nsWinUtils.h"
 #include "mozilla/dom/TabChild.h"
 #include "Role.h"
 #include "RootAccessible.h"
 #include "sdnDocAccessible.h"
 #include "Statistics.h"
 
 #include "nsIDocShell.h"
@@ -39,16 +40,40 @@ IMPL_IUNKNOWN_QUERY_HEAD(DocAccessibleWr
     statistics::ISimpleDOMUsed();
     *aInstancePtr = static_cast<ISimpleDOMDocument*>(new sdnDocAccessible(this));
     static_cast<IUnknown*>(*aInstancePtr)->AddRef();
     return S_OK;
   }
 IMPL_IUNKNOWN_QUERY_TAIL_INHERITED(HyperTextAccessibleWrap)
 
 STDMETHODIMP
+DocAccessibleWrap::get_accParent(
+      /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdispParent)
+{
+  HRESULT hr = DocAccessible::get_accParent(ppdispParent);
+  if (*ppdispParent) {
+    return hr;
+  }
+
+  // We might be a top-level document in a content process.
+  DocAccessibleChild* ipcDoc = IPCDoc();
+  if (!ipcDoc) {
+    return S_FALSE;
+  }
+  IAccessible* dispParent = ipcDoc->GetParentIAccessible();
+  if (!dispParent) {
+    return S_FALSE;
+  }
+
+  dispParent->AddRef();
+  *ppdispParent = static_cast<IDispatch*>(dispParent);
+  return S_OK;
+}
+
+STDMETHODIMP
 DocAccessibleWrap::get_accValue(VARIANT aVarChild, BSTR __RPC_FAR* aValue)
 {
   A11Y_TRYBLOCK_BEGIN
 
   if (!aValue)
     return E_INVALIDARG;
   *aValue = nullptr;
 
--- a/accessible/windows/msaa/DocAccessibleWrap.h
+++ b/accessible/windows/msaa/DocAccessibleWrap.h
@@ -17,20 +17,24 @@ class DocAccessibleWrap : public DocAcce
 public:
   DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
   virtual ~DocAccessibleWrap();
 
   DECL_IUNKNOWN_INHERITED
 
   // IAccessible
 
-    // Override get_accValue to provide URL when no other value is available
-    virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accValue( 
-        /* [optional][in] */ VARIANT varChild,
-        /* [retval][out] */ BSTR __RPC_FAR *pszValue);
+  // Override get_accParent for e10s
+  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accParent(
+      /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdispParent) override;
+
+  // Override get_accValue to provide URL when no other value is available
+  virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accValue(
+      /* [optional][in] */ VARIANT varChild,
+      /* [retval][out] */ BSTR __RPC_FAR *pszValue) override;
 
   // Accessible
   virtual void Shutdown();
 
   // DocAccessible
   virtual void* GetNativeWindow() const;
 
   /**
--- a/accessible/windows/msaa/Platform.cpp
+++ b/accessible/windows/msaa/Platform.cpp
@@ -5,38 +5,63 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Platform.h"
 
 #include "AccEvent.h"
 #include "Compatibility.h"
 #include "HyperTextAccessibleWrap.h"
 #include "ia2AccessibleText.h"
+#include "nsIXULRuntime.h"
 #include "nsWinUtils.h"
 #include "mozilla/a11y/ProxyAccessible.h"
+#include "mozilla/mscom/InterceptorLog.h"
+#include "mozilla/mscom/Registration.h"
+#include "mozilla/StaticPtr.h"
 #include "ProxyWrappers.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
+using namespace mozilla::mscom;
+
+static StaticAutoPtr<RegisteredProxy> gRegProxy;
+static StaticAutoPtr<RegisteredProxy> gRegAccTlb;
+static StaticAutoPtr<RegisteredProxy> gRegMiscTlb;
 
 void
 a11y::PlatformInit()
 {
   Compatibility::Init();
 
   nsWinUtils::MaybeStartWindowEmulation();
   ia2AccessibleText::InitTextChangeData();
+  if (BrowserTabsRemoteAutostart()) {
+    mscom::InterceptorLog::Init();
+    UniquePtr<RegisteredProxy> regProxy(
+        mscom::RegisterProxy(L"ia2marshal.dll"));
+    gRegProxy = regProxy.release();
+    UniquePtr<RegisteredProxy> regAccTlb(
+        mscom::RegisterTypelib(L"oleacc.dll",
+                               RegistrationFlags::eUseSystemDirectory));
+    gRegAccTlb = regAccTlb.release();
+    UniquePtr<RegisteredProxy> regMiscTlb(
+        mscom::RegisterTypelib(L"Accessible.tlb"));
+    gRegMiscTlb = regMiscTlb.release();
+  }
 }
 
 void
 a11y::PlatformShutdown()
 {
   ::DestroyCaret();
 
   nsWinUtils::ShutdownWindowEmulation();
+  gRegProxy = nullptr;
+  gRegAccTlb = nullptr;
+  gRegMiscTlb = nullptr;
 }
 
 void
 a11y::ProxyCreated(ProxyAccessible* aProxy, uint32_t aInterfaces)
 {
   AccessibleWrap* wrapper = nullptr;
   if (aInterfaces & Interfaces::DOCUMENT) {
     wrapper = new DocProxyAccessibleWrap(aProxy);