Bug 846636 - Use asynchronous getCharsetForURI in getShortcutOrURI for metro r=mbrubeck
authorRaymond Lee <raymond@raysquare.com>
Wed, 27 Mar 2013 03:41:46 +0800
changeset 126304 c8509229f2057a265a490d840bcc96036e7f5907
parent 126303 cce3081b9bf6ece91b8f5823aafca6c6e890a436
child 126305 4edaad0bb4544e45feb8aedbe54c459d33bdace8
push id24481
push userryanvm@gmail.com
push dateWed, 27 Mar 2013 16:41:34 +0000
treeherdermozilla-central@5dbcbd03d7ba [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmbrubeck
bugs846636
milestone22.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 846636 - Use asynchronous getCharsetForURI in getShortcutOrURI for metro r=mbrubeck
browser/metro/base/content/browser-scripts.js
browser/metro/base/content/browser-ui.js
browser/metro/base/content/browser.js
--- a/browser/metro/base/content/browser-scripts.js
+++ b/browser/metro/base/content/browser-scripts.js
@@ -20,16 +20,22 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/NetUtil.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PdfJs",
                                   "resource://pdf.js/PdfJs.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "DownloadUtils",
                                   "resource://gre/modules/DownloadUtils.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "Promise",
+                                  "resource://gre/modules/commonjs/sdk/core/promise.js");
+
+XPCOMUtils.defineLazyModuleGetter(this, "Task",
+                                  "resource://gre/modules/Task.jsm");
+
 /*
  * Services
  */
 
 #ifdef XP_WIN
 XPCOMUtils.defineLazyServiceGetter(this, "MetroUtils",
                                    "@mozilla.org/windows-metroutils;1",
                                    "nsIWinMetroUtils");
--- a/browser/metro/base/content/browser-ui.js
+++ b/browser/metro/base/content/browser-ui.js
@@ -273,27 +273,29 @@ var BrowserUI = {
 
     // Make sure we're online before attempting to load
     Util.forceOnline();
 
     BrowserUI.showContent(aURI);
     content.focus();
     this._setURI(aURI);
 
-    let postData = {};
-    aURI = Browser.getShortcutOrURI(aURI, postData);
-    Browser.loadURI(aURI, { flags: Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP, postData: postData });
+    Task.spawn(function() {
+      let postData = {};
+      aURI = yield Browser.getShortcutOrURI(aURI, postData);
+      Browser.loadURI(aURI, { flags: Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP, postData: postData });
 
-    // Delay doing the fixup so the raw URI is passed to loadURIWithFlags
-    // and the proper third-party fixup can be done
-    let fixupFlags = Ci.nsIURIFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
-    let uri = gURIFixup.createFixupURI(aURI, fixupFlags);
-    gHistSvc.markPageAsTyped(uri);
+      // Delay doing the fixup so the raw URI is passed to loadURIWithFlags
+      // and the proper third-party fixup can be done
+      let fixupFlags = Ci.nsIURIFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
+      let uri = gURIFixup.createFixupURI(aURI, fixupFlags);
+      gHistSvc.markPageAsTyped(uri);
 
-    this._titleChanged(Browser.selectedBrowser);
+      BrowserUI._titleChanged(Browser.selectedBrowser);
+    });
   },
 
   handleUrlbarEnter: function handleUrlbarEnter(aEvent) {
     let url = this._edit.value;
     if (aEvent instanceof KeyEvent)
       url = this._canonizeURL(url, aEvent);
     this.goToURI(url);
   },
--- a/browser/metro/base/content/browser.js
+++ b/browser/metro/base/content/browser.js
@@ -128,63 +128,16 @@ var Browser = {
 
     // If this is an intial window launch the commandline handler passes us the default
     // page as an argument. commandURL _should_ never be empty, but we protect against it
     // below. However, we delay trying to get the fallback homepage until we really need it.
     let commandURL = null;
     if (window.arguments && window.arguments[0])
       commandURL = window.arguments[0];
 
-    // Activation URIs come from protocol activations, secondary tiles, and file activations
-    let activationURI = this.getShortcutOrURI(MetroUtils.activationURI);
-
-    let self = this;
-    function loadStartupURI() {
-      let uri = activationURI || commandURL || Browser.getHomePage();
-      if (StartUI.isStartURI(uri)) {
-        self.addTab(uri, true);
-        StartUI.show(); // This makes about:start load a lot faster
-      } else if (activationURI) {
-        self.addTab(uri, true, null, { flags: Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP });
-      } else {
-        self.addTab(uri, true);
-      }
-    }
-
-    // Should we restore the previous session (crash or some other event)
-    let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
-    if (ss.shouldRestore() || Services.prefs.getBoolPref("browser.startup.sessionRestore")) {
-      let bringFront = false;
-      // First open any commandline URLs, except the homepage
-      if (activationURI && !StartUI.isStartURI(activationURI)) {
-        this.addTab(activationURI, true, null, { flags: Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP });
-      } else if (commandURL && !StartUI.isStartURI(commandURL)) {
-        this.addTab(commandURL, true);
-      } else {
-        bringFront = true;
-        // Initial window resizes call functions that assume a tab is in the tab list
-        // and restored tabs are added too late. We add a dummy to to satisfy the resize
-        // code and then remove the dummy after the session has been restored.
-        let dummy = this.addTab("about:blank", true);
-        let dummyCleanup = {
-          observe: function(aSubject, aTopic, aData) {
-            Services.obs.removeObserver(dummyCleanup, "sessionstore-windows-restored");
-            if (aData == "fail")
-              loadStartupURI();
-            dummy.chromeTab.ignoreUndo = true;
-            Browser.closeTab(dummy, { forceClose: true });
-          }
-        };
-        Services.obs.addObserver(dummyCleanup, "sessionstore-windows-restored", false);
-      }
-      ss.restoreLastSession(bringFront);
-    } else {
-      loadStartupURI();
-    }
-
     messageManager.addMessageListener("DOMLinkAdded", this);
     messageManager.addMessageListener("MozScrolledAreaChanged", this);
     messageManager.addMessageListener("Browser:ViewportMetadata", this);
     messageManager.addMessageListener("Browser:FormSubmit", this);
     messageManager.addMessageListener("Browser:ZoomToPoint:Return", this);
     messageManager.addMessageListener("Browser:CanUnload:Return", this);
     messageManager.addMessageListener("scroll", this);
     messageManager.addMessageListener("Browser:CertException", this);
@@ -192,20 +145,69 @@ var Browser = {
     messageManager.addMessageListener("Browser:ErrorPage", this);
     messageManager.addMessageListener("Browser:TapOnSelection", this);
     messageManager.addMessageListener("Browser:PluginClickToPlayClicked", this);
 
     // Let everyone know what kind of mouse input we are
     // starting with:
     InputSourceHelper.fireUpdate();
 
-    // Broadcast a UIReady message so add-ons know we are finished with startup
-    let event = document.createEvent("Events");
-    event.initEvent("UIReady", true, false);
-    window.dispatchEvent(event);
+    Task.spawn(function() {
+      // Activation URIs come from protocol activations, secondary tiles, and file activations
+      let activationURI = yield this.getShortcutOrURI(MetroUtils.activationURI);
+
+      let self = this;
+      function loadStartupURI() {
+        let uri = activationURI || commandURL || Browser.getHomePage();
+        if (StartUI.isStartURI(uri)) {
+          self.addTab(uri, true);
+          StartUI.show(); // This makes about:start load a lot faster
+        } else if (activationURI) {
+          self.addTab(uri, true, null, { flags: Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP });
+        } else {
+          self.addTab(uri, true);
+        }
+      }
+
+      // Should we restore the previous session (crash or some other event)
+      let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
+      if (ss.shouldRestore() || Services.prefs.getBoolPref("browser.startup.sessionRestore")) {
+        let bringFront = false;
+        // First open any commandline URLs, except the homepage
+        if (activationURI && !StartUI.isStartURI(activationURI)) {
+          this.addTab(activationURI, true, null, { flags: Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP });
+        } else if (commandURL && !StartUI.isStartURI(commandURL)) {
+          this.addTab(commandURL, true);
+        } else {
+          bringFront = true;
+          // Initial window resizes call functions that assume a tab is in the tab list
+          // and restored tabs are added too late. We add a dummy to to satisfy the resize
+          // code and then remove the dummy after the session has been restored.
+          let dummy = this.addTab("about:blank", true);
+          let dummyCleanup = {
+            observe: function(aSubject, aTopic, aData) {
+              Services.obs.removeObserver(dummyCleanup, "sessionstore-windows-restored");
+              if (aData == "fail")
+                loadStartupURI();
+              dummy.chromeTab.ignoreUndo = true;
+              Browser.closeTab(dummy, { forceClose: true });
+            }
+          };
+          Services.obs.addObserver(dummyCleanup, "sessionstore-windows-restored", false);
+        }
+        ss.restoreLastSession(bringFront);
+      } else {
+        loadStartupURI();
+      }
+
+      // Broadcast a UIReady message so add-ons know we are finished with startup
+      let event = document.createEvent("Events");
+      event.initEvent("UIReady", true, false);
+      window.dispatchEvent(event);
+    }.bind(this));
   },
 
   quit: function quit() {
     // NOTE: onclose seems to be called only when using OS chrome to close a window,
     // so we need to handle the Browser.closing check ourselves.
     if (this.closing()) {
       window.QueryInterface(Ci.nsIDOMChromeWindow).minimize();
       window.close();
@@ -343,87 +345,90 @@ var Browser = {
       dump("Error: " + e + "\n");
     }
   },
 
   /**
    * Determine if the given URL is a shortcut/keyword and, if so, expand it
    * @param aURL String
    * @param aPostDataRef Out param contains any required post data for a search
-   * @returns the expanded shortcut, or the original URL if not a shortcut
+   * @return {Promise}
+   * @result the expanded shortcut, or the original URL if not a shortcut
    */
   getShortcutOrURI: function getShortcutOrURI(aURL, aPostDataRef) {
-    if (!aURL)
-      return aURL;
-
-    let shortcutURL = null;
-    let keyword = aURL;
-    let param = "";
+    return Task.spawn(function() {
+      if (!aURL)
+        throw new Task.Result(aURL);
 
-    let offset = aURL.indexOf(" ");
-    if (offset > 0) {
-      keyword = aURL.substr(0, offset);
-      param = aURL.substr(offset + 1);
-    }
-
-    if (!aPostDataRef)
-      aPostDataRef = {};
-
-    let engine = Services.search.getEngineByAlias(keyword);
-    if (engine) {
-      let submission = engine.getSubmission(param);
-      aPostDataRef.value = submission.postData;
-      return submission.uri.spec;
-    }
+      let shortcutURL = null;
+      let keyword = aURL;
+      let param = "";
 
-    try {
-      [shortcutURL, aPostDataRef.value] = PlacesUtils.getURLAndPostDataForKeyword(keyword);
-    } catch (e) {}
-
-    if (!shortcutURL)
-      return aURL;
-
-    let postData = "";
-    if (aPostDataRef.value)
-      postData = unescape(aPostDataRef.value);
+      let offset = aURL.indexOf(" ");
+      if (offset > 0) {
+        keyword = aURL.substr(0, offset);
+        param = aURL.substr(offset + 1);
+      }
 
-    if (/%s/i.test(shortcutURL) || /%s/i.test(postData)) {
-      let charset = "";
-      const re = /^(.*)\&mozcharset=([a-zA-Z][_\-a-zA-Z0-9]+)\s*$/;
-      let matches = shortcutURL.match(re);
-      if (matches)
-        [, shortcutURL, charset] = matches;
-      else {
-        // Try to get the saved character-set.
-        try {
-          // makeURI throws if URI is invalid.
-          // Will return an empty string if character-set is not found.
-          charset = PlacesUtils.history.getCharsetForURI(Util.makeURI(shortcutURL));
-        } catch (e) { dump("--- error " + e + "\n"); }
+      if (!aPostDataRef)
+        aPostDataRef = {};
+
+      let engine = Services.search.getEngineByAlias(keyword);
+      if (engine) {
+        let submission = engine.getSubmission(param);
+        aPostDataRef.value = submission.postData;
+        throw new Task.Result(submission.uri.spec);
       }
 
-      let encodedParam = "";
-      if (charset)
-        encodedParam = escape(convertFromUnicode(charset, param));
-      else // Default charset is UTF-8
-        encodedParam = encodeURIComponent(param);
+      try {
+        [shortcutURL, aPostDataRef.value] = PlacesUtils.getURLAndPostDataForKeyword(keyword);
+      } catch (e) {}
 
-      shortcutURL = shortcutURL.replace(/%s/g, encodedParam).replace(/%S/g, param);
+      if (!shortcutURL)
+        throw new Task.Result(aURL);
+
+      let postData = "";
+      if (aPostDataRef.value)
+        postData = unescape(aPostDataRef.value);
 
-      if (/%s/i.test(postData)) // POST keyword
-        aPostDataRef.value = getPostDataStream(postData, param, encodedParam, "application/x-www-form-urlencoded");
-    } else if (param) {
-      // This keyword doesn't take a parameter, but one was provided. Just return
-      // the original URL.
-      aPostDataRef.value = null;
+      if (/%s/i.test(shortcutURL) || /%s/i.test(postData)) {
+        let charset = "";
+        const re = /^(.*)\&mozcharset=([a-zA-Z][_\-a-zA-Z0-9]+)\s*$/;
+        let matches = shortcutURL.match(re);
+        if (matches)
+          [, shortcutURL, charset] = matches;
+        else {
+          // Try to get the saved character-set.
+          try {
+            // makeURI throws if URI is invalid.
+            // Will return an empty string if character-set is not found.
+            charset = yield PlacesUtils.getCharsetForURI(Util.makeURI(shortcutURL));
+          } catch (e) { dump("--- error " + e + "\n"); }
+        }
 
-      return aURL;
-    }
+        let encodedParam = "";
+        if (charset)
+          encodedParam = escape(convertFromUnicode(charset, param));
+        else // Default charset is UTF-8
+          encodedParam = encodeURIComponent(param);
+
+        shortcutURL = shortcutURL.replace(/%s/g, encodedParam).replace(/%S/g, param);
 
-    return shortcutURL;
+        if (/%s/i.test(postData)) // POST keyword
+          aPostDataRef.value = getPostDataStream(postData, param, encodedParam, "application/x-www-form-urlencoded");
+      } else if (param) {
+        // This keyword doesn't take a parameter, but one was provided. Just return
+        // the original URL.
+        aPostDataRef.value = null;
+
+        throw new Task.Result(aURL);
+      }
+
+      throw new Task.Result(shortcutURL);
+    });
   },
 
   /**
    * Return the currently active <browser> object
    */
   get selectedBrowser() {
     return (this._selectedTab && this._selectedTab.browser);
   },