forked from mirrors/gecko-dev
Bug 1561435 - Format gfx/, a=automatic-formatting
# ignore-this-changeset Differential Revision: https://phabricator.services.mozilla.com/D35903 --HG-- extra : source : 00faaa954cecb534fa97f4e87de61635c8c526bc
This commit is contained in:
parent
5af464dcc4
commit
85064fe4c3
10 changed files with 844 additions and 286 deletions
|
|
@ -45,7 +45,6 @@ module.exports = {
|
|||
"overrides": [{
|
||||
"files": [
|
||||
"devtools/**",
|
||||
"gfx/**",
|
||||
"gradle/**",
|
||||
"hal/**",
|
||||
"image/**",
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ toolkit/components/telemetry/datareporting-prefs.js
|
|||
toolkit/components/telemetry/healthreport-prefs.js
|
||||
|
||||
# Ignore all top-level directories for now.
|
||||
gfx/**
|
||||
gradle/**
|
||||
hal/**
|
||||
image/**
|
||||
|
|
|
|||
|
|
@ -27,27 +27,36 @@ class FissionTestHelperChild extends JSWindowActorChild {
|
|||
// namespace.
|
||||
|
||||
let cw = this.cw();
|
||||
Cu.exportFunction((cond, msg) => this.sendAsyncMessage("ok", {cond, msg}),
|
||||
cw, { defineAs: "ok" });
|
||||
Cu.exportFunction((a, b, msg) => this.sendAsyncMessage("is", {a, b, msg}),
|
||||
cw, { defineAs: "is" });
|
||||
Cu.exportFunction(
|
||||
(cond, msg) => this.sendAsyncMessage("ok", { cond, msg }),
|
||||
cw,
|
||||
{ defineAs: "ok" }
|
||||
);
|
||||
Cu.exportFunction(
|
||||
(a, b, msg) => this.sendAsyncMessage("is", { a, b, msg }),
|
||||
cw,
|
||||
{ defineAs: "is" }
|
||||
);
|
||||
|
||||
let FissionTestHelper = Cu.createObjectIn(cw, { defineAs: "FissionTestHelper" });
|
||||
FissionTestHelper.startTestPromise =
|
||||
new cw.Promise(
|
||||
Cu.exportFunction(
|
||||
(resolve) => {
|
||||
this._startTestPromiseResolver = resolve;
|
||||
},
|
||||
cw));
|
||||
let FissionTestHelper = Cu.createObjectIn(cw, {
|
||||
defineAs: "FissionTestHelper",
|
||||
});
|
||||
FissionTestHelper.startTestPromise = new cw.Promise(
|
||||
Cu.exportFunction(resolve => {
|
||||
this._startTestPromiseResolver = resolve;
|
||||
}, cw)
|
||||
);
|
||||
|
||||
Cu.exportFunction(this.subtestDone.bind(this),
|
||||
FissionTestHelper, { defineAs: "subtestDone" });
|
||||
Cu.exportFunction(this.subtestDone.bind(this), FissionTestHelper, {
|
||||
defineAs: "subtestDone",
|
||||
});
|
||||
|
||||
Cu.exportFunction(this.sendToOopif.bind(this),
|
||||
FissionTestHelper, { defineAs: "sendToOopif" });
|
||||
Cu.exportFunction(this.fireEventInEmbedder.bind(this),
|
||||
FissionTestHelper, { defineAs: "fireEventInEmbedder" });
|
||||
Cu.exportFunction(this.sendToOopif.bind(this), FissionTestHelper, {
|
||||
defineAs: "sendToOopif",
|
||||
});
|
||||
Cu.exportFunction(this.fireEventInEmbedder.bind(this), FissionTestHelper, {
|
||||
defineAs: "fireEventInEmbedder",
|
||||
});
|
||||
}
|
||||
|
||||
// Called by the subtest to indicate completion to the top-level browser-chrome
|
||||
|
|
@ -67,12 +76,15 @@ class FissionTestHelperChild extends JSWindowActorChild {
|
|||
let msgId = ++this._msgCounter;
|
||||
let cw = this.cw();
|
||||
let responsePromise = new cw.Promise(
|
||||
Cu.exportFunction(
|
||||
(resolve) => {
|
||||
this._oopifResponsePromiseResolvers[msgId] = resolve;
|
||||
},
|
||||
cw));
|
||||
this.sendAsyncMessage("EmbedderToOopif", {browsingContextId, msgId, stringToEval});
|
||||
Cu.exportFunction(resolve => {
|
||||
this._oopifResponsePromiseResolvers[msgId] = resolve;
|
||||
}, cw)
|
||||
);
|
||||
this.sendAsyncMessage("EmbedderToOopif", {
|
||||
browsingContextId,
|
||||
msgId,
|
||||
stringToEval,
|
||||
});
|
||||
return responsePromise;
|
||||
}
|
||||
|
||||
|
|
@ -81,7 +93,7 @@ class FissionTestHelperChild extends JSWindowActorChild {
|
|||
// things that happen. The embedder can use promiseOneEvent from
|
||||
// helper_fission_utils.js to listen for these events.
|
||||
fireEventInEmbedder(eventType, data) {
|
||||
this.sendAsyncMessage("OopifToEmbedder", {eventType, data});
|
||||
this.sendAsyncMessage("OopifToEmbedder", { eventType, data });
|
||||
}
|
||||
|
||||
handleEvent(evt) {
|
||||
|
|
@ -91,7 +103,9 @@ class FissionTestHelperChild extends JSWindowActorChild {
|
|||
// is fired by the content. See comments in fission_subtest_init().
|
||||
// Once bug 1557486 is fixed we can just register the FissionTestHelper:Init
|
||||
// event directly instead of DOMWindowCreated.
|
||||
this.contentWindow.addEventListener("FissionTestHelper:Init", this, { wantUntrusted: true });
|
||||
this.contentWindow.addEventListener("FissionTestHelper:Init", this, {
|
||||
wantUntrusted: true,
|
||||
});
|
||||
break;
|
||||
case "FissionTestHelper:Init":
|
||||
this.initialize();
|
||||
|
|
@ -107,14 +121,23 @@ class FissionTestHelperChild extends JSWindowActorChild {
|
|||
break;
|
||||
case "FromEmbedder":
|
||||
let evalResult = this.contentWindow.eval(msg.data.stringToEval);
|
||||
this.sendAsyncMessage("OopifToEmbedder", {msgId: msg.data.msgId, evalResult});
|
||||
this.sendAsyncMessage("OopifToEmbedder", {
|
||||
msgId: msg.data.msgId,
|
||||
evalResult,
|
||||
});
|
||||
break;
|
||||
case "FromOopif":
|
||||
if (typeof msg.data.msgId == "number") {
|
||||
if (!(msg.data.msgId in this._oopifResponsePromiseResolvers)) {
|
||||
dump("Error: FromOopif got a message with unknown numeric msgId in " + this.contentWindow.location.href + "\n");
|
||||
dump(
|
||||
"Error: FromOopif got a message with unknown numeric msgId in " +
|
||||
this.contentWindow.location.href +
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
this._oopifResponsePromiseResolvers[msg.data.msgId](msg.data.evalResult);
|
||||
this._oopifResponsePromiseResolvers[msg.data.msgId](
|
||||
msg.data.evalResult
|
||||
);
|
||||
delete this._oopifResponsePromiseResolvers[msg.data.msgId];
|
||||
} else if (typeof msg.data.eventType == "string") {
|
||||
let cw = this.cw();
|
||||
|
|
@ -122,7 +145,11 @@ class FissionTestHelperChild extends JSWindowActorChild {
|
|||
event.data = Cu.cloneInto(msg.data.data, cw);
|
||||
this.contentWindow.dispatchEvent(event);
|
||||
} else {
|
||||
dump("Warning: Unrecognized FromOopif message received in " + this.contentWindow.location.href + "\n");
|
||||
dump(
|
||||
"Warning: Unrecognized FromOopif message received in " +
|
||||
this.contentWindow.location.href +
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ var EXPORTED_SYMBOLS = ["FissionTestHelperParent"];
|
|||
class FissionTestHelperParent extends JSWindowActorParent {
|
||||
constructor() {
|
||||
super();
|
||||
this._testCompletePromise = new Promise((resolve) => {
|
||||
this._testCompletePromise = new Promise(resolve => {
|
||||
this._testCompletePromiseResolver = resolve;
|
||||
});
|
||||
}
|
||||
|
|
@ -42,11 +42,18 @@ class FissionTestHelperParent extends JSWindowActorParent {
|
|||
receiveMessage(msg) {
|
||||
switch (msg.name) {
|
||||
case "ok":
|
||||
FissionTestHelperParent.SimpleTest.ok(msg.data.cond, this.docURI() + " | " + msg.data.msg);
|
||||
FissionTestHelperParent.SimpleTest.ok(
|
||||
msg.data.cond,
|
||||
this.docURI() + " | " + msg.data.msg
|
||||
);
|
||||
break;
|
||||
|
||||
case "is":
|
||||
FissionTestHelperParent.SimpleTest.is(msg.data.a, msg.data.b, this.docURI() + " | " + msg.data.msg);
|
||||
FissionTestHelperParent.SimpleTest.is(
|
||||
msg.data.a,
|
||||
msg.data.b,
|
||||
this.docURI() + " | " + msg.data.msg
|
||||
);
|
||||
break;
|
||||
|
||||
case "Test:Complete":
|
||||
|
|
@ -56,14 +63,24 @@ class FissionTestHelperParent extends JSWindowActorParent {
|
|||
case "EmbedderToOopif":
|
||||
// This relays messages from the embedder to an OOP-iframe. The browsing
|
||||
// context id in the message data identifies the OOP-iframe.
|
||||
let oopifBrowsingContext = BrowsingContext.get(msg.data.browsingContextId);
|
||||
let oopifBrowsingContext = BrowsingContext.get(
|
||||
msg.data.browsingContextId
|
||||
);
|
||||
if (oopifBrowsingContext == null) {
|
||||
FissionTestHelperParent.SimpleTest.ok(false, "EmbedderToOopif couldn't find oopif");
|
||||
FissionTestHelperParent.SimpleTest.ok(
|
||||
false,
|
||||
"EmbedderToOopif couldn't find oopif"
|
||||
);
|
||||
break;
|
||||
}
|
||||
let oopifActor = oopifBrowsingContext.currentWindowGlobal.getActor("FissionTestHelper");
|
||||
let oopifActor = oopifBrowsingContext.currentWindowGlobal.getActor(
|
||||
"FissionTestHelper"
|
||||
);
|
||||
if (!oopifActor) {
|
||||
FissionTestHelperParent.SimpleTest.ok(false, "EmbedderToOopif couldn't find oopif actor");
|
||||
FissionTestHelperParent.SimpleTest.ok(
|
||||
false,
|
||||
"EmbedderToOopif couldn't find oopif actor"
|
||||
);
|
||||
break;
|
||||
}
|
||||
oopifActor.sendAsyncMessage("FromEmbedder", msg.data);
|
||||
|
|
@ -74,7 +91,10 @@ class FissionTestHelperParent extends JSWindowActorParent {
|
|||
// window which is embedding it.
|
||||
let embedderActor = this.embedderWindow().getActor("FissionTestHelper");
|
||||
if (!embedderActor) {
|
||||
FissionTestHelperParent.SimpleTest.ok(false, "OopifToEmbedder couldn't find embedder");
|
||||
FissionTestHelperParent.SimpleTest.ok(
|
||||
false,
|
||||
"OopifToEmbedder couldn't find embedder"
|
||||
);
|
||||
break;
|
||||
}
|
||||
embedderActor.sendAsyncMessage("FromOopif", msg.data);
|
||||
|
|
|
|||
|
|
@ -28,20 +28,30 @@ function getPlatform() {
|
|||
|
||||
function nativeVerticalWheelEventMsg() {
|
||||
switch (getPlatform()) {
|
||||
case "windows": return 0x020A; // WM_MOUSEWHEEL
|
||||
case "mac": return 0; // value is unused, can be anything
|
||||
case "linux": return 4; // value is unused, pass GDK_SCROLL_SMOOTH anyway
|
||||
case "windows":
|
||||
return 0x020a; // WM_MOUSEWHEEL
|
||||
case "mac":
|
||||
return 0; // value is unused, can be anything
|
||||
case "linux":
|
||||
return 4; // value is unused, pass GDK_SCROLL_SMOOTH anyway
|
||||
}
|
||||
throw new Error("Native wheel events not supported on platform " + getPlatform());
|
||||
throw new Error(
|
||||
"Native wheel events not supported on platform " + getPlatform()
|
||||
);
|
||||
}
|
||||
|
||||
function nativeHorizontalWheelEventMsg() {
|
||||
switch (getPlatform()) {
|
||||
case "windows": return 0x020E; // WM_MOUSEHWHEEL
|
||||
case "mac": return 0; // value is unused, can be anything
|
||||
case "linux": return 4; // value is unused, pass GDK_SCROLL_SMOOTH anyway
|
||||
case "windows":
|
||||
return 0x020e; // WM_MOUSEHWHEEL
|
||||
case "mac":
|
||||
return 0; // value is unused, can be anything
|
||||
case "linux":
|
||||
return 4; // value is unused, pass GDK_SCROLL_SMOOTH anyway
|
||||
}
|
||||
throw new Error("Native wheel events not supported on platform " + getPlatform());
|
||||
throw new Error(
|
||||
"Native wheel events not supported on platform " + getPlatform()
|
||||
);
|
||||
}
|
||||
|
||||
// Given an event target which may be a window or an element, get the associated window.
|
||||
|
|
@ -72,7 +82,9 @@ function nativeScrollUnits(aTarget, aDimen) {
|
|||
// GTK deltas are treated as line height divided by 3 by gecko.
|
||||
var targetWindow = windowForTarget(aTarget);
|
||||
var targetElement = elementForTarget(aTarget);
|
||||
var lineHeight = targetWindow.getComputedStyle(targetElement)["font-size"];
|
||||
var lineHeight = targetWindow.getComputedStyle(targetElement)[
|
||||
"font-size"
|
||||
];
|
||||
return aDimen / (parseInt(lineHeight) * 3);
|
||||
}
|
||||
}
|
||||
|
|
@ -81,38 +93,57 @@ function nativeScrollUnits(aTarget, aDimen) {
|
|||
|
||||
function nativeMouseDownEventMsg() {
|
||||
switch (getPlatform()) {
|
||||
case "windows": return 2; // MOUSEEVENTF_LEFTDOWN
|
||||
case "mac": return 1; // NSLeftMouseDown
|
||||
case "linux": return 4; // GDK_BUTTON_PRESS
|
||||
case "android": return 5; // ACTION_POINTER_DOWN
|
||||
case "windows":
|
||||
return 2; // MOUSEEVENTF_LEFTDOWN
|
||||
case "mac":
|
||||
return 1; // NSLeftMouseDown
|
||||
case "linux":
|
||||
return 4; // GDK_BUTTON_PRESS
|
||||
case "android":
|
||||
return 5; // ACTION_POINTER_DOWN
|
||||
}
|
||||
throw new Error("Native mouse-down events not supported on platform " + getPlatform());
|
||||
throw new Error(
|
||||
"Native mouse-down events not supported on platform " + getPlatform()
|
||||
);
|
||||
}
|
||||
|
||||
function nativeMouseMoveEventMsg() {
|
||||
switch (getPlatform()) {
|
||||
case "windows": return 1; // MOUSEEVENTF_MOVE
|
||||
case "mac": return 5; // NSMouseMoved
|
||||
case "linux": return 3; // GDK_MOTION_NOTIFY
|
||||
case "android": return 7; // ACTION_HOVER_MOVE
|
||||
case "windows":
|
||||
return 1; // MOUSEEVENTF_MOVE
|
||||
case "mac":
|
||||
return 5; // NSMouseMoved
|
||||
case "linux":
|
||||
return 3; // GDK_MOTION_NOTIFY
|
||||
case "android":
|
||||
return 7; // ACTION_HOVER_MOVE
|
||||
}
|
||||
throw new Error("Native mouse-move events not supported on platform " + getPlatform());
|
||||
throw new Error(
|
||||
"Native mouse-move events not supported on platform " + getPlatform()
|
||||
);
|
||||
}
|
||||
|
||||
function nativeMouseUpEventMsg() {
|
||||
switch (getPlatform()) {
|
||||
case "windows": return 4; // MOUSEEVENTF_LEFTUP
|
||||
case "mac": return 2; // NSLeftMouseUp
|
||||
case "linux": return 7; // GDK_BUTTON_RELEASE
|
||||
case "android": return 6; // ACTION_POINTER_UP
|
||||
case "windows":
|
||||
return 4; // MOUSEEVENTF_LEFTUP
|
||||
case "mac":
|
||||
return 2; // NSLeftMouseUp
|
||||
case "linux":
|
||||
return 7; // GDK_BUTTON_RELEASE
|
||||
case "android":
|
||||
return 6; // ACTION_POINTER_UP
|
||||
}
|
||||
throw new Error("Native mouse-up events not supported on platform " + getPlatform());
|
||||
throw new Error(
|
||||
"Native mouse-up events not supported on platform " + getPlatform()
|
||||
);
|
||||
}
|
||||
|
||||
function getBoundingClientRectRelativeToVisualViewport(aElement) {
|
||||
let utils = SpecialPowers.getDOMWindowUtils(window);
|
||||
var rect = aElement.getBoundingClientRect();
|
||||
var offsetX = {}, offsetY = {};
|
||||
var offsetX = {},
|
||||
offsetY = {};
|
||||
// TODO: Audit whether these offset values are correct or not for
|
||||
// position:fixed elements especially in the case where the visual viewport
|
||||
// offset is not 0.
|
||||
|
|
@ -135,14 +166,19 @@ function coordinatesRelativeToScreen(aX, aY, aTarget) {
|
|||
var targetWindow = windowForTarget(aTarget);
|
||||
var deviceScale = targetWindow.devicePixelRatio;
|
||||
var resolution = getResolution();
|
||||
var rect = (aTarget instanceof Window)
|
||||
? {left: 0, top: 0} /* we don't use the width or height */
|
||||
: getBoundingClientRectRelativeToVisualViewport(aTarget);
|
||||
var rect =
|
||||
aTarget instanceof Window
|
||||
? { left: 0, top: 0 } /* we don't use the width or height */
|
||||
: getBoundingClientRectRelativeToVisualViewport(aTarget);
|
||||
// moxInnerScreen{X,Y} are in CSS coordinates of the browser chrome.
|
||||
// The device scale applies to them, but the resolution only zooms the content.
|
||||
return {
|
||||
x: (targetWindow.mozInnerScreenX + ((rect.left + aX) * resolution)) * deviceScale,
|
||||
y: (targetWindow.mozInnerScreenY + ((rect.top + aY) * resolution)) * deviceScale,
|
||||
x:
|
||||
(targetWindow.mozInnerScreenX + (rect.left + aX) * resolution) *
|
||||
deviceScale,
|
||||
y:
|
||||
(targetWindow.mozInnerScreenY + (rect.top + aY) * resolution) *
|
||||
deviceScale,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -155,8 +191,8 @@ function rectRelativeToScreen(aElement) {
|
|||
return {
|
||||
x: (targetWindow.mozInnerScreenX + rect.left) * scale,
|
||||
y: (targetWindow.mozInnerScreenY + rect.top) * scale,
|
||||
w: (rect.width * scale),
|
||||
h: (rect.height * scale),
|
||||
w: rect.width * scale,
|
||||
h: rect.height * scale,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -169,14 +205,29 @@ function rectRelativeToScreen(aElement) {
|
|||
function synthesizeNativeWheel(aTarget, aX, aY, aDeltaX, aDeltaY, aObserver) {
|
||||
var pt = coordinatesRelativeToScreen(aX, aY, aTarget);
|
||||
if (aDeltaX && aDeltaY) {
|
||||
throw new Error("Simultaneous wheeling of horizontal and vertical is not supported on all platforms.");
|
||||
throw new Error(
|
||||
"Simultaneous wheeling of horizontal and vertical is not supported on all platforms."
|
||||
);
|
||||
}
|
||||
aDeltaX = nativeScrollUnits(aTarget, aDeltaX);
|
||||
aDeltaY = nativeScrollUnits(aTarget, aDeltaY);
|
||||
var msg = aDeltaX ? nativeHorizontalWheelEventMsg() : nativeVerticalWheelEventMsg();
|
||||
var msg = aDeltaX
|
||||
? nativeHorizontalWheelEventMsg()
|
||||
: nativeVerticalWheelEventMsg();
|
||||
var utils = utilsForTarget(aTarget);
|
||||
var element = elementForTarget(aTarget);
|
||||
utils.sendNativeMouseScrollEvent(pt.x, pt.y, msg, aDeltaX, aDeltaY, 0, 0, 0, element, aObserver);
|
||||
utils.sendNativeMouseScrollEvent(
|
||||
pt.x,
|
||||
pt.y,
|
||||
msg,
|
||||
aDeltaX,
|
||||
aDeltaY,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
element,
|
||||
aObserver
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -184,7 +235,14 @@ function synthesizeNativeWheel(aTarget, aX, aY, aDeltaX, aDeltaY, aObserver) {
|
|||
// request has been successfully made to the OS. This does not necessarily
|
||||
// guarantee that the OS generates the event we requested. See
|
||||
// synthesizeNativeWheel for details on the parameters.
|
||||
function synthesizeNativeWheelAndWaitForObserver(aElement, aX, aY, aDeltaX, aDeltaY, aCallback) {
|
||||
function synthesizeNativeWheelAndWaitForObserver(
|
||||
aElement,
|
||||
aX,
|
||||
aY,
|
||||
aDeltaX,
|
||||
aDeltaY,
|
||||
aCallback
|
||||
) {
|
||||
var observer = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (aCallback && aTopic == "mousescrollevent") {
|
||||
|
|
@ -200,11 +258,22 @@ function synthesizeNativeWheelAndWaitForObserver(aElement, aX, aY, aDeltaX, aDel
|
|||
// targets content in a subdocument, |aTarget| should be inside the
|
||||
// subdocument (or the subdocument's window). See synthesizeNativeWheel for
|
||||
// details on the other parameters.
|
||||
function synthesizeNativeWheelAndWaitForWheelEvent(aTarget, aX, aY, aDeltaX, aDeltaY, aCallback) {
|
||||
function synthesizeNativeWheelAndWaitForWheelEvent(
|
||||
aTarget,
|
||||
aX,
|
||||
aY,
|
||||
aDeltaX,
|
||||
aDeltaY,
|
||||
aCallback
|
||||
) {
|
||||
var targetWindow = windowForTarget(aTarget);
|
||||
targetWindow.addEventListener("wheel", function(e) {
|
||||
setTimeout(aCallback, 0);
|
||||
}, {once: true});
|
||||
targetWindow.addEventListener(
|
||||
"wheel",
|
||||
function(e) {
|
||||
setTimeout(aCallback, 0);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
return synthesizeNativeWheel(aTarget, aX, aY, aDeltaX, aDeltaY);
|
||||
}
|
||||
|
||||
|
|
@ -213,11 +282,22 @@ function synthesizeNativeWheelAndWaitForWheelEvent(aTarget, aX, aY, aDeltaX, aDe
|
|||
// If the event targets content in a subdocument, |aTarget| should be inside
|
||||
// the subdocument (or the subdocument's window). See synthesizeNativeWheel
|
||||
// for details on the other parameters.
|
||||
function synthesizeNativeWheelAndWaitForScrollEvent(aTarget, aX, aY, aDeltaX, aDeltaY, aCallback) {
|
||||
function synthesizeNativeWheelAndWaitForScrollEvent(
|
||||
aTarget,
|
||||
aX,
|
||||
aY,
|
||||
aDeltaX,
|
||||
aDeltaY,
|
||||
aCallback
|
||||
) {
|
||||
var targetWindow = windowForTarget(aTarget);
|
||||
targetWindow.addEventListener("scroll", function() {
|
||||
setTimeout(aCallback, 0);
|
||||
}, {capture: true, once: true}); // scroll events don't always bubble
|
||||
targetWindow.addEventListener(
|
||||
"scroll",
|
||||
function() {
|
||||
setTimeout(aCallback, 0);
|
||||
},
|
||||
{ capture: true, once: true }
|
||||
); // scroll events don't always bubble
|
||||
return synthesizeNativeWheel(aTarget, aX, aY, aDeltaX, aDeltaY);
|
||||
}
|
||||
|
||||
|
|
@ -236,17 +316,33 @@ function synthesizeNativeMouseMove(aTarget, aX, aY) {
|
|||
// targets content in a subdocument, |aTarget| should be inside the
|
||||
// subdocument (or the subdocument window). See synthesizeNativeMouseMove for
|
||||
// details on the other parameters.
|
||||
function synthesizeNativeMouseMoveAndWaitForMoveEvent(aTarget, aX, aY, aCallback) {
|
||||
function synthesizeNativeMouseMoveAndWaitForMoveEvent(
|
||||
aTarget,
|
||||
aX,
|
||||
aY,
|
||||
aCallback
|
||||
) {
|
||||
var targetWindow = windowForTarget(aTarget);
|
||||
targetWindow.addEventListener("mousemove", function(e) {
|
||||
setTimeout(aCallback, 0);
|
||||
}, {once: true});
|
||||
targetWindow.addEventListener(
|
||||
"mousemove",
|
||||
function(e) {
|
||||
setTimeout(aCallback, 0);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
return synthesizeNativeMouseMove(aTarget, aX, aY);
|
||||
}
|
||||
|
||||
// Synthesizes a native touch event and dispatches it. aX and aY in CSS pixels
|
||||
// relative to the top-left of |aTarget|'s bounding rect.
|
||||
function synthesizeNativeTouch(aTarget, aX, aY, aType, aObserver = null, aTouchId = 0) {
|
||||
function synthesizeNativeTouch(
|
||||
aTarget,
|
||||
aX,
|
||||
aY,
|
||||
aType,
|
||||
aObserver = null,
|
||||
aTouchId = 0
|
||||
) {
|
||||
var pt = coordinatesRelativeToScreen(aX, aY, aTarget);
|
||||
var utils = utilsForTarget(aTarget);
|
||||
utils.sendNativeTouchPoint(aTouchId, aType, pt.x, pt.y, 1, 90, aObserver);
|
||||
|
|
@ -271,7 +367,12 @@ function synthesizeNativeTouch(aTarget, aX, aY, aType, aObserver = null, aTouchI
|
|||
// aObserver is the observer that will get registered on the very last
|
||||
// synthesizeNativeTouch call this function makes.
|
||||
// aTouchIds is an array holding the touch ID values of each "finger".
|
||||
function* synthesizeNativeTouchSequences(aTarget, aPositions, aObserver = null, aTouchIds = [0]) {
|
||||
function* synthesizeNativeTouchSequences(
|
||||
aTarget,
|
||||
aPositions,
|
||||
aObserver = null,
|
||||
aTouchIds = [0]
|
||||
) {
|
||||
// We use lastNonNullValue to figure out which synthesizeNativeTouch call
|
||||
// will be the last one we make, so that we can register aObserver on it.
|
||||
var lastNonNullValue = -1;
|
||||
|
|
@ -284,12 +385,14 @@ function* synthesizeNativeTouchSequences(aTarget, aPositions, aObserver = null,
|
|||
if (aPositions[i].length != aTouchIds.length) {
|
||||
throw new Error(
|
||||
`aPositions[${i}] did not have the expected number of positions; ` +
|
||||
`expected ${aTouchIds.length} touch points but found ${aPositions[i].length}`
|
||||
`expected ${aTouchIds.length} touch points but found ${
|
||||
aPositions[i].length
|
||||
}`
|
||||
);
|
||||
}
|
||||
for (let j = 0; j < aTouchIds.length; j++) {
|
||||
if (aPositions[i][j] != null) {
|
||||
lastNonNullValue = ((i - yields) * aTouchIds.length) + j;
|
||||
lastNonNullValue = (i - yields) * aTouchIds.length + j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -328,13 +431,27 @@ function* synthesizeNativeTouchSequences(aTarget, aPositions, aObserver = null,
|
|||
} else {
|
||||
// synthesize the touch-up. If this is the last call we're going to
|
||||
// make, pass the observer as well
|
||||
var thisIndex = ((i - yields) * aTouchIds.length) + j;
|
||||
var observer = (lastSynthesizeCall == thisIndex) ? aObserver : null;
|
||||
synthesizeNativeTouch(aTarget, currentPositions[j].x, currentPositions[j].y, SpecialPowers.DOMWindowUtils.TOUCH_REMOVE, observer, aTouchIds[j]);
|
||||
var thisIndex = (i - yields) * aTouchIds.length + j;
|
||||
var observer = lastSynthesizeCall == thisIndex ? aObserver : null;
|
||||
synthesizeNativeTouch(
|
||||
aTarget,
|
||||
currentPositions[j].x,
|
||||
currentPositions[j].y,
|
||||
SpecialPowers.DOMWindowUtils.TOUCH_REMOVE,
|
||||
observer,
|
||||
aTouchIds[j]
|
||||
);
|
||||
currentPositions[j] = null;
|
||||
}
|
||||
} else {
|
||||
synthesizeNativeTouch(aTarget, aPositions[i][j].x, aPositions[i][j].y, SpecialPowers.DOMWindowUtils.TOUCH_CONTACT, null, aTouchIds[j]);
|
||||
synthesizeNativeTouch(
|
||||
aTarget,
|
||||
aPositions[i][j].x,
|
||||
aPositions[i][j].y,
|
||||
SpecialPowers.DOMWindowUtils.TOUCH_CONTACT,
|
||||
null,
|
||||
aTouchIds[j]
|
||||
);
|
||||
currentPositions[j] = aPositions[i][j];
|
||||
}
|
||||
}
|
||||
|
|
@ -345,7 +462,15 @@ function* synthesizeNativeTouchSequences(aTarget, aPositions, aObserver = null,
|
|||
// Note that when calling this function you'll want to make sure that the pref
|
||||
// "apz.touch_start_tolerance" is set to 0, or some of the touchmove will get
|
||||
// consumed to overcome the panning threshold.
|
||||
function synthesizeNativeTouchDrag(aTarget, aX, aY, aDeltaX, aDeltaY, aObserver = null, aTouchId = 0) {
|
||||
function synthesizeNativeTouchDrag(
|
||||
aTarget,
|
||||
aX,
|
||||
aY,
|
||||
aDeltaX,
|
||||
aDeltaY,
|
||||
aObserver = null,
|
||||
aTouchId = 0
|
||||
) {
|
||||
var steps = Math.max(Math.abs(aDeltaX), Math.abs(aDeltaY));
|
||||
var positions = [[{ x: aX, y: aY }]];
|
||||
for (var i = 1; i < steps; i++) {
|
||||
|
|
@ -355,7 +480,12 @@ function synthesizeNativeTouchDrag(aTarget, aX, aY, aDeltaX, aDeltaY, aObserver
|
|||
positions.push([pos]);
|
||||
}
|
||||
positions.push([{ x: aX + aDeltaX, y: aY + aDeltaY }]);
|
||||
var continuation = synthesizeNativeTouchSequences(aTarget, positions, aObserver, [aTouchId]);
|
||||
var continuation = synthesizeNativeTouchSequences(
|
||||
aTarget,
|
||||
positions,
|
||||
aObserver,
|
||||
[aTouchId]
|
||||
);
|
||||
var yielded = continuation.next();
|
||||
while (!yielded.done) {
|
||||
yielded = continuation.next();
|
||||
|
|
@ -365,7 +495,9 @@ function synthesizeNativeTouchDrag(aTarget, aX, aY, aDeltaX, aDeltaY, aObserver
|
|||
|
||||
function synthesizeNativeTap(aElement, aX, aY, aObserver = null) {
|
||||
var pt = coordinatesRelativeToScreen(aX, aY, aElement);
|
||||
var utils = SpecialPowers.getDOMWindowUtils(aElement.ownerDocument.defaultView);
|
||||
var utils = SpecialPowers.getDOMWindowUtils(
|
||||
aElement.ownerDocument.defaultView
|
||||
);
|
||||
utils.sendNativeTouchTap(pt.x, pt.y, false, aObserver);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -380,10 +512,26 @@ function synthesizeNativeMouseEvent(aTarget, aX, aY, aType, aObserver = null) {
|
|||
|
||||
function synthesizeNativeClick(aElement, aX, aY, aObserver = null) {
|
||||
var pt = coordinatesRelativeToScreen(aX, aY, aElement);
|
||||
var utils = SpecialPowers.getDOMWindowUtils(aElement.ownerDocument.defaultView);
|
||||
utils.sendNativeMouseEvent(pt.x, pt.y, nativeMouseDownEventMsg(), 0, aElement, function() {
|
||||
utils.sendNativeMouseEvent(pt.x, pt.y, nativeMouseUpEventMsg(), 0, aElement, aObserver);
|
||||
});
|
||||
var utils = SpecialPowers.getDOMWindowUtils(
|
||||
aElement.ownerDocument.defaultView
|
||||
);
|
||||
utils.sendNativeMouseEvent(
|
||||
pt.x,
|
||||
pt.y,
|
||||
nativeMouseDownEventMsg(),
|
||||
0,
|
||||
aElement,
|
||||
function() {
|
||||
utils.sendNativeMouseEvent(
|
||||
pt.x,
|
||||
pt.y,
|
||||
nativeMouseUpEventMsg(),
|
||||
0,
|
||||
aElement,
|
||||
aObserver
|
||||
);
|
||||
}
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -395,20 +543,50 @@ function synthesizeNativeClick(aElement, aX, aY, aObserver = null) {
|
|||
// We also wait for the mouse move event to be processed before sending the
|
||||
// wheel event, otherwise there is a chance they might get reordered, and
|
||||
// we have the transaction problem again.
|
||||
function moveMouseAndScrollWheelOver(target, dx, dy, testDriver, waitForScroll = true) {
|
||||
return synthesizeNativeMouseMoveAndWaitForMoveEvent(target, dx, dy, function() {
|
||||
if (waitForScroll) {
|
||||
synthesizeNativeWheelAndWaitForScrollEvent(target, dx, dy, 0, -10, testDriver);
|
||||
} else {
|
||||
synthesizeNativeWheelAndWaitForWheelEvent(target, dx, dy, 0, -10, testDriver);
|
||||
function moveMouseAndScrollWheelOver(
|
||||
target,
|
||||
dx,
|
||||
dy,
|
||||
testDriver,
|
||||
waitForScroll = true
|
||||
) {
|
||||
return synthesizeNativeMouseMoveAndWaitForMoveEvent(
|
||||
target,
|
||||
dx,
|
||||
dy,
|
||||
function() {
|
||||
if (waitForScroll) {
|
||||
synthesizeNativeWheelAndWaitForScrollEvent(
|
||||
target,
|
||||
dx,
|
||||
dy,
|
||||
0,
|
||||
-10,
|
||||
testDriver
|
||||
);
|
||||
} else {
|
||||
synthesizeNativeWheelAndWaitForWheelEvent(
|
||||
target,
|
||||
dx,
|
||||
dy,
|
||||
0,
|
||||
-10,
|
||||
testDriver
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
// Same as moveMouseAndScrollWheelOver, but returns a promise instead of taking
|
||||
// a callback function. Eventually we should convert all these callback-taking
|
||||
// functions into promise-producing functions but for now this is a stopgap.
|
||||
function promiseMoveMouseAndScrollWheelOver(target, dx, dy, waitForScroll = true) {
|
||||
function promiseMoveMouseAndScrollWheelOver(
|
||||
target,
|
||||
dx,
|
||||
dy,
|
||||
waitForScroll = true
|
||||
) {
|
||||
return new Promise(resolve => {
|
||||
moveMouseAndScrollWheelOver(target, dx, dy, resolve, waitForScroll);
|
||||
});
|
||||
|
|
@ -425,9 +603,15 @@ function promiseMoveMouseAndScrollWheelOver(target, dx, dy, waitForScroll = true
|
|||
// Note: helper_scrollbar_snap_bug1501062.html contains a copy of this code
|
||||
// with modifications. Fixes here should be copied there if appropriate.
|
||||
// |target| can be an element (for subframes) or a window (for root frames).
|
||||
function* dragVerticalScrollbar(target, testDriver, distance = 20, increment = 5) {
|
||||
function* dragVerticalScrollbar(
|
||||
target,
|
||||
testDriver,
|
||||
distance = 20,
|
||||
increment = 5
|
||||
) {
|
||||
var targetElement = elementForTarget(target);
|
||||
var w = {}, h = {};
|
||||
var w = {},
|
||||
h = {};
|
||||
utilsForTarget(target).getScrollbarSizes(targetElement, w, h);
|
||||
var verticalScrollbarWidth = w.value;
|
||||
if (verticalScrollbarWidth == 0) {
|
||||
|
|
@ -435,24 +619,62 @@ function* dragVerticalScrollbar(target, testDriver, distance = 20, increment = 5
|
|||
}
|
||||
|
||||
var upArrowHeight = verticalScrollbarWidth; // assume square scrollbar buttons
|
||||
var mouseX = targetElement.clientWidth + (verticalScrollbarWidth / 2);
|
||||
var mouseX = targetElement.clientWidth + verticalScrollbarWidth / 2;
|
||||
var mouseY = upArrowHeight + 5; // start dragging somewhere in the thumb
|
||||
|
||||
dump("Starting drag at " + mouseX + ", " + mouseY + " from top-left of #" + targetElement.id + "\n");
|
||||
dump(
|
||||
"Starting drag at " +
|
||||
mouseX +
|
||||
", " +
|
||||
mouseY +
|
||||
" from top-left of #" +
|
||||
targetElement.id +
|
||||
"\n"
|
||||
);
|
||||
|
||||
// Move the mouse to the scrollbar thumb and drag it down
|
||||
yield synthesizeNativeMouseEvent(target, mouseX, mouseY, nativeMouseMoveEventMsg(), testDriver);
|
||||
yield synthesizeNativeMouseEvent(
|
||||
target,
|
||||
mouseX,
|
||||
mouseY,
|
||||
nativeMouseMoveEventMsg(),
|
||||
testDriver
|
||||
);
|
||||
// mouse down
|
||||
yield synthesizeNativeMouseEvent(target, mouseX, mouseY, nativeMouseDownEventMsg(), testDriver);
|
||||
yield synthesizeNativeMouseEvent(
|
||||
target,
|
||||
mouseX,
|
||||
mouseY,
|
||||
nativeMouseDownEventMsg(),
|
||||
testDriver
|
||||
);
|
||||
// drag vertically by |increment| until we reach the specified distance
|
||||
for (var y = increment; y < distance; y += increment) {
|
||||
yield synthesizeNativeMouseEvent(target, mouseX, mouseY + y, nativeMouseMoveEventMsg(), testDriver);
|
||||
yield synthesizeNativeMouseEvent(
|
||||
target,
|
||||
mouseX,
|
||||
mouseY + y,
|
||||
nativeMouseMoveEventMsg(),
|
||||
testDriver
|
||||
);
|
||||
}
|
||||
yield synthesizeNativeMouseEvent(target, mouseX, mouseY + distance, nativeMouseMoveEventMsg(), testDriver);
|
||||
yield synthesizeNativeMouseEvent(
|
||||
target,
|
||||
mouseX,
|
||||
mouseY + distance,
|
||||
nativeMouseMoveEventMsg(),
|
||||
testDriver
|
||||
);
|
||||
|
||||
// and return a generator to call afterwards to finish up the drag
|
||||
return function* () {
|
||||
return function*() {
|
||||
dump("Finishing drag of #" + targetElement.id + "\n");
|
||||
yield synthesizeNativeMouseEvent(target, mouseX, mouseY + distance, nativeMouseUpEventMsg(), testDriver);
|
||||
yield synthesizeNativeMouseEvent(
|
||||
target,
|
||||
mouseX,
|
||||
mouseY + distance,
|
||||
nativeMouseUpEventMsg(),
|
||||
testDriver
|
||||
);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,35 +24,55 @@ function convertEntries(entries) {
|
|||
function parseRect(str) {
|
||||
var pieces = str.replace(/[()\s]+/g, "").split(",");
|
||||
SimpleTest.is(pieces.length, 4, "expected string of form (x,y,w,h)");
|
||||
return { x: parseInt(pieces[0]),
|
||||
y: parseInt(pieces[1]),
|
||||
w: parseInt(pieces[2]),
|
||||
h: parseInt(pieces[3]) };
|
||||
return {
|
||||
x: parseInt(pieces[0]),
|
||||
y: parseInt(pieces[1]),
|
||||
w: parseInt(pieces[2]),
|
||||
h: parseInt(pieces[3]),
|
||||
};
|
||||
}
|
||||
|
||||
// These functions expect rects with fields named x/y/w/h, such as
|
||||
// that returned by parseRect().
|
||||
function rectContains(haystack, needle) {
|
||||
return haystack.x <= needle.x
|
||||
&& haystack.y <= needle.y
|
||||
&& (haystack.x + haystack.w) >= (needle.x + needle.w)
|
||||
&& (haystack.y + haystack.h) >= (needle.y + needle.h);
|
||||
return (
|
||||
haystack.x <= needle.x &&
|
||||
haystack.y <= needle.y &&
|
||||
haystack.x + haystack.w >= needle.x + needle.w &&
|
||||
haystack.y + haystack.h >= needle.y + needle.h
|
||||
);
|
||||
}
|
||||
function rectToString(rect) {
|
||||
return "(" + rect.x + "," + rect.y + "," + rect.w + "," + rect.h + ")";
|
||||
}
|
||||
function assertRectContainment(haystackRect, haystackDesc, needleRect, needleDesc) {
|
||||
SimpleTest.ok(rectContains(haystackRect, needleRect),
|
||||
haystackDesc + " " + rectToString(haystackRect) + " should contain " +
|
||||
needleDesc + " " + rectToString(needleRect));
|
||||
function assertRectContainment(
|
||||
haystackRect,
|
||||
haystackDesc,
|
||||
needleRect,
|
||||
needleDesc
|
||||
) {
|
||||
SimpleTest.ok(
|
||||
rectContains(haystackRect, needleRect),
|
||||
haystackDesc +
|
||||
" " +
|
||||
rectToString(haystackRect) +
|
||||
" should contain " +
|
||||
needleDesc +
|
||||
" " +
|
||||
rectToString(needleRect)
|
||||
);
|
||||
}
|
||||
|
||||
function getPropertyAsRect(scrollFrames, scrollId, prop) {
|
||||
SimpleTest.ok(scrollId in scrollFrames,
|
||||
"expected scroll frame data for scroll id " + scrollId);
|
||||
SimpleTest.ok(
|
||||
scrollId in scrollFrames,
|
||||
"expected scroll frame data for scroll id " + scrollId
|
||||
);
|
||||
var scrollFrameData = scrollFrames[scrollId];
|
||||
SimpleTest.ok("displayport" in scrollFrameData,
|
||||
"expected a " + prop + " for scroll id " + scrollId);
|
||||
SimpleTest.ok(
|
||||
"displayport" in scrollFrameData,
|
||||
"expected a " + prop + " for scroll id " + scrollId
|
||||
);
|
||||
var value = scrollFrameData[prop];
|
||||
return parseRect(value);
|
||||
}
|
||||
|
|
@ -68,7 +88,9 @@ function convertScrollFrameData(scrollFrames) {
|
|||
function convertBuckets(buckets) {
|
||||
var result = {};
|
||||
for (var i = 0; i < buckets.length; ++i) {
|
||||
result[buckets[i].sequenceNumber] = convertScrollFrameData(buckets[i].scrollFrames);
|
||||
result[buckets[i].sequenceNumber] = convertScrollFrameData(
|
||||
buckets[i].scrollFrames
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
@ -94,14 +116,20 @@ function getLastNonemptyBucket(buckets) {
|
|||
|
||||
// Takes something like "matrix(1, 0, 0, 1, 234.024, 528.29023)"" and returns a number array
|
||||
function parseTransform(transform) {
|
||||
return /matrix\((.*),(.*),(.*),(.*),(.*),(.*)\)/.exec(transform)
|
||||
.slice(1).map(parseFloat);
|
||||
return /matrix\((.*),(.*),(.*),(.*),(.*),(.*)\)/
|
||||
.exec(transform)
|
||||
.slice(1)
|
||||
.map(parseFloat);
|
||||
}
|
||||
|
||||
function isTransformClose(a, b, name) {
|
||||
is(a.length, b.length, `expected transforms ${a} and ${b} to be the same length`);
|
||||
is(
|
||||
a.length,
|
||||
b.length,
|
||||
`expected transforms ${a} and ${b} to be the same length`
|
||||
);
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
ok(Math.abs(a[i] - b[i]) < .01, name);
|
||||
ok(Math.abs(a[i] - b[i]) < 0.01, name);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -115,7 +143,7 @@ function buildApzcTree(paint) {
|
|||
// The APZC tree can potentially have multiple root nodes,
|
||||
// so we invent a node that is the parent of all roots.
|
||||
// This 'root' does not correspond to an APZC.
|
||||
var root = {scrollId: -1, children: []};
|
||||
var root = { scrollId: -1, children: [] };
|
||||
for (let scrollId in paint) {
|
||||
paint[scrollId].children = [];
|
||||
paint[scrollId].scrollId = scrollId;
|
||||
|
|
@ -135,7 +163,8 @@ function buildApzcTree(paint) {
|
|||
// Given an APZC tree produced by buildApzcTree, return the RCD node in
|
||||
// the tree, or null if there was none.
|
||||
function findRcdNode(apzcTree) {
|
||||
if (apzcTree.isRootContent) { // isRootContent will be undefined or "1"
|
||||
if (apzcTree.isRootContent) {
|
||||
// isRootContent will be undefined or "1"
|
||||
return apzcTree;
|
||||
}
|
||||
for (var i = 0; i < apzcTree.children.length; i++) {
|
||||
|
|
@ -151,7 +180,9 @@ function findRcdNode(apzcTree) {
|
|||
// Assumes |elementId| will be present in the content description for the
|
||||
// element, and not in the content descriptions of other elements.
|
||||
function isLayerized(elementId) {
|
||||
var contentTestData = SpecialPowers.getDOMWindowUtils(window).getContentAPZTestData();
|
||||
var contentTestData = SpecialPowers.getDOMWindowUtils(
|
||||
window
|
||||
).getContentAPZTestData();
|
||||
var nonEmptyBucket = getLastNonemptyBucket(contentTestData.paints);
|
||||
ok(nonEmptyBucket != null, "expected at least one nonempty paint");
|
||||
var seqno = nonEmptyBucket.sequenceNumber;
|
||||
|
|
@ -170,14 +201,19 @@ function isLayerized(elementId) {
|
|||
function promiseApzRepaintsFlushed(aWindow = window) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var repaintDone = function() {
|
||||
SpecialPowers.Services.obs.removeObserver(repaintDone, "apz-repaints-flushed");
|
||||
SpecialPowers.Services.obs.removeObserver(
|
||||
repaintDone,
|
||||
"apz-repaints-flushed"
|
||||
);
|
||||
setTimeout(resolve, 0);
|
||||
};
|
||||
SpecialPowers.Services.obs.addObserver(repaintDone, "apz-repaints-flushed");
|
||||
if (SpecialPowers.getDOMWindowUtils(aWindow).flushApzRepaints()) {
|
||||
dump("Flushed APZ repaints, waiting for callback...\n");
|
||||
} else {
|
||||
dump("Flushing APZ repaints was a no-op, triggering callback directly...\n");
|
||||
dump(
|
||||
"Flushing APZ repaints was a no-op, triggering callback directly...\n"
|
||||
);
|
||||
repaintDone();
|
||||
}
|
||||
});
|
||||
|
|
@ -248,18 +284,24 @@ function runSubtestsSeriallyInFreshWindows(aSubtests) {
|
|||
|
||||
// If the "apz.subtest" pref has been set, only a single subtest whose name matches
|
||||
// the pref's value (if any) will be run.
|
||||
var onlyOneSubtest = SpecialPowers.getCharPref("apz.subtest", /* default = */ "");
|
||||
var onlyOneSubtest = SpecialPowers.getCharPref(
|
||||
"apz.subtest",
|
||||
/* default = */ ""
|
||||
);
|
||||
|
||||
function advanceSubtestExecution() {
|
||||
var test = aSubtests[testIndex];
|
||||
if (w) {
|
||||
// Run any cleanup functions registered in the subtest
|
||||
if (w.ApzCleanup) { // guard against the subtest not loading apz_test_utils.js
|
||||
if (w.ApzCleanup) {
|
||||
// guard against the subtest not loading apz_test_utils.js
|
||||
w.ApzCleanup.execute();
|
||||
}
|
||||
if (typeof test.dp_suppression != "undefined") {
|
||||
// We modified the suppression when starting the test, so now undo that.
|
||||
SpecialPowers.getDOMWindowUtils(window).respectDisplayPortSuppression(!test.dp_suppression);
|
||||
SpecialPowers.getDOMWindowUtils(window).respectDisplayPortSuppression(
|
||||
!test.dp_suppression
|
||||
);
|
||||
}
|
||||
if (test.prefs) {
|
||||
// We pushed some prefs for this test, pop them, and re-invoke
|
||||
|
|
@ -286,15 +328,29 @@ function runSubtestsSeriallyInFreshWindows(aSubtests) {
|
|||
let recognizedProps = ["file", "prefs", "dp_suppression", "onload"];
|
||||
for (let prop in test) {
|
||||
if (!recognizedProps.includes(prop)) {
|
||||
SimpleTest.ok(false, "Subtest " + test.file + " has unrecognized property '" + prop + "'");
|
||||
setTimeout(function() { advanceSubtestExecution(); }, 0);
|
||||
SimpleTest.ok(
|
||||
false,
|
||||
"Subtest " + test.file + " has unrecognized property '" + prop + "'"
|
||||
);
|
||||
setTimeout(function() {
|
||||
advanceSubtestExecution();
|
||||
}, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (onlyOneSubtest && onlyOneSubtest != test.file) {
|
||||
SimpleTest.ok(true, "Skipping " + test.file + " because only " + onlyOneSubtest + " is being run");
|
||||
setTimeout(function() { advanceSubtestExecution(); }, 0);
|
||||
SimpleTest.ok(
|
||||
true,
|
||||
"Skipping " +
|
||||
test.file +
|
||||
" because only " +
|
||||
onlyOneSubtest +
|
||||
" is being run"
|
||||
);
|
||||
setTimeout(function() {
|
||||
advanceSubtestExecution();
|
||||
}, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -306,7 +362,9 @@ function runSubtestsSeriallyInFreshWindows(aSubtests) {
|
|||
// unsuppression can trigger a repaint which interferes with the test, so
|
||||
// to avoid that we can force the displayport to be unsuppressed for the
|
||||
// entire test which is more deterministic.
|
||||
SpecialPowers.getDOMWindowUtils(window).respectDisplayPortSuppression(test.dp_suppression);
|
||||
SpecialPowers.getDOMWindowUtils(window).respectDisplayPortSuppression(
|
||||
test.dp_suppression
|
||||
);
|
||||
}
|
||||
|
||||
function spawnTest(aFile) {
|
||||
|
|
@ -314,21 +372,39 @@ function runSubtestsSeriallyInFreshWindows(aSubtests) {
|
|||
w.subtestDone = advanceSubtestExecution;
|
||||
w.isApzSubtest = true;
|
||||
w.SimpleTest = SimpleTest;
|
||||
w.dump = function(msg) { return dump(aFile + " | " + msg); };
|
||||
w.is = function(a, b, msg) { return is(a, b, aFile + " | " + msg); };
|
||||
w.isfuzzy = function(a, b, eps, msg) { return isfuzzy(a, b, eps, aFile + " | " + msg); };
|
||||
w.dump = function(msg) {
|
||||
return dump(aFile + " | " + msg);
|
||||
};
|
||||
w.is = function(a, b, msg) {
|
||||
return is(a, b, aFile + " | " + msg);
|
||||
};
|
||||
w.isfuzzy = function(a, b, eps, msg) {
|
||||
return isfuzzy(a, b, eps, aFile + " | " + msg);
|
||||
};
|
||||
w.ok = function(cond, msg) {
|
||||
arguments[1] = aFile + " | " + msg;
|
||||
// Forward all arguments to SimpleTest.ok where we will check that ok() was
|
||||
// called with at most 2 arguments.
|
||||
return SimpleTest.ok.apply(SimpleTest, arguments);
|
||||
};
|
||||
w.todo_is = function(a, b, msg) { return todo_is(a, b, aFile + " | " + msg); };
|
||||
w.todo = function(cond, msg) { return todo(cond, aFile + " | " + msg); };
|
||||
w.todo_is = function(a, b, msg) {
|
||||
return todo_is(a, b, aFile + " | " + msg);
|
||||
};
|
||||
w.todo = function(cond, msg) {
|
||||
return todo(cond, aFile + " | " + msg);
|
||||
};
|
||||
if (test.onload) {
|
||||
w.addEventListener("load", function(e) { test.onload(w); }, { once: true });
|
||||
w.addEventListener(
|
||||
"load",
|
||||
function(e) {
|
||||
test.onload(w);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
}
|
||||
var subtestUrl = location.href.substring(0, location.href.lastIndexOf("/") + 1) + aFile;
|
||||
var subtestUrl =
|
||||
location.href.substring(0, location.href.lastIndexOf("/") + 1) +
|
||||
aFile;
|
||||
function urlResolves(url) {
|
||||
var request = new XMLHttpRequest();
|
||||
request.open("GET", url, false);
|
||||
|
|
@ -336,8 +412,13 @@ function runSubtestsSeriallyInFreshWindows(aSubtests) {
|
|||
return request.status !== 404;
|
||||
}
|
||||
if (!urlResolves(subtestUrl)) {
|
||||
SimpleTest.ok(false, "Subtest URL " + subtestUrl + " does not resolve. " +
|
||||
"Be sure it's present in the support-files section of mochitest.ini.");
|
||||
SimpleTest.ok(
|
||||
false,
|
||||
"Subtest URL " +
|
||||
subtestUrl +
|
||||
" does not resolve. " +
|
||||
"Be sure it's present in the support-files section of mochitest.ini."
|
||||
);
|
||||
reject();
|
||||
return undefined;
|
||||
}
|
||||
|
|
@ -347,7 +428,7 @@ function runSubtestsSeriallyInFreshWindows(aSubtests) {
|
|||
|
||||
if (test.prefs) {
|
||||
// Got some prefs for this subtest, push them
|
||||
SpecialPowers.pushPrefEnv({"set": test.prefs}, function() {
|
||||
SpecialPowers.pushPrefEnv({ set: test.prefs }, function() {
|
||||
w = spawnTest(test.file);
|
||||
});
|
||||
} else {
|
||||
|
|
@ -362,7 +443,7 @@ function runSubtestsSeriallyInFreshWindows(aSubtests) {
|
|||
}
|
||||
|
||||
function pushPrefs(prefs) {
|
||||
return SpecialPowers.pushPrefEnv({"set": prefs});
|
||||
return SpecialPowers.pushPrefEnv({ set: prefs });
|
||||
}
|
||||
|
||||
async function waitUntilApzStable() {
|
||||
|
|
@ -379,7 +460,9 @@ async function waitUntilApzStable() {
|
|||
/* eslint-env mozilla/frame-script */
|
||||
function parentProcessFlush() {
|
||||
function apzFlush() {
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Services } = ChromeUtils.import(
|
||||
"resource://gre/modules/Services.jsm"
|
||||
);
|
||||
var topWin = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
if (!topWin) {
|
||||
topWin = Services.wm.getMostRecentWindow("navigator:geckoview");
|
||||
|
|
@ -393,15 +476,21 @@ async function waitUntilApzStable() {
|
|||
};
|
||||
var flushRepaint = function() {
|
||||
if (topUtils.isMozAfterPaintPending) {
|
||||
topWin.addEventListener("MozAfterPaint", flushRepaint, { once: true });
|
||||
topWin.addEventListener("MozAfterPaint", flushRepaint, {
|
||||
once: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Services.obs.addObserver(repaintDone, "apz-repaints-flushed");
|
||||
if (topUtils.flushApzRepaints()) {
|
||||
dump("Parent process: flushed APZ repaints, waiting for callback...\n");
|
||||
dump(
|
||||
"Parent process: flushed APZ repaints, waiting for callback...\n"
|
||||
);
|
||||
} else {
|
||||
dump("Parent process: flushing APZ repaints was a no-op, triggering callback directly...\n");
|
||||
dump(
|
||||
"Parent process: flushing APZ repaints was a no-op, triggering callback directly...\n"
|
||||
);
|
||||
repaintDone();
|
||||
}
|
||||
};
|
||||
|
|
@ -420,7 +509,9 @@ async function waitUntilApzStable() {
|
|||
|
||||
// This is the first time waitUntilApzStable is being called, do initialization
|
||||
if (typeof waitUntilApzStable.chromeHelper == "undefined") {
|
||||
waitUntilApzStable.chromeHelper = SpecialPowers.loadChromeScript(parentProcessFlush);
|
||||
waitUntilApzStable.chromeHelper = SpecialPowers.loadChromeScript(
|
||||
parentProcessFlush
|
||||
);
|
||||
ApzCleanup.register(() => {
|
||||
waitUntilApzStable.chromeHelper.sendAsyncMessage("cleanup", null);
|
||||
waitUntilApzStable.chromeHelper.destroy();
|
||||
|
|
@ -510,7 +601,10 @@ function runContinuation(testFunction) {
|
|||
try {
|
||||
driveTest();
|
||||
} catch (ex) {
|
||||
SimpleTest.ok(false, "APZ test continuation failed with exception: " + ex);
|
||||
SimpleTest.ok(
|
||||
false,
|
||||
"APZ test continuation failed with exception: " + ex
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
@ -527,7 +621,10 @@ function runAsyncContinuation(testFunction) {
|
|||
ret = await asyncContinuation.next();
|
||||
}
|
||||
} catch (ex) {
|
||||
SimpleTest.ok(false, "APZ async test continuation failed with exception: " + ex);
|
||||
SimpleTest.ok(
|
||||
false,
|
||||
"APZ async test continuation failed with exception: " + ex
|
||||
);
|
||||
throw ex;
|
||||
}
|
||||
};
|
||||
|
|
@ -551,7 +648,9 @@ function runAsyncContinuation(testFunction) {
|
|||
function getSnapshot(rect) {
|
||||
function parentProcessSnapshot() {
|
||||
addMessageListener("snapshot", function(parentRect) {
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Services } = ChromeUtils.import(
|
||||
"resource://gre/modules/Services.jsm"
|
||||
);
|
||||
var topWin = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
if (!topWin) {
|
||||
topWin = Services.wm.getMostRecentWindow("navigator:geckoview");
|
||||
|
|
@ -563,21 +662,36 @@ function getSnapshot(rect) {
|
|||
parentRect.y -= topWin.mozInnerScreenY;
|
||||
|
||||
// take the snapshot
|
||||
var canvas = topWin.document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
|
||||
var canvas = topWin.document.createElementNS(
|
||||
"http://www.w3.org/1999/xhtml",
|
||||
"canvas"
|
||||
);
|
||||
canvas.width = parentRect.w;
|
||||
canvas.height = parentRect.h;
|
||||
var ctx = canvas.getContext("2d");
|
||||
ctx.drawWindow(topWin, parentRect.x, parentRect.y, parentRect.w, parentRect.h,
|
||||
ctx.drawWindow(
|
||||
topWin,
|
||||
parentRect.x,
|
||||
parentRect.y,
|
||||
parentRect.w,
|
||||
parentRect.h,
|
||||
"rgb(255,255,255)",
|
||||
ctx.DRAWWINDOW_DRAW_VIEW | ctx.DRAWWINDOW_USE_WIDGET_LAYERS | ctx.DRAWWINDOW_DRAW_CARET);
|
||||
ctx.DRAWWINDOW_DRAW_VIEW |
|
||||
ctx.DRAWWINDOW_USE_WIDGET_LAYERS |
|
||||
ctx.DRAWWINDOW_DRAW_CARET
|
||||
);
|
||||
return canvas.toDataURL();
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof getSnapshot.chromeHelper == "undefined") {
|
||||
// This is the first time getSnapshot is being called; do initialization
|
||||
getSnapshot.chromeHelper = SpecialPowers.loadChromeScript(parentProcessSnapshot);
|
||||
ApzCleanup.register(function() { getSnapshot.chromeHelper.destroy(); });
|
||||
getSnapshot.chromeHelper = SpecialPowers.loadChromeScript(
|
||||
parentProcessSnapshot
|
||||
);
|
||||
ApzCleanup.register(function() {
|
||||
getSnapshot.chromeHelper.destroy();
|
||||
});
|
||||
}
|
||||
|
||||
return getSnapshot.chromeHelper.sendQuery("snapshot", JSON.stringify(rect));
|
||||
|
|
@ -641,8 +755,8 @@ function injectScript(aScript, aWindow = window) {
|
|||
function getHitTestConfig() {
|
||||
if (!("hitTestConfig" in window)) {
|
||||
var utils = SpecialPowers.getDOMWindowUtils(window);
|
||||
var isWebRender = (utils.layerManagerType == "WebRender");
|
||||
var isWindows = (getPlatform() == "windows");
|
||||
var isWebRender = utils.layerManagerType == "WebRender";
|
||||
var isWindows = getPlatform() == "windows";
|
||||
window.hitTestConfig = { utils, isWebRender, isWindows };
|
||||
}
|
||||
return window.hitTestConfig;
|
||||
|
|
@ -656,7 +770,7 @@ function centerOf(element) {
|
|||
element = document.getElementById(element);
|
||||
}
|
||||
var bounds = element.getBoundingClientRect();
|
||||
return { x: bounds.x + (bounds.width / 2), y: bounds.y + (bounds.height / 2) };
|
||||
return { x: bounds.x + bounds.width / 2, y: bounds.y + bounds.height / 2 };
|
||||
}
|
||||
|
||||
// Peform a compositor hit test at the given point and return the result.
|
||||
|
|
@ -666,11 +780,30 @@ function centerOf(element) {
|
|||
function hitTest(point) {
|
||||
var utils = getHitTestConfig().utils;
|
||||
dump("Hit-testing point (" + point.x + ", " + point.y + ")\n");
|
||||
utils.sendMouseEvent("MozMouseHittest", point.x, point.y, 0, 0, 0, true, 0, 0, true, true);
|
||||
utils.sendMouseEvent(
|
||||
"MozMouseHittest",
|
||||
point.x,
|
||||
point.y,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
true,
|
||||
0,
|
||||
0,
|
||||
true,
|
||||
true
|
||||
);
|
||||
var data = utils.getCompositorAPZTestData();
|
||||
ok(data.hitResults.length >= 1, "Expected at least one hit result in the APZTestData");
|
||||
ok(
|
||||
data.hitResults.length >= 1,
|
||||
"Expected at least one hit result in the APZTestData"
|
||||
);
|
||||
var result = data.hitResults[data.hitResults.length - 1];
|
||||
return { hitInfo: result.hitResult, scrollId: result.scrollId, layersId: result.layersId };
|
||||
return {
|
||||
hitInfo: result.hitResult,
|
||||
scrollId: result.scrollId,
|
||||
layersId: result.layersId,
|
||||
};
|
||||
}
|
||||
|
||||
// Returns a canonical stringification of the hitInfo bitfield.
|
||||
|
|
@ -693,20 +826,30 @@ function hitInfoToString(hitInfo) {
|
|||
// Takes an object returned by hitTest, along with the expected values, and
|
||||
// asserts that they match. Notably, it uses hitInfoToString to provide a
|
||||
// more useful message for the case that the hit info doesn't match
|
||||
function checkHitResult(hitResult, expectedHitInfo, expectedScrollId, expectedLayersId, desc) {
|
||||
is(hitInfoToString(hitResult.hitInfo), hitInfoToString(expectedHitInfo), desc + " hit info");
|
||||
function checkHitResult(
|
||||
hitResult,
|
||||
expectedHitInfo,
|
||||
expectedScrollId,
|
||||
expectedLayersId,
|
||||
desc
|
||||
) {
|
||||
is(
|
||||
hitInfoToString(hitResult.hitInfo),
|
||||
hitInfoToString(expectedHitInfo),
|
||||
desc + " hit info"
|
||||
);
|
||||
is(hitResult.scrollId, expectedScrollId, desc + " scrollid");
|
||||
is(hitResult.layersId, expectedLayersId, desc + " layersid");
|
||||
}
|
||||
|
||||
// Symbolic constants used by hitTestScrollbar().
|
||||
var ScrollbarTrackLocation = {
|
||||
START: 1,
|
||||
END: 2,
|
||||
START: 1,
|
||||
END: 2,
|
||||
};
|
||||
var LayerState = {
|
||||
ACTIVE: 1,
|
||||
INACTIVE: 2,
|
||||
ACTIVE: 1,
|
||||
INACTIVE: 2,
|
||||
};
|
||||
|
||||
// Perform a hit test on the scrollbar(s) of a scroll frame.
|
||||
|
|
@ -743,8 +886,12 @@ function hitTestScrollbar(params) {
|
|||
// coordinates for hit-testing we need to account for this. We assume the
|
||||
// buttons are square, and so can use the scrollbar width/height to estimate
|
||||
// the size of the buttons
|
||||
var scrollbarArrowButtonHeight = config.isWindows ? verticalScrollbarWidth : 0;
|
||||
var scrollbarArrowButtonWidth = config.isWindows ? horizontalScrollbarHeight : 0;
|
||||
var scrollbarArrowButtonHeight = config.isWindows
|
||||
? verticalScrollbarWidth
|
||||
: 0;
|
||||
var scrollbarArrowButtonWidth = config.isWindows
|
||||
? horizontalScrollbarHeight
|
||||
: 0;
|
||||
|
||||
// Compute the expected hit result flags.
|
||||
// The direction flag (APZHitResultFlags.SCROLLBAR_VERTICAL) is added in
|
||||
|
|
@ -774,37 +921,51 @@ function hitTestScrollbar(params) {
|
|||
}
|
||||
}
|
||||
|
||||
var scrollframeMsg = (params.layerState == LayerState.ACTIVE)
|
||||
? "active scrollframe" : "inactive scrollframe";
|
||||
var scrollframeMsg =
|
||||
params.layerState == LayerState.ACTIVE
|
||||
? "active scrollframe"
|
||||
: "inactive scrollframe";
|
||||
|
||||
// Hit-test the targeted areas, assuming we don't have overlay scrollbars
|
||||
// with zero dimensions.
|
||||
if (params.directions.vertical && verticalScrollbarWidth > 0) {
|
||||
var verticalScrollbarPoint = {
|
||||
x: boundingClientRect.right - (verticalScrollbarWidth / 2),
|
||||
y: (params.trackLocation == ScrollbarTrackLocation.START)
|
||||
? (boundingClientRect.y + scrollbarArrowButtonHeight + 5)
|
||||
: (boundingClientRect.bottom - horizontalScrollbarHeight - scrollbarArrowButtonHeight - 5),
|
||||
x: boundingClientRect.right - verticalScrollbarWidth / 2,
|
||||
y:
|
||||
params.trackLocation == ScrollbarTrackLocation.START
|
||||
? boundingClientRect.y + scrollbarArrowButtonHeight + 5
|
||||
: boundingClientRect.bottom -
|
||||
horizontalScrollbarHeight -
|
||||
scrollbarArrowButtonHeight -
|
||||
5,
|
||||
};
|
||||
checkHitResult(hitTest(verticalScrollbarPoint),
|
||||
expectedHitInfo | APZHitResultFlags.SCROLLBAR_VERTICAL,
|
||||
params.expectedScrollId,
|
||||
params.expectedLayersId,
|
||||
scrollframeMsg + " - vertical scrollbar");
|
||||
checkHitResult(
|
||||
hitTest(verticalScrollbarPoint),
|
||||
expectedHitInfo | APZHitResultFlags.SCROLLBAR_VERTICAL,
|
||||
params.expectedScrollId,
|
||||
params.expectedLayersId,
|
||||
scrollframeMsg + " - vertical scrollbar"
|
||||
);
|
||||
}
|
||||
|
||||
if (params.directions.horizontal && horizontalScrollbarHeight > 0) {
|
||||
var horizontalScrollbarPoint = {
|
||||
x: (params.trackLocation == ScrollbarTrackLocation.START)
|
||||
? (boundingClientRect.x + scrollbarArrowButtonWidth + 5)
|
||||
: (boundingClientRect.right - verticalScrollbarWidth - scrollbarArrowButtonWidth - 5),
|
||||
y: boundingClientRect.bottom - (horizontalScrollbarHeight / 2),
|
||||
x:
|
||||
params.trackLocation == ScrollbarTrackLocation.START
|
||||
? boundingClientRect.x + scrollbarArrowButtonWidth + 5
|
||||
: boundingClientRect.right -
|
||||
verticalScrollbarWidth -
|
||||
scrollbarArrowButtonWidth -
|
||||
5,
|
||||
y: boundingClientRect.bottom - horizontalScrollbarHeight / 2,
|
||||
};
|
||||
checkHitResult(hitTest(horizontalScrollbarPoint),
|
||||
expectedHitInfo,
|
||||
params.expectedScrollId,
|
||||
params.expectedLayersId,
|
||||
scrollframeMsg + " - horizontal scrollbar");
|
||||
checkHitResult(
|
||||
hitTest(horizontalScrollbarPoint),
|
||||
expectedHitInfo,
|
||||
params.expectedScrollId,
|
||||
params.expectedLayersId,
|
||||
scrollframeMsg + " - horizontal scrollbar"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -862,7 +1023,16 @@ var ApzCleanup = {
|
|||
try {
|
||||
func();
|
||||
} catch (ex) {
|
||||
SimpleTest.ok(false, "Subtest cleanup function [" + func.toString() + "] threw exception [" + ex + "] on page [" + location.href + "]");
|
||||
SimpleTest.ok(
|
||||
false,
|
||||
"Subtest cleanup function [" +
|
||||
func.toString() +
|
||||
"] threw exception [" +
|
||||
ex +
|
||||
"] on page [" +
|
||||
location.href +
|
||||
"]"
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
add_task(async function test_main() {
|
||||
function httpURL(filename) {
|
||||
let chromeURL = getRootDirectory(gTestPath) + filename;
|
||||
return chromeURL.replace("chrome://mochitests/content/", "http://mochi.test:8888/");
|
||||
return chromeURL.replace(
|
||||
"chrome://mochitests/content/",
|
||||
"http://mochi.test:8888/"
|
||||
);
|
||||
}
|
||||
|
||||
var utils = SpecialPowers.getDOMWindowUtils(window);
|
||||
var isWebRender = (utils.layerManagerType == "WebRender");
|
||||
var isWebRender = utils.layerManagerType == "WebRender";
|
||||
|
||||
// Each of these URLs will get opened in a new top-level browser window that
|
||||
// is fission-enabled.
|
||||
|
|
@ -21,12 +24,15 @@ add_task(async function test_main() {
|
|||
]);
|
||||
}
|
||||
|
||||
let fissionWindow = await BrowserTestUtils.openNewBrowserWindow({fission: true});
|
||||
let fissionWindow = await BrowserTestUtils.openNewBrowserWindow({
|
||||
fission: true,
|
||||
});
|
||||
|
||||
// We import the JSM here so that we can install functions on the class
|
||||
// below.
|
||||
const {FissionTestHelperParent} = ChromeUtils.import(
|
||||
getRootDirectory(gTestPath) + "FissionTestHelperParent.jsm");
|
||||
const { FissionTestHelperParent } = ChromeUtils.import(
|
||||
getRootDirectory(gTestPath) + "FissionTestHelperParent.jsm"
|
||||
);
|
||||
FissionTestHelperParent.SimpleTest = SimpleTest;
|
||||
|
||||
ChromeUtils.registerWindowActor("FissionTestHelper", {
|
||||
|
|
@ -36,7 +42,7 @@ add_task(async function test_main() {
|
|||
child: {
|
||||
moduleURI: getRootDirectory(gTestPath) + "FissionTestHelperChild.jsm",
|
||||
events: {
|
||||
"DOMWindowCreated": {},
|
||||
DOMWindowCreated: {},
|
||||
},
|
||||
},
|
||||
allFrames: true,
|
||||
|
|
@ -49,13 +55,16 @@ add_task(async function test_main() {
|
|||
// Load the test URL and tell it to get started, and wait until it reports
|
||||
// completion.
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{gBrowser: fissionWindow.gBrowser, url},
|
||||
async (browser) => {
|
||||
let tabActor = browser.browsingContext.currentWindowGlobal.getActor("FissionTestHelper");
|
||||
{ gBrowser: fissionWindow.gBrowser, url },
|
||||
async browser => {
|
||||
let tabActor = browser.browsingContext.currentWindowGlobal.getActor(
|
||||
"FissionTestHelper"
|
||||
);
|
||||
let donePromise = tabActor.getTestCompletePromise();
|
||||
tabActor.startTest();
|
||||
await donePromise;
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
dump(`Finished test ${url}\n`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,12 +28,16 @@ function promiseOneEvent(eventType, filter) {
|
|||
try {
|
||||
success = filter(e);
|
||||
} catch (ex) {
|
||||
dump(`ERROR: Filter passed to promiseOneEvent threw exception: ${ex}\n`);
|
||||
dump(
|
||||
`ERROR: Filter passed to promiseOneEvent threw exception: ${ex}\n`
|
||||
);
|
||||
reject();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
dump("ERROR: Filter passed to promiseOneEvent was neither null nor a function\n");
|
||||
dump(
|
||||
"ERROR: Filter passed to promiseOneEvent was neither null nor a function\n"
|
||||
);
|
||||
reject();
|
||||
return;
|
||||
}
|
||||
|
|
@ -54,14 +58,18 @@ function promiseOneEvent(eventType, filter) {
|
|||
function loadOOPIFrame(iframeElementId, iframePage) {
|
||||
return async function() {
|
||||
if (window.location.href.startsWith("https://example.com/")) {
|
||||
dump(`WARNING: Calling loadOOPIFrame from ${window.location.href} so the iframe may not be OOP\n`);
|
||||
dump(
|
||||
`WARNING: Calling loadOOPIFrame from ${
|
||||
window.location.href
|
||||
} so the iframe may not be OOP\n`
|
||||
);
|
||||
ok(false, "Current origin is not example.com:443");
|
||||
}
|
||||
|
||||
let url = "https://example.com/browser/gfx/layers/apz/test/mochitest/" + iframePage;
|
||||
let url =
|
||||
"https://example.com/browser/gfx/layers/apz/test/mochitest/" + iframePage;
|
||||
let loadPromise = promiseOneEvent("OOPIF:Load", function(e) {
|
||||
return (typeof e.data.content) == "string" &&
|
||||
e.data.content == url;
|
||||
return typeof e.data.content == "string" && e.data.content == url;
|
||||
});
|
||||
let elem = document.getElementById(iframeElementId);
|
||||
elem.src = url;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
function toFixed(num, fixed) {
|
||||
fixed = fixed || 0;
|
||||
fixed = Math.pow(10, fixed);
|
||||
return Math.floor(num * fixed) / fixed;
|
||||
fixed = fixed || 0;
|
||||
fixed = Math.pow(10, fixed);
|
||||
return Math.floor(num * fixed) / fixed;
|
||||
}
|
||||
function createElement(name, props) {
|
||||
var el = document.createElement(name);
|
||||
|
|
@ -43,7 +43,9 @@ function parseDisplayList(lines) {
|
|||
root = layerObject;
|
||||
}
|
||||
|
||||
var matches = line.match("(\\s*)(\\w+)\\sp=(\\w+)\\sf=(.*?)\\((.*?)\\)\\s(z=(\\w+)\\s)?(.*?)?( layer=(\\w+))?$");
|
||||
var matches = line.match(
|
||||
"(\\s*)(\\w+)\\sp=(\\w+)\\sf=(.*?)\\((.*?)\\)\\s(z=(\\w+)\\s)?(.*?)?( layer=(\\w+))?$"
|
||||
);
|
||||
if (!matches) {
|
||||
dump("Failed to match: " + line + "\n");
|
||||
continue;
|
||||
|
|
@ -62,7 +64,8 @@ function parseDisplayList(lines) {
|
|||
layerObject.contentDescriptor = matches[5];
|
||||
layerObject.z = matches[7];
|
||||
var rest = matches[8];
|
||||
if (matches[10]) { // WrapList don't provide a layer
|
||||
if (matches[10]) {
|
||||
// WrapList don't provide a layer
|
||||
layerObject.layer = matches[10];
|
||||
}
|
||||
layerObject.rest = rest;
|
||||
|
|
@ -107,7 +110,7 @@ function parseDisplayList(lines) {
|
|||
}
|
||||
|
||||
function trim(s) {
|
||||
return ( s || "" ).replace( /^\s+|\s+$/g, "" );
|
||||
return (s || "").replace(/^\s+|\s+$/g, "");
|
||||
}
|
||||
|
||||
function getDataURI(str) {
|
||||
|
|
@ -115,9 +118,12 @@ function getDataURI(str) {
|
|||
return str;
|
||||
}
|
||||
|
||||
var matches = str.match("data:image/lz4bgra;base64,([0-9]+),([0-9]+),([0-9]+),(.*)");
|
||||
if (!matches)
|
||||
var matches = str.match(
|
||||
"data:image/lz4bgra;base64,([0-9]+),([0-9]+),([0-9]+),(.*)"
|
||||
);
|
||||
if (!matches) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var canvas = document.createElement("canvas");
|
||||
var w = parseInt(matches[1]);
|
||||
|
|
@ -212,8 +218,10 @@ function parseLayers(layersDumpLines) {
|
|||
}
|
||||
|
||||
var rect = [
|
||||
parseFloat(rectMatches[1]), parseFloat(rectMatches[2]),
|
||||
parseFloat(rectMatches[3]), parseFloat(rectMatches[4]),
|
||||
parseFloat(rectMatches[1]),
|
||||
parseFloat(rectMatches[2]),
|
||||
parseFloat(rectMatches[3]),
|
||||
parseFloat(rectMatches[4]),
|
||||
];
|
||||
return rect;
|
||||
}
|
||||
|
|
@ -228,14 +236,18 @@ function parseLayers(layersDumpLines) {
|
|||
var region = [];
|
||||
str = trim(str.substring(1, str.length - 1));
|
||||
while (str != "") {
|
||||
var rectMatches = str.match("^\\(x=(.*?), y=(.*?), w=(.*?), h=(.*?)\\);(.*)$");
|
||||
var rectMatches = str.match(
|
||||
"^\\(x=(.*?), y=(.*?), w=(.*?), h=(.*?)\\);(.*)$"
|
||||
);
|
||||
if (!rectMatches) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var rect = [
|
||||
parseFloat(rectMatches[1]), parseFloat(rectMatches[2]),
|
||||
parseFloat(rectMatches[3]), parseFloat(rectMatches[4]),
|
||||
parseFloat(rectMatches[1]),
|
||||
parseFloat(rectMatches[2]),
|
||||
parseFloat(rectMatches[3]),
|
||||
parseFloat(rectMatches[4]),
|
||||
];
|
||||
str = trim(rectMatches[5]);
|
||||
region.push(rect);
|
||||
|
|
@ -271,16 +283,21 @@ function parseLayers(layersDumpLines) {
|
|||
var surfaceMatches = line.match("(\\s*)Surface: (.*)");
|
||||
if (surfaceMatches) {
|
||||
let indentation = Math.floor(matches[1].length / 2);
|
||||
let parent = objectAtIndentation[indentation - 1] || objectAtIndentation[indentation - 2];
|
||||
let parent =
|
||||
objectAtIndentation[indentation - 1] ||
|
||||
objectAtIndentation[indentation - 2];
|
||||
|
||||
var surfaceURI = surfaceMatches[2];
|
||||
if (parent.surfaceURI != null) {
|
||||
console.log("error: surfaceURI already set for this layer " + parent.line);
|
||||
console.log(
|
||||
"error: surfaceURI already set for this layer " + parent.line
|
||||
);
|
||||
}
|
||||
parent.surfaceURI = surfaceURI;
|
||||
|
||||
// Look for the buffer-rect offset
|
||||
var contentHostLine = layersDumpLines[i - 2].name || layersDumpLines[i - 2];
|
||||
var contentHostLine =
|
||||
layersDumpLines[i - 2].name || layersDumpLines[i - 2];
|
||||
let matches = contentHostLine.match(LAYERS_LINE_REGEX);
|
||||
if (matches) {
|
||||
var contentHostRest = matches[4];
|
||||
|
|
@ -304,11 +321,13 @@ function parseLayers(layersDumpLines) {
|
|||
continue; // Something like a texturehost dump. Safe to ignore
|
||||
}
|
||||
|
||||
if (matches[2].includes("TiledContentHost") ||
|
||||
matches[2].includes("ContentHost") ||
|
||||
matches[2].includes("ContentClient") ||
|
||||
matches[2].includes("MemoryTextureHost") ||
|
||||
matches[2].includes("ImageHost")) {
|
||||
if (
|
||||
matches[2].includes("TiledContentHost") ||
|
||||
matches[2].includes("ContentHost") ||
|
||||
matches[2].includes("ContentClient") ||
|
||||
matches[2].includes("MemoryTextureHost") ||
|
||||
matches[2].includes("ImageHost")
|
||||
) {
|
||||
continue; // We're already pretty good at visualizing these
|
||||
}
|
||||
|
||||
|
|
@ -414,10 +433,15 @@ function parseLayers(layersDumpLines) {
|
|||
// Compute screenTransformX/screenTransformY
|
||||
// TODO Fully support transforms
|
||||
if (layerObject["shadow-transform"] && layerObject.transform) {
|
||||
layerObject["screen-transform"] = [layerObject["shadow-transform"][2][0], layerObject["shadow-transform"][2][1]];
|
||||
layerObject["screen-transform"] = [
|
||||
layerObject["shadow-transform"][2][0],
|
||||
layerObject["shadow-transform"][2][1],
|
||||
];
|
||||
var currIndentation = indentation - 1;
|
||||
while (currIndentation >= 0) {
|
||||
var transform = objectAtIndentation[currIndentation]["shadow-transform"] || objectAtIndentation[currIndentation].transform;
|
||||
var transform =
|
||||
objectAtIndentation[currIndentation]["shadow-transform"] ||
|
||||
objectAtIndentation[currIndentation].transform;
|
||||
if (transform) {
|
||||
layerObject["screen-transform"][0] += transform[2][0];
|
||||
layerObject["screen-transform"][1] += transform[2][1];
|
||||
|
|
@ -432,7 +456,15 @@ function parseLayers(layersDumpLines) {
|
|||
// dump("OBJECTS: " + JSON.stringify(root) + "\n");
|
||||
return root;
|
||||
}
|
||||
function populateLayers(root, displayList, pane, previewParent, hasSeenRoot, contentScale, rootPreviewParent) {
|
||||
function populateLayers(
|
||||
root,
|
||||
displayList,
|
||||
pane,
|
||||
previewParent,
|
||||
hasSeenRoot,
|
||||
contentScale,
|
||||
rootPreviewParent
|
||||
) {
|
||||
contentScale = contentScale || 1;
|
||||
rootPreviewParent = rootPreviewParent || previewParent;
|
||||
|
||||
|
|
@ -521,7 +553,8 @@ function populateLayers(root, displayList, pane, previewParent, hasSeenRoot, con
|
|||
});
|
||||
layerViewportMatrix[4] += -clip[0];
|
||||
layerViewportMatrix[5] += -clip[1];
|
||||
layerViewport.style.transform = "translate(-" + clip[0] + "px, -" + clip[1] + "px)";
|
||||
layerViewport.style.transform =
|
||||
"translate(-" + clip[0] + "px, -" + clip[1] + "px)";
|
||||
}
|
||||
if (root["shadow-transform"] || root.transform) {
|
||||
var matrix = root["shadow-transform"] || root.transform;
|
||||
|
|
@ -532,10 +565,24 @@ function populateLayers(root, displayList, pane, previewParent, hasSeenRoot, con
|
|||
layerViewportMatrix[4] += matrix[2][0];
|
||||
layerViewportMatrix[5] += matrix[2][1];
|
||||
}
|
||||
layerViewport.style.transform = "matrix(" + layerViewportMatrix[0] + "," + layerViewportMatrix[1] + "," + layerViewportMatrix[2] + "," + layerViewportMatrix[3] + "," + layerViewportMatrix[4] + "," + layerViewportMatrix[5] + ")";
|
||||
layerViewport.style.transform =
|
||||
"matrix(" +
|
||||
layerViewportMatrix[0] +
|
||||
"," +
|
||||
layerViewportMatrix[1] +
|
||||
"," +
|
||||
layerViewportMatrix[2] +
|
||||
"," +
|
||||
layerViewportMatrix[3] +
|
||||
"," +
|
||||
layerViewportMatrix[4] +
|
||||
"," +
|
||||
layerViewportMatrix[5] +
|
||||
")";
|
||||
if (!hasSeenRoot) {
|
||||
hasSeenRoot = true;
|
||||
layerViewport.style.transform = "scale(" + 1 / contentScale + "," + 1 / contentScale + ")";
|
||||
layerViewport.style.transform =
|
||||
"scale(" + 1 / contentScale + "," + 1 / contentScale + ")";
|
||||
}
|
||||
if (clipElem) {
|
||||
previewParent.appendChild(clipElem);
|
||||
|
|
@ -557,14 +604,19 @@ function populateLayers(root, displayList, pane, previewParent, hasSeenRoot, con
|
|||
height: rect2d[3] + "px",
|
||||
overflow: "hidden",
|
||||
border: "solid 1px black",
|
||||
background: 'url("noise.png"), linear-gradient(rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.2))',
|
||||
background:
|
||||
'url("noise.png"), linear-gradient(rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.2))',
|
||||
},
|
||||
});
|
||||
layerViewport.appendChild(layerPreview);
|
||||
|
||||
function isInside(rect1, rect2) {
|
||||
if (rect1[0] + rect1[2] < rect2[0] && rect2[0] + rect2[2] < rect1[0] &&
|
||||
rect1[1] + rect1[3] < rect2[1] && rect2[1] + rect2[3] < rect1[1]) {
|
||||
if (
|
||||
rect1[0] + rect1[2] < rect2[0] &&
|
||||
rect2[0] + rect2[2] < rect1[0] &&
|
||||
rect1[1] + rect1[3] < rect2[1] &&
|
||||
rect2[1] + rect2[3] < rect1[1]
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -583,8 +635,8 @@ function populateLayers(root, displayList, pane, previewParent, hasSeenRoot, con
|
|||
src: getDataURI(root.tiles[x][y]),
|
||||
style: {
|
||||
position: "absolute",
|
||||
left: (x - previewOffset[0]) + "px",
|
||||
top: (y - previewOffset[1]) + "px",
|
||||
left: x - previewOffset[0] + "px",
|
||||
top: y - previewOffset[1] + "px",
|
||||
pointerEvents: "auto",
|
||||
},
|
||||
});
|
||||
|
|
@ -605,8 +657,8 @@ function populateLayers(root, displayList, pane, previewParent, hasSeenRoot, con
|
|||
src: getDataURI(root.surfaceURI),
|
||||
style: {
|
||||
position: "absolute",
|
||||
left: (offsetX - previewOffset[0]) + "px",
|
||||
top: (offsetY - previewOffset[1]) + "px",
|
||||
left: offsetX - previewOffset[0] + "px",
|
||||
top: offsetY - previewOffset[1] + "px",
|
||||
pointerEvents: "auto",
|
||||
},
|
||||
});
|
||||
|
|
@ -614,7 +666,16 @@ function populateLayers(root, displayList, pane, previewParent, hasSeenRoot, con
|
|||
layerPreview.style.background = "";
|
||||
} else if (root.color) {
|
||||
hasImg = true;
|
||||
layerPreview.style.background = "rgba(" + root.color.r + ", " + root.color.g + ", " + root.color.b + ", " + root.color.a + ")";
|
||||
layerPreview.style.background =
|
||||
"rgba(" +
|
||||
root.color.r +
|
||||
", " +
|
||||
root.color.g +
|
||||
", " +
|
||||
root.color.b +
|
||||
", " +
|
||||
root.color.a +
|
||||
")";
|
||||
}
|
||||
|
||||
if (hasImg || true) {
|
||||
|
|
@ -648,14 +709,29 @@ function populateLayers(root, displayList, pane, previewParent, hasSeenRoot, con
|
|||
description += "Content: " + this.displayItem.contentDescriptor;
|
||||
} else {
|
||||
description += "Content: Unknown";
|
||||
}
|
||||
description += "<br>Item: " + this.displayItem.name + " (" + this.displayItem.address + ")";
|
||||
description += "<br>Layer: " + root.name + " (" + root.address + ")";
|
||||
}
|
||||
description +=
|
||||
"<br>Item: " +
|
||||
this.displayItem.name +
|
||||
" (" +
|
||||
this.displayItem.address +
|
||||
")";
|
||||
description +=
|
||||
"<br>Layer: " + root.name + " (" + root.address + ")";
|
||||
if (this.displayItem.frame) {
|
||||
description += "<br>Frame: " + this.displayItem.frame;
|
||||
}
|
||||
if (this.displayItem.layerBounds) {
|
||||
description += "<br>Bounds: [" + toFixed(this.displayItem.layerBounds[0] / 60, 2) + ", " + toFixed(this.displayItem.layerBounds[1] / 60, 2) + ", " + toFixed(this.displayItem.layerBounds[2] / 60, 2) + ", " + toFixed(this.displayItem.layerBounds[3] / 60, 2) + "] (CSS Pixels)";
|
||||
description +=
|
||||
"<br>Bounds: [" +
|
||||
toFixed(this.displayItem.layerBounds[0] / 60, 2) +
|
||||
", " +
|
||||
toFixed(this.displayItem.layerBounds[1] / 60, 2) +
|
||||
", " +
|
||||
toFixed(this.displayItem.layerBounds[2] / 60, 2) +
|
||||
", " +
|
||||
toFixed(this.displayItem.layerBounds[3] / 60, 2) +
|
||||
"] (CSS Pixels)";
|
||||
}
|
||||
if (this.displayItem.z) {
|
||||
description += "<br>Z: " + this.displayItem.z;
|
||||
|
|
@ -670,7 +746,11 @@ function populateLayers(root, displayList, pane, previewParent, hasSeenRoot, con
|
|||
className: "csstooltip",
|
||||
innerHTML: description,
|
||||
style: {
|
||||
top: Math.min(box.bottom, document.documentElement.clientHeight - 150) + "px",
|
||||
top:
|
||||
Math.min(
|
||||
box.bottom,
|
||||
document.documentElement.clientHeight - 150
|
||||
) + "px",
|
||||
left: box.left + "px",
|
||||
},
|
||||
});
|
||||
|
|
@ -699,7 +779,8 @@ function populateLayers(root, displayList, pane, previewParent, hasSeenRoot, con
|
|||
// bounds doesn't adjust for within the layer. It's not a bad fallback but
|
||||
// will have the wrong offset
|
||||
let rect2d = displayItem.layerBounds || displayItem.bounds;
|
||||
if (rect2d) { // This doesn't place them corectly
|
||||
if (rect2d) {
|
||||
// This doesn't place them corectly
|
||||
var appUnitsToPixels = 60 / contentScale;
|
||||
let diPreview = createElement("div", {
|
||||
id: "displayitem_" + displayItem.content + "_" + displayItem.address,
|
||||
|
|
@ -729,7 +810,15 @@ function populateLayers(root, displayList, pane, previewParent, hasSeenRoot, con
|
|||
}
|
||||
|
||||
for (var i = 0; i < root.children.length; i++) {
|
||||
populateLayers(root.children[i], displayList, pane, previewParent, hasSeenRoot, contentScale, rootPreviewParent);
|
||||
populateLayers(
|
||||
root.children[i],
|
||||
displayList,
|
||||
pane,
|
||||
previewParent,
|
||||
hasSeenRoot,
|
||||
contentScale,
|
||||
rootPreviewParent
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -796,7 +885,7 @@ function parseMultiLineDump(log) {
|
|||
display: "block",
|
||||
},
|
||||
href: "#",
|
||||
textContent: "LayerTree " + (frameID++),
|
||||
textContent: "LayerTree " + frameID++,
|
||||
onclick() {
|
||||
contents.innerHTML = "";
|
||||
var matchLines = matches[i].split("\n");
|
||||
|
|
@ -829,7 +918,9 @@ function parseDump(log, displayList, compositeTitle, compositeTime) {
|
|||
style: {
|
||||
width: "100%",
|
||||
},
|
||||
textContent: compositeTitle + (compositeTitle ? " (near " + compositeTime.toFixed(0) + " ms)" : ""),
|
||||
textContent:
|
||||
compositeTitle +
|
||||
(compositeTitle ? " (near " + compositeTime.toFixed(0) + " ms)" : ""),
|
||||
});
|
||||
container.appendChild(titleDiv);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,14 +5,17 @@ add_task(async function test_windowlessBrowserTroubleshootCrash() {
|
|||
let docShell = webNav.docShell;
|
||||
let listener = {
|
||||
observe(contentWindow, topic, data) {
|
||||
let observedDocShell = contentWindow.docShell
|
||||
.sameTypeRootTreeItem
|
||||
.QueryInterface(Ci.nsIDocShell);
|
||||
if (docShell === observedDocShell) {
|
||||
Services.obs.removeObserver(listener, "content-document-global-created");
|
||||
resolve();
|
||||
}
|
||||
},
|
||||
let observedDocShell = contentWindow.docShell.sameTypeRootTreeItem.QueryInterface(
|
||||
Ci.nsIDocShell
|
||||
);
|
||||
if (docShell === observedDocShell) {
|
||||
Services.obs.removeObserver(
|
||||
listener,
|
||||
"content-document-global-created"
|
||||
);
|
||||
resolve();
|
||||
}
|
||||
},
|
||||
};
|
||||
Services.obs.addObserver(listener, "content-document-global-created");
|
||||
});
|
||||
|
|
@ -25,21 +28,31 @@ add_task(async function test_windowlessBrowserTroubleshootCrash() {
|
|||
|
||||
let winUtils = webNav.document.defaultView.windowUtils;
|
||||
try {
|
||||
is(winUtils.layerManagerType, "Basic", "windowless browser's layerManagerType should be 'Basic'");
|
||||
is(
|
||||
winUtils.layerManagerType,
|
||||
"Basic",
|
||||
"windowless browser's layerManagerType should be 'Basic'"
|
||||
);
|
||||
} catch (e) {
|
||||
// The windowless browser may not have a layermanager at all yet, and that's ok.
|
||||
// The troubleshooting code similarly skips over windows with no layer managers.
|
||||
}
|
||||
ok(true, "not crashed");
|
||||
|
||||
var Troubleshoot = ChromeUtils.import("resource://gre/modules/Troubleshoot.jsm", {}).Troubleshoot;
|
||||
var Troubleshoot = ChromeUtils.import(
|
||||
"resource://gre/modules/Troubleshoot.jsm",
|
||||
{}
|
||||
).Troubleshoot;
|
||||
var data = await new Promise((resolve, reject) => {
|
||||
Troubleshoot.snapshot((data) => {
|
||||
Troubleshoot.snapshot(data => {
|
||||
resolve(data);
|
||||
});
|
||||
});
|
||||
|
||||
ok(data.graphics.windowLayerManagerType !== "None", "windowless browser window should not set windowLayerManagerType to 'None'");
|
||||
ok(
|
||||
data.graphics.windowLayerManagerType !== "None",
|
||||
"windowless browser window should not set windowLayerManagerType to 'None'"
|
||||
);
|
||||
|
||||
webNav.close();
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue