зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1893119: Part 5 - Fix coordinates use in dispatchDOMEventViaPresShellForTesting r=masayuki,mconley,places-reviewers,tabbrowser-reviewers,dao
Since we now add the widget to the event in dispatchDOMEventViaPresShellForTesting, WidgetGUIEvents that are sent in mochitests via that method need to transform their screen coordinates by nsIWidget::WidgetToScreenOffset, to mirror the transformation by BrowserParent::TransformParentToChild that they don't get because they skip the parent process. This exposes a bunch of things that were done to work around this bug. They are cleaned up here. Differential Revision: https://phabricator.services.mozilla.com/D211068
This commit is contained in:
Родитель
7c55f66983
Коммит
18f01ba217
|
@ -142,9 +142,63 @@ add_task(async function test() {
|
|||
)
|
||||
);
|
||||
|
||||
// synthesizeDrop will reference the center of the elements we pass. Since
|
||||
// dragging to anything from the center and below is considered _after_ an
|
||||
// element, and we are dragging up, we need to drag _just past_ the center
|
||||
// (1 pixel) to drop before the target element.
|
||||
let nodebound = placesItems.childNodes[0].getBoundingClientRect();
|
||||
let [centerX, centerY] = [
|
||||
nodebound.left + nodebound.width / 2,
|
||||
nodebound.top + nodebound.height / 2,
|
||||
];
|
||||
EventUtils.synthesizeDrop(
|
||||
placesItems,
|
||||
placesItems.childNodes[1],
|
||||
placesItems.childNodes[0],
|
||||
[
|
||||
[
|
||||
{
|
||||
type: "text/x-moz-place",
|
||||
data: PlacesUtils.wrapNode(
|
||||
placesItems.childNodes[0]._placesNode,
|
||||
"text/x-moz-place"
|
||||
),
|
||||
},
|
||||
],
|
||||
],
|
||||
"move",
|
||||
window,
|
||||
window,
|
||||
{
|
||||
clientX: centerX - 1,
|
||||
clientY: centerY - 1,
|
||||
}
|
||||
);
|
||||
|
||||
await urlMoveNotification;
|
||||
Assert.ok(spy.notCalled, "ShowBookmarksDialog not called on move for url");
|
||||
|
||||
info("Moving existing Bookmarklet from position [2] to [1] on Toolbar");
|
||||
let bookmarkletMoveNotification = PlacesTestUtils.waitForNotification(
|
||||
"bookmark-moved",
|
||||
events =>
|
||||
events.some(
|
||||
e =>
|
||||
e.parentGuid === PlacesUtils.bookmarks.toolbarGuid &&
|
||||
e.oldParentGuid === PlacesUtils.bookmarks.toolbarGuid &&
|
||||
e.oldIndex == 2 &&
|
||||
e.index == 1
|
||||
)
|
||||
);
|
||||
|
||||
nodebound = placesItems.childNodes[1].getBoundingClientRect();
|
||||
[centerX, centerY] = [
|
||||
nodebound.left + nodebound.width / 2,
|
||||
nodebound.top + nodebound.height / 2,
|
||||
];
|
||||
|
||||
EventUtils.synthesizeDrop(
|
||||
placesItems.childNodes[2],
|
||||
placesItems.childNodes[1],
|
||||
[
|
||||
[
|
||||
{
|
||||
|
@ -157,44 +211,15 @@ add_task(async function test() {
|
|||
],
|
||||
],
|
||||
"move",
|
||||
window
|
||||
window,
|
||||
window,
|
||||
{
|
||||
clientX: centerX - 1,
|
||||
clientY: centerY - 1,
|
||||
}
|
||||
);
|
||||
|
||||
await urlMoveNotification;
|
||||
Assert.ok(spy.notCalled, "ShowBookmarksDialog not called on move for url");
|
||||
|
||||
info("Moving existing Bookmarklet from position [2] to [1] on Toolbar");
|
||||
let bookmarkletMoveNotificatio = PlacesTestUtils.waitForNotification(
|
||||
"bookmark-moved",
|
||||
events =>
|
||||
events.some(
|
||||
e =>
|
||||
e.parentGuid === PlacesUtils.bookmarks.toolbarGuid &&
|
||||
e.oldParentGuid === PlacesUtils.bookmarks.toolbarGuid &&
|
||||
e.oldIndex == 2 &&
|
||||
e.index == 1
|
||||
)
|
||||
);
|
||||
|
||||
EventUtils.synthesizeDrop(
|
||||
toolbar,
|
||||
placesItems.childNodes[1],
|
||||
[
|
||||
[
|
||||
{
|
||||
type: "text/x-moz-place",
|
||||
data: PlacesUtils.wrapNode(
|
||||
placesItems.childNodes[2]._placesNode,
|
||||
"text/x-moz-place"
|
||||
),
|
||||
},
|
||||
],
|
||||
],
|
||||
"move",
|
||||
window
|
||||
);
|
||||
|
||||
await bookmarkletMoveNotificatio;
|
||||
await bookmarkletMoveNotification;
|
||||
Assert.ok(spy.notCalled, "ShowBookmarksDialog not called on move for url");
|
||||
sandbox.restore();
|
||||
});
|
||||
|
|
|
@ -268,7 +268,7 @@ async function dragAndDrop(
|
|||
let event = {
|
||||
ctrlKey: copy,
|
||||
altKey: copy,
|
||||
clientX: rect.left + rect.width / 2 + 10 * (afterTab ? 1 : -1),
|
||||
clientX: rect.left + rect.width / 2 + (afterTab ? 1 : -1),
|
||||
clientY: rect.top + rect.height / 2,
|
||||
};
|
||||
|
||||
|
|
|
@ -2298,7 +2298,18 @@ NS_IMETHODIMP nsDOMWindowUtils::DispatchDOMEventViaPresShellForTesting(
|
|||
WidgetGUIEvent* guiEvent = internalEvent->AsGUIEvent();
|
||||
if (guiEvent && !guiEvent->mWidget) {
|
||||
auto* pc = GetPresContext();
|
||||
guiEvent->mWidget = pc ? pc->GetRootWidget() : nullptr;
|
||||
auto* widget = pc ? pc->GetRootWidget() : nullptr;
|
||||
// In content, screen coordinates would have been
|
||||
// transformed by BrowserParent::TransformParentToChild
|
||||
// so we do that here.
|
||||
if (widget) {
|
||||
guiEvent->mWidget = widget;
|
||||
|
||||
// Setting the widget makes the event's mRefPoint coordinates
|
||||
// widget-relative, so we transform them from being
|
||||
// screen-relative here.
|
||||
guiEvent->mRefPoint -= widget->WidgetToScreenOffset();
|
||||
}
|
||||
}
|
||||
|
||||
targetDoc->FlushPendingNotifications(FlushType::Layout);
|
||||
|
|
|
@ -45,8 +45,13 @@ add_task(async function test_drag_coords() {
|
|||
await Promise.all(promises);
|
||||
info(JSON.stringify(coords));
|
||||
for (let coordType of ["screen", "client"]) {
|
||||
is(coords.dragend[coordType].x, coords.dragstart[coordType].x + 12, `x ${coordType} is correct`);
|
||||
is(coords.dragend[coordType].y, coords.dragstart[coordType].y + 12, `y ${coordType} is correct`);
|
||||
// Let (tx,ty) = (target.x, target.y). Then synthesizePlainDragAndDrop
|
||||
// sends mousedown/dragstart at (tx + srcX, ty + srcY), or (tx + 2, ty + 2).
|
||||
// It later sends dragend at (tx + srcX + 2*stepX, ty + srcY + 2*stepY),
|
||||
// or (tx + 22, ty + 22). In other words, the position at dragend should
|
||||
// be the position at dragstart, but offset by (20, 20).
|
||||
is(coords.dragend[coordType].x, coords.dragstart[coordType].x + 20, `x ${coordType} is correct`);
|
||||
is(coords.dragend[coordType].y, coords.dragstart[coordType].y + 20, `y ${coordType} is correct`);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
|
||||
<script type="application/javascript">
|
||||
|
||||
const { AppConstants } = SpecialPowers.ChromeUtils.importESModule(
|
||||
"resource://gre/modules/AppConstants.sys.mjs"
|
||||
);
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function checkInputEvent(aEvent, aExpectedTarget, aInputType, aData, aDataTransfer, aTargetRanges, aDescription) {
|
||||
|
@ -935,6 +939,10 @@ async function doTest() {
|
|||
})();
|
||||
|
||||
// -------- Test dragging contenteditable to same contenteditable
|
||||
// Bug 1904272: Android Non-XOrigin incorrectly inserts after the 3rd M
|
||||
// instead of after the 2nd M in some of the following tests.
|
||||
const isAndroidException = AppConstants.platform === "android" && !isXOrigin;
|
||||
|
||||
await (async function test_dragging_from_contenteditable_to_itself() {
|
||||
const description = "dragging text in contenteditable to same contenteditable";
|
||||
container.innerHTML = "<div contenteditable><b>bold</b> <span>MMMM</span></div>";
|
||||
|
@ -964,10 +972,16 @@ async function doTest() {
|
|||
}
|
||||
)
|
||||
) {
|
||||
todo_is(contenteditable.innerHTML, "<b>bd</b> <span>MM<b>ol</b>MM</span>",
|
||||
`${description}: dragged range should be removed from contenteditable`);
|
||||
todo_isnot(contenteditable.innerHTML, "<b>bd</b> <span>MMMM</span><b>ol</b>",
|
||||
`${description}: dragged range should be removed from contenteditable`);
|
||||
const kExpectedOffsets = isAndroidException ? [3,3] : [2,2];
|
||||
if (isAndroidException) {
|
||||
todo_is(contenteditable.innerHTML, "<b>bd</b> <span>MM</span><b>ol</b><span>MM</span>",
|
||||
`${description}: dragged range should be removed from contenteditable`);
|
||||
isnot(contenteditable.innerHTML, "<b>bd</b> <span>MMMM</span><b>ol</b>",
|
||||
`${description}: dragged range should be removed from contenteditable`);
|
||||
} else {
|
||||
is(contenteditable.innerHTML, "<b>bd</b> <span>MM</span><b>ol</b><span>MM</span>",
|
||||
`${description}: dragged range should be removed from contenteditable`);
|
||||
}
|
||||
is(beforeinputEvents.length, 2,
|
||||
`${description}: 2 "beforeinput" events should be fired on contenteditable`);
|
||||
checkInputEvent(beforeinputEvents[0], contenteditable, "deleteByDrag", null, null,
|
||||
|
@ -977,8 +991,8 @@ async function doTest() {
|
|||
checkInputEvent(beforeinputEvents[1], contenteditable, "insertFromDrop", null,
|
||||
[{type: "text/html", data: "<b>ol</b>"},
|
||||
{type: "text/plain", data: "ol"}],
|
||||
[{startContainer: lastTextNode, startOffset: 4,
|
||||
endContainer: lastTextNode, endOffset: 4}], // XXX unexpected
|
||||
[{startContainer: lastTextNode, startOffset: kExpectedOffsets[0],
|
||||
endContainer: lastTextNode, endOffset: kExpectedOffsets[1]}],
|
||||
description);
|
||||
is(inputEvents.length, 2,
|
||||
`${description}: 2 "input" events should be fired on contenteditable`);
|
||||
|
@ -1025,10 +1039,16 @@ async function doTest() {
|
|||
}
|
||||
)
|
||||
) {
|
||||
todo_is(contenteditable.innerHTML, "<b>bold</b> <span>MM<b>ol</b>MM</span>",
|
||||
`${description}: dragged range shouldn't be removed from contenteditable`);
|
||||
todo_isnot(contenteditable.innerHTML, "<b>bold</b> <span>MMMM</span><b>ol</b>",
|
||||
`${description}: dragged range shouldn't be removed from contenteditable`);
|
||||
const kExpectedOffsets = isAndroidException ? [3,3] : [2,2];
|
||||
if (isAndroidException) {
|
||||
todo_is(contenteditable.innerHTML, "<b>bold</b> <span>MM</span><b>ol</b><span>MM</span>",
|
||||
`${description}: dragged range shouldn't be removed from contenteditable`);
|
||||
isnot(contenteditable.innerHTML, "<b>bold</b> <span>MMMM</span><b>ol</b>",
|
||||
`${description}: dragged range shouldn't be removed from contenteditable`);
|
||||
} else {
|
||||
is(contenteditable.innerHTML, "<b>bold</b> <span>MM</span><b>ol</b><span>MM</span>",
|
||||
`${description}: dragged range shouldn't be removed from contenteditable`);
|
||||
}
|
||||
is(beforeinputEvents.length, 2,
|
||||
`${description}: 2 "beforeinput" events should be fired on contenteditable`);
|
||||
checkInputEvent(beforeinputEvents[0], contenteditable, "deleteByDrag", null, null,
|
||||
|
@ -1038,8 +1058,8 @@ async function doTest() {
|
|||
checkInputEvent(beforeinputEvents[1], contenteditable, "insertFromDrop", null,
|
||||
[{type: "text/html", data: "<b>ol</b>"},
|
||||
{type: "text/plain", data: "ol"}],
|
||||
[{startContainer: lastTextNode, startOffset: 4,
|
||||
endContainer: lastTextNode, endOffset: 4}], // XXX unexpected
|
||||
[{startContainer: lastTextNode, startOffset: kExpectedOffsets[0],
|
||||
endContainer: lastTextNode, endOffset: kExpectedOffsets[1]}],
|
||||
description);
|
||||
is(inputEvents.length, 1,
|
||||
`${description}: only one "input" event should be fired on contenteditable`);
|
||||
|
@ -1094,11 +1114,12 @@ async function doTest() {
|
|||
[{startContainer: selectionContainers[0], startOffset: 1,
|
||||
endContainer: selectionContainers[1], endOffset: 3}],
|
||||
description);
|
||||
const kExpectedOffsets = isAndroidException ? [3,3] : [2,2];
|
||||
checkInputEvent(beforeinputEvents[1], contenteditable, "insertFromDrop", null,
|
||||
[{type: "text/html", data: "<b>ol</b>"},
|
||||
{type: "text/plain", data: "ol"}],
|
||||
[{startContainer: lastTextNode, startOffset: 4,
|
||||
endContainer: lastTextNode, endOffset: 4}],
|
||||
[{startContainer: lastTextNode, startOffset: kExpectedOffsets[0],
|
||||
endContainer: lastTextNode, endOffset: kExpectedOffsets[1]}],
|
||||
description);
|
||||
is(inputEvents.length, 1,
|
||||
`${description}: only one "input" event should be fired on contenteditable`);
|
||||
|
@ -1141,17 +1162,23 @@ async function doTest() {
|
|||
}
|
||||
)
|
||||
) {
|
||||
todo_is(contenteditable.innerHTML, "<b>bold</b> <span>MM<b>ol</b>MM</span>",
|
||||
`${description}: dragged range shouldn't be removed from contenteditable`);
|
||||
todo_isnot(contenteditable.innerHTML, "<b>bold</b> <span>MMMM</span><b>ol</b>",
|
||||
`${description}: dragged range shouldn't be removed from contenteditable`);
|
||||
const kExpectedOffsets = isAndroidException ? [3,3] : [2,2];
|
||||
if (isAndroidException) {
|
||||
todo_is(contenteditable.innerHTML, "<b>bold</b> <span>MM</span><b>ol</b><span>MM</span>",
|
||||
`${description}: dragged range shouldn't be removed from contenteditable`);
|
||||
isnot(contenteditable.innerHTML, "<b>bold</b> <span>MMMM</span><b>ol</b>",
|
||||
`${description}: dragged range shouldn't be removed from contenteditable`);
|
||||
} else {
|
||||
is(contenteditable.innerHTML, "<b>bold</b> <span>MM</span><b>ol</b><span>MM</span>",
|
||||
`${description}: dragged range shouldn't be removed from contenteditable`);
|
||||
}
|
||||
is(beforeinputEvents.length, 1,
|
||||
`${description}: only 1 "beforeinput" events should be fired on contenteditable`);
|
||||
checkInputEvent(beforeinputEvents[0], contenteditable, "insertFromDrop", null,
|
||||
[{type: "text/html", data: "<b>ol</b>"},
|
||||
{type: "text/plain", data: "ol"}],
|
||||
[{startContainer: lastTextNode, startOffset: 4,
|
||||
endContainer: lastTextNode, endOffset: 4}], // XXX unexpected
|
||||
[{startContainer: lastTextNode, startOffset: kExpectedOffsets[0],
|
||||
endContainer: lastTextNode, endOffset: kExpectedOffsets[1]}],
|
||||
description);
|
||||
is(inputEvents.length, 1,
|
||||
`${description}: only 1 "input" events should be fired on contenteditable`);
|
||||
|
@ -2084,9 +2111,7 @@ async function doTest() {
|
|||
) {
|
||||
is(textarea.value, "Linne2",
|
||||
`${description}: dragged range should be removed from <textarea>`);
|
||||
todo_is(contenteditable.innerHTML, "<div>e1</div><div>Li</div>",
|
||||
`${description}: dragged content should be inserted into contenteditable`);
|
||||
todo_isnot(contenteditable.innerHTML, "e1<br>Li<br>",
|
||||
is(contenteditable.innerHTML, "e1<br>Li<br>",
|
||||
`${description}: dragged content should be inserted into contenteditable`);
|
||||
is(beforeinputEvents.length, 2,
|
||||
`${description}: 2 "beforeinput" events should be fired on <input> and contenteditable`);
|
||||
|
@ -2140,9 +2165,7 @@ async function doTest() {
|
|||
) {
|
||||
is(textarea.value, "Line1\nLine2",
|
||||
`${description}: dragged range should be removed from <textarea>`);
|
||||
todo_is(contenteditable.innerHTML, "<div>e1</div><div>Li</div>",
|
||||
`${description}: dragged content should be inserted into contenteditable`);
|
||||
todo_isnot(contenteditable.innerHTML, "e1<br>Li<br>",
|
||||
is(contenteditable.innerHTML, "e1<br>Li<br>",
|
||||
`${description}: dragged content should be inserted into contenteditable`);
|
||||
is(beforeinputEvents.length, 1,
|
||||
`${description}: only one "beforeinput" events should be fired on contenteditable`);
|
||||
|
|
|
@ -387,10 +387,10 @@ function sendDragEvent(aEvent, aTarget, aWindow = window) {
|
|||
cancelableArg,
|
||||
viewArg,
|
||||
detailArg,
|
||||
screenXArg,
|
||||
screenYArg,
|
||||
clientXArg,
|
||||
clientYArg,
|
||||
Math.round(screenXArg),
|
||||
Math.round(screenYArg),
|
||||
Math.round(clientXArg),
|
||||
Math.round(clientYArg),
|
||||
ctrlKeyArg,
|
||||
altKeyArg,
|
||||
shiftKeyArg,
|
||||
|
@ -3082,10 +3082,10 @@ function createDragEventObject(
|
|||
var destScreenX = aDestWindow.mozInnerScreenX + destClientX;
|
||||
var destScreenY = aDestWindow.mozInnerScreenY + destClientY;
|
||||
if ("clientX" in aDragEvent && !("screenX" in aDragEvent)) {
|
||||
aDragEvent.screenX = aDestWindow.mozInnerScreenX + aDragEvent.clientX;
|
||||
destScreenX = aDestWindow.mozInnerScreenX + aDragEvent.clientX;
|
||||
}
|
||||
if ("clientY" in aDragEvent && !("screenY" in aDragEvent)) {
|
||||
aDragEvent.screenY = aDestWindow.mozInnerScreenY + aDragEvent.clientY;
|
||||
destScreenY = aDestWindow.mozInnerScreenY + aDragEvent.clientY;
|
||||
}
|
||||
|
||||
// Wrap only in plain mochitests
|
||||
|
@ -3854,12 +3854,12 @@ async function synthesizePlainDragAndDrop(aParams) {
|
|||
// Since we don't synthesize drop event, we need to set drag end point
|
||||
// explicitly for "dragEnd" event which will be fired by
|
||||
// endDragSession().
|
||||
dragEvent.clientX = finalX;
|
||||
dragEvent.clientY = finalY;
|
||||
dragEvent.clientX = srcElement.getBoundingClientRect().x + finalX;
|
||||
dragEvent.clientY = srcElement.getBoundingClientRect().y + finalY;
|
||||
let event = createDragEventObject(
|
||||
"dragend",
|
||||
destElement || srcElement,
|
||||
destElement ? srcWindow : destWindow,
|
||||
srcElement,
|
||||
srcWindow,
|
||||
null,
|
||||
dragEvent
|
||||
);
|
||||
|
|
Загрузка…
Ссылка в новой задаче