Bug 678454 - coalesce events by accessible tree, r=tbsaunde

This commit is contained in:
Alexander Surkov 2012-11-20 13:53:38 +09:00
parent b361a10312
commit 2acd72040f
18 changed files with 201 additions and 374 deletions

View File

@ -35,47 +35,9 @@ AccEvent::AccEvent(uint32_t aEventType, Accessible* aAccessible,
CaptureIsFromUserInput(aIsFromUserInput); CaptureIsFromUserInput(aIsFromUserInput);
} }
AccEvent::AccEvent(uint32_t aEventType, nsINode* aNode,
EIsFromUserInput aIsFromUserInput, EEventRule aEventRule) :
mEventType(aEventType), mEventRule(aEventRule), mNode(aNode)
{
CaptureIsFromUserInput(aIsFromUserInput);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// AccEvent public methods // AccEvent public methods
Accessible*
AccEvent::GetAccessible()
{
if (!mAccessible)
mAccessible = GetAccessibleForNode();
return mAccessible;
}
nsINode*
AccEvent::GetNode()
{
if (!mNode && mAccessible)
mNode = mAccessible->GetNode();
return mNode;
}
DocAccessible*
AccEvent::GetDocAccessible()
{
if (mAccessible)
return mAccessible->Document();
nsINode* node = GetNode();
if (node)
return GetAccService()->GetDocAccessible(node->OwnerDoc());
return nullptr;
}
already_AddRefed<nsAccEvent> already_AddRefed<nsAccEvent>
AccEvent::CreateXPCOMObject() AccEvent::CreateXPCOMObject()
{ {
@ -104,56 +66,23 @@ NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AccEvent, Release)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// AccEvent protected methods // AccEvent protected methods
Accessible*
AccEvent::GetAccessibleForNode() const
{
if (mNode) {
DocAccessible* document =
GetAccService()->GetDocAccessible(mNode->OwnerDoc());
if (document)
return document->GetAccessible(mNode);
}
return nullptr;
}
void void
AccEvent::CaptureIsFromUserInput(EIsFromUserInput aIsFromUserInput) AccEvent::CaptureIsFromUserInput(EIsFromUserInput aIsFromUserInput)
{ {
nsINode *targetNode = GetNode();
#ifdef DEBUG
if (!targetNode) {
// XXX: remove this hack during reorganization of 506907. Meanwhile we
// want to get rid an assertion for application accessible events which
// don't have DOM node (see bug 506206).
if (mAccessible != static_cast<nsIAccessible*>(ApplicationAcc()))
NS_ASSERTION(targetNode, "There should always be a DOM node for an event");
}
#endif
if (aIsFromUserInput != eAutoDetect) { if (aIsFromUserInput != eAutoDetect) {
mIsFromUserInput = aIsFromUserInput == eFromUserInput ? true : false; mIsFromUserInput = aIsFromUserInput == eFromUserInput ? true : false;
return; return;
} }
if (!targetNode) DocAccessible* document = mAccessible->Document();
return; if (!document) {
NS_ASSERTION(mAccessible == ApplicationAcc(),
nsIPresShell *presShell = nsCoreUtils::GetPresShellFor(targetNode); "Accessible other than application should always have a doc!");
if (!presShell) {
NS_NOTREACHED("Threre should always be an pres shell for an event");
return; return;
} }
nsEventStateManager *esm = presShell->GetPresContext()->EventStateManager(); mIsFromUserInput =
if (!esm) { document->PresContext()->EventStateManager()->IsHandlingUserInputExternal();
NS_NOTREACHED("There should always be an ESM for an event");
return;
}
mIsFromUserInput = esm->IsHandlingUserInputExternal();
} }
@ -161,39 +90,6 @@ AccEvent::CaptureIsFromUserInput(EIsFromUserInput aIsFromUserInput)
// AccStateChangeEvent // AccStateChangeEvent
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Note: we pass in eAllowDupes to the base class because we don't currently
// support correct state change coalescence (XXX Bug 569356). Also we need to
// decide how to coalesce events created via accessible (instead of node).
AccStateChangeEvent::
AccStateChangeEvent(Accessible* aAccessible, uint64_t aState,
bool aIsEnabled, EIsFromUserInput aIsFromUserInput):
AccEvent(nsIAccessibleEvent::EVENT_STATE_CHANGE, aAccessible,
aIsFromUserInput, eAllowDupes),
mState(aState), mIsEnabled(aIsEnabled)
{
}
AccStateChangeEvent::
AccStateChangeEvent(nsINode* aNode, uint64_t aState, bool aIsEnabled):
AccEvent(::nsIAccessibleEvent::EVENT_STATE_CHANGE, aNode,
eAutoDetect, eAllowDupes),
mState(aState), mIsEnabled(aIsEnabled)
{
}
AccStateChangeEvent::
AccStateChangeEvent(nsINode* aNode, uint64_t aState) :
AccEvent(::nsIAccessibleEvent::EVENT_STATE_CHANGE, aNode,
eAutoDetect, eAllowDupes),
mState(aState)
{
// Use GetAccessibleForNode() because we do not want to store an accessible
// since it leads to problems with delayed events in the case when
// an accessible gets reorder event before delayed event is processed.
Accessible* accessible = GetAccessibleForNode();
mIsEnabled = accessible && ((accessible->State() & mState) != 0);
}
already_AddRefed<nsAccEvent> already_AddRefed<nsAccEvent>
AccStateChangeEvent::CreateXPCOMObject() AccStateChangeEvent::CreateXPCOMObject()
{ {
@ -296,20 +192,6 @@ AccShowEvent::
// AccCaretMoveEvent // AccCaretMoveEvent
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
AccCaretMoveEvent::
AccCaretMoveEvent(Accessible* aAccessible, int32_t aCaretOffset) :
AccEvent(::nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED, aAccessible),
mCaretOffset(aCaretOffset)
{
}
AccCaretMoveEvent::
AccCaretMoveEvent(nsINode* aNode) :
AccEvent(::nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED, aNode),
mCaretOffset(-1)
{
}
already_AddRefed<nsAccEvent> already_AddRefed<nsAccEvent>
AccCaretMoveEvent::CreateXPCOMObject() AccCaretMoveEvent::CreateXPCOMObject()
{ {

View File

@ -38,17 +38,18 @@ public:
// Rule for accessible events. // Rule for accessible events.
// The rule will be applied when flushing pending events. // The rule will be applied when flushing pending events.
enum EEventRule { enum EEventRule {
// eAllowDupes : More than one event of the same type is allowed. // eAllowDupes : More than one event of the same type is allowed.
// This event will always be emitted. // This event will always be emitted. This flag is used for events that
eAllowDupes, // don't support coalescence.
eAllowDupes,
// eCoalesceReorder : For reorder events from the same subtree or the same // eCoalesceReorder : For reorder events from the same subtree or the same
// node, only the umbrella event on the ancestor will be emitted. // node, only the umbrella event on the ancestor will be emitted.
eCoalesceReorder, eCoalesceReorder,
// eCoalesceMutationTextChange : coalesce text change events caused by // eCoalesceMutationTextChange : coalesce text change events caused by
// tree mutations of the same tree level. // tree mutations of the same tree level.
eCoalesceMutationTextChange, eCoalesceMutationTextChange,
// eCoalesceOfSameType : For events of the same type, only the newest event // eCoalesceOfSameType : For events of the same type, only the newest event
// will be processed. // will be processed.
@ -59,20 +60,16 @@ public:
// eRemoveDupes : For repeat events, only the newest event in queue // eRemoveDupes : For repeat events, only the newest event in queue
// will be emitted. // will be emitted.
eRemoveDupes, eRemoveDupes,
// eDoNotEmit : This event is confirmed as a duplicate, do not emit it. // eDoNotEmit : This event is confirmed as a duplicate, do not emit it.
eDoNotEmit eDoNotEmit
}; };
// Initialize with an nsIAccessible // Initialize with an nsIAccessible
AccEvent(uint32_t aEventType, Accessible* aAccessible, AccEvent(uint32_t aEventType, Accessible* aAccessible,
EIsFromUserInput aIsFromUserInput = eAutoDetect, EIsFromUserInput aIsFromUserInput = eAutoDetect,
EEventRule aEventRule = eRemoveDupes); EEventRule aEventRule = eRemoveDupes);
// Initialize with an nsINode
AccEvent(uint32_t aEventType, nsINode* aNode,
EIsFromUserInput aIsFromUserInput = eAutoDetect,
EEventRule aEventRule = eRemoveDupes);
virtual ~AccEvent() {} virtual ~AccEvent() {}
// AccEvent // AccEvent
@ -80,9 +77,8 @@ public:
EEventRule GetEventRule() const { return mEventRule; } EEventRule GetEventRule() const { return mEventRule; }
bool IsFromUserInput() const { return mIsFromUserInput; } bool IsFromUserInput() const { return mIsFromUserInput; }
Accessible* GetAccessible(); Accessible* GetAccessible() const { return mAccessible; }
DocAccessible* GetDocAccessible(); DocAccessible* GetDocAccessible() const { return mAccessible->Document(); }
nsINode* GetNode();
/** /**
* Create and return an XPCOM object for accessible event object. * Create and return an XPCOM object for accessible event object.
@ -119,10 +115,6 @@ public:
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(AccEvent) NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(AccEvent)
protected: protected:
/**
* Get an accessible from event target node.
*/
Accessible* GetAccessibleForNode() const;
/** /**
* Determine whether the event is from user input by event state manager if * Determine whether the event is from user input by event state manager if
@ -134,7 +126,6 @@ protected:
uint32_t mEventType; uint32_t mEventType;
EEventRule mEventRule; EEventRule mEventRule;
nsRefPtr<Accessible> mAccessible; nsRefPtr<Accessible> mAccessible;
nsCOMPtr<nsINode> mNode;
friend class NotificationController; friend class NotificationController;
friend class AccReorderEvent; friend class AccReorderEvent;
@ -149,11 +140,15 @@ class AccStateChangeEvent: public AccEvent
public: public:
AccStateChangeEvent(Accessible* aAccessible, uint64_t aState, AccStateChangeEvent(Accessible* aAccessible, uint64_t aState,
bool aIsEnabled, bool aIsEnabled,
EIsFromUserInput aIsFromUserInput = eAutoDetect); EIsFromUserInput aIsFromUserInput = eAutoDetect) :
AccEvent(nsIAccessibleEvent::EVENT_STATE_CHANGE, aAccessible,
aIsFromUserInput, eAllowDupes),
mState(aState), mIsEnabled(aIsEnabled) { }
AccStateChangeEvent(nsINode* aNode, uint64_t aState, bool aIsEnabled); AccStateChangeEvent(Accessible* aAccessible, uint64_t aState) :
AccEvent(::nsIAccessibleEvent::EVENT_STATE_CHANGE, aAccessible,
AccStateChangeEvent(nsINode* aNode, uint64_t aState); eAutoDetect, eAllowDupes), mState(aState)
{ mIsEnabled = (mAccessible->State() & mState) != 0; }
// AccEvent // AccEvent
virtual already_AddRefed<nsAccEvent> CreateXPCOMObject(); virtual already_AddRefed<nsAccEvent> CreateXPCOMObject();
@ -239,6 +234,7 @@ public:
bool IsHide() const { return mEventType == nsIAccessibleEvent::EVENT_HIDE; } bool IsHide() const { return mEventType == nsIAccessibleEvent::EVENT_HIDE; }
protected: protected:
nsCOMPtr<nsINode> mNode;
nsRefPtr<Accessible> mParent; nsRefPtr<Accessible> mParent;
nsRefPtr<AccTextChangeEvent> mTextChangeEvent; nsRefPtr<AccTextChangeEvent> mTextChangeEvent;
@ -350,8 +346,10 @@ protected:
class AccCaretMoveEvent: public AccEvent class AccCaretMoveEvent: public AccEvent
{ {
public: public:
AccCaretMoveEvent(Accessible* aAccessible, int32_t aCaretOffset); AccCaretMoveEvent(Accessible* aAccessible) :
AccCaretMoveEvent(nsINode* aNode); AccEvent(::nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED, aAccessible),
mCaretOffset(-1) { }
virtual ~AccCaretMoveEvent() { }
// AccEvent // AccEvent
virtual already_AddRefed<nsAccEvent> CreateXPCOMObject(); virtual already_AddRefed<nsAccEvent> CreateXPCOMObject();
@ -367,6 +365,8 @@ public:
private: private:
int32_t mCaretOffset; int32_t mCaretOffset;
friend class NotificationController;
}; };

View File

@ -219,7 +219,7 @@ FocusManager::DispatchFocusEvent(DocAccessible* aDocument,
nsRefPtr<AccEvent> event = nsRefPtr<AccEvent> event =
new AccEvent(nsIAccessibleEvent::EVENT_FOCUS, aTarget, new AccEvent(nsIAccessibleEvent::EVENT_FOCUS, aTarget,
eAutoDetect, AccEvent::eCoalesceOfSameType); eAutoDetect, AccEvent::eCoalesceOfSameType);
aDocument->FireDelayedAccessibleEvent(event); aDocument->FireDelayedEvent(event);
#ifdef A11Y_LOG #ifdef A11Y_LOG
if (logging::IsEnabled(logging::eFocus)) if (logging::IsEnabled(logging::eFocus))

View File

@ -471,12 +471,9 @@ logging::DocLoadEventHandled(AccEvent* aEvent)
MsgBegin(sDocEventTitle, "handled '%s' event", strEventType.get()); MsgBegin(sDocEventTitle, "handled '%s' event", strEventType.get());
nsINode* node = aEvent->GetNode(); DocAccessible* document = aEvent->GetAccessible()->AsDoc();
if (node->IsNodeOfType(nsINode::eDOCUMENT)) { if (document)
nsIDocument* documentNode = static_cast<nsIDocument*>(node); LogDocInfo(document->DocumentNode(), document);
DocAccessible* document = aEvent->GetDocAccessible();
LogDocInfo(documentNode, document);
}
MsgEnd(); MsgEnd();
} }

View File

@ -385,7 +385,7 @@ NotificationController::CoalesceEvents()
AccEvent* accEvent = mEvents[index]; AccEvent* accEvent = mEvents[index];
if (accEvent->mEventType == tailEvent->mEventType && if (accEvent->mEventType == tailEvent->mEventType &&
accEvent->mEventRule == tailEvent->mEventRule && accEvent->mEventRule == tailEvent->mEventRule &&
accEvent->mNode == tailEvent->mNode) { accEvent->mAccessible == tailEvent->mAccessible) {
tailEvent->mEventRule = AccEvent::eDoNotEmit; tailEvent->mEventRule = AccEvent::eDoNotEmit;
return; return;
} }
@ -705,12 +705,11 @@ NotificationController::ProcessEventQueue()
// Dispatch caret moved and text selection change events. // Dispatch caret moved and text selection change events.
if (event->mEventType == nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED) { if (event->mEventType == nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED) {
AccCaretMoveEvent* caretMoveEvent = downcast_accEvent(event);
HyperTextAccessible* hyperText = target->AsHyperText(); HyperTextAccessible* hyperText = target->AsHyperText();
int32_t caretOffset = -1;
if (hyperText && if (hyperText &&
NS_SUCCEEDED(hyperText->GetCaretOffset(&caretOffset))) { NS_SUCCEEDED(hyperText->GetCaretOffset(&caretMoveEvent->mCaretOffset))) {
nsRefPtr<AccEvent> caretMoveEvent =
new AccCaretMoveEvent(hyperText, caretOffset);
nsEventShell::FireEvent(caretMoveEvent); nsEventShell::FireEvent(caretMoveEvent);
// There's a selection so fire selection change as well. // There's a selection so fire selection change as well.

View File

@ -78,7 +78,7 @@ private:
Class* mInstance; Class* mInstance;
Callback mCallback; Callback mCallback;
nsCOMPtr<Arg> mArg; nsRefPtr<Arg> mArg;
}; };
/** /**

View File

@ -82,14 +82,14 @@ TextUpdater::DoUpdate(const nsAString& aNewText, const nsAString& aOldText,
// Fire text change event for removal. // Fire text change event for removal.
nsRefPtr<AccEvent> textRemoveEvent = nsRefPtr<AccEvent> textRemoveEvent =
new AccTextChangeEvent(mHyperText, mTextOffset, str1, false); new AccTextChangeEvent(mHyperText, mTextOffset, str1, false);
mDocument->FireDelayedAccessibleEvent(textRemoveEvent); mDocument->FireDelayedEvent(textRemoveEvent);
} }
if (strLen2 > 0) { if (strLen2 > 0) {
// Fire text change event for insertion. // Fire text change event for insertion.
nsRefPtr<AccEvent> textInsertEvent = nsRefPtr<AccEvent> textInsertEvent =
new AccTextChangeEvent(mHyperText, mTextOffset, str2, true); new AccTextChangeEvent(mHyperText, mTextOffset, str2, true);
mDocument->FireDelayedAccessibleEvent(textInsertEvent); mDocument->FireDelayedEvent(textInsertEvent);
} }
mDocument->MaybeNotifyOfValueChange(mHyperText); mDocument->MaybeNotifyOfValueChange(mHyperText);
@ -135,7 +135,7 @@ TextUpdater::DoUpdate(const nsAString& aNewText, const nsAString& aOldText,
// Fire events. // Fire events.
for (int32_t idx = events.Length() - 1; idx >= 0; idx--) for (int32_t idx = events.Length() - 1; idx >= 0; idx--)
mDocument->FireDelayedAccessibleEvent(events[idx]); mDocument->FireDelayedEvent(events[idx]);
mDocument->MaybeNotifyOfValueChange(mHyperText); mDocument->MaybeNotifyOfValueChange(mHyperText);

View File

@ -400,9 +400,8 @@ nsAccDocManager::CreateDocOrRootAccessible(nsIDocument* aDocument)
// the same document. // the same document.
// Note: don't use AccReorderEvent to avoid coalsecense and special reorder // Note: don't use AccReorderEvent to avoid coalsecense and special reorder
// events processing. // events processing.
nsRefPtr<AccEvent> reorderEvent = docAcc->FireDelayedEvent(nsIAccessibleEvent::EVENT_REORDER,
new AccEvent(nsIAccessibleEvent::EVENT_REORDER, ApplicationAcc()); ApplicationAcc());
docAcc->FireDelayedAccessibleEvent(reorderEvent);
} else { } else {
parentDocAcc->BindChildDocument(docAcc); parentDocAcc->BindChildDocument(docAcc);

View File

@ -243,10 +243,8 @@ nsCaretAccessible::NormalSelectionChanged(nsISelection* aSelection)
mLastCaretOffset = caretOffset; mLastCaretOffset = caretOffset;
mLastTextAccessible = textAcc; mLastTextAccessible = textAcc;
nsRefPtr<AccEvent> event = nsRefPtr<AccEvent> event = new AccCaretMoveEvent(mLastTextAccessible);
new AccCaretMoveEvent(mLastTextAccessible->GetNode()); mLastTextAccessible->Document()->FireDelayedEvent(event);
if (event)
mLastTextAccessible->Document()->FireDelayedAccessibleEvent(event);
} }
void void
@ -258,15 +256,13 @@ nsCaretAccessible::SpellcheckSelectionChanged(nsISelection* aSelection)
// misspelled word). If spellchecking is disabled (for example, // misspelled word). If spellchecking is disabled (for example,
// @spellcheck="false" on html:body) then we won't fire any event. // @spellcheck="false" on html:body) then we won't fire any event.
HyperTextAccessible* textAcc = HyperTextAccessible* hyperText =
nsAccUtils::GetTextAccessibleFromSelection(aSelection); nsAccUtils::GetTextAccessibleFromSelection(aSelection);
if (!textAcc) if (hyperText) {
return; hyperText->Document()->
FireDelayedEvent(nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED,
nsRefPtr<AccEvent> event = hyperText);
new AccEvent(nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED, textAcc); }
if (event)
textAcc->Document()->FireDelayedAccessibleEvent(event);
} }
nsIntRect nsIntRect

View File

@ -22,7 +22,7 @@ nsEventShell::FireEvent(AccEvent* aEvent)
Accessible* accessible = aEvent->GetAccessible(); Accessible* accessible = aEvent->GetAccessible();
NS_ENSURE_TRUE_VOID(accessible); NS_ENSURE_TRUE_VOID(accessible);
nsINode* node = aEvent->GetNode(); nsINode* node = accessible->GetNode();
if (node) { if (node) {
sEventTargetNode = node; sEventTargetNode = node;
sEventFromUserInput = aEvent->IsFromUserInput(); sEventFromUserInput = aEvent->IsFromUserInput();

View File

@ -12,9 +12,31 @@
#include "NotificationController.h" #include "NotificationController.h"
#include "States.h" #include "States.h"
#ifdef A11Y_LOG
#include "Logging.h"
#endif
namespace mozilla { namespace mozilla {
namespace a11y { namespace a11y {
inline void
DocAccessible::FireDelayedEvent(AccEvent* aEvent)
{
#ifdef A11Y_LOG
if (logging::IsEnabled(logging::eDocLoad))
logging::DocLoadEventFired(aEvent);
#endif
mNotificationController->QueueEvent(aEvent);
}
inline void
DocAccessible::FireDelayedEvent(uint32_t aEventType, Accessible* aTarget)
{
nsRefPtr<AccEvent> event = new AccEvent(aEventType, aTarget);
FireDelayedEvent(event);
}
inline void inline void
DocAccessible::BindChildDocument(DocAccessible* aDocument) DocAccessible::BindChildDocument(DocAccessible* aDocument)
{ {
@ -54,20 +76,16 @@ DocAccessible::NotifyOfLoad(uint32_t aLoadEventType)
if (HasLoadState(eCompletelyLoaded) && IsLoadEventTarget()) { if (HasLoadState(eCompletelyLoaded) && IsLoadEventTarget()) {
nsRefPtr<AccEvent> stateEvent = nsRefPtr<AccEvent> stateEvent =
new AccStateChangeEvent(this, states::BUSY, false); new AccStateChangeEvent(this, states::BUSY, false);
FireDelayedAccessibleEvent(stateEvent); FireDelayedEvent(stateEvent);
} }
} }
inline void inline void
DocAccessible::MaybeNotifyOfValueChange(Accessible* aAccessible) DocAccessible::MaybeNotifyOfValueChange(Accessible* aAccessible)
{ {
mozilla::a11y::role role = aAccessible->Role(); a11y::role role = aAccessible->Role();
if (role == roles::ENTRY || role == roles::COMBOBOX) { if (role == roles::ENTRY || role == roles::COMBOBOX)
nsRefPtr<AccEvent> valueChangeEvent = FireDelayedEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, aAccessible);
new AccEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, aAccessible,
eAutoDetect, AccEvent::eRemoveDupes);
FireDelayedAccessibleEvent(valueChangeEvent);
}
} }
} // namespace a11y } // namespace a11y

View File

@ -44,10 +44,6 @@
#include "mozilla/Assertions.h" #include "mozilla/Assertions.h"
#include "mozilla/dom/Element.h" #include "mozilla/dom/Element.h"
#ifdef A11Y_LOG
#include "Logging.h"
#endif
#ifdef MOZ_XUL #ifdef MOZ_XUL
#include "nsIXULDocument.h" #include "nsIXULDocument.h"
#endif #endif
@ -892,7 +888,7 @@ DocAccessible::Observe(nsISupports* aSubject, const char* aTopic,
// about this exceptional case. // about this exceptional case.
nsRefPtr<AccEvent> event = nsRefPtr<AccEvent> event =
new AccStateChangeEvent(this, states::EDITABLE, true); new AccStateChangeEvent(this, states::EDITABLE, true);
FireDelayedAccessibleEvent(event); FireDelayedEvent(event);
} }
return NS_OK; return NS_OK;
@ -987,7 +983,7 @@ DocAccessible::AttributeChanged(nsIDocument* aDocument,
// Fire accessible events iff there's an accessible, otherwise we consider // Fire accessible events iff there's an accessible, otherwise we consider
// the accessible state wasn't changed, i.e. its state is initial state. // the accessible state wasn't changed, i.e. its state is initial state.
AttributeChangedImpl(aElement, aNameSpaceID, aAttribute); AttributeChangedImpl(accessible, aNameSpaceID, aAttribute);
// Update dependent IDs cache. Take care of accessible elements because no // Update dependent IDs cache. Take care of accessible elements because no
// accessible element means either the element is not accessible at all or // accessible element means either the element is not accessible at all or
@ -1002,7 +998,8 @@ DocAccessible::AttributeChanged(nsIDocument* aDocument,
// DocAccessible protected member // DocAccessible protected member
void void
DocAccessible::AttributeChangedImpl(nsIContent* aContent, int32_t aNameSpaceID, nsIAtom* aAttribute) DocAccessible::AttributeChangedImpl(Accessible* aAccessible,
int32_t aNameSpaceID, nsIAtom* aAttribute)
{ {
// Fire accessible event after short timer, because we need to wait for // Fire accessible event after short timer, because we need to wait for
// DOM attribute & resulting layout to actually change. Otherwise, // DOM attribute & resulting layout to actually change. Otherwise,
@ -1033,14 +1030,12 @@ DocAccessible::AttributeChangedImpl(nsIContent* aContent, int32_t aNameSpaceID,
// ARIA's aria-disabled does not affect the disabled state bit. // ARIA's aria-disabled does not affect the disabled state bit.
nsRefPtr<AccEvent> enabledChangeEvent = nsRefPtr<AccEvent> enabledChangeEvent =
new AccStateChangeEvent(aContent, states::ENABLED); new AccStateChangeEvent(aAccessible, states::ENABLED);
FireDelayedEvent(enabledChangeEvent);
FireDelayedAccessibleEvent(enabledChangeEvent);
nsRefPtr<AccEvent> sensitiveChangeEvent = nsRefPtr<AccEvent> sensitiveChangeEvent =
new AccStateChangeEvent(aContent, states::SENSITIVE); new AccStateChangeEvent(aAccessible, states::SENSITIVE);
FireDelayedEvent(sensitiveChangeEvent);
FireDelayedAccessibleEvent(sensitiveChangeEvent);
return; return;
} }
@ -1049,7 +1044,7 @@ DocAccessible::AttributeChangedImpl(nsIContent* aContent, int32_t aNameSpaceID,
// Check for hyphenated aria-foo property? // Check for hyphenated aria-foo property?
if (StringBeginsWith(nsDependentAtomString(aAttribute), if (StringBeginsWith(nsDependentAtomString(aAttribute),
NS_LITERAL_STRING("aria-"))) { NS_LITERAL_STRING("aria-"))) {
ARIAAttributeChanged(aContent, aAttribute); ARIAAttributeChanged(aAccessible, aAttribute);
} }
} }
@ -1057,75 +1052,69 @@ DocAccessible::AttributeChangedImpl(nsIContent* aContent, int32_t aNameSpaceID,
aAttribute == nsGkAtoms::title || aAttribute == nsGkAtoms::title ||
aAttribute == nsGkAtoms::aria_label || aAttribute == nsGkAtoms::aria_label ||
aAttribute == nsGkAtoms::aria_labelledby) { aAttribute == nsGkAtoms::aria_labelledby) {
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, FireDelayedEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, aAccessible);
aContent);
return; return;
} }
if (aAttribute == nsGkAtoms::aria_busy) { if (aAttribute == nsGkAtoms::aria_busy) {
bool isOn = aContent->AttrValueIs(aNameSpaceID, aAttribute, bool isOn = aAccessible->GetContent()->
nsGkAtoms::_true, eCaseMatters); AttrValueIs(aNameSpaceID, aAttribute, nsGkAtoms::_true, eCaseMatters);
nsRefPtr<AccEvent> event = new AccStateChangeEvent(aContent, states::BUSY, isOn); nsRefPtr<AccEvent> event =
FireDelayedAccessibleEvent(event); new AccStateChangeEvent(aAccessible, states::BUSY, isOn);
FireDelayedEvent(event);
return; return;
} }
// ARIA or XUL selection // ARIA or XUL selection
if ((aContent->IsXUL() && aAttribute == nsGkAtoms::selected) || if ((aAccessible->GetContent()->IsXUL() && aAttribute == nsGkAtoms::selected) ||
aAttribute == nsGkAtoms::aria_selected) { aAttribute == nsGkAtoms::aria_selected) {
Accessible* item = GetAccessible(aContent);
if (!item)
return;
Accessible* widget = Accessible* widget =
nsAccUtils::GetSelectableContainer(item, item->State()); nsAccUtils::GetSelectableContainer(aAccessible, aAccessible->State());
if (widget) { if (widget) {
nsIContent* elm = aAccessible->GetContent();
AccSelChangeEvent::SelChangeType selChangeType = AccSelChangeEvent::SelChangeType selChangeType =
aContent->AttrValueIs(aNameSpaceID, aAttribute, elm->AttrValueIs(aNameSpaceID, aAttribute, nsGkAtoms::_true, eCaseMatters) ?
nsGkAtoms::_true, eCaseMatters) ?
AccSelChangeEvent::eSelectionAdd : AccSelChangeEvent::eSelectionRemove; AccSelChangeEvent::eSelectionAdd : AccSelChangeEvent::eSelectionRemove;
nsRefPtr<AccEvent> event = nsRefPtr<AccEvent> event =
new AccSelChangeEvent(widget, item, selChangeType); new AccSelChangeEvent(widget, aAccessible, selChangeType);
FireDelayedAccessibleEvent(event); FireDelayedEvent(event);
} }
return; return;
} }
if (aAttribute == nsGkAtoms::contenteditable) { if (aAttribute == nsGkAtoms::contenteditable) {
nsRefPtr<AccEvent> editableChangeEvent = nsRefPtr<AccEvent> editableChangeEvent =
new AccStateChangeEvent(aContent, states::EDITABLE); new AccStateChangeEvent(aAccessible, states::EDITABLE);
FireDelayedAccessibleEvent(editableChangeEvent); FireDelayedEvent(editableChangeEvent);
return; return;
} }
if (aAttribute == nsGkAtoms::value) { if (aAttribute == nsGkAtoms::value) {
Accessible* accessible = GetAccessible(aContent); if (aAccessible->IsProgress())
if(accessible && accessible->IsProgress()) { FireDelayedEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, aAccessible);
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
aContent);
}
} }
} }
// DocAccessible protected member // DocAccessible protected member
void void
DocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute) DocAccessible::ARIAAttributeChanged(Accessible* aAccessible, nsIAtom* aAttribute)
{ {
// Note: For universal/global ARIA states and properties we don't care if // Note: For universal/global ARIA states and properties we don't care if
// there is an ARIA role present or not. // there is an ARIA role present or not.
if (aAttribute == nsGkAtoms::aria_required) { if (aAttribute == nsGkAtoms::aria_required) {
nsRefPtr<AccEvent> event = nsRefPtr<AccEvent> event =
new AccStateChangeEvent(aContent, states::REQUIRED); new AccStateChangeEvent(aAccessible, states::REQUIRED);
FireDelayedAccessibleEvent(event); FireDelayedEvent(event);
return; return;
} }
if (aAttribute == nsGkAtoms::aria_invalid) { if (aAttribute == nsGkAtoms::aria_invalid) {
nsRefPtr<AccEvent> event = nsRefPtr<AccEvent> event =
new AccStateChangeEvent(aContent, states::INVALID); new AccStateChangeEvent(aAccessible, states::INVALID);
FireDelayedAccessibleEvent(event); FireDelayedEvent(event);
return; return;
} }
@ -1133,8 +1122,8 @@ DocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
// to the element with the id that activedescendant points to. Make sure // to the element with the id that activedescendant points to. Make sure
// the tree up to date before processing. // the tree up to date before processing.
if (aAttribute == nsGkAtoms::aria_activedescendant) { if (aAttribute == nsGkAtoms::aria_activedescendant) {
mNotificationController->HandleNotification<DocAccessible, nsIContent> mNotificationController->HandleNotification<DocAccessible, Accessible>
(this, &DocAccessible::ARIAActiveDescendantChanged, aContent); (this, &DocAccessible::ARIAActiveDescendantChanged, aAccessible);
return; return;
} }
@ -1142,8 +1131,8 @@ DocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
// We treat aria-expanded as a global ARIA state for historical reasons // We treat aria-expanded as a global ARIA state for historical reasons
if (aAttribute == nsGkAtoms::aria_expanded) { if (aAttribute == nsGkAtoms::aria_expanded) {
nsRefPtr<AccEvent> event = nsRefPtr<AccEvent> event =
new AccStateChangeEvent(aContent, states::EXPANDED); new AccStateChangeEvent(aAccessible, states::EXPANDED);
FireDelayedAccessibleEvent(event); FireDelayedEvent(event);
return; return;
} }
@ -1151,10 +1140,11 @@ DocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
// change event; at least until native API comes up with a more meaningful event. // change event; at least until native API comes up with a more meaningful event.
uint8_t attrFlags = nsAccUtils::GetAttributeCharacteristics(aAttribute); uint8_t attrFlags = nsAccUtils::GetAttributeCharacteristics(aAttribute);
if (!(attrFlags & ATTR_BYPASSOBJ)) if (!(attrFlags & ATTR_BYPASSOBJ))
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_OBJECT_ATTRIBUTE_CHANGED, FireDelayedEvent(nsIAccessibleEvent::EVENT_OBJECT_ATTRIBUTE_CHANGED,
aContent); aAccessible);
if (!aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::role)) { nsIContent* elm = aAccessible->GetContent();
if (!elm->HasAttr(kNameSpaceID_None, nsGkAtoms::role)) {
// We don't care about these other ARIA attribute changes unless there is // We don't care about these other ARIA attribute changes unless there is
// an ARIA role set for the element // an ARIA role set for the element
// XXX: we should check the role map to see if the changed property is // XXX: we should check the role map to see if the changed property is
@ -1165,29 +1155,26 @@ DocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
// The following ARIA attributes only take affect when dynamic content role is present // The following ARIA attributes only take affect when dynamic content role is present
if (aAttribute == nsGkAtoms::aria_checked || if (aAttribute == nsGkAtoms::aria_checked ||
aAttribute == nsGkAtoms::aria_pressed) { aAttribute == nsGkAtoms::aria_pressed) {
const uint32_t kState = (aAttribute == nsGkAtoms::aria_checked) ? const uint64_t kState = (aAttribute == nsGkAtoms::aria_checked) ?
states::CHECKED : states::PRESSED; states::CHECKED : states::PRESSED;
nsRefPtr<AccEvent> event = new AccStateChangeEvent(aContent, kState); nsRefPtr<AccEvent> event = new AccStateChangeEvent(aAccessible, kState);
FireDelayedAccessibleEvent(event); FireDelayedEvent(event);
Accessible* accessible = event->GetAccessible(); bool wasMixed = (mARIAAttrOldValue == nsGkAtoms::mixed);
if (accessible) { bool isMixed = elm->AttrValueIs(kNameSpaceID_None, aAttribute,
bool wasMixed = (mARIAAttrOldValue == nsGkAtoms::mixed); nsGkAtoms::mixed, eCaseMatters);
bool isMixed = aContent->AttrValueIs(kNameSpaceID_None, aAttribute, if (isMixed != wasMixed) {
nsGkAtoms::mixed, eCaseMatters); nsRefPtr<AccEvent> event =
if (isMixed != wasMixed) { new AccStateChangeEvent(aAccessible, states::MIXED, isMixed);
nsRefPtr<AccEvent> event = FireDelayedEvent(event);
new AccStateChangeEvent(aContent, states::MIXED, isMixed);
FireDelayedAccessibleEvent(event);
}
} }
return; return;
} }
if (aAttribute == nsGkAtoms::aria_readonly) { if (aAttribute == nsGkAtoms::aria_readonly) {
nsRefPtr<AccEvent> event = nsRefPtr<AccEvent> event =
new AccStateChangeEvent(aContent, states::READONLY); new AccStateChangeEvent(aAccessible, states::READONLY);
FireDelayedAccessibleEvent(event); FireDelayedEvent(event);
return; return;
} }
@ -1195,23 +1182,22 @@ DocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
// when aria-valuenow is changed and aria-valuetext is empty // when aria-valuenow is changed and aria-valuetext is empty
if (aAttribute == nsGkAtoms::aria_valuetext || if (aAttribute == nsGkAtoms::aria_valuetext ||
(aAttribute == nsGkAtoms::aria_valuenow && (aAttribute == nsGkAtoms::aria_valuenow &&
(!aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_valuetext) || (!elm->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_valuetext) ||
aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_valuetext, elm->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_valuetext,
nsGkAtoms::_empty, eCaseMatters)))) { nsGkAtoms::_empty, eCaseMatters)))) {
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, FireDelayedEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, aAccessible);
aContent);
return; return;
} }
} }
void void
DocAccessible::ARIAActiveDescendantChanged(nsIContent* aElm) DocAccessible::ARIAActiveDescendantChanged(Accessible* aAccessible)
{ {
Accessible* widget = GetAccessible(aElm); nsIContent* elm = aAccessible->GetContent();
if (widget && widget->IsActiveWidget()) { if (elm && aAccessible->IsActiveWidget()) {
nsAutoString id; nsAutoString id;
if (aElm->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_activedescendant, id)) { if (elm->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_activedescendant, id)) {
dom::Element* activeDescendantElm = aElm->OwnerDoc()->GetElementById(id); dom::Element* activeDescendantElm = elm->OwnerDoc()->GetElementById(id);
if (activeDescendantElm) { if (activeDescendantElm) {
Accessible* activeDescendant = GetAccessible(activeDescendantElm); Accessible* activeDescendant = GetAccessible(activeDescendantElm);
if (activeDescendant) { if (activeDescendant) {
@ -1240,31 +1226,32 @@ DocAccessible::ContentStateChanged(nsIDocument* aDocument,
nsIContent* aContent, nsIContent* aContent,
nsEventStates aStateMask) nsEventStates aStateMask)
{ {
Accessible* accessible = GetAccessible(aContent);
if (!accessible)
return;
if (aStateMask.HasState(NS_EVENT_STATE_CHECKED)) { if (aStateMask.HasState(NS_EVENT_STATE_CHECKED)) {
Accessible* item = GetAccessible(aContent); Accessible* widget = accessible->ContainerWidget();
if (item) { if (widget && widget->IsSelect()) {
Accessible* widget = item->ContainerWidget(); AccSelChangeEvent::SelChangeType selChangeType =
if (widget && widget->IsSelect()) { aContent->AsElement()->State().HasState(NS_EVENT_STATE_CHECKED) ?
AccSelChangeEvent::SelChangeType selChangeType = AccSelChangeEvent::eSelectionAdd : AccSelChangeEvent::eSelectionRemove;
aContent->AsElement()->State().HasState(NS_EVENT_STATE_CHECKED) ? nsRefPtr<AccEvent> event =
AccSelChangeEvent::eSelectionAdd : AccSelChangeEvent::eSelectionRemove; new AccSelChangeEvent(widget, accessible, selChangeType);
nsRefPtr<AccEvent> event = new AccSelChangeEvent(widget, item, FireDelayedEvent(event);
selChangeType);
FireDelayedAccessibleEvent(event);
}
} }
} }
if (aStateMask.HasState(NS_EVENT_STATE_INVALID)) { if (aStateMask.HasState(NS_EVENT_STATE_INVALID)) {
nsRefPtr<AccEvent> event = nsRefPtr<AccEvent> event =
new AccStateChangeEvent(aContent, states::INVALID, true); new AccStateChangeEvent(accessible, states::INVALID, true);
FireDelayedAccessibleEvent(event); FireDelayedEvent(event);
} }
if (aStateMask.HasState(NS_EVENT_STATE_VISITED)) { if (aStateMask.HasState(NS_EVENT_STATE_VISITED)) {
nsRefPtr<AccEvent> event = nsRefPtr<AccEvent> event =
new AccStateChangeEvent(aContent, states::TRAVERSED, true); new AccStateChangeEvent(accessible, states::TRAVERSED, true);
FireDelayedAccessibleEvent(event); FireDelayedEvent(event);
} }
} }
@ -1542,8 +1529,8 @@ DocAccessible::NotifyOfLoading(bool aIsReloading)
// Fire state busy change event. Use delayed event since we don't care // Fire state busy change event. Use delayed event since we don't care
// actually if event isn't delivered when the document goes away like a shot. // actually if event isn't delivered when the document goes away like a shot.
nsRefPtr<AccEvent> stateEvent = nsRefPtr<AccEvent> stateEvent =
new AccStateChangeEvent(mDocument, states::BUSY, true); new AccStateChangeEvent(this, states::BUSY, true);
FireDelayedAccessibleEvent(stateEvent); FireDelayedEvent(stateEvent);
} }
void void
@ -1567,7 +1554,7 @@ DocAccessible::DoInitialUpdate()
// a problem then consider to keep event processing per tab document. // a problem then consider to keep event processing per tab document.
if (!IsRoot()) { if (!IsRoot()) {
nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(Parent()); nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(Parent());
ParentDocument()->FireDelayedAccessibleEvent(reorderEvent); ParentDocument()->FireDelayedEvent(reorderEvent);
} }
} }
@ -1747,36 +1734,6 @@ DocAccessible::UpdateAccessibleOnAttrChange(dom::Element* aElement,
return false; return false;
} }
// DocAccessible public member
nsresult
DocAccessible::FireDelayedAccessibleEvent(uint32_t aEventType, nsINode* aNode,
AccEvent::EEventRule aAllowDupes,
EIsFromUserInput aIsFromUserInput)
{
nsRefPtr<AccEvent> event =
new AccEvent(aEventType, aNode, aIsFromUserInput, aAllowDupes);
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
return FireDelayedAccessibleEvent(event);
}
// DocAccessible public member
nsresult
DocAccessible::FireDelayedAccessibleEvent(AccEvent* aEvent)
{
NS_ENSURE_ARG(aEvent);
#ifdef A11Y_LOG
if (logging::IsEnabled(logging::eDocLoad))
logging::DocLoadEventFired(aEvent);
#endif
if (mNotificationController)
mNotificationController->QueueEvent(aEvent);
return NS_OK;
}
void void
DocAccessible::ProcessContentInserted(Accessible* aContainer, DocAccessible::ProcessContentInserted(Accessible* aContainer,
const nsTArray<nsCOMPtr<nsIContent> >* aInsertedContent) const nsTArray<nsCOMPtr<nsIContent> >* aInsertedContent)
@ -1874,9 +1831,7 @@ DocAccessible::UpdateTree(Accessible* aContainer, nsIContent* aChildNode,
Accessible* ancestor = aContainer; Accessible* ancestor = aContainer;
while (ancestor) { while (ancestor) {
if (ancestor->ARIARole() == roles::ALERT) { if (ancestor->ARIARole() == roles::ALERT) {
nsRefPtr<AccEvent> alertEvent = FireDelayedEvent(nsIAccessibleEvent::EVENT_ALERT, ancestor);
new AccEvent(nsIAccessibleEvent::EVENT_ALERT, ancestor);
FireDelayedAccessibleEvent(alertEvent);
break; break;
} }
@ -1892,7 +1847,7 @@ DocAccessible::UpdateTree(Accessible* aContainer, nsIContent* aChildNode,
// Fire reorder event so the MSAA clients know the children have changed. Also // Fire reorder event so the MSAA clients know the children have changed. Also
// the event is used internally by MSAA layer. // the event is used internally by MSAA layer.
FireDelayedAccessibleEvent(reorderEvent); FireDelayedEvent(reorderEvent);
} }
uint32_t uint32_t
@ -1916,11 +1871,8 @@ DocAccessible::UpdateTreeInternal(Accessible* aChild, bool aIsInsert,
// the changes before our processing and we may miss some menupopup // the changes before our processing and we may miss some menupopup
// events. Now we just want to be consistent in content insertion/removal // events. Now we just want to be consistent in content insertion/removal
// handling. // handling.
if (aChild->ARIARole() == roles::MENUPOPUP) { if (aChild->ARIARole() == roles::MENUPOPUP)
nsRefPtr<AccEvent> event = FireDelayedEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END, aChild);
new AccEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END, aChild);
FireDelayedAccessibleEvent(event);
}
} }
// Fire show/hide event. // Fire show/hide event.
@ -1930,23 +1882,19 @@ DocAccessible::UpdateTreeInternal(Accessible* aChild, bool aIsInsert,
else else
event = new AccHideEvent(aChild, node); event = new AccHideEvent(aChild, node);
FireDelayedAccessibleEvent(event); FireDelayedEvent(event);
aReorderEvent->AddSubMutationEvent(event); aReorderEvent->AddSubMutationEvent(event);
if (aIsInsert) { if (aIsInsert) {
roles::Role ariaRole = aChild->ARIARole(); roles::Role ariaRole = aChild->ARIARole();
if (ariaRole == roles::MENUPOPUP) { if (ariaRole == roles::MENUPOPUP) {
// Fire EVENT_MENUPOPUP_START if ARIA menu appears. // Fire EVENT_MENUPOPUP_START if ARIA menu appears.
nsRefPtr<AccEvent> event = FireDelayedEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START, aChild);
new AccEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START, aChild);
FireDelayedAccessibleEvent(event);
} else if (ariaRole == roles::ALERT) { } else if (ariaRole == roles::ALERT) {
// Fire EVENT_ALERT if ARIA alert appears. // Fire EVENT_ALERT if ARIA alert appears.
updateFlags = eAlertAccessible; updateFlags = eAlertAccessible;
nsRefPtr<AccEvent> event = FireDelayedEvent(nsIAccessibleEvent::EVENT_ALERT, aChild);
new AccEvent(nsIAccessibleEvent::EVENT_ALERT, aChild);
FireDelayedAccessibleEvent(event);
} }
// If focused node has been shown then it means its frame was recreated // If focused node has been shown then it means its frame was recreated
@ -1996,8 +1944,7 @@ DocAccessible::CacheChildrenInSubtree(Accessible* aRoot)
if (aRoot->HasARIARole() && !aRoot->IsDoc()) { if (aRoot->HasARIARole() && !aRoot->IsDoc()) {
a11y::role role = aRoot->ARIARole(); a11y::role role = aRoot->ARIARole();
if (role == roles::DIALOG || role == roles::DOCUMENT) if (role == roles::DIALOG || role == roles::DOCUMENT)
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE, FireDelayedEvent(nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE, aRoot);
aRoot->GetContent());
} }
} }

View File

@ -173,22 +173,10 @@ public:
{ return mChildDocuments.SafeElementAt(aIndex, nullptr); } { return mChildDocuments.SafeElementAt(aIndex, nullptr); }
/** /**
* Non-virtual method to fire a delayed event after a 0 length timeout. * Fire accessible event asynchronously.
*
* @param aEventType [in] the nsIAccessibleEvent event type
* @param aDOMNode [in] DOM node the accesible event should be fired for
* @param aAllowDupes [in] rule to process an event (see EEventRule constants)
*/ */
nsresult FireDelayedAccessibleEvent(uint32_t aEventType, nsINode *aNode, void FireDelayedEvent(AccEvent* aEvent);
AccEvent::EEventRule aAllowDupes = AccEvent::eRemoveDupes, void FireDelayedEvent(uint32_t aEventType, Accessible* aTarget);
EIsFromUserInput aIsFromUserInput = eAutoDetect);
/**
* Fire accessible event after timeout.
*
* @param aEvent [in] the event to fire
*/
nsresult FireDelayedAccessibleEvent(AccEvent* aEvent);
/** /**
* Fire value change event on the given accessible if applicable. * Fire value change event on the given accessible if applicable.
@ -398,27 +386,28 @@ protected:
bool UpdateAccessibleOnAttrChange(mozilla::dom::Element* aElement, bool UpdateAccessibleOnAttrChange(mozilla::dom::Element* aElement,
nsIAtom* aAttribute); nsIAtom* aAttribute);
/** /**
* Fires accessible events when attribute is changed. * Fire accessible events when attribute is changed.
* *
* @param aContent - node that attribute is changed for * @param aAccessible [in] accessible the DOM attribute is changed for
* @param aNameSpaceID - namespace of changed attribute * @param aNameSpaceID [in] namespace of changed attribute
* @param aAttribute - changed attribute * @param aAttribute [in] changed attribute
*/ */
void AttributeChangedImpl(nsIContent* aContent, int32_t aNameSpaceID, nsIAtom* aAttribute); void AttributeChangedImpl(Accessible* aAccessible,
int32_t aNameSpaceID, nsIAtom* aAttribute);
/** /**
* Fires accessible events when ARIA attribute is changed. * Fire accessible events when ARIA attribute is changed.
* *
* @param aContent - node that attribute is changed for * @param aAccessible [in] accesislbe the DOM attribute is changed for
* @param aAttribute - changed attribute * @param aAttribute [in] changed attribute
*/ */
void ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute); void ARIAAttributeChanged(Accessible* aAccessible, nsIAtom* aAttribute);
/** /**
* Process ARIA active-descendant attribute change. * Process ARIA active-descendant attribute change.
*/ */
void ARIAActiveDescendantChanged(nsIContent* aElm); void ARIAActiveDescendantChanged(Accessible* aAccessible);
/** /**
* Update the accessible tree for inserted content. * Update the accessible tree for inserted content.

View File

@ -311,8 +311,6 @@ RootAccessible::ProcessDOMEvent(nsIDOMEvent* aDOMEvent)
if (!accessible) if (!accessible)
return; return;
nsINode* targetNode = accessible->GetNode();
#ifdef MOZ_XUL #ifdef MOZ_XUL
XULTreeAccessible* treeAcc = accessible->AsXULTree(); XULTreeAccessible* treeAcc = accessible->AsXULTree();
if (treeAcc) { if (treeAcc) {
@ -383,6 +381,7 @@ RootAccessible::ProcessDOMEvent(nsIDOMEvent* aDOMEvent)
return; return;
} }
nsINode* targetNode = accessible->GetNode();
if (treeItemAcc && eventType.EqualsLiteral("select")) { if (treeItemAcc && eventType.EqualsLiteral("select")) {
// XXX: We shouldn't be based on DOM select event which doesn't provide us // XXX: We shouldn't be based on DOM select event which doesn't provide us
// any context info. We should integrate into nsTreeSelection instead. // any context info. We should integrate into nsTreeSelection instead.
@ -478,10 +477,10 @@ RootAccessible::ProcessDOMEvent(nsIDOMEvent* aDOMEvent)
//We don't process 'ValueChange' events for progress meters since we listen //We don't process 'ValueChange' events for progress meters since we listen
//@value attribute change for them. //@value attribute change for them.
if (!accessible->IsProgress()) if (!accessible->IsProgress()) {
targetDocument-> targetDocument->FireDelayedEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, accessible);
targetNode); }
} }
#ifdef DEBUG_DRAGDROPSTART #ifdef DEBUG_DRAGDROPSTART
else if (eventType.EqualsLiteral("mouseover")) { else if (eventType.EqualsLiteral("mouseover")) {
@ -677,7 +676,7 @@ RootAccessible::HandlePopupHidingEvent(nsINode* aPopupNode)
if (notifyOf & kNotifyOfState) { if (notifyOf & kNotifyOfState) {
nsRefPtr<AccEvent> event = nsRefPtr<AccEvent> event =
new AccStateChangeEvent(widget, states::EXPANDED, false); new AccStateChangeEvent(widget, states::EXPANDED, false);
document->FireDelayedAccessibleEvent(event); document->FireDelayedEvent(event);
} }
} }

View File

@ -7,7 +7,7 @@
#include "nsAccUtils.h" #include "nsAccUtils.h"
#include "nsARIAMap.h" #include "nsARIAMap.h"
#include "DocAccessible.h" #include "DocAccessible-inl.h"
#include "Role.h" #include "Role.h"
#include "nsIDOMHTMLCollection.h" #include "nsIDOMHTMLCollection.h"
@ -95,7 +95,7 @@ HTMLImageMapAccessible::UpdateChildAreas(bool aDoFireEvents)
if (aDoFireEvents) { if (aDoFireEvents) {
nsRefPtr<AccHideEvent> event = new AccHideEvent(area, area->GetContent()); nsRefPtr<AccHideEvent> event = new AccHideEvent(area, area->GetContent());
mDoc->FireDelayedAccessibleEvent(event); mDoc->FireDelayedEvent(event);
reorderEvent->AddSubMutationEvent(event); reorderEvent->AddSubMutationEvent(event);
doReorderEvent = true; doReorderEvent = true;
} }
@ -121,7 +121,7 @@ HTMLImageMapAccessible::UpdateChildAreas(bool aDoFireEvents)
if (aDoFireEvents) { if (aDoFireEvents) {
nsRefPtr<AccShowEvent> event = new AccShowEvent(area, areaContent); nsRefPtr<AccShowEvent> event = new AccShowEvent(area, areaContent);
mDoc->FireDelayedAccessibleEvent(event); mDoc->FireDelayedEvent(event);
reorderEvent->AddSubMutationEvent(event); reorderEvent->AddSubMutationEvent(event);
doReorderEvent = true; doReorderEvent = true;
} }
@ -130,7 +130,7 @@ HTMLImageMapAccessible::UpdateChildAreas(bool aDoFireEvents)
// Fire reorder event if needed. // Fire reorder event if needed.
if (doReorderEvent) if (doReorderEvent)
mDoc->FireDelayedAccessibleEvent(reorderEvent); mDoc->FireDelayedEvent(reorderEvent);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -45,7 +45,7 @@ nsAccEvent::GetDOMNode(nsIDOMNode** aDOMNode)
NS_ENSURE_ARG_POINTER(aDOMNode); NS_ENSURE_ARG_POINTER(aDOMNode);
*aDOMNode = nullptr; *aDOMNode = nullptr;
nsINode* node = mEvent->GetNode(); nsINode* node = mEvent->GetAccessible()->GetNode();
if (node) if (node)
CallQueryInterface(node, aDOMNode); CallQueryInterface(node, aDOMNode);

View File

@ -6,6 +6,7 @@
#include "XULTreeAccessible.h" #include "XULTreeAccessible.h"
#include "DocAccessible-inl.h"
#include "nsAccCache.h" #include "nsAccCache.h"
#include "nsAccUtils.h" #include "nsAccUtils.h"
#include "nsCoreUtils.h" #include "nsCoreUtils.h"
@ -663,7 +664,7 @@ XULTreeAccessible::TreeViewChanged(nsITreeView* aView)
// show/hide events on tree items because it can be expensive to fire them for // show/hide events on tree items because it can be expensive to fire them for
// each tree item. // each tree item.
nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(this); nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(this);
Document()->FireDelayedAccessibleEvent(reorderEvent); Document()->FireDelayedEvent(reorderEvent);
// Clear cache. // Clear cache.
ClearCache(mAccessibleCache); ClearCache(mAccessibleCache);

View File

@ -58,7 +58,7 @@
if (!MAC) { // Mac failure is bug 541093 if (!MAC) { // Mac failure is bug 541093
var checker = var checker =
new eventFromInputChecker(EVENT_TEXT_CARET_MOVED, id, "false", noTargetId); new eventFromInputChecker(EVENT_TEXT_CARET_MOVED, id, "true", noTargetId);
gQueue.push(new synthHomeKey(id, checker)); gQueue.push(new synthHomeKey(id, checker));
} }