Skip to content

Commit

Permalink
Bug 1885259 - Make AutoPointerEventTargetUpdater work without event…
Browse files Browse the repository at this point in the history
… target frame r=edgar,dom-core

The crash occurs when `PointerEventHandler::DispatchPointerFromMouseOrTouch`
dispatches a pointer event for `eTouchStart`.  In this case, `aFrame` of
the constructor of `AutoPointerEventTargetUpdater` is set to the primary frame
of the event target content [1][2] and the event target may have no frame
because touch targets are considered by `TouchManager` before dispatching
`ePointerDown` [3][4][5].  Therefore, we should make it take event target
content for the case of no event target frame.

I tried to reproduce the crash with removing the target or making the target
`display:contents` at first `pointerdown` or `touchstart` of multi-touch, but
I couldn't reproduce the crash.  Therefore, this patch does not contain new
tests.

1. https://searchfox.org/mozilla-central/rev/109bb25545f0d2df31954dc0a9afbf30d900b6bb/dom/events/PointerEventHandler.cpp#694,701
2. https://searchfox.org/mozilla-central/rev/109bb25545f0d2df31954dc0a9afbf30d900b6bb/layout/base/PresShell.cpp#8319,8341
3. https://searchfox.org/mozilla-central/rev/109bb25545f0d2df31954dc0a9afbf30d900b6bb/layout/base/TouchManager.cpp#115
4. https://searchfox.org/mozilla-central/rev/109bb25545f0d2df31954dc0a9afbf30d900b6bb/layout/base/PresShell.cpp#7400
5. https://searchfox.org/mozilla-central/rev/109bb25545f0d2df31954dc0a9afbf30d900b6bb/layout/base/PresShell.cpp#7198

Differential Revision: https://phabricator.services.mozilla.com/D204632
  • Loading branch information
masayuki-nakano committed Mar 14, 2024
1 parent 82be885 commit 39f5d90
Showing 1 changed file with 15 additions and 13 deletions.
28 changes: 15 additions & 13 deletions layout/base/PresShell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -565,49 +565,51 @@ class nsBeforeFirstPaintDispatcher : public Runnable {
class MOZ_STACK_CLASS AutoPointerEventTargetUpdater final {
public:
AutoPointerEventTargetUpdater(PresShell* aShell, WidgetEvent* aEvent,
nsIFrame* aFrame, nsIContent** aTargetContent) {
nsIFrame* aFrame, nsIContent* aTargetContent,
nsIContent** aOutTargetContent) {
MOZ_ASSERT(aEvent);
if (!aTargetContent || aEvent->mClass != ePointerEventClass) {
if (!aOutTargetContent || aEvent->mClass != ePointerEventClass) {
// Make the destructor happy.
mTargetContent = nullptr;
mOutTargetContent = nullptr;
return;
}
MOZ_ASSERT(aShell);
MOZ_ASSERT(aFrame);
MOZ_ASSERT(!aFrame->GetContent() ||
aShell->GetDocument() == aFrame->GetContent()->OwnerDoc());
MOZ_ASSERT_IF(aFrame && aFrame->GetContent(),
aShell->GetDocument() == aFrame->GetContent()->OwnerDoc());

mShell = aShell;
mWeakFrame = aFrame;
mTargetContent = aTargetContent;
mOutTargetContent = aOutTargetContent;
mFromTouch = aEvent->AsPointerEvent()->mFromTouchEvent;
// Touch event target may have no frame, e.g., removed from the DOM
MOZ_ASSERT_IF(!mFromTouch, aFrame);
mOriginalPointerEventTarget = aShell->mPointerEventTarget =
aFrame->GetContent();
aFrame ? aFrame->GetContent() : aTargetContent;
}

~AutoPointerEventTargetUpdater() {
if (!mTargetContent || !mShell || mWeakFrame.IsAlive()) {
if (!mOutTargetContent || !mShell || mWeakFrame.IsAlive()) {
return;
}
if (mFromTouch) {
// If the source event is a touch event, the touch event target should
// always be same target as preceding ePointerDown. Therefore, we should
// always set it back to the original event target.
mOriginalPointerEventTarget.swap(*mTargetContent);
mOriginalPointerEventTarget.swap(*mOutTargetContent);
} else {
// If the source event is not a touch event (must be a mouse event in
// this case), the event should be fired on the closest inclusive ancestor
// of the pointer event target which is still connected. The mutations
// are tracked by PresShell::ContentRemoved. Therefore, we should set it.
mShell->mPointerEventTarget.swap(*mTargetContent);
mShell->mPointerEventTarget.swap(*mOutTargetContent);
}
}

private:
RefPtr<PresShell> mShell;
nsCOMPtr<nsIContent> mOriginalPointerEventTarget;
AutoWeakFrame mWeakFrame;
nsIContent** mTargetContent;
nsIContent** mOutTargetContent;
bool mFromTouch = false;
};

Expand Down Expand Up @@ -8339,7 +8341,7 @@ nsresult PresShell::EventHandler::HandleEventWithTarget(
mPresShell->RecordPointerLocation(aEvent->AsMouseEvent());
}
AutoPointerEventTargetUpdater updater(mPresShell, aEvent, aNewEventFrame,
aTargetContent);
aNewEventContent, aTargetContent);
AutoCurrentEventInfoSetter eventInfoSetter(*this, aNewEventFrame,
aNewEventContent);
nsresult rv = HandleEventWithCurrentEventInfo(aEvent, aEventStatus, false,
Expand Down

0 comments on commit 39f5d90

Please sign in to comment.