Bug 979497 - Once DispatchPointerFromMouseOrTouch is called, aFrame can be deleted. r=smaug

--HG--
extra : rebase_source : 9556dce20748b3b581f8e39df6992513e90f62ff
This commit is contained in:
Maksim Lebedev 2015-04-14 11:46:39 -04:00
Родитель 2cfe169d44
Коммит f60627631d
5 изменённых файлов: 90 добавлений и 28 удалений

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

@ -472,6 +472,7 @@ nsresult
EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
WidgetEvent* aEvent,
nsIFrame* aTargetFrame,
nsIContent* aTargetContent,
nsEventStatus* aStatus)
{
NS_ENSURE_ARG_POINTER(aStatus);
@ -481,6 +482,11 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
return NS_ERROR_NULL_POINTER;
}
NS_WARN_IF_FALSE(!aTargetFrame ||
!aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent,
"aTargetContent should be related with aTargetFrame");
mCurrentTarget = aTargetFrame;
mCurrentTargetContent = nullptr;
@ -507,10 +513,9 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
WheelTransaction::OnEvent(aEvent);
// Focus events don't necessarily need a frame.
if (NS_EVENT_NEEDS_FRAME(aEvent)) {
if (!mCurrentTarget) {
return NS_ERROR_NULL_POINTER;
}
if (!mCurrentTarget && !aTargetContent) {
NS_ERROR("mCurrentTarget and aTargetContent are null");
return NS_ERROR_NULL_POINTER;
}
#ifdef DEBUG
if (aEvent->HasDragEventMessage() && sIsPointerLocked) {
@ -1515,10 +1520,12 @@ EventStateManager::BeginTrackingDragGesture(nsPresContext* aPresContext,
// synthesized mouse move event.
mGestureDownPoint = inDownEvent->refPoint + inDownEvent->widget->WidgetToScreenOffset();
inDownFrame->GetContentForEvent(inDownEvent,
getter_AddRefs(mGestureDownContent));
if (inDownFrame) {
inDownFrame->GetContentForEvent(inDownEvent,
getter_AddRefs(mGestureDownContent));
mGestureDownFrameOwner = inDownFrame->GetContent();
mGestureDownFrameOwner = inDownFrame->GetContent();
}
mGestureModifiers = inDownEvent->modifiers;
mGestureDownButtons = inDownEvent->buttons;
@ -4397,7 +4404,9 @@ EventStateManager::SetClickCount(nsPresContext* aPresContext,
{
nsCOMPtr<nsIContent> mouseContent;
nsIContent* mouseContentParent = nullptr;
mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(mouseContent));
if (mCurrentTarget) {
mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(mouseContent));
}
if (mouseContent) {
if (mouseContent->IsNodeOfType(nsINode::eTEXT)) {
mouseContent = mouseContent->GetParent();

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

@ -94,6 +94,7 @@ public:
nsresult PreHandleEvent(nsPresContext* aPresContext,
WidgetEvent* aEvent,
nsIFrame* aTargetFrame,
nsIContent* aTargetContent,
nsEventStatus* aStatus);
/* The PostHandleEvent method should contain all system processing which

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

@ -139,10 +139,10 @@ typedef struct CapturingContentInfo {
nsIContent* mContent;
} CapturingContentInfo;
// 9d010f90-2d90-471c-b640-038cc350c187
// d910f009-d209-74c1-6b04-30c83c051c78
#define NS_IPRESSHELL_IID \
{ 0x9d010f90, 0x2d90, 0x471c, \
{ 0xb6, 0x40, 0x03, 0x8c, 0xc3, 0x50, 0xc1, 0x87 } }
{ 0xd910f009, 0xd209, 0x74c1, \
{ 0x6b, 0x04, 0x30, 0xc8, 0x3c, 0x05, 0x1c, 0x78 } }
// debug VerifyReflow flags
#define VERIFY_REFLOW_ON 0x01
@ -1439,7 +1439,8 @@ public:
virtual nsresult HandleEvent(nsIFrame* aFrame,
mozilla::WidgetGUIEvent* aEvent,
bool aDontRetargetEvents,
nsEventStatus* aEventStatus) = 0;
nsEventStatus* aEventStatus,
nsIContent** aTargetContent = nullptr) = 0;
virtual bool ShouldIgnoreInvalidation() = 0;
/**
* Notify that we're going to call Paint with PAINT_LAYERS

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

@ -4584,6 +4584,13 @@ PresShell::ContentRemoved(nsIDocument *aDocument,
RestyleForRemove(aContainer->AsElement(), aChild, oldNextSibling);
}
// After removing aChild from tree we should save information about live ancestor
if (mPointerEventTarget) {
if (nsContentUtils::ContentIsDescendantOf(mPointerEventTarget, aChild)) {
mPointerEventTarget = aContainer;
}
}
// We should check that aChild does not contain pointer capturing elements.
// If it does we should release the pointer capture for the elements.
gPointerCaptureList->EnumerateRead(ReleasePointerCaptureFromRemovedContent, aChild);
@ -6819,7 +6826,8 @@ DispatchPointerFromMouseOrTouch(PresShell* aShell,
nsIFrame* aFrame,
WidgetGUIEvent* aEvent,
bool aDontRetargetEvents,
nsEventStatus* aStatus)
nsEventStatus* aStatus,
nsIContent** aTargetContent)
{
uint32_t pointerMessage = 0;
if (aEvent->mClass == eMouseEventClass) {
@ -6853,7 +6861,7 @@ DispatchPointerFromMouseOrTouch(PresShell* aShell,
mouseEvent->pressure ? mouseEvent->pressure : 0.5f :
0.0f;
event.convertToPointer = mouseEvent->convertToPointer = false;
aShell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus);
aShell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus, aTargetContent);
} else if (aEvent->mClass == eTouchEventClass) {
WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
// loop over all touches and dispatch pointer events on each touch
@ -6898,7 +6906,7 @@ DispatchPointerFromMouseOrTouch(PresShell* aShell,
event.buttons = WidgetMouseEvent::eLeftButtonFlag;
event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
event.convertToPointer = touch->convertToPointer = false;
aShell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus);
aShell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus, aTargetContent);
}
}
return NS_OK;
@ -7165,7 +7173,8 @@ nsresult
PresShell::HandleEvent(nsIFrame* aFrame,
WidgetGUIEvent* aEvent,
bool aDontRetargetEvents,
nsEventStatus* aEventStatus)
nsEventStatus* aEventStatus,
nsIContent** aTargetContent)
{
#ifdef MOZ_TASK_TRACER
// Make touch events, mouse events and hardware key events to be the source
@ -7181,11 +7190,27 @@ PresShell::HandleEvent(nsIFrame* aFrame,
AutoSourceEvent taskTracerEvent(type);
#endif
if (sPointerEventEnabled) {
DispatchPointerFromMouseOrTouch(this, aFrame, aEvent, aDontRetargetEvents, aEventStatus);
}
NS_ASSERTION(aFrame, "aFrame should be not null");
NS_ASSERTION(aFrame, "null frame");
if (sPointerEventEnabled) {
nsWeakFrame weakFrame(aFrame);
nsCOMPtr<nsIContent> targetContent;
DispatchPointerFromMouseOrTouch(this, aFrame, aEvent, aDontRetargetEvents,
aEventStatus, getter_AddRefs(targetContent));
if (!weakFrame.IsAlive()) {
if (targetContent) {
aFrame = targetContent->GetPrimaryFrame();
if (!aFrame) {
PushCurrentEventInfo(aFrame, targetContent);
nsresult rv = HandleEventInternal(aEvent, aEventStatus);
PopCurrentEventInfo();
return rv;
}
} else {
return NS_OK;
}
}
}
if (mIsDestroying ||
(sDisableNonTestMouseEvents && !aEvent->mFlags.mIsSynthesizedForTests &&
@ -7672,6 +7697,15 @@ PresShell::HandleEvent(nsIFrame* aFrame,
}
}
// Before HandlePositionedEvent we should save mPointerEventTarget in some cases
nsWeakFrame weakFrame;
if (sPointerEventEnabled && aTargetContent && ePointerEventClass == aEvent->mClass) {
weakFrame = frame;
shell->mPointerEventTarget = frame->GetContent();
MOZ_ASSERT(!frame->GetContent() || shell->GetDocument() == frame->GetContent()->OwnerDoc());
}
nsresult rv;
if (shell != this) {
// Handle the event in the correct shell.
// Prevent deletion until we're done with event handling (bug 336582).
@ -7680,10 +7714,20 @@ PresShell::HandleEvent(nsIFrame* aFrame,
// the only correct alternative; if the event was captured then it
// must have been captured by us or some ancestor shell and we
// now ask the subshell to dispatch it normally.
return shell->HandlePositionedEvent(frame, aEvent, aEventStatus);
rv = shell->HandlePositionedEvent(frame, aEvent, aEventStatus);
} else {
rv = HandlePositionedEvent(frame, aEvent, aEventStatus);
}
return HandlePositionedEvent(frame, aEvent, aEventStatus);
// After HandlePositionedEvent we should reestablish
// content (which still live in tree) in some cases
if (sPointerEventEnabled && aTargetContent && ePointerEventClass == aEvent->mClass) {
if (!weakFrame.IsAlive()) {
shell->mPointerEventTarget.swap(*aTargetContent);
}
}
return rv;
}
nsresult rv = NS_OK;
@ -7920,7 +7964,7 @@ PresShell::HandleEventInternal(WidgetEvent* aEvent, nsEventStatus* aStatus)
nsRefPtr<EventStateManager> manager = mPresContext->EventStateManager();
nsresult rv = NS_OK;
if (!NS_EVENT_NEEDS_FRAME(aEvent) || GetCurrentEventFrame()) {
if (!NS_EVENT_NEEDS_FRAME(aEvent) || GetCurrentEventFrame() || GetCurrentEventContent()) {
bool touchIsNew = false;
bool isHandlingUserInput = false;
@ -8033,7 +8077,8 @@ PresShell::HandleEventInternal(WidgetEvent* aEvent, nsEventStatus* aStatus)
// 1. Give event to event manager for pre event state changes and
// generation of synthetic events.
rv = manager->PreHandleEvent(mPresContext, aEvent, mCurrentEventFrame, aStatus);
rv = manager->PreHandleEvent(mPresContext, aEvent, mCurrentEventFrame,
mCurrentEventContent, aStatus);
// 2. Give event to the DOM for third party and JS use.
if (NS_SUCCEEDED(rv)) {
@ -8147,9 +8192,9 @@ PresShell::DispatchEventToDOM(WidgetEvent* aEvent,
}
if (eventTarget) {
if (aEvent->mClass == eCompositionEventClass) {
IMEStateManager::DispatchCompositionEvent(eventTarget,
mPresContext, aEvent->AsCompositionEvent(), aStatus,
eventCBPtr);
IMEStateManager::DispatchCompositionEvent(eventTarget, mPresContext,
aEvent->AsCompositionEvent(),
aStatus, eventCBPtr);
} else if (aEvent->mClass == eKeyboardEventClass) {
HandleKeyboardEvent(eventTarget, *(aEvent->AsKeyboardEvent()),
false, aStatus, eventCBPtr);

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

@ -215,7 +215,8 @@ public:
virtual nsresult HandleEvent(nsIFrame* aFrame,
mozilla::WidgetGUIEvent* aEvent,
bool aDontRetargetEvents,
nsEventStatus* aEventStatus) override;
nsEventStatus* aEventStatus,
nsIContent** aTargetContent) override;
virtual nsresult HandleDOMEventWithTarget(
nsIContent* aTargetContent,
mozilla::WidgetEvent* aEvent,
@ -835,6 +836,11 @@ protected:
nscoord mLastAnchorScrollPositionY;
// Information about live content (which still stay in DOM tree).
// Used in case we need re-dispatch event after sending pointer event,
// when target of pointer event was deleted during executing user handlers.
nsCOMPtr<nsIContent> mPointerEventTarget;
// This is used to protect ourselves from triggering reflow while in the
// middle of frame construction and the like... it really shouldn't be
// needed, one hopes, but it is for now.