Bug 1675375 Part 7: Update expectations in helper_hittest_clippath.html. r=botond
[gecko.git] / accessible / generic / OuterDocAccessible.cpp
blobfad269afc83454e413e9ef9c1c294bc1c94cbb46
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 #if defined(XP_WIN)
14 # include "mozilla/a11y/ProxyWrappers.h"
15 #endif
16 #include "mozilla/dom/BrowserBridgeChild.h"
17 #include "mozilla/dom/BrowserParent.h"
18 #include "Role.h"
19 #include "States.h"
21 #ifdef A11Y_LOG
22 # include "Logging.h"
23 #endif
25 using namespace mozilla;
26 using namespace mozilla::a11y;
28 ////////////////////////////////////////////////////////////////////////////////
29 // OuterDocAccessible
30 ////////////////////////////////////////////////////////////////////////////////
32 OuterDocAccessible::OuterDocAccessible(nsIContent* aContent,
33 DocAccessible* aDoc)
34 : AccessibleWrap(aContent, aDoc) {
35 mType = eOuterDocType;
37 #ifdef XP_WIN
38 if (DocAccessibleParent* remoteDoc = RemoteChildDoc()) {
39 remoteDoc->SendParentCOMProxy(this);
41 #endif
43 if (IPCAccessibilityActive()) {
44 auto bridge = dom::BrowserBridgeChild::GetFrom(aContent);
45 if (bridge) {
46 // This is an iframe which will be rendered in another process.
47 SendEmbedderAccessible(bridge);
51 // Request document accessible for the content document to make sure it's
52 // created. It will appended to outerdoc accessible children asynchronously.
53 dom::Document* outerDoc = mContent->GetUncomposedDoc();
54 if (outerDoc) {
55 dom::Document* innerDoc = outerDoc->GetSubDocumentFor(mContent);
56 if (innerDoc) GetAccService()->GetDocAccessible(innerDoc);
60 OuterDocAccessible::~OuterDocAccessible() {}
62 void OuterDocAccessible::SendEmbedderAccessible(
63 dom::BrowserBridgeChild* aBridge) {
64 MOZ_ASSERT(mDoc);
65 DocAccessibleChild* ipcDoc = mDoc->IPCDoc();
66 if (ipcDoc) {
67 uint64_t id = reinterpret_cast<uintptr_t>(UniqueID());
68 #if defined(XP_WIN)
69 ipcDoc->SetEmbedderOnBridge(aBridge, id);
70 #else
71 aBridge->SendSetEmbedderAccessible(ipcDoc, id);
72 #endif
76 ////////////////////////////////////////////////////////////////////////////////
77 // LocalAccessible public (DON'T add methods here)
79 role OuterDocAccessible::NativeRole() const { return roles::INTERNAL_FRAME; }
81 LocalAccessible* OuterDocAccessible::LocalChildAtPoint(
82 int32_t aX, int32_t aY, EWhichChildAtPoint aWhichChild) {
83 nsIntRect docRect = Bounds();
84 if (!docRect.Contains(aX, aY)) return nullptr;
86 // Always return the inner doc as direct child accessible unless bounds
87 // outside of it.
88 LocalAccessible* child = LocalChildAt(0);
89 NS_ENSURE_TRUE(child, nullptr);
91 if (aWhichChild == Accessible::EWhichChildAtPoint::DeepestChild) {
92 #if defined(XP_WIN)
93 // On Windows, OuterDocAccessible::GetChildAt can return a proxy wrapper
94 // for a remote document. These aren't real Accessibles and
95 // shouldn't be returned except to the Windows a11y code (which doesn't use
96 // eDeepestChild). Calling ChildAtPoint on these will crash!
97 return nullptr;
98 #else
99 return child->LocalChildAtPoint(
100 aX, aY, Accessible::EWhichChildAtPoint::DeepestChild);
101 #endif // defined(XP_WIN)
103 return child;
106 ////////////////////////////////////////////////////////////////////////////////
107 // LocalAccessible public
109 void OuterDocAccessible::Shutdown() {
110 #ifdef A11Y_LOG
111 if (logging::IsEnabled(logging::eDocDestroy)) logging::OuterDocDestroy(this);
112 #endif
114 LocalAccessible* child = mChildren.SafeElementAt(0, nullptr);
115 if (child) {
116 #ifdef A11Y_LOG
117 if (logging::IsEnabled(logging::eDocDestroy)) {
118 logging::DocDestroy("outerdoc's child document rebind is scheduled",
119 child->AsDoc()->DocumentNode());
121 #endif
122 RemoveChild(child);
124 // XXX: sometimes outerdoc accessible is shutdown because of layout style
125 // change however the presshell of underlying document isn't destroyed and
126 // the document doesn't get pagehide events. Schedule a document rebind
127 // to its parent document. Otherwise a document accessible may be lost if
128 // its outerdoc has being recreated (see bug 862863 for details).
129 if (!mDoc->IsDefunct()) {
130 MOZ_ASSERT(!child->IsDefunct(),
131 "Attempt to reattach shutdown document accessible");
132 if (!child->IsDefunct()) {
133 mDoc->BindChildDocument(child->AsDoc());
138 AccessibleWrap::Shutdown();
141 bool OuterDocAccessible::InsertChildAt(uint32_t aIdx,
142 LocalAccessible* aAccessible) {
143 MOZ_RELEASE_ASSERT(aAccessible->IsDoc(),
144 "OuterDocAccessible can have a document child only!");
146 // We keep showing the old document for a bit after creating the new one,
147 // and while building the new DOM and frame tree. That's done on purpose
148 // to avoid weird flashes of default background color.
149 // The old viewer will be destroyed after the new one is created.
150 // For a11y, it should be safe to shut down the old document now.
151 if (mChildren.Length()) mChildren[0]->Shutdown();
153 if (!AccessibleWrap::InsertChildAt(0, aAccessible)) return false;
155 #ifdef A11Y_LOG
156 if (logging::IsEnabled(logging::eDocCreate)) {
157 logging::DocCreate("append document to outerdoc",
158 aAccessible->AsDoc()->DocumentNode());
159 logging::Address("outerdoc", this);
161 #endif
163 return true;
166 bool OuterDocAccessible::RemoveChild(LocalAccessible* aAccessible) {
167 LocalAccessible* child = mChildren.SafeElementAt(0, nullptr);
168 MOZ_ASSERT(child == aAccessible, "Wrong child to remove!");
169 if (child != aAccessible) {
170 return false;
173 #ifdef A11Y_LOG
174 if (logging::IsEnabled(logging::eDocDestroy)) {
175 logging::DocDestroy("remove document from outerdoc",
176 child->AsDoc()->DocumentNode(), child->AsDoc());
177 logging::Address("outerdoc", this);
179 #endif
181 bool wasRemoved = AccessibleWrap::RemoveChild(child);
183 NS_ASSERTION(!mChildren.Length(),
184 "This child document of outerdoc accessible wasn't removed!");
186 return wasRemoved;
189 bool OuterDocAccessible::IsAcceptableChild(nsIContent* aEl) const {
190 // outer document accessible doesn't not participate in ordinal tree
191 // mutations.
192 return false;
195 #if defined(XP_WIN)
197 LocalAccessible* OuterDocAccessible::RemoteChildDocAccessible() const {
198 RemoteAccessible* docProxy = RemoteChildDoc();
199 if (docProxy) {
200 // We're in the parent process, but we're embedding a remote document.
201 return WrapperFor(docProxy);
204 if (IPCAccessibilityActive()) {
205 auto bridge = dom::BrowserBridgeChild::GetFrom(mContent);
206 if (bridge) {
207 // We're an iframe in a content process and we're embedding a remote
208 // document (in another content process). The COM proxy for the embedded
209 // document accessible was sent to us from the parent via PBrowserBridge.
210 return bridge->GetEmbeddedDocAccessible();
214 return nullptr;
217 // On Windows e10s, since we don't cache in the chrome process, these next two
218 // functions must be implemented so that we properly cross the chrome-to-content
219 // boundary when traversing.
221 uint32_t OuterDocAccessible::ChildCount() const {
222 uint32_t result = mChildren.Length();
223 if (!result && RemoteChildDocAccessible()) {
224 result = 1;
226 return result;
229 LocalAccessible* OuterDocAccessible::LocalChildAt(uint32_t aIndex) const {
230 LocalAccessible* result = AccessibleWrap::LocalChildAt(aIndex);
231 if (result || aIndex) {
232 return result;
234 // If we are asking for child 0 and GetChildAt doesn't return anything, try
235 // to get the remote child doc and return that instead.
236 return RemoteChildDocAccessible();
239 #endif // defined(XP_WIN)
241 // Accessible
243 Accessible* OuterDocAccessible::ChildAt(uint32_t aIndex) const {
244 LocalAccessible* result = AccessibleWrap::LocalChildAt(aIndex);
245 if (result || aIndex) {
246 #if defined(XP_WIN)
247 // On Windows, AccessibleWrap::LocalChildAt can return a proxy wrapper
248 // for a remote document. These aren't real Accessibles so we skip this
249 // block and retrieve the remote child doc.
250 if (!result || !result->IsProxy()) {
251 return result;
253 #else
254 return result;
255 #endif // defined(XP_WIN)
258 return RemoteChildDoc();
261 Accessible* OuterDocAccessible::ChildAtPoint(int32_t aX, int32_t aY,
262 EWhichChildAtPoint aWhichChild) {
263 nsIntRect docRect = Bounds();
264 if (!docRect.Contains(aX, aY)) return nullptr;
266 // Always return the inner doc as direct child accessible unless bounds
267 // outside of it.
268 Accessible* child = ChildAt(0);
269 NS_ENSURE_TRUE(child, nullptr);
271 if (aWhichChild == EWhichChildAtPoint::DeepestChild) {
272 return child->ChildAtPoint(aX, aY, EWhichChildAtPoint::DeepestChild);
274 return child;
277 DocAccessibleParent* OuterDocAccessible::RemoteChildDoc() const {
278 dom::BrowserParent* tab = dom::BrowserParent::GetFrom(GetContent());
279 if (!tab) {
280 return nullptr;
283 return tab->GetTopLevelDocAccessible();