Bug 1212321 - Stop painting on app launch. r=fabrice
authorVivien Nicolas <vnicolas@mozilla.com>
Fri, 06 Nov 2015 02:13:00 +0100
changeset 271591 50441cd0d6a14568d31a156934c9df106825e840
parent 271590 4ba6798c125bdabc50cb6b0923f36033827199bc
child 271592 a93a69859594569b51d6c8a792983d95d22115f0
push id16135
push usercbook@mozilla.com
push dateMon, 09 Nov 2015 13:59:56 +0000
treeherderfx-team@5898d8162f44 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfabrice
bugs1212321
milestone45.0a1
Bug 1212321 - Stop painting on app launch. r=fabrice
dom/apps/Webapps.js
dom/browser-element/BrowserElementChildPreload.js
--- a/dom/apps/Webapps.js
+++ b/dom/apps/Webapps.js
@@ -568,25 +568,26 @@ WebappsApplication.prototype = {
                             oid: this._id,
                             topId: this._topId,
                             requestID: this.getRequestId(request) });
     return request;
   },
 
   launch: function(aStartPoint) {
     let request = this.createRequest();
-    this.addMessageListeners(["Webapps:Launch:Return:OK",
-                              "Webapps:Launch:Return:KO"]);
     cpmm.sendAsyncMessage("Webapps:Launch", { origin: this.origin,
                                               manifestURL: this.manifestURL,
                                               startPoint: aStartPoint || "",
                                               oid: this._id,
                                               topId: this._topId,
                                               timestamp: Date.now(),
                                               requestID: this.getRequestId(request) });
+    Services.obs.notifyObservers(null, "will-launch-app", null);
+    this.addMessageListeners(["Webapps:Launch:Return:OK",
+                              "Webapps:Launch:Return:KO"]);
     return request;
   },
 
   clearBrowserData: function() {
     let request = this.createRequest();
     let browserChild =
       BrowserElementPromptService.getBrowserElementChildForWindow(this._window);
     if (browserChild) {
--- a/dom/browser-element/BrowserElementChildPreload.js
+++ b/dom/browser-element/BrowserElementChildPreload.js
@@ -22,16 +22,20 @@ XPCOMUtils.defineLazyServiceGetter(this,
 XPCOMUtils.defineLazyModuleGetter(this, "ManifestFinder",
                                   "resource://gre/modules/ManifestFinder.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ManifestObtainer",
                                   "resource://gre/modules/ManifestObtainer.jsm");
 
 
 var kLongestReturnedString = 128;
 
+const Timer = Components.Constructor("@mozilla.org/timer;1",
+                                     "nsITimer",
+                                     "initWithCallback");
+
 function debug(msg) {
   //dump("BrowserElementChildPreload - " + msg + "\n");
 }
 
 function sendAsyncMsg(msg, data) {
   // Ensure that we don't send any messages before BrowserElementChild.js
   // finishes loading.
   if (!BrowserElementIsReady)
@@ -60,17 +64,18 @@ function sendSyncMsg(msg, data) {
 }
 
 var CERTIFICATE_ERROR_PAGE_PREF = 'security.alternate_certificate_error_page';
 
 const OBSERVED_EVENTS = [
   'xpcom-shutdown',
   'audio-playback',
   'activity-done',
-  'invalid-widget'
+  'invalid-widget',
+  'will-launch-app'
 ];
 
 const COMMAND_MAP = {
   'cut': 'cmd_cut',
   'copy': 'cmd_copyAndCollapseToEnd',
   'copyImage': 'cmd_copyImage',
   'copyLink': 'cmd_copyLink',
   'paste': 'cmd_paste',
@@ -327,21 +332,24 @@ BrowserElementChild.prototype = {
 
     OBSERVED_EVENTS.forEach((aTopic) => {
       Services.obs.addObserver(this, aTopic, false);
     });
 
     this.forwarder.init();
   },
 
+  _paintFrozenTimer: null,
   observe: function(subject, topic, data) {
     // Ignore notifications not about our document.  (Note that |content| /can/
     // be null; see bug 874900.)
 
-    if (topic !== 'activity-done' && topic !== 'audio-playback' &&
+    if (topic !== 'activity-done' &&
+        topic !== 'audio-playback' &&
+        topic !== 'will-launch-app' &&
         (!content || subject !== content.document)) {
       return;
     }
     if (topic == 'activity-done' && docShell !== subject)
       return;
     switch (topic) {
       case 'activity-done':
         sendAsyncMsg('activitydone', { success: (data == 'activity-success') });
@@ -352,19 +360,36 @@ BrowserElementChild.prototype = {
         }
         break;
       case 'xpcom-shutdown':
         this._shuttingDown = true;
         break;
       case 'invalid-widget':
         sendAsyncMsg('error', { type: 'invalid-widget' });
         break;
+      case 'will-launch-app':
+        // If the launcher is not visible, let's ignore the message.
+        if (!docShell.isActive) {
+          return;
+        }
+
+        docShell.contentViewer.pausePainting();
+
+        this._paintFrozenTimer && this._paintFrozenTimer.cancel();
+        this._paintFrozenTimer = new Timer(this, 3000, Ci.nsITimer.TYPE_ONE_SHOT);
+        break;
     }
   },
 
+  notify: function(timer) {
+    docShell.contentViewer.resumePainting();
+    this._paintFrozenTimer.cancel();
+    this._paintFrozenTimer = null;
+  },
+
   /**
    * Called when our TabChildGlobal starts to die.  This is not called when the
    * page inside |content| unloads.
    */
   _unloadHandler: function() {
     this._shuttingDown = true;
     OBSERVED_EVENTS.forEach((aTopic) => {
       Services.obs.removeObserver(this, aTopic);
@@ -1373,16 +1398,21 @@ BrowserElementChild.prototype = {
     this._updateVisibility();
   },
 
   _updateVisibility: function() {
     var visible = this._forcedVisible && this._ownerVisible;
     if (docShell && docShell.isActive !== visible) {
       docShell.isActive = visible;
       sendAsyncMsg('visibilitychange', {visible: visible});
+
+      // Ensure painting is not frozen if the app goes visible.
+      if (visible && this._paintFrozenTimer) {
+        this.notify();
+      }
     }
   },
 
   _recvSendMouseEvent: function(data) {
     let json = data.json;
     let utils = content.QueryInterface(Ci.nsIInterfaceRequestor)
                        .getInterface(Ci.nsIDOMWindowUtils);
     utils.sendMouseEventToWindow(json.type, json.x, json.y, json.button,