Bug 1909020 - Make createDragEventObject() in EventUtils.js aware of HiDPI environments r=smaug
`synthesizePlainDragAndDrop()` sends `drop` event [1] via `PresShell` [2]. Then, the `screenX` and `screenY` values are set to `WidgetEvent::mRefPoint` [3]. Then, the `drop` event's position is recorded before dispatch [4]. So, `drop` event is fired on the target but the `mRefPoint` may be outside the target. Finally, synthesized `eMouseMove` after `eDrop` will be fired on the wrong element which is different from `eDrop`'s target. This caused the failures of `test_synthmousemove_after_dnd.html` and `test_dragdrop.html` on Android. Perhaps, we should improve `nsDOMWindowUtils` or something lower layer later. Instead, this patch fixes in `EventUtils.js` level. This makes the `createDragEventObject()`. 1. https://searchfox.org/mozilla-central/rev/6a72a6d20eeb1b20b93862a79166938d6ce794a0/testing/mochitest/tests/SimpleTest/EventUtils.js#3893-3900 2. https://searchfox.org/mozilla-central/rev/6a72a6d20eeb1b20b93862a79166938d6ce794a0/testing/mochitest/tests/SimpleTest/EventUtils.js#376-393,400 3. https://searchfox.org/mozilla-central/rev/6a72a6d20eeb1b20b93862a79166938d6ce794a0/dom/events/MouseEvent.cpp#81-84 4. https://searchfox.org/mozilla-central/rev/6a72a6d20eeb1b20b93862a79166938d6ce794a0/layout/base/PresShell.cpp#8987 Differential Revision: https://phabricator.services.mozilla.com/D251091
This commit is contained in:
committed by
masayuki@d-toybox.com
parent
842f61a7ac
commit
735e6414f0
@@ -939,9 +939,6 @@ async function doTest() {
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
// -------- Test dragging contenteditable to same contenteditable
|
// -------- 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() {
|
await (async function test_dragging_from_contenteditable_to_itself() {
|
||||||
const description = "dragging text in contenteditable to same contenteditable";
|
const description = "dragging text in contenteditable to same contenteditable";
|
||||||
@@ -972,16 +969,8 @@ async function doTest() {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
const kExpectedOffsets = isAndroidException ? [3,3] : [2,2];
|
is(contenteditable.innerHTML, "<b>bd</b> <span>MM</span><b>ol</b><span>MM</span>",
|
||||||
if (isAndroidException) {
|
`${description}: dragged range should be removed from contenteditable`);
|
||||||
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,
|
is(beforeinputEvents.length, 2,
|
||||||
`${description}: 2 "beforeinput" events should be fired on contenteditable`);
|
`${description}: 2 "beforeinput" events should be fired on contenteditable`);
|
||||||
checkInputEvent(beforeinputEvents[0], contenteditable, "deleteByDrag", null, null,
|
checkInputEvent(beforeinputEvents[0], contenteditable, "deleteByDrag", null, null,
|
||||||
@@ -991,8 +980,8 @@ async function doTest() {
|
|||||||
checkInputEvent(beforeinputEvents[1], contenteditable, "insertFromDrop", null,
|
checkInputEvent(beforeinputEvents[1], contenteditable, "insertFromDrop", null,
|
||||||
[{type: "text/html", data: "<b>ol</b>"},
|
[{type: "text/html", data: "<b>ol</b>"},
|
||||||
{type: "text/plain", data: "ol"}],
|
{type: "text/plain", data: "ol"}],
|
||||||
[{startContainer: lastTextNode, startOffset: kExpectedOffsets[0],
|
[{startContainer: lastTextNode, startOffset: 2,
|
||||||
endContainer: lastTextNode, endOffset: kExpectedOffsets[1]}],
|
endContainer: lastTextNode, endOffset: 2}],
|
||||||
description);
|
description);
|
||||||
is(inputEvents.length, 2,
|
is(inputEvents.length, 2,
|
||||||
`${description}: 2 "input" events should be fired on contenteditable`);
|
`${description}: 2 "input" events should be fired on contenteditable`);
|
||||||
@@ -1039,16 +1028,8 @@ async function doTest() {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
const kExpectedOffsets = isAndroidException ? [3,3] : [2,2];
|
is(contenteditable.innerHTML, "<b>bold</b> <span>MM</span><b>ol</b><span>MM</span>",
|
||||||
if (isAndroidException) {
|
`${description}: dragged range shouldn't be removed from contenteditable`);
|
||||||
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,
|
is(beforeinputEvents.length, 2,
|
||||||
`${description}: 2 "beforeinput" events should be fired on contenteditable`);
|
`${description}: 2 "beforeinput" events should be fired on contenteditable`);
|
||||||
checkInputEvent(beforeinputEvents[0], contenteditable, "deleteByDrag", null, null,
|
checkInputEvent(beforeinputEvents[0], contenteditable, "deleteByDrag", null, null,
|
||||||
@@ -1058,8 +1039,8 @@ async function doTest() {
|
|||||||
checkInputEvent(beforeinputEvents[1], contenteditable, "insertFromDrop", null,
|
checkInputEvent(beforeinputEvents[1], contenteditable, "insertFromDrop", null,
|
||||||
[{type: "text/html", data: "<b>ol</b>"},
|
[{type: "text/html", data: "<b>ol</b>"},
|
||||||
{type: "text/plain", data: "ol"}],
|
{type: "text/plain", data: "ol"}],
|
||||||
[{startContainer: lastTextNode, startOffset: kExpectedOffsets[0],
|
[{startContainer: lastTextNode, startOffset: 2,
|
||||||
endContainer: lastTextNode, endOffset: kExpectedOffsets[1]}],
|
endContainer: lastTextNode, endOffset: 2}],
|
||||||
description);
|
description);
|
||||||
is(inputEvents.length, 1,
|
is(inputEvents.length, 1,
|
||||||
`${description}: only one "input" event should be fired on contenteditable`);
|
`${description}: only one "input" event should be fired on contenteditable`);
|
||||||
@@ -1114,12 +1095,11 @@ async function doTest() {
|
|||||||
[{startContainer: selectionContainers[0], startOffset: 1,
|
[{startContainer: selectionContainers[0], startOffset: 1,
|
||||||
endContainer: selectionContainers[1], endOffset: 3}],
|
endContainer: selectionContainers[1], endOffset: 3}],
|
||||||
description);
|
description);
|
||||||
const kExpectedOffsets = isAndroidException ? [3,3] : [2,2];
|
|
||||||
checkInputEvent(beforeinputEvents[1], contenteditable, "insertFromDrop", null,
|
checkInputEvent(beforeinputEvents[1], contenteditable, "insertFromDrop", null,
|
||||||
[{type: "text/html", data: "<b>ol</b>"},
|
[{type: "text/html", data: "<b>ol</b>"},
|
||||||
{type: "text/plain", data: "ol"}],
|
{type: "text/plain", data: "ol"}],
|
||||||
[{startContainer: lastTextNode, startOffset: kExpectedOffsets[0],
|
[{startContainer: lastTextNode, startOffset: 2,
|
||||||
endContainer: lastTextNode, endOffset: kExpectedOffsets[1]}],
|
endContainer: lastTextNode, endOffset: 2}],
|
||||||
description);
|
description);
|
||||||
is(inputEvents.length, 1,
|
is(inputEvents.length, 1,
|
||||||
`${description}: only one "input" event should be fired on contenteditable`);
|
`${description}: only one "input" event should be fired on contenteditable`);
|
||||||
@@ -1162,23 +1142,15 @@ async function doTest() {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
const kExpectedOffsets = isAndroidException ? [3,3] : [2,2];
|
is(contenteditable.innerHTML, "<b>bold</b> <span>MM</span><b>ol</b><span>MM</span>",
|
||||||
if (isAndroidException) {
|
`${description}: dragged range shouldn't be removed from contenteditable`);
|
||||||
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,
|
is(beforeinputEvents.length, 1,
|
||||||
`${description}: only 1 "beforeinput" events should be fired on contenteditable`);
|
`${description}: only 1 "beforeinput" events should be fired on contenteditable`);
|
||||||
checkInputEvent(beforeinputEvents[0], contenteditable, "insertFromDrop", null,
|
checkInputEvent(beforeinputEvents[0], contenteditable, "insertFromDrop", null,
|
||||||
[{type: "text/html", data: "<b>ol</b>"},
|
[{type: "text/html", data: "<b>ol</b>"},
|
||||||
{type: "text/plain", data: "ol"}],
|
{type: "text/plain", data: "ol"}],
|
||||||
[{startContainer: lastTextNode, startOffset: kExpectedOffsets[0],
|
[{startContainer: lastTextNode, startOffset: 2,
|
||||||
endContainer: lastTextNode, endOffset: kExpectedOffsets[1]}],
|
endContainer: lastTextNode, endOffset: 2}],
|
||||||
description);
|
description);
|
||||||
is(inputEvents.length, 1,
|
is(inputEvents.length, 1,
|
||||||
`${description}: only 1 "input" events should be fired on contenteditable`);
|
`${description}: only 1 "input" events should be fired on contenteditable`);
|
||||||
@@ -3548,16 +3520,8 @@ async function doTest() {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
const kExpectedOffsets = isAndroidException ? [4,4] : [2,2];
|
is(contenteditable.innerHTML, "!!<span>MM</span>dragme<span>MM</span>",
|
||||||
if (isAndroidException) {
|
`${description}: dragged range should be moved in inline contenteditable`);
|
||||||
todo_is(contenteditable.innerHTML, "!!<span>MM</span>dragme<span>MM</span>",
|
|
||||||
`${description}: dragged range should be moved in inline contenteditable`);
|
|
||||||
is(contenteditable.innerHTML, "!!<span>MMMM</span>dragme",
|
|
||||||
`${description}: dragged range should be moved in inline contenteditable`);
|
|
||||||
} else {
|
|
||||||
is(contenteditable.innerHTML, "!!<span>MM</span>dragme<span>MM</span>",
|
|
||||||
`${description}: dragged range should be moved in inline contenteditable`);
|
|
||||||
}
|
|
||||||
is(beforeinputEvents.length, 2,
|
is(beforeinputEvents.length, 2,
|
||||||
`${description}: 2 "beforeinput" events should be fired on inline contenteditable`);
|
`${description}: 2 "beforeinput" events should be fired on inline contenteditable`);
|
||||||
checkInputEvent(beforeinputEvents[0], contenteditable, "deleteByDrag", null, null,
|
checkInputEvent(beforeinputEvents[0], contenteditable, "deleteByDrag", null, null,
|
||||||
@@ -3567,8 +3531,8 @@ async function doTest() {
|
|||||||
checkInputEvent(beforeinputEvents[1], contenteditable, "insertFromDrop", null,
|
checkInputEvent(beforeinputEvents[1], contenteditable, "insertFromDrop", null,
|
||||||
[{type: "text/html", data: "dragme"},
|
[{type: "text/html", data: "dragme"},
|
||||||
{type: "text/plain", data: "dragme"}],
|
{type: "text/plain", data: "dragme"}],
|
||||||
[{startContainer: span.firstChild, startOffset: kExpectedOffsets[0],
|
[{startContainer: span.firstChild, startOffset: 2,
|
||||||
endContainer: span.firstChild, endOffset: kExpectedOffsets[1]}],
|
endContainer: span.firstChild, endOffset: 2}],
|
||||||
description);
|
description);
|
||||||
is(inputEvents.length, 2,
|
is(inputEvents.length, 2,
|
||||||
`${description}: 2 "input" events should be fired on inline contenteditable`);
|
`${description}: 2 "input" events should be fired on inline contenteditable`);
|
||||||
@@ -3611,18 +3575,10 @@ async function doTest() {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
const kExpectedOffsets = isAndroidException ? [2,2] : [1,1];
|
|
||||||
is(contenteditable.innerHTML, "!!",
|
is(contenteditable.innerHTML, "!!",
|
||||||
`${description}: dragged range should be removed from inline contenteditable`);
|
`${description}: dragged range should be removed from inline contenteditable`);
|
||||||
if (isAndroidException) {
|
is(otherContenteditable.innerHTML, "MdragmeM",
|
||||||
todo_is(otherContenteditable.innerHTML, "MdragmeM",
|
`${description}: dragged content should be inserted into other inline contenteditable`);
|
||||||
`${description}: dragged content should be inserted into other inline contenteditable`);
|
|
||||||
is(otherContenteditable.innerHTML, "MMdragme",
|
|
||||||
`${description}: dragged content should be inserted into other inline contenteditable`);
|
|
||||||
} else {
|
|
||||||
is(otherContenteditable.innerHTML, "MdragmeM",
|
|
||||||
`${description}: dragged content should be inserted into other inline contenteditable`);
|
|
||||||
}
|
|
||||||
is(beforeinputEvents.length, 2,
|
is(beforeinputEvents.length, 2,
|
||||||
`${description}: 2 "beforeinput" events should be fired on inline contenteditable`);
|
`${description}: 2 "beforeinput" events should be fired on inline contenteditable`);
|
||||||
checkInputEvent(beforeinputEvents[0], contenteditable, "deleteByDrag", null, null,
|
checkInputEvent(beforeinputEvents[0], contenteditable, "deleteByDrag", null, null,
|
||||||
@@ -3632,8 +3588,8 @@ async function doTest() {
|
|||||||
checkInputEvent(beforeinputEvents[1], otherContenteditable, "insertFromDrop", null,
|
checkInputEvent(beforeinputEvents[1], otherContenteditable, "insertFromDrop", null,
|
||||||
[{type: "text/html", data: "dragme"},
|
[{type: "text/html", data: "dragme"},
|
||||||
{type: "text/plain", data: "dragme"}],
|
{type: "text/plain", data: "dragme"}],
|
||||||
[{startContainer: otherContenteditable.firstChild, startOffset: kExpectedOffsets[0],
|
[{startContainer: otherContenteditable.firstChild, startOffset: 1,
|
||||||
endContainer: otherContenteditable.firstChild, endOffset: kExpectedOffsets[1]}],
|
endContainer: otherContenteditable.firstChild, endOffset: 1}],
|
||||||
description);
|
description);
|
||||||
is(inputEvents.length, 2,
|
is(inputEvents.length, 2,
|
||||||
`${description}: 2 "input" events should be fired on inline contenteditable`);
|
`${description}: 2 "input" events should be fired on inline contenteditable`);
|
||||||
|
|||||||
@@ -597,7 +597,6 @@ support-files = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
["test_synthmousemove_after_dnd.html"]
|
["test_synthmousemove_after_dnd.html"]
|
||||||
skip-if = ["os == 'android'"] # Bug 1909020
|
|
||||||
|
|
||||||
["test_transformed_scrolling_repaints.html"]
|
["test_transformed_scrolling_repaints.html"]
|
||||||
|
|
||||||
|
|||||||
@@ -32,9 +32,19 @@ SimpleTest.waitForFocus(async () => {
|
|||||||
const promiseDrop = new Promise(resolve => {
|
const promiseDrop = new Promise(resolve => {
|
||||||
target.addEventListener("drop", event => {
|
target.addEventListener("drop", event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
target.addEventListener("mouseover", resolve, {once: true});
|
isnot(
|
||||||
|
document.querySelector("span:hover"),
|
||||||
|
target,
|
||||||
|
"The target should not have hover state during the drop event propagation"
|
||||||
|
);
|
||||||
|
info("Waiting for mouseover event after drop event...");
|
||||||
|
target.addEventListener("mouseover", () => {
|
||||||
|
info("Got mouseover event");
|
||||||
|
resolve();
|
||||||
|
}, {once: true});
|
||||||
}, { once: true });
|
}, { once: true });
|
||||||
});
|
});
|
||||||
|
info("Dragging selection is the source element and drop it to the target...");
|
||||||
getSelection().selectAllChildren(source);
|
getSelection().selectAllChildren(source);
|
||||||
synthesizePlainDragAndDrop({
|
synthesizePlainDragAndDrop({
|
||||||
srcSelection: getSelection(),
|
srcSelection: getSelection(),
|
||||||
|
|||||||
@@ -1465,13 +1465,7 @@ function synthesizeNativeMouseEvent(aParams, aCallback = null) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const rect = target?.getBoundingClientRect();
|
const rect = target?.getBoundingClientRect();
|
||||||
let resolution = 1.0;
|
const resolution = _getTopWindowResolution(win);
|
||||||
try {
|
|
||||||
resolution = _getDOMWindowUtils(win.top).getResolution();
|
|
||||||
} catch (e) {
|
|
||||||
// XXX How to get mobile viewport scale on Fission+xorigin since
|
|
||||||
// window.top access isn't allowed due to cross-origin?
|
|
||||||
}
|
|
||||||
const scaleValue = (() => {
|
const scaleValue = (() => {
|
||||||
if (scale === "inScreenPixels") {
|
if (scale === "inScreenPixels") {
|
||||||
return 1.0;
|
return 1.0;
|
||||||
@@ -1490,15 +1484,7 @@ function synthesizeNativeMouseEvent(aParams, aCallback = null) {
|
|||||||
if (screenX != undefined) {
|
if (screenX != undefined) {
|
||||||
return screenX * scaleValue;
|
return screenX * scaleValue;
|
||||||
}
|
}
|
||||||
let winInnerOffsetX = win.mozInnerScreenX;
|
const winInnerOffsetX = _getScreenXInUnscaledCSSPixels(win);
|
||||||
try {
|
|
||||||
winInnerOffsetX =
|
|
||||||
win.top.mozInnerScreenX +
|
|
||||||
(win.mozInnerScreenX - win.top.mozInnerScreenX) * resolution;
|
|
||||||
} catch (e) {
|
|
||||||
// XXX fission+xorigin test throws permission denied since win.top is
|
|
||||||
// cross-origin.
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
(((atCenter ? rect.width / 2 : offsetX) + rect.left) * resolution +
|
(((atCenter ? rect.width / 2 : offsetX) + rect.left) * resolution +
|
||||||
winInnerOffsetX) *
|
winInnerOffsetX) *
|
||||||
@@ -1511,15 +1497,7 @@ function synthesizeNativeMouseEvent(aParams, aCallback = null) {
|
|||||||
if (screenY != undefined) {
|
if (screenY != undefined) {
|
||||||
return screenY * scaleValue;
|
return screenY * scaleValue;
|
||||||
}
|
}
|
||||||
let winInnerOffsetY = win.mozInnerScreenY;
|
const winInnerOffsetY = _getScreenYInUnscaledCSSPixels(win);
|
||||||
try {
|
|
||||||
winInnerOffsetY =
|
|
||||||
win.top.mozInnerScreenY +
|
|
||||||
(win.mozInnerScreenY - win.top.mozInnerScreenY) * resolution;
|
|
||||||
} catch (e) {
|
|
||||||
// XXX fission+xorigin test throws permission denied since win.top is
|
|
||||||
// cross-origin.
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
(((atCenter ? rect.height / 2 : offsetY) + rect.top) * resolution +
|
(((atCenter ? rect.height / 2 : offsetY) + rect.top) * resolution +
|
||||||
winInnerOffsetY) *
|
winInnerOffsetY) *
|
||||||
@@ -2249,6 +2227,67 @@ function _getDOMWindowUtils(aWindow = window) {
|
|||||||
return aWindow.windowUtils;
|
return aWindow.windowUtils;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Window} aWindow The window.
|
||||||
|
* @returns The scaling value applied to the top window.
|
||||||
|
*/
|
||||||
|
function _getTopWindowResolution(aWindow) {
|
||||||
|
let resolution = 1.0;
|
||||||
|
try {
|
||||||
|
resolution = _getDOMWindowUtils(aWindow.top).getResolution();
|
||||||
|
} catch (e) {
|
||||||
|
// XXX How to get mobile viewport scale on Fission+xorigin since
|
||||||
|
// window.top access isn't allowed due to cross-origin?
|
||||||
|
}
|
||||||
|
return resolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Window} aWindow The window which you want to get its x-offset in the
|
||||||
|
* screen.
|
||||||
|
* @returns The screenX of aWindow in the unscaled CSS pixels.
|
||||||
|
*/
|
||||||
|
function _getScreenXInUnscaledCSSPixels(aWindow) {
|
||||||
|
// XXX mozInnerScreen might be invalid value on mobile viewport (Bug 1701546),
|
||||||
|
// so use window.top's mozInnerScreen. But this won't work fission+xorigin
|
||||||
|
// with mobile viewport until mozInnerScreen returns valid value with
|
||||||
|
// scale.
|
||||||
|
let winInnerOffsetX = aWindow.mozInnerScreenX;
|
||||||
|
try {
|
||||||
|
winInnerOffsetX =
|
||||||
|
aWindow.top.mozInnerScreenX +
|
||||||
|
(aWindow.mozInnerScreenX - aWindow.top.mozInnerScreenX) *
|
||||||
|
_getTopWindowResolution(aWindow);
|
||||||
|
} catch (e) {
|
||||||
|
// XXX fission+xorigin test throws permission denied since win.top is
|
||||||
|
// cross-origin.
|
||||||
|
}
|
||||||
|
return winInnerOffsetX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Window} aWindow The window which you want to get its y-offset in the
|
||||||
|
* screen.
|
||||||
|
* @returns The screenY of aWindow in the unscaled CSS pixels.
|
||||||
|
*/
|
||||||
|
function _getScreenYInUnscaledCSSPixels(aWindow) {
|
||||||
|
// XXX mozInnerScreen might be invalid value on mobile viewport (Bug 1701546),
|
||||||
|
// so use window.top's mozInnerScreen. But this won't work fission+xorigin
|
||||||
|
// with mobile viewport until mozInnerScreen returns valid value with
|
||||||
|
// scale.
|
||||||
|
let winInnerOffsetY = aWindow.mozInnerScreenY;
|
||||||
|
try {
|
||||||
|
winInnerOffsetY =
|
||||||
|
aWindow.top.mozInnerScreenY +
|
||||||
|
(aWindow.mozInnerScreenY - aWindow.top.mozInnerScreenY) *
|
||||||
|
_getTopWindowResolution(aWindow);
|
||||||
|
} catch (e) {
|
||||||
|
// XXX fission+xorigin test throws permission denied since win.top is
|
||||||
|
// cross-origin.
|
||||||
|
}
|
||||||
|
return winInnerOffsetY;
|
||||||
|
}
|
||||||
|
|
||||||
function _defineConstant(name, value) {
|
function _defineConstant(name, value) {
|
||||||
Object.defineProperty(this, name, {
|
Object.defineProperty(this, name, {
|
||||||
value,
|
value,
|
||||||
@@ -3127,17 +3166,28 @@ function createDragEventObject(
|
|||||||
aDataTransfer,
|
aDataTransfer,
|
||||||
aDragEvent
|
aDragEvent
|
||||||
) {
|
) {
|
||||||
var destRect = aDestElement.getBoundingClientRect();
|
const resolution = _getTopWindowResolution(aDestWindow.top);
|
||||||
var destClientX = destRect.left + destRect.width / 2;
|
const destRect = aDestElement.getBoundingClientRect();
|
||||||
var destClientY = destRect.top + destRect.height / 2;
|
// If clientX and/or clientY are specified, we should use them. Otherwise,
|
||||||
var destScreenX = aDestWindow.mozInnerScreenX + destClientX;
|
// use the center of the dest element.
|
||||||
var destScreenY = aDestWindow.mozInnerScreenY + destClientY;
|
const destClientXInCSSPixels =
|
||||||
if ("clientX" in aDragEvent && !("screenX" in aDragEvent)) {
|
"clientX" in aDragEvent && !("screenX" in aDragEvent)
|
||||||
destScreenX = aDestWindow.mozInnerScreenX + aDragEvent.clientX;
|
? aDragEvent.clientX
|
||||||
}
|
: destRect.left + destRect.width / 2;
|
||||||
if ("clientY" in aDragEvent && !("screenY" in aDragEvent)) {
|
const destClientYInCSSPixels =
|
||||||
destScreenY = aDestWindow.mozInnerScreenY + aDragEvent.clientY;
|
"clientY" in aDragEvent && !("screenY" in aDragEvent)
|
||||||
}
|
? aDragEvent.clientY
|
||||||
|
: destRect.top + destRect.height / 2;
|
||||||
|
|
||||||
|
const devicePixelRatio = aDestWindow.devicePixelRatio;
|
||||||
|
const destScreenXInDevicePixels =
|
||||||
|
(_getScreenXInUnscaledCSSPixels(aDestWindow) +
|
||||||
|
destClientXInCSSPixels * resolution) *
|
||||||
|
devicePixelRatio;
|
||||||
|
const destScreenYInDevicePixels =
|
||||||
|
(_getScreenYInUnscaledCSSPixels(aDestWindow) +
|
||||||
|
destClientYInCSSPixels * resolution) *
|
||||||
|
devicePixelRatio;
|
||||||
|
|
||||||
// Wrap only in plain mochitests
|
// Wrap only in plain mochitests
|
||||||
let dataTransfer;
|
let dataTransfer;
|
||||||
@@ -3151,14 +3201,13 @@ function createDragEventObject(
|
|||||||
// nsContentUtils::SetDataTransferInEvent for actual impl).
|
// nsContentUtils::SetDataTransferInEvent for actual impl).
|
||||||
dataTransfer.dropEffect = aDataTransfer.dropEffect;
|
dataTransfer.dropEffect = aDataTransfer.dropEffect;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Object.assign(
|
return Object.assign(
|
||||||
{
|
{
|
||||||
type: aType,
|
type: aType,
|
||||||
screenX: destScreenX,
|
screenX: _EU_roundDevicePixels(destScreenXInDevicePixels),
|
||||||
screenY: destScreenY,
|
screenY: _EU_roundDevicePixels(destScreenYInDevicePixels),
|
||||||
clientX: destClientX,
|
clientX: _EU_roundDevicePixels(destClientXInCSSPixels),
|
||||||
clientY: destClientY,
|
clientY: _EU_roundDevicePixels(destClientYInCSSPixels),
|
||||||
dataTransfer,
|
dataTransfer,
|
||||||
_domDispatchOnly: aDragEvent._domDispatchOnly,
|
_domDispatchOnly: aDragEvent._domDispatchOnly,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user