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

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

@ -246,6 +246,7 @@ public:
SelectionDetails **aReturnDetails, SelectionType aType, PRBool aSlowCheck); SelectionDetails **aReturnDetails, SelectionType aType, PRBool aSlowCheck);
NS_IMETHOD Repaint(nsPresContext* aPresContext); NS_IMETHOD Repaint(nsPresContext* aPresContext);
// Note: StartAutoScrollTimer might destroy arbitrary frames, views etc.
nsresult StartAutoScrollTimer(nsPresContext *aPresContext, nsresult StartAutoScrollTimer(nsPresContext *aPresContext,
nsIView *aView, nsIView *aView,
nsPoint& aPoint, nsPoint& aPoint,
@ -257,12 +258,15 @@ public:
private: private:
friend class nsAutoScrollTimer; friend class nsAutoScrollTimer;
// Note: DoAutoScrollView might destroy arbitrary frames, views etc.
nsresult DoAutoScrollView(nsPresContext *aPresContext, nsresult DoAutoScrollView(nsPresContext *aPresContext,
nsIView *aView, nsIView *aView,
nsPoint& aPoint, nsPoint& aPoint,
PRBool aScrollParentViews); PRBool aScrollParentViews);
// Note: ScrollPointIntoClipView might destroy arbitrary frames, views etc.
nsresult ScrollPointIntoClipView(nsPresContext *aPresContext, nsIView *aView, nsPoint& aPoint, PRBool *aDidScroll); 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 ScrollPointIntoView(nsPresContext *aPresContext, nsIView *aView, nsPoint& aPoint, PRBool aScrollParentViews, PRBool *aDidScroll);
nsresult GetViewAncestorOffset(nsIView *aView, nsIView *aAncestorView, nscoord *aXOffset, nscoord *aYOffset); nsresult GetViewAncestorOffset(nsIView *aView, nsIView *aAncestorView, nscoord *aXOffset, nscoord *aYOffset);
@ -5084,10 +5088,25 @@ nsTypedSelection::ScrollPointIntoClipView(nsPresContext *aPresContext, nsIView *
if (dx != 0 || dy != 0) if (dx != 0 || dy != 0)
{ {
// Make sure latest bits are available before we scroll them. nsCOMPtr<nsIPresShell> presShell;
aPresContext->GetViewManager()->Composite(); 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); 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!"); NS_PRECONDITION(aView, "Must have view!");
nsWeakView parentWeakView = aView;
if (aView->HasWidget()) { if (aView->HasWidget()) {
aView->GetWidget()->Update(); aView->GetWidget()->Update(); // Flushes Layout!
if (!parentWeakView.IsAlive()) {
return;
}
} }
for (nsView* childView = aView->GetFirstChild(); nsView* childView = aView->GetFirstChild();
childView; while (childView) {
childView = childView->GetNextSibling()) { nsWeakView childWeakView = childView;
UpdateWidgetsForView(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;
}
} }
} }