From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- accessible/ipc/DocAccessibleParent.h | 438 +++++++++++++++++++++++++++++++++++ 1 file changed, 438 insertions(+) create mode 100644 accessible/ipc/DocAccessibleParent.h (limited to 'accessible/ipc/DocAccessibleParent.h') diff --git a/accessible/ipc/DocAccessibleParent.h b/accessible/ipc/DocAccessibleParent.h new file mode 100644 index 0000000000..32e69cb56c --- /dev/null +++ b/accessible/ipc/DocAccessibleParent.h @@ -0,0 +1,438 @@ +/* -*- 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_DocAccessibleParent_h +#define mozilla_a11y_DocAccessibleParent_h + +#include "nsAccessibilityService.h" +#include "mozilla/a11y/PDocAccessibleParent.h" +#include "mozilla/a11y/RemoteAccessible.h" +#include "mozilla/dom/BrowserBridgeParent.h" +#include "nsClassHashtable.h" +#include "nsHashKeys.h" +#include "nsISupportsImpl.h" + +namespace mozilla { +namespace dom { +class CanonicalBrowsingContext; +} + +namespace a11y { + +class TextRange; +class xpcAccessibleGeneric; + +#if !defined(XP_WIN) +class DocAccessiblePlatformExtParent; +#endif + +#ifdef ANDROID +class SessionAccessibility; +#endif + +/* + * These objects live in the main process and comunicate with and represent + * an accessible document in a content process. + */ +class DocAccessibleParent : public RemoteAccessible, + public PDocAccessibleParent, + public nsIMemoryReporter { + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIMEMORYREPORTER + + private: + DocAccessibleParent(); + + public: + static already_AddRefed New(); + + /** + * Set this as a top level document; i.e. it is not embedded by another remote + * document. This also means it is a top level document in its content + * process. + * Tab documents are top level documents. + */ + void SetTopLevel() { + mTopLevel = true; + mTopLevelInContentProcess = true; + } + bool IsTopLevel() const { return mTopLevel; } + + /** + * Set this as a top level document in its content process. + * Note that this could be an out-of-process iframe embedded by a remote + * embedder document. In that case, IsToplevel() will return false, but + * IsTopLevelInContentProcess() will return true. + */ + void SetTopLevelInContentProcess() { mTopLevelInContentProcess = true; } + bool IsTopLevelInContentProcess() const { return mTopLevelInContentProcess; } + + /** + * Determine whether this is an out-of-process iframe document, embedded by a + * remote embedder document. + */ + bool IsOOPIframeDoc() const { + return !mTopLevel && mTopLevelInContentProcess; + } + + bool IsShutdown() const { return mShutdown; } + + /** + * Mark this actor as shutdown without doing any cleanup. This should only + * be called on actors that have just been initialized, so probably only from + * RecvPDocAccessibleConstructor. + */ + void MarkAsShutdown() { + MOZ_ASSERT(mChildDocs.IsEmpty()); + MOZ_ASSERT(mAccessibles.Count() == 0); + MOZ_ASSERT(!mBrowsingContext); + mShutdown = true; + } + + void SetBrowsingContext(dom::CanonicalBrowsingContext* aBrowsingContext); + + dom::CanonicalBrowsingContext* GetBrowsingContext() const { + return mBrowsingContext; + } + + /* + * Called when a message from a document in a child process notifies the main + * process it is firing an event. + */ + virtual mozilla::ipc::IPCResult RecvEvent(const uint64_t& aID, + const uint32_t& aType) override; + + virtual mozilla::ipc::IPCResult RecvShowEvent( + nsTArray&& aNewTree, const bool& aEventSuppressed, + const bool& aComplete, const bool& aFromUser) override; + virtual mozilla::ipc::IPCResult RecvHideEvent(const uint64_t& aRootID, + const bool& aFromUser) override; + mozilla::ipc::IPCResult RecvStateChangeEvent(const uint64_t& aID, + const uint64_t& aState, + const bool& aEnabled) final; + + mozilla::ipc::IPCResult RecvCaretMoveEvent( + const uint64_t& aID, +#if defined(XP_WIN) + const LayoutDeviceIntRect& aCaretRect, +#endif + const int32_t& aOffset, const bool& aIsSelectionCollapsed, + const bool& aIsAtEndOfLine, const int32_t& aGranularity) final; + + virtual mozilla::ipc::IPCResult RecvTextChangeEvent( + const uint64_t& aID, const nsAString& aStr, const int32_t& aStart, + const uint32_t& aLen, const bool& aIsInsert, + const bool& aFromUser) override; + +#if defined(XP_WIN) + virtual mozilla::ipc::IPCResult RecvSyncTextChangeEvent( + const uint64_t& aID, const nsAString& aStr, const int32_t& aStart, + const uint32_t& aLen, const bool& aIsInsert, + const bool& aFromUser) override; + + virtual mozilla::ipc::IPCResult RecvFocusEvent( + const uint64_t& aID, const LayoutDeviceIntRect& aCaretRect) override; +#endif // defined(XP_WIN) + + virtual mozilla::ipc::IPCResult RecvSelectionEvent( + const uint64_t& aID, const uint64_t& aWidgetID, + const uint32_t& aType) override; + + virtual mozilla::ipc::IPCResult RecvVirtualCursorChangeEvent( + const uint64_t& aID, const uint64_t& aOldPositionID, + const int32_t& aOldStartOffset, const int32_t& aOldEndOffset, + const uint64_t& aNewPositionID, const int32_t& aNewStartOffset, + const int32_t& aNewEndOffset, const int16_t& aReason, + const int16_t& aBoundaryType, const bool& aFromUser) override; + + virtual mozilla::ipc::IPCResult RecvScrollingEvent( + const uint64_t& aID, const uint64_t& aType, const uint32_t& aScrollX, + const uint32_t& aScrollY, const uint32_t& aMaxScrollX, + const uint32_t& aMaxScrollY) override; + + virtual mozilla::ipc::IPCResult RecvCache( + const mozilla::a11y::CacheUpdateType& aUpdateType, + nsTArray&& aData) override; + + virtual mozilla::ipc::IPCResult RecvSelectedAccessiblesChanged( + nsTArray&& aSelectedIDs, + nsTArray&& aUnselectedIDs) override; + + virtual mozilla::ipc::IPCResult RecvAccessiblesWillMove( + nsTArray&& aIDs) override; + +#if !defined(XP_WIN) + virtual mozilla::ipc::IPCResult RecvAnnouncementEvent( + const uint64_t& aID, const nsAString& aAnnouncement, + const uint16_t& aPriority) override; +#endif + + virtual mozilla::ipc::IPCResult RecvTextSelectionChangeEvent( + const uint64_t& aID, nsTArray&& aSelection) override; + + mozilla::ipc::IPCResult RecvRoleChangedEvent( + const a11y::role& aRole, const uint8_t& aRoleMapEntryIndex) final; + + virtual mozilla::ipc::IPCResult RecvBindChildDoc( + NotNull aChildDoc, const uint64_t& aID) override; + + void Unbind() { + if (DocAccessibleParent* parent = ParentDoc()) { + parent->RemoveChildDoc(this); + } + + SetParent(nullptr); + } + + virtual mozilla::ipc::IPCResult RecvShutdown() override; + void Destroy(); + virtual void ActorDestroy(ActorDestroyReason aWhy) override; + + /* + * Return the main processes representation of the parent document (if any) + * of the document this object represents. + */ + DocAccessibleParent* ParentDoc() const; + static const uint64_t kNoParentDoc = UINT64_MAX; + + /** + * Called when a document in a content process notifies the main process of a + * new child document. + * Although this is called internally for OOP child documents, these should be + * added via the BrowserBridgeParent version of this method, as the parent id + * might not exist yet in that case. + */ + ipc::IPCResult AddChildDoc(DocAccessibleParent* aChildDoc, uint64_t aParentID, + bool aCreating = true); + + /** + * Called when a document in a content process notifies the main process of a + * new OOP child document. + */ + ipc::IPCResult AddChildDoc(dom::BrowserBridgeParent* aBridge); + + void RemovePendingOOPChildDoc(dom::BrowserBridgeParent* aBridge) { + mPendingOOPChildDocs.Remove(aBridge); + } + + /* + * Called when the document in the content process this object represents + * notifies the main process a child document has been removed. + */ + void RemoveChildDoc(DocAccessibleParent* aChildDoc) { + RemoteAccessible* parent = aChildDoc->RemoteParent(); + MOZ_ASSERT(parent); + if (parent) { + aChildDoc->RemoteParent()->ClearChildDoc(aChildDoc); + } + DebugOnly result = mChildDocs.RemoveElement(aChildDoc->mActorID); + aChildDoc->mParentDoc = kNoParentDoc; + MOZ_ASSERT(result); + } + + void RemoveAccessible(RemoteAccessible* aAccessible) { + MOZ_DIAGNOSTIC_ASSERT(mAccessibles.GetEntry(aAccessible->ID())); + mAccessibles.RemoveEntry(aAccessible->ID()); + } + + /** + * Return the accessible for given id. + */ + RemoteAccessible* GetAccessible(uintptr_t aID) { + if (!aID) return this; + + ProxyEntry* e = mAccessibles.GetEntry(aID); + return e ? e->mProxy : nullptr; + } + + const RemoteAccessible* GetAccessible(uintptr_t aID) const { + return const_cast(this)->GetAccessible(aID); + } + + size_t ChildDocCount() const { return mChildDocs.Length(); } + const DocAccessibleParent* ChildDocAt(size_t aIdx) const { + return const_cast(this)->ChildDocAt(aIdx); + } + DocAccessibleParent* ChildDocAt(size_t aIdx) { + return LiveDocs().Get(mChildDocs[aIdx]); + } + +#if defined(XP_WIN) + void MaybeInitWindowEmulation(); + + /** + * Set emulated native window handle for a document. + * @param aWindowHandle emulated native window handle + */ + void SetEmulatedWindowHandle(HWND aWindowHandle); + HWND GetEmulatedWindowHandle() const { return mEmulatedWindowHandle; } +#endif + +#if !defined(XP_WIN) + virtual bool DeallocPDocAccessiblePlatformExtParent( + PDocAccessiblePlatformExtParent* aActor) override; + + virtual PDocAccessiblePlatformExtParent* + AllocPDocAccessiblePlatformExtParent() override; + + DocAccessiblePlatformExtParent* GetPlatformExtension(); +#endif + + // Accessible + virtual Accessible* Parent() const override { + if (IsTopLevel()) { + return OuterDocOfRemoteBrowser(); + } + return RemoteParent(); + } + + virtual int32_t IndexInParent() const override { + if (IsTopLevel() && OuterDocOfRemoteBrowser()) { + // An OuterDoc can only have 1 child. + return 0; + } + return RemoteAccessible::IndexInParent(); + } + + /** + * Get the focused Accessible in this document, if any. + */ + RemoteAccessible* GetFocusedAcc() const { + return const_cast(this)->GetAccessible(mFocus); + } + + /** + * Get the HyperText Accessible containing the caret and the offset of the + * caret within. If there is no caret in this document, returns + * {nullptr, -1}. + */ + std::pair GetCaret() const { + if (mCaretOffset == -1) { + return {nullptr, -1}; + } + RemoteAccessible* acc = + const_cast(this)->GetAccessible(mCaretId); + if (!acc) { + return {nullptr, -1}; + } + return {acc, mCaretOffset}; + } + + bool IsCaretAtEndOfLine() const { return mIsCaretAtEndOfLine; } + + virtual void SelectionRanges(nsTArray* aRanges) const override; + + virtual Accessible* FocusedChild() override; + + void URL(nsAString& aURL) const; + void URL(nsACString& aURL) const; + + void MimeType(nsAString& aURL) const; + + virtual Relation RelationByType(RelationType aType) const override; + + // Tracks cached reverse relations (ie. those not set explicitly by an + // attribute like aria-labelledby) for accessibles in this doc. This map is of + // the form: {accID, {relationType, [targetAccID, targetAccID, ...]}} + nsTHashMap>> + mReverseRelations; + + // Computed from the viewport cache, the accs referenced by these ids + // are currently on screen (making any acc not in this list offscreen). + nsTHashSet mOnScreenAccessibles; + + static DocAccessibleParent* GetFrom(dom::BrowsingContext* aBrowsingContext); + + size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) override; + +#ifdef ANDROID + RefPtr mSessionAccessibility; +#endif + + private: + ~DocAccessibleParent(); + + class ProxyEntry : public PLDHashEntryHdr { + public: + explicit ProxyEntry(const void*) : mProxy(nullptr) {} + ProxyEntry(ProxyEntry&& aOther) : mProxy(aOther.mProxy) { + aOther.mProxy = nullptr; + } + ~ProxyEntry() { delete mProxy; } + + typedef uint64_t KeyType; + typedef const void* KeyTypePointer; + + bool KeyEquals(const void* aKey) const { + return mProxy->ID() == (uint64_t)aKey; + } + + static const void* KeyToPointer(uint64_t aKey) { return (void*)aKey; } + + static PLDHashNumber HashKey(const void* aKey) { return (uint64_t)aKey; } + + enum { ALLOW_MEMMOVE = true }; + + RemoteAccessible* mProxy; + }; + + RemoteAccessible* CreateAcc(const AccessibleData& aAccData); + void AttachChild(RemoteAccessible* aParent, uint32_t aIndex, + RemoteAccessible* aChild); + [[nodiscard]] bool CheckDocTree() const; + xpcAccessibleGeneric* GetXPCAccessible(RemoteAccessible* aProxy); + + void FireEvent(RemoteAccessible* aAcc, const uint32_t& aType); + + /** + * If this Accessible is being moved, prepare it for reuse. Otherwise, it is + * being removed, so shut it down. + */ + void ShutdownOrPrepareForMove(RemoteAccessible* aAcc); + + nsTArray mChildDocs; + uint64_t mParentDoc; + +#if defined(XP_WIN) + // The handle associated with the emulated window that contains this document + HWND mEmulatedWindowHandle; +#endif // defined(XP_WIN) + + /* + * Conceptually this is a map from IDs to proxies, but we store the ID in the + * proxy object so we can't use a real map. + */ + nsTHashtable mAccessibles; + uint64_t mPendingShowChild = 0; + uint64_t mPendingShowParent = 0; + uint32_t mPendingShowIndex = 0; + nsTHashSet mMovingIDs; + uint64_t mActorID; + bool mTopLevel; + bool mTopLevelInContentProcess; + bool mShutdown; + RefPtr mBrowsingContext; + + nsTHashSet> mPendingOOPChildDocs; + + uint64_t mFocus; + uint64_t mCaretId; + int32_t mCaretOffset; + bool mIsCaretAtEndOfLine; + nsTArray mTextSelections; + + static uint64_t sMaxDocID; + static nsTHashMap& LiveDocs() { + static nsTHashMap sLiveDocs; + return sLiveDocs; + } +}; + +} // namespace a11y +} // namespace mozilla + +#endif -- cgit v1.2.3