/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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 aEvent); struct SerializedShow final : public DeferredEvent { SerializedShow(DocAccessibleChild* aTarget, ShowEventData& aEventData, bool aFromUser) : DeferredEvent(aTarget) , mEventData(aEventData.ID(), aEventData.Idx(), nsTArray()) , 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(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 mParentProxy; nsTArray> mDeferredEvents; }; } // namespace a11y } // namespace mozilla #endif // mozilla_a11y_DocAccessibleChild_h