Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Thu, 09 Aug 2012 13:41:13 -0700
changeset 112952 52fdeb6d8d6dc6947dc4712f0781fd17beba65d1
parent 112951 c0195737650c31a80a473456c58fe6774c717a79 (current diff)
parent 107405 4770bca010461123a3bfde393bdebd1884dc3fcf (diff)
child 112953 b07af1efa3dddb495ac1927830f9d0cb746ee886
push idunknown
push userunknown
push dateunknown
milestone17.0a1
Merge from mozilla-central.
browser/base/content/browser.js
browser/base/content/tabbrowser.xml
browser/base/content/test/test_contextmenu.html
browser/components/nsBrowserGlue.js
browser/themes/winstripe/browser.css
caps/src/nsPrincipal.cpp
content/base/public/DirectionalityUtils.h
content/base/public/nsIDocument.h
content/base/public/nsINode.h
content/base/src/DirectionalityUtils.cpp
content/base/src/Makefile.in
content/base/src/nsContentSink.h
content/base/src/nsDocument.cpp
content/base/src/nsDocument.h
content/base/src/nsFrameLoader.cpp
content/base/src/nsGenericElement.cpp
content/base/src/nsGkAtomList.h
content/base/src/nsNodeInfoManager.cpp
content/base/test/Makefile.in
content/base/test/test_bug562169-1.html
content/base/test/test_bug562169-2.html
content/canvas/test/test_canvas.html
content/events/src/nsDOMSimpleGestureEvent.cpp
content/html/content/src/nsGenericHTMLElement.cpp
content/html/content/src/nsGenericHTMLElement.h
content/html/document/src/ImageDocument.cpp
content/xslt/src/xpath/txMozillaXPathTreeWalker.cpp
content/xslt/src/xpath/txNodeSet.cpp
content/xslt/src/xpath/txXPathTreeWalker.h
content/xslt/src/xslt/txFormatNumberFunctionCall.cpp
content/xul/templates/src/nsRuleNetwork.cpp
content/xul/templates/src/nsRuleNetwork.h
content/xul/templates/src/nsXULTemplateQueryProcessorStorage.cpp
docshell/base/nsDocShell.cpp
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfo.h
dom/base/nsDOMNavigationTiming.cpp
dom/base/nsDOMNavigationTiming.h
dom/base/nsDOMWindowUtils.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/Makefile.in
dom/ipc/PBrowser.ipdl
dom/ipc/PContent.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
dom/plugins/base/nsPluginNativeWindowGtk2.cpp
dom/plugins/ipc/PluginInstanceParent.cpp
dom/plugins/ipc/PluginModuleParent.cpp
dom/plugins/ipc/PluginModuleParent.h
dom/src/geolocation/nsGeolocation.cpp
dom/src/geolocation/nsGeolocation.h
dom/src/notification/nsDesktopNotification.cpp
dom/src/notification/nsDesktopNotification.h
editor/libeditor/html/nsHTMLCSSUtils.cpp
editor/libeditor/html/nsHTMLEditor.cpp
gfx/layers/basic/BasicThebesLayer.h
gfx/src/nsColor.cpp
gfx/thebes/gfxWindowsPlatform.cpp
image/decoders/nsPNGDecoder.cpp
image/src/RasterImage.cpp
image/src/imgLoader.cpp
image/src/imgLoader.h
js/src/Makefile.in
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/ParseNode.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/js.msg
js/src/jsatom.cpp
js/src/jsatom.h
js/src/jsgc.cpp
js/src/jshash.cpp
js/src/jshash.h
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsopcode.cpp
js/src/jsopcode.h
js/src/jsproxy.cpp
js/src/jsreflect.cpp
js/src/jsscope.cpp
js/src/jsscript.h
js/src/jsstr.cpp
js/src/jstypedarray.cpp
js/src/jsweakmap.cpp
js/src/methodjit/PolyIC.cpp
js/src/vm/String.h
js/xpconnect/src/XPCMaps.cpp
layout/base/FrameLayerBuilder.cpp
layout/base/crashtests/crashtests.list
layout/base/nsBidi.cpp
layout/base/nsBidi.h
layout/base/nsCSSRendering.cpp
layout/base/nsCSSRendering.h
layout/base/nsCSSRenderingBorders.cpp
layout/base/nsCSSRenderingBorders.h
layout/base/nsFrameManager.cpp
layout/base/nsPresShell.cpp
layout/forms/nsFieldSetFrame.cpp
layout/forms/nsFileControlFrame.cpp
layout/forms/nsFileControlFrame.h
layout/forms/nsHTMLButtonControlFrame.cpp
layout/forms/nsHTMLButtonControlFrame.h
layout/forms/nsListControlFrame.cpp
layout/forms/nsListControlFrame.h
layout/generic/nsBlockFrame.cpp
layout/generic/nsBlockFrame.h
layout/generic/nsBlockReflowContext.cpp
layout/generic/nsBulletFrame.cpp
layout/generic/nsCanvasFrame.cpp
layout/generic/nsCanvasFrame.h
layout/generic/nsColumnSetFrame.cpp
layout/generic/nsFirstLetterFrame.cpp
layout/generic/nsFirstLetterFrame.h
layout/generic/nsFrame.cpp
layout/generic/nsFrame.h
layout/generic/nsFrameSetFrame.cpp
layout/generic/nsFrameSetFrame.h
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsGfxScrollFrame.h
layout/generic/nsIFrame.h
layout/generic/nsImageFrame.cpp
layout/generic/nsImageFrame.h
layout/generic/nsInlineFrame.cpp
layout/generic/nsInlineFrame.h
layout/generic/nsSubDocumentFrame.cpp
layout/generic/nsSubDocumentFrame.h
layout/ipc/RenderFrameParent.cpp
layout/ipc/RenderFrameParent.h
layout/mathml/nsMathMLChar.cpp
layout/mathml/nsMathMLContainerFrame.h
layout/mathml/nsMathMLTokenFrame.h
layout/mathml/nsMathMLmactionFrame.h
layout/mathml/nsMathMLmfracFrame.h
layout/mathml/nsMathMLmmultiscriptsFrame.h
layout/mathml/nsMathMLmoFrame.h
layout/mathml/nsMathMLmpaddedFrame.h
layout/mathml/nsMathMLmspaceFrame.h
layout/mathml/nsMathMLmsubFrame.h
layout/mathml/nsMathMLmsubsupFrame.h
layout/mathml/nsMathMLmsupFrame.h
layout/mathml/nsMathMLmtableFrame.h
layout/mathml/nsMathMLmunderoverFrame.h
layout/reftests/bidi/562169-1-ref.html
layout/reftests/bidi/562169-1.html
layout/reftests/bidi/562169-1a.html
layout/reftests/bidi/562169-2-ref.html
layout/reftests/bidi/562169-2.html
layout/reftests/bidi/562169-2a.html
layout/reftests/bidi/562169-3-ref.html
layout/reftests/bidi/562169-3.html
layout/reftests/bidi/562169-3a.html
layout/reftests/bidi/562169-4-ref.html
layout/reftests/bidi/562169-4.html
layout/style/nsCSSParser.cpp
layout/style/nsCSSPseudoClasses.cpp
layout/style/nsCSSRuleProcessor.cpp
layout/tables/nsTableCellFrame.cpp
layout/tables/nsTableCellFrame.h
layout/tables/nsTableColGroupFrame.cpp
layout/tables/nsTableColGroupFrame.h
layout/tables/nsTableFrame.cpp
layout/tables/nsTableFrame.h
layout/tables/nsTableOuterFrame.h
layout/tables/nsTableRowFrame.cpp
layout/tables/nsTableRowFrame.h
layout/tables/nsTableRowGroupFrame.cpp
layout/tables/nsTableRowGroupFrame.h
layout/xul/base/src/nsGroupBoxFrame.cpp
mobile/android/chrome/content/browser.js
mobile/xul/chrome/content/WebappsUI.js
modules/libpref/src/init/all.js
netwerk/cache/nsCacheEntryDescriptor.cpp
netwerk/cache/nsDiskCacheStreams.cpp
netwerk/cache/nsDiskCacheStreams.h
netwerk/dns/nsHostResolver.cpp
netwerk/protocol/http/nsHttpAuthCache.cpp
netwerk/protocol/http/nsHttpAuthCache.h
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/socket/nsSOCKSIOLayer.cpp
netwerk/streamconv/converters/mozTXTToHTMLConv.cpp
netwerk/test/TestProtocols.cpp
netwerk/test/TestSocketIO.cpp
rdf/base/src/nsRDFService.cpp
security/manager/ssl/src/nsCRLManager.cpp
security/manager/ssl/src/nsNSSCertHelper.cpp
security/manager/ssl/src/nsNSSComponent.cpp
security/manager/ssl/src/nsNSSIOLayer.cpp
security/manager/ssl/src/nsPKCS12Blob.cpp
testing/mochitest/ssltunnel/ssltunnel.cpp
toolkit/components/alerts/mac/nsAlertsService.h
toolkit/components/alerts/mac/nsAlertsService.mm
toolkit/components/alerts/nsAlertsService.cpp
toolkit/components/downloads/nsDownloadManager.cpp
toolkit/components/telemetry/TelemetryPing.js
toolkit/crashreporter/nsExceptionHandler.cpp
widget/nsGUIEvent.h
widget/qt/nsWindow.cpp
widget/xremoteclient/XRemoteClient.cpp
xpcom/base/nsDebugImpl.cpp
xpcom/base/nsMemoryImpl.cpp
xpcom/base/nsTraceRefcntImpl.cpp
xpcom/build/nsXPCOM.h
xpcom/build/nsXPCOMPrivate.h
xpcom/ds/nsCRT.h
xpcom/ds/nsSupportsArray.cpp
xpcom/ds/nsSupportsArray.h
xpcom/glue/nsMemory.cpp
xpcom/glue/nsMemory.h
xpcom/glue/nsTArray-inl.h
xpcom/glue/pldhash.cpp
xpcom/glue/standalone/nsXPCOMGlue.cpp
xpcom/io/nsLocalFileUnix.cpp
xpcom/io/nsLocalFileUnix.h
xpcom/io/nsLocalFileWin.cpp
xpcom/string/public/nsTSubstring.h
xpcom/string/src/nsTSubstring.cpp
xpcom/stub/nsXPComStub.cpp
xpcom/tests/TestTArray.cpp
--- a/b2g/components/AlertsService.js
+++ b/b2g/components/AlertsService.js
@@ -10,17 +10,17 @@ Cu.import("resource://gre/modules/Servic
 
 // -----------------------------------------------------------------------
 // Alerts Service
 // -----------------------------------------------------------------------
 
 function AlertsService() { }
 
 AlertsService.prototype = {
-  classID: Components.ID("{5dce03b2-8faa-4b6e-9242-6ddb0411750c}"),
+  classID: Components.ID("{fe33c107-82a4-41d6-8c64-5353267e04c9}"),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIAlertsService]),
 
   showAlertNotification: function(aImageUrl, aTitle, aText, aTextClickable, aCookie, aAlertListener, aName) {
     let browser = Services.wm.getMostRecentWindow("navigator:browser");
     browser.AlertsHelper.showAlertNotification(aImageUrl, aTitle, aText, aTextClickable, aCookie, aAlertListener, aName);
   }
 };
 
--- a/b2g/components/B2GComponents.manifest
+++ b/b2g/components/B2GComponents.manifest
@@ -2,18 +2,18 @@
 category agent-style-sheets browser-content-stylesheet chrome://browser/content/content.css
 
 # CameraContent.js
 component {eff4231b-abce-4f7f-a40a-d646e8fde3ce} CameraContent.js
 contract @mozilla.org/b2g-camera-content;1 {eff4231b-abce-4f7f-a40a-d646e8fde3ce}
 category JavaScript-navigator-property mozCamera @mozilla.org/b2g-camera-content;1
 
 # AlertsService.js
-component {5dce03b2-8faa-4b6e-9242-6ddb0411750c} AlertsService.js
-contract @mozilla.org/alerts-service;1 {5dce03b2-8faa-4b6e-9242-6ddb0411750c}
+component {fe33c107-82a4-41d6-8c64-5353267e04c9} AlertsService.js
+contract @mozilla.org/system-alerts-service;1 {fe33c107-82a4-41d6-8c64-5353267e04c9}
 
 # ContentPermissionPrompt.js
 component {8c719f03-afe0-4aac-91ff-6c215895d467} ContentPermissionPrompt.js
 contract @mozilla.org/content-permission/prompt;1 {8c719f03-afe0-4aac-91ff-6c215895d467}
 
 #ifdef MOZ_UPDATER
 # UpdatePrompt.js
 component {88b3eb21-d072-4e3b-886d-f89d8c49fe59} UpdatePrompt.js
--- a/b2g/components/ContentPermissionPrompt.js
+++ b/b2g/components/ContentPermissionPrompt.js
@@ -10,17 +10,17 @@ const Cc = Components.classes;
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 function ContentPermissionPrompt() {}
 
 ContentPermissionPrompt.prototype = {
 
   handleExistingPermission: function handleExistingPermission(request) {
-    let result = Services.perms.testExactPermission(request.uri, request.type);
+    let result = Services.perms.testExactPermissionFromPrincipal(request.principal, request.type);
     if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
       request.allow();
       return true;
     }
     if (result == Ci.nsIPermissionManager.DENY_ACTION) {
       request.cancel();
       return true;
     }
@@ -51,17 +51,17 @@ ContentPermissionPrompt.prototype = {
 
       request.cancel();
     });
 
     let details = {
       "type": "permission-prompt",
       "permission": request.type,
       "id": requestId,
-      "url": request.uri.spec
+      "url": request.principal.URI.spec
     };
     let event = content.document.createEvent("CustomEvent");
     event.initCustomEvent("mozChromeEvent", true, true, details);
     content.dispatchEvent(event);
   },
 
   classID: Components.ID("{8c719f03-afe0-4aac-91ff-6c215895d467}"),
 
--- a/browser/base/content/browser-plugins.js
+++ b/browser/base/content/browser-plugins.js
@@ -226,17 +226,17 @@ var gPluginHandler = {
                "PFSWindow", "chrome,centerscreen,resizable=yes",
                {plugins: missingPluginsArray, browser: gBrowser.selectedBrowser});
   },
 
   // Callback for user clicking on a disabled plugin
   managePlugins: function (aEvent) {
     BrowserOpenAddonsMgr("addons://list/plugin");
   },
- 
+
   // Callback for user clicking on the link in a click-to-play plugin
   // (where the plugin has an update)
   openPluginUpdatePage: function (aEvent) {
     openURL(Services.urlFormatter.formatURLPref("plugins.update.url"));
   },
 
 #ifdef MOZ_CRASHREPORTER
   // Callback for user clicking "submit a report" link
@@ -274,19 +274,18 @@ var gPluginHandler = {
       if (overlay)
         overlay.style.visibility = "hidden";
       return;
     }
 
     // The overlay is null if the XBL binding is not attached (element is display:none).
     if (overlay) {
       overlay.addEventListener("click", function(aEvent) {
-        // Have to check that the target is a XULElement and not the link
-        // to update the plugin
-        if (aEvent.target instanceof XULElement && 
+        // Have to check that the target is not the link to update the plugin
+        if (!(aEvent.originalTarget instanceof HTMLAnchorElement) &&
             aEvent.button == 0 && aEvent.isTrusted)
           gPluginHandler.activateSinglePlugin(aEvent.target.ownerDocument.defaultView.top, aPlugin);
       }, true);
     }
 
     if (!browser._clickToPlayDoorhangerShown)
       gPluginHandler._showClickToPlayNotification(browser);
   },
--- a/browser/base/content/browser-thumbnails.js
+++ b/browser/base/content/browser-thumbnails.js
@@ -21,21 +21,16 @@ let gBrowserThumbnails = {
   _sslDiskCacheEnabled: null,
 
   /**
    * Map of capture() timeouts assigned to their browsers.
    */
   _timeouts: null,
 
   /**
-   * Cache for the PageThumbs module.
-   */
-  _pageThumbs: null,
-
-  /**
    * List of tab events we want to listen for.
    */
   _tabEvents: ["TabClose", "TabSelect"],
 
   init: function Thumbnails_init() {
     try {
       if (Services.prefs.getBoolPref("browser.pagethumbnails.capturing_disabled"))
         return;
@@ -47,19 +42,16 @@ let gBrowserThumbnails = {
     this._sslDiskCacheEnabled =
       Services.prefs.getBoolPref(this.PREF_DISK_CACHE_SSL);
 
     this._tabEvents.forEach(function (aEvent) {
       gBrowser.tabContainer.addEventListener(aEvent, this, false);
     }, this);
 
     this._timeouts = new WeakMap();
-
-    XPCOMUtils.defineLazyModuleGetter(this, "_pageThumbs",
-      "resource:///modules/PageThumbs.jsm", "PageThumbs");
   },
 
   uninit: function Thumbnails_uninit() {
     gBrowser.removeTabsProgressListener(this);
     Services.prefs.removeObserver(this.PREF_DISK_CACHE_SSL, this);
 
     this._tabEvents.forEach(function (aEvent) {
       gBrowser.tabContainer.removeEventListener(aEvent, this, false);
@@ -95,17 +87,17 @@ let gBrowserThumbnails = {
                                                    aRequest, aStateFlags, aStatus) {
     if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
         aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK)
       this._delayedCapture(aBrowser);
   },
 
   _capture: function Thumbnails_capture(aBrowser) {
     if (this._shouldCapture(aBrowser))
-      this._pageThumbs.captureAndStore(aBrowser);
+      PageThumbs.captureAndStore(aBrowser);
   },
 
   _delayedCapture: function Thumbnails_delayedCapture(aBrowser) {
     if (this._timeouts.has(aBrowser))
       clearTimeout(this._timeouts.get(aBrowser));
     else
       aBrowser.addEventListener("scroll", this, true);
 
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -135,16 +135,19 @@ XPCOMUtils.defineLazyGetter(this, "Tilt"
 });
 
 XPCOMUtils.defineLazyGetter(this, "Social", function() {
   let tmp = {};
   Cu.import("resource:///modules/Social.jsm", tmp);
   return tmp.Social;
 });
 
+XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs",
+  "resource:///modules/PageThumbs.jsm");
+
 #ifdef MOZ_SAFE_BROWSING
 XPCOMUtils.defineLazyGetter(this, "SafeBrowsing", function() {
   let tmp = {};
   Cu.import("resource://gre/modules/SafeBrowsing.jsm", tmp);
   return tmp.SafeBrowsing;
 });
 #endif
 
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3402,17 +3402,30 @@
         // We must not set text/x-moz-url or text/plain data here,
         // otherwise trying to deatch the tab by dropping it on the desktop
         // may result in an "internet shortcut"
         dt.mozSetDataAt("text/x-moz-text-internal", spec, 0);
 
         // Set the cursor to an arrow during tab drags.
         dt.mozCursor = "default";
 
-        let canvas = tabPreviews.capture(tab, false);
+        // Create a canvas to which we capture the current tab.
+        let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
+        canvas.mozOpaque = true;
+
+        // We want drag images to be about 1/6th of the available screen width.
+        const widthFactor = 0.1739; // 1:5.75 inverse
+        canvas.width = Math.ceil(screen.availWidth * widthFactor);
+
+        // Maintain a 16:9 aspect ratio for drag images.
+        const aspectRatio = 0.5625; // 16:9 inverse
+        canvas.height = Math.round(canvas.width * aspectRatio);
+
+        let browser = tab.linkedBrowser;
+        PageThumbs.captureToCanvas(browser.contentWindow, canvas);
         dt.setDragImage(canvas, 0, 0);
 
         // _dragOffsetX/Y give the coordinates that the mouse should be
         // positioned relative to the corner of the new window created upon
         // dragend such that the mouse appears to have the same position
         // relative to the corner of the dragged tab.
         function clientX(ele) ele.getBoundingClientRect().left;
         let tabOffsetX = clientX(tab) -
--- a/browser/base/content/test/browser_pluginnotification.js
+++ b/browser/base/content/test/browser_pluginnotification.js
@@ -141,18 +141,17 @@ function test3() {
 
   new TabOpenListener("about:addons", test4, prepareTest5);
 
   var pluginNode = gTestBrowser.contentDocument.getElementById("test");
   ok(pluginNode, "Test 3, Found plugin in page");
   var manageLink = gTestBrowser.contentDocument.getAnonymousElementByAttribute(pluginNode, "class", "managePluginsLink");
   ok(manageLink, "Test 3, found 'manage' link in plugin-problem binding");
 
-  EventUtils.synthesizeMouse(manageLink,
-                             5, 5, {}, gTestBrowser.contentWindow);
+  EventUtils.synthesizeMouseAtCenter(manageLink, {}, gTestBrowser.contentWindow);
 }
 
 function test4(tab, win) {
   is(win.wrappedJSObject.gViewController.currentViewId, "addons://list/plugin", "Test 4, Should have displayed the plugins pane");
   gBrowser.removeTab(tab);
 }
 
 function prepareTest5() {
@@ -232,17 +231,17 @@ function test9a() {
 
   var plugin2 = doc.getElementById("test2");
   var rect = doc.getAnonymousElementByAttribute(plugin2, "class", "mainBox").getBoundingClientRect();
   ok(rect.width == 200, "Test 9a, Plugin with id=" + plugin2.id + " overlay rect should have 200px width before being clicked");
   ok(rect.height == 200, "Test 9a, Plugin with id=" + plugin2.id + " overlay rect should have 200px height before being clicked");
   var objLoadingContent = plugin2.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(!objLoadingContent.activated, "Test 9a, Plugin with id=" + plugin2.id + " should not be activated");
 
-  EventUtils.synthesizeMouse(plugin1, 100, 100, { });
+  EventUtils.synthesizeMouseAtCenter(plugin1, {}, gTestBrowser.contentWindow);
   var objLoadingContent = plugin1.QueryInterface(Ci.nsIObjectLoadingContent);
   var condition = function() objLoadingContent.activated;
   waitForCondition(condition, test9b, "Test 9a, Waited too long for plugin to activate");
 }
 
 // Tests that activating one click-to-play plugin will activate only that plugin (part 2/3)
 function test9b() {
   var notificationBox = gBrowser.getNotificationBox(gTestBrowser);
@@ -261,17 +260,17 @@ function test9b() {
 
   var plugin2 = doc.getElementById("test2");
   var pluginRect2 = doc.getAnonymousElementByAttribute(plugin2, "class", "mainBox").getBoundingClientRect();
   ok(pluginRect2.width != 0, "Test 9b, Plugin with id=" + plugin2.id + " should not have click-to-play overlay with zero width");
   ok(pluginRect2.height != 0, "Test 9b, Plugin with id=" + plugin2.id + " should not have click-to-play overlay with zero height");
   var objLoadingContent = plugin2.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(!objLoadingContent.activated, "Test 9b, Plugin with id=" + plugin2.id + " should not be activated");
 
-  EventUtils.synthesizeMouse(plugin2, 100, 100, { });
+  EventUtils.synthesizeMouseAtCenter(plugin2, {}, gTestBrowser.contentWindow);
   var objLoadingContent = plugin2.QueryInterface(Ci.nsIObjectLoadingContent);
   var condition = function() objLoadingContent.activated;
   waitForCondition(condition, test9c, "Test 9b, Waited too long for plugin to activate");
 }
 
 //
 // Tests that activating one click-to-play plugin will activate only that plugin (part 3/3)
 function test9c() {
@@ -477,17 +476,17 @@ function test16a() {
 
 // 2/4
 function test16b() {
   var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
   ok(popupNotification, "Test 16b, Should have a click-to-play notification");
   var plugin = gTestBrowser.contentDocument.getElementsByTagName("embed")[0];
   var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(!objLoadingContent.activated, "Test 16b, Plugin should not be activated");
-  EventUtils.synthesizeMouse(plugin, 100, 100, { });
+  EventUtils.synthesizeMouseAtCenter(plugin, {}, gTestBrowser.contentWindow);
   var condition = function() objLoadingContent.activated;
   waitForCondition(condition, test16c, "Test 16b, Waited too long for plugin to activate");
 }
 
 // 3/4
 function test16c() {
   var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
   ok(!popupNotification, "Test 16c, Should not have a click-to-play notification");
@@ -585,20 +584,28 @@ function test18a() {
     if (event.type == "TabOpen") {
       gBrowser.tabContainer.removeEventListener("TabOpen", this, false);
       this.tab = event.originalTarget;
       ok(event.target.label == this.url, "Test 18a, Update link should open up the plugin check page");
       gBrowser.removeTab(this.tab);
       test18b();
     }
   };
-  EventUtils.synthesizeMouse(updateLink, 5, 5, {}, gTestBrowser.contentWindow);
+  EventUtils.synthesizeMouseAtCenter(updateLink, {}, gTestBrowser.contentWindow);
 }
 
 function test18b() {
+  // clicking the update link should not activate the plugin
+  var doc = gTestBrowser.contentDocument;
+  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");
 }
 
 // Tests a vulnerable plugin with no update
 function test18c() {
   var clickToPlayNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
@@ -611,10 +618,76 @@ function test18c() {
   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");
 
   unregisterFakeBlocklistService();
   var plugin = get_test_plugin();
   plugin.clicktoplay = false;
 
+  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");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(!objLoadingContent.activated, "Test 19a, Plugin should not be activated");
+
+  var icon = doc.getAnonymousElementByAttribute(plugin, "class", "icon");
+  EventUtils.synthesizeMouseAtCenter(icon, {}, gTestBrowser.contentWindow);
+  var condition = function() objLoadingContent.activated;
+  waitForCondition(condition, test19b, "Test 19a, Waited too long for plugin to activate");
+}
+
+function test19b() {
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.activated, "Test 19b, Plugin should be activated");
+
+  prepareTest(test19c, gTestRoot + "plugin_test.html");
+}
+
+// Tests that clicking the text of the overlay activates the plugin
+function test19c() {
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(!objLoadingContent.activated, "Test 19c, Plugin should not be activated");
+
+  var text = doc.getAnonymousElementByAttribute(plugin, "class", "msg msgClickToPlay");
+  EventUtils.synthesizeMouseAtCenter(text, {}, gTestBrowser.contentWindow);
+  var condition = function() objLoadingContent.activated;
+  waitForCondition(condition, test19d, "Test 19c, Waited too long for plugin to activate");
+}
+
+function test19d() {
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.activated, "Test 19d, Plugin should be activated");
+
+  prepareTest(test19e, gTestRoot + "plugin_test.html");
+}
+
+// Tests that clicking the box of the overlay activates the plugin
+// (just to be thorough)
+function test19e() {
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(!objLoadingContent.activated, "Test 19e, Plugin should not be activated");
+
+  EventUtils.synthesizeMouse(plugin, 50, 50, {}, gTestBrowser.contentWindow);
+  var condition = function() objLoadingContent.activated;
+  waitForCondition(condition, test19f, "Test 19e, Waited too long for plugin to activate");
+}
+
+function test19f() {
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.activated, "Test 19f, Plugin should be activated");
+
   finishTest();
 }
--- a/browser/base/content/test/test_contextmenu.html
+++ b/browser/base/content/test/test_contextmenu.html
@@ -13,19 +13,17 @@ Browser context menu tests.
 <div id="content">
 </div>
 
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Login Manager: multiple login autocomplete. **/
 
-netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
-Components.utils.import("resource://gre/modules/InlineSpellChecker.jsm");
-Components.utils.import("resource://gre/modules/Services.jsm");
+SpecialPowers.wrap(Components).utils.import("resource://gre/modules/InlineSpellChecker.jsm", window);
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 function openContextMenuFor(element, shiftkey, shouldWaitForFocus) {
     // Context menu should be closed before we open it again.
     is(SpecialPowers.wrap(contextMenu).state, "closed", "checking if popup is closed");
 
@@ -724,33 +722,33 @@ function runTest(testNum) {
                          ].concat(inspectItems));
         closeContextMenu();
         selectText(selecttext); // Select text prior to opening context menu.
         openContextMenuFor(selecttext); // Invoke context menu for next test.
         return;
 
     case 24:
         // Context menu for selected text
-        if (Services.appinfo.OS == "Darwin") {
+        if (SpecialPowers.Services.appinfo.OS == "Darwin") {
           // This test is only enabled on Mac due to bug 736399.
           checkContextMenu(["context-copy",                        true,
                             "context-selectall",                   true,
                             "---",                                 null,
                             "context-searchselect",                true,
                             "context-viewpartialsource-selection", true
                            ].concat(inspectItems));
         }
         closeContextMenu();
         selectText(selecttextlink); // Select text prior to opening context menu.
         openContextMenuFor(selecttextlink); // Invoke context menu for next test.
         return;
 
     case 25:
         // Context menu for selected text which matches valid URL pattern
-        if (Services.appinfo.OS == "Darwin") {
+        if (SpecialPowers.Services.appinfo.OS == "Darwin") {
           // This test is only enabled on Mac due to bug 736399.
           checkContextMenu(["context-openlinkincurrent",           true,
                             "context-openlinkintab",               true,
                             "context-openlink",                    true,
                             "---",                                 null,
                             "context-bookmarklink",                true,
                             "context-savelink",                    true,
                             "context-copy",                        true,
@@ -785,18 +783,17 @@ function runTest(testNum) {
 
 var testNum = 1;
 var subwindow, chromeWin, contextMenu, lastElement;
 var text, link, mailto, input, img, canvas, video_ok, video_bad, video_bad2,
     iframe, video_in_iframe, image_in_iframe, textarea, contenteditable,
     inputspell, pagemenu, dom_full_screen, plainTextItems, audio_in_video;
 
 function startTest() {
-    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
-    chromeWin = subwindow
+    chromeWin = SpecialPowers.wrap(subwindow)
                     .QueryInterface(Ci.nsIInterfaceRequestor)
                     .getInterface(Ci.nsIWebNavigation)
                     .QueryInterface(Ci.nsIDocShellTreeItem)
                     .rootTreeItem
                     .QueryInterface(Ci.nsIInterfaceRequestor)
                     .getInterface(Ci.nsIDOMWindow)
                     .QueryInterface(Ci.nsIDOMChromeWindow);
     contextMenu = chromeWin.document.getElementById("contentAreaContextMenu");
--- a/browser/base/content/test/test_offlineNotification.html
+++ b/browser/base/content/test/test_offlineNotification.html
@@ -21,36 +21,36 @@ https://bugzilla.mozilla.org/show_bug.cg
 <iframe id="eventsTestFrame" src="offlineEvent.html"></iframe>
 
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
+const Cc = SpecialPowers.wrap(Components).classes;
 
 var numFinished = 0;
 
 window.addEventListener("message", function(event) {
     is(event.data, "success", "Child was successfully cached.");
 
     if (++numFinished == 3) {
       // Clean up after ourself
-      netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-      var pm = Components.classes["@mozilla.org/permissionmanager;1"].
+      var pm = Cc["@mozilla.org/permissionmanager;1"].
                getService(Components.interfaces.nsIPermissionManager);
-      var ioService = Components.classes["@mozilla.org/network/io-service;1"]
+      var ioService = Cc["@mozilla.org/network/io-service;1"]
                         .getService(Components.interfaces.nsIIOService);
       var uri1 = ioService.newURI(frames.testFrame.location, null, null);
       var uri2 = ioService.newURI(frames.testFrame3.location, null, null);
 
-      var principal1 = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
+      var principal1 = Cc["@mozilla.org/scriptsecuritymanager;1"]
                         .getService(Components.interfaces.nsIScriptSecurityManager)
                         .getNoAppCodebasePrincipal(uri1);
-      var principal2 = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
+      var principal2 = Cc["@mozilla.org/scriptsecuritymanager;1"]
                         .getService(Components.interfaces.nsIScriptSecurityManager)
                         .getNoAppCodebasePrincipal(uri2);
 
       pm.removeFromPrincipal(principal1, "offline-app");
       pm.removeFromPrincipal(principal2, "offline-app");
 
       SimpleTest.finish();
     }
@@ -103,26 +103,25 @@ function testEventHandling() {
 }
 
 function loaded() {
   testEventHandling();
 
   // Click the notification bar's "Allow" button.  This should kick
   // off updates, which will eventually lead to getting messages from
   // the children.
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].
+  var wm = SpecialPowers.wrap(Components).classes["@mozilla.org/appshell/window-mediator;1"].
            getService(Components.interfaces.nsIWindowMediator);
   var win = wm.getMostRecentWindow("navigator:browser");
   var notificationBox = win.gBrowser.getNotificationBox();
 
   var notification = notificationBox.getNotificationWithValue("offline-app-requested-mochi.test");
   notification.childNodes[0].click();
 
-  notification = notificationBox.getNotificationWithValue("offline-app-requested-example.com");
+  notification = SpecialPowers.wrap(notificationBox).getNotificationWithValue("offline-app-requested-example.com");
   notification.childNodes[0].click();
 }
 
 </script>
 </pre>
 </body>
 </html>
 
--- a/browser/base/content/test/test_offline_gzip.html
+++ b/browser/base/content/test/test_offline_gzip.html
@@ -27,25 +27,23 @@ cache, it can be fetched from the cache 
 var cacheCount = 0;
 var intervalID = 0;
 
 window.addEventListener("message", handleMessageEvents, false);
 SimpleTest.waitForExplicitFinish();
 
 function finishTest() {
   // Clean up after ourselves.
-  netscape.security.PrivilegeManager
-          .enablePrivilege("UniversalXPConnect");
-  var pm = Components.classes["@mozilla.org/permissionmanager;1"].
+  var Cc = SpecialPowers.wrap(Components).classes;
+  var pm = Cc["@mozilla.org/permissionmanager;1"].
            getService(Components.interfaces.nsIPermissionManager);
 
-  var uri = Components.classes["@mozilla.org/network/io-service;1"]
-              .getService(Components.interfaces.nsIIOService)
+  var uri = Cc["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService)
               .newURI(window.frames[0].location, null, null);
-  var principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
+  var principal = Cc["@mozilla.org/scriptsecuritymanager;1"]
                    .getService(Components.interfaces.nsIScriptSecurityManager)
                    .getNoAppCodebasePrincipal(uri);
 
   pm.removeFromPrincipal(principal, "offline-app");
 
   window.removeEventListener("message", handleMessageEvents, false);
 
   SimpleTest.finish();  
@@ -65,18 +63,16 @@ function handleMessageEvents(event) {
       // in the case of bug 501422.
       frames.testFrame.window.location.reload();
       // Use setInterval to repeatedly call a function which
       // checks that one of two things has occurred:  either
       // the offline cache is udpated (which means our iframe
       // successfully reloaded), or the string "error" appears
       // in the iframe, as in the case of bug 501422.
       intervalID = setInterval(function() {
-        netscape.security.PrivilegeManager
-                .enablePrivilege("UniversalXPConnect");
         // Sometimes document.body may not exist, and trying to access
         // it will throw an exception, so handle this case.
         try {
           var bodyInnerHTML = frames.testFrame.document.body.innerHTML;
         }
         catch (e) {
           var bodyInnerHTML = "";
         }
@@ -98,18 +94,17 @@ function handleMessageEvents(event) {
       ok(false, "cacheCount not 1 or 2");
   }
 }
 
 function loaded() {
   // Click the notification bar's "Allow" button.  This should kick
   // off updates, which will eventually lead to getting messages from
   // the iframe.
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].
+  var wm = SpecialPowers.wrap(Components).classes["@mozilla.org/appshell/window-mediator;1"].
            getService(Components.interfaces.nsIWindowMediator);
   var win = wm.getMostRecentWindow("navigator:browser");
   var notificationBox = win.gBrowser.getNotificationBox();
 
   var notification = notificationBox
     .getNotificationWithValue("offline-app-requested-mochi.test");
   notification.childNodes[0].click();
 }
--- a/browser/components/feeds/test/test_bug589543.html
+++ b/browser/components/feeds/test/test_bug589543.html
@@ -15,18 +15,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 589543 **/
 SimpleTest.waitForExplicitFinish();
 
 addLoadEvent(function() {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  var doc = $("testFrame").contentDocument;
+  var doc = SpecialPowers.wrap($("testFrame").contentDocument);
   var daddy = doc.getElementById("feedSubscribeLine");
   var popup = doc.getAnonymousElementByAttribute(daddy, "anonid", "handlersMenuPopup");
   isnot(popup, null, "Feed preview should have a handlers popup");
 });
 addLoadEvent(SimpleTest.finish);
 
 </script>
 </pre>
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -1555,23 +1555,24 @@ ContentPermissionPrompt.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt]),
 
   prompt: function CPP_prompt(request) {
 
     if (request.type != "geolocation") {
         return;
     }
 
-    var requestingURI = request.uri;
+    var requestingPrincipal = request.principal;
+    var requestingURI = requestingPrincipal.URI;
 
     // Ignore requests from non-nsIStandardURLs
     if (!(requestingURI instanceof Ci.nsIStandardURL))
       return;
 
-    var result = Services.perms.testExactPermission(requestingURI, "geo");
+    var result = Services.perms.testExactPermissionFromPrincipal(requestingPrincipal, "geo");
 
     if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
       request.allow();
       return;
     }
 
     if (result == Ci.nsIPermissionManager.DENY_ACTION) {
       request.cancel();
@@ -1614,25 +1615,25 @@ ContentPermissionPrompt.prototype = {
                                                    [requestingURI.host], 1);
 
       // Don't offer to "always/never share" in PB mode
       if (("gPrivateBrowsingUI" in chromeWin) && !chromeWin.gPrivateBrowsingUI.privateWindow) {
         secondaryActions.push({
           label: browserBundle.GetStringFromName("geolocation.alwaysShareLocation"),
           accessKey: browserBundle.GetStringFromName("geolocation.alwaysShareLocation.accesskey"),
           callback: function () {
-            Services.perms.add(requestingURI, "geo", Ci.nsIPermissionManager.ALLOW_ACTION);
+            Services.perms.addFromPrincipal(requestingPrincipal, "geo", Ci.nsIPermissionManager.ALLOW_ACTION);
             request.allow();
           }
         });
         secondaryActions.push({
           label: browserBundle.GetStringFromName("geolocation.neverShareLocation"),
           accessKey: browserBundle.GetStringFromName("geolocation.neverShareLocation.accesskey"),
           callback: function () {
-            Services.perms.add(requestingURI, "geo", Ci.nsIPermissionManager.DENY_ACTION);
+            Services.perms.addFromPrincipal(requestingPrincipal, "geo", Ci.nsIPermissionManager.DENY_ACTION);
             request.cancel();
           }
         });
       }
     }
 
     var browser = chromeWin.gBrowser.getBrowserForDocument(requestingWindow.document);
 
--- a/browser/components/thumbnails/PageThumbs.jsm
+++ b/browser/components/thumbnails/PageThumbs.jsm
@@ -111,43 +111,51 @@ let PageThumbs = {
    *                  captured. The first argument will be the data stream
    *                  containing the image data.
    */
   capture: function PageThumbs_capture(aWindow, aCallback) {
     if (!this._prefEnabled()) {
       return;
     }
 
-    let telemetryCaptureTime = new Date();
-    let [sw, sh, scale] = this._determineCropSize(aWindow);
+    let canvas = this._createCanvas();
+    this.captureToCanvas(aWindow, canvas);
 
-    let canvas = this._createCanvas();
-    let ctx = canvas.getContext("2d");
+    // Fetch the canvas data on the next event loop tick so that we allow
+    // some event processing in between drawing to the canvas and encoding
+    // its data. We want to block the UI as short as possible. See bug 744100.
+    Services.tm.currentThread.dispatch(function () {
+      canvas.mozFetchAsStream(aCallback, this.contentType);
+    }.bind(this), Ci.nsIThread.DISPATCH_NORMAL);
+  },
+
+  /**
+   * Captures a thumbnail from a given window and draws it to the given canvas.
+   * @param aWindow The DOM window to capture a thumbnail from.
+   * @param aCanvas The canvas to draw to.
+   */
+  captureToCanvas: function PageThumbs_captureToCanvas(aWindow, aCanvas) {
+    let telemetryCaptureTime = new Date();
+    let [sw, sh, scale] = this._determineCropSize(aWindow, aCanvas);
+    let ctx = aCanvas.getContext("2d");
 
     // Scale the canvas accordingly.
     ctx.scale(scale, scale);
 
     try {
       // Draw the window contents to the canvas.
       ctx.drawWindow(aWindow, 0, 0, sw, sh, THUMBNAIL_BG_COLOR,
                      ctx.DRAWWINDOW_DO_NOT_FLUSH);
     } catch (e) {
       // We couldn't draw to the canvas for some reason.
     }
 
     let telemetry = Services.telemetry;
     telemetry.getHistogramById("FX_THUMBNAILS_CAPTURE_TIME_MS")
       .add(new Date() - telemetryCaptureTime);
-
-    // Fetch the canvas data on the next event loop tick so that we allow
-    // some event processing in between drawing to the canvas and encoding
-    // its data. We want to block the UI as short as possible. See bug 744100.
-    Services.tm.currentThread.dispatch(function () {
-      canvas.mozFetchAsStream(aCallback, this.contentType);
-    }.bind(this), Ci.nsIThread.DISPATCH_NORMAL);
   },
 
   /**
    * Captures a thumbnail for the given browser and stores it to the cache.
    * @param aBrowser The browser to capture a thumbnail for.
    * @param aCallback The function to be called when finished (optional).
    */
   captureAndStore: function PageThumbs_captureAndStore(aBrowser, aCallback) {
@@ -188,23 +196,24 @@ let PageThumbs = {
 
       PageThumbsStorage.write(url, aInputStream, finish);
     });
   },
 
   /**
    * Determines the crop size for a given content window.
    * @param aWindow The content window.
+   * @param aCanvas The target canvas.
    * @return An array containing width, height and scale.
    */
-  _determineCropSize: function PageThumbs_determineCropSize(aWindow) {
+  _determineCropSize: function PageThumbs_determineCropSize(aWindow, aCanvas) {
     let sw = aWindow.innerWidth;
     let sh = aWindow.innerHeight;
 
-    let [thumbnailWidth, thumbnailHeight] = this._getThumbnailSize();
+    let {width: thumbnailWidth, height: thumbnailHeight} = aCanvas;
     let scale = Math.max(thumbnailWidth / sw, thumbnailHeight / sh);
     let scaledWidth = sw * scale;
     let scaledHeight = sh * scale;
 
     if (scaledHeight > thumbnailHeight)
       sh -= Math.floor(Math.abs(scaledHeight - thumbnailHeight) * scale);
 
     if (scaledWidth > thumbnailWidth)
--- a/browser/components/thumbnails/test/head.js
+++ b/browser/components/thumbnails/test/head.js
@@ -6,18 +6,16 @@ Cu.import("resource:///modules/PageThumb
 let PageThumbs = tmp.PageThumbs;
 let PageThumbsStorage = tmp.PageThumbsStorage;
 
 registerCleanupFunction(function () {
   while (gBrowser.tabs.length > 1)
     gBrowser.removeTab(gBrowser.tabs[1]);
 });
 
-let cachedXULDocument;
-
 /**
  * Provide the default test function to start our test runner.
  */
 function test() {
   TestRunner.run();
 }
 
 /**
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -46,25 +46,26 @@ let DebuggerController = {
   _startupDebugger: function DC__startupDebugger() {
     if (this._isInitialized) {
       return;
     }
     this._isInitialized = true;
     window.removeEventListener("DOMContentLoaded", this._startupDebugger, true);
 
     DebuggerView.initializePanes();
-    DebuggerView.initializeEditor();
-    DebuggerView.StackFrames.initialize();
-    DebuggerView.Breakpoints.initialize();
-    DebuggerView.Properties.initialize();
-    DebuggerView.Scripts.initialize();
-    DebuggerView.showCloseButton(!this._isRemoteDebugger && !this._isChromeDebugger);
+    DebuggerView.initializeEditor(function() {
+      DebuggerView.Scripts.initialize();
+      DebuggerView.StackFrames.initialize();
+      DebuggerView.Breakpoints.initialize();
+      DebuggerView.Properties.initialize();
+      DebuggerView.showCloseButton(!this._isRemoteDebugger && !this._isChromeDebugger);
 
-    this.dispatchEvent("Debugger:Loaded");
-    this._connect();
+      this.dispatchEvent("Debugger:Loaded");
+      this._connect();
+    }.bind(this));
   },
 
   /**
    * Destroys the debugger view, disconnects the debugger client and cleans up
    * any active listeners.
    */
   _shutdownDebugger: function DC__shutdownDebugger() {
     if (this._isDestroyed) {
@@ -929,17 +930,17 @@ SourceScripts.prototype = {
     for each (let script in this.activeThread.cachedScripts) {
       this._addScript(script, false);
     }
     DebuggerView.Scripts.commitScripts();
     DebuggerController.Breakpoints.updatePaneBreakpoints();
 
     // Select the preferred script if one exists, the first entry otherwise.
     let preferredScriptUrl = DebuggerView.Scripts.preferredScriptUrl;
-    if (preferredScriptUrl) {
+    if (preferredScriptUrl && DebuggerView.Scripts.contains(preferredScriptUrl)) {
       DebuggerView.Scripts.selectScript(preferredScriptUrl);
     } else {
       DebuggerView.Scripts.selectIndex(0);
     }
   },
 
   /**
    * Handler for the thread client's scriptscleared notification.
--- a/browser/devtools/debugger/debugger-view.js
+++ b/browser/devtools/debugger/debugger-view.js
@@ -27,30 +27,36 @@ let DebuggerView = {
     stackframes.setAttribute("width", Prefs.stackframesWidth);
 
     let variables = document.getElementById("variables");
     variables.setAttribute("width", Prefs.variablesWidth);
   },
 
   /**
    * Initializes the SourceEditor instance.
+   *
+   * @param function aCallback
+   *        Called after the editor finishes initializing.
    */
-  initializeEditor: function DV_initializeEditor() {
+  initializeEditor: function DV_initializeEditor(aCallback) {
     let placeholder = document.getElementById("editor");
 
     let config = {
       mode: SourceEditor.MODES.JAVASCRIPT,
       showLineNumbers: true,
       readOnly: true,
       showAnnotationRuler: true,
       showOverviewRuler: true,
     };
 
     this.editor = new SourceEditor();
-    this.editor.init(placeholder, config, this._onEditorLoad.bind(this));
+    this.editor.init(placeholder, config, function() {
+      this._onEditorLoad();
+      aCallback();
+    }.bind(this));
   },
 
   /**
    * Removes the displayed panes and saves any necessary state.
    */
   destroyPanes: function DV_destroyPanes() {
     let stackframes = document.getElementById("stackframes+breakpoints");
     Prefs.stackframesWidth = stackframes.getAttribute("width");
@@ -469,17 +475,17 @@ ScriptsView.prototype = {
     scripts.setAttribute("label", this._preferredScript.label);
     scripts.setAttribute("tooltiptext", this._preferredScript.value);
 
     // If we're not searching for a file anymore, unhide all the scripts.
     if (!file) {
       for (let i = 0, l = scripts.itemCount; i < l; i++) {
         scripts.getItemAtIndex(i).hidden = false;
       }
-    } else {
+    } else if (this._prevSearchedFile !== file) {
       let found = false;
 
       for (let i = 0, l = scripts.itemCount; i < l; i++) {
         let item = scripts.getItemAtIndex(i);
         let target = item.label.toLowerCase();
 
         // Search is not case sensitive, and is tied to the label not the url.
         if (target.match(file)) {
@@ -497,25 +503,28 @@ ScriptsView.prototype = {
           item.hidden = true;
         }
       }
       if (!found) {
         scripts.setAttribute("label", L10N.getStr("noMatchingScriptsText"));
         scripts.removeAttribute("tooltiptext");
       }
     }
-    if (line > -1) {
+    if (this._prevSearchedLine !== line && line > -1) {
       editor.setCaretPosition(line - 1);
     }
-    if (token.length) {
+    if (this._prevSearchedToken !== token && token.length > 0) {
       let offset = editor.find(token, { ignoreCase: true });
       if (offset > -1) {
         editor.setSelection(offset, offset + token.length)
       }
     }
+    this._prevSearchedFile = file;
+    this._prevSearchedLine = line;
+    this._prevSearchedToken = token;
   },
 
   /**
    * The keyup listener for the scripts search box.
    */
   _onScriptsKeyUp: function DVS__onScriptsKeyUp(e) {
     if (e.keyCode === e.DOM_VK_ESCAPE) {
       DebuggerView.editor.focus();
--- a/browser/devtools/debugger/test/Makefile.in
+++ b/browser/devtools/debugger/test/Makefile.in
@@ -39,16 +39,17 @@ MOCHITEST_BROWSER_TESTS = \
 	browser_dbg_panesize.js \
 	browser_dbg_panesize-inner.js \
 	browser_dbg_stack-01.js \
 	browser_dbg_stack-02.js \
 	browser_dbg_stack-03.js \
 	browser_dbg_stack-04.js \
 	browser_dbg_stack-05.js \
 	browser_dbg_location-changes.js \
+	browser_dbg_location-changes-new.js \
 	browser_dbg_location-changes-blank.js \
 	browser_dbg_script-switching.js \
 	browser_dbg_scripts-sorting.js \
 	browser_dbg_scripts-searching-01.js \
 	browser_dbg_scripts-searching-02.js \
 	browser_dbg_pause-resume.js \
 	browser_dbg_update-editor-mode.js \
 	$(warning browser_dbg_select-line.js temporarily disabled due to oranges, see bug 726609) \
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_location-changes-new.js
@@ -0,0 +1,91 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Make sure that changing the tab location URL to a page with other scripts works.
+ */
+
+var gPane = null;
+var gTab = null;
+var gDebuggee = null;
+var gDebugger = null;
+
+function test()
+{
+  debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
+    gTab = aTab;
+    gDebuggee = aDebuggee;
+    gPane = aPane;
+    gDebugger = gPane.contentWindow;
+
+    testSimpleCall();
+  });
+}
+
+function testSimpleCall() {
+  gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
+    Services.tm.currentThread.dispatch({
+      run: function() {
+        var frames = gDebugger.DebuggerView.StackFrames._frames,
+            childNodes = frames.childNodes;
+
+        is(gDebugger.DebuggerController.activeThread.state, "paused",
+          "Should only be getting stack frames while paused.");
+
+        is(frames.querySelectorAll(".dbg-stackframe").length, 1,
+          "Should have only one frame.");
+
+        is(childNodes.length, frames.querySelectorAll(".dbg-stackframe").length,
+          "All children should be frames.");
+
+        isnot(gDebugger.DebuggerView.Scripts.selected, null,
+          "There should be a selected script.");
+        isnot(gDebugger.editor.getText().length, 0,
+          "The source editor should have some text displayed.");
+
+        testLocationChange();
+      }
+    }, 0);
+  });
+
+  gDebuggee.simpleCall();
+}
+
+function testLocationChange()
+{
+  gDebugger.DebuggerController.activeThread.resume(function() {
+    gDebugger.DebuggerController.client.addOneTimeListener("tabNavigated", function(aEvent, aPacket) {
+      ok(true, "tabNavigated event was fired.");
+      gDebugger.DebuggerController.client.addOneTimeListener("tabAttached", function(aEvent, aPacket) {
+        ok(true, "Successfully reattached to the tab again.");
+
+        // Wait for the initial resume...
+        gDebugger.gClient.addOneTimeListener("resumed", function() {
+          isnot(gDebugger.DebuggerView.Scripts.selected, null,
+            "There should be a selected script.");
+          isnot(gDebugger.editor.getText().length, 0,
+            "The source editor should have some text displayed.");
+
+          let menulist = gDebugger.DebuggerView.Scripts._scripts;
+          let noScripts = gDebugger.L10N.getStr("noScriptsText");
+          isnot(menulist.getAttribute("label"), noScripts,
+            "The menulist should not display a notice that there are no scripts availalble.");
+          isnot(menulist.getAttribute("tooltiptext"), "",
+            "The menulist should have a tooltip text attributed.");
+
+          closeDebuggerAndFinish();
+        });
+      });
+    });
+    content.location = EXAMPLE_URL + "browser_dbg_iframes.html";
+  });
+}
+
+registerCleanupFunction(function() {
+  removeTab(gTab);
+  gPane = null;
+  gTab = null;
+  gDebuggee = null;
+  gDebugger = null;
+});
--- a/browser/devtools/debugger/test/browser_dbg_scripts-searching-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_scripts-searching-01.js
@@ -186,16 +186,21 @@ function testScriptSearching() {
 
 function clear() {
   gSearchBox.focus();
   gSearchBox.value = "";
 }
 
 function write(text) {
   clear();
+  append(text);
+}
+
+function append(text) {
+  gSearchBox.focus();
 
   for (let i = 0; i < text.length; i++) {
     EventUtils.sendChar(text[i]);
   }
   info("Editor caret position: " + gEditor.getCaretPosition().toSource() + "\n");
 }
 
 registerCleanupFunction(function() {
--- a/browser/devtools/debugger/test/browser_dbg_scripts-searching-02.js
+++ b/browser/devtools/debugger/test/browser_dbg_scripts-searching-02.js
@@ -91,72 +91,117 @@ function secondSearch() {
     info("Current script url:\n" + aEvent.detail.url + "\n");
     info("Debugger editor text:\n" + gEditor.getText() + "\n");
 
     let url = aEvent.detail.url;
     if (url.indexOf("-02.js") != -1) {
       window.removeEventListener(aEvent.type, _onEvent);
 
       executeSoon(function() {
+        append("#" + token);
+
         info("Editor caret position: " + gEditor.getCaretPosition().toSource() + "\n");
         ok(gEditor.getCaretPosition().line == 5 &&
            gEditor.getCaretPosition().col == 8 + token.length,
           "The editor didn't jump to the correct line. (2)");
         is(gScripts.visibleItemsCount, 1,
           "Not all the correct scripts are shown after the search. (2)");
 
+        waitForFirstScript();
+      });
+    }
+  });
+  gScripts.selectIndex(1);
+}
+
+function waitForFirstScript() {
+  window.addEventListener("Debugger:ScriptShown", function _onEvent(aEvent) {
+    info("Current script url:\n" + aEvent.detail.url + "\n");
+    info("Debugger editor text:\n" + gEditor.getText() + "\n");
+
+    let url = aEvent.detail.url;
+    if (url.indexOf("-01.js") != -1) {
+      window.removeEventListener(aEvent.type, _onEvent);
+
+      executeSoon(function() {
+        thirdSearch();
+      });
+    }
+  });
+  gScripts.selectIndex(0);
+}
+
+function thirdSearch() {
+  let token = "deb";
+
+  window.addEventListener("Debugger:ScriptShown", function _onEvent(aEvent) {
+    info("Current script url:\n" + aEvent.detail.url + "\n");
+    info("Debugger editor text:\n" + gEditor.getText() + "\n");
+
+    let url = aEvent.detail.url;
+    if (url.indexOf("-02.js") != -1) {
+      window.removeEventListener(aEvent.type, _onEvent);
+
+      executeSoon(function() {
+        info("Editor caret position: " + gEditor.getCaretPosition().toSource() + "\n");
+        ok(gEditor.getCaretPosition().line == 5 &&
+           gEditor.getCaretPosition().col == 8 + token.length,
+          "The editor didn't jump to the correct line. (3)");
+        is(gScripts.visibleItemsCount, 1,
+          "Not all the correct scripts are shown after the search. (3)");
+
         finalCheck(0, "ugger;", token);
       });
     }
   });
   write(".*-02\.js#" + token);
 }
 
 function finalCheck(i, string, token) {
   info("Searchbox value: " + gSearchBox.value);
 
   ok(gEditor.getCaretPosition().line == 5 &&
      gEditor.getCaretPosition().col == 8 + token.length + i,
-    "The editor didn't remain at the correct token. (3)");
+    "The editor didn't remain at the correct token. (4)");
 
   if (string[i]) {
     EventUtils.sendChar(string[i]);
     finalCheck(i + 1, string, token);
     return;
   }
 
   clear();
   ok(gEditor.getCaretPosition().line == 5 &&
      gEditor.getCaretPosition().col == 8 + token.length + i,
-    "The editor didn't remain at the correct token. (4)");
+    "The editor didn't remain at the correct token. (5)");
 
   executeSoon(function() {
     let noMatchingScripts = gDebugger.L10N.getStr("noMatchingScriptsText");
 
     is(gScripts.visibleItemsCount, 2,
       "Not all the scripts are shown after the searchbox was emptied.");
     is(gMenulist.selectedIndex, 1,
       "The menulist should have retained its selected index after the searchbox was emptied.");
 
     write("BOGUS");
     ok(gEditor.getCaretPosition().line == 5 &&
        gEditor.getCaretPosition().col == 8 + token.length + i,
-      "The editor didn't remain at the correct token. (5)");
+      "The editor didn't remain at the correct token. (6)");
 
     is(gMenulist.getAttribute("label"), noMatchingScripts,
       "The menulist should display a notice that no scripts match the searched token.");
     is(gScripts.visibleItemsCount, 0,
       "No scripts should be displayed in the menulist after a bogus search.");
     is(gMenulist.selectedIndex, 1,
       "The menulist should retain its selected index after a bogus search.");
 
     clear();
     ok(gEditor.getCaretPosition().line == 5 &&
        gEditor.getCaretPosition().col == 8 + token.length + i,
-      "The editor didn't remain at the correct token. (6)");
+      "The editor didn't remain at the correct token. (7)");
 
     isnot(gMenulist.getAttribute("label"), noMatchingScripts,
       "The menulist should not display a notice after the searchbox was emptied.");
     is(gScripts.visibleItemsCount, 2,
       "Not all the scripts are shown after the searchbox was emptied.");
     is(gMenulist.selectedIndex, 1,
       "The menulist should have retained its selected index after the searchbox was emptied of a bogus search.");
 
@@ -166,16 +211,21 @@ function finalCheck(i, string, token) {
 
 function clear() {
   gSearchBox.focus();
   gSearchBox.value = "";
 }
 
 function write(text) {
   clear();
+  append(text);
+}
+
+function append(text) {
+  gSearchBox.focus();
 
   for (let i = 0; i < text.length; i++) {
     EventUtils.sendChar(text[i]);
   }
   info("Editor caret position: " + gEditor.getCaretPosition().toSource() + "\n");
 }
 
 registerCleanupFunction(function() {
--- a/browser/devtools/shared/DeveloperToolbar.jsm
+++ b/browser/devtools/shared/DeveloperToolbar.jsm
@@ -545,45 +545,51 @@ function DT_resetErrorsCount(aTab)
 function OutputPanel(aChromeDoc, aInput, aLoadCallback)
 {
   this._input = aInput;
   this._toolbar = aChromeDoc.getElementById("developer-toolbar");
 
   this._loadCallback = aLoadCallback;
 
   /*
-  <panel id="gcli-output"
+  <tooltip id="gcli-output"
          noautofocus="true"
          noautohide="true"
          class="gcli-panel">
     <html:iframe xmlns:html="http://www.w3.org/1999/xhtml"
                  id="gcli-output-frame"
                  src="chrome://browser/content/devtools/gclioutput.xhtml"
                  flex="1"/>
-  </panel>
+  </tooltip>
   */
-  this._panel = aChromeDoc.createElement("panel");
+
+  // TODO: Switch back from tooltip to panel when metacity focus issue is fixed:
+  // https://bugzilla.mozilla.org/show_bug.cgi?id=780102
+  this._panel = aChromeDoc.createElement("tooltip");
+
   this._panel.id = "gcli-output";
   this._panel.classList.add("gcli-panel");
-  this._panel.setAttribute("noautofocus", "true");
-  this._panel.setAttribute("noautohide", "true");
   this._toolbar.parentElement.insertBefore(this._panel, this._toolbar);
 
   this._frame = aChromeDoc.createElementNS(NS_XHTML, "iframe");
   this._frame.id = "gcli-output-frame";
   this._frame.setAttribute("src", "chrome://browser/content/devtools/gclioutput.xhtml");
   this._frame.setAttribute("flex", "1");
   this._panel.appendChild(this._frame);
 
   this.displayedOutput = undefined;
 
   this._onload = this._onload.bind(this);
   this._frame.addEventListener("load", this._onload, true);
 
   this.loaded = false;
+  this.canHide = false;
+
+  this._onpopuphiding = this._onpopuphiding.bind(this);
+  this._panel.addEventListener("popuphiding", this._onpopuphiding, true);
 }
 
 /**
  * Wire up the element from the iframe, and inform the _loadCallback.
  */
 OutputPanel.prototype._onload = function OP_onload()
 {
   this._frame.removeEventListener("load", this._onload, true);
@@ -602,27 +608,41 @@ OutputPanel.prototype._onload = function
   this.loaded = true;
   if (this._loadCallback) {
     this._loadCallback();
     delete this._loadCallback;
   }
 };
 
 /**
+ * Prevent the popup from hiding if it is not permitted via this.canHide.
+ */
+OutputPanel.prototype._onpopuphiding = function OP_onpopuphiding(aEvent)
+{
+  // TODO: When we switch back from tooltip to panel we can remove this hack:
+  // https://bugzilla.mozilla.org/show_bug.cgi?id=780102
+  if (!this.canHide) {
+    aEvent.preventDefault();
+  }
+};
+
+/**
  * Display the OutputPanel.
  */
 OutputPanel.prototype.show = function OP_show()
 {
   // This is nasty, but displaying the panel causes it to re-flow, which can
   // change the size it should be, so we need to resize the iframe after the
   // panel has displayed
   this._panel.ownerDocument.defaultView.setTimeout(function() {
     this._resize();
   }.bind(this), 0);
 
+  this.canHide = false;
+
   this._panel.openPopup(this._input, "before_start", 0, 0, false, false, null);
   this._resize();
 
   this._input.focus();
 };
 
 /**
  * Internal helper to set the height of the output panel to fit the available
@@ -672,53 +692,59 @@ OutputPanel.prototype.update = function 
   }
 };
 
 /**
  * Detach listeners from the currently displayed Output.
  */
 OutputPanel.prototype.remove = function OP_remove()
 {
+  this.canHide = true;
   this._panel.hidePopup();
 
   if (this.displayedOutput) {
     this.displayedOutput.onChange.remove(this.update, this);
     this.displayedOutput.onClose.remove(this.remove, this);
     delete this.displayedOutput;
   }
 };
 
 /**
  * Detach listeners from the currently displayed Output.
  */
 OutputPanel.prototype.destroy = function OP_destroy()
 {
   this.remove();
 
+  this._panel.removeEventListener("popuphiding", this._onpopuphiding, true);
+
   this._panel.removeChild(this._frame);
   this._toolbar.parentElement.removeChild(this._panel);
 
   delete this._input;
   delete this._toolbar;
+  delete this._onload;
+  delete this._onpopuphiding;
   delete this._panel;
   delete this._frame;
   delete this._content;
   delete this._div;
   delete this.document;
 };
 
 /**
  * Called by GCLI to indicate that we should show or hide one either the
  * tooltip panel or the output panel.
  */
 OutputPanel.prototype._visibilityChanged = function OP_visibilityChanged(aEvent)
 {
   if (aEvent.outputVisible === true) {
     // this.show is called by _outputChanged
   } else {
+    this.canHide = true;
     this._panel.hidePopup();
   }
 };
 
 
 /**
  * Panel to handle tooltips.
  * @param aChromeDoc document from which we can pull the parts we need.
@@ -729,42 +755,49 @@ function TooltipPanel(aChromeDoc, aInput
 {
   this._input = aInput;
   this._toolbar = aChromeDoc.getElementById("developer-toolbar");
   this._dimensions = { start: 0, end: 0 };
 
   this._onload = this._onload.bind(this);
   this._loadCallback = aLoadCallback;
   /*
-  <panel id="gcli-tooltip"
+  <tooltip id="gcli-tooltip"
          type="arrow"
          noautofocus="true"
          noautohide="true"
          class="gcli-panel">
     <html:iframe xmlns:html="http://www.w3.org/1999/xhtml"
                  id="gcli-tooltip-frame"
                  src="chrome://browser/content/devtools/gclitooltip.xhtml"
                  flex="1"/>
-  </panel>
+  </tooltip>
   */
-  this._panel = aChromeDoc.createElement("panel");
+
+  // TODO: Switch back from tooltip to panel when metacity focus issue is fixed:
+  // https://bugzilla.mozilla.org/show_bug.cgi?id=780102
+  this._panel = aChromeDoc.createElement("tooltip");
+
   this._panel.id = "gcli-tooltip";
   this._panel.classList.add("gcli-panel");
-  this._panel.setAttribute("noautofocus", "true");
-  this._panel.setAttribute("noautohide", "true");
   this._toolbar.parentElement.insertBefore(this._panel, this._toolbar);
 
   this._frame = aChromeDoc.createElementNS(NS_XHTML, "iframe");
   this._frame.id = "gcli-tooltip-frame";
   this._frame.setAttribute("src", "chrome://browser/content/devtools/gclitooltip.xhtml");
   this._frame.setAttribute("flex", "1");
   this._panel.appendChild(this._frame);
 
   this._frame.addEventListener("load", this._onload, true);
+
   this.loaded = false;
+  this.canHide = false;
+
+  this._onpopuphiding = this._onpopuphiding.bind(this);
+  this._panel.addEventListener("popuphiding", this._onpopuphiding, true);
 }
 
 /**
  * Wire up the element from the iframe, and inform the _loadCallback.
  */
 TooltipPanel.prototype._onload = function TP_onload()
 {
   this._frame.removeEventListener("load", this._onload, true);
@@ -781,32 +814,46 @@ TooltipPanel.prototype._onload = functio
 
   if (this._loadCallback) {
     this._loadCallback();
     delete this._loadCallback;
   }
 };
 
 /**
+ * Prevent the popup from hiding if it is not permitted via this.canHide.
+ */
+TooltipPanel.prototype._onpopuphiding = function TP_onpopuphiding(aEvent)
+{
+  // TODO: When we switch back from tooltip to panel we can remove this hack:
+  // https://bugzilla.mozilla.org/show_bug.cgi?id=780102
+  if (!this.canHide) {
+    aEvent.preventDefault();
+  }
+};
+
+/**
  * Display the TooltipPanel.
  */
 TooltipPanel.prototype.show = function TP_show(aDimensions)
 {
   if (!aDimensions) {
     aDimensions = { start: 0, end: 0 };
   }
   this._dimensions = aDimensions;
 
   // This is nasty, but displaying the panel causes it to re-flow, which can
   // change the size it should be, so we need to resize the iframe after the
   // panel has displayed
   this._panel.ownerDocument.defaultView.setTimeout(function() {
     this._resize();
   }.bind(this), 0);
 
+  this.canHide = false;
+
   this._resize();
   this._panel.openPopup(this._input, "before_start", aDimensions.start * 10, 0, false, false, null);
   this._input.focus();
 };
 
 /**
  * One option is to spend lots of time taking an average width of characters
  * in the current font, dynamically, and weighting for the frequency of use of
@@ -840,33 +887,37 @@ TooltipPanel.prototype._resize = functio
   this._frame.height = this.document.body.scrollHeight;
 };
 
 /**
  * Hide the TooltipPanel.
  */
 TooltipPanel.prototype.remove = function TP_remove()
 {
+  this.canHide = true;
   this._panel.hidePopup();
 };
 
 /**
  * Hide the TooltipPanel.
  */
 TooltipPanel.prototype.destroy = function TP_destroy()
 {
   this.remove();
 
+  this._panel.removeEventListener("popuphiding", this._onpopuphiding, true);
+
   this._panel.removeChild(this._frame);
   this._toolbar.parentElement.removeChild(this._panel);
 
   delete this._connector;
   delete this._dimensions;
   delete this._input;
   delete this._onload;
+  delete this._onpopuphiding;
   delete this._panel;
   delete this._frame;
   delete this._toolbar;
   delete this._content;
   delete this.document;
   delete this.hintElement;
 };
 
@@ -874,11 +925,12 @@ TooltipPanel.prototype.destroy = functio
  * Called by GCLI to indicate that we should show or hide one either the
  * tooltip panel or the output panel.
  */
 TooltipPanel.prototype._visibilityChanged = function TP_visibilityChanged(aEvent)
 {
   if (aEvent.tooltipVisible === true) {
     this.show(aEvent.dimensions);
   } else {
+    this.canHide = true;
     this._panel.hidePopup();
   }
 };
--- a/browser/modules/webappsUI.jsm
+++ b/browser/modules/webappsUI.jsm
@@ -13,35 +13,40 @@ Cu.import("resource://gre/modules/XPCOMU
 Cu.import("resource://gre/modules/Webapps.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);
 
     switch(aTopic) {
       case "webapps-ask-install":
         let [chromeWin, browser] = this._getBrowserForId(data.oid);
         if (chromeWin)
           this.doInstall(data, browser, chromeWin);
         break;
       case "webapps-launch":
         WebappOSUtils.launch(data);
         break;
+      case "webapps-uninstall":
+        WebappOSUtils.uninstall(data);
+        break;
     }
   },
 
   openURL: function(aUrl, aOrigin) {
     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
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -3306,16 +3306,17 @@ stack[anonid=browserStack][responsivemod
 /* Error counter */
 
 #developer-toolbar-webconsole[error-count]:before {
   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*/
   padding: 1px;
--- a/build/mobile/b2gautomation.py
+++ b/build/mobile/b2gautomation.py
@@ -13,18 +13,18 @@ import sys
 import tempfile
 import time
 
 from automation import Automation
 from devicemanager import DeviceManager, NetworkTools
 from mozprocess import ProcessHandlerMixin
 
 
-class LogcatProc(ProcessHandlerMixin):
-    """Process handler for logcat which puts all output in a Queue.
+class StdOutProc(ProcessHandlerMixin):
+    """Process handler for b2g which puts all output in a Queue.
     """
 
     def __init__(self, cmd, queue, **kwargs):
         self.queue = queue
         kwargs.setdefault('processOutputLine', []).append(self.handle_output)
         ProcessHandlerMixin.__init__(self, cmd, **kwargs)
 
     def handle_output(self, line):
@@ -71,16 +71,30 @@ class B2GRemoteAutomation(Automation):
         # so no copying of os.environ
         if env is None:
             env = {}
 
         # 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.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
+
     def checkForCrashes(self, directory, symbolsPath):
         # XXX: This will have to be updated after crash reporting on b2g
         # is in place.
         dumpDir = tempfile.mkdtemp()
         self._devicemanager.getDirectory(self._remoteProfile + '/minidumps/', dumpDir)
         automationutils.checkForCrashes(dumpDir, symbolsPath, self.lastTestSeen)
         try:
           shutil.rmtree(dumpDir)
@@ -155,17 +169,21 @@ 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.checkCmd(['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()
         rserial, rstatus = self.getDeviceStatus(serial)
         while rstatus != 'device':
             if time.time() - start > 120:
                 # device hasn't come back online in 2 minutes, something's wrong
@@ -178,39 +196,46 @@ class B2GRemoteAutomation(Automation):
         # On a desktop or fennec run, the Process method invokes a gecko
         # process in which to run mochitests.  For B2G, we simply
         # reboot the device (which was configured with a test profile
         # already), wait for B2G to start up, and then navigate to the
         # test url using Marionette.  There doesn't seem to be any way
         # to pass env variables into the B2G process, but this doesn't 
         # seem to matter.
 
-        instance = self.B2GInstance(self._devicemanager)
-
         # reboot device so it starts up with the mochitest profile
         # XXX:  We could potentially use 'stop b2g' + 'start b2g' to achieve
         # a similar effect; will see which is more stable while attempting
         # to bring up the continuous integration.
-        if self._is_emulator:
-            self.restartB2G()
-        else:
+        if not self._is_emulator:
             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")
 
-        # Infrequently, gecko comes up before networking does, so wait a little
-        # bit to give the network time to become available.
-        # XXX:  need a more robust mechanism for this
-        time.sleep(40)
+        # 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
         # existed previously got wiped out by the reboot.
         if not self._is_emulator:
             self._devicemanager.checkCmd(['forward',
                                           'tcp:%s' % self.marionette.port,
                                           'tcp:%s' % self.marionette.port])
 
+        time.sleep(5)
+
         # start a marionette session
         session = self.marionette.start_session()
         if 'b2g' not in session:
             raise Exception("bad session value %s returned by start_session" % session)
 
         # Start the tests by navigating to the mochitest url, by setting it
         # as the 'src' attribute to the homescreen mozbrowser element
         # provided by B2G's shell.js.
@@ -223,46 +248,49 @@ class B2GRemoteAutomation(Automation):
     class B2GInstance(object):
         """Represents a B2G instance running on a device, and exposes
            some process-like methods/properties that are expected by the
            automation.
         """
 
         def __init__(self, dm):
             self.dm = dm
-            self.logcat_proc = None
+            self.stdout_proc = None
             self.queue = Queue.Queue()
 
-            # Launch logcat in a separate thread, and dump all output lines
+            # Launch b2g in a separate thread, and dump all output lines
             # into a queue.  The lines in this queue are
             # retrieved and returned by accessing the stdout property of
             # this class.
             cmd = [self.dm.adbPath]
             if self.dm.deviceSerial:
                 cmd.extend(['-s', self.dm.deviceSerial])
-            cmd.append('logcat')
-            proc = threading.Thread(target=self._save_logcat_proc, args=(cmd, self.queue))
+            cmd.append('shell')
+            cmd.append('/system/bin/b2g.sh')
+            proc = threading.Thread(target=self._save_stdout_proc, args=(cmd, self.queue))
             proc.daemon = True
             proc.start()
 
-        def _save_logcat_proc(self, cmd, queue):
-            self.logcat_proc = LogcatProc(cmd, queue)
-            self.logcat_proc.run()
-            self.logcat_proc.waitForFinish()
-            self.logcat_proc = None
+        def _save_stdout_proc(self, cmd, queue):
+            self.stdout_proc = StdOutProc(cmd, queue)
+            self.stdout_proc.run()
+            if hasattr(self.stdout_proc, 'processOutput'):
+                self.stdout_proc.processOutput()
+            self.stdout_proc.waitForFinish(timeout=10)
+            self.stdout_proc = None
 
         @property
         def pid(self):
             # a dummy value to make the automation happy
             return 0
 
         @property
         def stdout(self):
             # Return any lines in the queue used by the
-            # logcat process handler.
+            # b2g process handler.
             lines = []
             while True:
                 try:
                     lines.append(self.queue.get_nowait())
                 except Queue.Empty:
                     break
             return '\n'.join(lines)
 
--- a/caps/idl/nsIPrincipal.idl
+++ b/caps/idl/nsIPrincipal.idl
@@ -16,17 +16,17 @@ struct JSPrincipals;
 
 interface nsIURI;
 interface nsIContentSecurityPolicy;
 
 [ptr] native JSContext(JSContext);
 [ptr] native JSPrincipals(JSPrincipals);
 [ptr] native PrincipalArray(nsTArray<nsCOMPtr<nsIPrincipal> >);
 
-[scriptable, uuid(8a74b011-667d-4cfa-b2a2-b27582ba5f38)]
+[scriptable, uuid(6df7d16d-5b26-42a1-b1f7-069d46c37aa8)]
 interface nsIPrincipal : nsISerializable
 {
     /**
      * Values of capabilities for each principal. Order is
      * significant: if an operation is performed on a set
      * of capabilities, the minimum is computed.
      */
     const short ENABLE_DENIED                = 1;
@@ -225,23 +225,23 @@ interface nsIPrincipal : nsISerializable
      * The extendedOrigin is intended to be an opaque identifier. It is
      * currently "human-readable" but no callers should assume it will stay
      * as is and it might be crypto-hashed at some point.
      */
     readonly attribute AUTF8String extendedOrigin;
 
     const short APP_STATUS_NOT_INSTALLED = 0;
     const short APP_STATUS_INSTALLED     = 1;
-    const short APP_STATUS_TRUSTED       = 2;
+    const short APP_STATUS_PRIVILEGED    = 2;
     const short APP_STATUS_CERTIFIED     = 3;
 
     /**
      * Shows the status of the app.
      * Can be: APP_STATUS_NOT_INSTALLED, APP_STATUS_INSTALLED,
-     *         APP_STATUS_TRUSTED or APP_STATUS_CERTIFIED.
+     *         APP_STATUS_PRIVILEGED or APP_STATUS_CERTIFIED.
      */
     readonly attribute unsigned short appStatus;
 
     /**
      * Returns the app id the principal is in, or returns
      * nsIScriptSecurityManager::NO_APP_ID if this principal isn't part of an
      * app.
      */
--- a/caps/src/nsPrincipal.cpp
+++ b/caps/src/nsPrincipal.cpp
@@ -1038,17 +1038,17 @@ nsPrincipal::InitFromPersistent(const ch
     mTrusted = aTrusted;
   }
 
   //-- Save the preference name
   mPrefName = aPrefName;
 
   const char* ordinalBegin = PL_strpbrk(aPrefName, "1234567890");
   if (ordinalBegin) {
-    PRIntn n = atoi(ordinalBegin);
+    int n = atoi(ordinalBegin);
     if (sCapabilitiesOrdinal <= n) {
       sCapabilitiesOrdinal = n + 1;
     }
   }
 
   //-- Store the capabilities
   rv = NS_OK;
   if (aGrantedList) {
@@ -1117,17 +1117,17 @@ nsPrincipal::Read(nsIObjectInputStream* 
 
   rv = NS_ReadOptionalCString(aStream, mPrefName);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   const char* ordinalBegin = PL_strpbrk(mPrefName.get(), "1234567890");
   if (ordinalBegin) {
-    PRIntn n = atoi(ordinalBegin);
+    int n = atoi(ordinalBegin);
     if (sCapabilitiesOrdinal <= n) {
       sCapabilitiesOrdinal = n + 1;
     }
   }
 
   bool haveCert;
   rv = aStream->ReadBoolean(&haveCert);
   if (NS_FAILED(rv)) {
deleted file mode 100644
--- a/content/base/public/DirectionalityUtils.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* -*- 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 DirectionalityUtils_h___
-#define DirectionalityUtils_h___
-
-class nsIContent;
-class nsIDocument;
-class nsINode;
-
-namespace mozilla {
-namespace dom {
-class Element;
-} // namespace dom
-} // namespace mozilla
-
-namespace mozilla {
-
-namespace directionality {
-
-enum Directionality {
-  eDir_NotSet = 0,
-  eDir_RTL    = 1,
-  eDir_LTR    = 2
-};
-
-void SetDirectionality(mozilla::dom::Element* aElement, Directionality aDir,
-                       bool aNotify = true);
-
-/**
- * Set the directionality of an element according to the algorithm defined at
- * http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html#the-directionality,
- * not including elements with auto direction.
- *
- * @return the directionality that the element was set to
- */
-Directionality RecomputeDirectionality(mozilla::dom::Element* aElement,
-                                       bool aNotify = true);
-
-/**
- * Set the directionality of any descendants of a node that do not themselves
- * have a dir attribute.
- * For performance reasons we walk down the descendant tree in the rare case
- * of setting the dir attribute, rather than walking up the ancestor tree in
- * the much more common case of getting the element's directionality.
- */
-void SetDirectionalityOnDescendants(mozilla::dom::Element* aElement, 
-                                    Directionality aDir,
-                                    bool aNotify = true);
-
-} // end namespace directionality
-
-} // end namespace mozilla
-
-#endif /* DirectionalityUtils_h___ */
--- a/content/base/public/Element.h
+++ b/content/base/public/Element.h
@@ -5,17 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_Element_h__
 #define mozilla_dom_Element_h__
 
 #include "mozilla/dom/FragmentOrElement.h" // for base class
 #include "nsChangeHint.h"                  // for enum
 #include "nsEventStates.h"                 // for member
-#include "mozilla/dom/DirectionalityUtils.h"
 
 class nsEventStateManager;
 class nsFocusManager;
 class nsGlobalWindow;
 class nsICSSDeclaration;
 class nsISMILAttr;
 
 // Element-specific flags
@@ -212,28 +211,16 @@ public:
 
   /**
    * Returns an atom holding the name of the "class" attribute on this
    * content node (if applicable).  Returns null if there is no
    * "class" attribute for this type of content node.
    */
   virtual nsIAtom *GetClassAttributeName() const = 0;
 
-  inline mozilla::directionality::Directionality GetDirectionality() const {
-    if (HasFlag(NODE_HAS_DIRECTION_RTL)) {
-      return mozilla::directionality::eDir_RTL;
-    }
-
-    if (HasFlag(NODE_HAS_DIRECTION_LTR)) {
-      return mozilla::directionality::eDir_LTR;
-    }
-
-    return mozilla::directionality::eDir_NotSet;
-  }
-
 protected:
   /**
    * Method to get the _intrinsic_ content state of this element.  This is the
    * state that is independent of the element's presentation.  To get the full
    * content state, use State().  See nsEventStates.h for
    * the possible bits that could be set here.
    */
   virtual nsEventStates IntrinsicState() const;
--- a/content/base/public/Makefile.in
+++ b/content/base/public/Makefile.in
@@ -43,17 +43,16 @@ nsReferencedElement.h \
 nsTreeSanitizer.h \
 nsXMLNameSpaceMap.h \
 nsIXFormsUtilityService.h \
 $(NULL)
 
 EXPORTS_NAMESPACES = mozilla/dom mozilla
 
 EXPORTS_mozilla/dom = \
-		DirectionalityUtils.h \
 		Element.h \
 		FragmentOrElement.h \
 		FromParser.h \
 		$(NULL)
 
 EXPORTS_mozilla = \
 		CORSMode.h \
 		$(NULL)
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -18,17 +18,16 @@
 #include "nsILoadContext.h"              // for member (in nsCOMPtr)
 #include "nsILoadGroup.h"                // for member (in nsCOMPtr)
 #include "nsINode.h"                     // for base class
 #include "nsIScriptGlobalObject.h"       // for member (in nsCOMPtr)
 #include "nsIStructuredCloneContainer.h" // for member (in nsCOMPtr)
 #include "nsPIDOMWindow.h"               // for use in inline functions
 #include "nsPropertyTable.h"             // for member
 #include "nsTHashtable.h"                // for member
-#include "mozilla/dom/DirectionalityUtils.h"
 
 class imgIRequest;
 class nsAString;
 class nsBindingManager;
 class nsCSSStyleSheet;
 class nsDOMNavigationTiming;
 class nsEventStates;
 class nsFrameLoader;
@@ -393,20 +392,16 @@ public:
    * callers are expected to take action as needed if they want this
    * change to actually change anything immediately.
    * @see nsBidiUtils.h
    */
   void SetBidiOptions(PRUint32 aBidiOptions)
   {
     mBidiOptions = aBidiOptions;
   }
-
-  inline mozilla::directionality::Directionality GetDocumentDirectionality() {
-    return mDirectionality;
-  }
   
   /**
    * Access HTTP header data (this may also get set from other
    * sources, like HTML META tags).
    */
   virtual void GetHeaderData(nsIAtom* aHeaderField, nsAString& aData) const = 0;
   virtual void SetHeaderData(nsIAtom* aheaderField, const nsAString& aData) = 0;
 
@@ -1853,19 +1848,16 @@ protected:
   // If mIsStaticDocument is true, mOriginalDocument points to the original
   // document.
   nsCOMPtr<nsIDocument> mOriginalDocument;
 
   // The bidi options for this document.  What this bitfield means is
   // defined in nsBidiUtils.h
   PRUint32 mBidiOptions;
 
-  // The root directionality of this document.
-  mozilla::directionality::Directionality mDirectionality;
-
   nsCString mContentLanguage;
 private:
   nsCString mContentType;
 protected:
 
   // The document's security info
   nsCOMPtr<nsISupports> mSecurityInfo;
 
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -140,26 +140,18 @@ enum {
   NODE_HAS_ACCESSKEY           = 0x00020000U,
 
   // Set if the node is handling a click.
   NODE_HANDLING_CLICK          = 0x00040000U,
 
   // Set if the node has had :hover selectors matched against it
   NODE_HAS_RELEVANT_HOVER_RULES = 0x00080000U,
 
-  // Set if the node has right-to-left directionality
-  NODE_HAS_DIRECTION_RTL        = 0x00100000U,
-
-  // Set if the node has left-to-right directionality
-  NODE_HAS_DIRECTION_LTR        = 0x00200000U,
-
-  NODE_ALL_DIRECTION_FLAGS      = NODE_HAS_DIRECTION_LTR | NODE_HAS_DIRECTION_RTL,
-
   // Remaining bits are node type specific.
-  NODE_TYPE_SPECIFIC_BITS_OFFSET =        22
+  NODE_TYPE_SPECIFIC_BITS_OFFSET =        20
 };
 
 /**
  * Class used to detect unexpected mutations. To use the class create an
  * nsMutationGuard on the stack before unexpected mutations could occur.
  * You can then at any time call Mutated to check if any unexpected mutations
  * have occurred.
  *
@@ -1282,18 +1274,16 @@ private:
     // Set if element has pointer locked
     ElementHasPointerLock,
     // Set if the node may have DOMMutationObserver attached to it.
     NodeMayHaveDOMMutationObserver,
     // Set if node is Content
     NodeIsContent,
     // Set if the node has animations or transitions
     ElementHasAnimations,
-    // Set if node has a dir attribute with a valid value (ltr or rtl)
-    NodeHasValidDirAttribute,
     // Guard value
     BooleanFlagCount
   };
 
   void SetBoolFlag(BooleanFlag name, bool value) {
     PR_STATIC_ASSERT(BooleanFlagCount <= 8*sizeof(mBoolFlags));
     mBoolFlags = (mBoolFlags & ~(1 << name)) | (value << name);
   }
@@ -1351,19 +1341,16 @@ public:
   void SetMayHaveDOMMutationObserver()
     { SetBoolFlag(NodeMayHaveDOMMutationObserver, true); }
   bool HasListenerManager() { return HasFlag(NODE_HAS_LISTENERMANAGER); }
   bool HasPointerLock() const { return GetBoolFlag(ElementHasPointerLock); }
   void SetPointerLock() { SetBoolFlag(ElementHasPointerLock); }
   void ClearPointerLock() { ClearBoolFlag(ElementHasPointerLock); }
   bool MayHaveAnimations() { return GetBoolFlag(ElementHasAnimations); }
   void SetMayHaveAnimations() { SetBoolFlag(ElementHasAnimations); }
-  void SetHasValidDir() { SetBoolFlag(NodeHasValidDirAttribute); }
-  void ClearHasValidDir() { ClearBoolFlag(NodeHasValidDirAttribute); }
-  bool HasValidDir() const { return GetBoolFlag(NodeHasValidDirAttribute); }
 protected:
   void SetParentIsContent(bool aValue) { SetBoolFlag(ParentIsContent, aValue); }
   void SetInDocument() { SetBoolFlag(IsInDocument); }
   void SetNodeIsContent() { SetBoolFlag(NodeIsContent); }
   void ClearInDocument() { ClearBoolFlag(IsInDocument); }
   void SetIsElement() { SetBoolFlag(NodeIsElement); }
   void SetHasID() { SetBoolFlag(ElementHasID); }
   void ClearHasID() { ClearBoolFlag(ElementHasID); }
deleted file mode 100644
--- a/content/base/src/DirectionalityUtils.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 sw=2 et tw=78: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "mozilla/dom/DirectionalityUtils.h"
-#include "nsINode.h"
-#include "nsIContent.h"
-#include "nsIDocument.h"
-#include "mozilla/dom/Element.h"
-#include "nsIDOMNodeFilter.h"
-#include "nsTreeWalker.h"
-#include "nsIDOMHTMLDocument.h"
-
-
-namespace mozilla {
-
-namespace directionality {
-
-typedef mozilla::dom::Element Element;
-
-void
-SetDirectionality(Element* aElement, Directionality aDir, bool aNotify)
-{
-  aElement->UnsetFlags(NODE_ALL_DIRECTION_FLAGS);
-  switch (aDir) {
-    case eDir_RTL:
-      aElement->SetFlags(NODE_HAS_DIRECTION_RTL);
-      break;
-    case eDir_LTR:
-      aElement->SetFlags(NODE_HAS_DIRECTION_LTR);
-      break;
-    default:
-      break;
-  }
-
-  aElement->UpdateState(aNotify);
-}
-
-Directionality
-RecomputeDirectionality(Element* aElement, bool aNotify)
-{
-  Directionality dir = eDir_LTR;
-
-  if (aElement->HasValidDir()) {
-    dir = aElement->GetDirectionality();
-  } else {
-    Element* parent = aElement->GetElementParent();
-    if (parent) {
-      // If the element doesn't have an explicit dir attribute with a valid
-      // value, the directionality is the same as the parent element (but
-      // don't propagate the parent directionality if it isn't set yet).
-      Directionality parentDir = parent->GetDirectionality();
-      if (parentDir != eDir_NotSet) {
-        dir = parentDir;
-      }
-    } else {
-      // If there is no parent element, the directionality is the same as the
-      // document direction.
-      Directionality documentDir =
-        aElement->OwnerDoc()->GetDocumentDirectionality();
-      if (documentDir != eDir_NotSet) {
-        dir = documentDir;
-      }
-    }
-    
-    SetDirectionality(aElement, dir, aNotify);
-  }
-  return dir;
-}
-
-void
-SetDirectionalityOnDescendants(Element* aElement, Directionality aDir,
-                               bool aNotify)
-{
-  for (nsIContent* child = aElement->GetFirstChild(); child; ) {
-    if (!child->IsElement()) {
-      child = child->GetNextNode(aElement);
-      continue;
-    }
-
-    Element* element = child->AsElement();
-    if (element->HasValidDir()) {
-      child = child->GetNextNonChildNode(aElement);
-      continue;
-    }
-    SetDirectionality(element, aDir, aNotify);
-    child = child->GetNextNode(aElement);
-  }
-}
-
-} // end namespace directionality
-
-} // end namespace mozilla
-
--- a/content/base/src/Makefile.in
+++ b/content/base/src/Makefile.in
@@ -48,17 +48,16 @@ EXPORTS_NAMESPACES = mozilla/dom
 EXPORTS_mozilla/dom = \
   Link.h \
   $(NULL)
 
 LOCAL_INCLUDES = \
 		$(NULL)
 
 CPPSRCS		= \
-		DirectionalityUtils.cpp \
 		nsAtomListUtils.cpp \
 		nsAttrAndChildArray.cpp \
 		nsAttrValue.cpp \
 		nsAttrValueOrString.cpp \
 		nsCCUncollectableMarker.cpp \
 		nsChannelPolicy.cpp \
 		nsCommentNode.cpp \
 		nsContentAreaDragDrop.cpp \
--- a/content/base/src/nsContentSink.h
+++ b/content/base/src/nsContentSink.h
@@ -48,17 +48,17 @@ class Loader;
 #ifdef DEBUG
 
 extern PRLogModuleInfo* gContentSinkLogModuleInfo;
 
 #define SINK_TRACE_CALLS              0x1
 #define SINK_TRACE_REFLOW             0x2
 #define SINK_ALWAYS_REFLOW            0x4
 
-#define SINK_LOG_TEST(_lm, _bit) (PRIntn((_lm)->level) & (_bit))
+#define SINK_LOG_TEST(_lm, _bit) (int((_lm)->level) & (_bit))
 
 #define SINK_TRACE(_lm, _bit, _args) \
   PR_BEGIN_MACRO                     \
     if (SINK_LOG_TEST(_lm, _bit)) {  \
       PR_LogPrint _args;             \
     }                                \
   PR_END_MACRO
 
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -86,17 +86,16 @@
 // for radio group stuff
 #include "nsIDOMHTMLInputElement.h"
 #include "nsIRadioVisitor.h"
 #include "nsIFormControl.h"
 
 #include "nsXMLEventsManager.h"
 
 #include "nsBidiUtils.h"
-#include "mozilla/dom/DirectionalityUtils.h"
 
 #include "nsIDOMUserDataHandler.h"
 #include "nsIDOMXPathEvaluator.h"
 #include "nsIXPathEvaluatorInternal.h"
 #include "nsIParserService.h"
 #include "nsContentCreatorFunctions.h"
 
 #include "nsIScriptContext.h"
@@ -166,17 +165,16 @@
 
 #include "mozilla/Preferences.h"
 
 #include "imgILoader.h"
 #include "nsWrapperCacheInlines.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
-using namespace mozilla::directionality;
 
 typedef nsTArray<Link*> LinkArray;
 
 // Reference to the document which requested DOM full-screen mode.
 nsWeakPtr nsDocument::sFullScreenDoc = nullptr;
 
 // Reference to the root document of the branch containing the document
 // which requested DOM full-screen mode.
@@ -1507,18 +1505,17 @@ nsIDocument::nsIDocument()
     mRemovedFromDocShell(false),
     // mAllowDNSPrefetch starts true, so that we can always reliably && it
     // with various values that might disable it.  Since we never prefetch
     // unless we get a window, and in that case the docshell value will get
     // &&-ed in, this is safe.
     mAllowDNSPrefetch(true),
     mIsBeingUsedAsImage(false),
     mHasLinksToUpdate(false),
-    mPartID(0),
-    mDirectionality(eDir_LTR)
+    mPartID(0)
 {
   SetInDocument();
 }
 
 // NOTE! nsDocument::operator new() zeroes out all members, so don't
 // bother initializing members to 0.
 
 nsDocument::nsDocument(const char* aContentType)
@@ -5581,25 +5578,16 @@ nsDocument::SetDir(const nsAString& aDir
         if (shell) {
           nsPresContext *context = shell->GetPresContext();
           NS_ENSURE_TRUE(context, NS_ERROR_UNEXPECTED);
           context->SetBidi(options, true);
         } else {
           // No presentation; just set it on ourselves
           SetBidiOptions(options);
         }
-        Directionality dir = elt->mValue == IBMBIDI_TEXTDIRECTION_RTL ?
-                               eDir_RTL : eDir_LTR;
-        SetDocumentDirectionality(dir);
-        // Set the directionality of the root element and its descendants, if any
-        Element* rootElement = GetRootElement();
-        if (rootElement) {
-          SetDirectionality(rootElement, dir, true);
-          SetDirectionalityOnDescendants(rootElement, dir);
-        }
       }
 
       break;
     }
   }
 
   return NS_OK;
 }
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -1043,22 +1043,16 @@ protected:
   void DestroyElementMaps();
 
   // Refreshes the hrefs of all the links in the document.
   void RefreshLinkHrefs();
 
   nsIContent* GetFirstBaseNodeWithHref();
   nsresult SetFirstBaseNodeWithHref(nsIContent *node);
 
-  inline void
-  SetDocumentDirectionality(mozilla::directionality::Directionality aDir)
-  {
-    mDirectionality = aDir;
-  }
-
   // Get the first <title> element with the given IsNodeOfType type, or
   // return null if there isn't one
   nsIContent* GetTitleContent(PRUint32 aNodeType);
   // Find the first "title" element in the given IsNodeOfType type and
   // append the concatenation of its text node children to aTitle. Do
   // nothing if there is no such element.
   void GetTitleFromElement(PRUint32 aNodeType, nsAString& aTitle);
 
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -8,16 +8,17 @@
  * Class for managing loading of a subframe (creation of the docshell,
  * handling of loads in it, recursion-checking).
  */
 
 #include "base/basictypes.h"
 
 #include "prenv.h"
 
+#include "mozIApplication.h"
 #include "nsIDOMHTMLIFrameElement.h"
 #include "nsIDOMHTMLFrameElement.h"
 #include "nsIDOMMozBrowserFrame.h"
 #include "nsIDOMWindow.h"
 #include "nsIPresShell.h"
 #include "nsIContent.h"
 #include "nsIContentViewer.h"
 #include "nsIDocument.h"
@@ -26,16 +27,17 @@
 #include "nsPIDOMWindow.h"
 #include "nsIWebNavigation.h"
 #include "nsIWebProgress.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIDocShellTreeNode.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDocShellLoadInfo.h"
+#include "nsIDOMApplicationRegistry.h"
 #include "nsIBaseWindow.h"
 #include "nsContentUtils.h"
 #include "nsIXPConnect.h"
 #include "nsIJSContextStack.h"
 #include "nsUnicharUtils.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIScrollable.h"
@@ -1968,64 +1970,60 @@ nsFrameLoader::TryRemoteBrowser()
   nsCOMPtr<nsIXULWindow> window(do_GetInterface(parentOwner));
   if (!window) {
     return false;
   }
   if (NS_FAILED(window->GetChromeFlags(&chromeFlags))) {
     return false;
   }
 
-  PRUint32 appId = 0;
   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);
 
       nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
       if (!appsService) {
         NS_ERROR("Apps Service is not available!");
         return false;
       }
 
-      appsService->GetAppLocalIdByManifestURL(manifest, &appId);
-
-      // If the frame is actually an app, we should not mark it as a browser.
-      if (appId != nsIScriptSecurityManager::NO_APP_ID) {
+      nsCOMPtr<mozIDOMApplication> domApp;
+      appsService->GetAppByManifestURL(manifest, getter_AddRefs(domApp));
+      // If the frame is actually an app, we should not mark it as a
+      // browser.  This is to identify the data store: since <app>s
+      // and <browser>s-within-<app>s have different stores, we want
+      // to ensure the <app> uses its store, not the one for its
+      // <browser>s.
+      app = do_QueryInterface(domApp);
+      if (app) {
         isBrowserElement = false;
       }
     }
   }
 
-  // If our owner has no app manifest URL, then this is equivalent to
-  // ContentParent::GetNewOrUsed().
-  nsAutoString appManifest;
-  GetOwnerAppManifestURL(appManifest);
-  ContentParent* parent = ContentParent::GetForApp(appManifest);
-
-  NS_ASSERTION(parent->IsAlive(), "Process parent should be alive; something is very wrong!");
-  mRemoteBrowser = parent->CreateTab(chromeFlags, isBrowserElement, appId);
-  if (mRemoteBrowser) {
+  if ((mRemoteBrowser = ContentParent::CreateBrowser(app, isBrowserElement))) {
     nsCOMPtr<nsIDOMElement> element = do_QueryInterface(mOwnerContent);
     mRemoteBrowser->SetOwnerElement(element);
 
     nsCOMPtr<nsIDocShellTreeItem> rootItem;
     parentAsItem->GetRootTreeItem(getter_AddRefs(rootItem));
     nsCOMPtr<nsIDOMWindow> rootWin = do_GetInterface(rootItem);
     nsCOMPtr<nsIDOMChromeWindow> rootChromeWin = do_QueryInterface(rootWin);
     NS_ABORT_IF_FALSE(rootChromeWin, "How did we not get a chrome window here?");
 
     nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin;
     rootChromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin));
     mRemoteBrowser->SetBrowserDOMWindow(browserDOMWin);
-    
-    mChildHost = parent;
+
+    mChildHost = static_cast<ContentParent*>(mRemoteBrowser->Manager());
   }
   return true;
 }
 
 mozilla::dom::PBrowserParent*
 nsFrameLoader::GetRemoteBrowser()
 {
   return mRemoteBrowser;
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -46,17 +46,16 @@
 #include "nsDOMTokenList.h"
 #include "nsXBLPrototypeBinding.h"
 #include "nsDOMError.h"
 #include "nsDOMString.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsMutationEvent.h"
 #include "nsNodeUtils.h"
-#include "mozilla/dom/DirectionalityUtils.h"
 #include "nsDocument.h"
 #include "nsAttrValueOrString.h"
 #ifdef MOZ_XUL
 #include "nsXULElement.h"
 #endif /* MOZ_XUL */
 #include "nsFrameManager.h"
 #include "nsFrameSelection.h"
 #ifdef DEBUG
@@ -124,17 +123,16 @@
 #include "mozilla/Telemetry.h"
 
 #include "mozilla/CORSMode.h"
 
 #include "nsStyledElement.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
-using namespace mozilla::directionality;
 
 nsEventStates
 Element::IntrinsicState() const
 {
   return IsEditable() ? NS_EVENT_STATE_MOZ_READWRITE :
                         NS_EVENT_STATE_MOZ_READONLY;
 }
 
@@ -1355,23 +1353,16 @@ nsGenericElement::BindToTree(nsIDocument
                NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES |
                // And the restyle bits
                ELEMENT_ALL_RESTYLE_FLAGS);
   } else {
     // If we're not in the doc, update our subtree pointer.
     SetSubtreeRootPointer(aParent->SubtreeRoot());
   }
 
-  // This has to be here, rather than in nsGenericHTMLElement::BindToTree, 
-  //  because it has to happen after updating the parent pointer, but before
-  //  recursively binding the kids.
-  if (IsHTML()) {
-    RecomputeDirectionality(this, false);
-  }
-
   // If NODE_FORCE_XBL_BINDINGS was set we might have anonymous children
   // that also need to be told that they are moving.
   nsresult rv;
   if (hadForceXBL) {
     nsBindingManager* bmgr = OwnerDoc()->BindingManager();
 
     // First check if we have a binding...
     nsXBLBinding* contBinding =
@@ -1547,23 +1538,16 @@ nsGenericElement::UnbindFromTree(bool aD
 #endif
   {
     nsDOMSlots *slots = GetExistingDOMSlots();
     if (slots) {
       slots->mBindingParent = nullptr;
     }
   }
 
-  // This has to be here, rather than in nsGenericHTMLElement::UnbindFromTree, 
-  //  because it has to happen after unsetting the parent pointer, but before
-  //  recursively unbinding the kids.
-  if (IsHTML()) {
-    RecomputeDirectionality(this, false);
-  }
-
   if (aDeep) {
     // Do the kids. Don't call GetChildCount() here since that'll force
     // XUL to generate template children, which there is no need for since
     // all we're going to do is unbind them anyway.
     PRUint32 i, n = mAttrsAndChildren.ChildCount();
 
     for (i = 0; i < n; ++i) {
       // Note that we pass false for aNullParent here, since we don't want
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -265,17 +265,16 @@ GK_ATOM(details, "details")
 GK_ATOM(deviceAspectRatio, "device-aspect-ratio")
 GK_ATOM(deviceHeight, "device-height")
 GK_ATOM(deviceWidth, "device-width")
 GK_ATOM(dfn, "dfn")
 GK_ATOM(dialog, "dialog")
 GK_ATOM(difference, "difference")
 GK_ATOM(digit, "digit")
 GK_ATOM(dir, "dir")
-GK_ATOM(directionality, "directionality")
 GK_ATOM(disableOutputEscaping, "disable-output-escaping")
 GK_ATOM(disabled, "disabled")
 GK_ATOM(display, "display")
 GK_ATOM(distinct, "distinct")
 GK_ATOM(div, "div")
 GK_ATOM(dl, "dl")
 GK_ATOM(doctypePublic, "doctype-public")
 GK_ATOM(doctypeSystem, "doctype-system")
--- a/content/base/src/nsNodeInfoManager.cpp
+++ b/content/base/src/nsNodeInfoManager.cpp
@@ -49,17 +49,17 @@ nsNodeInfoManager::GetNodeInfoInnerHashV
     // the moment because node->mName->hash() is not the same as
     // HashString(*(node->mNameString)).  See bug 732815.
     return HashString(nsDependentAtomString(node->mName));
   }
   return HashString(*(node->mNameString));
 }
 
 
-PRIntn
+int
 nsNodeInfoManager::NodeInfoInnerKeyCompare(const void *key1, const void *key2)
 {
   NS_ASSERTION(key1 && key2, "Null key passed to NodeInfoInnerKeyCompare!");
 
   const nsINodeInfo::nsNodeInfoInner *node1 =
     reinterpret_cast<const nsINodeInfo::nsNodeInfoInner *>(key1);
   const nsINodeInfo::nsNodeInfoInner *node2 =
     reinterpret_cast<const nsINodeInfo::nsNodeInfoInner *>(key2);
@@ -178,18 +178,18 @@ nsNodeInfoManager::Init(nsIDocument *aDo
     PR_LOG(gNodeInfoManagerLeakPRLog, PR_LOG_DEBUG,
            ("NODEINFOMANAGER %p Init document=%p", this, aDocument));
 #endif
 
   return NS_OK;
 }
 
 // static
-PRIntn
-nsNodeInfoManager::DropNodeInfoDocument(PLHashEntry *he, PRIntn hashIndex, void *arg)
+int
+nsNodeInfoManager::DropNodeInfoDocument(PLHashEntry *he, int hashIndex, void *arg)
 {
   static_cast<nsINodeInfo*>(he->value)->mDocument = nullptr;
   return HT_ENUMERATE_NEXT;
 }
 
 void
 nsNodeInfoManager::DropDocumentReference()
 {
--- a/content/base/src/nsNodeInfoManager.h
+++ b/content/base/src/nsNodeInfoManager.h
@@ -111,19 +111,19 @@ protected:
                                         const nsAString& );
 
   /**
    * Sets the principal of the document this nodeinfo manager belongs to.
    */
   void SetDocumentPrincipal(nsIPrincipal *aPrincipal);
 
 private:
-  static PRIntn NodeInfoInnerKeyCompare(const void *key1, const void *key2);
+  static int NodeInfoInnerKeyCompare(const void *key1, const void *key2);
   static PLHashNumber GetNodeInfoInnerHashValue(const void *key);
-  static PRIntn DropNodeInfoDocument(PLHashEntry *he, PRIntn hashIndex,
+  static int DropNodeInfoDocument(PLHashEntry *he, int hashIndex,
                                      void *arg);
 
   PLHashTable *mNodeInfoHash;
   nsIDocument *mDocument; // WEAK
   PRUint32 mNonDocumentNodeInfos;
   nsIPrincipal *mPrincipal; // STRONG, but not nsCOMPtr to avoid include hell
                             // while inlining DocumentPrincipal().  Never null
                             // after Init() succeeds.
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -376,18 +376,16 @@ MOCHITEST_FILES_B = \
 		file_csp_redirects_page.sjs \
 		file_csp_redirects_main.html \
 		file_csp_redirects_resource.sjs \
 		test_bug346485.html \
 		test_bug560780.html \
 		test_bug562652.html \
 		test_bug562137.html \
 		file_bug562137.txt \
-		test_bug562169-1.html \
-		test_bug562169-2.html \
 		test_bug548193.html \
 		file_bug548193.sjs \
 		test_html_colors_quirks.html \
 		test_html_colors_standards.html \
 		test_bug300992.html \
 		test_websocket_hello.html \
 		file_websocket_hello_wsh.py \
 		test_websocket_basic.html \
--- a/content/base/test/test_bug345339.html
+++ b/content/base/test/test_bug345339.html
@@ -27,25 +27,24 @@ function afterLoad() {
     var iframeDoc = $("testframe").contentDocument;
 
     /* change all the form controls */
     iframeDoc.getElementById("select").selectedIndex = 1;
     iframeDoc.getElementById("radio2").checked = true;
     iframeDoc.getElementById("password").value = "123456";
     iframeDoc.getElementById("hidden").value = "gecko";
 
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var file = Components.classes["@mozilla.org/file/directory_service;1"]
+    var file = SpecialPowers.wrap(Components).classes["@mozilla.org/file/directory_service;1"]
              .getService(Components.interfaces.nsIProperties)
              .get("TmpD", Components.interfaces.nsILocalFile);
     file.append("345339_test.file");
     file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0666);
     filePath = file.path;
 
-    iframeDoc.getElementById("file").value = filePath;
+    SpecialPowers.wrap(iframeDoc).getElementById("file").value = filePath;
 
     /* Reload the page */
     $("testframe").setAttribute("onload", "afterReload()");
     iframeDoc.location.reload();
 }
 
 addLoadEvent(afterLoad);
 
@@ -57,18 +56,17 @@ function afterReload() {
     is(iframeDoc.getElementById("radio1").checked, false,
        "radio button #1 value preserved");
     is(iframeDoc.getElementById("radio2").checked, true,
        "radio button #2 value preserved");
     isnot(iframeDoc.getElementById("password").value, "123456",
        "password field value forgotten");
     is(iframeDoc.getElementById("hidden").value, "gecko",
        "hidden field value preserved");
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    is(iframeDoc.getElementById("file").value, filePath,
+    is(SpecialPowers.wrap(iframeDoc).getElementById("file").value, filePath,
        "file field value preserved");
 
     SimpleTest.finish();
 }
 </script>
 </pre>
 </body>
 </html>
--- a/content/base/test/test_bug372964.html
+++ b/content/base/test/test_bug372964.html
@@ -26,19 +26,20 @@ var eventHandlerCallCount = 0;
 function eventHandler(evt) {
   ++eventHandlerCallCount;
   is(evt.type, expectedEventType, "Wrong event type");
   is(evt.isTrusted, shouldBeTrusted, "Wrong .isTrusted");
 }
 
 function test(trusted, type, removeAddedListener, removeSetListener, allowUntrusted) {
   if (trusted) {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+    var x1 = SpecialPowers.wrap(new XMLHttpRequest());
+  } else {
+    x1 = new XMLHttpRequest();
   }
-  var x1 = new XMLHttpRequest();
 
   var handlerCount = 0;
   if (trusted || allowUntrusted || allowUntrusted == undefined) {
     ++handlerCount;
   }
 
   if (allowUntrusted == undefined) {
     // Test .addEventListener with 3 parameters.
--- a/content/base/test/test_bug380418.html
+++ b/content/base/test/test_bug380418.html
@@ -17,24 +17,23 @@
 
 	SimpleTest.waitForExplicitFinish();
 	
 	var request = new XMLHttpRequest();
 	request.open("GET", window.location.href, false);
 	request.send(null);
 	
 	// Try reading headers in privileged context
-	netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-	is(request.getResponseHeader("Set-Cookie"), "test", "Reading Set-Cookie response header in privileged context");
-	is(request.getResponseHeader("Set-Cookie2"), "test2", "Reading Set-Cookie2 response header in privileged context");
-	is(request.getResponseHeader("X-Dummy"), "test", "Reading X-Dummy response header in privileged context");
+	is(SpecialPowers.wrap(request).getResponseHeader("Set-Cookie"), "test", "Reading Set-Cookie response header in privileged context");
+	is(SpecialPowers.wrap(request).getResponseHeader("Set-Cookie2"), "test2", "Reading Set-Cookie2 response header in privileged context");
+	is(SpecialPowers.wrap(request).getResponseHeader("X-Dummy"), "test", "Reading X-Dummy response header in privileged context");
 	
-	ok(/\bSet-Cookie:/i.test(request.getAllResponseHeaders()), "Looking for Set-Cookie in all response headers in privileged context");
-	ok(/\bSet-Cookie2:/i.test(request.getAllResponseHeaders()), "Looking for Set-Cookie2 in all response headers in privileged context");
-	ok(/\bX-Dummy:/i.test(request.getAllResponseHeaders()), "Looking for X-Dummy in all response headers in privileged context");
+	ok(/\bSet-Cookie:/i.test(SpecialPowers.wrap(request).getAllResponseHeaders()), "Looking for Set-Cookie in all response headers in privileged context");
+	ok(/\bSet-Cookie2:/i.test(SpecialPowers.wrap(request).getAllResponseHeaders()), "Looking for Set-Cookie2 in all response headers in privileged context");
+	ok(/\bX-Dummy:/i.test(SpecialPowers.wrap(request).getAllResponseHeaders()), "Looking for X-Dummy in all response headers in privileged context");
 	
 	// Try reading headers in unprivileged context
 	setTimeout(function() {
 	  is(request.getResponseHeader("Set-Cookie"), null, "Reading Set-Cookie response header in unprivileged context");
 	  is(request.getResponseHeader("Set-Cookie2"), null, "Reading Set-Cookie2 response header in unprivileged context");
 	  is(request.getResponseHeader("X-Dummy"), "test", "Reading X-Dummy response header in unprivileged context");
 	  
 	  ok(!/\bSet-Cookie:/i.test(request.getAllResponseHeaders()), "Looking for Set-Cookie in all response headers in unprivileged context");
--- a/content/base/test/test_bug422537.html
+++ b/content/base/test/test_bug422537.html
@@ -14,38 +14,40 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 422537 **/
-netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-
-var isupports_string = Components.classes["@mozilla.org/supports-string;1"]
-                                 .createInstance(Components.interfaces.nsISupportsString);
+var isupports_string = SpecialPowers.wrap(Components)
+                                    .classes["@mozilla.org/supports-string;1"]
+                                    .createInstance(Components.interfaces.nsISupportsString);
 isupports_string.data = "foo";
 
 const url = "http://mochi.test:8888";
 var body = [
   document,
   "foo",
   isupports_string
 ];
 
 for each (var i in body) {
   var xhr = new XMLHttpRequest();
   xhr.open("POST", url, true);
-  xhr.send(i);
-  var chan = SpecialPowers.unwrap(SpecialPowers.wrap(xhr).channel);
-  if (!(chan instanceof Components.interfaces.nsIUploadChannel))
+  if (i == isupports_string)
+    SpecialPowers.wrap(xhr).send(i);
+  else
+    xhr.send(i);
+  var chan = SpecialPowers.wrap(xhr).channel;
+  if (!SpecialPowers.call_Instanceof(chan, Components.interfaces.nsIUploadChannel))
     throw "Must be an upload channel";
   var stream = chan.uploadStream;
-  if (!stream || !(stream instanceof Components.interfaces.nsISeekableStream))
+  if (!stream || !SpecialPowers.call_Instanceof(stream, Components.interfaces.nsISeekableStream))
     throw "Stream must be seekable";
   // the following is a no-op, but should not throw an exception
   stream.seek(Components.interfaces.nsISeekableStream.NS_SEEK_CUR, 0);
 }
 
 ok(true, "xhr is seekable");
 
 </script>
deleted file mode 100644
--- a/content/base/test/test_bug562169-1.html
+++ /dev/null
@@ -1,44 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=562169
--->
-<head>
-  <meta charset="utf-8">
-  <title>Test for Bug 562169</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=562169">Mozilla Bug 562169</a>
-<p id="display"></p>
-<div id="content" style="display: none">
- <div dir="rtl" id="z"></div>  
-</div>
-<pre id="test">
-<script type="application/javascript">
-
-/** Test for Bug 562169 **/
-/** Test that adding an child to an element with dir="rtl" makes the
-      child have rtl directionality, and removing the child makes it
-     go back to ltr directionality **/
-
-function checkSelector(element, expectedDir, expectedChild)
-{
-    ok(element.querySelector(":dir("+expectedDir+")") == expectedChild,
-       "direction should be " + expectedDir);
-}
-
-var x = document.createElement("div");
-var y = document.createElement("div");
-x.appendChild(y);
-checkSelector(x, "ltr", y);
-$(z).appendChild(x);
-checkSelector(x, "rtl", y);
-$(z).removeChild(x);
-checkSelector(x, "ltr", y);
-
-</script>
-</pre>
-</body>
-</html>
deleted file mode 100644
--- a/content/base/test/test_bug562169-2.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=562169
--->
-<head>
-  <meta charset="utf-8">
-  <title>Test for Bug 562169</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=562169">Mozilla Bug 562169</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-</div>
-<pre id="test">
-<script type="application/javascript">
-
-/** Test for Bug 562169 **/
-/** Test that a newly created element has ltr directionality **/
-
-ok(document.createElement("div").mozMatchesSelector(":dir(ltr)"),
-   "Element should be ltr on creation");
-
-</script>
-</pre>
-</body>
-</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/crashtests/727547.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<canvas></canvas>
+<script>
+var canvas = document.body.firstChild,
+    gl = canvas.getContext("experimental-webgl");
+gl.texImage2D(0, 0, 0, 0, 0, { width: 10, height: 10, data: 7 });
+</script>
new file mode 100644
--- /dev/null
+++ b/content/canvas/crashtests/780392-1.html
@@ -0,0 +1,10 @@
+<!doctype HTML>
+<html>
+<body>
+<canvas id="c" width="10000" height="10000"></canvas>
+<script>
+var ctx = document.getElementById("c").getContext("2d");
+ctx.fillText("Hello world!", 50, 50);
+</script>
+</body>
+</html>
--- a/content/canvas/crashtests/crashtests.list
+++ b/content/canvas/crashtests/crashtests.list
@@ -1,13 +1,15 @@
 load 360293-1.html
 load 421715-1.html
 load 553938-1.html
 load 647480.html
+load 727547.html
 load 0px-size-font-667225.html
 load texImage2D.html
 load 729116.html
 load 745699-1.html
 load 746813-1.html
 # this test crashes in a bunch places still
 #load 745818-large-source.html
 load 743499-negative-size.html
 load 767337-1.html
+load 780392-1.html
--- a/content/canvas/test/test_canvas.html
+++ b/content/canvas/test/test_canvas.html
@@ -1,79 +1,76 @@
 <!DOCTYPE HTML>
 <title>Canvas Tests</title>
 <script src="/tests/SimpleTest/SimpleTest.js"></script>
 <link rel="stylesheet" href="/tests/SimpleTest/test.css">
 <body>
 <script>
 
 SimpleTest.waitForExplicitFinish();
+const Cc = SpecialPowers.wrap(Components).classes;
+const Cr = SpecialPowers.wrap(Components).results;
 
 function IsD2DEnabled() {
     var enabled = false;
 
     try {
-        netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-        enabled = Components.classes["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).D2DEnabled;
+        enabled = Cc["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).D2DEnabled;
     } catch(e) {}
     
     return enabled;
 }
 
 function IsLinux() {
     return navigator.platform.indexOf("Linux") == 0;
 }
 
 function IsMacOSX10_5orOlder() {
     var is105orOlder = false;
 
     if (navigator.platform.indexOf("Mac") == 0) {
-        netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-        var version = Components.classes["@mozilla.org/system-info;1"]
-                            .getService(Components.interfaces.nsIPropertyBag2)
-                            .getProperty("version");
+        var version = Cc["@mozilla.org/system-info;1"]
+                        .getService(Components.interfaces.nsIPropertyBag2)
+                        .getProperty("version");
         // the next line is correct: Mac OS 10.6 corresponds to Darwin version 10 !
         // Mac OS 10.5 would be Darwin version 9. the |version| string we've got here
         // is the Darwin version.
         is105orOlder = (parseFloat(version) < 10.0);
     }
     return is105orOlder;
 }
 
 
 function IsAzureEnabled() {
   var enabled = false;
 
   try {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var backend = Components.classes["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).getInfo().AzureCanvasBackend;
+    var backend = Cc["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).getInfo().AzureCanvasBackend;
     enabled = (backend != "none");
   } catch (e) { }
 
   return enabled;
 }
 
 function IsAzureSkia() {
   var enabled = false;
   
   try {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var backend = Components.classes["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).getInfo().AzureCanvasBackend;
+    var backend = Cc["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).getInfo().AzureCanvasBackend;
     enabled = (backend == "skia");
   } catch (e) { }
 
   return enabled;
 }
 
 function IsAzureCairo() {
   var enabled = false;
   
   try {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var backend = Components.classes["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).getInfo().AzureCanvasBackend;
+    var backend = Cc["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).getInfo().AzureCanvasBackend;
     enabled = (backend == "cairo");
   } catch (e) { }
 
   return enabled;
 }
 
 </script>
 <!-- Includes all the tests in the content/canvas/tests except for test_bug397524.html -->
@@ -121,17 +118,18 @@ ok(ctx.canvas === canvas, "ctx.canvas ==
 <!-- [[[ test_2d.clearRect.basic.html ]]] -->
 
 <p>Canvas test: 2d.clearRect.basic</p>
 <canvas id="c3" width="100" height="50" style="background: #0f0"><p class="fallback">FAIL (fallback content)</p></canvas>
 <script>
 function isPixel(ctx, x,y, r,g,b,a, d) {
 	var pos = x + "," + y;
 	var colour = r + "," + g + "," + b + "," + a;
-    var pixel = ctx.getImageData(x, y, 1, 1);
+    var pixel = SpecialPowers.unwrap(SpecialPowers.wrap(ctx)
+                                                  .getImageData(x, y, 1, 1));
     var pr = pixel.data[0],
         pg = pixel.data[1],
         pb = pixel.data[2],
         pa = pixel.data[3];
     ok(r-d <= pr && pr <= r+d &&
        g-d <= pg && pg <= g+d &&
        b-d <= pb && pb <= b+d &&
        a-d <= pa && pa <= a+d,
@@ -19799,19 +19797,18 @@ function test_bug397524() {
 
 <!-- [[[ test_bug405982.html ]]] -->
 
 <p>Canvas test: toDataURL.png</p>
 <canvas id="c614" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
 <script>
 function test_bug405982() {
 
-var canvas = document.getElementById('c614');
-var ctx = canvas.getContext('2d');
-netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+var canvas = SpecialPowers.wrap(document.getElementById('c614'));
+var ctx = canvas.getContext('2d');
 
 var _threw = false;
 try {
   var data = canvas.toDataURL('image/png', 'quality=100');
 }
 catch (e) {
   _threw = true;
 }
@@ -21118,17 +21115,16 @@ ctx667.fillStyle = 'rgba(12, 16, 244, 0.
 ctx667.fillRect(75, 0, 25, 25);
 var img = new Image();
 deferTest();
 img.onload = wrapFunction(function ()
 {
     ctx667.drawImage(img, 0, 25);
     // (The alpha values do not really survive float->int conversion, so just
     // do approximate comparisons)
-    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
     isPixel(ctx667, 12,40, 1,3,254,255, 0);
     isPixel(ctx667, 37,40, 8,252,248,191, 2);
     isPixel(ctx667, 62,40, 6,10,250,127, 4);
     isPixel(ctx667, 87,40, 12,16,244,63, 8);
 });
 img.src = canvas667.toDataURL();
 
 
@@ -21245,17 +21241,16 @@ ctx672.fillRect(0, 40, 100, 10);
 var data = canvas672.toDataURL();
 ctx672.fillStyle = '#f00';
 ctx672.fillRect(0, 0, 100, 50);
 var img = new Image();
 deferTest();
 img.onload = wrapFunction(function ()
 {
     ctx672.drawImage(img, 0, 0);
-    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
     isPixel(ctx672, 12,20, 255,255,0,255, 0);
     isPixel(ctx672, 50,20, 0,255,255,255, 0);
     isPixel(ctx672, 87,20, 0,0,255,255, 0);
     isPixel(ctx672, 50,45, 255,255,255,255, 0);
 });
 img.src = data;
 
 
--- a/content/events/public/nsEventStates.h
+++ b/content/events/public/nsEventStates.h
@@ -243,20 +243,16 @@ private:
 // Content is in the sub-suboptimal region.
 #define NS_EVENT_STATE_SUB_SUB_OPTIMUM NS_DEFINE_EVENT_STATE_MACRO(39)
 // Handler for click to play plugin (vulnerable w/update)
 #define NS_EVENT_STATE_VULNERABLE_UPDATABLE NS_DEFINE_EVENT_STATE_MACRO(40)
 // Handler for click to play plugin (vulnerable w/no update)
 #define NS_EVENT_STATE_VULNERABLE_NO_UPDATE NS_DEFINE_EVENT_STATE_MACRO(41)
 // Platform does not support plugin content (some mobile platforms)
 #define NS_EVENT_STATE_TYPE_UNSUPPORTED_PLATFORM NS_DEFINE_EVENT_STATE_MACRO(42)
-// Element is ltr (for :dir pseudo-class)
-#define NS_EVENT_STATE_LTR NS_DEFINE_EVENT_STATE_MACRO(43)
-// Element is rtl (for :dir pseudo-class)
-#define NS_EVENT_STATE_RTL NS_DEFINE_EVENT_STATE_MACRO(44)
 
 /**
  * NOTE: do not go over 63 without updating nsEventStates::InternalType!
  */
 
 #define ESM_MANAGED_STATES (NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_FOCUS |     \
                             NS_EVENT_STATE_HOVER | NS_EVENT_STATE_DRAGOVER |   \
                             NS_EVENT_STATE_URLTARGET | NS_EVENT_STATE_FOCUSRING | \
--- a/content/events/src/nsDOMSimpleGestureEvent.cpp
+++ b/content/events/src/nsDOMSimpleGestureEvent.cpp
@@ -45,17 +45,17 @@ nsDOMSimpleGestureEvent::GetDirection(PR
 {
   NS_ENSURE_ARG_POINTER(aDirection);
   *aDirection = static_cast<nsSimpleGestureEvent*>(mEvent)->direction;
   return NS_OK;
 }
 
 /* readonly attribute float delta; */
 NS_IMETHODIMP
-nsDOMSimpleGestureEvent::GetDelta(PRFloat64 *aDelta)
+nsDOMSimpleGestureEvent::GetDelta(double *aDelta)
 {
   NS_ENSURE_ARG_POINTER(aDelta);
   *aDelta = static_cast<nsSimpleGestureEvent*>(mEvent)->delta;
   return NS_OK;
 }
 
 /* readonly attribute unsigned long clickCount; */
 NS_IMETHODIMP
@@ -78,17 +78,17 @@ nsDOMSimpleGestureEvent::InitSimpleGestu
                                                 PRInt32 aClientY,
                                                 bool aCtrlKeyArg,
                                                 bool aAltKeyArg,
                                                 bool aShiftKeyArg,
                                                 bool aMetaKeyArg,
                                                 PRUint16 aButton,
                                                 nsIDOMEventTarget* aRelatedTarget,
                                                 PRUint32 aDirectionArg,
-                                                PRFloat64 aDeltaArg,
+                                                double aDeltaArg,
                                                 PRUint32 aClickCountArg)
 {
   nsresult rv = nsDOMMouseEvent::InitMouseEvent(aTypeArg,
                                                 aCanBubbleArg,
                                                 aCancelableArg,
                                                 aViewArg,
                                                 aDetailArg,
                                                 aScreenX, 
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -48,17 +48,16 @@
 #include "nsScriptLoader.h"
 #include "nsRuleData.h"
 
 #include "nsPresState.h"
 #include "nsILayoutHistoryState.h"
 
 #include "nsHTMLParts.h"
 #include "nsContentUtils.h"
-#include "mozilla/dom/DirectionalityUtils.h"
 #include "nsString.h"
 #include "nsUnicharUtils.h"
 #include "nsGkAtoms.h"
 #include "nsEventStateManager.h"
 #include "nsIDOMEvent.h"
 #include "nsDOMCSSDeclaration.h"
 #include "nsITextControlFrame.h"
 #include "nsIForm.h"
@@ -92,17 +91,16 @@
 #include "HTMLPropertiesCollection.h"
 #include "nsVariant.h"
 #include "nsDOMSettableTokenList.h"
 #include "nsThreadUtils.h"
 #include "nsTextFragment.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
-using namespace mozilla::directionality;
 
 class nsINodeInfo;
 class nsIDOMNodeList;
 class nsRuleWalker;
 
 // XXX todo: add in missing out-of-memory checks
 
 //----------------------------------------------------------------------
@@ -1684,34 +1682,16 @@ nsGenericHTMLElement::UpdateEditableStat
   if (value != eInherit) {
     DoSetEditableFlag(!!value, aNotify);
     return;
   }
 
   nsStyledElement::UpdateEditableState(aNotify);
 }
 
-nsEventStates
-nsGenericHTMLElement::IntrinsicState() const
-{
-  nsEventStates state = nsGenericHTMLElementBase::IntrinsicState();
-
-  if (GetDirectionality() == eDir_RTL) {
-    state |= NS_EVENT_STATE_RTL;
-    state &= ~NS_EVENT_STATE_LTR;
-  } else { // at least for HTML, directionality is exclusively LTR or RTL
-    NS_ASSERTION(GetDirectionality() == eDir_LTR,
-                 "HTML element's directionality must be either RTL or LTR");
-    state |= NS_EVENT_STATE_LTR;
-    state &= ~NS_EVENT_STATE_RTL;
-  }
-
-  return state;
-}
-
 nsresult
 nsGenericHTMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                                  nsIContent* aBindingParent,
                                  bool aCompileEventHandlers)
 {
   nsresult rv = nsGenericHTMLElementBase::BindToTree(aDocument, aParent,
                                                      aBindingParent,
                                                      aCompileEventHandlers);
@@ -1904,30 +1884,16 @@ nsGenericHTMLElement::AfterSetAttr(PRInt
       NS_ABORT_IF_FALSE(aValue->Type() == nsAttrValue::eString,
         "Expected string value for script body");
       nsresult rv = AddScriptEventListener(aName, aValue->GetStringValue());
       NS_ENSURE_SUCCESS(rv, rv);
     }
     else if (aNotify && aName == nsGkAtoms::spellcheck) {
       SyncEditorsOnSubtree(this);
     }
-    else if (aName == nsGkAtoms::dir) {
-      Directionality dir;
-      if (aValue &&
-          (aValue->Equals(nsGkAtoms::ltr, eIgnoreCase) ||
-           aValue->Equals(nsGkAtoms::rtl, eIgnoreCase))) {
-        SetHasValidDir();
-        dir = aValue->Equals(nsGkAtoms::rtl, eIgnoreCase) ? eDir_RTL : eDir_LTR;
-        SetDirectionality(this, dir, aNotify);
-      } else {
-        ClearHasValidDir();
-        dir = RecomputeDirectionality(this, aNotify);
-      }
-      SetDirectionalityOnDescendants(this, dir, aNotify);
-    }
   }
 
   return nsGenericHTMLElementBase::AfterSetAttr(aNamespaceID, aName,
                                                 aValue, aNotify);
 }
 
 nsEventListenerManager*
 nsGenericHTMLElement::GetEventListenerManagerForAttr(nsIAtom* aAttrName,
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -44,18 +44,16 @@ typedef nsMappedAttributeElement nsGener
 class nsGenericHTMLElement : public nsGenericHTMLElementBase
 {
 public:
   nsGenericHTMLElement(already_AddRefed<nsINodeInfo> aNodeInfo)
     : nsGenericHTMLElementBase(aNodeInfo)
   {
     NS_ASSERTION(mNodeInfo->NamespaceID() == kNameSpaceID_XHTML,
                  "Unexpected namespace");
-    AddStatesSilently(NS_EVENT_STATE_LTR);
-    SetFlags(NODE_HAS_DIRECTION_LTR);
   }
 
   /** Typesafe, non-refcounting cast from nsIContent.  Cheaper than QI. **/
   static nsGenericHTMLElement* FromContent(nsIContent *aContent)
   {
     if (aContent->IsHTML())
       return static_cast<nsGenericHTMLElement*>(aContent);
     return nullptr;
@@ -199,18 +197,16 @@ public:
   nsresult PostHandleEventForAnchors(nsEventChainPostVisitor& aVisitor);
   bool IsHTMLLink(nsIURI** aURI) const;
 
   // HTML element methods
   void Compact() { mAttrsAndChildren.Compact(); }
 
   virtual void UpdateEditableState(bool aNotify);
 
-  virtual nsEventStates IntrinsicState() const;
-
   // Helper for setting our editable flag and notifying
   void DoSetEditableFlag(bool aEditable, bool aNotify) {
     SetEditableFlag(aEditable);
     UpdateState(aNotify);
   }
 
   virtual bool ParseAttribute(PRInt32 aNamespaceID,
                                 nsIAtom* aAttribute,
--- a/content/html/content/test/Makefile.in
+++ b/content/html/content/test/Makefile.in
@@ -260,16 +260,17 @@ MOCHITEST_FILES = \
 		test_bug651956.html \
 		test_bug694503.html \
 		test_object_plugin_nav.html \
 		test_bug742030.html \
 		test_bug742549.html \
 		test_bug745685.html \
 		test_input_file_picker.html \
 		test_bug763626.html \
+		test_bug780993.html \
 		$(NULL)
 
 MOCHITEST_BROWSER_FILES = \
 		browser_bug649778.js \
 		file_bug649778.html \
 		file_bug649778.html^headers^ \
 		$(NULL)
 
--- a/content/html/content/test/test_bug143220.html
+++ b/content/html/content/test/test_bug143220.html
@@ -19,37 +19,36 @@ https://bugzilla.mozilla.org/show_bug.cg
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 143220 **/
 var leafName;
 var fullPath;
 
+
 function initVals() {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"]
-                         .getService(Components.interfaces.nsIProperties);
+  var dirSvc = SpecialPowers.wrap(Components)
+                            .classes["@mozilla.org/file/directory_service;1"]
+                            .getService(Components.interfaces.nsIProperties);
   var file = dirSvc.get("XpcomLib", Components.interfaces.nsILocalFile);
   isnot(file, null, "Must have file here");
 
   leafName = file.leafName;
   fullPath = file.path;
 }
 
 function initControl1() {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  $("i1").value = fullPath;
-  is($("i1").value, fullPath, "Should have set full path 1");
+  SpecialPowers.wrap($("i1")).value = fullPath;
+  is(SpecialPowers.wrap($("i1")).value, fullPath, "Should have set full path 1");
 }
 
 function initControl2() {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  $("i2").value = fullPath;
-  is($("i2").value, fullPath, "Should have set full path 2");
+  SpecialPowers.wrap($("i2")).value = fullPath;
+  is(SpecialPowers.wrap($("i2")).value, fullPath, "Should have set full path 2");
 }
 
 initVals();
 
 // Check that we can't just set the value
 try {
   $("i1").value = fullPath;
   is(0, 1, "Should have thrown exception on set!");
--- a/content/html/content/test/test_bug523771.html
+++ b/content/html/content/test/test_bug523771.html
@@ -27,36 +27,35 @@ var input2Files =
   [{ name: "523771_file2", type: "", body: "second file contents" },
    { name: "523771_file3.txt", type: "text/plain", body: "123456" },
    { name: "523771_file4.html", type: "text/html", body: "<html>content</html>" }
   ];
 
 SimpleTest.waitForExplicitFinish();
 
 function setFileInputs () {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
   f = createFileWithData(input1File.name, input1File.body);
-  singleFileInput.mozSetFileNameArray([f.path], 1);
+  SpecialPowers.wrap(singleFileInput).mozSetFileNameArray([f.path], 1);
 
   var input2FileNames = [];
   for each (file in input2Files) {
     f = createFileWithData(file.name, file.body);
     input2FileNames.push(f.path);
   }
-  multiFileInput.mozSetFileNameArray(input2FileNames, input2FileNames.length);
+  SpecialPowers.wrap(multiFileInput).mozSetFileNameArray(input2FileNames, input2FileNames.length);
 }
 
 function createFileWithData(fileName, fileData) {
-  var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"]
-                         .getService(Components.interfaces.nsIProperties);
+  var dirSvc = SpecialPowers.wrap(Components).classes["@mozilla.org/file/directory_service;1"]
+                            .getService(Components.interfaces.nsIProperties);
   var testFile = dirSvc.get("ProfD", Components.interfaces.nsIFile);
   testFile.append(fileName);
-  var outStream = Components.
-                  classes["@mozilla.org/network/file-output-stream;1"].
-                  createInstance(Components.interfaces.nsIFileOutputStream);
+  var outStream = SpecialPowers.wrap(Components).
+                    classes["@mozilla.org/network/file-output-stream;1"].
+                    createInstance(Components.interfaces.nsIFileOutputStream);
   outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
                  0666, 0);
   outStream.write(fileData, fileData.length);
   outStream.close();
 
   filesToKill.push(testFile);
 
   return testFile;
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/test_bug780993.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Test for bug 780993</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<div id=log></div>
+<script>
+test(function() {
+  var select = document.createElement("select");
+  var option = document.createElement("option");
+  select.appendChild(option);
+  assert_equals(select[0], option);
+  select[0] = null;
+  assert_equals(option.parentNode, null);
+  assert_equals(select[0], null);
+}, "Should be able to set select[n] to null.");
+test(function() {
+  var select = document.createElement("select");
+  var option = document.createElement("option");
+  var option2 = document.createElement("option");
+  select.appendChild(option);
+  assert_equals(select[0], option);
+  select[0] = option2;
+  assert_equals(option.parentNode, null);
+  assert_equals(option2.parentNode, select);
+  assert_equals(select[0], option2);
+}, "Should be able to set select[n] to an option element");
+test(function() {
+  var select = document.createElement("select");
+  var option = document.createElement("option");
+  select.appendChild(option);
+  assert_equals(select[0], option);
+  assert_throws(null, function() {
+    select[0] = 42;
+  });
+  assert_equals(option.parentNode, select);
+  assert_equals(select[0], option);
+}, "Should not be able to set select[n] to a primitive.");
+</script>
--- a/content/html/document/src/ImageDocument.cpp
+++ b/content/html/document/src/ImageDocument.cpp
@@ -87,17 +87,19 @@ public:
   virtual void Destroy();
   virtual void OnPageShow(bool aPersisted,
                           nsIDOMEventTarget* aDispatchStartTarget);
 
   NS_DECL_NSIIMAGEDOCUMENT
 
   // imgIDecoderObserver (override nsStubImageDecoderObserver)
   NS_IMETHOD OnStartContainer(imgIRequest* aRequest, imgIContainer* aImage);
+  NS_IMETHOD OnStopContainer(imgIRequest* aRequest, imgIContainer* aImage);
   NS_IMETHOD OnStopDecode(imgIRequest *aRequest, nsresult aStatus, const PRUnichar *aStatusArg);
+  NS_IMETHOD OnDiscard(imgIRequest *aRequest);
 
   // nsIDOMEventListener
   NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ImageDocument, MediaDocument)
 
   friend class ImageListener;
 
@@ -515,28 +517,36 @@ ImageDocument::OnStartContainer(imgIRequ
     NS_NewRunnableMethod(this, &ImageDocument::DefaultCheckOverflowing);
   nsContentUtils::AddScriptRunner(runnable);
   UpdateTitleAndCharset();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+ImageDocument::OnStopContainer(imgIRequest* aRequest, imgIContainer* aImage)
+{
+  if (mImageContent) {
+    // Update the background-color of the image only after the
+    // image has been decoded to prevent flashes of just the
+    // background-color.
+    mImageContent->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
+                           NS_LITERAL_STRING("decoded"), true);
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 ImageDocument::OnStopDecode(imgIRequest *aRequest,
                             nsresult aStatus,
                             const PRUnichar *aStatusArg)
 {
   UpdateTitleAndCharset();
 
-  nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mImageContent);
-  if (imageLoader) {
-    mObservingImageLoader = false;
-    imageLoader->RemoveObserver(this);
-  }
-
   // mImageContent can be null if the document is already destroyed
   if (NS_FAILED(aStatus) && mStringBundle && mImageContent) {
     nsCAutoString src;
     mDocumentURI->GetSpec(src);
     NS_ConvertUTF8toUTF16 srcString(src);
     const PRUnichar* formatString[] = { srcString.get() };
     nsXPIDLString errorMsg;
     NS_NAMED_LITERAL_STRING(str, "InvalidImage");
@@ -545,16 +555,28 @@ ImageDocument::OnStopDecode(imgIRequest 
 
     mImageContent->SetAttr(kNameSpaceID_None, nsGkAtoms::alt, errorMsg, false);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+ImageDocument::OnDiscard(imgIRequest *aRequest)
+{
+  // mImageContent can be null if the document is already destroyed
+  if (mImageContent) {
+    // Remove any decoded-related styling when the image is unloaded.
+    mImageContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::_class,
+                             true);
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 ImageDocument::HandleEvent(nsIDOMEvent* aEvent)
 {
   nsAutoString eventType;
   aEvent->GetType(eventType);
   if (eventType.EqualsLiteral("resize")) {
     CheckOverflowing(false);
   }
   else if (eventType.EqualsLiteral("click") && mClickResizingEnabled) {
--- a/content/html/document/test/test_bug445004.html
+++ b/content/html/document/test/test_bug445004.html
@@ -50,19 +50,17 @@ function checkURI(uri, name, type) {
   var host = uri.match(/^http:\/\/([a-z.0-9]*)/)[1];
   var file = uri.match(/([^\/]*).png$/)[1];
   is(host, file, "Unexpected base URI for test " + name +
      " when testing " + type);
 }
 
 function checkFrame(num) {
   // Just snarf our data
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-
-  var outer = window.frames[num]
+  var outer = SpecialPowers.wrap(window.frames[num]);
   name = outer.name;
 
   is(outer.document.baseURI,
      "http://example.org/tests/content/html/document/test/bug445004-outer.html",
      "Unexpected base URI for " + name);
 
   var iswrite = name.match(/write/);
 
--- a/content/html/document/test/test_bug512367.html
+++ b/content/html/document/test/test_bug512367.html
@@ -19,31 +19,29 @@ https://bugzilla.mozilla.org/show_bug.cg
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 var frame = document.getElementById("i");
 
 SimpleTest.waitForExplicitFinish();
 addLoadEvent(function() {
-  netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
   var viewer =
-    frame.contentWindow
-         .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-         .getInterface(Components.interfaces.nsIWebNavigation)
-         .QueryInterface(Components.interfaces.nsIDocShell)
-         .contentViewer
-         .QueryInterface(Components.interfaces.nsIMarkupDocumentViewer);
+    SpecialPowers.wrap(frame.contentWindow
+                 .QueryInterface(Components.interfaces.nsIInterfaceRequestor))
+                 .getInterface(Components.interfaces.nsIWebNavigation)
+                 .QueryInterface(Components.interfaces.nsIDocShell)
+                 .contentViewer
+                 .QueryInterface(Components.interfaces.nsIMarkupDocumentViewer);
 
   viewer.fullZoom = 1.5;
 
   setTimeout(function() {
     synthesizeMouse(frame, 30, 30, {});
 
-    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
     is(viewer.fullZoom, 1.5, "Zoom in the image frame should not have been reset");
 
     SimpleTest.finish();
   }, 0);
 });
 </script>
 </pre>
 </body>
--- a/content/media/plugins/nsMediaPluginReader.h
+++ b/content/media/plugins/nsMediaPluginReader.h
@@ -11,18 +11,18 @@
 #include "nsBuiltinDecoderReader.h"
 
 #include "MPAPI.h"
 
 class nsMediaPluginReader : public nsBuiltinDecoderReader
 {
   nsCString mType;
   MPAPI::Decoder *mPlugin;
-  PRBool mHasAudio;
-  PRBool mHasVideo;
+  bool mHasAudio;
+  bool mHasVideo;
   nsIntRect mPicture;
   nsIntSize mInitialFrame;
   int64_t mVideoSeekTimeUs;
   int64_t mAudioSeekTimeUs;
   VideoData *mLastVideoFrame;
 public:
   nsMediaPluginReader(nsBuiltinDecoder* aDecoder);
   ~nsMediaPluginReader();
--- a/content/media/test/manifest.js
+++ b/content/media/test/manifest.js
@@ -154,20 +154,19 @@ var gPlayTests = [
 // Converts a path/filename to a file:// URI which we can load from disk.
 // Optionally checks whether the file actually exists on disk at the location
 // we've specified.
 function fileUriToSrc(path, mustExist) {
   // android mochitest doesn't support file://
   if (navigator.appVersion.indexOf("Android") != -1)
     return path;
 
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
   const Ci = Components.interfaces;
-  const Cc = Components.classes;
-  const Cr = Components.results;
+  const Cc = SpecialPowers.wrap(Components).classes;
+  const Cr = SpecialPowers.wrap(Components).results;
   var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
                getService(Ci.nsIProperties);
   var f = dirSvc.get("CurWorkD", Ci.nsILocalFile);
   var split = path.split("/");
   for(var i = 0; i < split.length; ++i) {
     f.append(split[i]);
   }
   if (mustExist && !f.exists()) {
@@ -439,18 +438,17 @@ function MediaTestManager() {
   }
 
   // Starts the next batch of tests, or finishes if they're all done.
   // Don't call this directly, call finished(token) when you're done.
   this.nextTest = function() {
     // Force a GC after every completed testcase. This ensures that any decoders
     // with live threads waiting for the GC are killed promptly, to free up the
     // thread stacks' address space.
-    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
-    Components.utils.forceGC();
+    SpecialPowers.forceGC();
     
     while (this.testNum < this.tests.length && this.tokens.length < PARALLEL_TESTS) {
       var test = this.tests[this.testNum];
       var token = (test.name ? (test.name + "-"): "") + this.testNum;
       this.testNum++;
 
       if (DEBUG_TEST_LOOP_FOREVER && this.testNum == this.tests.length) {
         this.testNum = 0;
@@ -492,40 +490,38 @@ function mediaTestCleanup() {
       V[i].parentNode.removeChild(V[i]);
       V[i] = null;
     }
     var A = document.getElementsByTagName("audio");
     for (i=0; i<A.length; i++) {
       A[i].parentNode.removeChild(A[i]);
       A[i] = null;
     }
-    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
-    Components.utils.forceGC();
+    SpecialPowers.forceGC();
 }
 
 (function() {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
   // Ensure that preload preferences are comsistent
-  var prefService = Components.classes["@mozilla.org/preferences-service;1"]
-                               .getService(Components.interfaces.nsIPrefService);
+  var prefService = SpecialPowers.wrap(Components)
+                                 .classes["@mozilla.org/preferences-service;1"]
+                                 .getService(Components.interfaces.nsIPrefService);
   var branch = prefService.getBranch("media.");
   var oldDefault = 2;
   var oldAuto = 3;
   var oldOpus = undefined;
   try {
     oldDefault = branch.getIntPref("preload.default");
     oldAuto    = branch.getIntPref("preload.auto");
     oldOpus    = branch.getBoolPref("opus.enabled");
   } catch(ex) { }
   branch.setIntPref("preload.default", 2); // preload_metadata
   branch.setIntPref("preload.auto", 3); // preload_enough
   // test opus playback iff the pref exists
   if (oldOpus !== undefined)
     branch.setBoolPref("opus.enabled", true);
 
   window.addEventListener("unload", function() {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
     branch.setIntPref("preload.default", oldDefault);
     branch.setIntPref("preload.auto", oldAuto);
     if (oldOpus !== undefined)
       branch.setBoolPref("opus.enabled", oldOpus);
   }, false);
  })();
--- a/content/xslt/src/base/txDouble.cpp
+++ b/content/xslt/src/base/txDouble.cpp
@@ -151,17 +151,17 @@ void txDouble::toString(double aValue, n
         aDest.AppendLiteral("Infinity");
         return;
     }
 
     // Mantissa length is 17, so this is plenty
     const int buflen = 20;
     char buf[buflen];
 
-    PRIntn intDigits, sign;
+    int intDigits, sign;
     char* endp;
     PR_dtoa(aValue, 0, 0, &intDigits, &sign, &endp, buf, buflen - 1);
 
     // compute length
     PRInt32 length = endp - buf;
     if (length > intDigits) {
         // decimal point needed
         ++length;
--- a/content/xslt/src/xpath/txMozillaXPathTreeWalker.cpp
+++ b/content/xslt/src/xpath/txMozillaXPathTreeWalker.cpp
@@ -567,17 +567,17 @@ txXPathNodeUtils::getXSLTId(const txXPat
 /* static */
 void
 txXPathNodeUtils::getBaseURI(const txXPathNode& aNode, nsAString& aURI)
 {
     aNode.mNode->GetDOMBaseURI(aURI);
 }
 
 /* static */
-PRIntn
+int
 txXPathNodeUtils::comparePosition(const txXPathNode& aNode,
                                   const txXPathNode& aOtherNode)
 {
     // First check for equal nodes or attribute-nodes on the same element.
     if (aNode.mNode == aOtherNode.mNode) {
         if (aNode.mIndex == aOtherNode.mIndex) {
             return 0;
         }
--- a/content/xslt/src/xpath/txNodeSet.cpp
+++ b/content/xslt/src/xpath/txNodeSet.cpp
@@ -562,33 +562,33 @@ txXPathNode*
 txNodeSet::findPosition(const txXPathNode& aNode, txXPathNode* aFirst,
                         txXPathNode* aLast, bool& aDupe) const
 {
     aDupe = false;
     if (aLast - aFirst <= 2) {
         // If we search 2 nodes or less there is no point in further divides
         txXPathNode* pos = aFirst;
         for (; pos < aLast; ++pos) {
-            PRIntn cmp = txXPathNodeUtils::comparePosition(aNode, *pos);
+            int cmp = txXPathNodeUtils::comparePosition(aNode, *pos);
             if (cmp < 0) {
                 return pos;
             }
 
             if (cmp == 0) {
                 aDupe = true;
 
                 return pos;
             }
         }
         return pos;
     }
 
     // (cannot add two pointers)
     txXPathNode* midpos = aFirst + (aLast - aFirst) / 2;
-    PRIntn cmp = txXPathNodeUtils::comparePosition(aNode, *midpos);
+    int cmp = txXPathNodeUtils::comparePosition(aNode, *midpos);
     if (cmp == 0) {
         aDupe = true;
 
         return midpos;
     }
 
     if (cmp > 0) {
         return findPosition(aNode, midpos + 1, aLast, aDupe);
--- a/content/xslt/src/xpath/txXPathTreeWalker.h
+++ b/content/xslt/src/xpath/txXPathTreeWalker.h
@@ -89,18 +89,18 @@ public:
     static void appendNodeValue(const txXPathNode& aNode, nsAString& aResult);
     static bool isWhitespace(const txXPathNode& aNode);
     static txXPathNode* getOwnerDocument(const txXPathNode& aNode);
     static PRInt32 getUniqueIdentifier(const txXPathNode& aNode);
     static nsresult getXSLTId(const txXPathNode& aNode,
                               const txXPathNode& aBase, nsAString& aResult);
     static void release(txXPathNode* aNode);
     static void getBaseURI(const txXPathNode& aNode, nsAString& aURI);
-    static PRIntn comparePosition(const txXPathNode& aNode,
-                                  const txXPathNode& aOtherNode);
+    static int comparePosition(const txXPathNode& aNode,
+                               const txXPathNode& aOtherNode);
     static bool localNameEquals(const txXPathNode& aNode,
                                   nsIAtom* aLocalName);
     static bool isRoot(const txXPathNode& aNode);
     static bool isElement(const txXPathNode& aNode);
     static bool isAttribute(const txXPathNode& aNode);
     static bool isProcessingInstruction(const txXPathNode& aNode);
     static bool isComment(const txXPathNode& aNode);
     static bool isText(const txXPathNode& aNode);
--- a/content/xslt/src/xslt/txFormatNumberFunctionCall.cpp
+++ b/content/xslt/src/xslt/txFormatNumberFunctionCall.cpp
@@ -272,17 +272,17 @@ txFormatNumberFunctionCall::evaluate(txI
     if (value > 1)
         bufsize = (int)log10(value) + 30;
     else
         bufsize = 1 + 30;
 
     char* buf = new char[bufsize];
     NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY);
 
-    PRIntn bufIntDigits, sign;
+    int bufIntDigits, sign;
     char* endp;
     PR_dtoa(value, 0, 0, &bufIntDigits, &sign, &endp, buf, bufsize-1);
 
     int buflen = endp - buf;
     int intDigits;
     intDigits = bufIntDigits > minIntegerSize ? bufIntDigits : minIntegerSize;
 
     if (groupSize < 0)
--- a/content/xul/templates/src/nsRuleNetwork.cpp
+++ b/content/xul/templates/src/nsRuleNetwork.cpp
@@ -200,17 +200,17 @@ Instantiation::Hash(const void* aKey)
     for (nsAssignmentSet::ConstIterator assignment = inst->mAssignments.First();
          assignment != last; ++assignment)
         result ^= assignment->Hash();
 
     return result;
 }
 
 
-PRIntn
+int
 Instantiation::Compare(const void* aLeft, const void* aRight)
 {
     const Instantiation* left  = static_cast<const Instantiation*>(aLeft);
     const Instantiation* right = static_cast<const Instantiation*>(aRight);
 
     return *left == *right;
 }
 
--- a/content/xul/templates/src/nsRuleNetwork.h
+++ b/content/xul/templates/src/nsRuleNetwork.h
@@ -461,17 +461,17 @@ public:
 
     bool operator==(const Instantiation& aInstantiation) const {
         return Equals(aInstantiation); }
 
     bool operator!=(const Instantiation& aInstantiation) const {
         return !Equals(aInstantiation); }
 
     static PLHashNumber Hash(const void* aKey);
-    static PRIntn Compare(const void* aLeft, const void* aRight);
+    static int Compare(const void* aLeft, const void* aRight);
 };
 
 
 //----------------------------------------------------------------------
 
 /**
  * A collection of intantiations
  */
--- a/content/xul/templates/src/nsXULTemplateQueryProcessorStorage.cpp
+++ b/content/xul/templates/src/nsXULTemplateQueryProcessorStorage.cpp
@@ -330,17 +330,17 @@ nsXULTemplateQueryProcessorStorage::Comp
                   &nsGkAtoms::null, &nsGkAtoms::double_, &nsGkAtoms::string, nullptr };
 
             PRInt32 typeError = 1;
             PRInt32 typeValue = child->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::type,
                                                        sTypeValues, eCaseMatters);
             rv = NS_ERROR_ILLEGAL_VALUE;
             PRInt32 valInt32 = 0;
             PRInt64 valInt64 = 0;
-            PRFloat64 valFloat = 0;
+            double valFloat = 0;
 
             switch (typeValue) {
               case 0:
               case 1:
                 typeError = PR_sscanf(NS_ConvertUTF16toUTF8(value).get(),"%d",&valInt32);
                 if (typeError > 0)
                     rv = statement->BindInt32ByIndex(index, valInt32);
                 break;
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -6050,27 +6050,29 @@ nsDocShell::OnStateChange(nsIWebProgress
 
     if ((~aStateFlags & (STATE_START | STATE_IS_NETWORK)) == 0) {
         // Save timing statistics.
         nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
         nsCOMPtr<nsIURI> uri;
         channel->GetURI(getter_AddRefs(uri));
         nsCAutoString aURI;
         uri->GetAsciiSpec(aURI);
-        if (this == aProgress){
+
+        nsCOMPtr<nsIWyciwygChannel>  wcwgChannel(do_QueryInterface(aRequest));
+        nsCOMPtr<nsIWebProgress> webProgress =
+            do_QueryInterface(GetAsSupports(this));
+
+        // We don't update navigation timing for wyciwyg channels
+        if (this == aProgress && !wcwgChannel){
             rv = MaybeInitTiming();
             if (mTiming) {
                 mTiming->NotifyFetchStart(uri, ConvertLoadTypeToNavigationType(mLoadType));
             } 
         }
 
-        nsCOMPtr<nsIWyciwygChannel>  wcwgChannel(do_QueryInterface(aRequest));
-        nsCOMPtr<nsIWebProgress> webProgress =
-            do_QueryInterface(GetAsSupports(this));
-
         // Was the wyciwyg document loaded on this docshell?
         if (wcwgChannel && !mLSHE && (mItemType == typeContent) && aProgress == webProgress.get()) {
             bool equalUri = true;
             // Store the wyciwyg url in session history, only if it is
             // being loaded fresh for the first time. We don't want 
             // multiple entries for successive loads
             if (mCurrentURI &&
                 NS_SUCCEEDED(uri->Equals(mCurrentURI, &equalUri)) &&
--- a/docshell/test/Makefile.in
+++ b/docshell/test/Makefile.in
@@ -90,16 +90,18 @@ MOCHITEST_FILES = \
 		file_bug669671.sjs \
 		test_bug675587.html \
 		test_bfcache_plus_hash.html \
 		test_bug680257.html \
 		file_bug680257.html \
 		test_bug691547.html \
 		bug691547_frame.html \
 		test_bug694612.html \
+		test_bug703855.html \
+		file_bug703855.html \
 		test_bug713825.html \
 		test_bug728939.html \
 		file_bug728939.html \
 		$(NULL)
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 MOCHITEST_FILES += \
 		test_bug511449.html \
new file mode 100644
--- /dev/null
+++ b/docshell/test/file_bug703855.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<!-- Just need an empty file here, as long as it's served over HTTP -->
--- a/docshell/test/navigation/NavigationUtils.js
+++ b/docshell/test/navigation/NavigationUtils.js
@@ -93,27 +93,28 @@ function isInaccessible(wnd, message) {
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // Functions that require UniversalXPConnect privilege
 ///////////////////////////////////////////////////////////////////////////
 
 function xpcEnumerateContentWindows(callback) {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
   var Ci = Components.interfaces;
-  var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
-                     .getService(Ci.nsIWindowWatcher);
+  var ww = SpecialPowers.wrap(Components)
+                        .classes["@mozilla.org/embedcomp/window-watcher;1"]
+                        .getService(Ci.nsIWindowWatcher);
   var enumerator = ww.getWindowEnumerator();
 
   var contentWindows = [];
 
   while (enumerator.hasMoreElements()) {
     var win = enumerator.getNext();
-    if (typeof ChromeWindow != "undefined" && win instanceof ChromeWindow) {
+    if (typeof ChromeWindow != "undefined" && SpecialPowers.call_Instanceof(win, ChromeWindow)) {
       var docshellTreeNode = win.QueryInterface(Ci.nsIInterfaceRequestor)
                                 .getInterface(Ci.nsIWebNavigation)
                                 .QueryInterface(Ci.nsIDocShellTreeNode);
       var childCount = docshellTreeNode.childCount;
       for (var i = 0; i < childCount; ++i) {
         var childTreeNode = docshellTreeNode.getChildAt(i);
 
         // we're only interested in content docshells
--- a/docshell/test/navigation/file_bug534178.html
+++ b/docshell/test/navigation/file_bug534178.html
@@ -1,15 +1,14 @@
 <html>
   <head>
     <script>
     
       function testDone() {
         document.body.removeChild(document.body.firstChild);
-        netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
         var isOK = false;
         try {
           isOK = history.previous != location;
         } catch(ex) {
           // history.previous should throw if this is the first page in shistory.
           isOK = true;
         }
         document.body.textContent = isOK ? "PASSED" : "FAILED";
--- a/docshell/test/navigation/test_bug386782.html
+++ b/docshell/test/navigation/test_bug386782.html
@@ -55,39 +55,36 @@ https://bugzilla.mozilla.org/show_bug.cg
         if ("onload" in gTest) {
           gTest.onload(gTest.window.document);
         }
         SimpleTest.waitForFocus(beginTest, gTest.window);
       }, false);
     }
 
     function beginTest() {
-      netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
       gTest.window.document.body.focus();
 
       // WARNING: If the following test fails, give the setTimeout() in the onload()
       // a bit longer; the doc hasn't had enough time to setup its editor.
       is(gTest.window.document.body.innerHTML, gTest.expectedBodyBeforeEdit, "Is doc setup yet");
       sendString('EDITED ', gTest.window);
       is(gTest.window.document.body.innerHTML, gTest.expectedBodyAfterEdit, "Editing failed.");
 
       gTest.window.location = 'data:text/html;charset=utf-8,SomeOtherDocument';
       SimpleTest.waitForFocus(goBack, gTest.window);
     }
     
     function goBack() {
-      netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
       gTest.window.history.back();
       setTimeout(function() {
         SimpleTest.waitForFocus(checkStillEditable, gTest.window);
       }, 0);
     }
 
     function checkStillEditable() {
-      netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 
       // Check that the contents are correct.
       is(gTest.window.document.body.innerHTML, gTest.expectedBodyAfterEdit, "Edited contents still correct?");
       
       // Check that we can undo/redo and the contents are correct.
       gTest.window.document.execCommand("undo", false, null);
       is(gTest.window.document.body.innerHTML, gTest.expectedBodyBeforeEdit, "Can we undo?");
 
--- a/docshell/test/test_bug369814.html
+++ b/docshell/test/test_bug369814.html
@@ -181,19 +181,19 @@ var gTests = [
     "func" : loadErrorTest
   },
 ];
 
 var gNextTest = 0;
 
 function runNextTest()
 {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  var prefs = Components.classes["@mozilla.org/preferences-service;1"].
-    getService(Components.interfaces.nsIPrefBranch);
+  var prefs = SpecialPowers.wrap(Components)
+                           .classes["@mozilla.org/preferences-service;1"]
+                           .getService(Components.interfaces.nsIPrefBranch);
 
   if (gNextTest < gTests.length) {
     gCurrentTest = gTests[gNextTest++];
     gNumPokes = 0;
 
     prefs.setBoolPref("network.jar.open-unsafe-types", gCurrentTest['pref']);
 
     // Create a new frame each time, so our restictions on loads in a
@@ -209,33 +209,33 @@ function runNextTest()
     // Put back the pref value we had at test start
     prefs.setBoolPref("network.jar.open-unsafe-types", gPrefValue);
     SimpleTest.finish();
   }
 }
 
 function finishTest()
 {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var prefs = Components.classes["@mozilla.org/preferences-service;1"].
-      getService(Components.interfaces.nsIPrefBranch);
+    var prefs = SpecialPowers.wrap(Components)
+                             .classes["@mozilla.org/preferences-service;1"]
+                             .getService(Components.interfaces.nsIPrefBranch);
     prefs.setBoolPref("network.jar.open-unsafe-types", false);
 
   if (gNumPokes == 0) {
     ok(true, gCurrentTest["name"] + ": no unexpected pokes");
   }
 
   runNextTest();
 }
 
 function startTests()
 {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  var prefs = Components.classes["@mozilla.org/preferences-service;1"].
-    getService(Components.interfaces.nsIPrefBranch);
+  var prefs = SpecialPowers.wrap(Components)
+                           .classes["@mozilla.org/preferences-service;1"]
+                           .getService(Components.interfaces.nsIPrefBranch);
   gPrefValue = prefs.getBoolPref("network.jar.open-unsafe-types");
 }
 
 addLoadEvent(runNextTest);
 
 </script>
 </pre>
 </body>
--- a/docshell/test/test_bug509055.html
+++ b/docshell/test/test_bug509055.html
@@ -36,18 +36,16 @@ function onChildHashchange(e) {
 }
 
 function onChildLoad(e) {
   if(gGen)
     gGen.next();
 }
 
 function runTest() {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-
   var popup = window.open("file_bug509055.html", "popup 0",
                            "height=200,width=200,location=yes," +
                            "menubar=yes,status=yes,toolbar=yes,dependent=yes");
   popup.hashchangeCallback = onChildHashchange;
   popup.onload = onChildLoad;
   dump('Waiting for initial load.\n');
   yield;
 
@@ -67,19 +65,20 @@ function runTest() {
 
   popup.document.title = "Changed";
 
   // Wait for listeners to be notified of the title change.
   shortWait();
   dump('Got second hashchange.  Spinning event loop.\n');
   yield;
 
-  var sh = popup.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                .getInterface(Components.interfaces.nsIWebNavigation)
-                .sessionHistory;
+  var sh = SpecialPowers.wrap(popup)
+                        .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                        .getInterface(Components.interfaces.nsIWebNavigation)
+                        .sessionHistory;
 
   // Get the title of the inner popup's current SHEntry 
   var sheTitle = sh.getEntryAtIndex(sh.index, false).title;
   is(sheTitle, "Changed", "SHEntry's title should change when we change.");
 
   popup.close();
 
   SimpleTest.executeSoon(SimpleTest.finish);
--- a/docshell/test/test_bug529119-1.html
+++ b/docshell/test/test_bug529119-1.html
@@ -38,42 +38,39 @@ function pollForPage(f, w)
         f(iterationsLeft > 0);
       }
     }, 100);
   }, 1000);
 }
 
 function windowLoaded()
 {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
   switch (phase)
   {
     case 0:
       /* 2. We have succeededfully loaded a page, now go to a faulty URL */
       window.setTimeout(function() {
         w.location.href = faultyURL;
       }, 0);
     
       phase = 1;
 
       pollForPage(function(succeeded) {
         ok(succeeded, "Waiting for error page succeeded");
         
-        netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
         /* 3. now, while we are on the error page, try to reload it, actually 
            click the "Try Again" button */
-        w.location.reload();
+        SpecialPowers.wrap(w).location.reload();
 
         pollForPage(function(succeeded) {
           ok(succeeded, "Waiting for error page succeeded");
           
-          netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
           /* 4-finish, check we are still on the error page */
-          is(w.location.href, faultyURL, "Is on an error page");
-          isnot(w.location.href, workingURL, "Is not on the previous page");
+          is(SpecialPowers.wrap(w).location.href, faultyURL, "Is on an error page");
+          isnot(SpecialPowers.wrap(w).location.href, workingURL, "Is not on the previous page");
           is(gotWrongPageOnTryAgainClick, false, 
             "Must not get www.example.com page on reload of an error page");
           w.close();
           SimpleTest.finish();
         }, w);
       }, w);
       break;
       
--- a/docshell/test/test_bug529119-2.html
+++ b/docshell/test/test_bug529119-2.html
@@ -37,43 +37,37 @@ function pollForPage(expectErrorPage, f,
         f(iterationsLeft > 0);
       }
     }, 100);
   }, 1000);
 }
 
 function windowLoaded()
 {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-
   /* 2. We have successfully loaded a page, now go to a faulty URL */
   // XXX The test fails when we change the location synchronously 
   window.setTimeout(function() {
     w.location.href = faultyURL;
   }, 0);
 
   pollForPage(true, function(succeeded) {
     ok(succeeded, "Waiting for error page succeeded");
-    
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
     /* 3. now, while we are on the error page, navigate back */
     try {
-      w.back();
+      SpecialPowers.wrap(w).back();
     }
     catch(ex) {
       ok(false, "w.back() threw " + ex);
     }
 
     pollForPage(false, function(succeeded) {
       ok(succeeded, "Waiting for original page succeeded");
-      
-      netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
       /* 4-finish, check we are back at the original page */
-      isnot(w.location.href, faultyURL, "Is on an error page");
-      is(w.location.href, workingURL, "Is not on the previous page");
+      isnot(SpecialPowers.wrap(w).location.href, faultyURL, "Is on an error page");
+      is(SpecialPowers.wrap(w).location.href, workingURL, "Is not on the previous page");
       w.close();
       SimpleTest.finish();
     }, w);
   }, w);
 }
 
 function startTest()
 {
new file mode 100644
--- /dev/null
+++ b/docshell/test/test_bug703855.html
@@ -0,0 +1,79 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=703855
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 703855</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=703855">Mozilla Bug 703855</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  <iframe id="f" src="file_bug703855.html"></iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 703855 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var timingAttributes = [
+  'connectEnd',
+  'connectStart',
+  'domComplete',
+  'domContentLoadedEventEnd',
+  'domContentLoadedEventStart',
+  'domInteractive',
+  'domLoading',
+  'domainLookupEnd',
+  'domainLookupStart',
+  'fetchStart',
+  'loadEventEnd',
+  'loadEventStart',
+  'navigationStart',
+  'redirectEnd',
+  'redirectStart',
+  'requestStart',
+  'responseEnd',
+  'responseStart',
+  'unloadEventEnd',
+  'unloadEventStart'
+];
+var originalTiming = {};
+
+function runTest() {
+  var timing = $("f").contentWindow.performance.timing;
+  for (i in timingAttributes) {
+    originalTiming[timingAttributes[i]] = timing[timingAttributes[i]];
+  }
+
+  var doc = $("f").contentDocument;
+  doc.open();
+  doc.write("<!DOCTYPE html>");
+  doc.close();
+
+  SimpleTest.executeSoon(function() {
+    var newTiming = $("f").contentWindow.performance.timing;
+    for (var i in timingAttributes) {
+      is(timing[timingAttributes[i]], originalTiming[timingAttributes[i]],
+         "document.open should not affect value of " + timingAttributes[i]);
+    }
+    SimpleTest.finish();
+  });
+}
+
+addLoadEvent(function() {
+  SimpleTest.executeSoon(runTest);
+});
+
+
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/apps/src/AppsService.js
+++ b/dom/apps/src/AppsService.js
@@ -48,13 +48,33 @@ AppsService.prototype = {
       return DOMApplicationRegistry.getAppLocalIdByManifestURL(aManifestURL);
     } else {
       let res = this.cpmm.sendSyncMessage("WebApps:GetAppLocalIdByManifestURL",
                                           { url: aManifestURL })[0];
       return res.id;
     }
   },
 
+  getAppByLocalId: function getAppByLocalId(aLocalId) {
+    debug("getAppByLocalId( " + aLocalId + " )");
+    if (this.inParent) {
+      return DOMApplicationRegistry.getAppByLocalId(aLocalId);
+    } else {
+      return this.cpmm.sendSyncMessage("WebApps:GetAppByLocalId",
+                                       { id: aLocalId })[0];
+    }
+  },
+
+  getManifestURLByLocalId: function getManifestURLByLocalId(aLocalId) {
+    debug("getManifestURLByLocalId( " + aLocalId + " )");
+    if (this.inParent) {
+      return DOMApplicationRegistry.getManifestURLByLocalId(aLocalId);
+    } else {
+      return this.cpmm.sendSyncMessage("WebApps:GetManifestURLByLocalId",
+                                       { id: aLocalId })[0];
+    }
+  },
+
   classID : APPS_SERVICE_CID,
   QueryInterface : XPCOMUtils.generateQI([Ci.nsIAppsService])
 }
 
 const NSGetFactory = XPCOMUtils.generateNSGetFactory([AppsService])
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -52,17 +52,18 @@ let DOMApplicationRegistry = {
   allAppsLaunchable: false,
 
   init: function() {
     this.messages = ["Webapps:Install", "Webapps:Uninstall",
                     "Webapps:GetSelf",
                     "Webapps:GetInstalled", "Webapps:GetNotInstalled",
                     "Webapps:Launch", "Webapps:GetAll",
                     "Webapps:InstallPackage", "Webapps:GetBasePath",
-                    "WebApps:GetAppByManifestURL", "WebApps:GetAppLocalIdByManifestURL"];
+                    "WebApps:GetAppByManifestURL", "WebApps:GetAppLocalIdByManifestURL",
+                    "WebApps:GetAppByLocalId", "Webapps:GetManifestURLByLocalId"];
 
     this.messages.forEach((function(msgName) {
       ppmm.addMessageListener(msgName, this);
     }).bind(this));
 
     Services.obs.addObserver(this, "xpcom-shutdown", false);
 
     this.appsFile = FileUtils.getFile(DIRECTORY_NAME,
@@ -215,16 +216,17 @@ let DOMApplicationRegistry = {
       case "Webapps:Install":
         // always ask for UI to install
         Services.obs.notifyObservers(this, "webapps-ask-install", JSON.stringify(msg));
         break;
       case "Webapps:GetSelf":
         this.getSelf(msg);
         break;
       case "Webapps:Uninstall":
+        Services.obs.notifyObservers(this, "webapps-uninstall", JSON.stringify(msg));
         this.uninstall(msg);
         break;
       case "Webapps:Launch":
         Services.obs.notifyObservers(this, "webapps-launch", JSON.stringify(msg));
         break;
       case "Webapps:GetInstalled":
         this.getInstalled(msg);
         break;
@@ -244,16 +246,22 @@ let DOMApplicationRegistry = {
         return FileUtils.getFile(DIRECTORY_NAME, ["webapps"], true).path;
         break;
       case "WebApps:GetAppByManifestURL":
         return this.getAppByManifestURL(msg.url);
         break;
       case "WebApps:GetAppLocalIdByManifestURL":
         return { id: this.getAppLocalIdByManifestURL(msg.url) };
         break;
+      case "WebApps:GetAppByLocalId":
+        return this.getAppByLocalId(msg.id);
+        break;
+      case "WebApps:GetManifestURLByLocalId":
+        return this.getManifestURLByLocalId(msg.id);
+        break;
     }
   },
 
   _writeFile: function ss_writeFile(aFile, aData, aCallbak) {
     // Initialize the file output stream.
     let ostream = FileUtils.openSafeFileOutputStream(aFile);
 
     // Obtain a converter to convert our data to a UTF-8 encoded input stream.
@@ -686,23 +694,63 @@ let DOMApplicationRegistry = {
 
   getAppByManifestURL: function(aManifestURL) {
     // This could be O(1) if |webapps| was a dictionary indexed on manifestURL
     // which should be the unique app identifier.
     // It's currently O(n).
     for (let id in this.webapps) {
       let app = this.webapps[id];
       if (app.manifestURL == aManifestURL) {
+        let res = this._cloneAppObject(app);
+        res.hasPermission = function(permission) {
+          let localId = DOMApplicationRegistry.getAppLocalIdByManifestURL(
+            this.manifestURL);
+          let uri = Services.io.newURI(this.manifestURL, null, null);
+          let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"]
+                       .getService(Ci.nsIScriptSecurityManager);
+          // XXX for the purposes of permissions checking, this helper
+          // should always be called on !isBrowser frames, so we
+          // assume false here.
+          let principal = secMan.getAppCodebasePrincipal(uri, localId,
+                                                         /*mozbrowser*/false);
+          let perm = Services.perms.testExactPermissionFromPrincipal(principal,
+                                                                     permission);
+          return (perm === Ci.nsIPermissionManager.ALLOW_ACTION);
+        };
+        res.QueryInterface = XPCOMUtils.generateQI([Ci.mozIDOMApplication,
+                                                    Ci.mozIApplication]);
+        return res;
+      }
+    }
+
+    return null;
+  },
+
+  getAppByLocalId: function(aLocalId) {
+    for (let id in this.webapps) {
+      let app = this.webapps[id];
+      if (app.localId == aLocalId) {
         return this._cloneAppObject(app);
       }
     }
 
     return null;
   },
 
+  getManifestURLByLocalId: function(aLocalId) {
+    for (let id in this.webapps) {
+      let app = this.webapps[id];
+      if (app.localId == aLocalId) {
+        return app.manifestURL;
+      }
+    }
+
+    return null;
+  },
+
   getAppLocalIdByManifestURL: function(aManifestURL) {
     for (let id in this.webapps) {
       if (this.webapps[id].manifestURL == aManifestURL) {
         return this.webapps[id].localId;
       }
     }
 
     return Ci.nsIScriptSecurityManager.NO_APP_ID;
@@ -923,16 +971,20 @@ DOMApplicationManifest.prototype = {
   get icons() {
     return this._localeProp("icons");
   },
 
   get appcache_path() {
     return this._localeProp("appcache_path");
   },
 
+  get orientation() {
+    return this._localeProp("orientation");
+  },
+
   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);
--- a/dom/base/nsContentPermissionHelper.cpp
+++ b/dom/base/nsContentPermissionHelper.cpp
@@ -2,34 +2,35 @@
  * 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 "nsContentPermissionHelper.h"
 #include "nsIContentPermissionPrompt.h"
 #include "nsCOMPtr.h"
 #include "nsIDOMWindow.h"
 #include "nsIDOMElement.h"
-
+#include "nsIPrincipal.h"
 #include "mozilla/unused.h"
 
 using mozilla::unused;          // <snicker>
+using namespace mozilla::dom;
 
 nsContentPermissionRequestProxy::nsContentPermissionRequestProxy()
 {
   MOZ_COUNT_CTOR(nsContentPermissionRequestProxy);
 }
 
 nsContentPermissionRequestProxy::~nsContentPermissionRequestProxy()
 {
   MOZ_COUNT_DTOR(nsContentPermissionRequestProxy);
 }
 
 nsresult
 nsContentPermissionRequestProxy::Init(const nsACString & type,
-				                      mozilla::dom::ContentPermissionRequestParent* parent)
+                                      ContentPermissionRequestParent* parent)
 {
   NS_ASSERTION(parent, "null parent");
   mParent = parent;
   mType   = type;
 
   nsCOMPtr<nsIContentPermissionPrompt> prompt = do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID);
   if (!prompt) {
     return NS_ERROR_FAILURE;
@@ -58,82 +59,89 @@ NS_IMETHODIMP
 nsContentPermissionRequestProxy::GetWindow(nsIDOMWindow * *aRequestingWindow)
 {
   NS_ENSURE_ARG_POINTER(aRequestingWindow);
   *aRequestingWindow = nullptr; // ipc doesn't have a window
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsContentPermissionRequestProxy::GetUri(nsIURI * *aRequestingURI)
+nsContentPermissionRequestProxy::GetPrincipal(nsIPrincipal * *aRequestingPrincipal)
 {
-  NS_ENSURE_ARG_POINTER(aRequestingURI);
-  if (mParent == nullptr)
+  NS_ENSURE_ARG_POINTER(aRequestingPrincipal);
+  if (mParent == nullptr) {
     return NS_ERROR_FAILURE;
+  }
 
-  NS_ADDREF(*aRequestingURI = mParent->mURI);
+  NS_ADDREF(*aRequestingPrincipal = mParent->mPrincipal);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsContentPermissionRequestProxy::GetElement(nsIDOMElement * *aRequestingElement)
 {
   NS_ENSURE_ARG_POINTER(aRequestingElement);
-  if (mParent == nullptr)
+  if (mParent == nullptr) {
     return NS_ERROR_FAILURE;
+  }
+
   NS_ADDREF(*aRequestingElement = mParent->mElement);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsContentPermissionRequestProxy::Cancel()
 {
-  if (mParent == nullptr)
+  if (mParent == nullptr) {
     return NS_ERROR_FAILURE;
-  unused << mozilla::dom::ContentPermissionRequestParent::Send__delete__(mParent, false);
+  }
+
+  unused << ContentPermissionRequestParent::Send__delete__(mParent, false);
   mParent = nullptr;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsContentPermissionRequestProxy::Allow()
 {
-  if (mParent == nullptr)
+  if (mParent == nullptr) {
     return NS_ERROR_FAILURE;
-  unused << mozilla::dom::ContentPermissionRequestParent::Send__delete__(mParent, true);
+  }
+  unused << ContentPermissionRequestParent::Send__delete__(mParent, true);
   mParent = nullptr;
   return NS_OK;
 }
 
 namespace mozilla {
 namespace dom {
 
 ContentPermissionRequestParent::ContentPermissionRequestParent(const nsACString& aType,
                                                                nsIDOMElement *aElement,
-                                                               const IPC::URI& aUri)
+                                                               const IPC::Principal& aPrincipal)
 {
   MOZ_COUNT_CTOR(ContentPermissionRequestParent);
-  
-  mURI       = aUri;
+
+  mPrincipal = aPrincipal;
   mElement   = aElement;
   mType      = aType;
 }
 
 ContentPermissionRequestParent::~ContentPermissionRequestParent()
 {
   MOZ_COUNT_DTOR(ContentPermissionRequestParent);
 }
 
 bool
 ContentPermissionRequestParent::Recvprompt()
 {
   mProxy = new nsContentPermissionRequestProxy();
   NS_ASSERTION(mProxy, "Alloc of request proxy failed");
-  if (NS_FAILED(mProxy->Init(mType, this)))
+  if (NS_FAILED(mProxy->Init(mType, this))) {
     mProxy->Cancel();
+  }
   return true;
 }
 
 void
 ContentPermissionRequestParent::ActorDestroy(ActorDestroyReason why)
 {
   mProxy->OnParentDestroyed();
 }
--- a/dom/base/nsContentPermissionHelper.h
+++ b/dom/base/nsContentPermissionHelper.h
@@ -6,51 +6,52 @@
 #define nsContentPermissionHelper_h
 
 #include "base/basictypes.h"
 
 #include "nsIContentPermissionPrompt.h"
 #include "nsString.h"
 #include "nsIDOMElement.h"
 
+#include "mozilla/dom/PermissionMessageUtils.h"
 #include "mozilla/dom/PContentPermissionRequestParent.h"
 
 class nsContentPermissionRequestProxy;
 
 namespace mozilla {
 namespace dom {
 
 class ContentPermissionRequestParent : public PContentPermissionRequestParent
 {
  public:
-  ContentPermissionRequestParent(const nsACString& type, nsIDOMElement *element, const IPC::URI& principal);
+  ContentPermissionRequestParent(const nsACString& type, nsIDOMElement *element, const IPC::Principal& principal);
   virtual ~ContentPermissionRequestParent();
-  
-  nsCOMPtr<nsIURI>           mURI;
+
+  nsCOMPtr<nsIPrincipal> mPrincipal;
   nsCOMPtr<nsIDOMElement>    mElement;
   nsCOMPtr<nsContentPermissionRequestProxy> mProxy;
   nsCString mType;
 
- private:  
+ private:
   virtual bool Recvprompt();
   virtual void ActorDestroy(ActorDestroyReason why);
 };
-  
+
 } // namespace dom
 } // namespace mozilla
 
 class nsContentPermissionRequestProxy : public nsIContentPermissionRequest
 {
  public:
   nsContentPermissionRequestProxy();
   virtual ~nsContentPermissionRequestProxy();
-  
+
   nsresult Init(const nsACString& type, mozilla::dom::ContentPermissionRequestParent* parent);
   void OnParentDestroyed();
-  
+
   NS_DECL_ISUPPORTS
   NS_DECL_NSICONTENTPERMISSIONREQUEST
 
  private:
   // Non-owning pointer to the ContentPermissionRequestParent object which owns this proxy.
   mozilla::dom::ContentPermissionRequestParent* mParent;
   nsCString mType;
 };
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1702,34 +1702,40 @@ static nsDOMClassInfoData sClassInfoData
 
 // Objects that should be constructable through |new Name();|
 struct nsContractIDMapData
 {
   PRInt32 mDOMClassInfoID;
   const char *mContractID;
 };
 
-#define NS_DEFINE_CONSTRUCTOR_DATA(_class, _contract_id)                      \
-  { eDOMClassInfo_##_class##_id, _contract_id },
-
-static const nsContractIDMapData kConstructorMap[] =
-{
-  NS_DEFINE_CONSTRUCTOR_DATA(DOMParser, NS_DOMPARSER_CONTRACTID)
-  NS_DEFINE_CONSTRUCTOR_DATA(FileReader, NS_FILEREADER_CONTRACTID)
-  NS_DEFINE_CONSTRUCTOR_DATA(ArchiveReader, NS_ARCHIVEREADER_CONTRACTID)
-  NS_DEFINE_CONSTRUCTOR_DATA(FormData, NS_FORMDATA_CONTRACTID)
-  NS_DEFINE_CONSTRUCTOR_DATA(XMLSerializer, NS_XMLSERIALIZER_CONTRACTID)
-  NS_DEFINE_CONSTRUCTOR_DATA(WebSocket, NS_WEBSOCKET_CONTRACTID)
-  NS_DEFINE_CONSTRUCTOR_DATA(XPathEvaluator, NS_XPATH_EVALUATOR_CONTRACTID)
-  NS_DEFINE_CONSTRUCTOR_DATA(XSLTProcessor,
-                             "@mozilla.org/document-transformer;1?type=xslt")
-  NS_DEFINE_CONSTRUCTOR_DATA(EventSource, NS_EVENTSOURCE_CONTRACTID)
-  NS_DEFINE_CONSTRUCTOR_DATA(MutationObserver, NS_DOMMUTATIONOBSERVER_CONTRACTID)
-  NS_DEFINE_CONSTRUCTOR_DATA(MozActivity, NS_DOMACTIVITY_CONTRACTID)
-};
+#define NS_DEFINE_CONTRACT_CTOR(_class, _contract_id)                           \
+  nsresult                                                                      \
+  _class##Ctor(nsISupports** aInstancePtrResult)                                \
+  {                                                                             \
+    nsresult rv = NS_OK;                                                        \
+    nsCOMPtr<nsISupports> native = do_CreateInstance(_contract_id, &rv);        \
+    native.forget(aInstancePtrResult);                                          \
+    return rv;                                                                  \
+  }
+
+NS_DEFINE_CONTRACT_CTOR(DOMParser, NS_DOMPARSER_CONTRACTID)
+NS_DEFINE_CONTRACT_CTOR(FileReader, NS_FILEREADER_CONTRACTID)
+NS_DEFINE_CONTRACT_CTOR(ArchiveReader, NS_ARCHIVEREADER_CONTRACTID)
+NS_DEFINE_CONTRACT_CTOR(FormData, NS_FORMDATA_CONTRACTID)
+NS_DEFINE_CONTRACT_CTOR(XMLSerializer, NS_XMLSERIALIZER_CONTRACTID)
+NS_DEFINE_CONTRACT_CTOR(WebSocket, NS_WEBSOCKET_CONTRACTID)
+NS_DEFINE_CONTRACT_CTOR(XPathEvaluator, NS_XPATH_EVALUATOR_CONTRACTID)
+NS_DEFINE_CONTRACT_CTOR(XSLTProcessor,
+                        "@mozilla.org/document-transformer;1?type=xslt")
+NS_DEFINE_CONTRACT_CTOR(EventSource, NS_EVENTSOURCE_CONTRACTID)
+NS_DEFINE_CONTRACT_CTOR(MutationObserver, NS_DOMMUTATIONOBSERVER_CONTRACTID)
+NS_DEFINE_CONTRACT_CTOR(MozActivity, NS_DOMACTIVITY_CONTRACTID)
+
+#undef NS_DEFINE_CONTRACT_CTOR
 
 #define NS_DEFINE_EVENT_CTOR(_class)                        \
   nsresult                                                  \
   NS_DOM##_class##Ctor(nsISupports** aInstancePtrResult)    \
   {                                                         \
     nsIDOMEvent* e = nullptr;                                \
     nsresult rv = NS_NewDOM##_class(&e, nullptr, nullptr);    \
     *aInstancePtrResult = e;                                \
@@ -1782,30 +1788,40 @@ static const nsConstructorFuncMapData kC
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MozWifiConnectionInfoEvent)
 #endif
 #define MOZ_GENERATED_EVENT_LIST
 #define MOZ_GENERATED_EVENT(_event_interface) \
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(_event_interface)
 #include "GeneratedEvents.h"
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MozSmsFilter, sms::SmsFilter::NewSmsFilter)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(XMLHttpRequest, NS_XMLHttpRequestCtor)
+  NS_DEFINE_CONSTRUCTOR_FUNC_DATA(DOMParser, DOMParserCtor)
+  NS_DEFINE_CONSTRUCTOR_FUNC_DATA(FileReader, FileReaderCtor)
+  NS_DEFINE_CONSTRUCTOR_FUNC_DATA(ArchiveReader, ArchiveReaderCtor)
+  NS_DEFINE_CONSTRUCTOR_FUNC_DATA(FormData, FormDataCtor)
+  NS_DEFINE_CONSTRUCTOR_FUNC_DATA(XMLSerializer, XMLSerializerCtor)
+  NS_DEFINE_CONSTRUCTOR_FUNC_DATA(WebSocket, WebSocketCtor)
+  NS_DEFINE_CONSTRUCTOR_FUNC_DATA(XPathEvaluator, XPathEvaluatorCtor)
+  NS_DEFINE_CONSTRUCTOR_FUNC_DATA(XSLTProcessor, XSLTProcessorCtor)
+  NS_DEFINE_CONSTRUCTOR_FUNC_DATA(EventSource, EventSourceCtor)
+  NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MutationObserver, MutationObserverCtor)
+  NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MozActivity, MozActivityCtor)
 };
 
 nsIXPConnect *nsDOMClassInfo::sXPConnect = nullptr;
 nsIScriptSecurityManager *nsDOMClassInfo::sSecMan = nullptr;
 bool nsDOMClassInfo::sIsInitialized = false;
 bool nsDOMClassInfo::sDisableDocumentAllSupport = false;
 bool nsDOMClassInfo::sDisableGlobalScopePollutionSupport = false;
 
 
 jsid nsDOMClassInfo::sParent_id          = JSID_VOID;
 jsid nsDOMClassInfo::sScrollbars_id      = JSID_VOID;
 jsid nsDOMClassInfo::sLocation_id        = JSID_VOID;
 jsid nsDOMClassInfo::sConstructor_id     = JSID_VOID;
-jsid nsDOMClassInfo::s_content_id        = JSID_VOID;
 jsid nsDOMClassInfo::sContent_id         = JSID_VOID;
 jsid nsDOMClassInfo::sMenubar_id         = JSID_VOID;
 jsid nsDOMClassInfo::sToolbar_id         = JSID_VOID;
 jsid nsDOMClassInfo::sLocationbar_id     = JSID_VOID;
 jsid nsDOMClassInfo::sPersonalbar_id     = JSID_VOID;
 jsid nsDOMClassInfo::sStatusbar_id       = JSID_VOID;
 jsid nsDOMClassInfo::sDialogArguments_id = JSID_VOID;
 jsid nsDOMClassInfo::sControllers_id     = JSID_VOID;
@@ -2072,17 +2088,16 @@ nsDOMClassInfo::DefineStaticJSVals(JSCon
       return NS_ERROR_OUT_OF_MEMORY;
 
   JSAutoRequest ar(cx);
 
   SET_JSID_TO_STRING(sParent_id,          cx, "parent");
   SET_JSID_TO_STRING(sScrollbars_id,      cx, "scrollbars");
   SET_JSID_TO_STRING(sLocation_id,        cx, "location");
   SET_JSID_TO_STRING(sConstructor_id,     cx, "constructor");
-  SET_JSID_TO_STRING(s_content_id,        cx, "_content");
   SET_JSID_TO_STRING(sContent_id,         cx, "content");
   SET_JSID_TO_STRING(sMenubar_id,         cx, "menubar");
   SET_JSID_TO_STRING(sToolbar_id,         cx, "toolbar");
   SET_JSID_TO_STRING(sLocationbar_id,     cx, "locationbar");
   SET_JSID_TO_STRING(sPersonalbar_id,     cx, "personalbar");
   SET_JSID_TO_STRING(sStatusbar_id,       cx, "statusbar");
   SET_JSID_TO_STRING(sDialogArguments_id, cx, "dialogArguments");
   SET_JSID_TO_STRING(sControllers_id,     cx, "controllers");
@@ -2180,33 +2195,16 @@ CutPrefix(const char *aName) {
     return aName + sizeof(prefix_nsI) - 1;
   }
 
   return aName;
 }
 
 // static
 nsresult
-nsDOMClassInfo::RegisterClassName(PRInt32 aClassInfoID)
-{
-  nsScriptNameSpaceManager *nameSpaceManager =
-    nsJSRuntime::GetNameSpaceManager();
-  NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
-
-  nameSpaceManager->RegisterClassName(sClassInfoData[aClassInfoID].mName,
-                                      aClassInfoID,
-                                      sClassInfoData[aClassInfoID].mChromeOnly,
-                                      sClassInfoData[aClassInfoID].mDisabled,
-                                      &sClassInfoData[aClassInfoID].mNameUTF16);
-
-  return NS_OK;
-}
-
-// static
-nsresult
 nsDOMClassInfo::RegisterClassProtos(PRInt32 aClassInfoID)
 {
   nsScriptNameSpaceManager *nameSpaceManager =
     nsJSRuntime::GetNameSpaceManager();
   NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
   bool found_old;
 
   const nsIID *primary_iid = sClassInfoData[aClassInfoID].mProtoChainInterface;
@@ -4540,17 +4538,19 @@ nsDOMClassInfo::Init()
 #endif
 
   // Initialize static JSString's
   DefineStaticJSVals(cx);
 
   PRInt32 i;
 
   for (i = 0; i < eDOMClassInfoIDCount; ++i) {
-    RegisterClassName(i);
+    nsDOMClassInfoData& data = sClassInfoData[i];
+    nameSpaceManager->RegisterClassName(data.mName, i, data.mChromeOnly,
+                                        data.mDisabled, &data.mNameUTF16);
   }
 
   for (i = 0; i < eDOMClassInfoIDCount; ++i) {
     RegisterClassProtos(i);
   }
 
   RegisterExternalClasses();
 
@@ -5199,17 +5199,16 @@ nsDOMClassInfo::ShutDown()
       NS_IF_RELEASE(sClassInfoData[i].mCachedClassInfo);
     }
   }
 
   sParent_id          = JSID_VOID;
   sScrollbars_id      = JSID_VOID;
   sLocation_id        = JSID_VOID;
   sConstructor_id     = JSID_VOID;
-  s_content_id        = JSID_VOID;
   sContent_id         = JSID_VOID;
   sMenubar_id         = JSID_VOID;
   sToolbar_id         = JSID_VOID;
   sLocationbar_id     = JSID_VOID;
   sPersonalbar_id     = JSID_VOID;
   sStatusbar_id       = JSID_VOID;
   sDialogArguments_id = JSID_VOID;
   sControllers_id     = JSID_VOID;
@@ -5638,29 +5637,16 @@ nsWindowSH::Enumerate(nsIXPConnectWrappe
 {
   if (!ObjectIsNativeWrapper(cx, obj)) {
     *_retval = JS_EnumerateStandardClasses(cx, obj);
   }
 
   return NS_OK;
 }
 
-static const char*
-FindConstructorContractID(const nsDOMClassInfoData *aDOMClassInfoData)
-{
-  PRUint32 i;
-  for (i = 0; i < ArrayLength(kConstructorMap); ++i) {
-    if (&sClassInfoData[kConstructorMap[i].mDOMClassInfoID] ==
-        aDOMClassInfoData) {
-      return kConstructorMap[i].mContractID;
-    }
-  }
-  return nullptr;
-}
-
 static nsDOMConstructorFunc
 FindConstructorFunc(const nsDOMClassInfoData *aDOMClassInfoData)
 {
   for (PRUint32 i = 0; i < ArrayLength(kConstructorFuncMap); ++i) {
     if (&sClassInfoData[kConstructorFuncMap[i].mDOMClassInfoID] ==
         aDOMClassInfoData) {
       return kConstructorFuncMap[i].mConstructorFunc;
     }
@@ -5673,28 +5659,21 @@ BaseStubConstructor(nsIWeakReference* aW
                     const nsGlobalNameStruct *name_struct, JSContext *cx,
                     JSObject *obj, unsigned argc, jsval *argv, jsval *rval)
 {
   nsresult rv;
   nsCOMPtr<nsISupports> native;
   if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
     const nsDOMClassInfoData* ci_data =
       &sClassInfoData[name_struct->mDOMClassInfoID];
-    const char *contractid = FindConstructorContractID(ci_data);
-    if (contractid) {
-      native = do_CreateInstance(contractid, &rv);
-    }
-    else {
-      nsDOMConstructorFunc func = FindConstructorFunc(ci_data);
-      if (func) {
-        rv = func(getter_AddRefs(native));
-      }
-      else {
-        rv = NS_ERROR_NOT_AVAILABLE;
-      }
+    nsDOMConstructorFunc func = FindConstructorFunc(ci_data);
+    if (func) {
+      rv = func(getter_AddRefs(native));
+    } else {
+      rv = NS_ERROR_NOT_AVAILABLE;
     }
   } else if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructor) {
     native = do_CreateInstance(name_struct->mCID, &rv);
   } else if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias) {
     native = do_CreateInstance(name_struct->mAlias->mCID, &rv);
   } else {
     native = do_CreateInstance(*name_struct->mData->mConstructorCID, &rv);
   }
@@ -6097,17 +6076,17 @@ private:
   static bool IsConstructable(const nsDOMClassInfoData *aData)
   {
     if (IS_EXTERNAL(aData->mCachedClassInfo)) {
       const nsExternalDOMClassInfoData* data =
         static_cast<const nsExternalDOMClassInfoData*>(aData);
       return data->mConstructorCID != nullptr;
     }
 
-    return FindConstructorContractID(aData) || FindConstructorFunc(aData);
+    return FindConstructorFunc(aData);
   }
   static bool IsConstructable(const nsGlobalNameStruct *aNameStruct)
   {
     return
       (aNameStruct->mType == nsGlobalNameStruct::eTypeClassConstructor &&
        IsConstructable(&sClassInfoData[aNameStruct->mDOMClassInfoID])) ||
       (aNameStruct->mType == nsGlobalNameStruct::eTypeExternalClassInfo &&
        IsConstructable(aNameStruct->mData)) ||
@@ -6957,28 +6936,16 @@ nsWindowSH::GlobalResolve(nsGlobalWindow
     rv = nameset->InitializeNameSet(context);
 
     *did_resolve = true;
   }
 
   return rv;
 }
 
-// Native code for window._content getter, this simply maps
-// window._content to window.content for backwards compatibility only.
-static JSBool
-ContentWindowGetter(JSContext *cx, unsigned argc, jsval *vp)
-{
-  JSObject *obj = JS_THIS_OBJECT(cx, vp);
-  if (!obj)
-    return JS_FALSE;
-
-  return ::JS_GetProperty(cx, obj, "content", vp);
-}
-
 static JSNewResolveOp sOtherResolveFuncs[] = {
   mozilla::dom::workers::ResolveWorkerClasses
 };
 
 template<class Interface>
 static nsresult
 LocationSetterGuts(JSContext *cx, JSObject *obj, jsval *vp)
 {
@@ -7080,78 +7047,76 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
       }
     }
 
     return NS_OK;
   }
 
   nsIScriptContext *my_context = win->GetContextInternal();
 
-  nsresult rv = NS_OK;
-
   // Resolve standard classes on my_context's JSContext (or on cx,
   // if we don't have a my_context yet), in case the two contexts
   // have different origins.  We want lazy standard class
   // initialization to behave as if it were done eagerly, on each
   // window's own context (not on some other window-caller's
   // context).
-
-  JSBool did_resolve = JS_FALSE;
-  JSContext *my_cx;
-
-  JSBool ok = JS_TRUE;
-  jsval exn = JSVAL_VOID;
   if (!ObjectIsNativeWrapper(cx, obj)) {
-    JSAutoEnterCompartment ac;
-
-    if (!my_context) {
-      my_cx = cx;
-    } else {
-      my_cx = my_context->GetNativeContext();
-
-      if (my_cx != cx) {
-        if (!ac.enter(my_cx, obj)) {
-          return NS_ERROR_UNEXPECTED;
+    JSBool did_resolve = JS_FALSE;
+    JSBool ok = JS_TRUE;
+    JS::Value exn = JSVAL_VOID;
+
+    {
+      JSAutoEnterCompartment ac;
+
+      JSContext* my_cx;
+      if (!my_context) {
+        my_cx = cx;
+      } else {
+        my_cx = my_context->GetNativeContext();
+
+        if (my_cx != cx) {
+          if (!ac.enter(my_cx, obj)) {
+            return NS_ERROR_UNEXPECTED;
+          }
         }
       }
-    }
-
-    JSAutoRequest transfer(my_cx);
-
-    // Don't resolve standard classes on XPCNativeWrapper etc, only
-    // resolve them if we're resolving on the real global object.
-    ok = JS_ResolveStandardClass(my_cx, obj, id, &did_resolve);
+
+      JSAutoRequest transfer(my_cx);
+
+      // Don't resolve standard classes on XPCNativeWrapper etc, only
+      // resolve them if we're resolving on the real global object.
+      ok = JS_ResolveStandardClass(my_cx, obj, id, &did_resolve);
+
+      if (!ok) {
+        // Trust the JS engine (or the script security manager) to set
+        // the exception in the JS engine.
+
+        if (!JS_GetPendingException(my_cx, &exn)) {
+          return NS_ERROR_UNEXPECTED;
+        }
+
+        // Return NS_OK to avoid stomping over the exception that was passed
+        // down from the ResolveStandardClass call.
+        // Note that the order of the JS_ClearPendingException and
+        // JS_SetPendingException is important in the case that my_cx == cx.
+
+        JS_ClearPendingException(my_cx);
+      }
+    }
 
     if (!ok) {
-      // Trust the JS engine (or the script security manager) to set
-      // the exception in the JS engine.
-
-      if (!JS_GetPendingException(my_cx, &exn)) {
-        return NS_ERROR_UNEXPECTED;
-      }
-
-      // Return NS_OK to avoid stomping over the exception that was passed
-      // down from the ResolveStandardClass call.
-      // Note that the order of the JS_ClearPendingException and
-      // JS_SetPendingException is important in the case that my_cx == cx.
-
-      JS_ClearPendingException(my_cx);
-    }
-  }
-
-  if (!ok) {
-    JS_SetPendingException(cx, exn);
-    *_retval = JS_FALSE;
-    return NS_OK;
-  }
-
-  if (did_resolve) {
-    *objp = obj;
-
-    return NS_OK;
+      JS_SetPendingException(cx, exn);
+      *_retval = JS_FALSE;
+      return NS_OK;
+    }
+
+    if (did_resolve) {
+      *objp = obj;
+      return NS_OK;
+    }
   }
 
   if (!(flags & JSRESOLVE_ASSIGNING)) {
     // We want this code to be before the child frame lookup code
     // below so that a child frame named 'constructor' doesn't
     // shadow the window's constructor property.
     if (sConstructor_id == id) {
       return ResolveConstructor(cx, obj, objp);
@@ -7160,16 +7125,17 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
 
   if (!my_context || !my_context->IsContextInitialized()) {
     // The context is not yet initialized so there's nothing we can do
     // here yet.
 
     return NS_OK;
   }
 
+  nsresult rv = NS_OK;
   if (sLocation_id == id) {
     // This must be done even if we're just getting the value of
     // window.location (i.e. no checking flags & JSRESOLVE_ASSIGNING
     // here) since we must define window.location to prevent the
     // getter from being overriden (for security reasons).
 
     // Note: Because we explicitly don't forward to the inner window
     // above, we have to ensure here that our window has a current
@@ -7301,46 +7267,16 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
     if (did_resolve) {
       // GlobalResolve() resolved something, so we're done here.
       *objp = obj;
 
       return NS_OK;
     }
   }
 
-  if (s_content_id == id) {
-    // Map window._content to window.content for backwards
-    // compatibility, this should spit out an message on the JS
-    // console.
-
-    JSObject *windowObj = win->GetGlobalJSObject();
-
-    JSAutoRequest ar(cx);
-
-    JSFunction *fun = ::JS_NewFunction(cx, ContentWindowGetter, 0, 0,
-                                       windowObj, "_content");
-    if (!fun) {
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-
-    JSObject *funObj = ::JS_GetFunctionObject(fun);
-
-    if (!::JS_DefinePropertyById(cx, windowObj, id, JSVAL_VOID,
-                                 JS_DATA_TO_FUNC_PTR(JSPropertyOp, funObj),
-                                 nullptr,
-                                 JSPROP_ENUMERATE | JSPROP_GETTER |
-                                 JSPROP_SHARED)) {
-      return NS_ERROR_FAILURE;
-    }
-
-    *objp = obj;
-
-    return NS_OK;
-  }
-
   if (flags & JSRESOLVE_ASSIGNING) {
     if (IsReadonlyReplaceable(id) ||
         (!(flags & JSRESOLVE_QUALIFIED) && IsWritableReplaceable(id))) {
       // A readonly "replaceable" property is being set, or a
       // readwrite "replaceable" property is being set w/o being
       // fully qualified. Define the property on obj with the value
       // undefined to override the predefined property. This is done
       // for compatibility with other browsers.
@@ -9060,25 +8996,26 @@ GetDocumentAllHelper(JSObject *obj)
   }
 
   return obj;
 }
 
 static inline void *
 FlagsToPrivate(PRUint32 flags)
 {
-  JS_ASSERT((flags & (1 << 31)) == 0);
-  return (void *)(flags << 1);
+  MOZ_ASSERT((flags & (1 << 31)) == 0);
+  return reinterpret_cast<void*>(static_cast<uintptr_t>(flags << 1));
 }
 
 static inline PRUint32
 PrivateToFlags(void *priv)
 {
-  JS_ASSERT(size_t(priv) <= PR_UINT32_MAX && (size_t(priv) & 1) == 0);
-  return (PRUint32)(size_t(priv) >> 1);
+  uintptr_t intPriv = reinterpret_cast<uintptr_t>(priv);
+  MOZ_ASSERT(intPriv <= PR_UINT32_MAX && (intPriv & 1) == 0);
+  return static_cast<PRUint32>(intPriv >> 1);
 }
 
 JSBool
 nsHTMLDocumentSH::DocumentAllHelperGetProperty(JSContext *cx, JSHandleObject obj,
                                                JSHandleId id, JSMutableHandleValue vp)
 {
   if (nsDOMClassInfo::sAll_id != id) {
     return JS_TRUE;
@@ -9573,24 +9510,28 @@ nsHTMLSelectElementSH::GetProperty(nsIXP
 // static
 nsresult
 nsHTMLSelectElementSH::SetOption(JSContext *cx, JS::Value *vp, PRUint32 aIndex,
                                  nsIDOMHTMLOptionsCollection *aOptCollection)
 {
   JSAutoRequest ar(cx);
 
   // vp must refer to an object
-  if (!vp->isObject()) {
+  if (!vp->isObjectOrNull()) {
     return NS_ERROR_UNEXPECTED;
   }
 
-  nsCOMPtr<nsIDOMHTMLOptionElement> new_option = do_QueryWrapper(cx, &vp->toObject());
-  if (!new_option) {
-    // Someone is trying to set an option to a non-option object.
-    return NS_ERROR_UNEXPECTED;
+  nsCOMPtr<nsIDOMHTMLOptionElement> new_option;
+
+  if (JSObject* obj = vp->toObjectOrNull()) {
+    new_option = do_QueryWrapper(cx, obj);
+    if (!new_option) {
+      // Someone is trying to set an option to a non-option object.
+      return NS_ERROR_UNEXPECTED;
+    }
   }
 
   return aOptCollection->SetOption(aIndex, new_option);
 }
 
 NS_IMETHODIMP
 nsHTMLSelectElementSH::SetProperty(nsIXPConnectWrappedNative *wrapper,
                                    JSContext *cx, JSObject *obj, jsid id,
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -152,17 +152,16 @@ protected:
   }
 
   virtual PRUint32 GetInterfacesBitmap()
   {
     return mData->mInterfacesBitmap;
   }
 
   static nsresult Init();
-  static nsresult RegisterClassName(PRInt32 aDOMClassInfoID);
   static nsresult RegisterClassProtos(PRInt32 aDOMClassInfoID);
   static nsresult RegisterExternalClasses();
   nsresult ResolveConstructor(JSContext *cx, JSObject *obj,
                               JSObject **objp);
 
   // Checks if id is a number and returns the number, if aIsNumber is
   // non-null it's set to true if the id is a number and false if it's
   // not a number. If id is not a number this method returns -1
--- a/dom/base/nsDOMNavigationTiming.cpp
+++ b/dom/base/nsDOMNavigationTiming.cpp
@@ -36,16 +36,24 @@ nsDOMNavigationTiming::Clear()
   mLoadEventStart = 0;
   mLoadEventEnd = 0;
   mDOMLoading = 0;
   mDOMInteractive = 0;
   mDOMContentLoadedEventStart = 0;
   mDOMContentLoadedEventEnd = 0;
   mDOMComplete = 0;
   mRedirectCheck = NOT_CHECKED;
+
+  mLoadEventStartSet = false;
+  mLoadEventEndSet = false;
+  mDOMLoadingSet = false;
+  mDOMInteractiveSet = false;
+  mDOMContentLoadedEventStartSet = false;
+  mDOMContentLoadedEventEndSet = false;
+  mDOMCompleteSet = false;
 }
 
 DOMTimeMilliSec
 nsDOMNavigationTiming::TimeStampToDOM(mozilla::TimeStamp aStamp) const
 {
   if (aStamp.IsNull()) {
     return 0;
   }
@@ -123,23 +131,29 @@ void
 nsDOMNavigationTiming::NotifyUnloadEventEnd()
 {
   mUnloadEnd = DurationFromStart();
 }
 
 void
 nsDOMNavigationTiming::NotifyLoadEventStart()
 {
-  mLoadEventStart = DurationFromStart();
+  if (!mLoadEventStartSet) {
+    mLoadEventStart = DurationFromStart();
+    mLoadEventStartSet = true;
+  }
 }
 
 void
 nsDOMNavigationTiming::NotifyLoadEventEnd()
 {
-  mLoadEventEnd = DurationFromStart();
+  if (!mLoadEventEndSet) {
+    mLoadEventEnd = DurationFromStart();
+    mLoadEventEndSet = true;
+  }
 }
 
 bool
 nsDOMNavigationTiming::ReportRedirects()
 {
   if (mRedirectCheck == NOT_CHECKED) {
     mRedirectCount = mRedirects.Count();
     if (mRedirects.Count() == 0) {
@@ -161,53 +175,71 @@ nsDOMNavigationTiming::ReportRedirects()
     }
   }
   return mRedirectCheck == CHECK_PASSED;
 }
 
 void
 nsDOMNavigationTiming::SetDOMLoadingTimeStamp(nsIURI* aURI, mozilla::TimeStamp aValue)
 {
-  mLoadedURI = aURI;
-  mDOMLoading = TimeStampToDOM(aValue);
+  if (!mDOMLoadingSet) {
+    mLoadedURI = aURI;
+    mDOMLoading = TimeStampToDOM(aValue);
+    mDOMLoadingSet = true;
+  }
 }
 
 void
 nsDOMNavigationTiming::NotifyDOMLoading(nsIURI* aURI)
 {
-  mLoadedURI = aURI;
-  mDOMLoading = DurationFromStart();
+  if (!mDOMLoadingSet) {
+    mLoadedURI = aURI;
+    mDOMLoading = DurationFromStart();
+    mDOMLoadingSet = true;
+  }
 }
 
 void
 nsDOMNavigationTiming::NotifyDOMInteractive(nsIURI* aURI)
 {
-  mLoadedURI = aURI;
-  mDOMInteractive = DurationFromStart();
+  if (!mDOMInteractiveSet) {
+    mLoadedURI = aURI;
+    mDOMInteractive = DurationFromStart();
+    mDOMInteractiveSet = true;
+  }
 }
 
 void
 nsDOMNavigationTiming::NotifyDOMComplete(nsIURI* aURI)
 {
-  mLoadedURI = aURI;
-  mDOMComplete = DurationFromStart();
+  if (!mDOMCompleteSet) {
+    mLoadedURI = aURI;
+    mDOMComplete = DurationFromStart();
+    mDOMCompleteSet = true;
+  }
 }
 
 void
 nsDOMNavigationTiming::NotifyDOMContentLoadedStart(nsIURI* aURI)
 {
-  mLoadedURI = aURI;
-  mDOMContentLoadedEventStart = DurationFromStart();
+  if (!mDOMContentLoadedEventStartSet) {
+    mLoadedURI = aURI;
+    mDOMContentLoadedEventStart = DurationFromStart();
+    mDOMContentLoadedEventStartSet = true;
+  }
 }
 
 void
 nsDOMNavigationTiming::NotifyDOMContentLoadedEnd(nsIURI* aURI)
 {
-  mLoadedURI = aURI;
-  mDOMContentLoadedEventEnd = DurationFromStart();
+  if (!mDOMContentLoadedEventEndSet) {
+    mLoadedURI = aURI;
+    mDOMContentLoadedEventEnd = DurationFromStart();
+    mDOMContentLoadedEventEndSet = true;
+  }
 }
 
 PRUint16
 nsDOMNavigationTiming::GetRedirectCount()
 {
   if (ReportRedirects()) {
     return mRedirectCount;
   }
--- a/dom/base/nsDOMNavigationTiming.h
+++ b/dom/base/nsDOMNavigationTiming.h
@@ -131,11 +131,22 @@ private:
   DOMTimeMilliSec mLoadEventStart;
   DOMTimeMilliSec mLoadEventEnd;
 
   DOMTimeMilliSec mDOMLoading;
   DOMTimeMilliSec mDOMInteractive;
   DOMTimeMilliSec mDOMContentLoadedEventStart;
   DOMTimeMilliSec mDOMContentLoadedEventEnd;
   DOMTimeMilliSec mDOMComplete;
+
+  // Booleans to keep track of what things we've already been notified
+  // about.  We don't update those once we've been notified about them
+  // once.
+  bool mLoadEventStartSet : 1;
+  bool mLoadEventEndSet : 1;
+  bool mDOMLoadingSet : 1;
+  bool mDOMInteractiveSet : 1;
+  bool mDOMContentLoadedEventStartSet : 1;
+  bool mDOMContentLoadedEventEndSet : 1;
+  bool mDOMCompleteSet : 1;
 };
 
 #endif /* nsDOMNavigationTiming_h___ */
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -1001,17 +1001,17 @@ nsDOMWindowUtils::CycleCollect(nsICycleC
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SendSimpleGestureEvent(const nsAString& aType,
                                          float aX,
                                          float aY,
                                          PRUint32 aDirection,
-                                         PRFloat64 aDelta,
+                                         double aDelta,
                                          PRInt32 aModifiers,
                                          PRUint32 aClickCount)
 {
   if (!IsUniversalXPConnectCapable()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   // get the widget to send the event to
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1951,16 +1951,27 @@ nsGlobalWindow::SetNewDocument(nsIDocume
         // Move the navigator from the old inner window to the new one since
         // this is a document.write. This is safe from a same-origin point of
         // view because document.write can only be used by the same origin.
         newInnerWindow->mNavigator = currentInner->mNavigator;
         currentInner->mNavigator = nullptr;
         if (newInnerWindow->mNavigator) {
           newInnerWindow->mNavigator->SetWindow(newInnerWindow);
         }
+
+        // Make a copy of the old window's performance object on document.open.
+        // Note that we have to force eager creation of it here, because we need
+        // to grab the current document channel and whatnot before that changes.
+        currentInner->CreatePerformanceObjectIfNeeded();
+        if (currentInner->mPerformance) {
+          newInnerWindow->mPerformance =
+            new nsPerformance(newInnerWindow,
+                              currentInner->mPerformance->GetDOMTiming(),
+                              currentInner->mPerformance->GetChannel());
+        }
       }
 
       // Don't free objects on our current inner window if it's going to be
       // held in the bfcache.
       if (!currentInner->IsFrozen()) {
         currentInner->FreeInnerObjects();
       }
     }
@@ -2926,37 +2937,41 @@ nsGlobalWindow::GetHistory(nsIDOMHistory
 NS_IMETHODIMP
 nsGlobalWindow::GetPerformance(nsISupports** aPerformance)
 {
   FORWARD_TO_INNER(GetPerformance, (aPerformance), NS_ERROR_NOT_INITIALIZED);
 
   *aPerformance = nullptr;
 
   if (nsGlobalWindow::HasPerformanceSupport()) {
-    if (!mPerformance) {
-      if (!mDoc) {
-        return NS_OK;
-      }
-      nsRefPtr<nsDOMNavigationTiming> timing = mDoc->GetNavigationTiming();
-      nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(mDoc->GetChannel()));
-      bool timingEnabled = false;
-      if (!timedChannel ||
-          !NS_SUCCEEDED(timedChannel->GetTimingEnabled(&timingEnabled)) ||
-          !timingEnabled) {
-        timedChannel = nullptr;
-      }
-      if (timing) {
-        mPerformance = new nsPerformance(this, timing, timedChannel);
-      }
-    }
+    CreatePerformanceObjectIfNeeded();
     NS_IF_ADDREF(*aPerformance = mPerformance);
   }
   return NS_OK;
 }
 
+void
+nsGlobalWindow::CreatePerformanceObjectIfNeeded()
+{
+  if (mPerformance || !mDoc) {
+    return;
+  }
+  nsRefPtr<nsDOMNavigationTiming> timing = mDoc->GetNavigationTiming();
+  nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(mDoc->GetChannel()));
+  bool timingEnabled = false;
+  if (!timedChannel ||
+      !NS_SUCCEEDED(timedChannel->GetTimingEnabled(&timingEnabled)) ||
+      !timingEnabled) {
+    timedChannel = nullptr;
+  }
+  if (timing) {
+    mPerformance = new nsPerformance(this, timing, timedChannel);
+  }
+}
+
 /**
  * GetScriptableParent is called when script reads window.parent.
  *
  * In contrast to GetRealParent, GetScriptableParent respects <iframe
  * mozbrowser> boundaries, so if |this| is contained by an <iframe
  * mozbrowser>, we will return |this| as its own parent.
  */
 NS_IMETHODIMP
@@ -3065,16 +3080,24 @@ nsGlobalWindow::GetTopImpl(nsIDOMWindow*
 
   if (parent) {
     parent.swap(*aTop);
   }
 
   return NS_OK;
 }
 
+// Map window._content to window.content for backwards compatibility, this
+// should spit out an message on the JS console.
+NS_IMETHODIMP
+nsGlobalWindow::GetContentForCompat(nsIDOMWindow** aContent)
+{
+  return GetContent(aContent);
+}
+
 NS_IMETHODIMP
 nsGlobalWindow::GetContent(nsIDOMWindow** aContent)
 {
   FORWARD_TO_OUTER(GetContent, (aContent), NS_ERROR_NOT_INITIALIZED);
   *aContent = nullptr;
 
   // If we're contained in <iframe mozbrowser>, then GetContent is the same as
   // window.top.
@@ -3109,17 +3132,17 @@ nsGlobalWindow::GetContent(nsIDOMWindow*
     nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
     GetTreeOwner(getter_AddRefs(treeOwner));
     NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
 
     treeOwner->GetPrimaryContentShell(getter_AddRefs(primaryContent));
   }
 
   nsCOMPtr<nsIDOMWindow> domWindow(do_GetInterface(primaryContent));
-  NS_IF_ADDREF(*aContent = domWindow);
+  domWindow.forget(aContent);
 
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsGlobalWindow::GetPrompter(nsIPrompt** aPrompt)
 {
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -900,16 +900,19 @@ protected:
 
   void SetIsApp(bool aValue);
   nsresult SetApp(const nsAString& aManifestURL);
   nsresult GetApp(mozIDOMApplication** aApplication);
 
   // Implements Get{Real,Scriptable}Top.
   nsresult GetTopImpl(nsIDOMWindow **aWindow, bool aScriptable);
 
+  // Helper for creating performance objects.
+  void CreatePerformanceObjectIfNeeded();
+
   // When adding new member variables, be careful not to create cycles
   // through JavaScript.  If there is any chance that a member variable
   // could own objects that are implemented in JavaScript, then those
   // objects will keep the global object (this object) alive.  To prevent
   // these cycles, ownership of such members must be released in
   // |CleanUp| and |DetachFromDocShell|.
 
   // This member is also used on both inner and outer windows, but
@@ -985,16 +988,17 @@ protected:
   nsCOMPtr<nsIScriptContext>    mContext;
   nsWeakPtr                     mOpener;
   nsCOMPtr<nsIControllers>      mControllers;
   nsCOMPtr<nsIArray>            mArguments;
   nsCOMPtr<nsIArray>            mArgumentsLast;
   nsCOMPtr<nsIPrincipal>        mArgumentsOrigin;
   nsRefPtr<Navigator>           mNavigator;
   nsRefPtr<nsScreen>            mScreen;
+  // mPerformance is only used on inner windows.
   nsRefPtr<nsPerformance>       mPerformance;
   nsRefPtr<nsDOMWindowList>     mFrames;
   nsRefPtr<nsBarProp>           mMenubar;
   nsRefPtr<nsBarProp>           mToolbar;
   nsRefPtr<nsBarProp>           mLocationbar;
   nsRefPtr<nsBarProp>           mPersonalbar;
   nsRefPtr<nsBarProp>           mStatusbar;
   nsRefPtr<nsBarProp>           mScrollbars;
--- a/dom/base/nsPerformance.h
+++ b/dom/base/nsPerformance.h
@@ -135,16 +135,21 @@ public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsPerformance)
 
   nsDOMNavigationTiming* GetDOMTiming() const
   {
     return mDOMTiming;
   }
 
+  nsITimedChannel* GetChannel() const
+  {
+    return mChannel;
+  }
+
   nsIDOMWindow* GetParentObject() const
   {
     return mWindow.get();
   }
 
   JSObject* WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap);
 
   // Performance WebIDL methods
--- a/dom/bindings/TypedArray.h
+++ b/dom/bindings/TypedArray.h
@@ -59,17 +59,17 @@ template<typename T,
          JSObject* CreateNew(JSContext*, uint32_t)>
 struct TypedArray : public TypedArray_base<T,UnboxArray> {
   TypedArray(JSContext* cx, JSObject* obj) :
     TypedArray_base<T,UnboxArray>(cx, obj)
   {}
 
   static inline JSObject*
   Create(JSContext* cx, nsWrapperCache* creator, uint32_t length,
-         T* data = NULL) {
+         const T* data = NULL) {
     JSObject* creatorWrapper;
     JSAutoEnterCompartment ac;
     if (creator && (creatorWrapper = creator->GetWrapperPreserveColor())) {
       if (!ac.enter(cx, creatorWrapper)) {
         return NULL;
       }
     }
     JSObject* obj = CreateNew(cx, length);
--- a/dom/bluetooth/BluetoothAdapter.cpp
+++ b/dom/bluetooth/BluetoothAdapter.cpp
@@ -57,24 +57,28 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothAdapter)
   NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothAdapter)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothAdapter)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(BluetoothAdapter, nsDOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(BluetoothAdapter, nsDOMEventTargetHelper)
 
-BluetoothAdapter::BluetoothAdapter(nsPIDOMWindow* aOwner, const nsAString& aPath)
+BluetoothAdapter::BluetoothAdapter(nsPIDOMWindow* aOwner, const BluetoothValue& aValue)
     : BluetoothPropertyContainer(BluetoothObjectType::TYPE_ADAPTER)
     , mJsUuids(nullptr)
     , mJsDeviceAddresses(nullptr)
     , mIsRooted(false)
 {
   BindToOwner(aOwner);
-  mPath = aPath;
+  const InfallibleTArray<BluetoothNamedValue>& values =
+    aValue.get_ArrayOfBluetoothNamedValue();
+  for (uint32_t i = 0; i < values.Length(); ++i) {
+    SetPropertyByValue(values[i]);
+  }
 }
 
 BluetoothAdapter::~BluetoothAdapter()
 {
   BluetoothService* bs = BluetoothService::Get();
   // We can be null on shutdown, where this might happen
   if (bs) {
     if (NS_FAILED(bs->UnregisterBluetoothSignalHandler(mPath, this))) {
@@ -170,31 +174,26 @@ BluetoothAdapter::SetPropertyByValue(con
     warningMsg.Append(NS_ConvertUTF16toUTF8(name));
     NS_WARNING(warningMsg.get());
 #endif
   }
 }
 
 // static
 already_AddRefed<BluetoothAdapter>
-BluetoothAdapter::Create(nsPIDOMWindow* aOwner, const nsAString& aPath)
+BluetoothAdapter::Create(nsPIDOMWindow* aOwner, const BluetoothValue& aValue)
 {
-  // Make sure we at least have a path
-  NS_ASSERTION(!aPath.IsEmpty(), "Adapter created with empty path!");
-    
   BluetoothService* bs = BluetoothService::Get();
   if (!bs) {
     NS_WARNING("BluetoothService not available!");
     return nullptr;
   }
 
-  nsRefPtr<BluetoothAdapter> adapter = new BluetoothAdapter(aOwner, aPath);
-  nsString path;
-  path = adapter->GetPath();
-  if (NS_FAILED(bs->RegisterBluetoothSignalHandler(path, adapter))) {
+  nsRefPtr<BluetoothAdapter> adapter = new BluetoothAdapter(aOwner, aValue);
+  if (NS_FAILED(bs->RegisterBluetoothSignalHandler(adapter->GetPath(), adapter))) {
     NS_WARNING("Failed to register object with observer!");
     return nullptr;
   }
   return adapter.forget();
 }
 
 void
 BluetoothAdapter::Notify(const BluetoothSignal& aData)
--- a/dom/bluetooth/BluetoothAdapter.h
+++ b/dom/bluetooth/BluetoothAdapter.h
@@ -15,33 +15,34 @@
 
 class nsIEventTarget;
 class nsIDOMDOMRequest;
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothSignal;
 class BluetoothNamedValue;
+class BluetoothValue;
 
 class BluetoothAdapter : public nsDOMEventTargetHelper
                        , public nsIDOMBluetoothAdapter
                        , public BluetoothSignalObserver
                        , public BluetoothPropertyContainer
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMBLUETOOTHADAPTER
 
   NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(BluetoothAdapter,
                                                          nsDOMEventTargetHelper)
 
   static already_AddRefed<BluetoothAdapter>
-  Create(nsPIDOMWindow* aOwner, const nsAString& name);
+  Create(nsPIDOMWindow* aOwner, const BluetoothValue& aValue);
 
   void Notify(const BluetoothSignal& aParam);
 
   nsIDOMEventTarget*
   ToIDOMEventTarget() const
   {
     return static_cast<nsDOMEventTargetHelper*>(
       const_cast<BluetoothAdapter*>(this));
@@ -52,17 +53,17 @@ public:
   {
     return ToIDOMEventTarget();
   }
 
   void Unroot();
   virtual void SetPropertyByValue(const BluetoothNamedValue& aValue);  
 private:
   
-  BluetoothAdapter(nsPIDOMWindow* aOwner, const nsAString& aPath);
+  BluetoothAdapter(nsPIDOMWindow* aOwner, const BluetoothValue& aValue);
   ~BluetoothAdapter();
 
   void Root();
   nsresult StartStopDiscovery(bool aStart, nsIDOMDOMRequest** aRequest);
   
   nsString mAddress;
   nsString mName;
   bool mEnabled;
--- a/dom/bluetooth/BluetoothManager.cpp
+++ b/dom/bluetooth/BluetoothManager.cpp
@@ -59,20 +59,19 @@ public:
   }
 
   bool
   ParseSuccessfulReply(jsval* aValue)
   {
     nsCOMPtr<nsIDOMBluetoothAdapter> adapter;
     *aValue = JSVAL_VOID;
 
-    const nsString& path =
-      mReply->get_BluetoothReplySuccess().value().get_nsString();
-    adapter = BluetoothAdapter::Create(mManagerPtr->GetOwner(),
-                                       path);
+    const InfallibleTArray<BluetoothNamedValue>& v =
+      mReply->get_BluetoothReplySuccess().value().get_ArrayOfBluetoothNamedValue();
+    adapter = BluetoothAdapter::Create(mManagerPtr->GetOwner(), v);
 
     nsresult rv;
     nsIScriptContext* sc = mManagerPtr->GetContextForEventHandlers(&rv);
     if (!sc) {
       NS_WARNING("Cannot create script context!");
       SetError(NS_LITERAL_STRING("BluetoothScriptContextError"));
       return false;
     }
--- a/dom/bluetooth/BluetoothService.cpp
+++ b/dom/bluetooth/BluetoothService.cpp
@@ -17,44 +17,47 @@
 #include "mozilla/Services.h"
 #include "mozilla/LazyIdleThread.h"
 #include "mozilla/Util.h"
 
 using namespace mozilla;
 
 USING_BLUETOOTH_NAMESPACE
 
-nsRefPtr<BluetoothService> gBluetoothService;
-nsCOMPtr<nsIThread> gToggleBtThread;
-int gPendingInitCount = 0;
-bool gInShutdown = false;
+static nsRefPtr<BluetoothService> gBluetoothService;
+static bool gInShutdown = false;
 
 NS_IMPL_ISUPPORTS1(BluetoothService, nsIObserver)
 
 class ToggleBtAck : public nsRunnable
 {
 public:
+  ToggleBtAck(bool aEnabled) :
+    mEnabled(aEnabled)
+  {
+  }
+  
   NS_IMETHOD Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
-    gPendingInitCount--;
-    
-    if (gPendingInitCount) {
-      return NS_OK;
+
+    if (!mEnabled || gInShutdown) {
+      nsCOMPtr<nsIThread> t;
+      gBluetoothService->mBluetoothCommandThread.swap(t);
+      t->Shutdown();
     }
     
     if (gInShutdown) {
       gBluetoothService = nullptr;
     }
 
-    nsCOMPtr<nsIThread> t;
-    gToggleBtThread.swap(t);
-    t->Shutdown();
     return NS_OK;
   }
+
+  bool mEnabled;
 };
 
 class ToggleBtTask : public nsRunnable
 {
 public:
   ToggleBtTask(bool aEnabled,
                BluetoothReplyRunnable* aRunnable)
     : mEnabled(aEnabled),
@@ -77,17 +80,17 @@ public:
       if (NS_FAILED(gBluetoothService->StopInternal())) {        
         replyError.AssignLiteral("Bluetooth service not available - We should never reach this point!");
       }
     }
 
     // Always has to be called since this is where we take care of our reference
     // count for runnables. If there's an error, replyError won't be empty, so
     // consider our status flipped.
-    nsCOMPtr<nsIRunnable> ackTask = new ToggleBtAck();
+    nsCOMPtr<nsIRunnable> ackTask = new ToggleBtAck(mEnabled);
     if (NS_FAILED(NS_DispatchToMainThread(ackTask))) {
       NS_WARNING("Failed to dispatch to main thread!");
     }
     
     if (!mRunnable) {
       return NS_OK;
     }
     
@@ -163,27 +166,26 @@ BluetoothService::StartStopBluetooth(Blu
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // If we're shutting down, bail early.
   if (gInShutdown && aStart) {
     NS_ERROR("Start called while in shutdown!");
     return NS_ERROR_FAILURE;
   }
-  if (!gToggleBtThread) {
-    nsresult rv = NS_NewNamedThread("BluetoothCtrl",
-                                    getter_AddRefs(gToggleBtThread));
+  if (!mBluetoothCommandThread) {
+    nsresult rv = NS_NewNamedThread("BluetoothCmd",
+                                    getter_AddRefs(mBluetoothCommandThread));
     NS_ENSURE_SUCCESS(rv, rv);
   }
   nsCOMPtr<nsIRunnable> r = new ToggleBtTask(aStart, aResultRunnable);
-  if (NS_FAILED(gToggleBtThread->Dispatch(r, NS_DISPATCH_NORMAL))) {
+  if (NS_FAILED(mBluetoothCommandThread->Dispatch(r, NS_DISPATCH_NORMAL))) {
     NS_WARNING("Cannot dispatch firmware loading task!");
     return NS_ERROR_FAILURE;
   }
-  gPendingInitCount++;
   return NS_OK;
 }
 
 nsresult
 BluetoothService::Start(BluetoothReplyRunnable* aResultRunnable)
 {
   return StartStopBluetooth(aResultRunnable, true);
 }
--- a/dom/bluetooth/BluetoothService.h
+++ b/dom/bluetooth/BluetoothService.h
@@ -187,16 +187,29 @@ public:
                 const nsAString& aDeviceAddress,
                 nsAString& aDevicePath) = 0;
 
   virtual int
   GetDeviceServiceChannelInternal(const nsAString& aObjectPath,
                                   const nsAString& aPattern,
                                   int aAttributeId) = 0;
 
+  /**
+   * Due to the fact that some operations require multiple calls, a
+   * CommandThread is created that can run blocking, platform-specific calls
+   * where either no asynchronous equivilent exists, or else where multiple
+   * asynchronous calls would require excessive runnable bouncing between main
+   * thread and IO thread.
+   *
+   * For instance, when we retrieve an Adapter object, we would like it to come
+   * with all of its properties filled in and registered as an agent, which
+   * requires a minimum of 3 calls to platform specific code on some platforms.
+   *
+   */
+  nsCOMPtr<nsIThread> mBluetoothCommandThread;
 protected:
   BluetoothService()
   {
     mBluetoothSignalObserverTable.Init();
   }
 
   virtual ~BluetoothService()
   {
--- a/dom/bluetooth/linux/BluetoothDBusService.cpp
+++ b/dom/bluetooth/linux/BluetoothDBusService.cpp
@@ -122,16 +122,23 @@ static const char* sBluetoothDBusSignals
   "type='signal',interface='org.bluez.Device'",
   "type='signal',interface='org.bluez.Input'",
   "type='signal',interface='org.bluez.Network'",
   "type='signal',interface='org.bluez.NetworkServer'",
   "type='signal',interface='org.bluez.HealthDevice'",
   "type='signal',interface='org.bluez.AudioSink'"
 };
 
+/**
+ * DBus Connection held for the BluetoothCommandThread to use. Should never be
+ * used by any other thread.
+ * 
+ */
+static nsAutoPtr<RawDBusConnection> gThreadConnection;
+
 class DistributeBluetoothSignalTask : public nsRunnable {
   BluetoothSignal mSignal;
 public:
   DistributeBluetoothSignalTask(const BluetoothSignal& aSignal) :
     mSignal(aSignal)
   {
   }
 
@@ -144,125 +151,135 @@ public:
       NS_WARNING("BluetoothService not available!");
       return NS_ERROR_FAILURE;
     }    
     return bs->DistributeSignal(mSignal);
   }  
 };
 
 bool
-IsDBusMessageError(DBusMessage* aMsg, nsAString& aError)
+IsDBusMessageError(DBusMessage* aMsg, DBusError* aErr, nsAString& aErrorStr)
 {
+  if(aErr && dbus_error_is_set(aErr)) {
+    aErrorStr = NS_ConvertUTF8toUTF16(aErr->message);
+    LOG_AND_FREE_DBUS_ERROR(aErr);
+    return true;
+  }
+  
   DBusError err;
   dbus_error_init(&err);
   if (dbus_message_get_type(aMsg) == DBUS_MESSAGE_TYPE_ERROR) {
     const char* error_msg;
     if (!dbus_message_get_args(aMsg, &err, DBUS_TYPE_STRING,
                                &error_msg, DBUS_TYPE_INVALID) ||
         !error_msg) {
       if (dbus_error_is_set(&err)) {
-        aError = NS_ConvertUTF8toUTF16(err.message);
+        aErrorStr = NS_ConvertUTF8toUTF16(err.message);
         LOG_AND_FREE_DBUS_ERROR(&err);
         return true;
+      } else {
+        aErrorStr.AssignLiteral("Unknown Error");
+        return true;
       }
     } else {
-      aError = NS_ConvertUTF8toUTF16(error_msg);
+      aErrorStr = NS_ConvertUTF8toUTF16(error_msg);
       return true;
     }
   }
   return false;
 }
 
 void
 DispatchBluetoothReply(BluetoothReplyRunnable* aRunnable,
-                       const BluetoothValue& aValue, const nsAString& aError)
+                       const BluetoothValue& aValue, const nsAString& aErrorStr)
 {
   // Reply will be deleted by the runnable after running on main thread
   BluetoothReply* reply;
-  if (!aError.IsEmpty()) {
-    nsString err(aError);
+  if (!aErrorStr.IsEmpty()) {
+    nsString err(aErrorStr);
     reply = new BluetoothReply(BluetoothReplyError(err));
-  }
-  else {
+  } else {
     reply = new BluetoothReply(BluetoothReplySuccess(aValue));
   }
   
   aRunnable->SetReply(reply);
   if (NS_FAILED(NS_DispatchToMainThread(aRunnable))) {
     NS_WARNING("Failed to dispatch to main thread!");
   }
 }
 
 void
-UnpackObjectPathMessage(DBusMessage* aMsg, BluetoothValue& aValue,
-                        nsAString& aErrorStr)
+UnpackObjectPathMessage(DBusMessage* aMsg, DBusError* aErr,
+                        BluetoothValue& aValue, nsAString& aErrorStr)
 {
   DBusError err;
   dbus_error_init(&err);
-  if (!IsDBusMessageError(aMsg, aErrorStr)) {
+  if (!IsDBusMessageError(aMsg, aErr, aErrorStr)) {
     NS_ASSERTION(dbus_message_get_type(aMsg) == DBUS_MESSAGE_TYPE_METHOD_RETURN,
                  "Got dbus callback that's not a METHOD_RETURN!");
     const char* object_path;
     if (!dbus_message_get_args(aMsg, &err, DBUS_TYPE_OBJECT_PATH,
                                &object_path, DBUS_TYPE_INVALID) ||
         !object_path) {
       if (dbus_error_is_set(&err)) {
         aErrorStr = NS_ConvertUTF8toUTF16(err.message);
         LOG_AND_FREE_DBUS_ERROR(&err);
       }
     } else {
       aValue = NS_ConvertUTF8toUTF16(object_path);
     }
   }
 }
 
-typedef void (*UnpackFunc)(DBusMessage*, BluetoothValue&, nsAString&);
+typedef void (*UnpackFunc)(DBusMessage*, DBusError*, BluetoothValue&, nsAString&);
 
 void
 RunDBusCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable,
                 UnpackFunc aFunc)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   nsRefPtr<BluetoothReplyRunnable> replyRunnable =
     dont_AddRef(static_cast< BluetoothReplyRunnable* >(aBluetoothReplyRunnable));
 
   NS_ASSERTION(replyRunnable, "Callback reply runnable is null!");
 
   nsString replyError;
   BluetoothValue v;
-  aFunc(aMsg, v, replyError);
+  aFunc(aMsg, nsnull, v, replyError);
   DispatchBluetoothReply(replyRunnable, v, replyError);  
 }
 
 void
 GetObjectPathCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
 {
-  RunDBusCallback(aMsg, aBluetoothReplyRunnable, UnpackObjectPathMessage);
+  RunDBusCallback(aMsg, aBluetoothReplyRunnable,
+                  UnpackObjectPathMessage);
 }
 
 void
-UnpackVoidMessage(DBusMessage* aMsg, BluetoothValue& aValue,
+UnpackVoidMessage(DBusMessage* aMsg, DBusError* aErr, BluetoothValue& aValue,
                   nsAString& aErrorStr)
 {
   DBusError err;
   dbus_error_init(&err);
-  if (!IsDBusMessageError(aMsg, aErrorStr) &&
+  if (!IsDBusMessageError(aMsg, aErr, aErrorStr) &&
       dbus_message_get_type(aMsg) == DBUS_MESSAGE_TYPE_METHOD_RETURN &&
       !dbus_message_get_args(aMsg, &err, DBUS_TYPE_INVALID)) {
     if (dbus_error_is_set(&err)) {
       aErrorStr = NS_ConvertUTF8toUTF16(err.message);
       LOG_AND_FREE_DBUS_ERROR(&err);
     }
   }
 }
 
 void
 GetVoidCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
 {
-  RunDBusCallback(aMsg, aBluetoothReplyRunnable, UnpackVoidMessage);
+  RunDBusCallback(aMsg, aBluetoothReplyRunnable,
+                  UnpackVoidMessage);
 }
 
 bool
 GetProperty(DBusMessageIter aIter, Properties* aPropertyTypes,
             int aPropertyTypeLen, int* aPropIndex,
             InfallibleTArray<BluetoothNamedValue>& aProperties)
 {
   DBusMessageIter prop_val, array_val_iter;
@@ -376,72 +393,83 @@ ParseProperties(DBusMessageIter* aIter,
       NS_WARNING("Can't create property!");
       return;
     }
   } while (dbus_message_iter_next(&dict));
 
   aValue = props;
 }
 
-void UnpackPropertiesMessage(DBusMessage* aMsg, BluetoothValue& aValue,
-                             nsAString& aErrorStr, Properties* aPropertyTypes,
-                             const int aPropertyTypeLen)
+void
+UnpackPropertiesMessage(DBusMessage* aMsg, DBusError* aErr,
+                        BluetoothValue& aValue, nsAString& aErrorStr,
+                        Properties* aPropertyTypes,
+                        const int aPropertyTypeLen)
 {
-  if (!IsDBusMessageError(aMsg, aErrorStr) &&
+  if (!IsDBusMessageError(aMsg, aErr, aErrorStr) &&
       dbus_message_get_type(aMsg) == DBUS_MESSAGE_TYPE_METHOD_RETURN) {
     DBusMessageIter iter;
     if (!dbus_message_iter_init(aMsg, &iter)) {
       aErrorStr.AssignLiteral("Cannot create dbus message iter!");
     } else {
       ParseProperties(&iter, aValue, aErrorStr, aPropertyTypes,
                       aPropertyTypeLen);
     }
   }
 }
 
-void UnpackAdapterPropertiesMessage(DBusMessage* aMsg, BluetoothValue& aValue,
-                                    nsAString& aErrorStr)
+void
+UnpackAdapterPropertiesMessage(DBusMessage* aMsg, DBusError* aErr,
+                               BluetoothValue& aValue,
+                               nsAString& aErrorStr)
 {
-  UnpackPropertiesMessage(aMsg, aValue, aErrorStr,
+  UnpackPropertiesMessage(aMsg, aErr, aValue, aErrorStr,
                           sAdapterProperties,
                           ArrayLength(sAdapterProperties));
 }
 
-void UnpackDevicePropertiesMessage(DBusMessage* aMsg, BluetoothValue& aValue,
-                                    nsAString& aErrorStr)
+void
+UnpackDevicePropertiesMessage(DBusMessage* aMsg, DBusError* aErr,
+                              BluetoothValue& aValue,
+                              nsAString& aErrorStr)
 {
-  UnpackPropertiesMessage(aMsg, aValue, aErrorStr,
+  UnpackPropertiesMessage(aMsg, aErr, aValue, aErrorStr,
                           sDeviceProperties,
                           ArrayLength(sDeviceProperties));
 }
 
-void UnpackManagerPropertiesMessage(DBusMessage* aMsg, BluetoothValue& aValue,
-                                    nsAString& aErrorStr)
+void
+UnpackManagerPropertiesMessage(DBusMessage* aMsg, DBusError* aErr,
+                               BluetoothValue& aValue,
+                               nsAString& aErrorStr)
 {
-  UnpackPropertiesMessage(aMsg, aValue, aErrorStr,
+  UnpackPropertiesMessage(aMsg, aErr, aValue, aErrorStr,
                           sManagerProperties,
                           ArrayLength(sManagerProperties));
 }
 
 void
 GetManagerPropertiesCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
 {
-  RunDBusCallback(aMsg, aBluetoothReplyRunnable, UnpackManagerPropertiesMessage);
+  RunDBusCallback(aMsg, aBluetoothReplyRunnable,
+                  UnpackManagerPropertiesMessage);
 }
 
 void
 GetAdapterPropertiesCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
 {
-  RunDBusCallback(aMsg, aBluetoothReplyRunnable, UnpackAdapterPropertiesMessage);
+  RunDBusCallback(aMsg, aBluetoothReplyRunnable,
+                  UnpackAdapterPropertiesMessage);
 }
 
 void
 GetDevicePropertiesCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
 {
-  RunDBusCallback(aMsg, aBluetoothReplyRunnable, UnpackDevicePropertiesMessage);
+  RunDBusCallback(aMsg, aBluetoothReplyRunnable,
+                  UnpackDevicePropertiesMessage);
 }
 
 static DBusCallback sBluetoothDBusPropCallbacks[] =
 {
   GetManagerPropertiesCallback,
   GetAdapterPropertiesCallback,
   GetDevicePropertiesCallback
 };
@@ -606,17 +634,25 @@ BluetoothDBusService::StartInternal()
     return NS_ERROR_FAILURE;
   }
   
   if (mConnection) {
     return NS_OK;
   }
 
   if (NS_FAILED(EstablishDBusConnection())) {
-    NS_WARNING("Cannot start DBus connection!");
+    NS_WARNING("Cannot start Main Thread DBus connection!");
+    StopDBus();
+    return NS_ERROR_FAILURE;
+  }
+
+  gThreadConnection = new RawDBusConnection();
+  
+  if (NS_FAILED(gThreadConnection->EstablishDBusConnection())) {
+    NS_WARNING("Cannot start Sync Thread DBus connection!");
     StopDBus();
     return NS_ERROR_FAILURE;
   }
 
   DBusError err;
   dbus_error_init(&err);
 
   // Set which messages will be processed by this dbus connection.
@@ -662,43 +698,105 @@ BluetoothDBusService::StopInternal()
     if (dbus_error_is_set(&err)) {
       LOG_AND_FREE_DBUS_ERROR(&err);
     }
   }
 
   dbus_connection_remove_filter(mConnection, EventFilter, nullptr);
   
   mConnection = nullptr;
+  gThreadConnection = nullptr;
   mBluetoothSignalObserverTable.Clear();
   StopDBus();
   return NS_OK;
 }
 
+class DefaultAdapterPropertiesRunnable : public nsRunnable
+{
+public:
+  DefaultAdapterPropertiesRunnable(BluetoothReplyRunnable* aRunnable)
+    : mRunnable(dont_AddRef(aRunnable))
+  {
+  }
+
+  nsresult
+  Run()
+  {
+    MOZ_ASSERT(!NS_IsMainThread());
+    DBusError err;
+    dbus_error_init(&err);
+   
+    BluetoothValue v;
+    nsString replyError;
+
+    DBusMessage* msg = dbus_func_args_timeout(gThreadConnection->GetConnection(),
+                                              1000,
+                                              &err,
+                                              "/",
+                                              DBUS_MANAGER_IFACE,
+                                              "DefaultAdapter",
+                                              DBUS_TYPE_INVALID);
+    UnpackObjectPathMessage(msg, &err, v, replyError);
+    if(msg) {
+      dbus_message_unref(msg);
+    }
+    if(!replyError.IsEmpty()) {
+      DispatchBluetoothReply(mRunnable, v, replyError);
+      return NS_ERROR_FAILURE;
+    }
+
+    nsString path = v.get_nsString();
+    nsCString tmp_path = NS_ConvertUTF16toUTF8(path);
+    const char* object_path = tmp_path.get();
+   
+    v = InfallibleTArray<BluetoothNamedValue>();
+    msg = dbus_func_args_timeout(gThreadConnection->GetConnection(),
+                                 1000,
+                                 &err,
+                                 object_path,
+                                 "org.bluez.Adapter",
+                                 "GetProperties",
+                                 DBUS_TYPE_INVALID);
+    UnpackAdapterPropertiesMessage(msg, &err, v, replyError);
+   
+    if(!replyError.IsEmpty()) {
+      DispatchBluetoothReply(mRunnable, v, replyError);
+      return NS_ERROR_FAILURE;
+    }
+    if(msg) {
+      dbus_message_unref(msg);
+    }
+    // We have to manually attach the path to the rest of the elements
+    v.get_ArrayOfBluetoothNamedValue().AppendElement(BluetoothNamedValue(NS_LITERAL_STRING("Path"),
+                                                                         path));
+    DispatchBluetoothReply(mRunnable, v, replyError);
+   
+    return NS_OK;
+  }
+
+private:
+  nsRefPtr<BluetoothReplyRunnable> mRunnable;
+};
+
 nsresult
 BluetoothDBusService::GetDefaultAdapterPathInternal(BluetoothReplyRunnable* aRunnable)
 {
-  if (!mConnection) {
+  if (!mConnection || !gThreadConnection) {
     NS_ERROR("Bluetooth service not started yet!");
     return NS_ERROR_FAILURE;
   }
   NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!");
-
   nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
 
-  if (!dbus_func_args_async(mConnection,
-                            1000,
-                            GetObjectPathCallback,
-                            (void*)aRunnable,
-                            "/",
-                            "org.bluez.Manager",
-                            "DefaultAdapter",
-                            DBUS_TYPE_INVALID)) {
-    NS_WARNING("Could not start async function!");
+  nsRefPtr<nsRunnable> func(new DefaultAdapterPropertiesRunnable(runnable));
+  if (NS_FAILED(mBluetoothCommandThread->Dispatch(func, NS_DISPATCH_NORMAL))) {
+    NS_WARNING("Cannot dispatch firmware loading task!");
     return NS_ERROR_FAILURE;
   }
+
   runnable.forget();
   return NS_OK;
 }
 
 nsresult
 BluetoothDBusService::SendDiscoveryMessage(const nsAString& aAdapterPath,
                                            const char* aMessageName,
                                            BluetoothReplyRunnable* aRunnable)
--- a/dom/browser-element/BrowserElementScrolling.js
+++ b/dom/browser-element/BrowserElementScrolling.js
@@ -4,16 +4,17 @@
 
 const ContentPanning = {
   init: function cp_init() {
     ['mousedown', 'mouseup', 'mousemove'].forEach(function(type) {
       addEventListener(type, ContentPanning, true);
     });
 
     addMessageListener("Viewport:Change", this._recvViewportChange.bind(this));
+    addMessageListener("Gesture:DoubleTap", this._recvDoubleTap.bind(this));
   },
 
   handleEvent: function cp_handleEvent(evt) {
     switch (evt.type) {
       case 'mousedown':
         this.onTouchStart(evt);
         break;
       case 'mousemove':
@@ -38,16 +39,26 @@ const ContentPanning = {
 
   onTouchStart: function cp_onTouchStart(evt) {
     this.dragging = true;
     this.panning = false;
 
     let oldTarget = this.target;
     [this.target, this.scrollCallback] = this.getPannable(evt.target);
 
+    // If we found a target, that means we have found a scrollable subframe. In
+    // this case, and if we are using async panning and zooming on the parent
+    // frame, inform the pan/zoom controller that it should not attempt to
+    // handle any touch events it gets until the next batch (meaning the next
+    // time we get a touch end).
+    if (this.target != null && ContentPanning._asyncPanZoomForViewportFrame) {
+      var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
+      os.notifyObservers(docShell, 'cancel-default-pan-zoom', null);
+    }
+
     // If there is a pan animation running (from a previous pan gesture) and
     // the user touch back the screen, stop this animation immediatly and
     // prevent the possible click action if the touch happens on the same
     // target.
     this.preventNextClick = false;
     if (KineticPanning.active) {
       KineticPanning.stop();
 
@@ -185,42 +196,158 @@ const ContentPanning = {
     this._domUtils.setContentState(root.documentElement, kStateActive);
   },
 
   get _asyncPanZoomForViewportFrame() {
     return docShell.asyncPanZoomEnabled;
   },
 
   _recvViewportChange: function(data) {
-    let viewport = data.json;
-    let displayPort = viewport.displayPort;
+    let metrics = data.json;
+    let displayPort = metrics.displayPort;
+
+    let screenWidth = metrics.screenSize.width;
+    let screenHeight = metrics.screenSize.height;
+
+    let x = metrics.x;
+    let y = metrics.y;
 
-    let screenWidth = viewport.screenSize.width;
-    let screenHeight = viewport.screenSize.height;
-
-    let x = viewport.x;
-    let y = viewport.y;
+    this._zoom = metrics.zoom;
+    this._viewport = new Rect(x, y,
+                              screenWidth / metrics.zoom,
+                              screenHeight / metrics.zoom);
+    this._cssPageRect = new Rect(metrics.cssPageRect.x,
+                                 metrics.cssPageRect.y,
+                                 metrics.cssPageRect.width,
+                                 metrics.cssPageRect.height);
 
     let cwu = content.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
-    cwu.setCSSViewport(screenWidth, screenHeight);
+    if (this._screenWidth != screenWidth || this._screenHeight != screenHeight) {
+      cwu.setCSSViewport(screenWidth, screenHeight);
+      this._screenWidth = screenWidth;
+      this._screenHeight = screenHeight;
+    }
 
     // Set scroll position
     cwu.setScrollPositionClampingScrollPortSize(
-      screenWidth / viewport.zoom, screenHeight / viewport.zoom);
+      screenWidth / metrics.zoom, screenHeight / metrics.zoom);
     content.scrollTo(x, y);
     cwu.setResolution(displayPort.resolution, displayPort.resolution);
 
     let element = null;
     if (content.document && (element = content.document.documentElement)) {
       cwu.setDisplayPortForElement(displayPort.left,
                                    displayPort.top,
                                    displayPort.width,
                                    displayPort.height,
                                    element);
     }
+  },
+
+  _recvDoubleTap: function(data) {
+    let data = data.json;
+
+    // We haven't received a metrics update yet; don't do anything.
+    if (this._viewport == null) {
+      return;
+    }
+
+    let win = content;
+
+    let zoom = this._zoom;
+    let element = ElementTouchHelper.anyElementFromPoint(win, data.x, data.y);
+    if (!element) {
+      this._zoomOut();
+      return;
+    }
+
+    while (element && !this._shouldZoomToElement(element))
+      element = element.parentNode;
+
+    if (!element) {
+      this._zoomOut();
+    } else {
+      const margin = 15;
+      let rect = ElementTouchHelper.getBoundingContentRect(element);
+
+      let cssPageRect = this._cssPageRect;
+      let viewport = this._viewport;
+      let bRect = new Rect(Math.max(cssPageRect.left, rect.x - margin),
+                           rect.y,
+                           rect.w + 2 * margin,
+                           rect.h);
+      // constrict the rect to the screen's right edge
+      bRect.width = Math.min(bRect.width, cssPageRect.right - bRect.x);
+
+      // if the rect is already taking up most of the visible area and is stretching the
+      // width of the page, then we want to zoom out instead.
+      if (this._isRectZoomedIn(bRect, viewport)) {
+        this._zoomOut();
+        return;
+      }
+
+      rect.x = Math.round(bRect.x);
+      rect.y = Math.round(bRect.y);
+      rect.w = Math.round(bRect.width);
+      rect.h = Math.round(Math.min(bRect.width * viewport.height / viewport.height, bRect.height));
+
+      // if the block we're zooming to is really tall, and the user double-tapped
+      // more than a screenful of height from the top of it, then adjust the y-coordinate
+      // so that we center the actual point the user double-tapped upon. this prevents
+      // flying to the top of a page when double-tapping to zoom in (bug 761721).
+      // the 1.2 multiplier is just a little fuzz to compensate for bRect including horizontal
+      // margins but not vertical ones.
+      let cssTapY = viewport.y + data.y;
+      if ((bRect.height > rect.h) && (cssTapY > rect.y + (rect.h * 1.2))) {
+        rect.y = cssTapY - (rect.h / 2);
+      }
+
+      var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
+      os.notifyObservers(docShell, 'browser-zoom-to-rect', JSON.stringify(rect));
+    }
+  },
+
+  _shouldZoomToElement: function(aElement) {
+    let win = aElement.ownerDocument.defaultView;
+    if (win.getComputedStyle(aElement, null).display == "inline")
+      return false;
+    if (aElement instanceof Ci.nsIDOMHTMLLIElement)
+      return false;
+    if (aElement instanceof Ci.nsIDOMHTMLQuoteElement)
+      return false;
+    return true;
+  },
+
+  _zoomOut: function() {
+    let rect = new Rect(0, 0, 0, 0);
+    var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
+    os.notifyObservers(docShell, 'browser-zoom-to-rect', JSON.stringify(rect));
+  },
+
+  _isRectZoomedIn: function(aRect, aViewport) {
+    // This function checks to see if the area of the rect visible in the
+    // viewport (i.e. the "overlapArea" variable below) is approximately
+    // the max area of the rect we can show. It also checks that the rect
+    // is actually on-screen by testing the left and right edges of the rect.
+    // In effect, this tells us whether or not zooming in to this rect
+    // will significantly change what the user is seeing.
+    const minDifference = -20;
+    const maxDifference = 20;
+
+    let vRect = new Rect(aViewport.x, aViewport.y, aViewport.width, aViewport.height);
+    let overlap = vRect.intersect(aRect);
+    let overlapArea = overlap.width * overlap.height;
+    let availHeight = Math.min(aRect.width * vRect.height / vRect.width, aRect.height);
+    let showing = overlapArea / (aRect.width * availHeight);
+    let dw = (aRect.width - vRect.width);
+    let dx = (aRect.x - vRect.x);
+
+    return (showing > 0.9 &&
+            dx > minDifference && dx < maxDifference &&
+            dw > minDifference && dw < maxDifference);
   }
 };
 
 ContentPanning.init();
 
 // Min/max velocity of kinetic panning. This is in pixels/millisecond.
 const kMinVelocity = 0.4;
 const kMaxVelocity = 6;
@@ -384,8 +511,57 @@ const KineticPanning = {
       }
 
       content.mozRequestAnimationFrame(callback);
     }).bind(this);
 
     content.mozRequestAnimationFrame(callback);
   }
 };
+
+const ElementTouchHelper = {
+  anyElementFromPoint: function(aWindow, aX, aY) {
+    let cwu = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
+    let elem = cwu.elementFromPoint(aX, aY, true, true);
+
+    let HTMLIFrameElement = Ci.nsIDOMHTMLIFrameElement;
+    let HTMLFrameElement = Ci.nsIDOMHTMLFrameElement;
+    while (elem && (elem instanceof HTMLIFrameElement || elem instanceof HTMLFrameElement)) {
+      let rect = elem.getBoundingClientRect();
+      aX -= rect.left;
+      aY -= rect.top;
+      cwu = elem.contentDocument.defaultView.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
+      elem = cwu.elementFromPoint(aX, aY, true, true);
+    }
+
+    return elem;
+  },
+
+  getBoundingContentRect: function(aElement) {
+    if (!aElement)
+      return {x: 0, y: 0, w: 0, h: 0};
+
+    let document = aElement.ownerDocument;
+    while (document.defaultView.frameElement)
+      document = document.defaultView.frameElement.ownerDocument;
+
+    let cwu = document.defaultView.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
+    let scrollX = {}, scrollY = {};
+    cwu.getScrollXY(false, scrollX, scrollY);
+
+    let r = aElement.getBoundingClientRect();
+
+    // step out of iframes and frames, offsetting scroll values
+    for (let frame = aElement.ownerDocument.defaultView; frame.frameElement && frame != content; frame = frame.parent) {
+      // adjust client coordinates' origin to be top left of iframe viewport
+      let rect = frame.frameElement.getBoundingClientRect();
+      let left = frame.getComputedStyle(frame.frameElement, "").borderLeftWidth;
+      let top = frame.getComputedStyle(frame.frameElement, "").borderTopWidth;
+      scrollX.value += rect.left + parseInt(left);
+      scrollY.value += rect.top + parseInt(top);
+    }
+
+    return {x: r.left + scrollX.value,
+            y: r.top + scrollY.value,
+            w: r.width,
+            h: r.height };
+  }
+};
--- a/dom/devicestorage/DeviceStorage.h
+++ b/dom/devicestorage/DeviceStorage.h
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef DeviceStorage_h
 #define DeviceStorage_h
 
 #include "nsIDOMDeviceStorage.h"
 #include "nsIFile.h"
+#include "nsIPrincipal.h"
 #include "nsIObserver.h"
 #include "nsDOMEventTargetHelper.h"
 
 class nsDOMDeviceStorage MOZ_FINAL
   : public nsIDOMDeviceStorage
   , public nsIFileUpdateListener
   , public nsDOMEventTargetHelper
   , public nsIObserver
@@ -50,17 +51,17 @@ private:
                              JSContext* aCx,
                              PRUint8 aArgc, 
                              bool aEditable, 
                              nsIDOMDeviceStorageCursor** aRetval);
 
   PRInt32 mStorageType;
   nsCOMPtr<nsIFile> mFile;
 
-  nsCOMPtr<nsIURI> mURI;
+  nsCOMPtr<nsIPrincipal> mPrincipal;
 
   friend class WatchFileEvent;
   friend class DeviceStorageRequest;
 
   bool  mIsWatchingFile;
 
   // nsIDOMDeviceStorage.type
   enum {
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -29,16 +29,17 @@
 #include "nsXULAppAPI.h"
 #include "TabChild.h"
 #include "DeviceStorageRequestChild.h"
 #include "nsIDOMDeviceStorageChangeEvent.h"
 #include "nsCRT.h"
 #include "mozilla/Services.h"
 #include "nsIObserverService.h"
 #include "GeneratedEvents.h"
+#include "mozilla/dom/PermissionMessageUtils.h"
 
 // Microsoft's API Name hackery sucks
 #undef CreateEvent
 
 #ifdef MOZ_WIDGET_GONK
 #include "nsIVolumeService.h"
 #endif
 
@@ -631,42 +632,42 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMDeviceStorageCursor)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DeviceStorageCursor)
 NS_INTERFACE_MAP_END_INHERITING(DOMRequest)
 
 NS_IMPL_ADDREF_INHERITED(nsDOMDeviceStorageCursor, DOMRequest)
 NS_IMPL_RELEASE_INHERITED(nsDOMDeviceStorageCursor, DOMRequest)
 
 nsDOMDeviceStorageCursor::nsDOMDeviceStorageCursor(nsIDOMWindow* aWindow,
-                                                   nsIURI* aURI,
+                                                   nsIPrincipal* aPrincipal,
                                                    DeviceStorageFile* aFile,
                                                    PRUint64 aSince)
   : DOMRequest(aWindow)
   , mOkToCallContinue(false)
   , mSince(aSince)
   , mFile(aFile)
-  , mURI(aURI)
+  , mPrincipal(aPrincipal)
 {
 }
 
 nsDOMDeviceStorageCursor::~nsDOMDeviceStorageCursor()
 {
 }
 
 NS_IMETHODIMP
 nsDOMDeviceStorageCursor::GetType(nsACString & aType)
 {
   aType = "device-storage";
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMDeviceStorageCursor::GetUri(nsIURI * *aRequestingURI)
+nsDOMDeviceStorageCursor::GetPrincipal(nsIPrincipal * *aRequestingPrincipal)
 {
-  NS_IF_ADDREF(*aRequestingURI = mURI);
+  NS_IF_ADDREF(*aRequestingPrincipal = mPrincipal);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMDeviceStorageCursor::GetWindow(nsIDOMWindow * *aRequestingWindow)
 {
   NS_IF_ADDREF(*aRequestingWindow = GetOwner());
   return NS_OK;
@@ -932,38 +933,38 @@ public:
         DEVICE_STORAGE_REQUEST_READ,
         DEVICE_STORAGE_REQUEST_WRITE,
         DEVICE_STORAGE_REQUEST_DELETE,
         DEVICE_STORAGE_REQUEST_WATCH
     };
 
     DeviceStorageRequest(const DeviceStorageRequestType aRequestType,
                          nsPIDOMWindow *aWindow,
-                         nsIURI *aURI,
+                         nsIPrincipal *aPrincipal,
                          DeviceStorageFile *aFile,
                          DOMRequest* aRequest,
                          nsDOMDeviceStorage *aDeviceStorage,
                          nsIDOMEventListener *aListener)
       : mRequestType(aRequestType)
       , mWindow(aWindow)
-      , mURI(aURI)
+      , mPrincipal(aPrincipal)
       , mFile(aFile)
       , mRequest(aRequest)
       , mDeviceStorage(aDeviceStorage)
-      , mListener(aListener) {}  
+      , mListener(aListener) {}
 
     DeviceStorageRequest(const DeviceStorageRequestType aRequestType,
                          nsPIDOMWindow *aWindow,
-                         nsIURI *aURI,
+                         nsIPrincipal *aPrincipal,
                          DeviceStorageFile *aFile,
                          DOMRequest* aRequest,
                          nsIDOMBlob *aBlob = nullptr)
       : mRequestType(aRequestType)
       , mWindow(aWindow)
-      , mURI(aURI)
+      , mPrincipal(aPrincipal)
       , mFile(aFile)
       , mRequest(aRequest)
       , mBlob(aBlob) {}
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(DeviceStorageRequest, nsIContentPermissionRequest)
 
   NS_IMETHOD Run() {
@@ -982,17 +983,17 @@ public:
         return NS_OK;
       }
 
       // Retain a reference so the object isn't deleted without IPDL's knowledge.
       // Corresponding release occurs in DeallocPContentPermissionRequest.
       AddRef();
 
       nsCString type = NS_LITERAL_CSTRING("device-storage");
-      child->SendPContentPermissionRequestConstructor(this, type, IPC::URI(mURI));
+      child->SendPContentPermissionRequestConstructor(this, type, IPC::Principal(mPrincipal));
 
       Sendprompt();
       return NS_OK;
     }
 
     nsCOMPtr<nsIContentPermissionPrompt> prompt = do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID);
     if (prompt) {
       prompt->Prompt(this);
@@ -1001,19 +1002,19 @@ public:
   }
 
   NS_IMETHOD GetType(nsACString & aType)
   {
     aType = "device-storage";
     return NS_OK;
   }
 
-  NS_IMETHOD GetUri(nsIURI * *aRequestingURI)
+  NS_IMETHOD GetPrincipal(nsIPrincipal * *aRequestingPrincipal)
   {
-    NS_IF_ADDREF(*aRequestingURI = mURI);
+    NS_IF_ADDREF(*aRequestingPrincipal = mPrincipal);
     return NS_OK;
   }
 
   NS_IMETHOD GetWindow(nsIDOMWindow * *aRequestingWindow)
   {
     NS_IF_ADDREF(*aRequestingWindow = mWindow);
     return NS_OK;
   }
@@ -1148,17 +1149,17 @@ public:
   void IPDLRelease()
   {
     Release();
   }
 
 private:
   PRInt32 mRequestType;
   nsCOMPtr<nsPIDOMWindow> mWindow;
-  nsCOMPtr<nsIURI> mURI;
+  nsCOMPtr<nsIPrincipal> mPrincipal;
   nsRefPtr<DeviceStorageFile> mFile;
 
   nsRefPtr<DOMRequest> mRequest;
   nsCOMPtr<nsIDOMBlob> mBlob;
   nsRefPtr<nsDOMDeviceStorage> mDeviceStorage;
   nsCOMPtr<nsIDOMEventListener> mListener;
 };
 
@@ -1221,24 +1222,24 @@ nsDOMDeviceStorage::Init(nsPIDOMWindow* 
 
   SetRootFileForType(aType);
   if (!mFile) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   BindToOwner(aWindow);
 
-  // Grab the uri of the document
+  // Grab the principal of the document
   nsCOMPtr<nsIDOMDocument> domdoc;
   aWindow->GetDocument(getter_AddRefs(domdoc));
   nsCOMPtr<nsIDocument> doc = do_QueryInterface(domdoc);
   if (!doc) {
     return NS_ERROR_FAILURE;
   }
-  doc->NodePrincipal()->GetURI(getter_AddRefs(mURI));
+  mPrincipal = doc->NodePrincipal();
   return NS_OK;
 }
 
 nsDOMDeviceStorage::~nsDOMDeviceStorage()
 {
 }
 
 void
@@ -1306,17 +1307,17 @@ nsDOMDeviceStorage::AddNamed(nsIDOMBlob 
 
   nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mFile, aPath);
 
   if (!dsf->IsSafePath()) {
     r = new PostErrorEvent(request, POST_ERROR_EVENT_ILLEGAL_FILE_NAME, dsf);
   }
   else {
     r = new DeviceStorageRequest(DeviceStorageRequest::DEVICE_STORAGE_REQUEST_WRITE,
-                                 win, mURI, dsf, request, aBlob);
+                                 win, mPrincipal, dsf, request, aBlob);
   }
   NS_DispatchToMainThread(r);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMDeviceStorage::Get(const JS::Value & aPath,
                         JSContext* aCx,
@@ -1362,17 +1363,17 @@ nsDOMDeviceStorage::GetInternal(const JS
 
   nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mFile, path);
   dsf->SetEditable(aEditable);
 
   if (!dsf->IsSafePath()) {
     r = new PostErrorEvent(request, POST_ERROR_EVENT_ILLEGAL_FILE_NAME, dsf);
   } else {
     r = new DeviceStorageRequest(DeviceStorageRequest::DEVICE_STORAGE_REQUEST_READ,
-                                 win, mURI, dsf, request);
+                                 win, mPrincipal, dsf, request);
   }
   NS_DispatchToMainThread(r);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMDeviceStorage::Delete(const JS::Value & aPath, JSContext* aCx, nsIDOMDOMRequest * *_retval)
 {
@@ -1397,17 +1398,17 @@ nsDOMDeviceStorage::Delete(const JS::Val
 
   nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mFile, path);
 
   if (!dsf->IsSafePath()) {
     r = new PostErrorEvent(request, POST_ERROR_EVENT_ILLEGAL_FILE_NAME, dsf);
   }
   else {
     r = new DeviceStorageRequest(DeviceStorageRequest::DEVICE_STORAGE_REQUEST_DELETE,
-                                 win, mURI, dsf, request);
+                                 win, mPrincipal, dsf, request);
   }
   NS_DispatchToMainThread(r);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMDeviceStorage::Enumerate(const JS::Value & aName,
                              const JS::Value & aOptions,
@@ -1480,17 +1481,18 @@ nsDOMDeviceStorage::EnumerateInternal(co
       return NS_ERROR_FAILURE;
     }
     since = ExtractDateFromOptions(aCx, aOptions);
   }
 
   nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mFile, path);
   dsf->SetEditable(aEditable);
 
-  nsRefPtr<nsDOMDeviceStorageCursor> cursor = new nsDOMDeviceStorageCursor(win, mURI, dsf, since);
+  nsRefPtr<nsDOMDeviceStorageCursor> cursor = new nsDOMDeviceStorageCursor(win, mPrincipal,
+                                                                           dsf, since);
   nsRefPtr<DeviceStorageCursorRequest> r = new DeviceStorageCursorRequest(cursor);
 
   NS_ADDREF(*aRetval = cursor);
 
   if (mozilla::Preferences::GetBool("device.storage.prompt.testing", false)) {
     r->Allow();
     return NS_OK;
   }
@@ -1502,17 +1504,17 @@ nsDOMDeviceStorage::EnumerateInternal(co
     if (!child)
       return NS_OK;
 
     // Retain a reference so the object isn't deleted without IPDL's knowledge.
     // Corresponding release occurs in DeallocPContentPermissionRequest.
     r->AddRef();
 
     nsCString type = NS_LITERAL_CSTRING("device-storage");
-    child->SendPContentPermissionRequestConstructor(r, type, IPC::URI(mURI));
+    child->SendPContentPermissionRequestConstructor(r, type, IPC::Principal(mPrincipal));
 
     r->Sendprompt();
 
     return NS_OK;
   }
 
   nsCOMPtr<nsIContentPermissionPrompt> prompt = do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID);
   if (prompt) {
@@ -1608,17 +1610,17 @@ nsDOMDeviceStorage::AddEventListener(con
   nsCOMPtr<nsPIDOMWindow> win = GetOwner();
   if (!win) {
     return NS_ERROR_UNEXPECTED;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(win);
   nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mFile);
   nsCOMPtr<nsIRunnable> r = new DeviceStorageRequest(DeviceStorageRequest::DEVICE_STORAGE_REQUEST_WATCH,
-                                                     win, mURI, dsf, request, this, aListener);
+                                                     win, mPrincipal, dsf, request, this, aListener);
   NS_DispatchToMainThread(r);
   return nsDOMEventTargetHelper::AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted, aArgc);
 }
 
 NS_IMETHODIMP
 nsDOMDeviceStorage::AddSystemEventListener(const nsAString & aType,
                                            nsIDOMEventListener *aListener,
                                            bool aUseCapture,
--- a/dom/devicestorage/nsDeviceStorage.h
+++ b/dom/devicestorage/nsDeviceStorage.h
@@ -13,16 +13,17 @@ class nsPIDOMWindow;
 #include "nsCycleCollectionParticipant.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIClassInfo.h"
 #include "nsIContentPermissionPrompt.h"
 #include "nsIDOMDeviceStorageCursor.h"
 #include "nsIDOMWindow.h"
 #include "nsIURI.h"
 #include "nsInterfaceHashtable.h"
+#include "nsIPrincipal.h"
 #include "nsString.h"
 #include "nsWeakPtr.h"
 #include "nsIDOMEventListener.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIObserver.h"
 #include "mozilla/Mutex.h"
 #include "DeviceStorage.h"
 
@@ -81,33 +82,33 @@ class nsDOMDeviceStorageCursor MOZ_FINAL
   , public PCOMContentPermissionRequestChild
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSICONTENTPERMISSIONREQUEST
   NS_DECL_NSIDOMDEVICESTORAGECURSOR
 
   nsDOMDeviceStorageCursor(nsIDOMWindow* aWindow,
-                           nsIURI* aURI,
+                           nsIPrincipal* aPrincipal,
                            DeviceStorageFile* aFile,
                            PRUint64 aSince);
 
 
   nsTArray<nsRefPtr<DeviceStorageFile> > mFiles;
   bool mOkToCallContinue;
   PRUint64 mSince;
 
   virtual bool Recv__delete__(const bool& allow);
   virtual void IPDLRelease();
 
 private:
   ~nsDOMDeviceStorageCursor();
 
   nsRefPtr<DeviceStorageFile> mFile;
-  nsCOMPtr<nsIURI> mURI;
+  nsCOMPtr<nsIPrincipal> mPrincipal;
 };
 
 //helpers
 jsval StringToJsval(nsPIDOMWindow* aWindow, nsAString& aString);
 jsval nsIFileToJsval(nsPIDOMWindow* aWindow, DeviceStorageFile* aFile, bool aEditable);
 jsval BlobToJsval(nsPIDOMWindow* aWindow, nsIDOMBlob* aBlob);
 
 
--- a/dom/file/ArchiveEvent.cpp
+++ b/dom/file/ArchiveEvent.cpp
@@ -8,18 +8,24 @@
 
 #include "nsContentUtils.h"
 #include "nsCExternalHandlerService.h"
 
 USING_FILE_NAMESPACE
 
 NS_IMPL_THREADSAFE_ISUPPORTS0(ArchiveItem)
 
+ArchiveItem::ArchiveItem()
+{
+  MOZ_COUNT_CTOR(ArchiveItem);
+}
+
 ArchiveItem::~ArchiveItem()
 {
+  MOZ_COUNT_DTOR(ArchiveItem);
 }
 
 
 nsCString
 ArchiveItem::GetType()
 {
   return mType.IsEmpty() ? nsCString("binary/octet-stream") : mType;
 }
--- a/dom/file/ArchiveEvent.h
+++ b/dom/file/ArchiveEvent.h
@@ -19,16 +19,17 @@ BEGIN_FILE_NAMESPACE
 
 // This class contains all the info needed for a single item
 // It must contain the implementation of the File() method.
 class ArchiveItem : public nsISupports
 {
 public:
   NS_DECL_ISUPPORTS
 
+  ArchiveItem();
   virtual ~ArchiveItem();
 
   // Getter/Setter for the type
   virtual nsCString GetType();
   virtual void SetType(const nsCString& aType);
 
   // Getter for the filename
   virtual nsCString GetFilename() = 0;
--- a/dom/file/ArchiveReader.cpp
+++ b/dom/file/ArchiveReader.cpp
@@ -18,21 +18,23 @@
 
 USING_FILE_NAMESPACE
 
 ArchiveReader::ArchiveReader()
 : mBlob(nullptr),
   mWindow(nullptr),
   mStatus(NOT_STARTED)
 {
+  MOZ_COUNT_CTOR(ArchiveReader);
   nsLayoutStatics::AddRef();
 }
 
 ArchiveReader::~ArchiveReader()
 {
+  MOZ_COUNT_DTOR(ArchiveReader);
   nsLayoutStatics::Release();
 }
 
 NS_IMETHODIMP
 ArchiveReader::Initialize(nsISupports* aOwner,
                           JSContext* aCx,
                           JSObject* aObj,
                           PRUint32 aArgc,
--- a/dom/file/ArchiveRequest.cpp
+++ b/dom/file/ArchiveRequest.cpp
@@ -46,25 +46,27 @@ ArchiveRequestEvent::Run()
 
 /* ArchiveRequest */
 
 ArchiveRequest::ArchiveRequest(nsIDOMWindow* aWindow,
                                ArchiveReader* aReader)
 : DOMRequest(aWindow),
   mArchiveReader(aReader)
 {
+  MOZ_COUNT_CTOR(ArchiveRequest);
   nsLayoutStatics::AddRef();
 
   /* An event to make this request asynchronous: */
   nsRefPtr<ArchiveRequestEvent> event = new ArchiveRequestEvent(this);
   NS_DispatchToCurrentThread(event);
 }
 
 ArchiveRequest::~ArchiveRequest()
 {
+  MOZ_COUNT_DTOR(ArchiveRequest);
   nsLayoutStatics::Release();
 }
 
 nsresult
 ArchiveRequest::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
   aVisitor.mCanHandle = true;
   aVisitor.mParentTarget = nullptr;
--- a/dom/file/ArchiveZipEvent.cpp
+++ b/dom/file/ArchiveZipEvent.cpp
@@ -17,16 +17,22 @@ USING_FILE_NAMESPACE
 #endif
 
 // ArchiveZipItem
 ArchiveZipItem::ArchiveZipItem(const char* aFilename,
                                ZipCentral& aCentralStruct)
 : mFilename(aFilename),
   mCentralStruct(aCentralStruct)
 {
+  MOZ_COUNT_CTOR(ArchiveZipItem);
+}
+
+ArchiveZipItem::~ArchiveZipItem()
+{
+  MOZ_COUNT_DTOR(ArchiveZipItem);
 }
 
 // Getter/Setter for the filename
 nsCString
 ArchiveZipItem::GetFilename()
 {
   return mFilename;
 }
--- a/dom/file/ArchiveZipEvent.h
+++ b/dom/file/ArchiveZipEvent.h
@@ -14,16 +14,17 @@
 
 BEGIN_FILE_NAMESPACE
 
 class ArchiveZipItem : public ArchiveItem
 {
 public:
   ArchiveZipItem(const char* aFilename,
                  ZipCentral& aCentralStruct);
+  virtual ~ArchiveZipItem();
 
   void SetFilename(const nsCString& aFilename);
   nsCString GetFilename();
 
   // From zipItem to DOMFile:
   virtual nsIDOMFile* File(ArchiveReader* aArchiveReader);
 
 public: // for the event
--- a/dom/file/ArchiveZipFile.cpp
+++ b/dom/file/ArchiveZipFile.cpp
@@ -25,21 +25,24 @@ public:
                      PRUint32 aStart,
                      PRUint32 aLength,
                      ZipCentral& aCentral)
   : mArchiveReader(aReader),
     mCentral(aCentral),
     mFilename(aFilename),
     mStart(aStart),
     mLength(aLength),
-    mRunning(false)
-  {}
+    mStatus(NotStarted)
+  {
+    MOZ_COUNT_CTOR(ArchiveInputStream);
+  }
 
-  ~ArchiveInputStream()
+  virtual ~ArchiveInputStream()
   {
+    MOZ_COUNT_DTOR(ArchiveInputStream);
     Close();
   }
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIINPUTSTREAM
 
 private:
   nsresult Init();
@@ -48,17 +51,21 @@ private: // data
   nsRefPtr<ArchiveReader> mArchiveReader;
   ZipCentral mCentral;
   nsString mFilename;
   PRUint32 mStart;
   PRUint32 mLength;
 
   z_stream mZs;
 
-  bool mRunning;
+  enum {
+    NotStarted,
+    Started,
+    Done
+  } mStatus;
 
   struct {
     nsCOMPtr<nsIInputStream> inputStream;
     unsigned char input[ZIP_CHUNK];
     PRUint32 sizeToBeRead;
     bool compressed; // a zip file can contain stored or compressed files
   } mData;
 };
@@ -142,26 +149,25 @@ ArchiveInputStream::Init()
 
       if (ret == 0)
         return NS_ERROR_UNEXPECTED;
 
       done -= ret;
     }
   }
 
-  mRunning = true;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ArchiveInputStream::Close()
 {
-  if (mRunning) {
+  if (mStatus != NotStarted) {
     inflateEnd(&mZs);
-    mRunning = false;
+    mStatus = NotStarted;
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ArchiveInputStream::Available(PRUint32* _retval)
 {
@@ -172,48 +178,57 @@ ArchiveInputStream::Available(PRUint32* 
 NS_IMETHODIMP
 ArchiveInputStream::Read(char* aBuffer,
                          PRUint32 aCount,
                          PRUint32* _retval)
 {
   NS_ENSURE_ARG_POINTER(aBuffer);
   NS_ENSURE_ARG_POINTER(_retval);
 
-  PRUint32 ret;
   nsresult rv;
 
   // This is the first time:
-  if (!mRunning) {
+  if (mStatus == NotStarted) {
+    mStatus = Started;
+
     rv = Init();
     if (rv != NS_OK)
       return rv;
+
+    // Let's set avail_out to -1 so we read something from the stream.
+    mZs.avail_out = (uInt)-1;
   }
 
   // Nothing more can be read
-  if (mData.sizeToBeRead == 0) {
+  if (mStatus == Done) {
     *_retval = 0;
     return NS_OK;
   }
 
   // Stored file:
   if (!mData.compressed)
   {
     rv = mData.inputStream->Read(aBuffer,
                                  (mData.sizeToBeRead > aCount ?
                                       aCount : mData.sizeToBeRead),
                                  _retval);
-    if (rv == NS_OK)
+    if (rv == NS_OK) {
       mData.sizeToBeRead -= *_retval;
 
+      if (mData.sizeToBeRead == 0)
+        mStatus = Done;
+    }
+
     return rv;
   }
 
   // We have nothing ready to be processed:
-  if (mZs.avail_out == 0)
+  if (mZs.avail_out != 0 && mData.sizeToBeRead != 0)
   {
+    PRUint32 ret;
     rv = mData.inputStream->Read((char*)mData.input,
                                  (mData.sizeToBeRead > sizeof(mData.input) ?
                                       sizeof(mData.input) : mData.sizeToBeRead),
                                  &ret);
     if (rv != NS_OK)
       return rv;
 
     // Terminator:
@@ -225,20 +240,23 @@ ArchiveInputStream::Read(char* aBuffer,
     mData.sizeToBeRead -= ret;
     mZs.avail_in = ret;
     mZs.next_in = mData.input;
   }
 
   mZs.avail_out = aCount;
   mZs.next_out = (unsigned char*)aBuffer;
 
-  ret = inflate(&mZs, mData.sizeToBeRead ? Z_NO_FLUSH : Z_FINISH);
-  if (ret != Z_OK && ret != Z_STREAM_END)
+  int ret = inflate(&mZs, mData.sizeToBeRead ? Z_NO_FLUSH : Z_FINISH);
+  if (ret != Z_BUF_ERROR && ret != Z_OK && ret != Z_STREAM_END)
     return NS_ERROR_UNEXPECTED;
 
+  if (ret == Z_STREAM_END)
+    mStatus = Done;
+
   *_retval = aCount - mZs.avail_out;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ArchiveInputStream::ReadSegments(nsWriteSegmentFun aWriter,
                                  void* aClosure,
                                  PRUint32 aCount,
--- a/dom/file/ArchiveZipFile.h
+++ b/dom/file/ArchiveZipFile.h
@@ -25,30 +25,37 @@ public:
                  ZipCentral& aCentral,
                  ArchiveReader* aReader)
   : nsDOMFileCC(aName, aContentType, aLength),
     mCentral(aCentral),
     mArchiveReader(aReader),
     mFilename(aName)
   {
     NS_ASSERTION(mArchiveReader, "must have a reader");
+    MOZ_COUNT_CTOR(ArchiveZipFile);
   }
 
   ArchiveZipFile(const nsAString& aName,
                  const nsAString& aContentType,
                  PRUint64 aStart,
                  PRUint64 aLength,
                  ZipCentral& aCentral,
                  ArchiveReader* aReader)
   : nsDOMFileCC(aContentType, aStart, aLength),
     mCentral(aCentral),
     mArchiveReader(aReader),
     mFilename(aName)
   {
     NS_ASSERTION(mArchiveReader, "must have a reader");
+    MOZ_COUNT_CTOR(ArchiveZipFile);
+  }
+
+  virtual ~ArchiveZipFile()
+  {
+    MOZ_COUNT_DTOR(ArchiveZipFile);
   }
 
   // Overrides:
   NS_IMETHOD GetInternalStream(nsIInputStream**);
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ArchiveZipFile, nsIDOMFile)
 
--- a/dom/interfaces/apps/Makefile.in
+++ b/dom/interfaces/apps/Makefile.in
@@ -10,14 +10,15 @@ VPATH          = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE         = dom
 XPIDL_MODULE   = dom_apps
 GRE_MODULE     = 1
 
 XPIDLSRCS =                               \
+            mozIApplication.idl \
             nsIDOMApplicationRegistry.idl \
             nsIAppsService.idl \
             nsIDOMMozApplicationEvent.idl \
             $(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/apps/mozIApplication.idl
@@ -0,0 +1,19 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* 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 "nsIDOMApplicationRegistry.idl"
+
+/**
+ * We expose Gecko-internal helpers related to "web apps" through this
+ * sub-interface.
+ */
+[scriptable, uuid(8de25e36-b4cb-4e89-9310-a199dce4e5f4)]
+interface mozIApplication: mozIDOMApplication
+{
+  /* Return true if this app has |permission|. */
+  boolean hasPermission(in string permission);
+};
--- a/dom/interfaces/apps/nsIAppsService.idl
+++ b/dom/interfaces/apps/nsIAppsService.idl
@@ -10,21 +10,31 @@ interface mozIDOMApplication;
 #define APPS_SERVICE_CID { 0x05072afa, 0x92fe, 0x45bf, { 0xae, 0x22, 0x39, 0xb6, 0x9c, 0x11, 0x70, 0x58 } }
 #define APPS_SERVICE_CONTRACTID "@mozilla.org/AppsService;1"
 %}
 
 /*
  * This service allows accessing some DOMApplicationRegistry methods from
  * non-javascript code.
  */
-[scriptable, uuid(1210a0f3-add3-4381-b892-9c102e3afc42)]
+[scriptable, uuid(04e4ef3c-1a30-45bc-ab08-291820f13872)]
 interface nsIAppsService : nsISupports
 {
   mozIDOMApplication getAppByManifestURL(in DOMString manifestURL);
 
   /**
    * Returns the |localId| of the app associated with the |manifestURL| passed
    * in parameter.
    * Returns nsIScriptSecurityManager::NO_APP_ID if |manifestURL| isn't a valid
    * installed manifest URL.
    */
   unsigned long getAppLocalIdByManifestURL(in DOMString manifestURL);
+
+  /**
+   * Returns the application associated to this localId.
+   */
+  mozIDOMApplication getAppByLocalId(in unsigned long localId);
+
+  /**
+   * Returns the manifest URL associated to this localId.
+   */
+  DOMString getManifestURLByLocalId(in unsigned long localId);
 };
--- a/dom/interfaces/base/nsIContentPermissionPrompt.idl
+++ b/dom/interfaces/base/nsIContentPermissionPrompt.idl
@@ -1,36 +1,36 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
-interface nsIURI;
+interface nsIPrincipal;
 interface nsIDOMWindow;
 interface nsIDOMElement;
 
 /**
  * Interface allows access to a content to request
  * permission to perform a privileged operation such as
  * geolocation.
  */
-[scriptable, uuid(E79C7063-DBAB-45E3-8A98-D0142E1ABC9A)]
+[scriptable, uuid(E1F3796C-ADFA-414B-B2A7-AC62F29395EE)]
 interface nsIContentPermissionRequest : nsISupports {
 
   /**
    *  The type of the permission request, such as
    *  "geolocation".
    */
   readonly attribute ACString type;
 
   /**
-   *  The uri of the permission request.
+   *  The principal of the permission request.
    */
-  readonly attribute nsIURI uri;
+  readonly attribute nsIPrincipal principal;
 
   /**
    *  The window or element that the permission request was
    *  originated in.  Typically the element will be non-null
    *  in when using out of process content.  window or
    *  element can be null but not both.
    */
   readonly attribute nsIDOMWindow window;
--- a/dom/interfaces/base/nsIDOMJSWindow.idl
+++ b/dom/interfaces/base/nsIDOMJSWindow.idl
@@ -1,16 +1,16 @@
 /* -*- Mode: IDL; 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/. */
 
 #include "domstubs.idl"
 
-[scriptable, uuid(6652c4d2-6b49-424b-aaf9-91f91006fab7)]
+[scriptable, uuid(1f4da4d4-1d72-4709-8207-3665dbaac4b4)]
 interface nsIDOMJSWindow : nsISupports
 {
   void                      dump(in DOMString str);
 
   /**
    * These methods take typeless arguments and optional arguments, the
    * first argument is either a function or a string, the second
    * argument must be a number (ms) and the rest of the arguments (2
@@ -71,9 +71,12 @@ interface nsIDOMJSWindow : nsISupports
    * window.frames in Netscape 4.x and IE is just a reference to the
    * window itself (i.e. window.frames === window), but this doesn't
    * make sense from a generic API point of view so that's why this is
    * JS specific.
    *
    * This property is "replaceable" in JavaScript.
    */
   readonly attribute nsIDOMWindow             frames;
+
+  [binaryname(ContentForCompat)]
+  readonly attribute nsIDOMWindow             _content;
 };
new file mode 100644
--- /dev/null
+++ b/dom/ipc/AppProcessPermissions.cpp
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* 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 "AppProcessPermissions.h"
+#include "ContentParent.h"
+#include "mozIApplication.h"
+#include "nsIDOMApplicationRegistry.h"
+#include "TabParent.h"
+
+using namespace mozilla::dom;
+using namespace mozilla::services;
+
+namespace mozilla {
+
+bool
+AppProcessHasPermission(PBrowserParent* aActor, const char* aPermission)
+{
+  if (!aActor) {
+    NS_WARNING("Testing permissions for null actor");
+    return false;
+  }
+
+  TabParent* tab = static_cast<TabParent*>(aActor);
+  nsCOMPtr<mozIApplication> app = tab->GetApp();
+  // isBrowser frames inherit their app descriptor to identify their
+  // data storage, but they don't inherit the permissions associated
+  // with that descriptor.
+  if (!app || tab->IsBrowserElement()) {
+    return false;
+  }
+
+  bool hasPermission = false;
+  return (NS_SUCCEEDED(app->HasPermission(aPermission, &hasPermission)) &&
+          hasPermission);
+}
+
+bool
+AppProcessHasPermission(PContentParent* aActor, const char* aPermission)
+{
+  const InfallibleTArray<PBrowserParent*>& browsers =
+    aActor->ManagedPBrowserParent();
+  for (uint32_t i = 0; i < browsers.Length(); ++i) {
+    if (AppProcessHasPermission(browsers[i], aPermission)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/ipc/AppProcessPermissions.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_Capabilities_h
+#define mozilla_Capabilities_h
+
+namespace mozilla {
+
+namespace dom {
+class PBrowserParent;
+class PContentParent;
+}
+
+/**
+ * Return true iff the specified browser has the specified capability.
+ */
+bool
+AppProcessHasPermissions(mozilla::dom::PBrowserParent* aActor,
+                         const char* aPermission);
+
+/**
+ * Return true iff any of the PBrowsers loaded in this content process
+ * has the specified capability.
+ */
+bool
+AppProcessHasPermission(mozilla::dom::PContentParent* aActor,
+                        const char* aPermission);
+
+// NB: when adding capability checks for other IPDL actors, please add
+// them to this file and have them delegate to the two functions above
+// as appropriate.  For example,
+//
+//   bool AppProcessHasCapability(PNeckoParent* aActor) {
+//     return AppProcessHasCapability(aActor->Manager());
+//   }
+
+} // namespace mozilla
+
+#endif // mozilla_Capabilities_h
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -34,16 +34,17 @@
 
 #if defined(MOZ_SYDNEYAUDIO)
 #include "nsAudioStream.h"
 #endif
 #include "nsIMemoryReporter.h"
 #include "nsIObserverService.h"
 #include "nsTObserverArray.h"
 #include "nsIObserver.h"
+#include "nsIScriptSecurityManager.h"
 #include "nsServiceManagerUtils.h"
 #include "nsXULAppAPI.h"
 #include "nsWeakReference.h"
 #include "nsIScriptError.h"
 #include "nsIConsoleService.h"
 #include "nsJSEnvironment.h"
 #include "SandboxHal.h"
 #include "nsDebugImpl.h"
@@ -397,20 +398,21 @@ PCompositorChild*
 ContentChild::AllocPCompositor(mozilla::ipc::Transport* aTransport,
                                base::ProcessId aOtherProcess)
 {
     return CompositorChild::Create(aTransport, aOtherProcess);
 }
 
 PBrowserChild*
 ContentChild::AllocPBrowser(const PRUint32& aChromeFlags,
-                            const bool& aIsBrowserElement,
-                            const PRUint32& aAppId)
+                            const bool& aIsBrowserElement, const AppId& aApp)
 {
-    nsRefPtr<TabChild> iframe = new TabChild(aChromeFlags, aIsBrowserElement, aAppId);
+    PRUint32 appId = aApp.get_uint32_t();
+    nsRefPtr<TabChild> iframe = new TabChild(aChromeFlags, aIsBrowserElement,
+                                             appId);
     return NS_SUCCEEDED(iframe->Init()) ? iframe.forget().get() : NULL;
 }
 
 bool
 ContentChild::DeallocPBrowser(PBrowserChild* iframe)
 {
     TabChild* child = static_cast<TabChild*>(iframe);
     NS_RELEASE(child);
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -63,17 +63,17 @@ public:
         return mAppInfo;
     }
 
     PCompositorChild* AllocPCompositor(mozilla::ipc::Transport* aTransport,
                                        base::ProcessId aOtherProcess) MOZ_OVERRIDE;
 
     virtual PBrowserChild* AllocPBrowser(const PRUint32& aChromeFlags,
                                          const bool& aIsBrowserElement,
-                                         const PRUint32& aAppId);
+                                         const AppId& aAppId);
     virtual bool DeallocPBrowser(PBrowserChild*);
 
     virtual PDeviceStorageRequestChild* AllocPDeviceStorageRequest(const DeviceStorageParams&);
     virtual bool DeallocPDeviceStorageRequest(PDeviceStorageRequestChild*);
 
     virtual PBlobChild* AllocPBlob(const BlobConstructorParams& aParams);
     virtual bool DeallocPBlob(PBlobChild*);
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -8,21 +8,24 @@
 
 #include "ContentParent.h"
 
 #if defined(ANDROID) || defined(LINUX)
 # include <sys/time.h>
 # include <sys/resource.h>
 #endif
 
+#include "chrome/common/process_watcher.h"
+
 #include "CrashReporterParent.h"
 #include "History.h"
 #include "IDBFactory.h"
 #include "IndexedDBParent.h"
 #include "IndexedDatabaseManager.h"
+#include "mozIApplication.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/Util.h"
 #include "mozilla/dom/ExternalHelperAppParent.h"
 #include "mozilla/dom/PMemoryReportRequestParent.h"
 #include "mozilla/dom/StorageParent.h"
 #include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h"
@@ -42,26 +45,29 @@
 #include "nsConsoleMessage.h"
 #include "nsDebugImpl.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsDOMFile.h"
 #include "nsExternalHelperAppService.h"
 #include "nsFrameMessageManager.h"
 #include "nsHashPropertyBag.h"
 #include "nsIAlertsService.h"
+#include "nsIAppsService.h"
 #include "nsIClipboard.h"
 #include "nsIConsoleService.h"
+#include "nsIDOMApplicationRegistry.h"
 #include "nsIDOMGeoGeolocation.h"
 #include "nsIDOMWindow.h"
 #include "nsIFilePicker.h"
 #include "nsIMemoryReporter.h"
 #include "nsIObserverService.h"
 #include "nsIPresShell.h"
 #include "nsIRemoteBlob.h"
 #include "nsIScriptError.h"
+#include "nsIScriptSecurityManager.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIWindowWatcher.h"
 #include "nsMemoryReporterManager.h"
 #include "nsServiceManagerUtils.h"
 #include "nsSystemInfo.h"
 #include "nsThreadUtils.h"
 #include "nsToolkitCompsCID.h"
 #include "nsWidgetsCID.h"
@@ -142,62 +148,96 @@ MemoryReportRequestParent::~MemoryReport
 
 nsDataHashtable<nsStringHashKey, ContentParent*>* ContentParent::gAppContentParents;
 nsTArray<ContentParent*>* ContentParent::gNonAppContentParents;
 nsTArray<ContentParent*>* ContentParent::gPrivateContent;
 
 // The first content child has ID 1, so the chrome process can have ID 0.
 static PRUint64 gContentChildID = 1;
 
-ContentParent*
+/*static*/ ContentParent*
 ContentParent::GetNewOrUsed()
 {
     if (!gNonAppContentParents)
         gNonAppContentParents = new nsTArray<ContentParent*>();
 
     PRInt32 maxContentProcesses = Preferences::GetInt("dom.ipc.processCount", 1);
     if (maxContentProcesses < 1)
         maxContentProcesses = 1;
 
     if (gNonAppContentParents->Length() >= PRUint32(maxContentProcesses)) {
         PRUint32 idx = rand() % gNonAppContentParents->Length();
         ContentParent* p = (*gNonAppContentParents)[idx];
         NS_ASSERTION(p->IsAlive(), "Non-alive contentparent in gNonAppContentParents?");
         return p;
     }
-        
+
     nsRefPtr<ContentParent> p =
         new ContentParent(/* appManifestURL = */ EmptyString());
     p->Init();
     gNonAppContentParents->AppendElement(p);
     return p;
 }
 
-ContentParent*
-ContentParent::GetForApp(const nsAString& aAppManifestURL)
+/*static*/ TabParent*
+ContentParent::CreateBrowser(mozIApplication* aApp, bool aIsBrowserElement)
 {
-    if (aAppManifestURL.IsEmpty()) {
-        return GetNewOrUsed();
+    if (!aApp) {
+        if (ContentParent* cp = GetNewOrUsed()) {
+            nsRefPtr<TabParent> tp(new TabParent(aApp, aIsBrowserElement));
+            return static_cast<TabParent*>(
+                cp->SendPBrowserConstructor(
+                    // DeallocPBrowserParent() releases the ref we take here
+                    tp.forget().get(),
+                    /*chromeFlags*/0,
+                    aIsBrowserElement, nsIScriptSecurityManager::NO_APP_ID));
+        }
+        return nullptr;
     }
 
     if (!gAppContentParents) {
         gAppContentParents =
             new nsDataHashtable<nsStringHashKey, ContentParent*>();
         gAppContentParents->Init();
     }
 
     // Each app gets its own ContentParent instance.
-    ContentParent* p = gAppContentParents->Get(aAppManifestURL);
-    if (!p) {
-        p = new ContentParent(aAppManifestURL);
-        p->Init();
-        gAppContentParents->Put(aAppManifestURL, p);
+    nsAutoString manifestURL;
+    if (NS_FAILED(aApp->GetManifestURL(manifestURL))) {
+        NS_ERROR("Failed to get manifest URL");
+        return nullptr;
+    }
+
+    nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
+    if (!appsService) {
+        NS_ERROR("Failed to get apps service");
+        return nullptr;
     }
 
-    return p;
+    // Send the local app ID to the new TabChild so it knows what app
+    // it is.
+    PRUint32 appId;
+    if (NS_FAILED(appsService->GetAppLocalIdByManifestURL(manifestURL, &appId))) {
+        NS_ERROR("Failed to get local app ID");
+        return nullptr;
+    }
+
+    ContentParent* p = gAppContentParents->Get(manifestURL);
+    if (!p) {
+        p = new ContentParent(manifestURL);
+        p->Init();
+        gAppContentParents->Put(manifestURL, p);
+    }
+
+    nsRefPtr<TabParent> tp(new TabParent(aApp, aIsBrowserElement));
+    return static_cast<TabParent*>(
+        // DeallocPBrowserParent() releases the ref we take here
+        p->SendPBrowserConstructor(tp.forget().get(),
+                                   /*chromeFlags*/0,
+                                   aIsBrowserElement, appId));
 }
 
 static PLDHashOperator
 AppendToTArray(const nsAString& aKey, ContentParent* aValue, void* aArray)
 {
     nsTArray<ContentParent*> *array =
         static_cast<nsTArray<ContentParent*>*>(aArray);
     array->AppendElement(aValue);
@@ -327,16 +367,36 @@ ContentParent::OnChannelConnected(int32 
             if (nice != 0 && cpus == 1) {
                 setpriority(PRIO_PROCESS, pid, getpriority(PRIO_PROCESS, pid) + nice);
             }
         }
 #endif
     }
 }
 
+void
+ContentParent::ProcessingError(Result what)
+{
+    if (MsgDropped == what) {
+        // Messages sent after crashes etc. are not a big deal.
+        return;
+    }
+    // Other errors are big deals.  This ensures the process is
+    // eventually killed, but doesn't immediately KILLITWITHFIRE
+    // because we want to get a minidump if possible.  After a timeout
+    // though, the process is forceably killed.
+    if (!KillProcess(OtherProcess(), 1, false)) {
+        NS_WARNING("failed to kill subprocess!");
+    }
+    XRE_GetIOMessageLoop()->PostTask(
+        FROM_HERE,
+        NewRunnableFunction(&ProcessWatcher::EnsureProcessTerminated,
+                            OtherProcess(), /*force=*/true));
+}
+
 namespace {
 
 void
 DelayedDeleteSubprocess(GeckoChildProcessHost* aSubprocess)
 {
     XRE_GetIOMessageLoop()
         ->PostTask(FROM_HERE,
                    new DeleteTask<GeckoChildProcessHost>(aSubprocess));
@@ -428,22 +488,16 @@ ContentParent::ActorDestroy(ActorDestroy
     // |this|.  If so, when we go out of scope here, we're deleted and
     // all hell breaks loose.
     //
     // This runnable ensures that a reference to |this| lives on at
     // least until after the current task finishes running.
     NS_DispatchToCurrentThread(new DelayedDeleteContentParentTask(this));
 }
 
-TabParent*
-ContentParent::CreateTab(PRUint32 aChromeFlags, bool aIsBrowserElement, PRUint32 aAppId)
-{
-  return static_cast<TabParent*>(SendPBrowserConstructor(aChromeFlags, aIsBrowserElement, aAppId));
-}
-
 void
 ContentParent::NotifyTabDestroyed(PBrowserParent* aTab)
 {
     // There can be more than one PBrowser for a given app process
     // because of popup windows.  When the last one closes, shut
     // us down.
     if (IsForApp() && ManagedPBrowserParent().Length() == 1) {
         MessageLoop::current()->PostTask(
@@ -835,32 +889,50 @@ PCompositorParent*
 ContentParent::AllocPCompositor(mozilla::ipc::Transport* aTransport,
                                 base::ProcessId aOtherProcess)
 {
     return CompositorParent::Create(aTransport, aOtherProcess);
 }
 
 PBrowserParent*
 ContentParent::AllocPBrowser(const PRUint32& aChromeFlags,
-                             const bool& aIsBrowserElement,
-                             const PRUint32& aAppId)
+                             const bool& aIsBrowserElement, const AppId& aApp)
 {
-  TabParent* parent = new TabParent();
-  if (parent){
+    // We only use this Alloc() method when the content processes asks
+    // us to open a window.  In that case, we're expecting to see the
+    // opening PBrowser as its app descriptor, and we can trust the data
+    // associated with that PBrowser since it's fully owned by this
+    // process.
+    if (AppId::TPBrowserParent != aApp.type()) {
+        NS_ERROR("Content process attempting to forge app ID");
+        return nullptr;
+    }
+    TabParent* opener = static_cast<TabParent*>(aApp.get_PBrowserParent());
+
+    // Popup windows of isBrowser frames are isBrowser if the parent
+    // isBrowser.  Allocating a !isBrowser frame with same app ID
+    // would allow the content to access data it's not supposed to.
+    if (opener && opener->IsBrowserElement() && !aIsBrowserElement) {
+        NS_ERROR("Content process attempting to escalate data access privileges");
+        return nullptr;
+    }
+
+    TabParent* parent = new TabParent(opener ? opener->GetApp() : nullptr,
+                                      aIsBrowserElement);
+    // We release this ref in DeallocPBrowser()
     NS_ADDREF(parent);
-  }
-  return parent;
+    return parent;
 }
 
 bool
 ContentParent::DeallocPBrowser(PBrowserParent* frame)
 {
-  TabParent* parent = static_cast<TabParent*>(frame);
-  NS_RELEASE(parent);
-  return true;
+    TabParent* parent = static_cast<TabParent*>(frame);
+    NS_RELEASE(parent);
+    return true;
 }
 
 PDeviceStorageRequestParent*
 ContentParent::AllocPDeviceStorageRequest(const DeviceStorageParams& aParams)
 {
   return new DeviceStorageRequestParent(aParams);
 }
 
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -21,16 +21,17 @@
 #include "nsIPermissionManager.h"
 #include "nsIDOMGeoPositionCallback.h"
 #include "nsIMemoryReporter.h"
 #include "nsCOMArray.h"
 #include "nsDataHashtable.h"
 #include "nsInterfaceHashtable.h"
 #include "nsHashKeys.h"
 
+class mozIApplication;
 class nsFrameMessageManager;
 class nsIDOMBlob;
 
 namespace mozilla {
 
 namespace ipc {
 class TestShellParent;
 }
@@ -55,38 +56,33 @@ private:
     typedef mozilla::ipc::TestShellParent TestShellParent;
     typedef mozilla::layers::PCompositorParent PCompositorParent;
     typedef mozilla::dom::ClonedMessageData ClonedMessageData;
 
 public:
     static ContentParent* GetNewOrUsed();
 
     /**
-     * Get or create a content process for the given app.  A given app
-     * (identified by its manifest URL) gets one process all to itself.
+     * Get or create a content process for the given app descriptor,
+     * which may be null.  This function will assign processes to app
+     * or non-app browsers by internal heuristics.
      *
-     * If the given manifest is the empty string, then this method is equivalent
-     * to GetNewOrUsed().
+     * Currently apps are given their own process, and browser tabs
+     * share processes.
      */
-    static ContentParent* GetForApp(const nsAString& aManifestURL);
+    static TabParent* CreateBrowser(mozIApplication* aApp,
+                                    bool aIsBrowserFrame);
+
     static void GetAll(nsTArray<ContentParent*>& aArray);
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIOBSERVER
     NS_DECL_NSITHREADOBSERVER
     NS_DECL_NSIDOMGEOPOSITIONCALLBACK
 
-    /**
-     * Create a new tab.
-     *
-     * |aIsBrowserElement| indicates whether this tab is part of an
-     * <iframe mozbrowser>.
-     * |aAppId| indicates which app the tab belongs to.
-     */
-    TabParent* CreateTab(PRUint32 aChromeFlags, bool aIsBrowserElement, PRUint32 aAppId);
     /** Notify that a tab was destroyed during normal operation. */
     void NotifyTabDestroyed(PBrowserParent* aTab);
 
     TestShellParent* CreateTestShell();
     bool DestroyTestShell(TestShellParent* aTestShell);
     TestShellParent* GetTestShellSingleton();
 
     void ReportChildAlreadyBlocked();
@@ -138,17 +134,19 @@ private:
      * by the Get*() funtions.  However, the shutdown sequence itself
      * may be asynchronous.
      */
     void ShutDown();
 
     PCompositorParent* AllocPCompositor(mozilla::ipc::Transport* aTransport,
                                         base::ProcessId aOtherProcess) MOZ_OVERRIDE;
 
-    virtual PBrowserParent* AllocPBrowser(const PRUint32& aChromeFlags, const bool& aIsBrowserElement, const PRUint32& aAppId);
+    virtual PBrowserParent* AllocPBrowser(const PRUint32& aChromeFlags,
+                                          const bool& aIsBrowserElement,
+                                          const AppId& aApp);
     virtual bool DeallocPBrowser(PBrowserParent* frame);
 
     virtual PDeviceStorageRequestParent* AllocPDeviceStorageRequest(const DeviceStorageParams&);
     virtual bool DeallocPDeviceStorageRequest(PDeviceStorageRequestParent*);
 
     virtual PBlobParent* AllocPBlob(const BlobConstructorParams& aParams);
     virtual bool DeallocPBlob(PBlobParent*);
 
@@ -257,16 +255,18 @@ private:
                                  const PRUint32& aFlags,
                                  const nsCString& aCategory);
 
     virtual bool RecvPrivateDocShellsExist(const bool& aExist);
 
     virtual bool RecvAddFileWatch(const nsString& root);
     virtual bool RecvRemoveFileWatch(const nsString& root);
 
+    virtual void ProcessingError(Result what) MOZ_OVERRIDE;
+
     GeckoChildProcessHost* mSubprocess;
 
     PRInt32 mGeolocationWatchID;
     int mRunToCompletionDepth;
     bool mShouldCallUnblockChild;
 
     // This is a cache of all of the memory reporters
     // registered in the child process.  To update this, one
--- a/dom/ipc/Makefile.in
+++ b/dom/ipc/Makefile.in
@@ -18,45 +18,53 @@ FAIL_ON_WARNINGS := 1
 
 ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 TEST_DIRS += tests
 endif
 
 EXPORTS = PCOMContentPermissionRequestChild.h
 
 EXPORTS_NAMESPACES = \
+  mozilla \
   mozilla/dom \
   mozilla/dom/ipc \
   $(NULL)
 
+EXPORTS_mozilla = \
+  AppProcessPermissions.h \
+  $(NULL)
+
 EXPORTS_mozilla/dom = \
   ContentChild.h \
   ContentParent.h \
   ContentProcess.h \
   CrashReporterChild.h \
   CrashReporterParent.h \
+  PermissionMessageUtils.h \
   StructuredCloneUtils.h \
   TabParent.h \
   TabChild.h \
   TabMessageUtils.h \
   $(NULL)
 
 EXPORTS_mozilla/dom/ipc = \
   Blob.h \
   ProcessPriorityManager.h \
   nsIRemoteBlob.h \
   $(NULL)
 
 CPPSRCS = \
+  AppProcessPermissions.cpp \
   Blob.cpp \
   ContentProcess.cpp \
   ContentParent.cpp \
   ContentChild.cpp \
   CrashReporterParent.cpp \
   CrashReporterChild.cpp \
+  PermissionMessageUtils.cpp \
   ProcessPriorityManager.cpp \
   StructuredCloneUtils.cpp \
   TabParent.cpp \
   TabChild.cpp \
   TabMessageUtils.cpp \
   $(NULL)
 
 ifdef MOZ_SYDNEYAUDIO
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -10,27 +10,32 @@ include protocol PContent;
 include protocol PContentDialog;
 include protocol PDocumentRenderer;
 include protocol PContentPermissionRequest;
 include protocol PRenderFrame;
 include protocol POfflineCacheUpdate;
 include protocol PIndexedDB;
 
 include "gfxMatrix.h";
+include "FrameMetrics.h";
 include "IPC/nsGUIEventIPC.h";
 include "mozilla/dom/TabMessageUtils.h";
+include "mozilla/dom/PermissionMessageUtils.h";
 include "mozilla/layout/RenderFrameUtils.h";
 include "mozilla/net/NeckoMessageUtils.h";
 
 include DOMTypes;
 
 using IPC::URI;
+using IPC::Principal;
 using gfxMatrix;
+using gfxRect;
 using gfxSize;
 using mozilla::layers::LayersBackend;
+using mozilla::layers::FrameMetrics;
 using mozilla::layout::ScrollingBehavior;
 using mozilla::WindowsHandle;
 using nscolor;
 using nsCompositionEvent;
 using nsIMEUpdatePreference;
 using nsIntPoint;
 using nsIntRect;
 using nsIntSize;
@@ -169,17 +174,30 @@ parent:
     /**
      * Return native data of root widget
      */
     sync GetWidgetNativeData() returns (WindowsHandle value);
 
     SetCursor(PRUint32 value);
     SetBackgroundColor(nscolor color);
 
-    PContentPermissionRequest(nsCString aType, URI uri);
+    /**
+     * Initiates an asynchronous request for permission for the
+     * provided principal.
+     *
+     * @param aType
+     *   The type of permission to request.
+     * @param aPrincipal
+     *   The principal of the request.
+     *
+     * NOTE: The principal is untrusted in the parent process. Only
+     *       principals that can live in the content process should
+     *       provided.
+     */
+    PContentPermissionRequest(nsCString aType, Principal principal);
 
     PContentDialog(PRUint32 aType, nsCString aName, nsCString aFeatures,
                    PRInt32[] aIntParams, nsString[] aStringParams);
 
     /**
      * Create a layout frame (encapsulating a remote layer tree) for
      * the page that is currently loaded in the <browser>.
      */
@@ -227,16 +245,24 @@ parent:
      * the window.open.
      *
      * @param opener the PBrowser whose content called window.open.
      */
     sync BrowserFrameOpenWindow(PBrowser opener, nsString aURL,
                                 nsString aName, nsString aFeatures)
       returns (bool windowOpened);
 
+    NotifyDOMTouchListenerAdded();
+
+    /**
+     * Instructs the TabParent to forward a request to zoom to a rect given in
+     * CSS pixels. This rect is relative to the document.
+     */
+    ZoomToRect(gfxRect aRect);
+
     __delete__();
 
 child:
     /**
      * Notify the remote browser that it has been Show()n on this
      * side, with the given |visibleRect|.  This message is expected
      * to trigger creation of the remote browser's "widget".
      *
@@ -245,20 +271,24 @@ child:
      * point.
      */
     Show(nsIntSize size);
 
     LoadURL(nsCString uri);
 
     UpdateDimensions(nsRect rect, nsIntSize size);
 
-    UpdateFrame(nsIntRect displayPort,
-                nsIntPoint scrollOffset,
-                gfxSize resolution,
-                nsIntRect screenSize);
+    UpdateFrame(FrameMetrics frame);
+
+    /**
+     * Requests handling of a double tap. |point| is in CSS pixels, relative to
+     * the scroll offset. This message is expected to round-trip back to
+     * ZoomToRect() with a rect indicating where we should zoom to.
+     */
+    HandleDoubleTap(nsIntPoint point);
 
     /**
      * Sending an activate message moves focus to the child.
      */
     Activate();
 
     Deactivate();
 
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -117,16 +117,21 @@ struct MysteryBlobConstructorParams
 union BlobConstructorParams
 {
   NormalBlobConstructorParams;
   FileBlobConstructorParams;
   SlicedBlobConstructorParams;
   MysteryBlobConstructorParams;
 };
 
+union AppId {
+  uint32_t;
+  nullable PBrowser;
+};
+
 rpc protocol PContent
 {
     parent opens PCompositor;
 
     manages PAudio;
     manages PBlob;
     manages PBrowser;
     manages PCrashReporter;
@@ -140,19 +145,26 @@ rpc protocol PContent
     manages PStorage;
     manages PTestShell;
 
 both:
     // Depending on exactly how the new browser is being created, it might be
     // created from either the child or parent process!
     //
     // The child creates the PBrowser as part of
-    // TabChild::BrowserFrameProvideWindow, and the parent creates the PBrowser
-    // as part of ContentParent::CreateTab.
-    async PBrowser(PRUint32 chromeFlags, bool isBrowserElement, PRUint32 appId);
+    // TabChild::BrowserFrameProvideWindow, and the parent creates the
+    // PBrowser as part of ContentParent::CreateTab.
+    //
+    // When the parent constructs a PBrowser, the app ID handed to the
+    // child side is trusted.  In that case, |appId| is uint32_t.
+    // However, when the child side constructs a PBrowser, for
+    // window.open(), the parent must validate the app ID used on the
+    // parent side.  To do so, the child process must pass a valid
+    // PBrowser as its |AppId|.
+    async PBrowser(PRUint32 chromeFlags, bool isBrowserElement, AppId appId);
 
     async PBlob(BlobConstructorParams params);
 
 child:
     PMemoryReportRequest();
 
     PTestShell();
 
new file mode 100644
--- /dev/null
+++ b/dom/ipc/PermissionMessageUtils.cpp
@@ -0,0 +1,68 @@
+/* -*- 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/. */
+
+#include "mozilla/dom/PermissionMessageUtils.h"
+#include "nsISerializable.h"
+#include "nsSerializationHelper.h"
+
+namespace IPC {
+
+void
+ParamTraits<Principal>::Write(Message* aMsg, const paramType& aParam) {
+  bool isNull = !aParam.mPrincipal;
+  WriteParam(aMsg, isNull);
+  if (isNull) {
+    return;
+  }
+
+  bool isSerialized = false;
+  nsCString principalString;
+  nsCOMPtr<nsISerializable> serializable = do_QueryInterface(aParam.mPrincipal);
+  if (serializable) {
+    nsresult rv = NS_SerializeToString(serializable, principalString);
+    if (NS_SUCCEEDED(rv)) {
+      isSerialized = true;
+    }
+  }
+
+  if (!isSerialized) {
+    NS_RUNTIMEABORT("Unable to serialize principal.");
+    return;
+  }
+
+  WriteParam(aMsg, principalString);
+}
+
+bool
+ParamTraits<Principal>::Read(const Message* aMsg, void** aIter, paramType* aResult)
+{
+  bool isNull;
+  if (!ReadParam(aMsg, aIter, &isNull)) {
+    return false;
+  }
+
+  if (isNull) {
+    aResult->mPrincipal = nullptr;
+    return true;
+  }
+
+  nsCString principalString;
+  if (!ReadParam(aMsg, aIter, &principalString)) {
+    return false;
+  }
+
+  nsCOMPtr<nsISupports> iSupports;
+  nsresult rv = NS_DeserializeObject(principalString, getter_AddRefs(iSupports));
+  NS_ENSURE_SUCCESS(rv, false);
+
+  nsCOMPtr<nsIPrincipal> principal = do_QueryInterface(iSupports);
+  NS_ENSURE_TRUE(principal, false);
+
+  principal.swap(aResult->mPrincipal);
+  return true;
+}
+
+} // namespace IPC
+
new file mode 100644
--- /dev/null
+++ b/dom/ipc/PermissionMessageUtils.h
@@ -0,0 +1,40 @@
+/* -*- 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 mozilla_dom_permission_message_utils_h__
+#define mozilla_dom_permission_message_utils_h__
+
+#include "IPC/IPCMessageUtils.h"
+#include "nsCOMPtr.h"
+#include "nsIPrincipal.h"
+
+namespace IPC {
+
+class Principal {
+  friend struct ParamTraits<Principal>;
+
+public:
+  Principal() : mPrincipal(nsnull) {}
+  Principal(nsIPrincipal* aPrincipal) : mPrincipal(aPrincipal) {}
+  operator nsIPrincipal*() const { return mPrincipal.get(); }
+
+private:
+  // Unimplemented
+  Principal& operator=(Principal&);
+  nsCOMPtr<nsIPrincipal> mPrincipal;
+};
+
+template <>
+struct ParamTraits<Principal>
+{
+  typedef Principal paramType;
+  static void Write(Message* aMsg, const paramType& aParam);
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult);
+};
+
+} // namespace IPC
+
+#endif // mozilla_dom_permission_message_utils_h__
+
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -15,16 +15,17 @@
 #include "mozilla/IntentionalCrash.h"
 #include "mozilla/docshell/OfflineCacheUpdateChild.h"
 #include "mozilla/dom/PContentChild.h"
 #include "mozilla/dom/PContentDialogChild.h"
 #include "mozilla/ipc/DocumentRendererChild.h"
 #include "mozilla/layers/CompositorChild.h"
 #include "mozilla/layers/PLayersChild.h"
 #include "mozilla/layout/RenderFrameChild.h"
+#include "mozilla/unused.h"
 #include "nsComponentManagerUtils.h"
 #include "nsComponentManagerUtils.h"
 #include "nsContentUtils.h"
 #include "nsEmbedCID.h"
 #include "nsEventListenerManager.h"
 #include "nsIBaseWindow.h"
 #include "nsIComponentManager.h"
 #include "nsIDOMClassInfo.h"
@@ -102,30 +103,80 @@ TabChild::TabChild(PRUint32 aChromeFlags
   , mDidFakeShow(false)
   , mIsBrowserElement(aIsBrowserElement)
   , mAppId(aAppId)
 {
     printf("creating %d!\n", NS_IsMainThread());
 }
 
 nsresult
+TabChild::Observe(nsISupports *aSubject,
+                  const char *aTopic,
+                  const PRUnichar *aData)
+{
+  if (!strcmp(aTopic, "dom-touch-listener-added")) {
+    nsCOMPtr<nsIDOMWindow> subject(do_QueryInterface(aSubject));
+    nsCOMPtr<nsIDOMWindow> win(do_GetInterface(mWebNav));
+    nsCOMPtr<nsIDOMWindow> topSubject;
+    subject->GetTop(getter_AddRefs(topSubject));
+    if (win == topSubject) {
+      SendNotifyDOMTouchListenerAdded();
+    }
+  } else if (!strcmp(aTopic, "cancel-default-pan-zoom")) {
+    nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject));
+    nsCOMPtr<nsITabChild> tabChild(GetTabChildFrom(docShell));
+    if (tabChild == this) {
+      mRemoteFrame->CancelDefaultPanZoom();
+    }
+  } else if (!strcmp(aTopic, "browser-zoom-to-rect")) {
+    nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject));
+    nsCOMPtr<nsITabChild> tabChild(GetTabChildFrom(docShell));
+    if (tabChild == this) {
+      gfxRect rect;
+      sscanf(NS_ConvertUTF16toUTF8(aData).get(),
+             "{\"x\":%lf,\"y\":%lf,\"w\":%lf,\"h\":%lf}",
+             &rect.x, &rect.y, &rect.width, &rect.height);
+      SendZoomToRect(rect);
+    }
+  }
+
+  return NS_OK;
+}
+
+nsresult
 TabChild::Init()
 {
   nsCOMPtr<nsIWebBrowser> webBrowser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID);
   if (!webBrowser) {
     NS_ERROR("Couldn't create a nsWebBrowser?");
     return NS_ERROR_FAILURE;
   }
 
   webBrowser->SetContainerWindow(this);
   mWebNav = do_QueryInterface(webBrowser);
   NS_ASSERTION(mWebNav, "nsWebBrowser doesn't implement nsIWebNavigation?");
 
   nsCOMPtr<nsIDocShellTreeItem> docShellItem(do_QueryInterface(mWebNav));
   docShellItem->SetItemType(nsIDocShellTreeItem::typeContentWrapper);
+
+  nsCOMPtr<nsIObserverService> observerService =
+    do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
+
+  if (observerService) {
+    observerService->AddObserver(this,
+                                 "dom-touch-listener-added",
+                                 false);
+    observerService->AddObserver(this,
+                                 "cancel-default-pan-zoom",
+                                 false);
+    observerService->AddObserver(this,
+                                 "browser-zoom-to-rect",
+                                 false);
+  }
+
   return NS_OK;
 }
 
 NS_INTERFACE_MAP_BEGIN(TabChild)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebBrowserChrome)
   NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome)
   NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome2)
   NS_INTERFACE_MAP_ENTRY(nsIEmbeddingSiteWindow)
@@ -379,20 +430,26 @@ TabChild::BrowserFrameProvideWindow(nsID
                                     nsIURI* aURI,
                                     const nsAString& aName,
                                     const nsACString& aFeatures,
                                     bool* aWindowIsNew,
                                     nsIDOMWindow** aReturn)
 {
   *aReturn = nullptr;
 
-  nsRefPtr<TabChild> newChild =
-    static_cast<TabChild*>(Manager()->SendPBrowserConstructor(
-      /* aChromeFlags = */ 0, mIsBrowserElement, mAppId));
-
+  PRUint32 chromeFlags = 0;
+  nsRefPtr<TabChild> newChild = new TabChild(chromeFlags,
+                                             mIsBrowserElement, mAppId);
+  if (!NS_SUCCEEDED(newChild->Init())) {
+      return NS_ERROR_ABORT;
+  }
+  unused << Manager()->SendPBrowserConstructor(
+      // We release this ref in DeallocPBrowserChild
+      nsRefPtr<TabChild>(newChild).forget().get(),
+      chromeFlags, mIsBrowserElement, this);
   nsCAutoString spec;
   if (aURI) {
     aURI->GetSpec(spec);
   }
 
   NS_ConvertUTF8toUTF16 url(spec);
   nsString name(aName);
   NS_ConvertUTF8toUTF16 features(aFeatures);
@@ -639,65 +696,93 @@ TabChild::RecvUpdateDimensions(const nsR
 
     nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mWebNav);
     baseWin->SetPositionAndSize(0, 0, size.width, size.height,
                                 true);
 
     return true;
 }
 
-bool
-TabChild::RecvUpdateFrame(const nsIntRect& aDisplayPort,
-                          const nsIntPoint& aScrollOffset,
-                          const gfxSize& aResolution,
-                          const nsIntRect& aScreenSize)
+void
+TabChild::DispatchMessageManagerMessage(const nsAString& aMessageName,
+                                        const nsACString& aJSONData)
 {
-    if (!mCx || !mTabChildGlobal) {
-        return true;
-    }
-    nsCString data;
-    data += nsPrintfCString("{ \"x\" : %d", aScrollOffset.x);
-    data += nsPrintfCString(", \"y\" : %d", aScrollOffset.y);
-    // We don't treat the x and y scales any differently for this
-    // semi-platform-specific code.
-    data += nsPrintfCString(", \"zoom\" : %f", aResolution.width);
-    data += nsPrintfCString(", \"displayPort\" : ");
-        data += nsPrintfCString("{ \"left\" : %d", aDisplayPort.X());
-        data += nsPrintfCString(", \"top\" : %d", aDisplayPort.Y());
-        data += nsPrintfCString(", \"width\" : %d", aDisplayPort.Width());
-        data += nsPrintfCString(", \"height\" : %d", aDisplayPort.Height());
-        data += nsPrintfCString(", \"resolution\" : %f", aResolution.width);
-        data += nsPrintfCString(" }");
-    data += nsPrintfCString(", \"screenSize\" : ");
-        data += nsPrintfCString("{ \"width\" : %d", aScreenSize.width);
-        data += nsPrintfCString(", \"height\" : %d", aScreenSize.height);
-        data += nsPrintfCString(" }");
-    data += nsPrintfCString(" }");
-
     JSAutoRequest ar(mCx);
     jsval json = JSVAL_NULL;
     StructuredCloneData cloneData;
     JSAutoStructuredCloneBuffer buffer;
     if (JS_ParseJSON(mCx,
-                      static_cast<const jschar*>(NS_ConvertUTF8toUTF16(data).get()),
-                      data.Length(),
+                      static_cast<const jschar*>(NS_ConvertUTF8toUTF16(aJSONData).get()),
+                      aJSONData.Length(),
                       &json)) {
         WriteStructuredClone(mCx, json, buffer, cloneData.mClosure);
         cloneData.mData = buffer.data();
         cloneData.mDataLength = buffer.nbytes();
     }
 
     nsFrameScriptCx cx(static_cast<nsIWebBrowserChrome*>(this), this);
     // Let the BrowserElementScrolling helper (if it exists) for this
     // content manipulate the frame state.
     nsRefPtr<nsFrameMessageManager> mm =
       static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
     mm->ReceiveMessage(static_cast<nsIDOMEventTarget*>(mTabChildGlobal),
-                       NS_LITERAL_STRING("Viewport:Change"), false,
-                       &cloneData, nullptr, nullptr);
+                       aMessageName, false, &cloneData, nullptr, nullptr);
+}
+
+bool
+TabChild::RecvUpdateFrame(const FrameMetrics& aFrameMetrics)
+{
+    if (!mCx || !mTabChildGlobal) {
+        return true;
+    }
+
+    nsCString data;
+    data += nsPrintfCString("{ \"x\" : %d", aFrameMetrics.mViewportScrollOffset.x);
+    data += nsPrintfCString(", \"y\" : %d", aFrameMetrics.mViewportScrollOffset.y);
+    // We don't treat the x and y scales any differently for this
+    // semi-platform-specific code.
+    data += nsPrintfCString(", \"zoom\" : %f", aFrameMetrics.mResolution.width);
+    data += nsPrintfCString(", \"displayPort\" : ");
+        data += nsPrintfCString("{ \"left\" : %d", aFrameMetrics.mDisplayPort.X());
+        data += nsPrintfCString(", \"top\" : %d", aFrameMetrics.mDisplayPort.Y());
+        data += nsPrintfCString(", \"width\" : %d", aFrameMetrics.mDisplayPort.Width());
+        data += nsPrintfCString(", \"height\" : %d", aFrameMetrics.mDisplayPort.Height());
+        data += nsPrintfCString(", \"resolution\" : %f", aFrameMetrics.mResolution.width);
+        data += nsPrintfCString(" }");
+    data += nsPrintfCString(", \"screenSize\" : ");
+        data += nsPrintfCString("{ \"width\" : %d", aFrameMetrics.mViewport.width);
+        data += nsPrintfCString(", \"height\" : %d", aFrameMetrics.mViewport.height);
+        data += nsPrintfCString(" }");
+    data += nsPrintfCString(", \"cssPageRect\" : ");
+        data += nsPrintfCString("{ \"x\" : %f", aFrameMetrics.mCSSContentRect.x);
+        data += nsPrintfCString(", \"y\" : %f", aFrameMetrics.mCSSContentRect.y);
+        data += nsPrintfCString(", \"width\" : %f", aFrameMetrics.mCSSContentRect.width);
+        data += nsPrintfCString(", \"height\" : %f", aFrameMetrics.mCSSContentRect.height);
+        data += nsPrintfCString(" }");
+    data += nsPrintfCString(" }");
+
+    DispatchMessageManagerMessage(NS_LITERAL_STRING("Viewport:Change"), data);
+
+    return true;
+}
+
+bool
+TabChild::RecvHandleDoubleTap(const nsIntPoint& aPoint)
+{
+    if (!mCx || !mTabChildGlobal) {
+        return true;
+    }
+
+    nsCString data;
+    data += nsPrintfCString("{ \"x\" : %d", aPoint.x);
+    data += nsPrintfCString(", \"y\" : %d", aPoint.y);
+    data += nsPrintfCString(" }");
+
+    DispatchMessageManagerMessage(NS_LITERAL_STRING("Gesture:DoubleTap"), data);
+
     return true;
 }
 
 bool
 TabChild::RecvActivate()
 {
   nsCOMPtr<nsIWebBrowserFocus> browser = do_QueryInterface(mWebNav);
   browser->Activate();
@@ -914,17 +999,17 @@ TabChild::AllocPContentDialog(const PRUi
 bool
 TabChild::DeallocPContentDialog(PContentDialogChild* aDialog)
 {
   delete aDialog;
   return true;
 }
 
 PContentPermissionRequestChild*
-TabChild::AllocPContentPermissionRequest(const nsCString& aType, const IPC::URI&)
+TabChild::AllocPContentPermissionRequest(const nsCString& aType, const IPC::Principal&)
 {
   NS_RUNTIMEABORT("unused");
   return nullptr;
 }
 
 bool
 TabChild::DeallocPContentPermissionRequest(PContentPermissionRequestChild* actor)
 {
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -42,16 +42,17 @@
 #include "nsIPresShell.h"
 #include "nsIPrincipal.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIScriptContext.h"
 #include "nsPIDOMWindow.h"
 #include "nsWeakReference.h"
 #include "nsITabChild.h"
 #include "mozilla/Attributes.h"
+#include "FrameMetrics.h"
 
 struct gfxMatrix;
 
 namespace mozilla {
 namespace layout {
 class RenderFrameChild;
 }
 
@@ -135,50 +136,52 @@ class TabChild : public PBrowserChild,
                  public nsFrameScriptExecutor,
                  public nsIWebBrowserChrome2,
                  public nsIEmbeddingSiteWindow,
                  public nsIWebBrowserChromeFocus,
                  public nsIInterfaceRequestor,
                  public nsIWindowProvider,
                  public nsSupportsWeakReference,
                  public nsIDialogCreator,
-                 public nsITabChild
+                 public nsITabChild,
+                 public nsIObserver
 {
     typedef mozilla::layout::RenderFrameChild RenderFrameChild;
     typedef mozilla::dom::ClonedMessageData ClonedMessageData;
 
 public:
     /**
      * Create a new TabChild object.
      *
      * |aIsBrowserElement| indicates whether the tab is inside an <iframe mozbrowser>.
      * |aAppId| is the app id of the app containing this tab. If the tab isn't
      * contained in an app, aAppId will be nsIScriptSecurityManager::NO_APP_ID.
      */
     TabChild(PRUint32 aChromeFlags, bool aIsBrowserElement, PRUint32 aAppId);
     virtual ~TabChild();
     nsresult Init();
 
+    PRUint32 GetAppId() { return mAppId; }
+
     NS_DECL_ISUPPORTS
     NS_DECL_NSIWEBBROWSERCHROME
     NS_DECL_NSIWEBBROWSERCHROME2
     NS_DECL_NSIEMBEDDINGSITEWINDOW
     NS_DECL_NSIWEBBROWSERCHROMEFOCUS
     NS_DECL_NSIINTERFACEREQUESTOR
     NS_DECL_NSIWINDOWPROVIDER
     NS_DECL_NSIDIALOGCREATOR
     NS_DECL_NSITABCHILD
+    NS_DECL_NSIOBSERVER
 
     virtual bool RecvLoadURL(const nsCString& uri);
     virtual bool RecvShow(const nsIntSize& size);
     virtual bool RecvUpdateDimensions(const nsRect& rect, const nsIntSize& size);
-    virtual bool RecvUpdateFrame(const nsIntRect& aDisplayPort,
-                                      const nsIntPoint& aScrollOffset,
-                                      const gfxSize& aResolution,
-                                      const nsIntRect& aScreenSize);
+    virtual bool RecvUpdateFrame(const mozilla::layers::FrameMetrics& aFrameMetrics);
+    virtual bool RecvHandleDoubleTap(const nsIntPoint& aPoint);
     virtual bool RecvActivate();
     virtual bool RecvDeactivate();
     virtual bool RecvMouseEvent(const nsString& aType,
                                 const float&    aX,
                                 const float&    aY,
                                 const PRInt32&  aButton,
                                 const PRInt32&  aClickCount,
                                 const PRInt32&  aModifiers,
@@ -225,26 +228,26 @@ public:
                                InfallibleTArray<nsString>& aStringParams);
     static void ArraysToParams(const InfallibleTArray<int>& aIntParams,
                                const InfallibleTArray<nsString>& aStringParams,
                                nsIDialogParamBlock* aParams);
 
 #ifdef DEBUG
     virtual PContentPermissionRequestChild* SendPContentPermissionRequestConstructor(PContentPermissionRequestChild* aActor,
                                                                                      const nsCString& aType,
-                                                                                     const URI& aUri)
+                                                                                     const IPC::Principal& aPrincipal)
     {
       PCOMContentPermissionRequestChild* child = static_cast<PCOMContentPermissionRequestChild*>(aActor);
-      PContentPermissionRequestChild* request = PBrowserChild::SendPContentPermissionRequestConstructor(aActor, aType, aUri);
+      PContentPermissionRequestChild* request = PBrowserChild::SendPContentPermissionRequestConstructor(aActor, aType, aPrincipal);
       child->mIPCOpen = true;
       return request;
     }
 #endif /* DEBUG */
 
-    virtual PContentPermissionRequestChild* AllocPContentPermissionRequest(const nsCString& aType, const IPC::URI& uri);
+    virtual PContentPermissionRequestChild* AllocPContentPermissionRequest(const nsCString& aType, const IPC::Principal& aPrincipal);
     virtual bool DeallocPContentPermissionRe