зеркало из https://github.com/mozilla/gecko-dev.git
Avoid a crash in nsAutoScrollTimer by keeping a reference to the content instead of the view. bug 322084, patch by jpl24 <jlurz24@gmail.com>, r+sr=roc
This commit is contained in:
Родитель
5472b873cc
Коммит
75ca976432
|
@ -2077,6 +2077,14 @@ static nsIView* GetNearestCapturingView(nsIFrame* aFrame) {
|
|||
return view;
|
||||
}
|
||||
|
||||
nsIFrame* nsFrame::GetNearestCapturingFrame(nsIFrame* aFrame) {
|
||||
nsIFrame* captureFrame = aFrame;
|
||||
while (captureFrame && !captureFrame->GetMouseCapturer()) {
|
||||
captureFrame = captureFrame->GetParent();
|
||||
}
|
||||
return captureFrame;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFrame::HandleDrag(nsPresContext* aPresContext,
|
||||
nsGUIEvent* aEvent,
|
||||
nsEventStatus* aEventStatus)
|
||||
|
|
|
@ -209,6 +209,15 @@ public:
|
|||
PRInt32 aLineStart,
|
||||
PRInt8 aOutSideLimit
|
||||
);
|
||||
|
||||
/**
|
||||
* Find the nearest frame with a mouse capturer. If no
|
||||
* parent has mouse capture this will return null.
|
||||
* @param aFrame Frame drag began in.
|
||||
* @return Nearest capturing frame.
|
||||
*/
|
||||
static nsIFrame* GetNearestCapturingFrame(nsIFrame* aFrame);
|
||||
|
||||
NS_IMETHOD CharacterDataChanged(nsPresContext* aPresContext,
|
||||
nsIContent* aChild,
|
||||
PRBool aAppend);
|
||||
|
|
|
@ -208,7 +208,6 @@ public:
|
|||
/** StartAutoScrollTimer is responsible for scrolling views so that aPoint is always
|
||||
* visible, and for selecting any frame that contains aPoint. The timer will also reset
|
||||
* itself to fire again if we have not scrolled to the end of the document.
|
||||
* @param aPresContext is the context to use when figuring out what frame contains the point.
|
||||
* @param aView is view to use when searching for the closest frame to the point,
|
||||
* which is the view that is capturing the mouse
|
||||
* @param aPoint is relative to the view.
|
||||
|
|
|
@ -97,7 +97,7 @@ static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID);
|
|||
#include "nsIDeviceContext.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsIServiceManager.h"
|
||||
|
||||
#include "nsFrameManager.h"
|
||||
// notifications
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIDocument.h"
|
||||
|
@ -242,10 +242,22 @@ public:
|
|||
SelectionDetails **aReturnDetails, SelectionType aType, PRBool aSlowCheck);
|
||||
NS_IMETHOD Repaint(nsPresContext* aPresContext);
|
||||
|
||||
nsresult StartAutoScrollTimer(nsPresContext *aPresContext, nsIView *aView, nsPoint& aPoint, PRUint32 aDelay);
|
||||
nsresult StartAutoScrollTimer(nsPresContext *aPresContext,
|
||||
nsIView *aView,
|
||||
nsPoint& aPoint,
|
||||
PRUint32 aDelay);
|
||||
|
||||
nsresult StopAutoScrollTimer();
|
||||
nsresult DoAutoScrollView(nsPresContext *aPresContext, nsIView *aView, nsPoint& aPoint, PRBool aScrollParentViews);
|
||||
|
||||
|
||||
private:
|
||||
friend class nsAutoScrollTimer;
|
||||
|
||||
nsresult DoAutoScrollView(nsPresContext *aPresContext,
|
||||
nsIView *aView,
|
||||
nsPoint& aPoint,
|
||||
PRBool aScrollParentViews);
|
||||
|
||||
nsresult ScrollPointIntoClipView(nsPresContext *aPresContext, nsIView *aView, nsPoint& aPoint, PRBool *aDidScroll);
|
||||
nsresult ScrollPointIntoView(nsPresContext *aPresContext, nsIView *aView, nsPoint& aPoint, PRBool aScrollParentViews, PRBool *aDidScroll);
|
||||
nsresult GetViewAncestorOffset(nsIView *aView, nsIView *aAncestorView, nscoord *aXOffset, nscoord *aYOffset);
|
||||
|
@ -299,7 +311,7 @@ private:
|
|||
nsFrameSelection *mFrameSelection;
|
||||
nsWeakPtr mPresShellWeak; //weak reference to presshell.
|
||||
SelectionType mType;//type of this nsTypedSelection;
|
||||
nsAutoScrollTimer *mAutoScrollTimer; // timer for autoscrolling.
|
||||
nsRefPtr<nsAutoScrollTimer> mAutoScrollTimer; // timer for autoscrolling.
|
||||
nsCOMArray<nsISelectionListener> mSelectionListeners;
|
||||
PRPackedBool mTrueDirection;
|
||||
nsRevocableEventPtr<ScrollSelectionIntoViewEvent> mScrollEvent;
|
||||
|
@ -358,7 +370,7 @@ public:
|
|||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsAutoScrollTimer()
|
||||
: mSelection(0), mView(0), mPresContext(0), mPoint(0,0), mDelay(30)
|
||||
: mFrameSelection(0), mSelection(0), mPresContext(0), mPoint(0,0), mDelay(30)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -370,9 +382,42 @@ public:
|
|||
|
||||
nsresult Start(nsPresContext *aPresContext, nsIView *aView, nsPoint &aPoint)
|
||||
{
|
||||
mView = aView;
|
||||
mPoint = aPoint;
|
||||
|
||||
// Store the presentation context. The timer will be
|
||||
// stopped by the selection if the prescontext is destroyed.
|
||||
mPresContext = aPresContext;
|
||||
mPoint = aPoint;
|
||||
|
||||
// Store the content from the nearest capturing frame. If this returns null
|
||||
// the capturing frame is the root.
|
||||
nsIFrame* clientFrame = NS_STATIC_CAST(nsIFrame*, aView->GetClientData());
|
||||
NS_ASSERTION(clientFrame, "Missing client frame");
|
||||
|
||||
nsIFrame* capturingFrame = nsFrame::GetNearestCapturingFrame(clientFrame);
|
||||
NS_ASSERTION(!capturingFrame || capturingFrame->GetMouseCapturer(),
|
||||
"Capturing frame should have a mouse capturer" );
|
||||
|
||||
NS_ASSERTION(!capturingFrame || mPresContext == capturingFrame->GetPresContext(),
|
||||
"Shouldn't have different pres contexts");
|
||||
|
||||
NS_ASSERTION(capturingFrame != mPresContext->PresShell()->FrameManager()->GetRootFrame(),
|
||||
"Capturing frame should not be the root frame");
|
||||
|
||||
if (capturingFrame)
|
||||
{
|
||||
mContent = capturingFrame->GetContent();
|
||||
NS_ASSERTION(mContent, "Need content");
|
||||
|
||||
NS_ASSERTION(mContent != mPresContext->PresShell()->FrameManager()->GetRootFrame()->GetContent(),
|
||||
"We didn't want the root content!");
|
||||
|
||||
NS_ASSERTION(capturingFrame == nsFrame::GetNearestCapturingFrame(
|
||||
mPresContext->PresShell()->GetPrimaryFrameFor(mContent)),
|
||||
"Mapping of frame to content failed.");
|
||||
}
|
||||
|
||||
// Check that if there was no capturing frame the content is null.
|
||||
NS_ASSERTION(capturingFrame || !mContent, "Content not cleared correctly.");
|
||||
|
||||
if (!mTimer)
|
||||
{
|
||||
|
@ -388,15 +433,14 @@ public:
|
|||
|
||||
nsresult Stop()
|
||||
{
|
||||
nsresult result = NS_OK;
|
||||
|
||||
if (mTimer)
|
||||
{
|
||||
mTimer->Cancel();
|
||||
mTimer = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
mContent = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult Init(nsFrameSelection *aFrameSelection, nsTypedSelection *aSelection)
|
||||
|
@ -414,50 +458,64 @@ public:
|
|||
|
||||
NS_IMETHOD Notify(nsITimer *timer)
|
||||
{
|
||||
if (mSelection && mPresContext && mView)
|
||||
if (mSelection && mPresContext)
|
||||
{
|
||||
nsIFrame *frame = NS_STATIC_CAST(nsIFrame*, mView->GetClientData());
|
||||
// If the content is null the capturing frame must be the root frame.
|
||||
nsIFrame* capturingFrame;
|
||||
if (mContent)
|
||||
{
|
||||
nsIFrame* contentFrame = mPresContext->PresShell()->GetPrimaryFrameFor(mContent);
|
||||
if (contentFrame)
|
||||
{
|
||||
capturingFrame = nsFrame::GetNearestCapturingFrame(contentFrame);
|
||||
}
|
||||
else
|
||||
{
|
||||
capturingFrame = nsnull;
|
||||
}
|
||||
NS_ASSERTION(!capturingFrame || capturingFrame->GetMouseCapturer(),
|
||||
"Capturing frame should have a mouse capturer" );
|
||||
}
|
||||
else
|
||||
{
|
||||
capturingFrame = mPresContext->PresShell()->FrameManager()->GetRootFrame();
|
||||
}
|
||||
|
||||
if (!frame)
|
||||
// Clear the content reference now that the frame has been found.
|
||||
mContent = nsnull;
|
||||
|
||||
// This could happen for a frame with style changed to display:none or a frame
|
||||
// that was destroyed.
|
||||
if (!capturingFrame) {
|
||||
NS_WARNING("Frame destroyed or set to display:none before scroll timer fired.");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mFrameSelection->HandleDrag(frame, mPoint);
|
||||
nsIView* captureView = capturingFrame->GetMouseCapturer();
|
||||
|
||||
nsIFrame* viewFrame = NS_STATIC_CAST(nsIFrame*, captureView->GetClientData());
|
||||
NS_ASSERTION(viewFrame, "View must have a client frame");
|
||||
|
||||
mFrameSelection->HandleDrag(viewFrame, mPoint);
|
||||
|
||||
mSelection->DoAutoScrollView(mPresContext, mView, mPoint, PR_TRUE);
|
||||
mSelection->DoAutoScrollView(mPresContext, captureView, mPoint, PR_TRUE);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
nsFrameSelection *mFrameSelection;
|
||||
nsFrameSelection *mFrameSelection;
|
||||
nsTypedSelection *mSelection;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
nsIView *mView;
|
||||
nsPresContext *mPresContext;
|
||||
nsPoint mPoint;
|
||||
PRUint32 mDelay;
|
||||
nsPoint mPoint;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
nsCOMPtr<nsIContent> mContent;
|
||||
PRUint32 mDelay;
|
||||
};
|
||||
|
||||
NS_IMPL_ADDREF(nsAutoScrollTimer)
|
||||
NS_IMPL_RELEASE(nsAutoScrollTimer)
|
||||
NS_IMPL_QUERY_INTERFACE1(nsAutoScrollTimer, nsITimerCallback)
|
||||
|
||||
nsresult NS_NewAutoScrollTimer(nsAutoScrollTimer **aResult);
|
||||
|
||||
nsresult NS_NewAutoScrollTimer(nsAutoScrollTimer **aResult)
|
||||
{
|
||||
if (!aResult)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
*aResult = (nsAutoScrollTimer*) new nsAutoScrollTimer;
|
||||
|
||||
if (!aResult)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
NS_ADDREF(*aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult NS_NewSelection(nsFrameSelection **aFrameSelection);
|
||||
|
||||
nsresult NS_NewSelection(nsFrameSelection **aFrameSelection)
|
||||
|
@ -3891,7 +3949,6 @@ nsTypedSelection::nsTypedSelection(nsFrameSelection *aList)
|
|||
mFrameSelection = aList;
|
||||
mFixupState = PR_FALSE;
|
||||
mDirection = eDirNext;
|
||||
mAutoScrollTimer = nsnull;
|
||||
mCachedOffsetForFrame = nsnull;
|
||||
}
|
||||
|
||||
|
@ -3901,7 +3958,6 @@ nsTypedSelection::nsTypedSelection()
|
|||
mFrameSelection = nsnull;
|
||||
mFixupState = PR_FALSE;
|
||||
mDirection = eDirNext;
|
||||
mAutoScrollTimer = nsnull;
|
||||
mCachedOffsetForFrame = nsnull;
|
||||
}
|
||||
|
||||
|
@ -3917,7 +3973,7 @@ void nsTypedSelection::DetachFromPresentation() {
|
|||
|
||||
if (mAutoScrollTimer) {
|
||||
mAutoScrollTimer->Stop();
|
||||
NS_RELEASE(mAutoScrollTimer);
|
||||
mAutoScrollTimer = nsnull;
|
||||
}
|
||||
|
||||
mScrollEvent.Revoke();
|
||||
|
@ -4712,18 +4768,20 @@ nsTypedSelection::GetFrameSelection(nsFrameSelection **aFrameSelection) {
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsTypedSelection::StartAutoScrollTimer(nsPresContext *aPresContext, nsIView *aView, nsPoint& aPoint, PRUint32 aDelay)
|
||||
nsTypedSelection::StartAutoScrollTimer(nsPresContext *aPresContext,
|
||||
nsIView *aView,
|
||||
nsPoint& aPoint,
|
||||
PRUint32 aDelay)
|
||||
{
|
||||
NS_PRECONDITION(aView, "Need a view");
|
||||
|
||||
nsresult result;
|
||||
if (!mFrameSelection)
|
||||
return NS_OK;//nothing to do
|
||||
|
||||
if (!mAutoScrollTimer)
|
||||
{
|
||||
result = NS_NewAutoScrollTimer(&mAutoScrollTimer);
|
||||
|
||||
if (NS_FAILED(result))
|
||||
return result;
|
||||
mAutoScrollTimer = new nsAutoScrollTimer();
|
||||
|
||||
if (!mAutoScrollTimer)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
@ -5007,7 +5065,10 @@ nsTypedSelection::ScrollPointIntoView(nsPresContext *aPresContext, nsIView *aVie
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsTypedSelection::DoAutoScrollView(nsPresContext *aPresContext, nsIView *aView, nsPoint& aPoint, PRBool aScrollParentViews)
|
||||
nsTypedSelection::DoAutoScrollView(nsPresContext *aPresContext,
|
||||
nsIView *aView,
|
||||
nsPoint& aPoint,
|
||||
PRBool aScrollParentViews)
|
||||
{
|
||||
if (!aPresContext || !aView)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
@ -5022,19 +5083,14 @@ nsTypedSelection::DoAutoScrollView(nsPresContext *aPresContext, nsIView *aView,
|
|||
//
|
||||
|
||||
nsPoint globalOffset;
|
||||
|
||||
result = GetViewAncestorOffset(aView, nsnull, &globalOffset.x, &globalOffset.y);
|
||||
|
||||
if (NS_FAILED(result))
|
||||
return result;
|
||||
NS_ENSURE_SUCCESS(result, result);
|
||||
|
||||
//
|
||||
// Convert aPoint into global coordinates so we can get back
|
||||
// to the same point after all the parent views have scrolled.
|
||||
//
|
||||
|
||||
nsPoint globalPoint = aPoint + globalOffset;
|
||||
|
||||
//
|
||||
// Now scroll aPoint into view.
|
||||
//
|
||||
|
@ -5042,9 +5098,7 @@ nsTypedSelection::DoAutoScrollView(nsPresContext *aPresContext, nsIView *aView,
|
|||
PRBool didScroll = PR_FALSE;
|
||||
|
||||
result = ScrollPointIntoView(aPresContext, aView, aPoint, aScrollParentViews, &didScroll);
|
||||
|
||||
if (NS_FAILED(result))
|
||||
return result;
|
||||
NS_ENSURE_SUCCESS(result, result);
|
||||
|
||||
//
|
||||
// Start the AutoScroll timer if necessary.
|
||||
|
@ -5058,13 +5112,10 @@ nsTypedSelection::DoAutoScrollView(nsPresContext *aPresContext, nsIView *aView,
|
|||
// window and its parents may have changed their offsets.
|
||||
//
|
||||
result = GetViewAncestorOffset(aView, nsnull, &globalOffset.x, &globalOffset.y);
|
||||
|
||||
if (NS_FAILED(result))
|
||||
return result;
|
||||
NS_ENSURE_SUCCESS(result, result);
|
||||
|
||||
nsPoint svPoint = globalPoint - globalOffset;
|
||||
|
||||
result = mAutoScrollTimer->Start(aPresContext, aView, svPoint);
|
||||
mAutoScrollTimer->Start(aPresContext, aView, svPoint);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
|
Загрузка…
Ссылка в новой задаче