mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1246918 - Handle PresShell gone after FlushLayout(). r=roc
After calling FlushLayout(), PresShell::Destroy() might be called and we should consider PresShell and other resources will be no longer valid. Before this patch, AccessibleCaretManager and AccessibleCaret(s) are deallocated in PresShell::Destroy(). However FlushLayout() are all invoked in AccessibleCaretManager, we need to keep manager alive to clean up after PresShell::Destroy(). This patch makes AccessibleCaretManager live after PresShell::Destroy(), and use IsTerminated() to check whether PreShell is vaild after each FlushLayout() calls. Note that event though AccessibleCaretEventHub will be unref in PresShell::Destroy(), all the callers to AccessibleCaretEventHub's public methods already add a ref to AccessibleCaretEventHub. So we don't need to worry about AccessibleCaretEventHub and AccessibleCaretManager die immediately after PresShell::Destroy(). MozReview-Commit-ID: DDpXZ7v3zyo
This commit is contained in:
parent
f838b222e3
commit
e96307320a
@ -199,9 +199,9 @@ protected:
|
||||
|
||||
bool mSelectionBarEnabled = false;
|
||||
|
||||
// AccessibleCaretManager owns us. When it's destroyed by
|
||||
// AccessibleCaretManager owns us by a UniquePtr. When it's terminated by
|
||||
// AccessibleCaretEventHub::Terminate() which is called in
|
||||
// PresShell::Destroy(), it frees us automatically. No need to worry we
|
||||
// PresShell::Destroy(), it frees us automatically. No need to worry if we
|
||||
// outlive mPresShell.
|
||||
nsIPresShell* MOZ_NON_OWNING_REF const mPresShell = nullptr;
|
||||
|
||||
|
@ -459,7 +459,7 @@ AccessibleCaretEventHub::Terminate()
|
||||
mScrollEndInjectorTimer->Cancel();
|
||||
}
|
||||
|
||||
mManager = nullptr;
|
||||
mManager->Terminate();
|
||||
mPresShell = nullptr;
|
||||
mInitialized = false;
|
||||
}
|
||||
|
@ -104,8 +104,18 @@ AccessibleCaretManager::AccessibleCaretManager(nsIPresShell* aPresShell)
|
||||
}
|
||||
|
||||
AccessibleCaretManager::~AccessibleCaretManager()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
AccessibleCaretManager::Terminate()
|
||||
{
|
||||
CancelCaretTimeoutTimer();
|
||||
mCaretTimeoutTimer = nullptr;
|
||||
mFirstCaret = nullptr;
|
||||
mSecondCaret = nullptr;
|
||||
mActiveCaret = nullptr;
|
||||
mPresShell = nullptr;
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -132,7 +142,6 @@ AccessibleCaretManager::OnSelectionChanged(nsIDOMDocument* aDoc,
|
||||
// Update visible carets, if javascript changes are allowed.
|
||||
if (sCaretsScriptUpdates &&
|
||||
(mFirstCaret->IsLogicallyVisible() || mSecondCaret->IsLogicallyVisible())) {
|
||||
FlushLayout();
|
||||
UpdateCarets();
|
||||
return NS_OK;
|
||||
}
|
||||
@ -192,6 +201,11 @@ AccessibleCaretManager::DoNotShowCarets()
|
||||
void
|
||||
AccessibleCaretManager::UpdateCarets(UpdateCaretsHint aHint)
|
||||
{
|
||||
FlushLayout();
|
||||
if (IsTerminated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mLastUpdateCaretMode = GetCaretMode();
|
||||
|
||||
switch (mLastUpdateCaretMode) {
|
||||
@ -372,6 +386,9 @@ AccessibleCaretManager::UpdateCaretsForSelectionMode(UpdateCaretsHint aHint)
|
||||
secondCaretResult == PositionChangedResult::Changed) {
|
||||
// Flush layout to make the carets intersection correct.
|
||||
FlushLayout();
|
||||
if (IsTerminated()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (aHint == UpdateCaretsHint::Default) {
|
||||
@ -594,11 +611,6 @@ AccessibleCaretManager::OnScrollEnd()
|
||||
mFirstCaret->SetAppearance(mFirstCaretAppearanceOnScrollStart);
|
||||
mSecondCaret->SetAppearance(mSecondCaretAppearanceOnScrollStart);
|
||||
|
||||
// Flush layout to make the carets intersection correct since we turn the
|
||||
// appearance of the carets from None or NormalNotShown into something
|
||||
// visible.
|
||||
FlushLayout();
|
||||
|
||||
if (GetCaretMode() == CaretMode::Cursor) {
|
||||
if (!mFirstCaret->IsLogicallyVisible()) {
|
||||
// If the caret is hidden (Appearance::None) due to timeout or blur, no
|
||||
@ -1132,7 +1144,7 @@ AccessibleCaretManager::CaretTimeoutMs() const
|
||||
void
|
||||
AccessibleCaretManager::LaunchCaretTimeoutTimer()
|
||||
{
|
||||
if (!mCaretTimeoutTimer || CaretTimeoutMs() == 0 ||
|
||||
if (!mPresShell || !mCaretTimeoutTimer || CaretTimeoutMs() == 0 ||
|
||||
GetCaretMode() != CaretMode::Cursor || mActiveCaret) {
|
||||
return;
|
||||
}
|
||||
@ -1159,11 +1171,12 @@ AccessibleCaretManager::CancelCaretTimeoutTimer()
|
||||
void
|
||||
AccessibleCaretManager::DispatchCaretStateChangedEvent(CaretChangedReason aReason) const
|
||||
{
|
||||
// Holding PresShell to prevent AccessibleCaretManager to be destroyed.
|
||||
nsCOMPtr<nsIPresShell> presShell = mPresShell;
|
||||
if (!mPresShell) {
|
||||
return;
|
||||
}
|
||||
|
||||
FlushLayout();
|
||||
if (presShell->IsDestroying()) {
|
||||
if (IsTerminated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,9 @@ public:
|
||||
explicit AccessibleCaretManager(nsIPresShell* aPresShell);
|
||||
virtual ~AccessibleCaretManager();
|
||||
|
||||
// Called by AccessibleCaretEventHub to inform us that PresShell is destroyed.
|
||||
void Terminate();
|
||||
|
||||
// The aPoint in the following public methods should be relative to root
|
||||
// frame.
|
||||
|
||||
@ -124,7 +127,9 @@ protected:
|
||||
friend std::ostream& operator<<(std::ostream& aStream,
|
||||
const UpdateCaretsHint& aResult);
|
||||
|
||||
// Update carets based on current selection status.
|
||||
// Update carets based on current selection status. This function will flush
|
||||
// layout, so caller must ensure the PresShell is still valid after calling
|
||||
// this method.
|
||||
void UpdateCarets(UpdateCaretsHint aHint = UpdateCaretsHint::Default);
|
||||
|
||||
// Force hiding all carets regardless of the current selection status.
|
||||
@ -160,7 +165,11 @@ protected:
|
||||
nsresult DragCaretInternal(const nsPoint& aPoint);
|
||||
nsPoint AdjustDragBoundary(const nsPoint& aPoint) const;
|
||||
void ClearMaintainedSelection() const;
|
||||
|
||||
// Caller is responsible to use IsTerminated() to check whether PresShell is
|
||||
// still valid.
|
||||
void FlushLayout() const;
|
||||
|
||||
dom::Element* GetEditingHostForFrame(nsIFrame* aFrame) const;
|
||||
dom::Selection* GetSelection() const;
|
||||
already_AddRefed<nsFrameSelection> GetFrameSelection() const;
|
||||
@ -184,6 +193,9 @@ protected:
|
||||
// ---------------------------------------------------------------------------
|
||||
// The following functions are made virtual for stubbing or mocking in gtest.
|
||||
//
|
||||
// @return true if Terminate() had been called.
|
||||
virtual bool IsTerminated() const { return !mPresShell; }
|
||||
|
||||
// Get caret mode based on current selection.
|
||||
virtual CaretMode GetCaretMode() const;
|
||||
|
||||
@ -202,8 +214,8 @@ protected:
|
||||
|
||||
virtual bool HasNonEmptyTextContent(nsINode* aNode) const;
|
||||
|
||||
// This function will call FlushPendingNotifications. So caller must ensure
|
||||
// everything exists after calling this method.
|
||||
// This function will flush layout, so caller must ensure the PresShell is
|
||||
// still valid after calling this method.
|
||||
virtual void DispatchCaretStateChangedEvent(dom::CaretChangedReason aReason) const;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@ -211,10 +223,12 @@ protected:
|
||||
//
|
||||
nscoord mOffsetYToCaretLogicalPosition = NS_UNCONSTRAINEDSIZE;
|
||||
|
||||
// AccessibleCaretEventHub owns us. When it's Terminate() called by
|
||||
// PresShell::Destroy(), we will be destroyed. No need to worry we outlive
|
||||
// mPresShell.
|
||||
nsIPresShell* MOZ_NON_OWNING_REF const mPresShell = nullptr;
|
||||
// AccessibleCaretEventHub owns us by a UniquePtr. When it's destroyed, we'll
|
||||
// also be destroyed. No need to worry if we outlive mPresShell.
|
||||
//
|
||||
// mPresShell will be set to nullptr in Terminate(). Therefore mPresShell is
|
||||
// nullptr either we are in gtest or PresShell::IsDestroying() is true.
|
||||
nsIPresShell* MOZ_NON_OWNING_REF mPresShell = nullptr;
|
||||
|
||||
// First caret is attached to nsCaret in cursor mode, and is attached to
|
||||
// selection highlight as the left caret in selection mode.
|
||||
|
@ -93,6 +93,8 @@ public:
|
||||
|
||||
virtual void UpdateCaretsForTilt() override {}
|
||||
|
||||
virtual bool IsTerminated() const override { return false; }
|
||||
|
||||
MOCK_CONST_METHOD0(GetCaretMode, CaretMode());
|
||||
MOCK_CONST_METHOD1(DispatchCaretStateChangedEvent,
|
||||
void(CaretChangedReason aReason));
|
||||
|
Loading…
Reference in New Issue
Block a user