|
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 "Accessible-inl.h" |
|
9 #include "nsAccUtils.h" |
|
10 #include "DocAccessible-inl.h" |
|
11 #include "Role.h" |
|
12 #include "States.h" |
|
13 |
|
14 #ifdef A11Y_LOG |
|
15 #include "Logging.h" |
|
16 #endif |
|
17 |
|
18 using namespace mozilla; |
|
19 using namespace mozilla::a11y; |
|
20 |
|
21 //////////////////////////////////////////////////////////////////////////////// |
|
22 // OuterDocAccessible |
|
23 //////////////////////////////////////////////////////////////////////////////// |
|
24 |
|
25 OuterDocAccessible:: |
|
26 OuterDocAccessible(nsIContent* aContent, DocAccessible* aDoc) : |
|
27 AccessibleWrap(aContent, aDoc) |
|
28 { |
|
29 } |
|
30 |
|
31 OuterDocAccessible::~OuterDocAccessible() |
|
32 { |
|
33 } |
|
34 |
|
35 //////////////////////////////////////////////////////////////////////////////// |
|
36 // nsISupports |
|
37 |
|
38 NS_IMPL_ISUPPORTS_INHERITED0(OuterDocAccessible, |
|
39 Accessible) |
|
40 |
|
41 //////////////////////////////////////////////////////////////////////////////// |
|
42 // Accessible public (DON'T add methods here) |
|
43 |
|
44 role |
|
45 OuterDocAccessible::NativeRole() |
|
46 { |
|
47 return roles::INTERNAL_FRAME; |
|
48 } |
|
49 |
|
50 Accessible* |
|
51 OuterDocAccessible::ChildAtPoint(int32_t aX, int32_t aY, |
|
52 EWhichChildAtPoint aWhichChild) |
|
53 { |
|
54 int32_t docX = 0, docY = 0, docWidth = 0, docHeight = 0; |
|
55 nsresult rv = GetBounds(&docX, &docY, &docWidth, &docHeight); |
|
56 NS_ENSURE_SUCCESS(rv, nullptr); |
|
57 |
|
58 if (aX < docX || aX >= docX + docWidth || aY < docY || aY >= docY + docHeight) |
|
59 return nullptr; |
|
60 |
|
61 // Always return the inner doc as direct child accessible unless bounds |
|
62 // outside of it. |
|
63 Accessible* child = GetChildAt(0); |
|
64 NS_ENSURE_TRUE(child, nullptr); |
|
65 |
|
66 if (aWhichChild == eDeepestChild) |
|
67 return child->ChildAtPoint(aX, aY, eDeepestChild); |
|
68 return child; |
|
69 } |
|
70 |
|
71 //////////////////////////////////////////////////////////////////////////////// |
|
72 // nsIAccessible |
|
73 |
|
74 uint8_t |
|
75 OuterDocAccessible::ActionCount() |
|
76 { |
|
77 // Internal frame, which is the doc's parent, should not have a click action. |
|
78 return 0; |
|
79 } |
|
80 |
|
81 NS_IMETHODIMP |
|
82 OuterDocAccessible::GetActionName(uint8_t aIndex, nsAString& aName) |
|
83 { |
|
84 aName.Truncate(); |
|
85 |
|
86 return NS_ERROR_INVALID_ARG; |
|
87 } |
|
88 |
|
89 NS_IMETHODIMP |
|
90 OuterDocAccessible::GetActionDescription(uint8_t aIndex, |
|
91 nsAString& aDescription) |
|
92 { |
|
93 aDescription.Truncate(); |
|
94 |
|
95 return NS_ERROR_INVALID_ARG; |
|
96 } |
|
97 |
|
98 NS_IMETHODIMP |
|
99 OuterDocAccessible::DoAction(uint8_t aIndex) |
|
100 { |
|
101 return NS_ERROR_INVALID_ARG; |
|
102 } |
|
103 |
|
104 //////////////////////////////////////////////////////////////////////////////// |
|
105 // Accessible public |
|
106 |
|
107 void |
|
108 OuterDocAccessible::Shutdown() |
|
109 { |
|
110 // XXX: sometimes outerdoc accessible is shutdown because of layout style |
|
111 // change however the presshell of underlying document isn't destroyed and |
|
112 // the document doesn't get pagehide events. Schedule a document rebind |
|
113 // to its parent document. Otherwise a document accessible may be lost if its |
|
114 // outerdoc has being recreated (see bug 862863 for details). |
|
115 |
|
116 #ifdef A11Y_LOG |
|
117 if (logging::IsEnabled(logging::eDocDestroy)) |
|
118 logging::OuterDocDestroy(this); |
|
119 #endif |
|
120 |
|
121 Accessible* child = mChildren.SafeElementAt(0, nullptr); |
|
122 if (child) { |
|
123 #ifdef A11Y_LOG |
|
124 if (logging::IsEnabled(logging::eDocDestroy)) { |
|
125 logging::DocDestroy("outerdoc's child document rebind is scheduled", |
|
126 child->AsDoc()->DocumentNode()); |
|
127 } |
|
128 #endif |
|
129 RemoveChild(child); |
|
130 mDoc->BindChildDocument(child->AsDoc()); |
|
131 } |
|
132 |
|
133 AccessibleWrap::Shutdown(); |
|
134 } |
|
135 |
|
136 void |
|
137 OuterDocAccessible::InvalidateChildren() |
|
138 { |
|
139 // Do not invalidate children because DocManager is responsible for |
|
140 // document accessible lifetime when DOM document is created or destroyed. If |
|
141 // DOM document isn't destroyed but its presshell is destroyed (for example, |
|
142 // when DOM node of outerdoc accessible is hidden), then outerdoc accessible |
|
143 // notifies DocManager about this. If presshell is created for existing |
|
144 // DOM document (for example when DOM node of outerdoc accessible is shown) |
|
145 // then allow DocManager to handle this case since the document |
|
146 // accessible is created and appended as a child when it's requested. |
|
147 |
|
148 SetChildrenFlag(eChildrenUninitialized); |
|
149 } |
|
150 |
|
151 bool |
|
152 OuterDocAccessible::InsertChildAt(uint32_t aIdx, Accessible* aAccessible) |
|
153 { |
|
154 NS_ASSERTION(aAccessible->IsDoc(), |
|
155 "OuterDocAccessible should only have document child!"); |
|
156 // We keep showing the old document for a bit after creating the new one, |
|
157 // and while building the new DOM and frame tree. That's done on purpose |
|
158 // to avoid weird flashes of default background color. |
|
159 // The old viewer will be destroyed after the new one is created. |
|
160 // For a11y, it should be safe to shut down the old document now. |
|
161 if (mChildren.Length()) |
|
162 mChildren[0]->Shutdown(); |
|
163 |
|
164 if (!AccessibleWrap::InsertChildAt(0, aAccessible)) |
|
165 return false; |
|
166 |
|
167 #ifdef A11Y_LOG |
|
168 if (logging::IsEnabled(logging::eDocCreate)) { |
|
169 logging::DocCreate("append document to outerdoc", |
|
170 aAccessible->AsDoc()->DocumentNode()); |
|
171 logging::Address("outerdoc", this); |
|
172 } |
|
173 #endif |
|
174 |
|
175 return true; |
|
176 } |
|
177 |
|
178 bool |
|
179 OuterDocAccessible::RemoveChild(Accessible* aAccessible) |
|
180 { |
|
181 Accessible* child = mChildren.SafeElementAt(0, nullptr); |
|
182 if (child != aAccessible) { |
|
183 NS_ERROR("Wrong child to remove!"); |
|
184 return false; |
|
185 } |
|
186 |
|
187 #ifdef A11Y_LOG |
|
188 if (logging::IsEnabled(logging::eDocDestroy)) { |
|
189 logging::DocDestroy("remove document from outerdoc", |
|
190 child->AsDoc()->DocumentNode(), child->AsDoc()); |
|
191 logging::Address("outerdoc", this); |
|
192 } |
|
193 #endif |
|
194 |
|
195 bool wasRemoved = AccessibleWrap::RemoveChild(child); |
|
196 |
|
197 NS_ASSERTION(!mChildren.Length(), |
|
198 "This child document of outerdoc accessible wasn't removed!"); |
|
199 |
|
200 return wasRemoved; |
|
201 } |
|
202 |
|
203 |
|
204 //////////////////////////////////////////////////////////////////////////////// |
|
205 // Accessible protected |
|
206 |
|
207 void |
|
208 OuterDocAccessible::CacheChildren() |
|
209 { |
|
210 // Request document accessible for the content document to make sure it's |
|
211 // created. It will appended to outerdoc accessible children asynchronously. |
|
212 nsIDocument* outerDoc = mContent->GetCurrentDoc(); |
|
213 if (outerDoc) { |
|
214 nsIDocument* innerDoc = outerDoc->GetSubDocumentFor(mContent); |
|
215 if (innerDoc) |
|
216 GetAccService()->GetDocAccessible(innerDoc); |
|
217 } |
|
218 } |