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:
Victor Porof 2019-07-05 10:46:28 +02:00
parent 5af464dcc4
commit 85064fe4c3
10 changed files with 844 additions and 286 deletions

View file

@ -45,7 +45,6 @@ module.exports = {
"overrides": [{ "overrides": [{
"files": [ "files": [
"devtools/**", "devtools/**",
"gfx/**",
"gradle/**", "gradle/**",
"hal/**", "hal/**",
"image/**", "image/**",

View file

@ -40,7 +40,6 @@ toolkit/components/telemetry/datareporting-prefs.js
toolkit/components/telemetry/healthreport-prefs.js toolkit/components/telemetry/healthreport-prefs.js
# Ignore all top-level directories for now. # Ignore all top-level directories for now.
gfx/**
gradle/** gradle/**
hal/** hal/**
image/** image/**

View file

@ -27,27 +27,36 @@ class FissionTestHelperChild extends JSWindowActorChild {
// namespace. // namespace.
let cw = this.cw(); 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" });
let FissionTestHelper = Cu.createObjectIn(cw, { defineAs: "FissionTestHelper" });
FissionTestHelper.startTestPromise =
new cw.Promise(
Cu.exportFunction( Cu.exportFunction(
(resolve) => { (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; this._startTestPromiseResolver = resolve;
}, }, cw)
cw)); );
Cu.exportFunction(this.subtestDone.bind(this), Cu.exportFunction(this.subtestDone.bind(this), FissionTestHelper, {
FissionTestHelper, { defineAs: "subtestDone" }); defineAs: "subtestDone",
});
Cu.exportFunction(this.sendToOopif.bind(this), Cu.exportFunction(this.sendToOopif.bind(this), FissionTestHelper, {
FissionTestHelper, { defineAs: "sendToOopif" }); defineAs: "sendToOopif",
Cu.exportFunction(this.fireEventInEmbedder.bind(this), });
FissionTestHelper, { defineAs: "fireEventInEmbedder" }); Cu.exportFunction(this.fireEventInEmbedder.bind(this), FissionTestHelper, {
defineAs: "fireEventInEmbedder",
});
} }
// Called by the subtest to indicate completion to the top-level browser-chrome // 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 msgId = ++this._msgCounter;
let cw = this.cw(); let cw = this.cw();
let responsePromise = new cw.Promise( let responsePromise = new cw.Promise(
Cu.exportFunction( Cu.exportFunction(resolve => {
(resolve) => {
this._oopifResponsePromiseResolvers[msgId] = resolve; this._oopifResponsePromiseResolvers[msgId] = resolve;
}, }, cw)
cw)); );
this.sendAsyncMessage("EmbedderToOopif", {browsingContextId, msgId, stringToEval}); this.sendAsyncMessage("EmbedderToOopif", {
browsingContextId,
msgId,
stringToEval,
});
return responsePromise; return responsePromise;
} }
@ -91,7 +103,9 @@ class FissionTestHelperChild extends JSWindowActorChild {
// is fired by the content. See comments in fission_subtest_init(). // is fired by the content. See comments in fission_subtest_init().
// Once bug 1557486 is fixed we can just register the FissionTestHelper:Init // Once bug 1557486 is fixed we can just register the FissionTestHelper:Init
// event directly instead of DOMWindowCreated. // event directly instead of DOMWindowCreated.
this.contentWindow.addEventListener("FissionTestHelper:Init", this, { wantUntrusted: true }); this.contentWindow.addEventListener("FissionTestHelper:Init", this, {
wantUntrusted: true,
});
break; break;
case "FissionTestHelper:Init": case "FissionTestHelper:Init":
this.initialize(); this.initialize();
@ -107,14 +121,23 @@ class FissionTestHelperChild extends JSWindowActorChild {
break; break;
case "FromEmbedder": case "FromEmbedder":
let evalResult = this.contentWindow.eval(msg.data.stringToEval); 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; break;
case "FromOopif": case "FromOopif":
if (typeof msg.data.msgId == "number") { if (typeof msg.data.msgId == "number") {
if (!(msg.data.msgId in this._oopifResponsePromiseResolvers)) { 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]; delete this._oopifResponsePromiseResolvers[msg.data.msgId];
} else if (typeof msg.data.eventType == "string") { } else if (typeof msg.data.eventType == "string") {
let cw = this.cw(); let cw = this.cw();
@ -122,7 +145,11 @@ class FissionTestHelperChild extends JSWindowActorChild {
event.data = Cu.cloneInto(msg.data.data, cw); event.data = Cu.cloneInto(msg.data.data, cw);
this.contentWindow.dispatchEvent(event); this.contentWindow.dispatchEvent(event);
} else { } 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; break;
} }

View file

@ -11,7 +11,7 @@ var EXPORTED_SYMBOLS = ["FissionTestHelperParent"];
class FissionTestHelperParent extends JSWindowActorParent { class FissionTestHelperParent extends JSWindowActorParent {
constructor() { constructor() {
super(); super();
this._testCompletePromise = new Promise((resolve) => { this._testCompletePromise = new Promise(resolve => {
this._testCompletePromiseResolver = resolve; this._testCompletePromiseResolver = resolve;
}); });
} }
@ -42,11 +42,18 @@ class FissionTestHelperParent extends JSWindowActorParent {
receiveMessage(msg) { receiveMessage(msg) {
switch (msg.name) { switch (msg.name) {
case "ok": 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; break;
case "is": 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; break;
case "Test:Complete": case "Test:Complete":
@ -56,14 +63,24 @@ class FissionTestHelperParent extends JSWindowActorParent {
case "EmbedderToOopif": case "EmbedderToOopif":
// This relays messages from the embedder to an OOP-iframe. The browsing // This relays messages from the embedder to an OOP-iframe. The browsing
// context id in the message data identifies the OOP-iframe. // 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) { if (oopifBrowsingContext == null) {
FissionTestHelperParent.SimpleTest.ok(false, "EmbedderToOopif couldn't find oopif"); FissionTestHelperParent.SimpleTest.ok(
false,
"EmbedderToOopif couldn't find oopif"
);
break; break;
} }
let oopifActor = oopifBrowsingContext.currentWindowGlobal.getActor("FissionTestHelper"); let oopifActor = oopifBrowsingContext.currentWindowGlobal.getActor(
"FissionTestHelper"
);
if (!oopifActor) { if (!oopifActor) {
FissionTestHelperParent.SimpleTest.ok(false, "EmbedderToOopif couldn't find oopif actor"); FissionTestHelperParent.SimpleTest.ok(
false,
"EmbedderToOopif couldn't find oopif actor"
);
break; break;
} }
oopifActor.sendAsyncMessage("FromEmbedder", msg.data); oopifActor.sendAsyncMessage("FromEmbedder", msg.data);
@ -74,7 +91,10 @@ class FissionTestHelperParent extends JSWindowActorParent {
// window which is embedding it. // window which is embedding it.
let embedderActor = this.embedderWindow().getActor("FissionTestHelper"); let embedderActor = this.embedderWindow().getActor("FissionTestHelper");
if (!embedderActor) { if (!embedderActor) {
FissionTestHelperParent.SimpleTest.ok(false, "OopifToEmbedder couldn't find embedder"); FissionTestHelperParent.SimpleTest.ok(
false,
"OopifToEmbedder couldn't find embedder"
);
break; break;
} }
embedderActor.sendAsyncMessage("FromOopif", msg.data); embedderActor.sendAsyncMessage("FromOopif", msg.data);

View file

@ -28,20 +28,30 @@ function getPlatform() {
function nativeVerticalWheelEventMsg() { function nativeVerticalWheelEventMsg() {
switch (getPlatform()) { switch (getPlatform()) {
case "windows": return 0x020A; // WM_MOUSEWHEEL case "windows":
case "mac": return 0; // value is unused, can be anything return 0x020a; // WM_MOUSEWHEEL
case "linux": return 4; // value is unused, pass GDK_SCROLL_SMOOTH anyway 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() { function nativeHorizontalWheelEventMsg() {
switch (getPlatform()) { switch (getPlatform()) {
case "windows": return 0x020E; // WM_MOUSEHWHEEL case "windows":
case "mac": return 0; // value is unused, can be anything return 0x020e; // WM_MOUSEHWHEEL
case "linux": return 4; // value is unused, pass GDK_SCROLL_SMOOTH anyway 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. // 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. // GTK deltas are treated as line height divided by 3 by gecko.
var targetWindow = windowForTarget(aTarget); var targetWindow = windowForTarget(aTarget);
var targetElement = elementForTarget(aTarget); var targetElement = elementForTarget(aTarget);
var lineHeight = targetWindow.getComputedStyle(targetElement)["font-size"]; var lineHeight = targetWindow.getComputedStyle(targetElement)[
"font-size"
];
return aDimen / (parseInt(lineHeight) * 3); return aDimen / (parseInt(lineHeight) * 3);
} }
} }
@ -81,38 +93,57 @@ function nativeScrollUnits(aTarget, aDimen) {
function nativeMouseDownEventMsg() { function nativeMouseDownEventMsg() {
switch (getPlatform()) { switch (getPlatform()) {
case "windows": return 2; // MOUSEEVENTF_LEFTDOWN case "windows":
case "mac": return 1; // NSLeftMouseDown return 2; // MOUSEEVENTF_LEFTDOWN
case "linux": return 4; // GDK_BUTTON_PRESS case "mac":
case "android": return 5; // ACTION_POINTER_DOWN 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() { function nativeMouseMoveEventMsg() {
switch (getPlatform()) { switch (getPlatform()) {
case "windows": return 1; // MOUSEEVENTF_MOVE case "windows":
case "mac": return 5; // NSMouseMoved return 1; // MOUSEEVENTF_MOVE
case "linux": return 3; // GDK_MOTION_NOTIFY case "mac":
case "android": return 7; // ACTION_HOVER_MOVE 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() { function nativeMouseUpEventMsg() {
switch (getPlatform()) { switch (getPlatform()) {
case "windows": return 4; // MOUSEEVENTF_LEFTUP case "windows":
case "mac": return 2; // NSLeftMouseUp return 4; // MOUSEEVENTF_LEFTUP
case "linux": return 7; // GDK_BUTTON_RELEASE case "mac":
case "android": return 6; // ACTION_POINTER_UP 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) { function getBoundingClientRectRelativeToVisualViewport(aElement) {
let utils = SpecialPowers.getDOMWindowUtils(window); let utils = SpecialPowers.getDOMWindowUtils(window);
var rect = aElement.getBoundingClientRect(); var rect = aElement.getBoundingClientRect();
var offsetX = {}, offsetY = {}; var offsetX = {},
offsetY = {};
// TODO: Audit whether these offset values are correct or not for // TODO: Audit whether these offset values are correct or not for
// position:fixed elements especially in the case where the visual viewport // position:fixed elements especially in the case where the visual viewport
// offset is not 0. // offset is not 0.
@ -135,14 +166,19 @@ function coordinatesRelativeToScreen(aX, aY, aTarget) {
var targetWindow = windowForTarget(aTarget); var targetWindow = windowForTarget(aTarget);
var deviceScale = targetWindow.devicePixelRatio; var deviceScale = targetWindow.devicePixelRatio;
var resolution = getResolution(); var resolution = getResolution();
var rect = (aTarget instanceof Window) var rect =
aTarget instanceof Window
? { left: 0, top: 0 } /* we don't use the width or height */ ? { left: 0, top: 0 } /* we don't use the width or height */
: getBoundingClientRectRelativeToVisualViewport(aTarget); : getBoundingClientRectRelativeToVisualViewport(aTarget);
// moxInnerScreen{X,Y} are in CSS coordinates of the browser chrome. // moxInnerScreen{X,Y} are in CSS coordinates of the browser chrome.
// The device scale applies to them, but the resolution only zooms the content. // The device scale applies to them, but the resolution only zooms the content.
return { return {
x: (targetWindow.mozInnerScreenX + ((rect.left + aX) * resolution)) * deviceScale, x:
y: (targetWindow.mozInnerScreenY + ((rect.top + aY) * resolution)) * deviceScale, (targetWindow.mozInnerScreenX + (rect.left + aX) * resolution) *
deviceScale,
y:
(targetWindow.mozInnerScreenY + (rect.top + aY) * resolution) *
deviceScale,
}; };
} }
@ -155,8 +191,8 @@ function rectRelativeToScreen(aElement) {
return { return {
x: (targetWindow.mozInnerScreenX + rect.left) * scale, x: (targetWindow.mozInnerScreenX + rect.left) * scale,
y: (targetWindow.mozInnerScreenY + rect.top) * scale, y: (targetWindow.mozInnerScreenY + rect.top) * scale,
w: (rect.width * scale), w: rect.width * scale,
h: (rect.height * scale), h: rect.height * scale,
}; };
} }
@ -169,14 +205,29 @@ function rectRelativeToScreen(aElement) {
function synthesizeNativeWheel(aTarget, aX, aY, aDeltaX, aDeltaY, aObserver) { function synthesizeNativeWheel(aTarget, aX, aY, aDeltaX, aDeltaY, aObserver) {
var pt = coordinatesRelativeToScreen(aX, aY, aTarget); var pt = coordinatesRelativeToScreen(aX, aY, aTarget);
if (aDeltaX && aDeltaY) { 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); aDeltaX = nativeScrollUnits(aTarget, aDeltaX);
aDeltaY = nativeScrollUnits(aTarget, aDeltaY); aDeltaY = nativeScrollUnits(aTarget, aDeltaY);
var msg = aDeltaX ? nativeHorizontalWheelEventMsg() : nativeVerticalWheelEventMsg(); var msg = aDeltaX
? nativeHorizontalWheelEventMsg()
: nativeVerticalWheelEventMsg();
var utils = utilsForTarget(aTarget); var utils = utilsForTarget(aTarget);
var element = elementForTarget(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; 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 // request has been successfully made to the OS. This does not necessarily
// guarantee that the OS generates the event we requested. See // guarantee that the OS generates the event we requested. See
// synthesizeNativeWheel for details on the parameters. // synthesizeNativeWheel for details on the parameters.
function synthesizeNativeWheelAndWaitForObserver(aElement, aX, aY, aDeltaX, aDeltaY, aCallback) { function synthesizeNativeWheelAndWaitForObserver(
aElement,
aX,
aY,
aDeltaX,
aDeltaY,
aCallback
) {
var observer = { var observer = {
observe(aSubject, aTopic, aData) { observe(aSubject, aTopic, aData) {
if (aCallback && aTopic == "mousescrollevent") { 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 // targets content in a subdocument, |aTarget| should be inside the
// subdocument (or the subdocument's window). See synthesizeNativeWheel for // subdocument (or the subdocument's window). See synthesizeNativeWheel for
// details on the other parameters. // 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); var targetWindow = windowForTarget(aTarget);
targetWindow.addEventListener("wheel", function(e) { targetWindow.addEventListener(
"wheel",
function(e) {
setTimeout(aCallback, 0); setTimeout(aCallback, 0);
}, {once: true}); },
{ once: true }
);
return synthesizeNativeWheel(aTarget, aX, aY, aDeltaX, aDeltaY); 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 // If the event targets content in a subdocument, |aTarget| should be inside
// the subdocument (or the subdocument's window). See synthesizeNativeWheel // the subdocument (or the subdocument's window). See synthesizeNativeWheel
// for details on the other parameters. // 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); var targetWindow = windowForTarget(aTarget);
targetWindow.addEventListener("scroll", function() { targetWindow.addEventListener(
"scroll",
function() {
setTimeout(aCallback, 0); setTimeout(aCallback, 0);
}, {capture: true, once: true}); // scroll events don't always bubble },
{ capture: true, once: true }
); // scroll events don't always bubble
return synthesizeNativeWheel(aTarget, aX, aY, aDeltaX, aDeltaY); 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 // targets content in a subdocument, |aTarget| should be inside the
// subdocument (or the subdocument window). See synthesizeNativeMouseMove for // subdocument (or the subdocument window). See synthesizeNativeMouseMove for
// details on the other parameters. // details on the other parameters.
function synthesizeNativeMouseMoveAndWaitForMoveEvent(aTarget, aX, aY, aCallback) { function synthesizeNativeMouseMoveAndWaitForMoveEvent(
aTarget,
aX,
aY,
aCallback
) {
var targetWindow = windowForTarget(aTarget); var targetWindow = windowForTarget(aTarget);
targetWindow.addEventListener("mousemove", function(e) { targetWindow.addEventListener(
"mousemove",
function(e) {
setTimeout(aCallback, 0); setTimeout(aCallback, 0);
}, {once: true}); },
{ once: true }
);
return synthesizeNativeMouseMove(aTarget, aX, aY); return synthesizeNativeMouseMove(aTarget, aX, aY);
} }
// Synthesizes a native touch event and dispatches it. aX and aY in CSS pixels // Synthesizes a native touch event and dispatches it. aX and aY in CSS pixels
// relative to the top-left of |aTarget|'s bounding rect. // 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 pt = coordinatesRelativeToScreen(aX, aY, aTarget);
var utils = utilsForTarget(aTarget); var utils = utilsForTarget(aTarget);
utils.sendNativeTouchPoint(aTouchId, aType, pt.x, pt.y, 1, 90, aObserver); 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 // aObserver is the observer that will get registered on the very last
// synthesizeNativeTouch call this function makes. // synthesizeNativeTouch call this function makes.
// aTouchIds is an array holding the touch ID values of each "finger". // 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 // We use lastNonNullValue to figure out which synthesizeNativeTouch call
// will be the last one we make, so that we can register aObserver on it. // will be the last one we make, so that we can register aObserver on it.
var lastNonNullValue = -1; var lastNonNullValue = -1;
@ -284,12 +385,14 @@ function* synthesizeNativeTouchSequences(aTarget, aPositions, aObserver = null,
if (aPositions[i].length != aTouchIds.length) { if (aPositions[i].length != aTouchIds.length) {
throw new Error( throw new Error(
`aPositions[${i}] did not have the expected number of positions; ` + `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++) { for (let j = 0; j < aTouchIds.length; j++) {
if (aPositions[i][j] != null) { 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 { } else {
// synthesize the touch-up. If this is the last call we're going to // synthesize the touch-up. If this is the last call we're going to
// make, pass the observer as well // make, pass the observer as well
var thisIndex = ((i - yields) * aTouchIds.length) + j; var thisIndex = (i - yields) * aTouchIds.length + j;
var observer = (lastSynthesizeCall == thisIndex) ? aObserver : null; var observer = lastSynthesizeCall == thisIndex ? aObserver : null;
synthesizeNativeTouch(aTarget, currentPositions[j].x, currentPositions[j].y, SpecialPowers.DOMWindowUtils.TOUCH_REMOVE, observer, aTouchIds[j]); synthesizeNativeTouch(
aTarget,
currentPositions[j].x,
currentPositions[j].y,
SpecialPowers.DOMWindowUtils.TOUCH_REMOVE,
observer,
aTouchIds[j]
);
currentPositions[j] = null; currentPositions[j] = null;
} }
} else { } 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]; 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 // 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 // "apz.touch_start_tolerance" is set to 0, or some of the touchmove will get
// consumed to overcome the panning threshold. // 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 steps = Math.max(Math.abs(aDeltaX), Math.abs(aDeltaY));
var positions = [[{ x: aX, y: aY }]]; var positions = [[{ x: aX, y: aY }]];
for (var i = 1; i < steps; i++) { for (var i = 1; i < steps; i++) {
@ -355,7 +480,12 @@ function synthesizeNativeTouchDrag(aTarget, aX, aY, aDeltaX, aDeltaY, aObserver
positions.push([pos]); positions.push([pos]);
} }
positions.push([{ x: aX + aDeltaX, y: aY + aDeltaY }]); 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(); var yielded = continuation.next();
while (!yielded.done) { while (!yielded.done) {
yielded = continuation.next(); yielded = continuation.next();
@ -365,7 +495,9 @@ function synthesizeNativeTouchDrag(aTarget, aX, aY, aDeltaX, aDeltaY, aObserver
function synthesizeNativeTap(aElement, aX, aY, aObserver = null) { function synthesizeNativeTap(aElement, aX, aY, aObserver = null) {
var pt = coordinatesRelativeToScreen(aX, aY, aElement); 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); utils.sendNativeTouchTap(pt.x, pt.y, false, aObserver);
return true; return true;
} }
@ -380,10 +512,26 @@ function synthesizeNativeMouseEvent(aTarget, aX, aY, aType, aObserver = null) {
function synthesizeNativeClick(aElement, aX, aY, aObserver = null) { function synthesizeNativeClick(aElement, aX, aY, aObserver = null) {
var pt = coordinatesRelativeToScreen(aX, aY, aElement); var pt = coordinatesRelativeToScreen(aX, aY, aElement);
var utils = SpecialPowers.getDOMWindowUtils(aElement.ownerDocument.defaultView); var utils = SpecialPowers.getDOMWindowUtils(
utils.sendNativeMouseEvent(pt.x, pt.y, nativeMouseDownEventMsg(), 0, aElement, function() { aElement.ownerDocument.defaultView
utils.sendNativeMouseEvent(pt.x, pt.y, nativeMouseUpEventMsg(), 0, aElement, aObserver); );
}); utils.sendNativeMouseEvent(
pt.x,
pt.y,
nativeMouseDownEventMsg(),
0,
aElement,
function() {
utils.sendNativeMouseEvent(
pt.x,
pt.y,
nativeMouseUpEventMsg(),
0,
aElement,
aObserver
);
}
);
return true; 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 // 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 // wheel event, otherwise there is a chance they might get reordered, and
// we have the transaction problem again. // we have the transaction problem again.
function moveMouseAndScrollWheelOver(target, dx, dy, testDriver, waitForScroll = true) { function moveMouseAndScrollWheelOver(
return synthesizeNativeMouseMoveAndWaitForMoveEvent(target, dx, dy, function() { target,
dx,
dy,
testDriver,
waitForScroll = true
) {
return synthesizeNativeMouseMoveAndWaitForMoveEvent(
target,
dx,
dy,
function() {
if (waitForScroll) { if (waitForScroll) {
synthesizeNativeWheelAndWaitForScrollEvent(target, dx, dy, 0, -10, testDriver); synthesizeNativeWheelAndWaitForScrollEvent(
target,
dx,
dy,
0,
-10,
testDriver
);
} else { } else {
synthesizeNativeWheelAndWaitForWheelEvent(target, dx, dy, 0, -10, testDriver); synthesizeNativeWheelAndWaitForWheelEvent(
target,
dx,
dy,
0,
-10,
testDriver
);
} }
}); }
);
} }
// Same as moveMouseAndScrollWheelOver, but returns a promise instead of taking // Same as moveMouseAndScrollWheelOver, but returns a promise instead of taking
// a callback function. Eventually we should convert all these callback-taking // a callback function. Eventually we should convert all these callback-taking
// functions into promise-producing functions but for now this is a stopgap. // 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 => { return new Promise(resolve => {
moveMouseAndScrollWheelOver(target, dx, dy, resolve, waitForScroll); 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 // Note: helper_scrollbar_snap_bug1501062.html contains a copy of this code
// with modifications. Fixes here should be copied there if appropriate. // with modifications. Fixes here should be copied there if appropriate.
// |target| can be an element (for subframes) or a window (for root frames). // |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 targetElement = elementForTarget(target);
var w = {}, h = {}; var w = {},
h = {};
utilsForTarget(target).getScrollbarSizes(targetElement, w, h); utilsForTarget(target).getScrollbarSizes(targetElement, w, h);
var verticalScrollbarWidth = w.value; var verticalScrollbarWidth = w.value;
if (verticalScrollbarWidth == 0) { if (verticalScrollbarWidth == 0) {
@ -435,24 +619,62 @@ function* dragVerticalScrollbar(target, testDriver, distance = 20, increment = 5
} }
var upArrowHeight = verticalScrollbarWidth; // assume square scrollbar buttons 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 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 // 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 // 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 // drag vertically by |increment| until we reach the specified distance
for (var y = increment; y < distance; y += increment) { 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 // and return a generator to call afterwards to finish up the drag
return function*() { return function*() {
dump("Finishing drag of #" + targetElement.id + "\n"); dump("Finishing drag of #" + targetElement.id + "\n");
yield synthesizeNativeMouseEvent(target, mouseX, mouseY + distance, nativeMouseUpEventMsg(), testDriver); yield synthesizeNativeMouseEvent(
target,
mouseX,
mouseY + distance,
nativeMouseUpEventMsg(),
testDriver
);
}; };
} }

View file

@ -24,35 +24,55 @@ function convertEntries(entries) {
function parseRect(str) { function parseRect(str) {
var pieces = str.replace(/[()\s]+/g, "").split(","); var pieces = str.replace(/[()\s]+/g, "").split(",");
SimpleTest.is(pieces.length, 4, "expected string of form (x,y,w,h)"); SimpleTest.is(pieces.length, 4, "expected string of form (x,y,w,h)");
return { x: parseInt(pieces[0]), return {
x: parseInt(pieces[0]),
y: parseInt(pieces[1]), y: parseInt(pieces[1]),
w: parseInt(pieces[2]), w: parseInt(pieces[2]),
h: parseInt(pieces[3]) }; h: parseInt(pieces[3]),
};
} }
// These functions expect rects with fields named x/y/w/h, such as // These functions expect rects with fields named x/y/w/h, such as
// that returned by parseRect(). // that returned by parseRect().
function rectContains(haystack, needle) { function rectContains(haystack, needle) {
return haystack.x <= needle.x return (
&& haystack.y <= needle.y haystack.x <= needle.x &&
&& (haystack.x + haystack.w) >= (needle.x + needle.w) haystack.y <= needle.y &&
&& (haystack.y + haystack.h) >= (needle.y + needle.h); haystack.x + haystack.w >= needle.x + needle.w &&
haystack.y + haystack.h >= needle.y + needle.h
);
} }
function rectToString(rect) { function rectToString(rect) {
return "(" + rect.x + "," + rect.y + "," + rect.w + "," + rect.h + ")"; return "(" + rect.x + "," + rect.y + "," + rect.w + "," + rect.h + ")";
} }
function assertRectContainment(haystackRect, haystackDesc, needleRect, needleDesc) { function assertRectContainment(
SimpleTest.ok(rectContains(haystackRect, needleRect), haystackRect,
haystackDesc + " " + rectToString(haystackRect) + " should contain " + haystackDesc,
needleDesc + " " + rectToString(needleRect)); needleRect,
needleDesc
) {
SimpleTest.ok(
rectContains(haystackRect, needleRect),
haystackDesc +
" " +
rectToString(haystackRect) +
" should contain " +
needleDesc +
" " +
rectToString(needleRect)
);
} }
function getPropertyAsRect(scrollFrames, scrollId, prop) { function getPropertyAsRect(scrollFrames, scrollId, prop) {
SimpleTest.ok(scrollId in scrollFrames, SimpleTest.ok(
"expected scroll frame data for scroll id " + scrollId); scrollId in scrollFrames,
"expected scroll frame data for scroll id " + scrollId
);
var scrollFrameData = scrollFrames[scrollId]; var scrollFrameData = scrollFrames[scrollId];
SimpleTest.ok("displayport" in scrollFrameData, SimpleTest.ok(
"expected a " + prop + " for scroll id " + scrollId); "displayport" in scrollFrameData,
"expected a " + prop + " for scroll id " + scrollId
);
var value = scrollFrameData[prop]; var value = scrollFrameData[prop];
return parseRect(value); return parseRect(value);
} }
@ -68,7 +88,9 @@ function convertScrollFrameData(scrollFrames) {
function convertBuckets(buckets) { function convertBuckets(buckets) {
var result = {}; var result = {};
for (var i = 0; i < buckets.length; ++i) { 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; 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 // Takes something like "matrix(1, 0, 0, 1, 234.024, 528.29023)"" and returns a number array
function parseTransform(transform) { function parseTransform(transform) {
return /matrix\((.*),(.*),(.*),(.*),(.*),(.*)\)/.exec(transform) return /matrix\((.*),(.*),(.*),(.*),(.*),(.*)\)/
.slice(1).map(parseFloat); .exec(transform)
.slice(1)
.map(parseFloat);
} }
function isTransformClose(a, b, name) { 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++) { 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);
} }
} }
@ -135,7 +163,8 @@ function buildApzcTree(paint) {
// Given an APZC tree produced by buildApzcTree, return the RCD node in // Given an APZC tree produced by buildApzcTree, return the RCD node in
// the tree, or null if there was none. // the tree, or null if there was none.
function findRcdNode(apzcTree) { function findRcdNode(apzcTree) {
if (apzcTree.isRootContent) { // isRootContent will be undefined or "1" if (apzcTree.isRootContent) {
// isRootContent will be undefined or "1"
return apzcTree; return apzcTree;
} }
for (var i = 0; i < apzcTree.children.length; i++) { 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 // Assumes |elementId| will be present in the content description for the
// element, and not in the content descriptions of other elements. // element, and not in the content descriptions of other elements.
function isLayerized(elementId) { function isLayerized(elementId) {
var contentTestData = SpecialPowers.getDOMWindowUtils(window).getContentAPZTestData(); var contentTestData = SpecialPowers.getDOMWindowUtils(
window
).getContentAPZTestData();
var nonEmptyBucket = getLastNonemptyBucket(contentTestData.paints); var nonEmptyBucket = getLastNonemptyBucket(contentTestData.paints);
ok(nonEmptyBucket != null, "expected at least one nonempty paint"); ok(nonEmptyBucket != null, "expected at least one nonempty paint");
var seqno = nonEmptyBucket.sequenceNumber; var seqno = nonEmptyBucket.sequenceNumber;
@ -170,14 +201,19 @@ function isLayerized(elementId) {
function promiseApzRepaintsFlushed(aWindow = window) { function promiseApzRepaintsFlushed(aWindow = window) {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
var repaintDone = function() { var repaintDone = function() {
SpecialPowers.Services.obs.removeObserver(repaintDone, "apz-repaints-flushed"); SpecialPowers.Services.obs.removeObserver(
repaintDone,
"apz-repaints-flushed"
);
setTimeout(resolve, 0); setTimeout(resolve, 0);
}; };
SpecialPowers.Services.obs.addObserver(repaintDone, "apz-repaints-flushed"); SpecialPowers.Services.obs.addObserver(repaintDone, "apz-repaints-flushed");
if (SpecialPowers.getDOMWindowUtils(aWindow).flushApzRepaints()) { if (SpecialPowers.getDOMWindowUtils(aWindow).flushApzRepaints()) {
dump("Flushed APZ repaints, waiting for callback...\n"); dump("Flushed APZ repaints, waiting for callback...\n");
} else { } 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(); repaintDone();
} }
}); });
@ -248,18 +284,24 @@ function runSubtestsSeriallyInFreshWindows(aSubtests) {
// If the "apz.subtest" pref has been set, only a single subtest whose name matches // If the "apz.subtest" pref has been set, only a single subtest whose name matches
// the pref's value (if any) will be run. // 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() { function advanceSubtestExecution() {
var test = aSubtests[testIndex]; var test = aSubtests[testIndex];
if (w) { if (w) {
// Run any cleanup functions registered in the subtest // 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(); w.ApzCleanup.execute();
} }
if (typeof test.dp_suppression != "undefined") { if (typeof test.dp_suppression != "undefined") {
// We modified the suppression when starting the test, so now undo that. // 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) { if (test.prefs) {
// We pushed some prefs for this test, pop them, and re-invoke // 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"]; let recognizedProps = ["file", "prefs", "dp_suppression", "onload"];
for (let prop in test) { for (let prop in test) {
if (!recognizedProps.includes(prop)) { if (!recognizedProps.includes(prop)) {
SimpleTest.ok(false, "Subtest " + test.file + " has unrecognized property '" + prop + "'"); SimpleTest.ok(
setTimeout(function() { advanceSubtestExecution(); }, 0); false,
"Subtest " + test.file + " has unrecognized property '" + prop + "'"
);
setTimeout(function() {
advanceSubtestExecution();
}, 0);
return; return;
} }
} }
if (onlyOneSubtest && onlyOneSubtest != test.file) { if (onlyOneSubtest && onlyOneSubtest != test.file) {
SimpleTest.ok(true, "Skipping " + test.file + " because only " + onlyOneSubtest + " is being run"); SimpleTest.ok(
setTimeout(function() { advanceSubtestExecution(); }, 0); true,
"Skipping " +
test.file +
" because only " +
onlyOneSubtest +
" is being run"
);
setTimeout(function() {
advanceSubtestExecution();
}, 0);
return; return;
} }
@ -306,7 +362,9 @@ function runSubtestsSeriallyInFreshWindows(aSubtests) {
// unsuppression can trigger a repaint which interferes with the test, so // unsuppression can trigger a repaint which interferes with the test, so
// to avoid that we can force the displayport to be unsuppressed for the // to avoid that we can force the displayport to be unsuppressed for the
// entire test which is more deterministic. // entire test which is more deterministic.
SpecialPowers.getDOMWindowUtils(window).respectDisplayPortSuppression(test.dp_suppression); SpecialPowers.getDOMWindowUtils(window).respectDisplayPortSuppression(
test.dp_suppression
);
} }
function spawnTest(aFile) { function spawnTest(aFile) {
@ -314,21 +372,39 @@ function runSubtestsSeriallyInFreshWindows(aSubtests) {
w.subtestDone = advanceSubtestExecution; w.subtestDone = advanceSubtestExecution;
w.isApzSubtest = true; w.isApzSubtest = true;
w.SimpleTest = SimpleTest; w.SimpleTest = SimpleTest;
w.dump = function(msg) { return dump(aFile + " | " + msg); }; w.dump = function(msg) {
w.is = function(a, b, msg) { return is(a, b, aFile + " | " + msg); }; return dump(aFile + " | " + msg);
w.isfuzzy = function(a, b, eps, msg) { return isfuzzy(a, b, eps, 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) { w.ok = function(cond, msg) {
arguments[1] = aFile + " | " + msg; arguments[1] = aFile + " | " + msg;
// Forward all arguments to SimpleTest.ok where we will check that ok() was // Forward all arguments to SimpleTest.ok where we will check that ok() was
// called with at most 2 arguments. // called with at most 2 arguments.
return SimpleTest.ok.apply(SimpleTest, arguments); return SimpleTest.ok.apply(SimpleTest, arguments);
}; };
w.todo_is = function(a, b, msg) { return todo_is(a, b, aFile + " | " + msg); }; w.todo_is = function(a, b, msg) {
w.todo = function(cond, msg) { return todo(cond, aFile + " | " + msg); }; return todo_is(a, b, aFile + " | " + msg);
};
w.todo = function(cond, msg) {
return todo(cond, aFile + " | " + msg);
};
if (test.onload) { 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) { function urlResolves(url) {
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
request.open("GET", url, false); request.open("GET", url, false);
@ -336,8 +412,13 @@ function runSubtestsSeriallyInFreshWindows(aSubtests) {
return request.status !== 404; return request.status !== 404;
} }
if (!urlResolves(subtestUrl)) { if (!urlResolves(subtestUrl)) {
SimpleTest.ok(false, "Subtest URL " + subtestUrl + " does not resolve. " + SimpleTest.ok(
"Be sure it's present in the support-files section of mochitest.ini."); false,
"Subtest URL " +
subtestUrl +
" does not resolve. " +
"Be sure it's present in the support-files section of mochitest.ini."
);
reject(); reject();
return undefined; return undefined;
} }
@ -347,7 +428,7 @@ function runSubtestsSeriallyInFreshWindows(aSubtests) {
if (test.prefs) { if (test.prefs) {
// Got some prefs for this subtest, push them // Got some prefs for this subtest, push them
SpecialPowers.pushPrefEnv({"set": test.prefs}, function() { SpecialPowers.pushPrefEnv({ set: test.prefs }, function() {
w = spawnTest(test.file); w = spawnTest(test.file);
}); });
} else { } else {
@ -362,7 +443,7 @@ function runSubtestsSeriallyInFreshWindows(aSubtests) {
} }
function pushPrefs(prefs) { function pushPrefs(prefs) {
return SpecialPowers.pushPrefEnv({"set": prefs}); return SpecialPowers.pushPrefEnv({ set: prefs });
} }
async function waitUntilApzStable() { async function waitUntilApzStable() {
@ -379,7 +460,9 @@ async function waitUntilApzStable() {
/* eslint-env mozilla/frame-script */ /* eslint-env mozilla/frame-script */
function parentProcessFlush() { function parentProcessFlush() {
function apzFlush() { 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"); var topWin = Services.wm.getMostRecentWindow("navigator:browser");
if (!topWin) { if (!topWin) {
topWin = Services.wm.getMostRecentWindow("navigator:geckoview"); topWin = Services.wm.getMostRecentWindow("navigator:geckoview");
@ -393,15 +476,21 @@ async function waitUntilApzStable() {
}; };
var flushRepaint = function() { var flushRepaint = function() {
if (topUtils.isMozAfterPaintPending) { if (topUtils.isMozAfterPaintPending) {
topWin.addEventListener("MozAfterPaint", flushRepaint, { once: true }); topWin.addEventListener("MozAfterPaint", flushRepaint, {
once: true,
});
return; return;
} }
Services.obs.addObserver(repaintDone, "apz-repaints-flushed"); Services.obs.addObserver(repaintDone, "apz-repaints-flushed");
if (topUtils.flushApzRepaints()) { if (topUtils.flushApzRepaints()) {
dump("Parent process: flushed APZ repaints, waiting for callback...\n"); dump(
"Parent process: flushed APZ repaints, waiting for callback...\n"
);
} else { } 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(); repaintDone();
} }
}; };
@ -420,7 +509,9 @@ async function waitUntilApzStable() {
// This is the first time waitUntilApzStable is being called, do initialization // This is the first time waitUntilApzStable is being called, do initialization
if (typeof waitUntilApzStable.chromeHelper == "undefined") { if (typeof waitUntilApzStable.chromeHelper == "undefined") {
waitUntilApzStable.chromeHelper = SpecialPowers.loadChromeScript(parentProcessFlush); waitUntilApzStable.chromeHelper = SpecialPowers.loadChromeScript(
parentProcessFlush
);
ApzCleanup.register(() => { ApzCleanup.register(() => {
waitUntilApzStable.chromeHelper.sendAsyncMessage("cleanup", null); waitUntilApzStable.chromeHelper.sendAsyncMessage("cleanup", null);
waitUntilApzStable.chromeHelper.destroy(); waitUntilApzStable.chromeHelper.destroy();
@ -510,7 +601,10 @@ function runContinuation(testFunction) {
try { try {
driveTest(); driveTest();
} catch (ex) { } 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(); ret = await asyncContinuation.next();
} }
} catch (ex) { } 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; throw ex;
} }
}; };
@ -551,7 +648,9 @@ function runAsyncContinuation(testFunction) {
function getSnapshot(rect) { function getSnapshot(rect) {
function parentProcessSnapshot() { function parentProcessSnapshot() {
addMessageListener("snapshot", function(parentRect) { 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"); var topWin = Services.wm.getMostRecentWindow("navigator:browser");
if (!topWin) { if (!topWin) {
topWin = Services.wm.getMostRecentWindow("navigator:geckoview"); topWin = Services.wm.getMostRecentWindow("navigator:geckoview");
@ -563,21 +662,36 @@ function getSnapshot(rect) {
parentRect.y -= topWin.mozInnerScreenY; parentRect.y -= topWin.mozInnerScreenY;
// take the snapshot // 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.width = parentRect.w;
canvas.height = parentRect.h; canvas.height = parentRect.h;
var ctx = canvas.getContext("2d"); 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)", "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(); return canvas.toDataURL();
}); });
} }
if (typeof getSnapshot.chromeHelper == "undefined") { if (typeof getSnapshot.chromeHelper == "undefined") {
// This is the first time getSnapshot is being called; do initialization // This is the first time getSnapshot is being called; do initialization
getSnapshot.chromeHelper = SpecialPowers.loadChromeScript(parentProcessSnapshot); getSnapshot.chromeHelper = SpecialPowers.loadChromeScript(
ApzCleanup.register(function() { getSnapshot.chromeHelper.destroy(); }); parentProcessSnapshot
);
ApzCleanup.register(function() {
getSnapshot.chromeHelper.destroy();
});
} }
return getSnapshot.chromeHelper.sendQuery("snapshot", JSON.stringify(rect)); return getSnapshot.chromeHelper.sendQuery("snapshot", JSON.stringify(rect));
@ -641,8 +755,8 @@ function injectScript(aScript, aWindow = window) {
function getHitTestConfig() { function getHitTestConfig() {
if (!("hitTestConfig" in window)) { if (!("hitTestConfig" in window)) {
var utils = SpecialPowers.getDOMWindowUtils(window); var utils = SpecialPowers.getDOMWindowUtils(window);
var isWebRender = (utils.layerManagerType == "WebRender"); var isWebRender = utils.layerManagerType == "WebRender";
var isWindows = (getPlatform() == "windows"); var isWindows = getPlatform() == "windows";
window.hitTestConfig = { utils, isWebRender, isWindows }; window.hitTestConfig = { utils, isWebRender, isWindows };
} }
return window.hitTestConfig; return window.hitTestConfig;
@ -656,7 +770,7 @@ function centerOf(element) {
element = document.getElementById(element); element = document.getElementById(element);
} }
var bounds = element.getBoundingClientRect(); 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. // Peform a compositor hit test at the given point and return the result.
@ -666,11 +780,30 @@ function centerOf(element) {
function hitTest(point) { function hitTest(point) {
var utils = getHitTestConfig().utils; var utils = getHitTestConfig().utils;
dump("Hit-testing point (" + point.x + ", " + point.y + ")\n"); 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(); 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]; 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. // Returns a canonical stringification of the hitInfo bitfield.
@ -693,8 +826,18 @@ function hitInfoToString(hitInfo) {
// Takes an object returned by hitTest, along with the expected values, and // Takes an object returned by hitTest, along with the expected values, and
// asserts that they match. Notably, it uses hitInfoToString to provide a // asserts that they match. Notably, it uses hitInfoToString to provide a
// more useful message for the case that the hit info doesn't match // more useful message for the case that the hit info doesn't match
function checkHitResult(hitResult, expectedHitInfo, expectedScrollId, expectedLayersId, desc) { function checkHitResult(
is(hitInfoToString(hitResult.hitInfo), hitInfoToString(expectedHitInfo), desc + " hit info"); hitResult,
expectedHitInfo,
expectedScrollId,
expectedLayersId,
desc
) {
is(
hitInfoToString(hitResult.hitInfo),
hitInfoToString(expectedHitInfo),
desc + " hit info"
);
is(hitResult.scrollId, expectedScrollId, desc + " scrollid"); is(hitResult.scrollId, expectedScrollId, desc + " scrollid");
is(hitResult.layersId, expectedLayersId, desc + " layersid"); is(hitResult.layersId, expectedLayersId, desc + " layersid");
} }
@ -743,8 +886,12 @@ function hitTestScrollbar(params) {
// coordinates for hit-testing we need to account for this. We assume the // 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 // buttons are square, and so can use the scrollbar width/height to estimate
// the size of the buttons // the size of the buttons
var scrollbarArrowButtonHeight = config.isWindows ? verticalScrollbarWidth : 0; var scrollbarArrowButtonHeight = config.isWindows
var scrollbarArrowButtonWidth = config.isWindows ? horizontalScrollbarHeight : 0; ? verticalScrollbarWidth
: 0;
var scrollbarArrowButtonWidth = config.isWindows
? horizontalScrollbarHeight
: 0;
// Compute the expected hit result flags. // Compute the expected hit result flags.
// The direction flag (APZHitResultFlags.SCROLLBAR_VERTICAL) is added in // The direction flag (APZHitResultFlags.SCROLLBAR_VERTICAL) is added in
@ -774,37 +921,51 @@ function hitTestScrollbar(params) {
} }
} }
var scrollframeMsg = (params.layerState == LayerState.ACTIVE) var scrollframeMsg =
? "active scrollframe" : "inactive scrollframe"; params.layerState == LayerState.ACTIVE
? "active scrollframe"
: "inactive scrollframe";
// Hit-test the targeted areas, assuming we don't have overlay scrollbars // Hit-test the targeted areas, assuming we don't have overlay scrollbars
// with zero dimensions. // with zero dimensions.
if (params.directions.vertical && verticalScrollbarWidth > 0) { if (params.directions.vertical && verticalScrollbarWidth > 0) {
var verticalScrollbarPoint = { var verticalScrollbarPoint = {
x: boundingClientRect.right - (verticalScrollbarWidth / 2), x: boundingClientRect.right - verticalScrollbarWidth / 2,
y: (params.trackLocation == ScrollbarTrackLocation.START) y:
? (boundingClientRect.y + scrollbarArrowButtonHeight + 5) params.trackLocation == ScrollbarTrackLocation.START
: (boundingClientRect.bottom - horizontalScrollbarHeight - scrollbarArrowButtonHeight - 5), ? boundingClientRect.y + scrollbarArrowButtonHeight + 5
: boundingClientRect.bottom -
horizontalScrollbarHeight -
scrollbarArrowButtonHeight -
5,
}; };
checkHitResult(hitTest(verticalScrollbarPoint), checkHitResult(
hitTest(verticalScrollbarPoint),
expectedHitInfo | APZHitResultFlags.SCROLLBAR_VERTICAL, expectedHitInfo | APZHitResultFlags.SCROLLBAR_VERTICAL,
params.expectedScrollId, params.expectedScrollId,
params.expectedLayersId, params.expectedLayersId,
scrollframeMsg + " - vertical scrollbar"); scrollframeMsg + " - vertical scrollbar"
);
} }
if (params.directions.horizontal && horizontalScrollbarHeight > 0) { if (params.directions.horizontal && horizontalScrollbarHeight > 0) {
var horizontalScrollbarPoint = { var horizontalScrollbarPoint = {
x: (params.trackLocation == ScrollbarTrackLocation.START) x:
? (boundingClientRect.x + scrollbarArrowButtonWidth + 5) params.trackLocation == ScrollbarTrackLocation.START
: (boundingClientRect.right - verticalScrollbarWidth - scrollbarArrowButtonWidth - 5), ? boundingClientRect.x + scrollbarArrowButtonWidth + 5
y: boundingClientRect.bottom - (horizontalScrollbarHeight / 2), : boundingClientRect.right -
verticalScrollbarWidth -
scrollbarArrowButtonWidth -
5,
y: boundingClientRect.bottom - horizontalScrollbarHeight / 2,
}; };
checkHitResult(hitTest(horizontalScrollbarPoint), checkHitResult(
hitTest(horizontalScrollbarPoint),
expectedHitInfo, expectedHitInfo,
params.expectedScrollId, params.expectedScrollId,
params.expectedLayersId, params.expectedLayersId,
scrollframeMsg + " - horizontal scrollbar"); scrollframeMsg + " - horizontal scrollbar"
);
} }
} }
@ -862,7 +1023,16 @@ var ApzCleanup = {
try { try {
func(); func();
} catch (ex) { } 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 +
"]"
);
} }
} }
}, },

View file

@ -1,11 +1,14 @@
add_task(async function test_main() { add_task(async function test_main() {
function httpURL(filename) { function httpURL(filename) {
let chromeURL = getRootDirectory(gTestPath) + 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 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 // Each of these URLs will get opened in a new top-level browser window that
// is fission-enabled. // 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 // We import the JSM here so that we can install functions on the class
// below. // below.
const { FissionTestHelperParent } = ChromeUtils.import( const { FissionTestHelperParent } = ChromeUtils.import(
getRootDirectory(gTestPath) + "FissionTestHelperParent.jsm"); getRootDirectory(gTestPath) + "FissionTestHelperParent.jsm"
);
FissionTestHelperParent.SimpleTest = SimpleTest; FissionTestHelperParent.SimpleTest = SimpleTest;
ChromeUtils.registerWindowActor("FissionTestHelper", { ChromeUtils.registerWindowActor("FissionTestHelper", {
@ -36,7 +42,7 @@ add_task(async function test_main() {
child: { child: {
moduleURI: getRootDirectory(gTestPath) + "FissionTestHelperChild.jsm", moduleURI: getRootDirectory(gTestPath) + "FissionTestHelperChild.jsm",
events: { events: {
"DOMWindowCreated": {}, DOMWindowCreated: {},
}, },
}, },
allFrames: true, allFrames: true,
@ -50,12 +56,15 @@ add_task(async function test_main() {
// completion. // completion.
await BrowserTestUtils.withNewTab( await BrowserTestUtils.withNewTab(
{ gBrowser: fissionWindow.gBrowser, url }, { gBrowser: fissionWindow.gBrowser, url },
async (browser) => { async browser => {
let tabActor = browser.browsingContext.currentWindowGlobal.getActor("FissionTestHelper"); let tabActor = browser.browsingContext.currentWindowGlobal.getActor(
"FissionTestHelper"
);
let donePromise = tabActor.getTestCompletePromise(); let donePromise = tabActor.getTestCompletePromise();
tabActor.startTest(); tabActor.startTest();
await donePromise; await donePromise;
}); }
);
dump(`Finished test ${url}\n`); dump(`Finished test ${url}\n`);
} }

View file

@ -28,12 +28,16 @@ function promiseOneEvent(eventType, filter) {
try { try {
success = filter(e); success = filter(e);
} catch (ex) { } catch (ex) {
dump(`ERROR: Filter passed to promiseOneEvent threw exception: ${ex}\n`); dump(
`ERROR: Filter passed to promiseOneEvent threw exception: ${ex}\n`
);
reject(); reject();
return; return;
} }
} else { } 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(); reject();
return; return;
} }
@ -54,14 +58,18 @@ function promiseOneEvent(eventType, filter) {
function loadOOPIFrame(iframeElementId, iframePage) { function loadOOPIFrame(iframeElementId, iframePage) {
return async function() { return async function() {
if (window.location.href.startsWith("https://example.com/")) { 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"); 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) { let loadPromise = promiseOneEvent("OOPIF:Load", function(e) {
return (typeof e.data.content) == "string" && return typeof e.data.content == "string" && e.data.content == url;
e.data.content == url;
}); });
let elem = document.getElementById(iframeElementId); let elem = document.getElementById(iframeElementId);
elem.src = url; elem.src = url;

View file

@ -43,7 +43,9 @@ function parseDisplayList(lines) {
root = layerObject; 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) { if (!matches) {
dump("Failed to match: " + line + "\n"); dump("Failed to match: " + line + "\n");
continue; continue;
@ -62,7 +64,8 @@ function parseDisplayList(lines) {
layerObject.contentDescriptor = matches[5]; layerObject.contentDescriptor = matches[5];
layerObject.z = matches[7]; layerObject.z = matches[7];
var rest = matches[8]; 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.layer = matches[10];
} }
layerObject.rest = rest; layerObject.rest = rest;
@ -115,9 +118,12 @@ function getDataURI(str) {
return str; return str;
} }
var matches = str.match("data:image/lz4bgra;base64,([0-9]+),([0-9]+),([0-9]+),(.*)"); var matches = str.match(
if (!matches) "data:image/lz4bgra;base64,([0-9]+),([0-9]+),([0-9]+),(.*)"
);
if (!matches) {
return null; return null;
}
var canvas = document.createElement("canvas"); var canvas = document.createElement("canvas");
var w = parseInt(matches[1]); var w = parseInt(matches[1]);
@ -212,8 +218,10 @@ function parseLayers(layersDumpLines) {
} }
var rect = [ var rect = [
parseFloat(rectMatches[1]), parseFloat(rectMatches[2]), parseFloat(rectMatches[1]),
parseFloat(rectMatches[3]), parseFloat(rectMatches[4]), parseFloat(rectMatches[2]),
parseFloat(rectMatches[3]),
parseFloat(rectMatches[4]),
]; ];
return rect; return rect;
} }
@ -228,14 +236,18 @@ function parseLayers(layersDumpLines) {
var region = []; var region = [];
str = trim(str.substring(1, str.length - 1)); str = trim(str.substring(1, str.length - 1));
while (str != "") { while (str != "") {
var rectMatches = str.match("^\\(x=(.*?), y=(.*?), w=(.*?), h=(.*?)\\);(.*)$"); var rectMatches = str.match(
"^\\(x=(.*?), y=(.*?), w=(.*?), h=(.*?)\\);(.*)$"
);
if (!rectMatches) { if (!rectMatches) {
return null; return null;
} }
var rect = [ var rect = [
parseFloat(rectMatches[1]), parseFloat(rectMatches[2]), parseFloat(rectMatches[1]),
parseFloat(rectMatches[3]), parseFloat(rectMatches[4]), parseFloat(rectMatches[2]),
parseFloat(rectMatches[3]),
parseFloat(rectMatches[4]),
]; ];
str = trim(rectMatches[5]); str = trim(rectMatches[5]);
region.push(rect); region.push(rect);
@ -271,16 +283,21 @@ function parseLayers(layersDumpLines) {
var surfaceMatches = line.match("(\\s*)Surface: (.*)"); var surfaceMatches = line.match("(\\s*)Surface: (.*)");
if (surfaceMatches) { if (surfaceMatches) {
let indentation = Math.floor(matches[1].length / 2); 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]; var surfaceURI = surfaceMatches[2];
if (parent.surfaceURI != null) { 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; parent.surfaceURI = surfaceURI;
// Look for the buffer-rect offset // 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); let matches = contentHostLine.match(LAYERS_LINE_REGEX);
if (matches) { if (matches) {
var contentHostRest = matches[4]; var contentHostRest = matches[4];
@ -304,11 +321,13 @@ function parseLayers(layersDumpLines) {
continue; // Something like a texturehost dump. Safe to ignore continue; // Something like a texturehost dump. Safe to ignore
} }
if (matches[2].includes("TiledContentHost") || if (
matches[2].includes("TiledContentHost") ||
matches[2].includes("ContentHost") || matches[2].includes("ContentHost") ||
matches[2].includes("ContentClient") || matches[2].includes("ContentClient") ||
matches[2].includes("MemoryTextureHost") || matches[2].includes("MemoryTextureHost") ||
matches[2].includes("ImageHost")) { matches[2].includes("ImageHost")
) {
continue; // We're already pretty good at visualizing these continue; // We're already pretty good at visualizing these
} }
@ -414,10 +433,15 @@ function parseLayers(layersDumpLines) {
// Compute screenTransformX/screenTransformY // Compute screenTransformX/screenTransformY
// TODO Fully support transforms // TODO Fully support transforms
if (layerObject["shadow-transform"] && layerObject.transform) { 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; var currIndentation = indentation - 1;
while (currIndentation >= 0) { while (currIndentation >= 0) {
var transform = objectAtIndentation[currIndentation]["shadow-transform"] || objectAtIndentation[currIndentation].transform; var transform =
objectAtIndentation[currIndentation]["shadow-transform"] ||
objectAtIndentation[currIndentation].transform;
if (transform) { if (transform) {
layerObject["screen-transform"][0] += transform[2][0]; layerObject["screen-transform"][0] += transform[2][0];
layerObject["screen-transform"][1] += transform[2][1]; layerObject["screen-transform"][1] += transform[2][1];
@ -432,7 +456,15 @@ function parseLayers(layersDumpLines) {
// dump("OBJECTS: " + JSON.stringify(root) + "\n"); // dump("OBJECTS: " + JSON.stringify(root) + "\n");
return root; return root;
} }
function populateLayers(root, displayList, pane, previewParent, hasSeenRoot, contentScale, rootPreviewParent) { function populateLayers(
root,
displayList,
pane,
previewParent,
hasSeenRoot,
contentScale,
rootPreviewParent
) {
contentScale = contentScale || 1; contentScale = contentScale || 1;
rootPreviewParent = rootPreviewParent || previewParent; rootPreviewParent = rootPreviewParent || previewParent;
@ -521,7 +553,8 @@ function populateLayers(root, displayList, pane, previewParent, hasSeenRoot, con
}); });
layerViewportMatrix[4] += -clip[0]; layerViewportMatrix[4] += -clip[0];
layerViewportMatrix[5] += -clip[1]; 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) { if (root["shadow-transform"] || root.transform) {
var matrix = 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[4] += matrix[2][0];
layerViewportMatrix[5] += matrix[2][1]; 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) { if (!hasSeenRoot) {
hasSeenRoot = true; hasSeenRoot = true;
layerViewport.style.transform = "scale(" + 1 / contentScale + "," + 1 / contentScale + ")"; layerViewport.style.transform =
"scale(" + 1 / contentScale + "," + 1 / contentScale + ")";
} }
if (clipElem) { if (clipElem) {
previewParent.appendChild(clipElem); previewParent.appendChild(clipElem);
@ -557,14 +604,19 @@ function populateLayers(root, displayList, pane, previewParent, hasSeenRoot, con
height: rect2d[3] + "px", height: rect2d[3] + "px",
overflow: "hidden", overflow: "hidden",
border: "solid 1px black", 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); layerViewport.appendChild(layerPreview);
function isInside(rect1, rect2) { function isInside(rect1, rect2) {
if (rect1[0] + rect1[2] < rect2[0] && rect2[0] + rect2[2] < rect1[0] && if (
rect1[1] + rect1[3] < rect2[1] && rect2[1] + rect2[3] < rect1[1]) { 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;
} }
return true; return true;
@ -583,8 +635,8 @@ function populateLayers(root, displayList, pane, previewParent, hasSeenRoot, con
src: getDataURI(root.tiles[x][y]), src: getDataURI(root.tiles[x][y]),
style: { style: {
position: "absolute", position: "absolute",
left: (x - previewOffset[0]) + "px", left: x - previewOffset[0] + "px",
top: (y - previewOffset[1]) + "px", top: y - previewOffset[1] + "px",
pointerEvents: "auto", pointerEvents: "auto",
}, },
}); });
@ -605,8 +657,8 @@ function populateLayers(root, displayList, pane, previewParent, hasSeenRoot, con
src: getDataURI(root.surfaceURI), src: getDataURI(root.surfaceURI),
style: { style: {
position: "absolute", position: "absolute",
left: (offsetX - previewOffset[0]) + "px", left: offsetX - previewOffset[0] + "px",
top: (offsetY - previewOffset[1]) + "px", top: offsetY - previewOffset[1] + "px",
pointerEvents: "auto", pointerEvents: "auto",
}, },
}); });
@ -614,7 +666,16 @@ function populateLayers(root, displayList, pane, previewParent, hasSeenRoot, con
layerPreview.style.background = ""; layerPreview.style.background = "";
} else if (root.color) { } else if (root.color) {
hasImg = true; 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) { if (hasImg || true) {
@ -649,13 +710,28 @@ function populateLayers(root, displayList, pane, previewParent, hasSeenRoot, con
} else { } else {
description += "Content: Unknown"; description += "Content: Unknown";
} }
description += "<br>Item: " + this.displayItem.name + " (" + this.displayItem.address + ")"; description +=
description += "<br>Layer: " + root.name + " (" + root.address + ")"; "<br>Item: " +
this.displayItem.name +
" (" +
this.displayItem.address +
")";
description +=
"<br>Layer: " + root.name + " (" + root.address + ")";
if (this.displayItem.frame) { if (this.displayItem.frame) {
description += "<br>Frame: " + this.displayItem.frame; description += "<br>Frame: " + this.displayItem.frame;
} }
if (this.displayItem.layerBounds) { 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) { if (this.displayItem.z) {
description += "<br>Z: " + this.displayItem.z; description += "<br>Z: " + this.displayItem.z;
@ -670,7 +746,11 @@ function populateLayers(root, displayList, pane, previewParent, hasSeenRoot, con
className: "csstooltip", className: "csstooltip",
innerHTML: description, innerHTML: description,
style: { 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", 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 // bounds doesn't adjust for within the layer. It's not a bad fallback but
// will have the wrong offset // will have the wrong offset
let rect2d = displayItem.layerBounds || displayItem.bounds; 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; var appUnitsToPixels = 60 / contentScale;
let diPreview = createElement("div", { let diPreview = createElement("div", {
id: "displayitem_" + displayItem.content + "_" + displayItem.address, 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++) { 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", display: "block",
}, },
href: "#", href: "#",
textContent: "LayerTree " + (frameID++), textContent: "LayerTree " + frameID++,
onclick() { onclick() {
contents.innerHTML = ""; contents.innerHTML = "";
var matchLines = matches[i].split("\n"); var matchLines = matches[i].split("\n");
@ -829,7 +918,9 @@ function parseDump(log, displayList, compositeTitle, compositeTime) {
style: { style: {
width: "100%", width: "100%",
}, },
textContent: compositeTitle + (compositeTitle ? " (near " + compositeTime.toFixed(0) + " ms)" : ""), textContent:
compositeTitle +
(compositeTitle ? " (near " + compositeTime.toFixed(0) + " ms)" : ""),
}); });
container.appendChild(titleDiv); container.appendChild(titleDiv);
} }

View file

@ -5,11 +5,14 @@ add_task(async function test_windowlessBrowserTroubleshootCrash() {
let docShell = webNav.docShell; let docShell = webNav.docShell;
let listener = { let listener = {
observe(contentWindow, topic, data) { observe(contentWindow, topic, data) {
let observedDocShell = contentWindow.docShell let observedDocShell = contentWindow.docShell.sameTypeRootTreeItem.QueryInterface(
.sameTypeRootTreeItem Ci.nsIDocShell
.QueryInterface(Ci.nsIDocShell); );
if (docShell === observedDocShell) { if (docShell === observedDocShell) {
Services.obs.removeObserver(listener, "content-document-global-created"); Services.obs.removeObserver(
listener,
"content-document-global-created"
);
resolve(); resolve();
} }
}, },
@ -25,21 +28,31 @@ add_task(async function test_windowlessBrowserTroubleshootCrash() {
let winUtils = webNav.document.defaultView.windowUtils; let winUtils = webNav.document.defaultView.windowUtils;
try { 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) { } catch (e) {
// The windowless browser may not have a layermanager at all yet, and that's ok. // 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. // The troubleshooting code similarly skips over windows with no layer managers.
} }
ok(true, "not crashed"); 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) => { var data = await new Promise((resolve, reject) => {
Troubleshoot.snapshot((data) => { Troubleshoot.snapshot(data => {
resolve(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(); webNav.close();
}); });