From fcea19dfd2c426bac0456da850e7c12258e4b9eb Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 8 Apr 2024 17:11:26 +0200 Subject: Adding upstream version 115.8.0esr. Signed-off-by: Daniel Baumann --- accessible/base/NotificationController.cpp | 67 +++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 14 deletions(-) (limited to 'accessible/base/NotificationController.cpp') diff --git a/accessible/base/NotificationController.cpp b/accessible/base/NotificationController.cpp index 6ac4223b7e..c7a702831f 100644 --- a/accessible/base/NotificationController.cpp +++ b/accessible/base/NotificationController.cpp @@ -41,7 +41,11 @@ NotificationController::NotificationController(DocAccessible* aDocument, NotificationController::~NotificationController() { NS_ASSERTION(!mDocument, "Controller wasn't shutdown properly!"); - if (mDocument) Shutdown(); + if (mDocument) { + Shutdown(); + } + MOZ_RELEASE_ASSERT(mObservingState == eNotObservingRefresh, + "Must unregister before being destroyed"); } //////////////////////////////////////////////////////////////////////////////// @@ -53,7 +57,9 @@ NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE(NotificationController) NS_IMPL_CYCLE_COLLECTION_CLASS(NotificationController) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(NotificationController) - if (tmp->mDocument) tmp->Shutdown(); + if (tmp->mDocument) { + tmp->Shutdown(); + } NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(NotificationController) @@ -78,8 +84,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END void NotificationController::Shutdown() { if (mObservingState != eNotObservingRefresh && mPresShell->RemoveRefreshObserver(this, FlushType::Display)) { + // Note, this was our last chance to unregister, since we're about to + // clear mPresShell further down in this function. mObservingState = eNotObservingRefresh; } + MOZ_RELEASE_ASSERT(mObservingState == eNotObservingRefresh, + "Must unregister before being destroyed (and we just " + "passed our last change to unregister)"); + // Immediately null out mPresShell, to prevent us from being registered as a + // refresh observer again. + mPresShell = nullptr; // Shutdown handling child documents. int32_t childDocCount = mHangingChildDocuments.Length(); @@ -92,7 +106,6 @@ void NotificationController::Shutdown() { mHangingChildDocuments.Clear(); mDocument = nullptr; - mPresShell = nullptr; mTextHash.Clear(); mContentInsertions.Clear(); @@ -434,9 +447,11 @@ void NotificationController::ScheduleContentInsertion( } void NotificationController::ScheduleProcessing() { - // If notification flush isn't planed yet start notification flush + // If notification flush isn't planned yet, start notification flush // asynchronously (after style and layout). - if (mObservingState == eNotObservingRefresh) { + // Note: the mPresShell null-check might be unnecessary; it's just to prevent + // a null-deref here, if we somehow get called after we've been shut down. + if (mObservingState == eNotObservingRefresh && mPresShell) { if (mPresShell->AddRefreshObserver(this, FlushType::Display, "Accessibility notifications")) { mObservingState = eRefreshObserving; @@ -656,12 +671,17 @@ void NotificationController::WillRefresh(mozilla::TimeStamp aTime) { AUTO_PROFILER_LABEL("NotificationController::WillRefresh", A11Y); - // If the document accessible that notification collector was created for is - // now shut down, don't process notifications anymore. - NS_ASSERTION( + // If mDocument is null, the document accessible that this notification + // controller was created for is now shut down. This means we've lost our + // ability to unregister ourselves, which is bad. (However, it also shouldn't + // be logically possible for us to get here with a null mDocument; the only + // thing that clears that pointer is our Shutdown() method, which first + // unregisters and fatally asserts if that fails). + MOZ_RELEASE_ASSERT( mDocument, "The document was shut down while refresh observer is attached!"); - if (!mDocument || ipc::ProcessChild::ExpectingShutdown()) { + + if (ipc::ProcessChild::ExpectingShutdown()) { return; } @@ -835,7 +855,9 @@ void NotificationController::WillRefresh(mozilla::TimeStamp aTime) { nsTArray> newChildDocs; for (uint32_t idx = 0; idx < hangingDocCnt; idx++) { DocAccessible* childDoc = mHangingChildDocuments[idx]; - if (childDoc->IsDefunct()) continue; + if (childDoc->IsDefunct()) { + continue; + } if (IPCAccessibilityActive() && !mDocument->IPCDoc()) { childDoc->Shutdown(); @@ -874,12 +896,16 @@ void NotificationController::WillRefresh(mozilla::TimeStamp aTime) { uint32_t childDocCnt = mDocument->ChildDocumentCount(), childDocIdx = 0; for (; childDocIdx < childDocCnt; childDocIdx++) { DocAccessible* childDoc = mDocument->GetChildDocumentAt(childDocIdx); - if (!childDoc->HasLoadState(DocAccessible::eCompletelyLoaded)) break; + if (!childDoc->HasLoadState(DocAccessible::eCompletelyLoaded)) { + break; + } } if (childDocIdx == childDocCnt) { mDocument->ProcessLoad(); - if (!mDocument) return; + if (!mDocument) { + return; + } } } @@ -909,7 +935,9 @@ void NotificationController::WillRefresh(mozilla::TimeStamp aTime) { uint32_t notificationCount = notifications.Length(); for (uint32_t idx = 0; idx < notificationCount; idx++) { notifications[idx]->Process(); - if (!mDocument) return; + if (!mDocument) { + return; + } } if (ipc::ProcessChild::ExpectingShutdown()) { @@ -991,8 +1019,19 @@ void NotificationController::WillRefresh(mozilla::TimeStamp aTime) { } } + if (!mDocument) { + // A null mDocument means we've gotten a Shutdown() call (presumably via + // some script that we triggered above), and that means we're done here. + // Note: in this case, it's important that don't modify mObservingState; + // Shutdown() will have *unregistered* us as a refresh observer, and we + // don't want to mistakenly overwrite mObservingState and fool ourselves + // into thinking we've re-registered when we really haven't! + MOZ_ASSERT(mObservingState == eNotObservingRefresh, + "We've been shutdown, which means we should've been " + "unregistered as a refresh observer"); + return; + } mObservingState = eRefreshObserving; - if (!mDocument) return; // Stop further processing if there are no new notifications of any kind or // events and document load is processed. -- cgit v1.2.3