Merge fx-team to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 03 Jun 2014 14:41:54 -0400
changeset 205554 9654f1526db498f3394e7c386e309bc22ab23038
parent 205538 e6f5801009752ca35ef2330f59b87cc452a92193 (current diff)
parent 205553 54e8f6d1410a7e395272fd0ced12ed793dec8bc1 (diff)
child 205605 298b39b50ff7b6165f9ba27193258f73a2527649
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone32.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 fx-team to m-c.
browser/themes/shared/devtools/images/dropmarker.png
--- a/browser/components/customizableui/test/browser_995164_registerArea_during_customize_mode.js
+++ b/browser/components/customizableui/test/browser_995164_registerArea_during_customize_mode.js
@@ -80,38 +80,44 @@ add_task(function*() {
 
   simulateItemDrag(syncButton, toolbar);
   ok(CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved out of palette");
   is(CustomizableUI.getPlacementOfWidget("sync-button").area, TOOLBARID, "Button's back on toolbar");
   ok(toolbar.querySelector("#sync-button"), "Sync button really is on toolbar.");
   ok(otherTB.querySelector("#sync-button"), "Sync button is on other toolbar, too.");
 
   let wasInformedCorrectlyOfAreaDisappearing = false;
-  let windowClosed = null;
+  //XXXgijs So we could be using promiseWindowClosed here. However, after
+  // repeated random oranges, I'm instead relying on onWindowClosed below to
+  // fire appropriately - it is linked to an unload event as well, and so
+  // reusing it prevents a potential race between unload handlers where the
+  // one from promiseWindowClosed could fire before the onWindowClosed
+  // (and therefore onAreaNodeRegistered) one, causing the test to fail.
+  let windowCloseDeferred = Promise.defer();
   listener = {
     onAreaNodeUnregistered: function(aArea, aNode, aReason) {
       if (aArea == TOOLBARID) {
         is(aNode, otherTB, "Should be informed about other toolbar");
         is(aReason, CustomizableUI.REASON_WINDOW_CLOSED, "Reason should be correct.");
         wasInformedCorrectlyOfAreaDisappearing = (aReason === CustomizableUI.REASON_WINDOW_CLOSED);
       }
     },
     onWindowClosed: function(aWindow) {
       if (aWindow == otherWin) {
-        info("Got window closed notification for correct window.");
-        windowClosed = aWindow;
+        windowCloseDeferred.resolve(aWindow);
       } else {
         info("Other window was closed!");
         info("Other window title: " + (aWindow.document && aWindow.document.title));
         info("Our window title: " + (otherWin.document && otherWin.document.title));
       }
     },
   };
   CustomizableUI.addListener(listener);
-  yield promiseWindowClosed(otherWin);
+  otherWin.close();
+  let windowClosed = yield windowCloseDeferred.promise;
 
   is(windowClosed, otherWin, "Window should have sent onWindowClosed notification.");
   ok(wasInformedCorrectlyOfAreaDisappearing, "Should be told about window closing.");
   // Closing the other window should not be counted against this window's customize mode:
   is(syncButton.parentNode.localName, "toolbarpaletteitem", "Sync button's parent node should still be a wrapper.");
   isnot(gCustomizeMode.areas.indexOf(toolbar), -1, "Toolbar should still be a customizable area for this customize mode instance.");
 
   yield gCustomizeMode.reset();
--- a/browser/components/customizableui/test/head.js
+++ b/browser/components/customizableui/test/head.js
@@ -244,18 +244,23 @@ function openAndLoadWindow(aOptions, aWa
       win.removeEventListener("load", onLoad);
       deferred.resolve(win);
     });
   }
   return deferred.promise;
 }
 
 function promiseWindowClosed(win) {
+  let deferred = Promise.defer();
+  win.addEventListener("unload", function onunload() {
+    win.removeEventListener("unload", onunload);
+    deferred.resolve();
+  });
   win.close();
-  return waitForCondition(() => win.closed);
+  return deferred.promise;
 }
 
 function promisePanelShown(win) {
   let panelEl = win.PanelUI.panel;
   return promisePanelElementShown(win, panelEl);
 }
 
 function promiseOverflowShown(win) {
--- a/browser/components/preferences/permissions.js
+++ b/browser/components/preferences/permissions.js
@@ -198,16 +198,21 @@ var gPermissionManager = {
                        .getService(Components.interfaces.nsIObserverService);
     os.removeObserver(this, "perm-changed");
   },
   
   observe: function (aSubject, aTopic, aData)
   {
     if (aTopic == "perm-changed") {
       var permission = aSubject.QueryInterface(Components.interfaces.nsIPermission);
+
+      // Ignore unrelated permission types.
+      if (permission.type != this._type)
+        return;
+
       if (aData == "added") {
         this._addPermissionToList(permission);
         ++this._view._rowCount;
         this._tree.treeBoxObject.rowCountChanged(this._view.rowCount - 1, 1);        
         // Re-do the sort, since we inserted this new item at the end. 
         gTreeUtils.sort(this._tree, this._view, this._permissions,
                         this._permissionsComparator,
                         this._lastPermissionSortColumn, 
--- a/browser/components/translation/BingTranslator.jsm
+++ b/browser/components/translation/BingTranslator.jsm
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 this.EXPORTED_SYMBOLS = [ "BingTranslation" ];
 
+Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Log.jsm");
 Cu.import("resource://gre/modules/Promise.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://services-common/utils.js");
 Cu.import("resource://services-common/rest.js");
 
 // The maximum amount of net data allowed per request on Bing's API.
 const MAX_REQUEST_DATA = 5000; // Documentation says 10000 but anywhere
@@ -322,24 +323,26 @@ let BingTokenManager = {
    *                     string once it is obtained.
    */
   _getNewToken: function() {
     let request = new RESTRequest("https://datamarket.accesscontrol.windows.net/v2/OAuth2-13");
     request.setHeader("Content-type", "application/x-www-form-urlencoded");
     let params = [
       "grant_type=client_credentials",
       "scope=" + encodeURIComponent("http://api.microsofttranslator.com"),
-      "client_id=",
-      "client_secret="
+      "client_id=" +
+      getAuthTokenParam("%BING_API_CLIENTID%", "browser.translation.bing.clientIdOverride"),
+      "client_secret=" +
+      getAuthTokenParam("%BING_API_KEY%", "browser.translation.bing.apiKeyOverride")
     ];
 
     let deferred = Promise.defer();
     this._pendingRequest = deferred.promise;
     request.post(params.join("&"), function(err) {
-      this._pendingRequest = null;
+      BingTokenManager._pendingRequest = null;
 
       if (err) {
         deferred.reject(err);
       }
 
       try {
         let json = JSON.parse(this.response.body);
         let token = json.access_token;
@@ -362,8 +365,21 @@ let BingTokenManager = {
 function escapeXML(aStr) {
   return aStr.toString()
              .replace("&", "&amp;", "g")
              .replace('"', "&quot;", "g")
              .replace("'", "&apos;", "g")
              .replace("<", "&lt;", "g")
              .replace(">", "&gt;", "g");
 }
+
+/**
+ * Fetch an auth token (clientID or client secret), which may be overridden by
+ * a pref if it's set.
+ */
+function getAuthTokenParam(key, prefName) {
+  let val;
+  try {
+    val = Services.prefs.getCharPref(prefName);
+  } catch(ex) {}
+
+  return encodeURIComponent(Services.urlFormatter.formatURL(val || key));
+}
--- a/browser/components/translation/translation-infobar.xml
+++ b/browser/components/translation/translation-infobar.xml
@@ -37,37 +37,39 @@
                           anonid="translate"
                           oncommand="document.getBindingParent(this).translate();"/>
               <xul:button class="translate-infobar-element"
                           label="&translation.notNow.button;" anonid="notNow"
                           oncommand="document.getBindingParent(this).close();"/>
             </xul:hbox>
 
             <!-- translating -->
-            <xul:hbox class="translating-box" pack="center">
+            <xul:vbox class="translating-box" pack="center">
               <xul:label class="translate-infobar-element"
                          value="&translation.translatingContent.label;"/>
-            </xul:hbox>
+            </xul:vbox>
 
             <!-- translated -->
             <xul:hbox class="translated-box" align="center">
               <xul:label class="translate-infobar-element"
                          value="&translation.translatedFrom.label;"/>
               <xul:menulist class="translate-infobar-element"
                             anonid="fromLanguage"
                             oncommand="document.getBindingParent(this).translate()">
                 <xul:menupopup/>
               </xul:menulist>
               <xul:label class="translate-infobar-element"
                          value="&translation.translatedTo.label;"/>
-              <xul:menulist anonid="toLanguage"
+              <xul:menulist class="translate-infobar-element"
+                            anonid="toLanguage"
                             oncommand="document.getBindingParent(this).translate()">
                 <xul:menupopup/>
               </xul:menulist>
-              <xul:label value="&translation.translatedToSuffix.label;"/>
+              <xul:label class="translate-infobar-element"
+                         value="&translation.translatedToSuffix.label;"/>
               <xul:button anonid="showOriginal"
                           class="translate-infobar-element"
                           label="&translation.showOriginal.button;"
                           oncommand="document.getBindingParent(this).showOriginal();"/>
               <xul:button anonid="showTranslation"
                           class="translate-infobar-element"
                           label="&translation.showTranslation.button;"
                           oncommand="document.getBindingParent(this).showTranslation();"/>
--- a/browser/devtools/debugger/test/browser.ini
+++ b/browser/devtools/debugger/test/browser.ini
@@ -108,27 +108,30 @@ skip-if = os == 'win' # bug 1005274
 [browser_dbg_break-on-dom-01.js]
 [browser_dbg_break-on-dom-02.js]
 [browser_dbg_break-on-dom-03.js]
 [browser_dbg_break-on-dom-04.js]
 [browser_dbg_break-on-dom-05.js]
 [browser_dbg_break-on-dom-06.js]
 [browser_dbg_break-on-dom-07.js]
 [browser_dbg_break-on-dom-08.js]
+[browser_dbg_break-on-dom-event.js]
+skip-if = os == "mac" || e10s # Bug 895426
 [browser_dbg_breakpoints-actual-location.js]
 [browser_dbg_breakpoints-break-on-last-line-of-script-on-reload.js]
 [browser_dbg_breakpoints-button-01.js]
 [browser_dbg_breakpoints-button-02.js]
 [browser_dbg_breakpoints-contextmenu-add.js]
 [browser_dbg_breakpoints-contextmenu.js]
 [browser_dbg_breakpoints-disabled-reload.js]
 [browser_dbg_breakpoints-editor.js]
 [browser_dbg_breakpoints-highlight.js]
 [browser_dbg_breakpoints-new-script.js]
 [browser_dbg_breakpoints-pane.js]
+[browser_dbg_chrome-create.js]
 [browser_dbg_chrome-debugging.js]
 [browser_dbg_clean-exit-window.js]
 skip-if = true # Bug 933950 (leaky test)
 [browser_dbg_clean-exit.js]
 [browser_dbg_closure-inspection.js]
 [browser_dbg_cmd-blackbox.js]
 [browser_dbg_cmd-break.js]
 [browser_dbg_cmd-dbg.js]
@@ -160,16 +163,18 @@ skip-if = true # Bug 933950 (leaky test)
 [browser_dbg_location-changes-01-simple.js]
 [browser_dbg_location-changes-02-blank.js]
 [browser_dbg_location-changes-03-new.js]
 [browser_dbg_location-changes-04-breakpoint.js]
 [browser_dbg_multiple-windows.js]
 [browser_dbg_navigation.js]
 [browser_dbg_no-page-sources.js]
 [browser_dbg_on-pause-highlight.js]
+[browser_dbg_on-pause-raise.js]
+skip-if = os == "linux" || e10s # Bug 888811 & bug 891176
 [browser_dbg_optimized-out-vars.js]
 [browser_dbg_panel-size.js]
 [browser_dbg_parser-01.js]
 [browser_dbg_parser-02.js]
 [browser_dbg_parser-03.js]
 [browser_dbg_parser-04.js]
 [browser_dbg_parser-05.js]
 [browser_dbg_parser-06.js]
@@ -293,14 +298,8 @@ skip-if = (os == 'mac' || os == 'win') &
 [browser_dbg_variables-view-popup-15.js]
 [browser_dbg_variables-view-popup-16.js]
 [browser_dbg_variables-view-reexpand-01.js]
 [browser_dbg_variables-view-reexpand-02.js]
 [browser_dbg_variables-view-reexpand-03.js]
 [browser_dbg_variables-view-webidl.js]
 [browser_dbg_watch-expressions-01.js]
 [browser_dbg_watch-expressions-02.js]
-[browser_dbg_chrome-create.js]
-skip-if = true # Test doesn't clean up after itself (bug 918507), but also bug 847558 on Linux
-[browser_dbg_on-pause-raise.js]
-skip-if = os == "linux" || e10s # Bug 888811 & bug 891176
-[browser_dbg_break-on-dom-event.js]
-skip-if = os == "mac" || e10s # Bug 895426
--- a/browser/locales/en-US/chrome/browser/preferences/colors.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/colors.dtd
@@ -6,21 +6,21 @@
 <!ENTITY  window.width                    "38em">
 <!ENTITY  window.macWidth                 "41em">
 
 <!ENTITY  allowPagesToUse.label           "Allow pages to choose their own colors, instead of my selections above">
 <!ENTITY  allowPagesToUse.accesskey       "A">
 
 <!ENTITY  color                           "Text and Background">
 <!ENTITY  textColor.label                 "Text:">
-<!ENTITY  textColor.accesskey             "t">
+<!ENTITY  textColor.accesskey             "T">
 <!ENTITY  backgroundColor.label           "Background:">
-<!ENTITY  backgroundColor.accesskey       "b">
+<!ENTITY  backgroundColor.accesskey       "B">
 <!ENTITY  useSystemColors.label           "Use system colors">
 <!ENTITY  useSystemColors.accesskey       "s">
 
 <!ENTITY  underlineLinks.label            "Underline links">
-<!ENTITY  underlineLinks.accesskey        "u">
+<!ENTITY  underlineLinks.accesskey        "U">
 <!ENTITY  links                           "Link Colors">
 <!ENTITY  linkColor.label                 "Unvisited Links:">
-<!ENTITY  linkColor.accesskey             "l">
+<!ENTITY  linkColor.accesskey             "L">
 <!ENTITY  visitedLinkColor.label          "Visited Links:">
-<!ENTITY  visitedLinkColor.accesskey      "v">
+<!ENTITY  visitedLinkColor.accesskey      "V">
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -245,17 +245,17 @@ browser.jar:
   skin/classic/browser/devtools/magnifying-glass-light@2x.png (../shared/devtools/images/magnifying-glass-light@2x.png)
   skin/classic/browser/devtools/itemToggle.png         (../shared/devtools/images/itemToggle.png)
   skin/classic/browser/devtools/itemToggle@2x.png      (../shared/devtools/images/itemToggle@2x.png)
   skin/classic/browser/devtools/itemArrow-dark-rtl.svg (../shared/devtools/images/itemArrow-dark-rtl.svg)
   skin/classic/browser/devtools/itemArrow-dark-ltr.svg (../shared/devtools/images/itemArrow-dark-ltr.svg)
   skin/classic/browser/devtools/itemArrow-rtl.svg      (../shared/devtools/images/itemArrow-rtl.svg)
   skin/classic/browser/devtools/itemArrow-ltr.svg      (../shared/devtools/images/itemArrow-ltr.svg)
   skin/classic/browser/devtools/noise.png             (../shared/devtools/images/noise.png)
-  skin/classic/browser/devtools/dropmarker.png        (../shared/devtools/images/dropmarker.png)
+  skin/classic/browser/devtools/dropmarker.svg        (../shared/devtools/images/dropmarker.svg)
   skin/classic/browser/devtools/layoutview.css         (../shared/devtools/layoutview.css)
   skin/classic/browser/devtools/debugger-collapse.png  (../shared/devtools/images/debugger-collapse.png)
   skin/classic/browser/devtools/debugger-collapse@2x.png  (../shared/devtools/images/debugger-collapse@2x.png)
   skin/classic/browser/devtools/debugger-expand.png    (../shared/devtools/images/debugger-expand.png)
   skin/classic/browser/devtools/debugger-expand@2x.png    (../shared/devtools/images/debugger-expand@2x.png)
   skin/classic/browser/devtools/debugger-pause.png     (../shared/devtools/images/debugger-pause.png)
   skin/classic/browser/devtools/debugger-pause@2x.png     (../shared/devtools/images/debugger-pause@2x.png)
   skin/classic/browser/devtools/debugger-play.png      (../shared/devtools/images/debugger-play.png)
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -363,17 +363,17 @@ browser.jar:
   skin/classic/browser/devtools/magnifying-glass-light@2x.png (../shared/devtools/images/magnifying-glass-light@2x.png)
   skin/classic/browser/devtools/itemToggle.png              (../shared/devtools/images/itemToggle.png)
   skin/classic/browser/devtools/itemToggle@2x.png           (../shared/devtools/images/itemToggle@2x.png)
   skin/classic/browser/devtools/itemArrow-dark-rtl.svg      (../shared/devtools/images/itemArrow-dark-rtl.svg)
   skin/classic/browser/devtools/itemArrow-dark-ltr.svg      (../shared/devtools/images/itemArrow-dark-ltr.svg)
   skin/classic/browser/devtools/itemArrow-rtl.svg           (../shared/devtools/images/itemArrow-rtl.svg)
   skin/classic/browser/devtools/itemArrow-ltr.svg           (../shared/devtools/images/itemArrow-ltr.svg)
   skin/classic/browser/devtools/noise.png                   (../shared/devtools/images/noise.png)
-  skin/classic/browser/devtools/dropmarker.png              (../shared/devtools/images/dropmarker.png)
+  skin/classic/browser/devtools/dropmarker.svg              (../shared/devtools/images/dropmarker.svg)
   skin/classic/browser/devtools/layoutview.css              (../shared/devtools/layoutview.css)
   skin/classic/browser/devtools/debugger-collapse.png       (../shared/devtools/images/debugger-collapse.png)
   skin/classic/browser/devtools/debugger-collapse@2x.png    (../shared/devtools/images/debugger-collapse@2x.png)
   skin/classic/browser/devtools/debugger-expand.png         (../shared/devtools/images/debugger-expand.png)
   skin/classic/browser/devtools/debugger-expand@2x.png      (../shared/devtools/images/debugger-expand@2x.png)
   skin/classic/browser/devtools/debugger-pause.png          (../shared/devtools/images/debugger-pause.png)
   skin/classic/browser/devtools/debugger-pause@2x.png       (../shared/devtools/images/debugger-pause@2x.png)
   skin/classic/browser/devtools/debugger-play.png           (../shared/devtools/images/debugger-play.png)
--- a/browser/themes/shared/devtools/canvasdebugger.inc.css
+++ b/browser/themes/shared/devtools/canvasdebugger.inc.css
@@ -148,16 +148,21 @@
 
 #snapshots-list .selected label {
   /* Text inside a selected item should not be custom colored. */
   color: inherit !important;
 }
 
 /* Debugging pane controls */
 
+#debugging-controls .devtools-toolbarbutton > .toolbarbutton-icon {
+  width: 16px;
+  height: 16px;
+}
+
 #resume {
   list-style-image: url(debugger-play.png);
   -moz-image-region: rect(0px,32px,16px,16px);
 }
 
 #step-over {
   list-style-image: url(debugger-step-over.png);
 }
@@ -165,16 +170,35 @@
 #step-in {
   list-style-image: url(debugger-step-in.png);
 }
 
 #step-out {
   list-style-image: url(debugger-step-out.png);
 }
 
+@media (min-resolution: 2dppx) {
+  #resume {
+    list-style-image: url(debugger-play@2x.png);
+    -moz-image-region: rect(0px,64px,32px,32px);
+  }
+
+  #step-over {
+    list-style-image: url(debugger-step-over@2x.png);
+  }
+
+  #step-in {
+    list-style-image: url(debugger-step-in@2x.png);
+  }
+
+  #step-out {
+    list-style-image: url(debugger-step-out@2x.png);
+  }
+}
+
 #debugging-controls > toolbarbutton {
   transition: opacity 0.15s ease-in-out;
 }
 
 #debugging-controls > toolbarbutton[disabled=true] {
   opacity: 0.5;
 }
 
@@ -251,16 +275,22 @@
 
 .selected .call-item-gutter {
   background-image: url("editor-debug-location.png");
   background-repeat: no-repeat;
   background-position: 6px center;
   background-size: 12px;
 }
 
+@media (min-resolution: 2dppx) {
+  .selected .call-item-gutter {
+    background-image: url("editor-debug-location@2x.png");
+  }
+}
+
 .theme-dark .call-item-gutter {
   background-color: #181d20;
   color: #5f7387;
   border-color: #000;
 }
 
 .theme-light .call-item-gutter {
   background-color: #f7f7f7;
deleted file mode 100644
index 7e91860fb5bccc230d94b2ebc5b549b9e2637087..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/devtools/images/dropmarker.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="8" height="4" viewBox="0 0 8 4" enable-background="new 0 0 8 4">
+  <polygon points="0,0 4,4 8,0" fill="#B6BABF" />
+</svg>
\ No newline at end of file
--- a/browser/themes/shared/devtools/responsivedesign.inc.css
+++ b/browser/themes/shared/devtools/responsivedesign.inc.css
@@ -91,17 +91,17 @@
 .devtools-responsiveui-menulist > .menulist-label-box {
   text-align: center;
 }
 
 .devtools-responsiveui-menulist > .menulist-dropmarker {
   -moz-appearance: none;
   display: -moz-box;
   background-color: transparent;
-  list-style-image: url("chrome://browser/skin/devtools/dropmarker.png");
+  list-style-image: url("chrome://browser/skin/devtools/dropmarker.svg");
   -moz-box-align: center;
   border-width: 0;
   min-width: 16px;
 }
 
 .devtools-responsiveui-toolbarbutton[type=menu-button] > .toolbarbutton-menubutton-button {
   -moz-appearance: none;
   color: inherit;
@@ -117,17 +117,17 @@
 .devtools-responsiveui-toolbarbutton[type=menu-button] {
   padding: 0 1px;
   -moz-box-align: stretch;
 }
 
 .devtools-responsiveui-toolbarbutton[type=menu] > .toolbarbutton-menu-dropmarker,
 .devtools-responsiveui-toolbarbutton[type=menu-button] > .toolbarbutton-menubutton-dropmarker {
   -moz-appearance: none !important;
-  list-style-image: url("chrome://browser/skin/devtools/dropmarker.png");
+  list-style-image: url("chrome://browser/skin/devtools/dropmarker.svg");
   -moz-box-align: center;
   padding: 0 3px;
 }
 
 .devtools-responsiveui-toolbar:-moz-locale-dir(ltr) > *:first-child,
 .devtools-responsiveui-toolbar:-moz-locale-dir(rtl) > *:last-child {
   margin-left: 0;
 }
--- a/browser/themes/shared/devtools/toolbars.inc.css
+++ b/browser/themes/shared/devtools/toolbars.inc.css
@@ -131,17 +131,17 @@
 
 .devtools-menulist > .menulist-label-box {
   text-align: center;
 }
 
 .devtools-menulist > .menulist-dropmarker {
   -moz-appearance: none;
   display: -moz-box;
-  list-style-image: url("chrome://browser/skin/devtools/dropmarker.png");
+  list-style-image: url("chrome://browser/skin/devtools/dropmarker.svg");
   -moz-box-align: center;
   min-width: 16px;
 }
 
 .devtools-toolbarbutton[type=menu-button] > .toolbarbutton-menubutton-button {
   -moz-appearance: none;
   color: inherit;
   border-width: 0;
@@ -163,17 +163,17 @@
 .devtools-toolbarbutton[type=menu-button] {
   padding: 0 1px;
   -moz-box-align: stretch;
 }
 
 .devtools-toolbarbutton[type=menu] > .toolbarbutton-menu-dropmarker,
 .devtools-toolbarbutton[type=menu-button] > .toolbarbutton-menubutton-dropmarker {
   -moz-appearance: none !important;
-  list-style-image: url("chrome://browser/skin/devtools/dropmarker.png");
+  list-style-image: url("chrome://browser/skin/devtools/dropmarker.svg");
   -moz-box-align: center;
   padding: 0 3px;
 }
 
 /* Toolbar button groups */
 .theme-light .devtools-toolbarbutton-group > .devtools-toolbarbutton,
 .theme-dark .devtools-toolbarbutton-group > .devtools-toolbarbutton {
   margin: 0;
--- a/browser/themes/shared/devtools/webaudioeditor.inc.css
+++ b/browser/themes/shared/devtools/webaudioeditor.inc.css
@@ -120,15 +120,35 @@ text {
 #inspector-pane-toggle {
   background: none;
   box-shadow: none;
   border: none;
   list-style-image: url(debugger-collapse.png);
   -moz-image-region: rect(0px,16px,16px,0px);
 }
 
+#inspector-pane-toggle > .toolbarbutton-icon {
+  width: 16px;
+  height: 16px;
+}
+
 #inspector-pane-toggle[pane-collapsed] {
   list-style-image: url(debugger-expand.png);
 }
 
 #inspector-pane-toggle:active {
   -moz-image-region: rect(0px,32px,16px,16px);
 }
+
+@media (min-resolution: 2dppx) {
+  #inspector-pane-toggle {
+    list-style-image: url(debugger-collapse@2x.png);
+    -moz-image-region: rect(0px,32px,32px,0px);
+  }
+
+  #inspector-pane-toggle[pane-collapsed] {
+    list-style-image: url(debugger-expand@2x.png);
+  }
+
+  #inspector-pane-toggle:active {
+    -moz-image-region: rect(0px,64px,32px,32px);
+  }
+}
\ No newline at end of file
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -283,17 +283,17 @@ browser.jar:
         skin/classic/browser/devtools/magnifying-glass-light@2x.png  (../shared/devtools/images/magnifying-glass-light@2x.png)
         skin/classic/browser/devtools/itemToggle.png                (../shared/devtools/images/itemToggle.png)
         skin/classic/browser/devtools/itemToggle@2x.png             (../shared/devtools/images/itemToggle@2x.png)
         skin/classic/browser/devtools/itemArrow-dark-rtl.svg        (../shared/devtools/images/itemArrow-dark-rtl.svg)
         skin/classic/browser/devtools/itemArrow-dark-ltr.svg        (../shared/devtools/images/itemArrow-dark-ltr.svg)
         skin/classic/browser/devtools/itemArrow-rtl.svg             (../shared/devtools/images/itemArrow-rtl.svg)
         skin/classic/browser/devtools/itemArrow-ltr.svg             (../shared/devtools/images/itemArrow-ltr.svg)
         skin/classic/browser/devtools/noise.png                     (../shared/devtools/images/noise.png)
-        skin/classic/browser/devtools/dropmarker.png                (../shared/devtools/images/dropmarker.png)
+        skin/classic/browser/devtools/dropmarker.svg                (../shared/devtools/images/dropmarker.svg)
         skin/classic/browser/devtools/layoutview.css                (../shared/devtools/layoutview.css)
         skin/classic/browser/devtools/debugger-collapse.png         (../shared/devtools/images/debugger-collapse.png)
         skin/classic/browser/devtools/debugger-collapse@2x.png      (../shared/devtools/images/debugger-collapse@2x.png)
         skin/classic/browser/devtools/debugger-expand.png           (../shared/devtools/images/debugger-expand.png)
         skin/classic/browser/devtools/debugger-expand@2x.png        (../shared/devtools/images/debugger-expand@2x.png)
         skin/classic/browser/devtools/debugger-pause.png            (../shared/devtools/images/debugger-pause.png)
         skin/classic/browser/devtools/debugger-pause@2x.png         (../shared/devtools/images/debugger-pause@2x.png)
         skin/classic/browser/devtools/debugger-play.png             (../shared/devtools/images/debugger-play.png)
@@ -683,17 +683,17 @@ browser.jar:
         skin/classic/aero/browser/devtools/magnifying-glass-light@2x.png  (../shared/devtools/images/magnifying-glass-light@2x.png)
         skin/classic/aero/browser/devtools/itemToggle.png            (../shared/devtools/images/itemToggle.png)
         skin/classic/aero/browser/devtools/itemToggle@2x.png         (../shared/devtools/images/itemToggle@2x.png)
         skin/classic/aero/browser/devtools/itemArrow-dark-rtl.svg    (../shared/devtools/images/itemArrow-dark-rtl.svg)
         skin/classic/aero/browser/devtools/itemArrow-dark-ltr.svg    (../shared/devtools/images/itemArrow-dark-ltr.svg)
         skin/classic/aero/browser/devtools/itemArrow-rtl.svg         (../shared/devtools/images/itemArrow-rtl.svg)
         skin/classic/aero/browser/devtools/itemArrow-ltr.svg         (../shared/devtools/images/itemArrow-ltr.svg)
         skin/classic/aero/browser/devtools/noise.png                 (../shared/devtools/images/noise.png)
-        skin/classic/aero/browser/devtools/dropmarker.png            (../shared/devtools/images/dropmarker.png)
+        skin/classic/aero/browser/devtools/dropmarker.svg            (../shared/devtools/images/dropmarker.svg)
         skin/classic/aero/browser/devtools/layoutview.css            (../shared/devtools/layoutview.css)
         skin/classic/aero/browser/devtools/debugger-collapse.png     (../shared/devtools/images/debugger-collapse.png)
         skin/classic/aero/browser/devtools/debugger-collapse@2x.png  (../shared/devtools/images/debugger-collapse@2x.png)
         skin/classic/aero/browser/devtools/debugger-expand.png       (../shared/devtools/images/debugger-expand.png)
         skin/classic/aero/browser/devtools/debugger-expand@2x.png    (../shared/devtools/images/debugger-expand@2x.png)
         skin/classic/aero/browser/devtools/debugger-pause.png        (../shared/devtools/images/debugger-pause.png)
         skin/classic/aero/browser/devtools/debugger-pause@2x.png     (../shared/devtools/images/debugger-pause@2x.png)
         skin/classic/aero/browser/devtools/debugger-play.png         (../shared/devtools/images/debugger-play.png)
--- a/mobile/android/base/sqlite/SQLiteBridge.java
+++ b/mobile/android/base/sqlite/SQLiteBridge.java
@@ -222,16 +222,17 @@ public class SQLiteBridge {
     public int getVersion()
                throws SQLiteBridgeException {
         Cursor cursor = internalQuery("PRAGMA user_version", null);
         int ret = -1;
         if (cursor != null) {
             cursor.moveToFirst();
             String version = cursor.getString(0);
             ret = Integer.parseInt(version);
+            cursor.close();
         }
         return ret;
     }
 
     // Do an SQL query, substituting the parameters in the query with the passed
     // parameters. The parameters are substituted in order: named parameters
     // are not supported.
     private Cursor internalQuery(String aQuery, String[] aParams)
--- a/services/healthreport/healthreporter.jsm
+++ b/services/healthreport/healthreporter.jsm
@@ -397,17 +397,28 @@ AbstractHealthReporter.prototype = Objec
 
       // As soon as we have could have storage, we need to register cleanup or
       // else bad things happen on shutdown.
       Services.obs.addObserver(this, "quit-application", false);
 
       // The database needs to be shut down by the end of shutdown
       // phase profileBeforeChange.
       Metrics.Storage.shutdown.addBlocker("FHR: Flushing storage shutdown",
-        this._promiseShutdown);
+        this._promiseShutdown,
+        () => ({
+            shutdownInitiated: this._shutdownInitiated,
+            initialized: this._initialized,
+            shutdownRequested: this._shutdownRequested,
+            initializeHadError: this._initializeHadError,
+            providerManagerInProgress: this._providerManagerInProgress,
+            storageInProgress: this._storageInProgress,
+            hasProviderManager: !!this._providerManager,
+            hasStorage: !!this._storage,
+            shutdownComplete: this.shutdownComplete
+          }));
 
       try {
         this._storageInProgress = true;
         TelemetryStopwatch.start(this._dbOpenHistogram, this);
         let storage = yield Metrics.Storage(this._dbName);
         TelemetryStopwatch.finish(this._dbOpenHistogram, this);
         yield this._onStorageCreated();
 
@@ -566,17 +577,17 @@ AbstractHealthReporter.prototype = Objec
     this._log.info("Request to shut down.");
 
     this._initialized = false;
     this._shutdownRequested = true;
 
     if (this._initializeHadError) {
       this._log.warn("Initialization had error. Shutting down immediately.");
     } else {
-      if (this._providerManagerInProcess) {
+      if (this._providerManagerInProgress) {
         this._log.warn("Provider manager is in progress of initializing. " +
                        "Waiting to finish.");
         return;
       }
 
       // If storage is in the process of initializing, we need to wait for it
       // to finish before continuing. The initialization process will call us
       // again once storage has initialized.
--- a/toolkit/content/tests/browser/browser.ini
+++ b/toolkit/content/tests/browser/browser.ini
@@ -5,16 +5,17 @@ skip-if = e10s # Bug ?????? - test touch
 [browser_browserDrop.js]
 [browser_bug295977_autoscroll_overflow.js]
 skip-if = e10s # Bug 921935 - focusmanager issues with e10s
 [browser_bug594509.js]
 skip-if = e10s # Bug ?????? - intermittent crash of child process reported when run under e10s
 [browser_bug982298.js]
 [browser_default_image_filename.js]
 skip-if = e10s # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly
+[browser_f7_caret_browsing.js]
 [browser_findbar.js]
 skip-if = e10s # Disabled for e10s: Bug ?????? - seems to be a timing issue with RemoteFinder.jsm messages coming later than the tests expect.
 [browser_input_file_tooltips.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content (TypeError: doc.createElement is not a function)
 [browser_keyevents_during_autoscrolling.js]
 skip-if = e10s # Bug 921935 - focusmanager issues with e10s
 [browser_save_resend_postdata.js]
 support-files =
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_f7_caret_browsing.js
@@ -0,0 +1,279 @@
+XPCOMUtils.defineLazyModuleGetter(this, "Promise",
+  "resource://gre/modules/Promise.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Task",
+  "resource://gre/modules/Task.jsm");
+
+let gTab = null;
+let gListener = null;
+const kURL = "data:text/html;charset=utf-8,Caret browsing is fun.<input id='in'>";
+
+const kPrefShortcutEnabled = "accessibility.browsewithcaret_shortcut.enabled";
+const kPrefWarnOnEnable    = "accessibility.warn_on_browsewithcaret";
+const kPrefCaretBrowsingOn = "accessibility.browsewithcaret";
+
+let oldPrefs = {};
+for (let pref of [kPrefShortcutEnabled, kPrefWarnOnEnable, kPrefCaretBrowsingOn]) {
+  oldPrefs[pref] = Services.prefs.getBoolPref(pref);
+}
+
+Services.prefs.setBoolPref(kPrefShortcutEnabled, true);
+Services.prefs.setBoolPref(kPrefWarnOnEnable, true);
+Services.prefs.setBoolPref(kPrefCaretBrowsingOn, false);
+
+registerCleanupFunction(function() {
+  if (gTab)
+    gBrowser.removeTab(gTab);
+  if (gListener)
+    Services.wm.removeListener(gListener);
+
+  for (let pref of [kPrefShortcutEnabled, kPrefWarnOnEnable, kPrefCaretBrowsingOn]) {
+    Services.prefs.setBoolPref(pref, oldPrefs[pref]);
+  }
+});
+
+function waitForCondition(aConditionFn, aMaxTries=50, aCheckInterval=100) {
+  function tryNow() {
+    tries++;
+    if (aConditionFn()) {
+      deferred.resolve();
+    } else if (tries < aMaxTries) {
+      tryAgain();
+    } else {
+      deferred.reject("Condition timed out: " + aConditionFn.toSource());
+    }
+  }
+  function tryAgain() {
+    setTimeout(tryNow, aCheckInterval);
+  }
+  let deferred = Promise.defer();
+  let tries = 0;
+  tryAgain();
+  return deferred.promise;
+}
+
+function promiseWaitForDialogUnload(dialog) {
+  let deferred = Promise.defer();
+  dialog.addEventListener("unload", function listener() {
+    dialog.removeEventListener("unload", listener, false);
+    deferred.resolve();
+  }, false);
+  return deferred.promise;
+}
+
+function promiseWaitForFocusEvent(el) {
+  if (el.ownerDocument.activeElement == el) {
+    return true;
+  }
+  let deferred = Promise.defer();
+  el.addEventListener("focus", function listener() {
+    el.removeEventListener("focus", listener, false);
+    deferred.resolve();
+  }, false);
+  return deferred.promise;
+}
+
+function promiseTestPageLoad() {
+  let deferred = Promise.defer();
+  info("Waiting for test page to load.");
+
+  gTab = gBrowser.selectedTab = gBrowser.addTab(kURL);
+  let browser = gBrowser.selectedBrowser;
+  browser.addEventListener("load", function listener() {
+    if (browser.currentURI.spec == "about:blank")
+      return;
+    info("Page loaded: " + browser.currentURI.spec);
+    browser.removeEventListener("load", listener, true);
+
+    deferred.resolve();
+  }, true);
+
+  return deferred.promise;
+}
+
+function promiseCaretPromptOpened() {
+  let deferred = Promise.defer();
+  if (gListener) {
+    console.trace();
+    ok(false, "Should not be waiting for another prompt right now.");
+    return false;
+  }
+  info("Waiting for caret prompt to open");
+  gListener = {
+    onOpenWindow: function(win) {
+      let window = win.QueryInterface(Ci.nsIInterfaceRequestor)
+                      .getInterface(Ci.nsIDOMWindow);
+      window.addEventListener("load", function listener() {
+        window.removeEventListener("load", listener);
+        if (window.location.href == "chrome://global/content/commonDialog.xul") {
+          info("Caret prompt opened, removing listener and focusing");
+          Services.wm.removeListener(gListener);
+          gListener = null;
+          deferred.resolve(window);
+        }
+      });
+    },
+    onCloseWindow: function() {},
+  };
+  Services.wm.addListener(gListener);
+  return deferred.promise;
+}
+
+function hitF7(async = true) {
+  let f7 = () => EventUtils.sendKey("F7", window.content);
+  // Need to not stop execution inside this task:
+  if (async) {
+    executeSoon(f7);
+  } else {
+    f7();
+  }
+}
+
+function syncToggleCaretNoDialog(expected) {
+  let openedDialog = false;
+  promiseCaretPromptOpened().then(function(win) {
+    openedDialog = true;
+    win.close(); // This will eventually return focus here and allow the test to continue...
+  });
+  // Cause the dialog to appear sync, if it still does.
+  hitF7(false);
+  if (gListener) {
+    Services.wm.removeListener(gListener);
+    gListener = null;
+  }
+  let expectedStr = expected ? "on." : "off.";
+  ok(!openedDialog, "Shouldn't open a dialog to turn caret browsing " + expectedStr);
+  let prefVal = Services.prefs.getBoolPref(kPrefCaretBrowsingOn);
+  is(prefVal, expected, "Caret browsing should now be " + expectedStr);
+}
+
+add_task(function* checkTogglingCaretBrowsing() {
+  yield promiseTestPageLoad();
+  let textEl = window.content.document.getElementById("in");
+  textEl.focus();
+
+  let promiseGotKey = promiseCaretPromptOpened();
+  hitF7();
+  let prompt = yield promiseGotKey;
+  let doc = prompt.document;
+  is(doc.documentElement.defaultButton, "cancel", "No button should be the default");
+  ok(!doc.getElementById("checkbox").checked, "Checkbox shouldn't be checked by default.");
+  let promiseDialogUnloaded = promiseWaitForDialogUnload(prompt);
+  doc.documentElement.cancelDialog();
+  yield promiseDialogUnloaded;
+  yield waitForCondition(() => textEl.ownerDocument.activeElement == textEl);
+  ok(!Services.prefs.getBoolPref(kPrefCaretBrowsingOn), "Caret browsing should still be off after cancelling the dialog.");
+
+  promiseGotKey = promiseCaretPromptOpened();
+  hitF7();
+  prompt = yield promiseGotKey;
+
+  doc = prompt.document;
+  is(doc.documentElement.defaultButton, "cancel", "No button should be the default");
+  ok(!doc.getElementById("checkbox").checked, "Checkbox shouldn't be checked by default.");
+  promiseDialogUnloaded = promiseWaitForDialogUnload(prompt);
+  doc.documentElement.acceptDialog();
+  yield promiseDialogUnloaded;
+  yield waitForCondition(() => textEl.ownerDocument.activeElement == textEl);
+  ok(Services.prefs.getBoolPref(kPrefCaretBrowsingOn), "Caret browsing should be on after accepting the dialog.");
+
+  syncToggleCaretNoDialog(false);
+
+  promiseGotKey = promiseCaretPromptOpened();
+  hitF7();
+  prompt = yield promiseGotKey;
+  doc = prompt.document;
+
+  is(doc.documentElement.defaultButton, "cancel", "No button should be the default");
+  ok(!doc.getElementById("checkbox").checked, "Checkbox shouldn't be checked by default.");
+
+  promiseDialogUnloaded = promiseWaitForDialogUnload(prompt);
+  doc.documentElement.cancelDialog();
+  yield promiseDialogUnloaded;
+  yield waitForCondition(() => textEl.ownerDocument.activeElement == textEl);
+
+  ok(!Services.prefs.getBoolPref(kPrefCaretBrowsingOn), "Caret browsing should still be off after cancelling the dialog.");
+
+  Services.prefs.setBoolPref(kPrefShortcutEnabled, true);
+  Services.prefs.setBoolPref(kPrefWarnOnEnable, true);
+  Services.prefs.setBoolPref(kPrefCaretBrowsingOn, false);
+
+  gBrowser.removeTab(gTab);
+  gTab = null;
+});
+
+add_task(function* toggleCheckboxNoCaretBrowsing() {
+  yield promiseTestPageLoad();
+  let textEl = window.content.document.getElementById("in");
+  textEl.focus();
+
+  let promiseGotKey = promiseCaretPromptOpened();
+  hitF7();
+  let prompt = yield promiseGotKey;
+  let doc = prompt.document;
+  is(doc.documentElement.defaultButton, "cancel", "No button should be the default");
+  let checkbox = doc.getElementById("checkbox");
+  ok(!checkbox.checked, "Checkbox shouldn't be checked by default.");
+
+  // Check the box:
+  checkbox.click();
+  let promiseDialogUnloaded = promiseWaitForDialogUnload(prompt);
+  // Say no:
+  doc.documentElement.getButton("cancel").click();
+  yield promiseDialogUnloaded;
+  yield waitForCondition(() => textEl.ownerDocument.activeElement == textEl);
+  ok(!Services.prefs.getBoolPref(kPrefCaretBrowsingOn), "Caret browsing should still be off.");
+
+  ok(!Services.prefs.getBoolPref(kPrefShortcutEnabled), "Shortcut should now be disabled.");
+
+  syncToggleCaretNoDialog(false);
+  ok(!Services.prefs.getBoolPref(kPrefShortcutEnabled), "Shortcut should still be disabled.");
+
+  Services.prefs.setBoolPref(kPrefShortcutEnabled, true);
+  Services.prefs.setBoolPref(kPrefWarnOnEnable, true);
+  Services.prefs.setBoolPref(kPrefCaretBrowsingOn, false);
+
+  gBrowser.removeTab(gTab);
+  gTab = null;
+});
+
+
+add_task(function* toggleCheckboxWantCaretBrowsing() {
+  yield promiseTestPageLoad();
+  let textEl = window.content.document.getElementById("in");
+  textEl.focus();
+
+  let promiseGotKey = promiseCaretPromptOpened();
+  hitF7();
+  let prompt = yield promiseGotKey;
+  let doc = prompt.document;
+  is(doc.documentElement.defaultButton, "cancel", "No button should be the default");
+  let checkbox = doc.getElementById("checkbox");
+  ok(!checkbox.checked, "Checkbox shouldn't be checked by default.");
+
+  // Check the box:
+  checkbox.click();
+  let promiseDialogUnloaded = promiseWaitForDialogUnload(prompt);
+  // Say yes:
+  doc.documentElement.acceptDialog();
+  yield promiseDialogUnloaded;
+  yield waitForCondition(() => textEl.ownerDocument.activeElement == textEl);
+  ok(Services.prefs.getBoolPref(kPrefCaretBrowsingOn), "Caret browsing should now be on.");
+  ok(Services.prefs.getBoolPref(kPrefShortcutEnabled), "Shortcut should still be enabled.");
+  ok(!Services.prefs.getBoolPref(kPrefWarnOnEnable), "Should no longer warn when enabling.");
+
+
+  syncToggleCaretNoDialog(false);
+  syncToggleCaretNoDialog(true);
+  syncToggleCaretNoDialog(false);
+  
+  Services.prefs.setBoolPref(kPrefShortcutEnabled, true);
+  Services.prefs.setBoolPref(kPrefWarnOnEnable, true);
+  Services.prefs.setBoolPref(kPrefCaretBrowsingOn, false);
+
+  gBrowser.removeTab(gTab);
+  gTab = null;
+});
+
+
+
+
--- a/toolkit/content/widgets/browser.xml
+++ b/toolkit/content/widgets/browser.xml
@@ -1095,58 +1095,70 @@
     </implementation>
 
     <handlers>
       <handler event="keypress" keycode="VK_F7" group="system">
         <![CDATA[
           if (event.defaultPrevented || !event.isTrusted)
             return;
 
-          var isEnabled = this.mPrefs.getBoolPref("accessibility.browsewithcaret_shortcut.enabled");
+          const kPrefShortcutEnabled = "accessibility.browsewithcaret_shortcut.enabled";
+          const kPrefWarnOnEnable    = "accessibility.warn_on_browsewithcaret";
+          const kPrefCaretBrowsingOn = "accessibility.browsewithcaret";
+
+          var isEnabled = this.mPrefs.getBoolPref(kPrefShortcutEnabled);
           if (!isEnabled)
             return;
 
           // Toggle browse with caret mode
           var browseWithCaretOn = false;
           var warn = true;
 
           try {
-            warn = this.mPrefs.getBoolPref("accessibility.warn_on_browsewithcaret");
+            warn = this.mPrefs.getBoolPref(kPrefWarnOnEnable);
           } catch (ex) {
           }
 
           try {
-            browseWithCaretOn = this.mPrefs.getBoolPref("accessibility.browsewithcaret");
+            browseWithCaretOn = this.mPrefs.getBoolPref(kPrefCaretBrowsingOn);
           } catch (ex) {
           }
           if (warn && !browseWithCaretOn) {
             var checkValue = {value:false};
             var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
                                           .getService(Components.interfaces.nsIPromptService);
 
             var buttonPressed = promptService.confirmEx(window,
               this.mStrBundle.GetStringFromName('browsewithcaret.checkWindowTitle'),
               this.mStrBundle.GetStringFromName('browsewithcaret.checkLabel'),
-              promptService.STD_YES_NO_BUTTONS,
+              // Make "No" the default:
+              promptService.STD_YES_NO_BUTTONS | promptService.BUTTON_POS_1_DEFAULT,
               null, null, null, this.mStrBundle.GetStringFromName('browsewithcaret.checkMsg'),
               checkValue);
-            if (buttonPressed != 0)
+            if (buttonPressed != 0) {
+              if (checkValue.value) {
+                try {
+                  this.mPrefs.setBoolPref(kPrefShortcutEnabled, false);
+                } catch (ex) {
+                }
+              }
               return;
+            }
             if (checkValue.value) {
               try {
-                this.mPrefs.setBoolPref("accessibility.warn_on_browsewithcaret", false);
+                this.mPrefs.setBoolPref(kPrefWarnOnEnable, false);
               }
               catch (ex) {
               }
             }
           }
 
           // Toggle the pref
           try {
-            this.mPrefs.setBoolPref("accessibility.browsewithcaret",!browseWithCaretOn);
+            this.mPrefs.setBoolPref(kPrefCaretBrowsingOn, !browseWithCaretOn);
           } catch (ex) {
           }
         ]]>
       </handler>
       <handler event="dragover" group="system">
       <![CDATA[
         if (!this.droppedLinkHandler || event.defaultPrevented)
           return;
--- a/toolkit/crashreporter/test/unit/test_crash_AsyncShutdown.js
+++ b/toolkit/crashreporter/test/unit/test_crash_AsyncShutdown.js
@@ -15,25 +15,28 @@ function setup_crash() {
   let phase = AsyncShutdown._getPhase(TOPIC);
   phase.addBlocker("A blocker that is never satisfied", function() {
     dump("Installing blocker\n");
     let deferred = Promise.defer();
     return deferred.promise;
   });
 
   Services.obs.notifyObservers(null, TOPIC, null);
+  dump(new Error().stack + "\n");
   dump("Waiting for crash\n");
 }
 
 function after_crash(mdump, extra) {
   do_print("after crash: " + extra.AsyncShutdownTimeout);
   let info = JSON.parse(extra.AsyncShutdownTimeout);
-  do_check_eq(info.phase, "testing-async-shutdown-crash");
-  do_print("Condition: " + JSON.stringify(info.conditions));
-  do_check_true(JSON.stringify(info.conditions).indexOf("A blocker that is never satisfied") != -1);
+  Assert.equal(info.phase, "testing-async-shutdown-crash");
+  Assert.equal(info.conditions[0].name, "A blocker that is never satisfied");
+  // This test spawns subprocesses by using argument "-e" of xpcshell, so
+  // this is the filename known to xpcshell.
+  Assert.equal(info.conditions[0].filename, "-e");
 }
 
 // Test that AsyncShutdown + OS.File reports errors correctly, in a case in which
 // the latest operation succeeded
 
 function setup_osfile_crash_noerror() {
   Components.utils.import("resource://gre/modules/Services.jsm", this);
   Components.utils.import("resource://gre/modules/osfile.jsm", this);
--- a/toolkit/modules/AsyncShutdown.jsm
+++ b/toolkit/modules/AsyncShutdown.jsm
@@ -423,22 +423,32 @@ function Barrier(name) {
       if (fetchState && typeof fetchState != "function") {
         throw new TypeError("Expected nothing or a function as third argument");
       }
       if (!this._conditions) {
 	throw new Error("Phase " + this._name +
 			" has already begun, it is too late to register" +
 			" completion condition '" + name + "'.");
       }
+
+      // Determine the filename and line number of the caller.
+      let leaf = Components.stack;
+      let frame;
+      for (frame = leaf; frame != null && frame.filename == leaf.filename; frame = frame.caller) {
+        // Climb up the stack
+      }
       let set = this._conditions.get(condition);
       if (!set) {
         set = [];
         this._conditions.set(condition, set);
       }
-      set.push({name: name, fetchState: fetchState});
+      set.push({name: name,
+                fetchState: fetchState,
+                filename: frame ? frame.filename : "?",
+                lineNumber: frame ? frame.lineNumber : -1});
     }.bind(this),
 
     /**
      * Remove the blocker for a condition.
      *
      * If several blockers have been registered for the same
      * condition, remove all these blockers. If no blocker has been
      * registered for this condition, this is a noop.
@@ -475,19 +485,22 @@ Barrier.prototype = Object.freeze({
   get state() {
     if (this._conditions) {
       return "Not started";
     }
     if (!this._monitors) {
       return "Complete";
     }
     let frozen = [];
-    for (let {name, isComplete, fetchState} of this._monitors) {
+    for (let {name, isComplete, fetchState, filename, lineNumber} of this._monitors) {
       if (!isComplete) {
-        frozen.push({name: name, state: safeGetState(fetchState)});
+        frozen.push({name: name,
+                     state: safeGetState(fetchState),
+                     filename: filename,
+                     lineNumber: lineNumber});
       }
     }
     return frozen;
   },
 
   /**
    * Wait until all currently registered blockers are complete.
    *
@@ -531,17 +544,17 @@ Barrier.prototype = Object.freeze({
 
     // Information to determine and report to the user which conditions
     // are not satisfied yet.
     this._monitors = [];
 
     for (let _condition of conditions.keys()) {
       for (let current of conditions.get(_condition)) {
         let condition = _condition; // Avoid capturing the wrong variable
-        let {name, fetchState} = current;
+        let {name, fetchState, filename, lineNumber} = current;
 
         // An indirection on top of condition, used to let clients
         // cancel a blocker through removeBlocker.
         let indirection = Promise.defer();
         this._indirections.set(condition, indirection);
 
         // Gather all completion conditions
 
@@ -560,17 +573,19 @@ Barrier.prototype = Object.freeze({
           // function returned |undefined| or failed), that new promise
           // isn't going to be terribly interesting, but it will behave
           // as a promise.
           condition = Promise.resolve(condition);
 
           let monitor = {
             isComplete: false,
             name: name,
-            fetchState: fetchState
+            fetchState: fetchState,
+            filename: filename,
+            lineNumber: lineNumber
           };
 
 	  condition = condition.then(null, function onError(error) {
             let msg = "A completion condition encountered an error" +
               " while we were spinning the event loop." +
 	      " Condition: " + name +
               " Phase: " + topic +
               " State: " + safeGetState(fetchState);
@@ -664,45 +679,63 @@ Barrier.prototype = Object.freeze({
       // can do to avoid leaving the user's computer in an unstable (and
       // battery-sucking) situation is report the issue and crash.
       timeToCrash = looseTimer(crashAfterMS);
       timeToCrash.promise.then(
         function onTimeout() {
 	  // Report the problem as best as we can, then crash.
 	  let state = this.state;
 
-	  let msg = "At least one completion condition failed to complete" +
+          // If you change the following message, please make sure
+          // that any information on the topic and state appears
+          // within the first 200 characters of the message. This
+          // helps automatically sort oranges.
+          let msg = "AsyncShutdown timeout in " + topic +
+            " Conditions: " + JSON.stringify(state) +
+            " At least one completion condition failed to complete" +
 	    " within a reasonable amount of time. Causing a crash to" +
 	    " ensure that we do not leave the user with an unresponsive" +
 	    " process draining resources." +
-	    " Conditions: " + JSON.stringify(state) +
-	    " Barrier: " + topic;
 	  err(msg);
 	  if (gCrashReporter && gCrashReporter.enabled) {
             let data = {
               phase: topic,
               conditions: state
 	    };
             gCrashReporter.annotateCrashReport("AsyncShutdownTimeout",
-            JSON.stringify(data));
+              JSON.stringify(data));
 	  } else {
             warn("No crash reporter available");
 	  }
 
-	  let error = new Error();
-	  gDebug.abort(error.fileName, error.lineNumber + 1);
+          // To help sorting out bugs, we want to make sure that the
+          // call to nsIDebug.abort points to a guilty client, rather
+          // than to AsyncShutdown itself. We search through all the
+          // clients until we find one that is guilty and use its
+          // filename/lineNumber, which have been determined during
+          // the call to `addBlocker`.
+          let filename = "?";
+          let lineNumber = -1;
+          for (let monitor of this._monitors) {
+            if (monitor.isComplete) {
+              continue;
+            }
+            filename = monitor.filename;
+            lineNumber = monitor.lineNumber;
+          }
+	  gDebug.abort(filename, lineNumber);
         }.bind(this),
 	  function onSatisfied() {
             // The promise has been rejected, which means that we have satisfied
             // all completion conditions.
           });
 
       promise = promise.then(function() {
         timeToCrash.reject();
-      }.bind(this)/* No error is possible here*/);
+      }/* No error is possible here*/);
     }
 
     return promise;
   },
 });
 
 
 
--- a/toolkit/modules/tests/xpcshell/test_AsyncShutdown.js
+++ b/toolkit/modules/tests/xpcshell/test_AsyncShutdown.js
@@ -265,12 +265,40 @@ add_task(function* test_phase_removeBloc
 
     do_print("Attempt to remove non-registered blocker after wait()");
     do_check_false(lock.removeBlocker("foo"));
     do_check_false(lock.removeBlocker(null));
   }
 
 });
 
-add_task(function() {
+add_task(function* test_state() {
+  do_print("Testing information contained in `state`");
+
+  let BLOCKER_NAME = "test_state blocker " + Math.random();
+
+  // Set up the barrier. Note that we cannot test `barrier.state`
+  // immediately, as it initially contains "Not started"
+  let barrier = new AsyncShutdown.Barrier("test_filename");
+  let deferred = Promise.defer();
+  let {filename, lineNumber} = Components.stack;
+  barrier.client.addBlocker(BLOCKER_NAME,
+    function() {
+      return deferred.promise;
+    });
+
+  let promiseDone = barrier.wait();
+
+  // Now that we have called `wait()`, the state contains interesting things
+  let state = barrier.state[0];
+  do_print("State: " + JSON.stringify(barrier.state, null, "\t"));
+  Assert.equal(state.filename, filename);
+  Assert.equal(state.lineNumber, lineNumber + 2);
+  Assert.equal(state.name, BLOCKER_NAME);
+  
+  deferred.resolve();
+  yield promiseDone;
+});
+
+add_task(function*() {
   Services.prefs.clearUserPref("toolkit.asyncshutdown.testing");
 });