tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

DocAccessibleParent.h (12994B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_a11y_DocAccessibleParent_h
      8 #define mozilla_a11y_DocAccessibleParent_h
      9 
     10 #include "nsAccessibilityService.h"
     11 #include "mozilla/a11y/PDocAccessibleParent.h"
     12 #include "mozilla/a11y/RemoteAccessible.h"
     13 #include "mozilla/dom/BrowserBridgeParent.h"
     14 #include "nsClassHashtable.h"
     15 #include "nsHashKeys.h"
     16 #include "nsISupportsImpl.h"
     17 
     18 namespace mozilla {
     19 namespace dom {
     20 class CanonicalBrowsingContext;
     21 }
     22 
     23 namespace a11y {
     24 
     25 class TextRange;
     26 class xpcAccessibleGeneric;
     27 
     28 /*
     29 * These objects live in the main process and comunicate with and represent
     30 * an accessible document in a content process.
     31 */
     32 class DocAccessibleParent : public RemoteAccessible,
     33                            public PDocAccessibleParent,
     34                            public nsIMemoryReporter {
     35 public:
     36  NS_DECL_ISUPPORTS
     37  NS_DECL_NSIMEMORYREPORTER
     38 
     39 private:
     40  DocAccessibleParent();
     41 
     42 public:
     43  static already_AddRefed<DocAccessibleParent> New();
     44 
     45  /**
     46   * Set this as a top level document; i.e. it is not embedded by another remote
     47   * document. This also means it is a top level document in its content
     48   * process.
     49   * Tab documents are top level documents.
     50   */
     51  void SetTopLevel() {
     52    mTopLevel = true;
     53    mTopLevelInContentProcess = true;
     54  }
     55  bool IsTopLevel() const { return mTopLevel; }
     56 
     57  /**
     58   * Set this as a top level document in its content process.
     59   * Note that this could be an out-of-process iframe embedded by a remote
     60   * embedder document. In that case, IsToplevel() will return false, but
     61   * IsTopLevelInContentProcess() will return true.
     62   */
     63  void SetTopLevelInContentProcess() { mTopLevelInContentProcess = true; }
     64  bool IsTopLevelInContentProcess() const { return mTopLevelInContentProcess; }
     65 
     66  /**
     67   * Determine whether this is an out-of-process iframe document, embedded by a
     68   * remote embedder document.
     69   */
     70  bool IsOOPIframeDoc() const {
     71    return !mTopLevel && mTopLevelInContentProcess;
     72  }
     73 
     74  bool IsShutdown() const { return mShutdown; }
     75 
     76  /**
     77   * Mark this actor as shutdown without doing any cleanup.  This should only
     78   * be called on actors that have just been initialized, so probably only from
     79   * RecvPDocAccessibleConstructor.
     80   */
     81  void MarkAsShutdown() {
     82    MOZ_ASSERT(mChildDocs.IsEmpty());
     83    MOZ_ASSERT(mAccessibles.Count() == 0);
     84    MOZ_ASSERT(!mBrowsingContext);
     85    mShutdown = true;
     86  }
     87 
     88  void SetBrowsingContext(dom::CanonicalBrowsingContext* aBrowsingContext);
     89 
     90  dom::CanonicalBrowsingContext* GetBrowsingContext() const {
     91    return mBrowsingContext;
     92  }
     93 
     94  /*
     95   * Called when a message from a document in a child process notifies the main
     96   * process it is firing an event.
     97   */
     98  virtual mozilla::ipc::IPCResult RecvEvent(const uint64_t& aID,
     99                                            const uint32_t& aType) override;
    100 
    101  mozilla::ipc::IPCResult RecvStateChangeEvent(const uint64_t& aID,
    102                                               const uint64_t& aState,
    103                                               const bool& aEnabled) final;
    104 
    105  mozilla::ipc::IPCResult RecvCaretMoveEvent(
    106      const uint64_t& aID, const LayoutDeviceIntRect& aCaretRect,
    107      const int32_t& aOffset, const bool& aIsSelectionCollapsed,
    108      const bool& aIsAtEndOfLine, const int32_t& aGranularity,
    109      const bool& aFromUser) final;
    110 
    111  virtual mozilla::ipc::IPCResult RecvMutationEvents(
    112      nsTArray<MutationEventData>&& aData) override;
    113 
    114  virtual mozilla::ipc::IPCResult RecvRequestAckMutationEvents() override;
    115 
    116  virtual mozilla::ipc::IPCResult RecvFocusEvent(
    117      const uint64_t& aID, const LayoutDeviceIntRect& aCaretRect) override;
    118 
    119  virtual mozilla::ipc::IPCResult RecvSelectionEvent(
    120      const uint64_t& aID, const uint64_t& aWidgetID,
    121      const uint32_t& aType) override;
    122 
    123  virtual mozilla::ipc::IPCResult RecvScrollingEvent(
    124      const uint64_t& aID, const uint64_t& aType, const uint32_t& aScrollX,
    125      const uint32_t& aScrollY, const uint32_t& aMaxScrollX,
    126      const uint32_t& aMaxScrollY) override;
    127 
    128  virtual mozilla::ipc::IPCResult RecvCache(
    129      const mozilla::a11y::CacheUpdateType& aUpdateType,
    130      nsTArray<CacheData>&& aData) override;
    131 
    132  virtual mozilla::ipc::IPCResult RecvSelectedAccessiblesChanged(
    133      nsTArray<uint64_t>&& aSelectedIDs,
    134      nsTArray<uint64_t>&& aUnselectedIDs) override;
    135 
    136  virtual mozilla::ipc::IPCResult RecvAccessiblesWillMove(
    137      nsTArray<uint64_t>&& aIDs) override;
    138 
    139 #if !defined(XP_WIN)
    140  virtual mozilla::ipc::IPCResult RecvAnnouncementEvent(
    141      const uint64_t& aID, const nsAString& aAnnouncement,
    142      const uint16_t& aPriority) override;
    143 #endif
    144 
    145  virtual mozilla::ipc::IPCResult RecvTextSelectionChangeEvent(
    146      const uint64_t& aID, nsTArray<TextRangeData>&& aSelection) override;
    147 
    148  mozilla::ipc::IPCResult RecvRoleChangedEvent(
    149      const a11y::role& aRole, const uint8_t& aRoleMapEntryIndex) final;
    150 
    151  virtual mozilla::ipc::IPCResult RecvBindChildDoc(
    152      NotNull<PDocAccessibleParent*> aChildDoc, const uint64_t& aID) override;
    153 
    154  void Unbind() {
    155    if (RemoteAccessible* parent = RemoteParent()) {
    156      DocAccessibleParent* parentDoc = parent->Document();
    157      parent->ClearChildDoc(this);
    158      DebugOnly<bool> result = parentDoc->mChildDocs.RemoveElement(mActorID);
    159      MOZ_ASSERT(result);
    160    }
    161 
    162    SetParent(nullptr);
    163  }
    164 
    165  virtual mozilla::ipc::IPCResult RecvShutdown() override;
    166  void Destroy();
    167  virtual void ActorDestroy(ActorDestroyReason aWhy) override;
    168 
    169  /*
    170   * Return the main processes representation of the parent document (if any)
    171   * of the document this object represents.
    172   */
    173  DocAccessibleParent* ParentDoc() const;
    174 
    175  /**
    176   * Called when a document in a content process notifies the main process of a
    177   * new child document.
    178   * Although this is called internally for OOP child documents, these should be
    179   * added via the BrowserBridgeParent version of this method, as the parent id
    180   * might not exist yet in that case.
    181   */
    182  ipc::IPCResult AddChildDoc(DocAccessibleParent* aChildDoc, uint64_t aParentID,
    183                             bool aCreating = true);
    184 
    185  /**
    186   * Called when a document in a content process notifies the main process of a
    187   * new OOP child document.
    188   */
    189  ipc::IPCResult AddChildDoc(dom::BrowserBridgeParent* aBridge);
    190 
    191  void RemovePendingOOPChildDoc(dom::BrowserBridgeParent* aBridge) {
    192    mPendingOOPChildDocs.Remove(aBridge);
    193  }
    194 
    195  void RemoveAccessible(RemoteAccessible* aAccessible) {
    196    MOZ_DIAGNOSTIC_ASSERT(mAccessibles.GetEntry(aAccessible->ID()));
    197    mAccessibles.RemoveEntry(aAccessible->ID());
    198  }
    199 
    200  /**
    201   * Return the accessible for given id.
    202   */
    203  RemoteAccessible* GetAccessible(uintptr_t aID) {
    204    if (!aID) return this;
    205 
    206    ProxyEntry* e = mAccessibles.GetEntry(aID);
    207    return e ? e->mProxy : nullptr;
    208  }
    209 
    210  const RemoteAccessible* GetAccessible(uintptr_t aID) const {
    211    return const_cast<DocAccessibleParent*>(this)->GetAccessible(aID);
    212  }
    213 
    214  size_t ChildDocCount() const { return mChildDocs.Length(); }
    215  const DocAccessibleParent* ChildDocAt(size_t aIdx) const {
    216    return const_cast<DocAccessibleParent*>(this)->ChildDocAt(aIdx);
    217  }
    218  DocAccessibleParent* ChildDocAt(size_t aIdx) {
    219    return LiveDocs().Get(mChildDocs[aIdx]);
    220  }
    221 
    222 #if defined(XP_WIN)
    223  void MaybeInitWindowEmulation();
    224 
    225  /**
    226   * Set emulated native window handle for a document.
    227   * @param aWindowHandle emulated native window handle
    228   */
    229  void SetEmulatedWindowHandle(HWND aWindowHandle);
    230  HWND GetEmulatedWindowHandle() const { return mEmulatedWindowHandle; }
    231 #endif
    232 
    233  // Accessible
    234  virtual Accessible* Parent() const override {
    235    if (IsTopLevel()) {
    236      return OuterDocOfRemoteBrowser();
    237    }
    238    return RemoteParent();
    239  }
    240 
    241  virtual int32_t IndexInParent() const override {
    242    if (IsTopLevel() && OuterDocOfRemoteBrowser()) {
    243      // An OuterDoc can only have 1 child.
    244      return 0;
    245    }
    246    return RemoteAccessible::IndexInParent();
    247  }
    248 
    249  /**
    250   * Get the focused Accessible in this document, if any.
    251   */
    252  RemoteAccessible* GetFocusedAcc() const {
    253    return const_cast<DocAccessibleParent*>(this)->GetAccessible(mFocus);
    254  }
    255 
    256  /**
    257   * Get the HyperText Accessible containing the caret and the offset of the
    258   * caret within. If there is no caret in this document, returns
    259   * {nullptr, -1}.
    260   */
    261  std::pair<RemoteAccessible*, int32_t> GetCaret() const {
    262    if (mCaretOffset == -1) {
    263      return {nullptr, -1};
    264    }
    265    RemoteAccessible* acc =
    266        const_cast<DocAccessibleParent*>(this)->GetAccessible(mCaretId);
    267    if (!acc) {
    268      return {nullptr, -1};
    269    }
    270    return {acc, mCaretOffset};
    271  }
    272 
    273  bool IsCaretAtEndOfLine() const { return mIsCaretAtEndOfLine; }
    274 
    275  mozilla::LayoutDeviceIntRect GetCachedCaretRect();
    276 
    277  virtual void SelectionRanges(nsTArray<TextRange>* aRanges) const override;
    278 
    279  virtual Accessible* FocusedChild() override;
    280 
    281  void URL(nsAString& aURL) const;
    282  void URL(nsACString& aURL) const;
    283 
    284  void MimeType(nsAString& aURL) const;
    285 
    286  virtual Relation RelationByType(RelationType aType) const override;
    287 
    288  // Tracks cached reverse relations (ie. those not set explicitly by an
    289  // attribute like aria-labelledby) for accessibles in this doc. This map is of
    290  // the form: {accID, {pointerToRelationDataAddress, [targetAccID, ...]}}
    291  nsTHashMap<uint64_t, nsTHashMap<const RelationData*, nsTArray<uint64_t>>>
    292      mReverseRelations;
    293 
    294  // Computed from the viewport cache, the accs referenced by these ids
    295  // are currently on screen (making any acc not in this list offscreen).
    296  nsTHashSet<uint64_t> mOnScreenAccessibles;
    297 
    298  static DocAccessibleParent* GetFrom(dom::BrowsingContext* aBrowsingContext);
    299 
    300  size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) override;
    301 
    302 private:
    303  ~DocAccessibleParent();
    304 
    305  class ProxyEntry : public PLDHashEntryHdr {
    306   public:
    307    explicit ProxyEntry(const void*) : mProxy(nullptr) {}
    308    ProxyEntry(ProxyEntry&& aOther) : mProxy(aOther.mProxy) {
    309      aOther.mProxy = nullptr;
    310    }
    311    ~ProxyEntry() { delete mProxy; }
    312 
    313    typedef uint64_t KeyType;
    314    typedef const void* KeyTypePointer;
    315 
    316    bool KeyEquals(const void* aKey) const {
    317      return mProxy->ID() == (uint64_t)aKey;
    318    }
    319 
    320    static const void* KeyToPointer(uint64_t aKey) { return (void*)aKey; }
    321 
    322    static PLDHashNumber HashKey(const void* aKey) { return (uint64_t)aKey; }
    323 
    324    enum { ALLOW_MEMMOVE = true };
    325 
    326    RemoteAccessible* mProxy;
    327  };
    328 
    329  RemoteAccessible* CreateAcc(const AccessibleData& aAccData);
    330  void AttachChild(RemoteAccessible* aParent, uint32_t aIndex,
    331                   RemoteAccessible* aChild);
    332  [[nodiscard]] bool CheckDocTree() const;
    333  xpcAccessibleGeneric* GetXPCAccessible(RemoteAccessible* aProxy);
    334 
    335  void FireEvent(RemoteAccessible* aAcc, const uint32_t& aType);
    336 
    337  /**
    338   * If this Accessible is being moved, prepare it for reuse. Otherwise, it is
    339   * being removed, so shut it down.
    340   */
    341  void ShutdownOrPrepareForMove(RemoteAccessible* aAcc);
    342 
    343  mozilla::ipc::IPCResult ProcessShowEvent(nsTArray<AccessibleData>&& aNewTree,
    344                                           const bool& aEventSuppressed,
    345                                           const bool& aComplete,
    346                                           const bool& aFromUser);
    347  mozilla::ipc::IPCResult ProcessHideEvent(const uint64_t& aRootID,
    348                                           const bool& aFromUser);
    349  mozilla::ipc::IPCResult ProcessTextChangeEvent(
    350      const uint64_t& aID, const nsAString& aStr, const int32_t& aStart,
    351      const uint32_t& aLen, const bool& aIsInsert, const bool& aFromUser);
    352 
    353  nsTArray<uint64_t> mChildDocs;
    354 
    355 #if defined(XP_WIN)
    356  // The handle associated with the emulated window that contains this document
    357  HWND mEmulatedWindowHandle;
    358 #endif  // defined(XP_WIN)
    359 
    360  /*
    361   * Conceptually this is a map from IDs to proxies, but we store the ID in the
    362   * proxy object so we can't use a real map.
    363   */
    364  nsTHashtable<ProxyEntry> mAccessibles;
    365  uint64_t mPendingShowChild = 0;
    366  uint64_t mPendingShowParent = 0;
    367  uint32_t mPendingShowIndex = 0;
    368  nsTHashSet<uint64_t> mMovingIDs;
    369  uint64_t mActorID;
    370  bool mTopLevel;
    371  bool mTopLevelInContentProcess;
    372  bool mShutdown;
    373  RefPtr<dom::CanonicalBrowsingContext> mBrowsingContext;
    374 
    375  nsTHashSet<RefPtr<dom::BrowserBridgeParent>> mPendingOOPChildDocs;
    376 
    377  uint64_t mFocus;
    378  uint64_t mCaretId;
    379  int32_t mCaretOffset;
    380  bool mIsCaretAtEndOfLine;
    381  LayoutDeviceIntRect mCaretRect;
    382  nsTArray<TextRangeData> mTextSelections;
    383 
    384  static uint64_t sMaxDocID;
    385  static nsTHashMap<nsUint64HashKey, DocAccessibleParent*>& LiveDocs() {
    386    static nsTHashMap<nsUint64HashKey, DocAccessibleParent*> sLiveDocs;
    387    return sLiveDocs;
    388  }
    389 };
    390 
    391 }  // namespace a11y
    392 }  // namespace mozilla
    393 
    394 #endif