Loading accessible/src/base/AccEvent.cpp +16 −0 Original line number Diff line number Diff line Loading @@ -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 //////////////////////////////////////////////////////////////////////////////// Loading Loading @@ -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 //////////////////////////////////////////////////////////////////////////////// Loading accessible/src/base/AccEvent.h +35 −3 Original line number Diff line number Diff line Loading @@ -10,6 +10,8 @@ #include "mozilla/a11y/Accessible.h" class nsISelection; namespace mozilla { namespace a11y { Loading Loading @@ -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, Loading @@ -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(); } Loading @@ -93,6 +100,7 @@ public: eHideEvent, eShowEvent, eCaretMoveEvent, eTextSelChangeEvent, eSelectionChangeEvent, eTableChangeEvent, eVirtualCursorChangeEvent Loading Loading @@ -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 Loading @@ -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; }; Loading accessible/src/base/EventQueue.cpp +22 −15 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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; } Loading accessible/src/base/FocusManager.cpp +5 −8 Original line number Diff line number Diff line Loading @@ -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(); Loading Loading @@ -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); } Loading @@ -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); } } Loading @@ -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; Loading @@ -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 Loading @@ -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); } Loading accessible/src/base/SelectionManager.cpp +55 −130 Original line number Diff line number Diff line Loading @@ -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" Loading @@ -23,14 +21,6 @@ using namespace mozilla; using namespace mozilla::a11y; void SelectionManager::Shutdown() { ClearControlSelectionListener(); mLastTextAccessible = nullptr; mLastUsedSelection = nullptr; } void SelectionManager::ClearControlSelectionListener() { Loading Loading @@ -64,8 +54,6 @@ SelectionManager::SetControlSelectionListener(dom::Element* aFocusedElm) // the current focus. ClearControlSelectionListener(); mLastTextAccessible = nullptr; mCurrCtrlFrame = aFocusedElm->GetPrimaryFrame(); if (!mCurrCtrlFrame) return; Loading Loading @@ -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, Loading Loading @@ -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
accessible/src/base/AccEvent.cpp +16 −0 Original line number Diff line number Diff line Loading @@ -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 //////////////////////////////////////////////////////////////////////////////// Loading Loading @@ -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 //////////////////////////////////////////////////////////////////////////////// Loading
accessible/src/base/AccEvent.h +35 −3 Original line number Diff line number Diff line Loading @@ -10,6 +10,8 @@ #include "mozilla/a11y/Accessible.h" class nsISelection; namespace mozilla { namespace a11y { Loading Loading @@ -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, Loading @@ -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(); } Loading @@ -93,6 +100,7 @@ public: eHideEvent, eShowEvent, eCaretMoveEvent, eTextSelChangeEvent, eSelectionChangeEvent, eTableChangeEvent, eVirtualCursorChangeEvent Loading Loading @@ -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 Loading @@ -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; }; Loading
accessible/src/base/EventQueue.cpp +22 −15 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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; } Loading
accessible/src/base/FocusManager.cpp +5 −8 Original line number Diff line number Diff line Loading @@ -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(); Loading Loading @@ -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); } Loading @@ -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); } } Loading @@ -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; Loading @@ -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 Loading @@ -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); } Loading
accessible/src/base/SelectionManager.cpp +55 −130 Original line number Diff line number Diff line Loading @@ -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" Loading @@ -23,14 +21,6 @@ using namespace mozilla; using namespace mozilla::a11y; void SelectionManager::Shutdown() { ClearControlSelectionListener(); mLastTextAccessible = nullptr; mLastUsedSelection = nullptr; } void SelectionManager::ClearControlSelectionListener() { Loading Loading @@ -64,8 +54,6 @@ SelectionManager::SetControlSelectionListener(dom::Element* aFocusedElm) // the current focus. ClearControlSelectionListener(); mLastTextAccessible = nullptr; mCurrCtrlFrame = aFocusedElm->GetPrimaryFrame(); if (!mCurrCtrlFrame) return; Loading Loading @@ -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, Loading Loading @@ -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; }