Merge m-c to inbound
authorWes Kocher <wkocher@mozilla.com>
Tue, 22 Oct 2013 18:43:11 -0400
changeset 165542 adc7d2090b3a42d52d255aa285b568c22f1d10fb
parent 165540 fa13474d7b16433307c5f090c152c25e3e8a5292 (current diff)
parent 165471 31382b5fa51e14ce2e8c37e307a900fe8889ff84 (diff)
child 165543 820620c8a288fbd4ce80da9ec48d85851a6bf30e
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone27.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
Merge m-c to inbound
b2g/app/b2g.js
browser/devtools/shared/helpers.js
layout/base/nsDisplayList.cpp
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -744,17 +744,17 @@ pref("webgl.can-lose-context-in-foregrou
 // Allow nsMemoryInfoDumper to create a fifo in the temp directory.  We use
 // this fifo to trigger about:memory dumps, among other things.
 pref("memory_info_dumper.watch_fifo.enabled", true);
 pref("memory_info_dumper.watch_fifo.directory", "/data/local");
 
 pref("general.useragent.enable_overrides", true);
 // See ua-update.json.in for the packaged UA override list
 pref("general.useragent.updates.enabled", true);
-pref("general.useragent.updates.url", "");
+pref("general.useragent.updates.url", "https://dynamicua.cdn.mozilla.net/0/%APP_ID%");
 pref("general.useragent.updates.interval", 604800); // 1 week
 pref("general.useragent.updates.retry", 86400); // 1 day
 
 // Make <audio> and <video> talk to the AudioChannelService.
 pref("media.useAudioChannelService", true);
 
 pref("b2g.version", @MOZ_B2G_VERSION@);
 
--- a/b2g/app/ua-update.json.in
+++ b/b2g/app/ua-update.json.in
@@ -1,19 +1,15 @@
 // Comments must be on their own lines and must start with "//"
 
 // Send these sites a custom user-agent. Bugs to remove each override after
 // evangelism are included.
 {
-  // bug 802981, maps.google.com
-  "maps.google.com": "\\(Mobile#(Android; Mobile",
   // bug 826330, uol.com.br
   "uol.com.br": "Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19",
-  // bug 826332, live.com
-  "live.com": "Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19",
   // bug 826335, globo.com
   "globo.com": "\\(Mobile#(Android; Mobile",
   // bug 826338, yahoo.com
   "yahoo.com": "\\(Mobile#(Android; Mobile",
   // bug 826342, mercadolivre.com.br
   "mercadolivre.com.br": "\\(Mobile#(Android; Mobile",
   // bug 826343, ig.com.br
   "ig.com.br": "\\(Mobile#(Android; Mobile",
@@ -36,18 +32,16 @@
   // bug 826711, bb.com.br
   "bb.com.br": "\\(Mobile#(Android; Mobile",
   // bug 826712, orkut.com
   "orkut.com": "Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19",
   // bug 826715, noticias.uol.com.br
   "noticias.uol.com.br": "\\(Mobile#(Android; Mobile",
   // bug 826720, olx.com.br
   "olx.com.br": "\\(Mobile#(Android; Mobile",
-  // bug 826736, bancobrasil.com.br
-  "bancobrasil.com.br": "\\(Mobile#(Android; Mobile",
   // bug 826845, techtudo.com.br
   "techtudo.com.br": "\\(Mobile#(Android; Mobile",
   // bug 826958, ebay.com
   "ebay.com": "\\(Mobile#(Android; Mobile",
   // bug 827622, bing.com
   "bing.com": "\\(Mobile#(Android; Mobile",
   // bug 827625, pagseguro.uol.com.br
   "pagseguro.uol.com.br": "\\(Mobile#(Android; Mobile",
@@ -90,18 +84,16 @@
   // bug 828364, nk.pl
   "nk.pl": "\\(Mobile#(Android; Mobile",
   // bug 828366, wyborcza.biz
   "wyborcza.biz": "\\(Mobile#(Android; Mobile",
   // bug 828369, money.pl
   "money.pl": "\\(Mobile#(Android; Mobile",
   // bug 828371, ingbank.pl
   "ingbank.pl": "\\(Mobile#(Android; Mobile",
-  // bug 828376, plotek.pl
-  "plotek.pl": "Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19",
   // bug 828378, wyborcza.pl
   "wyborcza.pl": "\\(Mobile#(Android; Mobile",
   // bug 828380, deser.pl
   "deser.pl": "\\(Mobile#(Android; Mobile",
   // bug 828386, ebay.es
   "ebay.es": "\\(Mobile#(Android; Mobile",
   // bug 828392, infojobs.net
   "infojobs.net": "\\(Mobile#(Android; Mobile",
@@ -126,20 +118,16 @@
   // bug 828433, olx.com.ve
   "olx.com.ve": "\\(Mobile#(Android; Mobile",
   // bug 828439, movistar.com.ve
   "movistar.com.ve": "\\(Mobile#(Android; Mobile",
   // bug 828445, bumeran.com.ve
   "bumeran.com.ve": "\\(Mobile#(Android; Mobile",
   // bug 828448, petardas.com
   "petardas.com": "\\(Mobile#(Android; Mobile",
-  // bug 827869, mail.google.com
-  "mail.google.com": "\\(Mobile#(Android; Mobile",
-  // bug 843109, enfemenino.com
-  "enfemenino.com": "\\(Mobile#(Android; Mobile",
   // bug 843112, movil.bankinter.es
   "movil.bankinter.es": "\\(Mobile#(Android; Mobile",
   // bug 843114, einforma.com
   "einforma.com": "\\(Mobile#(Android; Mobile",
   // bug 843116, wwwhatsnew.com
   "wwwhatsnew.com": "\\(Mobile#(Android; Mobile",
   // bug 843119, askthebuilder.com
   "askthebuilder.com": "\\(Mobile#(Android; Mobile",
@@ -150,28 +138,22 @@
   // bug 843126, es.playstation.com
   "es.playstation.com": "Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19",
   // bug 843129, 11870.com
   "11870.com": "\\(Mobile#(Android; Mobile",
   // bug 843200, iphonejuegosgratis.com
   "iphonejuegosgratis.com": "\\(Mobile#(Android; Mobile",
   // bug 843132, comunio.es
   "comunio.es": "\\(Mobile#(Android; Mobile",
-  // bug 843134, news.google.com
-  "news.google.com": "\\(Mobile#(Android; Mobile",
   // bug 843136, deviantart.com
   "deviantart.com": "\\(Mobile#(Android; Mobile",
-  // bug 843137, nytimes.com
-  "nytimes.com": "\\(Mobile#(Android; Mobile",
   // bug 843139, consumersearch.com
   "consumersearch.com": "\\(Mobile#(Android; Mobile",
   // bug 843141, foodily.com
   "foodily.com": "\\(Mobile#(Android; Mobile",
-  // bug 843197, icanhas.cheezburger.com
-  "icanhas.cheezburger.com": "\\(Mobile#(Android; Mobile",
   // bug 843151, citibank.com
   "citibank.com": "\\(Mobile#(Android; Mobile",
   // bug 843153, games.com
   "games.com": "\\(Mobile#(Android; Mobile",
   // bug 843156, orbitz.com
   "orbitz.com": "\\(Mobile#(Android; Mobile",
   // bug 843158, starwoodhotels.com
   "starwoodhotels.com": "\\(Mobile#(Android; Mobile",
@@ -220,18 +202,16 @@
   // bug 878246, port.hu
   "port.hu": "\\(Mobile#(Android; Mobile",
   // bug 878249, portfolio.hu
   "portfolio.hu": "\\(Mobile#(Android; Mobile",
   // bug 878253, vatera.hu
   "vatera.hu": "\\(Mobile#(Android; Mobile",
   // bug 878255, 24sata.hr
   "24sata.hr": "\\(Mobile#(Android; Mobile",
-  // bug 878256, bet365.com
-  "bet365.com": "\\(Mobile#(Android; Mobile",
   // bug 878258, blackhatteam.com
   "blackhatteam.com": "\\(Mobile#(Android; Mobile",
   // bug 878260, cdm.me
   "cdm.me": "\\(Mobile#(Android; Mobile",
   // bug 878262, download.com
   "download.com": "\\(Mobile#(Android; Mobile",
   // bug 878264, haber.ba
   "haber.ba": "\\(Mobile#(Android; Mobile",
@@ -250,18 +230,16 @@
   // bug 878286, yandex.ru
   "yandex.ru": "\\(Mobile#(Android; Mobile",
   // bug 878630, ask.com
   "ask.com": "\\(Mobile#(Android; Mobile",
   // bug 878632, banorte.com
   "banorte.com": "\\(Mobile#(Android; Mobile",
   // bug 878634, buenastareas.com
   "buenastareas.com": "\\(Mobile#(Android; Mobile",
-  // bug 878635, cnn.com
-  "cnn.com": "Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19",
   // bug 878637, eluniversal.com.mx
   "eluniversal.com.mx": "\\(Mobile#(Android; Mobile",
   // bug 878640, hootsuite.com
   "hootsuite.com": "\\(Mobile#(Android; Mobile",
   // bug 878642, mercadolibre.com.mx
   "mercadolibre.com.mx": "\\(Mobile#(Android; Mobile",
   // bug 878645, olx.com.mx
   "olx.com.mx": "\\(Mobile#(Android; Mobile",
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "175b7a89aa5f39aa2b2263029ab086ac1833a636", 
+    "revision": "ef355aa8244d698a5b226ac4ef2408a2eb0812bb", 
     "repo_path": "/integration/gaia-central"
 }
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -495,30 +495,16 @@ HistoryMenu.prototype = {
     // no restorable tabs, so disable menu
     if (SessionStore.getClosedTabCount(window) == 0)
       undoMenu.setAttribute("disabled", true);
     else
       undoMenu.removeAttribute("disabled");
   },
 
   /**
-    * Re-open a closed tab and put it to the end of the tab strip.
-    * Used for a middle click.
-    * @param aEvent
-    *        The event when the user clicks the menu item
-    */
-  _undoCloseMiddleClick: function PHM__undoCloseMiddleClick(aEvent) {
-    if (aEvent.button != 1)
-      return;
-
-    undoCloseTab(aEvent.originalTarget.value);
-    gBrowser.moveTabToEnd();
-  },
-
-  /**
    * Populate when the history menu is opened
    */
   populateUndoSubmenu: function PHM_populateUndoSubmenu() {
     var undoMenu = this._rootElt.getElementsByClassName("recentlyClosedTabsMenu")[0];
     var undoPopup = undoMenu.firstChild;
 
     // remove existing menu items
     while (undoPopup.hasChildNodes())
--- a/browser/components/sessionstore/src/RecentlyClosedTabsAndWindowsMenuUtils.jsm
+++ b/browser/components/sessionstore/src/RecentlyClosedTabsAndWindowsMenuUtils.jsm
@@ -60,20 +60,18 @@ this.RecentlyClosedTabsAndWindowsMenuUti
         if (i == 0)
           element.setAttribute("key", "key_undoCloseTab");
         fragment.appendChild(element);
       }
 
       fragment.appendChild(doc.createElementNS(kNSXUL, "menuseparator"));
       let restoreAllTabs = fragment.appendChild(doc.createElementNS(kNSXUL, aTagName));
       restoreAllTabs.setAttribute("label", navigatorBundle.GetStringFromName("menuRestoreAllTabs.label"));
-      restoreAllTabs.addEventListener("command", function() {
-        for (var i = 0; i < closedTabs.length; i++)
-          undoCloseTab(0);
-      }, false);
+      restoreAllTabs.setAttribute("oncommand",
+              "for (var i = 0; i < " + closedTabs.length + "; i++) undoCloseTab(0);");
     }
     return fragment;
   },
 
   /**
   * Builds up a document fragment of UI items for the recently closed windows.
   * @param   aWindow
   *          A window that can be used to create the elements and document fragment.
@@ -123,16 +121,31 @@ this.RecentlyClosedTabsAndWindowsMenuUti
       fragment.appendChild(doc.createElementNS(kNSXUL, "menuseparator"));
       let restoreAllWindows = fragment.appendChild(doc.createElementNS(kNSXUL, aTagName));
       restoreAllWindows.setAttribute("label", navigatorBundle.GetStringFromName("menuRestoreAllWindows.label"));
       restoreAllWindows.setAttribute("oncommand",
         "for (var i = 0; i < " + closedWindowData.length + "; i++) undoCloseWindow();");
     }
     return fragment;
   },
+
+
+  /**
+    * Re-open a closed tab and put it to the end of the tab strip.
+    * Used for a middle click.
+    * @param aEvent
+    *        The event when the user clicks the menu item
+    */
+  _undoCloseMiddleClick: function(aEvent) {
+    if (aEvent.button != 1)
+      return;
+
+    aEvent.view.undoCloseTab(aEvent.originalTarget.value);
+    aEvent.view.gBrowser.moveTabToEnd();
+  },
 };
 
 function setImage(aItem, aElement) {
   let iconURL = aItem.image;
   // don't initiate a connection just to fetch a favicon (see bug 467828)
   if (/^https?:/.test(iconURL))
     iconURL = "moz-anno:favicon:" + iconURL;
   aElement.setAttribute("image", iconURL);
--- a/browser/components/sessionstore/src/SessionStore.jsm
+++ b/browser/components/sessionstore/src/SessionStore.jsm
@@ -576,19 +576,16 @@ let SessionStoreInternal = {
         this.onPurgeSessionHistory();
         break;
       case "browser:purge-domain-data":
         this.onPurgeDomainData(aData);
         break;
       case "nsPref:changed": // catch pref changes
         this.onPrefChange(aData);
         break;
-      case "timer-callback": // timer call back for delayed saving
-        this.onTimerCallback();
-        break;
     }
   },
 
   /**
    * This method handles incoming messages sent by the session store content
    * script and thus enables communication with OOP tabs.
    */
   receiveMessage: function ssi_receiveMessage(aMessage) {
@@ -690,19 +687,18 @@ let SessionStoreInternal = {
    * @param aInitialState
    *        The initial state to be loaded after startup (optional)
    */
   onLoad: function ssi_onLoad(aWindow, aInitialState = null) {
     // return if window has already been initialized
     if (aWindow && aWindow.__SSi && this._windows[aWindow.__SSi])
       return;
 
-    // ignore non-browser windows and windows opened while shutting down
-    if (aWindow.document.documentElement.getAttribute("windowtype") != "navigator:browser" ||
-        this._loadState == STATE_QUITTING)
+    // ignore windows opened while shutting down
+    if (this._loadState == STATE_QUITTING)
       return;
 
     // Assign the window a unique identifier we can use to reference
     // internal data about the window.
     aWindow.__SSi = this._generateWindowID();
 
     // and create its data object
     this._windows[aWindow.__SSi] = { tabs: [], selected: 0, _closedTabs: [], busy: false };
@@ -857,16 +853,23 @@ let SessionStoreInternal = {
    * On window open
    * @param aWindow
    *        Window reference
    */
   onOpen: function ssi_onOpen(aWindow) {
     let onload = () => {
       aWindow.removeEventListener("load", onload);
 
+      let windowType = aWindow.document.documentElement.getAttribute("windowtype");
+
+      // Ignore non-browser windows.
+      if (windowType != "navigator:browser") {
+        return;
+      }
+
       if (this._sessionInitialized) {
         this.onLoad(aWindow);
         return;
       }
 
       // We can't call this.onLoad since initialization
       // hasn't completed, so we'll wait until it is done.
       // Even if additional windows are opened and wait
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -91,23 +91,18 @@ XPCOMUtils.defineLazyModuleGetter(this, 
   "resource:///modules/devtools/Parser.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "devtools",
   "resource://gre/modules/devtools/Loader.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "DevToolsUtils",
   "resource://gre/modules/devtools/DevToolsUtils.jsm");
 
-Object.defineProperty(this, "DevtoolsHelpers", {
-  get: function() {
-    return devtools.require("devtools/shared/helpers");
-  },
-  configurable: true,
-  enumerable: true
-});
+XPCOMUtils.defineLazyModuleGetter(this, "ShortcutUtils",
+  "resource://gre/modules/ShortcutUtils.jsm");
 
 Object.defineProperty(this, "NetworkHelper", {
   get: function() {
     return devtools.require("devtools/toolkit/webconsole/network-helper");
   },
   configurable: true,
   enumerable: true
 });
@@ -510,16 +505,17 @@ ThreadState.prototype = {
  * stack frame cache.
  */
 function StackFrames() {
   this._onPaused = this._onPaused.bind(this);
   this._onResumed = this._onResumed.bind(this);
   this._onFrames = this._onFrames.bind(this);
   this._onFramesCleared = this._onFramesCleared.bind(this);
   this._onBlackBoxChange = this._onBlackBoxChange.bind(this);
+  this._onPrettyPrintChange = this._onPrettyPrintChange.bind(this);
   this._afterFramesCleared = this._afterFramesCleared.bind(this);
   this.evaluate = this.evaluate.bind(this);
 }
 
 StackFrames.prototype = {
   get activeThread() DebuggerController.activeThread,
   currentFrameDepth: -1,
   _isWatchExpressionsEvaluation: false,
@@ -536,32 +532,34 @@ StackFrames.prototype = {
    */
   connect: function() {
     dumpn("StackFrames is connecting...");
     this.activeThread.addListener("paused", this._onPaused);
     this.activeThread.addListener("resumed", this._onResumed);
     this.activeThread.addListener("framesadded", this._onFrames);
     this.activeThread.addListener("framescleared", this._onFramesCleared);
     this.activeThread.addListener("blackboxchange", this._onBlackBoxChange);
+    this.activeThread.addListener("prettyprintchange", this._onPrettyPrintChange);
     this.handleTabNavigation();
   },
 
   /**
    * Disconnect from the client.
    */
   disconnect: function() {
     if (!this.activeThread) {
       return;
     }
     dumpn("StackFrames is disconnecting...");
     this.activeThread.removeListener("paused", this._onPaused);
     this.activeThread.removeListener("resumed", this._onResumed);
     this.activeThread.removeListener("framesadded", this._onFrames);
     this.activeThread.removeListener("framescleared", this._onFramesCleared);
     this.activeThread.removeListener("blackboxchange", this._onBlackBoxChange);
+    this.activeThread.removeListener("prettyprintchange", this._onPrettyPrintChange);
   },
 
   /**
    * Handles any initialization on a tab navigation event issued by the client.
    */
   handleTabNavigation: function() {
     dumpn("Handling tab navigation in the StackFrames");
     // Nothing to do here yet.
@@ -738,22 +736,30 @@ StackFrames.prototype = {
     window.setTimeout(this._afterFramesCleared, FRAME_STEP_CLEAR_DELAY);
   },
 
   /**
    * Handler for the debugger's blackboxchange notification.
    */
   _onBlackBoxChange: function() {
     if (this.activeThread.state == "paused") {
-      this.currentFrame = null;
       this._refillFrames();
     }
   },
 
   /**
+   * Handler for the debugger's prettyprintchange notification.
+   */
+  _onPrettyPrintChange: function() {
+    if (this.activeThread.state == "paused") {
+      this.activeThread.fillFrames(CALL_STACK_PAGE_SIZE);
+    }
+  },
+
+  /**
    * Called soon after the thread client's framescleared notification.
    */
   _afterFramesCleared: function() {
     // Ignore useless notifications.
     if (this.activeThread.cachedFrames.length) {
       return;
     }
     DebuggerView.StackFrames.empty();
@@ -990,45 +996,48 @@ StackFrames.prototype = {
  * Keeps the source script list up-to-date, using the thread client's
  * source script cache.
  */
 function SourceScripts() {
   this._onNewGlobal = this._onNewGlobal.bind(this);
   this._onNewSource = this._onNewSource.bind(this);
   this._onSourcesAdded = this._onSourcesAdded.bind(this);
   this._onBlackBoxChange = this._onBlackBoxChange.bind(this);
+  this._onPrettyPrintChange = this._onPrettyPrintChange.bind(this);
 }
 
 SourceScripts.prototype = {
   get activeThread() DebuggerController.activeThread,
   get debuggerClient() DebuggerController.client,
   _cache: new Map(),
 
   /**
    * Connect to the current thread client.
    */
   connect: function() {
     dumpn("SourceScripts is connecting...");
     this.debuggerClient.addListener("newGlobal", this._onNewGlobal);
     this.debuggerClient.addListener("newSource", this._onNewSource);
     this.activeThread.addListener("blackboxchange", this._onBlackBoxChange);
+    this.activeThread.addListener("prettyprintchange", this._onPrettyPrintChange);
     this.handleTabNavigation();
   },
 
   /**
    * Disconnect from the client.
    */
   disconnect: function() {
     if (!this.activeThread) {
       return;
     }
     dumpn("SourceScripts is disconnecting...");
     this.debuggerClient.removeListener("newGlobal", this._onNewGlobal);
     this.debuggerClient.removeListener("newSource", this._onNewSource);
     this.activeThread.removeListener("blackboxchange", this._onBlackBoxChange);
+    this.activeThread.addListener("prettyprintchange", this._onPrettyPrintChange);
   },
 
   /**
    * Clears all the cached source contents.
    */
   clearCache: function() {
     this._cache.clear();
   },
@@ -1175,65 +1184,74 @@ SourceScripts.prototype = {
         deferred.resolve([aSource, sourceClient.isBlackBoxed]);
       }
     });
 
     return deferred.promise;
   },
 
   /**
-   * Pretty print a source's text. All subsequent calls to |getText| will return
-   * the pretty text. Nothing will happen for non-javascript files.
+   * Toggle the pretty printing of a source's text. All subsequent calls to
+   * |getText| will return the pretty-toggled text. Nothing will happen for
+   * non-javascript files.
    *
    * @param Object aSource
    *        The source form from the RDP.
    * @returns Promise
    *          A promise that resolves to [aSource, prettyText] or rejects to
    *          [aSource, error].
    */
-  prettyPrint: function(aSource) {
+  togglePrettyPrint: function(aSource) {
     // Only attempt to pretty print JavaScript sources.
     if (!SourceUtils.isJavaScript(aSource.url, aSource.contentType)) {
       return promise.reject([aSource, "Can't prettify non-javascript files."]);
     }
 
+    const sourceClient = this.activeThread.source(aSource);
+    const wantPretty = !sourceClient.isPrettyPrinted;
+
     // Only use the existing promise if it is pretty printed.
     let textPromise = this._cache.get(aSource.url);
-    if (textPromise && textPromise.pretty) {
+    if (textPromise && textPromise.pretty === wantPretty) {
       return textPromise;
     }
 
     const deferred = promise.defer();
+    deferred.promise.pretty = wantPretty;
     this._cache.set(aSource.url, deferred.promise);
 
-    this.activeThread.source(aSource)
-      .prettyPrint(Prefs.editorTabSize, ({ error, message, source: text }) => {
-        if (error) {
-          // Revert the rejected promise from the cache, so that the original
-          // source's text may be shown when the source is selected.
-          this._cache.set(aSource.url, textPromise);
-          deferred.reject([aSource, message || error]);
-          return;
-        }
+    const afterToggle = ({ error, message, source: text }) => {
+      if (error) {
+        // Revert the rejected promise from the cache, so that the original
+        // source's text may be shown when the source is selected.
+        this._cache.set(aSource.url, textPromise);
+
+        deferred.reject([aSource, message || error]);
+        return;
+      }
+
+      deferred.resolve([aSource, text]);
+    };
 
-        // Remove the cached source AST from the Parser, to avoid getting
-        // wrong locations when searching for functions.
-        DebuggerController.Parser.clearSource(aSource.url);
+    if (wantPretty) {
+      sourceClient.prettyPrint(Prefs.editorTabSize, afterToggle);
+    } else {
+      sourceClient.disablePrettyPrint(afterToggle);
+    }
 
-        if (this.activeThread.paused) {
-          // Update the stack frame list.
-          this.activeThread._clearFrames();
-          this.activeThread.fillFrames(CALL_STACK_PAGE_SIZE);
-        }
+    return deferred.promise;
+  },
 
-        deferred.resolve([aSource, text]);
-      });
-
-    deferred.promise.pretty = true;
-    return deferred.promise;
+  /**
+   * Handler for the debugger's prettyprintchange notification.
+   */
+  _onPrettyPrintChange: function(aEvent, { url }) {
+    // Remove the cached source AST from the Parser, to avoid getting
+    // wrong locations when searching for functions.
+    DebuggerController.Parser.clearSource(url);
   },
 
   /**
    * Gets a specified source's text.
    *
    * @param object aSource
    *        The source object coming from the active thread.
    * @param function aOnTimeout [optional]
--- a/browser/devtools/debugger/debugger-panes.js
+++ b/browser/devtools/debugger/debugger-panes.js
@@ -6,33 +6,34 @@
 "use strict";
 
 /**
  * Functions handling the sources UI.
  */
 function SourcesView() {
   dumpn("SourcesView was instantiated");
 
-  this.prettyPrint = this.prettyPrint.bind(this);
+  this.togglePrettyPrint = this.togglePrettyPrint.bind(this);
   this._onEditorLoad = this._onEditorLoad.bind(this);
   this._onEditorUnload = this._onEditorUnload.bind(this);
   this._onEditorSelection = this._onEditorSelection.bind(this);
   this._onEditorContextMenu = this._onEditorContextMenu.bind(this);
   this._onSourceSelect = this._onSourceSelect.bind(this);
   this._onSourceClick = this._onSourceClick.bind(this);
   this._onBreakpointRemoved = this._onBreakpointRemoved.bind(this);
   this._onSourceCheck = this._onSourceCheck.bind(this);
   this._onStopBlackBoxing = this._onStopBlackBoxing.bind(this);
   this._onBreakpointClick = this._onBreakpointClick.bind(this);
   this._onBreakpointCheckboxClick = this._onBreakpointCheckboxClick.bind(this);
   this._onConditionalPopupShowing = this._onConditionalPopupShowing.bind(this);
   this._onConditionalPopupShown = this._onConditionalPopupShown.bind(this);
   this._onConditionalPopupHiding = this._onConditionalPopupHiding.bind(this);
   this._onConditionalTextboxInput = this._onConditionalTextboxInput.bind(this);
   this._onConditionalTextboxKeyPress = this._onConditionalTextboxKeyPress.bind(this);
+  this._updatePrettyPrintButtonState = this._updatePrettyPrintButtonState.bind(this);
 }
 
 SourcesView.prototype = Heritage.extend(WidgetMethods, {
   /**
    * Initialization function, called when the debugger is started.
    */
   initialize: function() {
     dumpn("Initializing the SourcesView");
@@ -58,17 +59,16 @@ SourcesView.prototype = Heritage.extend(
     }
 
     window.on(EVENTS.EDITOR_LOADED, this._onEditorLoad, false);
     window.on(EVENTS.EDITOR_UNLOADED, this._onEditorUnload, false);
     this.widget.addEventListener("select", this._onSourceSelect, false);
     this.widget.addEventListener("click", this._onSourceClick, false);
     this.widget.addEventListener("check", this._onSourceCheck, false);
     this._stopBlackBoxButton.addEventListener("click", this._onStopBlackBoxing, false);
-    this._prettyPrintButton.addEventListener("click", this.prettyPrint, false);
     this._cbPanel.addEventListener("popupshowing", this._onConditionalPopupShowing, false);
     this._cbPanel.addEventListener("popupshown", this._onConditionalPopupShown, false);
     this._cbPanel.addEventListener("popuphiding", this._onConditionalPopupHiding, false);
     this._cbTextbox.addEventListener("input", this._onConditionalTextboxInput, false);
     this._cbTextbox.addEventListener("keypress", this._onConditionalTextboxKeyPress, false);
 
     this.autoFocusOnSelection = false;
 
@@ -83,17 +83,16 @@ SourcesView.prototype = Heritage.extend(
     dumpn("Destroying the SourcesView");
 
     window.off(EVENTS.EDITOR_LOADED, this._onEditorLoad, false);
     window.off(EVENTS.EDITOR_UNLOADED, this._onEditorUnload, false);
     this.widget.removeEventListener("select", this._onSourceSelect, false);
     this.widget.removeEventListener("click", this._onSourceClick, false);
     this.widget.removeEventListener("check", this._onSourceCheck, false);
     this._stopBlackBoxButton.removeEventListener("click", this._onStopBlackBoxing, false);
-    this._prettyPrintButton.removeEventListener("click", this.prettyPrint, false);
     this._cbPanel.removeEventListener("popupshowing", this._onConditionalPopupShowing, false);
     this._cbPanel.removeEventListener("popupshowing", this._onConditionalPopupShown, false);
     this._cbPanel.removeEventListener("popuphiding", this._onConditionalPopupHiding, false);
     this._cbTextbox.removeEventListener("input", this._onConditionalTextboxInput, false);
     this._cbTextbox.removeEventListener("keypress", this._onConditionalTextboxKeyPress, false);
   },
 
   /**
@@ -374,40 +373,44 @@ SourcesView.prototype = Heritage.extend(
    * Unhighlights the current breakpoint in this sources container.
    */
   unhighlightBreakpoint: function() {
     this._unselectBreakpoint();
     this._hideConditionalPopup();
   },
 
   /**
-   * Pretty print the selected source.
+   * Toggle the pretty printing of the selected source.
    */
-  prettyPrint: function() {
+  togglePrettyPrint: function() {
     if (this._prettyPrintButton.hasAttribute("disabled")) {
       return;
     }
 
     const resetEditor = ([{ url }]) => {
       // Only set the text when the source is still selected.
       if (url == this.selectedValue) {
         DebuggerView.setEditorLocation(url, 0, { force: true });
       }
     };
+
     const printError = ([{ url }, error]) => {
-      let err = DevToolsUtils.safeErrorString(error);
-      let msg = "Couldn't prettify source: " + url + "\n" + err;
-      Cu.reportError(msg);
-      dumpn(msg);
-      return;
-    }
+      DevToolsUtils.reportException("togglePrettyPrint", error);
+    };
 
     DebuggerView.showProgressBar();
     const { source } = this.selectedItem.attachment;
-    DebuggerController.SourceScripts.prettyPrint(source)
+
+    if (gThreadClient.source(source).isPrettyPrinted) {
+      this._prettyPrintButton.removeAttribute("checked");
+    } else {
+      this._prettyPrintButton.setAttribute("checked", true);
+    }
+
+    DebuggerController.SourceScripts.togglePrettyPrint(source)
       .then(resetEditor, printError)
       .then(DebuggerView.showEditor);
   },
 
   /**
    * Marks a breakpoint as selected in this sources container.
    *
    * @param object aItem
@@ -696,25 +699,34 @@ SourcesView.prototype = Heritage.extend(
     document.title = L10N.getFormatStr("DebuggerWindowScriptTitle", script);
 
     DebuggerView.maybeShowBlackBoxMessage();
     this._updatePrettyPrintButtonState();
   },
 
   /**
    * Enable or disable the pretty print button depending on whether the selected
-   * source is black boxed or not.
+   * source is black boxed or not and check or uncheck it depending on if the
+   * selected source is already pretty printed or not.
    */
   _updatePrettyPrintButtonState: function() {
     const { source } = this.selectedItem.attachment;
-    if (gThreadClient.source(source).isBlackBoxed) {
+    const sourceClient = gThreadClient.source(source);
+
+    if (sourceClient.isBlackBoxed) {
       this._prettyPrintButton.setAttribute("disabled", true);
     } else {
       this._prettyPrintButton.removeAttribute("disabled");
     }
+
+    if (sourceClient.isPrettyPrinted) {
+      this._prettyPrintButton.setAttribute("checked", true);
+    } else {
+      this._prettyPrintButton.removeAttribute("checked");
+    }
   },
 
   /**
    * The click listener for the sources container.
    */
   _onSourceClick: function() {
     // Use this container as a filtering target.
     DebuggerView.Filtering.target = this;
--- a/browser/devtools/debugger/debugger-toolbar.js
+++ b/browser/devtools/debugger/debugger-toolbar.js
@@ -33,20 +33,20 @@ ToolbarView.prototype = {
     this._instrumentsPaneToggleButton = document.getElementById("instruments-pane-toggle");
     this._resumeOrderPanel = document.getElementById("resumption-order-panel");
     this._resumeButton = document.getElementById("resume");
     this._stepOverButton = document.getElementById("step-over");
     this._stepInButton = document.getElementById("step-in");
     this._stepOutButton = document.getElementById("step-out");
     this._chromeGlobals = document.getElementById("chrome-globals");
 
-    let resumeKey = DevtoolsHelpers.prettyKey(document.getElementById("resumeKey"), true);
-    let stepOverKey = DevtoolsHelpers.prettyKey(document.getElementById("stepOverKey"), true);
-    let stepInKey = DevtoolsHelpers.prettyKey(document.getElementById("stepInKey"), true);
-    let stepOutKey = DevtoolsHelpers.prettyKey(document.getElementById("stepOutKey"), true);
+    let resumeKey = ShortcutUtils.prettifyShortcut(document.getElementById("resumeKey"));
+    let stepOverKey = ShortcutUtils.prettifyShortcut(document.getElementById("stepOverKey"));
+    let stepInKey = ShortcutUtils.prettifyShortcut(document.getElementById("stepInKey"));
+    let stepOutKey = ShortcutUtils.prettifyShortcut(document.getElementById("stepOutKey"));
     this._resumeTooltip = L10N.getFormatStr("resumeButtonTooltip", resumeKey);
     this._pauseTooltip = L10N.getFormatStr("pauseButtonTooltip", resumeKey);
     this._stepOverTooltip = L10N.getFormatStr("stepOverTooltip", stepOverKey);
     this._stepInTooltip = L10N.getFormatStr("stepInTooltip", stepInKey);
     this._stepOutTooltip = L10N.getFormatStr("stepOutTooltip", stepOutKey);
 
     this._instrumentsPaneToggleButton.addEventListener("mousedown", this._onTogglePanesPressed, false);
     this._resumeButton.addEventListener("mousedown", this._onResumePressed, false);
@@ -691,22 +691,22 @@ FilterView.prototype = {
     this._functionOperatorLabel = document.getElementById("function-operator-label");
     this._tokenOperatorButton = document.getElementById("token-operator-button");
     this._tokenOperatorLabel = document.getElementById("token-operator-label");
     this._lineOperatorButton = document.getElementById("line-operator-button");
     this._lineOperatorLabel = document.getElementById("line-operator-label");
     this._variableOperatorButton = document.getElementById("variable-operator-button");
     this._variableOperatorLabel = document.getElementById("variable-operator-label");
 
-    this._fileSearchKey = DevtoolsHelpers.prettyKey(document.getElementById("fileSearchKey"), true);
-    this._globalSearchKey = DevtoolsHelpers.prettyKey(document.getElementById("globalSearchKey"), true);
-    this._filteredFunctionsKey = DevtoolsHelpers.prettyKey(document.getElementById("functionSearchKey"), true);
-    this._tokenSearchKey = DevtoolsHelpers.prettyKey(document.getElementById("tokenSearchKey"), true);
-    this._lineSearchKey = DevtoolsHelpers.prettyKey(document.getElementById("lineSearchKey"), true);
-    this._variableSearchKey = DevtoolsHelpers.prettyKey(document.getElementById("variableSearchKey"), true);
+    this._fileSearchKey = ShortcutUtils.prettifyShortcut(document.getElementById("fileSearchKey"));
+    this._globalSearchKey = ShortcutUtils.prettifyShortcut(document.getElementById("globalSearchKey"));
+    this._filteredFunctionsKey = ShortcutUtils.prettifyShortcut(document.getElementById("functionSearchKey"));
+    this._tokenSearchKey = ShortcutUtils.prettifyShortcut(document.getElementById("tokenSearchKey"));
+    this._lineSearchKey = ShortcutUtils.prettifyShortcut(document.getElementById("lineSearchKey"));
+    this._variableSearchKey = ShortcutUtils.prettifyShortcut(document.getElementById("variableSearchKey"));
 
     this._searchbox.addEventListener("click", this._onClick, false);
     this._searchbox.addEventListener("select", this._onInput, false);
     this._searchbox.addEventListener("input", this._onInput, false);
     this._searchbox.addEventListener("keypress", this._onKeyPress, false);
     this._searchbox.addEventListener("blur", this._onBlur, false);
 
     this._globalOperatorButton.setAttribute("label", SEARCH_GLOBAL_FLAG);
--- a/browser/devtools/debugger/debugger-view.js
+++ b/browser/devtools/debugger/debugger-view.js
@@ -63,16 +63,17 @@ let DebuggerView = {
     this.ChromeGlobals.initialize();
     this.StackFrames.initialize();
     this.Sources.initialize();
     this.WatchExpressions.initialize();
     this.EventListeners.initialize();
     this.GlobalSearch.initialize();
     this._initializeVariablesView();
     this._initializeEditor(deferred.resolve);
+
     document.title = L10N.getStr("DebuggerWindowTitle");
 
     return deferred.promise;
   },
 
   /**
    * Destroys the debugger view.
    *
--- a/browser/devtools/debugger/debugger.xul
+++ b/browser/devtools/debugger/debugger.xul
@@ -28,17 +28,17 @@
   <script type="text/javascript" src="debugger-toolbar.js"/>
   <script type="text/javascript" src="debugger-panes.js"/>
 
   <commandset id="editMenuCommands"/>
   <commandset id="sourceEditorCommands"/>
 
   <commandset id="debuggerCommands">
     <command id="prettyPrintCommand"
-             oncommand="DebuggerView.Sources.prettyPrint()"/>
+             oncommand="DebuggerView.Sources.togglePrettyPrint()"/>
     <command id="unBlackBoxButton"
              oncommand="DebuggerView.Sources._onStopBlackBoxing()"/>
     <command id="nextSourceCommand"
              oncommand="DebuggerView.Sources.selectNextItem()"/>
     <command id="prevSourceCommand"
              oncommand="DebuggerView.Sources.selectPrevItem()"/>
     <command id="resumeCommand"
              oncommand="DebuggerView.Toolbar._onResumePressed()"/>
--- a/browser/devtools/debugger/test/browser.ini
+++ b/browser/devtools/debugger/test/browser.ini
@@ -119,16 +119,17 @@ support-files =
 [browser_dbg_pretty-print-03.js]
 [browser_dbg_pretty-print-04.js]
 [browser_dbg_pretty-print-05.js]
 [browser_dbg_pretty-print-06.js]
 [browser_dbg_pretty-print-07.js]
 [browser_dbg_pretty-print-08.js]
 [browser_dbg_pretty-print-09.js]
 [browser_dbg_pretty-print-10.js]
+[browser_dbg_pretty-print-11.js]
 [browser_dbg_progress-listener-bug.js]
 [browser_dbg_reload-preferred-script-01.js]
 [browser_dbg_reload-preferred-script-02.js]
 [browser_dbg_reload-preferred-script-03.js]
 [browser_dbg_reload-same-script.js]
 [browser_dbg_scripts-switching-01.js]
 [browser_dbg_scripts-switching-02.js]
 [browser_dbg_scripts-switching-03.js]
--- a/browser/devtools/debugger/test/browser_dbg_pause-resume.js
+++ b/browser/devtools/debugger/test/browser_dbg_pause-resume.js
@@ -25,26 +25,26 @@ function test() {
 }
 
 function testPause() {
   is(gDebugger.gThreadClient.paused, false,
     "Should be running after starting the test.");
 
   is(gResumeButton.getAttribute("tooltiptext"),
      gDebugger.L10N.getFormatStr("pauseButtonTooltip",
-      gDebugger.DevtoolsHelpers.prettyKey(gResumeKey)),
+      gDebugger.ShortcutUtils.prettifyShortcut(gResumeKey)),
     "Button tooltip should be 'pause' when running.");
 
   gDebugger.gThreadClient.addOneTimeListener("paused", () => {
     is(gDebugger.gThreadClient.paused, true,
       "Should be paused after an interrupt request.");
 
     is(gResumeButton.getAttribute("tooltiptext"),
        gDebugger.L10N.getFormatStr("resumeButtonTooltip",
-        gDebugger.DevtoolsHelpers.prettyKey(gResumeKey)),
+        gDebugger.ShortcutUtils.prettifyShortcut(gResumeKey)),
       "Button tooltip should be 'resume' when paused.");
 
     is(gFrames.itemCount, 0,
       "Should have no frames when paused in the main loop.");
 
     testResume();
   });
 
@@ -53,17 +53,17 @@ function testPause() {
 
 function testResume() {
   gDebugger.gThreadClient.addOneTimeListener("resumed", () => {
     is(gDebugger.gThreadClient.paused, false,
       "Should be paused after an interrupt request.");
 
     is(gResumeButton.getAttribute("tooltiptext"),
        gDebugger.L10N.getFormatStr("pauseButtonTooltip",
-        gDebugger.DevtoolsHelpers.prettyKey(gResumeKey)),
+        gDebugger.ShortcutUtils.prettifyShortcut(gResumeKey)),
       "Button tooltip should be pause when running.");
 
     closeDebuggerAndFinish(gPanel);
   });
 
   EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
 }
 
--- a/browser/devtools/debugger/test/browser_dbg_pretty-print-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_pretty-print-01.js
@@ -38,19 +38,17 @@ function test() {
 }
 
 function testSourceIsUgly() {
   ok(!gEditor.getText().contains("\n    "),
      "The source shouldn't be pretty printed yet.");
 }
 
 function clickPrettyPrintButton() {
-  EventUtils.sendMouseEvent({ type: "click" },
-                            gDebugger.document.getElementById("pretty-print"),
-                            gDebugger);
+  gDebugger.document.getElementById("pretty-print").click();
 }
 
 function testProgressBarShown() {
   const deck = gDebugger.document.getElementById("editor-deck");
   is(deck.selectedIndex, 2, "The progress bar should be shown");
 }
 
 function testSourceIsPretty() {
--- a/browser/devtools/debugger/test/browser_dbg_pretty-print-03.js
+++ b/browser/devtools/debugger/test/browser_dbg_pretty-print-03.js
@@ -36,19 +36,17 @@ function runCodeAndPause() {
   const deferred = promise.defer();
   once(gDebugger.gThreadClient, "paused").then(deferred.resolve);
   // Have to executeSoon so that we don't pause before this function returns.
   executeSoon(gDebuggee.foo);
   return deferred.promise;
 }
 
 function clickPrettyPrintButton() {
-  EventUtils.sendMouseEvent({ type: "click" },
-                            gDebugger.document.getElementById("pretty-print"),
-                            gDebugger);
+  gDebugger.document.getElementById("pretty-print").click();
 }
 
 registerCleanupFunction(function() {
   gTab = null;
   gDebuggee = null;
   gPanel = null;
   gDebugger = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_pretty-print-04.js
+++ b/browser/devtools/debugger/test/browser_dbg_pretty-print-04.js
@@ -42,19 +42,17 @@ function testUglySearch() {
     deferred.resolve();
   });
 
   setText(gSearchBox, "@bar");
   return deferred.promise;
 }
 
 function clickPrettyPrintButton() {
-  EventUtils.sendMouseEvent({ type: "click" },
-                            gDebugger.document.getElementById("pretty-print"),
-                            gDebugger);
+  gDebugger.document.getElementById("pretty-print").click();
 }
 
 function testPrettyPrintedSearch() {
   const deferred = promise.defer();
 
   once(gDebugger, "popupshown").then(() => {
     ok(isCaretPos(gPanel, 6, 10),
        "The bar function's pretty printed location should be shown.");
--- a/browser/devtools/debugger/test/browser_dbg_pretty-print-05.js
+++ b/browser/devtools/debugger/test/browser_dbg_pretty-print-05.js
@@ -32,17 +32,17 @@ function test() {
         "The correct source is currently selected.");
       ok(gEditor.getText().contains("myFunction"),
         "The source shouldn't be pretty printed yet.");
 
       clickPrettyPrintButton();
 
       let { source } = gSources.selectedItem.attachment;
       try {
-        yield gControllerSources.prettyPrint(source);
+        yield gControllerSources.togglePrettyPrint(source);
         ok(false, "The promise for a prettified source should be rejected!");
       } catch ([source, error]) {
         is(error, "Can't prettify non-javascript files.",
           "The promise was correctly rejected with a meaningful message.");
       }
 
       let [source, text] = yield gControllerSources.getText(source);
       is(gSources.selectedValue, TAB_URL,
@@ -53,19 +53,17 @@ function test() {
         "The cached source text wasn't altered in any way.");
 
       yield closeDebuggerAndFinish(gPanel);
     });
   });
 }
 
 function clickPrettyPrintButton() {
-  EventUtils.sendMouseEvent({ type: "click" },
-    gDebugger.document.getElementById("pretty-print"),
-    gDebugger);
+  gDebugger.document.getElementById("pretty-print").click();
 }
 
 function prepareDebugger(aPanel) {
   aPanel._view.Sources.preferredSource = TAB_URL;
 }
 
 registerCleanupFunction(function() {
   gTab = null;
--- a/browser/devtools/debugger/test/browser_dbg_pretty-print-06.js
+++ b/browser/devtools/debugger/test/browser_dbg_pretty-print-06.js
@@ -48,17 +48,17 @@ function test() {
         "The correct source is currently selected.");
       ok(gEditor.getText().contains("myFunction"),
         "The source shouldn't be pretty printed yet.");
 
       clickPrettyPrintButton();
 
       let { source } = gSources.selectedItem.attachment;
       try {
-        yield gControllerSources.prettyPrint(source);
+        yield gControllerSources.togglePrettyPrint(source);
         ok(false, "The promise for a prettified source should be rejected!");
       } catch ([source, error]) {
         ok(error.contains("prettyPrintError"),
           "The promise was correctly rejected with a meaningful message.");
       }
 
       let [source, text] = yield gControllerSources.getText(source);
       is(gSources.selectedValue, JS_URL,
@@ -72,19 +72,17 @@ function test() {
         "The hijacked pretty print method was executed.");
 
       yield closeDebuggerAndFinish(gPanel);
     });
   });
 }
 
 function clickPrettyPrintButton() {
-  EventUtils.sendMouseEvent({ type: "click" },
-    gDebugger.document.getElementById("pretty-print"),
-    gDebugger);
+  gDebugger.document.getElementById("pretty-print").click();
 }
 
 registerCleanupFunction(function() {
   gTab = null;
   gDebuggee = null;
   gPanel = null;
   gDebugger = null;
   gClient = null;
--- a/browser/devtools/debugger/test/browser_dbg_pretty-print-07.js
+++ b/browser/devtools/debugger/test/browser_dbg_pretty-print-07.js
@@ -1,16 +1,16 @@
 /* -*- Mode: javascript; js-indent-level: 2; -*- */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Test basic pretty printing functionality. Would be an xpcshell test, except
 // for bug 921252.
 
-let gTab, gDebuggee, gPanel, gClient, gThreadClient;
+let gTab, gDebuggee, gPanel, gClient, gThreadClient, gSource;
 
 const TAB_URL = EXAMPLE_URL + "doc_pretty-print-2.html";
 
 function test() {
   initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPanel = aPanel;
@@ -21,26 +21,36 @@ function test() {
   });
 }
 
 function findSource() {
   gThreadClient.getSources(({ error, sources }) => {
     ok(!error);
     sources = sources.filter(s => s.url.contains('code_ugly-2.js'));
     is(sources.length, 1);
-    prettyPrintSource(sources[0]);
+    gSource = sources[0];
+    prettyPrintSource();
   });
 }
 
-function prettyPrintSource(source) {
-  gThreadClient.source(source).prettyPrint(4, testPrettyPrinted);
+function prettyPrintSource() {
+  gThreadClient.source(gSource).prettyPrint(4, testPrettyPrinted);
 }
 
-function testPrettyPrinted({ error, source}) {
+function testPrettyPrinted({ error, source }) {
   ok(!error);
   ok(source.contains("\n    "));
+  disablePrettyPrint();
+}
 
+function disablePrettyPrint() {
+  gThreadClient.source(gSource).disablePrettyPrint(testUgly);
+}
+
+function testUgly({ error, source }) {
+  ok(!error);
+  ok(!source.contains("\n    "));
   closeDebuggerAndFinish(gPanel);
 }
 
 registerCleanupFunction(function() {
-  gTab = gDebuggee = gPanel = gClient = gThreadClient = null;
+  gTab = gDebuggee = gPanel = gClient = gThreadClient = gSource = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_pretty-print-09.js
+++ b/browser/devtools/debugger/test/browser_dbg_pretty-print-09.js
@@ -4,17 +4,17 @@
 
 // Test pretty printing source mapped sources.
 
 var gDebuggee;
 var gClient;
 var gThreadClient;
 var gSource;
 
-let gTab, gDebuggee, gPanel, gClient, gThreadClient;
+let gTab, gDebuggee, gPanel, gClient, gThreadClient, gSource;
 
 const TAB_URL = EXAMPLE_URL + "doc_pretty-print-2.html";
 
 function test() {
   initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPanel = aPanel;
@@ -33,41 +33,58 @@ const A_URL = dataUrl(A);
 const B = "function b(){debugger}";
 const B_URL = dataUrl(B);
 
 function findSource() {
   gThreadClient.getSources(({ error, sources }) => {
     ok(!error);
     sources = sources.filter(s => s.url === B_URL);
     is(sources.length, 1);
-    prettyPrint(sources[0]);
+    gSource = sources[0];
+    prettyPrint();
   });
 }
 
-function prettyPrint(source) {
-  gThreadClient.source(source).prettyPrint(2, runCode);
+function prettyPrint() {
+  gThreadClient.source(gSource).prettyPrint(2, runCode);
 }
 
 function runCode({ error }) {
   ok(!error);
   gClient.addOneTimeListener("paused", testDbgStatement);
   gDebuggee.a();
 }
 
 function testDbgStatement(event, { frame, why }) {
-  dump("FITZGEN: inside testDbgStatement\n");
+  is(why.type, "debuggerStatement");
+  const { url, line, column } = frame.where;
+  is(url, B_URL);
+  is(line, 2);
+  is(column, 2);
+
+  disablePrettyPrint();
+}
+
+function disablePrettyPrint() {
+  gThreadClient.source(gSource).disablePrettyPrint(testUgly);
+}
 
-  try {
-    is(why.type, "debuggerStatement");
-    const { url, line, column } = frame.where;
-    is(url, B_URL);
-    is(line, 2);
-    is(column, 2);
+function testUgly({ error, source }) {
+  ok(!error);
+  ok(!source.contains("\n  "));
+  getFrame();
+}
 
-    resumeDebuggerThenCloseAndFinish(gPanel);
-  } catch (e) {
-    dump("FITZGEN: got an error! " + DevToolsUtils.safeErrorString(e) + "\n");
-  }
+function getFrame() {
+  gThreadClient.getFrames(0, 1, testFrame);
+}
+
+function testFrame({ frames: [frame] }) {
+  const { url, line } = frame.where;
+  is(url, B_URL);
+  is(line, 1);
+
+  resumeDebuggerThenCloseAndFinish(gPanel);
 }
 
 registerCleanupFunction(function() {
   gTab = gDebuggee = gPanel = gClient = gThreadClient = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_pretty-print-10.js
+++ b/browser/devtools/debugger/test/browser_dbg_pretty-print-10.js
@@ -40,19 +40,17 @@ function testSourceIsUgly() {
 
 function blackBoxSource() {
   const checkbox = gDebugger.document.querySelector(
     ".selected .side-menu-widget-item-checkbox");
   checkbox.click();
 }
 
 function clickPrettyPrintButton() {
-  EventUtils.sendMouseEvent({ type: "click" },
-                            gDebugger.document.getElementById("pretty-print"),
-                            gDebugger);
+  gDebugger.document.getElementById("pretty-print").click();
 }
 
 function testSourceIsStillUgly() {
   const { source } = gSources.selectedItem.attachment;
   return gDebugger.DebuggerController.SourceScripts.getText(source).then(([, text]) => {
     ok(!text.contains("\n    "));
   });
 }
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_pretty-print-11.js
@@ -0,0 +1,60 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Make sure that pretty printing is maintained across refreshes.
+ */
+
+const TAB_URL = EXAMPLE_URL + "doc_pretty-print.html";
+
+let gTab, gDebuggee, gPanel, gDebugger;
+let gEditor, gSources;
+
+function test() {
+  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+    gTab = aTab;
+    gDebuggee = aDebuggee;
+    gPanel = aPanel;
+    gDebugger = gPanel.panelWin;
+    gEditor = gDebugger.DebuggerView.editor;
+    gSources = gDebugger.DebuggerView.Sources;
+
+    waitForSourceShown(gPanel, "code_ugly.js")
+      .then(testSourceIsUgly)
+      .then(() => {
+        const finished = waitForSourceShown(gPanel, "code_ugly.js");
+        clickPrettyPrintButton();
+        return finished;
+      })
+      .then(testSourceIsPretty)
+      .then(reloadActiveTab.bind(null, gPanel, gDebugger.EVENTS.SOURCE_SHOWN))
+      .then(testSourceIsPretty)
+      .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
+      .then(null, aError => {
+        ok(false, "Got an error: " + DevToolsUtils.safeErrorString(aError));
+      });
+  });
+}
+
+function testSourceIsUgly() {
+  ok(!gEditor.getText().contains("\n    "),
+     "The source shouldn't be pretty printed yet.");
+}
+
+function clickPrettyPrintButton() {
+  gDebugger.document.getElementById("pretty-print").click();
+}
+
+function testSourceIsPretty() {
+  ok(gEditor.getText().contains("\n    "),
+     "The source should be pretty printed.")
+}
+
+registerCleanupFunction(function() {
+  gTab = null;
+  gDebuggee = null;
+  gPanel = null;
+  gDebugger = null;
+  gEditor = null;
+  gSources = null;
+});
--- a/browser/devtools/debugger/test/code_ugly-4.js
+++ b/browser/devtools/debugger/test/code_ugly-4.js
@@ -15,10 +15,10 @@ function a(){b()}function b(){debugger}
 //
 //    let result = (new SourceNode(null, null, null, [
 //      new SourceNode(1, 0, A_URL, A),
 //      B.split("").map((ch, i) => new SourceNode(1, i, B_URL, ch))
 //    ])).toStringWithSourceMap({
 //      file: "abc.js"
 //    });
 //
-//    result.code + "\n//# sourceMappingURL=data:application/json;base64," + btoa(JSON.stringify(result.map));
+//    result.code + "\n//# " + "sourceMappingURL=data:application/json;base64," + btoa(JSON.stringify(result.map));
 
--- a/browser/devtools/devtools-clhandler.js
+++ b/browser/devtools/devtools-clhandler.js
@@ -1,24 +1,36 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+const kDebuggerPrefs = [
+  "devtools.debugger.remote-enabled",
+  "devtools.debugger.chrome-enabled",
+  "devtools.chrome.enabled"
+];
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm");
 
 function devtoolsCommandlineHandler() {
 }
 devtoolsCommandlineHandler.prototype = {
   handle: function(cmdLine) {
-    if (!cmdLine.handleFlag("jsconsole", false)) {
-      return;
+    let consoleFlag = cmdLine.handleFlag("jsconsole", false);
+    let debuggerFlag = cmdLine.handleFlag("jsdebugger", false);
+    if (consoleFlag) {
+      this.handleConsoleFlag(cmdLine);
     }
+    if (debuggerFlag) {
+      this.handleDebuggerFlag(cmdLine);
+    }
+  },
 
-    Cu.import("resource://gre/modules/Services.jsm");
+  handleConsoleFlag: function(cmdLine) {
     let window = Services.wm.getMostRecentWindow("devtools:webconsole");
     if (!window) {
       let devtools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
       // Load the browser devtools main module as the loader's main module.
       devtools.main("main");
       let hudservice = devtools.require("devtools/webconsole/hudservice");
       let console = Cu.import("resource://gre/modules/devtools/Console.jsm", {}).console;
       hudservice.toggleBrowserConsole().then(null, console.error);
@@ -26,15 +38,40 @@ devtoolsCommandlineHandler.prototype = {
       window.focus(); // the Browser Console was already open
     }
 
     if (cmdLine.state == Ci.nsICommandLine.STATE_REMOTE_AUTO) {
       cmdLine.preventDefault = true;
     }
   },
 
-  helpInfo : "  -jsconsole         Open the Browser Console.\n",
+  handleDebuggerFlag: function(cmdLine) {
+    let remoteDebuggingEnabled = false;
+    try {
+      remoteDebuggingEnabled = kDebuggerPrefs.every((pref) => Services.prefs.getBoolPref(pref));
+    } catch (ex) {
+      Cu.reportError(ex);
+      return;
+    }
+    if (remoteDebuggingEnabled) {
+      Cu.import("resource:///modules/devtools/DebuggerProcess.jsm");
+      BrowserDebuggerProcess.init();
+    } else {
+      let errorMsg = "Could not run chrome debugger! You need the following prefs " +
+                     "to be set to true: " + kDebuggerPrefs.join(", ");
+      Cu.reportError(errorMsg);
+      // Dump as well, as we're doing this from a commandline, make sure people don't miss it:
+      dump(errorMsg + "\n");
+    }
+
+    if (cmdLine.state == Ci.nsICommandLine.STATE_REMOTE_AUTO) {
+      cmdLine.preventDefault = true;
+    }
+  },
+
+  helpInfo : "  -jsconsole         Open the Browser Console.\n" +
+             "  -jsdebugger        Open the Browser Debugger.\n",
 
   classID: Components.ID("{9e9a9283-0ce9-4e4a-8f1c-ba129a032c32}"),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]),
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([devtoolsCommandlineHandler]);
--- a/browser/devtools/scratchpad/scratchpad.js
+++ b/browser/devtools/scratchpad/scratchpad.js
@@ -32,17 +32,16 @@ const PREF_RECENT_FILES_MAX = "devtools.
 const VARIABLES_VIEW_URL = "chrome://browser/content/devtools/widgets/VariablesView.xul";
 
 const require   = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
 const promise   = require("sdk/core/promise");
 const Telemetry = require("devtools/shared/telemetry");
 const escodegen = require("escodegen/escodegen");
 const Editor    = require("devtools/sourceeditor/editor");
 const TargetFactory = require("devtools/framework/target").TargetFactory;
-const DevtoolsHelpers = require("devtools/shared/helpers");
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import("resource:///modules/devtools/scratchpad-manager.jsm");
 Cu.import("resource://gre/modules/jsdebugger.jsm");
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 Cu.import("resource://gre/modules/osfile.jsm");
@@ -69,16 +68,19 @@ XPCOMUtils.defineLazyModuleGetter(this, 
   "resource://gre/modules/devtools/dbg-server.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "DebuggerClient",
   "resource://gre/modules/devtools/dbg-client.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "REMOTE_TIMEOUT", () =>
   Services.prefs.getIntPref("devtools.debugger.remote-timeout"));
 
+XPCOMUtils.defineLazyModuleGetter(this, "ShortcutUtils",
+  "resource://gre/modules/ShortcutUtils.jsm");
+
 // Because we have no constructor / destructor where we can log metrics we need
 // to do so here.
 let telemetry = new Telemetry();
 telemetry.toolOpened("scratchpad");
 
 /**
  * The scratchpad object handles the Scratchpad window functionality.
  */
@@ -1243,19 +1245,19 @@ var Scratchpad = {
       let chromeContextCommand = document.getElementById("sp-cmd-browserContext");
       environmentMenu.removeAttribute("hidden");
       chromeContextCommand.removeAttribute("disabled");
       errorConsoleCommand.removeAttribute("disabled");
     }
 
     let initialText = this.strings.formatStringFromName(
       "scratchpadIntro1",
-      [DevtoolsHelpers.prettyKey(document.getElementById("sp-key-run")),
-       DevtoolsHelpers.prettyKey(document.getElementById("sp-key-inspect")),
-       DevtoolsHelpers.prettyKey(document.getElementById("sp-key-display"))],
+      [ShortcutUtils.prettifyShortcut(document.getElementById("sp-key-run"), true),
+       ShortcutUtils.prettifyShortcut(document.getElementById("sp-key-inspect"), true),
+       ShortcutUtils.prettifyShortcut(document.getElementById("sp-key-display"), true)],
       3);
 
     let args = window.arguments;
     let state = null;
 
     if (args && args[0] instanceof Ci.nsIDialogParamBlock) {
       args = args[0];
       this._instanceId = args.GetString(0);
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -170,23 +170,16 @@
 @BINPATH@/components/content_xslt.xpt
 @BINPATH@/components/cookie.xpt
 @BINPATH@/components/directory.xpt
 @BINPATH@/components/docshell.xpt
 @BINPATH@/components/dom.xpt
 @BINPATH@/components/dom_apps.xpt
 @BINPATH@/components/dom_base.xpt
 @BINPATH@/components/dom_system.xpt
-#ifdef MOZ_B2G_RIL
-@BINPATH@/components/dom_voicemail.xpt
-@BINPATH@/components/dom_wifi.xpt
-@BINPATH@/components/dom_system_gonk.xpt
-@BINPATH@/components/dom_icc.xpt
-@BINPATH@/components/dom_wappush.xpt
-#endif
 #ifdef MOZ_B2G_BT
 @BINPATH@/components/dom_bluetooth.xpt
 #endif
 @BINPATH@/components/dom_camera.xpt
 @BINPATH@/components/dom_canvas.xpt
 @BINPATH@/components/dom_alarm.xpt
 @BINPATH@/components/dom_core.xpt
 @BINPATH@/components/dom_css.xpt
@@ -441,29 +434,16 @@
 @BINPATH@/components/nsFormAutoComplete.js
 @BINPATH@/components/nsFormHistory.js
 @BINPATH@/components/FormHistoryStartup.js
 @BINPATH@/components/nsInputListAutoComplete.js
 @BINPATH@/components/contentSecurityPolicy.manifest
 @BINPATH@/components/contentSecurityPolicy.js
 @BINPATH@/components/contentAreaDropListener.manifest
 @BINPATH@/components/contentAreaDropListener.js
-#ifdef MOZ_B2G_RIL
-@BINPATH@/components/RadioInterfaceLayer.manifest
-@BINPATH@/components/RadioInterfaceLayer.js
-@BINPATH@/components/MmsService.manifest
-@BINPATH@/components/MmsService.js
-@BINPATH@/components/RILContentHelper.js
-@BINPATH@/components/MobileMessageDatabaseService.manifest
-@BINPATH@/components/MobileMessageDatabaseService.js
-@BINPATH@/components/WifiWorker.js
-@BINPATH@/components/WifiWorker.manifest
-@BINPATH@/components/DOMWifiManager.js
-@BINPATH@/components/DOMWifiManager.manifest
-#endif
 @BINPATH@/browser/components/BrowserProfileMigrators.manifest
 @BINPATH@/browser/components/ProfileMigrator.js
 @BINPATH@/browser/components/ChromeProfileMigrator.js
 @BINPATH@/browser/components/FirefoxProfileMigrator.js
 #ifdef XP_WIN
 @BINPATH@/browser/components/IEProfileMigrator.js
 @BINPATH@/browser/components/SafariProfileMigrator.js
 #endif
--- a/browser/metro/base/content/startui/BookmarksView.js
+++ b/browser/metro/base/content/startui/BookmarksView.js
@@ -137,17 +137,16 @@ BookmarksView.prototype = Util.extend(Ob
 
     // Remove extra items in case a refresh added more than the limit.
     // This can happen when undoing a delete.
     if (aRefresh) {
       while (this._set.itemCount > limit)
         this._set.removeItemAt(this._set.itemCount - 1, true);
     }
     this._set.arrangeItems();
-    this._set.removeAttribute("fade");
     this._inBatch = false;
     rootNode.containerOpen = false;
   },
 
   inCurrentView: function bv_inCurrentView(aParentId, aItemId) {
     if (this._root && aParentId != this._root)
       return false;
 
@@ -303,16 +302,17 @@ BookmarksView.prototype = Util.extend(Ob
 
 let BookmarksStartView = {
   _view: null,
   get _grid() { return document.getElementById("start-bookmarks-grid"); },
 
   init: function init() {
     this._view = new BookmarksView(this._grid, StartUI.maxResultsPerSection, Bookmarks.metroRoot, true);
     this._view.getBookmarks();
+    this._grid.removeAttribute("fade");
   },
 
   uninit: function uninit() {
     if (this._view) {
       this._view.destruct();
     }
   },
 };
--- a/browser/metro/base/content/startui/HistoryView.js
+++ b/browser/metro/base/content/startui/HistoryView.js
@@ -90,17 +90,16 @@ HistoryView.prototype = Util.extend(Obje
     // This can happen when undoing a delete.
     if (aRefresh) {
       while (this._set.itemCount > limit)
         this._set.removeItemAt(this._set.itemCount - 1);
     }
 
     rootNode.containerOpen = false;
     this._set.arrangeItems();
-    this._set.removeAttribute("fade");
     if (this._inBatch > 0)
       this._inBatch--;
   },
 
   addItemToSet: function addItemToSet(aURI, aTitle, aIcon, aPos) {
     let item = this._set.insertItemAt(aPos || 0, aTitle, aURI, this._inBatch);
     this._setContextActions(item);
     this._updateFavicon(item, aURI);
@@ -295,16 +294,17 @@ HistoryView.prototype = Util.extend(Obje
 
 let HistoryStartView = {
   _view: null,
   get _grid() { return document.getElementById("start-history-grid"); },
 
   init: function init() {
     this._view = new HistoryView(this._grid, StartUI.maxResultsPerSection, true);
     this._view.populateGrid();
+    this._grid.removeAttribute("fade");
   },
 
   uninit: function uninit() {
     if (this._view) {
       this._view.destruct();
     }
   }
 };
--- a/browser/metro/base/content/startui/RemoteTabsView.js
+++ b/browser/metro/base/content/startui/RemoteTabsView.js
@@ -88,17 +88,16 @@ RemoteTabsView.prototype = Util.extend(O
 
         let item = this._set.appendItem((title || url), url);
         item.setAttribute("iconURI", Weave.Utils.getIcon(icon));
 
       }, this);
     }
     this.setUIAccessVisible(show);
     this._set.arrangeItems();
-    this._set.removeAttribute("fade");
   },
 
   destruct: function destruct() {
     Weave.Svc.Obs.remove("weave:engine:sync:finish", this);
     Weave.Svc.Obs.remove("weave:service:logout:start-over", this);
     View.prototype.destruct.call(this);
   },
 
@@ -111,16 +110,17 @@ RemoteTabsView.prototype = Util.extend(O
 let RemoteTabsStartView = {
   _view: null,
   get _grid() { return document.getElementById("start-remotetabs-grid"); },
 
   init: function init() {
     let vbox = document.getElementById("start-remotetabs");
     let uiList = [vbox];
     this._view = new RemoteTabsView(this._grid, uiList);
+    this._grid.removeAttribute("fade");
   },
 
   uninit: function uninit() {
     if (this._view) {
       this._view.destruct();
     }
   },
 };
--- a/browser/metro/base/content/startui/TopSitesView.js
+++ b/browser/metro/base/content/startui/TopSitesView.js
@@ -197,17 +197,16 @@ TopSitesView.prototype = Util.extend(Obj
     let tileset = this._set;
     tileset.clearAll(true);
 
     for (let site of sites) {
       let slot = tileset.nextSlot();
       this.updateTile(slot, site);
     }
     tileset.arrangeItems();
-    tileset.removeAttribute("fade");
     this.isUpdating = false;
   },
 
   forceReloadOfThumbnail: function forceReloadOfThumbnail(url) {
     let nodes = this._set.querySelectorAll('richgriditem[value="'+url+'"]');
     for (let item of nodes) {
       if ("isBound" in item && item.isBound) {
         item.refreshBackgroundImage();
@@ -297,16 +296,17 @@ let TopSitesStartView = {
   get _grid() { return document.getElementById("start-topsites-grid"); },
 
   init: function init() {
     this._view = new TopSitesView(this._grid, 8);
     if (this._view.isFirstRun()) {
       let topsitesVbox = document.getElementById("start-topsites");
       topsitesVbox.setAttribute("hidden", "true");
     }
+    this._grid.removeAttribute("fade");
   },
 
   uninit: function uninit() {
     if (this._view) {
       this._view.destruct();
     }
   },
 };
--- a/browser/metro/base/tests/mochitest/helpers/ViewStateHelper.js
+++ b/browser/metro/base/tests/mochitest/helpers/ViewStateHelper.js
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const snappedSize = 330;
 const portraitSize = 900;
+const maxPortraitHeight = 900;
 
 function setSnappedViewstate() {
   ok(isLandscapeMode(), "setSnappedViewstate expects landscape mode to work.");
 
   let browser = Browser.selectedBrowser;
 
   // Reduce browser width to simulate small screen size.
   let fullWidth = browser.clientWidth;
@@ -27,26 +28,32 @@ function setSnappedViewstate() {
 }
 
 function setPortraitViewstate() {
   ok(isLandscapeMode(), "setPortraitViewstate expects landscape mode to work.");
 
   let browser = Browser.selectedBrowser;
 
   let fullWidth = browser.clientWidth;
+  let fullHeight = browser.clientHeight;
   let padding = fullWidth - portraitSize;
 
   browser.style.borderRight = padding + "px solid gray";
 
+  // cap the height to create more even surface for testing on
+  if (fullHeight > maxPortraitHeight)
+    browser.style.borderBottom = (fullHeight - maxPortraitHeight) + "px solid gray";
+
   ContentAreaObserver._updateViewState("portrait");
 
   // Make sure it renders the new mode properly
   yield waitForMs(0);
 }
 
 function restoreViewstate() {
   ContentAreaObserver._updateViewState("landscape");
   ok(isLandscapeMode(), "restoreViewstate should restore landscape mode.");
 
   Browser.selectedBrowser.style.removeProperty("border-right");
+  Browser.selectedBrowser.style.removeProperty("border-bottom");
 
   yield waitForMs(0);
 }
--- a/browser/metro/theme/platform.css
+++ b/browser/metro/theme/platform.css
@@ -684,16 +684,44 @@ arrowbox {
 }
 
 .meta-section-container[viewstate="snapped"] .meta-section-title,
 .meta-section-container[viewstate="snapped"] richgrid {
   margin-top: @metro_spacing_xnormal@;
   padding: 0;
 }
 
+.meta-section > richgrid {
+  opacity: 1;
+  transform: translateX(0) scale(1);
+  transition-duration: 367ms;
+  transition-delay: 500ms;
+  transition-timing-function: @metro_animation_easing@;
+}
+
+.meta-section:nth-child(2) > richgrid {
+  transition-delay: 600ms;
+}
+.meta-section:nth-child(3) > richgrid {
+  transition-delay: 700ms;
+}
+.meta-section:nth-child(4) > richgrid {
+  transition-delay: 800ms;
+}
+
+.meta-section > richgrid[fade] {
+  opacity: 0;
+  transform: translateX(150px) scale(.9);
+}
+
+#start-container[viewstate="snapped"] .meta-section > richgrid {
+  transition-property: none;
+}
+
+
 /* App bars ----------------------------------------------------------------- */
 
 appbar {
   display: block;
   position: fixed;
   bottom: 0;
   width: 100%;
   transform: translateY(100%);
--- a/browser/metro/theme/tiles.css
+++ b/browser/metro/theme/tiles.css
@@ -27,16 +27,17 @@ richgriditem[compact] {
 }
 /*
  *****************************************************
  */
 richgrid {
   display: -moz-box;
   overflow: hidden;
 }
+
 richgrid > .richgrid-grid {
   -moz-column-width: @grid_double_column_width@; /* tile width (2x unit + gutter) */
   min-width: @grid_double_column_width@; /* min 1 column */
   min-height: @grid_double_row_height@; /* 2 rows (or 1 double rows) minimum; multiple of tile_height */
   -moz-column-fill: auto; /* do not attempt to balance content between columns */
   -moz-column-gap: 0;
   -moz-column-count: auto;
   display: block;
@@ -49,19 +50,16 @@ richgriditem {
   display: block;
   position: relative;
   width: @grid_double_column_width@;
   height: @grid_row_height@;
   -moz-box-sizing: border-box;
   -moz-column-gap: 0;
   overflow:hidden;
   cursor: default;
-  transition: 300ms height ease-out,
-              150ms opacity ease-out,
-              100ms transform ease-out;
 }
 
 .tile-content {
   display: block;
   position: absolute;
   /* background-color colors the tile-edge,
      and will normally be overridden with a favicon-based color */
   background-color: #ccc;
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -32,35 +32,33 @@
 #include "mozilla/Hal.h"
 #include "nsISiteSpecificUserAgent.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/StaticPtr.h"
 #include "Connection.h"
 #include "nsDOMEvent.h"
 #include "nsGlobalWindow.h"
 #ifdef MOZ_B2G_RIL
-#include "IccManager.h"
+#include "mozilla/dom/IccManager.h"
 #include "MobileConnection.h"
 #include "mozilla/dom/CellBroadcast.h"
+#include "mozilla/dom/Telephony.h"
 #include "mozilla/dom/Voicemail.h"
 #endif
 #include "nsIIdleObserver.h"
 #include "nsIPermissionManager.h"
 #include "nsNetUtil.h"
 #include "nsIHttpChannel.h"
 #include "TimeManager.h"
 #include "DeviceStorage.h"
 #include "nsIDOMNavigatorSystemMessages.h"
 
 #ifdef MOZ_MEDIA_NAVIGATOR
 #include "MediaManager.h"
 #endif
-#ifdef MOZ_B2G_RIL
-#include "mozilla/dom/Telephony.h"
-#endif
 #ifdef MOZ_B2G_BT
 #include "BluetoothManager.h"
 #endif
 #include "DOMCameraManager.h"
 
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
 #include "AudioChannelManager.h"
 #endif
@@ -135,25 +133,23 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlugins)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMimeTypes)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGeolocation)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotification)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPowerManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileMessageManager)
-#ifdef MOZ_B2G_RIL
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTelephony)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVoicemail)
-#endif
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
 #ifdef MOZ_B2G_RIL
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileConnection)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCellBroadcast)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIccManager)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTelephony)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVoicemail)
 #endif
 #ifdef MOZ_B2G_BT
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBluetooth)
 #endif
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioChannelManager)
 #endif
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCameraManager)
@@ -208,26 +204,16 @@ Navigator::Invalidate()
     mPowerManager = nullptr;
   }
 
   if (mMobileMessageManager) {
     mMobileMessageManager->Shutdown();
     mMobileMessageManager = nullptr;
   }
 
-#ifdef MOZ_B2G_RIL
-  if (mTelephony) {
-    mTelephony = nullptr;
-  }
-
-  if (mVoicemail) {
-    mVoicemail = nullptr;
-  }
-#endif
-
   if (mConnection) {
     mConnection->Shutdown();
     mConnection = nullptr;
   }
 
 #ifdef MOZ_B2G_RIL
   if (mMobileConnection) {
     mMobileConnection->Shutdown();
@@ -237,16 +223,24 @@ Navigator::Invalidate()
   if (mCellBroadcast) {
     mCellBroadcast = nullptr;
   }
 
   if (mIccManager) {
     mIccManager->Shutdown();
     mIccManager = nullptr;
   }
+
+  if (mTelephony) {
+    mTelephony = nullptr;
+  }
+
+  if (mVoicemail) {
+    mVoicemail = nullptr;
+  }
 #endif
 
 #ifdef MOZ_B2G_BT
   if (mBluetooth) {
     mBluetooth = nullptr;
   }
 #endif
 
@@ -1224,17 +1218,17 @@ Navigator::GetMozIccManager(ErrorResult&
 {
   if (!mIccManager) {
     if (!mWindow) {
       aRv.Throw(NS_ERROR_UNEXPECTED);
       return nullptr;
     }
     NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr);
 
-    mIccManager = new icc::IccManager();
+    mIccManager = new IccManager();
     mIccManager->Init(mWindow);
   }
 
   return mIccManager;
 }
 
 #endif // MOZ_B2G_RIL
 
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -65,37 +65,32 @@ class MozIdleObserver;
 class Gamepad;
 #endif // MOZ_GAMEPAD
 #ifdef MOZ_MEDIA_NAVIGATOR
 class NavigatorUserMediaSuccessCallback;
 class NavigatorUserMediaErrorCallback;
 class MozGetUserMediaDevicesSuccessCallback;
 #endif // MOZ_MEDIA_NAVIGATOR
 
-namespace icc {
-#ifdef MOZ_B2G_RIL
-class IccManager;
-#endif
-}
-
 namespace network {
 class Connection;
 #ifdef MOZ_B2G_RIL
 class MobileConnection;
 #endif
 } // namespace Connection;
 
 #ifdef MOZ_B2G_BT
 namespace bluetooth {
 class BluetoothManager;
 } // namespace bluetooth
 #endif // MOZ_B2G_BT
 
 #ifdef MOZ_B2G_RIL
 class CellBroadcast;
+class IccManager;
 class Telephony;
 class Voicemail;
 #endif
 
 class PowerManager;
 
 namespace time {
 class TimeManager;
@@ -326,25 +321,23 @@ private:
   nsRefPtr<Geolocation> mGeolocation;
   nsRefPtr<DesktopNotificationCenter> mNotification;
   nsRefPtr<battery::BatteryManager> mBatteryManager;
 #ifdef MOZ_B2G_FM
   nsRefPtr<FMRadio> mFMRadio;
 #endif
   nsRefPtr<PowerManager> mPowerManager;
   nsRefPtr<MobileMessageManager> mMobileMessageManager;
-#ifdef MOZ_B2G_RIL
-  nsRefPtr<Telephony> mTelephony;
-  nsRefPtr<Voicemail> mVoicemail;
-#endif
   nsRefPtr<network::Connection> mConnection;
 #ifdef MOZ_B2G_RIL
   nsRefPtr<network::MobileConnection> mMobileConnection;
   nsRefPtr<CellBroadcast> mCellBroadcast;
-  nsRefPtr<icc::IccManager> mIccManager;
+  nsRefPtr<IccManager> mIccManager;
+  nsRefPtr<Telephony> mTelephony;
+  nsRefPtr<Voicemail> mVoicemail;
 #endif
 #ifdef MOZ_B2G_BT
   nsCOMPtr<bluetooth::BluetoothManager> mBluetooth;
 #endif
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
   nsRefPtr<system::AudioChannelManager> mAudioChannelManager;
 #endif
   nsRefPtr<nsDOMCameraManager> mCameraManager;
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -778,18 +778,17 @@ DOMInterfaces = {
     'nativeType': 'nsDOMAttributeMap',
 },
 
 'MozPowerManager': {
     'nativeType': 'mozilla::dom::PowerManager',
 },
 
 'MozStkCommandEvent' : {
-    'nativeType': 'mozilla::dom::icc::StkCommandEvent',
-    'headerFile': 'StkCommandEvent.h',
+    'nativeType': 'mozilla::dom::StkCommandEvent',
 },
 
 'MozTimeManager': {
     'nativeType': 'mozilla::dom::time::TimeManager',
 },
 
 'MozVoicemail': {
     'nativeType': 'mozilla::dom::Voicemail',
@@ -1867,9 +1866,9 @@ addExternalIface('CameraCapabilities', n
 addExternalIface('CameraAutoFocusCallback', nativeType='nsICameraAutoFocusCallback', headerFile='nsIDOMCameraManager.h')
 addExternalIface('CameraShutterCallback', nativeType='nsICameraShutterCallback', headerFile='nsIDOMCameraManager.h')
 addExternalIface('CameraClosedCallback', nativeType='nsICameraClosedCallback', headerFile='nsIDOMCameraManager.h')
 addExternalIface('CameraTakePictureCallback', nativeType='nsICameraTakePictureCallback', headerFile='nsIDOMCameraManager.h')
 addExternalIface('CameraReleaseCallback', nativeType='nsICameraReleaseCallback', headerFile='nsIDOMCameraManager.h')
 addExternalIface('CameraStartRecordingCallback', nativeType='nsICameraStartRecordingCallback', headerFile='nsIDOMCameraManager.h')
 addExternalIface('CameraPreviewStateChange', nativeType='nsICameraPreviewStateChange', headerFile='nsIDOMCameraManager.h')
 addExternalIface('CameraPreviewStreamCallback', nativeType='nsICameraPreviewStreamCallback', headerFile='nsIDOMCameraManager.h')
-addExternalIface('CameraRecorderStateChange', nativeType='nsICameraRecorderStateChange', headerFile='nsIDOMCameraManager.h')
\ No newline at end of file
+addExternalIface('CameraRecorderStateChange', nativeType='nsICameraRecorderStateChange', headerFile='nsIDOMCameraManager.h')
--- a/dom/bindings/Makefile.in
+++ b/dom/bindings/Makefile.in
@@ -90,22 +90,16 @@ LOCAL_INCLUDES += -I$(topsrcdir)/js/xpco
   $(NULL)
 
 ifdef MOZ_AUDIO_CHANNEL_MANAGER
 LOCAL_INCLUDES += \
   -I$(topsrcdir)/dom/system/gonk \
   $(NULL)
 endif
 
-ifdef MOZ_B2G_RIL
-LOCAL_INCLUDES += \
-  -I$(topsrcdir)/dom/icc/src \
-  $(NULL)
-endif
-
 ABS_DIST := $(abspath $(DIST))
 
 EXTRA_EXPORT_MDDEPEND_FILES := $(addsuffix .pp,$(binding_dependency_trackers))
 
 EXPORTS_GENERATED_FILES := $(exported_binding_headers) $(exported_generated_events_headers)
 EXPORTS_GENERATED_DEST := $(ABS_DIST)/include/$(binding_include_path)
 EXPORTS_GENERATED_TARGET := export
 INSTALL_TARGETS += EXPORTS_GENERATED
--- a/dom/dom-config.mk
+++ b/dom/dom-config.mk
@@ -36,17 +36,16 @@ DOM_SRCDIRS = \
   layout/xul/tree \
   dom/camera \
   $(NULL)
 
 ifdef MOZ_B2G_RIL
 DOM_SRCDIRS += \
   dom/system/gonk \
   dom/wifi \
-  dom/icc/src \
   $(NULL)
 endif
 
 ifdef MOZ_B2G_FM
 DOM_SRCDIRS += \
   dom/fmradio \
   $(NULL)
 endif
--- a/dom/icc/interfaces/SimToolKit.idl
+++ b/dom/icc/interfaces/SimToolKit.idl
@@ -618,16 +618,33 @@ dictionary MozStkLanguageSelectionEvent
    * Language Information
    *
    * @see ISO 639-1, Alpha-2 code
    *      "de" for German, "en" for English, "zh" for Chinese, etc.
    */
   DOMString language;
 };
 
+dictionary MozStkBrowserTerminationEvent
+{
+  /**
+   * The type of this event.
+   * It shall be nsIDOMMozIccManager.STK_EVENT_TYPE_BROWSER_TERMINATION
+   */
+  unsigned short eventType;
+
+  /**
+   * This object shall contain the browser termination cause.
+   * See TZ 102 223 8.51. It shall be one of following:
+   * - nsIDOMMozIccManager.STK_BROWSER_TERMINATION_CAUSE_USER
+   * - nsIDOMMozIccManager.STK_BROWSER_TERMINATION_CAUSE_ERROR
+   */
+  unsigned short terminationCause;
+};
+
 dictionary MozStkGeneralEvent
 {
   /**
    * The type of this event, MozStkGeneralEvent can be used for all Stk Event
    * requires no more parameter than event type, including
    * nsIDOMMozIccManager.STK_EVENT_TYPE_USER_ACTIVITY.
    * nsIDOMMozIccManager.STK_EVENT_TYPE_IDLE_SCREEN_AVAILABLE.
    * HCI Connectivity Event(Not defined in interface yet).
--- a/dom/icc/interfaces/nsIDOMIccManager.idl
+++ b/dom/icc/interfaces/nsIDOMIccManager.idl
@@ -4,17 +4,17 @@
 
 #include "nsIDOMEventTarget.idl"
 #include "SimToolKit.idl"
 
 interface nsIDOMDOMRequest;
 interface nsIDOMEventListener;
 interface nsIDOMMozIccInfo;
 
-[scriptable, builtinclass, uuid(6b5875dc-de44-4681-84a1-9ea12d60fbe2)]
+[scriptable, builtinclass, uuid(b403e307-e4ff-47a0-ac1e-c97b042b4595)]
 interface nsIDOMMozIccManager : nsIDOMEventTarget
 {
   /**
    * STK Menu Presentation types.
    */
   const unsigned short STK_MENU_TYPE_NOT_SPECIFIED      = 0x00;
   const unsigned short STK_MENU_TYPE_DATA_VALUES        = 0x01;
   const unsigned short STK_MENU_TYPE_NAVIGATION_OPTIONS = 0x03;
@@ -211,16 +211,22 @@ interface nsIDOMMozIccManager : nsIDOMEv
    /**
    * Timer Management
    */
   const unsigned short STK_TIMER_START             = 0x00;
   const unsigned short STK_TIMER_DEACTIVATE        = 0x01;
   const unsigned short STK_TIMER_GET_CURRENT_VALUE = 0x02;
 
   /**
+   * Browser Termination Cause
+   */
+  const unsigned short STK_BROWSER_TERMINATION_CAUSE_USER  = 0x00;
+  const unsigned short STK_BROWSER_TERMINATION_CAUSE_ERROR = 0x01;
+
+  /**
    * Send the response back to ICC after an attempt to execute STK Proactive
    * Command.
    *
    * @param command
    *        Command received from ICC. See MozStkCommand.
    * @param response
    *        The response that will be sent to ICC.
    * @see MozStkResponse for the detail of response.
@@ -255,16 +261,17 @@ interface nsIDOMMozIccManager : nsIDOMEv
    * ICC will not respond with any data for this command.
    *
    * @param event
    *        one of events below:
    *        - MozStkLocationEvent
    *        - MozStkCallEvent
    *        - MozStkLanguageSelectionEvent
    *        - MozStkGeneralEvent
+   *        - MozStkBrowserTerminationEvent
    */
   void sendStkEventDownload(in jsval event);
 
   /**
    * The 'stkcommand' event is notified whenever STK Proactive Command is
    * issued from ICC.
    */
   [implicit_jscontext] attribute jsval onstkcommand;
--- a/dom/icc/src/IccManager.cpp
+++ b/dom/icc/src/IccManager.cpp
@@ -1,23 +1,24 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "mozilla/dom/IccManager.h"
+
+#include "GeneratedEvents.h"
+#include "mozilla/dom/StkCommandEvent.h"
 #include "mozilla/Services.h"
 #include "nsIDOMClassInfo.h"
 #include "nsIDOMIccInfo.h"
-#include "GeneratedEvents.h"
-#include "IccManager.h"
 #include "SimToolKit.h"
-#include "StkCommandEvent.h"
 
 #define NS_RILCONTENTHELPER_CONTRACTID "@mozilla.org/ril/content-helper;1"
 
-using namespace mozilla::dom::icc;
+using namespace mozilla::dom;
 
 class IccManager::Listener : public nsIIccListener
 {
   IccManager* mIccManager;
 
 public:
   NS_DECL_ISUPPORTS
   NS_FORWARD_SAFE_NSIICCLISTENER(mIccManager)
@@ -33,17 +34,17 @@ public:
   {
     MOZ_ASSERT(mIccManager);
     mIccManager = nullptr;
   }
 };
 
 NS_IMPL_ISUPPORTS1(IccManager::Listener, nsIIccListener)
 
-DOMCI_DATA(MozIccManager, mozilla::dom::icc::IccManager)
+DOMCI_DATA(MozIccManager, IccManager)
 
 NS_INTERFACE_MAP_BEGIN(IccManager)
   NS_INTERFACE_MAP_ENTRY(nsIDOMMozIccManager)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozIccManager)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(IccManager, nsDOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(IccManager, nsDOMEventTargetHelper)
@@ -272,9 +273,9 @@ IccManager::NotifyCardStateChanged()
 {
   return DispatchTrustedEvent(NS_LITERAL_STRING("cardstatechange"));
 }
 
 NS_IMETHODIMP
 IccManager::NotifyIccInfoChanged()
 {
   return DispatchTrustedEvent(NS_LITERAL_STRING("iccinfochange"));
-}
\ No newline at end of file
+}
--- a/dom/icc/src/IccManager.h
+++ b/dom/icc/src/IccManager.h
@@ -1,23 +1,22 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef mozilla_dom_icc_IccManager_h
-#define mozilla_dom_icc_IccManager_h
+#ifndef mozilla_dom_IccManager_h
+#define mozilla_dom_IccManager_h
 
 #include "nsCycleCollectionParticipant.h"
 #include "nsDOMEventTargetHelper.h"
 #include "nsIDOMIccManager.h"
 #include "nsIIccProvider.h"
 
 namespace mozilla {
 namespace dom {
-namespace icc {
 
 class IccManager : public nsDOMEventTargetHelper
                  , public nsIDOMMozIccManager
 {
   /**
    * Class IccManager doesn't actually inherit nsIIccListener. Instead, it owns
    * an nsIIccListener derived instance mListener and passes it to
    * nsIIccProvider. The onreceived events are first delivered to mListener and
@@ -37,13 +36,12 @@ public:
   void Init(nsPIDOMWindow *aWindow);
   void Shutdown();
 
 private:
   nsCOMPtr<nsIIccProvider> mProvider;
   nsRefPtr<Listener> mListener;
 };
 
-} // namespace icc
 } // namespace dom
 } // namespace mozilla
 
-#endif // mozilla_dom_icc_IccManager_h
+#endif // mozilla_dom_IccManager_h
--- a/dom/icc/src/StkCommandEvent.cpp
+++ b/dom/icc/src/StkCommandEvent.cpp
@@ -1,25 +1,24 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "SimToolKit.h"
-#include "StkCommandEvent.h"
+#include "mozilla/dom/StkCommandEvent.h"
 
-#include "nsJSON.h"
 #include "jsapi.h"
 #include "jsfriendapi.h"
+#include "nsJSON.h"
+#include "SimToolKit.h"
 
 namespace mozilla {
 namespace dom {
-namespace icc {
 
 already_AddRefed<StkCommandEvent>
-StkCommandEvent::Create(mozilla::dom::EventTarget* aOwner,
+StkCommandEvent::Create(EventTarget* aOwner,
                         const nsAString& aMessage)
 {
   nsRefPtr<StkCommandEvent> event = new StkCommandEvent(aOwner);
   event->mCommand = aMessage;
   return event.forget();
 }
 
 NS_IMPL_ADDREF_INHERITED(StkCommandEvent, nsDOMEvent)
@@ -40,11 +39,10 @@ StkCommandEvent::GetCommand(JSContext* a
     NS_ENSURE_SUCCESS(rv, rv);
   } else {
     *aCommand = JSVAL_VOID;
   }
 
   return NS_OK;
 }
 
-}
-}
-}
+} // namespace dom
+} // namespace mozilla
--- a/dom/icc/src/StkCommandEvent.h
+++ b/dom/icc/src/StkCommandEvent.h
@@ -1,22 +1,21 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef mozilla_dom_icc_stkcommandevent_h
-#define mozilla_dom_icc_stkcommandevent_h
+#ifndef mozilla_dom_StkCommandEvent_h
+#define mozilla_dom_StkCommandEvent_h
 
+#include "mozilla/dom/MozStkCommandEventBinding.h"
 #include "nsDOMEvent.h"
 #include "SimToolKit.h"
-#include "mozilla/dom/MozStkCommandEventBinding.h"
 
 namespace mozilla {
 namespace dom {
-namespace icc {
 
 class StkCommandEvent : public nsDOMEvent,
                         public nsIDOMMozStkCommandEvent
 {
   nsString mCommand;
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
@@ -44,34 +43,33 @@ public:
     NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_OK;
   }
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aScope) MOZ_OVERRIDE
   {
-    return mozilla::dom::MozStkCommandEventBinding::Wrap(aCx, aScope, this);
+    return MozStkCommandEventBinding::Wrap(aCx, aScope, this);
   }
 
-  JS::Value GetCommand(JSContext* aCx, mozilla::ErrorResult& aRv)
+  JS::Value GetCommand(JSContext* aCx, ErrorResult& aRv)
   {
     JS::Rooted<JS::Value> retVal(aCx);
     aRv = GetCommand(aCx, retVal.address());
     return retVal;
   }
 
 private:
-  StkCommandEvent(mozilla::dom::EventTarget* aOwner)
+  StkCommandEvent(EventTarget* aOwner)
   : nsDOMEvent(aOwner, nullptr, nullptr)
   {
     SetIsDOMBinding();
   }
 
   ~StkCommandEvent()
   { }
 };
 
-}
-}
-}
+} // namespace dom
+} // namespace mozilla
 
-#endif // mozilla_dom_icc_stkcommandevent_h
+#endif // mozilla_dom_StkCommandEvent_h
--- a/dom/icc/src/moz.build
+++ b/dom/icc/src/moz.build
@@ -1,15 +1,16 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-EXPORTS.mozilla.dom.icc += [
+EXPORTS.mozilla.dom += [
+    'IccManager.h',
     'StkCommandEvent.h',
 ]
 
 CPP_SOURCES += [
     'IccManager.cpp',
     'StkCommandEvent.cpp',
 ]
 
--- a/dom/network/src/Makefile.in
+++ b/dom/network/src/Makefile.in
@@ -1,23 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 VPATH            = $(srcdir)
 
-ifdef MOZ_B2G_RIL
-endif
-
 include $(topsrcdir)/dom/dom-config.mk
 
 LOCAL_INCLUDES = \
   -I$(topsrcdir)/content/events/src \
   $(NULL)
 
-ifdef MOZ_B2G_RIL
-LOCAL_INCLUDES += \
-  -I$(topsrcdir)/dom/icc/src \
-  $(NULL)
-endif
-
 include $(topsrcdir)/config/rules.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -707,16 +707,17 @@ this.COMPREHENSIONTLV_TAG_EVENT_LIST = 0
 this.COMPREHENSIONTLV_TAG_ICON_ID = 0x1e;
 this.COMPREHENSIONTLV_TAG_ICON_ID_LIST = 0x1f;
 this.COMPREHENSIONTLV_TAG_TIMER_IDENTIFIER = 0x24;
 this.COMPREHENSIONTLV_TAG_TIMER_VALUE = 0x25;
 this.COMPREHENSIONTLV_TAG_DATE_TIME_ZONE = 0x26;
 this.COMPREHENSIONTLV_TAG_IMMEDIATE_RESPONSE = 0x2b;
 this.COMPREHENSIONTLV_TAG_LANGUAGE = 0x2d;
 this.COMPREHENSIONTLV_TAG_URL = 0x31;
+this.COMPREHENSIONTLV_TAG_BROWSER_TERMINATION_CAUSE = 0x34;
 this.COMPREHENSIONTLV_TAG_ACCESS_TECH = 0x3f;
 this.COMPREHENSIONTLV_TAG_SERVICE_RECORD = 0x41;
 this.COMPREHENSIONTLV_TAG_IMEISV = 0x62;
 this.COMPREHENSIONTLV_TAG_BATTERY_STATE = 0x63;
 this.COMPREHENSIONTLV_TAG_NETWORK_SEARCH_MODE = 0x65;
 this.COMPREHENSIONTLV_TAG_MEID = 0x6d;
 this.COMPREHENSIONTLV_TAG_BROADCAST_NETWORK_INFO = 0x7a;
 
@@ -959,16 +960,20 @@ this.STK_LOCAL_INFO_MULTIPLE_ACCESS_TECH
 this.STK_LOCAL_INFO_INFO_FOR_MULTIPLE_ACCESS_TECH = 0x0F;
 this.STK_LOCAL_INFO_NMR_FOR_MULTIPLE_ACCESS_TECH = 0x10;
 
 // Timer Management.
 this.STK_TIMER_START = 0x00;
 this.STK_TIMER_DEACTIVATE = 0x01;
 this.STK_TMIER_GET_CURRENT_VALUE = 0x02;
 
+// Browser Termination Cause.
+this.STK_BROWSER_TERMINATION_CAUSE_USER = 0x00;
+this.STK_BROWSER_TERMINATION_CAUSE_ERROR = 0x01;
+
 /**
  * Supported Terminal Facilities.
  *
  * value = 1, supported.
  *         0, not supported.
  */
 this.STK_TERMINAL_SUPPORT_PROFILE_DOWNLOAD             = 1;
 this.STK_TERMINAL_SUPPORT_SMS_PP_DOWNLOAD              = 1;
@@ -1011,17 +1016,17 @@ this.STK_TERMINAL_SUPPORT_EVENT_MT_CALL 
 this.STK_TERMINAL_SUPPORT_EVENT_CALL_CONNECTED         = 1;
 this.STK_TERMINAL_SUPPORT_EVENT_CALL_DISCONNECTED      = 1;
 this.STK_TERMINAL_SUPPORT_EVENT_LOCATION_STATUS        = 1;
 this.STK_TERMINAL_SUPPORT_EVENT_USER_ACTIVITY          = 1;
 this.STK_TERMINAL_SUPPORT_EVENT_IDLE_SCREEN_AVAILABLE  = 1;
 this.STK_TERMINAL_SUPPORT_EVENT_CARD_READER_STATUS     = 0;
 
 this.STK_TERMINAL_SUPPORT_EVENT_LANGUAGE_SELECTION     = 1;
-this.STK_TERMINAL_SUPPORT_EVENT_BROWSER_TERMINATION    = 0;
+this.STK_TERMINAL_SUPPORT_EVENT_BROWSER_TERMINATION    = 1;
 this.STK_TERMINAL_SUPPORT_EVENT_DATA_AVAILABLE         = 0;
 this.STK_TERMINAL_SUPPORT_EVENT_CHANNEL_STATUS         = 0;
 
 this.STK_TERMINAL_SUPPORT_PROACTIVE_TIMER_START_STOP   = 1;
 this.STK_TERMINAL_SUPPORT_PROACTIVE_TIMER_GET_CURRENT  = 1;
 this.STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_DATE    = 1;
 this.STK_TERMINAL_SUPPORT_GET_INKEY                    = 1;
 this.STK_TERMINAL_SUPPORT_SET_UP_IDLE_MODE_TEXT        = 1;
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -2722,16 +2722,23 @@ let RIL = {
         break;
       case STK_EVENT_TYPE_LANGUAGE_SELECTION:
         command.deviceId = {
           sourceId: STK_DEVICE_ID_ME,
           destinationId: STK_DEVICE_ID_SIM
         };
         command.language = command.event.language;
         break;
+      case STK_EVENT_TYPE_BROWSER_TERMINATION:
+        command.deviceId = {
+          sourceId: STK_DEVICE_ID_ME,
+          destinationId: STK_DEVICE_ID_SIM
+        };
+        command.terminationCause = command.event.terminationCause;
+        break;
     }
     this.sendICCEnvelopeCommand(command);
   },
 
   /**
    * Send REQUEST_STK_SEND_ENVELOPE_COMMAND to ICC.
    *
    * @param tag
@@ -2741,16 +2748,17 @@ let RIL = {
    * @param [optional] eventList
    * @param [optional] locationStatus
    * @param [optional] locationInfo
    * @param [optional] address
    * @param [optional] transactionId
    * @param [optional] cause
    * @param [optional] timerId
    * @param [optional] timerValue
+   * @param [optional] terminationCause
    */
   sendICCEnvelopeCommand: function sendICCEnvelopeCommand(options) {
     if (DEBUG) {
       debug("Stk Envelope " + JSON.stringify(options));
     }
     Buf.newParcel(REQUEST_STK_SEND_ENVELOPE_COMMAND);
 
     // 1st mark for Parcel size
@@ -2848,16 +2856,24 @@ let RIL = {
         ComprehensionTlvHelper.writeTimerValueTlv(options.timerValue, true);
     }
 
     // Language
     if (options.language) {
       ComprehensionTlvHelper.writeLanguageTlv(options.language);
     }
 
+    // Browser Termination
+    if (options.terminationCause != null) {
+      GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_BROWSER_TERMINATION_CAUSE |
+                                 COMPREHENSIONTLV_FLAG_CR);
+      GsmPDUHelper.writeHexOctet(1);
+      GsmPDUHelper.writeHexOctet(options.terminationCause);
+    }
+
     // Calculate and write BER length to 2nd mark
     Buf.stopCalOutgoingSize();
 
     // Calculate and write Parcel size to 1st mark
     Buf.stopCalOutgoingSize();
 
     Buf.writeInt32(0);
     Buf.sendParcel();
--- a/dom/system/gonk/tests/test_ril_worker_stk.js
+++ b/dom/system/gonk/tests/test_ril_worker_stk.js
@@ -968,8 +968,65 @@ add_test(function test_stk_event_downloa
 
   let event = {
     eventType: STK_EVENT_TYPE_IDLE_SCREEN_AVAILABLE
   };
   worker.RIL.sendStkEventDownload({
     event: event
   });
 });
+
+/**
+ * Verify Event Downloaded Command :Browser Termination
+ */
+add_test(function test_stk_event_download_browser_termination() {
+  let worker = newUint8SupportOutgoingIndexWorker();
+  let buf = worker.Buf;
+  let pduHelper = worker.GsmPDUHelper;
+
+  buf.sendParcel = function () {
+    // Type
+    do_check_eq(this.readInt32(), REQUEST_STK_SEND_ENVELOPE_COMMAND);
+
+    // Token : we don't care
+    this.readInt32();
+
+    // Data Size, 24 = 2 * ( 2+TLV_DEVICE_ID(4)+TLV_EVENT_LIST_SIZE(3)
+    //                        +TLV_BROWSER_TERMINATION_CAUSE(3) )
+    do_check_eq(this.readInt32(), 24);
+
+    // BER tag
+    do_check_eq(pduHelper.readHexOctet(), BER_EVENT_DOWNLOAD_TAG);
+
+    // BER length, 10 = TLV_DEVICE_ID(4)+TLV_EVENT_LIST_SIZE(3)
+    //                  ++TLV_BROWSER_TERMINATION_CAUSE(3)
+    do_check_eq(pduHelper.readHexOctet(), 10);
+
+    // Device Identities, Type-Length-Value(Source ID-Destination ID)
+    do_check_eq(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DEVICE_ID |
+                                          COMPREHENSIONTLV_FLAG_CR);
+    do_check_eq(pduHelper.readHexOctet(), 2);
+    do_check_eq(pduHelper.readHexOctet(), STK_DEVICE_ID_ME);
+    do_check_eq(pduHelper.readHexOctet(), STK_DEVICE_ID_SIM);
+
+    // Event List, Type-Length-Value
+    do_check_eq(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_EVENT_LIST |
+                                          COMPREHENSIONTLV_FLAG_CR);
+    do_check_eq(pduHelper.readHexOctet(), 1);
+    do_check_eq(pduHelper.readHexOctet(), STK_EVENT_TYPE_BROWSER_TERMINATION);
+
+    // Browser Termination Case, Type-Length-Value
+    do_check_eq(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_BROWSER_TERMINATION_CAUSE |
+                                          COMPREHENSIONTLV_FLAG_CR);
+    do_check_eq(pduHelper.readHexOctet(), 1);
+    do_check_eq(pduHelper.readHexOctet(), STK_BROWSER_TERMINATION_CAUSE_USER);
+
+    run_next_test();
+  };
+
+  let event = {
+    eventType: STK_EVENT_TYPE_BROWSER_TERMINATION,
+    terminationCause: STK_BROWSER_TERMINATION_CAUSE_USER
+  };
+  worker.RIL.sendStkEventDownload({
+    event: event
+  });
+});
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -3670,43 +3670,33 @@ nsDisplayScrollLayer::GetScrollLayerCoun
   // that it is processed last.
   NS_ABORT_IF_FALSE(hasCount, "nsDisplayScrollLayer should always be defined");
   return result;
 #else
   return reinterpret_cast<intptr_t>(props.Get(nsIFrame::ScrollLayerCount()));
 #endif
 }
 
-intptr_t
-nsDisplayScrollLayer::RemoveScrollLayerCount()
-{
-  intptr_t result = GetScrollLayerCount();
-  FrameProperties props = mScrolledFrame->Properties();
-  props.Remove(nsIFrame::ScrollLayerCount());
-  return result;
-}
-
-
 nsDisplayScrollInfoLayer::nsDisplayScrollInfoLayer(
   nsDisplayListBuilder* aBuilder,
   nsIFrame* aScrolledFrame,
   nsIFrame* aScrollFrame)
   : nsDisplayScrollLayer(aBuilder, aScrollFrame, aScrolledFrame, aScrollFrame)
 {
 #ifdef NS_BUILD_REFCNT_LOGGING
   MOZ_COUNT_CTOR(nsDisplayScrollInfoLayer);
 #endif
 }
 
-#ifdef NS_BUILD_REFCNT_LOGGING
 nsDisplayScrollInfoLayer::~nsDisplayScrollInfoLayer()
 {
+  FrameProperties props = mScrolledFrame->Properties();
+  props.Remove(nsIFrame::ScrollLayerCount());
   MOZ_COUNT_DTOR(nsDisplayScrollInfoLayer);
 }
-#endif
 
 LayerState
 nsDisplayScrollInfoLayer::GetLayerState(nsDisplayListBuilder* aBuilder,
                                         LayerManager* aManager,
                                         const ContainerParameters& aParameters)
 {
   return LAYER_ACTIVE_EMPTY;
 }
@@ -3720,17 +3710,17 @@ nsDisplayScrollInfoLayer::TryMerge(nsDis
 
 bool
 nsDisplayScrollInfoLayer::ShouldFlattenAway(nsDisplayListBuilder* aBuilder)
 {
   // Layer metadata for a particular scroll frame needs to be unique. Only
   // one nsDisplayScrollLayer (with rendered content) or one
   // nsDisplayScrollInfoLayer (with only the metadata) should survive the
   // visibility computation.
-  return RemoveScrollLayerCount() == 1;
+  return GetScrollLayerCount() == 1;
 }
 
 nsDisplayZoom::nsDisplayZoom(nsDisplayListBuilder* aBuilder,
                              nsIFrame* aFrame, nsDisplayList* aList,
                              int32_t aAPD, int32_t aParentAPD,
                              uint32_t aFlags)
     : nsDisplayOwnLayer(aBuilder, aFrame, aList, aFlags)
     , mAPD(aAPD), mParentAPD(aParentAPD) {
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -2723,21 +2723,20 @@ public:
                           nsDisplayItem* aItem) MOZ_OVERRIDE;
 
   virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
 
   // Get the number of nsDisplayScrollLayers for a scroll frame. Note that this
   // number does not include nsDisplayScrollInfoLayers. If this number is not 1
   // after merging, all the nsDisplayScrollLayers should flatten away.
   intptr_t GetScrollLayerCount();
-  intptr_t RemoveScrollLayerCount();
 
   virtual nsIFrame* GetScrolledFrame() { return mScrolledFrame; }
 
-private:
+protected:
   nsIFrame* mScrollFrame;
   nsIFrame* mScrolledFrame;
 };
 
 /**
  * Like nsDisplayScrollLayer, but only has metadata on the scroll frame. This
  * creates a layer that has no Thebes child layer, but still allows the
  * compositor process to know of the scroll frame's existence.
@@ -2750,19 +2749,17 @@ private:
  */
 class nsDisplayScrollInfoLayer : public nsDisplayScrollLayer
 {
 public:
   nsDisplayScrollInfoLayer(nsDisplayListBuilder* aBuilder,
                            nsIFrame* aScrolledFrame, nsIFrame* aScrollFrame);
   NS_DISPLAY_DECL_NAME("ScrollInfoLayer", TYPE_SCROLL_INFO_LAYER)
 
-#ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayScrollInfoLayer();
-#endif
 
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerParameters& aParameters) MOZ_OVERRIDE;
   virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE
   { return true; }
   virtual bool TryMerge(nsDisplayListBuilder* aBuilder,
                           nsDisplayItem* aItem) MOZ_OVERRIDE;
--- a/toolkit/devtools/client/dbg-client.jsm
+++ b/toolkit/devtools/client/dbg-client.jsm
@@ -640,17 +640,17 @@ DebuggerClient.prototype = {
    * @param aIgnoreCompatibility boolean
    *        Set true to not pass the packet through the compatibility layer.
    */
   onPacket: function DC_onPacket(aPacket, aIgnoreCompatibility=false) {
     let packet = aIgnoreCompatibility
       ? aPacket
       : this.compat.onPacket(aPacket);
 
-    resolve(packet).then((aPacket) => {
+    resolve(packet).then(aPacket => {
       if (!aPacket.from) {
         let msg = "Server did not specify an actor, dropping packet: " +
                   JSON.stringify(aPacket);
         Cu.reportError(msg);
         dumpn(msg);
         return;
       }
 
@@ -1972,23 +1972,25 @@ LongStringClient.prototype = {
  * @param aClient DebuggerClient
  *        The debugger client parent.
  * @param aForm Object
  *        The form sent across the remote debugging protocol.
  */
 function SourceClient(aClient, aForm) {
   this._form = aForm;
   this._isBlackBoxed = aForm.isBlackBoxed;
+  this._isPrettyPrinted = aForm.isPrettyPrinted;
   this._client = aClient;
 }
 
 SourceClient.prototype = {
   get _transport() this._client._transport,
   get _activeThread() this._client.activeThread,
   get isBlackBoxed() this._isBlackBoxed,
+  get isPrettyPrinted() this._isPrettyPrinted,
   get actor() this._form.actor,
   get request() this._client.request,
   get url() this._form.url,
 
   /**
    * Black box this SourceClient's source.
    *
    * @param aCallback Function
@@ -2048,16 +2050,39 @@ SourceClient.prototype = {
    */
   prettyPrint: function SC_prettyPrint(aIndent, aCallback) {
     const packet = {
       to: this._form.actor,
       type: "prettyPrint",
       indent: aIndent
     };
     this._client.request(packet, aResponse => {
+      if (!aResponse.error) {
+        this._isPrettyPrinted = true;
+        this._activeThread._clearFrames();
+        this._activeThread.notify("prettyprintchange", this);
+      }
+      this._onSourceResponse(aResponse, aCallback);
+    });
+  },
+
+  /**
+   * Stop pretty printing this source's text.
+   */
+  disablePrettyPrint: function SC_disablePrettyPrint(aCallback) {
+    const packet = {
+      to: this._form.actor,
+      type: "disablePrettyPrint"
+    };
+    this._client.request(packet, aResponse => {
+      if (!aResponse.error) {
+        this._isPrettyPrinted = false;
+        this._activeThread._clearFrames();
+        this._activeThread.notify("prettyprintchange", this);
+      }
       this._onSourceResponse(aResponse, aCallback);
     });
   },
 
   _onSourceResponse: function SC__onSourceResponse(aResponse, aCallback) {
     if (aResponse.error) {
       aCallback(aResponse);
       return;
--- a/toolkit/devtools/server/actors/script.js
+++ b/toolkit/devtools/server/actors/script.js
@@ -2360,34 +2360,49 @@ function SourceActor({ url, thread, sour
   this._sourceMap = sourceMap;
   this._generatedSource = generatedSource;
   this._text = text;
   this._contentType = contentType;
 
   this.onSource = this.onSource.bind(this);
   this._invertSourceMap = this._invertSourceMap.bind(this);
   this._saveMap = this._saveMap.bind(this);
+  this._getSourceText = this._getSourceText.bind(this);
+
+  if (this.threadActor.sources.isPrettyPrinted(this.url)) {
+    this._init = this.onPrettyPrint({
+      indent: this.threadActor.sources.prettyPrintIndent(this.url)
+    }).then(null, error => {
+      DevToolsUtils.reportException("SourceActor", error);
+    });
+  } else {
+    this._init = null;
+  }
 }
 
 SourceActor.prototype = {
   constructor: SourceActor,
   actorPrefix: "source",
 
+  _oldSourceMap: null,
+  _init: null,
+
   get threadActor() this._threadActor,
   get url() this._url,
 
   get prettyPrintWorker() {
     return this.threadActor.prettyPrintWorker;
   },
 
   form: function SA_form() {
     return {
       actor: this.actorID,
       url: this._url,
-      isBlackBoxed: this.threadActor.sources.isBlackBoxed(this.url)
+      isBlackBoxed: this.threadActor.sources.isBlackBoxed(this.url),
+      isPrettyPrinted: this.threadActor.sources.isPrettyPrinted(this.url)
       // TODO bug 637572: introductionScript
     };
   },
 
   disconnect: function SA_disconnect() {
     if (this.registeredPool && this.registeredPool.sourceActors) {
       delete this.registeredPool.sourceActors[this.actorID];
     }
@@ -2412,52 +2427,63 @@ SourceActor.prototype = {
     // source because we can't guarantee that the cache has the most up to date
     // content for this source like we can if it isn't source mapped.
     return fetch(this._url, { loadFromCache: !this._sourceMap });
   },
 
   /**
    * Handler for the "source" packet.
    */
-  onSource: function SA_onSource(aRequest) {
-    return this._getSourceText()
+  onSource: function SA_onSource() {
+    return resolve(this._init)
+      .then(this._getSourceText)
       .then(({ content, contentType }) => {
         return {
           from: this.actorID,
           source: this.threadActor.createValueGrip(
             content, this.threadActor.threadLifetimePool),
           contentType: contentType
         };
       })
-      .then(null, (aError) => {
+      .then(null, aError => {
         reportError(aError, "Got an exception during SA_onSource: ");
         return {
           "from": this.actorID,
           "error": "loadSourceError",
           "message": "Could not load the source for " + this._url + ".\n"
             + safeErrorString(aError)
         };
       });
   },
 
   /**
    * Handler for the "prettyPrint" packet.
    */
   onPrettyPrint: function ({ indent }) {
+    this.threadActor.sources.prettyPrint(this._url, indent);
     return this._getSourceText()
       .then(this._parseAST)
       .then(this._sendToPrettyPrintWorker(indent))
       .then(this._invertSourceMap)
       .then(this._saveMap)
+      .then(() => {
+        // We need to reset `_init` now because we have already done the work of
+        // pretty printing, and don't want onSource to wait forever for
+        // initialization to complete.
+        this._init = null;
+      })
       .then(this.onSource)
-      .then(null, error => ({
-        from: this.actorID,
-        error: "prettyPrintError",
-        message: DevToolsUtils.safeErrorString(error)
-      }));
+      .then(null, error => {
+        this.onDisablePrettyPrint();
+        return {
+          from: this.actorID,
+          error: "prettyPrintError",
+          message: DevToolsUtils.safeErrorString(error)
+        };
+      });
   },
 
   /**
    * Parse the source content into an AST.
    */
   _parseAST: function SA__parseAST({ content}) {
     return Reflect.parse(content);
   },
@@ -2567,28 +2593,40 @@ SourceActor.prototype = {
    * Save the source map back to our thread's ThreadSources object so that
    * stepping, breakpoints, debugger statements, etc can use it. If we are
    * pretty printing a source mapped source, we need to compose the existing
    * source map with our new one.
    */
   _saveMap: function SA__saveMap({ map }) {
     if (this._sourceMap) {
       // Compose the source maps
+      this._oldSourceMap = this._sourceMap;
       this._sourceMap = SourceMapGenerator.fromSourceMap(this._sourceMap);
       this._sourceMap.applySourceMap(map, this._url);
       this._sourceMap = SourceMapConsumer.fromSourceMap(this._sourceMap);
       this._threadActor.sources.saveSourceMap(this._sourceMap,
                                               this._generatedSource);
     } else {
       this._sourceMap = map;
       this._threadActor.sources.saveSourceMap(this._sourceMap, this._url);
     }
   },
 
   /**
+   * Handler for the "disablePrettyPrint" packet.
+   */
+  onDisablePrettyPrint: function SA_onDisablePrettyPrint() {
+    this._sourceMap = this._oldSourceMap;
+    this.threadActor.sources.saveSourceMap(this._sourceMap,
+                                           this._generatedSource || this._url);
+    this.threadActor.sources.disablePrettyPrint(this._url);
+    return this.onSource();
+  },
+
+  /**
    * Handler for the "blackbox" packet.
    */
   onBlackBox: function SA_onBlackBox(aRequest) {
     this.threadActor.sources.blackBox(this.url);
     let packet = {
       from: this.actorID
     };
     if (this.threadActor.state == "paused"
@@ -2609,17 +2647,18 @@ SourceActor.prototype = {
     };
   }
 };
 
 SourceActor.prototype.requestTypes = {
   "source": SourceActor.prototype.onSource,
   "blackbox": SourceActor.prototype.onBlackBox,
   "unblackbox": SourceActor.prototype.onUnblackBox,
-  "prettyPrint": SourceActor.prototype.onPrettyPrint
+  "prettyPrint": SourceActor.prototype.onPrettyPrint,
+  "disablePrettyPrint": SourceActor.prototype.onDisablePrettyPrint
 };
 
 
 /**
  * Creates an actor for the specified object.
  *
  * @param aObj Debugger.Object
  *        The debuggee object.
@@ -3713,16 +3752,17 @@ function ThreadSources(aThreadActor, aUs
   this._generatedUrlsByOriginalUrl = Object.create(null);
 }
 
 /**
  * Must be a class property because it needs to persist across reloads, same as
  * the breakpoint store.
  */
 ThreadSources._blackBoxedSources = new Set();
+ThreadSources._prettyPrintedSources = new Map();
 
 ThreadSources.prototype = {
   /**
    * Return the source actor representing |url|, creating one if none
    * exists already. Returns null if |url| is not allowed by the 'allow'
    * predicate.
    *
    * Right now this takes a URL, but in the future it should
@@ -3842,16 +3882,20 @@ ThreadSources.prototype = {
     return map;
   },
 
   /**
    * Save the given source map so that we can use it to query source locations
    * down the line.
    */
   saveSourceMap: function TS_saveSourceMap(aSourceMap, aGeneratedSource) {
+    if (!aSourceMap) {
+      delete this._sourceMapsByGeneratedSource[aGeneratedSource];
+      return null;
+    }
     this._sourceMapsByGeneratedSource[aGeneratedSource] = resolve(aSourceMap);
     for (let s of aSourceMap.sources) {
       this._generatedUrlsByOriginalUrl[s] = aGeneratedSource;
       this._sourceMapsByOriginalSource[s] = resolve(aSourceMap);
     }
     return aSourceMap;
   },
 
@@ -3964,19 +4008,17 @@ ThreadSources.prototype = {
    *        The URL of the source which we are checking whether it is black
    *        boxed or not.
    */
   isBlackBoxed: function TS_isBlackBoxed(aURL) {
     return ThreadSources._blackBoxedSources.has(aURL);
   },
 
   /**
-   * Add the given source URL to the set of sources that are black boxed. If the
-   * thread is currently paused and we are black boxing the yougest frame's
-   * source, this will force a step.
+   * Add the given source URL to the set of sources that are black boxed.
    *
    * @param aURL String
    *        The URL of the source which we are black boxing.
    */
   blackBox: function TS_blackBox(aURL) {
     ThreadSources._blackBoxedSources.add(aURL);
   },
 
@@ -3986,16 +4028,53 @@ ThreadSources.prototype = {
    * @param aURL String
    *        The URL of the source which we are no longer black boxing.
    */
   unblackBox: function TS_unblackBox(aURL) {
     ThreadSources._blackBoxedSources.delete(aURL);
   },
 
   /**
+   * Returns true if the given URL is pretty printed.
+   *
+   * @param aURL String
+   *        The URL of the source that might be pretty printed.
+   */
+  isPrettyPrinted: function TS_isPrettyPrinted(aURL) {
+    return ThreadSources._prettyPrintedSources.has(aURL);
+  },
+
+  /**
+   * Add the given URL to the set of sources that are pretty printed.
+   *
+   * @param aURL String
+   *        The URL of the source to be pretty printed.
+   */
+  prettyPrint: function TS_prettyPrint(aURL, aIndent) {
+    ThreadSources._prettyPrintedSources.set(aURL, aIndent);
+  },
+
+  /**
+   * Return the indent the given URL was pretty printed by.
+   */
+  prettyPrintIndent: function TS_prettyPrintIndent(aURL) {
+    return ThreadSources._prettyPrintedSources.get(aURL);
+  },
+
+  /**
+   * Remove the given URL from the set of sources that are pretty printed.
+   *
+   * @param aURL String
+   *        The URL of the source that is no longer pretty printed.
+   */
+  disablePrettyPrint: function TS_disablePrettyPrint(aURL) {
+    ThreadSources._prettyPrintedSources.delete(aURL);
+  },
+
+  /**
    * Normalize multiple relative paths towards the base paths on the right.
    */
   _normalize: function TS__normalize(...aURLs) {
     dbg_assert(aURLs.length > 1, "Should have more than 1 URL");
     let base = Services.io.newURI(aURLs.pop(), null, null);
     let url;
     while ((url = aURLs.pop())) {
       base = Services.io.newURI(url, null, base);
rename from browser/devtools/shared/helpers.js
rename to toolkit/modules/ShortcutUtils.jsm
--- a/browser/devtools/shared/helpers.js
+++ b/toolkit/modules/ShortcutUtils.jsm
@@ -1,72 +1,100 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-const {Cu} = require("chrome");
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["ShortcutUtils"];
+
+const Cu = Components.utils;
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
-let { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
 XPCOMUtils.defineLazyGetter(this, "PlatformKeys", function() {
   return Services.strings.createBundle(
     "chrome://global-platform/locale/platformKeys.properties");
 });
 
-/**
-  * Prettifies the modifier keys for an element.
-  *
-  * @param Node aElemKey
-  *        The key element to get the modifiers from.
-  * @param boolean aAllowCloverleaf
-  *        Pass true to use the cloverleaf symbol instead of a descriptive string.
-  * @return string
-  *         A prettified and properly separated modifier keys string.
-  */
-exports.prettyKey = function Helpers_prettyKey(aElemKey, aAllowCloverleaf) {
-  let elemString = "";
-  let elemMod = aElemKey.getAttribute("modifiers");
+XPCOMUtils.defineLazyGetter(this, "Keys", function() {
+  return Services.strings.createBundle(
+    "chrome://global/locale/keys.properties");
+});
 
-  if (elemMod.match("accel")) {
-    if (Services.appinfo.OS == "Darwin") {
-      // XXX bug 779642 Use "Cmd-" literal vs. cloverleaf meta-key until
-      // Orion adds variable height lines.
-      if (!aAllowCloverleaf) {
-        elemString += "Cmd-";
+let ShortcutUtils = {
+  /**
+    * Prettifies the modifier keys for an element.
+    *
+    * @param Node aElemKey
+    *        The key element to get the modifiers from.
+    * @param boolean aNoCloverLeaf
+    *        Pass true to use a descriptive string instead of the cloverleaf symbol. (OS X only)
+    * @return string
+    *         A prettified and properly separated modifier keys string.
+    */
+  prettifyShortcut: function(aElemKey, aNoCloverLeaf) {
+    let elemString = "";
+    let elemMod = aElemKey.getAttribute("modifiers");
+
+    if (elemMod.match("accel")) {
+      if (Services.appinfo.OS == "Darwin") {
+        // XXX bug 779642 Use "Cmd-" literal vs. cloverleaf meta-key until
+        // Orion adds variable height lines.
+        if (aNoCloverLeaf) {
+          elemString += "Cmd-";
+        } else {
+          elemString += PlatformKeys.GetStringFromName("VK_META") +
+            PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+        }
       } else {
-        elemString += PlatformKeys.GetStringFromName("VK_META") +
+        elemString += PlatformKeys.GetStringFromName("VK_CONTROL") +
           PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
       }
-    } else {
+    }
+    if (elemMod.match("access")) {
+      if (Services.appinfo.OS == "Darwin") {
+        elemString += PlatformKeys.GetStringFromName("VK_CONTROL") +
+          PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+      } else {
+        elemString += PlatformKeys.GetStringFromName("VK_ALT") +
+          PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+      }
+    }
+    if (elemMod.match("os")) {
+      elemString += PlatformKeys.GetStringFromName("VK_WIN") +
+        PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+    }
+    if (elemMod.match("shift")) {
+      elemString += PlatformKeys.GetStringFromName("VK_SHIFT") +
+        PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+    }
+    if (elemMod.match("alt")) {
+      elemString += PlatformKeys.GetStringFromName("VK_ALT") +
+        PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+    }
+    if (elemMod.match("ctrl") || elemMod.match("control")) {
       elemString += PlatformKeys.GetStringFromName("VK_CONTROL") +
         PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
     }
-  }
-  if (elemMod.match("access")) {
-    if (Services.appinfo.OS == "Darwin") {
-      elemString += PlatformKeys.GetStringFromName("VK_CONTROL") +
-        PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
-    } else {
-      elemString += PlatformKeys.GetStringFromName("VK_ALT") +
+    if (elemMod.match("meta")) {
+      elemString += PlatformKeys.GetStringFromName("VK_META") +
         PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
     }
-  }
-  if (elemMod.match("shift")) {
-    elemString += PlatformKeys.GetStringFromName("VK_SHIFT") +
-      PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
-  }
-  if (elemMod.match("alt")) {
-    elemString += PlatformKeys.GetStringFromName("VK_ALT") +
-      PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+
+    let key;
+    let keyCode = aElemKey.getAttribute("keycode");
+    if (keyCode) {
+      try {
+        // Some keys might not exist in the locale file, which will throw:
+        key = Keys.GetStringFromName(keyCode.toUpperCase());
+      } catch (ex) {
+        Cu.reportError("Error finding " + keyCode + ": " + ex);
+        key = keyCode.replace(/^VK_/, '');
+      }
+    } else {
+      key = aElemKey.getAttribute("key");
+    }
+    return elemString + key;
   }
-  if (elemMod.match("ctrl") || elemMod.match("control")) {
-    elemString += PlatformKeys.GetStringFromName("VK_CONTROL") +
-      PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
-  }
-  if (elemMod.match("meta")) {
-    elemString += PlatformKeys.GetStringFromName("VK_META") +
-      PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
-  }
+};
 
-  return elemString +
-    (aElemKey.getAttribute("keycode").replace(/^.*VK_/, "") ||
-     aElemKey.getAttribute("key")).toUpperCase();
-}
+Object.freeze(ShortcutUtils);
--- a/toolkit/modules/moz.build
+++ b/toolkit/modules/moz.build
@@ -30,16 +30,17 @@ EXTRA_JS_MODULES += [
     'RemoteAddonsParent.jsm',
     'RemoteController.jsm',
     'RemoteFinder.jsm',
     'RemoteSecurityUI.jsm',
     'RemoteWebNavigation.jsm',
     'RemoteWebProgress.jsm',
     'SelectContentHelper.jsm',
     'SelectParentHelper.jsm',
+    'ShortcutUtils.jsm',
     'Sntp.jsm',
     'SpatialNavigation.jsm',
     'Sqlite.jsm',
     'Task.jsm',
     'TelemetryTimestamps.jsm',
     'Timer.jsm',
     'debug.js',
 ]
--- a/tools/profiler/platform.cpp
+++ b/tools/profiler/platform.cpp
@@ -19,16 +19,17 @@
 #include "TableTicker.h"
 #include "UnwinderThread2.h"
 #include "nsIObserverService.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsDirectoryServiceDefs.h"
 #include "mozilla/Services.h"
 #include "nsThreadUtils.h"
 #include "ProfilerMarkers.h"
+#include "nsXULAppAPI.h"
 
 #if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
   #include "AndroidBridge.h"
 #endif
 
 mozilla::ThreadLocal<PseudoStack *> tlsPseudoStack;
 mozilla::ThreadLocal<TableTicker *> tlsTicker;
 mozilla::ThreadLocal<void *> tlsStackTop;
@@ -60,16 +61,23 @@ unsigned int sCurrentEventGeneration = 0
 std::vector<ThreadInfo*>* Sampler::sRegisteredThreads = nullptr;
 mozilla::Mutex* Sampler::sRegisteredThreadsMutex = nullptr;
 
 TableTicker* Sampler::sActiveSampler;
 
 static mozilla::StaticAutoPtr<mozilla::ProfilerIOInterposeObserver>
                                                             sInterposeObserver;
 
+// The name that identifies the gecko thread for calls to
+// profiler_register_thread. For all platform except metro
+// the thread that calls mozilla_sampler_init is considered
+// the gecko thread.  With metro the gecko thread is
+// registered later based on this thread name.
+static const char * gGeckoThreadName = "GeckoMain";
+
 void Sampler::Startup() {
   sRegisteredThreads = new std::vector<ThreadInfo*>();
   sRegisteredThreadsMutex = new mozilla::Mutex("sRegisteredThreads mutex");
 }
 
 void Sampler::Shutdown() {
   while (sRegisteredThreads->size() > 0) {
     delete sRegisteredThreads->back();
@@ -362,16 +370,23 @@ void set_tls_stack_top(void* stackTop)
   // assumes that no target has a page size smaller than 4096.
   uintptr_t stackTopR = (uintptr_t)stackTop;
   if (stackTop) {
     stackTopR = (stackTopR & ~(uintptr_t)4095) + (uintptr_t)4095;
   }
   tlsStackTop.set((void*)stackTopR);
 }
 
+bool is_main_thread_name(const char* aName) {
+  if (aName) {
+    return false;
+  }
+  return strcmp(aName, gGeckoThreadName) == 0;
+}
+
 ////////////////////////////////////////////////////////////////////////
 // BEGIN externally visible functions
 
 void mozilla_sampler_init(void* stackTop)
 {
   sInitCount++;
 
   if (stack_key_initialized)
@@ -384,17 +399,24 @@ void mozilla_sampler_init(void* stackTop
   }
   stack_key_initialized = true;
 
   Sampler::Startup();
 
   PseudoStack *stack = new PseudoStack();
   tlsPseudoStack.set(stack);
 
-  Sampler::RegisterCurrentThread("GeckoMain", stack, true, stackTop);
+  bool isMainThread = true;
+#ifdef XP_WIN
+  // For metrofx, we'll register the main thread once it's created.
+  isMainThread = !(XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro);
+#endif
+  Sampler::RegisterCurrentThread(isMainThread ?
+                                   gGeckoThreadName : "Application Thread",
+                                 stack, isMainThread, stackTop);
 
   // Read mode settings from MOZ_PROFILER_MODE and interval
   // settings from MOZ_PROFILER_INTERVAL and stack-scan threshhold
   // from MOZ_PROFILER_STACK_SCAN.
   read_profiler_env_vars();
 
   // Allow the profiler to be started using signals
   OS::RegisterStartHandler();
@@ -725,18 +747,18 @@ bool mozilla_sampler_register_thread(con
   // running on startup.
   if (!profiler_is_active()) {
     return false;
   }
 #endif
 
   PseudoStack* stack = new PseudoStack();
   tlsPseudoStack.set(stack);
-
-  return Sampler::RegisterCurrentThread(aName, stack, false, stackTop);
+  bool isMainThread = is_main_thread_name(aName);
+  return Sampler::RegisterCurrentThread(aName, stack, isMainThread, stackTop);
 }
 
 void mozilla_sampler_unregister_thread()
 {
   Sampler::UnregisterCurrentThread();
 
   PseudoStack *stack = tlsPseudoStack.get();
   if (!stack) {
--- a/widget/windows/winrt/MetroApp.cpp
+++ b/widget/windows/winrt/MetroApp.cpp
@@ -7,31 +7,34 @@
 #include "MetroWidget.h"
 #include "mozilla/widget/AudioSession.h"
 #include "nsIRunnable.h"
 #include "MetroUtils.h"
 #include "MetroAppShell.h"
 #include "nsICommandLineRunner.h"
 #include "FrameworkView.h"
 #include "nsAppDirectoryServiceDefs.h"
+#include "GeckoProfiler.h"
 #include <shellapi.h>
 
 using namespace ABI::Windows::ApplicationModel;
 using namespace ABI::Windows::ApplicationModel::Core;
 using namespace ABI::Windows::UI::Core;
 using namespace ABI::Windows::System;
 using namespace ABI::Windows::Foundation;
 using namespace Microsoft::WRL;
 using namespace Microsoft::WRL::Wrappers;
 
 // Metro specific XRE methods we call from here on an
 // appropriate thread.
 extern nsresult XRE_metroStartup(bool runXREMain);
 extern void XRE_metroShutdown();
 
+static const char* gGeckoThreadName = "GeckoMain";
+
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* gWindowsLog;
 #endif
 
 namespace mozilla {
 namespace widget {
 namespace winrt {
 
@@ -60,16 +63,22 @@ MetroApp::CreateView(ABI::Windows::Appli
 ////////////////////////////////////////////////////
 // MetroApp impl.
 
 void
 MetroApp::Run()
 {
   LogThread();
 
+  // Name this thread for debugging and register it with the profiler
+  // as the main gecko thread.
+  char aLocal;
+  PR_SetCurrentThreadName(gGeckoThreadName);
+  profiler_register_thread(gGeckoThreadName, &aLocal);
+
   HRESULT hr;
   hr = sCoreApp->add_Suspending(Callback<__FIEventHandler_1_Windows__CApplicationModel__CSuspendingEventArgs_t>(
     this, &MetroApp::OnSuspending).Get(), &mSuspendEvent);
   AssertHRESULT(hr);
 
   hr = sCoreApp->add_Resuming(Callback<__FIEventHandler_1_IInspectable_t>(
     this, &MetroApp::OnResuming).Get(), &mResumeEvent);
   AssertHRESULT(hr);
@@ -96,16 +105,19 @@ MetroApp::ShutdownXPCOM()
   }
 
   if (sFrameworkView) {
     sFrameworkView->ShutdownXPCOM();
   }
 
   // Shut down xpcom
   XRE_metroShutdown();
+
+  // Unhook this thread from the profiler
+  profiler_unregister_thread();
 }
 
 // Request a shutdown of the application
 void
 MetroApp::CoreExit()
 {
   LogFunction();
   HRESULT hr;