зеркало из https://github.com/mozilla/pjs.git
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:
Родитель
d765c4ab2c
Коммит
a549264d0c
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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")) {
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -156,6 +156,8 @@ public:
|
|||
return sUserInputEventDepth > 0;
|
||||
}
|
||||
|
||||
NS_IMETHOD_(PRBool) IsHandlingUserInputExternal() { return IsHandlingUserInput(); }
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsEventStateManager,
|
||||
nsIEventStateManager)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче