Bug 1732219 - Add API for fetching the preview image. r=geckoview-reviewers,agi,mconley
[gecko.git] / accessible / generic / OuterDocAccessible.cpp
blobe5320ce0ee87a7deb6767159073dc1e4a52849a2
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/. */
6 #include "OuterDocAccessible.h"
8 #include "LocalAccessible-inl.h"
9 #include "nsAccUtils.h"
10 #include "DocAccessible-inl.h"
11 #include "mozilla/a11y/DocAccessibleChild.h"
12 #include "mozilla/a11y/DocAccessibleParent.h"
13 #include "mozilla/dom/BrowserBridgeChild.h"
14 #include "mozilla/dom/BrowserParent.h"
15 #include "Role.h"
16 #include "States.h"
18 #ifdef A11Y_LOG
19 # include "Logging.h"
20 #endif
22 using namespace mozilla;
23 using namespace mozilla::a11y;
25 ////////////////////////////////////////////////////////////////////////////////
26 // OuterDocAccessible
27 ////////////////////////////////////////////////////////////////////////////////
29 OuterDocAccessible::OuterDocAccessible(nsIContent* aContent,
30 DocAccessible* aDoc)
31 : AccessibleWrap(aContent, aDoc) {
32 mType = eOuterDocType;
34 #ifdef XP_WIN
35 if (DocAccessibleParent* remoteDoc = RemoteChildDoc()) {
36 remoteDoc->SendParentCOMProxy(this);
38 #endif
40 if (IPCAccessibilityActive()) {
41 auto bridge = dom::BrowserBridgeChild::GetFrom(aContent);
42 if (bridge) {
43 // This is an iframe which will be rendered in another process.
44 SendEmbedderAccessible(bridge);
48 // Request document accessible for the content document to make sure it's
49 // created. It will appended to outerdoc accessible children asynchronously.
50 dom::Document* outerDoc = mContent->GetUncomposedDoc();
51 if (outerDoc) {
52 dom::Document* innerDoc = outerDoc->GetSubDocumentFor(mContent);
53 if (innerDoc) GetAccService()->GetDocAccessible(innerDoc);
57 OuterDocAccessible::~OuterDocAccessible() {}
59 void OuterDocAccessible::SendEmbedderAccessible(
60 dom::BrowserBridgeChild* aBridge) {
61 MOZ_ASSERT(mDoc);
62 DocAccessibleChild* ipcDoc = mDoc->IPCDoc();
63 if (ipcDoc) {
64 uint64_t id = reinterpret_cast<uintptr_t>(UniqueID());
65 #if defined(XP_WIN)
66 ipcDoc->SetEmbedderOnBridge(aBridge, id);
67 #else
68 aBridge->SetEmbedderAccessible(ipcDoc, id);
69 #endif
73 ////////////////////////////////////////////////////////////////////////////////
74 // LocalAccessible public (DON'T add methods here)
76 role OuterDocAccessible::NativeRole() const { return roles::INTERNAL_FRAME; }
78 LocalAccessible* OuterDocAccessible::LocalChildAtPoint(
79 int32_t aX, int32_t aY, EWhichChildAtPoint aWhichChild) {
80 nsIntRect docRect = Bounds();
81 if (!docRect.Contains(aX, aY)) return nullptr;
83 // Always return the inner doc as direct child accessible unless bounds
84 // outside of it.
85 LocalAccessible* child = LocalChildAt(0);
86 NS_ENSURE_TRUE(child, nullptr);
88 if (aWhichChild == Accessible::EWhichChildAtPoint::DeepestChild) {
89 return child->LocalChildAtPoint(
90 aX, aY, Accessible::EWhichChildAtPoint::DeepestChild);
92 return child;
95 ////////////////////////////////////////////////////////////////////////////////
96 // LocalAccessible public
98 void OuterDocAccessible::Shutdown() {
99 #ifdef A11Y_LOG
100 if (logging::IsEnabled(logging::eDocDestroy)) logging::OuterDocDestroy(this);
101 #endif
103 if (auto* bridge = dom::BrowserBridgeChild::GetFrom(mContent)) {
104 uint64_t id = reinterpret_cast<uintptr_t>(UniqueID());
105 if (bridge->GetEmbedderAccessibleID() == id) {
106 // We were the last embedder accessible sent via PBrowserBridge; i.e. a
107 // new embedder accessible hasn't been created yet for this iframe. Clear
108 // the embedder accessible on PBrowserBridge.
109 bridge->SetEmbedderAccessible(nullptr, 0);
113 LocalAccessible* child = mChildren.SafeElementAt(0, nullptr);
114 if (child) {
115 #ifdef A11Y_LOG
116 if (logging::IsEnabled(logging::eDocDestroy)) {
117 logging::DocDestroy("outerdoc's child document rebind is scheduled",
118 child->AsDoc()->DocumentNode());
120 #endif
121 RemoveChild(child);
123 // XXX: sometimes outerdoc accessible is shutdown because of layout style
124 // change however the presshell of underlying document isn't destroyed and
125 // the document doesn't get pagehide events. Schedule a document rebind
126 // to its parent document. Otherwise a document accessible may be lost if
127 // its outerdoc has being recreated (see bug 862863 for details).
128 if (!mDoc->IsDefunct()) {
129 MOZ_ASSERT(!child->IsDefunct(),
130 "Attempt to reattach shutdown document accessible");
131 if (!child->IsDefunct()) {
132 mDoc->BindChildDocument(child->AsDoc());
137 AccessibleWrap::Shutdown();
140 bool OuterDocAccessible::InsertChildAt(uint32_t aIdx,
141 LocalAccessible* aAccessible) {
142 MOZ_RELEASE_ASSERT(aAccessible->IsDoc(),
143 "OuterDocAccessible can have a document child only!");
145 // We keep showing the old document for a bit after creating the new one,
146 // and while building the new DOM and frame tree. That's done on purpose
147 // to avoid weird flashes of default background color.
148 // The old viewer will be destroyed after the new one is created.
149 // For a11y, it should be safe to shut down the old document now.
150 if (mChildren.Length()) mChildren[0]->Shutdown();
152 if (!AccessibleWrap::InsertChildAt(0, aAccessible)) return false;
154 #ifdef A11Y_LOG
155 if (logging::IsEnabled(logging::eDocCreate)) {
156 logging::DocCreate("append document to outerdoc",
157 aAccessible->AsDoc()->DocumentNode());
158 logging::Address("outerdoc", this);
160 #endif
162 return true;
165 bool OuterDocAccessible::RemoveChild(LocalAccessible* aAccessible) {
166 LocalAccessible* child = mChildren.SafeElementAt(0, nullptr);
167 MOZ_ASSERT(child == aAccessible, "Wrong child to remove!");
168 if (child != aAccessible) {
169 return false;
172 #ifdef A11Y_LOG
173 if (logging::IsEnabled(logging::eDocDestroy)) {
174 logging::DocDestroy("remove document from outerdoc",
175 child->AsDoc()->DocumentNode(), child->AsDoc());
176 logging::Address("outerdoc", this);
178 #endif
180 bool wasRemoved = AccessibleWrap::RemoveChild(child);
182 NS_ASSERTION(!mChildren.Length(),
183 "This child document of outerdoc accessible wasn't removed!");
185 return wasRemoved;
188 bool OuterDocAccessible::IsAcceptableChild(nsIContent* aEl) const {
189 // outer document accessible doesn't not participate in ordinal tree
190 // mutations.
191 return false;
194 // Accessible
196 uint32_t OuterDocAccessible::ChildCount() const {
197 uint32_t result = mChildren.Length();
198 if (!result && RemoteChildDoc()) {
199 result = 1;
201 return result;
204 Accessible* OuterDocAccessible::ChildAt(uint32_t aIndex) const {
205 LocalAccessible* result = LocalChildAt(aIndex);
206 if (result || aIndex) {
207 return result;
210 return RemoteChildDoc();
213 Accessible* OuterDocAccessible::ChildAtPoint(int32_t aX, int32_t aY,
214 EWhichChildAtPoint aWhichChild) {
215 nsIntRect docRect = Bounds();
216 if (!docRect.Contains(aX, aY)) return nullptr;
218 // Always return the inner doc as direct child accessible unless bounds
219 // outside of it.
220 Accessible* child = ChildAt(0);
221 NS_ENSURE_TRUE(child, nullptr);
223 if (aWhichChild == EWhichChildAtPoint::DeepestChild) {
224 return child->ChildAtPoint(aX, aY, EWhichChildAtPoint::DeepestChild);
226 return child;
229 DocAccessibleParent* OuterDocAccessible::RemoteChildDoc() const {
230 dom::BrowserParent* tab = dom::BrowserParent::GetFrom(GetContent());
231 if (!tab) {
232 return nullptr;
235 return tab->GetTopLevelDocAccessible();