зеркало из https://github.com/mozilla/pjs.git
Modify event flow to avoid walking into trashed frames.
This commit is contained in:
Родитель
86806ec906
Коммит
c3708b2ed8
|
@ -46,6 +46,7 @@ public:
|
|||
nsEventStatus& aStatus) = 0;
|
||||
|
||||
NS_IMETHOD SetPresContext(nsIPresContext* aPresContext) = 0;
|
||||
NS_IMETHOD ClearFrameRefs(nsIFrame* aFrame) = 0;
|
||||
|
||||
NS_IMETHOD GetEventTarget(nsIFrame **aFrame) = 0;
|
||||
|
||||
|
|
|
@ -67,6 +67,12 @@ nsEventStateManager::HandleEvent(nsIPresContext& aPresContext,
|
|||
nsEventStatus& aStatus)
|
||||
{
|
||||
mCurrentTarget = aTargetFrame;
|
||||
|
||||
nsFrameState state;
|
||||
mCurrentTarget->GetFrameState(state);
|
||||
state |= NS_FRAME_EXTERNAL_REFERENCE;
|
||||
mCurrentTarget->SetFrameState(state);
|
||||
|
||||
aStatus = nsEventStatus_eIgnore;
|
||||
|
||||
switch (aEvent->message) {
|
||||
|
@ -100,6 +106,18 @@ nsEventStateManager::SetPresContext(nsIPresContext* aPresContext)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEventStateManager::ClearFrameRefs(nsIFrame* aFrame)
|
||||
{
|
||||
if (aFrame == mLastMouseOverFrame) {
|
||||
mLastMouseOverFrame = nsnull;
|
||||
}
|
||||
else if (aFrame == mCurrentTarget) {
|
||||
mCurrentTarget = nsnull;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsEventStateManager::UpdateCursor(nsIPresContext& aPresContext, nsPoint& aPoint, nsIFrame* aTargetFrame)
|
||||
{
|
||||
|
@ -171,7 +189,10 @@ nsEventStateManager::GenerateMouseEnterExit(nsIPresContext& aPresContext, nsGUIE
|
|||
mLastMouseOverFrame->GetContent(lastContent);
|
||||
|
||||
if (lastContent != targetContent) {
|
||||
lastContent->HandleDOMEvent(aPresContext, &event, nsnull, DOM_EVENT_INIT, status);
|
||||
//XXX This event should still go somewhere!!
|
||||
if (nsnull != lastContent) {
|
||||
lastContent->HandleDOMEvent(aPresContext, &event, nsnull, DOM_EVENT_INIT, status);
|
||||
}
|
||||
}
|
||||
|
||||
//Now dispatch to the frame
|
||||
|
@ -186,7 +207,10 @@ nsEventStateManager::GenerateMouseEnterExit(nsIPresContext& aPresContext, nsGUIE
|
|||
|
||||
//The frame has change but the content may not have. Check before dispatching to content
|
||||
if (lastContent != targetContent) {
|
||||
targetContent->HandleDOMEvent(aPresContext, &event, nsnull, DOM_EVENT_INIT, status);
|
||||
//XXX This event should still go somewhere!!
|
||||
if (nsnull != targetContent) {
|
||||
targetContent->HandleDOMEvent(aPresContext, &event, nsnull, DOM_EVENT_INIT, status);
|
||||
}
|
||||
}
|
||||
|
||||
//Now dispatch to the frame
|
||||
|
@ -196,6 +220,11 @@ nsEventStateManager::GenerateMouseEnterExit(nsIPresContext& aPresContext, nsGUIE
|
|||
NS_IF_RELEASE(targetContent);
|
||||
|
||||
mLastMouseOverFrame = aTargetFrame;
|
||||
|
||||
nsFrameState state;
|
||||
mLastMouseOverFrame->GetFrameState(state);
|
||||
state |= NS_FRAME_EXTERNAL_REFERENCE;
|
||||
mLastMouseOverFrame->SetFrameState(state);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -41,12 +41,14 @@ public:
|
|||
nsEventStatus& aStatus);
|
||||
|
||||
NS_IMETHOD SetPresContext(nsIPresContext* aPresContext);
|
||||
NS_IMETHOD ClearFrameRefs(nsIFrame* aFrame);
|
||||
|
||||
NS_IMETHOD GetEventTarget(nsIFrame **aFrame);
|
||||
|
||||
NS_IMETHOD GetActiveLink(nsIContent **aLink);
|
||||
NS_IMETHOD SetActiveLink(nsIContent *aLink);
|
||||
|
||||
|
||||
protected:
|
||||
void UpdateCursor(nsIPresContext& aPresContext, nsPoint& aPoint, nsIFrame* aTargetFrame);
|
||||
void GenerateMouseEnterExit(nsIPresContext& aPresContext, nsGUIEvent* aEvent, nsIFrame* aTargetFrame);
|
||||
|
|
|
@ -100,6 +100,7 @@ public:
|
|||
|
||||
virtual void ProcessReflowCommands() = 0;
|
||||
|
||||
virtual void ClearFrameRefs(nsIFrame* aFrame) = 0;
|
||||
/**
|
||||
* Given a frame, cough up a rendering context suitable for use with
|
||||
* the frame.
|
||||
|
|
|
@ -215,6 +215,7 @@ public:
|
|||
virtual nsIFrame* FindFrameWithContent(nsIContent* aContent);
|
||||
virtual void AppendReflowCommand(nsIReflowCommand* aReflowCommand);
|
||||
virtual void ProcessReflowCommands();
|
||||
virtual void ClearFrameRefs(nsIFrame*);
|
||||
NS_IMETHOD CreateRenderingContext(nsIFrame *aFrame, nsIRenderingContext *&aContext);
|
||||
|
||||
//nsIViewObserver interface
|
||||
|
@ -739,6 +740,16 @@ PresShell::ProcessReflowCommands()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
PresShell::ClearFrameRefs(nsIFrame* aFrame)
|
||||
{
|
||||
nsIEventStateManager *manager;
|
||||
if (NS_OK == mPresContext->GetEventStateManager(&manager)) {
|
||||
manager->ClearFrameRefs(aFrame);
|
||||
NS_RELEASE(manager);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP PresShell :: CreateRenderingContext(nsIFrame *aFrame,
|
||||
nsIRenderingContext *&aContext)
|
||||
{
|
||||
|
@ -1013,7 +1024,7 @@ NS_IMETHODIMP PresShell :: HandleEvent(nsIView *aView,
|
|||
|
||||
NS_ASSERTION(!(nsnull == aView), "null view");
|
||||
|
||||
if (mIsDestroying) {
|
||||
if (mIsDestroying || mReflowLockCount > 0) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -105,6 +105,11 @@ typedef PRUint32 nsFrameState;
|
|||
// must operate differently.
|
||||
#define NS_FRAME_OUTSIDE_CHILDREN 0x00000008
|
||||
|
||||
// If this bit is set then a reference to the frame is being held
|
||||
// elsewhere. The frame may want to send a notification when it is
|
||||
// destroyed to allow these references to be cleared.
|
||||
#define NS_FRAME_EXTERNAL_REFERENCE 0x00000010
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
|
|
|
@ -100,6 +100,7 @@ public:
|
|||
|
||||
virtual void ProcessReflowCommands() = 0;
|
||||
|
||||
virtual void ClearFrameRefs(nsIFrame* aFrame) = 0;
|
||||
/**
|
||||
* Given a frame, cough up a rendering context suitable for use with
|
||||
* the frame.
|
||||
|
|
|
@ -46,6 +46,7 @@ public:
|
|||
nsEventStatus& aStatus) = 0;
|
||||
|
||||
NS_IMETHOD SetPresContext(nsIPresContext* aPresContext) = 0;
|
||||
NS_IMETHOD ClearFrameRefs(nsIFrame* aFrame) = 0;
|
||||
|
||||
NS_IMETHOD GetEventTarget(nsIFrame **aFrame) = 0;
|
||||
|
||||
|
|
|
@ -67,6 +67,12 @@ nsEventStateManager::HandleEvent(nsIPresContext& aPresContext,
|
|||
nsEventStatus& aStatus)
|
||||
{
|
||||
mCurrentTarget = aTargetFrame;
|
||||
|
||||
nsFrameState state;
|
||||
mCurrentTarget->GetFrameState(state);
|
||||
state |= NS_FRAME_EXTERNAL_REFERENCE;
|
||||
mCurrentTarget->SetFrameState(state);
|
||||
|
||||
aStatus = nsEventStatus_eIgnore;
|
||||
|
||||
switch (aEvent->message) {
|
||||
|
@ -100,6 +106,18 @@ nsEventStateManager::SetPresContext(nsIPresContext* aPresContext)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEventStateManager::ClearFrameRefs(nsIFrame* aFrame)
|
||||
{
|
||||
if (aFrame == mLastMouseOverFrame) {
|
||||
mLastMouseOverFrame = nsnull;
|
||||
}
|
||||
else if (aFrame == mCurrentTarget) {
|
||||
mCurrentTarget = nsnull;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsEventStateManager::UpdateCursor(nsIPresContext& aPresContext, nsPoint& aPoint, nsIFrame* aTargetFrame)
|
||||
{
|
||||
|
@ -171,7 +189,10 @@ nsEventStateManager::GenerateMouseEnterExit(nsIPresContext& aPresContext, nsGUIE
|
|||
mLastMouseOverFrame->GetContent(lastContent);
|
||||
|
||||
if (lastContent != targetContent) {
|
||||
lastContent->HandleDOMEvent(aPresContext, &event, nsnull, DOM_EVENT_INIT, status);
|
||||
//XXX This event should still go somewhere!!
|
||||
if (nsnull != lastContent) {
|
||||
lastContent->HandleDOMEvent(aPresContext, &event, nsnull, DOM_EVENT_INIT, status);
|
||||
}
|
||||
}
|
||||
|
||||
//Now dispatch to the frame
|
||||
|
@ -186,7 +207,10 @@ nsEventStateManager::GenerateMouseEnterExit(nsIPresContext& aPresContext, nsGUIE
|
|||
|
||||
//The frame has change but the content may not have. Check before dispatching to content
|
||||
if (lastContent != targetContent) {
|
||||
targetContent->HandleDOMEvent(aPresContext, &event, nsnull, DOM_EVENT_INIT, status);
|
||||
//XXX This event should still go somewhere!!
|
||||
if (nsnull != targetContent) {
|
||||
targetContent->HandleDOMEvent(aPresContext, &event, nsnull, DOM_EVENT_INIT, status);
|
||||
}
|
||||
}
|
||||
|
||||
//Now dispatch to the frame
|
||||
|
@ -196,6 +220,11 @@ nsEventStateManager::GenerateMouseEnterExit(nsIPresContext& aPresContext, nsGUIE
|
|||
NS_IF_RELEASE(targetContent);
|
||||
|
||||
mLastMouseOverFrame = aTargetFrame;
|
||||
|
||||
nsFrameState state;
|
||||
mLastMouseOverFrame->GetFrameState(state);
|
||||
state |= NS_FRAME_EXTERNAL_REFERENCE;
|
||||
mLastMouseOverFrame->SetFrameState(state);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -41,12 +41,14 @@ public:
|
|||
nsEventStatus& aStatus);
|
||||
|
||||
NS_IMETHOD SetPresContext(nsIPresContext* aPresContext);
|
||||
NS_IMETHOD ClearFrameRefs(nsIFrame* aFrame);
|
||||
|
||||
NS_IMETHOD GetEventTarget(nsIFrame **aFrame);
|
||||
|
||||
NS_IMETHOD GetActiveLink(nsIContent **aLink);
|
||||
NS_IMETHOD SetActiveLink(nsIContent *aLink);
|
||||
|
||||
|
||||
protected:
|
||||
void UpdateCursor(nsIPresContext& aPresContext, nsPoint& aPoint, nsIFrame* aTargetFrame);
|
||||
void GenerateMouseEnterExit(nsIPresContext& aPresContext, nsGUIEvent* aEvent, nsIFrame* aTargetFrame);
|
||||
|
|
|
@ -312,6 +312,14 @@ NS_IMETHODIMP nsFrame::SetInitialChildList(nsIPresContext& aPresContext,
|
|||
|
||||
NS_IMETHODIMP nsFrame::DeleteFrame(nsIPresContext& aPresContext)
|
||||
{
|
||||
if (mState & NS_FRAME_EXTERNAL_REFERENCE) {
|
||||
nsIPresShell *shell = aPresContext.GetShell();
|
||||
if (nsnull != shell) {
|
||||
shell->ClearFrameRefs(this);
|
||||
NS_RELEASE(shell);
|
||||
}
|
||||
}
|
||||
|
||||
//XXX Why is this done in nsFrame instead of some frame class
|
||||
// that actually loads images?
|
||||
aPresContext.StopLoadImage(this);
|
||||
|
|
|
@ -105,6 +105,11 @@ typedef PRUint32 nsFrameState;
|
|||
// must operate differently.
|
||||
#define NS_FRAME_OUTSIDE_CHILDREN 0x00000008
|
||||
|
||||
// If this bit is set then a reference to the frame is being held
|
||||
// elsewhere. The frame may want to send a notification when it is
|
||||
// destroyed to allow these references to be cleared.
|
||||
#define NS_FRAME_EXTERNAL_REFERENCE 0x00000010
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
|
|
|
@ -312,6 +312,14 @@ NS_IMETHODIMP nsFrame::SetInitialChildList(nsIPresContext& aPresContext,
|
|||
|
||||
NS_IMETHODIMP nsFrame::DeleteFrame(nsIPresContext& aPresContext)
|
||||
{
|
||||
if (mState & NS_FRAME_EXTERNAL_REFERENCE) {
|
||||
nsIPresShell *shell = aPresContext.GetShell();
|
||||
if (nsnull != shell) {
|
||||
shell->ClearFrameRefs(this);
|
||||
NS_RELEASE(shell);
|
||||
}
|
||||
}
|
||||
|
||||
//XXX Why is this done in nsFrame instead of some frame class
|
||||
// that actually loads images?
|
||||
aPresContext.StopLoadImage(this);
|
||||
|
|
|
@ -215,6 +215,7 @@ public:
|
|||
virtual nsIFrame* FindFrameWithContent(nsIContent* aContent);
|
||||
virtual void AppendReflowCommand(nsIReflowCommand* aReflowCommand);
|
||||
virtual void ProcessReflowCommands();
|
||||
virtual void ClearFrameRefs(nsIFrame*);
|
||||
NS_IMETHOD CreateRenderingContext(nsIFrame *aFrame, nsIRenderingContext *&aContext);
|
||||
|
||||
//nsIViewObserver interface
|
||||
|
@ -739,6 +740,16 @@ PresShell::ProcessReflowCommands()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
PresShell::ClearFrameRefs(nsIFrame* aFrame)
|
||||
{
|
||||
nsIEventStateManager *manager;
|
||||
if (NS_OK == mPresContext->GetEventStateManager(&manager)) {
|
||||
manager->ClearFrameRefs(aFrame);
|
||||
NS_RELEASE(manager);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP PresShell :: CreateRenderingContext(nsIFrame *aFrame,
|
||||
nsIRenderingContext *&aContext)
|
||||
{
|
||||
|
@ -1013,7 +1024,7 @@ NS_IMETHODIMP PresShell :: HandleEvent(nsIView *aView,
|
|||
|
||||
NS_ASSERTION(!(nsnull == aView), "null view");
|
||||
|
||||
if (mIsDestroying) {
|
||||
if (mIsDestroying || mReflowLockCount > 0) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче