tor-browser

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

OuterDocAccessible.cpp (7437B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "OuterDocAccessible.h"
      7 
      8 #include "LocalAccessible-inl.h"
      9 #include "DocAccessible-inl.h"
     10 #include "mozilla/a11y/DocAccessibleChild.h"
     11 #include "mozilla/a11y/DocAccessibleParent.h"
     12 #include "mozilla/dom/BrowserBridgeChild.h"
     13 #include "mozilla/dom/BrowserParent.h"
     14 #include "mozilla/a11y/Role.h"
     15 
     16 #ifdef A11Y_LOG
     17 #  include "Logging.h"
     18 #endif
     19 
     20 using namespace mozilla;
     21 using namespace mozilla::a11y;
     22 
     23 ////////////////////////////////////////////////////////////////////////////////
     24 // OuterDocAccessible
     25 ////////////////////////////////////////////////////////////////////////////////
     26 
     27 OuterDocAccessible::OuterDocAccessible(nsIContent* aContent,
     28                                       DocAccessible* aDoc)
     29    : AccessibleWrap(aContent, aDoc) {
     30  mType = eOuterDocType;
     31 
     32  if (IPCAccessibilityActive()) {
     33    auto bridge = dom::BrowserBridgeChild::GetFrom(aContent);
     34    if (bridge) {
     35      // This is an iframe which will be rendered in another process.
     36      SendEmbedderAccessible(bridge);
     37    }
     38  }
     39 
     40  // Request document accessible for the content document to make sure it's
     41  // created. It will appended to outerdoc accessible children asynchronously.
     42  dom::Document* outerDoc = mContent->GetUncomposedDoc();
     43  if (outerDoc) {
     44    dom::Document* innerDoc = outerDoc->GetSubDocumentFor(mContent);
     45    if (innerDoc) GetAccService()->GetDocAccessible(innerDoc);
     46  }
     47 }
     48 
     49 OuterDocAccessible::~OuterDocAccessible() {}
     50 
     51 void OuterDocAccessible::SendEmbedderAccessible(
     52    dom::BrowserBridgeChild* aBridge) {
     53  MOZ_ASSERT(mDoc);
     54  DocAccessibleChild* ipcDoc = mDoc->IPCDoc();
     55  if (ipcDoc) {
     56    uint64_t id = reinterpret_cast<uintptr_t>(UniqueID());
     57    aBridge->SetEmbedderAccessible(ipcDoc, id);
     58  }
     59 }
     60 
     61 ////////////////////////////////////////////////////////////////////////////////
     62 // LocalAccessible public (DON'T add methods here)
     63 
     64 role OuterDocAccessible::NativeRole() const { return roles::INTERNAL_FRAME; }
     65 
     66 LocalAccessible* OuterDocAccessible::LocalChildAtPoint(
     67    int32_t aX, int32_t aY, EWhichChildAtPoint aWhichChild) {
     68  LayoutDeviceIntRect docRect = Bounds();
     69  if (!docRect.Contains(aX, aY)) return nullptr;
     70 
     71  // Always return the inner doc as direct child accessible unless bounds
     72  // outside of it.
     73  LocalAccessible* child = LocalChildAt(0);
     74  NS_ENSURE_TRUE(child, nullptr);
     75 
     76  if (aWhichChild == Accessible::EWhichChildAtPoint::DeepestChild) {
     77    return child->LocalChildAtPoint(
     78        aX, aY, Accessible::EWhichChildAtPoint::DeepestChild);
     79  }
     80  return child;
     81 }
     82 
     83 ////////////////////////////////////////////////////////////////////////////////
     84 // LocalAccessible public
     85 
     86 void OuterDocAccessible::Shutdown() {
     87 #ifdef A11Y_LOG
     88  if (logging::IsEnabled(logging::eDocDestroy)) logging::OuterDocDestroy(this);
     89 #endif
     90 
     91  if (auto* bridge = dom::BrowserBridgeChild::GetFrom(mContent)) {
     92    uint64_t id = reinterpret_cast<uintptr_t>(UniqueID());
     93    if (bridge->GetEmbedderAccessibleID() == id) {
     94      // We were the last embedder accessible sent via PBrowserBridge; i.e. a
     95      // new embedder accessible hasn't been created yet for this iframe. Clear
     96      // the embedder accessible on PBrowserBridge.
     97      bridge->SetEmbedderAccessible(nullptr, 0);
     98    }
     99  }
    100 
    101  LocalAccessible* child = mChildren.SafeElementAt(0, nullptr);
    102  if (child) {
    103 #ifdef A11Y_LOG
    104    if (logging::IsEnabled(logging::eDocDestroy)) {
    105      logging::DocDestroy("outerdoc's child document rebind is scheduled",
    106                          child->AsDoc()->DocumentNode());
    107    }
    108 #endif
    109    RemoveChild(child);
    110 
    111    // XXX: sometimes outerdoc accessible is shutdown because of layout style
    112    // change however the presshell of underlying document isn't destroyed and
    113    // the document doesn't get pagehide events. Schedule a document rebind
    114    // to its parent document. Otherwise a document accessible may be lost if
    115    // its outerdoc has being recreated (see bug 862863 for details).
    116    if (!mDoc->IsDefunct()) {
    117      MOZ_ASSERT(!child->IsDefunct(),
    118                 "Attempt to reattach shutdown document accessible");
    119      if (!child->IsDefunct()) {
    120        mDoc->BindChildDocument(child->AsDoc());
    121      }
    122    }
    123  }
    124 
    125  AccessibleWrap::Shutdown();
    126 }
    127 
    128 bool OuterDocAccessible::InsertChildAt(uint32_t aIdx,
    129                                       LocalAccessible* aAccessible) {
    130  MOZ_RELEASE_ASSERT(aAccessible->IsDoc(),
    131                     "OuterDocAccessible can have a document child only!");
    132 
    133  // We keep showing the old document for a bit after creating the new one,
    134  // and while building the new DOM and frame tree. That's done on purpose
    135  // to avoid weird flashes of default background color.
    136  // The old viewer will be destroyed after the new one is created.
    137  // For a11y, it should be safe to shut down the old document now.
    138  if (mChildren.Length()) mChildren[0]->Shutdown();
    139 
    140  if (!AccessibleWrap::InsertChildAt(0, aAccessible)) return false;
    141 
    142 #ifdef A11Y_LOG
    143  if (logging::IsEnabled(logging::eDocCreate)) {
    144    logging::DocCreate("append document to outerdoc",
    145                       aAccessible->AsDoc()->DocumentNode());
    146    logging::Address("outerdoc", this);
    147  }
    148 #endif
    149 
    150  return true;
    151 }
    152 
    153 bool OuterDocAccessible::RemoveChild(LocalAccessible* aAccessible) {
    154  LocalAccessible* child = mChildren.SafeElementAt(0, nullptr);
    155  MOZ_ASSERT(child == aAccessible, "Wrong child to remove!");
    156  if (child != aAccessible) {
    157    return false;
    158  }
    159 
    160 #ifdef A11Y_LOG
    161  if (logging::IsEnabled(logging::eDocDestroy)) {
    162    logging::DocDestroy("remove document from outerdoc",
    163                        child->AsDoc()->DocumentNode(), child->AsDoc());
    164    logging::Address("outerdoc", this);
    165  }
    166 #endif
    167 
    168  bool wasRemoved = AccessibleWrap::RemoveChild(child);
    169 
    170  NS_ASSERTION(!mChildren.Length(),
    171               "This child document of outerdoc accessible wasn't removed!");
    172 
    173  return wasRemoved;
    174 }
    175 
    176 bool OuterDocAccessible::IsAcceptableChild(nsIContent* aEl) const {
    177  // outer document accessible doesn't not participate in ordinal tree
    178  // mutations.
    179  return false;
    180 }
    181 
    182 // Accessible
    183 
    184 uint32_t OuterDocAccessible::ChildCount() const {
    185  uint32_t result = mChildren.Length();
    186  if (!result && RemoteChildDoc()) {
    187    result = 1;
    188  }
    189  return result;
    190 }
    191 
    192 Accessible* OuterDocAccessible::ChildAt(uint32_t aIndex) const {
    193  LocalAccessible* result = LocalChildAt(aIndex);
    194  if (result || aIndex) {
    195    return result;
    196  }
    197 
    198  return RemoteChildDoc();
    199 }
    200 
    201 Accessible* OuterDocAccessible::ChildAtPoint(int32_t aX, int32_t aY,
    202                                             EWhichChildAtPoint aWhichChild) {
    203  LayoutDeviceIntRect docRect = Bounds();
    204  if (!docRect.Contains(aX, aY)) return nullptr;
    205 
    206  // Always return the inner doc as direct child accessible unless bounds
    207  // outside of it.
    208  Accessible* child = ChildAt(0);
    209  NS_ENSURE_TRUE(child, nullptr);
    210 
    211  if (aWhichChild == EWhichChildAtPoint::DeepestChild) {
    212    return child->ChildAtPoint(aX, aY, EWhichChildAtPoint::DeepestChild);
    213  }
    214  return child;
    215 }
    216 
    217 DocAccessibleParent* OuterDocAccessible::RemoteChildDoc() const {
    218  dom::BrowserParent* tab = dom::BrowserParent::GetFrom(GetContent());
    219  if (!tab) {
    220    return nullptr;
    221  }
    222 
    223  return tab->GetTopLevelDocAccessible();
    224 }