Bug 1434376 - Switch over all uses of BrowserUtils.promiseLayoutFlushed to window.promiseDocumentFlushed. r=Paolo

window.promiseDocumentFlushed will call a callback as soon as a style or layout
flush is not required for the document (which might be immediately). This is a
new ChromeOnly API introduced in an earlier patch in this series.

This patch also removes the now-unneeded BrowserUtils.promiseLayoutFlushed and
BrowserUtils.promiseReflowed methods and infrastructure.

MozReview-Commit-ID: Jv7KoxBXhHG

--HG--
extra : rebase_source : b8c9ae40dbdd0f5587d03e8b7c0833bd94032a78
This commit is contained in:
Mike Conley 2018-02-11 20:15:11 -05:00
Родитель 262bcb1bef
Коммит 4e9c3d2fe2
7 изменённых файлов: 16 добавлений и 124 удалений

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

@ -8010,7 +8010,7 @@ var gIdentityHandler = {
classes += " in-use"; classes += " in-use";
// Synchronize control center and identity block blinking animations. // Synchronize control center and identity block blinking animations.
BrowserUtils.promiseLayoutFlushed(document, "style", () => { window.promiseDocumentFlushed(() => {}).then(() => {
let sharingIconBlink = document.getElementById("sharing-icon").getAnimations()[0]; let sharingIconBlink = document.getElementById("sharing-icon").getAnimations()[0];
if (sharingIconBlink) { if (sharingIconBlink) {
let startTime = sharingIconBlink.startTime; let startTime = sharingIconBlink.startTime;

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

@ -283,7 +283,7 @@
<parameter name="aTab"/> <parameter name="aTab"/>
<body> <body>
<![CDATA[ <![CDATA[
BrowserUtils.promiseLayoutFlushed(aTab.ownerDocument, "style", () => { aTab.ownerGlobal.promiseDocumentFlushed(() => {
if (!aTab.parentNode) { if (!aTab.parentNode) {
return; return;
} }

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

@ -82,9 +82,8 @@ async function withReflowObserver(testFn, expectedReflows = [], win = window) {
}, },
reflowInterruptible(start, end) { reflowInterruptible(start, end) {
// We're not interested in interruptible reflows, but might as well take the // Interruptible reflows are the reflows caused by the refresh
// opportuntiy to dirty the root frame. // driver ticking. These are fine.
dirtyFrameFn();
}, },
QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver, QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver,

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

@ -569,11 +569,7 @@ CustomizeMode.prototype = {
} }
// Wait until the next frame before setting the class to ensure // Wait until the next frame before setting the class to ensure
// we do start the animation. We cannot use promiseLayoutFlushed // we do start the animation.
// here because callback is only invoked when any actual reflow
// happens, while that may not happen soonish enough. If we have
// an observer for style flush, we may be able to replace the
// nested rAFs with that.
this.window.requestAnimationFrame(() => { this.window.requestAnimationFrame(() => {
this.window.requestAnimationFrame(() => { this.window.requestAnimationFrame(() => {
animationNode.classList.add("animate-out"); animationNode.classList.add("animate-out");
@ -2421,7 +2417,8 @@ CustomizeMode.prototype = {
panelOnTheLeft = true; panelOnTheLeft = true;
} }
} else { } else {
await BrowserUtils.promiseLayoutFlushed(doc, "display", () => {}); await this.window.promiseDocumentFlushed(() => {});
if (!this._customizing || !this._wantToBeInCustomizeMode) { if (!this._customizing || !this._wantToBeInCustomizeMode) {
return; return;
} }

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

@ -495,8 +495,8 @@ var PanelMultiView = class extends this.AssociatedToNode {
// binding for the <panelmultiview> element may still be disconnected. // binding for the <panelmultiview> element may still be disconnected.
// In this case, give the layout code a chance to run. // In this case, give the layout code a chance to run.
if (!this.connected) { if (!this.connected) {
await BrowserUtils.promiseLayoutFlushed(this.document, "layout", await this.window.promiseDocumentFlushed(() => {});
() => {});
// The XBL binding must be connected at this point. If this is not the // The XBL binding must be connected at this point. If this is not the
// case, the calling code should be updated to unhide the panel. // case, the calling code should be updated to unhide the panel.
if (!this.connected) { if (!this.connected) {
@ -788,7 +788,7 @@ var PanelMultiView = class extends this.AssociatedToNode {
return; return;
} }
const {window, document} = this; const { window } = this;
let nextPanelView = PanelView.forNode(viewNode); let nextPanelView = PanelView.forNode(viewNode);
let prevPanelView = PanelView.forNode(previousViewNode); let prevPanelView = PanelView.forNode(previousViewNode);
@ -847,7 +847,7 @@ var PanelMultiView = class extends this.AssociatedToNode {
// description elements it contains. // description elements it contains.
nextPanelView.descriptionHeightWorkaround(); nextPanelView.descriptionHeightWorkaround();
viewRect = await BrowserUtils.promiseLayoutFlushed(this.document, "layout", () => { viewRect = await window.promiseDocumentFlushed(() => {
return this._dwu.getBoundsWithoutFlushing(viewNode); return this._dwu.getBoundsWithoutFlushing(viewNode);
}); });
@ -894,7 +894,7 @@ var PanelMultiView = class extends this.AssociatedToNode {
// sliding animation with smaller views. // sliding animation with smaller views.
viewNode.style.width = viewRect.width + "px"; viewNode.style.width = viewRect.width + "px";
await BrowserUtils.promiseLayoutFlushed(document, "layout", () => {}); await window.promiseDocumentFlushed(() => {});
// Kick off the transition! // Kick off the transition!
details.phase = TRANSITION_PHASES.TRANSITION; details.phase = TRANSITION_PHASES.TRANSITION;
@ -1000,7 +1000,7 @@ var PanelMultiView = class extends this.AssociatedToNode {
// We force 'display: none' on the previous view node to make sure that it // We force 'display: none' on the previous view node to make sure that it
// doesn't cause an annoying flicker whilst resetting the styles above. // doesn't cause an annoying flicker whilst resetting the styles above.
previousViewNode.style.display = "none"; previousViewNode.style.display = "none";
await BrowserUtils.promiseLayoutFlushed(this.document, "layout", () => {}); await this.window.promiseDocumentFlushed(() => {});
previousViewNode.style.removeProperty("display"); previousViewNode.style.removeProperty("display");
} }
} }

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

@ -1608,10 +1608,8 @@ PlacesToolbar.prototype = {
notify: function PT_notify(aTimer) { notify: function PT_notify(aTimer) {
if (aTimer == this._updateNodesVisibilityTimer) { if (aTimer == this._updateNodesVisibilityTimer) {
this._updateNodesVisibilityTimer = null; this._updateNodesVisibilityTimer = null;
// TODO: This should use promiseLayoutFlushed("layout"), so that // Bug 1440070: This should use promiseDocumentFlushed, so that
// _updateNodesVisibilityTimerCallback can use getBoundsWithoutFlush. But // _updateNodesVisibilityTimerCallback can use getBoundsWithoutFlush.
// for yet unknown reasons doing that causes intermittent failures,
// apparently due the flush not happening in a meaningful time.
window.requestAnimationFrame(this._updateNodesVisibilityTimerCallback.bind(this)); window.requestAnimationFrame(this._updateNodesVisibilityTimerCallback.bind(this));
} else if (aTimer == this._ibTimer) { } else if (aTimer == this._ibTimer) {
// * Timer to turn off indicator bar. // * Timer to turn off indicator bar.

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

@ -14,48 +14,6 @@ ChromeUtils.defineModuleGetter(this, "PlacesUtils",
Cu.importGlobalProperties(["URL"]); Cu.importGlobalProperties(["URL"]);
let reflowObservers = new WeakMap();
function ReflowObserver(doc) {
this._doc = doc;
doc.docShell.addWeakReflowObserver(this);
reflowObservers.set(this._doc, this);
this.callbacks = [];
}
ReflowObserver.prototype = {
QueryInterface: XPCOMUtils.generateQI(["nsIReflowObserver", "nsISupportsWeakReference"]),
_onReflow() {
reflowObservers.delete(this._doc);
this._doc.docShell.removeWeakReflowObserver(this);
for (let callback of this.callbacks) {
try {
callback();
} catch (e) {
Cu.reportError(e);
}
}
},
reflow() {
this._onReflow();
},
reflowInterruptible() {
this._onReflow();
},
};
const FLUSH_TYPES = {
"style": Ci.nsIDOMWindowUtils.FLUSH_STYLE,
"layout": Ci.nsIDOMWindowUtils.FLUSH_LAYOUT,
"display": Ci.nsIDOMWindowUtils.FLUSH_DISPLAY,
};
var BrowserUtils = { var BrowserUtils = {
/** /**
@ -428,8 +386,7 @@ var BrowserUtils = {
} }
let bounds = dwu.getBoundsWithoutFlushing(toolbarItem); let bounds = dwu.getBoundsWithoutFlushing(toolbarItem);
if (!bounds.height) { if (!bounds.height) {
let document = element.ownerDocument; await window.promiseDocumentFlushed(() => {
await BrowserUtils.promiseLayoutFlushed(document, "layout", () => {
bounds = dwu.getBoundsWithoutFlushing(toolbarItem); bounds = dwu.getBoundsWithoutFlushing(toolbarItem);
}); });
} }
@ -687,65 +644,6 @@ var BrowserUtils = {
return [url, postData]; return [url, postData];
}, },
/**
* Calls the given function when the given document has just reflowed,
* and returns a promise which resolves to its return value after it
* has been called.
*
* The function *must not trigger any reflows*, or make any changes
* which would require a layout flush.
*
* @param {Document} doc
* @param {function} callback
* @returns {Promise}
*/
promiseReflowed(doc, callback) {
let observer = reflowObservers.get(doc);
if (!observer) {
observer = new ReflowObserver(doc);
reflowObservers.set(doc, observer);
}
return new Promise((resolve, reject) => {
observer.callbacks.push(() => {
try {
resolve(callback());
} catch (e) {
reject(e);
}
});
});
},
/**
* Calls the given function as soon as a layout flush of the given
* type is not necessary, and returns a promise which resolves to the
* callback's return value after it executes.
*
* The function *must not trigger any reflows*, or make any changes
* which would require a layout flush.
*
* @param {Document} doc
* @param {string} flushType
* The flush type required. Must be one of:
*
* - "style"
* - "layout"
* - "display"
* @param {function} callback
* @returns {Promise}
*/
async promiseLayoutFlushed(doc, flushType, callback) {
let utils = doc.defaultView.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
if (!utils.needsFlush(FLUSH_TYPES[flushType])) {
return callback();
}
return this.promiseReflowed(doc, callback);
},
/** /**
* Generate a document fragment for a localized string that has DOM * Generate a document fragment for a localized string that has DOM
* node replacements. This avoids using getFormattedString followed * node replacements. This avoids using getFormattedString followed