Bug 390692. Fix live region support to provide useful information on the node that's being shown or hidden, or has a text change event. r=ginn.chen, sr=roc, a=roc

This commit is contained in:
aaronleventhal@moonset.net 2007-08-10 18:44:44 -07:00
parent 3d937ce26b
commit 4c1685120f
21 changed files with 404 additions and 134 deletions

View File

@ -61,38 +61,41 @@ interface nsIDOMNode;
*
* @status UNDER_REVIEW
*/
[scriptable, uuid(18612bcb-79bd-45c1-92e9-07aded5fd0f5)]
[scriptable, uuid(98f9e2d4-ec22-4601-b927-b9faf7a63248)]
interface nsIAccessibleEvent : nsISupports
{
/**
* An object has been created.
*/
const unsigned long EVENT_CREATE = 0x0001;
const unsigned long EVENT_DOM_CREATE = 0x0001;
/**
* An object has been destroyed.
*/
const unsigned long EVENT_DESTROY = 0x0002;
const unsigned long EVENT_DOM_DESTROY = 0x0002;
/**
* A hidden object is shown.
* An object's properties or content have changed significantly so that the
* type of object has really changed, and therefore the accessible should be
* destroyed or recreated.
*/
const unsigned long EVENT_SHOW = 0x0003;
const unsigned long EVENT_DOM_SIGNIFICANT_CHANGE = 0x0003;
/**
* An object is hidden.
* A hidden object is shown -- this is a layout occurance and is thus asynchronous
*/
const unsigned long EVENT_HIDE = 0x0004;
const unsigned long EVENT_ASYNCH_SHOW = 0x0004;
/**
* A container object has added, removed, or reordered its children.
* An object is hidden -- this is a layout occurance and is thus asynchronous
*/
const unsigned long EVENT_REORDER = 0x0005;
const unsigned long EVENT_ASYNCH_HIDE = 0x0005;
/**
* An object has a new parent object.
* An object had a significant layout change which could affect
* the type of accessible object -- this is a layout occurance and is thus asynchronous
*/
const unsigned long EVENT_PARENT_CHANGE = 0x0006;
const unsigned long EVENT_ASYNCH_SIGNIFICANT_CHANGE = 0x0006;
/**
* The active descendant of a component has changed. The active descendant
@ -498,6 +501,12 @@ interface nsIAccessibleEvent : nsISupports
* May return null if accessible for event has been shut down
*/
readonly attribute nsIDOMNode DOMNode;
/**
* Returns true if the event was caused by explicit user input,
* as opposed to purely originating from a timer or mouse movement
*/
readonly attribute boolean isFromUserInput;
};

View File

@ -1120,8 +1120,10 @@ nsAccessibleWrap::FireAccessibleEvent(nsIAccessibleEvent *aEvent)
// We don't create ATK objects for nsIAccessible plain text leaves,
// just return NS_OK in such case
if (!atkObj) {
NS_ASSERTION(type == nsIAccessibleEvent::EVENT_SHOW ||
type == nsIAccessibleEvent::EVENT_HIDE,
NS_ASSERTION(type == nsIAccessibleEvent::EVENT_ASYNCH_SHOW ||
type == nsIAccessibleEvent::EVENT_ASYNCH_HIDE ||
type == nsIAccessibleEvent::EVENT_DOM_CREATE ||
type == nsIAccessibleEvent::EVENT_DOM_DESTROY,
"Event other than SHOW and HIDE fired for plain text leaves");
return NS_OK;
}
@ -1137,7 +1139,8 @@ nsAccessibleWrap::FireAccessibleEvent(nsIAccessibleEvent *aEvent)
case nsIAccessibleEvent::EVENT_STATE_CHANGE:
return FireAtkStateChangeEvent(aEvent, atkObj);
case nsIAccessibleEvent::EVENT_TEXT_CHANGED:
case nsIAccessibleEvent::EVENT_TEXT_REMOVED:
case nsIAccessibleEvent::EVENT_TEXT_INSERTED:
return FireAtkTextChangedEvent(aEvent, atkObj);
case nsIAccessibleEvent::EVENT_PROPERTY_CHANGED:
@ -1291,10 +1294,12 @@ nsAccessibleWrap::FireAccessibleEvent(nsIAccessibleEvent *aEvent)
*(gint *)eventData);
break;
case nsIAccessibleEvent::EVENT_SHOW:
case nsIAccessibleEvent::EVENT_DOM_CREATE:
case nsIAccessibleEvent::EVENT_ASYNCH_SHOW:
return FireAtkShowHideEvent(aEvent, atkObj, PR_TRUE);
case nsIAccessibleEvent::EVENT_HIDE:
case nsIAccessibleEvent::EVENT_DOM_DESTROY:
case nsIAccessibleEvent::EVENT_ASYNCH_HIDE:
return FireAtkShowHideEvent(aEvent, atkObj, PR_FALSE);
/*
@ -1417,7 +1422,7 @@ nsresult
nsAccessibleWrap::FireAtkTextChangedEvent(nsIAccessibleEvent *aEvent,
AtkObject *aObject)
{
MAI_LOG_DEBUG(("\n\nReceived: EVENT_TEXT_CHANGED\n"));
MAI_LOG_DEBUG(("\n\nReceived: EVENT_TEXT_REMOVED/INSERTED\n"));
nsCOMPtr<nsIAccessibleTextChangeEvent> event =
do_QueryInterface(aEvent);
@ -1516,9 +1521,9 @@ nsAccessibleWrap::FireAtkShowHideEvent(nsIAccessibleEvent *aEvent,
AtkObject *aObject, PRBool aIsAdded)
{
if (aIsAdded)
MAI_LOG_DEBUG(("\n\nReceived: EVENT_SHOW\n"));
MAI_LOG_DEBUG(("\n\nReceived: Show event\n"));
else
MAI_LOG_DEBUG(("\n\nReceived: EVENT_HIDE\n"));
MAI_LOG_DEBUG(("\n\nReceived: Hide event\n"));
nsCOMPtr<nsIAccessible> accessible;
aEvent->GetAccessible(getter_AddRefs(accessible));

View File

@ -1788,9 +1788,9 @@ NS_IMETHODIMP nsAccessibilityService::InvalidateSubtreeFor(nsIPresShell *aShell,
nsIContent *aChangeContent,
PRUint32 aEvent)
{
NS_ASSERTION(aEvent == nsIAccessibleEvent::EVENT_REORDER ||
aEvent == nsIAccessibleEvent::EVENT_SHOW ||
aEvent == nsIAccessibleEvent::EVENT_HIDE,
NS_ASSERTION(aEvent == nsIAccessibleEvent::EVENT_ASYNCH_SIGNIFICANT_CHANGE ||
aEvent == nsIAccessibleEvent::EVENT_ASYNCH_SHOW ||
aEvent == nsIAccessibleEvent::EVENT_ASYNCH_HIDE,
"Incorrect aEvent passed in");
nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(aShell));

View File

@ -168,7 +168,8 @@ nsAccUtils::HasListener(nsIContent *aContent, const nsAString& aEventType)
}
nsresult
nsAccUtils::FireAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible)
nsAccUtils::FireAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible,
PRBool aIsAsynch)
{
NS_ENSURE_ARG(aAccessible);
@ -176,7 +177,7 @@ nsAccUtils::FireAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible)
NS_ASSERTION(pAccessible, "Accessible doesn't implement nsPIAccessible");
nsCOMPtr<nsIAccessibleEvent> event =
new nsAccEvent(aEventType, aAccessible, nsnull);
new nsAccEvent(aEventType, aAccessible, nsnull, aIsAsynch);
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
return pAccessible->FireAccessibleEvent(event);

View File

@ -111,7 +111,8 @@ public:
/**
* Fire accessible event of the given type for the given accessible.
*/
static nsresult FireAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible);
static nsresult FireAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible,
PRBool aIsAsynch = PR_FALSE);
};
#endif

View File

@ -2083,6 +2083,8 @@ nsAccessible::GetAttributes(nsIPersistentProperties **aAttributes)
do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID);
NS_ENSURE_TRUE(attributes, NS_ERROR_OUT_OF_MEMORY);
nsAccEvent::GetLastEventAttributes(mDOMNode, attributes);
nsresult rv = GetAttributesInternal(attributes);
NS_ENSURE_SUCCESS(rv, rv);
@ -2121,17 +2123,13 @@ nsAccessible::GetAttributes(nsIPersistentProperties **aAttributes)
// If accessible is invisible we don't want to calculate group ARIA
// attributes for it.
PRUint32 state = State(this);
if (state & nsIAccessibleStates::STATE_INVISIBLE)
return NS_OK;
PRUint32 role = Role(this);
if (role == nsIAccessibleRole::ROLE_LISTITEM ||
if ((role == nsIAccessibleRole::ROLE_LISTITEM ||
role == nsIAccessibleRole::ROLE_MENUITEM ||
role == nsIAccessibleRole::ROLE_RADIOBUTTON ||
role == nsIAccessibleRole::ROLE_PAGETAB ||
role == nsIAccessibleRole::ROLE_OUTLINEITEM) {
role == nsIAccessibleRole::ROLE_OUTLINEITEM) &&
0 == (State(this) & nsIAccessibleStates::STATE_INVISIBLE)) {
nsCOMPtr<nsIAccessible> parent = GetParent();
NS_ENSURE_TRUE(parent, NS_ERROR_FAILURE);
@ -2721,6 +2719,11 @@ NS_IMETHODIMP nsAccessible::GetAccessibleRelated(PRUint32 aRelationType, nsIAcce
}
break;
}
case nsIAccessibleRelation::RELATION_MEMBER_OF:
{
relatedNode = nsAccEvent::GetLastEventAtomicRegion(mDOMNode);
break;
}
default:
return NS_ERROR_NOT_IMPLEMENTED;
}

View File

@ -37,26 +37,184 @@
* ***** END LICENSE BLOCK ***** */
#include "nsAccessibleEventData.h"
#include "nsAccessibilityAtoms.h"
#include "nsIAccessibilityService.h"
#include "nsIAccessNode.h"
#include "nsIDocument.h"
#include "nsIDOMDocument.h"
#include "nsIEventStateManager.h"
#include "nsIPersistentProperties2.h"
#include "nsIServiceManager.h"
#ifdef MOZ_XUL
#include "nsIDOMXULMultSelectCntrlEl.h"
#include "nsXULTreeAccessible.h"
#endif
PRBool nsAccEvent::gLastEventFromUserInput = PR_FALSE;
nsIDOMNode* nsAccEvent::gLastEventNodeWeak = 0;
NS_IMPL_ISUPPORTS1(nsAccEvent, nsIAccessibleEvent)
nsAccEvent::nsAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible,
void *aEventData):
void *aEventData, PRBool aIsAsynch):
mEventType(aEventType), mAccessible(aAccessible), mEventData(aEventData)
{
CaptureIsFromUserInput(aIsAsynch);
}
nsAccEvent::nsAccEvent(PRUint32 aEventType, nsIDOMNode *aDOMNode,
void *aEventData):
void *aEventData, PRBool aIsAsynch):
mEventType(aEventType), mDOMNode(aDOMNode), mEventData(aEventData)
{
CaptureIsFromUserInput(aIsAsynch);
}
void nsAccEvent::GetLastEventAttributes(nsIDOMNode *aNode,
nsIPersistentProperties *aAttributes)
{
if (aNode != gLastEventNodeWeak) {
return; // Passed-in node doesn't Change the last event's node
}
nsAutoString oldValueUnused;
aAttributes->SetStringProperty(NS_LITERAL_CSTRING("event-from-input"),
gLastEventFromUserInput ? NS_LITERAL_STRING("true") :
NS_LITERAL_STRING("false"),
oldValueUnused);
nsCOMPtr<nsIContent> lastEventContent = do_QueryInterface(aNode);
nsIContent *loopContent = lastEventContent;
nsAutoString atomic, live, relevant, channel, busy;
while (loopContent) {
if (relevant.IsEmpty()) {
loopContent->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::relevant, relevant);
}
if (live.IsEmpty()) {
loopContent->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::live, live);
}
if (channel.IsEmpty()) {
loopContent->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::channel, channel);
}
if (atomic.IsEmpty()) {
loopContent->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::atomic, atomic);
}
if (busy.IsEmpty()) {
loopContent->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::busy, busy);
}
loopContent = loopContent->GetParent();
}
if (!relevant.IsEmpty()) {
aAttributes->SetStringProperty(NS_LITERAL_CSTRING("container-relevant"), relevant, oldValueUnused);
}
if (!live.IsEmpty()) {
aAttributes->SetStringProperty(NS_LITERAL_CSTRING("container-live"), live, oldValueUnused);
}
if (!channel.IsEmpty()) {
aAttributes->SetStringProperty(NS_LITERAL_CSTRING("container-channel"), channel, oldValueUnused);
}
if (!atomic.IsEmpty()) {
aAttributes->SetStringProperty(NS_LITERAL_CSTRING("container-atomic"), atomic, oldValueUnused);
}
if (!busy.IsEmpty()) {
aAttributes->SetStringProperty(NS_LITERAL_CSTRING("container-busy"), busy, oldValueUnused);
}
}
nsIDOMNode* nsAccEvent::GetLastEventAtomicRegion(nsIDOMNode *aNode)
{
if (aNode != gLastEventNodeWeak) {
return nsnull; // Passed-in node doesn't Change the last changed node
}
nsCOMPtr<nsIContent> lastEventContent = do_QueryInterface(aNode);
nsIContent *loopContent = lastEventContent;
nsAutoString atomic;
while (loopContent) {
loopContent->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::atomic, atomic);
if (!atomic.IsEmpty()) {
break;
}
loopContent = loopContent->GetParent();
}
nsCOMPtr<nsIDOMNode> atomicRegion;
if (atomic.EqualsLiteral("true")) {
atomicRegion = do_QueryInterface(loopContent);
}
return atomicRegion;
}
void nsAccEvent::CaptureIsFromUserInput(PRBool aIsAsynch)
{
nsCOMPtr<nsIDOMNode> eventNode;
GetDOMNode(getter_AddRefs(eventNode));
if (!eventNode) {
NS_NOTREACHED("There should always be a DOM node for an event");
return;
}
if (aIsAsynch) {
// Cannot calculate, so use previous value
gLastEventNodeWeak = eventNode;
}
else {
PrepareForEvent(eventNode);
}
mIsFromUserInput = gLastEventFromUserInput;
}
NS_IMETHODIMP
nsAccEvent::GetIsFromUserInput(PRBool *aIsFromUserInput)
{
*aIsFromUserInput = mIsFromUserInput;
return NS_OK;
}
void nsAccEvent::PrepareForEvent(nsIAccessibleEvent *aEvent)
{
nsCOMPtr<nsIDOMNode> eventNode;
aEvent->GetDOMNode(getter_AddRefs(eventNode));
PRBool isFromUserInput;
aEvent->GetIsFromUserInput(&isFromUserInput);
PrepareForEvent(eventNode, isFromUserInput);
}
void nsAccEvent::PrepareForEvent(nsIDOMNode *aEventNode,
PRBool aForceIsFromUserInput)
{
gLastEventNodeWeak = aEventNode;
if (aForceIsFromUserInput) {
gLastEventFromUserInput = PR_TRUE;
return;
}
nsCOMPtr<nsIDOMDocument> domDoc;
aEventNode->GetOwnerDocument(getter_AddRefs(domDoc));
if (!domDoc) { // IF the node is a document itself
domDoc = do_QueryInterface(aEventNode);
}
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
if (!doc) {
NS_NOTREACHED("There should always be a document for an event");
return;
}
nsCOMPtr<nsIPresShell> presShell = doc->GetPrimaryShell();
if (!presShell) {
NS_NOTREACHED("Threre should always be an pres shell for an event");
return;
}
nsIEventStateManager *esm = presShell->GetPresContext()->EventStateManager();
if (!esm) {
NS_NOTREACHED("Threre should always be an ESM for an event");
return;
}
gLastEventFromUserInput = esm->IsHandlingUserInputExternal();
}
NS_IMETHODIMP
@ -234,7 +392,8 @@ NS_IMPL_ISUPPORTS_INHERITED1(nsAccTextChangeEvent, nsAccEvent,
nsAccTextChangeEvent::
nsAccTextChangeEvent(nsIAccessible *aAccessible,
PRInt32 aStart, PRUint32 aLength, PRBool aIsInserted):
nsAccEvent(::nsIAccessibleEvent::EVENT_TEXT_CHANGED, aAccessible, nsnull),
nsAccEvent(aIsInserted ? nsIAccessibleEvent::EVENT_TEXT_INSERTED : nsIAccessibleEvent::EVENT_TEXT_REMOVED,
aAccessible, nsnull),
mStart(aStart), mLength(aLength), mIsInserted(aIsInserted)
{
}
@ -266,14 +425,14 @@ NS_IMPL_ISUPPORTS_INHERITED1(nsAccCaretMoveEvent, nsAccEvent,
nsAccCaretMoveEvent::
nsAccCaretMoveEvent(nsIAccessible *aAccessible, PRInt32 aCaretOffset) :
nsAccEvent(::nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED, aAccessible, nsnull),
nsAccEvent(::nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED, aAccessible, nsnull, PR_TRUE), // Currently always asynch
mCaretOffset(aCaretOffset)
{
}
nsAccCaretMoveEvent::
nsAccCaretMoveEvent(nsIDOMNode *aNode) :
nsAccEvent(::nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED, aNode, nsnull),
nsAccEvent(::nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED, aNode, nsnull, PR_TRUE), // Currently always asynch
mCaretOffset(-1)
{
}

View File

@ -46,29 +46,56 @@
#include "nsIAccessible.h"
#include "nsIAccessibleDocument.h"
#include "nsIDOMNode.h"
class nsIPresShell;
class nsAccEvent: public nsIAccessibleEvent
{
public:
// Initialize with an nsIAccessible
nsAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible, void *aEventData);
nsAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible, void *aEventData, PRBool aIsAsynch = PR_FALSE);
// Initialize with an nsIDOMNode
nsAccEvent(PRUint32 aEventType, nsIDOMNode *aDOMNode, void *aEventData);
nsAccEvent(PRUint32 aEventType, nsIDOMNode *aDOMNode, void *aEventData, PRBool aIsAsynch = PR_FALSE);
virtual ~nsAccEvent() {}
NS_DECL_ISUPPORTS
NS_DECL_NSIACCESSIBLEEVENT
static void GetLastEventAttributes(nsIDOMNode *aNode,
nsIPersistentProperties *aAttributes);
static nsIDOMNode* nsAccEvent::GetLastEventAtomicRegion(nsIDOMNode *aNode);
protected:
already_AddRefed<nsIAccessible> GetAccessibleByNode();
void CaptureIsFromUserInput(PRBool aIsAsynch);
PRBool mIsFromUserInput;
private:
PRUint32 mEventType;
nsCOMPtr<nsIAccessible> mAccessible;
nsCOMPtr<nsIDOMNode> mDOMNode;
nsCOMPtr<nsIAccessibleDocument> mDocAccessible;
static PRBool gLastEventFromUserInput;
static nsIDOMNode* gLastEventNodeWeak;
public:
/**
* Find and cache the last input state. This will be called automatically
* for synchronous events. For asynchronous events it should be
* called from the synchronous code which is the true source of the event,
* before the event is fired.
*/
static void PrepareForEvent(nsIDOMNode *aChangeNode,
PRBool aForceIsFromUserInput = PR_FALSE);
/**
* The input state was previously stored with the nsIAccessibleEvent,
* so use that state now -- call this when about to flush an event that
* was waiting in an event queue
*/
static void PrepareForEvent(nsIAccessibleEvent *aEvent);
void *mEventData;
};

View File

@ -950,6 +950,11 @@ nsDocAccessible::AttributeChanged(nsIDocument *aDocument, nsIContent* aContent,
return;
}
// Since we're in synchronous code, we can store whether the current attribute
// change is from user input or not. If the attribute change causes an asynchronous
// layout change, that event can use the last known user input state
nsAccEvent::PrepareForEvent(targetNode);
// Universal boolean properties that don't require a role.
if (aAttribute == nsAccessibilityAtoms::disabled) {
// Fire the state change whether disabled attribute is
@ -979,14 +984,14 @@ nsDocAccessible::AttributeChanged(nsIDocument *aDocument, nsIContent* aContent,
if (aNameSpaceID == kNameSpaceID_XHTML2_Unofficial ||
aNameSpaceID == kNameSpaceID_XHTML) {
if (aAttribute == nsAccessibilityAtoms::role)
InvalidateCacheSubtree(aContent, nsIAccessibleEvent::EVENT_REORDER);
InvalidateCacheSubtree(aContent, nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE);
return;
}
if (aAttribute == nsAccessibilityAtoms::href ||
aAttribute == nsAccessibilityAtoms::onclick ||
aAttribute == nsAccessibilityAtoms::droppable) {
InvalidateCacheSubtree(aContent, nsIAccessibleEvent::EVENT_REORDER);
InvalidateCacheSubtree(aContent, nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE);
return;
}
@ -1112,7 +1117,7 @@ nsDocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
if (HasRoleAttribute(aContent)) {
// The multiselectable and other waistate attributes only take affect
// when dynamic content role is present
InvalidateCacheSubtree(aContent, nsIAccessibleEvent::EVENT_REORDER);
InvalidateCacheSubtree(aContent, nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE);
}
}
}
@ -1139,7 +1144,7 @@ void nsDocAccessible::ContentAppended(nsIDocument *aDocument,
// unless an accessible can be created for the passed in node, which it
// can't do unless the node is visible. The right thing happens there so
// no need for an extra visibility check here.
InvalidateCacheSubtree(child, nsIAccessibleEvent::EVENT_SHOW);
InvalidateCacheSubtree(child, nsIAccessibleEvent::EVENT_DOM_CREATE);
}
}
@ -1173,7 +1178,7 @@ nsDocAccessible::ContentInserted(nsIDocument *aDocument, nsIContent* aContainer,
// unless an accessible can be created for the passed in node, which it
// can't do unless the node is visible. The right thing happens there so
// no need for an extra visibility check here.
InvalidateCacheSubtree(aChild, nsIAccessibleEvent::EVENT_SHOW);
InvalidateCacheSubtree(aChild, nsIAccessibleEvent::EVENT_DOM_CREATE);
}
void
@ -1183,7 +1188,7 @@ nsDocAccessible::ContentRemoved(nsIDocument *aDocument, nsIContent* aContainer,
FireTextChangedEventOnDOMNodeRemoved(aChild, aContainer, aIndexInContainer);
// Invalidate the subtree of the removed element.
InvalidateCacheSubtree(aChild, nsIAccessibleEvent::EVENT_HIDE);
InvalidateCacheSubtree(aChild, nsIAccessibleEvent::EVENT_DOM_DESTROY);
}
void
@ -1364,17 +1369,20 @@ nsDocAccessible::FireTextChangedEventOnDOMNodeRemoved(nsIContent *aChild,
nsresult nsDocAccessible::FireDelayedToolkitEvent(PRUint32 aEvent,
nsIDOMNode *aDOMNode,
void *aData,
PRBool aAllowDupes)
PRBool aAllowDupes,
PRBool aIsAsynch)
{
nsCOMPtr<nsIAccessibleEvent> event = new nsAccEvent(aEvent, aDOMNode, aData);
nsCOMPtr<nsIAccessibleEvent> event =
new nsAccEvent(aEvent, aDOMNode, aData, PR_TRUE);
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
return FireDelayedAccessibleEvent(event);
return FireDelayedAccessibleEvent(event, aAllowDupes, aIsAsynch);
}
nsresult
nsDocAccessible::FireDelayedAccessibleEvent(nsIAccessibleEvent *aEvent,
PRBool aAllowDupes)
PRBool aAllowDupes,
PRBool aIsAsynch)
{
PRBool isTimerStarted = PR_TRUE;
PRInt32 numQueuedEvents = mEventsToFire.Count();
@ -1390,6 +1398,13 @@ nsDocAccessible::FireDelayedAccessibleEvent(nsIAccessibleEvent *aEvent,
nsCOMPtr<nsIDOMNode> newEventDOMNode;
aEvent->GetDOMNode(getter_AddRefs(newEventDOMNode));
if (!aIsAsynch) {
// If already asynchronous don't call PrepareFromEvent() -- it
// should only be called while ESM still knows if the event occurred
// originally because of user input
nsAccEvent::PrepareForEvent(newEventDOMNode);
}
if (numQueuedEvents == 0) {
isTimerStarted = PR_FALSE;
} else if (!aAllowDupes) {
@ -1470,11 +1485,14 @@ NS_IMETHODIMP nsDocAccessible::FlushPendingEvents()
accessibleText->GetSelectionCount(&selectionCount);
if (selectionCount) { // There's a selection so fire selection change as well
nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED,
accessible);
accessible, PR_TRUE);
}
}
}
else {
// The input state was previously stored with the nsIAccessibleEvent,
// so use that state now when firing the event
nsAccEvent::PrepareForEvent(accessibleEvent);
FireAccessibleEvent(accessibleEvent);
}
}
@ -1490,11 +1508,8 @@ void nsDocAccessible::FlushEventsCallback(nsITimer *aTimer, void *aClosure)
accessibleDoc->FlushPendingEvents();
}
void nsDocAccessible::RefreshNodes(nsIDOMNode *aStartNode, PRUint32 aChangeEvent)
void nsDocAccessible::RefreshNodes(nsIDOMNode *aStartNode)
{
NS_ASSERTION(aChangeEvent != nsIAccessibleEvent::EVENT_SHOW,
"nsDocAccessible::RefreshNodes isn't supposed to work with show event.");
nsCOMPtr<nsIDOMNode> iterNode(aStartNode), nextNode;
nsCOMPtr<nsIAccessNode> accessNode;
@ -1565,11 +1580,26 @@ void nsDocAccessible::RefreshNodes(nsIDOMNode *aStartNode, PRUint32 aChangeEvent
NS_IMETHODIMP nsDocAccessible::InvalidateCacheSubtree(nsIContent *aChild,
PRUint32 aChangeEventType)
{
NS_ASSERTION(aChangeEventType == nsIAccessibleEvent::EVENT_REORDER ||
aChangeEventType == nsIAccessibleEvent::EVENT_SHOW ||
aChangeEventType == nsIAccessibleEvent::EVENT_HIDE,
PRBool isHiding =
aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_HIDE ||
aChangeEventType == nsIAccessibleEvent::EVENT_DOM_DESTROY;
PRBool isShowing =
aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_SHOW ||
aChangeEventType == nsIAccessibleEvent::EVENT_DOM_CREATE;
PRBool isChanging =
aChangeEventType == nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE ||
aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_SIGNIFICANT_CHANGE;
NS_ASSERTION(isChanging || isHiding || isShowing,
"Incorrect aChangeEventType passed in");
PRBool isAsynch =
aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_HIDE ||
aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_SHOW ||
aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_SIGNIFICANT_CHANGE;
// Invalidate cache subtree
// We have to check for accessibles for each dom node by traversing DOM tree
// instead of just the accessible tree, although that would be faster
@ -1591,10 +1621,11 @@ NS_IMETHODIMP nsDocAccessible::InvalidateCacheSubtree(nsIContent *aChild,
return InvalidateChildren();
}
// Update last change state information
nsCOMPtr<nsIAccessNode> childAccessNode;
GetCachedAccessNode(childNode, getter_AddRefs(childAccessNode));
nsCOMPtr<nsIAccessible> childAccessible = do_QueryInterface(childAccessNode);
if (!childAccessible && aChangeEventType != nsIAccessibleEvent::EVENT_HIDE) {
if (!childAccessible && isHiding) {
// If not about to hide it, make sure there's an accessible so we can fire an
// event for it
GetAccService()->GetAccessibleFor(childNode, getter_AddRefs(childAccessible));
@ -1604,28 +1635,35 @@ NS_IMETHODIMP nsDocAccessible::InvalidateCacheSubtree(nsIContent *aChild,
nsAutoString localName;
childNode->GetLocalName(localName);
const char *hasAccessible = childAccessible ? " (acc)" : "";
if (aChangeEventType == nsIAccessibleEvent::EVENT_HIDE) {
if (aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_HIDE) {
printf("[Hide %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
}
else if (aChangeEventType == nsIAccessibleEvent::EVENT_SHOW) {
else if (aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_SHOW) {
printf("[Show %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
}
else if (aChangeEventType == nsIAccessibleEvent::EVENT_REORDER) {
printf("[Reorder %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
else if (aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_SIGNIFICANT_CHANGE) {
printf("[Layout change %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
}
else if (aChangeEventType == nsIAccessibleEvent::EVENT_DOM_CREATE) {
printf("[Create %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
}
else if (aChangeEventType == nsIAccessibleEvent::EVENT_DOM_DESTROY) {
printf("[Destroy %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
}
else if (aChangeEventType == nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE) {
printf("[Type change %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
}
#endif
if (aChangeEventType == nsIAccessibleEvent::EVENT_HIDE ||
aChangeEventType == nsIAccessibleEvent::EVENT_REORDER) {
// Fire EVENT_HIDE if previous accessible existed for node being hidden.
if (!isShowing) {
// Fire EVENT_HIDE or EVENT_DOM_DESTROY if previous accessible existed for node being hidden.
// Fire this before the accessible goes away.
if (childAccessible)
nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_HIDE, childAccessible);
}
// Shutdown nsIAccessNode's or nsIAccessibles for any DOM nodes in this subtree
if (aChangeEventType != nsIAccessibleEvent::EVENT_SHOW) {
RefreshNodes(childNode, aChangeEventType);
if (childAccessible) {
PRUint32 removalEvent = isAsynch ? nsIAccessibleEvent::EVENT_ASYNCH_HIDE : nsIAccessibleEvent::EVENT_DOM_DESTROY;
nsAccUtils::FireAccEvent(removalEvent, childAccessible, isAsynch);
}
// Shutdown nsIAccessNode's or nsIAccessibles for any DOM nodes in this subtree
RefreshNodes(childNode);
}
// We need to get an accessible for the mutation event's container node
@ -1646,46 +1684,35 @@ NS_IMETHODIMP nsDocAccessible::InvalidateCacheSubtree(nsIContent *aChild,
privateContainerAccessible->InvalidateChildren();
}
// Fire an event so the assistive technology knows the objects it is holding onto
// in this part of the subtree are no longer useful and should be released.
// However, they still won't crash if the AT tries to use them, because a stub of the
// object still exists as long as it is refcounted, even from outside of Gecko.
nsCOMPtr<nsIAccessNode> containerAccessNode =
do_QueryInterface(containerAccessible);
if (containerAccessNode) {
nsCOMPtr<nsIDOMNode> containerNode;
containerAccessNode->GetDOMNode(getter_AddRefs(containerNode));
if (containerNode) {
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_REORDER,
containerNode, nsnull);
}
}
if (aChild && (aChangeEventType == nsIAccessibleEvent::EVENT_SHOW ||
aChangeEventType == nsIAccessibleEvent::EVENT_REORDER)) {
if (aChild && !isHiding) {
// Fire EVENT_SHOW, EVENT_MENUPOPUP_START for newly visible content.
// Fire after a short timer, because we want to make sure the view has been
// updated to make this accessible content visible. If we don't wait,
// the assistive technology may receive the event and then retrieve
// nsIAccessibleStates::STATE_INVISIBLE for the event's accessible object.
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_SHOW, childNode, nsnull);
PRUint32 additionEvent = isAsynch ? nsIAccessibleEvent::EVENT_ASYNCH_SHOW :
nsIAccessibleEvent::EVENT_DOM_CREATE;
if (!isAsynch) {
// Calculate "is from user input" while we still synchronous and have the info
nsAccEvent::PrepareForEvent(childNode);
}
FireDelayedToolkitEvent(additionEvent, childNode, nsnull, PR_TRUE, isAsynch);
// Check to see change occured in an ARIA menu, and fire an EVENT_MENUPOPUP_START if it did
nsAutoString role;
if (GetRoleAttribute(aChild, role) &&
StringEndsWith(role, NS_LITERAL_STRING(":menu"), nsCaseInsensitiveStringComparator())) {
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START,
childNode, nsnull);
childNode, nsnull, PR_TRUE, isAsynch);
}
}
// Check to see if change occured inside an alert, and fire an EVENT_ALERT if it did
if (aChangeEventType != nsIAccessibleEvent::EVENT_HIDE) {
// Check to see if change occured inside an alert, and fire an EVENT_ALERT if it did
nsIContent *ancestor = aChild;
nsAutoString role;
while (ancestor) {
if (GetRoleAttribute(ancestor, role) &&
StringEndsWith(role, NS_LITERAL_STRING(":alert"), nsCaseInsensitiveStringComparator())) {
nsCOMPtr<nsIDOMNode> alertNode(do_QueryInterface(ancestor));
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_ALERT, alertNode, nsnull);
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_ALERT, alertNode, nsnull, PR_FALSE, isAsynch);
break;
}
ancestor = ancestor->GetParent();
@ -1755,7 +1782,7 @@ void nsDocAccessible::DocLoadCallback(nsITimer *aTimer, void *aClosure)
docShellTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
if (sameTypeRoot != docShellTreeItem) {
// A frame or iframe has finished loading new content
docAcc->InvalidateCacheSubtree(nsnull, nsIAccessibleEvent::EVENT_REORDER);
docAcc->InvalidateCacheSubtree(nsnull, nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE);
return;
}

View File

@ -99,19 +99,35 @@ class nsDocAccessible : public nsHyperTextAccessibleWrap,
// nsPIAccessNode
NS_IMETHOD_(nsIFrame *) GetFrame(void);
// Non-virtual
/**
* Non-virtual method to fire a delayed event after a 0 length timeout
*
* @param aEvent - the nsIAccessibleEvent event ype
* @param aDOMNode - DOM node the accesible event should be fired for
* @param aData - any additional data for the event
* @param aAllowDupes - set to PR_TRUE if more than one event of the same
* type is allowed. By default this is false and events
* of the same type are discarded (the last one is used)
* @param aIsAsyn - set to PR_TRUE if this is not being called from code
* synchronous with a DOM event
*/
nsresult FireDelayedToolkitEvent(PRUint32 aEvent, nsIDOMNode *aDOMNode,
void *aData, PRBool aAllowDupes = PR_FALSE);
void *aData, PRBool aAllowDupes = PR_FALSE,
PRBool aIsAsynch = PR_FALSE);
/**
* Fire accessible event in timeout.
*
* @param aEvent - the event to fire
* @param aAllowDupes - if false then delayed events of the same type and
* for the same DOM node in the event queue won't
* be fired.
* @param aIsAsych - set to PR_TRUE if this is being called from
* an event asynchronous with the DOM
*/
nsresult FireDelayedAccessibleEvent(nsIAccessibleEvent *aEvent,
PRBool aAllowDupes = PR_FALSE);
PRBool aAllowDupes = PR_FALSE,
PRBool aIsAsynch = PR_FALSE);
void ShutdownChildDocuments(nsIDocShellTreeItem *aStart);
@ -121,7 +137,7 @@ class nsDocAccessible : public nsHyperTextAccessibleWrap,
virtual nsresult RemoveEventListeners();
void AddScrollListener();
void RemoveScrollListener();
void RefreshNodes(nsIDOMNode *aStartNode, PRUint32 aChangeEvent);
void RefreshNodes(nsIDOMNode *aStartNode);
static void ScrollTimerCallback(nsITimer *aTimer, void *aClosure);
void CheckForEditor();
virtual void SetEditor(nsIEditor *aEditor);

View File

@ -425,7 +425,8 @@ void nsRootAccessible::TryFireEarlyLoadEvent(nsIDOMNode *aDocNode)
PRBool nsRootAccessible::FireAccessibleFocusEvent(nsIAccessible *aAccessible,
nsIDOMNode *aNode,
nsIDOMEvent *aFocusEvent,
PRBool aForceEvent)
PRBool aForceEvent,
PRBool aIsAsynch)
{
if (mCaretAccessible) {
nsCOMPtr<nsIDOMNSEvent> nsevent(do_QueryInterface(aFocusEvent));
@ -510,7 +511,7 @@ PRBool nsRootAccessible::FireAccessibleFocusEvent(nsIAccessible *aAccessible,
}
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_FOCUS,
finalFocusNode, nsnull);
finalFocusNode, nsnull, PR_FALSE, aIsAsynch);
return PR_TRUE;
}
@ -607,12 +608,12 @@ nsresult nsRootAccessible::HandleEventWithTarget(nsIDOMEvent* aEvent,
return NS_OK;
}
if (eventType.EqualsLiteral("TreeViewChanged")) {
if (eventType.EqualsLiteral("TreeViewChanged")) { // Always asynch, always from user input
NS_ENSURE_TRUE(localName.EqualsLiteral("tree"), NS_OK);
nsCOMPtr<nsIContent> treeContent = do_QueryInterface(aTargetNode);
nsAccEvent::PrepareForEvent(aTargetNode, PR_TRUE);
return accService->InvalidateSubtreeFor(eventShell, treeContent,
nsIAccessibleEvent::EVENT_REORDER);
nsIAccessibleEvent::EVENT_ASYNCH_SIGNIFICANT_CHANGE);
}
nsCOMPtr<nsIAccessible> accessible;
@ -764,7 +765,7 @@ nsresult nsRootAccessible::HandleEventWithTarget(nsIDOMEvent* aEvent,
// The accessible for it stays the same no matter where it moves.
// AT's expect to get an EVENT_SHOW for the tooltip.
// In event callback the tooltip's accessible will be ready.
event = nsIAccessibleEvent::EVENT_SHOW;
event = nsIAccessibleEvent::EVENT_ASYNCH_SHOW;
}
if (event) {
nsAccUtils::FireAccEvent(event, accessible);
@ -822,13 +823,16 @@ nsresult nsRootAccessible::HandleEventWithTarget(nsIDOMEvent* aEvent,
return NS_OK;
}
}
FireAccessibleFocusEvent(accessible, aTargetNode, aEvent, PR_TRUE);
nsAccEvent::PrepareForEvent(aTargetNode, PR_TRUE); // Always asynch, always from user input
FireAccessibleFocusEvent(accessible, aTargetNode, aEvent, PR_TRUE, PR_TRUE);
}
else if (eventType.EqualsLiteral("DOMMenuBarActive")) {
nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_MENU_START, accessible);
else if (eventType.EqualsLiteral("DOMMenuBarActive")) { // Always asynch, always from user input
nsAccEvent::PrepareForEvent(aTargetNode, PR_TRUE);
nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_MENU_START, accessible, PR_TRUE);
}
else if (eventType.EqualsLiteral("DOMMenuBarInactive")) {
nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_MENU_END, accessible);
else if (eventType.EqualsLiteral("DOMMenuBarInactive")) { // Always asynch, always from user input
nsAccEvent::PrepareForEvent(aTargetNode, PR_TRUE);
nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_MENU_END, accessible, PR_TRUE);
FireCurrentFocusEvent();
}
else if (eventType.EqualsLiteral("ValueChange")) {

View File

@ -101,7 +101,8 @@ class nsRootAccessible : public nsDocAccessibleWrap,
PRBool FireAccessibleFocusEvent(nsIAccessible *aFocusAccessible,
nsIDOMNode *aFocusNode,
nsIDOMEvent *aFocusEvent,
PRBool aForceEvent = PR_FALSE);
PRBool aForceEvent = PR_FALSE,
PRBool aIsAsynch = PR_FALSE);
nsCaretAccessible *GetCaretAccessible();

View File

@ -520,12 +520,17 @@ nsresult nsHyperTextAccessible::DOMPointToHypertextOffset(nsIDOMNode* aNode, PRI
NS_ENSURE_TRUE(parentContent, NS_ERROR_FAILURE);
// findNode could be null if aNodeOffset == # of child nodes, which means one of two things:
// 1) we're at the end of the children, keep findNode = null, so that we get the last possible offset
// 2) there are no children, use parentContent for the node to find. In this case parentContent can't be
// the nsIAccessibleText, because an accesible text must have children
// 2) there are no children and the passed-in node is mDOMNode, which means we're an aempty nsIAccessibleText
// 3) there are no children, and the passed-in node is not mDOMNode -- use parentContent for the node to find
findNode = do_QueryInterface(parentContent->GetChildAt(aNodeOffset));
if (!findNode && !aNodeOffset) {
NS_ASSERTION(!SameCOMIdentity(parentContent, mDOMNode), "Cannot find child for DOMPointToHypertextOffset search");
if (SameCOMIdentity(parentContent, mDOMNode)) {
// There are no children, which means this is an empty nsIAccessibleText, in which
// case we can only be at hypertext offset 0
*aHyperTextOffset = 0;
return NS_OK;
}
findNode = do_QueryInterface(parentContent); // Case #2: there are no children
}
}

View File

@ -1529,7 +1529,8 @@ nsAccessibleWrap::FireAccessibleEvent(nsIAccessibleEvent *aEvent)
// See if we're in a scrollable area with its own window
nsCOMPtr<nsIAccessible> newAccessible;
if (eventType == nsIAccessibleEvent::EVENT_HIDE) {
if (eventType == nsIAccessibleEvent::EVENT_ASYNCH_HIDE ||
eventType == nsIAccessibleEvent::EVENT_DOM_DESTROY) {
// Don't use frame from current accessible when we're hiding that
// accessible.
accessible->GetParent(getter_AddRefs(newAccessible));

View File

@ -46,12 +46,12 @@ const PRUint32 kEVENT_LAST_ENTRY = 0xffffffff;
static const PRUint32 gWinEventMap[] = {
kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent doesn't have 0 constant
kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_CREATE
kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_DESTROY
EVENT_OBJECT_SHOW, // nsIAccessibleEvent::EVENT_SHOW
EVENT_OBJECT_HIDE, // nsIAccessibleEvent::EVENT_HIDE
EVENT_OBJECT_REORDER, // nsIAccessibleEvent::EVENT_REORDER
kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_PARENT_CHANGE
EVENT_OBJECT_SHOW, // nsIAccessibleEvent::EVENT_DOM_CREATE
EVENT_OBJECT_HIDE, // nsIAccessibleEvent::EVENT_DOM_DESTROY
kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE
EVENT_OBJECT_SHOW, // nsIAccessibleEvent::EVENT_ASYNCH_SHOW
EVENT_OBJECT_HIDE, // nsIAccessibleEvent::EVENT_ASYNCH_HIDE
kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_ASYNCH_LAYOUT_CHANGE
IA2_EVENT_ACTIVE_DECENDENT_CHANGED, // nsIAccessibleEvent::EVENT_ACTIVE_DECENDENT_CHANGED
EVENT_OBJECT_FOCUS, // nsIAccessibleEvent::EVENT_FOCUS
EVENT_OBJECT_STATECHANGE, // nsIAccessibleEvent::EVENT_STATE_CHANGE

View File

@ -54,7 +54,8 @@ nsHyperTextAccessibleWrap::FireAccessibleEvent(nsIAccessibleEvent *aEvent)
PRUint32 eventType;
aEvent->GetEventType(&eventType);
if (eventType == nsIAccessibleEvent::EVENT_TEXT_CHANGED) {
if (eventType == nsIAccessibleEvent::EVENT_TEXT_REMOVED ||
eventType == nsIAccessibleEvent::EVENT_TEXT_INSERTED) {
nsCOMPtr<nsIAccessible> accessible;
aEvent->GetAccessible(getter_AddRefs(accessible));
if (accessible) {

View File

@ -52,12 +52,10 @@ class imgIContainer;
/*
* Event state manager interface.
*/
// {9d25327a-7a17-4d19-928c-f7f3ac19b763}
// {fb7516ff-2f01-4893-84e8-e4b282813023}
#define NS_IEVENTSTATEMANAGER_IID \
{ 0x9d25327a, 0x7a17, 0x4d19, \
{ 0x92, 0x8c, 0xf7, 0xf3, 0xac, 0x19, 0xb7, 0x63 } }
{ 0xfb7516ff, 0x2f01, 0x4893, \
{ 0x84, 0xe8, 0xe4, 0xb2, 0x82, 0x81, 0x30, 0x23 } };
#define NS_EVENT_NEEDS_FRAME(event) (!NS_IS_FOCUS_EVENT(event))
@ -145,6 +143,15 @@ public:
NS_IMETHOD ShiftFocus(PRBool aDirection, nsIContent* aStart)=0;
NS_IMETHOD NotifyDestroyPresContext(nsPresContext* aPresContext) = 0;
/**
* Returns true if the current code is being executed as a result of user input.
* This includes timers or anything else that is initiated from user input.
* However, mouse hover events are not counted as user input, nor are
* page load events. If this method is called from asynchronously executed code,
* such as during layout reflows, it will return false.
*/
NS_IMETHOD_(PRBool) IsHandlingUserInputExternal() = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIEventStateManager, NS_IEVENTSTATEMANAGER_IID)

View File

@ -156,6 +156,8 @@ public:
return sUserInputEventDepth > 0;
}
NS_IMETHOD_(PRBool) IsHandlingUserInputExternal() { return IsHandlingUserInput(); }
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsEventStateManager,
nsIEventStateManager)

View File

@ -11133,10 +11133,11 @@ nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent)
PRUint32 event;
if (frame) {
nsIFrame *newFrame = mPresShell->GetPrimaryFrameFor(aContent);
event = newFrame ? nsIAccessibleEvent::EVENT_REORDER : nsIAccessibleEvent::EVENT_HIDE;
event = newFrame ? nsIAccessibleEvent::EVENT_ASYNCH_SIGNIFICANT_CHANGE :
nsIAccessibleEvent::EVENT_ASYNCH_HIDE;
}
else {
event = nsIAccessibleEvent::EVENT_SHOW;
event = nsIAccessibleEvent::EVENT_ASYNCH_SHOW;
}
// A significant enough change occured that this part

View File

@ -1381,8 +1381,8 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
do_GetService("@mozilla.org/accessibilityService;1");
if (accService) {
accService->InvalidateSubtreeFor(mPresShell, aFrame->GetContent(),
isVisible ? nsIAccessibleEvent::EVENT_HIDE :
nsIAccessibleEvent::EVENT_SHOW);
isVisible ? nsIAccessibleEvent::EVENT_ASYNCH_HIDE :
nsIAccessibleEvent::EVENT_ASYNCH_SHOW);
}
}
#endif

View File

@ -3271,7 +3271,7 @@ void nsIPresShell::InvalidateAccessibleSubtree(nsIContent *aContent)
do_GetService("@mozilla.org/accessibilityService;1");
if (accService) {
accService->InvalidateSubtreeFor(this, aContent,
nsIAccessibleEvent::EVENT_REORDER);
nsIAccessibleEvent::EVENT_ASYNCH_SIGNIFICANT_CHANGE);
}
}
}