Source code

Revision control

Other Tools

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 "RootAccessible.h"
7
8
#include "mozilla/ArrayUtils.h"
9
#include "mozilla/PresShell.h" // for nsAccUtils::GetDocAccessibleFor()
10
11
#define CreateEvent CreateEventA
12
13
#include "Accessible-inl.h"
14
#include "DocAccessible-inl.h"
15
#include "nsAccessibilityService.h"
16
#include "nsAccUtils.h"
17
#include "nsCoreUtils.h"
18
#include "nsEventShell.h"
19
#include "Relation.h"
20
#include "Role.h"
21
#include "States.h"
22
#ifdef MOZ_XUL
23
# include "XULTreeAccessible.h"
24
#endif
25
26
#include "mozilla/dom/BindingUtils.h"
27
#include "mozilla/dom/CustomEvent.h"
28
#include "mozilla/dom/Element.h"
29
#include "mozilla/dom/ScriptSettings.h"
30
#include "mozilla/dom/BrowserHost.h"
31
32
#include "nsIDocShellTreeOwner.h"
33
#include "mozilla/dom/Event.h"
34
#include "mozilla/dom/EventTarget.h"
35
#include "nsIDOMXULMultSelectCntrlEl.h"
36
#include "mozilla/dom/Document.h"
37
#include "nsIInterfaceRequestorUtils.h"
38
#include "nsIPropertyBag2.h"
39
#include "nsPIDOMWindow.h"
40
#include "nsIWebBrowserChrome.h"
41
#include "nsReadableUtils.h"
42
#include "nsFocusManager.h"
43
#include "nsGlobalWindow.h"
44
45
#ifdef MOZ_XUL
46
# include "nsIAppWindow.h"
47
#endif
48
49
using namespace mozilla;
50
using namespace mozilla::a11y;
51
using namespace mozilla::dom;
52
53
////////////////////////////////////////////////////////////////////////////////
54
// nsISupports
55
56
NS_IMPL_ISUPPORTS_INHERITED(RootAccessible, DocAccessible, nsIDOMEventListener)
57
58
////////////////////////////////////////////////////////////////////////////////
59
// Constructor/destructor
60
61
RootAccessible::RootAccessible(Document* aDocument, PresShell* aPresShell)
62
: DocAccessibleWrap(aDocument, aPresShell) {
63
mType = eRootType;
64
}
65
66
RootAccessible::~RootAccessible() {}
67
68
////////////////////////////////////////////////////////////////////////////////
69
// Accessible
70
71
ENameValueFlag RootAccessible::Name(nsString& aName) const {
72
aName.Truncate();
73
74
if (ARIARoleMap()) {
75
Accessible::Name(aName);
76
if (!aName.IsEmpty()) return eNameOK;
77
}
78
79
mDocumentNode->GetTitle(aName);
80
return eNameOK;
81
}
82
83
// RootAccessible protected member
84
#ifdef MOZ_XUL
85
uint32_t RootAccessible::GetChromeFlags() const {
86
// Return the flag set for the top level window as defined
87
// by nsIWebBrowserChrome::CHROME_WINDOW_[FLAGNAME]
88
// Not simple: nsIAppWindow is not just a QI from nsIDOMWindow
89
nsCOMPtr<nsIDocShell> docShell = nsCoreUtils::GetDocShellFor(mDocumentNode);
90
NS_ENSURE_TRUE(docShell, 0);
91
nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
92
docShell->GetTreeOwner(getter_AddRefs(treeOwner));
93
NS_ENSURE_TRUE(treeOwner, 0);
94
nsCOMPtr<nsIAppWindow> appWin(do_GetInterface(treeOwner));
95
if (!appWin) {
96
return 0;
97
}
98
uint32_t chromeFlags;
99
appWin->GetChromeFlags(&chromeFlags);
100
return chromeFlags;
101
}
102
#endif
103
104
uint64_t RootAccessible::NativeState() const {
105
uint64_t state = DocAccessibleWrap::NativeState();
106
if (state & states::DEFUNCT) return state;
107
108
#ifdef MOZ_XUL
109
uint32_t chromeFlags = GetChromeFlags();
110
if (chromeFlags & nsIWebBrowserChrome::CHROME_WINDOW_RESIZE)
111
state |= states::SIZEABLE;
112
// If it has a titlebar it's movable
113
// XXX unless it's minimized or maximized, but not sure
114
// how to detect that
115
if (chromeFlags & nsIWebBrowserChrome::CHROME_TITLEBAR)
116
state |= states::MOVEABLE;
117
if (chromeFlags & nsIWebBrowserChrome::CHROME_MODAL) state |= states::MODAL;
118
#endif
119
120
nsFocusManager* fm = nsFocusManager::GetFocusManager();
121
if (fm && fm->GetActiveWindow() == mDocumentNode->GetWindow())
122
state |= states::ACTIVE;
123
124
return state;
125
}
126
127
const char* const kEventTypes[] = {
128
#ifdef DEBUG_DRAGDROPSTART
129
// Capture mouse over events and fire fake DRAGDROPSTART event to simplify
130
// debugging a11y objects with event viewers.
131
"mouseover",
132
#endif
133
// Fired when list or tree selection changes.
134
"select",
135
// Fired when value changes immediately, wether or not focused changed.
136
"ValueChange", "AlertActive", "TreeRowCountChanged", "TreeInvalidated",
137
// add ourself as a OpenStateChange listener (custom event fired in
138
// tree.xml)
139
"OpenStateChange",
140
// add ourself as a CheckboxStateChange listener (custom event fired in
141
// HTMLInputElement.cpp)
142
"CheckboxStateChange",
143
// add ourself as a RadioStateChange Listener (custom event fired in in
144
// HTMLInputElement.cpp & radio.js)
145
"RadioStateChange", "popupshown", "popuphiding", "DOMMenuInactive",
146
"DOMMenuItemActive", "DOMMenuItemInactive", "DOMMenuBarActive",
147
"DOMMenuBarInactive"};
148
149
nsresult RootAccessible::AddEventListeners() {
150
// EventTarget interface allows to register event listeners to
151
// receive untrusted events (synthetic events generated by untrusted code).
152
// For example, XBL bindings implementations for elements that are hosted in
153
// non chrome document fire untrusted events.
154
// We must use the window's parent target in order to receive events from
155
// iframes and shadow DOM; e.g. ValueChange events from a <select> in an
156
// iframe or shadow DOM. The root document itself doesn't receive these.
157
nsPIDOMWindowOuter* window = mDocumentNode->GetWindow();
158
nsCOMPtr<EventTarget> nstarget = window ? window->GetParentTarget() : nullptr;
159
160
if (nstarget) {
161
for (const char *const *e = kEventTypes, *const *e_end =
162
ArrayEnd(kEventTypes);
163
e < e_end; ++e) {
164
nsresult rv = nstarget->AddEventListener(NS_ConvertASCIItoUTF16(*e), this,
165
true, true);
166
NS_ENSURE_SUCCESS(rv, rv);
167
}
168
}
169
170
return DocAccessible::AddEventListeners();
171
}
172
173
nsresult RootAccessible::RemoveEventListeners() {
174
nsPIDOMWindowOuter* window = mDocumentNode->GetWindow();
175
nsCOMPtr<EventTarget> target = window ? window->GetParentTarget() : nullptr;
176
if (target) {
177
for (const char *const *e = kEventTypes, *const *e_end =
178
ArrayEnd(kEventTypes);
179
e < e_end; ++e) {
180
target->RemoveEventListener(NS_ConvertASCIItoUTF16(*e), this, true);
181
}
182
}
183
184
// Do this before removing clearing caret accessible, so that it can use
185
// shutdown the caret accessible's selection listener
186
DocAccessible::RemoveEventListeners();
187
return NS_OK;
188
}
189
190
////////////////////////////////////////////////////////////////////////////////
191
// public
192
193
void RootAccessible::DocumentActivated(DocAccessible* aDocument) {}
194
195
////////////////////////////////////////////////////////////////////////////////
196
// nsIDOMEventListener
197
198
NS_IMETHODIMP
199
RootAccessible::HandleEvent(Event* aDOMEvent) {
200
MOZ_ASSERT(aDOMEvent);
201
if (IsDefunct()) {
202
// Even though we've been shut down, RemoveEventListeners might not have
203
// removed the event handlers on the window's parent target if GetWindow
204
// returned null, so we might still get events here in this case. We should
205
// just ignore these events.
206
return NS_OK;
207
}
208
209
nsCOMPtr<nsINode> origTargetNode =
210
do_QueryInterface(aDOMEvent->GetOriginalTarget());
211
if (!origTargetNode) return NS_OK;
212
213
#ifdef A11Y_LOG
214
if (logging::IsEnabled(logging::eDOMEvents)) {
215
nsAutoString eventType;
216
aDOMEvent->GetType(eventType);
217
logging::DOMEvent("handled", origTargetNode, eventType);
218
}
219
#endif
220
221
DocAccessible* document =
222
GetAccService()->GetDocAccessible(origTargetNode->OwnerDoc());
223
224
if (document) {
225
// Root accessible exists longer than any of its descendant documents so
226
// that we are guaranteed notification is processed before root accessible
227
// is destroyed.
228
// For shadow DOM, GetOriginalTarget on the Event returns null if we
229
// process the event async, so we must pass the target node as well.
230
document->HandleNotification<RootAccessible, Event, nsINode>(
231
this, &RootAccessible::ProcessDOMEvent, aDOMEvent, origTargetNode);
232
}
233
234
return NS_OK;
235
}
236
237
// RootAccessible protected
238
void RootAccessible::ProcessDOMEvent(Event* aDOMEvent, nsINode* aTarget) {
239
MOZ_ASSERT(aDOMEvent);
240
MOZ_ASSERT(aTarget);
241
242
nsAutoString eventType;
243
aDOMEvent->GetType(eventType);
244
245
#ifdef A11Y_LOG
246
if (logging::IsEnabled(logging::eDOMEvents))
247
logging::DOMEvent("processed", aTarget, eventType);
248
#endif
249
250
if (eventType.EqualsLiteral("popuphiding")) {
251
HandlePopupHidingEvent(aTarget);
252
return;
253
}
254
255
DocAccessible* targetDocument =
256
GetAccService()->GetDocAccessible(aTarget->OwnerDoc());
257
if (!targetDocument) {
258
// Document has ceased to exist.
259
return;
260
}
261
262
Accessible* accessible = targetDocument->GetAccessibleOrContainer(aTarget);
263
if (!accessible) return;
264
265
#ifdef MOZ_XUL
266
XULTreeAccessible* treeAcc = accessible->AsXULTree();
267
if (treeAcc) {
268
if (eventType.EqualsLiteral("TreeRowCountChanged")) {
269
HandleTreeRowCountChangedEvent(aDOMEvent, treeAcc);
270
return;
271
}
272
273
if (eventType.EqualsLiteral("TreeInvalidated")) {
274
HandleTreeInvalidatedEvent(aDOMEvent, treeAcc);
275
return;
276
}
277
}
278
#endif
279
280
if (eventType.EqualsLiteral("RadioStateChange")) {
281
uint64_t state = accessible->State();
282
bool isEnabled = (state & (states::CHECKED | states::SELECTED)) != 0;
283
284
if (accessible->NeedsDOMUIEvent()) {
285
RefPtr<AccEvent> accEvent =
286
new AccStateChangeEvent(accessible, states::CHECKED, isEnabled);
287
nsEventShell::FireEvent(accEvent);
288
}
289
290
if (isEnabled) {
291
FocusMgr()->ActiveItemChanged(accessible);
292
#ifdef A11Y_LOG
293
if (logging::IsEnabled(logging::eFocus))
294
logging::ActiveItemChangeCausedBy("RadioStateChange", accessible);
295
#endif
296
}
297
298
return;
299
}
300
301
if (eventType.EqualsLiteral("CheckboxStateChange")) {
302
if (accessible->NeedsDOMUIEvent()) {
303
uint64_t state = accessible->State();
304
bool isEnabled = !!(state & states::CHECKED);
305
306
RefPtr<AccEvent> accEvent =
307
new AccStateChangeEvent(accessible, states::CHECKED, isEnabled);
308
nsEventShell::FireEvent(accEvent);
309
}
310
return;
311
}
312
313
Accessible* treeItemAcc = nullptr;
314
#ifdef MOZ_XUL
315
// If it's a tree element, need the currently selected item.
316
if (treeAcc) {
317
treeItemAcc = accessible->CurrentItem();
318
if (treeItemAcc) accessible = treeItemAcc;
319
}
320
321
if (treeItemAcc && eventType.EqualsLiteral("OpenStateChange")) {
322
uint64_t state = accessible->State();
323
bool isEnabled = (state & states::EXPANDED) != 0;
324
325
RefPtr<AccEvent> accEvent =
326
new AccStateChangeEvent(accessible, states::EXPANDED, isEnabled);
327
nsEventShell::FireEvent(accEvent);
328
return;
329
}
330
331
nsINode* targetNode = accessible->GetNode();
332
if (treeItemAcc && eventType.EqualsLiteral("select")) {
333
// XXX: We shouldn't be based on DOM select event which doesn't provide us
334
// any context info. We should integrate into nsTreeSelection instead.
335
// If multiselect tree, we should fire selectionadd or selection removed
336
if (FocusMgr()->HasDOMFocus(targetNode)) {
337
nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSel =
338
targetNode->AsElement()->AsXULMultiSelectControl();
339
if (!multiSel) {
340
// This shouldn't be possible. All XUL trees should have
341
// nsIDOMXULMultiSelectControlElement, and the tree is focused, so it
342
// shouldn't be dying. Nevertheless, this sometimes happens in the wild
343
// (bug 1597043).
344
MOZ_ASSERT_UNREACHABLE(
345
"XUL tree doesn't have nsIDOMXULMultiSelectControlElement");
346
return;
347
}
348
nsAutoString selType;
349
multiSel->GetSelType(selType);
350
if (selType.IsEmpty() || !selType.EqualsLiteral("single")) {
351
// XXX: We need to fire EVENT_SELECTION_ADD and EVENT_SELECTION_REMOVE
352
// for each tree item. Perhaps each tree item will need to cache its
353
// selection state and fire an event after a DOM "select" event when
354
// that state changes. XULTreeAccessible::UpdateTreeSelection();
355
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SELECTION_WITHIN,
356
accessible);
357
return;
358
}
359
360
RefPtr<AccSelChangeEvent> selChangeEvent = new AccSelChangeEvent(
361
treeAcc, treeItemAcc, AccSelChangeEvent::eSelectionAdd);
362
nsEventShell::FireEvent(selChangeEvent);
363
return;
364
}
365
} else
366
#endif
367
if (eventType.EqualsLiteral("AlertActive")) {
368
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_ALERT, accessible);
369
} else if (eventType.EqualsLiteral("popupshown")) {
370
HandlePopupShownEvent(accessible);
371
} else if (eventType.EqualsLiteral("DOMMenuInactive")) {
372
if (accessible->Role() == roles::MENUPOPUP) {
373
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END,
374
accessible);
375
}
376
} else if (eventType.EqualsLiteral("DOMMenuItemActive")) {
377
FocusMgr()->ActiveItemChanged(accessible);
378
#ifdef A11Y_LOG
379
if (logging::IsEnabled(logging::eFocus))
380
logging::ActiveItemChangeCausedBy("DOMMenuItemActive", accessible);
381
#endif
382
} else if (eventType.EqualsLiteral("DOMMenuItemInactive")) {
383
// Process DOMMenuItemInactive event for autocomplete only because this is
384
// unique widget that may acquire focus from autocomplete popup while popup
385
// stays open and has no active item. In case of XUL tree autocomplete
386
// popup this event is fired for tree accessible.
387
Accessible* widget =
388
accessible->IsWidget() ? accessible : accessible->ContainerWidget();
389
if (widget && widget->IsAutoCompletePopup()) {
390
FocusMgr()->ActiveItemChanged(nullptr);
391
#ifdef A11Y_LOG
392
if (logging::IsEnabled(logging::eFocus))
393
logging::ActiveItemChangeCausedBy("DOMMenuItemInactive", accessible);
394
#endif
395
}
396
} else if (eventType.EqualsLiteral(
397
"DOMMenuBarActive")) { // Always from user input
398
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENU_START, accessible,
399
eFromUserInput);
400
401
// Notify of active item change when menubar gets active and if it has
402
// current item. This is a case of mouseover (set current menuitem) and
403
// mouse click (activate the menubar). If menubar doesn't have current item
404
// (can be a case of menubar activation from keyboard) then ignore this
405
// notification because later we'll receive DOMMenuItemActive event after
406
// current menuitem is set.
407
Accessible* activeItem = accessible->CurrentItem();
408
if (activeItem) {
409
FocusMgr()->ActiveItemChanged(activeItem);
410
#ifdef A11Y_LOG
411
if (logging::IsEnabled(logging::eFocus))
412
logging::ActiveItemChangeCausedBy("DOMMenuBarActive", accessible);
413
#endif
414
}
415
} else if (eventType.EqualsLiteral(
416
"DOMMenuBarInactive")) { // Always from user input
417
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENU_END, accessible,
418
eFromUserInput);
419
420
FocusMgr()->ActiveItemChanged(nullptr);
421
#ifdef A11Y_LOG
422
if (logging::IsEnabled(logging::eFocus))
423
logging::ActiveItemChangeCausedBy("DOMMenuBarInactive", accessible);
424
#endif
425
} else if (accessible->NeedsDOMUIEvent() &&
426
eventType.EqualsLiteral("ValueChange")) {
427
uint32_t event = accessible->HasNumericValue()
428
? nsIAccessibleEvent::EVENT_VALUE_CHANGE
429
: nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE;
430
targetDocument->FireDelayedEvent(event, accessible);
431
}
432
#ifdef DEBUG_DRAGDROPSTART
433
else if (eventType.EqualsLiteral("mouseover")) {
434
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_DRAGDROP_START,
435
accessible);
436
}
437
#endif
438
}
439
440
////////////////////////////////////////////////////////////////////////////////
441
// Accessible
442
443
void RootAccessible::Shutdown() {
444
// Called manually or by Accessible::LastRelease()
445
if (HasShutdown()) {
446
return;
447
}
448
DocAccessibleWrap::Shutdown();
449
}
450
451
Relation RootAccessible::RelationByType(RelationType aType) const {
452
if (!mDocumentNode || aType != RelationType::EMBEDS)
453
return DocAccessibleWrap::RelationByType(aType);
454
455
if (nsPIDOMWindowOuter* rootWindow = mDocumentNode->GetWindow()) {
456
nsCOMPtr<nsPIDOMWindowOuter> contentWindow =
457
nsGlobalWindowOuter::Cast(rootWindow)->GetContent();
458
if (contentWindow) {
459
RefPtr<Document> contentDocumentNode = contentWindow->GetDoc();
460
if (contentDocumentNode) {
461
DocAccessible* contentDocument =
462
GetAccService()->GetDocAccessible(contentDocumentNode);
463
if (contentDocument) return Relation(contentDocument);
464
}
465
}
466
}
467
468
return Relation();
469
}
470
471
////////////////////////////////////////////////////////////////////////////////
472
// Protected members
473
474
void RootAccessible::HandlePopupShownEvent(Accessible* aAccessible) {
475
roles::Role role = aAccessible->Role();
476
477
if (role == roles::MENUPOPUP) {
478
// Don't fire menupopup events for combobox and autocomplete lists.
479
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START,
480
aAccessible);
481
return;
482
}
483
484
if (role == roles::TOOLTIP) {
485
// There is a single <xul:tooltip> node which Mozilla moves around.
486
// The accessible for it stays the same no matter where it moves.
487
// AT's expect to get an EVENT_SHOW for the tooltip.
488
// In event callback the tooltip's accessible will be ready.
489
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SHOW, aAccessible);
490
return;
491
}
492
493
if (role == roles::COMBOBOX_LIST) {
494
// Fire expanded state change event for comboboxes and autocompeletes.
495
Accessible* combobox = aAccessible->Parent();
496
if (!combobox) return;
497
498
if (combobox->IsCombobox() || combobox->IsAutoComplete()) {
499
RefPtr<AccEvent> event =
500
new AccStateChangeEvent(combobox, states::EXPANDED, true);
501
if (event) nsEventShell::FireEvent(event);
502
}
503
}
504
}
505
506
void RootAccessible::HandlePopupHidingEvent(nsINode* aPopupNode) {
507
// Get popup accessible. There are cases when popup element isn't accessible
508
// but an underlying widget is and behaves like popup, an example is
509
// autocomplete popups.
510
DocAccessible* document = nsAccUtils::GetDocAccessibleFor(aPopupNode);
511
if (!document) return;
512
513
Accessible* popup = document->GetAccessible(aPopupNode);
514
if (!popup) {
515
Accessible* popupContainer = document->GetContainerAccessible(aPopupNode);
516
if (!popupContainer) return;
517
518
uint32_t childCount = popupContainer->ChildCount();
519
for (uint32_t idx = 0; idx < childCount; idx++) {
520
Accessible* child = popupContainer->GetChildAt(idx);
521
if (child->IsAutoCompletePopup()) {
522
popup = child;
523
break;
524
}
525
}
526
527
// No popup no events. Focus is managed by DOM. This is a case for
528
// menupopups of menus on Linux since there are no accessible for popups.
529
if (!popup) return;
530
}
531
532
// In case of autocompletes and comboboxes fire state change event for
533
// expanded state. Note, HTML form autocomplete isn't a subject of state
534
// change event because they aren't autocompletes strictly speaking.
535
// When popup closes (except nested popups and menus) then fire focus event to
536
// where it was. The focus event is expected even if popup didn't take a
537
// focus.
538
539
static const uint32_t kNotifyOfFocus = 1;
540
static const uint32_t kNotifyOfState = 2;
541
uint32_t notifyOf = 0;
542
543
// HTML select is target of popuphidding event. Otherwise get container
544
// widget. No container widget means this is either tooltip or menupopup.
545
// No events in the former case.
546
Accessible* widget = nullptr;
547
if (popup->IsCombobox()) {
548
widget = popup;
549
} else {
550
widget = popup->ContainerWidget();
551
if (!widget) {
552
if (!popup->IsMenuPopup()) return;
553
554
widget = popup;
555
}
556
}
557
558
if (popup->IsAutoCompletePopup()) {
559
// No focus event for autocomplete because it's managed by
560
// DOMMenuItemInactive events.
561
if (widget->IsAutoComplete()) notifyOf = kNotifyOfState;
562
563
} else if (widget->IsCombobox()) {
564
// Fire focus for active combobox, otherwise the focus is managed by DOM
565
// focus notifications. Always fire state change event.
566
if (widget->IsActiveWidget()) notifyOf = kNotifyOfFocus;
567
notifyOf |= kNotifyOfState;
568
569
} else if (widget->IsMenuButton()) {
570
// Can be a part of autocomplete.
571
Accessible* compositeWidget = widget->ContainerWidget();
572
if (compositeWidget && compositeWidget->IsAutoComplete()) {
573
widget = compositeWidget;
574
notifyOf = kNotifyOfState;
575
}
576
577
// Autocomplete (like searchbar) can be inactive when popup hiddens
578
notifyOf |= kNotifyOfFocus;
579
580
} else if (widget == popup) {
581
// Top level context menus and alerts.
582
// Ignore submenus and menubar. When submenu is closed then sumbenu
583
// container menuitem takes a focus via DOMMenuItemActive notification.
584
// For menubars processing we listen DOMMenubarActive/Inactive
585
// notifications.
586
notifyOf = kNotifyOfFocus;
587
}
588
589
// Restore focus to where it was.
590
if (notifyOf & kNotifyOfFocus) {
591
FocusMgr()->ActiveItemChanged(nullptr);
592
#ifdef A11Y_LOG
593
if (logging::IsEnabled(logging::eFocus))
594
logging::ActiveItemChangeCausedBy("popuphiding", popup);
595
#endif
596
}
597
598
// Fire expanded state change event.
599
if (notifyOf & kNotifyOfState) {
600
RefPtr<AccEvent> event =
601
new AccStateChangeEvent(widget, states::EXPANDED, false);
602
document->FireDelayedEvent(event);
603
}
604
}
605
606
#ifdef MOZ_XUL
607
static void GetPropertyBagFromEvent(Event* aEvent,
608
nsIPropertyBag2** aPropertyBag) {
609
*aPropertyBag = nullptr;
610
611
CustomEvent* customEvent = aEvent->AsCustomEvent();
612
if (!customEvent) return;
613
614
AutoJSAPI jsapi;
615
if (!jsapi.Init(customEvent->GetParentObject())) return;
616
617
JSContext* cx = jsapi.cx();
618
JS::Rooted<JS::Value> detail(cx);
619
customEvent->GetDetail(cx, &detail);
620
if (!detail.isObject()) return;
621
622
JS::Rooted<JSObject*> detailObj(cx, &detail.toObject());
623
624
nsresult rv;
625
nsCOMPtr<nsIPropertyBag2> propBag;
626
rv = UnwrapArg<nsIPropertyBag2>(cx, detailObj, getter_AddRefs(propBag));
627
if (NS_FAILED(rv)) return;
628
629
propBag.forget(aPropertyBag);
630
}
631
632
void RootAccessible::HandleTreeRowCountChangedEvent(
633
Event* aEvent, XULTreeAccessible* aAccessible) {
634
nsCOMPtr<nsIPropertyBag2> propBag;
635
GetPropertyBagFromEvent(aEvent, getter_AddRefs(propBag));
636
if (!propBag) return;
637
638
nsresult rv;
639
int32_t index, count;
640
rv = propBag->GetPropertyAsInt32(NS_LITERAL_STRING("index"), &index);
641
if (NS_FAILED(rv)) return;
642
643
rv = propBag->GetPropertyAsInt32(NS_LITERAL_STRING("count"), &count);
644
if (NS_FAILED(rv)) return;
645
646
aAccessible->InvalidateCache(index, count);
647
}
648
649
void RootAccessible::HandleTreeInvalidatedEvent(
650
Event* aEvent, XULTreeAccessible* aAccessible) {
651
nsCOMPtr<nsIPropertyBag2> propBag;
652
GetPropertyBagFromEvent(aEvent, getter_AddRefs(propBag));
653
if (!propBag) return;
654
655
int32_t startRow = 0, endRow = -1, startCol = 0, endCol = -1;
656
propBag->GetPropertyAsInt32(NS_LITERAL_STRING("startrow"), &startRow);
657
propBag->GetPropertyAsInt32(NS_LITERAL_STRING("endrow"), &endRow);
658
propBag->GetPropertyAsInt32(NS_LITERAL_STRING("startcolumn"), &startCol);
659
propBag->GetPropertyAsInt32(NS_LITERAL_STRING("endcolumn"), &endCol);
660
661
aAccessible->TreeViewInvalidated(startRow, endRow, startCol, endCol);
662
}
663
#endif
664
665
ProxyAccessible* RootAccessible::GetPrimaryRemoteTopLevelContentDoc() const {
666
nsCOMPtr<nsIDocShellTreeOwner> owner;
667
mDocumentNode->GetDocShell()->GetTreeOwner(getter_AddRefs(owner));
668
NS_ENSURE_TRUE(owner, nullptr);
669
670
nsCOMPtr<nsIRemoteTab> remoteTab;
671
owner->GetPrimaryRemoteTab(getter_AddRefs(remoteTab));
672
if (!remoteTab) {
673
return nullptr;
674
}
675
676
auto tab = static_cast<dom::BrowserHost*>(remoteTab.get());
677
return tab->GetTopLevelDocAccessible();
678
}