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:
Masayuki Nakano
2024-07-30 00:06:09 +00:00
parent 84c538e41e
commit 66321dce9c
2 changed files with 119 additions and 88 deletions

View File

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