summaryrefslogtreecommitdiffstats
path: root/accessible/ipc/win
diff options
context:
space:
mode:
Diffstat (limited to 'accessible/ipc/win')
-rw-r--r--accessible/ipc/win/COMPtrTypes.cpp50
-rw-r--r--accessible/ipc/win/COMPtrTypes.h27
-rw-r--r--accessible/ipc/win/DocAccessibleChild.cpp237
-rw-r--r--accessible/ipc/win/DocAccessibleChild.h318
-rw-r--r--accessible/ipc/win/PDocAccessible.ipdl75
-rw-r--r--accessible/ipc/win/PlatformChild.cpp62
-rw-r--r--accessible/ipc/win/PlatformChild.h35
-rw-r--r--accessible/ipc/win/ProxyAccessible.cpp599
-rw-r--r--accessible/ipc/win/ProxyAccessible.h58
-rw-r--r--accessible/ipc/win/moz.build39
-rw-r--r--accessible/ipc/win/typelib/Accessible.idl16
-rw-r--r--accessible/ipc/win/typelib/Makefile.in31
-rw-r--r--accessible/ipc/win/typelib/moz.build13
13 files changed, 1560 insertions, 0 deletions
diff --git a/accessible/ipc/win/COMPtrTypes.cpp b/accessible/ipc/win/COMPtrTypes.cpp
new file mode 100644
index 000000000..857f4235e
--- /dev/null
+++ b/accessible/ipc/win/COMPtrTypes.cpp
@@ -0,0 +1,50 @@
+/* -*- 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/COMPtrTypes.h"
+
+#include "MainThreadUtils.h"
+#include "mozilla/a11y/Accessible.h"
+#include "mozilla/Move.h"
+#include "mozilla/mscom/MainThreadHandoff.h"
+#include "mozilla/RefPtr.h"
+
+using mozilla::mscom::MainThreadHandoff;
+using mozilla::mscom::STAUniquePtr;
+
+namespace mozilla {
+namespace a11y {
+
+IAccessibleHolder
+CreateHolderFromAccessible(Accessible* aAccToWrap)
+{
+ MOZ_ASSERT(aAccToWrap && NS_IsMainThread());
+ if (!aAccToWrap) {
+ return nullptr;
+ }
+
+ IAccessible* rawNative = nullptr;
+ aAccToWrap->GetNativeInterface((void**)&rawNative);
+ MOZ_ASSERT(rawNative);
+ if (!rawNative) {
+ return nullptr;
+ }
+
+ STAUniquePtr<IAccessible> iaToProxy(rawNative);
+
+ IAccessible* rawIntercepted = nullptr;
+ HRESULT hr = MainThreadHandoff::WrapInterface(Move(iaToProxy), &rawIntercepted);
+ MOZ_ASSERT(SUCCEEDED(hr));
+ if (FAILED(hr)) {
+ return nullptr;
+ }
+
+ IAccessibleHolder::COMPtrType iaIntercepted(rawIntercepted);
+ return IAccessibleHolder(Move(iaIntercepted));
+}
+
+} // namespace a11y
+} // namespace mozilla
diff --git a/accessible/ipc/win/COMPtrTypes.h b/accessible/ipc/win/COMPtrTypes.h
new file mode 100644
index 000000000..122e1ea5e
--- /dev/null
+++ b/accessible/ipc/win/COMPtrTypes.h
@@ -0,0 +1,27 @@
+/* -*- 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_COMPtrTypes_h
+#define mozilla_a11y_COMPtrTypes_h
+
+#include "mozilla/mscom/COMPtrHolder.h"
+
+#include <oleacc.h>
+
+namespace mozilla {
+namespace a11y {
+
+typedef mozilla::mscom::COMPtrHolder<IAccessible, IID_IAccessible> IAccessibleHolder;
+
+class Accessible;
+
+IAccessibleHolder
+CreateHolderFromAccessible(Accessible* aAccToWrap);
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif // mozilla_a11y_COMPtrTypes_h
diff --git a/accessible/ipc/win/DocAccessibleChild.cpp b/accessible/ipc/win/DocAccessibleChild.cpp
new file mode 100644
index 000000000..e8b8bebe5
--- /dev/null
+++ b/accessible/ipc/win/DocAccessibleChild.cpp
@@ -0,0 +1,237 @@
+/* -*- 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 "Accessible-inl.h"
+#include "mozilla/a11y/PlatformChild.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "RootAccessible.h"
+
+namespace mozilla {
+namespace a11y {
+
+static StaticAutoPtr<PlatformChild> sPlatformChild;
+
+DocAccessibleChild::DocAccessibleChild(DocAccessible* aDoc)
+ : DocAccessibleChildBase(aDoc)
+ , mIsRemoteConstructed(false)
+{
+ 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::Shutdown()
+{
+ if (IsConstructedInParentProcess()) {
+ DocAccessibleChildBase::Shutdown();
+ return;
+ }
+
+ PushDeferredEvent(MakeUnique<SerializedShutdown>(this));
+ DetachDocument();
+}
+
+bool
+DocAccessibleChild::RecvParentCOMProxy(const IAccessibleHolder& aParentCOMProxy)
+{
+ MOZ_ASSERT(!mParentProxy && !aParentCOMProxy.IsNull());
+ mParentProxy.reset(const_cast<IAccessibleHolder&>(aParentCOMProxy).Release());
+ SetConstructedInParentProcess();
+
+ for (uint32_t i = 0, l = mDeferredEvents.Length(); i < l; ++i) {
+ mDeferredEvents[i]->Dispatch();
+ }
+
+ mDeferredEvents.Clear();
+
+ return true;
+}
+
+void
+DocAccessibleChild::PushDeferredEvent(UniquePtr<DeferredEvent> aEvent)
+{
+ DocAccessibleChild* topLevelIPCDoc = nullptr;
+
+ if (mDoc && mDoc->IsRoot()) {
+ topLevelIPCDoc = this;
+ } else {
+ auto tabChild = static_cast<dom::TabChild*>(Manager());
+ if (!tabChild) {
+ return;
+ }
+
+ nsTArray<PDocAccessibleChild*> ipcDocAccs;
+ tabChild->ManagedPDocAccessibleChild(ipcDocAccs);
+
+ // Look for the top-level DocAccessibleChild - there will only be one
+ // per TabChild.
+ for (uint32_t i = 0, l = ipcDocAccs.Length(); i < l; ++i) {
+ auto ipcDocAcc = static_cast<DocAccessibleChild*>(ipcDocAccs[i]);
+ if (ipcDocAcc->mDoc && ipcDocAcc->mDoc->IsRoot()) {
+ topLevelIPCDoc = ipcDocAcc;
+ break;
+ }
+ }
+ }
+
+ if (topLevelIPCDoc) {
+ topLevelIPCDoc->mDeferredEvents.AppendElement(Move(aEvent));
+ }
+}
+
+bool
+DocAccessibleChild::SendEvent(const uint64_t& aID, const uint32_t& aType)
+{
+ if (IsConstructedInParentProcess()) {
+ return PDocAccessibleChild::SendEvent(aID, aType);
+ }
+
+ PushDeferredEvent(MakeUnique<SerializedEvent>(this, aID, aType));
+ return false;
+}
+
+void
+DocAccessibleChild::MaybeSendShowEvent(ShowEventData& aData, bool aFromUser)
+{
+ if (IsConstructedInParentProcess()) {
+ Unused << SendShowEvent(aData, aFromUser);
+ return;
+ }
+
+ PushDeferredEvent(MakeUnique<SerializedShow>(this, aData, aFromUser));
+}
+
+bool
+DocAccessibleChild::SendHideEvent(const uint64_t& aRootID,
+ const bool& aFromUser)
+{
+ if (IsConstructedInParentProcess()) {
+ return PDocAccessibleChild::SendHideEvent(aRootID, aFromUser);
+ }
+
+ PushDeferredEvent(MakeUnique<SerializedHide>(this, aRootID, aFromUser));
+ return true;
+}
+
+bool
+DocAccessibleChild::SendStateChangeEvent(const uint64_t& aID,
+ const uint64_t& aState,
+ const bool& aEnabled)
+{
+ if (IsConstructedInParentProcess()) {
+ return PDocAccessibleChild::SendStateChangeEvent(aID, aState, aEnabled);
+ }
+
+ PushDeferredEvent(MakeUnique<SerializedStateChange>(this, aID, aState,
+ aEnabled));
+ return true;
+}
+
+bool
+DocAccessibleChild::SendCaretMoveEvent(const uint64_t& aID,
+ const int32_t& aOffset)
+{
+ if (IsConstructedInParentProcess()) {
+ return PDocAccessibleChild::SendCaretMoveEvent(aID, aOffset);
+ }
+
+ PushDeferredEvent(MakeUnique<SerializedCaretMove>(this, aID, aOffset));
+ return true;
+}
+
+bool
+DocAccessibleChild::SendTextChangeEvent(const uint64_t& aID,
+ const nsString& aStr,
+ const int32_t& aStart,
+ const uint32_t& aLen,
+ const bool& aIsInsert,
+ const bool& aFromUser)
+{
+ if (IsConstructedInParentProcess()) {
+ return PDocAccessibleChild::SendTextChangeEvent(aID, aStr, aStart,
+ aLen, aIsInsert, aFromUser);
+ }
+
+ PushDeferredEvent(MakeUnique<SerializedTextChange>(this, aID, aStr, aStart,
+ aLen, aIsInsert, aFromUser));
+ return true;
+}
+
+bool
+DocAccessibleChild::SendSelectionEvent(const uint64_t& aID,
+ const uint64_t& aWidgetID,
+ const uint32_t& aType)
+{
+ if (IsConstructedInParentProcess()) {
+ return PDocAccessibleChild::SendSelectionEvent(aID, aWidgetID, aType);
+ }
+
+ PushDeferredEvent(MakeUnique<SerializedSelection>(this, aID,
+ aWidgetID,
+ aType));
+ return true;
+}
+
+bool
+DocAccessibleChild::SendRoleChangedEvent(const uint32_t& aRole)
+{
+ if (IsConstructedInParentProcess()) {
+ return PDocAccessibleChild::SendRoleChangedEvent(aRole);
+ }
+
+ PushDeferredEvent(MakeUnique<SerializedRoleChanged>(this, aRole));
+ return true;
+}
+
+bool
+DocAccessibleChild::ConstructChildDocInParentProcess(
+ DocAccessibleChild* aNewChildDoc,
+ uint64_t aUniqueID, uint32_t aMsaaID)
+{
+ if (IsConstructedInParentProcess()) {
+ // We may send the constructor immediately
+ auto tabChild = static_cast<dom::TabChild*>(Manager());
+ MOZ_ASSERT(tabChild);
+ bool result = tabChild->SendPDocAccessibleConstructor(aNewChildDoc, this,
+ aUniqueID, aMsaaID,
+ IAccessibleHolder());
+ if (result) {
+ aNewChildDoc->SetConstructedInParentProcess();
+ }
+ return result;
+ }
+
+ PushDeferredEvent(MakeUnique<SerializedChildDocConstructor>(aNewChildDoc, this,
+ aUniqueID, aMsaaID));
+ return true;
+}
+
+bool
+DocAccessibleChild::SendBindChildDoc(DocAccessibleChild* aChildDoc,
+ const uint64_t& aNewParentID)
+{
+ if (IsConstructedInParentProcess()) {
+ return DocAccessibleChildBase::SendBindChildDoc(aChildDoc, aNewParentID);
+ }
+
+ PushDeferredEvent(MakeUnique<SerializedBindChildDoc>(this, aChildDoc,
+ aNewParentID));
+ return true;
+}
+
+} // namespace a11y
+} // namespace mozilla
+
diff --git a/accessible/ipc/win/DocAccessibleChild.h b/accessible/ipc/win/DocAccessibleChild.h
new file mode 100644
index 000000000..7a3da0172
--- /dev/null
+++ b/accessible/ipc/win/DocAccessibleChild.h
@@ -0,0 +1,318 @@
+/* -*- 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_DocAccessibleChild_h
+#define mozilla_a11y_DocAccessibleChild_h
+
+#include "mozilla/a11y/COMPtrTypes.h"
+#include "mozilla/a11y/DocAccessibleChildBase.h"
+#include "mozilla/dom/TabChild.h"
+#include "mozilla/mscom/Ptr.h"
+
+namespace mozilla {
+namespace a11y {
+
+/*
+ * These objects handle content side communication for an accessible document,
+ * and their lifetime is the same as the document they represent.
+ */
+class DocAccessibleChild : public DocAccessibleChildBase
+{
+public:
+ explicit DocAccessibleChild(DocAccessible* aDoc);
+ ~DocAccessibleChild();
+
+ virtual void Shutdown() override;
+
+ virtual bool
+ RecvParentCOMProxy(const IAccessibleHolder& aParentCOMProxy) override;
+
+ 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);
+ bool SendStateChangeEvent(const uint64_t& aID, const uint64_t& aState,
+ const bool& aEnabled);
+ bool SendCaretMoveEvent(const uint64_t& aID, const int32_t& aOffset);
+ bool SendTextChangeEvent(const uint64_t& aID, const nsString& aStr,
+ const int32_t& aStart, const uint32_t& aLen,
+ const bool& aIsInsert, const bool& aFromUser);
+ bool SendSelectionEvent(const uint64_t& aID, const uint64_t& aWidgetID,
+ const uint32_t& aType);
+ bool SendRoleChangedEvent(const uint32_t& aRole);
+
+ bool ConstructChildDocInParentProcess(DocAccessibleChild* aNewChildDoc,
+ uint64_t aUniqueID, uint32_t aMsaaID);
+
+ bool SendBindChildDoc(DocAccessibleChild* aChildDoc,
+ const uint64_t& aNewParentID);
+
+protected:
+ virtual void MaybeSendShowEvent(ShowEventData& aData, bool aFromUser) override;
+
+private:
+ void RemoveDeferredConstructor();
+
+ bool IsConstructedInParentProcess() const { return mIsRemoteConstructed; }
+ void SetConstructedInParentProcess() { mIsRemoteConstructed = true; }
+
+ /**
+ * DocAccessibleChild should not fire events until it has asynchronously
+ * received the COM proxy for its parent. OTOH, content a11y may still be
+ * attempting to fire events during this window of time. If this object does
+ * not yet have its parent proxy, instead of immediately sending the events to
+ * our parent, we enqueue them to mDeferredEvents. As soon as
+ * RecvParentCOMProxy is called, we play back mDeferredEvents.
+ */
+ struct DeferredEvent
+ {
+ void Dispatch()
+ {
+ Dispatch(mTarget);
+ }
+
+ virtual ~DeferredEvent() {}
+
+ protected:
+ explicit DeferredEvent(DocAccessibleChild* aTarget)
+ : mTarget(aTarget)
+ {}
+
+ virtual void Dispatch(DocAccessibleChild* aIPCDoc) = 0;
+
+ private:
+ DocAccessibleChild* mTarget;
+ };
+
+ void PushDeferredEvent(UniquePtr<DeferredEvent> aEvent);
+
+ struct SerializedShow final : public DeferredEvent
+ {
+ SerializedShow(DocAccessibleChild* aTarget,
+ ShowEventData& aEventData, bool aFromUser)
+ : DeferredEvent(aTarget)
+ , mEventData(aEventData.ID(), aEventData.Idx(), nsTArray<AccessibleData>())
+ , mFromUser(aFromUser)
+ {
+ // Since IPDL doesn't generate a move constructor for ShowEventData,
+ // we move NewTree manually (ugh). We still construct with an empty
+ // NewTree above so that the compiler catches any changes made to the
+ // ShowEventData structure in IPDL.
+ mEventData.NewTree() = Move(aEventData.NewTree());
+ }
+
+ void Dispatch(DocAccessibleChild* aIPCDoc) override
+ {
+ Unused << aIPCDoc->SendShowEvent(mEventData, mFromUser);
+ }
+
+ ShowEventData mEventData;
+ bool mFromUser;
+ };
+
+ struct SerializedHide final : public DeferredEvent
+ {
+ SerializedHide(DocAccessibleChild* aTarget, uint64_t aRootID, bool aFromUser)
+ : DeferredEvent(aTarget)
+ , mRootID(aRootID)
+ , mFromUser(aFromUser)
+ {}
+
+ void Dispatch(DocAccessibleChild* aIPCDoc) override
+ {
+ Unused << aIPCDoc->SendHideEvent(mRootID, mFromUser);
+ }
+
+ uint64_t mRootID;
+ bool mFromUser;
+ };
+
+ struct SerializedStateChange final : public DeferredEvent
+ {
+ SerializedStateChange(DocAccessibleChild* aTarget, uint64_t aID,
+ uint64_t aState, bool aEnabled)
+ : DeferredEvent(aTarget)
+ , mID(aID)
+ , mState(aState)
+ , mEnabled(aEnabled)
+ {}
+
+ void Dispatch(DocAccessibleChild* aIPCDoc) override
+ {
+ Unused << aIPCDoc->SendStateChangeEvent(mID, mState, mEnabled);
+ }
+
+ uint64_t mID;
+ uint64_t mState;
+ bool mEnabled;
+ };
+
+ struct SerializedCaretMove final : public DeferredEvent
+ {
+ SerializedCaretMove(DocAccessibleChild* aTarget, uint64_t aID,
+ int32_t aOffset)
+ : DeferredEvent(aTarget)
+ , mID(aID)
+ , mOffset(aOffset)
+ {}
+
+ void Dispatch(DocAccessibleChild* aIPCDoc) override
+ {
+ Unused << aIPCDoc->SendCaretMoveEvent(mID, mOffset);
+ }
+
+ uint64_t mID;
+ int32_t mOffset;
+ };
+
+ struct SerializedTextChange final : public DeferredEvent
+ {
+ SerializedTextChange(DocAccessibleChild* aTarget, uint64_t aID,
+ const nsString& aStr, int32_t aStart, uint32_t aLen,
+ bool aIsInsert, bool aFromUser)
+ : DeferredEvent(aTarget)
+ , mID(aID)
+ , mStr(aStr)
+ , mStart(aStart)
+ , mLen(aLen)
+ , mIsInsert(aIsInsert)
+ , mFromUser(aFromUser)
+ {}
+
+ void Dispatch(DocAccessibleChild* aIPCDoc) override
+ {
+ Unused << aIPCDoc->SendTextChangeEvent(mID, mStr, mStart, mLen, mIsInsert,
+ mFromUser);
+ }
+
+ uint64_t mID;
+ nsString mStr;
+ int32_t mStart;
+ uint32_t mLen;
+ bool mIsInsert;
+ bool mFromUser;
+ };
+
+ struct SerializedSelection final : public DeferredEvent
+ {
+ SerializedSelection(DocAccessibleChild* aTarget, uint64_t aID,
+ uint64_t aWidgetID, uint32_t aType)
+ : DeferredEvent(aTarget)
+ , mID(aID)
+ , mWidgetID(aWidgetID)
+ , mType(aType)
+ {}
+
+ void Dispatch(DocAccessibleChild* aIPCDoc) override
+ {
+ Unused << aIPCDoc->SendSelectionEvent(mID, mWidgetID, mType);
+ }
+
+ uint64_t mID;
+ uint64_t mWidgetID;
+ uint32_t mType;
+ };
+
+ struct SerializedRoleChanged final : public DeferredEvent
+ {
+ explicit SerializedRoleChanged(DocAccessibleChild* aTarget, uint32_t aRole)
+ : DeferredEvent(aTarget)
+ , mRole(aRole)
+ {}
+
+ void Dispatch(DocAccessibleChild* aIPCDoc) override
+ {
+ Unused << aIPCDoc->SendRoleChangedEvent(mRole);
+ }
+
+ uint32_t mRole;
+ };
+
+ struct SerializedEvent final : public DeferredEvent
+ {
+ SerializedEvent(DocAccessibleChild* aTarget, uint64_t aID, uint32_t aType)
+ : DeferredEvent(aTarget)
+ , mID(aID)
+ , mType(aType)
+ {}
+
+ void Dispatch(DocAccessibleChild* aIPCDoc) override
+ {
+ Unused << aIPCDoc->SendEvent(mID, mType);
+ }
+
+ uint64_t mID;
+ uint32_t mType;
+ };
+
+ struct SerializedChildDocConstructor final : public DeferredEvent
+ {
+ SerializedChildDocConstructor(DocAccessibleChild* aIPCDoc,
+ DocAccessibleChild* aParentIPCDoc,
+ uint64_t aUniqueID, uint32_t aMsaaID)
+ : DeferredEvent(aParentIPCDoc)
+ , mIPCDoc(aIPCDoc)
+ , mUniqueID(aUniqueID)
+ , mMsaaID(aMsaaID)
+ {}
+
+ void Dispatch(DocAccessibleChild* aParentIPCDoc) override
+ {
+ auto tabChild = static_cast<dom::TabChild*>(aParentIPCDoc->Manager());
+ MOZ_ASSERT(tabChild);
+ Unused << tabChild->SendPDocAccessibleConstructor(mIPCDoc, aParentIPCDoc,
+ mUniqueID, mMsaaID,
+ IAccessibleHolder());
+ mIPCDoc->SetConstructedInParentProcess();
+ }
+
+ DocAccessibleChild* mIPCDoc;
+ uint64_t mUniqueID;
+ uint32_t mMsaaID;
+ };
+
+ friend struct SerializedChildDocConstructor;
+
+ struct SerializedBindChildDoc final : public DeferredEvent
+ {
+ SerializedBindChildDoc(DocAccessibleChild* aParentDoc,
+ DocAccessibleChild* aChildDoc, uint64_t aNewParentID)
+ : DeferredEvent(aParentDoc)
+ , mChildDoc(aChildDoc)
+ , mNewParentID(aNewParentID)
+ {}
+
+ void Dispatch(DocAccessibleChild* aParentIPCDoc) override
+ {
+ Unused << aParentIPCDoc->SendBindChildDoc(mChildDoc, mNewParentID);
+ }
+
+ DocAccessibleChild* mChildDoc;
+ uint64_t mNewParentID;
+ };
+
+ struct SerializedShutdown final : public DeferredEvent
+ {
+ explicit SerializedShutdown(DocAccessibleChild* aTarget)
+ : DeferredEvent(aTarget)
+ {
+ }
+
+ void Dispatch(DocAccessibleChild* aIPCDoc) override
+ {
+ aIPCDoc->Shutdown();
+ }
+ };
+
+ bool mIsRemoteConstructed;
+ mscom::ProxyUniquePtr<IAccessible> mParentProxy;
+ nsTArray<UniquePtr<DeferredEvent>> mDeferredEvents;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif // mozilla_a11y_DocAccessibleChild_h
diff --git a/accessible/ipc/win/PDocAccessible.ipdl b/accessible/ipc/win/PDocAccessible.ipdl
new file mode 100644
index 000000000..3389abd23
--- /dev/null
+++ b/accessible/ipc/win/PDocAccessible.ipdl
@@ -0,0 +1,75 @@
+/* -*- 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 protocol PFileDescriptorSet;
+include protocol PBrowser;
+
+using mozilla::a11y::IAccessibleHolder from "mozilla/a11y/IPCTypes.h";
+using mozilla::WindowsHandle from "ipc/IPCMessageUtils.h";
+
+namespace mozilla {
+namespace a11y {
+
+struct AccessibleData
+{
+ uint64_t ID;
+ int32_t MsaaID;
+ uint32_t Role;
+ uint32_t ChildrenCount;
+ uint32_t Interfaces;
+};
+
+struct ShowEventData
+{
+ uint64_t ID;
+ uint32_t Idx;
+ AccessibleData[] NewTree;
+};
+
+struct Attribute
+{
+ nsCString Name;
+ nsString Value;
+};
+
+sync protocol PDocAccessible
+{
+ manager PBrowser;
+
+parent:
+ async Shutdown();
+
+ /*
+ * Notify the parent process the document in the child process is firing an
+ * event.
+ */
+ async Event(uint64_t aID, uint32_t type);
+ async ShowEvent(ShowEventData data, bool aFromUser);
+ async HideEvent(uint64_t aRootID, bool aFromUser);
+ async StateChangeEvent(uint64_t aID, uint64_t aState, bool aEnabled);
+ async CaretMoveEvent(uint64_t aID, int32_t aOffset);
+ async TextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart, uint32_t aLen,
+ bool aIsInsert, bool aFromUser);
+ async SelectionEvent(uint64_t aID, uint64_t aWidgetID, uint32_t aType);
+ async RoleChangedEvent(uint32_t aRole);
+
+ /*
+ * Tell the parent document to bind the existing document as a new child
+ * document.
+ */
+ async BindChildDoc(PDocAccessible aChildDoc, uint64_t aID);
+
+ sync GetWindowedPluginIAccessible(WindowsHandle aHwnd)
+ returns (IAccessibleHolder aPluginCOMProxy);
+
+child:
+ async ParentCOMProxy(IAccessibleHolder aParentCOMProxy);
+
+ async __delete__();
+};
+
+}
+}
diff --git a/accessible/ipc/win/PlatformChild.cpp b/accessible/ipc/win/PlatformChild.cpp
new file mode 100644
index 000000000..01434a081
--- /dev/null
+++ b/accessible/ipc/win/PlatformChild.cpp
@@ -0,0 +1,62 @@
+/* -*- 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"
+#include "Accessible2_2.h"
+#include "AccessibleHypertext2.h"
+#include "AccessibleTableCell.h"
+
+#include "AccessibleHypertext2_i.c"
+
+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},
+ {IID_IAccessible2_2, 48, 2, VT_UNKNOWN | VT_BYREF, IID_IUnknown, 3,
+ mozilla::mscom::ArrayData::Flag::eAllocatedByServer},
+ {IID_IAccessibleTableCell, 4, 0, VT_UNKNOWN | VT_BYREF, IID_IUnknown, 1,
+ mozilla::mscom::ArrayData::Flag::eAllocatedByServer},
+ {IID_IAccessibleTableCell, 7, 0, VT_UNKNOWN | VT_BYREF, IID_IUnknown, 1,
+ mozilla::mscom::ArrayData::Flag::eAllocatedByServer},
+ {IID_IAccessibleHypertext2, 25, 0, VT_UNKNOWN | VT_BYREF, IID_IUnknown, 1,
+ mozilla::mscom::ArrayData::Flag::eAllocatedByServer}
+};
+
+// 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
+
diff --git a/accessible/ipc/win/PlatformChild.h b/accessible/ipc/win/PlatformChild.h
new file mode 100644
index 000000000..49daf161d
--- /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
+
diff --git a/accessible/ipc/win/ProxyAccessible.cpp b/accessible/ipc/win/ProxyAccessible.cpp
new file mode 100644
index 000000000..dcdf20ef9
--- /dev/null
+++ b/accessible/ipc/win/ProxyAccessible.cpp
@@ -0,0 +1,599 @@
+/* -*- 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 "Accessible2.h"
+#include "ProxyAccessible.h"
+#include "ia2AccessibleValue.h"
+#include "mozilla/a11y/DocAccessibleParent.h"
+#include "DocAccessible.h"
+#include "mozilla/a11y/DocManager.h"
+#include "mozilla/dom/Element.h"
+#include "mozilla/dom/TabParent.h"
+#include "mozilla/Unused.h"
+#include "mozilla/a11y/Platform.h"
+#include "RelationType.h"
+#include "mozilla/a11y/Role.h"
+#include "xpcAccessibleDocument.h"
+
+#include <comutil.h>
+
+static const VARIANT kChildIdSelf = {VT_I4};
+
+namespace mozilla {
+namespace a11y {
+
+bool
+ProxyAccessible::GetCOMInterface(void** aOutAccessible) const
+{
+ if (!aOutAccessible) {
+ return false;
+ }
+
+ if (!mCOMProxy) {
+ // See if we can lazily obtain a COM proxy
+ AccessibleWrap* wrap = WrapperFor(this);
+ bool isDefunct = false;
+ ProxyAccessible* thisPtr = const_cast<ProxyAccessible*>(this);
+ // NB: Don't pass CHILDID_SELF here, use the absolute MSAA ID. Otherwise
+ // GetIAccessibleFor will recurse into this function and we will just
+ // overflow the stack.
+ VARIANT realId = {VT_I4};
+ realId.ulVal = wrap->GetExistingID();
+ thisPtr->mCOMProxy = wrap->GetIAccessibleFor(realId, &isDefunct);
+ }
+
+ RefPtr<IAccessible> addRefed = mCOMProxy;
+ addRefed.forget(aOutAccessible);
+ return !!mCOMProxy;
+}
+
+/**
+ * Specializations of this template map an IAccessible type to its IID
+ */
+template<typename Interface> struct InterfaceIID {};
+
+template<>
+struct InterfaceIID<IAccessibleValue>
+{
+ static REFIID Value() { return IID_IAccessibleValue; }
+};
+
+template<>
+struct InterfaceIID<IAccessibleText>
+{
+ static REFIID Value() { return IID_IAccessibleText; }
+};
+
+/**
+ * Get the COM proxy for this proxy accessible and QueryInterface it with the
+ * correct IID
+ */
+template<typename Interface>
+static already_AddRefed<Interface>
+QueryInterface(const ProxyAccessible* aProxy)
+{
+ RefPtr<IAccessible> acc;
+ if (!aProxy->GetCOMInterface((void**)getter_AddRefs(acc))) {
+ return nullptr;
+ }
+
+ RefPtr<Interface> acc2;
+ if (FAILED(acc->QueryInterface(InterfaceIID<Interface>::Value(),
+ (void**)getter_AddRefs(acc2)))) {
+ return nullptr;
+ }
+
+ return acc2.forget();
+}
+
+void
+ProxyAccessible::Name(nsString& aName) const
+{
+ aName.Truncate();
+ RefPtr<IAccessible> acc;
+ if (!GetCOMInterface((void**)getter_AddRefs(acc))) {
+ return;
+ }
+
+ BSTR result;
+ HRESULT hr = acc->get_accName(kChildIdSelf, &result);
+ _bstr_t resultWrap(result, false);
+ if (FAILED(hr)) {
+ return;
+ }
+ aName = (wchar_t*)resultWrap;
+}
+
+void
+ProxyAccessible::Value(nsString& aValue) const
+{
+ aValue.Truncate();
+ RefPtr<IAccessible> acc;
+ if (!GetCOMInterface((void**)getter_AddRefs(acc))) {
+ return;
+ }
+
+ BSTR result;
+ HRESULT hr = acc->get_accValue(kChildIdSelf, &result);
+ _bstr_t resultWrap(result, false);
+ if (FAILED(hr)) {
+ return;
+ }
+ aValue = (wchar_t*)resultWrap;
+}
+
+void
+ProxyAccessible::Description(nsString& aDesc) const
+{
+ aDesc.Truncate();
+ RefPtr<IAccessible> acc;
+ if (!GetCOMInterface((void**)getter_AddRefs(acc))) {
+ return;
+ }
+
+ BSTR result;
+ HRESULT hr = acc->get_accDescription(kChildIdSelf, &result);
+ _bstr_t resultWrap(result, false);
+ if (FAILED(hr)) {
+ return;
+ }
+ aDesc = (wchar_t*)resultWrap;
+}
+
+uint64_t
+ProxyAccessible::State() const
+{
+ uint64_t state = 0;
+ RefPtr<IAccessible> acc;
+ if (!GetCOMInterface((void**)getter_AddRefs(acc))) {
+ return state;
+ }
+
+ VARIANT varState;
+ HRESULT hr = acc->get_accState(kChildIdSelf, &varState);
+ if (FAILED(hr)) {
+ return state;
+ }
+ return uint64_t(varState.lVal);
+}
+
+nsIntRect
+ProxyAccessible::Bounds()
+{
+ nsIntRect rect;
+
+ RefPtr<IAccessible> acc;
+ if (!GetCOMInterface((void**)getter_AddRefs(acc))) {
+ return rect;
+ }
+
+ long left;
+ long top;
+ long width;
+ long height;
+ HRESULT hr = acc->accLocation(&left, &top, &width, &height, kChildIdSelf);
+ if (FAILED(hr)) {
+ return rect;
+ }
+ rect.x = left;
+ rect.y = top;
+ rect.width = width;
+ rect.height = height;
+ return rect;
+}
+
+void
+ProxyAccessible::Language(nsString& aLocale)
+{
+ aLocale.Truncate();
+
+ RefPtr<IAccessible> acc;
+ if (!GetCOMInterface((void**)getter_AddRefs(acc))) {
+ return;
+ }
+
+ RefPtr<IAccessible2> acc2;
+ if (FAILED(acc->QueryInterface(IID_IAccessible2, (void**)getter_AddRefs(acc2)))) {
+ return;
+ }
+
+ IA2Locale locale;
+ HRESULT hr = acc2->get_locale(&locale);
+
+ _bstr_t langWrap(locale.language, false);
+ _bstr_t countryWrap(locale.country, false);
+ _bstr_t variantWrap(locale.variant, false);
+
+ if (FAILED(hr)) {
+ return;
+ }
+
+ // The remaining code should essentially be the inverse of the
+ // ia2Accessible::get_locale conversion to IA2Locale.
+
+ if (!!variantWrap) {
+ aLocale = (wchar_t*)variantWrap;
+ return;
+ }
+
+ if (!!langWrap) {
+ aLocale = (wchar_t*)langWrap;
+ if (!!countryWrap) {
+ aLocale += L"-";
+ aLocale += (wchar_t*)countryWrap;
+ }
+ }
+}
+
+static bool
+IsEscapedChar(const wchar_t c)
+{
+ return c == L'\\' || c == L':' || c == ',' || c == '=' || c == ';';
+}
+
+static bool
+ConvertBSTRAttributesToArray(const nsAString& aStr,
+ nsTArray<Attribute>* aAttrs)
+{
+ if (!aAttrs) {
+ return false;
+ }
+
+ enum
+ {
+ eName = 0,
+ eValue = 1,
+ eNumStates
+ } state;
+ nsAutoString tokens[eNumStates];
+ auto itr = aStr.BeginReading(), end = aStr.EndReading();
+
+ state = eName;
+ while (itr != end) {
+ switch (*itr) {
+ case L'\\':
+ // Skip the backslash so that we're looking at the escaped char
+ ++itr;
+ if (itr == end || !IsEscapedChar(*itr)) {
+ // Invalid state
+ return false;
+ }
+ break;
+ case L':':
+ if (state != eName) {
+ // Bad, should be looking at name
+ return false;
+ }
+ state = eValue;
+ ++itr;
+ continue;
+ case L';':
+ if (state != eValue) {
+ // Bad, should be looking at value
+ return false;
+ }
+ state = eName;
+ aAttrs->AppendElement(Attribute(NS_ConvertUTF16toUTF8(tokens[eName]),
+ tokens[eValue]));
+ tokens[eName].Truncate();
+ tokens[eValue].Truncate();
+ ++itr;
+ continue;
+ default:
+ break;
+ }
+ tokens[state] += *itr;
+ }
+ return true;
+}
+
+void
+ProxyAccessible::Attributes(nsTArray<Attribute>* aAttrs) const
+{
+ aAttrs->Clear();
+
+ RefPtr<IAccessible> acc;
+ if (!GetCOMInterface((void**)getter_AddRefs(acc))) {
+ return;
+ }
+
+ RefPtr<IAccessible2> acc2;
+ if (FAILED(acc->QueryInterface(IID_IAccessible2, (void**)getter_AddRefs(acc2)))) {
+ return;
+ }
+
+ BSTR attrs;
+ HRESULT hr = acc2->get_attributes(&attrs);
+ _bstr_t attrsWrap(attrs, false);
+ if (FAILED(hr)) {
+ return;
+ }
+
+ ConvertBSTRAttributesToArray(nsDependentString((wchar_t*)attrs,
+ attrsWrap.length()),
+ aAttrs);
+}
+
+double
+ProxyAccessible::CurValue()
+{
+ RefPtr<IAccessibleValue> acc = QueryInterface<IAccessibleValue>(this);
+ if (!acc) {
+ return UnspecifiedNaN<double>();
+ }
+
+ VARIANT currentValue;
+ HRESULT hr = acc->get_currentValue(&currentValue);
+ if (FAILED(hr) || currentValue.vt != VT_R8) {
+ return UnspecifiedNaN<double>();
+ }
+
+ return currentValue.dblVal;
+}
+
+bool
+ProxyAccessible::SetCurValue(double aValue)
+{
+ RefPtr<IAccessibleValue> acc = QueryInterface<IAccessibleValue>(this);
+ if (!acc) {
+ return false;
+ }
+
+ VARIANT currentValue;
+ VariantInit(&currentValue);
+ currentValue.vt = VT_R8;
+ currentValue.dblVal = aValue;
+ HRESULT hr = acc->setCurrentValue(currentValue);
+ return SUCCEEDED(hr);
+}
+
+double
+ProxyAccessible::MinValue()
+{
+ RefPtr<IAccessibleValue> acc = QueryInterface<IAccessibleValue>(this);
+ if (!acc) {
+ return UnspecifiedNaN<double>();
+ }
+
+ VARIANT minimumValue;
+ HRESULT hr = acc->get_minimumValue(&minimumValue);
+ if (FAILED(hr) || minimumValue.vt != VT_R8) {
+ return UnspecifiedNaN<double>();
+ }
+
+ return minimumValue.dblVal;
+}
+
+double
+ProxyAccessible::MaxValue()
+{
+ RefPtr<IAccessibleValue> acc = QueryInterface<IAccessibleValue>(this);
+ if (!acc) {
+ return UnspecifiedNaN<double>();
+ }
+
+ VARIANT maximumValue;
+ HRESULT hr = acc->get_maximumValue(&maximumValue);
+ if (FAILED(hr) || maximumValue.vt != VT_R8) {
+ return UnspecifiedNaN<double>();
+ }
+
+ return maximumValue.dblVal;
+}
+
+static IA2TextBoundaryType
+GetIA2TextBoundary(AccessibleTextBoundary aGeckoBoundaryType)
+{
+ switch (aGeckoBoundaryType) {
+ case nsIAccessibleText::BOUNDARY_CHAR:
+ return IA2_TEXT_BOUNDARY_CHAR;
+ case nsIAccessibleText::BOUNDARY_WORD_START:
+ return IA2_TEXT_BOUNDARY_WORD;
+ case nsIAccessibleText::BOUNDARY_LINE_START:
+ return IA2_TEXT_BOUNDARY_LINE;
+ default:
+ MOZ_RELEASE_ASSERT(false);
+ }
+}
+
+bool
+ProxyAccessible::TextSubstring(int32_t aStartOffset, int32_t aEndOffset,
+ nsString& aText) const
+{
+ RefPtr<IAccessibleText> acc = QueryInterface<IAccessibleText>(this);
+ if (!acc) {
+ return false;
+ }
+
+ BSTR result;
+ HRESULT hr = acc->get_text(static_cast<long>(aStartOffset),
+ static_cast<long>(aEndOffset), &result);
+ if (FAILED(hr)) {
+ return false;
+ }
+
+ _bstr_t resultWrap(result, false);
+ aText = (wchar_t*)result;
+
+ return true;
+}
+
+void
+ProxyAccessible::GetTextBeforeOffset(int32_t aOffset,
+ AccessibleTextBoundary aBoundaryType,
+ nsString& aText, int32_t* aStartOffset,
+ int32_t* aEndOffset)
+{
+ RefPtr<IAccessibleText> acc = QueryInterface<IAccessibleText>(this);
+ if (!acc) {
+ return;
+ }
+
+ BSTR result;
+ long start, end;
+ HRESULT hr = acc->get_textBeforeOffset(aOffset,
+ GetIA2TextBoundary(aBoundaryType),
+ &start, &end, &result);
+ if (FAILED(hr)) {
+ return;
+ }
+
+ _bstr_t resultWrap(result, false);
+ *aStartOffset = start;
+ *aEndOffset = end;
+ aText = (wchar_t*)result;
+}
+
+void
+ProxyAccessible::GetTextAfterOffset(int32_t aOffset,
+ AccessibleTextBoundary aBoundaryType,
+ nsString& aText, int32_t* aStartOffset,
+ int32_t* aEndOffset)
+{
+ RefPtr<IAccessibleText> acc = QueryInterface<IAccessibleText>(this);
+ if (!acc) {
+ return;
+ }
+
+ BSTR result;
+ long start, end;
+ HRESULT hr = acc->get_textAfterOffset(aOffset,
+ GetIA2TextBoundary(aBoundaryType),
+ &start, &end, &result);
+ if (FAILED(hr)) {
+ return;
+ }
+
+ _bstr_t resultWrap(result, false);
+ aText = (wchar_t*)result;
+ *aStartOffset = start;
+ *aEndOffset = end;
+}
+
+void
+ProxyAccessible::GetTextAtOffset(int32_t aOffset,
+ AccessibleTextBoundary aBoundaryType,
+ nsString& aText, int32_t* aStartOffset,
+ int32_t* aEndOffset)
+{
+ RefPtr<IAccessibleText> acc = QueryInterface<IAccessibleText>(this);
+ if (!acc) {
+ return;
+ }
+
+ BSTR result;
+ long start, end;
+ HRESULT hr = acc->get_textAtOffset(aOffset, GetIA2TextBoundary(aBoundaryType),
+ &start, &end, &result);
+ if (FAILED(hr)) {
+ return;
+ }
+
+ _bstr_t resultWrap(result, false);
+ aText = (wchar_t*)result;
+ *aStartOffset = start;
+ *aEndOffset = end;
+}
+
+bool
+ProxyAccessible::AddToSelection(int32_t aStartOffset, int32_t aEndOffset)
+{
+ RefPtr<IAccessibleText> acc = QueryInterface<IAccessibleText>(this);
+ if (!acc) {
+ return false;
+ }
+
+ return SUCCEEDED(acc->addSelection(static_cast<long>(aStartOffset),
+ static_cast<long>(aEndOffset)));
+}
+
+bool
+ProxyAccessible::RemoveFromSelection(int32_t aSelectionNum)
+{
+ RefPtr<IAccessibleText> acc = QueryInterface<IAccessibleText>(this);
+ if (!acc) {
+ return false;
+ }
+
+ return SUCCEEDED(acc->removeSelection(static_cast<long>(aSelectionNum)));
+}
+
+int32_t
+ProxyAccessible::CaretOffset()
+{
+ RefPtr<IAccessibleText> acc = QueryInterface<IAccessibleText>(this);
+ if (!acc) {
+ return -1;
+ }
+
+ long offset;
+ HRESULT hr = acc->get_caretOffset(&offset);
+ if (FAILED(hr)) {
+ return -1;
+ }
+
+ return static_cast<int32_t>(offset);
+}
+
+void
+ProxyAccessible::SetCaretOffset(int32_t aOffset)
+{
+ RefPtr<IAccessibleText> acc = QueryInterface<IAccessibleText>(this);
+ if (!acc) {
+ return;
+ }
+
+ acc->setCaretOffset(static_cast<long>(aOffset));
+}
+
+/**
+ * aScrollType should be one of the nsIAccessiblescrollType constants.
+ */
+void
+ProxyAccessible::ScrollSubstringTo(int32_t aStartOffset, int32_t aEndOffset,
+ uint32_t aScrollType)
+{
+ RefPtr<IAccessibleText> acc = QueryInterface<IAccessibleText>(this);
+ if (!acc) {
+ return;
+ }
+
+ acc->scrollSubstringTo(static_cast<long>(aStartOffset),
+ static_cast<long>(aEndOffset),
+ static_cast<IA2ScrollType>(aScrollType));
+}
+
+/**
+ * aCoordinateType is one of the nsIAccessibleCoordinateType constants.
+ */
+void
+ProxyAccessible::ScrollSubstringToPoint(int32_t aStartOffset, int32_t aEndOffset,
+ uint32_t aCoordinateType, int32_t aX,
+ int32_t aY)
+{
+ RefPtr<IAccessibleText> acc = QueryInterface<IAccessibleText>(this);
+ if (!acc) {
+ return;
+ }
+
+ IA2CoordinateType coordType;
+ if (aCoordinateType == nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE) {
+ coordType = IA2_COORDTYPE_SCREEN_RELATIVE;
+ } else if (aCoordinateType == nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE) {
+ coordType = IA2_COORDTYPE_PARENT_RELATIVE;
+ } else {
+ MOZ_RELEASE_ASSERT(false, "unsupported coord type");
+ }
+
+ acc->scrollSubstringToPoint(static_cast<long>(aStartOffset),
+ static_cast<long>(aEndOffset),
+ coordType,
+ static_cast<long>(aX),
+ static_cast<long>(aY));
+}
+
+} // namespace a11y
+} // namespace mozilla
diff --git a/accessible/ipc/win/ProxyAccessible.h b/accessible/ipc/win/ProxyAccessible.h
new file mode 100644
index 000000000..c8e5a43b1
--- /dev/null
+++ b/accessible/ipc/win/ProxyAccessible.h
@@ -0,0 +1,58 @@
+/* -*- 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_ProxyAccessible_h
+#define mozilla_a11y_ProxyAccessible_h
+
+#include "Accessible.h"
+#include "mozilla/a11y/ProxyAccessibleBase.h"
+#include "mozilla/a11y/Role.h"
+#include "nsIAccessibleText.h"
+#include "nsIAccessibleTypes.h"
+#include "nsString.h"
+#include "nsTArray.h"
+#include "nsRect.h"
+
+#include <oleacc.h>
+
+namespace mozilla {
+namespace a11y {
+
+class ProxyAccessible : public ProxyAccessibleBase<ProxyAccessible>
+{
+public:
+ ProxyAccessible(uint64_t aID, ProxyAccessible* aParent,
+ DocAccessibleParent* aDoc, role aRole, uint32_t aInterfaces)
+ : ProxyAccessibleBase(aID, aParent, aDoc, aRole, aInterfaces)
+ {
+ MOZ_COUNT_CTOR(ProxyAccessible);
+ }
+
+ ~ProxyAccessible()
+ {
+ MOZ_COUNT_DTOR(ProxyAccessible);
+ }
+
+#include "mozilla/a11y/ProxyAccessibleShared.h"
+
+ bool GetCOMInterface(void** aOutAccessible) const;
+
+protected:
+ explicit ProxyAccessible(DocAccessibleParent* aThisAsDoc)
+ : ProxyAccessibleBase(aThisAsDoc)
+ { MOZ_COUNT_CTOR(ProxyAccessible); }
+
+ void SetCOMInterface(const RefPtr<IAccessible>& aIAccessible)
+ { mCOMProxy = aIAccessible; }
+
+private:
+ RefPtr<IAccessible> mCOMProxy;
+};
+
+}
+}
+
+#endif
diff --git a/accessible/ipc/win/moz.build b/accessible/ipc/win/moz.build
new file mode 100644
index 000000000..4bbcec417
--- /dev/null
+++ b/accessible/ipc/win/moz.build
@@ -0,0 +1,39 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+if CONFIG['COMPILE_ENVIRONMENT']:
+ DIRS += ['typelib']
+
+# With --disable-accessibility, we need to compile PDocAccessible.ipdl (which
+# also depends on COMPtrTypes.h), but not the C++.
+IPDL_SOURCES += ['PDocAccessible.ipdl']
+EXPORTS.mozilla.a11y += ['COMPtrTypes.h']
+
+if CONFIG['ACCESSIBILITY']:
+ EXPORTS.mozilla.a11y += [
+ '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',
+ '/accessible/xpcom',
+ ]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'xul'
diff --git a/accessible/ipc/win/typelib/Accessible.idl b/accessible/ipc/win/typelib/Accessible.idl
new file mode 100644
index 000000000..82ddcf506
--- /dev/null
+++ b/accessible/ipc/win/typelib/Accessible.idl
@@ -0,0 +1,16 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=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/. */
+
+import "oaidl.idl";
+import "servprov.idl";
+
+[uuid(b4d37cda-0dac-45e6-b613-158a5eb94293)]
+library Accessible
+{
+ interface IEnumVARIANT;
+ interface IServiceProvider;
+};
+
diff --git a/accessible/ipc/win/typelib/Makefile.in b/accessible/ipc/win/typelib/Makefile.in
new file mode 100644
index 000000000..78e0cea29
--- /dev/null
+++ b/accessible/ipc/win/typelib/Makefile.in
@@ -0,0 +1,31 @@
+# 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/.
+
+GARBAGE += $(MIDL_GENERATED_FILES) done_gen dlldata.c
+
+MIDL_GENERATED_FILES = \
+ Accessible.h \
+ Accessible_i.c \
+ Accessible_p.c \
+ Accessible.tlb \
+ $(NULL)
+
+$(MIDL_GENERATED_FILES): done_gen
+
+done_gen: Accessible.idl
+ $(MIDL) $(MIDL_FLAGS) -Oicf $(srcdir)/Accessible.idl
+ touch $@
+
+export:: done_gen
+
+midl_exports := \
+ Accessible.tlb \
+ $(NULL)
+
+INSTALL_TARGETS += midl_exports
+midl_exports_FILES := $(midl_exports)
+midl_exports_DEST = $(DIST)/bin
+midl_exports_TARGET := export
+
+include $(topsrcdir)/config/rules.mk
diff --git a/accessible/ipc/win/typelib/moz.build b/accessible/ipc/win/typelib/moz.build
new file mode 100644
index 000000000..3bc45a136
--- /dev/null
+++ b/accessible/ipc/win/typelib/moz.build
@@ -0,0 +1,13 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+FINAL_TARGET_FILES += [
+ '!Accessible.tlb',
+]
+
+GENERATED_FILES += [
+ 'Accessible.tlb',
+]