Merge m-c to s-c.
authorRichard Newman <rnewman@mozilla.com>
Wed, 03 Oct 2012 23:43:39 -0700
changeset 111105 baffb4084bbddc5bf15ad67385a6a8fc522b7099
parent 111104 8d1ffa2548af2bb99e74add6c78297610edf4cd0 (current diff)
parent 109252 0a095af171f4fa1fa6509727e0f9daaf15d5ba88 (diff)
child 111106 7e9d2d39d6ede5f14c7f9773e5df39fbc672fa2c
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
milestone18.0a1
Merge m-c to s-c.
build/valgrind/x86_64-redhat-linux-gnu.sup
dom/apps/src/PermissionsTable.jsm
dom/encoding/test/test-big5.js
dom/encoding/test/test-euc-jp.js
dom/encoding/test/test-euc-kr.js
dom/encoding/test/test-gbk.js
dom/encoding/test/test-hz-gb-2312.js
dom/encoding/test/test-iso-2022-jp.js
dom/encoding/test/test-iso-2022-kr.js
dom/encoding/test/test-shift_jis.js
dom/encoding/test/tests.js
--- a/accessible/src/msaa/Makefile.in
+++ b/accessible/src/msaa/Makefile.in
@@ -47,30 +47,31 @@ ifdef MOZ_XUL
 CPPSRCS += \
   XULListboxAccessibleWrap.cpp \
   XULMenuAccessibleWrap.cpp \
   XULTreeGridAccessibleWrap.cpp \
   $(NULL)
 endif
 
 EXPORTS = \
-  				CAccessibleValue.h \
-  				ia2AccessibleAction.h \
-  				ia2AccessibleComponent.h \
-  				ia2AccessibleEditableText.h \
-  				ia2AccessibleHyperlink.h \
-  				ia2AccessibleHypertext.h \
-  				ia2AccessibleText.h \
+  CAccessibleValue.h \
+  ia2AccessibleAction.h \
+  ia2AccessibleComponent.h \
+  ia2AccessibleEditableText.h \
+  ia2AccessibleHyperlink.h \
+  ia2AccessibleHypertext.h \
+  ia2AccessibleText.h \
   nsAccessNodeWrap.h \
   $(NULL)
 
 EXPORTS_NAMESPACES = mozilla/a11y \
 
 EXPORTS_mozilla/a11y = \
   AccessibleWrap.h \
+  Compatibility.h \
   HyperTextAccessibleWrap.h \
   $(null)
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
--- a/accessible/tests/mochitest/events/test_docload.xul
+++ b/accessible/tests/mochitest/events/test_docload.xul
@@ -106,17 +106,18 @@
       this.unexpectedEventSeq = [
         new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, getNestedDoc),
         new invokerChecker(EVENT_STATE_CHANGE, getNestedDoc)
       ];
 
       function getNestedDoc()
       {
         var iframeNodes = currentTabDocument().getElementsByTagName("iframe");
-        return iframeNodes ? iframeNodes[0].firstChild : null;
+        return iframeNodes && iframeNodes.length > 0 ?
+          iframeNodes[0].firstChild : null;
       }
     }
 
     /**
      * Reload the page by F5 (isFromUserInput flag is true).
      */
     function userReloadInvoker()
     {
--- a/accessible/tests/mochitest/treeupdate/Makefile.in
+++ b/accessible/tests/mochitest/treeupdate/Makefile.in
@@ -15,17 +15,17 @@ MOCHITEST_A11Y_FILES =\
 		test_ariadialog.html \
 		test_canvas.html \
 		test_colorpicker.xul \
 		test_cssoverflow.html \
 		test_contextmenu.xul \
 		test_doc.html \
 		test_gencontent.html \
 		test_hidden.html \
-		test_imagemap.html \
+		$(warning test_imagemap.html temporarily disabled because of very frequent oranges, see bug 745788) \
 		test_list_editabledoc.html \
 		test_list.html \
 		test_listbox.xul \
 		test_menu.xul \
 		test_menubutton.xul \
 		test_recreation.html \
 		test_select.html \
 		test_textleaf.html \
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -382,16 +382,17 @@ pref("browser.link.open_newwindow.restri
 pref("dom.mozBrowserFramesEnabled", true);
 
 pref("dom.ipc.tabs.disabled", false);
 
 pref("dom.ipc.browser_frames.oop_by_default", false);
 
 // Temporary permission hack for WebSMS
 pref("dom.sms.enabled", true);
+pref("dom.sms.strict7BitEncoding", false); // Disabled by default.
 
 // Temporary permission hack for WebContacts
 pref("dom.mozContacts.enabled", true);
 
 // WebAlarms
 pref("dom.mozAlarms.enabled", true);
 
 // WebSettings
@@ -445,18 +446,18 @@ pref("marionette.defaultPrefs.port", 282
 #endif
 
 #ifdef MOZ_UPDATER
 // When we're applying updates, we can't let anything hang us on
 // quit+restart.  The user has no recourse.
 pref("shutdown.watchdog.timeoutSecs", 5);
 // Timeout before the update prompt automatically installs the update
 pref("b2g.update.apply-prompt-timeout", 60000); // milliseconds
-// Optional timeout the user can wait before getting another update prompt
-pref("b2g.update.apply-wait-timeout", 1800000); // milliseconds
+// Amount of time to wait after the user is idle before prompting to apply an update
+pref("b2g.update.apply-idle-timeout", 600000); // milliseconds
 // Amount of time the updater waits for the process to exit cleanly before
 // forcefully exiting the process
 pref("b2g.update.self-destruct-timeout", 5000); // milliseconds
 
 pref("app.update.enabled", true);
 pref("app.update.auto", false);
 pref("app.update.silent", false);
 pref("app.update.mode", 0);
@@ -538,19 +539,19 @@ pref("hal.processPriorityManager.gonk.fo
 pref("hal.processPriorityManager.gonk.backgroundOomScoreAdjust", 400);
 pref("hal.processPriorityManager.gonk.masterNice", -1);
 pref("hal.processPriorityManager.gonk.foregroundNice", 0);
 pref("hal.processPriorityManager.gonk.backgroundNice", 10);
 
 #ifndef DEBUG
 // Enable pre-launching content processes for improved startup time
 // (hiding latency).
-pref("dom.ipc.processPrelauch.enabled", true);
+pref("dom.ipc.processPrelaunch.enabled", true);
 // Wait this long before pre-launching a new subprocess.
-pref("dom.ipc.processPrelauch.delayMs", 1000);
+pref("dom.ipc.processPrelaunch.delayMs", 1000);
 #endif
 
 // Ignore the "dialog=1" feature in window.open.
 pref("dom.disable_window_open_dialog_feature", true);
 
 // Screen reader support
 pref("accessibility.accessfu.activate", 2);
 
@@ -570,8 +571,12 @@ pref("ui.mouse.radius.bottommm", 2);
 // Disable native prompt
 pref("browser.prompt.allowNative", false);
 
 // Minimum delay in milliseconds between network activity notifications (0 means
 // no notifications). The delay is the same for both download and upload, though
 // they are handled separately. This pref is only read once at startup:
 // a restart is required to enable a new value.
 pref("network.activity.blipIntervalMilliseconds", 250);
+
+// Send some sites a custom user-agent.
+pref("general.useragent.override.facebook.com", "\(Mobile#(Android; Mobile");
+pref("general.useragent.override.youtube.com", "\(Mobile#(Android; Mobile");
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -18,16 +18,18 @@ Cu.import('resource://gre/modules/DOMFMR
 #endif
 Cu.import('resource://gre/modules/AlarmService.jsm');
 Cu.import('resource://gre/modules/ActivitiesService.jsm');
 Cu.import('resource://gre/modules/PermissionPromptHelper.jsm');
 Cu.import('resource://gre/modules/PermissionSettings.jsm');
 Cu.import('resource://gre/modules/ObjectWrapper.jsm');
 Cu.import('resource://gre/modules/accessibility/AccessFu.jsm');
 Cu.import('resource://gre/modules/Payment.jsm');
+Cu.import("resource://gre/modules/AppsUtils.jsm");
+Cu.import('resource://gre/modules/UserAgentOverrides.jsm');
 
 XPCOMUtils.defineLazyServiceGetter(Services, 'env',
                                    '@mozilla.org/process/environment;1',
                                    'nsIEnvironment');
 
 XPCOMUtils.defineLazyServiceGetter(Services, 'ss',
                                    '@mozilla.org/content/style-sheet-service;1',
                                    'nsIStyleSheetService');
@@ -172,16 +174,17 @@ var shell = {
       Services.audioManager.masterVolume = 0.5;
     } catch(e) {
       dump('Error setting master volume: ' + e + '\n');
     }
 
     CustomEventManager.init();
     WebappsHelper.init();
     AccessFu.attach(window);
+    UserAgentOverrides.init();
 
     // XXX could factor out into a settings->pref map.  Not worth it yet.
     SettingsListener.observe("debug.fps.enabled", false, function(value) {
       Services.prefs.setBoolPref("layers.acceleration.draw-fps", value);
     });
     SettingsListener.observe("debug.paint-flashing.enabled", false, function(value) {
       Services.prefs.setBoolPref("nglayout.debug.paint_flashing", value);
     });
@@ -207,16 +210,17 @@ var shell = {
     if (this.timer) {
       this.timer.cancel();
       this.timer = null;
     }
 
 #ifndef MOZ_WIDGET_GONK
     delete Services.audioManager;
 #endif
+    UserAgentOverrides.uninit();
   },
 
   // If this key event actually represents a hardware button, filter it here
   // and send a mozChromeEvent with detail.type set to xxx-button-press or
   // xxx-button-release instead.
   filterHardwareKeys: function shell_filterHardwareKeys(evt) {
     var type;
     switch (evt.keyCode) {
@@ -646,17 +650,17 @@ var WebappsHelper = {
     json.mm = subject;
 
     switch(topic) {
       case "webapps-launch":
         DOMApplicationRegistry.getManifestFor(json.origin, function(aManifest) {
           if (!aManifest)
             return;
 
-          let manifest = new DOMApplicationManifest(aManifest, json.origin);
+          let manifest = new ManifestHelper(aManifest, json.origin);
           shell.sendChromeEvent({
             "type": "webapps-launch",
             "url": manifest.fullLaunchPath(json.startPoint),
             "manifestURL": json.manifestURL
           });
         });
         break;
       case "webapps-ask-install":
--- a/b2g/components/ContentPermissionPrompt.js
+++ b/b2g/components/ContentPermissionPrompt.js
@@ -5,16 +5,17 @@
 const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cu = Components.utils;
 const Cc = Components.classes;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Webapps.jsm");
+Cu.import("resource://gre/modules/AppsUtils.jsm");
 
 function ContentPermissionPrompt() {}
 
 ContentPermissionPrompt.prototype = {
 
   handleExistingPermission: function handleExistingPermission(request) {
     let result = Services.perms.testExactPermissionFromPrincipal(request.principal, request.type);
     if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
@@ -67,17 +68,17 @@ ContentPermissionPrompt.prototype = {
     if (!isApp) {
       browser.shell.sendChromeEvent(details);
       return;
     }
 
     // When it's an app, get the manifest to add the l10n application name.
     let app = DOMApplicationRegistry.getAppByLocalId(principal.appId);
     DOMApplicationRegistry.getManifestFor(app.origin, function getManifest(aManifest) {
-      let helper = new DOMApplicationManifest(aManifest, app.origin);
+      let helper = new ManifestHelper(aManifest, app.origin);
       details.appName = helper.name;
       browser.shell.sendChromeEvent(details);
     });
   },
 
   classID: Components.ID("{8c719f03-afe0-4aac-91ff-6c215895d467}"),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt])
--- a/b2g/components/UpdatePrompt.js
+++ b/b2g/components/UpdatePrompt.js
@@ -15,36 +15,43 @@ Cu.import("resource://gre/modules/Servic
 const VERBOSE = 1;
 let log =
   VERBOSE ?
   function log_dump(msg) { dump("UpdatePrompt: "+ msg +"\n"); } :
   function log_noop(msg) { };
 
 const APPLY_PROMPT_TIMEOUT =
       Services.prefs.getIntPref("b2g.update.apply-prompt-timeout");
-const APPLY_WAIT_TIMEOUT =
-      Services.prefs.getIntPref("b2g.update.apply-wait-timeout");
+const APPLY_IDLE_TIMEOUT =
+      Services.prefs.getIntPref("b2g.update.apply-idle-timeout");
 const SELF_DESTRUCT_TIMEOUT =
       Services.prefs.getIntPref("b2g.update.self-destruct-timeout");
 
+const APPLY_IDLE_TIMEOUT_SECONDS = APPLY_IDLE_TIMEOUT / 1000;
+
+
 XPCOMUtils.defineLazyServiceGetter(Services, "aus",
                                    "@mozilla.org/updates/update-service;1",
                                    "nsIApplicationUpdateService");
 
+XPCOMUtils.defineLazyServiceGetter(Services, "idle",
+                                   "@mozilla.org/widget/idleservice;1",
+                                   "nsIIdleService");
 function UpdatePrompt() { }
 
 UpdatePrompt.prototype = {
   classID: Components.ID("{88b3eb21-d072-4e3b-886d-f89d8c49fe59}"),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIUpdatePrompt,
                                          Ci.nsIRequestObserver,
-                                         Ci.nsIProgressEventSink]),
+                                         Ci.nsIProgressEventSink,
+                                         Ci.nsIObserver]),
 
   _update: null,
   _applyPromptTimer: null,
-  _applyWaitTimer: null,
+  _waitingForIdle: false,
 
   // nsIUpdatePrompt
 
   // FIXME/bug 737601: we should have users opt-in to downloading
   // updates when on a billed pipe.  Initially, opt-in for 3g, but
   // that doesn't cover all cases.
   checkForUpdates: function UP_checkForUpdates() { },
 
@@ -53,37 +60,70 @@ UpdatePrompt.prototype = {
                              this.handleAvailableResult)) {
 
       log("Unable to prompt for available update, forcing download");
       this.downloadUpdate(aUpdate);
     }
   },
 
   showUpdateDownloaded: function UP_showUpdateDownloaded(aUpdate, aBackground) {
-    if (!this.sendUpdateEvent("update-downloaded", aUpdate,
-                             this.handleDownloadedResult)) {
-      log("Unable to prompt, forcing restart");
-      this.restartProcess();
+    // The update has been downloaded and staged. We send the update-downloaded
+    // event right away. After the user has been idle for a while, we send the
+    // update-prompt-restart event, increasing the chances that we can apply the
+    // update quietly without user intervention.
+    this.sendUpdateEvent("update-downloaded", aUpdate);
+
+    if (Services.idle.idleTime >= APPLY_IDLE_TIMEOUT) {
+      this.showApplyPrompt(aUpdate);
       return;
     }
 
-    // Schedule a fallback timeout in case the UI is unable to respond or show
-    // a prompt for some reason
-    this._applyPromptTimer = this.createTimer(APPLY_PROMPT_TIMEOUT);
+    // We haven't been idle long enough, so register an observer
+    log("Update is ready to apply, registering idle timeout of " +
+        APPLY_IDLE_TIMEOUT_SECONDS + " seconds before prompting.");
+
+    this._update = aUpdate;
+    this.waitForIdle();
   },
 
   showUpdateError: function UP_showUpdateError(aUpdate) {
     if (aUpdate.state == "failed") {
       log("Failed to download update, errorCode: " + aUpdate.errorCode);
     }
   },
 
   showUpdateHistory: function UP_showUpdateHistory(aParent) { },
   showUpdateInstalled: function UP_showUpdateInstalled() { },
 
+  // Custom functions
+
+  waitForIdle: function UP_waitForIdle() {
+    if (this._waitingForIdle) {
+      return;
+    }
+
+    this._waitingForIdle = true;
+    Services.idle.addIdleObserver(this, APPLY_IDLE_TIMEOUT_SECONDS);
+    Services.obs.addObserver(this, "quit-application", false);
+  },
+
+
+  showApplyPrompt: function UP_showApplyPrompt(aUpdate) {
+    if (!this.sendUpdateEvent("update-prompt-apply", aUpdate,
+                             this.handleApplyPromptResult)) {
+      log("Unable to prompt, forcing restart");
+      this.restartProcess();
+      return;
+    }
+
+    // Schedule a fallback timeout in case the UI is unable to respond or show
+    // a prompt for some reason.
+    this._applyPromptTimer = this.createTimer(APPLY_PROMPT_TIMEOUT);
+  },
+
   sendUpdateEvent: function UP_sendUpdateEvent(aType, aUpdate, aCallback) {
     let detail = {
       displayVersion: aUpdate.displayVersion,
       detailsURL: aUpdate.detailsURL
     };
 
     let patch = aUpdate.selectedPatch;
     if (!patch) {
@@ -150,27 +190,26 @@ UpdatePrompt.prototype = {
     // showUpdateAvailable again after a certain period of time
     switch (aDetail.result) {
       case "download":
         this.downloadUpdate(this._update);
         break;
     }
   },
 
-  handleDownloadedResult: function UP_handleDownloadedResult(aDetail) {
+  handleApplyPromptResult: function UP_handleApplyPromptResult(aDetail) {
     if (this._applyPromptTimer) {
       this._applyPromptTimer.cancel();
       this._applyPromptTimer = null;
     }
 
     switch (aDetail.result) {
       case "wait":
-        // Wait for a fixed period of time, allowing the user to temporarily
-        // postpone applying an update
-        this._applyWaitTimer = this.createTimer(APPLY_WAIT_TIMEOUT);
+        // Wait until the user is idle before prompting to apply the update
+        this.waitForIdle();
         break;
       case "restart":
         this.finishUpdate();
         break;
     }
   },
 
   downloadUpdate: function UP_downloadUpdate(aUpdate) {
@@ -204,51 +243,62 @@ UpdatePrompt.prototype = {
     }
 
     this.finishOSUpdate(updateFile.path);
   },
 
   restartProcess: function UP_restartProcess() {
     log("Update downloaded, restarting to apply it");
 
+#ifndef MOZ_WIDGET_GONK
     let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"]
-                       .getService(Ci.nsIAppStartup);
-    // NB: on Gonk, we rely on the system process manager to restart
-    // us.  Trying to restart here would conflict with the process
-    // manager.  We should be using a runtime check to detect Gonk
-    // instead of this gross ifdef, but the ifdef works for now.
-    appStartup.quit(appStartup.eForceQuit
-#ifndef ANDROID
-                    | appStartup.eRestart
+                     .getService(Ci.nsIAppStartup);
+    appStartup.quit(appStartup.eForceQuit | appStartup.eRestart);
+#else
+    // NB: on Gonk, we rely on the system process manager to restart us.
+    let pmService = Cc["@mozilla.org/power/powermanagerservice;1"]
+                    .getService(Ci.nsIPowerManagerService);
+    pmService.restart();
 #endif
-      );
   },
 
   finishOSUpdate: function UP_finishOSUpdate(aOsUpdatePath) {
     let recoveryService = Cc["@mozilla.org/recovery-service;1"]
                             .getService(Ci.nsIRecoveryService);
 
     log("Rebooting into recovery to apply FOTA update: " + aOsUpdatePath);
 
     try {
       recoveryService.installFotaUpdate(aOsUpdatePath);
     } catch(e) {
       log("Error: Couldn't reboot into recovery to apply FOTA update " +
           aOsUpdatePath);
     }
   },
 
+  // nsIObserver
+
+  observe: function UP_observe(aSubject, aTopic, aData) {
+    switch (aTopic) {
+      case "idle":
+        this._waitingForIdle = false;
+        this.showApplyPrompt(this._update);
+        // Fall through
+      case "quit-application":
+        Services.idle.removeIdleObserver(this, APPLY_IDLE_TIMEOUT_SECONDS);
+        Services.obs.removeObserver(this, "quit-application");
+        break;
+    }
+  },
+
   notify: function UP_notify(aTimer) {
     if (aTimer == this._applyPromptTimer) {
       log("Timed out waiting for result, restarting");
       this._applyPromptTimer = null;
       this.finishUpdate();
-    } else if (aTimer == this._applyWaitTimer) {
-      this._applyWaitTimer = null;
-      this.showUpdatePrompt();
     }
   },
 
   createTimer: function UP_createTimer(aTimeoutMs) {
     let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
     timer.initWithCallback(this, aTimeoutMs, timer.TYPE_ONE_SHOT);
     return timer;
   },
--- a/b2g/config/tooltool-manifests/macosx64/releng.manifest
+++ b/b2g/config/tooltool-manifests/macosx64/releng.manifest
@@ -4,14 +4,14 @@
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 57746646,
-"digest": "e1d76c4c9d12edfba0d7c8db4cd37669d90e6824ee3d1f949dddc0f168815b115f9809a335d3ee0025432df995f898d9dc7545ee89e499944ed84e2407fc54b8",
+"size": 52539217,
+"digest": "88eb1c08043919a224da1d25b37a5b0c5719f3547ddfc1b456c577d5fa66564706b6e25853fedefaa08ca8fb1dff765d7eb747bbe99ed81c09afbfd43b222e96",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/b2g/confvars.sh
+++ b/b2g/confvars.sh
@@ -3,16 +3,18 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MOZ_APP_BASENAME=B2G
 MOZ_APP_VENDOR=Mozilla
 
 MOZ_APP_VERSION=18.0a1
 MOZ_APP_UA_NAME=Firefox
 
+MOZ_UA_OS_AGNOSTIC=1
+
 MOZ_B2G_VERSION=1.0.0
 
 MOZ_BRANDING_DIRECTORY=b2g/branding/unofficial
 MOZ_OFFICIAL_BRANDING_DIRECTORY=b2g/branding/official
 # MOZ_APP_DISPLAYNAME is set by branding/configure.sh
 
 MOZ_SAFE_BROWSING=
 MOZ_SERVICES_SYNC=1
--- a/browser/app/profile/extensions/testpilot@labs.mozilla.com/content/experiment-page.js
+++ b/browser/app/profile/extensions/testpilot@labs.mozilla.com/content/experiment-page.js
@@ -96,17 +96,17 @@ var stringBundle;
         persist.persistFlags = nsIWebBrowserPersist.
           PERSIST_FLAGS_REPLACE_EXISTING_FILES;
         persist.persistFlags |= nsIWebBrowserPersist.
           PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
 
         // displays a download dialog (remove these 3 lines for silent download)
         let xfer = Components.classes["@mozilla.org/transfer;1"].
                    createInstance(Components.interfaces.nsITransfer);
-        xfer.init(source, target, "", null, null, null, persist);
+        xfer.init(source, target, "", null, null, null, persist, false);
         persist.progressListener = xfer;
 
         // save the canvas data to the file
         persist.saveURI(source, null, null, null, null, file);
       }
     };
 
     fp.init(window, null, nsIFilePicker.modeSave);
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1024,17 +1024,17 @@ pref("devtools.layoutview.open", false);
 pref("devtools.responsiveUI.enabled", true);
 
 // Enable the Debugger
 pref("devtools.debugger.enabled", true);
 pref("devtools.debugger.chrome-enabled", false);
 pref("devtools.debugger.remote-host", "localhost");
 pref("devtools.debugger.remote-autoconnect", false);
 pref("devtools.debugger.remote-connection-retries", 3);
-pref("devtools.debugger.remote-timeout", 3000);
+pref("devtools.debugger.remote-timeout", 20000);
 
 // The default Debugger UI settings
 pref("devtools.debugger.ui.height", 250);
 pref("devtools.debugger.ui.remote-win.width", 900);
 pref("devtools.debugger.ui.remote-win.height", 400);
 pref("devtools.debugger.ui.stackframes-width", 200);
 pref("devtools.debugger.ui.stackframes-pane-visible", true);
 pref("devtools.debugger.ui.variables-width", 300);
--- a/browser/base/content/browser-plugins.js
+++ b/browser/base/content/browser-plugins.js
@@ -2,16 +2,17 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 function getPluginInfo(pluginElement)
 {
   var tagMimetype;
   var pluginsPage;
+  var pluginName = gNavigatorBundle.getString("pluginInfo.unknownPlugin");
   if (pluginElement instanceof HTMLAppletElement) {
     tagMimetype = "application/x-java-vm";
   } else {
     if (pluginElement instanceof HTMLObjectElement) {
       pluginsPage = pluginElement.getAttribute("codebase");
     } else {
       pluginsPage = pluginElement.getAttribute("pluginspage");
     }
@@ -30,37 +31,50 @@ function getPluginInfo(pluginElement)
     tagMimetype = pluginElement.QueryInterface(Components.interfaces.nsIObjectLoadingContent)
                                .actualType;
 
     if (tagMimetype == "") {
       tagMimetype = pluginElement.type;
     }
   }
 
-  return {mimetype: tagMimetype, pluginsPage: pluginsPage};
+  if (tagMimetype) {
+    let navMimeType = navigator.mimeTypes[tagMimetype];
+    if (navMimeType && navMimeType.enabledPlugin) {
+      pluginName = navMimeType.enabledPlugin.name;
+      pluginName = gPluginHandler.makeNicePluginName(pluginName);
+    }
+  }
+
+  return { mimetype: tagMimetype,
+           pluginsPage: pluginsPage,
+           pluginName: pluginName };
 }
 
 var gPluginHandler = {
 
 #ifdef MOZ_CRASHREPORTER
   get CrashSubmit() {
     delete this.CrashSubmit;
     Cu.import("resource://gre/modules/CrashSubmit.jsm", this);
     return this.CrashSubmit;
   },
 #endif
 
   // Map the plugin's name to a filtered version more suitable for user UI.
-  makeNicePluginName : function (aName, aFilename) {
+  makeNicePluginName : function (aName) {
     if (aName == "Shockwave Flash")
       return "Adobe Flash";
 
     // Clean up the plugin name by stripping off any trailing version numbers
     // or "plugin". EG, "Foo Bar Plugin 1.23_02" --> "Foo Bar"
-    let newName = aName.replace(/\bplug-?in\b/i, "").replace(/[\s\d\.\-\_\(\)]+$/, "");
+    // Do this by first stripping the numbers, etc. off the end, and then
+    // removing "Plugin" (and then trimming to get rid of any whitespace).
+    // (Otherwise, something like "Java(TM) Plug-in 1.7.0_07" gets mangled)
+    let newName = aName.replace(/[\s\d\.\-\_\(\)]+$/, "").replace(/\bplug-?in\b/i, "").trim();
     return newName;
   },
 
   isTooSmall : function (plugin, overlay) {
     // Is the <object>'s size too small to hold what we want to show?
     let pluginRect = plugin.getBoundingClientRect();
     // XXX bug 446693. The text-shadow on the submitted-report text at
     //     the bottom causes scrollHeight to be larger than it should be.
@@ -143,16 +157,27 @@ var gPluginHandler = {
       case "PluginVulnerableUpdatable":
         let updateLink = doc.getAnonymousElementByAttribute(plugin, "class", "checkForUpdatesLink");
         self.addLinkClickCallback(updateLink, "openPluginUpdatePage");
         /* FALLTHRU */
 
       case "PluginVulnerableNoUpdate":
       case "PluginClickToPlay":
         self._handleClickToPlayEvent(plugin);
+        let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
+        let pluginName = getPluginInfo(plugin).pluginName;
+        let messageString = gNavigatorBundle.getFormattedString("PluginClickToPlay", [pluginName]);
+        let overlayText = doc.getAnonymousElementByAttribute(plugin, "class", "msg msgClickToPlay");
+        overlayText.textContent = messageString;
+        if (event.type == "PluginVulnerableUpdatable" ||
+            event.type == "PluginVulnerableNoUpdate") {
+          let vulnerabilityString = gNavigatorBundle.getString(event.type);
+          let vulnerabilityText = doc.getAnonymousElementByAttribute(plugin, "anonid", "vulnerabilityStatus");
+          vulnerabilityText.textContent = vulnerabilityString;
+        }
         break;
 
       case "PluginPlayPreview":
         self._handlePlayPreviewEvent(plugin);
         break;
 
       case "PluginDisabled":
         let manageLink = doc.getAnonymousElementByAttribute(plugin, "class", "managePluginsLink");
@@ -192,26 +217,26 @@ var gPluginHandler = {
 
   activateSinglePlugin: function PH_activateSinglePlugin(aContentWindow, aPlugin) {
     let objLoadingContent = aPlugin.QueryInterface(Ci.nsIObjectLoadingContent);
     if (gPluginHandler.canActivatePlugin(objLoadingContent))
       objLoadingContent.playPlugin();
 
     let cwu = aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                             .getInterface(Ci.nsIDOMWindowUtils);
-    let haveUnplayedPlugins = cwu.plugins.some(function(plugin) {
-      let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
-      return (plugin != aPlugin && gPluginHandler.canActivatePlugin(objLoadingContent));
-    });
+    let pluginNeedsActivation = gPluginHandler._pluginNeedsActivationExceptThese([aPlugin]);
     let browser = gBrowser.getBrowserForDocument(aContentWindow.document);
     let notification = PopupNotifications.getNotification("click-to-play-plugins", browser);
-    if (notification && !haveUnplayedPlugins) {
+    if (notification) {
       browser._clickToPlayDoorhangerShown = false;
       notification.remove();
     }
+    if (pluginNeedsActivation) {
+      gPluginHandler._showClickToPlayNotification(browser);
+    }
   },
 
   stopPlayPreview: function PH_stopPlayPreview(aPlugin, aPlayPlugin) {
     let objLoadingContent = aPlugin.QueryInterface(Ci.nsIObjectLoadingContent);
     if (objLoadingContent.activated)
       return;
 
     if (aPlayPlugin)
@@ -355,37 +380,131 @@ var gPluginHandler = {
       return;
 
     let browser = gBrowser.selectedBrowser;
 
     let pluginsPermission = Services.perms.testPermission(browser.currentURI, "plugins");
     if (pluginsPermission == Ci.nsIPermissionManager.DENY_ACTION)
       return;
 
-    let contentWindow = browser.contentWindow;
+    if (gPluginHandler._pluginNeedsActivationExceptThese([]))
+      gPluginHandler._showClickToPlayNotification(browser);
+  },
+
+  // returns true if there is a plugin on this page that needs activation
+  // and isn't in the "except these" list
+  _pluginNeedsActivationExceptThese: function PH_pluginNeedsActivationExceptThese(aExceptThese) {
+    let contentWindow = gBrowser.selectedBrowser.contentWindow;
     let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                            .getInterface(Ci.nsIDOMWindowUtils);
     let pluginNeedsActivation = cwu.plugins.some(function(plugin) {
       let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
-      return gPluginHandler.canActivatePlugin(objLoadingContent);
+      return (gPluginHandler.canActivatePlugin(objLoadingContent) &&
+              aExceptThese.indexOf(plugin) < 0);
     });
-    if (pluginNeedsActivation)
-      gPluginHandler._showClickToPlayNotification(browser);
+
+    return pluginNeedsActivation;
+  },
+
+  /* Gets all plugins currently in the page of the given name */
+  _getPluginsByName: function PH_getPluginsByName(aDOMWindowUtils, aName) {
+    let plugins = [];
+    for (let plugin of aDOMWindowUtils.plugins) {
+      let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+      if (gPluginHandler.canActivatePlugin(objLoadingContent)) {
+        let pluginName = getPluginInfo(plugin).pluginName;
+        if (aName == pluginName) {
+          plugins.push(objLoadingContent);
+        }
+      }
+    }
+    return plugins;
   },
 
+  _makeCenterActions: function PH_makeCenterActions(aBrowser) {
+    let contentWindow = aBrowser.contentWindow;
+    let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                           .getInterface(Ci.nsIDOMWindowUtils);
+    let pluginsDictionary = {};
+    for (let plugin of cwu.plugins) {
+      let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+      if (gPluginHandler.canActivatePlugin(objLoadingContent)) {
+        let pluginName = getPluginInfo(plugin).pluginName;
+        if (!pluginsDictionary[pluginName]) pluginsDictionary[pluginName] = [];
+        pluginsDictionary[pluginName].push(objLoadingContent);
+      }
+    }
+
+    let centerActions = [];
+    for (let pluginName in pluginsDictionary) {
+      let plugin = pluginsDictionary[pluginName][0];
+      let warn = false;
+      let warningText = "";
+      let updateLink = Services.urlFormatter.formatURLPref("plugins.update.url");
+      if (plugin.pluginFallbackType) {
+        if (plugin.pluginFallbackType ==
+              Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE) {
+          warn = true;
+          warningText = gNavigatorBundle.getString("vulnerableUpdatablePluginWarning");
+        }
+        else if (plugin.pluginFallbackType ==
+                   Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE) {
+          warn = true;
+          warningText = gNavigatorBundle.getString("vulnerableNoUpdatePluginWarning");
+          updateLink = "";
+        }
+      }
+
+      let action = {
+        message: pluginName,
+        warn: warn,
+        warningText: warningText,
+        updateLink: updateLink,
+        label: gNavigatorBundle.getString("activateSinglePlugin"),
+        callback: function() {
+          let plugins = gPluginHandler._getPluginsByName(cwu, this.message);
+          for (let objLoadingContent of plugins) {
+            objLoadingContent.playPlugin();
+          }
+
+          let notification = PopupNotifications.getNotification("click-to-play-plugins", aBrowser);
+          if (notification &&
+              !gPluginHandler._pluginNeedsActivationExceptThese(plugins)) {
+            notification.remove();
+          }
+        }
+      };
+      centerActions.push(action);
+    }
+
+    return centerActions;
+   },
+
   _showClickToPlayNotification: function PH_showClickToPlayNotification(aBrowser) {
     aBrowser._clickToPlayDoorhangerShown = true;
     let contentWindow = aBrowser.contentWindow;
 
     let messageString = gNavigatorBundle.getString("activatePluginsMessage.message");
     let mainAction = {
       label: gNavigatorBundle.getString("activatePluginsMessage.label"),
       accessKey: gNavigatorBundle.getString("activatePluginsMessage.accesskey"),
       callback: function() { gPluginHandler.activatePlugins(contentWindow); }
     };
+    let centerActions = gPluginHandler._makeCenterActions(aBrowser);
+    let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                           .getInterface(Ci.nsIDOMWindowUtils);
+    let haveVulnerablePlugin = cwu.plugins.some(function(plugin) {
+      let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+      return (gPluginHandler.canActivatePlugin(objLoadingContent) &&
+              (objLoadingContent.pluginFallbackType == Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE ||
+               objLoadingContent.pluginFallbackType == Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE));
+    });
+    if (haveVulnerablePlugin) {
+      messageString = gNavigatorBundle.getString("vulnerablePluginsMessage");
+    }
     let secondaryActions = [{
       label: gNavigatorBundle.getString("activatePluginsMessage.always"),
       accessKey: gNavigatorBundle.getString("activatePluginsMessage.always.accesskey"),
       callback: function () {
         Services.perms.add(aBrowser.currentURI, "plugins", Ci.nsIPermissionManager.ALLOW_ACTION);
         gPluginHandler.activatePlugins(contentWindow);
       }
     },{
@@ -394,17 +513,17 @@ var gPluginHandler = {
       callback: function () {
         Services.perms.add(aBrowser.currentURI, "plugins", Ci.nsIPermissionManager.DENY_ACTION);
         let notification = PopupNotifications.getNotification("click-to-play-plugins", aBrowser);
         if (notification)
           notification.remove();
         gPluginHandler._removeClickToPlayOverlays(contentWindow);
       }
     }];
-    let options = { dismissed: true };
+    let options = { dismissed: true, centerActions: centerActions };
     PopupNotifications.show(aBrowser, "click-to-play-plugins",
                             messageString, "plugins-notification-icon",
                             mainAction, secondaryActions, options);
   },
 
   _removeClickToPlayOverlays: function PH_removeClickToPlayOverlays(aContentWindow) {
     let doc = aContentWindow.document;
     let cwu = aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
@@ -615,22 +734,21 @@ var gPluginHandler = {
     // Ensure the plugin and event are of the right type.
     if (!(aEvent instanceof Ci.nsIDOMDataContainerEvent))
       return;
 
     let submittedReport = aEvent.getData("submittedCrashReport");
     let doPrompt        = true; // XXX followup for .getData("doPrompt");
     let submitReports   = true; // XXX followup for .getData("submitReports");
     let pluginName      = aEvent.getData("pluginName");
-    let pluginFilename  = aEvent.getData("pluginFilename");
     let pluginDumpID    = aEvent.getData("pluginDumpID");
     let browserDumpID   = aEvent.getData("browserDumpID");
 
     // Remap the plugin name to a more user-presentable form.
-    pluginName = this.makeNicePluginName(pluginName, pluginFilename);
+    pluginName = this.makeNicePluginName(pluginName);
 
     let messageString = gNavigatorBundle.getFormattedString("crashedpluginsMessage.title", [pluginName]);
 
     //
     // Configure the crashed-plugin placeholder.
     //
     let doc = plugin.ownerDocument;
     let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -94,17 +94,17 @@
     <command id="Tools:Inspect" oncommand="InspectorUI.toggleInspectorUI();"/>
     <command id="Tools:Debugger" oncommand="DebuggerUI.toggleDebugger();" disabled="true" hidden="true"/>
     <command id="Tools:RemoteDebugger" oncommand="DebuggerUI.toggleRemoteDebugger();" disabled="true" hidden="true"/>
     <command id="Tools:ChromeDebugger" oncommand="DebuggerUI.toggleChromeDebugger();" disabled="true" hidden="true"/>
     <command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();" disabled="true" hidden="true"/>
     <command id="Tools:StyleEditor" oncommand="StyleEditor.toggle();" disabled="true" hidden="true"/>
     <command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();" disabled="true" hidden="true"/>
     <command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/>
-    <command id="Tools:ErrorConsole" oncommand="toJavaScriptConsole()" disabled="true" hidden="true"/>
+    <command id="Tools:ErrorConsole" oncommand="toJavaScriptConsole()" hidden="true"/>
     <command id="Tools:Sanitize"
      oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/>
     <command id="Tools:PrivateBrowsing" oncommand="gPrivateBrowsingUI.toggleMode();"/>
     <command id="History:UndoCloseTab" oncommand="undoCloseTab();"/>
     <command id="History:UndoCloseWindow" oncommand="undoCloseWindow();"/>
     <command id="Browser:ToggleAddonBar" oncommand="toggleAddonBar();"/>
     <command id="Social:SharePage" oncommand="SocialShareButton.sharePage();"/>
     <command id="Social:UnsharePage" oncommand="SocialShareButton.unsharePage();"/>
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -23,18 +23,22 @@ let SocialUI = {
     Services.obs.removeObserver(this, "social:ambient-notification-changed");
     Services.obs.removeObserver(this, "social:profile-changed");
 
     Services.prefs.removeObserver("social.sidebar.open", this);
     Services.prefs.removeObserver("social.toast-notifications.enabled", this);
   },
 
   showProfile: function SocialUI_showProfile() {
-    if (Social.provider)
+    if (this.haveLoggedInUser())
       openUILinkIn(Social.provider.profile.profileURL, "tab");
+    else {
+      // XXX Bug 789585 will implement an API for provider-specified login pages.
+      openUILinkIn(Social.provider.origin, "tab");
+    }
   },
 
   observe: function SocialUI_observe(subject, topic, data) {
     switch (topic) {
       case "social:pref-changed":
         // Exceptions here sometimes don't get reported properly, report them
         // manually :(
         try {
@@ -526,43 +530,31 @@ let SocialShareButton = {
     }
     shareButton.style.backgroundImage = 'url("' + encodeURI(imageURL) + '")';
   }
 };
 
 var SocialToolbar = {
   // Called once, after window load, when the Social.provider object is initialized
   init: function SocialToolbar_init() {
-    document.getElementById("social-provider-image").setAttribute("image", Social.provider.iconURL);
-
-    let statusAreaPopup = document.getElementById("social-statusarea-popup");
-    statusAreaPopup.addEventListener("popupshown", function(e) {
-      this.button.setAttribute("open", "true");
-    }.bind(this));
-    statusAreaPopup.addEventListener("popuphidden", function(e) {
-      this.button.removeAttribute("open");
-    }.bind(this));
-
+    document.getElementById("social-provider-button").setAttribute("image", Social.provider.iconURL);
     this.updateButton();
     this.updateProfile();
   },
 
-  get button() {
-    return document.getElementById("social-toolbar-button");
-  },
-
   updateButtonHiddenState: function SocialToolbar_updateButtonHiddenState() {
-    this.button.hidden = !Social.uiVisible;
+    let tbi = document.getElementById("social-toolbar-item");
+    tbi.hidden = !Social.uiVisible;
     if (!SocialUI.haveLoggedInUser()) {
-      ["social-notification-box",
-       "social-status-iconbox"].forEach(function removeChildren(parentId) {
-        let parent = document.getElementById(parentId);
-        while(parent.hasChildNodes())
-          parent.removeChild(parent.firstChild);
-      });
+      let parent = document.getElementById("social-notification-box");
+      while (parent.hasChildNodes())
+        parent.removeChild(parent.firstChild);
+
+      while (tbi.lastChild != tbi.firstChild)
+        tbi.removeChild(tbi.lastChild);
     }
   },
 
   updateProfile: function SocialToolbar_updateProfile() {
     // Profile may not have been initialized yet, since it depends on a worker
     // response. In that case we'll be called again when it's available, via
     // social:profile-changed
     let profile = Social.provider.profile || {};
@@ -580,17 +572,17 @@ var SocialToolbar = {
       userNameBtn.hidden = true;
     }
   },
 
   updateButton: function SocialToolbar_updateButton() {
     this.updateButtonHiddenState();
     let provider = Social.provider;
     let iconNames = Object.keys(provider.ambientNotificationIcons);
-    let iconBox = document.getElementById("social-status-iconbox");
+    let iconBox = document.getElementById("social-toolbar-item");
     let notifBox = document.getElementById("social-notification-box");
     let panel = document.getElementById("social-notification-panel");
     panel.hidden = false;
     let notificationFrames = document.createDocumentFragment();
     let iconContainers = document.createDocumentFragment();
 
     let command = document.getElementById("Social:ToggleNotifications");
     command.setAttribute("checked", Services.prefs.getBoolPref("social.toast-notifications.enabled"));
@@ -608,54 +600,70 @@ var SocialToolbar = {
         notificationFrame.setAttribute("mozbrowser", "true");
         notificationFrames.appendChild(notificationFrame);
       }
       notificationFrame.setAttribute("origin", provider.origin);
       if (notificationFrame.getAttribute("src") != icon.contentPanel)
         notificationFrame.setAttribute("src", icon.contentPanel);
 
       let iconId = "social-notification-icon-" + icon.name;
-      let iconContainer = document.getElementById(iconId);
-      let iconImage, iconCounter;
-      if (iconContainer) {
-        iconImage = iconContainer.getElementsByClassName("social-notification-icon-image")[0];
-        iconCounter = iconContainer.getElementsByClassName("social-notification-icon-counter")[0];
+      let imageId = iconId + "-image";
+      let labelId = iconId + "-label";
+      let stackId = iconId + "-stack";
+      let stack = document.getElementById(stackId);
+      let image, label;
+      if (stack) {
+        image = document.getElementById(imageId);
+        label = document.getElementById(labelId);
       } else {
-        iconContainer = document.createElement("box");
-        iconContainer.setAttribute("id", iconId);
-        iconContainer.classList.add("social-notification-icon-container");
-        iconContainer.addEventListener("click", function (e) { SocialToolbar.showAmbientPopup(iconContainer); }, false);
+        let box = document.createElement("box");
+        box.classList.add("toolbarbutton-1");
+        box.setAttribute("id", iconId);
+        box.addEventListener("mousedown", function (e) {
+          if (e.button == 0)
+            SocialToolbar.showAmbientPopup(box);
+        }, false);
+        box.setAttribute("notificationFrameId", notificationFrameId);
+        stack = document.createElement("stack");
+        stack.setAttribute("id", stackId);
+        stack.classList.add("social-notification-icon-stack");
+        stack.classList.add("toolbarbutton-icon");
+        image = document.createElement("image");
+        image.setAttribute("id", imageId);
+        image = stack.appendChild(image);
+        label = document.createElement("label");
+        label.setAttribute("id", labelId);
+        label.classList.add("social-notification-icon-label");
+        let hbox = document.createElement("hbox");
+        hbox.classList.add("social-notification-icon-hbox");
+        hbox.setAttribute("align", "start");
+        hbox.setAttribute("pack", "end");
+        label = hbox.appendChild(label);
+        stack.appendChild(hbox);
+        box.appendChild(stack);
+        iconContainers.appendChild(box);
+      }
 
-        iconImage = document.createElement("image");
-        iconImage.classList.add("social-notification-icon-image");
-        iconImage = iconContainer.appendChild(iconImage);
-
-        iconCounter = document.createElement("box");
-        iconCounter.classList.add("social-notification-icon-counter");
-        iconCounter.appendChild(document.createTextNode(""));
-        iconCounter = iconContainer.appendChild(iconCounter);
+      let labelValue = icon.counter || "";
+      // Only update the value attribute if it has changed to reduce layout changes.
+      if (!label.hasAttribute("value") || label.getAttribute("value") != labelValue)
+        label.setAttribute("value", labelValue);
 
-        iconContainers.appendChild(iconContainer);
-      }
-      if (iconImage.getAttribute("src") != icon.iconURL)
-        iconImage.setAttribute("src", icon.iconURL);
-      iconImage.setAttribute("notificationFrameId", notificationFrameId);
-
-      iconCounter.collapsed = !icon.counter;
-      iconCounter.firstChild.textContent = icon.counter || "";
+      if (image.getAttribute("src") != icon.iconURL)
+        image.setAttribute("src", icon.iconURL);
     }
     notifBox.appendChild(notificationFrames);
     iconBox.appendChild(iconContainers);
   },
 
-  showAmbientPopup: function SocialToolbar_showAmbientPopup(iconContainer) {
-    let iconImage = iconContainer.firstChild;
+  showAmbientPopup: function SocialToolbar_showAmbientPopup(aToolbarButtonBox) {
     let panel = document.getElementById("social-notification-panel");
     let notifBox = document.getElementById("social-notification-box");
-    let notificationFrame = document.getElementById(iconImage.getAttribute("notificationFrameId"));
+    let notificationFrameId = aToolbarButtonBox.getAttribute("notificationFrameId");
+    let notificationFrame = document.getElementById(notificationFrameId);
 
     // Clear dimensions on all browsers so the panel size will
     // only use the selected browser.
     let frameIter = notifBox.firstElementChild;
     while (frameIter) {
       frameIter.collapsed = (frameIter != notificationFrame);
       frameIter = frameIter.nextElementSibling;
     }
@@ -663,24 +671,24 @@ var SocialToolbar = {
     function dispatchPanelEvent(name) {
       let evt = notificationFrame.contentDocument.createEvent("CustomEvent");
       evt.initCustomEvent(name, true, true, {});
       notificationFrame.contentDocument.documentElement.dispatchEvent(evt);
     }
 
     panel.addEventListener("popuphidden", function onpopuphiding() {
       panel.removeEventListener("popuphidden", onpopuphiding);
-      SocialToolbar.button.removeAttribute("open");
+      aToolbarButtonBox.removeAttribute("open");
       notificationFrame.docShell.isActive = false;
       dispatchPanelEvent("socialFrameHide");
     });
 
     panel.addEventListener("popupshown", function onpopupshown() {
       panel.removeEventListener("popupshown", onpopupshown);
-      SocialToolbar.button.setAttribute("open", "true");
+      aToolbarButtonBox.setAttribute("open", "true");
       notificationFrame.docShell.isActive = true;
       notificationFrame.docShell.isAppTab = true;
       if (notificationFrame.contentDocument.readyState == "complete") {
         setupDynamicPanelResizer(notificationFrame);
         dispatchPanelEvent("socialFrameShow");
       } else {
         // first time load, wait for load and dispatch after load
         notificationFrame.addEventListener("load", function panelBrowserOnload(e) {
@@ -688,17 +696,19 @@ var SocialToolbar = {
           setupDynamicPanelResizer(notificationFrame);
           setTimeout(function() {
             dispatchPanelEvent("socialFrameShow");
           }, 0);
         }, true);
       }
     });
 
-    panel.openPopup(iconImage, "bottomcenter topleft", 0, 0, false, false);
+    let imageId = aToolbarButtonBox.getAttribute("id") + "-image";
+    let toolbarButtonImage = document.getElementById(imageId);
+    panel.openPopup(toolbarButtonImage, "bottomcenter topleft", 0, 0, false, false);
   }
 }
 
 var SocialSidebar = {
   // Called once, after window load, when the Social.provider object is initialized
   init: function SocialSidebar_init() {
     let sbrowser = document.getElementById("social-sidebar-browser");
     // setting isAppTab causes clicks on untargeted links to open new tabs
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -485,16 +485,24 @@ window[chromehidden~="toolbar"] toolbar:
 #addon-progress-notification {
   -moz-binding: url("chrome://browser/content/urlbarBindings.xml#addon-progress-notification");
 }
 
 #identity-request-notification {
   -moz-binding: url("chrome://browser/content/urlbarBindings.xml#identity-request-notification");
 }
 
+#click-to-play-plugins-notification {
+  -moz-binding: url("chrome://browser/content/urlbarBindings.xml#click-to-play-plugins-notification");
+}
+
+popupnotification-centeritem {
+  -moz-binding: url("chrome://browser/content/urlbarBindings.xml#center-item");
+}
+
 /* override hidden="true" for the status bar compatibility shim
    in case it was persisted for the real status bar */
 #status-bar {
   display: -moz-box;
 }
 
 /* Remove the resizer from the statusbar compatibility shim */
 #status-bar[hideresizer] > .statusbar-resizerpanel {
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1451,21 +1451,19 @@ var gBrowserInit = {
                   gPrefService.getBoolPref("devtools.debugger.remote-enabled");
     if (enabled) {
       let cmd = document.getElementById("Tools:ChromeDebugger");
       cmd.removeAttribute("disabled");
       cmd.removeAttribute("hidden");
     }
 
     // Enable Error Console?
-    // XXX Temporarily always-enabled, see bug 601201
-    let consoleEnabled = true || gPrefService.getBoolPref("devtools.errorconsole.enabled");
+    let consoleEnabled = gPrefService.getBoolPref("devtools.errorconsole.enabled");
     if (consoleEnabled) {
       let cmd = document.getElementById("Tools:ErrorConsole");
-      cmd.removeAttribute("disabled");
       cmd.removeAttribute("hidden");
     }
 
     // Enable Scratchpad in the UI, if the preference allows this.
     let scratchpadEnabled = gPrefService.getBoolPref(Scratchpad.prefEnabledName);
     if (scratchpadEnabled) {
       let cmd = document.getElementById("Tools:Scratchpad");
       cmd.removeAttribute("disabled");
@@ -5310,17 +5308,17 @@ function handleLinkClick(event, href, li
   var where = whereToOpenLink(event);
   if (where == "current")
     return false;
 
   var doc = event.target.ownerDocument;
 
   if (where == "save") {
     saveURL(href, linkNode ? gatherTextUnder(linkNode) : "", null, true,
-            true, doc.documentURIObject);
+            true, doc.documentURIObject, doc);
     event.preventDefault();
     return true;
   }
 
   urlSecurityCheck(href, doc.nodePrincipal);
   openLinkIn(href, where, { referrerURI: doc.documentURIObject,
                             charset: doc.characterSet });
   event.preventDefault();
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -655,51 +655,42 @@
                      label="&homeButton.label;"
                      ondragover="homeButtonObserver.onDragOver(event)"
                      ondragenter="homeButtonObserver.onDragOver(event)"
                      ondrop="homeButtonObserver.onDrop(event)"
                      ondragexit="homeButtonObserver.onDragExit(event)"
                      onclick="BrowserGoHome(event);"
                      aboutHomeOverrideTooltip="&abouthome.pageTitle;"/>
 
-      <toolbaritem id="social-toolbar-button"
-                   class="toolbarbutton-1 chromeclass-toolbar-additional"
+      <toolbaritem id="social-toolbar-item"
+                   class="chromeclass-toolbar-additional"
                    removable="false"
-                   pack="center"
                    title="&socialToolbar.title;"
                    hidden="true">
-        <hbox id="social-toolbar-button-box" class="social-statusarea-container">
-          <button id="social-provider-image" type="menu">
-            <menupopup id="social-statusarea-popup">
-              <hbox id="social-statusarea-user" pack="left" align="center">
-                <image id="social-statusarea-user-portrait"/>
-                <vbox>
-                  <label id="social-statusarea-notloggedin"
-                         value="&social.notLoggedIn.label;"/>
-                  <button id="social-statusarea-username"
-                          oncommand="SocialUI.showProfile(); document.getElementById('social-statusarea-popup').hidePopup();"/>
-                </vbox>
-              </hbox>
-              <menuitem id="social-toggle-sidebar-menuitem"
-                        type="checkbox"
-                        autocheck="false"
-                        command="Social:ToggleSidebar"
-                        label="&social.toggleSidebar.label;"
-                        accesskey="&social.toggleSidebar.accesskey;"/>
-              <menuitem id="social-toggle-notifications-menuitem"
-                        type="checkbox"
-                        autocheck="false"
-                        command="Social:ToggleNotifications"
-                        label="&social.toggleNotifications.label;"
-                        accesskey="&social.toggleNotifications.accesskey;"/>
-            </menupopup>
-          </button>
-          <hbox id="social-status-iconbox" flex="1">
-          </hbox>
-        </hbox>
+        <toolbarbutton id="social-provider-button"
+                       class="toolbarbutton-1"
+                       type="menu">
+          <menupopup id="social-statusarea-popup">
+            <hbox id="social-statusarea-user" pack="start" align="center"
+                  onclick="SocialUI.showProfile(); document.getElementById('social-statusarea-popup').hidePopup();">
+              <image id="social-statusarea-user-portrait"/>
+              <vbox>
+                <button id="social-statusarea-notloggedin"
+                        class="link" label="&social.notLoggedIn.label;"/>
+                <button id="social-statusarea-username" class="link"/>
+              </vbox>
+            </hbox>
+            <menuitem id="social-toggle-sidebar-menuitem"
+                      type="checkbox"
+                      autocheck="false"
+                      command="Social:ToggleSidebar"
+                      label="&social.toggleSidebar.label;"
+                      accesskey="&social.toggleSidebar.accesskey;"/>
+          </menupopup>
+        </toolbarbutton>
       </toolbaritem>
 
       <toolbaritem id="bookmarks-menu-button-container"
                    class="chromeclass-toolbar-additional"
                    removable="true"
                    title="&bookmarksMenuButton.label;">
         <toolbarbutton id="bookmarks-menu-button"
                        type="menu"
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -1,12 +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/.
 
+Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
+
 function nsContextMenu(aXulMenu, aBrowser, aIsShift) {
   this.shouldDisplay = true;
   this.initMenu(aBrowser, aXulMenu, aIsShift);
 }
 
 // Prototype for nsContextMenu "class."
 nsContextMenu.prototype = {
   initMenu: function CM_initMenu(aBrowser, aXulMenu, aIsShift) {
@@ -956,17 +958,17 @@ nsContextMenu.prototype = {
         this.extListener.onStartRequest(aRequest, aContext);
       }, 
 
       onStopRequest: function saveLinkAs_onStopRequest(aRequest, aContext, 
                                                        aStatusCode) {
         if (aStatusCode == NS_ERROR_SAVE_LINK_AS_TIMEOUT) {
           // do it the old fashioned way, which will pick the best filename
           // it can without waiting.
-          saveURL(linkURL, linkText, dialogTitle, bypassCache, false, doc.documentURIObject);
+          saveURL(linkURL, linkText, dialogTitle, bypassCache, false, doc.documentURIObject, doc);
         }
         if (this.extListener)
           this.extListener.onStopRequest(aRequest, aContext, aStatusCode);
       },
 
       onDataAvailable: function saveLinkAs_onDataAvailable(aRequest, aContext,
                                                            aInputStream,
                                                            aOffset, aCount) {
@@ -1001,16 +1003,20 @@ nsContextMenu.prototype = {
         return;
       }
     }
 
     // set up a channel to do the saving
     var ioService = Cc["@mozilla.org/network/io-service;1"].
                     getService(Ci.nsIIOService);
     var channel = ioService.newChannelFromURI(makeURI(linkURL));
+    if (channel instanceof Ci.nsIPrivateBrowsingChannel) {
+      let docIsPrivate = PrivateBrowsingUtils.isWindowPrivate(doc.defaultView);
+      channel.setPrivate(docIsPrivate);
+    }
     channel.notificationCallbacks = new callbacks();
 
     let flags = Ci.nsIChannel.LOAD_CALL_CONTENT_SNIFFERS;
 
     if (bypassCache)
       flags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
 
     if (channel instanceof Ci.nsICachingChannel)
--- a/browser/base/content/pageinfo/pageInfo.js
+++ b/browser/base/content/pageinfo/pageInfo.js
@@ -802,24 +802,24 @@ function saveMedia()
     if (url) {
       var titleKey = "SaveImageTitle";
 
       if (item instanceof HTMLVideoElement)
         titleKey = "SaveVideoTitle";
       else if (item instanceof HTMLAudioElement)
         titleKey = "SaveAudioTitle";
 
-      saveURL(url, null, titleKey, false, false, makeURI(item.baseURI));
+      saveURL(url, null, titleKey, false, false, makeURI(item.baseURI), gDocument);
     }
   } else {
     selectSaveFolder(function(aDirectory) {
       if (aDirectory) {
         var saveAnImage = function(aURIString, aChosenData, aBaseURI) {
           internalSave(aURIString, null, null, null, null, false, "SaveImageTitle",
-                       aChosenData, aBaseURI);
+                       aChosenData, aBaseURI, gDocument);
         };
       
         for (var i = 0; i < rowArray.length; i++) {
           var v = rowArray[i];
           var dir = aDirectory.clone();
           var item = gImageView.data[v][COL_IMAGE_NODE];
           var uriString = gImageView.data[v][COL_IMAGE_ADDRESS];
           var uri = makeURI(uriString);
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -188,16 +188,19 @@ endif
                  browser_clearplugindata.html \
                  browser_clearplugindata_noage.html \
                  browser_popupUI.js \
                  browser_sanitizeDialog.js \
                  browser_save_video.js \
                  bug564387.html \
                  bug564387_video1.ogv \
                  bug564387_video1.ogv^headers^ \
+                 browser_save_link.js \
+                 bug792517-2.html \
+                 bug792517.sjs \
                  browser_scope.js \
                  browser_selectTabAtIndex.js \
                  browser_tab_dragdrop.js \
                  browser_tab_dragdrop2.js \
                  browser_tab_dragdrop2_frame1.xul \
                  browser_tabfocus.js \
                  browser_tabs_isActive.js \
                  browser_tabs_owner.js \
@@ -231,16 +234,17 @@ endif
                  plugin_alternate_content.html \
                  plugin_both.html \
                  plugin_both2.html \
                  plugin_bug743421.html \
                  plugin_clickToPlayAllow.html \
                  plugin_clickToPlayDeny.html \
                  plugin_bug749455.html \
                  plugin_hidden_to_visible.html \
+                 plugin_two_types.html \
                  alltabslistener.html \
                  zoom_test.html \
                  dummy_page.html \
                  browser_tabMatchesInAwesomebar.js \
                  file_bug550565_popup.html \
                  file_bug550565_favicon.ico \
                  browser_aboutHome.js \
                  app_bug575561.html \
--- a/browser/base/content/test/browser_pluginnotification.js
+++ b/browser/base/content/test/browser_pluginnotification.js
@@ -218,17 +218,19 @@ function test8() {
 }
 
 // Tests that activating one click-to-play plugin will activate only that plugin (part 1/3)
 function test9a() {
   var notificationBox = gBrowser.getNotificationBox(gTestBrowser);
   ok(!notificationBox.getNotificationWithValue("missing-plugins"), "Test 9a, Should not have displayed the missing plugin notification");
   ok(!notificationBox.getNotificationWithValue("blocked-plugins"), "Test 9a, Should not have displayed the blocked plugin notification");
   ok(!gTestBrowser.missingPlugins, "Test 9a, Should not be a missing plugin list");
-  ok(PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser), "Test 9a, Should have a click-to-play notification");
+  var notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+  ok(notification, "Test 9a, Should have a click-to-play notification");
+  ok(notification.options.centerActions.length == 1, "Test 9a, Should have only one type of plugin in the notification");
 
   var doc = gTestBrowser.contentDocument;
   var plugin1 = doc.getElementById("test1");
   var rect = doc.getAnonymousElementByAttribute(plugin1, "class", "mainBox").getBoundingClientRect();
   ok(rect.width == 200, "Test 9a, Plugin with id=" + plugin1.id + " overlay rect should have 200px width before being clicked");
   ok(rect.height == 200, "Test 9a, Plugin with id=" + plugin1.id + " overlay rect should have 200px height before being clicked");
   var objLoadingContent = plugin1.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(!objLoadingContent.activated, "Test 9a, Plugin with id=" + plugin1.id + " should not be activated");
@@ -247,17 +249,19 @@ function test9a() {
 }
 
 // Tests that activating one click-to-play plugin will activate only that plugin (part 2/3)
 function test9b() {
   var notificationBox = gBrowser.getNotificationBox(gTestBrowser);
   ok(!notificationBox.getNotificationWithValue("missing-plugins"), "Test 9b, Should not have displayed the missing plugin notification");
   ok(!notificationBox.getNotificationWithValue("blocked-plugins"), "Test 9b, Should not have displayed the blocked plugin notification");
   ok(!gTestBrowser.missingPlugins, "Test 9b, Should not be a missing plugin list");
-  ok(PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser), "Test 9b, Click to play notification should not be removed now");
+  var notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+  ok(notification, "Test 9b, Click to play notification should not be removed now");
+  ok(notification.options.centerActions.length == 1, "Test 9b, Should have only one type of plugin in the notification");
 
   var doc = gTestBrowser.contentDocument;
   var plugin1 = doc.getElementById("test1");
   var pluginRect1 = doc.getAnonymousElementByAttribute(plugin1, "class", "mainBox").getBoundingClientRect();
   ok(pluginRect1.width == 0, "Test 9b, Plugin with id=" + plugin1.id + " should have click-to-play overlay with zero width");
   ok(pluginRect1.height == 0, "Test 9b, Plugin with id=" + plugin1.id + " should have click-to-play overlay with zero height");
   var objLoadingContent = plugin1.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(objLoadingContent.activated, "Test 9b, Plugin with id=" + plugin1.id + " should be activated");
@@ -517,17 +521,17 @@ function test16d() {
 // inspected type.
 function test17() {
   var clickToPlayNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
   ok(clickToPlayNotification, "Test 17, Should have a click-to-play notification");
   var missingNotification = PopupNotifications.getNotification("missing-plugins", gTestBrowser);
   ok(!missingNotification, "Test 17, Should not have a missing plugin notification");
 
   registerFakeBlocklistService(Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE);
-  prepareTest(test18a, gTestRoot + "plugin_test.html");
+  prepareTest(test18a, gHttpTestRoot + "plugin_test.html");
 }
 
 const Cr = Components.results;
 const Cm = Components.manager;
 const Cc = Components.classes;
 const gReg = Cm.QueryInterface(Ci.nsIComponentRegistrar);
 const gRealBlocklistServiceCID = Cc["@mozilla.org/extensions/blocklist;1"];
 const gFakeBlocklistServiceCID = Components.ID("{614b68a0-3c53-4ec0-8146-28cc1e25f8a1}");
@@ -604,17 +608,17 @@ function test18b() {
   var plugin = doc.getElementById("test");
   var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(!objLoadingContent.activated, "Test 18b, Plugin should not be activated");
   var overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
   ok(overlay.style.visibility != "hidden", "Test 18b, Plugin overlay should exist, not be hidden");
 
   unregisterFakeBlocklistService();
   registerFakeBlocklistService(Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE);
-  prepareTest(test18c, gTestRoot + "plugin_test.html");
+  prepareTest(test18c, gHttpTestRoot + "plugin_test.html");
 }
 
 // Tests a vulnerable plugin with no update
 function test18c() {
   var clickToPlayNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
   ok(clickToPlayNotification, "Test 18c, Should have a click-to-play notification");
   var doc = gTestBrowser.contentDocument;
   var plugin = doc.getElementById("test");
@@ -622,19 +626,45 @@ function test18c() {
   var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
   is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE, "Test 18c, plugin fallback type should be PLUGIN_VULNERABLE_NO_UPDATE");
   ok(!objLoadingContent.activated, "Test 18c, Plugin should not be activated");
   var overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
   ok(overlay.style.visibility != "hidden", "Test 18c, Plugin overlay should exist, not be hidden");
   var updateLink = doc.getAnonymousElementByAttribute(plugin, "class", "checkForUpdatesLink");
   ok(updateLink.style.display != "block", "Test 18c, Plugin should not have an update link");
 
+  // check that click "Always allow" works with blocklisted plugins (for now)
+  clickToPlayNotification.secondaryActions[0].callback();
+  var condition = function() objLoadingContent.activated;
+  waitForCondition(condition, test18d, "Test 18d, Waited too long for plugin to activate");
+}
+
+// continue testing "Always allow"
+function test18d() {
+  var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+  ok(!popupNotification, "Test 18d, Should not have a click-to-play notification");
+  var plugin = gTestBrowser.contentDocument.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.activated, "Test 18d, Plugin should be activated");
+
+  prepareTest(test18e, gHttpTestRoot + "plugin_test.html");
+}
+
+// continue testing "Always allow"
+function test18e() {
+  var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+  ok(!popupNotification, "Test 18e, Should not have a click-to-play notification");
+  var plugin = gTestBrowser.contentDocument.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.activated, "Test 18e, Plugin should be activated");
+
   unregisterFakeBlocklistService();
   var plugin = getTestPlugin();
   plugin.clicktoplay = false;
+  Services.perms.removeAll();
 
   prepareTest(test19a, gTestRoot + "plugin_test.html");
 }
 
 // Tests that clicking the icon of the overlay activates the plugin
 function test19a() {
   var doc = gTestBrowser.contentDocument;
   var plugin = doc.getElementById("test");
@@ -743,10 +773,143 @@ function test20c() {
   var doc = gTestBrowser.contentDocument;
   var plugin = doc.getElementById("plugin");
   var pluginRect = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox").getBoundingClientRect();
   ok(pluginRect.width == 0, "Test 20c, plugin should have click-to-play overlay with zero width");
   ok(pluginRect.height == 0, "Test 20c, plugin should have click-to-play overlay with zero height");
   var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(objLoadingContent.activated, "Test 20c, plugin should be activated");
 
+  prepareTest(test21a, gTestRoot + "plugin_two_types.html");
+}
+
+// Test having multiple different types of plugin on one page
+function test21a() {
+  var notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+  ok(notification, "Test 21a, Should have a click-to-play notification");
+  ok(notification.options.centerActions.length == 2, "Test 21a, Should have two types of plugin in the notification");
+
+  var doc = gTestBrowser.contentDocument;
+  var ids = ["test", "secondtestA", "secondtestB"];
+  for (var id of ids) {
+    var plugin = doc.getElementById(id);
+    var rect = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox").getBoundingClientRect();
+    ok(rect.width == 200, "Test 21a, Plugin with id=" + plugin.id + " overlay rect should have 200px width before being clicked");
+    ok(rect.height == 200, "Test 21a, Plugin with id=" + plugin.id + " overlay rect should have 200px height before being clicked");
+    var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+    ok(!objLoadingContent.activated, "Test 21a, Plugin with id=" + plugin.id + " should not be activated");
+  }
+
+  // we have to actually show the panel to get the bindings to instantiate
+  notification.options.dismissed = false;
+  notification.options.eventCallback = test21b;
+  PopupNotifications._showPanel([notification], notification.anchorElement);
+}
+
+function test21b() {
+  var notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+  notification.options.eventCallback = null;
+  var centerAction = null;
+  for (var action of notification.options.centerActions) {
+    if (action.message == "Test") {
+      centerAction = action;
+      break;
+    }
+  }
+  ok(centerAction, "Test 21b, found center action for the Test plugin");
+
+  var centerItem = null;
+  for (var item of centerAction.popupnotification.childNodes) {
+    if (item.action == centerAction) {
+      centerItem = item;
+      break;
+    }
+  }
+  ok(centerItem, "Test 21b, found center item for the Test plugin");
+
+  // "click" the button to activate the Test plugin
+  centerItem.runCallback.apply(centerItem);
+
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  var condition = function() objLoadingContent.activated;
+  waitForCondition(condition, test21c, "Test 21b, Waited too long for plugin to activate");
+}
+
+function test21c() {
+  var notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+  ok(notification, "Test 21c, Should have a click-to-play notification");
+  ok(notification.options.centerActions.length == 1, "Test 21c, Should have one type of plugin in the notification");
+
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var rect = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox").getBoundingClientRect();
+  ok(rect.width == 0, "Test 21c, Plugin with id=" + plugin.id + " overlay rect should have 0px width after being clicked");
+  ok(rect.height == 0, "Test 21c, Plugin with id=" + plugin.id + " overlay rect should have 0px height after being clicked");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.activated, "Test 21c, Plugin with id=" + plugin.id + " should be activated");
+
+  var ids = ["secondtestA", "secondtestB"];
+  for (var id of ids) {
+    var plugin = doc.getElementById(id);
+    var rect = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox").getBoundingClientRect();
+    ok(rect.width == 200, "Test 21c, Plugin with id=" + plugin.id + " overlay rect should have 200px width before being clicked");
+    ok(rect.height == 200, "Test 21c, Plugin with id=" + plugin.id + " overlay rect should have 200px height before being clicked");
+    var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+    ok(!objLoadingContent.activated, "Test 21c, Plugin with id=" + plugin.id + " should not be activated");
+  }
+
+  // we have to actually show the panel to get the bindings to instantiate
+  notification.options.dismissed = false;
+  notification.options.eventCallback = test21d;
+  PopupNotifications._showPanel([notification], notification.anchorElement);
+}
+
+function test21d() {
+  var notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+  notification.options.eventCallback = null;
+
+  var centerAction = null;
+  for (var action of notification.options.centerActions) {
+    if (action.message == "Second Test") {
+      centerAction = action;
+      break;
+    }
+  }
+  ok(centerAction, "Test 21d, found center action for the Second Test plugin");
+
+  var centerItem = null;
+  for (var item of centerAction.popupnotification.childNodes) {
+    if (item.action == centerAction) {
+      centerItem = item;
+      break;
+    }
+  }
+  ok(centerItem, "Test 21d, found center item for the Second Test plugin");
+
+  // "click" the button to activate the Second Test plugins
+  centerItem.runCallback.apply(centerItem);
+
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("secondtestA");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  var condition = function() objLoadingContent.activated;
+  waitForCondition(condition, test21e, "Test 21d, Waited too long for plugin to activate");
+}
+
+function test21e() {
+  var notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+  ok(!notification, "Test 21e, Should not have a click-to-play notification");
+
+  var doc = gTestBrowser.contentDocument;
+  var ids = ["test", "secondtestA", "secondtestB"];
+  for (var id of ids) {
+    var plugin = doc.getElementById(id);
+    var rect = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox").getBoundingClientRect();
+    ok(rect.width == 0, "Test 21e, Plugin with id=" + plugin.id + " overlay rect should have 0px width after being clicked");
+    ok(rect.height == 0, "Test 21e, Plugin with id=" + plugin.id + " overlay rect should have 0px height after being clicked");
+    var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+    ok(objLoadingContent.activated, "Test 21e, Plugin with id=" + plugin.id + " should be activated");
+  }
+
   finishTest();
 }
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_save_link.js
@@ -0,0 +1,128 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+var MockFilePicker = SpecialPowers.MockFilePicker;
+MockFilePicker.init();
+
+let tempScope = {};
+Cu.import("resource://gre/modules/NetUtil.jsm", tempScope);
+let NetUtil = tempScope.NetUtil;
+
+// Trigger a save of a link in public mode, then trigger an identical save
+// in private mode and ensure that the second request is differentiated from
+// the first by checking the cookies that are sent.
+
+function triggerSave(aCallback) {
+  var fileName;
+  gBrowser.selectedTab = gBrowser.addTab();
+  let testBrowser = gBrowser.selectedBrowser;
+  testBrowser.loadURI("http://mochi.test:8888/browser/browser/base/content/test/bug792517-2.html");
+  testBrowser.addEventListener("pageshow", function pageShown(event) {
+    if (event.target.location == "about:blank")
+      return;
+    testBrowser.removeEventListener("pageshow", pageShown, false);
+
+    executeSoon(function () {
+      document.addEventListener("popupshown", contextMenuOpened, false);
+
+      var link = testBrowser.contentDocument.getElementById("fff");
+      EventUtils.synthesizeMouseAtCenter(link,
+                                         { type: "contextmenu", button: 2 },
+                                         testBrowser.contentWindow);
+    });
+  }, false);
+
+  function contextMenuOpened(event) {
+    event.currentTarget.removeEventListener("popupshown", contextMenuOpened, false);
+
+    // Create the folder the link will be saved into.
+    var destDir = createTemporarySaveDirectory();
+    var destFile = destDir.clone();
+
+    MockFilePicker.displayDirectory = destDir;
+    MockFilePicker.showCallback = function(fp) {
+      fileName = fp.defaultString;
+      destFile.append (fileName);
+      MockFilePicker.returnFiles = [destFile];
+      MockFilePicker.filterIndex = 1; // kSaveAsType_URL
+    };
+
+    mockTransferCallback = function(a) onTransferComplete(a, destFile, destDir);
+
+    // Select "Save Link As" option from context menu
+    var saveLinkCommand = document.getElementById("context-savelink");
+    saveLinkCommand.doCommand();
+
+    event.target.hidePopup();
+  }
+
+  function onTransferComplete(downloadSuccess, destFile, destDir) {
+    ok(downloadSuccess, "Link should have been downloaded successfully");
+    gBrowser.removeCurrentTab();
+
+    // Give the request a chance to finish
+    executeSoon(function() aCallback(destFile, destDir));
+  }
+}
+
+function readFile(file, callback) {
+  let channel = NetUtil.newChannel(file);
+  channel.contentType = "application/javascript";
+
+  NetUtil.asyncFetch(channel, function(inputStream, status) {
+    ok(Components.isSuccessCode(status),
+       "file was read successfully");
+
+    let content = NetUtil.readInputStreamToString(inputStream,
+                                                  inputStream.available());
+    executeSoon(function() callback(content));
+  });
+}
+
+function test() {
+  waitForExplicitFinish();
+
+  let pb = Cc["@mozilla.org/privatebrowsing;1"]
+             .getService(Ci.nsIPrivateBrowsingService);
+
+  mockTransferRegisterer.register();
+
+  registerCleanupFunction(function () {
+    mockTransferRegisterer.unregister();
+    MockFilePicker.cleanup();
+    pb.privateBrowsingEnabled = false;
+    Services.prefs.clearUserPref("browser.privatebrowsing.keep_current_session");
+  });
+
+  triggerSave(function(destFile, destDir) {
+    readFile(destFile, function(content) {
+      is(content, "cookie-not-present", "no cookie should be sent");
+      destDir.remove(true);
+
+      Services.prefs.setBoolPref("browser.privatebrowsing.keep_current_session", true);
+      pb.privateBrowsingEnabled = true;
+      triggerSave(function(destFile, destDir) {
+        readFile(destFile, function(content) {
+          is(content, "cookie-not-present", "no cookie should be sent");
+          destDir.remove(true);
+          finish();
+        });
+      });
+    });
+  });  
+}
+
+Cc["@mozilla.org/moz/jssubscript-loader;1"]
+  .getService(Ci.mozIJSSubScriptLoader)
+  .loadSubScript("chrome://mochitests/content/browser/toolkit/content/tests/browser/common/mockTransfer.js",
+                 this);
+
+function createTemporarySaveDirectory() {
+  var saveDir = Cc["@mozilla.org/file/directory_service;1"]
+                  .getService(Ci.nsIProperties)
+                  .get("TmpD", Ci.nsIFile);
+  saveDir.append("testsavedir");
+  if (!saveDir.exists())
+    saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
+  return saveDir;
+}
--- a/browser/base/content/test/browser_social_chatwindow.js
+++ b/browser/base/content/test/browser_social_chatwindow.js
@@ -111,16 +111,43 @@ var tests = {
           port.close();
           ensureSocialUrlNotRemembered(chatUrl);
           next();
           break;
       }
     }
     port.postMessage({topic: "test-worker-chat", data: chatUrl});
   },
+  testCloseSelf: function(next) {
+    let chats = document.getElementById("pinnedchats");
+    let port = Social.provider.getWorkerPort();
+    ok(port, "provider has a port");
+    port.onmessage = function (e) {
+      let topic = e.data.topic;
+      switch (topic) {
+        case "test-init-done":
+          port.postMessage({topic: "test-chatbox-open"});
+          break;
+        case "got-chatbox-visibility":
+          is(e.data.result, "shown", "chatbox shown");
+          port.close(); // don't want any more visibility messages.
+          let chat = chats.selectedChat;
+          ok(chat.parentNode, "chat has a parent node before it is closed");
+          // ask it to close itself.
+          let doc = chat.iframe.contentDocument;
+          let evt = doc.createEvent("CustomEvent");
+          evt.initCustomEvent("socialTest-CloseSelf", true, true, {});
+          doc.documentElement.dispatchEvent(evt);
+          ok(!chat.parentNode, "chat is now closed");
+          next();
+          break;
+      }
+    }
+    port.postMessage({topic: "test-init", data: { id: 1 }});
+  },
   testCloseOnLogout: function(next) {
     const chatUrl = "https://example.com/browser/browser/base/content/test/social_chat.html";
     let port = Social.provider.getWorkerPort();
     ok(port, "provider has a port");
     port.postMessage({topic: "test-init"});
     port.onmessage = function (e) {
       let topic = e.data.topic;
       switch (topic) {
--- a/browser/base/content/test/browser_social_flyout.js
+++ b/browser/base/content/test/browser_social_flyout.js
@@ -62,18 +62,44 @@ var tests = {
           let iframe = panel.firstChild;
           let cs = iframe.contentWindow.getComputedStyle(iframe.contentDocument.body);
           is(cs.width, "250px", "should be 250px wide");
           iframe.contentDocument.addEventListener("SocialTest-DoneMakeWider", function _doneHandler() {
             iframe.contentDocument.removeEventListener("SocialTest-DoneMakeWider", _doneHandler, false);
             cs = iframe.contentWindow.getComputedStyle(iframe.contentDocument.body);
             is(cs.width, "500px", "should now be 500px wide");
             panel.hidePopup();
+            port.close();
             next();
           }, false);
           SocialFlyout.dispatchPanelEvent("socialTest-MakeWider");
           break;
       }
     }
     port.postMessage({topic: "test-init"});
+  },
+
+  testCloseSelf: function(next) {
+    let panel = document.getElementById("social-flyout-panel");
+    let port = Social.provider.getWorkerPort();
+    ok(port, "provider has a port");
+    port.onmessage = function (e) {
+      let topic = e.data.topic;
+      switch (topic) {
+        case "test-init-done":
+          port.postMessage({topic: "test-flyout-open"});
+          break;
+        case "got-flyout-visibility":
+          let iframe = panel.firstChild;
+          iframe.contentDocument.addEventListener("SocialTest-DoneCloseSelf", function _doneHandler() {
+            iframe.contentDocument.removeEventListener("SocialTest-DoneCloseSelf", _doneHandler, false);
+            is(panel.state, "closed", "flyout should have closed itself");
+            next();
+          }, false);
+          is(panel.state, "open", "flyout should be open");
+          port.close(); // so we don't get the -visibility message as it hides...
+          SocialFlyout.dispatchPanelEvent("socialTest-CloseSelf");
+          break;
+      }
+    }
+    port.postMessage({topic: "test-init"});
   }
 }
-
--- a/browser/base/content/test/browser_social_mozSocial_API.js
+++ b/browser/base/content/test/browser_social_mozSocial_API.js
@@ -5,17 +5,17 @@
 function test() {
   waitForExplicitFinish();
 
   let manifest = { // normal provider
     name: "provider 1",
     origin: "https://example.com",
     sidebarURL: "https://example.com/browser/browser/base/content/test/social_sidebar.html",
     workerURL: "https://example.com/browser/browser/base/content/test/social_worker.js",
-    iconURL: "chrome://branding/content/icon48.png"
+    iconURL: "https://example.com/browser/browser/base/content/test/moz.png"
   };
   runSocialTestWithProvider(manifest, function (finishcb) {
     runSocialTests(tests, undefined, undefined, finishcb);
   });
 }
 
 var tests = {
   testStatusIcons: function(next) {
@@ -23,22 +23,26 @@ var tests = {
     let gotSidebarMessage = false;
 
     function checkNext() {
       if (iconsReady && gotSidebarMessage)
         triggerIconPanel();
     }
 
     function triggerIconPanel() {
-      let statusIcons = document.getElementById("social-status-iconbox");
-      waitForCondition(function() statusIcons.firstChild && !statusIcons.firstChild.hidden,
-                       function() {
+      let statusIcon = document.querySelector("#social-toolbar-item > box");
+      info("status icon is " + statusIcon);
+      waitForCondition(function() {
+        statusIcon = document.querySelector("#social-toolbar-item > box");
+        info("status icon is " + statusIcon);
+        return !!statusIcon;
+      }, function() {
         // Click the button to trigger its contentPanel
         let panel = document.getElementById("social-notification-panel");
-        EventUtils.synthesizeMouseAtCenter(statusIcons.firstChild, {});
+        EventUtils.synthesizeMouseAtCenter(statusIcon, {});
       }, "Status icon didn't become non-hidden");
     }
 
     let port = Social.provider.getWorkerPort();
     ok(port, "provider has a port");
     port.onmessage = function (e) {
       let topic = e.data.topic;
       switch (topic) {
--- a/browser/base/content/test/browser_social_toolbar.js
+++ b/browser/base/content/test/browser_social_toolbar.js
@@ -37,34 +37,36 @@ var tests = {
     let ambience = {
       name: "testIcon",
       iconURL: "chrome://branding/content/icon48.png",
       contentPanel: "about:blank",
       counter: 42
     };
     Social.provider.setAmbientNotification(ambience);
 
-    let statusIcons = document.getElementById("social-status-iconbox");
-    ok(!statusIcons.firstChild.collapsed, "status icon is visible");
-    ok(!statusIcons.firstChild.lastChild.collapsed, "status value is visible");
-    is(statusIcons.firstChild.lastChild.textContent, "42", "status value is correct");
+    let statusIcon = document.querySelector("#social-toolbar-item > box");
+    waitForCondition(function() {
+      statusIcon = document.querySelector("#social-toolbar-item > box");
+      return !!statusIcon;
+    }, function () {
+      let statusIconLabel = statusIcon.querySelector("label");
+      is(statusIconLabel.value, "42", "status value is correct");
 
-    ambience.counter = 0;
-    Social.provider.setAmbientNotification(ambience);
-    ok(statusIcons.firstChild.lastChild.collapsed, "status value is not visible");
-    is(statusIcons.firstChild.lastChild.textContent, "", "status value is correct");
-    next();
+      ambience.counter = 0;
+      Social.provider.setAmbientNotification(ambience);
+      is(statusIconLabel.value, "", "status value is correct");
+      next();
+    }, "statusIcon was never found");
   },
   testProfileUnset: function(next) {
     Social.provider.updateUserProfile({});
     // check dom values
     let userButton = document.getElementById("social-statusarea-username");
     ok(userButton.hidden, "username is not visible");
-    let ambience = document.getElementById("social-status-iconbox").firstChild;
-    while (ambience) {
-      ok(ambience.collapsed, "ambient icon (" + ambience.id + ") is collapsed");
-      ambience = ambience.nextSibling;
+    let ambientIcons = document.querySelectorAll("#social-toolbar-item > box");
+    for (let ambientIcon of ambientIcons) {
+      ok(ambientIcon.collapsed, "ambient icon (" + ambientIcon.id + ") is collapsed");
     }
     
     next();
   }
 }
 
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/bug792517-2.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+<a href="bug792517.sjs" id="fff">this is a link</a>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/bug792517.sjs
@@ -0,0 +1,13 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function handleRequest(aRequest, aResponse) {
+ aResponse.setStatusLine(aRequest.httpVersion, 200);
+ if (aRequest.hasHeader('Cookie')) {
+   aResponse.write("cookie-present");
+ } else {
+   aResponse.setHeader("Set-Cookie", "foopy=1");
+   aResponse.write("cookie-not-present");
+ }
+}
--- a/browser/base/content/test/head.js
+++ b/browser/base/content/test/head.js
@@ -128,16 +128,20 @@ function runSocialTestWithProvider(manif
   SocialService.addProvider(manifest, function(provider) {
     info("runSocialTestWithProvider: provider added");
     oldProvider = Social.provider;
     Social.provider = provider;
 
     // Now that we've set the UI's provider, enable the social functionality
     Services.prefs.setBoolPref("social.enabled", true);
 
+    // Need to re-call providerReady since it is actually called before the test
+    // framework is loaded and the provider state won't be set in the browser yet.
+    SocialUI._providerReady();
+
     registerCleanupFunction(function () {
       // if one test happens to fail, it is likely finishSocialTest will not
       // be called, causing most future social tests to also fail as they
       // attempt to add a provider which already exists - so work
       // around that by also attempting to remove the test provider.
       try {
         SocialService.removeProvider(provider.origin, finish);
       } catch (ex) {
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/plugin_two_types.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head><meta charset="utf-8"/></head>
+<body>
+<embed id="test" style="width: 200px; height: 200px" type="application/x-test"/>
+<embed id="secondtestA" style="width: 200px; height: 200px" type="application/x-second-test"/>
+<embed id="secondtestB" style="width: 200px; height: 200px" type="application/x-second-test"/>
+</body>
+</html>
--- a/browser/base/content/test/social_chat.html
+++ b/browser/base/content/test/social_chat.html
@@ -9,14 +9,17 @@
       window.addEventListener("socialFrameShow", function(e) {
         var port = navigator.mozSocial.getWorker().port;
         port.postMessage({topic: "chatbox-visibility", result: "shown"});
       }, false);
       window.addEventListener("socialFrameHide", function(e) {
         var port = navigator.mozSocial.getWorker().port;
         port.postMessage({topic: "chatbox-visibility", result: "hidden"});
       }, false);
+      window.addEventListener("socialTest-CloseSelf", function(e) {
+        window.close();
+      }, false);
     </script>
   </head>
   <body onload="pingWorker();">
     <p>This is a test social chat window.</p>
   </body>
 </html>
--- a/browser/base/content/test/social_flyout.html
+++ b/browser/base/content/test/social_flyout.html
@@ -16,14 +16,20 @@
       }, false);
       window.addEventListener("socialTest-MakeWider", function(e) {
         document.body.setAttribute("style", "width: 500px;");
         document.body.offsetWidth; // force a layout flush
         var evt = document.createEvent("CustomEvent");
         evt.initCustomEvent("SocialTest-DoneMakeWider", true, true, {});
         document.documentElement.dispatchEvent(evt);
       }, false);
+      window.addEventListener("socialTest-CloseSelf", function(e) {
+        window.close();
+        var evt = document.createEvent("CustomEvent");
+        evt.initCustomEvent("SocialTest-DoneCloseSelf", true, true, {});
+        document.documentElement.dispatchEvent(evt);
+      }, false);
     </script>
   </head>
   <body style="max-width: 250px;" onload="pingWorker();">
     <p>This is a test social flyout panel.</p>
   </body>
 </html>
--- a/browser/base/content/test/social_worker.js
+++ b/browser/base/content/test/social_worker.js
@@ -82,17 +82,17 @@ onconnect = function(e) {
           displayName: "Kuma Lisa",
           profileURL: "http://en.wikipedia.org/wiki/Kuma_Lisa"
         };
         port.postMessage({topic: "social.user-profile", data: profile});
         break;
       case "test-ambient-notification":
         let icon = {
           name: "testIcon",
-          iconURL: "chrome://branding/content/icon48.png",
+          iconURL: "chrome://browser/skin/Info.png",
           contentPanel: "https://example.com/browser/browser/base/content/test/social_panel.html",
           counter: 1
         };
         apiPort.postMessage({topic: "social.ambient-notification", data: icon});
         break;
       case "test-isVisible":
         sidebarPort.postMessage({topic: "test-isVisible"});
         break;
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -1413,16 +1413,133 @@
           this.identity.selected = chosenId;
           this.onIdentitySelected();
         ]]></body>
       </method>
 
     </implementation>
   </binding>
 
+  <binding id="center-item">
+    <content align="center">
+      <xul:vbox flex="1" class="center-item-box"
+                xbl:inherits="warn,showseparator,padbottom">
+        <xul:hbox flex="1" align="center">
+          <xul:image class="center-item-icon"
+                     xbl:inherits="src=itemicon"/>
+          <xul:description class="center-item-label"
+                           xbl:inherits="xbl:text=itemtext"/>
+          <xul:spacer flex="1"/>
+          <xul:button class="popup-notification-menubutton center-item-button"
+                      oncommand="document.getBindingParent(this).runCallback();"
+                      xbl:inherits="label=buttonlabel"/>
+        </xul:hbox>
+        <xul:hbox flex="1" align="center" class="center-item-warning">
+          <xul:image class="center-item-warning-icon"/>
+          <xul:label class="center-item-warning-description" xbl:inherits="xbl:text=warningText"/>
+          <xul:label xbl:inherits="href=updateLink" value="&checkForUpdates;" class="text-link"/>
+          <xul:spacer flex="1"/>
+        </xul:hbox>
+      </xul:vbox>
+    </content>
+    <resources>
+      <stylesheet src="chrome://global/skin/notification.css"/>
+    </resources>
+    <implementation>
+      <field name="action"></field>
+      <method name="runCallback">
+        <body><![CDATA[
+          let action = this.action;
+          action.callback();
+          let cas = action.popupnotification.notification.options.centerActions;
+          cas.splice(cas.indexOf(action), 1);
+          PopupNotifications._dismiss();
+        ]]></body>
+      </method>
+    </implementation>
+  </binding>
+
+  <binding id="click-to-play-plugins-notification" extends="chrome://global/content/bindings/notification.xml#popup-notification">
+    <content align="start" class="click-to-play-plugins-notification-content">
+      <xul:hbox flex="1">
+        <xul:vbox class="click-to-play-plugins-notification-icon-box" flex="1">
+          <xul:image class="popup-notification-icon"
+                     xbl:inherits="popupid,src=icon"/>
+          <xul:spacer flex="1"/>
+        </xul:vbox>
+        <xul:spacer class="click-to-play-plugins-notification-separator"/>
+        <xul:vbox flex="1" class="popup-notification-main-box"
+                  xbl:inherits="popupid">
+          <xul:box class="click-to-play-plugins-notification-description-box" flex="1">
+            <xul:description xbl:inherits="xbl:text=label"/>
+          </xul:box>
+          <xul:spacer class="click-to-play-plugins-notification-separator"/>
+          <xul:vbox class="click-to-play-plugins-notification-center-box">
+            <children includes="popupnotification-centeritem"/>
+          </xul:vbox>
+          <xul:spacer class="click-to-play-plugins-notification-separator"/>
+          <xul:hbox class="click-to-play-plugins-notification-button-container"
+                    pack="end" align="center">
+            <xul:button anonid="button"
+                        class="popup-notification-menubutton"
+                        type="menu-button"
+                        xbl:inherits="oncommand=buttoncommand,label=buttonlabel,accesskey=buttonaccesskey">
+              <xul:menupopup anonid="menupopup"
+                             xbl:inherits="oncommand=menucommand">
+                <children/>
+                <xul:menuitem class="menuitem-iconic popup-notification-closeitem"
+                              label="&closeNotificationItem.label;"
+                              xbl:inherits="oncommand=closeitemcommand"/>
+              </xul:menupopup>
+            </xul:button>
+          </xul:hbox>
+        </xul:vbox>
+      </xul:hbox>
+    </content>
+    <resources>
+      <stylesheet src="chrome://global/skin/notification.css"/>
+    </resources>
+    <implementation>
+      <field name="button" readonly="true">
+        document.getAnonymousElementByAttribute(this, "anonid", "button");
+      </field>
+      <field name="menupopup" readonly="true">
+        document.getAnonymousElementByAttribute(this, "anonid", "menupopup");
+      </field>
+      <constructor><![CDATA[
+        const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+        let popupnotification = this;
+        let item = null;
+        let prev = null;
+        this.notification.options.centerActions.forEach(function(action) {
+          action.popupnotification = popupnotification;
+          item = document.createElementNS(XUL_NS, "popupnotification-centeritem");
+          item.action = action;
+          item.setAttribute("itemtext", action.message);
+          item.setAttribute("buttonlabel", action.label);
+          item.setAttribute("warn", action.warn);
+          item.setAttribute("warningText", action.warningText);
+          item.setAttribute("updateLink", action.updateLink);
+          if (prev &&
+              (prev.getAttribute("warn") == "true" ||
+               item.getAttribute("warn") == "true")) {
+            item.setAttribute("showseparator", true);
+            if (prev.getAttribute("warn") != "true") {
+              prev.setAttribute("padbottom", true);
+            }
+          }
+          popupnotification.appendChild(item);
+          prev = item;
+        });
+        if (item != null) {
+          item.setAttribute("padbottom", "true");
+        }
+      ]]></constructor>
+    </implementation>
+  </binding>
 
   <binding id="splitmenu">
     <content>
       <xul:hbox anonid="menuitem" flex="1"
                 class="splitmenu-menuitem"
                 xbl:inherits="iconic,label,disabled,onclick=oncommand,_moz-menuactive=active"/>
       <xul:menu anonid="menu" class="splitmenu-menu"
                 xbl:inherits="disabled,_moz-menuactive=active"
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -104,17 +104,18 @@ function openUILink(url, event, aIgnoreB
     aIgnoreButton = params.ignoreButton;
     aIgnoreAlt = params.ignoreAlt;
     delete params.ignoreButton;
     delete params.ignoreAlt;
   } else {
     params = {
       allowThirdPartyFixup: aAllowThirdPartyFixup,
       postData: aPostData,
-      referrerURI: aReferrerURI
+      referrerURI: aReferrerURI,
+      initiatingDoc: event.target.ownerDocument
     };
   }
 
   let where = whereToOpenLink(event, aIgnoreButton, aIgnoreAlt);
   openUILinkIn(url, where, params);
 }
 
 
@@ -219,19 +220,20 @@ function openLinkIn(url, where, params) 
   var aPostData             = params.postData;
   var aCharset              = params.charset;
   var aReferrerURI          = params.referrerURI;
   var aRelatedToCurrent     = params.relatedToCurrent;
   var aInBackground         = params.inBackground;
   var aDisallowInheritPrincipal = params.disallowInheritPrincipal;
   // Currently, this parameter works only for where=="tab" or "current"
   var aIsUTF8               = params.isUTF8;
+  var aInitiatingDoc        = params.initiatingDoc;
 
   if (where == "save") {
-    saveURL(url, null, null, true, null, aReferrerURI);
+    saveURL(url, null, null, true, null, aReferrerURI, aInitiatingDoc);
     return;
   }
   const Cc = Components.classes;
   const Ci = Components.interfaces;
 
   var w = getTopWin();
   if ((where == "tab" || where == "tabshifted") &&
       w && !w.toolbar.visible) {
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -1420,23 +1420,23 @@ let PlacesControllerDragHelper = {
       catch (e) {
         return false;
       }
 
       // Only bookmarks and urls can be dropped into tag containers.
       if (ip.isTag && ip.orientation == Ci.nsITreeView.DROP_ON &&
           dragged.type != PlacesUtils.TYPE_X_MOZ_URL &&
           (dragged.type != PlacesUtils.TYPE_X_MOZ_PLACE ||
-           dragged.uri.startsWith("place:")))
+           (dragged.uri && dragged.uri.startsWith("place:")) ))
         return false;
 
       // The following loop disallows the dropping of a folder on itself or
       // on any of its descendants.
       if (dragged.type == PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER ||
-          dragged.uri.startsWith("place:")) {
+          (dragged.uri && dragged.uri.startsWith("place:")) ) {
         let parentId = ip.itemId;
         while (parentId != PlacesUtils.placesRootId) {
           if (dragged.concreteId == parentId || dragged.id == parentId)
             return false;
           parentId = PlacesUtils.bookmarks.getFolderIdForItem(parentId);
         }
       }
     }
@@ -1629,17 +1629,23 @@ function goUpdatePlacesCommands() {
   updatePlacesCommand("placesCmd_paste");
   updatePlacesCommand("placesCmd_delete");
 }
 
 function doGetPlacesControllerForCommand(aCommand)
 {
   // A context menu may be built for non-focusable views.  Thus, we first try
   // to look for a view associated with document.popupNode
-  let popupNode = document.popupNode;
+  let popupNode; 
+  try {
+    popupNode = document.popupNode;
+  } catch (e) {
+    // The document went away (bug 797307).
+    return null;
+  }
   if (popupNode) {
     let view = PlacesUIUtils.getViewForNode(popupNode);
     if (view && view._contextMenuShown)
       return view.controllers.getControllerForCommand(aCommand);
   }
 
   // When we're not building a context menu, only focusable views
   // are possible.  Thus, we can safely use the command dispatcher.
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadmonitor.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadmonitor.js
@@ -24,16 +24,17 @@ function test() {
     if (acceptDialog-- > 0)
       dialogWin.document.documentElement.getButton("accept").click();
   }
 
   Services.obs.addObserver(promptObserver, "common-dialog-loaded", false);
 
   // Add a new download
   let [file, persist] = addDownload(dm, {
+    isPrivate: window.gPrivateBrowsingUI.privateWindow,
     resultFileName: "pbtest-1",
     downloadName: "PB Test 1"
   });
 
   // Make sure that the download is being displayed in the monitor panel
   if (!DownloadMonitorPanel.inited())
     DownloadMonitorPanel.init();
   else
@@ -46,16 +47,17 @@ function test() {
   is(confirmCalls, 1, "One prompt was accepted");
   ok(pb.privateBrowsingEnabled, "The private browsing transition was successful");
 
   executeSoon(function () {
     ok(panel.hidden, "The download panel should be hidden when entering the private browsing mode");
 
     // Add a new download
     let [file2, persist2] = addDownload(dm, {
+      isPrivate: window.gPrivateBrowsingUI.privateWindow,
       resultFileName: "pbtest-2",
       downloadName: "PB Test 2"
     });
 
     // Update the panel
     DownloadMonitorPanel.updateStatus();
 
     // Make sure that the panel is visible
@@ -93,16 +95,17 @@ function test() {
  * (Copied from toolkit/componentns/downloads/test/unit/head_download_manager.js)
  * @param aParams (optional): an optional object which contains the function
  *                            parameters:
  *                              resultFileName: leaf node for the target file
  *                              targetFile: nsIFile for the target (overrides resultFileName)
  *                              sourceURI: the download source URI
  *                              downloadName: the display name of the download
  *                              runBeforeStart: a function to run before starting the download
+ *                              isPrivate: whether the download is private
  */
 function addDownload(dm, aParams)
 {
   if (!aParams)
     aParams = {};
   if (!("resultFileName" in aParams))
     aParams.resultFileName = "download.result";
   if (!("targetFile" in aParams)) {
@@ -123,17 +126,17 @@ function addDownload(dm, aParams)
                 .createInstance(Ci.nsIWebBrowserPersist);
   persist.persistFlags = nsIWBP.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
                          nsIWBP.PERSIST_FLAGS_BYPASS_CACHE |
                          nsIWBP.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
 
   let dl = dm.addDownload(Ci.nsIDownloadManager.DOWNLOAD_TYPE_DOWNLOAD,
                           createURI(aParams.sourceURI),
                           createURI(aParams.targetFile), aParams.downloadName, null,
-                          Math.round(Date.now() * 1000), null, persist);
+                          Math.round(Date.now() * 1000), null, persist, aParams.isPrivate);
 
   // This will throw if it isn't found, and that would mean test failure, so no
   // try catch block
   let test = dm.getDownload(dl.id);
 
   aParams.runBeforeStart.call(undefined, dl);
 
   persist.progressListener = dl.QueryInterface(Ci.nsIWebProgressListener);
--- a/browser/components/sessionstore/test/Makefile.in
+++ b/browser/components/sessionstore/test/Makefile.in
@@ -43,22 +43,17 @@ MOCHITEST_BROWSER_FILES = \
 	browser_423132_sample.html \
 	browser_447951.js \
 	browser_447951_sample.html \
 	browser_448741.js \
 	browser_454908.js \
 	browser_454908_sample.html \
 	browser_456342.js \
 	browser_456342_sample.xhtml \
-	browser_459906.js \
-	browser_459906_empty.html \
-	browser_459906_sample.html \
 	browser_461634.js \
-	browser_461743.js \
-	browser_461743_sample.html \
 	browser_463205.js \
 	browser_463205_helper.html \
 	browser_463205_sample.html \
 	browser_463206.js \
 	browser_463206_sample.html \
 	browser_464199.js \
 	browser_465215.js \
 	browser_465223.js \
@@ -134,16 +129,22 @@ MOCHITEST_BROWSER_FILES = \
 	browser_701377.js \
 	browser_705597.js \
 	browser_707862.js \
 	browser_739531.js \
 	browser_739531_sample.html \
 	browser_739805.js \
 	$(NULL)
 
+$(warning browser_459906.js is disabled for intermittent failures. Bug 766044)
+#	browser_459906_empty.html \
+#	browser_459906_sample.html \
+$(warning browser_461743.js is disabled for intermittent failures. Bug 765389)
+#	browser_461743_sample.html \
+
 # Disabled on Windows for frequent intermittent failures
 ifneq ($(OS_ARCH), WINNT)
 MOCHITEST_FILES += \
 	browser_464620_a.js \
 	browser_464620_a.html \
 	browser_464620_b.js \
 	browser_464620_b.html \
 	browser_464620_xd.html \
--- a/browser/config/tooltool-manifests/linux32/clang.manifest
+++ b/browser/config/tooltool-manifests/linux32/clang.manifest
@@ -4,14 +4,14 @@
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 69252183,
-"digest": "565fef702482b2bf9de3cdb87273fb41ce2c746f586bbe7e7a9ba4f3c796e525f41acd4b10e9f91c986c20b0435bcad71d7203fa2139ab3a6617e62ac96818f0",
+"size": 63128096,
+"digest": "4cd01a86dba4e62587bd97a7aca1fada8b532683ac8b2f96aacf437083dc2161d56d4d7c432a894d7b11e9aabfd7a740a073247c49334b7f63e973f562ddd633",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/linux64/clang.manifest
+++ b/browser/config/tooltool-manifests/linux64/clang.manifest
@@ -4,14 +4,14 @@
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 65214493,
-"digest": "9584ec012d55e2c755cd7cc83e574a7a565e93993e9f705462890f25914401dd3e92893b3a5f76a856d77037a7f1843a9fb7b65dc77c80f8e1a32210df0dd5fb",
+"size": 59573143,
+"digest": "f4a025d7c495b47a540b2c94e960fce9740e8f3eb182f6f703c049d22d6a212a8de62f6876d28a61266da1ff2a50332658d3c3433075c26c5a801538cd5ec7d5",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/macosx32/releng.manifest
+++ b/browser/config/tooltool-manifests/macosx32/releng.manifest
@@ -4,14 +4,14 @@
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 57746646,
-"digest": "e1d76c4c9d12edfba0d7c8db4cd37669d90e6824ee3d1f949dddc0f168815b115f9809a335d3ee0025432df995f898d9dc7545ee89e499944ed84e2407fc54b8",
+"size": 52539217,
+"digest": "88eb1c08043919a224da1d25b37a5b0c5719f3547ddfc1b456c577d5fa66564706b6e25853fedefaa08ca8fb1dff765d7eb747bbe99ed81c09afbfd43b222e96",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/macosx64/releng.manifest
+++ b/browser/config/tooltool-manifests/macosx64/releng.manifest
@@ -4,14 +4,14 @@
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 57746646,
-"digest": "e1d76c4c9d12edfba0d7c8db4cd37669d90e6824ee3d1f949dddc0f168815b115f9809a335d3ee0025432df995f898d9dc7545ee89e499944ed84e2407fc54b8",
+"size": 52539217,
+"digest": "88eb1c08043919a224da1d25b37a5b0c5719f3547ddfc1b456c577d5fa66564706b6e25853fedefaa08ca8fb1dff765d7eb747bbe99ed81c09afbfd43b222e96",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/devtools/debugger/DebuggerUI.jsm
+++ b/browser/devtools/debugger/DebuggerUI.jsm
@@ -6,17 +6,17 @@
 "use strict";
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 const DBG_XUL = "chrome://browser/content/debugger.xul";
 const DBG_STRINGS_URI = "chrome://browser/locale/devtools/debugger.properties";
-const REMOTE_PROFILE_NAME = "_remote-debug";
+const CHROME_DEBUGGER_PROFILE_NAME = "_chrome-debugger-profile";
 const TAB_SWITCH_NOTIFICATION = "debugger-tab-switch";
 
 Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/FileUtils.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 let EXPORTED_SYMBOLS = ["DebuggerUI"];
@@ -484,19 +484,19 @@ ChromeDebuggerProcess.prototype = {
    * Initializes a profile for the remote debugger process.
    */
   _initProfile: function RDP__initProfile() {
     let profileService = Cc["@mozilla.org/toolkit/profile-service;1"]
       .createInstance(Ci.nsIToolkitProfileService);
 
     let dbgProfileName;
     try {
-      dbgProfileName = profileService.selectedProfile.name + REMOTE_PROFILE_NAME;
+      dbgProfileName = profileService.selectedProfile.name + CHROME_DEBUGGER_PROFILE_NAME;
     } catch(e) {
-      dbgProfileName = REMOTE_PROFILE_NAME;
+      dbgProfileName = CHROME_DEBUGGER_PROFILE_NAME;
       Cu.reportError(e);
     }
 
     this._dbgProfile = profileService.createProfile(null, null, dbgProfileName);
     profileService.flush();
   },
 
   /**
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -1348,16 +1348,26 @@ SourceScripts.prototype = {
    *        The content type of the source script.
    * @param object aOptions [optional]
    *        Additional options for showing the script. Supported options:
    *        - targetLine: place the editor at the given line number.
    */
   _onLoadSourceFinished:
   function SS__onLoadSourceFinished(aScriptUrl, aSourceText, aContentType, aOptions) {
     let element = DebuggerView.Scripts.getScriptByLocation(aScriptUrl);
+
+    // Tab navigated before we got a chance to finish loading and displaying
+    // the source. The outcome is that the expected url is not present anymore
+    // in the scripts container, hence the original script object coming from
+    // the active thread no longer exists. There's really nothing that needs
+    // to be done in this case, nor something that can be currently avoided.
+    if (!element) {
+      return;
+    }
+
     let script = element.getUserData("sourceScript");
 
     script.loaded = true;
     script.text = aSourceText;
     script.contentType = aContentType;
     element.setUserData("sourceScript", script, null);
 
     if (aOptions.silent) {
--- a/browser/devtools/debugger/debugger.xul
+++ b/browser/devtools/debugger/debugger.xul
@@ -78,18 +78,17 @@
         <toolbarbutton id="step-in"
                        class="devtools-toolbarbutton"
                        tabindex="0"/>
         <toolbarbutton id="step-out"
                        class="devtools-toolbarbutton"
                        tabindex="0"/>
       </hbox>
       <menulist id="scripts" class="devtools-menulist"
-                sizetopopup="always"
-                label="&debuggerUI.emptyScriptText;"/>
+                sizetopopup="always"/>
       <textbox id="scripts-search" type="search"
                class="devtools-searchinput"/>
       <checkbox id="pause-exceptions"
                 type="checkbox"
                 tabindex="0"
                 label="&debuggerUI.pauseExceptions;"/>
       <spacer flex="1"/>
 #ifndef XP_MACOSX
--- a/browser/devtools/debugger/test/Makefile.in
+++ b/browser/devtools/debugger/test/Makefile.in
@@ -7,17 +7,16 @@ topsrcdir       = @top_srcdir@
 srcdir          = @srcdir@
 VPATH           = @srcdir@
 relativesrcdir  = @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_BROWSER_TESTS = \
 	browser_dbg_leaktest.js \
-	browser_dbg_createRemote.js \
 	browser_dbg_createChrome.js \
 	browser_dbg_debugger-tab-switch.js \
 	browser_dbg_debugger-tab-switch-window.js \
 	browser_dbg_debuggerstatement.js \
 	browser_dbg_listtabs.js \
 	browser_dbg_tabactor-01.js \
 	browser_dbg_tabactor-02.js \
 	browser_dbg_globalactor-01.js \
@@ -69,16 +68,25 @@ MOCHITEST_BROWSER_TESTS = \
 	browser_dbg_pause-exceptions.js \
 	browser_dbg_multiple-windows.js \
 	browser_dbg_menustatus.js \
 	browser_dbg_bfcache.js \
 	browser_dbg_breakpoint-new-script.js \
 	head.js \
 	$(NULL)
 
+# Disabled on Windows for frequent intermittent failures
+ifneq ($(OS_ARCH), WINNT)
+MOCHITEST_BROWSER_TESTS += \
+	browser_dbg_createRemote.js \
+	$(NULL)
+else
+$(warning browser_dbg_createRemote.js is disabled on Windows for intermittent failures. Bug 753225)
+endif
+
 MOCHITEST_BROWSER_PAGES = \
 	browser_dbg_tab1.html \
 	browser_dbg_tab2.html \
 	browser_dbg_debuggerstatement.html \
 	browser_dbg_stack.html \
 	browser_dbg_script-switching.html \
 	test-script-switching-01.js \
 	test-script-switching-02.js \
--- a/browser/devtools/debugger/test/browser_dbg_createRemote.js
+++ b/browser/devtools/debugger/test/browser_dbg_createRemote.js
@@ -2,29 +2,35 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // Tests that a remote debugger can be created in a new window.
 
 var gWindow = null;
 var gTab = null;
+var gRemoteHost = null;
 var gRemotePort = null;
+var gRemoteTimeout = null;
 var gAutoConnect = null;
 
 const TEST_URL = EXAMPLE_URL + "browser_dbg_iframes.html";
 
 function test() {
   debug_remote(TEST_URL, function(aTab, aDebuggee, aWindow) {
     gTab = aTab;
     gWindow = aWindow;
     let gDebugger = gWindow.contentWindow;
 
+    info("Current remote host: " +
+      Services.prefs.getCharPref("devtools.debugger.remote-host"));
     info("Current remote port: " +
       Services.prefs.getIntPref("devtools.debugger.remote-port"));
+    info("Current remote timeout: " +
+      Services.prefs.getIntPref("devtools.debugger.remote-timeout"));
     info("Current autoconnect flag: " +
       Services.prefs.getBoolPref("devtools.debugger.remote-autoconnect"));
 
     is(gDebugger.document.getElementById("close").getAttribute("hidden"), "true",
       "The close button should be hidden in a remote debugger.");
 
     is(gDebugger.DebuggerController.activeThread.paused, false,
       "Should be running after debug_remote.");
@@ -61,28 +67,32 @@ function test() {
   },
   function beforeTabAdded() {
     if (!DebuggerServer.initialized) {
       DebuggerServer.init(function() { return true; });
       DebuggerServer.addBrowserActors();
     }
     DebuggerServer.closeListener();
 
+    gRemoteHost = Services.prefs.getCharPref("devtools.debugger.remote-host");
     gRemotePort = Services.prefs.getIntPref("devtools.debugger.remote-port");
+    gRemoteTimeout = Services.prefs.getIntPref("devtools.debugger.remote-timeout");
     gAutoConnect = Services.prefs.getBoolPref("devtools.debugger.remote-autoconnect");
 
     // Open the listener at some point in the future to test automatic reconnect.
-    openListener(gRemotePort + 1);
+    openListener(gRemoteHost, gRemotePort + 1, gRemoteTimeout / 10);
   });
 }
 
 let attempts = 0;
 
-function openListener(port) {
+function openListener(host, port, timeout) {
+  Services.prefs.setCharPref("devtools.debugger.remote-host", host);
   Services.prefs.setIntPref("devtools.debugger.remote-port", port);
+  Services.prefs.setIntPref("devtools.debugger.remote-timeout", timeout);
   Services.prefs.setBoolPref("devtools.debugger.remote-autoconnect", true);
 
   info("Attempting to open a new listener on port " + port);
   try {
     info("Closing listener...");
     DebuggerServer.closeListener();
     info("Opening listener...");
     DebuggerServer.openListener(port);
@@ -96,16 +106,20 @@ function openListener(port) {
       openListener(port);
     } else {
       ok(false, "Timed out while opening a listener.");
     }
   }
 }
 
 registerCleanupFunction(function() {
+  Services.prefs.setCharPref("devtools.debugger.remote-host", gRemoteHost);
   Services.prefs.setIntPref("devtools.debugger.remote-port", gRemotePort);
+  Services.prefs.setIntPref("devtools.debugger.remote-timeout", gRemoteTimeout);
   Services.prefs.setBoolPref("devtools.debugger.remote-autoconnect", gAutoConnect);
   removeTab(gTab);
   gWindow = null;
   gTab = null;
+  gRemoteHost = null;
   gRemotePort = null;
+  gRemoteTimeout = null;
   gAutoConnect = null;
 });
--- a/browser/devtools/markupview/MarkupView.jsm
+++ b/browser/devtools/markupview/MarkupView.jsm
@@ -94,17 +94,17 @@ MarkupView.prototype = {
   },
 
   /**
    * Highlight the given element in the markup panel.
    */
   _onSelect: function MT__onSelect()
   {
     if (this._inspector.selection) {
-      this.showNode(this._inspector.selection);
+      this.showNode(this._inspector.selection, true);
     }
     this.selectNode(this._inspector.selection);
   },
 
   /**
    * Create a TreeWalker to find the next/previous
    * node for selection.
    */
@@ -249,17 +249,17 @@ MarkupView.prototype = {
    */
   navigate: function MT__navigate(aContainer, aIgnoreFocus)
   {
     if (!aContainer) {
       return;
     }
 
     let node = aContainer.node;
-    this.showNode(node);
+    this.showNode(node, false);
     this.selectNode(node);
 
     if (this._inspector._IUI.highlighter.isNodeHighlightable(node)) {
       this._inspector._IUI.select(node, true, false, "treepanel");
       this._inspector._IUI.highlighter.highlight(node);
     }
 
     if (!aIgnoreFocus) {
@@ -338,25 +338,25 @@ MarkupView.prototype = {
     }
     this._inspector.emit("markupmutation");
   },
 
   /**
    * Make sure the given node's parents are expanded and the
    * node is scrolled on to screen.
    */
-  showNode: function MT_showNode(aNode)
+  showNode: function MT_showNode(aNode, centered)
   {
     this.importNode(aNode);
     let walker = documentWalker(aNode);
     let parent;
     while (parent = walker.parentNode()) {
       this.expandNode(parent);
     }
-    LayoutHelpers.scrollIntoViewIfNeeded(this._containers.get(aNode).editor.elt, false);
+    LayoutHelpers.scrollIntoViewIfNeeded(this._containers.get(aNode).editor.elt, centered);
   },
 
   /**
    * Expand the container's children.
    */
   _expandContainer: function MT__expandContainer(aContainer)
   {
     if (aContainer.hasChildren && !aContainer.expanded) {
--- a/browser/devtools/markupview/markup-view.xhtml
+++ b/browser/devtools/markupview/markup-view.xhtml
@@ -4,36 +4,37 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <!DOCTYPE html>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
   <link rel="stylesheet" href="chrome://browser/content/devtools/markup-view.css" type="text/css"/>
   <link rel="stylesheet" href="chrome://browser/skin/devtools/markup-view.css" type="text/css"/>
+  <link rel="stylesheet" href="chrome://browser/skin/devtools/common.css" type="text/css"/>
 </head>
 <body role="application">
   <div id="root"></div>
   <div id="templates" style="display:none">
     <ul>
       <li id="template-container" save="${elt}" class="container"><span save="${expander}" class="expander"></span><span save="${codeBox}" class="codebox"><ul save="${children}" class="children"></ul></span></li>
     </ul>
 
-    <span id="template-element" save="${elt}" class="editor"><span>&lt;</span><span save="${tag}" class="tagname"></span><span save="${attrList}"></span><span save="${newAttr}" class="newattr" tabindex="0"></span>&gt;</span>
+    <span id="template-element" save="${elt}" class="editor"><span>&lt;</span><span save="${tag}" class="tagname devtools-theme-tagname"></span><span save="${attrList}"></span><span save="${newAttr}" class="newattr" tabindex="0"></span>&gt;</span>
 
-    <span id="template-attribute" save="${attr}" data-attr="${attrName}" class="attreditor" style="display:none"> <span class="editable" save="${inner}" tabindex="0"><span save="${name}" class="attrname"></span>=&quot;<span save="${val}" class="attrvalue"></span>&quot;</span></span>
+    <span id="template-attribute" save="${attr}" data-attr="${attrName}" class="attreditor" style="display:none"> <span class="editable" save="${inner}" tabindex="0"><span save="${name}" class="attrname devtools-theme-attrname"></span>=&quot;<span save="${val}" class="attrvalue devtools-theme-attrvalue"></span>&quot;</span></span>
 
-    <span id="template-text" save="${elt}" class="editor">
+    <span id="template-text" save="${elt}" class="editor text">
       <pre save="${value}" style="display:inline-block;" tabindex="0"></pre>
     </span>
 
-    <span id="template-comment" save="${elt}" class="editor comment">
+    <span id="template-comment" save="${elt}" class="editor comment devtools-theme-comment">
       <span>&lt;!--</span><pre save="${value}" style="display:inline-block;" tabindex="0"></pre><span>--&gt;</span>
     </span>
 
-    <span id="template-elementClose" save="${closeElt}">&lt;/<span save="${closeTag}" class="tagname"></span>&gt;</span>
+    <span id="template-elementClose" save="${closeElt}">&lt;/<span save="${closeTag}" class="tagname devtools-theme-tagname"></span>&gt;</span>
    </div>
    <div id="previewbar" class="disabled">
      <div id="preview"/>
      <div id="viewbox"/>
    </div>
 </body>
 </html>
--- a/browser/devtools/styleeditor/StyleEditor.jsm
+++ b/browser/devtools/styleeditor/StyleEditor.jsm
@@ -904,16 +904,23 @@ StyleEditor.prototype = {
         if (!Components.isSuccessCode(aStatusCode)) {
           return this._signalError(LOAD_ERROR);
         }
 
         this._onSourceLoad(chunks.join(""), channelCharset);
       }.bind(this)
     };
 
+    if (channel instanceof Ci.nsIPrivateBrowsingChannel) {
+      let contentWin = this.contentDocument.defaultView;
+      let loadContext = contentWin.QueryInterface(Ci.nsIInterfaceRequestor)
+                          .getInterface(Ci.nsIWebNavigation)
+                          .QueryInterface(Ci.nsILoadContext);
+      channel.setPrivate(loadContext.usePrivateBrowsing);
+    }
     channel.loadFlags = channel.LOAD_FROM_CACHE;
     channel.asyncOpen(streamListener, null);
   },
 
   /**
    * Called when source has been loaded.
    *
    * @param string aSourceText
--- a/browser/devtools/styleeditor/test/Makefile.in
+++ b/browser/devtools/styleeditor/test/Makefile.in
@@ -17,16 +17,17 @@ include $(topsrcdir)/config/rules.mk
                  browser_styleeditor_cmd_edit.js \
                  browser_styleeditor_cmd_edit.html \
                  browser_styleeditor_import.js \
                  browser_styleeditor_init.js \
                  browser_styleeditor_loading.js \
                  browser_styleeditor_new.js \
                  browser_styleeditor_passedinsheet.js \
                  browser_styleeditor_pretty.js \
+                 browser_styleeditor_private.js \
                  browser_styleeditor_readonly.js \
                  browser_styleeditor_reopen.js \
                  browser_styleeditor_sv_keynav.js \
                  browser_styleeditor_sv_resize.js \
                  four.html \
                  head.js \
                  helpers.js \
                  media.html \
@@ -35,12 +36,14 @@ include $(topsrcdir)/config/rules.mk
                  resources_inpage.jsi \
                  resources_inpage1.css \
                  resources_inpage2.css \
                  simple.css \
                  simple.css.gz \
                  simple.css.gz^headers^ \
                  simple.gz.html \
                  simple.html \
+                 test_private.html \
+                 test_private.css \
                  $(NULL)
 
 libs::	$(_BROWSER_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleeditor/test/browser_styleeditor_private.js
@@ -0,0 +1,63 @@
+/* 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/. */
+
+// This test makes sure that the style editor does not store any
+// content CSS files in the permanent cache when opened from PB mode.
+
+function checkDiskCacheFor(host) {
+  let visitor = {
+    visitDevice: function(deviceID, deviceInfo) {
+      if (deviceID == "disk")
+        info("disk device contains " + deviceInfo.entryCount + " entries");
+      return deviceID == "disk";
+    },
+    
+    visitEntry: function(deviceID, entryInfo) {
+      info(entryInfo.key);
+      is(entryInfo.key.contains(host), false, "web content present in disk cache");
+    }
+  };
+  cache.visitEntries(visitor);
+}
+
+const TEST_HOST = 'mochi.test:8888';
+
+var cache = Cc["@mozilla.org/network/cache-service;1"]
+              .getService(Ci.nsICacheService);
+
+function test() {
+  waitForExplicitFinish();
+  
+  gPrefService.setBoolPref("browser.privatebrowsing.keep_current_session", true);
+  let pb = Cc["@mozilla.org/privatebrowsing;1"].
+           getService(Ci.nsIPrivateBrowsingService);
+  pb.privateBrowsingEnabled = true;
+  
+  function checkCache() {
+    checkDiskCacheFor(TEST_HOST);
+    pb.privateBrowsingEnabled = false;
+    gPrefService.clearUserPref("browser.privatebrowsing.keep_current_session");
+    finish();
+  }
+
+  gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
+    gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
+    cache.evictEntries(Ci.nsICache.STORE_ANYWHERE);
+    launchStyleEditorChrome(function(aChrome) {
+      aChrome.addChromeListener({
+        onEditorAdded: function(aChrome, aEditor) {
+          if (aEditor.isLoaded) {
+            checkCache();            
+          } else {
+            aEditor.addActionListener({
+              onLoad: checkCache
+            });
+          }
+        }
+      });
+    });
+  }, true);
+
+  content.location = 'http://' + TEST_HOST + '/browser/browser/devtools/styleeditor/test/test_private.html';
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleeditor/test/test_private.css
@@ -0,0 +1,3 @@
+body {
+    background-color: red;
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleeditor/test/test_private.html
@@ -0,0 +1,7 @@
+<html>
+<head>
+<link rel="stylesheet" href="test_private.css"></link>
+</head>
+<body>
+</body>
+</html>
--- a/browser/devtools/tilt/test/Makefile.in
+++ b/browser/devtools/tilt/test/Makefile.in
@@ -5,16 +5,19 @@
 DEPTH			= @DEPTH@
 topsrcdir		= @top_srcdir@
 srcdir			= @srcdir@
 VPATH			= @srcdir@
 relativesrcdir 	= @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
+# browser_tilt* disabled on Linux due to:
+# bug 759157, bug 795308, bug 761007, bug 795952, bug 795621
+ifneq (gtk2,$(MOZ_WIDGET_TOOLKIT))
 MOCHITEST_BROWSER_FILES = \
 	head.js \
 	browser_tilt_01_lazy_getter.js \
 	browser_tilt_02_notifications-seq.js \
 	browser_tilt_02_notifications.js \
 	browser_tilt_03_tab_switch.js \
 	browser_tilt_04_initialization-key.js \
 	browser_tilt_04_initialization.js \
@@ -52,10 +55,13 @@ MOCHITEST_BROWSER_FILES = \
 	browser_tilt_utils03.js \
 	browser_tilt_utils04.js \
 	browser_tilt_utils05.js \
 	browser_tilt_utils06.js \
 	browser_tilt_utils07.js \
 	browser_tilt_visualizer.js \
 	browser_tilt_zoom.js \
 	$(NULL)
+else
+$(warning browser_tilt_* disabled on Linux for intermittent failures. Bug 759157 and friends)
+endif
 
 include $(topsrcdir)/config/rules.mk
--- a/browser/installer/windows/nsis/stub.nsi
+++ b/browser/installer/windows/nsis/stub.nsi
@@ -1043,28 +1043,30 @@ Function UpdateFreeSpaceLabel
       StrCpy $1 "$(MEGA)$(BYTE)"
       ${If} $0 > 10240
       ${OrIf} $0 < 0
         System::Int64Op $0 / 1024
         Pop $0
         StrCpy $1 "$(GIGA)$(BYTE)"
       ${EndIf}
     ${EndIf}
-    StrCpy $4 "$0"
     StrLen $3 "$0"
-    ${If} $3 > 2
-      StrCpy $2 "$0" 2
-      StrCpy $0 "$0" 1 2
-      StrCpy $0 "$2.$0"
-    ${ElseIf} $3 == 2
-      StrCpy $2 "$0" 1
-      StrCpy $0 "$0" -1
-      StrCpy $0 "$2.$0"
+    ${If} $3 > 1
+      StrCpy $2 "$0" -1 ; All characters except the last one
+      StrCpy $0 "$0" "" -1 ; The last character
+      ${If} "$0" == "0"
+        StrCpy $0 "$2" ; Don't display the decimal if it is 0
+      ${Else}
+        StrCpy $0 "$2.$0"
+      ${EndIf}
+    ${ElseIf} $3 == 1
+      StrCpy $0 "0.$0"
     ${Else}
-      System::Int64Op $4 / 10
+      ; This should never happen
+      System::Int64Op $0 / 10
       Pop $0
     ${EndIf}
   ${EndIf}
 
   SendMessage $LabelFreeSpace ${WM_SETTEXT} 0 "STR:$0 $1"
 
 FunctionEnd
 
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -115,22 +115,32 @@ crashedpluginsMessage.reloadButton.label
 crashedpluginsMessage.reloadButton.accesskey=R
 crashedpluginsMessage.submitButton.label=Submit a crash report
 crashedpluginsMessage.submitButton.accesskey=S
 crashedpluginsMessage.learnMore=Learn More…
 carbonFailurePluginsMessage.message=This page asks to use a plugin that can only run in 32-bit mode
 carbonFailurePluginsMessage.restartButton.label=Restart in 32-bit mode
 carbonFailurePluginsMessage.restartButton.accesskey=R
 activatePluginsMessage.message=Would you like to activate the plugins on this page?
-activatePluginsMessage.label=Activate plugins
+activatePluginsMessage.label=Activate All Plugins
 activatePluginsMessage.accesskey=A
 activatePluginsMessage.always=Always activate plugins for this site
 activatePluginsMessage.always.accesskey=c
 activatePluginsMessage.never=Never activate plugins for this site
 activatePluginsMessage.never.accesskey=N
+activateSinglePlugin=Activate
+PluginClickToPlay=Click here to activate the %S plugin.
+# LOCALIZATION NOTE - "vulnerable" indicates there is a security bug in the
+# plugin that is being exploited by attackers.
+PluginVulnerableUpdatable=This plugin is vulnerable and should be updated.
+PluginVulnerableNoUpdate=This plugin has security vulnerabilities.
+vulnerableUpdatablePluginWarning=Outdated Version!
+vulnerableNoUpdatePluginWarning=Vulnerable Plugin!
+vulnerablePluginsMessage=Some plugins have been deactivated for your safety.
+pluginInfo.unknownPlugin=Unknown
 
 # Sanitize
 # LOCALIZATION NOTE (sanitizeDialog2.everything.title): When "Time range to
 # clear" is set to "Everything", the Clear Recent History dialog's title is
 # changed to this.  See UI mockup and comment 11 at bug 480169 -->
 sanitizeDialog2.everything.title=Clear All History
 sanitizeButtonOK=Clear Now
 # LOCALIZATION NOTE (sanitizeEverythingWarning2): Warning that appears when
--- a/browser/locales/en-US/chrome/browser/devtools/debugger.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/debugger.dtd
@@ -30,29 +30,11 @@
 <!-- LOCALIZATION NOTE (debuggerUI.closeButton.tooltip): This is the tooltip for
   -  the button that closes the debugger UI. -->
 <!ENTITY debuggerUI.closeButton.tooltip "Close">
 
 <!-- LOCALIZATION NOTE (debuggerUI.pauseExceptions): This is the label for the
   -  checkbox that toggles pausing on exceptions. -->
 <!ENTITY debuggerUI.pauseExceptions     "Pause on exceptions">
 
-<!-- LOCALIZATION NOTE (debuggerUI.stackTitle): This is the label for the
-  -  widget that displays the call stack frames in the debugger. -->
-<!ENTITY debuggerUI.stackTitle          "Call stack">
-
-<!-- LOCALIZATION NOTE (debuggerUI.scriptTitle): This is the label for the
-  -  widget that displays the source code for the script that is currently
-  -  being inspected in the debugger. -->
-<!ENTITY debuggerUI.scriptTitle         "Script">
-
-<!-- LOCALIZATION NOTE (debuggerUI.propertiesTitle): This is the label for the
-  -  widget that displays the variables in the various available scopes in the
-  -  debugger. -->
-<!ENTITY debuggerUI.propertiesTitle     "Scope variables">
-
 <!-- LOCALIZATION NOTE (debuggerUI.searchPanelTitle): This is the text that
   -  appears in the filter panel popup as a description. -->
 <!ENTITY debuggerUI.searchPanelTitle    "Operators">
-
-<!-- LOCALIZATION NOTE (emptyScriptText): The text to display in the menulist when
-  - there are no scripts. -->
-<!ENTITY debuggerUI.emptyScriptText     "No scripts">
--- a/browser/locales/en-US/chrome/browser/devtools/responsiveUI.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/responsiveUI.properties
@@ -1,8 +1,12 @@
+# 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/.
+
 # LOCALIZATION NOTE These strings are used inside the Responsive Mode
 # which is available from the Web Developer sub-menu -> 'Responsive Mode'.
 #
 # The correct localization of this file might be to keep it in
 # English, or another language commonly spoken among web developers.
 # You want to make that choice consistent across the developer tools.
 # A good criteria is the language in which you'd find the best
 # documentation on web development on the web.
@@ -28,9 +32,9 @@ responsiveUI.customResolution=%S (custom
 responsiveUI.namedResolution=%S (%S)
 
 # LOCALIZATION NOTE  (responsiveUI.customNamePromptTitle): prompt title when asking
 # the user to specify a name for a new custom preset.
 responsiveUI.customNamePromptTitle=Responsive Design View
 
 # LOCALIZATION NOTE  (responsiveUI.customNamePromptMsg): prompt message when asking
 # the user to specify a name for a new custom preset.
-responsiveUI.customNamePromptMsg=Give a name to the %Sx%S preset
\ No newline at end of file
+responsiveUI.customNamePromptMsg=Give a name to the %Sx%S preset
--- a/browser/locales/en-US/defines.inc
+++ b/browser/locales/en-US/defines.inc
@@ -1,8 +1,11 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
 #filter emptyLines
 
 #define MOZ_LANGPACK_CREATOR mozilla.org
 
 # If non-English locales wish to credit multiple contributors, uncomment this
 # variable definition and use the format specified.
 # #define MOZ_LANGPACK_CONTRIBUTORS <em:contributor>Joe Solon</em:contributor> <em:contributor>Suzy Solon</em:contributor>
 
--- a/browser/locales/en-US/pdfviewer/chrome.properties
+++ b/browser/locales/en-US/pdfviewer/chrome.properties
@@ -1,4 +1,8 @@
+# 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/.
+
 # Chrome notification bar messages and buttons
 unsupported_feature=This PDF document might not be displayed correctly.
 open_with_different_viewer=Open With Different Viewer
 open_with_different_viewer.accessKey=o
--- a/browser/locales/en-US/pdfviewer/viewer.properties
+++ b/browser/locales/en-US/pdfviewer/viewer.properties
@@ -1,8 +1,12 @@
+# 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/.
+
 # Main toolbar buttons (tooltips and alt text for images)
 previous.title=Previous Page
 previous_label=Previous
 next.title=Next Page
 next_label=Next
 
 # LOCALIZATION NOTE (page_label, page_of):
 # These strings are concatenated to form the "Page: X of Y" string.
--- a/browser/locales/en-US/profile/bookmarks.inc
+++ b/browser/locales/en-US/profile/bookmarks.inc
@@ -1,8 +1,11 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
 #filter emptyLines
 
 # LOCALIZATION NOTE: The 'en-US' strings in the URLs will be replaced with
 # your locale code, and link to your translated pages as soon as they're 
 # live.
 
 #define bookmarks_title Bookmarks
 #define bookmarks_heading Bookmarks
--- a/browser/modules/webappsUI.jsm
+++ b/browser/modules/webappsUI.jsm
@@ -6,26 +6,27 @@ let EXPORTED_SYMBOLS = ["webappsUI"];
 
 let Ci = Components.interfaces;
 let Cc = Components.classes;
 let Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Webapps.jsm");
+Cu.import("resource://gre/modules/AppsUtils.jsm");
 Cu.import("resource://gre/modules/WebappsInstaller.jsm");
 Cu.import("resource://gre/modules/WebappOSUtils.jsm");
 
 let webappsUI = {
   init: function webappsUI_init() {
     Services.obs.addObserver(this, "webapps-ask-install", false);
     Services.obs.addObserver(this, "webapps-launch", false);
     Services.obs.addObserver(this, "webapps-uninstall", false);
   },
-  
+
   uninit: function webappsUI_uninit() {
     Services.obs.removeObserver(this, "webapps-ask-install");
     Services.obs.removeObserver(this, "webapps-launch");
     Services.obs.removeObserver(this, "webapps-uninstall");
   },
 
   observe: function webappsUI_observe(aSubject, aTopic, aData) {
     let data = JSON.parse(aData);
@@ -42,17 +43,17 @@ let webappsUI = {
         break;
       case "webapps-uninstall":
         WebappOSUtils.uninstall(data);
         break;
     }
   },
 
   openURL: function(aUrl, aOrigin) {
-    let browserEnumerator = Services.wm.getEnumerator("navigator:browser");  
+    let browserEnumerator = Services.wm.getEnumerator("navigator:browser");
     let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
 
     // Check each browser instance for our URL
     let found = false;
     while (!found && browserEnumerator.hasMoreElements()) {
       let browserWin = browserEnumerator.getNext();
       let tabbrowser = browserWin.gBrowser;
 
@@ -122,17 +123,17 @@ let webappsUI = {
           installationSuccessNotification(app, aWindow);
         } else {
           DOMApplicationRegistry.denyInstall(aData);
         }
       }
     };
 
     let requestingURI = aWindow.makeURI(aData.from);
-    let manifest = new DOMApplicationManifest(aData.app.manifest, aData.app.origin);
+    let manifest = new ManifestHelper(aData.app.manifest, aData.app.origin);
 
     let host;
     try {
       host = requestingURI.host;
     } catch(e) {
       host = requestingURI.spec;
     }
 
--- a/browser/themes/LICENSE
+++ b/browser/themes/LICENSE
@@ -1,2 +1,2 @@
-All files in this directory are assumed to be licensed under the 
-tri-license (MPL/GPL/LGPL) used throughout this codebase.
\ No newline at end of file
+All files in this directory are assumed to be licensed under the MPL 2 license
+which is used throughout this codebase.
--- a/browser/themes/gnomestripe/browser.css
+++ b/browser/themes/gnomestripe/browser.css
@@ -1154,19 +1154,17 @@ toolbar[iconsize="small"] #feed-button {
 .popup-notification-icon[popupid="addon-install-failed"],
 .popup-notification-icon[popupid="addon-install-complete"] {
   list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
   width: 32px;
   height: 32px;
 }
 
 .popup-notification-icon[popupid="click-to-play-plugins"] {
-  list-style-image: url(chrome://mozapps/skin/plugins/pluginGeneric.png);
-  width: 32px;
-  height: 32px;
+  list-style-image: url(chrome://mozapps/skin/plugins/pluginBlocked-64.png);
 }
 
 .addon-progress-description {
   width: 350px;
   max-width: 350px;
 }
 
 .popup-progress-label,
@@ -2604,122 +2602,105 @@ html|*#gcli-output-frame {
   color: #FDF3DE;
   min-width: 16px;
   text-shadow: none;
   background-image: -moz-linear-gradient(top, #B4211B, #8A1915);
   border-radius: 1px;
   -moz-margin-end: 2px;
 }
 
-#social-toolbar-button {
-  -moz-appearance: toolbarbutton;
-}
-
-/* favicon for the service */
-#social-provider-image {
-  -moz-appearance: none;
-  border: none;
-  min-width: 20px;
-  min-height: 20px;
-  padding: 2px 5px;
-  margin: 0;
-  background: transparent;
-  list-style-image: url("chrome://browser/skin/social/social.png");
-}
-
-#social-provider-image > .button-box > .box-inherit > .button-icon {
-  max-height: 16px;
-  max-width: 16px;
-}
-
-#social-provider-image > .button-box {
-  padding: 0;
-  margin: 0;
-  background: transparent;
-  border: none;
-}
-
-#social-provider-image > .button-box > .button-menu-dropmarker {
-  display: none;
-}
-
-/* hbox that hold notification icons */
-#social-status-iconbox {
+#social-toolbar-item {
+  -moz-box-orient: horizontal;
+}
+
+#social-toolbar-item > .toolbarbutton-1 {
   margin: 0;
   padding: 0;
-}
-
-/* hbox that surrounds an image and its counter */
-.social-notification-icon-container {
+  -moz-appearance: toolbarbutton;
+}
+
+.social-notification-icon-hbox {
+  pointer-events: none;
+}
+
+.social-status-button {
+  list-style-image: none;
+}
+
+#social-provider-button > image {
+  margin: 5px 3px;
+}
+
+#social-provider-button > .toolbarbutton-menu-dropmarker {
+  display: none;
+}
+
+.social-notification-icon-stack {
   padding: 0;
-  margin: 0;
-  position: relative;
-}
-
-/* notification counter box */
-.social-notification-icon-counter {
+}
+
+.social-notification-icon-stack > image {
+  margin: 5px 3px;
+  max-height: 16px;
+}
+
+.social-notification-icon-hbox {
+  padding: 0;
+}
+
+.social-notification-icon-label {
   background-color: rgb(240,61,37);
   border: 1px solid rgb(216,55,34);
   box-shadow: 0px 1px 0px rgba(0,39,121,0.77);
   padding-right: 1px;
   padding-left: 1px;
   color: white;
   font-size: 9px;
   font-weight: bold;
-  position: absolute;
-  right: -3px;
-  top: -4px;
-  z-index: 1;
-  text-align: center;
-}
-
-/* notification image */
-.social-notification-icon-image {
-  padding: 2px;
   margin: 0;
-  min-width: 20px;
-  max-width: 32px;
-  max-height: 20px;
-  list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
+}
+
+.social-notification-icon-label[value=""] {
+  display: none;
 }
 
 /* social toolbar provider menu */
 #social-statusarea-popup {
   margin-top: 0;
   margin-left: -12px;
   margin-right: -12px;
 }
 
 #social-statusarea-user {
   border-bottom: 1px solid rgb(221,221,221);
   background-color: -moz-Dialog;
   color: -moz-dialogtext;
   position: relative;
   font: message-box;
   font-size: 12px;
+  cursor: pointer;
 }
 
 #social-statusarea-user-portrait {
   width: 32px;
   height: 32px;
   border-radius: 2px;
   margin: 10px;
 }
 
-#social-statusarea-username {
+#social-statusarea-user > vbox > .link {
   -moz-appearance: none;
   background: transparent;
   border: none;
   color: -moz-nativehyperlinktext;
-  cursor: pointer;
   min-width: 0;
   margin: 0 6px;
   list-style-image: none;
 }
-#social-statusarea-username:hover {
+#social-statusarea-user:hover > vbox > .link {
   text-decoration: underline;
 }
 
 .social-panel > .panel-arrowcontainer > .panel-arrowcontent {
   padding: 0;
 }
 
 .chat-status-icon {
@@ -2839,8 +2820,114 @@ chatbox {
   border: 1px solid gray;
   border-bottom: none;
 }
 
 chatbox[minimized="true"] {
   width: 160px;
   height: 20px;
 }
+
+panel[type="arrow"][popupid="click-to-play-plugins"] > .panel-arrowcontainer > .panel-arrowbox > .panel-arrow[side="top"],
+panel[type="arrow"][popupid="click-to-play-plugins"] > .panel-arrowcontainer > .panel-arrowbox > .panel-arrow[side="bottom"] {
+  list-style-image: url("chrome://global/skin/icons/panelarrow-light-vertical.svg");
+}
+
+.click-to-play-plugins-notification-content {
+  margin: -10px;
+}
+
+.click-to-play-plugins-notification-icon-box {
+  background: hsla(0,0%,100%,.4);
+  -moz-border-end: 1px solid hsla(0,0%,100%,.2);
+  padding-top: 16px;
+  -moz-padding-start: 16px;
+  -moz-padding-end: 6px;
+}
+
+.click-to-play-plugins-notification-separator {
+  -moz-border-start: 1px solid hsla(211,79%,6%,.1);
+  border-top: 1px solid hsla(211,79%,6%,.1);
+}
+
+.click-to-play-plugins-notification-description-box {
+  border-bottom: 1px solid hsla(0,0%,100%,.2);
+  -moz-border-start: 1px solid hsla(0,0%,100%,.2);
+  padding: 14px 10px 9px 10px;
+}
+
+.click-to-play-plugins-notification-center-box {
+  border-top: 1px solid hsla(0,0%,100%,.2);
+  border-bottom: 1px solid hsla(0,0%,100%,.2);
+  background-color: hsla(211,79%,6%,.05);
+}
+
+.click-to-play-plugins-notification-button-container {
+  border-top: 1px solid hsla(0,0%,100%,.2);
+  -moz-border-start: 1px solid hsla(0,0%,100%,.2);
+  margin: 0px;
+  padding: 15px 11px 14px 11px;
+}
+
+.center-item-box {
+  padding-top: 11px;
+  -moz-padding-start: 16px;
+  -moz-padding-end: 11px;
+  margin-bottom: -2px;
+  -moz-border-start: 1px solid hsla(0,0%,100%,.2);
+}
+
+.center-item-box[padbottom="true"] {
+  padding-bottom: 12px;
+}
+
+.center-item-icon {
+  background-image: url("chrome://mozapps/skin/plugins/pluginGeneric-16.png");
+  background-repeat: no-repeat;
+  height: 16px;
+  width: 16px;
+  margin-bottom: 4px;
+}
+
+.center-item-box[warn="true"] {
+  background-image: url("chrome://mozapps/skin/extensions/stripes-info-negative-small.png");
+  background-repeat: repeat-x;
+  padding-top: 7px;
+  -moz-padding-end: 11px;
+  padding-bottom: 9px;
+  -moz-padding-start: 16px;
+}
+
+.center-item-box[padbottom="true"][warn="true"] {
+  padding-bottom: 7px;
+}
+
+.center-item-box[showseparator="true"] {
+  border-top: 1px solid hsla(211,79%,6%,.1);
+}
+
+.center-item-box[warn="false"] > .center-item-warning {
+  display: none;
+}
+
+.center-item-warning > .text-link {
+  color: #3d8cd7;
+}
+
+.center-item-warning > .text-link[href=""] {
+  display: none;
+}
+
+.center-item-warning-icon {
+  background-image: url("chrome://mozapps/skin/extensions/alerticon-info-negative.png");
+  background-repeat: no-repeat;
+  width: 16px;
+  height: 15px;
+  margin-bottom: 4px;
+}
+
+.center-item-warning-description {
+  color: #828282;
+}
+
+.center-item-button {
+  min-width: 0;
+}
--- a/browser/themes/gnomestripe/devtools/common.css
+++ b/browser/themes/gnomestripe/devtools/common.css
@@ -169,8 +169,38 @@
   border: 0;
   -moz-border-start: 1px solid black;
   min-width: 0;
   width: 3px;
   background-color: transparent;
   -moz-margin-end: -3px;
   position: relative;
 }
+
+/* Theme */
+
+.devtools-theme-background {
+  background-color: white;
+}
+
+.devtools-theme-comment {
+  color: hsl(90,2%,46%); /* grey */
+}
+
+.devtools-theme-keyword {
+  color: hsl(276,44%,45%); /* purple */
+}
+
+.devtools-theme-string {
+  color: hsl(72,100%,27%); /* green */
+}
+
+.devtools-theme-tagname {
+  color: hsl(208,81%,21%); /* dark blue */
+}
+
+.devtools-theme-attrname {
+  color: hsl(208,56%,40%); /* blue */
+}
+
+.devtools-theme-attrvalue {
+  color: hsl(24,85%,39%); /* orange */
+}
--- a/browser/themes/gnomestripe/devtools/csshtmltree.css
+++ b/browser/themes/gnomestripe/devtools/csshtmltree.css
@@ -139,17 +139,17 @@
  * CSS Rule View
  */
 
 .ruleview {
   background-color: white;
 }
 
 .ruleview-rule-source {
-  color: hsl(121,42%,43%); /* green */
+  color: hsl(90,2%,46%); /* grey */
   -moz-padding-start: 5px;
   cursor: pointer;
   text-align: right;
   float: right;
   -moz-user-select: -moz-none;
 }
 
 .ruleview-rule-inheritance {
@@ -226,17 +226,17 @@
 
 .ruleview-newproperty {
   /* (enable checkbox width: 12px) + (expander width: 15px) */
   -moz-margin-start: 27px;
 }
 
 .ruleview-propertyname {
   padding: 1px 0;
-  color: hsl(210,100%,38%); /* blue */
+  color: hsl(276,44%,45%); /* purple */
 }
 
 .ruleview-propertyvalue {
   padding: 1px 0;
 }
 
 .ruleview-namecontainer,
 .ruleview-propertycontainer,
--- a/browser/themes/gnomestripe/devtools/markup-view.css
+++ b/browser/themes/gnomestripe/devtools/markup-view.css
@@ -4,42 +4,29 @@
 
 * {
   padding: 0;
   margin: 0;
 }
 
 body {
   font: message-box;
-  background-color: #131c26;
-  color: #8fa1b2;
+  color: hsl(0,0%,50%);
 }
 
-.tagname {
-  color: #a673bf;
-}
-
-.attrname {
-  color: #b26b47;
-}
-
-.attrvalue {
-  color: #3689b2;
+.text {
+  color: black;
 }
 
 .newattr {
   cursor: pointer;
 }
 
-.comment {
-  color: #5c6773;
-}
-
 .selected {
-  background-color: #253847;
+  background-color: hsl(0,0%,90%);
 }
 
 /* Give some padding to focusable elements to match the editor input
  * that will replace them. */
 span[tabindex] {
   display: inline-block;
   padding: 1px 0;
 }
--- a/browser/themes/gnomestripe/devtools/orion.css
+++ b/browser/themes/gnomestripe/devtools/orion.css
@@ -1,31 +1,31 @@
 /* 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/. */
 
 .viewContainer {
-  background: #cddae5; /* This will be seen as the continuation of the ruler */
+  background: hsl(0,0%,89%); /* This will be seen as the continuation of the ruler */
   font-family: monospace;
   font-size: inherit; /* inherit browser's default monospace font size */
 }
 
 .view {
   color: black; /* Default text color */
-  background: #f0f0ff; /* Background of the editor */
+  background: white; /* Background of the editor */
   padding-left: 4px;
 }
 
 .readonly > .view {
-  background: #f0f0ff;
+  background: #fdfefd; /* super light green */
 }
 
 .ruler {
-  background: #cddae5;
-  color: #7a8a99;
+  background: hsl(0,0%,89%);
+  color: hsl(0,0%,55%);
 }
 .ruler.annotations {
   width: 16px;
   padding-left: 4px;
 }
 .ruler.lines {
   border-right: 1px solid #b4c4d3;
   min-width: 1.4em;
@@ -100,48 +100,42 @@
 }
 .annotationRange.task {
   outline: 1px dashed rgba(0, 255, 0, 0.5);
 }
 .annotationRange.matchingBracket {
   outline: 1px solid grey;
 }
 
-.token_singleline_comment {
-  color: #45a946; /* green */
-}
-
-.token_multiline_comment {
-  color: #45a946; /* green */
-}
-
-.token_doc_comment {
-  color: #45a946; /* green */
+.token_singleline_comment,
+.token_multiline_comment,
+.token_doc_comment  {
+  color: hsl(90,2%,50%); /* grey */
 }
 
 .token_doc_html_markup {
   color: #dd0058; /* purple */
 }
 
 .token_doc_tag {
   color: #dd0058; /* purple */
 }
 
 .token_task_tag { /* "TODO" */
   color: black;
   background: yellow;
 }
 
 .token_string {
-  color: #1e66b1; /* blue */
+  color: hsl(72,100%,27%); /* green */
   font-style: italic;
 }
 
 .token_keyword {
-  color: #dd0058; /* purple */
+  color: hsl(276,44%,45%); /* purple */
 }
 
 .token_space {
   /* images/white_space.png */
   background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAIAAABv85FHAAAABnRSTlMA/wAAAACkwsAdAAAAIUlEQVR4nGP4z8CAC+GUIEXuABhgkTuABEiRw2cmae4EAH05X7xDolNRAAAAAElFTkSuQmCC");
   background-repeat: no-repeat;
   background-position: center center;
 }
@@ -150,42 +144,41 @@
   /* images/white_tab.png */
   background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAJCAIAAACJ2loDAAAABnRSTlMA/wD/AP83WBt9AAAAMklEQVR4nGP4TwRgoK6i52c3bz5w6zMSA6tJn28d2Lx589nnCAYu63AaSLxJRLoJPwAAeNk0aG4opfMAAAAASUVORK5CYII=");
   background-repeat: no-repeat;
   background-position: left center;
 }
 
 .line_caret,
 .annotationLine.currentLine { /* Current line */
-  background: #dae2ee; /* lighter than the background */
+  background: hsl(208, 93%, 94%);
 }
 
 .readonly .line_caret,
 .readonly .annotationLine.currentLine {
-  background: #cddae5; /* a bit darker than the background */
+  background: hsl(208, 80%, 90%);
 }
 
 /* Styling for html syntax highlighting */
 .entity-name-tag {
-  color: #dd0058; /* purple */
+  color: hsl(208,48%,40%); /* blue */
 }
 
 .entity-other-attribute-name {
-  color: #dd0058; /* purple */
+  color: hsl(208,48%,40%); /* blue */
 }
 
 .punctuation-definition-comment {
-  color: #45a946; /* green */
+  color: hsl(90,2%,50%); /* grey */
 }
 
 .comment {
-  color: #45a946; /* green */
+  color: hsl(90,2%,50%); /* grey */
 }
 
 .string-quoted {
-  color: #1e66b1; /* blue */
-  font-style: italic;
+  color: hsl(24,85%,39%); /* orange */
 }
 
 .invalid {
   color: red;
   font-weight: bold;
 }
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -3050,19 +3050,17 @@ toolbarbutton.chevron > .toolbarbutton-m
 .popup-notification-icon[popupid="addon-install-failed"],
 .popup-notification-icon[popupid="addon-install-complete"] {
   list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
   width: 32px;
   height: 32px;
 }
 
 .popup-notification-icon[popupid="click-to-play-plugins"] {
-  list-style-image: url(chrome://mozapps/skin/plugins/pluginGeneric.png);
-  width: 32px;
-  height: 32px;
+  list-style-image: url(chrome://mozapps/skin/plugins/pluginBlocked-64.png);
 }
 
 .addon-progress-description {
   width: 350px;
   max-width: 350px;
 }
 
 .popup-progress-label,
@@ -4023,92 +4021,103 @@ html|*#gcli-output-frame {
   text-shadow: none;
   background-image: -moz-linear-gradient(top, #B4211B, #8A1915);
   border-radius: 1px;
 }
 
 /* === social toolbar button === */
 
 /* button icon for the service */
-#social-provider-image {
-  -moz-appearance: none;
+#social-toolbar-item {
+  -moz-box-orient: horizontal;
+}
+
+#social-toolbar-item > .toolbarbutton-1 {
+  margin: 0px;
+}
+
+.social-notification-icon-hbox {
+  pointer-events: none;
+}
+
+.social-status-button {
+  list-style-image: none;
+}
+
+#social-provider-button > .toolbarbutton-menu-dropmarker {
+  display: none;
+}
+
+.social-notification-icon-stack {
+  padding: 0;
+}
+
+.social-notification-icon-stack > image {
+  max-height: 16px;
+}
+
+.social-notification-icon-hbox {
+  padding: 0;
+}
+.social-notification-icon-label {
+  text-align: end;
+  font-size: 9px;
+  font-weight: bold;
+  padding: 0 1px;
+  color: white;
   margin: 0;
-  padding: 2px;
-  min-width: 0;
-  max-height: 20px;
-  list-style-image: url("chrome://browser/skin/social/social.png");
-}
-
-/* hbox that surrounds an image and its counter */
-.social-notification-icon-container {
-  cursor: pointer;
-  padding: 0px;
-  margin: 0px;
-  position: relative;
-}
-
-/* notification counter box */
-.social-notification-icon-counter {
   background-color: rgb(240,61,37);
   border: 1px solid rgb(216,55,34);
-  box-shadow: 0px 1px 0px rgba(0,39,121,0.77);
-  padding-right: 1px;
-  padding-left: 1px;
-  color: white;
-  font-size: 9px;
-  font-weight: bold;
-  position: absolute;
-  right: -3px;
-  top: -4px;
-  z-index: 1;
-  text-align: center;
-}
-
-/* notification image */
-.social-notification-icon-image {
-  padding: 2px;
-  margin: 0px;
-  min-width: 20px;
-  max-width: 32px;
-  max-height: 20px;
-  list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
+  box-shadow: 0 1px 0 rgba(0,39,121,0.77);
+  -moz-margin-end: -4px;
+  margin-top: -4px;
+}
+
+.social-notification-icon-label[value=""] {
+  display: none;
+}
+
+@media (-moz-mac-lion-theme) {
+  .social-notification-icon-stack > image:-moz-window-inactive {
+    opacity: .5;
+  }
 }
 
 @media (min-resolution: 2dppx) {
   .social-notification-icon-image {
     list-style-image: url("chrome://mozapps/skin/places/defaultFavicon@2x.png");
   }
 }
 
 /* === end of social toolbar button === */
 
 /* === social toolbar provider menu  === */
 
 #social-statusarea-user {
   cursor: default;
   font-family: "lucida grande",tahoma,verdana,arial,sans-serif;
   font-size: 12px;
+  cursor: pointer;
 }
 
 #social-statusarea-user-portrait {
   width: 32px;
   height: 32px;
   margin: 10px;
 }
 
-#social-statusarea-username {
+#social-statusarea-user > vbox > .link {
   -moz-appearance: none;
   color: -moz-nativehyperlinktext;
-  cursor: pointer;
   min-width: 0;
   margin: 0 6px;
   list-style-image: none;
 }
 
-#social-statusarea-username:hover {
+#social-statusarea-user:hover > vbox > .link {
   text-decoration: underline;
 }
 
 .social-panel > .panel-arrowcontainer > .panel-arrowcontent {
   padding: 0;
 }
 
 #social-notification-box,
@@ -4235,8 +4244,127 @@ chatbox {
   border: 1px solid #404040;
   border-bottom: none;
 }
 
 chatbox[minimized="true"] {
   width: 160px;
   height: 20px;
 }
+
+panel[type="arrow"][popupid="click-to-play-plugins"] > .panel-arrowcontainer > .panel-arrowbox > .panel-arrow[side="top"],
+panel[type="arrow"][popupid="click-to-play-plugins"] > .panel-arrowcontainer > .panel-arrowbox > .panel-arrow[side="bottom"] {
+  list-style-image: url("chrome://global/skin/arrow/panelarrow-light-vertical.png");
+}
+
+.click-to-play-plugins-notification-content {
+  margin: -16px;
+  border-radius: 5px;
+}
+
+.click-to-play-plugins-notification-icon-box {
+  background: hsla(0,0%,100%,.4);
+  -moz-border-end: 1px solid hsla(0,0%,100%,.2);
+  padding-top: 16px;
+  -moz-padding-end: 12px;
+  -moz-padding-start: 20px;
+}
+
+.click-to-play-plugins-notification-icon-box:-moz-locale-dir(ltr) {
+  border-bottom-left-radius: 5px;
+  border-top-left-radius: 5px;
+}
+
+.click-to-play-plugins-notification-icon-box:-moz-locale-dir(rtl) {
+  border-bottom-right-radius: 5px;
+  border-top-right-radius: 5px;
+}
+
+.click-to-play-plugins-notification-separator {
+  -moz-border-start: 1px solid hsla(211,79%,6%,.1);
+  border-top: 1px solid hsla(211,79%,6%,.1);
+}
+
+.click-to-play-plugins-notification-description-box {
+  border-bottom: 1px solid hsla(0,0%,100%,.2);
+  -moz-border-start: 1px solid hsla(0,0%,100%,.2);
+  max-width: 28em;
+  padding: 14px 16px 9px 16px;
+}
+
+.click-to-play-plugins-notification-center-box {
+  border-top: 1px solid hsla(0,0%,100%,.2);
+  border-bottom: 1px solid hsla(0,0%,100%,.2);
+  background-color: hsla(211,79%,6%,.05);
+}
+
+.click-to-play-plugins-notification-button-container {
+  border-top: 1px solid hsla(0,0%,100%,.2);
+  -moz-border-start: 1px solid hsla(0,0%,100%,.2);
+  margin: 0px;
+  padding: 16px 16px 17px 16px;
+}
+
+.center-item-box {
+  -moz-border-start: 1px solid hsla(0,0%,100%,.2);
+  padding-top: 7px;
+  -moz-padding-end: 11px;
+  -moz-padding-start: 16px;
+  margin-bottom: -3px;
+}
+
+.center-item-box[padbottom="true"] {
+  padding-bottom: 12px;
+}
+
+.center-item-icon {
+  background-image: url("chrome://mozapps/skin/plugins/pluginGeneric-16.png");
+  background-repeat: no-repeat;
+  height: 16px;
+  width: 16px;
+  margin-bottom: 4px;
+  -moz-margin-end: 6px;
+}
+
+.center-item-box[warn="true"] {
+  background-image: url("chrome://mozapps/skin/extensions/stripes-info-negative-small.png");
+  background-repeat: repeat-x;
+  padding-top: 3px;
+  -moz-padding-end: 11px;
+  padding-bottom: 9px;
+  -moz-padding-start: 16px;
+}
+
+.center-item-box[padbottom="true"][warn="true"] {
+  padding-bottom: 7px;
+}
+
+.center-item-box[showseparator="true"] {
+  border-top: 1px solid hsla(211,79%,6%,.1);
+}
+
+.center-item-box[warn="false"] > .center-item-warning {
+  display: none;
+}
+
+.center-item-warning > .text-link {
+  color: #3d8cd7;
+}
+
+.center-item-warning > .text-link[href=""] {
+  display: none;
+}
+
+.center-item-warning-icon {
+  background-image: url("chrome://mozapps/skin/extensions/alerticon-info-negative.png");
+  background-repeat: no-repeat;
+  width: 16px;
+  height: 15px;
+  margin-bottom: 4px;
+}
+
+.center-item-warning-description {
+  color: #828282;
+}
+
+.center-item-button {
+  min-width: 0;
+}
--- a/browser/themes/pinstripe/devtools/common.css
+++ b/browser/themes/pinstripe/devtools/common.css
@@ -184,8 +184,38 @@
   background-image: none;
   border: 0;
   -moz-border-start: 1px solid black;
   min-width: 0;
   width: 3px;
   -moz-margin-end: -3px;
   position: relative;
 }
+
+/* Theme */
+
+.devtools-theme-background {
+  background-color: white;
+}
+
+.devtools-theme-comment {
+  color: hsl(90,2%,46%); /* grey */
+}
+
+.devtools-theme-keyword {
+  color: hsl(276,44%,45%); /* purple */
+}
+
+.devtools-theme-string {
+  color: hsl(72,100%,27%); /* green */
+}
+
+.devtools-theme-tagname {
+  color: hsl(208,81%,21%); /* dark blue */
+}
+
+.devtools-theme-attrname {
+  color: hsl(208,56%,40%); /* blue */
+}
+
+.devtools-theme-attrvalue {
+  color: hsl(24,85%,39%); /* orange */
+}
--- a/browser/themes/pinstripe/devtools/csshtmltree.css
+++ b/browser/themes/pinstripe/devtools/csshtmltree.css
@@ -141,17 +141,17 @@
  * CSS Rule View
  */
 
 .ruleview {
   background-color: white;
 }
 
 .ruleview-rule-source {
-  color: hsl(121,42%,43%); /* green */
+  color: hsl(90,2%,46%); /* grey */
   -moz-padding-start: 5px;
   cursor: pointer;
   text-align: right;
   float: right;
   -moz-user-select: -moz-none;
 }
 
 .ruleview-rule-inheritance {
@@ -228,17 +228,17 @@
 
 .ruleview-newproperty {
   /* (enable checkbox width: 12px) + (expander width: 15px) */
   -moz-margin-start: 27px;
 }
 
 .ruleview-propertyname {
   padding: 1px 0;
-  color: hsl(210,100%,38%); /* blue */
+  color: hsl(276,44%,45%); /* purple */
 }
 
 .ruleview-propertyvalue {
   padding: 1px 0;
 }
 
 .ruleview-namecontainer,
 .ruleview-propertycontainer,
--- a/browser/themes/pinstripe/devtools/markup-view.css
+++ b/browser/themes/pinstripe/devtools/markup-view.css
@@ -4,42 +4,29 @@
 
 * {
   padding: 0;
   margin: 0;
 }
 
 body {
   font: message-box;
-  background-color: #131c26;
-  color: #8fa1b2;
+  color: hsl(0,0%,50%);
 }
 
-.tagname {
-  color: #a673bf;
-}
-
-.attrname {
-  color: #b26b47;
-}
-
-.attrvalue {
-  color: #3689b2;
+.text {
+  color: black;
 }
 
 .newattr {
   cursor: pointer;
 }
 
-.comment {
-  color: #5c6773;
-}
-
 .selected {
-  background-color: #253847;
+  background-color: hsl(0,0%,90%);
 }
 
 /* Give some padding to focusable elements to match the editor input
  * that will replace them. */
 span[tabindex] {
   display: inline-block;
   padding: 1px 0;
 }
--- a/browser/themes/pinstripe/devtools/orion.css
+++ b/browser/themes/pinstripe/devtools/orion.css
@@ -1,31 +1,31 @@
 /* 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/. */
 
 .viewContainer {
-  background: #cddae5; /* This will be seen as the continuation of the ruler */
+  background: hsl(0,0%,89%); /* This will be seen as the continuation of the ruler */
   font-family: monospace;
   font-size: inherit; /* inherit browser's default monospace font size */
 }
 
 .view {
   color: black; /* Default text color */
-  background: #f0f0ff; /* Background of the editor */
+  background: white; /* Background of the editor */
   padding-left: 4px;
 }
 
 .readonly > .view {
-  background: #f0f0ff;
+  background: #fdfefd; /* super light green */
 }
 
 .ruler {
-  background: #cddae5;
-  color: #7a8a99;
+  background: hsl(0,0%,89%);
+  color: hsl(0,0%,55%);
 }
 .ruler.annotations {
   width: 16px;
   padding-left: 4px;
 }
 .ruler.lines {
   border-right: 1px solid #b4c4d3;
   min-width: 1.4em;
@@ -100,48 +100,42 @@
 }
 .annotationRange.task {
   outline: 1px dashed rgba(0, 255, 0, 0.5);
 }
 .annotationRange.matchingBracket {
   outline: 1px solid grey;
 }
 
-.token_singleline_comment {
-  color: #45a946; /* green */
-}
-
-.token_multiline_comment {
-  color: #45a946; /* green */
-}
-
-.token_doc_comment {
-  color: #45a946; /* green */
+.token_singleline_comment,
+.token_multiline_comment,
+.token_doc_comment  {
+  color: hsl(90,2%,50%); /* grey */
 }
 
 .token_doc_html_markup {
   color: #dd0058; /* purple */
 }
 
 .token_doc_tag {
   color: #dd0058; /* purple */
 }
 
 .token_task_tag { /* "TODO" */
   color: black;
   background: yellow;
 }
 
 .token_string {
-  color: #1e66b1; /* blue */
+  color: hsl(72,100%,27%); /* green */
   font-style: italic;
 }
 
 .token_keyword {
-  color: #dd0058; /* purple */
+  color: hsl(276,44%,45%); /* purple */
 }
 
 .token_space {
   /* images/white_space.png */
   background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAIAAABv85FHAAAABnRSTlMA/wAAAACkwsAdAAAAIUlEQVR4nGP4z8CAC+GUIEXuABhgkTuABEiRw2cmae4EAH05X7xDolNRAAAAAElFTkSuQmCC");
   background-repeat: no-repeat;
   background-position: center center;
 }
@@ -150,42 +144,41 @@
   /* images/white_tab.png */
   background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAJCAIAAACJ2loDAAAABnRSTlMA/wD/AP83WBt9AAAAMklEQVR4nGP4TwRgoK6i52c3bz5w6zMSA6tJn28d2Lx589nnCAYu63AaSLxJRLoJPwAAeNk0aG4opfMAAAAASUVORK5CYII=");
   background-repeat: no-repeat;
   background-position: left center;
 }
 
 .line_caret,
 .annotationLine.currentLine { /* Current line */
-  background: #dae2ee; /* lighter than the background */
+  background: hsl(208, 93%, 94%);
 }
 
 .readonly .line_caret,
 .readonly .annotationLine.currentLine {
-  background: #cddae5; /* a bit darker than the background */
+  background: hsl(208, 80%, 90%);
 }
 
 /* Styling for html syntax highlighting */
 .entity-name-tag {
-  color: #dd0058; /* purple */
+  color: hsl(208,48%,40%); /* blue */
 }
 
 .entity-other-attribute-name {
-  color: #dd0058; /* purple */
+  color: hsl(208,48%,40%); /* blue */
 }
 
 .punctuation-definition-comment {
-  color: #45a946; /* green */
+  color: hsl(90,2%,50%); /* grey */
 }
 
 .comment {
-  color: #45a946; /* green */
+  color: hsl(90,2%,50%); /* grey */
 }
 
 .string-quoted {
-  color: #1e66b1; /* blue */
-  font-style: italic;
+  color: hsl(24,85%,39%); /* orange */
 }
 
 .invalid {
   color: red;
   font-weight: bold;
 }
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -665,17 +665,17 @@ toolbar[mode=full] .toolbarbutton-1 > .t
 
 @navbarLargeIcons@ .toolbarbutton-1:not([type=menu-button]),
 @navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button,
 @navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
   padding: 5px 2px;
   -moz-box-pack: center;
 }
 
-@navbarLargeIcons@ .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button) {
+@navbarLargeIcons@ .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button):not(#social-provider-button) {
   padding-left: 5px;
   padding-right: 5px;
 }
 
 @navbarLargeIcons@ .toolbarbutton-1 > menupopup {
   margin-top: -3px;
 }
 
@@ -703,40 +703,45 @@ toolbar[mode=full] .toolbarbutton-1 > .t
   transition-duration: 150ms;
 }
 
 @navbarLargeIcons@ .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon,
 @navbarLargeIcons@ .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
   padding: 3px 7px;
 }
 
-@navbarLargeIcons@ .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button) > .toolbarbutton-icon,
+@navbarLargeIcons@ .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button):not(#social-provider-button) > .toolbarbutton-icon,
 @navbarLargeIcons@ .toolbarbutton-1[type=menu] > .toolbarbutton-text /* hack for add-ons that forcefully display the label */ {
   -moz-padding-end: 17px;
 }
 
 @navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menu-dropmarker {
   -moz-margin-start: -15px;
 }
 
 @navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
   -moz-border-end: none;
 }
 
 @navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
   padding: 8px 3px 7px;
 }
 
-@navbarLargeIcons@ .toolbarbutton-1:not(:hover):not(:active):not([open]) > .toolbarbutton-menubutton-dropmarker::before {
+@navbarLargeIcons@ .toolbarbutton-1:not(:hover):not(:active):not([open]) > .toolbarbutton-menubutton-dropmarker::before,
+@navbarLargeIcons@ > #social-toolbar-item > .toolbarbutton-1:not(:first-child)::before {
   content: "";
   display: -moz-box;
   width: 1px;
   height: 18px;
   -moz-margin-end: -1px;
-  background: hsla(210,54%,20%,.2) padding-box;
+  background-image: linear-gradient(hsla(210,54%,20%,.2) 0, hsla(210,54%,20%,.2) 18px);
+  background-clip: padding-box;
+  background-position: center;
+  background-repeat: no-repeat;
+  background-size: 1px 18px;
   box-shadow: 0 0 0 1px hsla(0,0%,100%,.2);
 }
 
 @navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon:-moz-locale-dir(ltr),
 @navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:-moz-locale-dir(rtl) {
   border-top-right-radius: 0;
   border-bottom-right-radius: 0;
 }
@@ -2272,19 +2277,17 @@ toolbarbutton.bookmark-item[dragover="tr
 .popup-notification-icon[popupid="addon-install-failed"],
 .popup-notification-icon[popupid="addon-install-complete"] {
   list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
   width: 32px;
   height: 32px;
 }
 
 .popup-notification-icon[popupid="click-to-play-plugins"] {
-  list-style-image: url(chrome://mozapps/skin/plugins/pluginGeneric.png);
-  width: 32px;
-  height: 32px;
+  list-style-image: url(chrome://mozapps/skin/plugins/pluginBlocked-64.png);
 }
 
 .addon-progress-description {
   width: 350px;
   max-width: 350px;
 }
 
 .popup-progress-label,
@@ -3281,98 +3284,54 @@ html|*#gcli-output-frame {
   color: #FDF3DE;
   min-width: 16px;
   text-shadow: none;
   background-image: -moz-linear-gradient(top, #B4211B, #8A1915);
   border-radius: 1px;
   -moz-margin-end: 5px;
 }
 
-
-/* social toolbar button */
-.social-statusarea-container {
-  -moz-appearance: none;
-  margin: 2px; /* make sure we have the correct platform spacing*/
+/* Social toolbar item */
+
+#social-provider-button > .toolbarbutton-menu-dropmarker {
+  display: none;
+}
+
+@navbarLargeIcons@ > #social-toolbar-item > .toolbarbutton-1 {
+  padding: 5px 0;
+}
+
+@navbarLargeIcons@ > #social-toolbar-item > .toolbarbutton-1:first-child {
+  -moz-padding-start: 5px;
+}
+
+@navbarLargeIcons@ > #social-toolbar-item > .toolbarbutton-1:last-child {
+  -moz-padding-end: 5px;
+}
+
+.social-notification-icon-hbox {
+  pointer-events: none;
+  margin-top: -5px;
+  -moz-margin-end: -12px;
+}
+
+.social-notification-icon-label {
+  text-align: end;
+  font-size: 9px;
+  font-weight: bold;
   padding: 0 1px;
-  border: 1px solid transparent;
-  border-radius: 2px;
-}
-
-.social-statusarea-container:hover {
-  background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
-  border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.2) hsla(210,54%,20%,.25);
-  box-shadow: 0 1px hsla(0,0%,100%,.3) inset,
-              0 1px hsla(210,54%,20%,.03),
-              0 0 2px hsla(210,54%,20%,.1);
-}
-
-#social-toolbar-button[open="true"] > .social-statusarea-container {
-  background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
-  background-color: hsla(210,54%,20%,.15);
-  border-color: hsla(210,54%,20%,.3) hsla(210,54%,20%,.35) hsla(210,54%,20%,.4);
-  box-shadow: 0 1px 1px hsla(210,54%,20%,.1) inset,
-              0 0 1px hsla(210,54%,20%,.2) inset;
-}
-
-/* favicon for the service */
-#social-provider-image {
-  -moz-appearance: none;
-  border: none;
-  min-width: 20px;
-  min-height: 16px;
-  padding: 2px 5px;
-  margin: 0;
-  background: transparent;
-  list-style-image: url("chrome://browser/skin/social/social.png");
-}
-
-#social-provider-image > .button-box > .box-inherit > .button-icon {
-  max-height: 16px;
-  max-width: 16px;
-}
-
-#social-provider-image > .button-box {
-  padding: 0;
-  margin: 0;
-  background: transparent;
-  border: none;
-}
-
-#social-provider-image > .button-box > .button-menu-dropmarker {
-  display: none;
-}
-
-/* hbox that hold notification icons */
-#social-status-iconbox {
-  margin: 0;
-  padding: 0;
-}
-
-/* hbox that surrounds an image and its counter */
-.social-notification-icon-container {
-  padding: 0;
-  margin: 0;
-  position: relative;
-}
-
-/* notification counter box */
-.social-notification-icon-counter {
+  color: white;
   background-color: rgb(240,61,37);
   border: 1px solid rgb(216,55,34);
-  box-shadow: 0px 1px 0px rgba(0,39,121,0.77);
-  padding-right: 1px;
-  padding-left: 1px;
-  color: white;
-  font-size: 9px;
-  font-weight: bold;
-  position: absolute;
-  right: -3px;
-  top: -4px;
-  z-index: 1;
-  text-align: center;
+  border-radius: 2px;
+  box-shadow: 0 1px 0 rgba(0,39,121,0.77);
+}
+
+.social-notification-icon-label[value=""] {
+  display: none;
 }
 
 /* notification image */
 .social-notification-icon-image {
   padding: 2px;
   margin: 0;
   min-width: 20px;
   max-width: 32px;
@@ -3389,36 +3348,36 @@ html|*#gcli-output-frame {
 
 #social-statusarea-user {
   border-bottom: 1px solid rgb(221,221,221);
   background-color: -moz-Dialog;
   color: -moz-dialogtext;
   position: relative;
   font: message-box;
   font-size: 12px;
+  cursor: pointer;
 }
 
 #social-statusarea-user-portrait {
   width: 32px;
   height: 32px;
   border-radius: 2px;
   margin: 10px;
 }
 
-#social-statusarea-username {
+#social-statusarea-user > vbox > .link {
   -moz-appearance: none;
   background: transparent;
   border: none;
   color: -moz-nativehyperlinktext;
-  cursor: pointer;
   min-width: 0;
   margin: 0 6px;
   list-style-image: none;
 }
-#social-statusarea-username:hover {
+#social-statusarea-user:hover > vbox > .link {
   text-decoration: underline;
 }
 
 .social-panel > .panel-arrowcontainer > .panel-arrowcontent {
   padding: 0;
 }
 
 #social-notification-box,
@@ -3552,8 +3511,117 @@ chatbox {
   border: 1px solid gray;
   border-bottom: none;
 }
 
 chatbox[minimized="true"] {
   width: 160px;
   height: 20px;
 }
+
+.click-to-play-plugins-notification-content {
+  margin: -10px;
+  border-radius: 4px;
+}
+
+.click-to-play-plugins-notification-icon-box {
+  background: hsla(0,0%,100%,.4);
+  -moz-border-end: 1px solid hsla(0,0%,100%,.2);
+  padding-top: 16px;
+  -moz-padding-end: 16px;
+  -moz-padding-start: 24px;
+}
+
+.click-to-play-plugins-notification-icon-box:-moz-locale-dir(ltr) {
+  border-bottom-left-radius: 4px;
+  border-top-left-radius: 4px;
+}
+
+.click-to-play-plugins-notification-icon-box:-moz-locale-dir(rtl) {
+  border-bottom-right-radius: 4px;
+  border-top-right-radius: 4px;
+}
+
+.click-to-play-plugins-notification-separator {
+  -moz-border-start: 1px solid hsla(211,79%,6%,.1);
+  border-top: 1px solid hsla(211,79%,6%,.1);
+}
+
+.click-to-play-plugins-notification-description-box {
+  border-bottom: 1px solid hsla(0,0%,100%,.2);
+  -moz-border-start: 1px solid hsla(0,0%,100%,.2);
+  padding-top: 12px;
+  -moz-padding-end: 11px;
+  padding-bottom: 9px;
+  -moz-padding-start: 10px;
+}
+
+.click-to-play-plugins-notification-center-box {
+  border-top: 1px solid hsla(0,0%,100%,.2);
+  border-bottom: 1px solid hsla(0,0%,100%,.2);
+  -moz-border-start: 1px solid hsla(0,0%,100%,.2);
+  background-color: hsla(211,79%,6%,.05);
+}
+
+.click-to-play-plugins-notification-button-container {
+  border-top: 1px solid hsla(0,0%,100%,.2);
+  -moz-border-start: 1px solid hsla(0,0%,100%,.2);
+  margin: 0px;
+  padding: 16px;
+}
+
+.center-item-box {
+  padding: 12px 16px 0px 16px;
+}
+
+.center-item-box[padbottom="true"] {
+  padding-bottom: 12px;
+}
+
+.center-item-icon {
+  background-image: url("chrome://mozapps/skin/plugins/pluginGeneric-16.png");
+  background-repeat: no-repeat;
+  height: 16px;
+  width: 16px;
+  margin-bottom: 4px;
+}
+
+.center-item-box[warn="true"] {
+  background-image: url("chrome://mozapps/skin/extensions/stripes-info-negative-small.png");
+  background-repeat: repeat-x;
+  padding: 8px 16px 6px 16px;
+}
+
+.center-item-box[padbottom="true"][warn="true"] {
+  padding-bottom: 4px;
+}
+
+.center-item-box[showseparator="true"] {
+  border-top: 1px solid hsla(211,79%,6%,.1);
+}
+
+.center-item-box[warn="false"] > .center-item-warning {
+  display: none;
+}
+
+.center-item-warning > .text-link {
+  color: #3d8cd7;
+}
+
+.center-item-warning > .text-link[href=""] {
+  display: none;
+}
+
+.center-item-warning-icon {
+  background-image: url("chrome://mozapps/skin/extensions/alerticon-info-negative.png");
+  background-repeat: no-repeat;
+  width: 16px;
+  height: 15px;
+  margin-bottom: 4px;
+}
+
+.center-item-warning-description {
+  color: #828282;
+}
+
+.center-item-button {
+  min-width: 0;
+}
--- a/browser/themes/winstripe/devtools/common.css
+++ b/browser/themes/winstripe/devtools/common.css
@@ -190,8 +190,38 @@
   border: 0;
   -moz-border-start: 1px solid #242b33;
   min-width: 0;
   width: 3px;
   background-color: transparent;
   -moz-margin-end: -3px;
   position: relative;
 }
+
+/* Theme */
+
+.devtools-theme-background {
+  background-color: white;
+}
+
+.devtools-theme-comment {
+  color: hsl(90,2%,46%); /* grey */
+}
+
+.devtools-theme-keyword {
+  color: hsl(276,44%,45%); /* purple */
+}
+
+.devtools-theme-string {
+  color: hsl(72,100%,27%); /* green */
+}
+
+.devtools-theme-tagname {
+  color: hsl(208,81%,21%); /* dark blue */
+}
+
+.devtools-theme-attrname {
+  color: hsl(208,56%,40%); /* blue */
+}
+
+.devtools-theme-attrvalue {
+  color: hsl(24,85%,39%); /* orange */
+}
--- a/browser/themes/winstripe/devtools/csshtmltree.css
+++ b/browser/themes/winstripe/devtools/csshtmltree.css
@@ -141,17 +141,17 @@
  * CSS Rule View
  */
 
 .ruleview {
   background-color: white;
 }
 
 .ruleview-rule-source {
-  color: hsl(121,42%,43%); /* green */
+  color: hsl(90,2%,46%); /* grey */
   -moz-padding-start: 5px;
   cursor: pointer;
   text-align: right;
   float: right;
   -moz-user-select: -moz-none;
 }
 
 .ruleview-rule-inheritance {
@@ -228,17 +228,17 @@
 
 .ruleview-newproperty {
   /* (enable checkbox width: 12px) + (expander width: 15px) */
   -moz-margin-start: 27px;
 }
 
 .ruleview-propertyname {
   padding: 1px 0;
-  color: hsl(210,100%,38%); /* blue */
+  color: hsl(276,44%,45%); /* purple */
 }
 
 .ruleview-propertyvalue {
   padding: 1px 0;
 }
 
 .ruleview-namecontainer,
 .ruleview-propertycontainer,
--- a/browser/themes/winstripe/devtools/markup-view.css
+++ b/browser/themes/winstripe/devtools/markup-view.css
@@ -4,42 +4,29 @@
 
 * {
   padding: 0;
   margin: 0;
 }
 
 body {
   font: message-box;
-  background-color: #131c26;
-  color: #8fa1b2;
+  color: hsl(0,0%,50%);
 }
 
-.tagname {
-  color: #a673bf;
-}
-
-.attrname {
-  color: #b26b47;
-}
-
-.attrvalue {
-  color: #3689b2;
+.text {
+  color: black;
 }
 
 .newattr {
   cursor: pointer;
 }
 
-.comment {
-  color: #5c6773;
-}
-
 .selected {
-  background-color: #253847;
+  background-color: hsl(0,0%,90%);
 }
 
 /* Give some padding to focusable elements to match the editor input
  * that will replace them. */
 span[tabindex] {
   display: inline-block;
   padding: 1px 0;
 }
--- a/browser/themes/winstripe/devtools/orion.css
+++ b/browser/themes/winstripe/devtools/orion.css
@@ -1,31 +1,31 @@
 /* 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/. */
 
 .viewContainer {
-  background: #cddae5; /* This will be seen as the continuation of the ruler */
+  background: hsl(0,0%,89%); /* This will be seen as the continuation of the ruler */
   font-family: monospace;
   font-size: inherit; /* inherit browser's default monospace font size */
 }
 
 .view {
   color: black; /* Default text color */
-  background: #f0f0ff; /* Background of the editor */
+  background: white; /* Background of the editor */
   padding-left: 4px;
 }
 
 .readonly > .view {
-  background: #f0f0ff;
+  background: #fdfefd; /* super light green */
 }
 
 .ruler {
-  background: #cddae5;
-  color: #7a8a99;
+  background: hsl(0,0%,89%);
+  color: hsl(0,0%,55%);
 }
 .ruler.annotations {
   width: 16px;
   padding-left: 4px;
 }
 .ruler.lines {
   border-right: 1px solid #b4c4d3;
   min-width: 1.4em;
@@ -100,48 +100,42 @@
 }
 .annotationRange.task {
   outline: 1px dashed rgba(0, 255, 0, 0.5);
 }
 .annotationRange.matchingBracket {
   outline: 1px solid grey;
 }
 
-.token_singleline_comment {
-  color: #45a946; /* green */
-}
-
-.token_multiline_comment {
-  color: #45a946; /* green */
-}
-
-.token_doc_comment {
-  color: #45a946; /* green */
+.token_singleline_comment,
+.token_multiline_comment,
+.token_doc_comment  {
+  color: hsl(90,2%,50%); /* grey */
 }
 
 .token_doc_html_markup {
   color: #dd0058; /* purple */
 }
 
 .token_doc_tag {
   color: #dd0058; /* purple */
 }
 
 .token_task_tag { /* "TODO" */
   color: black;
   background: yellow;
 }
 
 .token_string {
-  color: #1e66b1; /* blue */
+  color: hsl(72,100%,27%); /* green */
   font-style: italic;
 }
 
 .token_keyword {
-  color: #dd0058; /* purple */
+  color: hsl(276,44%,45%); /* purple */
 }
 
 .token_space {
   /* images/white_space.png */
   background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAIAAABv85FHAAAABnRSTlMA/wAAAACkwsAdAAAAIUlEQVR4nGP4z8CAC+GUIEXuABhgkTuABEiRw2cmae4EAH05X7xDolNRAAAAAElFTkSuQmCC");
   background-repeat: no-repeat;
   background-position: center center;
 }
@@ -150,42 +144,41 @@
   /* images/white_tab.png */
   background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAJCAIAAACJ2loDAAAABnRSTlMA/wD/AP83WBt9AAAAMklEQVR4nGP4TwRgoK6i52c3bz5w6zMSA6tJn28d2Lx589nnCAYu63AaSLxJRLoJPwAAeNk0aG4opfMAAAAASUVORK5CYII=");
   background-repeat: no-repeat;
   background-position: left center;
 }
 
 .line_caret,
 .annotationLine.currentLine { /* Current line */
-  background: #dae2ee; /* lighter than the background */
+  background: hsl(208, 93%, 94%);
 }
 
 .readonly .line_caret,
 .readonly .annotationLine.currentLine {
-  background: #cddae5; /* a bit darker than the background */
+  background: hsl(208, 80%, 90%);
 }
 
 /* Styling for html syntax highlighting */
 .entity-name-tag {
-  color: #dd0058; /* purple */
+  color: hsl(208,48%,40%); /* blue */
 }
 
 .entity-other-attribute-name {
-  color: #dd0058; /* purple */
+  color: hsl(208,48%,40%); /* blue */
 }
 
 .punctuation-definition-comment {
-  color: #45a946; /* green */
+  color: hsl(90,2%,50%); /* grey */
 }
 
 .comment {
-  color: #45a946; /* green */
+  color: hsl(90,2%,50%); /* grey */
 }
 
 .string-quoted {
-  color: #1e66b1; /* blue */
-  font-style: italic;
+  color: hsl(24,85%,39%); /* orange */
 }
 
 .invalid {
   color: red;
   font-weight: bold;
 }
--- a/build/mobile/b2gautomation.py
+++ b/build/mobile/b2gautomation.py
@@ -80,17 +80,17 @@ class B2GRemoteAutomation(Automation):
         # We always hide the results table in B2G; it's much slower if we don't.
         env['MOZ_HIDE_RESULTS_TABLE'] = '1'
         return env
 
     def waitForNet(self): 
         active = False
         time_out = 0
         while not active and time_out < 40:
-            data = self._devicemanager.runCmd(['shell', '/system/bin/netcfg']).stdout.readlines()
+            data = self._devicemanager._runCmd(['shell', '/system/bin/netcfg']).stdout.readlines()
             data.pop(0)
             for line in data:
                 if (re.search(r'UP\s+(?:[0-9]{1,3}\.){3}[0-9]{1,3}', line)):
                     active = True
                     break
             time_out += 1
             time.sleep(1)
         return active
@@ -151,17 +151,17 @@ class B2GRemoteAutomation(Automation):
 
     def getDeviceStatus(self, serial=None):
         # Get the current status of the device.  If we know the device
         # serial number, we look for that, otherwise we use the (presumably
         # only) device shown in 'adb devices'.
         serial = serial or self._devicemanager.deviceSerial
         status = 'unknown'
 
-        for line in self._devicemanager.runCmd(['devices']).stdout.readlines():
+        for line in self._devicemanager._runCmd(['devices']).stdout.readlines():
             result =  re.match('(.*?)\t(.*)', line)
             if result:
                 thisSerial = result.group(1)
                 if not serial or thisSerial == serial:
                     serial = thisSerial
                     status = result.group(2)
 
         return (serial, status)
@@ -176,17 +176,17 @@ class B2GRemoteAutomation(Automation):
         if self._is_emulator:
             self.marionette.emulator.wait_for_port()
 
     def rebootDevice(self):
         # find device's current status and serial number
         serial, status = self.getDeviceStatus()
 
         # reboot!
-        self._devicemanager.runCmd(['shell', '/system/bin/reboot'])
+        self._devicemanager._runCmd(['shell', '/system/bin/reboot'])
 
         # The above command can return while adb still thinks the device is
         # connected, so wait a little bit for it to disconnect from adb.
         time.sleep(10)
 
         # wait for device to come back to previous status
         print 'waiting for device to come back online after reboot'
         start = time.time()
@@ -216,17 +216,17 @@ class B2GRemoteAutomation(Automation):
             self.rebootDevice()
             time.sleep(5)
             #wait for wlan to come up 
             if not self.waitForNet():
                 raise Exception("network did not come up, please configure the network" + 
                                 " prior to running before running the automation framework")
 
         # stop b2g
-        self._devicemanager.runCmd(['shell', 'stop', 'b2g'])
+        self._devicemanager._runCmd(['shell', 'stop', 'b2g'])
         time.sleep(5)
 
         # relaunch b2g inside b2g instance
         instance = self.B2GInstance(self._devicemanager)
 
         time.sleep(5)
 
         # Set up port forwarding again for Marionette, since any that
--- a/build/pymake/make.py
+++ b/build/pymake/make.py
@@ -7,13 +7,16 @@ A drop-in or mostly drop-in replacement 
 """
 
 import sys, os
 import pymake.command, pymake.process
 
 import gc
 
 if __name__ == '__main__':
+  sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
+  sys.stderr = os.fdopen(sys.stderr.fileno(), 'w', 0)
+
   gc.disable()
 
   pymake.command.main(sys.argv[1:], os.environ, os.getcwd(), cb=sys.exit)
   pymake.process.ParallelContext.spin()
   assert False, "Not reached"
--- a/build/pymake/pymake/data.py
+++ b/build/pymake/pymake/data.py
@@ -442,17 +442,17 @@ class Variables(object):
     SOURCE_IMPLICIT = 5
 
     def __init__(self, parent=None):
         self._map = {} # vname -> flavor, source, valuestr, valueexp
         self.parent = parent
 
     def readfromenvironment(self, env):
         for k, v in env.iteritems():
-            self.set(k, self.FLAVOR_SIMPLE, self.SOURCE_ENVIRONMENT, v)
+            self.set(k, self.FLAVOR_RECURSIVE, self.SOURCE_ENVIRONMENT, v)
 
     def get(self, name, expand=True):
         """
         Get the value of a named variable. Returns a tuple (flavor, source, value)
 
         If the variable is not present, returns (None, None, None)
 
         @param expand If true, the value will be returned as an expansion. If false,
new file mode 100644
--- /dev/null
+++ b/build/pymake/tests/env-var-append.mk
@@ -0,0 +1,7 @@
+#T environment: {'FOO': 'TEST'}
+
+FOO += $(BAR)
+BAR := PASS
+
+all:
+	@echo $(subst $(NULL) ,-,$(FOO))
new file mode 100644
--- /dev/null
+++ b/build/pymake/tests/env-var-append2.mk
@@ -0,0 +1,8 @@
+#T environment: {'FOO': '$(BAZ)'}
+
+FOO += $(BAR)
+BAR := PASS
+BAZ := TEST
+
+all:
+	@echo $(subst $(NULL) ,-,$(FOO))
--- a/build/valgrind/cross-architecture.sup
+++ b/build/valgrind/cross-architecture.sup
@@ -50,21 +50,21 @@
 {
    Bug 793532
    Memcheck:Leak
    fun:malloc
    fun:_ZN8JSObject25allocateSlowArrayElementsEP9JSContext
    ...
 }
 {
-   Bug 793533
+   Bug 793533 (all 64-bit systems)
    Memcheck:Leak
    fun:malloc
    fun:moz_xmalloc
-   fun:_Z22xpc_CreateGlobalObjectP9JSContextP7JSClassP12nsIPrincipalP11nsISupportsbPP8JSObjectPP13JSCompartment
+   fun:_ZN3xpc18CreateGlobalObjectEP9JSContextP7JSClassP12nsIPrincipalbPP8JSObjectPP13JSCompartment
    ...
 }
 {
    Bug 793536 (all 64-bit systems)
    Memcheck:Leak
    fun:malloc
    fun:moz_xmalloc
    fun:_ZNSt11_Deque_baseIN11MessageLoop11PendingTaskESaIS1_EE17_M_initialize_mapEm
@@ -83,65 +83,16 @@
    Memcheck:Leak
    fun:malloc
    fun:moz_xmalloc
    fun:NS_Alloc_P
    fun:_Z12ToNewCStringRK19nsACString_internal
    fun:_ZN13CrashReporter14SetupExtraDataEP7nsIFileRK19nsACString_internal
    ...
 }
-# Suppressing the suppression(s) to get Valgrind stacks with line numbers
-#{
-#   Bug 793601
-#   Memcheck:Leak
-#   fun:malloc
-#   fun:_ZN2js15ArgumentsObject6createEP9JSContextPNS_10StackFrameE
-#   ...
-#}
-#{
-#   Bug 793602
-#   Memcheck:Leak
-#   fun:malloc
-#   fun:moz_xmalloc
-#   fun:_Z22NS_NewComputedDOMStylePN7mozilla3dom7ElementERK18nsAString_internalP12nsIPresShell
-#   fun:_ZN14nsGlobalWindow16GetComputedStyleEP13nsIDOMElementRK18nsAString_internalPP25nsIDOMCSSStyleDeclaration
-#   ...
-#}
-#{
-#   Bug 793603
-#   Memcheck:Leak
-#   fun:malloc
-#   fun:moz_xmalloc
-#   fun:_ZN18nsDeflateConverter15OnDataAvailableEP10nsIRequestP11nsISupportsP14nsIInputStreammj
-#   ...
-#}
-#{
-#   Bug 793605
-#   Memcheck:Leak
-#   fun:malloc
-#   fun:moz_xmalloc
-#   fun:_Z30nsStringInputStreamConstructorP11nsISupportsRK4nsIDPPv
-#   ...
-#}
-#{
-#   Bug 793606
-#   Memcheck:Leak
-#   fun:malloc
-#   fun:moz_xmalloc
-#   fun:_ZL27nsXMLHttpRequestConstructorP11nsISupportsRK4nsIDPPv
-#   ...
-#}
-#{
-#   Bug 793607
-#   Memcheck:Leak
-#   fun:malloc
-#   fun:moz_xmalloc
-#   fun:_ZN11nsZipWriter14AddEntryStreamERK19nsACString_internalliP14nsIInputStreambj
-#   ...
-#}
 {
    Bug 793608
    Memcheck:Leak
    ...
    fun:gaih_inet
    fun:getaddrinfo
    fun:PR_GetAddrInfoByName
    fun:_ZN14nsHostResolver10ThreadFuncEPv
--- a/caps/tests/mochitest/test_principal_extendedorigin_appid_appstatus.html
+++ b/caps/tests/mochitest/test_principal_extendedorigin_appid_appstatus.html
@@ -359,16 +359,17 @@ function checkIFrame(aFrame, data) {
     }
   }
 
   eoList.push(principal.extendedOrigin);
 
   checkedCount++;
   if (checkedCount == checksTodo) {
     SpecialPowers.removePermission("browser", "http://example.org");
+    SpecialPowers.removePermission("embed-apps", "http://example.org");
     SimpleTest.finish();
   } else {
     gTestRunner.next();
   }
 }
 
 is('appStatus' in document.nodePrincipal, true,
    'appStatus should be present in nsIPrincipal');
@@ -384,16 +385,17 @@ function runTest() {
     let data = gData[i];
 
     var iframe = document.createElement('iframe');
     iframe.check = function() {
       checkIFrame(this, data);
     };
     iframe.addChild = function() {
       SpecialPowers.addPermission("browser", true, iframe.contentDocument);
+      SpecialPowers.addPermission("embed-apps", true, iframe.contentDocument);
 
       var childFrame = document.createElement('iframe');
 
       if (data.child.app) {
         childFrame.setAttribute('mozapp', data.child.app)
         childFrame.setAttribute('mozbrowser', '');
       } else if (data.child.browser) {
         childFrame.setAttribute('mozbrowser', '');
--- a/configure.in
+++ b/configure.in
@@ -49,17 +49,17 @@ dnl ====================================
 _SUBDIR_HOST_CFLAGS="$HOST_CFLAGS"
 _SUBDIR_HOST_CXXFLAGS="$HOST_CXXFLAGS"
 _SUBDIR_HOST_LDFLAGS="$HOST_LDFLAGS"
 _SUBDIR_CONFIG_ARGS="$ac_configure_args"
 
 dnl Set the version number of the libs included with mozilla
 dnl ========================================================
 MOZJPEG=62
-MOZPNG=10511
+MOZPNG=10513
 NSPR_VERSION=4
 NSS_VERSION=3
 
 dnl Set the minimum version of toolkit libs used by mozilla
 dnl ========================================================
 GLIB_VERSION=1.2.0
 PERL_VERSION=5.006
 PYTHON_VERSION_MAJOR=2
@@ -1481,21 +1481,23 @@ if test "$GNU_CXX"; then
     # Turn on GNU-specific warnings:
     # -Wall - turn on a lot of warnings
     # -pedantic - this is turned on below
     # -Wpointer-arith - enabled with -pedantic, but good to have even if not
     # -Woverloaded-virtual - ???
     # -Werror=return-type - catches missing returns, zero false positives
     # -Wtype-limits - catches overflow bugs, few false positives
     # -Wempty-body - catches bugs, e.g. "if (c); foo();", few false positives
+    # -Werror=conversion-null - catches conversions between NULL and non-pointer types
     #
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall -Wpointer-arith -Woverloaded-virtual"
     MOZ_CXX_SUPPORTS_WARNING(-W, error=return-type, ac_cxx_has_werror_return_type)
     MOZ_CXX_SUPPORTS_WARNING(-W, type-limits, ac_cxx_has_wtype_limits)
     MOZ_CXX_SUPPORTS_WARNING(-W, empty-body, ac_cxx_has_wempty_body)
+    MOZ_CXX_SUPPORTS_WARNING(-W, error=conversion-null, ac_cxx_has_werror_conversion_null)
 
     # Turn off the following warnings that -Wall/-pedantic turn on:
     # -Wno-ctor-dtor-privacy - ???
     # -Wno-overlength-strings - we exceed the minimum maximum length frequently 
     # -Wno-invalid-offsetof - we use offsetof on non-POD types frequently
     # -Wno-variadic-macros - ???
     #
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-ctor-dtor-privacy"
@@ -2192,17 +2194,23 @@ ia64*-hpux*)
         MKSHLIB_FORCE_ALL=
         MKSHLIB_UNFORCE_ALL=
         DSO_LDOPTS=-SUBSYSTEM:WINDOWS
         _USE_CPP_INCLUDE_FLAG=1
         _DEFINES_CFLAGS='-FI $(DEPTH)/dist/include/mozilla-config.h -DMOZILLA_CLIENT'
         _DEFINES_CXXFLAGS='-FI $(DEPTH)/dist/include/mozilla-config.h -DMOZILLA_CLIENT'
         CFLAGS="$CFLAGS -W3 -Gy -Fd\$(COMPILE_PDBFILE)"
         CXXFLAGS="$CXXFLAGS -W3 -Gy -Fd\$(COMPILE_PDBFILE)"
-        CXXFLAGS="$CXXFLAGS -wd4800" # disable warning "forcing value to bool"
+        # MSVC warning C4345 warns of newly conformant behavior as of VS2003.
+        # MSVC warning C4351 warns of newly conformant behavior as of VS2005.
+        # MSVC warning C4800 warns when a value is implicitly cast to bool,
+        # because this also forces narrowing to a single byte, which can be a
+        # perf hit.  But this matters so little in practice (and often we want
+        # that behavior) that it's better to turn it off.
+        CXXFLAGS="$CXXFLAGS -wd4345 -wd4351 -wd4800"
         # make 'foo == bar;' error out
         CFLAGS="$CFLAGS -we4553"
         CXXFLAGS="$CXXFLAGS -we4553"
         LIBS="$LIBS kernel32.lib user32.lib gdi32.lib winmm.lib wsock32.lib advapi32.lib"
         MOZ_DEBUG_FLAGS='-Zi'
         MOZ_DEBUG_LDFLAGS='-DEBUG -DEBUGTYPE:CV'
         WARNINGS_AS_ERRORS='-WX'
         MOZ_OPTIMIZE_FLAGS='-O1'
@@ -2964,21 +2972,55 @@ freebsd*|openbsd*)
     ;;
 esac
 MOZ_CHECK_COMMON_HEADERS
 
 dnl These are all the places some variant of statfs can be hiding.
 MOZ_CHECK_HEADERS(sys/statvfs.h sys/statfs.h sys/vfs.h sys/mount.h)
 
 dnl Quota support
+dnl SCTP support - needs various network include headers
 MOZ_CHECK_HEADERS(sys/quota.h sys/sysmacros.h)
-MOZ_CHECK_HEADERS(linux/quota.h)
+MOZ_CHECK_HEADERS([linux/quota.h linux/if_addr.h linux/rtnetlink.h],,,[#include <sys/socket.h>])
 
 MOZ_CHECK_HEADERS(sys/types.h netinet/in.h byteswap.h)
 
+dnl Check for sin_len and sin6_len - used by SCTP; only appears in Mac/*BSD generally
+AC_CACHE_CHECK(for sockaddr_in.sin_len,
+                   ac_cv_sockaddr_in_sin_len,
+                   [AC_TRY_COMPILE([#ifdef HAVE_SYS_TYPES_H
+                                    #include <sys/types.h>
+                                    #endif
+                                    #include <netinet/in.h>
+                                    struct sockaddr_in x;
+                                    void *foo = (void*) &x.sin_len;],
+                                   [],
+                                   [ac_cv_sockaddr_in_sin_len=true],
+                                   [ac_cv_sockaddr_in_sin_len=false])])
+if test "$ac_cv_sockaddr_in_sin_len" = true ; then
+  AC_DEFINE(HAVE_SIN_LEN)
+dnl HAVE_CONN_LEN must be the same as HAVE_SIN_LEN (and HAVE_SIN6_LEN too)
+  AC_DEFINE(HAVE_CONN_LEN)
+fi
+
+AC_CACHE_CHECK(for sockaddr_in6.sin6_len,
+               ac_cv_sockaddr_in6_sin6_len,
+               [AC_TRY_COMPILE([#ifdef HAVE_SYS_TYPES_H
+                                #include <sys/types.h>
+                                #endif
+                                #include <netinet/in.h>
+                                struct sockaddr_in6 x;
+                                void *foo = (void*) &x.sin6_len;],
+                               [],
+                               [ac_cv_sockaddr_in6_sin6_len=true],
+                               [ac_cv_sockaddr_in6_sin6_len=false])])
+if test "$ac_cv_sockaddr_in6_sin6_len" = true ; then
+  AC_DEFINE(HAVE_SIN6_LEN)
+fi
+
 dnl Check whether the compiler supports the new-style C++ standard
 dnl library headers (i.e. <new>) or needs the old "new.h"
 AC_LANG_CPLUSPLUS
 NEW_H=new.h
 MOZ_CHECK_HEADER(new, [NEW_H=new])
 AC_DEFINE_UNQUOTED(NEW_H, <$NEW_H>)
 AC_LANG_C
 
@@ -4180,16 +4222,17 @@ MOZ_SAMPLE_TYPE_FLOAT32=
 MOZ_SAMPLE_TYPE_S16=
 MOZ_MEDIA=
 MOZ_OPUS=1
 MOZ_WEBM=1
 MOZ_DASH=
 MOZ_WEBRTC=1
 MOZ_SRTP=
 MOZ_WEBRTC_SIGNALING=
+MOZ_SCTP=
 MOZ_MEDIA_PLUGINS=
 MOZ_MEDIA_NAVIGATOR=
 MOZ_OMX_PLUGIN=
 MOZ_VP8=
 MOZ_VP8_ERROR_CONCEALMENT=
 MOZ_VP8_ENCODER=
 VPX_AS=
 VPX_ASFLAGS=
@@ -4208,17 +4251,17 @@ MOZ_PERMISSIONS=1
 MOZ_PLACES=1
 MOZ_PREF_EXTENSIONS=1
 MOZ_PROFILELOCKING=1
 MOZ_PSM=1
 MOZ_REFLOW_PERF=
 MOZ_SAFE_BROWSING=
 MOZ_HELP_VIEWER=
 MOZ_SPELLCHECK=1
-MOZ_JAVA_COMPOSITOR=
+MOZ_ANDROID_OMTC=
 MOZ_ONLY_TOUCH_EVENTS=
 MOZ_TOOLKIT_SEARCH=1
 MOZ_UI_LOCALE=en-US
 MOZ_UNIVERSALCHARDET=1
 MOZ_URL_CLASSIFIER=
 MOZ_XTF=1
 MOZ_XUL=1
 MOZ_ZIPWRITER=1
@@ -5035,21 +5078,21 @@ dnl = Enable Android History instead of 
 dnl ========================================================
 if test -n "$MOZ_ANDROID_HISTORY"; then
      dnl Do this if defined in confvars.sh
      AC_DEFINE(MOZ_ANDROID_HISTORY)
 fi
 
 
 dnl ========================================================
-dnl = Build with the Android Java compositor
-dnl ========================================================
-if test -n "$MOZ_JAVA_COMPOSITOR"; then
+dnl = Build with the Android compositor
+dnl ========================================================
+if test -n "$MOZ_ANDROID_OMTC"; then
      dnl Do this if defined in confvars.sh
-     AC_DEFINE(MOZ_JAVA_COMPOSITOR)
+     AC_DEFINE(MOZ_ANDROID_OMTC)
 fi
 
 dnl ========================================================
 dnl = Disable WebSMS backend
 dnl ========================================================
 MOZ_ARG_DISABLE_BOOL(websms-backend,
 [  --disable-websms-backend
                            Disable WebSMS backend],
@@ -5175,21 +5218,24 @@ MOZ_ARG_DISABLE_BOOL(webrtc,
 
 if test -n "$MOZ_WEBRTC"; then
     AC_DEFINE(MOZ_WEBRTC)
     MOZ_MEDIA=1
     MOZ_RAW=1
     MOZ_VP8=1
     MOZ_VP8_ENCODER=1
     MOZ_VP8_ERROR_CONCEALMENT=1
+    MOZ_SCTP=1
     MOZ_SRTP=1
+    AC_DEFINE(MOZ_SCTP)
     AC_DEFINE(MOZ_SRTP)
 fi
 
 AC_SUBST(MOZ_WEBRTC)
+AC_SUBST(MOZ_SCTP)
 AC_SUBST(MOZ_SRTP)
 
 case "$target_cpu" in
 arm*)
     MOZ_SAMPLE_TYPE_S16=1
     AC_DEFINE(MOZ_SAMPLE_TYPE_S16)
     AC_SUBST(MOZ_SAMPLE_TYPE_S16)
 ;;
@@ -8248,17 +8294,17 @@ AC_SUBST(JAR)
 AC_SUBST(MOZ_PROFILELOCKING)
 
 AC_SUBST(ENABLE_TESTS)
 AC_SUBST(ENABLE_MARIONETTE)
 AC_SUBST(IBMBIDI)
 AC_SUBST(MOZ_UNIVERSALCHARDET)
 AC_SUBST(ACCESSIBILITY)
 AC_SUBST(MOZ_SPELLCHECK)
-AC_SUBST(MOZ_JAVA_COMPOSITOR)
+AC_SUBST(MOZ_ANDROID_OMTC)
 AC_SUBST(MOZ_ONLY_TOUCH_EVENTS)
 AC_SUBST(MOZ_CRASHREPORTER)
 AC_SUBST(MOZ_CRASHREPORTER_INJECTOR)
 AC_SUBST(MOZ_MAINTENANCE_SERVICE)
 AC_SUBST(MOZ_STUB_INSTALLER)
 AC_SUBST(MOZ_VERIFY_MAR_SIGNATURE)
 AC_SUBST(MOZ_ENABLE_SIGNMAR)
 AC_SUBST(MOZ_UPDATER)
--- a/content/base/public/Element.h
+++ b/content/base/public/Element.h
@@ -13,51 +13,52 @@
 #include "mozilla/dom/DirectionalityUtils.h"
 
 class nsEventStateManager;
 class nsFocusManager;
 class nsGlobalWindow;
 class nsICSSDeclaration;
 class nsISMILAttr;
 
+#define ELEMENT_FLAG_BIT(n_) NODE_FLAG_BIT(NODE_TYPE_SPECIFIC_BITS_OFFSET + (n_))
+
 // Element-specific flags
 enum {
   // Set if the element has a pending style change.
-  ELEMENT_HAS_PENDING_RESTYLE     = (1 << NODE_TYPE_SPECIFIC_BITS_OFFSET),
+  ELEMENT_HAS_PENDING_RESTYLE =                 ELEMENT_FLAG_BIT(0),
 
   // Set if the element is a potential restyle root (that is, has a style
   // change pending _and_ that style change will attempt to restyle
   // descendants).
-  ELEMENT_IS_POTENTIAL_RESTYLE_ROOT =
-    (1 << (NODE_TYPE_SPECIFIC_BITS_OFFSET + 1)),
+  ELEMENT_IS_POTENTIAL_RESTYLE_ROOT =           ELEMENT_FLAG_BIT(1),
 
   // Set if the element has a pending animation style change.
-  ELEMENT_HAS_PENDING_ANIMATION_RESTYLE =
-    (1 << (NODE_TYPE_SPECIFIC_BITS_OFFSET + 2)),
+  ELEMENT_HAS_PENDING_ANIMATION_RESTYLE =       ELEMENT_FLAG_BIT(2),
 
   // Set if the element is a potential animation restyle root (that is,
   // has an animation style change pending _and_ that style change
   // will attempt to restyle descendants).
-  ELEMENT_IS_POTENTIAL_ANIMATION_RESTYLE_ROOT =
-    (1 << (NODE_TYPE_SPECIFIC_BITS_OFFSET + 3)),
+  ELEMENT_IS_POTENTIAL_ANIMATION_RESTYLE_ROOT = ELEMENT_FLAG_BIT(3),
 
   // All of those bits together, for convenience.
   ELEMENT_ALL_RESTYLE_FLAGS = ELEMENT_HAS_PENDING_RESTYLE |
                               ELEMENT_IS_POTENTIAL_RESTYLE_ROOT |
                               ELEMENT_HAS_PENDING_ANIMATION_RESTYLE |
                               ELEMENT_IS_POTENTIAL_ANIMATION_RESTYLE_ROOT,
 
   // Just the HAS_PENDING bits, for convenience
   ELEMENT_PENDING_RESTYLE_FLAGS = ELEMENT_HAS_PENDING_RESTYLE |
                                   ELEMENT_HAS_PENDING_ANIMATION_RESTYLE,
 
   // Remaining bits are for subclasses
   ELEMENT_TYPE_SPECIFIC_BITS_OFFSET = NODE_TYPE_SPECIFIC_BITS_OFFSET + 4
 };
 
+#undef ELEMENT_FLAG_BIT
+
 namespace mozilla {
 namespace dom {
 
 class Link;
 
 // IID for the dom::Element interface
 #define NS_ELEMENT_IID \
 { 0xc6c049a1, 0x96e8, 0x4580, \
--- a/content/base/public/FragmentOrElement.h
+++ b/content/base/public/FragmentOrElement.h
@@ -405,17 +405,17 @@ public:
   };
 
 protected:
   // Override from nsINode
   virtual nsINode::nsSlots* CreateSlots();
 
   nsDOMSlots *DOMSlots()
   {
-    return static_cast<nsDOMSlots*>(GetSlots());
+    return static_cast<nsDOMSlots*>(Slots());
   }
 
   nsDOMSlots *GetExistingDOMSlots() const
   {
     return static_cast<nsDOMSlots*>(GetExistingSlots());
   }
 
   friend class ::ContentUnbinder;
--- a/content/base/public/nsDeprecatedOperationList.h
+++ b/content/base/public/nsDeprecatedOperationList.h
@@ -42,8 +42,9 @@ DEPRECATED_OPERATION(EnablePrivilege)
 DEPRECATED_OPERATION(Position)
 DEPRECATED_OPERATION(TotalSize)
 DEPRECATED_OPERATION(InputEncoding)
 DEPRECATED_OPERATION(MozBeforePaint)
 DEPRECATED_OPERATION(DOMExceptionCode)
 DEPRECATED_OPERATION(NoExposedProps)
 DEPRECATED_OPERATION(MutationEvent)
 DEPRECATED_OPERATION(MozSlice)
+DEPRECATED_OPERATION(Components)
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -51,113 +51,114 @@ class Element;
 } // namespace mozilla
 
 namespace JS {
 class Value;
 }
 
 inline void SetDOMStringToNull(nsAString& aString);
 
+#define NODE_FLAG_BIT(n_) (1U << (n_))
+
 enum {
   // This bit will be set if the node has a listener manager.
-  NODE_HAS_LISTENERMANAGER =     0x00000001U,
+  NODE_HAS_LISTENERMANAGER =              NODE_FLAG_BIT(0),
 
   // Whether this node has had any properties set on it
-  NODE_HAS_PROPERTIES =          0x00000002U,
+  NODE_HAS_PROPERTIES =                   NODE_FLAG_BIT(1),
 
   // Whether this node is the root of an anonymous subtree.  Note that this
   // need not be a native anonymous subtree.  Any anonymous subtree, including
   // XBL-generated ones, will do.  This flag is set-once: once a node has it,
   // it must not be removed.
   // NOTE: Should only be used on nsIContent nodes
-  NODE_IS_ANONYMOUS =            0x00000004U,
+  NODE_IS_ANONYMOUS =                     NODE_FLAG_BIT(2),
 
   // Whether the node has some ancestor, possibly itself, that is native
   // anonymous.  This includes ancestors crossing XBL scopes, in cases when an
   // XBL binding is attached to an element which has a native anonymous
   // ancestor.  This flag is set-once: once a node has it, it must not be
   // removed.
   // NOTE: Should only be used on nsIContent nodes
-  NODE_IS_IN_ANONYMOUS_SUBTREE = 0x00000008U,
+  NODE_IS_IN_ANONYMOUS_SUBTREE =          NODE_FLAG_BIT(3),
 
   // Whether this node is the root of a native anonymous (from the perspective
   // of its parent) subtree.  This flag is set-once: once a node has it, it
   // must not be removed.
   // NOTE: Should only be used on nsIContent nodes
-  NODE_IS_NATIVE_ANONYMOUS_ROOT = 0x00000010U,
+  NODE_IS_NATIVE_ANONYMOUS_ROOT =         NODE_FLAG_BIT(4),
 
   // Forces the XBL code to treat this node as if it were
   // in the document and therefore should get bindings attached.
-  NODE_FORCE_XBL_BINDINGS =      0x00000020U,
+  NODE_FORCE_XBL_BINDINGS =               NODE_FLAG_BIT(5),
 
   // Whether a binding manager may have a pointer to this
-  NODE_MAY_BE_IN_BINDING_MNGR =  0x00000040U,
+  NODE_MAY_BE_IN_BINDING_MNGR =           NODE_FLAG_BIT(6),
 
-  NODE_IS_EDITABLE =             0x00000080U,
+  NODE_IS_EDITABLE =                      NODE_FLAG_BIT(7),
 
   // For all Element nodes, NODE_MAY_HAVE_CLASS is guaranteed to be set if the
   // node in fact has a class, but may be set even if it doesn't.
-  NODE_MAY_HAVE_CLASS =          0x00000100U,
+  NODE_MAY_HAVE_CLASS =                   NODE_FLAG_BIT(8),
 
-  NODE_IS_INSERTION_PARENT =     0x00000200U,
+  NODE_IS_INSERTION_PARENT =              NODE_FLAG_BIT(9),
 
   // Node has an :empty or :-moz-only-whitespace selector
-  NODE_HAS_EMPTY_SELECTOR =      0x00000400U,
+  NODE_HAS_EMPTY_SELECTOR =               NODE_FLAG_BIT(10),
 
   // A child of the node has a selector such that any insertion,
   // removal, or appending of children requires restyling the parent.
-  NODE_HAS_SLOW_SELECTOR =       0x00000800U,
+  NODE_HAS_SLOW_SELECTOR =                NODE_FLAG_BIT(11),
 
   // A child of the node has a :first-child, :-moz-first-node,
   // :only-child, :last-child or :-moz-last-node selector.
-  NODE_HAS_EDGE_CHILD_SELECTOR = 0x00001000U,
+  NODE_HAS_EDGE_CHILD_SELECTOR =          NODE_FLAG_BIT(12),
 
   // A child of the node has a selector such that any insertion or
   // removal of children requires restyling later siblings of that
   // element.  Additionally (in this manner it is stronger than
   // NODE_HAS_SLOW_SELECTOR), if a child's style changes due to any
   // other content tree changes (e.g., the child changes to or from
   // matching :empty due to a grandchild insertion or removal), the
   // child's later siblings must also be restyled.
-  NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS
-                               = 0x00002000U,
+  NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS = NODE_FLAG_BIT(13),
 
-  NODE_ALL_SELECTOR_FLAGS =      NODE_HAS_EMPTY_SELECTOR |
-                                 NODE_HAS_SLOW_SELECTOR |
-                                 NODE_HAS_EDGE_CHILD_SELECTOR |
-                                 NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS,
+  NODE_ALL_SELECTOR_FLAGS =               NODE_HAS_EMPTY_SELECTOR |
+                                          NODE_HAS_SLOW_SELECTOR |
+                                          NODE_HAS_EDGE_CHILD_SELECTOR |
+                                          NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS,
 
-  NODE_ATTACH_BINDING_ON_POSTCREATE
-                               = 0x00004000U,
+  NODE_ATTACH_BINDING_ON_POSTCREATE =     NODE_FLAG_BIT(14),
 
   // This node needs to go through frame construction to get a frame (or
   // undisplayed entry).
-  NODE_NEEDS_FRAME =             0x00008000U,
+  NODE_NEEDS_FRAME =                      NODE_FLAG_BIT(15),
 
   // At least one descendant in the flattened tree has NODE_NEEDS_FRAME set.
   // This should be set on every node on the flattened tree path between the
   // node(s) with NODE_NEEDS_FRAME and the root content.
-  NODE_DESCENDANTS_NEED_FRAMES = 0x00010000U,
+  NODE_DESCENDANTS_NEED_FRAMES =          NODE_FLAG_BIT(16),
 
   // Set if the node has the accesskey attribute set.
-  NODE_HAS_ACCESSKEY           = 0x00020000U,
+  NODE_HAS_ACCESSKEY =                    NODE_FLAG_BIT(17),
 
   // Set if the node is handling a click.
-  NODE_HANDLING_CLICK          = 0x00040000U,
+  NODE_HANDLING_CLICK =                   NODE_FLAG_BIT(18),
 
   // Set if the node has had :hover selectors matched against it
-  NODE_HAS_RELEVANT_HOVER_RULES = 0x00080000U,
+  NODE_HAS_RELEVANT_HOVER_RULES =         NODE_FLAG_BIT(19),
 
   // Set if the node has right-to-left directionality
-  NODE_HAS_DIRECTION_RTL        = 0x00100000U,
+  NODE_HAS_DIRECTION_RTL =                NODE_FLAG_BIT(20),
 
   // Set if the node has left-to-right directionality
-  NODE_HAS_DIRECTION_LTR        = 0x00200000U,
+  NODE_HAS_DIRECTION_LTR =                NODE_FLAG_BIT(21),
 
-  NODE_ALL_DIRECTION_FLAGS      = NODE_HAS_DIRECTION_LTR | NODE_HAS_DIRECTION_RTL,
+  NODE_ALL_DIRECTION_FLAGS =              NODE_HAS_DIRECTION_LTR |
+                                          NODE_HAS_DIRECTION_RTL,
 
   // Remaining bits are node type specific.
   NODE_TYPE_SPECIFIC_BITS_OFFSET =        22
 };
 
 /**
  * Class used to detect unexpected mutations. To use the class create an
  * nsMutationGuard on the stack before unexpected mutations could occur.
@@ -784,35 +785,31 @@ public:
    * remove itself in case it dies before the node.  If an observer is added
    * while observers are being notified, it may also be notified.  In general,
    * adding observers while inside a notification is not a good idea.  An
    * observer that is already observing the node must not be added without
    * being removed first.
    */
   void AddMutationObserver(nsIMutationObserver* aMutationObserver)
   {
-    nsSlots* s = GetSlots();
-    if (s) {
-      NS_ASSERTION(s->mMutationObservers.IndexOf(aMutationObserver) ==
-                   nsTArray<int>::NoIndex,
-                   "Observer already in the list");
-      s->mMutationObservers.AppendElement(aMutationObserver);
-    }
+    nsSlots* s = Slots();
+    NS_ASSERTION(s->mMutationObservers.IndexOf(aMutationObserver) ==
+                 nsTArray<int>::NoIndex,
+                 "Observer already in the list");
+    s->mMutationObservers.AppendElement(aMutationObserver);
   }
 
   /**
    * Same as above, but only adds the observer if its not observing
    * the node already.
    */
   void AddMutationObserverUnlessExists(nsIMutationObserver* aMutationObserver)
   {
-    nsSlots* s = GetSlots();
-    if (s) {
-      s->mMutationObservers.AppendElementUnlessExists(aMutationObserver);
-    }
+    nsSlots* s = Slots();
+    s->mMutationObservers.AppendElementUnlessExists(aMutationObserver);
   }
 
   /**
    * Removes a mutation observer.
    */
   void RemoveMutationObserver(nsIMutationObserver* aMutationObserver)
   {
     nsSlots* s = GetExistingSlots();
@@ -888,21 +885,21 @@ public:
   };
 
   /**
    * Functions for managing flags and slots
    */
 #ifdef DEBUG
   nsSlots* DebugGetSlots()
   {
-    return GetSlots();
+    return Slots();
   }
 #endif
 
-  bool HasFlag(PtrBits aFlag) const
+  bool HasFlag(uintptr_t aFlag) const
   {
     return !!(GetFlags() & aFlag);
   }
 
   uint32_t GetFlags() const
   {
     return mFlags;
   }
@@ -1414,32 +1411,34 @@ public:
    * Returns the length of this node, as specified at
    * <http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-length>
    */
   uint32_t Length() const;
 
 protected:
 
   // Override this function to create a custom slots class.
+  // Must not return null.
   virtual nsINode::nsSlots* CreateSlots();
 
   bool HasSlots() const
   {
     return mSlots != nullptr;
   }
 
   nsSlots* GetExistingSlots() const
   {
     return mSlots;
   }
 
-  nsSlots* GetSlots()
+  nsSlots* Slots()
   {
     if (!HasSlots()) {
       mSlots = CreateSlots();
+      MOZ_ASSERT(mSlots);
     }
     return GetExistingSlots();
   }
 
   nsTObserverArray<nsIMutationObserver*> *GetMutationObservers()
   {
     return HasSlots() ? &GetExistingSlots()->mMutationObservers : nullptr;
   }
--- a/content/base/src/CSPUtils.jsm
+++ b/content/base/src/CSPUtils.jsm
@@ -402,16 +402,17 @@ CSPRep.fromString = function(aStr, self,
 
       // suspend the parent document request while we fetch the policy-uri
       try {
         docRequest.suspend();
         var chan = gIoService.newChannel(uri.asciiSpec, null, null);
         // make request anonymous (no cookies, etc.) so the request for the
         // policy-uri can't be abused for CSRF
         chan.loadFlags |= Ci.nsIChannel.LOAD_ANONYMOUS;
+        chan.loadGroup = docRequest.loadGroup;
         chan.asyncOpen(new CSPPolicyURIListener(uri, docRequest, csp), null);
       }
       catch (e) {
         // resume the document request and apply most restrictive policy
         docRequest.resume();
         cspError(aCSPR, CSPLocalizer.getFormatStr("errorFetchingPolicy",
                                                   [e.toString()]));
         return CSPRep.fromString("default-src 'none'");
--- a/content/base/src/FragmentOrElement.cpp
+++ b/content/base/src/FragmentOrElement.cpp
@@ -477,20 +477,19 @@ FragmentOrElement::GetChildrenList()
 
 
 NS_IMPL_ISUPPORTS1(nsNodeWeakReference,
                    nsIWeakReference)
 
 nsNodeWeakReference::~nsNodeWeakReference()
 {
   if (mNode) {
-    NS_ASSERTION(mNode->GetSlots() &&
-                 mNode->GetSlots()->mWeakReference == this,
+    NS_ASSERTION(mNode->Slots()->mWeakReference == this,
                  "Weak reference has wrong value");
-    mNode->GetSlots()->mWeakReference = nullptr;
+    mNode->Slots()->mWeakReference = nullptr;
   }
 }
 
 NS_IMETHODIMP
 nsNodeWeakReference::QueryReferent(const nsIID& aIID, void** aInstancePtr)
 {
   return mNode ? mNode->QueryInterface(aIID, aInstancePtr) :
                  NS_ERROR_NULL_POINTER;
@@ -504,19 +503,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
 NS_INTERFACE_MAP_END_AGGREGATED(mNode)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsNodeSupportsWeakRefTearoff)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsNodeSupportsWeakRefTearoff)
 
 NS_IMETHODIMP
 nsNodeSupportsWeakRefTearoff::GetWeakReference(nsIWeakReference** aInstancePtr)
 {
-  nsINode::nsSlots* slots = mNode->GetSlots();
-  NS_ENSURE_TRUE(slots, NS_ERROR_OUT_OF_MEMORY);
-
+  nsINode::nsSlots* slots = mNode->Slots();
   if (!slots->mWeakReference) {
     slots->mWeakReference = new nsNodeWeakReference(mNode);
     NS_ENSURE_TRUE(slots->mWeakReference, NS_ERROR_OUT_OF_MEMORY);
   }
 
   NS_ADDREF(*aInstancePtr = slots->mWeakReference);
 
   return NS_OK;
--- a/content/base/src/nsAttrName.h
+++ b/content/base/src/nsAttrName.h
@@ -11,76 +11,74 @@
 
 #ifndef nsAttrName_h___
 #define nsAttrName_h___
 
 #include "nsINodeInfo.h"
 #include "nsIAtom.h"
 #include "nsDOMString.h"
 
-typedef uintptr_t PtrBits;
-
 #define NS_ATTRNAME_NODEINFO_BIT 1
 class nsAttrName
 {
 public:
   nsAttrName(const nsAttrName& aOther)
     : mBits(aOther.mBits)
   {
     AddRefInternalName();
   }
 
   explicit nsAttrName(nsIAtom* aAtom)
-    : mBits(reinterpret_cast<PtrBits>(aAtom))
+    : mBits(reinterpret_cast<uintptr_t>(aAtom))
   {
     NS_ASSERTION(aAtom, "null atom-name in nsAttrName");
     NS_ADDREF(aAtom);
   }
 
   explicit nsAttrName(nsINodeInfo* aNodeInfo)
   {
     NS_ASSERTION(aNodeInfo, "null nodeinfo-name in nsAttrName");
     if (aNodeInfo->NamespaceEquals(kNameSpaceID_None)) {
-      mBits = reinterpret_cast<PtrBits>(aNodeInfo->NameAtom());
+      mBits = reinterpret_cast<uintptr_t>(aNodeInfo->NameAtom());
       NS_ADDREF(aNodeInfo->NameAtom());
     }
     else {
-      mBits = reinterpret_cast<PtrBits>(aNodeInfo) |
+      mBits = reinterpret_cast<uintptr_t>(aNodeInfo) |
               NS_ATTRNAME_NODEINFO_BIT;
       NS_ADDREF(aNodeInfo);
     }
   }
 
   ~nsAttrName()
   {
     ReleaseInternalName();
   }
 
   void SetTo(nsINodeInfo* aNodeInfo)
   {
     NS_ASSERTION(aNodeInfo, "null nodeinfo-name in nsAttrName");
 
     ReleaseInternalName();
     if (aNodeInfo->NamespaceEquals(kNameSpaceID_None)) {
-      mBits = reinterpret_cast<PtrBits>(aNodeInfo->NameAtom());
+      mBits = reinterpret_cast<uintptr_t>(aNodeInfo->NameAtom());
       NS_ADDREF(aNodeInfo->NameAtom());
     }
     else {
-      mBits = reinterpret_cast<PtrBits>(aNodeInfo) |
+      mBits = reinterpret_cast<uintptr_t>(aNodeInfo) |
               NS_ATTRNAME_NODEINFO_BIT;
       NS_ADDREF(aNodeInfo);
     }
   }
 
   void SetTo(nsIAtom* aAtom)
   {
     NS_ASSERTION(aAtom, "null atom-name in nsAttrName");
 
     ReleaseInternalName();
-    mBits = reinterpret_cast<PtrBits>(aAtom);
+    mBits = reinterpret_cast<uintptr_t>(aAtom);
     NS_ADDREF(aAtom);
   }
 
   bool IsAtom() const
   {
     return !(mBits & NS_ATTRNAME_NODEINFO_BIT);
   }
 
@@ -99,17 +97,17 @@ public:
   bool Equals(const nsAttrName& aOther) const
   {
     return mBits == aOther.mBits;
   }
 
   // Faster comparison in the case we know the namespace is null
   bool Equals(nsIAtom* aAtom) const
   {
-    return reinterpret_cast<PtrBits>(aAtom) == mBits;
+    return reinterpret_cast<uintptr_t>(aAtom) == mBits;
   }
 
   bool Equals(nsIAtom* aLocalName, int32_t aNamespaceID) const
   {
     if (aNamespaceID == kNameSpaceID_None) {
       return Equals(aLocalName);
     }
     return !IsAtom() && NodeInfo()->Equals(aLocalName, aNamespaceID);
@@ -175,17 +173,17 @@ public:
     // mBits and uint32_t might have different size. This should silence
     // any warnings or compile-errors. This is what the implementation of
     // NS_PTR_TO_INT32 does to take care of the same problem.
     return mBits - 0;
   }
 
   bool IsSmaller(nsIAtom* aOther) const
   {
-    return mBits < reinterpret_cast<PtrBits>(aOther);
+    return mBits < reinterpret_cast<uintptr_t>(aOther);
   }
 
 private:
 
   void AddRefInternalName()
   {
     // Since both nsINodeInfo and nsIAtom inherit nsISupports as its first
     // interface we can safely assume that it's first in the vtable
@@ -200,12 +198,12 @@ private:
     // Since both nsINodeInfo and nsIAtom inherit nsISupports as its first
     // interface we can safely assume that it's first in the vtable
     nsISupports* name = reinterpret_cast<nsISupports *>
                                         (mBits & ~NS_ATTRNAME_NODEINFO_BIT);
 
     NS_RELEASE(name);
   }
 
-  PtrBits mBits;
+  uintptr_t mBits;
 };
 
 #endif
--- a/content/base/src/nsAttrValue.cpp
+++ b/content/base/src/nsAttrValue.cpp
@@ -559,17 +559,17 @@ void
 nsAttrValue::SetTo(const nsSVGViewBox& aValue, const nsAString* aSerialized)
 {
   SetSVGType(eSVGViewBox, &aValue, aSerialized);
 }
 
 void
 nsAttrValue::SwapValueWith(nsAttrValue& aOther)
 {
-  PtrBits tmp = aOther.mBits;
+  uintptr_t tmp = aOther.mBits;
   aOther.mBits = mBits;
   mBits = tmp;
 }
 
 void
 nsAttrValue::ToString(nsAString& aResult) const
 {
   MiscContainer* cont = nullptr;
@@ -1531,17 +1531,17 @@ nsAttrValue::SetColorValue(nscolor aColo
     return;
   }
 
   MiscContainer* cont = EnsureEmptyMiscContainer();
   cont->mValue.mColor = aColor;
   cont->mType = eColor;
 
   // Save the literal string we were passed for round-tripping.
-  cont->mStringBits = reinterpret_cast<PtrBits>(buf) | eStringBase;
+  cont->mStringBits = reinterpret_cast<uintptr_t>(buf) | eStringBase;
 }
 
 bool
 nsAttrValue::ParseColor(const nsAString& aString)
 {
   ResetIfSet();
 
   // FIXME (partially, at least): HTML5's algorithm says we shouldn't do
@@ -1708,22 +1708,22 @@ nsAttrValue::SetMiscAtomOrString(const n
     //   for enumerated values that are not limited enumerated.
     // Add other types as needed.
     NS_ASSERTION(len || Type() == eCSSStyleRule || Type() == eEnum,
                  "Empty string?");
     MiscContainer* cont = GetMiscContainer();
     if (len <= NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM) {
       nsIAtom* atom = NS_NewAtom(*aValue);
       if (atom) {
-        cont->mStringBits = reinterpret_cast<PtrBits>(atom) | eAtomBase;
+        cont->mStringBits = reinterpret_cast<uintptr_t>(atom) | eAtomBase;
       }
     } else {
       nsStringBuffer* buf = GetStringBuffer(*aValue);
       if (buf) {
-        cont->mStringBits = reinterpret_cast<PtrBits>(buf) | eStringBase;
+        cont->mStringBits = reinterpret_cast<uintptr_t>(buf) | eStringBase;
       }
     }
   }
 }
 
 void
 nsAttrValue::ResetMiscAtomOrString()
 {
--- a/content/base/src/nsAttrValue.h
+++ b/content/base/src/nsAttrValue.h
@@ -15,17 +15,16 @@
 #include "nsStringGlue.h"
 #include "nsStringBuffer.h"
 #include "nsColor.h"
 #include "nsCaseTreatment.h"
 #include "nsMargin.h"
 #include "nsCOMPtr.h"
 #include "SVGAttrValueWrapper.h"
 
-typedef uintptr_t PtrBits;
 class nsAString;
 class nsIAtom;
 class nsIDocument;
 template<class E, class A> class nsTArray;
 struct nsTArrayDefaultAllocator;
 class nsStyledElementNotElementCSSInlineStyle;
 struct MiscContainer;
 
@@ -34,30 +33,30 @@ namespace css {
 class StyleRule;
 struct URLValue;
 struct ImageValue;
 }
 }
 
 #define NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM 12
 
-#define NS_ATTRVALUE_BASETYPE_MASK (PtrBits(3))
+#define NS_ATTRVALUE_BASETYPE_MASK (uintptr_t(3))
 #define NS_ATTRVALUE_POINTERVALUE_MASK (~NS_ATTRVALUE_BASETYPE_MASK)
 
 #define NS_ATTRVALUE_INTEGERTYPE_BITS 4
-#define NS_ATTRVALUE_INTEGERTYPE_MASK (PtrBits((1 << NS_ATTRVALUE_INTEGERTYPE_BITS) - 1))
+#define NS_ATTRVALUE_INTEGERTYPE_MASK (uintptr_t((1 << NS_ATTRVALUE_INTEGERTYPE_BITS) - 1))
 #define NS_ATTRVALUE_INTEGERTYPE_MULTIPLIER (1 << NS_ATTRVALUE_INTEGERTYPE_BITS)
 #define NS_ATTRVALUE_INTEGERTYPE_MAXVALUE ((1 << (31 - NS_ATTRVALUE_INTEGERTYPE_BITS)) - 1)
 #define NS_ATTRVALUE_INTEGERTYPE_MINVALUE (-NS_ATTRVALUE_INTEGERTYPE_MAXVALUE - 1)
 
 #define NS_ATTRVALUE_ENUMTABLEINDEX_BITS (32 - 16 - NS_ATTRVALUE_INTEGERTYPE_BITS)
 #define NS_ATTRVALUE_ENUMTABLE_VALUE_NEEDS_TO_UPPER (1 << (NS_ATTRVALUE_ENUMTABLEINDEX_BITS - 1))
 #define NS_ATTRVALUE_ENUMTABLEINDEX_MAXVALUE (NS_ATTRVALUE_ENUMTABLE_VALUE_NEEDS_TO_UPPER - 1)
 #define NS_ATTRVALUE_ENUMTABLEINDEX_MASK \
-  (PtrBits((((1 << NS_ATTRVALUE_ENUMTABLEINDEX_BITS) - 1) &~ NS_ATTRVALUE_ENUMTABLE_VALUE_NEEDS_TO_UPPER)))
+  (uintptr_t((((1 << NS_ATTRVALUE_ENUMTABLEINDEX_BITS) - 1) &~ NS_ATTRVALUE_ENUMTABLE_VALUE_NEEDS_TO_UPPER)))
 
 /**
  * A class used to construct a nsString from a nsStringBuffer (we might
  * want to move this to nsString at some point).
  */
 class nsCheapString : public nsString {
 public:
   nsCheapString(nsStringBuffer* aBuf)
@@ -423,17 +422,17 @@ private:
                           bool* aIsPercent = nullptr) const;
   // Given an enum table and a particular entry in that table, return
   // the actual integer value we should store.
   int32_t EnumTableEntryToValue(const EnumTable* aEnumTable,
                                 const EnumTable* aTableEntry);  
 
   static nsTArray<const EnumTable*, nsTArrayDefaultAllocator>* sEnumTableArray;
 
-  PtrBits mBits;
+  uintptr_t mBits;
 };
 
 inline const nsAttrValue&
 nsAttrValue::operator=(const nsAttrValue& aOther)
 {
   SetTo(aOther);
   return *this;
 }
--- a/content/base/src/nsAttrValueInlines.h
+++ b/content/base/src/nsAttrValueInlines.h
@@ -1,25 +1,27 @@
 /* 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 nsAttrValueInlines_h__
 #define nsAttrValueInlines_h__
 
+#include "mozilla/StandardInteger.h"
+
 struct MiscContainer
 {
   typedef nsAttrValue::ValueType ValueType;
 
   ValueType mType;
   // mStringBits points to either nsIAtom* or nsStringBuffer* and is used when
   // mType isn't mCSSStyleRule.
   // Note eStringBase and eAtomBase is used also to handle the type of
   // mStringBits.
-  PtrBits mStringBits;
+  uintptr_t mStringBits;
   union {
     struct {
       union {
         int32_t mInteger;
         nscolor mColor;
         uint32_t mEnumValue;
         int32_t mPercent;
         mozilla::css::StyleRule* mCSSStyleRule;
@@ -178,17 +180,17 @@ nsAttrValue::IsSVGType(ValueType aType) 
   return aType >= eSVGTypesBegin && aType <= eSVGTypesEnd;
 }
 
 inline void
 nsAttrValue::SetPtrValueAndType(void* aValue, ValueBaseType aType)
 {
   NS_ASSERTION(!(NS_PTR_TO_INT32(aValue) & ~NS_ATTRVALUE_POINTERVALUE_MASK),
                "pointer not properly aligned, this will crash");
-  mBits = reinterpret_cast<PtrBits>(aValue) | aType;
+  mBits = reinterpret_cast<intptr_t>(aValue) | aType;
 }
 
 inline void
 nsAttrValue::ResetIfSet()
 {
   if (mBits) {
     Reset();
   }
--- a/content/base/src/nsContentSink.cpp
+++ b/content/base/src/nsContentSink.cpp
@@ -1270,17 +1270,17 @@ nsContentSink::IsTimeToNotify()
   }
 
   PRTime now = PR_Now();
   int64_t interval, diff;
 
   LL_I2L(interval, GetNotificationInterval());
   LL_SUB(diff, now, mLastNotificationTime);
 
-  if (LL_CMP(diff, >, interval)) {
+  if (diff > interval) {
     mBackoffCount--;
     return true;
   }
 
   return false;
 }
 
 nsresult
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -6923,19 +6923,17 @@ nsContentUtils::ReleaseWrapper(nsISuppor
                                nsWrapperCache* aCache)
 {
   if (aCache->PreservingWrapper()) {
     // PreserveWrapper puts new DOM bindings in the JS holders hash, but they
     // can also be in the DOM expando hash, so we need to try to remove them
     // from both here.
     JSObject* obj = aCache->GetWrapperPreserveColor();
     if (aCache->IsDOMBinding() && obj) {
-      JSCompartment *compartment = js::GetObjectCompartment(obj);
-      xpc::CompartmentPrivate *priv =
-        static_cast<xpc::CompartmentPrivate *>(JS_GetCompartmentPrivate(compartment));
+      xpc::CompartmentPrivate *priv = xpc::GetCompartmentPrivate(obj);
       priv->RemoveDOMExpandoObject(obj);
     }
     DropJSObjects(aScriptObjectHolder);
 
     aCache->SetPreservingWrapper(false);
   }
 }
 
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -1981,17 +1981,17 @@ nsDocument::Init()
     return NS_ERROR_ALREADY_INITIALIZED;
   }
 
   mIdentifierMap.Init();
   mStyledLinks.Init();
   mRadioGroups.Init();
 
   // Force initialization.
-  nsINode::nsSlots* slots = GetSlots();
+  nsINode::nsSlots* slots = Slots();
 
   // Prepend self as mutation-observer whether we need it or not (some
   // subclasses currently do, other don't). This is because the code in
   // nsNodeUtils always notifies the first observer first, expecting the
   // first observer to be the document.
   NS_ENSURE_TRUE(slots->mMutationObservers.PrependElementUnlessExists(static_cast<nsIMutationObserver*>(this)),
                  NS_ERROR_OUT_OF_MEMORY);
 
@@ -6876,25 +6876,25 @@ nsDocument::RetrieveRelevantHeaders(nsIC
       rv = aChannel->GetContentDispositionHeader(contentDisp);
       if (NS_SUCCEEDED(rv)) {
         SetHeaderData(nsGkAtoms::headerContentDisposition,
                       NS_ConvertASCIItoUTF16(contentDisp));
       }
     }
   }
 
-  if (LL_IS_ZERO(modDate)) {
+  if (modDate == 0) {
     // We got nothing from our attempt to ask nsIFileChannel and
     // nsIHttpChannel for the last modified time. Return the current
     // time.
     modDate = PR_Now();
   }
 
   mLastModified.Truncate();
-  if (LL_NE(modDate, LL_ZERO)) {
+  if (modDate != LL_ZERO) {
     PRExplodedTime prtime;
     PR_ExplodeTime(modDate, PR_LocalTimeParameters, &prtime);
     // "MM/DD/YYYY hh:mm:ss"
     char formatedTime[24];
     if (PR_snprintf(formatedTime, sizeof(formatedTime),
                     "%02ld/%02ld/%04hd %02ld:%02ld:%02ld",
                     prtime.tm_month + 1, prtime.tm_mday, prtime.tm_year,
                     prtime.tm_hour     ,  prtime.tm_min,  prtime.tm_sec)) {
@@ -9326,16 +9326,17 @@ nsDocument::RequestFullScreen(Element* a
                           NS_LITERAL_STRING("MozEnteredDomFullscreen"),
                           true,
                           true);
     e->PostDOMEvent();
   }
 
   // Remember this is the requesting full-screen document.
   sFullScreenDoc = do_GetWeakReference(static_cast<nsIDocument*>(this));
+  NS_ASSERTION(sFullScreenDoc, "nsDocument should support weak ref!");
 
 #ifdef DEBUG
   // Note assertions must run before SetWindowFullScreen() as that does
   // synchronous event dispatch which can run script which exits full-screen!
   NS_ASSERTION(GetFullScreenElement() == aElement,
                "Full-screen element should be the requested element!");
   NS_ASSERTION(IsFullScreenDoc(), "Should be full-screen doc");
   nsCOMPtr<nsIDOMElement> fse;
@@ -9672,16 +9673,20 @@ nsDocument::RequestPointerLock(Element* 
     DispatchPointerLockError(this);
     return;
   }
 
   aElement->SetPointerLock();
   nsEventStateManager::sPointerLockedElement = do_GetWeakReference(aElement);
   nsEventStateManager::sPointerLockedDoc =
     do_GetWeakReference(static_cast<nsIDocument*>(this));
+  NS_ASSERTION(nsEventStateManager::sPointerLockedElement &&
+               nsEventStateManager::sPointerLockedDoc,
+               "aElement and this should support weak references!");
+
   DispatchPointerLockChange(this);
 }
 
 bool
 nsDocument::ShouldLockPointer(Element* aElement)
 {
   // Check if pointer lock pref is enabled
   if (!Preferences::GetBool("full-screen-api.pointer-lock.enabled")) {
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -1482,32 +1482,32 @@ nsFrameLoader::MaybeCreateDocShell()
     doc->GetContainer();
   nsCOMPtr<nsIWebNavigation> parentAsWebNav = do_QueryInterface(container);
   NS_ENSURE_STATE(parentAsWebNav);
 
   // Create the docshell...
   mDocShell = do_CreateInstance("@mozilla.org/docshell;1");
   NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
 
-  if (OwnerIsBrowserFrame() &&
-      mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::mozapp)) {
-    nsCOMPtr<nsIAppsService> appsService =
-      do_GetService(APPS_SERVICE_CONTRACTID);
-    if (!appsService) {
-      NS_ERROR("Apps Service is not available!");
-      return NS_ERROR_FAILURE;
+  if (OwnerIsBrowserFrame()) {
+    nsAutoString manifest;
+    GetOwnerAppManifestURL(manifest);
+    if (!manifest.IsEmpty()) {
+      nsCOMPtr<nsIAppsService> appsService =
+        do_GetService(APPS_SERVICE_CONTRACTID);
+      if (!appsService) {
+        NS_ERROR("Apps Service is not available!");
+        return NS_ERROR_FAILURE;
+      }
+
+      uint32_t appId;
+      appsService->GetAppLocalIdByManifestURL(manifest, &appId);
+
+      mDocShell->SetAppId(appId);
     }
-
-    nsAutoString manifest;
-    mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::mozapp, manifest);
-
-    uint32_t appId;
-    appsService->GetAppLocalIdByManifestURL(manifest, &appId);
-
-    mDocShell->SetAppId(appId);
   }
 
   if (!mNetworkCreated) {
     nsCOMPtr<nsIDocShellHistory> history = do_QueryInterface(mDocShell);
     if (history) {
       history->SetCreatedDynamically(true);
     }
   }
@@ -1976,20 +1976,19 @@ nsFrameLoader::TryRemoteBrowser()
     return false;
   }
 
   bool isBrowserElement = false;
   nsCOMPtr<mozIApplication> app;
   if (OwnerIsBrowserFrame()) {
     isBrowserElement = true;
 
-    if (mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::mozapp)) {
-      nsAutoString manifest;
-      mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::mozapp, manifest);
-
+    nsAutoString manifest;
+    GetOwnerAppManifestURL(manifest);
+    if (!manifest.IsEmpty()) {
       nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
       if (!appsService) {
         NS_ERROR("Apps Service is not available!");
         return false;
       }
 
       nsCOMPtr<mozIDOMApplication> domApp;
       appsService->GetAppByManifestURL(manifest, getter_AddRefs(domApp));
--- a/content/base/src/nsGenericDOMDataNode.cpp
+++ b/content/base/src/nsGenericDOMDataNode.cpp
@@ -453,25 +453,22 @@ nsGenericDOMDataNode::BindToTree(nsIDocu
                   "own binding parent");
 
   if (!aBindingParent && aParent) {
     aBindingParent = aParent->GetBindingParent();
   }
 
   // First set the binding parent
   if (aBindingParent) {
-    nsDataSlots *slots = GetDataSlots();
-    NS_ENSURE_TRUE(slots, NS_ERROR_OUT_OF_MEMORY);
-
     NS_ASSERTION(IsRootOfNativeAnonymousSubtree() ||
                  !HasFlag(NODE_IS_IN_ANONYMOUS_SUBTREE) ||
                  (aParent && aParent->IsInNativeAnonymousSubtree()),
                  "Trying to re-bind content from native anonymous subtree to "
                  "non-native anonymous parent!");
-    slots->mBindingParent = aBindingParent; // Weak, so no addref happens.
+    DataSlots()->mBindingParent = aBindingParent; // Weak, so no addref happens.
     if (aParent->IsInNativeAnonymousSubtree()) {
       SetFlags(NODE_IS_IN_ANONYMOUS_SUBTREE);
     }
   }
 
   // Set parent
   if (aParent) {
     if (!GetParent()) {
--- a/content/base/src/nsGenericDOMDataNode.h
+++ b/content/base/src/nsGenericDOMDataNode.h
@@ -16,36 +16,43 @@
 #include "nsTextFragment.h"
 #include "nsError.h"
 #include "nsEventListenerManager.h"
 #include "nsGenericElement.h"
 #include "nsCycleCollectionParticipant.h"
 
 #include "nsISMILAttr.h"
 
-// This bit is set to indicate that if the text node changes to
-// non-whitespace, we may need to create a frame for it. This bit must
-// not be set on nodes that already have a frame.
-#define NS_CREATE_FRAME_IF_NON_WHITESPACE (1 << NODE_TYPE_SPECIFIC_BITS_OFFSET)
-
-// This bit is set to indicate that if the text node changes to
-// whitespace, we may need to reframe it (or its ancestors).
-#define NS_REFRAME_IF_WHITESPACE (1 << (NODE_TYPE_SPECIFIC_BITS_OFFSET + 1))
-
-// Make sure we have enough space for those bits
-PR_STATIC_ASSERT(NODE_TYPE_SPECIFIC_BITS_OFFSET + 1 < 32);
-
 class nsIDOMAttr;
 class nsIDOMEventListener;
 class nsIDOMNodeList;
 class nsIFrame;
 class nsIDOMText;
 class nsINodeInfo;
 class nsURI;
 
+#define DATA_NODE_FLAG_BIT(n_) NODE_FLAG_BIT(NODE_TYPE_SPECIFIC_BITS_OFFSET + (n_))
+
+// Data node specific flags
+enum {
+  // This bit is set to indicate that if the text node changes to
+  // non-whitespace, we may need to create a frame for it. This bit must
+  // not be set on nodes that already have a frame.
+  NS_CREATE_FRAME_IF_NON_WHITESPACE =     DATA_NODE_FLAG_BIT(0),
+
+  // This bit is set to indicate that if the text node changes to
+  // whitespace, we may need to reframe it (or its ancestors).
+  NS_REFRAME_IF_WHITESPACE =              DATA_NODE_FLAG_BIT(1)
+};
+
+// Make sure we have enough space for those bits
+PR_STATIC_ASSERT(NODE_TYPE_SPECIFIC_BITS_OFFSET + 1 < 32);
+
+#undef DATA_NODE_FLAG_BIT
+
 class nsGenericDOMDataNode : public nsIContent
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
   NS_DECL_SIZEOF_EXCLUDING_THIS
 
   nsGenericDOMDataNode(already_AddRefed<nsINodeInfo> aNodeInfo);
@@ -264,19 +271,19 @@ protected:
      * @see nsIContent::GetBindingParent
      */
     nsIContent* mBindingParent;  // [Weak]
   };
 
   // Override from nsINode
   virtual nsINode::nsSlots* CreateSlots();
 
-  nsDataSlots *GetDataSlots()
+  nsDataSlots* DataSlots()
   {
-    return static_cast<nsDataSlots*>(GetSlots());
+    return static_cast<nsDataSlots*>(Slots());
   }
 
   nsDataSlots *GetExistingDataSlots() const
   {
     return static_cast<nsDataSlots*>(GetExistingSlots());
   }
 
   nsresult SplitText(uint32_t aOffset, nsIDOMText** aReturn);
--- a/content/base/src/nsGenericElement.h
+++ b/content/base/src/nsGenericElement.h
@@ -52,18 +52,16 @@ class nsEventChainVisitor;
 class nsEventListenerManager;
 class nsIScrollableFrame;
 class nsAttrValueOrString;
 class nsContentList;
 class nsDOMTokenList;
 class ContentUnbinder;
 struct nsRect;
 
-typedef uintptr_t PtrBits;
-
 /**
  * A generic base class for DOM elements, implementing many nsIContent,
  * nsIDOMNode and nsIDOMElement methods.
  */
 class nsGenericElement : public mozilla::dom::Element
 {
 public:
   nsGenericElement(already_AddRefed<nsINodeInfo> aNodeInfo);
--- a/content/base/src/nsINode.cpp
+++ b/content/base/src/nsINode.cpp
@@ -306,21 +306,17 @@ nsINode::GetSelectionRootContent(nsIPres
   NS_ENSURE_TRUE(content, nullptr);
   return nsContentUtils::IsInSameAnonymousTree(this, content) ?
            content : GetRootForContentSubtree(static_cast<nsIContent*>(this));
 }
 
 nsINodeList*
 nsINode::GetChildNodesList()
 {
-  nsSlots *slots = GetSlots();
-  if (!slots) {
-    return nullptr;
-  }
-
+  nsSlots* slots = Slots();
   if (!slots->mChildNodes) {
     slots->mChildNodes = new nsChildContentList(this);
     if (slots->mChildNodes) {
       NS_ADDREF(slots->mChildNodes);
     }
   }
 
   return slots->mChildNodes;
@@ -1118,21 +1114,21 @@ nsINode::Trace(nsINode *tmp, TraceCallba
 {
   nsContentUtils::TraceWrapper(tmp, cb, closure);
 }
 
 
 bool
 nsINode::UnoptimizableCCNode() const
 {
-  const PtrBits problematicFlags = (NODE_IS_ANONYMOUS |
-                                    NODE_IS_IN_ANONYMOUS_SUBTREE |
-                                    NODE_IS_NATIVE_ANONYMOUS_ROOT |
-                                    NODE_MAY_BE_IN_BINDING_MNGR |
-                                    NODE_IS_INSERTION_PARENT);
+  const uintptr_t problematicFlags = (NODE_IS_ANONYMOUS |
+                                      NODE_IS_IN_ANONYMOUS_SUBTREE |
+                                      NODE_IS_NATIVE_ANONYMOUS_ROOT |
+                                      NODE_MAY_BE_IN_BINDING_MNGR |
+                                      NODE_IS_INSERTION_PARENT);
   return HasFlag(problematicFlags) ||
          NodeType() == nsIDOMNode::ATTRIBUTE_NODE ||
          // For strange cases like xbl:content/xbl:children
          (IsElement() &&
           AsElement()->IsInNamespace(kNameSpaceID_XBL));
 }
 
 /* static */
--- a/content/base/src/nsImageLoadingContent.cpp
+++ b/content/base/src/nsImageLoadingContent.cpp
@@ -1178,19 +1178,19 @@ nsImageLoadingContent::UnbindFromTree(bo
     return;
 
   // Push a null JSContext on the stack so that callbacks triggered by the
   // below code won't think they're being called from JS.
   nsCxPusher pusher;
   pusher.PushNull();
 
   if (mCurrentRequestFlags & REQUEST_SHOULD_BE_TRACKED)
-    doc->RemoveImage(mCurrentRequest, nsIDocument::REQUEST_DISCARD);
+    doc->RemoveImage(mCurrentRequest);
   if (mPendingRequestFlags & REQUEST_SHOULD_BE_TRACKED)
-    doc->RemoveImage(mPendingRequest, nsIDocument::REQUEST_DISCARD);
+    doc->RemoveImage(mPendingRequest);
 }
 
 nsresult
 nsImageLoadingContent::TrackImage(imgIRequest* aImage)
 {
   if (!aImage)
     return NS_OK;
 
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -6,17 +6,17 @@
 
 /*
  * A base class implementing nsIObjectLoadingContent for use by
  * various content nodes that want to provide plugin/document/image
  * loading functionality (eg <embed>, <object>, <applet>, etc).
  */
 
 // Interface headers
-#include "imgILoader.h"
+#include "imgLoader.h"
 #include "nsEventDispatcher.h"
 #include "nsIContent.h"
 #include "nsIDocShell.h"
 #include "nsIDocument.h"
 #include "nsIDOMDataContainerEvent.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIExternalProtocolHandler.h"
@@ -472,24 +472,17 @@ URIEquals(nsIURI *a, nsIURI *b)
 {
   bool equal;
   return (!a && !b) || (a && b && NS_SUCCEEDED(a->Equals(b, &equal)) && equal);
 }
 
 static bool
 IsSupportedImage(const nsCString& aMimeType)
 {
-  nsCOMPtr<imgILoader> loader = nsContentUtils::GetImgLoaderForChannel(nullptr);
-  if (!loader) {
-    return false;
-  }
-
-  bool supported;
-  nsresult rv = loader->SupportImageWithMimeType(aMimeType.get(), &supported);
-  return NS_SUCCEEDED(rv) && supported;
+  return imgLoader::SupportImageWithMimeType(aMimeType.get());
 }
 
 static void
 GetExtensionFromURI(nsIURI* uri, nsCString& ext)
 {
   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
   if (url) {
     url->GetFileExtension(ext);
@@ -2517,22 +2510,32 @@ nsObjectLoadingContent::ShouldPlay(Fallb
     already_AddRefed<nsPluginHost>(nsPluginHost::GetInst());
 
   bool isCTP = pluginHost->IsPluginClickToPlayForType(mContentType.get());
 
   if (!isCTP || mActivated) {
     return true;
   }
 
+  // set the fallback reason
   aReason = eFallbackClickToPlay;
+  // (if it's click-to-play, it might be because of the blocklist)
+  uint32_t state;
+  nsresult rv = pluginHost->GetBlocklistStateForType(mContentType.get(), &state);
+  NS_ENSURE_SUCCESS(rv, false);
+  if (state == nsIBlocklistService::STATE_VULNERABLE_UPDATE_AVAILABLE) {
+    aReason = eFallbackVulnerableUpdatable;
+  }
+  else if (state == nsIBlocklistService::STATE_VULNERABLE_NO_UPDATE) {
+    aReason = eFallbackVulnerableNoUpdate;
+  }
 
   // If plugin type is click-to-play and we have not been explicitly clicked.
   // check if permissions lets this page bypass - (e.g. user selected 'Always
   // play plugins on this page')
-  nsresult rv = NS_ERROR_UNEXPECTED;
 
   nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIObjectLoadingContent*>(this));
   MOZ_ASSERT(thisContent);
   nsIDocument* ownerDoc = thisContent->OwnerDoc();
 
   nsCOMPtr<nsIDOMWindow> window = ownerDoc->GetWindow();
   if (!window) {
     return false;
@@ -2558,25 +2561,11 @@ nsObjectLoadingContent::ShouldPlay(Fallb
     uint32_t permission;
     rv = permissionManager->TestPermissionFromPrincipal(topDoc->NodePrincipal(),
                                                         "plugins",
                                                         &permission);
     NS_ENSURE_SUCCESS(rv, false);
     allowPerm = permission == nsIPermissionManager::ALLOW_ACTION;
   }
 
-  uint32_t state;
-  rv = pluginHost->GetBlocklistStateForType(mContentType.get(), &state);
-  NS_ENSURE_SUCCESS(rv, false);
-
-  // Always c2p vulnerable plugins, regardless of permissions
-  if (state == nsIBlocklistService::STATE_VULNERABLE_UPDATE_AVAILABLE) {
-    aReason = eFallbackVulnerableUpdatable;
-    return false;
-  }
-  if (state == nsIBlocklistService::STATE_VULNERABLE_NO_UPDATE) {
-    aReason = eFallbackVulnerableNoUpdate;
-    return false;
-  }
-
   return allowPerm;
 }
 
--- a/content/base/src/nsPropertyTable.h
+++ b/content/base/src/nsPropertyTable.h
@@ -22,17 +22,16 @@
 
 #ifndef nsPropertyTable_h_
 #define nsPropertyTable_h_
 
 #include "nscore.h"
 #include "prtypes.h"
 
 class nsIAtom;
-typedef uintptr_t PtrBits;
 
 typedef void
 (*NSPropertyFunc)(void           *aObject,
                   nsIAtom        *aPropertyName,
                   void           *aPropertyValue,
                   void           *aData);
 
 /**
--- a/content/base/src/nsTextFragment.cpp
+++ b/content/base/src/nsTextFragment.cpp
@@ -12,16 +12,17 @@
 #include "nsTextFragment.h"
 #include "nsCRT.h"
 #include "nsReadableUtils.h"
 #include "nsMemory.h"
 #include "nsBidiUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsUTF8Utils.h"
 #include "mozilla/SSE.h"
+#include "nsTextFragmentImpl.h"
 
 #define TEXTFRAG_WHITE_AFTER_NEWLINE 50
 #define TEXTFRAG_MAX_NEWLINES 7
 
 // Static buffer used for common fragments
 static char* sSpaceSharedString[TEXTFRAG_MAX_NEWLINES + 1];
 static char* sTabSharedString[TEXTFRAG_MAX_NEWLINES + 1];
 static char sSingleCharSharedString[256];
@@ -112,28 +113,20 @@ nsTextFragment::operator=(const nsTextFr
   }
 
   return *this;
 }
 
 static inline int32_t
 FirstNon8BitUnvectorized(const PRUnichar *str, const PRUnichar *end)
 {
-#if PR_BYTES_PER_WORD == 4
-  const size_t mask = 0xff00ff00;
-  const uint32_t alignMask = 0x3;
-  const uint32_t numUnicharsPerWord = 2;
-#elif PR_BYTES_PER_WORD == 8
-  const size_t mask = 0xff00ff00ff00ff00;
-  const uint32_t alignMask = 0x7;
-  const uint32_t numUnicharsPerWord = 4;
-#else
-#error Unknown platform!
-#endif
-
+  typedef Non8BitParameters<sizeof(size_t)> p;
+  const size_t mask = p::mask();
+  const uint32_t alignMask = p::alignMask();
+  const uint32_t numUnicharsPerWord = p::numUnicharsPerWord();
   const int32_t len = end - str;
   int32_t i = 0;
 
   // Align ourselves to a word boundary.
   int32_t alignLen =
     NS_MIN(len, int32_t(((-NS_PTR_TO_INT32(str)) & alignMask) / sizeof(PRUnichar)));
   for (; i < alignLen; i++) {
     if (str[i] > 255)
new file mode 100644
--- /dev/null
+++ b/content/base/src/nsTextFragmentImpl.h
@@ -0,0 +1,24 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 nsTextFragmentImpl_h__
+#define nsTextFragmentImpl_h__
+
+#include "mozilla/StandardInteger.h"
+
+template<size_t size> struct Non8BitParameters;
+template<> struct Non8BitParameters<4> {
+  static inline size_t mask() { return 0xff00ff00; }
+  static inline uint32_t alignMask() { return 0x3; }
+  static inline uint32_t numUnicharsPerWord() { return 2; }
+};
+
+template<> struct Non8BitParameters<8> {
+  static inline size_t mask() { return 0xff00ff00ff00ff00; }
+  static inline uint32_t alignMask() { return 0x7; }
+  static inline uint32_t numUnicharsPerWord() { return 4; }
+};
+
+#endif
--- a/content/base/src/nsTextFragmentSSE2.cpp
+++ b/content/base/src/nsTextFragmentSSE2.cpp
@@ -3,42 +3,35 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // This file should only be compiled if you're on x86 or x86_64.  Additionally,
 // you'll need to compile this file with -msse2 if you're using gcc.
 
 #include <emmintrin.h>
 #include "nscore.h"
 #include "nsAlgorithm.h"
+#include "nsTextFragmentImpl.h"
 
 namespace mozilla {
 namespace SSE2 {
 
 static inline bool
 is_zero (__m128i x)
 {
   return
     _mm_movemask_epi8(_mm_cmpeq_epi8(x, _mm_setzero_si128())) == 0xffff;
 }
 
 int32_t
 FirstNon8Bit(const PRUnichar *str, const PRUnichar *end)
 {
   const uint32_t numUnicharsPerVector = 8;
-
-#if PR_BYTES_PER_WORD == 4
-  const size_t mask = 0xff00ff00;
-  const uint32_t numUnicharsPerWord = 2;
-#elif PR_BYTES_PER_WORD == 8
-  const size_t mask = 0xff00ff00ff00ff00;
-  const uint32_t numUnicharsPerWord = 4;
-#else
-#error Unknown platform!
-#endif
-
+  typedef Non8BitParameters<sizeof(size_t)> p;
+  const size_t mask = p::mask();
+  const uint32_t numUnicharsPerWord = p::numUnicharsPerWord();
   const int32_t len = end - str;
   int32_t i = 0;
 
   // Align ourselves to a 16-byte boundary, as required by _mm_load_si128
   // (i.e. MOVDQA).
   int32_t alignLen =
     NS_MIN(len, int32_t(((-NS_PTR_TO_INT32(str)) & 0xf) / sizeof(PRUnichar)));
   for (; i < alignLen; i++) {
--- a/content/base/src/nsXMLHttpRequest.h
+++ b/content/base/src/nsXMLHttpRequest.h
@@ -410,21 +410,18 @@ public:
                          ErrorResult& aRv)
   {
     nsCString result;
     GetResponseHeader(NS_ConvertUTF16toUTF8(aHeader), result, aRv);
     if (result.IsVoid()) {
       aResult.SetIsVoid(true);
     }
     else {
-      // We use UTF8ToNewUnicode here because it truncates after invalid UTF-8
-      // characters, CopyUTF8toUTF16 just doesn't copy in that case.
-      uint32_t length;
-      PRUnichar* chars = UTF8ToNewUnicode(result, &length);
-      aResult.Adopt(chars, length);
+      // The result value should be inflated:
+      CopyASCIItoUTF16(result, aResult);
     }
   }
   void GetAllResponseHeaders(nsString& aResponseHeaders);
   void OverrideMimeType(const nsAString& aMimeType)
   {
     // XXX Should we do some validation here?
     mOverrideMimeType = aMimeType;
   }
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -183,16 +183,18 @@ MOCHITEST_FILES_A = \
 		file_XHR_pass2.txt \
 		file_XHR_pass3.txt \
 		file_XHR_pass3.txt^headers^ \
 		file_XHR_fail1.txt \
 		file_XHR_fail1.txt^headers^ \
 		file_XHR_binary1.bin \
 		file_XHR_binary1.bin^headers^ \
 		file_XHR_binary2.bin \
+		file_XHR_header.sjs \
+		test_XHR_header.html \
 		test_bug428847.html \
 		file_bug428847-1.xhtml \
 		file_bug428847-2.xhtml \
 		test_bug431701.html \
 		test_bug431833.html \
 		test_bug435425.html \
 		bug435425.sjs \
 		bug435425_redirect.sjs \
@@ -569,17 +571,17 @@ MOCHITEST_FILES_B = \
 		file_mixed_content_main.html \
 		file_mixed_content_server.sjs \
 		test_bug789856.html \
 		$(NULL)
 
 # OOP tests don't work on Windows (bug 763081) or native-fennec
 # (see Bug 774939)
 ifneq ($(OS_ARCH),WINNT)
-ifndef MOZ_JAVA_COMPOSITOR
+ifndef MOZ_ANDROID_OMTC
 MOCHITEST_FILES_B += \
 		test_messagemanager_assertpermission.html \
 		test_child_process_shutdown_message.html \
 		$(NULL)
 endif
 endif
 
 MOCHITEST_CHROME_FILES =	\
new file mode 100644
--- /dev/null
+++ b/content/base/test/file_XHR_header.sjs
@@ -0,0 +1,6 @@
+// SJS file for getAllResponseRequests vs getResponseRequest
+function handleRequest(request, response)
+{
+  response.setHeader("X-Custom-Header-Bytes", "…", false);
+  response.write("42");
+}
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_XHR_header.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for XMLHttpRequest.GetResponseHeader(foo) byte-inflates the output</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+  <meta charset="utf-8">
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="application/javascript;version=1.7">
+"use strict";
+SimpleTest.waitForExplicitFinish();
+
+let xhr = new XMLHttpRequest();
+xhr.open('GET', 'file_XHR_header.sjs', true);
+xhr.onreadystatechange = function() {
+  if (xhr.readyState == 4) {
+    ok(xhr.getResponseHeader('X-Custom-Header-Bytes') == "\xE2\x80\xA6", 'getResponseHeader byte-inflates the output');
+    SimpleTest.finish();
+  }
+}
+xhr.send(null);
+</script>
+</pre>
+</body>
+</html>
--- a/content/base/test/test_XHR_timeout.js
+++ b/content/base/test/test_XHR_timeout.js
@@ -7,33 +7,40 @@
 
 var inWorker = false;
 try {
   inWorker = !(self instanceof Window);
 } catch (e) {
   inWorker = true;
 }
 
+function message(data) {
+  if (inWorker)
+    self.postMessage(data);
+  else
+    self.postMessage(data, "*");
+}
+
 function is(got, expected, msg) {
   var obj = {};
   obj.type = "is";
   obj.got = got;
   obj.expected = expected;
   obj.msg = msg;
 
-  self.postMessage(obj, "*");
+  message(obj);
 }
 
 function ok(bool, msg) {
   var obj = {};
   obj.type = "ok";
   obj.bool = bool;
   obj.msg = msg;
 
-  self.postMessage(obj, "*");
+  message(obj);
 }
 
 /**
  * Generate and track results from a XMLHttpRequest with regards to timeouts.
  *
  * @param {String} id         The test description.
  * @param {Number} timeLimit  The initial setting for the request timeout.
  * @param {Number} resetAfter (Optional) The time after sending the request, to
@@ -318,17 +325,17 @@ var TestCounter = {
 
   next: function() {
     var test = TestRequests.shift();
 
     if (test) {
       test.startXHR();
     }
     else {
-      self.postMessage("done", "*");
+      message("done");
     }
   }
 };
 
 self.addEventListener("message", function (event) {
   if (event.data == "start") {
     TestCounter.next();
   }
--- a/content/base/test/test_child_process_shutdown_message.html
+++ b/content/base/test/test_child_process_shutdown_message.html
@@ -106,16 +106,17 @@ function expectFrameProcessShutdown(ifra
     countMessage();
   });
 }
 
 function setUp() {
   SpecialPowers.setBoolPref("dom.mozBrowserFramesEnabled", true);
   SpecialPowers.setBoolPref("dom.ipc.browser_frames.oop_by_default", true);
   SpecialPowers.addPermission("browser", true, window.document);
+  SpecialPowers.addPermission("embed-apps", true, window.document);
   runNextTest();
 }
 
 function makeKillTest(isApp) function testKill() {
   loadBrowser(isApp, function (iframe) {
     // We want to make sure we get notified on both the frame and
     // process message managers.
     let frameMM = SpecialPowers.getBrowserFrameMessageManager(iframe);
--- a/content/base/test/test_messagemanager_assertpermission.html
+++ b/content/base/test/test_messagemanager_assertpermission.html
@@ -27,16 +27,17 @@ let cpmm = Cc["@mozilla.org/childprocess
              .getService(Ci.nsISyncMessageSender);
 let gAppsService = Cc["@mozilla.org/AppsService;1"]
                      .getService(Ci.nsIAppsService);
 
 function setUp() {
   SpecialPowers.setBoolPref("dom.mozBrowserFramesEnabled", true);
   SpecialPowers.setBoolPref("dom.ipc.browser_frames.oop_by_default", true);
   SpecialPowers.addPermission("browser", true, window.document);
+  SpecialPowers.addPermission("embed-apps", true, window.document);
 
   let appId = gAppsService.getAppLocalIdByManifestURL(APP_MANIFEST);
   SpecialPowers.addPermission("foobar", true, { url: APP_URL,
                                                 appId: appId,
                                                 isInBrowserElement: false });
   runNextTest();
 }
 
--- a/content/canvas/src/Makefile.in
+++ b/content/canvas/src/Makefile.in
@@ -16,16 +16,17 @@ MODULE		= content
 LIBRARY_NAME	= gkconcvs_s
 LIBXUL_LIBRARY  = 1
 
 EXPORTS = \
 	CustomQS_Canvas.h \
 	CustomQS_Canvas2D.h \
 	WebGLContext.h \
 	WebGLElementArrayCache.h \
+	WebGLExtensions.h \
 	$(NULL)
 
 EXPORTS_NAMESPACES = mozilla/dom
 
 EXPORTS_mozilla/dom = \
   ImageData.h \
   $(NULL)
 
@@ -42,25 +43,27 @@ CPPSRCS	= \
 ifdef MOZ_WEBGL
 
 CPPSRCS += \
 	WebGLContext.cpp \
 	WebGLContextGL.cpp \
 	WebGLContextUtils.cpp \
 	WebGLContextReporter.cpp \
 	WebGLContextValidate.cpp \
+	WebGLTexelConversions.cpp \
+	WebGLElementArrayCache.cpp \
+	WebGLExtensionBase.cpp \
+	WebGLExtensionCompressedTextureATC.cpp \
+	WebGLExtensionCompressedTexturePVRTC.cpp \
+	WebGLExtensionCompressedTextureS3TC.cpp \
+	WebGLExtensionDepthTexture.cpp \
+	WebGLExtensionLoseContext.cpp \
 	WebGLExtensionStandardDerivatives.cpp \
 	WebGLExtensionTextureFilterAnisotropic.cpp \
-	WebGLExtensionLoseContext.cpp \
-	WebGLTexelConversions.cpp \
-	WebGLExtensionCompressedTextureS3TC.cpp \
-	WebGLExtensionCompressedTextureATC.cpp \
-	WebGLExtensionCompressedTexturePVRTC.cpp \
-	WebGLExtensionDepthTexture.cpp \
-	WebGLElementArrayCache.cpp \
+	WebGLExtensionTextureFloat.cpp \
 	$(NULL)
 
 DEFINES += -DUSE_ANGLE
 USE_ANGLE=1
 
 else
 
 CPPSRCS += WebGLContextNotSupported.cpp
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -36,21 +36,23 @@
 
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/Telemetry.h"
 
 #include "nsIObserverService.h"
 #include "mozilla/Services.h"
 #include "mozilla/dom/WebGLRenderingContextBinding.h"
+#include "mozilla/dom/BindingUtils.h"
 
 #include "Layers.h"
 
 using namespace mozilla;
 using namespace mozilla::gl;
+using namespace mozilla::dom;
 using namespace mozilla::layers;
 
 NS_IMPL_ISUPPORTS1(WebGLMemoryPressureObserver, nsIObserver)
 
 NS_IMETHODIMP
 WebGLMemoryPressureObserver::Observe(nsISupports* aSubject,
                                      const char* aTopic,
                                      const PRUnichar* aSomeData)
@@ -84,17 +86,16 @@ WebGLContextOptions::WebGLContextOptions
     if (Preferences::GetBool("webgl.default-no-alpha", false))
         alpha = false;
 }
 
 WebGLContext::WebGLContext()
     : gl(nullptr)
 {
     SetIsDOMBinding();
-    mExtensions.SetLength(WebGLExtensionID_number_of_extensions);
 
     mGeneration = 0;
     mInvalidated = false;
     mResetLayer = true;
     mOptionsFrozen = false;
 
     mActiveTexture = 0;
     mWebGLError = LOCAL_GL_NO_ERROR;
@@ -909,16 +910,21 @@ WebGLContext::GetContextAttributes(Error
     {
         rv.Throw(NS_ERROR_FAILURE);
         return NULL;
     }
 
     return obj;
 }
 
+bool
+WebGLContext::IsExtensionEnabled(WebGLExtensionID ext) const {
+    return mExtensions.SafeElementAt(ext);
+}
+
 /* [noscript] DOMString mozGetUnderlyingParamString(in WebGLenum pname); */
 NS_IMETHODIMP
 WebGLContext::MozGetUnderlyingParamString(uint32_t pname, nsAString& retval)
 {
     if (!IsContextStable())
         return NS_OK;
 
     retval.SetIsVoid(true);
@@ -938,171 +944,176 @@ WebGLContext::MozGetUnderlyingParamStrin
 
     default:
         return NS_ERROR_INVALID_ARG;
     }
 
     return NS_OK;
 }
 
-bool WebGLContext::IsExtensionSupported(WebGLExtensionID ext)
+bool WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const
 {
-    bool isSupported = false;
+    if (mDisableExtensions) {
+        return false;
+    }
 
     switch (ext) {
         case OES_standard_derivatives:
         case WEBGL_lose_context:
             // We always support these extensions.
-            isSupported = true;
-            break;
+            return true;
         case OES_texture_float:
-            isSupported = gl->IsExtensionSupported(gl->IsGLES2() ? GLContext::OES_texture_float 
-                                                                 : GLContext::ARB_texture_float);
-            break;
+            return gl->IsExtensionSupported(gl->IsGLES2() ? GLContext::OES_texture_float
+                                                          : GLContext::ARB_texture_float);
         case EXT_texture_filter_anisotropic:
-            isSupported = gl->IsExtensionSupported(GLContext::EXT_texture_filter_anisotropic);
-            break;
+            return gl->IsExtensionSupported(GLContext::EXT_texture_filter_anisotropic);
         case WEBGL_compressed_texture_s3tc:
             if (gl->IsExtensionSupported(GLContext::EXT_texture_compression_s3tc)) {
-                isSupported = true;
-            } else if (gl->IsExtensionSupported(GLContext::EXT_texture_compression_dxt1) &&
+                return true;
+            }
+            else if (gl->IsExtensionSupported(GLContext::EXT_texture_compression_dxt1) &&
                        gl->IsExtensionSupported(GLContext::ANGLE_texture_compression_dxt3) &&
                        gl->IsExtensionSupported(GLContext::ANGLE_texture_compression_dxt5))
             {
-                isSupported = true;
-            }
-            break;
-        case WEBGL_compressed_texture_atc:
-            if (gl->IsExtensionSupported(GLContext::AMD_compressed_ATC_texture)) {
-                isSupported = true;
+                return true;
             }
-            break;
+            else
+            {
+                return false;
+            }
+        case WEBGL_compressed_texture_atc:
+            return gl->IsExtensionSupported(GLContext::AMD_compressed_ATC_texture);
         case WEBGL_compressed_texture_pvrtc:
-            if (gl->IsExtensionSupported(GLContext::IMG_texture_compression_pvrtc)) {
-                isSupported = true;
-            }
-            break;
+            return gl->IsExtensionSupported(GLContext::IMG_texture_compression_pvrtc);
         case WEBGL_depth_texture:
             if (gl->IsGLES2() && 
                 gl->IsExtensionSupported(GLContext::OES_packed_depth_stencil) &&
                 gl->IsExtensionSupported(GLContext::OES_depth_texture)) 
             {
-                isSupported = true;
-            } else if (!gl->IsGLES2() &&
-                       gl->IsExtensionSupported(GLContext::EXT_packed_depth_stencil)) 
+                return true;
+            }
+            else if (!gl->IsGLES2() &&
+                     gl->IsExtensionSupported(GLContext::EXT_packed_depth_stencil))
             {
-                isSupported = true;
+                return true;
             }
-            break;
+            else
+            {
+                return false;
+            }
         default:
             MOZ_ASSERT(false, "should not get there.");
     }
 
-    return isSupported;
+    MOZ_ASSERT(false, "should not get there.");
+    return false;
 }
 
-nsIWebGLExtension*
-WebGLContext::GetExtension(const nsAString& aName)
+static bool
+CompareWebGLExtensionName(const nsACString& name, const char *other)
+{
+    return name.Equals(other, nsCaseInsensitiveCStringComparator());
+}
+
+JSObject*
+WebGLContext::GetExtension(JSContext *cx, const nsAString& aName)
 {
     if (!IsContextStable())
         return nullptr;
 
-    if (mDisableExtensions) {
-        return nullptr;
-    }
+    NS_LossyConvertUTF16toASCII name(aName);
 
     WebGLExtensionID ext = WebGLExtensionID_unknown_extension;
 
-    if (aName.Equals(NS_LITERAL_STRING("OES_texture_float"),
-        nsCaseInsensitiveStringComparator()))
+    // step 1: figure what extension is wanted
+    if (CompareWebGLExtensionName(name, "OES_texture_float"))
     {
-        if (IsExtensionSupported(OES_texture_float))
-            ext = OES_texture_float;
-    }
-    else if (aName.Equals(NS_LITERAL_STRING("OES_standard_derivatives"),
-             nsCaseInsensitiveStringComparator()))
-    {
-        if (IsExtensionSupported(OES_standard_derivatives))
-            ext = OES_standard_derivatives;
+        ext = OES_texture_float;
     }
-    else if (aName.Equals(NS_LITERAL_STRING("EXT_texture_filter_anisotropic"),
-             nsCaseInsensitiveStringComparator()))
+    else if (CompareWebGLExtensionName(name, "OES_standard_derivatives"))
     {
-        if (IsExtensionSupported(EXT_texture_filter_anisotropic))
-            ext = EXT_texture_filter_anisotropic;
+        ext = OES_standard_derivatives;
     }
-    else if (aName.Equals(NS_LITERAL_STRING("MOZ_WEBGL_lose_context"),
-             nsCaseInsensitiveStringComparator()))
+    else if (CompareWebGLExtensionName(name, "EXT_texture_filter_anisotropic"))
     {
-        if (IsExtensionSupported(WEBGL_lose_context))
-            ext = WEBGL_lose_context;
+        ext = EXT_texture_filter_anisotropic;
     }
-    else if (aName.Equals(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_s3tc"),
-             nsCaseInsensitiveStringComparator()))
+    else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_lose_context"))
     {
-        if (IsExtensionSupported(WEBGL_compressed_texture_s3tc))
-            ext = WEBGL_compressed_texture_s3tc;
+        ext = WEBGL_lose_context;
     }
-    else if (aName.Equals(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_atc"),
-             nsCaseInsensitiveStringComparator()))
+    else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_compressed_texture_s3tc"))
     {
-        if (IsExtensionSupported(WEBGL_compressed_texture_atc))
-            ext = WEBGL_compressed_texture_atc;
+        ext = WEBGL_compressed_texture_s3tc;
     }
-    else if (aName.Equals(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_pvrtc"),
-             nsCaseInsensitiveStringComparator()))
+    else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_compressed_texture_atc"))
     {
-        if (IsExtensionSupported(WEBGL_compressed_texture_pvrtc))
-            ext = WEBGL_compressed_texture_pvrtc;
+        ext = WEBGL_compressed_texture_atc;
     }
-    else if (aName.Equals(NS_LITERAL_STRING("MOZ_WEBGL_depth_texture"),
-             nsCaseInsensitiveStringComparator()))
+    else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_compressed_texture_pvrtc"))
     {
-        if (IsExtensionSupported(WEBGL_depth_texture))
-            ext = WEBGL_depth_texture;
+        ext = WEBGL_compressed_texture_pvrtc;
+    }
+    else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_depth_texture"))
+    {
+        ext = WEBGL_depth_texture;
     }
 
     if (ext == WebGLExtensionID_unknown_extension) {
       return nullptr;
     }
 
-    if (!mExtensions[ext]) {
+    // step 2: check if the extension is supported
+    if (!IsExtensionSupported(ext)) {
+        return nullptr;
+    }
+
+    // step 3: if the extension hadn't been previously been created, create it now, thus enabling it
+    if (!IsExtensionEnabled(ext)) {
+        WebGLExtensionBase *obj = nullptr;
         switch (ext) {
             case OES_standard_derivatives:
-                mExtensions[ext] = new WebGLExtensionStandardDerivatives(this);
+                obj = new WebGLExtensionStandardDerivatives(this);
                 break;
             case EXT_texture_filter_anisotropic:
-                mExtensions[ext] = new WebGLExtensionTextureFilterAnisotropic(this);
+                obj = new WebGLExtensionTextureFilterAnisotropic(this);
                 break;
             case WEBGL_lose_context:
-                mExtensions[ext] = new WebGLExtensionLoseContext(this);
+                obj = new WebGLExtensionLoseContext(this);
                 break;
             case WEBGL_compressed_texture_s3tc:
-                mExtensions[ext] = new WebGLExtensionCompressedTextureS3TC(this);
+                obj = new WebGLExtensionCompressedTextureS3TC(this);
                 break;
             case WEBGL_compressed_texture_atc:
-                mExtensions[ext] = new WebGLExtensionCompressedTextureATC(this);
+                obj = new WebGLExtensionCompressedTextureATC(this);
                 break;
             case WEBGL_compressed_texture_pvrtc:
-                mExtensions[ext] = new WebGLExtensionCompressedTexturePVRTC(this);
+                obj = new WebGLExtensionCompressedTexturePVRTC(this);
                 break;
             case WEBGL_depth_texture:
-                mExtensions[ext] = new WebGLExtensionDepthTexture(this);
+                obj = new WebGLExtensionDepthTexture(this);
+                break;
+            case OES_texture_float:
+                obj = new WebGLExtensionTextureFloat(this);
                 break;
             default:
-                // create a generic WebGLExtension object for any extensions that don't
-                // have any additional tokens or methods. We still need these to be separate
-                // objects in case the user might extend the corresponding JS objects with custom
-                // properties.
-                mExtensions[ext] = new WebGLExtension(this);
-                break;
+                MOZ_ASSERT(false, "should not get there.");
         }
+        mExtensions.EnsureLengthAtLeast(ext + 1);
+        mExtensions[ext] = obj;
     }
 
-    return mExtensions[ext];
+    // step 4: return the extension as a JS object
+    JS::Value v;
+    JSObject* wrapper = GetWrapper();
+    JSAutoCompartment ac(cx, wrapper);
+    if (!WrapNewBindingObject(cx, wrapper, mExtensions[ext], &v)) {
+        return nullptr;
+    }
+    return &v.toObject();
 }
 
 void
 WebGLContext::ForceClearFramebufferWithDefaultValues(uint32_t mask, const nsIntRect& viewportRect)
 {
     MakeContextCurrent();
 
     bool initializeColorBuffer = 0 != (mask & LOCAL_GL_COLOR_BUFFER_BIT);
@@ -1446,43 +1457,47 @@ NS_IMPL_RELEASE(WebGLRenderbuffer)
 DOMCI_DATA(WebGLRenderbuffer, WebGLRenderbuffer)
 
 NS_INTERFACE_MAP_BEGIN(WebGLRenderbuffer)
   NS_INTERFACE_MAP_ENTRY(nsIWebGLRenderbuffer)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLRenderbuffer)
 NS_INTERFACE_MAP_END
 
+// WebGLUniformLocation
+
 NS_IMPL_ADDREF(WebGLUniformLocation)
 NS_IMPL_RELEASE(WebGLUniformLocation)
 
-DOMCI_DATA(WebGLUniformLocation, WebGLUniformLocation)
-
 NS_INTERFACE_MAP_BEGIN(WebGLUniformLocation)
-  NS_INTERFACE_MAP_ENTRY(nsIWebGLUniformLocation)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLUniformLocation)
 NS_INTERFACE_MAP_END
 
 JSObject*
 WebGLUniformLocation::WrapObject(JSContext *cx, JSObject *scope)
 {
     return dom::WebGLUniformLocationBinding::Wrap(cx, scope, this);
 }
 
+// WebGLShaderPrecisionFormat
+
+NS_INTERFACE_MAP_BEGIN(WebGLShaderPrecisionFormat)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
 NS_IMPL_ADDREF(WebGLShaderPrecisionFormat)
 NS_IMPL_RELEASE(WebGLShaderPrecisionFormat)
 
-DOMCI_DATA(WebGLShaderPrecisionFormat, WebGLShaderPrecisionFormat)
+JSObject*
+WebGLShaderPrecisionFormat::WrapObject(JSContext *cx, JSObject *scope)
+{
+    return dom::WebGLShaderPrecisionFormatBinding::Wrap(cx, scope, this);
+}
 
-NS_INTERFACE_MAP_BEGIN(WebGLShaderPrecisionFormat)
-  NS_INTERFACE_MAP_ENTRY(nsIWebGLShaderPrecisionFormat)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLShaderPrecisionFormat)
-NS_INTERFACE_MAP_END
+// WebGLActiveInfo
 
 NS_IMPL_ADDREF(WebGLActiveInfo)
 NS_IMPL_RELEASE(WebGLActiveInfo)
 
 DOMCI_DATA(WebGLActiveInfo, WebGLActiveInfo)
 
 NS_INTERFACE_MAP_BEGIN(WebGLActiveInfo)
   NS_INTERFACE_MAP_ENTRY(nsIWebGLActiveInfo)
@@ -1498,45 +1513,16 @@ NS_IMETHODIMP base::SetName(WebGLuint aN
 
 NAME_NOT_SUPPORTED(WebGLTexture)
 NAME_NOT_SUPPORTED(WebGLBuffer)
 NAME_NOT_SUPPORTED(WebGLProgram)
 NAME_NOT_SUPPORTED(WebGLShader)
 NAME_NOT_SUPPORTED(WebGLFramebuffer)
 NAME_NOT_SUPPORTED(WebGLRenderbuffer)
 
-// WebGLExtension
-
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLExtension)
-  
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebGLExtension)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-  NS_INTERFACE_MAP_ENTRY(nsIWebGLExtension)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLExtension)
-NS_INTERFACE_MAP_END 
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLExtension)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLExtension)
-
-DOMCI_DATA(WebGLExtension, WebGLExtension)
-
-/* [noscript] attribute WebGLint location; */
-NS_IMETHODIMP
-WebGLUniformLocation::GetLocation(WebGLint *aLocation)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-WebGLUniformLocation::SetLocation(WebGLint aLocation)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
 /* readonly attribute WebGLint size; */
 NS_IMETHODIMP
 WebGLActiveInfo::GetSize(WebGLint *aSize)
 {
     *aSize = mSize;
     return NS_OK;
 }
 
@@ -1551,60 +1537,31 @@ WebGLActiveInfo::GetType(WebGLenum *aTyp
 /* readonly attribute DOMString name; */
 NS_IMETHODIMP
 WebGLActiveInfo::GetName(nsAString & aName)
 {
     aName = mName;
     return NS_OK;
 }
 
-/* readonly attribute WebGLint rangeMin */
-NS_IMETHODIMP
-WebGLShaderPrecisionFormat::GetRangeMin(WebGLint *aRangeMin)
-{
-    *aRangeMin = mRangeMin;
-    return NS_OK;
-}
-
-/* readonly attribute WebGLint rangeMax */
-NS_IMETHODIMP
-WebGLShaderPrecisionFormat::GetRangeMax(WebGLint *aRangeMax)
-{
-    *aRangeMax = mRangeMax;
-    return NS_OK;
-}
-
-/* readonly attribute WebGLint precision */
-NS_IMETHODIMP
-WebGLShaderPrecisionFormat::GetPrecision(WebGLint *aPrecision)
-{
-    *aPrecision = mPrecision;
-    return NS_OK;
-}
-
 void
 WebGLContext::GetSupportedExtensions(Nullable< nsTArray<nsString> > &retval)
 {
     retval.SetNull();
     if (!IsContextStable())
         return;
-    
-    if (mDisableExtensions) {
-        return;
-    }
 
     nsTArray<nsString>& arr = retval.SetValue();
     
     if (IsExtensionSupported(OES_texture_float))
         arr.AppendElement(NS_LITERAL_STRING("OES_texture_float"));
     if (IsExtensionSupported(OES_standard_derivatives))
         arr.AppendElement(NS_LITERAL_STRING("OES_standard_derivatives"));
-    if (IsExtensionSupported(EXT_texture_filter_anisotropic)) {
+    if (IsExtensionSupported(EXT_texture_filter_anisotropic))
         arr.AppendElement(NS_LITERAL_STRING("EXT_texture_filter_anisotropic"));
-    }
     if (IsExtensionSupported(WEBGL_lose_context))
         arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_lose_context"));
     if (IsExtensionSupported(WEBGL_compressed_texture_s3tc))
         arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_s3tc"));
     if (IsExtensionSupported(WEBGL_compressed_texture_atc))
         arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_atc"));
     if (IsExtensionSupported(WEBGL_compressed_texture_pvrtc))
         arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_pvrtc"));
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -67,24 +67,24 @@ namespace mozilla {
 
 class WebGLTexture;
 class WebGLBuffer;
 class WebGLProgram;
 class WebGLShader;
 class WebGLFramebuffer;
 class WebGLRenderbuffer;
 class WebGLUniformLocation;
-class WebGLExtension;
 class WebGLContext;
 struct WebGLVertexAttribData;
 class WebGLMemoryPressureObserver;
 class WebGLRectangleObject;
 class WebGLContextBoundObject;
 class WebGLActiveInfo;
 class WebGLShaderPrecisionFormat;
+class WebGLExtensionBase;
 
 enum FakeBlackStatus { DoNotNeedFakeBlack, DoNeedFakeBlack, DontKnowIfNeedFakeBlack };
 
 struct VertexAttrib0Status {
     enum { Default, EmulatedUninitializedArray, EmulatedInitializedArray };
 };
 
 struct BackbufferClearingStatus {
@@ -626,17 +626,17 @@ public:
         if (!IsContextStable())
             return 0;
         return mHeight;
     }
         
     JSObject *GetContextAttributes(ErrorResult &rv);
     bool IsContextLost() const { return !IsContextStable(); }
     void GetSupportedExtensions(dom::Nullable< nsTArray<nsString> > &retval);
-    nsIWebGLExtension* GetExtension(const nsAString& aName);
+    JSObject* GetExtension(JSContext* ctx, const nsAString& aName);
     void ActiveTexture(WebGLenum texture);
     void AttachShader(WebGLProgram* program, WebGLShader* shader);
     void BindAttribLocation(WebGLProgram* program, WebGLuint location,
                             const nsAString& name);
     void BindBuffer(WebGLenum target, WebGLBuffer* buf);
     void BindFramebuffer(WebGLenum target, WebGLFramebuffer* wfb);
     void BindRenderbuffer(WebGLenum target, WebGLRenderbuffer* wrb);
     void BindTexture(WebGLenum target, WebGLTexture *tex);
@@ -1170,28 +1170,25 @@ protected:
         OES_texture_float,
         OES_standard_derivatives,
         EXT_texture_filter_anisotropic,
         WEBGL_lose_context,
         WEBGL_compressed_texture_s3tc,
         WEBGL_compressed_texture_atc,
         WEBGL_compressed_texture_pvrtc,
         WEBGL_depth_texture,
-        WebGLExtensionID_number_of_extensions,
         WebGLExtensionID_unknown_extension
     };
-    nsAutoTArray<nsRefPtr<WebGLExtension>, WebGLExtensionID_number_of_extensions> mExtensions;
+    nsTArray<nsRefPtr<WebGLExtensionBase> > mExtensions;
 
     // returns true if the extension has been enabled by calling getExtension.
-    bool IsExtensionEnabled(WebGLExtensionID ext) {
-        return mExtensions[ext];
-    }
+    bool IsExtensionEnabled(WebGLExtensionID ext) const;
 
     // returns true if the extension is supported (as returned by getSupportedExtensions)
-    bool IsExtensionSupported(WebGLExtensionID ext);
+    bool IsExtensionSupported(WebGLExtensionID ext) const;
 
     nsTArray<WebGLenum> mCompressedTextureFormats;
 
     bool InitAndValidateGL();
     bool ValidateBuffers(int32_t *maxAllowedCount, const char *info);
     bool ValidateCapabilityEnum(WebGLenum cap, const char *info);
     bool ValidateBlendEquationEnum(WebGLenum cap, const char *info);
     bool ValidateBlendFuncDstEnum(WebGLenum mode, const char *info);
@@ -1415,16 +1412,23 @@ public:
     friend class WebGLFramebuffer;
     friend class WebGLRenderbuffer;
     friend class WebGLProgram;
     friend class WebGLBuffer;
     friend class WebGLShader;
     friend class WebGLUniformLocation;
 };
 
+// used by DOM bindings in conjunction with GetParentObject
+inline nsISupports*
+ToSupports(WebGLContext* context)
+{
+  return static_cast<nsICanvasRenderingContextInternal*>(context);
+}
+
 // This class is a mixin for objects that are tied to a specific
 // context (which is to say, all of them).  They provide initialization
 // as well as comparison with the current context.
 class WebGLContextBoundObject
 {
 public:
     WebGLContextBoundObject(WebGLContext *context) {
         mContext = context;
@@ -2995,17 +2999,17 @@ public:
     // we will only need to initialize renderbuffers. Textures are already initialized.
     WebGLFramebufferAttachment mColorAttachment,
                                mDepthAttachment,
                                mStencilAttachment,
                                mDepthStencilAttachment;
 };
 
 class WebGLUniformLocation MOZ_FINAL
-    : public nsIWebGLUniformLocation
+    : public nsISupports
     , public WebGLContextBoundObject
 {
 public:
     WebGLUniformLocation(WebGLContext *context, WebGLProgram *program, GLint location, const WebGLUniformInfo& info)
         : WebGLContextBoundObject(context)
         , mProgram(program)
         , mProgramGeneration(program->Generation())
         , mLocation(location)
@@ -3026,17 +3030,16 @@ public:
     WebGLProgram *Program() const { return mProgram; }
     GLint Location() const { return mLocation; }
     uint32_t ProgramGeneration() const { return mProgramGeneration; }
     int ElementSize() const { return mElementSize; }
 
     virtual JSObject* WrapObject(JSContext *cx, JSObject *scope);
 
     NS_DECL_ISUPPORTS
-    NS_DECL_NSIWEBGLUNIFORMLOCATION
 protected:
     // nsRefPtr, not WebGLRefPtr, so that we don't prevent the program from being explicitly deleted.
     // we just want to avoid having a dangling pointer.
     nsRefPtr<WebGLProgram> mProgram;
 
     uint32_t mProgramGeneration;
     GLint mLocation;
     WebGLUniformInfo mInfo;
@@ -3058,53 +3061,49 @@ public:
     NS_DECL_NSIWEBGLACTIVEINFO
 protected:
     WebGLint mSize;
     WebGLenum mType;
     nsString mName;
 };
 
 class WebGLShaderPrecisionFormat MOZ_FINAL
-    : public nsIWebGLShaderPrecisionFormat
+    : public nsISupports
+    , public WebGLContextBoundObject
 {
 public:
-    WebGLShaderPrecisionFormat(WebGLint rangeMin, WebGLint rangeMax, WebGLint precision) :
+    WebGLShaderPrecisionFormat(WebGLContext *context, WebGLint rangeMin, WebGLint rangeMax, WebGLint precision) :
+        WebGLContextBoundObject(context),
         mRangeMin(rangeMin),
         mRangeMax(rangeMax),
         mPrecision(precision)
     {
-    
     }
 
+    virtual JSObject* WrapObject(JSContext *cx, JSObject *scope);
+
     NS_DECL_ISUPPORTS
-    NS_DECL_NSIWEBGLSHADERPRECISIONFORMAT
+
+    // WebIDL WebGLShaderPrecisionFormat API
+    WebGLint RangeMin() const {
+        return mRangeMin;
+    }
+    WebGLint RangeMax() const {
+        return mRangeMax;
+    }
+    WebGLint Precision() const {
+        return mPrecision;
+    }
 
 protected:
     WebGLint mRangeMin;
     WebGLint mRangeMax;
     WebGLint mPrecision;
 };
 
-class WebGLExtension
-    : public nsIWebGLExtension
-    , public WebGLContextBoundObject
-    , public nsWrapperCache
-{
-public:
-    WebGLExtension(WebGLContext *baseContext)
-        : WebGLContextBoundObject(baseContext)
-    {}
-
-    NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-    NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WebGLExtension)
-    NS_DECL_NSIWEBGLEXTENSION
-
-    virtual ~WebGLExtension() {}
-};
-
 inline const WebGLRectangleObject *WebGLContext::FramebufferRectangleObject() const {
     return mBoundFramebuffer ? mBoundFramebuffer->RectangleObject()
                              : static_cast<const WebGLRectangleObject*>(this);
 }
 
 /**
  ** Template implementations
  **/
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -1718,17 +1718,17 @@ WebGLContext::GenerateMipmap(WebGLenum t
 
     if (!tex->IsFirstImagePowerOfTwo())
         return ErrorInvalidOperation("generateMipmap: Level zero of texture does not have power-of-two width and height.");
 
     GLenum format = tex->ImageInfoAt(0, 0).Format();
     if (IsTextureFormatCompressed(format))
         return ErrorInvalidOperation("generateMipmap: Texture data at level zero is compressed.");
 
-    if (IsExtensionEnabled(WEBGL_depth_texture) && 
+    if (IsExtensionEnabled(WEBGL_depth_texture) &&
         (format == LOCAL_GL_DEPTH_COMPONENT || format == LOCAL_GL_DEPTH_STENCIL))
         return ErrorInvalidOperation("generateMipmap: "
                                      "A texture that has a base internal format of "
                                      "DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
 
     if (!tex->AreAllLevel0ImageInfosEqual())
         return ErrorInvalidOperation("generateMipmap: The six faces of this cube map have different dimensions, format, or type.");
 
@@ -2664,17 +2664,16 @@ WebGLContext::GetTexParameter(WebGLenum 
         }
         case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
             if (IsExtensionEnabled(EXT_texture_filter_anisotropic)) {
                 GLfloat f = 0.f;
                 gl->fGetTexParameterfv(target, pname, &f);
                 return JS::DoubleValue(f);
             }
 
-            
             ErrorInvalidEnumInfo("getTexParameter: parameter", pname);
             break;
 
         default:
             ErrorInvalidEnumInfo("getTexParameter: parameter", pname);
     }
 
     return JS::NullValue();
@@ -4486,17 +4485,17 @@ WebGLContext::GetShaderPrecisionFormat(W
     }
 
     MakeContextCurrent();
 
     GLint range[2], precision;
     gl->fGetShaderPrecisionFormat(shadertype, precisiontype, range, &precision);
 
     WebGLShaderPrecisionFormat *retShaderPrecisionFormat
-        = new WebGLShaderPrecisionFormat(range[0], range[1], precision);
+        = new WebGLShaderPrecisionFormat(this, range[0], range[1], precision);
     NS_ADDREF(retShaderPrecisionFormat);
     return retShaderPrecisionFormat;
 }
 
 void
 WebGLContext::GetShaderSource(WebGLShader *shader, nsAString& retval)
 {
     if (!IsContextStable())
@@ -4870,17 +4869,17 @@ WebGLContext::TexSubImage2D_base(WebGLen
     }
 
     if (level >= 1) {
         if (!(is_pot_assuming_nonnegative(width) &&
               is_pot_assuming_nonnegative(height)))
             return ErrorInvalidValue("texSubImage2D: with level > 0, width and height must be powers of two");
     }
 
-    if (IsExtensionEnabled(WEBGL_depth_texture) && 
+    if (IsExtensionEnabled(WEBGL_depth_texture) &&
         (format == LOCAL_GL_DEPTH_COMPONENT || format == LOCAL_GL_DEPTH_STENCIL)) {
         return ErrorInvalidOperation("texSubImage2D: format");
     }
 
     uint32_t dstTexelSize = 0;
     if (!ValidateTexFormatAndType(format, type, jsArrayType, &dstTexelSize, "texSubImage2D"))
         return;
 
new file mode 100644
--- /dev/null
+++ b/content/canvas/src/WebGLExtensionBase.cpp
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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 "WebGLContext.h"
+#include "WebGLExtensions.h"
+
+using namespace mozilla;
+
+WebGLExtensionBase::WebGLExtensionBase(WebGLContext* context)
+    : WebGLContextBoundObject(context)
+{
+    SetIsDOMBinding();
+}
+
+WebGLExtensionBase::~WebGLExtensionBase()
+{
+}
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLExtensionBase)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLExtensionBase)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLExtensionBase)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebGLExtensionBase)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
--- a/content/canvas/src/WebGLExtensionCompressedTextureATC.cpp
+++ b/content/canvas/src/WebGLExtensionCompressedTextureATC.cpp
@@ -1,32 +1,23 @@
 /* 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 "WebGLContext.h"
 #include "WebGLExtensions.h"
+#include "mozilla/dom/WebGLRenderingContextBinding.h"
 
 using namespace mozilla;
 
 WebGLExtensionCompressedTextureATC::WebGLExtensionCompressedTextureATC(WebGLContext* context)
-    : WebGLExtension(context)
+    : WebGLExtensionBase(context)
 {
     context->mCompressedTextureFormats.AppendElement(LOCAL_GL_ATC_RGB);
     context->mCompressedTextureFormats.AppendElement(LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA);
     context->mCompressedTextureFormats.AppendElement(LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA);
 }
 
 WebGLExtensionCompressedTextureATC::~WebGLExtensionCompressedTextureATC()
 {
-
 }
 
-NS_IMPL_ADDREF_INHERITED(WebGLExtensionCompressedTextureATC, WebGLExtension)
-NS_IMPL_RELEASE_INHERITED(WebGLExtensionCompressedTextureATC, WebGLExtension)
-
-DOMCI_DATA(WebGLExtensionCompressedTextureATC, WebGLExtensionCompressedTextureATC)
-
-NS_INTERFACE_MAP_BEGIN(WebGLExtensionCompressedTextureATC)
-  NS_INTERFACE_MAP_ENTRY(nsIWebGLExtensionCompressedTextureATC)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, WebGLExtension)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLExtensionCompressedTextureATC)
-NS_INTERFACE_MAP_END_INHERITING(WebGLExtension)
+IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionCompressedTextureATC)
--- a/content/canvas/src/WebGLExtensionCompressedTexturePVRTC.cpp
+++ b/content/canvas/src/WebGLExtensionCompressedTexturePVRTC.cpp
@@ -1,33 +1,24 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WebGLContext.h"
 #include "WebGLExtensions.h"
+#include "mozilla/dom/WebGLRenderingContextBinding.h"
 
 using namespace mozilla;
 
 WebGLExtensionCompressedTexturePVRTC::WebGLExtensionCompressedTexturePVRTC(WebGLContext* context)
-    : WebGLExtension(context)
+    : WebGLExtensionBase(context)
 {
     context->mCompressedTextureFormats.AppendElement(LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1);
     context->mCompressedTextureFormats.AppendElement(LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1);
     context->mCompressedTextureFormats.AppendElement(LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1);
     context->mCompressedTextureFormats.AppendElement(LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1);
 }
 
 WebGLExtensionCompressedTexturePVRTC::~WebGLExtensionCompressedTexturePVRTC()
 {
-
 }
 
-NS_IMPL_ADDREF_INHERITED(WebGLExtensionCompressedTexturePVRTC, WebGLExtension)
-NS_IMPL_RELEASE_INHERITED(WebGLExtensionCompressedTexturePVRTC, WebGLExtension)
-
-DOMCI_DATA(WebGLExtensionCompressedTexturePVRTC, WebGLExtensionCompressedTexturePVRTC)
-
-NS_INTERFACE_MAP_BEGIN(WebGLExtensionCompressedTexturePVRTC)
-  NS_INTERFACE_MAP_ENTRY(nsIWebGLExtensionCompressedTexturePVRTC)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, WebGLExtension)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLExtensionCompressedTexturePVRTC)
-NS_INTERFACE_MAP_END_INHERITING(WebGLExtension)
+IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionCompressedTexturePVRTC)
--- a/content/canvas/src/WebGLExtensionCompressedTextureS3TC.cpp
+++ b/content/canvas/src/WebGLExtensionCompressedTextureS3TC.cpp
@@ -1,33 +1,24 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WebGLContext.h"
 #include "WebGLExtensions.h"
+#include "mozilla/dom/WebGLRenderingContextBinding.h"
 
 using namespace mozilla;
 
 WebGLExtensionCompressedTextureS3TC::WebGLExtensionCompressedTextureS3TC(WebGLContext* context)
-    : WebGLExtension(context)
+    : WebGLExtensionBase(context)
 {
     context->mCompressedTextureFormats.AppendElement(LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT);
     context->mCompressedTextureFormats.AppendElement(LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT);
     context->mCompressedTextureFormats.AppendElement(LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT);
     context->mCompressedTextureFormats.AppendElement(LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT);
 }
 
 WebGLExtensionCompressedTextureS3TC::~WebGLExtensionCompressedTextureS3TC()
 {
-
 }
 
-NS_IMPL_ADDREF_INHERITED(WebGLExtensionCompressedTextureS3TC, WebGLExtension)
-NS_IMPL_RELEASE_INHERITED(WebGLExtensionCompressedTextureS3TC, WebGLExtension)
-
-DOMCI_DATA(WebGLExtensionCompressedTextureS3TC, WebGLExtensionCompressedTextureS3TC)
-
-NS_INTERFACE_MAP_BEGIN(WebGLExtensionCompressedTextureS3TC)
-  NS_INTERFACE_MAP_ENTRY(nsIWebGLExtensionCompressedTextureS3TC)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, WebGLExtension)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLExtensionCompressedTextureS3TC)
-NS_INTERFACE_MAP_END_INHERITING(WebGLExtension)
+IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionCompressedTextureS3TC)
--- a/content/canvas/src/WebGLExtensionDepthTexture.cpp
+++ b/content/canvas/src/WebGLExtensionDepthTexture.cpp
@@ -1,32 +1,21 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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 "WebGLContext.h"
 #include "WebGLExtensions.h"
+#include "mozilla/dom/WebGLRenderingContextBinding.h"
 
 using namespace mozilla;
 
-WebGLExtensionDepthTexture::WebGLExtensionDepthTexture(WebGLContext* context) :
-    WebGLExtension(context)
+WebGLExtensionDepthTexture::WebGLExtensionDepthTexture(WebGLContext* context)
+    : WebGLExtensionBase(context)
 {
-
 }
 
 WebGLExtensionDepthTexture::~WebGLExtensionDepthTexture()
 {
-
 }
 
-NS_IMPL_ADDREF_INHERITED(WebGLExtensionDepthTexture, WebGLExtension)
-NS_IMPL_RELEASE_INHERITED(WebGLExtensionDepthTexture, WebGLExtension)
-
-DOMCI_DATA(WebGLExtensionDepthTexture, WebGLExtensionDepthTexture)
-
-NS_INTERFACE_MAP_BEGIN(WebGLExtensionDepthTexture)
-  NS_INTERFACE_MAP_ENTRY(nsIWebGLExtensionDepthTexture)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, WebGLExtension)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLExtensionDepthTexture)
-NS_INTERFACE_MAP_END_INHERITING(WebGLExtension)
-
+IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionDepthTexture)
--- a/content/canvas/src/WebGLExtensionLoseContext.cpp
+++ b/content/canvas/src/WebGLExtensionLoseContext.cpp
@@ -1,49 +1,35 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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 "WebGLContext.h"
 #include "WebGLExtensions.h"
+#include "mozilla/dom/WebGLRenderingContextBinding.h"
 
 using namespace mozilla;
 
-WebGLExtensionLoseContext::WebGLExtensionLoseContext(WebGLContext* context) :
-    WebGLExtension(context)
+WebGLExtensionLoseContext::WebGLExtensionLoseContext(WebGLContext* context)
+    : WebGLExtensionBase(context)
 {
-
 }
 
 WebGLExtensionLoseContext::~WebGLExtensionLoseContext()
 {
-
 }
 
-NS_IMETHODIMP 
+void
 WebGLExtensionLoseContext::LoseContext()
 {
     if (!mContext->LoseContext())
         mContext->mWebGLError = LOCAL_GL_INVALID_OPERATION;
-
-    return NS_OK;
 }
 
-NS_IMETHODIMP 
+void 
 WebGLExtensionLoseContext::RestoreContext()
 {
     if (!mContext->RestoreContext())
         mContext->mWebGLError = LOCAL_GL_INVALID_OPERATION;
-
-    return NS_OK;
 }
 
-NS_IMPL_ADDREF_INHERITED(WebGLExtensionLoseContext, WebGLExtension)
-NS_IMPL_RELEASE_INHERITED(WebGLExtensionLoseContext, WebGLExtension)
-
-DOMCI_DATA(WebGLExtensionLoseContext, WebGLExtensionLoseContext)
-
-NS_INTERFACE_MAP_BEGIN(WebGLExtensionLoseContext)
-  NS_INTERFACE_MAP_ENTRY(nsIWebGLExtensionLoseContext)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, WebGLExtension)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLExtensionLoseContext)
-NS_INTERFACE_MAP_END_INHERITING(WebGLExtension)
+IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionLoseContext)
--- a/content/canvas/src/WebGLExtensionStandardDerivatives.cpp
+++ b/content/canvas/src/WebGLExtensionStandardDerivatives.cpp
@@ -1,31 +1,21 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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 "WebGLContext.h"
 #include "WebGLExtensions.h"
+#include "mozilla/dom/WebGLRenderingContextBinding.h"
 
 using namespace mozilla;
 
-WebGLExtensionStandardDerivatives::WebGLExtensionStandardDerivatives(WebGLContext* context) :
-    WebGLExtension(context)
+WebGLExtensionStandardDerivatives::WebGLExtensionStandardDerivatives(WebGLContext* context)
+    : WebGLExtensionBase(context)
 {
-
 }
 
 WebGLExtensionStandardDerivatives::~WebGLExtensionStandardDerivatives()
 {
-
 }
 
-NS_IMPL_ADDREF_INHERITED(WebGLExtensionStandardDerivatives, WebGLExtension)
-NS_IMPL_RELEASE_INHERITED(WebGLExtensionStandardDerivatives, WebGLExtension)
-
-DOMCI_DATA(WebGLExtensionStandardDerivatives, WebGLExtensionStandardDerivatives)
-
-NS_INTERFACE_MAP_BEGIN(WebGLExtensionStandardDerivatives)
-  NS_INTERFACE_MAP_ENTRY(nsIWebGLExtensionStandardDerivatives)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, WebGLExtension)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLExtensionStandardDerivatives)
-NS_INTERFACE_MAP_END_INHERITING(WebGLExtension)
+IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionStandardDerivatives)
--- a/content/canvas/src/WebGLExtensionTextureFilterAnisotropic.cpp
+++ b/content/canvas/src/WebGLExtensionTextureFilterAnisotropic.cpp
@@ -1,31 +1,21 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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 "WebGLContext.h"
 #include "WebGLExtensions.h"
+#include "mozilla/dom/WebGLRenderingContextBinding.h"
 
 using namespace mozilla;
 
-WebGLExtensionTextureFilterAnisotropic::WebGLExtensionTextureFilterAnisotropic(WebGLContext* context) :
-    WebGLExtension(context)
+WebGLExtensionTextureFilterAnisotropic::WebGLExtensionTextureFilterAnisotropic(WebGLContext* context)
+    : WebGLExtensionBase(context)
 {
-
 }
 
 WebGLExtensionTextureFilterAnisotropic::~WebGLExtensionTextureFilterAnisotropic()
 {
-
 }
 
-NS_IMPL_ADDREF_INHERITED(WebGLExtensionTextureFilterAnisotropic, WebGLExtension)
-NS_IMPL_RELEASE_INHERITED(WebGLExtensionTextureFilterAnisotropic, WebGLExtension)
-
-DOMCI_DATA(WebGLExtensionTextureFilterAnisotropic, WebGLExtensionTextureFilterAnisotropic)
-
-NS_INTERFACE_MAP_BEGIN(WebGLExtensionTextureFilterAnisotropic)
-  NS_INTERFACE_MAP_ENTRY(nsIWebGLExtensionTextureFilterAnisotropic)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, WebGLExtension)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLExtensionTextureFilterAnisotropic)
-NS_INTERFACE_MAP_END_INHERITING(WebGLExtension)
+IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionTextureFilterAnisotropic)
new file mode 100644
--- /dev/null
+++ b/content/canvas/src/WebGLExtensionTextureFloat.cpp
@@ -0,0 +1,20 @@
+/* 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 "WebGLContext.h"
+#include "WebGLExtensions.h"
+#include "mozilla/dom/WebGLRenderingContextBinding.h"
+
+using namespace mozilla;
+
+WebGLExtensionTextureFloat::WebGLExtensionTextureFloat(WebGLContext* context)
+    : WebGLExtensionBase(context)
+{
+}
+
+WebGLExtensionTextureFloat::~WebGLExtensionTextureFloat()
+{
+}
+
+IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionTextureFloat)
--- a/content/canvas/src/WebGLExtensions.h
+++ b/content/canvas/src/WebGLExtensions.h
@@ -1,97 +1,124 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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 WEBGLEXTENSIONS_H_
 #define WEBGLEXTENSIONS_H_
 
+#include "WebGLContext.h"
+
 namespace mozilla {
 
-class WebGLExtensionLoseContext :
-    public nsIWebGLExtensionLoseContext,
-    public WebGLExtension
+class WebGLExtensionBase
+    : public nsISupports
+    , public WebGLContextBoundObject
+    , public nsWrapperCache
+{
+public:
+    WebGLExtensionBase(WebGLContext*);
+    virtual ~WebGLExtensionBase();
+
+    WebGLContext *GetParentObject() const {
+        return Context();
+    }
+
+    NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+    NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WebGLExtensionBase)
+};
+
+#define DECL_WEBGL_EXTENSION_GOOP \
+    JSObject* WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap);
+
+#define IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionType) \
+    JSObject* \
+    WebGLExtensionType::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap) { \
+        return dom::WebGLExtensionType##Binding::Wrap(cx, scope, this, triedToWrap); \
+    }
+
+class WebGLExtensionCompressedTextureATC
+    : public WebGLExtensionBase
+{
+public:
+    WebGLExtensionCompressedTextureATC(WebGLContext*);
+    virtual ~WebGLExtensionCompressedTextureATC();
+
+    DECL_WEBGL_EXTENSION_GOOP
+};
+
+class WebGLExtensionCompressedTexturePVRTC
+    : public WebGLExtensionBase
+{
+public:
+    WebGLExtensionCompressedTexturePVRTC(WebGLContext*);
+    virtual ~WebGLExtensionCompressedTexturePVRTC();
+
+    DECL_WEBGL_EXTENSION_GOOP
+};
+
+class WebGLExtensionCompressedTextureS3TC
+    : public WebGLExtensionBase
+{
+public:
+    WebGLExtensionCompressedTextureS3TC(WebGLContext*);
+    virtual ~WebGLExtensionCompressedTextureS3TC();
+
+    DECL_WEBGL_EXTENSION_GOOP
+};
+
+class WebGLExtensionDepthTexture
+    : public WebGLExtensionBase
+{
+public:
+    WebGLExtensionDepthTexture(WebGLContext*);
+    virtual ~WebGLExtensionDepthTexture();
+
+    DECL_WEBGL_EXTENSION_GOOP
+};
+
+class WebGLExtensionLoseContext
+    : public WebGLExtensionBase
 {
 public:
     WebGLExtensionLoseContext(WebGLContext*);
     virtual ~WebGLExtensionLoseContext();
 
-    NS_DECL_ISUPPORTS_INHERITED
-    NS_DECL_NSIWEBGLEXTENSIONLOSECONTEXT
-};
+    void LoseContext();
+    void RestoreContext();
 
-class WebGLExtensionStandardDerivatives :
-    public nsIWebGLExtensionStandardDerivatives,
-    public WebGLExtension
-{
-public:
-    WebGLExtensionStandardDerivatives(WebGLContext* context);
-    virtual ~WebGLExtensionStandardDerivatives();
-
-    NS_DECL_ISUPPORTS_INHERITED
-    NS_DECL_NSIWEBGLEXTENSION
+    DECL_WEBGL_EXTENSION_GOOP
 };
 
-class WebGLExtensionTextureFilterAnisotropic :
-    public nsIWebGLExtensionTextureFilterAnisotropic,
-    public WebGLExtension
+class WebGLExtensionStandardDerivatives
+    : public WebGLExtensionBase
 {
 public:
-    WebGLExtensionTextureFilterAnisotropic(WebGLContext* context);
-    virtual ~WebGLExtensionTextureFilterAnisotropic();
-
-    NS_DECL_ISUPPORTS_INHERITED
-    NS_DECL_NSIWEBGLEXTENSION
-};
+    WebGLExtensionStandardDerivatives(WebGLContext*);
+    virtual ~WebGLExtensionStandardDerivatives();
 
-class WebGLExtensionCompressedTextureS3TC :
-    public nsIWebGLExtensionCompressedTextureS3TC,
-    public WebGLExtension
-{
-public:
-    WebGLExtensionCompressedTextureS3TC(WebGLContext* context);
-    virtual ~WebGLExtensionCompressedTextureS3TC();
-
-    NS_DECL_ISUPPORTS_INHERITED
-    NS_DECL_NSIWEBGLEXTENSION
+    DECL_WEBGL_EXTENSION_GOOP
 };
 
-class WebGLExtensionCompressedTextureATC :
-    public nsIWebGLExtensionCompressedTextureATC,
-    public WebGLExtension
-{
-public:
-    WebGLExtensionCompressedTextureATC(WebGLContext* context);
-    virtual ~WebGLExtensionCompressedTextureATC();
-
-    NS_DECL_ISUPPORTS_INHERITED
-    NS_DECL_NSIWEBGLEXTENSION
-};
-
-class WebGLExtensionCompressedTexturePVRTC :
-    public nsIWebGLExtensionCompressedTexturePVRTC,
-    public WebGLExtension
+class WebGLExtensionTextureFilterAnisotropic
+    : public WebGLExtensionBase
 {
 public:
-    WebGLExtensionCompressedTexturePVRTC(WebGLContext* context);
-    virtual ~WebGLExtensionCompressedTexturePVRTC();
+    WebGLExtensionTextureFilterAnisotropic(WebGLContext*);
+    virtual ~WebGLExtensionTextureFilterAnisotropic();
 
-    NS_DECL_ISUPPORTS_INHERITED
-    NS_DECL_NSIWEBGLEXTENSION
+    DECL_WEBGL_EXTENSION_GOOP
 };
 
-class WebGLExtensionDepthTexture :
-    public nsIWebGLExtensionDepthTexture,
-    public WebGLExtension
+class WebGLExtensionTextureFloat
+    : public WebGLExtensionBase
 {
 public:
-    WebGLExtensionDepthTexture(WebGLContext* context);
-    virtual ~WebGLExtensionDepthTexture();
+    WebGLExtensionTextureFloat(WebGLContext*);
+    virtual ~WebGLExtensionTextureFloat();
 
-    NS_DECL_ISUPPORTS_INHERITED
-    NS_DECL_NSIWEBGLEXTENSION
+    DECL_WEBGL_EXTENSION_GOOP
 };
 
-}
+} // namespace mozilla
 
 #endif // WEBGLEXTENSIONS_H_
--- a/content/events/src/nsEventListenerManager.cpp
+++ b/content/events/src/nsEventListenerManager.cpp
@@ -817,16 +817,17 @@ nsEventListenerManager::CompileEventHand
                                      aListenerStruct->mTypeAtom,
                                      &argCount, &argNames);
 
     result = context->CompileEventHandler(aListenerStruct->mTypeAtom,
                                           argCount, argNames,
                                           *body,
                                           url.get(), lineNo,
                                           SCRIPTVERSION_DEFAULT, // for now?
+                                          /* aIsXBL = */ false,
                                           handler);
     if (result == NS_ERROR_ILLEGAL_VALUE) {
       NS_WARNING("Probably a syntax error in the event handler!");
       return NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA;
     }
     NS_ENSURE_SUCCESS(result, result);
   }
 
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -2869,34 +2869,24 @@ nsGenericHTMLElement::SetBoolAttr(nsIAto
 {
   if (aValue) {
     return SetAttr(kNameSpaceID_None, aAttr, EmptyString(), true);
   }
 
   return UnsetAttr(kNameSpaceID_None, aAttr, true);
 }
 
-nsresult
-nsGenericHTMLElement::GetBoolAttr(nsIAtom* aAttr, bool* aValue) const
-{
-  *aValue = HasAttr(kNameSpaceID_None, aAttr);
-  return NS_OK;
-}
-
-nsresult
-nsGenericHTMLElement::GetIntAttr(nsIAtom* aAttr, int32_t aDefault, int32_t* aResult)
+int32_t
+nsGenericHTMLElement::GetIntAttr(nsIAtom* aAttr, int32_t aDefault) const
 {
   const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(aAttr);
   if (attrVal && attrVal->Type() == nsAttrValue::eInteger) {
-    *aResult = attrVal->GetIntegerValue();
+    return attrVal->GetIntegerValue();
   }
-  else {
-    *aResult = aDefault;
-  }
-  return NS_OK;
+  return aDefault;
 }
 
 nsresult
 nsGenericHTMLElement::SetIntAttr(nsIAtom* aAttr, int32_t aValue)
 {
   nsAutoString value;
   value.AppendInt(aValue);
 
@@ -3550,18 +3540,17 @@ nsGenericHTMLFormElement::IntrinsicState
                    "Default submit element that isn't a submit control.");
       // We are the default submit element (:default)
       state |= NS_EVENT_STATE_DEFAULT;
   }
 
   // Make the text controls read-write
   if (!state.HasState(NS_EVENT_STATE_MOZ_READWRITE) &&
       IsTextControl(false)) {
-    bool roState;
-    GetBoolAttr(nsGkAtoms::readonly, &roState);
+    bool roState = GetBoolAttr(nsGkAtoms::readonly);
 
     if (!roState) {
       state |= NS_EVENT_STATE_MOZ_READWRITE;
       state &= ~NS_EVENT_STATE_MOZ_READONLY;
     }
   }
 
   return state;
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -640,17 +640,20 @@ protected:
   /**
    * Helper method for NS_IMPL_BOOL_ATTR macro.
    * Gets value of boolean attribute. Only works for attributes in null
    * namespace.
    *
    * @param aAttr    name of attribute.
    * @param aValue   Boolean value of attribute.
    */
-  NS_HIDDEN_(nsresult) GetBoolAttr(nsIAtom* aAttr, bool* aValue) const;
+  NS_HIDDEN_(bool) GetBoolAttr(nsIAtom* aAttr) const
+  {
+    return HasAttr(kNameSpaceID_None, aAttr);
+  }
 
   /**
    * Helper method for NS_IMPL_BOOL_ATTR macro.
    * Sets value of boolean attribute by removing attribute or setting it to
    * the empty string. Only works for attributes in null namespace.
    *
    * @param aAttr    name of attribute.
    * @param aValue   Boolean value of attribute.
@@ -660,19 +663,18 @@ protected:
   /**
    * Helper method for NS_IMPL_INT_ATTR macro.
    * Gets the integer-value of an attribute, returns specified default value
    * if the attribute isn't set or isn't set to an integer. Only works for
    * attributes in null namespace.
    *
    * @param aAttr    name of attribute.
    * @param aDefault default-value to return if attribute isn't set.
-   * @param aResult  result value [out]
    */
-  NS_HIDDEN_(nsresult) GetIntAttr(nsIAtom* aAttr, int32_t aDefault, int32_t* aValue);
+  NS_HIDDEN_(int32_t) GetIntAttr(nsIAtom* aAttr, int32_t aDefault) const;
 
   /**
    * Helper method for NS_IMPL_INT_ATTR macro.
    * Sets value of attribute to specified integer. Only works for attributes
    * in null namespace.
    *
    * @param aAttr    name of attribute.
    * @param aValue   Integer value of attribute.
@@ -811,16 +813,41 @@ protected:
   bool IsEditableRoot() const;
 
 private:
   void ChangeEditableState(int32_t aChange);
 };
 
 class nsHTMLFieldSetElement;
 
+#define FORM_ELEMENT_FLAG_BIT(n_) NODE_FLAG_BIT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + (n_))
+
+// Form element specific bits
+enum {
+  // If this flag is set on an nsGenericHTMLFormElement, that means that we have
+  // added ourselves to our mForm.  It's possible to have a non-null mForm, but
+  // not have this flag set.  That happens when the form is set via the content
+  // sink.
+  ADDED_TO_FORM =                         FORM_ELEMENT_FLAG_BIT(0),
+
+  // If this flag is set on an nsGenericHTMLFormElement, that means that its form
+  // is in the process of being unbound from the tree, and this form element
+  // hasn't re-found its form in nsGenericHTMLFormElement::UnbindFromTree yet.
+  MAYBE_ORPHAN_FORM_ELEMENT =             FORM_ELEMENT_FLAG_BIT(1)
+};
+
+// NOTE: I don't think it's possible to have the above two flags set at the
+// same time, so if it becomes an issue we can probably merge them into the
+// same bit.  --bz
+
+// Make sure we have enough space for those bits
+PR_STATIC_ASSERT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 1 < 32);
+
+#undef FORM_ELEMENT_FLAG_BIT
+
 /**
  * A helper class for form elements that can contain children
  */
 class nsGenericHTMLFormElement : public nsGenericHTMLElement,
                                  public nsIFormControl
 {
 public:
   nsGenericHTMLFormElement(already_AddRefed<nsINodeInfo> aNodeInfo);
@@ -964,34 +991,16 @@ protected:
 
   /** The form that contains this control */
   nsHTMLFormElement* mForm;
 
   /* This is a pointer to our closest fieldset parent if any */
   nsHTMLFieldSetElement* mFieldSet;
 };
 
-// If this flag is set on an nsGenericHTMLFormElement, that means that we have
-// added ourselves to our mForm.  It's possible to have a non-null mForm, but
-// not have this flag set.  That happens when the form is set via the content
-// sink.
-#define ADDED_TO_FORM (1 << ELEMENT_TYPE_SPECIFIC_BITS_OFFSET)
-
-// If this flag is set on an nsGenericHTMLFormElement, that means that its form
-// is in the process of being unbound from the tree, and this form element
-// hasn't re-found its form in nsGenericHTMLFormElement::UnbindFromTree yet.
-#define MAYBE_ORPHAN_FORM_ELEMENT (1 << (ELEMENT_TYPE_SPECIFIC_BITS_OFFSET+1))
-
-// NOTE: I don't think it's possible to have the above two flags set at the
-// same time, so if it becomes an issue we can probably merge them into the
-// same bit.  --bz
-
-// Make sure we have enough space for those bits
-PR_STATIC_ASSERT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 1 < 32);
-
 //----------------------------------------------------------------------
 
 /**
  * This macro is similar to NS_IMPL_STRING_ATTR except that the getter method
  * falls back to an alternative method if the content attribute isn't set.
  */
 #define NS_IMPL_STRING_ATTR_WITH_FALLBACK(_class, _method, _atom, _fallback) \
   NS_IMETHODIMP                                                              \
@@ -1012,17 +1021,18 @@ PR_STATIC_ASSERT(ELEMENT_TYPE_SPECIFIC_B
  * A macro to implement the getter and setter for a given boolean
  * valued content property. The method uses the generic GetAttr and
  * SetAttr methods.
  */
 #define NS_IMPL_BOOL_ATTR(_class, _method, _atom)                     \
   NS_IMETHODIMP                                                       \
   _class::Get##_method(bool* aValue)                                \
   {                                                                   \
-    return GetBoolAttr(nsGkAtoms::_atom, aValue);                   \
+    *aValue = GetBoolAttr(nsGkAtoms::_atom);                          \
+    return NS_OK;                                                     \
   }                                                                   \
   NS_IMETHODIMP                                                       \
   _class::Set##_method(bool aValue)                                 \
   {                                                                   \
     return SetBoolAttr(nsGkAtoms::_atom, aValue);                   \
   }
 
 /**
@@ -1032,22 +1042,23 @@ PR_STATIC_ASSERT(ELEMENT_TYPE_SPECIFIC_B
  */
 #define NS_IMPL_INT_ATTR(_class, _method, _atom)                    \
   NS_IMPL_INT_ATTR_DEFAULT_VALUE(_class, _method, _atom, 0)
 
 #define NS_IMPL_INT_ATTR_DEFAULT_VALUE(_class, _method, _atom, _default)  \
   NS_IMETHODIMP                                                           \
   _class::Get##_method(int32_t* aValue)                                   \
   {                                                                       \
-    return GetIntAttr(nsGkAtoms::_atom, _default, aValue);              \
+    *aValue = GetIntAttr(nsGkAtoms::_atom, _default);                     \
+    return NS_OK;                                                         \
   }                                                                       \
   NS_IMETHODIMP                                                           \
   _class::Set##_method(int32_t aValue)                                    \
   {                                                                       \
-    return SetIntAttr(nsGkAtoms::_atom, aValue);                        \
+    return SetIntAttr(nsGkAtoms::_atom, aValue);                          \
   }
 
 /**
  * A macro to implement the getter and setter for a given unsigned integer
  * valued content property. The method uses GetUnsignedIntAttr and
  * SetUnsignedIntAttr methods.
  */
 #define NS_IMPL_UINT_ATTR(_class, _method, _atom)                         \
@@ -1150,17 +1161,18 @@ PR_STATIC_ASSERT(ELEMENT_TYPE_SPECIFIC_B
  */
 #define NS_IMPL_NON_NEGATIVE_INT_ATTR(_class, _method, _atom)             \
   NS_IMPL_NON_NEGATIVE_INT_ATTR_DEFAULT_VALUE(_class, _method, _atom, -1)
 
 #define NS_IMPL_NON_NEGATIVE_INT_ATTR_DEFAULT_VALUE(_class, _method, _atom, _default)  \
   NS_IMETHODIMP                                                           \
   _class::Get##_method(int32_t* aValue)                                   \
   {                                                                       \
-    return GetIntAttr(nsGkAtoms::_atom, _default, aValue);                \
+    *aValue = GetIntAttr(nsGkAtoms::_atom, _default);                     \
+    return NS_OK;                                                         \
   }                                                                       \
   NS_IMETHODIMP                                                           \
   _class::Set##_method(int32_t aValue)                                    \
   {                                                                       \
     if (aValue < 0) {                                                     \
       return NS_ERROR_DOM_INDEX_SIZE_ERR;                                 \
     }                                                                     \
     return SetIntAttr(nsGkAtoms::_atom, aValue);                          \
--- a/content/html/content/src/nsGenericHTMLFrameElement.cpp
+++ b/content/html/content/src/nsGenericHTMLFrameElement.cpp
@@ -320,18 +320,30 @@ nsGenericHTMLFrameElement::GetAppManifes
 
   // At the moment, you can't be an app without being a browser.
   bool isBrowser = false;
   GetReallyIsBrowser(&isBrowser);
   if (!isBrowser) {
     return NS_OK;
   }
 
-  // TODO: We surely need a permissions check here, particularly once we no
-  // longer rely on the mozbrowser permission check.
+  // Check permission.
+  nsIPrincipal *principal = NodePrincipal();
+  nsCOMPtr<nsIPermissionManager> permMgr =
+    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+  NS_ENSURE_STATE(permMgr);
+
+  uint32_t permission = nsIPermissionManager::DENY_ACTION;
+  nsresult rv = permMgr->TestPermissionFromPrincipal(principal,
+                                                     "embed-apps",
+                                                     &permission);
+  NS_ENSURE_SUCCESS(rv, NS_OK);
+  if (permission != nsIPermissionManager::ALLOW_ACTION) {
+    return NS_OK;
+  }
 
   nsAutoString manifestURL;
   GetAttr(kNameSpaceID_None, nsGkAtoms::mozapp, manifestURL);
   if (manifestURL.IsEmpty()) {
     return NS_OK;
   }
 
   nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
--- a/content/html/content/src/nsHTMLAnchorElement.cpp
+++ b/content/html/content/src/nsHTMLAnchorElement.cpp
@@ -109,25 +109,31 @@ public:
   virtual void OnDNSPrefetchRequested();
   virtual bool HasDeferredDNSPrefetchRequest();
 
 protected:
   virtual void GetItemValueText(nsAString& text);
   virtual void SetItemValueText(const nsAString& text);
 };
 
-// Indicates that a DNS Prefetch has been requested from this Anchor elem
-#define HTML_ANCHOR_DNS_PREFETCH_REQUESTED \
-  (1 << ELEMENT_TYPE_SPECIFIC_BITS_OFFSET)
-// Indicates that a DNS Prefetch was added to the deferral queue
-#define HTML_ANCHOR_DNS_PREFETCH_DEFERRED \
-  (1 << (ELEMENT_TYPE_SPECIFIC_BITS_OFFSET+1))
+#define ANCHOR_ELEMENT_FLAG_BIT(n_) NODE_FLAG_BIT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + (n_))
+
+// Anchor element specific bits
+enum {
+  // Indicates that a DNS Prefetch has been requested from this Anchor elem
+  HTML_ANCHOR_DNS_PREFETCH_REQUESTED =    ANCHOR_ELEMENT_FLAG_BIT(0),
+
+  // Indicates that a DNS Prefetch was added to the deferral queue
+  HTML_ANCHOR_DNS_PREFETCH_DEFERRED =     ANCHOR_ELEMENT_FLAG_BIT(1)
+};
 
 // Make sure we have enough space for those bits
-PR_STATIC_ASSERT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET+1 < 32);
+PR_STATIC_ASSERT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 1 < 32);
+
+#undef ANCHOR_ELEMENT_FLAG_BIT
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Anchor)
 
 nsHTMLAnchorElement::nsHTMLAnchorElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo)
   , Link(this)
 {
 }
--- a/content/html/content/src/nsHTMLScriptElement.cpp
+++ b/content/html/content/src/nsHTMLScriptElement.cpp
@@ -212,21 +212,18 @@ NS_IMPL_URI_ATTR(nsHTMLScriptElement, Sr
 NS_IMPL_STRING_ATTR(nsHTMLScriptElement, Type, type)
 NS_IMPL_STRING_ATTR(nsHTMLScriptElement, HtmlFor, _for)
 NS_IMPL_STRING_ATTR(nsHTMLScriptElement, Event, event)
 NS_IMPL_STRING_ATTR(nsHTMLScriptElement, CrossOrigin, crossorigin)
 
 nsresult
 nsHTMLScriptElement::GetAsync(bool* aValue)
 {
-  if (mForceAsync) {
-    *aValue = true;
-    return NS_OK;
-  }
-  return GetBoolAttr(nsGkAtoms::async, aValue);
+  *aValue = mForceAsync || GetBoolAttr(nsGkAtoms::async);
+  return NS_OK;
 }
 
 nsresult
 nsHTMLScriptElement::SetAsync(bool aValue)
 {
   mForceAsync = false;
   return SetBoolAttr(nsGkAtoms::async, aValue);
 }
--- a/content/media/MediaResource.cpp
+++ b/content/media/MediaResource.cpp
@@ -597,17 +597,17 @@ nsresult ChannelMediaResource::OpenChann
 
     nsCOMPtr<nsIStreamListener> listener = mListener.get();
 
     // Ensure that if we're loading cross domain, that the server is sending
     // an authorizing Access-Control header.
     nsHTMLMediaElement* element = mDecoder->GetMediaElement();
     NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
     if (element->ShouldCheckAllowOrigin()) {
-      nsCORSListenerProxy* crossSiteListener =
+      nsRefPtr<nsCORSListenerProxy> crossSiteListener =
         new nsCORSListenerProxy(mListener,
                                 element->NodePrincipal(),
                                 false);
       nsresult rv = crossSiteListener->Init(mChannel);
       listener = crossSiteListener;
       NS_ENSURE_TRUE(crossSiteListener, NS_ERROR_OUT_OF_MEMORY);
       NS_ENSURE_SUCCESS(rv, rv);
     } else {
--- a/content/media/webaudio/AudioBufferSourceNode.cpp
+++ b/content/media/webaudio/AudioBufferSourceNode.cpp
@@ -5,25 +5,37 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "AudioBufferSourceNode.h"
 #include "mozilla/dom/AudioBufferSourceNodeBinding.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_ISUPPORTS_INHERITED0(AudioBufferSourceNode, AudioSourceNode)
+NS_IMPL_CYCLE_COLLECTION_INHERITED_1(AudioBufferSourceNode, AudioSourceNode, mBuffer)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(AudioBufferSourceNode)
+NS_INTERFACE_MAP_END_INHERITING(AudioSourceNode)
+
+NS_IMPL_ADDREF_INHERITED(AudioBufferSourceNode, AudioSourceNode)
+NS_IMPL_RELEASE_INHERITED(AudioBufferSourceNode, AudioSourceNode)
 
 AudioBufferSourceNode::AudioBufferSourceNode(AudioContext* aContext)
   : AudioSourceNode(aContext)
 {
 }
 
 JSObject*
 AudioBufferSourceNode::WrapObject(JSContext* aCx, JSObject* aScope,
                                   bool* aTriedToWrap)
 {
   return AudioBufferSourceNodeBinding::Wrap(aCx, aScope, this, aTriedToWrap);
 }
 
+void
+AudioBufferSourceNode::SetBuffer(AudioBuffer* aBuffer)
+{
+  mBuffer = aBuffer;
+}
+
 }
 }
 
--- a/content/media/webaudio/AudioBufferSourceNode.h
+++ b/content/media/webaudio/AudioBufferSourceNode.h
@@ -2,30 +2,40 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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/. */
 
 #pragma once
 
 #include "AudioSourceNode.h"
+#include "AudioBuffer.h"
 
 namespace mozilla {
 namespace dom {
 
 class AudioBufferSourceNode : public AudioSourceNode
 {
 public:
   explicit AudioBufferSourceNode(AudioContext* aContext);
 
   NS_DECL_ISUPPORTS_INHERITED
-
-  void NoteOn(double) { /* no-op for now */ }
-  void NoteOff(double) { /* no-op for now */ }
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AudioBufferSourceNode, AudioSourceNode)
 
   virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope,
                                bool* aTriedToWrap);
 
+  void Start(double) { /* no-op for now */ }
+  void Stop(double) { /* no-op for now */ }
+
+  AudioBuffer* GetBuffer() const
+  {
+    return mBuffer;
+  }
+  void SetBuffer(AudioBuffer* aBuffer);
+
+private:
+  nsRefPtr<AudioBuffer> mBuffer;
 };
 
 }
 }
 
--- a/content/media/webaudio/AudioDestinationNode.h
+++ b/content/media/webaudio/AudioDestinationNode.h
@@ -18,13 +18,22 @@ class AudioDestinationNode : public Audi
 public:
   explicit AudioDestinationNode(AudioContext* aContext);
 
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope,
                                bool* aTriedToWrap);
 
+  virtual uint32_t MaxNumberOfInputs() const MOZ_FINAL MOZ_OVERRIDE
+  {
+    return 1;
+  }
+  virtual uint32_t MaxNumberOfOutputs() const MOZ_FINAL MOZ_OVERRIDE
+  {
+    return 0;
+  }
+
 };
 
 }
 }
 
--- a/content/media/webaudio/AudioNode.cpp
+++ b/content/media/webaudio/AudioNode.cpp
@@ -2,30 +2,115 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 "AudioNode.h"
 #include "AudioContext.h"
 #include "nsContentUtils.h"
+#include "mozilla/ErrorResult.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(AudioNode, mContext)
+template <typename T>
+static void
+TraverseElements(nsCycleCollectionTraversalCallback& cb,
+                 const nsTArray<T>& array,
+                 const char* name)
+{
+  for (uint32_t i = 0, length = array.Length(); i < length; ++i) {
+    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, name);
+    AudioNode* node = array[i].get();
+    cb.NoteXPCOMChild(node);
+  }
+}
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(AudioNode)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AudioNode)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContext)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mInputs)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mOutputs)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AudioNode)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
+  TraverseElements(cb, tmp->mInputs, "mInputs[i]");
+  TraverseElements(cb, tmp->mOutputs, "mOutputs[i]");
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(AudioNode)
+
 NS_IMPL_CYCLE_COLLECTING_ADDREF(AudioNode)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(AudioNode)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AudioNode)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 AudioNode::AudioNode(AudioContext* aContext)
   : mContext(aContext)
 {
   MOZ_ASSERT(aContext);
   SetIsDOMBinding();
 }
 
+void
+AudioNode::Connect(AudioNode& aDestination, uint32_t aOutput,
+                   uint32_t aInput, ErrorResult& aRv)
+{
+  if (aOutput >= MaxNumberOfOutputs() ||
+      aInput >= aDestination.MaxNumberOfInputs()) {
+    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    return;
+  }
+
+  if (Context() != aDestination.Context()) {
+    aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+    return;
+  }
+
+  // XXX handle cycle detection per spec
+
+  Output output(&aDestination, aInput);
+  mOutputs.EnsureLengthAtLeast(aOutput + 1);
+  mOutputs.ReplaceElementAt(aOutput, output);
+  Input input(this, aOutput);
+  aDestination.mInputs.EnsureLengthAtLeast(aInput + 1);
+  aDestination.mInputs.ReplaceElementAt(aInput, input);
+}
+
+void
+AudioNode::Disconnect(uint32_t aOutput, ErrorResult& aRv)
+{
+  if (aOutput >= NumberOfOutputs()) {
+    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    return;
+  }
+
+  // We do a copy of the objects to AddRef source and destination
+  // objects so that they don't go away before we're done here.
+  const Output output = mOutputs[aOutput];
+  if (!output) {
+    aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+    return;
+  }
+  const Input input = output.mDestination->mInputs[output.mInput];
+
+  MOZ_ASSERT(Context() == output.mDestination->Context());
+  MOZ_ASSERT(aOutput == input.mOutput);
+
+  if (!input || input.mSource != this) {
+    aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+    return;
+  }
+
+  output.mDestination->mInputs.ReplaceElementAt(output.mInput, Input());
+  mOutputs.ReplaceElementAt(input.mOutput, Output());
+}
+
 }
 }
 
--- a/content/media/webaudio/AudioNode.h
+++ b/content/media/webaudio/AudioNode.h
@@ -6,21 +6,25 @@
 
 #pragma once
 
 #include "nsWrapperCache.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/Attributes.h"
 #include "EnableWebAudioCheck.h"
 #include "nsAutoPtr.h"
+#include "nsTArray.h"
 #include "AudioContext.h"
 
 struct JSContext;
 
 namespace mozilla {
+
+class ErrorResult;
+
 namespace dom {
 
 class AudioNode : public nsISupports,
                   public nsWrapperCache,
                   public EnableWebAudioCheck
 {
 public:
   explicit AudioNode(AudioContext* aContext);
@@ -35,21 +39,92 @@ public:
   }
 
   AudioContext* Context() const
   {
     return mContext;
   }
 
   void Connect(AudioNode& aDestination, uint32_t aOutput,
-               uint32_t aInput)
-  { /* no-op for now */ }
+               uint32_t aInput, ErrorResult& aRv);
+
+  void Disconnect(uint32_t aOutput, ErrorResult& aRv);
+
+  uint32_t NumberOfInputs() const
+  {
+    return mInputs.Length();
+  }
+  uint32_t NumberOfOutputs() const
+  {
+    return mOutputs.Length();
+  }
+
+  // The following two virtual methods must be implemented by each node type
+  // to provide the maximum number of input and outputs they accept.
+  virtual uint32_t MaxNumberOfInputs() const = 0;
+  virtual uint32_t MaxNumberOfOutputs() const = 0;
+
+  struct Output {
+    enum { InvalidIndex = 0xffffffff };
+    Output()
+      : mInput(InvalidIndex)
+    {
+    }
+    Output(AudioNode* aDestination, uint32_t aInput)
+      : mDestination(aDestination),
+        mInput(aInput)
+    {
+    }
+
+    // Check whether the slot is valid
+    typedef void**** ConvertibleToBool;
+    operator ConvertibleToBool() const {
+      return ConvertibleToBool(mDestination && mInput != InvalidIndex);
+    }
 
-  void Disconnect(uint32_t aOutput)
-  { /* no-op for now */ }
+    // Needed for the CC traversal
+    AudioNode* get() const {
+      return mDestination;
+    }
+
+    nsRefPtr<AudioNode> mDestination;
+    // This is an index into mDestination->mInputs which specifies the Input
+    // object corresponding to this Output node.
+    const uint32_t mInput;
+  };
+  struct Input {
+    enum { InvalidIndex = 0xffffffff };
+    Input()
+      : mOutput(InvalidIndex)
+    {
+    }
+    Input(AudioNode* aSource, uint32_t aOutput)
+      : mSource(aSource),
+        mOutput(aOutput)
+    {
+    }
+
+    // Check whether the slot is valid
+    typedef void**** ConvertibleToBool;
+    operator ConvertibleToBool() const {
+      return ConvertibleToBool(mSource && mOutput != InvalidIndex);
+    }
+
+    // Needed for the CC traversal
+    AudioNode* get() const {
+      return mSource;
+    }
+
+    nsRefPtr<AudioNode> mSource;
+    // This is an index into mSource->mOutputs which specifies the Output
+    // object corresponding to this Input node.
+    const uint32_t mOutput;
+  };
 
 private:
   nsRefPtr<AudioContext> mContext;
+  nsTArray<Input> mInputs;
+  nsTArray<Output> mOutputs;
 };
 
 }
 }
 
--- a/content/media/webaudio/AudioSourceNode.h
+++ b/content/media/webaudio/AudioSourceNode.h
@@ -13,13 +13,22 @@ namespace dom {
 
 class AudioSourceNode : public AudioNode
 {
 public:
   explicit AudioSourceNode(AudioContext* aContext);
 
   NS_DECL_ISUPPORTS_INHERITED
 
+  virtual uint32_t MaxNumberOfInputs() const MOZ_FINAL MOZ_OVERRIDE
+  {
+    return 0;
+  }
+  virtual uint32_t MaxNumberOfOutputs() const MOZ_FINAL MOZ_OVERRIDE
+  {
+    return 1;
+  }
+
 };
 
 }
 }
 
--- a/content/media/webaudio/test/Makefile.in
+++ b/content/media/webaudio/test/Makefile.in
@@ -8,11 +8,13 @@ srcdir         := @srcdir@
 VPATH          := @srcdir@
 relativesrcdir := @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_FILES := \
   test_AudioBuffer.html \
   test_AudioContext.html \
+  test_badConnect.html \
+  test_singleSourceDest.html \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_badConnect.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test whether we can create an AudioContext interface</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+function expectException(func, exceptionCode) {
+  var threw = false;
+  try {
+    func();
+  } catch (ex) {
+    threw = true;
+    ok(ex instanceof DOMException, "Expect a DOM exception");
+    ok(ex.code, exceptionCode, "Expect the correct exception code");
+  }
+  ok(threw, "The exception was thrown");
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+  SpecialPowers.setBoolPref("media.webaudio.enabled", true);
+
+  var context1 = new mozAudioContext();
+  var context2 = new mozAudioContext();
+
+  var destination1 = context1.destination;
+  var destination2 = context2.destination;
+
+  isnot(destination1, destination2, "Destination nodes should not be the same");
+  isnot(destination1.context, destination2.context, "Destination nodes should not have the same context");
+
+  var source1 = context1.createBufferSource();
+
+  expectException(function() {
+    source1.connect(destination1, 1);
+  }, DOMException.INDEX_SIZE_ERR);
+  expectException(function() {
+    source1.connect(destination1, 0, 1);
+  }, DOMException.INDEX_SIZE_ERR);
+  expectException(function() {
+    source1.connect(destination2);
+  }, DOMException.SYNTAX_ERR);
+
+  source1.connect(destination1);
+
+  expectException(function() {
+    source1.disconnect(1);
+  }, DOMException.INDEX_SIZE_ERR);
+
+  SpecialPowers.clearUserPref("media.webaudio.enabled");
+  SimpleTest.finish();
+});
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_singleSourceDest.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test whether we can create an AudioContext interface</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+  SpecialPowers.setBoolPref("media.webaudio.enabled", true);
+
+  var context = new mozAudioContext();
+  var buffer = context.createBuffer(1, 2048, 44100);
+  for (var i = 0; i < 2048; ++i) {
+    buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / 44100);
+  }
+
+  var destination = context.destination;
+  is(destination.context, context, "Destination node has proper context");
+  is(destination.context, context, "Destination node has proper context");
+  is(destination.numberOfInputs, 0, "Destination node has 0 inputs");
+  is(destination.numberOfOutputs, 0, "Destination node has 0 outputs");
+
+  var source = context.createBufferSource();
+  is(source.context, context, "Source node has proper context");
+  is(source.numberOfInputs, 0, "Source node has 0 inputs");
+  is(source.numberOfOutputs, 0, "Source node has 0 outputs");
+  ok(!source.buffer, "Source node should not have a buffer when it's created");
+
+  source.buffer = buffer;
+  ok(source.buffer, "Source node should have a buffer now");
+
+  source.connect(destination);
+
+  is(source.numberOfInputs, 0, "Source node has 0 inputs");
+  is(source.numberOfOutputs, 1, "Source node has 0 outputs");
+  is(destination.numberOfInputs, 1, "Destination node has 0 inputs");
+  is(destination.numberOfOutputs, 0, "Destination node has 0 outputs");
+
+  source.start(0);
+  SimpleTest.executeSoon(function() {
+    source.stop(0);
+    source.disconnect();
+
+    SpecialPowers.clearUserPref("media.webaudio.enabled");
+    SimpleTest.finish();
+  });
+});
+
+</script>
+</pre>
+</body>
+</html>
--- a/content/media/webrtc/MediaEngine.h
+++ b/content/media/webrtc/MediaEngine.h
@@ -16,16 +16,23 @@ namespace mozilla {
  * must implement a concrete class that will map these classes and methods
  * to the appropriate backend. For example, on Desktop platforms, these will
  * correspond to equivalent webrtc (GIPS) calls, and on B2G they will map to
  * a Gonk interface.
  */
 class MediaEngineVideoSource;
 class MediaEngineAudioSource;
 
+enum MediaEngineState {
+  kAllocated,
+  kStarted,
+  kStopped,
+  kReleased
+};
+
 class MediaEngine
 {
 public:
   virtual ~MediaEngine() {};
 
   /* Populate an array of video sources in the nsTArray. Also include devices
    * that are currently unavailable. */
   virtual void EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSource> >*) = 0;
--- a/content/media/webrtc/MediaEngineDefault.h
+++ b/content/media/webrtc/MediaEngineDefault.h
@@ -24,24 +24,16 @@ namespace mozilla {
 namespace layers {
 class ImageContainer;
 class PlanarYCbCrImage;
 }
 
 /**
  * The default implementation of the MediaEngine interface.
  */
-
-enum DefaultEngineState {
-  kAllocated,
-  kStarted,
-  kStopped,
-  kReleased
-};
-
 class MediaEngineDefaultVideoSource : public nsITimerCallback,
                                       public MediaEngineVideoSource
 {
 public:
   MediaEngineDefaultVideoSource();
   ~MediaEngineDefaultVideoSource();
 
   virtual void GetName(nsAString&);
@@ -58,17 +50,17 @@ public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSITIMERCALLBACK
 
 protected:
   TrackID mTrackID;
   nsCOMPtr<nsITimer> mTimer;
   nsRefPtr<layers::ImageContainer> mImageContainer;
 
-  DefaultEngineState mState;
+  MediaEngineState mState;
   SourceMediaStream* mSource;
   layers::PlanarYCbCrImage* mImage;
 };
 
 class MediaEngineDefaultAudioSource : public nsITimerCallback,
                                       public MediaEngineAudioSource
 {
 public:
@@ -87,17 +79,17 @@ public:
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSITIMERCALLBACK
 
 protected:
   TrackID mTrackID;
   nsCOMPtr<nsITimer> mTimer;
 
-  DefaultEngineState mState;
+  MediaEngineState mState;
   SourceMediaStream* mSource;
 };
 
 class MediaEngineDefault : public MediaEngine
 {
 public:
   MediaEngineDefault() {
     mVSource = new MediaEngineDefaultVideoSource();
--- a/content/media/webrtc/MediaEngineWebRTC.h
+++ b/content/media/webrtc/MediaEngineWebRTC.h
@@ -43,24 +43,16 @@
 #include "video_engine/include/vie_file.h"
 
 
 namespace mozilla {
 
 /**
  * The WebRTC implementation of the MediaEngine interface.
  */
-
-enum WebRTCEngineState {
-  kAllocated,
-  kStarted,
-  kStopped,
-  kReleased
-};
-
 class MediaEngineWebRTCVideoSource : public MediaEngineVideoSource,
                                      public webrtc::ExternalRenderer,
                                      public nsRunnable
 {
 public:
   // ViEExternalRenderer.
   virtual int FrameSizeChange(unsigned int, unsigned int, unsigned int);
   virtual int DeliverFrame(unsigned char*, int, uint32_t, int64_t);
@@ -114,17 +106,17 @@ private:
   webrtc::ViECapture* mViECapture;
   webrtc::ViERender* mViERender;
   webrtc::CaptureCapability mCaps; // Doesn't work on OS X.
 
   int mCapIndex;
   int mWidth, mHeight;
   TrackID mTrackID;
 
-  WebRTCEngineState mState;
+  MediaEngineState mState;
   mozilla::ReentrantMonitor mMonitor; // Monitor for processing WebRTC frames.
   SourceMediaStream* mSource;
 
   int mFps; // Track rate (30 fps by default)
   bool mInitDone;
   bool mInSnapshotMode;
   nsString* mSnapshotPath;
 
@@ -184,17 +176,17 @@ private:
   webrtc::VoEExternalMedia* mVoERender;
 
   mozilla::ReentrantMonitor mMonitor;
 
   int mCapIndex;
   int mChannel;
   TrackID mTrackID;
   bool mInitDone;
-  WebRTCEngineState mState;
+  MediaEngineState mState;
 
   nsString mDeviceName;
   nsString mDeviceUUID;
 
   SourceMediaStream* mSource;
 };
 
 class MediaEngineWebRTC : public MediaEngine
--- a/content/xbl/src/nsXBLDocumentInfo.cpp
+++ b/content/xbl/src/nsXBLDocumentInfo.cpp
@@ -279,18 +279,18 @@ nsXBLDocGlobalObject::EnsureScriptEnviro
   // nsJSEnvironment set the error reporter to NS_ScriptErrorReporter so
   // we must apparently override that with our own (although it isn't clear 
   // why - see bug 339647)
   JS_SetErrorReporter(cx, XBL_ProtoErrorReporter);
 
   nsIPrincipal *principal = GetPrincipal();
   JSCompartment *compartment;
 
-  rv = xpc_CreateGlobalObject(cx, &gSharedGlobalClass, principal, nullptr,
-                              false, &mJSObject, &compartment);
+  rv = xpc::CreateGlobalObject(cx, &gSharedGlobalClass, principal, false,
+                               &mJSObject, &compartment);
   NS_ENSURE_SUCCESS(rv, NS_OK);
 
   // Set the location information for the new global, so that tools like
   // about:memory may use that information
   nsIURI *ownerURI = mGlobalObjectOwner->DocumentURI();
   xpc::SetLocationForGlobal(mJSObject, ownerURI);
 
   ::JS_SetGlobalObject(cx, mJSObject);
--- a/content/xbl/src/nsXBLProtoImplMethod.cpp
+++ b/content/xbl/src/nsXBLProtoImplMethod.cpp
@@ -201,17 +201,18 @@ nsXBLProtoImplMethod::CompileMember(nsIS
   nsresult rv = aContext->CompileFunction(aClassObject,
                                           cname,
                                           paramCount,
                                           const_cast<const char**>(args),
                                           body, 
                                           functionUri.get(),
                                           uncompiledMethod->mBodyText.GetLineNumber(),
                                           JSVERSION_LATEST,
-                                          true,
+                                          /* aShared = */ true,
+                                          /* aIsXBL = */ true,
                                           &methodObject);
 
   // Destroy our uncompiled method and delete our arg list.
   delete uncompiledMethod;
   delete [] args;
   if (NS_FAILED(rv)) {
     SetUncompiledMethod(nullptr);
     return rv;
--- a/content/xbl/src/nsXBLProtoImplProperty.cpp
+++ b/content/xbl/src/nsXBLProtoImplProperty.cpp
@@ -212,17 +212,18 @@ nsXBLProtoImplProperty::CompileMember(ns
                                      NS_LITERAL_CSTRING("get_") +
                                      NS_ConvertUTF16toUTF8(mName),
                                      0,
                                      nullptr,
                                      getter, 
                                      functionUri.get(),
                                      mGetterText->GetLineNumber(),
                                      JSVERSION_LATEST,
-                                     true,
+                                     /* aShared = */ true,
+                                     /* aIsXBL = */ true,
                                      &getterObject);
 
       // Make sure we free mGetterText here before setting mJSGetterObject, since
       // that'll overwrite mGetterText
       delete mGetterText;
       deletedGetter = true;
       mJSGetterObject = getterObject;
     
@@ -262,17 +263,18 @@ nsXBLProtoImplProperty::CompileMember(ns
                                      NS_LITERAL_CSTRING("set_") +
                                      NS_ConvertUTF16toUTF8(mName),
                                      1,
                                      gPropertyArgs,
                                      setter, 
                                      functionUri.get(),
                                      mSetterText->GetLineNumber(),
                                      JSVERSION_LATEST,
-                                     true,
+                                     /* aShared = */ true,
+                                     /* aIsXBL = */ true,
                                      &setterObject);
 
       // Make sure we free mSetterText here before setting mJSGetterObject, since
       // that'll overwrite mSetterText
       delete mSetterText;
       deletedSetter = true;
       mJSSetterObject = setterObject;
 
--- a/content/xbl/src/nsXBLPrototypeHandler.cpp
+++ b/content/xbl/src/nsXBLPrototypeHandler.cpp
@@ -335,17 +335,19 @@ nsXBLPrototypeHandler::EnsureEventHandle
   uint32_t argCount;
   const char **argNames;
   nsContentUtils::GetEventArgNames(kNameSpaceID_XBL, aName, &argCount,
                                    &argNames);
   nsresult rv = aBoundContext->CompileEventHandler(aName, argCount, argNames,
                                                    handlerText,
                                                    bindingURI.get(), 
                                                    mLineNumber,
-                                                   JSVERSION_LATEST, aHandler);
+                                                   JSVERSION_LATEST,
+                                                   /* aIsXBL = */ true,
+                                                   aHandler);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (pWindow) {
     pWindow->CacheXBLPrototypeHandler(this, aHandler);
   }
 
   return NS_OK;
 }
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -1371,18 +1371,17 @@ nsXULElement::LoadSrc()
         return NS_OK;
     }
     if (!IsInDoc() ||
         !OwnerDoc()->GetRootElement() ||
         OwnerDoc()->GetRootElement()->
             NodeInfo()->Equals(nsGkAtoms::overlay, kNameSpaceID_XUL)) {
         return NS_OK;
     }
-    nsXULSlots* slots = static_cast<nsXULSlots*>(GetSlots());
-    NS_ENSURE_TRUE(slots, NS_ERROR_OUT_OF_MEMORY);
+    nsXULSlots* slots = static_cast<nsXULSlots*>(Slots());
     if (!slots->mFrameLoader) {
         // false as the last parameter so that xul:iframe/browser/editor
         // session history handling works like dynamic html:iframes.
         // Usually xul elements are used in chrome, which doesn't have
         // session history at all.
         slots->mFrameLoader = nsFrameLoader::Create(this, false);
         NS_ENSURE_TRUE(slots->mFrameLoader, NS_OK);
     }
--- a/content/xul/content/src/nsXULElement.h
+++ b/content/xul/content/src/nsXULElement.h
@@ -312,21 +312,28 @@ public:
 ////////////////////////////////////////////////////////////////////////
 
 /**
 
   The XUL element.
 
  */
 
-#define XUL_ELEMENT_TEMPLATE_GENERATED (1 << ELEMENT_TYPE_SPECIFIC_BITS_OFFSET)
+#define XUL_ELEMENT_FLAG_BIT(n_) NODE_FLAG_BIT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + (n_))
+
+// XUL element specific bits
+enum {
+  XUL_ELEMENT_TEMPLATE_GENERATED =        XUL_ELEMENT_FLAG_BIT(0)
+};
 
 // Make sure we have space for our bit
 PR_STATIC_ASSERT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET < 32);
 
+#undef XUL_ELEMENT_FLAG_BIT
+
 class nsScriptEventHandlerOwnerTearoff;
 
 class nsXULElement : public nsStyledElement, public nsIDOMXULElement
 {
 public:
 
     /** Typesafe, non-refcounting cast from nsIContent.  Cheaper than QI. **/
     static nsXULElement* FromContent(nsIContent *aContent)
--- a/content/xul/document/src/nsXULPrototypeDocument.cpp
+++ b/content/xul/document/src/nsXULPrototypeDocument.cpp
@@ -751,18 +751,18 @@ nsXULPDGlobalObject::EnsureScriptEnviron
   {
     JSContext *cx = ctxNew->GetNativeContext();
     JSAutoRequest ar(cx);
 
     nsIPrincipal *principal = GetPrincipal();
     JSObject *newGlob;
     JSCompartment *compartment;
 
-    rv = xpc_CreateGlobalObject(cx, &gSharedGlobalClass, principal, nullptr,
-                                false, &newGlob, &compartment);
+    rv = xpc::CreateGlobalObject(cx, &gSharedGlobalClass, principal, false,
+                                 &newGlob, &compartment);
     NS_ENSURE_SUCCESS(rv, NS_OK);
 
     ::JS_SetGlobalObject(cx, newGlob);
 
     // Add an owning reference from JS back to us. This'll be
     // released when the JSObject is finalized.
     ::JS_SetPrivate(newGlob, this);
     NS_ADDREF(this);
--- a/content/xul/templates/src/nsXULTemplateQueryProcessorRDF.cpp
+++ b/content/xul/templates/src/nsXULTemplateQueryProcessorRDF.cpp
@@ -689,19 +689,19 @@ nsXULTemplateQueryProcessorRDF::CompareR
             if (r) {
                 PRTime ldate, rdate;
                 l->GetValue(&ldate);
                 r->GetValue(&rdate);
 
                 int64_t delta;
                 LL_SUB(delta, ldate, rdate);
 
-                if (LL_IS_ZERO(delta))
+                if (delta == 0)
                     *aResult = 0;
-                else if (LL_GE_ZERO(delta))
+                else if (delta >= 0)
                     *aResult = 1;
                 else
                     *aResult = -1;
             }
 
             return NS_OK;
         }
     }
--- a/docshell/base/nsWebNavigationInfo.cpp
+++ b/docshell/base/nsWebNavigationInfo.cpp
@@ -5,32 +5,31 @@
 
 #include "nsWebNavigationInfo.h"
 #include "nsIWebNavigation.h"
 #include "nsString.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIDocumentLoaderFactory.h"
 #include "nsIPluginHost.h"
 #include "nsContentUtils.h"
+#include "imgLoader.h"
 
 NS_IMPL_ISUPPORTS1(nsWebNavigationInfo, nsIWebNavigationInfo)
 
 #define CONTENT_DLF_CONTRACT "@mozilla.org/content/document-loader-factory;1"
 #define PLUGIN_DLF_CONTRACT \
     "@mozilla.org/content/plugin/document-loader-factory;1"
 
 nsresult
 nsWebNavigationInfo::Init()
 {
   nsresult rv;
   mCategoryManager = do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  mImgLoader = nsContentUtils::GetImgLoaderForChannel(nullptr);
-
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWebNavigationInfo::IsTypeSupported(const nsACString& aType,
                                      nsIWebNavigation* aWebNav,
                                      uint32_t* aIsTypeSupported)
 {
@@ -92,19 +91,20 @@ nsWebNavigationInfo::IsTypeSupportedInte
     *aIsSupported = nsIWebNavigationInfo::PLUGIN;
     break;
 
   case nsContentUtils::TYPE_UNKNOWN:
     *aIsSupported = nsIWebNavigationInfo::OTHER;
     break;
 
   case nsContentUtils::TYPE_CONTENT:
-    bool isImage = false;
-    mImgLoader->SupportImageWithMimeType(aType.get(), &isImage);
-    if (isImage) {
+    // XXXbz we only need this because images register for the same
+    // contractid as documents, so we can't tell them apart based on
+    // contractid.
+    if (imgLoader::SupportImageWithMimeType(aType.get())) {
       *aIsSupported = nsIWebNavigationInfo::IMAGE;
     }
     else {
       *aIsSupported = nsIWebNavigationInfo::OTHER;
     }
     break;
   }
 
--- a/docshell/base/nsWebNavigationInfo.h
+++ b/docshell/base/nsWebNavigationInfo.h
@@ -4,17 +4,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsWebNavigationInfo_h__
 #define nsWebNavigationInfo_h__
 
 #include "nsIWebNavigationInfo.h"
 #include "nsCOMPtr.h"
 #include "nsICategoryManager.h"
-#include "imgILoader.h"
 #include "nsStringFwd.h"
 #include "mozilla/Attributes.h"
 
 // Class ID for webnavigationinfo
 #define NS_WEBNAVIGATION_INFO_CID \
  { 0xf30bc0a2, 0x958b, 0x4287,{0xbf, 0x62, 0xce, 0x38, 0xba, 0x0c, 0x81, 0x1e}}
 
 class nsWebNavigationInfo MOZ_FINAL : public nsIWebNavigationInfo
@@ -32,15 +31,11 @@ private:
   ~nsWebNavigationInfo() {}
   
   // Check whether aType is supported.  If this method throws, the
   // value of aIsSupported is not changed.
   nsresult IsTypeSupportedInternal(const nsCString& aType,
                                    uint32_t* aIsSupported);
   
   nsCOMPtr<nsICategoryManager> mCategoryManager;
-  // XXXbz we only need this because images register for the same
-  // contractid as documents, so we can't tell them apart based on
-  // contractid.
-  nsCOMPtr<imgILoader> mImgLoader;
 };
 
 #endif  // nsWebNavigationInfo_h__
--- a/docshell/shistory/src/nsSHistory.cpp
+++ b/docshell/shistory/src/nsSHistory.cpp
@@ -279,23 +279,23 @@ nsSHistory::CalcMaxTotalViewers()
   // 128  Mb       2
   // 256  Mb       3
   // 512  Mb       5
   // 1024 Mb       8
   // 2048 Mb       8
   // 4096 Mb       8
   uint64_t bytes = PR_GetPhysicalMemorySize();
 
-  if (LL_IS_ZERO(bytes))
+  if (bytes == 0)
     return 0;
 
   // Conversion from unsigned int64 to double doesn't work on all platforms.
   // We need to truncate the value at INT64_MAX to make sure we don't
   // overflow.
-  if (LL_CMP(bytes, >, INT64_MAX))
+  if (bytes > INT64_MAX)
     bytes = INT64_MAX;
 
   uint64_t kbytes;
   LL_SHR(kbytes, bytes, 10);
 
   double kBytesD;
   LL_L2D(kBytesD, (int64_t) kbytes);
 
--- a/dom/apps/src/AppsUtils.jsm
+++ b/dom/apps/src/AppsUtils.jsm
@@ -9,17 +9,17 @@ const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 // Shared code for AppsServiceChild.jsm, Webapps.jsm and Webapps.js
 
-let EXPORTED_SYMBOLS = ["AppsUtils"];
+let EXPORTED_SYMBOLS = ["AppsUtils", "ManifestHelper"];
 
 function debug(s) {
   //dump("-*- AppsUtils.jsm: " + s + "\n");
 }
 
 let AppsUtils = {
   // Clones a app, without the manifest.
   cloneAppObject: function cloneAppObject(aApp) {
@@ -171,10 +171,158 @@ let AppsUtils = {
 
     for (let localeName in aManifest.locales) {
       if (checkAbsoluteEntryPoints(aManifest.locales[localeName].entry_points)) {
         return false;
       }
     }
 
     return true;
+  },
+
+  /**
+ * Determine the type of app (app, privileged, certified)
+ * that is installed by the manifest
+ * @param object aManifest
+ * @returns integer
+ **/
+  getAppManifestStatus: function getAppManifestStatus(aManifest) {
+    let type = aManifest.type || "web";
+
+    switch(type) {
+    case "web":
+      return Ci.nsIPrincipal.APP_STATUS_INSTALLED;
+    case "privileged":
+      return Ci.nsIPrincipal.APP_STATUS_PRIVILEGED;
+    case "certified":
+      return Ci.nsIPrincipal.APP_STATUS_CERTIFIED;
+    default:
+      throw new Error("Webapps.jsm: Undetermined app manifest type");
+    }
   }
 }
+
+/**
+ * Helper object to access manifest information with locale support
+ */
+let ManifestHelper = function(aManifest, aOrigin) {
+  this._origin = Services.io.newURI(aOrigin, null, null);
+  this._manifest = aManifest;
+  let chrome = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry)
+                                                          .QueryInterface(Ci.nsIToolkitChromeRegistry);
+  let locale = chrome.getSelectedLocale("browser").toLowerCase();
+  this._localeRoot = this._manifest;
+
+  if (this._manifest.locales && this._manifest.locales[locale]) {
+    this._localeRoot = this._manifest.locales[locale];
+  }
+  else if (this._manifest.locales) {
+    // try with the language part of the locale ("en" for en-GB) only
+    let lang = locale.split('-')[0];
+    if (lang != locale && this._manifest.locales[lang])
+      this._localeRoot = this._manifest.locales[lang];
+  }
+};
+
+ManifestHelper.prototype = {
+  _localeProp: function(aProp) {
+    if (this._localeRoot[aProp] != undefined)
+      return this._localeRoot[aProp];
+    return this._manifest[aProp];
+  },
+
+  get name() {
+    return this._localeProp("name");
+  },
+
+  get description() {
+    return this._localeProp("description");
+  },
+
+  get version() {
+    return this._localeProp("version");
+  },
+
+  get launch_path() {
+    return this._localeProp("launch_path");
+  },
+
+  get developer() {
+    return this._localeProp("developer");
+  },
+
+  get icons() {
+    return this._localeProp("icons");
+  },
+
+  get appcache_path() {
+    return this._localeProp("appcache_path");
+  },
+
+  get orientation() {
+    return this._localeProp("orientation");
+  },
+
+  get package_path() {
+    return this._localeProp("package_path");
+  },
+
+  get size() {
+    return this._manifest["size"] || 0;
+  },
+
+  get permissions() {
+    if (this._manifest.permissions) {
+      return this._manifest.permissions;
+    }
+    return {};
+  },
+
+  iconURLForSize: function(aSize) {
+    let icons = this._localeProp("icons");
+    if (!icons)
+      return null;
+    let dist = 100000;
+    let icon = null;
+    for (let size in icons) {
+      let iSize = parseInt(size);
+      if (Math.abs(iSize - aSize) < dist) {
+        icon = this._origin.resolve(icons[size]);
+        dist = Math.abs(iSize - aSize);
+      }
+    }
+    return icon;
+  },
+
+  fullLaunchPath: function(aStartPoint) {
+    // If no start point is specified, we use the root launch path.
+    // In all error cases, we just return null.
+    if ((aStartPoint || "") === "") {
+      return this._origin.resolve(this._localeProp("launch_path") || "");
+    }
+
+    // Search for the l10n entry_points property.
+    let entryPoints = this._localeProp("entry_points");
+    if (!entryPoints) {
+      return null;
+    }
+
+    if (entryPoints[aStartPoint]) {
+      return this._origin.resolve(entryPoints[aStartPoint].launch_path || "");
+    }
+
+    return null;
+  },
+
+  resolveFromOrigin: function(aURI) {
+    return this._origin.resolve(aURI);
+  },
+
+  fullAppcachePath: function() {
+    let appcachePath = this._localeProp("appcache_path");
+    return this._origin.resolve(appcachePath ? appcachePath : "");
+  },
+
+  fullPackagePath: function() {
+    let packagePath = this._localeProp("package_path");
+    return this._origin.resolve(packagePath ? packagePath : "");
+  }
+}
--- a/dom/apps/src/Makefile.in
+++ b/dom/apps/src/Makefile.in
@@ -16,17 +16,17 @@ EXTRA_COMPONENTS = \
   $(NULL)
 
 EXTRA_PP_COMPONENTS = \
   Webapps.js \
   $(NULL)
 
 EXTRA_PP_JS_MODULES += \
   Webapps.jsm \
-  AppsServiceChild.jsm \
-  AppsUtils.jsm \
   $(NULL)
 
 EXTRA_JS_MODULES += \
-  PermissionsTable.jsm \
+  AppsServiceChild.jsm \
+  AppsUtils.jsm \
+  PermissionsInstaller.jsm \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
rename from dom/apps/src/PermissionsTable.jsm
rename to dom/apps/src/PermissionsInstaller.jsm
--- a/dom/apps/src/PermissionsTable.jsm
+++ b/dom/apps/src/PermissionsInstaller.jsm
@@ -1,30 +1,49 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const Ci = Components.interfaces;
+const Cu = Components.utils;
 
-var EXPORTED_SYMBOLS = ["PermissionsTable",
-                        "UNKNOWN_ACTION",
-                        "ALLOW_ACTION",
-                        "DENY_ACTION",
-                        "PROMPT_ACTION",
-                        "AllPossiblePermissions",
-                        "mapSuffixes",
-                       ];
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/AppsUtils.jsm");
+
+var EXPORTED_SYMBOLS = ["PermissionsInstaller"];
 
 const UNKNOWN_ACTION = Ci.nsIPermissionManager.UNKNOWN_ACTION;
 const ALLOW_ACTION = Ci.nsIPermissionManager.ALLOW_ACTION;
 const DENY_ACTION = Ci.nsIPermissionManager.DENY_ACTION;
 const PROMPT_ACTION = Ci.nsIPermissionManager.PROMPT_ACTION;
 
+// Permission access flags
+const READONLY = "readonly";
+const CREATEONLY = "createonly";
+const READCREATE = "readcreate";
+const READWRITE = "readwrite";
+
+const PERM_TO_STRING = ["unknown", "allow", "deny", "prompt"];
+
+XPCOMUtils.defineLazyServiceGetter(this,
+                                   "PermSettings",
+                                   "@mozilla.org/permissionSettings;1",
+                                   "nsIDOMPermissionSettings");
+
+XPCOMUtils.defineLazyServiceGetter(this,
+                                   "permissionManager",
+                                   "@mozilla.org/permissionmanager;1",
+                                   "nsIPermissionManager");
+
+function debug(aMsg) {
+  //dump("-*-*- PermissionsInstaller.jsm : " + aMsg + "\n");
+}
+
 /**
  * Converts ['read', 'write'] to ['contacts-read', 'contacts-write'], etc...
  * @param string aPermName
  * @param Array aSuffixes
  * @returns Array
  **/
 function mapSuffixes(aPermName, aSuffixes)
 {
@@ -173,8 +192,159 @@ for (let permName in PermissionsTable) {
     AllPossiblePermissions =
       AllPossiblePermissions.concat(mapSuffixes(permName,
                                     PermissionsTable[permName].access));
   }
   else {
     AllPossiblePermissions.push(permName);
   }
 }
+
+/**
+ * Expand an access string into multiple permission names,
+ *   e.g: perm 'contacts' with 'readwrite' =
+ *   ['contacts-read', 'contacts-create', contacts-write']
+ * @param string aPermName
+ * @param string aAccess
+ * @returns Array
+ **/
+function expandPermissions(aPermName, aAccess) {
+  if (!PermissionsTable[aPermName]) {
+    Cu.reportError("PermissionsTable.jsm: expandPermissions: Unknown Permission: " + aPermName);
+    throw new Error("PermissionsTable.jsm: expandPermissions: Unknown Permission: " + aPermName);
+  }
+  if (!aAccess && PermissionsTable[aPermName].access ||
+      aAccess && !PermissionsTable[aPermName].access) {
+    Cu.reportError("PermissionsTable.jsm: expandPermissions: Invalid Manifest");
+    throw new Error("PermissionsTable.jsm: expandPermissions: Invalid Manifest");
+  }
+  if (!PermissionsTable[aPermName].access) {
+    return [aPermName];
+  }
+
+  let requestedSuffixes = [];
+  switch(aAccess) {
+  case READONLY:
+    requestedSuffixes.push("read");
+    break;
+  case CREATEONLY:
+    requestedSuffixes.push("create");
+    break;
+  case READCREATE:
+    requestedSuffixes.push("read", "create");
+    break;
+  case READWRITE:
+    requestedSuffixes.push("read", "create", "write");
+    break;
+  default:
+    return [];
+  }
+
+  let permArr = mapSuffixes(aPermName, requestedSuffixes);
+
+  let expandedPerms = [];
+  for (let idx in permArr) {
+    if (PermissionsTable[aPermName].access.indexOf(requestedSuffixes[idx]) != -1) {
+      expandedPerms.push(permArr[idx]);
+    }
+  }
+  return expandedPerms;
+}
+
+let PermissionsInstaller = {
+/**
+   * Install permissisions or remove deprecated permissions upon re-install
+   * @param object aData
+   *        The just-installed app configuration
+   * @param boolean aIsReinstall
+   *        Indicates the app was just re-installed
+   * @returns void
+   **/
+  installPermissions: function installPermissions(aApp, aIsReinstall, aOnError) {
+    try {
+      let newManifest = new ManifestHelper(aApp.manifest, aApp.origin);
+      if (!newManifest.permissions && !aIsReinstall) {
+        return;
+      }
+
+      if (aIsReinstall) {
+        // Compare the original permissions against the new permissions
+        // Remove any deprecated Permissions
+
+        if (newManifest.permissions) {
+          // Expand perms
+          let newPerms = [];
+          for (let perm in newManifest.permissions) {
+            let _perms = expandPermissions(perm,
+                                           newManifest.permissions[perm].access);
+            newPerms = newPerms.concat(_perms);
+          }
+
+          for (let idx in AllPossiblePermissions) {
+            let index = newPerms.indexOf(AllPossiblePermissions[idx]);
+            if (index == -1) {
+              // See if the permission was installed previously
+              let _perm = PermSettings.get(AllPossiblePermissions[idx],
+                                           aApp.manifestURL,
+                                           aApp.origin,
+                                           false);
+              if (_perm == "unknown" || _perm == "deny") {
+                // All 'deny' permissions should be preserved
+                continue;
+              }
+              // Remove the deprecated permission
+              // TODO: use PermSettings.remove, see bug 793204
+              PermSettings.set(AllPossiblePermissions[idx],
+                               "unknown",
+                               aApp.manifestURL,
+                               aApp.origin,
+                               false);
+            }
+          }
+        }
+      }
+
+      let installPermType;
+      // Check to see if the 'webapp' is app/priv/certified
+      switch (AppsUtils.getAppManifestStatus(newManifest)) {
+      case Ci.nsIPrincipal.APP_STATUS_CERTIFIED:
+        installPermType = "certified";
+        break;
+      case Ci.nsIPrincipal.APP_STATUS_PRIVILEGED:
+        installPermType = "privileged";
+        break;
+      case Ci.nsIPrincipal.APP_STATUS_INSTALLED:
+        installPermType = "app";
+        break;
+      default:
+        // Cannot determine app type, abort install by throwing an error
+        throw new Error("Webapps.jsm: Cannot determine app type, install cancelled");
+      }
+
+      for (let permName in newManifest.permissions) {
+        if (!PermissionsTable[permName]) {
+          throw new Error("Webapps.jsm: '" + permName + "'" +
+                         " is not a valid Webapps permission type. Aborting Webapp installation");
+          return;
+        }
+
+        let perms = expandPermissions(permName,
+                                      newManifest.permissions[permName].access);
+        for (let idx in perms) {
+          let perm = PermissionsTable[permName][installPermType];
+          let permValue = PERM_TO_STRING[perm];
+          PermSettings.set(perms[idx],
+                           permValue,
+                           aApp.manifestURL,
+                           aApp.origin,
+                           false);
+        }
+      }
+    }
+    catch (ex) {
+      debug("Caught webapps install permissions error");
+      Cu.reportError(ex);
+      if (aOnError) {
+        aOnError();
+      }
+    }
+  }
+}
\ No newline at end of file
--- a/dom/apps/src/Webapps.js
+++ b/dom/apps/src/Webapps.js
@@ -60,18 +60,18 @@ WebappsRegistry.prototype = {
       case "Webapps:GetSelf:Return:OK":
         if (msg.apps.length) {
           app = msg.apps[0];
           Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app));
         } else {
           Services.DOMRequest.fireSuccess(req, null);
         }
         break;
-      case "Webapps:IsInstalled:Return:OK":
-        Services.DOMRequest.fireSuccess(req, msg.installed);
+      case "Webapps:CheckInstalled:Return:OK":
+        Services.DOMRequest.fireSuccess(req, msg.app);
         break;
       case "Webapps:GetInstalled:Return:OK":
         Services.DOMRequest.fireSuccess(req, convertAppsArray(msg.apps, this._window));
         break;
     }
     this.removeRequest(msg.requestID);
   },
 
@@ -154,25 +154,25 @@ WebappsRegistry.prototype = {
     let request = this.createRequest();
     cpmm.sendAsyncMessage("Webapps:GetSelf", { origin: this._getOrigin(this._window.location.href),
                                                appId: this._window.document.nodePrincipal.appId,
                                                oid: this._id,
                                                requestID: this.getRequestId(request) });
     return request;
   },
 
-  isInstalled: function(aManifestURL) {
+  checkInstalled: function(aManifestURL) {
     let manifestURL = Services.io.newURI(aManifestURL, null, this._window.document.baseURIObject);
     this._window.document.nodePrincipal.checkMayLoad(manifestURL, true, false);
 
     let request = this.createRequest();
-    cpmm.sendAsyncMessage("Webapps:IsInstalled", { origin: this._getOrigin(this._window.location.href),
-                                                   manifestURL: manifestURL.spec,
-                                                   oid: this._id,
-                                                   requestID: this.getRequestId(request) });
+    cpmm.sendAsyncMessage("Webapps:CheckInstalled", { origin: this._getOrigin(this._window.location.href),
+                                                      manifestURL: manifestURL.spec,
+                                                      oid: this._id,
+                                                      requestID: this.getRequestId(request) });
     return request;
   },
 
   getInstalled: function() {
     let request = this.createRequest();
     cpmm.sendAsyncMessage("Webapps:GetInstalled", { origin: this._getOrigin(this._window.location.href),
                                                     oid: this._id,
                                                     requestID: this.getRequestId(request) });
@@ -254,17 +254,17 @@ WebappsRegistry.prototype = {
     return request;
   },
 
   // nsIDOMGlobalPropertyInitializer implementation
   init: function(aWindow) {
     this.initHelper(aWindow, ["Webapps:Install:Return:OK", "Webapps:Install:Return:KO",
                               "Webapps:GetInstalled:Return:OK",
                               "Webapps:GetSelf:Return:OK",
-                              "Webapps:IsInstalled:Return:OK" ]);
+                              "Webapps:CheckInstalled:Return:OK" ]);
 
     let util = this._window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
     this._id = util.outerWindowID;
     cpmm.sendAsyncMessage("Webapps:RegisterForMessages",
                           ["Webapps:Install:Return:OK"]);
   },
 
   classID: Components.ID("{fff440b3-fae2-45c1-bf03-3b5a2e432270}"),
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -4,54 +4,36 @@
 
 "use strict";
 
 const Cu = Components.utils;
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 
-let EXPORTED_SYMBOLS = ["DOMApplicationRegistry", "DOMApplicationManifest"];
+let EXPORTED_SYMBOLS = ["DOMApplicationRegistry"];
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/FileUtils.jsm");
 Cu.import('resource://gre/modules/ActivitiesService.jsm');
 Cu.import("resource://gre/modules/AppsUtils.jsm");
-Cu.import("resource://gre/modules/PermissionsTable.jsm");
+Cu.import("resource://gre/modules/PermissionsInstaller.jsm");
 
 function debug(aMsg) {
   //dump("-*-*- Webapps.jsm : " + aMsg + "\n");
 }
 
 const WEBAPP_RUNTIME = Services.appinfo.ID == "webapprt@mozilla.org";
 
-// Permission access flags
-const READONLY = "readonly";
-const CREATEONLY = "createonly";
-const READCREATE = "readcreate";
-const READWRITE = "readwrite";
-
-const PERM_TO_STRING = ["unknown", "allow", "deny", "prompt"];
-
-XPCOMUtils.defineLazyServiceGetter(this,
-                                   "PermSettings",
-                                   "@mozilla.org/permissionSettings;1",
-                                   "nsIDOMPermissionSettings");
-
 XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
   Cu.import("resource://gre/modules/NetUtil.jsm");
   return NetUtil;
 });
 
-XPCOMUtils.defineLazyServiceGetter(this,
-                                   "permissionManager",
-                                   "@mozilla.org/permissionmanager;1",
-                                   "nsIPermissionManager");
-
 XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
                                    "@mozilla.org/parentprocessmessagemanager;1",
                                    "nsIMessageBroadcaster");
 
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
                                    "nsIMessageSender");
 
@@ -66,100 +48,26 @@ XPCOMUtils.defineLazyGetter(this, "msgmg
   const DIRECTORY_NAME = "webappsDir";
 #else
   // If we're executing in the context of the webapp runtime, the data files
   // are in a different directory (currently the Firefox profile that installed
   // the webapp); otherwise, they're in the current profile.
   const DIRECTORY_NAME = WEBAPP_RUNTIME ? "WebappRegD" : "ProfD";
 #endif
 
-/**
- * Determine the type of app (app, privileged, certified)
- * that is installed by the manifest
- * @param object aManifest
- * @returns integer
- **/
-function getAppManifestStatus(aManifest)
-{
-  let type = aManifest.type || "web";
-
-  switch(type) {
-  case "web":
-    return Ci.nsIPrincipal.APP_STATUS_INSTALLED;
-  case "privileged":
-    return Ci.nsIPrincipal.APP_STATUS_PRIVILEGED;
-  case "certified":
-    return Ci.nsIPrincipal.APP_STATUS_CERTIFIED;
-  default:
-    throw new Error("Webapps.jsm: Undetermined app manifest type");
-  }
-}
-
-/**
- * Expand an access string into multiple permission names,
- *   e.g: perm 'contacts' with 'readwrite' =
- *   ['contacts-read', 'contacts-create', contacts-write']
- * @param string aPermName
- * @param string aAccess
- * @returns Array
- **/
-function expandPermissions(aPermName, aAccess)
-{
-  if (!PermissionsTable[aPermName]) {
-    Cu.reportError("Unknown permission: " + aPermName);
-    throw new Error("Webapps.jsm: App install failed, Unknown Permission: " + aPermName);
-  }
-  if (!aAccess && PermissionsTable[aPermName].access ||
-      aAccess && !PermissionsTable[aPermName].access) {
-    Cu.reportError("Webapps.jsm: installPermissions: Invalid Manifest");
-    throw new Error("Webapps.jsm: App install failed, Invalid Manifest");
-  }
-  if (!PermissionsTable[aPermName].access) {
-    return [aPermName];
-  }
-
-  let requestedSuffixes = [];
-  switch(aAccess) {
-  case READONLY:
-    requestedSuffixes.push("read");
-    break;
-  case CREATEONLY:
-    requestedSuffixes.push("create");
-    break;
-  case READCREATE:
-    requestedSuffixes.push("read", "create");
-    break;
-  case READWRITE:
-    requestedSuffixes.push("read", "create", "write");
-    break;
-  default:
-    return [];
-  }
-
-  let permArr = mapSuffixes(aPermName, requestedSuffixes);
-
-  let expandedPerms = [];
-  for (let idx in permArr) {
-    if (PermissionsTable[aPermName].access.indexOf(requestedSuffixes[idx]) != -1) {
-      expandedPerms.push(permArr[idx]);
-    }
-  }
-  return expandedPerms;
-}
-
 let DOMApplicationRegistry = {
   appsFile: null,
   webapps: { },
   children: [ ],
   allAppsLaunchable: false,
   downloads: { },
 
   init: function() {
     this.messages = ["Webapps:Install", "Webapps:Uninstall",
-                     "Webapps:GetSelf", "Webapps:IsInstalled",
+                     "Webapps:GetSelf", "Webapps:CheckInstalled",
                      "Webapps:GetInstalled", "Webapps:GetNotInstalled",
                      "Webapps:Launch", "Webapps:GetAll",
                      "Webapps:InstallPackage", "Webapps:GetBasePath",
                      "Webapps:GetList", "Webapps:RegisterForMessages",
                      "Webapps:CancelDownload", "Webapps:CheckForUpdate",
                      "Webapps::Download", "Webapps::ApplyDownload",
                      "child-process-shutdown"];
 
@@ -322,17 +230,17 @@ let DOMApplicationRegistry = {
       root = aManifest.entry_points[aEntryPoint];
     }
 
     if (!root.messages || !Array.isArray(root.messages) ||
         root.messages.length == 0) {
       return;
     }
 
-    let manifest = new DOMApplicationManifest(aManifest, aApp.origin);
+    let manifest = new ManifestHelper(aManifest, aApp.origin);
     let launchPath = Services.io.newURI(manifest.fullLaunchPath(aEntryPoint), null, null);
     let manifestURL = Services.io.newURI(aApp.manifestURL, null, null);
     root.messages.forEach(function registerPages(aMessage) {
       let href = launchPath;
       let messageName;
       if (typeof(aMessage) === "object" && Object.keys(aMessage).length === 1) {
         messageName = Object.keys(aMessage)[0];
         href = Services.io.newURI(manifest.resolveFromOrigin(aMessage[messageName]), null, null);
@@ -362,17 +270,17 @@ let DOMApplicationRegistry = {
     if (aEntryPoint && aManifest.entry_points[aEntryPoint]) {
       root = aManifest.entry_points[aEntryPoint];
     }
 
     if (!root.activities) {
       return;
     }
 
-    let manifest = new DOMApplicationManifest(aManifest, aApp.origin);
+    let manifest = new ManifestHelper(aManifest, aApp.origin);
     for (let activity in root.activities) {
       let description = root.activities[activity];
       if (!description.href) {
         description.href = manifest.launch_path;
       }
       description.href = manifest.resolveFromOrigin(description.href);
       let json = {
         "manifest": aApp.manifestURL,
@@ -556,33 +464,34 @@ let DOMApplicationRegistry = {
         break;
       case "Webapps:Uninstall":
         this.uninstall(msg, mm);
         debug("Webapps:Uninstall");
         break;
       case "Webapps:Launch":
         this.launchApp(msg, mm);
         break;
-      case "Webapps:IsInstalled":
-        this.isInstalled(msg, mm);
+      case "Webapps:CheckInstalled":
+        this.checkInstalled(msg, mm);
         break;
       case "Webapps:GetInstalled":
         this.getInstalled(msg, mm);
         break;
       case "Webapps:GetNotInstalled":
         this.getNotInstalled(msg, mm);
         break;
       case "Webapps:GetAll":