Bug 1393136 - Schedule measurement and positioning of the notifier with promisedLayoutFlushed. r?paolo
MozReview-Commit-ID: ATJ3BdJBJCL
--- a/browser/components/downloads/content/indicator.js
+++ b/browser/components/downloads/content/indicator.js
@@ -22,17 +22,18 @@
* Builds and updates the actual downloads status widget, responding to changes
* in the global status data, or provides a neutral view if the indicator is
* removed from the toolbars and only used as a temporary anchor. In addition,
* handles the user interaction events raised by the widget.
*/
"use strict";
-Components.utils.import("resource://gre/modules/AppConstants.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils",
+ "resource://gre/modules/BrowserUtils.jsm");
// DownloadsButton
/**
* Main entry point for the downloads indicator. Depending on how the toolbars
* have been customized, this object determines if we should show a fully
* functional indicator, a placeholder used during customization and in the
* customization palette, or a neutral view as a temporary anchor for the
@@ -328,17 +329,17 @@ const DownloadsIndicatorView = {
/**
* If the status indicator is visible in its assigned position, shows for a
* brief time a visual notification of a relevant event, like a new download.
*
* @param aType
* Set to "start" for new downloads, "finish" for completed downloads.
*/
- _showNotification(aType) {
+ async _showNotification(aType) {
// No need to show visual notification if the panel is visible.
if (DownloadsPanel.isPanelShowing) {
return;
}
let anchor = DownloadsButton._placeholder;
let widgetGroup = CustomizableUI.getWidget("downloads-button");
let widget = widgetGroup.forWindow(window);
@@ -360,44 +361,55 @@ const DownloadsIndicatorView = {
// The notification element is positioned to show in the same location as
// the downloads button. It's not in the downloads button itself in order to
// be able to anchor the notification elsewhere if required, and to ensure
// the notification isn't clipped by overflow properties of the anchor's
// container.
// Note: no notifier animation for download finished in Photon
let notifier = this.notifier;
+ let notifierCoords = {};
+ let shouldShowNotifier = (aType == "start");
+ this._currentNotificationType = aType;
- if (aType == "start") {
+ if (shouldShowNotifier) {
// Show the notifier before measuring for size/placement. Being hidden by default
// avoids the interference with scrolling/APZ when the notifier element is
// tall enough to overlap the tabbrowser element
notifier.removeAttribute("hidden");
- // the anchor height may vary if font-size is changed or
- // compact/tablet mode is selected so recalculate this each time
- let anchorRect = anchor.getBoundingClientRect();
- let notifierRect = notifier.getBoundingClientRect();
+ // measure elements at the first opportunity in the next frame after
+ // un-hiding the notifier
+ let [anchorRect, notifierRect] = await BrowserUtils.promiseLayoutFlushed(document, "layout", () => {
+ // the anchor height may vary if font-size is changed or
+ // compact/tablet mode is selected so recalculate this each time
+ return [anchor.getBoundingClientRect(),
+ notifier.getBoundingClientRect()];
+ });
+
let topDiff = anchorRect.top - notifierRect.top;
let leftDiff = anchorRect.left - notifierRect.left;
let heightDiff = anchorRect.height - notifierRect.height;
let widthDiff = anchorRect.width - notifierRect.width;
- let translateX = (leftDiff + .5 * widthDiff) + "px";
- let translateY = (topDiff + .5 * heightDiff) + "px";
- notifier.style.transform = "translate(" + translateX + ", " + translateY + ")";
+ notifierCoords.x = (leftDiff + .5 * widthDiff) + "px";
+ notifierCoords.y = (topDiff + .5 * heightDiff) + "px";
+ }
+
+ await new Promise(resolve => requestAnimationFrame(resolve));
+
+ if (shouldShowNotifier) {
+ notifier.style.transform = "translate(" + notifierCoords.x + ", " + notifierCoords.y + ")";
notifier.setAttribute("notification", aType);
}
anchor.setAttribute("notification", aType);
let animationDuration;
// This value is determined by the overall duration of animation in CSS.
animationDuration = aType == "start" ? 760 : 850;
- this._currentNotificationType = aType;
-
setTimeout(() => {
requestAnimationFrame(() => {
notifier.setAttribute("hidden", "true");
notifier.removeAttribute("notification");
notifier.style.transform = "";
anchor.removeAttribute("notification");
requestAnimationFrame(() => {