Bug 1930931 - Make the dragging interaction still happens when the event target frame is moved/destroyed upon mousedown r=masayuki,dom-core
Differential Revision: https://phabricator.services.mozilla.com/D238318
This commit is contained in:
@@ -7593,4 +7593,24 @@ bool EventStateManager::WheelPrefs::IsOverOnePageScrollAllowedY(
|
||||
MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL;
|
||||
}
|
||||
|
||||
void EventStateManager::NotifyDestroyingFrameForGesture(nsIFrame* aFrame) {
|
||||
MOZ_ASSERT(aFrame);
|
||||
if (mGestureDownContent != aFrame->GetContent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nsIFrame* parent = aFrame->GetParent()) {
|
||||
nsIFrame* f = nsLayoutUtils::GetNonGeneratedAncestor(parent);
|
||||
MOZ_ASSERT(f);
|
||||
|
||||
nsIContent* content = f->GetContent();
|
||||
mGestureDownContent = content;
|
||||
mGestureDownFrameOwner = content;
|
||||
mGestureDownInTextControl =
|
||||
content && content->IsInNativeAnonymousSubtree() &&
|
||||
TextControlElement::FromNodeOrNull(
|
||||
content->GetClosestNativeAnonymousSubtreeRootParentOrHost());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -526,6 +526,17 @@ class EventStateManager : public nsSupportsWeakReference, public nsIObserver {
|
||||
return mMouseEnterLeaveHelper;
|
||||
}
|
||||
|
||||
nsIContent* GetTrackingDragGestureContent() const {
|
||||
return mGestureDownContent;
|
||||
}
|
||||
|
||||
// If the current frame is for the current gesture down content (being
|
||||
// dragged), when it's destroyed, we should continue the gesture on its
|
||||
// parent.
|
||||
void NotifyDestroyingFrameForGesture(nsIFrame* aFrame);
|
||||
|
||||
bool IsTrackingDragGesture() const { return mGestureDownContent != nullptr; }
|
||||
|
||||
protected:
|
||||
/*
|
||||
* If aTargetFrame's widget has a cached cursor value, resets the cursor
|
||||
@@ -1215,7 +1226,6 @@ class EventStateManager : public nsSupportsWeakReference, public nsIObserver {
|
||||
dom::RemoteDragStartData* aDragStartData, nsIPrincipal* aPrincipal,
|
||||
nsIContentSecurityPolicy* aCsp, nsICookieJarSettings* aCookieJarSettings);
|
||||
|
||||
bool IsTrackingDragGesture() const { return mGestureDownContent != nullptr; }
|
||||
/**
|
||||
* Set the fields of aEvent to reflect the mouse position and modifier keys
|
||||
* that were set when the user first pressed the mouse button (stored by
|
||||
|
||||
@@ -2230,6 +2230,9 @@ void PresShell::NotifyDestroyingFrame(nsIFrame* aFrame) {
|
||||
}
|
||||
}
|
||||
|
||||
EventStateManager* const esm = mPresContext->EventStateManager();
|
||||
esm->NotifyDestroyingFrameForGesture(aFrame);
|
||||
|
||||
mFramesToDirty.Remove(aFrame);
|
||||
|
||||
if (ScrollContainerFrame* scrollContainerFrame = do_QueryFrame(aFrame)) {
|
||||
|
||||
@@ -4696,6 +4696,17 @@ nsresult nsIFrame::MoveCaretToEventPoint(nsPresContext* aPresContext,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
EventStateManager* const esm = aPresContext->EventStateManager();
|
||||
if (nsIContent* dragGestureContent = esm->GetTrackingDragGestureContent()) {
|
||||
if (dragGestureContent != this->GetContent()) {
|
||||
// When the current tracked dragging gesture is different
|
||||
// than this frame, it means this frame was being dragged, however
|
||||
// it got moved/destroyed. So we should consider the drag is
|
||||
// still happening, so return early here.
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
const nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(
|
||||
aMouseEvent, RelativeTo{this});
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<!doctype html>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/resources/testdriver.js"></script>
|
||||
<script src="/resources/testdriver-vendor.js"></script>
|
||||
<script src="/resources/testdriver-actions.js"></script>
|
||||
<head>
|
||||
<title>Test dragging still occurs when mousedown moves the inner element</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="element" draggable="true" style="width: 40px; height: 40px; background-color:red;">
|
||||
<div id="inner" style="width: 30px; height: 30px; background-color:black;"></div>
|
||||
</div>
|
||||
|
||||
<div id="element2"></div>
|
||||
<script>
|
||||
|
||||
promise_test(function() {
|
||||
return new Promise(r => {
|
||||
element.addEventListener("dragstart", function(e) {
|
||||
assert_equals(e.target, element);
|
||||
r();
|
||||
});
|
||||
|
||||
element.addEventListener("mousedown", function() {
|
||||
element2.appendChild(inner);
|
||||
});
|
||||
|
||||
new test_driver.Actions()
|
||||
.pointerMove(0, 0, {origin: inner})
|
||||
.pointerDown()
|
||||
.pointerMove(10, 10, {origin:inner})
|
||||
.pointerUp()
|
||||
.send();
|
||||
});
|
||||
}, "dragstart should still fire when the mousedown event moves the inner element around");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user