Commit 811b36eb authored by Phil Ringnalda's avatar Phil Ringnalda
Browse files

Merge m-c to b-i

CLOSED TREE
parents 7d1df404 9e2ec4ca
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -16,6 +16,10 @@
using namespace mozilla;
using namespace mozilla::a11y;

static_assert(static_cast<bool>(eNoUserInput) == false &&
              static_cast<bool>(eFromUserInput) == true,
              "EIsFromUserInput cannot be casted to bool");

////////////////////////////////////////////////////////////////////////////////
// AccEvent
////////////////////////////////////////////////////////////////////////////////
@@ -117,6 +121,18 @@ AccShowEvent::
}


////////////////////////////////////////////////////////////////////////////////
// AccTextSelChangeEvent
////////////////////////////////////////////////////////////////////////////////

AccTextSelChangeEvent::AccTextSelChangeEvent(HyperTextAccessible* aTarget,
                                             nsISelection* aSelection) :
  AccEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED, aTarget,
           eAutoDetect, eCoalesceTextSelChange),
  mSel(aSelection) {}

AccTextSelChangeEvent::~AccTextSelChangeEvent() { }

////////////////////////////////////////////////////////////////////////////////
// AccSelChangeEvent
////////////////////////////////////////////////////////////////////////////////
+35 −3
Original line number Diff line number Diff line
@@ -10,6 +10,8 @@

#include "mozilla/a11y/Accessible.h"

class nsISelection;

namespace mozilla {
namespace a11y {

@@ -59,6 +61,9 @@ public:
    // eCoalesceStateChange: coalesce state change events.
    eCoalesceStateChange,

    // eCoalesceTextSelChange: coalescence of text selection change events.
    eCoalesceTextSelChange,

     // eRemoveDupes : For repeat events, only the newest event in queue
     //    will be emitted.
    eRemoveDupes,
@@ -77,6 +82,8 @@ public:
  uint32_t GetEventType() const { return mEventType; }
  EEventRule GetEventRule() const { return mEventRule; }
  bool IsFromUserInput() const { return mIsFromUserInput; }
  EIsFromUserInput FromUserInput() const
    { return static_cast<EIsFromUserInput>(mIsFromUserInput); }

  Accessible* GetAccessible() const { return mAccessible; }
  DocAccessible* GetDocAccessible() const { return mAccessible->Document(); }
@@ -93,6 +100,7 @@ public:
    eHideEvent,
    eShowEvent,
    eCaretMoveEvent,
    eTextSelChangeEvent,
    eSelectionChangeEvent,
    eTableChangeEvent,
    eVirtualCursorChangeEvent
@@ -330,9 +338,11 @@ protected:
class AccCaretMoveEvent: public AccEvent
{
public:
  AccCaretMoveEvent(Accessible* aAccessible) :
    AccEvent(::nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED, aAccessible),
    mCaretOffset(-1) { }
  AccCaretMoveEvent(Accessible* aAccessible, int32_t aCaretOffset,
                    EIsFromUserInput aIsFromUserInput = eAutoDetect) :
    AccEvent(::nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED, aAccessible,
             aIsFromUserInput),
    mCaretOffset(aCaretOffset) { }
  virtual ~AccCaretMoveEvent() { }

  // AccEvent
@@ -347,8 +357,30 @@ public:

private:
  int32_t mCaretOffset;
};


/**
 * Accessible text selection change event.
 */
class AccTextSelChangeEvent : public AccEvent
{
public:
  AccTextSelChangeEvent(HyperTextAccessible* aTarget, nsISelection* aSelection);
  virtual ~AccTextSelChangeEvent();

  // AccEvent
  static const EventGroup kEventGroup = eTextSelChangeEvent;
  virtual unsigned int GetEventGroups() const
  {
    return AccEvent::GetEventGroups() | (1U << eTextSelChangeEvent);
  }

private:
  nsCOMPtr<nsISelection> mSel;

  friend class EventQueue;
  friend class SelectionManager;
};


+22 −15
Original line number Diff line number Diff line
@@ -152,6 +152,26 @@ EventQueue::CoalesceEvents()
      break; // eCoalesceStateChange
    }

    case AccEvent::eCoalesceTextSelChange:
    {
      // Coalesce older event by newer event for the same selection or target.
      // Events for same selection may have different targets and vice versa one
      // target may be pointed by different selections (for latter see
      // bug 927159).
      for (uint32_t index = tail - 1; index < tail; index--) {
        AccEvent* thisEvent = mEvents[index];
        if (thisEvent->mEventRule != AccEvent::eDoNotEmit &&
            thisEvent->mEventType == tailEvent->mEventType) {
          AccTextSelChangeEvent* thisTSCEvent = downcast_accEvent(thisEvent);
          AccTextSelChangeEvent* tailTSCEvent = downcast_accEvent(tailEvent);
          if (thisTSCEvent->mSel == tailTSCEvent->mSel ||
              thisEvent->mAccessible == tailEvent->mAccessible)
            thisEvent->mEventRule = AccEvent::eDoNotEmit;
        }

      }
    } break; // eCoalesceTextSelChange

    case AccEvent::eRemoveDupes:
    {
      // Check for repeat events, coalesce newly appended event by more older
@@ -458,21 +478,8 @@ EventQueue::ProcessEventQueue()
      }

      // Dispatch caret moved and text selection change events.
      if (event->mEventType == nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED) {
        AccCaretMoveEvent* caretMoveEvent = downcast_accEvent(event);
        HyperTextAccessible* hyperText = target->AsHyperText();
        if (hyperText &&
            NS_SUCCEEDED(hyperText->GetCaretOffset(&caretMoveEvent->mCaretOffset))) {

          nsEventShell::FireEvent(caretMoveEvent);

          // There's a selection so fire selection change as well.
          int32_t selectionCount;
          hyperText->GetSelectionCount(&selectionCount);
          if (selectionCount)
            nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED,
                                    hyperText);
        }
      if (event->mEventType == nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED) {
        SelectionMgr()->ProcessTextSelChangeEvent(event);
        continue;
      }

+5 −8
Original line number Diff line number Diff line
@@ -265,9 +265,6 @@ FocusManager::ProcessFocusEvent(AccEvent* aEvent)
  NS_PRECONDITION(aEvent->GetEventType() == nsIAccessibleEvent::EVENT_FOCUS,
                  "Focus event is expected!");

  EIsFromUserInput fromUserInputFlag = aEvent->IsFromUserInput() ?
    eFromUserInput : eNoUserInput;

  // Emit focus event if event target is the active item. Otherwise then check
  // if it's still focused and then update active item and emit focus event.
  Accessible* target = aEvent->GetAccessible();
@@ -299,7 +296,7 @@ FocusManager::ProcessFocusEvent(AccEvent* aEvent)
      if (mActiveARIAMenubar) {
        nsRefPtr<AccEvent> menuEndEvent =
          new AccEvent(nsIAccessibleEvent::EVENT_MENU_END, mActiveARIAMenubar,
                       fromUserInputFlag);
                       aEvent->FromUserInput());
        nsEventShell::FireEvent(menuEndEvent);
      }

@@ -309,7 +306,7 @@ FocusManager::ProcessFocusEvent(AccEvent* aEvent)
      if (mActiveARIAMenubar) {
        nsRefPtr<AccEvent> menuStartEvent =
          new AccEvent(nsIAccessibleEvent::EVENT_MENU_START,
                       mActiveARIAMenubar, fromUserInputFlag);
                       mActiveARIAMenubar, aEvent->FromUserInput());
        nsEventShell::FireEvent(menuStartEvent);
      }
    }
@@ -317,7 +314,7 @@ FocusManager::ProcessFocusEvent(AccEvent* aEvent)
    // Focus left a menu. Fire menu_end event.
    nsRefPtr<AccEvent> menuEndEvent =
      new AccEvent(nsIAccessibleEvent::EVENT_MENU_END, mActiveARIAMenubar,
                   fromUserInputFlag);
                   aEvent->FromUserInput());
    nsEventShell::FireEvent(menuEndEvent);

    mActiveARIAMenubar = nullptr;
@@ -329,7 +326,7 @@ FocusManager::ProcessFocusEvent(AccEvent* aEvent)
#endif

  nsRefPtr<AccEvent> focusEvent =
    new AccEvent(nsIAccessibleEvent::EVENT_FOCUS, target, fromUserInputFlag);
    new AccEvent(nsIAccessibleEvent::EVENT_FOCUS, target, aEvent->FromUserInput());
  nsEventShell::FireEvent(focusEvent);

  // Fire scrolling_start event when the document receives the focus if it has
@@ -342,7 +339,7 @@ FocusManager::ProcessFocusEvent(AccEvent* aEvent)
      // XXX: bug 625699, note in some cases the node could go away before we
      // we receive focus event, for example if the node is removed from DOM.
      nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SCROLLING_START,
                              anchorJump, fromUserInputFlag);
                              anchorJump, aEvent->FromUserInput());
    }
    targetDocument->SetAnchorJump(nullptr);
  }
+55 −130
Original line number Diff line number Diff line
@@ -9,12 +9,10 @@
#include "nsAccessibilityService.h"
#include "nsAccUtils.h"
#include "nsCoreUtils.h"
#include "nsIAccessibleEvent.h"
#include "nsEventShell.h"

#include "nsCaret.h"
#include "nsIAccessibleTypes.h"
#include "nsIDOMDocument.h"
#include "nsIFrame.h"
#include "nsIPresShell.h"
#include "nsISelectionPrivate.h"
#include "mozilla/Selection.h"
@@ -23,14 +21,6 @@
using namespace mozilla;
using namespace mozilla::a11y;

void
SelectionManager::Shutdown()
{
  ClearControlSelectionListener();
  mLastTextAccessible = nullptr;
  mLastUsedSelection = nullptr;
}

void
SelectionManager::ClearControlSelectionListener()
{
@@ -64,8 +54,6 @@ SelectionManager::SetControlSelectionListener(dom::Element* aFocusedElm)
  // the current focus.
  ClearControlSelectionListener();

  mLastTextAccessible = nullptr;

  mCurrCtrlFrame = aFocusedElm->GetPrimaryFrame();
  if (!mCurrCtrlFrame)
    return;
@@ -119,6 +107,37 @@ SelectionManager::RemoveDocSelectionListener(nsIPresShell* aPresShell)
  spellSel->RemoveSelectionListener(this);
}

void
SelectionManager::ProcessTextSelChangeEvent(AccEvent* aEvent)
{
  AccTextSelChangeEvent* event = downcast_accEvent(aEvent);
  Selection* sel = static_cast<Selection*>(event->mSel.get());

  // Fire selection change event if it's not pure caret-move selection change.
  if (sel->GetRangeCount() != 1 || !sel->IsCollapsed())
    nsEventShell::FireEvent(aEvent);

  // Fire caret move event if there's a caret in the selection.
  nsINode* caretCntrNode =
    nsCoreUtils::GetDOMNodeFromDOMPoint(sel->GetFocusNode(),
                                        sel->GetFocusOffset());
  if (!caretCntrNode)
    return;

  HyperTextAccessible* caretCntr = nsAccUtils::GetTextContainer(caretCntrNode);
  NS_ASSERTION(caretCntr,
               "No text container for focus while there's one for common ancestor?!");
  if (!caretCntr)
    return;

  int32_t caretOffset = -1;
  if (NS_SUCCEEDED(caretCntr->GetCaretOffset(&caretOffset)) && caretOffset != -1) {
    nsRefPtr<AccCaretMoveEvent> caretMoveEvent =
      new AccCaretMoveEvent(caretCntr, caretOffset, aEvent->FromUserInput());
    nsEventShell::FireEvent(caretMoveEvent);
  }
}

NS_IMETHODIMP
SelectionManager::NotifySelectionChanged(nsIDOMDocument* aDOMDocument,
                                         nsISelection* aSelection,
@@ -149,128 +168,34 @@ SelectionManager::NotifySelectionChanged(nsIDOMDocument* aDOMDocument,
void
SelectionManager::ProcessSelectionChanged(nsISelection* aSelection)
{
  nsCOMPtr<nsISelectionPrivate> privSel(do_QueryInterface(aSelection));

  int16_t type = 0;
  privSel->GetType(&type);

  if (type == nsISelectionController::SELECTION_NORMAL)
    NormalSelectionChanged(aSelection);

  else if (type == nsISelectionController::SELECTION_SPELLCHECK)
    SpellcheckSelectionChanged(aSelection);
}

void
SelectionManager::NormalSelectionChanged(nsISelection* aSelection)
{
  mLastUsedSelection = do_GetWeakReference(aSelection);

  int32_t rangeCount = 0;
  aSelection->GetRangeCount(&rangeCount);
  if (rangeCount == 0) {
    mLastTextAccessible = nullptr;
    return; // No selection
  }

  HyperTextAccessible* textAcc =
    nsAccUtils::GetTextAccessibleFromSelection(aSelection);
  if (!textAcc)
    return;

  int32_t caretOffset = -1;
  nsresult rv = textAcc->GetCaretOffset(&caretOffset);
  if (NS_FAILED(rv))
  Selection* selection = static_cast<Selection*>(aSelection);
  const nsRange* range = selection->GetAnchorFocusRange();
  nsINode* cntrNode = nullptr;
  if (range)
    cntrNode = range->GetCommonAncestor();
  if (!cntrNode) {
    cntrNode = selection->GetFrameSelection()->GetAncestorLimiter();
    if (!cntrNode) {
      cntrNode = selection->GetPresShell()->GetDocument();
      NS_ASSERTION(selection->GetPresShell()->ConstFrameSelection() == selection->GetFrameSelection(),
                   "Wrong selection container was used!");
    }
  }

  HyperTextAccessible* text = nsAccUtils::GetTextContainer(cntrNode);
  if (!text) {
    NS_NOTREACHED("We must reach document accessible implementing text interface!");
    return;

  if (textAcc == mLastTextAccessible && caretOffset == mLastCaretOffset) {
    int32_t selectionCount = 0;
    textAcc->GetSelectionCount(&selectionCount);   // Don't swallow similar events when selecting text
    if (!selectionCount)
      return;  // Swallow duplicate caret event
  }

  mLastCaretOffset = caretOffset;
  mLastTextAccessible = textAcc;
  if (selection->GetType() == nsISelectionController::SELECTION_NORMAL) {
    nsRefPtr<AccEvent> event = new AccTextSelChangeEvent(text, aSelection);
    text->Document()->FireDelayedEvent(event);

  nsRefPtr<AccEvent> event = new AccCaretMoveEvent(mLastTextAccessible);
  mLastTextAccessible->Document()->FireDelayedEvent(event);
  } else if (selection->GetType() == nsISelectionController::SELECTION_SPELLCHECK) {
    // XXX: fire an event for container accessible of the focus/anchor range
    // of the spelcheck selection.
    text->Document()->FireDelayedEvent(nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED,
                                       text);
  }

void
SelectionManager::SpellcheckSelectionChanged(nsISelection* aSelection)
{
  // XXX: fire an event for accessible of focus node of the selection. If
  // spellchecking is enabled then we will fire the number of events for
  // the same accessible for newly appended range of the selection (for every
  // misspelled word). If spellchecking is disabled (for example,
  // @spellcheck="false" on html:body) then we won't fire any event.

  HyperTextAccessible* hyperText =
    nsAccUtils::GetTextAccessibleFromSelection(aSelection);
  if (hyperText) {
    hyperText->Document()->
      FireDelayedEvent(nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED,
                       hyperText);
  }
}

nsIntRect
SelectionManager::GetCaretRect(nsIWidget** aWidget)
{
  nsIntRect caretRect;
  NS_ENSURE_TRUE(aWidget, caretRect);
  *aWidget = nullptr;

  if (!mLastTextAccessible) {
    return caretRect;    // Return empty rect
  }

  nsINode *lastNodeWithCaret = mLastTextAccessible->GetNode();
  NS_ENSURE_TRUE(lastNodeWithCaret, caretRect);

  nsIPresShell *presShell = nsCoreUtils::GetPresShellFor(lastNodeWithCaret);
  NS_ENSURE_TRUE(presShell, caretRect);

  nsRefPtr<nsCaret> caret = presShell->GetCaret();
  NS_ENSURE_TRUE(caret, caretRect);

  nsCOMPtr<nsISelection> caretSelection(do_QueryReferent(mLastUsedSelection));
  NS_ENSURE_TRUE(caretSelection, caretRect);
  
  bool isVisible;
  caret->GetCaretVisible(&isVisible);
  if (!isVisible) {
    return nsIntRect();  // Return empty rect
  }

  nsRect rect;
  nsIFrame* frame = caret->GetGeometry(caretSelection, &rect);
  if (!frame || rect.IsEmpty()) {
    return nsIntRect(); // Return empty rect
  }

  nsPoint offset;
  // Offset from widget origin to the frame origin, which includes chrome
  // on the widget.
  *aWidget = frame->GetNearestWidget(offset);
  NS_ENSURE_TRUE(*aWidget, nsIntRect());
  rect.MoveBy(offset);

  caretRect = rect.ToOutsidePixels(frame->PresContext()->AppUnitsPerDevPixel());
  // ((content screen origin) - (content offset in the widget)) = widget origin on the screen
  caretRect.MoveBy((*aWidget)->WidgetToScreenOffset() - (*aWidget)->GetClientOffset());

  // Correct for character size, so that caret always matches the size of the character
  // This is important for font size transitions, and is necessary because the Gecko caret uses the
  // previous character's size as the user moves forward in the text by character.
  int32_t charX, charY, charWidth, charHeight;
  if (NS_SUCCEEDED(mLastTextAccessible->GetCharacterExtents(mLastCaretOffset, &charX, &charY,
                                                            &charWidth, &charHeight,
                                                            nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE))) {
    caretRect.height -= charY - caretRect.y;
    caretRect.y = charY;
  }

  return caretRect;
}
Loading