Modify event flow to avoid walking into trashed frames.

This commit is contained in:
joki%netscape.com 1998-11-19 00:43:36 +00:00
Родитель 4c99ecc9ce
Коммит 65520ba928
14 изменённых файлов: 120 добавлений и 6 удалений

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

@ -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;
}