Merge m-c to b-i
authorPhil Ringnalda <philringnalda@gmail.com>
Sun, 16 Mar 2014 21:56:21 -0700
changeset 173879 8e798988fe2c
parent 173878 aeee5566c492 (current diff)
parent 173852 25cfa01ba054 (diff)
child 173880 5231e0fb5892
push id26429
push usercbook@mozilla.com
push date2014-03-17 11:40 +0000
treeherdermozilla-central@a1592db51b9a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone30.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 b-i
dom/file/DOMFileRequest.cpp
dom/file/DOMFileRequest.h
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -113,34 +113,35 @@ tabbrowser {
 }
 
 .tabbrowser-tab:not([pinned]):not([fadein]) {
   max-width: 0.1px;
   min-width: 0.1px;
   visibility: hidden;
 }
 
+.tab-close-button,
 .tab-background {
   /* Explicitly set the visibility to override the value (collapsed)
    * we inherit from #TabsToolbar[collapsed] upon opening a browser window. */
   visibility: visible;
   /* The transition is only delayed for opening tabs. */
   transition: visibility 0ms 25ms;
 }
 
+.tab-close-button:not([fadein]):not([pinned]),
 .tab-background:not([fadein]):not([pinned]) {
   visibility: hidden;
   /* Closing tabs are hidden without a delay. */
   transition-delay: 0ms;
 }
 
 .tab-throbber:not([fadein]):not([pinned]),
 .tab-label:not([fadein]):not([pinned]),
-.tab-icon-image:not([fadein]):not([pinned]),
-.tab-close-button:not([fadein]):not([pinned]) {
+.tab-icon-image:not([fadein]):not([pinned]) {
   display: none;
 }
 
 .tabbrowser-tabs[positionpinnedtabs] > .tabbrowser-tab[pinned] {
   position: fixed !important;
   display: block; /* position:fixed already does this (bug 579776), but let's be explicit */
 }
 
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -1158,24 +1158,25 @@
                          tooltiptext="&devToolbarCloseButton.tooltiptext;"/>
 #endif
    </toolbar>
   </vbox>
 
   <svg:svg height="0">
 #include tab-shape.inc.svg
 
-#ifndef XP_MACOSX
-    <svg:clipPath id="keyhole-forward-clip-path" clipPathUnits="objectBoundingBox">
+#ifndef XP_UNIX
+    <svg:clipPath id="windows-keyhole-forward-clip-path" clipPathUnits="objectBoundingBox">
       <svg:path d="m 0,0 c .3,.25 .3,.75, 0,1 l 1,0 0,-1 z"/>
     </svg:clipPath>
-    <svg:clipPath id="urlbar-back-button-clip-path" clipPathUnits="userSpaceOnUse">
+    <svg:clipPath id="windows-urlbar-back-button-clip-path" clipPathUnits="userSpaceOnUse">
       <svg:path d="m 0,-5 l 0,7.8 c 2.5,3.2 4,6.2 4,10.2 c 0,4 -1.5,7 -4,10 l 0,22l10000,0 l 0,-50 l -10000,0 z"/>
     </svg:clipPath>
-#else
+#endif
+#ifdef XP_MACOSX
     <svg:clipPath id="osx-keyhole-forward-clip-path" clipPathUnits="objectBoundingBox">
       <svg:path d="M 0,0 C 0.15,0.12 0.25,0.3 0.25,0.5 0.25,0.7 0.15,0.88 0,1 L 1,1 1,0 0,0 z"/>
     </svg:clipPath>
     <svg:clipPath id="osx-urlbar-back-button-clip-path" clipPathUnits="userSpaceOnUse">
       <svg:path d="m -3,-10 l -0.1,7.7 c 6.6,1.8 8.8,7.6 8.8,12.5 c 0,5 -1.9,11.5 -8.25,13.25 l 0.05,25.75 l 10000,0 l 0,-55 l -10000,-4.2 z"/>
     </svg:clipPath>
 #endif
   </svg:svg>
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -258,17 +258,16 @@ skip-if = true # bug 432425
 [browser_sanitize-timespans.js]
 [browser_sanitizeDialog.js]
 [browser_sanitizeDialog_treeView.js]
 skip-if = true  # disabled until the tree view is added
                 # back to the clear recent history dialog (sanitize.xul), if
                 # it ever is (bug 480169)
 [browser_save_link-perwindowpb.js]
 [browser_save_private_link_perwindowpb.js]
-skip-if = os == "linux" # bug 857427
 [browser_save_video.js]
 [browser_scope.js]
 [browser_selectTabAtIndex.js]
 [browser_star_hsts.js]
 [browser_subframe_favicons_not_used.js]
 [browser_tabDrop.js]
 [browser_tabMatchesInAwesomebar_perwindowpb.js]
 [browser_tab_drag_drop_perwindow.js]
--- a/browser/base/content/test/general/browser_save_private_link_perwindowpb.js
+++ b/browser/base/content/test/general/browser_save_private_link_perwindowpb.js
@@ -31,86 +31,86 @@ function test() {
       }
     };
     function Visitor() {}
 
     var storage = cache.diskCacheStorage(LoadContextInfo.default, false);
     storage.asyncVisitStorage(new Visitor(), true /* Do walk entries */);
   }
 
-  function contextMenuOpened(aWindow, event) {
-    cache.clear();
-
-    event.currentTarget.removeEventListener("popupshown", contextMenuOpened);
-
-    // Create the folder the image will be saved into.
-    var destDir = createTemporarySaveDirectory();
-    var destFile = destDir.clone();
-
-    MockFilePicker.displayDirectory = destDir;
-    MockFilePicker.showCallback = function(fp) {
-      fileName = fp.defaultString;
-      destFile.append (fileName);
-      MockFilePicker.returnFiles = [destFile];
-      MockFilePicker.filterIndex = 1; // kSaveAsType_URL
-    };
-
-    mockTransferCallback = onTransferComplete;
-    mockTransferRegisterer.register();
-
-    registerCleanupFunction(function () {
-      mockTransferRegisterer.unregister();
-      MockFilePicker.cleanup();
-      destDir.remove(true);
-    });
-
-    // Select "Save Image As" option from context menu
-    var saveVideoCommand = aWindow.document.getElementById("context-saveimage");
-    saveVideoCommand.doCommand();
-
-    event.target.hidePopup();
-  }
-
   function onTransferComplete(downloadSuccess) {
     ok(downloadSuccess, "Image file should have been downloaded successfully");
 
     // Give the request a chance to finish and create a cache entry
     executeSoon(function() {
       checkDiskCacheFor(fileName, finish);
+      mockTransferCallback = null;
     });
   }
 
   function createTemporarySaveDirectory() {
     var saveDir = Cc["@mozilla.org/file/directory_service;1"]
                     .getService(Ci.nsIProperties)
                     .get("TmpD", Ci.nsIFile);
     saveDir.append("testsavedir");
     if (!saveDir.exists())
       saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
     return saveDir;
   }
 
   function doTest(aIsPrivateMode, aWindow, aCallback) {
+    function contextMenuOpened(event) {
+      cache.clear();
+
+      aWindow.document.removeEventListener("popupshown", contextMenuOpened);
+
+      // Create the folder the image will be saved into.
+      var destDir = createTemporarySaveDirectory();
+      var destFile = destDir.clone();
+
+      MockFilePicker.displayDirectory = destDir;
+      MockFilePicker.showCallback = function(fp) {
+        fileName = fp.defaultString;
+        destFile.append (fileName);
+        MockFilePicker.returnFiles = [destFile];
+        MockFilePicker.filterIndex = 1; // kSaveAsType_URL
+      };
+
+      mockTransferCallback = onTransferComplete;
+      mockTransferRegisterer.register();
+
+      registerCleanupFunction(function () {
+        mockTransferRegisterer.unregister();
+        MockFilePicker.cleanup();
+        destDir.remove(true);
+      });
+
+      // Select "Save Image As" option from context menu
+      var saveVideoCommand = aWindow.document.getElementById("context-saveimage");
+      saveVideoCommand.doCommand();
+
+      event.target.hidePopup();
+    }
+
     aWindow.gBrowser.addEventListener("pageshow", function pageShown(event) {
       // If data: -url PAC file isn't loaded soon enough, we may get about:privatebrowsing loaded
       if (event.target.location == "about:blank" ||
           event.target.location == "about:privatebrowsing") {
         aWindow.gBrowser.selectedBrowser.loadURI(testURI);
         return;
       }
       aWindow.gBrowser.removeEventListener("pageshow", pageShown);
 
-      executeSoon(function () {
-        aWindow.document.addEventListener("popupshown",
-                                          function(e) contextMenuOpened(aWindow, e), false);
+      waitForFocus(function () {
+        aWindow.document.addEventListener("popupshown", contextMenuOpened, false);
         var img = aWindow.gBrowser.selectedBrowser.contentDocument.getElementById("img");
         EventUtils.synthesizeMouseAtCenter(img,
                                            { type: "contextmenu", button: 2 },
                                            aWindow.gBrowser.contentWindow);
-      });
+      }, aWindow.gBrowser.selectedBrowser.contentWindow);
     });
   }
 
   function testOnWindow(aOptions, aCallback) {
     whenNewWindowLoaded(aOptions, function(aWin) {
       windowsToClose.push(aWin);
       // execute should only be called when need, like when you are opening
       // web pages on the test. If calling executeSoon() is not necesary, then
--- a/browser/components/customizableui/content/panelUI.js
+++ b/browser/components/customizableui/content/panelUI.js
@@ -326,16 +326,17 @@ const PanelUI = {
       tempPanel.setAttribute("class", "cui-widget-panel");
       tempPanel.setAttribute("context", "");
       document.getElementById(CustomizableUI.AREA_NAVBAR).appendChild(tempPanel);
       // If the view has a footer, set a convenience class on the panel.
       tempPanel.classList.toggle("cui-widget-panelWithFooter",
                                  viewNode.querySelector(".panel-subview-footer"));
 
       let multiView = document.createElement("panelmultiview");
+      multiView.setAttribute("nosubviews", "true");
       tempPanel.appendChild(multiView);
       multiView.setAttribute("mainViewIsSubView", "true");
       multiView.setMainView(viewNode);
       viewNode.classList.add("cui-widget-panelview");
       CustomizableUI.addPanelCloseListeners(tempPanel);
 
       let panelRemover = function() {
         tempPanel.removeEventListener("popuphidden", panelRemover);
--- a/browser/themes/linux/browser-lightweightTheme.css
+++ b/browser/themes/linux/browser-lightweightTheme.css
@@ -12,18 +12,20 @@
 
 /* Lightweight theme on tabs */
 #tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start[selected=true]:-moz-lwtheme::before,
 #tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end[selected=true]:-moz-lwtheme::before {
   background-attachment: scroll, fixed;
   background-color: transparent;
   background-image: @fgTabTextureLWT@;/*, lwtHeader;*/
   background-position: 0 0, right top;
+  background-repeat: repeat-x, no-repeat;
 }
 
 #tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme {
   background-attachment: scroll, scroll, fixed;
   background-color: transparent;
   background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png),
                     @fgTabTextureLWT@;/*,
                     lwtHeader;*/
   background-position: 0 0, 0 0, right top;
+  background-repeat: repeat-x, repeat-x, no-repeat;
 }
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -11,17 +11,17 @@
 @namespace svg url("http://www.w3.org/2000/svg");
 
 %include ../shared/browser.inc
 %include linuxShared.inc
 %filter substitution
 
 %define forwardTransitionLength 150ms
 %define conditionalForwardWithUrlbar window:not([chromehidden~="toolbar"]) #urlbar-container
-%define conditionalForwardWithUrlbarWidth 27
+%define conditionalForwardWithUrlbarWidth 40
 
 #menubar-items {
   -moz-box-orient: vertical; /* for flex hack */
 }
 
 #main-menubar {
   -moz-box-flex: 1; /* make menu items expand to fill toolbar height */
 }
@@ -648,108 +648,31 @@ toolbarbutton[sdk-button="true"][cui-are
   background-size: 1px 18px;
   box-shadow: 0 0 0 1px hsla(0,0%,100%,.2);
 }
 
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
   -moz-margin-start: -4px;
 }
 
-#back-button {
-  padding-top: 3px;
-  padding-bottom: 3px;
-  -moz-padding-start: 5px;
-  -moz-padding-end: 0;
-  position: relative;
-  z-index: 1;
-  border-radius: 0 10000px 10000px 0;
-}
-
-#back-button:-moz-locale-dir(rtl) {
-  border-radius: 10000px 0 0 10000px;
-}
-
-#back-button > menupopup {
-  margin-top: -1px;
+#forward-button[disabled] {
+  transform: scale(0);
+  opacity: 0;
+  pointer-events: none;
 }
 
-#back-button > .toolbarbutton-icon {
-  border-radius: 10000px;
-  padding: 5px;
-  margin-top: -5px;
-  margin-bottom: -5px;
-  border: none;
-  box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
-              0 0 0 1px hsla(0,0%,100%,.3) inset,
-              0 0 0 1px hsla(210,54%,20%,.25),
-              0 1px 0 hsla(210,54%,20%,.35);
-  background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
-  transition-property: background-color, box-shadow;
-  transition-duration: 250ms;
-}
-
-#back-button:not([disabled="true"]):not([open="true"]):not(:active):hover > .toolbarbutton-icon {
-  background-color: hsla(210,48%,96%,.75);
-  box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
-              0 0 0 1px hsla(0,0%,100%,.3) inset,
-              0 0 0 1px hsla(210,54%,20%,.3),
-              0 1px 0 hsla(210,54%,20%,.4),
-              0 0 4px hsla(210,54%,20%,.2);
-}
-
-#back-button:not([disabled="true"]):hover:active > .toolbarbutton-icon,
-#back-button[open="true"] > .toolbarbutton-icon {
-  background-color: hsla(210,54%,20%,.15);
-  box-shadow: 0 1px 1px hsla(210,54%,20%,.1) inset,
-              0 0 1px hsla(210,54%,20%,.2) inset,
-              0 0 0 1px hsla(210,54%,20%,.4),
-              0 1px 0 hsla(210,54%,20%,.2);
-  transition: none;
-}
-
-#main-window:not([customizing]) #back-button[disabled] > .toolbarbutton-icon {
-  box-shadow: 0 0 0 1px hsla(210,54%,20%,.55),
-              0 1px 0 hsla(210,54%,20%,.65) !important;
-  transition: none;
+@conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button {
+  transition: @forwardTransitionLength@ ease-out;
 }
 
 #back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
-#forward-button:-moz-locale-dir(rtl) {
+#forward-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
   transform: scaleX(-1);
 }
 
-@conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] {
-  opacity: 0;
-}
-
-@conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button {
-  transition: opacity @forwardTransitionLength@ ease-out;
-}
-
-@conditionalForwardWithUrlbar@ > #forward-button[occluded-by-urlbar] {
-  visibility: hidden;
-}
-
-#forward-button {
-  padding: 0;
-}
-
-#forward-button > .toolbarbutton-icon {
-  background-clip: padding-box;
-  clip-path: url("chrome://browser/content/browser.xul#keyhole-forward-clip-path");
-  margin-left: -7px;
-  border-left-style: none;
-  border-radius: 0;
-  padding-left: 7px;
-  padding-right: 3px;
-  padding-top: 2px;
-  padding-bottom: 2px;
-  border: 1px solid #9a9a9a;
-}
-
 /* tabview menu item */
 
 #menu_tabview {
   list-style-image: url(chrome://browser/skin/tabview/tabview.png);
   -moz-image-region: rect(0, 80px, 16px, 64px);
 }
 
 #menu_tabview[groups="0"] {
@@ -848,31 +771,19 @@ toolbarbutton[sdk-button="true"][cui-are
 #restore-button {
   list-style-image: url("chrome://global/skin/icons/Restore.gif");
 }
 #close-button {
   list-style-image: url("chrome://global/skin/icons/Close.gif");
 }
 
 /* Location bar */
-#urlbar,
-.searchbar-textbox {
-  -moz-appearance: none;
-  padding: 1px;
-  border: 1px solid ThreeDShadow;
-  border-radius: 2px;
-}
-
-#urlbar[focused],
-.searchbar-textbox[focused] {
-  border-color: Highlight;
-}
-
 #urlbar {
-  background-color: -moz-field;
+  -moz-appearance: textfield;
+  padding: 0;
 }
 
 .urlbar-textbox-container {
   -moz-appearance: none;
   -moz-box-align: stretch;
 }
 
 .urlbar-input-box {
@@ -884,66 +795,36 @@ toolbarbutton[sdk-button="true"][cui-are
 }
 
 #urlbar-container {
   -moz-box-orient: horizontal;
   -moz-box-align: stretch;
 }
 
 @conditionalForwardWithUrlbar@ > #urlbar-wrapper {
-  padding-left: @conditionalForwardWithUrlbarWidth@px;
+  -moz-padding-start: @conditionalForwardWithUrlbarWidth@px;
   -moz-margin-start: -@conditionalForwardWithUrlbarWidth@px;
   position: relative;
   pointer-events: none;
 }
 
 @conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar {
-  -moz-border-start: none;
-  margin-left: 0;
   pointer-events: all;
 }
 
 @conditionalForwardWithUrlbar@:not([switchingtabs]) > #urlbar-wrapper > #urlbar {
-  transition: margin-left @forwardTransitionLength@ ease-out;
-}
-
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(ltr) {
-  border-top-left-radius: 0;
-  border-bottom-left-radius: 0;
-}
-
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) {
-  border-top-right-radius: 0;
-  border-bottom-right-radius: 0;
-}
-
-@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper {
-  clip-path: url("chrome://browser/content/browser.xul#urlbar-back-button-clip-path");
+  transition: margin-left @forwardTransitionLength@ ease-out,
+              margin-right @forwardTransitionLength@ ease-out;
 }
 
-@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar {
+@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar:-moz-locale-dir(ltr) {
   margin-left: -@conditionalForwardWithUrlbarWidth@px;
 }
-
-@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) > #urlbar-wrapper > #urlbar {
-  /* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */
-  transition-delay: 100s;
-}
-
-@conditionalForwardWithUrlbar@[forwarddisabled][switchingtabs] + #urlbar-container > #urlbar,
-@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar {
-  /* when switching tabs, or when not hovered anymore, trigger a new transition
-   * to hide the forward button immediately */
-  margin-left: -@conditionalForwardWithUrlbarWidth@.01px;
-}
-
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper:-moz-locale-dir(rtl),
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) {
-  /* let windows-urlbar-back-button-mask clip the urlbar's right side for RTL */
-  transform: scaleX(-1);
+@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) {
+  margin-right: -@conditionalForwardWithUrlbarWidth@px;
 }
 
 #urlbar-icons {
   -moz-box-align: center;
 }
 
 .urlbar-icon {
   cursor: pointer;
@@ -973,109 +854,67 @@ toolbarbutton[sdk-button="true"][cui-are
   -moz-margin-start: 0;
   color: GrayText;
 }
 
 #search-container {
   min-width: calc(54px + 11ch);
 }
 
-/* identity box */
+%include ../shared/identity-block.inc.css
+
+#page-proxy-favicon {
+  margin-top: 2px;
+  margin-bottom: 2px;
+  -moz-margin-start: 4px;
+  -moz-margin-end: 3px;
+  -moz-image-region: rect(0, 16px, 16px, 0);
+}
 
+#identity-box:hover > #page-proxy-favicon {
+  -moz-image-region: rect(0, 32px, 16px, 16px);
+}
+
+#identity-box:hover:active > #page-proxy-favicon,
+#identity-box[open=true] > #page-proxy-favicon {
+  -moz-image-region: rect(0, 48px, 16px, 32px);
+}
+
+/* Identity indicator */
 #identity-box {
   padding: 1px;
+  margin: -1px;
+  -moz-margin-end: 0;
   font-size: .9em;
 }
 
 #identity-box:-moz-locale-dir(ltr) {
-  border-top-left-radius: 1.5px;
-  border-bottom-left-radius: 1.5px;
+  border-top-left-radius: 2.5px;
+  border-bottom-left-radius: 2.5px;
 }
 
 #identity-box:-moz-locale-dir(rtl) {
-  border-top-right-radius: 1.5px;
-  border-bottom-right-radius: 1.5px;
-}
-
-#notification-popup-box:not([hidden]) + #identity-box {
-  -moz-padding-start: 10px;
-  border-radius: 0;
-}
-
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar > #identity-box {
-  border-radius: 0;
-}
-
-@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
-  padding-left: 5px;
-  transition: padding-left;
-}
-
-@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
-  padding-right: 5px;
-  transition: padding-right;
-}
-
-@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box {
-  /* forward button hiding is delayed when hovered */
-  transition-delay: 100s;
-}
-
-@conditionalForwardWithUrlbar@[forwarddisabled][switchingtabs] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr),
-@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
-  /* when not hovered anymore, trigger a new non-delayed transition to react to the forward button hiding */
-  padding-left: 5.01px;
-}
-
-@conditionalForwardWithUrlbar@[forwarddisabled][switchingtabs] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl),
-@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
-  /* when not hovered anymore, trigger a new non-delayed transition to react to the forward button hiding */
-  padding-right: 5.01px;
-}
-
-#urlbar[pageproxystate="valid"] > #identity-box.chromeUI,
-#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity {
-  -moz-margin-end: 4px;
-}
-
-#identity-box.verifiedIdentity:not(:-moz-lwtheme) {
-  background-color: #fff;
+  border-top-right-radius: 2.5px;
+  border-bottom-right-radius: 2.5px;
 }
 
 #identity-box:-moz-focusring {
   outline: 1px dotted #000;
   outline-offset: -3px;
 }
 
 #identity-icon-labels {
   -moz-padding-start: 2px;
   -moz-padding-end: 5px;
 }
 
-%include ../shared/identity-block.inc.css
-
-#page-proxy-favicon {
-  margin-top: 1px;
-  margin-bottom: 1px;
-  -moz-margin-start: 3px;
-  -moz-margin-end: 2px;
-  -moz-image-region: rect(0, 16px, 16px, 0);
-}
-
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar > #identity-box > #page-proxy-favicon {
-  -moz-margin-end: 1px;
-}
-
-#identity-box:hover > #page-proxy-favicon {
-  -moz-image-region: rect(0, 32px, 16px, 16px);
-}
-
-#identity-box:hover:active > #page-proxy-favicon,
-#identity-box[open=true] > #page-proxy-favicon {
-  -moz-image-region: rect(0, 48px, 16px, 32px);
+#urlbar[pageproxystate="valid"] > #identity-box.chromeUI,
+#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity {
+  background-color: #fff;
+  -moz-margin-end: 4px;
 }
 
 /* Identity popup icons */
 #identity-popup-icon {
   height: 64px;
   width: 64px;
   padding: 0;
   list-style-image: url("chrome://browser/skin/identity.png");
--- a/browser/themes/osx/browser-lightweightTheme.css
+++ b/browser/themes/osx/browser-lightweightTheme.css
@@ -11,25 +11,27 @@
 
 /* Lightweight theme on tabs */
 #tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start[selected=true]:-moz-lwtheme::before,
 #tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end[selected=true]:-moz-lwtheme::before {
   background-attachment: scroll, fixed;
   background-color: transparent;
   background-image: @fgTabTextureLWT@;/*, lwtHeader;*/
   background-position: 0 0, right top;
+  background-repeat: repeat-x, no-repeat;
 }
 
 #tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme {
   background-attachment: scroll, scroll, fixed;
   background-color: transparent;
   background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png),
                     @fgTabTextureLWT@;/*,
                     lwtHeader;*/
   background-position: 0 0, 0 0, right top;
+  background-repeat: repeat-x, repeat-x, no-repeat;
 }
 
 @media (min-resolution: 2dppx) {
   #tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme {
     background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle@2x.png),
                       @fgTabTextureLWT@;/*,
                       lwtHeader;*/
   }
--- a/browser/themes/shared/customizableui/panelUIOverlay.inc.css
+++ b/browser/themes/shared/customizableui/panelUIOverlay.inc.css
@@ -1,15 +1,16 @@
 /* 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/. */
 
 %filter substitution
 
 %define menuPanelWidth 22.35em
+%define standaloneSubviewWidth 30em
 % XXXgijs This is the ugliest bit of code I think I've ever written for Mozilla.
 % Basically, the 0.1px is there to avoid CSS rounding errors causing buttons to wrap.
 % For gory details, refer to https://bugzilla.mozilla.org/show_bug.cgi?id=963365#c11
 % There's no calc() here (and therefore lots of calc() where this is used) because
 % we don't support nested calc(): https://bugzilla.mozilla.org/show_bug.cgi?id=968761
 %define menuPanelButtonWidth (@menuPanelWidth@ / 3 - 0.1px)
 %define exitSubviewGutterWidth 38px
 %define buttonStateHover :not(:-moz-any([disabled],[open],:active)):hover
@@ -84,16 +85,20 @@
 .panel-viewstack[viewtype="main"] > .panel-subviews {
   transform: translateX(@menuPanelWidth@);
 }
 
 .panel-viewstack[viewtype="main"] > .panel-subviews:-moz-locale-dir(rtl) {
   transform: translateX(-@menuPanelWidth@);
 }
 
+panelmultiview[nosubviews=true] > .panel-viewcontainer > .panel-viewstack > .panel-subviews {
+  display: none;
+}
+
 .panel-viewstack:not([viewtype="main"]) > .panel-mainview > #PanelUI-mainView {
   -moz-box-flex: 1;
 }
 
 .panel-subview-body {
   overflow-y: auto;
   overflow-x: hidden;
   -moz-box-flex: 1;
@@ -181,20 +186,23 @@
   margin: -1px 0 0;
 }
 
 #wrapper-edit-controls:-moz-any([place="palette"],[place="panel"]) > #edit-controls,
 #wrapper-zoom-controls:-moz-any([place="palette"],[place="panel"]) > #zoom-controls {
   -moz-margin-start: 0;
 }
 
-#PanelUI-contents,
+#PanelUI-contents {
+  max-width: @menuPanelWidth@;
+}
+
 #BMB_bookmarksPopup,
 .panel-mainview:not([panelid="PanelUI-popup"]) {
-  max-width: @menuPanelWidth@;
+  max-width: @standaloneSubviewWidth@;
 }
 
 panelview:not([mainview]) .toolbarbutton-text,
 .cui-widget-panel toolbarbutton > .toolbarbutton-text {
   text-align: start;
   display: -moz-box;
 }
 
--- a/browser/themes/windows/browser-lightweightTheme.css
+++ b/browser/themes/windows/browser-lightweightTheme.css
@@ -12,18 +12,20 @@
 
 /* Lightweight theme on tabs */
 #tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start[selected=true]:-moz-lwtheme::before,
 #tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end[selected=true]:-moz-lwtheme::before {
   background-attachment: scroll, fixed;
   background-color: transparent;
   background-image: @fgTabTextureLWT@;/*, lwtHeader;*/
   background-position: 0 0, right top;
+  background-repeat: repeat-x, no-repeat;
 }
 
 #tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme {
   background-attachment: scroll, scroll, fixed;
   background-color: transparent;
   background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png),
                     @fgTabTextureLWT@;/*,
                     lwtHeader;*/
   background-position: 0 0, 0 0, right top;
+  background-repeat: repeat-x, repeat-x, no-repeat;
 }
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -759,17 +759,17 @@ toolbarbutton[sdk-button="true"][cui-are
   #nav-bar .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon,
   #nav-bar .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-text,
   #nav-bar .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-container {
     background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
     background-color: hsla(210,54%,20%,.15);
     border-color: hsla(210,54%,20%,.3) hsla(210,54%,20%,.35) hsla(210,54%,20%,.4);
     box-shadow: 0 1px 1px hsla(210,54%,20%,.1) inset,
                 0 0 1px hsla(210,54%,20%,.2) inset,
-                /* allows keyhole-forward-clip-path to be used for non-hover as well as hover: */
+                /* allows windows-keyhole-forward-clip-path to be used for non-hover as well as hover: */
                 0 1px 0 hsla(210,54%,20%,0),
                 0 0 2px hsla(210,54%,20%,0);
     text-shadow: none;
     transition: none;
   }
 
   #nav-bar .toolbarbutton-1:-moz-any(:hover,[open]) > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon {
     -moz-border-start-color: hsla(210,54%,20%,.35);
@@ -813,17 +813,17 @@ toolbarbutton[sdk-button="true"][cui-are
 
 #forward-button > menupopup {
   margin-top: 1px !important;
 }
 
 #forward-button > .toolbarbutton-icon {
   background-clip: padding-box !important;
   /*mask: url(keyhole-forward-mask.svg#mask); XXX: this regresses twinopen */
-  clip-path: url(chrome://browser/content/browser.xul#keyhole-forward-clip-path) !important;
+  clip-path: url(chrome://browser/content/browser.xul#windows-keyhole-forward-clip-path) !important;
   margin-left: -7px !important;
   border-left-style: none !important;
   border-radius: 0 !important;
   padding-left: 7px !important;
   padding-right: 3px !important;
 }
 
 %ifdef WINDOWS_AERO
@@ -1118,17 +1118,17 @@ toolbarbutton[sdk-button="true"][cui-are
 }
 
 @conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) {
   border-top-right-radius: 0;
   border-bottom-right-radius: 0;
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper {
-  clip-path: url("chrome://browser/content/browser.xul#urlbar-back-button-clip-path");
+  clip-path: url("chrome://browser/content/browser.xul#windows-urlbar-back-button-clip-path");
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar {
   margin-left: -@conditionalForwardWithUrlbarWidth@px;
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) > #urlbar-wrapper > #urlbar {
   /* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */
--- a/content/canvas/public/nsICanvasRenderingContextInternal.h
+++ b/content/canvas/public/nsICanvasRenderingContextInternal.h
@@ -92,16 +92,17 @@ public:
   // of the canvas at the time it was called.
   virtual mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot() = 0;
 
   // If this context is opaque, the backing store of the canvas should
   // be created as opaque; all compositing operators should assume the
   // dst alpha is always 1.0.  If this is never called, the context
   // defaults to false (not opaque).
   NS_IMETHOD SetIsOpaque(bool isOpaque) = 0;
+  virtual bool GetIsOpaque() = 0;
 
   // Invalidate this context and release any held resources, in preperation
   // for possibly reinitializing with SetDimensions/InitializeWithSurface.
   NS_IMETHOD Reset() = 0;
 
   // Return the CanvasLayer for this context, creating
   // one for the given layer manager if not available.
   virtual already_AddRefed<CanvasLayer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -983,16 +983,20 @@ CanvasRenderingContext2D::InitializeWith
 NS_IMETHODIMP
 CanvasRenderingContext2D::SetIsOpaque(bool isOpaque)
 {
   if (isOpaque != mOpaque) {
     mOpaque = isOpaque;
     ClearTarget();
   }
 
+  if (mOpaque) {
+    EnsureTarget();
+  }
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 CanvasRenderingContext2D::SetIsIPC(bool isIPC)
 {
   if (isIPC != mIPC) {
     mIPC = isIPC;
@@ -1057,16 +1061,20 @@ CanvasRenderingContext2D::SetContextOpti
   ContextAttributes2D attributes;
   NS_ENSURE_TRUE(attributes.Init(aCx, aOptions), NS_ERROR_UNEXPECTED);
 
   if (Preferences::GetBool("gfx.canvas.willReadFrequently.enable", false)) {
     // Use software when there is going to be a lot of readback
     mForceSoftware = attributes.mWillReadFrequently;
   }
 
+  if (!attributes.mAlpha) {
+    SetIsOpaque(true);
+  }
+
   return NS_OK;
 }
 
 void
 CanvasRenderingContext2D::GetImageBuffer(uint8_t** aImageBuffer,
                                          int32_t* aFormat)
 {
   *aImageBuffer = nullptr;
@@ -3802,16 +3810,40 @@ CanvasRenderingContext2D::GetImageDataAr
   }
 
   // NOTE! dst is the same as src, and this relies on reading
   // from src and advancing that ptr before writing to dst.
   // NOTE! I'm not sure that it is, I think this comment might have been
   // inherited from Thebes canvas and is no longer true
   uint8_t* dst = data + dstWriteRect.y * (aWidth * 4) + dstWriteRect.x * 4;
 
+  if (mOpaque) {
+    for (int32_t j = 0; j < dstWriteRect.height; ++j) {
+      for (int32_t i = 0; i < dstWriteRect.width; ++i) {
+        // XXX Is there some useful swizzle MMX we can use here?
+#if MOZ_LITTLE_ENDIAN
+        uint8_t b = *src++;
+        uint8_t g = *src++;
+        uint8_t r = *src++;
+        src++;
+#else
+        src++;
+        uint8_t r = *src++;
+        uint8_t g = *src++;
+        uint8_t b = *src++;
+#endif
+        *dst++ = r;
+        *dst++ = g;
+        *dst++ = b;
+        *dst++ = 255;
+      }
+      src += srcStride - (dstWriteRect.width * 4);
+      dst += (aWidth * 4) - (dstWriteRect.width * 4);
+    }
+  } else
   for (int32_t j = 0; j < dstWriteRect.height; ++j) {
     for (int32_t i = 0; i < dstWriteRect.width; ++i) {
       // XXX Is there some useful swizzle MMX we can use here?
 #if MOZ_LITTLE_ENDIAN
       uint8_t b = *src++;
       uint8_t g = *src++;
       uint8_t r = *src++;
       uint8_t a = *src++;
--- a/content/canvas/src/CanvasRenderingContext2D.h
+++ b/content/canvas/src/CanvasRenderingContext2D.h
@@ -403,16 +403,17 @@ public:
                             const char16_t* aEncoderOptions,
                             nsIInputStream **aStream) MOZ_OVERRIDE;
   NS_IMETHOD GetThebesSurface(gfxASurface **surface) MOZ_OVERRIDE;
 
   mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot() MOZ_OVERRIDE
   { EnsureTarget(); return mTarget->Snapshot(); }
 
   NS_IMETHOD SetIsOpaque(bool isOpaque) MOZ_OVERRIDE;
+  bool GetIsOpaque() MOZ_OVERRIDE { return mOpaque; }
   NS_IMETHOD Reset() MOZ_OVERRIDE;
   already_AddRefed<CanvasLayer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
                                                CanvasLayer *aOldLayer,
                                                LayerManager *aManager) MOZ_OVERRIDE;
   virtual bool ShouldForceInactiveLayer(LayerManager *aManager) MOZ_OVERRIDE;
   void MarkContextClean() MOZ_OVERRIDE;
   NS_IMETHOD SetIsIPC(bool isIPC) MOZ_OVERRIDE;
   // this rect is in canvas device space
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -173,16 +173,17 @@ public:
     virtual void GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat);
     NS_IMETHOD GetInputStream(const char* aMimeType,
                               const char16_t* aEncoderOptions,
                               nsIInputStream **aStream) MOZ_OVERRIDE;
     NS_IMETHOD GetThebesSurface(gfxASurface **surface) MOZ_OVERRIDE;
     mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot() MOZ_OVERRIDE;
 
     NS_IMETHOD SetIsOpaque(bool b) MOZ_OVERRIDE { return NS_OK; };
+    bool GetIsOpaque() MOZ_OVERRIDE { return false; }
     NS_IMETHOD SetContextOptions(JSContext* aCx,
                                  JS::Handle<JS::Value> aOptions) MOZ_OVERRIDE;
 
     NS_IMETHOD SetIsIPC(bool b) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
     NS_IMETHOD Redraw(const gfxRect&) { return NS_ERROR_NOT_IMPLEMENTED; }
     NS_IMETHOD Swap(mozilla::ipc::Shmem& aBack,
                     int32_t x, int32_t y, int32_t w, int32_t h)
                     { return NS_ERROR_NOT_IMPLEMENTED; }
--- a/content/canvas/test/test_canvas.html
+++ b/content/canvas/test/test_canvas.html
@@ -21572,16 +21572,34 @@ function test_linedash() {
   isPixel(ctx, 120, 25, 0, 255, 0, 255, 0);
   isPixel(ctx, 115, 40, 0, 0, 0, 0, 0);
   isPixel(ctx, 105, 40, 0, 255, 0, 255, 0);
   isPixel(ctx, 90, 35, 0, 0, 0, 0, 0);
   isPixel(ctx, 90, 25, 0, 255, 0, 255, 0);
 }
 </script>
 
+<p>Canvas test: test_opaque</p>
+<canvas id="c688" width="150" height="50"></canvas>
+<script type="text/javascript">
+
+function test_opaque() {
+  var c = document.getElementById("c688");
+  var ctx = c.getContext("2d", {alpha: false});
+  ctx.fillStyle = "green";
+  ctx.fillRect(0,0,10,10);
+  ctx.fillStyle = "rgba(255,0,0,.5)";
+  ctx.fillRect(10,0,10,10);
+
+  isPixel(ctx, 20, 20, 0, 0, 0, 255, 0);
+  isPixel(ctx, 5, 5, 0, 128, 0, 255, 0);
+  isPixel(ctx, 15, 5, 128, 0, 0, 255, 0);
+}
+</script>
+
 <script>
 
 function asyncTestsDone() {
 	if (isDone_test_2d_drawImage_animated_apng &&
 		isDone_test_2d_drawImage_animated_gif) {
 		SimpleTest.finish();
 	} else {
 		setTimeout(asyncTestsDone, 500);
@@ -24868,16 +24886,22 @@ function runTests() {
   ok(false, "unexpected exception thrown in: test_getImageData_after_zero_canvas");
  }
  try {
   test_linedash();
  } catch(e) {
   throw e;
   ok(false, "unexpected exception thrown in: test_linedash");
  }
+try {
+  test_opaque();
+ } catch(e) {
+  throw e;
+  ok(false, "unexpected exception thrown in: test_opaque");
+ }
  try {
   // run this test last since it replaces the getContext method
   test_type_replace();
  } catch (e) {
   ok(false, "unexpected exception thrown in: test_type_replace");
  }
  
  //run the asynchronous tests
--- a/content/html/content/src/HTMLCanvasElement.cpp
+++ b/content/html/content/src/HTMLCanvasElement.cpp
@@ -776,17 +776,17 @@ HTMLCanvasElement::MozGetIPCContext(cons
 nsresult
 HTMLCanvasElement::UpdateContext(JSContext* aCx, JS::Handle<JS::Value> aNewContextOptions)
 {
   if (!mCurrentContext)
     return NS_OK;
 
   nsIntSize sz = GetWidthHeight();
 
-  nsresult rv = mCurrentContext->SetIsOpaque(GetIsOpaque());
+  nsresult rv = mCurrentContext->SetIsOpaque(HasAttr(kNameSpaceID_None, nsGkAtoms::moz_opaque));
   if (NS_FAILED(rv)) {
     mCurrentContext = nullptr;
     mCurrentContextId.Truncate();
     return rv;
   }
 
   rv = mCurrentContext->SetContextOptions(aCx, aNewContextOptions);
   if (NS_FAILED(rv)) {
@@ -898,16 +898,20 @@ HTMLCanvasElement::GetContextAtIndex(int
     return mCurrentContext;
 
   return nullptr;
 }
 
 bool
 HTMLCanvasElement::GetIsOpaque()
 {
+  if (mCurrentContext) {
+    return mCurrentContext->GetIsOpaque();
+  }
+
   return HasAttr(kNameSpaceID_None, nsGkAtoms::moz_opaque);
 }
 
 already_AddRefed<CanvasLayer>
 HTMLCanvasElement::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
                                   CanvasLayer *aOldLayer,
                                   LayerManager *aManager)
 {
--- a/content/html/content/test/test_ignoreuserfocus.html
+++ b/content/html/content/test/test_ignoreuserfocus.html
@@ -4,16 +4,17 @@
     <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
     <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   </head>
   <body>
     <script type="application/javascript;version=1.7">
       "use strict";
 
+      SimpleTest.requestCompleteLog();
       SimpleTest.waitForExplicitFinish();
 
       // Copied from EventUtils.js, but we want *ToWindow methods.
       function synthesizeMouseAtPoint(left, top, aEvent, aWindow) {
         var utils = _getDOMWindowUtils(aWindow);
         var defaultPrevented = false;
         if (utils) {
           var button = aEvent.button || 0;
--- a/content/media/gstreamer/GStreamerAllocator.cpp
+++ b/content/media/gstreamer/GStreamerAllocator.cpp
@@ -55,17 +55,17 @@ G_DEFINE_TYPE(MozGfxBufferPool, moz_gfx_
 
 void
 moz_gfx_memory_reset(MozGfxMemory *mem)
 {
   if (mem->image)
     mem->image->Release();
 
   ImageContainer* container = ((MozGfxMemoryAllocator*) mem->memory.allocator)->reader->GetImageContainer();
-  mem->image = reinterpret_cast<PlanarYCbCrImage*>(container->CreateImage(ImageFormat::PLANAR_YCBCR).get());
+  mem->image = reinterpret_cast<PlanarYCbCrImage*>(container->CreateImage(ImageFormat::PLANAR_YCBCR).take());
   mem->data = mem->image->AllocateAndGetNewBuffer(mem->memory.size);
 }
 
 static GstMemory*
 moz_gfx_memory_allocator_alloc(GstAllocator* aAllocator, gsize aSize,
     GstAllocationParams* aParams)
 {
   MozGfxMemory* mem = g_slice_new (MozGfxMemory);
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -405,17 +405,17 @@ DOMInterfaces = {
 },
 
 'FileReaderSync': {
     'workers': True,
     'wrapperCache': False,
 },
 
 'FileRequest': {
-    'nativeType': 'mozilla::dom::file::DOMFileRequest',
+    'nativeType': 'mozilla::dom::file::FileRequest',
 },
 
 'FormData': [
 {
     'nativeType': 'nsFormData'
 },
 {
     'workers': True,
deleted file mode 100644
--- a/dom/file/DOMFileRequest.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* 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 "DOMFileRequest.h"
-
-#include "mozilla/dom/FileRequestBinding.h"
-#include "LockedFile.h"
-
-USING_FILE_NAMESPACE
-
-DOMFileRequest::DOMFileRequest(nsPIDOMWindow* aWindow)
-  : FileRequest(aWindow)
-{
-}
-
-// static
-already_AddRefed<DOMFileRequest>
-DOMFileRequest::Create(nsPIDOMWindow* aOwner, LockedFile* aLockedFile)
-{
-  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
-
-  nsRefPtr<DOMFileRequest> request = new DOMFileRequest(aOwner);
-  request->mLockedFile = aLockedFile;
-
-  return request.forget();
-}
-
-/* virtual */ JSObject*
-DOMFileRequest::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
-{
-  return FileRequestBinding::Wrap(aCx, aScope, this);
-}
-
-nsIDOMLockedFile*
-DOMFileRequest::GetLockedFile() const
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-  return mLockedFile;
-}
deleted file mode 100644
--- a/dom/file/DOMFileRequest.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* 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_file_DOMFileRequest_h
-#define mozilla_dom_file_DOMFileRequest_h
-
-#include "FileRequest.h"
-
-class nsIDOMLockedFile;
-
-BEGIN_FILE_NAMESPACE
-
-class DOMFileRequest : public FileRequest
-{
-public:
-  static already_AddRefed<DOMFileRequest>
-  Create(nsPIDOMWindow* aOwner, LockedFile* aLockedFile);
-
-  virtual JSObject* WrapObject(JSContext* aCx,
-                               JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
-
-  nsIDOMLockedFile* GetLockedFile() const;
-  IMPL_EVENT_HANDLER(progress)
-
-protected:
-  DOMFileRequest(nsPIDOMWindow* aWindow);
-};
-
-END_FILE_NAMESPACE
-
-#endif // mozilla_dom_file_DOMFileRequest_h
--- a/dom/file/FileHandle.cpp
+++ b/dom/file/FileHandle.cpp
@@ -159,17 +159,18 @@ FileHandle::GetFile(ErrorResult& aError)
 
   nsRefPtr<LockedFile> lockedFile =
     LockedFile::Create(this, FileMode::Readonly, LockedFile::PARALLEL);
   if (!lockedFile) {
     aError.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
     return nullptr;
   }
 
-  nsRefPtr<FileRequest> request = FileRequest::Create(GetOwner(), lockedFile);
+  nsRefPtr<FileRequest> request =
+    FileRequest::Create(GetOwner(), lockedFile, /* aWrapAsDOMRequest */ true);
 
   nsRefPtr<MetadataParameters> params = new MetadataParameters(true, false);
 
   nsRefPtr<GetFileHelper> helper =
     new GetFileHelper(lockedFile, request, params, this);
 
   nsresult rv = helper->Enqueue();
   if (NS_FAILED(rv)) {
--- a/dom/file/FileRequest.cpp
+++ b/dom/file/FileRequest.cpp
@@ -1,46 +1,48 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* 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 "FileRequest.h"
 
-#include "DOMFileRequest.h"
+#include "mozilla/dom/FileRequestBinding.h"
 #include "nsCxPusher.h"
 #include "nsEventDispatcher.h"
 #include "nsError.h"
 #include "nsIDOMProgressEvent.h"
 #include "nsDOMClassInfoID.h"
 #include "FileHelper.h"
 #include "LockedFile.h"
 
 USING_FILE_NAMESPACE
 
 FileRequest::FileRequest(nsPIDOMWindow* aWindow)
-  : DOMRequest(aWindow)
+  : DOMRequest(aWindow), mWrapAsDOMRequest(false)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
 FileRequest::~FileRequest()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
 // static
 already_AddRefed<FileRequest>
-FileRequest::Create(nsPIDOMWindow* aOwner, LockedFile* aLockedFile)
+FileRequest::Create(nsPIDOMWindow* aOwner, LockedFile* aLockedFile,
+                    bool aWrapAsDOMRequest)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   nsRefPtr<FileRequest> request = new FileRequest(aOwner);
   request->mLockedFile = aLockedFile;
+  request->mWrapAsDOMRequest = aWrapAsDOMRequest;
 
   return request.forget();
 }
 
 nsresult
 FileRequest::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@@ -96,16 +98,33 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED_1(Fil
                                      mLockedFile)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FileRequest)
 NS_INTERFACE_MAP_END_INHERITING(DOMRequest)
 
 NS_IMPL_ADDREF_INHERITED(FileRequest, DOMRequest)
 NS_IMPL_RELEASE_INHERITED(FileRequest, DOMRequest)
 
+// virtual
+JSObject*
+FileRequest::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
+{
+  if (mWrapAsDOMRequest) {
+    return DOMRequest::WrapObject(aCx, aScope);
+  }
+  return FileRequestBinding::Wrap(aCx, aScope, this);
+}
+
+nsIDOMLockedFile*
+FileRequest::GetLockedFile() const
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+  return mLockedFile;
+}
+
 void
 FileRequest::FireProgressEvent(uint64_t aLoaded, uint64_t aTotal)
 {
   if (NS_FAILED(CheckInnerWindowCorrectness())) {
     return;
   }
 
   nsCOMPtr<nsIDOMEvent> event;
--- a/dom/file/FileRequest.h
+++ b/dom/file/FileRequest.h
@@ -7,48 +7,63 @@
 #ifndef mozilla_dom_file_filerequest_h__
 #define mozilla_dom_file_filerequest_h__
 
 #include "mozilla/Attributes.h"
 #include "FileCommon.h"
 
 #include "DOMRequest.h"
 
+class nsIDOMLockedFile;
+
 BEGIN_FILE_NAMESPACE
 
 class FileHelper;
 class LockedFile;
 
 class FileRequest : public mozilla::dom::DOMRequest
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FileRequest, DOMRequest)
 
   static already_AddRefed<FileRequest>
-  Create(nsPIDOMWindow* aOwner, LockedFile* aLockedFile);
+  Create(nsPIDOMWindow* aOwner, LockedFile* aLockedFile,
+         bool aWrapAsDOMRequest);
 
   // nsIDOMEventTarget
   virtual nsresult
   PreHandleEvent(nsEventChainPreVisitor& aVisitor) MOZ_OVERRIDE;
 
   void
   OnProgress(uint64_t aProgress, uint64_t aProgressMax)
   {
     FireProgressEvent(aProgress, aProgressMax);
   }
 
   nsresult
   NotifyHelperCompleted(FileHelper* aFileHelper);
 
+  // nsWrapperCache
+  virtual JSObject*
+  WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
+  // WebIDL
+  nsIDOMLockedFile*
+  GetLockedFile() const;
+
+  IMPL_EVENT_HANDLER(progress)
+
 protected:
   FileRequest(nsPIDOMWindow* aWindow);
   ~FileRequest();
 
   void
   FireProgressEvent(uint64_t aLoaded, uint64_t aTotal);
 
   nsRefPtr<LockedFile> mLockedFile;
+
+  bool mWrapAsDOMRequest;
 };
 
 END_FILE_NAMESPACE
 
 #endif // mozilla_dom_file_filerequest_h__
--- a/dom/file/LockedFile.cpp
+++ b/dom/file/LockedFile.cpp
@@ -17,19 +17,19 @@
 #include "nsNetUtil.h"
 #include "nsDOMClassInfoID.h"
 #include "nsJSUtils.h"
 #include "nsStringStream.h"
 #include "nsWidgetsCID.h"
 #include "xpcpublic.h"
 
 #include "AsyncHelper.h"
-#include "DOMFileRequest.h"
 #include "FileHandle.h"
 #include "FileHelper.h"
+#include "FileRequest.h"
 #include "FileService.h"
 #include "FileStreamWrappers.h"
 #include "MemoryStreams.h"
 #include "MetadataHelper.h"
 #include "nsError.h"
 #include "nsContentUtils.h"
 
 #include "mozilla/dom/EncodingUtils.h"
@@ -415,21 +415,21 @@ LockedFile::GetOrCreateStream(nsISupport
   }
 
   nsCOMPtr<nsISupports> stream(mStream);
   stream.forget(aStream);
 
   return NS_OK;
 }
 
-already_AddRefed<DOMFileRequest>
+already_AddRefed<FileRequest>
 LockedFile::GenerateFileRequest()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-  return DOMFileRequest::Create(GetOwner(), this);
+  return FileRequest::Create(GetOwner(), this, /* aWrapAsDOMRequest */ false);
 }
 
 bool
 LockedFile::IsOpen() const
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   // If we haven't started anything then we're open.
@@ -551,17 +551,17 @@ LockedFile::GetMetadata(JS::Handle<JS::V
   NS_ENSURE_TRUE(result, NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
 
   nsRefPtr<MetadataParameters> params =
     new MetadataParameters(config.mSize, config.mLastModified);
   if (!params->IsConfigured()) {
     return NS_ERROR_TYPE_ERR;
   }
 
-  nsRefPtr<DOMFileRequest> fileRequest = GenerateFileRequest();
+  nsRefPtr<FileRequest> fileRequest = GenerateFileRequest();
 
   nsRefPtr<MetadataHelper> helper =
     new MetadataHelper(this, fileRequest, params);
 
   nsresult rv = helper->Enqueue();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
 
   nsRefPtr<nsIDOMDOMRequest> request = fileRequest.forget();
@@ -588,17 +588,17 @@ LockedFile::ReadAsArrayBuffer(uint64_t a
     return NS_ERROR_TYPE_ERR;
   }
 
   // Do nothing if the window is closed
   if (!GetOwner()) {
     return NS_OK;
   }
 
-  nsRefPtr<DOMFileRequest> fileRequest = GenerateFileRequest();
+  nsRefPtr<FileRequest> fileRequest = GenerateFileRequest();
 
   nsRefPtr<ReadHelper> helper =
     new ReadHelper(this, fileRequest, mLocation, aSize);
 
   nsresult rv = helper->Init();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
 
   rv = helper->Enqueue();
@@ -630,17 +630,17 @@ LockedFile::ReadAsText(uint64_t aSize,
     return NS_ERROR_TYPE_ERR;
   }
 
   // Do nothing if the window is closed
   if (!GetOwner()) {
     return NS_OK;
   }
 
-  nsRefPtr<DOMFileRequest> fileRequest = GenerateFileRequest();
+  nsRefPtr<FileRequest> fileRequest = GenerateFileRequest();
 
   nsRefPtr<ReadTextHelper> helper =
     new ReadTextHelper(this, fileRequest, mLocation, aSize, aEncoding);
 
   nsresult rv = helper->Init();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
 
   rv = helper->Enqueue();
@@ -701,17 +701,17 @@ LockedFile::Truncate(uint64_t aSize,
     location = mLocation;
   }
 
   // Do nothing if the window is closed
   if (!GetOwner()) {
     return NS_OK;
   }
 
-  nsRefPtr<DOMFileRequest> fileRequest = GenerateFileRequest();
+  nsRefPtr<FileRequest> fileRequest = GenerateFileRequest();
 
   nsRefPtr<TruncateHelper> helper =
     new TruncateHelper(this, fileRequest, location);
 
   nsresult rv = helper->Enqueue();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
 
   if (aOptionalArgCount) {
@@ -736,17 +736,17 @@ LockedFile::Flush(nsISupports** _retval)
     return NS_ERROR_DOM_FILEHANDLE_READ_ONLY_ERR;
   }
 
   // Do nothing if the window is closed
   if (!GetOwner()) {
     return NS_OK;
   }
 
-  nsRefPtr<DOMFileRequest> fileRequest = GenerateFileRequest();
+  nsRefPtr<FileRequest> fileRequest = GenerateFileRequest();
 
   nsRefPtr<FlushHelper> helper = new FlushHelper(this, fileRequest);
 
   nsresult rv = helper->Enqueue();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
 
   nsRefPtr<nsIDOMDOMRequest> request = fileRequest.forget();
   request.forget(_retval);
@@ -858,17 +858,17 @@ LockedFile::WriteOrAppend(JS::Handle<JS:
     GetInputStreamForJSVal(aValue, aCx, getter_AddRefs(inputStream),
                            &inputLength);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!inputLength) {
     return NS_OK;
   }
 
-  nsRefPtr<DOMFileRequest> fileRequest = GenerateFileRequest();
+  nsRefPtr<FileRequest> fileRequest = GenerateFileRequest();
 
   uint64_t location = aAppend ? UINT64_MAX : mLocation;
 
   nsRefPtr<WriteHelper> helper =
     new WriteHelper(this, fileRequest, location, inputStream, inputLength);
 
   rv = helper->Enqueue();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
--- a/dom/file/LockedFile.h
+++ b/dom/file/LockedFile.h
@@ -14,17 +14,16 @@
 #include "nsIRunnable.h"
 
 #include "nsDOMEventTargetHelper.h"
 
 class nsIInputStream;
 
 BEGIN_FILE_NAMESPACE
 
-class DOMFileRequest;
 class FileHandle;
 class FileRequest;
 class MetadataHelper;
 
 class LockedFile : public nsDOMEventTargetHelper,
                    public nsIDOMLockedFile,
                    public nsIRunnable
 {
@@ -93,17 +92,17 @@ private:
   ~LockedFile();
 
   void
   OnNewRequest();
 
   void
   OnRequestFinished();
 
-  inline already_AddRefed<DOMFileRequest>
+  already_AddRefed<FileRequest>
   GenerateFileRequest();
 
   nsresult
   WriteOrAppend(JS::Handle<JS::Value> aValue, JSContext* aCx,
                 nsISupports** _retval, bool aAppend);
 
   nsresult
   Finish();
--- a/dom/file/moz.build
+++ b/dom/file/moz.build
@@ -17,33 +17,32 @@ EXPORTS += [
 ]
 
 EXPORTS.mozilla.dom.file += [
     'ArchiveEvent.h',
     'ArchiveReader.h',
     'ArchiveRequest.h',
     'ArchiveZipEvent.h',
     'ArchiveZipFile.h',
-    'DOMFileRequest.h',
     'File.h',
     'FileCommon.h',
     'FileHandle.h',
     'FileHelper.h',
+    'FileRequest.h',
     'FileService.h',
     'LockedFile.h',
 ]
 
 UNIFIED_SOURCES += [
     'ArchiveEvent.cpp',
     'ArchiveReader.cpp',
     'ArchiveRequest.cpp',
     'ArchiveZipEvent.cpp',
     'ArchiveZipFile.cpp',
     'AsyncHelper.cpp',
-    'DOMFileRequest.cpp',
     'File.cpp',
     'FileHandle.cpp',
     'FileHelper.cpp',
     'FileRequest.cpp',
     'FileService.cpp',
     'FileStreamWrappers.cpp',
     'LockedFile.cpp',
     'MemoryStreams.cpp',
--- a/dom/file/test/mochitest.ini
+++ b/dom/file/test/mochitest.ini
@@ -8,16 +8,18 @@ support-files =
 skip-if = buildapp == 'b2g'
 [test_archivereader.html]
 skip-if = buildapp == 'b2g'
 [test_archivereader_nonUnicode.html]
 skip-if = buildapp == 'b2g'
 [test_archivereader_zip_in_zip.html]
 skip-if = buildapp == 'b2g'
 [test_bug_793311.html]
+[test_getFile.html]
+skip-if = buildapp == 'b2g'
 [test_getFileId.html]
 [test_location.html]
 skip-if = buildapp == 'b2g'
 [test_lockedfile_lifetimes.html]
 skip-if = buildapp == 'b2g'
 [test_lockedfile_lifetimes_nested.html]
 skip-if = buildapp == 'b2g'
 [test_lockedfile_ordering.html]
new file mode 100644
--- /dev/null
+++ b/dom/file/test/test_getFile.html
@@ -0,0 +1,43 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>File Handle Test</title>
+
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+  <script type="text/javascript;version=1.7">
+  function testSteps()
+  {
+    for each (let fileStorage in fileStorages) {
+      let request = getFileHandle(fileStorage.key, "test.txt");
+      request.onerror = errorHandler;
+      request.onsuccess = grabEventAndContinueHandler;
+      let event = yield undefined;
+
+      let fileHandle = event.target.result;
+      fileHandle.onerror = errorHandler;
+
+      request = fileHandle.getFile();
+      ok(request instanceof DOMRequest, "Correct interface");
+      ok(!(request instanceof FileRequest), "Correct interface");
+      ok(!('lockedFile' in request), "Property should not exist");
+      ok(request.lockedFile === undefined, "Property should not exist");
+      ok(!('onprogress' in request), "Property should not exist");
+      ok(request.onprogress === undefined, "Property should not exist");
+    }
+
+    finishTest();
+    yield undefined;
+  }
+  </script>
+  <script type="text/javascript;version=1.7" src="helpers.js"></script>
+
+</head>
+
+<body onload="runTest();"></body>
+
+</html>
--- a/dom/webidl/CanvasRenderingContext2D.webidl
+++ b/dom/webidl/CanvasRenderingContext2D.webidl
@@ -11,16 +11,18 @@
  * and create derivative works of this document.
  */
 
 enum CanvasWindingRule { "nonzero", "evenodd" };
 
 dictionary ContextAttributes2D {
   // whether or not we're planning to do a lot of readback operations
   boolean willReadFrequently = false;
+  // signal if the canvas contains an alpha channel
+  boolean alpha = true;
 };
 
 dictionary HitRegionOptions {
   DOMString id = "";
   Element? control = null;
 };
 
 interface CanvasRenderingContext2D {
--- a/js/src/builtin/TypeRepresentation.cpp
+++ b/js/src/builtin/TypeRepresentation.cpp
@@ -304,53 +304,53 @@ StructTypeRepresentation::init(JSContext
                                AutoPropertyNameVector &names,
                                AutoObjectVector &typeReprOwners)
 {
     JS_ASSERT(names.length() == typeReprOwners.length());
     fieldCount_ = names.length();
 
     // We compute alignment into the field `align_` directly in the
     // loop below, but not `size_` because we have to very careful
-    // about overflow. For now, we always use a uint32_t for
+    // about overflow. For now, we always use a int32_t for
     // consistency across build environments.
-    uint32_t totalSize = 0;
+    int32_t totalSize = 0;
 
     // These will be adjusted in the loop below:
     alignment_ = 1;
     opaque_ = false;
 
     for (size_t i = 0; i < names.length(); i++) {
         SizedTypeRepresentation *fieldTypeRepr =
             fromOwnerObject(*typeReprOwners[i])->asSized();
 
         if (fieldTypeRepr->opaque())
             opaque_ = true;
 
-        uint32_t alignedSize = alignTo(totalSize, fieldTypeRepr->alignment());
+        int32_t alignedSize = alignTo(totalSize, fieldTypeRepr->alignment());
         if (alignedSize < totalSize) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
                                  JSMSG_TYPEDOBJECT_TOO_BIG);
             return false;
         }
 
         new(fields() + i) StructField(i, names[i],
                                       fieldTypeRepr, alignedSize);
         alignment_ = js::Max(alignment_, fieldTypeRepr->alignment());
 
-        uint32_t incrementedSize = alignedSize + fieldTypeRepr->size();
+        int32_t incrementedSize = alignedSize + fieldTypeRepr->size();
         if (incrementedSize < alignedSize) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
                                  JSMSG_TYPEDOBJECT_TOO_BIG);
             return false;
         }
 
         totalSize = incrementedSize;
     }
 
-    uint32_t alignedSize = alignTo(totalSize, alignment_);
+    int32_t alignedSize = alignTo(totalSize, alignment_);
     if (alignedSize < totalSize) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
                              JSMSG_TYPEDOBJECT_TOO_BIG);
         return false;
     }
 
     size_ = alignedSize;
     return true;
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -2296,16 +2296,22 @@ TypedObject::constructSized(JSContext *c
         return true;
     }
 
     // Buffer constructor.
     if (args[0].isObject() && args[0].toObject().is<ArrayBufferObject>()) {
         Rooted<ArrayBufferObject*> buffer(cx);
         buffer = &args[0].toObject().as<ArrayBufferObject>();
 
+        if (buffer->isNeutered()) {
+            JS_ReportErrorNumber(cx, js_GetErrorMessage,
+                                 nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
+            return false;
+        }
+
         int32_t offset;
         if (args.length() >= 2 && !args[1].isUndefined()) {
             if (!args[1].isInt32()) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage,
                                      nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
                 return false;
             }
 
@@ -2402,16 +2408,22 @@ TypedObject::constructUnsized(JSContext 
         return true;
     }
 
     // Buffer constructor.
     if (args[0].isObject() && args[0].toObject().is<ArrayBufferObject>()) {
         Rooted<ArrayBufferObject*> buffer(cx);
         buffer = &args[0].toObject().as<ArrayBufferObject>();
 
+        if (buffer->isNeutered()) {
+            JS_ReportErrorNumber(cx, js_GetErrorMessage,
+                                 nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
+            return false;
+        }
+
         int32_t offset;
         if (args.length() >= 2 && !args[1].isUndefined()) {
             if (!args[1].isInt32()) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage,
                                      nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
                 return false;
             }
 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/TypedObject/atopneuteredbuffer.js
@@ -0,0 +1,23 @@
+// Bug 976697. Check for various quirks when instantiating a typed
+// object atop an already neutered buffer.
+
+if (typeof TypedObject === "undefined")
+  quit();
+
+load(libdir + "asserts.js")
+
+var {StructType, uint32, Object, Any, storage, objectType} = TypedObject;
+
+function main() { // once a C programmer, always a C programmer.
+  var Uints = uint32.array();
+  var Unit = new StructType({});   // Empty struct type
+  var buffer = new ArrayBuffer(0); // Empty buffer
+  var p = new Unit(buffer);        // OK
+  neuter(buffer);
+  assertThrowsInstanceOf(() => new Unit(buffer), TypeError,
+                         "Able to instantiate atop neutered buffer");
+  assertThrowsInstanceOf(() => new Uints(buffer, 0), TypeError,
+                         "Able to instantiate atop neutered buffer");
+}
+
+main();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/TypedObject/bug976530.js
@@ -0,0 +1,10 @@
+// |jit-test| error:Error
+
+// Test that we don't permit structs whose fields exceed 32 bits.
+
+if (!this.hasOwnProperty("TypedObject"))
+  throw new Error();
+
+var Vec3u16Type = TypedObject.uint16.array((1073741823));
+var PairVec3u16Type = new TypedObject.StructType({ fst: Vec3u16Type, snd: Vec3u16Type });
+new PairVec3u16Type();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/TypedObject/bug976697.js
@@ -0,0 +1,13 @@
+// Test that instantiating a typed array on top of a neutered buffer
+// doesn't trip any asserts.
+//
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+if (!this.hasOwnProperty("TypedObject"))
+  quit();
+
+x = ArrayBuffer();
+neuter(x);
+Uint32Array(x);
+gc();
--- a/js/src/jit/arm/Assembler-arm.cpp
+++ b/js/src/jit/arm/Assembler-arm.cpp
@@ -1802,21 +1802,16 @@ Assembler::patchConstantPoolLoad(void* l
 
 uint32_t
 Assembler::placeConstantPoolBarrier(int offset)
 {
     // BUG: 700526
     // this is still an active path, however, we do not hit it in the test
     // suite at all.
     MOZ_ASSUME_UNREACHABLE("ARMAssembler holdover");
-#if 0
-    offset = (offset - sizeof(ARMWord)) >> 2;
-    ASSERT((offset <= BOFFSET_MAX && offset >= BOFFSET_MIN));
-    return AL | B | (offset & BRANCH_MASK);
-#endif
 }
 
 // Control flow stuff:
 
 // bx can *only* branch to a register
 // never to an immediate.
 BufferOffset
 Assembler::as_bx(Register r, Condition c, bool isPatchable)
--- a/js/src/jit/arm/Bailouts-arm.cpp
+++ b/js/src/jit/arm/Bailouts-arm.cpp
@@ -8,64 +8,16 @@
 #include "jscompartment.h"
 
 #include "jit/Bailouts.h"
 #include "jit/JitCompartment.h"
 
 using namespace js;
 using namespace js::jit;
 
-#if 0
-// no clue what these asserts should be.
-JS_STATIC_ASSERT(sizeof(BailoutStack) ==
-                 sizeof(uintptr_t) +
-                 sizeof(double) * 8 +
-                 sizeof(uintptr_t) * 8 +
-                 sizeof(uintptr_t));
-
-JS_STATIC_ASSERT(sizeof(ExtendedBailoutStack) ==
-                 sizeof(BailoutStack) +
-                 sizeof(uintptr_t));
-
-#endif
-#if 0
-BailoutEnvironment::BailoutEnvironment(JitCompartment *ion, void **sp)
-  : sp_(sp)
-{
-    bailout_ = reinterpret_cast<ExtendedBailoutStack *>(sp);
-
-    if (bailout_->frameClass() != FrameSizeClass::None()) {
-        frameSize_ = bailout_->frameSize();
-        frame_ = &sp_[sizeof(BailoutStack) / sizeof(void *)];
-
-        // Compute the bailout ID.
-        JitCode *code = ion->getBailoutTable(bailout_->frameClass());
-        uintptr_t tableOffset = bailout_->tableOffset();
-        uintptr_t tableStart = reinterpret_cast<uintptr_t>(code->raw());
-
-        JS_ASSERT(tableOffset >= tableStart &&
-                  tableOffset < tableStart + code->instructionsSize());
-        JS_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0);
-
-        bailoutId_ = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1;
-        JS_ASSERT(bailoutId_ < BAILOUT_TABLE_SIZE);
-    } else {
-        frameSize_ = bailout_->frameSize();
-        frame_ = &sp_[sizeof(ExtendedBailoutStack) / sizeof(void *)];
-    }
-}
-
-IonFramePrefix *
-BailoutEnvironment::top() const
-{
-    return (IonFramePrefix *)&frame_[frameSize_ / sizeof(void *)];
-}
-
-#endif
-
 namespace js {
 namespace jit {
 
 class BailoutStack
 {
     uintptr_t frameClassId_;
     // This is pushed in the bailout handler.  Both entry points into the handler
     // inserts their own value int lr, which is then placed onto the stack along
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -237,33 +237,18 @@ CodeGeneratorARM::bailoutFrom(Label *lab
     if (!encode(snapshot))
         return false;
 
     // Though the assembler doesn't track all frame pushes, at least make sure
     // the known value makes sense. We can't use bailout tables if the stack
     // isn't properly aligned to the static frame size.
     JS_ASSERT_IF(frameClass_ != FrameSizeClass::None(),
                  frameClass_.frameSize() == masm.framePushed());
-    // This involves retargeting a label, which I've declared is always going
-    // to be a pc-relative branch to an absolute address!
-    // With no assurance that this is going to be a local branch, I am wary to
-    // implement this.  Moreover, If it isn't a local branch, it will be large
-    // and possibly slow.  I believe that the correct way to handle this is to
-    // subclass label into a fatlabel, where we generate enough room for a load
-    // before the branch
-#if 0
-    if (assignBailoutId(snapshot)) {
-        uint8_t *code = deoptTable_->raw() + snapshot->bailoutId() * BAILOUT_TABLE_ENTRY_SIZE;
-        masm.retarget(label, code, Relocation::HARDCODED);
-        return true;
-    }
-#endif
-    // We could not use a jump table, either because all bailout IDs were
-    // reserved, or a jump table is not optimal for this frame size or
-    // platform. Whatever, we will generate a lazy bailout.
+
+    // On ARM we don't use a bailout table.
     OutOfLineBailout *ool = new(alloc()) OutOfLineBailout(snapshot, masm.framePushed());
     if (!addOutOfLineCode(ool)) {
         return false;
     }
 
     masm.retarget(label, ool->entry());
 
     return true;
@@ -1656,24 +1641,16 @@ CodeGeneratorARM::visitNotD(LNotD *ins)
         masm.ma_lsr(Imm32(28), dest, dest);
         masm.ma_alu(dest, lsr(dest, 2), dest, op_orr); // 28 + 2 = 30
         masm.ma_and(Imm32(1), dest);
     } else {
         masm.as_vmrs(pc);
         masm.ma_mov(Imm32(0), dest);
         masm.ma_mov(Imm32(1), dest, NoSetCond, Assembler::Equal);
         masm.ma_mov(Imm32(1), dest, NoSetCond, Assembler::Overflow);
-#if 0
-        masm.as_vmrs(ToRegister(dest));
-        // Mask out just the two bits we care about.  If neither bit is set,
-        // the dest is already zero
-        masm.ma_and(Imm32(0x50000000), dest, dest, Assembler::SetCond);
-        // If it is non-zero, then force it to be 1.
-        masm.ma_mov(Imm32(1), dest, NoSetCond, Assembler::NotEqual);
-#endif
     }
     return true;
 }
 
 bool
 CodeGeneratorARM::visitNotF(LNotF *ins)
 {
     // Since this operation is not, we want to set a bit if
@@ -1693,24 +1670,16 @@ CodeGeneratorARM::visitNotF(LNotF *ins)
         masm.ma_lsr(Imm32(28), dest, dest);
         masm.ma_alu(dest, lsr(dest, 2), dest, op_orr); // 28 + 2 = 30
         masm.ma_and(Imm32(1), dest);
     } else {
         masm.as_vmrs(pc);
         masm.ma_mov(Imm32(0), dest);
         masm.ma_mov(Imm32(1), dest, NoSetCond, Assembler::Equal);
         masm.ma_mov(Imm32(1), dest, NoSetCond, Assembler::Overflow);
-#if 0
-        masm.as_vmrs(ToRegister(dest));
-        // Mask out just the two bits we care about.  If neither bit is set,
-        // the dest is already zero
-        masm.ma_and(Imm32(0x50000000), dest, dest, Assembler::SetCond);
-        // If it is non-zero, then force it to be 1.
-        masm.ma_mov(Imm32(1), dest, NoSetCond, Assembler::NotEqual);
-#endif
     }
     return true;
 }
 
 bool
 CodeGeneratorARM::visitLoadSlotV(LLoadSlotV *load)
 {
     const ValueOperand out = ToOutValue(load);
--- a/js/src/jit/arm/Trampoline-arm.cpp
+++ b/js/src/jit/arm/Trampoline-arm.cpp
@@ -143,28 +143,16 @@ JitRuntime::generateEnterJIT(JSContext *
     // Save stack pointer.
     if (type == EnterJitBaseline)
         masm.movePtr(sp, r11);
 
     // Load the number of actual arguments into r10.
     masm.loadPtr(slot_vp, r10);
     masm.unboxInt32(Address(r10, 0), r10);
 
-#if 0
-    // This is in case we want to go back to using frames that
-    // aren't 8 byte alinged
-    // there are r1 2-word arguments to the js code
-    // we want 2 word alignment, so this shouldn't matter.
-    // After the arguments have been pushed, we want to push an additional 3 words of
-    // data, so in all, we want to decrease sp by 4 if it is currently aligned to
-    // 8, and not touch it otherwise
-    aasm->as_sub(sp, sp, Imm8(4));
-    aasm->as_orr(sp, sp, Imm8(4));
-#endif
-
     // Subtract off the size of the arguments from the stack pointer, store elsewhere
     aasm->as_sub(r4, sp, O2RegImmShift(r1, LSL, 3)); //r4 = sp - argc*8
     // Get the final position of the stack pointer into the stack pointer
     aasm->as_sub(sp, r4, Imm8(16)); // sp' = sp - argc*8 - 16
     // Get a copy of the number of args to use as a decrement counter, also
     // Set the zero condition code
     aasm->as_mov(r5, O2Reg(r1), SetCond);
 
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -298,16 +298,17 @@ ArrayBufferObject::class_constructor(JSC
  * with the cx if available and fall back to the runtime.  If oldptr is given,
  * it's expected to be a previously-allocated ObjectElements* pointer that we
  * then realloc.
  */
 static ObjectElements *
 AllocateArrayBufferContents(JSContext *maybecx, uint32_t nbytes, void *oldptr = nullptr)
 {
     uint32_t size = nbytes + sizeof(ObjectElements);
+    JS_ASSERT(size > nbytes); // be wary of rollover
     ObjectElements *newheader;
 
     // if oldptr is given, then we need to do a realloc
     if (oldptr) {
         ObjectElements *oldheader = static_cast<ObjectElements *>(oldptr);
         uint32_t oldnbytes = ArrayBufferObject::headerInitializedLength(oldheader);
 
         void *p = maybecx ? maybecx->runtime()->reallocCanGC(oldptr, size) : js_realloc(oldptr, size);
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -297,17 +297,24 @@ PostBarrierTypedArrayObject(JSObject *ob
 inline void
 InitArrayBufferViewDataPointer(ArrayBufferViewObject *obj, ArrayBufferObject *buffer, size_t byteOffset)
 {
     /*
      * N.B. The base of the array's data is stored in the object's
      * private data rather than a slot to avoid alignment restrictions
      * on private Values.
      */
-    obj->initPrivate(buffer->dataPointer() + byteOffset);
+
+    if (buffer->isNeutered()) {
+        JS_ASSERT(byteOffset == 0);
+        obj->initPrivate(nullptr);
+    } else {
+        obj->initPrivate(buffer->dataPointer() + byteOffset);
+    }
+
     PostBarrierTypedArrayObject(obj);
 }
 
 /*
  * Tests for either ArrayBufferObject or SharedArrayBufferObject.
  * For specific class testing, use e.g., obj->is<ArrayBufferObject>().
  */
 bool IsArrayBuffer(HandleValue v);
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -357,17 +357,17 @@ class TypedArrayObjectTemplate : public 
         if (!empty)
             return nullptr;
         obj->setLastPropertyInfallible(empty);
 
 #ifdef DEBUG
         uint32_t bufferByteLength = buffer->byteLength();
         uint32_t arrayByteLength = obj->byteLength();
         uint32_t arrayByteOffset = obj->byteOffset();
-        JS_ASSERT(buffer->dataPointer() <= obj->viewData());
+        JS_ASSERT_IF(!buffer->isNeutered(), buffer->dataPointer() <= obj->viewData());
         JS_ASSERT(bufferByteLength - arrayByteOffset >= arrayByteLength);
         JS_ASSERT(arrayByteOffset <= bufferByteLength);
 
         // Verify that the private slot is at the expected place
         JS_ASSERT(obj->numFixedSlots() == DATA_SLOT);
 #endif
 
         buffer->addView(obj);
--- a/services/sync/Makefile.in
+++ b/services/sync/Makefile.in
@@ -54,16 +54,17 @@ sync_stage_modules := \
   declined.js \
   enginesync.js \
   $(NULL)
 
 sync_testing_modules := \
   fakeservices.js \
   rotaryengine.js \
   utils.js \
+  fxa_utils.js \
   $(NULL)
 
 PREF_JS_EXPORTS := $(srcdir)/services-sync.js
 
 # Install JS module files.
 SYNC_MAIN_FILES := $(addprefix modules/,$(sync_modules))
 SYNC_MAIN_DEST = $(FINAL_TARGET)/modules/services-sync
 INSTALL_TARGETS += SYNC_MAIN
new file mode 100644
--- /dev/null
+++ b/services/sync/modules-testing/fxa_utils.js
@@ -0,0 +1,67 @@
+"use strict";
+
+this.EXPORTED_SYMBOLS = [
+  "Assert_rejects",
+  "initializeIdentityWithTokenServerResponse",
+];
+
+const {utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/Log.jsm");
+Cu.import("resource://services-sync/main.js");
+Cu.import("resource://services-sync/browserid_identity.js");
+Cu.import("resource://services-common/tokenserverclient.js");
+Cu.import("resource://testing-common/services-common/logging.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
+
+// This shouldn't be here - it should be part of the xpcshell harness.
+// Maybe as Assert.rejects - so we name it like that.
+function Assert_rejects(promise, message) {
+  let deferred = Promise.defer();
+  promise.then(
+    () => deferred.reject(message || "Expected the promise to be rejected"),
+    deferred.resolve
+  );
+  return deferred.promise;
+}
+
+// Create a new browserid_identity object and initialize it with a
+// mocked TokenServerClient which always receives the specified response.
+this.initializeIdentityWithTokenServerResponse = function(response) {
+  // First create a mock "request" object that well' hack into the token server.
+  // A log for it
+  let requestLog = Log.repository.getLogger("testing.mock-rest");
+  if (!requestLog.appenders.length) { // might as well see what it says :)
+    requestLog.addAppender(new Log.DumpAppender());
+    requestLog.level = Log.Level.Trace;
+  }
+
+  // A mock request object.
+  function MockRESTRequest(url) {};
+  MockRESTRequest.prototype = {
+    _log: requestLog,
+    setHeader: function() {},
+    get: function(callback) {
+      this.response = response;
+      callback.call(this);
+    }
+  }
+  // The mocked TokenServer client which will get the response.
+  function MockTSC() { }
+  MockTSC.prototype = new TokenServerClient();
+  MockTSC.prototype.constructor = MockTSC;
+  MockTSC.prototype.newRESTRequest = function(url) {
+    return new MockRESTRequest(url);
+  }
+  // tie it all together.
+  Weave.Status.__authManager = Weave.Service.identity = new BrowserIDManager();
+  Weave.Service._clusterManager = Weave.Service.identity.createClusterManager(Weave.Service);
+  let browseridManager = Weave.Service.identity;
+  // a sanity check
+  if (!(browseridManager instanceof BrowserIDManager)) {
+    throw new Error("sync isn't configured for browserid_identity");
+  }
+  let mockTSC = new MockTSC()
+  configureFxAccountIdentity(browseridManager);
+  browseridManager._tokenServerClient = mockTSC;
+}
--- a/services/sync/modules/browserid_identity.js
+++ b/services/sync/modules/browserid_identity.js
@@ -629,17 +629,38 @@ BrowserIDClusterManager.prototype = {
       ).then(
         () => endPointFromIdentityToken()
       );
     }.bind(this);
 
     let cb = Async.makeSpinningCallback();
     promiseClusterURL().then(function (clusterURL) {
       cb(null, clusterURL);
-    }).then(null, cb);
+    }).then(
+      null, err => {
+      // service.js's verifyLogin() method will attempt to fetch a cluster
+      // URL when it sees a 401.  If it gets null, it treats it as a "real"
+      // auth error and sets Status.login to LOGIN_FAILED_LOGIN_REJECTED, which
+      // in turn causes a notification bar to appear informing the user they
+      // need to re-authenticate.
+      // On the other hand, if fetching the cluster URL fails with an exception,
+      // verifyLogin() assumes it is a transient error, and thus doesn't show
+      // the notification bar under the assumption the issue will resolve
+      // itself.
+      // Thus:
+      // * On a real 401, we must return null.
+      // * On any other problem we must let an exception bubble up.
+      if (err instanceof AuthenticationError) {
+        // callback with no error and a null result - cb.wait() returns null.
+        cb(null, null);
+      } else {
+        // callback with an error - cb.wait() completes by raising an exception.
+        cb(err);
+      }
+    });
     return cb.wait();
   },
 
   getUserBaseURL: function() {
     // Legacy Sync and FxA Sync construct the userBaseURL differently. Legacy
     // Sync appends path components onto an empty path, and in FxA Sync the
     // token server constructs this for us in an opaque manner. Since the
     // cluster manager already sets the clusterURL on Service and also has
--- a/services/sync/tests/unit/test_browserid_identity.js
+++ b/services/sync/tests/unit/test_browserid_identity.js
@@ -3,40 +3,29 @@
 
 Cu.import("resource://gre/modules/FxAccounts.jsm");
 Cu.import("resource://services-sync/browserid_identity.js");
 Cu.import("resource://services-sync/rest.js");
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://services-common/utils.js");
 Cu.import("resource://services-crypto/utils.js");
 Cu.import("resource://testing-common/services/sync/utils.js");
+Cu.import("resource://testing-common/services/sync/fxa_utils.js");
 Cu.import("resource://services-common/hawkclient.js");
 Cu.import("resource://gre/modules/FxAccounts.jsm");
 Cu.import("resource://gre/modules/FxAccountsClient.jsm");
 Cu.import("resource://gre/modules/FxAccountsCommon.js");
-Cu.import("resource://services-common/tokenserverclient.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/status.js");
 Cu.import("resource://services-sync/constants.js");
 
 const SECOND_MS = 1000;
 const MINUTE_MS = SECOND_MS * 60;
 const HOUR_MS = MINUTE_MS * 60;
 
-// This shouldn't be here - it should be part of the xpcshell harness.
-// Maybe as Assert.rejects - so we name it like that.
-function Assert_rejects(promise, message) {
-  let deferred = Promise.defer();
-  promise.then(
-    () => deferred.reject(message || "Expected the promise to be rejected"),
-    deferred.resolve
-  );
-  return deferred.promise;
-}
-
 let identityConfig = makeIdentityConfig();
 let browseridManager = new BrowserIDManager();
 configureFxAccountIdentity(browseridManager, identityConfig);
 
 /**
  * Mock client clock and skew vs server in FxAccounts signed-in user module and
  * API client.  browserid_identity.js queries these values to construct HAWK
  * headers.  We will use this to test clock skew compensation in these headers
@@ -343,62 +332,83 @@ add_test(function test_computeXClientSta
   do_check_eq(header, "6ae94683571c7a7c54dab4700aa3995f");
   run_next_test();
 });
 
 add_task(function test_getTokenErrors() {
   _("BrowserIDManager correctly handles various failures to get a token.");
 
   _("Arrange for a 401 - Sync should reflect an auth error.");
-  yield initializeIdentityWithTokenServerFailure({
+  initializeIdentityWithTokenServerResponse({
     status: 401,
     headers: {"content-type": "application/json"},
     body: JSON.stringify({}),
   });
+  let browseridManager = Service.identity;
+
+  yield browseridManager.initializeWithCurrentIdentity();
+  yield Assert_rejects(browseridManager.whenReadyToAuthenticate.promise,
+                       "should reject due to 401");
   Assert.equal(Status.login, LOGIN_FAILED_LOGIN_REJECTED, "login was rejected");
 
   // XXX - other interesting responses to return?
 
   // And for good measure, some totally "unexpected" errors - we generally
   // assume these problems are going to magically go away at some point.
   _("Arrange for an empty body with a 200 response - should reflect a network error.");
-  yield initializeIdentityWithTokenServerFailure({
+  initializeIdentityWithTokenServerResponse({
     status: 200,
     headers: [],
     body: "",
   });
+  browseridManager = Service.identity;
+  yield browseridManager.initializeWithCurrentIdentity();
+  yield Assert_rejects(browseridManager.whenReadyToAuthenticate.promise,
+                       "should reject due to non-JSON response");
   Assert.equal(Status.login, LOGIN_FAILED_NETWORK_ERROR, "login state is LOGIN_FAILED_NETWORK_ERROR");
 });
 
 add_task(function test_getTokenErrorWithRetry() {
   _("tokenserver sends an observer notification on various backoff headers.");
 
   // Set Sync's backoffInterval to zero - after we simulated the backoff header
   // it should reflect the value we sent.
   Status.backoffInterval = 0;
   _("Arrange for a 503 with a Retry-After header.");
-  yield initializeIdentityWithTokenServerFailure({
+  initializeIdentityWithTokenServerResponse({
     status: 503,
     headers: {"content-type": "application/json",
               "retry-after": "100"},
     body: JSON.stringify({}),
   });
+  let browseridManager = Service.identity;
+
+  yield browseridManager.initializeWithCurrentIdentity();
+  yield Assert_rejects(browseridManager.whenReadyToAuthenticate.promise,
+                       "should reject due to 503");
+
   // The observer should have fired - check it got the value in the response.
   Assert.equal(Status.login, LOGIN_FAILED_NETWORK_ERROR, "login was rejected");
   // Sync will have the value in ms with some slop - so check it is at least that.
   Assert.ok(Status.backoffInterval >= 100000);
 
   _("Arrange for a 200 with an X-Backoff header.");
   Status.backoffInterval = 0;
-  yield initializeIdentityWithTokenServerFailure({
+  initializeIdentityWithTokenServerResponse({
     status: 503,
     headers: {"content-type": "application/json",
               "x-backoff": "200"},
     body: JSON.stringify({}),
   });
+  browseridManager = Service.identity;
+
+  yield browseridManager.initializeWithCurrentIdentity();
+  yield Assert_rejects(browseridManager.whenReadyToAuthenticate.promise,
+                       "should reject due to no token in response");
+
   // The observer should have fired - check it got the value in the response.
   Assert.ok(Status.backoffInterval >= 200000);
 });
 
 add_task(function test_getHAWKErrors() {
   _("BrowserIDManager correctly handles various HAWK failures.");
 
   _("Arrange for a 401 - Sync should reflect an auth error.");
@@ -467,55 +477,16 @@ add_task(function test_getKeysError() {
 
   Assert.ok(ex.message.indexOf("missing kA or kB") >= 0);
 });
 
 // End of tests
 // Utility functions follow
 
 // Create a new browserid_identity object and initialize it with a
-// mocked TokenServerClient which always gets the specified response.
-function* initializeIdentityWithTokenServerFailure(response) {
-  // First create a mock "request" object that well' hack into the token server.
-  // A log for it
-  let requestLog = Log.repository.getLogger("testing.mock-rest");
-  if (!requestLog.appenders.length) { // might as well see what it says :)
-    requestLog.addAppender(new Log.DumpAppender());
-    requestLog.level = Log.Level.Trace;
-  }
-
-  // A mock request object.
-  function MockRESTRequest(url) {};
-  MockRESTRequest.prototype = {
-    _log: requestLog,
-    setHeader: function() {},
-    get: function(callback) {
-      this.response = response;
-      callback.call(this);
-    }
-  }
-  // The mocked TokenServer client which will get the response.
-  function MockTSC() { }
-  MockTSC.prototype = new TokenServerClient();
-  MockTSC.prototype.constructor = MockTSC;
-  MockTSC.prototype.newRESTRequest = function(url) {
-    return new MockRESTRequest(url);
-  }
-  // tie it all together.
-  let mockTSC = new MockTSC()
-  configureFxAccountIdentity(browseridManager);
-  browseridManager._tokenServerClient = mockTSC;
-
-  yield browseridManager.initializeWithCurrentIdentity();
-  yield Assert_rejects(browseridManager.whenReadyToAuthenticate.promise,
-                       "expecting rejection due to tokenserver error");
-}
-
-
-// Create a new browserid_identity object and initialize it with a
 // hawk mock that simulates a failure.
 // A token server mock will be used that doesn't hit a server, so we move
 // directly to a hawk request.
 function* initializeIdentityWithHAWKFailure(response) {
   // A mock request object.
   function MockRESTRequest() {};
   MockRESTRequest.prototype = {
     setHeader: function() {},
new file mode 100644
--- /dev/null
+++ b/services/sync/tests/unit/test_fxa_service_cluster.js
@@ -0,0 +1,68 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+Cu.import("resource://services-sync/service.js");
+Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/fxa_utils.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
+
+add_task(function test_findCluster() {
+  _("Test FxA _findCluster()");
+
+  _("_findCluster() throws on 500 errors.");
+  initializeIdentityWithTokenServerResponse({
+    status: 500,
+    headers: [],
+    body: "",
+  });
+
+  yield Service.identity.initializeWithCurrentIdentity();
+  yield Assert_rejects(Service.identity.whenReadyToAuthenticate.promise,
+                       "should reject due to 500");
+
+  Assert.throws(function() {
+    Service._clusterManager._findCluster();
+  });
+
+  _("_findCluster() returns null on authentication errors.");
+  initializeIdentityWithTokenServerResponse({
+    status: 401,
+    headers: {"content-type": "application/json"},
+    body: "{}",
+  });
+
+  yield Service.identity.initializeWithCurrentIdentity();
+  yield Assert_rejects(Service.identity.whenReadyToAuthenticate.promise,
+                       "should reject due to 401");
+
+  cluster = Service._clusterManager._findCluster();
+  Assert.strictEqual(cluster, null);
+
+  _("_findCluster() works with correct tokenserver response.");
+  let endpoint = "http://example.com/something";
+  initializeIdentityWithTokenServerResponse({
+    status: 200,
+    headers: {"content-type": "application/json"},
+    body:
+      JSON.stringify({
+        api_endpoint: endpoint,
+        duration: 300,
+        id: "id",
+        key: "key",
+        uid: "uid",
+      })
+  });
+
+  yield Service.identity.initializeWithCurrentIdentity();
+  yield Service.identity.whenReadyToAuthenticate.promise;
+  cluster = Service._clusterManager._findCluster();
+  // The cluster manager ensures a trailing "/"
+  Assert.strictEqual(cluster, endpoint + "/");
+
+  Svc.Prefs.resetBranch("");
+});
+
+function run_test() {
+  initTestLogging();
+  run_next_test();
+}
--- a/services/sync/tests/unit/test_load_modules.js
+++ b/services/sync/tests/unit/test_load_modules.js
@@ -32,16 +32,17 @@ const modules = [
   "userapi.js",
   "util.js",
 ];
 
 const testingModules = [
   "fakeservices.js",
   "rotaryengine.js",
   "utils.js",
+  "fxa_utils.js",
 ];
 
 function run_test() {
   for (let m of modules) {
     let res = "resource://services-sync/" + m;
     _("Attempting to load " + res);
     Cu.import(res, {});
   }
--- a/services/sync/tests/unit/xpcshell.ini
+++ b/services/sync/tests/unit/xpcshell.ini
@@ -119,16 +119,17 @@ skip-if = os == "android"
 [test_sendcredentials_controller.js]
 [test_status.js]
 [test_status_checkSetup.js]
 [test_syncscheduler.js]
 [test_upgrade_old_sync_key.js]
 
 # Firefox Accounts specific tests
 [test_fxa_startOver.js]
+[test_fxa_service_cluster.js]
 
 # Finally, we test each engine.
 [test_addons_engine.js]
 run-sequentially = Hardcoded port in static files.
 [test_addons_reconciler.js]
 [test_addons_store.js]
 run-sequentially = Hardcoded port in static files.
 [test_addons_tracker.js]
--- a/toolkit/components/passwordmgr/test/test_privbrowsing_perwindowpb.html
+++ b/toolkit/components/passwordmgr/test/test_privbrowsing_perwindowpb.html
@@ -19,16 +19,18 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 /** Test for Bug 248970 **/
 // based on test_notifications.html
 
 const Ci = SpecialPowers.Ci;
 const Cc = SpecialPowers.Cc;
 const Cr = SpecialPowers.Cr;
 
+Components.utils.import("resource://gre/modules/Services.jsm");
+
 var testpath = "/tests/toolkit/components/passwordmgr/test/";
 var prefix = "http://test2.example.com" + testpath;
 var subtests = [
                    "subtst_privbrowsing_1.html", // 1
                    "subtst_privbrowsing_1.html", // 2
                    "subtst_privbrowsing_1.html", // 3
                    "subtst_privbrowsing_2.html", // 4
                    "subtst_privbrowsing_2.html", // 5
@@ -186,34 +188,45 @@ var mainWindow = window.QueryInterface(C
                     .getInterface(Ci.nsIWebNavigation)
                     .QueryInterface(Ci.nsIDocShellTreeItem)
                     .rootTreeItem
                     .QueryInterface(Ci.nsIInterfaceRequestor)
                     .getInterface(Ci.nsIDOMWindow);
 var contentPage = "http://mochi.test:8888/tests/toolkit/components/passwordmgr/test/privbrowsing_perwindowpb_iframe.html";
 var testWindows = [];
 
+function whenDelayedStartupFinished(aWindow, aCallback) {
+  Services.obs.addObserver(function observer(aSubject, aTopic) {
+    if (aWindow == aSubject) {
+      Services.obs.removeObserver(observer, aTopic);
+      setTimeout(aCallback, 0);
+    }
+  }, "browser-delayed-startup-finished", false);
+}
+
 function testOnWindow(aIsPrivate, aCallback) {
   var win = mainWindow.OpenBrowserWindow({private: aIsPrivate});
   win.addEventListener("load", function onLoad() {
     win.removeEventListener("load", onLoad, false);
-    win.addEventListener("DOMContentLoaded", function onInnerLoad() {
-      if (win.content.location.href != contentPage) {
-        win.gBrowser.loadURI(contentPage);
-        return;
-      }
-      win.removeEventListener("DOMContentLoaded", onInnerLoad, true);
+    whenDelayedStartupFinished(win, function() {
+      win.addEventListener("DOMContentLoaded", function onInnerLoad() {
+        if (win.content.location.href != contentPage) {
+          win.gBrowser.loadURI(contentPage);
+          return;
+        }
+        win.removeEventListener("DOMContentLoaded", onInnerLoad, true);
 
-      win.content.addEventListener('load', function innerLoad2() {
-        win.content.removeEventListener('load', innerLoad2, false);
-        testWindows.push(win);
-        SimpleTest.executeSoon(function() { aCallback(win); });
-      }, false, true);
-    }, true);
-    SimpleTest.executeSoon(function() { win.gBrowser.loadURI(contentPage); });
+        win.content.addEventListener('load', function innerLoad2() {
+          win.content.removeEventListener('load', innerLoad2, false);
+          testWindows.push(win);
+          SimpleTest.executeSoon(function() { aCallback(win); });
+        }, false, true);
+      }, true);
+      SimpleTest.executeSoon(function() { win.gBrowser.loadURI(contentPage); });
+    });
   }, true);
 }
 
 var ignoreLoad = false;
 function handleLoad(aEvent) {
   // ignore every other load event ... We get one for loading the subtest (which
   // we want to ignore), and another when the subtest's form submits itself
   // (which we want to handle, to start the next test).
--- a/toolkit/content/tests/chrome/test_dialogfocus.xul
+++ b/toolkit/content/tests/chrome/test_dialogfocus.xul
@@ -19,64 +19,73 @@
 <pre id="test">
 </pre>
 </body>
 
 <script>
 <![CDATA[
 
 SimpleTest.waitForExplicitFinish();
+SimpleTest.requestCompleteLog();
 
 var expected = [ "one", "_extra2", "tab", "one", "tabbutton2", "tabbutton", "two", "textbox-yes", "one" ];
 // non-Mac will always focus the default button if any of the dialog buttons
 // would be focused
 if (navigator.platform.indexOf("Mac") == -1)
   expected[1] = "_accept";
 
 var step = 0;
 var fullKeyboardAccess = false;
 
 function startTest()
 {
   var testButton = document.getElementById("test");
   synthesizeKey("VK_TAB", { });
   fullKeyboardAccess = (document.activeElement == testButton);
+  info("We " + (fullKeyboardAccess ? "have" : "don't have") + " full keyboard access");
   runTest();
 }
 
 function runTest()
 {
   step++;
+  info("runTest(), step = " + step + ", expected = " + expected[step - 1]);
   if (step > expected.length || (!fullKeyboardAccess && step == 2)) {
+    info("finishing");
     SimpleTest.finish();
     return;
   }
 
   var expectedFocus = expected[step - 1];
   var win = window.openDialog("dialog_dialogfocus.xul", "_new", "chrome,dialog", step);
 
   function checkDialogFocus(event)
   {
+    info("checkDialogFocus()");
     // if full keyboard access is not on, just skip the tests
     var match = false;
     if (fullKeyboardAccess) {
-      if (!(event.target instanceof Element))
+      if (!(event.target instanceof Element)) {
+        info("target not an Element");
         return;
+      }
 
       if (expectedFocus == "textbox-yes")
         match = (win.document.activeElement == win.document.getElementById(expectedFocus).inputField);
       else if (expectedFocus[0] == "_")
         match = (win.document.activeElement.dlgType == expectedFocus.substring(1));
       else
         match = (win.document.activeElement.id == expectedFocus);
+      info("match = " + match);
       if (!match)
         return;
     }
     else {
       match = (win.document.activeElement == win.document.documentElement);
+      info("match = " + match);
     }
 
     win.removeEventListener("focus", checkDialogFocus, true);
     ok(match, "focus step " + step);
 
     win.close();
     SimpleTest.waitForFocus(runTest, window);
   }