diff --git a/accessible/public/nsIAccessible.idl b/accessible/public/nsIAccessible.idl index 689eb8684253..c76a5ae63964 100644 --- a/accessible/public/nsIAccessible.idl +++ b/accessible/public/nsIAccessible.idl @@ -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); diff --git a/accessible/public/nsIAccessibleDocument.idl b/accessible/public/nsIAccessibleDocument.idl index 90b47f89245e..c175a77d00d0 100644 --- a/accessible/public/nsIAccessibleDocument.idl +++ b/accessible/public/nsIAccessibleDocument.idl @@ -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(); }; diff --git a/accessible/src/base/nsAccessNode.cpp b/accessible/src/base/nsAccessNode.cpp index ec839a2a4ce0..1b781201c7a4 100755 --- a/accessible/src/base/nsAccessNode.cpp +++ b/accessible/src/base/nsAccessNode.cpp @@ -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) diff --git a/accessible/src/base/nsAccessibilityService.cpp b/accessible/src/base/nsAccessibilityService.cpp index 78a4b9d2e581..526e29ad6a53 100644 --- a/accessible/src/base/nsAccessibilityService.cpp +++ b/accessible/src/base/nsAccessibilityService.cpp @@ -762,15 +762,16 @@ nsAccessibilityService::CreateHTMLTextAccessible(nsISupports *aFrame, nsIAccessi nsCOMPtr 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 parentNode; diff --git a/accessible/src/base/nsAccessible.cpp b/accessible/src/base/nsAccessible.cpp index 4e52bd60baa0..7a83cd89ef0a 100644 --- a/accessible/src/base/nsAccessible.cpp +++ b/accessible/src/base/nsAccessible.cpp @@ -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 docAccessible(GetDocAccessible()); nsCOMPtr eventHandlingAccessible(do_QueryInterface(docAccessible)); if (eventHandlingAccessible) { diff --git a/accessible/src/base/nsDocAccessible.cpp b/accessible/src/base/nsDocAccessible.cpp index f517ffedf437..914093a81e8e 100644 --- a/accessible/src/base/nsDocAccessible.cpp +++ b/accessible/src/base/nsDocAccessible.cpp @@ -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 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 presShell(do_QueryReferent(mWeakShell)); RemoveScrollListener(presShell); + + nsCOMPtr 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 '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 iterNode(aStartNode), nextNode; + nsCOMPtr 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 domEvent(do_QueryInterface(aEvent)); + nsCOMPtr domEventTarget; + if (domEvent) { + domEvent->GetTarget(getter_AddRefs(domEventTarget)); + } + nsCOMPtr targetNode(do_QueryInterface(domEventTarget)); + if (!targetNode) + return; + + nsCOMPtr 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 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 accService = + do_GetService("@mozilla.org/accessibilityService;1"); + if (!accService) + return; + + nsCOMPtr 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); +} + diff --git a/accessible/src/base/nsDocAccessible.h b/accessible/src/base/nsDocAccessible.h index bada316c38b5..b1941d1837e6 100644 --- a/accessible/src/base/nsDocAccessible.h +++ b/accessible/src/base/nsDocAccessible.h @@ -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 diff --git a/accessible/src/base/nsRootAccessible.cpp b/accessible/src/base/nsRootAccessible.cpp index de3911fcdfb2..323a68358272 100644 --- a/accessible/src/base/nsRootAccessible.cpp +++ b/accessible/src/base/nsRootAccessible.cpp @@ -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 domDocument; + aNode->GetOwnerDocument(getter_AddRefs(domDocument)); + nsCOMPtr 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 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 domDocument; - targetNode->GetOwnerDocument(getter_AddRefs(domDocument)); - nsCOMPtr doc(do_QueryInterface(domDocument)); nsCOMPtr eventShell; - if (doc) { - doc->GetShellAt(0, getter_AddRefs(eventShell)); - } + GetEventShell(targetNode, getter_AddRefs(eventShell)); + + nsCOMPtr accessible; if (!eventShell || NS_FAILED(mAccService->GetAccessibleInShell(targetNode, eventShell, getter_AddRefs(accessible)))) diff --git a/accessible/src/base/nsRootAccessible.h b/accessible/src/base/nsRootAccessible.h index ecdc3188a0b7..9b9c61fc5bb0 100644 --- a/accessible/src/base/nsRootAccessible.h +++ b/accessible/src/base/nsRootAccessible.h @@ -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 mAccService; nsCOMPtr mCaretAccessible; }; diff --git a/content/html/content/src/nsGenericHTMLElement.cpp b/content/html/content/src/nsGenericHTMLElement.cpp index a4adda1c2459..213fee0e82c4 100644 --- a/content/html/content/src/nsGenericHTMLElement.cpp +++ b/content/html/content/src/nsGenericHTMLElement.cpp @@ -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); diff --git a/widget/src/windows/nsWindow.cpp b/widget/src/windows/nsWindow.cpp index 33ba825f6a93..3e5368f574be 100644 --- a/widget/src/windows/nsWindow.cpp +++ b/widget/src/windows/nsWindow.cpp @@ -817,9 +817,9 @@ nsWindow::~nsWindow() { #ifdef ACCESSIBILITY if (mRootAccessible) { - nsCOMPtr accessNode(do_QueryInterface(mRootAccessible)); - if (accessNode) { - accessNode->Shutdown(); + nsCOMPtr 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"; } //-------------------------------------------------------------------------