예제 #1
0
nsresult
AccessibleWrap::FireAtkTextChangedEvent(AccEvent* aEvent,
                                        AtkObject* aObject)
{
    AccTextChangeEvent* event = downcast_accEvent(aEvent);
    NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);

    int32_t start = event->GetStartOffset();
    uint32_t length = event->GetLength();
    bool isInserted = event->IsTextInserted();
    bool isFromUserInput = aEvent->IsFromUserInput();

  if (gAvailableAtkSignals == eUnknown)
    gAvailableAtkSignals =
      g_signal_lookup("text-insert", G_OBJECT_TYPE(aObject)) ?
        eHaveNewAtkTextSignals : eNoNewAtkSignals;

  if (gAvailableAtkSignals == eNoNewAtkSignals) {
    // XXX remove this code and the gHaveNewTextSignals check when we can
    // stop supporting old atk since it doesn't really work anyway
    // see bug 619002
    const char* signal_name =
      oldTextChangeStrings[isFromUserInput][isInserted];
    g_signal_emit_by_name(aObject, signal_name, start, length);
  } else {
    nsAutoString text;
    event->GetModifiedText(text);
    const char* signal_name =
      textChangedStrings[isFromUserInput][isInserted];
    g_signal_emit_by_name(aObject, signal_name, start, length,
                          NS_ConvertUTF16toUTF8(text).get());
  }

  return NS_OK;
}
예제 #2
0
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();
  }
예제 #3
0
nsresult
HyperTextAccessibleWrap::HandleAccEvent(AccEvent* aEvent)
{
  uint32_t eventType = aEvent->GetEventType();

  if (eventType == nsIAccessibleEvent::EVENT_TEXT_REMOVED ||
      eventType == nsIAccessibleEvent::EVENT_TEXT_INSERTED) {
    Accessible* accessible = aEvent->GetAccessible();
    if (accessible && accessible->IsHyperText()) {
      AccTextChangeEvent* event = downcast_accEvent(aEvent);
        HyperTextAccessibleWrap* text =
          static_cast<HyperTextAccessibleWrap*>(accessible->AsHyperText());
      ia2AccessibleText::UpdateTextChangeData(text, event->IsTextInserted(),
                                              event->ModifiedText(),
                                              event->GetStartOffset(),
                                              event->GetLength());
    }
  }

  return HyperTextAccessible::HandleAccEvent(aEvent);
}
예제 #4
0
nsresult
AccessibleWrap::FireAtkTextChangedEvent(AccEvent* aEvent,
                                        AtkObject* aObject)
{
    MAI_LOG_DEBUG(("\n\nReceived: EVENT_TEXT_REMOVED/INSERTED\n"));

    AccTextChangeEvent* event = downcast_accEvent(aEvent);
    NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);

    PRInt32 start = event->GetStartOffset();
    PRUint32 length = event->GetLength();
    bool isInserted = event->IsTextInserted();
    bool isFromUserInput = aEvent->IsFromUserInput();
    char* signal_name = nsnull;

  if (gAvailableAtkSignals == eUnknown)
    gAvailableAtkSignals =
      g_signal_lookup("text-insert", G_OBJECT_TYPE(aObject)) ?
        eHaveNewAtkTextSignals : eNoNewAtkSignals;

  if (gAvailableAtkSignals == eNoNewAtkSignals) {
    // XXX remove this code and the gHaveNewTextSignals check when we can
    // stop supporting old atk since it doesn't really work anyway
    // see bug 619002
    signal_name = g_strconcat(isInserted ? "text_changed::insert" :
                              "text_changed::delete",
                              isFromUserInput ? "" : kNonUserInputEvent, NULL);
    g_signal_emit_by_name(aObject, signal_name, start, length);
  } else {
    nsAutoString text;
    event->GetModifiedText(text);
    signal_name = g_strconcat(isInserted ? "text-insert" : "text-remove",
                              isFromUserInput ? "" : "::system", NULL);
    g_signal_emit_by_name(aObject, signal_name, start, length,
                          NS_ConvertUTF16toUTF8(text).get());
  }

  g_free(signal_name);
  return NS_OK;
}
void
EventQueue::CoalesceTextChangeEventsFor(AccHideEvent* aTailEvent,
                                        AccHideEvent* aThisEvent)
{
    // XXX: we need a way to ignore SplitNode and JoinNode() when they do not
    // affect the text within the hypertext.

    AccTextChangeEvent* textEvent = aThisEvent->mTextChangeEvent;
    if (!textEvent)
        return;

    if (aThisEvent->mNextSibling == aTailEvent->mAccessible) {
        aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText);

    } else if (aThisEvent->mPrevSibling == aTailEvent->mAccessible) {
        uint32_t oldLen = textEvent->GetLength();
        aTailEvent->mAccessible->AppendTextTo(textEvent->mModifiedText);
        textEvent->mStart -= textEvent->GetLength() - oldLen;
    }

    aTailEvent->mTextChangeEvent.swap(aThisEvent->mTextChangeEvent);
}
예제 #6
0
nsresult
nsAccessibleWrap::FireAtkTextChangedEvent(AccEvent* aEvent,
                                          AtkObject *aObject)
{
    MAI_LOG_DEBUG(("\n\nReceived: EVENT_TEXT_REMOVED/INSERTED\n"));

    AccTextChangeEvent* event = downcast_accEvent(aEvent);
    NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);

    PRInt32 start = event->GetStartOffset();
    PRUint32 length = event->GetLength();
    PRBool isInserted = event->IsTextInserted();

    PRBool isFromUserInput = aEvent->IsFromUserInput();

    char *signal_name = g_strconcat(isInserted ? "text_changed::insert" : "text_changed::delete",
                                    isFromUserInput ? "" : kNonUserInputEvent, NULL);
    g_signal_emit_by_name(aObject, signal_name, start, length);
    g_free (signal_name);

    return NS_OK;
}
예제 #7
0
nsresult
HyperTextAccessibleWrap::HandleAccEvent(AccEvent* aEvent)
{
    uint32_t eventType = aEvent->GetEventType();

    if (eventType == nsIAccessibleEvent::EVENT_TEXT_REMOVED ||
            eventType == nsIAccessibleEvent::EVENT_TEXT_INSERTED) {
        Accessible* accessible = aEvent->GetAccessible();
        if (accessible && accessible->IsHyperText()) {
            sLastTextChangeAcc = accessible;
            if (!sLastTextChangeString)
                sLastTextChangeString = new nsString();

            AccTextChangeEvent* event = downcast_accEvent(aEvent);
            event->GetModifiedText(*sLastTextChangeString);
            sLastTextChangeStart = event->GetStartOffset();
            sLastTextChangeEnd = sLastTextChangeStart + event->GetLength();
            sLastTextChangeWasInsert = event->IsTextInserted();
        }
    }

    return HyperTextAccessible::HandleAccEvent(aEvent);
}
예제 #8
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;
}
예제 #9
0
void
EventTree::Mutated(AccMutationEvent* aEv)
{
  // If shown or hidden node is a root of previously mutated subtree, then
  // discard those subtree mutations as we are no longer interested in them.
  UniquePtr<EventTree>* node = &mFirst;
  while (*node) {
    if ((*node)->mContainer == aEv->mAccessible) {
      *node = Move((*node)->mNext);
      break;
    }
    node = &(*node)->mNext;
  }

  AccMutationEvent* prevEvent = mDependentEvents.SafeLastElement(nullptr);
  mDependentEvents.AppendElement(aEv);

  // Coalesce text change events from this hide/show event and the previous one.
  if (prevEvent && aEv->mEventType == prevEvent->mEventType) {
    if (aEv->IsHide()) {
      // XXX: we need a way to ignore SplitNode and JoinNode() when they do not
      // affect the text within the hypertext.
      AccTextChangeEvent* prevTextEvent = prevEvent->mTextChangeEvent;
      if (prevTextEvent) {
        AccHideEvent* hideEvent = downcast_accEvent(aEv);
        AccHideEvent* prevHideEvent = downcast_accEvent(prevEvent);

        if (prevHideEvent->mNextSibling == hideEvent->mAccessible) {
          hideEvent->mAccessible->AppendTextTo(prevTextEvent->mModifiedText);
        }
        else if (prevHideEvent->mPrevSibling == hideEvent->mAccessible) {
          uint32_t oldLen = prevTextEvent->GetLength();
          hideEvent->mAccessible->AppendTextTo(prevTextEvent->mModifiedText);
          prevTextEvent->mStart -= prevTextEvent->GetLength() - oldLen;
        }

        hideEvent->mTextChangeEvent.swap(prevEvent->mTextChangeEvent);
      }
    }
    else {
      AccTextChangeEvent* prevTextEvent = prevEvent->mTextChangeEvent;
      if (prevTextEvent) {
        if (aEv->mAccessible->IndexInParent() ==
            prevEvent->mAccessible->IndexInParent() + 1) {
          // If tail target was inserted after this target, i.e. tail target is next
          // sibling of this target.
          aEv->mAccessible->AppendTextTo(prevTextEvent->mModifiedText);
        }
        else if (aEv->mAccessible->IndexInParent() ==
                 prevEvent->mAccessible->IndexInParent() - 1) {
          // If tail target was inserted before this target, i.e. tail target is
          // previous sibling of this target.
          nsAutoString startText;
          aEv->mAccessible->AppendTextTo(startText);
          prevTextEvent->mModifiedText = startText + prevTextEvent->mModifiedText;
          prevTextEvent->mStart -= startText.Length();
        }

        aEv->mTextChangeEvent.swap(prevEvent->mTextChangeEvent);
      }
    }
  }

  // Create a text change event caused by this hide/show event. When a node is
  // hidden/removed or shown/appended, the text in an ancestor hyper text will
  // lose or get new characters.
  if (aEv->mTextChangeEvent || !mContainer->IsHyperText()) {
    return;
  }

  nsAutoString text;
  aEv->mAccessible->AppendTextTo(text);
  if (text.IsEmpty()) {
    return;
  }

  int32_t offset = mContainer->AsHyperText()->GetChildOffset(aEv->mAccessible);
  aEv->mTextChangeEvent =
    new AccTextChangeEvent(mContainer, offset, text, aEv->IsShow(),
                           aEv->mIsFromUserInput ? eFromUserInput : eNoUserInput);
}
예제 #10
0
void
EventTree::Mutated(AccMutationEvent* aEv)
{
  // If shown or hidden node is a root of previously mutated subtree, then
  // discard those subtree mutations as we are no longer interested in them.
  UniquePtr<EventTree>* node = &mFirst;
  while (*node) {
    Accessible* cntr = (*node)->mContainer;
    while (cntr != mContainer) {
      if (cntr == aEv->mAccessible) {
#ifdef A11Y_LOG
        if (logging::IsEnabled(logging::eEventTree)) {
          logging::MsgBegin("EVENTS_TREE", "Trim subtree");
          logging::AccessibleInfo("Show/hide container", aEv->mAccessible);
          logging::AccessibleInfo("Trimmed subtree root", (*node)->mContainer);
          logging::MsgEnd();
        }
#endif

        // If the new hide is part of a move and it contains existing child
        // shows, then move preceding events from the child shows to the buffer,
        // so the ongoing show event will pick them up.
        if (aEv->IsHide()) {
          AccHideEvent* hideEv = downcast_accEvent(aEv);
          if (!hideEv->mNeedsShutdown) {
            for (uint32_t i = 0; i < (*node)->mDependentEvents.Length(); i++) {
              AccMutationEvent* childEv = (*node)->mDependentEvents[i];
              if (childEv->IsShow()) {
                AccShowEvent* childShowEv = downcast_accEvent(childEv);
                if (childShowEv->mPrecedingEvents.Length() > 0) {
                  Controller(mContainer)->StorePrecedingEvents(
                    mozilla::Move(childShowEv->mPrecedingEvents));
                }
              }
            }
          }
        }
        // If the new show contains existing child shows, then move preceding
        // events from the child shows to the new show.
        else if (aEv->IsShow()) {
          AccShowEvent* showEv = downcast_accEvent(aEv);
          for (uint32_t i = 0; (*node)->mDependentEvents.Length(); i++) {
            AccMutationEvent* childEv = (*node)->mDependentEvents[i];
            if (childEv->IsShow()) {
              AccShowEvent* showChildEv = downcast_accEvent(childEv);
              if (showChildEv->mPrecedingEvents.Length() > 0) {
#ifdef A11Y_LOG
                if (logging::IsEnabled(logging::eEventTree)) {
                  logging::MsgBegin("EVENTS_TREE", "Adopt preceding events");
                  logging::AccessibleInfo("Parent", aEv->mAccessible);
                  for (uint32_t j = 0; j < showChildEv->mPrecedingEvents.Length(); j++) {
                    logging::AccessibleInfo("Adoptee",
                      showChildEv->mPrecedingEvents[i]->mAccessible);
                  }
                  logging::MsgEnd();
                }
#endif
                showEv->mPrecedingEvents.AppendElements(showChildEv->mPrecedingEvents);
              }
            }
          }
        }

        *node = Move((*node)->mNext);
        break;
      }
      cntr = cntr->Parent();
    }
    if (cntr == aEv->mAccessible) {
      continue;
    }
    node = &(*node)->mNext;
  }

  AccMutationEvent* prevEvent = mDependentEvents.SafeLastElement(nullptr);
  mDependentEvents.AppendElement(aEv);

  // Coalesce text change events from this hide/show event and the previous one.
  if (prevEvent && aEv->mEventType == prevEvent->mEventType) {
    if (aEv->IsHide()) {
      // XXX: we need a way to ignore SplitNode and JoinNode() when they do not
      // affect the text within the hypertext.
      AccTextChangeEvent* prevTextEvent = prevEvent->mTextChangeEvent;
      if (prevTextEvent) {
        AccHideEvent* hideEvent = downcast_accEvent(aEv);
        AccHideEvent* prevHideEvent = downcast_accEvent(prevEvent);

        if (prevHideEvent->mNextSibling == hideEvent->mAccessible) {
          hideEvent->mAccessible->AppendTextTo(prevTextEvent->mModifiedText);
        }
        else if (prevHideEvent->mPrevSibling == hideEvent->mAccessible) {
          uint32_t oldLen = prevTextEvent->GetLength();
          hideEvent->mAccessible->AppendTextTo(prevTextEvent->mModifiedText);
          prevTextEvent->mStart -= prevTextEvent->GetLength() - oldLen;
        }

        hideEvent->mTextChangeEvent.swap(prevEvent->mTextChangeEvent);
      }
    }
    else {
      AccTextChangeEvent* prevTextEvent = prevEvent->mTextChangeEvent;
      if (prevTextEvent) {
        if (aEv->mAccessible->IndexInParent() ==
            prevEvent->mAccessible->IndexInParent() + 1) {
          // If tail target was inserted after this target, i.e. tail target is next
          // sibling of this target.
          aEv->mAccessible->AppendTextTo(prevTextEvent->mModifiedText);
        }
        else if (aEv->mAccessible->IndexInParent() ==
                 prevEvent->mAccessible->IndexInParent() - 1) {
          // If tail target was inserted before this target, i.e. tail target is
          // previous sibling of this target.
          nsAutoString startText;
          aEv->mAccessible->AppendTextTo(startText);
          prevTextEvent->mModifiedText = startText + prevTextEvent->mModifiedText;
          prevTextEvent->mStart -= startText.Length();
        }

        aEv->mTextChangeEvent.swap(prevEvent->mTextChangeEvent);
      }
    }
  }

  // Create a text change event caused by this hide/show event. When a node is
  // hidden/removed or shown/appended, the text in an ancestor hyper text will
  // lose or get new characters.
  if (aEv->mTextChangeEvent || !mContainer->IsHyperText()) {
    return;
  }

  nsAutoString text;
  aEv->mAccessible->AppendTextTo(text);
  if (text.IsEmpty()) {
    return;
  }

  int32_t offset = mContainer->AsHyperText()->GetChildOffset(aEv->mAccessible);
  aEv->mTextChangeEvent =
    new AccTextChangeEvent(mContainer, offset, text, aEv->IsShow(),
                           aEv->mIsFromUserInput ? eFromUserInput : eNoUserInput);
}