Merge f-t to m-c, a=merge
authorPhil Ringnalda <philringnalda@gmail.com>
Sun, 21 Feb 2016 19:50:31 -0800
changeset 285012 e1cf617a1f2813b6cd66f460313a61c223406c9b
parent 285008 08d7af2bfe303f01069475abebfe4c2407e9d719 (current diff)
parent 285011 d6c06db9e3d49ff30f0670b8e8aef1eb90197978 (diff)
child 285017 241581e67d7535834591ae9ec031e5f0f37f6210
child 285020 58b32ee79ddb6bc44dfa79c4ebf48ab24daddf62
push id30019
push userphilringnalda@gmail.com
push dateMon, 22 Feb 2016 03:50:42 +0000
treeherdermozilla-central@e1cf617a1f28 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone47.0a1
first release with
nightly linux32
e1cf617a1f28 / 47.0a1 / 20160222030212 / files
nightly linux64
e1cf617a1f28 / 47.0a1 / 20160222030212 / files
nightly mac
e1cf617a1f28 / 47.0a1 / 20160222030212 / files
nightly win32
e1cf617a1f28 / 47.0a1 / 20160222030212 / files
nightly win64
e1cf617a1f28 / 47.0a1 / 20160222030212 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge f-t to m-c, a=merge
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -49,20 +49,16 @@ const WINDOW_ATTRIBUTES = ["width", "hei
 // Hideable window features to (re)store
 // Restored in restoreWindowFeatures()
 const WINDOW_HIDEABLE_FEATURES = [
   "menubar", "toolbar", "locationbar", "personalbar", "statusbar", "scrollbars"
 ];
 
 // Messages that will be received via the Frame Message Manager.
 const MESSAGES = [
-  // The content script gives us a reference to an object that performs
-  // synchronous collection of session data.
-  "SessionStore:setupSyncHandler",
-
   // The content script sends us data that has been invalidated and needs to
   // be saved to disk.
   "SessionStore:update",
 
   // The restoreHistory code has run. This is a good time to run SSTabRestoring.
   "SessionStore:restoreHistoryComplete",
 
   // The load for the restoring tab has begun. We update the URL bar at this
@@ -84,35 +80,29 @@ const MESSAGES = [
 ];
 
 // The list of messages we accept from <xul:browser>s that have no tab
 // assigned, or whose windows have gone away. Those are for example the
 // ones that preload about:newtab pages, or from browsers where the window
 // has just been closed.
 const NOTAB_MESSAGES = new Set([
   // For a description see above.
-  "SessionStore:setupSyncHandler",
-
-  // For a description see above.
   "SessionStore:crashedTabRevived",
 
   // For a description see above.
   "SessionStore:update",
 
   // For a description see above.
   "SessionStore:error",
 ]);
 
 // The list of messages we accept without an "epoch" parameter.
 // See getCurrentEpoch() and friends to find out what an "epoch" is.
 const NOEPOCH_MESSAGES = new Set([
   // For a description see above.
-  "SessionStore:setupSyncHandler",
-
-  // For a description see above.
   "SessionStore:crashedTabRevived",
 
   // For a description see above.
   "SessionStore:error",
 ]);
 
 // The list of messages we want to receive even during the short period after a
 // frame has been removed from the DOM and before its frame script has finished
@@ -701,19 +691,16 @@ var SessionStoreInternal = {
     }
 
     // Ignore messages from previous epochs.
     if (hasEpoch && !this.isCurrentEpoch(browser, data.epoch)) {
       return;
     }
 
     switch (aMessage.name) {
-      case "SessionStore:setupSyncHandler":
-        TabState.setSyncHandler(browser, aMessage.objects.handler);
-        break;
       case "SessionStore:update":
         // |browser.frameLoader| might be empty if the browser was already
         // destroyed and its tab removed. In that case we still have the last
         // frameLoader we know about to compare.
         let frameLoader = browser.frameLoader ||
                           this._lastKnownFrameLoader.get(browser.permanentKey);
 
         // If the message isn't targeting the latest frameLoader discard it.
--- a/browser/components/sessionstore/TabState.jsm
+++ b/browser/components/sessionstore/TabState.jsm
@@ -22,98 +22,39 @@ XPCOMUtils.defineLazyModuleGetter(this, 
   "resource:///modules/sessionstore/TabAttributes.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Utils",
   "resource:///modules/sessionstore/Utils.jsm");
 
 /**
  * Module that contains tab state collection methods.
  */
 this.TabState = Object.freeze({
-  setSyncHandler: function (browser, handler) {
-    TabStateInternal.setSyncHandler(browser, handler);
-  },
-
   update: function (browser, data) {
     TabStateInternal.update(browser, data);
   },
 
-  flushAsync: function (browser) {
-    TabStateInternal.flushAsync(browser);
-  },
-
-  flushWindow: function (window) {
-    TabStateInternal.flushWindow(window);
-  },
-
   collect: function (tab) {
     return TabStateInternal.collect(tab);
   },
 
   clone: function (tab) {
     return TabStateInternal.clone(tab);
   },
 
   copyFromCache(browser, tabData, options) {
     TabStateInternal.copyFromCache(browser, tabData, options);
-  }
+  },
 });
 
 var TabStateInternal = {
-  // A map (xul:browser -> handler) that maps a tab to the
-  // synchronous collection handler object for that tab.
-  // See SyncHandler in content-sessionStore.js.
-  _syncHandlers: new WeakMap(),
-
-  // A map (xul:browser -> int) that maps a browser to the
-  // last "SessionStore:update" message ID we received for it.
-  _latestMessageID: new WeakMap(),
-
-  /**
-   * Install the sync handler object from a given tab.
-   */
-  setSyncHandler: function (browser, handler) {
-    this._syncHandlers.set(browser.permanentKey, handler);
-    this._latestMessageID.set(browser.permanentKey, 0);
-  },
-
   /**
    * Processes a data update sent by the content script.
    */
-  update: function (browser, {id, data}) {
-    // Only ever process messages that have an ID higher than the last one we
-    // saw. This ensures we don't use stale data that has already been received
-    // synchronously.
-    if (id > this._latestMessageID.get(browser.permanentKey)) {
-      this._latestMessageID.set(browser.permanentKey, id);
-      TabStateCache.update(browser, data);
-    }
-  },
-
-  /**
-   * DO NOT USE - DEBUGGING / TESTING ONLY
-   *
-   * This function is used to simulate certain situations where race conditions
-   * can occur by sending data shortly before flushing synchronously.
-   */
-  flushAsync: function(browser) {
-    if (this._syncHandlers.has(browser.permanentKey)) {
-      this._syncHandlers.get(browser.permanentKey).flushAsync();
-    }
-  },
-
-  /**
-   * Flushes queued content script data for all browsers of a given window.
-   */
-  flushWindow: function (window) {
-    for (let browser of window.gBrowser.browsers) {
-      if (this._syncHandlers.has(browser.permanentKey)) {
-        let lastID = this._latestMessageID.get(browser.permanentKey);
-        this._syncHandlers.get(browser.permanentKey).flush(lastID);
-      }
-    }
+  update: function (browser, {data}) {
+    TabStateCache.update(browser, data);
   },
 
   /**
    * Collect data related to a single tab, synchronously.
    *
    * @param tab
    *        tabbrowser tab
    *
--- a/browser/components/sessionstore/content/content-sessionStore.js
+++ b/browser/components/sessionstore/content/content-sessionStore.js
@@ -187,62 +187,16 @@ var MessageListener = {
 
   flush({id}) {
     // Flush the message queue, send the latest updates.
     MessageQueue.send({flushID: id});
   }
 };
 
 /**
- * On initialization, this handler gets sent to the parent process as a CPOW.
- * The parent will use it only to flush pending data from the frame script
- * when needed, i.e. when closing a tab, closing a window, shutting down, etc.
- *
- * This will hopefully not be needed in the future once we have async APIs for
- * closing windows and tabs.
- */
-var SyncHandler = {
-  init: function () {
-    // Send this object as a CPOW to chrome. In single-process mode,
-    // the synchronous send ensures that the handler object is
-    // available in SessionStore.jsm immediately upon loading
-    // content-sessionStore.js.
-    sendSyncMessage("SessionStore:setupSyncHandler", {}, {handler: this});
-  },
-
-  /**
-   * This function is used to make the tab process flush all data that
-   * hasn't been sent to the parent process, yet.
-   *
-   * @param id (int)
-   *        A unique id that represents the last message received by the chrome
-   *        process before flushing. We will use this to determine data that
-   *        would be lost when data has been sent asynchronously shortly
-   *        before flushing synchronously.
-   */
-  flush: function (id) {
-    MessageQueue.flush(id);
-  },
-
-  /**
-   * DO NOT USE - DEBUGGING / TESTING ONLY
-   *
-   * This function is used to simulate certain situations where race conditions
-   * can occur by sending data shortly before flushing synchronously.
-   */
-  flushAsync: function () {
-    if (!Services.prefs.getBoolPref("browser.sessionstore.debug")) {
-      throw new Error("flushAsync() must be used for testing, only.");
-    }
-
-    MessageQueue.send();
-  }
-};
-
-/**
  * Listens for changes to the session history. Whenever the user navigates
  * we will collect URLs and everything belonging to session history.
  *
  * Causes a SessionStore:update message to be sent that contains the current
  * session history.
  *
  * Example:
  *   {entries: [{url: "about:mozilla", ...}, ...], index: 1}
@@ -631,37 +585,23 @@ var PrivacyListener = {
  * A message queue that takes collected data and will take care of sending it
  * to the chrome process. It allows flushing using synchronous messages and
  * takes care of any race conditions that might occur because of that. Changes
  * will be batched if they're pushed in quick succession to avoid a message
  * flood.
  */
 var MessageQueue = {
   /**
-   * A unique, monotonically increasing ID used for outgoing messages. This is
-   * important to make it possible to reuse tabs and allow sync flushes before
-   * data could be destroyed.
-   */
-  _id: 1,
-
-  /**
    * A map (string -> lazy fn) holding lazy closures of all queued data
    * collection routines. These functions will return data collected from the
    * docShell.
    */
   _data: new Map(),
 
   /**
-   * A map holding the |this._id| value for every type of data back when it
-   * was pushed onto the queue. We will use those IDs to find the data to send
-   * and flush.
-   */
-  _lastUpdated: new Map(),
-
-  /**
    * The delay (in ms) used to delay sending changes after data has been
    * invalidated.
    */
   BATCH_DELAY_MS: 1000,
 
   /**
    * The current timeout ID, null if there is no queue data. We use timeouts
    * to damp a flood of data changes and send lots of changes as one batch.
@@ -724,132 +664,84 @@ var MessageQueue = {
    * @param key (string)
    *        A unique identifier specific to the type of data this is passed.
    * @param fn (function)
    *        A function that returns the value that will be sent to the parent
    *        process.
    */
   push: function (key, fn) {
     this._data.set(key, createLazy(fn));
-    this._lastUpdated.set(key, this._id);
 
     if (!this._timeout && !this._timeoutDisabled) {
       // Wait a little before sending the message to batch multiple changes.
       this._timeout = setTimeout(() => this.send(), this.BATCH_DELAY_MS);
     }
   },
 
   /**
    * Sends queued data to the chrome process.
    *
    * @param options (object)
-   *        {id: 123} to override the update ID used to accumulate data to send.
-   *        {sync: true} to send data to the parent process synchronously.
    *        {flushID: 123} to specify that this is a flush
    *        {isFinal: true} to signal this is the final message sent on unload
    */
   send: function (options = {}) {
     // Looks like we have been called off a timeout after the tab has been
     // closed. The docShell is gone now and we can just return here as there
     // is nothing to do.
     if (!docShell) {
       return;
     }
 
     if (this._timeout) {
       clearTimeout(this._timeout);
       this._timeout = null;
     }
 
-    let sync = options && options.sync;
-    let startID = (options && options.id) || this._id;
     let flushID = (options && options.flushID) || 0;
 
-    // We use sendRpcMessage in the sync case because we may have been called
-    // through a CPOW. RPC messages are the only synchronous messages that the
-    // child is allowed to send to the parent while it is handling a CPOW
-    // request.
-    let sendMessage = sync ? sendRpcMessage : sendAsyncMessage;
-
     let durationMs = Date.now();
 
     let data = {};
     let telemetry = {};
-    for (let [key, id] of this._lastUpdated) {
-      // There is no data for the given key anymore because
-      // the parent process already marked it as received.
-      if (!this._data.has(key)) {
-        continue;
-      }
-
-      if (startID > id) {
-        // If the |id| passed by the parent process is higher than the one
-        // stored in |_lastUpdated| for the given key we know that the parent
-        // received all necessary data and we can remove it from the map.
-        this._data.delete(key);
-        continue;
-      }
-
-      let value = this._data.get(key)();
+    for (let [key, func] of this._data) {
+      let value = func();
       if (key == "telemetry") {
         for (let histogramId of Object.keys(value)) {
           telemetry[histogramId] = value[histogramId];
         }
       } else {
         data[key] = value;
       }
     }
 
     durationMs = Date.now() - durationMs;
     telemetry.FX_SESSION_RESTORE_CONTENT_COLLECT_DATA_LONGEST_OP_MS = durationMs;
 
     try {
       // Send all data to the parent process.
-      sendMessage("SessionStore:update", {
-        id: this._id, data, telemetry, flushID,
+      sendAsyncMessage("SessionStore:update", {
+        data, telemetry, flushID,
         isFinal: options.isFinal || false,
         epoch: gCurrentEpoch
       });
     } catch (ex if ex && ex.result == Cr.NS_ERROR_OUT_OF_MEMORY) {
       let telemetry = {
         FX_SESSION_RESTORE_SEND_UPDATE_CAUSED_OOM: 1
       };
-      sendMessage("SessionStore:error", {
+      sendAsyncMessage("SessionStore:error", {
         telemetry
       });
     }
-
-    // Increase our unique message ID.
-    this._id++;
   },
-
-  /**
-   * This function is used to make the message queue flush all queue data that
-   * hasn't been sent to the parent process, yet.
-   *
-   * @param id (int)
-   *        A unique id that represents the latest message received by the
-   *        chrome process. We can use this to determine which messages have not
-   *        yet been received because they are still stuck in the event queue.
-   */
-  flush: function (id) {
-    // It's important to always send data, even if there is nothing to flush.
-    // The update message will be received by the parent process that can then
-    // update its last received update ID to ignore stale messages.
-    this.send({id: id + 1, sync: true});
-
-    this._data.clear();
-    this._lastUpdated.clear();
-  }
 };
 
 EventListener.init();
 MessageListener.init();
 FormDataListener.init();
-SyncHandler.init();
 PageStyleListener.init();
 SessionHistoryListener.init();
 SessionStorageListener.init();
 ScrollPositionListener.init();
 DocShellCapabilitiesListener.init();
 PrivacyListener.init();
 MessageQueue.init();
 
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -858,17 +858,21 @@ menuitem:not([type]):not(.menuitem-toolt
   -moz-margin-start: 0;
 }
 
 .urlbar-history-dropmarker {
   -moz-appearance: toolbarbutton-dropdown;
   transition: opacity 0.15s ease;
 }
 
-#navigator-toolbox:not(:hover) .urlbar-history-dropmarker {
+#urlbar-wrapper[switchingtabs] > #urlbar > .urlbar-textbox-container > .urlbar-history-dropmarker {
+  transition: none;
+}
+
+#navigator-toolbox:not(:hover) #urlbar:not([focused]) > .urlbar-textbox-container > .urlbar-history-dropmarker {
   opacity: 0;
 }
 
 #urlbar-container {
   -moz-box-align: center;
 }
 
 @conditionalForwardWithUrlbar@ > #urlbar {
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -1618,17 +1618,21 @@ toolbar .toolbarbutton-1 > .toolbarbutto
 
 .urlbar-history-dropmarker {
   padding: 0 3px;
   list-style-image: var(--urlbar-dropmarker-url);
   -moz-image-region: var(--urlbar-dropmarker-region);
   transition: opacity 0.15s ease;
 }
 
-#navigator-toolbox:not(:hover) .urlbar-history-dropmarker {
+#urlbar-wrapper[switchingtabs] > #urlbar > .urlbar-textbox-container > .urlbar-history-dropmarker {
+  transition: none;
+}
+
+#navigator-toolbox:not(:hover) #urlbar:not([focused]) > .urlbar-textbox-container > .urlbar-history-dropmarker {
   opacity: 0;
 }
 
 .urlbar-history-dropmarker[open="true"],
 .urlbar-history-dropmarker:hover:active {
   -moz-image-region: var(--urlbar-dropmarker-active-region);
 }
 
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -1361,17 +1361,21 @@ html|*.urlbar-input:-moz-lwtheme::-moz-p
   background-color: transparent;
   border: none;
   width: auto;
   list-style-image: var(--urlbar-dropmarker-url);
   -moz-image-region: var(--urlbar-dropmarker-region);
   transition: opacity 0.15s ease;
 }
 
-#navigator-toolbox:not(:hover) .urlbar-history-dropmarker {
+#urlbar-wrapper[switchingtabs] > #urlbar > .urlbar-textbox-container > .urlbar-history-dropmarker {
+  transition: none;
+}
+
+#navigator-toolbox:not(:hover) #urlbar:not([focused]) > .urlbar-textbox-container > .urlbar-history-dropmarker {
   opacity: 0;
 }
 
 .urlbar-history-dropmarker:hover {
   -moz-image-region: var(--urlbar-dropmarker-hover-region);
 }
 
 .urlbar-history-dropmarker:hover:active,
--- a/mobile/android/base/java/org/mozilla/gecko/favicons/Favicons.java
+++ b/mobile/android/base/java/org/mozilla/gecko/favicons/Favicons.java
@@ -18,22 +18,21 @@ import org.mozilla.gecko.util.NonEvictin
 import org.mozilla.gecko.util.ThreadUtils;
 
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.drawable.BitmapDrawable;
+import android.net.Uri;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseArray;
 
-import java.net.URI;
-import java.net.URISyntaxException;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -509,29 +508,33 @@ public class Favicons {
      * @param pageURL Page URL for which a default Favicon URL is requested
      * @return The default Favicon URL.
      */
     public static String guessDefaultFaviconURL(String pageURL) {
         // Special-casing for about: pages. The favicon for about:pages which don't provide a link tag
         // is bundled in the database, keyed only by page URL, hence the need to return the page URL
         // here. If the database ever migrates to stop being silly in this way, this can plausibly
         // be removed.
+        if (TextUtils.isEmpty(pageURL)) {
+            return null;
+        }
         if (AboutPages.isAboutPage(pageURL) || pageURL.startsWith("jar:")) {
             return pageURL;
         }
 
         try {
             // Fall back to trying "someScheme:someDomain.someExtension/favicon.ico".
-            URI u = new URI(pageURL);
-            return new URI(u.getScheme(),
-                           u.getAuthority(),
-                           "/favicon.ico", null,
-                           null).toString();
-        } catch (URISyntaxException e) {
-            Log.e(LOGTAG, "URISyntaxException getting default favicon URL", e);
+            Uri u = Uri.parse(pageURL);
+            Uri.Builder builder = new Uri.Builder();
+            builder.scheme(u.getScheme())
+                   .authority(u.getAuthority())
+                   .appendPath("favicon.ico");
+            return builder.build().toString();
+        } catch (Exception e) {
+            Log.d(LOGTAG, "Exception getting default favicon URL");
             return null;
         }
     }
 
     /**
      * Helper function to determine if we can decode a particular mime type.
      * @param imgType Mime type to check for decodability.
      * @return false if the given mime type is certainly not decodable, true if it might be.