diff options
Diffstat (limited to 'accessible/ipc/win/DocAccessibleChild.h')
-rw-r--r-- | accessible/ipc/win/DocAccessibleChild.h | 392 |
1 files changed, 392 insertions, 0 deletions
diff --git a/accessible/ipc/win/DocAccessibleChild.h b/accessible/ipc/win/DocAccessibleChild.h new file mode 100644 index 0000000000..2f4eef00d7 --- /dev/null +++ b/accessible/ipc/win/DocAccessibleChild.h @@ -0,0 +1,392 @@ +/* -*- 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/BrowserBridgeChild.h" +#include "mozilla/dom/BrowserChild.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: + DocAccessibleChild(DocAccessible* aDoc, IProtocol* aManager); + ~DocAccessibleChild(); + + virtual void Shutdown() override; + + virtual ipc::IPCResult RecvParentCOMProxy( + const IDispatchHolder& aParentCOMProxy) override; + virtual ipc::IPCResult RecvEmulatedWindow( + const WindowsHandle& aEmulatedWindowHandle, + const IDispatchHolder& aEmulatedWindowCOMProxy) override; + virtual ipc::IPCResult RecvTopLevelDocCOMProxy( + const IAccessibleHolder& aCOMProxy) override; + virtual ipc::IPCResult RecvRestoreFocus() override; + + HWND GetNativeWindowHandle() const; + IDispatch* GetEmulatedWindowIAccessible() const { + return mEmulatedWindowProxy.get(); + } + + IDispatch* GetParentIAccessible() const { return mParentProxy.get(); } + IAccessible* GetTopLevelDocIAccessible() const { + return mTopLevelDocProxy.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, + const bool& aIsSelectionCollapsed, + const bool& aIsAtEndOfLine, + const int32_t& aGranularity); + bool SendCaretMoveEvent(const uint64_t& aID, + const LayoutDeviceIntRect& aCaretRect, + const int32_t& aOffset, + const bool& aIsSelectionCollapsed, + const bool& aIsAtEndOfLine, + const int32_t& aGranularity); + bool SendFocusEvent(const uint64_t& aID); + bool SendFocusEvent(const uint64_t& aID, + const LayoutDeviceIntRect& aCaretRect); + bool SendTextChangeEvent(const uint64_t& aID, const nsString& aStr, + const int32_t& aStart, const uint32_t& aLen, + const bool& aIsInsert, const bool& aFromUser, + const bool aDoSync = false); + bool SendSelectionEvent(const uint64_t& aID, const uint64_t& aWidgetID, + const uint32_t& aType); + bool SendRoleChangedEvent(const a11y::role& aRole, + uint8_t aRoleMapEntryIndex); + bool SendScrollingEvent(const uint64_t& aID, const uint64_t& aType, + const uint32_t& aScrollX, const uint32_t& aScrollY, + const uint32_t& aMaxScrollX, + const uint32_t& aMaxScrollY); + + bool ConstructChildDocInParentProcess(DocAccessibleChild* aNewChildDoc, + uint64_t aUniqueID, uint32_t aMsaaID); + + bool SendBindChildDoc(DocAccessibleChild* aChildDoc, + const uint64_t& aNewParentID); + + /** + * Set the embedder accessible on a BrowserBridgeChild to an accessible in + * this document. + * Sending this will be deferred if this DocAccessibleChild hasn't been + * constructed in the parent process yet. + */ + void SetEmbedderOnBridge(dom::BrowserBridgeChild* aBridge, uint64_t aID); + + protected: + virtual void MaybeSendShowEvent(ShowEventData& aData, + bool aFromUser) override; + + private: + void RemoveDeferredConstructor(); + + LayoutDeviceIntRect GetCaretRectFor(const uint64_t& aID); + + /** + * 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>(), aEventData.EventSuppressed()), + 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() = std::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, + const LayoutDeviceIntRect& aCaretRect, int32_t aOffset, + bool aIsSelectionCollapsed, bool aIsAtEndOfLine, + int32_t aGranularity) + : DeferredEvent(aTarget), + mID(aID), + mCaretRect(aCaretRect), + mOffset(aOffset), + mIsSelectionCollapsed(aIsSelectionCollapsed), + mIsAtEndOfLine(aIsAtEndOfLine), + mGranularity(aGranularity) {} + + void Dispatch(DocAccessibleChild* aIPCDoc) override { + Unused << aIPCDoc->SendCaretMoveEvent(mID, mCaretRect, mOffset, + mIsSelectionCollapsed, + mIsAtEndOfLine, mGranularity); + } + + uint64_t mID; + LayoutDeviceIntRect mCaretRect; + int32_t mOffset; + bool mIsSelectionCollapsed; + bool mIsAtEndOfLine; + int32_t mGranularity; + }; + + struct SerializedFocus final : public DeferredEvent { + SerializedFocus(DocAccessibleChild* aTarget, uint64_t aID, + const LayoutDeviceIntRect& aCaretRect) + : DeferredEvent(aTarget), mID(aID), mCaretRect(aCaretRect) {} + + void Dispatch(DocAccessibleChild* aIPCDoc) override { + Unused << aIPCDoc->SendFocusEvent(mID, mCaretRect); + } + + uint64_t mID; + LayoutDeviceIntRect mCaretRect; + }; + + 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, false); + } + + 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, + a11y::role aRole, uint8_t aRoleMapEntryIndex) + : DeferredEvent(aTarget), + mRole(aRole), + mRoleMapEntryIndex(aRoleMapEntryIndex) {} + + void Dispatch(DocAccessibleChild* aIPCDoc) override { + Unused << aIPCDoc->SendRoleChangedEvent(mRole, mRoleMapEntryIndex); + } + + a11y::role mRole; + uint8_t mRoleMapEntryIndex; + }; + + struct SerializedScrolling final : public DeferredEvent { + explicit SerializedScrolling(DocAccessibleChild* aTarget, uint64_t aID, + uint64_t aType, uint32_t aScrollX, + uint32_t aScrollY, uint32_t aMaxScrollX, + uint32_t aMaxScrollY) + : DeferredEvent(aTarget), + mID(aID), + mType(aType), + mScrollX(aScrollX), + mScrollY(aScrollY), + mMaxScrollX(aMaxScrollX), + mMaxScrollY(aMaxScrollY) {} + + void Dispatch(DocAccessibleChild* aIPCDoc) override { + Unused << aIPCDoc->SendScrollingEvent(mID, mType, mScrollX, mScrollY, + mMaxScrollX, mMaxScrollY); + } + + uint64_t mID; + uint64_t mType; + uint32_t mScrollX; + uint32_t mScrollY; + uint32_t mMaxScrollX; + uint32_t mMaxScrollY; + }; + + 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, + dom::BrowsingContext* aBrowsingContext, + uint32_t aMsaaID) + : DeferredEvent(aParentIPCDoc), + mIPCDoc(aIPCDoc), + mUniqueID(aUniqueID), + mBrowsingContext(aBrowsingContext), + mMsaaID(aMsaaID) {} + + void Dispatch(DocAccessibleChild* aParentIPCDoc) override { + auto browserChild = + static_cast<dom::BrowserChild*>(aParentIPCDoc->Manager()); + MOZ_ASSERT(browserChild); + Unused << browserChild->SendPDocAccessibleConstructor( + mIPCDoc, aParentIPCDoc, mUniqueID, mBrowsingContext, mMsaaID, + IAccessibleHolder()); + mIPCDoc->SetConstructedInParentProcess(); + } + + DocAccessibleChild* mIPCDoc; + uint64_t mUniqueID; + // By the time we replay this, the document and its BrowsingContext might + // be dead, so we use MaybeDiscardedBrowsingContext here. Ideally, we just + // wouldn't replay this, but this is tricky because IPDL should manage the + // lifetime of DocAccessibleChild, which means we must send the constructor. + dom::MaybeDiscardedBrowsingContext mBrowsingContext; + 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(); } + }; + + struct SerializedSetEmbedder final : public DeferredEvent { + SerializedSetEmbedder(dom::BrowserBridgeChild* aBridge, + DocAccessibleChild* aDoc, uint64_t aID) + : DeferredEvent(aDoc), mBridge(aBridge), mID(aID) {} + + void Dispatch(DocAccessibleChild* aDoc) override { + mBridge->SetEmbedderAccessible(aDoc, mID); + } + + RefPtr<dom::BrowserBridgeChild> mBridge; + uint64_t mID; + }; + + mscom::ProxyUniquePtr<IDispatch> mParentProxy; + mscom::ProxyUniquePtr<IDispatch> mEmulatedWindowProxy; + mscom::ProxyUniquePtr<IAccessible> mTopLevelDocProxy; + nsTArray<UniquePtr<DeferredEvent>> mDeferredEvents; + HWND mEmulatedWindowHandle; +}; + +} // namespace a11y +} // namespace mozilla + +#endif // mozilla_a11y_DocAccessibleChild_h |