mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-26 14:46:02 +00:00
Bug 149654. Send accessibility events for DOM mutations, invalidate appropriate parts of accessibility cache based on DOM mutation events. Also fixes bug 74218, implement DOMSubtreeModified event. r=kyle, sr=jst
This commit is contained in:
parent
3a3c81e016
commit
7ae87df2aa
@ -80,6 +80,7 @@ interface nsIAccessible : nsISupports
|
||||
[noscript] void setAccParent(in nsIAccessible aAccParent);
|
||||
[noscript] void setAccFirstChild(in nsIAccessible aAccFirstChild);
|
||||
[noscript] void setAccNextSibling(in nsIAccessible aAccNextSibling);
|
||||
[noscript] void invalidateChildren();
|
||||
[noscript] void fireToolkitEvent(in unsigned long aEvent, in nsIAccessible aTarget, in voidPtr aData);
|
||||
[noscript] void getNativeInterface(out voidPtr aOutAccessible);
|
||||
|
||||
|
@ -43,4 +43,5 @@ interface nsIAccessibleDocument : nsISupports
|
||||
[noscript] readonly attribute voidPtr window;
|
||||
[noscript] nsIAccessNode getCachedAccessNode(in voidPtr aUniqueID);
|
||||
[noscript] void cacheAccessNode(in voidPtr aUniqueID, in nsIAccessNode aAccessNode);
|
||||
[noscript] void destroy();
|
||||
};
|
||||
|
@ -283,7 +283,7 @@ PRIntn PR_CALLBACK nsAccessNode::ClearCacheEntry(nsHashKey *aKey, void *aAccessN
|
||||
nsIAccessNode* accessNode = NS_STATIC_CAST(nsIAccessNode*, aAccessNode);
|
||||
accessNode->Shutdown();
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
return kHashEnumerateRemove;
|
||||
}
|
||||
|
||||
void nsAccessNode::ClearCache(nsSupportsHashtable *aCache)
|
||||
|
@ -762,15 +762,16 @@ nsAccessibilityService::CreateHTMLTextAccessible(nsISupports *aFrame, nsIAccessi
|
||||
nsCOMPtr<nsITextContent> textContent(do_QueryInterface(node));
|
||||
if (textContent) {
|
||||
// If empty text string, don't include in accessible tree
|
||||
// Items with length 0 are already gone, we just need to check for single NBSP's
|
||||
// Items with length 0 are already gone, we also need to check for single NBSP's
|
||||
// or newlines, both of which indicate an empty text object
|
||||
PRInt32 textLength = 0;
|
||||
textContent->GetTextLength(&textLength);
|
||||
if (textLength == 1) {
|
||||
const PRUnichar NBSP = 160;
|
||||
const nsTextFragment *textFrag;
|
||||
textContent->GetText(&textFrag);
|
||||
PRUnichar theChar = textFrag->CharAt(0);
|
||||
if (theChar == NBSP)
|
||||
// Check for NBSP (160) or newline
|
||||
if (theChar == 160 || theChar=='\n')
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsCOMPtr<nsIDOMNode> parentNode;
|
||||
|
@ -209,6 +209,14 @@ NS_IMETHODIMP nsAccessible::SetAccNextSibling(nsIAccessible *aNextSibling)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAccessible::InvalidateChildren()
|
||||
{
|
||||
// Document has transformed, reset our invalid children and child count
|
||||
mAccChildCount = -1;
|
||||
mFirstChild = mNextSibling = mParent = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAccessible::GetAccParent(nsIAccessible ** aAccParent)
|
||||
{
|
||||
if (mParent) {
|
||||
@ -1293,6 +1301,8 @@ NS_IMETHODIMP nsAccessible::GetXULAccName(nsAString& _retval)
|
||||
|
||||
NS_IMETHODIMP nsAccessible::FireToolkitEvent(PRUint32 aEvent, nsIAccessible *aTarget, void * aData)
|
||||
{
|
||||
if (!mWeakShell)
|
||||
return NS_ERROR_FAILURE; // Don't fire event for accessible that has been shut down
|
||||
nsCOMPtr<nsIAccessibleDocument> docAccessible(GetDocAccessible());
|
||||
nsCOMPtr<nsIAccessible> eventHandlingAccessible(do_QueryInterface(docAccessible));
|
||||
if (eventHandlingAccessible) {
|
||||
|
@ -41,9 +41,12 @@
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIDOMNSDocument.h"
|
||||
#include "nsIDOMEventTarget.h"
|
||||
#include "nsIDOMEvent.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIDOMDocumentType.h"
|
||||
#include "nsIDOMNSDocument.h"
|
||||
#include "nsIDOMMutationEvent.h"
|
||||
#ifdef MOZ_XUL
|
||||
#include "nsIXULDocument.h"
|
||||
#endif
|
||||
@ -109,8 +112,9 @@ nsDocAccessible::~nsDocAccessible()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED5(nsDocAccessible, nsAccessible, nsIAccessibleDocument,
|
||||
NS_IMPL_ISUPPORTS_INHERITED6(nsDocAccessible, nsAccessible, nsIAccessibleDocument,
|
||||
nsIAccessibleEventReceiver, nsIWebProgressListener,
|
||||
nsIDOMMutationListener,
|
||||
nsIScrollPositionListener, nsISupportsWeakReference)
|
||||
|
||||
NS_IMETHODIMP nsDocAccessible::AddEventListeners()
|
||||
@ -244,17 +248,34 @@ NS_IMETHODIMP nsDocAccessible::CacheAccessNode(void *aUniqueID, nsIAccessNode *a
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDocAccessible::Destroy()
|
||||
{
|
||||
#ifdef OLD_HASH
|
||||
nsVoidKey key(NS_STATIC_CAST(void*, mWeakShell));
|
||||
gGlobalDocAccessibleCache->Remove(&key);
|
||||
#else
|
||||
gGlobalDocAccessibleCache->Remove(NS_STATIC_CAST(void*, mWeakShell));
|
||||
#endif
|
||||
return Shutdown();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDocAccessible::Shutdown()
|
||||
{
|
||||
if (!mWeakShell) {
|
||||
return NS_OK; // Already shutdown
|
||||
}
|
||||
|
||||
void* presShellKey = NS_STATIC_CAST(void*, mWeakShell);
|
||||
mWeakShell = nsnull; // Avoid reentrancy
|
||||
|
||||
RemoveEventListeners();
|
||||
mScrollWatchTimer = mDocLoadTimer = nsnull;
|
||||
if (mScrollWatchTimer) {
|
||||
mScrollWatchTimer->Cancel();
|
||||
mScrollWatchTimer = nsnull;
|
||||
}
|
||||
if (mDocLoadTimer) {
|
||||
mDocLoadTimer->Cancel();
|
||||
mDocLoadTimer = nsnull;
|
||||
}
|
||||
mWebProgress = nsnull;
|
||||
|
||||
if (mAccessNodeCache) {
|
||||
@ -269,12 +290,6 @@ NS_IMETHODIMP nsDocAccessible::Shutdown()
|
||||
}
|
||||
|
||||
NS_ASSERTION(gGlobalDocAccessibleCache, "Global doc cache does not exist");
|
||||
#ifdef OLD_HASH
|
||||
nsVoidKey key(presShellKey);
|
||||
gGlobalDocAccessibleCache->Remove(&key);
|
||||
#else
|
||||
gGlobalDocAccessibleCache->Remove(presShellKey);
|
||||
#endif
|
||||
mDocument = nsnull;
|
||||
return nsAccessibleWrap::Shutdown();
|
||||
}
|
||||
@ -363,6 +378,29 @@ void nsDocAccessible::AddContentDocListeners()
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
}
|
||||
}
|
||||
|
||||
// add ourself as a mutation event listener
|
||||
// (this slows down mozilla about 3%, but only used when accessibility APIs active)
|
||||
nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(mDocument));
|
||||
NS_ASSERTION(target, "No dom event target for document");
|
||||
nsresult rv = target->AddEventListener(NS_LITERAL_STRING("DOMAttrModified"),
|
||||
this, PR_TRUE);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register listener");
|
||||
rv = target->AddEventListener(NS_LITERAL_STRING("DOMSubtreeModified"),
|
||||
this, PR_TRUE);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register listener");
|
||||
rv = target->AddEventListener(NS_LITERAL_STRING("DOMNodeInserted"),
|
||||
this, PR_TRUE);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register listener");
|
||||
rv = target->AddEventListener(NS_LITERAL_STRING("DOMNodeRemoved"),
|
||||
this, PR_TRUE);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register listener");
|
||||
rv = target->AddEventListener(NS_LITERAL_STRING("DOMNodeInsertedIntoDocument"),
|
||||
this, PR_TRUE);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register listener");
|
||||
rv = target->AddEventListener(NS_LITERAL_STRING("DOMNodeRemovedFromDocument"),
|
||||
this, PR_TRUE);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register listener");
|
||||
}
|
||||
|
||||
void nsDocAccessible::RemoveContentDocListeners()
|
||||
@ -378,13 +416,21 @@ void nsDocAccessible::RemoveContentDocListeners()
|
||||
// Remove scroll position listener
|
||||
nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(mWeakShell));
|
||||
RemoveScrollListener(presShell);
|
||||
|
||||
nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(mDocument));
|
||||
NS_ASSERTION(target, "No dom event target for document");
|
||||
target->RemoveEventListener(NS_LITERAL_STRING("DOMAttrModified"), this, PR_TRUE);
|
||||
target->RemoveEventListener(NS_LITERAL_STRING("DOMSubtreeModified"), this, PR_TRUE);
|
||||
target->RemoveEventListener(NS_LITERAL_STRING("DOMNodeInserted"), this, PR_TRUE);
|
||||
target->RemoveEventListener(NS_LITERAL_STRING("DOMNodeRemoved"), this, PR_TRUE);
|
||||
target->RemoveEventListener(NS_LITERAL_STRING("DOMNodeInsertedIntoDocument"), this, PR_TRUE);
|
||||
target->RemoveEventListener(NS_LITERAL_STRING("DOMNodeRemovedFromDocument"), this, PR_TRUE);
|
||||
}
|
||||
|
||||
void nsDocAccessible::FireDocLoadFinished()
|
||||
{
|
||||
NS_ASSERTION(mDocument, "No Document - Bug 202972");
|
||||
if (!mDocument)
|
||||
return;
|
||||
if (!mDocument || !mWeakShell)
|
||||
return; // Document has been shut down
|
||||
|
||||
// Hook up our new accessible with our parent
|
||||
if (!mParent) {
|
||||
@ -535,8 +581,8 @@ NS_IMETHODIMP nsDocAccessible::OnLocationChange(nsIWebProgress *aWebProgress,
|
||||
{
|
||||
// Load has been verified, it will occur, about to commence
|
||||
|
||||
// We won't fire a "doc finished loading" event on this nsRootAccessible
|
||||
// Instead we fire that on the new nsRootAccessible that is created for the new doc
|
||||
// We won't fire a "doc finished loading" event on this nsDocAccessible
|
||||
// Instead we fire that on the new nsDocAccessible that is created for the new doc
|
||||
mIsNewDocument = PR_FALSE; // We're a doc that's going away
|
||||
|
||||
if (mBusy != eBusyStateLoading) {
|
||||
@ -572,3 +618,187 @@ NS_IMETHODIMP nsDocAccessible::OnSecurityChange(nsIWebProgress *aWebProgress,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// ---------- Mutation event listeners ------------
|
||||
NS_IMETHODIMP nsDocAccessible::NodeInserted(nsIDOMEvent* aEvent)
|
||||
{
|
||||
HandleMutationEvent(aEvent, nsIAccessibleEventReceiver::EVENT_CREATE);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDocAccessible::NodeRemoved(nsIDOMEvent* aEvent)
|
||||
{
|
||||
// The related node for the event will be the parent of the removed node or subtree
|
||||
|
||||
HandleMutationEvent(aEvent, nsIAccessibleEventReceiver::EVENT_DESTROY);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDocAccessible::SubtreeModified(nsIDOMEvent* aEvent)
|
||||
{
|
||||
HandleMutationEvent(aEvent, nsIAccessibleEventReceiver::EVENT_REORDER);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDocAccessible::AttrModified(nsIDOMEvent* aMutationEvent)
|
||||
{
|
||||
// XXX todo
|
||||
// We will probably need to handle special cases here
|
||||
// For example, if an <img>'s usemap attribute is modified
|
||||
// Otherwise it may just be a state change, for example an object changing
|
||||
// its visibility.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDocAccessible::NodeRemovedFromDocument(nsIDOMEvent* aMutationEvent)
|
||||
{
|
||||
// Not implemented yet, see bug 74220
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDocAccessible::NodeInsertedIntoDocument(nsIDOMEvent* aMutationEvent)
|
||||
{
|
||||
|
||||
// Not implemented yet, see bug 74219
|
||||
// This is different from NodeInserted() in that it's fired when
|
||||
// a node is inserted into a document, but isn't necessarily mean that
|
||||
// it's becoming part of the DOM tree.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDocAccessible::HandleEvent(nsIDOMEvent* aEvent)
|
||||
{
|
||||
NS_NOTREACHED("Should be handled by specific methods like NodeInserted, etc.");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDocAccessible::CharacterDataModified(nsIDOMEvent* aMutationEvent)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsDocAccessible::InvalidateCacheSubtree(nsIDOMNode *aStartNode)
|
||||
{
|
||||
// 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
|
||||
// Otherwise we might miss the nsAccessNode's that are not nsAccessible's.
|
||||
|
||||
if (!aStartNode)
|
||||
return;
|
||||
nsCOMPtr<nsIDOMNode> iterNode(aStartNode), nextNode;
|
||||
nsCOMPtr<nsIAccessNode> accessNode;
|
||||
|
||||
do {
|
||||
GetCachedAccessNode(NS_STATIC_CAST(void*, iterNode),
|
||||
getter_AddRefs(accessNode));
|
||||
if (accessNode) {
|
||||
// XXX aaronl todo: accessibles that implement their own subtrees,
|
||||
// like html combo boxes and xul trees, need to shutdown all of their own
|
||||
// children when they override Shutdown()
|
||||
accessNode->Shutdown();
|
||||
}
|
||||
|
||||
iterNode->GetFirstChild(getter_AddRefs(nextNode));
|
||||
if (nextNode) {
|
||||
iterNode = nextNode;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (iterNode == aStartNode)
|
||||
break;
|
||||
iterNode->GetNextSibling(getter_AddRefs(nextNode));
|
||||
if (nextNode) {
|
||||
iterNode = nextNode;
|
||||
continue;
|
||||
}
|
||||
|
||||
do {
|
||||
iterNode->GetParentNode(getter_AddRefs(nextNode));
|
||||
if (!nextNode || nextNode == aStartNode) {
|
||||
return;
|
||||
}
|
||||
nextNode->GetNextSibling(getter_AddRefs(iterNode));
|
||||
if (iterNode)
|
||||
break;
|
||||
iterNode = nextNode;
|
||||
} while (PR_TRUE);
|
||||
}
|
||||
while (iterNode && iterNode != aStartNode);
|
||||
}
|
||||
|
||||
void nsDocAccessible::HandleMutationEvent(nsIDOMEvent *aEvent, PRUint32 aAccessibleEventType)
|
||||
{
|
||||
if (mBusy != eBusyStateDone)
|
||||
return; // We don't want mutation events until doc is fully loaded
|
||||
|
||||
nsCOMPtr<nsIDOMEvent> domEvent(do_QueryInterface(aEvent));
|
||||
nsCOMPtr<nsIDOMEventTarget> domEventTarget;
|
||||
if (domEvent) {
|
||||
domEvent->GetTarget(getter_AddRefs(domEventTarget));
|
||||
}
|
||||
nsCOMPtr<nsIDOMNode> targetNode(do_QueryInterface(domEventTarget));
|
||||
if (!targetNode)
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> subTreeNode;
|
||||
if (aAccessibleEventType == nsIAccessibleEventReceiver::EVENT_CREATE) {
|
||||
// DOMNodeInserted
|
||||
// We'll need to invalidate the child count and cached children of
|
||||
// the direct parent, otherwise no new accessibles will appear at this
|
||||
// place in the tree.
|
||||
// However, don't invalidate the entire subtree - most of it is still good.
|
||||
targetNode->GetParentNode(getter_AddRefs(subTreeNode));
|
||||
NS_ASSERTION(subTreeNode, "No valid parent of insertion");
|
||||
targetNode = subTreeNode;
|
||||
}
|
||||
else {
|
||||
if (aAccessibleEventType == nsIAccessibleEventReceiver::EVENT_REORDER) {
|
||||
// DOMSubtreeModified
|
||||
// The event target is the parent of the reordered tree
|
||||
// We don't want to invalidate that entire subtree.
|
||||
nsCOMPtr<nsIDOMMutationEvent> mutationEvent(do_QueryInterface(aEvent));
|
||||
NS_ASSERTION(mutationEvent, "Not a mutation event!");
|
||||
mutationEvent->GetRelatedNode(getter_AddRefs(subTreeNode));
|
||||
NS_ASSERTION(subTreeNode, "No old sub tree being replaced in DOMSubtreeModified");
|
||||
}
|
||||
else {
|
||||
// nsIAccessibleEventReceiver::EVENT_DESTROY / DOMNodeRemoved
|
||||
subTreeNode = targetNode;
|
||||
}
|
||||
InvalidateCacheSubtree(subTreeNode);
|
||||
}
|
||||
|
||||
// We need to get an accessible for the mutation event's target node
|
||||
// If there is no accessible for that node, we need to keep moving up the parent
|
||||
// chain so there is some accessible.
|
||||
// We will use this accessible to fire the accessible mutation event.
|
||||
// We're guaranteed success, because we will eventually end up at the doc accessible,
|
||||
// and there is always one of those.
|
||||
// XXX aaronl todo: are MSAA mutation events always fired on the container?
|
||||
// if so, we always need to get the dom parent at least once
|
||||
|
||||
nsCOMPtr<nsIAccessibilityService> accService =
|
||||
do_GetService("@mozilla.org/accessibilityService;1");
|
||||
if (!accService)
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIAccessible> accessible;
|
||||
while (NS_FAILED(accService->GetAccessibleInWeakShell(targetNode, mWeakShell,
|
||||
getter_AddRefs(accessible)))) {
|
||||
targetNode->GetParentNode(getter_AddRefs(subTreeNode));
|
||||
NS_ASSERTION(subTreeNode, "Crawled up parent chain without finding accessible");
|
||||
targetNode = subTreeNode;
|
||||
}
|
||||
|
||||
accessible->InvalidateChildren();
|
||||
|
||||
#ifdef XP_WIN
|
||||
// Windows MSAA clients crash if the listen to create or destroy events
|
||||
aAccessibleEventType = nsIAccessibleEventReceiver::EVENT_REORDER;
|
||||
#endif
|
||||
accessible->FireToolkitEvent(aAccessibleEventType, accessible, nsnull);
|
||||
}
|
||||
|
||||
|
@ -40,15 +40,16 @@
|
||||
#define _nsDocAccessible_H_
|
||||
|
||||
#include "nsAccessibleWrap.h"
|
||||
#include "nsIAccessibleDocument.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIAccessibleEventReceiver.h"
|
||||
#include "nsHashtable.h"
|
||||
#include "nsIWebProgressListener.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsIWebProgress.h"
|
||||
#include "nsIAccessibleDocument.h"
|
||||
#include "nsIAccessibleEventReceiver.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMMutationListener.h"
|
||||
#include "nsIScrollPositionListener.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsIWeakReference.h"
|
||||
#include "nsIWebProgress.h"
|
||||
#include "nsIWebProgressListener.h"
|
||||
|
||||
class nsIScrollableView;
|
||||
|
||||
@ -58,11 +59,12 @@ class nsDocAccessible : public nsAccessibleWrap,
|
||||
public nsIAccessibleDocument,
|
||||
public nsIAccessibleEventReceiver,
|
||||
public nsIWebProgressListener,
|
||||
public nsIDOMMutationListener,
|
||||
public nsIScrollPositionListener,
|
||||
public nsSupportsWeakReference
|
||||
{
|
||||
enum EBusyState {eBusyStateUninitialized, eBusyStateLoading, eBusyStateDone};
|
||||
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIACCESSIBLEDOCUMENT
|
||||
NS_DECL_NSIACCESSIBLEEVENTRECEIVER
|
||||
@ -80,12 +82,22 @@ class nsDocAccessible : public nsAccessibleWrap,
|
||||
NS_IMETHOD ScrollPositionWillChange(nsIScrollableView *aView, nscoord aX, nscoord aY);
|
||||
NS_IMETHOD ScrollPositionDidChange(nsIScrollableView *aView, nscoord aX, nscoord aY);
|
||||
|
||||
// ----- nsIDOMMutationListener -------------------------
|
||||
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
|
||||
NS_IMETHOD SubtreeModified(nsIDOMEvent* aMutationEvent);
|
||||
NS_IMETHOD NodeInserted(nsIDOMEvent* aMutationEvent);
|
||||
NS_IMETHOD NodeRemoved(nsIDOMEvent* aMutationEvent);
|
||||
NS_IMETHOD NodeRemovedFromDocument(nsIDOMEvent* aMutationEvent);
|
||||
NS_IMETHOD NodeInsertedIntoDocument(nsIDOMEvent* aMutationEvent);
|
||||
NS_IMETHOD AttrModified(nsIDOMEvent* aMutationEvent);
|
||||
NS_IMETHOD CharacterDataModified(nsIDOMEvent* aMutationEvent);
|
||||
|
||||
NS_DECL_NSIWEBPROGRESSLISTENER
|
||||
|
||||
// nsIAccessNode
|
||||
NS_IMETHOD Shutdown();
|
||||
|
||||
protected:
|
||||
protected:
|
||||
virtual void GetBounds(nsRect& aRect, nsIFrame** aRelativeFrame);
|
||||
virtual nsIFrame* GetFrame();
|
||||
void AddContentDocListeners();
|
||||
@ -93,6 +105,8 @@ class nsDocAccessible : public nsAccessibleWrap,
|
||||
void AddScrollListener(nsIPresShell *aPresShell);
|
||||
void RemoveScrollListener(nsIPresShell *aPresShell);
|
||||
void FireDocLoadFinished();
|
||||
void InvalidateCacheSubtree(nsIDOMNode *aStartNode);
|
||||
void HandleMutationEvent(nsIDOMEvent *aEvent, PRUint32 aEventType);
|
||||
static void DocLoadCallback(nsITimer *aTimer, void *aClosure);
|
||||
static void ScrollTimerCallback(nsITimer *aTimer, void *aClosure);
|
||||
|
||||
@ -111,5 +125,4 @@ class nsDocAccessible : public nsAccessibleWrap,
|
||||
PRPackedBool mIsNewDocument;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -175,7 +175,7 @@ NS_IMETHODIMP nsRootAccessible::AddEventListeners()
|
||||
|
||||
rv = target->AddEventListener(NS_LITERAL_STRING("DOMMenuBarInactive"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register listener");
|
||||
|
||||
|
||||
AddContentDocListeners();
|
||||
}
|
||||
if (!mCaretAccessible)
|
||||
@ -198,6 +198,9 @@ NS_IMETHODIMP nsRootAccessible::RemoveEventListeners()
|
||||
target->RemoveEventListener(NS_LITERAL_STRING("DOMMenuItemActive"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE);
|
||||
target->RemoveEventListener(NS_LITERAL_STRING("DOMMenuBarActive"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE);
|
||||
target->RemoveEventListener(NS_LITERAL_STRING("DOMMenuBarInactive"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE);
|
||||
target->RemoveEventListener(NS_LITERAL_STRING("DOMMenuBarInactive"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE);
|
||||
target->RemoveEventListener(NS_LITERAL_STRING("RadioStateChange"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE);
|
||||
target->RemoveEventListener(NS_LITERAL_STRING("ListitemStateChange"), NS_STATIC_CAST(nsIDOMXULListener*, this), PR_TRUE);
|
||||
}
|
||||
|
||||
if (mScrollWatchTimer) {
|
||||
@ -246,6 +249,21 @@ void nsRootAccessible::FireAccessibleFocusEvent(nsIAccessible *focusAccessible,
|
||||
}
|
||||
}
|
||||
|
||||
void nsRootAccessible::GetEventShell(nsIDOMNode *aNode, nsIPresShell **aEventShell)
|
||||
{
|
||||
// XXX aaronl - this is not ideal.
|
||||
// We could avoid this whole section and the fallible
|
||||
// doc->GetShellAt(0, ...) by putting the event handler
|
||||
// on nsDocAccessible instead.
|
||||
// The disadvantage would be that we would be seeing some events
|
||||
// for inner documents that we don't care about.
|
||||
nsCOMPtr<nsIDOMDocument> domDocument;
|
||||
aNode->GetOwnerDocument(getter_AddRefs(domDocument));
|
||||
nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDocument));
|
||||
if (doc)
|
||||
doc->GetShellAt(0, aEventShell);
|
||||
}
|
||||
|
||||
// --------------- nsIDOMEventListener Methods (3) ------------------------
|
||||
|
||||
NS_IMETHODIMP nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
|
||||
@ -279,21 +297,10 @@ NS_IMETHODIMP nsRootAccessible::HandleEvent(nsIDOMEvent* aEvent)
|
||||
}
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIAccessible> accessible;
|
||||
|
||||
// XXX aaronl - this is not ideal.
|
||||
// We could avoid this whole section and the fallible
|
||||
// doc->GetShellAt(0, ...) by putting the event handler
|
||||
// on nsDocAccessible instead.
|
||||
// The disadvantage would be that we would be seeing some events
|
||||
// for inner documents that we don't care about.
|
||||
nsCOMPtr<nsIDOMDocument> domDocument;
|
||||
targetNode->GetOwnerDocument(getter_AddRefs(domDocument));
|
||||
nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDocument));
|
||||
nsCOMPtr<nsIPresShell> eventShell;
|
||||
if (doc) {
|
||||
doc->GetShellAt(0, getter_AddRefs(eventShell));
|
||||
}
|
||||
GetEventShell(targetNode, getter_AddRefs(eventShell));
|
||||
|
||||
nsCOMPtr<nsIAccessible> accessible;
|
||||
if (!eventShell ||
|
||||
NS_FAILED(mAccService->GetAccessibleInShell(targetNode, eventShell,
|
||||
getter_AddRefs(accessible))))
|
||||
|
@ -40,14 +40,14 @@
|
||||
#define _nsRootAccessible_H_
|
||||
|
||||
#include "nsDocAccessibleWrap.h"
|
||||
#include "nsHashtable.h"
|
||||
#include "nsIAccessibilityService.h"
|
||||
#include "nsIAccessibleEventReceiver.h"
|
||||
#include "nsIAccessibleDocument.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMFocusListener.h"
|
||||
#include "nsIDOMFormListener.h"
|
||||
#include "nsIDOMXULListener.h"
|
||||
#include "nsIDOMFocusListener.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIAccessibilityService.h"
|
||||
#include "nsHashtable.h"
|
||||
|
||||
class nsIAccessibleEventListener;
|
||||
|
||||
@ -102,8 +102,9 @@ class nsRootAccessible : public nsDocAccessibleWrap,
|
||||
void ShutdownAll();
|
||||
|
||||
protected:
|
||||
void GetTargetNode(nsIDOMEvent *aEvent, nsIDOMNode **aTargetNode);
|
||||
static void GetTargetNode(nsIDOMEvent *aEvent, nsIDOMNode **aTargetNode);
|
||||
void FireAccessibleFocusEvent(nsIAccessible *focusAccessible, nsIDOMNode *focusNode);
|
||||
void GetEventShell(nsIDOMNode *aNode, nsIPresShell **aEventShell);
|
||||
nsCOMPtr<nsIAccessibilityService> mAccService;
|
||||
nsCOMPtr<nsIAccessibleCaret> mCaretAccessible;
|
||||
};
|
||||
|
@ -3726,6 +3726,18 @@ nsGenericHTMLContainerElement::ReplaceChildAt(nsIContent* aKid,
|
||||
doc->ContentReplaced(this, oldKid, aKid, aIndex);
|
||||
}
|
||||
}
|
||||
if (nsGenericElement::HasMutationListeners(this, NS_EVENT_BITS_MUTATION_SUBTREEMODIFIED)) {
|
||||
nsMutationEvent mutation;
|
||||
mutation.eventStructType = NS_MUTATION_EVENT;
|
||||
mutation.message = NS_MUTATION_SUBTREEMODIFIED;
|
||||
mutation.mTarget = do_QueryInterface(this);
|
||||
mutation.mRelatedNode = do_QueryInterface(oldKid);
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
HandleDOMEvent(nsnull, &mutation, nsnull,
|
||||
NS_EVENT_FLAG_INIT, &status);
|
||||
}
|
||||
|
||||
if (oldKid) {
|
||||
oldKid->SetDocument(nsnull, PR_TRUE, PR_TRUE);
|
||||
oldKid->SetParent(nsnull);
|
||||
|
@ -817,9 +817,9 @@ nsWindow::~nsWindow()
|
||||
{
|
||||
#ifdef ACCESSIBILITY
|
||||
if (mRootAccessible) {
|
||||
nsCOMPtr<nsIAccessNode> accessNode(do_QueryInterface(mRootAccessible));
|
||||
if (accessNode) {
|
||||
accessNode->Shutdown();
|
||||
nsCOMPtr<nsIAccessibleDocument> accessDoc(do_QueryInterface(mRootAccessible));
|
||||
if (accessDoc) {
|
||||
accessDoc->Destroy();
|
||||
}
|
||||
mRootAccessible->Release();
|
||||
mRootAccessible = nsnull;
|
||||
@ -4669,24 +4669,24 @@ LPCWSTR nsWindow::WindowPopupClassW()
|
||||
|
||||
LPCTSTR nsWindow::WindowClass()
|
||||
{
|
||||
// Call into the wide version to make sure things get
|
||||
// registered properly.
|
||||
WindowClassW();
|
||||
|
||||
// XXX: The class name used here must be kept in sync with
|
||||
// the classname used in WindowClassW();
|
||||
return "MozillaWindowClass";
|
||||
// Call into the wide version to make sure things get
|
||||
// registered properly.
|
||||
WindowClassW();
|
||||
|
||||
// XXX: The class name used here must be kept in sync with
|
||||
// the classname used in WindowClassW();
|
||||
return "MozillaWindowClass";
|
||||
}
|
||||
|
||||
LPCTSTR nsWindow::WindowPopupClass()
|
||||
{
|
||||
// Call into the wide version to make sure things get
|
||||
// registered properly.
|
||||
WindowPopupClassW();
|
||||
|
||||
// XXX: The class name used here must be kept in sync with
|
||||
// the classname used in WindowPopupClassW();
|
||||
return "MozillaDropShadowWindowClass";
|
||||
// Call into the wide version to make sure things get
|
||||
// registered properly.
|
||||
WindowPopupClassW();
|
||||
|
||||
// XXX: The class name used here must be kept in sync with
|
||||
// the classname used in WindowPopupClassW();
|
||||
return "MozillaDropShadowWindowClass";
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
Loading…
x
Reference in New Issue
Block a user