already_AddRefed<nsIAccessibleEvent> a11y::MakeXPCEvent(AccEvent* aEvent) { DocAccessible* doc = aEvent->GetDocAccessible(); Accessible* acc = aEvent->GetAccessible(); nsINode* node = acc->GetNode(); nsIDOMNode* domNode = node ? node->AsDOMNode() : nullptr; bool fromUser = aEvent->IsFromUserInput(); uint32_t type = aEvent->GetEventType(); uint32_t eventGroup = aEvent->GetEventGroups(); nsCOMPtr<nsIAccessibleEvent> xpEvent; if (eventGroup & (1 << AccEvent::eStateChangeEvent)) { AccStateChangeEvent* sc = downcast_accEvent(aEvent); bool extra = false; uint32_t state = nsAccUtils::To32States(sc->GetState(), &extra); xpEvent = new xpcAccStateChangeEvent(type, acc, doc, domNode, fromUser, state, extra, sc->IsStateEnabled()); return xpEvent.forget(); } if (eventGroup & (1 << AccEvent::eTextChangeEvent)) { AccTextChangeEvent* tc = downcast_accEvent(aEvent); nsString text; tc->GetModifiedText(text); xpEvent = new xpcAccTextChangeEvent(type, acc, doc, domNode, fromUser, tc->GetStartOffset(), tc->GetLength(), tc->IsTextInserted(), text); return xpEvent.forget(); } if (eventGroup & (1 << AccEvent::eHideEvent)) { AccHideEvent* hideEvent = downcast_accEvent(aEvent); xpEvent = new xpcAccHideEvent(type, acc, doc, domNode, fromUser, hideEvent->TargetParent(), hideEvent->TargetNextSibling(), hideEvent->TargetPrevSibling()); return xpEvent.forget(); } if (eventGroup & (1 << AccEvent::eCaretMoveEvent)) { AccCaretMoveEvent* cm = downcast_accEvent(aEvent); xpEvent = new xpcAccCaretMoveEvent(type, acc, doc, domNode, fromUser, cm->GetCaretOffset()); return xpEvent.forget(); } if (eventGroup & (1 << AccEvent::eVirtualCursorChangeEvent)) { AccVCChangeEvent* vcc = downcast_accEvent(aEvent); xpEvent = new xpcAccVirtualCursorChangeEvent(type, acc, doc, domNode, fromUser, vcc->OldAccessible(), vcc->OldStartOffset(), vcc->OldEndOffset(), vcc->Reason()); return xpEvent.forget(); } xpEvent = new xpcAccEvent(type, acc, doc, domNode, fromUser); return xpEvent.forget(); }
void nsEventShell::FireEvent(AccEvent* aEvent) { if (!aEvent) return; Accessible* accessible = aEvent->GetAccessible(); NS_ENSURE_TRUE_VOID(accessible); nsINode* node = accessible->GetNode(); if (node) { sEventTargetNode = node; sEventFromUserInput = aEvent->IsFromUserInput(); } accessible->HandleAccEvent(aEvent); sEventTargetNode = nullptr; }
// RootAccessible protected void RootAccessible::ProcessDOMEvent(nsIDOMEvent* aDOMEvent) { MOZ_ASSERT(aDOMEvent); Event* event = aDOMEvent->InternalDOMEvent(); nsCOMPtr<nsINode> origTargetNode = do_QueryInterface(event->GetOriginalTarget()); nsAutoString eventType; aDOMEvent->GetType(eventType); #ifdef A11Y_LOG if (logging::IsEnabled(logging::eDOMEvents)) logging::DOMEvent("processed", origTargetNode, eventType); #endif if (eventType.EqualsLiteral("popuphiding")) { HandlePopupHidingEvent(origTargetNode); return; } DocAccessible* targetDocument = GetAccService()-> GetDocAccessible(origTargetNode->OwnerDoc()); NS_ASSERTION(targetDocument, "No document while accessible is in document?!"); Accessible* accessible = targetDocument->GetAccessibleOrContainer(origTargetNode); if (!accessible) return; #ifdef MOZ_XUL XULTreeAccessible* treeAcc = accessible->AsXULTree(); if (treeAcc) { if (eventType.EqualsLiteral("TreeRowCountChanged")) { HandleTreeRowCountChangedEvent(aDOMEvent, treeAcc); return; } if (eventType.EqualsLiteral("TreeInvalidated")) { HandleTreeInvalidatedEvent(aDOMEvent, treeAcc); return; } } #endif if (eventType.EqualsLiteral("RadioStateChange")) { uint64_t state = accessible->State(); bool isEnabled = (state & (states::CHECKED | states::SELECTED)) != 0; if (accessible->NeedsDOMUIEvent()) { nsRefPtr<AccEvent> accEvent = new AccStateChangeEvent(accessible, states::CHECKED, isEnabled); nsEventShell::FireEvent(accEvent); } if (isEnabled) { FocusMgr()->ActiveItemChanged(accessible); #ifdef A11Y_LOG if (logging::IsEnabled(logging::eFocus)) logging::ActiveItemChangeCausedBy("RadioStateChange", accessible); #endif } return; } if (eventType.EqualsLiteral("CheckboxStateChange")) { if (accessible->NeedsDOMUIEvent()) { uint64_t state = accessible->State(); bool isEnabled = !!(state & states::CHECKED); nsRefPtr<AccEvent> accEvent = new AccStateChangeEvent(accessible, states::CHECKED, isEnabled); nsEventShell::FireEvent(accEvent); } return; } Accessible* treeItemAcc = nullptr; #ifdef MOZ_XUL // If it's a tree element, need the currently selected item. if (treeAcc) { treeItemAcc = accessible->CurrentItem(); if (treeItemAcc) accessible = treeItemAcc; } if (treeItemAcc && eventType.EqualsLiteral("OpenStateChange")) { uint64_t state = accessible->State(); bool isEnabled = (state & states::EXPANDED) != 0; nsRefPtr<AccEvent> accEvent = new AccStateChangeEvent(accessible, states::EXPANDED, isEnabled); nsEventShell::FireEvent(accEvent); return; } nsINode* targetNode = accessible->GetNode(); if (treeItemAcc && eventType.EqualsLiteral("select")) { // XXX: We shouldn't be based on DOM select event which doesn't provide us // any context info. We should integrate into nsTreeSelection instead. // If multiselect tree, we should fire selectionadd or selection removed if (FocusMgr()->HasDOMFocus(targetNode)) { nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSel = do_QueryInterface(targetNode); nsAutoString selType; multiSel->GetSelType(selType); if (selType.IsEmpty() || !selType.EqualsLiteral("single")) { // XXX: We need to fire EVENT_SELECTION_ADD and EVENT_SELECTION_REMOVE // for each tree item. Perhaps each tree item will need to cache its // selection state and fire an event after a DOM "select" event when // that state changes. XULTreeAccessible::UpdateTreeSelection(); nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SELECTION_WITHIN, accessible); return; } nsRefPtr<AccSelChangeEvent> selChangeEvent = new AccSelChangeEvent(treeAcc, treeItemAcc, AccSelChangeEvent::eSelectionAdd); nsEventShell::FireEvent(selChangeEvent); return; } } else #endif if (eventType.EqualsLiteral("AlertActive")) { nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_ALERT, accessible); } else if (eventType.EqualsLiteral("popupshown")) { HandlePopupShownEvent(accessible); } else if (eventType.EqualsLiteral("DOMMenuInactive")) { if (accessible->Role() == roles::MENUPOPUP) { nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END, accessible); } } else if (eventType.EqualsLiteral("DOMMenuItemActive")) { FocusMgr()->ActiveItemChanged(accessible); #ifdef A11Y_LOG if (logging::IsEnabled(logging::eFocus)) logging::ActiveItemChangeCausedBy("DOMMenuItemActive", accessible); #endif } else if (eventType.EqualsLiteral("DOMMenuItemInactive")) { // Process DOMMenuItemInactive event for autocomplete only because this is // unique widget that may acquire focus from autocomplete popup while popup // stays open and has no active item. In case of XUL tree autocomplete // popup this event is fired for tree accessible. Accessible* widget = accessible->IsWidget() ? accessible : accessible->ContainerWidget(); if (widget && widget->IsAutoCompletePopup()) { FocusMgr()->ActiveItemChanged(nullptr); #ifdef A11Y_LOG if (logging::IsEnabled(logging::eFocus)) logging::ActiveItemChangeCausedBy("DOMMenuItemInactive", accessible); #endif } } else if (eventType.EqualsLiteral("DOMMenuBarActive")) { // Always from user input nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENU_START, accessible, eFromUserInput); // Notify of active item change when menubar gets active and if it has // current item. This is a case of mouseover (set current menuitem) and // mouse click (activate the menubar). If menubar doesn't have current item // (can be a case of menubar activation from keyboard) then ignore this // notification because later we'll receive DOMMenuItemActive event after // current menuitem is set. Accessible* activeItem = accessible->CurrentItem(); if (activeItem) { FocusMgr()->ActiveItemChanged(activeItem); #ifdef A11Y_LOG if (logging::IsEnabled(logging::eFocus)) logging::ActiveItemChangeCausedBy("DOMMenuBarActive", accessible); #endif } } else if (eventType.EqualsLiteral("DOMMenuBarInactive")) { // Always from user input nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENU_END, accessible, eFromUserInput); FocusMgr()->ActiveItemChanged(nullptr); #ifdef A11Y_LOG if (logging::IsEnabled(logging::eFocus)) logging::ActiveItemChangeCausedBy("DOMMenuBarInactive", accessible); #endif } else if (accessible->NeedsDOMUIEvent() && eventType.EqualsLiteral("ValueChange")) { targetDocument->FireDelayedEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, accessible); } #ifdef DEBUG_DRAGDROPSTART else if (eventType.EqualsLiteral("mouseover")) { nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_DRAGDROP_START, accessible); } #endif }
// RootAccessible protected void RootAccessible::ProcessDOMEvent(nsIDOMEvent* aDOMEvent) { nsCOMPtr<nsIDOMNSEvent> DOMNSEvent(do_QueryInterface(aDOMEvent)); nsCOMPtr<nsIDOMEventTarget> DOMEventTarget; DOMNSEvent->GetOriginalTarget(getter_AddRefs(DOMEventTarget)); nsCOMPtr<nsINode> origTargetNode(do_QueryInterface(DOMEventTarget)); nsAutoString eventType; aDOMEvent->GetType(eventType); if (eventType.EqualsLiteral("popuphiding")) { HandlePopupHidingEvent(origTargetNode); return; } DocAccessible* targetDocument = GetAccService()-> GetDocAccessible(origTargetNode->OwnerDoc()); NS_ASSERTION(targetDocument, "No document while accessible is in document?!"); Accessible* accessible = targetDocument->GetAccessibleOrContainer(origTargetNode); if (!accessible) return; nsINode* targetNode = accessible->GetNode(); #ifdef MOZ_XUL XULTreeAccessible* treeAcc = accessible->AsXULTree(); if (treeAcc) { if (eventType.EqualsLiteral("TreeRowCountChanged")) { HandleTreeRowCountChangedEvent(aDOMEvent, treeAcc); return; } if (eventType.EqualsLiteral("TreeInvalidated")) { HandleTreeInvalidatedEvent(aDOMEvent, treeAcc); return; } } #endif if (eventType.EqualsLiteral("RadioStateChange")) { PRUint64 state = accessible->State(); // radiogroup in prefWindow is exposed as a list, // and panebutton is exposed as XULListitem in A11y. // XULListitemAccessible::GetStateInternal uses STATE_SELECTED in this case, // so we need to check states::SELECTED also. bool isEnabled = (state & (states::CHECKED | states::SELECTED)) != 0; nsRefPtr<AccEvent> accEvent = new AccStateChangeEvent(accessible, states::CHECKED, isEnabled); nsEventShell::FireEvent(accEvent); if (isEnabled) { FocusMgr()->ActiveItemChanged(accessible); A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE("RadioStateChange", accessible) } return; }