From 3f07ab58a46973ef03540d383c72429d23351130 Mon Sep 17 00:00:00 2001 From: Alexander Surkov Date: Tue, 1 Nov 2011 08:52:27 +0800 Subject: [PATCH] Bug 414302 - Incorrect selection events in HTML, XUL and ARIA, r=tbsaunde, f=marcoz --- accessible/public/nsIAccessibleEvent.idl | 17 +- accessible/src/atk/nsAccessibleWrap.cpp | 22 +- accessible/src/base/AccEvent.cpp | 22 ++ accessible/src/base/AccEvent.h | 33 ++- .../src/base/NotificationController.cpp | 104 ++++++++ accessible/src/base/NotificationController.h | 8 +- accessible/src/base/nsAccessibilityService.h | 3 +- accessible/src/base/nsDocAccessible.cpp | 50 ++-- accessible/src/base/nsRootAccessible.cpp | 2 + .../src/html/nsHTMLSelectAccessible.cpp | 86 ++---- accessible/src/html/nsHTMLSelectAccessible.h | 8 +- accessible/src/msaa/nsEventMap.h | 3 +- accessible/tests/mochitest/events.js | 2 + accessible/tests/mochitest/events/Makefile.in | 2 + .../mochitest/events/test_selection.html | 95 ++++--- .../tests/mochitest/events/test_selection.xul | 244 ++++++++++++++++++ .../mochitest/events/test_selection_aria.html | 112 ++++++++ 17 files changed, 663 insertions(+), 150 deletions(-) create mode 100644 accessible/tests/mochitest/events/test_selection.xul create mode 100644 accessible/tests/mochitest/events/test_selection_aria.html diff --git a/accessible/public/nsIAccessibleEvent.idl b/accessible/public/nsIAccessibleEvent.idl index e4eb0dfc27f6..7f609f8ae122 100644 --- a/accessible/public/nsIAccessibleEvent.idl +++ b/accessible/public/nsIAccessibleEvent.idl @@ -59,7 +59,7 @@ interface nsIDOMNode; * if (NS_SUCCEEDED(rv)) * rv = observerService->AddObserver(this, "accessible-event", PR_TRUE); */ -[scriptable, uuid(fd1378c5-c606-4a5e-a321-8e7fc107e5cf)] +[scriptable, uuid(7f66a33a-9ed7-4fd4-87a8-e431b0f43368)] interface nsIAccessibleEvent : nsISupports { /** @@ -280,7 +280,12 @@ interface nsIAccessibleEvent : nsISupports const unsigned long EVENT_DOCUMENT_CONTENT_CHANGED = 0x002B; const unsigned long EVENT_PROPERTY_CHANGED = 0x002C; - const unsigned long EVENT_SELECTION_CHANGED = 0x002D; + + /** + * A slide changed in a presentation document or a page boundary was + * crossed in a word processing document. + */ + const unsigned long EVENT_PAGE_CHANGED = 0x002D; /** * A text object's attributes changed. @@ -436,16 +441,10 @@ interface nsIAccessibleEvent : nsISupports */ const unsigned long EVENT_OBJECT_ATTRIBUTE_CHANGED = 0x0055; - /** - * A slide changed in a presentation document or a page boundary was - * crossed in a word processing document. - */ - const unsigned long EVENT_PAGE_CHANGED = 0x0056; - /** * Help make sure event map does not get out-of-line. */ - const unsigned long EVENT_LAST_ENTRY = 0x0057; + const unsigned long EVENT_LAST_ENTRY = 0x0056; /** * The type of event, based on the enumerated event values diff --git a/accessible/src/atk/nsAccessibleWrap.cpp b/accessible/src/atk/nsAccessibleWrap.cpp index 5956ddcb9b5b..c626ccf778e4 100644 --- a/accessible/src/atk/nsAccessibleWrap.cpp +++ b/accessible/src/atk/nsAccessibleWrap.cpp @@ -1089,10 +1089,24 @@ nsAccessibleWrap::FirePlatformEvent(AccEvent* aEvent) } } break; - case nsIAccessibleEvent::EVENT_SELECTION_CHANGED: - MAI_LOG_DEBUG(("\n\nReceived: EVENT_SELECTION_CHANGED\n")); - g_signal_emit_by_name(atkObj, "selection_changed"); - break; + case nsIAccessibleEvent::EVENT_SELECTION: + case nsIAccessibleEvent::EVENT_SELECTION_ADD: + case nsIAccessibleEvent::EVENT_SELECTION_REMOVE: + { + // XXX: dupe events may be fired + MAI_LOG_DEBUG(("\n\nReceived: EVENT_SELECTION_CHANGED\n")); + AccSelChangeEvent* selChangeEvent = downcast_accEvent(aEvent); + g_signal_emit_by_name(nsAccessibleWrap::GetAtkObject(selChangeEvent->Widget()), + "selection_changed"); + break; + } + + case nsIAccessibleEvent::EVENT_SELECTION_WITHIN: + { + MAI_LOG_DEBUG(("\n\nReceived: EVENT_SELECTION_CHANGED\n")); + g_signal_emit_by_name(atkObj, "selection_changed"); + break; + } case nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED: MAI_LOG_DEBUG(("\n\nReceived: EVENT_TEXT_SELECTION_CHANGED\n")); diff --git a/accessible/src/base/AccEvent.cpp b/accessible/src/base/AccEvent.cpp index 31043b65d9f1..1847a6398e3e 100644 --- a/accessible/src/base/AccEvent.cpp +++ b/accessible/src/base/AccEvent.cpp @@ -330,6 +330,28 @@ AccCaretMoveEvent::CreateXPCOMObject() } +//////////////////////////////////////////////////////////////////////////////// +// AccSelChangeEvent +//////////////////////////////////////////////////////////////////////////////// + +AccSelChangeEvent:: + AccSelChangeEvent(nsAccessible* aWidget, nsAccessible* aItem, + SelChangeType aSelChangeType) : + AccEvent(0, aItem, eAutoDetect, eCoalesceSelectionChange), + mWidget(aWidget), mItem(aItem), mSelChangeType(aSelChangeType), + mPreceedingCount(0), mPackedEvent(nsnull) +{ + if (aSelChangeType == eSelectionAdd) { + if (mWidget->GetSelectedItem(1)) + mEventType = nsIAccessibleEvent::EVENT_SELECTION_ADD; + else + mEventType = nsIAccessibleEvent::EVENT_SELECTION; + } else { + mEventType = nsIAccessibleEvent::EVENT_SELECTION_REMOVE; + } +} + + //////////////////////////////////////////////////////////////////////////////// // AccTableChangeEvent //////////////////////////////////////////////////////////////////////////////// diff --git a/accessible/src/base/AccEvent.h b/accessible/src/base/AccEvent.h index 5bb277cee59c..762a1563a6e5 100644 --- a/accessible/src/base/AccEvent.h +++ b/accessible/src/base/AccEvent.h @@ -82,6 +82,9 @@ public: // will be processed. eCoalesceOfSameType, + // eCoalesceSelectionChange: coalescence of selection change events. + eCoalesceSelectionChange, + // eRemoveDupes : For repeat events, only the newest event in queue // will be emitted. eRemoveDupes, @@ -125,6 +128,7 @@ public: eHideEvent, eShowEvent, eCaretMoveEvent, + eSelectionChangeEvent, eTableChangeEvent }; @@ -327,10 +331,37 @@ private: /** * Accessible widget selection change event. */ -class AccSelectionChangeEvent : public AccEvent +class AccSelChangeEvent : public AccEvent { public: + enum SelChangeType { + eSelectionAdd, + eSelectionRemove + }; + AccSelChangeEvent(nsAccessible* aWidget, nsAccessible* aItem, + SelChangeType aSelChangeType); + + virtual ~AccSelChangeEvent() { } + + // AccEvent + static const EventGroup kEventGroup = eSelectionChangeEvent; + virtual unsigned int GetEventGroups() const + { + return AccEvent::GetEventGroups() | (1U << eSelectionChangeEvent); + } + + // AccSelChangeEvent + nsAccessible* Widget() const { return mWidget; } + +private: + nsRefPtr mWidget; + nsRefPtr mItem; + SelChangeType mSelChangeType; + PRUint32 mPreceedingCount; + AccSelChangeEvent* mPackedEvent; + + friend class NotificationController; }; diff --git a/accessible/src/base/NotificationController.cpp b/accessible/src/base/NotificationController.cpp index d903de8b75da..a51a2324b997 100644 --- a/accessible/src/base/NotificationController.cpp +++ b/accessible/src/base/NotificationController.cpp @@ -51,6 +51,10 @@ using namespace mozilla::a11y; +// Defines the number of selection add/remove events in the queue when they +// aren't packed into single selection within event. +const unsigned int kSelChangeCountToPack = 5; + //////////////////////////////////////////////////////////////////////////////// // NotificationCollector //////////////////////////////////////////////////////////////////////////////// @@ -491,6 +495,26 @@ NotificationController::CoalesceEvents() } } break; // case eRemoveDupes + case AccEvent::eCoalesceSelectionChange: + { + AccSelChangeEvent* tailSelChangeEvent = downcast_accEvent(tailEvent); + PRInt32 index = tail - 1; + for (; index >= 0; index--) { + AccEvent* thisEvent = mEvents[index]; + if (thisEvent->mEventRule == tailEvent->mEventRule) { + AccSelChangeEvent* thisSelChangeEvent = + downcast_accEvent(thisEvent); + + // Coalesce selection change events within same control. + if (tailSelChangeEvent->mWidget == thisSelChangeEvent->mWidget) { + CoalesceSelChangeEvents(tailSelChangeEvent, thisSelChangeEvent, index); + return; + } + } + } + + } break; // eCoalesceSelectionChange + default: break; // case eAllowDupes, eDoNotEmit } // switch @@ -511,6 +535,86 @@ NotificationController::ApplyToSiblings(PRUint32 aStart, PRUint32 aEnd, } } +void +NotificationController::CoalesceSelChangeEvents(AccSelChangeEvent* aTailEvent, + AccSelChangeEvent* aThisEvent, + PRInt32 aThisIndex) +{ + aTailEvent->mPreceedingCount = aThisEvent->mPreceedingCount + 1; + + // Pack all preceding events into single selection within event + // when we receive too much selection add/remove events. + if (aTailEvent->mPreceedingCount >= kSelChangeCountToPack) { + aTailEvent->mEventType = nsIAccessibleEvent::EVENT_SELECTION_WITHIN; + aTailEvent->mAccessible = aTailEvent->mWidget; + aThisEvent->mEventRule = AccEvent::eDoNotEmit; + + // Do not emit any preceding selection events for same widget if they + // weren't coalesced yet. + if (aThisEvent->mEventType != nsIAccessibleEvent::EVENT_SELECTION_WITHIN) { + for (PRInt32 jdx = aThisIndex - 1; jdx >= 0; jdx--) { + AccEvent* prevEvent = mEvents[jdx]; + if (prevEvent->mEventRule == aTailEvent->mEventRule) { + AccSelChangeEvent* prevSelChangeEvent = + downcast_accEvent(prevEvent); + if (prevSelChangeEvent->mWidget == aTailEvent->mWidget) + prevSelChangeEvent->mEventRule = AccEvent::eDoNotEmit; + } + } + } + return; + } + + // Pack sequential selection remove and selection add events into + // single selection change event. + if (aTailEvent->mPreceedingCount == 1 && + aTailEvent->mItem != aThisEvent->mItem) { + if (aTailEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd && + aThisEvent->mSelChangeType == AccSelChangeEvent::eSelectionRemove) { + aThisEvent->mEventRule = AccEvent::eDoNotEmit; + aTailEvent->mEventType = nsIAccessibleEvent::EVENT_SELECTION; + aTailEvent->mPackedEvent = aThisEvent; + return; + } + + if (aThisEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd && + aTailEvent->mSelChangeType == AccSelChangeEvent::eSelectionRemove) { + aTailEvent->mEventRule = AccEvent::eDoNotEmit; + aThisEvent->mEventType = nsIAccessibleEvent::EVENT_SELECTION; + aThisEvent->mPackedEvent = aThisEvent; + return; + } + } + + // Unpack the packed selection change event because we've got one + // more selection add/remove. + if (aThisEvent->mEventType == nsIAccessibleEvent::EVENT_SELECTION) { + if (aThisEvent->mPackedEvent) { + aThisEvent->mPackedEvent->mEventType = + aThisEvent->mPackedEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd ? + nsIAccessibleEvent::EVENT_SELECTION_ADD : + nsIAccessibleEvent::EVENT_SELECTION_REMOVE; + + aThisEvent->mPackedEvent->mEventRule = + AccEvent::eCoalesceSelectionChange; + + aThisEvent->mPackedEvent = nsnull; + } + + aThisEvent->mEventType = + aThisEvent->mSelChangeType == AccSelChangeEvent::eSelectionAdd ? + nsIAccessibleEvent::EVENT_SELECTION_ADD : + nsIAccessibleEvent::EVENT_SELECTION_REMOVE; + + return; + } + + // Convert into selection add since control has single selection but other + // selection events for this control are queued. + if (aTailEvent->mEventType == nsIAccessibleEvent::EVENT_SELECTION) + aTailEvent->mEventType = nsIAccessibleEvent::EVENT_SELECTION_ADD; +} + void NotificationController::CoalesceTextChangeEventsFor(AccHideEvent* aTailEvent, AccHideEvent* aThisEvent) diff --git a/accessible/src/base/NotificationController.h b/accessible/src/base/NotificationController.h index 8a1c87cfa75e..30810e1b1754 100644 --- a/accessible/src/base/NotificationController.h +++ b/accessible/src/base/NotificationController.h @@ -251,11 +251,11 @@ private: AccEvent::EEventRule aEventRule); /** - * Do not emit one of two given reorder events fired for DOM nodes in the case - * when one DOM node is in parent chain of second one. + * Coalesce two selection change events within the same select control. */ - void CoalesceReorderEventsFromSameTree(AccEvent* aAccEvent, - AccEvent* aDescendantAccEvent); + void CoalesceSelChangeEvents(AccSelChangeEvent* aTailEvent, + AccSelChangeEvent* aThisEvent, + PRInt32 aThisIndex); /** * Coalesce text change events caused by sibling hide events. diff --git a/accessible/src/base/nsAccessibilityService.h b/accessible/src/base/nsAccessibilityService.h index 27c028947f77..841814a09b4b 100644 --- a/accessible/src/base/nsAccessibilityService.h +++ b/accessible/src/base/nsAccessibilityService.h @@ -473,7 +473,7 @@ static const char kEventTypeNames[][40] = { "document attributes changed", // EVENT_DOCUMENT_ATTRIBUTES_CHANGED "document content changed", // EVENT_DOCUMENT_CONTENT_CHANGED "property changed", // EVENT_PROPERTY_CHANGED - "selection changed", // EVENT_SELECTION_CHANGED + "page changed", // EVENT_PAGE_CHANGED "text attribute changed", // EVENT_TEXT_ATTRIBUTE_CHANGED "text caret moved", // EVENT_TEXT_CARET_MOVED "text changed", // EVENT_TEXT_CHANGED @@ -514,7 +514,6 @@ static const char kEventTypeNames[][40] = { "hypertext changed", // EVENT_HYPERTEXT_CHANGED "hypertext links count changed", // EVENT_HYPERTEXT_NLINKS_CHANGED "object attribute changed", // EVENT_OBJECT_ATTRIBUTE_CHANGED - "page changed" // EVENT_PAGE_CHANGED }; /** diff --git a/accessible/src/base/nsDocAccessible.cpp b/accessible/src/base/nsDocAccessible.cpp index d80861e6ec14..fd68d6da5438 100644 --- a/accessible/src/base/nsDocAccessible.cpp +++ b/accessible/src/base/nsDocAccessible.cpp @@ -1042,32 +1042,23 @@ nsDocAccessible::AttributeChangedImpl(nsIContent* aContent, PRInt32 aNameSpaceID return; } - if (aAttribute == nsGkAtoms::selected || + // ARIA or XUL selection + if ((aContent->IsXUL() && aAttribute == nsGkAtoms::selected) || aAttribute == nsGkAtoms::aria_selected) { - // ARIA or XUL selection + nsAccessible* item = GetAccessible(aContent); + nsAccessible* widget = + nsAccUtils::GetSelectableContainer(item, item->State()); + if (widget) { + AccSelChangeEvent::SelChangeType selChangeType = + aContent->AttrValueIs(aNameSpaceID, aAttribute, + nsGkAtoms::_true, eCaseMatters) ? + AccSelChangeEvent::eSelectionAdd : AccSelChangeEvent::eSelectionRemove; - nsAccessible *multiSelect = - nsAccUtils::GetMultiSelectableContainer(aContent); - // XXX: Multi selects are handled here only (bug 414302). - if (multiSelect) { - // Need to find the right event to use here, SELECTION_WITHIN would - // seem right but we had started using it for something else - FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_SELECTION_WITHIN, - multiSelect->GetNode(), - AccEvent::eAllowDupes); - - static nsIContent::AttrValuesArray strings[] = - {&nsGkAtoms::_empty, &nsGkAtoms::_false, nsnull}; - if (aContent->FindAttrValueIn(kNameSpaceID_None, aAttribute, - strings, eCaseMatters) >= 0) { - FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_SELECTION_REMOVE, - aContent); - return; - } - - FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_SELECTION_ADD, - aContent); + nsRefPtr event = + new AccSelChangeEvent(widget, item, selChangeType); + FireDelayedAccessibleEvent(event); } + return; } if (aAttribute == nsGkAtoms::contenteditable) { @@ -1209,7 +1200,18 @@ void nsDocAccessible::ContentStateChanged(nsIDocument* aDocument, nsEventStates aStateMask) { if (aStateMask.HasState(NS_EVENT_STATE_CHECKED)) { - nsHTMLSelectOptionAccessible::SelectionChangedIfOption(aContent); + nsAccessible* item = GetAccessible(aContent); + if (item) { + nsAccessible* widget = item->ContainerWidget(); + if (widget && widget->IsSelect()) { + AccSelChangeEvent::SelChangeType selChangeType = + aContent->AsElement()->State().HasState(NS_EVENT_STATE_CHECKED) ? + AccSelChangeEvent::eSelectionAdd : AccSelChangeEvent::eSelectionRemove; + nsRefPtr event = new AccSelChangeEvent(widget, item, + selChangeType); + FireDelayedAccessibleEvent(event); + } + } } if (aStateMask.HasState(NS_EVENT_STATE_INVALID)) { diff --git a/accessible/src/base/nsRootAccessible.cpp b/accessible/src/base/nsRootAccessible.cpp index 1ef2e3d92e9c..a31d1f2ca282 100644 --- a/accessible/src/base/nsRootAccessible.cpp +++ b/accessible/src/base/nsRootAccessible.cpp @@ -473,6 +473,8 @@ nsRootAccessible::ProcessDOMEvent(nsIDOMEvent* aDOMEvent) } if (treeItemAccessible && eventType.EqualsLiteral("select")) { + // XXX: We shouldn't be based on DOM select event which doesn't provide us + // any context info. We should integrate into nsTreeSelection instead. // If multiselect tree, we should fire selectionadd or selection removed if (FocusMgr()->HasDOMFocus(targetNode)) { nsCOMPtr multiSel = diff --git a/accessible/src/html/nsHTMLSelectAccessible.cpp b/accessible/src/html/nsHTMLSelectAccessible.cpp index b0a728459f22..204b1ab2a866 100644 --- a/accessible/src/html/nsHTMLSelectAccessible.cpp +++ b/accessible/src/html/nsHTMLSelectAccessible.cpp @@ -416,59 +416,7 @@ nsHTMLSelectOptionAccessible::SetSelected(bool aSelect) nsAccessible* nsHTMLSelectOptionAccessible::ContainerWidget() const { - if (mParent && mParent->IsListControl()) { - nsAccessible* grandParent = mParent->Parent(); - if (grandParent && grandParent->IsCombobox()) - return grandParent; - - return mParent; - } - return nsnull; -} - -//////////////////////////////////////////////////////////////////////////////// -// nsHTMLSelectOptionAccessible: static methods - -void -nsHTMLSelectOptionAccessible::SelectionChangedIfOption(nsIContent *aPossibleOptionNode) -{ - if (!aPossibleOptionNode || - aPossibleOptionNode->Tag() != nsGkAtoms::option || - !aPossibleOptionNode->IsHTML()) { - return; - } - - nsAccessible *multiSelect = - nsAccUtils::GetMultiSelectableContainer(aPossibleOptionNode); - if (!multiSelect) - return; - - nsAccessible *option = GetAccService()->GetAccessible(aPossibleOptionNode); - if (!option) - return; - - - nsRefPtr selWithinEvent = - new AccEvent(nsIAccessibleEvent::EVENT_SELECTION_WITHIN, multiSelect); - - if (!selWithinEvent) - return; - - option->GetDocAccessible()->FireDelayedAccessibleEvent(selWithinEvent); - - PRUint64 state = option->State(); - PRUint32 eventType; - if (state & states::SELECTED) { - eventType = nsIAccessibleEvent::EVENT_SELECTION_ADD; - } - else { - eventType = nsIAccessibleEvent::EVENT_SELECTION_REMOVE; - } - - nsRefPtr selAddRemoveEvent = new AccEvent(eventType, option); - - if (selAddRemoveEvent) - option->GetDocAccessible()->FireDelayedAccessibleEvent(selAddRemoveEvent); + return mParent && mParent->IsListControl() ? mParent : nsnull; } //////////////////////////////////////////////////////////////////////////////// @@ -738,26 +686,22 @@ nsHTMLComboboxAccessible::AreItemsOperable() const nsAccessible* nsHTMLComboboxAccessible::CurrentItem() { - // No current item for collapsed combobox. - return SelectedOption(true); + return AreItemsOperable() ? mListAccessible->CurrentItem() : nsnull; } //////////////////////////////////////////////////////////////////////////////// // nsHTMLComboboxAccessible: protected nsAccessible* -nsHTMLComboboxAccessible::SelectedOption(bool aIgnoreIfCollapsed) const +nsHTMLComboboxAccessible::SelectedOption() const { nsIFrame* frame = GetFrame(); nsIComboboxControlFrame* comboboxFrame = do_QueryFrame(frame); - if (comboboxFrame) { - if (aIgnoreIfCollapsed && !comboboxFrame->IsDroppedDown()) - return nsnull; + if (!comboboxFrame) + return nsnull; - frame = comboboxFrame->GetDropDown(); - } - - nsIListControlFrame* listControlFrame = do_QueryFrame(frame); + nsIListControlFrame* listControlFrame = + do_QueryFrame(comboboxFrame->GetDropDown()); if (listControlFrame) { nsCOMPtr activeOptionNode = listControlFrame->GetCurrentOption(); if (activeOptionNode) { @@ -858,3 +802,19 @@ void nsHTMLComboboxListAccessible::GetBoundsRect(nsRect& aBounds, nsIFrame** aBo *aBoundingFrame = frame->GetParent(); aBounds = (*aBoundingFrame)->GetRect(); } + +//////////////////////////////////////////////////////////////////////////////// +// nsHTMLComboboxListAccessible: Widgets + +bool +nsHTMLComboboxListAccessible::IsActiveWidget() const +{ + return mParent && mParent->IsActiveWidget(); +} + +bool +nsHTMLComboboxListAccessible::AreItemsOperable() const +{ + return mParent && mParent->AreItemsOperable(); +} + diff --git a/accessible/src/html/nsHTMLSelectAccessible.h b/accessible/src/html/nsHTMLSelectAccessible.h index 10f98492a2f8..67a3682d0b46 100644 --- a/accessible/src/html/nsHTMLSelectAccessible.h +++ b/accessible/src/html/nsHTMLSelectAccessible.h @@ -130,8 +130,6 @@ public: // Widgets virtual nsAccessible* ContainerWidget() const; - static void SelectionChangedIfOption(nsIContent *aPossibleOption); - protected: // nsAccessible virtual nsIFrame* GetBoundsFrame(); @@ -219,7 +217,7 @@ protected: /** * Return selected option. */ - nsAccessible* SelectedOption(bool aIgnoreIfCollapsed = false) const; + nsAccessible* SelectedOption() const; private: nsRefPtr mListAccessible; @@ -246,6 +244,10 @@ public: // nsAccessible virtual PRUint64 NativeState(); virtual void GetBoundsRect(nsRect& aBounds, nsIFrame** aBoundingFrame); + + // Widgets + virtual bool IsActiveWidget() const; + virtual bool AreItemsOperable() const; }; #endif diff --git a/accessible/src/msaa/nsEventMap.h b/accessible/src/msaa/nsEventMap.h index 622489a41539..d11028973643 100644 --- a/accessible/src/msaa/nsEventMap.h +++ b/accessible/src/msaa/nsEventMap.h @@ -90,7 +90,7 @@ static const PRUint32 gWinEventMap[] = { IA2_EVENT_DOCUMENT_ATTRIBUTE_CHANGED, // nsIAccessibleEvent::EVENT_DOCUMENT_ATTRIBUTES_CHANGED IA2_EVENT_DOCUMENT_CONTENT_CHANGED, // nsIAccessibleEvent::EVENT_DOCUMENT_CONTENT_CHANGED kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_PROPERTY_CHANGED - kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_SELECTION_CHANGED + IA2_EVENT_PAGE_CHANGED, // nsIAccessibleEvent::IA2_EVENT_PAGE_CHANGED IA2_EVENT_TEXT_ATTRIBUTE_CHANGED, // nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED IA2_EVENT_TEXT_CARET_MOVED, // nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED IA2_EVENT_TEXT_CHANGED, // nsIAccessibleEvent::EVENT_TEXT_CHANGED @@ -131,7 +131,6 @@ static const PRUint32 gWinEventMap[] = { IA2_EVENT_HYPERTEXT_CHANGED, // nsIAccessibleEvent::EVENT_HYPERTEXT_CHANGED IA2_EVENT_HYPERTEXT_NLINKS_CHANGED, // nsIAccessibleEvent::EVENT_HYPERTEXT_NLINKS_CHANGED IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED, // nsIAccessibleEvent::EVENT_OBJECT_ATTRIBUTE_CHANGED - IA2_EVENT_PAGE_CHANGED, // nsIAccessibleEvent::EVENT_PAGE_CHANGED kEVENT_LAST_ENTRY // nsIAccessibleEvent::EVENT_LAST_ENTRY }; diff --git a/accessible/tests/mochitest/events.js b/accessible/tests/mochitest/events.js index 9d3c7c3ce3d0..7b7f36f432d1 100644 --- a/accessible/tests/mochitest/events.js +++ b/accessible/tests/mochitest/events.js @@ -15,7 +15,9 @@ const EVENT_MENUPOPUP_END = nsIAccessibleEvent.EVENT_MENUPOPUP_END; const EVENT_OBJECT_ATTRIBUTE_CHANGED = nsIAccessibleEvent.EVENT_OBJECT_ATTRIBUTE_CHANGED; const EVENT_REORDER = nsIAccessibleEvent.EVENT_REORDER; const EVENT_SCROLLING_START = nsIAccessibleEvent.EVENT_SCROLLING_START; +const EVENT_SELECTION = nsIAccessibleEvent.EVENT_SELECTION; const EVENT_SELECTION_ADD = nsIAccessibleEvent.EVENT_SELECTION_ADD; +const EVENT_SELECTION_REMOVE = nsIAccessibleEvent.EVENT_SELECTION_REMOVE; const EVENT_SELECTION_WITHIN = nsIAccessibleEvent.EVENT_SELECTION_WITHIN; const EVENT_SHOW = nsIAccessibleEvent.EVENT_SHOW; const EVENT_STATE_CHANGE = nsIAccessibleEvent.EVENT_STATE_CHANGE; diff --git a/accessible/tests/mochitest/events/Makefile.in b/accessible/tests/mochitest/events/Makefile.in index 88ec2e13c912..56041ec8655c 100644 --- a/accessible/tests/mochitest/events/Makefile.in +++ b/accessible/tests/mochitest/events/Makefile.in @@ -82,7 +82,9 @@ _TEST_FILES =\ test_mutation.html \ test_mutation.xhtml \ test_scroll.xul \ + test_selection_aria.html \ test_selection.html \ + test_selection.xul \ test_statechange.html \ test_text_alg.html \ test_text.html \ diff --git a/accessible/tests/mochitest/events/test_selection.html b/accessible/tests/mochitest/events/test_selection.html index 21bb2bef2d3c..7bf94838bcb1 100644 --- a/accessible/tests/mochitest/events/test_selection.html +++ b/accessible/tests/mochitest/events/test_selection.html @@ -22,39 +22,45 @@ //////////////////////////////////////////////////////////////////////////// // Invokers - function addSelection(aNode, aOption) - { - this.DOMNode = aNode; - this.optionNode = aOption; - - this.eventSeq = [ - new invokerChecker(EVENT_SELECTION_WITHIN, getAccessible(this.DOMNode)), - new invokerChecker(EVENT_SELECTION_ADD, getAccessible(this.optionNode)) - ]; - - this.invoke = function addselection_invoke() { - synthesizeMouse(this.optionNode, 1, 1, {}); - }; - - this.getID = function addselection_getID() { - return prettyName(this.optionNode) + " added to selection"; - }; - } - //////////////////////////////////////////////////////////////////////////// // Do tests + //gA11yEventDumpToConsole = true; // debuggin + var gQueue = null; - - //var gA11yEventDumpID = "eventdump"; // debug stuff - function doTests() { gQueue = new eventQueue(); - var select = document.getElementById("toppings"); - var option = document.getElementById("onions"); - gQueue.push(new addSelection(select, option)); + // open combobox + gQueue.push(new synthClick("combobox", + new invokerChecker(EVENT_FOCUS, "cb1_item1"))); + gQueue.push(new synthDownKey("cb1_item1", + new invokerChecker(EVENT_SELECTION, "cb1_item2"))); + + // closed combobox + gQueue.push(new synthEscapeKey("combobox", + new invokerChecker(EVENT_FOCUS, "combobox"))); + gQueue.push(new synthDownKey("cb1_item2", + new invokerChecker(EVENT_SELECTION, "cb1_item3"))); + + // listbox + gQueue.push(new synthClick("lb1_item1", + new invokerChecker(EVENT_SELECTION, "lb1_item1"))); + gQueue.push(new synthDownKey("lb1_item1", + new invokerChecker(EVENT_SELECTION, "lb1_item2"))); + + // multiselectable listbox + gQueue.push(new synthClick("lb2_item1", + new invokerChecker(EVENT_SELECTION, "lb2_item1"))); + gQueue.push(new synthDownKey("lb2_item1", + new invokerChecker(EVENT_SELECTION_ADD, "lb2_item2"), + { shiftKey: true })); + gQueue.push(new synthUpKey("lb2_item2", + new invokerChecker(EVENT_SELECTION_REMOVE, "lb2_item2"), + { shiftKey: true })); + gQueue.push(new synthKey("lb2_item1", " ", { ctrlKey: true }, + new invokerChecker(EVENT_SELECTION_REMOVE, "lb2_item1"))); gQueue.invoke(); // Will call SimpleTest.finish(); } @@ -67,9 +73,9 @@ - Mozilla Bug 569653 + href="https://bugzilla.mozilla.org/show_bug.cgi?id=414302" + title="Incorrect selection events in HTML, XUL and ARIA"> + Mozilla Bug 414302

@@ -77,18 +83,31 @@
   
-

Pizza

- +