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();
  }
Exemple #2
0
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;
}