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(); }
nsresult AccessibleWrap::HandleAccEvent(AccEvent* aEvent) { auto accessible = static_cast<AccessibleWrap*>(aEvent->GetAccessible()); NS_ENSURE_TRUE(accessible, NS_ERROR_FAILURE); DocAccessibleWrap* doc = static_cast<DocAccessibleWrap*>(accessible->Document()); if (doc) { switch (aEvent->GetEventType()) { case nsIAccessibleEvent::EVENT_FOCUS: { if (DocAccessibleWrap* topContentDoc = doc->GetTopLevelContentDoc(accessible)) { topContentDoc->CacheFocusPath(accessible); } break; } case nsIAccessibleEvent::EVENT_VIRTUALCURSOR_CHANGED: { AccVCChangeEvent* vcEvent = downcast_accEvent(aEvent); auto newPosition = static_cast<AccessibleWrap*>(vcEvent->NewAccessible()); if (newPosition) { if (DocAccessibleWrap* topContentDoc = doc->GetTopLevelContentDoc(accessible)) { topContentDoc->CacheFocusPath(newPosition); } } break; } } } nsresult rv = Accessible::HandleAccEvent(aEvent); NS_ENSURE_SUCCESS(rv, rv); if (IPCAccessibilityActive()) { return NS_OK; } // The accessible can become defunct if we have an xpcom event listener // which decides it would be fun to change the DOM and flush layout. if (accessible->IsDefunct() || !accessible->IsBoundToParent()) { return NS_OK; } if (doc) { if (!nsCoreUtils::IsContentDocument(doc->DocumentNode())) { return NS_OK; } } SessionAccessibility* sessionAcc = SessionAccessibility::GetInstanceFor(accessible); if (!sessionAcc) { return NS_OK; } switch (aEvent->GetEventType()) { case nsIAccessibleEvent::EVENT_FOCUS: sessionAcc->SendFocusEvent(accessible); break; case nsIAccessibleEvent::EVENT_VIRTUALCURSOR_CHANGED: { AccVCChangeEvent* vcEvent = downcast_accEvent(aEvent); auto newPosition = static_cast<AccessibleWrap*>(vcEvent->NewAccessible()); auto oldPosition = static_cast<AccessibleWrap*>(vcEvent->OldAccessible()); if (sessionAcc && newPosition) { if (oldPosition != newPosition) { if (vcEvent->Reason() == nsIAccessiblePivot::REASON_POINT) { sessionAcc->SendHoverEnterEvent(newPosition); } else { sessionAcc->SendAccessibilityFocusedEvent(newPosition); } } if (vcEvent->BoundaryType() != nsIAccessiblePivot::NO_BOUNDARY) { sessionAcc->SendTextTraversedEvent( newPosition, vcEvent->NewStartOffset(), vcEvent->NewEndOffset()); } } break; } case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED: { AccCaretMoveEvent* event = downcast_accEvent(aEvent); sessionAcc->SendTextSelectionChangedEvent(accessible, event->GetCaretOffset()); break; } case nsIAccessibleEvent::EVENT_TEXT_INSERTED: case nsIAccessibleEvent::EVENT_TEXT_REMOVED: { AccTextChangeEvent* event = downcast_accEvent(aEvent); sessionAcc->SendTextChangedEvent( accessible, event->ModifiedText(), event->GetStartOffset(), event->GetLength(), event->IsTextInserted(), event->IsFromUserInput()); break; } case nsIAccessibleEvent::EVENT_STATE_CHANGE: { AccStateChangeEvent* event = downcast_accEvent(aEvent); auto state = event->GetState(); if (state & states::CHECKED) { sessionAcc->SendClickedEvent(accessible, event->IsStateEnabled()); } if (state & states::SELECTED) { sessionAcc->SendSelectedEvent(accessible, event->IsStateEnabled()); } if (state & states::BUSY) { sessionAcc->SendWindowStateChangedEvent(accessible); } break; } case nsIAccessibleEvent::EVENT_SCROLLING: { AccScrollingEvent* event = downcast_accEvent(aEvent); sessionAcc->SendScrollingEvent(accessible, event->ScrollX(), event->ScrollY(), event->MaxScrollX(), event->MaxScrollY()); break; } case nsIAccessibleEvent::EVENT_SHOW: case nsIAccessibleEvent::EVENT_HIDE: { AccMutationEvent* event = downcast_accEvent(aEvent); auto parent = static_cast<AccessibleWrap*>(event->Parent()); sessionAcc->SendWindowContentChangedEvent(parent); break; } default: break; } return NS_OK; }