diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp index ce90c079f08b..2a9494a9c9fa 100644 --- a/layout/base/PresShell.cpp +++ b/layout/base/PresShell.cpp @@ -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 PresShell::GetEventTargetContent( @@ -6590,30 +6583,33 @@ already_AddRefed 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 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 fm = nsFocusManager::GetFocusManager()) { // This may run script now. So, mPresShell might be destroyed after here. nsCOMPtr 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 presContext = GetPresContext(); - nsCOMPtr eventContent = mPresShell->mCurrentEventContent; + nsCOMPtr 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 eventTarget = mPresShell->mCurrentEventContent; + nsCOMPtr eventTarget = mPresShell->mCurrentEventTarget.mContent; nsPresShellEventCB* eventCBPtr = aEventCB; if (!eventTarget) { nsCOMPtr 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 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(); } } diff --git a/layout/base/PresShell.h b/layout/base/PresShell.h index edcc3e05fbbe..05a92422ce8d 100644 --- a/layout/base/PresShell.h +++ b/layout/base/PresShell.h @@ -1798,7 +1798,28 @@ class PresShell final : public nsStubDocumentObserver, #endif } - void PushCurrentEventInfo(nsIFrame* aFrame, nsIContent* aContent); + struct EventTargetInfo { + EventTargetInfo() = default; + EventTargetInfo(nsIFrame* aFrame, nsIContent* aContent) + : mFrame(aFrame), mContent(aContent) {} + + [[nodiscard]] bool IsSet() const { return mFrame || mContent; } + void Clear() { + mFrame = nullptr; + mContent = nullptr; + } + void ClearFrame() { mFrame = nullptr; } + void SetFrameAndContent(nsIFrame* aFrame, nsIContent* aContent) { + mFrame = aFrame; + mContent = aContent; + } + + nsIFrame* mFrame = nullptr; + nsCOMPtr mContent; + }; + + void PushCurrentEventInfo(const EventTargetInfo& aInfo); + void PushCurrentEventInfo(EventTargetInfo&& aInfo); void PopCurrentEventInfo(); nsIContent* GetCurrentEventContent(); @@ -2616,7 +2637,8 @@ class PresShell final : public nsStubDocumentObserver, nsresult HandleRetargetedEvent(WidgetGUIEvent* aGUIEvent, nsEventStatus* aEventStatus, nsIContent* aTarget) { - AutoCurrentEventInfoSetter eventInfoSetter(*this, nullptr, aTarget); + AutoCurrentEventInfoSetter eventInfoSetter( + *this, EventTargetInfo(nullptr, aTarget)); if (!mPresShell->GetCurrentEventFrame()) { return NS_OK; } @@ -2819,22 +2841,30 @@ class PresShell final : public nsStubDocumentObserver, : mEventHandler(aEventHandler) { MOZ_DIAGNOSTIC_ASSERT(!mEventHandler.mCurrentEventInfoSetter); mEventHandler.mCurrentEventInfoSetter = this; - mEventHandler.mPresShell->PushCurrentEventInfo(nullptr, nullptr); + mEventHandler.mPresShell->PushCurrentEventInfo(EventTargetInfo()); } - AutoCurrentEventInfoSetter(EventHandler& aEventHandler, nsIFrame* aFrame, - nsIContent* aContent) + AutoCurrentEventInfoSetter(EventHandler& aEventHandler, + const EventTargetInfo& aInfo) : mEventHandler(aEventHandler) { MOZ_DIAGNOSTIC_ASSERT(!mEventHandler.mCurrentEventInfoSetter); mEventHandler.mCurrentEventInfoSetter = this; - mEventHandler.mPresShell->PushCurrentEventInfo(aFrame, aContent); + mEventHandler.mPresShell->PushCurrentEventInfo(aInfo); + } + AutoCurrentEventInfoSetter(EventHandler& aEventHandler, + EventTargetInfo&& aInfo) + : mEventHandler(aEventHandler) { + MOZ_DIAGNOSTIC_ASSERT(!mEventHandler.mCurrentEventInfoSetter); + mEventHandler.mCurrentEventInfoSetter = this; + mEventHandler.mPresShell->PushCurrentEventInfo( + std::forward(aInfo)); } AutoCurrentEventInfoSetter(EventHandler& aEventHandler, EventTargetData& aEventTargetData) : mEventHandler(aEventHandler) { MOZ_DIAGNOSTIC_ASSERT(!mEventHandler.mCurrentEventInfoSetter); mEventHandler.mCurrentEventInfoSetter = this; - mEventHandler.mPresShell->PushCurrentEventInfo( - aEventTargetData.GetFrame(), aEventTargetData.GetContent()); + mEventHandler.mPresShell->PushCurrentEventInfo(EventTargetInfo( + aEventTargetData.GetFrame(), aEventTargetData.GetContent())); } ~AutoCurrentEventInfoSetter() { mEventHandler.mPresShell->PopCurrentEventInfo(); @@ -3005,10 +3035,8 @@ class PresShell final : public nsStubDocumentObserver, a11y::DocAccessible* mDocAccessible; #endif // #ifdef ACCESSIBILITY - nsIFrame* mCurrentEventFrame; - nsCOMPtr mCurrentEventContent; - nsTArray mCurrentEventFrameStack; - nsCOMArray mCurrentEventContentStack; + EventTargetInfo mCurrentEventTarget; + nsTArray mCurrentEventTargetStack; // Set of frames that we should mark with NS_FRAME_HAS_DIRTY_CHILDREN after // we finish reflowing mCurrentReflowRoot. nsTHashSet mFramesToDirty;