Don't crash if views were destroyed while flushing notifications. b=421839 r+sr=roc

This commit is contained in:
Mats Palmgren 2008-12-08 00:11:37 +01:00
Родитель 3337889961
Коммит d9338f796c
3 изменённых файлов: 41 добавлений и 8 удалений

Просмотреть файл

@ -297,6 +297,7 @@ public:
* @param aPoint is relative to the view.
* @param aDelay is the timer's interval.
*/
/*unsafe*/
nsresult StartAutoScrollTimer(nsIView *aView,
nsPoint aPoint,
PRUint32 aDelay);
@ -352,6 +353,7 @@ public:
* @param aIsSynchronous when PR_TRUE, scrolls the selection into view
* at some point after the method returns.request which is processed
*/
/*unsafe*/
nsresult ScrollSelectionIntoView(SelectionType aType,
SelectionRegion aRegion,
PRBool aIsSynchronous) const;
@ -558,7 +560,7 @@ public:
nsIPresShell *GetShell()const { return mShell; }
void DisconnectFromPresShell() { mShell = nsnull; }
void DisconnectFromPresShell() { StopAutoScrollTimer(); mShell = nsnull; }
private:
nsresult TakeFocus(nsIContent *aNewFocus,
PRUint32 aContentOffset,

Просмотреть файл

@ -246,6 +246,7 @@ public:
SelectionDetails **aReturnDetails, SelectionType aType, PRBool aSlowCheck);
NS_IMETHOD Repaint(nsPresContext* aPresContext);
// Note: StartAutoScrollTimer might destroy arbitrary frames, views etc.
nsresult StartAutoScrollTimer(nsPresContext *aPresContext,
nsIView *aView,
nsPoint& aPoint,
@ -257,12 +258,15 @@ public:
private:
friend class nsAutoScrollTimer;
// Note: DoAutoScrollView might destroy arbitrary frames, views etc.
nsresult DoAutoScrollView(nsPresContext *aPresContext,
nsIView *aView,
nsPoint& aPoint,
PRBool aScrollParentViews);
// Note: ScrollPointIntoClipView might destroy arbitrary frames, views etc.
nsresult ScrollPointIntoClipView(nsPresContext *aPresContext, nsIView *aView, nsPoint& aPoint, PRBool *aDidScroll);
// Note: ScrollPointIntoView might destroy arbitrary frames, views etc.
nsresult ScrollPointIntoView(nsPresContext *aPresContext, nsIView *aView, nsPoint& aPoint, PRBool aScrollParentViews, PRBool *aDidScroll);
nsresult GetViewAncestorOffset(nsIView *aView, nsIView *aAncestorView, nscoord *aXOffset, nscoord *aYOffset);
@ -5084,10 +5088,25 @@ nsTypedSelection::ScrollPointIntoClipView(nsPresContext *aPresContext, nsIView *
if (dx != 0 || dy != 0)
{
// Make sure latest bits are available before we scroll them.
aPresContext->GetViewManager()->Composite();
nsCOMPtr<nsIPresShell> presShell;
GetPresShell(getter_AddRefs(presShell));
NS_ASSERTION(presShell, "no pres shell");
// Now scroll the view!
nsWeakView weakView = scrollableView->View();
// Make sure latest bits are available before we scroll them. This flushes
// pending notifications and thus might destroy stuff (bug 421839).
// We need to hold a strong ref on the view manager to keep it alive.
nsCOMPtr<nsIViewManager> viewManager = aPresContext->GetViewManager();
viewManager->Composite();
if (!weakView.IsAlive()) {
return NS_ERROR_NULL_POINTER;
}
if (presShell->IsDestroying()) {
return NS_ERROR_NULL_POINTER;
}
result = scrollableView->ScrollTo(bounds.x + dx, bounds.y + dy, 0);

Просмотреть файл

@ -1764,14 +1764,26 @@ void nsViewManager::UpdateWidgetsForView(nsView* aView)
{
NS_PRECONDITION(aView, "Must have view!");
nsWeakView parentWeakView = aView;
if (aView->HasWidget()) {
aView->GetWidget()->Update();
aView->GetWidget()->Update(); // Flushes Layout!
if (!parentWeakView.IsAlive()) {
return;
}
}
for (nsView* childView = aView->GetFirstChild();
childView;
childView = childView->GetNextSibling()) {
nsView* childView = aView->GetFirstChild();
while (childView) {
nsWeakView childWeakView = childView;
UpdateWidgetsForView(childView);
if (NS_LIKELY(childWeakView.IsAlive())) {
childView = childView->GetNextSibling();
}
else {
// The current view was destroyed - restart at the first child if the
// parent is still alive.
childView = parentWeakView.IsAlive() ? aView->GetFirstChild() : nsnull;
}
}
}