Bug 1615505. Forward MozAfterPaint events from child processes to the reftest harness. r=kmag,mattwoodrow

Differential Revision: https://phabricator.services.mozilla.com/D62859

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Timothy Nikkel 2020-02-28 12:06:27 +00:00
Родитель 310400ad9a
Коммит 5c0874aab0
4 изменённых файлов: 114 добавлений и 16 удалений

Просмотреть файл

@ -2,8 +2,67 @@ var EXPORTED_SYMBOLS = ["ReftestFissionChild"];
class ReftestFissionChild extends JSWindowActorChild {
forwardAfterPaintEventToParent(rects, originalTargetUri, dispatchToSelfAsWell) {
if (dispatchToSelfAsWell) {
let event = new this.contentWindow.CustomEvent("Reftest:MozAfterPaintFromChild",
{bubbles: true, detail: {rects, originalTargetUri}});
this.contentWindow.dispatchEvent(event);
}
let parentContext = this.browsingContext.parent;
if (parentContext) {
this.sendAsyncMessage("ForwardAfterPaintEvent",
{toBrowsingContext: parentContext, fromBrowsingContext: this.browsingContext,
rects, originalTargetUri});
}
}
handleEvent(evt) {
switch (evt.type) {
case "MozAfterPaint":
// We want to forward any after paint events to our parent document so that
// that it reaches the root content document where the main reftest harness
// code (reftest-content.js) will process it and update the canvas.
var rects = [];
for (let r of evt.clientRects) {
rects.push({ left: r.left, top: r.top, right: r.right, bottom: r.bottom });
}
this.forwardAfterPaintEventToParent(rects, this.document.documentURI, /* dispatchToSelfAsWell */ false);
break;
}
}
transformRect(transform, rect) {
let p1 = transform.transformPoint({x: rect.left, y: rect.top});
let p2 = transform.transformPoint({x: rect.right, y: rect.top});
let p3 = transform.transformPoint({x: rect.left, y: rect.bottom});
let p4 = transform.transformPoint({x: rect.right, y: rect.bottom});
let quad = new DOMQuad(p1, p2, p3, p4);
return quad.getBounds();
}
receiveMessage(msg) {
switch (msg.name) {
case "ForwardAfterPaintEventToSelfAndParent":
{
// Transform the rects from fromBrowsingContext to us.
// We first translate from the content rect to the border rect of the iframe.
let style = this.contentWindow.getComputedStyle(msg.data.fromBrowsingContext.embedderElement);
let translate = new DOMMatrixReadOnly().translate(
parseFloat(style.paddingLeft) + parseFloat(style.borderLeftWidth),
parseFloat(style.paddingTop) + parseFloat(style.borderTopWidth));
// Then we transform from the iframe to our root frame.
// We are guaranteed to be the process with the embedderElement for fromBrowsingContext.
let transform = msg.data.fromBrowsingContext.embedderElement.getTransformToViewport();
let combined = translate.multiply(transform);
let newrects = msg.data.rects.map(r => this.transformRect(combined, r))
this.forwardAfterPaintEventToParent(newrects, msg.data.originalTargetUri, /* dispatchToSelfAsWell */ true);
break;
}
case "EmptyMessage":
return undefined;
case "UpdateLayerTree":

Просмотреть файл

@ -112,6 +112,17 @@ class ReftestFissionParent extends JSWindowActorParent {
receiveMessage(msg) {
switch (msg.name) {
case "ForwardAfterPaintEvent":
{
let cwg = msg.data.toBrowsingContext.currentWindowGlobal;
if (cwg) {
let a = cwg.getActor("ReftestFission");
if (a) {
a.sendAsyncMessage("ForwardAfterPaintEventToSelfAndParent", msg.data);
}
}
break;
}
case "FlushRendering":
{
let promise = this.tellChildrenToFlushRendering(msg.data.browsingContext, msg.data.ignoreThrottledAnimations);

Просмотреть файл

@ -652,6 +652,20 @@ function WaitForTestEnd(contentRootElement, inPrintMode, spellCheckedElements, f
}
}
// true if rectA contains rectB
function Contains(rectA, rectB) {
return (rectA.left <= rectB.left && rectB.right <= rectA.right && rectA.top <= rectB.top && rectB.bottom <= rectA.bottom);
}
// true if some rect in rectList contains rect
function ContainedIn(rectList, rect) {
for (let i = 0; i < rectList.length; ++i) {
if (Contains(rectList[i], rect)) {
return true;
}
}
return false;
}
function AfterPaintListener(event) {
LogInfo("AfterPaintListener in " + event.target.document.location.href);
if (event.target.document != currentDoc) {
@ -660,23 +674,8 @@ function WaitForTestEnd(contentRootElement, inPrintMode, spellCheckedElements, f
return;
}
// true if rectA contains rectB
function Contains(rectA, rectB) {
return (rectA.left <= rectB.left && rectB.right <= rectA.right && rectA.top <= rectB.top && rectB.bottom <= rectA.bottom);
}
// true if some rect in rectList contains rect
function ContainedIn(rectList, rect) {
for (let i = 0; i < rectList.length; ++i) {
if (Contains(rectList[i], rect)) {
return true;
}
}
return false;
}
updateCanvasPending = true;
for (let i = 0; i < event.clientRects.length; ++i) {
let r = event.clientRects[i];
for (let r of event.clientRects) {
if (ContainedIn(updateCanvasRects, r)) {
continue;
}
@ -700,6 +699,29 @@ function WaitForTestEnd(contentRootElement, inPrintMode, spellCheckedElements, f
// call, so we don't need to do anything.
}
function FromChildAfterPaintListener(event) {
LogInfo("FromChildAfterPaintListener from " + event.detail.originalTargetUri);
updateCanvasPending = true;
for (let r of event.detail.rects) {
if (ContainedIn(updateCanvasRects, r)) {
continue;
}
// Copy the rect; it's content and we are chrome, which means if the
// document goes away (and it can in some crashtests) our reference
// to it will be turned into a dead wrapper that we can't acccess.
updateCanvasRects.push({ left: r.left, top: r.top, right: r.right, bottom: r.bottom });
}
if (!operationInProgress) {
HandlePendingTasksAfterMakeProgress();
}
// Otherwise we know that eventually after the operation finishes we
// will get a MakeProgress and/or HandlePendingTasksAfterMakeProgress
// call, so we don't need to do anything.
}
function AttrModifiedListener() {
LogInfo("AttrModifiedListener fired");
// Wait for the next return-to-event-loop before continuing --- for
@ -719,6 +741,7 @@ function WaitForTestEnd(contentRootElement, inPrintMode, spellCheckedElements, f
function RemoveListeners() {
// OK, we can end the test now.
removeEventListener("MozAfterPaint", AfterPaintListener, false);
removeEventListener("Reftest:MozAfterPaintFromChild", FromChildAfterPaintListener, false);
CheckForLivenessOfContentRootElement();
if (contentRootElement) {
contentRootElement.removeEventListener("DOMAttrModified", AttrModifiedListener);
@ -968,6 +991,8 @@ function WaitForTestEnd(contentRootElement, inPrintMode, spellCheckedElements, f
LogInfo("WaitForTestEnd: Adding listeners");
addEventListener("MozAfterPaint", AfterPaintListener, false);
addEventListener("Reftest:MozAfterPaintFromChild", FromChildAfterPaintListener, false);
// If contentRootElement is null then shouldWaitForReftestWaitRemoval will
// always return false so we don't need a listener anyway
CheckForLivenessOfContentRootElement();

Просмотреть файл

@ -1576,6 +1576,9 @@ function RegisterMessageListenersAndLoadContentScript(aReload)
},
child: {
moduleURI: "resource://reftest/ReftestFissionChild.jsm",
events: {
MozAfterPaint: {},
},
},
allFrames: true,
includeChrome: true,