Bug 391846. Fire correct text change events when a node is shown or hidden. r=surkov, sr=sicking, a=sicking

git-svn-id: svn://10.0.0.236/trunk@233243 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
aaronleventhal%moonset.net 2007-08-28 21:57:53 +00:00
parent f8270d4e58
commit 7e62128d84
13 changed files with 214 additions and 162 deletions

View File

@ -98,8 +98,8 @@ interface nsIAccessibilityService : nsIAccessibleRetrieval
* EVENT_HIDE (destroy or hide)
*/
void invalidateSubtreeFor(in nsIPresShell aPresShell,
in nsIContent aChangedContent,
in PRUint32 aEvent);
in nsIContent aChangedContent,
in PRUint32 aEvent);
};

View File

@ -553,6 +553,11 @@ interface nsIAccessibleTextChangeEvent : nsIAccessibleEvent
* Returns true if text was inserted, otherwise false.
*/
boolean isInserted();
/**
* The inserted or removed text
*/
readonly attribute DOMString modifiedText;
};
[scriptable, uuid(b9076dce-4cd3-4e3d-a7f6-7f33a7f40c31)]

View File

@ -1804,11 +1804,14 @@ NS_IMETHODIMP nsAccessibilityService::InvalidateSubtreeFor(nsIPresShell *aShell,
{
NS_ASSERTION(aEvent == nsIAccessibleEvent::EVENT_ASYNCH_SIGNIFICANT_CHANGE ||
aEvent == nsIAccessibleEvent::EVENT_ASYNCH_SHOW ||
aEvent == nsIAccessibleEvent::EVENT_ASYNCH_HIDE,
aEvent == nsIAccessibleEvent::EVENT_ASYNCH_HIDE ||
aEvent == nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE ||
aEvent == nsIAccessibleEvent::EVENT_DOM_CREATE ||
aEvent == nsIAccessibleEvent::EVENT_DOM_DESTROY,
"Incorrect aEvent passed in");
NS_ENSURE_ARG_POINTER(aShell);
nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(aShell));
NS_ASSERTION(aShell, "No pres shell in call to InvalidateSubtreeFor");
nsCOMPtr<nsIAccessibleDocument> accessibleDoc =
nsAccessNode::GetDocAccessibleFor(weakShell);
nsCOMPtr<nsPIAccessibleDocument> privateAccessibleDoc =

View File

@ -394,11 +394,16 @@ NS_IMPL_ISUPPORTS_INHERITED1(nsAccTextChangeEvent, nsAccEvent,
nsAccTextChangeEvent::
nsAccTextChangeEvent(nsIAccessible *aAccessible,
PRInt32 aStart, PRUint32 aLength, PRBool aIsInserted):
PRInt32 aStart, PRUint32 aLength, PRBool aIsInserted, PRBool aIsAsynch):
nsAccEvent(aIsInserted ? nsIAccessibleEvent::EVENT_TEXT_INSERTED : nsIAccessibleEvent::EVENT_TEXT_REMOVED,
aAccessible, nsnull),
aAccessible, nsnull, aIsAsynch),
mStart(aStart), mLength(aLength), mIsInserted(aIsInserted)
{
nsCOMPtr<nsIAccessibleText> textAccessible = do_QueryInterface(aAccessible);
NS_ASSERTION(textAccessible, "Should not be firing test change event for non-text accessible!!!");
if (textAccessible) {
textAccessible->GetText(aStart, aStart + aLength, mModifiedText);
}
}
NS_IMETHODIMP
@ -422,6 +427,13 @@ nsAccTextChangeEvent::IsInserted(PRBool *aIsInserted)
return NS_OK;
}
NS_IMETHODIMP
nsAccTextChangeEvent::GetModifiedText(nsAString& aModifiedText)
{
aModifiedText = mModifiedText;
return NS_OK;
}
// nsAccCaretMoveEvent
NS_IMPL_ISUPPORTS_INHERITED1(nsAccCaretMoveEvent, nsAccEvent,
nsIAccessibleCaretMoveEvent)

View File

@ -46,6 +46,8 @@
#include "nsIAccessible.h"
#include "nsIAccessibleDocument.h"
#include "nsIDOMNode.h"
#include "nsString.h"
class nsIPresShell;
class nsAccEvent: public nsIAccessibleEvent
@ -128,8 +130,8 @@ class nsAccTextChangeEvent: public nsAccEvent,
public nsIAccessibleTextChangeEvent
{
public:
nsAccTextChangeEvent(nsIAccessible *aAccessible,
PRInt32 aStart, PRUint32 aLength, PRBool aIsInserted);
nsAccTextChangeEvent(nsIAccessible *aAccessible, PRInt32 aStart, PRUint32 aLength,
PRBool aIsInserted, PRBool aIsAsynch = PR_FALSE);
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_NSIACCESSIBLEEVENT(nsAccEvent::)
@ -139,6 +141,7 @@ private:
PRInt32 mStart;
PRUint32 mLength;
PRBool mIsInserted;
nsString mModifiedText;
};
class nsAccCaretMoveEvent: public nsAccEvent,

View File

@ -1149,9 +1149,6 @@ void nsDocAccessible::ContentAppended(nsIDocument *aDocument,
PRUint32 childCount = aContainer->GetChildCount();
for (PRUint32 index = aNewIndexInContainer; index < childCount; index ++) {
nsCOMPtr<nsIContent> child(aContainer->GetChildAt(index));
FireTextChangedEventOnDOMNodeInserted(child, aContainer, index);
// InvalidateCacheSubtree will not fire the EVENT_SHOW for the new node
// 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
@ -1184,8 +1181,6 @@ void
nsDocAccessible::ContentInserted(nsIDocument *aDocument, nsIContent* aContainer,
nsIContent* aChild, PRInt32 aIndexInContainer)
{
FireTextChangedEventOnDOMNodeInserted(aChild, aContainer, aIndexInContainer);
// InvalidateCacheSubtree will not fire the EVENT_SHOW for the new node
// 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
@ -1197,10 +1192,11 @@ void
nsDocAccessible::ContentRemoved(nsIDocument *aDocument, nsIContent* aContainer,
nsIContent* aChild, PRInt32 aIndexInContainer)
{
FireTextChangedEventOnDOMNodeRemoved(aChild, aContainer, aIndexInContainer);
// Invalidate the subtree of the removed element.
InvalidateCacheSubtree(aChild, nsIAccessibleEvent::EVENT_DOM_DESTROY);
// InvalidateCacheSubtree(aChild, nsIAccessibleEvent::EVENT_DOM_DESTROY);
// This is no longer needed, we get our notifications directly from content
// *before* the frame for the content is destroyed, or any other side effects occur.
// That allows us to correctly calculate the TEXT_REMOVED event if there is one.
}
void
@ -1256,122 +1252,82 @@ nsDocAccessible::FireTextChangedEventOnDOMCharacterDataModified(nsIContent *aCon
}
}
void
nsDocAccessible::FireTextChangedEventOnDOMNodeInserted(nsIContent *aChild,
nsIContent *aContainer,
PRInt32 aIndexInContainer)
already_AddRefed<nsIAccessibleTextChangeEvent>
nsDocAccessible::CreateTextChangeEventForNode(nsIAccessible *aContainerAccessible,
nsIDOMNode *aChangeNode,
nsIAccessible *aAccessibleForChangeNode,
PRBool aIsInserting,
PRBool aIsAsynch)
{
if (!mIsContentLoaded || !mDocument) {
return;
nsRefPtr<nsHyperTextAccessible> textAccessible;
aContainerAccessible->QueryInterface(NS_GET_IID(nsHyperTextAccessible),
getter_AddRefs(textAccessible));
if (!textAccessible) {
return nsnull;
}
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(aChild));
if (!node)
return;
PRInt32 offset;
PRInt32 length = 0;
nsCOMPtr<nsIAccessible> changeAccessible;
nsresult rv = textAccessible->DOMPointToHypertextOffset(aChangeNode, -1, &offset,
getter_AddRefs(changeAccessible));
NS_ENSURE_SUCCESS(rv, nsnull);
nsCOMPtr<nsIAccessible> accessible;
nsresult rv = GetAccessibleInParentChain(node, getter_AddRefs(accessible));
if (NS_FAILED(rv) || !accessible)
return;
nsRefPtr<nsHyperTextAccessible> textAccessible;
rv = accessible->QueryInterface(NS_GET_IID(nsHyperTextAccessible),
getter_AddRefs(textAccessible));
if (NS_FAILED(rv) || !textAccessible)
return;
PRUint32 length = 1;
if (aChild && aChild->IsNodeOfType(nsINode::eTEXT)) {
length = aChild->TextLength();
if (!length)
return;
} else {
// Don't fire event for the first html:br in an editor.
nsCOMPtr<nsIEditor> editor;
textAccessible->GetAssociatedEditor(getter_AddRefs(editor));
if (editor) {
PRBool isEmpty = PR_FALSE;
editor->GetDocumentIsEmpty(&isEmpty);
if (isEmpty)
return;
if (!aAccessibleForChangeNode) {
// A span-level object or something else without an accessible is being removed, where
// it has no accessible but it has descendant content which is aggregated as text
// into the parent hypertext.
// In this case, accessibleToBeRemoved may just be the first
// accessible that is removed, which affects the text in the hypertext container
if (!changeAccessible) {
return nsnull; // No descendant content that represents any text in the hypertext parent
}
nsCOMPtr<nsIAccessible> child = changeAccessible;
while (PR_TRUE) {
nsCOMPtr<nsIAccessNode> childAccessNode =
do_QueryInterface(changeAccessible);
nsCOMPtr<nsIDOMNode> childNode;
childAccessNode->GetDOMNode(getter_AddRefs(childNode));
if (!nsAccUtils::IsAncestorOf(aChangeNode, childNode)) {
break; // We only want accessibles with DOM nodes as children of this node
}
length += TextLength(child);
child->GetNextSibling(getter_AddRefs(changeAccessible));
if (!changeAccessible) {
break;
}
child.swap(changeAccessible);
}
}
else {
NS_ASSERTION(changeAccessible == aAccessibleForChangeNode,
"Hypertext is reporting a different accessible for this node");
length = TextLength(aAccessibleForChangeNode);
if (Role(aAccessibleForChangeNode) == nsIAccessibleRole::ROLE_WHITESPACE) { // newline
// Don't fire event for the first html:br in an editor.
nsCOMPtr<nsIEditor> editor;
textAccessible->GetAssociatedEditor(getter_AddRefs(editor));
if (editor) {
PRBool isEmpty = PR_FALSE;
editor->GetDocumentIsEmpty(&isEmpty);
if (isEmpty) {
return nsnull;
}
}
}
}
nsCOMPtr<nsIDOMNode> parentNode(do_QueryInterface(aContainer));
if (!parentNode)
return;
PRInt32 offset = 0;
rv = textAccessible->DOMPointToHypertextOffset(parentNode, aIndexInContainer, &offset);
if (NS_FAILED(rv))
return;
nsCOMPtr<nsIAccessibleTextChangeEvent> event =
new nsAccTextChangeEvent(accessible, offset, length, PR_TRUE);
if (!event)
return;
textAccessible->FireAccessibleEvent(event);
}
void
nsDocAccessible::FireTextChangedEventOnDOMNodeRemoved(nsIContent *aChild,
nsIContent *aContainer,
PRInt32 aIndexInContainer)
{
if (!mIsContentLoaded || !mDocument) {
return;
if (length <= 0) {
return nsnull;
}
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(aChild));
if (!node)
return;
nsIAccessibleTextChangeEvent *event =
new nsAccTextChangeEvent(aContainerAccessible, offset, length, aIsInserting, aIsAsynch);
NS_IF_ADDREF(event);
nsCOMPtr<nsIAccessible> accessible;
nsresult rv = GetAccessibleInParentChain(node, getter_AddRefs(accessible));
if (NS_FAILED(rv) || !accessible)
return;
nsRefPtr<nsHyperTextAccessible> textAccessible;
rv = accessible->QueryInterface(NS_GET_IID(nsHyperTextAccessible),
getter_AddRefs(textAccessible));
if (NS_FAILED(rv) || !textAccessible)
return;
PRUint32 length = 1;
if (aChild && aChild->IsNodeOfType(nsINode::eTEXT)) {
length = aChild->TextLength();
if (!length)
return;
} else {
// Don't fire event for the last html:br in an editor.
nsCOMPtr<nsIEditor> editor;
textAccessible->GetAssociatedEditor(getter_AddRefs(editor));
if (editor) {
PRBool isEmpty = PR_FALSE;
editor->GetDocumentIsEmpty(&isEmpty);
if (isEmpty)
return;
}
}
nsCOMPtr<nsIDOMNode> parentNode(do_QueryInterface(aContainer));
if (!parentNode)
return;
PRInt32 offset = 0;
rv = textAccessible->DOMPointToHypertextOffset(parentNode, aIndexInContainer, &offset);
if (NS_FAILED(rv))
return;
nsCOMPtr<nsIAccessibleTextChangeEvent> event =
new nsAccTextChangeEvent(accessible, offset, length, PR_FALSE);
if (!event)
return;
textAccessible->FireAccessibleEvent(event);
return event;
}
nsresult nsDocAccessible::FireDelayedToolkitEvent(PRUint32 aEvent,
nsIDOMNode *aDOMNode,
void *aData,
@ -1492,9 +1448,38 @@ NS_IMETHODIMP nsDocAccessible::FlushPendingEvents()
nsCOMPtr<nsIAccessible> accessible;
accessibleEvent->GetAccessible(getter_AddRefs(accessible));
PRUint32 eventType;
accessibleEvent->GetEventType(&eventType);
if (eventType == nsIAccessibleEvent::EVENT_DOM_CREATE ||
eventType == nsIAccessibleEvent::EVENT_ASYNCH_SHOW) {
// Also fire text changes if the node being created could affect the text in an nsIAccessibleText parent.
// When a node is being made visible or is inserted, the text in an ancestor hyper text will gain characters
// At this point we now have the frame and accessible for this node if there is one. That is why we
// wait to fire this here, instead of in InvalidateCacheSubtree(), where we wouldn't be able to calculate
// the offset, length and text for the text change.
nsCOMPtr<nsIDOMNode> domNode;
accessibleEvent->GetDOMNode(getter_AddRefs(domNode));
if (domNode && domNode != mDOMNode) {
nsCOMPtr<nsIAccessible> containerAccessible;
GetAccessibleInParentChain(domNode, getter_AddRefs(containerAccessible));
nsCOMPtr<nsIAccessibleTextChangeEvent> textChangeEvent =
CreateTextChangeEventForNode(containerAccessible, domNode, accessible, PR_TRUE, PR_TRUE);
if (textChangeEvent) {
PRBool isFromUserInput;
accessibleEvent->GetIsFromUserInput(&isFromUserInput);
nsCOMPtr<nsIDOMNode> hyperTextNode;
textChangeEvent->GetDOMNode(getter_AddRefs(hyperTextNode));
nsAccEvent::PrepareForEvent(hyperTextNode, isFromUserInput);
// XXX Queue them up and merge the text change events
// XXX We need a way to ignore SplitNode and JoinNode() when they
// do not affect the text within the hypertext
FireAccessibleEvent(textChangeEvent);
}
}
}
if (accessible) {
PRUint32 eventType;
accessibleEvent->GetEventType(&eventType);
if (eventType == nsIAccessibleEvent::EVENT_INTERNAL_LOAD) {
nsCOMPtr<nsPIAccessibleDocument> docAccessible =
do_QueryInterface(accessible);
@ -1534,6 +1519,14 @@ NS_IMETHODIMP nsDocAccessible::FlushPendingEvents()
// Post event processing
if (eventType == nsIAccessibleEvent::EVENT_ASYNCH_HIDE ||
eventType == nsIAccessibleEvent::EVENT_DOM_DESTROY) {
// Invalidate children
nsCOMPtr<nsIAccessible> containerAccessible;
accessible->GetParent(getter_AddRefs(containerAccessible));
nsCOMPtr<nsPIAccessible> privateContainerAccessible =
do_QueryInterface(containerAccessible);
if (privateContainerAccessible) {
privateContainerAccessible->InvalidateChildren();
}
// Shutdown nsIAccessNode's or nsIAccessibles for any DOM nodes in this subtree
nsCOMPtr<nsIDOMNode> hidingNode;
accessibleEvent->GetDOMNode(getter_AddRefs(hidingNode));
@ -1702,6 +1695,12 @@ NS_IMETHODIMP nsDocAccessible::InvalidateCacheSubtree(nsIContent *aChild,
}
#endif
nsCOMPtr<nsIAccessible> containerAccessible;
GetAccessibleInParentChain(childNode, getter_AddRefs(containerAccessible));
if (!containerAccessible) {
containerAccessible = this;
}
if (!isShowing) {
// Fire EVENT_ASYNCH_HIDE or EVENT_DOM_DESTROY if previous accessible existed for node being hidden.
// Fire this before the accessible goes away.
@ -1713,6 +1712,19 @@ NS_IMETHODIMP nsDocAccessible::InvalidateCacheSubtree(nsIContent *aChild,
NS_ENSURE_TRUE(removalEvent, NS_ERROR_OUT_OF_MEMORY);
FireDelayedAccessibleEvent(removalEvent, eCoalesceFromSameSubtree, isAsynch);
}
if (childNode != mDOMNode) { // Fire text change unless the node being removed is for this doc
// When a node is hidden or removed, the text in an ancestor hyper text will lose characters
// At this point we still have the frame and accessible for this node if there was one
// XXX Collate events when a range is deleted
// XXX We need a way to ignore SplitNode and JoinNode() when they
// do not affect the text within the hypertext
nsCOMPtr<nsIAccessibleTextChangeEvent> textChangeEvent =
CreateTextChangeEventForNode(containerAccessible, childNode, childAccessible,
PR_FALSE, isAsynch);
if (textChangeEvent) {
FireAccessibleEvent(textChangeEvent);
}
}
}
// We need to get an accessible for the mutation event's container node
@ -1722,18 +1734,12 @@ NS_IMETHODIMP nsDocAccessible::InvalidateCacheSubtree(nsIContent *aChild,
// We're guaranteed success, because we will eventually end up at the doc accessible,
// and there is always one of those.
nsCOMPtr<nsIAccessible> containerAccessible;
GetAccessibleInParentChain(childNode, getter_AddRefs(containerAccessible));
if (!containerAccessible) {
containerAccessible = this;
}
nsCOMPtr<nsPIAccessible> privateContainerAccessible =
do_QueryInterface(containerAccessible);
if (privateContainerAccessible) {
privateContainerAccessible->InvalidateChildren();
}
if (aChild && !isHiding) {
nsCOMPtr<nsPIAccessible> privateContainerAccessible =
do_QueryInterface(containerAccessible);
if (privateContainerAccessible) {
privateContainerAccessible->InvalidateChildren();
}
// 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,

View File

@ -107,7 +107,7 @@ class nsDocAccessible : public nsHyperTextAccessibleWrap,
/**
* Non-virtual method to fire a delayed event after a 0 length timeout
*
* @param aEvent - the nsIAccessibleEvent event ype
* @param aEvent - the nsIAccessibleEvent event type
* @param aDOMNode - DOM node the accesible event should be fired for
* @param aData - any additional data for the event
* @param aAllowDupes - eAllowDupes: more than one event of the same type is allowed.
@ -161,21 +161,20 @@ class nsDocAccessible : public nsHyperTextAccessibleWrap,
*/
void FireTextChangedEventOnDOMCharacterDataModified(nsIContent *aContent,
CharacterDataChangeInfo* aInfo);
/**
* Fire text changed event for the inserted element if it is inside a text
* accessible.
*/
void FireTextChangedEventOnDOMNodeInserted(nsIContent *aChild,
nsIContent *aContainer,
PRInt32 aIndexInContainer);
/**
* Fire text changed event for the removed element if it is inside a text
* accessible.
* Create a text change event for a changed node
* @param aContainerAccessible, the first accessible in the container
* @param aChangeNode, the node that is being inserted or removed, or shown/hidden
* @param aAccessibleForChangeNode, the accessible for that node, or nsnull if none exists
* @param aIsInserting, is aChangeNode being created or shown (vs. removed or hidden)
*/
void FireTextChangedEventOnDOMNodeRemoved(nsIContent *aChild,
nsIContent *aContainer,
PRInt32 aIndexInContainer);
already_AddRefed<nsIAccessibleTextChangeEvent>
nsDocAccessible::CreateTextChangeEventForNode(nsIAccessible *aContainerAccessible,
nsIDOMNode *aChangeNode,
nsIAccessible *aAccessibleForNode,
PRBool aIsInserting,
PRBool aIsAsynch);
nsAccessNodeHashtable mAccessNodeCache;
void *mWnd;

View File

@ -62,9 +62,9 @@ NS_IMETHODIMP nsHTMLTextAccessible::GetName(nsAString& aName)
NS_IMETHODIMP nsHTMLTextAccessible::GetRole(PRUint32 *aRole)
{
nsIFrame *frame = GetFrame();
NS_ENSURE_TRUE(frame, NS_ERROR_NULL_POINTER);
if (frame->IsGeneratedContentFrame()) {
// Don't return on null frame -- we still return a role
// after accessible is shutdown/DEFUNCT
if (frame && frame->IsGeneratedContentFrame()) {
*aRole = nsIAccessibleRole::ROLE_STATICTEXT;
return NS_OK;
}

View File

@ -526,7 +526,6 @@ nsresult nsHyperTextAccessible::DOMPointToHypertextOffset(nsIDOMNode* aNode, PRI
NS_ENSURE_ARG_POINTER(aHyperTextOffset);
*aHyperTextOffset = 0;
NS_ENSURE_ARG_POINTER(aNode);
NS_ENSURE_TRUE(aNodeOffset >= 0, NS_ERROR_INVALID_ARG);
if (aFinalAccessible) {
*aFinalAccessible = nsnull;
}
@ -536,7 +535,10 @@ nsresult nsHyperTextAccessible::DOMPointToHypertextOffset(nsIDOMNode* aNode, PRI
unsigned short nodeType;
aNode->GetNodeType(&nodeType);
if (nodeType == nsIDOMNode::TEXT_NODE) {
if (aNodeOffset == -1) {
findNode = aNode;
}
else if (nodeType == nsIDOMNode::TEXT_NODE) {
// For text nodes, aNodeOffset comes in as a character offset
// Text offset will be added at the end, if we find the offset in this hypertext
// We want the "skipped" offset into the text (rendered text without the extra whitespace)
@ -618,6 +620,7 @@ nsresult nsHyperTextAccessible::DOMPointToHypertextOffset(nsIDOMNode* aNode, PRI
NS_ADDREF(*aFinalAccessible = childAccessible);
}
}
return NS_OK;
}

View File

@ -101,6 +101,9 @@ public:
*
* @param aNode - the node to look for
* @param aNodeOffset - the offset to look for
* if -1 just look directly for the node
* if >=0 and aNode is text, this represents a char offset
* if >=0 and aNode is not text, this represents a child node offset
* @param aResultOffset - the character offset into the current
* nsHyperTextAccessible
* @param aFinalAccessible [optional] - returns the accessible child which

View File

@ -89,28 +89,24 @@ nsHyperTextAccessibleWrap::GetModifiedText(PRBool aGetInsertedText,
if (!gTextEvent)
return NS_OK;
PRBool isInserted;
gTextEvent->IsInserted(&isInserted);
if (aGetInsertedText != isInserted)
return NS_OK;
nsCOMPtr<nsIAccessible> targetAcc;
gTextEvent->GetAccessible(getter_AddRefs(targetAcc));
if (targetAcc != this)
return NS_OK;
PRBool isInserted;
gTextEvent->IsInserted(&isInserted);
if (aGetInsertedText != isInserted)
return NS_OK;
nsAutoString text;
PRInt32 offset;
PRUint32 length;
gTextEvent->GetStart(&offset);
gTextEvent->GetLength(&length);
GetText(offset, offset + length, aText);
*aStartOffset = offset;
*aEndOffset = offset + length;
return NS_OK;
return gTextEvent->GetModifiedText(aText);
}

View File

@ -82,6 +82,7 @@ REQUIRES = xpcom \
util \
appshell \
shistory \
accessibility \
$(NULL)
EXPORTS = \

View File

@ -125,6 +125,11 @@
#include "nsIXULDocument.h"
#endif /* MOZ_XUL */
#ifdef ACCESSIBILITY
#include "nsIAccessibilityService.h"
#include "nsIAccessibleEvent.h"
#endif /* ACCESSIBILITY */
#include "nsCycleCollectionParticipant.h"
#include "nsCCUncollectableMarker.h"
#include "nsCycleCollector.h"
@ -2694,6 +2699,22 @@ nsGenericElement::doRemoveChildAt(PRUint32 aIndex, PRBool aNotify,
NS_PRECONDITION(!aParent || aParent->GetCurrentDoc() == aDocument,
"Incorrect aDocument");
#ifdef ACCESSIBILITY
// A11y needs to be notified of content removals first, so accessibility
// events can be fired before any changes occur
if (aNotify && aDocument) {
nsIPresShell *presShell = aDocument->GetPrimaryShell();
if (presShell && presShell->IsAccessibilityActive()) {
nsCOMPtr<nsIAccessibilityService> accService =
do_GetService("@mozilla.org/accessibilityService;1");
if (accService) {
accService->InvalidateSubtreeFor(presShell, aKid,
nsIAccessibleEvent::EVENT_DOM_DESTROY);
}
}
}
#endif
nsMutationGuard::DidMutate();
nsINode* container = NODE_FROM(aParent, aDocument);