Merge the last PGO-green inbound changeset to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 23 Oct 2012 22:28:33 -0400
changeset 111191 93cc1ee9429165ad859ac031ade8fde49eceeeaa
parent 111120 d3de9d8e2b5ba7885ae533ce7d6ffc5695ee0617 (current diff)
parent 111190 5cce74c60214653c2dbe2d0080f595bb981b3b62 (diff)
child 111192 f7982ce0280a261bb605ef98a632eafb8d914c7c
child 111213 3593d9ccfec22d065ee4fa6065dca29be4990439
push id23730
push userryanvm@gmail.com
push dateWed, 24 Oct 2012 02:28:59 +0000
treeherdermozilla-central@93cc1ee94291 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone19.0a1
first release with
nightly linux32
93cc1ee94291 / 19.0a1 / 20121024030643 / files
nightly linux64
93cc1ee94291 / 19.0a1 / 20121024030643 / files
nightly mac
93cc1ee94291 / 19.0a1 / 20121024030643 / files
nightly win32
93cc1ee94291 / 19.0a1 / 20121024030643 / files
nightly win64
93cc1ee94291 / 19.0a1 / 20121024030643 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge the last PGO-green inbound changeset to m-c.
content/events/src/nsDOMWifiEvent.cpp
content/events/src/nsDOMWifiEvent.h
dom/interfaces/events/nsIWifiEventInits.idl
--- a/accessible/tests/mochitest/common.js
+++ b/accessible/tests/mochitest/common.js
@@ -78,16 +78,18 @@ const COORDTYPE_WINDOW_RELATIVE = nsIAcc
 const COORDTYPE_PARENT_RELATIVE = nsIAccessibleCoordinateType.COORDTYPE_PARENT_RELATIVE;
 
 const kEmbedChar = String.fromCharCode(0xfffc);
 
 const kDiscBulletText = String.fromCharCode(0x2022) + " ";
 const kCircleBulletText = String.fromCharCode(0x25e6) + " ";
 const kSquareBulletText = String.fromCharCode(0x25aa) + " ";
 
+const MAX_TRIM_LENGTH = 100;
+
 /**
  * nsIAccessibleRetrieval service.
  */
 var gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
   getService(nsIAccessibleRetrieval);
 
 /**
  * Enable/disable logging.
@@ -602,17 +604,17 @@ function getTextFromClipboard()
 function prettyName(aIdentifier)
 {
   if (aIdentifier instanceof nsIAccessible) {
     var acc = getAccessible(aIdentifier);
     var msg = "[" + getNodePrettyName(acc.DOMNode);
     try {
       msg += ", role: " + roleToString(acc.role);
       if (acc.name)
-        msg += ", name: '" + acc.name + "'";
+        msg += ", name: '" + shortenString(acc.name) + "'";
     } catch (e) {
       msg += "defunct";
     }
 
     if (acc)
       msg += ", address: " + getObjAddress(acc);
     msg += "]";
 
@@ -620,16 +622,31 @@ function prettyName(aIdentifier)
   }
 
   if (aIdentifier instanceof nsIDOMNode)
     return "[ " + getNodePrettyName(aIdentifier) + " ]";
 
   return " '" + aIdentifier + "' ";
 }
 
+/**
+ * Shorten a long string if it exceeds MAX_TRIM_LENGTH.
+ * @param aString the string to shorten.
+ * @returns the shortened string.
+ */
+function shortenString(aString, aMaxLength)
+{
+  if (aString.length <= MAX_TRIM_LENGTH)
+    return aString;
+
+  // Trim the string if its length is > MAX_TRIM_LENGTH characters.
+  var trimOffset = MAX_TRIM_LENGTH / 2;
+  return aString.substring(0, trimOffset - 1) + "..." +
+    aString.substring(aString.length - trimOffset, aString.length);
+}
 
 ////////////////////////////////////////////////////////////////////////////////
 // Private
 ////////////////////////////////////////////////////////////////////////////////
 
 ////////////////////////////////////////////////////////////////////////////////
 // Accessible general
 
--- a/accessible/tests/mochitest/events/test_text_alg.html
+++ b/accessible/tests/mochitest/events/test_text_alg.html
@@ -51,18 +51,19 @@
 
       this.invoke = function changeText_invoke()
       {
         this.textNode.data = aValue;
       }
 
       this.getID = function changeText_getID()
       {
-        return "change text '" + this.textData + "' -> " + this.textNode.data +
-          "for " + prettyName(this.containerNode);
+        return "change text '" + shortenString(this.textData) + "' -> '" +
+          shortenString(this.textNode.data) + "' for " +
+          prettyName(this.containerNode);
       }
     }
 
     function expStr(x, doublings)
     {
       for (var i = 0; i < doublings; ++i)
         x = x + x;
       return x;
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -14,17 +14,16 @@ Cu.import('resource://gre/modules/Servic
 Cu.import('resource://gre/modules/ContactService.jsm');
 Cu.import('resource://gre/modules/SettingsChangeNotifier.jsm');
 #ifdef MOZ_B2G_FM
 Cu.import('resource://gre/modules/DOMFMRadioParent.jsm');
 #endif
 Cu.import('resource://gre/modules/AlarmService.jsm');
 Cu.import('resource://gre/modules/ActivitiesService.jsm');
 Cu.import('resource://gre/modules/PermissionPromptHelper.jsm');
-Cu.import('resource://gre/modules/PermissionSettings.jsm');
 Cu.import('resource://gre/modules/ObjectWrapper.jsm');
 Cu.import('resource://gre/modules/accessibility/AccessFu.jsm');
 Cu.import('resource://gre/modules/Payment.jsm');
 Cu.import("resource://gre/modules/AppsUtils.jsm");
 Cu.import('resource://gre/modules/UserAgentOverrides.jsm');
 #ifdef MOZ_B2G_RIL
 Cu.import('resource://gre/modules/NetworkStatsService.jsm');
 #endif
--- a/b2g/components/UpdatePrompt.js
+++ b/b2g/components/UpdatePrompt.js
@@ -39,32 +39,78 @@ XPCOMUtils.defineLazyServiceGetter(Servi
 XPCOMUtils.defineLazyServiceGetter(Services, "idle",
                                    "@mozilla.org/widget/idleservice;1",
                                    "nsIIdleService");
 
 XPCOMUtils.defineLazyServiceGetter(Services, "settings",
                                    "@mozilla.org/settingsService;1",
                                    "nsISettingsService");
 
+function UpdateCheckListener(updatePrompt) {
+  this._updatePrompt = updatePrompt;
+}
+
+UpdateCheckListener.prototype = {
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIUpdateCheckListener]),
+
+  _updatePrompt: null,
+
+  onCheckComplete: function UCL_onCheckComplete(request, updates, updateCount) {
+    if (Services.um.activeUpdate) {
+      return;
+    }
+
+    if (updateCount == 0) {
+      this._updatePrompt.setUpdateStatus("no-updates");
+      return;
+    }
+
+    let update = Services.aus.selectUpdate(updates, updateCount);
+    if (!update) {
+      this._updatePrompt.setUpdateStatus("already-latest-version");
+      return;
+    }
+
+    this._updatePrompt.setUpdateStatus("check-complete");
+    this._updatePrompt.showUpdateAvailable(update);
+  },
+
+  onError: function UCL_onError(request, update) {
+    if (update.errorCode == NETWORK_ERROR_OFFLINE) {
+      this._updatePrompt.setUpdateStatus("retry-when-online");
+    }
+
+    Services.aus.QueryInterface(Ci.nsIUpdateCheckListener);
+    Services.aus.onError(request, update);
+  },
+
+  onProgress: function UCL_onProgress(request, position, totalSize) {
+    Services.aus.QueryInterface(Ci.nsIUpdateCheckListener);
+    Services.aus.onProgress(request, position, totalSize);
+  }
+};
+
 function UpdatePrompt() {
   this.wrappedJSObject = this;
+  this._updateCheckListener = new UpdateCheckListener(this);
 }
 
 UpdatePrompt.prototype = {
   classID: Components.ID("{88b3eb21-d072-4e3b-886d-f89d8c49fe59}"),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIUpdatePrompt,
                                          Ci.nsIUpdateCheckListener,
                                          Ci.nsIRequestObserver,
                                          Ci.nsIProgressEventSink,
                                          Ci.nsIObserver]),
   _xpcom_factory: XPCOMUtils.generateSingletonFactory(UpdatePrompt),
 
   _update: null,
   _applyPromptTimer: null,
   _waitingForIdle: false,
+  _updateCheckListner: null,
 
   // nsIUpdatePrompt
 
   // FIXME/bug 737601: we should have users opt-in to downloading
   // updates when on a billed pipe.  Initially, opt-in for 3g, but
   // that doesn't cover all cases.
   checkForUpdates: function UP_checkForUpdates() { },
 
@@ -102,52 +148,16 @@ UpdatePrompt.prototype = {
 
     this.sendUpdateEvent("update-error", aUpdate);
     this.setUpdateStatus(aUpdate.statusText);
   },
 
   showUpdateHistory: function UP_showUpdateHistory(aParent) { },
   showUpdateInstalled: function UP_showUpdateInstalled() { },
 
-  // nsIUpdateCheckListener
-
-  onCheckComplete: function UP_onCheckComplete(request, updates, updateCount) {
-    if (Services.um.activeUpdate) {
-      return;
-    }
-
-    if (updateCount == 0) {
-      this.setUpdateStatus("no-updates");
-      return;
-    }
-
-    let update = Services.aus.selectUpdate(updates, updateCount);
-    if (!update) {
-      this.setUpdateStatus("already-latest-version");
-      return;
-    }
-
-    this.setUpdateStatus("check-complete");
-    this.showUpdateAvailable(update);
-  },
-
-  onError: function UP_onError(request, update) {
-    if (update.errorCode == NETWORK_ERROR_OFFLINE) {
-      this.setUpdateStatus("retry-when-online");
-    }
-
-    Services.aus.QueryInterface(Ci.nsIUpdateCheckListener);
-    Services.aus.onError(request, update);
-  },
-
-  onProgress: function UP_onProgress(request, position, totalSize) {
-    Services.aus.QueryInterface(Ci.nsIUpdateCheckListener);
-    Services.aus.onProgress(request, position, totalSize);
-  },
-
   // Custom functions
 
   waitForIdle: function UP_waitForIdle() {
     if (this._waitingForIdle) {
       return;
     }
 
     this._waitingForIdle = true;
@@ -315,17 +325,17 @@ UpdatePrompt.prototype = {
     if (Services.um.activeUpdate) {
       this.setUpdateStatus("check-complete");
       this.showApplyPrompt(Services.um.activeUpdate);
       return;
     }
 
     let checker = Cc["@mozilla.org/updates/update-checker;1"]
                     .createInstance(Ci.nsIUpdateChecker);
-    checker.checkForUpdates(this, true);
+    checker.checkForUpdates(this._updateCheckListener, true);
   },
 
   handleEvent: function UP_handleEvent(evt) {
     if (evt.type !== "mozContentEvent") {
       return;
     }
 
     let detail = evt.detail;
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -477,19 +477,17 @@
     </menupopup>
   </menu>
 
             <menu id="tools-menu"
                   label="&toolsMenu.label;"
                   accesskey="&toolsMenu.accesskey;">
               <menupopup id="menu_ToolsPopup"
 #ifdef MOZ_SERVICES_SYNC
-                         onpopupshowing="gSyncUI.updateUI(); SocialMenu.populate();"
-#else
-                         onpopupshowing="SocialMenu.populate();"
+                         onpopupshowing="gSyncUI.updateUI();"
 #endif
                          >
               <menuitem id="menu_search"
                         class="show-only-for-keyboard"
                         label="&search.label;"
                         accesskey="&search.accesskey;"
                         key="key_search"
                         command="Tools:Search"/>
@@ -505,19 +503,33 @@
                         accesskey="&addons.accesskey;"
                         key="key_openAddons"
                         command="Tools:Addons"/>
               <menuitem id="menu_socialToggle"
                         type="checkbox"
                         autocheck="false"
                         command="Social:Toggle"/>
               <menu id="menu_socialAmbientMenu"
-                    class="show-only-for-keyboard"
-                    command="Social:Toggle">
-                <menupopup id="menu_socialAmbientMenuPopup"/>
+                    class="show-only-for-keyboard">
+                <menupopup id="menu_socialAmbientMenuPopup">
+                  <menuseparator id="socialAmbientMenuSeparator"
+                                 hidden="true"/>
+                  <menuitem id="social-toggle-sidebar-keyboardmenuitem"
+                            type="checkbox"
+                            autocheck="false"
+                            command="Social:ToggleSidebar"
+                            label="&social.toggleSidebar.label;"
+                            accesskey="&social.toggleSidebar.accesskey;"/>
+                  <menuitem id="social-toggle-notifications-keyboardmenuitem"
+                            type="checkbox"
+                            autocheck="false"
+                            command="Social:ToggleNotifications"
+                            label="&social.toggleNotifications.label;"
+                            accesskey="&social.toggleNotifications.accesskey;"/>
+                </menupopup>
               </menu>
 #ifdef MOZ_SERVICES_SYNC
               <!-- only one of sync-setup or sync-menu will be showing at once -->
               <menuitem id="sync-setup"
                         label="&syncSetup.label;"
                         accesskey="&syncSetup.accesskey;"
                         observes="sync-setup-state"
                         oncommand="gSyncUI.openSetup()"/>
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -57,26 +57,28 @@ let SocialUI = {
           SocialFlyout.unload();
         } catch (e) {
           Components.utils.reportError(e);
           throw e;
         }
         break;
       case "social:ambient-notification-changed":
         SocialToolbar.updateButton();
-        SocialMenu.updateMenu();
+        SocialMenu.populate();
         break;
       case "social:profile-changed":
         SocialToolbar.updateProfile();
         SocialShareButton.updateProfileInfo();
         SocialChatBar.update();
         break;
       case "nsPref:changed":
         SocialSidebar.updateSidebar();
         SocialToolbar.updateButton();
+        SocialMenu.populate();
+        break;
     }
   },
 
   get toggleCommand() {
     return document.getElementById("Social:Toggle");
   },
 
   // Called once Social.jsm's provider has been set
@@ -94,35 +96,24 @@ let SocialUI = {
                                                      brandShortName]);
     let accesskey = gNavigatorBundle.getString("social.toggle.accesskey");
     toggleCommand.setAttribute("label", label);
     toggleCommand.setAttribute("accesskey", accesskey);
 
     SocialToolbar.init();
     SocialShareButton.init();
     SocialSidebar.init();
+    SocialMenu.populate();
   },
 
   updateToggleCommand: function SocialUI_updateToggleCommand() {
     let toggleCommand = this.toggleCommand;
+    // We only need to update the command itself - all our menu items use it.
     toggleCommand.setAttribute("checked", Services.prefs.getBoolPref("social.enabled"));
-
-    // FIXME: bug 772808: menu items don't inherit the "hidden" state properly,
-    // need to update them manually.
-    // This should just be: toggleCommand.hidden = !Social.active;
-    for (let id of ["appmenu_socialToggle", "menu_socialToggle", "menu_socialAmbientMenu"]) {
-      let el = document.getElementById(id);
-      if (!el)
-        continue;
-
-      if (Social.active)
-        el.removeAttribute("hidden");
-      else
-        el.setAttribute("hidden", "true");
-    }
+    toggleCommand.setAttribute("hidden", Social.active ? "false" : "true");
   },
 
   // This handles "ActivateSocialFeature" events fired against content documents
   // in this window.
   _activationEventHandler: function SocialUI_activationHandler(e) {
     // Nothing to do if Social is already active, or we don't have a provider
     // to enable yet.
     if (Social.active || !Social.provider)
@@ -605,34 +596,38 @@ let SocialShareButton = {
     shareButton.style.backgroundImage = 'url("' + encodeURI(imageURL) + '")';
   }
 };
 
 var SocialMenu = {
   populate: function SocialMenu_populate() {
     // This menu is only accessible through keyboard navigation.
     let submenu = document.getElementById("menu_socialAmbientMenuPopup");
-    while (submenu.hasChildNodes())
-      submenu.removeChild(submenu.firstChild);
+    let ambientMenuItems = submenu.getElementsByClassName("ambient-menuitem");
+    for (let ambientMenuItem of ambientMenuItems)
+      submenu.removeChild(ambientMenuItem);
     let provider = Social.provider;
     if (Social.active && provider) {
       let iconNames = Object.keys(provider.ambientNotificationIcons);
+      let separator = document.getElementById("socialAmbientMenuSeparator");
       for (let name of iconNames) {
         let icon = provider.ambientNotificationIcons[name];
         if (!icon.label || !icon.menuURL)
           continue;
         let menuitem = document.createElement("menuitem");
         menuitem.setAttribute("label", icon.label);
+        menuitem.classList.add("ambient-menuitem");
         menuitem.addEventListener("command", function() {
           openUILinkIn(icon.menuURL, "tab");
         }, false);
-        submenu.appendChild(menuitem);
+        submenu.insertBefore(menuitem, separator);
       }
+      separator.hidden = !iconNames.length;
     }
-    document.getElementById("menu_socialAmbientMenu").hidden = !submenu.querySelector("menuitem");
+    document.getElementById("menu_socialAmbientMenu").hidden = !Social.enabled;
   }
 };
 
 var SocialToolbar = {
   // Called once, after window load, when the Social.provider object is initialized
   init: function SocialToolbar_init() {
     this.button.setAttribute("image", Social.provider.iconURL);
     this.updateButton();
@@ -687,21 +682,22 @@ var SocialToolbar = {
     panel.hidden = false;
 
     let command = document.getElementById("Social:ToggleNotifications");
     command.setAttribute("checked", Services.prefs.getBoolPref("social.toast-notifications.enabled"));
 
     const CACHE_PREF_NAME = "social.cached.notificationIcons";
     // provider.profile == undefined means no response yet from the provider
     // to tell us whether the user is logged in or not.
-    if (!SocialUI.haveLoggedInUser() && provider.profile !== undefined) {
-      // The provider has responded with a profile and the user isn't logged
-      // in.  The icons etc have already been removed by
-      // updateButtonHiddenState, so we want to nuke any cached icons we
-      // have and get out of here!
+    if (!Social.provider || !Social.provider.enabled ||
+        (!SocialUI.haveLoggedInUser() && provider.profile !== undefined)) {
+      // Either no enabled provider, or there is a provider and it has
+      // responded with a profile and the user isn't loggedin.  The icons
+      // etc have already been removed by updateButtonHiddenState, so we want
+      // to nuke any cached icons we have and get out of here!
       Services.prefs.clearUserPref(CACHE_PREF_NAME);
       return;
     }
     if (Social.provider.profile === undefined) {
       // provider has not told us about the login state yet - see if we have
       // a cached version for this provider.
       let cached;
       try {
@@ -918,17 +914,17 @@ var SocialSidebar = {
     let evt = sbrowser.contentDocument.createEvent("CustomEvent");
     evt.initCustomEvent(aType, true, true, aDetail ? aDetail : {});
     sbrowser.contentDocument.documentElement.dispatchEvent(evt);
   },
 
   updateSidebar: function SocialSidebar_updateSidebar() {
     // Hide the toggle menu item if the sidebar cannot appear
     let command = document.getElementById("Social:ToggleSidebar");
-    command.hidden = !this.canShow;
+    command.setAttribute("hidden", this.canShow ? "false" : "true");
 
     // Hide the sidebar if it cannot appear, or has been toggled off.
     // Also set the command "checked" state accordingly.
     let hideSidebar = !this.canShow || !this.opened;
     let broadcaster = document.getElementById("socialSidebarBroadcaster");
     broadcaster.hidden = hideSidebar;
     command.setAttribute("checked", !hideSidebar);
 
--- a/browser/base/content/test/browser_social_toolbar.js
+++ b/browser/base/content/test/browser_social_toolbar.js
@@ -41,17 +41,18 @@ var tests = {
     }
 
     // Test that keyboard accessible menuitem doesn't exist when no ambient icons specified.
     let toolsPopup = document.getElementById("menu_ToolsPopup");
     toolsPopup.addEventListener("popupshown", function ontoolspopupshownNoAmbient() {
       toolsPopup.removeEventListener("popupshown", ontoolspopupshownNoAmbient);
       let socialToggleMore = document.getElementById("menu_socialAmbientMenu");
       ok(socialToggleMore, "Keyboard accessible social menu should exist");
-      is(socialToggleMore.hidden, true, "Menu should be hidden when no ambient notifications.");
+      is(socialToggleMore.querySelectorAll("menuitem").length, 2, "The minimum number of menuitems is two when there are no ambient notifications.");
+      is(socialToggleMore.hidden, false, "Menu should be visible since we show some non-ambient notifications in the menu.");
       toolsPopup.hidePopup();
       next();
     }, false);
     document.getElementById("menu_ToolsPopup").openPopup();
   },
   testAmbientNotifications: function(next) {
     let ambience = {
       name: "testIcon",
@@ -80,16 +81,17 @@ var tests = {
         next();
 
       // Test that keyboard accessible menuitem was added.
       let toolsPopup = document.getElementById("menu_ToolsPopup");
       toolsPopup.addEventListener("popupshown", function ontoolspopupshownAmbient() {
         toolsPopup.removeEventListener("popupshown", ontoolspopupshownAmbient);
         let socialToggleMore = document.getElementById("menu_socialAmbientMenu");
         ok(socialToggleMore, "Keyboard accessible social menu should exist");
+        is(socialToggleMore.querySelectorAll("menuitem").length, 3, "The number of menuitems is minimum plus one ambient notification menuitem.");
         is(socialToggleMore.hidden, false, "Menu is visible when ambient notifications have label & menuURL");
         let menuitem = socialToggleMore.querySelector("menuitem");
         is(menuitem.getAttribute("label"), "Test Ambient 1", "Keyboard accessible ambient menuitem should have specified label");
         toolsPopup.hidePopup();
         next();
       }, false);
       document.getElementById("menu_ToolsPopup").openPopup();
     }, "statusIcon was never found");
@@ -104,17 +106,21 @@ var tests = {
       ok(ambientIcon.collapsed, "ambient icon (" + ambientIcon.id + ") is collapsed");
     }
     
     next();
   },
   testShowSidebarMenuitemExists: function(next) {
     let toggleSidebarMenuitem = document.getElementById("social-toggle-sidebar-menuitem");
     ok(toggleSidebarMenuitem, "Toggle Sidebar menuitem exists");
+    let toggleSidebarKeyboardMenuitem = document.getElementById("social-toggle-sidebar-keyboardmenuitem");
+    ok(toggleSidebarKeyboardMenuitem, "Toggle Sidebar keyboard menuitem exists");
     next();
   },
   testShowDesktopNotificationsMenuitemExists: function(next) {
     let toggleDesktopNotificationsMenuitem = document.getElementById("social-toggle-notifications-menuitem");
     ok(toggleDesktopNotificationsMenuitem, "Toggle notifications menuitem exists");
+    let toggleDesktopNotificationsKeyboardMenuitem = document.getElementById("social-toggle-notifications-keyboardmenuitem");
+    ok(toggleDesktopNotificationsKeyboardMenuitem, "Toggle notifications keyboard menuitem exists");
     next();
   }
 }
 
--- a/browser/themes/browserShared.inc
+++ b/browser/themes/browserShared.inc
@@ -1,3 +1,3 @@
 %filter substitution
 
-%define primaryToolbarButtons #back-button, #forward-button, #reload-button, #stop-button, #home-button, #print-button, #downloads-button, #history-button, #bookmarks-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #cut-button, #copy-button, #paste-button, #fullscreen-button, #zoom-out-button, #zoom-in-button, #sync-button, #feed-button, #alltabs-button, #tabview-button
+%define primaryToolbarButtons #back-button, #forward-button, #reload-button, #stop-button, #home-button, #print-button, #downloads-button, #downloads-indicator, #history-button, #bookmarks-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #cut-button, #copy-button, #paste-button, #fullscreen-button, #zoom-out-button, #zoom-in-button, #sync-button, #feed-button, #alltabs-button, #tabview-button
--- a/browser/themes/gnomestripe/browser.css
+++ b/browser/themes/gnomestripe/browser.css
@@ -2729,16 +2729,17 @@ html|*#gcli-output-frame {
 .chat-title {
   font-weight: bold;
   color: -moz-dialogtext;
   cursor: inherit;
 }
 
 .chat-titlebar {
   background-color: #d9d9d9;
+  background-image: linear-gradient(@toolbarHighlight@, rgba(255,255,255,0));
   height: 20px;
   min-height: 20px;
   width: 100%;
   margin: 0;
   padding: 2px;
   -moz-padding-start: 6px;
   border: none;
   border-bottom: 1px solid #ccc;
@@ -2749,50 +2750,62 @@ html|*#gcli-output-frame {
   border-bottom: none;
 }
 
 .chat-titlebar[selected] {
   background-color: #f0f0f0;
 }
 
 .chat-titlebar[activity] {
-  background-color: #ceeaff;
+  background-image: radial-gradient(ellipse closest-side at center, rgb(255,255,255), rgba(255,255,255,0));
+  background-repeat: no-repeat;
+  background-size: 100% 20px;
+  background-position: 0 -10px;
 }
 
 .chat-frame {
   padding: 0;
   margin: 0;
   overflow: hidden;
 }
 
 .chatbar-button {
+  -moz-appearance: none;
   background-color: #d9d9d9;
   list-style-image: url("chrome://browser/skin/social/social.png");
   border: none;
   margin: 0;
   padding: 2px;
   height: 21px;
   width: 21px;
   border-top: 1px solid #ccc;
   -moz-border-end: 1px solid #ccc;
 }
 
-.chatbar-button[open="true"],
-.chatbar-button:active:hover {
+.chatbar-button > .toolbarbutton-icon {
+  opacity: .6;
+  -moz-margin-end: 0;
+}
+.chatbar-button:hover > .toolbarbutton-icon,
+.chatbar-button[open="true"] > .toolbarbutton-icon {
+  opacity: 1;
+}
+
+.chatbar-button[open="true"] {
   background-color: #f0f0f0;
   box-shadow: inset 0 2px 5px rgba(0,0,0,0.6), 0 1px rgba(255,255,255,0.2);
 }
 
 .chatbar-button > .toolbarbutton-text,
 .chatbar-button > .toolbarbutton-menu-dropmarker {
   display: none;
 }
 
 .chatbar-button[activity] {
-  background-color: #ceeaff;
+  background-image: radial-gradient(circle farthest-corner at center 3px, rgb(233,242,252) 3%, rgba(172,206,255,0.75) 40%, rgba(87,151,201,0.5) 80%, rgba(87,151,201,0));
 }
 
 .chatbar-button > menupopup > menuitem[activity] {
   font-weight: bold;
 }
 
 .chatbar-innerbox {
   background: transparent;
@@ -2806,16 +2819,18 @@ chatbar {
 
 chatbox {
   height: 285px;
   width: 260px;
   -moz-margin-start: 4px;
   background-color: white;
   border: 1px solid #ccc;
   border-bottom: none;
+  border-top-left-radius: 2.5px;
+  border-top-right-radius: 2.5px;
 }
 
 chatbox[minimized="true"] {
   width: 160px;
   height: 20px;
 }
 
 .click-to-play-plugins-notification-content {
--- a/browser/themes/gnomestripe/downloads/downloads.css
+++ b/browser/themes/gnomestripe/downloads/downloads.css
@@ -56,17 +56,16 @@ richlistitem[type="download"]:first-chil
 
 richlistitem[type="download"]:last-child {
   border-bottom: 1px solid transparent;
 }
 
 #downloadsListBox:-moz-focusring > richlistitem[type="download"][selected] {
   outline: 1px -moz-dialogtext dotted;
   outline-offset: -1px;
-  -moz-outline-radius: 3px;
 }
 
 .downloadTypeIcon {
   -moz-margin-end: 8px;
   /* Prevent flickering when changing states. */
   min-height: 32px;
   min-width: 32px;
 }
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -4151,33 +4151,37 @@ html|*#gcli-output-frame {
 .chat-title {
   font-weight: bold;
   color: -moz-dialogtext;
   cursor: inherit;
 }
 
 .chat-titlebar {
   background-color: #d9d9d9;
+  background-image: linear-gradient(rgba(255,255,255,.43), rgba(255,255,255,0));
   height: 20px;
   min-height: 20px;
   width: 100%;
   margin: 0;
   padding: 2px;
   -moz-padding-start: 6px;
   border: none;
   border-bottom: 1px solid #ccc;
   cursor: pointer;
 }
 
 .chat-titlebar[minimized="true"] {
   border-bottom: none;
 }
 
 .chat-titlebar[activity] {
-  background-color: #ceeaff;
+  background-image: radial-gradient(ellipse closest-side at center, rgb(255,255,255), rgba(255,255,255,0));
+  background-repeat: no-repeat;
+  background-size: 100% 20px;
+  background-position: 0 -10px;
 }
 
 .chat-titlebar[selected] {
   background-color: #f0f0f0;
 }
 
 .chat-frame {
   padding: 0;
@@ -4192,52 +4196,61 @@ html|*#gcli-output-frame {
   margin: 0;
   padding: 2px;
   height: 21px;
   width: 21px;
   border-top: 1px solid #ccc;
   -moz-border-end: 1px solid #ccc;
 }
 
-.chatbar-button[open="true"],
-.chatbar-button:active:hover {
+.chatbar-button > .toolbarbutton-icon {
+  opacity: .6;
+}
+.chatbar-button:hover > .toolbarbutton-icon,
+.chatbar-button[open="true"] > .toolbarbutton-icon {
+  opacity: 1;
+}
+
+.chatbar-button[open="true"] {
   background-color: #f0f0f0;
   box-shadow: inset 0 2px 5px rgba(0,0,0,0.6), 0 1px rgba(255,255,255,0.2);
 }
 
 .chatbar-button > .toolbarbutton-text,
 .chatbar-button > .toolbarbutton-menu-dropmarker {
   display: none;
 }
 
 .chatbar-button[activity] {
-  background-color: #ceeaff;
+  background-image: radial-gradient(circle farthest-corner at center 2px, rgb(254,254,255) 3%, rgba(210,235,255,0.9) 12%, rgba(148,205,253,0.6) 30%, rgba(148,205,253,0.2) 70%);
 }
 
 .chatbar-button > menupopup > menuitem[activity] {
   font-weight: bold;
 }
 
 .chatbar-innerbox {
   background: transparent;
-  margin: -285px -1px 0 -1px;
+  margin: -285px 0 0;
   overflow: hidden;
 }
 
 chatbar {
   -moz-margin-end: 20px;
 }
 
 chatbox {
   height: 285px;
   width: 260px;
   -moz-margin-start: 4px;
   background-color: white;
   border: 1px solid #ccc;
   border-bottom: none;
+  border-top-left-radius: @toolbarbuttonCornerRadius@;
+  border-top-right-radius: @toolbarbuttonCornerRadius@;
 }
 
 chatbox[minimized="true"] {
   width: 160px;
   height: 20px;
 }
 
 panel[type="arrow"][popupid="click-to-play-plugins"] > .panel-arrowcontainer > .panel-arrowbox > .panel-arrow[side="top"],
--- a/browser/themes/pinstripe/downloads/downloads.css
+++ b/browser/themes/pinstripe/downloads/downloads.css
@@ -72,17 +72,16 @@ richlistitem[type="download"]:first-chil
 
 richlistitem[type="download"]:last-child {
   border-bottom: 1px solid transparent;
 }
 
 #downloadsListBox:-moz-focusring > richlistitem[type="download"][selected] {
   outline: 1px -moz-dialogtext dotted;
   outline-offset: -1px;
-  -moz-outline-radius: 3px;
 }
 
 .downloadTypeIcon {
   -moz-margin-end: 8px;
   /* Prevent flickering when changing states. */
   min-height: 32px;
   min-width: 32px;
 }
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -3433,16 +3433,17 @@ html|*#gcli-output-frame {
 .chat-title {
   font-weight: bold;
   color: -moz-dialogtext;
   cursor: inherit;
 }
 
 .chat-titlebar {
   background-color: #c4cfde;
+  background-image: linear-gradient(rgba(255,255,255,.5), rgba(255,255,255,0));
   height: 20px;
   min-height: 20px;
   width: 100%;
   margin: 0;
   padding: 2px;
   -moz-padding-start: 6px;
   border: none;
   border-bottom: 1px solid #ccc;
@@ -3453,17 +3454,20 @@ html|*#gcli-output-frame {
   border-bottom: none;
 }
 
 .chat-titlebar[selected] {
   background-color: #dae3f0;
 }
 
 .chat-titlebar[activity] {
-  background-color: #ceeaff;
+  background-image: radial-gradient(ellipse closest-side at center, rgb(255,255,255), rgba(255,255,255,0));
+  background-repeat: no-repeat;
+  background-size: 100% 20px;
+  background-position: 0 -10px;
 }
 
 .chat-frame {
   padding: 0;
   margin: 0;
   overflow: hidden;
 }
 
@@ -3482,53 +3486,62 @@ html|*#gcli-output-frame {
 }
 
 .chatbar-button > .button-box > .box-inherit > .button-icon {
   max-height: 16px;
   max-width: 16px;
   padding: 2px;
 }
 
-.chatbar-button[open="true"],
-.chatbar-button:hover,
-.chatbar-button:active:hover {
+.chatbar-button > .toolbarbutton-icon {
+  opacity: .6;
+  -moz-margin-end: 0;
+}
+.chatbar-button:hover > .toolbarbutton-icon,
+.chatbar-button[open="true"] > .toolbarbutton-icon {
+  opacity: 1;
+}
+
+.chatbar-button[open="true"] {
   background-color: #dae3f0;
   box-shadow: inset 0 2px 5px rgba(0,0,0,0.6), 0 1px rgba(255,255,255,0.2);
 }
 
 .chatbar-button > .toolbarbutton-text,
 .chatbar-button > .toolbarbutton-menu-dropmarker {
   display: none;
 }
 
-.chatbar-button[activity] {
-  background-color: #ceeaff;
+.chatbar-button[activity]:not([open="true"]) {
+  background-image: radial-gradient(circle farthest-corner at center 3px, rgb(255,255,255) 3%, rgba(186,221,251,0.75) 40%, rgba(127,179,255,0.5) 80%, rgba(127,179,255,0.25));
 }
 
 .chatbar-button > menupopup > menuitem[activity] {
   font-weight: bold;
 }
 
 .chatbar-innerbox {
   background: transparent;
-  margin: -285px -1px 0 -1px;
+  margin: -285px 0 0;
   overflow: hidden;
 }
 
 chatbar {
   -moz-margin-end: 20px;
 }
 
 chatbox {
   height: 285px;
   width: 260px;
   -moz-margin-start: 4px;
   background-color: white;
   border: 1px solid #ccc;
   border-bottom: none;
+  border-top-left-radius: 2.5px;
+  border-top-right-radius: 2.5px;
 }
 
 chatbox[minimized="true"] {
   width: 160px;
   height: 20px;
 }
 
 .click-to-play-plugins-notification-content {
--- a/browser/themes/winstripe/downloads/downloads.css
+++ b/browser/themes/winstripe/downloads/downloads.css
@@ -67,17 +67,16 @@ richlistitem[type="download"]:first-chil
   richlistitem[type="download"]:last-child {
     border-bottom: 1px solid transparent;
   }
 }
 
 #downloadsListBox:-moz-focusring > richlistitem[type="download"][selected] {
   outline: 1px -moz-dialogtext dotted;
   outline-offset: -1px;
-  -moz-outline-radius: 3px;
 }
 
 .downloadTypeIcon {
   -moz-margin-end: 8px;
   /* Prevent flickering when changing states. */
   min-height: 32px;
   min-width: 32px;
 }
--- 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(96a92f0c-adcb-44ac-a034-37627647ec97)]
+[scriptable, uuid(3a283dc9-f733-4618-a36f-e2b68c280ab7)]
 interface nsIPrincipal : nsISerializable
 {
     /**
      * Returns whether the other principal is equivalent to this principal.
      * Principals are considered equal if they are the same principal, or
      * they have the same origin.
      */
     boolean equals(in nsIPrincipal other);
@@ -190,16 +190,22 @@ interface nsIPrincipal : nsISerializable
     readonly attribute boolean isInBrowserElement;
 
     /**
      * Returns true if this principal has an unknown appId. This shouldn't
      * generally be used. We only expose it due to not providing the correct
      * appId everywhere where we construct principals.
      */
     readonly attribute boolean unknownAppId;
+
+    /**
+     * Returns true iff this principal is a null principal (corresponding to an
+     * unknown, hence assumed minimally privileged, security context).
+     */
+    readonly attribute boolean isNullPrincipal;
 };
 
 /**
  * If nsSystemPrincipal is too risky to use, but we want a principal to access 
  * more than one origin, nsExpandedPrincipals letting us define an array of 
  * principals it subsumes. So script with an nsExpandedPrincipals will gain
  * same origin access when at least one of its principals it contains gained 
  * sameorigin acccess. An nsExpandedPrincipal will be subsumed by the system
@@ -212,9 +218,9 @@ interface nsIPrincipal : nsISerializable
 interface nsIExpandedPrincipal : nsISupports
 {
   /**
    * An array of principals that the expanded principal subsumes.
    * Note: this list is not reference counted, it is shared, so 
    * should not be changed and should only be used ephemerally.
    */
   [noscript] readonly attribute PrincipalArray whiteList;
-};
+};
\ No newline at end of file
--- a/caps/include/nsPrincipal.h
+++ b/caps/include/nsPrincipal.h
@@ -66,16 +66,17 @@ public:
   NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval);
   NS_IMETHOD SubsumesIgnoringDomain(nsIPrincipal* other, bool* _retval);
   NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report, bool allowIfInheritsPrincipal);
   NS_IMETHOD GetExtendedOrigin(nsACString& aExtendedOrigin);
   NS_IMETHOD GetAppStatus(uint16_t* aAppStatus);
   NS_IMETHOD GetAppId(uint32_t* aAppStatus);
   NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement);
   NS_IMETHOD GetUnknownAppId(bool* aUnknownAppId);
+  NS_IMETHOD GetIsNullPrincipal(bool* aIsNullPrincipal);
 #ifdef DEBUG
   virtual void dumpImpl();
 #endif
 
   nsPrincipal();
 
   // Init() must be called before the principal is in a usable state.
   nsresult Init(nsIURI* aCodebase,
@@ -147,16 +148,17 @@ public:
   NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval);
   NS_IMETHOD SubsumesIgnoringDomain(nsIPrincipal* other, bool* _retval);
   NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report, bool allowIfInheritsPrincipal);
   NS_IMETHOD GetExtendedOrigin(nsACString& aExtendedOrigin);
   NS_IMETHOD GetAppStatus(uint16_t* aAppStatus);
   NS_IMETHOD GetAppId(uint32_t* aAppStatus);
   NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement);
   NS_IMETHOD GetUnknownAppId(bool* aUnknownAppId);
+  NS_IMETHOD GetIsNullPrincipal(bool* aIsNullPrincipal);
 #ifdef DEBUG
   virtual void dumpImpl();
 #endif
   
   virtual void GetScriptLocation(nsACString &aStr) MOZ_OVERRIDE;
 
 private:
   nsTArray< nsCOMPtr<nsIPrincipal> > mPrincipals;
--- a/caps/src/nsNullPrincipal.cpp
+++ b/caps/src/nsNullPrincipal.cpp
@@ -286,16 +286,23 @@ nsNullPrincipal::GetIsInBrowserElement(b
 
 NS_IMETHODIMP
 nsNullPrincipal::GetUnknownAppId(bool* aUnknownAppId)
 {
   *aUnknownAppId = false;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsNullPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal)
+{
+  *aIsNullPrincipal = true;
+  return NS_OK;
+}
+
 /**
  * nsISerializable implementation
  */
 NS_IMETHODIMP
 nsNullPrincipal::Read(nsIObjectInputStream* aStream)
 {
   // no-op: CID is sufficient to create a useful nsNullPrincipal, since the URI
   // is not really relevant.
--- a/caps/src/nsPrincipal.cpp
+++ b/caps/src/nsPrincipal.cpp
@@ -537,16 +537,23 @@ nsPrincipal::GetIsInBrowserElement(bool*
 NS_IMETHODIMP
 nsPrincipal::GetUnknownAppId(bool* aUnknownAppId)
 {
   *aUnknownAppId = mAppId == nsIScriptSecurityManager::UNKNOWN_APP_ID;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal)
+{
+  *aIsNullPrincipal = false;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsPrincipal::Read(nsIObjectInputStream* aStream)
 {
   nsCOMPtr<nsIURI> codebase;
   nsresult rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(codebase));
   if (NS_FAILED(rv)) {
     return rv;
   }
 
@@ -847,16 +854,23 @@ nsExpandedPrincipal::GetIsInBrowserEleme
 
 NS_IMETHODIMP
 nsExpandedPrincipal::GetUnknownAppId(bool* aUnknownAppId)
 {
   *aUnknownAppId = false;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsExpandedPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal)
+{
+  *aIsNullPrincipal = false;
+  return NS_OK;
+}
+
 void
 nsExpandedPrincipal::GetScriptLocation(nsACString& aStr)
 {
   // Is that a good idea to list it's principals?
   aStr.Assign(EXPANDED_PRINCIPAL_SPEC);
 }
 
 #ifdef DEBUG
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -2987,21 +2987,23 @@ GetExtendedOrigin(nsIURI* aURI, uint32_t
   nsPrincipal::GetOriginForURI(aURI, getter_Copies(origin));
 
   // Fallback.
   if (aAppId == nsIScriptSecurityManager::NO_APP_ID && !aInMozBrowser) {
     aExtendedOrigin.Assign(origin);
     return;
   }
 
-  // aExtendedOrigin = appId + "+" + origin + "+" + { 't', 'f' }
+  // aExtendedOrigin = appId + "+" + { 't', 'f' } "+" + origin;
   aExtendedOrigin.Truncate();
   aExtendedOrigin.AppendInt(aAppId);
-  aExtendedOrigin.Append(NS_LITERAL_CSTRING("+") + origin + NS_LITERAL_CSTRING("+"));
+  aExtendedOrigin.Append('+');
   aExtendedOrigin.Append(aInMozBrowser ? 't' : 'f');
+  aExtendedOrigin.Append('+');
+  aExtendedOrigin.Append(origin);
 
   return;
 }
 
 } // namespace mozilla
 
 NS_IMETHODIMP
 nsScriptSecurityManager::GetExtendedOrigin(nsIURI* aURI,
--- a/caps/src/nsSystemPrincipal.cpp
+++ b/caps/src/nsSystemPrincipal.cpp
@@ -193,16 +193,23 @@ nsSystemPrincipal::GetIsInBrowserElement
 
 NS_IMETHODIMP
 nsSystemPrincipal::GetUnknownAppId(bool* aUnknownAppId)
 {
   *aUnknownAppId = false;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsSystemPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal)
+{
+  *aIsNullPrincipal = false;
+  return NS_OK;
+}
+
 //////////////////////////////////////////
 // Methods implementing nsISerializable //
 //////////////////////////////////////////
 
 NS_IMETHODIMP
 nsSystemPrincipal::Read(nsIObjectInputStream* aStream)
 {
     // no-op: CID is sufficient to identify the mSystemPrincipal singleton
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -1197,25 +1197,25 @@ WebGLContext::DummyFramebufferOperation(
 // In all of these situations, we use this timer to send the script context lost
 // and restored events asynchronously. For example, if it triggers a context loss,
 // the webglcontextlost event will be sent to it the next time the robustness timer
 // fires.
 // Note that this timer mechanism is not used unless one of these 3 criteria
 // are met.
 // At a bare minimum, from context lost to context restores, it would take 3
 // full timer iterations: detection, webglcontextlost, webglcontextrestored.
-NS_IMETHODIMP
-WebGLContext::Notify(nsITimer* timer)
+void
+WebGLContext::RobustnessTimerCallback(nsITimer* timer)
 {
     TerminateContextLossTimer();
 
     if (!mCanvasElement) {
         // the canvas is gone. That happens when the page was closed before we got
         // this timer event. In this case, there's nothing to do here, just don't crash.
-        return NS_OK;
+        return;
     }
 
     // If the context has been lost and we're waiting for it to be restored, do
     // that now.
     if (mContextStatus == ContextLostAwaitingEvent) {
         bool defaultAction;
         nsContentUtils::DispatchTrustedEvent(mCanvasElement->OwnerDoc(),
                                              static_cast<nsIDOMHTMLCanvasElement*>(mCanvasElement),
@@ -1238,32 +1238,32 @@ WebGLContext::Notify(nsITimer* timer)
             SetupContextLossTimer();
         } else {
             mContextStatus = ContextLost;
         }
     } else if (mContextStatus == ContextLostAwaitingRestore) {
         // Try to restore the context. If it fails, try again later.
         if (NS_FAILED(SetDimensions(mWidth, mHeight))) {
             SetupContextLossTimer();
-            return NS_OK;
+            return;
         }
         mContextStatus = ContextStable;
         nsContentUtils::DispatchTrustedEvent(mCanvasElement->OwnerDoc(),
                                              static_cast<nsIDOMHTMLCanvasElement*>(mCanvasElement),
                                              NS_LITERAL_STRING("webglcontextrestored"),
                                              true,
                                              true);
         // Set all flags back to the state they were in before the context was
         // lost.
         mContextLostErrorSet = false;
         mAllowRestore = true;
     }
 
     MaybeRestoreContext();
-    return NS_OK;
+    return;
 }
 
 void
 WebGLContext::MaybeRestoreContext()
 {
     // Don't try to handle it if we already know it's busted.
     if (mContextStatus != ContextStable || gl == nullptr)
         return;
@@ -1403,14 +1403,13 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebGLContext)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsIDOMWebGLRenderingContext)
   NS_INTERFACE_MAP_ENTRY(nsICanvasRenderingContextInternal)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
-  NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
   // If the exact way we cast to nsISupports here ever changes, fix our
   // PreCreate hook!
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports,
                                    nsICanvasRenderingContextInternal)
 NS_INTERFACE_MAP_END
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -468,17 +468,16 @@ struct WebGLContextOptions {
     bool antialias;
     bool preserveDrawingBuffer;
 };
 
 class WebGLContext :
     public nsIDOMWebGLRenderingContext,
     public nsICanvasRenderingContextInternal,
     public nsSupportsWeakReference,
-    public nsITimerCallback,
     public WebGLRectangleObject,
     public nsWrapperCache
 {
     friend class WebGLContextUserData;
     friend class WebGLMemoryPressureObserver;
     friend class WebGLMemoryMultiReporterWrapper;
     friend class WebGLExtensionLoseContext;
     friend class WebGLExtensionCompressedTextureS3TC;
@@ -505,18 +504,16 @@ public:
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(WebGLContext,
                                                            nsIDOMWebGLRenderingContext)
 
     virtual JSObject* WrapObject(JSContext *cx, JSObject *scope,
                                  bool *triedToWrap);
 
     NS_DECL_NSIDOMWEBGLRENDERINGCONTEXT
 
-    NS_DECL_NSITIMERCALLBACK
-
     // nsICanvasRenderingContextInternal
     NS_IMETHOD SetDimensions(int32_t width, int32_t height);
     NS_IMETHOD InitializeWithSurface(nsIDocShell *docShell, gfxASurface *surface, int32_t width, int32_t height)
         { return NS_ERROR_NOT_IMPLEMENTED; }
     NS_IMETHOD Reset()
         { /* (InitializeWithSurface) */ return NS_ERROR_NOT_IMPLEMENTED; }
     NS_IMETHOD Render(gfxContext *ctx,
                       gfxPattern::GraphicsFilter f,
@@ -602,29 +599,36 @@ public:
         GLenum currentGLError;
         UpdateWebGLErrorAndClearGLError(&currentGLError);
     }
     
     bool MinCapabilityMode() const {
         return mMinCapability;
     }
 
+    void RobustnessTimerCallback(nsITimer* timer);
+
+    static void RobustnessTimerCallbackStatic(nsITimer* timer, void *thisPointer) {
+        static_cast<WebGLContext*>(thisPointer)->RobustnessTimerCallback(timer);
+    }
+
     void SetupContextLossTimer() {
         // If the timer was already running, don't restart it here. Instead,
         // wait until the previous call is done, then fire it one more time.
         // This is an optimization to prevent unnecessary cross-communication
         // between threads.
         if (mContextLossTimerRunning) {
             mDrawSinceContextLossTimerSet = true;
             return;
         }
-        
-        mContextRestorer->InitWithCallback(static_cast<nsITimerCallback*>(this),
-                                           PR_MillisecondsToInterval(1000),
-                                           nsITimer::TYPE_ONE_SHOT);
+
+        mContextRestorer->InitWithFuncCallback(RobustnessTimerCallbackStatic,
+                                               static_cast<void*>(this),
+                                               PR_MillisecondsToInterval(1000),
+                                               nsITimer::TYPE_ONE_SHOT);
         mContextLossTimerRunning = true;
         mDrawSinceContextLossTimerSet = false;
     }
 
     void TerminateContextLossTimer() {
         if (mContextLossTimerRunning) {
             mContextRestorer->Cancel();
             mContextLossTimerRunning = false;
--- a/content/events/src/Makefile.in
+++ b/content/events/src/Makefile.in
@@ -59,22 +59,16 @@ CPPSRCS		= \
 		nsDOMTransitionEvent.cpp \
 		nsDOMAnimationEvent.cpp \
 		nsDOMTouchEvent.cpp \
 		nsDOMCompositionEvent.cpp \
 		DOMWheelEvent.cpp \
 		TextComposition.cpp \
 		$(NULL)
 
-ifdef MOZ_B2G_RIL
-CPPSRCS += \
-    nsDOMWifiEvent.cpp \
-    $(NULL)
-endif
-
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES	+= \
deleted file mode 100644
--- a/content/events/src/nsDOMWifiEvent.cpp
+++ /dev/null
@@ -1,179 +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/. */
-
-#include "nsDOMWifiEvent.h"
-#include "nsContentUtils.h"
-#include "DictionaryHelpers.h"
-#include "nsDOMClassInfoID.h"
-
-// nsDOMMozWifiStatusChangeEvent
-
-DOMCI_DATA(MozWifiStatusChangeEvent, nsDOMMozWifiStatusChangeEvent)
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMMozWifiStatusChangeEvent)
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMMozWifiStatusChangeEvent, nsDOMEvent)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mNetwork)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMMozWifiStatusChangeEvent, nsDOMEvent)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mNetwork)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_INTERFACE_MAP_BEGIN(nsDOMMozWifiStatusChangeEvent)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMMozWifiStatusChangeEvent)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozWifiStatusChangeEvent)
-NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
-
-NS_IMPL_ADDREF_INHERITED(nsDOMMozWifiStatusChangeEvent, nsDOMEvent)
-NS_IMPL_RELEASE_INHERITED(nsDOMMozWifiStatusChangeEvent, nsDOMEvent)
-
-NS_IMETHODIMP
-nsDOMMozWifiStatusChangeEvent::GetNetwork(nsIVariant** aNetwork)
-{
-  NS_IF_ADDREF(*aNetwork = mNetwork);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMMozWifiStatusChangeEvent::GetStatus(nsAString& aStatus)
-{
-  aStatus = mStatus;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMMozWifiStatusChangeEvent::InitMozWifiStatusChangeEvent(const nsAString& aType,
-                                                            bool aCanBubble,
-                                                            bool aCancelable,
-                                                            nsIVariant* aNetwork,
-                                                            const nsAString& aStatus)
-{
-  nsresult rv = nsDOMEvent::InitEvent(aType, aCanBubble, aCancelable);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  mNetwork = aNetwork;
-  mStatus = aStatus;
-
-  return NS_OK;
-}
-
-nsresult
-nsDOMMozWifiStatusChangeEvent::InitFromCtor(const nsAString& aType,
-                                            JSContext* aCx, jsval* aVal)
-{
-  mozilla::dom::MozWifiStatusChangeEventInit d;
-  nsresult rv = d.Init(aCx, aVal);
-  NS_ENSURE_SUCCESS(rv, rv);
-  return InitMozWifiStatusChangeEvent(aType, d.bubbles, d.cancelable, d.network, d.status);
-}
-
-nsresult
-NS_NewDOMMozWifiStatusChangeEvent(nsIDOMEvent** aInstancePtrResult,
-                                  nsPresContext* aPresContext,
-                                  nsEvent* aEvent) 
-{
-  nsDOMMozWifiStatusChangeEvent* e = new nsDOMMozWifiStatusChangeEvent(aPresContext, aEvent);
-  return CallQueryInterface(e, aInstancePtrResult);
-}
-
-// nsDOMMozWifiConnectionInfoEvent
-DOMCI_DATA(MozWifiConnectionInfoEvent, nsDOMMozWifiConnectionInfoEvent)
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMMozWifiConnectionInfoEvent)
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMMozWifiConnectionInfoEvent, nsDOMEvent)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mNetwork)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMMozWifiConnectionInfoEvent, nsDOMEvent)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mNetwork)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_INTERFACE_MAP_BEGIN(nsDOMMozWifiConnectionInfoEvent)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMMozWifiConnectionInfoEvent)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozWifiConnectionInfoEvent)
-NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
-
-NS_IMPL_ADDREF_INHERITED(nsDOMMozWifiConnectionInfoEvent, nsDOMEvent)
-NS_IMPL_RELEASE_INHERITED(nsDOMMozWifiConnectionInfoEvent, nsDOMEvent)
-
-NS_IMETHODIMP
-nsDOMMozWifiConnectionInfoEvent::GetNetwork(nsIVariant** aNetwork)
-{
-  NS_IF_ADDREF(*aNetwork = mNetwork);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMMozWifiConnectionInfoEvent::GetSignalStrength(int16_t* aSignalStrength)
-{
-  *aSignalStrength = mSignalStrength;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMMozWifiConnectionInfoEvent::GetRelSignalStrength(int16_t* aRelSignalStrength)
-{
-  *aRelSignalStrength = mRelSignalStrength;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMMozWifiConnectionInfoEvent::GetLinkSpeed(int32_t* aLinkSpeed)
-{
-  *aLinkSpeed = mLinkSpeed;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMMozWifiConnectionInfoEvent::GetIpAddress(nsAString& aIpAddress)
-{
-    aIpAddress = mIpAddress;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMMozWifiConnectionInfoEvent::InitMozWifiConnectionInfoEvent(const nsAString& aType,
-                                                                bool aCanBubble,
-                                                                bool aCancelable,
-                                                                nsIVariant *aNetwork,
-                                                                int16_t aSignalStrength,
-                                                                int16_t aRelSignalStrength,
-                                                                int32_t aLinkSpeed,
-                                                                const nsAString &aIpAddress)
-{
-  nsresult rv = nsDOMEvent::InitEvent(aType, aCanBubble, aCancelable);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  mNetwork = aNetwork;
-  mSignalStrength = aSignalStrength;
-  mRelSignalStrength = aRelSignalStrength;
-  mLinkSpeed = aLinkSpeed;
-  mIpAddress = aIpAddress;
-
-  return NS_OK;
-}
-
-nsresult
-nsDOMMozWifiConnectionInfoEvent::InitFromCtor(const nsAString& aType,
-                                              JSContext* aCx, jsval* aVal)
-{
-  mozilla::dom::MozWifiConnectionInfoEventInit d;
-  nsresult rv = d.Init(aCx, aVal);
-  NS_ENSURE_SUCCESS(rv, rv);
-  return InitMozWifiConnectionInfoEvent(aType, d.bubbles, d.cancelable, d.network,
-                                        d.signalStrength, d.relSignalStrength, d.linkSpeed,
-                                        d.ipAddress);
-}
-
-nsresult
-NS_NewDOMMozWifiConnectionInfoEvent(nsIDOMEvent** aInstancePtrResult,
-                                    nsPresContext* aPresContext,
-                                    nsEvent* aEvent) 
-{
-  nsDOMMozWifiConnectionInfoEvent* e = new nsDOMMozWifiConnectionInfoEvent(aPresContext, aEvent);
-  return CallQueryInterface(e, aInstancePtrResult);
-}
deleted file mode 100644
--- a/content/events/src/nsDOMWifiEvent.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 nsDOMWifiEvent_h__
-#define nsDOMWifiEvent_h__
-
-#include "nsIWifi.h"
-#include "nsIWifiEventInits.h"
-#include "nsDOMEvent.h"
-
-class nsDOMMozWifiStatusChangeEvent : public nsDOMEvent,
-                                   public nsIDOMMozWifiStatusChangeEvent
-{
-public:
-  nsDOMMozWifiStatusChangeEvent(nsPresContext* aPresContext, nsEvent* aEvent)
-    : nsDOMEvent(aPresContext, aEvent) {}
-
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMMozWifiStatusChangeEvent, nsDOMEvent)
-  // Forward to base class
-  NS_FORWARD_TO_NSDOMEVENT
-
-  NS_DECL_NSIDOMMOZWIFISTATUSCHANGEEVENT
-
-  virtual nsresult InitFromCtor(const nsAString& aType,
-                                JSContext* aCx, jsval* aVal);
-private:
-  nsCOMPtr<nsIVariant> mNetwork;
-  nsString mStatus;
-};
-
-class nsDOMMozWifiConnectionInfoEvent : public nsDOMEvent,
-                                        public nsIDOMMozWifiConnectionInfoEvent
-{
-public:
-  nsDOMMozWifiConnectionInfoEvent(nsPresContext* aPresContext, nsEvent* aEvent)
-    : nsDOMEvent(aPresContext, aEvent) {}
-
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMMozWifiConnectionInfoEvent, nsDOMEvent)
-  // Forward to base class
-  NS_FORWARD_TO_NSDOMEVENT
-
-  NS_DECL_NSIDOMMOZWIFICONNECTIONINFOEVENT
-
-  virtual nsresult InitFromCtor(const nsAString& aType,
-                                JSContext* aCx, jsval* aVal);
-private:
-  nsCOMPtr<nsIVariant> mNetwork;
-  int16_t mSignalStrength;
-  int16_t mRelSignalStrength;
-  int32_t mLinkSpeed;
-  nsString mIpAddress;
-};
-
-#endif // nsDOMWifiEvent_h__
--- a/content/svg/content/src/nsSVGSVGElement.cpp
+++ b/content/svg/content/src/nsSVGSVGElement.cpp
@@ -162,17 +162,19 @@ nsSVGSVGElement::nsSVGSVGElement(already
                                  FromParser aFromParser)
   : nsSVGSVGElementBase(aNodeInfo),
     mViewportWidth(0),
     mViewportHeight(0),
     mCurrentTranslate(0.0f, 0.0f),
     mCurrentScale(1.0f),
     mPreviousTranslate(0.0f, 0.0f),
     mPreviousScale(1.0f),
-    mStartAnimationOnBindToTree(!aFromParser),
+    mStartAnimationOnBindToTree(aFromParser == NOT_FROM_PARSER ||
+                                aFromParser == FROM_PARSER_FRAGMENT ||
+                                aFromParser == FROM_PARSER_XSLT),
     mImageNeedsTransformInvalidation(false),
     mIsPaintingSVGImageElement(false),
     mHasChildrenOnlyTransform(false),
     mUseCurrentView(false)
 {
 }
 
 //----------------------------------------------------------------------
--- a/dom/alarm/AlarmHalService.cpp
+++ b/dom/alarm/AlarmHalService.cpp
@@ -14,39 +14,39 @@ NS_IMPL_ISUPPORTS1(AlarmHalService, nsIA
 
 void
 AlarmHalService::Init()
 {
   mAlarmEnabled = RegisterTheOneAlarmObserver(this);
   if (!mAlarmEnabled) {
     return;
   }
-  RegisterSystemTimeChangeObserver(this);
+  RegisterSystemTimezoneChangeObserver(this);
 }
 
 /* virtual */ AlarmHalService::~AlarmHalService() 
 {
   if (mAlarmEnabled) {
     UnregisterTheOneAlarmObserver();
-    UnregisterSystemTimeChangeObserver(this);
+    UnregisterSystemTimezoneChangeObserver(this);
   }
 }
 
 /* static */ StaticRefPtr<AlarmHalService> AlarmHalService::sSingleton;
 
-/* static */ already_AddRefed<nsIAlarmHalService>
+/* static */ already_AddRefed<AlarmHalService>
 AlarmHalService::GetInstance()
 {
   if (!sSingleton) {
     sSingleton = new AlarmHalService();
     sSingleton->Init(); 
     ClearOnShutdown(&sSingleton);
   }
 
-  nsCOMPtr<nsIAlarmHalService> service(do_QueryInterface(sSingleton));
+  nsRefPtr<AlarmHalService> service = sSingleton.get();
   return service.forget();
 }
 
 NS_IMETHODIMP
 AlarmHalService::SetAlarm(int32_t aSeconds, int32_t aNanoseconds, bool* aStatus)
 {
   if (!mAlarmEnabled) {
     return NS_ERROR_FAILURE;
@@ -71,42 +71,30 @@ AlarmHalService::SetAlarmFiredCb(nsIAlar
 NS_IMETHODIMP
 AlarmHalService::SetTimezoneChangedCb(nsITimezoneChangedCb* aTimeZoneChangedCb)
 {
   mTimezoneChangedCb = aTimeZoneChangedCb;
   return NS_OK;
 }
 
 void
-AlarmHalService::Notify(const mozilla::void_t& aVoid)
+AlarmHalService::Notify(const void_t& aVoid)
 {
   if (!mAlarmFiredCb) {
     return;
   }
   mAlarmFiredCb->OnAlarmFired();
 }
 
 void
-AlarmHalService::Notify(const SystemTimeChange& aReason)
+AlarmHalService::Notify(
+  const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo)
 {
-  if (aReason != SYS_TIME_CHANGE_TZ || !mTimezoneChangedCb) {
+  if (!mTimezoneChangedCb) {
     return;
   }
-  mTimezoneChangedCb->OnTimezoneChanged(GetTimezoneOffset(false));
-}
-
-int32_t
-AlarmHalService::GetTimezoneOffset(bool aIgnoreDST)
-{
-  PRExplodedTime prTime;
-  PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &prTime);
-
-  int32_t offset = prTime.tm_params.tp_gmt_offset;
-  if (!aIgnoreDST) {
-    offset += prTime.tm_params.tp_dst_offset;
-  }
-
-  return -(offset / 60);
+  mTimezoneChangedCb->OnTimezoneChanged(
+    aSystemTimezoneChangeInfo.newTimezoneOffsetMinutes());
 }
 
 } // alarm
 } // dom
 } // mozilla
--- a/dom/alarm/AlarmHalService.h
+++ b/dom/alarm/AlarmHalService.h
@@ -8,50 +8,48 @@
 #include "base/basictypes.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/Hal.h"
 #include "mozilla/Services.h"
 #include "nsIAlarmHalService.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
-#include "prtime.h"
 
 namespace mozilla {
 namespace dom {
 namespace alarm {
-
-using namespace hal;
+  
+typedef Observer<void_t> AlarmObserver;
+typedef Observer<hal::SystemTimezoneChangeInformation> SystemTimezoneChangeObserver;
 
 class AlarmHalService : public nsIAlarmHalService, 
                         public AlarmObserver,
-                        public SystemTimeObserver
+                        public SystemTimezoneChangeObserver
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIALARMHALSERVICE
 
   void Init();
   virtual ~AlarmHalService();
 
-  static already_AddRefed<nsIAlarmHalService> GetInstance();
+  static already_AddRefed<AlarmHalService> GetInstance();
 
   // Implementing hal::AlarmObserver
-  void Notify(const mozilla::void_t& aVoid);
+  void Notify(const void_t& aVoid);
 
-  // Implementing hal::SystemTimeObserver
-  void Notify(const SystemTimeChange& aReason);
+  // Implementing hal::SystemTimezoneChangeObserver
+  void Notify(const hal::SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo);
 
 private:
   bool mAlarmEnabled;
   static StaticRefPtr<AlarmHalService> sSingleton;
 
   nsCOMPtr<nsIAlarmFiredCb> mAlarmFiredCb;
   nsCOMPtr<nsITimezoneChangedCb> mTimezoneChangedCb;
-
-  int32_t GetTimezoneOffset(bool aIgnoreDST);
 };
 
 } // namespace alarm
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_alarm_AlarmHalService_h
--- a/dom/apps/src/Makefile.in
+++ b/dom/apps/src/Makefile.in
@@ -21,12 +21,13 @@ EXTRA_PP_COMPONENTS = \
 
 EXTRA_PP_JS_MODULES += \
   Webapps.jsm \
   $(NULL)
 
 EXTRA_JS_MODULES += \
   AppsServiceChild.jsm \
   AppsUtils.jsm \
+  OfflineCacheInstaller.jsm \
   PermissionsInstaller.jsm \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/apps/src/OfflineCacheInstaller.jsm
@@ -0,0 +1,174 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const Cu = Components.utils;
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const CC = Components.Constructor;
+
+let EXPORTED_SYMBOLS = ["OfflineCacheInstaller"];
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/AppsUtils.jsm");
+Cu.import("resource://gre/modules/NetUtil.jsm");
+
+let Namespace = CC('@mozilla.org/network/application-cache-namespace;1',
+                   'nsIApplicationCacheNamespace',
+                   'init');
+let makeFile = CC('@mozilla.org/file/local;1',
+                'nsIFile',
+                'initWithPath');
+const nsICache = Ci.nsICache;
+const nsIApplicationCache = Ci.nsIApplicationCache;
+const applicationCacheService =
+  Cc['@mozilla.org/network/application-cache-service;1']
+    .getService(Ci.nsIApplicationCacheService);
+
+
+function debug(aMsg) {
+  //dump("-*-*- OfflineCacheInstaller.jsm : " + aMsg + "\n");
+}
+
+
+function enableOfflineCacheForApp(origin, appId) {
+  let originURI = Services.io.newURI(origin, null, null);
+  let principal = Services.scriptSecurityManager.getAppCodebasePrincipal(
+                    originURI, appId, false);
+  Services.perms.addFromPrincipal(principal, 'offline-app',
+                                  Ci.nsIPermissionManager.ALLOW_ACTION);
+  // Prevent cache from being evicted:
+  Services.perms.addFromPrincipal(principal, 'pin-app',
+                                  Ci.nsIPermissionManager.ALLOW_ACTION);
+}
+
+
+function storeCache(applicationCache, url, file, itemType) {
+  let session = Services.cache.createSession(applicationCache.clientID,
+                                             nsICache.STORE_OFFLINE, true);
+  session.asyncOpenCacheEntry(url, nsICache.ACCESS_WRITE, {
+    onCacheEntryAvailable: function (cacheEntry, accessGranted, status) {
+      cacheEntry.setMetaDataElement('request-method', 'GET');
+      cacheEntry.setMetaDataElement('response-head', 'HTTP/1.1 200 OK\r\n');
+
+      let outputStream = cacheEntry.openOutputStream(0);
+
+      // Input-Output stream machinery in order to push nsIFile content into cache
+      let inputStream = Cc['@mozilla.org/network/file-input-stream;1']
+                          .createInstance(Ci.nsIFileInputStream);
+      inputStream.init(file, 1, -1, null);
+      let bufferedOutputStream = Cc['@mozilla.org/network/buffered-output-stream;1']
+                                   .createInstance(Ci.nsIBufferedOutputStream);
+      bufferedOutputStream.init(outputStream, 1024);
+      bufferedOutputStream.writeFrom(inputStream, inputStream.available());
+      bufferedOutputStream.flush();
+      bufferedOutputStream.close();
+      outputStream.close();
+      inputStream.close();
+
+      cacheEntry.markValid();
+      debug (file.path + ' -> ' + url + ' (' + itemType + ')');
+      applicationCache.markEntry(url, itemType);
+      cacheEntry.close();
+    }
+  });
+}
+
+function readFile(aFile, aCallback) {
+  let channel = NetUtil.newChannel(aFile);
+  channel.contentType = "pain/text";
+  NetUtil.asyncFetch(channel, function(aStream, aResult) {
+    if (!Components.isSuccessCode(aResult)) {
+      Cu.reportError("OfflineCacheInstaller: Could not read file " + aFile.path);
+      if (aCallback)
+        aCallback(null);
+      return;
+    }
+
+    // Obtain a converter to read from a UTF-8 encoded input stream.
+    let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
+                      .createInstance(Ci.nsIScriptableUnicodeConverter);
+    converter.charset = "UTF-8";
+
+    let data = NetUtil.readInputStreamToString(aStream,
+                                               aStream.available());
+    aCallback(converter.ConvertToUnicode(data));
+  });
+}
+
+const OfflineCacheInstaller = {
+  installCache: function installCache(app) {
+    let cacheDir = makeFile(app.basePath)
+    cacheDir.append(app.appId);
+    cacheDir.append("cache");
+    if (!cacheDir.exists())
+      return;
+
+    let cacheManifest = cacheDir.clone();
+    cacheManifest.append("manifest.appcache");
+    if (!cacheManifest.exists())
+      return;
+
+    enableOfflineCacheForApp(app.origin, app.localId);
+
+    // Get the url for the manifest.
+    let appcacheURL = app.origin + "cache/manifest.appcache";
+
+    // The group ID contains application id and 'f' for not being hosted in
+    // a browser element, but a mozbrowser iframe.
+    // See netwerk/cache/nsDiskCacheDeviceSQL.cpp: AppendJARIdentifier
+    let groupID = appcacheURL + '#' + app.localId+ '+f';
+    let applicationCache = applicationCacheService.createApplicationCache(groupID);
+    applicationCache.activate();
+
+    readFile(cacheManifest, function (content) {
+      let lines = content.split(/\r?\n/);
+      // Process each manifest line, read only CACHE entries
+      // (ignore NETWORK entries) and compute absolute URL for each entry
+      let urls = [];
+      for(let i = 0; i < lines.length; i++) {
+        let line = lines[i];
+        // Ignore comments
+        if (/^#/.test(line) || !line.length)
+          continue;
+        if (line == 'CACHE MANIFEST')
+          continue;
+        if (line == 'CACHE:')
+          continue;
+        // Ignore network entries and everything that comes after
+        if (line == 'NETWORK:')
+          break;
+
+        // Prepend webapp origin in case of absolute path
+        if (line[0] == '/') {
+          urls.push(app.origin + line.substring(1));
+        // Just pass along the url, if we have one
+        } else if (line.substr(0, 4) == 'http') {
+          urls.push(line);
+        } else {
+          throw new Error('Invalid line in appcache manifest:\n' + line +
+                          '\nFrom: ' + cacheManifest.path);
+        }
+      }
+      urls.forEach(function processCachedFile(url) {
+        // Get this nsIFile from cache folder for this URL
+        let path = url.replace(/https?:\/\//, '');
+        let file = cacheDir.clone();
+        let paths = path.split('/');
+        paths.forEach(file.append);
+
+        if (!file.exists()) {
+          let msg = 'File ' + file.path + ' exists in the manifest but does ' +
+                    'not points to a real file.';
+          throw new Error(msg);
+        }
+
+        let itemType = nsIApplicationCache.ITEM_EXPLICIT;
+        storeCache(applicationCache, url, file, itemType);
+      });
+    });
+  }
+};
+
--- a/dom/apps/src/PermissionsInstaller.jsm
+++ b/dom/apps/src/PermissionsInstaller.jsm
@@ -4,42 +4,33 @@
 
 "use strict";
 
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/AppsUtils.jsm");
+Cu.import("resource://gre/modules/PermissionSettings.jsm");
 
 var EXPORTED_SYMBOLS = ["PermissionsInstaller"];
 
 const UNKNOWN_ACTION = Ci.nsIPermissionManager.UNKNOWN_ACTION;
 const ALLOW_ACTION = Ci.nsIPermissionManager.ALLOW_ACTION;
 const DENY_ACTION = Ci.nsIPermissionManager.DENY_ACTION;
 const PROMPT_ACTION = Ci.nsIPermissionManager.PROMPT_ACTION;
 
 // Permission access flags
 const READONLY = "readonly";
 const CREATEONLY = "createonly";
 const READCREATE = "readcreate";
 const READWRITE = "readwrite";
 
 const PERM_TO_STRING = ["unknown", "allow", "deny", "prompt"];
 
-XPCOMUtils.defineLazyServiceGetter(this,
-                                   "PermSettings",
-                                   "@mozilla.org/permissionSettings;1",
-                                   "nsIDOMPermissionSettings");
-
-XPCOMUtils.defineLazyServiceGetter(this,
-                                   "permissionManager",
-                                   "@mozilla.org/permissionmanager;1",
-                                   "nsIPermissionManager");
-
 function debug(aMsg) {
   //dump("-*-*- PermissionsInstaller.jsm : " + aMsg + "\n");
 }
 
 /**
  * Converts ['read', 'write'] to ['contacts-read', 'contacts-write'], etc...
  * @param string aPermName
  * @param Array aSuffixes
@@ -339,17 +330,17 @@ let PermissionsInstaller = {
                                            newManifest.permissions[perm].access);
             newPerms = newPerms.concat(_perms);
           }
 
           for (let idx in AllPossiblePermissions) {
             let index = newPerms.indexOf(AllPossiblePermissions[idx]);
             if (index == -1) {
               // See if the permission was installed previously
-              let _perm = PermSettings.get(AllPossiblePermissions[idx],
+              let _perm = PermissionSettingsModule.getPermission(AllPossiblePermissions[idx],
                                            aApp.manifestURL,
                                            aApp.origin,
                                            false);
               if (_perm == "unknown" || _perm == "deny") {
                 // All 'deny' permissions should be preserved
                 continue;
               }
               // Remove the deprecated permission
@@ -410,19 +401,31 @@ let PermissionsInstaller = {
    *        The permission value.
    * @param object aApp
    *        The just-installed app configuration.
             The properties used are manifestURL, origin and manifest.
    * @returns void
    **/
   _setPermission: function setPermission(aPerm, aValue, aApp) {
     if (aPerm != "storage") {
-      PermSettings.set(aPerm, aValue, aApp.manifestURL, aApp.origin, false);
+      PermissionSettingsModule.addPermission({
+        type: aPerm,
+        origin: aApp.origin,
+        manifestURL: aApp.manifestURL,
+        value: aValue,
+        browserFlag: false
+      });
       return;
     }
 
     ["indexedDB-unlimited", "offline-app", "pin-app"].forEach(
       function(aName) {
-        PermSettings.set(aName, aValue, aApp.manifestURL, aApp.origin, false);
+        PermissionSettingsModule.addPermission({
+          type: aName,
+          origin: aApp.origin,
+          manifestURL: aApp.manifestURL,
+          value: aValue,
+          browserFlag: false
+        });
       }
     );
   }
 }
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -12,16 +12,17 @@ const Cr = Components.results;
 let EXPORTED_SYMBOLS = ["DOMApplicationRegistry"];
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/FileUtils.jsm");
 Cu.import('resource://gre/modules/ActivitiesService.jsm');
 Cu.import("resource://gre/modules/AppsUtils.jsm");
 Cu.import("resource://gre/modules/PermissionsInstaller.jsm");
+Cu.import("resource://gre/modules/OfflineCacheInstaller.jsm");
 
 function debug(aMsg) {
   //dump("-*-*- Webapps.jsm : " + aMsg + "\n");
 }
 
 const WEBAPP_RUNTIME = Services.appinfo.ID == "webapprt@mozilla.org";
 
 XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
@@ -87,17 +88,17 @@ let DOMApplicationRegistry = {
 
     this.loadAndUpdateApps();
   },
 
   // loads the current registry, that could be empty on first run.
   // aNext() is called after we load the current webapps list.
   loadCurrentRegistry: function loadCurrentRegistry(aNext) {
     let file = FileUtils.getFile(DIRECTORY_NAME, ["webapps", "webapps.json"], false);
-    if (file && file.exists) {
+    if (file && file.exists()) {
       this._loadJSONAsync(file, (function loadRegistry(aData) {
         if (aData) {
           this.webapps = aData;
           let appDir = FileUtils.getDir(DIRECTORY_NAME, ["webapps"], false);
           for (let id in this.webapps) {
             // Make sure we have a localId
             if (this.webapps[id].localId === undefined) {
               this.webapps[id].localId = this._nextLocalId();
@@ -170,99 +171,109 @@ let DOMApplicationRegistry = {
         manifestURL: this.webapps[aId].manifestURL,
         origin: this.webapps[aId].origin
       }, true, function() {
         debug("Error installing permissions for " + aId);
       });
     }).bind(this));
   },
 
+  updateOfflineCacheForApp: function updateOfflineCacheForApp(aId) {
+    let app = this.webapps[aId];
+    OfflineCacheInstaller.installCache({
+      basePath: app.basePath,
+      appId: aId,
+      origin: app.origin,
+      localId: app.localId
+    });
+  },
+
   // Implements the core of bug 787439
-  // 1. load the apps from the current registry.
-  // 2. if at first run, go through these steps:
+  // if at first run, go through these steps:
   //   a. load the core apps registry.
   //   b. uninstall any core app from the current registry but not in the
   //      new core apps registry.
   //   c. for all apps in the new core registry, install them if they are not
   //      yet in the current registry, and run installPermissions()
+  installSystemApps: function installSystemApps(aNext) {
+    let file;
+    try {
+      file = FileUtils.getFile("coreAppsDir", ["webapps", "webapps.json"], false);
+    } catch(e) { }
+
+    if (file && file.exists()) {
+      // a
+      this._loadJSONAsync(file, (function loadCoreRegistry(aData) {
+        if (!aData) {
+          aNext();
+          return;
+        }
+
+        // b : core apps are not removable.
+        for (let id in this.webapps) {
+          if (id in aData || this.webapps[id].removable)
+            continue;
+          delete this.webapps[id];
+          // Remove the permissions, cookies and private data for this app.
+          let localId = this.webapps[id].localId;
+          let permMgr = Cc["@mozilla.org/permissionmanager;1"]
+                          .getService(Ci.nsIPermissionManager);
+          permMgr.RemovePermissionsForApp(localId);
+          Services.cookies.removeCookiesForApp(localId, false);
+          this._clearPrivateData(localId, false);
+        }
+
+        let appDir = FileUtils.getDir("coreAppsDir", ["webapps"], false);
+        // c
+        for (let id in aData) {
+          // Core apps have ids matching their domain name (eg: dialer.gaiamobile.org)
+          // Use that property to check if they are new or not.
+          if (!(id in this.webapps)) {
+            this.webapps[id] = aData[id];
+            this.webapps[id].basePath = appDir.path;
+
+            // Create a new localId.
+            this.webapps[id].localId = this._nextLocalId();
+
+            // Core apps are not removable.
+            if (this.webapps[id].removable === undefined) {
+              this.webapps[id].removable = false;
+            }
+          }
+        }
+        aNext();
+      }).bind(this));
+    } else {
+      aNext();
+    }
+  },
+
   loadAndUpdateApps: function loadAndUpdateApps() {
     let runUpdate = AppsUtils.isFirstRun(Services.prefs);
 
-    // 1.
+    let onAppsLoaded = (function onAppsLoaded() {
+      if (runUpdate) {
+        // At first run, set up the permissions
+        for (let id in this.webapps) {
+          this.updatePermissionsForApp(id);
+          this.updateOfflineCacheForApp(id);
+        }
+      }
+      this.registerAppsHandlers();
+    }).bind(this);
+
     this.loadCurrentRegistry((function() {
 #ifdef MOZ_WIDGET_GONK
-    // if first run, merge the system apps.
-    if (runUpdate) {
-      let file;
-      try {
-        file = FileUtils.getFile("coreAppsDir", ["webapps", "webapps.json"], false);
-      } catch(e) { }
-
-      if (file && file.exists) {
-        // 2.a
-        this._loadJSONAsync(file, (function loadCoreRegistry(aData) {
-          if (!aData) {
-            this.registerAppsHandlers();
-            return;
-          }
-
-          // 2.b : core apps are not removable.
-          for (let id in this.webapps) {
-            if (id in aData || this.webapps[id].removable)
-              continue;
-            delete this.webapps[id];
-            // Remove the permissions, cookies and private data for this app.
-            let localId = this.webapps[id].localId;
-            let permMgr = Cc["@mozilla.org/permissionmanager;1"]
-                            .getService(Ci.nsIPermissionManager);
-            permMgr.RemovePermissionsForApp(localId);
-            Services.cookies.removeCookiesForApp(localId, false);
-            this._clearPrivateData(localId, false);
-          }
-
-          let appDir = FileUtils.getDir("coreAppsDir", ["webapps"], false);
-          // 2.c
-          for (let id in aData) {
-            // Core apps have ids matching their domain name (eg: dialer.gaiamobile.org)
-            // Use that property to check if they are new or not.
-            if (!(id in this.webapps)) {
-              this.webapps[id] = aData[id];
-              this.webapps[id].basePath = appDir.path;
-
-              // Create a new localId.
-              this.webapps[id].localId = this._nextLocalId();
-
-              // Core apps are not removable.
-              if (this.webapps[id].removable === undefined) {
-                this.webapps[id].removable = false;
-              }
-            }
-
-            this.updatePermissionsForApp(id);
-          }
-          this.registerAppsHandlers();
-        }).bind(this));
-      } else {
-        // At first run, set up the permissions for eng builds.
-        for (let id in this.webapps) {
-          this.updatePermissionsForApp(id);
-        }
-        this.registerAppsHandlers();
-      }
-    } else {
-      this.registerAppsHandlers();
-    }
+      // if first run, merge the system apps.
+      if (runUpdate)
+        this.installSystemApps(onAppsLoaded);
+      else
+        onAppsLoaded();
 #else
-    if (runUpdate) {
-      // At first run, set up the permissions for desktop builds.
-      for (let id in this.webapps) {
-        this.updatePermissionsForApp(id);
-      }
-    }
-    this.registerAppsHandlers();
+      onAppsLoaded();
 #endif
     }).bind(this));
   },
 
 #ifdef MOZ_SYS_MSG
   // |aEntryPoint| is either the entry_point name or the null in which case we
   // use the root of the manifest.
   _registerSystemMessagesForEntryPoint: function(aManifest, aApp, aEntryPoint) {
@@ -470,24 +481,24 @@ let DOMApplicationRegistry = {
 
           data = JSON.parse(converter.ConvertToUnicode(NetUtil.readInputStreamToString(aStream,
                                                             aStream.available()) || ""));
           aStream.close();
           if (aCallback)
             aCallback(data);
         } catch (ex) {
           Cu.reportError("DOMApplicationRegistry: Could not parse JSON: " +
-                         aFile.path + " " + ex);
+                         aFile.path + " " + ex + "\n" + ex.stack);
           if (aCallback)
             aCallback(null);
         }
       });
     } catch (ex) {
       Cu.reportError("DOMApplicationRegistry: Could not read from " +
-                     aFile.path + " : " + ex);
+                     aFile.path + " : " + ex + "\n" + ex.stack);
       if (aCallback)
         aCallback(null);
     }
   },
 
   addMessageListener: function(aMsgNames, aMm) {
     aMsgNames.forEach(function (aMsgName) {
       if (!(aMsgName in this.children)) {
@@ -1720,16 +1731,20 @@ let DOMApplicationRegistry = {
       mm.addMessageListener(msgName, listener);
     });
   },
 
   receiveAppMessage: function(appId, message) {
     switch (message.name) {
       case "Webapps:ClearBrowserData":
         this._clearPrivateData(appId, true);
+        // XXXbent This is a hack until bug 802366 is fixed. Currently all data
+        //         loaded in mozbrowser frames within an app believe that their
+        //         appId is 0.
+        this._clearPrivateData(0, true);
         break;
     }
   },
 
   _clearPrivateData: function(appId, browserOnly) {
     let subject = {
       appId: appId,
       browserOnly: browserOnly,
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -174,17 +174,16 @@
 #include "nsEventSource.h"
 #include "nsIDOMSettingsManager.h"
 #include "nsIDOMContactManager.h"
 #include "nsIDOMPermissionSettings.h"
 #include "nsIDOMApplicationRegistry.h"
 
 #ifdef MOZ_B2G_RIL
 #include "nsIWifi.h"
-#include "nsIWifiEventInits.h"
 #endif
 
 // includes needed for the prototype chain interfaces
 #include "nsIDOMNavigator.h"
 #include "nsIDOMBarProp.h"
 #include "nsIDOMScreen.h"
 #include "nsIDOMDocumentType.h"
 #include "nsIDOMDocumentFragment.h"
@@ -1614,20 +1613,16 @@ static nsDOMClassInfoData sClassInfoData
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(MutationObserver, nsDOMMutationObserverSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS |
                            nsIXPCScriptable::WANT_ADDPROPERTY)
   NS_DEFINE_CLASSINFO_DATA(MutationRecord, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
 #ifdef MOZ_B2G_RIL
-  NS_DEFINE_CLASSINFO_DATA(MozWifiStatusChangeEvent, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(MozWifiConnectionInfoEvent, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(Telephony, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(TelephonyCall, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CallEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(MozVoicemail, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
@@ -1728,20 +1723,16 @@ NS_DEFINE_CONTRACT_CTOR(MozActivity, NS_
     *aInstancePtrResult = e;                                \
     return rv;                                              \
   }
 
 NS_DEFINE_EVENT_CTOR(Event)
 NS_DEFINE_EVENT_CTOR(UIEvent)
 NS_DEFINE_EVENT_CTOR(MouseEvent)
 NS_DEFINE_EVENT_CTOR(WheelEvent)
-#ifdef MOZ_B2G_RIL
-NS_DEFINE_EVENT_CTOR(MozWifiStatusChangeEvent)
-NS_DEFINE_EVENT_CTOR(MozWifiConnectionInfoEvent)
-#endif
 
 #define MOZ_GENERATED_EVENT_LIST
 #define MOZ_GENERATED_EVENT(_event_interface) \
   NS_DEFINE_EVENT_CTOR(_event_interface)
 #include "GeneratedEvents.h"
 #undef MOZ_GENERATED_EVENT_LIST
 
 nsresult
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -483,18 +483,16 @@ DOMCI_CLASS(MozCSSKeyframeRule)
 DOMCI_CLASS(MozCSSKeyframesRule)
 
 DOMCI_CLASS(MediaQueryList)
 
 DOMCI_CLASS(MutationObserver)
 DOMCI_CLASS(MutationRecord)
 
 #ifdef MOZ_B2G_RIL
-DOMCI_CLASS(MozWifiStatusChangeEvent)
-DOMCI_CLASS(MozWifiConnectionInfoEvent)
 DOMCI_CLASS(Telephony)
 DOMCI_CLASS(TelephonyCall)
 DOMCI_CLASS(CallEvent)
 DOMCI_CLASS(MozVoicemail)
 DOMCI_CLASS(MozVoicemailEvent)
 DOMCI_CLASS(MozIccManager)
 DOMCI_CLASS(MozStkCommandEvent)
 #endif
--- a/dom/indexedDB/DatabaseInfo.cpp
+++ b/dom/indexedDB/DatabaseInfo.cpp
@@ -176,41 +176,16 @@ DatabaseInfo::Remove(nsIAtom* aId)
 
     if (!gDatabaseHash->Count()) {
       delete gDatabaseHash;
       gDatabaseHash = nullptr;
     }
   }
 }
 
-PLDHashOperator
-EnumerateDatabasesRemoveOrigin(nsISupports* aId,
-                               DatabaseInfo*& aDatabaseInfo,
-                               void* aUserArg)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  const nsACString* origin = static_cast<const nsACString*>(aUserArg);
-  return aDatabaseInfo->origin.Equals(*origin) ?
-    PL_DHASH_REMOVE :
-    PL_DHASH_NEXT;
-}
-
-// static
-void
-DatabaseInfo::RemoveAllForOrigin(const nsACString& aOrigin)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  if (gDatabaseHash) {
-    gDatabaseHash->Enumerate(EnumerateDatabasesRemoveOrigin,
-                             const_cast<nsACString*>(&aOrigin));
-  }
-}
-
 bool
 DatabaseInfo::GetObjectStoreNames(nsTArray<nsString>& aNames)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   aNames.Clear();
   if (objectStoreHash) {
     objectStoreHash->EnumerateRead(EnumerateObjectStoreNames, &aNames);
--- a/dom/indexedDB/DatabaseInfo.h
+++ b/dom/indexedDB/DatabaseInfo.h
@@ -57,18 +57,16 @@ struct DatabaseInfo : public DatabaseInf
 
   static bool Get(nsIAtom* aId,
                   DatabaseInfo** aInfo);
 
   static bool Put(DatabaseInfo* aInfo);
 
   static void Remove(nsIAtom* aId);
 
-  static void RemoveAllForOrigin(const nsACString& aOrigin);
-
   bool GetObjectStoreNames(nsTArray<nsString>& aNames);
   bool ContainsStoreName(const nsAString& aName);
 
   ObjectStoreInfo* GetObjectStore(const nsAString& aName);
 
   bool PutObjectStore(ObjectStoreInfo* aInfo);
 
   void RemoveObjectStore(const nsAString& aName);
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 
 #include "IDBDatabase.h"
 
 #include "mozilla/Mutex.h"
 #include "mozilla/storage.h"
+#include "mozilla/unused.h"
 #include "mozilla/dom/ContentParent.h"
 #include "nsDOMClassInfo.h"
 #include "nsDOMLists.h"
 #include "nsJSUtils.h"
 #include "nsProxyRelease.h"
 #include "nsThreadUtils.h"
 
 #include "AsyncConnectionHelper.h"
@@ -28,16 +29,17 @@
 #include "IDBTransaction.h"
 #include "IDBFactory.h"
 #include "IndexedDatabaseManager.h"
 #include "TransactionThreadPool.h"
 #include "DictionaryHelpers.h"
 #include "nsContentUtils.h"
 
 #include "ipc/IndexedDBChild.h"
+#include "ipc/IndexedDBParent.h"
 
 USING_INDEXEDDB_NAMESPACE
 using mozilla::dom::ContentParent;
 
 namespace {
 
 class NoRequestDatabaseHelper : public AsyncConnectionHelper
 {
@@ -264,22 +266,24 @@ IDBDatabase::Invalidate()
 
   // When the IndexedDatabaseManager needs to invalidate databases, all it has
   // is an origin, so we call back into the manager to cancel any prompts for
   // our owner.
   nsPIDOMWindow* owner = GetOwner();
   if (owner) {
     IndexedDatabaseManager::CancelPromptsForWindow(owner);
   }
-}
+
+  DatabaseInfo::Remove(mDatabaseId);
 
-bool
-IDBDatabase::IsInvalidated()
-{
-  return mInvalidated;
+  // And let the child process know as well.
+  if (mActorParent) {
+    NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+    mozilla::unused << mActorParent->SendInvalidate();
+  }
 }
 
 void
 IDBDatabase::DisconnectFromActor()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (IsDisconnectedFromActor()) {
@@ -294,18 +298,19 @@ IDBDatabase::DisconnectFromActor()
   // Kill any outstanding prompts.
   nsPIDOMWindow* owner = GetOwner();
   if (owner) {
     IndexedDatabaseManager::CancelPromptsForWindow(owner);
   }
 }
 
 bool
-IDBDatabase::IsDisconnectedFromActor()
+IDBDatabase::IsDisconnectedFromActor() const
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   return mDisconnected;
 }
 
 void
 IDBDatabase::CloseInternal(bool aIsDead)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
@@ -325,25 +330,25 @@ IDBDatabase::CloseInternal(bool aIsDead)
     }
 
     IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
     if (mgr) {
       mgr->OnDatabaseClosed(this);
     }
 
     // And let the parent process know as well.
-    if (mActorChild) {
+    if (mActorChild && !IsInvalidated()) {
       NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
       mActorChild->SendClose(aIsDead);
     }
   }
 }
 
 bool
-IDBDatabase::IsClosed()
+IDBDatabase::IsClosed() const
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   return mClosed;
 }
 
 void
 IDBDatabase::EnterSetVersionTransaction()
 {
--- a/dom/indexedDB/IDBDatabase.h
+++ b/dom/indexedDB/IDBDatabase.h
@@ -69,59 +69,63 @@ public:
     return mDatabaseId;
   }
 
   DatabaseInfo* Info() const
   {
     return mDatabaseInfo;
   }
 
-  const nsString& Name()
+  const nsString& Name() const
   {
     return mName;
   }
 
-  const nsString& FilePath()
+  const nsString& FilePath() const
   {
     return mFilePath;
   }
 
   already_AddRefed<nsIDocument> GetOwnerDocument()
   {
     if (!GetOwner()) {
       return nullptr;
     }
 
     nsCOMPtr<nsIDocument> doc =
       do_QueryInterface(GetOwner()->GetExtantDocument());
     return doc.forget();
   }
 
-  nsCString& Origin()
+  const nsCString& Origin() const
   {
     return mASCIIOrigin;
   }
 
   void Invalidate();
 
   // Whether or not the database has been invalidated. If it has then no further
-  // transactions for this database will be allowed to run.
-  bool IsInvalidated();
+  // transactions for this database will be allowed to run. This function may be
+  // called on any thread.
+  bool IsInvalidated() const
+  {
+    return mInvalidated;
+  }
 
   void DisconnectFromActor();
 
   // Whether or not the database has been disconnected from its actor.  If true
   // it is not safe to send any IPC messages to the actor representing this db
   // or any of its subactors.
-  bool IsDisconnectedFromActor();
+  bool IsDisconnectedFromActor() const;
 
   void CloseInternal(bool aIsDead);
 
   // Whether or not the database has had Close called on it.
-  bool IsClosed();
+  bool IsClosed() const;
 
   void EnterSetVersionTransaction();
   void ExitSetVersionTransaction();
 
   // Called when a versionchange transaction is aborted to reset the
   // DatabaseInfo.
   void RevertToPreviousState();
 
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -536,18 +536,19 @@ IDBFactory::OpenCommon(const nsAString& 
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     nsRefPtr<CheckPermissionsHelper> permissionHelper =
       new CheckPermissionsHelper(openHelper, window, aDeleting);
 
     IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
     NS_ASSERTION(mgr, "This should never be null!");
 
-    rv = 
-      mgr->WaitForOpenAllowed(mASCIIOrigin, openHelper->Id(), permissionHelper);
+    rv =
+      mgr->WaitForOpenAllowed(OriginOrPatternString::FromOrigin(mASCIIOrigin),
+                              openHelper->Id(), permissionHelper);
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
   else if (aDeleting) {
     nsCOMPtr<nsIAtom> databaseId =
       IndexedDatabaseManager::GetDatabaseId(mASCIIOrigin, aName);
     NS_ENSURE_TRUE(databaseId, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     IndexedDBDeleteDatabaseRequestChild* actor =
--- a/dom/indexedDB/IndexedDatabase.h
+++ b/dom/indexedDB/IndexedDatabase.h
@@ -170,11 +170,49 @@ struct SerializedStructuredCloneWriteInf
   }
 
   // Make sure to update ipc/SerializationHelpers.h when changing members here!
   uint64_t* data;
   size_t dataLength;
   uint64_t offsetToKeyProp;
 };
 
+class OriginOrPatternString : public nsCString
+{
+public:
+  static OriginOrPatternString
+  FromOrigin(const nsACString& aOrigin)
+  {
+    return OriginOrPatternString(aOrigin, true);
+  }
+
+  static OriginOrPatternString
+  FromPattern(const nsACString& aPattern)
+  {
+    return OriginOrPatternString(aPattern, false);
+  }
+
+  bool
+  IsOrigin() const
+  {
+    return mIsOrigin;
+  }
+
+  bool
+  IsPattern() const
+  {
+    return !mIsOrigin;
+  }
+
+private:
+  OriginOrPatternString(const nsACString& aOriginOrPattern, bool aIsOrigin)
+  : nsCString(aOriginOrPattern), mIsOrigin(aIsOrigin)
+  { }
+
+  bool
+  operator==(const OriginOrPatternString& aOther) MOZ_DELETE;
+
+  bool mIsOrigin;
+};
+
 END_INDEXEDDB_NAMESPACE
 
 #endif // mozilla_dom_indexeddb_indexeddatabase_h__
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -1,39 +1,42 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "IndexedDatabaseManager.h"
-#include "DatabaseInfo.h"
-
+
+#include "mozIApplicationClearPrivateDataParams.h"
 #include "nsIAtom.h"
 #include "nsIConsoleService.h"
 #include "nsIDOMScriptObjectFactory.h"
 #include "nsIFile.h"
 #include "nsIFileStorage.h"
 #include "nsIObserverService.h"
+#include "nsIPrincipal.h"
 #include "nsIScriptError.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsISHEntry.h"
 #include "nsISimpleEnumerator.h"
 #include "nsITimer.h"
 
 #include "mozilla/dom/file/FileService.h"
 #include "mozilla/LazyIdleThread.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/storage.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsContentUtils.h"
+#include "nsCRTGlue.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsEventDispatcher.h"
+#include "nsScriptSecurityManager.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOM.h"
 #include "nsXPCOMPrivate.h"
 #include "test_quota.h"
 #include "xpcpublic.h"
 
 #include "AsyncConnectionHelper.h"
 #include "CheckQuotaHelper.h"
@@ -128,42 +131,255 @@ EnumerateToTArray(const nsACString& aKey
                   nsTArray<IDBDatabase*>* aValue,
                   void* aUserArg)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(!aKey.IsEmpty(), "Empty key!");
   NS_ASSERTION(aValue, "Null pointer!");
   NS_ASSERTION(aUserArg, "Null pointer!");
 
-  nsTArray<T>* array =
-    static_cast<nsTArray<T>*>(aUserArg);
-
-  if (!array->AppendElements(*aValue)) {
-    NS_WARNING("Out of memory!");
-    return PL_DHASH_STOP;
+  static_cast<nsTArray<T>*>(aUserArg)->AppendElements(*aValue);
+  return PL_DHASH_NEXT;
+}
+
+bool
+PatternMatchesOrigin(const nsACString& aPatternString, const nsACString& aOrigin)
+{
+  // Aren't we smart!
+  return StringBeginsWith(aOrigin, aPatternString);
+}
+
+enum MozBrowserPatternFlag
+{
+  MozBrowser = 0,
+  NotMozBrowser,
+  IgnoreMozBrowser
+};
+
+// Use one of the friendly overloads below.
+void
+GetOriginPatternString(uint32_t aAppId, MozBrowserPatternFlag aBrowserFlag,
+                       const nsACString& aOrigin, nsAutoCString& _retval)
+{
+  NS_ASSERTION(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
+               "Bad appId!");
+  NS_ASSERTION(aOrigin.IsEmpty() || aBrowserFlag != IgnoreMozBrowser,
+               "Bad args!");
+
+  if (aOrigin.IsEmpty()) {
+    _retval.Truncate();
+
+    _retval.AppendInt(aAppId);
+    _retval.Append('+');
+
+    if (aBrowserFlag != IgnoreMozBrowser) {
+      if (aBrowserFlag == MozBrowser) {
+        _retval.Append('t');
+      }
+      else {
+        _retval.Append('f');
+      }
+      _retval.Append('+');
+    }
+
+    return;
+  }
+
+#ifdef DEBUG
+  if (aAppId != nsIScriptSecurityManager::NO_APP_ID ||
+      aBrowserFlag == MozBrowser) {
+    nsAutoCString pattern;
+    GetOriginPatternString(aAppId, aBrowserFlag, EmptyCString(), pattern);
+    NS_ASSERTION(PatternMatchesOrigin(pattern, aOrigin),
+                 "Origin doesn't match parameters!");
+  }
+#endif
+
+  _retval = aOrigin;
+}
+
+void
+GetOriginPatternString(uint32_t aAppId, nsAutoCString& _retval)
+{
+  return GetOriginPatternString(aAppId, IgnoreMozBrowser, EmptyCString(),
+                                _retval);
+}
+
+void
+GetOriginPatternString(uint32_t aAppId, bool aBrowserOnly,
+                       nsAutoCString& _retval)
+{
+  return GetOriginPatternString(aAppId,
+                                aBrowserOnly ? MozBrowser : NotMozBrowser,
+                                EmptyCString(), _retval);
+}
+
+void
+GetOriginPatternString(uint32_t aAppId, bool aBrowserOnly,
+                       const nsACString& aOrigin, nsAutoCString& _retval)
+{
+  return GetOriginPatternString(aAppId,
+                                aBrowserOnly ? MozBrowser : NotMozBrowser,
+                                aOrigin, _retval);
+}
+
+void
+GetOriginPatternStringMaybeIgnoreBrowser(uint32_t aAppId, bool aBrowserOnly,
+                                         nsAutoCString& _retval)
+{
+  return GetOriginPatternString(aAppId,
+                                aBrowserOnly ? MozBrowser : IgnoreMozBrowser,
+                                EmptyCString(), _retval);
+}
+
+template <class ValueType>
+class PatternMatchArray : public nsAutoTArray<ValueType, 20>
+{
+  typedef PatternMatchArray<ValueType> SelfType;
+
+  struct Closure
+  {
+    Closure(SelfType& aSelf, const nsACString& aPattern)
+    : mSelf(aSelf), mPattern(aPattern)
+    { }
+
+    SelfType& mSelf;
+    const nsACString& mPattern;
+  };
+
+public:
+  template <class T>
+  void
+  Find(const T& aHashtable,
+       const nsACString& aPattern)
+  {
+    SelfType::Clear();
+
+    Closure closure(*this, aPattern);
+    aHashtable.EnumerateRead(SelfType::Enumerate, &closure);
+  }
+
+private:
+  static PLDHashOperator
+  Enumerate(const nsACString& aKey,
+            nsTArray<ValueType>* aValue,
+            void* aUserArg)
+  {
+    NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+    NS_ASSERTION(!aKey.IsEmpty(), "Empty key!");
+    NS_ASSERTION(aValue, "Null pointer!");
+    NS_ASSERTION(aUserArg, "Null pointer!");
+
+    Closure* closure = static_cast<Closure*>(aUserArg);
+
+    if (PatternMatchesOrigin(closure->mPattern, aKey)) {
+      closure->mSelf.AppendElements(*aValue);
+    }
+
+    return PL_DHASH_NEXT;
+  }
+};
+
+typedef PatternMatchArray<IDBDatabase*> DatabasePatternMatchArray;
+
+PLDHashOperator
+InvalidateAndRemoveFileManagers(
+                           const nsACString& aKey,
+                           nsAutoPtr<nsTArray<nsRefPtr<FileManager> > >& aValue,
+                           void* aUserArg)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(!aKey.IsEmpty(), "Empty key!");
+  NS_ASSERTION(aValue, "Null pointer!");
+
+  const nsACString* pattern =
+    static_cast<const nsACString*>(aUserArg);
+
+  if (!pattern || PatternMatchesOrigin(*pattern, aKey)) {
+    for (uint32_t i = 0; i < aValue->Length(); i++) {
+      nsRefPtr<FileManager>& fileManager = aValue->ElementAt(i);
+      fileManager->Invalidate();
+    }
+    return PL_DHASH_REMOVE;
   }
 
   return PL_DHASH_NEXT;
 }
 
-PLDHashOperator
-InvalidateAllFileManagers(const nsACString& aKey,
-                          nsTArray<nsRefPtr<FileManager> >* aValue,
-                          void* aUserArg)
+void
+SanitizeOriginString(nsCString& aOrigin)
+{
+  // We want profiles to be platform-independent so we always need to replace
+  // the same characters on every platform. Windows has the most extensive set
+  // of illegal characters so we use its FILE_ILLEGAL_CHARACTERS and
+  // FILE_PATH_SEPARATOR.
+  static const char kReplaceChars[] = CONTROL_CHARACTERS "/:*?\"<>|\\";
+
+#ifdef XP_WIN
+  NS_ASSERTION(!strcmp(kReplaceChars,
+                       FILE_ILLEGAL_CHARACTERS FILE_PATH_SEPARATOR),
+               "Illegal file characters have changed!");
+#endif
+
+  aOrigin.ReplaceChar(kReplaceChars, '+');
+}
+
+nsresult
+GetASCIIOriginFromURI(nsIURI* aURI,
+                      uint32_t aAppId,
+                      bool aInMozBrowser,
+                      nsACString& aOrigin)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-  NS_ASSERTION(!aKey.IsEmpty(), "Empty key!");
-  NS_ASSERTION(aValue, "Null pointer!");
-
-  for (uint32_t i = 0; i < aValue->Length(); i++) {
-    nsRefPtr<FileManager> fileManager = aValue->ElementAt(i);
-    fileManager->Invalidate();
+  NS_ASSERTION(aURI, "Null uri!");
+
+  nsCString origin;
+  mozilla::GetExtendedOrigin(aURI, aAppId, aInMozBrowser, origin);
+
+  if (origin.IsEmpty()) {
+    NS_WARNING("GetExtendedOrigin returned empty string!");
+    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
-  return PL_DHASH_NEXT;
+  aOrigin.Assign(origin);
+  return NS_OK;
+}
+
+nsresult
+GetASCIIOriginFromPrincipal(nsIPrincipal* aPrincipal,
+                            nsACString& aOrigin)
+{
+  NS_ASSERTION(aPrincipal, "Don't hand me a null principal!");
+
+  static const char kChromeOrigin[] = "chrome";
+
+  nsCString origin;
+  if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
+    origin.AssignLiteral(kChromeOrigin);
+  }
+  else {
+    bool isNullPrincipal;
+    nsresult rv = aPrincipal->GetIsNullPrincipal(&isNullPrincipal);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    if (isNullPrincipal) {
+      NS_WARNING("IndexedDB not supported from this principal!");
+      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+    }
+
+    rv = aPrincipal->GetExtendedOrigin(origin);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    if (origin.EqualsLiteral(kChromeOrigin)) {
+      NS_WARNING("Non-chrome principal can't use chrome origin!");
+      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+    }
+  }
+
+  aOrigin.Assign(origin);
+  return NS_OK;
 }
 
 } // anonymous namespace
 
 IndexedDatabaseManager::IndexedDatabaseManager()
 : mCurrentWindowIndex(BAD_TLS_INDEX),
   mQuotaHelperMutex("IndexedDatabaseManager.mQuotaHelperMutex"),
   mFileMutex("IndexedDatabaseManager.mFileMutex")
@@ -292,20 +508,20 @@ IndexedDatabaseManager::GetDirectoryForO
   nsresult rv;
   nsCOMPtr<nsIFile> directory =
     do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = directory->InitWithPath(GetBaseDirectory());
   NS_ENSURE_SUCCESS(rv, rv);
 
-  NS_ConvertASCIItoUTF16 originSanitized(aASCIIOrigin);
-  originSanitized.ReplaceChar(":/", '+');
-
-  rv = directory->Append(originSanitized);
+  nsAutoCString originSanitized(aASCIIOrigin);
+  SanitizeOriginString(originSanitized);
+
+  rv = directory->Append(NS_ConvertASCIItoUTF16(originSanitized));
   NS_ENSURE_SUCCESS(rv, rv);
 
   directory.forget(aDirectory);
   return NS_OK;
 }
 
 // static
 already_AddRefed<nsIAtom>
@@ -401,16 +617,47 @@ IndexedDatabaseManager::FireWindowOnErro
 
   nsCOMPtr<nsIConsoleService> consoleService =
     do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return consoleService->LogMessage(scriptError);
 }
 
+// static
+bool
+IndexedDatabaseManager::OriginMatchesApp(const nsACString& aOrigin,
+                                         uint32_t aAppId)
+{
+  NS_ASSERTION(!aOrigin.IsEmpty(), "Empty origin!");
+  NS_ASSERTION(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
+               "Bad appId!");
+
+  nsAutoCString pattern;
+  GetOriginPatternString(aAppId, pattern);
+
+  return PatternMatchesOrigin(pattern, aOrigin);
+}
+
+// static
+bool
+IndexedDatabaseManager::OriginMatchesApp(const nsACString& aOrigin,
+                                         uint32_t aAppId,
+                                         bool aInMozBrowser)
+{
+  NS_ASSERTION(!aOrigin.IsEmpty(), "Empty origin!");
+  NS_ASSERTION(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
+               "Bad appId!");
+
+  nsAutoCString pattern;
+  GetOriginPatternString(aAppId, aInMozBrowser, pattern);
+
+  return PatternMatchesOrigin(pattern, aOrigin);
+}
+
 bool
 IndexedDatabaseManager::RegisterDatabase(IDBDatabase* aDatabase)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aDatabase, "Null pointer!");
 
   // Don't allow any new databases to be created after shutdown.
   if (IsShuttingDown()) {
@@ -461,25 +708,26 @@ IndexedDatabaseManager::OnUsageCheckComp
   NS_ASSERTION(!aRunnable->mCallback, "Should have been cleared!");
 
   if (!mUsageRunnables.RemoveElement(aRunnable)) {
     NS_ERROR("Don't know anything about this runnable!");
   }
 }
 
 nsresult
-IndexedDatabaseManager::WaitForOpenAllowed(const nsACString& aOrigin,
-                                           nsIAtom* aId,
-                                           nsIRunnable* aRunnable)
+IndexedDatabaseManager::WaitForOpenAllowed(
+                                  const OriginOrPatternString& aOriginOrPattern,
+                                  nsIAtom* aId,
+                                  nsIRunnable* aRunnable)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-  NS_ASSERTION(!aOrigin.IsEmpty(), "Empty origin!");
+  NS_ASSERTION(!aOriginOrPattern.IsEmpty(), "Empty pattern!");
   NS_ASSERTION(aRunnable, "Null pointer!");
 
-  nsAutoPtr<SynchronizedOp> op(new SynchronizedOp(aOrigin, aId));
+  nsAutoPtr<SynchronizedOp> op(new SynchronizedOp(aOriginOrPattern, aId));
 
   // See if this runnable needs to wait.
   bool delayed = false;
   for (uint32_t index = mSynchronizedOps.Length(); index > 0; index--) {
     nsAutoPtr<SynchronizedOp>& existingOp = mSynchronizedOps[index - 1];
     if (op->MustWaitFor(*existingOp)) {
       existingOp->DelayRunnable(aRunnable);
       delayed = true;
@@ -496,26 +744,28 @@ IndexedDatabaseManager::WaitForOpenAllow
   // Adding this to the synchronized ops list will block any additional
   // ops from proceeding until this one is done.
   mSynchronizedOps.AppendElement(op.forget());
 
   return NS_OK;
 }
 
 void
-IndexedDatabaseManager::AllowNextSynchronizedOp(const nsACString& aOrigin,
-                                                nsIAtom* aId)
+IndexedDatabaseManager::AllowNextSynchronizedOp(
+                                  const OriginOrPatternString& aOriginOrPattern,
+                                  nsIAtom* aId)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-  NS_ASSERTION(!aOrigin.IsEmpty(), "Empty origin!");
+  NS_ASSERTION(!aOriginOrPattern.IsEmpty(), "Empty origin/pattern!");
 
   uint32_t count = mSynchronizedOps.Length();
   for (uint32_t index = 0; index < count; index++) {
     nsAutoPtr<SynchronizedOp>& op = mSynchronizedOps[index];
-    if (op->mOrigin.Equals(aOrigin)) {
+    if (op->mOriginOrPattern.IsOrigin() == aOriginOrPattern.IsOrigin() &&
+        op->mOriginOrPattern == aOriginOrPattern) {
       if (op->mId == aId) {
         NS_ASSERTION(op->mDatabases.IsEmpty(), "How did this happen?");
 
         op->DispatchDelayedRunnables();
 
         mSynchronizedOps.RemoveElementAt(index);
         return;
       }
@@ -526,60 +776,60 @@ IndexedDatabaseManager::AllowNextSynchro
     }
   }
 
   NS_NOTREACHED("Why didn't we find a SynchronizedOp?");
 }
 
 nsresult
 IndexedDatabaseManager::AcquireExclusiveAccess(
-                                           const nsACString& aOrigin,
+                                           const nsACString& aPattern,
                                            IDBDatabase* aDatabase,
                                            AsyncConnectionHelper* aHelper,
                                            nsIRunnable* aRunnable,
                                            WaitingOnDatabasesCallback aCallback,
                                            void* aClosure)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(!aDatabase || aHelper, "Need a helper with a database!");
   NS_ASSERTION(aDatabase || aRunnable, "Need a runnable without a database!");
 
   // Find the right SynchronizedOp.
   SynchronizedOp* op =
-    FindSynchronizedOp(aOrigin, aDatabase ? aDatabase->Id() : nullptr);
+    FindSynchronizedOp(aPattern, aDatabase ? aDatabase->Id() : nullptr);
 
   NS_ASSERTION(op, "We didn't find a SynchronizedOp?");
   NS_ASSERTION(!op->mHelper, "SynchronizedOp already has a helper?!?");
   NS_ASSERTION(!op->mRunnable, "SynchronizedOp already has a runnable?!?");
 
-  nsTArray<IDBDatabase*>* array;
-  mLiveDatabases.Get(aOrigin, &array);
+  DatabasePatternMatchArray matches;
+  matches.Find(mLiveDatabases, aPattern);
 
   // We need to wait for the databases to go away.
   // Hold on to all database objects that represent the same database file
   // (except the one that is requesting this version change).
   nsTArray<nsRefPtr<IDBDatabase> > liveDatabases;
 
-  if (array) {
+  if (!matches.IsEmpty()) {
     if (aDatabase) {
       // Grab all databases that are not yet closed but whose database id match
       // the one we're looking for.
-      for (uint32_t index = 0; index < array->Length(); index++) {
-        IDBDatabase*& database = array->ElementAt(index);
+      for (uint32_t index = 0; index < matches.Length(); index++) {
+        IDBDatabase*& database = matches[index];
         if (!database->IsClosed() &&
             database != aDatabase &&
             database->Id() == aDatabase->Id()) {
           liveDatabases.AppendElement(database);
         }
       }
     }
     else {
       // We want *all* databases, even those that are closed, if we're going to
       // clear the origin.
-      liveDatabases.AppendElements(*array);
+      liveDatabases.AppendElements(matches);
     }
   }
 
   op->mHelper = aHelper;
   op->mRunnable = aRunnable;
 
   if (!liveDatabases.IsEmpty()) {
     NS_ASSERTION(op->mDatabases.IsEmpty(),
@@ -981,28 +1231,18 @@ IndexedDatabaseManager::GetASCIIOriginFr
   }
 
   nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
   NS_ENSURE_TRUE(sop, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
   NS_ENSURE_TRUE(principal, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-  if (nsContentUtils::IsSystemPrincipal(principal)) {
-    aASCIIOrigin.AssignLiteral("chrome");
-  }
-  else {
-    nsresult rv = principal->GetExtendedOrigin(aASCIIOrigin);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-    if (aASCIIOrigin.EqualsLiteral("null")) {
-      NS_WARNING("IndexedDB databases not allowed for this principal!");
-      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-    }
-  }
+  nsresult rv = GetASCIIOriginFromPrincipal(principal, aASCIIOrigin);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 #ifdef DEBUG
 //static
 bool
 IndexedDatabaseManager::IsMainProcess()
@@ -1048,27 +1288,22 @@ IndexedDatabaseManager::AddFileManager(c
     array = new nsTArray<nsRefPtr<FileManager> >();
     mFileManagers.Put(aOrigin, array);
   }
 
   array->AppendElement(aFileManager);
 }
 
 void
-IndexedDatabaseManager::InvalidateFileManagersForOrigin(
-                                                     const nsACString& aOrigin)
+IndexedDatabaseManager::InvalidateFileManagersForPattern(
+                                                     const nsACString& aPattern)
 {
-  nsTArray<nsRefPtr<FileManager> >* array;
-  if (mFileManagers.Get(aOrigin, &array)) {
-    for (uint32_t i = 0; i < array->Length(); i++) {
-      nsRefPtr<FileManager> fileManager = array->ElementAt(i);
-      fileManager->Invalidate();
-    }
-    mFileManagers.Remove(aOrigin);
-  }
+  NS_ASSERTION(!aPattern.IsEmpty(), "Empty pattern!");
+  mFileManagers.Enumerate(InvalidateAndRemoveFileManagers,
+                          const_cast<nsACString*>(&aPattern));
 }
 
 void
 IndexedDatabaseManager::InvalidateFileManager(const nsACString& aOrigin,
                                               const nsAString& aDatabaseName)
 {
   nsTArray<nsRefPtr<FileManager> >* array;
   if (!mFileManagers.Get(aOrigin, &array)) {
@@ -1168,130 +1403,212 @@ IndexedDatabaseManager::RunSynchronizedO
   if (pool && !pool->WaitForAllDatabasesToComplete(databases, runnable)) {
     NS_WARNING("Failed to wait for databases to complete!");
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
+IndexedDatabaseManager::SynchronizedOp*
+IndexedDatabaseManager::FindSynchronizedOp(const nsACString& aPattern,
+                                           nsIAtom* aId)
+{
+  for (uint32_t index = 0; index < mSynchronizedOps.Length(); index++) {
+    const nsAutoPtr<SynchronizedOp>& currentOp = mSynchronizedOps[index];
+    if (PatternMatchesOrigin(aPattern, currentOp->mOriginOrPattern) &&
+        (!currentOp->mId || currentOp->mId == aId)) {
+      return currentOp;
+    }
+  }
+
+  return nullptr;
+}
+
+nsresult
+IndexedDatabaseManager::ClearDatabasesForApp(uint32_t aAppId, bool aBrowserOnly)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
+               "Bad appId!");
+
+  // This only works from the main process.
+  NS_ENSURE_TRUE(IsMainProcess(), NS_ERROR_NOT_AVAILABLE);
+
+  nsAutoCString pattern;
+  GetOriginPatternStringMaybeIgnoreBrowser(aAppId, aBrowserOnly, pattern);
+
+  // If there is a pending or running clear operation for this app, return
+  // immediately.
+  if (IsClearOriginPending(pattern)) {
+    return NS_OK;
+  }
+
+  OriginOrPatternString oops = OriginOrPatternString::FromPattern(pattern);
+
+  // Queue up the origin clear runnable.
+  nsRefPtr<OriginClearRunnable> runnable = new OriginClearRunnable(oops);
+
+  nsresult rv = WaitForOpenAllowed(oops, nullptr, runnable);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  runnable->AdvanceState();
+
+  // Give the runnable some help by invalidating any databases in the way.
+  DatabasePatternMatchArray matches;
+  matches.Find(mLiveDatabases, pattern);
+
+  for (uint32_t index = 0; index < matches.Length(); index++) {
+    // We need to grab references here to prevent the database from dying while
+    // we invalidate it.
+    nsRefPtr<IDBDatabase> database = matches[index];
+    database->Invalidate();
+  }
+
+  return NS_OK;
+}
+
 NS_IMPL_ISUPPORTS2(IndexedDatabaseManager, nsIIndexedDatabaseManager,
                                            nsIObserver)
 
 NS_IMETHODIMP
 IndexedDatabaseManager::GetUsageForURI(
                                      nsIURI* aURI,
-                                     nsIIndexedDatabaseUsageCallback* aCallback)
+                                     nsIIndexedDatabaseUsageCallback* aCallback,
+                                     uint32_t aAppId,
+                                     bool aInMozBrowserOnly,
+                                     uint8_t aOptionalArgCount)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   NS_ENSURE_ARG_POINTER(aURI);
   NS_ENSURE_ARG_POINTER(aCallback);
 
+  // This only works from the main process.
+  NS_ENSURE_TRUE(IsMainProcess(), NS_ERROR_NOT_AVAILABLE);
+
+  if (!aOptionalArgCount) {
+    aAppId = nsIScriptSecurityManager::NO_APP_ID;
+  }
+
   // Figure out which origin we're dealing with.
   nsCString origin;
-  nsresult rv = nsContentUtils::GetASCIIOrigin(aURI, origin);
+  nsresult rv = GetASCIIOriginFromURI(aURI, aAppId, aInMozBrowserOnly, origin);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  OriginOrPatternString oops = OriginOrPatternString::FromOrigin(origin);
+
   nsRefPtr<AsyncUsageRunnable> runnable =
-    new AsyncUsageRunnable(aURI, origin, aCallback);
+    new AsyncUsageRunnable(aAppId, aInMozBrowserOnly, oops, aURI, aCallback);
 
   nsRefPtr<AsyncUsageRunnable>* newRunnable =
     mUsageRunnables.AppendElement(runnable);
   NS_ENSURE_TRUE(newRunnable, NS_ERROR_OUT_OF_MEMORY);
 
-  // Non-standard URIs can't create databases anyway so fire the callback
-  // immediately.
-  if (origin.EqualsLiteral("null")) {
-    return runnable->TakeShortcut();
-  }
-
   // Otherwise put the computation runnable in the queue.
-  rv = WaitForOpenAllowed(origin, nullptr, runnable);
+  rv = WaitForOpenAllowed(oops, nullptr, runnable);
   NS_ENSURE_SUCCESS(rv, rv);
 
   runnable->AdvanceState();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IndexedDatabaseManager::CancelGetUsageForURI(
                                      nsIURI* aURI,
-                                     nsIIndexedDatabaseUsageCallback* aCallback)
+                                     nsIIndexedDatabaseUsageCallback* aCallback,
+                                     uint32_t aAppId,
+                                     bool aInMozBrowserOnly,
+                                     uint8_t aOptionalArgCount)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   NS_ENSURE_ARG_POINTER(aURI);
   NS_ENSURE_ARG_POINTER(aCallback);
 
+  // This only works from the main process.
+  NS_ENSURE_TRUE(IsMainProcess(), NS_ERROR_NOT_AVAILABLE);
+
+  if (!aOptionalArgCount) {
+    aAppId = nsIScriptSecurityManager::NO_APP_ID;
+  }
+
   // See if one of our pending callbacks matches both the URI and the callback
   // given. Cancel an remove it if so.
   for (uint32_t index = 0; index < mUsageRunnables.Length(); index++) {
     nsRefPtr<AsyncUsageRunnable>& runnable = mUsageRunnables[index];
 
-    bool equals;
-    nsresult rv = runnable->mURI->Equals(aURI, &equals);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    if (equals && SameCOMIdentity(aCallback, runnable->mCallback)) {
-      runnable->Cancel();
-      break;
+    if (runnable->mAppId == aAppId &&
+        runnable->mInMozBrowserOnly == aInMozBrowserOnly) {
+      bool equals;
+      nsresult rv = runnable->mURI->Equals(aURI, &equals);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      if (equals && SameCOMIdentity(aCallback, runnable->mCallback)) {
+        runnable->Cancel();
+        break;
+      }
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
-IndexedDatabaseManager::ClearDatabasesForURI(nsIURI* aURI)
+IndexedDatabaseManager::ClearDatabasesForURI(nsIURI* aURI,
+                                             uint32_t aAppId,
+                                             bool aInMozBrowserOnly,
+                                             uint8_t aOptionalArgCount)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   NS_ENSURE_ARG_POINTER(aURI);
 
+  // This only works from the main process.
+  NS_ENSURE_TRUE(IsMainProcess(), NS_ERROR_NOT_AVAILABLE);
+
+  if (!aOptionalArgCount) {
+    aAppId = nsIScriptSecurityManager::NO_APP_ID;
+  }
+
   // Figure out which origin we're dealing with.
   nsCString origin;
-  nsresult rv = nsContentUtils::GetASCIIOrigin(aURI, origin);
+  nsresult rv = GetASCIIOriginFromURI(aURI, aAppId, aInMozBrowserOnly, origin);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // Non-standard URIs can't create databases anyway, so return immediately.
-  if (origin.EqualsLiteral("null")) {
-    return NS_OK;
-  }
+  nsAutoCString pattern;
+  GetOriginPatternString(aAppId, aInMozBrowserOnly, origin, pattern);
 
   // If there is a pending or running clear operation for this origin, return
   // immediately.
-  if (IsClearOriginPending(origin)) {
+  if (IsClearOriginPending(pattern)) {
     return NS_OK;
   }
 
+  OriginOrPatternString oops = OriginOrPatternString::FromPattern(pattern);
+
   // Queue up the origin clear runnable.
-  nsRefPtr<OriginClearRunnable> runnable = new OriginClearRunnable(origin);
-
-  rv = WaitForOpenAllowed(origin, nullptr, runnable);
+  nsRefPtr<OriginClearRunnable> runnable = new OriginClearRunnable(oops);
+
+  rv = WaitForOpenAllowed(oops, nullptr, runnable);
   NS_ENSURE_SUCCESS(rv, rv);
 
   runnable->AdvanceState();
 
-  // Give the runnable some help by invalidating any databases in the way. We
-  // need to grab references to any live databases here to prevent them from
-  // dying while we invalidate them.
-  nsTArray<nsRefPtr<IDBDatabase> > liveDatabases;
-
-  nsTArray<IDBDatabase*>* array;
-  if (mLiveDatabases.Get(origin, &array)) {
-    liveDatabases.AppendElements(*array);
+  // Give the runnable some help by invalidating any databases in the way.
+  DatabasePatternMatchArray matches;
+  matches.Find(mLiveDatabases, pattern);
+
+  for (uint32_t index = 0; index < matches.Length(); index++) {
+    // We need to grab references to any live databases here to prevent them
+    // from dying while we invalidate them.
+    nsRefPtr<IDBDatabase> database = matches[index];
+    database->Invalidate();
   }
 
-  for (uint32_t index = 0; index < liveDatabases.Length(); index++) {
-    liveDatabases[index]->Invalidate();
-  }
-
-  DatabaseInfo::RemoveAllForOrigin(origin);
-
   // After everything has been invalidated the helper should be dispatched to
   // the end of the event queue.
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IndexedDatabaseManager::Observe(nsISupports* aSubject,
                                 const char* aTopic,
@@ -1356,17 +1673,17 @@ IndexedDatabaseManager::Observe(nsISuppo
       TransactionThreadPool::Shutdown();
 
       // Cancel the timer regardless of whether it actually fired.
       if (NS_FAILED(mShutdownTimer->Cancel())) {
         NS_WARNING("Failed to cancel shutdown timer!");
       }
     }
 
-    mFileManagers.EnumerateRead(InvalidateAllFileManagers, nullptr);
+    mFileManagers.Enumerate(InvalidateAndRemoveFileManagers, nullptr);
 
     if (PR_ATOMIC_SET(&gClosed, 1)) {
       NS_ERROR("Close more than once?!");
     }
 
     return NS_OK;
   }
 
@@ -1387,42 +1704,120 @@ IndexedDatabaseManager::Observe(nsISuppo
       for (uint32_t index = 0; index < count; index++) {
         liveDatabases[index]->Invalidate();
       }
     }
 
     return NS_OK;
   }
 
+  if (!strcmp(aTopic, TOPIC_WEB_APP_CLEAR_DATA)) {
+    nsCOMPtr<mozIApplicationClearPrivateDataParams> params =
+      do_QueryInterface(aSubject);
+    NS_ENSURE_TRUE(params, NS_ERROR_UNEXPECTED);
+
+    uint32_t appId;
+    nsresult rv = params->GetAppId(&appId);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    bool browserOnly;
+    rv = params->GetBrowserOnly(&browserOnly);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = ClearDatabasesForApp(appId, browserOnly);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return NS_OK;
+  }
+
   NS_NOTREACHED("Unknown topic!");
   return NS_ERROR_UNEXPECTED;
 }
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(IndexedDatabaseManager::OriginClearRunnable,
                               nsIRunnable)
 
 // static
 void
 IndexedDatabaseManager::
 OriginClearRunnable::InvalidateOpenedDatabases(
                                    nsTArray<nsRefPtr<IDBDatabase> >& aDatabases,
                                    void* aClosure)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  OriginClearRunnable* self = static_cast<OriginClearRunnable*>(aClosure);
-
   nsTArray<nsRefPtr<IDBDatabase> > databases;
   databases.SwapElements(aDatabases);
 
   for (uint32_t index = 0; index < databases.Length(); index++) {
     databases[index]->Invalidate();
   }
-
-  DatabaseInfo::RemoveAllForOrigin(self->mOrigin);
+}
+
+void
+IndexedDatabaseManager::
+OriginClearRunnable::DeleteFiles(IndexedDatabaseManager* aManager)
+{
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(aManager, "Don't pass me null!");
+
+  nsresult rv;
+
+  nsCOMPtr<nsIFile> directory =
+    do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
+  NS_ENSURE_SUCCESS_VOID(rv);
+
+  rv = directory->InitWithPath(aManager->GetBaseDirectory());
+  NS_ENSURE_SUCCESS_VOID(rv);
+
+  nsCOMPtr<nsISimpleEnumerator> entries;
+  rv = directory->GetDirectoryEntries(getter_AddRefs(entries));
+  NS_ENSURE_SUCCESS_VOID(rv);
+
+  if (!entries) {
+    return;
+  }
+
+  nsCString originSanitized(mOriginOrPattern);
+  SanitizeOriginString(originSanitized);
+
+  bool hasMore;
+  while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
+    nsCOMPtr<nsISupports> entry;
+    rv = entries->GetNext(getter_AddRefs(entry));
+    NS_ENSURE_SUCCESS_VOID(rv);
+
+    nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
+    NS_ASSERTION(file, "Don't know what this is!");
+
+    bool isDirectory;
+    rv = file->IsDirectory(&isDirectory);
+    NS_ENSURE_SUCCESS_VOID(rv);
+
+    if (!isDirectory) {
+      NS_WARNING("Something in the IndexedDB directory that doesn't belong!");
+      continue;
+    }
+
+    nsString leafName;
+    rv = file->GetLeafName(leafName);
+    NS_ENSURE_SUCCESS_VOID(rv);
+
+    // Skip databases for other apps.
+    if (!PatternMatchesOrigin(originSanitized,
+                              NS_ConvertUTF16toUTF8(leafName))) {
+      continue;
+    }
+
+    if (NS_FAILED(file->Remove(true))) {
+      // This should never fail if we've closed all database connections
+      // correctly...
+      NS_ERROR("Failed to remove directory!");
+    }
+  }
 }
 
 NS_IMETHODIMP
 IndexedDatabaseManager::OriginClearRunnable::Run()
 {
   IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
   NS_ASSERTION(mgr, "This should never fail!");
 
@@ -1434,91 +1829,79 @@ IndexedDatabaseManager::OriginClearRunna
 
     case OpenAllowed: {
       NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
       AdvanceState();
 
       // Now we have to wait until the thread pool is done with all of the
       // databases we care about.
-      nsresult rv =
-        mgr->AcquireExclusiveAccess(mOrigin, this, InvalidateOpenedDatabases,
-                                    this);
+      nsresult rv = mgr->AcquireExclusiveAccess(mOriginOrPattern, this,
+                                                InvalidateOpenedDatabases,
+                                                nullptr);
       NS_ENSURE_SUCCESS(rv, rv);
 
       return NS_OK;
     }
 
     case IO: {
       NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
 
       AdvanceState();
 
-      // Remove the directory that contains all our databases.
-      nsCOMPtr<nsIFile> directory;
-      nsresult rv =
-        mgr->GetDirectoryForOrigin(mOrigin, getter_AddRefs(directory));
-      NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to get directory to remove!");
-
-      if (NS_SUCCEEDED(rv)) {
-        bool exists;
-        rv = directory->Exists(&exists);
-        NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
-                         "Failed to check that the directory exists!");
-
-        if (NS_SUCCEEDED(rv) && exists && NS_FAILED(directory->Remove(true))) {
-          // This should never fail if we've closed all database connections
-          // correctly...
-          NS_ERROR("Failed to remove directory!");
-        }
-      }
+      DeleteFiles(mgr);
 
       // Now dispatch back to the main thread.
       if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) {
         NS_WARNING("Failed to dispatch to main thread!");
         return NS_ERROR_FAILURE;
       }
 
       return NS_OK;
     }
 
     case Complete: {
       NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-      mgr->InvalidateFileManagersForOrigin(mOrigin);
+      mgr->InvalidateFileManagersForPattern(mOriginOrPattern);
 
       // Tell the IndexedDatabaseManager that we're done.
-      mgr->AllowNextSynchronizedOp(mOrigin, nullptr);
+      mgr->AllowNextSynchronizedOp(mOriginOrPattern, nullptr);
 
       return NS_OK;
     }
 
     default:
       NS_ERROR("Unknown state value!");
       return NS_ERROR_UNEXPECTED;
   }
 
   NS_NOTREACHED("Should never get here!");
   return NS_ERROR_UNEXPECTED;
 }
 
 IndexedDatabaseManager::AsyncUsageRunnable::AsyncUsageRunnable(
+                                     uint32_t aAppId,
+                                     bool aInMozBrowserOnly,
+                                     const OriginOrPatternString& aOrigin,
                                      nsIURI* aURI,
-                                     const nsACString& aOrigin,
                                      nsIIndexedDatabaseUsageCallback* aCallback)
 : mURI(aURI),
-  mOrigin(aOrigin),
   mCallback(aCallback),
   mUsage(0),
   mFileUsage(0),
+  mAppId(aAppId),
   mCanceled(0),
-  mCallbackState(Pending)
+  mOrigin(aOrigin),
+  mCallbackState(Pending),
+  mInMozBrowserOnly(aInMozBrowserOnly)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aURI, "Null pointer!");
+  NS_ASSERTION(aOrigin.IsOrigin(), "Expect origin only here!");
   NS_ASSERTION(!aOrigin.IsEmpty(), "Empty origin!");
   NS_ASSERTION(aCallback, "Null pointer!");
 }
 
 void
 IndexedDatabaseManager::AsyncUsageRunnable::Cancel()
 {
   if (PR_ATOMIC_SET(&mCanceled, 1)) {
@@ -1607,17 +1990,18 @@ IndexedDatabaseManager::AsyncUsageRunnab
     case Complete: // Fall through
     case Shortcut: {
       NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
       // Call the callback unless we were canceled.
       if (!mCanceled) {
         uint64_t usage = mUsage;
         IncrementUsage(&usage, mFileUsage);
-        mCallback->OnUsageResult(mURI, usage, mFileUsage);
+        mCallback->OnUsageResult(mURI, usage, mFileUsage, mAppId,
+                                 mInMozBrowserOnly);
       }
 
       // Clean up.
       mURI = nullptr;
       mCallback = nullptr;
 
       // And tell the IndexedDatabaseManager that we're done.
       mgr->OnUsageCheckComplete(this);
@@ -1774,49 +2158,67 @@ IndexedDatabaseManager::WaitForLockedFil
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   mBusy = false;
 
   return NS_OK;
 }
 
 IndexedDatabaseManager::
-SynchronizedOp::SynchronizedOp(const nsACString& aOrigin,
+SynchronizedOp::SynchronizedOp(const OriginOrPatternString& aOriginOrPattern,
                                nsIAtom* aId)
-: mOrigin(aOrigin), mId(aId)
+: mOriginOrPattern(aOriginOrPattern), mId(aId)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   MOZ_COUNT_CTOR(IndexedDatabaseManager::SynchronizedOp);
 }
 
 IndexedDatabaseManager::SynchronizedOp::~SynchronizedOp()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   MOZ_COUNT_DTOR(IndexedDatabaseManager::SynchronizedOp);
 }
 
 bool
-IndexedDatabaseManager::SynchronizedOp::MustWaitFor(const SynchronizedOp& aRhs)
-  const
+IndexedDatabaseManager::
+SynchronizedOp::MustWaitFor(const SynchronizedOp& aExistingOp)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
+  bool match;
+
+  if (aExistingOp.mOriginOrPattern.IsOrigin()) {
+    if (mOriginOrPattern.IsOrigin()) {
+      match = aExistingOp.mOriginOrPattern.Equals(mOriginOrPattern);
+    }
+    else {
+      match = PatternMatchesOrigin(mOriginOrPattern, aExistingOp.mOriginOrPattern);
+    }
+  }
+  else if (mOriginOrPattern.IsOrigin()) {
+    match = PatternMatchesOrigin(aExistingOp.mOriginOrPattern, mOriginOrPattern);
+  }
+  else {
+    match = PatternMatchesOrigin(mOriginOrPattern, aExistingOp.mOriginOrPattern) ||
+            PatternMatchesOrigin(aExistingOp.mOriginOrPattern, mOriginOrPattern);
+  }
+
   // If the origins don't match, the second can proceed.
-  if (!aRhs.mOrigin.Equals(mOrigin)) {
+  if (!match) {
     return false;
   }
 
   // If the origins and the ids match, the second must wait.
-  if (aRhs.mId == mId) {
+  if (aExistingOp.mId == mId) {
     return true;
   }
 
   // Waiting is required if either one corresponds to an origin clearing
   // (a null Id).
-  if (!aRhs.mId || !mId) {
+  if (!aExistingOp.mId || !mId) {
     return true;
   }
 
   // Otherwise, things for the same origin but different databases can proceed
   // independently.
   return false;
 }
 
--- a/dom/indexedDB/IndexedDatabaseManager.h
+++ b/dom/indexedDB/IndexedDatabaseManager.h
@@ -52,21 +52,21 @@ public:
   static IndexedDatabaseManager* FactoryCreate();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIINDEXEDDATABASEMANAGER
   NS_DECL_NSIOBSERVER
 
   // Waits for databases to be cleared and for version change transactions to
   // complete before dispatching the given runnable.
-  nsresult WaitForOpenAllowed(const nsACString& aOrigin,
+  nsresult WaitForOpenAllowed(const OriginOrPatternString& aOriginOrPattern,
                               nsIAtom* aId,
                               nsIRunnable* aRunnable);
 
-  void AllowNextSynchronizedOp(const nsACString& aOrigin,
+  void AllowNextSynchronizedOp(const OriginOrPatternString& aOriginOrPattern,
                                nsIAtom* aId);
 
   nsIThread* IOThread()
   {
     NS_ASSERTION(mIOThread, "This should never be null!");
     return mIOThread;
   }
 
@@ -164,17 +164,17 @@ public:
   GetFileManager(const nsACString& aOrigin,
                  const nsAString& aDatabaseName);
 
   void
   AddFileManager(const nsACString& aOrigin,
                  const nsAString& aDatabaseName,
                  FileManager* aFileManager);
 
-  void InvalidateFileManagersForOrigin(const nsACString& aOrigin);
+  void InvalidateFileManagersForPattern(const nsACString& aPattern);
 
   void InvalidateFileManager(const nsACString& aOrigin,
                              const nsAString& aDatabaseName);
 
   nsresult AsyncDeleteFile(FileManager* aFileManager,
                            int64_t aFileId);
 
   const nsString&
@@ -195,17 +195,28 @@ public:
     return mgr->mFileMutex;
   }
 
   static already_AddRefed<nsIAtom>
   GetDatabaseId(const nsACString& aOrigin,
                 const nsAString& aName);
 
   static nsresult
-  FireWindowOnError(nsPIDOMWindow* aOwner, nsEventChainPostVisitor& aVisitor);
+  FireWindowOnError(nsPIDOMWindow* aOwner,
+                    nsEventChainPostVisitor& aVisitor);
+
+  static bool
+  OriginMatchesApp(const nsACString& aOrigin,
+                   uint32_t aAppId);
+
+  static bool
+  OriginMatchesApp(const nsACString& aOrigin,
+                   uint32_t aAppId,
+                   bool aInMozBrowser);
+
 private:
   IndexedDatabaseManager();
   ~IndexedDatabaseManager();
 
   nsresult AcquireExclusiveAccess(const nsACString& aOrigin,
                                   IDBDatabase* aDatabase,
                                   AsyncConnectionHelper* aHelper,
                                   nsIRunnable* aRunnable,
@@ -220,16 +231,18 @@ private:
   bool RegisterDatabase(IDBDatabase* aDatabase);
 
   // Called when a database is being unlinked or destroyed.
   void UnregisterDatabase(IDBDatabase* aDatabase);
 
   // Called when a database has been closed.
   void OnDatabaseClosed(IDBDatabase* aDatabase);
 
+  nsresult ClearDatabasesForApp(uint32_t aAppId, bool aBrowserOnly);
+
   // Responsible for clearing the database files for a particular origin on the
   // IO thread. Created when nsIIDBIndexedDatabaseManager::ClearDatabasesForURI
   // is called. Runs three times, first on the main thread, next on the IO
   // thread, and then finally again on the main thread. While on the IO thread
   // the runnable will actually remove the origin's database files and the
   // directory that contains them before dispatching itself back to the main
   // thread. When back on the main thread the runnable will notify the
   // IndexedDatabaseManager that the job has been completed.
@@ -248,18 +261,18 @@ private:
       // Running on the main thread after all work is done.
       Complete
     };
 
   public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIRUNNABLE
 
-    OriginClearRunnable(const nsACString& aOrigin)
-    : mOrigin(aOrigin),
+    OriginClearRunnable(const OriginOrPatternString& aOriginOrPattern)
+    : mOriginOrPattern(aOriginOrPattern),
       mCallbackState(Pending)
     { }
 
     void AdvanceState()
     {
       switch (mCallbackState) {
         case Pending:
           mCallbackState = OpenAllowed;
@@ -274,18 +287,20 @@ private:
           NS_NOTREACHED("Can't advance past Complete!");
       }
     }
 
     static void InvalidateOpenedDatabases(
                                    nsTArray<nsRefPtr<IDBDatabase> >& aDatabases,
                                    void* aClosure);
 
+    void DeleteFiles(IndexedDatabaseManager* aManager);
+
   private:
-    nsCString mOrigin;
+    OriginOrPatternString mOriginOrPattern;
     CallbackState mCallbackState;
   };
 
   // Responsible for calculating the amount of space taken up by databases of a
   // certain origin. Created when nsIIDBIndexedDatabaseManager::GetUsageForURI
   // is called. May be canceled with
   // nsIIDBIndexedDatabaseManager::CancelGetUsageForURI. Runs twice, first on
   // the IO thread, then again on the main thread. While on the IO thread the
@@ -306,22 +321,25 @@ private:
       IO,
 
       // Running on the main thread after all work is done.
       Complete,
 
       // Running on the main thread after skipping the work
       Shortcut
     };
+
   public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIRUNNABLE
 
-    AsyncUsageRunnable(nsIURI* aURI,
-                       const nsACString& aOrigin,
+    AsyncUsageRunnable(uint32_t aAppId,
+                       bool aInMozBrowserOnly,
+                       const OriginOrPatternString& aOrigin,
+                       nsIURI* aURI,
                        nsIIndexedDatabaseUsageCallback* aCallback);
 
     // Sets the canceled flag so that the callback is never called.
     void Cancel();
 
     void AdvanceState()
     {
       switch (mCallbackState) {
@@ -344,43 +362,45 @@ private:
     // Run calls the RunInternal method and makes sure that we always dispatch
     // to the main thread in case of an error.
     inline nsresult RunInternal();
 
     nsresult GetUsageForDirectory(nsIFile* aDirectory,
                                   uint64_t* aUsage);
 
     nsCOMPtr<nsIURI> mURI;
-    nsCString mOrigin;
-
     nsCOMPtr<nsIIndexedDatabaseUsageCallback> mCallback;
     uint64_t mUsage;
     uint64_t mFileUsage;
+    uint32_t mAppId;
     int32_t mCanceled;
+    OriginOrPatternString mOrigin;
     CallbackState mCallbackState;
+    bool mInMozBrowserOnly;
   };
 
   // Called when AsyncUsageRunnable has finished its Run() method.
   inline void OnUsageCheckComplete(AsyncUsageRunnable* aRunnable);
 
   // A struct that contains the information corresponding to a pending or
   // running operation that requires synchronization (e.g. opening a db,
   // clearing dbs for an origin, etc).
   struct SynchronizedOp
   {
-    SynchronizedOp(const nsACString& aOrigin, nsIAtom* aId);
+    SynchronizedOp(const OriginOrPatternString& aOriginOrPattern,
+                   nsIAtom* aId);
     ~SynchronizedOp();
 
-    // Test whether the second SynchronizedOp needs to get behind this one.
-    bool MustWaitFor(const SynchronizedOp& aRhs) const;
+    // Test whether this SynchronizedOp needs to wait for the given op.
+    bool MustWaitFor(const SynchronizedOp& aOp);
 
     void DelayRunnable(nsIRunnable* aRunnable);
     void DispatchDelayedRunnables();
 
-    const nsCString mOrigin;
+    const OriginOrPatternString mOriginOrPattern;
     nsCOMPtr<nsIAtom> mId;
     nsRefPtr<AsyncConnectionHelper> mHelper;
     nsCOMPtr<nsIRunnable> mRunnable;
     nsTArray<nsCOMPtr<nsIRunnable> > mDelayedRunnables;
     nsTArray<IDBDatabase*> mDatabases;
   };
 
   // A callback runnable used by the TransactionPool when it's safe to proceed
@@ -437,32 +457,22 @@ private:
   private:
     nsRefPtr<FileManager> mFileManager;
     int64_t mFileId;
   };
 
   static nsresult RunSynchronizedOp(IDBDatabase* aDatabase,
                                     SynchronizedOp* aOp);
 
-  SynchronizedOp* FindSynchronizedOp(const nsACString& aOrigin,
-                                     nsIAtom* aId)
+  SynchronizedOp* FindSynchronizedOp(const nsACString& aPattern,
+                                     nsIAtom* aId);
+
+  bool IsClearOriginPending(const nsACString& aPattern)
   {
-    for (uint32_t index = 0; index < mSynchronizedOps.Length(); index++) {
-      const nsAutoPtr<SynchronizedOp>& currentOp = mSynchronizedOps[index];
-      if (currentOp->mOrigin == aOrigin &&
-          (!currentOp->mId || currentOp->mId == aId)) {
-        return currentOp;
-      }
-    }
-    return nullptr;
-  }
-
-  bool IsClearOriginPending(const nsACString& aOrigin)
-  {
-    return !!FindSynchronizedOp(aOrigin, nullptr);
+    return !!FindSynchronizedOp(aPattern, nullptr);
   }
 
   // Maintains a list of live databases per origin.
   nsClassHashtable<nsCStringHashKey, nsTArray<IDBDatabase*> > mLiveDatabases;
 
   // TLS storage index for the current thread's window
   unsigned mCurrentWindowIndex;
 
--- a/dom/indexedDB/Makefile.in
+++ b/dom/indexedDB/Makefile.in
@@ -61,22 +61,23 @@ EXPORTS_mozilla/dom/indexedDB = \
   IndexedDatabaseManager.h \
   Key.h \
   KeyPath.h \
   FileManager.h \
   FileInfo.h \
   $(NULL)
 
 LOCAL_INCLUDES = \
+  -I$(topsrcdir)/caps/include \
+  -I$(topsrcdir)/content/base/src \
+  -I$(topsrcdir)/content/events/src \
   -I$(topsrcdir)/db/sqlite3/src \
-  -I$(topsrcdir)/xpcom/build \
   -I$(topsrcdir)/dom/base \
   -I$(topsrcdir)/dom/src/storage \
-  -I$(topsrcdir)/content/base/src \
-  -I$(topsrcdir)/content/events/src \
+  -I$(topsrcdir)/xpcom/build \
   $(NULL)
 
 DEFINES += -D_IMPL_NS_LAYOUT
 
 # Make sure to quickstub as much as possible here! See
 # js/xpconnect/src/dom_quickstubs.qsconf.
 XPIDLSRCS = \
   nsIIDBCursor.idl \
--- a/dom/indexedDB/OpenDatabaseHelper.cpp
+++ b/dom/indexedDB/OpenDatabaseHelper.cpp
@@ -2013,17 +2013,19 @@ OpenDatabaseHelper::Run()
       DispatchErrorEvent();
     } else {
       DispatchSuccessEvent();
     }
 
     IndexedDatabaseManager* manager = IndexedDatabaseManager::Get();
     NS_ASSERTION(manager, "This should never be null!");
 
-    manager->AllowNextSynchronizedOp(mASCIIOrigin, mDatabaseId);
+    manager->AllowNextSynchronizedOp(
+                                OriginOrPatternString::FromOrigin(mASCIIOrigin),
+                                mDatabaseId);
 
     ReleaseMainThreadObjects();
 
     return NS_OK;
   }
 
   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
 
--- a/dom/indexedDB/ipc/IndexedDBChild.cpp
+++ b/dom/indexedDB/ipc/IndexedDBChild.cpp
@@ -430,16 +430,25 @@ IndexedDBDatabaseChild::RecvVersionChang
   if (NS_FAILED(target.Dispatch(runnable, NS_DISPATCH_NORMAL))) {
     NS_WARNING("Dispatch of versionchange event failed!");
   }
 
   return true;
 }
 
 bool
+IndexedDBDatabaseChild::RecvInvalidate()
+{
+  if (mDatabase) {
+    mDatabase->Invalidate();
+  }
+  return true;
+}
+
+bool
 IndexedDBDatabaseChild::RecvPIndexedDBTransactionConstructor(
                                              PIndexedDBTransactionChild* aActor,
                                              const TransactionParams& aParams)
 {
   // This only happens when the parent has created a version-change transaction
   // for us.
 
   IndexedDBTransactionChild* actor =
@@ -579,19 +588,40 @@ IndexedDBTransactionChild::ActorDestroy(
     mTransaction->SetActor(static_cast<IndexedDBTransactionChild*>(NULL));
 #ifdef DEBUG
     mTransaction = NULL;
 #endif
   }
 }
 
 bool
-IndexedDBTransactionChild::RecvComplete(const nsresult& aRv)
+IndexedDBTransactionChild::RecvComplete(const CompleteParams& aParams)
 {
-  FireCompleteEvent(aRv);
+  MOZ_ASSERT(mTransaction);
+  MOZ_ASSERT(mStrongTransaction);
+
+  nsresult resultCode;
+
+  switch (aParams.type()) {
+    case CompleteParams::TCompleteResult:
+      resultCode = NS_OK;
+      break;
+    case CompleteParams::TAbortResult:
+      resultCode = aParams.get_AbortResult().errorCode();
+      if (NS_SUCCEEDED(resultCode)) {
+        resultCode = NS_ERROR_DOM_INDEXEDDB_ABORT_ERR;
+      }
+      break;
+
+    default:
+      MOZ_NOT_REACHED("Unknown union type!");
+      return false;
+  }
+
+  FireCompleteEvent(resultCode);
   return true;
 }
 
 PIndexedDBObjectStoreChild*
 IndexedDBTransactionChild::AllocPIndexedDBObjectStore(
                                     const ObjectStoreConstructorParams& aParams)
 {
   MOZ_NOT_REACHED("Caller is supposed to manually construct an object store!");
--- a/dom/indexedDB/ipc/IndexedDBChild.h
+++ b/dom/indexedDB/ipc/IndexedDBChild.h
@@ -115,16 +115,19 @@ protected:
   virtual bool
   RecvBlocked(const uint64_t& aOldVersion) MOZ_OVERRIDE;
 
   virtual bool
   RecvVersionChange(const uint64_t& aOldVersion, const uint64_t& aNewVersion)
                     MOZ_OVERRIDE;
 
   virtual bool
+  RecvInvalidate() MOZ_OVERRIDE;
+
+  virtual bool
   RecvPIndexedDBTransactionConstructor(PIndexedDBTransactionChild* aActor,
                                        const TransactionParams& aParams)
                                        MOZ_OVERRIDE;
 
   virtual PIndexedDBTransactionChild*
   AllocPIndexedDBTransaction(const TransactionParams& aParams) MOZ_OVERRIDE;
 
   virtual bool
@@ -158,17 +161,17 @@ public:
 protected:
   void
   FireCompleteEvent(nsresult aRv);
 
   virtual void
   ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
 
   virtual bool
-  RecvComplete(const nsresult& aRv) MOZ_OVERRIDE;
+  RecvComplete(const CompleteParams& aParams) MOZ_OVERRIDE;
 
   virtual PIndexedDBObjectStoreChild*
   AllocPIndexedDBObjectStore(const ObjectStoreConstructorParams& aParams)
                              MOZ_OVERRIDE;
 
   virtual bool
   DeallocPIndexedDBObjectStore(PIndexedDBObjectStoreChild* aActor) MOZ_OVERRIDE;
 };
--- a/dom/indexedDB/ipc/IndexedDBParent.cpp
+++ b/dom/indexedDB/ipc/IndexedDBParent.cpp
@@ -350,17 +350,21 @@ IndexedDBDatabaseParent::HandleRequestEv
     rv = target->AddEventListener(versionChange, mEventListener, false);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (!SendSuccess(*dbInfo, objectStoreInfos)) {
       return NS_ERROR_FAILURE;
     }
 
     MOZ_ASSERT(!mDatabase || mDatabase == databaseConcrete);
-    mDatabase = databaseConcrete;
+
+    if (!mDatabase) {
+      databaseConcrete->SetActor(this);
+      mDatabase = databaseConcrete;
+    }
 
     return NS_OK;
   }
 
   if (aType.EqualsLiteral(UPGRADENEEDED_EVT_STR)) {
     MOZ_ASSERT(!mDatabase);
 
     nsCOMPtr<nsIIDBVersionChangeEvent> changeEvent = do_QueryInterface(aEvent);
@@ -385,16 +389,17 @@ IndexedDBDatabaseParent::HandleRequestEv
     versionChangeParams.osInfo() = objectStoreInfos;
     versionChangeParams.oldVersion() = oldVersion;
 
     if (!SendPIndexedDBTransactionConstructor(actor.forget(),
                                               versionChangeParams)) {
       return NS_ERROR_FAILURE;
     }
 
+    databaseConcrete->SetActor(this);
     mDatabase = databaseConcrete;
 
     return NS_OK;
   }
 
   MOZ_NOT_REACHED("Unexpected message type!");
   return NS_ERROR_UNEXPECTED;
 }
@@ -550,43 +555,42 @@ IndexedDBTransactionParent::SetTransacti
 
 nsresult
 IndexedDBTransactionParent::HandleEvent(nsIDOMEvent* aEvent)
 {
   nsString type;
   nsresult rv = aEvent->GetType(type);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsresult transactionResult;
+  CompleteParams params;
 
   if (type.EqualsLiteral(COMPLETE_EVT_STR)) {
-    transactionResult = NS_OK;
+    params = CompleteResult();
   }
   else if (type.EqualsLiteral(ABORT_EVT_STR)) {
 #ifdef DEBUG
     {
       nsCOMPtr<nsIDOMEventTarget> target;
       if (NS_FAILED(aEvent->GetTarget(getter_AddRefs(target)))) {
         NS_WARNING("Failed to get target!");
       }
       else {
         MOZ_ASSERT(SameCOMIdentity(target, NS_ISUPPORTS_CAST(nsIDOMEventTarget*,
                                                              mTransaction)));
       }
     }
 #endif
-    MOZ_ASSERT(NS_FAILED(mTransaction->GetAbortCode()));
-    transactionResult = mTransaction->GetAbortCode();
+    params = AbortResult(mTransaction->GetAbortCode());
   }
   else {
     NS_WARNING("Unknown message type!");
     return NS_ERROR_UNEXPECTED;
   }
 
-  if (!SendComplete(transactionResult)) {
+  if (!SendComplete(params)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 void
 IndexedDBTransactionParent::ActorDestroy(ActorDestroyReason aWhy)
--- a/dom/indexedDB/ipc/PIndexedDBDatabase.ipdl
+++ b/dom/indexedDB/ipc/PIndexedDBDatabase.ipdl
@@ -53,15 +53,17 @@ child:
   Success(DatabaseInfoGuts dbInfo, ObjectStoreInfoGuts[] osInfo);
 
   Error(nsresult rv);
 
   Blocked(uint64_t oldVersion);
 
   VersionChange(uint64_t oldVersion, uint64_t newVersion);
 
+  Invalidate();
+
 both:
   PIndexedDBTransaction(TransactionParams params);
 };
 
 } // namespace indexedDB
 } // namespace dom
 } // namespace mozilla
--- a/dom/indexedDB/ipc/PIndexedDBTransaction.ipdl
+++ b/dom/indexedDB/ipc/PIndexedDBTransaction.ipdl
@@ -26,16 +26,30 @@ struct GetObjectStoreParams
 };
 
 union ObjectStoreConstructorParams
 {
   CreateObjectStoreParams;
   GetObjectStoreParams;
 };
 
+struct CompleteResult
+{ };
+
+struct AbortResult
+{
+  nsresult errorCode;
+};
+
+union CompleteParams
+{
+  CompleteResult;
+  AbortResult;
+};
+
 } // namespace ipc
 
 protocol PIndexedDBTransaction
 {
   manager PIndexedDBDatabase;
 
   manages PIndexedDBObjectStore;
 
@@ -46,14 +60,14 @@ parent:
 
   Abort(nsresult abortCode);
 
   AllRequestsFinished();
 
   DeleteObjectStore(nsString name);
 
 child:
-  Complete(nsresult rv);
+  Complete(CompleteParams params);
 };
 
 } // namespace indexedDB
 } // namespace dom
 } // namespace mozilla
--- a/dom/indexedDB/nsIIndexedDatabaseManager.idl
+++ b/dom/indexedDB/nsIIndexedDatabaseManager.idl
@@ -3,63 +3,70 @@
 /* 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;
 
-[scriptable, function, uuid(ef1795ec-7050-4658-b80f-0e48cbe1d64b)]
+[scriptable, function, uuid(38f15cc7-2df0-4a90-8b7f-1606b2243522)]
 interface nsIIndexedDatabaseUsageCallback : nsISupports
 {
-  /**
-   *
-   */
   void onUsageResult(in nsIURI aURI,
                      in unsigned long long aUsage,
-                     in unsigned long long aFileUsage);
+                     in unsigned long long aFileUsage,
+                     in unsigned long aAppId,
+                     in boolean aInMozBrowserOnly);
 };
 
-[scriptable, builtinclass, uuid(02256aa7-70d8-473f-bf3b-8cb35d28fd75)]
+[scriptable, builtinclass, uuid(e5168115-baff-4559-887e-7c0405cc9e63)]
 interface nsIIndexedDatabaseManager : nsISupports
 {
   /**
    * Schedules an asynchronous callback that will return the total amount of
    * disk space being used by databases for the given origin.
    *
    * @param aURI
    *        The URI whose usage is being queried.
    * @param aCallback
    *        The callback that will be called when the usage is available.
    */
+  [optional_argc]
   void getUsageForURI(in nsIURI aURI,
-                      in nsIIndexedDatabaseUsageCallback aCallback);
+                      in nsIIndexedDatabaseUsageCallback aCallback,
+                      [optional] in unsigned long aAppId,
+                      [optional] in boolean aInMozBrowserOnly);
 
   /**
    * Cancels an asynchronous usage check initiated by a previous call to
    * getUsageForURI().
    *
    * @param aURI
    *        The URI whose usage is being queried.
    * @param aCallback
    *        The callback that will be called when the usage is available.
    */
+  [optional_argc]
   void cancelGetUsageForURI(in nsIURI aURI,
-                            in nsIIndexedDatabaseUsageCallback aCallback);
-
+                            in nsIIndexedDatabaseUsageCallback aCallback,
+                            [optional] in unsigned long aAppId,
+                            [optional] in boolean aInMozBrowserOnly);
 
   /**
    * Removes all databases stored for the given URI. The files may not be
    * deleted immediately depending on prohibitive concurrent operations.
    *
    * @param aURI
    *        The URI whose databases are to be cleared.
    */
-  void clearDatabasesForURI(in nsIURI aURI);
+  [optional_argc]
+  void clearDatabasesForURI(in nsIURI aURI,
+                            [optional] in unsigned long aAppId,
+                            [optional] in boolean aInMozBrowserOnly);
 
   /**
    * Defines indexedDB and IDBKeyrange with its static functions on 
    * aObject and initializes DOM exception providers if needed.
    *
    * @param aObject
    *        The object, indexedDB and IDBKeyrange should be defined on.
    */
--- a/dom/indexedDB/test/Makefile.in
+++ b/dom/indexedDB/test/Makefile.in
@@ -16,16 +16,18 @@ XPCSHELL_TESTS = unit
 
 MOCHITEST_FILES = \
   bfcache_iframe1.html \
   bfcache_iframe2.html \
   error_events_abort_transactions_iframe.html \
   event_propagation_iframe.html \
   exceptions_in_events_iframe.html \
   file.js \
+  file_app_isolation.html \
+  file_app_isolation.js \
   helpers.js \
   leaving_page_iframe.html \
   test_add_put.html \
   test_add_twice_failure.html \
   test_advance.html \
   test_autoIncrement_indexes.html \
   test_autoIncrement.html \
   test_bfcache.html \
@@ -95,22 +97,23 @@ MOCHITEST_FILES = \
   test_transaction_lifetimes.html \
   test_transaction_lifetimes_nested.html \
   test_transaction_ordering.html \
   test_setVersion.html \
   test_setVersion_abort.html \
   test_setVersion_events.html \
   test_setVersion_exclusion.html \
   test_unique_index_update.html \
+  test_webapp_clearBrowserData.html \
   third_party_iframe1.html \
   third_party_iframe2.html \
   test_app_isolation_inproc.html \
   test_app_isolation_oop.html \
-  file_app_isolation.html \
-  file_app_isolation.js \
+  webapp_clearBrowserData_appFrame.html \
+  webapp_clearBrowserData_browserFrame.html \
   $(NULL)
 
 #   test_writer_starvation.html  disabled for infinite loops, bug 595368
 
 ifeq (browser,$(MOZ_BUILD_APP))
 MOCHITEST_BROWSER_FILES = \
   browser_forgetThisSite.js \
   browser_forgetThisSiteAdd.html \
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/test_webapp_clearBrowserData.html
@@ -0,0 +1,137 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>Indexed Database Clear Browser Data Test</title>
+
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+  <script type="text/javascript;version=1.7">
+    "use strict";
+
+    const appDomain = "example.org";
+    const manifestURL =
+      location.protocol + "//" + appDomain + "/manifest.webapp";
+
+    function testSteps()
+    {
+      const objectStoreName = "foo";
+      const testKey = 1;
+      const testValue = objectStoreName;
+
+      let request = indexedDB.open(window.location.pathname, 1);
+      request.onerror = errorHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
+      request.onsuccess = unexpectedSuccessHandler;
+      let event = yield;
+
+      let db = event.target.result;
+      db.onerror = errorHandler;
+      db.onversionchange = function(event) {
+        event.target.close();
+      }
+
+      let objectStore = db.createObjectStore(objectStoreName);
+      objectStore.add(testValue, testKey);
+
+      request.onsuccess = grabEventAndContinueHandler;
+      event = yield;
+
+      let srcURL =
+        location.protocol + "//" + appDomain +
+        location.pathname.replace("test_webapp_clearBrowserData.html",
+                                  "webapp_clearBrowserData_appFrame.html");
+
+      let iframe = document.createElement("iframe");
+      iframe.setAttribute("mozbrowser", "");
+      iframe.setAttribute("mozapp", manifestURL);
+      iframe.setAttribute("src", srcURL);
+      iframe.setAttribute("remote", "true");
+      iframe.addEventListener("mozbrowsershowmodalprompt", function(event) {
+        let message = JSON.parse(event.detail.message);
+        switch (message.type) {
+          case "info":
+          case "ok":
+            window[message.type].apply(window, message.args);
+            break;
+          case "done":
+            continueToNextStepSync();
+            break;
+          default:
+            throw "unknown message";
+        }
+      });
+
+      info("loading app frame");
+
+      document.body.appendChild(iframe);
+      yield;
+
+      request = indexedDB.open(window.location.pathname, 1);
+      request.onerror = errorHandler;
+      request.onupgradeneeded = unexpectedSuccessHandler;
+      request.onsuccess = grabEventAndContinueHandler;
+      event = yield;
+
+      db = event.target.result;
+      db.onerror = errorHandler;
+
+      objectStore =
+        db.transaction(objectStoreName).objectStore(objectStoreName);
+      objectStore.get(testKey).onsuccess = grabEventAndContinueHandler;
+      event = yield;
+
+      ok(testValue == event.target.result, "data still exists");
+
+      finishTest();
+      yield;
+    }
+
+    function start()
+    {
+      if (!SpecialPowers.isMainProcess()) {
+        todo(false, "Test disabled in child processes, for now");
+        SimpleTest.finish();
+        return;
+      }
+
+      SpecialPowers.addPermission("browser", true, document);
+      SpecialPowers.addPermission("browser", true, { manifestURL: manifestURL,
+                                                     isInBrowserElement: false });
+      SpecialPowers.addPermission("embed-apps", true, document);
+
+      let Webapps = {};
+      SpecialPowers.wrap(Components)
+                   .utils.import("resource://gre/modules/Webapps.jsm", Webapps);
+      let appRegistry = SpecialPowers.wrap(Webapps.DOMApplicationRegistry);
+
+      let originalAllAppsLaunchable = appRegistry.allAppsLaunchable;
+      appRegistry.allAppsLaunchable = true;
+
+      window.addEventListener("unload", function cleanup(event) {
+        if (event.target == document) {
+          window.removeEventListener("unload", cleanup, false);
+
+          SpecialPowers.removePermission("browser", location.href);
+          SpecialPowers.removePermission("browser",
+                                         location.protocol + "//" + appDomain);
+          SpecialPowers.removePermission("embed-apps", location.href);
+          appRegistry.allAppsLaunchable = originalAllAppsLaunchable;
+        }
+      }, false);
+
+      SpecialPowers.pushPrefEnv({
+        "set": [["dom.mozBrowserFramesEnabled", true]]
+      }, runTest);
+    }
+  </script>
+
+  <script type="text/javascript;version=1.7" src="helpers.js"></script>
+</head>
+
+<body onload="start();"></body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/webapp_clearBrowserData_appFrame.html
@@ -0,0 +1,126 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>Indexed Database Clear Browser Data Test</title>
+
+  <script type="text/javascript;version=1.7">
+    "use strict";
+
+    function ok(cond, message)
+    {
+      alert(JSON.stringify({ type: "ok",
+                             args: [!!cond, "appFrame: " + message] }));
+    }
+
+    function info(message)
+    {
+      alert(JSON.stringify({ type: "info",
+                             args: ["appFrame: " + message] }));
+    }
+
+    function finish()
+    {
+      alert(JSON.stringify({ type: "done" }));
+    }
+
+    window.onerror = ok.bind(window, false);
+
+    function testSteps()
+    {
+      const objectStoreName = "foo";
+      const testKey = 1;
+      const testValue = objectStoreName;
+
+      let request = indexedDB.open(window.location.pathname, 1);
+      request.onerror = errorHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
+      request.onsuccess = unexpectedSuccessHandler;
+      let event = yield;
+
+      let db = event.target.result;
+      db.onerror = errorHandler;
+      db.onversionchange = function(event) {
+        event.target.close();
+      }
+
+      let objectStore = db.createObjectStore(objectStoreName);
+      objectStore.add(testValue, testKey);
+
+      request.onsuccess = grabEventAndContinueHandler;
+      event = yield;
+
+      ok(db === event.target.result, "created database");
+
+      objectStore =
+        db.transaction(objectStoreName).objectStore(objectStoreName);
+      objectStore.get(testKey).onsuccess = grabEventAndContinueHandler;
+      event = yield;
+
+      ok(testValue == event.target.result, "data exists");
+
+      let iframe = document.createElement("iframe");
+      iframe.setAttribute("mozbrowser", "");
+      iframe.setAttribute("src", "webapp_clearBrowserData_browserFrame.html");
+      iframe.addEventListener("mozbrowsershowmodalprompt", function(event) {
+        let message = JSON.parse(event.detail.message);
+        switch (message.type) {
+          case "block":
+            info("blocking browserFrame");
+            event.preventDefault();
+
+            let request = navigator.mozApps.getSelf();
+            request.onsuccess = function() {
+              let app = request.result;
+              ok(app, "got app");
+
+              info("clearing browser data");
+              app.clearBrowserData();
+
+              info("unblocking browserFrame");
+              event.detail.unblock();
+            }
+            break;
+          case "done":
+            continueToNextStepSync();
+            break;
+          default:
+            alert(event.detail.message);
+        }
+      });
+
+      info("loading browser frame");
+
+      document.body.appendChild(iframe);
+      yield;
+
+      request = indexedDB.open(window.location.pathname, 1);
+      request.onerror = errorHandler;
+      request.onupgradeneeded = unexpectedSuccessHandler;
+      request.onsuccess = grabEventAndContinueHandler;
+      event = yield;
+
+      db = event.target.result;
+      db.onerror = errorHandler;
+
+      objectStore =
+        db.transaction(objectStoreName).objectStore(objectStoreName);
+      objectStore.get(testKey).onsuccess = grabEventAndContinueHandler;
+      event = yield;
+
+      ok(testValue == event.target.result, "data still exists");
+
+      finish();
+      yield;
+    }
+
+  </script>
+
+  <script type="text/javascript;version=1.7" src="helpers.js"></script>
+</head>
+
+<body onload="testGenerator.next();"></body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/webapp_clearBrowserData_browserFrame.html
@@ -0,0 +1,103 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>Indexed Database Clear Browser Data Test</title>
+
+  <script type="text/javascript;version=1.7">
+    "use strict";
+
+    function ok(cond, message)
+    {
+      alert(JSON.stringify({ type: "ok",
+                             args: [!!cond, "browserFrame: " + message] }));
+    }
+
+    function info(message)
+    {
+      alert(JSON.stringify({ type: "info",
+                             args: ["browserFrame: " + message] }));
+    }
+
+    function block()
+    {
+      info("about to block");
+
+      // This will block until the parent has cleared our database.
+      alert(JSON.stringify({ type: "block" }));
+
+      info("unblocked");
+    }
+
+    function finish()
+    {
+      alert(JSON.stringify({ type: "done" }));
+    }
+
+    window.onerror = ok.bind(window, false);
+
+    function testSteps()
+    {
+      const objectStoreName = "foo";
+      const testKey = 1;
+      const testValue = objectStoreName;
+
+      let request = indexedDB.open(window.location.pathname, 1);
+      request.onerror = errorHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
+      request.onsuccess = unexpectedSuccessHandler;
+      let event = yield;
+
+      let db = event.target.result;
+      db.onerror = errorHandler;
+      db.onversionchange = function(event) {
+        event.target.close();
+      }
+
+      let objectStore = db.createObjectStore(objectStoreName);
+      objectStore.add(testValue, testKey);
+
+      request.onsuccess = grabEventAndContinueHandler;
+      event = yield;
+
+      ok(db === event.target.result, "created database");
+
+      objectStore =
+        db.transaction(objectStoreName).objectStore(objectStoreName);
+      objectStore.get(testKey).onsuccess = grabEventAndContinueHandler;
+      event = yield;
+
+      ok(testValue == event.target.result, "data exists");
+
+      block();
+
+      request = indexedDB.open(window.location.pathname, 1);
+      request.onerror = errorHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
+      request.onsuccess = unexpectedSuccessHandler;
+      event = yield;
+
+      ok(event.type == "upgradeneeded", "db doesn't exist");
+
+      request.onsuccess = grabEventAndContinueHandler;
+      event = yield;
+
+      db = event.target.result;
+      info(db.objectStoreNames.length);
+      ok(!db.objectStoreNames.length, "no object stores");
+
+      finish();
+
+      yield;
+    }
+
+  </script>
+
+  <script type="text/javascript;version=1.7" src="helpers.js"></script>
+</head>
+
+<body onload="testGenerator.next();"></body>
+
+</html>
--- a/dom/interfaces/apps/mozIApplicationClearPrivateDataParams.idl
+++ b/dom/interfaces/apps/mozIApplicationClearPrivateDataParams.idl
@@ -8,8 +8,12 @@
 #include "nsISupports.idl"
 
 [scriptable, uuid(ba0e6c8e-8c03-4b9b-8f9b-4fb14216f56e)]
 interface mozIApplicationClearPrivateDataParams : nsISupports
 {
   readonly attribute unsigned long appId;
   readonly attribute boolean browserOnly;
 };
+
+%{C++
+#define TOPIC_WEB_APP_CLEAR_DATA "webapps-clear-data"
+%}
--- a/dom/interfaces/events/Makefile.in
+++ b/dom/interfaces/events/Makefile.in
@@ -52,16 +52,15 @@ XPIDLSRCS =					\
 	nsIDOMAnimationEvent.idl		\
 	nsIDOMPopStateEvent.idl			\
 	nsIDOMCloseEvent.idl			\
 	nsIDOMTouchEvent.idl			\
 	nsIDOMHashChangeEvent.idl		\
 	nsIDOMCustomEvent.idl			\
 	nsIDOMCompositionEvent.idl		\
 	nsIDOMWheelEvent.idl			\
-	nsIWifiEventInits.idl \
 	$(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
 XPIDL_FLAGS += \
   -I$(topsrcdir)/dom/interfaces/base \
   $(NULL)
--- a/dom/interfaces/events/nsIDOMEvent.idl
+++ b/dom/interfaces/events/nsIDOMEvent.idl
@@ -324,14 +324,10 @@ nsresult
 NS_NewDOMAnimationEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsAnimationEvent* aEvent);
 nsresult
 NS_NewDOMTouchEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsTouchEvent *aEvent);
 nsresult
 NS_NewDOMSmsEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent* aEvent);
 nsresult
 NS_NewDOMMozSettingsEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent* aEvent);
 nsresult
-NS_NewDOMMozWifiStatusChangeEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent* aEvent);
-nsresult
-NS_NewDOMMozWifiConnectionInfoEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent* aEvent);
-nsresult
 NS_NewDOMMozApplicationEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent* aEvent);
 %}
deleted file mode 100644
--- a/dom/interfaces/events/nsIWifiEventInits.idl
+++ /dev/null
@@ -1,24 +0,0 @@
-/* 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"
-#include "nsIDOMEventTarget.idl"
-#include "nsIDOMEvent.idl"
-
-interface nsIVariant;
-
-dictionary MozWifiStatusChangeEventInit : EventInit
-{
-  nsIVariant network;
-  DOMString status;
-};
-
-dictionary MozWifiConnectionInfoEventInit : EventInit
-{
-  nsIVariant network;
-  short signalStrength;
-  short relSignalStrength;
-  long linkSpeed;
-  DOMString ipAddress;
-};
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -879,32 +879,48 @@ TabParent::RecvPIndexedDBConstructor(PIn
 {
   nsRefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::GetOrCreate();
   NS_ENSURE_TRUE(mgr, false);
 
   if (!IndexedDatabaseManager::IsMainProcess()) {
     NS_RUNTIMEABORT("Not supported yet!");
   }
 
+  nsresult rv;
+
+  // XXXbent Need to make sure we have a whitelist for chrome databases!
+
+  // Verify the appID in the origin first.
+  if (mApp && !aASCIIOrigin.EqualsLiteral("chrome")) {
+    uint32_t appId;
+    rv = mApp->GetLocalId(&appId);
+    NS_ENSURE_SUCCESS(rv, false);
+
+    if (!IndexedDatabaseManager::OriginMatchesApp(aASCIIOrigin, appId)) {
+      NS_WARNING("App attempted to open databases that it does not have "
+                 "permission to access!");
+      return false;
+    }
+  }
+
   nsCOMPtr<nsINode> node = do_QueryInterface(GetOwnerElement());
   NS_ENSURE_TRUE(node, false);
 
   nsIDocument* doc = node->GetOwnerDocument();
   NS_ENSURE_TRUE(doc, false);
 
   nsCOMPtr<nsPIDOMWindow> window = doc->GetInnerWindow();
   NS_ENSURE_TRUE(window, false);
 
   ContentParent* contentParent = static_cast<ContentParent*>(Manager());
   NS_ASSERTION(contentParent, "Null manager?!");
 
   nsRefPtr<IDBFactory> factory;
-  nsresult rv =
-    IDBFactory::Create(window, aASCIIOrigin, contentParent,
-                       getter_AddRefs(factory));
+  rv = IDBFactory::Create(window, aASCIIOrigin, contentParent,
+                          getter_AddRefs(factory));
   NS_ENSURE_SUCCESS(rv, false);
 
   if (!factory) {
     *aAllowed = false;
     return true;
   }
 
   IndexedDBParent* actor = static_cast<IndexedDBParent*>(aActor);
new file mode 100644
--- /dev/null
+++ b/dom/media/tests/crashtests/791330.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=791330
+-->
+<head>
+  <meta charset="utf-8">
+  <title>PeerConnection test - operate on closed connection</title>
+  <script type="application/javascript">
+    function finish() {
+      document.documentElement.removeAttribute("class");
+    }
+
+    function runTest() {
+      var pc = mozRTCPeerConnection();
+      pc.close();
+
+      navigator.mozGetUserMedia({audio: true, fake: true}, function (stream) {
+        pc.addStream(stream);
+        pc.createOffer(function (offer) {
+        }, finish);
+      }, function () {});
+    }
+  </script>
+</head>
+
+<body onload="setTimeout(runTest, 100)">
+</body>
+</html>
--- a/dom/media/tests/crashtests/crashtests.list
+++ b/dom/media/tests/crashtests/crashtests.list
@@ -1,3 +1,4 @@
 pref(media.peerconnection.enabled,true) load 780790.html
 pref(media.peerconnection.enabled,true) load 791270.html
 pref(media.peerconnection.enabled,true) load 791278.html
+pref(media.peerconnection.enabled,true) load 791330.html
--- a/dom/permission/PermissionSettings.js
+++ b/dom/permission/PermissionSettings.js
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 function debug(aMsg) {
-  // dump("-*- PermissionSettings.js: " + aMsg + "\n");
+  //dump("-*- PermissionSettings.js: " + aMsg + "\n");
 }
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
@@ -23,19 +23,30 @@ const PERMISSIONSETTINGS_CONTRACTID = "@
 const PERMISSIONSETTINGS_CID        = Components.ID("{18390770-02ab-11e2-a21f-0800200c9a66}");
 const nsIDOMPermissionSettings      = Ci.nsIDOMPermissionSettings;
 
 function PermissionSettings()
 {
   debug("Constructor");
 }
 
-var permissionManager = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager);
-var secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager);
-var appsService = Cc["@mozilla.org/AppsService;1"].getService(Ci.nsIAppsService);
+XPCOMUtils.defineLazyServiceGetter(this,
+                                   "permissionManager",
+                                   "@mozilla.org/permissionmanager;1",
+                                   "nsIPermissionManager");
+
+XPCOMUtils.defineLazyServiceGetter(this,
+                                   "secMan",
+                                   "@mozilla.org/scriptsecuritymanager;1",
+                                   "nsIScriptSecurityManager");
+
+XPCOMUtils.defineLazyServiceGetter(this,
+                                   "appsService",
+                                   "@mozilla.org/AppsService;1",
+                                   "nsIAppsService");
 
 PermissionSettings.prototype = {
   get: function get(aPermission, aManifestURL, aOrigin, aBrowserFlag) {
     debug("Get called with: " + aPermission + ", " + aManifestURL + ", " + aOrigin + ", " + aBrowserFlag);
     let uri = Services.io.newURI(aOrigin, null, null);
     let appID = appsService.getAppLocalIdByManifestURL(aManifestURL);
     let principal = secMan.getAppCodebasePrincipal(uri, appID, aBrowserFlag);
     let result = permissionManager.testExactPermissionFromPrincipal(principal, aPermission);
--- a/dom/permission/PermissionSettings.jsm
+++ b/dom/permission/PermissionSettings.jsm
@@ -1,36 +1,45 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-let DEBUG = 0;
-if (DEBUG)
-  debug = function (s) { dump("-*- PermissionSettings Module: " + s + "\n"); }
-else
-  debug = function (s) {}
+function debug(s) {
+  //dump("-*- PermissionSettings Module: " + s + "\n");
+}
 
 const Cu = Components.utils;
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 let EXPORTED_SYMBOLS = ["PermissionSettingsModule"];
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
                                    "@mozilla.org/parentprocessmessagemanager;1",
                                    "nsIMessageListenerManager");
 
-var permissionManager = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager);
-var secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager);
-var appsService = Cc["@mozilla.org/AppsService;1"].getService(Ci.nsIAppsService);
+XPCOMUtils.defineLazyServiceGetter(this,
+                                   "permissionManager",
+                                   "@mozilla.org/permissionmanager;1",
+                                   "nsIPermissionManager");
+
+XPCOMUtils.defineLazyServiceGetter(this,
+                                   "secMan",
+                                   "@mozilla.org/scriptsecuritymanager;1",
+                                   "nsIScriptSecurityManager");
+
+XPCOMUtils.defineLazyServiceGetter(this,
+                                   "appsService",
+                                   "@mozilla.org/AppsService;1",
+                                   "nsIAppsService");
 
 let PermissionSettingsModule = {
   init: function() {
     debug("Init");
     ppmm.addMessageListener("PermissionSettings:AddPermission", this);
     Services.obs.addObserver(this, "profile-before-change", false);
   },
 
@@ -57,16 +66,39 @@ let PermissionSettingsModule = {
       default:
         dump("Unsupported PermisionSettings Action: " + aData.value +"\n");
         action = Ci.nsIPermissionManager.UNKNOWN_ACTION;
     }
     debug("add: " + aData.origin + " " + appID + " " + action);
     permissionManager.addFromPrincipal(principal, aData.type, action);
   },
 
+  getPermission: function getPermission(aPermission, aManifestURL, aOrigin, aBrowserFlag) {
+    debug("getPermission: " + aPermission + ", " + aManifestURL + ", " + aOrigin);
+    let uri = Services.io.newURI(aOrigin, null, null);
+    let appID = appsService.getAppLocalIdByManifestURL(aManifestURL);
+    let principal = secMan.getAppCodebasePrincipal(uri, appID, aBrowserFlag);
+    let result = permissionManager.testExactPermissionFromPrincipal(principal, aPermission);
+
+    switch (result)
+    {
+      case Ci.nsIPermissionManager.UNKNOWN_ACTION:
+        return "unknown";
+      case Ci.nsIPermissionManager.ALLOW_ACTION:
+        return "allow";
+      case Ci.nsIPermissionManager.DENY_ACTION:
+        return "deny";
+      case Ci.nsIPermissionManager.PROMPT_ACTION:
+        return "prompt";
+      default:
+        dump("Unsupported PermissionSettings Action!\n");
+        return "unknown";
+    }
+  },
+
   observe: function(aSubject, aTopic, aData) {
     ppmm.removeMessageListener("PermissionSettings:AddPermission", this);
     Services.obs.removeObserver(this, "profile-before-change");
     ppmm = null;
   },
 
   receiveMessage: function(aMessage) {
     debug("PermissionSettings::receiveMessage " + aMessage.name);
--- a/dom/src/storage/nsDOMStorage.cpp
+++ b/dom/src/storage/nsDOMStorage.cpp
@@ -326,17 +326,17 @@ nsDOMStorageManager::Observe(nsISupports
     bool browserOnly;
 
     nsresult rv = params->GetAppId(&appId);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = params->GetBrowserOnly(&browserOnly);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    MOZ_ASSERT(appId != nsIScriptSecurityManager::NO_APP_ID);
+    MOZ_ASSERT(appId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
 
     return DOMStorageImpl::gStorageDB->RemoveAllForApp(appId, browserOnly);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/dom/src/storage/nsDOMStoragePersistentDB.cpp
+++ b/dom/src/storage/nsDOMStoragePersistentDB.cpp
@@ -16,16 +16,17 @@
 #include "mozStorageHelper.h"
 #include "mozIStorageService.h"
 #include "mozIStorageBindingParamsArray.h"
 #include "mozIStorageBindingParams.h"
 #include "mozIStorageValueArray.h"
 #include "mozIStorageFunction.h"
 #include "nsNetUtil.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/Telemetry.h"
 
 #include "sampler.h"
 
 using namespace mozilla;
 
 // Temporary tables for a storage scope will be flushed if found older
 // then this time in seconds since the load
 #define TEMP_TABLE_MAX_AGE (10) // seconds
@@ -221,16 +222,18 @@ nsDOMStoragePersistentDB::Close()
 nsresult
 nsDOMStoragePersistentDB::EnsureLoadTemporaryTableForStorage(DOMStorageImpl* aStorage)
 {
   TimeStamp timeStamp;
 
   if (!mTempTableLoads.Get(aStorage->GetScopeDBKey(), &timeStamp)) {
     nsresult rv;
 
+    Telemetry::AutoTimer<Telemetry::LOCALDOMSTORAGE_FETCH_DOMAIN_MS> timer;
+
     rv = MaybeCommitInsertTransaction();
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<mozIStorageStatement> stmt = mStatements.GetCachedStatement(
       "INSERT INTO webappsstore2_temp (scope, key, value, secure, owner) "
         "SELECT scope, key, value, secure, owner FROM webappsstore2 "
         "WHERE scope = :scope "
           "AND NOT EXISTS ( "
@@ -302,41 +305,61 @@ nsDOMStoragePersistentDB::FlushTemporary
   }
 
   return PL_DHASH_REMOVE;
 }
 
 nsresult
 nsDOMStoragePersistentDB::FlushTemporaryTables(bool force)
 {
+  nsCOMPtr<mozIStorageStatement> stmt =
+    mStatements.GetCachedStatement(
+      "SELECT COUNT(*) FROM webappsstore2_temp WHERE modified = 1"
+    );
+  mozStorageStatementScoper scope(stmt);
+
+  TimeStamp startTime;
+  bool exists;
+  int32_t dirtyCount;
+  if (stmt &&
+      NS_SUCCEEDED(stmt->ExecuteStep(&exists)) && exists &&
+      NS_SUCCEEDED(stmt->GetInt32(0, &dirtyCount)) && dirtyCount > 0) {
+    // Time the operation if dirty entries will be flushed
+    startTime = TimeStamp::Now();
+  }
+
   mozStorageTransaction trans(mConnection, false);
-
   nsresult rv;
 
   FlushTemporaryTableData data;
   data.mDB = this;
   data.mForce = force;
   data.mRV = NS_OK;
 
   mTempTableLoads.Enumerate(FlushTemporaryTable, &data);
   NS_ENSURE_SUCCESS(data.mRV, data.mRV);
 
   rv = trans.Commit();
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = MaybeCommitInsertTransaction();
   NS_ENSURE_SUCCESS(rv, rv);
 
+  if (!startTime.IsNull()) {
+    Telemetry::AutoTimer<Telemetry::LOCALDOMSTORAGE_TIMER_FLUSH_MS> timer(startTime);
+  }
+
   return NS_OK;
 }
 
 nsresult
 nsDOMStoragePersistentDB::GetAllKeys(DOMStorageImpl* aStorage,
                                      nsTHashtable<nsSessionStorageEntry>* aKeys)
 {
+  Telemetry::AutoTimer<Telemetry::LOCALDOMSTORAGE_GETALLKEYS_MS> timer;
   nsresult rv;
 
   rv = MaybeCommitInsertTransaction();
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = EnsureLoadTemporaryTableForStorage(aStorage);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -379,16 +402,17 @@ nsDOMStoragePersistentDB::GetAllKeys(DOM
 }
 
 nsresult
 nsDOMStoragePersistentDB::GetKeyValue(DOMStorageImpl* aStorage,
                                       const nsAString& aKey,
                                       nsAString& aValue,
                                       bool* aSecure)
 {
+  Telemetry::AutoTimer<Telemetry::LOCALDOMSTORAGE_GETVALUE_MS> timer;
   SAMPLE_LABEL("nsDOMStoragePersistentDB", "GetKeyValue");
   nsresult rv;
 
   rv = MaybeCommitInsertTransaction();
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = EnsureLoadTemporaryTableForStorage(aStorage);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -430,16 +454,18 @@ nsDOMStoragePersistentDB::GetKeyValue(DO
 }
 
 nsresult
 nsDOMStoragePersistentDB::SetKey(DOMStorageImpl* aStorage,
                                  const nsAString& aKey,
                                  const nsAString& aValue,
                                  bool aSecure)
 {
+  Telemetry::AutoTimer<Telemetry::LOCALDOMSTORAGE_SETVALUE_MS> timer;
+
   nsresult rv;
 
   rv = EnsureLoadTemporaryTableForStorage(aStorage);
   NS_ENSURE_SUCCESS(rv, rv);
 
   int32_t usage = 0;
   if (!aStorage->GetQuotaDBKey().IsEmpty()) {
     rv = GetUsage(aStorage, &usage);
@@ -536,16 +562,17 @@ nsDOMStoragePersistentDB::SetSecure(DOMS
 
   return NS_OK;
 }
 
 nsresult
 nsDOMStoragePersistentDB::RemoveKey(DOMStorageImpl* aStorage,
                                     const nsAString& aKey)
 {
+  Telemetry::AutoTimer<Telemetry::LOCALDOMSTORAGE_REMOVEKEY_MS> timer;
   nsresult rv;
 
   rv = MaybeCommitInsertTransaction();
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<mozIStorageStatement> stmt = mStatements.GetCachedStatement(
     "DELETE FROM webappsstore2_view "
     "WHERE scope = :scope "
@@ -640,16 +667,17 @@ nsDOMStoragePersistentDB::RemoveOwner(co
   MarkAllScopesDirty();
 
   return NS_OK;
 }
 
 nsresult
 nsDOMStoragePersistentDB::RemoveAll()
 {
+  Telemetry::AutoTimer<Telemetry::LOCALDOMSTORAGE_REMOVEALL_MS> timer;
   nsresult rv;
 
   rv = MaybeCommitInsertTransaction();
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<mozIStorageStatement> stmt = mStatements.GetCachedStatement(
     "DELETE FROM webappsstore2_view "
   );
@@ -721,16 +749,18 @@ nsresult
 nsDOMStoragePersistentDB::GetUsageInternal(const nsACString& aQuotaDBKey,
                                            int32_t *aUsage)
 {
   if (aQuotaDBKey == mCachedOwner) {
     *aUsage = mCachedUsage;
     return NS_OK;
   }
 
+  Telemetry::AutoTimer<Telemetry::LOCALDOMSTORAGE_FETCH_QUOTA_USE_MS> timer;
+
   nsresult rv;
 
   rv = MaybeCommitInsertTransaction();
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<mozIStorageStatement> stmt;
   stmt = mStatements.GetCachedStatement(
     "SELECT SUM(LENGTH(key) + LENGTH(value)) "
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -35,16 +35,17 @@ const nsIAudioManager = Ci.nsIAudioManag
 const nsIRadioInterfaceLayer = Ci.nsIRadioInterfaceLayer;
 
 const kNetworkInterfaceStateChangedTopic = "network-interface-state-changed";
 const kSmsReceivedObserverTopic          = "sms-received";
 const kSmsSentObserverTopic              = "sms-sent";
 const kSmsDeliveredObserverTopic         = "sms-delivered";
 const kMozSettingsChangedObserverTopic   = "mozsettings-changed";
 const kSysMsgListenerReadyObserverTopic  = "system-message-listener-ready";
+const kSysClockChangeObserverTopic       = "system-clock-change";
 const kTimeNitzAutomaticUpdateEnabled    = "time.nitz.automatic-update.enabled";
 const DOM_SMS_DELIVERY_RECEIVED          = "received";
 const DOM_SMS_DELIVERY_SENT              = "sent";
 
 const RIL_IPC_TELEPHONY_MSG_NAMES = [
   "RIL:EnumerateCalls",
   "RIL:GetMicrophoneMuted",
   "RIL:SetMicrophoneMuted",
@@ -269,16 +270,17 @@ function RadioInterfaceLayer() {
     ppmm.addMessageListener(msgname, this);
   }
   for (let msgname of RIL_IPC_VOICEMAIL_MSG_NAMES) {
     ppmm.addMessageListener(msgname, this);
   }
   Services.obs.addObserver(this, "xpcom-shutdown", false);
   Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false);
   Services.obs.addObserver(this, kSysMsgListenerReadyObserverTopic, false);
+  Services.obs.addObserver(this, kSysClockChangeObserverTopic, false);
 
   this._sentSmsEnvelopes = {};
 
   this.portAddressedSmsApps = {};
   this.portAddressedSmsApps[WAP.WDP_PORT_PUSH] = this.handleSmsWdpPortPush.bind(this);
 }
 RadioInterfaceLayer.prototype = {
 
@@ -1361,22 +1363,19 @@ RadioInterfaceLayer.prototype = {
    * Handle data call list.
    */
   handleDataCallList: function handleDataCallList(message) {
     this._deliverDataCallCallback("receiveDataCallList",
                                   [message.datacalls, message.datacalls.length]);
   },
 
   /**
-   * Handle the NITZ message.
+   * Set the NITZ message in our system time.
    */
-  handleNitzTime: function handleNitzTime(message) {
-    if (!this._nitzAutomaticUpdateEnabled) {
-      return;
-    }
+  setNitzTime: function setNitzTime(message) {
     // To set the system clock time. Note that there could be a time diff
     // between when the NITZ was received and when the time is actually set.
     gTimeService.set(
       message.networkTimeInMS + (Date.now() - message.receiveTimeInMS));
 
     // To set the sytem timezone. Note that we need to convert the time zone
     // value to a UTC repesentation string in the format of "UTC(+/-)hh:mm".
     // Ex, time zone -480 is "UTC-08:00"; time zone 630 is "UTC+10:30".
@@ -1389,16 +1388,29 @@ RadioInterfaceLayer.prototype = {
       timeZoneStr += (message.networkTimeZoneInMinutes >= 0 ? "+" : "-");
       timeZoneStr += ("0" + Math.floor(absTimeZoneInMinutes / 60)).slice(-2);
       timeZoneStr += ":";
       timeZoneStr += ("0" + absTimeZoneInMinutes % 60).slice(-2);
       gSettingsService.createLock().set("time.timezone", timeZoneStr, null);
     }
   },
 
+  /**
+   * Handle the NITZ message.
+   */
+  handleNitzTime: function handleNitzTime(message) {
+    // Cache the latest NITZ message whenever receiving it.
+    this._lastNitzMessage = message;
+
+    // Set the received NITZ time if the setting is enabled.
+    if (this._nitzAutomaticUpdateEnabled) {
+      this.setNitzTime(message);
+    }
+  },
+
   handleICCInfoChange: function handleICCInfoChange(message) {
     let oldIcc = this.rilContext.icc;
     this.rilContext.icc = message;
    
     let iccInfoChanged = !oldIcc ||
                          oldIcc.iccid != message.iccid ||
                          oldIcc.mcc != message.mcc || 
                          oldIcc.mnc != message.mnc ||
@@ -1413,17 +1425,17 @@ RadioInterfaceLayer.prototype = {
   },
 
   handleICCCardLockResult: function handleICCCardLockResult(message) {
     this._sendRequestResults("RIL:CardLockResult", message);
   },
 
   handleUSSDReceived: function handleUSSDReceived(ussd) {
     debug("handleUSSDReceived " + JSON.stringify(ussd));
-    this._sendMobileConnectionMessage("RIL:UssdReceived", ussd);
+    this._sendMobileConnectionMessage("RIL:USSDReceived", ussd);
   },
 
   handleSendMMI: function handleSendMMI(message) {
     debug("handleSendMMI " + JSON.stringify(message));
     let messageType = message.success ? "RIL:SendMMI:Return:OK" :
                                         "RIL:SendMMI:Return:KO";
     this._sendRequestResults(messageType, message);
   },
@@ -1467,16 +1479,22 @@ RadioInterfaceLayer.prototype = {
         }
         // Shutdown all RIL network interfaces
         this.dataNetworkInterface.shutdown();
         this.mmsNetworkInterface.shutdown();
         this.suplNetworkInterface.shutdown();
         ppmm = null;
         Services.obs.removeObserver(this, "xpcom-shutdown");
         Services.obs.removeObserver(this, kMozSettingsChangedObserverTopic);
+        Services.obs.removeObserver(this, kSysClockChangeObserverTopic);
+        break;
+      case kSysClockChangeObserverTopic:
+        if (this._lastNitzMessage) {
+          this._lastNitzMessage.receiveTimeInMS += parseInt(data, 10);
+        }
         break;
     }
   },
 
   // Flag to determine whether the UI's system app is ready to receive
   // events yet.
   _sysMsgListenerReady: false,
 
@@ -1499,16 +1517,20 @@ RadioInterfaceLayer.prototype = {
   dataCallSettingsSUPL: {},
   _dataCallSettingsToRead: [],
   _oldRilDataEnabledState: null,
 
   // Flag to determine whether to use NITZ. It corresponds to the
   // 'time.nitz.automatic-update.enabled' setting from the UI.
   _nitzAutomaticUpdateEnabled: null,
 
+  // Remember the last NITZ message so that we can set the time based on
+  // the network immediately when users enable network-based time.
+  _lastNitzMessage: null,
+
   // nsISettingsServiceCallback
   handle: function handle(aName, aResult) {
     switch(aName) {
       case "ril.radio.disabled":
         debug("'ril.radio.disabled' is now " + aResult);
         this._radioEnabled = !aResult;
         this._ensureRadioState();
         break;
@@ -1554,16 +1576,21 @@ RadioInterfaceLayer.prototype = {
         this.dataCallSettingsSUPL[key] = aResult;
         break;
       case "ril.callwaiting.enabled":
         this._callWaitingEnabled = aResult;
         this.setCallWaitingEnabled(this._callWaitingEnabled);
         break;
       case kTimeNitzAutomaticUpdateEnabled:
         this._nitzAutomaticUpdateEnabled = aResult;
+
+        // Set the latest cached NITZ time if the setting is enabled.
+        if (this._nitzAutomaticUpdateEnabled && this._lastNitzMessage) {
+          this.setNitzTime(this._lastNitzMessage);
+        }
         break;
     };
   },
 
   handleError: function handleError(aErrorMessage) {
     debug("There was an error while reading RIL settings.");
 
     // Default radio to on.
--- a/dom/time/DateCacheCleaner.cpp
+++ b/dom/time/DateCacheCleaner.cpp
@@ -11,34 +11,30 @@
 #include "mozilla/StaticPtr.h"
 
 using namespace mozilla::hal;
 
 namespace mozilla {
 namespace dom {
 namespace time {
 
-class DateCacheCleaner : public SystemTimeChangeObserver
+class DateCacheCleaner : public SystemTimezoneChangeObserver
 {
 public:
   DateCacheCleaner()
   {
-    RegisterSystemTimeChangeObserver(this);
+    RegisterSystemTimezoneChangeObserver(this);
   }
 
   ~DateCacheCleaner()
   {
-    UnregisterSystemTimeChangeObserver(this);
+    UnregisterSystemTimezoneChangeObserver(this);
   }
-  void Notify(const SystemTimeChange& aReason)
+  void Notify(const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo)
   {
-    if (aReason == SYS_TIME_CHANGE_CLOCK) {
-      return;
-    }
-
     nsCOMPtr<nsIThreadJSContextStack> stack =
       do_GetService("@mozilla.org/js/xpc/ContextStack;1");
     if (!stack) {
       NS_WARNING("Failed to get JSContextStack");
     }
     JSContext *cx = stack->GetSafeJSContext();
     if (!cx) {
       NS_WARNING("Failed to GetSafeJSContext");
--- a/dom/time/TimeChangeObserver.cpp
+++ b/dom/time/TimeChangeObserver.cpp
@@ -4,39 +4,42 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "TimeChangeObserver.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/StaticPtr.h"
 #include "nsPIDOMWindow.h"
 #include "nsDOMEvent.h"
 #include "nsContentUtils.h"
+#include "nsIObserverService.h"
 
+using namespace mozilla;
 using namespace mozilla::hal;
-using namespace mozilla;
+using namespace mozilla::services;
 
 StaticAutoPtr<nsSystemTimeChangeObserver> sObserver;
 
 nsSystemTimeChangeObserver* nsSystemTimeChangeObserver::GetInstance()
 {
   if (!sObserver) {
     sObserver = new nsSystemTimeChangeObserver();
     ClearOnShutdown(&sObserver);
   }
   return sObserver;
 }
 
 nsSystemTimeChangeObserver::~nsSystemTimeChangeObserver()
 {
   mWindowListeners.Clear();
-  UnregisterSystemTimeChangeObserver(this);
+  UnregisterSystemClockChangeObserver(this);
+  UnregisterSystemTimezoneChangeObserver(this);
 }
 
 void
-nsSystemTimeChangeObserver::Notify(const SystemTimeChange& aReason)
+nsSystemTimeChangeObserver::FireMozTimeChangeEvent()
 {
   //Copy mWindowListeners and iterate over windowListeners instead because
   //mWindowListeners may be modified while we loop.
   nsTArray<nsWeakPtr> windowListeners;
   for (uint32_t i = 0; i < mWindowListeners.Length(); i++) {
     windowListeners.AppendElement(mWindowListeners.SafeElementAt(i));
   }
 
@@ -53,16 +56,38 @@ nsSystemTimeChangeObserver::Notify(const
     }
 
     nsContentUtils::DispatchTrustedEvent(document, window,
       NS_LITERAL_STRING("moztimechange"), /* bubbles = */ true,
       /* canceable = */ false);
   }
 }
 
+void
+nsSystemTimeChangeObserver::Notify(const int64_t& aClockDeltaMS)
+{
+  // Notify observers that the system clock has been adjusted.
+  nsCOMPtr<nsIObserverService> observerService = GetObserverService();
+  if (observerService) {
+    nsString dataStr;
+    dataStr.AppendFloat(static_cast<double>(aClockDeltaMS));
+    observerService->NotifyObservers(
+      nullptr, "system-clock-change", dataStr.get());
+  }
+
+  FireMozTimeChangeEvent();
+}
+
+void
+nsSystemTimeChangeObserver::Notify(
+  const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo)
+{
+  FireMozTimeChangeEvent();
+}
+
 nsresult
 nsSystemTimeChangeObserver::AddWindowListener(nsIDOMWindow* aWindow)
 {
   return GetInstance()->AddWindowListenerImpl(aWindow);
 }
 
 nsresult
 nsSystemTimeChangeObserver::AddWindowListenerImpl(nsIDOMWindow* aWindow)
@@ -75,17 +100,18 @@ nsSystemTimeChangeObserver::AddWindowLis
   NS_ASSERTION(windowWeakRef, "nsIDOMWindow implementations shuld support weak ref");
 
   if (mWindowListeners.IndexOf(windowWeakRef) !=
       nsTArray<nsIDOMWindow*>::NoIndex) {
     return NS_OK;
   }
 
   if (mWindowListeners.Length() == 0) {
-    RegisterSystemTimeChangeObserver(sObserver);
+    RegisterSystemClockChangeObserver(sObserver);
+    RegisterSystemTimezoneChangeObserver(sObserver);
   }
 
   mWindowListeners.AppendElement(windowWeakRef);
   return NS_OK;
 }
 
 nsresult
 nsSystemTimeChangeObserver::RemoveWindowListener(nsIDOMWindow* aWindow)
@@ -98,13 +124,14 @@ nsSystemTimeChangeObserver::RemoveWindow
 }
 
 nsresult
 nsSystemTimeChangeObserver::RemoveWindowListenerImpl(nsIDOMWindow* aWindow)
 {
   mWindowListeners.RemoveElement(NS_GetWeakReference(aWindow));
 
   if (mWindowListeners.Length() == 0) {
-    UnregisterSystemTimeChangeObserver(sObserver);
+    UnregisterSystemClockChangeObserver(sObserver);
+    UnregisterSystemTimezoneChangeObserver(sObserver);
   }
 
   return NS_OK;
 }
--- a/dom/time/TimeChangeObserver.h
+++ b/dom/time/TimeChangeObserver.h
@@ -7,26 +7,36 @@
 #define _mozilla_time_change_observer_h_
 
 #include "mozilla/Hal.h"
 #include "mozilla/Observer.h"
 #include "mozilla/HalTypes.h"
 #include "nsPIDOMWindow.h"
 #include "nsWeakPtr.h"
 
-typedef mozilla::Observer<mozilla::hal::SystemTimeChange> SystemTimeChangeObserver;
+typedef mozilla::Observer<int64_t> SystemClockChangeObserver;
+typedef mozilla::Observer<mozilla::hal::SystemTimezoneChangeInformation> SystemTimezoneChangeObserver;
 
-class nsSystemTimeChangeObserver : public SystemTimeChangeObserver
+class nsSystemTimeChangeObserver : public SystemClockChangeObserver,
+                                   public SystemTimezoneChangeObserver
 {
 public:
   static nsSystemTimeChangeObserver* GetInstance();
   virtual ~nsSystemTimeChangeObserver();
-  void Notify(const mozilla::hal::SystemTimeChange& aReason);
+
+  // Implementing hal::SystemClockChangeObserver::Notify()
+  void Notify(const int64_t& aClockDeltaMS);
+
+  // Implementing hal::SystemTimezoneChangeObserver::Notify()
+  void Notify(
+    const mozilla::hal::SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo);
+
   static nsresult AddWindowListener(nsIDOMWindow* aWindow);
   static nsresult RemoveWindowListener(nsIDOMWindow* aWindow);
 private:
   nsresult AddWindowListenerImpl(nsIDOMWindow* aWindow);
   nsresult RemoveWindowListenerImpl(nsIDOMWindow* aWindow);
   nsSystemTimeChangeObserver() { };
   nsTArray<nsWeakPtr> mWindowListeners;
+  void FireMozTimeChangeEvent();
 };
 
 #endif //_mozilla_time_change_observer_h_
--- a/dom/wifi/Makefile.in
+++ b/dom/wifi/Makefile.in
@@ -14,16 +14,18 @@ LIBRARY_NAME     = domwifi_s
 XPIDL_MODULE     = dom_wifi
 LIBXUL_LIBRARY   = 1
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/dom/dom-config.mk
 
 XPIDLSRCS = \
   nsIWifi.idl \
+  nsIDOMMozWifiStatusChangeEvent.idl \
+  nsIDOMMozWifiConnectionInfoEvent.idl \
   $(NULL)
 
 EXTRA_COMPONENTS = \
   WifiWorker.js \
   WifiWorker.manifest \
   DOMWifiManager.js \
   DOMWifiManager.manifest \
   $(NULL)
new file mode 100644
--- /dev/null
+++ b/dom/wifi/nsIDOMMozWifiConnectionInfoEvent.idl
@@ -0,0 +1,55 @@
+/* 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 "nsIDOMEvent.idl"
+
+interface nsIVariant;
+
+[scriptable, builtinclass, uuid(1717f9d9-5fd8-43d8-a098-55924c6d37de)]
+interface nsIDOMMozWifiConnectionInfoEvent : nsIDOMEvent
+{
+    /**
+     * Network object with an SSID field.
+     */
+    readonly attribute nsIVariant network;
+
+    /**
+     * Strength of the signal to network, in dBm between -55 and -100 dBm.
+     */
+    readonly attribute short signalStrength;
+
+    /**
+     * Relative signal strength between 0 and 100.
+     */
+    readonly attribute short relSignalStrength;
+
+    /**
+     * Link speed in Mb/s.
+     */
+    readonly attribute long linkSpeed;
+
+    /**
+     * IP address in the dotted quad format.
+     */
+    readonly attribute DOMString ipAddress;
+
+    [noscript] void initMozWifiConnectionInfoEvent(in DOMString aType,
+                                                   in boolean aCanBubble,
+                                                   in boolean aCancelable,
+                                                   in nsIVariant aNetwork,
+                                                   in short signalStrength,
+                                                   in short relSignalStrength,
+                                                   in long linkSpeed,
+                                                   in DOMString ipAddress);
+};
+
+dictionary MozWifiConnectionInfoEventInit : EventInit
+{
+  nsIVariant network;
+  short signalStrength;
+  short relSignalStrength;
+  long linkSpeed;
+  DOMString ipAddress;
+};
+
new file mode 100644
--- /dev/null
+++ b/dom/wifi/nsIDOMMozWifiStatusChangeEvent.idl
@@ -0,0 +1,35 @@
+/* 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 "nsIDOMEvent.idl"
+
+interface nsIVariant;
+
+[scriptable, builtinclass, uuid(f3ef70b0-b2d3-4eb5-8ea4-008f8d330cd6)]
+interface nsIDOMMozWifiStatusChangeEvent : nsIDOMEvent
+{
+    /**
+     * Network object with a SSID field describing the network affected by
+     * this change. This might be null.
+     */
+    readonly attribute nsIVariant network;
+
+    /**
+     * String describing the current status of the wifi manager. See above for
+     * the possible values.
+     */
+    readonly attribute DOMString status;
+
+    [noscript] void initMozWifiStatusChangeEvent(in DOMString aType,
+                                                 in boolean aCanBubble,
+                                                 in boolean aCancelable,
+                                                 in nsIVariant aNetwork,
+                                                 in DOMString aStatus);
+};
+
+dictionary MozWifiStatusChangeEventInit : EventInit
+{
+  nsIVariant network;
+  DOMString  status;
+};
--- a/dom/wifi/nsIWifi.idl
+++ b/dom/wifi/nsIWifi.idl
@@ -181,68 +181,8 @@ interface nsIDOMWifiManager : nsISupport
 
     /**
      * These two events fire when the wifi system is brought online or taken
      * offline.
      */
     attribute nsIDOMEventListener onenabled;
     attribute nsIDOMEventListener ondisabled;
 };
-
-[scriptable, builtinclass, uuid(f3ef70b0-b2d3-4eb5-8ea4-008f8d330cd6)]
-interface nsIDOMMozWifiStatusChangeEvent : nsIDOMEvent
-{
-    /**
-     * Network object with a SSID field describing the network affected by
-     * this change. This might be null.
-     */
-    readonly attribute nsIVariant network;
-
-    /**
-     * String describing the current status of the wifi manager. See above for
-     * the possible values.
-     */
-    readonly attribute DOMString status;
-
-    [noscript] void initMozWifiStatusChangeEvent(in DOMString aType,
-                                                 in boolean aCanBubble,
-                                                 in boolean aCancelable,
-                                                 in nsIVariant aNetwork,
-                                                 in DOMString status);
-};
-
-[scriptable, builtinclass, uuid(1717f9d9-5fd8-43d8-a098-55924c6d37de)]
-interface nsIDOMMozWifiConnectionInfoEvent : nsIDOMEvent
-{
-    /**
-     * Network object with an SSID field.
-     */
-    readonly attribute nsIVariant network;
-
-    /**
-     * Strength of the signal to network, in dBm between -55 and -100 dBm.
-     */
-    readonly attribute short signalStrength;
-
-    /**
-     * Relative signal strength between 0 and 100.
-     */
-    readonly attribute short relSignalStrength;
-
-    /**
-     * Link speed in Mb/s.
-     */
-    readonly attribute long linkSpeed;
-
-    /**
-     * IP address in the dotted quad format.
-     */
-    readonly attribute DOMString ipAddress;
-
-    [noscript] void initMozWifiConnectionInfoEvent(in DOMString aType,
-                                                   in boolean aCanBubble,
-                                                   in boolean aCancelable,
-                                                   in nsIVariant aNetwork,
-                                                   in short signalStrength,
-                                                   in short relSignalStrength,
-                                                   in long linkSpeed,
-                                                   in DOMString ipAddress);
-};
--- a/gfx/2d/DrawTargetCG.cpp
+++ b/gfx/2d/DrawTargetCG.cpp
@@ -696,19 +696,17 @@ DrawTargetCG::FillGlyphs(ScaledFont *aFo
 
   CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp));
   UnboundnessFixer fixer;
   CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp);
   CGContextSetAlpha(cg, aDrawOptions.mAlpha);
 
   CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform));
 
-  ScaledFontMac* cgFont = static_cast<ScaledFontMac*>(aFont);
-  CGContextSetFont(cg, cgFont->mFont);
-  CGContextSetFontSize(cg, cgFont->mSize);
+  ScaledFontMac* macFont = static_cast<ScaledFontMac*>(aFont);
 
   //XXX: we should use a stack vector here when we have a class like that
   std::vector<CGGlyph> glyphs;
   std::vector<CGPoint> positions;
   glyphs.resize(aBuffer.mNumGlyphs);
   positions.resize(aBuffer.mNumGlyphs);
 
   // Handle the flip
@@ -724,24 +722,42 @@ DrawTargetCG::FillGlyphs(ScaledFont *aFo
     // XXX: CGPointMake might not be inlined
     positions[i] = CGPointMake(aBuffer.mGlyphs[i].mPosition.x,
                               -aBuffer.mGlyphs[i].mPosition.y);
   }
 
   //XXX: CGContextShowGlyphsAtPositions is 10.5+ for older versions use CGContextShowGlyphsWithAdvances
   if (isGradient(aPattern)) {
     CGContextSetTextDrawingMode(cg, kCGTextClip);
-    CGContextShowGlyphsAtPositions(cg, &glyphs.front(), &positions.front(), aBuffer.mNumGlyphs);
+    if (ScaledFontMac::CTFontDrawGlyphsPtr != nullptr) {
+      ScaledFontMac::CTFontDrawGlyphsPtr(macFont->mCTFont, &glyphs.front(),
+                                         &positions.front(),
+                                         aBuffer.mNumGlyphs, cg);
+    } else {
+      CGContextSetFont(cg, macFont->mFont);
+      CGContextSetFontSize(cg, macFont->mSize);
+      CGContextShowGlyphsAtPositions(cg, &glyphs.front(), &positions.front(),
+                                     aBuffer.mNumGlyphs);
+    }
     DrawGradient(cg, aPattern);
   } else {
     //XXX: with CoreGraphics we can stroke text directly instead of going
     // through GetPath. It would be nice to add support for using that
     CGContextSetTextDrawingMode(cg, kCGTextFill);
     SetFillFromPattern(cg, mColorSpace, aPattern);
-    CGContextShowGlyphsAtPositions(cg, &glyphs.front(), &positions.front(), aBuffer.mNumGlyphs);
+    if (ScaledFontMac::CTFontDrawGlyphsPtr != nullptr) {
+      ScaledFontMac::CTFontDrawGlyphsPtr(macFont->mCTFont, &glyphs.front(),
+                                         &positions.front(),
+                                         aBuffer.mNumGlyphs, cg);
+    } else {
+      CGContextSetFont(cg, macFont->mFont);
+      CGContextSetFontSize(cg, macFont->mSize);
+      CGContextShowGlyphsAtPositions(cg, &glyphs.front(), &positions.front(),
+                                     aBuffer.mNumGlyphs);
+    }
   }
 
   fixer.Fix(mCg);
   CGContextRestoreGState(cg);
 }
 
 extern "C" {
 void
--- a/gfx/2d/ScaledFontMac.cpp
+++ b/gfx/2d/ScaledFontMac.cpp
@@ -7,45 +7,68 @@
 #ifdef USE_SKIA
 #include "PathSkia.h"
 #include "skia/SkPaint.h"
 #include "skia/SkPath.h"
 #include "skia/SkTypeface_mac.h"
 #endif
 #include "DrawTargetCG.h"
 #include <vector>
+#include <dlfcn.h>
 
 // prototype for private API
 extern "C" {
 CGPathRef CGFontGetGlyphPath(CGFontRef fontRef, CGAffineTransform *textTransform, int unknown, CGGlyph glyph);
 };
 
 
 namespace mozilla {
 namespace gfx {
 
+ScaledFontMac::CTFontDrawGlyphsFuncT* ScaledFontMac::CTFontDrawGlyphsPtr = nullptr;
+bool ScaledFontMac::sSymbolLookupDone = false;
+
 ScaledFontMac::ScaledFontMac(CGFontRef aFont, Float aSize)
   : ScaledFontBase(aSize)
 {
+  if (!sSymbolLookupDone) {
+    CTFontDrawGlyphsPtr =
+      (CTFontDrawGlyphsFuncT*)dlsym(RTLD_DEFAULT, "CTFontDrawGlyphs");
+    sSymbolLookupDone = true;
+  }
+
   // XXX: should we be taking a reference
   mFont = CGFontRetain(aFont);
+  if (CTFontDrawGlyphsPtr != nullptr) {
+    // only create mCTFont if we're going to be using the CTFontDrawGlyphs API
+    mCTFont = CTFontCreateWithGraphicsFont(aFont, aSize, nullptr, nullptr);
+  } else {
+    mCTFont = nullptr;
+  }
 }
 
 ScaledFontMac::~ScaledFontMac()
 {
+  if (mCTFont) {
+    CFRelease(mCTFont);
+  }
   CGFontRelease(mFont);
 }
 
 #ifdef USE_SKIA
 SkTypeface* ScaledFontMac::GetSkTypeface()
 {
   if (!mTypeface) {
-    CTFontRef fontFace = CTFontCreateWithGraphicsFont(mFont, mSize, nullptr, nullptr);
-    mTypeface = SkCreateTypefaceFromCTFont(fontFace);
-    CFRelease(fontFace);
+    if (mCTFont) {
+      mTypeface = SkCreateTypefaceFromCTFont(mCTFont);
+    } else {
+      CTFontRef fontFace = CTFontCreateWithGraphicsFont(mFont, mSize, nullptr, nullptr);
+      mTypeface = SkCreateTypefaceFromCTFont(fontFace);
+      CFRelease(fontFace);
+    }
   }
   return mTypeface;
 }
 #endif
 
 // private API here are the public options on OS X
 // CTFontCreatePathForGlyph
 // ATSUGlyphGetCubicPaths
--- a/gfx/2d/ScaledFontMac.h
+++ b/gfx/2d/ScaledFontMac.h
@@ -20,17 +20,31 @@ public:
   ScaledFontMac(CGFontRef aFont, Float aSize);
   virtual ~ScaledFontMac();
 
   virtual FontType GetType() const { return FONT_MAC; }
 #ifdef USE_SKIA
   virtual SkTypeface* GetSkTypeface();
 #endif
   virtual TemporaryRef<Path> GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget);
+
 private:
   friend class DrawTargetCG;
   CGFontRef mFont;
+  CTFontRef mCTFont; // only created if CTFontDrawGlyphs is available, otherwise null
+
+  typedef void (CTFontDrawGlyphsFuncT)(CTFontRef,
+                                       const CGGlyph[], const CGPoint[],
+                                       size_t, CGContextRef);
+
+  static bool sSymbolLookupDone;
+
+public:
+  // function pointer for CTFontDrawGlyphs, if available;
+  // initialized the first time a ScaledFontMac is created,
+  // so it will be valid by the time DrawTargetCG wants to use it
+  static CTFontDrawGlyphsFuncT* CTFontDrawGlyphsPtr;
 };
 
 }
 }
 
 #endif /* MOZILLA_GFX_SCALEDFONTMAC_H_ */
--- a/gfx/cairo/README
+++ b/gfx/cairo/README
@@ -211,11 +211,15 @@ pixman-limits.patch: include limits.h fo
 pixman-lowres-interp.patch: Use lower quality interpolation for more speed.
 
 pixman-bilinear-fastpath.patch: Bilinear fast paths for non-neon
 
 pixman-16-bit-pipeline.patch: 16 bit pipeline for dithering
 
 pixman-dither.patch: Add dithering of 16 bit gradients
 
+quartz-support-color-emoji-font.patch: support Apple Color Emoji font in cairo-quartz backend
+
+use-show-text-glyphs-if-glyph-path-fails.patch: fall back to show_text_glyphs even at huge sizes if scaled_font_glyph_path didn't work
+
 ==== disable printing patch ====
 
 disable-printing.patch:  allows us to use NS_PRINTING to disable printing.
--- a/gfx/cairo/cairo/src/cairo-gstate.c
+++ b/gfx/cairo/cairo/src/cairo-gstate.c
@@ -2002,23 +2002,34 @@ cairo_status_t
 	cairo_path_fixed_t path;
 
 	_cairo_path_fixed_init (&path);
 
 	status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
 						transformed_glyphs, num_glyphs,
 						&path);
 
-	if (status == CAIRO_STATUS_SUCCESS) {
+	if (status == CAIRO_STATUS_SUCCESS && !_cairo_path_fixed_fill_is_empty (&path)) {
 	    status = _cairo_surface_fill (gstate->target, op, pattern,
 					  &path,
 					  CAIRO_FILL_RULE_WINDING,
 					  gstate->tolerance,
 					  gstate->scaled_font->options.antialias,
 					  _gstate_get_clip (gstate, &clip));
+	} else {
+	    /* if _cairo_scaled_font_glyph_path() failed, maybe the font doesn't support
+	     * returning paths, so try the _cairo_surface_show_text_glyphs() option
+	     */
+	    status = _cairo_surface_show_text_glyphs (gstate->target, op, pattern,
+						      utf8, utf8_len,
+						      transformed_glyphs, num_glyphs,
+						      transformed_clusters, num_clusters,
+						      cluster_flags,
+						      gstate->scaled_font,
+						      _gstate_get_clip (gstate, &clip));
 	}
 
 	_cairo_path_fixed_fini (&path);
     }
 
     _cairo_clip_fini (&clip);
 
 CLEANUP_GLYPHS:
--- a/gfx/cairo/cairo/src/cairo-quartz-font.c
+++ b/gfx/cairo/cairo/src/cairo-quartz-font.c
@@ -85,16 +85,20 @@ typedef struct {
     int descent;
     int leading;
 } quartz_CGFontMetrics;
 static quartz_CGFontMetrics* (*CGFontGetHMetricsPtr) (CGFontRef fontRef) = NULL;
 static int (*CGFontGetAscentPtr) (CGFontRef fontRef) = NULL;
 static int (*CGFontGetDescentPtr) (CGFontRef fontRef) = NULL;
 static int (*CGFontGetLeadingPtr) (CGFontRef fontRef) = NULL;
 
+/* CTFontCreateWithGraphicsFont is not public until 10.5. */
+typedef const struct __CTFontDescriptor *CTFontDescriptorRef;
+static CTFontRef (*CTFontCreateWithGraphicsFontPtr) (CGFontRef, CGFloat, const CGAffineTransform *, CTFontDescriptorRef) = NULL;
+
 static cairo_bool_t _cairo_quartz_font_symbol_lookup_done = FALSE;
 static cairo_bool_t _cairo_quartz_font_symbols_present = FALSE;
 
 static void
 quartz_font_ensure_symbols(void)
 {
     if (_cairo_quartz_font_symbol_lookup_done)
 	return;
@@ -122,16 +126,18 @@ quartz_font_ensure_symbols(void)
     CGFontGetHMetricsPtr = dlsym(RTLD_DEFAULT, "CGFontGetHMetrics");
     CGFontGetAscentPtr = dlsym(RTLD_DEFAULT, "CGFontGetAscent");
     CGFontGetDescentPtr = dlsym(RTLD_DEFAULT, "CGFontGetDescent");
     CGFontGetLeadingPtr = dlsym(RTLD_DEFAULT, "CGFontGetLeading");
 
     CGContextGetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing");
     CGContextSetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing");
 
+    CTFontCreateWithGraphicsFontPtr = dlsym(RTLD_DEFAULT, "CTFontCreateWithGraphicsFont");
+
     if ((CGFontCreateWithFontNamePtr || CGFontCreateWithNamePtr) &&
 	CGFontGetGlyphBBoxesPtr &&
 	CGFontGetGlyphsForUnicharsPtr &&
 	CGFontGetUnitsPerEmPtr &&
 	CGFontGetGlyphAdvancesPtr &&
 	CGFontGetGlyphPathPtr &&
 	(CGFontGetHMetricsPtr || (CGFontGetAscentPtr && CGFontGetDescentPtr && CGFontGetLeadingPtr)))
 	_cairo_quartz_font_symbols_present = TRUE;
@@ -145,16 +151,17 @@ typedef struct _cairo_quartz_scaled_font
 struct _cairo_quartz_scaled_font {
     cairo_scaled_font_t base;
 };
 
 struct _cairo_quartz_font_face {
     cairo_font_face_t base;
 
     CGFontRef cgFont;
+    CTFontRef ctFont;
 };
 
 /*
  * font face backend
  */
 
 static cairo_status_t
 _cairo_quartz_font_face_create_for_toy (cairo_toy_font_face_t   *toy_face,
@@ -229,16 +236,20 @@ static cairo_status_t
     return CAIRO_STATUS_SUCCESS;
 }
 
 static void
 _cairo_quartz_font_face_destroy (void *abstract_face)
 {
     cairo_quartz_font_face_t *font_face = (cairo_quartz_font_face_t*) abstract_face;
 
+    if (font_face->ctFont) {
+        CFRelease (font_face->ctFont);
+    }
+
     CGFontRelease (font_face->cgFont);
 }
 
 static const cairo_scaled_font_backend_t _cairo_quartz_scaled_font_backend;
 
 static cairo_status_t
 _cairo_quartz_font_face_scaled_font_create (void *abstract_face,
 					    const cairo_matrix_t *font_matrix,
@@ -353,16 +364,22 @@ cairo_quartz_font_face_create_for_cgfont
     if (!font_face) {
 	cairo_status_t ignore_status;
 	ignore_status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	return (cairo_font_face_t *)&_cairo_font_face_nil;
     }
 
     font_face->cgFont = CGFontRetain (font);
 
+    if (CTFontCreateWithGraphicsFontPtr) {
+        font_face->ctFont = CTFontCreateWithGraphicsFontPtr (font, 1.0, NULL, NULL);
+    } else {
+        font_face->ctFont = NULL;
+    }
+
     _cairo_font_face_init (&font_face->base, &_cairo_quartz_font_face_backend);
 
     return &font_face->base;
 }
 
 /*
  * scaled font backend
  */
@@ -772,16 +789,24 @@ static const cairo_scaled_font_backend_t
 CGFontRef
 _cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *abstract_font)
 {
     cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(abstract_font);
 
     return ffont->cgFont;
 }
 
+CTFontRef
+_cairo_quartz_scaled_font_get_ct_font_ref (cairo_scaled_font_t *abstract_font)
+{
+    cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(abstract_font);
+
+    return ffont->ctFont;
+}
+
 #ifndef __LP64__
 /*
  * compat with old ATSUI backend
  */
 
 /**
  * cairo_quartz_font_face_create_for_atsu_font_id
  * @font_id: an ATSUFontID for the font.
--- a/gfx/cairo/cairo/src/cairo-quartz-private.h
+++ b/gfx/cairo/cairo/src/cairo-quartz-private.h
@@ -45,16 +45,19 @@
 #include "cairo-surface-clipper-private.h"
 
 #ifdef CGFLOAT_DEFINED
 typedef CGFloat cairo_quartz_float_t;
 #else
 typedef float cairo_quartz_float_t;
 #endif
 
+/* define CTFontRef for pre-10.5 SDKs */
+typedef const struct __CTFont *CTFontRef;
+
 typedef struct cairo_quartz_surface {
     cairo_surface_t base;
 
     CGContextRef cgContext;
     CGAffineTransform cgContextBaseCTM;
 
     void *imageData;
     cairo_surface_t *imageSurfaceEquiv;
@@ -99,15 +102,18 @@ CGImageRef
 			      cairo_bool_t interpolate,
 			      CGColorSpaceRef colorSpaceOverride,
 			      CGDataProviderReleaseDataCallback releaseCallback,
 			      void *releaseInfo);
 
 CGFontRef
 _cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *sfont);
 
+CTFontRef
+_cairo_quartz_scaled_font_get_ct_font_ref (cairo_scaled_font_t *sfont);
+
 #else
 
 # error Cairo was not compiled with support for the quartz backend
 
 #endif /* CAIRO_HAS_QUARTZ_SURFACE */
 
 #endif /* CAIRO_QUARTZ_PRIVATE_H */
--- a/gfx/cairo/cairo/src/cairo-quartz-surface.c
+++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c
@@ -130,16 +130,19 @@ static void (*CGContextClipToMaskPtr) (C
 static void (*CGContextDrawTiledImagePtr) (CGContextRef, CGRect, CGImageRef) = NULL;
 static unsigned int (*CGContextGetTypePtr) (CGContextRef) = NULL;
 static void (*CGContextSetShouldAntialiasFontsPtr) (CGContextRef, bool) = NULL;
 static void (*CGContextSetAllowsFontSmoothingPtr) (CGContextRef, bool) = NULL;
 static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL;
 static CGPathRef (*CGContextCopyPathPtr) (CGContextRef) = NULL;
 static CGFloat (*CGContextGetAlphaPtr) (CGContextRef) = NULL;
 
+/* CTFontDrawGlyphs is not available until 10.7 */
+static void (*CTFontDrawGlyphsPtr) (CTFontRef, const CGGlyph[], const CGPoint[], size_t, CGContextRef) = NULL;
+
 static SInt32 _cairo_quartz_osx_version = 0x0;
 
 static cairo_bool_t _cairo_quartz_symbol_lookup_done = FALSE;
 
 /*
  * Utility functions
  */
 
@@ -167,16 +170,18 @@ static void quartz_ensure_symbols(void)
     CGContextDrawTiledImagePtr = dlsym(RTLD_DEFAULT, "CGContextDrawTiledImage");
     CGContextGetTypePtr = dlsym(RTLD_DEFAULT, "CGContextGetType");
     CGContextSetShouldAntialiasFontsPtr = dlsym(RTLD_DEFAULT, "CGContextSetShouldAntialiasFonts");
     CGContextCopyPathPtr = dlsym(RTLD_DEFAULT, "CGContextCopyPath");
     CGContextGetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing");
     CGContextSetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing");
     CGContextGetAlphaPtr = dlsym(RTLD_DEFAULT, "CGContextGetAlpha");
 
+    CTFontDrawGlyphsPtr = dlsym(RTLD_DEFAULT, "CTFontDrawGlyphs");
+
     if (Gestalt(gestaltSystemVersion, &_cairo_quartz_osx_version) != noErr) {
         // assume 10.5
         _cairo_quartz_osx_version = 0x1050;
     }
 
     _cairo_quartz_symbol_lookup_done = TRUE;
 }
 
@@ -605,20 +610,23 @@ static inline void
     dst->d = src->yy;
     dst->tx = src->x0;
     dst->ty = src->y0;
 }
 
 typedef struct {
     bool isClipping;
     CGGlyph *cg_glyphs;
-    CGSize *cg_advances;
+    union {
+      CGSize *cg_advances;
+      CGPoint *cg_positions;
+    } u;
     size_t nglyphs;
     CGAffineTransform textTransform;
-    CGFontRef font;
+    cairo_scaled_font_t *scaled_font;
     CGPoint origin;
 } unbounded_show_glyphs_t;
 
 typedef struct {
     CGPathRef cgPath;
     cairo_fill_rule_t fill_rule;
 } unbounded_stroke_fill_t;
 
@@ -686,36 +694,43 @@ static void
 	CGContextBeginPath (cgc);
 	CGContextAddPath (cgc, op->u.stroke_fill.cgPath);
 
 	if (op->u.stroke_fill.fill_rule == CAIRO_FILL_RULE_WINDING)
 	    CGContextFillPath (cgc);
 	else
 	    CGContextEOFillPath (cgc);
     } else if (op->op == UNBOUNDED_SHOW_GLYPHS) {
-	CGContextSetFont (cgc, op->u.show_glyphs.font);
-	CGContextSetFontSize (cgc, 1.0);
-	CGContextSetTextMatrix (cgc, CGAffineTransformIdentity);
-	CGContextTranslateCTM (cgc, op->u.show_glyphs.origin.x, op->u.show_glyphs.origin.y);
-	CGContextConcatCTM (cgc, op->u.show_glyphs.textTransform);
-
 	if (op->u.show_glyphs.isClipping) {
 	    /* Note that the comment in show_glyphs about kCGTextClip
 	     * and the text transform still applies here; however, the
 	     * cg_advances we have were already transformed, so we
 	     * don't have to do anything. */
 	    CGContextSetTextDrawingMode (cgc, kCGTextClip);
 	    CGContextSaveGState (cgc);
 	}
-
-	CGContextShowGlyphsWithAdvances (cgc,
-					 op->u.show_glyphs.cg_glyphs,
-					 op->u.show_glyphs.cg_advances,
-					 op->u.show_glyphs.nglyphs);
-
+        CGContextTranslateCTM (cgc, op->u.show_glyphs.origin.x, op->u.show_glyphs.origin.y);
+        CGContextConcatCTM (cgc, op->u.show_glyphs.textTransform);
+        if (CTFontDrawGlyphsPtr) {
+            CTFontDrawGlyphsPtr (_cairo_quartz_scaled_font_get_ct_font_ref (op->u.show_glyphs.scaled_font),
+                                 op->u.show_glyphs.cg_glyphs,
+                                 op->u.show_glyphs.u.cg_positions,
+                                 op->u.show_glyphs.nglyphs,
+                                 cgc);
+        } else {
+	    CGContextSetFont (cgc, _cairo_quartz_scaled_font_get_cg_font_ref (op->u.show_glyphs.scaled_font));
+	    CGContextSetFontSize (cgc, 1.0);
+	    CGContextSetTextMatrix (cgc, CGAffineTransformIdentity);
+
+	    CGContextShowGlyphsWithAdvances (cgc,
+					     op->u.show_glyphs.cg_glyphs,
+					     op->u.show_glyphs.u.cg_advances,
+					     op->u.show_glyphs.nglyphs);
+
+        }
 	if (op->u.show_glyphs.isClipping) {
 	    CGContextClearRect (cgc, clipBoxRound);
 	    CGContextRestoreGState (cgc);
 	}
     } else if (op->op == UNBOUNDED_MASK) {
 	CGAffineTransform ctm = CGContextGetCTM (cgc);
 	CGContextSaveGState (cgc);
 	CGContextConcatCTM (cgc, op->u.mask.maskTransform);
@@ -2684,16 +2699,19 @@ static cairo_int_status_t
 				      cairo_clip_t *clip,
 				      int *remaining_glyphs)
 {
     CGAffineTransform textTransform, ctm, invTextTransform;
 #define STATIC_BUF_SIZE 64
     CGGlyph glyphs_static[STATIC_BUF_SIZE];
     CGSize cg_advances_static[STATIC_BUF_SIZE];
     CGGlyph *cg_glyphs = &glyphs_static[0];
+    /* We'll use the cg_advances array for either advances or positions,
+       depending which API we're using to actually draw. The types involved
+       have the same size, so this is safe. */
     CGSize *cg_advances = &cg_advances_static[0];
 
     cairo_rectangle_int_t glyph_extents;
     cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
     cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
     cairo_quartz_drawing_state_t state;
     cairo_quartz_float_t xprev, yprev;
     int i;
@@ -2796,41 +2814,62 @@ static cairo_int_status_t
     invTextTransform = CGAffineTransformMake (scaled_font->scale_inverse.xx,
 					      -scaled_font->scale_inverse.yx,
 					      scaled_font->scale_inverse.xy,
 					      -scaled_font->scale_inverse.yy,
 					      0.0, 0.0);
 
     CGContextSetTextMatrix (state.context, CGAffineTransformIdentity);
 
-    /* Convert our glyph positions to glyph advances.  We need n-1 advances,
-     * since the advance at index 0 is applied after glyph 0. */
-    xprev = glyphs[0].x;
-    yprev = glyphs[0].y;
-
-    cg_glyphs[0] = glyphs[0].index;
-
-    for (i = 1; i < num_glyphs; i++) {
-	cairo_quartz_float_t xf = glyphs[i].x;
-	cairo_quartz_float_t yf = glyphs[i].y;
-	cg_glyphs[i] = glyphs[i].index;
-	cg_advances[i - 1] = CGSizeApplyAffineTransform(CGSizeMake (xf - xprev, yf - yprev), invTextTransform);
-	xprev = xf;
-	yprev = yf;
-    }
-
     /* Translate to the first glyph's position before drawing */
     ctm = CGContextGetCTM (state.context);
     CGContextTranslateCTM (state.context, glyphs[0].x, glyphs[0].y);
     CGContextConcatCTM (state.context, textTransform);
 
-    CGContextShowGlyphsWithAdvances (state.context,
-				     cg_glyphs,
-				     cg_advances,
-				     num_glyphs);
+    if (CTFontDrawGlyphsPtr) {
+        /* If CTFontDrawGlyphs is available (i.e. OS X 10.7 or later), we want to use
+         * that in preference to CGContextShowGlyphsWithAdvances so that colored-bitmap
+         * fonts like Apple Color Emoji will render properly.
+         * For this, we need to convert our glyph positions to Core Graphics's CGPoint.
+         * We borrow the cg_advances array, as CGPoint and CGSize are the same size. */
+
+        CGPoint *cg_positions = (CGPoint*) cg_advances;
+        cairo_quartz_float_t origin_x = glyphs[0].x;
+        cairo_quartz_float_t origin_y = glyphs[0].y;
+
+        for (i = 0; i < num_glyphs; i++) {
+            CGPoint pt = CGPointMake (glyphs[i].x - origin_x, glyphs[i].y - origin_y);
+            cg_positions[i] = CGPointApplyAffineTransform (pt, invTextTransform);
+            cg_glyphs[i] = glyphs[i].index;
+        }
+
+        CTFontDrawGlyphsPtr (_cairo_quartz_scaled_font_get_ct_font_ref (scaled_font),
+                             cg_glyphs, cg_positions, num_glyphs, state.context);
+    } else {
+        /* Convert our glyph positions to glyph advances.  We need n-1 advances,
+         * since the advance at index 0 is applied after glyph 0. */
+        xprev = glyphs[0].x;
+        yprev = glyphs[0].y;
+
+        cg_glyphs[0] = glyphs[0].index;
+
+        for (i = 1; i < num_glyphs; i++) {
+	    cairo_quartz_float_t xf = glyphs[i].x;
+	    cairo_quartz_float_t yf = glyphs[i].y;
+	    cg_glyphs[i] = glyphs[i].index;
+	    cg_advances[i - 1] = CGSizeApplyAffineTransform(CGSizeMake (xf - xprev, yf - yprev), invTextTransform);
+	    xprev = xf;
+	    yprev = yf;
+        }
+
+        CGContextShowGlyphsWithAdvances (state.context,
+				         cg_glyphs,
+				         cg_advances,
+				         num_glyphs);
+    }
 
     CGContextSetCTM (state.context, ctm);
 
     if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE ||
         state.action == DO_LAYER) {
 	_cairo_quartz_draw_image (&state, op);
     } else if (state.action == DO_SHADING) {
 	CGContextConcatCTM (state.context, state.transform);
@@ -2847,20 +2886,27 @@ BAIL:
 	cgfref &&
 	!_cairo_operator_bounded_by_mask (op))
     {
 	unbounded_op_data_t ub;
 	ub.op = UNBOUNDED_SHOW_GLYPHS;
 
 	ub.u.show_glyphs.isClipping = isClipping;
 	ub.u.show_glyphs.cg_glyphs = cg_glyphs;
-	ub.u.show_glyphs.cg_advances = cg_advances;
+	if (CTFontDrawGlyphsPtr) {
+	    /* we're using Core Text API: the cg_advances array was
+	       reused (above) for glyph positions */
+            CGPoint *cg_positions = (CGPoint*) cg_advances;
+	    ub.u.show_glyphs.u.cg_positions = cg_positions;
+	} else {
+	    ub.u.show_glyphs.u.cg_advances = cg_advances;
+	}
 	ub.u.show_glyphs.nglyphs = num_glyphs;
 	ub.u.show_glyphs.textTransform = textTransform;
-	ub.u.show_glyphs.font = cgfref;
+	ub.u.show_glyphs.scaled_font = scaled_font;
 	ub.u.show_glyphs.origin = CGPointMake (glyphs[0].x, glyphs[0].y);
 
 	_cairo_quartz_fixup_unbounded_operation (surface, &ub, scaled_font->options.antialias);
     }
 
 
     if (cg_advances != &cg_advances_static[0]) {
 	free (cg_advances);
new file mode 100644
--- /dev/null
+++ b/gfx/cairo/quartz-support-color-emoji-font.patch
@@ -0,0 +1,432 @@
+From: Jonathan Kew <jkew@mozilla.com>
+bug 715798 pt 1 - support Apple Color Emoji font in cairo-quartz backend. r=jrmuizel
+
+diff --git a/gfx/cairo/cairo/src/cairo-quartz-font.c b/gfx/cairo/cairo/src/cairo-quartz-font.c
+--- a/gfx/cairo/cairo/src/cairo-quartz-font.c
++++ b/gfx/cairo/cairo/src/cairo-quartz-font.c
+@@ -85,16 +85,20 @@ typedef struct {
+     int descent;
+     int leading;
+ } quartz_CGFontMetrics;
+ static quartz_CGFontMetrics* (*CGFontGetHMetricsPtr) (CGFontRef fontRef) = NULL;
+ static int (*CGFontGetAscentPtr) (CGFontRef fontRef) = NULL;
+ static int (*CGFontGetDescentPtr) (CGFontRef fontRef) = NULL;
+ static int (*CGFontGetLeadingPtr) (CGFontRef fontRef) = NULL;
+ 
++/* CTFontCreateWithGraphicsFont is not public until 10.5. */
++typedef const struct __CTFontDescriptor *CTFontDescriptorRef;
++static CTFontRef (*CTFontCreateWithGraphicsFontPtr) (CGFontRef, CGFloat, const CGAffineTransform *, CTFontDescriptorRef) = NULL;
++
+ static cairo_bool_t _cairo_quartz_font_symbol_lookup_done = FALSE;
+ static cairo_bool_t _cairo_quartz_font_symbols_present = FALSE;
+ 
+ static void
+ quartz_font_ensure_symbols(void)
+ {
+     if (_cairo_quartz_font_symbol_lookup_done)
+ 	return;
+@@ -122,16 +126,18 @@ quartz_font_ensure_symbols(void)
+     CGFontGetHMetricsPtr = dlsym(RTLD_DEFAULT, "CGFontGetHMetrics");
+     CGFontGetAscentPtr = dlsym(RTLD_DEFAULT, "CGFontGetAscent");
+     CGFontGetDescentPtr = dlsym(RTLD_DEFAULT, "CGFontGetDescent");
+     CGFontGetLeadingPtr = dlsym(RTLD_DEFAULT, "CGFontGetLeading");
+ 
+     CGContextGetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing");
+     CGContextSetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing");
+ 
++    CTFontCreateWithGraphicsFontPtr = dlsym(RTLD_DEFAULT, "CTFontCreateWithGraphicsFont");
++
+     if ((CGFontCreateWithFontNamePtr || CGFontCreateWithNamePtr) &&
+ 	CGFontGetGlyphBBoxesPtr &&
+ 	CGFontGetGlyphsForUnicharsPtr &&
+ 	CGFontGetUnitsPerEmPtr &&
+ 	CGFontGetGlyphAdvancesPtr &&
+ 	CGFontGetGlyphPathPtr &&
+ 	(CGFontGetHMetricsPtr || (CGFontGetAscentPtr && CGFontGetDescentPtr && CGFontGetLeadingPtr)))
+ 	_cairo_quartz_font_symbols_present = TRUE;
+@@ -145,16 +151,17 @@ typedef struct _cairo_quartz_scaled_font
+ struct _cairo_quartz_scaled_font {
+     cairo_scaled_font_t base;
+ };
+ 
+ struct _cairo_quartz_font_face {
+     cairo_font_face_t base;
+ 
+     CGFontRef cgFont;
++    CTFontRef ctFont;
+ };
+ 
+ /*
+  * font face backend
+  */
+ 
+ static cairo_status_t
+ _cairo_quartz_font_face_create_for_toy (cairo_toy_font_face_t   *toy_face,
+@@ -229,16 +236,20 @@ static cairo_status_t
+     return CAIRO_STATUS_SUCCESS;
+ }
+ 
+ static void
+ _cairo_quartz_font_face_destroy (void *abstract_face)
+ {
+     cairo_quartz_font_face_t *font_face = (cairo_quartz_font_face_t*) abstract_face;
+ 
++    if (font_face->ctFont) {
++        CFRelease (font_face->ctFont);
++    }
++
+     CGFontRelease (font_face->cgFont);
+ }
+ 
+ static const cairo_scaled_font_backend_t _cairo_quartz_scaled_font_backend;
+ 
+ static cairo_status_t
+ _cairo_quartz_font_face_scaled_font_create (void *abstract_face,
+ 					    const cairo_matrix_t *font_matrix,
+@@ -353,16 +364,22 @@ cairo_quartz_font_face_create_for_cgfont
+     if (!font_face) {
+ 	cairo_status_t ignore_status;
+ 	ignore_status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ 	return (cairo_font_face_t *)&_cairo_font_face_nil;
+     }
+ 
+     font_face->cgFont = CGFontRetain (font);
+ 
++    if (CTFontCreateWithGraphicsFontPtr) {
++        font_face->ctFont = CTFontCreateWithGraphicsFontPtr (font, 1.0, NULL, NULL);
++    } else {
++        font_face->ctFont = NULL;
++    }
++
+     _cairo_font_face_init (&font_face->base, &_cairo_quartz_font_face_backend);
+ 
+     return &font_face->base;
+ }
+ 
+ /*
+  * scaled font backend
+  */
+@@ -772,16 +789,24 @@ static const cairo_scaled_font_backend_t
+ CGFontRef
+ _cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *abstract_font)
+ {
+     cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(abstract_font);
+ 
+     return ffont->cgFont;
+ }
+ 
++CTFontRef
++_cairo_quartz_scaled_font_get_ct_font_ref (cairo_scaled_font_t *abstract_font)
++{
++    cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(abstract_font);
++
++    return ffont->ctFont;
++}
++
+ #ifndef __LP64__
+ /*
+  * compat with old ATSUI backend
+  */
+ 
+ /**
+  * cairo_quartz_font_face_create_for_atsu_font_id
+  * @font_id: an ATSUFontID for the font.
+diff --git a/gfx/cairo/cairo/src/cairo-quartz-private.h b/gfx/cairo/cairo/src/cairo-quartz-private.h
+--- a/gfx/cairo/cairo/src/cairo-quartz-private.h
++++ b/gfx/cairo/cairo/src/cairo-quartz-private.h
+@@ -45,16 +45,19 @@
+ #include "cairo-surface-clipper-private.h"
+ 
+ #ifdef CGFLOAT_DEFINED
+ typedef CGFloat cairo_quartz_float_t;
+ #else
+ typedef float cairo_quartz_float_t;
+ #endif
+ 
++/* define CTFontRef for pre-10.5 SDKs */
++typedef const struct __CTFont *CTFontRef;
++
+ typedef struct cairo_quartz_surface {
+     cairo_surface_t base;
+ 
+     CGContextRef cgContext;
+     CGAffineTransform cgContextBaseCTM;
+ 
+     void *imageData;
+     cairo_surface_t *imageSurfaceEquiv;
+@@ -99,15 +102,18 @@ CGImageRef
+ 			      cairo_bool_t interpolate,
+ 			      CGColorSpaceRef colorSpaceOverride,
+ 			      CGDataProviderReleaseDataCallback releaseCallback,
+ 			      void *releaseInfo);
+ 
+ CGFontRef
+ _cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *sfont);
+ 
++CTFontRef
++_cairo_quartz_scaled_font_get_ct_font_ref (cairo_scaled_font_t *sfont);
++
+ #else
+ 
+ # error Cairo was not compiled with support for the quartz backend
+ 
+ #endif /* CAIRO_HAS_QUARTZ_SURFACE */
+ 
+ #endif /* CAIRO_QUARTZ_PRIVATE_H */
+diff --git a/gfx/cairo/cairo/src/cairo-quartz-surface.c b/gfx/cairo/cairo/src/cairo-quartz-surface.c
+--- a/gfx/cairo/cairo/src/cairo-quartz-surface.c
++++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c
+@@ -130,16 +130,19 @@ static void (*CGContextClipToMaskPtr) (C
+ static void (*CGContextDrawTiledImagePtr) (CGContextRef, CGRect, CGImageRef) = NULL;
+ static unsigned int (*CGContextGetTypePtr) (CGContextRef) = NULL;
+ static void (*CGContextSetShouldAntialiasFontsPtr) (CGContextRef, bool) = NULL;
+ static void (*CGContextSetAllowsFontSmoothingPtr) (CGContextRef, bool) = NULL;
+ static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL;
+ static CGPathRef (*CGContextCopyPathPtr) (CGContextRef) = NULL;
+ static CGFloat (*CGContextGetAlphaPtr) (CGContextRef) = NULL;
+ 
++/* CTFontDrawGlyphs is not available until 10.7 */
++static void (*CTFontDrawGlyphsPtr) (CTFontRef, const CGGlyph[], const CGPoint[], size_t, CGContextRef) = NULL;
++
+ static SInt32 _cairo_quartz_osx_version = 0x0;
+ 
+ static cairo_bool_t _cairo_quartz_symbol_lookup_done = FALSE;
+ 
+ /*
+  * Utility functions
+  */
+ 
+@@ -167,16 +170,18 @@ static void quartz_ensure_symbols(void)
+     CGContextDrawTiledImagePtr = dlsym(RTLD_DEFAULT, "CGContextDrawTiledImage");
+     CGContextGetTypePtr = dlsym(RTLD_DEFAULT, "CGContextGetType");
+     CGContextSetShouldAntialiasFontsPtr = dlsym(RTLD_DEFAULT, "CGContextSetShouldAntialiasFonts");
+     CGContextCopyPathPtr = dlsym(RTLD_DEFAULT, "CGContextCopyPath");
+     CGContextGetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing");
+     CGContextSetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing");
+     CGContextGetAlphaPtr = dlsym(RTLD_DEFAULT, "CGContextGetAlpha");
+ 
++    CTFontDrawGlyphsPtr = dlsym(RTLD_DEFAULT, "CTFontDrawGlyphs");
++
+     if (Gestalt(gestaltSystemVersion, &_cairo_quartz_osx_version) != noErr) {
+         // assume 10.5
+         _cairo_quartz_osx_version = 0x1050;
+     }
+ 
+     _cairo_quartz_symbol_lookup_done = TRUE;
+ }
+ 
+@@ -605,20 +610,23 @@ static inline void
+     dst->d = src->yy;
+     dst->tx = src->x0;
+     dst->ty = src->y0;
+ }
+ 
+ typedef struct {
+     bool isClipping;
+     CGGlyph *cg_glyphs;
+-    CGSize *cg_advances;
++    union {
++      CGSize *cg_advances;
++      CGPoint *cg_positions;
++    } u;
+     size_t nglyphs;
+     CGAffineTransform textTransform;
+-    CGFontRef font;
++    cairo_scaled_font_t *scaled_font;
+     CGPoint origin;
+ } unbounded_show_glyphs_t;
+ 
+ typedef struct {
+     CGPathRef cgPath;
+     cairo_fill_rule_t fill_rule;
+ } unbounded_stroke_fill_t;
+ 
+@@ -686,36 +694,43 @@ static void
+ 	CGContextBeginPath (cgc);
+ 	CGContextAddPath (cgc, op->u.stroke_fill.cgPath);
+ 
+ 	if (op->u.stroke_fill.fill_rule == CAIRO_FILL_RULE_WINDING)
+ 	    CGContextFillPath (cgc);
+ 	else
+ 	    CGContextEOFillPath (cgc);
+     } else if (op->op == UNBOUNDED_SHOW_GLYPHS) {
+-	CGContextSetFont (cgc, op->u.show_glyphs.font);
+-	CGContextSetFontSize (cgc, 1.0);
+-	CGContextSetTextMatrix (cgc, CGAffineTransformIdentity);
+-	CGContextTranslateCTM (cgc, op->u.show_glyphs.origin.x, op->u.show_glyphs.origin.y);
+-	CGContextConcatCTM (cgc, op->u.show_glyphs.textTransform);
+-
+ 	if (op->u.show_glyphs.isClipping) {
+ 	    /* Note that the comment in show_glyphs about kCGTextClip
+ 	     * and the text transform still applies here; however, the
+ 	     * cg_advances we have were already transformed, so we
+ 	     * don't have to do anything. */
+ 	    CGContextSetTextDrawingMode (cgc, kCGTextClip);
+ 	    CGContextSaveGState (cgc);
+ 	}
+-
+-	CGContextShowGlyphsWithAdvances (cgc,
+-					 op->u.show_glyphs.cg_glyphs,
+-					 op->u.show_glyphs.cg_advances,
+-					 op->u.show_glyphs.nglyphs);
+-
++        CGContextTranslateCTM (cgc, op->u.show_glyphs.origin.x, op->u.show_glyphs.origin.y);
++        CGContextConcatCTM (cgc, op->u.show_glyphs.textTransform);
++        if (CTFontDrawGlyphsPtr) {
++            CTFontDrawGlyphsPtr (_cairo_quartz_scaled_font_get_ct_font_ref (op->u.show_glyphs.scaled_font),
++                                 op->u.show_glyphs.cg_glyphs,
++                                 op->u.show_glyphs.u.cg_positions,
++                                 op->u.show_glyphs.nglyphs,
++                                 cgc);
++        } else {
++	    CGContextSetFont (cgc, _cairo_quartz_scaled_font_get_cg_font_ref (op->u.show_glyphs.scaled_font));
++	    CGContextSetFontSize (cgc, 1.0);
++	    CGContextSetTextMatrix (cgc, CGAffineTransformIdentity);
++
++	    CGContextShowGlyphsWithAdvances (cgc,
++					     op->u.show_glyphs.cg_glyphs,
++					     op->u.show_glyphs.u.cg_advances,
++					     op->u.show_glyphs.nglyphs);
++
++        }
+ 	if (op->u.show_glyphs.isClipping) {
+ 	    CGContextClearRect (cgc, clipBoxRound);
+ 	    CGContextRestoreGState (cgc);
+ 	}
+     } else if (op->op == UNBOUNDED_MASK) {
+ 	CGAffineTransform ctm = CGContextGetCTM (cgc);
+ 	CGContextSaveGState (cgc);
+ 	CGContextConcatCTM (cgc, op->u.mask.maskTransform);
+@@ -2684,16 +2699,19 @@ static cairo_int_status_t
+ 				      cairo_clip_t *clip,
+ 				      int *remaining_glyphs)
+ {
+     CGAffineTransform textTransform, ctm, invTextTransform;
+ #define STATIC_BUF_SIZE 64
+     CGGlyph glyphs_static[STATIC_BUF_SIZE];
+     CGSize cg_advances_static[STATIC_BUF_SIZE];
+     CGGlyph *cg_glyphs = &glyphs_static[0];
++    /* We'll use the cg_advances array for either advances or positions,
++       depending which API we're using to actually draw. The types involved
++       have the same size, so this is safe. */
+     CGSize *cg_advances = &cg_advances_static[0];
+ 
+     cairo_rectangle_int_t glyph_extents;
+     cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
+     cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
+     cairo_quartz_drawing_state_t state;
+     cairo_quartz_float_t xprev, yprev;
+     int i;
+@@ -2796,41 +2814,62 @@ static cairo_int_status_t
+     invTextTransform = CGAffineTransformMake (scaled_font->scale_inverse.xx,
+ 					      -scaled_font->scale_inverse.yx,
+ 					      scaled_font->scale_inverse.xy,
+ 					      -scaled_font->scale_inverse.yy,
+ 					      0.0, 0.0);
+ 
+     CGContextSetTextMatrix (state.context, CGAffineTransformIdentity);
+ 
+-    /* Convert our glyph positions to glyph advances.  We need n-1 advances,
+-     * since the advance at index 0 is applied after glyph 0. */
+-    xprev = glyphs[0].x;
+-    yprev = glyphs[0].y;
+-
+-    cg_glyphs[0] = glyphs[0].index;
+-
+-    for (i = 1; i < num_glyphs; i++) {
+-	cairo_quartz_float_t xf = glyphs[i].x;
+-	cairo_quartz_float_t yf = glyphs[i].y;
+-	cg_glyphs[i] = glyphs[i].index;
+-	cg_advances[i - 1] = CGSizeApplyAffineTransform(CGSizeMake (xf - xprev, yf - yprev), invTextTransform);
+-	xprev = xf;
+-	yprev = yf;
+-    }
+-
+     /* Translate to the first glyph's position before drawing */
+     ctm = CGContextGetCTM (state.context);
+     CGContextTranslateCTM (state.context, glyphs[0].x, glyphs[0].y);
+     CGContextConcatCTM (state.context, textTransform);
+ 
+-    CGContextShowGlyphsWithAdvances (state.context,
+-				     cg_glyphs,
+-				     cg_advances,
+-				     num_glyphs);
++    if (CTFontDrawGlyphsPtr) {
++        /* If CTFontDrawGlyphs is available (i.e. OS X 10.7 or later), we want to use
++         * that in preference to CGContextShowGlyphsWithAdvances so that colored-bitmap
++         * fonts like Apple Color Emoji will render properly.
++         * For this, we need to convert our glyph positions to Core Graphics's CGPoint.
++         * We borrow the cg_advances array, as CGPoint and CGSize are the same size. */
++
++        CGPoint *cg_positions = (CGPoint*) cg_advances;
++        cairo_quartz_float_t origin_x = glyphs[0].x;
++        cairo_quartz_float_t origin_y = glyphs[0].y;
++
++        for (i = 0; i < num_glyphs; i++) {
++            CGPoint pt = CGPointMake (glyphs[i].x - origin_x, glyphs[i].y - origin_y);
++            cg_positions[i] = CGPointApplyAffineTransform (pt, invTextTransform);
++            cg_glyphs[i] = glyphs[i].index;
++        }
++
++        CTFontDrawGlyphsPtr (_cairo_quartz_scaled_font_get_ct_font_ref (scaled_font),
++                             cg_glyphs, cg_positions, num_glyphs, state.context);
++    } else {
++        /* Convert our glyph positions to glyph advances.  We need n-1 advances,
++         * since the advance at index 0 is applied after glyph 0. */
++        xprev = glyphs[0].x;
++        yprev = glyphs[0].y;
++
++        cg_glyphs[0] = glyphs[0].index;
++
++        for (i = 1; i < num_glyphs; i++) {
++	    cairo_quartz_float_t xf = glyphs[i].x;
++	    cairo_quartz_float_t yf = glyphs[i].y;
++	    cg_glyphs[i] = glyphs[i].index;
++	    cg_advances[i - 1] = CGSizeApplyAffineTransform(CGSizeMake (xf - xprev, yf - yprev), invTextTransform);
++	    xprev = xf;
++	    yprev = yf;
++        }
++
++        CGContextShowGlyphsWithAdvances (state.context,
++				         cg_glyphs,
++				         cg_advances,
++				         num_glyphs);
++    }
+ 
+     CGContextSetCTM (state.context, ctm);
+ 
+     if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE ||
+         state.action == DO_LAYER) {
+ 	_cairo_quartz_draw_image (&state, op);
+     } else if (state.action == DO_SHADING) {
+ 	CGContextConcatCTM (state.context, state.transform);
+@@ -2847,20 +2886,27 @@ BAIL:
+ 	cgfref &&
+ 	!_cairo_operator_bounded_by_mask (op))
+     {
+ 	unbounded_op_data_t ub;
+ 	ub.op = UNBOUNDED_SHOW_GLYPHS;
+ 
+ 	ub.u.show_glyphs.isClipping = isClipping;
+ 	ub.u.show_glyphs.cg_glyphs = cg_glyphs;
+-	ub.u.show_glyphs.cg_advances = cg_advances;
++	if (CTFontDrawGlyphsPtr) {
++	    /* we're using Core Text API: the cg_advances array was
++	       reused (above) for glyph positions */
++            CGPoint *cg_positions = (CGPoint*) cg_advances;
++	    ub.u.show_glyphs.u.cg_positions = cg_positions;
++	} else {
++	    ub.u.show_glyphs.u.cg_advances = cg_advances;
++	}
+ 	ub.u.show_glyphs.nglyphs = num_glyphs;
+ 	ub.u.show_glyphs.textTransform = textTransform;
+-	ub.u.show_glyphs.font = cgfref;
++	ub.u.show_glyphs.scaled_font = scaled_font;
+ 	ub.u.show_glyphs.origin = CGPointMake (glyphs[0].x, glyphs[0].y);
+ 
+ 	_cairo_quartz_fixup_unbounded_operation (surface, &ub, scaled_font->options.antialias);
+     }
+ 
+ 
+     if (cg_advances != &cg_advances_static[0]) {
+ 	free (cg_advances);
new file mode 100644
--- /dev/null
+++ b/gfx/cairo/use-show-text-glyphs-if-glyph-path-fails.patch
@@ -0,0 +1,42 @@
+From: Jonathan Kew <jkew@mozilla.com>
+bug 715798 pt 2 - fall back to show_text_glyphs even at huge sizes if scaled_font_glyph_path didn't work. r=jrmuizel
+
+diff --git a/gfx/cairo/cairo/src/cairo-gstate.c b/gfx/cairo/cairo/src/cairo-gstate.c
+--- a/gfx/cairo/cairo/src/cairo-gstate.c
++++ b/gfx/cairo/cairo/src/cairo-gstate.c
+@@ -2002,23 +2002,34 @@ cairo_status_t
+ 	cairo_path_fixed_t path;
+ 
+ 	_cairo_path_fixed_init (&path);
+ 
+ 	status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
+ 						transformed_glyphs, num_glyphs,
+ 						&path);
+ 
+-	if (status == CAIRO_STATUS_SUCCESS) {
++	if (status == CAIRO_STATUS_SUCCESS && !_cairo_path_fixed_fill_is_empty (&path)) {
+ 	    status = _cairo_surface_fill (gstate->target, op, pattern,
+ 					  &path,
+ 					  CAIRO_FILL_RULE_WINDING,
+ 					  gstate->tolerance,
+ 					  gstate->scaled_font->options.antialias,
+ 					  _gstate_get_clip (gstate, &clip));
++	} else {
++	    /* if _cairo_scaled_font_glyph_path() failed, maybe the font doesn't support
++	     * returning paths, so try the _cairo_surface_show_text_glyphs() option
++	     */
++	    status = _cairo_surface_show_text_glyphs (gstate->target, op, pattern,
++						      utf8, utf8_len,
++						      transformed_glyphs, num_glyphs,
++						      transformed_clusters, num_clusters,
++						      cluster_flags,
++						      gstate->scaled_font,
++						      _gstate_get_clip (gstate, &clip));
+ 	}
+ 
+ 	_cairo_path_fixed_fini (&path);
+     }
+ 
+     _cairo_clip_fini (&clip);
+ 
+ CLEANUP_GLYPHS:
--- a/gfx/layers/basic/BasicTiledThebesLayer.cpp
+++ b/gfx/layers/basic/BasicTiledThebesLayer.cpp
@@ -405,17 +405,20 @@ BasicTiledThebesLayer::PaintThebes(gfxCo
     for (ContainerLayer* parent = GetParent(); parent; parent = parent->GetParent()) {
       if (parent->UseIntermediateSurface()) {
         transform.PreMultiply(parent->GetEffectiveTransform());
       }
     }
     transform.Invert();
 
     // Store the old valid region, then clear it before painting.
+    // We clip the old valid region to the visible region, as it only gets
+    // used to decide stale content (currently valid and previously visible)
     nsIntRegion oldValidRegion = mTiledBuffer.GetValidRegion();
+    oldValidRegion.And(oldValidRegion, mVisibleRegion);
     mTiledBuffer.ClearPaintedRegion();
 
     // Make sure that tiles that fall outside of the visible region are
     // discarded on the first update.
     if (!BasicManager()->IsRepeatTransaction()) {
       mValidRegion.And(mValidRegion, mVisibleRegion);
     }
 
@@ -448,18 +451,24 @@ BasicTiledThebesLayer::PaintThebes(gfxCo
         } else {
           return;
         }
       }
 
       // Keep track of what we're about to refresh.
       mValidRegion.Or(mValidRegion, regionToPaint);
 
+      // mValidRegion would have been altered by InvalidateRegion, but we still
+      // want to display stale content until it gets progressively updated.
+      // Create a region that includes stale content.
+      nsIntRegion validOrStale;
+      validOrStale.Or(mValidRegion, oldValidRegion);
+
       // Paint the computed region and subtract it from the invalid region.
-      mTiledBuffer.PaintThebes(this, mValidRegion, regionToPaint, aCallback, aCallbackData);
+      mTiledBuffer.PaintThebes(this, validOrStale, regionToPaint, aCallback, aCallbackData);
       invalidRegion.Sub(invalidRegion, regionToPaint);
     } while (repeat);
   } else {
     mTiledBuffer.ClearPaintedRegion();
     mTiledBuffer.SetResolution(resolution);
     mValidRegion = mVisibleRegion;
     mTiledBuffer.PaintThebes(this, mValidRegion, invalidRegion, aCallback, aCallbackData);
   }
--- a/gfx/src/nsCoord.h
+++ b/gfx/src/nsCoord.h
@@ -439,32 +439,16 @@ inline nscoord NSFloatPixelsToAppUnits(f
 {
   return NSToCoordRoundWithClamp(aPixels * aAppUnitsPerPixel);
 }
 
 inline nscoord NSIntPixelsToAppUnits(int32_t aPixels, int32_t aAppUnitsPerPixel)
 {
   // The cast to nscoord makes sure we don't overflow if we ever change
   // nscoord to float
-#ifndef NS_COORD_IS_FLOAT
-  const int pixels_MAX = nscoord_MAX / aAppUnitsPerPixel;
-  // Bounds-check before converting out of float, to avoid overflow
-  NS_WARN_IF_FALSE(aPixels <= pixels_MAX,
-                   "Overflowed nscoord_MAX in conversion to nscoord");
-  if (aPixels >= pixels_MAX) {
-    aPixels = pixels_MAX;
-  } else {
-    const int pixels_MIN = nscoord_MIN / aAppUnitsPerPixel;
-    NS_WARN_IF_FALSE(aPixels >= pixels_MIN,
-                     "Overflowed nscoord_MIN in conversion to nscoord");
-    if (aPixels <= pixels_MIN) {
-      aPixels = pixels_MIN;
-    }
-  }
-#endif
   nscoord r = aPixels * (nscoord)aAppUnitsPerPixel;
   VERIFY_COORD(r);
   return r;
 }
 
 inline float NSAppUnitsToFloatPixels(nscoord aAppUnits, float aAppUnitsPerPixel)
 {
   return (float(aAppUnits) / aAppUnitsPerPixel);
--- a/hal/Hal.cpp
+++ b/hal/Hal.cpp
@@ -400,62 +400,96 @@ double GetScreenBrightness()
 }
 
 void SetScreenBrightness(double brightness)
 {
   AssertMainThread();
   PROXY_IF_SANDBOXED(SetScreenBrightness(clamped(brightness, 0.0, 1.0)));
 }
 
-bool SetLight(LightType light, const hal::LightConfiguration& aConfig)
+bool SetLight(LightType light, const LightConfiguration& aConfig)
 {
   AssertMainThread();
   RETURN_PROXY_IF_SANDBOXED(SetLight(light, aConfig), false);
 }
 
-bool GetLight(LightType light, hal::LightConfiguration* aConfig)
+bool GetLight(LightType light, LightConfiguration* aConfig)
 {
   AssertMainThread();
   RETURN_PROXY_IF_SANDBOXED(GetLight(light, aConfig), false);
 }
 
-class SystemTimeObserversManager : public ObserversManager<SystemTimeChange>
+class SystemClockChangeObserversManager : public ObserversManager<int64_t>
 {
 protected:
   void EnableNotifications() {
-    PROXY_IF_SANDBOXED(EnableSystemTimeChangeNotifications());
+    PROXY_IF_SANDBOXED(EnableSystemClockChangeNotifications());
   }
 
   void DisableNotifications() {
-    PROXY_IF_SANDBOXED(DisableSystemTimeChangeNotifications());
+    PROXY_IF_SANDBOXED(DisableSystemClockChangeNotifications());
   }
 };
 
-static SystemTimeObserversManager sSystemTimeObservers;
+static SystemClockChangeObserversManager sSystemClockChangeObservers;
 
 void
-RegisterSystemTimeChangeObserver(SystemTimeObserver *aObserver)
+RegisterSystemClockChangeObserver(SystemClockChangeObserver* aObserver)
 {
   AssertMainThread();
-  sSystemTimeObservers.AddObserver(aObserver);
+  sSystemClockChangeObservers.AddObserver(aObserver);
+}
+
+void
+UnregisterSystemClockChangeObserver(SystemClockChangeObserver* aObserver)
+{
+  AssertMainThread();
+  sSystemClockChangeObservers.RemoveObserver(aObserver);
 }
 
 void
-UnregisterSystemTimeChangeObserver(SystemTimeObserver *aObserver)
+NotifySystemClockChange(const int64_t& aClockDeltaMS)
+{
+  sSystemClockChangeObservers.BroadcastInformation(aClockDeltaMS);
+}
+
+class SystemTimezoneChangeObserversManager : public ObserversManager<SystemTimezoneChangeInformation>
+{
+protected:
+  void EnableNotifications() {
+    PROXY_IF_SANDBOXED(EnableSystemTimezoneChangeNotifications());
+  }
+
+  void DisableNotifications() {
+    PROXY_IF_SANDBOXED(DisableSystemTimezoneChangeNotifications());
+  }
+};
+
+static SystemTimezoneChangeObserversManager sSystemTimezoneChangeObservers;
+
+void
+RegisterSystemTimezoneChangeObserver(SystemTimezoneChangeObserver* aObserver)
 {
   AssertMainThread();
-  sSystemTimeObservers.RemoveObserver(aObserver);
+  sSystemTimezoneChangeObservers.AddObserver(aObserver);
 }
 
 void
-NotifySystemTimeChange(const hal::SystemTimeChange& aReason)
+UnregisterSystemTimezoneChangeObserver(SystemTimezoneChangeObserver* aObserver)
 {
-  sSystemTimeObservers.BroadcastInformation(aReason);
+  AssertMainThread();
+  sSystemTimezoneChangeObservers.RemoveObserver(aObserver);
 }
- 
+
+void
+NotifySystemTimezoneChange(const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo)
+{
+  sSystemTimezoneChangeObservers.BroadcastInformation(aSystemTimezoneChangeInfo);
+}
+
 void 
 AdjustSystemClock(int64_t aDeltaMilliseconds)
 {
   AssertMainThread();
   PROXY_IF_SANDBOXED(AdjustSystemClock(aDeltaMilliseconds));
 }
 
 void 
@@ -602,18 +636,18 @@ void
 UnregisterWakeLockObserver(WakeLockObserver* aObserver)
 {
   AssertMainThread();
   sWakeLockObservers.RemoveObserver(aObserver);
 }
 
 void
 ModifyWakeLock(const nsAString &aTopic,
-               hal::WakeLockControl aLockAdjust,
-               hal::WakeLockControl aHiddenAdjust)
+               WakeLockControl aLockAdjust,
+               WakeLockControl aHiddenAdjust)
 {
   AssertMainThread();
   PROXY_IF_SANDBOXED(ModifyWakeLock(aTopic, aLockAdjust, aHiddenAdjust));
 }
 
 void
 GetWakeLockInfo(const nsAString &aTopic, WakeLockInformation *aWakeLockInfo)
 {
@@ -666,39 +700,39 @@ LockScreenOrientation(const dom::ScreenO
 void
 UnlockScreenOrientation()
 {
   AssertMainThread();
   PROXY_IF_SANDBOXED(UnlockScreenOrientation());
 }
 
 void
-EnableSwitchNotifications(hal::SwitchDevice aDevice) {
+EnableSwitchNotifications(SwitchDevice aDevice) {
   AssertMainThread();
   PROXY_IF_SANDBOXED(EnableSwitchNotifications(aDevice));
 }
 
 void
-DisableSwitchNotifications(hal::SwitchDevice aDevice) {
+DisableSwitchNotifications(SwitchDevice aDevice) {
   AssertMainThread();
   PROXY_IF_SANDBOXED(DisableSwitchNotifications(aDevice));
 }
 
-hal::SwitchState GetCurrentSwitchState(hal::SwitchDevice aDevice)
+SwitchState GetCurrentSwitchState(SwitchDevice aDevice)
 {
   AssertMainThread();
   RETURN_PROXY_IF_SANDBOXED(GetCurrentSwitchState(aDevice), SWITCH_STATE_UNKNOWN);
 }
 
 typedef mozilla::ObserverList<SwitchEvent> SwitchObserverList;
 
 static SwitchObserverList *sSwitchObserverLists = NULL;
 
 static SwitchObserverList&
-GetSwitchObserverList(hal::SwitchDevice aDevice) {
+GetSwitchObserverList(SwitchDevice aDevice) {
   MOZ_ASSERT(0 <= aDevice && aDevice < NUM_SWITCH_DEVICE); 
   if (sSwitchObserverLists == NULL) {
     sSwitchObserverLists = new SwitchObserverList[NUM_SWITCH_DEVICE];
   }
   return sSwitchObserverLists[aDevice];
 }
 
 static void
@@ -709,28 +743,28 @@ ReleaseObserversIfNeeded() {
   }
 
   //The length of every list is 0, no observer in the list.
   delete [] sSwitchObserverLists;
   sSwitchObserverLists = NULL;
 }
 
 void
-RegisterSwitchObserver(hal::SwitchDevice aDevice, hal::SwitchObserver *aObserver)
+RegisterSwitchObserver(SwitchDevice aDevice, SwitchObserver *aObserver)
 {
   AssertMainThread();
   SwitchObserverList& observer = GetSwitchObserverList(aDevice);
   observer.AddObserver(aObserver);
   if (observer.Length() == 1) {
     EnableSwitchNotifications(aDevice);
   }
 }
 
 void
-UnregisterSwitchObserver(hal::SwitchDevice aDevice, hal::SwitchObserver *aObserver)
+UnregisterSwitchObserver(SwitchDevice aDevice, SwitchObserver *aObserver)
 {
   AssertMainThread();
 
   if (!sSwitchObserverLists) {
     return;
   }
 
   SwitchObserverList& observer = GetSwitchObserverList(aDevice);
@@ -738,17 +772,17 @@ UnregisterSwitchObserver(hal::SwitchDevi
     return;
   }
 
   DisableSwitchNotifications(aDevice);
   ReleaseObserversIfNeeded();
 }
 
 void
-NotifySwitchChange(const hal::SwitchEvent& aEvent)
+NotifySwitchChange(const SwitchEvent& aEvent)
 {
   // When callback this notification, main thread may call unregister function
   // first. We should check if this pointer is valid.
   if (!sSwitchObserverLists)
     return;
 
   SwitchObserverList& observer = GetSwitchObserverList(aEvent.device());
   observer.Broadcast(aEvent);
--- a/hal/Hal.h
+++ b/hal/Hal.h
@@ -45,17 +45,18 @@ namespace hal {
 typedef Observer<void_t> AlarmObserver;
 typedef Observer<ScreenConfiguration> ScreenConfigurationObserver;
 
 class WindowIdentifier;
 
 extern PRLogModuleInfo *sHalLog;
 #define HAL_LOG(msg) PR_LOG(mozilla::hal::sHalLog, PR_LOG_DEBUG, msg)
 
-typedef Observer<SystemTimeChange> SystemTimeObserver;
+typedef Observer<int64_t> SystemClockChangeObserver;
+typedef Observer<SystemTimezoneChangeInformation> SystemTimezoneChangeObserver;
 
 } // namespace hal
 
 namespace MOZ_HAL_NAMESPACE {
 
 /**
  * Turn the default vibrator device on/off per the pattern specified
  * by |pattern|.  Each element in the pattern is the number of
@@ -253,32 +254,55 @@ void SetTimezone(const nsCString& aTimez
 
 /**
  * Get timezone
  * http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
  */
 nsCString GetTimezone();
 
 /**
- * Register observer for system time changed notification.
+ * Register observer for system clock changed notification.
  * @param aObserver The observer that should be added.
  */
-void RegisterSystemTimeChangeObserver(hal::SystemTimeObserver* aObserver);
+void RegisterSystemClockChangeObserver(
+  hal::SystemClockChangeObserver* aObserver);
+
+/**
+ * Unregister the observer for system clock changed.
+ * @param aObserver The observer that should be removed.
+ */
+void UnregisterSystemClockChangeObserver(
+  hal::SystemClockChangeObserver* aObserver);
+
+/**
+ * Notify of a change in the system clock.
+ * @param aClockDeltaMS
+ */
+void NotifySystemClockChange(const int64_t& aClockDeltaMS);
 
 /**
- * Unregister the observer for system time changed.
+ * Register observer for system timezone changed notification.
+ * @param aObserver The observer that should be added.
+ */
+void RegisterSystemTimezoneChangeObserver(
+  hal::SystemTimezoneChangeObserver* aObserver);
+
+/**
+ * Unregister the observer for system timezone changed.
  * @param aObserver The observer that should be removed.
  */
-void UnregisterSystemTimeChangeObserver(hal::SystemTimeObserver* aObserver);
+void UnregisterSystemTimezoneChangeObserver(
+  hal::SystemTimezoneChangeObserver* aObserver);
 
 /**
- * Notify of a change in the system cloeck or time zone.
- * @param aReason
+ * Notify of a change in the system timezone.
+ * @param aSystemTimezoneChangeInfo
  */
-void NotifySystemTimeChange(const hal::SystemTimeChange& aReason);
+void NotifySystemTimezoneChange(
+  const hal::SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo);
 
 /**
  * Reboot the device.
  * 
  * This API is currently only allowed to be used from the main process.
  */
 void Reboot();
 
--- a/hal/HalInternal.h
+++ b/hal/HalInternal.h
@@ -70,22 +70,32 @@ void DisableSwitchNotifications(hal::Swi
 bool EnableAlarm();
 
 /**
  * Disable alarm notifications from the backend.
  */
 void DisableAlarm();
 
 /**
- * Enable system time change notifications from the backend.
+ * Enable system clock change notifications from the backend.
  */
-void EnableSystemTimeChangeNotifications();
+void EnableSystemClockChangeNotifications();
 
 /**
- * Disable system time change notifications from the backend.
+ * Disable system clock change notifications from the backend.
+ */
+void DisableSystemClockChangeNotifications();
+
+/**
+ * Enable system timezone change notifications from the backend.
  */
-void DisableSystemTimeChangeNotifications();
+void EnableSystemTimezoneChangeNotifications();
+
+/**
+ * Disable system timezone change notifications from the backend.
+ */
+void DisableSystemTimezoneChangeNotifications();
 
 bool IsHalChildLive();
 } // namespace MOZ_HAL_NAMESPACE
 } // namespace mozilla
 
 #endif  // mozilla_HalInternal_h
--- a/hal/HalTypes.h
+++ b/hal/HalTypes.h
@@ -79,23 +79,16 @@ enum ProcessPriority {
  */
 enum WakeLockControl {
   WAKE_LOCK_REMOVE_ONE = -1,
   WAKE_LOCK_NO_CHANGE  = 0,
   WAKE_LOCK_ADD_ONE    = 1,
   NUM_WAKE_LOCK
 };
 
-enum SystemTimeChange {
-  SYS_TIME_CHANGE_UNKNOWN = -1,
-  SYS_TIME_CHANGE_CLOCK,
-  SYS_TIME_CHANGE_TZ,
-  SYS_TIME_CHANGE_GUARD
-};
-
 class FMRadioOperationInformation;
 
 enum FMRadioOperation {
   FM_RADIO_OPERATION_UNKNOWN = -1,
   FM_RADIO_OPERATION_ENABLE,
   FM_RADIO_OPERATION_DISABLE,
   FM_RADIO_OPERATION_SEEK,
   NUM_FM_RADIO_OPERATION
@@ -162,17 +155,16 @@ enum FMRadioCountry {
   FM_RADIO_COUNTRY_TW,  //Taiwan
   FM_RADIO_COUNTRY_TR,  //Turkey
   FM_RADIO_COUNTRY_UA,  //Ukraine
   FM_RADIO_COUNTRY_USER_DEFINED,
   NUM_FM_RADIO_COUNTRY
 };
 
 typedef Observer<FMRadioOperationInformation> FMRadioObserver;
-typedef Observer<SystemTimeChange> SystemTimeChangeObserver;
 } // namespace hal
 } // namespace mozilla
 
 namespace IPC {
 
 /**
  * Light type serializer.
  */
@@ -246,26 +238,16 @@ struct ParamTraits<mozilla::hal::SwitchD
 template <>
 struct ParamTraits<mozilla::hal::ProcessPriority>:
   public EnumSerializer<mozilla::hal::ProcessPriority,
                         mozilla::hal::PROCESS_PRIORITY_BACKGROUND,
                         mozilla::hal::NUM_PROCESS_PRIORITY> {
 };
 
 /**
- * SystemTimeChange serializer.
- */
-template <>
-struct ParamTraits<mozilla::hal::SystemTimeChange>
-  : public EnumSerializer<mozilla::hal::SystemTimeChange,
-                          mozilla::hal::SYS_TIME_CHANGE_UNKNOWN,
-                          mozilla::hal::SYS_TIME_CHANGE_GUARD>
-{};
- 
-/**
  * Serializer for FMRadioOperation
  */
 template <>
 struct ParamTraits<mozilla::hal::FMRadioOperation>:
   public EnumSerializer<mozilla::hal::FMRadioOperation,
                         mozilla::hal::FM_RADIO_OPERATION_UNKNOWN,
                         mozilla::hal::NUM_FM_RADIO_OPERATION>
 {};
--- a/hal/fallback/FallbackTime.cpp
+++ b/hal/fallback/FallbackTime.cpp
@@ -20,18 +20,29 @@ SetTimezone(const nsCString& aTimezoneSp
 
 nsCString
 GetTimezone()
 {
   return EmptyCString();
 }
 
 void
-EnableSystemTimeChangeNotifications()
+EnableSystemClockChangeNotifications()
+{
+}
+
+void
+DisableSystemClockChangeNotifications()
 {
 }
 
 void
-DisableSystemTimeChangeNotifications()
+EnableSystemTimezoneChangeNotifications()
 {
 }
+
+void
+DisableSystemTimezoneChangeNotifications()
+{
+}
+
 } // namespace hal_impl
 } // namespace mozilla
--- a/hal/gonk/GonkHal.cpp
+++ b/hal/gonk/GonkHal.cpp
@@ -78,16 +78,23 @@
 #ifndef OOM_SCORE_ADJ_MIN
 #define OOM_SCORE_ADJ_MIN  (-1000)
 #endif
 
 #ifndef OOM_SCORE_ADJ_MAX
 #define OOM_SCORE_ADJ_MAX  1000
 #endif
 
+#ifndef BATTERY_CHARGING_ARGB
+#define BATTERY_CHARGING_ARGB 0x00FF0000
+#endif
+#ifndef BATTERY_FULL_ARGB
+#define BATTERY_FULL_ARGB 0x0000FF00
+#endif
+
 using namespace mozilla;
 using namespace mozilla::hal;
 
 namespace mozilla {
 namespace hal_impl {
 
 namespace {
 
@@ -245,16 +252,36 @@ CancelVibrate(const hal::WindowIdentifie
 namespace {
 
 class BatteryUpdater : public nsRunnable {
 public:
   NS_IMETHOD Run()
   {
     hal::BatteryInformation info;
     hal_impl::GetCurrentBatteryInformation(&info);
+
+    // Control the battery indicator (led light) here using BatteryInformation
+    // we just retrieved.
+    uint32_t color = 0; // Format: 0x00rrggbb.
+    if (info.charging() && (info.level() == 1)) {
+      // Charging and battery full.
+      color = BATTERY_FULL_ARGB;
+    } else if (info.charging() && (info.level() < 1)) {
+      // Charging but not full.
+      color = BATTERY_CHARGING_ARGB;
+    } // else turn off battery indicator.
+
+    hal::LightConfiguration aConfig(hal::eHalLightID_Battery,
+                                    hal::eHalLightMode_User,
+                                    hal::eHalLightFlash_None,
+                                    0,
+                                    0,
+                                    color);
+    hal_impl::SetLight(hal::eHalLightID_Battery, aConfig);
+
     hal::NotifyBatteryChange(info);
     return NS_OK;
   }
 };
 
 } // anonymous namespace
 
 class BatteryObserver : public IUeventObserver,
@@ -638,48 +665,76 @@ AdjustSystemClock(int64_t aDeltaMillisec
     return;
   }
 
   if (ioctl(fd, ANDROID_ALARM_SET_RTC, &now) < 0) {
     HAL_LOG(("ANDROID_ALARM_SET_RTC failed: %s", strerror(errno)));
     return;
   }
 
-  hal::NotifySystemTimeChange(hal::SYS_TIME_CHANGE_CLOCK);
+  hal::NotifySystemClockChange(aDeltaMilliseconds);
+}
+
+static int32_t
+GetTimezoneOffset()
+{
+  PRExplodedTime prTime;
+  PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &prTime);
+
+  // Daylight saving time (DST) will be taken into account.
+  int32_t offset = prTime.tm_params.tp_gmt_offset;
+  offset += prTime.tm_params.tp_dst_offset;
+
+  // Returns the timezone offset relative to UTC in minutes.
+  return -(offset / 60);
 }
 
 void
 SetTimezone(const nsCString& aTimezoneSpec)
 {
   if (aTimezoneSpec.Equals(GetTimezone())) {
     return;
   }
 
+  int32_t oldTimezoneOffsetMinutes = GetTimezoneOffset();
   property_set("persist.sys.timezone", aTimezoneSpec.get());
   // this function is automatically called by the other time conversion
   // functions that depend on the timezone. To be safe, we call it manually.
   tzset();
-  hal::NotifySystemTimeChange(hal::SYS_TIME_CHANGE_TZ);
+  int32_t newTimezoneOffsetMinutes = GetTimezoneOffset();
+  hal::NotifySystemTimezoneChange(
+    hal::SystemTimezoneChangeInformation(
+      oldTimezoneOffsetMinutes, newTimezoneOffsetMinutes));
 }
 
 nsCString
 GetTimezone()
 {
   char timezone[32];
   property_get("persist.sys.timezone", timezone, "");
   return nsCString(timezone);
 }
 
 void
-EnableSystemTimeChangeNotifications()
+EnableSystemClockChangeNotifications()
 {
 }
 
 void
-DisableSystemTimeChangeNotifications()
+DisableSystemClockChangeNotifications()
+{
+}
+
+void
+EnableSystemTimezoneChangeNotifications()
+{
+}
+
+void
+DisableSystemTimezoneChangeNotifications()
 {
 }
 
 // Nothing to do here.  Gonk widgetry always listens for screen
 // orientation changes.
 void
 EnableScreenConfigurationNotifications()
 {
--- a/hal/sandbox/PHal.ipdl
+++ b/hal/sandbox/PHal.ipdl
@@ -19,17 +19,16 @@ using mozilla::hal::LightMode;
 using mozilla::hal::SensorType;
 using mozilla::hal::SensorAccuracyType;
 using mozilla::hal::WakeLockControl;
 using mozilla::hal::SwitchState;
 using mozilla::hal::SwitchDevice;
 using mozilla::hal::ProcessPriority;
 using nsIntRect;
 using PRTime;
-using mozilla::hal::SystemTimeChange;
 using mozilla::hal::FMRadioCountry;
 using mozilla::hal::FMRadioOperation;
 using mozilla::hal::FMRadioOperationStatus;
 using mozilla::hal::FMRadioSeekDirection;
 
 namespace mozilla {
 
 namespace hal {
@@ -87,30 +86,38 @@ struct FMRadioOperationInformation {
 struct FMRadioSettings {
   FMRadioCountry country;
   uint32_t upperLimit;
   uint32_t lowerLimit;
   uint32_t spaceType;
   uint32_t preEmphasis;
 };
 
+struct SystemTimezoneChangeInformation {
+  // These timezone offsets are relative to UTC in minutes and
+  // have already taken daylight saving time (DST) into account.
+  int32_t oldTimezoneOffsetMinutes;
+  int32_t newTimezoneOffsetMinutes;
+};
+
 } // namespace hal
 
 namespace hal_sandbox {
 
 sync protocol PHal {
     manager PContent;
 
 child:
     NotifyBatteryChange(BatteryInformation aBatteryInfo);
     NotifyNetworkChange(NetworkInformation aNetworkInfo);
     NotifyWakeLockChange(WakeLockInformation aWakeLockInfo);
     NotifyScreenConfigurationChange(ScreenConfiguration aScreenOrientation);
     NotifySwitchChange(SwitchEvent aEvent);
-    NotifySystemTimeChange(SystemTimeChange aReason); 
+    NotifySystemClockChange(int64_t aClockDeltaMS); 
+    NotifySystemTimezoneChange(SystemTimezoneChangeInformation aSystemTimezoneChangeInfo); 
     NotifyFMRadioStatus(FMRadioOperationInformation aInfo);
 
 parent:
     Vibrate(uint32_t[] pattern, uint64_t[] id, PBrowser browser);
     CancelVibrate(uint64_t[] id, PBrowser browser);
 
     EnableBatteryNotifications();
     DisableBatteryNotifications();
@@ -130,18 +137,20 @@ parent:
 
     sync GetScreenBrightness() returns (double brightness);
     SetScreenBrightness(double brightness);
 
     AdjustSystemClock(int64_t aDeltaMilliseconds);
     SetTimezone(nsCString aTimezoneSpec);
     sync GetTimezone()
       returns (nsCString aTimezoneSpec);
-    EnableSystemTimeChangeNotifications();
-    DisableSystemTimeChangeNotifications();
+    EnableSystemClockChangeNotifications();
+    DisableSystemClockChangeNotifications();
+    EnableSystemTimezoneChangeNotifications();
+    DisableSystemTimezoneChangeNotifications();
 
     sync SetLight(LightType light, LightConfiguration aConfig)
       returns (bool status);
     sync GetLight(LightType light)
       returns (LightConfiguration aConfig, bool status);
 
     ModifyWakeLock(nsString aTopic, WakeLockControl aLockAdjust, WakeLockControl aHiddenAdjust);
     EnableWakeLockNotifications();
--- a/hal/sandbox/SandboxHal.cpp
+++ b/hal/sandbox/SandboxHal.cpp
@@ -207,25 +207,37 @@ nsCString
 GetTimezone()
 {
   nsCString timezone;
   Hal()->SendGetTimezone(&timezone);
   return timezone;
 }
 
 void
-EnableSystemTimeChangeNotifications()
+EnableSystemClockChangeNotifications()
 {
-  Hal()->SendEnableSystemTimeChangeNotifications();
+  Hal()->SendEnableSystemClockChangeNotifications();
 }
 
 void
-DisableSystemTimeChangeNotifications()
+DisableSystemClockChangeNotifications()
+{
+  Hal()->SendDisableSystemClockChangeNotifications();
+}
+
+void
+EnableSystemTimezoneChangeNotifications()
 {
-  Hal()->SendDisableSystemTimeChangeNotifications();
+  Hal()->SendEnableSystemTimezoneChangeNotifications();
+}
+
+void
+DisableSystemTimezoneChangeNotifications()
+{
+  Hal()->SendDisableSystemTimezoneChangeNotifications();
 }
 
 void
 Reboot()
 {
   NS_RUNTIMEABORT("Reboot() can't be called from sandboxed contexts.");
 }
 
@@ -389,33 +401,35 @@ FactoryReset()
 
 class HalParent : public PHalParent
                 , public BatteryObserver
                 , public NetworkObserver
                 , public ISensorObserver
                 , public WakeLockObserver
                 , public ScreenConfigurationObserver
                 , public SwitchObserver
-                , public SystemTimeObserver
+                , public SystemClockChangeObserver
+                , public SystemTimezoneChangeObserver
 {
 public:
   virtual void
   ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE
   {
     // NB: you *must* unconditionally unregister your observer here,
     // if it *may* be registered below.
     hal::UnregisterBatteryObserver(this);
     hal::UnregisterNetworkObserver(this);
     hal::UnregisterScreenConfigurationObserver(this);
     for (int32_t sensor = SENSOR_UNKNOWN + 1;
          sensor < NUM_SENSOR_TYPE; ++sensor) {
       hal::UnregisterSensorObserver(SensorType(sensor), this);
     }
     hal::UnregisterWakeLockObserver(this);
-    hal::UnregisterSystemTimeChangeObserver(this);
+    hal::UnregisterSystemClockChangeObserver(this);
+    hal::UnregisterSystemTimezoneChangeObserver(this);
   }
 
   virtual bool
   RecvVibrate(const InfallibleTArray<unsigned int>& pattern,
               const InfallibleTArray<uint64_t> &id,
               PBrowserParent *browserParent) MOZ_OVERRIDE
   {
     // We give all content vibration permission.
@@ -638,26 +652,40 @@ public:
     if (!AssertAppProcessPermission(this, "time")) {
       return false;
     }
     *aTimezoneSpec = hal::GetTimezone();
     return true;
   }
 
   virtual bool
-  RecvEnableSystemTimeChangeNotifications() MOZ_OVERRIDE
+  RecvEnableSystemClockChangeNotifications() MOZ_OVERRIDE
   {
-    hal::RegisterSystemTimeChangeObserver(this);
+    hal::RegisterSystemClockChangeObserver(this);
     return true;
   }
 
   virtual bool
-  RecvDisableSystemTimeChangeNotifications() MOZ_OVERRIDE
+  RecvDisableSystemClockChangeNotifications() MOZ_OVERRIDE
+  {
+    hal::UnregisterSystemClockChangeObserver(this);
+    return true;
+  }
+
+  virtual bool
+  RecvEnableSystemTimezoneChangeNotifications() MOZ_OVERRIDE
   {
-    hal::UnregisterSystemTimeChangeObserver(this);
+    hal::RegisterSystemTimezoneChangeObserver(this);
+    return true;
+  }
+
+  virtual bool
+  RecvDisableSystemTimezoneChangeNotifications() MOZ_OVERRIDE
+  {
+    hal::UnregisterSystemTimezoneChangeObserver(this);
     return true;
   }
 
   virtual bool
   RecvEnableSensorNotifications(const SensorType &aSensor) MOZ_OVERRIDE {
     // We currently allow any content to register device-sensor
     // listeners.
     hal::RegisterSensorObserver(aSensor, this);
@@ -744,19 +772,24 @@ public:
   RecvSetProcessPriority(const int& aPid, const ProcessPriority& aPriority)
   {
     // TODO As a security check, we should ensure that aPid is either the pid
     // of our child, or the pid of one of the child's children.
     hal::SetProcessPriority(aPid, aPriority);
     return true;
   }
 
-  void Notify(const SystemTimeChange& aReason)
+  void Notify(const int64_t& aClockDeltaMS)
   {
-    unused << SendNotifySystemTimeChange(aReason);
+    unused << SendNotifySystemClockChange(aClockDeltaMS);
+  }
+
+  void Notify(const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo)
+  {
+    unused << SendNotifySystemTimezoneChange(aSystemTimezoneChangeInfo);
   }
 
   virtual bool
   RecvEnableFMRadio(const hal::FMRadioSettings& aSettings)
   {
     if (!AssertAppProcessPermission(this, "fmradio")) {
       return false;
     }
@@ -897,18 +930,25 @@ public:
 
   virtual bool
   RecvNotifySwitchChange(const mozilla::hal::SwitchEvent& aEvent) MOZ_OVERRIDE {
     hal::NotifySwitchChange(aEvent);
     return true;
   }
 
   virtual bool
-  RecvNotifySystemTimeChange(const SystemTimeChange& aReason) {
-    hal::NotifySystemTimeChange(aReason);
+  RecvNotifySystemClockChange(const int64_t& aClockDeltaMS) {
+    hal::NotifySystemClockChange(aClockDeltaMS);
+    return true;
+  }
+
+  virtual bool
+  RecvNotifySystemTimezoneChange(
+    const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo) {
+    hal::NotifySystemTimezoneChange(aSystemTimezoneChangeInfo);
     return true;
   }
 
   virtual bool
   RecvNotifyFMRadioStatus(const FMRadioOperationInformation& aRadioStatus) {
     hal::NotifyFMRadioStatus(aRadioStatus);
     return true;
   }
--- a/intl/unicharutil/util/nsUnicharUtils.cpp
+++ b/intl/unicharutil/util/nsUnicharUtils.cpp
@@ -31,27 +31,27 @@ static const uint8_t gASCIIToLower [128]
 #define IS_ASCII_UPPER(u) (('A' <= (u)) && ((u) <= 'Z'))
 #define IS_ASCII_LOWER(u) (('a' <= (u)) && ((u) <= 'z'))
 #define IS_ASCII_ALPHA(u) (IS_ASCII_UPPER(u) || IS_ASCII_LOWER(u))
 #define IS_ASCII_SPACE(u) (' ' == (u))
 
 // We want ToLowerCase(uint32_t) and ToLowerCaseASCII(uint32_t) to be fast
 // when they're called from within the case-insensitive comparators, so we
 // define inlined versions.
-static NS_ALWAYS_INLINE uint32_t
+static MOZ_ALWAYS_INLINE uint32_t
 ToLowerCase_inline(uint32_t aChar)
 {
   if (IS_ASCII(aChar)) {
     return gASCIIToLower[aChar];
   }
 
   return mozilla::unicode::GetLowercase(aChar);
 }
 
-static NS_ALWAYS_INLINE uint32_t
+static MOZ_ALWAYS_INLINE uint32_t
 ToLowerCaseASCII_inline(const uint32_t aChar)
 {
   if (IS_ASCII(aChar)) {
     return gASCIIToLower[aChar];
   }
 
   return aChar;
 }
@@ -266,17 +266,17 @@ CaseInsensitiveCompare(const PRUnichar *
 
 // Calculates the codepoint of the UTF8 sequence starting at aStr.  Sets aNext
 // to the byte following the end of the sequence.
 //
 // If the sequence is invalid, or if computing the codepoint would take us off
 // the end of the string (as marked by aEnd), returns -1 and does not set
 // aNext.  Note that this function doesn't check that aStr < aEnd -- it assumes
 // you've done that already.
-static NS_ALWAYS_INLINE uint32_t
+static MOZ_ALWAYS_INLINE uint32_t
 GetLowerUTF8Codepoint(const char* aStr, const char* aEnd, const char **aNext)
 {
   // Convert to unsigned char so that stuffing chars into PRUint32s doesn't
   // sign extend.
   const unsigned char *str = (unsigned char*)aStr;
 
   if (UTF8traits::isASCII(str[0])) {
     // It's ASCII; just convert to lower-case and return it.
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/bug781859-1.js
@@ -0,0 +1,25 @@
+// |jit-test| error:ReferenceError
+function e() {
+    try {} catch (e) {
+    return (actual = "FAIL");
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+      a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
+    }
+    while (t) continue;
+}
+e();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/bug781859-2.js
@@ -0,0 +1,9 @@
+mjitChunkLimit(42);
+Function("\
+    switch (/x/) {\
+        case 8:\
+        break;\
+        t(function(){})\
+    }\
+    while (false)(function(){})\
+")()
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/bug781859-3.js
@@ -0,0 +1,10 @@
+mjitChunkLimit(10);
+function e() {
+    try {
+        var t = undefined;
+    } catch (e) { }
+    while (t)
+        continue;
+}
+for (var i = 0; i < 20; i++)
+  e();
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2598,17 +2598,17 @@ MarkRuntime(JSTracer *trc, bool useSaved
     }
 
 #ifdef JS_METHODJIT
     /* We need to expand inline frames before stack scanning. */
     for (CompartmentsIter c(rt); !c.done(); c.next())
         mjit::ExpandInlineFrames(c);
 #endif
 
-    rt->stackSpace.markAndClobber(trc);
+    rt->stackSpace.mark(trc);
     rt->debugScopes->mark(trc);
 
 #ifdef JS_ION
     ion::MarkIonActivations(rt, trc);
 #endif
 
     for (CompartmentsIter c(rt); !c.done(); c.next())
         c->mark(trc);
@@ -3846,23 +3846,16 @@ BeginSweepPhase(JSRuntime *rt)
     Debugger::sweepAll(&fop);
 
     PartitionCompartments partition(rt);
     partition.partition();
 
     {
         gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_COMPARTMENTS);
 
-        /*
-         * Eliminate any garbage values from the VM stack that may have been
-         * left by the JIT in between incremental GC slices. We need to do this
-         * before discarding analysis data during JSCompartment::sweep.
-         */
-        rt->stackSpace.markAndClobber(NULL);
-
         bool releaseTypes = ReleaseObservedTypes(rt);
         for (CompartmentsIter c(rt); !c.done(); c.next()) {
             gcstats::AutoSCC scc(rt->gcStats, partition.getSCC(c));
             if (c->isCollecting())
                 c->sweep(&fop, releaseTypes);
             else
                 c->sweepCrossCompartmentWrappers();
         }
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -743,22 +743,17 @@ class TypeConstraintPropagateThis : publ
 
     void newType(JSContext *cx, TypeSet *source, Type type);
 };
 
 void
 StackTypeSet::addPropagateThis(JSContext *cx, HandleScript script, jsbytecode *pc,
                                Type type, StackTypeSet *types)
 {
-    /* Don't add constraints when the call will be 'new' (see addCallProperty). */
-    jsbytecode *callpc = script->analysis()->getCallPC(pc);
-    if (JSOp(*callpc) == JSOP_NEW)
-        return;
-
-    add(cx, cx->analysisLifoAlloc().new_<TypeConstraintPropagateThis>(script, callpc, type, types));
+    add(cx, cx->analysisLifoAlloc().new_<TypeConstraintPropagateThis>(script, pc, type, types));
 }
 
 /* Subset constraint which filters out primitive types. */
 class TypeConstraintFilterPrimitive : public TypeConstraint
 {
   public:
     TypeSet *target;
 
@@ -1202,17 +1197,16 @@ TypeConstraintCallProp<access>::newType(
         if (object->unknownProperties()) {
             cx->compartment->types.monitorBytecode(cx, script, callpc - script->code);
         } else {
             TypeSet *types = object->getProperty(cx, id, false);
             if (!types)
                 return;
             if (!types->hasPropagatedProperty())
                 object->getFromPrototypes(cx, id, types);
-            /* Bypass addPropagateThis, we already have the callpc. */
             if (access == PROPERTY_READ) {
                 types->add(cx, cx->typeLifoAlloc().new_<TypeConstraintPropagateThis>(
                                 script_, callpc, type, (StackTypeSet *) NULL));
             } else {
                 TypeConstraintPropagateThis constraint(script, callpc, type, NULL);
                 types->addTypesToConstraint(cx, &constraint);
             }
         }
@@ -3574,26 +3568,16 @@ GetInitializerType(JSContext *cx, Handle
     JSProtoKey key = isArray ? JSProto_Array : JSProto_Object;
 
     if (UseNewTypeForInitializer(cx, script, pc, key))
         return NULL;
 
     return TypeScript::InitObject(cx, script, pc, key);
 }
 
-static inline Type
-GetCalleeThisType(jsbytecode *pc)
-{
-    pc += GetBytecodeLength(pc);
-    if (*pc == JSOP_UNDEFINED)
-        return Type::UndefinedType();
-    JS_ASSERT(*pc == JSOP_IMPLICITTHIS);
-    return Type::UnknownType();
-}
-
 /* Analyze type information for a single bytecode. */
 bool
 ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferenceState &state)
 {
     RootedScript script(cx, script_);
 
     jsbytecode *pc = script_->code + offset;
     JSOp op = (JSOp)*pc;
@@ -3818,31 +3802,26 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
 
         TypeObject *global = script_->global().getType(cx);
 
         /* Handle as a property access. */
         if (state.hasPropertyReadTypes)
             PropertyAccess<PROPERTY_READ_EXISTING>(cx, script, pc, global, seen, id);
         else
             PropertyAccess<PROPERTY_READ>(cx, script, pc, global, seen, id);
-
-        if (op == JSOP_CALLGNAME)
-            pushed[0].addPropagateThis(cx, script, pc, GetCalleeThisType(pc));
         break;
       }
 
       case JSOP_NAME:
       case JSOP_INTRINSICNAME:
       case JSOP_CALLNAME:
       case JSOP_CALLINTRINSIC: {
         StackTypeSet *seen = bytecodeTypes(pc);
         addTypeBarrier(cx, pc, seen, Type::UnknownType());
         seen->addSubset(cx, &pushed[0]);
-        if (op == JSOP_CALLNAME || op == JSOP_CALLINTRINSIC)
-            pushed[0].addPropagateThis(cx, script, pc, GetCalleeThisType(pc));
         break;
       }
 
       case JSOP_BINDGNAME:
       case JSOP_BINDNAME:
         break;
 
       case JSOP_SETGNAME: {
@@ -3880,18 +3859,16 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
             poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
         } else if (slot < TotalSlots(script_)) {
             StackTypeSet *types = TypeScript::SlotTypes(script_, slot);
             types->addSubset(cx, &pushed[0]);
         } else {
             /* Local 'let' variable. Punt on types for these, for now. */
             pushed[0].addType(cx, Type::UnknownType());
         }
-        if (op == JSOP_CALLARG || op == JSOP_CALLLOCAL)
-            pushed[0].addPropagateThis(cx, script, pc, Type::UndefinedType());
         break;
       }
 
       case JSOP_SETARG:
       case JSOP_SETLOCAL: {
         uint32_t slot = GetBytecodeSlot(script_, pc);
         if (!trackSlot(slot) && slot < TotalSlots(script_)) {
             TypeSet *types = TypeScript::SlotTypes(script_, slot);
@@ -3912,18 +3889,16 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
         /*
          * Every aliased variable will contain 'undefined' in addition to the
          * type of whatever value is written to it. Thus, a dynamic barrier is
          * necessary. Since we don't expect the to observe more than 1 type,
          * there is little benefit to maintaining a TypeSet for the aliased
          * variable. Instead, we monitor/barrier all reads unconditionally.
          */
         bytecodeTypes(pc)->addSubset(cx, &pushed[0]);
-        if (op == JSOP_CALLALIASEDVAR)
-            pushed[0].addPropagateThis(cx, script, pc, Type::UnknownType());
         break;
 
       case JSOP_SETALIASEDVAR:
         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
         break;
 
       case JSOP_INCARG:
       case JSOP_DECARG:
@@ -4030,18 +4005,16 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
         if (state.hasPropertyReadTypes) {
             TypeConstraintGetPropertyExisting getProp(script_, pc, seen, JSID_VOID);
             input->addTypesToConstraint(cx, &getProp);
         } else {
             input->addGetProperty(cx, script, pc, seen, JSID_VOID);
         }
 
         seen->addSubset(cx, &pushed[0]);
-        if (op == JSOP_CALLELEM)
-            pushed[0].addPropagateThis(cx, script, pc, Type::UndefinedType(), poppedTypes(pc, 1));
         break;
       }
 
       case JSOP_SETELEM:
         poppedTypes(pc, 1)->addSetElement(cx, script, pc, poppedTypes(pc, 2), poppedTypes(pc, 0));
         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
         break;
 
@@ -4128,17 +4101,34 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
         /*
          * Mark FUNCALL and FUNAPPLY sites as monitored. The method JIT may
          * lower these into normal calls, and we need to make sure the
          * callee's argument types are checked on entry.
          */
         if (op == JSOP_FUNCALL || op == JSOP_FUNAPPLY)
             cx->compartment->types.monitorBytecode(cx, script, pc - script_->code);
 
-        poppedTypes(pc, argCount + 1)->addCall(cx, callsite);
+        StackTypeSet *calleeTypes = poppedTypes(pc, argCount + 1);
+
+        /*
+         * Propagate possible 'this' types to the callee except when the call
+         * came through JSOP_CALLPROP (which uses TypeConstraintCallProperty)
+         * or for JSOP_NEW (where the callee will construct the 'this' object).
+         */
+        SSAValue calleeValue = poppedValue(pc, argCount + 1);
+        if (*pc != JSOP_NEW &&
+            (calleeValue.kind() != SSAValue::PUSHED ||
+             script->code[calleeValue.pushedOffset()] != JSOP_CALLPROP))
+        {
+            HandleScript script_ = script;
+            calleeTypes->add(cx, cx->analysisLifoAlloc().new_<TypeConstraintPropagateThis>
+                                   (script_, pc, Type::UndefinedType(), callsite->thisTypes));
+        }
+
+        calleeTypes->addCall(cx, callsite);
         break;
       }
 
       case JSOP_NEWINIT:
       case JSOP_NEWARRAY:
       case JSOP_NEWOBJECT: {
         StackTypeSet *types = script_->analysis()->bytecodeTypes(pc);
         types->addSubset(cx, &pushed[0]);
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -699,17 +699,17 @@ MakeJITScript(JSContext *cx, JSScript *s
 
             jsbytecode *pc = script->code + offset;
             JSOp op = JSOp(*pc);
 
             nextOffset = offset + GetBytecodeLength(pc);
 
             Bytecode *code = analysis->maybeCode(offset);
             if (!code)
-                continue;
+                op = JSOP_NOP; /* Ignore edges from unreachable opcodes. */
 
             /* Whether this should be the last opcode in the chunk. */
             bool finishChunk = false;
 
             /* Keep going, override finishChunk. */
             bool preserveChunk = false;
 
             /*
@@ -1287,27 +1287,17 @@ mjit::Compiler::ensureDoubleArguments()
 }
 
 void
 mjit::Compiler::markUndefinedLocal(uint32_t offset, uint32_t i)
 {
     uint32_t depth = ssa.getFrame(a->inlineIndex).depth;
     uint32_t slot = LocalSlot(script_, i);
     Address local(JSFrameReg, sizeof(StackFrame) + (depth + i) * sizeof(Value));
-    if (!cx->typeInferenceEnabled() || !analysis->trackSlot(slot)) {
-        masm.storeValue(UndefinedValue(), local);
-    } else {
-        Lifetime *lifetime = analysis->liveness(slot).live(offset);
-        if (lifetime)
-            masm.storeValue(UndefinedValue(), local);
-#ifdef DEBUG
-        else
-            masm.storeValue(ObjectValueCrashOnTouch(), local);
-#endif
-    }
+    masm.storeValue(UndefinedValue(), local);
 }
 
 void
 mjit::Compiler::markUndefinedLocals()
 {
     /*
      * Set locals to undefined. Skip locals which aren't closed and are known
      * to be defined before used,
--- a/js/src/methodjit/FrameState-inl.h
+++ b/js/src/methodjit/FrameState-inl.h
@@ -933,18 +933,16 @@ inline void
 FrameState::fakeSync(FrameEntry *fe)
 {
     /*
      * If a frame entry's value will no longer be used, we can mark it as being
      * synced without actually performing the sync: the value is not observed.
      */
     if (!fe->data.synced())
         fe->data.sync();
-    if (!fe->type.synced())
-        fe->type.sync();
 }
 
 inline void
 FrameState::forgetType(FrameEntry *fe)
 {
     /*
      * The type may have been forgotten with an intervening storeLocal in the
      * presence of eval or closed variables. For defense in depth and to make
--- a/js/src/methodjit/FrameState.cpp
+++ b/js/src/methodjit/FrameState.cpp
@@ -307,21 +307,21 @@ FrameState::bestEvictReg(uint32_t mask, 
         }
 
         /*
          * All entries still in registers should have a lifetime, except 'this'
          * in constructors which are not accessed later on.
          */
         Lifetime *lifetime = variableLive(fe, a->PC);
 
+        /* Evict variables whose value is no longer live. */
         if (!lifetime) {
-            JS_ASSERT(isConstructorThis(fe));
             fallback = reg;
             fallbackOffset = a->script->length;
-            JaegerSpew(JSpew_Regalloc, "    %s is 'this' in a constructor\n", reg.name());
+            JaegerSpew(JSpew_Regalloc, "    %s is dead\n", reg.name());
             continue;
         }
 
         /*
          * Evict variables which are only live in future loop iterations, and are
          * not carried around the loop in a register.
          */
         if (lifetime->loopTail && (!loop || !loop->carriesLoopReg(fe))) {
@@ -348,16 +348,31 @@ FrameState::bestEvictReg(uint32_t mask, 
     }
 
     JS_ASSERT(fallback.isSet());
 
     JaegerSpew(JSpew_Regalloc, "result %s\n", fallback.name());
     return fallback;
 }
 
+/*
+ * Whether we can pretend the payload for a given entry is synced provided that
+ * the value in the entry is dead. The contents of dead variables can still be
+ * observed during stack scanning, so the payloads of values which might hold
+ * objects or strings must be preserved.
+ */
+static inline bool
+CanFakeSync(FrameEntry *fe)
+{
+    return fe->isNotType(JSVAL_TYPE_OBJECT)
+        && fe->isNotType(JSVAL_TYPE_STRING)
+        && fe->isNotType(JSVAL_TYPE_DOUBLE)
+        && fe->isNotType(JSVAL_TYPE_MAGIC);
+}
+
 void
 FrameState::evictDeadEntries(bool includePinned)
 {
     for (uint32_t i = 0; i < Registers::TotalAnyRegisters; i++) {
         AnyRegisterID reg = AnyRegisterID::fromRaw(i);
 
         /* Follow along with the same filters as bestEvictReg. */
 
@@ -369,35 +384,27 @@ FrameState::evictDeadEntries(bool includ
             continue;
 
         if (fe == a->callee_ || isConstructorThis(fe) ||
             fe >= a->spBase || fe->isCopied() || (a->parent && fe < a->locals)) {
             continue;
         }
 
         Lifetime *lifetime = variableLive(fe, a->PC);
-        if (lifetime)
+        if (lifetime || !CanFakeSync(fe))
             continue;
 
-        /*
-         * If we are about to fake sync for an entry with known type, reset
-         * that type. We don't want to regard it as correctly synced later.
-         */
-        if (!fe->type.synced() && fe->isTypeKnown())
-            fe->type.setMemory();
+        JS_ASSERT(regstate(reg).type() == RematInfo::DATA);
 
         /*
          * Mark the entry as synced to avoid emitting a store, we don't need
          * to keep this value around.
          */
         fakeSync(fe);
-        if (regstate(reg).type() == RematInfo::DATA)
-            fe->data.setMemory();
-        else
-            fe->type.setMemory();
+        fe->data.setMemory();
         forgetReg(reg);
     }
 }
 
 AnyRegisterID
 FrameState::evictSomeReg(uint32_t mask)
 {
     JS_ASSERT(!freeRegs.hasRegInMask(mask));
@@ -714,27 +721,27 @@ FrameState::syncForAllocation(RegisterAl
             forgetAllRegs(fe);
             fe->resetSynced();
             continue;
         }
 
         /* Force syncs for locals which are dead at the current PC. */
         if (isLocal(fe) && !fe->copied && !a->analysis->slotEscapes(entrySlot(fe))) {
             Lifetime *lifetime = a->analysis->liveness(entrySlot(fe)).live(a->PC - a->script->code);
-            if (!lifetime)
+            if (!lifetime && CanFakeSync(fe))
                 fakeSync(fe);
         }
 
         /* If returning from a script, fake syncs for dead locals in the immediate parent. */
         if (inlineReturn && fe >= a->parent->locals &&
             fe - a->parent->locals < a->parent->script->nfixed &&
             !a->parent->analysis->slotEscapes(frameSlot(a->parent, fe))) {
             const LifetimeVariable &var = a->parent->analysis->liveness(frameSlot(a->parent, fe));
             Lifetime *lifetime = var.live(a->parent->PC - a->parent->script->code);
-            if (!lifetime)
+            if (!lifetime && CanFakeSync(fe))
                 fakeSync(fe);
         }
 
         if (!fe->isCopy() && alloc->hasAnyReg(fe - entries)) {
             /* Types are always synced, except for known doubles. */
             if (!fe->isType(JSVAL_TYPE_DOUBLE))
                 syncType(fe);
         } else {
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -628,91 +628,24 @@ StackSpace::containingSegment(const Stac
         if (s->contains(target))
             return *s;
     }
     JS_NOT_REACHED("frame not in stack space");
     return *(StackSegment *)NULL;
 }
 
 void
-StackSpace::markAndClobberFrame(JSTracer *trc, StackFrame *fp, Value *slotsEnd, jsbytecode *pc)
+StackSpace::markFrame(JSTracer *trc, StackFrame *fp, Value *slotsEnd)
 {
-    AutoAssertNoGC nogc;
     Value *slotsBegin = fp->slots();
-
-    /* If it's a scripted frame, we should have a pc. */
-    JS_ASSERT(pc);
-
-    RawScript script = fp->script();
-    if (!script->hasAnalysis() || !script->analysis()->ranLifetimes()) {
-        if (trc)
-            gc::MarkValueRootRange(trc, slotsBegin, slotsEnd, "vm_stack");
-        return;
-    }
-
-    /*
-     * If the JIT ran a lifetime analysis, then it may have left garbage in the
-     * slots considered not live. We need to avoid marking them. Additionally,
-     * in case the analysis information is thrown out later, we overwrite these
-     * dead slots with valid values so that future GCs won't crash. Analysis
-     * results are thrown away during the sweeping phase, so we always have at
-     * least one GC to do this.
-     */
-    JSRuntime *rt = script->compartment()->rt;
-    analyze::AutoEnterAnalysis aea(script->compartment());
-    analyze::ScriptAnalysis *analysis = script->analysis();
-    uint32_t offset = pc - script->code;
-    Value *fixedEnd = slotsBegin + script->nfixed;
-    for (Value *vp = slotsBegin; vp < fixedEnd; vp++) {
-        uint32_t slot = analyze::LocalSlot(script, vp - slotsBegin);
-
-        /* Will this slot be synced by the JIT? */
-        if (!analysis->trackSlot(slot) || analysis->liveness(slot).live(offset)) {
-            if (trc)
-                gc::MarkValueRoot(trc, vp, "vm_stack");
-        } else if (!trc || script->compartment()->isDiscardingJitCode(trc)) {
-            /*
-             * If we're throwing away analysis information, we need to replace
-             * non-live Values with ones that can safely be marked in later
-             * collections.
-             */
-            if (vp->isDouble()) {
-                *vp = DoubleValue(0.0);
-            } else {
-                /*
-                 * It's possible that *vp may not be a valid Value. For example,
-                 * it may be tagged as a NullValue but the low bits may be
-                 * nonzero so that isNull() returns false. This can cause
-                 * problems later on when marking the value. Extracting the type
-                 * in this way and then overwriting the value circumvents the
-                 * problem.
-                 */
-                JSValueType type = vp->extractNonDoubleType();
-                if (type == JSVAL_TYPE_INT32)
-                    *vp = Int32Value(0);
-                else if (type == JSVAL_TYPE_UNDEFINED)
-                    *vp = UndefinedValue();
-                else if (type == JSVAL_TYPE_BOOLEAN)
-                    *vp = BooleanValue(false);
-                else if (type == JSVAL_TYPE_STRING)
-                    *vp = StringValue(rt->atomState.null);
-                else if (type == JSVAL_TYPE_NULL)
-                    *vp = NullValue();
-                else if (type == JSVAL_TYPE_OBJECT)
-                    *vp = ObjectValue(fp->scopeChain()->global());
-            }
-        }
-    }
-
-    if (trc)
-        gc::MarkValueRootRange(trc, fixedEnd, slotsEnd, "vm_stack");
+    gc::MarkValueRootRange(trc, slotsBegin, slotsEnd, "vm_stack");
 }
 
 void
-StackSpace::markAndClobber(JSTracer *trc)
+StackSpace::mark(JSTracer *trc)
 {
     /* NB: this depends on the continuity of segments in memory. */
     Value *nextSegEnd = firstUnused();
     for (StackSegment *seg = seg_; seg; seg = seg->prevInMemory()) {
         /*
          * A segment describes a linear region of memory that contains a stack
          * of native and interpreted calls. For marking purposes, though, we
          * only need to distinguish between frames and values and mark
@@ -721,28 +654,26 @@ StackSpace::markAndClobber(JSTracer *trc
          * calls. Thus, marking can view the stack as the regex:
          *   (segment slots (frame slots)*)*
          * which gets marked in reverse order.
          */
         Value *slotsEnd = nextSegEnd;
         jsbytecode *pc = seg->maybepc();
         for (StackFrame *fp = seg->maybefp(); (Value *)fp > (Value *)seg; fp = fp->prev()) {
             /* Mark from fp->slots() to slotsEnd. */
-            markAndClobberFrame(trc, fp, slotsEnd, pc);
+            markFrame(trc, fp, slotsEnd);
 
-            if (trc)
-                fp->mark(trc);
+            fp->mark(trc);
             slotsEnd = (Value *)fp;
 
             InlinedSite *site;
             pc = fp->prevpc(&site);
             JS_ASSERT_IF(fp->prev(), !site);
         }
-        if (trc)
-            gc::MarkValueRootRange(trc, seg->slotsBegin(), slotsEnd, "vm_stack");
+        gc::MarkValueRootRange(trc, seg->slotsBegin(), slotsEnd, "vm_stack");
         nextSegEnd = (Value *)seg;
     }
 }
 
 void
 StackSpace::markActiveCompartments()
 {
     for (StackSegment *seg = seg_; seg; seg = seg->prevInMemory()) {
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1377,17 +1377,17 @@ class StackSpace
                                         Value *from, ptrdiff_t nvals) const;
 
     StackSegment &findContainingSegment(const StackFrame *target) const;
 
     bool containsFast(StackFrame *fp) {
         return (Value *)fp >= base_ && (Value *)fp <= trustedEnd_;
     }
 
-    void markAndClobberFrame(JSTracer *trc, StackFrame *fp, Value *slotsEnd, jsbytecode *pc);
+    void markFrame(JSTracer *trc, StackFrame *fp, Value *slotsEnd);
 
   public:
     StackSpace();
     bool init();
     ~StackSpace();
 
     /*
      * Maximum supported value of arguments.length. This bounds the maximum
@@ -1430,17 +1430,17 @@ class StackSpace
      * most script->nslots deep). getStackLimit ensures that the returned limit
      * does indeed have this required space and reports an error and returns
      * NULL if this reserve space cannot be allocated.
      */
     inline Value *getStackLimit(JSContext *cx, MaybeReportError report);
     bool tryBumpLimit(JSContext *cx, Value *from, unsigned nvals, Value **limit);
 
     /* Called during GC: mark segments, frames, and slots under firstUnused. */
-    void markAndClobber(JSTracer *trc);
+    void mark(JSTracer *trc);
 
     /* Called during GC: sets active flag on compartments with active frames. */
     void markActiveCompartments();
 
     /*
      * On Windows, report the committed size; on *nix, we report the resident
      * size (which means that if part of the stack is swapped to disk, we say
      * it's shrunk).
--- a/js/xpconnect/src/dictionary_helper_gen.conf
+++ b/js/xpconnect/src/dictionary_helper_gen.conf
@@ -6,18 +6,16 @@
 dictionaries = [
      [ 'EventInit', 'nsIDOMEvent.idl' ],
      [ 'UIEventInit', 'nsIDOMUIEvent.idl' ],
      [ 'MouseEventInit', 'nsIDOMMouseEvent.idl' ],
      [ 'WheelEventInit', 'nsIDOMWheelEvent.idl' ],
      [ 'IDBObjectStoreParameters', 'nsIIDBDatabase.idl' ],
      [ 'IDBIndexParameters', 'nsIIDBObjectStore.idl' ],
      [ 'MutationObserverInit', 'nsIDOMMutationObserver.idl' ],
-     [ 'WifiConnectionInfoEventInit', 'nsIWifiEventInits.idl' ],
-     [ 'WifiStatusChangeEventInit', 'nsIWifiEventInits.idl' ],
      [ 'GeoPositionOptions', 'nsIDOMGeoGeolocation.idl' ],
      [ 'DOMFileMetadataParameters', 'nsIDOMLockedFile.idl' ],
      [ 'XMLHttpRequestParameters', 'nsIXMLHttpRequest.idl' ],
      [ 'DeviceStorageEnumerationParameters', 'nsIDOMDeviceStorage.idl' ],
      [ 'CameraSize', 'nsIDOMCameraManager.idl' ],
      [ 'CameraRegion', 'nsIDOMCameraManager.idl' ],
      [ 'CameraPosition', 'nsIDOMCameraManager.idl' ],
      [ 'CameraSelector', 'nsIDOMCameraManager.idl' ],
--- a/js/xpconnect/src/event_impl_gen.conf.in
+++ b/js/xpconnect/src/event_impl_gen.conf.in
@@ -23,16 +23,18 @@ simple_events = [
     'DeviceLightEvent',
     'MozApplicationEvent',
 #ifdef MOZ_B2G_BT
     'BluetoothDeviceEvent',
     'BluetoothDeviceAddressEvent',
 #endif
 #ifdef MOZ_B2G_RIL
     'ICCCardLockErrorEvent',
+    'MozWifiStatusChangeEvent',
+    'MozWifiConnectionInfoEvent',
 #endif
     'DeviceStorageChangeEvent',
     'PopupBlockedEvent'
   ]
 
 """ include file names """
 special_includes = [
     'DictionaryHelpers.h',
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -1938,18 +1938,17 @@ PaintInactiveLayer(nsDisplayListBuilder*
     }
   } else {
     basic->EndTransaction(FrameLayerBuilder::DrawThebesLayer, aBuilder);
   }
   FrameLayerBuilder *builder = static_cast<FrameLayerBuilder*>(basic->GetUserData(&gLayerManagerLayerBuilder));
   if (builder) {
     builder->DidEndTransaction();
   }
- 
-  basic->SetUserData(&gLayerManagerLayerBuilder, NULL);
+
 #ifdef MOZ_DUMP_PAINTING
   if (gfxUtils::sDumpPainting) {
     DumpPaintedImage(aItem, surf);
 
     surf->SetDeviceOffset(gfxPoint(0, 0));
     aContext->SetSource(surf, itemVisibleRect.TopLeft());
     aContext->Rectangle(itemVisibleRect);
     aContext->Fill();
@@ -2335,17 +2334,17 @@ FrameLayerBuilder::AddThebesDisplayItem(
   if (aLayerState != LAYER_NONE) {
     DisplayItemData *data = GetDisplayItemDataForManager(aItem, aLayer->Manager());
     if (data) {
       tempManager = data->mInactiveManager;
     }
     if (!tempManager) {
       tempManager = new BasicLayerManager();
     }
-        
+
     // We need to grab these before calling AddLayerDisplayItem because it will overwrite them.
     nsRegion clip;
     FrameLayerBuilder::Clip* oldClip = nullptr;
     GetOldLayerFor(aItem, nullptr, &oldClip);
     hasClip = ComputeCombinedClip(aClip, oldClip, 
                                   aTopLeft - thebesData->mLastActiveScrolledRootOrigin,
                                   clip);
 
@@ -2418,17 +2417,17 @@ FrameLayerBuilder::AddThebesDisplayItem(
         invalid.ScaleRoundOut(thebesData->mXScale, thebesData->mYScale);
         InvalidatePostTransformRegion(aLayer, invalid,
                                       GetTranslationForThebesLayer(aLayer));
       }
     }
     ClippedDisplayItem* cdi =
       entry->mItems.AppendElement(ClippedDisplayItem(aItem, aClip,
                                                      mContainerLayerGeneration));
-    cdi->mInactiveLayer = tempManager;
+    cdi->mInactiveLayerManager = tempManager;
   }
 }
 
 FrameLayerBuilder::DisplayItemData*
 FrameLayerBuilder::StoreDataForFrame(nsDisplayItem* aItem, Layer* aLayer, LayerState aState)
 {
   DisplayItemData* oldData = GetDisplayItemDataForManager(aItem, mRetainingManager);
   if (oldData) {
@@ -2479,21 +2478,21 @@ FrameLayerBuilder::StoreDataForFrame(nsI
 
   data->AddFrame(aFrame);
 
   lmd->mDisplayItems.PutEntry(data);
 }
 
 FrameLayerBuilder::ClippedDisplayItem::~ClippedDisplayItem()
 {
-  if (mInactiveLayer) {
+  if (mInactiveLayerManager) {
     // We always start a transaction during layer construction for all inactive
     // layers, but we don't necessarily call EndTransaction during painting.
     // If the transaaction is still open, end it to avoid assertions.
-    BasicLayerManager* basic = static_cast<BasicLayerManager*>(mInactiveLayer.get());
+    BasicLayerManager* basic = static_cast<BasicLayerManager*>(mInactiveLayerManager.get());
     if (basic->InTransaction()) {
       basic->EndTransaction(nullptr, nullptr);
     }
     basic->SetUserData(&gLayerManagerLayerBuilder, nullptr);
   }
 }
 
 void
@@ -3106,16 +3105,17 @@ FrameLayerBuilder::DrawThebesLayer(Thebe
                                    void* aCallbackData)
 {
   SAMPLE_LABEL("gfx", "DrawThebesLayer");
 
   nsDisplayListBuilder* builder = static_cast<nsDisplayListBuilder*>
     (aCallbackData);
 
   FrameLayerBuilder *layerBuilder = aLayer->Manager()->GetLayerBuilder();
+  NS_ASSERTION(layerBuilder, "Unexpectedly null layer builder!");
 
   if (layerBuilder->CheckDOMModified())
     return;
 
   nsTArray<ClippedDisplayItem> items;
   uint32_t commonClipCount;
   nsIFrame* containerLayerFrame;
   {
@@ -3233,18 +3233,18 @@ FrameLayerBuilder::DrawThebesLayer(Thebe
         currentClip = cdi->mClip;
         aContext->Save();
         NS_ASSERTION(commonClipCount < 100,
           "Maybe you really do have more than a hundred clipping rounded rects, or maybe something has gone wrong.");
         currentClip.ApplyTo(aContext, presContext, commonClipCount);
       }
     }
 
-    if (cdi->mInactiveLayer) {
-      PaintInactiveLayer(builder, cdi->mInactiveLayer, cdi->mItem, aContext, rc);
+    if (cdi->mInactiveLayerManager) {
+      PaintInactiveLayer(builder, cdi->mInactiveLayerManager, cdi->mItem, aContext, rc);
     } else {
       nsIFrame* frame = cdi->mItem->GetUnderlyingFrame();
       if (frame) {
         frame->AddStateBits(NS_FRAME_PAINTED_THEBES);
       }
 #ifdef MOZ_DUMP_PAINTING
 
       if (gfxUtils::sDumpPainting) {
--- a/layout/base/FrameLayerBuilder.h
+++ b/layout/base/FrameLayerBuilder.h
@@ -604,17 +604,17 @@ protected:
 
     nsDisplayItem* mItem;
 
     /**
      * If the display item is being rendered as an inactive
      * layer, then this stores the layer manager being
      * used for the inactive transaction.
      */
-    nsRefPtr<LayerManager> mInactiveLayer;
+    nsRefPtr<LayerManager> mInactiveLayerManager;
 
     Clip mClip;
     uint32_t mContainerLayerGeneration;
   };
 
   /**
    * We accumulate ClippedDisplayItem elements in a hashtable during
    * the paint process. This is the hashentry for that hashtable.
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -1009,16 +1009,19 @@ void nsDisplayList::PaintForFrame(nsDisp
   if (!layerManager) {
     if (!aCtx) {
       NS_WARNING("Nowhere to paint into");
       return;
     }
     layerManager = new BasicLayerManager();
   }
 
+  // Store the existing layer builder to reinstate it on return.
+  FrameLayerBuilder *oldBuilder = layerManager->GetLayerBuilder();
+
   FrameLayerBuilder *layerBuilder = new FrameLayerBuilder();
   layerBuilder->Init(aBuilder, layerManager);
 
   if (aFlags & PAINT_FLUSH_LAYERS) {
     FrameLayerBuilder::InvalidateAllLayers(layerManager);
   }
 
   if (doBeginTransaction) {
@@ -1045,23 +1048,23 @@ void nsDisplayList::PaintForFrame(nsDisp
                                      LayerProperties::CloneFrom(layerManager->GetRoot()) : 
                                      nullptr);
 
   nsDisplayItem::ContainerParameters containerParameters
     (presShell->GetXResolution(), presShell->GetYResolution());
   nsRefPtr<ContainerLayer> root = layerBuilder->
     BuildContainerLayerFor(aBuilder, layerManager, aForFrame, nullptr, *this,
                            containerParameters, nullptr);
-  
+
   if (widgetTransaction) {
     aForFrame->ClearInvalidationStateBits();
   }
 
   if (!root) {
-    layerManager->RemoveUserData(&gLayerManagerLayerBuilder);
+    layerManager->SetUserData(&gLayerManagerLayerBuilder, oldBuilder);
     return;
   }
   // Root is being scaled up by the X/Y resolution. Scale it back down.
   root->SetPostScale(1.0f/containerParameters.mXScale,
                      1.0f/containerParameters.mYScale);
 
   ViewID id = presContext->IsRootContentDocument() ? FrameMetrics::ROOT_SCROLL_ID
                                                    : FrameMetrics::NULL_SCROLL_ID;
@@ -1130,17 +1133,17 @@ void nsDisplayList::PaintForFrame(nsDisp
     }
   }
 
   if (aFlags & PAINT_FLUSH_LAYERS) {
     FrameLayerBuilder::InvalidateAllLayers(layerManager);
   }
 
   nsCSSRendering::DidPaint();
-  layerManager->RemoveUserData(&gLayerManagerLayerBuilder);
+  layerManager->SetUserData(&gLayerManagerLayerBuilder, oldBuilder);
 }
 
 uint32_t nsDisplayList::Count() const {
   uint32_t count = 0;
   for (nsDisplayItem* i = GetBottom(); i; i = i->GetAbove()) {
     ++count;
   }
   return count;
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -86,16 +86,17 @@
 #include "nsIControllerCommandTable.h"
 #include "nsJSProtocolHandler.h"
 #include "nsScriptNameSpaceManager.h"
 #include "nsIControllerContext.h"
 #include "nsDOMScriptObjectFactory.h"
 #include "nsDOMStorage.h"
 #include "nsJSON.h"
 #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
+#include "mozIApplicationClearPrivateDataParams.h"
 #include "mozilla/dom/DOMRequest.h"
 #include "mozilla/OSFileConstants.h"
 #include "mozilla/dom/Activity.h"
 #include "mozilla/dom/network/TCPSocketChild.h"
 
 #ifdef MOZ_B2G_RIL
 #include "SystemWorkerManager.h"
 using mozilla::dom::gonk::SystemWorkerManager;
@@ -1291,16 +1292,17 @@ static const mozilla::Module::CategoryEn
 #endif
   { "content-policy", NS_DATADOCUMENTCONTENTPOLICY_CONTRACTID, NS_DATADOCUMENTCONTENTPOLICY_CONTRACTID },
   { "content-policy", NS_NODATAPROTOCOLCONTENTPOLICY_CONTRACTID, NS_NODATAPROTOCOLCONTENTPOLICY_CONTRACTID },
   { "content-policy", "CSPService", CSPSERVICE_CONTRACTID },
   { "content-policy", NS_MIXEDCONTENTBLOCKER_CONTRACTID, NS_MIXEDCONTENTBLOCKER_CONTRACTID },
   { "net-channel-event-sinks", "CSPService", CSPSERVICE_CONTRACTID },
   { JAVASCRIPT_GLOBAL_STATIC_NAMESET_CATEGORY, "PrivilegeManager", NS_SECURITYNAMESET_CONTRACTID },
   { "app-startup", "Script Security Manager", "service," NS_SCRIPTSECURITYMANAGER_CONTRACTID },
+  { TOPIC_WEB_APP_CLEAR_DATA, "IndexedDatabaseManager", "service," INDEXEDDB_MANAGER_CONTRACTID },
 #ifdef MOZ_WIDGET_GONK
   { "app-startup", "Volume Service", "service," NS_VOLUMESERVICE_CONTRACTID },
 #endif
   CONTENTDLF_CATEGORIES
 #ifdef MOZ_B2G_RIL
   { "profile-after-change", "Telephony System Worker Manager", SYSTEMWORKERMANAGER_CONTRACTID },
 #endif
 #ifdef MOZ_B2G_BT
--- a/layout/reftests/canvas/reftest.list
+++ b/layout/reftests/canvas/reftest.list
@@ -44,16 +44,19 @@ asserts-if(cocoaWidget,0-2) == size-chan
 == text-bidi-rtl-test.html text-bidi-rtl-ref.html
 
 fails-if(Android) != text-font-lang.html text-font-lang-notref.html
 
 == text-measure.html text-measure-ref.html
 
 == strokeText-path.html strokeText-path-ref.html
 
+# check that emoji character renders as something non-blank (for Apple Color Emoji font, bug 715798)
+random-if(!cocoaWidget) fails-if(OSX==10.6) random-if(OSX==10.7) != text-emoji.html text-emoji-notref.html
+
 # azure quartz uses CGDrawLinearGradient instead of DrawShading
 # so we have less control over degenerate behaviour as tested by this
 # test
 fails-if(azureQuartz) == linear-gradient-1a.html linear-gradient-1-ref.html
 
 # this passes with cairo on 10.7 and 10.8 but not with azure for reasons unknown
 fails-if(OSX==10.6||(azureQuartz&&(OSX==10.7||OSX==10.8))) == linear-gradient-1b.html linear-gradient-1-ref.html
 
new file mode 100644
--- /dev/null
+++ b/layout/reftests/canvas/text-emoji-notref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Test for Unicode emoji in canvas</title>
+<script type="text/javascript">
+function test(canvasID) {
+  var canvas = document.getElementById(canvasID);
+  var ctx = canvas.getContext('2d');
+  var str = 'Hello';
+  ctx.font = '2em sans-serif';
+  ctx.fillStyle = 'black';
+  ctx.textAlign = 'left';
+  ctx.textBaseline = 'top';
+  ctx.fillText(str, 10, 10);
+};
+</script>
+</head>
+<body>
+
+<div lang="en" style="margin:20px; height:100px;">
+<canvas id="c1" width="400" height="50"></canvas>
+<script type="text/javascript">
+  test("c1");
+</script>
+</div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/canvas/text-emoji.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Test for Unicode emoji in canvas</title>
+<script type="text/javascript">
+function test(canvasID) {
+  var canvas = document.getElementById(canvasID);
+  var ctx = canvas.getContext('2d');
+  var str = 'Hello \uD83D\uDE0E'; // U+1F60E
+  ctx.font = '2em sans-serif';
+  ctx.fillStyle = 'black';
+  ctx.textAlign = 'left';
+  ctx.textBaseline = 'top';
+  ctx.fillText(str, 10, 10);
+};
+</script>
+</head>
+<body>
+
+<div lang="en" style="margin:20px; height:100px;">
+<canvas id="c1" width="400" height="50"></canvas>
+<script type="text/javascript">
+  test("c1");
+</script>
+</div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/emoji-01-notref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Check that emoji char renders something visible (bug 715798, bug 779042)</title>
+<style type="text/css">
+body {
+  margin: 10px;
+  font-size: 40px;
+  line-height: 2em;
+}
+</style>
+</head>
+<body>
+<div>
+U+1F603:
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/emoji-01.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Check that emoji char renders something visible (bug 715798, bug 779042)</title>
+<style type="text/css">
+body {
+  margin: 10px;
+  font-size: 40px;
+  line-height: 2em;
+}
+</style>
+</head>
+<body>
+<div>
+U+1F603: &#x1F603;
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/emoji-02-notref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Check that HUGE emoji char renders something visible (bug 715798, bug 779042)</title>
+<style type="text/css">
+body {
+  margin: 10px;
+  font-size: 40px;
+  line-height: 600px;
+}
+</style>
+</head>
+<body>
+<div>
+U+1F633: <span style="font-size:400px">&nbsp;</span>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/emoji-02.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Check that HUGE emoji char renders something visible (bug 715798, bug 779042)</title>
+<style type="text/css">
+body {
+  margin: 10px;
+  font-size: 40px;
+  line-height: 600px;
+}
+</style>
+</head>
+<body>
+<div>
+U+1F633: <span style="font-size:400px">&#x1F633;</span>
+</div>
+</body>
+</html>
--- a/layout/reftests/text/reftest.list
+++ b/layout/reftests/text/reftest.list
@@ -157,16 +157,21 @@ fails-if(cocoaWidget) HTTP(..) == arabic
 fails-if(!cocoaWidget) HTTP(..) != arabic-fallback-4.html arabic-fallback-4-notref.html
 
 == 726392-1.html 726392-1-ref.html
 == 726392-2.html 726392-2-ref.html
 == 726392-3.html 726392-3-ref.html
 == 745555-1.html 745555-1-ref.html
 == 745555-2.html 745555-2-ref.html
 
+# ensure emoji chars don't render blank (bug 715798, bug 779042);
+# should at least render hexboxes if there's no font support
+!= emoji-01.html emoji-01-notref.html
+!= emoji-02.html emoji-02-notref.html
+
 # tests to compare graphite to opentype (will trivially pass when graphite not enabled)
 HTTP(..) == graphite-05-ot-only.html graphite-05-ref.html
 HTTP(..) != graphite-05-ot-only.html graphite-05-fail.html
 HTTP(..) == graphite-05-simple.html graphite-05-ref.html
 HTTP(..) == graphite-05-multipass.html graphite-05-ref.html
 HTTP(..) == graphite-05-lang.html graphite-05-ref.html
 HTTP(..) == graphite-05-badlang.html graphite-05-ref.html
 HTTP(..) == graphite-05-feat.html graphite-05-ref.html
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -2998,18 +2998,19 @@ nsRuleNode::SetFont(nsPresContext* aPres
 
   // Fall back to defaultVariableFont.
   nsFont systemFont = *defaultVariableFont;
   const nsCSSValue* systemFontValue = aRuleData->ValueForSystemFont();
   if (eCSSUnit_Enumerated == systemFontValue->GetUnit()) {
     gfxFontStyle fontStyle;
     LookAndFeel::FontID fontID =
       (LookAndFeel::FontID)systemFontValue->GetIntValue();
-    float devPerCSS = (float)nsPresContext::AppUnitsPerCSSPixel() /
-                      aPresContext->AppUnitsPerDevPixel();
+    float devPerCSS =
+      (float)nsPresContext::AppUnitsPerCSSPixel() /
+      aPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
     if (LookAndFeel::GetFont(fontID, systemFont.name, fontStyle, devPerCSS)) {
       systemFont.style = fontStyle.style;
       systemFont.systemFont = fontStyle.systemFont;
       systemFont.variant = NS_FONT_VARIANT_NORMAL;
       systemFont.weight = fontStyle.weight;
       systemFont.stretch = fontStyle.stretch;
       systemFont.decorations = NS_FONT_DECORATION_NONE;
       systemFont.size = NSFloatPixelsToAppUnits(fontStyle.size,
--- a/layout/xul/base/public/nsIPopupBoxObject.idl
+++ b/layout/xul/base/public/nsIPopupBoxObject.idl
@@ -5,17 +5,17 @@
 
 #include "nsIBoxObject.idl"
 
 interface nsIDOMElement;
 interface nsIDOMNode;
 interface nsIDOMEvent;
 interface nsIDOMClientRect;
 
-[scriptable, uuid(6AD1B199-95D3-448B-98D7-896BCE3A1DCD)]
+[scriptable, uuid(ACCEA57B-C3D8-4B6E-9101-90F04EE9DEA0)]
 interface nsIPopupBoxObject : nsISupports
 {
   /**
    *  This method is deprecated. Use openPopup or openPopupAtScreen instead.
    */
   void showPopup(in nsIDOMElement srcContent, in nsIDOMElement popupContent,
                  in long xpos, in long ypos,
                  in wstring popupType, in wstring anchorAlignment, 
@@ -146,20 +146,30 @@ interface nsIPopupBoxObject : nsISupport
   readonly attribute nsIDOMNode triggerNode;
 
   /**
    * Retrieve the anchor that was specified to openPopup or for menupopups in a
    * menu, the parent menu.
    */
   readonly attribute nsIDOMElement anchorNode;
 
-  /*
+  /**
    * Retrieve the screen rectangle of the popup, including the area occupied by
    * any titlebar or borders present.
    */
   nsIDOMClientRect getOuterScreenRect();
+
+  /**
+   * Move an open popup to the given anchor position. The arguments have the same
+   * meaning as the corresponding argument to openPopup. This method has no effect
+   * on popups that are not open.
+   */
+  void moveToAnchor(in nsIDOMElement anchorElement,
+                    in AString position,
+                    in long x, in long y,
+                    in boolean attributesOverride);
 };
 
 %{C++
 nsresult
 NS_NewPopupBoxObject(nsIBoxObject** aResult);
 
 %}
--- a/layout/xul/base/src/nsMenuPopupFrame.cpp
+++ b/layout/xul/base/src/nsMenuPopupFrame.cpp
@@ -1862,16 +1862,33 @@ nsMenuPopupFrame::MoveTo(int32_t aLeft, 
     nsAutoString left, top;
     left.AppendInt(aLeft);
     top.AppendInt(aTop);
     popup->SetAttr(kNameSpaceID_None, nsGkAtoms::left, left, false);
     popup->SetAttr(kNameSpaceID_None, nsGkAtoms::top, top, false);
   }
 }
 
+void
+nsMenuPopupFrame::MoveToAnchor(nsIContent* aAnchorContent,
+                               const nsAString& aPosition,
+                               int32_t aXPos, int32_t aYPos,
+                               bool aAttributesOverride)
+{
+  NS_ASSERTION(mPopupState == ePopupOpenAndVisible, "popup must be open to move it");
+
+  InitializePopup(aAnchorContent, mTriggerContent, aPosition,
+                  aXPos, aYPos, aAttributesOverride);
+  // InitializePopup changed the state so reset it.
+  mPopupState = ePopupOpenAndVisible;
+
+  // Pass false here so that flipping and adjusting to fit on the screen happen.
+  SetPopupPosition(nullptr, false);
+}
+
 bool
 nsMenuPopupFrame::GetAutoPosition()
 {
   return mShouldAutoPosition;
 }
 
 void
 nsMenuPopupFrame::SetAutoPosition(bool aShouldAutoPosition)
--- a/layout/xul/base/src/nsMenuPopupFrame.h
+++ b/layout/xul/base/src/nsMenuPopupFrame.h
@@ -264,16 +264,21 @@ public:
   void EnsureMenuItemIsVisible(nsMenuFrame* aMenuFrame);
 
   // Move the popup to the screen coordinate (aLeft, aTop) in CSS pixels.
   // If aUpdateAttrs is true, and the popup already has left or top attributes,
   // then those attributes are updated to the new location.
   // The frame may be destroyed by this method.
   void MoveTo(int32_t aLeft, int32_t aTop, bool aUpdateAttrs);
 
+  void MoveToAnchor(nsIContent* aAnchorContent,
+                    const nsAString& aPosition,
+                    int32_t aXPos, int32_t aYPos,
+                    bool aAttributesOverride);
+
   bool GetAutoPosition();
   void SetAutoPosition(bool aShouldAutoPosition);
   void SetConsumeRollupEvent(uint32_t aConsumeMode);
 
   nsIScrollableFrame* GetScrollFrame(nsIFrame* aStart);
 
   // For a popup that should appear anchored at the given rect, determine
   // the screen area that it is constrained by. This will be the available
--- a/layout/xul/base/src/nsPopupBoxObject.cpp
+++ b/layout/xul/base/src/nsPopupBoxObject.cpp
@@ -102,25 +102,44 @@ nsPopupBoxObject::OpenPopupAtScreen(int3
   if (pm && mContent)
     pm->ShowPopupAtScreen(mContent, aXPos, aYPos, aIsContextMenu, aTriggerEvent);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsPopupBoxObject::MoveTo(int32_t aLeft, int32_t aTop)
 {
-  nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(false));
+  nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
   if (menuPopupFrame) {
     menuPopupFrame->MoveTo(aLeft, aTop, true);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsPopupBoxObject::MoveToAnchor(nsIDOMElement* aAnchorElement,
+                               const nsAString& aPosition,
+                               int32_t aXPos, int32_t aYPos,
+                               bool aAttributesOverride)
+{
+  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+  if (pm && mContent) {
+    nsCOMPtr<nsIContent> anchorContent(do_QueryInterface(aAnchorElement));
+
+    nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(mContent->GetPrimaryFrame());
+    if (menuPopupFrame && menuPopupFrame->PopupState() == ePopupOpenAndVisible) {
+      menuPopupFrame->MoveToAnchor(anchorContent, aPosition, aXPos, aYPos, aAttributesOverride);
+    }
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsPopupBoxObject::SizeTo(int32_t aWidth, int32_t aHeight)
 {
   if (!mContent)
     return NS_OK;
 
   nsAutoString width, height;
   width.AppendInt(aWidth);
   height.AppendInt(aHeight);
@@ -130,28 +149,30 @@ nsPopupBoxObject::SizeTo(int32_t aWidth,
   content->SetAttr(kNameSpaceID_None, nsGkAtoms::height, height, true);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsPopupBoxObject::GetAutoPosition(bool* aShouldAutoPosition)
 {
-  nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(false));
+  *aShouldAutoPosition = true;
+
+  nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
   if (menuPopupFrame) {
     *aShouldAutoPosition = menuPopupFrame->GetAutoPosition();
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsPopupBoxObject::SetAutoPosition(bool aShouldAutoPosition)
 {
-  nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(false));
+  nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
   if (menuPopupFrame) {
     menuPopupFrame->SetAutoPosition(aShouldAutoPosition);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -189,17 +210,17 @@ nsPopupBoxObject::EnableKeyboardNavigato
 }
 
 NS_IMETHODIMP
 nsPopupBoxObject::GetPopupState(nsAString& aState)
 {
   // set this here in case there's no frame for the popup
   aState.AssignLiteral("closed");
 
-  nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(false));
+  nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
   if (menuPopupFrame) {
     switch (menuPopupFrame->PopupState()) {
       case ePopupShowing:
       case ePopupOpen:
         aState.AssignLiteral("showing");
         break;
       case ePopupOpenAndVisible:
         aState.AssignLiteral("open");
@@ -219,30 +240,30 @@ nsPopupBoxObject::GetPopupState(nsAStrin
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsPopupBoxObject::GetTriggerNode(nsIDOMNode** aTriggerNode)
 {
   *aTriggerNode = nullptr;
 
-  nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(false));
+  nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
   nsIContent* triggerContent = nsMenuPopupFrame::GetTriggerContent(menuPopupFrame);
   if (triggerContent)
     CallQueryInterface(triggerContent, aTriggerNode);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsPopupBoxObject::GetAnchorNode(nsIDOMElement** aAnchor)
 {
   *aAnchor = nullptr;
 
-  nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(false));
+  nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
   if (!menuPopupFrame)
     return NS_OK;
 
   nsIContent* anchor = menuPopupFrame->GetAnchor();
   if (anchor)
     CallQueryInterface(anchor, aAnchor);
 
   return NS_OK;
--- a/media/webrtc/signaling/include/CC_Call.h
+++ b/media/webrtc/signaling/include/CC_Call.h
@@ -265,17 +265,17 @@ namespace CSF
            @param [in] ip address - the ip address of the peer to call
 
            @return void
           */
         virtual void originateP2PCall (cc_sdp_direction_t video_pref, const std::string & digits, const std::string & ip) = 0;
 
         virtual void createOffer (const cc_media_constraints_t* constraints) = 0;
 
-        virtual void createAnswer(const cc_media_constraints_t* constraints, const std::string & offersdp) = 0;
+        virtual void createAnswer(const cc_media_constraints_t* constraints) = 0;
 
         virtual void setLocalDescription(cc_jsep_action_t action, const std::string & sdp) = 0;
 
         virtual void setRemoteDescription(cc_jsep_action_t action, const std::string & sdp) = 0;
 
         virtual void setPeerConnection(const std::string& handle) = 0;
 
         virtual void addStream(cc_media_stream_id_t stream_id, cc_media_track_id_t track_id, cc_media_type_t media_type) = 0;
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -75,28 +75,34 @@ void MediaConstraints::setBooleanConstra
 void MediaConstraints::buildArray(cc_media_constraints_t** constraintarray) {
 
   if (0 == mConstraints.size())
     return;
 
   short i = 0;
   std::string tmpStr;
   *constraintarray = (cc_media_constraints_t*) cpr_malloc(sizeof(cc_media_constraints_t));
+  int tmpStrAllocLength;
 
   (*constraintarray)->constraints = (cc_media_constraint_t**) cpr_malloc(mConstraints.size() * sizeof(cc_media_constraint_t));
 
   for (constraints_map::iterator it = mConstraints.begin();
           it != mConstraints.end(); ++it) {
     (*constraintarray)->constraints[i] = (cc_media_constraint_t*) cpr_malloc(sizeof(cc_media_constraint_t));
+
     tmpStr = it->first;
-    (*constraintarray)->constraints[i]->name = (char*) cpr_malloc(tmpStr.size());
-    sstrncpy((*constraintarray)->constraints[i]->name, tmpStr.c_str(), tmpStr.size()+1);
+    tmpStrAllocLength = tmpStr.size() + 1;
+    (*constraintarray)->constraints[i]->name = (char*) cpr_malloc(tmpStrAllocLength);
+    sstrncpy((*constraintarray)->constraints[i]->name, tmpStr.c_str(), tmpStrAllocLength);
+
     tmpStr = it->second.value;
-    (*constraintarray)->constraints[i]->value = (char*) cpr_malloc(tmpStr.size());
-    sstrncpy((*constraintarray)->constraints[i]->value, tmpStr.c_str(), tmpStr.size()+1);
+    tmpStrAllocLength = tmpStr.size() + 1;
+    (*constraintarray)->constraints[i]->value = (char*) cpr_malloc(tmpStrAllocLength);
+    sstrncpy((*constraintarray)->constraints[i]->value, tmpStr.c_str(), tmpStrAllocLength);
+
     (*constraintarray)->constraints[i]->mandatory = it->second.mandatory;
     i++;
   }
   (*constraintarray)->constraint_count = i;
 }
 
 typedef enum {
   PC_OBSERVER_CALLBACK,
@@ -747,36 +753,38 @@ PeerConnectionImpl::CreateOffer(MediaCon
 
   mCall->createOffer(cc_constraints);
   return NS_OK;
 }
 
 /*
  * the Constraints UI IDL work is being done. The CreateAnswer below is the one
  * currently called by the signaling unit tests.
+ *
+ * The aOffer parameter needs to be removed here and in the PeerConnection IDL
  */
+
 NS_IMETHODIMP
 PeerConnectionImpl::CreateAnswer(const char* constraints, const char* aOffer) {
   MOZ_ASSERT(constraints);
-  MOZ_ASSERT(aOffer);
 
   CheckIceState();
   mRole = kRoleAnswerer;  // TODO(ekr@rtfm.com): Interrogate SIPCC here?
   MediaConstraints aconstraints;
-  CreateAnswer(aconstraints, aOffer);
+  CreateAnswer(aconstraints);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-PeerConnectionImpl::CreateAnswer(MediaConstraints& constraints, const char* offer) {
+PeerConnectionImpl::CreateAnswer(MediaConstraints& constraints) {
 
   cc_media_constraints_t* cc_constraints = nullptr;
   constraints.buildArray(&cc_constraints);
 
-  mCall->createAnswer(cc_constraints, offer);
+  mCall->createAnswer(cc_constraints);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PeerConnectionImpl::SetLocalDescription(int32_t aAction, const char* aSDP) {
   if (!aSDP) {
     CSFLogError(logTag, "%s - aSDP is NULL", __FUNCTION__);
     return NS_ERROR_FAILURE;
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
@@ -393,17 +393,17 @@ public:
 
   // Create a fake media stream
   nsresult CreateFakeMediaStream(uint32_t hint, nsIDOMMediaStream** retval);
 
   nsPIDOMWindow* GetWindow() const { return mWindow; }
 
   NS_IMETHODIMP CreateOffer(MediaConstraints& constraints);
 
-  NS_IMETHODIMP CreateAnswer(MediaConstraints& constraints, const char* offer);
+  NS_IMETHODIMP CreateAnswer(MediaConstraints& constraints);
 
 private:
   PeerConnectionImpl(const PeerConnectionImpl&rhs);
   PeerConnectionImpl& operator=(PeerConnectionImpl);
 
   void ChangeReadyState(ReadyState aReadyState);
   void CheckIceState() {
     PR_ASSERT(mIceState != kIceGathering);
--- a/media/webrtc/signaling/src/sipcc/core/ccapp/cc_call_feature.c
+++ b/media/webrtc/signaling/src/sipcc/core/ccapp/cc_call_feature.c
@@ -142,17 +142,16 @@ cc_return_t cc_invokeFeatureSDPMode(cc_c
     case CC_FEATURE_DIALSTR:
     case CC_FEATURE_SPEEDDIAL:
     case CC_FEATURE_BLIND_XFER_WITH_DIALSTRING:
     case CC_FEATURE_END_CALL:
     case CC_FEATURE_B2BCONF:
     case CC_FEATURE_CONF:
     case CC_FEATURE_XFER:
     case CC_FEATURE_HOLD:
-    case CC_FEATURE_CREATEANSWER:
     case CC_FEATURE_SETLOCALDESC:
     case CC_FEATURE_SETREMOTEDESC:
     case CC_FEATURE_SETPEERCONNECTION:
     	callFeature.featData.ccData.info = strlib_malloc(data, strlen(data));
         callFeature.featData.ccData.info1 = NULL;
     	break;
     case CC_FEATURE_ADDICECANDIDATE:
     	callFeature.featData.ccData.info = strlib_malloc(data, strlen(data));
@@ -299,22 +298,22 @@ cc_return_t CC_CallFeature_dial(cc_call_
 cc_return_t CC_CallFeature_CreateOffer(cc_call_handle_t call_handle, const cc_media_constraints_t *constraints) {
     CCAPP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(SIP_CC_PROV, GET_CALL_ID(call_handle),
                 GET_LINE_ID(call_handle), __FUNCTION__));
 
     return cc_invokeFeatureSDPMode(call_handle, CC_FEATURE_CREATEOFFER, JSEP_NO_ACTION,
                                    0, 0, NO_STREAM, 0, constraints, NULL, NULL);
 }
 
-cc_return_t CC_CallFeature_CreateAnswer(cc_call_handle_t call_handle, const cc_media_constraints_t *constraints, string_t sdp) {
+cc_return_t CC_CallFeature_CreateAnswer(cc_call_handle_t call_handle, const cc_media_constraints_t *constraints) {
     CCAPP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(SIP_CC_PROV, GET_CALL_ID(call_handle),
                 GET_LINE_ID(call_handle), __FUNCTION__));
 
     return cc_invokeFeatureSDPMode(call_handle, CC_FEATURE_CREATEANSWER, JSEP_NO_ACTION,
-                                   0, 0, NO_STREAM, 0, constraints, sdp, NULL);
+                                   0, 0, NO_STREAM, 0, constraints, NULL, NULL);
 }
 
 cc_return_t CC_CallFeature_SetLocalDescription(cc_call_handle_t call_handle, cc_jsep_action_t action, string_t sdp) {
     const cc_media_constraints_t *constraints = NULL;
     CCAPP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(SIP_CC_PROV, GET_CALL_ID(call_handle),
             GET_LINE_ID(call_handle), __FUNCTION__));
 
     return cc_invokeFeatureSDPMode(call_handle, CC_FEATURE_SETLOCALDESC, action,
--- a/media/webrtc/signaling/src/sipcc/core/ccapp/ccapi_call.c
+++ b/media/webrtc/signaling/src/sipcc/core/ccapp/ccapi_call.c
@@ -89,18 +89,18 @@ cc_lineid_t CCAPI_Call_getLine(cc_call_h
 cc_return_t CCAPI_Call_originateCall(cc_call_handle_t handle, cc_sdp_direction_t video_pref, cc_string_t digits){
 	return CC_CallFeature_dial(handle, video_pref, digits);
 }
 
 cc_return_t CCAPI_CreateOffer(cc_call_handle_t handle, const cc_media_constraints_t *constraints) {
 	return CC_CallFeature_CreateOffer(handle, constraints);
 }
 
-cc_return_t CCAPI_CreateAnswer(cc_call_handle_t handle, const cc_media_constraints_t *constraints, cc_string_t offersdp) {
-	return CC_CallFeature_CreateAnswer(handle, constraints, offersdp);
+cc_return_t CCAPI_CreateAnswer(cc_call_handle_t handle, const cc_media_constraints_t *constraints) {
+	return CC_CallFeature_CreateAnswer(handle, constraints);
 }
 
 cc_return_t CCAPI_SetLocalDescription(cc_call_handle_t handle, cc_jsep_action_t action, cc_string_t sdp) {
 	return CC_CallFeature_SetLocalDescription(handle, action, sdp);
 }
 
 cc_return_t CCAPI_SetRemoteDescription(cc_call_handle_t handle, cc_jsep_action_t action, cc_string_t sdp) {
     return CC_CallFeature_SetRemoteDescription(handle, action, sdp);
--- a/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c
+++ b/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c
@@ -1582,19 +1582,18 @@ gsmsdp_set_rtcp_mux_attribute (sdp_attr_
 static void
 gsmsdp_set_dtls_fingerprint_attribute (sdp_attr_e sdp_attr, uint16_t level, void *sdp_p,
   char *hash_func,char *fingerprint)
 {
     uint16_t      a_instance = 0;
     sdp_result_e  result;
     char hash_and_fingerprint[FSMDEF_MAX_DIGEST_ALG_LEN + FSMDEF_MAX_DIGEST_LEN + 2];
 
-    sstrncpy(hash_and_fingerprint, (cc_string_t)hash_func, FSMDEF_MAX_DIGEST_ALG_LEN);
-    sstrncat(hash_and_fingerprint, (cc_string_t)" ", sizeof(hash_and_fingerprint) - strlen(hash_and_fingerprint) - 1);
-    sstrncat(hash_and_fingerprint, (cc_string_t)fingerprint, FSMDEF_MAX_DIGEST_LEN);
+    snprintf(hash_and_fingerprint, sizeof(hash_and_fingerprint),
+         "%s %s", hash_func, fingerprint);
 
     result = sdp_add_new_attr(sdp_p, level, 0, sdp_attr, &a_instance);
     if (result != SDP_SUCCESS) {
         GSM_ERR_MSG("Failed to add attribute\n");
         return;
     }
 
     result = sdp_attr_set_dtls_fingerprint_attribute(sdp_p, level, 0, sdp_attr, a_instance, hash_and_fingerprint);
--- a/media/webrtc/signaling/src/sipcc/include/cc_call_feature.h
+++ b/media/webrtc/signaling/src/sipcc/include/cc_call_feature.h
@@ -148,17 +148,17 @@ cc_return_t CC_CallFeature_backSpace(cc_
  * @param video_pref the sdp direction
  * @param numbers dialed string
  * @return SUCCESS or FAILURE
  */
 cc_return_t CC_CallFeature_dial(cc_call_handle_t call_handle, cc_sdp_direction_t video_pref, const cc_string_t numbers);
 
 cc_return_t CC_CallFeature_CreateOffer(cc_call_handle_t call_handle, const cc_media_constraints_t *constraints);
 
-cc_return_t CC_CallFeature_CreateAnswer(cc_call_handle_t call_handle, const cc_media_constraints_t *constraints, const char* sdp);
+cc_return_t CC_CallFeature_CreateAnswer(cc_call_handle_t call_handle, const cc_media_constraints_t *constraints);
 
 cc_return_t CC_CallFeature_SetLocalDescription(cc_call_handle_t call_handle, cc_jsep_action_t action, const char* sdp);
 
 cc_return_t CC_CallFeature_SetRemoteDescription(cc_call_handle_t call_handle, cc_jsep_action_t action, const char* sdp);
 
 cc_return_t CC_CallFeature_SetPeerConnection(cc_call_handle_t call_handle, cc_peerconnection_t pc);
 
 cc_return_t CC_CallFeature_AddStream(cc_call_handle_t call_handle, cc_media_stream_id_t stream_id, cc_media_track_id_t id, cc_media_type_t media_type);
--- a/media/webrtc/signaling/src/sipcc/include/ccapi_call.h
+++ b/media/webrtc/signaling/src/sipcc/include/ccapi_call.h
@@ -45,17 +45,17 @@ cc_lineid_t CCAPI_Call_getLine(cc_call_h
  * @param [in] digits - digits to be dialed. can be empty then this API simply goes offhook
  * @return SUCCESS or FAILURE
  */
 cc_return_t CCAPI_Call_originateCall(cc_call_handle_t handle, cc_sdp_direction_t video_pref, cc_string_t digits);
 
 
 cc_return_t CCAPI_CreateOffer(cc_call_handle_t handle, const cc_media_constraints_t *constraints);
 
-cc_return_t CCAPI_CreateAnswer(cc_call_handle_t handle, const cc_media_constraints_t *constraints, cc_string_t offersdp);
+cc_return_t CCAPI_CreateAnswer(cc_call_handle_t handle, const cc_media_constraints_t *constraints);
 
 cc_return_t CCAPI_SetLocalDescription(cc_call_handle_t handle, cc_jsep_action_t action, cc_string_t sdp);
 
 cc_return_t CCAPI_SetRemoteDescription(cc_call_handle_t handle, cc_jsep_action_t action, cc_string_t sdp);
 
 cc_return_t CCAPI_SetPeerConnection(cc_call_handle_t handle, cc_peerconnection_t pc);
 
 cc_return_t CCAPI_AddStream(cc_call_handle_t handle, cc_media_stream_id_t stream_id, cc_media_track_id_t track_id, cc_media_type_t media_type);
--- a/media/webrtc/signaling/src/softphonewrapper/CC_SIPCCCall.cpp
+++ b/media/webrtc/signaling/src/softphonewrapper/CC_SIPCCCall.cpp
@@ -529,18 +529,19 @@ void CC_SIPCCCall::originateP2PCall (cc_
  * This method works asynchronously, is an onCallEvent with the resulting SDP
  */
 void CC_SIPCCCall::createOffer (const cc_media_constraints_t *constraints) {
     CCAPI_CreateOffer(callHandle, constraints);
 }
 /*
  * This method works asynchronously, there is onCallEvent with the resulting SDP
  */
-void CC_SIPCCCall::createAnswer (const cc_media_constraints_t *constraints, const std::string & offersdp) {
-    CCAPI_CreateAnswer(callHandle, constraints, offersdp.c_str());
+void CC_SIPCCCall::createAnswer (const cc_media_constraints_t *constraints) {
+    CCAPI_CreateAnswer(callHandle, constraints);
+
 }
 
 void CC_SIPCCCall::setLocalDescription(cc_jsep_action_t action, const std::string & sdp) {
     CCAPI_SetLocalDescription(callHandle, action, sdp.c_str());
 }
 
 void CC_SIPCCCall::setRemoteDescription(cc_jsep_action_t action, const std::string & sdp) {
     CCAPI_SetRemoteDescription(callHandle, action, sdp.c_str());
--- a/media/webrtc/signaling/src/softphonewrapper/CC_SIPCCCall.h
+++ b/media/webrtc/signaling/src/softphonewrapper/CC_SIPCCCall.h
@@ -106,17 +106,17 @@ namespace CSF
         virtual bool unmuteAudio();
         virtual bool muteVideo();
         virtual bool unmuteVideo();
         virtual void addStream(int streamId, bool isVideo);
         virtual void removeStream(int streamId);
         virtual bool setVolume(int volume);
         virtual void originateP2PCall (cc_sdp_direction_t video_pref, const std::string & digits, const std::string & ip);
         virtual void createOffer(const  cc_media_constraints_t *constraints);
-        virtual void createAnswer(const  cc_media_constraints_t *constraints, const std::string & offersdp);
+        virtual void createAnswer(const  cc_media_constraints_t *constraints);
         virtual void setLocalDescription(cc_jsep_action_t action, const std::string & sdp);
         virtual void setRemoteDescription(cc_jsep_action_t action, const std::string & sdp);
         virtual void setPeerConnection(const std::string& handle);
         virtual const std::string& getPeerConnection() const;
         virtual void addStream(cc_media_stream_id_t stream_id, cc_media_track_id_t track_id, cc_media_type_t media_type);
         virtual void removeStream(cc_media_stream_id_t stream_id, cc_media_track_id_t track_id, cc_media_type_t media_type);
         virtual CC_SIPCCCallMediaDataPtr getMediaData();
         virtual void addICECandidate(const std::string & candidate, const std::string & mid, unsigned short level);
--- a/media/webrtc/signaling/test/signaling_unittests.cpp
+++ b/media/webrtc/signaling/test/signaling_unittests.cpp
@@ -519,17 +519,17 @@ class SignalingAgent {
     offer_ = pObserver->lastString;
   }
 
   void CreateOfferExpectError(sipcc::MediaConstraints& constraints) {
     ASSERT_EQ(pc->CreateOffer(constraints), NS_OK);
     ASSERT_TRUE_WAIT(pObserver->state == TestObserver::stateError, kDefaultTimeout);
   }
 
-  void CreateAnswer(sipcc::MediaConstraints& constraints, std::string offer, bool audio, bool video) {
+  void CreateAnswer(sipcc::MediaConstraints& constraints, bool audio, bool video) {
     // Create a media stream as if it came from GUM
     nsRefPtr<nsDOMMediaStream> domMediaStream = new nsDOMMediaStream();
 
     uint32_t aHintContents = 0;
 
     if (audio) {
       aHintContents |= nsDOMMediaStream::HINT_CONTENTS_AUDIO;
     }
@@ -539,17 +539,17 @@ class SignalingAgent {
 
     PR_ASSERT(aHintContents);
 
     domMediaStream->SetHintContents(aHintContents);
 
     pc->AddStream(domMediaStream);
 
     pObserver->state = TestObserver::stateNoResponse;
-    ASSERT_EQ(pc->CreateAnswer(constraints, offer.c_str()), NS_OK);
+    ASSERT_EQ(pc->CreateAnswer(constraints, NS_OK);
     ASSERT_TRUE_WAIT(pObserver->state == TestObserver::stateSuccess, kDefaultTimeout);
     SDPSanityCheck(pObserver->lastString, audio, video, false);
     answer_ = pObserver->lastString;
   }
 
   void CreateOfferRemoveStream(sipcc::MediaConstraints& constraints, bool audio, bool video) {
 
     uint32_t aHintContents = 0;
@@ -675,47 +675,47 @@ public:
     a1_.SetLocal(TestObserver::OFFER, a1_.offer());
   }
 
   void OfferAnswer(sipcc::MediaConstraints& aconstraints, sipcc::MediaConstraints& bconstraints,
                        bool audio, bool video, bool finishAfterAnswer) {
     a1_.CreateOffer(aconstraints, audio, video);
     a1_.SetLocal(TestObserver::OFFER, a1_.offer());
     a2_.SetRemote(TestObserver::OFFER, a1_.offer());
-    a2_.CreateAnswer(bconstraints, a1_.offer(), audio, video);
+    a2_.CreateAnswer(bconstraints, audio, video);
     if(true == finishAfterAnswer) {
         a2_.SetLocal(TestObserver::ANSWER, a2_.answer());
         a1_.SetRemote(TestObserver::ANSWER, a2_.answer());
 
         ASSERT_TRUE_WAIT(a1_.IceCompleted() == true, kDefaultTimeout);
         ASSERT_TRUE_WAIT(a2_.IceCompleted() == true, kDefaultTimeout);
     }
   }
 
   void OfferModifiedAnswer(sipcc::MediaConstraints& aconstraints, sipcc::MediaConstraints& bconstraints) {
     a1_.CreateOffer(aconstraints, true, true);
     a1_.SetLocal(TestObserver::OFFER, a1_.offer());
     a2_.SetRemote(TestObserver::OFFER, a1_.offer());
-    a2_.CreateAnswer(bconstraints, a1_.offer(), true, true);
+    a2_.CreateAnswer(bconstraints, true, true);
     a2_.SetLocal(TestObserver::ANSWER, a2_.answer());
     ParsedSDP sdpWrapper(a2_.answer());
     sdpWrapper.ReplaceLine("m=audio", "m=audio 65375 RTP/SAVPF 109 8 101\r\n");
     sdpWrapper.AddLine("a=rtpmap:8 PCMA/8000\r\n");
     cout << "Modified SDP " << sdpWrapper.getSdp() << endl;
     a1_.SetRemote(TestObserver::ANSWER, sdpWrapper.getSdp());
     ASSERT_TRUE_WAIT(a1_.IceCompleted() == true, kDefaultTimeout);
     ASSERT_TRUE_WAIT(a2_.IceCompleted() == true, kDefaultTimeout);
   }
 
   void OfferAnswerTrickle(sipcc::MediaConstraints& aconstraints, sipcc::MediaConstraints& bconstraints) {
     a1_.CreateOffer(aconstraints, true, true);
     a1_.SetLocal(TestObserver::OFFER, a1_.offer());
     ParsedSDP a1_offer(a1_.offer());
     a2_.SetRemote(TestObserver::OFFER, a1_offer.sdp_without_ice_);
-    a2_.CreateAnswer(bconstraints, a1_offer.sdp_without_ice_, true, true);
+    a2_.CreateAnswer(bconstraints, true, true);
     a2_.SetLocal(TestObserver::ANSWER, a2_.answer());
     ParsedSDP a2_answer(a2_.answer());
     a1_.SetRemote(TestObserver::ANSWER, a2_answer.sdp_without_ice_);
     // Now set the trickle ICE candidates
     a1_.DoTrickleIce(a2_answer);
     a2_.DoTrickleIce(a1_offer);
     ASSERT_TRUE_WAIT(a1_.IceCompleted() == true, kDefaultTimeout);
     ASSERT_TRUE_WAIT(a2_.IceCompleted() == true, kDefaultTimeout);
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -338,17 +338,17 @@ pref("gfx.displayport.strategy_vb.revers
 pref("gfx.displayport.strategy_vb.danger_x_base", -1); // danger zone on x-axis when multiplied by viewport width
 pref("gfx.displayport.strategy_vb.danger_y_base", -1); // danger zone on y-axis when multiplied by viewport height
 pref("gfx.displayport.strategy_vb.danger_x_incr", -1); // additional danger zone on x-axis when multiplied by viewport width and velocity
 pref("gfx.displayport.strategy_vb.danger_y_incr", -1); // additional danger zone on y-axis when multiplied by viewport height and velocity
 
 // prediction bias strategy options
 pref("gfx.displayport.strategy_pb.threshold", -1); // velocity threshold in inches/frame
 
-pref("gfx.java.screenshot.enabled", true);
+pref("gfx.java.screenshot.enabled", false);
 
 // don't allow JS to move and resize existing windows
 pref("dom.disable_window_move_resize", true);
 
 // prevent click image resizing for nsImageDocument
 pref("browser.enable_click_image_resizing", false);
 
 // open in tab preferences
@@ -517,17 +517,17 @@ pref("editor.singleLine.pasteNewlines", 
 // threshold where a tap becomes a drag, in 1/240" reference pixels
 // The names of the preferences are to be in sync with nsEventStateManager.cpp
 pref("ui.dragThresholdX", 25);
 pref("ui.dragThresholdY", 25);
 
 pref("layers.acceleration.disabled", false);
 pref("layers.offmainthreadcomposition.enabled", true);
 pref("layers.async-video.enabled", true);
-pref("layers.progressive-paint", false);
+pref("layers.progressive-paint", true);
 
 pref("notification.feature.enabled", true);
 
 // prevent tooltips from showing up
 pref("browser.chrome.toolbar_tips", false);
 pref("indexedDB.feature.enabled", true);
 pref("dom.indexedDB.warningQuota", 5);
 
@@ -627,18 +627,16 @@ pref("ui.scrolling.overscroll_decel_rate
 // The fraction of the surface which can be overscrolled before it must snap back, in 1000ths.
 pref("ui.scrolling.overscroll_snap_limit", -1);
 // The minimum amount of space that must be present for an axis to be considered scrollable,
 // in 1/1000ths of pixels.
 pref("ui.scrolling.min_scrollable_distance", -1);
 
 // Enable accessibility mode if platform accessibility is enabled.
 pref("accessibility.accessfu.activate", 2);
-// Enable explore by touch if it is enabled in the platform
-pref("accessibility.accessfu.explorebytouch", 2);
 
 // Mobile manages state by autodetection
 pref("network.manage-offline-status", true);
 
 // increase the timeout clamp for background tabs to 15 minutes
 pref("dom.min_background_timeout_value", 900000);
 
 // The default of font size in reader (1-7)
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -292,107 +292,105 @@ abstract public class GeckoApp
                         vreader.close();
                     }
                 } catch (IOException ex) {
                     // nothing
                 }
             }
         }
 
-        Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - start of getPluginDirectories");
-
         ArrayList<String> directories = new ArrayList<String>();
         PackageManager pm = mAppContext.getPackageManager();
         List<ResolveInfo> plugins = pm.queryIntentServices(new Intent(PLUGIN_ACTION),
                 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
 
         synchronized(mPackageInfoCache) {
 
             // clear the list of existing packageInfo objects
             mPackageInfoCache.clear();
 
 
             for (ResolveInfo info : plugins) {
 
                 // retrieve the plugin's service information
                 ServiceInfo serviceInfo = info.serviceInfo;
                 if (serviceInfo == null) {
-                    Log.w(LOGTAG, "Ignore bad plugin");
+                    Log.w(LOGTAG, "Ignoring bad plugin.");
                     continue;
                 }
 
                 // Blacklist HTC's flash lite.
                 // See bug #704516 - We're not quite sure what Flash Lite does,
                 // but loading it causes Flash to give errors and fail to draw.
                 if (serviceInfo.packageName.equals("com.htc.flashliteplugin")) {
                     Log.w(LOGTAG, "Skipping HTC's flash lite plugin");
                     continue;
                 }
 
-                Log.w(LOGTAG, "Loading plugin: " + serviceInfo.packageName);
-
-
-                // retrieve information from the plugin's manifest
+
+                // Retrieve information from the plugin's manifest.
                 PackageInfo pkgInfo;
                 try {
                     pkgInfo = pm.getPackageInfo(serviceInfo.packageName,
                                     PackageManager.GET_PERMISSIONS
                                     | PackageManager.GET_SIGNATURES);
                 } catch (Exception e) {
                     Log.w(LOGTAG, "Can't find plugin: " + serviceInfo.packageName);
                     continue;
                 }
+
                 if (pkgInfo == null) {
-                    Log.w(LOGTAG, "Loading plugin: " + serviceInfo.packageName + ". Could not load package information.");
+                    Log.w(LOGTAG, "Not loading plugin: " + serviceInfo.packageName + ". Could not load package information.");
                     continue;
                 }
 
                 /*
                  * find the location of the plugin's shared library. The default
                  * is to assume the app is either a user installed app or an
                  * updated system app. In both of these cases the library is
                  * stored in the app's data directory.
                  */
                 String directory = pkgInfo.applicationInfo.dataDir + "/lib";
                 final int appFlags = pkgInfo.applicationInfo.flags;
                 final int updatedSystemFlags = ApplicationInfo.FLAG_SYSTEM |
                                                ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+
                 // preloaded system app with no user updates
                 if ((appFlags & updatedSystemFlags) == ApplicationInfo.FLAG_SYSTEM) {
                     directory = PLUGIN_SYSTEM_LIB + pkgInfo.packageName;
                 }
 
                 // check if the plugin has the required permissions
                 String permissions[] = pkgInfo.requestedPermissions;
                 if (permissions == null) {
-                    Log.w(LOGTAG, "Loading plugin: " + serviceInfo.packageName + ". Does not have required permission.");
+                    Log.w(LOGTAG, "Not loading plugin: " + serviceInfo.packageName + ". Does not have required permission.");
                     continue;
                 }
                 boolean permissionOk = false;
                 for (String permit : permissions) {
                     if (PLUGIN_PERMISSION.equals(permit)) {
                         permissionOk = true;
                         break;
                     }
                 }
                 if (!permissionOk) {
-                    Log.w(LOGTAG, "Loading plugin: " + serviceInfo.packageName + ". Does not have required permission (2).");
+                    Log.w(LOGTAG, "Not loading plugin: " + serviceInfo.packageName + ". Does not have required permission (2).");
                     continue;
                 }
 
                 // check to ensure the plugin is properly signed
                 Signature signatures[] = pkgInfo.signatures;
                 if (signatures == null) {
-                    Log.w(LOGTAG, "Loading plugin: " + serviceInfo.packageName + ". Not signed.");
+                    Log.w(LOGTAG, "Not loading plugin: " + serviceInfo.packageName + ". Not signed.");
                     continue;
                 }
 
                 // determine the type of plugin from the manifest
                 if (serviceInfo.metaData == null) {
-                    Log.e(LOGTAG, "The plugin '" + serviceInfo.name + "' has no type defined");
+                    Log.e(LOGTAG, "The plugin '" + serviceInfo.name + "' has no defined type.");
                     continue;
                 }
 
                 String pluginType = serviceInfo.metaData.getString(PLUGIN_TYPE);
                 if (!TYPE_NATIVE.equals(pluginType)) {
                     Log.e(LOGTAG, "Unrecognized plugin type: " + pluginType);
                     continue;
                 }
@@ -417,19 +415,17 @@ abstract public class GeckoApp
                 }
 
                 // if all checks have passed then make the plugin available
                 mPackageInfoCache.add(pkgInfo);
                 directories.add(directory);
             }
         }
 
-        String [] result = directories.toArray(new String[directories.size()]);
-        Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - end of getPluginDirectories");
-        return result;
+        return directories.toArray(new String[directories.size()]);
     }
 
     String getPluginPackage(String pluginLib) {
 
         if (pluginLib == null || pluginLib.length() == 0) {
             return null;
         }
 
@@ -694,18 +690,16 @@ abstract public class GeckoApp
             GeckoAppShell.openUriExternal(url, "text/plain", "", "",
                                           Intent.ACTION_SEND, tab.getDisplayTitle());
         }
     }
 
     protected void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
 
-        Log.i(LOGTAG, "onSaveInstanceState");
-
         if (outState == null)
             outState = new Bundle();
 
         Tab tab = Tabs.getInstance().getSelectedTab();
         if (tab != null)
             outState.putString(SAVED_STATE_TITLE, tab.getDisplayTitle());
 
         boolean inBackground =
@@ -740,17 +734,17 @@ abstract public class GeckoApp
             processThumbnail(tab, b, null);
         }
     }
 
     void processThumbnail(Tab thumbnailTab, Bitmap bitmap, byte[] compressed) {
         try {
             if (bitmap == null) {
                 if (compressed == null) {
-                    Log.e(LOGTAG, "processThumbnail: one of bitmap or compressed must be non-null!");
+                    Log.w(LOGTAG, "processThumbnail: one of bitmap or compressed must be non-null!");
                     return;
                 }
                 bitmap = BitmapFactory.decodeByteArray(compressed, 0, compressed.length);
             }
             thumbnailTab.updateThumbnail(bitmap);
         } catch (OutOfMemoryError ome) {
             Log.w(LOGTAG, "decoding byte array ran out of memory", ome);
         }
@@ -792,17 +786,17 @@ abstract public class GeckoApp
             public void onPostExecute(String faviconUrl) {
                 JSONObject args = new JSONObject();
 
                 if (faviconUrl != null) {
                     try {
                         args.put("url", url);
                         args.put("faviconUrl", faviconUrl);
                     } catch (JSONException e) {
-                        Log.e(LOGTAG, "error building json arguments");
+                        Log.w(LOGTAG, "Error building JSON favicon arguments.", e);
                     }
                 }
 
                 GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Reader:FaviconReturn", args.toString()));
             }
         }).execute();
     }
 
@@ -821,19 +815,21 @@ abstract public class GeckoApp
 
     void handlePageShow(final int tabId) { }
 
     void handleClearHistory() {
         BrowserDB.clearHistory(getContentResolver());
         getFavicons().clearFavicons();
     }
 
+    /**
+     * This function might perform synchronous IO. Don't call it
+     * from the main thread.
+     */
     public StartupMode getStartupMode() {
-        // This function might touch the disk and should not
-        // be called from UI's main thread.
 
         synchronized(this) {
             if (mStartupMode != null)
                 return mStartupMode;
 
             String packageName = getPackageName();
             SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE);
 
@@ -903,17 +899,16 @@ abstract public class GeckoApp
 
         if (Build.VERSION.SDK_INT >= 14)
             hasMenu = ViewConfiguration.get(GeckoApp.mAppContext).hasPermanentMenuKey();
 
         return hasMenu;
     }
 
     public void handleMessage(String event, JSONObject message) {
-        Log.i(LOGTAG, "Got message: " + event);
         try {
             if (event.equals("Toast:Show")) {
                 final String msg = message.getString("message");
                 final String duration = message.getString("duration");
                 handleShowToast(msg, duration);
             } else if (event.equals("DOMContentLoaded")) {
                 final int tabId = message.getInt("tabID");
                 final String backgroundColor = message.getString("bgColor");
@@ -943,17 +938,17 @@ abstract public class GeckoApp
                 final int size = message.getInt("size");
                 handleLinkAdded(tabId, rel, href, size);
             } else if (event.equals("DOMWindowClose")) {
                 final int tabId = message.getInt("tabID");
                 handleWindowClose(tabId);
             } else if (event.equals("log")) {
                 // generic log listener
                 final String msg = message.getString("msg");
-                Log.i(LOGTAG, "Log: " + msg);
+                Log.d(LOGTAG, "Log: " + msg);
             } else if (event.equals("Content:SecurityChange")) {
                 final int tabId = message.getInt("tabID");
                 final JSONObject identity = message.getJSONObject("identity");
                 Log.i(LOGTAG, "Security Mode - " + identity.getString("mode"));
                 handleSecurityChange(tabId, identity);
             } else if (event.equals("Content:ReaderEnabled")) {
                 final int tabId = message.getInt("tabID");
                 handleReaderEnabled(tabId);
@@ -962,24 +957,24 @@ abstract public class GeckoApp
                 handleFaviconRequest(url);
             } else if (event.equals("Reader:GoToReadingList")) {
                 showReadingList();
             } else if (event.equals("Content:StateChange")) {
                 final int tabId = message.getInt("tabID");
                 final String uri = message.getString("uri");
                 final boolean success = message.getBoolean("success");
                 int state = message.getInt("state");
-                Log.i(LOGTAG, "State - " + state);
+                Log.d(LOGTAG, "State - " + state);
                 if ((state & GeckoAppShell.WPL_STATE_IS_NETWORK) != 0) {
                     if ((state & GeckoAppShell.WPL_STATE_START) != 0) {
-                        Log.i(LOGTAG, "Got a document start");
+                        Log.d(LOGTAG, "Got a document start event.");
                         final boolean showProgress = message.getBoolean("showProgress");
                         handleDocumentStart(tabId, showProgress, uri);
                     } else if ((state & GeckoAppShell.WPL_STATE_STOP) != 0) {
-                        Log.i(LOGTAG, "Got a document stop");
+                        Log.d(LOGTAG, "Got a document stop event.");
                         handleDocumentStop(tabId, success);
                     }
                 }
             } else if (event.equals("Content:LoadError")) {
                 final int tabId = message.getInt("tabID");
                 final String uri = message.getString("uri");
                 final String title = message.getString("title");
                 handleLoadError(tabId, uri, title);
@@ -1104,17 +1099,16 @@ abstract public class GeckoApp
                 }
             }
         } catch (Exception e) {
             Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
         }
     }
 
     public String getResponse() {
-        Log.i(LOGTAG, "Return " + mCurrentResponse);
         String res = mCurrentResponse;
         mCurrentResponse = "";
         return res;
     }
 
     void onStatePurged() { }
 
     /**
@@ -1136,22 +1130,21 @@ abstract public class GeckoApp
             builder.setMessage(R.string.site_settings_no_settings);
         } else {
             // Eventually we should use a list adapter and custom checkable list items
             // to make a two-line UI to match the mock-ups
             CharSequence[] items = new CharSequence[aPermissions.length()];
             boolean[] states = new boolean[aPermissions.length()];
             for (int i = 0; i < aPermissions.length(); i++) {
                 try {
-                    items[i] = aPermissions.getJSONObject(i).
-                               getString("setting");
-                    // Make all the items checked by default
+                    items[i] = aPermissions.getJSONObject(i).getString("setting");
+                    // Make all the items checked by default.
                     states[i] = true;
                 } catch (JSONException e) {
-                    Log.i(LOGTAG, "JSONException", e);
+                    Log.w(LOGTAG, "Exception populating settings items.", e);
                 }
             }
             builder.setMultiChoiceItems(items, states, new DialogInterface.OnMultiChoiceClickListener(){
                 public void onClick(DialogInterface dialog, int item, boolean state) {
                     // Do nothing
                 }
             });
             builder.setPositiveButton(R.string.site_settings_clear, new DialogInterface.OnClickListener() {
@@ -1493,17 +1486,16 @@ abstract public class GeckoApp
         if (sGeckoThread != null) {
             // this happens when the GeckoApp activity is destroyed by android
             // without killing the entire application (see bug 769269)
             mIsRestoringActivity = true;
             Telemetry.HistogramAdd("FENNEC_RESTORING_ACTIVITY", 1);
         }
 
         mMainHandler = new Handler();
-        Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - onCreate");
 
         LayoutInflater.from(this).setFactory(GeckoViewsFactory.getInstance());
 
         super.onCreate(savedInstanceState);
 
         mOrientation = getResources().getConfiguration().orientation;
 
         setContentView(getLayout());
@@ -1514,22 +1506,20 @@ abstract public class GeckoApp
 
         // setup tabs panel
         mTabsPanel = (TabsPanel) findViewById(R.id.tabs_panel);
 
         // check if the last run was exited due to a normal kill while
         // we were in the background, or a more harsh kill while we were
         // active
         if (savedInstanceState != null) {
-            Log.i(LOGTAG, "Restoring from OOM");
             mRestoreMode = GeckoAppShell.RESTORE_OOM;
 
             boolean wasInBackground =
                 savedInstanceState.getBoolean(SAVED_STATE_IN_BACKGROUND, false);
-            Log.i(LOGTAG, "Was in background: " + wasInBackground);
 
             // Don't log OOM-kills if only one activity was destroyed. (For example
             // from "Don't keep activities" on ICS)
             if (!wasInBackground && !mIsRestoringActivity) {
                 Telemetry.HistogramAdd("FENNEC_WAS_KILLED", 1);
             }
 
             mPrivateBrowsingSession = savedInstanceState.getString(SAVED_STATE_PRIVATE_SESSION);
@@ -1538,17 +1528,16 @@ abstract public class GeckoApp
         GeckoBackgroundThread.getHandler().post(new Runnable() {
             public void run() {
                 SharedPreferences prefs =
                     GeckoApp.mAppContext.getSharedPreferences(PREFS_NAME, 0);
 
                 boolean wasOOM = prefs.getBoolean(PREFS_OOM_EXCEPTION, false);
                 boolean wasStopped = prefs.getBoolean(PREFS_WAS_STOPPED, true);
                 if (wasOOM || !wasStopped) {
-                    Log.i(LOGTAG, "Crashed due to OOM last run");
                     Telemetry.HistogramAdd("FENNEC_WAS_KILLED", 1);
                 }
                 SharedPreferences.Editor editor = prefs.edit();
                 editor.putBoolean(GeckoApp.PREFS_OOM_EXCEPTION, false);
 
                 // put a flag to check if we got a normal onSaveInstaceState
                 // on exit, or if we were suddenly killed (crash or native OOM)
                 editor.putBoolean(GeckoApp.PREFS_WAS_STOPPED, false);
@@ -1602,17 +1591,16 @@ abstract public class GeckoApp
 
         String passedUri = null;
         String uri = getURIFromIntent(intent);
         if (uri != null && uri.length() > 0) {
             passedUri = uri;
         }
 
         if (mRestoreMode == GeckoAppShell.RESTORE_NONE && getProfile().shouldRestoreSession()) {
-            Log.i(LOGTAG, "Restoring crash");
             mRestoreMode = GeckoAppShell.RESTORE_CRASH;
         }
 
         boolean isExternalURL = passedUri != null && !passedUri.equals("about:home");
         StartupAction startupAction;
         if (isExternalURL) {
             startupAction = StartupAction.URL;
         } else {
@@ -1658,40 +1646,36 @@ abstract public class GeckoApp
         }
         if (!ACTION_DEBUG.equals(action) &&
             checkAndSetLaunchState(LaunchState.Launching, LaunchState.Launched)) {
             sGeckoThread.start();
         } else if (ACTION_DEBUG.equals(action) &&
             checkAndSetLaunchState(LaunchState.Launching, LaunchState.WaitForDebugger)) {
             mMainHandler.postDelayed(new Runnable() {
                 public void run() {
-                    Log.i(LOGTAG, "Launching from debug intent after 5s wait");
                     setLaunchState(LaunchState.Launching);
                     sGeckoThread.start();
                 }
             }, 1000 * 5 /* 5 seconds */);
-            Log.i(LOGTAG, "Intent : ACTION_DEBUG - waiting 5s before launching");
         }
 
         if (cameraView == null) {
             cameraView = new SurfaceView(this);
             cameraView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
         }
 
         if (mLayerView == null) {
             LayerView layerView = (LayerView) findViewById(R.id.layer_view);
             layerView.initializeView(GeckoAppShell.getEventDispatcher());
             mLayerView = layerView;
         }
 
         mPluginContainer = (AbsoluteLayout) findViewById(R.id.plugin_container);
         mFormAssistPopup = (FormAssistPopup) findViewById(R.id.form_assist_popup);
 
-        Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - UI almost up");
-
         //register for events
         registerEventListener("DOMContentLoaded");
         registerEventListener("DOMTitleChanged");
         registerEventListener("DOMLinkAdded");
         registerEventListener("DOMWindowClose");
         registerEventListener("log");
         registerEventListener("Content:SecurityChange");
         registerEventListener("Content:ReaderEnabled");
@@ -1747,25 +1731,23 @@ abstract public class GeckoApp
 
         final GeckoApp self = this;
 
         // End of the startup of our Java App
         mJavaUiStartupTimer.stop();
 
         GeckoAppShell.getHandler().postDelayed(new Runnable() {
             public void run() {
-                Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - pre checkLaunchState");
                 // Sync settings need Gecko to be loaded, so
                 // no hurry in starting this.
                 checkMigrateSync();
 
                 // Kick off our background service to fetch product announcements.
                 // We do this by invoking the broadcast receiver, which uses the
                 // system alarm infrastructure to perform tasks at intervals.
-                Log.d(LOGTAG, "Broadcasting announcements pref.");
                 GeckoPreferences.broadcastAnnouncementsPref(GeckoApp.mAppContext);
 
                 /*
                   XXXX see bug 635342
                    We want to disable this code if possible.  It is about 145ms in runtime
                 SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE);
                 String localeCode = settings.getString(getPackageName() + ".locale", "");
                 if (localeCode != null && localeCode.length() > 0)
@@ -1882,17 +1864,17 @@ abstract public class GeckoApp
                         mIntent.setData(data);
                     } else {
                         mIntent.putExtra("prefetched", 1);
                     }
                 } else {
                     mIntent.putExtra("prefetched", 1);
                 }
             } catch (IOException ioe) {
-                Log.i(LOGTAG, "exception trying to pre-fetch redirected url", ioe);
+                Log.w(LOGTAG, "Exception trying to pre-fetch redirected URL.", ioe);
                 mIntent.putExtra("prefetched", 1);
             }
         }
         public void run() {
             super.run();
 
             mMainHandler.postAtFrontOfQueue(new Runnable() {
                 public void run() {
@@ -1916,18 +1898,16 @@ abstract public class GeckoApp
         new CopyOnWriteArrayList<String>(kRedirectWhiteListArray);
 
     private boolean isHostOnRedirectWhitelist(String host) {
         return kRedirectWhiteList.contains(host);
     }
 
     @Override
     protected void onNewIntent(Intent intent) {
-        Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - onNewIntent");
-
         if (checkLaunchState(LaunchState.GeckoExiting)) {
             // We're exiting and shouldn't try to do anything else just incase
             // we're hung for some reason we'll force the process to exit
             System.exit(0);
             return;
         }
 
         // if we were previously OOM killed, we can end up here when launching
@@ -1957,17 +1937,16 @@ abstract public class GeckoApp
                 } else {
                     GeckoAppShell.getHandler().post(new PrefetchRunnable(intent));
                 }
             }
         }
         final String action = intent.getAction();
 
         if (Intent.ACTION_MAIN.equals(action)) {
-            Log.i(LOGTAG, "Intent : ACTION_MAIN");
             GeckoAppShell.sendEventToGecko(GeckoEvent.createURILoadEvent(""));
         }
         else if (ACTION_LOAD.equals(action)) {
             String uri = intent.getDataString();
             Tabs.getInstance().loadUrl(uri);
         }
         else if (Intent.ACTION_VIEW.equals(action)) {
             String uri = intent.getDataString();
@@ -2024,18 +2003,16 @@ abstract public class GeckoApp
             }
         }
         return uri;
     }
 
     @Override
     public void onResume()
     {
-        Log.i(LOGTAG, "resume");
-
         // After an onPause, the activity is back in the foreground.
         // Undo whatever we did in onPause.
         super.onResume();
 
         SiteIdentityPopup.getInstance().dismiss();
 
         int newOrientation = getResources().getConfiguration().orientation;
 
@@ -2066,17 +2043,16 @@ abstract public class GeckoApp
 
         if (!mInitialized && hasFocus)
             initialize();
     }
 
     @Override
     public void onStop()
     {
-        Log.i(LOGTAG, "stop");
         // We're about to be stopped, potentially in preparation for
         // being destroyed.  We're killable after this point -- as I
         // understand it, in extreme cases the process can be terminated
         // without going through onDestroy.
         //
         // We might also get an onRestart after this; not sure what
         // that would mean for Gecko if we were to kill it here.
         // Instead, what we should do here is save prefs, session,
@@ -2085,18 +2061,16 @@ abstract public class GeckoApp
 
         GeckoAppShell.sendEventToGecko(GeckoEvent.createStoppingEvent(isApplicationInBackground()));
         super.onStop();
     }
 
     @Override
     public void onPause()
     {
-        Log.i(LOGTAG, "pause");
-
         // In some way it's sad that Android will trigger StrictMode warnings
         // here as the whole point is to save to disk while the activity is not
         // interacting with the user.
         GeckoBackgroundThread.getHandler().post(new Runnable() {
             public void run() {
                 SharedPreferences prefs =
                     GeckoApp.mAppContext.getSharedPreferences(GeckoApp.PREFS_NAME, 0);
                 SharedPreferences.Editor editor = prefs.edit();
@@ -2111,46 +2085,39 @@ abstract public class GeckoApp
         GeckoScreenOrientationListener.getInstance().stop();
 
         super.onPause();
     }
 
     @Override
     public void onRestart()
     {
-        Log.i(LOGTAG, "restart");
-
         GeckoBackgroundThread.getHandler().post(new Runnable() {
             public void run() {
                 SharedPreferences prefs =
                     GeckoApp.mAppContext.getSharedPreferences(GeckoApp.PREFS_NAME, 0);
                 SharedPreferences.Editor editor = prefs.edit();
                 editor.putBoolean(GeckoApp.PREFS_WAS_STOPPED, false);
                 editor.commit();
             }
         });
 
         super.onRestart();
     }
 
     @Override
     public void onStart()
     {
-        Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - onStart");
-
-        Log.i(LOGTAG, "start");
         GeckoAppShell.sendEventToGecko(GeckoEvent.createStartEvent(isApplicationInBackground()));
         super.onStart();
     }
 
     @Override
     public void onDestroy()
     {
-        Log.i(LOGTAG, "destroy");
-
         // Tell Gecko to shutting down; we'll end up calling System.exit()
         // in onXreExit.
         if (isFinishing())
             GeckoAppShell.sendEventToGecko(GeckoEvent.createShutdownEvent());
 
         unregisterEventListener("DOMContentLoaded");
         unregisterEventListener("DOMTitleChanged");
         unregisterEventListener("DOMLinkAdded");
@@ -2251,20 +2218,17 @@ abstract public class GeckoApp
 
     @Override
     public void onContentChanged() {
         super.onContentChanged();
     }
 
 
     @Override
-    public void onConfigurationChanged(Configuration newConfig)
-    {
-        Log.i(LOGTAG, "configuration changed");
-
+    public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
 
         if (mOrientation != newConfig.orientation) {
             mOrientation = newConfig.orientation;
             if (mFormAssistPopup != null)
                 mFormAssistPopup.hide();
             SiteIdentityPopup.getInstance().dismiss();
             refreshChrome();
@@ -2294,103 +2258,107 @@ abstract public class GeckoApp
         }
     }
 
     public void doRestart() {
         doRestart("org.mozilla.gecko.restart");
     }
 
     public void doRestart(String action) {
-        Log.i(LOGTAG, "doRestart(\"" + action + "\")");
+        Log.d(LOGTAG, "doRestart(\"" + action + "\")");
         try {
             Intent intent = new Intent(action);
             intent.setClassName(getPackageName(),
                                 getPackageName() + ".Restarter");
             /* TODO: addEnvToIntent(intent); */
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                             Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
-            Log.i(LOGTAG, intent.toString());
+            Log.d(LOGTAG, "Restart intent: " + intent.toString());
             GeckoAppShell.killAnyZombies();
             startActivity(intent);
         } catch (Exception e) {
-            Log.e(LOGTAG, "error doing restart", e);
+            Log.e(LOGTAG, "Error effecting restart.", e);
         }
         finish();
         // Give the restart process time to start before we die
         GeckoAppShell.waitForAnotherGeckoProc();
     }
 
     public void handleNotification(String action, String alertName, String alertCookie) {
         GeckoAppShell.handleNotification(action, alertName, alertCookie);
     }
 
     private void checkMigrateProfile() {
         final File profileDir = getProfile().getDir();
-        final long currentTime = SystemClock.uptimeMillis();
 
         if (profileDir != null) {
             final GeckoApp app = GeckoApp.mAppContext;
 
             GeckoAppShell.getHandler().post(new Runnable() {
                 public void run() {
-                    Log.i(LOGTAG, "Checking profile migration in: " + profileDir.getAbsolutePath());
-
                     ProfileMigrator profileMigrator = new ProfileMigrator(app);
 
                     // Do a migration run on the first start after an upgrade.
                     if (!GeckoApp.sIsUsingCustomProfile &&
                         !profileMigrator.hasMigrationRun()) {
                         // Show the "Setting up Fennec" screen if this takes
                         // a while.
-                        final SetupScreen setupScreen = new SetupScreen(app);
+
+                        // Create a "final" holder for the setup screen so that we can
+                        // create it in startCallback and still find a reference to it
+                        // in stopCallback. (We must create it on the UI thread to fix
+                        // bug 788216). Note that synchronization is not a problem here
+                        // since it is only ever touched on the UI thread.
+                        final SetupScreen[] setupScreenHolder = new SetupScreen[1];
 
                         final Runnable startCallback = new Runnable() {
                             public void run() {
                                 GeckoApp.mAppContext.runOnUiThread(new Runnable() {
                                     public void run() {
-                                       setupScreen.show();
+                                        setupScreenHolder[0] = new SetupScreen(app);
+                                        setupScreenHolder[0].show();
                                     }
                                 });
                             }
                         };
 
                         final Runnable stopCallback = new Runnable() {
                             public void run() {
                                 GeckoApp.mAppContext.runOnUiThread(new Runnable() {
                                     public void run() {
-                                        setupScreen.dismiss();
+                                        SetupScreen screen = setupScreenHolder[0];
+                                        // screen will never be null if this code runs, but
+                                        // stranger things have happened...
+                                        if (screen != null) {
+                                            screen.dismiss();
+                                        }
                                     }
                                 });
                             }
                         };
 
                         profileMigrator.setLongOperationCallbacks(startCallback,
                                                                   stopCallback);
                         profileMigrator.launchPlaces(profileDir);
-
-                        long timeDiff = SystemClock.uptimeMillis() - currentTime;
-                        Log.i(LOGTAG, "Profile migration took " + timeDiff + " ms");
-
                         finishProfileMigration();
                     }
                 }}
             );
         }
     }
 
     protected void finishProfileMigration() {
     }
 
     private void checkMigrateSync() {
         final File profileDir = getProfile().getDir();
         if (!GeckoApp.sIsUsingCustomProfile && profileDir != null) {
             final GeckoApp app = GeckoApp.mAppContext;