Bug 1905267 - part 1: Make PresShell manage event target frame and content with a struct r=smaug
`PresShell::mCurrentEventTargetContent` may be update to non-element node when `PresShell::mCurrentEventTargetFrame` is destroyed. Therefore, for avoiding it, I'd like to add `EventMessage` to the group to consider whether the content needs to be `Element`. However, adding new members for current and stack would make `PresShell` members more messy. Therefore, I'd like to group the data with the simple struct. Differential Revision: https://phabricator.services.mozilla.com/D217204
This commit is contained in:
@@ -762,7 +762,6 @@ PresShell::PresShell(Document* aDocument)
|
||||
#ifdef ACCESSIBILITY
|
||||
mDocAccessible(nullptr),
|
||||
#endif // ACCESSIBILITY
|
||||
mCurrentEventFrame(nullptr),
|
||||
mMouseLocation(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE),
|
||||
mLastResolutionChangeOrigin(ResolutionChangeOrigin::Apz),
|
||||
mPaintCount(0),
|
||||
@@ -862,7 +861,7 @@ PresShell::~PresShell() {
|
||||
Destroy();
|
||||
}
|
||||
|
||||
NS_ASSERTION(mCurrentEventContentStack.Count() == 0,
|
||||
NS_ASSERTION(mCurrentEventTargetStack.IsEmpty(),
|
||||
"Huh, event content left on the stack in pres shell dtor!");
|
||||
NS_ASSERTION(mFirstCallbackEventRequest == nullptr &&
|
||||
mLastCallbackEventRequest == nullptr,
|
||||
@@ -872,7 +871,6 @@ PresShell::~PresShell() {
|
||||
"Some pres arena objects were not freed");
|
||||
|
||||
mFrameConstructor = nullptr;
|
||||
mCurrentEventContent = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1297,11 +1295,10 @@ void PresShell::Destroy() {
|
||||
// leave them in) and null out the mCurrentEventFrame pointer as
|
||||
// well.
|
||||
|
||||
mCurrentEventFrame = nullptr;
|
||||
mCurrentEventTarget.ClearFrame();
|
||||
|
||||
int32_t i, count = mCurrentEventFrameStack.Length();
|
||||
for (i = 0; i < count; i++) {
|
||||
mCurrentEventFrameStack[i] = nullptr;
|
||||
for (EventTargetInfo& eventTargetInfo : mCurrentEventTargetStack) {
|
||||
eventTargetInfo.ClearFrame();
|
||||
}
|
||||
|
||||
mFramesToDirty.Clear();
|
||||
@@ -2148,20 +2145,19 @@ void PresShell::NativeAnonymousContentRemoved(nsIContent* aAnonContent) {
|
||||
if (mDocument->DevToolsAnonymousAndShadowEventsEnabled()) {
|
||||
aAnonContent->QueueDevtoolsAnonymousEvent(/* aIsRemove = */ true);
|
||||
}
|
||||
if (nsIContent* root = GetNativeAnonymousSubtreeRoot(mCurrentEventContent)) {
|
||||
if (nsIContent* root =
|
||||
GetNativeAnonymousSubtreeRoot(mCurrentEventTarget.mContent)) {
|
||||
if (aAnonContent == root) {
|
||||
mCurrentEventContent = aAnonContent->GetFlattenedTreeParent();
|
||||
mCurrentEventFrame = nullptr;
|
||||
mCurrentEventTarget.SetFrameAndContent(
|
||||
nullptr, aAnonContent->GetFlattenedTreeParent());
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < mCurrentEventContentStack.Length(); i++) {
|
||||
nsIContent* anon =
|
||||
GetNativeAnonymousSubtreeRoot(mCurrentEventContentStack.ElementAt(i));
|
||||
for (EventTargetInfo& eventTargetInfo : mCurrentEventTargetStack) {
|
||||
nsIContent* anon = GetNativeAnonymousSubtreeRoot(eventTargetInfo.mContent);
|
||||
if (aAnonContent == anon) {
|
||||
mCurrentEventContentStack.ReplaceObjectAt(
|
||||
aAnonContent->GetFlattenedTreeParent(), i);
|
||||
mCurrentEventFrameStack[i] = nullptr;
|
||||
eventTargetInfo.SetFrameAndContent(
|
||||
nullptr, aAnonContent->GetFlattenedTreeParent());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2193,18 +2189,15 @@ void PresShell::NotifyDestroyingFrame(nsIFrame* aFrame) {
|
||||
// Remove frame properties
|
||||
aFrame->RemoveAllProperties();
|
||||
|
||||
if (aFrame == mCurrentEventFrame) {
|
||||
mCurrentEventContent = aFrame->GetContent();
|
||||
mCurrentEventFrame = nullptr;
|
||||
if (aFrame == mCurrentEventTarget.mFrame) {
|
||||
mCurrentEventTarget.SetFrameAndContent(nullptr, aFrame->GetContent());
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < mCurrentEventFrameStack.Length(); i++) {
|
||||
if (aFrame == mCurrentEventFrameStack.ElementAt(i)) {
|
||||
for (EventTargetInfo& eventTargetInfo : mCurrentEventTargetStack) {
|
||||
if (aFrame == eventTargetInfo.mFrame) {
|
||||
// One of our stack frames was deleted. Get its content so that when we
|
||||
// pop it we can still get its new frame from its content
|
||||
nsIContent* currentEventContent = aFrame->GetContent();
|
||||
mCurrentEventContentStack.ReplaceObjectAt(currentEventContent, i);
|
||||
mCurrentEventFrameStack[i] = nullptr;
|
||||
eventTargetInfo.SetFrameAndContent(nullptr, aFrame->GetContent());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6550,12 +6543,11 @@ void PresShell::SetCapturingContent(nsIContent* aContent, CaptureFlags aFlags,
|
||||
}
|
||||
|
||||
nsIContent* PresShell::GetCurrentEventContent() {
|
||||
if (mCurrentEventContent &&
|
||||
mCurrentEventContent->GetComposedDoc() != mDocument) {
|
||||
mCurrentEventContent = nullptr;
|
||||
mCurrentEventFrame = nullptr;
|
||||
if (mCurrentEventTarget.mContent &&
|
||||
mCurrentEventTarget.mContent->GetComposedDoc() != mDocument) {
|
||||
mCurrentEventTarget.Clear();
|
||||
}
|
||||
return mCurrentEventContent;
|
||||
return mCurrentEventTarget.mContent;
|
||||
}
|
||||
|
||||
nsIFrame* PresShell::GetCurrentEventFrame() {
|
||||
@@ -6568,12 +6560,13 @@ nsIFrame* PresShell::GetCurrentEventFrame() {
|
||||
// frame shouldn't get an event, nor should we even assume its safe
|
||||
// to try and find the frame.
|
||||
nsIContent* content = GetCurrentEventContent();
|
||||
if (!mCurrentEventFrame && content) {
|
||||
mCurrentEventFrame = content->GetPrimaryFrame();
|
||||
MOZ_ASSERT(!mCurrentEventFrame ||
|
||||
mCurrentEventFrame->PresContext()->GetPresShell() == this);
|
||||
if (!mCurrentEventTarget.mFrame && content) {
|
||||
mCurrentEventTarget.mFrame = content->GetPrimaryFrame();
|
||||
MOZ_ASSERT_IF(
|
||||
mCurrentEventTarget.mFrame,
|
||||
mCurrentEventTarget.mFrame->PresContext()->GetPresShell() == this);
|
||||
}
|
||||
return mCurrentEventFrame;
|
||||
return mCurrentEventTarget.mFrame;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIContent> PresShell::GetEventTargetContent(
|
||||
@@ -6590,30 +6583,33 @@ already_AddRefed<nsIContent> PresShell::GetEventTargetContent(
|
||||
return content.forget();
|
||||
}
|
||||
|
||||
void PresShell::PushCurrentEventInfo(nsIFrame* aFrame, nsIContent* aContent) {
|
||||
if (mCurrentEventFrame || mCurrentEventContent) {
|
||||
mCurrentEventFrameStack.InsertElementAt(0, mCurrentEventFrame);
|
||||
mCurrentEventContentStack.InsertObjectAt(mCurrentEventContent, 0);
|
||||
void PresShell::PushCurrentEventInfo(const EventTargetInfo& aInfo) {
|
||||
if (mCurrentEventTarget.IsSet()) {
|
||||
// XXX Why do we insert first item instead of append it? This requires to
|
||||
// move the previous items...
|
||||
mCurrentEventTargetStack.InsertElementAt(0, std::move(mCurrentEventTarget));
|
||||
}
|
||||
mCurrentEventFrame = aFrame;
|
||||
mCurrentEventContent = aContent;
|
||||
mCurrentEventTarget = aInfo;
|
||||
}
|
||||
|
||||
void PresShell::PushCurrentEventInfo(EventTargetInfo&& aInfo) {
|
||||
if (mCurrentEventTarget.IsSet()) {
|
||||
mCurrentEventTargetStack.InsertElementAt(0, std::move(mCurrentEventTarget));
|
||||
}
|
||||
mCurrentEventTarget = std::move(aInfo);
|
||||
}
|
||||
|
||||
void PresShell::PopCurrentEventInfo() {
|
||||
mCurrentEventFrame = nullptr;
|
||||
mCurrentEventContent = nullptr;
|
||||
mCurrentEventTarget.Clear();
|
||||
|
||||
if (0 != mCurrentEventFrameStack.Length()) {
|
||||
mCurrentEventFrame = mCurrentEventFrameStack.ElementAt(0);
|
||||
mCurrentEventFrameStack.RemoveElementAt(0);
|
||||
mCurrentEventContent = mCurrentEventContentStack.ObjectAt(0);
|
||||
mCurrentEventContentStack.RemoveObjectAt(0);
|
||||
if (!mCurrentEventTargetStack.IsEmpty()) {
|
||||
mCurrentEventTarget = std::move(mCurrentEventTargetStack[0]);
|
||||
mCurrentEventTargetStack.RemoveElementAt(0);
|
||||
|
||||
// Don't use it if it has moved to a different document.
|
||||
if (mCurrentEventContent &&
|
||||
mCurrentEventContent->GetComposedDoc() != mDocument) {
|
||||
mCurrentEventContent = nullptr;
|
||||
mCurrentEventFrame = nullptr;
|
||||
if (mCurrentEventTarget.mContent &&
|
||||
mCurrentEventTarget.mContent->GetComposedDoc() != mDocument) {
|
||||
mCurrentEventTarget.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8208,7 +8204,10 @@ nsresult PresShell::EventHandler::HandleEventAtFocusedContent(
|
||||
RefPtr<Element> eventTargetElement =
|
||||
ComputeFocusedEventTargetElement(aGUIEvent);
|
||||
|
||||
mPresShell->mCurrentEventFrame = nullptr;
|
||||
// mCurrentEventTarget is cleared by eventInfoSetter and
|
||||
// ComputeFocusedEventTargetElement shouldn't set it again.
|
||||
MOZ_ASSERT(!mPresShell->mCurrentEventTarget.IsSet());
|
||||
|
||||
if (eventTargetElement) {
|
||||
nsresult rv = NS_OK;
|
||||
if (MaybeHandleEventWithAnotherPresShell(eventTargetElement, aGUIEvent,
|
||||
@@ -8219,10 +8218,11 @@ nsresult PresShell::EventHandler::HandleEventAtFocusedContent(
|
||||
|
||||
// If we cannot handle the event with mPresShell, let's try to handle it
|
||||
// with parent PresShell.
|
||||
mPresShell->mCurrentEventContent = eventTargetElement;
|
||||
mPresShell->mCurrentEventTarget.SetFrameAndContent(nullptr,
|
||||
eventTargetElement);
|
||||
if (!mPresShell->GetCurrentEventContent() ||
|
||||
!mPresShell->GetCurrentEventFrame() ||
|
||||
InZombieDocument(mPresShell->mCurrentEventContent)) {
|
||||
InZombieDocument(mPresShell->mCurrentEventTarget.mContent)) {
|
||||
return RetargetEventToParent(aGUIEvent, aEventStatus);
|
||||
}
|
||||
|
||||
@@ -8320,8 +8320,8 @@ nsresult PresShell::EventHandler::HandleEventWithFrameForPresShell(
|
||||
MOZ_ASSERT(!aGUIEvent->IsTargetedAtFocusedContent());
|
||||
MOZ_ASSERT(aEventStatus);
|
||||
|
||||
AutoCurrentEventInfoSetter eventInfoSetter(*this, aFrameForPresShell,
|
||||
nullptr);
|
||||
AutoCurrentEventInfoSetter eventInfoSetter(
|
||||
*this, EventTargetInfo(aFrameForPresShell, nullptr));
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
if (mPresShell->GetCurrentEventFrame()) {
|
||||
@@ -8386,8 +8386,8 @@ nsresult PresShell::EventHandler::HandleEventWithTarget(
|
||||
}
|
||||
AutoPointerEventTargetUpdater updater(mPresShell, aEvent, aNewEventFrame,
|
||||
aNewEventContent, aTargetContent);
|
||||
AutoCurrentEventInfoSetter eventInfoSetter(*this, aNewEventFrame,
|
||||
aNewEventContent);
|
||||
AutoCurrentEventInfoSetter eventInfoSetter(
|
||||
*this, EventTargetInfo(aNewEventFrame, aNewEventContent));
|
||||
nsresult rv = HandleEventWithCurrentEventInfo(aEvent, aEventStatus, false,
|
||||
aOverrideClickTarget);
|
||||
return rv;
|
||||
@@ -8451,12 +8451,13 @@ nsresult PresShell::EventHandler::HandleEventWithCurrentEventInfo(
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mPresShell->mCurrentEventContent && aEvent->IsTargetedAtFocusedWindow() &&
|
||||
if (mPresShell->mCurrentEventTarget.mContent &&
|
||||
aEvent->IsTargetedAtFocusedWindow() &&
|
||||
aEvent->AllowFlushingPendingNotifications()) {
|
||||
if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
|
||||
// This may run script now. So, mPresShell might be destroyed after here.
|
||||
nsCOMPtr<nsIContent> currentEventContent =
|
||||
mPresShell->mCurrentEventContent;
|
||||
mPresShell->mCurrentEventTarget.mContent;
|
||||
fm->FlushBeforeEventHandlingIfNeeded(currentEventContent);
|
||||
}
|
||||
}
|
||||
@@ -8513,10 +8514,11 @@ nsresult PresShell::EventHandler::DispatchEvent(
|
||||
// generation of synthetic events.
|
||||
{ // Scope for presContext
|
||||
RefPtr<nsPresContext> presContext = GetPresContext();
|
||||
nsCOMPtr<nsIContent> eventContent = mPresShell->mCurrentEventContent;
|
||||
nsCOMPtr<nsIContent> eventContent =
|
||||
mPresShell->mCurrentEventTarget.mContent;
|
||||
nsresult rv = aEventStateManager->PreHandleEvent(
|
||||
presContext, aEvent, mPresShell->mCurrentEventFrame, eventContent,
|
||||
aEventStatus, aOverrideClickTarget);
|
||||
presContext, aEvent, mPresShell->mCurrentEventTarget.mFrame,
|
||||
eventContent, aEventStatus, aOverrideClickTarget);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
@@ -8641,7 +8643,8 @@ bool PresShell::EventHandler::PrepareToDispatchEvent(
|
||||
case eTouchCancel:
|
||||
case eTouchPointerCancel:
|
||||
return mPresShell->mTouchManager.PreHandleEvent(
|
||||
aEvent, aEventStatus, *aTouchIsNew, mPresShell->mCurrentEventContent);
|
||||
aEvent, aEventStatus, *aTouchIsNew,
|
||||
mPresShell->mCurrentEventTarget.mContent);
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
@@ -8724,7 +8727,7 @@ void PresShell::EventHandler::MaybeHandleKeyboardEventBeforeDispatch(
|
||||
// If we're in fullscreen mode, exit from it forcibly when Escape key is
|
||||
// pressed.
|
||||
Document* doc = mPresShell->GetCurrentEventContent()
|
||||
? mPresShell->mCurrentEventContent->OwnerDoc()
|
||||
? mPresShell->mCurrentEventTarget.mContent->OwnerDoc()
|
||||
: nullptr;
|
||||
Document* root = nsContentUtils::GetInProcessSubtreeRootDocument(doc);
|
||||
if (root && root->GetFullscreenElement()) {
|
||||
@@ -8920,12 +8923,12 @@ nsresult PresShell::EventHandler::DispatchEventToDOM(
|
||||
WidgetEvent* aEvent, nsEventStatus* aEventStatus,
|
||||
nsPresShellEventCB* aEventCB) {
|
||||
nsresult rv = NS_OK;
|
||||
nsCOMPtr<nsINode> eventTarget = mPresShell->mCurrentEventContent;
|
||||
nsCOMPtr<nsINode> eventTarget = mPresShell->mCurrentEventTarget.mContent;
|
||||
nsPresShellEventCB* eventCBPtr = aEventCB;
|
||||
if (!eventTarget) {
|
||||
nsCOMPtr<nsIContent> targetContent;
|
||||
if (mPresShell->mCurrentEventFrame) {
|
||||
rv = mPresShell->mCurrentEventFrame->GetContentForEvent(
|
||||
if (mPresShell->mCurrentEventTarget.mFrame) {
|
||||
rv = mPresShell->mCurrentEventTarget.mFrame->GetContentForEvent(
|
||||
aEvent, getter_AddRefs(targetContent));
|
||||
}
|
||||
if (NS_SUCCEEDED(rv) && targetContent) {
|
||||
@@ -9054,8 +9057,8 @@ void PresShell::EventHandler::DispatchTouchEventToDOM(
|
||||
if (contentPresShell) {
|
||||
// XXXsmaug huge hack. Pushing possibly capturing content,
|
||||
// even though event target is something else.
|
||||
contentPresShell->PushCurrentEventInfo(content->GetPrimaryFrame(),
|
||||
content);
|
||||
contentPresShell->PushCurrentEventInfo(
|
||||
EventTargetInfo(content->GetPrimaryFrame(), content));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9098,7 +9101,7 @@ nsresult PresShell::HandleDOMEventWithTarget(nsIContent* aTargetContent,
|
||||
nsEventStatus* aStatus) {
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
PushCurrentEventInfo(nullptr, aTargetContent);
|
||||
PushCurrentEventInfo(EventTargetInfo(nullptr, aTargetContent));
|
||||
|
||||
// Bug 41013: Check if the event should be dispatched to content.
|
||||
// It's possible that we are in the middle of destroying the window
|
||||
@@ -9122,7 +9125,7 @@ nsresult PresShell::HandleDOMEventWithTarget(nsIContent* aTargetContent,
|
||||
nsEventStatus* aStatus) {
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
PushCurrentEventInfo(nullptr, aTargetContent);
|
||||
PushCurrentEventInfo(EventTargetInfo(nullptr, aTargetContent));
|
||||
nsCOMPtr<nsISupports> container = mPresContext->GetContainerWeak();
|
||||
if (container) {
|
||||
rv = EventDispatcher::DispatchDOMEvent(aTargetContent, nullptr, aEvent,
|
||||
@@ -9153,8 +9156,8 @@ bool PresShell::EventHandler::AdjustContextMenuKeyEvent(
|
||||
itemFrame->PresContext()->AppUnitsPerDevPixel()) -
|
||||
widgetPoint;
|
||||
|
||||
mPresShell->mCurrentEventContent = itemFrame->GetContent();
|
||||
mPresShell->mCurrentEventFrame = itemFrame;
|
||||
mPresShell->mCurrentEventTarget.SetFrameAndContent(
|
||||
itemFrame, itemFrame->GetContent());
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -9217,8 +9220,8 @@ bool PresShell::EventHandler::AdjustContextMenuKeyEvent(
|
||||
currentFocus, getter_AddRefs(currentPointElement),
|
||||
aMouseEvent->mRefPoint, MOZ_KnownLive(aMouseEvent->mWidget));
|
||||
if (currentPointElement) {
|
||||
mPresShell->mCurrentEventContent = currentPointElement;
|
||||
mPresShell->mCurrentEventFrame = nullptr;
|
||||
mPresShell->mCurrentEventTarget.SetFrameAndContent(nullptr,
|
||||
currentPointElement);
|
||||
mPresShell->GetCurrentEventFrame();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user