Merge mozilla-central to b2g-inbound
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 24 Jul 2014 15:44:44 +0200
changeset 195890 8b82cdc779987cc3189b6c7de9a56129f92b1bfc
parent 195889 f30f74b034469e7cd0003de08bc551bb73b8e84d (current diff)
parent 195860 616e6924cb0b98ab5abde62f1d06993feb3976d6 (diff)
child 195891 c631f2a36220ec8071d8608de7b722bfdb6a29f1
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
milestone34.0a1
Merge mozilla-central to b2g-inbound
browser/devtools/projecteditor/test/browser_projecteditor_tree_selection.js
browser/themes/shared/incontentprefs/header.png
browser/themes/shared/incontentprefs/header@2x.png
media/libspeex_resampler/reset.patch
mobile/android/base/resources/values-v14/styles.xml
mobile/android/search/res/drawable-hdpi/search_icon.png
mobile/android/search/res/drawable-mdpi/search_icon.png
mobile/android/search/res/drawable-xhdpi/search_icon.png
--- a/accessible/tests/mochitest/actions/a11y.ini
+++ b/accessible/tests/mochitest/actions/a11y.ini
@@ -4,11 +4,12 @@
 [test_aria.html]
 [test_controls.html]
 [test_general.html]
 [test_general.xul]
 [test_keys.html]
 [test_keys_menu.xul]
 [test_link.html]
 [test_media.html]
+skip-if = buildapp == 'mulet'
 [test_select.html]
 [test_tree.xul]
 [test_treegrid.xul]
--- a/accessible/tests/mochitest/elm/a11y.ini
+++ b/accessible/tests/mochitest/elm/a11y.ini
@@ -1,9 +1,11 @@
 [DEFAULT]
 
 [test_HTMLSpec.html]
+skip-if = buildapp == 'mulet'
 [test_figure.html]
 [test_listbox.xul]
 [test_nsApplicationAcc.html]
 [test_plugin.html]
+skip-if = buildapp == 'mulet'
 [test_canvas.html]
 [test_shadowroot.html]
--- a/accessible/tests/mochitest/events/a11y.ini
+++ b/accessible/tests/mochitest/events/a11y.ini
@@ -11,16 +11,17 @@ support-files =
 [test_attrs.html]
 [test_caretmove.html]
 [test_caretmove.xul]
 [test_coalescence.html]
 [test_contextmenu.html]
 [test_descrchange.html]
 [test_docload.html]
 [test_docload.xul]
+skip-if = buildapp == 'mulet'
 [test_docload_aria.html]
 [test_dragndrop.html]
 [test_flush.html]
 [test_focus_aria_activedescendant.html]
 [test_focus_autocomplete.xul]
 # Disabled on Linux and Windows due to frequent failures - bug 695019, bug 890795
 skip-if = os == 'win' || os == 'linux'
 [test_focus_browserui.xul]
@@ -41,16 +42,17 @@ skip-if = os == 'win' || os == 'linux'
 [test_label.xul]
 [test_menu.xul]
 [test_mutation.html]
 [test_mutation.xhtml]
 [test_namechange.xul]
 [test_namechange.html]
 [test_scroll.xul]
 [test_selection.html]
+skip-if = buildapp == 'mulet'
 [test_selection.xul]
 [test_selection_aria.html]
 [test_statechange.html]
 [test_text.html]
 [test_text_alg.html]
 [test_textattrchange.html]
 [test_textselchange.html]
 [test_tree.xul]
--- a/accessible/tests/mochitest/focus/a11y.ini
+++ b/accessible/tests/mochitest/focus/a11y.ini
@@ -1,5 +1,6 @@
 [DEFAULT]
 
 [test_focusedChild.html]
 [test_takeFocus.html]
+skip-if = buildapp == 'mulet'
 [test_takeFocus.xul]
--- a/accessible/tests/mochitest/jsat/a11y.ini
+++ b/accessible/tests/mochitest/jsat/a11y.ini
@@ -5,17 +5,19 @@ support-files =
   jsatcommon.js
   output.js
   doc_traversal.html
   doc_content_integration.html
   doc_content_text.html
 
 [test_alive.html]
 [test_content_integration.html]
+skip-if = buildapp == 'mulet'
 [test_content_text.html]
+skip-if = buildapp == 'mulet'
 [test_explicit_names.html]
 [test_gesture_tracker.html]
 [test_landmarks.html]
 [test_live_regions.html]
 [test_output.html]
 [test_tables.html]
 [test_pointer_relay.html]
 [test_traversal.html]
--- a/accessible/tests/mochitest/states/a11y.ini
+++ b/accessible/tests/mochitest/states/a11y.ini
@@ -24,8 +24,9 @@ support-files =
 [test_popup.xul]
 [test_selects.html]
 [test_stale.html]
 [test_tabs.xul]
 [test_textbox.xul]
 [test_tree.xul]
 [test_visibility.html]
 [test_visibility.xul]
+skip-if = buildapp == "mulet"
--- a/accessible/tests/mochitest/tree/a11y.ini
+++ b/accessible/tests/mochitest/tree/a11y.ini
@@ -15,26 +15,28 @@ skip-if = true # Bug 561508
 [test_button.xul]
 [test_canvas.html]
 [test_combobox.xul]
 [test_cssoverflow.html]
 [test_dochierarchy.html]
 [test_dockids.html]
 [test_filectrl.html]
 [test_formctrl.html]
+skip-if = buildapp == "mulet"
 [test_formctrl.xul]
 [test_gencontent.html]
 [test_groupbox.xul]
 [test_iframe.html]
 [test_img.html]
 [test_invalid_img.xhtml]
 [test_invalidationlist.html]
 [test_list.html]
 [test_map.html]
 [test_media.html]
+skip-if = buildapp == "mulet"
 [test_select.html]
 [test_tabbox.xul]
 [test_tabbrowser.xul]
 [test_table.html]
 [test_tree.xul]
 [test_txtcntr.html]
 [test_txtctrl.html]
 [test_txtctrl.xul]
--- a/accessible/tests/mochitest/treeupdate/a11y.ini
+++ b/accessible/tests/mochitest/treeupdate/a11y.ini
@@ -9,16 +9,17 @@
 [test_colorpicker.xul]
 [test_contextmenu.xul]
 [test_cssoverflow.html]
 [test_deck.xul]
 [test_doc.html]
 [test_gencontent.html]
 [test_hidden.html]
 [test_imagemap.html]
+skip-if = buildapp == "mulet"
 [test_list.html]
 [test_list_editabledoc.html]
 [test_listbox.xul]
 [test_menu.xul]
 [test_menubutton.xul]
 [test_optgroup.html]
 [test_recreation.html]
 [test_select.html]
--- a/b2g/chrome/content/test/mochitest/mochitest.ini
+++ b/b2g/chrome/content/test/mochitest/mochitest.ini
@@ -1,10 +1,10 @@
 [DEFAULT]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #require OOP support for mochitest-b2g-desktop, Bug 957554
+skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') #require OOP support for mochitest-b2g-desktop, Bug 957554
 support-files =
   RecordingStatusChromeScript.js
   RecordingStatusHelper.js
   file_getusermedia_iframe.html
 
 [test_recordingStatus_basic.html]
 [test_recordingStatus_multiple_requests.html]
 [test_recordingStatus_iframe.html]
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -804,16 +804,43 @@ pref("plugin.state.npmcffplg", 2);
 #endif
 
 // F5 Networks SSLVPN plugin, bug 985640
 #ifdef XP_MACOSX
 pref("plugin.state.f5 ssl vpn plugin", 2);
 pref("plugin.state.f5 sam inspection host plugin", 2);
 #endif
 
+// Roblox Launcher Plugin, bug 1024073
+#ifdef XP_WIN
+pref("plugin.state.nprobloxproxy", 2);
+#endif
+#ifdef XP_MACOSX
+pref("plugins.state.nproblox", 2);
+#endif
+
+// Box Edit, bug 1029654
+#ifdef XP_WIN
+pref("plugins.state.npboxedit", 2);
+#endif
+#ifdef XP_MACOSX
+pref("plugins.state.box edit", 2);
+#endif
+
+// Nexus Personal, bug 1024965
+#ifdef XP_WIN
+pref("plugins.state.np_prsnl", 2);
+#endif
+#ifdef XP_MACOSX
+pref("plugins.state.personalplugin", 2);
+#endif
+#ifdef UNIX_BUT_NOT_MAC
+pref("plugins.state.libplugins", 2);
+#endif
+
 // display door hanger if flash not installed
 pref("plugins.notifyMissingFlash", true);
 
 #ifdef XP_MACOSX
 pref("browser.preferences.animateFadeIn", true);
 #else
 pref("browser.preferences.animateFadeIn", false);
 #endif
@@ -1351,16 +1378,17 @@ pref("devtools.scratchpad.enableAutocomp
 
 // Enable the Style Editor.
 pref("devtools.styleeditor.enabled", true);
 pref("devtools.styleeditor.source-maps-enabled", false);
 pref("devtools.styleeditor.autocompletion-enabled", true);
 pref("devtools.styleeditor.showMediaSidebar", true);
 pref("devtools.styleeditor.mediaSidebarWidth", 238);
 pref("devtools.styleeditor.navSidebarWidth", 245);
+pref("devtools.styleeditor.transitions", true);
 
 // Enable the Shader Editor.
 pref("devtools.shadereditor.enabled", false);
 
 // Enable the Canvas Debugger.
 pref("devtools.canvasdebugger.enabled", false);
 
 // Enable the Web Audio Editor
@@ -1474,16 +1502,19 @@ pref("browser.panorama.animate_zoom", tr
 // Defines the url to be used for new tabs.
 pref("browser.newtab.url", "about:newtab");
 // Activates preloading of the new tab url.
 pref("browser.newtab.preload", true);
 
 // Toggles the content of 'about:newtab'. Shows the grid when enabled.
 pref("browser.newtabpage.enabled", true);
 
+// Toggles the enhancement of history content of 'about:newtab'
+pref("browser.newtabpage.enhanced", false);
+
 // number of rows of newtab grid
 pref("browser.newtabpage.rows", 3);
 
 // number of columns of newtab grid
 pref("browser.newtabpage.columns", 3);
 
 // directory tiles download URL
 pref("browser.newtabpage.directory.source", "chrome://global/content/directoryLinks.json");
--- a/browser/base/content/newtab/grid.js
+++ b/browser/base/content/newtab/grid.js
@@ -156,16 +156,17 @@ let gGrid = {
     let site = document.createElementNS(HTML_NAMESPACE, "div");
     site.classList.add("newtab-site");
     site.setAttribute("draggable", "true");
 
     // Create the site's inner HTML code.
     site.innerHTML =
       '<a class="newtab-link">' +
       '  <span class="newtab-thumbnail"/>' +
+      '  <span class="newtab-thumbnail enhanced-content"/>' +
       '  <span class="newtab-title"/>' +
       '</a>' +
       '<input type="button" title="' + newTabString("pin") + '"' +
       '       class="newtab-control newtab-control-pin"/>' +
       '<input type="button" title="' + newTabString("block") + '"' +
       '       class="newtab-control newtab-control-block"/>' +
       '<input type="button" title="' + newTabString("sponsored") + '"' +
       '       class="newtab-control newtab-control-sponsored"/>';
--- a/browser/base/content/newtab/page.js
+++ b/browser/base/content/newtab/page.js
@@ -46,16 +46,21 @@ let gPage = {
   /**
    * Listens for notifications specific to this page.
    */
   observe: function Page_observe(aSubject, aTopic, aData) {
     if (aTopic == "nsPref:changed") {
       let enabled = gAllPages.enabled;
       this._updateAttributes(enabled);
 
+      // Update thumbnails to the new enhanced setting
+      if (aData == "browser.newtabpage.enhanced") {
+        this.update();
+      }
+
       // Initialize the whole page if we haven't done that, yet.
       if (enabled) {
         this._init();
       } else {
         gUndoDialog.hide();
       }
     } else if (aTopic == "page-thumbnail:create" && gGrid.ready) {
       for (let site of gGrid.sites) {
--- a/browser/base/content/newtab/sites.js
+++ b/browser/base/content/newtab/sites.js
@@ -148,22 +148,36 @@ Site.prototype = {
       BackgroundPageThumbs.captureIfMissing(this.url);
     }
   },
 
   /**
    * Refreshes the thumbnail for the site.
    */
   refreshThumbnail: function Site_refreshThumbnail() {
+    // Only enhance tiles if that feature is turned on
+    let link = gAllPages.enhanced && DirectoryLinksProvider.getEnhancedLink(this.link) ||
+               this.link;
+
     let thumbnail = this._querySelector(".newtab-thumbnail");
-    if (this.link.bgColor) {
-      thumbnail.style.backgroundColor = this.link.bgColor;
+    if (link.bgColor) {
+      thumbnail.style.backgroundColor = link.bgColor;
     }
-    let uri = this.link.imageURI || PageThumbs.getThumbnailURL(this.url);
+
+    let uri = link.imageURI || PageThumbs.getThumbnailURL(this.url);
     thumbnail.style.backgroundImage = 'url("' + uri + '")';
+
+    if (link.enhancedImageURI) {
+      let enhanced = this._querySelector(".enhanced-content");
+      enhanced.style.backgroundImage = 'url("' + link.enhancedImageURI + '")';
+
+      if (this.link.type != link.type) {
+        this.node.setAttribute("type", "enhanced");
+      }
+    }
   },
 
   /**
    * Adds event handlers for the site and its buttons.
    */
   _addEventHandlers: function Site_addEventHandlers() {
     // Register drag-and-drop event handlers.
     this._node.addEventListener("dragstart", this, false);
--- a/browser/base/content/test/chat/browser.ini
+++ b/browser/base/content/test/chat/browser.ini
@@ -1,8 +1,9 @@
 [DEFAULT]
+skip-if = buildapp == 'mulet'
 support-files =
   head.js
   chat.html
 
 [browser_chatwindow.js]
 [browser_focus.js]
 [browser_tearoff.js]
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -96,17 +96,17 @@ skip-if = e10s # Bug ?????? - no about:h
 [browser_aboutSyncProgress.js]
 [browser_addKeywordSearch.js]
 [browser_alltabslistener.js]
 skip-if = os == "linux" || e10s # Linux: Intermittent failures, bug 951680; e10s: Bug ?????? - notifications don't work correctly.
 [browser_backButtonFitts.js]
 skip-if = os != "win" || e10s # The Fitts Law back button is only supported on Windows (bug 571454) / e10s - Bug ?????? test touches content (attempts to add an event listener directly to the contentWindow)
 [browser_blob-channelname.js]
 [browser_bookmark_titles.js]
-skip-if = toolkit == "windows" || e10s # Disabled on Windows due to frequent failures (bugs 825739, 841341) / e10s - Bug ?????? test checks event.target on load event, which our e10s utils don't support
+skip-if = buildapp == 'mulet' || toolkit == "windows" || e10s # Disabled on Windows due to frequent failures (bugs 825739, 841341) / e10s - Bug ?????? test checks event.target on load event, which our e10s utils don't support
 [browser_bug304198.js]
 [browser_bug321000.js]
 skip-if = true # browser_bug321000.js is disabled because newline handling is shaky (bug 592528)
 [browser_bug329212.js]
 [browser_bug331772_xul_tooltiptext_in_html.js]
 [browser_bug356571.js]
 [browser_bug380960.js]
 [browser_bug386835.js]
@@ -130,53 +130,53 @@ skip-if = true # bug 428712
 skip-if = e10s # Bug ?????? - test directly manipulates content
 [browser_bug427559.js]
 skip-if = e10s # Bug ?????? - "content window is focused - Got [object ChromeWindow], expected [object XrayWrapper [object Window]]"
 [browser_bug431826.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content (eg, var expertDiv = gBrowser.contentDocument.getElementById("expertContent");)
 [browser_bug432599.js]
 [browser_bug435035.js]
 [browser_bug435325.js]
-skip-if = e10s # Bug ?????? - test directly manipulates content
+skip-if = buildapp == 'mulet' || e10s # Bug ?????? - test directly manipulates content
 [browser_bug441778.js]
-skip-if = e10s # Bug 691614 - no e10s zoom support yet
+skip-if = buildapp == 'mulet' || e10s # Bug 691614 - no e10s zoom support yet
 [browser_bug455852.js]
 [browser_bug460146.js]
 skip-if = e10s # Bug 866413 - PageInfo doesn't work in e10s
 [browser_bug462289.js]
 skip-if = toolkit == "cocoa" || e10s # Bug ?????? - not sure why this is timing out and crashing!!
 [browser_bug462673.js]
 skip-if = e10s # Bug 924260 - "Window is closed"
 [browser_bug477014.js]
 skip-if = e10s # Bug 918634 - swapFrameLoaders not implemented for e10s
 [browser_bug479408.js]
-skip-if = e10s # Bug 918663 - DOMLinkAdded events don't make their way to chrome
+skip-if = buildapp == 'mulet' || e10s # Bug 918663 - DOMLinkAdded events don't make their way to chrome
 [browser_bug481560.js]
 skip-if = e10s # Bug ????? - This bug attached an event listener directly to the content
 [browser_bug484315.js]
 [browser_bug491431.js]
-skip-if = e10s # Bug 918634 - swapFrameLoaders (and thus replaceTabWithWindow) not implemented for e10s
+skip-if = buildapp == 'mulet' || e10s # Bug 918634 - swapFrameLoaders (and thus replaceTabWithWindow) not implemented for e10s
 [browser_bug495058.js]
 skip-if = e10s # Bug 918634 - swapFrameLoaders (and thus replaceTabWithWindow) not implemented for e10s
 [browser_bug517902.js]
 skip-if = e10s # Bug 866413 - PageInfo doesn't work in e10s
 [browser_bug519216.js]
 skip-if = e10s # Bug ?????? - some weird timing issue with progress listeners that fails intermittently
 [browser_bug520538.js]
 [browser_bug521216.js]
 skip-if = e10s # Bug 918663 - DOMLinkAdded events don't make their way to chrome
 [browser_bug533232.js]
 [browser_bug537013.js]
-skip-if = e10s # Bug 918634 - swapFrameLoaders not implemented for e10s (test calls replaceTabWithWindow)
+skip-if = buildapp == 'mulet' || e10s # Bug 918634 - swapFrameLoaders not implemented for e10s (test calls replaceTabWithWindow)
 [browser_bug537474.js]
 skip-if = e10s # Bug ?????? - test doesn't wait for document to be created before it checks it
 [browser_bug550565.js]
 skip-if = e10s # Bug 918663 - DOMLinkAdded events don't make their way to chrome (which is how gBrowser.getIcon works)
 [browser_bug553455.js]
-skip-if = e10s # Bug ????? - I don't think either popup notifications nor addon install stuff works?
+skip-if = buildapp == 'mulet' || e10s # Bug ????? - I don't think either popup notifications nor addon install stuff works?
 [browser_bug555224.js]
 skip-if = e10s # Bug 691614 - no e10s zoom support yet
 [browser_bug555767.js]
 skip-if = e10s # Bug 916974 - Session history doesn't work in e10s
 [browser_bug556061.js]
 skip-if = e10s # Bug 932651 - getClipboardData in specialpowersAPI.js not e10s friendly
 [browser_bug559991.js]
 skip-if = e10s # Bug 691614 - no e10s zoom support yet
@@ -228,21 +228,21 @@ skip-if = e10s # Bug 516755 - SessionSto
 [browser_bug623155.js]
 skip-if = e10s # Bug ?????? - URLBar issues (apparently issues with redirection)
 [browser_bug623893.js]
 skip-if = e10s # Bug 916974 - Session history doesn't work in e10s
 [browser_bug624734.js]
 [browser_bug633691.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content (eg, var expertDiv = gBrowser.contentDocument.getElementById("expertContent");)
 [browser_bug647886.js]
-skip-if = e10s # Bug 916974 - Session history doesn't work in e10s
+skip-if = buildapp == 'mulet' || e10s # Bug 916974 - Session history doesn't work in e10s
 [browser_bug655584.js]
 [browser_bug664672.js]
 [browser_bug676619.js]
-skip-if = os == "mac" || e10s # mac: Intermittent failures, bug 925225; e10s: Bug ?????? - test directly manipulates content (event.target.location)
+skip-if = buildapp == 'mulet' || os == "mac" || e10s # mac: Intermittent failures, bug 925225; e10s: Bug ?????? - test directly manipulates content (event.target.location)
 [browser_bug678392.js]
 skip-if = e10s # Bug ?????? - Obscure non-windows failures ("Snapshot array has correct length of 1 after loading one page. - Got 0, expected 1" and more)
 [browser_bug710878.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content (doc.querySelector)
 [browser_bug719271.js]
 skip-if = e10s # Bug 691614 - no e10s zoom support yet
 [browser_bug724239.js]
 [browser_bug734076.js]
@@ -264,48 +264,49 @@ skip-if = e10s # Bug 916974 - Session hi
 skip-if = e10s # Bug 921959 - reload with LOAD_FLAGS_ALLOW_MIXED_CONTENT fails in e10s
 [browser_bug832435.js]
 [browser_bug839103.js]
 [browser_bug880101.js]
 [browser_bug882977.js]
 [browser_bug902156.js]
 skip-if = e10s # Bug 921959 - reload with LOAD_FLAGS_ALLOW_MIXED_CONTENT fails in e10s
 [browser_bug906190.js]
-skip-if = e10s # Bug ?????? - test directly manipulates content (strange - gets an element from a child which it tries to treat as a string, but that fails)
+skip-if = buildapp == "mulet" || e10s # Bug ?????? - test directly manipulates content (strange - gets an element from a child which it tries to treat as a string, but that fails)
 [browser_bug970746.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content (directly gets elements from the content)
 [browser_canonizeURL.js]
 skip-if = e10s # Bug ?????? - [JavaScript Error: "Error in AboutHome.sendAboutHomeData TypeError: target.messageManager is undefined" {file: "resource:///modules/AboutHome.jsm" line: 208}]
 [browser_contentAreaClick.js]
 [browser_contextSearchTabPosition.js]
 skip-if = os == "mac" # bug 967013, bug 926729
 [browser_ctrlTab.js]
 skip-if = e10s # Bug ????? - thumbnail captures need e10s love (tabPreviews_capture fails with Argument 1 of CanvasRenderingContext2D.drawWindow does not implement interface Window.)
 [browser_customize_popupNotification.js]
 [browser_datareporting_notification.js]
 run-if = datareporting
 [browser_devices_get_user_media.js]
-skip-if = (os == "linux" && debug) || e10s # linux: bug 976544; e10s: Bug 973001 - appears user media notifications only happen in the child and don't make their way to the parent?
+skip-if = buildapp == 'mulet' || (os == "linux" && debug) || e10s # linux: bug 976544; e10s: Bug 973001 - appears user media notifications only happen in the child and don't make their way to the parent?
 [browser_devices_get_user_media_about_urls.js]
 skip-if = e10s # Bug 973001 - appears user media notifications only happen in the child and don't make their way to the parent?
 [browser_discovery.js]
 skip-if = e10s # Bug 918663 - DOMLinkAdded events don't make their way to chrome
 [browser_duplicateIDs.js]
 [browser_drag.js]
 skip-if = true # browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638.
 [browser_favicon_change.js]
 [browser_findbarClose.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content (tries to grab an iframe directly from content)
 [browser_fullscreen-window-open.js]
-skip-if = e10s || os == "linux" # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly. Linux: Intermittent failures - bug 941575.
+skip-if = buildapp == 'mulet' || e10s || os == "linux" # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly. Linux: Intermittent failures - bug 941575.
 [browser_gestureSupport.js]
 skip-if = e10s # Bug 863514 - no gesture support.
 [browser_getshortcutoruri.js]
 [browser_hide_removing.js]
 [browser_homeDrop.js]
+skip-if = buildapp == 'mulet'
 [browser_identity_UI.js]
 skip-if = e10s # Bug ?????? - this test fails for obscure reasons on non-windows builds only.
 [browser_keywordBookmarklets.js]
 skip-if = e10s # Bug ?????? - this test fails for obscure reasons on non-windows builds only.
 [browser_keywordSearch.js]
 skip-if = e10s # Bug 921957 - remote webprogress doesn't supply originalURI attribute on the request object
 [browser_keywordSearch_postData.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content (gBrowser.contentDocument.body.textContent)
@@ -318,84 +319,91 @@ skip-if = os == "linux" || e10s # Linux:
 skip-if = os != "win" || e10s # The Fitts Law menu button is only supported on Windows (bug 969376); # Bug ?????? - URL bar issues ("There should be no focused element - Got [object XULElement], expected null")
 [browser_middleMouse_noJSPaste.js]
 skip-if = e10s # Bug 921952 - Content:Click event issues
 [browser_minimize.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content (TypeError: gBrowser.docShell is null)
 [browser_mixedcontent_securityflags.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content ("cannot ipc non-cpow object")
 [browser_notification_tab_switching.js]
-skip-if = e10s # Bug ?????? - uncaught exception - Error: cannot ipc non-cpow object at chrome://mochitests/content/browser/browser/base/content/test/general/browser_notification_tab_switching.js:32
+skip-if = buildapp == 'mulet' || e10s # Bug ?????? - uncaught exception - Error: cannot ipc non-cpow object at chrome://mochitests/content/browser/browser/base/content/test/general/browser_notification_tab_switching.js:32
 [browser_offlineQuotaNotification.js]
-skip-if = e10s # Bug ?????? - test directly manipulates content (gBrowser.selectedBrowser.contentWindow.applicationCache.oncached = function() {...})
+skip-if = buildapp == 'mulet' || e10s # Bug ?????? - test directly manipulates content (gBrowser.selectedBrowser.contentWindow.applicationCache.oncached = function() {...})
 [browser_overflowScroll.js]
 skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
 [browser_pageInfo.js]
-skip-if = e10s # Bug 866413 - PageInfo doesn't work in e10s
+skip-if = buildapp == 'mulet' || e10s # Bug 866413 - PageInfo doesn't work in e10s
 [browser_page_style_menu.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content
 
 [browser_parsable_css.js]
 
 [browser_pinnedTabs.js]
 skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
 [browser_plainTextLinks.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content (creates and fetches elements directly from content document)
 [browser_popupUI.js]
-skip-if = e10s # Bug ?????? - test directly manipulates content (tries to get a popup element directly from content)
+skip-if = buildapp == 'mulet' || e10s # Bug ?????? - test directly manipulates content (tries to get a popup element directly from content)
 [browser_printpreview.js]
-skip-if = e10s # Bug ?????? - timeout after logging "Error: Channel closing: too late to send/recv, messages will be lost"
+skip-if = buildapp == 'mulet' || e10s # Bug ?????? - timeout after logging "Error: Channel closing: too late to send/recv, messages will be lost"
 [browser_private_browsing_window.js]
+skip-if = buildapp == 'mulet'
 [browser_private_no_prompt.js]
+skip-if = buildapp == 'mulet'
 [browser_relatedTabs.js]
 [browser_removeTabsToTheEnd.js]
 skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
 [browser_removeUnsafeProtocolsFromURLBarPaste.js]
 [browser_sanitize-download-history.js]
 skip-if = true # bug 432425
 [browser_sanitize-passwordDisabledHosts.js]
 [browser_sanitize-sitepermissions.js]
 [browser_sanitize-timespans.js]
+skip-if = buildapp == 'mulet'
 [browser_sanitizeDialog.js]
+skip-if = buildapp == 'mulet'
 [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]
-skip-if = e10s # Bug ?????? - test directly manipulates content (event.target)
+skip-if = buildapp == 'mulet' || e10s # Bug ?????? - test directly manipulates content (event.target)
 [browser_save_private_link_perwindowpb.js]
-skip-if = e10s # e10s: Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly
+skip-if = buildapp == 'mulet' || e10s # e10s: Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly
 [browser_save_video.js]
-skip-if = e10s # Bug ?????? - test directly manipulates content (event.target)
+skip-if = buildapp == 'mulet' || e10s # Bug ?????? - test directly manipulates content (event.target)
 [browser_scope.js]
 [browser_selectTabAtIndex.js]
 skip-if = e10s # Bug ?????? - no idea! "Accel+9 selects expected tab - Got 0, expected 9"
 [browser_star_hsts.js]
 skip-if = e10s # Bug ?????? - timeout after logging "Error: Channel closing: too late to send/recv, messages will be lost"
 [browser_subframe_favicons_not_used.js]
 [browser_tabDrop.js]
+skip-if = buildapp == 'mulet'
 [browser_tabMatchesInAwesomebar_perwindowpb.js]
 skip-if = e10s # Bug 918634 - swapFrameLoaders not implemented for e10s (test uses gBrowser.swapBrowsersAndCloseOther)
 [browser_tab_drag_drop_perwindow.js]
+skip-if = buildapp == 'mulet'
 [browser_tab_dragdrop.js]
-skip-if = e10s # Bug 918634 - swapFrameLoaders not implemented for e10s (test uses gBrowser.swapBrowsersAndCloseOther)
+skip-if = buildapp == 'mulet' || e10s # Bug 918634 - swapFrameLoaders not implemented for e10s (test uses gBrowser.swapBrowsersAndCloseOther)
 [browser_tab_dragdrop2.js]
+skip-if = buildapp == 'mulet'
 [browser_tabbar_big_widgets.js]
 skip-if = os == "linux" || os == "mac" # No tabs in titlebar on linux
                                        # Disabled on OS X because of bug 967917
 [browser_tabfocus.js]
 skip-if = e10s # Bug 921935 - focusmanager issues with e10s (test calls getFocusedElementForWindow with a content window)
 [browser_tabkeynavigation.js]
 [browser_tabopen_reflows.js]
 skip-if = e10s # Bug ?????? - test needs to be updated for e10s (captures a stack that isn't correct in e10s)
 [browser_tabs_isActive.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content (tries to get/set attributes directly on content docshell)
 [browser_tabs_owner.js]
 [browser_typeAheadFind.js]
-skip-if = e10s # Bug 921935 - focusmanager issues with e10s (test calls waitForFocus)
+skip-if = buildapp == 'mulet' || e10s # Bug 921935 - focusmanager issues with e10s (test calls waitForFocus)
 [browser_unloaddialogs.js]
 skip-if = e10s # Bug ?????? - test uses chrome windowMediator to try and see alert() from content
 [browser_urlHighlight.js]
 [browser_urlbarAutoFillTrimURLs.js]
 [browser_urlbarCopying.js]
 skip-if = e10s # Bug 932651 - getClipboardData in specialpowersAPI.js not e10s friendly
 [browser_urlbarEnter.js]
 skip-if = e10s # Bug ?????? - obscure non-windows child process crashes on try
@@ -417,16 +425,17 @@ skip-if = e10s # Bug 921905 - pinTab/unp
 skip-if = true # Bug 1005420 - fails intermittently. also with e10s enabled: bizarre problem with hidden tab having _mouseenter called, via _setPositionalAttributes, and tab not being found resulting in 'candidate is undefined'
 [browser_visibleTabs_bookmarkAllTabs.js]
 skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
 [browser_visibleTabs_contextMenu.js]
 skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
 [browser_visibleTabs_tabPreview.js]
 skip-if = (os == "win" && !debug) || e10s # Bug 1007418 / Bug 698371 - thumbnail captures need e10s love (tabPreviews_capture fails with Argument 1 of CanvasRenderingContext2D.drawWindow does not implement interface Window.)
 [browser_windowopen_reflows.js]
+skip-if = buildapp == 'mulet'
 [browser_wyciwyg_urlbarCopying.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content (content.document.getElementById)
 [browser_zbug569342.js]
 skip-if = e10s # Bug 516755 - SessionStore disabled for e10s
 [browser_registerProtocolHandler_notification.js]
 skip-if = e10s # Bug 940206 - nsIWebContentHandlerRegistrar::registerProtocolHandler doesn't work in e10s
 [browser_no_mcb_on_http_site.js]
 skip-if = e10s # Bug 516755 - SessionStore disabled for e10s
--- a/browser/base/content/test/newtab/browser.ini
+++ b/browser/base/content/test/newtab/browser.ini
@@ -1,10 +1,10 @@
 [DEFAULT]
-skip-if = e10s # Bug ?????? - about:newtab tests don't work in e10s
+skip-if = buildapp == 'mulet' || e10s # Bug ?????? - about:newtab tests don't work in e10s
 support-files =
   head.js
 
 [browser_newtab_background_captures.js]
 [browser_newtab_block.js]
 [browser_newtab_bug721442.js]
 [browser_newtab_bug722273.js]
 [browser_newtab_bug723102.js]
@@ -18,16 +18,17 @@ skip-if = os == "mac" # Intermittent fai
 [browser_newtab_bug876313.js]
 [browser_newtab_bug991111.js]
 [browser_newtab_bug991210.js]
 [browser_newtab_bug998387.js]
 [browser_newtab_disable.js]
 [browser_newtab_drag_drop.js]
 [browser_newtab_drag_drop_ext.js]
 [browser_newtab_drop_preview.js]
+[browser_newtab_enhanced.js]
 [browser_newtab_focus.js]
 [browser_newtab_perwindow_private_browsing.js]
 [browser_newtab_reportLinkAction.js]
 [browser_newtab_reset.js]
 [browser_newtab_search.js]
 support-files =
   searchEngineNoLogo.xml
   searchEngine1xLogo.xml
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/newtab/browser_newtab_enhanced.js
@@ -0,0 +1,55 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const PRELOAD_PREF = "browser.newtab.preload";
+
+gDirectorySource = "data:application/json," + JSON.stringify({
+  "en-US": [{
+    url: "http://example.com/",
+    enhancedImageURI: "data:image/png;base64,helloWORLD",
+    type: "organic"
+  }]
+});
+
+function runTests() {
+  let origEnhanced = NewTabUtils.allPages.enhanced;
+  registerCleanupFunction(() => {
+    Services.prefs.clearUserPref(PRELOAD_PREF);
+    NewTabUtils.allPages.enhanced = origEnhanced;
+  });
+
+  Services.prefs.setBoolPref(PRELOAD_PREF, false);
+
+  function getData(cellNum) {
+    let siteNode = getCell(cellNum).site.node;
+    return {
+      type: siteNode.getAttribute("type"),
+      enhanced: siteNode.querySelector(".enhanced-content").style.backgroundImage,
+    };
+  }
+
+  // Make the page have a directory link followed by a history link
+  yield setLinks("1");
+
+  // Test with enhanced = false
+  NewTabUtils.allPages.enhanced = false;
+  yield addNewTabPageTab();
+  let {type, enhanced} = getData(0);
+  is(type, "organic", "directory link is organic");
+  isnot(enhanced, "", "directory link has enhanced image");
+
+  let {type, enhanced} = getData(1);
+  is(type, "history", "history link is history");
+  is(enhanced, "", "history link has no enhanced image");
+
+  // Test with enhanced = true
+  NewTabUtils.allPages.enhanced = true;
+  yield addNewTabPageTab();
+  let {type, enhanced} = getData(0);
+  is(type, "organic", "directory link is still organic");
+  isnot(enhanced, "", "directory link still has enhanced image");
+
+  let {type, enhanced} = getData(1);
+  is(type, "enhanced", "history link now is enhanced");
+  isnot(enhanced, "", "history link now has enhanced image");
+}
--- a/browser/base/content/test/newtab/head.js
+++ b/browser/base/content/test/newtab/head.js
@@ -603,16 +603,17 @@ function createDragEvent(aEventType, aDa
  * Resumes testing when all pages have been updated.
  * @param aCallback Called when done. If not specified, TestRunner.next is used.
  * @param aOnlyIfHidden If true, this resumes testing only when an update that
  *                      applies to pre-loaded, hidden pages is observed.  If
  *                      false, this resumes testing when any update is observed.
  */
 function whenPagesUpdated(aCallback, aOnlyIfHidden=false) {
   let page = {
+    observe: _ => _,
     update: function (onlyIfHidden=false) {
       if (onlyIfHidden == aOnlyIfHidden) {
         NewTabUtils.allPages.unregister(this);
         executeSoon(aCallback || TestRunner.next);
       }
     }
   };
 
--- a/browser/base/content/test/plugins/browser.ini
+++ b/browser/base/content/test/plugins/browser.ini
@@ -1,16 +1,16 @@
 [DEFAULT]
 # These tests all fail with e10s enabled.
 # * Bug 899347 - no e10s click-to-play support
 # * Bug 921916 - no plugin events
 # * Bug XXXXX - no plugins in content processes ("Error: You cannot use the AddonManager in child processes!")
 # * Bug 866413 - PageInfo doesn't work in e10s [browser_pageInfo_plugins.js]
 # * Bug 921957 - remote webprogress doesn't supply originalURI attribute on the request object [browser_clearplugindata.js]
-skip-if = e10s
+skip-if = buildapp == "mulet" || e10s
 support-files =
   blockNoPlugins.xml
   blockPluginHard.xml
   blockPluginVulnerableNoUpdate.xml
   blockPluginVulnerableUpdatable.xml
   browser_clearplugindata.html
   browser_clearplugindata_noage.html
   head.js
--- a/browser/base/content/test/social/browser.ini
+++ b/browser/base/content/test/social/browser.ini
@@ -1,10 +1,10 @@
 [DEFAULT]
-skip-if = e10s # Bug 915547 (social providers don't install)
+skip-if = buildapp == "mulet" || e10s # Bug 915547 (social providers don't install)
 support-files =
   blocklist.xml
   checked.jpg
   head.js
   opengraph/og_invalid_url.html
   opengraph/opengraph.html
   opengraph/shortlink_linkrel.html
   opengraph/shorturl_link.html
--- a/browser/components/customizableui/test/browser.ini
+++ b/browser/components/customizableui/test/browser.ini
@@ -1,9 +1,10 @@
 [DEFAULT]
+skip-if = buildapp == "mulet"
 support-files =
   head.js
   support/test_967000_charEncoding_page.html
   support/feeds_test_page.html
   support/test-feed.xml
 
 [browser_873501_handle_specials.js]
 [browser_876926_customize_mode_wrapping.js]
@@ -70,17 +71,17 @@ skip-if = e10s # Bug ?????? - test uses 
 [browser_952963_areaType_getter_no_area.js]
 [browser_956602_remove_special_widget.js]
 [browser_962069_drag_to_overflow_chevron.js]
 [browser_962884_opt_in_disable_hyphens.js]
 [browser_963639_customizing_attribute_non_customizable_toolbar.js]
 [browser_967000_button_charEncoding.js]
 skip-if = e10s # Bug ?????? - test uses promiseTabLoadEvent() which isn't e10s friendly.
 [browser_967000_button_feeds.js]
-skip-if = e10s # Bug ?????? - test uses promiseTabLoadEvent() which isn't e10s friendly.
+skip-if = buildapp == 'mulet' || e10s # Bug ?????? - test uses promiseTabLoadEvent() which isn't e10s friendly.
 [browser_967000_button_sync.js]
 skip-if = e10s # Bug ?????? - test uses promiseTabLoadEvent() which isn't e10s friendly.
 [browser_967000_button_tabView.js]
 [browser_968447_bookmarks_toolbar_items_in_panel.js]
 skip-if = os == "linux" # Intemittent failures - bug 979207
 [browser_968565_insert_before_hidden_items.js]
 [browser_969427_recreate_destroyed_widget_after_reset.js]
 [browser_969661_character_encoding_navbar_disabled.js]
--- a/browser/components/downloads/test/browser/browser.ini
+++ b/browser/components/downloads/test/browser/browser.ini
@@ -1,8 +1,9 @@
 [DEFAULT]
 support-files = head.js
 
 [browser_basic_functionality.js]
+skip-if = buildapp == "mulet"
 [browser_first_download_panel.js]
 skip-if = os == "linux" # Bug 949434
 [browser_overflow_anchor.js]
 skip-if = os == "linux" # Bug 952422
--- a/browser/components/feeds/test/chrome/chrome.ini
+++ b/browser/components/feeds/test/chrome/chrome.ini
@@ -1,7 +1,8 @@
 [DEFAULT]
 support-files = sample_feed.atom
 
 [test_423060.xul]
 [test_bug368464.html]
 [test_bug408328.html]
+skip-if= buildapp == 'mulet'
 [test_maxSniffing.html]
--- a/browser/components/feeds/test/mochitest.ini
+++ b/browser/components/feeds/test/mochitest.ini
@@ -1,10 +1,10 @@
 [DEFAULT]
-skip-if = buildapp == 'b2g' || e10s
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || e10s
 support-files =
   bug368464-data.xml
   bug408328-data.xml
   bug436801-data.xml
   bug494328-data.xml
   bug589543-data.xml
   valid-feed.xml
   valid-unsniffable-feed.xml
--- a/browser/components/loop/test/mochitest/browser.ini
+++ b/browser/components/loop/test/mochitest/browser.ini
@@ -1,6 +1,7 @@
 [DEFAULT]
 support-files =
     head.js
 
 [browser_mozLoop_charPref.js]
 [browser_mozLoop_doNotDisturb.js]
+skip-if = buildapp == 'mulet'
--- a/browser/components/places/tests/browser/browser.ini
+++ b/browser/components/places/tests/browser/browser.ini
@@ -1,13 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 [DEFAULT]
+skip-if = buildapp == "mulet"
 support-files =
   head.js
   framedPage.html
   frameLeft.html
   frameRight.html
   sidebarpanels_click_test_page.html
 
 [browser_0_library_left_pane_migration.js]
--- a/browser/components/preferences/in-content/advanced.xul
+++ b/browser/components/preferences/in-content/advanced.xul
@@ -130,17 +130,16 @@
   <stringbundle id="bundleBrand" src="chrome://branding/locale/brand.properties"/>
 #endif
   <stringbundle id="bundlePreferences" src="chrome://browser/locale/preferences/preferences.properties"/>
 
 <hbox id="header-advanced"
       class="header"
       hidden="true"
       data-category="paneAdvanced">
-  <image class="header-icon"/>
   <label class="header-name">&paneAdvanced.title;</label>
 </hbox>
 
 <tabbox id="advancedPrefs"
         handleCtrlTab="false"
         handleCtrlPageUpDown="false"
         flex="1"
         data-category="paneAdvanced"
--- a/browser/components/preferences/in-content/applications.xul
+++ b/browser/components/preferences/in-content/applications.xul
@@ -56,17 +56,16 @@
   <key key="&focusSearch1.key;" modifiers="accel" oncommand="gApplicationsPane.focusFilterBox();"/>
   <key key="&focusSearch2.key;" modifiers="accel" oncommand="gApplicationsPane.focusFilterBox();"/>
 </keyset>
 
 <hbox id="header-application"
       class="header"
       hidden="true"
       data-category="paneApplications">
-  <image class="header-icon"/>
   <label class="header-name">&paneApplications.title;</label>
 </hbox>
 
 <vbox id="applicationsContent"
       data-category="paneApplications"
       hidden="true"
       flex="1">
   <hbox>
--- a/browser/components/preferences/in-content/content.xul
+++ b/browser/components/preferences/in-content/content.xul
@@ -27,17 +27,16 @@
         src="chrome://mozapps/content/preferences/fontbuilder.js"/>
 <script type="application/javascript" 
         src="chrome://browser/content/preferences/in-content/content.js"/>
 
 <hbox id="header-content"
       class="header"
       hidden="true"
       data-category="paneContent">
-  <image class="header-icon"/>
   <label class="header-name">&paneContent.title;</label>
 </hbox>
 
 <groupbox id="miscGroup" data-category="paneContent" hidden="true">
   <caption><label>&popups.label;</label></caption>
 
   <grid id="contentGrid">
     <columns>
--- a/browser/components/preferences/in-content/main.xul
+++ b/browser/components/preferences/in-content/main.xul
@@ -86,17 +86,16 @@
                 type="bool"/>
 #endif
 </preferences>
 
 <hbox id="header-general"
       class="header"
       hidden="true"
       data-category="paneGeneral">
-  <image class="header-icon"/>
   <label class="header-name">&paneGeneral.title;</label>
 </hbox>
 
 <!-- Startup -->
 <groupbox id="startupGroup"
           data-category="paneGeneral"
           hidden="true">
   <caption><label>&startup.label;</label></caption>
--- a/browser/components/preferences/in-content/privacy.xul
+++ b/browser/components/preferences/in-content/privacy.xul
@@ -66,17 +66,16 @@
               type="bool"/>
 
 </preferences>
 
 <hbox id="header-privacy"
       class="header"
       hidden="true"
       data-category="panePrivacy">
-  <image class="header-icon"/>
   <label class="header-name">&panePrivacy.title;</label>
 </hbox>
 
 <!-- Tracking -->
 <groupbox id="trackingGroup" data-category="panePrivacy" hidden="true" align="start">
   <caption><label>&tracking.label;</label></caption>
   <radiogroup id="doNotTrackSelection" orient="vertical" align="start"
               preference="privacy.donottrackheader.value"
--- a/browser/components/preferences/in-content/security.xul
+++ b/browser/components/preferences/in-content/security.xul
@@ -31,17 +31,16 @@
   <preference id="signon.rememberSignons" name="signon.rememberSignons" type="bool"/>
 
 </preferences>
 
 <hbox id="header-security"
       class="header"
       hidden="true"
       data-category="paneSecurity">
-  <image class="header-icon"/>
   <label class="header-name">&paneSecurity.title;</label>
 </hbox>
 
 <!-- addons, forgery (phishing) UI -->
 <groupbox id="addonsPhishingGroup" data-category="paneSecurity" hidden="true">
   <caption><label>&general.label;</label></caption>
 
   <hbox id="addonInstallBox">
--- a/browser/components/preferences/in-content/sync.xul
+++ b/browser/components/preferences/in-content/sync.xul
@@ -29,17 +29,16 @@
         src="chrome://browser/content/preferences/in-content/sync.js"/>
 <script type="application/javascript"
         src="chrome://browser/content/sync/utils.js"/>
 
 <hbox id="header-sync"
       class="header"
       hidden="true"
       data-category="paneSync">
-  <image class="header-icon"/>
   <label class="header-name">&paneSync.title;</label>
 </hbox>
 
 <deck id="weavePrefsDeck" data-category="paneSync" hidden="true">
   <!-- These panels are for the "legacy" sync provider -->
   <vbox id="noAccount" align="center">
     <spacer flex="1"/>
     <description id="syncDesc">
--- a/browser/components/preferences/in-content/tests/browser.ini
+++ b/browser/components/preferences/in-content/tests/browser.ini
@@ -1,9 +1,10 @@
 [DEFAULT]
+skip-if = buildapp == "mulet"
 support-files =
   head.js
   privacypane_tests_perwindow.js
 
 [browser_advanced_update.js]
 [browser_bug410900.js]
 [browser_bug731866.js]
 [browser_bug1020245_openPreferences_to_paneContent.js]
--- a/browser/components/preferences/tests/browser.ini
+++ b/browser/components/preferences/tests/browser.ini
@@ -1,9 +1,10 @@
 [DEFAULT]
+skip-if = buildapp == "mulet"
 support-files =
   head.js
   privacypane_tests_perwindow.js
 
 [browser_advanced_update.js]
 [browser_bug410900.js]
 [browser_bug705422.js]
 skip-if = e10s # Bug 941459 - pushPrefEnv, popPrefEnv in specialPowersAPI.js not e10s friendly
--- a/browser/components/privatebrowsing/test/browser/browser.ini
+++ b/browser/components/privatebrowsing/test/browser/browser.ini
@@ -1,9 +1,10 @@
 [DEFAULT]
+skip-if = buildapp == "mulet"
 support-files =
   browser_privatebrowsing_concurrent_page.html
   browser_privatebrowsing_cookieacceptdialog.html
   browser_privatebrowsing_geoprompt_page.html
   browser_privatebrowsing_localStorage_before_after_page.html
   browser_privatebrowsing_localStorage_before_after_page2.html
   browser_privatebrowsing_localStorage_page1.html
   browser_privatebrowsing_localStorage_page2.html
--- a/browser/components/search/test/browser.ini
+++ b/browser/components/search/test/browser.ini
@@ -1,9 +1,10 @@
 [DEFAULT]
+skip-if = buildapp == 'mulet'
 support-files =
   426329.xml
   483086-1.xml
   483086-2.xml
   head.js
   test.html
   testEngine.src
   testEngine.xml
--- a/browser/components/sessionstore/test/browser.ini
+++ b/browser/components/sessionstore/test/browser.ini
@@ -63,16 +63,17 @@ support-files =
 [browser_backup_recovery.js]
 [browser_broadcast.js]
 [browser_capabilities.js]
 [browser_cleaner.js]
 [browser_dying_cache.js]
 [browser_dynamic_frames.js]
 [browser_form_restore_events.js]
 [browser_formdata.js]
+skip-if = buildapp == 'mulet'
 [browser_formdata_format.js]
 [browser_formdata_xpath.js]
 [browser_frametree.js]
 [browser_frame_history.js]
 [browser_global_store.js]
 [browser_history_cap.js]
 [browser_label_and_icon.js]
 [browser_merge_closed_tabs.js]
--- a/browser/components/tabview/test/browser.ini
+++ b/browser/components/tabview/test/browser.ini
@@ -11,16 +11,17 @@ support-files =
   test_bug678374_icon16.png
 
 [browser_tabview_alltabs.js]
 [browser_tabview_apptabs.js]
 [browser_tabview_bug580412.js]
 [browser_tabview_bug586553.js]
 [browser_tabview_bug587043.js]
 [browser_tabview_bug587231.js]
+skip-if = buildapp == 'mulet'
 [browser_tabview_bug587276.js]
 [browser_tabview_bug587351.js]
 [browser_tabview_bug587503.js]
 [browser_tabview_bug587990.js]
 [browser_tabview_bug588265.js]
 [browser_tabview_bug589324.js]
 [browser_tabview_bug590606.js]
 [browser_tabview_bug591706.js]
@@ -64,34 +65,37 @@ skip-if = os == 'linux' # Bug 947521
 skip-if = true # Bug 736036
 [browser_tabview_bug612470.js]
 [browser_tabview_bug613541.js]
 skip-if = os == "win" # Bug 951477
 [browser_tabview_bug616729.js]
 [browser_tabview_bug616967.js]
 [browser_tabview_bug618816.js]
 [browser_tabview_bug618828.js]
+skip-if = buildapp == 'mulet'
 [browser_tabview_bug619937.js]
 [browser_tabview_bug622835.js]
 [browser_tabview_bug623768.js]
 [browser_tabview_bug624265_perwindowpb.js]
 skip-if = true # Bug 921984, hopefully fixed by bug 930202
 [browser_tabview_bug624692.js]
 [browser_tabview_bug624727_perwindowpb.js]
+skip-if = buildapp == 'mulet'
 [browser_tabview_bug624847.js]
 [browser_tabview_bug624931.js]
 [browser_tabview_bug624953.js]
 [browser_tabview_bug625195.js]
 [browser_tabview_bug625269.js]
 [browser_tabview_bug625424.js]
 [browser_tabview_bug625955.js]
 [browser_tabview_bug626368.js]
 [browser_tabview_bug626455.js]
 [browser_tabview_bug626525.js]
 [browser_tabview_bug626791.js]
+skip-if = buildapp == 'mulet'
 [browser_tabview_bug627736.js]
 [browser_tabview_bug628061.js]
 [browser_tabview_bug628165.js]
 [browser_tabview_bug628270.js]
 [browser_tabview_bug628887.js]
 [browser_tabview_bug629189.js]
 [browser_tabview_bug629195.js]
 skip-if = os == 'linux'&&debug # bug 981703
@@ -102,16 +106,17 @@ skip-if = true # Bug 922422
 skip-if = true # Bug 922422
 [browser_tabview_bug631752.js]
 [browser_tabview_bug633788.js]
 [browser_tabview_bug634077.js]
 [browser_tabview_bug634085.js]
 [browser_tabview_bug634672.js]
 [browser_tabview_bug635696.js]
 [browser_tabview_bug637840.js]
+skip-if = buildapp == 'mulet'
 [browser_tabview_bug640765.js]
 [browser_tabview_bug641802.js]
 [browser_tabview_bug642793.js]
 [browser_tabview_bug643392.js]
 [browser_tabview_bug644097.js]
 [browser_tabview_bug648882.js]
 skip-if = true # Bug 752862
 [browser_tabview_bug649006.js]
@@ -128,32 +133,34 @@ skip-if = true # Bug 754222
 [browser_tabview_bug656778.js]
 skip-if = os == "mac" # Bug 946918
 [browser_tabview_bug656913.js]
 [browser_tabview_bug659594.js]
 skip-if = os == "mac" || e10s # mac: Bug 939617; e10s - Bug ?????? - "leaked until shutdown [nsGlobalWindow #82 about:blank]"
 [browser_tabview_bug662266.js]
 [browser_tabview_bug663421.js]
 [browser_tabview_bug665502.js]
+skip-if = buildapp == 'mulet'
 [browser_tabview_bug669694.js]
 [browser_tabview_bug673196.js]
 [browser_tabview_bug673729.js]
 skip-if = true # Bug 749980
 [browser_tabview_bug678374.js]
 skip-if = true # Bug 795265
 [browser_tabview_bug681599.js]
 [browser_tabview_bug685476.js]
 [browser_tabview_bug685692.js]
 [browser_tabview_bug686654.js]
 [browser_tabview_bug696602.js]
 skip-if = true # Bug 736425
 [browser_tabview_bug697390.js]
 [browser_tabview_bug705621.js]
 [browser_tabview_bug706430.js]
 [browser_tabview_bug706736.js]
+skip-if = buildapp == 'mulet'
 [browser_tabview_bug707466.js]
 [browser_tabview_bug712203.js]
 [browser_tabview_bug715454.js]
 [browser_tabview_bug716880.js]
 [browser_tabview_bug728887.js]
 [browser_tabview_bug733115.js]
 [browser_tabview_bug749658.js]
 [browser_tabview_bug766597.js]
--- a/browser/devtools/commandline/test/browser.ini
+++ b/browser/devtools/commandline/test/browser.ini
@@ -2,16 +2,17 @@
 skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
 subsuite = devtools
 support-files =
   head.js
   helpers.js
   mockCommands.js
 
 [browser_cmd_addon.js]
+skip-if = buildapp == 'mulet'
 [browser_cmd_calllog.js]
 skip-if = true || e10s # Bug 845831
 [browser_cmd_calllog_chrome.js]
 skip-if = true || e10s # Bug 845831
 [browser_cmd_appcache_invalid.js]
 support-files =
   browser_cmd_appcache_invalid_appcache.appcache
   browser_cmd_appcache_invalid_appcache.appcache^headers^
--- a/browser/devtools/debugger/test/browser.ini
+++ b/browser/devtools/debugger/test/browser.ini
@@ -283,16 +283,17 @@ skip-if = (os == 'mac' || os == 'win') &
 [browser_dbg_variables-view-filter-05.js]
 [browser_dbg_variables-view-filter-pref.js]
 [browser_dbg_variables-view-filter-searchbox.js]
 [browser_dbg_variables-view-frame-parameters-01.js]
 [browser_dbg_variables-view-frame-parameters-02.js]
 [browser_dbg_variables-view-frame-parameters-03.js]
 [browser_dbg_variables-view-frame-with.js]
 [browser_dbg_variables-view-frozen-sealed-nonext.js]
+skip-if = buildapp == 'mulet'
 [browser_dbg_variables-view-hide-non-enums.js]
 [browser_dbg_variables-view-large-array-buffer.js]
 [browser_dbg_variables-view-override-01.js]
 [browser_dbg_variables-view-override-02.js]
 [browser_dbg_variables-view-popup-01.js]
 [browser_dbg_variables-view-popup-02.js]
 [browser_dbg_variables-view-popup-03.js]
 [browser_dbg_variables-view-popup-04.js]
--- a/browser/devtools/netmonitor/netmonitor-view.js
+++ b/browser/devtools/netmonitor/netmonitor-view.js
@@ -2282,17 +2282,17 @@ NetworkDetailsView.prototype = {
       let cookieVar = cookiesScope.addItem(cookie.name, {}, true);
       let cookieValue = yield gNetwork.getString(cookie.value);
       cookieVar.setGrip(cookieValue);
 
       // By default the cookie name and value are shown. If this is the only
       // information available, then nothing else is to be displayed.
       let cookieProps = Object.keys(cookie);
       if (cookieProps.length == 2) {
-        return;
+        continue;
       }
 
       // Display any other information other than the cookie name and value
       // which may be available.
       let rawObject = Object.create(null);
       let otherProps = cookieProps.filter(e => e != "name" && e != "value");
       for (let prop of otherProps) {
         rawObject[prop] = cookie[prop];
--- a/browser/devtools/netmonitor/test/browser.ini
+++ b/browser/devtools/netmonitor/test/browser.ini
@@ -34,16 +34,17 @@ support-files =
 
 [browser_net_aaa_leaktest.js]
 [browser_net_accessibility-01.js]
 [browser_net_accessibility-02.js]
 [browser_net_autoscroll.js]
 [browser_net_charts-01.js]
 [browser_net_charts-02.js]
 [browser_net_charts-03.js]
+skip-if= buildapp == 'mulet'
 [browser_net_charts-04.js]
 [browser_net_charts-05.js]
 [browser_net_charts-06.js]
 [browser_net_charts-07.js]
 [browser_net_clear.js]
 [browser_net_complex-params.js]
 [browser_net_content-type.js]
 [browser_net_curl-utils.js]
--- a/browser/devtools/netmonitor/test/browser_net_simple-request-data.js
+++ b/browser/devtools/netmonitor/test/browser_net_simple-request-data.js
@@ -81,75 +81,75 @@ function test() {
       verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS);
     });
 
     aMonitor.panelWin.once(aMonitor.panelWin.EVENTS.RECEIVED_REQUEST_HEADERS, () => {
       let requestItem = RequestsMenu.getItemAtIndex(0);
 
       ok(requestItem.attachment.requestHeaders,
         "There should be a requestHeaders attachment available.");
-      is(requestItem.attachment.requestHeaders.headers.length, 8,
+      is(requestItem.attachment.requestHeaders.headers.length, 9,
         "The requestHeaders attachment has an incorrect |headers| property.");
       isnot(requestItem.attachment.requestHeaders.headersSize, 0,
         "The requestHeaders attachment has an incorrect |headersSize| property.");
       // Can't test for the exact request headers size because the value may
       // vary across platforms ("User-Agent" header differs).
 
       verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS);
     });
 
     aMonitor.panelWin.once(aMonitor.panelWin.EVENTS.RECEIVED_REQUEST_COOKIES, () => {
       let requestItem = RequestsMenu.getItemAtIndex(0);
 
       ok(requestItem.attachment.requestCookies,
         "There should be a requestCookies attachment available.");
-      is(requestItem.attachment.requestCookies.cookies.length, 0,
+      is(requestItem.attachment.requestCookies.cookies.length, 2,
         "The requestCookies attachment has an incorrect |cookies| property.");
 
       verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS);
     });
 
     aMonitor.panelWin.once(aMonitor.panelWin.EVENTS.RECEIVED_REQUEST_POST_DATA, () => {
       ok(false, "Trap listener: this request doesn't have any post data.")
     });
 
     aMonitor.panelWin.once(aMonitor.panelWin.EVENTS.RECEIVED_RESPONSE_HEADERS, () => {
       let requestItem = RequestsMenu.getItemAtIndex(0);
 
       ok(requestItem.attachment.responseHeaders,
         "There should be a responseHeaders attachment available.");
-      is(requestItem.attachment.responseHeaders.headers.length, 9,
+      is(requestItem.attachment.responseHeaders.headers.length, 10,
         "The responseHeaders attachment has an incorrect |headers| property.");
-      is(requestItem.attachment.responseHeaders.headersSize, 255,
+      is(requestItem.attachment.responseHeaders.headersSize, 330,
         "The responseHeaders attachment has an incorrect |headersSize| property.");
 
       verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS);
     });
 
     aMonitor.panelWin.once(aMonitor.panelWin.EVENTS.RECEIVED_RESPONSE_COOKIES, () => {
       let requestItem = RequestsMenu.getItemAtIndex(0);
 
       ok(requestItem.attachment.responseCookies,
         "There should be a responseCookies attachment available.");
-      is(requestItem.attachment.responseCookies.cookies.length, 0,
+      is(requestItem.attachment.responseCookies.cookies.length, 2,
         "The responseCookies attachment has an incorrect |cookies| property.");
 
       verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS);
     });
 
     aMonitor.panelWin.once(aMonitor.panelWin.EVENTS.STARTED_RECEIVING_RESPONSE, () => {
       let requestItem = RequestsMenu.getItemAtIndex(0);
 
       is(requestItem.attachment.httpVersion, "HTTP/1.1",
         "The httpVersion attachment has an incorrect value.");
       is(requestItem.attachment.status, "200",
         "The status attachment has an incorrect value.");
       is(requestItem.attachment.statusText, "Och Aye",
         "The statusText attachment has an incorrect value.");
-      is(requestItem.attachment.headersSize, 255,
+      is(requestItem.attachment.headersSize, 330,
         "The headersSize attachment has an incorrect value.");
 
       verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS, {
         status: "200",
         statusText: "Och Aye"
       });
     });
 
--- a/browser/devtools/netmonitor/test/browser_net_simple-request-details.js
+++ b/browser/devtools/netmonitor/test/browser_net_simple-request-details.js
@@ -30,17 +30,17 @@ function test() {
         "There should be a selected item in the requests menu.");
       is(RequestsMenu.selectedIndex, 0,
         "The first item should be selected in the requests menu.");
       is(NetMonitorView.detailsPaneHidden, false,
         "The details pane should not be hidden after toggle button was pressed.");
 
       yield waitFor(aMonitor.panelWin, TAB_UPDATED)
       testHeadersTab();
-      testCookiesTab();
+      yield testCookiesTab();
       testParamsTab();
       yield testResponseTab();
       testTimingsTab();
       yield teardown(aMonitor);
       finish();
     });
 
     function testHeadersTab() {
@@ -58,28 +58,28 @@ function test() {
         "GET", "The method summary value is incorrect.");
       is(tabpanel.querySelector("#headers-summary-status-circle").getAttribute("code"),
         "200", "The status summary code is incorrect.");
       is(tabpanel.querySelector("#headers-summary-status-value").getAttribute("value"),
         "200 Och Aye", "The status summary value is incorrect.");
 
       is(tabpanel.querySelectorAll(".variables-view-scope").length, 2,
         "There should be 2 header scopes displayed in this tabpanel.");
-      is(tabpanel.querySelectorAll(".variable-or-property").length, 17,
-        "There should be 17 header values displayed in this tabpanel.");
+      is(tabpanel.querySelectorAll(".variable-or-property").length, 19,
+        "There should be 19 header values displayed in this tabpanel.");
 
       is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 0,
         "The empty notice should not be displayed in this tabpanel.");
 
       let responseScope = tabpanel.querySelectorAll(".variables-view-scope")[0];
       let requestScope = tabpanel.querySelectorAll(".variables-view-scope")[1];
 
       is(responseScope.querySelector(".name").getAttribute("value"),
         L10N.getStr("responseHeaders") + " (" +
-        L10N.getFormatStr("networkMenu.sizeKB", L10N.numberWithDecimals(255/1024, 3)) + ")",
+        L10N.getFormatStr("networkMenu.sizeKB", L10N.numberWithDecimals(330/1024, 3)) + ")",
         "The response headers scope doesn't have the correct title.");
 
       ok(requestScope.querySelector(".name").getAttribute("value").contains(
         L10N.getStr("requestHeaders") + " (0"),
         "The request headers scope doesn't have the correct title.");
       // Can't test for full request headers title because the size may
       // vary across platforms ("User-Agent" header differs). We're pretty
       // sure it's smaller than 1 MB though, so it starts with a 0.
@@ -95,55 +95,57 @@ function test() {
       is(responseScope.querySelectorAll(".variables-view-variable .name")[2].getAttribute("value"),
         "Content-Length", "The third response header name was incorrect.");
       is(responseScope.querySelectorAll(".variables-view-variable .value")[2].getAttribute("value"),
         "\"12\"", "The third response header value was incorrect.");
       is(responseScope.querySelectorAll(".variables-view-variable .name")[3].getAttribute("value"),
         "Content-Type", "The fourth response header name was incorrect.");
       is(responseScope.querySelectorAll(".variables-view-variable .value")[3].getAttribute("value"),
         "\"text/plain; charset=utf-8\"", "The fourth response header value was incorrect.");
-      is(responseScope.querySelectorAll(".variables-view-variable .name")[8].getAttribute("value"),
+      is(responseScope.querySelectorAll(".variables-view-variable .name")[9].getAttribute("value"),
         "foo-bar", "The last response header name was incorrect.");
-      is(responseScope.querySelectorAll(".variables-view-variable .value")[8].getAttribute("value"),
+      is(responseScope.querySelectorAll(".variables-view-variable .value")[9].getAttribute("value"),
         "\"baz\"", "The last response header value was incorrect.");
 
       is(requestScope.querySelectorAll(".variables-view-variable .name")[0].getAttribute("value"),
         "Host", "The first request header name was incorrect.");
       is(requestScope.querySelectorAll(".variables-view-variable .value")[0].getAttribute("value"),
         "\"example.com\"", "The first request header value was incorrect.");
-      is(requestScope.querySelectorAll(".variables-view-variable .name")[5].getAttribute("value"),
+      is(requestScope.querySelectorAll(".variables-view-variable .name")[6].getAttribute("value"),
         "Connection", "The ante-penultimate request header name was incorrect.");
-      is(requestScope.querySelectorAll(".variables-view-variable .value")[5].getAttribute("value"),
+      is(requestScope.querySelectorAll(".variables-view-variable .value")[6].getAttribute("value"),
         "\"keep-alive\"", "The ante-penultimate request header value was incorrect.");
-      is(requestScope.querySelectorAll(".variables-view-variable .name")[6].getAttribute("value"),
+      is(requestScope.querySelectorAll(".variables-view-variable .name")[7].getAttribute("value"),
         "Pragma", "The penultimate request header name was incorrect.");
-      is(requestScope.querySelectorAll(".variables-view-variable .value")[6].getAttribute("value"),
+      is(requestScope.querySelectorAll(".variables-view-variable .value")[7].getAttribute("value"),
         "\"no-cache\"", "The penultimate request header value was incorrect.");
-      is(requestScope.querySelectorAll(".variables-view-variable .name")[7].getAttribute("value"),
+      is(requestScope.querySelectorAll(".variables-view-variable .name")[8].getAttribute("value"),
         "Cache-Control", "The last request header name was incorrect.");
-      is(requestScope.querySelectorAll(".variables-view-variable .value")[7].getAttribute("value"),
+      is(requestScope.querySelectorAll(".variables-view-variable .value")[8].getAttribute("value"),
         "\"no-cache\"", "The last request header value was incorrect.");
     }
 
     function testCookiesTab() {
       EventUtils.sendMouseEvent({ type: "mousedown" },
         document.querySelectorAll("#details-pane tab")[1]);
 
-      let tab = document.querySelectorAll("#details-pane tab")[1];
-      let tabpanel = document.querySelectorAll("#details-pane tabpanel")[1];
+      return Task.spawn(function*() {
+        yield waitFor(aMonitor.panelWin, TAB_UPDATED);
 
-      is(tab.getAttribute("selected"), "true",
-        "The cookies tab in the network details pane should be selected.");
+        let tab = document.querySelectorAll("#details-pane tab")[1];
+        let tabpanel = document.querySelectorAll("#details-pane tabpanel")[1];
 
-      is(tabpanel.querySelectorAll(".variables-view-scope").length, 0,
-        "There should be no cookie scopes displayed in this tabpanel.");
-      is(tabpanel.querySelectorAll(".variable-or-property").length, 0,
-        "There should be no cookie values displayed in this tabpanel.");
-      is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 1,
-        "The empty notice should be displayed in this tabpanel.");
+        is(tab.getAttribute("selected"), "true",
+          "The cookies tab in the network details pane should be selected.");
+
+        is(tabpanel.querySelectorAll(".variables-view-scope").length, 2,
+          "There should be 2 cookie scopes displayed in this tabpanel.");
+        is(tabpanel.querySelectorAll(".variable-or-property").length, 6,
+          "There should be 6 cookie values displayed in this tabpanel.");
+      });
     }
 
     function testParamsTab() {
       EventUtils.sendMouseEvent({ type: "mousedown" },
         document.querySelectorAll("#details-pane tab")[2]);
 
       let tab = document.querySelectorAll("#details-pane tab")[2];
       let tabpanel = document.querySelectorAll("#details-pane tabpanel")[2];
--- a/browser/devtools/netmonitor/test/sjs_simple-test-server.sjs
+++ b/browser/devtools/netmonitor/test/sjs_simple-test-server.sjs
@@ -3,12 +3,15 @@
 
 function handleRequest(request, response) {
   response.setStatusLine(request.httpVersion, 200, "Och Aye");
 
   response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
   response.setHeader("Pragma", "no-cache");
   response.setHeader("Expires", "0");
 
+  response.setHeader("Set-Cookie", "bob=true; Max-Age=10; HttpOnly", true);
+  response.setHeader("Set-Cookie", "tom=cool; Max-Age=10; HttpOnly", true);
+
   response.setHeader("Content-Type", "text/plain; charset=utf-8", false);
   response.setHeader("Foo-Bar", "baz", false);
   response.write("Hello world!");
 }
--- a/browser/devtools/projecteditor/lib/editors.js
+++ b/browser/devtools/projecteditor/lib/editors.js
@@ -163,23 +163,26 @@ var TextEditor = Class({
     this.editor = new Editor({
       mode: mode,
       lineNumbers: true,
       extraKeys: this.extraKeys,
       themeSwitching: false,
       autocomplete: true
     });
 
-    // Trigger editor specific events on `this`
+    // Trigger a few editor specific events on `this`.
     this.editor.on("change", (...args) => {
       this.emit("change", ...args);
     });
     this.editor.on("cursorActivity", (...args) => {
       this.emit("cursorActivity", ...args);
     });
+    this.editor.on("focus", (...args) => {
+      this.emit("focus", ...args);
+    });
 
     this.appended = this.editor.appendTo(this.elt);
   },
 
   /**
    * Clean up the editor.  This can have different meanings
    * depending on the type of editor.
    */
--- a/browser/devtools/projecteditor/lib/projecteditor.js
+++ b/browser/devtools/projecteditor/lib/projecteditor.js
@@ -381,18 +381,19 @@ var ProjectEditor = Class({
 
   /**
    * Open a resource in a particular shell.
    *
    * @param Resource resource
    *                 The file to be opened.
    */
   openResource: function(resource) {
-    this.shells.open(resource);
+    let shell = this.shells.open(resource);
     this.projectTree.selectResource(resource);
+    shell.editor.focus();
   },
 
   /**
    * When a node is selected in the tree, open its associated editor.
    *
    * @param Resource resource
    *                 The file that has been selected
    */
@@ -541,16 +542,20 @@ var ProjectEditor = Class({
    *               The new editor instance.
    */
   _onEditorCreated: function(editor) {
     this.pluginDispatch("onEditorCreated", editor);
     this._editorListenAndDispatch(editor, "change", "onEditorChange");
     this._editorListenAndDispatch(editor, "cursorActivity", "onEditorCursorActivity");
     this._editorListenAndDispatch(editor, "load", "onEditorLoad");
     this._editorListenAndDispatch(editor, "save", "onEditorSave");
+
+    editor.on("focus", () => {
+      this.projectTree.selectResource(this.resourceFor(editor));
+    });
   },
 
   /**
    * Dispatch an onEditorActivated event and finish setting up once the
    * editor is ready to use.
    *
    * @param Editor editor
    *               The editor instance, which is now appended in the document.
@@ -579,18 +584,16 @@ var ProjectEditor = Class({
    * Also emits the same handler name on `this`.
    *
    * @param string handler
    *               Which function name to call on plugins.
    * @param ...args args
    *                All remaining parameters are passed into the handler.
    */
   pluginDispatch: function(handler, ...args) {
-    // XXX: Memory leak when console.log an Editor here
-    // console.log("DISPATCHING EVENT TO PLUGIN", handler, args);
     emit(this, handler, ...args);
     this.plugins.forEach(plugin => {
       try {
         if (handler in plugin) plugin[handler](...args);
       } catch(ex) {
         console.error(ex);
       }
     })
@@ -603,18 +606,16 @@ var ProjectEditor = Class({
    * @param Editor editor
    *               Which editor to listen to
    * @param string event
    *               Which editor event to listen for
    * @param string handler
    *               Which plugin method to call
    */
   _editorListenAndDispatch: function(editor, event, handler) {
-    /// XXX: Uncommenting this line also causes memory leak.
-    // console.log("Binding listen and dispatch", editor);
     editor.on(event, (...args) => {
       this.pluginDispatch(handler, editor, this.resourceFor(editor), ...args);
     });
   },
 
   /**
    * Find a shell for a resource.
    *
--- a/browser/devtools/projecteditor/test/browser.ini
+++ b/browser/devtools/projecteditor/test/browser.ini
@@ -1,19 +1,23 @@
 [DEFAULT]
 subsuite = devtools
 support-files =
   head.js
   helper_homepage.html
   helper_edits.js
 
 [browser_projecteditor_app_options.js]
+skip-if = buildapp == 'mulet'
 [browser_projecteditor_delete_file.js]
+skip-if = buildapp == 'mulet'
 [browser_projecteditor_editing_01.js]
+skip-if = buildapp == 'mulet'
 [browser_projecteditor_editors_image.js]
 [browser_projecteditor_external_change.js]
 [browser_projecteditor_immediate_destroy.js]
 [browser_projecteditor_init.js]
 [browser_projecteditor_menubar_01.js]
 [browser_projecteditor_menubar_02.js]
 [browser_projecteditor_new_file.js]
 [browser_projecteditor_stores.js]
-[browser_projecteditor_tree_selection.js]
+[browser_projecteditor_tree_selection_01.js]
+[browser_projecteditor_tree_selection_02.js]
rename from browser/devtools/projecteditor/test/browser_projecteditor_tree_selection.js
rename to browser/devtools/projecteditor/test/browser_projecteditor_tree_selection_01.js
--- a/browser/devtools/projecteditor/test/browser_projecteditor_tree_selection.js
+++ b/browser/devtools/projecteditor/test/browser_projecteditor_tree_selection_01.js
@@ -54,16 +54,33 @@ function selectFileFirstLoad(projectedit
 function selectFileSubsequentLoad(projecteditor, resource) {
   ok (resource && resource.path, "A valid resource has been passed in for selection " + (resource && resource.path));
   projecteditor.projectTree.selectResource(resource);
 
   if (resource.isDir) {
     return;
   }
 
+  // Make sure text editors are focused immediately when selected.
+  let focusPromise = promise.resolve();
+  if (projecteditor.currentEditor.editor) {
+    focusPromise = onEditorFocus(projecteditor.currentEditor);
+  }
+
   // Only activated should fire the next time
   // (may add load() if we begin checking for changes from disk)
   let [editorActivated] = yield promise.all([
     onceEditorActivated(projecteditor)
   ]);
 
   is (editorActivated, projecteditor.currentEditor,  "Editor has been activated for " + resource.path);
+
+  yield focusPromise;
 }
+
+function onEditorFocus(editor) {
+  let def = promise.defer();
+  editor.on("focus", function focus() {
+    editor.off("focus", focus);
+    def.resolve();
+  });
+  return def.promise;
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/projecteditor/test/browser_projecteditor_tree_selection_02.js
@@ -0,0 +1,70 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that files get reselected in the tree when their editor
+// is focused.  https://bugzilla.mozilla.org/show_bug.cgi?id=1011116.
+
+let test = asyncTest(function*() {
+  let projecteditor = yield addProjectEditorTabForTempDirectory();
+  let TEMP_PATH = projecteditor.project.allPaths()[0];
+
+  is (getTempFile("").path, TEMP_PATH, "Temp path is set correctly.");
+
+  ok (projecteditor.currentEditor, "There is an editor for projecteditor");
+  let resources = projecteditor.project.allResources();
+
+  is (
+    resources.map(r=>r.basename).join("|"),
+    "ProjectEditor|css|styles.css|data|img|icons|128x128.png|16x16.png|32x32.png|vector.svg|fake.png|js|script.js|index.html|LICENSE|README.md",
+    "Resources came through in proper order"
+  );
+
+  for (let i = 0; i < resources.length; i++){
+    yield selectAndRefocusFile(projecteditor, resources[i]);
+  }
+});
+
+function selectAndRefocusFile(projecteditor, resource) {
+  ok (resource && resource.path, "A valid resource has been passed in for selection " + (resource && resource.path));
+  projecteditor.projectTree.selectResource(resource);
+
+  if (resource.isDir) {
+    return;
+  }
+
+  let [editorCreated, editorLoaded, editorActivated] = yield promise.all([
+    onceEditorCreated(projecteditor),
+    onceEditorLoad(projecteditor),
+    onceEditorActivated(projecteditor)
+  ]);
+
+  if (projecteditor.currentEditor.editor) {
+    // This is a text editor.  Go ahead and select a directory then refocus
+    // the editor to make sure it is reselected in tree.
+    let treeContainer = projecteditor.projectTree.getViewContainer(getDirectoryInStore(resource));
+    treeContainer.line.click();
+    EventUtils.synthesizeMouseAtCenter(treeContainer.elt, {}, treeContainer.elt.ownerDocument.defaultView);
+    let waitForTreeSelect = onTreeSelection(projecteditor);
+    projecteditor.currentEditor.focus();
+    yield waitForTreeSelect;
+
+    is (projecteditor.projectTree.getSelectedResource(), resource, "The resource gets reselected in the tree");
+  }
+}
+
+// Return a directory to select in the tree.
+function getDirectoryInStore(resource) {
+  return resource.store.root.childrenSorted.filter(r=>r.isDir)[0];
+}
+
+function onTreeSelection(projecteditor) {
+  let def = promise.defer();
+  projecteditor.projectTree.on("selection", function selection() {
+    projecteditor.projectTree.off("focus", selection);
+    def.resolve();
+  });
+  return def.promise;
+}
--- a/browser/devtools/scratchpad/test/browser.ini
+++ b/browser/devtools/scratchpad/test/browser.ini
@@ -3,16 +3,17 @@ skip-if = e10s # Bug ?????? - devtools t
 subsuite = devtools
 support-files = head.js
 
 [browser_scratchpad_autocomplete.js]
 [browser_scratchpad_browser_last_window_closing.js]
 [browser_scratchpad_reset_undo.js]
 [browser_scratchpad_display_outputs_errors.js]
 [browser_scratchpad_eval_func.js]
+skip-if = buildapp == 'mulet'
 [browser_scratchpad_goto_line_ui.js]
 [browser_scratchpad_reload_and_run.js]
 [browser_scratchpad_display_non_error_exceptions.js]
 [browser_scratchpad_modeline.js]
 [browser_scratchpad_chrome_context_pref.js]
 [browser_scratchpad_help_key.js]
 [browser_scratchpad_recent_files.js]
 # [browser_scratchpad_confirm_close.js]
--- a/browser/devtools/shared/test/browser.ini
+++ b/browser/devtools/shared/test/browser.ini
@@ -37,16 +37,17 @@ support-files =
 [browser_observableobject.js]
 [browser_outputparser.js]
 [browser_prefs.js]
 [browser_require_basic.js]
 [browser_spectrum.js]
 [browser_tableWidget_basic.js]
 [browser_tableWidget_keyboard_interaction.js]
 [browser_tableWidget_mouse_interaction.js]
+skip-if = buildapp == 'mulet'
 [browser_telemetry_button_paintflashing.js]
 [browser_telemetry_button_responsive.js]
 [browser_telemetry_button_scratchpad.js]
 [browser_telemetry_button_tilt.js]
 [browser_telemetry_sidebar.js]
 [browser_telemetry_toolbox.js]
 [browser_telemetry_toolboxtabs_canvasdebugger.js]
 [browser_telemetry_toolboxtabs_inspector.js]
@@ -57,11 +58,12 @@ support-files =
 [browser_telemetry_toolboxtabs_shadereditor.js]
 [browser_telemetry_toolboxtabs_styleeditor.js]
 [browser_telemetry_toolboxtabs_webaudioeditor.js]
 [browser_telemetry_toolboxtabs_webconsole.js]
 [browser_templater_basic.js]
 [browser_toolbar_basic.js]
 [browser_toolbar_tooltip.js]
 [browser_toolbar_webconsole_errors_count.js]
+skip-if = buildapp == 'mulet'
 [browser_treeWidget_basic.js]
 [browser_treeWidget_keyboard_interaction.js]
 [browser_treeWidget_mouse_interaction.js]
--- a/browser/devtools/styleeditor/StyleSheetEditor.jsm
+++ b/browser/devtools/styleeditor/StyleSheetEditor.jsm
@@ -28,16 +28,19 @@ const SAVE_ERROR = "error-save";
 
 // max update frequency in ms (avoid potential typing lag and/or flicker)
 // @see StyleEditor.updateStylesheet
 const UPDATE_STYLESHEET_THROTTLE_DELAY = 500;
 
 // Pref which decides if CSS autocompletion is enabled in Style Editor or not.
 const AUTOCOMPLETION_PREF = "devtools.styleeditor.autocompletion-enabled";
 
+// Pref which decides whether updates to the stylesheet use transitions
+const TRANSITION_PREF = "devtools.styleeditor.transitions";
+
 // How long to wait to update linked CSS file after original source was saved
 // to disk. Time in ms.
 const CHECK_LINKED_SHEET_DELAY=500;
 
 // How many times to check for linked file changes
 const MAX_CHECK_COUNT=10;
 
 // The classname used to show a line that is not used
@@ -456,17 +459,19 @@ StyleSheetEditor.prototype = {
                              // (stylesheet is enabled) so that 'missed' updates
                              // while the stylesheet is disabled can be performed
                              // when it is enabled back. @see enableStylesheet
 
     if (this.sourceEditor) {
       this._state.text = this.sourceEditor.getText();
     }
 
-    this.styleSheet.update(this._state.text, true);
+    let transitionsEnabled = Services.prefs.getBoolPref(TRANSITION_PREF);
+
+    this.styleSheet.update(this._state.text, transitionsEnabled);
   },
 
   /**
    * Save the editor contents into a file and set savedFile property.
    * A file picker UI will open if file is not set and editor is not headless.
    *
    * @param mixed file
    *        Optional nsIFile or string representing the filename to save in the
--- a/browser/devtools/webconsole/console-output.js
+++ b/browser/devtools/webconsole/console-output.js
@@ -6,16 +6,17 @@
 "use strict";
 
 const {Cc, Ci, Cu} = require("chrome");
 
 loader.lazyImporter(this, "VariablesView", "resource:///modules/devtools/VariablesView.jsm");
 loader.lazyImporter(this, "escapeHTML", "resource:///modules/devtools/VariablesView.jsm");
 loader.lazyImporter(this, "gDevTools", "resource:///modules/devtools/gDevTools.jsm");
 loader.lazyImporter(this, "Task","resource://gre/modules/Task.jsm");
+loader.lazyImporter(this, "PluralForm", "resource://gre/modules/PluralForm.jsm");
 
 const Heritage = require("sdk/core/heritage");
 const URI = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
 const XHTML_NS = "http://www.w3.org/1999/xhtml";
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 const STRINGS_URI = "chrome://browser/locale/devtools/webconsole.properties";
 
 const WebConsoleUtils = require("devtools/toolkit/webconsole/utils").Utils;
@@ -2173,42 +2174,64 @@ Widgets.ObjectRenderers.add({
       this._text("[");
       this.element.appendChild(this.el("span.cm-number", preview.length));
       this._text("]");
       return this;
     }
 
     this._text(" [ ");
 
-    let shown = 0;
+    let isFirst = true;
+    let emptySlots = 0;
+    // A helper that renders a comma between items if isFirst == false.
+    let renderSeparator = () => !isFirst && this._text(", ");
+
     for (let item of items) {
-      if (shown > 0) {
-        this._text(", ");
+      if (item === null) {
+        emptySlots++;
       }
-
-      if (item !== null) {
+      else {
+        renderSeparator();
+        isFirst = false;
+
+        if (emptySlots) {
+          this._renderEmptySlots(emptySlots);
+          emptySlots = 0;
+        }
         let elem = this.message._renderValueGrip(item, { concise: true });
         this.element.appendChild(elem);
-      } else if (shown == (items.length - 1)) {
-        this._text(", ");
       }
-
-      shown++;
     }
 
+    if (emptySlots) {
+      renderSeparator();
+      this._renderEmptySlots(emptySlots, false);
+    }
+
+    let shown = items.length;
     if (shown < preview.length) {
       this._text(", ");
 
       let n = preview.length - shown;
       let str = VariablesView.stringifiers._getNMoreString(n);
       this._anchor(str);
     }
 
     this._text(" ]");
   },
+
+  _renderEmptySlots: function(aNumSlots, aAppendComma=true) {
+    let slotLabel = l10n.getStr("emptySlotLabel");
+    let slotText = PluralForm.get(aNumSlots, slotLabel);
+    this._text("<" + slotText.replace("#1", aNumSlots) + ">");
+    if (aAppendComma) {
+      this._text(", ");
+    }
+  },
+
 }); // Widgets.ObjectRenderers.byKind.ArrayLike
 
 /**
  * The widget used for displaying MapLike objects.
  */
 Widgets.ObjectRenderers.add({
   byKind: "MapLike",
 
--- a/browser/devtools/webconsole/test/browser.ini
+++ b/browser/devtools/webconsole/test/browser.ini
@@ -117,51 +117,60 @@ support-files =
 [browser_bug664688_sandbox_update_after_navigation.js]
 [browser_bug_638949_copy_link_location.js]
 [browser_bug_862916_console_dir_and_filter_off.js]
 [browser_bug_865288_repeat_different_objects.js]
 [browser_bug_865871_variables_view_close_on_esc_key.js]
 [browser_bug_869003_inspect_cross_domain_object.js]
 [browser_bug_871156_ctrlw_close_tab.js]
 [browser_cached_messages.js]
+skip-if = buildapp == 'mulet'
 [browser_console.js]
 [browser_console_addonsdk_loader_exception.js]
 [browser_console_clear_on_reload.js]
 [browser_console_click_focus.js]
 [browser_console_consolejsm_output.js]
 [browser_console_dead_objects.js]
 [browser_console_error_source_click.js]
+skip-if = buildapp == 'mulet'
 [browser_console_filters.js]
 [browser_console_iframe_messages.js]
+skip-if = buildapp == 'mulet'
 [browser_console_keyboard_accessibility.js]
 [browser_console_log_inspectable_object.js]
 [browser_console_native_getters.js]
 [browser_console_navigation_marker.js]
 [browser_console_nsiconsolemessage.js]
+skip-if = buildapp == 'mulet'
 [browser_console_optimized_out_vars.js]
 [browser_console_private_browsing.js]
+skip-if = buildapp == 'mulet'
 [browser_console_variables_view.js]
 [browser_console_variables_view_dom_nodes.js]
 [browser_console_variables_view_dont_sort_non_sortable_classes_properties.js]
+skip-if = buildapp == 'mulet'
 [browser_console_variables_view_while_debugging.js]
 [browser_console_variables_view_while_debugging_and_inspecting.js]
 [browser_eval_in_debugger_stackframe.js]
 [browser_jsterm_inspect.js]
 [browser_longstring_hang.js]
 [browser_netpanel_longstring_expand.js]
 [browser_output_breaks_after_console_dir_uninspectable.js]
 [browser_output_longstring_expand.js]
 [browser_repeated_messages_accuracy.js]
+skip-if = buildapp == 'mulet'
 [browser_result_format_as_string.js]
 [browser_warn_user_about_replaced_api.js]
 [browser_webconsole_abbreviate_source_url.js]
 [browser_webconsole_allow_mixedcontent_securityerrors.js]
+skip-if = buildapp == 'mulet'
 [browser_webconsole_assert.js]
 [browser_webconsole_basic_net_logging.js]
 [browser_webconsole_block_mixedcontent_securityerrors.js]
+skip-if = buildapp == 'mulet'
 [browser_webconsole_bug_579412_input_focus.js]
 [browser_webconsole_bug_580001_closing_after_completion.js]
 [browser_webconsole_bug_580030_errors_after_page_reload.js]
 [browser_webconsole_bug_580454_timestamp_l10n.js]
 [browser_webconsole_bug_582201_duplicate_errors.js]
 [browser_webconsole_bug_583816_No_input_and_Tab_key_pressed.js]
 [browser_webconsole_bug_585237_line_limit.js]
 [browser_webconsole_bug_585956_console_trace.js]
@@ -218,26 +227,32 @@ run-if = os == "win"
 [browser_webconsole_bug_659907_console_dir.js]
 [browser_webconsole_bug_660806_history_nav.js]
 [browser_webconsole_bug_664131_console_group.js]
 [browser_webconsole_bug_686937_autocomplete_JSTerm_helpers.js]
 [browser_webconsole_bug_704295.js]
 [browser_webconsole_bug_734061_No_input_change_and_Tab_key_pressed.js]
 [browser_webconsole_bug_737873_mixedcontent.js]
 [browser_webconsole_bug_762593_insecure_passwords_about_blank_web_console_warning.js]
+skip-if = buildapp == 'mulet'
 [browser_webconsole_bug_762593_insecure_passwords_web_console_warning.js]
+skip-if = buildapp == 'mulet'
 [browser_webconsole_bug_764572_output_open_url.js]
 [browser_webconsole_bug_766001_JS_Console_in_Debugger.js]
+skip-if = buildapp == 'mulet'
 [browser_webconsole_bug_770099_violation.js]
 [browser_webconsole_bug_782653_CSS_links_in_Style_Editor.js]
+skip-if = buildapp == 'mulet'
 [browser_webconsole_bug_804845_ctrl_key_nav.js]
 run-if = os == "mac"
 [browser_webconsole_bug_817834_add_edited_input_to_history.js]
 [browser_webconsole_bug_837351_securityerrors.js]
+skip-if = buildapp == 'mulet'
 [browser_webconsole_bug_846918_hsts_invalid-headers.js]
+skip-if = buildapp == 'mulet'
 [browser_webconsole_bug_915141_toggle_response_logging_with_keyboard.js]
 [browser_webconsole_bug_1006027_message_timestamps_incorrect.js]
 [browser_webconsole_bug_1010953_cspro.js]
 [browser_webconsole_cached_autocomplete.js]
 [browser_webconsole_change_font_size.js]
 [browser_webconsole_chrome.js]
 [browser_webconsole_clickable_urls.js]
 [browser_webconsole_closure_inspection.js]
@@ -274,16 +289,17 @@ run-if = os == "mac"
 [browser_webconsole_autocomplete_popup_close_on_tab_switch.js]
 [browser_webconsole_autocomplete-properties-with-non-alphanumeric-names.js]
 [browser_console_hide_jsterm_when_devtools_chrome_enabled_false.js]
 [browser_webconsole_output_01.js]
 [browser_webconsole_output_02.js]
 [browser_webconsole_output_03.js]
 [browser_webconsole_output_04.js]
 [browser_webconsole_output_05.js]
+[browser_webconsole_output_06.js]
 [browser_webconsole_output_dom_elements_01.js]
 [browser_webconsole_output_dom_elements_02.js]
 [browser_webconsole_output_dom_elements_03.js]
 [browser_webconsole_output_dom_elements_04.js]
 [browser_webconsole_output_events.js]
 [browser_console_variables_view_highlighter.js]
 [browser_webconsole_start_netmon_first.js]
 [browser_webconsole_console_trace_duplicates.js]
--- a/browser/devtools/webconsole/test/browser_webconsole_output_02.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_output_02.js
@@ -81,17 +81,17 @@ let inputTests = [
                  'function testfn3() { return 42; },[object Object],foo,bar"',
     inspectable: true,
     variablesViewLabel: "Array[13]",
   },
 
   // 8 - array with holes and a cyclic reference
   {
     input: "window.array4",
-    output: 'Array [ , , , , , "test", Array[7] ]',
+    output: 'Array [ <5 empty slots>, "test", Array[7] ]',
     printOutput: '",,,,,test,"',
     inspectable: true,
     variablesViewLabel: "Array[7]",
   },
 
   // 9
   {
     input: "window.typedarray1",
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_output_06.js
@@ -0,0 +1,114 @@
+ /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+ /* Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/ */
+ "use strict";
+
+// Test the webconsole output for various arrays.
+
+const TEST_URI = "data:text/html;charset=utf8,test for console output - 06";
+
+let inputTests = [
+  // 1 - array with empty slots only
+  {
+    input: 'Array(5)',
+    output: 'Array [ <5 empty slots> ]',
+    printOutput: ',,,,',
+    inspectable: true,
+    variablesViewLabel: "Array[5]",
+  },
+  // 2 - array with one empty slot at the beginning
+  {
+    input: '[,1,2,3]',
+    output: 'Array [ <1 empty slot>, 1, 2, 3 ]',
+    printOutput: ",1,2,3",
+    inspectable: true,
+    variablesViewLabel: "Array[4]",
+  },
+  // 3 - array with multiple consecutive empty slots at the beginning
+  {
+    input: '[,,,3,4,5]',
+    output: 'Array [ <3 empty slots>, 3, 4, 5 ]',
+    printOutput: ",,,3,4,5",
+    inspectable: true,
+    variablesViewLabel: "Array[6]",
+  },
+  // 4 - array with one empty slot at the middle
+  {
+    input: '[0,1,,3,4,5]',
+    output: 'Array [ 0, 1, <1 empty slot>, 3, 4, 5 ]',
+    printOutput: "0,1,,3,4,5",
+    inspectable: true,
+    variablesViewLabel: "Array[6]",
+  },
+  // 5 - array with multiple successive empty slots at the middle
+  {
+    input: '[0,1,,,,5]',
+    output: 'Array [ 0, 1, <3 empty slots>, 5 ]',
+    printOutput: "0,1,,,,5",
+    inspectable: true,
+    variablesViewLabel: "Array[6]",
+  },
+  // 6 - array with multiple non successive single empty slots
+  {
+    input: '[0,,2,,4,5]',
+    output: 'Array [ 0, <1 empty slot>, 2, <1 empty slot>, 4, 5 ]',
+    printOutput: "0,,2,,4,5",
+    inspectable: true,
+    variablesViewLabel: "Array[6]",
+  },
+  // 7 - array with multiple multi-slot holes
+  {
+    input: '[0,,,3,,,,7,8]',
+    output: 'Array [ 0, <2 empty slots>, 3, <3 empty slots>, 7, 8 ]',
+    printOutput: "0,,,3,,,,7,8",
+    inspectable: true,
+    variablesViewLabel: "Array[9]",
+  },
+  // 8 - array with a single slot hole at the end
+  {
+    input: '[0,1,2,3,4,,]',
+    output: 'Array [ 0, 1, 2, 3, 4, <1 empty slot> ]',
+    printOutput: "0,1,2,3,4,",
+    inspectable: true,
+    variablesViewLabel: "Array[6]",
+  },
+  // 9 - array with multiple consecutive empty slots at the end
+  {
+    input: '[0,1,2,,,,]',
+    output: 'Array [ 0, 1, 2, <3 empty slots> ]',
+    printOutput: "0,1,2,,,",
+    inspectable: true,
+    variablesViewLabel: "Array[6]",
+  },
+
+  // 10 - array with members explicitly set to null
+  {
+    input: '[0,null,null,3,4,5]',
+    output: 'Array [ 0, null, null, 3, 4, 5 ]',
+    printOutput: "0,,,3,4,5",
+    inspectable: true,
+    variablesViewLabel: "Array[6]"
+  },
+
+  // 11 - array with members explicitly set to undefined
+  {
+    input: '[0,undefined,undefined,3,4,5]',
+    output: 'Array [ 0, undefined, undefined, 3, 4, 5 ]',
+    printOutput: "0,,,3,4,5",
+    inspectable: true,
+    variablesViewLabel: "Array[6]"
+  }
+];
+
+function test() {
+  Task.spawn(function*() {
+    let {tab} = yield loadTab(TEST_URI);
+    let hud = yield openConsole(tab);
+    return checkOutputForInputs(hud, inputTests);
+  }).then(finishUp);
+}
+
+function finishUp() {
+  inputTests = null;
+  finishTest();
+}
--- a/browser/experiments/Experiments.jsm
+++ b/browser/experiments/Experiments.jsm
@@ -2176,17 +2176,21 @@ this.Experiments.PreviousExperimentProvi
 this.Experiments.PreviousExperimentProvider.prototype = Object.freeze({
   startup: function () {
     this._log.trace("startup()");
     Services.obs.addObserver(this, EXPERIMENTS_CHANGED_TOPIC, false);
   },
 
   shutdown: function () {
     this._log.trace("shutdown()");
-    Services.obs.removeObserver(this, EXPERIMENTS_CHANGED_TOPIC);
+    try {
+      Services.obs.removeObserver(this, EXPERIMENTS_CHANGED_TOPIC);
+    } catch(e) {
+      // Prevent crash in mochitest-browser3 on Mulet
+    }
   },
 
   observe: function (subject, topic, data) {
     switch (topic) {
       case EXPERIMENTS_CHANGED_TOPIC:
         this._updateExperimentList();
         break;
     }
--- a/browser/locales/en-US/chrome/browser/devtools/webconsole.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/webconsole.properties
@@ -236,8 +236,17 @@ selfxss.msg=Scam Warning: Take care when
 # in by a new user of the developer tools when they receive the sefxss.msg prompt.
 # Please avoid using non-keyboard characters here
 selfxss.okstring=allow pasting
 
 # LOCALIZATION NOTE (messageToggleDetails): the text that is displayed when
 # you hover the arrow for expanding/collapsing the message details. For
 # console.error() and other messages we show the stacktrace.
 messageToggleDetails=Show/hide message details.
+
+# LOCALIZATION NOTE (emptySlotLabel): the text is displayed when an Array
+# with empty slots is printed to the console.
+# This is a semi-colon list of plural forms.
+# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
+# #1 number of empty slots
+# example: 1 empty slot
+# example: 5 empty slots
+emptySlotLabel=#1 empty slot;#1 empty slots
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -146,18 +146,16 @@ browser.jar:
 #endif
 * skin/classic/browser/preferences/preferences.css    (preferences/preferences.css)
 * skin/classic/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
   skin/classic/browser/preferences/in-content/favicon.ico     (../shared/incontentprefs/favicon.ico)
   skin/classic/browser/preferences/in-content/check.png       (../shared/incontentprefs/check.png)
   skin/classic/browser/preferences/in-content/check@2x.png    (../shared/incontentprefs/check@2x.png)
   skin/classic/browser/preferences/in-content/icons.png       (../shared/incontentprefs/icons.png)
   skin/classic/browser/preferences/in-content/icons@2x.png    (../shared/incontentprefs/icons@2x.png)
-  skin/classic/browser/preferences/in-content/header.png      (../shared/incontentprefs/header.png)
-  skin/classic/browser/preferences/in-content/header@2x.png   (../shared/incontentprefs/header@2x.png)
   skin/classic/browser/preferences/in-content/help-glyph.png  (../shared/incontentprefs/help-glyph.png)
   skin/classic/browser/preferences/in-content/help-glyph@2x.png (../shared/incontentprefs/help-glyph@2x.png)
   skin/classic/browser/preferences/in-content/dropdown.png    (../shared/incontentprefs/dropdown.png)
   skin/classic/browser/preferences/in-content/dropdown@2x.png (../shared/incontentprefs/dropdown@2x.png)
   skin/classic/browser/preferences/in-content/sorter.png      (../shared/incontentprefs/sorter.png)
   skin/classic/browser/preferences/in-content/sorter@2x.png   (../shared/incontentprefs/sorter@2x.png)
   skin/classic/browser/preferences/in-content/dropdown-disabled.png    (../shared/incontentprefs/dropdown-disabled.png)
   skin/classic/browser/preferences/in-content/dropdown-disabled@2x.png (../shared/incontentprefs/dropdown-disabled@2x.png)
--- a/browser/themes/linux/preferences/in-content/preferences.css
+++ b/browser/themes/linux/preferences/in-content/preferences.css
@@ -7,29 +7,39 @@
 tab[selected] {
   /* Override styles for tab[selected] from
      toolkit/themes/linux/global/tabbox.css */
   margin-bottom: 0;
   border-bottom-left-radius: 0;
   border-bottom-right-radius: 0;
 }
 
+button,
+colorpicker[type="button"],
+menulist {
+  margin: 2px 4px;
+}
+
 button > .button-box,
 menulist > .menulist-label-box {
   -moz-appearance: none;
 }
 
 button[type="menu"] > .button-box > .button-menu-dropmarker {
   -moz-appearance: none !important;
 }
 
 .help-button > .button-box > .button-icon {
   -moz-margin-end: 0;
 }
 
+menulist {
+  font-size: inherit;
+}
+
 menulist:not([editable="true"]) > .menulist-dropmarker {
   display: -moz-box;
   margin-top: 6px;
   margin-bottom: 6px;
 }
 
 checkbox {
   -moz-binding: url("chrome://global/content/bindings/checkbox.xml#checkbox");
@@ -75,8 +85,22 @@ spinbuttons {
 .actionsMenu > .menulist-label-box > .menulist-label {
   margin-top: 2px !important;
 }
 
 menulist.actionsMenu > .menulist-dropmarker {
   margin-top: 11px;
   margin-bottom: 11px;
 }
+
+textbox + button,
+filefield + button {
+  -moz-margin-start: -4px;
+}
+
+#dialogTitle {
+  -moz-margin-start: 12px !important;
+}
+
+.actionButtons {
+  margin-right: 8px !important;
+  margin-left: 8px !important;
+}
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -238,18 +238,16 @@ browser.jar:
   skin/classic/browser/preferences/saveFile.png             (preferences/saveFile.png)
 * skin/classic/browser/preferences/preferences.css          (preferences/preferences.css)
 * skin/classic/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
   skin/classic/browser/preferences/in-content/favicon.ico     (../shared/incontentprefs/favicon.ico)
   skin/classic/browser/preferences/in-content/check.png       (../shared/incontentprefs/check.png)
   skin/classic/browser/preferences/in-content/check@2x.png    (../shared/incontentprefs/check@2x.png)
   skin/classic/browser/preferences/in-content/icons.png       (../shared/incontentprefs/icons.png)
   skin/classic/browser/preferences/in-content/icons@2x.png    (../shared/incontentprefs/icons@2x.png)
-  skin/classic/browser/preferences/in-content/header.png      (../shared/incontentprefs/header.png)
-  skin/classic/browser/preferences/in-content/header@2x.png   (../shared/incontentprefs/header@2x.png)
   skin/classic/browser/preferences/in-content/help-glyph.png  (../shared/incontentprefs/help-glyph.png)
   skin/classic/browser/preferences/in-content/help-glyph@2x.png (../shared/incontentprefs/help-glyph@2x.png)
   skin/classic/browser/preferences/in-content/sorter.png      (../shared/incontentprefs/sorter.png)
   skin/classic/browser/preferences/in-content/sorter@2x.png   (../shared/incontentprefs/sorter@2x.png)
   skin/classic/browser/preferences/in-content/dropdown.png    (../shared/incontentprefs/dropdown.png)
   skin/classic/browser/preferences/in-content/dropdown@2x.png (../shared/incontentprefs/dropdown@2x.png)
   skin/classic/browser/preferences/in-content/dropdown-disabled.png    (../shared/incontentprefs/dropdown-disabled.png)
   skin/classic/browser/preferences/in-content/dropdown-disabled@2x.png (../shared/incontentprefs/dropdown-disabled@2x.png)
--- a/browser/themes/osx/preferences/in-content/preferences.css
+++ b/browser/themes/osx/preferences/in-content/preferences.css
@@ -13,16 +13,22 @@ tabs {
   padding-right: 0;
   padding-left: 0;
 }
 
 tab[selected] {
   text-shadow: none;
 }
 
+button,
+colorpicker[type="button"],
+menulist {
+  margin-top: 3px;
+}
+
 menulist:not([editable="true"]) > menupopup > menuitem[checked="true"]::before,
 menulist:not([editable="true"]) > menupopup > menuitem[selected="true"]::before {
   display: none;
 }
 
 menulist:not([editable="true"]) > .menulist-dropmarker {
   display: -moz-box;
   margin-top: 1px;
@@ -82,15 +88,31 @@ spinbuttons {
   -moz-margin-end: 8px !important;
 }
 
 description {
   font-size: 1.25rem;
   line-height: 22px;
 }
 
+#downloadFolder > .fileFieldContentBox {
+  -moz-padding-start: 3px;
+}
+
+textbox + button {
+  -moz-margin-start: -4px;
+}
+
+filefield + button {
+  -moz-margin-start: -8px;
+}
+
+#dialogTitle {
+  -moz-margin-start: 6px !important;
+}
+
 #popupPolicyRow {
   /* Override styles from
      browser/themes/osx/preferences/preferences.css */
   margin-bottom: 0 !important;
   padding-bottom: 0 !important;
   border-bottom: none;
 }
deleted file mode 100644
index ce05ed2792b983d16b6077f36d9a364e90b79d46..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 83e8868ace71693a5c5a91bce30069236a3f06b9..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/themes/shared/incontentprefs/preferences.css
+++ b/browser/themes/shared/incontentprefs/preferences.css
@@ -7,17 +7,17 @@
 
 #dialogBox,
 dialog,
 window,
 prefwindow,
 .windowDialog,
 page {
   -moz-appearance: none;
-  background-color: white;
+  background-color: #f1f1f1;
   color: #424E5A;
 }
 
 * {
   -moz-user-select: text;
 }
 
 treecol {
@@ -56,17 +56,16 @@ prefpane > .content-box {
 
 /* groupboxes */
 
 groupbox {
   -moz-appearance: none;
   border: none;
   margin-top: 15px;
   margin-bottom: 15px;
-  -moz-margin-start: 60px;
   -moz-margin-end: 0;
   -moz-padding-start: 0;
   -moz-padding-end: 0;
   font-size: 1.25rem;
 }
 
 groupbox label {
   /* !important needed to override toolkit !important rule */
@@ -81,17 +80,16 @@ tabpanels {
   font-size: 1.25rem;
   line-height: 22px;
   border: none;
   padding: 0;
   background-color: transparent;
 }
 
 tabs {
-  -moz-margin-start: 60px;
   margin-bottom: 15px;
   border-top: 1px solid #c1c1c1;
   border-bottom: 1px solid #c1c1c1;
   background-color: #fbfbfb;
 }
 
 .tabs-left,
 .tabs-right {
@@ -578,95 +576,33 @@ radio[disabled="true"] > .radio-check {
   #category-advanced > .category-icon {
     -moz-image-region: rect(0, 336px, 48px, 288px);
   }
 }
 
 /* header */
 
 .header {
+  border-bottom: 1px solid #c8c8c8;
   margin-bottom: 15px;
+  padding-bottom: 15px;
 }
 
-.header-icon {
-  width: 40px;
-  max-height: 40px;
-  -moz-margin-end: 20px;
-  list-style-image: url("chrome://browser/skin/preferences/in-content/header.png");
+#header-advanced {
+  border-bottom: none;
+  padding-bottom: 0;
 }
 
 .header-name {
   font-size: 2.5rem;
   font-weight: normal;
   line-height: 40px;
   margin: 0;
 }
 
-#header-general > .header-icon {
-  -moz-image-region: rect(0, 40px, 40px, 0);
-}
-
-#header-content > .header-icon {
-  -moz-image-region: rect(0, 80px, 40px, 40px);
-}
-
-#header-application > .header-icon {
-  -moz-image-region: rect(0, 120px, 40px, 80px);
-}
-
-#header-privacy > .header-icon {
-  -moz-image-region: rect(0, 160px, 40px, 120px);
-}
-
-#header-security > .header-icon {
-  -moz-image-region: rect(0, 200px, 40px, 160px);
-}
-
-#header-sync > .header-icon {
-  -moz-image-region: rect(0, 240px, 40px, 200px);
-}
-
-#header-advanced > .header-icon {
-  -moz-image-region: rect(0, 280px, 40px, 240px);
-}
-
-@media (min-resolution: 2dppx) {
-  .header-icon {
-    list-style-image: url("chrome://browser/skin/preferences/in-content/header@2x.png");
-  }
-
-  #header-general > .header-icon {
-    -moz-image-region: rect(0, 80px, 80px, 0);
-  }
-
-  #header-content > .header-icon {
-    -moz-image-region: rect(0, 160px, 80px, 80px);
-  }
-
-  #header-application > .header-icon {
-    -moz-image-region: rect(0, 240px, 80px, 160px);
-  }
-
-  #header-privacy > .header-icon {
-    -moz-image-region: rect(0, 320px, 80px, 240px);
-  }
-
-  #header-security > .header-icon {
-    -moz-image-region: rect(0, 400px, 80px, 320px);
-  }
-
-  #header-sync > .header-icon {
-    -moz-image-region: rect(0, 480px, 80px, 400px);
-  }
-
-  #header-advanced > .header-icon {
-    -moz-image-region: rect(0, 560px, 80px, 480px);
-  }
-}
-
 /* General Pane */
 
 filefield {
   -moz-appearance: none;
   background-color: transparent;
   border: none;
   padding: 0;
 }
@@ -680,20 +616,44 @@ filefield {
   -moz-margin-end: 0;
 }
 
 .fileFieldLabel {
   -moz-margin-start: -26px;
   -moz-padding-start: 36px;
 }
 
+textbox:-moz-locale-dir(rtl),
+.fileFieldLabel:-moz-locale-dir(rtl),
+textbox + button:-moz-locale-dir(ltr),
+filefield + button:-moz-locale-dir(ltr) {
+  border-top-left-radius: 0;
+  border-bottom-left-radius: 0;
+}
+
+textbox:-moz-locale-dir(ltr),
+.fileFieldLabel:-moz-locale-dir(ltr),
+textbox + button:-moz-locale-dir(rtl),
+filefield + button:-moz-locale-dir(rtl) {
+  border-top-right-radius: 0;
+  border-bottom-right-radius: 0;
+}
+
+textbox + button,
+filefield + button {
+  -moz-border-start: none;
+}
+
+#downloadFolder {
+  -moz-margin-start: 0;
+}
+
 /* Applications Pane Styles */
 
 #applicationsContent {
-  -moz-margin-start: 60px;
   padding: 15px 0;
 }
 
 #filter {
   -moz-margin-start: 0;
 }
 
 #handlersView {
@@ -806,20 +766,16 @@ description > html|a {
   -moz-appearance: none;
   color: #333333;
   padding: 10px;
   border: 1px solid #C1C1C1;
   border-radius: 2px;
   background-color: #FBFBFB;
 }
 
-#weavePrefsDeck {
-  -moz-margin-start: 60px;
-}
-
 #noFxaAccount {
   /* Overriding the margins from the base preferences.css theme file.
      These overrides can be simplified by fixing bug 1027174 */
   margin: 0;
 }
 
 #weavePrefsDeck > vbox > label,
 #weavePrefsDeck > vbox > groupbox,
@@ -832,17 +788,16 @@ description > html|a {
 }
 
 #advancedPrefs {
   padding-bottom: 0; /* no padding needed in inContent prefs */
 }
 
 #encryptionPanel {
   margin-top: 15px;
-  -moz-margin-start: 60px;
 }
 
 #telemetryLearnMore,
 #FHRLearnMore,
 #crashReporterLearnMore {
   /* center the links */
   margin-top: 8px;
   margin-bottom: 8px;
@@ -871,20 +826,16 @@ description > html|a {
 
 #dialogBox[resizable="true"] {
   resize: both;
   overflow: hidden;
   min-height: 30em;
   min-width: 66ch;
 }
 
-#dialogTitle {
-  -moz-margin-start: 5px !important;
-}
-
 .close-icon {
   background-color: transparent !important;
   border: none;
   box-shadow: none;
   height: 18px;
   padding: 0;
   min-width: 18px;
 }
--- a/browser/themes/shared/newtab/newTab.inc.css
+++ b/browser/themes/shared/newtab/newTab.inc.css
@@ -119,17 +119,22 @@
   background-origin: padding-box;
   background-clip: padding-box;
   background-repeat: no-repeat;
   background-size: cover;
   border-radius: inherit;
   transition: opacity 100ms ease-out;
 }
 
+.newtab-thumbnail.enhanced-content:hover {
+  opacity: 0;
+}
+
 .newtab-site[type=affiliate] .newtab-thumbnail,
+.newtab-site[type=enhanced] .newtab-thumbnail,
 .newtab-site[type=organic] .newtab-thumbnail,
 .newtab-site[type=sponsored] .newtab-thumbnail {
   background-position: center center;
   background-size: auto;
 }
 
 /* Use a pseudo-element to overlay a gradient on the thumbnail */
 .newtab-site[type=history]:not(:hover) .newtab-thumbnail:first-child::after {
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -172,18 +172,16 @@ browser.jar:
         skin/classic/browser/preferences/saveFile.png                (preferences/saveFile.png)
 *       skin/classic/browser/preferences/preferences.css             (preferences/preferences.css)
 *       skin/classic/browser/preferences/in-content/preferences.css  (preferences/in-content/preferences.css)
         skin/classic/browser/preferences/in-content/favicon.ico      (../shared/incontentprefs/favicon.ico)
         skin/classic/browser/preferences/in-content/check.png        (../shared/incontentprefs/check.png)
         skin/classic/browser/preferences/in-content/check@2x.png     (../shared/incontentprefs/check@2x.png)
         skin/classic/browser/preferences/in-content/icons.png        (../shared/incontentprefs/icons.png)
         skin/classic/browser/preferences/in-content/icons@2x.png     (../shared/incontentprefs/icons@2x.png)
-        skin/classic/browser/preferences/in-content/header.png       (../shared/incontentprefs/header.png)
-        skin/classic/browser/preferences/in-content/header@2x.png    (../shared/incontentprefs/header@2x.png)
         skin/classic/browser/preferences/in-content/help-glyph.png   (../shared/incontentprefs/help-glyph.png)
         skin/classic/browser/preferences/in-content/help-glyph@2x.png (../shared/incontentprefs/help-glyph@2x.png)
         skin/classic/browser/preferences/in-content/sorter.png       (../shared/incontentprefs/sorter.png)
         skin/classic/browser/preferences/in-content/sorter@2x.png    (../shared/incontentprefs/sorter@2x.png)
         skin/classic/browser/preferences/in-content/dropdown.png     (../shared/incontentprefs/dropdown.png)
         skin/classic/browser/preferences/in-content/dropdown@2x.png  (../shared/incontentprefs/dropdown@2x.png)
         skin/classic/browser/preferences/in-content/dropdown-disabled.png     (../shared/incontentprefs/dropdown-disabled.png)
         skin/classic/browser/preferences/in-content/dropdown-disabled@2x.png  (../shared/incontentprefs/dropdown-disabled@2x.png)
@@ -591,18 +589,16 @@ browser.jar:
         skin/classic/aero/browser/preferences/saveFile.png           (preferences/saveFile-aero.png)
 *       skin/classic/aero/browser/preferences/preferences.css        (preferences/preferences.css)
 *       skin/classic/aero/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
         skin/classic/aero/browser/preferences/in-content/favicon.ico      (../shared/incontentprefs/favicon.ico)
         skin/classic/aero/browser/preferences/in-content/check.png       (../shared/incontentprefs/check.png)
         skin/classic/aero/browser/preferences/in-content/check@2x.png    (../shared/incontentprefs/check@2x.png)
         skin/classic/aero/browser/preferences/in-content/icons.png       (../shared/incontentprefs/icons.png)
         skin/classic/aero/browser/preferences/in-content/icons@2x.png    (../shared/incontentprefs/icons@2x.png)
-        skin/classic/aero/browser/preferences/in-content/header.png      (../shared/incontentprefs/header.png)
-        skin/classic/aero/browser/preferences/in-content/header@2x.png   (../shared/incontentprefs/header@2x.png)
         skin/classic/aero/browser/preferences/in-content/help-glyph.png  (../shared/incontentprefs/help-glyph.png)
         skin/classic/aero/browser/preferences/in-content/help-glyph@2x.png (../shared/incontentprefs/help-glyph@2x.png)
         skin/classic/aero/browser/preferences/in-content/sorter.png      (../shared/incontentprefs/sorter.png)
         skin/classic/aero/browser/preferences/in-content/sorter@2x.png   (../shared/incontentprefs/sorter@2x.png)
         skin/classic/aero/browser/preferences/in-content/dropdown.png    (../shared/incontentprefs/dropdown.png)
         skin/classic/aero/browser/preferences/in-content/dropdown@2x.png (../shared/incontentprefs/dropdown@2x.png)
         skin/classic/aero/browser/preferences/in-content/dropdown-disabled.png    (../shared/incontentprefs/dropdown-disabled.png)
         skin/classic/aero/browser/preferences/in-content/dropdown-disabled@2x.png (../shared/incontentprefs/dropdown-disabled@2x.png)
--- a/browser/themes/windows/preferences/in-content/preferences.css
+++ b/browser/themes/windows/preferences/in-content/preferences.css
@@ -3,16 +3,22 @@
    - You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 %include ../../../shared/incontentprefs/preferences.css
 
 caption {
   background-color: transparent;
 }
 
+button,
+colorpicker[type="button"],
+menulist {
+  margin: 2px 4px;
+}
+
 menulist:not([editable="true"]) > .menulist-dropmarker {
   margin-top: 1px;
   margin-bottom: 1px;
 }
 
 checkbox {
   -moz-padding-start: 0;
 }
@@ -26,8 +32,22 @@ radio {
 .radio-icon,
 .checkbox-icon {
   -moz-margin-end: 0;
 }
 
 .actionsMenu > .menulist-label-box > .menulist-icon {
   -moz-margin-end: 9px;
 }
+
+textbox + button,
+filefield + button {
+  -moz-margin-start: -4px;
+}
+
+#dialogTitle {
+  -moz-margin-start: 13px !important;
+}
+
+.actionButtons {
+  margin-right: 8px !important;
+  margin-left: 8px !important;
+}
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -792,16 +792,17 @@ ifneq (,$(HOST_CPPSRCS)$(USE_HOST_CXX))
 else
 	$(EXPAND_LIBS_EXEC) -- $(HOST_CC) $(HOST_OUTOPTION)$@ $(HOST_CFLAGS) $(INCLUDES) $< $(HOST_LIBS) $(HOST_EXTRA_LIBS)
 endif
 endif
 
 ifdef DTRACE_PROBE_OBJ
 EXTRA_DEPS += $(DTRACE_PROBE_OBJ)
 OBJS += $(DTRACE_PROBE_OBJ)
+EXCLUDED_OBJS += $(DTRACE_PROBE_OBJ)
 endif
 
 $(filter %.$(LIB_SUFFIX),$(LIBRARY)): $(OBJS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
 	$(REPORT_BUILD)
 	$(RM) $(LIBRARY)
 	$(EXPAND_AR) $(AR_FLAGS) $(OBJS) $(SHARED_LIBRARY_LIBS) $(filter %.$(LIB_SUFFIX),$(EXTRA_LIBS))
 
 $(filter-out %.$(LIB_SUFFIX),$(LIBRARY)): $(filter %.$(LIB_SUFFIX),$(LIBRARY)) $(OBJS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
--- a/content/base/test/chrome.ini
+++ b/content/base/test/chrome.ini
@@ -1,5 +1,6 @@
 [DEFAULT]
 
 [test_bug357450.js]
 [test_copypaste.xul]
 [test_messagemanager_principal.html]
+skip-if = buildapp == 'mulet'
--- a/content/base/test/chrome/chrome.ini
+++ b/content/base/test/chrome/chrome.ini
@@ -28,16 +28,17 @@ support-files =
 [test_bug391728.html]
 [test_bug421622.xul]
 [test_bug429785.xul]
 [test_bug430050.xul]
 [test_bug467123.xul]
 [test_bug549682.xul]
 [test_bug571390.xul]
 [test_bug574596.html]
+skip-if = buildapp == 'mulet'
 [test_bug599295.html]
 [test_bug616841.xul]
 [test_bug635835.xul]
 [test_bug650776.html]
 [test_bug650784.html]
 [test_bug682305.html]
 [test_bug683852.xul]
 [test_bug750096.html]
@@ -47,13 +48,13 @@ support-files =
 [test_bug780199.xul]
 [test_bug780529.xul]
 [test_bug800386.xul]
 [test_bug814638.xul]
 [test_bug816340.xul]
 [test_bug914381.html]
 [test_bug990812.xul]
 [test_cpows.xul]
-skip-if = toolkit == "cocoa"
+skip-if = buildapp == 'mulet' || toolkit == "cocoa"
 [test_document_register.xul]
 [test_domparsing.xul]
 [test_fileconstructor.xul]
 [test_title.xul]
--- a/content/base/test/mochitest-child-permissions.ini
+++ b/content/base/test/mochitest-child-permissions.ini
@@ -1,4 +1,4 @@
 [test_messagemanager_assertpermission.html]
-skip-if = buildapp == 'b2g' #b2g(specialpowers.wrap issue, NS_ERROR_XPC_GS_RETURNED_FAILURE) b2g-debug(specialpowers.wrap issue, NS_ERROR_XPC_GS_RETURNED_FAILURE) b2g-desktop(specialpowers.wrap issue, NS_ERROR_XPC_GS_RETURNED_FAILURE)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' #b2g(specialpowers.wrap issue, NS_ERROR_XPC_GS_RETURNED_FAILURE) b2g-debug(specialpowers.wrap issue, NS_ERROR_XPC_GS_RETURNED_FAILURE) b2g-desktop(specialpowers.wrap issue, NS_ERROR_XPC_GS_RETURNED_FAILURE)
 [test_child_process_shutdown_message.html]
-skip-if = buildapp == 'b2g' #b2g(specialpowers.wrap issue, NS_ERROR_XPC_GS_RETURNED_FAILURE) b2g-debug(specialpowers.wrap issue, NS_ERROR_XPC_GS_RETURNED_FAILURE) b2g-desktop(specialpowers.wrap issue, NS_ERROR_XPC_GS_RETURNED_FAILURE)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' #b2g(specialpowers.wrap issue, NS_ERROR_XPC_GS_RETURNED_FAILURE) b2g-debug(specialpowers.wrap issue, NS_ERROR_XPC_GS_RETURNED_FAILURE) b2g-desktop(specialpowers.wrap issue, NS_ERROR_XPC_GS_RETURNED_FAILURE)
--- a/content/base/test/mochitest.ini
+++ b/content/base/test/mochitest.ini
@@ -531,17 +531,17 @@ skip-if = (buildapp == 'b2g' && toolkit 
 [test_bug810494.html]
 [test_bug811701.html]
 [test_bug811701.xhtml]
 [test_bug813919.html]
 [test_bug814576.html]
 [test_bug819051.html]
 [test_bug820909.html]
 [test_bug827160.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #needs plugin support # b2g(needs plugin support) b2g-debug(debug-only failure) b2g-desktop(needs plugin support)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #needs plugin support # b2g(needs plugin support) b2g-debug(debug-only failure) b2g-desktop(needs plugin support)
 [test_bug840098.html]
 [test_bug864595.html]
 [test_bug868999.html]
 [test_bug869000.html]
 [test_bug869002.html]
 [test_bug869006.html]
 [test_bug876282.html]
 [test_bug890580.html]
@@ -587,30 +587,30 @@ skip-if = buildapp == 'b2g' || toolkit =
 [test_meta_viewport0.html]
 [test_meta_viewport1.html]
 [test_meta_viewport2.html]
 [test_meta_viewport3.html]
 [test_meta_viewport4.html]
 [test_meta_viewport5.html]
 [test_meta_viewport6.html]
 [test_mixed_content_blocker.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #TIMED_OUT, SSL_REQUIRED
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #TIMED_OUT, SSL_REQUIRED
 [test_mixed_content_blocker_bug803225.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #TIMED_OUT, SSL_REQUIRED
 [test_mixed_content_blocker_frameNavigation.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #TIMED_OUT, SSL_REQUIRED
 [test_mozfiledataurl.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #TIMED_OUT
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #TIMED_OUT
 [test_mutationobservers.html]
 skip-if = buildapp == 'b2g' || e10s # b2g(bug 901385, showmodaldialog) b2g-debug(bug 901385, showmodaldialog) b2g-desktop(bug 901385, showmodaldialog)
 [test_nodelist_holes.html]
 [test_object.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(needs plugin support) b2g-debug(needs plugin support) b2g-desktop(needs plugin support)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(needs plugin support) b2g-debug(needs plugin support) b2g-desktop(needs plugin support)
 [test_plugin_freezing.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #CLICK_TO_PLAY
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #CLICK_TO_PLAY
 [test_processing_instruction_update_stylesheet.xhtml]
 [test_range_bounds.html]
 skip-if = toolkit == 'android' || e10s
 [test_reentrant_flush.html]
 skip-if = toolkit == 'android' || e10s #RANDOM
 [test_sync_xhr_timer.xhtml]
 skip-if = toolkit == 'android' || e10s #RANDOM
 [test_text_wholeText.html]
--- a/content/canvas/test/mochitest.ini
+++ b/content/canvas/test/mochitest.ini
@@ -197,17 +197,17 @@ skip-if = (toolkit == 'gonk' && !debug) 
 [test_hitregion_event.html]
 skip-if = os == "android" || appname == "b2g"
 [test_canvas_strokeStyle_getter.html]
 [test_drawImageIncomplete.html]
 [test_drawImage_document_domain.html]
 [test_drawImage_edge_cases.html]
 [test_drawWindow.html]
 support-files = file_drawWindow_source.html file_drawWindow_common.js
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk')
+skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && toolkit != 'gonk')
 [test_ImageData_ctor.html]
 [test_isPointInStroke.html]
 [test_mozDashOffset.html]
 [test_mozGetAsFile.html]
 [test_strokeText_throw.html]
 [test_toBlob.html]
 [test_toDataURL_alpha.html]
 [test_toDataURL_lowercase_ascii.html]
--- a/content/canvas/test/webgl-conformance/mochitest.ini
+++ b/content/canvas/test/webgl-conformance/mochitest.ini
@@ -13,9 +13,9 @@ support-files =
   failing_tests_windows.txt
   skipped_tests_android.txt
   skipped_tests_android_x86.txt
   skipped_tests_linux_mesa.txt
   skipped_tests_win_vista.txt
   skipped_tests_winxp.txt
 
 [test_webgl_conformance_test_suite.html]
-skip-if = (buildapp == 'b2g') # bug 865443- separate suite - the non_conf* tests pass except for one on armv6 tests
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' # bug 865443- separate suite - the non_conf* tests pass except for one on armv6 tests
--- a/content/canvas/test/webgl-mochitest/mochitest.ini
+++ b/content/canvas/test/webgl-mochitest/mochitest.ini
@@ -10,15 +10,15 @@ support-files =
 [test_highp_fs.html]
 [test_no_arr_points.html]
 [test_noprog_draw.html]
 [test_privileged_exts.html]
 [test_texsubimage_float.html]
 [test_webgl_available.html]
 skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
 [test_webgl_conformance.html]
-skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
+skip-if = buildapp == 'mulet' || toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
 [test_webgl_request_context.html]
 skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
 [test_webgl_request_mismatch.html]
 skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
 [test_webgl2_not_exposed.html]
 skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
--- a/content/html/content/test/forms/mochitest.ini
+++ b/content/html/content/test/forms/mochitest.ini
@@ -2,62 +2,69 @@
 support-files =
   save_restore_radio_groups.sjs
   submit_invalid_file.sjs
   test_input_number_data.js
 
 [test_button_attributes_reflection.html]
 [test_input_radio_radiogroup.html]
 [test_change_event.html]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
+skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_datalist_element.html]
 [test_experimental_forms_pref.html]
 [test_form_attribute-1.html]
 [test_form_attribute-2.html]
 [test_form_attribute-3.html]
 [test_form_attribute-4.html]
 [test_form_attributes_reflection.html]
 [test_form_named_getter_dynamic.html]
 [test_formaction_attribute.html]
+skip-if = buildapp == 'mulet'
 [test_formnovalidate_attribute.html]
+skip-if = buildapp == 'mulet'
 [test_input_attributes_reflection.html]
 [test_input_autocomplete.html]
 [test_input_color_input_change_events.html]
+skip-if = buildapp == 'mulet'
 [test_input_color_picker_initial.html]
+skip-if = buildapp == 'mulet'
 [test_input_color_picker_popup.html]
+skip-if = buildapp == 'mulet'
 [test_input_color_picker_update.html]
+skip-if = buildapp == 'mulet'
 [test_input_defaultValue.html]
 [test_input_email.html]
 [test_input_event.html]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
+skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop and mulet specific, initial triage
 [test_input_file_picker.html]
 skip-if = buildapp == 'b2g' # b2g(5 failures out of 139 and timing out, bug 901581) b2g-debug(5 failures out of 139 and timing out, bug 901581) b2g-desktop(5 failures out of 139 and timing out, bug 901581)
 [test_input_list_attribute.html]
 [test_input_number_l10n.html]
 # We don't build ICU for Firefox for Android or Firefox OS:
-skip-if = os == "android" || appname == "b2g"
+skip-if = buildapp == 'mulet' || os == "android" || appname == "b2g"
 [test_input_number_key_events.html]
 [test_input_number_mouse_events.html]
 # Not run on Firefox OS and Firefox for Android where the spin buttons are hidden:
-skip-if = os == "android" || appname == "b2g"
+skip-if = os == "android" || appname == "b2g" || buildapp == "mulet"
 [test_input_number_rounding.html]
-skip-if = os == "android"
+skip-if = os == "android" || buildapp == "mulet"
 [test_input_number_validation.html]
 # We don't build ICU for Firefox for Android or Firefox OS:
-skip-if = os == "android" || appname == "b2g"
+skip-if = buildapp == 'mulet' || os == "android" || appname == "b2g"
 [test_input_range_attr_order.html]
 [test_input_range_key_events.html]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
+skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_input_range_mouse_and_touch_events.html]
 skip-if = (toolkit == 'gonk' && debug) #debug-only failure; bug 926546
 [test_input_range_rounding.html]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
+skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_input_sanitization.html]
 [test_input_textarea_set_value_no_scroll.html]
 [test_input_typing_sanitization.html]
+skip-if = buildapp == 'mulet'
 [test_input_untrusted_key_events.html]
 [test_input_url.html]
 [test_label_control_attribute.html]
 [test_label_input_controls.html]
 [test_max_attribute.html]
 skip-if = e10s
 [test_maxlength_attribute.html]
 [test_meter_element.html]
--- a/content/html/content/test/mochitest.ini
+++ b/content/html/content/test/mochitest.ini
@@ -319,24 +319,24 @@ skip-if = e10s
 [test_bug605125-1.html]
 [test_bug605125-2.html]
 [test_bug606817.html]
 [test_bug607145.html]
 [test_bug610212.html]
 [test_bug610687.html]
 [test_bug611189.html]
 [test_bug612730.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' # b2g(form control not selected/checked with synthesizeMouse, also fails on Android) b2g-debug(form control not selected/checked with synthesizeMouse, also fails on Android) b2g-desktop(form control not selected/checked with synthesizeMouse, also fails on Android)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' # b2g(form control not selected/checked with synthesizeMouse, also fails on Android) b2g-debug(form control not selected/checked with synthesizeMouse, also fails on Android) b2g-desktop(form control not selected/checked with synthesizeMouse, also fails on Android)
 [test_bug613113.html]
 skip-if = buildapp == 'b2g' || e10s # b2g(bug 587671, need an invalidformsubmit observer) b2g-debug(bug 587671, need an invalidformsubmit observer) b2g-desktop(bug 587671, need an invalidformsubmit observer)
 [test_bug613722.html]
 [test_bug613979.html]
 [test_bug615595.html]
 [test_bug615833.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT # b2g(form control not selected/checked with synthesizeMouse, also fails on Android) b2g-debug(form control not selected/checked with synthesizeMouse, also fails on Android) b2g-desktop(form control not selected/checked with synthesizeMouse, also fails on Android)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT # b2g(form control not selected/checked with synthesizeMouse, also fails on Android) b2g-debug(form control not selected/checked with synthesizeMouse, also fails on Android) b2g-desktop(form control not selected/checked with synthesizeMouse, also fails on Android)
 [test_bug617528.html]
 [test_bug618948.html]
 skip-if = buildapp == 'b2g' || e10s # b2g(bug 587671, need an invalidformsubmit observer) b2g-debug(bug 587671, need an invalidformsubmit observer) b2g-desktop(bug 587671, need an invalidformsubmit observer)
 [test_bug619278.html]
 skip-if = buildapp == 'b2g' || e10s # b2g(bug 587671, need an invalidformsubmit observer) b2g-debug(bug 587671, need an invalidformsubmit observer) b2g-desktop(bug 587671, need an invalidformsubmit observer)
 [test_bug622558.html]
 skip-if = e10s
 [test_bug622597.html]
@@ -427,31 +427,31 @@ skip-if = (toolkit == 'gonk' && debug) |
 [test_embed_attributes_reflection.html]
 [test_formData.html]
 [test_formSubmission.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #TIMED_OUT # b2g(NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) b2g-debug(NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) b2g-desktop(NS_ERROR_FILE_TARGET_DOES_NOT_EXIST)
 [test_formSubmission2.html]
 skip-if = toolkit == 'android'
 [test_formelements.html]
 [test_fullscreen-api.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #TIMED_OUT # b2g(time out, some kind of focus issue) b2g-debug(time out, some kind of focus issue) b2g-desktop(time out, some kind of focus issue)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #TIMED_OUT # b2g(time out, some kind of focus issue) b2g-debug(time out, some kind of focus issue) b2g-desktop(time out, some kind of focus issue)
 [test_hidden.html]
 [test_html_attributes_reflection.html]
 [test_htmlcollection.html]
 [test_iframe_sandbox_general.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_iframe_sandbox_inheritance.html]
 [test_iframe_sandbox_modal.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #modal tests fail on android # b2g(modal tests fail on B2G) b2g-debug(modal tests fail on B2G) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #modal tests fail on android # b2g(modal tests fail on B2G) b2g-debug(modal tests fail on B2G) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
 [test_iframe_sandbox_navigation.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #time out on b2g desktop specific
 [test_iframe_sandbox_navigation2.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #time out on b2g desktop specific
 [test_iframe_sandbox_plugins.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(plugins not supported) b2g-debug(plugins not supported) b2g-desktop(plugins not supported)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(plugins not supported) b2g-debug(plugins not supported) b2g-desktop(plugins not supported)
 [test_iframe_sandbox_popups.html]
 skip-if = buildapp == 'b2g' # b2g(multiple concurrent window.open()s fail on B2G) b2g-debug(multiple concurrent window.open()s fail on B2G) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
 [test_iframe_sandbox_popups_inheritance.html]
 skip-if = buildapp == 'b2g' || e10s # b2g(multiple concurrent window.open()s fail on B2G) b2g-debug(multiple concurrent window.open()s fail on B2G) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
 [test_iframe_sandbox_redirect.html]
 [test_iframe_sandbox_same_origin.html]
 [test_iframe_sandbox_workers.html]
 [test_img_attributes_reflection.html]
@@ -461,22 +461,22 @@ skip-if = buildapp == 'b2g' || e10s # b2
 [test_imports_nonhttp.html]
 [test_li_attributes_reflection.html]
 [test_link_attributes_reflection.html]
 [test_link_sizes.html]
 [test_map_attributes_reflection.html]
 [test_meta_attributes_reflection.html]
 [test_mod_attributes_reflection.html]
 [test_mozaudiochannel.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(Perma-orange on debug emulator) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
+skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(Perma-orange on debug emulator) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
 [test_named_options.html]
 [test_nested_invalid_fieldsets.html]
 [test_object_attributes_reflection.html]
 [test_object_plugin_nav.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #TIMED_OUT # b2g(plugins not supported) b2g-debug(plugins not supported) b2g-desktop(plugins not supported)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #TIMED_OUT # b2g(plugins not supported) b2g-debug(plugins not supported) b2g-desktop(plugins not supported)
 [test_ol_attributes_reflection.html]
 [test_option_defaultSelected.html]
 [test_option_selected_state.html]
 [test_param_attributes_reflection.html]
 [test_q_attributes_reflection.html]
 [test_restore_from_parser_fragment.html]
 [test_rowscollection.html]
 [test_srcdoc-2.html]
--- a/content/html/document/test/mochitest.ini
+++ b/content/html/document/test/mochitest.ini
@@ -33,20 +33,20 @@ skip-if = (buildapp == 'b2g' && toolkit 
 [test_bug259332.html]
 [test_bug311681.html]
 [test_bug311681.xhtml]
 [test_bug324378.html]
 [test_bug332848.xhtml]
 [test_bug340017.xhtml]
 [test_bug359657.html]
 [test_bug369370.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s
 [test_bug380383.html]
 [test_bug391777.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(showmodaldialog) b2g-debug(showmodaldialog) b2g-desktop(showmodaldialog)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(showmodaldialog) b2g-debug(showmodaldialog) b2g-desktop(showmodaldialog)
 [test_bug402680.html]
 [test_bug403868.html]
 [test_bug403868.xhtml]
 [test_bug435128.html]
 skip-if = true # Disabled for timeouts.
 [test_bug463104.html]
 [test_form-parsing.html]
 [test_viewport.html]
--- a/content/media/MediaDecoderStateMachine.cpp
+++ b/content/media/MediaDecoderStateMachine.cpp
@@ -1400,17 +1400,19 @@ void MediaDecoderStateMachine::Play()
   // Once we start playing, we don't want to minimize our prerolling, as we
   // assume the user is likely to want to keep playing in future.
   mMinimizePreroll = false;
   ScheduleStateMachine();
 }
 
 void MediaDecoderStateMachine::ResetPlayback()
 {
-  MOZ_ASSERT(mState == DECODER_STATE_SEEKING || mState == DECODER_STATE_SHUTDOWN);
+  MOZ_ASSERT(mState == DECODER_STATE_SEEKING ||
+             mState == DECODER_STATE_SHUTDOWN ||
+             mState == DECODER_STATE_DORMANT);
   mVideoFrameEndTime = -1;
   mAudioStartTime = -1;
   mAudioEndTime = -1;
   mAudioCompleted = false;
   AudioQueue().Reset();
   VideoQueue().Reset();
   mFirstVideoFrameAfterSeek = nullptr;
   mDropAudioUntilNextDiscontinuity = true;
--- a/content/media/gmp/GMPVideoDecoderChild.cpp
+++ b/content/media/gmp/GMPVideoDecoderChild.cpp
@@ -92,16 +92,24 @@ void
 GMPVideoDecoderChild::ResetComplete()
 {
   MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
 
   SendResetComplete();
 }
 
 void
+GMPVideoDecoderChild::Error(GMPErr aError)
+{
+  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
+
+  SendError(aError);
+}
+
+void
 GMPVideoDecoderChild::CheckThread()
 {
   MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
 }
 
 bool
 GMPVideoDecoderChild::RecvInitDecode(const GMPVideoCodec& aCodecSettings,
                                      const nsTArray<uint8_t>& aCodecSpecific,
--- a/content/media/gmp/GMPVideoDecoderChild.h
+++ b/content/media/gmp/GMPVideoDecoderChild.h
@@ -31,16 +31,17 @@ public:
 
   // GMPVideoDecoderCallback
   virtual void Decoded(GMPVideoi420Frame* decodedFrame) MOZ_OVERRIDE;
   virtual void ReceivedDecodedReferenceFrame(const uint64_t pictureId) MOZ_OVERRIDE;
   virtual void ReceivedDecodedFrame(const uint64_t pictureId) MOZ_OVERRIDE;
   virtual void InputDataExhausted() MOZ_OVERRIDE;
   virtual void DrainComplete() MOZ_OVERRIDE;
   virtual void ResetComplete() MOZ_OVERRIDE;
+  virtual void Error(GMPErr aError) MOZ_OVERRIDE;
 
   // GMPSharedMemManager
   virtual void CheckThread();
   virtual bool Alloc(size_t aSize, Shmem::SharedMemory::SharedMemoryType aType, Shmem* aMem)
   {
 #ifndef SHMEM_ALLOC_IN_CHILD
     return CallNeedShmem(aSize, aMem);
 #else
--- a/content/media/gmp/GMPVideoDecoderParent.cpp
+++ b/content/media/gmp/GMPVideoDecoderParent.cpp
@@ -262,16 +262,29 @@ GMPVideoDecoderParent::RecvResetComplete
 
   // Ignore any return code. It is OK for this to fail without killing the process.
   mCallback->ResetComplete();
 
   return true;
 }
 
 bool
+GMPVideoDecoderParent::RecvError(const GMPErr& aError)
+{
+  if (!mCallback) {
+    return false;
+  }
+
+  // Ignore any return code. It is OK for this to fail without killing the process.
+  mCallback->Error(aError);
+
+  return true;
+}
+
+bool
 GMPVideoDecoderParent::RecvParentShmemForPool(Shmem& aEncodedBuffer)
 {
   if (aEncodedBuffer.IsWritable()) {
     mVideoHost.SharedMemMgr()->MgrDeallocShmem(GMPSharedMemManager::kGMPEncodedData,
                                                aEncodedBuffer);
   }
   return true;
 }
--- a/content/media/gmp/GMPVideoDecoderParent.h
+++ b/content/media/gmp/GMPVideoDecoderParent.h
@@ -65,16 +65,17 @@ private:
   // PGMPVideoDecoderParent
   virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
   virtual bool RecvDecoded(const GMPVideoi420FrameData& aDecodedFrame) MOZ_OVERRIDE;
   virtual bool RecvReceivedDecodedReferenceFrame(const uint64_t& aPictureId) MOZ_OVERRIDE;
   virtual bool RecvReceivedDecodedFrame(const uint64_t& aPictureId) MOZ_OVERRIDE;
   virtual bool RecvInputDataExhausted() MOZ_OVERRIDE;
   virtual bool RecvDrainComplete() MOZ_OVERRIDE;
   virtual bool RecvResetComplete() MOZ_OVERRIDE;
+  virtual bool RecvError(const GMPErr& aError) MOZ_OVERRIDE;
   virtual bool RecvParentShmemForPool(Shmem& aEncodedBuffer) MOZ_OVERRIDE;
   virtual bool AnswerNeedShmem(const uint32_t& aFrameBufferSize,
                                Shmem* aMem) MOZ_OVERRIDE;
   virtual bool Recv__delete__() MOZ_OVERRIDE;
 
   bool mCanSendMessages;
   nsRefPtr<GMPParent> mPlugin;
   GMPVideoDecoderCallback* mCallback;
--- a/content/media/gmp/GMPVideoEncodedFrameImpl.cpp
+++ b/content/media/gmp/GMPVideoEncodedFrameImpl.cpp
@@ -46,17 +46,17 @@ GMPVideoEncodedFrameImpl::GMPVideoEncode
 GMPVideoEncodedFrameImpl::~GMPVideoEncodedFrameImpl()
 {
   DestroyBuffer();
   if (mHost) {
     mHost->EncodedFrameDestroyed(this);
   }
 }
 
-const GMPEncryptedBufferData*
+const GMPEncryptedBufferMetadata*
 GMPVideoEncodedFrameImpl::GetDecryptionData() const
 {
   return nullptr;
 }
 
 GMPVideoFrameFormat
 GMPVideoEncodedFrameImpl::GetFrameFormat()
 {
--- a/content/media/gmp/GMPVideoEncodedFrameImpl.h
+++ b/content/media/gmp/GMPVideoEncodedFrameImpl.h
@@ -86,17 +86,17 @@ public:
   virtual void     SetSize(uint32_t aSize) MOZ_OVERRIDE;
   virtual uint32_t Size() MOZ_OVERRIDE;
   virtual void     SetCompleteFrame(bool aCompleteFrame) MOZ_OVERRIDE;
   virtual bool     CompleteFrame() MOZ_OVERRIDE;
   virtual const uint8_t* Buffer() const MOZ_OVERRIDE;
   virtual uint8_t* Buffer() MOZ_OVERRIDE;
   virtual GMPBufferType BufferType() const MOZ_OVERRIDE;
   virtual void     SetBufferType(GMPBufferType aBufferType) MOZ_OVERRIDE;
-  virtual const    GMPEncryptedBufferData* GetDecryptionData() const MOZ_OVERRIDE;
+  virtual const    GMPEncryptedBufferMetadata* GetDecryptionData() const MOZ_OVERRIDE;
 
 private:
   void DestroyBuffer();
 
   uint32_t mEncodedWidth;
   uint32_t mEncodedHeight;
   uint64_t mTimeStamp;
   uint64_t mDuration;
--- a/content/media/gmp/GMPVideoEncoderChild.cpp
+++ b/content/media/gmp/GMPVideoEncoderChild.cpp
@@ -53,16 +53,24 @@ GMPVideoEncoderChild::Encoded(GMPVideoEn
   nsTArray<uint8_t> codecSpecific;
   codecSpecific.AppendElements(aCodecSpecificInfo, aCodecSpecificInfoLength);
   SendEncoded(frameData, codecSpecific);
 
   aEncodedFrame->Destroy();
 }
 
 void
+GMPVideoEncoderChild::Error(GMPErr aError)
+{
+  MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
+
+  SendError(aError);
+}
+
+void
 GMPVideoEncoderChild::CheckThread()
 {
   MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current());
 }
 
 bool
 GMPVideoEncoderChild::RecvInitEncode(const GMPVideoCodec& aCodecSettings,
                                      const nsTArray<uint8_t>& aCodecSpecific,
--- a/content/media/gmp/GMPVideoEncoderChild.h
+++ b/content/media/gmp/GMPVideoEncoderChild.h
@@ -27,16 +27,17 @@ public:
 
   void Init(GMPVideoEncoder* aEncoder);
   GMPVideoHostImpl& Host();
 
   // GMPVideoEncoderCallback
   virtual void Encoded(GMPVideoEncodedFrame* aEncodedFrame,
                        const uint8_t* aCodecSpecificInfo,
                        uint32_t aCodecSpecificInfoLength) MOZ_OVERRIDE;
+  virtual void Error(GMPErr aError) MOZ_OVERRIDE;
 
   // GMPSharedMemManager
   virtual void CheckThread();
   virtual bool Alloc(size_t aSize, Shmem::SharedMemory::SharedMemoryType aType, Shmem* aMem)
   {
 #ifndef SHMEM_ALLOC_IN_CHILD
     return CallNeedShmem(aSize, aMem);
 #else
--- a/content/media/gmp/GMPVideoEncoderParent.cpp
+++ b/content/media/gmp/GMPVideoEncoderParent.cpp
@@ -215,16 +215,29 @@ GMPVideoEncoderParent::RecvEncoded(const
   mCallback->Encoded(f, aCodecSpecificInfo);
 
   // Return SHM to sender to recycle
   //SendEncodedReturn(aEncodedFrame, aCodecSpecificInfo);
   return true;
 }
 
 bool
+GMPVideoEncoderParent::RecvError(const GMPErr& aError)
+{
+  if (!mCallback) {
+    return false;
+  }
+
+  // Ignore any return code. It is OK for this to fail without killing the process.
+  mCallback->Error(aError);
+
+  return true;
+}
+
+bool
 GMPVideoEncoderParent::RecvParentShmemForPool(Shmem& aFrameBuffer)
 {
   if (aFrameBuffer.IsWritable()) {
     mVideoHost.SharedMemMgr()->MgrDeallocShmem(GMPSharedMemManager::kGMPFrameData,
                                                aFrameBuffer);
   }
   return true;
 }
--- a/content/media/gmp/GMPVideoEncoderParent.h
+++ b/content/media/gmp/GMPVideoEncoderParent.h
@@ -62,16 +62,17 @@ public:
 
 private:
   virtual ~GMPVideoEncoderParent();
 
   // PGMPVideoEncoderParent
   virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
   virtual bool RecvEncoded(const GMPVideoEncodedFrameData& aEncodedFrame,
                            const nsTArray<uint8_t>& aCodecSpecificInfo) MOZ_OVERRIDE;
+  virtual bool RecvError(const GMPErr& aError) MOZ_OVERRIDE;
   virtual bool RecvParentShmemForPool(Shmem& aFrameBuffer) MOZ_OVERRIDE;
   virtual bool AnswerNeedShmem(const uint32_t& aEncodedBufferSize,
                                Shmem* aMem) MOZ_OVERRIDE;
   virtual bool Recv__delete__() MOZ_OVERRIDE;
 
   bool mCanSendMessages;
   nsRefPtr<GMPParent> mPlugin;
   GMPVideoEncoderCallbackProxy* mCallback;
--- a/content/media/gmp/GMPVideoEncoderProxy.h
+++ b/content/media/gmp/GMPVideoEncoderProxy.h
@@ -10,16 +10,17 @@
 #include "gmp-video-encode.h"
 #include "gmp-video-frame-i420.h"
 #include "gmp-video-frame-encoded.h"
 
 class GMPVideoEncoderCallbackProxy {
 public:
   virtual void Encoded(GMPVideoEncodedFrame* aEncodedFrame,
                        const nsTArray<uint8_t>& aCodecSpecificInfo) = 0;
+  virtual void Error(GMPErr aError) = 0;
 };
 
 // A proxy to GMPVideoEncoder in the child process.
 // GMPVideoEncoderParent exposes this to users the GMP.
 // This enables Gecko to pass nsTArrays to the child GMP and avoid
 // an extra copy when doing so.
 class GMPVideoEncoderProxy {
 public:
--- a/content/media/gmp/PGMPVideoDecoder.ipdl
+++ b/content/media/gmp/PGMPVideoDecoder.ipdl
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PGMP;
 include GMPTypes;
 
 using GMPVideoCodec from "gmp-video-codec.h";
+using GMPErr from "gmp-errors.h";
 
 include "GMPMessageUtils.h";
 
 namespace mozilla {
 namespace gmp {
 
 intr protocol PGMPVideoDecoder
 {
@@ -32,16 +33,17 @@ child:
 parent:
   async __delete__();
   async Decoded(GMPVideoi420FrameData aDecodedFrame);
   async ReceivedDecodedReferenceFrame(uint64_t aPictureId);
   async ReceivedDecodedFrame(uint64_t aPictureId);
   async InputDataExhausted();
   async DrainComplete();
   async ResetComplete();
+  async Error(GMPErr aErr);
   async ParentShmemForPool(Shmem aEncodedBuffer);
   // MUST be intr - if sync and we create a new Shmem, when the returned
   // Shmem is received in the Child it will fail to Deserialize
   intr NeedShmem(uint32_t aFrameBufferSize) returns (Shmem aMem);
 };
 
 } // namespace gmp
 } // namespace mozilla
--- a/content/media/gmp/PGMPVideoEncoder.ipdl
+++ b/content/media/gmp/PGMPVideoEncoder.ipdl
@@ -3,16 +3,17 @@
  * 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 protocol PGMP;
 include GMPTypes;
 
 using GMPVideoCodec from "gmp-video-codec.h";
 using GMPVideoFrameType from "gmp-video-frame-encoded.h";
+using GMPErr from "gmp-errors.h";
 
 include "GMPMessageUtils.h";
 
 namespace mozilla {
 namespace gmp {
 
 intr protocol PGMPVideoEncoder
 {
@@ -30,16 +31,17 @@ child:
   async SetPeriodicKeyFrames(bool aEnable);
   async EncodingComplete();
   async ChildShmemForPool(Shmem aEncodedBuffer);
 
 parent:
   async __delete__();
   async Encoded(GMPVideoEncodedFrameData aEncodedFrame,
                 uint8_t[] aCodecSpecificInfo);
+  async Error(GMPErr aErr);
   async ParentShmemForPool(Shmem aFrameBuffer);
   // MUST be intr - if sync and we create a new Shmem, when the returned
   // Shmem is received in the Child it will fail to Deserialize
   intr NeedShmem(uint32_t aEncodedBufferSize) returns (Shmem aMem);
 };
 
 } // namespace gmp
 } // namespace mozilla
--- a/content/media/gmp/gmp-api/gmp-audio-decode.h
+++ b/content/media/gmp/gmp-api/gmp-audio-decode.h
@@ -30,43 +30,47 @@ public:
 
   virtual void Decoded(GMPAudioSamples* aDecodedSamples) = 0;
 
   virtual void InputDataExhausted() = 0;
 
   virtual void DrainComplete() = 0;
 
   virtual void ResetComplete() = 0;
+
+  // Called when the decoder encounters a catestrophic error and cannot
+  // continue. Gecko will not send any more input for decoding.
+  virtual void Error(GMPErr aError) = 0;
 };
 
 // ALL METHODS MUST BE CALLED ON THE MAIN THREAD
 class GMPAudioDecoder
 {
 public:
   virtual ~GMPAudioDecoder() {}
 
   // aCallback: Subclass should retain reference to it until DecodingComplete
   //            is called. Do not attempt to delete it, host retains ownership.
   // TODO: Pass AudioHost so decoder can create GMPAudioEncodedFrame objects?
-  virtual GMPErr InitDecode(const GMPAudioCodec& aCodecSettings,
-                            GMPAudioDecoderCallback* aCallback) = 0;
+  virtual void InitDecode(const GMPAudioCodec& aCodecSettings,
+                          GMPAudioDecoderCallback* aCallback) = 0;
 
   // Decode encoded audio frames (as a part of an audio stream). The decoded
   // frames must be returned to the user through the decode complete callback.
-  virtual GMPErr Decode(GMPAudioSamples* aEncodedSamples) = 0;
+  virtual void Decode(GMPAudioSamples* aEncodedSamples) = 0;
 
   // Reset decoder state and prepare for a new call to Decode(...).
   // Flushes the decoder pipeline.
   // The decoder should enqueue a task to run ResetComplete() on the main
   // thread once the reset has finished.
-  virtual GMPErr Reset() = 0;
+  virtual void Reset() = 0;
 
   // Output decoded frames for any data in the pipeline, regardless of ordering.
   // All remaining decoded frames should be immediately returned via callback.
   // The decoder should enqueue a task to run DrainComplete() on the main
   // thread once the reset has finished.
-  virtual GMPErr Drain() = 0;
+  virtual void Drain() = 0;
 
   // May free decoder memory.
   virtual void DecodingComplete() = 0;
 };
 
 #endif // GMP_VIDEO_DECODE_h_
--- a/content/media/gmp/gmp-api/gmp-audio-samples.h
+++ b/content/media/gmp/gmp-api/gmp-audio-samples.h
@@ -44,14 +44,14 @@ public:
 
   // Timestamps are in microseconds, and are the playback start time of the
   // first sample in the buffer.
   virtual void SetTimeStamp(uint64_t aTimeStamp) = 0;
   virtual uint64_t TimeStamp() = 0;
   virtual const uint8_t* Buffer() const = 0;
   virtual uint8_t*       Buffer() = 0;
 
-  // Get data describing how this frame is encrypted, or nullptr if the
+  // Get metadata describing how this frame is encrypted, or nullptr if the
   // buffer is not encrypted.
-  virtual const GMPEncryptedBufferData* GetDecryptionData() const = 0;
+  virtual const GMPEncryptedBufferMetadata* GetDecryptionData() const = 0;
 };
 
 #endif // GMP_AUDIO_FRAME_h_
--- a/content/media/gmp/gmp-api/gmp-decryption.h
+++ b/content/media/gmp/gmp-api/gmp-decryption.h
@@ -14,38 +14,47 @@
 * limitations under the License.
 */
 
 #ifndef GMP_DECRYPTION_h_
 #define GMP_DECRYPTION_h_
 
 #include "gmp-platform.h"
 
-class GMPEncryptedBufferData {
+class GMPEncryptedBufferMetadata {
 public:
   // Key ID to identify the decryption key.
   virtual const uint8_t* KeyId() const = 0;
 
   // Size (in bytes) of |KeyId()|.
   virtual uint32_t KeyIdSize() const = 0;
 
   // Initialization vector.
   virtual const uint8_t* IV() const = 0;
 
   // Size (in bytes) of |IV|.
   virtual uint32_t IVSize() const = 0;
 
-  // Number of enties returned by ClearBytes and CipherBytes().
+  // Number of entries returned by ClearBytes() and CipherBytes().
   virtual uint32_t NumSubsamples() const = 0;
 
-  virtual const uint32_t* ClearBytes() const = 0;
+  virtual const uint16_t* ClearBytes() const = 0;
 
   virtual const uint32_t* CipherBytes() const = 0;
 };
 
+class GMPBuffer {
+public:
+  virtual uint32_t Id() const = 0;
+  virtual uint8_t* Data() = 0;
+  virtual uint32_t Size() const = 0;
+  virtual void Resize(uint32_t aSize) = 0;
+  virtual ~GMPBuffer() {}
+};
+
 // These match to the DOMException codes as per:
 // http://www.w3.org/TR/dom/#domexception
 enum GMPDOMException {
   kGMPNoModificationAllowedError = 7,
   kGMPNotFoundError = 8,
   kGMPNotSupportedError = 9,
   kGMPInvalidStateError = 11,
   kGMPSyntaxError = 12,
@@ -55,81 +64,116 @@ enum GMPDOMException {
   kGMPAbortError = 20,
   kGMPQuotaExceededError = 22,
   kGMPTimeoutError = 23
 };
 
 // Time in milliseconds, as offset from epoch, 1 Jan 1970.
 typedef int64_t GMPTimestamp;
 
+// Capability definitions. The capabilities of the EME GMP are reported
+// to Gecko by calling the GMPDecryptorCallback::SetCapabilities()
+// callback and specifying the logical OR of the GMP_EME_CAP_* flags below.
+//
+// Note the DECRYPT and the DECRYPT_AND_DECODE are mutually exclusive;
+// only one mode should be reported for each stream type, but different
+// modes can be reported for different stream types.
+//
+// Note: Gecko does not currently support the caps changing at runtime.
+// Set them once per plugin initialization, during the startup of
+// the GMPdecryptor.
+
+// Capability; CDM can decrypt encrypted buffers and return still
+// compressed buffers back to Gecko for decompression there.
+#define GMP_EME_CAP_DECRYPT_AUDIO (uint64_t(1) << 0)
+#define GMP_EME_CAP_DECRYPT_VIDEO (uint64_t(1) << 1)
+
+// Capability; CDM can decrypt and then decode encrypted buffers,
+// and return decompressed samples to Gecko for playback.
+#define GMP_EME_CAP_DECRYPT_AND_DECODE_AUDIO (uint64_t(1) << 2)
+#define GMP_EME_CAP_DECRYPT_AND_DECODE_VIDEO (uint64_t(1) << 3)
+
 class GMPDecryptorCallback {
 public:
   // Resolves a promise for a session created or loaded.
   // Passes the session id to be exposed to JavaScript.
-  // Must be called before OnSessionMessage().
+  // Must be called before SessionMessage().
   // aSessionId must be null terminated.
-  virtual void OnResolveNewSessionPromise(uint32_t aPromiseId,
-                                          const char* aSessionId,
-                                          uint32_t aSessionIdLength) = 0;
+  virtual void ResolveNewSessionPromise(uint32_t aPromiseId,
+                                        const char* aSessionId,
+                                        uint32_t aSessionIdLength) = 0;
 
   // Called to resolve a specified promise with "undefined".
-  virtual void OnResolvePromise(uint32_t aPromiseId) = 0;
+  virtual void ResolvePromise(uint32_t aPromiseId) = 0;
 
   // Called to reject a promise with a DOMException.
   // aMessage is logged to the WebConsole.
   // aMessage is optional, but if present must be null terminated.
-  virtual void OnRejectPromise(uint32_t aPromiseId,
-                               GMPDOMException aException,
-                               const char* aMessage,
-                               uint32_t aMessageLength) = 0;
+  virtual void RejectPromise(uint32_t aPromiseId,
+                             GMPDOMException aException,
+                             const char* aMessage,
+                             uint32_t aMessageLength) = 0;
 
   // Called by the CDM when it has a message for session |session_id|.
   // Length parameters should not include null termination.
   // aSessionId must be null terminated.
-  virtual void OnSessionMessage(const char* aSessionId,
-                                uint32_t aSessionIdLength,
-                                const uint8_t* aMessage,
-                                uint32_t aMessageLength,
-                                const char* aDestinationURL,
-                                uint32_t aDestinationURLLength) = 0;
+  virtual void SessionMessage(const char* aSessionId,
+                              uint32_t aSessionIdLength,
+                              const uint8_t* aMessage,
+                              uint32_t aMessageLength,
+                              const char* aDestinationURL,
+                              uint32_t aDestinationURLLength) = 0;
 
   // aSessionId must be null terminated.
-   virtual void OnExpirationChange(const char* aSessionId,
-                                   uint32_t aSessionIdLength,
-                                   GMPTimestamp aExpiryTime) = 0;
+   virtual void ExpirationChange(const char* aSessionId,
+                                 uint32_t aSessionIdLength,
+                                 GMPTimestamp aExpiryTime) = 0;
 
   // Called by the GMP when a session is closed. All file IO
   // that a session requires should be complete before calling this.
   // aSessionId must be null terminated.
-  virtual void OnSessionClosed(const char* aSessionId,
-                               uint32_t aSessionIdLength) = 0;
+  virtual void SessionClosed(const char* aSessionId,
+                             uint32_t aSessionIdLength) = 0;
 
   // Called by the GMP when an error occurs in a session.
   // aSessionId must be null terminated.
   // aMessage is logged to the WebConsole.
   // aMessage is optional, but if present must be null terminated.
-  virtual void OnSessionError(const char* aSessionId,
-                              uint32_t aSessionIdLength,
-                              GMPDOMException aException,
-                              uint32_t aSystemCode,
-                              const char* aMessage,
-                              uint32_t aMessageLength) = 0;
+  virtual void SessionError(const char* aSessionId,
+                            uint32_t aSessionIdLength,
+                            GMPDOMException aException,
+                            uint32_t aSystemCode,
+                            const char* aMessage,
+                            uint32_t aMessageLength) = 0;
 
-  virtual void OnKeyIdUsable(const char* aSessionId,
-                             uint32_t aSessionIdLength,
-                             const uint8_t* aKeyId,
-                             uint32_t aKeyIdLength) = 0;
+  // Marks a key as usable. Gecko will not call into the CDM to decrypt
+  // or decode content encrypted with a key unless the CDM has marked it
+  // usable first. So a CDM *MUST* mark its usable keys as usable!
+  virtual void KeyIdUsable(const char* aSessionId,
+                           uint32_t aSessionIdLength,
+                           const uint8_t* aKeyId,
+                           uint32_t aKeyIdLength) = 0;
 
   // Marks a key as no longer usable.
   // Note: Keys are assumed to be not usable when a session is closed or removed.
-  virtual void OnKeyIdNotUsable(const char* aSessionId,
-                                uint32_t aSessionIdLength,
-                                const uint8_t* aKeyId,
-                                uint32_t aKeyIdLength) = 0;
+  virtual void KeyIdNotUsable(const char* aSessionId,
+                              uint32_t aSessionIdLength,
+                              const uint8_t* aKeyId,
+                              uint32_t aKeyIdLength) = 0;
 
+  // The CDM must report its capabilites of this CDM. aCaps should be a
+  // logical OR of the GMP_EME_CAP_* flags. The CDM *MUST* call this
+  // function and report whether it can decrypt and/or decode. Without
+  // this, Gecko does not know how to use the CDM and will not send
+  // samples to the CDM to decrypt or decrypt-and-decode mode. Note a
+  // CDM cannot change modes once playback has begun.
+  virtual void SetCapabilities(uint64_t aCaps) = 0;
+
+  // Returns decrypted buffer to Gecko, or reports failure.
+  virtual void Decrypted(GMPBuffer* aBuffer, GMPErr aResult) = 0;
 };
 
 // Host interface, passed to GetAPIFunc(), with "decrypt".
 class GMPDecryptorHost {
 public:
 
   // Returns an origin specific string uniquely identifying the device.
   // The node id contains a random component, and is consistent between
@@ -161,20 +205,24 @@ enum GMPSessionType {
 class GMPDecryptor {
 public:
 
   // Sets the callback to use with the decryptor to return results
   // to Gecko.
   virtual void Init(GMPDecryptorCallback* aCallback) = 0;
 
   // Requests the creation of a session given |aType| and |aInitData|.
-  // Decryptor should callback GMPDecryptorCallback::OnSessionCreated()
-  // with the web session ID on success, or OnSessionError() on failure,
-  // and then call OnSessionReady() once all keys for that session are
-  // available.
+  // Decryptor should callback GMPDecryptorCallback::SessionCreated()
+  // with the web session ID on success, or SessionError() on failure,
+  // and then call KeyIdUsable() as keys for that session become
+  // usable.
+  //
+  // The CDM must also call GMPDecryptorCallback::SetCapabilities()
+  // exactly once during start up, to inform Gecko whether to use the CDM
+  // in decrypt or decrypt-and-decode mode.
   virtual void CreateSession(uint32_t aPromiseId,
                              const char* aInitDataType,
                              uint32_t aInitDataTypeSize,
                              const uint8_t* aInitData,
                              uint32_t aInitDataSize,
                              GMPSessionType aSessionType) = 0;
 
   // Loads a previously loaded persistent session.
@@ -198,11 +246,24 @@ public:
   virtual void RemoveSession(uint32_t aPromiseId,
                              const char* aSessionId,
                              uint32_t aSessionIdLength) = 0;
 
   // Resolve/reject promise on completion.
   virtual void SetServerCertificate(uint32_t aPromiseId,
                                     const uint8_t* aServerCert,
                                     uint32_t aServerCertSize) = 0;
+
+  // Asynchronously decrypts aBuffer in place. When the decryption is
+  // complete, GMPDecryptor should write the decrypted data back into the
+  // same GMPBuffer object and return it to Gecko by calling Decrypted(),
+  // with the GMPNoErr successcode. If decryption fails, call Decrypted()
+  // with a failure code, and an error event will fire on the media element.
+  virtual void Decrypt(GMPBuffer* aBuffer,
+                       GMPEncryptedBufferMetadata* aMetadata) = 0;
+
+  // Called when the decryption operations are complete.
+  // Do not call the GMPDecryptorCallback's functions after this is called.
+  virtual void DecryptingComplete() = 0;
+
 };
 
 #endif // GMP_DECRYPTION_h_
--- a/content/media/gmp/gmp-api/gmp-errors.h
+++ b/content/media/gmp/gmp-api/gmp-errors.h
@@ -34,17 +34,21 @@
 #define GMP_ERRORS_h_
 
 typedef enum {
   GMPNoErr = 0,
   GMPGenericErr = 1,
   GMPClosedErr = 2,
   GMPAllocErr = 3,
   GMPNotImplementedErr = 4,
-  GMPNotClosedErr = 5,
+  GMPRecordInUse = 5,
   GMPQuotaExceededErr = 6,
+  GMPDecodeErr = 7,
+  GMPEncodeErr = 8,
+  GMPNoKeyErr = 9,
+  GMPCryptoErr = 10,
   GMPLastErr // Placeholder, must be last. This enum's values must remain consecutive!
 } GMPErr;
 
 #define GMP_SUCCEEDED(x) ((x) == GMPNoErr)
 #define GMP_FAILED(x) ((x) != GMPNoErr)
 
 #endif // GMP_ERRORS_h_
--- a/content/media/gmp/gmp-api/gmp-storage.h
+++ b/content/media/gmp/gmp-api/gmp-storage.h
@@ -16,75 +16,78 @@
 
 #ifndef GMP_STORAGE_h_
 #define GMP_STORAGE_h_
 
 #include "gmp-errors.h"
 #include <stdint.h>
 
 // Provides basic per-origin storage for CDMs. GMPRecord instances can be
-// retrieved by calling GMPPlatformAPI->openstorage. Multiple GMPRecord
-// can be open at once. This interface is asynchronous, with results
-// being returned via callbacks to the GMPRecordClient pointer provided
-// to the GMPPlatformAPI->openstorage call, on the main thread.
+// retrieved by calling GMPPlatformAPI->openstorage. Multiple GMPRecords
+// with different names can be open at once, but a single record can only
+// be opened by one client at a time. This interface is asynchronous, with
+// results being returned via callbacks to the GMPRecordClient pointer
+// provided to the GMPPlatformAPI->openstorage call, on the main thread.
 class GMPRecord {
 public:
 
-  // Opens the record. Calls OnOpenComplete() once the record is open.
-  // Note: OnReadComplete() is only called if this returns GMPNoErr.
+  // Opens the record. Calls OpenComplete() once the record is open.
+  // Note: OpenComplete() is only called if this returns GMPNoErr.
   virtual GMPErr Open() = 0;
 
-  // Reads the entire contents of the file, and calls
-  // GMPRecordClient::OnReadComplete() once the operation is complete.
-  // Note: OnReadComplete() is only called if this returns GMPNoErr.
+  // Reads the entire contents of the record, and calls
+  // GMPRecordClient::ReadComplete() once the operation is complete.
+  // Note: ReadComplete() is only called if this returns GMPNoErr.
   virtual GMPErr Read() = 0;
 
-  // Writes aDataSize bytes of aData into the file, overwritting the contents
-  // of the file. Overwriting with 0 bytes "deletes" the file.
-  // Write 0 bytes to "delete" a file.
-  // Note: OnWriteComplete is only called if this returns GMPNoErr.
+  // Writes aDataSize bytes of aData into the record, overwriting the
+  // contents of the record. Overwriting with 0 bytes "deletes" the file.
+  // Note: WriteComplete is only called if this returns GMPNoErr.
   virtual GMPErr Write(const uint8_t* aData, uint32_t aDataSize) = 0;
 
-  // Closes a file. File must not be used after this is called. Cancels all
-  // callbacks.
+  // Closes a record. GMPRecord object must not be used after this is
+  // called, request a new one with GMPPlatformAPI->openstorage to re-open
+  // this record. Cancels all callbacks.
   virtual GMPErr Close() = 0;
 
   virtual ~GMPRecord() {}
 };
 
 // Callback object that receives the results of GMPRecord calls. Callbacks
 // run asynchronously to the GMPRecord call, on the main thread.
 class GMPRecordClient {
  public:
 
   // Response to a GMPRecord::Open() call with the open |status|.
   // aStatus values:
-  // - GMPNoErr - File opened successfully. File may be empty.
-  // - GMPFileInUse - There file is in use by another client.
+  // - GMPNoErr - Record opened successfully. Record may be empty.
+  // - GMPRecordInUse - This record is in use by another client.
   // - GMPGenericErr - Unspecified error.
   // Do not use the GMPRecord if aStatus is not GMPNoErr.
-  virtual void OnOpenComplete(GMPErr aStatus) = 0;
+  virtual void OpenComplete(GMPErr aStatus) = 0;
 
-  // Response to a GMPRecord::Read() call, where aData is the file contents,
+  // Response to a GMPRecord::Read() call, where aData is the record contents,
   // of length aDataSize.
-  // aData is only valid for the duration of the call to OnReadComplete.
+  // aData is only valid for the duration of the call to ReadComplete.
   // Copy it if you want to hang onto it!
   // aStatus values:
-  // - GMPNoErr - File contents read successfully, aDataSize 0 means file
+  // - GMPNoErr - Record contents read successfully, aDataSize 0 means record
   //   is empty.
-  // - GMPFileInUse - There are other operations or clients in use on this file.
+  // - GMPRecordInUse - There are other operations or clients in use on
+  //   this record.
   // - GMPGenericErr - Unspecified error.
   // Do not continue to use the GMPRecord if aStatus is not GMPNoErr.
-  virtual void OnReadComplete(GMPErr aStatus,
-                              const uint8_t* aData,
-                              uint32_t aDataSize) = 0;
+  virtual void ReadComplete(GMPErr aStatus,
+                            const uint8_t* aData,
+                            uint32_t aDataSize) = 0;
 
   // Response to a GMPRecord::Write() call.
   // - GMPNoErr - File contents written successfully.
-  // - GMPFileInUse - There are other operations or clients in use on this file.
-  // - GMPGenericErr - Unspecified error. File should be regarded as corrupt.
+  // - GMPRecordInUse - There are other operations or clients in use on
+  //   this record.
+  // - GMPGenericErr - Unspecified error.
   // Do not continue to use the GMPRecord if aStatus is not GMPNoErr.
-  virtual void OnWriteComplete(GMPErr aStatus) = 0;
+  virtual void WriteComplete(GMPErr aStatus) = 0;
 
   virtual ~GMPRecordClient() {}
 };
 
 #endif // GMP_STORAGE_h_
--- a/content/media/gmp/gmp-api/gmp-video-decode.h
+++ b/content/media/gmp/gmp-api/gmp-video-decode.h
@@ -52,64 +52,68 @@ public:
 
   virtual void ReceivedDecodedFrame(const uint64_t aPictureId) = 0;
 
   virtual void InputDataExhausted() = 0;
 
   virtual void DrainComplete() = 0;
 
   virtual void ResetComplete() = 0;
+
+  // Called when the decoder encounters a catestrophic error and cannot
+  // continue. Gecko will not send any more input for decoding.
+  virtual void Error(GMPErr aError) = 0;
 };
 
 // ALL METHODS MUST BE CALLED ON THE MAIN THREAD
 class GMPVideoDecoder
 {
 public:
   virtual ~GMPVideoDecoder() {}
 
   // - aCodecSettings: Details of decoder to create.
   // - aCodecSpecific: codec specific data, cast to a GMPVideoCodecXXX struct
   //                   to get codec specific config data.
   // - aCodecSpecificLength: number of bytes in aCodecSpecific.
   // - aCallback: Subclass should retain reference to it until DecodingComplete
   //              is called. Do not attempt to delete it, host retains ownership.
   // aCoreCount: number of CPU cores.
-  virtual GMPErr InitDecode(const GMPVideoCodec& aCodecSettings,
-                            const uint8_t* aCodecSpecific,
-                            uint32_t aCodecSpecificLength,
-                            GMPVideoDecoderCallback* aCallback,
-                            int32_t aCoreCount) = 0;
+  virtual void InitDecode(const GMPVideoCodec& aCodecSettings,
+                          const uint8_t* aCodecSpecific,
+                          uint32_t aCodecSpecificLength,
+                          GMPVideoDecoderCallback* aCallback,
+                          int32_t aCoreCount) = 0;
 
   // Decode encoded frame (as a part of a video stream). The decoded frame
   // will be returned to the user through the decode complete callback.
   //
   // - aInputFrame: Frame to decode. Call Destroy() on frame when it's decoded.
   // - aMissingFrames: True if one or more frames have been lost since the
   //                   previous decode call.
   // - aCodecSpecificInfo : codec specific data, pointer to a
   //                        GMPCodecSpecificInfo structure appropriate for
   //                        this codec type.
   // - aCodecSpecificInfoLength : number of bytes in aCodecSpecificInfo
   // - renderTimeMs : System time to render in milliseconds. Only used by
   //                  decoders with internal rendering.
-  virtual GMPErr Decode(GMPVideoEncodedFrame* aInputFrame,
-                        bool aMissingFrames,
-                        const uint8_t* aCodecSpecificInfo,
-                        uint32_t aCodecSpecificInfoLength,
-                        int64_t aRenderTimeMs = -1) = 0;
+  virtual void Decode(GMPVideoEncodedFrame* aInputFrame,
+                      bool aMissingFrames,
+                      const uint8_t* aCodecSpecificInfo,
+                      uint32_t aCodecSpecificInfoLength,
+                      int64_t aRenderTimeMs = -1) = 0;
 
   // Reset decoder state and prepare for a new call to Decode(...).
   // Flushes the decoder pipeline.
   // The decoder should enqueue a task to run ResetComplete() on the main
   // thread once the reset has finished.
-  virtual GMPErr Reset() = 0;
+  virtual void Reset() = 0;
 
   // Output decoded frames for any data in the pipeline, regardless of ordering.
   // All remaining decoded frames should be immediately returned via callback.
   // The decoder should enqueue a task to run DrainComplete() on the main
   // thread once the reset has finished.
-  virtual GMPErr Drain() = 0;
+  virtual void Drain() = 0;
 
   // May free decoder memory.
   virtual void DecodingComplete() = 0;
 };
 
 #endif // GMP_VIDEO_DECODE_h_
--- a/content/media/gmp/gmp-api/gmp-video-encode.h
+++ b/content/media/gmp/gmp-api/gmp-video-encode.h
@@ -46,16 +46,20 @@
 class GMPVideoEncoderCallback
 {
 public:
   virtual ~GMPVideoEncoderCallback() {}
 
   virtual void Encoded(GMPVideoEncodedFrame* aEncodedFrame,
                        const uint8_t* aCodecSpecificInfo,
                        uint32_t aCodecSpecificInfoLength) = 0;
+
+  // Called when the encoder encounters a catestrophic error and cannot
+  // continue. Gecko will not send any more input for encoding.
+  virtual void Error(GMPErr aError) = 0;
 };
 
 // ALL METHODS MUST BE CALLED ON THE MAIN THREAD
 class GMPVideoEncoder
 {
 public:
   virtual ~GMPVideoEncoder() {}
 
@@ -67,57 +71,57 @@ public:
   //                    GMPCodecSpecific structure appropriate for
   //                    this codec type.
   // - aCodecSpecificLength : number of bytes in aCodecSpecific
   // - aCallback: Subclass should retain reference to it until EncodingComplete
   //              is called. Do not attempt to delete it, host retains ownership.
   // - aNnumberOfCores : Number of cores available for the encoder
   // - aMaxPayloadSize : The maximum size each payload is allowed
   //                    to have. Usually MTU - overhead.
-  virtual GMPErr InitEncode(const GMPVideoCodec& aCodecSettings,
-                            const uint8_t* aCodecSpecific,
-                            uint32_t aCodecSpecificLength,
-                            GMPVideoEncoderCallback* aCallback,
-                            int32_t aNumberOfCores,
-                            uint32_t aMaxPayloadSize) = 0;
+  virtual void InitEncode(const GMPVideoCodec& aCodecSettings,
+                          const uint8_t* aCodecSpecific,
+                          uint32_t aCodecSpecificLength,
+                          GMPVideoEncoderCallback* aCallback,
+                          int32_t aNumberOfCores,
+                          uint32_t aMaxPayloadSize) = 0;
 
   // Encode an I420 frame (as a part of a video stream). The encoded frame
   // will be returned to the user through the encode complete callback.
   //
   // Input:
   // - aInputFrame : Frame to be encoded
   // - aCodecSpecificInfo : codec specific data, pointer to a
   //                        GMPCodecSpecificInfo structure appropriate for
   //                        this codec type.
   // - aCodecSpecificInfoLength : number of bytes in aCodecSpecific
   // - aFrameTypes : The frame type to encode
   // - aFrameTypesLength : The number of elements in aFrameTypes array.
-  virtual GMPErr Encode(GMPVideoi420Frame* aInputFrame,
-                        const uint8_t* aCodecSpecificInfo,
-                        uint32_t aCodecSpecificInfoLength,
-                        const GMPVideoFrameType* aFrameTypes,
-                        uint32_t aFrameTypesLength) = 0;
+  virtual void Encode(GMPVideoi420Frame* aInputFrame,
+                      const uint8_t* aCodecSpecificInfo,
+                      uint32_t aCodecSpecificInfoLength,
+                      const GMPVideoFrameType* aFrameTypes,
+                      uint32_t aFrameTypesLength) = 0;
 
   // Inform the encoder about the packet loss and round trip time on the
   // network used to decide the best pattern and signaling.
   //
   // - packetLoss : Fraction lost (loss rate in percent =
   // 100 * packetLoss / 255)
   // - rtt : Round-trip time in milliseconds
-  virtual GMPErr SetChannelParameters(uint32_t aPacketLoss, uint32_t aRTT) = 0;
+  virtual void SetChannelParameters(uint32_t aPacketLoss, uint32_t aRTT) = 0;
 
   // Inform the encoder about the new target bit rate.
   //
   // - newBitRate : New target bit rate
   // - frameRate : The target frame rate
-  virtual GMPErr SetRates(uint32_t aNewBitRate, uint32_t aFrameRate) = 0;
+  virtual void SetRates(uint32_t aNewBitRate, uint32_t aFrameRate) = 0;
 
   // Use this function to enable or disable periodic key frames. Can be useful for codecs
   // which have other ways of stopping error propagation.
   //
   // - enable : Enable or disable periodic key frames
-  virtual GMPErr SetPeriodicKeyFrames(bool aEnable) = 0;
+  virtual void SetPeriodicKeyFrames(bool aEnable) = 0;
 
   // May free Encoder memory.
   virtual void EncodingComplete() = 0;
 };
 
 #endif // GMP_VIDEO_ENCODE_h_
--- a/content/media/gmp/gmp-api/gmp-video-frame-encoded.h
+++ b/content/media/gmp/gmp-api/gmp-video-frame-encoded.h
@@ -85,14 +85,14 @@ public:
   virtual uint32_t Size() = 0;
   virtual void     SetCompleteFrame(bool aCompleteFrame) = 0;
   virtual bool     CompleteFrame() = 0;
   virtual const uint8_t* Buffer() const = 0;
   virtual uint8_t*       Buffer() = 0;
   virtual GMPBufferType  BufferType() const = 0;
   virtual void     SetBufferType(GMPBufferType aBufferType) = 0;
 
-  // Get data describing how this frame is encrypted, or nullptr if the
+  // Get metadata describing how this frame is encrypted, or nullptr if the
   // frame is not encrypted.
-  virtual const GMPEncryptedBufferData* GetDecryptionData() const = 0;
+  virtual const GMPEncryptedBufferMetadata* GetDecryptionData() const = 0;
 };
 
 #endif // GMP_VIDEO_FRAME_ENCODED_h_
--- a/content/media/mediasource/MediaSourceDecoder.cpp
+++ b/content/media/mediasource/MediaSourceDecoder.cpp
@@ -19,16 +19,21 @@
 #include "nsIThread.h"
 #include "prlog.h"
 #include "MediaSource.h"
 #include "SubBufferDecoder.h"
 #include "SourceBufferResource.h"
 #include "SourceBufferList.h"
 #include "VideoUtils.h"
 
+#ifdef MOZ_FMP4
+#include "MP4Decoder.h"
+#include "MP4Reader.h"
+#endif
+
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* gMediaSourceLog;
 #define MSE_DEBUG(...) PR_LOG(gMediaSourceLog, PR_LOG_DEBUG, (__VA_ARGS__))
 #else
 #define MSE_DEBUG(...)
 #endif
 
 namespace mozilla {
@@ -413,25 +418,42 @@ MediaSourceReader::InitializePendingDeco
       MSE_DEBUG("%p: Reader %p not activated", this, reader);
     }
   }
   NS_DispatchToMainThread(new ReleaseDecodersTask(mPendingDecoders));
   MOZ_ASSERT(mPendingDecoders.IsEmpty());
   mDecoder->NotifyWaitingForResourcesStatusChanged();
 }
 
+MediaDecoderReader*
+CreateReaderForType(const nsACString& aType, AbstractMediaDecoder* aDecoder)
+{
+#ifdef MOZ_FMP4
+  // The MP4Reader that supports fragmented MP4 and uses
+  // PlatformDecoderModules is hidden behind prefs for regular video
+  // elements, but we always want to use it for MSE, so instantiate it
+  // directly here.
+  if ((aType.LowerCaseEqualsLiteral("video/mp4") ||
+       aType.LowerCaseEqualsLiteral("audio/mp4")) &&
+      MP4Decoder::IsEnabled()) {
+    return new MP4Reader(aDecoder);
+  }
+#endif
+  return DecoderTraits::CreateReader(aType, aDecoder);
+}
+
 already_AddRefed<SubBufferDecoder>
 MediaSourceReader::CreateSubDecoder(const nsACString& aType,
                                     MediaSourceDecoder* aParentDecoder,
                                     MediaTaskQueue* aTaskQueue)
 {
   // XXX: Why/when is mDecoder null here, since it should be equal to aParentDecoder?!
   nsRefPtr<SubBufferDecoder> decoder =
     new SubBufferDecoder(new SourceBufferResource(nullptr, aType), aParentDecoder);
-  nsRefPtr<MediaDecoderReader> reader(DecoderTraits::CreateReader(aType, decoder));
+  nsRefPtr<MediaDecoderReader> reader(CreateReaderForType(aType, decoder));
   if (!reader) {
     return nullptr;
   }
   // Set a callback on the subreader that forwards calls to this reader.
   // This reader will then forward them onto the state machine via this
   // reader's callback.
   RefPtr<MediaDataDecodedListener<MediaSourceReader>> callback =
     new MediaDataDecodedListener<MediaSourceReader>(this, aTaskQueue);
--- a/content/media/omx/moz.build
+++ b/content/media/omx/moz.build
@@ -43,17 +43,17 @@ if 'rtsp' in CONFIG['NECKO_PROTOCOLS']:
         'RtspOmxDecoder.h',
         'RtspOmxReader.h',
     ]
     SOURCES += [
         'RtspOmxDecoder.cpp',
         'RtspOmxReader.cpp',
     ]
 
-if CONFIG['ANDROID_VERSION'] and int(CONFIG['ANDROID_VERSION']) >= 18:
+if CONFIG['ANDROID_VERSION'] >= '18':
     EXPORTS += [
         'I420ColorConverterHelper.h',
         'MediaCodecDecoder.h',
         'MediaCodecProxy.h',
         'MediaCodecReader.h',
     ]
     SOURCES += [
         'I420ColorConverterHelper.cpp',
--- a/content/media/test/mochitest.ini
+++ b/content/media/test/mochitest.ini
@@ -17,17 +17,17 @@
 # throws an error (and does not cause a crash or hang), just add it to
 # gErrorTests in manifest.js.
 
 # To test for a specific bug in handling a specific resource type, make the
 # test first check canPlayType for the type, and if it's not supported, just
 # do ok(true, "Type not supported") and stop the test.
 
 [DEFAULT]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug,b2g-desktop(bug 918299)
+skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug,b2g-desktop(bug 918299)
 support-files =
   320x240.ogv
   320x240.ogv^headers^
   448636.ogv
   448636.ogv^headers^
   VID_0001.ogg
   VID_0001.ogg^headers^
   allowed.sjs
@@ -301,17 +301,17 @@ support-files =
 [test_audio1.html]
 [test_audio2.html]
 [test_audioDocumentTitle.html]
 skip-if = true # bug 475110 - disabled since we don't play Wave files standalone
 [test_autoplay.html]
 [test_autoplay_contentEditable.html]
 [test_buffered.html]
 [test_bug448534.html]
-skip-if = os == 'win' # bug 894922
+skip-if = buildapp == 'mulet' || os == 'win' # bug 894922
 [test_bug463162.xhtml]
 [test_bug465498.html]
 [test_bug493187.html]
 [test_bug495145.html]
 [test_bug495300.html]
 [test_bug654550.html]
 [test_bug686942.html]
 [test_bug726904.html]
--- a/content/media/webspeech/recognition/test/mochitest.ini
+++ b/content/media/webspeech/recognition/test/mochitest.ini
@@ -5,15 +5,15 @@ support-files =
   hello.ogg^headers^
   silence.ogg
   silence.ogg^headers^
 
 [test_abort.html]
 [test_audio_capture_error.html]
 [test_call_start_from_end_handler.html]
 [test_nested_eventloop.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(showmodaldialog)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(showmodaldialog)
 [test_preference_enable.html]
 [test_recognition_service_error.html]
 skip-if = buildapp == 'b2g' # b2g(timed out)
 [test_success_without_recognition_service.html]
 [test_timeout.html]
 skip-if = os == "win"
--- a/content/svg/content/test/mochitest.ini
+++ b/content/svg/content/test/mochitest.ini
@@ -81,17 +81,17 @@ skip-if = true
 [test_SVGxxxList.xhtml]
 [test_switch.xhtml]
 [test_text_2.html]
 [test_text_dirty.html]
 [test_text.html]
 [test_text_lengthAdjust.html]
 [test_text_scaled.html]
 [test_text_selection.html]
-skip-if = buildapp == 'b2g' # b2g(Mouse selection not workin on b2g) b2g-debug(Mouse selection not workin on b2g) b2g-desktop(Mouse selection not workin on b2g)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' # b2g(Mouse selection not workin on b2g) b2g-debug(Mouse selection not workin on b2g) b2g-desktop(Mouse selection not workin on b2g)
 [test_text_update.html]
 [test_transform.xhtml]
 [test_transformParsing.html]
 [test_valueAsString.xhtml]
 [test_valueLeaks.xhtml]
 [test_viewport.html]
 [test_zoom.xhtml]
 
--- a/content/xul/content/test/mochitest.ini
+++ b/content/xul/content/test/mochitest.ini
@@ -1,6 +1,6 @@
 [DEFAULT]
-skip-if = buildapp == 'b2g' #tests that use xul
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' #tests that use xul
 
 [test_bug486990.xul]
 skip-if = toolkit == 'android' #TIMED_OUT
 [test_bug749367.xul]
--- a/content/xul/templates/tests/chrome/chrome.ini
+++ b/content/xul/templates/tests/chrome/chrome.ini
@@ -1,9 +1,10 @@
 [DEFAULT]
+skip-if = buildapp == 'mulet'
 support-files =
   animals.rdf
   animals.sqlite
   animals.xml
   bug441785-1.rdf
   bug441785-2.rdf
   templates_shared.js
 
--- a/docshell/test/browser/browser.ini
+++ b/docshell/test/browser/browser.ini
@@ -67,18 +67,19 @@ skip-if = e10s # Bug ?????? - test touch
 skip-if = e10s # Bug ?????? - test touches content (newBrowser.contentDocument.nodePrincipal)
 [browser_bug388121-2.js]
 skip-if = e10s # Bug ?????? - test touches content (newBrowser.contentDocument.nodePrincipal)
 [browser_bug420605.js]
 skip-if = e10s # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly
 [browser_bug422543.js]
 skip-if = e10s # Bug ?????? - obscure test failures (shistory has a new entry - Got initial, expected newentry)
 [browser_bug441169.js]
+skip-if = buildapp == 'mulet'
 [browser_bug503832.js]
-skip-if = e10s # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly
+skip-if = buildapp == 'mulet' || e10s # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly
 [browser_bug554155.js]
 [browser_bug655270.js]
 skip-if = e10s # Bug ?????? - PlacesUtils.history.addObserver notifications don't seem to fire
 [browser_bug655273.js]
 [browser_bug670318.js]
 skip-if = e10s # Bug 916974 - browser.sessionHistory is null
 [browser_bug673467.js]
 skip-if = e10s # Bug ?????? - test touches content (adds event listener to content document's iframe)
--- a/docshell/test/chrome/chrome.ini
+++ b/docshell/test/chrome/chrome.ini
@@ -51,20 +51,22 @@ support-files =
 [test_bug113934.xul]
 [test_bug215405.xul]
 [test_bug293235.xul]
 [test_bug294258.xul]
 [test_bug298622.xul]
 [test_bug301397.xul]
 [test_bug303267.xul]
 [test_bug311007.xul]
+skip-if = buildapp == 'mulet'
 [test_bug321671.xul]
 [test_bug360511.xul]
 [test_bug364461.xul]
 [test_bug396519.xul]
+skip-if = buildapp == 'mulet'
 [test_bug396649.xul]
 [test_bug428288.html]
 [test_bug449778.xul]
 [test_bug449780.xul]
 [test_bug453650.xul]
 [test_bug454235.xul]
 # bug 684176
 skip-if = toolkit == "gtk2"
--- a/docshell/test/mochitest.ini
+++ b/docshell/test/mochitest.ini
@@ -35,36 +35,36 @@ support-files =
   file_pushState_after_document_open.html
   historyframes.html
 
 [test_anchor_scroll_after_document_open.html]
 [test_bfcache_plus_hash.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug123696.html]
 [test_bug369814.html]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
+skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug384014.html]
 [test_bug385434.html]
 [test_bug387979.html]
 [test_bug402210.html]
 [test_bug404548.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug413310.html]
 skip-if = true || toolkit == 'android' || buildapp == 'b2g'
 # Disabled for too many intermittent failures (bug 719186)
 [test_bug475636.html]
 [test_bug509055.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug511449.html]
 skip-if = toolkit != "cocoa" || e10s
 support-files = file_bug511449.html
 [test_bug529119-1.html]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
+skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug529119-2.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(debug-only failure) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
+skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(debug-only failure) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
 [test_bug530396.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Timeouts on B2G desktop
 support-files = bug530396-noref.sjs bug530396-subframe.html
 [test_bug540462.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug551225.html]
 [test_bug570341.html]
 skip-if = (toolkit == 'gonk' && debug) #debug-only failure
--- a/dom/alarm/test/mochitest.ini
+++ b/dom/alarm/test/mochitest.ini
@@ -1,20 +1,20 @@
 [DEFAULT]
 skip-if = e10s
 
 support-files =
   file_empty.html
 
 [test_alarm_add_data.html]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
+skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_alarm_add_date.html]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
+skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_alarm_add_respectTimezone.html]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
+skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_alarm_non_permitted_app.html]
 [test_alarm_permitted_app.html]
 [test_alarm_remove.html]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
+skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug1015540.html]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
+skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug1037079.html]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
+skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
--- a/dom/animation/AnimationTimeline.cpp
+++ b/dom/animation/AnimationTimeline.cpp
@@ -1,16 +1,15 @@
 /* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
 /* 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 "AnimationTimeline.h"
 #include "mozilla/dom/AnimationTimelineBinding.h"
-#include "mozilla/TimeStamp.h"
 #include "nsContentUtils.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsRefreshDriver.h"
 #include "nsDOMNavigationTiming.h"
 
 namespace mozilla {
 namespace dom {
@@ -31,29 +30,45 @@ AnimationTimeline::GetCurrentTime() cons
 {
   return ToTimelineTime(GetCurrentTimeStamp());
 }
 
 TimeStamp
 AnimationTimeline::GetCurrentTimeStamp() const
 {
   // Always return the same object to benefit from return-value optimization.
-  TimeStamp result; // Initializes to null timestamp
+  TimeStamp result = mLastCurrentTime;
+
+  // If we've never been sampled, initialize the current time to the timeline's
+  // zero time since that is the time we'll use if we don't have a refresh
+  // driver.
+  if (result.IsNull()) {
+    nsRefPtr<nsDOMNavigationTiming> timing = mDocument->GetNavigationTiming();
+    if (!timing) {
+      return result;
+    }
+    result = timing->GetNavigationStartTimeStamp();
+  }
 
   nsIPresShell* presShell = mDocument->GetShell();
   if (MOZ_UNLIKELY(!presShell)) {
     return result;
   }
 
   nsPresContext* presContext = presShell->GetPresContext();
   if (MOZ_UNLIKELY(!presContext)) {
     return result;
   }
 
   result = presContext->RefreshDriver()->MostRecentRefresh();
+  // FIXME: We would like to assert that:
+  //   mLastCurrentTime.IsNull() || result >= mLastCurrentTime
+  // but due to bug 1043078 this will not be the case when the refresh driver
+  // is restored from test control.
+  mLastCurrentTime = result;
   return result;
 }
 
 Nullable<double>
 AnimationTimeline::ToTimelineTime(const mozilla::TimeStamp& aTimeStamp) const
 {
   Nullable<double> result; // Initializes to null
   if (aTimeStamp.IsNull()) {
--- a/dom/animation/AnimationTimeline.h
+++ b/dom/animation/AnimationTimeline.h
@@ -4,25 +4,23 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_AnimationTimeline_h
 #define mozilla_dom_AnimationTimeline_h
 
 #include "nsWrapperCache.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/TimeStamp.h"
 #include "js/TypeDecls.h"
 #include "nsIDocument.h"
 
 struct JSContext;
 
 namespace mozilla {
-
-class TimeStamp;
-
 namespace dom {
 
 class AnimationTimeline MOZ_FINAL : public nsWrapperCache
 {
 public:
   AnimationTimeline(nsIDocument* aDocument)
     : mDocument(aDocument)
   {
@@ -39,14 +37,19 @@ public:
   mozilla::TimeStamp GetCurrentTimeStamp() const;
 
   Nullable<double> ToTimelineTime(const mozilla::TimeStamp& aTimeStamp) const;
 
 protected:
   virtual ~AnimationTimeline() { }
 
   nsCOMPtr<nsIDocument> mDocument;
+
+  // Store the most recently returned value of current time. This is used
+  // in cases where we don't have a refresh driver (e.g. because we are in
+  // a display:none iframe).
+  mutable mozilla::TimeStamp mLastCurrentTime;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_AnimationTimeline_h
--- a/dom/animation/test/animation-timeline/test_animation-timeline.html
+++ b/dom/animation/test/animation-timeline/test_animation-timeline.html
@@ -2,16 +2,17 @@
 <meta charset=utf-8>
 <title>Web Animations API: AnimationTimeline tests</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/WebIDLParser.js"></script>
 <script src="/resources/idlharness.js"></script>
 <div id="log"></div>
 <iframe src="data:text/html;charset=utf-8," width="10" height="10" id="iframe"></iframe>
+<iframe src="data:text/html;charset=utf-8,%3Chtml%20style%3D%22display%3Anone%22%3E%3C%2Fhtml%3E" width="10" height="10" id="hidden-iframe"></iframe>
 <script type="text/plain" id="AnimationTimeline-IDL">
 interface AnimationTimeline {
   readonly attribute double? currentTime;
 };
 </script>
 <script>
 'use strict';
 
@@ -97,9 +98,55 @@ async_test(function(t) {
 'document.timeline.currentTime liveness tests',
 {
   help: 'http://dev.w3.org/fxtf/web-animations/#script-execution-and-live-updates-to-the-model',
   assert: [ 'The value returned by the currentTime attribute of a' +
             ' document timeline will not change within a script block' ],
   author: 'Brian Birtles'
 });
 
+test(function() {
+  var hiddenIFrame = document.getElementById('hidden-iframe');
+  assert_equals(typeof hiddenIFrame.contentDocument.timeline.currentTime,
+    'number',
+    'currentTime of an initially hidden subframe\'s timeline is a number');
+  assert_true(hiddenIFrame.contentDocument.timeline.currentTime >= 0,
+    'currentTime of an initially hidden subframe\'s timeline is >= 0');
+}, 'document.timeline.currentTime hidden subframe test');
+
+async_test(function(t) {
+  var hiddenIFrame = document.getElementById('hidden-iframe');
+
+  // Don't run the test until after the iframe has completed loading or else the
+  // contentDocument may change.
+  var testToRunOnLoad = t.step_func(function() {
+    // Remove display:none
+    hiddenIFrame.style.display = 'block';
+    window.getComputedStyle(hiddenIFrame).display;
+
+    window.requestAnimationFrame(t.step_func(function() {
+      assert_true(hiddenIFrame.contentDocument.timeline.currentTime > 0,
+        'document.timeline.currentTime is positive after removing'
+        + ' display:none');
+      var previousValue = hiddenIFrame.contentDocument.timeline.currentTime;
+
+      // Re-introduce display:none
+      hiddenIFrame.style.display = 'none';
+      window.getComputedStyle(hiddenIFrame).display;
+
+      window.requestAnimationFrame(t.step_func(function() {
+        assert_true(
+          hiddenIFrame.contentDocument.timeline.currentTime >= previousValue,
+          'document.timeline.currentTime does not go backwards after'
+          + ' re-setting display:none');
+        t.done();
+      }));
+    }));
+  });
+
+  if (hiddenIFrame.contentDocument.readyState === 'complete') {
+    testToRunOnLoad();
+  } else {
+    hiddenIFrame.addEventListener("load", testToRunOnLoad);
+  }
+}, 'document.timeline.currentTime hidden subframe dynamic test');
+
 </script>
--- a/dom/animation/test/mochitest.ini
+++ b/dom/animation/test/mochitest.ini
@@ -1,3 +1,5 @@
 [animation-timeline/test_animation-timeline.html]
+skip-if = buildapp == 'mulet'
 [css-integration/test_element-get-animation-players.html]
+skip-if = buildapp == 'mulet'
 [css-integration/test_animations-dynamic-changes.html]
--- a/dom/apps/tests/file_packaged_app.sjs
+++ b/dom/apps/tests/file_packaged_app.sjs
@@ -15,33 +15,45 @@ var gMiniManifestTemplate = "file_packag
 var gAppTemplate = "file_packaged_app.template.html";
 var gAppName = "appname";
 var gDevName = "devname";
 var gDevUrl = "http://dev.url";
 
 function handleRequest(request, response) {
   var query = getQuery(request);
 
-  response.setHeader("Access-Control-Allow-Origin", "*", false);
-
   var packageSize = ("packageSize" in query) ? query.packageSize : 0;
   var appName = ("appName" in query) ? query.appName : gAppName;
   var devName = ("devName" in query) ? query.devName : gDevName;
   var devUrl = ("devUrl" in query) ? query.devUrl : gDevUrl;
+  // allowCancel just means deliver the file slowly so we have time to cancel it
+  var allowCancel = "allowCancel" in query;
+  var getPackage = "getPackage" in query;
+  var alreadyDeferred = Number(getState("alreadyDeferred"));
+
+  if (allowCancel && getPackage && !alreadyDeferred) {
+    // Only do this for the actual package delivery.
+    response.processAsync();
+    // And to avoid timer problems, only do this once.
+    setState("alreadyDeferred", "1");
+  }
+
+  response.setHeader("Access-Control-Allow-Origin", "*", false);
 
   // If this is a version update, update state, prepare the manifest,
   // the application package and return.
   if ("setVersion" in query) {
     var version = query.setVersion;
     setState("version", version);
     var packageVersion = ("dontUpdatePackage" in query) ? version - 1 : version;
     var packageName = "test_packaged_app_" + packageVersion + ".zip";
 
     setState("packageName", packageName);
-    var packagePath = "/" + gBasePath + "file_packaged_app.sjs?getPackage=" +
+    var packagePath = "/" + gBasePath + "file_packaged_app.sjs?" +
+                      (allowCancel?"allowCancel&": "") + "getPackage=" +
                       packageName;
     setState("packagePath", packagePath);
 
     if (version == packageVersion) {
       // Create the application package.
       var zipWriter = Cc["@mozilla.org/zipwriter;1"]
                         .createInstance(Ci.nsIZipWriter);
       var zipFile = FileUtils.getFile("TmpD", [packageName]);
@@ -79,21 +91,30 @@ function handleRequest(request, response
     dump("Etags Match. Sending 304\n");
     response.setStatusLine(request.httpVersion, "304", "Not modified");
     return;
   }
 
   response.setHeader("Etag", etag, false);
 
   // Serve the application package corresponding to the requested app version.
-  if ("getPackage" in query) {
+  if (getPackage) {
     var resource = readFile(packageName, true);
     response.setHeader("Content-Type",
                        "Content-Type: application/java-archive", false);
-    response.write(resource);
+    if (allowCancel && !alreadyDeferred) {
+      var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+      timer.initWithCallback(function (aTimer) {
+        response.write(resource);
+        aTimer.cancel();
+        response.finish();
+      }, 1000, Ci.nsITimer.TYPE_ONE_SHOT);
+    } else {
+      response.write(resource);
+    }
     return;
   }
 
   // Serve the mini-manifest corresponding to the requested app version.
   if ("getManifest" in query) {
     var template = gBasePath + gMiniManifestTemplate;
     if (!("noManifestContentType" in query)) {
       response.setHeader("Content-Type",
--- a/dom/apps/tests/test_packaged_app_common.js
+++ b/dom/apps/tests/test_packaged_app_common.js
@@ -52,23 +52,27 @@ var PackagedTestHelper = (function Packa
     finish();
   }
 
   function xhrAbort(url) {
     ok(false, "XHR abort loading " + url);
     finish();
   }
 
-  function setAppVersion(aVersion, aCb, aDontUpdatePackage) {
+  function setAppVersion(aVersion, aCb, aDontUpdatePackage, aAllowCancel) {
     var xhr = new XMLHttpRequest();
     var dontUpdate = "";
+    var allowCancel = "";
     if (aDontUpdatePackage) {
       dontUpdate = "&dontUpdatePackage=1";
     }
-    var url = gSJS + "?setVersion=" + aVersion + dontUpdate;
+    if (aAllowCancel) {
+      allowCancel= "&allowCancel=1";
+    }
+    var url = gSJS + "?setVersion=" + aVersion + dontUpdate + allowCancel;
     xhr.addEventListener("load", function() {
                            is(xhr.responseText, "OK", "setAppVersion OK");
                            aCb();
                          });
     xhr.addEventListener("error", event => xhrError(event, url));
     xhr.addEventListener("abort", event => xhrAbort(url));
     xhr.open("GET", url, true);
     xhr.send();
--- a/dom/apps/tests/test_packaged_app_install.html
+++ b/dom/apps/tests/test_packaged_app_install.html
@@ -29,29 +29,29 @@ function checkAppInstallError(aMiniManif
   var req = navigator.mozApps.installPackage(aMiniManifestURL);
   req.onsuccess = function() {
     ok(false, "We are supposed to throw " + aExpectedError);
     PackagedTestHelper.finish();
   };
   req.onerror = function(evt) {
     var error = evt.target.error.name;
     if (error == aExpectedError) {
-      ok(true, "Got expected " + aExpectedError);
+      info("Got expected " + aExpectedError);
       PackagedTestHelper.next();
     } else {
       ok(false, "Got unexpected " + error);
       PackagedTestHelper.finish();
     }
   };
 }
 
 function checkUninstallApp(aApp) {
   var req = navigator.mozApps.mgmt.uninstall(aApp);
   req.onsuccess = function() {
-    ok(true, "App uninstalled");
+    info("App uninstalled");
     aApp.ondownloadsuccess = null;
     aApp.ondownloaderror = null;
     aApp.onprogress = null;
     PackagedTestHelper.next();
   };
   req.onerror = function(evt) {
     ok(false, "Got unexpected " + evt.target.error.name);
     PackagedTestHelper.finish();
@@ -78,84 +78,84 @@ function checkInstalledApp(aMiniManifest
 
 SimpleTest.waitForExplicitFinish();
 
 var steps = [
   function() {
     // Set up
     SpecialPowers.setAllAppsLaunchable(true);
     SpecialPowers.addPermission("webapps-manage", true, document);
-    ok(true, "Set up");
+    info("Set up");
     PackagedTestHelper.next();
   },
   function() {
-    ok(true, "autoConfirmAppInstall");
+    info("autoConfirmAppInstall");
     SpecialPowers.autoConfirmAppInstall(PackagedTestHelper.next);
   },
   function() {
     PackagedTestHelper.setAppVersion(0, PackagedTestHelper.next);
   },
   function() {
     // Bug 927699 - navigator.mozApps.install(url) lets NS_ERROR_FAILURE onto
     //              the web.
-    ok(true, "== TEST == INVALID_URL");
+    info("== TEST == INVALID_URL");
     checkAppInstallError("", "INVALID_URL");
   },
   function() {
     // Test network error.
-    ok(true, "== TEST == Network error");
+    info("== TEST == Network error");
     checkAppInstallError("http://notvalidurl", "NETWORK_ERROR");
   },
   function() {
     // Test wrong mini-manifest content type.
-    ok(true, "== TEST == Not valid mini-manifest content type");
+    info("== TEST == Not valid mini-manifest content type");
     var miniManifestURL = PackagedTestHelper.gSJS +
                           "?getManifest=true" +
                           "&noManifestContentType=true";
     checkAppInstallError(miniManifestURL, "INVALID_MANIFEST_CONTENT_TYPE");
   },
   function() {
     // Test mini-manifest 'size' value is not number. Bug 839435.
-    ok(true, "== TEST == Size value is not a number");
+    info("== TEST == Size value is not a number");
     var miniManifestURL = PackagedTestHelper.gSJS +
                           "?getManifest=true" +
                           "&packageSize=\"NotANumber\"";
     checkAppInstallError(miniManifestURL, "INVALID_MANIFEST");
   },
   function() {
     // Test mini-manifest  negative 'size' value. Bug 839435.
-    ok(true, "== TEST == Negative size value");
+    info("== TEST == Negative size value");
     var miniManifestURL = PackagedTestHelper.gSJS +
                           "?getManifest=true" +
                           "&packageSize=-1";
     checkAppInstallError(miniManifestURL, "INVALID_MANIFEST");
   },
   function() {
     // Test wrong package path
-    ok(true, "== TEST == Installing app with wrong package path");
+    info("== TEST == Installing app with wrong package path");
     var miniManifestURL = PackagedTestHelper.gSJS +
                           "?getManifest=true" +
                           "&wrongPackagePath=true";
     checkAppInstallError(miniManifestURL, "INVALID_MANIFEST");
   },
   function() {
     // Test no manifest in zip file.
-    ok(true, "== TEST == No manifest in the zip file");
+    info("== TEST == No manifest in the zip file");
     var miniManifestURL = PackagedTestHelper.gSJS + "?getManifest=true";
     PackagedTestHelper.checkAppDownloadError(miniManifestURL,
                                             "MISSING_MANIFEST", 0, true, true,
                                              PackagedTestHelper.gAppName);
   },
   function() {
       PackagedTestHelper.setAppVersion(1, PackagedTestHelper.next);
   },
   function() {
     // Test mini-manifest app name is different from the webapp manifest name.
     // Bug 844243.
-    ok(true, "== TEST == Mini-manifest app name is different from webapp " +
+    info("== TEST == Mini-manifest app name is different from webapp " +
              "manifest name");
     var miniManifestURL = PackagedTestHelper.gSJS +
                           "?getManifest=true" +
                           "&appName=arandomname";
     PackagedTestHelper.checkAppDownloadError(miniManifestURL,
                                              "MANIFEST_MISMATCH", 1, true, true,
                                              "arandomname");
   },
@@ -182,29 +182,29 @@ var steps = [
     PackagedTestHelper.checkAppDownloadError(miniManifestURL,
                                              "MANIFEST_MISMATCH", 1, true, true,
                                              PackagedTestHelper.gAppName);
   },
   function() {
     PackagedTestHelper.setAppVersion(2, PackagedTestHelper.next);
   },
   function() {
-    ok(true, "== TEST == Install packaged app");
+    info("== TEST == Install packaged app");
     var miniManifestURL = PackagedTestHelper.gSJS +
                           "?getManifest=true";
     navigator.mozApps.mgmt.oninstall = function(evt) {
-      ok(true, "Got oninstall event");
+      info("Got oninstall event");
       PackagedTestHelper.gApp = evt.application;
       PackagedTestHelper.gApp.ondownloaderror = function() {
         ok(false, "Download error " +
                   PackagedTestHelper.gApp.downloadError.name);
         PackagedTestHelper.finish();
       };
       PackagedTestHelper.gApp.ondownloadsuccess = function() {
-        ok(true, "App downloaded");
+        info("App downloaded");
         var expected = {
           name: PackagedTestHelper.gAppName,
           manifestURL: miniManifestURL,
           installOrigin: PackagedTestHelper.gInstallOrigin,
           progress: 0,
           installState: "installed",
           downloadAvailable: false,
           downloading: false,
@@ -215,21 +215,102 @@ var steps = [
         PackagedTestHelper.checkAppState(PackagedTestHelper.gApp, 2, expected,
                                          true, false, PackagedTestHelper.next);
       };
     };
 
     var request = navigator.mozApps.installPackage(miniManifestURL);
     request.onerror = PackagedTestHelper.mozAppsError;
     request.onsuccess = function() {
-      ok(true, "Application installed");
+      info("Application installed");
     };
   },
   function() {
-    ok(true, "all done!\n");
+    PackagedTestHelper.setAppVersion(3, PackagedTestHelper.next, false, true);
+  },
+  function() {
+    info("== TEST == Install packaged app with a cancel/resume");
+    var miniManifestURL = PackagedTestHelper.gSJS +
+                          "?getManifest=true&allowCancel";
+    navigator.mozApps.mgmt.oninstall = function(evt) {
+      info("Got oninstall event");
+      PackagedTestHelper.gApp = evt.application;
+
+      PackagedTestHelper.gApp.onprogress = function() {
+        // The first onprogress event is generated *before* the actual
+        // download is started. And the next one will be generated too late.
+        // So we just try to delay the canceling a bit.
+        setTimeout(function() {
+          // Let's try cancelling and resuming the download later on.
+          info("Cancelling the download");
+          PackagedTestHelper.gApp.cancelDownload();
+          // And only do this once.
+          PackagedTestHelper.gApp.onprogress = null;
+        }, 40);
+      };
+
+      var alreadyCanceled = false;
+      PackagedTestHelper.gApp.ondownloaderror = function() {
+        info("Got a expected download error");
+        ok(!alreadyCanceled, "The download should be cancelled only once!");
+        is(PackagedTestHelper.gApp.downloadError.name, "DOWNLOAD_CANCELED",
+           "Download error " + PackagedTestHelper.gApp.downloadError.name);
+        if (!alreadyCanceled) {
+          PackagedTestHelper.gApp.download();
+          alreadyCanceled = true;
+        }
+      };
+
+      PackagedTestHelper.gApp.ondownloadsuccess = function() {
+        info("App downloaded");
+        // We could try also applying the download we just made.
+        var expected = {
+          name: PackagedTestHelper.gAppName,
+          manifestURL: miniManifestURL,
+          installOrigin: PackagedTestHelper.gInstallOrigin,
+          progress: 0,
+          installState: "pending",
+          downloadAvailable: false,
+          downloading: false,
+          downloadSize: 0,
+          size: 0,
+          readyToApplyDownload: true
+        };
+        PackagedTestHelper.checkAppState(PackagedTestHelper.gApp, 3, expected,
+                                         true, false, function() {});
+      };
+
+      PackagedTestHelper.gApp.ondownloadapplied = function() {
+        info("App download applied.");
+        var expected = {
+          name: PackagedTestHelper.gAppName,
+          manifestURL: miniManifestURL,
+          installOrigin: PackagedTestHelper.gInstallOrigin,
+          progress: 0,
+          installState: "installed",
+          downloadAvailable: false,
+          downloading: false,
+          downloadSize: 0,
+          size: 0,
+          readyToApplyDownload: false
+        };
+        PackagedTestHelper.checkAppState(PackagedTestHelper.gApp, 3, expected,
+                                         true, false, PackagedTestHelper.next);
+      }
+
+    };
+
+    var request = navigator.mozApps.installPackage(miniManifestURL);
+    request.onerror = PackagedTestHelper.mozAppsError;
+    request.onsuccess = function() {
+      info("Application installed");
+    };
+  },
+  function() {
+    info("all done!\n");
     PackagedTestHelper.finish();
   }
 ];
 
 PackagedTestHelper.setSteps(steps);
 
 addLoadEvent(PackagedTestHelper.start);
 
--- a/dom/audiochannel/tests/mochitest.ini
+++ b/dom/audiochannel/tests/mochitest.ini
@@ -1,11 +1,11 @@
 [DEFAULT]
 support-files =
   audio.ogg
   file_audio.html
   file_telephonyPolicy.html
   AudioChannelChromeScript.js
 
 [test_telephonyPolicy.html]
-skip-if = (toolkit == 'gonk' || e10s)
+skip-if = buildapp == 'mulet' || (toolkit == 'gonk' || e10s)
 [test_audioChannelChange.html]
 skip-if = (toolkit != 'gonk')
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -58,16 +58,17 @@
 
 #if defined(MOZ_X11) && defined(MOZ_WIDGET_GTK)
 #include <gdk/gdk.h>
 #include <gdk/gdkx.h>
 #endif
 
 #include "Layers.h"
 #include "mozilla/layers/ShadowLayers.h"
+#include "gfxPrefs.h"
 
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/IDBFactoryBinding.h"
 #include "mozilla/dom/IDBMutableFileBinding.h"
 #include "mozilla/dom/indexedDB/IDBMutableFile.h"
 #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
@@ -353,21 +354,23 @@ nsDOMWindowUtils::SetDisplayPortForEleme
                      nsPresContext::CSSPixelsToAppUnits(aYPx),
                      nsPresContext::CSSPixelsToAppUnits(aWidthPx),
                      nsPresContext::CSSPixelsToAppUnits(aHeightPx));
 
   content->SetProperty(nsGkAtoms::DisplayPort,
                        new DisplayPortPropertyData(displayport, aPriority),
                        nsINode::DeleteProperty<DisplayPortPropertyData>);
 
-  nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
-  if (rootScrollFrame && content == rootScrollFrame->GetContent()) {
-    // We are setting a root displayport for a document.
-    // The pres shell needs a special flag set.
-    presShell->SetIgnoreViewportScrolling(true);
+  if (gfxPrefs::AsyncPanZoomEnabled()) {
+    nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
+    if (rootScrollFrame && content == rootScrollFrame->GetContent()) {
+      // We are setting a root displayport for a document.
+      // The pres shell needs a special flag set.
+      presShell->SetIgnoreViewportScrolling(true);
+    }
   }
 
   nsIFrame* rootFrame = presShell->FrameManager()->GetRootFrame();
   if (rootFrame) {
     rootFrame->SchedulePaint();
 
     // If we are hiding something that is a display root then send empty paint
     // transaction in order to release retained layers because it won't get
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -8,29 +8,30 @@ support-files =
   iframe_messageChannel_post.html
   file_empty.html
   iframe_postMessage_solidus.html
   file_setname.html
 
 [test_appname_override.html]
 [test_audioWindowUtils.html]
 [test_audioNotification.html]
+skip-if = buildapp == 'mulet'
 [test_bug793311.html]
 [test_bug913761.html]
 [test_bug976673.html]
 [test_bug978522.html]
 [test_bug979109.html]
 [test_bug989665.html]
 [test_bug999456.html]
 [test_clearTimeoutIntervalNoArg.html]
 [test_consoleEmptyStack.html]
 [test_constructor-assignment.html]
 [test_constructor.html]
 [test_dialogArguments.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s
 [test_document.all_unqualified.html]
 [test_domcursor.html]
 [test_domrequest.html]
 [test_domwindowutils.html]
 [test_e4x_for_each.html]
 [test_error.html]
 [test_getTranslationNodes.html]
 [test_getTranslationNodes_limit.html]
--- a/dom/browser-element/mochitest/mochitest-oop.ini
+++ b/dom/browser-element/mochitest/mochitest-oop.ini
@@ -1,14 +1,14 @@
 [DEFAULT]
 # Both the "inproc" and "oop" versions of OpenMixedProcess open remote frames,
 # so we don't run that test on platforms which don't support OOP tests.
 # OOP tests don't work on native-fennec (bug 774939).
 # Bug 960345 - Disabled on OSX debug for frequent crashes.
-skip-if = os == "android" || (toolkit == "cocoa" && debug) || (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || e10s
+skip-if = os == "android" || (toolkit == "cocoa" && debug) || buildapp == 'mulet' || (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || e10s
 support-files =
   browserElement_OpenMixedProcess.js
   file_browserElement_OpenMixedProcess.html
 
 [test_browserElement_oop_ThemeColor.html]
 [test_browserElement_inproc_ErrorSecurity.html]
 skip-if = toolkit=='gonk'
 [test_browserElement_inproc_OpenMixedProcess.html]
--- a/dom/browser-element/mochitest/mochitest.ini
+++ b/dom/browser-element/mochitest/mochitest.ini
@@ -1,10 +1,10 @@
 [DEFAULT]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || e10s
+skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || e10s
 support-files =
   ../../../browser/base/content/test/general/audio.ogg
   ../../../content/media/test/short-video.ogv
   browserElementTestHelpers.js
   browserElement_Alert.js
   browserElement_AlertInFrame.js
   browserElement_AppFramePermission.js
   browserElement_AppWindowNamespace.js
--- a/dom/browser-element/mochitest/priority/mochitest.ini
+++ b/dom/browser-element/mochitest/priority/mochitest.ini
@@ -1,11 +1,11 @@
 [DEFAULT]
 # Good luck running these tests on anything but desktop Linux.
-skip-if = toolkit != "gtk2" || (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || e10s
+skip-if = toolkit != "gtk2" || ((buildapp =='mulet' || buildapp == 'b2g') && (toolkit != 'gonk' || debug)) || e10s
 
 # Note: ../browserElementTestHelpers.js makes all tests in this directory OOP,
 # because testing the process-priority manager without OOP frames does not make
 # much sense.
 
 [test_Simple.html]
 [test_Visibility.html]
 [test_HighPriority.html]
--- a/dom/devicestorage/ipc/mochitest.ini
+++ b/dom/devicestorage/ipc/mochitest.ini
@@ -1,6 +1,6 @@
 [DEFAULT]
 skip-if = toolkit == 'android' || e10s #bug 781789 & bug 782275
 support-files = ../test/devicestorage_common.js
 
 [test_ipc.html]
-skip-if = buildapp == 'b2g' # b2g(nested ipc not working) b2g-debug(nested ipc not working) b2g-desktop(nested ipc not working)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' # b2g(nested ipc not working) b2g-debug(nested ipc not working) b2g-desktop(nested ipc not working)
--- a/dom/devicestorage/test/chrome.ini
+++ b/dom/devicestorage/test/chrome.ini
@@ -1,4 +1,5 @@
 [DEFAULT]
+skip-if = buildapp == 'mulet'
 
 [test_app_permissions.html]
 [test_fs_app_permissions.html]
--- a/dom/downloads/tests/mochitest.ini
+++ b/dom/downloads/tests/mochitest.ini
@@ -1,10 +1,10 @@
 [DEFAULT]
-skip-if = buildapp == 'b2g' # bug 979446, frequent failures
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' # bug 979446, frequent failures
 support-files =
   serve_file.sjs
 
 [test_downloads_navigator_object.html]
 [test_downloads_basic.html]
 [test_downloads_large.html]
 [test_downloads_bad_file.html]
 [test_downloads_pause_remove.html]
--- a/dom/events/test/mochitest.ini
+++ b/dom/events/test/mochitest.ini
@@ -35,40 +35,42 @@ skip-if = (buildapp == 'b2g' && toolkit 
 [test_bug402089.html]
 [test_bug405632.html]
 [test_bug409604.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT
 [test_bug412567.html]
 [test_bug422132.html]
 skip-if = buildapp == 'b2g' || e10s # b2g(2 failures out of 8, mousewheel test) b2g-debug(2 failures out of 8, mousewheel test) b2g-desktop(2 failures out of 8, mousewheel test)
 [test_bug426082.html]
-skip-if = buildapp == 'b2g' || os == "win" || toolkit == 'android' || e10s # Intermittent failures, bug 921693 # b2g(1 failure out of 6, Moving the mouse down from the label should have unpressed the button) b2g-debug(1 failure out of 6, Moving the mouse down from the label should have unpressed the button) b2g-desktop(1 failure out of 6, Moving the mouse down from the label should have unpressed the button)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || os == "win" || toolkit == 'android' || e10s # Intermittent failures, bug 921693 # b2g(1 failure out of 6, Moving the mouse down from the label should have unpressed the button) b2g-debug(1 failure out of 6, Moving the mouse down from the label should have unpressed the button) b2g-desktop(1 failure out of 6, Moving the mouse down from the label should have unpressed the button)
 [test_bug427537.html]
 [test_bug428988.html]
 [test_bug432698.html]
+skip-if = buildapp == 'mulet'
 [test_bug443985.html]
 [test_bug447736.html]
 [test_bug448602.html]
 [test_bug450876.html]
+skip-if = buildapp == 'mulet'
 [test_bug456273.html]
 [test_bug457672.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' #CRASH_DUMP, RANDOM
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' #CRASH_DUMP, RANDOM
 [test_bug489671.html]
 [test_bug493251.html]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
+skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug502818.html]
 skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
 [test_bug508479.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #CRASH_DUMP, RANDOM # b2g(drag event, also fails on Android) b2g-debug(drag event, also fails on Android) b2g-desktop(drag event, also fails on Android)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #CRASH_DUMP, RANDOM # b2g(drag event, also fails on Android) b2g-debug(drag event, also fails on Android) b2g-desktop(drag event, also fails on Android)
 [test_bug822898.html]
 [test_bug517851.html]
 [test_bug534833.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' #CRASH_DUMP, RANDOM # b2g(4 failures out of 6, bug 901564,click not fired, also disabled on Android) b2g-debug(4 failures out of 6, bug 901564,click not fired, also disabled on Android) b2g-desktop(4 failures out of 6, bug 901564,click not fired, also disabled on Android)
 [test_bug545268.html]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || toolkit == 'android' #CRASH_DUMP, RANDOM #Bug 931116, b2g desktop specific, initial triage
+skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && toolkit != 'gonk') || toolkit == 'android' #CRASH_DUMP, RANDOM #Bug 931116, b2g desktop specific, initial triage
 [test_bug547996-1.html]
 skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
 [test_bug547996-2.xhtml]
 skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
 [test_bug556493.html]
 skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
 [test_bug563329.html]
 skip-if = true # Disabled due to timeouts.
@@ -76,17 +78,17 @@ skip-if = true # Disabled due to timeout
 skip-if = buildapp == 'b2g' || toolkit == 'android' #CRASH_DUMP, RANDOM
 [test_bug591815.html]
 [test_bug593959.html]
 [test_bug603008.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' # b2g(1 failure out of 615, bug 901533, Six move events fired - got 7, expected 6, also disabled on Android, touchmove) b2g-debug(1 failure out of 615, bug 901533, Six move events fired - got 7, expected 6, also disabled on Android, touchmove) b2g-desktop(1 failure out of 615, bug 901533, Six move events fired - got 7, expected 6, also disabled on Android, touchmove)
 [test_bug605242.html]
 skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
 [test_bug607464.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' #CRASH_DUMP, RANDOM
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' #CRASH_DUMP, RANDOM
 [test_bug613634.html]
 skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
 [test_bug615597.html]
 skip-if = buildapp == 'b2g' # b2g(bug 900969, 5 tests) b2g-debug(bug 900969, 5 tests) b2g-desktop(bug 900969, 5 tests)
 [test_bug624127.html]
 skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
 [test_bug635465.html]
 skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
@@ -138,23 +140,25 @@ skip-if = buildapp == 'b2g' || e10s # b2
 skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
 [test_dom_mouse_event.html]
 skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
 [test_dom_wheel_event.html]
 skip-if = buildapp == 'b2g' || e10s # b2g(456 failed out of 19873, mousewheel test) b2g-debug(456 failed out of 19873, mousewheel test) b2g-desktop(456 failed out of 19873, mousewheel test)
 [test_draggableprop.html]
 skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
 [test_dragstart.html]
-skip-if = buildapp == 'b2g' # b2g(drag event, also fails on Android) b2g-debug(drag event, also fails on Android) b2g-desktop(drag event, also fails on Android)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' # b2g(drag event, also fails on Android) b2g-debug(drag event, also fails on Android) b2g-desktop(drag event, also fails on Android)
 [test_error_events.html]
 skip-if = toolkit == 'android' #TIMED_OUT
 [test_eventctors.html]
 skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
 [test_eventTimeStamp.html]
 [test_focus_disabled.html]
+skip-if = buildapp == 'mulet'
 [test_messageEvent.html]
 [test_moz_mouse_pixel_scroll_event.html]
+skip-if = buildapp == 'mulet'
 [test_onerror_handler_args.html]
 [test_wheel_default_action.html]
-skip-if = buildapp == 'b2g' || e10s
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || e10s
 [test_bug985988.html]
 [test_dom_storage_event.html]
 [test_bug998809.html]
--- a/dom/filesystem/CreateFileTask.h
+++ b/dom/filesystem/CreateFileTask.h
@@ -66,17 +66,17 @@ private:
   static uint32_t sOutputBufferSize;
   nsRefPtr<Promise> mPromise;
   nsString mTargetRealPath;
   nsCOMPtr<nsIDOMBlob> mBlobData;
   nsCOMPtr<nsIInputStream> mBlobStream;
   InfallibleTArray<uint8_t> mArrayData;
   bool mReplace;
 
-  // This cannot be a DOMFile bacause this object is created on a different
+  // This cannot be a DOMFile because this object is created on a different
   // thread and DOMFile is not thread-safe. Let's use the DOMFileImpl instead.
   nsRefPtr<DOMFileImpl> mTargetFileImpl;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_CreateFileTask_h
--- a/dom/filesystem/DeviceStorageFileSystem.cpp
+++ b/dom/filesystem/DeviceStorageFileSystem.cpp
@@ -8,17 +8,17 @@
 
 #include "DeviceStorage.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/Directory.h"
 #include "mozilla/dom/FileSystemUtils.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsDeviceStorage.h"
-#include "nsIDOMFile.h"
+#include "nsDOMFile.h"
 #include "nsIFile.h"
 #include "nsPIDOMWindow.h"
 
 namespace mozilla {
 namespace dom {
 
 DeviceStorageFileSystem::DeviceStorageFileSystem(
   const nsAString& aStorageType,
@@ -109,17 +109,17 @@ DeviceStorageFileSystem::GetLocalFile(co
   nsresult rv = NS_NewLocalFile(localPath, false, getter_AddRefs(file));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return nullptr;
   }
   return file.forget();
 }
 
 bool
-DeviceStorageFileSystem::GetRealPath(nsIDOMFile* aFile, nsAString& aRealPath) const
+DeviceStorageFileSystem::GetRealPath(DOMFileImpl* aFile, nsAString& aRealPath) const
 {
   MOZ_ASSERT(FileSystemUtils::IsParentProcess(),
              "Should be on parent process!");
   MOZ_ASSERT(aFile, "aFile Should not be null.");
 
   aRealPath.Truncate();
 
   nsAutoString filePath;
--- a/dom/filesystem/DeviceStorageFileSystem.h
+++ b/dom/filesystem/DeviceStorageFileSystem.h
@@ -32,17 +32,17 @@ public:
 
   virtual nsPIDOMWindow*
   GetWindow() const MOZ_OVERRIDE;
 
   virtual already_AddRefed<nsIFile>
   GetLocalFile(const nsAString& aRealPath) const MOZ_OVERRIDE;
 
   virtual bool
-  GetRealPath(nsIDOMFile* aFile, nsAString& aRealPath) const MOZ_OVERRIDE;
+  GetRealPath(DOMFileImpl* aFile, nsAString& aRealPath) const MOZ_OVERRIDE;
 
   virtual const nsAString&
   GetRootName() const MOZ_OVERRIDE;
 
   virtual bool
   IsSafeFile(nsIFile* aFile) const MOZ_OVERRIDE;
 
   virtual bool
--- a/dom/filesystem/Directory.cpp
+++ b/dom/filesystem/Directory.cpp
@@ -190,22 +190,22 @@ Directory::RemoveDeep(const StringOrFile
 }
 
 already_AddRefed<Promise>
 Directory::RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive,
                           ErrorResult& aRv)
 {
   nsresult error = NS_OK;
   nsString realPath;
-  nsCOMPtr<nsIDOMFile> file;
+  nsRefPtr<DOMFileImpl> file;
 
   // Check and get the target path.
 
   if (aPath.IsFile()) {
-    file = aPath.GetAsFile();
+    file = static_cast<DOMFile*>(aPath.GetAsFile())->Impl();
     goto parameters_check_done;
   }
 
   if (aPath.IsString()) {
     if (!DOMPathToRealPath(aPath.GetAsString(), realPath)) {
       error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
     }
     goto parameters_check_done;
--- a/dom/filesystem/FileSystemBase.h
+++ b/dom/filesystem/FileSystemBase.h
@@ -5,23 +5,23 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_FileSystemBase_h
 #define mozilla_dom_FileSystemBase_h
 
 #include "nsAutoPtr.h"
 #include "nsString.h"
 
-class nsIDOMFile;
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
 class Directory;
+class DOMFileImpl;
 
 class FileSystemBase
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FileSystemBase)
 public:
 
   // Create file system object from its string representation.
   static already_AddRefed<FileSystemBase>
@@ -68,17 +68,17 @@ public:
   IsSafeDirectory(Directory* aDir) const;
 
   /*
    * Get the real path (absolute DOM path) of the DOM file in the file system.
    * If succeeded, returns true. Otherwise, returns false and set aRealPath to
    * empty string.
    */
   virtual bool
-  GetRealPath(nsIDOMFile* aFile, nsAString& aRealPath) const = 0;
+  GetRealPath(DOMFileImpl* aFile, nsAString& aRealPath) const = 0;
 
   /*
    * Get the permission name required to access this file system.
    */
   const nsCString&
   GetPermission() const
   {
     return mPermission;
--- a/dom/filesystem/RemoveTask.cpp
+++ b/dom/filesystem/RemoveTask.cpp
@@ -5,32 +5,32 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "RemoveTask.h"
 
 #include "DOMError.h"
 #include "mozilla/dom/FileSystemBase.h"
 #include "mozilla/dom/FileSystemUtils.h"
 #include "mozilla/dom/Promise.h"
-#include "nsIDOMFile.h"
+#include "nsDOMFile.h"
 #include "nsIFile.h"
 #include "nsStringGlue.h"
 
 namespace mozilla {
 namespace dom {
 
 RemoveTask::RemoveTask(FileSystemBase* aFileSystem,
                        const nsAString& aDirPath,
-                       nsIDOMFile* aTargetFile,
+                       DOMFileImpl* aTargetFile,
                        const nsAString& aTargetPath,
                        bool aRecursive,
                        ErrorResult& aRv)
   : FileSystemTaskBase(aFileSystem)
   , mDirRealPath(aDirPath)
-  , mTargetFile(aTargetFile)
+  , mTargetFileImpl(aTargetFile)
   , mTargetRealPath(aTargetPath)
   , mRecursive(aRecursive)
   , mReturnValue(false)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   MOZ_ASSERT(aFileSystem);
   nsCOMPtr<nsIGlobalObject> globalObject =
     do_QueryInterface(aFileSystem->GetWindow());
@@ -60,18 +60,18 @@ RemoveTask::RemoveTask(FileSystemBase* a
 
   if (target.type() == FileSystemPathOrFileValue::TnsString) {
     mTargetRealPath = target;
     return;
   }
 
   BlobParent* bp = static_cast<BlobParent*>(static_cast<PBlobParent*>(target));
   nsCOMPtr<nsIDOMBlob> blob = bp->GetBlob();
-  mTargetFile = do_QueryInterface(blob);
-  MOZ_ASSERT(mTargetFile, "mTargetFile should not be null.");
+  MOZ_ASSERT(blob);
+  mTargetFileImpl = static_cast<DOMFile*>(blob.get())->Impl();
 }
 
 RemoveTask::~RemoveTask()
 {
   MOZ_ASSERT(!mPromise || NS_IsMainThread(),
              "mPromise should be released on main thread!");
 }
 
@@ -85,19 +85,20 @@ RemoveTask::GetPromise()
 FileSystemParams
 RemoveTask::GetRequestParams(const nsString& aFileSystem) const
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   FileSystemRemoveParams param;
   param.filesystem() = aFileSystem;
   param.directory() = mDirRealPath;
   param.recursive() = mRecursive;
-  if (mTargetFile) {
+  if (mTargetFileImpl) {
+    nsRefPtr<DOMFile> file = new DOMFile(mTargetFileImpl);
     BlobChild* actor
-      = ContentChild::GetSingleton()->GetOrCreateActorForBlob(mTargetFile);
+      = ContentChild::GetSingleton()->GetOrCreateActorForBlob(file);
     if (actor) {
       param.target() = actor;
     }
   } else {
     param.target() = mTargetRealPath;
   }
   return param;
 }
@@ -124,18 +125,18 @@ RemoveTask::Work()
              "Only call from parent process!");
   MOZ_ASSERT(!NS_IsMainThread(), "Only call on worker thread!");
 
   if (mFileSystem->IsShutdown()) {
     return NS_ERROR_FAILURE;
   }
 
   // Get the DOM path if a DOMFile is passed as the target.
-  if (mTargetFile) {
-    if (!mFileSystem->GetRealPath(mTargetFile, mTargetRealPath)) {
+  if (mTargetFileImpl) {
+    if (!mFileSystem->GetRealPath(mTargetFileImpl, mTargetRealPath)) {
       return NS_ERROR_DOM_SECURITY_ERR;
     }
     if (!FileSystemUtils::IsDescendantPath(mDirRealPath, mTargetRealPath)) {
       return NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR;
     }
   }
 
   nsCOMPtr<nsIFile> file = mFileSystem->GetLocalFile(mTargetRealPath);
--- a/dom/filesystem/RemoveTask.h
+++ b/dom/filesystem/RemoveTask.h
@@ -9,25 +9,26 @@
 
 #include "mozilla/dom/FileSystemTaskBase.h"
 #include "nsAutoPtr.h"
 #include "mozilla/ErrorResult.h"
 
 namespace mozilla {
 namespace dom {
 
+class DOMFileImpl;
 class Promise;
 
 class RemoveTask MOZ_FINAL
   : public FileSystemTaskBase
 {
 public:
   RemoveTask(FileSystemBase* aFileSystem,
              const nsAString& aDirPath,
-             nsIDOMFile* aTargetFile,
+             DOMFileImpl* aTargetFile,
              const nsAString& aTargetPath,
              bool aRecursive,
              ErrorResult& aRv);
   RemoveTask(FileSystemBase* aFileSystem,
              const FileSystemRemoveParams& aParam,
              FileSystemRequestParent* aParent);
 
   virtual
@@ -53,17 +54,19 @@ protected:
   Work() MOZ_OVERRIDE;
 
   virtual void
   HandlerCallback() MOZ_OVERRIDE;
 
 private:
   nsRefPtr<Promise> mPromise;
   nsString mDirRealPath;
-  nsCOMPtr<nsIDOMFile> mTargetFile;
+  // This cannot be a DOMFile because this object will be used on a different
+  // thread and DOMFile is not thread-safe. Let's use the DOMFileImpl instead.
+  nsRefPtr<DOMFileImpl> mTargetFileImpl;
   nsString mTargetRealPath;
   bool mRecursive;
   bool mReturnValue;
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/identity/tests/mochitest/chrome.ini
+++ b/dom/identity/tests/mochitest/chrome.ini
@@ -7,10 +7,11 @@ support-files=
   file_fxa_rp_ok.html
   file_fxa_rp_noOnready.html
   file_fxa_rp_noOnlogin.html
   file_fxa_rp_noOnlogout.html
   file_syntheticEvents.html
 
 [test_declareAudience.html]
 [test_rpHasValidCallbacks.html]
+skip-if = buildapp == 'mulet'
 [test_syntheticEvents.html]
 
--- a/dom/indexedDB/ipc/mochitest.ini
+++ b/dom/indexedDB/ipc/mochitest.ini
@@ -1,4 +1,4 @@
 [DEFAULT]
 
 [test_ipc.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #bug 783513 # b2g(nested ipc not working) b2g-debug(nested ipc not working) b2g-desktop(nested ipc not working)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #bug 783513 # b2g(nested ipc not working) b2g-debug(nested ipc not working) b2g-desktop(nested ipc not working)
--- a/dom/indexedDB/test/mochitest.ini
+++ b/dom/indexedDB/test/mochitest.ini
@@ -234,15 +234,15 @@ skip-if = (buildapp == 'b2g' && toolkit 
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_transaction_lifetimes_nested.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_transaction_ordering.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_unique_index_update.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_webapp_clearBrowserData_inproc_inproc.html]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || toolkit == 'android' #No test app installed #Bug 931116, b2g desktop specific, initial triage
+skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') || toolkit == 'android' #No test app installed #Bug 931116, b2g desktop specific, initial triage
 [test_webapp_clearBrowserData_inproc_oop.html]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || toolkit == 'android' #No test app installed #Bug 931116, b2g desktop specific, initial triage
+skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') || toolkit == 'android' #No test app installed #Bug 931116, b2g desktop specific, initial triage
 [test_webapp_clearBrowserData_oop_inproc.html]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || toolkit == 'android' #No test app installed #Bug 931116, b2g desktop specific, initial triage
+skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') || toolkit == 'android' #No test app installed #Bug 931116, b2g desktop specific, initial triage
 [test_bug937006.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
--- a/dom/indexedDB/test/unit/xpcshell.ini
+++ b/dom/indexedDB/test/unit/xpcshell.ini
@@ -26,17 +26,17 @@ support-files =
 [test_cursor_update_updates_indexes.js]
 [test_cursors.js]
 [test_deleteDatabase.js]
 [test_deleteDatabase_interactions.js]
 [test_event_source.js]
 [test_getAll.js]
 [test_globalObjects_ipc.js]
 # FIXME/bug 575918: out-of-process xpcshell is broken on OS X
-skip-if = os == "mac" || os == "android"
+skip-if = buildapp == 'mulet' || os == "mac" || os == "android"
 [test_globalObjects_other.js]
 [test_globalObjects_xpc.js]
 [test_global_data.js]
 [test_index_empty_keyPath.js]
 [test_index_getAll.js]
 [test_index_getAllObjects.js]
 [test_index_object_cursors.js]
 [test_index_update_delete.js]
--- a/dom/ipc/tests/chrome.ini
+++ b/dom/ipc/tests/chrome.ini
@@ -1,6 +1,7 @@
 [DEFAULT]
 support-files =
   process_error.xul
   process_error_contentscript.js
 
 [test_process_error.xul]
+skip-if = buildapp == "mulet"
--- a/dom/media/gmp-plugin/gmp-fake.cpp
+++ b/dom/media/gmp-plugin/gmp-fake.cpp
@@ -116,46 +116,42 @@ class FakeEncoderTask : public GMPTask {
 };
 
 class FakeVideoEncoder : public GMPVideoEncoder {
  public:
   FakeVideoEncoder (GMPVideoHost* hostAPI) :
     host_ (hostAPI),
     callback_ (NULL) {}
 
-  virtual GMPErr InitEncode (const GMPVideoCodec& codecSettings,
+  virtual void InitEncode (const GMPVideoCodec& codecSettings,
                              const uint8_t* aCodecSpecific,
                              uint32_t aCodecSpecificSize,
                              GMPVideoEncoderCallback* callback,
                              int32_t numberOfCores,
                              uint32_t maxPayloadSize) {
     callback_ = callback;
 
     GMPLOG (GL_INFO, "Initialized encoder");
-
-    return GMPNoErr;
   }
 
-  virtual GMPErr Encode (GMPVideoi420Frame* inputImage,
+  virtual void Encode (GMPVideoi420Frame* inputImage,
                          const uint8_t* aCodecSpecificInfo,
                          uint32_t aCodecSpecificInfoLength,
                          const GMPVideoFrameType* aFrameTypes,
                          uint32_t aFrameTypesLength) {
     GMPLOG (GL_DEBUG,
             __FUNCTION__
             << " size="
             << inputImage->Width() << "x" << inputImage->Height());
 
     assert (aFrameTypesLength != 0);
 
     g_platform_api->runonmainthread(new FakeEncoderTask(this,
                                                         inputImage,
                                                         aFrameTypes[0]));
-
-    return GMPGenericErr;
   }
 
   void Encode_m (GMPVideoi420Frame* inputImage,
                  GMPVideoFrameType frame_type) {
     if (frame_type  == kGMPKeyFrame) {
       if (!inputImage)
         return;
     }
@@ -218,26 +214,23 @@ class FakeVideoEncoder : public GMPVideo
     info.mCodecType = kGMPVideoCodecH264;
     info.mBufferType = GMP_BufferLength32;
     info.mCodecSpecific.mH264.mSimulcastIdx = 0;
     GMPLOG (GL_DEBUG, "Calling callback");
     callback_->Encoded (f, reinterpret_cast<uint8_t*> (&info), sizeof(info));
     GMPLOG (GL_DEBUG, "Callback called");
   }
 
-  virtual GMPErr SetChannelParameters (uint32_t aPacketLoss, uint32_t aRTT) {
-    return GMPNoErr;
+  virtual void SetChannelParameters (uint32_t aPacketLoss, uint32_t aRTT) {
   }
 
-  virtual GMPErr SetRates (uint32_t aNewBitRate, uint32_t aFrameRate) {
-    return GMPNoErr;
+  virtual void SetRates (uint32_t aNewBitRate, uint32_t aFrameRate) {
   }
 
-  virtual GMPErr SetPeriodicKeyFrames (bool aEnable) {
-    return GMPNoErr;
+  virtual void SetPeriodicKeyFrames (bool aEnable) {
   }
 
   virtual void EncodingComplete() {
     delete this;
   }
 
  private:
   uint8_t AveragePlane(uint8_t* ptr, size_t len) {
@@ -278,46 +271,41 @@ class FakeVideoDecoder : public GMPVideo
  public:
   FakeVideoDecoder (GMPVideoHost* hostAPI) :
     host_ (hostAPI),
     callback_ (NULL) {}
 
   virtual ~FakeVideoDecoder() {
   }
 
-  virtual GMPErr InitDecode (const GMPVideoCodec& codecSettings,
+  virtual void InitDecode (const GMPVideoCodec& codecSettings,
                              const uint8_t* aCodecSpecific,
                              uint32_t aCodecSpecificSize,
                              GMPVideoDecoderCallback* callback,
                              int32_t coreCount) {
     GMPLOG (GL_INFO, "InitDecode");
 
     callback_ = callback;
-    return GMPNoErr;
   }
 
-  virtual GMPErr Decode (GMPVideoEncodedFrame* inputFrame,
+  virtual void Decode (GMPVideoEncodedFrame* inputFrame,
                          bool missingFrames,
                          const uint8_t* aCodecSpecificInfo,
                          uint32_t aCodecSpecificInfoLength,
                          int64_t renderTimeMs = -1) {
     GMPLOG (GL_DEBUG, __FUNCTION__
             << "Decoding frame size=" << inputFrame->Size()
             << " timestamp=" << inputFrame->TimeStamp());
     g_platform_api->runonmainthread(new FakeDecoderTask(this, inputFrame, renderTimeMs));
-
-    return GMPNoErr;
   }
 
-  virtual GMPErr Reset() {
-    return GMPNoErr;
+  virtual void Reset() {
   }
 
-  virtual GMPErr Drain() {
-    return GMPNoErr;
+  virtual void Drain() {
   }
 
   virtual void DecodingComplete() {
     delete this;
   }
 
   // Return the decoded data back to the parent.
   void Decode_m (GMPVideoEncodedFrame* inputFrame,
--- a/dom/messages/test/mochitest.ini
+++ b/dom/messages/test/mochitest.ini
@@ -1,5 +1,5 @@
 [DEFAULT]
 skip-if = e10s
 
 [test_bug_993732.html]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
+skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
--- a/dom/permission/tests/mochitest.ini
+++ b/dom/permission/tests/mochitest.ini
@@ -2,26 +2,26 @@
 skip-if = e10s
 support-files =
   file_framework.js
   file_shim.html
 
 [test_alarms.html]
 [test_browser.html]
 [test_embed-apps.html]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
+skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_idle.html]
 skip-if = (toolkit == 'gonk' && debug) #debug-only failure
 [test_permission_basics.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' # b2g(https not working, bug 907770) b2g-debug(https not working, bug 907770) b2g-desktop(Bug 907770)
 [test_permissions.html]
 [test_power.html]
 [test_systemXHR.html]
 [test_tcp-socket.html]
 [test_webapps-manage.html]
 [test_camera.html]
 disabled = disabled until bug 859593 is fixed
 [test_keyboard.html]
 skip-if = toolkit == 'android'
 [test_input-manage.html]
 skip-if = toolkit == 'android'
 [test_wifi-manage.html]
-skip-if = (buildapp != 'b2g') || (buildapp == 'b2g' && toolkit != 'gonk') #b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
\ No newline at end of file
+skip-if = (buildapp != 'b2g') || (buildapp == 'b2g' && toolkit != 'gonk') #b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
--- a/dom/plugins/test/mochitest/chrome.ini
+++ b/dom/plugins/test/mochitest/chrome.ini
@@ -1,9 +1,10 @@
 [DEFAULT]
+skip-if = buildapp == "mulet"
 support-files =
   hang_test.js
   privatemode_perwindowpb.xul
   utils.js
 
 [test_bug479979.xul]
 [test_bug751809.html]
 [test_busy_hang.xul]
--- a/dom/plugins/test/mochitest/mochitest.ini
+++ b/dom/plugins/test/mochitest/mochitest.ini
@@ -1,10 +1,10 @@
 [DEFAULT]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || e10s #b2g-desktop(tests that use plugins)
+skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') || e10s #b2g-desktop(tests that use plugins)
 support-files =
   307-xo-redirect.sjs
   crashing_subpage.html
   file_bug738396.html
   file_bug771202.html
   file_bug863792.html
   large-pic.jpg
   loremipsum.txt
--- a/dom/plugins/test/unit/xpcshell.ini
+++ b/dom/plugins/test/unit/xpcshell.ini
@@ -1,9 +1,10 @@
 [DEFAULT]
+skip-if = buildapp == 'mulet'
 head = head_plugins.js
 tail = 
 
 [test_bug455213.js]
 # Bug 676953: test fails consistently on Android
 fail-if = os == "android"
 [test_bug471245.js]
 # Bug 676953: test fails consistently on Android
--- a/dom/power/test/mochitest.ini
+++ b/dom/power/test/mochitest.ini
@@ -1,15 +1,15 @@
 [DEFAULT]
 skip-if = e10s
 
 [test_bug957893.html]
 [test_bug957899.html]
 [test_wakelock_not_exposed.html]
-run-if = appname != "b2g"
+run-if = appname != "b2g" && buildapp != "mulet"
 [test_power_basics.html]
 [test_power_set_cpusleepallowed.html]
 skip-if = toolkit != "gonk"
 [test_power_set_screen_brightness.html]
 skip-if = toolkit != "gonk"
 [test_power_set_screen_enabled.html]
 skip-if = toolkit != "gonk"
 [test_power_set_key_light_enabled.html]
--- a/dom/settings/tests/chrome.ini
+++ b/dom/settings/tests/chrome.ini
@@ -1,6 +1,7 @@
 [DEFAULT]
 
 [test_settings_service.js]
 [test_settings_service.xul]
+skip-if= buildapp == 'mulet'
 [test_settings_service_callback.js]
 [test_settings_service_callback.xul]
--- a/dom/tests/browser/browser.ini
+++ b/dom/tests/browser/browser.ini
@@ -6,37 +6,40 @@ support-files =
   network_geolocation.sjs
   page_privatestorageevent.html
   position.html
   test-console-api.html
   test_bug1004814.html
   worker_bug1004814.js
 
 [browser_bug1008941_dismissGeolocationHanger.js]
+skip-if = buildapp == 'mulet'
 [browser_test__content.js]
 [browser_ConsoleAPITests.js]
 [browser_ConsoleStorageAPITests.js]
 [browser_ConsoleStoragePBTest_perwindowpb.js]
 [browser_autofocus_background.js]
+skip-if= buildapp == 'mulet'
 [browser_autofocus_preference.js]
 [browser_bug396843.js]
 [browser_focus_steal_from_chrome.js]
 [browser_focus_steal_from_chrome_during_mousedown.js]
 [browser_frame_elements.js]
 [browser_geolocation_privatebrowsing_perwindowpb.js]
 [browser_localStorage_privatestorageevent.js]
 [browser_test_new_window_from_content.js]
-skip-if = (toolkit == 'android' || buildapp == 'b2g')
+skip-if = (toolkit == 'android' || buildapp == 'b2g' || buildapp == 'mulet')
 support-files =
   test_new_window_from_content_child.html
   test_new_window_from_content_child.js
 [browser_webapps_permissions.js]
 # TODO: Re-enable permissions tests on Mac, bug 795334
 skip-if = buildapp != "b2g"
 support-files =
   test-webapp.webapp
   test-webapp-reinstall.webapp
   test-webapp-original.webapp
   test-webapps-permissions.html
 [browser_webapps_perms_reinstall.js]
 disabled = re-enable when bug 794920 is fixed
 [browser_xhr_sandbox.js]
+skip-if= buildapp == 'mulet'
 [browser_bug1004814.js]
--- a/dom/tests/mochitest/ajax/offline/mochitest.ini
+++ b/dom/tests/mochitest/ajax/offline/mochitest.ini
@@ -69,17 +69,17 @@ support-files =
 skip-if = buildapp == 'b2g' # b2g(all related, needs fix in offlineTests.js which could help) b2g-debug(all related, needs fix in offlineTests.js which could help) b2g-desktop(all related, needs fix in offlineTests.js which could help)
 [test_bug445544.html]
 skip-if = buildapp == 'b2g'
 [test_bug460353.html]
 skip-if = buildapp == 'b2g'
 [test_bug474696.html]
 skip-if = buildapp == 'b2g'
 [test_bug544462.html]
-skip-if = buildapp == 'b2g'
+skip-if = buildapp == 'mulet' || buildapp == 'b2g'
 [test_bug744719-cancel.html]
 skip-if = buildapp == 'b2g'
 [test_bug744719.html]
 skip-if = buildapp == 'b2g'
 [test_bug765203.html]
 skip-if = buildapp == 'b2g'
 [test_bypass.html]
 skip-if = buildapp == 'b2g'
--- a/dom/tests/mochitest/bugs/mochitest.ini
+++ b/dom/tests/mochitest/bugs/mochitest.ini
@@ -39,17 +39,17 @@ support-files =
 [test_bug159849.html]
 [test_bug260264.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(dom.disable_open_during_load not implemented in b2g) b2g-debug(dom.disable_open_during_load not implemented in b2g) b2g-desktop(dom.disable_open_during_load not implemented in b2g)
 [test_bug260264_nested.html]
 skip-if = buildapp == 'b2g' || e10s # b2g(dom.disable_open_during_load not implemented in b2g) b2g-debug(dom.disable_open_during_load not implemented in b2g) b2g-desktop(dom.disable_open_during_load not implemented in b2g)
 [test_bug265203.html]
 [test_bug291377.html]
 [test_bug291653.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #TIMED_OUT # b2g(showmodaldialog) b2g-debug(showmodaldialog) b2g-desktop(showmodaldialog)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #TIMED_OUT # b2g(showmodaldialog) b2g-debug(showmodaldialog) b2g-desktop(showmodaldialog)
 [test_bug304459.html]
 [test_bug308856.html]
 [test_bug327891.html]
 [test_bug333983.html]
 [test_bug335976.xhtml]
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
 [test_bug342448.html]
 [test_bug345521.html]
@@ -66,41 +66,41 @@ skip-if = (buildapp == 'b2g' && (toolkit
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug393974.html]
 [test_bug394769.html]
 [test_bug396843.html]
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
 [test_bug400204.html]
 [test_bug404748.html]
 [test_bug406375.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s
 [test_bug411103.html]
 [test_bug414291.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(showmodaldialog) b2g-debug(showmodaldialog) b2g-desktop(showmodaldialog)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(showmodaldialog) b2g-debug(showmodaldialog) b2g-desktop(showmodaldialog)
 [test_bug427744.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s
 [test_bug42976.html]
 [test_bug430276.html]
 [test_bug437361.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(dom.disable_open_during_load not implemented in b2g, showmodaldialog) b2g-debug(dom.disable_open_during_load not implemented in b2g, showmodaldialog) b2g-desktop(dom.disable_open_during_load not implemented in b2g, showmodaldialog)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(dom.disable_open_during_load not implemented in b2g, showmodaldialog) b2g-debug(dom.disable_open_during_load not implemented in b2g, showmodaldialog) b2g-desktop(dom.disable_open_during_load not implemented in b2g, showmodaldialog)
 [test_bug440572.html]
 [test_bug456151.html]
 [test_bug458091.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug459848.html]
 [test_bug465263.html]
 [test_bug479143.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(showmodaldialog) b2g-debug(showmodaldialog) b2g-desktop(showmodaldialog)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(showmodaldialog) b2g-debug(showmodaldialog) b2g-desktop(showmodaldialog)
 [test_bug484775.html]
 [test_bug492925.html]
 [test_bug49312.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug495219.html]
 [test_bug504862.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #RANDOM # b2g(showmodaldialog) b2g-debug(showmodaldialog) b2g-desktop(showmodaldialog)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #RANDOM # b2g(showmodaldialog) b2g-debug(showmodaldialog) b2g-desktop(showmodaldialog)
 [test_bug529328.html]
 [test_bug531176.html]
 [test_bug531542.html]
 [test_bug534149.html]
 [test_bug541530.html]
 [test_bug545314.html]
 [test_bug548828.html]
 [test_bug558973.html]
@@ -111,17 +111,17 @@ skip-if = (buildapp == 'b2g' && toolkit 
 [test_bug583225.html]
 [test_bug585240.html]
 [test_bug585819.html]
 [test_bug593174.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug597809.html]
 skip-if = toolkit == 'android' || e10s
 [test_bug61098.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(showmodaldialog) b2g-debug(showmodaldialog) b2g-desktop(showmodaldialog)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(showmodaldialog) b2g-debug(showmodaldialog) b2g-desktop(showmodaldialog)
 [test_bug612267.html]
 [test_bug617296.html]
 [test_bug620947.html]
 [test_bug622361.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug633133.html]
 [test_bug641552.html]
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || toolkit == 'android' || e10s
@@ -153,15 +153,15 @@ skip-if = (buildapp == 'b2g' && toolkit 
 [test_bug876098.html]
 [test_bug927901.html]
 [test_devicemotion_multiple_listeners.html]
 skip-if = toolkit == 'android' || e10s #bug 775227
 [test_domparser_after_blank.html]
 [test_onerror_message.html]
 [test_protochains.html]
 [test_resize_move_windows.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #Windows can't change size and position on Android # b2g(Windows can't change size and position on B2G) b2g-debug(Windows can't change size and position on B2G) b2g-desktop(Windows can't change size and position on B2G)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #Windows can't change size and position on Android # b2g(Windows can't change size and position on B2G) b2g-debug(Windows can't change size and position on B2G) b2g-desktop(Windows can't change size and position on B2G)
 [test_sizetocontent_clamp.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #Windows can't change size on Android # b2g(Windows can't change size on B2G) b2g-debug(Windows can't change size on B2G) b2g-desktop(Windows can't change size on B2G)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #Windows can't change size on Android # b2g(Windows can't change size on B2G) b2g-debug(Windows can't change size on B2G) b2g-desktop(Windows can't change size on B2G)
 [test_toJSON.html]
 [test_window_bar.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s
 [test_bug1022869.html]
--- a/dom/tests/mochitest/chrome/chrome.ini
+++ b/dom/tests/mochitest/chrome/chrome.ini
@@ -31,16 +31,17 @@ support-files =
 [test_bug800817.xul]
 [test_bug830396.xul]
 [test_bug830858.xul]
 [test_callback_wrapping.xul]
 [test_clonewrapper.xul]
 [test_cyclecollector.xul]
 [test_docshell_swap.xul]
 [test_focus.xul]
+skip-if = buildapp == 'mulet'
 [test_focus_docnav.xul]
 [test_focus_switchbinding.xul]
 [test_focused_link_scroll.xul]
 [test_fullscreen.xul]
 # disabled on linux for timeouts--bug-867745
 skip-if = os == 'linux'
 [test_fullscreen_preventdefault.xul]
 [test_geolocation.xul]
--- a/dom/tests/mochitest/general/chrome.ini
+++ b/dom/tests/mochitest/general/chrome.ini
@@ -1,6 +1,7 @@
 [DEFAULT]
 
 [test_innerScreen.xul]
 [test_offsets.css]
 [test_offsets.js]
 [test_offsets.xul]
+skip-if = buildapp == 'mulet'
--- a/dom/tests/mochitest/general/mochitest.ini
+++ b/dom/tests/mochitest/general/mochitest.ini
@@ -29,39 +29,42 @@ skip-if = (buildapp == 'b2g' && toolkit 
 [test_clipboard_events.html]
 skip-if = buildapp == 'b2g' # b2g(clipboard undefined) b2g-debug(clipboard undefined) b2g-desktop(clipboard undefined)
 [test_consoleAPI.html]
 [test_DOMMatrix.html]
 [test_domWindowUtils.html]
 [test_domWindowUtils_scrollXY.html]
 [test_domWindowUtils_scrollbarSize.html]
 [test_donottrack.html]
+skip-if = buildapp == 'mulet'
 [test_focus_legend_noparent.html]
 [test_focusrings.xul]
-skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT
 [test_for_of.html]
 [test_frameElementWrapping.html]
 [test_framedhistoryframes.html]
 [test_idleapi_permissions.html]
-skip-if = buildapp == 'b2g'
+skip-if = buildapp == 'b2g' || buildapp == 'mulet'
 [test_interfaces.html]
-skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
+skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 # [test_network_events.html]
 # Disable this test until bug 795711 is fixed.
 [test_offsets.html]
 [test_offsets.js]
 [test_outerHTML.html]
 [test_outerHTML.xhtml]
+skip-if = buildapp == 'mulet'
 [test_paste_selection.html]
+skip-if = buildapp == 'mulet'
 [test_picture_pref.html]
 [test_resource_timing.html]
-skip-if = buildapp == 'b2g' # b2g(No clipboard) b2g-debug(No clipboard) b2g-desktop(No clipboard)
+skip-if = buildapp == 'b2g' || buildapp == 'mulet' # b2g(No clipboard) b2g-debug(No clipboard) b2g-desktop(No clipboard)
 [test_performance_now.html]
 [test_srcset_pref.html]
 [test_showModalDialog.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' #Don't run modal tests on Android # b2g(showmodaldialog) b2g-debug(showmodaldialog) b2g-desktop(showmodaldialog)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' #Don't run modal tests on Android # b2g(showmodaldialog) b2g-debug(showmodaldialog) b2g-desktop(showmodaldialog)
 [test_stylesheetPI.html]
 [test_vibrator.html]
-skip-if = toolkit == 'android' #CRASH_SUTAGENT
+skip-if = buildapp == 'mulet' || toolkit == 'android' #CRASH_SUTAGENT
 [test_windowProperties.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_windowedhistoryframes.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
--- a/dom/tests/mochitest/geolocation/mochitest.ini
+++ b/dom/tests/mochitest/geolocation/mochitest.ini
@@ -18,27 +18,27 @@ skip-if = buildapp == 'b2g'
 [test_clearWatch.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT
 [test_clearWatch_invalid.html]
 skip-if = buildapp == 'b2g'
 [test_errorcheck.html]
 skip-if = toolkit=='gonk' || toolkit == 'android' || e10s #TIMED_OUT # b2g-debug(debug-only timeout)
 [test_geolocation_is_undefined_when_pref_is_off.html]
 [test_handlerSpinsEventLoop.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #Don't run modal tests on Android # b2g(showmodaldialog) b2g-debug(showmodaldialog) b2g-desktop(showmodaldialog)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #Don't run modal tests on Android # b2g(showmodaldialog) b2g-debug(showmodaldialog) b2g-desktop(showmodaldialog)
 [test_manyCurrentConcurrent.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT
 [test_manyCurrentSerial.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT
 [test_manyWatchConcurrent.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT
 [test_manyWatchSerial.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT
 [test_manyWindows.html]
-skip-if = buildapp == 'b2g'
+skip-if = buildapp == 'mulet' || buildapp == 'b2g'
 [test_mozsettings.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #mozSettings is undefined
 [test_mozsettingsWatch.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #mozSettings is undefined
 [test_optional_api_params.html]
 skip-if = buildapp == 'b2g'
 [test_shutdown.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT
--- a/dom/tests/mochitest/notification/mochitest.ini
+++ b/dom/tests/mochitest/notification/mochitest.ini
@@ -1,10 +1,10 @@
 [DEFAULT]
-skip-if = e10s
+skip-if = e10s || buildapp == 'mulet'
 support-files =
   MockServices.js
   NotificationTest.js
 
 [test_notification_basics.html]
 [test_notification_storage.html]
 skip-if = (toolkit == 'gonk' && debug) #debug-only timeout
 [test_bug931307.html]
--- a/dom/tests/mochitest/storageevent/mochitest.ini
+++ b/dom/tests/mochitest/storageevent/mochitest.ini
@@ -9,10 +9,11 @@ support-files =
   frameSessionStorageSlaveEqual.html
   frameSessionStorageSlaveNotEqual.html
   interOriginFrame.js
   interOriginTest2.js
 
 [test_storageLocalStorageEventCheckNoPropagation.html]
 [test_storageLocalStorageEventCheckPropagation.html]
 [test_storageNotifications.html]
+skip-if = buildapp == 'mulet'
 [test_storageSessionStorageEventCheckNoPropagation.html]
 [test_storageSessionStorageEventCheckPropagation.html]
--- a/dom/webidl/HTMLElement.webidl
+++ b/dom/webidl/HTMLElement.webidl
@@ -71,20 +71,16 @@ interface HTMLElement : Element {
   //readonly attribute boolean? commandDisabled;
   //readonly attribute boolean? commandChecked;
 
   // styling
   [PutForwards=cssText, Constant]
   readonly attribute CSSStyleDeclaration style;
 
   // Mozilla specific stuff
-  // FIXME Bug 810677 Move className from HTMLElement to Element
-  [Pure]
-           attribute DOMString className;
-
            attribute EventHandler oncopy;
            attribute EventHandler oncut;
            attribute EventHandler onpaste;
 };
 
 // http://dev.w3.org/csswg/cssom-view/#extensions-to-the-htmlelement-interface
 partial interface HTMLElement {
   // CSSOM things are not [Pure] because they can flush
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -732,16 +732,39 @@ public:
     AssertIsOnMainThread();
 
     nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     swm->FinishInstall(mRegistration.get());
     return NS_OK;
   }
 };
 
+class FinishActivationRunnable : public nsRunnable
+{
+  nsMainThreadPtrHandle<ServiceWorkerRegistration> mRegistration;
+
+public:
+  FinishActivationRunnable(const nsMainThreadPtrHandle<ServiceWorkerRegistration>& aRegistration)
+    : mRegistration(aRegistration)
+  {
+    MOZ_ASSERT(!NS_IsMainThread());
+  }
+
+  NS_IMETHODIMP
+  Run()
+  {
+    AssertIsOnMainThread();
+
+    // FinishActivate takes ownership of the passed info.
+    nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+    swm->FinishActivate(mRegistration.get());
+    return NS_OK;
+  }
+};
+
 class CancelServiceWorkerInstallationRunnable MOZ_FINAL : public nsRunnable
 {
   nsMainThreadPtrHandle<ServiceWorkerRegistration> mRegistration;
 
 public:
   explicit CancelServiceWorkerInstallationRunnable(
     const nsMainThreadPtrHandle<ServiceWorkerRegistration>& aRegistration)
     : mRegistration(aRegistration)
@@ -793,16 +816,49 @@ public:
   RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) MOZ_OVERRIDE
   {
     nsRefPtr<CancelServiceWorkerInstallationRunnable> r =
       new CancelServiceWorkerInstallationRunnable(mRegistration);
     NS_DispatchToMainThread(r);
   }
 };
 
+class FinishActivateHandler : public PromiseNativeHandler
+{
+  nsMainThreadPtrHandle<ServiceWorkerRegistration> mRegistration;
+
+public:
+  FinishActivateHandler(const nsMainThreadPtrHandle<ServiceWorkerRegistration>& aRegistration)
+    : mRegistration(aRegistration)
+  {
+    MOZ_ASSERT(!NS_IsMainThread());
+  }
+
+  virtual
+  ~FinishActivateHandler()
+  { }
+
+  void
+  ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) MOZ_OVERRIDE
+  {
+    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
+    MOZ_ASSERT(workerPrivate);
+    workerPrivate->AssertIsOnWorkerThread();
+
+    nsRefPtr<FinishActivationRunnable> r = new FinishActivationRunnable(mRegistration);
+    NS_DispatchToMainThread(r);
+  }
+
+  void
+  RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) MOZ_OVERRIDE
+  {
+    // FIXME(nsm). Spec is undefined.
+  }
+};
+
 /*
  * Fires 'install' event on the ServiceWorkerGlobalScope. Modifies busy count
  * since it fires the event. This is ok since there can't be nested
  * ServiceWorkers, so the parent thread -> worker thread requirement for
  * runnables is satisfied.
  */
 class InstallEventRunnable MOZ_FINAL : public WorkerRunnable
 {
@@ -868,22 +924,87 @@ private:
 
     nsRefPtr<FinishInstallHandler> handler =
       new FinishInstallHandler(mRegistration);
     waitUntilPromise->AppendNativeHandler(handler);
     return true;
   }
 };
 
+class ActivateEventRunnable : public WorkerRunnable
+{
+  nsMainThreadPtrHandle<ServiceWorkerRegistration> mRegistration;
+
+public:
+  ActivateEventRunnable(WorkerPrivate* aWorkerPrivate,
+                        const nsMainThreadPtrHandle<ServiceWorkerRegistration>& aRegistration)
+      : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount),
+        mRegistration(aRegistration)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+  }
+
+  bool
+  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    return DispatchActivateEvent(aCx, aWorkerPrivate);
+  }
+
+private:
+  bool
+  DispatchActivateEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
+  {
+    MOZ_ASSERT(aWorkerPrivate->IsServiceWorker());
+    nsRefPtr<EventTarget> target = do_QueryObject(aWorkerPrivate->GlobalScope());
+
+    // FIXME(nsm): Set activeWorker to the correct thing.
+    EventInit init;
+    init.mBubbles = false;
+    init.mCancelable = true;
+    nsRefPtr<InstallPhaseEvent> event =
+      InstallPhaseEvent::Constructor(target, NS_LITERAL_STRING("activate"), init);
+
+    event->SetTrusted(true);
+
+    nsRefPtr<Promise> waitUntilPromise;
+
+    nsresult rv = target->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
+    if (NS_SUCCEEDED(rv)) {
+      waitUntilPromise = event->GetPromise();
+      if (!waitUntilPromise) {
+        ErrorResult rv;
+        nsCOMPtr<nsIGlobalObject> global =
+          do_QueryObject(aWorkerPrivate->GlobalScope());
+        waitUntilPromise =
+          Promise::Resolve(global,
+                           aCx, JS::UndefinedHandleValue, rv);
+      }
+    } else {
+      ErrorResult rv;
+      nsCOMPtr<nsIGlobalObject> global =
+        do_QueryObject(aWorkerPrivate->GlobalScope());
+      // Continue with a canceled install.
+      waitUntilPromise = Promise::Reject(global, aCx,
+                                         JS::UndefinedHandleValue, rv);
+    }
+
+    nsRefPtr<FinishActivateHandler> handler = new FinishActivateHandler(mRegistration);
+    waitUntilPromise->AppendNativeHandler(handler);
+    return true;
+  }
+};
+
 void
 ServiceWorkerManager::Install(ServiceWorkerRegistration* aRegistration,
                               ServiceWorkerInfo* aServiceWorkerInfo)
 {
   AssertIsOnMainThread();
   aRegistration->mInstallingWorker = aServiceWorkerInfo;
+  MOZ_ASSERT(aRegistration->mInstallingWorker);
 
   nsMainThreadPtrHandle<ServiceWorkerRegistration> handle =
     new nsMainThreadPtrHolder<ServiceWorkerRegistration>(aRegistration);
 
   nsRefPtr<ServiceWorker> serviceWorker;
   nsresult rv =
     CreateServiceWorker(aServiceWorkerInfo->GetScriptSpec(),
                         aRegistration->mScope,
@@ -915,49 +1036,110 @@ ServiceWorkerManager::Install(ServiceWor
   // transactions in the first place.
 
   FireEventOnServiceWorkerContainers(aRegistration,
                                      NS_LITERAL_STRING("updatefound"));
 }
 
 class ActivationRunnable : public nsRunnable
 {
+  nsRefPtr<ServiceWorkerRegistration> mRegistration;
 public:
   explicit ActivationRunnable(ServiceWorkerRegistration* aRegistration)
-  { }
+    : mRegistration(aRegistration)
+  {
+  }
+
+  NS_IMETHODIMP
+  Run() MOZ_OVERRIDE
+  {
+    if (mRegistration->mCurrentWorker) {
+      // FIXME(nsm). Steps 3.1-3.4 of the algorithm.
+    }
+
+    mRegistration->mCurrentWorker = mRegistration->mWaitingWorker.forget();
+
+    // FIXME(nsm): Steps 7 of the algorithm.
+
+    nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+
+    swm->FireEventOnServiceWorkerContainers(mRegistration,
+                                            NS_LITERAL_STRING("controllerchange"));
+
+    MOZ_ASSERT(mRegistration->mCurrentWorker);
+    nsRefPtr<ServiceWorker> serviceWorker;
+    nsresult rv =
+      swm->CreateServiceWorker(mRegistration->mCurrentWorker->GetScriptSpec(),
+                               mRegistration->mScope,
+                               getter_AddRefs(serviceWorker));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    nsMainThreadPtrHandle<ServiceWorkerRegistration> handle =
+      new nsMainThreadPtrHolder<ServiceWorkerRegistration>(mRegistration);
+
+    nsRefPtr<ActivateEventRunnable> r =
+      new ActivateEventRunnable(serviceWorker->GetWorkerPrivate(), handle);
+
+    AutoSafeJSContext cx;
+    if (!r->Dispatch(cx)) {
+      return NS_ERROR_FAILURE;
+    }
+
+    return NS_OK;
+  }
 };
 
 void
 ServiceWorkerManager::FinishInstall(ServiceWorkerRegistration* aRegistration)
 {
   AssertIsOnMainThread();
 
   if (aRegistration->mWaitingWorker) {
     // FIXME(nsm): Actually update the state of active ServiceWorker instances.
   }
 
+  if (!aRegistration->mInstallingWorker) {
+    // It is possible that while this run of [[Install]] was waiting for
+    // the worker to handle the install event, some page called register() with
+    // a different script leading to [[Update]] terminating the
+    // installingWorker and setting it to null. The FinishInstallRunnable may
+    // already have been dispatched, hence the check.
+    return;
+  }
+
   aRegistration->mWaitingWorker = aRegistration->mInstallingWorker.forget();
+  MOZ_ASSERT(aRegistration->mWaitingWorker);
 
   // FIXME(nsm): Actually update state of active ServiceWorker instances to
   // installed.
   // FIXME(nsm): Fire statechange on the instances.
 
   // FIXME(nsm): Handle replace().
 
-  // FIXME(nsm): Check that no document is using the registration!
-
-  nsRefPtr<ActivationRunnable> r =
-    new ActivationRunnable(aRegistration);
+  if (!aRegistration->IsControllingDocuments()) {
+    nsRefPtr<ActivationRunnable> r =
+      new ActivationRunnable(aRegistration);
 
-  nsresult rv = NS_DispatchToMainThread(r);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    // FIXME(nsm): Handle error.
+    nsresult rv = NS_DispatchToMainThread(r);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      // FIXME(nsm): Handle error.
+      // How likely is this to happen and can we really do anything about it?
+    }
   }
 }
 
+void
+ServiceWorkerManager::FinishActivate(ServiceWorkerRegistration* aRegistration)
+{
+  // FIXME(nsm): Set aRegistration->mCurrentWorker state to activated.
+  // Fire statechange.
+}
+
 NS_IMETHODIMP
 ServiceWorkerManager::CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow,
                                                    const nsACString& aScriptSpec,
                                                    const nsACString& aScope,
                                                    ServiceWorker** aServiceWorker)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aWindow);
@@ -1210,16 +1392,17 @@ ServiceWorkerManager::GetScopeForUrl(con
   nsRefPtr<ServiceWorkerRegistration> r = GetServiceWorkerRegistration(uri);
   if (!r) {
       return NS_ERROR_FAILURE;
   }
 
   aScope = NS_ConvertUTF8toUTF16(r->mScope);
   return NS_OK;
 }
+
 NS_IMETHODIMP
 ServiceWorkerManager::AddContainerEventListener(nsIURI* aDocumentURI, nsIDOMEventTarget* aListener)
 {
   MOZ_ASSERT(aDocumentURI);
   nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(aDocumentURI);
   if (!domainInfo) {
     nsCString domain;
     nsresult rv = aDocumentURI->GetHost(domain);
--- a/dom/workers/ServiceWorkerManager.h
+++ b/dom/workers/ServiceWorkerManager.h
@@ -181,16 +181,17 @@ public:
 
 /*
  * The ServiceWorkerManager is a per-process global that deals with the
  * installation, querying and event dispatch of ServiceWorkers for all the
  * origins in the process.
  */
 class ServiceWorkerManager MOZ_FINAL : public nsIServiceWorkerManager
 {
+  friend class ActivationRunnable;
   friend class RegisterRunnable;
   friend class CallInstallRunnable;
   friend class ServiceWorkerUpdateInstance;
 
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSISERVICEWORKERMANAGER
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_SERVICEWORKERMANAGER_IMPL_IID)
@@ -281,16 +282,19 @@ public:
   void
   FinishFetch(ServiceWorkerRegistration* aRegistration,
               nsPIDOMWindow* aWindow);
 
   void
   FinishInstall(ServiceWorkerRegistration* aRegistration);
 
   void
+  FinishActivate(ServiceWorkerRegistration* aRegistration);
+
+  void
   HandleError(JSContext* aCx,
               const nsACString& aScope,
               const nsAString& aWorkerURL,
               nsString aMessage,
               nsString aFilename,
               nsString aLine,
               uint32_t aLineNumber,
               uint32_t aColumnNumber,
--- a/dom/workers/test/mochitest.ini
+++ b/dom/workers/test/mochitest.ini
@@ -114,16 +114,17 @@ skip-if = buildapp == 'b2g' # b2g(Failed
 skip-if = (toolkit == 'gonk' && debug) #debug-only failure
 [test_loadEncoding.html]
 [test_loadError.html]
 [test_location.html]
 [test_longThread.html]
 [test_multi_sharedWorker.html]
 [test_multi_sharedWorker_lifetimes.html]
 [test_navigator.html]
+skip-if = buildapp == 'mulet'
 [test_newError.html]
 [test_onLine.html]
 skip-if = (toolkit == 'gonk' && debug) #debug-only failure
 [test_promise.html]
 [test_promise_resolved_with_string.html]
 [test_recursion.html]
 [test_recursiveOnerror.html]
 [test_relativeLoad.html]
--- a/dom/workers/test/serviceworkers/install_event_worker.js
+++ b/dom/workers/test/serviceworkers/install_event_worker.js
@@ -1,4 +1,3 @@
 oninstall = function(e) {
-  dump("NSM Got install event\n");
-  dump(e.activeWorker);
+  dump("Got install event\n");
 }
--- a/dom/workers/test/serviceworkers/test_install_event.html
+++ b/dom/workers/test/serviceworkers/test_install_event.html
@@ -11,24 +11,29 @@
 </head>
 <body>
 <p id="display"></p>
 <div id="content" style="display: none"></div>
 <pre id="test"></pre>
 <script class="testbody" type="text/javascript">
 
   function simpleRegister() {
-    var p = navigator.serviceWorker.register("worker.js");
+    var p = navigator.serviceWorker.register("worker.js", { scope: "./*" });
     return p;
   }
 
   function nextRegister() {
-    var p = navigator.serviceWorker.register("install_event_worker.js");
-    todo(false, "Check for onupdatefound event");
-    return p;
+    var p = navigator.serviceWorker.register("install_event_worker.js", { scope: "./*" });
+
+    return new Promise(function(resolve, reject) {
+      navigator.serviceWorker.onupdatefound = function(e) {
+        ok(true, "Received onupdatefound");
+        resolve();
+      };
+    });
   }
 
   function runTest() {
     simpleRegister()
       .then(nextRegister)
       .then(function() {
         SimpleTest.finish();
       }).catch(function(e) {
--- a/dom/workers/test/serviceworkers/test_installation_simple.html
+++ b/dom/workers/test/serviceworkers/test_installation_simple.html
@@ -123,17 +123,17 @@
     simpleRegister()
       .then(sameOriginWorker)
       .then(sameOriginScope)
       .then(httpsOnly)
       .then(realWorker)
       .then(abortPrevious)
       .then(networkError404)
       .then(parseError)
-      .then(updatefound)
+      //.then(updatefound)
       // put more tests here.
       .then(function() {
         SimpleTest.finish();
       }).catch(function(e) {
         ok(false, "Some test failed with error " + e);
         SimpleTest.finish();
       });
   }
--- a/editor/composer/test/mochitest.ini
+++ b/editor/composer/test/mochitest.ini
@@ -1,10 +1,10 @@
 [DEFAULT]
-skip-if = buildapp == 'b2g'
+skip-if = buildapp == 'b2g' || buildapp == 'mulet'
 support-files = bug678842_subframe.html
 
 [test_bug348497.html]
 [test_bug384147.html]
 [test_bug389350.html]
 skip-if = toolkit == 'android'
 [test_bug519928.html]
 [test_bug738440.html]
--- a/editor/libeditor/base/tests/chrome.ini
+++ b/editor/libeditor/base/tests/chrome.ini
@@ -1,8 +1,10 @@
 [DEFAULT]
 
 [test_bug46555.html]
 [test_bug599983.xul]
+skip-if = buildapp == 'mulet'
 [test_bug646194.xul]
 [test_composition_event_created_in_chrome.html]
 [test_dragdrop.html]
+skip-if = buildapp == 'mulet'
 [test_selection_move_commands.xul]
--- a/editor/libeditor/base/tests/mochitest.ini
+++ b/editor/libeditor/base/tests/mochitest.ini
@@ -1,10 +1,10 @@
 [DEFAULT]
-skip-if = buildapp == 'b2g'
+skip-if = buildapp == 'b2g' || buildapp == 'mulet'
 support-files = file_bug586662.html
 
 [test_bug408231.html]
 skip-if = toolkit == 'android'
 [test_bug502673.html]
 [test_bug514156.html]
 [test_bug567213.html]
 [test_bug586662.html]
--- a/editor/libeditor/html/tests/mochitest.ini
+++ b/editor/libeditor/html/tests/mochitest.ini
@@ -1,10 +1,10 @@
 [DEFAULT]
-skip-if = buildapp == 'b2g'
+skip-if = buildapp == 'mulet' || buildapp == 'b2g'
 support-files =
   data/cfhtml-chromium.txt
   data/cfhtml-firefox.txt
   data/cfhtml-ie.txt
   data/cfhtml-ooo.txt
   data/cfhtml-nocontext.txt
   file_bug549262.html
   file_bug674770-1.html
--- a/editor/libeditor/text/tests/chrome.ini
+++ b/editor/libeditor/text/tests/chrome.ini
@@ -1,9 +1,10 @@
 [test_bug471319.html]
 [test_bug483651.html]
 [test_bug569988.html]
+skip-if = buildapp == 'mulet'
 [test_bug636465.xul]
 [test_bug830600.html]
 [test_texteditor_keyevent_handling.html]
 # disables the key handling test on gtk because gtk overrides some key events
 # on our editor, and the combinations depend on the system.
 skip-if = toolkit == "gtk2" || toolkit == "gtk3"
--- a/editor/libeditor/text/tests/mochitest.ini
+++ b/editor/libeditor/text/tests/mochitest.ini
@@ -6,16 +6,17 @@ skip-if = buildapp == 'b2g'
 [test_bug527935.html]
 skip-if = toolkit == 'android' || e10s
 [test_bug590554.html]
 [test_bug596001.html]
 [test_bug596333.html]
 skip-if = toolkit == 'android' || e10s
 [test_bug596506.html]
 [test_bug597331.html]
+skip-if = buildapp == 'mulet'
 [test_bug600570.html]
 skip-if = toolkit == 'android'
 [test_bug602130.html]
 [test_bug603556.html]
 [test_bug604532.html]
 skip-if = toolkit == 'android'
 [test_bug625452.html]
 [test_bug629172.html]
--- a/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/upstream-hunspell.diff
+++ b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/upstream-hunspell.diff
@@ -10548,813 +10548,816 @@ 36041c41717
 < packing's
 ---
 > packing/M
 36056,36059d41731
 < paederast/S
 < paediatrician's
 < paediatricians
 < paediatrics/M
-36291a41964
+36290a41963,41964
+> parallelization/SM
+> parallelize/SGD
+36291a41966
 > paralyses
-36377a42051
+36377a42053
 > parkour
-36403d42076
+36403d42078
 < parrakeet/MS
-36418,36419c42091
+36418,36419c42093
 < part's
 < part/CDSG
 ---
 > part/CDSGM
-36445,36447c42117
+36445,36447c42119
 < partition's
 < partition/ADG
 < partitions
 ---
 > partition/ADGMS
-36449d42118
+36449d42120
 < partizan/SM
-36621,36622c42290
+36621,36622c42292
 < pay's
 < pay/ASGBL
 ---
 > pay/ASGBLM
-37093a42762
+37093a42764
 > petabyte/MS
-37102c42771
+37102c42773
 < petitioner/M
 ---
 > petitioner/MS
-37221a42891,42892
+37221a42893,42894
 > phlebotomist/SM
 > phlebotomize/SGD
-37264a42936
+37264a42938
 > phosphorylate/DSGN
-37310,37311c42982
+37310,37311c42984
 < phrase's
 < phrase/AGDS
 ---
 > phrase/AGDSM
-37316d42986
+37316d42988
 < phrenetic
-37469,37470c43139
+37469,37470c43141
 < pine's
 < pine/AGDS
 ---
 > pine/AGDSM
-37596,37597c43265
+37596,37597c43267
 < place's
 < place/EAGLDS
 ---
 > place/EAGLDSM
-37630a43299
+37630a43301
 > plaintext
-37636,37637c43305
+37636,37637c43307
 < plane's
 < plane/CGDS
 ---
 > plane/CGDSM
-37786,37787c43454
+37786,37787c43456
 < ploy's
 < ploy/S
 ---
 > ploy/SM
-37792,37793c43459
+37792,37793c43461
 < plug's
 < plug/US
 ---
 > plug/USM
-37796a43463
+37796a43465
 > plugin/MS
-37987c43654
+37987c43656
 < polypeptide/S
 ---
 > polypeptide/MS
-38106,38107c43773
+38106,38107c43775
 < port's
 < port/CAEGDS
 ---
 > port/CAEGDSM
-38134,38135c43800
+38134,38135c43802
 < pose's/A
 < pose/CAKEGDS
 ---
 > pose/CAKEGDSM
-38140,38141c43805
+38140,38141c43807
 < position's/KC
 < position/ACKES
 ---
 > position/ACKESM
-38260,38261c43924
+38260,38261c43926
 < pound's
 < pound/KDSG
 ---
 > pound/KDSGM
-38291d43953
+38291d43955
 < practise's
-38451a44114
+38451a44116
 > prejudgement/MS
-38568,38569c44231
+38568,38569c44233
 < press's
 < press/ACGSD
 ---
 > press/ACGSDM
-38638,38639c44300
+38638,38639c44302
 < price's
 < price/AGDS
 ---
 > price/AGDSM
-38756,38757c44417
+38756,38757c44419
 < process's
 < process/AGDS
 ---
 > process/AGDSM
-38780,38781c44440
+38780,38781c44442
 < produce's
 < produce/AZGDRS
 ---
 > produce/AZGDRSM
-38805a44465
+38805a44467
 > profiler/SM
-38835a44496
+38835a44498
 > programmatically
-38891a44553,44554
+38891a44555,44556
 > pronate/DSGN
 > pronator/MS
-38951c44614
+38951c44616
 < proprietorship/M
 ---
 > proprietorship/MS
-39039a44703
+39039a44705
 > provender/M
-39095a44760
+39095a44762
 > pseudorandom/Y
-39564a45230
+39564a45232
 > quinoa
-39581,39582c45247
+39581,39582c45249
 < quire's
 < quire/IAS
 ---
 > quire/IASM
-39614,39615c45279
+39614,39615c45281
 < quote's
 < quote/UDSG
 ---
 > quote/UDSGM
-39653,39654c45317
+39653,39654c45319
 < racoon's
 < racoons
 ---
 > racoon/MS
-39738,39739c45401
+39738,39739c45403
 < rail's
 < rail/CGDS
 ---
 > rail/CGDSM
-39816,39817c45478
+39816,39817c45480
 < range's
 < range/CGDS
 ---
 > range/CGDSM
-39873a45535,45536
+39873a45537,45538
 > rasterization/M
 > rasterize/SGDR
-39925,39926c45588
+39925,39926c45590
 < ravel's
 < ravel/UDSG
 ---
 > ravel/UDSGM
-40036a45699
+40036a45701
 > recency
-40140a45804
+40140a45806
 > recurse/DGSV
-40141a45806
+40141a45808
 > recuse/DGS
-40204,40205c45869
+40204,40205c45871
 < reel's
 < reel/UGDS
 ---
 > reel/UGDSM
-40208a45873
+40208a45875
 > refactor/SMDG
-40244d45908
+40244d45910
 < reflexion/SM
-40659d46322
+40659d46324
 < resizing
-40829c46492
+40829c46494
 < reverie/M
 ---
 > reverie/MS
-40895a46559,46561
+40895a46561,46563
 > rheumatological
 > rheumatology/M
 > rheumatologist/SM
-40944,40945c46610
+40944,40945c46612
 < ride's
 < ride/CZGS
 ---
 > ride/CZGSM
-41104,41105c46769
+41104,41105c46771
 < robe's
 < robe/EGDS
 ---
 > robe/EGDSM
-41132,41133c46796
+41132,41133c46798
 < rogue's
 < rogue/KS
 ---
 > rogue/KSM
-41185a46849
+41185a46851
 > rootkit/MS
-41258,41259c46922
+41258,41259c46924
 < route's
 < route/ADSG
 ---
 > route/ADSGM
-41415a47079
+41415a47081
 > sabre/MS
-41447,41448c47111
+41447,41448c47113
 < saddle's
 < saddle/UDSG
 ---
 > saddle/UDSGM
-41463,41464c47126
+41463,41464c47128
 < safe's
 < safe/UYTPR
 ---
 > safe/UYTPRM
-41544,41545c47206
+41544,41545c47208
 < salt's
 < salt/CTGDS
 ---
 > salt/CTGDSM
-41765,41766c47426
+41765,41766c47428
 < say's
 < say/USG
 ---
 > say/USGM
-41787,41788c47447
+41787,41788c47449
 < scale's
 < scale/ACSDG
 ---
 > scale/ACSDGM
-41806,41807c47465
+41806,41807c47467
 < scan's
 < scan/AS
 ---
 > scan/ASM
-41880,41881c47538
+41880,41881c47540
 < schedule's
 < schedule/ADSG
 ---
 > schedule/ADSGM
-41914c47571
+41914c47573
 < schnaps's
 ---
 > schnaps/M
-41949c47606
+41949c47608
 < schrod's
 ---
 > schrod/SM
-41998a47656
+41998a47658
 > scot-free
-42016,42017c47674
+42016,42017c47676
 < scramble's
 < scramble/UGDS
 ---
 > scramble/UGDSM
-42055,42056c47712
+42055,42056c47714
 < screw's
 < screw/UDSG
 ---
 > screw/UDSGM
-42065,42066c47721
+42065,42066c47723
 < scribe's
 < scribe/IKCGSD
 ---
 > scribe/IKCGSDM
-42170,42171c47825
+42170,42171c47827
 < seal's
 < seal/AUSDG
 ---
 > seal/AUSDGM
-42204,42205c47858
+42204,42205c47860
 < seat's
 < seat/UGDS
 ---
 > seat/UGDSM
-42288,42289c47941
+42288,42289c47943
 < seed's
 < seed/AGDS
 ---
 > seed/AGDSM
-42365,42367c48017,48018
+42365,42367c48019,48020
 < sell's
 < sell/AZGRS
 < seller's
 ---
 > sell/AZGRSM
 > seller/M
-42524c48175
+42524c48177
 < seraphim's
 ---
 > seraphim/M
-42558,42559c48209
+42558,42559c48211
 < serve's/AF
 < serve/FACGDS
 ---
 > serve/FACGDSM
-42574,42575c48224
+42574,42575c48226
 < serving's
 < servings
 ---
 > serving/MS
-42594,42595c48243
+42594,42595c48245
 < settle's
 < settle/AUGDS
 ---
 > settle/AUGDSM
-42647,42648c48295
+42647,42648c48297
 < shackle's
 < shackle/UGDS
 ---
 > shackle/UGDSM
-42716,42717c48363
+42716,42717c48365
 < shape's
 < shape/AGDS
 ---
 > shape/AGDSM
-42851,42852c48497
+42851,42852c48499
 < ship's
 < ship/ALS
 ---
 > ship/ALSM
-42883,42885c48528
+42883,42885c48530
 < shit's
 < shit/S!
 < shite/S!
 ---
 > shit/MS!
-42887,42888c48530,48531
+42887,42888c48532,48533
 < shithead/S!
 < shitload/!
 ---
 > shithead/MS!
 > shitload/MS!
-42891c48534
+42891c48536
 < shitty/RT!
 ---
 > shitty/TR!
-42976a48620
+42976a48622
 > should've
-43008c48652
+43008c48654
 < showtime
 ---
 > showtime/MS
-43090,43091c48734
+43090,43091c48736
 < side's
 < side/AGDS
 ---
 > side/AGDSM
-43143,43144c48786
+43143,43144c48788
 < sign's
 < sign/AFCGDS
 ---
 > sign/AFCGDSM
-43163,43164c48805
+43163,43164c48807
 < signing's/C
 < signings
 ---
 > signing/MCS
-43328c48969
+43328c48971
 < size/MGBDRS
 ---
 > size/AMGBDRS
-43368,43369c49009
+43368,43369c49011
 < skill's
 < skill/CSD
 ---
 > skill/CSDM
-43724,43726c49364
+43724,43726c49366
 < smoulder's
 < smouldered
 < smoulders
 ---
 > smoulder/GSMD
-43752,43753c49390
+43752,43753c49392
 < snap's
 < snap/US
 ---
 > snap/USM
-43767,43768c49404,49406
+43767,43768c49406,49408
 < snarl's
 < snarl/USDG
 ---
 > snarkily
 > snarky/TR
 > snarl/USDGM
-44012,44013c49650
+44012,44013c49652
 < solute's
 < solute/XN
 ---
 > solute/XNM
-44015c49652
+44015c49654
 < solution's/EA
 ---
 > solution/EAM
-44021c49658
+44021c49660
 < solver's
 ---
 > solver/M
-44041a49679
+44041a49681
 > sommelier/SM
-44062c49700
+44062c49702
 < sonofabitch
 ---
 > sonofabitch/!
-44177,44178c49815
+44177,44178c49817
 < sow's
 < sow/ASGD
 ---
 > sow/ASGDM
-44346a49984
+44346a49986
 > spelled
-44348a49987
+44348a49989
 > spelt
-44371a50011
+44371a50013
 > spick/S!
-44383c50023
+44383c50025
 < spik/S
 ---
 > spik/S!
-44413,44414c50053
+44413,44414c50055
 < spire's
 < spire/IFAS
 ---
 > spire/IFASM
-44416,44417c50055
+44416,44417c50057
 < spirit's
 < spirit/ISGD
 ---
 > spirit/ISGDM
-44475,44476c50113
+44475,44476c50115
 < spoil's
 < spoil/CSDRZG
 ---
 > spoil/CSDRZGM
-44549,44550c50186
+44549,44550c50188
 < spray's
 < spray/ASDG
 ---
 > spray/ASDGM
-44688,44689c50324
+44688,44689c50326
 < staff's
 < staff/ASDG
 ---
 > staff/ASDGM
-44729,44730c50364
+44729,44730c50366
 < stall's
 < stall/SDG
 ---
 > stall/SDGM
-44985,44986c50619
+44985,44986c50621
 < still's
 < still/ITGSD
 ---
 > still/ITGSDM
-45024,45025c50657
+45024,45025c50659
 < stitch's
 < stitch/ADSG
 ---
 > stitch/ADSGM
-45030,45031c50662
+45030,45031c50664
 < stock's
 < stock/AGSD
 ---
 > stock/AGSDM
-45090,45091c50721
+45090,45091c50723
 < stop's
 < stop/US
 ---
 > stop/USM
-45105,45106c50735
+45105,45106c50737
 < store's
 < store/ADSG
 ---
 > store/ADSGM
-45148,45149c50777
+45148,45149c50779
 < strain's
 < strain/FADSG
 ---
 > strain/FADSGM
-45164,45165c50792
+45164,45165c50794
 < strap's
 < strap/US
 ---
 > strap/USM
-45290,45291c50917
+45290,45291c50919
 < structure's
 < structure/AGDS
 ---
 > structure/AGDSM
-45330,45331c50956
+45330,45331c50958
 < study's
 < study/AGDS
 ---
 > study/AGDSM
-45368,45369c50993
+45368,45369c50995
 < style's
 < style/ADSG
 ---
 > style/ADSGM
-45455,45456c51079
+45455,45456c51081
 < submission's
 < submission/AS
 ---
 > submission/ASM
-45872,45873c51495
+45872,45873c51497
 < surface's
 < surface/AGDS
 ---
 > surface/AGDSM
-45918,45919c51540
+45918,45919c51542
 < survey's
 < survey/ADGS
 ---
 > survey/ADGSM
-46106a51728
+46106a51730
 > syllabi
-46160c51782
+46160c51784
 < synch/GMD
 ---
 > synch/GMDS
-46167d51788
+46167d51790
 < synchs
-46178a51800,51802
+46178a51802,51804
 > synesthesia
 > synesthete/S
 > synesthetic
-46203,46204c51827,51828
+46203,46204c51829,51830
 < sysadmin/S
 < sysop/S
 ---
 > sysadmin/MS
 > sysop/MS
-46363,46364c51987
+46363,46364c51989
 < tangle's
 < tangle/UDSG
 ---
 > tangle/UDSGM
-46632a52256,52257
+46632a52258,52259
 > teleport/SGD
 > teleportation
-46675,46676c52300
+46675,46676c52302
 < template's
 < template/S
 ---
 > template/SM
-46752a52377
+46752a52379
 > terabit/MS
-46753a52379,52380
+46753a52381,52382
 > terahertz/M
 > terapixel/MS
-46806,46807c52433
+46806,46807c52435
 < test's/AFK
 < test/AKFCDGS
 ---
 > test/AKFCDGSM
-46817a52444
+46817a52446
 > testcase/MS
-46831a52459
+46831a52461
 > testsuite/MS
-46845a52474
+46845a52476
 > textbox/SM
-46925a52555
+46925a52557
 > theremin/MS
-46999c52629
+46999c52631
 < thinking's
 ---
 > thinking/M
-47095,47096c52725
+47095,47096c52727
 < throne's
 < throne/CDS
 ---
 > throne/CDSM
-47188,47189c52817
+47188,47189c52819
 < tie's
 < tie/AUSD
 ---
 > tie/AUSDM
-47213,47214c52841
+47213,47214c52843
 < till's
 < till/EDRZGS
 ---
 > till/EDRZGSM
-47303,47304c52930
+47303,47304c52932
 < tire's
 < tire/AGDS
 ---
 > tire/AGDSM
-47433,47434c53059
+47433,47434c53061
 < tone's
 < tone/IZGDRS
 ---
 > tone/IZGDRSM
-47453,47455c53078,53079
+47453,47455c53080,53081
 < tool's
 < tool/ADGS
 < toolbar
 ---
 > tool/ADGSM
 > toolbar/MS
-47540,47541c53164
+47540,47541c53166
 < tort's
 < tort/FEAS
 ---
 > tort/FEASM
-47644a53268
+47644a53270
 > traceur/SM
-47657,47658c53281
+47657,47658c53283
 < tract's
 < tract/CEKFAS
 ---
 > tract/CEKFASM
-47755a53379
+47755a53381
 > transfect/DSMG
-47774a53399,53400
+47774a53401,53402
 > transgenderism
 > transgene/MS
-47807,47808c53433
+47807,47808c53435
 < transmission's
 < transmission/AS
 ---
 > transmission/ASM
-47928,47929c53553
+47928,47929c53555
 < trench's
 < trench/AIGSD
 ---
 > trench/AIGSDM
-47951c53575
+47951c53577
 < triage/M
 ---
 > triage/MGS
-47976,47977c53600
+47976,47977c53602
 < tribute's
 < tribute/FS
 ---
 > tribute/FSM
-47997a53621
+47997a53623
 > trifecta/S
-48165,48166c53789
+48165,48166c53791
 < trust's/E
 < trust/IESGD
 ---
 > trust/IESGDM
-48180,48181c53803
+48180,48181c53805
 < try's
 < try/AGDS
 ---
 > try/AGDSM
-48371,48372c53993
+48371,48372c53995
 < twist's
 < twist/USDG
 ---
 > twist/USDGM
-48396,48397c54017
+48396,48397c54019
 < type's
 < type/AGDS
 ---
 > type/AGDSM
-48869a54490
+48869a54492
 > unlikeable
-49163,49164c54784
+49163,49164c54786
 < usual's
 < usual/UY
 ---
 > usual/UYM
-49211c54831
+49211c54833
 < vagina/M
 ---
 > vagina/MS
-49249,49250c54869
+49249,49250c54871
 < value's
 < value/CAGSD
 ---
 > value/CAGSDM
-49292,49293c54911
+49292,49293c54913
 < variant's
 < variant/IS
 ---
 > variant/ISM
-49356,49357c54974
+49356,49357c54976
 < veil's
 < veil/UDGS
 ---
 > veil/UDGSM
-49368,49369c54985
+49368,49369c54987
 < velour's
 < velours's
 ---
 > velour/MS
-49398,49399c55014
+49398,49399c55016
 < vent's
 < vent/DGS
 ---
 > vent/DGSM
-49435,49436c55050
+49435,49436c55052
 < verge's
 < verge/FDSG
 ---
 > verge/FDSGM
-49478a55093
+49478a55095
 > vertices
-49488,49489c55103
+49488,49489c55105
 < vest's
 < vest/ILDGS
 ---
 > vest/ILDGSM
-49681,49682c55295
+49681,49682c55297
 < visit's
 < visit/ASGD
 ---
 > visit/ASGDM
-49772a55386,55388
+49772a55388,55390
 > volcanological
 > volcanologist/MS
 > volcanology/M
-49807,49808c55423
+49807,49808c55425
 < vote's
 < vote/CGVDS
 ---
 > vote/CGVDSM
-50148a55764
+50148a55766
 > weaponize/DSG
-50215,50216c55831
+50215,50216c55833
 < weigh's
 < weigh/AGD
 ---
 > weigh/AGDM
-50260,50261d55874
+50260,50261d55876
 < werwolf/M
 < werwolves
-50555,50556c56168
+50555,50556c56170
 < wind's
 < wind/UASG
 ---
 > wind/UASGM
-50626,50627c56238
+50626,50627c56240
 < wire's
 < wire/AGDS
 ---
 > wire/AGDSM
-50728c56339
+50728c56341
 < women
 ---
 > women/M
-50794,50796c56405,56406
+50794,50796c56407,56408
 < wop/S!
 < word's
 < word/AJDSG
 ---
 > wop/MS!
 > word/AJDSGM
-50801c56411
+50801c56413
 < wording's
 ---
 > wording/M
-50808,50809c56418
+50808,50809c56420
 < work's
 < work/ADJSG
 ---
 > work/ADJSGM
-50824c56433
+50824c56435
 < working's
 ---
 > working/M
-50884,50885c56493
+50884,50885c56495
 < worthy's
 < worthy/UPRT
 ---
 > worthy/UPRTM
-50903,50904c56511
+50903,50904c56513
 < wrap's
 < wrap/US
 ---
 > wrap/USM
-50945c56552
+50945c56554
 < writing's
 ---
 > writing/M
-51118,51119c56725
+51118,51119c56727
 < yoke's
 < yoke/UGDS
 ---
 > yoke/UGDSM
-51212,51213c56818
+51212,51213c56820
 < zip's
 < zip/US
 ---
 > zip/USM
-51228,51229c56833
+51228,51229c56835
 < zone's
 < zone/AGDS
 ---
 > zone/AGDSM
--- a/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
+++ b/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
@@ -1,9 +1,9 @@
-57220
+57222
 0/nm
 0th/pt
 1/n1
 1st/p
 1th/tc
 2/nm
 2nd/p
 2th/tc
@@ -42275,16 +42275,18 @@ paragraphs
 parakeet/SM
 paralegal/MS
 paralinguistic
 parallax/MS
 parallel/SGMD
 paralleled/U
 parallelepiped
 parallelism/SM
+parallelization/SM
+parallelize/SGD
 parallelogram/SM
 paralyses
 paralysis/M
 paralytic/SM
 paralytically
 paralyze/DSG
 paralyzing/Y
 paramagnetic
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -388,48 +388,29 @@ static inline void LogRendertraceRect(co
     aGuid.mLayersId, aGuid.mPresShellId, aGuid.mScrollId,
     aDesc, delta.ToMilliseconds(), aColor,
     aRect.x, aRect.y, aRect.width, aRect.height);
 #endif
 }
 
 static TimeStamp sFrameTime;
 static bool sThreadAssertionsEnabled = true;
+static PRThread* sControllerThread;
 
 // Counter used to give each APZC a unique id
 static uint32_t sAsyncPanZoomControllerCount = 0;
 
 static TimeStamp
 GetFrameTime() {
   if (sFrameTime.IsNull()) {
     return TimeStamp::Now();
   }
   return sFrameTime;
 }
 
-static PRThread* sControllerThread;
-
-static void
-AssertOnControllerThread() {
-  if (!AsyncPanZoomController::GetThreadAssertionsEnabled()) {
-    return;
-  }
-
-  static bool sControllerThreadDetermined = false;
-  if (!sControllerThreadDetermined) {
-    // Technically this may not actually pick up the correct controller thread,
-    // if the first call to this method happens from a non-controller thread.
-    // If the assertion below fires, it is possible that it is because
-    // sControllerThread is not actually the controller thread.
-    sControllerThread = PR_GetCurrentThread();
-    sControllerThreadDetermined = true;
-  }
-  MOZ_ASSERT(sControllerThread == PR_GetCurrentThread());
-}
-
 class FlingAnimation: public AsyncPanZoomAnimation {
 public:
   FlingAnimation(AsyncPanZoomController& aApzc,
                  bool aApplyAcceleration,
                  bool aAllowOverscroll)
     : AsyncPanZoomAnimation(TimeDuration::FromMilliseconds(gfxPrefs::APZFlingRepaintInterval()))
     , mApzc(aApzc)
     , mAllowOverscroll(aAllowOverscroll)
@@ -683,16 +664,34 @@ AsyncPanZoomController::SetThreadAsserti
   sThreadAssertionsEnabled = aEnabled;
 }
 
 bool
 AsyncPanZoomController::GetThreadAssertionsEnabled() {
   return sThreadAssertionsEnabled;
 }
 
+void
+AsyncPanZoomController::AssertOnControllerThread() {
+  if (!GetThreadAssertionsEnabled()) {
+    return;
+  }
+
+  static bool sControllerThreadDetermined = false;
+  if (!sControllerThreadDetermined) {
+    // Technically this may not actually pick up the correct controller thread,
+    // if the first call to this method happens from a non-controller thread.
+    // If the assertion below fires, it is possible that it is because
+    // sControllerThread is not actually the controller thread.
+    sControllerThread = PR_GetCurrentThread();
+    sControllerThreadDetermined = true;
+  }
+  MOZ_ASSERT(sControllerThread == PR_GetCurrentThread());
+}
+
 /*static*/ void
 AsyncPanZoomController::InitializeGlobalState()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   static bool sInitialized = false;
   if (sInitialized)
     return;
@@ -1147,16 +1146,18 @@ nsEventStatus AsyncPanZoomController::On
   }
 
   return nsEventStatus_eConsumeNoDefault;
 }
 
 nsEventStatus AsyncPanZoomController::OnTouchCancel(const MultiTouchInput& aEvent) {
   APZC_LOG("%p got a touch-cancel in state %d\n", this, mState);
   OnTouchEndOrCancel();
+  mX.CancelTouch();
+  mY.CancelTouch();
   CancelAnimation();
   return nsEventStatus_eConsumeNoDefault;
 }
 
 nsEventStatus AsyncPanZoomController::OnScaleBegin(const PinchGestureInput& aEvent) {
   APZC_LOG("%p got a scale-begin in state %d\n", this, mState);
 
   // Note that there may not be a touch block at this point, if we received the
@@ -2354,19 +2355,17 @@ void AsyncPanZoomController::NotifyLayer
         && (aLayerMetrics.GetScrollGeneration() != mFrameMetrics.GetScrollGeneration());
 
   if (aIsFirstPaint || isDefault) {
     // Initialize our internal state to something sane when the content
     // that was just painted is something we knew nothing about previously
     mPaintThrottler.ClearHistory();
     mPaintThrottler.SetMaxDurations(gfxPrefs::APZNumPaintDurationSamples());
 
-    mX.CancelTouch();
-    mY.CancelTouch();
-    SetState(NOTHING);
+    CancelAnimation();
 
     mFrameMetrics = aLayerMetrics;
     mLastDispatchedPaintMetrics = aLayerMetrics;
     ShareCompositorFrameMetrics();
 
     if (mFrameMetrics.GetDisplayPortMargins() != LayerMargin()) {
       // A non-zero display port margin here indicates a displayport has
       // been set by a previous APZC for the content at this guid. The
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -998,33 +998,39 @@ private:
    * a CrossProcessMutex that may be shared with the content process
    * for use in progressive tiled update calculations.
    */
   void ShareCompositorFrameMetrics();
 
 
   /* ===================================================================
    * The functions and members in this section are used for testing
-   * purposes only.
+   * and assertion purposes only.
    */
 public:
   /**
    * Sync panning and zooming animation using a fixed frame time.
    * This will ensure that we animate the APZC correctly with other external
    * animations to the same timestamp.
    */
   static void SetFrameTime(const TimeStamp& aMilliseconds);
   /**
    * In the gtest environment everything runs on one thread, so we
    * shouldn't assert that we're on a particular thread. This enables
    * that behaviour.
    */
   static void SetThreadAssertionsEnabled(bool aEnabled);
   static bool GetThreadAssertionsEnabled();
   /**
+   * This can be used to assert that the current thread is the
+   * controller/UI thread (on which input events are received.
+   * This does nothing if thread assertions are disabled.
+   */
+  static void AssertOnControllerThread();
+  /**
    * Set an extra offset for testing async scrolling.
    */
   void SetTestAsyncScrollOffset(const CSSPoint& aPoint)
   {
     mTestAsyncScrollOffset = aPoint;
   }
 
 private:
--- a/gfx/layers/apz/src/Axis.cpp
+++ b/gfx/layers/apz/src/Axis.cpp
@@ -29,16 +29,19 @@ Axis::Axis(AsyncPanZoomController* aAsyn
     mVelocity(0.0f),
     mAxisLocked(false),
     mAsyncPanZoomController(aAsyncPanZoomController),
     mOverscroll(0)
 {
 }
 
 void Axis::UpdateWithTouchAtDevicePoint(int32_t aPos, uint32_t aTimestampMs) {
+  // mVelocityQueue is controller-thread only
+  AsyncPanZoomController::AssertOnControllerThread();
+
   if (aTimestampMs == mPosTimeMs) {
     // Duplicate event?
     return;
   }
 
   float newVelocity = mAxisLocked ? 0 : (float)(mPos - aPos) / (float)(aTimestampMs - mPosTimeMs);
   if (gfxPrefs::APZMaxVelocity() > 0.0f) {
     newVelocity = std::min(newVelocity, gfxPrefs::APZMaxVelocity() * APZCTreeManager::GetDPI());
@@ -189,32 +192,38 @@ float Axis::PanDistance() {
   return fabsf(mPos - mStartPos);
 }
 
 float Axis::PanDistance(float aPos) {
   return fabsf(aPos - mStartPos);
 }
 
 void Axis::EndTouch(uint32_t aTimestampMs) {
+  // mVelocityQueue is controller-thread only
+  AsyncPanZoomController::AssertOnControllerThread();
+
   mVelocity = 0;
   int count = 0;
   while (!mVelocityQueue.IsEmpty()) {
     uint32_t timeDelta = (aTimestampMs - mVelocityQueue[0].first);
     if (timeDelta < gfxPrefs::APZVelocityRelevanceTime()) {
       count++;
       mVelocity += mVelocityQueue[0].second;
     }
     mVelocityQueue.RemoveElementAt(0);
   }
   if (count > 1) {
     mVelocity /= count;
   }
 }
 
 void Axis::CancelTouch() {
+  // mVelocityQueue is controller-thread only
+  AsyncPanZoomController::AssertOnControllerThread();
+
   mVelocity = 0.0f;
   while (!mVelocityQueue.IsEmpty()) {
     mVelocityQueue.RemoveElementAt(0);
   }
 }
 
 bool Axis::CanScroll() const {
   return GetPageLength() - GetCompositionLength() > COORDINATE_EPSILON;
--- a/gfx/layers/apz/src/Axis.h
+++ b/gfx/layers/apz/src/Axis.h
@@ -228,17 +228,18 @@ protected:
   // If this amount is nonzero, the relevant component of
   // mAsyncPanZoomController->mFrameMetrics.mScrollOffset must be at its
   // extreme allowed value in the relevant direction (that is, it must be at
   // its maximum value if mOverscroll is positive, and at its minimum value
   // if mOverscroll is negative).
   float mOverscroll;
   // A queue of (timestamp, velocity) pairs; these are the historical
   // velocities at the given timestamps. Timestamps are in milliseconds,
-  // velocities are in screen pixels per ms.
+  // velocities are in screen pixels per ms. This member can only be
+  // accessed on the controller/UI thread.
   nsTArray<std::pair<uint32_t, float> > mVelocityQueue;
 
   const FrameMetrics& GetFrameMetrics() const;
 
   // Adjust a requested overscroll amount for resistance, yielding a smaller
   // actual overscroll amount.
   float ApplyResistance(float aOverscroll) const;
 };
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -82,16 +82,20 @@ void BasicCompositor::Destroy()
   mWidget = nullptr;
 }
 
 TemporaryRef<CompositingRenderTarget>
 BasicCompositor::CreateRenderTarget(const IntRect& aRect, SurfaceInitMode aInit)
 {
   RefPtr<DrawTarget> target = mDrawTarget->CreateSimilarDrawTarget(aRect.Size(), SurfaceFormat::B8G8R8A8);
 
+  if (!target) {
+    return nullptr;
+  }
+
   RefPtr<BasicCompositingRenderTarget> rt = new BasicCompositingRenderTarget(target, aRect);
 
   return rt.forget();
 }
 
 TemporaryRef<CompositingRenderTarget>
 BasicCompositor::CreateRenderTargetFromSource(const IntRect &aRect,
                                               const CompositingRenderTarget *aSource,
@@ -422,16 +426,22 @@ BasicCompositor::BeginFrame(const nsIntR
   }
   if (!mDrawTarget) {
     return;
   }
 
   // Setup an intermediate render target to buffer all compositing. We will
   // copy this into mDrawTarget (the widget), and/or mTarget in EndFrame()
   RefPtr<CompositingRenderTarget> target = CreateRenderTarget(mInvalidRect, INIT_MODE_CLEAR);
+  if (!target) {
+    if (!mTarget) {
+      mWidget->EndRemoteDrawing();
+    }
+    return;
+  }
   SetRenderTarget(target);
 
   // We only allocate a surface sized to the invalidated region, so we need to
   // translate future coordinates.
   Matrix transform;
   transform.Translate(-invalidRect.x, -invalidRect.y);
   mRenderTarget->mDrawTarget->SetTransform(transform);
 
--- a/gfx/src/FilterSupport.cpp
+++ b/gfx/src/FilterSupport.cpp
@@ -961,16 +961,21 @@ FilterNodeFromPrimitiveDescription(const
 
       RefPtr<FilterNode> transform = aDT->CreateFilter(FilterType::TRANSFORM);
       transform->SetInput(IN_TRANSFORM_IN, inputImage);
       transform->SetAttribute(ATT_TRANSFORM_MATRIX, TM);
       transform->SetAttribute(ATT_TRANSFORM_FILTER, atts.GetUint(eImageFilter));
       return transform;
     }
 
+    case PrimitiveType::ToAlpha:
+    {
+      return FilterWrappers::ToAlpha(aDT, aSources[0]);
+    }
+
     default:
       return nullptr;
   }
 }
 
 template<typename T>
 static const T&
 ElementForIndex(int32_t aIndex,
@@ -996,16 +1001,17 @@ ElementForIndex(int32_t aIndex,
 static AlphaModel
 InputAlphaModelForPrimitive(const FilterPrimitiveDescription& aDescr,
                             int32_t aInputIndex,
                             AlphaModel aOriginalAlphaModel)
 {
   switch (aDescr.Type()) {
     case PrimitiveType::Tile:
     case PrimitiveType::Offset:
+    case PrimitiveType::ToAlpha:
       return aOriginalAlphaModel;
 
     case PrimitiveType::ColorMatrix:
     case PrimitiveType::ComponentTransfer:
       return AlphaModel::Unpremultiplied;
 
     case PrimitiveType::DisplacementMap:
       return aInputIndex == 0 ?
@@ -1191,16 +1197,17 @@ ResultChangeRegionForPrimitive(const Fil
 
     case PrimitiveType::Blend:
     case PrimitiveType::Composite:
     case PrimitiveType::Merge:
       return UnionOfRegions(aInputChangeRegions);
 
     case PrimitiveType::ColorMatrix:
     case PrimitiveType::ComponentTransfer:
+    case PrimitiveType::ToAlpha:
       return aInputChangeRegions[0];
 
     case PrimitiveType::Morphology:
     {
       Size radii = atts.GetSize(eMorphologyRadii);
       int32_t rx = clamped(int32_t(ceil(radii.width)), 0, kMorphologyMaxRadius);
       int32_t ry = clamped(int32_t(ceil(radii.height)), 0, kMorphologyMaxRadius);
       return aInputChangeRegions[0].Inflated(nsIntMargin(ry, rx, ry, rx));
@@ -1420,16 +1427,17 @@ SourceNeededRegionForPrimitive(const Fil
     case PrimitiveType::Empty:
       return nsIntRegion();
 
     case PrimitiveType::Blend:
     case PrimitiveType::Composite:
     case PrimitiveType::Merge:
     case PrimitiveType::ColorMatrix:
     case PrimitiveType::ComponentTransfer:
+    case PrimitiveType::ToAlpha:
       return aResultNeededRegion;
 
     case PrimitiveType::Morphology:
     {
       Size radii = atts.GetSize(eMorphologyRadii);
       int32_t rx = clamped(int32_t(ceil(radii.width)), 0, kMorphologyMaxRadius);
       int32_t ry = clamped(int32_t(ceil(radii.height)), 0, kMorphologyMaxRadius);
       return aResultNeededRegion.Inflated(nsIntMargin(ry, rx, ry, rx));
--- a/gfx/src/FilterSupport.h
+++ b/gfx/src/FilterSupport.h
@@ -265,16 +265,17 @@ MOZ_BEGIN_ENUM_CLASS(PrimitiveType)
   Turbulence,
   Composite,
   Merge,
   Image,
   GaussianBlur,
   DropShadow,
   DiffuseLighting,
   SpecularLighting,
+  ToAlpha,
   Max
 MOZ_END_ENUM_CLASS(PrimitiveType)
 
 /**
  * A data structure to carry attributes for a given primitive that's part of a
  * filter. Will be serializable via IPDL, so it must not contain complex
  * functionality.
  * Used as part of a FilterDescription.
--- a/gfx/tests/mochitest.ini
+++ b/gfx/tests/mochitest.ini
@@ -1,6 +1,6 @@
 [DEFAULT]
-skip-if = buildapp == 'b2g'
+skip-if = buildapp == 'mulet' || buildapp == 'b2g'
 [mochitest/test_bug509244.html]
 [mochitest/test_bug513439.html]
 skip-if = e10s
 [mochitest/test_acceleration.html]
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -242,29 +242,29 @@ GC(JSContext *cx, unsigned argc, jsval *
                 return false;
         } else if (arg.isObject()) {
             PrepareZoneForGC(UncheckedUnwrap(&arg.toObject())->zone());
             compartment = true;
         }
     }
 
 #ifndef JS_MORE_DETERMINISTIC
-    size_t preBytes = cx->runtime()->gc.bytesAllocated();
+    size_t preBytes = cx->runtime()->gc.usage.gcBytes();
 #endif
 
     if (compartment)
         PrepareForDebugGC(cx->runtime());
     else
         PrepareForFullGC(cx->runtime());
     GCForReason(cx->runtime(), gcreason::API);
 
     char buf[256] = { '\0' };
 #ifndef JS_MORE_DETERMINISTIC
     JS_snprintf(buf, sizeof(buf), "before %lu, after %lu\n",
-                (unsigned long)preBytes, (unsigned long)cx->runtime()->gc.bytesAllocated());
+                (unsigned long)preBytes, (unsigned long)cx->runtime()->gc.usage.gcBytes());
 #endif
     JSString *str = JS_NewStringCopyZ(cx, buf);
     if (!str)
         return false;
     args.rval().setString(str);
     return true;
 }
 
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -181,17 +181,16 @@ class GCRuntime
     void verifyPostBarriers();
     void maybeVerifyPreBarriers(bool always);
     void maybeVerifyPostBarriers(bool always);
     bool selectForMarking(JSObject *object);
     void clearSelectedForMarking();
     void setDeterministic(bool enable);
 #endif
 
-    size_t bytesAllocated() { return bytes; }
     size_t maxBytesAllocated() { return maxBytes; }
     size_t maxMallocBytesAllocated() { return maxBytes; }
 
   public:
     // Internal public interface
     js::gc::State state() { return incrementalState; }
     void recordNativeStackTop();
 #ifdef JS_THREADSAFE
@@ -325,17 +324,16 @@ class GCRuntime
     JSGCMode gcMode() const { return mode; }
     void setGCMode(JSGCMode m) {
         mode = m;
         marker.setGCMode(mode);
     }
 
     inline void updateOnFreeArenaAlloc(const ChunkInfo &info);
     inline void updateOnArenaFree(const ChunkInfo &info);
-    inline void updateBytesAllocated(ptrdiff_t size);
 
     GCChunkSet::Range allChunks() { return chunkSet.all(); }
     inline Chunk **getAvailableChunkList(Zone *zone);
     void moveChunkToFreePool(Chunk *chunk);
     bool hasChunk(Chunk *chunk) { return chunkSet.has(chunk); }
 
 #ifdef JS_GC_ZEAL
     void startVerifyPreBarriers();
@@ -424,16 +422,19 @@ class GCRuntime
     js::Nursery           nursery;
     js::gc::StoreBuffer   storeBuffer;
 #endif
 
     js::gcstats::Statistics stats;
 
     js::GCMarker          marker;
 
+    /* Track heap usage for this runtime. */
+    HeapUsage usage;
+
   private:
     /*
      * Set of all GC chunks with at least one allocated thing. The
      * conservative GC uses it to quickly check if a possible GC thing points
      * into an allocated chunk.
      */
     js::GCChunkSet        chunkSet;
 
@@ -445,19 +446,16 @@ class GCRuntime
      * removed from the list and scheduled for release.
      */
     js::gc::Chunk         *systemAvailableChunkListHead;
     js::gc::Chunk         *userAvailableChunkListHead;
     js::gc::ChunkPool     chunkPool;
 
     js::RootedValueMap    rootsHash;
 
-    /* This is updated by both the main and GC helper threads. */
-    mozilla::Atomic<size_t, mozilla::ReleaseAcquire>   bytes;
-
     size_t                maxBytes;
     size_t                maxMallocBytes;
 
     /*
      * Number of the committed arenas in all GC chunks including empty chunks.
      */
     mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire>   numArenasFreeCommitted;
     void                  *verifyPreData;
--- a/js/src/gc/Heap.h
+++ b/js/src/gc/Heap.h
@@ -2,16 +2,17 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 gc_Heap_h
 #define gc_Heap_h
 
+#include "mozilla/Atomics.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/PodOperations.h"
 
 #include <stddef.h>
 #include <stdint.h>
 
 #include "jspubtd.h"
 #include "jstypes.h"
@@ -887,16 +888,64 @@ static_assert(js::gc::ChunkRuntimeOffset
                                             offsetof(ChunkInfo, trailer) +
                                             offsetof(ChunkTrailer, runtime),
               "The hardcoded API runtime offset must match the actual offset.");
 static_assert(js::gc::ChunkLocationOffset == offsetof(Chunk, info) +
                                              offsetof(ChunkInfo, trailer) +
                                              offsetof(ChunkTrailer, location),
               "The hardcoded API location offset must match the actual offset.");
 
+/*
+ * Tracks the used sizes for owned heap data and automatically maintains the
+ * memory usage relationship between GCRuntime and Zones.
+ */
+class HeapUsage
+{
+    /*
+     * A heap usage that contains our parent's heap usage, or null if this is
+     * the top-level usage container.
+     */
+    HeapUsage *parent_;
+
+    /*
+     * The approximate number of bytes in use on the GC heap, to the nearest
+     * ArenaSize. This does not include any malloc data. It also does not
+     * include not-actively-used addresses that are still reserved at the OS
+     * level for GC usage. It is atomic because it is updated by both the main
+     * and GC helper threads.
+     */
+    mozilla::Atomic<size_t, mozilla::ReleaseAcquire> gcBytes_;
+
+  public:
+    HeapUsage(HeapUsage *parent)
+      : parent_(parent),
+        gcBytes_(0)
+    {}
+
+    size_t gcBytes() const { return gcBytes_; }
+
+    void addGCArena() {
+        gcBytes_ += ArenaSize;
+        if (parent_)
+            parent_->addGCArena();
+    }
+    void removeGCArena() {
+        MOZ_ASSERT(gcBytes_ >= ArenaSize);
+        gcBytes_ -= ArenaSize;
+        if (parent_)
+            parent_->removeGCArena();
+    }
+
+    /* Pair to adoptArenas. Adopts the attendant usage statistics. */
+    void adopt(HeapUsage &other) {
+        gcBytes_ += other.gcBytes_;
+        other.gcBytes_ = 0;
+    }
+};
+
 inline uintptr_t
 ArenaHeader::address() const
 {
     uintptr_t addr = reinterpret_cast<uintptr_t>(this);
     JS_ASSERT(!(addr & ArenaMask));
     JS_ASSERT(Chunk::withinArenasRange(addr));
     return addr;
 }
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -890,17 +890,17 @@ js::Nursery::collect(JSRuntime *rt, JS::
 
     TIME_START(clearStoreBuffer);
     rt->gc.storeBuffer.clear();
     TIME_END(clearStoreBuffer);
 
     // We ignore gcMaxBytes when allocating for minor collection. However, if we
     // overflowed, we disable the nursery. The next time we allocate, we'll fail
     // because gcBytes >= gcMaxBytes.
-    if (rt->gc.bytesAllocated() >= rt->gc.maxBytesAllocated())
+    if (rt->gc.usage.gcBytes() >= rt->gc.maxBytesAllocated())
         disable();
 
     TIME_END(total);
 
     TraceMinorGCEnd();
 
 #ifdef PROFILE_NURSERY
     int64_t totalTime = TIME_TOTAL(total);
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -523,17 +523,17 @@ Statistics::beginGC()
 {
     PodArrayZero(phaseStartTimes);
     PodArrayZero(phaseTimes);
 
     slices.clearAndFree();
     sccTimes.clearAndFree();
     nonincrementalReason = nullptr;
 
-    preBytes = runtime->gc.bytesAllocated();
+    preBytes = runtime->gc.usage.gcBytes();
 }
 
 void
 Statistics::endGC()
 {
     crash::SnapshotGCStack();
 
     for (int i = 0; i < PHASE_LIMIT; i++)
--- a/js/src/gc/Zone.cpp
+++ b/js/src/gc/Zone.cpp
@@ -25,17 +25,17 @@ JS::Zone::Zone(JSRuntime *rt)
   : JS::shadow::Zone(rt, &rt->gc.marker),
     allocator(this),
     types(this),
     compartments(),
     gcGrayRoots(),
     gcHeapGrowthFactor(3.0),
     gcMallocBytes(0),
     gcMallocGCTriggered(false),
-    gcBytes(0),
+    usage(&rt->gc.usage),
     gcTriggerBytes(0),
     data(nullptr),
     isSystem(false),
     usedByExclusiveThread(false),
     scheduledForDestruction(false),
     maybeAlive(true),
     active(false),
     jitZone_(nullptr),
--- a/js/src/gc/Zone.h
+++ b/js/src/gc/Zone.h
@@ -239,19 +239,18 @@ struct Zone : public JS::shadow::Zone,
 
     // Whether a GC has been triggered as a result of gcMallocBytes falling
     // below zero.
     //
     // This should be a bool, but Atomic only supports 32-bit and pointer-sized
     // types.
     mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> gcMallocGCTriggered;
 
-    // Counts the number of bytes allocated in the GC heap for this zone. It is
-    // updated by both the main and GC helper threads.
-    mozilla::Atomic<size_t, mozilla::ReleaseAcquire> gcBytes;
+    // Track heap usage under this Zone.
+    js::gc::HeapUsage usage;
 
     // GC trigger threshold for allocations on the GC heap.
     size_t gcTriggerBytes;
 
     // Per-zone data for use by an embedder.
     void *data;
 
     bool isSystem;
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug1035287-track-allocation-sites-recursion.js
@@ -0,0 +1,7 @@
+// |jit-test| exitstatus: 3
+
+enableTrackAllocations();
+function f() {
+    eval('f();');
+}
+f();
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -918,30 +918,23 @@ Chunk::fetchNextFreeArena(JSRuntime *rt)
     info.freeArenasHead = aheader->next;
     --info.numArenasFreeCommitted;
     --info.numArenasFree;
     rt->gc.updateOnFreeArenaAlloc(info);
 
     return aheader;
 }
 
-inline void
-GCRuntime::updateBytesAllocated(ptrdiff_t size)
-{
-    JS_ASSERT_IF(size < 0, bytes >= size_t(-size));
-    bytes += size;
-}
-
 ArenaHeader *
 Chunk::allocateArena(Zone *zone, AllocKind thingKind)
 {
     JS_ASSERT(hasAvailableArenas());
 
     JSRuntime *rt = zone->runtimeFromAnyThread();
-    if (!rt->isHeapMinorCollecting() && rt->gc.bytesAllocated() >= rt->gc.maxBytesAllocated()) {
+    if (!rt->isHeapMinorCollecting() && rt->gc.usage.gcBytes() >= rt->gc.maxBytesAllocated()) {
 #ifdef JSGC_FJGENERATIONAL
         // This is an approximation to the best test, which would check that
         // this thread is currently promoting into the tenured area.  I doubt
         // the better test would make much difference.
         if (!rt->isFJMinorCollecting())
             return nullptr;
 #else
         return nullptr;
@@ -950,20 +943,19 @@ Chunk::allocateArena(Zone *zone, AllocKi
 
     ArenaHeader *aheader = MOZ_LIKELY(info.numArenasFreeCommitted > 0)
                            ? fetchNextFreeArena(rt)
                            : fetchNextDecommittedArena();
     aheader->init(zone, thingKind);
     if (MOZ_UNLIKELY(!hasAvailableArenas()))
         removeFromAvailableList();
 
-    rt->gc.updateBytesAllocated(ArenaSize);
-    zone->gcBytes += ArenaSize;
-
-    if (zone->gcBytes >= zone->gcTriggerBytes) {
+    zone->usage.addGCArena();
+
+    if (zone->usage.gcBytes() >= zone->gcTriggerBytes) {
         AutoUnlockGC unlock(rt);
         TriggerZoneGC(zone, JS::gcreason::ALLOC_TRIGGER);
     }
 
     return aheader;
 }
 
 inline void
@@ -997,22 +989,19 @@ Chunk::releaseArena(ArenaHeader *aheader
     JS_ASSERT(aheader->allocated());
     JS_ASSERT(!aheader->hasDelayedMarking);
     Zone *zone = aheader->zone;
     JSRuntime *rt = zone->runtimeFromAnyThread();
     AutoLockGC maybeLock;
     if (rt->gc.isBackgroundSweeping())
         maybeLock.lock(rt);
 
-    JS_ASSERT(rt->gc.bytesAllocated() >= ArenaSize);
-    JS_ASSERT(zone->gcBytes >= ArenaSize);
     if (rt->gc.isBackgroundSweeping())
         zone->reduceGCTriggerBytes(zone->gcHeapGrowthFactor * ArenaSize);
-    rt->gc.updateBytesAllocated(-ArenaSize);
-    zone->gcBytes -= ArenaSize;
+    zone->usage.removeGCArena();
 
     aheader->setAsNotAllocated();
     addArenaToFreeList(rt, aheader);
 
     if (info.numArenasFree == 1) {
         JS_ASSERT(!info.prevp);
         JS_ASSERT(!info.next);
         addToAvailableList(zone);
@@ -1121,19 +1110,19 @@ GCRuntime::GCRuntime(JSRuntime *rt) :
     rt(rt),
     systemZone(nullptr),
 #ifdef JSGC_GENERATIONAL
     nursery(rt),
     storeBuffer(rt, nursery),
 #endif
     stats(rt),
     marker(rt),
+    usage(nullptr),
     systemAvailableChunkListHead(nullptr),
     userAvailableChunkListHead(nullptr),
-    bytes(0),
     maxBytes(0),
     maxMallocBytes(0),
     numArenasFreeCommitted(0),
     verifyPreData(nullptr),
     verifyPostData(nullptr),
     chunkAllocationSinceLastGC(false),
     nextFullGCTime(0),
     lastGCTime(0),
@@ -1419,17 +1408,17 @@ js::gc::FinishPersistentRootedChains(JSR
     rt->valuePersistentRooteds.clear();
 }
 
 void
 GCRuntime::setParameter(JSGCParamKey key, uint32_t value)
 {
     switch (key) {
       case JSGC_MAX_BYTES: {
-        JS_ASSERT(value >= bytes);
+        JS_ASSERT(value >= usage.gcBytes());
         maxBytes = value;
         break;
       }
       case JSGC_MAX_MALLOC_BYTES:
         setMaxMallocBytes(value);
         break;
       case JSGC_SLICE_TIME_BUDGET:
         sliceBudget = SliceBudget::TimeBudget(value);
@@ -1494,17 +1483,17 @@ uint32_t
 GCRuntime::getParameter(JSGCParamKey key)
 {
     switch (key) {
       case JSGC_MAX_BYTES:
         return uint32_t(maxBytes);
       case JSGC_MAX_MALLOC_BYTES:
         return maxMallocBytes;
       case JSGC_BYTES:
-        return uint32_t(bytes);
+        return uint32_t(usage.gcBytes());
       case JSGC_MODE:
         return uint32_t(mode);
       case JSGC_UNUSED_CHUNKS:
         return uint32_t(chunkPool.getEmptyCount());
       case JSGC_TOTAL_CHUNKS:
         return uint32_t(chunkSet.count() + chunkPool.getEmptyCount());
       case JSGC_SLICE_TIME_BUDGET:
         return uint32_t(sliceBudget > 0 ? sliceBudget / PRMJ_USEC_PER_MSEC : 0);
@@ -2204,17 +2193,17 @@ ArenaLists::refillFreeList(ThreadSafeCon
 {
     JS_ASSERT(cx->allocator()->arenas.freeLists[thingKind].isEmpty());
     JS_ASSERT_IF(cx->isJSContext(), !cx->asJSContext()->runtime()->isHeapBusy());
 
     Zone *zone = cx->allocator()->zone_;
 
     bool runGC = cx->allowGC() && allowGC &&
                  cx->asJSContext()->runtime()->gc.incrementalState != NO_INCREMENTAL &&
-                 zone->gcBytes > zone->gcTriggerBytes;
+                 zone->usage.gcBytes() > zone->gcTriggerBytes;
 
 #ifdef JS_THREADSAFE
     JS_ASSERT_IF(cx->isJSContext() && allowGC,
                  !cx->asJSContext()->runtime()->currentThreadHasExclusiveAccess());
 #endif
 
     for (;;) {
         if (MOZ_UNLIKELY(runGC)) {
@@ -2458,18 +2447,18 @@ GCRuntime::maybeGC(Zone *zone)
 #endif
 
     if (isNeeded) {
         GCSlice(rt, GC_NORMAL, JS::gcreason::MAYBEGC);
         return;
     }
 
     double factor = highFrequencyGC ? 0.85 : 0.9;
-    if (zone->gcBytes > 1024 * 1024 &&
-        zone->gcBytes >= factor * zone->gcTriggerBytes &&
+    if (zone->usage.gcBytes() > 1024 * 1024 &&
+        zone->usage.gcBytes() >= factor * zone->gcTriggerBytes &&
         incrementalState == NO_INCREMENTAL &&
         !isBackgroundSweeping())
     {
         PrepareZoneForGC(zone);
         GCSlice(rt, GC_NORMAL, JS::gcreason::MAYBEGC);
         return;
     }
 
@@ -4572,17 +4561,17 @@ GCRuntime::endSweepPhase(JSGCInvocationK
             sweepZones(&fop, lastGC);
     }
 
     uint64_t currentTime = PRMJ_Now();
     highFrequencyGC = dynamicHeapGrowth && lastGCTime &&
         lastGCTime + highFrequencyTimeThreshold * PRMJ_USEC_PER_MSEC > currentTime;
 
     for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
-        zone->setGCLastBytes(zone->gcBytes, gckind);
+        zone->setGCLastBytes(zone->usage.gcBytes(), gckind);
         if (zone->isCollecting()) {
             JS_ASSERT(zone->isGCFinished());
             zone->setGCState(Zone::NoGC);
         }
 
 #ifdef DEBUG
         JS_ASSERT(!zone->isCollecting());
         JS_ASSERT(!zone->wasGCStarted());
@@ -4996,17 +4985,17 @@ GCRuntime::budgetIncrementalGC(int64_t *
 
     if (isTooMuchMalloc()) {
         *budget = SliceBudget::Unlimited;
         stats.nonincremental("malloc bytes trigger");
     }
 
     bool reset = false;
     for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
-        if (zone->gcBytes >= zone->gcTriggerBytes) {
+        if (zone->usage.gcBytes() >= zone->gcTriggerBytes) {
             *budget = SliceBudget::Unlimited;
             stats.nonincremental("allocation trigger");
         }
 
         if (incrementalState != NO_INCREMENTAL &&
             zone->isGCScheduled() != zone->wasGCStarted())
         {
             reset = true;
@@ -5583,18 +5572,17 @@ gc::MergeCompartments(JSCompartment *sou
     }
 
     // The source should be the only compartment in its zone.
     for (CompartmentsInZoneIter c(source->zone()); !c.done(); c.next())
         JS_ASSERT(c.get() == source);
 
     // Merge the allocator in source's zone into target's zone.
     target->zone()->allocator.arenas.adoptArenas(rt, &source->zone()->allocator.arenas);
-    target->zone()->gcBytes += source->zone()->gcBytes;
-    source->zone()->gcBytes = 0;
+    target->zone()->usage.adopt(source->zone()->usage);
 
     // Merge other info in source's zone into target's zone.
     target->zone()->types.typeLifoAlloc.transferFrom(&source->zone()->types.typeLifoAlloc);
 }
 
 void
 gc::RunDebugGC(JSContext *cx)
 {
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -8,72 +8,84 @@
 #include "vm/SavedStacks.h"
 
 #include "jsapi.h"
 #include "jscompartment.h"
 #include "jsfriendapi.h"
 #include "jsnum.h"
 
 #include "gc/Marking.h"
+#include "js/Vector.h"
 #include "vm/GlobalObject.h"
 #include "vm/StringBuffer.h"
 
 #include "jscntxtinlines.h"
 #include "jsobjinlines.h"
 
 using mozilla::AddToHash;
 using mozilla::HashString;
 
 namespace js {
 
 struct SavedFrame::Lookup {
-    Lookup(JSAtom *source, size_t line, size_t column, JSAtom *functionDisplayName,
+    Lookup(JSAtom *source, uint32_t line, uint32_t column, JSAtom *functionDisplayName,
            SavedFrame *parent, JSPrincipals *principals)
-        : source(source),
-          line(line),
-          column(column),
-          functionDisplayName(functionDisplayName),
-          parent(parent),
-          principals(principals)
+      : source(source),
+        line(line),
+        column(column),
+        functionDisplayName(functionDisplayName),
+        parent(parent),
+        principals(principals)
     {
         JS_ASSERT(source);
     }
 
     JSAtom       *source;
-    size_t       line;
-    size_t       column;
+    uint32_t     line;
+    uint32_t     column;
     JSAtom       *functionDisplayName;
     SavedFrame   *parent;
     JSPrincipals *principals;
 };
 
 class SavedFrame::AutoLookupRooter : public JS::CustomAutoRooter
 {
   public:
-    AutoLookupRooter(JSContext *cx, JSAtom *source, size_t line, size_t column,
+    AutoLookupRooter(JSContext *cx, JSAtom *source, uint32_t line, uint32_t column,
                      JSAtom *functionDisplayName, SavedFrame *parent, JSPrincipals *principals)
       : JS::CustomAutoRooter(cx),
         value(source, line, column, functionDisplayName, parent, principals) {}
 
     operator const SavedFrame::Lookup&() const { return value; }
+    SavedFrame::Lookup &get() { return value; }
 
   private:
     virtual void trace(JSTracer *trc) {
         gc::MarkStringUnbarriered(trc, &value.source, "SavedFrame::Lookup::source");
         if (value.functionDisplayName) {
             gc::MarkStringUnbarriered(trc, &value.functionDisplayName,
                                       "SavedFrame::Lookup::functionDisplayName");
         }
         if (value.parent)
             gc::MarkObjectUnbarriered(trc, &value.parent, "SavedFrame::Lookup::parent");
     }
 
     SavedFrame::Lookup value;
 };
 
+class SavedFrame::HandleLookup
+{
+  public:
+    HandleLookup(SavedFrame::AutoLookupRooter &lookup) : ref(lookup) { }
+    SavedFrame::Lookup *operator->() { return &ref.get(); }
+    operator const SavedFrame::Lookup&() const { return ref; }
+  private:
+    SavedFrame::AutoLookupRooter &ref;
+};
+
 /* static */ HashNumber
 SavedFrame::HashPolicy::hash(const Lookup &lookup)
 {
     JS::AutoCheckCannotGC nogc;
     // Assume that we can take line mod 2^32 without losing anything of
     // interest.  If that assumption changes, we'll just need to start with 0
     // and add another overload of AddToHash with more arguments.
     return AddToHash(lookup.line,
@@ -145,24 +157,24 @@ SavedFrame::finalize(FreeOp *fop, JSObje
 JSAtom *
 SavedFrame::getSource()
 {
     const Value &v = getReservedSlot(JSSLOT_SOURCE);
     JSString *s = v.toString();
     return &s->asAtom();
 }
 
-size_t
+uint32_t
 SavedFrame::getLine()
 {
     const Value &v = getReservedSlot(JSSLOT_LINE);
     return v.toInt32();
 }
 
-size_t
+uint32_t
 SavedFrame::getColumn()
 {
     const Value &v = getReservedSlot(JSSLOT_COLUMN);
     return v.toInt32();
 }
 
 JSAtom *
 SavedFrame::getFunctionDisplayName()
@@ -186,35 +198,35 @@ SavedFrame::getPrincipals()
 {
     const Value &v = getReservedSlot(JSSLOT_PRINCIPALS);
     if (v.isUndefined())
         return nullptr;
     return static_cast<JSPrincipals *>(v.toPrivate());
 }
 
 void
-SavedFrame::initFromLookup(const Lookup &lookup)
+SavedFrame::initFromLookup(SavedFrame::HandleLookup lookup)
 {
-    JS_ASSERT(lookup.source);
+    JS_ASSERT(lookup->source);
     JS_ASSERT(getReservedSlot(JSSLOT_SOURCE).isUndefined());
-    setReservedSlot(JSSLOT_SOURCE, StringValue(lookup.source));
+    setReservedSlot(JSSLOT_SOURCE, StringValue(lookup->source));
 
-    setReservedSlot(JSSLOT_LINE, NumberValue(lookup.line));
-    setReservedSlot(JSSLOT_COLUMN, NumberValue(lookup.column));
+    setReservedSlot(JSSLOT_LINE, NumberValue(lookup->line));
+    setReservedSlot(JSSLOT_COLUMN, NumberValue(lookup->column));
     setReservedSlot(JSSLOT_FUNCTIONDISPLAYNAME,
-                    lookup.functionDisplayName
-                        ? StringValue(lookup.functionDisplayName)
+                    lookup->functionDisplayName
+                        ? StringValue(lookup->functionDisplayName)
                         : NullValue());
-    setReservedSlot(JSSLOT_PARENT, ObjectOrNullValue(lookup.parent));
-    setReservedSlot(JSSLOT_PRIVATE_PARENT, PrivateValue(lookup.parent));
+    setReservedSlot(JSSLOT_PARENT, ObjectOrNullValue(lookup->parent));
+    setReservedSlot(JSSLOT_PRIVATE_PARENT, PrivateValue(lookup->parent));
 
     JS_ASSERT(getReservedSlot(JSSLOT_PRINCIPALS).isUndefined());
-    if (lookup.principals)
-        JS_HoldPrincipals(lookup.principals);
-    setReservedSlot(JSSLOT_PRINCIPALS, PrivateValue(lookup.principals));
+    if (lookup->principals)
+        JS_HoldPrincipals(lookup->principals);
+    setReservedSlot(JSSLOT_PRINCIPALS, PrivateValue(lookup->principals));
 }
 
 bool
 SavedFrame::parentMoved()
 {
     const Value &v = getReservedSlot(JSSLOT_PRIVATE_PARENT);
     JSObject *p = static_cast<JSObject *>(v.toPrivate());
     return p == getParent();
@@ -475,88 +487,84 @@ SavedStacks::sizeOfExcludingThis(mozilla
 {
     return frames.sizeOfExcludingThis(mallocSizeOf);
 }
 
 bool
 SavedStacks::insertFrames(JSContext *cx, FrameIter &iter, MutableHandleSavedFrame frame,
                           unsigned maxFrameCount)
 {
-    if (iter.done()) {
-        frame.set(nullptr);
-        return true;
-    }
-
-    // Don't report the over-recursion error because if we are blowing the stack
-    // here, we already blew the stack in JS, reported it, and we are creating
-    // the saved stack for the over-recursion error object. We do this check
-    // here, rather than inside saveCurrentStack, because in some cases we will
-    // pass the check there, despite later failing the check here (for example,
-    // in js/src/jit-test/tests/saved-stacks/bug-1006876-too-much-recursion.js).
-    JS_CHECK_RECURSION_DONT_REPORT(cx, return false);
+    // In order to lookup a cached SavedFrame object, we need to have its parent
+    // SavedFrame, which means we need to walk the stack from oldest frame to
+    // youngest. However, FrameIter walks the stack from youngest frame to
+    // oldest. The solution is to append stack frames to a vector as we walk the
+    // stack with FrameIter, and then do a second pass through that vector in
+    // reverse order after the traversal has completed and get or create the
+    // SavedFrame objects at that time.
+    //
+    // To avoid making many copies of FrameIter (whose copy constructor is
+    // relatively slow), we save the subset of FrameIter's data that is relevant
+    // to our needs in a FrameState object, and maintain a vector of FrameState
+    // objects instead of a vector of FrameIter objects.
 
-    JSPrincipals* principals = iter.compartment()->principals;
-    RootedAtom name(cx, iter.isNonEvalFunctionFrame() ? iter.functionDisplayAtom() : nullptr);
+    // Accumulate the vector of FrameState objects in |stackState|.
+    AutoFrameStateVector stackState(cx);
+    while (!iter.done()) {
+        AutoLocationValueRooter location(cx);
 
-    // When we have a |JSScript| for this frame, use |getLocation| to get a
-    // potentially memoized location result and copy it into |location|. When we
-    // do not have a |JSScript| for this frame (asm.js frames), we take a slow
-    // path that doesn't employ memoization, and update |location|'s slots
-    // directly.
-    AutoLocationValueRooter location(cx);
-    if (iter.hasScript()) {
-        JSScript *script = iter.script();
-        jsbytecode *pc = iter.pc();
         {
             AutoCompartment ac(cx, iter.compartment());
-            if (!cx->compartment()->savedStacks().getLocation(cx, script, pc, &location))
+            if (!cx->compartment()->savedStacks().getLocation(cx, iter, &location))
+                return false;
+        }
+
+        {
+            FrameState frameState(iter);
+            frameState.location = location.get();
+            if (!stackState->append(frameState))
                 return false;
         }
-    } else {
-        const char *filename = iter.scriptFilename();
-        if (!filename)
-            filename = "";
-        location.get().source = Atomize(cx, filename, strlen(filename));
-        if (!location.get().source)
-            return false;
-        uint32_t column;
-        location.get().line = iter.computeLine(&column);
-        location.get().column = column;
+
+        ++iter;
+
+        if (maxFrameCount == 0) {
+            // If maxFrameCount is zero, then there's no limit on the number of
+            // frames.
+            continue;
+        } else if (maxFrameCount == 1) {
+            // Since we were only asked to save one frame, do not continue
+            // walking the stack and saving frame state.
+            break;
+        } else {
+            maxFrameCount--;
+        }
     }
 
-    RootedSavedFrame parentFrame(cx);
-
-    // If maxFrameCount is zero, then there's no limit on the number of frames.
-    if (maxFrameCount == 0) {
-        if (!insertFrames(cx, ++iter, &parentFrame, 0))
-            return false;
-    } else if (maxFrameCount == 1) {
-        // Since we were only asked to save one frame, the SavedFrame we're
-        // building here should have no parent, even if there are older frames
-        // on the stack.
-        parentFrame = nullptr;
-    } else {
-        if (!insertFrames(cx, ++iter, &parentFrame, maxFrameCount - 1))
+    // Iterate through |stackState| in reverse order and get or create the
+    // actual SavedFrame instances.
+    RootedSavedFrame parentFrame(cx, nullptr);
+    for (size_t i = stackState->length(); i != 0; i--) {
+        SavedFrame::AutoLookupRooter lookup(cx,
+                                            stackState[i-1].location.source,
+                                            stackState[i-1].location.line,
+                                            stackState[i-1].location.column,
+                                            stackState[i-1].name,
+                                            parentFrame,
+                                            stackState[i-1].principals);
+        parentFrame.set(getOrCreateSavedFrame(cx, lookup));
+        if (!parentFrame)
             return false;
     }
 
-    SavedFrame::AutoLookupRooter lookup(cx,
-                                        location.get().source,
-                                        location.get().line,
-                                        location.get().column,
-                                        name,
-                                        parentFrame,
-                                        principals);
-
-    frame.set(getOrCreateSavedFrame(cx, lookup));
-    return frame.get() != nullptr;
+    frame.set(parentFrame);
+    return true;
 }
 
 SavedFrame *
-SavedStacks::getOrCreateSavedFrame(JSContext *cx, const SavedFrame::Lookup &lookup)
+SavedStacks::getOrCreateSavedFrame(JSContext *cx, SavedFrame::HandleLookup lookup)
 {
     SavedFrame::Set::AddPtr p = frames.lookupForAdd(lookup);
     if (p)
         return *p;
 
     RootedSavedFrame frame(cx, createFrameFromLookup(cx, lookup));
     if (!frame)
         return nullptr;
@@ -589,17 +597,17 @@ SavedStacks::getOrCreateSavedFrameProtot
     savedFrameProto = proto;
     // The only object with the SavedFrame::class_ that doesn't have a source
     // should be the prototype.
     savedFrameProto->setReservedSlot(SavedFrame::JSSLOT_SOURCE, NullValue());
     return savedFrameProto;
 }
 
 SavedFrame *
-SavedStacks::createFrameFromLookup(JSContext *cx, const SavedFrame::Lookup &lookup)
+SavedStacks::createFrameFromLookup(JSContext *cx, SavedFrame::HandleLookup lookup)
 {
     RootedObject proto(cx, getOrCreateSavedFramePrototype(cx));
     if (!proto)
         return nullptr;
 
     assertSameCompartment(cx, proto);
 
     RootedObject global(cx, cx->compartment()->maybeGlobal());
@@ -635,24 +643,43 @@ SavedStacks::sweepPCLocationMap()
         } else if (script != key.script.get()) {
             key.script = script;
             e.rekeyFront(key);
         }
     }
 }
 
 bool
-SavedStacks::getLocation(JSContext *cx, JSScript *script, jsbytecode *pc,
-                         MutableHandleLocationValue locationp)
+SavedStacks::getLocation(JSContext *cx, const FrameIter &iter, MutableHandleLocationValue locationp)
 {
     // We should only ever be caching location values for scripts in this
     // compartment. Otherwise, we would get dead cross-compartment scripts in
     // the cache because our compartment's sweep method isn't called when their
     // compartment gets collected.
-    assertSameCompartment(cx, this, script);
+    assertSameCompartment(cx, this, iter.compartment());
+
+    // When we have a |JSScript| for this frame, use a potentially memoized
+    // location from our PCLocationMap and copy it into |locationp|. When we do
+    // not have a |JSScript| for this frame (asm.js frames), we take a slow path
+    // that doesn't employ memoization, and update |locationp|'s slots directly.
+
+    if (!iter.hasScript()) {
+        const char *filename = iter.scriptFilename();
+        if (!filename)
+            filename = "";
+        locationp->source = Atomize(cx, filename, strlen(filename));
+        if (!locationp->source)
+            return false;
+
+        locationp->line = iter.computeLine(&locationp->column);
+        return true;
+    }
+
+    RootedScript script(cx, iter.script());
+    jsbytecode *pc = iter.pc();
 
     PCKey key(script, pc);
     PCLocationMap::AddPtr p = pcLocationMap.lookupForAdd(key);
 
     if (!p) {
         const char *filename = script->filename() ? script->filename() : "";
         RootedAtom source(cx, Atomize(cx, filename, strlen(filename)));
         if (!source)
@@ -665,16 +692,46 @@ SavedStacks::getLocation(JSContext *cx, 
         if (!pcLocationMap.add(p, key, value))
             return false;
     }
 
     locationp.set(p->value());
     return true;
 }
 
+SavedStacks::FrameState::FrameState(const FrameIter &iter)
+    : principals(iter.compartment()->principals),
+      name(iter.isNonEvalFunctionFrame() ? iter.functionDisplayAtom() : nullptr),
+      location()
+{
+    if (principals)
+        JS_HoldPrincipals(principals);
+}
+
+SavedStacks::FrameState::FrameState(const FrameState &fs)
+    : principals(fs.principals),
+      name(fs.name),
+      location(fs.location)
+{
+    if (principals)
+        JS_HoldPrincipals(principals);
+}
+
+SavedStacks::FrameState::~FrameState() {
+    if (principals)
+        JS_DropPrincipals(TlsPerThreadData.get()->runtimeFromMainThread(), principals);
+}
+
+void
+SavedStacks::FrameState::trace(JSTracer *trc) {
+    if (name)
+        gc::MarkStringUnbarriered(trc, &name, "SavedStacks::FrameState::name");
+    location.trace(trc);
+}
+
 bool
 SavedStacksMetadataCallback(JSContext *cx, JSObject **pmetadata)
 {
     RootedSavedFrame frame(cx);
     if (!cx->compartment()->savedStacks().saveCurrentStack(cx, &frame))
         return false;
     *pmetadata = frame;
     return true;
--- a/js/src/vm/SavedStacks.h
+++ b/js/src/vm/SavedStacks.h
@@ -28,35 +28,36 @@ class SavedFrame : public JSObject {
     static bool lineProperty(JSContext *cx, unsigned argc, Value *vp);
     static bool columnProperty(JSContext *cx, unsigned argc, Value *vp);
     static bool functionDisplayNameProperty(JSContext *cx, unsigned argc, Value *vp);
     static bool parentProperty(JSContext *cx, unsigned argc, Value *vp);
     static bool toStringMethod(JSContext *cx, unsigned argc, Value *vp);
 
     // Convenient getters for SavedFrame's reserved slots for use from C++.
     JSAtom       *getSource();
-    size_t       getLine();
-    size_t       getColumn();
+    uint32_t     getLine();
+    uint32_t     getColumn();
     JSAtom       *getFunctionDisplayName();
     SavedFrame   *getParent();
     JSPrincipals *getPrincipals();
 
     bool         isSelfHosted();
 
     struct Lookup;
     struct HashPolicy;
 
     typedef HashSet<js::ReadBarriered<SavedFrame *>,
                     HashPolicy,
                     SystemAllocPolicy> Set;
 
     class AutoLookupRooter;
+    class HandleLookup;
 
   private:
-    void initFromLookup(const Lookup &lookup);
+    void initFromLookup(HandleLookup lookup);
 
     enum {
         // The reserved slots in the SavedFrame class.
         JSSLOT_SOURCE,
         JSSLOT_LINE,
         JSSLOT_COLUMN,
         JSSLOT_FUNCTIONDISPLAYNAME,
         JSSLOT_PARENT,
@@ -113,77 +114,76 @@ class SavedStacks {
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
 
   private:
     SavedFrame::Set frames;
     JSObject        *savedFrameProto;
 
     bool       insertFrames(JSContext *cx, FrameIter &iter, MutableHandleSavedFrame frame,
                             unsigned maxFrameCount = 0);
-    SavedFrame *getOrCreateSavedFrame(JSContext *cx, const SavedFrame::Lookup &lookup);
+    SavedFrame *getOrCreateSavedFrame(JSContext *cx, SavedFrame::HandleLookup lookup);
     // |SavedFrame.prototype| is created lazily and held weakly. It should only
     // be accessed through this method.
     JSObject   *getOrCreateSavedFramePrototype(JSContext *cx);
-    SavedFrame *createFrameFromLookup(JSContext *cx, const SavedFrame::Lookup &lookup);
+    SavedFrame *createFrameFromLookup(JSContext *cx, SavedFrame::HandleLookup lookup);
 
     // Cache for memoizing PCToLineNumber lookups.
 
     struct PCKey {
         PCKey(JSScript *script, jsbytecode *pc) : script(script), pc(pc) { }
 
         PreBarrieredScript script;
         jsbytecode         *pc;
     };
 
     struct LocationValue {
         LocationValue() : source(nullptr), line(0), column(0) { }
-        LocationValue(JSAtom *source, size_t line, size_t column)
+        LocationValue(JSAtom *source, size_t line, uint32_t column)
             : source(source),
               line(line),
               column(column)
         { }
 
+        void trace(JSTracer *trc) {
+            if (source)
+                gc::MarkString(trc, &source, "SavedStacks::LocationValue::source");
+        }
+
         PreBarrieredAtom source;
         size_t           line;
-        size_t           column;
+        uint32_t         column;
     };
 
     class MOZ_STACK_CLASS AutoLocationValueRooter : public JS::CustomAutoRooter
     {
       public:
         AutoLocationValueRooter(JSContext *cx)
             : JS::CustomAutoRooter(cx),
               value() {}
 
-        void set(LocationValue &loc) {
-            value = loc;
-        }
-
-        LocationValue &get() {
-            return value;
-        }
+        inline LocationValue *operator->() { return &value; }
+        void set(LocationValue &loc) { value = loc; }
+        LocationValue &get() { return value; }
 
       private:
         virtual void trace(JSTracer *trc) {
-            if (value.source)
-                gc::MarkString(trc, &value.source, "SavedStacks::LocationValue::source");
+            value.trace(trc);
         }
 
         SavedStacks::LocationValue value;
     };
 
     class MOZ_STACK_CLASS MutableHandleLocationValue
     {
       public:
         inline MOZ_IMPLICIT MutableHandleLocationValue(AutoLocationValueRooter *location)
             : location(location) {}
 
-        void set(LocationValue &loc) {
-            location->set(loc);
-        }
+        inline LocationValue *operator->() { return &location->get(); }
+        void set(LocationValue &loc) { location->set(loc); }
 
       private:
         AutoLocationValueRooter *location;
     };
 
     struct PCLocationHasher : public DefaultHasher<PCKey> {
         typedef PointerHasher<JSScript *, 3>   ScriptPtrHasher;
         typedef PointerHasher<jsbytecode *, 3> BytecodePtrHasher;
@@ -198,17 +198,51 @@ class SavedStacks {
         }
     };
 
     typedef HashMap<PCKey, LocationValue, PCLocationHasher, SystemAllocPolicy> PCLocationMap;
 
     PCLocationMap pcLocationMap;
 
     void sweepPCLocationMap();
-    bool getLocation(JSContext *cx, JSScript *script, jsbytecode *pc,
-                     MutableHandleLocationValue locationp);
+    bool getLocation(JSContext *cx, const FrameIter &iter, MutableHandleLocationValue locationp);
+
+    struct FrameState
+    {
+        FrameState() : principals(nullptr), name(nullptr), location() { }
+        FrameState(const FrameIter &iter);
+        FrameState(const FrameState &fs);
+
+        ~FrameState();
+
+        void trace(JSTracer *trc);
+
+        JSPrincipals  *principals;
+        JSAtom        *name;
+        LocationValue location;
+    };
+
+    class MOZ_STACK_CLASS AutoFrameStateVector : public JS::CustomAutoRooter {
+      public:
+        AutoFrameStateVector(JSContext *cx)
+          : JS::CustomAutoRooter(cx),
+            frames(cx)
+        { }
+
+        typedef Vector<FrameState> FrameStateVector;
+        inline FrameStateVector *operator->() { return &frames; }
+        inline FrameState &operator[](size_t i) { return frames[i]; }
+
+      private:
+        FrameStateVector frames;
+
+        virtual void trace(JSTracer *trc) {
+            for (size_t i = 0; i < frames.length(); i++)
+                frames[i].trace(trc);
+        }
+    };
 };
 
 bool SavedStacksMetadataCallback(JSContext *cx, JSObject **pmetadata);
 
 } /* namespace js */
 
 #endif /* vm_SavedStacks_h */
--- a/js/xpconnect/tests/chrome/chrome.ini
+++ b/js/xpconnect/tests/chrome/chrome.ini
@@ -13,74 +13,87 @@ support-files =
 
 [test_APIExposer.xul]
 [test_bug361111.xul]
 [test_bug448587.xul]
 [test_bug484459.xul]
 [test_bug500931.xul]
 [test_bug503926.xul]
 [test_bug533596.xul]
+skip-if = buildapp == 'mulet'
 [test_bug571849.xul]
 [test_bug596580.xul]
 [test_bug601803.xul]
 [test_bug610390.xul]
 [test_bug614757.xul]
 [test_bug616992.xul]
 [test_bug618176.xul]
 [test_bug654370.xul]
 [test_bug658560.xul]
 [test_bug658909.xul]
 [test_bug664689.xul]
 [test_bug679861.xul]
 [test_bug706301.xul]
 [test_bug726949.xul]
+skip-if = buildapp == 'mulet'
 [test_bug732665.xul]
+skip-if = buildapp == 'mulet'
 [test_bug738244.xul]
 [test_bug743843.xul]
 [test_bug760076.xul]
+skip-if = buildapp == 'mulet'
 [test_bug760109.xul]
+skip-if = buildapp == 'mulet'
 [test_bug760131.html]
 [test_bug763343.xul]
 [test_bug771429.xul]
 [test_bug773962.xul]
 [test_bug792280.xul]
 [test_bug793433.xul]
 [test_bug795275.xul]
 [test_bug799348.xul]
 [test_bug801241.xul]
+skip-if = buildapp == 'mulet'
 [test_bug812415.xul]
 [test_bug853283.xul]
 [test_bug853571.xul]
 [test_bug858101.xul]
+skip-if = buildapp == 'mulet'
 [test_bug860494.xul]
 [test_bug866823.xul]
 [test_bug895340.xul]
 [test_bug932906.xul]
 [test_bug996069.xul]
 [test_bug1041626.xul]
 [test_xrayToJS.xul]
+skip-if = buildapp == 'mulet'
 [test_chrometoSource.xul]
+skip-if = buildapp == 'mulet'
 [test_cloneInto.xul]
 [test_cows.xul]
+skip-if = buildapp == 'mulet'
 [test_discardSystemSource.xul]
+skip-if = buildapp == 'mulet'
 [test_documentdomain.xul]
 [test_doublewrappedcompartments.xul]
 [test_evalInSandbox.xul]
 [test_evalInWindow.xul]
 [test_exnstack.xul]
 [test_expandosharing.xul]
+skip-if = buildapp == 'mulet'
 [test_exposeInDerived.xul]
 [test_getweakmapkeys.xul]
 [test_localstorage_with_nsEp.xul]
 [test_mozMatchesSelector.xul]
 [test_nodelists.xul]
 [test_paris_weakmap_keys.xul]
 [test_precisegc.xul]
 [test_sandboxImport.xul]
 [test_scriptSettings.xul]
+skip-if = buildapp == 'mulet'
 [test_weakmap_keys_preserved.xul]
 [test_weakmap_keys_preserved2.xul]
 [test_weakref.xul]
 [test_wrappers.xul]
 [test_weakmaps.xul]
 skip-if = os == "win" # Bug 820471
 [test_wrappers-2.xul]
 # Disabled until this test gets updated to test the new proxy based wrappers.
--- a/js/xpconnect/tests/mochitest/mochitest.ini
+++ b/js/xpconnect/tests/mochitest/mochitest.ini
@@ -32,16 +32,17 @@ support-files =
   file_mozMatchesSelector.html
   file_nodelists.html
   file_wrappers-2.html
   inner.html
   test1_bug629331.html
   test2_bug629331.html
 
 [test_bug384632.html]
+skip-if= buildapp == 'mulet'
 [test_bug390488.html]
 [test_bug393269.html]
 [test_bug396851.html]
 [test_bug428021.html]
 [test_bug446584.html]
 [test_bug462428.html]
 [test_bug478438.html]
 [test_bug500691.html]
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/unit/test_xrayed_iterator.js
@@ -0,0 +1,36 @@
+const Cu = Components.utils;
+function run_test() {
+
+  var toEval = [
+    "var customIterator = {",
+    "  _array: [6, 7, 8, 9],",
+    "  __iterator__: function() {",
+    "    for (var i = 0; i < this._array.length; ++i)",
+    "      yield this._array[i];",
+    "  }",
+    "}"
+  ].join('\n');
+
+  function checkIterator(iterator) {
+    var control = [6, 7, 8, 9];
+    var i = 0;
+    for (var item in iterator) {
+      do_check_eq(item, control[i]);
+      ++i;
+    }
+  }
+
+  // First, try in our own scope.
+  eval(toEval);
+  checkIterator(customIterator);
+
+  // Next, try a vanilla CCW.
+  var sbChrome = Cu.Sandbox(this);
+  Cu.evalInSandbox(toEval, sbChrome, '1.7');
+  checkIterator(sbChrome.customIterator);
+
+  // Finally, try an Xray waiver.
+  var sbContent = Cu.Sandbox('http://www.example.com');
+  Cu.evalInSandbox(toEval, sbContent, '1.7');
+  checkIterator(Cu.waiveXrays(sbContent.customIterator));
+}
--- a/js/xpconnect/tests/unit/xpcshell.ini
+++ b/js/xpconnect/tests/unit/xpcshell.ini
@@ -94,8 +94,9 @@ head = head_watchdog.js
 head = head_watchdog.js
 [test_watchdog_toggle.js]
 head = head_watchdog.js
 [test_watchdog_default.js]
 head = head_watchdog.js
 [test_watchdog_hibernate.js]
 head = head_watchdog.js
 [test_writeToGlobalPrototype.js]
+[test_xrayed_iterator.js]
--- a/js/xpconnect/wrappers/WaiveXrayWrapper.cpp
+++ b/js/xpconnect/wrappers/WaiveXrayWrapper.cpp
@@ -62,16 +62,24 @@ WaiveXrayWrapper::get(JSContext *cx, Han
                       HandleObject receiver, HandleId id,
                       MutableHandleValue vp) const
 {
     return CrossCompartmentWrapper::get(cx, wrapper, receiver, id, vp) &&
            WrapperFactory::WaiveXrayAndWrap(cx, vp);
 }
 
 bool
+WaiveXrayWrapper::iterate(JSContext *cx, HandleObject proxy, unsigned flags,
+                         MutableHandleValue vp) const
+{
+    return CrossCompartmentWrapper::iterate(cx, proxy, flags, vp) &&
+           WrapperFactory::WaiveXrayAndWrap(cx, vp);
+}
+
+bool
 WaiveXrayWrapper::call(JSContext *cx, HandleObject wrapper, const JS::CallArgs &args) const
 {
     return CrossCompartmentWrapper::call(cx, wrapper, args) &&
            WrapperFactory::WaiveXrayAndWrap(cx, args.rval());
 }
 
 bool
 WaiveXrayWrapper::construct(JSContext *cx, HandleObject wrapper, const JS::CallArgs &args) const
--- a/js/xpconnect/wrappers/WaiveXrayWrapper.h
+++ b/js/xpconnect/wrappers/WaiveXrayWrapper.h
@@ -21,16 +21,19 @@ class WaiveXrayWrapper : public js::Cros
     virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                        JS::Handle<jsid> id,
                                        JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool getOwnPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                           JS::Handle<jsid> id,
                                           JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
     virtual bool get(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<JSObject*> receiver,
                      JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
+    virtual bool iterate(JSContext *cx, JS::Handle<JSObject*> proxy, unsigned flags,
+                         JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
+
 
     virtual bool call(JSContext *cx, JS::Handle<JSObject*> wrapper,
                       const JS::CallArgs &args) const MOZ_OVERRIDE;
     virtual bool construct(JSContext *cx, JS::Handle<JSObject*> wrapper,
                            const JS::CallArgs &args) const MOZ_OVERRIDE;
 
     virtual bool nativeCall(JSContext *cx, JS::IsAcceptableThis test,
                             JS::NativeImpl impl, JS::CallArgs args) const MOZ_OVERRIDE;
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -553,17 +553,18 @@ void nsDisplayListBuilder::SetContainsBl
   mContainedBlendModes += gfx::CompositionOpForOp(op);
 }
 
 void nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame,
                                                         nsIFrame* aFrame,
                                                         const nsRect& aDirtyRect)
 {
   nsRect dirtyRectRelativeToDirtyFrame = aDirtyRect;
-  if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(aFrame)) {
+  if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(aFrame) &&
+      IsPaintingToWindow()) {
     NS_ASSERTION(aDirtyFrame == aFrame->GetParent(), "Dirty frame should be viewport frame");
     // position: fixed items are reflowed into and only drawn inside the
     // viewport, or the scroll position clamping scrollport size, if one is
     // set.
     nsIPresShell* ps = aFrame->PresContext()->PresShell();
     dirtyRectRelativeToDirtyFrame.MoveTo(0, 0);
     if (ps->IsScrollPositionClampingScrollPortSizeSet()) {
       dirtyRectRelativeToDirtyFrame.SizeTo(ps->GetScrollPositionClampingScrollPortSize());
@@ -629,17 +630,17 @@ static void RecordFrameMetrics(nsIFrame*
   nsIContent* content = aScrollFrame ? aScrollFrame->GetContent() : nullptr;
   if (content) {
     if (!aForceNullScrollId) {
       scrollId = nsLayoutUtils::FindOrCreateIDFor(content);
     }
     nsRect dp;
     if (nsLayoutUtils::GetDisplayPort(content, &dp)) {
       metrics.mDisplayPort = CSSRect::FromAppUnits(dp);
-      nsLayoutUtils::LogTestDataForPaint(presShell, scrollId, "displayport",
+      nsLayoutUtils::LogTestDataForPaint(aRoot->Manager(), scrollId, "displayport",
           metrics.mDisplayPort);
     }
     if (nsLayoutUtils::GetCriticalDisplayPort(content, &dp)) {
       metrics.mCriticalDisplayPort = CSSRect::FromAppUnits(dp);
     }
     DisplayPortMarginsPropertyData* marginsData =
         static_cast<DisplayPortMarginsPropertyData*>(content->GetProperty(nsGkAtoms::DisplayPortMargins));
     if (marginsData) {
@@ -2932,16 +2933,17 @@ nsDisplayBoxShadowInner::ComputeVisibili
   mVisibleRegion.And(*aVisibleRegion, mVisibleRect);
   return true;
 }
 
 nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
                                      nsIFrame* aFrame, nsDisplayList* aList)
   : nsDisplayItem(aBuilder, aFrame)
   , mOverrideZIndex(0)
+  , mHasZIndexOverride(false)
 {
   MOZ_COUNT_CTOR(nsDisplayWrapList);
 
   mList.AppendToTop(aList);
   UpdateBounds(aBuilder);
 
   if (!aFrame || !aFrame->IsTransformed()) {
     return;
@@ -2978,16 +2980,17 @@ nsDisplayWrapList::nsDisplayWrapList(nsD
   }
   mVisibleRect = aBuilder->GetDirtyRect() + mToReferenceFrame;
 }
 
 nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
                                      nsIFrame* aFrame, nsDisplayItem* aItem)
   : nsDisplayItem(aBuilder, aFrame)
   , mOverrideZIndex(0)
+  , mHasZIndexOverride(false)
 {
   MOZ_COUNT_CTOR(nsDisplayWrapList);
 
   mList.AppendToTop(aItem);
   UpdateBounds(aBuilder);
   
   if (!aFrame || !aFrame->IsTransformed()) {
     return;
@@ -3595,19 +3598,30 @@ nsDisplaySubDocument::ComputeVisibility(
   // content to asynchronously pan while content is being refreshed.
   childVisibleRegion = displayport + mFrame->GetOffsetToCrossDoc(ReferenceFrame());
 
   nsRect boundedRect =
     childVisibleRegion.GetBounds().Intersect(mList.GetBounds(aBuilder));
   bool visible = mList.ComputeVisibilityForSublist(
     aBuilder, &childVisibleRegion, boundedRect,
     usingDisplayPort ? mFrame : nullptr);
-  // We don't allow this computation to influence aVisibleRegion, on the
-  // assumption that the layer can be asynchronously scrolled so we'll
-  // definitely need all the content under it.
+
+#ifndef MOZ_WIDGET_ANDROID
+  // If APZ is enabled then don't allow this computation to influence
+  // aVisibleRegion, on the assumption that the layer can be asynchronously
+  // scrolled so we'll definitely need all the content under it.
+  if (!gfxPrefs::AsyncPanZoomEnabled()) {
+    bool snap;
+    nsRect bounds = GetBounds(aBuilder, &snap);
+    nsRegion removed;
+    removed.Sub(bounds, childVisibleRegion);
+
+    aBuilder->SubtractFromVisibleRegion(aVisibleRegion, removed);
+  }
+#endif
 
   return visible;
 }
 
 bool
 nsDisplaySubDocument::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder)
 {
   bool usingDisplayPort =
@@ -3882,30 +3896,43 @@ nsDisplayScrollLayer::ShouldBuildLayerEv
 
   return nsDisplayWrapList::ShouldBuildLayerEvenIfInvisible(aBuilder);
 }
 
 bool
 nsDisplayScrollLayer::ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                         nsRegion* aVisibleRegion)
 {
+  if (aBuilder->IsForPluginGeometry()) {
+    return nsDisplayWrapList::ComputeVisibility(aBuilder, aVisibleRegion);
+  }
   nsRect displayport;
   bool usingDisplayPort =
     nsLayoutUtils::GetDisplayPort(mScrolledFrame->GetContent(), &displayport);
   nsRect scrolledContentRect = GetScrolledContentRectToDraw(aBuilder,
       usingDisplayPort ? &displayport : nullptr);
 
   nsRect boundedRect = scrolledContentRect.Intersect(mList.GetBounds(aBuilder));
   nsRegion childVisibleRegion = scrolledContentRect;
   bool visible = mList.ComputeVisibilityForSublist(
     aBuilder, &childVisibleRegion, boundedRect,
     usingDisplayPort ? mScrollFrame : nullptr);
-  // We don't allow this computation to influence aVisibleRegion, on the
-  // assumption that the layer can be asynchronously scrolled so we'll
-  // definitely need all the content under it.
+
+#ifndef MOZ_WIDGET_ANDROID
+  // If APZ is enabled then don't allow this computation to influence
+  // aVisibleRegion, on the assumption that the layer can be asynchronously
+  // scrolled so we'll definitely need all the content under it.
+  if (!gfxPrefs::AsyncPanZoomEnabled()) {
+    bool snap;
+    nsRect bounds = GetBounds(aBuilder, &snap);
+    nsRegion removed;
+    removed.Sub(bounds, childVisibleRegion);
+    aBuilder->SubtractFromVisibleRegion(aVisibleRegion, removed);
+  }
+#endif
 
   return visible;
 }
 
 LayerState
 nsDisplayScrollLayer::GetLayerState(nsDisplayListBuilder* aBuilder,
                                     LayerManager* aManager,
                                     const ContainerLayerParameters& aParameters)
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -2506,17 +2506,17 @@ public:
   /**
    * Takes all the items from aList and puts them in our list.
    */
   nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                     nsDisplayList* aList);
   nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                     nsDisplayItem* aItem);
   nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
-    : nsDisplayItem(aBuilder, aFrame), mOverrideZIndex(0)
+    : nsDisplayItem(aBuilder, aFrame), mOverrideZIndex(0), mHasZIndexOverride(false)
   {
     MOZ_COUNT_CTOR(nsDisplayWrapList);
   }
   virtual ~nsDisplayWrapList();
   /**
    * Call this if the wrapped list is changed.
    */
   virtual void UpdateBounds(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE
@@ -2569,21 +2569,22 @@ public:
                  mList.GetBottom()->ReferenceFrame() == ReferenceFrame(),
                  "Children must have same reference frame");
     return &mList;
   }
   virtual nsDisplayList* GetChildren() MOZ_OVERRIDE { return &mList; }
 
   virtual int32_t ZIndex() const MOZ_OVERRIDE
   {
-    return (mOverrideZIndex > 0) ? mOverrideZIndex : nsDisplayItem::ZIndex();
+    return (mHasZIndexOverride) ? mOverrideZIndex : nsDisplayItem::ZIndex();
   }
 
   void SetOverrideZIndex(int32_t aZIndex)
   {
+    mHasZIndexOverride = true;
     mOverrideZIndex = aZIndex;
   }
 
   /**
    * This creates a copy of this item, but wrapping aItem instead of
    * our existing list. Only gets called if this item returned nullptr
    * for GetUnderlyingFrame(). aItem is guaranteed to return non-null from
    * GetUnderlyingFrame().
@@ -2606,18 +2607,18 @@ protected:
     mMergedFrames.MoveElementsFrom(aOther->mMergedFrames);
   }
 
   nsDisplayList mList;
   // The frames from items that have been merged into this item, excluding
   // this item's own frame.
   nsTArray<nsIFrame*> mMergedFrames;
   nsRect mBounds;
-  // Overrides the ZIndex of our frame if > 0.
   int32_t mOverrideZIndex;
+  bool mHasZIndexOverride;
 };
 
 /**
  * We call WrapDisplayList on the in-flow lists: BorderBackground(),
  * BlockBorderBackgrounds() and Content().
  * We call WrapDisplayItem on each item of Outlines(), PositionedDescendants(),
  * and Floats(). This is done to support special wrapping processing for frames
  * that may not be in-flow descendants of the current frame.
--- a/layout/base/nsLayoutDebugger.cpp
+++ b/layout/base/nsLayoutDebugger.cpp
@@ -156,18 +156,19 @@ PrintDisplayItemTo(nsDisplayListBuilder*
   const DisplayItemClip& clip = aItem->GetClip();
   nsRegion opaque = aItem->GetOpaqueRegion(aBuilder, &snap);
   if (aDumpHtml && aItem->Painted()) {
     nsCString string(aItem->Name());
     string.Append('-');
     string.AppendInt((uint64_t)aItem);
     aStream << nsPrintfCString("<a href=\"javascript:ViewImage('%s')\">", string.BeginReading());
   }
-  aStream << nsPrintfCString("%s p=0x%p f=0x%p(%s) bounds(%d,%d,%d,%d) visible(%d,%d,%d,%d) componentAlpha(%d,%d,%d,%d) clip(%s) %s",
+  aStream << nsPrintfCString("%s p=0x%p f=0x%p(%s) %sbounds(%d,%d,%d,%d) visible(%d,%d,%d,%d) componentAlpha(%d,%d,%d,%d) clip(%s) %s",
           aItem->Name(), aItem, (void*)f, NS_ConvertUTF16toUTF8(fName).get(),
+          (aItem->ZIndex() ? nsPrintfCString("z=%d ", aItem->ZIndex()).get() : ""),
           rect.x, rect.y, rect.width, rect.height,
           vis.x, vis.y, vis.width, vis.height,
           component.x, component.y, component.width, component.height,
           clip.ToString().get(),
           aItem->IsUniform(aBuilder, &color) ? " uniform" : "");
 
   nsRegionRectIterator iter(opaque);
   for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
@@ -261,17 +262,17 @@ PrintDisplayListSetItem(nsDisplayListBui
                         const char* aItemName,
                         const nsDisplayList& aList,
                         std::stringstream& aStream,
                         bool aDumpHtml)
 {
   if (aDumpHtml) {
     aStream << "<li>";
   }
-  aStream << aItemName;
+  aStream << aItemName << "\n";
   PrintDisplayListTo(aBuilder, aList, aStream, 0, aDumpHtml);
   if (aDumpHtml) {
     aStream << "</li>";
   }
 }
 
 void
 nsFrame::PrintDisplayListSet(nsDisplayListBuilder* aBuilder,
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -924,21 +924,24 @@ nsLayoutUtils::SetDisplayPortMargins(nsI
     return;
   }
 
   aContent->SetProperty(nsGkAtoms::DisplayPortMargins,
                         new DisplayPortMarginsPropertyData(
                             aMargins, aAlignmentX, aAlignmentY, aPriority),
                         nsINode::DeleteProperty<DisplayPortMarginsPropertyData>);
 
-  nsIFrame* rootScrollFrame = aPresShell->GetRootScrollFrame();
-  if (rootScrollFrame && aContent == rootScrollFrame->GetContent()) {
-    // We are setting a root displayport for a document.
-    // The pres shell needs a special flag set.
-    aPresShell->SetIgnoreViewportScrolling(true);
+  if (gfxPrefs::AsyncPanZoomEnabled()) {
+    nsIFrame* rootScrollFrame = aPresShell->GetRootScrollFrame();
+    if (rootScrollFrame && aContent == rootScrollFrame->GetContent()) {
+      // We are setting a root displayport for a document.
+      // If we have APZ, then set a special flag on the pres shell so
+      // that we don't get scrollbars drawn.
+      aPresShell->SetIgnoreViewportScrolling(true);
+    }
   }
 
   if (aRepaintMode == RepaintMode::Repaint) {
     nsIFrame* rootFrame = aPresShell->FrameManager()->GetRootFrame();
     if (rootFrame) {
       rootFrame->SchedulePaint();
     }
   }
@@ -6812,25 +6815,23 @@ nsLayoutUtils::WantSubAPZC()
   if (XRE_GetProcessType() != GeckoProcessType_Content) {
     wantSubAPZC = false;
   }
 #endif
   return wantSubAPZC;
 }
 
 /* static */ void
-nsLayoutUtils::DoLogTestDataForPaint(nsIPresShell* aPresShell,
+nsLayoutUtils::DoLogTestDataForPaint(LayerManager* aManager,
                                      ViewID aScrollId,
                                      const std::string& aKey,
                                      const std::string& aValue)
 {
-  nsRefPtr<LayerManager> lm = aPresShell->GetPresContext()->GetRootPresContext()
-      ->GetPresShell()->GetLayerManager();
-  if (lm && lm->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
-    static_cast<ClientLayerManager*>(lm.get())->LogTestDataForCurrentPaint(aScrollId, aKey, aValue);
+  if (aManager->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
+    static_cast<ClientLayerManager*>(aManager)->LogTestDataForCurrentPaint(aScrollId, aKey, aValue);
   }
 }
 
 /* static */ bool
 nsLayoutUtils::IsAPZTestLoggingEnabled()
 {
   return gfxPrefs::APZTestLoggingEnabled();
 }
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -2194,44 +2194,43 @@ public:
   /**
    * Return whether we want to use APZ for subframes in this process.
    * Currently we don't support APZ for the parent process on B2G.
    */
   static bool WantSubAPZC();
 
   /**
    * Log a key/value pair for APZ testing during a paint.
-   * @param aPresShell The pres shell that identifies where to log to. The data
-   *                   will be written to the APZTestData associated with the
-   *                   pres shell's layer manager.
+   * @param aManager   The data will be written to the APZTestData associated 
+   *                   with this layer manager.
    * @param aScrollId Identifies the scroll frame to which the data pertains.
    * @param aKey The key under which to log the data.
    * @param aValue The value of the data to be logged.
    */
-  static void LogTestDataForPaint(nsIPresShell* aPresShell,
+  static void LogTestDataForPaint(mozilla::layers::LayerManager* aManager,
                                   ViewID aScrollId,
                                   const std::string& aKey,
                                   const std::string& aValue) {
     if (IsAPZTestLoggingEnabled()) {
-      DoLogTestDataForPaint(aPresShell, aScrollId, aKey, aValue);
+      DoLogTestDataForPaint(aManager, aScrollId, aKey, aValue);
     }
   }
 
   /**
    * A convenience overload of LogTestDataForPaint() that accepts any type
    * as the value, and passes it through mozilla::ToString() to obtain a string
    * value. The type passed must support streaming to an std::ostream.
    */
   template <typename Value>
-  static void LogTestDataForPaint(nsIPresShell* aPresShell,
+  static void LogTestDataForPaint(mozilla::layers::LayerManager* aManager,
                                   ViewID aScrollId,
                                   const std::string& aKey,
                                   const Value& aValue) {
     if (IsAPZTestLoggingEnabled()) {
-      DoLogTestDataForPaint(aPresShell, aScrollId, aKey,
+      DoLogTestDataForPaint(aManager, aScrollId, aKey,
           mozilla::ToString(aValue));
     }
   }
 
  /**
    * Get the display port for |aScrollFrame|'s content. If |aScrollFrame|
    * WantsAsyncScroll() and we don't have a scrollable displayport yet (as
    * tracked by |aBuilder|), calculate and set a display port. Returns true if
@@ -2263,17 +2262,17 @@ private:
   static bool sFontSizeInflationDisabledInMasterProcess;
   static bool sInvalidationDebuggingIsEnabled;
   static bool sCSSVariablesEnabled;
   static bool sInterruptibleReflowEnabled;
 
   /**
    * Helper function for LogTestDataForPaint().
    */
-  static void DoLogTestDataForPaint(nsIPresShell* aPresShell,
+  static void DoLogTestDataForPaint(mozilla::layers::LayerManager* aManager,
                                     ViewID aScrollId,
                                     const std::string& aKey,
                                     const std::string& aValue);
 
   static bool IsAPZTestLoggingEnabled();
 };
 
 MOZ_FINISH_NESTED_ENUM_CLASS(nsLayoutUtils::RepaintMode)
--- a/layout/base/tests/chrome/chrome.ini
+++ b/layout/base/tests/chrome/chrome.ini
@@ -21,25 +21,28 @@ support-files =
 [test_bug396367-1.html]
 [test_bug396367-2.html]
 [test_bug420499.xul]
 [test_bug458898.html]
 [test_bug495648.xul]
 [test_bug504311.xul]
 [test_bug514660.xul]
 [test_bug533845.xul]
+skip-if = buildapp == 'mulet'
 [test_bug551434.html]
 [test_bug708062.html]
 [test_bug812817.xul]
 [test_bug847890_paintFlashing.html]
 [test_bug1018265.xul]
+skip-if = buildapp == 'mulet'
 [test_bug1041200.xul]
 support-files=bug1041200_window.html
 [test_chrome_content_integration.xul]
 [test_chrome_over_plugin.xul]
+skip-if = buildapp == 'mulet'
 [test_default_background.xul]
 [test_dialog_with_positioning.html]
 [test_fixed_bg_scrolling_repaints.html]
 [test_leaf_layers_partition_browser_window.xul]
 skip-if = (!debug) || (toolkit == "cocoa") # Disabled on Mac because of Bug 748219
 [test_no_clip_iframe.xul]
 [test_passpointerevents.html]
 [test_prerendered_transforms.html]
--- a/layout/base/tests/mochitest.ini
+++ b/layout/base/tests/mochitest.ini
@@ -177,27 +177,27 @@ support-files = file_bug607529.html
 [test_bug677878.html]
 [test_bug696020.html]
 [test_event_target_radius.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # bug 1040987
 [test_event_target_iframe_oop.html]
 skip-if = e10s # bug 1020135, nested oop iframes not supported
 support-files = bug921928_event_target_iframe_apps_oop.html
 [test_mozPaintCount.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(depends on plugins support) b2g-debug(depends on plugins support) b2g-desktop(depends on plugins support)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(depends on plugins support) b2g-debug(depends on plugins support) b2g-desktop(depends on plugins support)
 [test_scroll_event_ordering.html]
 [test_bug583889.html]
 support-files = bug583889_inner1.html bug583889_inner2.html
 [test_bug582771.html]
 [test_bug968148.html]
 support-files = bug968148_inner.html
 [test_bug603550.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #TIMED_OUT # b2g(Components.classes[@mozilla.org/widget/dragservice;1] is undefined) b2g-debug(Components.classes[@mozilla.org/widget/dragservice;1] is undefined) b2g-desktop(Components.classes[@mozilla.org/widget/dragservice;1] is undefined)
 [test_bug629838.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(depends on plugins support) b2g-debug(depends on plugins support) b2g-desktop(depends on plugins support)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(depends on plugins support) b2g-debug(depends on plugins support) b2g-desktop(depends on plugins support)
 [test_bug646757.html]
 [test_bug718809.html]
 [test_bug725426.html]
 [test_bug731777.html]
 [test_bug761572.html]
 [test_bug770106.html]
 [test_maxLineBoxWidth.html]
 [test_remote_frame.html]
@@ -211,17 +211,17 @@ skip-if = (buildapp == 'b2g' && toolkit 
 support-files = bug851445_helper.html
 [test_bug970964.html]
 support-files = bug970964_inner.html
 [test_bug976963.html]
 support-files = bug976963_inner.html
 [test_emulateMedium.html]
 [test_getClientRects_emptytext.html]
 [test_bug858459.html]
-skip-if = toolkit == "gonk" || buildapp == 'b2g' #Bug 931116, b2g desktop specific, initial triage
+skip-if = toolkit == "gonk" || buildapp == 'mulet' || buildapp == 'b2g' #Bug 931116, b2g desktop specific, initial triage
 
 # Tests for bugs 441782, 467672 and 570378 do not pass reliably on Windows,
 # because of bug 469208.
 [test_bug332655-1.html]
 skip-if = toolkit == "win" || toolkit == 'android'
 [test_bug332655-2.html]
 skip-if = toolkit == "win"
 [test_bug441782-1a.html]
--- a/layout/forms/test/chrome.ini
+++ b/layout/forms/test/chrome.ini
@@ -1,8 +1,9 @@
 [DEFAULT]
 support-files =
   bug536567_iframe.html
   bug536567_subframe.html
   bug665540_window.xul
 
 [test_bug536567_perwindowpb.html]
 [test_bug665540.html]
+skip-if = buildapp == 'mulet'
--- a/layout/forms/test/mochitest.ini
+++ b/layout/forms/test/mochitest.ini
@@ -5,17 +5,17 @@ support-files =
   bug564115_window.html
 
 [test_bug231389.html]
 [test_bug287446.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #bug 947789
 [test_bug345267.html]
 skip-if = e10s
 [test_bug348236.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(select form control popup) b2g-debug(select form control popup) b2g-desktop(select form control popup)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(select form control popup) b2g-debug(select form control popup) b2g-desktop(select form control popup)
 [test_bug353539.html]
 [test_bug365410.html]
 [test_bug378670.html]
 skip-if = toolkit == 'android' #TIMED_OUT
 [test_bug402198.html]
 [test_bug411236.html]
 [test_bug446663.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' # b2g(needs copy support) b2g-debug(needs copy support) b2g-desktop(needs copy support)
@@ -28,17 +28,17 @@ skip-if = buildapp == 'b2g' || toolkit =
 [test_bug542914.html]
 skip-if = (toolkit == 'gonk' && debug) #debug-only failure
 [test_bug549170.html]
 [test_bug562447.html]
 [test_bug563642.html]
 [test_bug564115.html]
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || toolkit == 'android' || e10s #TIMED_OUT # b2g-debug(times out on window.open and focus event) b2g-desktop(times out on window.open and focus event)
 [test_bug571352.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT # b2g(shift-click multi-select not working?) b2g-debug(shift-click multi-select not working?) b2g-desktop(shift-click multi-select not working?)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT # b2g(shift-click multi-select not working?) b2g-debug(shift-click multi-select not working?) b2g-desktop(shift-click multi-select not working?)
 [test_bug572406.html]
 [test_bug572649.html]
 skip-if = toolkit == 'android' #TIMED_OUT
 [test_bug595310.html]
 [test_bug620936.html]
 [test_bug644542.html]
 skip-if = toolkit == 'android' #TIMED_OUT
 [test_bug672810.html]
@@ -53,11 +53,11 @@ skip-if = buildapp == 'b2g' || toolkit =
 # Bug 1023472 - Fails when pushed into a different chunk on Android
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || toolkit == 'android'
 [test_bug957562.html]
 [test_bug960277.html]
 [test_listcontrol_search.html]
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || toolkit == 'android' #select elements don't use an in-page popup on Android # b2g-debug(select elements don't use an in-page popup in B2G) b2g-desktop(select elements don't use an in-page popup in B2G)
 [test_select_prevent_default.html]
 [test_textarea_resize.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' # b2g(resizing textarea not available in b2g) b2g-debug(resizing textarea not available in b2g) b2g-desktop(resizing textarea not available in b2g)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' # b2g(resizing textarea not available in b2g) b2g-debug(resizing textarea not available in b2g) b2g-desktop(resizing textarea not available in b2g)
 [test_bug961363.html]
 skip-if = toolkit == 'android' # Bug 1021644 - Fails when pushed into a different chunk on Android
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -1599,16 +1599,34 @@ ScrollFrameHelper::ScrollFrameHelper(nsC
 {
   mScrollingActive = IsAlwaysActive();
 
   if (LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) != 0) {
     mScrollbarActivity = new ScrollbarActivity(do_QueryFrame(aOuter));
   }
 
   EnsureImageVisPrefsCached();
+
+#ifndef MOZ_WIDGET_ANDROID
+  if (mScrollingActive &&
+      gfxPrefs::LayersTilesEnabled() &&
+      !gfxPrefs::AsyncPanZoomEnabled() &&
+      mOuter->GetContent()) {
+    // If we have tiling but no APZ, then set a 0-margin display port on
+    // active scroll containers so that we paint by whole tile increments
+    // when scrolling.
+    nsLayoutUtils::SetDisplayPortMargins(mOuter->GetContent(),
+                                         mOuter->PresContext()->PresShell(),
+                                         LayerMargin(),
+                                         gfxPrefs::LayersTileWidth(), gfxPrefs::LayersTileHeight(),
+                                         0,
+                                         nsLayoutUtils::RepaintMode::DoNotRepaint);
+  }
+#endif
+
 }
 
 ScrollFrameHelper::~ScrollFrameHelper()
 {
   if (mActivityExpirationState.IsTracked()) {
     gScrollFrameActivityTracker->RemoveObject(this);
   }
   if (gScrollFrameActivityTracker &&
@@ -2428,51 +2446,46 @@ ScrollFrameHelper::BuildDisplayList(nsDi
   bool createLayersForScrollbars = mIsRoot &&
     mOuter->PresContext()->IsRootContentDocument();
 
   if (aBuilder->GetIgnoreScrollFrame() == mOuter || IsIgnoringViewportClipping()) {
 
     // If we are a root scroll frame that has a display port we want to add
     // scrollbars, they will be children of the scrollable layer, but they get
     // adjusted by the APZC automatically.
-    bool addScrollBars = mIsRoot &&
-      nsLayoutUtils::GetDisplayPort(mOuter->GetContent()) &&
-      !aBuilder->IsForEventDelivery();
+    bool usingDisplayPort = nsLayoutUtils::GetDisplayPort(mOuter->GetContent());
+    bool addScrollBars = mIsRoot && usingDisplayPort && !aBuilder->IsForEventDelivery();
+
+    nsRect scrollbarDirty = aDirtyRect;
+    if (usingDisplayPort) {
+      // Make sure we include the scrollbars.
+      scrollbarDirty.Inflate(GetActualScrollbarSizes());
+    }
 
     if (addScrollBars) {
       // Add classic scrollbars.
-      AppendScrollPartsTo(aBuilder, aDirtyRect, aLists, createLayersForScrollbars,
+      AppendScrollPartsTo(aBuilder, scrollbarDirty, aLists, createLayersForScrollbars,
                           false);
     }
 
     // Don't clip the scrolled child, and don't paint scrollbars/scrollcorner.
     // The scrolled frame shouldn't have its own background/border, so we
     // can just pass aLists directly.
     mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame,
                                      aDirtyRect, aLists);
 
     if (addScrollBars) {
       // Add overlay scrollbars.
-      AppendScrollPartsTo(aBuilder, aDirtyRect, aLists,
+      AppendScrollPartsTo(aBuilder, scrollbarDirty, aLists,
                           createLayersForScrollbars, true);
     }
 
     return;
   }
 
-  // Now display the scrollbars and scrollcorner. These parts are drawn
-  // in the border-background layer, on top of our own background and
-  // borders and underneath borders and backgrounds of later elements
-  // in the tree.
-  // Note that this does not apply for overlay scrollbars; those are drawn
-  // in the positioned-elements layer on top of everything else by the call
-  // to AppendScrollPartsTo(..., true) further down.
-  AppendScrollPartsTo(aBuilder, aDirtyRect, aLists, createLayersForScrollbars,
-                      false);
-
   // Overflow clipping can never clip frames outside our subtree, so there
   // is no need to worry about whether we are a moving frame that might clip
   // non-moving frames.
   // Not all our descendants will be clipped by overflow clipping, but all
   // the ones that aren't clipped will be out of flow frames that have already
   // had dirty rects saved for them by their parent frames calling
   // MarkOutOfFlowChildrenForDisplayList, so it's safe to restrict our
   // dirty rect here.
@@ -2509,16 +2522,32 @@ ScrollFrameHelper::BuildDisplayList(nsDi
     }
 
     // Override the dirty rectangle if the displayport has been set.
     if (usingDisplayport) {
       dirtyRect = displayPort;
     }
   }
 
+  nsRect scrollbarDirty = aDirtyRect;
+  if (usingDisplayport) {
+    // Make sure we include the scrollbars.
+    scrollbarDirty.Inflate(GetActualScrollbarSizes());
+  }
+
+  // Now display the scrollbars and scrollcorner. These parts are drawn
+  // in the border-background layer, on top of our own background and
+  // borders and underneath borders and backgrounds of later elements
+  // in the tree.
+  // Note that this does not apply for overlay scrollbars; those are drawn
+  // in the positioned-elements layer on top of everything else by the call
+  // to AppendScrollPartsTo(..., true) further down.
+  AppendScrollPartsTo(aBuilder, scrollbarDirty, aLists, createLayersForScrollbars,
+                      false);
+
   if (aBuilder->IsForImageVisibility()) {
     // We expand the dirty rect to catch images just outside of the scroll port.
     // We use the dirty rect instead of the whole scroll port to prevent
     // too much expansion in the presence of very large (bigger than the
     // viewport) scroll ports.
     dirtyRect = ExpandRectToNearlyVisible(dirtyRect);
   }
 
@@ -2645,17 +2674,17 @@ ScrollFrameHelper::BuildDisplayList(nsDi
     if (!positionedDescendants->IsEmpty()) {
       layerItem->SetOverrideZIndex(MaxZIndexInList(positionedDescendants, aBuilder));
       positionedDescendants->AppendNewToTop(layerItem);
     } else {
       aLists.Outlines()->AppendNewToTop(layerItem);
     }
   }
   // Now display overlay scrollbars and the resizer, if we have one.
-  AppendScrollPartsTo(aBuilder, aDirtyRect, scrolledContent,
+  AppendScrollPartsTo(aBuilder, scrollbarDirty, scrolledContent,
                       createLayersForScrollbars, true);
   scrolledContent.MoveTo(aLists);
 }
 
 bool
 ScrollFrameHelper::IsRectNearlyVisible(const nsRect& aRect) const
 {
   // Use the right rect depending on if a display port is set.
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -403,17 +403,18 @@ nsSubDocumentFrame::BuildDisplayList(nsD
     dirty = dirty.ConvertAppUnitsRoundOut(parentAPD, subdocAPD);
 
     if (nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame()) {
       // for root content documents we want the base to be the composition bounds
       nsRect displayportBase = presContext->IsRootContentDocument() ?
           nsRect(nsPoint(0,0), nsLayoutUtils::CalculateCompositionSizeForFrame(rootScrollFrame)) :
           dirty.Intersect(nsRect(nsPoint(0,0), subdocRootFrame->GetSize()));
       nsRect displayPort;
-      if (nsLayoutUtils::GetOrMaybeCreateDisplayPort(
+      if (!aBuilder->IsForEventDelivery() &&
+          nsLayoutUtils::GetOrMaybeCreateDisplayPort(
             *aBuilder, rootScrollFrame, displayportBase, &displayPort)) {
         haveDisplayPort = true;
         dirty = displayPort;
       }
 
       ignoreViewportScrolling = presShell->IgnoringViewportScrolling();
       if (ignoreViewportScrolling) {
         savedIgnoreScrollFrame = aBuilder->GetIgnoreScrollFrame();
--- a/layout/generic/test/chrome.ini
+++ b/layout/generic/test/chrome.ini
@@ -7,10 +7,12 @@ support-files =
 
 [test_backspace_delete.xul]
 [test_bug348681.html]
 [test_bug469613.xul]
 [test_bug469774.xul]
 [test_bug508115.xul]
 [test_bug514732-2.xul]
 [test_bug632379.xul]
+skip-if = buildapp == 'mulet'
 [test_selection_preventDefault.html]
+skip-if = buildapp == 'mulet'
 [test_selection_underline.html]
--- a/layout/generic/test/mochitest.ini
+++ b/layout/generic/test/mochitest.ini
@@ -23,17 +23,17 @@ support-files =
 [test_bug344830.html]
 support-files = bug344830_testembed.svg
 [test_bug382429.html]
 [test_bug384527.html]
 [test_bug385751.html]
 [test_bug389630.html]
 [test_bug391747.html]
 [test_bug392746.html]
-skip-if = buildapp == 'b2g' # b2g(ctrl mouse select not working in b2g) b2g-debug(ctrl mouse select not working in b2g) b2g-desktop(ctrl mouse select not working in b2g)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' # b2g(ctrl mouse select not working in b2g) b2g-debug(ctrl mouse select not working in b2g) b2g-desktop(ctrl mouse select not working in b2g)
 [test_bug392923.html]
 [test_bug394173.html]
 [test_bug394239.html]
 [test_bug402380.html]
 [test_bug404872.html]
 [test_bug405178.html]
 [test_bug416168.html]
 [test_bug421436.html]
@@ -54,17 +54,17 @@ support-files = file_bug449653_1.html fi
 [test_bug468167.html]
 [test_bug470212.html]
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(shift mouse select not working in b2g) b2g-desktop(shift mouse select not working in b2g)
 [test_bug488417.html]
 skip-if = true # Bug 489560
 [test_bug496275.html]
 skip-if = toolkit == 'android' #CRASH_DUMP
 [test_bug503813.html]
-skip-if = toolkit == 'android' #CRASH_DUMP
+skip-if = buildapp == 'mulet' || toolkit == 'android' #CRASH_DUMP
 [test_bug507902.html]
 skip-if = true # Bug 510001
 [test_bug514732.html]
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || toolkit == 'android' #CRASH_DUMP # b2g-debug(times out, also on Android) b2g-desktop(times out, also on Android)
 support-files = file_bug514732_1.html file_bug514732_helper.html
 [test_bug527306.html]
 [test_bug579767.html]
 support-files = file_bug579767_1.html file_bug579767_2.html
@@ -93,17 +93,17 @@ skip-if = buildapp == 'b2g' # b2g(Target
 [test_bug904810.html]
 [test_bug938772.html]
 [test_bug970363.html]
 [test_contained_plugin_transplant.html]
 skip-if = os=='win' || e10s
 [test_image_selection.html]
 [test_image_selection_2.html]
 [test_invalidate_during_plugin_paint.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(plugins not supported) b2g-debug(plugins not supported) b2g-desktop(plugins not supported)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(plugins not supported) b2g-debug(plugins not supported) b2g-desktop(plugins not supported)
 [test_movement_by_characters.html]
 [test_movement_by_words.html]
 # Disable the caret movement by word test on Linux because the shortcut keys
 # are defined in system level.  So, it depends on the environment.
 # Disable on Windows for too many intermittent failures (bug 916143).
 skip-if = (toolkit == "gtk2") || (toolkit == "gtk3") || (os == "win")
 [test_overflow_event.html]
 [test_page_scroll_with_fixed_pos.html]
@@ -113,20 +113,20 @@ support-files = page_scroll_with_fixed_p
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || e10s #Bug 931116, b2g desktop specific, initial triage
 [test_plugin_clipping2.xhtml]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || e10s #Bug 931116, b2g desktop specific, initial triage
 [test_plugin_clipping_transformed.xhtml]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || e10s #Bug 931116, b2g desktop specific, initial triage
 [test_plugin_clipping_table.xhtml]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || e10s #Bug 931116, b2g desktop specific, initial triage
 [test_plugin_focus.html]
-skip-if = buildapp == 'b2g' || e10s # b2g(plugins not supported) b2g-debug(plugins not supported) b2g-desktop(plugins not supported)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || e10s # b2g(plugins not supported) b2g-debug(plugins not supported) b2g-desktop(plugins not supported)
 [test_plugin_mouse_coords.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(plugins not supported) b2g-debug(plugins not supported) b2g-desktop(plugins not supported)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(plugins not supported) b2g-debug(plugins not supported) b2g-desktop(plugins not supported)
 [test_plugin_position.xhtml]
 skip-if = e10s
 [test_selection_expanding.html]
-skip-if = buildapp == 'b2g' # b2g(mouse selection not working) b2g-debug(mouse selection not working) b2g-desktop(mouse selection not working)
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' # b2g(mouse selection not working) b2g-debug(mouse selection not working) b2g-desktop(mouse selection not working)
 support-files = selection_expanding_xbl.xml
 [test_selection_splitText-normalize.html]
 [test_selection_touchevents.html]
 [test_taintedfilters.html]
 support-files = file_taintedfilters_feDisplacementMap-tainted-1.svg file_taintedfilters_feDisplacementMap-tainted-2.svg file_taintedfilters_feDisplacementMap-tainted-3.svg file_taintedfilters_feDisplacementMap-tainted-ref.svg file_taintedfilters_feDisplacementMap-untainted-ref.svg file_taintedfilters_feDisplacementMap-untainted-1.svg file_taintedfilters_feDisplacementMap-untainted-2.svg file_taintedfilters_red-flood-for-feImage-cors.svg file_taintedfilters_red-flood-for-feImage-cors.svg^headers^ file_taintedfilters_red-flood-for-feImage.svg
--- a/layout/reftests/svg/filters/svg-filter-chains/reftest.list
+++ b/layout/reftests/svg/filters/svg-filter-chains/reftest.list
@@ -4,10 +4,11 @@
 default-preferences pref(layout.css.filters.enabled,true)
 
 == clip-input.svg clip-input-ref.svg
 == clip-output.svg clip-output.svg
 == default-subregion.svg default-subregion-ref.svg
 == intersecting-filter-regions.svg intersecting-filter-regions-ref.svg
 == long-chain.svg simple-chain-ref.svg
 == multiple-primitives-per-filter.svg simple-chain-ref.svg
+== second-filter-uses-SourceAlpha.svg second-filter-uses-SourceAlpha.svg
 == second-filter-uses-SourceGraphic.svg simple-chain-ref.svg
 == simple-chain.svg simple-chain-ref.svg
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/filters/svg-filter-chains/second-filter-uses-SourceAlpha-ref.svg
@@ -0,0 +1,29 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<svg id="svg-root"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink">
+
+  <g id="testmeta">
+    <title>SVG Filter Chains: Second Filter Uses SourceAlpha</title>
+    <link rel="copyright"
+          href="http://www.w3.org/Graphics/SVG/Test/Copyright"/>
+    <link rel="license"
+          href="http://www.w3.org/Consortium/Legal/2008/03-bsd-license.html"/>
+    <link rel="author"
+          title="Max Vujovic"
+          href="mailto:mvujovic@adobe.com"/>
+    <link rel="help"
+          href="http://dev.w3.org/fxtf/filters/#FilterPrimitiveSubRegion"/>
+    <metadata class="flags">namespace svg</metadata>
+  </g>
+
+  <g id="test-body-content">
+    <filter id="blur">
+      <feGaussianBlur stdDeviation="3"/>
+    </filter>
+    <rect x="100" y="100" width="100" height="100" filter="url(#blur)" fill="#00ff00"/>
+  </g>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/filters/svg-filter-chains/second-filter-uses-SourceAlpha.svg
@@ -0,0 +1,49 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<svg id="svg-root"
+  xmlns="http://www.w3.org/2000/svg"
+  xmlns:xlink="http://www.w3.org/1999/xlink">
+
+  <g id="testmeta">
+    <title>SVG Filter Chains: Second Filter Uses SourceAlpha</title>
+    <link rel="copyright"
+          href="http://www.w3.org/Graphics/SVG/Test/Copyright"/>
+    <link rel="license"
+          href="http://www.w3.org/Consortium/Legal/2008/03-bsd-license.html"/>
+    <link rel="author"
+          title="Max Vujovic"
+          href="mailto:mvujovic@adobe.com"/>
+    <link rel="help"
+          href="http://dev.w3.org/fxtf/filters/#FilterPrimitiveSubRegion"/>
+    <link rel="match"
+          href="second-filter-uses-SourceAlpha.svg" />
+    <metadata class="flags">namespace svg</metadata>
+    <desc class="assert">
+      In an SVG filter chain, this test verifies that a filter receives the
+      correct SourceAlpha input from the previous filter in the chain. If the
+      test passes, you should see a blurred green square.
+    </desc>
+  </g>
+
+  <g id="test-body-content">
+    <filter id="blur">
+      <feGaussianBlur stdDeviation="3"/>
+    </filter>
+    <filter id="add-green">
+      <!--
+        This filter receives transparent black and the alpha channel of the
+        previous blur filter. Then, it adds to the green channel where the alpha
+        channel is set, resulting in a blurred green square.
+      -->
+      <feComponentTransfer in="SourceAlpha">
+        <feFuncR type="identity"/>
+        <feFuncG type="table" tableValues="1 1"/>
+        <feFuncB type="identity"/>
+        <feFuncA type="identity"/>
+      </feComponentTransfer>
+    </filter>
+    <rect x="100" y="100" width="100" height="100" filter="url(#blur) url(#add-green)" fill="red"/>
+  </g>
+</svg>
--- a/layout/style/AnimationCommon.cpp
+++ b/layout/style/AnimationCommon.cpp
@@ -430,18 +430,18 @@ double
 ElementAnimation::CurrentTime() const
 {
   // In Web Animations, AnimationPlayers have a *current* time and Animations
   // have a *local* time. However, since we have a 1:1 correspondence between
   // AnimationPlayers and Animations, and since the startTime of *Animations*
   // (but not AnimationPlayers) is always 0, these are currently identical.
   Nullable<TimeDuration> currentTime = GetLocalTime();
 
-  // The current time is currently only going to be null when don't have a
-  // refresh driver (e.g. because we are in a display:none iframe).
+  // The current time is only going to be null when we don't have a refresh
+  // driver or navigation timing object and never did.
   //
   // Web Animations says that in this case we should use a timeline time of
   // 0 (the "effective timeline time") and calculate the current time from that.
   // Doing that, however, requires storing the start time as an offset rather
   // than a timestamp so for now we just return 0.
   //
   // FIXME: Store player start time and pause start as offsets rather than
   // timestamps and return the appropriate current time when the timeline time
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -1171,17 +1171,17 @@ nsStyleSet::WalkRuleProcessors(nsIStyleR
   (*aFunc)(mRuleProcessors[eAnimationSheet], aData);
   (*aFunc)(mRuleProcessors[eTransitionSheet], aData);
 }
 
 static void
 InitStyleScopes(TreeMatchContext& aTreeContext, Element* aElement)
 {
   if (aElement->IsElementInStyleScope()) {
-    aTreeContext.InitStyleScopes(aElement->GetParentElement());
+    aTreeContext.InitStyleScopes(aElement->GetParentElementCrossingShadowRoot());
   }
 }
 
 already_AddRefed<nsStyleContext>
 nsStyleSet::ResolveStyleFor(Element* aElement,
                             nsStyleContext* aParentContext)
 {
   TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
--- a/layout/style/test/chrome/chrome.ini
+++ b/layout/style/test/chrome/chrome.ini
@@ -5,9 +5,10 @@ support-files =
   bug535806-xul.xul
   hover_helper.html
 
 [test_addSheet.html]
 [test_additional_sheets.html]
 [test_author_specified_style.html]
 [test_bug535806.xul]
 [test_hover.html]
+skip-if = buildapp == 'mulet'
 [test_moz_document_rules.html]
--- a/layout/svg/nsSVGFilterInstance.cpp
+++ b/layout/svg/nsSVGFilterInstance.cpp
@@ -29,16 +29,17 @@ nsSVGFilterInstance::nsSVGFilterInstance
                                          const gfxRect& aTargetBBox,
                                          const gfxSize& aUserSpaceToFilterSpaceScale,
                                          const gfxSize& aFilterSpaceToUserSpaceScale) :
   mFilter(aFilter),
   mTargetFrame(aTargetFrame),
   mTargetBBox(aTargetBBox),
   mUserSpaceToFilterSpaceScale(aUserSpaceToFilterSpaceScale),
   mFilterSpaceToUserSpaceScale(aFilterSpaceToUserSpaceScale),
+  mSourceAlphaAvailable(false),
   mInitialized(false) {
 
   // Get the filter frame.
   mFilterFrame = GetFilterFrame();
   if (!mFilterFrame) {
     return;
   }
 
@@ -283,34 +284,71 @@ static int32_t
 GetLastResultIndex(const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs)
 {
   uint32_t numPrimitiveDescrs = aPrimitiveDescrs.Length();
   return !numPrimitiveDescrs ?
     FilterPrimitiveDescription::kPrimitiveIndexSourceGraphic :
     numPrimitiveDescrs - 1;
 }
 
+int32_t
+nsSVGFilterInstance::GetOrCreateSourceAlphaIndex(nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs)
+{
+  // If the SourceAlpha index has already been determined or created for this
+  // SVG filter, just return it.
+  if (mSourceAlphaAvailable)
+    return mSourceAlphaIndex;
+
+  // If this is the first filter in the chain, we can just use the
+  // kPrimitiveIndexSourceAlpha keyword to refer to the SourceAlpha of the
+  // original image.
+  if (mSourceGraphicIndex < 0) {
+    mSourceAlphaIndex = FilterPrimitiveDescription::kPrimitiveIndexSourceAlpha;
+    mSourceAlphaAvailable = true;
+    return mSourceAlphaIndex;
+  }
+
+  // Otherwise, create a primitive description to turn the previous filter's
+  // output into a SourceAlpha input.
+  FilterPrimitiveDescription descr(PrimitiveType::ToAlpha);
+  descr.SetInputPrimitive(0, mSourceGraphicIndex);
+
+  const FilterPrimitiveDescription& sourcePrimitiveDescr =
+    aPrimitiveDescrs[mSourceGraphicIndex];
+  descr.SetPrimitiveSubregion(sourcePrimitiveDescr.PrimitiveSubregion());
+  descr.SetIsTainted(sourcePrimitiveDescr.IsTainted());
+
+  ColorSpace colorSpace = sourcePrimitiveDescr.OutputColorSpace();
+  descr.SetInputColorSpace(0, colorSpace);
+  descr.SetOutputColorSpace(colorSpace);
+
+  aPrimitiveDescrs.AppendElement(descr);
+  mSourceAlphaIndex = aPrimitiveDescrs.Length() - 1;
+  mSourceAlphaAvailable = true;
+  return mSourceAlphaIndex;
+}
+
 nsresult
 nsSVGFilterInstance::GetSourceIndices(nsSVGFE* aPrimitiveElement,
-                                      const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs,
+                                      nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs,
                                       const nsDataHashtable<nsStringHashKey, int32_t>& aImageTable,
                                       nsTArray<int32_t>& aSourceIndices)
 {
   nsAutoTArray<nsSVGStringInfo,2> sources;
   aPrimitiveElement->GetSourceImageNames(sources);
 
   for (uint32_t j = 0; j < sources.Length(); j++) {
     nsAutoString str;
     sources[j].mString->GetAnimValue(str, sources[j].mElement);
 
     int32_t sourceIndex = 0;
     if (str.EqualsLiteral("SourceGraphic")) {
       sourceIndex = mSourceGraphicIndex;
     } else if (str.EqualsLiteral("SourceAlpha")) {
-      sourceIndex = FilterPrimitiveDescription::kPrimitiveIndexSourceAlpha;
+      sourceIndex = GetOrCreateSourceAlphaIndex(aPrimitiveDescrs);
     } else if (str.EqualsLiteral("FillPaint")) {
       sourceIndex = FilterPrimitiveDescription::kPrimitiveIndexFillPaint;
     } else if (str.EqualsLiteral("StrokePaint")) {
       sourceIndex = FilterPrimitiveDescription::kPrimitiveIndexStrokePaint;
     } else if (str.EqualsLiteral("BackgroundImage") ||
                str.EqualsLiteral("BackgroundAlpha")) {
       return NS_ERROR_NOT_IMPLEMENTED;
     } else if (str.EqualsLiteral("")) {
--- a/layout/svg/nsSVGFilterInstance.h
+++ b/layout/svg/nsSVGFilterInstance.h
@@ -169,24 +169,34 @@ private:
   /**
    * Returns the transform from frame space to the coordinate space that
    * GetCanvasTM transforms to. "Frame space" is the origin of a frame, aka the
    * top-left corner of its border box, aka the top left corner of its mRect.
    */
   gfxMatrix GetUserSpaceToFrameSpaceInCSSPxTransform() const;
 
   /**
+   * Appends a new FilterPrimitiveDescription to aPrimitiveDescrs that
+   * converts the FilterPrimitiveDescription at mSourceGraphicIndex into
+   * a SourceAlpha input for the next FilterPrimitiveDescription.
+   *
+   * The new FilterPrimitiveDescription zeros out the SourceGraphic's RGB
+   * channels and keeps the alpha channel intact.
+   */
+  int32_t GetOrCreateSourceAlphaIndex(nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs);
+
+  /**
    * Finds the index in aPrimitiveDescrs of each input to aPrimitiveElement.
    * For example, if aPrimitiveElement is:
    *   <feGaussianBlur in="another-primitive" .../>
    * Then, the resulting aSourceIndices will contain the index of the
    * FilterPrimitiveDescription representing "another-primitive".
    */
   nsresult GetSourceIndices(nsSVGFE* aPrimitiveElement,
-                            const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs,
+                            nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs,
                             const nsDataHashtable<nsStringHashKey, int32_t>& aImageTable,
                             nsTArray<int32_t>& aSourceIndices);
 
   /**
    * Compute the filter region in user space, filter space, and filter
    * space.
    */
   nsresult ComputeBounds();
@@ -235,12 +245,24 @@ private:
 
   /**
    * The index of the FilterPrimitiveDescription that this SVG filter should use
    * as its SourceGraphic, or the SourceGraphic keyword index if this is the
    * first filter in a chain.
    */
   int32_t mSourceGraphicIndex;
 
+  /**
+   * The index of the FilterPrimitiveDescription that this SVG filter should use
+   * as its SourceAlpha, or the SourceAlpha keyword index if this is the first
+   * filter in a chain.
+   */
+  int32_t mSourceAlphaIndex;
+
+  /**
+   * SourceAlpha is available if GetOrCreateSourceAlphaIndex has been called.
+   */
+  int32_t mSourceAlphaAvailable;
+
   bool                    mInitialized;
 };
 
 #endif
--- a/layout/xul/test/chrome.ini
+++ b/layout/xul/test/chrome.ini
@@ -1,18 +1,21 @@
 [DEFAULT]
 support-files =
   window_resizer.xul
   window_resizer_element.xul
 
 [test_bug159346.xul]
+skip-if = buildapp == 'mulet'
 [test_bug372685.xul]
 [test_bug381167.xhtml]
 [test_bug393970.xul]
 [test_bug398982-1.xul]
 [test_bug398982-2.xul]
 [test_bug467442.xul]
 [test_bug477754.xul]
 [test_bug703150.xul]
+skip-if = buildapp == 'mulet'
 [test_popupSizeTo.xul]
 [test_resizer.xul]
 [test_stack.xul]
 [test_windowminmaxsize.xul]
+skip-if = buildapp == 'mulet'
--- a/layout/xul/test/mochitest.ini
+++ b/layout/xul/test/mochitest.ini
@@ -1,10 +1,10 @@
 [DEFAULT]
-skip-if = buildapp == 'b2g'
+skip-if = buildapp == 'mulet' || buildapp == 'b2g'
 
 [test_bug386386.html]
 [test_bug394800.xhtml]
 [test_bug511075.html]
 skip-if = toolkit == 'android' #bug 798806
 [test_bug563416.html]
 [test_resizer_incontent.xul]
 [test_splitter.xul]
--- a/media/libspeex_resampler/AUTHORS
+++ b/media/libspeex_resampler/AUTHORS
@@ -1,5 +1,18 @@
-Gregory Maxwell (greg@xiph.org)
-Jean-Marc Valin - Original opusdec implementation / Resampler
-Thorvald Natvig - Resampler
-Michael Smith   - Ogginfo (basis of opusinfo)
-John Edwards    - Windows audio output
+Jean-Marc Valin <jean-marc.valin@usherbrooke.ca>
+   All the code except the following
+
+David Rowe <david@rowetel.com>
+   lsp.c lsp.h 
+   Also ideas and feedback
+
+John Francis Edwards
+   wave_out.[ch], some #ifdefs for windows port and MSVC project files
+
+Segher Boessenkool
+   Misc. optimizations (for QMF in particular)
+
+Atsuhiko Yamanaka <ymnk@jcraft.com>:
+   Patch to speexenc.c to add Vorbis comment format
+
+Radim Kolar <hsn@cybermail.net>:
+   Patch to speexenc.c for supporting more input formats
--- a/media/libspeex_resampler/COPYING
+++ b/media/libspeex_resampler/COPYING
@@ -1,371 +1,35 @@
-
-Opus-tools, with the exception of opusinfo.[ch] is available under
-the following two clause BSD-style license: