author | Alexander Surkov <surkov.alexander@gmail.com> |
Fri, 18 Jun 2010 11:44:09 +0900 | |
changeset 43765 | 279ce7f9b1e31683679d11168ef5905508bfe0d7 |
parent 43764 | 31d4d880d0a81e4a2cbf920670a17a24be272923 |
child 43766 | 598c5f8d295cb5e1456e55cd512758d6c3498df2 |
push id | 1 |
push user | root |
push date | Tue, 26 Apr 2011 22:38:44 +0000 |
treeherder | mozilla-beta@bfdb6e623a36 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | surkov, davidb, roc, bz |
bugs | 571459 |
milestone | 1.9.3a6pre |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/accessible/public/nsIAccessibilityService.h +++ b/accessible/public/nsIAccessibilityService.h @@ -46,20 +46,20 @@ class nsAccessible; class nsIContent; class nsIDocument; class nsIFrame; class nsIPresShell; class nsObjectFrame; -// 9f43b315-53c6-4d46-9818-9c8593e91984 +// 10ff6dca-b219-4b64-9a4c-67a62b86edce #define NS_IACCESSIBILITYSERVICE_IID \ -{0x9f43b315, 0x53c6, 0x4d46, \ - {0x98, 0x18, 0x9c, 0x85, 0x93, 0xe9, 0x19, 0x84} } +{ 0x10ff6dca, 0xb219, 0x4b64, \ + { 0x9a, 0x4c, 0x67, 0xa6, 0x2b, 0x86, 0xed, 0xce } } class nsIAccessibilityService : public nsIAccessibleRetrieval { public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_IACCESSIBILITYSERVICE_IID) /** * Return an accessible object for a DOM node in the given pres shell. @@ -162,16 +162,22 @@ public: /** * Notify accessibility that anchor jump has been accomplished to the given * target. Used by layout. */ virtual void NotifyOfAnchorJumpTo(nsIContent *aTarget) = 0; /** + * Notify the accessibility service that the given presshell is + * being destroyed. + */ + virtual void PresShellDestroyed(nsIPresShell *aPresShell) = 0; + + /** * Fire accessible event of the given type for the given target. * * @param aEvent [in] accessible event type * @param aTarget [in] target of accessible event */ virtual nsresult FireAccessibleEvent(PRUint32 aEvent, nsIAccessible *aTarget) = 0; };
--- a/accessible/src/base/nsAccDocManager.cpp +++ b/accessible/src/base/nsAccDocManager.cpp @@ -91,16 +91,17 @@ nsAccDocManager::FindAccessibleInCache(v void nsAccDocManager::ShutdownDocAccessiblesInTree(nsIDocument *aDocument) { nsCOMPtr<nsISupports> container = aDocument->GetContainer(); nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(container); ShutdownDocAccessiblesInTree(treeItem, aDocument); } + //////////////////////////////////////////////////////////////////////////////// // nsAccDocManager protected PRBool nsAccDocManager::Init() { mDocAccessibleCache.Init(4); @@ -123,16 +124,32 @@ nsAccDocManager::Shutdown() do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID); if (progress) progress->RemoveProgressListener(static_cast<nsIWebProgressListener*>(this)); ClearDocCache(); } +void +nsAccDocManager::ShutdownDocAccessible(nsIDocument *aDocument) +{ + nsDocAccessible* docAccessible = + mDocAccessibleCache.GetWeak(static_cast<void*>(aDocument)); + if (!docAccessible) + return; + + // We're allowed to not remove listeners when accessible document is shutdown + // since we don't keep strong reference on chrome event target and listeners + // are removed automatically when chrome event target goes away. + + docAccessible->Shutdown(); + mDocAccessibleCache.Remove(static_cast<void*>(aDocument)); +} + //////////////////////////////////////////////////////////////////////////////// // nsISupports NS_IMPL_THREADSAFE_ISUPPORTS3(nsAccDocManager, nsIWebProgressListener, nsIDOMEventListener, nsISupportsWeakReference) @@ -408,40 +425,16 @@ nsAccDocManager::AddListeners(nsIDocumen if (aAddDOMContentLoadedListener) { elm->AddEventListenerByType(this, NS_LITERAL_STRING("DOMContentLoaded"), NS_EVENT_FLAG_CAPTURE, nsnull); NS_LOG_ACCDOCCREATE_TEXT(" added 'DOMContentLoaded' listener") } } -void -nsAccDocManager::RemoveListeners(nsIDocument *aDocument) -{ - // Document has no window when application shuts down. The document can still - // exist because we didn't receive a "pagehide" event. - nsPIDOMWindow *window = aDocument->GetWindow(); - if (!window) - return; - - nsPIDOMEventTarget *target = window->GetChromeEventHandler(); - nsIEventListenerManager* elm = target->GetListenerManager(PR_TRUE); - elm->RemoveEventListenerByType(this, NS_LITERAL_STRING("pagehide"), - NS_EVENT_FLAG_CAPTURE, nsnull); - - NS_LOG_ACCDOCDESTROY("removed 'pagehide' listener", aDocument) - - if (nsCoreUtils::IsRootDocument(aDocument)) { - elm->RemoveEventListenerByType(this, NS_LITERAL_STRING("DOMContentLoaded"), - NS_EVENT_FLAG_CAPTURE, nsnull); - - NS_LOG_ACCDOCDESTROY("removed 'DOMContentLoaded' listener", aDocument) - } -} - nsDocAccessible* nsAccDocManager::CreateDocOrRootAccessible(nsIDocument *aDocument) { // Ignore temporary, hiding and svg resource documents. if (aDocument->IsInitialDocument() || !aDocument->IsVisible() || aDocument->GetDisplayDocument()) return nsnull; @@ -497,27 +490,26 @@ nsAccDocManager::CreateDocOrRootAccessib return nsnull; } // XXX: ideally we should initialize an accessible and then put it into tree, // also this code should be shared between doc and root accessibles. if (outerDocAcc) { // Root document accessible doesn't have associated outerdoc accessible, it // adds itself to application accessible instead. - NS_LOG_ACCDOCCREATE("append document to outerdoc", aDocument) outerDocAcc->AppendChild(docAcc); } if (!GetAccService()->InitAccessible(docAcc, nsAccUtils::GetRoleMapEntry(aDocument))) { mDocAccessibleCache.Remove(static_cast<void*>(aDocument)); return nsnull; } - NS_LOG_ACCDOCCREATE("document created", aDocument) + NS_LOG_ACCDOCCREATE("document creation finished", aDocument) AddListeners(aDocument, isRootDoc); return docAcc; } void nsAccDocManager::ShutdownDocAccessiblesInTree(nsIDocShellTreeItem *aTreeItem, nsIDocument *aDocument) @@ -542,50 +534,31 @@ nsAccDocManager::ShutdownDocAccessiblesI ShutdownDocAccessiblesInTree(treeItemChild, contentViewer->GetDocument()); } } ShutdownDocAccessible(aDocument); } -void -nsAccDocManager::ShutdownDocAccessible(nsIDocument *aDocument) -{ - RemoveListeners(aDocument); - - nsDocAccessible *docAccessible = - mDocAccessibleCache.GetWeak(static_cast<void*>(aDocument)); - if (docAccessible) - docAccessible->Shutdown(); - - mDocAccessibleCache.Remove(static_cast<void*>(aDocument)); -} - //////////////////////////////////////////////////////////////////////////////// // nsAccDocManager static PLDHashOperator nsAccDocManager::ClearDocCacheEntry(const void* aKey, nsRefPtr<nsDocAccessible>& aDocAccessible, void* aUserArg) { nsAccDocManager *accDocMgr = static_cast<nsAccDocManager*>(aUserArg); NS_ASSERTION(aDocAccessible, "Calling ClearDocCacheEntry with a NULL pointer!"); - if (aDocAccessible) { - nsCOMPtr<nsIDocument> document = aDocAccessible->GetDOMDocument(); - NS_ASSERTION(document, "Document accessible was shutdown already!"); - if (document) - accDocMgr->RemoveListeners(document); - + if (aDocAccessible) aDocAccessible->Shutdown(); - } return PL_DHASH_REMOVE; } PLDHashOperator nsAccDocManager::SearchAccessibleInDocCache(const void* aKey, nsDocAccessible* aDocAccessible, void* aUserArg)
--- a/accessible/src/base/nsAccDocManager.h +++ b/accessible/src/base/nsAccDocManager.h @@ -43,16 +43,18 @@ #include "nsIDocument.h" #include "nsIDOMEventListener.h" #include "nsIWebProgress.h" #include "nsIWebProgressListener.h" #include "nsWeakReference.h" class nsDocAccessible; +//#define DEBUG_ACCDOCMGR + /** * Manage the document accessible life cycle. */ class nsAccDocManager : public nsIWebProgressListener, public nsIDOMEventListener, public nsSupportsWeakReference { public: @@ -75,33 +77,41 @@ public: /** * Shutdown document accessibles in the tree starting from the given one. * * @param aDocument [in] the DOM document of start document accessible */ void ShutdownDocAccessiblesInTree(nsIDocument *aDocument); + /** + * Return document accessible from the cache. Convenient method for testing. + */ + inline nsDocAccessible* GetDocAccessibleFromCache(nsIDocument* aDocument) const + { + return mDocAccessibleCache.GetWeak(static_cast<void*>(aDocument)); + } + protected: nsAccDocManager() { }; /** * Initialize the manager. */ PRBool Init(); /** * Shutdown the manager. */ void Shutdown(); - inline nsDocAccessible* GetDocAccessibleFromCache(nsIDocument* aDocument) const - { - return mDocAccessibleCache.GetWeak(static_cast<void*>(aDocument)); - } + /** + * Shutdown the document accessible. + */ + void ShutdownDocAccessible(nsIDocument* aDocument); private: nsAccDocManager(const nsAccDocManager&); nsAccDocManager& operator =(const nsAccDocManager&); private: /** * Create an accessible document if it was't created and fire accessibility @@ -132,37 +142,31 @@ private: * them have separate processing of iframe documents on the page and therefore * they need a way to distinguish sub documents from page document). Ideally * we should make events firing for any loaded document and provide additional * info AT are needing. */ PRBool IsEventTargetDocument(nsIDocument *aDocument) const; /** - * Add/remove 'pagehide' and 'DOMContentLoaded' event listeners. + * Add 'pagehide' and 'DOMContentLoaded' event listeners. */ void AddListeners(nsIDocument *aDocument, PRBool aAddPageShowListener); - void RemoveListeners(nsIDocument *aDocument); /** * Create document or root accessible. */ nsDocAccessible *CreateDocOrRootAccessible(nsIDocument *aDocument); /** * Shutdown document accessibles in the tree starting from given tree item. */ void ShutdownDocAccessiblesInTree(nsIDocShellTreeItem *aTreeItem, nsIDocument *aDocument); - /** - * Shutdown the document accessible. - */ - void ShutdownDocAccessible(nsIDocument *aDocument); - typedef nsRefPtrHashtable<nsVoidPtrHashKey, nsDocAccessible> nsDocAccessibleHashtable; /** * Shutdown and remove the document accessible from cache. */ static PLDHashOperator ClearDocCacheEntry(const void* aKey, @@ -189,30 +193,26 @@ private: void* aUserArg); nsDocAccessibleHashtable mDocAccessibleCache; }; /** * nsAccDocManager debugging macros. */ -//#define DEBUG_ACCDOCMGR - #ifdef DEBUG_ACCDOCMGR // Enable these to log accessible document loading, creation or destruction. #define DEBUG_ACCDOCMGR_DOCLOAD #define DEBUG_ACCDOCMGR_DOCCREATE #define DEBUG_ACCDOCMGR_DOCDESTROY // Common macros, do not use directly. #define NS_LOG_ACCDOC_ADDRESS(aDocument, aDocAcc) \ - printf("DOM id: 0x%x, acc id: 0x%x", \ - reinterpret_cast<PRInt32>(static_cast<void*>(aDocument)), \ - reinterpret_cast<PRInt32>(aDocAcc)); + printf("DOM id: %p, acc id: %p", aDocument, aDocAcc); #define NS_LOG_ACCDOC_URI(aDocument) \ nsIURI *uri = aDocument->GetDocumentURI(); \ nsCAutoString spec; \ uri->GetSpec(spec); \ printf("uri: %s", spec); #define NS_LOG_ACCDOC_TYPE(aDocument) \ @@ -255,29 +255,28 @@ private: printf("doc state: %s", docState); \ printf(", %sinitial", aDocument->IsInitialDocument() ? "" : "not "); \ printf(", %sshowing", aDocument->IsShowing() ? "" : "not "); \ printf(", %svisible", aDocument->IsVisible() ? "" : "not "); \ printf(", %sactive", aDocument->IsActive() ? "" : "not "); #define NS_LOG_ACCDOC_DOCPRESSHELL(aDocument) \ nsIPresShell *ps = aDocument->GetPrimaryShell(); \ - printf("presshell: 0x%x", reinterpret_cast<PRInt32>(ps)); \ + printf("presshell: %p", ps); \ nsIScrollableFrame *sf = ps ? \ ps->GetRootScrollFrameAsScrollableExternal() : nsnull; \ - printf(", root scroll frame: 0x%x", reinterpret_cast<PRInt32>(sf)); + printf(", root scroll frame: %p", sf); #define NS_LOG_ACCDOC_DOCLOADGROUP(aDocument) \ nsCOMPtr<nsILoadGroup> loadGroup = aDocument->GetDocumentLoadGroup(); \ - printf("load group: 0x%x", reinterpret_cast<PRInt32>(loadGroup.get())); + printf("load group: %p", loadGroup); #define NS_LOG_ACCDOC_DOCPARENT(aDocument) \ nsIDocument *parentDoc = aDocument->GetParentDocument(); \ - printf("parent id: 0x%x", \ - reinterpret_cast<PRInt32>(parentDoc)); \ + printf("parent id: %p", parentDoc); \ if (parentDoc) { \ printf("\n parent "); \ NS_LOG_ACCDOC_URI(parentDoc) \ printf("\n"); \ } #define NS_LOG_ACCDOC_SHELLLOADTYPE(aDocShell) \ { \ @@ -392,16 +391,31 @@ private: strEventType.AssignLiteral("busy "); \ if (event->IsStateEnabled()) \ strEventType.AppendLiteral("true"); \ else \ strEventType.AppendLiteral("false"); \ } \ } +#define NS_LOG_ACCDOC_ACCADDRESS(aName, aAcc) \ + { \ + nsINode* node = aAcc->GetNode(); \ + nsIDocument* doc = aAcc->GetDocumentNode(); \ + nsDocAccessible *docacc = GetAccService()->GetDocAccessibleFromCache(doc); \ + printf(" " aName " accessible: %p, node: %p\n", aAcc, node); \ + printf(" docacc for " aName " accessible: %p, node: %p\n", docacc, doc); \ + printf(" "); \ + NS_LOG_ACCDOC_URI(doc) \ + printf("\n"); \ + } + +#define NS_LOG_ACCDOC_MSG(aMsg) \ + printf("\n" aMsg "\n"); \ + #define NS_LOG_ACCDOC_TEXT(aMsg) \ printf(" " aMsg "\n"); // Accessible document loading macros. #ifdef DEBUG_ACCDOCMGR_DOCLOAD #define NS_LOG_ACCDOCLOAD_REQUEST(aRequest) \ if (aRequest) { \ @@ -426,27 +440,27 @@ private: if (loadFlags & nsIChannel::LOAD_CLASSIFY_URI) \ printf("classify uri; "); \ } else { \ printf(" no request"); \ } #define NS_LOG_ACCDOCLOAD(aMsg, aWebProgress, aRequest, aStateFlags) \ { \ - printf("\nA11Y DOCLOAD: " aMsg "\n"); \ + NS_LOG_ACCDOC_MSG("A11Y DOCLOAD: " aMsg); \ \ nsCOMPtr<nsIDOMWindow> DOMWindow; \ aWebProgress->GetDOMWindow(getter_AddRefs(DOMWindow)); \ if (DOMWindow) { \ nsCOMPtr<nsIDOMDocument> DOMDocument; \ DOMWindow->GetDocument(getter_AddRefs(DOMDocument)); \ if (DOMDocument) { \ nsCOMPtr<nsIDocument> document(do_QueryInterface(DOMDocument)); \ nsDocAccessible *docAcc = \ - mDocAccessibleCache.GetWeak(static_cast<void*>(document)); \ + GetAccService()->GetDocAccessibleFromCache(document); \ NS_LOG_ACCDOC_DOCINFO(document, docAcc) \ \ printf(" {\n"); \ nsCOMPtr<nsIWebNavigation> webNav(do_GetInterface(DOMWindow)); \ nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(webNav)); \ printf(" "); \ NS_LOG_ACCDOC_SHELLLOADTYPE(docShell) \ printf("\n"); \ @@ -458,19 +472,19 @@ private: printf(", document is %sloading\n", (isDocLoading ? "" : "not ")); \ printf(" }\n"); \ } \ } \ } #define NS_LOG_ACCDOCLOAD2(aMsg, aDocument) \ { \ - printf("\nA11Y DOCLOAD: " aMsg "\n"); \ + NS_LOG_ACCDOC_MSG("A11Y DOCLOAD: " aMsg); \ nsDocAccessible *docAcc = \ - mDocAccessibleCache.GetWeak(static_cast<void*>(aDocument)); \ + GetAccService()->GetDocAccessibleFromCache(aDocument); \ NS_LOG_ACCDOC_DOCINFO(aDocument, docAcc) \ } #define NS_LOG_ACCDOCLOAD_FIREEVENT(aEvent) \ { \ NS_GET_ACCDOC_EVENTTYPE(aEvent) \ if (!strEventType.IsEmpty()) \ printf(" fire: %s\n", strEventType.get()); \ @@ -491,44 +505,55 @@ private: #define NS_LOG_ACCDOCLOAD_TEXT(aMsg) \ NS_LOG_ACCDOC_TEXT(aMsg) #endif // DEBUG_ACCDOCMGR_DOCLOAD // Accessible document creation macros. #ifdef DEBUG_ACCDOCMGR_DOCCREATE #define NS_LOG_ACCDOCCREATE_FOR(aMsg, aDocument, aDocAcc) \ - printf("\nA11Y DOCCREATE: " aMsg "\n"); \ + NS_LOG_ACCDOC_MSG("A11Y DOCCREATE: " aMsg); \ NS_LOG_ACCDOC_DOCINFO(aDocument, aDocAcc) #define NS_LOG_ACCDOCCREATE(aMsg, aDocument) \ { \ nsDocAccessible *docAcc = \ - mDocAccessibleCache.GetWeak(static_cast<void*>(aDocument)); \ + GetAccService()->GetDocAccessibleFromCache(aDocument); \ NS_LOG_ACCDOCCREATE_FOR(aMsg, aDocument, docAcc) \ } +#define NS_LOG_ACCDOCCREATE_ACCADDRESS(aName, aAcc) \ + NS_LOG_ACCDOC_ACCADDRESS(aName, aAcc) + #define NS_LOG_ACCDOCCREATE_TEXT(aMsg) \ NS_LOG_ACCDOC_TEXT(aMsg) #endif // DEBUG_ACCDOCMGR_DOCCREATE // Accessible document destruction macros. #ifdef DEBUG_ACCDOCMGR_DOCDESTROY #define NS_LOG_ACCDOCDESTROY_FOR(aMsg, aDocument, aDocAcc) \ - printf("\nA11Y DOCDESTROY: " aMsg "\n"); \ + NS_LOG_ACCDOC_MSG("A11Y DOCDESTROY: " aMsg); \ NS_LOG_ACCDOC_DOCINFO(aDocument, aDocAcc) #define NS_LOG_ACCDOCDESTROY(aMsg, aDocument) \ - nsDocAccessible *docAcc = \ - mDocAccessibleCache.GetWeak(static_cast<void*>(aDocument)); \ - NS_LOG_ACCDOCDESTROY_FOR(aMsg, aDocument, docAcc) + { \ + nsDocAccessible* docAcc = \ + GetAccService()->GetDocAccessibleFromCache(aDocument); \ + NS_LOG_ACCDOCDESTROY_FOR(aMsg, aDocument, docAcc) \ + } -#define NS_LOG_ACCDOCDESTROY_TEXT(aMsg) \ - NS_LOG_ACCDOC_TEXT(aMsg) +#define NS_LOG_ACCDOCDESTROY_ACCADDRESS(aName, aAcc) \ + NS_LOG_ACCDOC_ACCADDRESS(aName, aAcc) + +#define NS_LOG_ACCDOCDESTROY_MSG(aMsg) \ + NS_LOG_ACCDOC_MSG(aMsg) + +#define NS_LOG_ACCDOCDESTROY_TEXT(aMsg) \ + NS_LOG_ACCDOC_TEXT(aMsg) #endif // DEBUG_ACCDOCMGR_DOCDESTROY #endif // DEBUG_ACCDOCMGR #ifndef DEBUG_ACCDOCMGR_DOCLOAD #define NS_LOG_ACCDOCLOAD(aMsg, aWebProgress, aRequest, aStateFlags) #define NS_LOG_ACCDOCLOAD2(aMsg, aDocument) @@ -536,18 +561,21 @@ private: #define NS_LOG_ACCDOCLOAD_FIREEVENT(aEvent) #define NS_LOG_ACCDOCLOAD_HANDLEEVENT(aEvent) #define NS_LOG_ACCDOCLOAD_TEXT(aMsg) #endif #ifndef DEBUG_ACCDOCMGR_DOCCREATE #define NS_LOG_ACCDOCCREATE_FOR(aMsg, aDocument, aDocAcc) #define NS_LOG_ACCDOCCREATE(aMsg, aDocument) +#define NS_LOG_ACCDOCCREATE_ACCADDRESS(aName, aAcc) #define NS_LOG_ACCDOCCREATE_TEXT(aMsg) #endif #ifndef DEBUG_ACCDOCMGR_DOCDESTROY #define NS_LOG_ACCDOCDESTROY_FOR(aMsg, aDocument, aDocAcc) #define NS_LOG_ACCDOCDESTROY(aMsg, aDocument) +#define NS_LOG_ACCDOCDESTROY_MSG(aMsg) +#define NS_LOG_ACCDOCDESTROY_ACCADDRESS(aName, aAcc) #define NS_LOG_ACCDOCDESTROY_TEXT(aMsg) #endif #endif // nsAccDocManager_h_
--- a/accessible/src/base/nsAccessNode.h +++ b/accessible/src/base/nsAccessNode.h @@ -152,16 +152,18 @@ public: return DOMNode; } /** * Return DOM node associated with the accessible. */ virtual nsINode* GetNode() const { return mContent; } nsIContent* GetContent() const { return mContent; } + nsIDocument* GetDocumentNode() const + { return mContent ? mContent->GetOwnerDoc() : nsnull; } /** * Return node type information of DOM node associated with the accessible. */ PRBool IsContent() const { return GetNode() && GetNode()->IsNodeOfType(nsINode::eCONTENT); }
--- a/accessible/src/base/nsAccessibilityService.cpp +++ b/accessible/src/base/nsAccessibilityService.cpp @@ -775,16 +775,35 @@ nsAccessibilityService::CreateHTMLCaptio *aAccessible = new nsHTMLCaptionAccessible(content, weakShell); if (!*aAccessible) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(*aAccessible); return NS_OK; } +void +nsAccessibilityService::PresShellDestroyed(nsIPresShell *aPresShell) +{ + // Presshell destruction will automatically destroy shells for descendant + // documents, so no need to worry about those. Just shut down the accessible + // for this one document. That keeps us from having bad behavior in case of + // deep bushy subtrees. + // When document subtree containing iframe is hidden then we don't get + // pagehide event for the iframe's underlying document and its presshell is + // destroyed before we're notified styles were changed. Shutdown the document + // accessible early. + nsIDocument* doc = aPresShell->GetDocument(); + if (!doc) + return; + + NS_LOG_ACCDOCDESTROY("presshell destroyed", doc) + ShutdownDocAccessible(doc); +} + // nsAccessibilityService protected nsAccessible * nsAccessibilityService::GetCachedAccessible(nsINode *aNode, nsIWeakReference *aWeakShell) { nsDocAccessible *docAccessible = GetDocAccessible(aNode->GetOwnerDoc()); return docAccessible ? docAccessible->GetCachedAccessible(static_cast<void*>(aNode)) : nsnull;
--- a/accessible/src/base/nsAccessibilityService.h +++ b/accessible/src/base/nsAccessibilityService.h @@ -119,16 +119,18 @@ public: virtual nsresult RemoveNativeRootAccessible(nsIAccessible *aRootAccessible); virtual nsresult InvalidateSubtreeFor(nsIPresShell *aPresShell, nsIContent *aContent, PRUint32 aChangeType); virtual void NotifyOfAnchorJumpTo(nsIContent *aTarget); + virtual void PresShellDestroyed(nsIPresShell* aPresShell); + virtual nsresult FireAccessibleEvent(PRUint32 aEvent, nsIAccessible *aTarget); // nsAccessibiltiyService /** * Return true if accessibility service has been shutdown. */ static PRBool IsShutdown() { return gIsShutdown; }
--- a/accessible/src/base/nsDocAccessible.cpp +++ b/accessible/src/base/nsDocAccessible.cpp @@ -591,16 +591,18 @@ nsDocAccessible::RemoveAccessNodeFromCac } //////////////////////////////////////////////////////////////////////////////// // nsAccessNode PRBool nsDocAccessible::Init() { + NS_LOG_ACCDOCCREATE_FOR("document initialize", mDocument, this) + // Initialize event queue. mEventQueue = new nsAccEventQueue(this); if (!mEventQueue) return PR_FALSE; AddEventListeners(); // Fire reorder event to notify new accessible document has been created and @@ -625,18 +627,18 @@ nsDocAccessible::Shutdown() if (mEventQueue) { mEventQueue->Shutdown(); mEventQueue = nsnull; } RemoveEventListeners(); if (mParent) { - NS_LOG_ACCDOCDESTROY_FOR("remove document from outer doc", mDocument, this); mParent->RemoveChild(this); + mParent = nsnull; } mWeakShell = nsnull; // Avoid reentrancy ClearCache(mAccessibleCache); nsCOMPtr<nsIDocument> kungFuDeathGripDoc = mDocument; mDocument = nsnull;
--- a/accessible/src/base/nsDocAccessible.h +++ b/accessible/src/base/nsDocAccessible.h @@ -119,18 +119,16 @@ public: virtual nsresult HandleAccEvent(nsAccEvent *aAccEvent); #endif // nsIAccessibleText NS_IMETHOD GetAssociatedEditor(nsIEditor **aEditor); // nsDocAccessible - nsIDocument *GetDOMDocument() const { return mDocument; } - /** * Return true if associated DOM document was loaded and isn't unloading. */ PRBool IsContentLoaded() const { return mDocument && mDocument->IsVisible() && (mDocument->IsShowing() || mIsLoaded); }
--- a/accessible/src/base/nsOuterDocAccessible.cpp +++ b/accessible/src/base/nsOuterDocAccessible.cpp @@ -154,27 +154,30 @@ nsOuterDocAccessible::DoAction(PRUint8 a } //////////////////////////////////////////////////////////////////////////////// // nsAccessNode public void nsOuterDocAccessible::Shutdown() { - // Shutdown child document if any. + // XXX: sometimes outerdoc accessible is shutdown because of layout style + // change however the presshell of underlying document isn't destroyed and + // the document doesn't get pagehide events. Shutdown underlying document if + // any to avoid hanging document accessible. + NS_LOG_ACCDOCDESTROY_MSG("A11y outerdoc shutdown") + NS_LOG_ACCDOCDESTROY_ACCADDRESS("outerdoc", this) + nsAccessible *childAcc = mChildren.SafeElementAt(0, nsnull); if (childAcc) { - nsRefPtr<nsDocAccessible> docAcc(do_QueryObject(childAcc)); - NS_LOG_ACCDOCDESTROY_FOR("outerdoc document shutdown", - docAcc->GetDOMDocument(), docAcc.get()) - GetAccService()->ShutdownDocAccessiblesInTree(docAcc->GetDOMDocument()); + NS_LOG_ACCDOCDESTROY("outerdoc's child document shutdown", + childAcc->GetDocumentNode()) + GetAccService()->ShutdownDocAccessiblesInTree(childAcc->GetDocumentNode()); } - nsAccessible::InvalidateChildren(); - nsAccessibleWrap::Shutdown(); } //////////////////////////////////////////////////////////////////////////////// // nsAccessible public void nsOuterDocAccessible::InvalidateChildren() @@ -196,35 +199,46 @@ nsOuterDocAccessible::AppendChild(nsAcce { NS_ASSERTION(!mChildren.Length(), "Previous child document of outerdoc accessible wasn't removed!"); if (!mChildren.AppendElement(aAccessible)) return PR_FALSE; aAccessible->SetParent(this); + + NS_LOG_ACCDOCCREATE("append document to outerdoc", + aAccessible->GetDocumentNode()) + NS_LOG_ACCDOCCREATE_ACCADDRESS("outerdoc", this) + return PR_TRUE; } PRBool nsOuterDocAccessible::RemoveChild(nsAccessible *aAccessible) { nsAccessible *child = mChildren.SafeElementAt(0, nsnull); if (child != aAccessible) { NS_ERROR("Wrong child to remove!"); return PR_FALSE; } + NS_LOG_ACCDOCDESTROY("remove document from outerdoc", + child->GetDocumentNode()) + NS_LOG_ACCDOCDESTROY_ACCADDRESS("outerdoc", this) + mChildren.RemoveElement(child); + NS_ASSERTION(!mChildren.Length(), "This child document of outerdoc accessible wasn't removed!"); return PR_TRUE; } + //////////////////////////////////////////////////////////////////////////////// // nsAccessible protected void nsOuterDocAccessible::CacheChildren() { // Request document accessible for the content document to make sure it's // created because once it's created it appends itself as a child.
--- a/accessible/tests/mochitest/events.js +++ b/accessible/tests/mochitest/events.js @@ -21,16 +21,21 @@ const EVENT_VALUE_CHANGE = nsIAccessible // General /** * Set up this variable to dump events into DOM. */ var gA11yEventDumpID = ""; /** + * Set up this variable to dump event processing into console. + */ +var gA11yEventDumpToConsole = false; + +/** * Executes the function when requested event is handled. * * @param aEventType [in] event type * @param aTarget [in] event target * @param aFunc [in] function to call when event is handled * @param aContext [in, optional] object in which context the function is * called * @param aArg1 [in, optional] argument passed into the function @@ -257,16 +262,19 @@ function eventQueue(aEventType) return; } // Start processing of next invoker. invoker = this.getNextInvoker(); this.setEventHandler(invoker); + if (gA11yEventDumpToConsole) + dump("\nEvent queue: \n invoke: " + invoker.getID() + "\n"); + if (invoker.invoke() == INVOKER_ACTION_FAILED) { // Invoker failed to prepare action, fail and finish tests. this.processNextInvoker(); return; } if (this.areAllEventsUnexpected()) this.processNextInvokerInTimeout(true);
--- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -1811,16 +1811,26 @@ PresShell::Destroy() delete mReflowCountMgr; mReflowCountMgr = nsnull; } #endif if (mHaveShutDown) return; +#ifdef ACCESSIBILITY + if (gIsAccessibilityActive) { + nsCOMPtr<nsIAccessibilityService> accService = + do_GetService("@mozilla.org/accessibilityService;1"); + if (accService) { + accService->PresShellDestroyed(this); + } + } +#endif // ACCESSIBILITY + MaybeReleaseCapturingContent(); mContentToScrollTo = nsnull; if (mPresContext) { // We need to notify the destroying the nsPresContext to ESM for // suppressing to use from ESM. mPresContext->EventStateManager()->NotifyDestroyPresContext(mPresContext);