Merge MC -> JM
authorBrian Hackett <bhackett1024@gmail.com>
Tue, 23 Aug 2011 07:08:50 -0700
changeset 76147 78a56e48dd3c55309866bf656115555705421fb7
parent 76146 b9a48e6f870ef1612ea94146bd45072bbb707109 (current diff)
parent 75703 071d9c997f3d44c52e4dcf798ec466245b3b88c1 (diff)
child 76148 4eed9e7ab27f8a35853328fcd1271efb64dbeb1c
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
milestone9.0a1
Merge MC -> JM
browser/base/content/tabview/modules/AllTabs.jsm
browser/base/content/test/tabview/browser_tabview_bug627239.js
content/svg/content/test/test_animLengthRelativeUnits.xhtml
dom/base/nsGlobalWindow.cpp
js/src/Makefile.in
js/src/config/autoconf.mk.in
js/src/configure.in
js/src/jsfun.cpp
js/src/xpconnect/shell/xpcshell.cpp
js/src/xpconnect/src/nsXPConnect.cpp
js/src/xpconnect/src/xpcjsruntime.cpp
js/src/xpconnect/src/xpcprivate.h
--- a/accessible/src/atk/nsAccessibleWrap.cpp
+++ b/accessible/src/atk/nsAccessibleWrap.cpp
@@ -971,19 +971,21 @@ refRelationSetCB(AtkObject *aAtkObj)
       atk_relation_set_remove(relation_set, atkRelation);
 
     Relation rel(accWrap->RelationByType(relationTypes[i]));
     nsTArray<AtkObject*> targets;
     nsAccessible* tempAcc = nsnull;
     while ((tempAcc = rel.Next()))
       targets.AppendElement(nsAccessibleWrap::GetAtkObject(tempAcc));
 
-    atkRelation = atk_relation_new(targets.Elements(), targets.Length(), atkType);
-    atk_relation_set_add(relation_set, atkRelation);
-    g_object_unref(atkRelation);
+    if (targets.Length()) {
+      atkRelation = atk_relation_new(targets.Elements(), targets.Length(), atkType);
+      atk_relation_set_add(relation_set, atkRelation);
+      g_object_unref(atkRelation);
+    }
   }
 
   return relation_set;
 }
 
 // Check if aAtkObj is a valid MaiAtkObject, and return the nsAccessibleWrap
 // for it.
 nsAccessibleWrap *GetAccessibleWrap(AtkObject *aAtkObj)
--- a/browser/base/content/inspector.js
+++ b/browser/base/content/inspector.js
@@ -863,18 +863,21 @@ var InspectorUI = {
     if (this.treePanelDiv) {
       this.treePanelDiv.ownerPanel = null;
       let parent = this.treePanelDiv.parentNode;
       parent.removeChild(this.treePanelDiv);
       delete this.treePanelDiv;
       delete this.treeBrowserDocument;
     }
 
-    if (this.treeIFrame)
+    if (this.treeIFrame) {
+      let parent = this.treeIFrame.parentNode;
+      parent.removeChild(this.treeIFrame);
       delete this.treeIFrame;
+    }
     delete this.ioBox;
 
     if (this.domplate) {
       this.domplateUtils.setDOM(null);
       delete this.domplate;
       delete this.HTMLTemplates;
       delete this.domplateUtils;
     }
@@ -888,16 +891,18 @@ var InspectorUI = {
 
     this.inspectCmd.setAttribute("checked", false);
     this.browser = this.win = null; // null out references to browser and window
     this.winID = null;
     this.selection = null;
     this.treeLoaded = false;
 
     this.treePanel.addEventListener("popuphidden", function treePanelHidden() {
+      this.removeEventListener("popuphidden", treePanelHidden, false);
+
       InspectorUI.closing = false;
       Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.CLOSED, null);
     }, false);
 
     this.treePanel.hidePopup();
     delete this.treePanel;
   },
 
--- a/browser/base/content/sanitize.js
+++ b/browser/base/content/sanitize.js
@@ -151,20 +151,19 @@ Sanitizer.prototype = {
           }
         }
         else {
           // Remove everything
           cookieMgr.removeAll();
         }
 
         // Clear plugin data.
-        let ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
         const phInterface = Ci.nsIPluginHost;
         const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL;
-        ph.QueryInterface(phInterface);
+        let ph = Cc["@mozilla.org/plugin/host;1"].getService(phInterface);
 
         // Determine age range in seconds. (-1 means clear all.) We don't know
         // that this.range[1] is actually now, so we compute age range based
         // on the lower bound. If this.range results in a negative age, do
         // nothing.
         let age = this.range ? (Date.now() / 1000 - this.range[0] / 1000000)
                              : -1;
         if (!this.range || age >= 0) {
@@ -190,23 +189,23 @@ Sanitizer.prototype = {
         var psvc = Components.classes["@mozilla.org/preferences-service;1"]
                              .getService(Components.interfaces.nsIPrefService);
         try {
             var branch = psvc.getBranch("geo.wifi.access_token.");
             branch.deleteBranch("");
         } catch (e) {}
 
       },
-      
+
       get canClear()
       {
         return true;
       }
     },
-    
+
     offlineApps: {
       clear: function ()
       {
         const Cc = Components.classes;
         const Ci = Components.interfaces;
         var cacheService = Cc["@mozilla.org/network/cache-service;1"].
                            getService(Ci.nsICacheService);
         try {
new file mode 100644
--- /dev/null
+++ b/browser/base/content/tabview/content.js
@@ -0,0 +1,46 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is content.js.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Tim Taubert <ttaubert@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+addEventListener("DOMWillOpenModalDialog", function (event) {
+  // (event.isTrusted == true) when the event is generated by a user action
+  // and does not originate from a script.
+  if (event.isTrusted) {
+    // we're intentionally sending a synchronous message to handle this event
+    // as quick as possible, switch the selected tab and hide the tabview
+    // before the modal dialog is shown
+    sendSyncMessage("Panorama:DOMWillOpenModalDialog");
+  }
+}, true);
--- a/browser/base/content/tabview/groupitems.js
+++ b/browser/base/content/tabview/groupitems.js
@@ -226,17 +226,17 @@ function GroupItem(listOfEls, options) {
   let appTabTrayContainer = iQ("<div/>")
     .addClass("appTabTrayContainer")
     .appendTo($container);
   this.$appTabTray = iQ("<div/>")
     .addClass("appTabTray")
     .appendTo(appTabTrayContainer);
 
   AllTabs.tabs.forEach(function(xulTab) {
-    if (xulTab.pinned && xulTab.ownerDocument.defaultView == gWindow)
+    if (xulTab.pinned)
       self.addAppTab(xulTab, {dontAdjustTray: true});
   });
 
   // ___ Undo Close
   this.$undoContainer = null;
   this._undoButtonTimeoutId = null;
 
   // ___ Superclass initialization
@@ -739,40 +739,55 @@ GroupItem.prototype = Utils.extend(new I
       return true;
     }
     return false;
   },
 
   // ----------
   // Function: _unhide
   // Shows the hidden group.
-  _unhide: function GroupItem__unhide() {
-    let self = this;
-
+  //
+  // Parameters:
+  //   options - various options (see below)
+  //
+  // Possible options:
+  //   immediately - true when no animations should be used
+  _unhide: function GroupItem__unhide(options) {
     this._cancelFadeAwayUndoButtonTimer();
     this.hidden = false;
     this.$undoContainer.remove();
     this.$undoContainer = null;
     this.droppable(true);
     this.setTrenches(this.bounds);
 
-    iQ(this.container).show().animate({
-      "-moz-transform": "scale(1)",
-      "opacity": 1
-    }, {
-      duration: 170,
-      complete: function() {
-        self._children.forEach(function(child) {
-          iQ(child.container).show();
-        });
+    let self = this;
+
+    let finalize = function () {
+      self._children.forEach(function(child) {
+        iQ(child.container).show();
+      });
+
+      UI.setActive(self);
+      self._sendToSubscribers("groupShown", { groupItemId: self.id });
+    };
+
+    let $container = iQ(this.container).show();
 
-        UI.setActive(self);
-        self._sendToSubscribers("groupShown", { groupItemId: self.id });
-      }
-    });
+    if (!options || !options.immediately) {
+      $container.animate({
+        "-moz-transform": "scale(1)",
+        "opacity": 1
+      }, {
+        duration: 170,
+        complete: finalize
+      });
+    } else {
+      $container.css({"-moz-transform": "none", opacity: 1});
+      finalize();
+    }
 
     GroupItems.updateGroupCloseButtons();
   },
 
   // ----------
   // Function: closeHidden
   // Removes the group item, its children and its container.
   closeHidden: function GroupItem_closeHidden() {
@@ -780,69 +795,83 @@ GroupItem.prototype = Utils.extend(new I
 
     this._cancelFadeAwayUndoButtonTimer();
 
     // When the last non-empty groupItem is closed and there are no
     // pinned tabs then create a new group with a blank tab.
     let remainingGroups = GroupItems.groupItems.filter(function (groupItem) {
       return (groupItem != self && groupItem.getChildren().length);
     });
+
+    let tab = null;
+
     if (!gBrowser._numPinnedTabs && !remainingGroups.length) {
       let emptyGroups = GroupItems.groupItems.filter(function (groupItem) {
         return (groupItem != self && !groupItem.getChildren().length);
       });
       let group = (emptyGroups.length ? emptyGroups[0] : GroupItems.newGroup());
-      group.newTab(null, { closedLastTab: true });
+      tab = group.newTab(null, {dontZoomIn: true});
     }
 
-    this.destroy();
+    let closed = this.destroy();
+
+    if (!tab)
+      return;
+
+    if (closed) {
+      // Let's make the new tab the selected tab.
+      UI.goToTab(tab);
+    } else {
+      // Remove the new tab and group, if this group is no longer closed.
+      tab._tabViewTabItem.parent.destroy({immediately: true});
+    }
   },
 
   // ----------
   // Function: destroy
   // Close all tabs linked to children (tabItems), removes all children and 
   // close the groupItem.
   //
   // Parameters:
   //   options - An object with optional settings for this call.
   //
   // Options:
   //   immediately - (bool) if true, no animation will be used
+  //
+  // Returns true if the groupItem has been closed, or false otherwise. A group
+  // could not have been closed due to a tab with an onUnload handler (that
+  // waits for user interaction).
   destroy: function GroupItem_destroy(options) {
     let self = this;
 
     // when "TabClose" event is fired, the browser tab is about to close and our 
     // item "close" event is fired.  And then, the browser tab gets closed. 
     // In other words, the group "close" event is fired before all browser
     // tabs in the group are closed.  The below code would fire the group "close"
     // event only after all browser tabs in that group are closed.
-    let shouldRemoveTabItems = [];
-    let toClose = this._children.concat();
-    toClose.forEach(function(child) {
+    this._children.concat().forEach(function(child) {
       child.removeSubscriber("close", self._onChildClose);
 
-      let removed = child.close(true);
-      if (removed) {
-        shouldRemoveTabItems.push(child);
+      if (child.close(true)) {
+        self.remove(child, { dontArrange: true });
       } else {
         // child.removeSubscriber() must be called before child.close(), 
         // therefore we call child.addSubscriber() if the tab is not removed.
         child.addSubscriber("close", self._onChildClose);
       }
     });
 
-    if (shouldRemoveTabItems.length != toClose.length) {
-      // remove children without the assiciated tab and show the group item
-      shouldRemoveTabItems.forEach(function(child) {
-        self.remove(child, { dontArrange: true });
-      });
+    if (this._children.length) {
+      if (this.hidden)
+        this.$undoContainer.fadeOut(function() { self._unhide() });
 
-      this.$undoContainer.fadeOut(function() { self._unhide() });
+      return false;
     } else {
       this.close(options);
+      return true;
     }
   },
 
   // ----------
   // Function: _fadeAwayUndoButton
   // Fades away the undo button
   _fadeAwayUndoButton: function GroupItem__fadeAwayUdoButton() {
     let self = this;
@@ -1813,23 +1842,26 @@ GroupItem.prototype = Utils.extend(new I
   },
 
   // ----------
   // Function: newTab
   // Creates a new tab within this groupItem.
   // Parameters:
   //  url - the new tab should open this url as well
   //  options - the options object
+  //    dontZoomIn - set to true to not zoom into the newly created tab
   //    closedLastTab - boolean indicates the last tab has just been closed
   newTab: function GroupItem_newTab(url, options) {
     if (options && options.closedLastTab)
       UI.closedLastTabInTabView = true;
 
     UI.setActive(this, { dontSetActiveTabInGroup: true });
-    gBrowser.loadOneTab(url || "about:blank", { inBackground: false });
+
+    let dontZoomIn = !!(options && options.dontZoomIn);
+    return gBrowser.loadOneTab(url || "about:blank", { inBackground: dontZoomIn });
   },
 
   // ----------
   // Function: reorderTabItemsBasedOnTabOrder
   // Reorders the tabs in a groupItem based on the arrangment of the tabs
   // shown in the tab bar. It does it by sorting the children
   // of the groupItem by the positions of their respective tabs in the
   // tab bar.
@@ -1921,23 +1953,23 @@ let GroupItems = {
   },
 
   // ----------
   // Function: init
   init: function GroupItems_init() {
     let self = this;
 
     // setup attr modified handler, and prepare for its uninit
-    function handleAttrModified(xulTab) {
-      self._handleAttrModified(xulTab);
+    function handleAttrModified(event) {
+      self._handleAttrModified(event.target);
     }
 
     // make sure any closed tabs are removed from the delay update list
-    function handleClose(xulTab) {
-      let idx = self._delayedModUpdates.indexOf(xulTab);
+    function handleClose(event) {
+      let idx = self._delayedModUpdates.indexOf(event.target);
       if (idx != -1)
         self._delayedModUpdates.splice(idx, 1);
     }
 
     AllTabs.register("attrModified", handleAttrModified);
     AllTabs.register("close", handleClose);
     this._cleanupFunctions.push(function() {
       AllTabs.unregister("attrModified", handleAttrModified);
@@ -2035,17 +2067,17 @@ let GroupItems = {
     });
     this._delayedModUpdates = [];
   },
 
   // ----------
   // Function: _updateAppTabIcons
   // Update images of any apptab icons that point to passed in xultab 
   _updateAppTabIcons: function GroupItems__updateAppTabIcons(xulTab) {
-    if (xulTab.ownerDocument.defaultView != gWindow || !xulTab.pinned)
+    if (!xulTab.pinned)
       return;
 
     let iconUrl = this.getAppTabFavIconUrl(xulTab);
     this.groupItems.forEach(function(groupItem) {
       iQ(".appTabIcon", groupItem.$appTabTray).each(function(icon) {
         let $icon = iQ(icon);
         if ($icon.data("xulTab") != xulTab)
           return true;
deleted file mode 100644
--- a/browser/base/content/tabview/modules/AllTabs.jsm
+++ /dev/null
@@ -1,183 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is TabView AllTabs.
- *
- * The Initial Developer of the Original Code is
- * Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2010
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Edward Lee <edilee@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-"use strict";
-
-const Cu = Components.utils;
-Cu.import("resource://gre/modules/Services.jsm");
-
-let EXPORTED_SYMBOLS = ["AllTabs"];
-
-let AllTabs = {
-  // ----------
-  // Function: toString
-  // Prints [AllTabs] for debug use
-  toString: function AllTabs_toString() {
-    return "[AllTabs]";
-  },
-
-  /**
-   * Get an array of all tabs from all tabbrowser windows.
-   *
-   * @usage let numAllTabs = AllTabs.tabs.length;
-   *        AllTabs.tabs.forEach(handleAllTabs);
-   */
-  get tabs() {
-    // Get tabs from each browser window and flatten them into one array
-    return Array.concat.apply(null, browserWindows.map(function(browserWindow) {
-      return Array.filter(browserWindow.gBrowser.tabs, function (tab) !tab.closing);
-    }));
-  },
-
-  /**
-   * Attach a callback for a given tab event.
-   *
-   * @param eventName
-   *        Name of the corresponding Tab* Event; one of "attrModified",
-   *        "close", "move", "open", "select", "pinned", "unpinned".
-   * @param callback
-   *        Callback that gets called with the tab as the first argument and
-   *        the event as the second argument.
-   * @usage AllTabs.register("change", function handleChange(tab, event) {});
-   */
-  register: function register(eventName, callback) {
-    // Either add additional callbacks or create the first entry
-    let listeners = eventListeners[events[eventName]];
-    if (listeners)
-      listeners.push(callback);
-    else
-      eventListeners[events[eventName]] = [callback];
-  },
-
-  /**
-   * Remove a callback for a given tab event.
-   *
-   * @param eventName
-   *        Name of the corresponding Tab* Event; one of "attrModified",
-   *        "close", "move", "open", "select", "pinned", "unpinned".
-   * @param callback
-   *        The callback given for the original AllTabs.register call.
-   * @usage AllTabs.unregister("close", handleClose);
-   */
-  unregister: function unregister(eventName, callback) {
-    // Nothing to remove for this event
-    let listeners = eventListeners[events[eventName]];
-    if (!listeners)
-      return;
-
-    // Can only remove a callback if we have it
-    let index = listeners.indexOf(callback);
-    if (index == -1)
-      return;
-
-    listeners.splice(index, 1);
-  }
-};
-
-__defineGetter__("browserWindows", function browserWindows() {
-  let browserWindows = [];
-  let windows = Services.wm.getEnumerator("navigator:browser");
-  while (windows.hasMoreElements())
-    browserWindows.push(windows.getNext());
-  return browserWindows;
-});
-
-let events = {
-  attrModified: "TabAttrModified",
-  close:        "TabClose",
-  move:         "TabMove",
-  open:         "TabOpen",
-  select:       "TabSelect",
-  pinned:       "TabPinned",
-  unpinned:     "TabUnpinned"
-};
-let eventListeners = {};
-
-function registerBrowserWindow(browserWindow) {
-  for each (let event in events)
-    browserWindow.addEventListener(event, tabEventListener, true);
-
-  browserWindow.addEventListener("unload", unregisterBrowserWindow, false);
-}
-
-function unregisterBrowserWindow(unloadEvent) {
-  let browserWindow = unloadEvent.currentTarget;
-
-  for each (let event in events)
-    browserWindow.removeEventListener(event, tabEventListener, true);
-
-  browserWindow.removeEventListener("unload", unregisterBrowserWindow, false);
-}
-
-function tabEventListener(event) {
-  // Make sure we've gotten listeners before trying to call
-  let listeners = eventListeners[event.type];
-  if (!listeners)
-    return;
-
-  let tab = event.target;
-
-  // Make a copy of the listeners, so it can't change as we call back
-  listeners.slice().forEach(function (callback) {
-    try {
-      callback(tab, event);
-    }
-    // Don't let failing callbacks stop us but report the failure
-    catch (ex) {
-      Cu.reportError(ex);
-    }
-  });
-}
-
-function observer(subject, topic, data) {
-  switch (topic) {
-    case "domwindowopened":
-      subject.addEventListener("load", function onLoad() {
-        subject.removeEventListener("load", onLoad, false);
-
-        // Now that the window has loaded, only register on browser windows
-        let doc = subject.document.documentElement;
-        if (doc.getAttribute("windowtype") == "navigator:browser")
-          registerBrowserWindow(subject);
-      }, false);
-      break;
-  }
-}
-
-// Register listeners on all browser windows and future ones
-browserWindows.forEach(registerBrowserWindow);
-Services.obs.addObserver(observer, "domwindowopened", false);
--- a/browser/base/content/tabview/search.js
+++ b/browser/base/content/tabview/search.js
@@ -515,16 +515,19 @@ var TabHandlers = {
   _mouseDownLocation: null
 };
 
 function createSearchTabMacher() {
   return new TabMatcher(iQ("#searchbox").val());
 }
 
 function hideSearch(event) {
+  if (!isSearchEnabled())
+    return;
+
   iQ("#searchbox").val("");
   iQ("#searchshade").hide();
   iQ("#search").hide();
 
   iQ("#searchbutton").css({ opacity:.8 });
 
 #ifdef XP_MACOSX
   UI.setTitlebarColors(true);
--- a/browser/base/content/tabview/storage.js
+++ b/browser/base/content/tabview/storage.js
@@ -74,19 +74,16 @@ let Storage = {
   // Function: wipe
   // Cleans out all the stored data, leaving empty objects.
   wipe: function Storage_wipe() {
     try {
       var self = this;
 
       // ___ Tabs
       AllTabs.tabs.forEach(function(tab) {
-        if (tab.ownerDocument.defaultView != gWindow)
-          return;
-
         self.saveTab(tab, null);
       });
 
       // ___ Other
       this.saveGroupItemsData(gWindow, {});
       this.saveUIData(gWindow, {});
 
       this._sessionStore.setWindowValue(gWindow, this.GROUP_DATA_IDENTIFIER,
@@ -180,16 +177,33 @@ let Storage = {
     } catch (e) {
       // getWindowValue will fail if the property doesn't exist
       Utils.log("Error in readGroupItemData: "+e, data);
     }
     return existingData;
   },
 
   // ----------
+  // Function: readWindowBusyState
+  // Returns the current busyState for the given window.
+  readWindowBusyState: function Storage_readWindowBusyState(win) {
+    let state;
+
+    try {
+      let data = this._sessionStore.getWindowState(win);
+      if (data)
+        state = JSON.parse(data);
+    } catch (e) {
+      Utils.log("Error while parsing window state");
+    }
+
+    return (state && state.windows[0].busy);
+  },
+
+  // ----------
   // Function: saveGroupItemsData
   // Saves the global data for the <GroupItems> singleton for the given window.
   saveGroupItemsData: function Storage_saveGroupItemsData(win, data) {
     this.saveData(win, this.GROUPS_DATA_IDENTIFIER, data);
   },
 
   // ----------
   // Function: readGroupItemsData
--- a/browser/base/content/tabview/tabitems.js
+++ b/browser/base/content/tabview/tabitems.js
@@ -473,39 +473,32 @@ TabItem.prototype = Utils.extend(new Ite
   // Parameters:
   //   groupClose - true if this method is called by group close action.
   // Returns true if this tab is removed.
   close: function TabItem_close(groupClose) {
     // When the last tab is closed, put a new tab into closing tab's group. If
     // closing tab doesn't belong to a group and no empty group, create a new 
     // one for the new tab.
     if (!groupClose && gBrowser.tabs.length == 1) {
-      let group;
-      if (this.tab._tabViewTabItem.parent) {
-        group = this.tab._tabViewTabItem.parent;
-      } else {
-        let emptyGroups = GroupItems.groupItems.filter(function (groupItem) {
-          return (!groupItem.getChildren().length);
-        });
-        group = (emptyGroups.length ? emptyGroups[0] : GroupItems.newGroup());
-      }
+      let group = this.tab._tabViewTabItem.parent;
       group.newTab(null, { closedLastTab: true });
     }
+
     // when "TabClose" event is fired, the browser tab is about to close and our 
     // item "close" is fired before the browser tab actually get closed. 
     // Therefore, we need "tabRemoved" event below.
     gBrowser.removeTab(this.tab);
-    let tabNotClosed = 
-      Array.some(gBrowser.tabs, function(tab) { return tab == this.tab; }, this);
-    if (!tabNotClosed)
+    let tabClosed = !this.tab;
+
+    if (tabClosed)
       this._sendToSubscribers("tabRemoved");
 
     // No need to explicitly delete the tab data, becasue sessionstore data
     // associated with the tab will automatically go away
-    return !tabNotClosed;
+    return tabClosed;
   },
 
   // ----------
   // Function: addClass
   // Adds the specified CSS class to this item's container DOM element.
   addClass: function TabItem_addClass(className) {
     this.$container.addClass(className);
   },
@@ -741,46 +734,45 @@ let TabItems = {
     $canvas.hide();
     this.tempCanvas = $canvas[0];
     // 150 pixels is an empirical size, below which FF's drawWindow()
     // algorithm breaks down
     this.tempCanvas.width = 150;
     this.tempCanvas.height = 112;
 
     // When a tab is opened, create the TabItem
-    this._eventListeners["open"] = function(tab) {
-      if (tab.ownerDocument.defaultView != gWindow || tab.pinned)
-        return;
+    this._eventListeners.open = function (event) {
+      let tab = event.target;
 
-      self.link(tab);
+      if (!tab.pinned)
+        self.link(tab);
     }
     // When a tab's content is loaded, show the canvas and hide the cached data
     // if necessary.
-    this._eventListeners["attrModified"] = function(tab) {
-      if (tab.ownerDocument.defaultView != gWindow || tab.pinned)
-        return;
+    this._eventListeners.attrModified = function (event) {
+      let tab = event.target;
 
-      self.update(tab);
+      if (!tab.pinned)
+        self.update(tab);
     }
     // When a tab is closed, unlink.
-    this._eventListeners["close"] = function(tab) {
-      if (tab.ownerDocument.defaultView != gWindow || tab.pinned)
-        return;
+    this._eventListeners.close = function (event) {
+      let tab = event.target;
 
       // XXX bug #635975 - don't unlink the tab if the dom window is closing.
-      if (!UI.isDOMWindowClosing)
+      if (!tab.pinned && !UI.isDOMWindowClosing)
         self.unlink(tab);
     }
     for (let name in this._eventListeners) {
       AllTabs.register(name, this._eventListeners[name]);
     }
 
     // For each tab, create the link.
-    AllTabs.tabs.forEach(function(tab) {
-      if (tab.ownerDocument.defaultView != gWindow || tab.pinned)
+    AllTabs.tabs.forEach(function (tab) {
+      if (tab.pinned)
         return;
 
       self.link(tab, {immediately: true});
       self.update(tab);
     });
   },
 
   // ----------
--- a/browser/base/content/tabview/tabview.js
+++ b/browser/base/content/tabview/tabview.js
@@ -1,16 +1,15 @@
 "use strict";
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 const Cr = Components.results;
 
-Cu.import("resource:///modules/tabview/AllTabs.jsm");
 Cu.import("resource:///modules/tabview/utils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "tabviewBundle", function() {
   return Services.strings.
     createBundle("chrome://browser/locale/tabview.properties");
 });
@@ -39,16 +38,40 @@ XPCOMUtils.defineLazyGetter(this, "gNetU
 
 var gWindow = window.parent;
 var gBrowser = gWindow.gBrowser;
 var gTabView = gWindow.TabView;
 var gTabViewDeck = gWindow.document.getElementById("tab-view-deck");
 var gBrowserPanel = gWindow.document.getElementById("browser-panel");
 var gTabViewFrame = gWindow.document.getElementById("tab-view");
 
+let AllTabs = {
+  _events: {
+    attrModified: "TabAttrModified",
+    close:        "TabClose",
+    move:         "TabMove",
+    open:         "TabOpen",
+    select:       "TabSelect",
+    pinned:       "TabPinned",
+    unpinned:     "TabUnpinned"
+  },
+
+  get tabs() {
+    return Array.filter(gBrowser.tabs, function (tab) !tab.closing);
+  },
+
+  register: function AllTabs_register(eventName, callback) {
+    gBrowser.tabContainer.addEventListener(this._events[eventName], callback, false);
+  },
+
+  unregister: function AllTabs_unregister(eventName, callback) {
+    gBrowser.tabContainer.removeEventListener(this._events[eventName], callback, false);
+  }
+};
+
 # NB: Certain files need to evaluate before others
 
 #include iq.js
 #include storage.js
 #include items.js
 #include groupitems.js
 #include tabitems.js
 #include drag.js
--- a/browser/base/content/tabview/ui.js
+++ b/browser/base/content/tabview/ui.js
@@ -21,16 +21,17 @@
  * Contributor(s):
  * Ian Gilman <ian@iangilman.com>
  * Aza Raskin <aza@mozilla.com>
  * Michael Yoshitaka Erlewine <mitcho@mitcho.com>
  * Ehsan Akhgari <ehsan@mozilla.com>
  * Raymond Lee <raymond@appcoast.com>
  * Sean Dunn <seanedunn@yahoo.com>
  * Tim Taubert <tim.taubert@gmx.de>
+ * Mihai Sucan <mihai.sucan@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -75,16 +76,20 @@ let UI = {
   // Variable: _closedSelectedTabInTabView
   // If true, a select tab has just been closed in TabView.
   _closedSelectedTabInTabView: false,
 
   // Variable: restoredClosedTab
   // If true, a closed tab has just been restored.
   restoredClosedTab: false,
 
+  // Variable: _isChangingVisibility
+  // Tracks whether we're currently in the process of showing/hiding the tabview.
+  _isChangingVisibility: false,
+
   // Variable: _reorderTabItemsOnShow
   // Keeps track of the <GroupItem>s which their tab items' tabs have been moved
   // and re-orders the tab items when switching to TabView.
   _reorderTabItemsOnShow: [],
 
   // Variable: _reorderTabsOnHide
   // Keeps track of the <GroupItem>s which their tab items have been moved in
   // TabView UI and re-orders the tabs when switcing back to main browser.
@@ -118,19 +123,19 @@ let UI = {
   // Keeps track of info related to private browsing, including: 
   //   transitionMode - whether we're entering or exiting PB
   //   wasInTabView - whether TabView was visible before we went into PB
   _privateBrowsing: {
     transitionMode: "",
     wasInTabView: false 
   },
   
-  // Variable: _storageBusyCount
-  // Used to keep track of how many calls to storageBusy vs storageReady.
-  _storageBusyCount: 0,
+  // Variable: _storageBusy
+  // Tells whether the storage is currently busy or not.
+  _storageBusy: false,
 
   // Variable: isDOMWindowClosing
   // Tells wether the parent window is about to close
   isDOMWindowClosing: false,
 
   // Variable: _browserKeys
   // Used to keep track of allowed browser keys.
   _browserKeys: null,
@@ -164,16 +169,20 @@ let UI = {
       // initialize the direction of the page
       this._initPageDirection();
 
       // ___ thumbnail storage
       ThumbnailStorage.init();
 
       // ___ storage
       Storage.init();
+
+      if (Storage.readWindowBusyState(gWindow))
+        this.storageBusy();
+
       let data = Storage.readUIData(gWindow);
       this._storageSanity(data);
       this._pageBounds = data.pageBounds;
 
       // ___ currentTab
       this._currentTab = gBrowser.selectedTab;
 
       // ___ exit button
@@ -225,16 +234,25 @@ let UI = {
           }
         }
       });
 
       iQ(window).bind("unload", function() {
         self.uninit();
       });
 
+      // ___ setup DOMWillOpenModalDialog message handler
+      let mm = gWindow.messageManager;
+      let callback = this._onDOMWillOpenModalDialog.bind(this);
+      mm.addMessageListener("Panorama:DOMWillOpenModalDialog", callback);
+
+      this._cleanupFunctions.push(function () {
+        mm.removeMessageListener("Panorama:DOMWillOpenModalDialog", callback);
+      });
+
       // ___ setup key handlers
       this._setTabViewFrameKeyHandlers();
 
       // ___ add tab action handlers
       this._addTabActionHandlers();
 
       // ___ groups
       GroupItems.init();
@@ -267,16 +285,20 @@ let UI = {
         if (self.isTabViewVisible())
           GroupItems.removeHiddenGroups();
 
         Storage.saveActiveGroupName(gWindow);
         TabItems.saveAll(true);
         self._save();
       }, false);
 
+      // ___ load frame script
+      let frameScript = "chrome://browser/content/tabview-content.js";
+      gWindow.messageManager.loadFrameScript(frameScript, true);
+
       // ___ Done
       this._frameInitialized = true;
       this._save();
 
       // fire an iframe initialized event so everyone knows tab view is 
       // initialized.
       let event = document.createEvent("Events");
       event.initEvent("tabviewframeinitialized", true, false);
@@ -472,19 +494,21 @@ let UI = {
   },
 
   // ----------
   // Function: showTabView
   // Shows TabView and hides the main browser UI.
   // Parameters:
   //   zoomOut - true for zoom out animation, false for nothing.
   showTabView: function UI_showTabView(zoomOut) {
-    if (this.isTabViewVisible())
+    if (this.isTabViewVisible() || this._isChangingVisibility)
       return;
 
+    this._isChangingVisibility = true;
+
     // initialize the direction of the page
     this._initPageDirection();
 
     var self = this;
     var currentTab = this._currentTab;
 
     this._reorderTabItemsOnShow.forEach(function(groupItem) {
       groupItem.reorderTabItemsBasedOnTabOrder();
@@ -517,44 +541,48 @@ let UI = {
       // Zoom out!
       item.zoomOut(function() {
         if (!currentTab._tabViewTabItem) // if the tab's been destroyed
           item = null;
 
         self.setActive(item);
 
         self._resize(true);
+        self._isChangingVisibility = false;
         dispatchEvent(event);
 
         // Flush pending updates
         GroupItems.flushAppTabUpdates();
 
         TabItems.resumePainting();
       });
     } else {
       self.clearActiveTab();
+      self._isChangingVisibility = false;
       dispatchEvent(event);
 
       // Flush pending updates
       GroupItems.flushAppTabUpdates();
 
       TabItems.resumePainting();
     }
 
     if (gTabView.firstUseExperienced)
       gTabView.enableSessionRestore();
   },
 
   // ----------
   // Function: hideTabView
   // Hides TabView and shows the main browser UI.
   hideTabView: function UI_hideTabView() {
-    if (!this.isTabViewVisible())
+    if (!this.isTabViewVisible() || this._isChangingVisibility)
       return;
 
+    this._isChangingVisibility = true;
+
     // another tab might be select if user decides to stay on a page when
     // a onclose confirmation prompts.
     GroupItems.removeHiddenGroups();
     TabItems.pausePainting();
 
     this._reorderTabsOnHide.forEach(function(groupItem) {
       groupItem.reorderTabsBasedOnTabItemOrder();
     });
@@ -571,16 +599,18 @@ let UI = {
     gBrowser.contentWindow.focus();
 
     gBrowser.updateTitlebar();
 #ifdef XP_MACOSX
     this.setTitlebarColors(false);
 #endif
     Storage.saveVisibilityData(gWindow, "false");
 
+    this._isChangingVisibility = false;
+
     let event = document.createEvent("Events");
     event.initEvent("tabviewhidden", true, false);
     dispatchEvent(event);
   },
 
 #ifdef XP_MACOSX
   // ----------
   // Function: setTitlebarColors
@@ -607,39 +637,42 @@ let UI = {
   },
 #endif
 
   // ----------
   // Function: storageBusy
   // Pauses the storage activity that conflicts with sessionstore updates and 
   // private browsing mode switches. Calls can be nested. 
   storageBusy: function UI_storageBusy() {
-    if (!this._storageBusyCount) {
-      TabItems.pauseReconnecting();
-      GroupItems.pauseAutoclose();
-    }
-    
-    this._storageBusyCount++;
+    if (this._storageBusy)
+      return;
+
+    this._storageBusy = true;
+
+    TabItems.pauseReconnecting();
+    GroupItems.pauseAutoclose();
   },
   
   // ----------
   // Function: storageReady
   // Resumes the activity paused by storageBusy, and updates for any new group
   // information in sessionstore. Calls can be nested. 
   storageReady: function UI_storageReady() {
-    this._storageBusyCount--;
-    if (!this._storageBusyCount) {
-      let hasGroupItemsData = GroupItems.load();
-      if (!hasGroupItemsData)
-        this.reset();
-  
-      TabItems.resumeReconnecting();
-      GroupItems._updateTabBar();
-      GroupItems.resumeAutoclose();
-    }
+    if (!this._storageBusy)
+      return;
+
+    this._storageBusy = false;
+
+    let hasGroupItemsData = GroupItems.load();
+    if (!hasGroupItemsData)
+      this.reset();
+
+    TabItems.resumeReconnecting();
+    GroupItems._updateTabBar();
+    GroupItems.resumeAutoclose();
   },
 
   // ----------
   // Function: _addTabActionHandlers
   // Adds handlers to handle tab actions.
   _addTabActionHandlers: function UI__addTabActionHandlers() {
     var self = this;
 
@@ -673,16 +706,17 @@ let UI = {
         if (data == "enter") {
           // If we are in Tab View, exit. 
           self._privateBrowsing.wasInTabView = self.isTabViewVisible();
           if (self.isTabViewVisible())
             self.goToTab(gBrowser.selectedTab);
         }
       } else if (topic == "private-browsing-change-granted") {
         if (data == "enter" || data == "exit") {
+          hideSearch();
           self._privateBrowsing.transitionMode = data;
           self.storageBusy();
         }
       } else if (topic == "private-browsing-transition-complete") {
         // We use .transitionMode here, as aData is empty.
         if (self._privateBrowsing.transitionMode == "exit" &&
             self._privateBrowsing.wasInTabView)
           self.showTabView(false);
@@ -698,44 +732,42 @@ let UI = {
 
     this._cleanupFunctions.push(function() {
       Services.obs.removeObserver(pbObserver, "private-browsing");
       Services.obs.removeObserver(pbObserver, "private-browsing-change-granted");
       Services.obs.removeObserver(pbObserver, "private-browsing-transition-complete");
     });
 
     // TabOpen
-    this._eventListeners.open = function(tab) {
-      if (tab.ownerDocument.defaultView != gWindow)
-        return;
+    this._eventListeners.open = function (event) {
+      let tab = event.target;
 
       // if it's an app tab, add it to all the group items
       if (tab.pinned)
         GroupItems.addAppTab(tab);
       else if (self.isTabViewVisible() && !self._storageBusyCount)
         self._lastOpenedTab = tab;
     };
     
     // TabClose
-    this._eventListeners.close = function(tab) {
-      if (tab.ownerDocument.defaultView != gWindow)
-        return;
+    this._eventListeners.close = function (event) {
+      let tab = event.target;
 
       // if it's an app tab, remove it from all the group items
       if (tab.pinned)
         GroupItems.removeAppTab(tab);
         
       if (self.isTabViewVisible()) {
         // just closed the selected tab in the TabView interface.
         if (self._currentTab == tab)
           self._closedSelectedTabInTabView = true;
       } else {
         // If we're currently in the process of entering private browsing,
         // we don't want to go to the Tab View UI. 
-        if (self._storageBusyCount)
+        if (self._storageBusy)
           return;
 
         // if not closing the last tab
         if (gBrowser.tabs.length > 1) {
           // Don't return to TabView if there are any app tabs
           for (let a = 0; a < gBrowser._numPinnedTabs; a++) {
             if (!gBrowser.tabs[a].closing)
               return;
@@ -744,77 +776,64 @@ let UI = {
           var groupItem = GroupItems.getActiveGroupItem();
 
           // 1) Only go back to the TabView tab when there you close the last
           // tab of a groupItem.
           let closingLastOfGroup = (groupItem && 
               groupItem._children.length == 1 && 
               groupItem._children[0].tab == tab);
 
-          // 2) Take care of the case where you've closed the last tab in
-          // an un-named groupItem, which means that the groupItem is gone (null) and
-          // there are no visible tabs. 
-          let closingUnnamedGroup = (groupItem == null &&
-              gBrowser.visibleTabs.length <= 1); 
-
-          // 3) When a blank tab is active while restoring a closed tab the
+          // 2) When a blank tab is active while restoring a closed tab the
           // blank tab gets removed. The active group is not closed as this is
           // where the restored tab goes. So do not show the TabView.
           let tabItem = tab && tab._tabViewTabItem;
           let closingBlankTabAfterRestore =
             (tabItem && tabItem.isRemovedAfterRestore);
 
-          if ((closingLastOfGroup || closingUnnamedGroup) &&
-              !closingBlankTabAfterRestore) {
+          if (closingLastOfGroup && !closingBlankTabAfterRestore) {
             // for the tab focus event to pick up.
             self._closedLastVisibleTab = true;
             self.showTabView();
           }
         }
       }
     };
 
     // TabMove
-    this._eventListeners.move = function(tab) {
-      if (tab.ownerDocument.defaultView != gWindow)
-        return;
+    this._eventListeners.move = function (event) {
+      let tab = event.target;
 
       if (GroupItems.groupItems.length > 0) {
         if (tab.pinned) {
           if (gBrowser._numPinnedTabs > 1)
             GroupItems.arrangeAppTab(tab);
         } else {
           let activeGroupItem = GroupItems.getActiveGroupItem();
           if (activeGroupItem)
             self.setReorderTabItemsOnShow(activeGroupItem);
         }
       }
     };
 
     // TabSelect
-    this._eventListeners.select = function(tab) {
-      if (tab.ownerDocument.defaultView != gWindow)
-        return;
-
-      self.onTabSelect(tab);
+    this._eventListeners.select = function (event) {
+      self.onTabSelect(event.target);
     };
 
     // TabPinned
-    this._eventListeners.pinned = function(tab) {
-      if (tab.ownerDocument.defaultView != gWindow)
-        return;
+    this._eventListeners.pinned = function (event) {
+      let tab = event.target;
 
       TabItems.handleTabPin(tab);
       GroupItems.addAppTab(tab);
     };
 
     // TabUnpinned
-    this._eventListeners.unpinned = function(tab) {
-      if (tab.ownerDocument.defaultView != gWindow)
-        return;
+    this._eventListeners.unpinned = function (event) {
+      let tab = event.target;
 
       TabItems.handleTabUnpin(tab);
       GroupItems.removeAppTab(tab);
 
       let groupItem = tab._tabViewTabItem.parent;
       if (groupItem)
         self.setReorderTabItemsOnShow(groupItem);
     };
@@ -878,18 +897,24 @@ let UI = {
     this._closedLastVisibleTab = false;
     this._closedSelectedTabInTabView = false;
     this.closedLastTabInTabView = false;
     this.restoredClosedTab = false;
     this._lastOpenedTab = null;
 
     // if TabView is visible but we didn't just close the last tab or
     // selected tab, show chrome.
-    if (this.isTabViewVisible())
+    if (this.isTabViewVisible()) {
+      // Unhide the group of the tab the user is activating.
+      if (tab && tab._tabViewTabItem && tab._tabViewTabItem.parent &&
+          tab._tabViewTabItem.parent.hidden)
+        tab._tabViewTabItem.parent._unhide({immediately: true});
+
       this.hideTabView();
+    }
 
     // another tab might be selected when hideTabView() is invoked so a
     // validation is needed.
     if (this._currentTab != tab)
       return;
 
     let newItem = null;
     // update the tab bar for the new tab's group
@@ -914,16 +939,37 @@ let UI = {
       }
 
       if (GroupItems.getActiveGroupItem())
         GroupItems._updateTabBar();
     }
   },
 
   // ----------
+  // Function: _onDOMWillOpenModalDialog
+  // Called when a web page is about to show a modal dialog.
+  _onDOMWillOpenModalDialog: function UI__onDOMWillOpenModalDialog(cx) {
+    if (!this.isTabViewVisible())
+      return;
+
+    let index = gBrowser.browsers.indexOf(cx.target);
+    if (index == -1)
+      return;
+
+    let tab = gBrowser.tabs[index];
+
+    // When TabView is visible, we need to call onTabSelect to make sure that
+    // TabView is hidden and that the correct group is activated. When a modal
+    // dialog is shown for currently selected tab the onTabSelect event handler
+    // is not called, so we need to do it.
+    if (gBrowser.selectedTab == tab && this._currentTab == tab)
+      this.onTabSelect(tab);
+  },
+
+  // ----------
   // Function: setReorderTabsOnHide
   // Sets the groupItem which the tab items' tabs should be re-ordered when
   // switching to the main browser UI.
   // Parameters:
   //   groupItem - the groupItem which would be used for re-ordering tabs.
   setReorderTabsOnHide: function UI_setReorderTabsOnHide(groupItem) {
     if (this.isTabViewVisible()) {
       var index = this._reorderTabsOnHide.indexOf(groupItem);
--- a/browser/base/content/test/tabview/Makefile.in
+++ b/browser/base/content/test/tabview/Makefile.in
@@ -106,16 +106,17 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_bug624727.js \
                  browser_tabview_bug624847.js \
                  browser_tabview_bug624931.js \
                  browser_tabview_bug624953.js \
                  browser_tabview_bug625195.js \
                  browser_tabview_bug625269.js \
                  browser_tabview_bug625424.js \
                  browser_tabview_bug626368.js \
+                 browser_tabview_bug626455.js \
                  browser_tabview_bug626525.js \
                  browser_tabview_bug626791.js \
                  browser_tabview_bug627239.js \
                  browser_tabview_bug627288.js \
                  browser_tabview_bug627736.js \
                  browser_tabview_bug628061.js \
                  browser_tabview_bug628165.js \
                  browser_tabview_bug628270.js \
@@ -134,16 +135,17 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_bug641802.js \
                  browser_tabview_bug642793.js \
                  browser_tabview_bug643392.js \
                  browser_tabview_bug644097.js \
                  browser_tabview_bug648882.js \
                  browser_tabview_bug649006.js \
                  browser_tabview_bug649307.js \
                  browser_tabview_bug649319.js \
+                 browser_tabview_bug650280.js \
                  browser_tabview_bug650573.js \
                  browser_tabview_bug651311.js \
                  browser_tabview_bug654721.js \
                  browser_tabview_bug654941.js \
                  browser_tabview_bug655269.js \
                  browser_tabview_bug656778.js \
                  browser_tabview_bug656913.js \
                  browser_tabview_bug662266.js \
--- a/browser/base/content/test/tabview/browser_tabview_alltabs.js
+++ b/browser/base/content/test/tabview/browser_tabview_alltabs.js
@@ -1,38 +1,45 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-Cu.import("resource:///modules/tabview/AllTabs.jsm");
-
 function test() {
   waitForExplicitFinish();
 
+  let AllTabs;
   let newTab = gBrowser.addTab();
 
   // TabPinned
-  let pinned = function(tab) {
+  let pinned = function (event) {
+    let tab = event.target;
+
     is(tab, newTab, "The tabs are the same after the tab is pinned");
     ok(tab.pinned, "The tab gets pinned");
 
     gBrowser.unpinTab(tab);
   };
 
   // TabUnpinned
-  let unpinned = function(tab) {
+  let unpinned = function (event) {
+    let tab = event.target;
+
     AllTabs.unregister("pinned", pinned);
     AllTabs.unregister("unpinned", unpinned);
 
     is(tab, newTab, "The tabs are the same after the tab is unpinned");
     ok(!tab.pinned, "The tab gets unpinned");
 
     // clean up and finish
     gBrowser.removeTab(tab);
-    finish();
+    hideTabView(finish);
   };
 
-  AllTabs.register("pinned", pinned);
-  AllTabs.register("unpinned", unpinned);
+  showTabView(function () {
+    AllTabs = TabView.getContentWindow().AllTabs;
 
-  ok(!newTab.pinned, "The tab is not pinned");
-  gBrowser.pinTab(newTab);
+    AllTabs.register("pinned", pinned);
+    AllTabs.register("unpinned", unpinned);
+
+    ok(!newTab.pinned, "The tab is not pinned");
+    gBrowser.pinTab(newTab);
+  });
 }
 
--- a/browser/base/content/test/tabview/browser_tabview_bug597248.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug597248.js
@@ -17,51 +17,45 @@ function setupOne(win) {
   win.TabView.firstUseExperienced = true;
 
   win.gBrowser.addTab("http://mochi.test:8888/browser/browser/base/content/test/tabview/search1.html");
   win.gBrowser.addTab("http://mochi.test:8888/browser/browser/base/content/test/tabview/dummy_page.html");
 
   afterAllTabsLoaded(function () setupTwo(win), win);
 }
 
-let restoreWin;
+let restoredWin;
 
 function setupTwo(win) {
   let contentWindow = win.TabView.getContentWindow();
 
   let tabItems = contentWindow.TabItems.getItems();
   is(tabItems.length, 3, "There should be 3 tab items before closing");
 
   let numTabsToSave = tabItems.length;
 
   // force all canvases to update, and hook in imageData save detection
   tabItems.forEach(function(tabItem) {
     contentWindow.TabItems.update(tabItem.tab);
     tabItem.addSubscriber("savedCachedImageData", function onSaved(item) {
       item.removeSubscriber("savedCachedImageData", onSaved);
-      --numTabsToSave;
+
+      if (!--numTabsToSave)
+        restoreWindow();
     });
   });
 
   // after the window is closed, restore it.
-  let xulWindowDestory = function() {
-    Services.obs.removeObserver(
-       xulWindowDestory, "xul-window-destroyed", false);
-
-    // "xul-window-destroyed" is just fired just before a XUL window is
-    // destroyed so restore window and test it after a delay
+  let restoreWindow = function() {
     executeSoon(function() {
       restoredWin = undoCloseWindow();
       restoredWin.addEventListener("load", function onLoad(event) {
         restoredWin.removeEventListener("load", onLoad, false);
 
         registerCleanupFunction(function() restoredWin.close());
-
-        // ensure that closed tabs have been saved
-        is(numTabsToSave, 0, "All tabs were saved when window was closed.");
         is(restoredWin.gBrowser.tabs.length, 3, "The total number of tabs is 3");
 
         // setup tab variables and listen to the tabs load progress
         newTabOne = restoredWin.gBrowser.tabs[0];
         newTabTwo = restoredWin.gBrowser.tabs[1];
         newTabThree = restoredWin.gBrowser.tabs[2];
         restoredWin.gBrowser.addTabsProgressListener(gTabsProgressListener);
 
@@ -98,17 +92,16 @@ function setupTwo(win) {
           });
         }
 
         restoredWin.addEventListener(
           "tabviewframeinitialized", onTabViewFrameInitialized, false);
       }, false);
     });
   };
-  Services.obs.addObserver(xulWindowDestory, "xul-window-destroyed", false);
 
   win.close();
 }
 
 let gTabsProgressListener = {
   onStateChange: function(browser, webProgress, request, stateFlags, status) {
     // ensure about:blank doesn't trigger the code
     if ((stateFlags & Ci.nsIWebProgressListener.STATE_STOP) &&
--- a/browser/base/content/test/tabview/browser_tabview_bug597980.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug597980.js
@@ -5,17 +5,17 @@ function test() {
   waitForExplicitFinish();
 
   newWindowWithTabView(part1);
 }
 
 function part1(win) {
   registerCleanupFunction(function() win.close());
 
-  let contentWindow = win.document.getElementById("tab-view").contentWindow;
+  let contentWindow = win.TabView.getContentWindow();
   is(contentWindow.GroupItems.groupItems.length, 1, "Has only one group");
 
   let originalTab = win.gBrowser.selectedTab;
   let originalGroup = contentWindow.GroupItems.groupItems[0];
   let newTab = win.gBrowser.loadOneTab("about:blank", {inBackground: true});
   
   is(originalGroup.getChildren().length, 2, "The original group now has two tabs");
   
@@ -66,20 +66,17 @@ function part2(win) {
   let newTab = win.gBrowser.loadOneTab("about:blank", {inBackground: true});
   hideTabView(function() {
     let selectedTab = win.gBrowser.selectedTab;
     isnot(selectedTab, newTab, "They are different tabs");
 
     // switch the selected tab to new tab
     win.gBrowser.selectedTab = newTab;
 
-    whenTabViewIsHidden(function () {
-      is(win.gBrowser.selectedTab, newTab, "The seleted tab should be the same as before (new tab)");
-       win.close();
-       finish();
-    });
-
-    // show tabview
-    EventUtils.synthesizeKey("e", { accelKey: true, shiftKey: true }, win);
-    // hide tabview
-    EventUtils.synthesizeKey("e", { accelKey: true, shiftKey: true }, win);
-  })
+    showTabView(function () {
+      hideTabView(function () {
+        is(win.gBrowser.selectedTab, newTab,
+           "The selected tab should be the same as before (new tab)");
+        waitForFocus(finish);
+      }, win);
+    }, win);
+  }, win);
 }
--- a/browser/base/content/test/tabview/browser_tabview_bug599626.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug599626.js
@@ -16,19 +16,17 @@ function onTabViewShown() {
 
   afterAllTabsLoaded(function () {
     testStayOnPage(contentWindow, groupItemOne, groupItemTwo);
   });
 }
 
 function testStayOnPage(contentWindow, groupItemOne, groupItemTwo) {
   whenDialogOpened(function (dialog) {
-    groupItemTwo.addSubscriber("groupShown", function onShown() {
-      groupItemTwo.removeSubscriber("groupShown", onShown);
-
+    executeSoon(function () {
       is(gBrowser.tabs.length, 2, 
          "The total number of tab is 2 when staying on the page");
       is(contentWindow.TabItems.getItems().length, 2, 
          "The total number of tab items is 2 when staying on the page");
 
       showTabView(function () {
         // start the next test
         testLeavePage(contentWindow, groupItemOne, groupItemTwo);
--- a/browser/base/content/test/tabview/browser_tabview_bug604098.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug604098.js
@@ -20,16 +20,17 @@ function test() {
   });
 }
 
 function test1() {
   let groupItems = contentWindow.GroupItems.groupItems;
   is(groupItems.length, 1, "there is one groupItem");
 
   whenTabViewIsHidden(function() {
+    gBrowser.selectedTab = gBrowser.tabs[0];
     is(groupItems.length, 2, "there are two groupItems");
     closeGroupItem(groupItems[1], finish);
   });
 
   // first click
   mouseClick(contentElement, 0);
   // second click
   mouseClick(contentElement, 0);
--- a/browser/base/content/test/tabview/browser_tabview_bug624953.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug624953.js
@@ -13,11 +13,11 @@ function test() {
 
     groupItem.setSize(100, 100, true);
     groupItem.setUserSize();
     ok(!groupItem.isStacked(), 'groupItem is still not stacked');
 
     cw.GroupItems.resumeArrange();
     ok(groupItem.isStacked(), 'groupItem is now stacked');
 
-    closeGroupItem(groupItem, finish);
+    closeGroupItem(groupItem, function () hideTabView(finish));
   });
 }
--- a/browser/base/content/test/tabview/browser_tabview_bug625195.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug625195.js
@@ -29,17 +29,17 @@ function test() {
 
     whenTabViewIsHidden(function() {
       popup(gBrowser.tabs[0]);
 
       ok(!document.getElementById("context_closeTab").disabled, "The 'Close tab' menu item is enabled");
       ok(!document.getElementById("context_openTabInWindow").disabled, "The 'Move to New Window' menu item is enabled");
 
       let newTabTwo = gBrowser.selectedTab;
-      gBrowser.selected = originalTab;
+      gBrowser.selectedTab = originalTab;
 
       gBrowser.removeTab(newTabOne);
       gBrowser.removeTab(newTabTwo);
 
       finish();
     });
     let newGroup = contentWindow.GroupItems.newGroup();
     newGroup.newTab();
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug626455.js
@@ -0,0 +1,127 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ *   Mihai Sucan <mihai.sucan@gmail.com>
+ *   Raymond Lee <raymond@appcoast.com>
+ */
+
+const TEST_URL = 'data:text/html,<script>window.onbeforeunload=' +
+                 'function(e){e.returnValue="?"}</script><body ' +
+                 'onunload="alert(\'onunload\')" onpagehide="' +
+                 'alert(\'onpagehide\')"></body>';
+
+let contentWindow;
+let activeGroup;
+
+function test() {
+  waitForExplicitFinish();
+
+  showTabView(function () {
+    contentWindow = TabView.getContentWindow();
+    activeGroup = contentWindow.GroupItems.getActiveGroupItem();
+
+    gBrowser.browsers[0].contentWindow.location =
+      "data:text/html,<p>test for bug 626455, tab1";
+    gBrowser.addTab(TEST_URL);
+
+    afterAllTabsLoaded(testStayOnPage);
+  });
+}
+
+function testStayOnPage() {
+  whenDialogOpened(function (dialog) {
+    // stay on page
+    dialog.cancelDialog();
+
+    executeSoon(function () {
+      showTabView(function () {
+        is(gBrowser.tabs.length, 1,
+           "The total number of tab is 1 when staying on the page");
+
+        let location = gBrowser.browsers[0].contentWindow.location.toString();
+        isnot(location.indexOf("onbeforeunload"), -1,
+              "The open tab is the expected one");
+
+        is(contentWindow.GroupItems.getActiveGroupItem(), activeGroup,
+           "Active group is still the same");
+
+        is(contentWindow.GroupItems.groupItems.length, 1,
+           "Only one group is open");
+
+        // start the next test
+        testLeavePage();
+      });
+    });
+  });
+
+  closeGroupItem(activeGroup);
+}
+
+function testLeavePage() {
+  let dialogsAccepted = 0;
+
+  whenDialogOpened(function onDialogOpened(dialog) {
+    if (++dialogsAccepted < 3)
+      whenDialogOpened(onDialogOpened);
+
+    // Leave page
+    dialog.acceptDialog();
+  });
+
+  whenGroupClosed(activeGroup, finishTest);
+  closeGroupItem(activeGroup);
+}
+
+function finishTest() {
+  is(gBrowser.tabs.length, 1,
+     "The total number of tab is 1 after leaving the page");
+  is(contentWindow.TabItems.getItems().length, 1,
+     "The total number of tab items is 1 after leaving the page");
+
+  let location = gBrowser.browsers[0].contentWindow.location.toString();
+  is(location, "about:blank", "The open tab is the expected one");
+
+  isnot(contentWindow.GroupItems.getActiveGroupItem(), activeGroup,
+     "Active group is no longer the same");
+
+  is(contentWindow.GroupItems.groupItems.length, 1,
+     "Only one group is open");
+
+  finish();
+}
+
+// ----------
+function whenGroupClosed(group, callback) {
+  group.addSubscriber("close", function onClose() {
+    group.removeSubscriber("close", onClose);
+    callback();
+  });
+}
+
+// ----------
+function whenDialogOpened(callback) {
+  let wm = Cc["@mozilla.org/appshell/window-mediator;1"]
+           .getService(Ci.nsIWindowMediator);
+
+  let listener = {
+    onCloseWindow: function () {},
+    onWindowTitleChange: function () {},
+
+    onOpenWindow: function (xulWin) {
+      let domWin = xulWin.QueryInterface(Ci.nsIInterfaceRequestor)
+                   .getInterface(Ci.nsIDOMWindow);
+
+      whenWindowLoaded(domWin, function () {
+        let dialog = domWin.document.querySelector("dialog");
+        if (dialog) {
+          wm.removeListener(listener);
+          callback(dialog);
+        }
+      });
+    }
+  };
+
+  wm.addListener(listener);
+}
--- a/browser/base/content/test/tabview/browser_tabview_bug642793.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug642793.js
@@ -10,17 +10,17 @@ function loadTabs (win) {
   for (let i = 0; i < 4; i++)
     win.gBrowser.loadOneTab('about:blank', {inBackground: false});
   win.gBrowser.selectedTab = win.gBrowser.tabs[2];
 }
 
 function testTopOfStack(win) {
   registerCleanupFunction(function () { win.close(); });
   let cw = win.TabView.getContentWindow();
-  groupItem = cw.GroupItems.getActiveGroupItem();
+  let groupItem = cw.GroupItems.getActiveGroupItem();
   ok(!groupItem.isStacked(), 'groupItem is not stacked');
   groupItem.setSize(150, 150);
   groupItem.setUserSize();
   ok(groupItem.isStacked(), 'groupItem is now stacked');
   ok(groupItem.isTopOfStack(groupItem.getChild(2)),
     'the third tab is on top of stack');
   finish();
 }
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug650280.js
@@ -0,0 +1,67 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let pb = Cc["@mozilla.org/privatebrowsing;1"].
+         getService(Ci.nsIPrivateBrowsingService);
+
+function test() {
+  let cw;
+
+  registerCleanupFunction(function() {
+    if (cw)
+      cw.hideSearch();
+
+    TabView.hide();
+    pb.privateBrowsingEnabled = false;
+  });
+
+  let enableSearch = function (callback) {
+    if (cw.isSearchEnabled()) {
+      callback();
+      return;
+    }
+
+    cw.addEventListener("tabviewsearchenabled", function onSearchEnabled() {
+      cw.removeEventListener("tabviewsearchenabled", onSearchEnabled, false);
+      executeSoon(callback);
+    }, false);
+
+    cw.ensureSearchShown();
+  };
+
+  let getSearchboxValue = function () {
+    return cw.iQ("#searchbox").val();
+  };
+
+  let prepareSearchbox = function (callback) {
+    ok(!cw.isSearchEnabled(), "search is disabled");
+
+    enableSearch(function () {
+      cw.iQ("#searchbox").val("moz");
+      callback();
+    });
+  };
+
+  let searchAndSwitchPBMode = function (callback) {
+    prepareSearchbox(function () {
+      togglePrivateBrowsing(function () {
+        showTabView(function () {
+          ok(!cw.isSearchEnabled(), "search is disabled");
+          is(getSearchboxValue(), "", "search box is empty");
+          callback();
+        });
+      });
+    });
+  };
+
+  waitForExplicitFinish();
+
+  showTabView(function () {
+    cw = TabView.getContentWindow();
+    searchAndSwitchPBMode(function () {
+      searchAndSwitchPBMode(function () {
+        hideTabView(finish);
+      });
+    });
+  });
+}
--- a/browser/base/content/test/tabview/browser_tabview_bug663421.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug663421.js
@@ -62,17 +62,17 @@ function test() {
     let target = tab._tabViewTabItem.container;
 
     waitForFocus(function () {
       EventUtils.synthesizeMouseAtCenter(target, {type: "mousedown"}, cw);
       EventUtils.synthesizeMouse(target, 600, 5, {type: "mousemove"}, cw);
       EventUtils.synthesizeMouse(target, 600, 5, {type: "mouseup"}, cw);
 
       checkNumberOfGroupItems(2);
-      next();
+      closeGroupItem(cw.GroupItems.groupItems[1], next);
     }, win);
   }
 
   let tests = [test1, test2, test3, test4];
 
   waitForExplicitFinish();
 
   newWindowWithTabView(function (aWin) {
--- a/browser/base/content/test/tabview/browser_tabview_dragdrop.js
+++ b/browser/base/content/test/tabview/browser_tabview_dragdrop.js
@@ -1,56 +1,39 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test() {
   waitForExplicitFinish();
-
-  window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
-  TabView.toggle();
+  showTabView(onTabViewShown);
 }
 
-function onTabViewWindowLoaded() {
-  window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
-
+function onTabViewShown() {
   ok(TabView.isVisible(), "Tab View is visible");
 
-  let contentWindow = document.getElementById("tab-view").contentWindow;
+  let contentWindow = TabView.getContentWindow();
   let [originalTab] = gBrowser.visibleTabs;
 
+  let createGroupItem = function (left, top, width, height) {
+    let box = new contentWindow.Rect(left, top, width, height);
+    let groupItem = new contentWindow.GroupItem([], {bounds: box, immediately: true});
+
+    contentWindow.UI.setActive(groupItem);
+    gBrowser.loadOneTab("about:blank", {inBackground: true});
+
+    return groupItem;
+  };
+
   // create group one and two
-  let boxOne = new contentWindow.Rect(20, 20, 300, 300);
-  let groupOne = new contentWindow.GroupItem([], { bounds: boxOne });
-  ok(groupOne.isEmpty(), "This group is empty");
-
-  let boxTwo = new contentWindow.Rect(20, 400, 300, 300);
-  let groupTwo = new contentWindow.GroupItem([], { bounds: boxTwo });
-
-  groupOne.addSubscriber("childAdded", function onChildAdded() {
-    groupOne.removeSubscriber("childAdded", onChildAdded);
-    groupTwo.newTab();
-  });
+  let groupOne = createGroupItem(20, 20, 300, 300);
+  let groupTwo = createGroupItem(20, 400, 300, 300);
 
-  let count = 0;
-  let onTabViewShown = function() {
-    if (count == 2) {
-      window.removeEventListener("tabviewshown", onTabViewShown, false);
-      addTest(contentWindow, groupOne.id, groupTwo.id, originalTab);
-    }
-  };
-  let onTabViewHidden = function() {
-    TabView.toggle();
-    if (++count == 2)
-      window.removeEventListener("tabviewhidden", onTabViewHidden, false);
-  };
-  window.addEventListener("tabviewshown", onTabViewShown, false);
-  window.addEventListener("tabviewhidden", onTabViewHidden, false);
-
-  // open tab in group
-  groupOne.newTab();
+  waitForFocus(function () {
+    addTest(contentWindow, groupOne.id, groupTwo.id, originalTab);
+  });
 }
 
 function addTest(contentWindow, groupOneId, groupTwoId, originalTab) {
   let groupOne = contentWindow.GroupItems.groupItem(groupOneId);
   let groupTwo = contentWindow.GroupItems.groupItem(groupTwoId);
   let groupOneTabItemCount = groupOne.getChildren().length;
   let groupTwoTabItemCount = groupTwo.getChildren().length;
   is(groupOneTabItemCount, 1, "GroupItem one has one tab");
@@ -69,34 +52,23 @@ function addTest(contentWindow, groupOne
 
   function endGame() {
     groupTwo.removeSubscriber("childAdded", endGame);
 
     is(groupOne.getChildren().length, --groupOneTabItemCount,
        "The number of children in group one is decreased by 1");
     is(groupTwo.getChildren().length, ++groupTwoTabItemCount,
        "The number of children in group two is increased by 1");
-  
-    let onTabViewHidden = function() {
-      window.removeEventListener("tabviewhidden", onTabViewHidden, false);
-      groupTwo.closeAll();
-      // close undo group
-      let closeButton = groupTwo.$undoContainer.find(".close");
-      EventUtils.sendMouseEvent(
-        { type: "click" }, closeButton[0], contentWindow);
-    };
-    groupTwo.addSubscriber("close", function onClose() {
-      groupTwo.removeSubscriber("close", onClose);
-      finish(); 
+
+    closeGroupItem(groupOne, function () {
+      closeGroupItem(groupTwo, function () hideTabView(finish));
     });
-    window.addEventListener("tabviewhidden", onTabViewHidden, false);
-    gBrowser.selectedTab = originalTab;
   }
+
   groupTwo.addSubscriber("childAdded", endGame);
-  
   simulateDragDrop(tabItem.container, offsetX, offsetY, contentWindow);
 }
 
 function simulateDragDrop(element, offsetX, offsetY, contentWindow) {
   let rect = element.getBoundingClientRect();
   let startX = (rect.right - rect.left)/2;
   let startY = (rect.bottom - rect.top)/2;
   let incrementX = offsetX / 2;
--- a/browser/base/content/test/tabview/browser_tabview_launch.js
+++ b/browser/base/content/test/tabview/browser_tabview_launch.js
@@ -1,52 +1,54 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-let timerId;
 let newWin;
 
 // ----------
 function test() {
   waitForExplicitFinish();
 
-  // launch tab view for the first time
-  newWindowWithTabView(function() {}, function(win) {
+  let panelSelected = false;
+  registerCleanupFunction(function () ok(panelSelected, "panel is selected"));
+
+  let onLoad = function (win) {
+    registerCleanupFunction(function () win.close());
+
     newWin = win;
 
     let onSelect = function(event) {
       if (deck != event.target)
         return;
 
       let iframe = win.document.getElementById("tab-view");
       if (deck.selectedPanel != iframe)
         return;
 
       deck.removeEventListener("select", onSelect, true);
-
-      whenTabViewIsShown(function() {
-        executeSoon(function() {
-          testMethodToHideAndShowTabView(function() {
-            newWin.document.getElementById("menu_tabview").doCommand();
-          }, function() {
-            testMethodToHideAndShowTabView(function() {
-              EventUtils.synthesizeKey("e", { accelKey: true, shiftKey: true }, newWin);
-            }, finish);
-          });
-        });
-      }, win);
+      panelSelected = true;
     };
 
     let deck = win.document.getElementById("tab-view-deck");
     deck.addEventListener("select", onSelect, true);
-  });
+  };
 
-  registerCleanupFunction(function () {
-    newWin.close();
-  });
+  let onShow = function (win) {
+    executeSoon(function() {
+      testMethodToHideAndShowTabView(function() {
+        newWin.document.getElementById("menu_tabview").doCommand();
+      }, function() {
+        testMethodToHideAndShowTabView(function() {
+          EventUtils.synthesizeKey("E", { accelKey: true, shiftKey: true }, newWin);
+        }, finish);
+      });
+    });
+  };
+
+  newWindowWithTabView(onShow, onLoad);
 }
 
 function testMethodToHideAndShowTabView(executeFunc, callback) {
   whenTabViewIsHidden(function() {
     ok(!newWin.TabView.isVisible(), "Tab View is not visible after executing the function");
     whenTabViewIsShown(function() {
       ok(newWin.TabView.isVisible(), "Tab View is visible after executing the function again");
       callback();
--- a/browser/base/content/test/tabview/browser_tabview_privatebrowsing.js
+++ b/browser/base/content/test/tabview/browser_tabview_privatebrowsing.js
@@ -44,21 +44,25 @@ function onTabViewLoadedAndShown() {
 
   // collect the group titles
   let count = contentWindow.GroupItems.groupItems.length;
   for (let a = 0; a < count; a++) {
     let gi = contentWindow.GroupItems.groupItems[a];
     groupTitles[a] = gi.getTitle();
   }
 
+  contentWindow.gPrefBranch.setBoolPref("animate_zoom", false);
+
   // Create a second tab
   gBrowser.addTab("about:robots");
   is(gBrowser.tabs.length, 2, "we now have 2 tabs");
+
   registerCleanupFunction(function() {
     gBrowser.removeTab(gBrowser.tabs[1]);
+    contentWindow.gPrefBranch.clearUserPref("animate_zoom");
   });
 
   afterAllTabsLoaded(function() {
     // Get normal tab urls
     for (let a = 0; a < gBrowser.tabs.length; a++)
       normalURLs.push(gBrowser.tabs[a].linkedBrowser.currentURI.spec);
 
     // verify that we're all set up for our test
--- a/browser/base/content/test/tabview/head.js
+++ b/browser/base/content/test/tabview/head.js
@@ -356,16 +356,19 @@ function restoreTab(callback, index, win
 }
 
 // ----------
 function togglePrivateBrowsing(callback) {
   let topic = "private-browsing-transition-complete";
 
   Services.obs.addObserver(function observe() {
     Services.obs.removeObserver(observe, topic);
-    afterAllTabsLoaded(callback);
+
+    // use executeSoon() to let Panorama load its group data from the session
+    // before we call afterAllTabsLoaded()
+    executeSoon(function () afterAllTabsLoaded(callback));
   }, topic, false);
 
   let pb = Cc["@mozilla.org/privatebrowsing;1"].
            getService(Ci.nsIPrivateBrowsingService);
 
   pb.privateBrowsingEnabled = !pb.privateBrowsingEnabled;
 }
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -48,16 +48,17 @@ browser.jar:
 *       content/browser/sanitize.xul                  (content/sanitize.xul)
 *       content/browser/sanitizeDialog.js             (content/sanitizeDialog.js)
         content/browser/sanitizeDialog.css            (content/sanitizeDialog.css)
 *       content/browser/tabbrowser.css                (content/tabbrowser.css)
 *       content/browser/tabbrowser.xml                (content/tabbrowser.xml)
         content/browser/tabview.css                   (content/tabview/tabview.css)
 *       content/browser/tabview.js                    (content/tabview/tabview.js)
         content/browser/tabview.html                  (content/tabview/tabview.html)
+        content/browser/tabview-content.js            (content/tabview/content.js)
 *       content/browser/urlbarBindings.xml            (content/urlbarBindings.xml)
 *       content/browser/utilityOverlay.js             (content/utilityOverlay.js)
 *       content/browser/web-panels.js                 (content/web-panels.js)
 *       content/browser/web-panels.xul                (content/web-panels.xul)
 *       content/browser/baseMenuOverlay.xul           (content/baseMenuOverlay.xul)
 *       content/browser/nsContextMenu.js              (content/nsContextMenu.js)
 #ifdef MOZ_SERVICES_SYNC
 *       content/browser/aboutSyncTabs.xul             (content/aboutSyncTabs.xul)
--- a/browser/components/feeds/src/FeedWriter.js
+++ b/browser/components/feeds/src/FeedWriter.js
@@ -251,17 +251,18 @@ FeedWriter.prototype = {
 
   /**
    * Use this sandbox to run any dom manipulation code on nodes which
    * are already inserted into the content document.
    */
   __contentSandbox: null,
   get _contentSandbox() {
     if (!this.__contentSandbox)
-      this.__contentSandbox = new Cu.Sandbox(this._window);
+      this.__contentSandbox = new Cu.Sandbox(this._window, 
+                                             {sandboxName: 'FeedWriter'});
 
     return this.__contentSandbox;
   },
 
   /**
    * Calls doCommand for a given XUL element within the context of the
    * content document.
    *
--- a/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
+++ b/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
@@ -614,21 +614,19 @@ PrivateBrowsingService.prototype = {
       let enumerator = cm.getCookiesFromHost(aDomain);
       while (enumerator.hasMoreElements()) {
         let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie);
         cm.remove(cookie.host, cookie.name, cookie.path, false);
       }
     }
 
     // Plugin data
-    let (ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost)) {
-      const phInterface = Ci.nsIPluginHost;
-      const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL;
-      ph.QueryInterface(phInterface);
-
+    const phInterface = Ci.nsIPluginHost;
+    const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL;
+    let (ph = Cc["@mozilla.org/plugin/host;1"].getService(phInterface)) {
       let tags = ph.getPluginTags();
       for (let i = 0; i < tags.length; i++) {
         try {
           ph.clearSiteData(tags[i], aDomain, FLAG_CLEAR_ALL, -1);
         } catch (e) {
           // Ignore errors from the plugin
         }
       }
--- a/browser/components/sessionstore/content/aboutSessionRestore.js
+++ b/browser/components/sessionstore/content/aboutSessionRestore.js
@@ -54,17 +54,17 @@ window.onload = function() {
 
   // remove unneeded braces (added for compatibility with Firefox 2.0 and 3.0)
   if (sessionData.value.charAt(0) == '(')
     sessionData.value = sessionData.value.slice(1, -1);
   try {
     gStateObject = JSON.parse(sessionData.value);
   }
   catch (exJSON) {
-    var s = new Cu.Sandbox("about:blank");
+    var s = new Cu.Sandbox("about:blank", {sandboxName: 'aboutSessionRestore'});
     gStateObject = Cu.evalInSandbox("(" + sessionData.value + ")", s);
     // If we couldn't parse the string with JSON.parse originally, make sure
     // that the value in the textbox will be parsable.
     sessionData.value = JSON.stringify(gStateObject);
   }
 
   // make sure the data is tracked to be restored in case of a subsequent crash
   var event = document.createEvent("UIEvents");
--- a/browser/components/sessionstore/src/nsSessionStartup.js
+++ b/browser/components/sessionstore/src/nsSessionStartup.js
@@ -130,17 +130,17 @@ SessionStartup.prototype = {
     try {
       // remove unneeded braces (added for compatibility with Firefox 2.0 and 3.0)
       if (iniString.charAt(0) == '(')
         iniString = iniString.slice(1, -1);
       try {
         this._initialState = JSON.parse(iniString);
       }
       catch (exJSON) {
-        var s = new Cu.Sandbox("about:blank");
+        var s = new Cu.Sandbox("about:blank", {sandboxName: 'nsSessionStartup'});
         this._initialState = Cu.evalInSandbox("(" + iniString + ")", s);
       }
 
       // If this is a normal restore then throw away any previous session
       if (!doResumeSessionOnce)
         delete this._initialState.lastSessionState;
     }
     catch (ex) { debug("The session file is invalid: " + ex); }
--- a/browser/components/sessionstore/src/nsSessionStore.js
+++ b/browser/components/sessionstore/src/nsSessionStore.js
@@ -780,17 +780,17 @@ SessionStoreService.prototype = {
     if (aWindow.document.documentElement.getAttribute("windowtype") != "navigator:browser" ||
         this._loadState == STATE_QUITTING)
       return;
 
     // assign it a unique identifier (timestamp)
     aWindow.__SSi = "window" + Date.now();
 
     // and create its data object
-    this._windows[aWindow.__SSi] = { tabs: [], selected: 0, _closedTabs: [] };
+    this._windows[aWindow.__SSi] = { tabs: [], selected: 0, _closedTabs: [], busy: false };
     if (!this._isWindowLoaded(aWindow))
       this._windows[aWindow.__SSi]._restoring = true;
     if (!aWindow.toolbar.visible)
       this._windows[aWindow.__SSi].isPopup = true;
     
     // perform additional initialization when the first window is loading
     if (this._loadState == STATE_STOPPED) {
       this._loadState = STATE_RUNNING;
@@ -964,16 +964,19 @@ SessionStoreService.prototype = {
       // Until we decide otherwise elsewhere, this window is part of a series
       // of closing windows to quit.
       winData._shouldRestore = true;
 #endif
 
       // save the window if it has multiple tabs or a single saveable tab
       if (winData.tabs.length > 1 ||
           (winData.tabs.length == 1 && this._shouldSaveTabState(winData.tabs[0]))) {
+        // we don't want to save the busy state
+        delete winData.busy;
+
         this._closedWindows.unshift(winData);
         this._capClosedWindows();
       }
       
       // clear this window from the list
       delete this._windows[aWindow.__SSi];
       
       // save the state without this window to disk
@@ -1260,33 +1263,33 @@ SessionStoreService.prototype = {
   },
 
   setTabState: function sss_setTabState(aTab, aState) {
     var tabState = JSON.parse(aState);
     if (!tabState.entries || !aTab.ownerDocument || !aTab.ownerDocument.defaultView.__SSi)
       throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
     
     var window = aTab.ownerDocument.defaultView;
-    this._sendWindowStateEvent(window, "Busy");
+    this._setWindowStateBusy(window);
     this.restoreHistoryPrecursor(window, [aTab], [tabState], 0, 0, 0);
   },
 
   duplicateTab: function sss_duplicateTab(aWindow, aTab, aDelta) {
     if (!aTab.ownerDocument || !aTab.ownerDocument.defaultView.__SSi ||
         !aWindow.getBrowser)
       throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
 
     var tabState = this._collectTabData(aTab, true);
     var sourceWindow = aTab.ownerDocument.defaultView;
     this._updateTextAndScrollDataForTab(sourceWindow, aTab.linkedBrowser, tabState, true);
     tabState.index += aDelta;
     tabState.index = Math.max(1, Math.min(tabState.index, tabState.entries.length));
     tabState.pinned = false;
 
-    this._sendWindowStateEvent(aWindow, "Busy");
+    this._setWindowStateBusy(aWindow);
     let newTab = aTab == aWindow.gBrowser.selectedTab ?
       aWindow.gBrowser.addTab(null, {relatedToCurrent: true, ownerTab: aTab}) :
       aWindow.gBrowser.addTab();
     this.restoreHistoryPrecursor(aWindow, [newTab], [tabState], 0, 0, 0);
 
     return newTab;
   },
 
@@ -1319,17 +1322,17 @@ SessionStoreService.prototype = {
     aIndex = aIndex || 0;
     if (!(aIndex in closedTabs))
       throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
     
     // fetch the data of closed tab, while removing it from the array
     let closedTab = closedTabs.splice(aIndex, 1).shift();
     let closedTabState = closedTab.state;
 
-    this._sendWindowStateEvent(aWindow, "Busy");
+    this._setWindowStateBusy(aWindow);
     // create a new tab
     let browser = aWindow.gBrowser;
     let tab = browser.addTab();
 
     // restore tab content
     this.restoreHistoryPrecursor(aWindow, [tab], [closedTabState], 1, 0, 0);
       
     // restore the tab's position
@@ -2529,17 +2532,17 @@ SessionStoreService.prototype = {
     catch (ex) { // invalid state object - don't restore anything 
       debug(ex);
       this._sendRestoreCompletedNotifications();
       return;
     }
 
     // We're not returning from this before we end up calling restoreHistoryPrecursor
     // for this window, so make sure we send the SSWindowStateBusy event.
-    this._sendWindowStateEvent(aWindow, "Busy");
+    this._setWindowStateBusy(aWindow);
 
     if (root._closedWindows)
       this._closedWindows = root._closedWindows;
 
     var winData;
     if (!aState.selectedWindow) {
       aState.selectedWindow = 0;
     }
@@ -2716,17 +2719,17 @@ SessionStoreService.prototype = {
       delete this._statesToRestore[aWindow.__SS_restoreID];
       delete aWindow.__SS_restoreID;
       delete this._windows[aWindow.__SSi]._restoring;
     }
 
     if (aTabs.length == 0) {
       // this is normally done in restoreHistory() but as we're returning early
       // here we need to take care of it.
-      this._sendWindowStateEvent(aWindow, "Ready");
+      this._setWindowStateReady(aWindow);
       return;
     }
 
     let unhiddenTabs = aTabData.filter(function (aData) !aData.hidden).length;
 
     // if all tabs to be restored are hidden, make the first one visible
     if (unhiddenTabs == 0) {
       aTabData[0].hidden = false;
@@ -2861,17 +2864,17 @@ SessionStoreService.prototype = {
     var _this = this;
     while (aTabs.length > 0 && (!aTabData[0]._tabStillLoading || !aTabs[0].parentNode)) {
       aTabs.shift(); // this tab got removed before being completely restored
       aTabData.shift();
     }
     if (aTabs.length == 0) {
       // At this point we're essentially ready for consumers to read/write data
       // via the sessionstore API so we'll send the SSWindowStateReady event.
-      this._sendWindowStateEvent(aWindow, "Ready");
+      this._setWindowStateReady(aWindow);
       return; // no more tabs to restore
     }
     
     var tab = aTabs.shift();
     var tabData = aTabData.shift();
 
     var browser = aWindow.gBrowser.getBrowserForTab(tab);
     var history = browser.webNavigation.sessionHistory;
@@ -4006,16 +4009,52 @@ SessionStoreService.prototype = {
     Services.obs.notifyObservers(null,
       this._browserSetState ? NOTIFY_BROWSER_STATE_RESTORED : NOTIFY_WINDOWS_RESTORED,
       "");
 
     this._browserSetState = false;
     this._restoreCount = -1;
   },
 
+   /**
+   * Set the given window's busy state
+   * @param aWindow the window
+   * @param aValue the window's busy state
+   */
+  _setWindowStateBusyValue:
+    function sss__changeWindowStateBusyValue(aWindow, aValue) {
+
+    this._windows[aWindow.__SSi].busy = aValue;
+
+    // Keep the to-be-restored state in sync because that is returned by
+    // getWindowState() as long as the window isn't loaded, yet.
+    if (!this._isWindowLoaded(aWindow)) {
+      let stateToRestore = this._statesToRestore[aWindow.__SS_restoreID].windows[0];
+      stateToRestore.busy = aValue;
+    }
+  },
+
+  /**
+   * Set the given window's state to 'not busy'.
+   * @param aWindow the window
+   */
+  _setWindowStateReady: function sss__setWindowStateReady(aWindow) {
+    this._setWindowStateBusyValue(aWindow, false);
+    this._sendWindowStateEvent(aWindow, "Ready");
+  },
+
+  /**
+   * Set the given window's state to 'busy'.
+   * @param aWindow the window
+   */
+  _setWindowStateBusy: function sss__setWindowStateBusy(aWindow) {
+    this._setWindowStateBusyValue(aWindow, true);
+    this._sendWindowStateEvent(aWindow, "Busy");
+  },
+
   /**
    * Dispatch an SSWindowState_____ event for the given window.
    * @param aWindow the window
    * @param aType the type of event, SSWindowState will be prepended to this string
    */
   _sendWindowStateEvent: function sss__sendWindowStateEvent(aWindow, aType) {
     let event = aWindow.document.createEvent("Events");
     event.initEvent("SSWindowState" + aType, true, false);
--- a/browser/components/sessionstore/test/browser/Makefile.in
+++ b/browser/components/sessionstore/test/browser/Makefile.in
@@ -146,16 +146,17 @@ include $(topsrcdir)/config/rules.mk
 	browser_623779.js \
 	browser_624727.js \
 	browser_625257.js \
 	browser_628270.js \
 	browser_635418.js \
 	browser_636279.js \
 	browser_645428.js \
 	browser_659591.js \
+	browser_662812.js \
 	$(NULL)
 
 ifneq ($(OS_ARCH),Darwin)
 _BROWSER_TEST_FILES += \
 	browser_597071.js \
 	browser_625016.js \
 	$(NULL)
 endif
--- a/browser/components/sessionstore/test/browser/browser_595601-restore_hidden.js
+++ b/browser/components/sessionstore/test/browser/browser_595601-restore_hidden.js
@@ -1,113 +1,117 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const TAB_STATE_NEEDS_RESTORE = 1;
 const TAB_STATE_RESTORING = 2;
 
-let stateBackup = ss.getBrowserState();
-
 let state = {windows:[{tabs:[
   {entries:[{url:"http://example.com#1"}]},
   {entries:[{url:"http://example.com#2"}]},
   {entries:[{url:"http://example.com#3"}]},
   {entries:[{url:"http://example.com#4"}]},
   {entries:[{url:"http://example.com#5"}], hidden: true},
   {entries:[{url:"http://example.com#6"}], hidden: true},
   {entries:[{url:"http://example.com#7"}], hidden: true},
   {entries:[{url:"http://example.com#8"}], hidden: true}
 ]}]};
 
 function test() {
   waitForExplicitFinish();
 
   registerCleanupFunction(function () {
     Services.prefs.clearUserPref("browser.sessionstore.restore_hidden_tabs");
-
-    TabsProgressListener.uninit();
-
-    ss.setBrowserState(stateBackup);
   });
 
-  TabsProgressListener.init();
-
   // First stage: restoreHiddenTabs = true
   // Second stage: restoreHiddenTabs = false
   test_loadTabs(true, function () {
-    test_loadTabs(false, function () {
-      waitForFocus(finish);
-    });
+    test_loadTabs(false, finish);
   });
 }
 
 function test_loadTabs(restoreHiddenTabs, callback) {
   Services.prefs.setBoolPref("browser.sessionstore.restore_hidden_tabs", restoreHiddenTabs);
 
   let expectedTabs = restoreHiddenTabs ? 8 : 4;
-
   let firstProgress = true;
 
-  TabsProgressListener.setCallback(function (needsRestore, isRestoring) {
+  newWindowWithState(state, function (win, needsRestore, isRestoring) {
     if (firstProgress) {
       firstProgress = false;
       is(isRestoring, 3, "restoring 3 tabs concurrently");
     } else {
       ok(isRestoring < 4, "restoring max. 3 tabs concurrently");
     }
 
-    if (gBrowser.tabs.length - needsRestore == expectedTabs) {
-      TabsProgressListener.unsetCallback();
-      is(gBrowser.visibleTabs.length, 4, "only 4 visible tabs");
+    if (win.gBrowser.tabs.length - needsRestore == expectedTabs) {
+      is(win.gBrowser.visibleTabs.length, 4, "only 4 visible tabs");
+
+      TabsProgressListener.uninit();
       callback();
     }
   });
-
-  ss.setBrowserState(JSON.stringify(state));
-}
-
-function countTabs() {
-  let needsRestore = 0, isRestoring = 0;
-  let windowsEnum = Services.wm.getEnumerator("navigator:browser");
-
-  while (windowsEnum.hasMoreElements()) {
-    let window = windowsEnum.getNext();
-    if (window.closed)
-      continue;
-
-    for (let i = 0; i < window.gBrowser.tabs.length; i++) {
-      let browser = window.gBrowser.tabs[i].linkedBrowser;
-      if (browser.__SS_restoreState == TAB_STATE_RESTORING)
-        isRestoring++;
-      else if (browser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE)
-        needsRestore++;
-    }
-  }
-
-  return [needsRestore, isRestoring];
 }
 
 let TabsProgressListener = {
-  init: function () {
-    gBrowser.addTabsProgressListener(this);
+  init: function (win) {
+    this.window = win;
+
+    this.window.gBrowser.addTabsProgressListener(this);
   },
 
   uninit: function () {
-    this.unsetCallback();
-    gBrowser.removeTabsProgressListener(this);
+    this.window.gBrowser.removeTabsProgressListener(this);
+
+    delete this.window;
+    delete this.callback;
   },
 
   setCallback: function (callback) {
     this.callback = callback;
   },
 
-  unsetCallback: function () {
-    delete this.callback;
-  },
-
   onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
     if (this.callback && aBrowser.__SS_restoreState == TAB_STATE_RESTORING &&
         aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
         aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
         aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW)
-      this.callback.apply(null, countTabs());
+      this.callback.apply(null, [this.window].concat(this.countTabs()));
+  },
+
+  countTabs: function () {
+    let needsRestore = 0, isRestoring = 0;
+
+    for (let i = 0; i < this.window.gBrowser.tabs.length; i++) {
+      let browser = this.window.gBrowser.tabs[i].linkedBrowser;
+      if (browser.__SS_restoreState == TAB_STATE_RESTORING)
+        isRestoring++;
+      else if (browser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE)
+        needsRestore++;
+    }
+
+    return [needsRestore, isRestoring];
   }
 }
+
+// ----------
+function whenWindowLoaded(win, callback) {
+  win.addEventListener("load", function onLoad() {
+    win.removeEventListener("load", onLoad, false);
+    executeSoon(callback);
+  }, false);
+}
+
+// ----------
+function newWindowWithState(state, callback) {
+  let opts = "chrome,all,dialog=no,height=800,width=800";
+  let win = window.openDialog(getBrowserURL(), "_blank", opts);
+
+  registerCleanupFunction(function () win.close());
+
+  whenWindowLoaded(win, function () {
+    TabsProgressListener.init(win);
+    TabsProgressListener.setCallback(callback);
+
+    ss.setWindowState(win, JSON.stringify(state), true);
+  });
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/browser/browser_662812.js
@@ -0,0 +1,34 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+  waitForExplicitFinish();
+
+  window.addEventListener("SSWindowStateBusy", function onBusy() {
+    window.removeEventListener("SSWindowStateBusy", onBusy, false);
+
+    let state = JSON.parse(ss.getWindowState(window));
+    ok(state.windows[0].busy, "window is busy");
+
+    window.addEventListener("SSWindowStateReady", function onReady() {
+      window.removeEventListener("SSWindowStateReady", onReady, false);
+
+      let state = JSON.parse(ss.getWindowState(window));
+      ok(!state.windows[0].busy, "window is not busy");
+
+      gBrowser.removeTab(gBrowser.tabs[1]);
+      executeSoon(finish);
+    }, false);
+  }, false);
+
+  // create a new tab
+  let tab = gBrowser.addTab("about:mozilla");
+  let browser = tab.linkedBrowser;
+
+  // close and restore it
+  browser.addEventListener("load", function onLoad() {
+    browser.removeEventListener("load", onLoad, true);
+    gBrowser.removeTab(tab);
+    ss.undoCloseTab(window, 0);
+  }, true);
+}
--- a/browser/devtools/scratchpad/scratchpad.js
+++ b/browser/devtools/scratchpad/scratchpad.js
@@ -173,17 +173,18 @@ var Scratchpad = {
     }
 
     if (!this._contentSandbox ||
         this.browserWindow != this._previousBrowserWindow ||
         this._previousBrowser != this.gBrowser.selectedBrowser ||
         this._previousLocation != this.gBrowser.contentWindow.location.href) {
       let contentWindow = this.gBrowser.selectedBrowser.contentWindow;
       this._contentSandbox = new Cu.Sandbox(contentWindow,
-        { sandboxPrototype: contentWindow, wantXrays: false });
+        { sandboxPrototype: contentWindow, wantXrays: false, 
+          sandboxName: 'scratchpad-content'});
 
       this._previousBrowserWindow = this.browserWindow;
       this._previousBrowser = this.gBrowser.selectedBrowser;
       this._previousLocation = contentWindow.location.href;
     }
 
     return this._contentSandbox;
   },
@@ -206,17 +207,18 @@ var Scratchpad = {
       Cu.reportError(this.strings.
                      GetStringFromName("browserWindow.unavailable"));
       return;
     }
 
     if (!this._chromeSandbox ||
         this.browserWindow != this._previousBrowserWindow) {
       this._chromeSandbox = new Cu.Sandbox(this.browserWindow,
-        { sandboxPrototype: this.browserWindow, wantXrays: false });
+        { sandboxPrototype: this.browserWindow, wantXrays: false, 
+          sandboxName: 'scratchpad-chrome'});
 
       this._previousBrowserWindow = this.browserWindow;
     }
 
     return this._chromeSandbox;
   },
 
   /**
--- a/browser/themes/gnomestripe/browser/browser.css
+++ b/browser/themes/gnomestripe/browser/browser.css
@@ -598,28 +598,47 @@ toolbar[mode="full"] .toolbarbutton-1 > 
   list-style-image: url("moz-icon://stock/gtk-go-back-rtl?size=toolbar");
 }
 #back-button[disabled="true"]:-moz-locale-dir(rtl) {
   list-style-image: url("moz-icon://stock/gtk-go-back-rtl?size=toolbar&state=disabled");
 }
 
 #forward-button {
   list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=toolbar");
+  -moz-transition: 250ms ease-out;
 }
-#forward-button[disabled="true"] {
-  list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=toolbar&state=disabled");
-}
-
 #forward-button:-moz-locale-dir(rtl) {
   list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=toolbar");
 }
-#forward-button[disabled="true"]:-moz-locale-dir(rtl) {
+
+toolbar:not([mode=icons]) #forward-button[disabled="true"] {
+  list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=toolbar&state=disabled");
+}
+toolbar:not([mode=icons]) #forward-button[disabled="true"]:-moz-locale-dir(rtl) {
   list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=toolbar&state=disabled");
 }
 
+toolbar[mode=icons] #forward-button[disabled="true"] {
+  -moz-transform: scale(0);
+  opacity: 0;
+  pointer-events: none;
+}
+toolbar[mode=icons] #forward-button[disabled="true"]:-moz-locale-dir(ltr) {
+  margin-left: -36px;
+}
+toolbar[mode=icons] #forward-button[disabled="true"]:-moz-locale-dir(rtl) {
+  margin-right: -36px;
+}
+toolbar[mode=icons][iconsize=small] #forward-button[disabled="true"]:-moz-locale-dir(ltr) {
+  margin-left: -28px;
+}
+toolbar[mode=icons][iconsize=small] #forward-button[disabled="true"]:-moz-locale-dir(rtl) {
+  margin-right: -28px;
+}
+
 #reload-button {
   list-style-image: url("moz-icon://stock/gtk-refresh?size=toolbar");
 }
 #reload-button[disabled="true"] {
   list-style-image: url("moz-icon://stock/gtk-refresh?size=toolbar&state=disabled");
 }
 
 #stop-button {
@@ -781,27 +800,27 @@ toolbar[iconsize="small"] #back-button[d
 }
 
 toolbar[iconsize="small"] #forward-button {
   list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=menu");
 }
 .unified-nav-forward[_moz-menuactive] {
   list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=menu") !important;
 }
-toolbar[iconsize="small"] #forward-button[disabled="true"] {
+toolbar[iconsize="small"]:not([mode=icons]) #forward-button[disabled="true"] {
   list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=menu&state=disabled");
 }
 
 toolbar[iconsize="small"] #forward-button:-moz-locale-dir(rtl) {
   list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=menu");
 }
 .unified-nav-forward[_moz-menuactive]:-moz-locale-dir(rtl) {
   list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=menu") !important;
 }
-toolbar[iconsize="small"] #forward-button[disabled="true"]:-moz-locale-dir(rtl) {
+toolbar[iconsize="small"]:not([mode=icons]) #forward-button[disabled="true"]:-moz-locale-dir(rtl) {
   list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=menu&state=disabled");
 }
 
 toolbar[iconsize="small"] #stop-button {
   list-style-image: url("moz-icon://stock/gtk-stop?size=menu");
 }
 toolbar[iconsize="small"] #stop-button[disabled="true"] {
   list-style-image: url("moz-icon://stock/gtk-stop?size=menu&state=disabled");
--- a/build/mobile/devicemanagerADB.py
+++ b/build/mobile/devicemanagerADB.py
@@ -1,38 +1,47 @@
 import subprocess
 from devicemanager import DeviceManager, DMError
 import re
 import os
 
 class DeviceManagerADB(DeviceManager):
 
-  def __init__(self, host = None, port = 20701, retrylimit = 5, packageName = "org.mozilla.fennec_unofficial"):
+  def __init__(self, host = None, port = 20701, retrylimit = 5, packageName = None):
     self.host = host
     self.port = port
     self.retrylimit = retrylimit
     self.retries = 0
     self._sock = None
+    if packageName == None:
+      if os.getenv('USER'):
+        packageName = 'org.mozilla.fennec_' + os.getenv('USER')
+      else:
+        packageName = 'org.mozilla.fennec_'
     self.Init(packageName)
 
   def Init(self, packageName):
     # Initialization code that may fail: Catch exceptions here to allow
     # successful initialization even if, for example, adb is not installed.
     try:
       root = self.getDeviceRoot()
       self.verifyPackage(packageName)
       self.tmpDir = root + "/tmp"
       if (not self.dirExists(self.tmpDir)):
         self.mkDir(self.tmpDir)
     except:
       self.packageName = None
       self.tmpDir = None
     try:
       # a test to see if we have root privs
-      self.checkCmd(["shell", "ls", "/sbin"])
+      files = self.listFiles("/data/data")
+      if (len(files) == 1):
+        if (files[0].find("Permission denied") != -1):
+          print "NOT running as root"
+          raise Exception("not running as root")
     except:
       try:
         self.checkCmd(["root"])
       except:
         print "restarting as root failed"
 
   # external function
   # returns:
@@ -93,17 +102,17 @@ class DeviceManagerADB(DeviceManager):
   #  failure: None
   def pushDir(self, localDir, remoteDir):
     # adb "push" accepts a directory as an argument, but if the directory
     # contains symbolic links, the links are pushed, rather than the linked
     # files; we push file-by-file to get around this limitation
     try:
       if (not self.dirExists(remoteDir)):
         self.mkDirs(remoteDir+"/x")
-      for root, dirs, files in os.walk(localDir):
+      for root, dirs, files in os.walk(localDir, followlinks='true'):
         relRoot = os.path.relpath(root, localDir)
         for file in files:
           localFile = os.path.join(root, file)
           remoteFile = remoteDir + "/"
           if (relRoot!="."):
             remoteFile = remoteFile + relRoot + "/"
           remoteFile = remoteFile + file
           self.pushFile(localFile, remoteFile)
@@ -129,18 +138,22 @@ class DeviceManagerADB(DeviceManager):
 
   # Because we always have / style paths we make this a lot easier with some
   # assumptions
   # external function
   # returns:
   #  success: True
   #  failure: False
   def fileExists(self, filepath):
-    self.checkCmd(["shell", "ls", filepath])
-    return True
+    p = self.runCmd(["shell", "ls", "-a", filepath])
+    data = p.stdout.readlines()
+    if (len(data) == 1):
+      if (data[0].rstrip() == filepath):
+        return True
+    return False
 
   def removeFile(self, filename):
     return self.runCmd(["shell", "rm", filename]).stdout.read()
 
   # does a recursive delete of directory on the device: rm -Rf remoteDir
   # external function
   # returns:
   #  success: output of telnet, i.e. "removing file: /mnt/sdcard/tests/test.txt"
@@ -376,28 +389,21 @@ class DeviceManagerADB(DeviceManager):
     devroot = self.getDeviceRoot()
     if (devroot == None):
       return None
 
     if (self.dirExists(devroot + '/fennec')):
       return devroot + '/fennec'
     elif (self.dirExists(devroot + '/firefox')):
       return devroot + '/firefox'
-    elif (self.dirExists('/data/data/org.mozilla.fennec')):
-      return '/data/data/org.mozilla.fennec'
-    elif (self.dirExists('/data/data/org.mozilla.firefox')):
-      return '/data/data/org.mozilla.firefox'
-    elif (self.dirExists('/data/data/org.mozilla.fennec_unofficial')):
-      return '/data/data/org.mozilla.fennec_unofficial'
-    elif (self.dirExists('/data/data/org.mozilla.fennec_aurora')):
-      return '/data/data/org.mozilla.fennec_aurora'
-    elif (self.dirExists('/data/data/org.mozilla.firefox_beta')):
-      return '/data/data/org.mozilla.firefox_beta'
+    elif (self.packageName and self.dirExists('/data/data/' + self.packageName)):
+      return '/data/data/' + self.packageName
 
     # Failure (either not installed or not a recognized platform)
+    print "devicemanagerADB: getAppRoot failed"
     return None
 
   # Gets the directory location on the device for a specific test type
   # Type is one of: xpcshell|reftest|mochitest
   # external function
   # returns:
   #  success: path for test root
   #  failure: None
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -38,17 +38,16 @@
 
 # A netscape style .mk file for autoconf builds
 
 INCLUDED_AUTOCONF_MK = 1
 USE_AUTOCONF 	= 1
 MOZILLA_CLIENT	= 1
 target          = @target@
 ac_configure_args = @ac_configure_args@
-BUILD_MODULES	= @BUILD_MODULES@
 MOZILLA_VERSION = @MOZILLA_VERSION@
 FIREFOX_VERSION	= @FIREFOX_VERSION@
 
 MOZ_BUILD_APP = @MOZ_BUILD_APP@
 MOZ_APP_NAME	= @MOZ_APP_NAME@
 MOZ_APP_DISPLAYNAME = @MOZ_APP_DISPLAYNAME@
 MOZ_APP_BASENAME = @MOZ_APP_BASENAME@
 MOZ_APP_VENDOR = @MOZ_APP_VENDOR@
--- a/config/nsinstall_win.c
+++ b/config/nsinstall_win.c
@@ -36,16 +36,48 @@ static const char *sh_GetLastErrorMessag
 static BOOL sh_DoCopy(wchar_t *srcFileName, DWORD srcFileAttributes,
         wchar_t *dstFileName, DWORD dstFileAttributes,
         int force, int recursive);
 
 #define LONGPATH_PREFIX L"\\\\?\\"
 #define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
 #define STR_LEN(a) (ARRAY_LEN(a) - 1)
 
+#ifdef __MINGW32__
+
+/* MingW currently does not implement a wide version of the
+   startup routines.  Workaround is to implement something like
+   it ourselves. */
+
+#include <shellapi.h>
+
+int wmain(int argc, WCHAR **argv);
+
+int main(int argc, char **argv)
+{
+    int result;
+    wchar_t *commandLine = GetCommandLineW();
+    int argcw = 0;
+    wchar_t **_argvw = CommandLineToArgvW( commandLine, &argcw );
+    wchar_t *argvw[argcw + 1];
+    int i;
+    if (!_argvw)
+        return 127;
+    /* CommandLineToArgvW doesn't output the ending NULL so
+       we have to manually add it on */
+    for ( i = 0; i < argcw; i++ )
+        argvw[i] = _argvw[i];
+    argvw[argcw] = NULL;
+
+    result = wmain(argcw, argvw);
+    LocalFree(_argvw);
+    return result;
+}
+#endif /* __MINGW32__ */
+
 /* changes all forward slashes in token to backslashes */
 void changeForwardSlashesToBackSlashes ( wchar_t *arg )
 {
     if ( arg == NULL )
         return;
 
     while ( *arg ) {
         if ( *arg == '/' )
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -148,16 +148,30 @@ xpcshell-tests:
 	  -I$(topsrcdir)/build \
 	  $(testxpcsrcdir)/runxpcshelltests.py \
 	  --symbols-path=$(DIST)/crashreporter-symbols \
 	  --build-info-json=$(DEPTH)/mozinfo.json \
 	  $(EXTRA_TEST_ARGS) \
 	  $(LIBXUL_DIST)/bin/xpcshell \
 	  $(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
 
+xpcshell-tests-remote: DM_TRANS?=adb
+xpcshell-tests-remote:
+	$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
+	  -I$(topsrcdir)/build \
+	  -I$(topsrcdir)/build/mobile \
+	  $(topsrcdir)/testing/xpcshell/remotexpcshelltests.py \
+	  --symbols-path=$(DIST)/crashreporter-symbols \
+	  --build-info-json=$(DEPTH)/mozinfo.json \
+	  $(EXTRA_TEST_ARGS) \
+	  --dm_trans=$(DM_TRANS) \
+	  --deviceIP=${TEST_DEVICE} \
+	  --objdir=$(DEPTH) \
+	  $(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
+
 # Execute a single test, specified in $(SOLO_FILE), but don't automatically
 # start the test. Instead, present the xpcshell prompt so the user can
 # attach a debugger and then start the test.
 check-interactive:
 	$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
 	  -I$(topsrcdir)/build \
 	  $(testxpcsrcdir)/runxpcshelltests.py \
 	  --symbols-path=$(DIST)/crashreporter-symbols \
@@ -177,16 +191,33 @@ check-one:
 	  --build-info-json=$(DEPTH)/mozinfo.json \
 	  --test-path=$(SOLO_FILE) \
 	  --profile-name=$(MOZ_APP_NAME) \
 	  --verbose \
 	  $(EXTRA_TEST_ARGS) \
 	  $(LIBXUL_DIST)/bin/xpcshell \
 	  $(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
 
+check-one-remote: DM_TRANS?=adb
+check-one-remote:
+	$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
+	  -I$(topsrcdir)/build \
+	  -I$(topsrcdir)/build/mobile \
+	  $(testxpcsrcdir)/remotexpcshelltests.py \
+	  --symbols-path=$(DIST)/crashreporter-symbols \
+	  --build-info-json=$(DEPTH)/mozinfo.json \
+	  --test-path=$(SOLO_FILE) \
+	  --profile-name=$(MOZ_APP_NAME) \
+	  --verbose \
+	  $(EXTRA_TEST_ARGS) \
+	  --dm_trans=$(DM_TRANS) \
+	  --deviceIP=${TEST_DEVICE} \
+	  --objdir=$(DEPTH) \
+          --noSetup \
+	  $(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
 endif # XPCSHELL_TESTS
 
 ifdef CPP_UNIT_TESTS
 
 # Compile the tests to $(DIST)/bin.  Make lots of niceties available by default
 # through TestHarness.h, by modifying the list of includes and the libs against
 # which stuff links.
 CPPSRCS += $(CPP_UNIT_TESTS)
@@ -1117,18 +1148,19 @@ endif # OS/2
 	$(RM) $@
 	$(HOST_AR) $(HOST_AR_FLAGS) $(HOST_OBJS)
 	$(HOST_RANLIB) $@
 
 ifdef HAVE_DTRACE
 ifndef XP_MACOSX
 ifdef DTRACE_PROBE_OBJ
 ifndef DTRACE_LIB_DEPENDENT
-$(DTRACE_PROBE_OBJ):
-	dtrace -G -C -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ)
+NON_DTRACE_OBJS := $(filter-out $(DTRACE_PROBE_OBJ),$(OBJS))
+$(DTRACE_PROBE_OBJ): $(NON_DTRACE_OBJS)
+	dtrace -G -C -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ) $(NON_DTRACE_OBJS)
 endif
 endif
 endif
 endif
 
 # On Darwin (Mac OS X), dwarf2 debugging uses debug info left in .o files,
 # so instead of deleting .o files after repacking them into a dylib, we make
 # symlinks back to the originals. The symlinks are a no-op for stabs debugging,
@@ -1514,19 +1546,16 @@ ifeq ($(XPIDL_MODULE),) # we need $(XPID
 export:: FORCE
 	@echo
 	@echo "*** Error processing XPIDLSRCS:"
 	@echo "Please define MODULE or XPIDL_MODULE when defining XPIDLSRCS,"
 	@echo "so we have a module name to use when creating MODULE.xpt."
 	@echo; sleep 2; false
 endif
 
-$(IDL_DIR)::
-	$(NSINSTALL) -D $@
-
 # generate .h files from into $(XPIDL_GEN_DIR), then export to $(DIST)/include;
 # warn against overriding existing .h file. 
 $(XPIDL_GEN_DIR)/.done:
 	$(MKDIR) -p $(XPIDL_GEN_DIR)
 	@$(TOUCH) $@
 
 # don't depend on $(XPIDL_GEN_DIR), because the modification date changes
 # with any addition to the directory, regenerating all .h files -> everything.
@@ -1587,24 +1616,18 @@ export:: $(XPIDLSRCS) $(IDL_DIR)
 export:: $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.h, $(XPIDLSRCS)) $(DIST)/include
 	$(INSTALL) $(IFLAGS1) $^ 
 endif # NO_DIST_INSTALL
 
 endif # XPIDLSRCS
 
 
 
-#
 # General rules for exporting idl files.
-#
-# WORK-AROUND ONLY, for mozilla/tools/module-deps/bootstrap.pl build.
-# Bug to fix idl dependency problems w/o this extra build pass is
-#   http://bugzilla.mozilla.org/show_bug.cgi?id=145777
-#
-$(IDL_DIR)::
+$(IDL_DIR):
 	$(NSINSTALL) -D $@
 
 export-idl:: $(SUBMAKEFILES) $(MAKE_DIRS)
 
 ifneq ($(XPIDLSRCS),)
 ifndef NO_DIST_INSTALL
 export-idl:: $(XPIDLSRCS) $(IDL_DIR)
 	$(INSTALL) $(IFLAGS1) $^
@@ -2061,17 +2084,16 @@ showhost:
 	@echo "HOST_EXTRA_LIBS    = $(HOST_EXTRA_LIBS)"
 	@echo "HOST_EXTRA_DEPS    = $(HOST_EXTRA_DEPS)"
 	@echo "HOST_PROGRAM       = $(HOST_PROGRAM)"
 	@echo "HOST_OBJS          = $(HOST_OBJS)"
 	@echo "HOST_PROGOBJS      = $(HOST_PROGOBJS)"
 	@echo "HOST_LIBRARY       = $(HOST_LIBRARY)"
 
 showbuildmods::
-	@echo "Build Modules	= $(BUILD_MODULES)"
 	@echo "Module dirs	= $(BUILD_MODULE_DIRS)"
 
 documentation:
 	@cd $(DEPTH)
 	$(DOXYGEN) $(DEPTH)/config/doxygen.cfg
 
 ifdef ENABLE_TESTS
 check:: $(SUBMAKEFILES) $(MAKE_DIRS)
--- a/configure.in
+++ b/configure.in
@@ -965,17 +965,16 @@ if test -n "$_WIN32_MSVC"; then
     SKIP_COMPILER_CHECKS=1
     SKIP_LIBRARY_CHECKS=1
 
     # Since we're skipping compiler and library checks, hard-code
     # some facts here.
     AC_DEFINE(HAVE_IO_H)
     AC_DEFINE(HAVE_SETBUF)
     AC_DEFINE(HAVE_ISATTY)
-    AC_DEFINE(HAVE_STDCALL)
 fi
 
 fi # COMPILE_ENVIRONMENT
 
 AC_SUBST(MIDL_FLAGS)
 AC_SUBST(_MSC_VER)
 
 AC_SUBST(GNU_AS)
@@ -2477,16 +2476,18 @@ ia64*-hpux*)
 
         if test $_MSC_VER -ge 1400; then
             LDFLAGS="$LDFLAGS -SAFESEH"
         fi
 
         if test -n "$GNU_CC"; then
             CFLAGS="$CFLAGS -mstackrealign"
             CXXFLAGS="$CXXFLAGS -mstackrealign"
+        else
+            AC_DEFINE(HAVE_STDCALL)
         fi
 
         MOZ_CHECK_HEADERS(mmintrin.h)
     	AC_DEFINE(_X86_)
 	;;
     x86_64-*)
         AC_DEFINE(_AMD64_)
         ;;
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -6120,17 +6120,17 @@ nsDocument::AdoptNode(nsIDOMNode *aAdopt
           if (node &&
               nsContentUtils::ContentIsDescendantOf(node, adoptedNode)) {
             return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
           }
         }
       } while ((doc = doc->GetParentDocument()));
 
       // Remove from parent.
-      nsINode* parent = adoptedNode->GetNodeParent();
+      nsCOMPtr<nsINode> parent = adoptedNode->GetNodeParent();
       if (parent) {
         rv = parent->RemoveChildAt(parent->IndexOf(adoptedNode), PR_TRUE);
         NS_ENSURE_SUCCESS(rv, rv);
       }
 
       break;
     }
     case nsIDOMNode::ENTITY_REFERENCE_NODE:
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -615,17 +615,17 @@ nsINode::Normalize()
           tmpStr.Truncate();
           text->AppendTo(tmpStr);
           t->AppendTextForNormalize(tmpStr.get(), tmpStr.Length(), PR_TRUE, node);
         }
       }
     }
 
     // Remove node
-    nsINode* parent = node->GetNodeParent();
+    nsCOMPtr<nsINode> parent = node->GetNodeParent();
     NS_ASSERTION(parent || hasRemoveListeners,
                  "Should always have a parent unless "
                  "mutation events messed us up");
     if (parent) {
       parent->RemoveChildAt(parent->IndexOf(node), PR_TRUE);
     }
   }
 
@@ -3940,17 +3940,17 @@ nsINode::ReplaceOrInsertBefore(PRBool aR
   if (newContent->IsRootOfAnonymousSubtree()) {
     // This is anonymous content.  Don't allow its insertion
     // anywhere, since it might have UnbindFromTree calls coming
     // its way.
     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
   }
 
   // Remove the new child from the old parent if one exists
-  nsINode* oldParent = newContent->GetNodeParent();
+  nsCOMPtr<nsINode> oldParent = newContent->GetNodeParent();
   if (oldParent) {
     PRInt32 removeIndex = oldParent->IndexOf(newContent);
     if (removeIndex < 0) {
       // newContent is anonymous.  We can't deal with this, so just bail
       NS_ERROR("How come our flags didn't catch this?");
       return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
     }
 
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -2505,22 +2505,22 @@ nsHTMLInputElement::SanitizeValue(nsAStr
   NS_ASSERTION(!GET_BOOLBIT(mBitField, BF_PARSER_CREATING),
                "The element parsing should be finished!");
 
   switch (mType) {
     case NS_FORM_INPUT_TEXT:
     case NS_FORM_INPUT_SEARCH:
     case NS_FORM_INPUT_TEL:
     case NS_FORM_INPUT_PASSWORD:
-    case NS_FORM_INPUT_EMAIL:
       {
         PRUnichar crlf[] = { PRUnichar('\r'), PRUnichar('\n'), 0 };
         aValue.StripChars(crlf);
       }
       break;
+    case NS_FORM_INPUT_EMAIL:
     case NS_FORM_INPUT_URL:
       {
         PRUnichar crlf[] = { PRUnichar('\r'), PRUnichar('\n'), 0 };
         aValue.StripChars(crlf);
 
         aValue = nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(aValue);
       }
       break;
--- a/content/html/content/test/forms/test_input_email.html
+++ b/content/html/content/test/forms/test_input_email.html
@@ -70,18 +70,22 @@ function testEmailAddress(aElement, aVal
 }
 
 var email = document.forms[0].elements[0];
 
 // Simple values, checking the e-mail syntax validity.
 var values = [
   [ '', true ], // The empty string shouldn't be considered as invalid.
   [ 'foo@bar.com', true ],
-  [ ' foo@bar.com', false ],
-  [ 'foo@bar.com ', false ],
+  [ ' foo@bar.com', true ],
+  [ 'foo@bar.com ', true ],
+  [ '\r\n foo@bar.com', true ],
+  [ 'foo@bar.com \n\r', true ],
+  [ '\n\n \r\rfoo@bar.com\n\n   \r\r', true ],
+  [ '\n\r \n\rfoo@bar.com\n\r   \n\r', true ],
   [ 'tulip', false ],
   // Some checks on the user part of the address.
   [ '@bar.com', false ],
   [ 'f\noo@bar.com', true ],
   [ 'f\roo@bar.com', true ],
   [ 'f\r\noo@bar.com', true ],
   // Some checks for the domain part.
   [ 'foo@bar', true ],
@@ -158,17 +162,17 @@ for each (c in legalCharacters) {
   values.push(["foo@foo.bar" + c, true]);
 }
 // Add the concatenation of all legal characters too.
 values.push(["foo@bar.com" + legalCharacters, true]);
 
 // Add domain illegal characters.
 illegalCharacters = "()<>[]:;@\\,!#$%&'*+/=?^_`{|}~ \t";
 for each (c in illegalCharacters) {
-  values.push(['foo@foo.bar' + c, false]);
+  values.push(['foo@foo.ba' + c + 'r', false]);
 }
 
 values.forEach(function([value, valid]) {
   testEmailAddress(email, value, false, valid);
 });
 
 multipleValues.forEach(function([value, valid]) {
   testEmailAddress(email, value, true, valid);
--- a/content/html/content/test/test_bug549475.html
+++ b/content/html/content/test/test_bug549475.html
@@ -42,19 +42,19 @@ var valueModeValue =
 
 function sanitizeValue(aType, aValue)
 {
   switch (aType) {
     case "text":
     case "password":
     case "search":
     case "tel":
-    case "email":
       return aValue.replace(/[\n\r]/g, "");
     case "url":
+    case "email":
       return aValue.replace(/[\n\r]/g, "").replace(/^\s+|\s+$/g, "");
     case "date":
     case "month":
     case "week":
     case "time":
     case "datetime":
     case "datetime-local":
       // TODO: write the sanitize algorithm.
--- a/content/media/test/test_replay_metadata.html
+++ b/content/media/test/test_replay_metadata.html
@@ -27,17 +27,16 @@ var manager = new MediaTestManager;
 function seekStarted(evt) {
   var v = evt.target;
   v._gotSeekStarted = true;
 }
 
 function seekEnded(evt) {
   var v = evt.target;
   v._gotSeekEnded = true;
-  v.play();
 }
 
 function loadedData(evt) {
   var v = evt.target;
   v._loadedDataCount++;
   ok(v._loadedDataCount <= 1, "No more than 1 onloadeddata event for " + v._name);
 }
 
--- a/content/smil/nsSMILCSSProperty.cpp
+++ b/content/smil/nsSMILCSSProperty.cpp
@@ -141,46 +141,47 @@ nsSMILCSSProperty::GetBaseValue() const
 
   // (3) Put cached override style back (if it's non-empty)
   if (overrideDecl && !cachedOverrideStyleVal.IsEmpty()) {
     overrideDecl->SetPropertyValue(mPropID, cachedOverrideStyleVal);
   }
 
   // (4) Populate our nsSMILValue from the computed style
   if (didGetComputedVal) {
+    // When we parse animation values we check if they are context-sensitive or
+    // not so that we don't cache animation values whose meaning may change.
+    // For base values however this is unnecessary since on each sample the
+    // compositor will fetch the (computed) base value and compare it against
+    // the cached (computed) value and detect changes for us.
     nsSMILCSSValueType::ValueFromString(mPropID, mElement,
-                                        computedStyleVal, baseValue);
+                                        computedStyleVal, baseValue,
+                                        nsnull);
   }
   return baseValue;
 }
 
 nsresult
 nsSMILCSSProperty::ValueFromString(const nsAString& aStr,
                                    const nsISMILAnimationElement* aSrcElement,
                                    nsSMILValue& aValue,
                                    PRBool& aPreventCachingOfSandwich) const
 {
   NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE);
 
-  nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue);
-  if (aValue.IsNull()) {
-    return NS_ERROR_FAILURE;
+  nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue,
+      &aPreventCachingOfSandwich);
+
+  // XXX Due to bug 536660 (or at least that seems to be the most likely
+  // culprit), when we have animation setting display:none on a <use> element,
+  // if we DON'T set the property every sample, chaos ensues.
+  if (!aPreventCachingOfSandwich && mPropID == eCSSProperty_display) {
+    aPreventCachingOfSandwich = PR_TRUE;
   }
 
-  // XXXdholbert: For simplicity, just assume that all CSS values have to
-  // reparsed every sample. This prevents us from doing the "nothing's changed
-  // so don't recompose" optimization (bug 533291) for CSS properties & mapped
-  // attributes.  If it ends up being expensive to always recompose those, we
-  // can be a little smarter here.  We really only need to set
-  // aPreventCachingOfSandwich to true for "inherit" & "currentColor" (whose
-  // values could change at any time), for length-valued types (particularly
-  // those with em/ex/percent units, since their conversion ratios can change
-  // at any time), and for any value for 'font-family'.
-  aPreventCachingOfSandwich = PR_TRUE;
-  return NS_OK;
+  return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK;
 }
 
 nsresult
 nsSMILCSSProperty::SetAnimValue(const nsSMILValue& aValue)
 {
   NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE);
 
   // Convert nsSMILValue to string
--- a/content/smil/nsSMILCSSValueType.cpp
+++ b/content/smil/nsSMILCSSValueType.cpp
@@ -366,32 +366,34 @@ GetPresContextForElement(Element* aElem)
 }
 
 // Helper function to parse a string into a nsStyleAnimation::Value
 static PRBool
 ValueFromStringHelper(nsCSSProperty aPropID,
                       Element* aTargetElement,
                       nsPresContext* aPresContext,
                       const nsAString& aString,
-                      nsStyleAnimation::Value& aStyleAnimValue)
+                      nsStyleAnimation::Value& aStyleAnimValue,
+                      PRBool* aIsContextSensitive)
 {
   // If value is negative, we'll strip off the "-" so the CSS parser won't
   // barf, and then manually make the parsed value negative.
   // (This is a partial solution to let us accept some otherwise out-of-bounds
   // CSS values. Bug 501188 will provide a more complete fix.)
   PRBool isNegative = PR_FALSE;
   PRUint32 subStringBegin = 0;
   PRInt32 absValuePos = nsSMILParserUtils::CheckForNegativeNumber(aString);
   if (absValuePos > 0) {
     isNegative = PR_TRUE;
     subStringBegin = (PRUint32)absValuePos; // Start parsing after '-' sign
   }
   nsDependentSubstring subString(aString, subStringBegin);
   if (!nsStyleAnimation::ComputeValue(aPropID, aTargetElement, subString,
-                                      PR_TRUE, aStyleAnimValue)) {
+                                      PR_TRUE, aStyleAnimValue,
+                                      aIsContextSensitive)) {
     return PR_FALSE;
   }
   if (isNegative) {
     InvertSign(aStyleAnimValue);
   }
   
   if (aPropID == eCSSProperty_font_size) {
     // Divide out text-zoom, since SVG is supposed to ignore it
@@ -404,28 +406,29 @@ ValueFromStringHelper(nsCSSProperty aPro
   return PR_TRUE;
 }
 
 // static
 void
 nsSMILCSSValueType::ValueFromString(nsCSSProperty aPropID,
                                     Element* aTargetElement,
                                     const nsAString& aString,
-                                    nsSMILValue& aValue)
+                                    nsSMILValue& aValue,
+                                    PRBool* aIsContextSensitive)
 {
   NS_ABORT_IF_FALSE(aValue.IsNull(), "Outparam should be null-typed");
   nsPresContext* presContext = GetPresContextForElement(aTargetElement);
   if (!presContext) {
     NS_WARNING("Not parsing animation value; unable to get PresContext");
     return;
   }
 
   nsStyleAnimation::Value parsedValue;
   if (ValueFromStringHelper(aPropID, aTargetElement, presContext,
-                            aString, parsedValue)) {
+                            aString, parsedValue, aIsContextSensitive)) {
     sSingleton.Init(aValue);
     aValue.mU.mPtr = new ValueWrapper(aPropID, parsedValue, presContext);
   }
 }
 
 // static
 PRBool
 nsSMILCSSValueType::ValueToString(const nsSMILValue& aValue,
--- a/content/smil/nsSMILCSSValueType.h
+++ b/content/smil/nsSMILCSSValueType.h
@@ -95,23 +95,30 @@ public:
    * Otherwise, this method leaves aValue.mType == this class's singleton.
    *
    * @param       aPropID         The property for which we're parsing a value.
    * @param       aTargetElement  The target element to whom the property/value
    *                              setting applies.
    * @param       aString         The string to be parsed as a CSS value.
    * @param [out] aValue          The nsSMILValue to be populated. Should
    *                              initially be null-typed.
+   * @param [out] aIsContextSensitive Set to PR_TRUE if |aString| may produce
+   *                                  a different |aValue| depending on other
+   *                                  CSS properties on |aTargetElement|
+   *                                  or its ancestors (e.g. 'inherit).
+   *                                  PR_FALSE otherwise. May be nsnull.
+   *                                  Not set if the method fails.
    * @pre  aValue.IsNull()
    * @post aValue.IsNull() || aValue.mType == nsSMILCSSValueType::sSingleton
    */
   static void ValueFromString(nsCSSProperty aPropID,
                               Element* aTargetElement,
                               const nsAString& aString,
-                              nsSMILValue& aValue);
+                              nsSMILValue& aValue,
+                              PRBool* aIsContextSensitive);
 
   /**
    * Creates a string representation of the given nsSMILValue.
    *
    * Note: aValue is expected to be of this type (that is, it's expected to
    * have been initialized by nsSMILCSSValueType::sSingleton).  If aValue is a
    * freshly-initialized value, this method will succeed, though the resulting
    * string will be empty.
--- a/content/smil/nsSMILMappedAttribute.cpp
+++ b/content/smil/nsSMILMappedAttribute.cpp
@@ -62,38 +62,36 @@ ReleaseStringBufferPropertyValue(void*  
 nsresult
 nsSMILMappedAttribute::ValueFromString(const nsAString& aStr,
                                        const nsISMILAnimationElement* aSrcElement,
                                        nsSMILValue& aValue,
                                        PRBool& aPreventCachingOfSandwich) const
 {
   NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE);
 
-  nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue);
-  if (aValue.IsNull()) {
-    return NS_ERROR_FAILURE;
-  }
-
-  // XXXdholbert: For simplicity, just assume that all CSS values have to
-  // reparsed every sample. See note in nsSMILCSSProperty::ValueFromString.
-  aPreventCachingOfSandwich = PR_TRUE;
-  return NS_OK;
+  nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue,
+                                      &aPreventCachingOfSandwich);
+  return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK;
 }
 
 nsSMILValue
 nsSMILMappedAttribute::GetBaseValue() const
 {
   nsAutoString baseStringValue;
   nsRefPtr<nsIAtom> attrName = GetAttrNameAtom();
   PRBool success = mElement->GetAttr(kNameSpaceID_None, attrName,
                                      baseStringValue);
   nsSMILValue baseValue;
   if (success) {
+    // For base values, we don't need to worry whether the value returned is
+    // context-sensitive or not since the compositor will take care of comparing
+    // the returned (computed) base value and its cached value and determining
+    // if an update is required or not.
     nsSMILCSSValueType::ValueFromString(mPropID, mElement,
-                                        baseStringValue, baseValue);
+                                        baseStringValue, baseValue, nsnull);
   } else {
     // Attribute is unset -- use computed value.
     // FIRST: Temporarily clear animated value, to make sure it doesn't pollute
     // the computed value. (We want base value, _without_ animations applied.)
     void* buf = mElement->UnsetProperty(SMIL_MAPPED_ATTR_ANIMVAL,
                                         attrName, nsnull);
     FlushChangesToTargetAttr();
 
--- a/content/smil/test/test_smilChangeAfterFrozen.xhtml
+++ b/content/smil/test/test_smilChangeAfterFrozen.xhtml
@@ -3,118 +3,153 @@
   <title>Test for SMIL when things change after an animation is frozen</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="text/javascript" src="smilTestUtils.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=533291">Mozilla Bug 533291</a>
 <p id="display"></p>
-<div id="content" style="display: none">
+<!-- Bug 628848: The following should be display: none but we currently don't
+     handle percentage lengths properly when the whole fragment is display: none
+     -->
+<div id="content" style="visibility: hidden">
 <svg id="svg" xmlns="http://www.w3.org/2000/svg" width="120px" height="120px"
      onload="this.pauseAnimations()">
   <g id="circleParent">
     <circle cx="0" cy="20" r="15" fill="blue" id="circle"/>
   </g>
 </svg>
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 <![CDATA[
-/** Test for SMIL fill modes **/
+/** Test for SMIL values that are context-sensitive **/
+
+/* See bugs 533291 and 562815.
+   
+   The format of each test is basically:
+   1) create some animated and frozen state
+   2) test the animated values
+   3) change the context
+   4) test that context-sensitive animation values have changed
+
+   Ideally, after changing the context (3), the animated state would instantly
+   update. However, this is not currently the case for many situations.
+
+     For CSS properties we have bug 545282 - In animations involving 'inherit'
+     / 'currentColor', changes to inherited value / 'color' don't show up in
+     animated value immediately
+
+     For SVG lengths we have bug 508206 - Relative units used in
+     animation don't update immediately
+
+     (There are a few of todo_is's in the following tests so that if those bugs
+     are ever resolved we'll know to update this test case accordingly.)
+
+   So in between (3) and (4) we force a sample. This is currently done by
+   calling SVGSVGElement.setCurrentTime with the same current time which has the
+   side effect of forcing a sample.
+
+   What we *are* testing is that we're not too zealous with caching animation
+   values whilst in the frozen state. Normally we'd say, "Hey, we're frozen,
+   let's just use the same animation result as last time" but for some
+   context-sensitive animation values that doesn't work.
+*/
 
 /* Global Variables */
 const SVGNS = "http://www.w3.org/2000/svg";
+
+// Animation parameters -- not used for <set> animation
 const ANIM_DUR = "4s";
 const TIME_ANIM_END = "4";
 const TIME_AFTER_ANIM_END = "5";
 
-// SETTIMEOUT_INTERVAL: This value just needs to be at least as large as
-// nsSMILAnimationController::kTimerInterval, so we can queue up a callback
-// for this far in the future and be assured that an animation sample will
-// have happened before the callback fires (because we presumably already
-// have an animation sample in the setTimeout queue, with a lower timeout
-// value than this).
-// NOTE: We only need to use timeouts here because of Bug 545282.
-const SETTIMEOUT_INTERVAL = 60;
-
-const gTestArray =
-  [ testBaseValueChange,
-    testCurrentColorChange,
-    testCurrentColorChangeUsingStyle,
-    testInheritChange,
-    testInheritChangeUsingStyle
-   ];
-
-// Index of current test in gTestArray
-var gNextTestIndex = 0;
-
 const gSvg = document.getElementById("svg");
 const gCircle = document.getElementById("circle");
 const gCircleParent = document.getElementById("circleParent");
 
-
 SimpleTest.waitForExplicitFinish();
 
 // MAIN FUNCTION
 // -------------
 
-function main() {
+function main()
+{
   ok(gSvg.animationsPaused(), "should be paused by <svg> load handler");
   is(gSvg.getCurrentTime(), 0, "should be paused at 0 in <svg> load handler");
 
-  if (gNextTestIndex != 0) {
-    ok(false, "expecting to start at first test in array.");
+  const tests =
+    [ testBaseValueChange,
+      testCurrentColorChange,
+      testCurrentColorChangeUsingStyle,
+      testCurrentColorChangeOnFallback,
+      testInheritChange,
+      testInheritChangeUsingStyle,
+      testEmUnitChangeOnProp,
+      testEmUnitChangeOnPropBase,
+      testEmUnitChangeOnLength,
+      testPercentUnitChangeOnProp,
+      testPercentUnitChangeOnLength,
+      testRelativeFontSize,
+      testRelativeFontWeight,
+      testRelativeFont,
+      testCalcFontSize,
+      testDashArray,
+      testClip
+     ];
+
+  while (tests.length) {
+    tests.shift()();
   }
-  // Kick off first test.  (It will kick off the one after it, and so on.)
-  runNextTest();
+  SimpleTest.finish();
 }
 
 // HELPER FUNCTIONS
 // ----------------
-function createAnimFromTo(attrName, fromVal, toVal) {
-  var anim = document.createElementNS(SVGNS,"animate");
+function createAnimSetTo(attrName, toVal)
+{
+  var anim = document.createElementNS(SVGNS,"set");
   anim.setAttribute("attributeName", attrName);
-  anim.setAttribute("dur", ANIM_DUR);
-  anim.setAttribute("begin", "0s");
-  anim.setAttribute("from", fromVal);
   anim.setAttribute("to", toVal);
-  anim.setAttribute("fill", "freeze");
   return gCircle.appendChild(anim);
 }
-function createAnimBy(attrName, byVal) {
+
+function createAnimBy(attrName, byVal)
+{
   var anim = document.createElementNS(SVGNS,"animate");
   anim.setAttribute("attributeName", attrName);
   anim.setAttribute("dur", ANIM_DUR);
   anim.setAttribute("begin","0s");
   anim.setAttribute("by", byVal);
   anim.setAttribute("fill", "freeze");
   return gCircle.appendChild(anim);
 }
 
+function createAnimFromTo(attrName, fromVal, toVal)
+{
+  var anim = document.createElementNS(SVGNS,"animate");
+  anim.setAttribute("attributeName", attrName);
+  anim.setAttribute("dur", ANIM_DUR);
+  anim.setAttribute("begin","0s");
+  anim.setAttribute("from", fromVal);
+  anim.setAttribute("to", toVal);
+  anim.setAttribute("fill", "freeze");
+  return gCircle.appendChild(anim);
+}
+
 // Common setup code for each test function: seek to 0, and make sure
 // the previous test cleaned up its animations.
 function setupTest() {
   gSvg.setCurrentTime(0);
   if (gCircle.firstChild) {
     ok(false, "Previous test didn't clean up after itself.");
   }
 }
 
-function runNextTest() {
-  if (gNextTestIndex == gTestArray.length) {
-    // No tests left! we're done.
-    SimpleTest.finish();
-    return;
-  }
-
-  // Call next test (and increment next-test index)
-  gTestArray[gNextTestIndex++]();
-}
-
 // THE TESTS
 // ---------
 
 function testBaseValueChange()
 {
   setupTest();
   var anim = createAnimBy("cx", "50");
   gSvg.setCurrentTime(TIME_ANIM_END);
@@ -125,116 +160,410 @@ function testBaseValueChange()
   is(gCircle.cx.animVal.value, 50,
      "Checking animated cx after anim ends");
 
   gCircle.setAttribute("cx", 20);
   is(gCircle.cx.animVal.value, 70,
      "Checking animated cx after anim ends & after changing base val");
 
   anim.parentNode.removeChild(anim); // clean up
-  runNextTest();
 }
 
 function testCurrentColorChange()
 {
   gCircle.setAttribute("color", "red"); // At first: currentColor=red
-  var anim = createAnimFromTo("fill", "yellow", "currentColor");
+  var anim = createAnimSetTo("fill", "currentColor");
 
-  gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
+  gSvg.setCurrentTime(0); // trigger synchronous sample
   is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(255, 0, 0)",
-     "Checking animated fill=currentColor after anim ends");
+     "Checking animated fill=currentColor after animating");
 
   gCircle.setAttribute("color", "lime"); // Change: currentColor=lime
-  setTimeout(testCurrentColorChange_final, SETTIMEOUT_INTERVAL);
-}
-
-function testCurrentColorChange_final()
-{
+  // Bug 545282: We should really detect this change and update immediately but
+  // currently we don't until we get sampled again
+  todo_is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(0, 255, 0)",
+     "Checking animated fill=currentColor after updating context but before " +
+     "sampling");
+  gSvg.setCurrentTime(0);
   is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(0, 255, 0)",
-     "Checking animated fill=currentColor after anim ends and 'color' changes");
+     "Checking animated fill=currentColor after updating context");
 
   // Clean up
   gCircle.removeAttribute("color");
-  gCircle.firstChild.parentNode.removeChild(gCircle.firstChild);
-
-  // Kick off next test
-  runNextTest();
+  gCircle.removeChild(gCircle.firstChild);
 }
 
 function testCurrentColorChangeUsingStyle()
 {
   setupTest();
   gCircle.setAttribute("style", "color: red"); // At first: currentColor=red
-  var anim = createAnimFromTo("fill", "yellow", "currentColor");
+  var anim = createAnimSetTo("fill", "currentColor");
 
-  gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
+  gSvg.setCurrentTime(0);
   is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(255, 0, 0)",
-     "Checking animated fill=currentColor after anim ends (using style attr)");
+     "Checking animated fill=currentColor after animating (using style attr)");
 
   gCircle.setAttribute("style", "color: lime"); // Change: currentColor=lime
-  setTimeout(testCurrentColorChangeUsingStyle_final, SETTIMEOUT_INTERVAL);
-}
-
-function testCurrentColorChangeUsingStyle_final()
-{
+  gSvg.setCurrentTime(0);
   is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(0, 255, 0)",
-     "Checking animated fill=currentColor after anim ends and 'color' changes "
+     "Checking animated fill=currentColor after updating context "
      + "(using style attr)");
 
   // Clean up
   gCircle.removeAttribute("style");
-  gCircle.firstChild.parentNode.removeChild(gCircle.firstChild);
-  runNextTest();
+  gCircle.removeChild(gCircle.firstChild);
+}
+
+function getFallbackColor(pServerStr)
+{
+  return pServerStr.substr(pServerStr.indexOf(" ")+1);
+}
+
+function testCurrentColorChangeOnFallback()
+{
+  setupTest();
+  gCircle.setAttribute("color", "red"); // At first: currentColor=red
+  var anim = createAnimSetTo("fill", "url(#missingGrad) currentColor");
+
+  gSvg.setCurrentTime(0);
+  var fallback =
+    getFallbackColor(SMILUtil.getComputedStyleSimple(gCircle, "fill"));
+  is(fallback, "rgb(255, 0, 0)",
+     "Checking animated fallback fill=currentColor after animating");
+
+  gCircle.setAttribute("color", "lime"); // Change: currentColor=lime
+  gSvg.setCurrentTime(0);
+  fallback = getFallbackColor(SMILUtil.getComputedStyleSimple(gCircle, "fill"));
+  is(fallback, "rgb(0, 255, 0)",
+     "Checking animated fallback fill=currentColor after updating context");
+
+  gCircle.removeAttribute("style");
+  gCircle.removeChild(gCircle.firstChild);
 }
 
 function testInheritChange()
 {
   setupTest();
   gCircleParent.setAttribute("fill", "red"); // At first: inherit=red
-  var anim = createAnimFromTo("fill", "yellow", "inherit");
+  var anim = createAnimSetTo("fill", "inherit");
 
-  gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
+  gSvg.setCurrentTime(0);
   is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(255, 0, 0)",
-     "Checking animated fill=inherit after anim ends");
+     "Checking animated fill=inherit after animating");
 
   gCircleParent.setAttribute("fill", "lime"); // Change: inherit=lime
-  setTimeout(testInheritChange_final, SETTIMEOUT_INTERVAL);
-}
-
-function testInheritChange_final() {
+  gSvg.setCurrentTime(0);
   is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(0, 255, 0)",
-     "Checking animated fill=inherit after anim ends and parent val changes");
+     "Checking animated fill=inherit after updating context");
 
   gCircleParent.removeAttribute("fill");
-  gCircle.firstChild.parentNode.removeChild(gCircle.firstChild);
-  runNextTest();
+  gCircle.removeChild(gCircle.firstChild);
 }
 
 function testInheritChangeUsingStyle()
 {
   setupTest();
   gCircleParent.setAttribute("style", "fill: red"); // At first: inherit=red
-  var anim = createAnimFromTo("fill", "yellow", "inherit");
+  var anim = createAnimSetTo("fill", "inherit");
 
-  gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
+  gSvg.setCurrentTime(0);
   is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(255, 0, 0)",
-     "Checking animated fill=inherit after anim ends (using style attr)");
+     "Checking animated fill=inherit after animating (using style attr)");
 
   gCircleParent.setAttribute("style", "fill: lime"); // Change: inherit=lime
-  setTimeout(testInheritChangeUsingStyle_final, SETTIMEOUT_INTERVAL);
-}
-
-function testInheritChangeUsingStyle_final() {
+  gSvg.setCurrentTime(0);
   is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(0, 255, 0)",
-     "Checking animated fill=inherit after anim ends and parent val changes "
+     "Checking animated fill=inherit after updating context "
      + "(using style attr)");
 
   gCircleParent.removeAttribute("style");
-  gCircle.firstChild.parentNode.removeChild(gCircle.firstChild);
-  runNextTest();
+  gCircle.removeChild(gCircle.firstChild);
+}
+
+function testEmUnitChangeOnProp()
+{
+  setupTest();
+  gCircleParent.setAttribute("font-size", "10px"); // At first: font-size: 10px
+  var anim = createAnimSetTo("font-size", "2em");
+
+  gSvg.setCurrentTime(0);
+  is(SMILUtil.getComputedStyleSimple(gCircle, "font-size"), "20px",
+     "Checking animated font-size=2em after animating ends");
+
+  gCircleParent.setAttribute("font-size", "20px"); // Change: font-size: 20px
+  gSvg.setCurrentTime(0);
+  is(SMILUtil.getComputedStyleSimple(gCircle, "font-size"), "40px",
+     "Checking animated font-size=2em after updating context");
+
+  gCircleParent.removeAttribute("font-size");
+  gCircle.removeChild(gCircle.firstChild);
+}
+
+function testEmUnitChangeOnPropBase()
+{
+  // Test the case where the base value for our animation sandwich is
+  // context-sensitive.
+  // Currently, this is taken care of by the compositor which keeps a cached
+  // base value and compares it with the current base value. This test then just
+  // serves as a regression test in case the compositor's behaviour changes.
+  setupTest();
+  gSvg.setAttribute("font-size", "10px"); // At first: font-size: 10px
+  gCircleParent.setAttribute("font-size", "1em"); // Base: 10px
+  var anim = createAnimBy("font-size", "10px");
+
+  gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
+  is(SMILUtil.getComputedStyleSimple(gCircle, "font-size"), "20px",
+     "Checking animated font-size=20px after anim ends");
+
+  gSvg.setAttribute("font-size", "20px"); // Change: font-size: 20px
+  gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
+  is(SMILUtil.getComputedStyleSimple(gCircle, "font-size"), "30px",
+     "Checking animated font-size=30px after updating context");
+
+  gCircleParent.removeAttribute("font-size");
+  gCircle.removeChild(gCircle.firstChild);
+}
+
+function testEmUnitChangeOnLength()
+{
+  setupTest();
+  gCircleParent.setAttribute("font-size", "10px"); // At first: font-size: 10px
+  var anim = createAnimSetTo("cx", "2em");
+
+  gSvg.setCurrentTime(0);
+  is(gCircle.cx.animVal.value, 20,
+     "Checking animated length=2em after animating");
+
+  gCircleParent.setAttribute("font-size", "20px"); // Change: font-size: 20px
+  // Bug 508206: We should really detect this change and update immediately but
+  // currently we don't until we get sampled again
+  todo_is(gCircle.cx.animVal.value, 40,
+     "Checking animated length=2em after updating context but before sampling");
+
+  gSvg.setCurrentTime(0);
+  is(gCircle.cx.animVal.value, 40,
+     "Checking animated length=2em after updating context and after " +
+     "resampling");
+
+  gCircleParent.removeAttribute("font-size");
+  gCircle.removeChild(gCircle.firstChild);
+}
+
+function testPercentUnitChangeOnProp()
+{
+  setupTest();
+  gCircleParent.setAttribute("font-size", "10px"); // At first: font-size: 10px
+  var anim = createAnimSetTo("font-size", "150%");
+
+  gSvg.setCurrentTime(0);
+  is(SMILUtil.getComputedStyleSimple(gCircle, "font-size"), "15px",
+     "Checking animated font-size=150% after animating");
+
+  gCircleParent.setAttribute("font-size", "20px"); // Change: font-size: 20px
+  gSvg.setCurrentTime(0);
+  is(SMILUtil.getComputedStyleSimple(gCircle, "font-size"), "30px",
+     "Checking animated font-size=150% after updating context");
+
+  gCircleParent.removeAttribute("font-size");
+  gCircle.removeChild(gCircle.firstChild);
+}
+
+function testPercentUnitChangeOnLength()
+{
+  setupTest();
+  var oldHeight = gSvg.getAttribute("height");
+  gSvg.setAttribute("height", "100px"); // At first: viewport height: 100px
+  var anim = createAnimSetTo("cy", "100%");
+
+  gSvg.setCurrentTime(0); // Force synchronous sample so animation takes effect
+  // Due to bug 627594 (SVGLength.value for percent value lengths doesn't
+  // reflect updated viewport until reflow) the following will fail.
+  // Check that it does indeed fail so that when that bug is fixed this test
+  // can be updated.
+  todo_is(gCircle.cy.animVal.value, 100,
+     "Checking animated length=100% after animating but before reflow");
+  gSvg.forceRedraw();
+  // Even after doing a reflow though we'll still fail due to bug 508206
+  // (Relative units used in animation don't update immediately)
+  todo_is(gCircle.cy.animVal.value, 100,
+     "Checking animated length=100% after animating but before resampling");
+  gSvg.setCurrentTime(0);
+  // Now we should be up to date
+  is(gCircle.cy.animVal.value, 100,
+     "Checking animated length=100% after animating");
+
+  gSvg.setAttribute("height", "50px"); // Change: height: 50px
+  gSvg.forceRedraw(); // Bug 627594
+  gSvg.setCurrentTime(0); // Bug 508206
+  is(gCircle.cy.animVal.value, 50,
+     "Checking animated length=100% after updating context");
+
+  gSvg.setAttribute("height", oldHeight);
+  gCircle.removeChild(gCircle.firstChild);
+}
+
+function testRelativeFontSize()
+{
+  setupTest();
+  gCircleParent.setAttribute("font-size", "10px"); // At first: font-size: 10px
+  var anim = createAnimSetTo("font-size", "larger");
+
+  gSvg.setCurrentTime(0);
+  var fsize = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-size"));
+  // CSS 2 suggests a scaling factor of 1.2 so we should be looking at something
+  // around about 12 or so
+  ok(fsize > 10 && fsize < 20,
+    "Checking animated font-size > 10px after animating");
+
+  gCircleParent.setAttribute("font-size", "20px"); // Change: font-size: 20px
+  gSvg.setCurrentTime(0);
+  fsize = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-size"));
+  ok(fsize > 20, "Checking animated font-size > 20px after updating context");
+
+  gCircleParent.removeAttribute("font-size");
+  gCircle.removeChild(gCircle.firstChild);
+}
+
+function testRelativeFontWeight()
+{
+  setupTest();
+  gCircleParent.setAttribute("font-weight", "100"); // At first: font-weight 100
+  var anim = createAnimSetTo("font-weight", "bolder");
+  // CSS 2: 'bolder': Specifies the next weight that is assigned to a font
+  // that is darker than the inherited one. If there is no such weight, it
+  // simply results in the next darker numerical value (and the font remains
+  // unchanged), unless the inherited value was '900', in which case the
+  // resulting weight is also '900'.
+
+  gSvg.setCurrentTime(0);
+  var weight =
+    parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-weight"));
+  ok(weight > 100, "Checking animated font-weight > 100 after animating");
+
+  gCircleParent.setAttribute("font-weight", "800"); // Change: font-weight 800
+  gSvg.setCurrentTime(0);
+  weight = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-weight"));
+  is(weight, 900,
+     "Checking animated font-weight = 900 after updating context");
+
+  gCircleParent.removeAttribute("font-weight");
+  gCircle.removeChild(gCircle.firstChild);
+}
+
+function testRelativeFont()
+{
+  // Test a relative font-size as part of a 'font' spec since the code path
+  // is different in this case
+  // It turns out that, due to the way we store shorthand font properties, we
+  // don't need to worry about marking such values as context-sensitive since we
+  // seem to store them in their relative form. If, however, we change the way
+  // we store shorthand font properties in the future, this will serve as
+  // a useful regression test.
+  setupTest();
+  gCircleParent.setAttribute("font-size", "10px"); // At first: font-size: 10px
+  // We must be sure to set every part of the shorthand property to some
+  // non-context sensitive value because we want to test that even if only the
+  // font-size is relative we will update it appropriately.
+  var anim =
+    createAnimSetTo("font", "normal normal bold larger/normal sans-serif");
+
+  gSvg.setCurrentTime(0);
+  var fsize = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-size"));
+  ok(fsize > 10 && fsize < 20,
+    "Checking size of shorthand 'font' > 10px after animating");
+
+  gCircleParent.setAttribute("font-size", "20px"); // Change: font-size: 20px
+  gSvg.setCurrentTime(0);
+  fsize  = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-size"));
+  ok(fsize > 20,
+     "Checking size of shorthand 'font' > 20px after updating context");
+
+  gCircleParent.removeAttribute("font-size");
+  gCircle.removeChild(gCircle.firstChild);
+}
+
+function testCalcFontSize()
+{
+  setupTest();
+  gCircleParent.setAttribute("font-size", "10px"); // At first: font-size: 10px
+  var anim = createAnimSetTo("font-size", "-moz-calc(110% + 0.1em)");
+
+  gSvg.setCurrentTime(0);
+  var fsize = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-size"));
+  // Font size should be 1.1 * 10px + 0.1 * 10px = 12
+  is(fsize, 12, "Checking animated calc font-size == 12px after animating");
+
+  gCircleParent.setAttribute("font-size", "20px"); // Change: font-size: 20px
+  gSvg.setCurrentTime(0);
+  fsize = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-size"));
+  is(fsize, 24, "Checking animated calc font-size == 24px after updating " +
+                "context");
+
+  gCircleParent.removeAttribute("font-size");
+  gCircle.removeChild(gCircle.firstChild);
+}
+
+function testDashArray()
+{
+  // stroke dasharrays don't currently convert units--but if someone ever fixes
+  // that, hopefully this test will fail and remind us not to cache percentage
+  // values in that case
+  setupTest();
+  var oldHeight = gSvg.getAttribute("height");
+  var oldWidth  = gSvg.getAttribute("width");
+  gSvg.setAttribute("height", "100px"); // At first: viewport: 100x100px
+  gSvg.setAttribute("width",  "100px");
+  var anim = createAnimFromTo("stroke-dasharray", "0 5", "0 50%");
+
+  gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
+
+  // Now we should be up to date
+  is(SMILUtil.getComputedStyleSimple(gCircle, "stroke-dasharray"), "0, 50%",
+     "Checking animated stroke-dasharray after animating");
+
+  gSvg.setAttribute("height", "50px"); // Change viewport: 50x50px
+  gSvg.setAttribute("width",  "50px");
+  gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
+  is(SMILUtil.getComputedStyleSimple(gCircle, "stroke-dasharray"), "0, 50%",
+     "Checking animated stroke-dasharray after updating context");
+
+  gSvg.setAttribute("height", oldHeight);
+  gSvg.setAttribute("width",  oldWidth);
+  gCircle.removeChild(gCircle.firstChild);
+}
+
+function testClip()
+{
+  setupTest();
+  gCircleParent.setAttribute("font-size", "20px"); // At first: font-size: 20px
+
+  // The clip property only applies to elements that establish a new
+  // viewport so we need to create a nested svg and add animation to that
+  var nestedSVG = document.createElementNS(SVGNS, "svg");
+  nestedSVG.setAttribute("clip", "rect(0px 0px 0px 0px)");
+  gCircleParent.appendChild(nestedSVG);
+
+  var anim = createAnimSetTo("clip", "rect(1em 1em 1em 1em)");
+  // createAnimSetTo will make the animation a child of gCircle so we need to
+  // move it so it targets nestedSVG instead
+  nestedSVG.appendChild(anim);
+
+  gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
+  is(SMILUtil.getComputedStyleSimple(nestedSVG, "clip"),
+     "rect(20px, 20px, 20px, 20px)",
+     "Checking animated clip rect after animating");
+
+  gCircleParent.setAttribute("font-size", "10px"); // Change: font-size: 10px
+  gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
+  is(SMILUtil.getComputedStyleSimple(nestedSVG, "clip"),
+     "rect(10px, 10px, 10px, 10px)",
+     "Checking animated clip rect after updating context");
+
+  gCircleParent.removeAttribute("font-size");
+  gCircleParent.removeChild(nestedSVG);
 }
 
 window.addEventListener("load", main, false);
 ]]>
 </script>
 </pre>
 </body>
 </html>
--- a/content/svg/content/test/Makefile.in
+++ b/content/svg/content/test/Makefile.in
@@ -52,17 +52,16 @@ include $(topsrcdir)/config/rules.mk
 		test_a_href_01.xhtml \
 		test_a_href_02.xhtml \
 		a_href_destination.svg \
 		a_href_helper_01.svg \
 		a_href_helper_02_03.svg \
 		a_href_helper_04.svg \
 		test_animLengthObjectIdentity.xhtml \
 		test_animLengthReadonly.xhtml \
-		test_animLengthRelativeUnits.xhtml \
 		test_animLengthUnits.xhtml \
 		test_bbox.xhtml \
 		test_bbox-with-invalid-viewBox.xhtml \
 		bbox-helper.svg \
 		bounds-helper.svg \
 		test_dataTypes.html \
 		dataTypes-helper.svg \
 		getCTM-helper.svg \
deleted file mode 100644
--- a/content/svg/content/test/test_animLengthRelativeUnits.xhtml
+++ /dev/null
@@ -1,80 +0,0 @@
-<html xmlns="http://www.w3.org/1999/xhtml">
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=508206
--->
-<head>
-  <title>Test for liveness of relative units in animation</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=508206">Mozilla Bug 508206</a>
-<p id="display"></p>
-<!-- XXX The following should be display: none but that's broken by bug 413975
-     where we don't handle percentage lengths when the whole fragment is
-     display: none properly. -->
-<div id="content" style="visibility: hidden">
-<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="100px" height="100px"
-     onload="this.pauseAnimations()">
-  <g font-size="10px">
-    <circle cx="0" cy="0" r="15" fill="blue" id="circle">
-      <animate attributeName="cx" from="0" to="10em" dur="10s" begin="0s"
-        fill="freeze" id="animate"/>
-      <animate attributeName="cy" from="0" to="100%" dur="10s" begin="0s"
-        fill="freeze"/>
-    </circle>
-  </g>
-</svg>
-</div>
-<pre id="test">
-<script class="testbody" type="text/javascript">
-<![CDATA[
-/** Test liveness of relative units of animated lengths **/
-
-/* Global Variables */
-const svgns="http://www.w3.org/2000/svg";
-var svg = document.getElementById("svg");
-var circle = document.getElementById('circle');
-
-SimpleTest.waitForExplicitFinish();
-
-function main() {
-  ok(svg.animationsPaused(), "should be paused by <svg> load handler");
-  is(svg.getCurrentTime(), 0, "should be paused at 0 in <svg> load handler");
-
-  // Sample mid-way through the animation
-  svg.setCurrentTime(5);
-
-  // (1) Check values mid-way
-  is(circle.cx.animVal.value, 50,
-    "(1) Unexpected animVal for cx before changing base length");
-  is(circle.cy.animVal.value, 50,
-    "(1) Unexpected animVal for cy before changing base length");
-
-  // (2) Change the frame of reference and check values are updated immediately
-
-  // Change font-size
-  circle.parentNode.setAttribute('font-size', '5px');
-  todo_is(circle.cx.animVal.value, 25,
-    "(2) Unexpected animVal for cx after changing parent font-size");
-
-  // Change the viewport size
-  svg.setAttribute('height', '50px');
-  todo_is(circle.cy.animVal.value, 25,
-    "(2) Unexpected animVal for cy after changing containing viewport size");
-
-  SimpleTest.finish();
-}
-
-var animate = document.getElementById('animate');
-if (animate && animate.targetElement) {
-  window.addEventListener("load", main, false);
-} else {
-  ok(true); // Skip tests but don't report 'todo' either
-  SimpleTest.finish();
-}
-]]>
-</script>
-</pre>
-</body>
-</html>
--- a/content/xbl/src/nsXBLDocumentInfo.cpp
+++ b/content/xbl/src/nsXBLDocumentInfo.cpp
@@ -424,41 +424,41 @@ static PRBool IsChromeURI(nsIURI* aURI)
   PRBool isChrome = PR_FALSE;
   if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)))
       return isChrome;
   return PR_FALSE;
 }
 
 /* Implementation file */
 
-static PRIntn
+static PRBool
 TraverseProtos(nsHashKey *aKey, void *aData, void* aClosure)
 {
   nsCycleCollectionTraversalCallback *cb = 
     static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
   nsXBLPrototypeBinding *proto = static_cast<nsXBLPrototypeBinding*>(aData);
   proto->Traverse(*cb);
   return kHashEnumerateNext;
 }
 
-static PRIntn
+static PRBool
 UnlinkProtoJSObjects(nsHashKey *aKey, void *aData, void* aClosure)
 {
   nsXBLPrototypeBinding *proto = static_cast<nsXBLPrototypeBinding*>(aData);
   proto->UnlinkJSObjects();
   return kHashEnumerateNext;
 }
 
 struct ProtoTracer
 {
   TraceCallback mCallback;
   void *mClosure;
 };
 
-static PRIntn
+static PRBool
 TraceProtos(nsHashKey *aKey, void *aData, void* aClosure)
 {
   ProtoTracer* closure = static_cast<ProtoTracer*>(aClosure);
   nsXBLPrototypeBinding *proto = static_cast<nsXBLPrototypeBinding*>(aData);
   proto->Trace(closure->mCallback, closure->mClosure);
   return kHashEnumerateNext;
 }
 
--- a/content/xbl/src/nsXBLPrototypeBinding.cpp
+++ b/content/xbl/src/nsXBLPrototypeBinding.cpp
@@ -323,17 +323,17 @@ PRBool nsXBLPrototypeBinding::CompareBin
   PRBool equal = PR_FALSE;
   mBindingURI->Equals(aURI, &equal);
   if (!equal && mAlternateBindingURI) {
     mAlternateBindingURI->Equals(aURI, &equal);
   }
   return equal;
 }
 
-static PRIntn
+static PRBool
 TraverseInsertionPoint(nsHashKey* aKey, void* aData, void* aClosure)
 {
   nsCycleCollectionTraversalCallback &cb = 
     *static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
   nsXBLInsertionPointEntry* entry =
     static_cast<nsXBLInsertionPointEntry*>(aData);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(entry,
                                                nsXBLInsertionPointEntry,
@@ -1208,17 +1208,17 @@ nsXBLPrototypeBinding::ConstructInsertio
                                                DeleteInsertionPointEntry,
                                                nsnull, 4);
   if (!mInsertionPointTable)
     return;
 
   PRInt32 i;
   for (i = 0; i < count; i++) {
     nsIContent* child = childrenElements[i];
-    nsIContent* parent = child->GetParent(); 
+    nsCOMPtr<nsIContent> parent = child->GetParent(); 
 
     // Create an XBL insertion point entry.
     nsXBLInsertionPointEntry* xblIns = nsXBLInsertionPointEntry::Create(parent);
 
     nsAutoString includes;
     child->GetAttr(kNameSpaceID_None, nsGkAtoms::includes, includes);
     if (includes.IsEmpty()) {
       nsISupportsKey key(nsGkAtoms::children);
--- a/content/xul/document/src/nsXULDocument.cpp
+++ b/content/xul/document/src/nsXULDocument.cpp
@@ -4042,17 +4042,18 @@ nsXULDocument::OverlayForwardReference::
         nsAutoString value;
         aOverlayNode->GetAttr(nameSpaceID, attr, value);
 
         // Element in the overlay has the 'removeelement' attribute set
         // so remove it from the actual document.
         if (attr == nsGkAtoms::removeelement &&
             value.EqualsLiteral("true")) {
 
-            rv = RemoveElement(aTargetNode->GetParent(), aTargetNode);
+            nsCOMPtr<nsIContent> parent = aTargetNode->GetParent();
+            rv = RemoveElement(parent, aTargetNode);
             if (NS_FAILED(rv)) return rv;
 
             return NS_OK;
         }
 
         rv = aTargetNode->SetAttr(nameSpaceID, attr, prefix, value, aNotify);
         if (!NS_FAILED(rv) && !aNotify)
             rv = mDocument->BroadcastAttributeChangeFromOverlay(aTargetNode,
--- a/content/xul/templates/src/nsXULContentBuilder.cpp
+++ b/content/xul/templates/src/nsXULContentBuilder.cpp
@@ -1319,17 +1319,17 @@ nsXULContentBuilder::RemoveGeneratedCont
     nsAutoTArray<nsIContent*, 8> ungenerated;
     if (ungenerated.AppendElement(aElement) == nsnull)
         return NS_ERROR_OUT_OF_MEMORY;
 
     PRUint32 count;
     while (0 != (count = ungenerated.Length())) {
         // Pull the next "ungenerated" element off the queue.
         PRUint32 last = count - 1;
-        nsIContent* element = ungenerated[last];
+        nsCOMPtr<nsIContent> element = ungenerated[last];
         ungenerated.RemoveElementAt(last);
 
         PRUint32 i = element->GetChildCount();
 
         while (i-- > 0) {
             nsCOMPtr<nsIContent> child = element->GetChildAt(i);
 
             // Optimize for the <template> element, because we *know*
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -8447,23 +8447,23 @@ nsDocShell::InternalLoad(nsIURI * aURI,
             // Save the current URI; we need it if we fire a hashchange later.
             nsCOMPtr<nsIURI> oldURI = mCurrentURI;
 
             // Save the position of the scrollers.
             nscoord cx = 0, cy = 0;
             GetCurScrollPos(ScrollOrientation_X, &cx);
             GetCurScrollPos(ScrollOrientation_Y, &cy);
 
-            // We scroll whenever we're not doing a history load.  Note that
-            // sometimes we might scroll even if we don't fire a hashchange
-            // event!  See bug 653741.
-            if (!aSHEntry) {
-                rv = ScrollToAnchor(curHash, newHash, aLoadType);
-                NS_ENSURE_SUCCESS(rv, rv);
-            }
+            // ScrollToAnchor doesn't necessarily cause us to scroll the window;
+            // the function decides whether a scroll is appropriate based on the
+            // arguments it receives.  But even if we don't end up scrolling,
+            // ScrollToAnchor performs other important tasks, such as informing
+            // the presShell that we have a new hash.  See bug 680257.
+            rv = ScrollToAnchor(curHash, newHash, aLoadType);
+            NS_ENSURE_SUCCESS(rv, rv);
 
             mLoadType = aLoadType;
             mURIResultedInDocument = PR_TRUE;
 
             /* we need to assign mLSHE to aSHEntry right here, so that on History loads,
              * SetCurrentURI() called from OnNewURI() will send proper
              * onLocationChange() notifications to the browser to update
              * back/forward buttons.
--- a/docshell/test/Makefile.in
+++ b/docshell/test/Makefile.in
@@ -115,16 +115,18 @@ include $(topsrcdir)/config/rules.mk
 		bug570341_recordevents.html \
 		test_bug668513.html \
 		bug668513_redirect.html \
 		bug668513_redirect.html^headers^ \
 		test_bug669671.html \
 		file_bug669671.sjs \
 		test_bug675587.html \
 		test_bfcache_plus_hash.html \
+		test_bug680257.html \
+		file_bug680257.html \
 		$(NULL)
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 _TEST_FILES += \
 		test_bug511449.html \
 		file_bug511449.html \
 		$(NULL)
 endif
new file mode 100644
--- /dev/null
+++ b/docshell/test/file_bug680257.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <style type='text/css'>
+    a        { color: black; }
+    a:target { color: red; }
+  </style>
+</head>
+
+<body onload='(opener || parent).popupLoaded()'>
+
+<a id='a' href='#a'>link</a>
+<a id='b' href='#b'>link2</a>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/test_bug680257.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=680257
+-->
+<head>
+  <title>Test for Bug 680257</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=680257">Mozilla Bug 680257</a>
+
+<script type="application/javascript;version=1.7">
+
+SimpleTest.waitForExplicitFinish();
+
+var popup = window.open('file_bug680257.html');
+
+// The popup will call into popupLoaded() once it loads.
+function popupLoaded() {
+  // runTests() needs to be called from outside popupLoaded's onload handler.
+  // Otherwise, the navigations we do in runTests won't create new SHEntries.
+  SimpleTest.executeSoon(runTests);
+}
+
+function runTests() {
+  checkPopupLinkStyle(false, 'Initial');
+
+  popup.location.hash = 'a';
+  checkPopupLinkStyle(true, 'After setting hash');
+
+  popup.history.back();
+  checkPopupLinkStyle(false, 'After going back');
+
+  popup.history.forward();
+  checkPopupLinkStyle(true, 'After going forward');
+
+  popup.close();
+  SimpleTest.finish();
+}
+
+function checkPopupLinkStyle(isTarget, desc) {
+  var link = popup.document.getElementById('a');
+  var style = popup.getComputedStyle(link);
+  var color = style.getPropertyValue('color');
+
+  // Color is red if isTarget, black otherwise.
+  if (isTarget) {
+    is(color, 'rgb(255, 0, 0)', desc);
+  }
+  else {
+    is(color, 'rgb(0, 0, 0)', desc);
+  }
+}
+
+</script>
+</body>
+</html>
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -8215,29 +8215,31 @@ nsGlobalWindow::GetLocalStorage(nsIDOMSt
 //*****************************************************************************
 // nsGlobalWindow::nsIDOMStorageIndexedDB
 //*****************************************************************************
 
 NS_IMETHODIMP
 nsGlobalWindow::GetMozIndexedDB(nsIIDBFactory** _retval)
 {
   if (!mIndexedDB) {
-    nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
-      do_GetService(THIRDPARTYUTIL_CONTRACTID);
-    NS_ENSURE_TRUE(thirdPartyUtil, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-    PRBool isThirdParty;
-    nsresult rv = thirdPartyUtil->IsThirdPartyWindow(this, nsnull,
-                                                     &isThirdParty);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-    if (isThirdParty) {
-      NS_WARNING("IndexedDB is not permitted in a third-party window.");
-      *_retval = nsnull;
-      return NS_OK;
+    if (!IsChromeWindow()) {
+      nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
+        do_GetService(THIRDPARTYUTIL_CONTRACTID);
+      NS_ENSURE_TRUE(thirdPartyUtil, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+      PRBool isThirdParty;
+      nsresult rv = thirdPartyUtil->IsThirdPartyWindow(this, nsnull,
+                                                       &isThirdParty);
+      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+      if (isThirdParty) {
+        NS_WARNING("IndexedDB is not permitted in a third-party window.");
+        *_retval = nsnull;
+        return NS_OK;
+      }
     }
 
     mIndexedDB = indexedDB::IDBFactory::Create(this);
     NS_ENSURE_TRUE(mIndexedDB, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 
   nsCOMPtr<nsIIDBFactory> request(mIndexedDB);
   request.forget(_retval);
--- a/dom/interfaces/css/nsIDOMCSS2Properties.idl
+++ b/dom/interfaces/css/nsIDOMCSS2Properties.idl
@@ -46,17 +46,17 @@
  * The nsIDOMCSS2Properties interface is a datatype for additional
  * reflection of data already provided in nsIDOMCSSStyleDeclaration in
  * the Document Object Model.
  *
  * For more information on this interface please see
  * http://www.w3.org/TR/DOM-Level-2-Style
  */
 
-[builtinclass, scriptable, uuid(10f43750-b379-11e0-aff2-0800200c9a66)]
+[builtinclass, scriptable, uuid(286466f1-4246-4574-afdb-2f8a03ad7cc8)]
 interface nsIDOMCSS2Properties : nsISupports
 {
            attribute DOMString        background;
                                         // raises(DOMException) on setting
 
            attribute DOMString        backgroundAttachment;
                                         // raises(DOMException) on setting
 
@@ -652,16 +652,19 @@ interface nsIDOMCSS2Properties : nsISupp
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozStackSizing;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozBorderImage;
                                         // raises(DOMException) on setting
 
+           attribute DOMString        MozColumns;
+                                        // raises(DOMException) on setting
+
            attribute DOMString        MozColumnRule;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozColumnRuleWidth;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozColumnRuleStyle;
                                         // raises(DOMException) on setting
--- a/dom/interfaces/events/nsIDOMMessageEvent.idl
+++ b/dom/interfaces/events/nsIDOMMessageEvent.idl
@@ -40,17 +40,17 @@
 
 /**
  * The nsIDOMMessageEvent interface is used for server-sent events and for
  * cross-domain messaging.
  *
  * For more information on this interface, please see
  * http://www.whatwg.org/specs/web-apps/current-work/#messageevent
  */
-[scriptable, uuid(dc8ec5c6-ebf2-4f95-be99-cd13e3c0d0c6)]
+[scriptable, uuid(9ac4fa26-4d19-4f4e-807e-b30cd0dbe56a)]
 interface nsIDOMMessageEvent : nsIDOMEvent
 {
   /**
    * Custom string data associated with this event.
    */
   [implicit_jscontext]
   readonly attribute jsval data;
   
--- a/dom/plugins/test/unit/xpcshell.ini
+++ b/dom/plugins/test/unit/xpcshell.ini
@@ -1,6 +1,10 @@
 [DEFAULT]
 head = head_plugins.js
 tail = 
 
 [test_bug455213.js]
+# Bug 676953: test fails consistently on Android
+fail-if = os == "android"
 [test_bug471245.js]
+# Bug 676953: test fails consistently on Android
+fail-if = os == "android"
--- a/embedding/android/GeckoApp.java
+++ b/embedding/android/GeckoApp.java
@@ -416,16 +416,17 @@ abstract public class GeckoApp
         GeckoAppShell.putChildInForeground();
         super.onRestart();
     }
 
     @Override
     public void onStart()
     {
         Log.i(LOG_FILE_NAME, "start");
+        GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_START));
         super.onStart();
     }
 
     @Override
     public void onDestroy()
     {
         Log.i(LOG_FILE_NAME, "destroy");
         // Tell Gecko to shutting down; we'll end up calling System.exit()
--- a/embedding/android/GeckoEvent.java
+++ b/embedding/android/GeckoEvent.java
@@ -67,16 +67,17 @@ public class GeckoEvent {
     public static final int SIZE_CHANGED = 8;
     public static final int ACTIVITY_STOPPING = 9;
     public static final int ACTIVITY_PAUSING = 10;
     public static final int ACTIVITY_SHUTDOWN = 11;
     public static final int LOAD_URI = 12;
     public static final int SURFACE_CREATED = 13;
     public static final int SURFACE_DESTROYED = 14;
     public static final int GECKO_EVENT_SYNC = 15;
+    public static final int ACTIVITY_START = 17;
 
     public static final int IME_COMPOSITION_END = 0;
     public static final int IME_COMPOSITION_BEGIN = 1;
     public static final int IME_SET_TEXT = 2;
     public static final int IME_GET_TEXT = 3;
     public static final int IME_DELETE_TEXT = 4;
     public static final int IME_SET_SELECTION = 5;
     public static final int IME_GET_SELECTION = 6;
--- a/embedding/android/GeckoSurfaceView.java
+++ b/embedding/android/GeckoSurfaceView.java
@@ -164,18 +164,40 @@ class GeckoSurfaceView
             if (c == null)
                 return;
             c.drawBitmap(bitmap, 0, 0, null);
             holder.unlockCanvasAndPost(c);
         }
     }
 
     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+
+        // Force exactly one frame to render
+        // because the surface change is only seen after we
+        // have swapped the back buffer.
+        // The buffer size only changes after the next swap buffer.
+        // We need to make sure the Gecko's view resize when Android's 
+        // buffer resizes.
+        if (mDrawMode == DRAW_GLES_2) {
+            // When we get a surfaceChange event, we have 0 to n paint events 
+            // waiting in the Gecko event queue. We will make the first
+            // succeed and the abort the others.
+            mDrawSingleFrame = true;
+            if (!mInDrawing) { 
+                // Queue at least one paint event in case none are queued.
+                GeckoAppShell.scheduleRedraw();
+            }
+            GeckoAppShell.geckoEventSync();
+            mDrawSingleFrame = false;
+            mAbortDraw = false;
+        }
+
         if (mShowingSplashScreen)
             drawSplashScreen(holder, width, height);
+
         mSurfaceLock.lock();
 
         try {
             if (mInDrawing) {
                 Log.w(LOG_FILE_NAME, "surfaceChanged while mInDrawing is true!");
             }
 
             boolean invalidSize;
@@ -216,16 +238,22 @@ class GeckoSurfaceView
                 c.drawARGB(255, 255, 255, 255);
                 holder.unlockCanvasAndPost(c);
                 return;
             } else {
                 GeckoAppShell.scheduleRedraw();
             }
         } finally {
             mSurfaceLock.unlock();
+            if (mDrawMode == DRAW_GLES_2) {
+                // Force a frame to be drawn before the surfaceChange returns,
+                // otherwise we get artifacts.
+                GeckoAppShell.scheduleRedraw();
+                GeckoAppShell.geckoEventSync();
+            }
         }
 
         Object syncDrawObject = null;
         try {
             syncDrawObject = mSyncDraws.take();
         } catch (InterruptedException ie) {
             Log.e(LOG_FILE_NAME, "Threw exception while getting sync draw bitmap/buffer: ", ie);
         }
@@ -288,23 +316,33 @@ class GeckoSurfaceView
 
     /*
      * Called on Gecko thread
      */
 
     public static final int DRAW_ERROR = 0;
     public static final int DRAW_GLES_2 = 1;
     public static final int DRAW_2D = 2;
+    // Drawing is disable when the surface buffer
+    // has changed size but we haven't yet processed the
+    // resize event.
+    public static final int DRAW_DISABLED = 3;
 
     public int beginDrawing() {
         if (mInDrawing) {
             Log.e(LOG_FILE_NAME, "Recursive beginDrawing call!");
             return DRAW_ERROR;
         }
 
+        // Once we drawn our first frame after resize we can ignore
+        // the other draw events until we handle the resize events.
+        if (mAbortDraw) {
+            return DRAW_DISABLED;
+        }
+
         /* Grab the lock, which we'll hold while we're drawing.
          * It gets released in endDrawing(), and is also used in surfaceChanged
          * to make sure that we don't change our surface details while
          * we're in the middle of drawing (and especially in the middle of
          * executing beginDrawing/endDrawing).
          *
          * We might not need to hold this lock in between
          * beginDrawing/endDrawing, and might just be able to make
@@ -325,16 +363,19 @@ class GeckoSurfaceView
     }
 
     public void endDrawing() {
         if (!mInDrawing) {
             Log.e(LOG_FILE_NAME, "endDrawing without beginDrawing!");
             return;
         }
 
+       if (mDrawSingleFrame)
+            mAbortDraw = true;
+
         try {
             if (!mSurfaceValid) {
                 Log.e(LOG_FILE_NAME, "endDrawing with false mSurfaceValid");
                 return;
             }
         } finally {
             mInDrawing = false;
 
@@ -652,16 +693,20 @@ class GeckoSurfaceView
     }
 
     // Is this surface valid for drawing into?
     boolean mSurfaceValid;
 
     // Are we actively between beginDrawing/endDrawing?
     boolean mInDrawing;
 
+    // Used to finish the current buffer before changing the surface size
+    boolean mDrawSingleFrame = false;
+    boolean mAbortDraw = false;
+
     // Are we waiting for a buffer to draw in surfaceChanged?
     boolean mSyncDraw;
 
     // True if gecko requests a buffer
     int mDrawMode;
 
     static boolean mShowingSplashScreen = true;
     static String  mSplashStatusMsg = "";
--- a/embedding/tests/unit/xpcshell.ini
+++ b/embedding/tests/unit/xpcshell.ini
@@ -1,6 +1,10 @@
 [DEFAULT]
 head = 
 tail = 
 
 [test_wwauthpromptfactory.js]
+# Bug 676955: test fails consistently on Android
+fail-if = os == "android"
 [test_wwpromptfactory.js]
+# Bug 676955: test fails consistently on Android
+fail-if = os == "android"
--- a/extensions/pref/system-pref/src/gconf/nsSystemPrefService.cpp
+++ b/extensions/pref/system-pref/src/gconf/nsSystemPrefService.cpp
@@ -280,17 +280,17 @@ NS_IMETHODIMP nsSystemPrefService::GetPr
 /* boolean getBoolPref (in string aPrefName); */
 NS_IMETHODIMP nsSystemPrefService::GetBoolPref(const char *aPrefName, PRBool *_retval)
 {
     return mInitialized ?
         mGConf->GetBoolPref(aPrefName, _retval) : NS_ERROR_FAILURE;
 }
 
 /* void setBoolPref (in string aPrefName, in long aValue); */
-NS_IMETHODIMP nsSystemPrefService::SetBoolPref(const char *aPrefName, PRInt32 aValue)
+NS_IMETHODIMP nsSystemPrefService::SetBoolPref(const char *aPrefName, PRBool aValue)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /* string getCharPref (in string aPrefName); */
 NS_IMETHODIMP nsSystemPrefService::GetCharPref(const char *aPrefName, char **_retval)
 {
     return mInitialized ?
--- a/extensions/spellcheck/src/mozSpellChecker.cpp
+++ b/extensions/spellcheck/src/mozSpellChecker.cpp
@@ -36,20 +36,16 @@
 
 #include "mozSpellChecker.h"
 #include "nsIServiceManager.h"
 #include "mozISpellI18NManager.h"
 #include "nsIStringEnumerator.h"
 #include "nsICategoryManager.h"
 #include "nsISupportsPrimitives.h"
 
-// The number 130 more or less comes out of thin air.
-// See https://bugzilla.mozilla.org/show_bug.cgi?id=355178#c78 for a pseudo-rationale.
-#define UNREASONABLE_WORD_LENGTH 130
-
 #define DEFAULT_SPELL_CHECKER "@mozilla.org/spellchecker/engine;1"
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(mozSpellChecker)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(mozSpellChecker)
 
 NS_INTERFACE_MAP_BEGIN(mozSpellChecker)
   NS_INTERFACE_MAP_ENTRY(nsISpellChecker)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISpellChecker)
@@ -144,22 +140,16 @@ mozSpellChecker::NextMisspelledWord(nsAS
 NS_IMETHODIMP 
 mozSpellChecker::CheckWord(const nsAString &aWord, PRBool *aIsMisspelled, nsTArray<nsString> *aSuggestions)
 {
   nsresult result;
   PRBool correct;
   if(!mSpellCheckingEngine)
     return NS_ERROR_NULL_POINTER;
 
-  // don't bother to check crazy words
-  if (aWord.Length() > UNREASONABLE_WORD_LENGTH) {
-    *aIsMisspelled = PR_TRUE;
-    return NS_OK;
-  }
-
   *aIsMisspelled = PR_FALSE;
   result = mSpellCheckingEngine->Check(PromiseFlatString(aWord).get(), &correct);
   NS_ENSURE_SUCCESS(result, result);
   if(!correct){
     if(aSuggestions){
       PRUint32 count,i;
       PRUnichar **words;
       
--- a/intl/uconv/tests/unit/xpcshell.ini
+++ b/intl/uconv/tests/unit/xpcshell.ini
@@ -106,16 +106,18 @@ tail =
 [test_encode_CP1255.js]
 [test_encode_CP1256.js]
 [test_encode_CP1257.js]
 [test_encode_CP1258.js]
 [test_encode_CP850.js]
 [test_encode_CP852.js]
 [test_encode_CP855.js]
 [test_encode_CP857.js]
+# Bug 676958: test consistently hangs on Android
+skip-if = os == "android"
 [test_encode_CP862.js]
 [test_encode_CP864.js]
 [test_encode_CP874.js]
 [test_encode_armscii.js]
 [test_encode_geostd8.js]
 [test_encode_gbk.js]
 [test_encode_tcvn5712.js]
 [test_encode_utf-7_internal.js]
--- a/ipc/testshell/tests/xpcshell.ini
+++ b/ipc/testshell/tests/xpcshell.ini
@@ -1,6 +1,8 @@
 [DEFAULT]
 head = 
 tail = 
 
 [test_ipcshell.js]
+# Bug 676963: test fails consistently on Android
+fail-if = os == "android"
 [test_ipcshell_child.js]
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -72,16 +72,46 @@ endif
 
 MODULE		    = js
 LIBRARY_NAME	    = mozjs
 STATIC_LIBRARY_NAME = js_static
 GRE_MODULE	    = 1
 
 LIBS		= $(NSPR_LIBS) 
 
+ifdef GNU_CXX
+ifdef INTEL_CXX
+# icc gets special optimize flags
+ifdef MOZ_PROFILE_GENERATE
+MODULE_OPTIMIZE_FLAGS = -O0
+else
+MODULE_OPTIMIZE_FLAGS = -O2 -ip
+endif
+else # not INTEL_CXX
+
+MODULE_OPTIMIZE_FLAGS = -O3 -fstrict-aliasing -fno-stack-protector
+
+# We normally want -fomit-frame-pointer, but we want an explicit
+# -fno-omit-frame-pointer if we're using a sampling profiler.
+ifndef MOZ_PROFILING
+MODULE_OPTIMIZE_FLAGS += -fomit-frame-pointer
+else
+MODULE_OPTIMIZE_FLAGS += -fno-omit-frame-pointer
+endif
+
+endif
+else # not GNU_CXX
+ifeq ($(OS_ARCH),SunOS)
+MODULE_OPTIMIZE_FLAGS = -xO4
+endif
+ifeq ($(OS_ARCH),WINNT)
+MODULE_OPTIMIZE_FLAGS = -O2
+endif
+endif
+
 ifeq ($(OS_ARCH),WINNT)
 NO_PROFILE_GUIDED_OPTIMIZE = 1
 endif
 
 # JavaScript must be built shared, even for static builds, as it is used by
 # other modules which are always built shared. Failure to do so results in
 # the js code getting copied into xpinstall and jsd as well as mozilla-bin,
 # and then the static data cells used for locking no longer work.
--- a/js/src/config/autoconf.mk.in
+++ b/js/src/config/autoconf.mk.in
@@ -38,17 +38,16 @@
 
 # A netscape style .mk file for autoconf builds
 
 INCLUDED_AUTOCONF_MK = 1
 USE_AUTOCONF 	= 1
 MOZILLA_CLIENT	= 1
 target          = @target@
 ac_configure_args = @ac_configure_args@
-BUILD_MODULES	= @BUILD_MODULES@
 MOZILLA_VERSION = @MOZILLA_VERSION@
 
 MOZ_BUILD_APP = @MOZ_BUILD_APP@
 MOZ_APP_NAME	= @MOZ_APP_NAME@
 MOZ_APP_DISPLAYNAME = @MOZ_APP_DISPLAYNAME@
 MOZ_APP_VERSION = @MOZ_APP_VERSION@
 
 MOZ_PKG_SPECIAL = @MOZ_PKG_SPECIAL@
--- a/js/src/config/nsinstall_win.c
+++ b/js/src/config/nsinstall_win.c
@@ -36,16 +36,48 @@ static const char *sh_GetLastErrorMessag
 static BOOL sh_DoCopy(wchar_t *srcFileName, DWORD srcFileAttributes,
         wchar_t *dstFileName, DWORD dstFileAttributes,
         int force, int recursive);
 
 #define LONGPATH_PREFIX L"\\\\?\\"
 #define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
 #define STR_LEN(a) (ARRAY_LEN(a) - 1)
 
+#ifdef __MINGW32__
+
+/* MingW currently does not implement a wide version of the
+   startup routines.  Workaround is to implement something like
+   it ourselves. */
+
+#include <shellapi.h>
+
+int wmain(int argc, WCHAR **argv);
+
+int main(int argc, char **argv)
+{
+    int result;
+    wchar_t *commandLine = GetCommandLineW();
+    int argcw = 0;
+    wchar_t **_argvw = CommandLineToArgvW( commandLine, &argcw );
+    wchar_t *argvw[argcw + 1];
+    int i;
+    if (!_argvw)
+        return 127;
+    /* CommandLineToArgvW doesn't output the ending NULL so
+       we have to manually add it on */
+    for ( i = 0; i < argcw; i++ )
+        argvw[i] = _argvw[i];
+    argvw[argcw] = NULL;
+
+    result = wmain(argcw, argvw);
+    LocalFree(_argvw);
+    return result;
+}
+#endif /* __MINGW32__ */
+
 /* changes all forward slashes in token to backslashes */
 void changeForwardSlashesToBackSlashes ( wchar_t *arg )
 {
     if ( arg == NULL )
         return;
 
     while ( *arg ) {
         if ( *arg == '/' )
--- a/js/src/config/rules.mk
+++ b/js/src/config/rules.mk
@@ -148,16 +148,30 @@ xpcshell-tests:
 	  -I$(topsrcdir)/build \
 	  $(testxpcsrcdir)/runxpcshelltests.py \
 	  --symbols-path=$(DIST)/crashreporter-symbols \
 	  --build-info-json=$(DEPTH)/mozinfo.json \
 	  $(EXTRA_TEST_ARGS) \
 	  $(LIBXUL_DIST)/bin/xpcshell \
 	  $(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
 
+xpcshell-tests-remote: DM_TRANS?=adb
+xpcshell-tests-remote:
+	$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
+	  -I$(topsrcdir)/build \
+	  -I$(topsrcdir)/build/mobile \
+	  $(topsrcdir)/testing/xpcshell/remotexpcshelltests.py \
+	  --symbols-path=$(DIST)/crashreporter-symbols \
+	  --build-info-json=$(DEPTH)/mozinfo.json \
+	  $(EXTRA_TEST_ARGS) \
+	  --dm_trans=$(DM_TRANS) \
+	  --deviceIP=${TEST_DEVICE} \
+	  --objdir=$(DEPTH) \
+	  $(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
+
 # Execute a single test, specified in $(SOLO_FILE), but don't automatically
 # start the test. Instead, present the xpcshell prompt so the user can
 # attach a debugger and then start the test.
 check-interactive:
 	$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
 	  -I$(topsrcdir)/build \
 	  $(testxpcsrcdir)/runxpcshelltests.py \
 	  --symbols-path=$(DIST)/crashreporter-symbols \
@@ -177,16 +191,33 @@ check-one:
 	  --build-info-json=$(DEPTH)/mozinfo.json \
 	  --test-path=$(SOLO_FILE) \
 	  --profile-name=$(MOZ_APP_NAME) \
 	  --verbose \
 	  $(EXTRA_TEST_ARGS) \
 	  $(LIBXUL_DIST)/bin/xpcshell \
 	  $(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
 
+check-one-remote: DM_TRANS?=adb
+check-one-remote:
+	$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
+	  -I$(topsrcdir)/build \
+	  -I$(topsrcdir)/build/mobile \
+	  $(testxpcsrcdir)/remotexpcshelltests.py \
+	  --symbols-path=$(DIST)/crashreporter-symbols \
+	  --build-info-json=$(DEPTH)/mozinfo.json \
+	  --test-path=$(SOLO_FILE) \
+	  --profile-name=$(MOZ_APP_NAME) \
+	  --verbose \
+	  $(EXTRA_TEST_ARGS) \
+	  --dm_trans=$(DM_TRANS) \
+	  --deviceIP=${TEST_DEVICE} \
+	  --objdir=$(DEPTH) \
+          --noSetup \
+	  $(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
 endif # XPCSHELL_TESTS
 
 ifdef CPP_UNIT_TESTS
 
 # Compile the tests to $(DIST)/bin.  Make lots of niceties available by default
 # through TestHarness.h, by modifying the list of includes and the libs against
 # which stuff links.
 CPPSRCS += $(CPP_UNIT_TESTS)
@@ -1117,18 +1148,19 @@ endif # OS/2
 	$(RM) $@
 	$(HOST_AR) $(HOST_AR_FLAGS) $(HOST_OBJS)
 	$(HOST_RANLIB) $@
 
 ifdef HAVE_DTRACE
 ifndef XP_MACOSX
 ifdef DTRACE_PROBE_OBJ
 ifndef DTRACE_LIB_DEPENDENT
-$(DTRACE_PROBE_OBJ):
-	dtrace -G -C -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ)
+NON_DTRACE_OBJS := $(filter-out $(DTRACE_PROBE_OBJ),$(OBJS))
+$(DTRACE_PROBE_OBJ): $(NON_DTRACE_OBJS)
+	dtrace -G -C -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ) $(NON_DTRACE_OBJS)
 endif
 endif
 endif
 endif
 
 # On Darwin (Mac OS X), dwarf2 debugging uses debug info left in .o files,
 # so instead of deleting .o files after repacking them into a dylib, we make
 # symlinks back to the originals. The symlinks are a no-op for stabs debugging,
@@ -1514,19 +1546,16 @@ ifeq ($(XPIDL_MODULE),) # we need $(XPID
 export:: FORCE
 	@echo
 	@echo "*** Error processing XPIDLSRCS:"
 	@echo "Please define MODULE or XPIDL_MODULE when defining XPIDLSRCS,"
 	@echo "so we have a module name to use when creating MODULE.xpt."
 	@echo; sleep 2; false
 endif
 
-$(IDL_DIR)::
-	$(NSINSTALL) -D $@
-
 # generate .h files from into $(XPIDL_GEN_DIR), then export to $(DIST)/include;
 # warn against overriding existing .h file. 
 $(XPIDL_GEN_DIR)/.done:
 	$(MKDIR) -p $(XPIDL_GEN_DIR)
 	@$(TOUCH) $@
 
 # don't depend on $(XPIDL_GEN_DIR), because the modification date changes
 # with any addition to the directory, regenerating all .h files -> everything.
@@ -1587,24 +1616,18 @@ export:: $(XPIDLSRCS) $(IDL_DIR)
 export:: $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.h, $(XPIDLSRCS)) $(DIST)/include
 	$(INSTALL) $(IFLAGS1) $^ 
 endif # NO_DIST_INSTALL
 
 endif # XPIDLSRCS
 
 
 
-#
 # General rules for exporting idl files.
-#
-# WORK-AROUND ONLY, for mozilla/tools/module-deps/bootstrap.pl build.
-# Bug to fix idl dependency problems w/o this extra build pass is
-#   http://bugzilla.mozilla.org/show_bug.cgi?id=145777
-#
-$(IDL_DIR)::
+$(IDL_DIR):
 	$(NSINSTALL) -D $@
 
 export-idl:: $(SUBMAKEFILES) $(MAKE_DIRS)
 
 ifneq ($(XPIDLSRCS),)
 ifndef NO_DIST_INSTALL
 export-idl:: $(XPIDLSRCS) $(IDL_DIR)
 	$(INSTALL) $(IFLAGS1) $^
@@ -2061,17 +2084,16 @@ showhost:
 	@echo "HOST_EXTRA_LIBS    = $(HOST_EXTRA_LIBS)"
 	@echo "HOST_EXTRA_DEPS    = $(HOST_EXTRA_DEPS)"
 	@echo "HOST_PROGRAM       = $(HOST_PROGRAM)"
 	@echo "HOST_OBJS          = $(HOST_OBJS)"
 	@echo "HOST_PROGOBJS      = $(HOST_PROGOBJS)"
 	@echo "HOST_LIBRARY       = $(HOST_LIBRARY)"
 
 showbuildmods::
-	@echo "Build Modules	= $(BUILD_MODULES)"
 	@echo "Module dirs	= $(BUILD_MODULE_DIRS)"
 
 documentation:
 	@cd $(DEPTH)
 	$(DOXYGEN) $(DEPTH)/config/doxygen.cfg
 
 ifdef ENABLE_TESTS
 check:: $(SUBMAKEFILES) $(MAKE_DIRS)
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -1987,24 +1987,21 @@ case "$target" in
 	    MKSHLIB_UNFORCE_ALL=''
 	;;
     esac
     ;;
 
 *-darwin*) 
     MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@'
     MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@'
-
-    MOZ_OPTIMIZE_FLAGS="-O3  -fstrict-aliasing -fno-stack-protector"
-    # We normally want -fomit-frame-pointer, but we want an explicit
-    # -fno-omit-frame-pointer if we're using a sampling profiler.
+    # If we're building with --enable-profiling, we need a frame pointer.
     if test -z "$MOZ_PROFILING"; then
-        MOZ_OPTIMIZE_FLAGS="$MOZ_OPTIMIZE_FLAGS -fomit-frame-pointer"
+        MOZ_OPTIMIZE_FLAGS="-O3 -fomit-frame-pointer"
     else
-        MOZ_OPTIMIZE_FLAGS="$MOZ_OPTIMIZE_FLAGS -fno-omit-frame-pointer"
+        MOZ_OPTIMIZE_FLAGS="-O3 -fno-omit-frame-pointer"
     fi
     _PEDANTIC=
     CFLAGS="$CFLAGS -fpascal-strings -fno-common"
     CXXFLAGS="$CXXFLAGS -fpascal-strings -fno-common"
     DLL_SUFFIX=".dylib"
     DSO_LDOPTS=''
     STRIP="$STRIP -x -S"
     _PLATFORM_DEFAULT_TOOLKIT='cairo-cocoa'
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -2558,16 +2558,17 @@ js_CloneFunctionObject(JSContext *cx, JS
         clone->setPrivate(cfun);
         if (cfun->isInterpreted()) {
             JSScript *script = cfun->script();
             JS_ASSERT(script);
             JS_ASSERT(script->compartment == fun->compartment());
             JS_ASSERT(script->compartment != cx->compartment);
             JS_OPT_ASSERT(script->ownerObject == fun);
 
+            cfun->u.i.script = NULL;
             JSScript *cscript = js_CloneScript(cx, script);
             if (!cscript)
                 return NULL;
 
             cfun->u.i.script = cscript;
             if (!cfun->u.i.script->typeSetFunction(cx, cfun))
                 return NULL;
 
--- a/js/src/xpconnect/shell/xpcshell.cpp
+++ b/js/src/xpconnect/shell/xpcshell.cpp
@@ -1834,17 +1834,19 @@ main(int argc, char **argv, char **envp)
         if (argc > 1 && !strcmp(argv[1], "--greomni")) {
             nsCOMPtr<nsILocalFile> greOmni;
             nsCOMPtr<nsILocalFile> appOmni;
             XRE_GetFileFromPath(argv[2], getter_AddRefs(greOmni));
             if (argc > 3 && !strcmp(argv[3], "--appomni")) {
                 XRE_GetFileFromPath(argv[4], getter_AddRefs(appOmni));
                 argc-=2;
                 argv+=2;
-            } 
+            } else {
+                appOmni = greOmni;
+            }
             
             XRE_InitOmnijar(greOmni, appOmni);
             argc-=2;
             argv+=2;
         }
 
         nsCOMPtr<nsIServiceManager> servMan;
         rv = NS_InitXPCOM2(getter_AddRefs(servMan), appDir, &dirprovider);
--- a/js/src/xpconnect/src/Makefile.in
+++ b/js/src/xpconnect/src/Makefile.in
@@ -41,27 +41,18 @@ DEPTH		= ../../../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= xpconnect
 
-ifeq (xpconnect, $(findstring xpconnect, $(BUILD_MODULES)))
-LIBRARY_NAME	= xpconnect
-EXPORT_LIBRARY = 1
-SHORT_LIBNAME	= xpconect
-IS_COMPONENT	= 1
-MODULE_NAME	= xpconnect
-GRE_MODULE	= 1
-else
 LIBRARY_NAME    = xpconnect_s
 FORCE_STATIC_LIB = 1
-endif
 LIBXUL_LIBRARY = 1
 EXPORTS = xpcpublic.h
 
 CPPSRCS		= \
 		nsScriptError.cpp \
 		nsXPConnect.cpp \
 		xpccallcontext.cpp \
 		xpccomponents.cpp \
--- a/js/src/xpconnect/src/nsXPConnect.cpp
+++ b/js/src/xpconnect/src/nsXPConnect.cpp
@@ -2069,17 +2069,18 @@ nsXPConnect::CreateSandbox(JSContext *cx
     if(!ccx.IsValid())
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     *_retval = nsnull;
 
     jsval rval = JSVAL_VOID;
     AUTO_MARK_JSVAL(ccx, &rval);
 
-    nsresult rv = xpc_CreateSandboxObject(cx, &rval, principal, NULL, false);
+    nsresult rv = xpc_CreateSandboxObject(cx, &rval, principal, NULL, false, 
+                                          EmptyCString());
     NS_ASSERTION(NS_FAILED(rv) || !JSVAL_IS_PRIMITIVE(rval),
                  "Bad return value from xpc_CreateSandboxObject()!");
 
     if (NS_SUCCEEDED(rv) && !JSVAL_IS_PRIMITIVE(rval)) {
         *_retval = XPCJSObjectHolder::newHolder(ccx, JSVAL_TO_OBJECT(rval));
         NS_ENSURE_TRUE(*_retval, NS_ERROR_OUT_OF_MEMORY);
 
         NS_ADDREF(*_retval);
--- a/js/src/xpconnect/src/xpccomponents.cpp
+++ b/js/src/xpconnect/src/xpccomponents.cpp
@@ -3148,17 +3148,17 @@ class Identity : public nsISupports
 {
     NS_DECL_ISUPPORTS
 };
 
 NS_IMPL_ISUPPORTS0(Identity)
 
 nsresult
 xpc_CreateSandboxObject(JSContext * cx, jsval * vp, nsISupports *prinOrSop, JSObject *proto,
-                        bool wantXrays)
+                        bool wantXrays, const nsACString &sandboxName)
 {
     // Create the sandbox global object
     nsresult rv;
     nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
     if(NS_FAILED(rv))
         return NS_ERROR_XPC_UNEXPECTED;
 
     nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(prinOrSop));
@@ -3235,16 +3235,20 @@ xpc_CreateSandboxObject(JSContext * cx, 
 
     if (vp) {
         *vp = OBJECT_TO_JSVAL(sandbox);
         if (!WrapForSandbox(cx, wantXrays, vp)) {
             return NS_ERROR_UNEXPECTED;
         }
     }
 
+    xpc::CompartmentPrivate *compartmentPrivate =
+        static_cast<xpc::CompartmentPrivate*>(JS_GetCompartmentPrivate(cx, compartment));
+    compartmentPrivate->location = sandboxName;
+
     return NS_OK;
 }
 
 /* PRBool call(in nsIXPConnectWrappedNative wrapper,
                in JSContextPtr cx,
                in JSObjectPtr obj,
                in PRUint32 argc,
                in JSValPtr argv,
@@ -3346,16 +3350,18 @@ nsXPCComponents_utils_Sandbox::CallOrCon
         }
 
         if (!prinOrSop)
             return ThrowAndFail(NS_ERROR_INVALID_ARG, cx, _retval);
     }
 
     JSObject *proto = nsnull;
     bool wantXrays = true;
+    nsCString sandboxName;
+
     if (argc > 1) {
         if (!JSVAL_IS_OBJECT(argv[1]))
             return ThrowAndFail(NS_ERROR_INVALID_ARG, cx, _retval);
 
         JSObject *optionsObject = JSVAL_TO_OBJECT(argv[1]);
         jsval option;
 
         JSBool found;
@@ -3377,19 +3383,36 @@ nsXPCComponents_utils_Sandbox::CallOrCon
         if (found) {
             if (!JS_GetProperty(cx, optionsObject, "wantXrays", &option) ||
                 !JSVAL_IS_BOOLEAN(option)) {
                 return ThrowAndFail(NS_ERROR_INVALID_ARG, cx, _retval);
             }
 
             wantXrays = JSVAL_TO_BOOLEAN(option);
         }
+
+        if (!JS_HasProperty(cx, optionsObject, "sandboxName", &found))
+            return NS_ERROR_INVALID_ARG;
+
+        if (found) {
+            if (!JS_GetProperty(cx, optionsObject, "sandboxName", &option) ||
+                !JSVAL_IS_STRING(option)) {
+                return ThrowAndFail(NS_ERROR_INVALID_ARG, cx, _retval);
+            }
+
+            char *tmp = JS_EncodeString(cx, JSVAL_TO_STRING(option));
+            if (!tmp) {
+                return ThrowAndFail(NS_ERROR_INVALID_ARG, cx, _retval);
+            }
+
+            sandboxName.Adopt(tmp, strlen(tmp));
+        }
     }
 
-    rv = xpc_CreateSandboxObject(cx, vp, prinOrSop, proto, wantXrays);
+    rv = xpc_CreateSandboxObject(cx, vp, prinOrSop, proto, wantXrays, sandboxName);
 
     if (NS_FAILED(rv)) {
         return ThrowAndFail(rv, cx, _retval);
     }
 
     *_retval = PR_TRUE;
 
     return rv;
--- a/js/src/xpconnect/src/xpcjsruntime.cpp
+++ b/js/src/xpconnect/src/xpcjsruntime.cpp
@@ -1579,32 +1579,40 @@ CompartmentStats::CompartmentStats(JSCon
     if(c == cx->runtime->atomsCompartment)
     {
         name.AssignLiteral("atoms");
     }
     else if(c->principals)
     {
         if(c->principals->codebase)
         {
-            // A hack: replace forward slashes with '\\' so they aren't
-            // treated as path separators.  Users of the reporters
-            // (such as about:memory) have to undo this change.
             name.Assign(c->principals->codebase);
-            name.ReplaceChar('/', '\\');
 
             // If it's the system compartment, append the address.
             // This means that multiple system compartments (and there
             // can be many) can be distinguished.
             if(c->isSystemCompartment)
             {
+                if (c->data && 
+                    !((xpc::CompartmentPrivate*)c->data)->location.IsEmpty())
+                {
+                    name.AppendLiteral(", ");
+                    name.Append(((xpc::CompartmentPrivate*)c->data)->location);
+                }
+
                 // ample; 64-bit address max is 18 chars
                 static const int maxLength = 31;
                 nsPrintfCString address(maxLength, ", 0x%llx", PRUint64(c));
                 name.Append(address);
             }
+
+            // A hack: replace forward slashes with '\\' so they aren't
+            // treated as path separators.  Users of the reporters
+            // (such as about:memory) have to undo this change.
+            name.ReplaceChar('/', '\\');
         }
         else
         {
             name.AssignLiteral("null-codebase");
         }
     }
     else
     {
--- a/js/src/xpconnect/src/xpcprivate.h
+++ b/js/src/xpconnect/src/xpcprivate.h
@@ -4310,17 +4310,17 @@ xpc_GetJSPrivate(JSObject *obj)
 // do setup etc on, puts the sandbox object in *vp (which must be
 // rooted by the caller), and uses the principal that's either
 // directly passed in prinOrSop or indirectly as an
 // nsIScriptObjectPrincipal holding the principal. If no principal is
 // reachable through prinOrSop, a new null principal will be created
 // and used.
 nsresult
 xpc_CreateSandboxObject(JSContext * cx, jsval * vp, nsISupports *prinOrSop,
-                        JSObject *proto, bool preferXray);
+                        JSObject *proto, bool preferXray, const nsACString &sandboxName);
 
 // Helper for evaluating scripts in a sandbox object created with
 // xpc_CreateSandboxObject(). The caller is responsible of ensuring
 // that *rval doesn't get collected during the call or usage after the
 // call. This helper will use filename and lineNo for error reporting,
 // and if no filename is provided it will use the codebase from the
 // principal and line number 1 as a fallback. if returnStringOnly is
 // true, then the result in *rval, or the exception in cx->exception
@@ -4391,16 +4391,17 @@ struct CompartmentPrivate
     // NB: key and ptr are mutually exclusive.
     nsAutoPtr<PtrAndPrincipalHashKey> key;
     nsCOMPtr<nsISupports> ptr;
     bool wantXrays;
     bool cycleCollectionEnabled;
     JSObject2JSObjectMap *waiverWrapperMap;
     // NB: we don't want this map to hold a strong reference to the wrapper.
     nsDataHashtable<nsPtrHashKey<XPCWrappedNative>, JSObject *> *expandoMap;
+    nsCString location;
 
     bool RegisterExpandoObject(XPCWrappedNative *wn, JSObject *expando) {
         if (!expandoMap) {
             expandoMap = new nsDataHashtable<nsPtrHashKey<XPCWrappedNative>, JSObject *>();
             if (!expandoMap->Init(8))
                 return false;
         }
         return expandoMap->Put(wn, expando);
--- a/js/src/xpconnect/tests/unit/xpcshell.ini
+++ b/js/src/xpconnect/tests/unit/xpcshell.ini
@@ -10,11 +10,13 @@ tail =
 [test_bug608142.js]
 [test_bug641378.js]
 [test_bug677864.js]
 [test_bug_442086.js]
 [test_file.js]
 [test_import.js]
 [test_js_weak_references.js]
 [test_localeCompare.js]
+# Bug 676965: test fails consistently on Android
+fail-if = os == "android"
 [test_recursive_import.js]
 [test_xpcomutils.js]
 [test_unload.js]
--- a/layout/base/nsPresArena.cpp
+++ b/layout/base/nsPresArena.cpp
@@ -78,21 +78,17 @@
 #   define MAP_ANON MAP_ANONYMOUS
 #  else
 #   error "Don't know how to get anonymous memory"
 #  endif
 # endif
 #endif
 
 // Size to use for PLArena block allocations.
-// XXX: This should be 8192;  the subtracted elements are a hack that's
-// required to ensure the allocation requests are power-of-two-sized and thus
-// avoid lots of wasted memory caused by the heap allocator rounding up request
-// sizes.  Bug 676457 will fix it properly.
-static const size_t ARENA_PAGE_SIZE = 8192 - sizeof(PLArena) - PL_ARENA_CONST_ALIGN_MASK;
+static const size_t ARENA_PAGE_SIZE = 8192;
 
 // Freed memory is filled with a poison value, which we arrange to
 // form a pointer either to an always-unmapped region of the address
 // space, or to a page that has been reserved and rendered
 // inaccessible via OS primitives.  See tests/TestPoisonArea.cpp for
 // extensive discussion of the requirements for this page.  The code
 // from here to 'class FreeList' needs to be kept in sync with that
 // file.
--- a/layout/base/tests/bug613433-1.html
+++ b/layout/base/tests/bug613433-1.html
@@ -7,18 +7,18 @@
         overflow-x: auto;
       }
     </style>
     <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
     <script>
       function test() {
         document.querySelector("div").focus();
         // type a character, then press backspace to delete it
-        sendKey("X", window);
-        sendKey("BACK_SPACE", window);
+        sendKey("X", "div1");
+        sendKey("BACK_SPACE", "div1");
         document.documentElement.removeAttribute("class");
       }
     </script>
   </head>
   <body onload="test()">
-    <div contenteditable></div>
+    <div id="div1" contenteditable></div>
   </body>
 </html>
--- a/layout/base/tests/bug613433-2.html
+++ b/layout/base/tests/bug613433-2.html
@@ -7,18 +7,18 @@
         overflow-y: auto;
       }
     </style>
     <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
     <script>
       function test() {
         document.querySelector("div").focus();
         // type a character, then press backspace to delete it
-        sendKey("X", window);
-        sendKey("BACK_SPACE", window);
+        sendKey("X", "div1");
+        sendKey("BACK_SPACE", "div1");
         document.documentElement.removeAttribute("class");
       }
     </script>
   </head>
   <body onload="test()">
-    <div contenteditable></div>
+    <div id="div1" contenteditable></div>
   </body>
 </html>
--- a/layout/base/tests/bug613433-3.html
+++ b/layout/base/tests/bug613433-3.html
@@ -7,18 +7,18 @@
         overflow: auto;
       }
     </style>
     <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
     <script>
       function test() {
         document.querySelector("div").focus();
         // type a character, then press backspace to delete it
-        sendKey("X", window);
-        sendKey("BACK_SPACE", window);
+        sendKey("X", "div1");
+        sendKey("BACK_SPACE", "div1");
         document.documentElement.removeAttribute("class");
       }
     </script>
   </head>
   <body onload="test()">
-    <div contenteditable></div>
+    <div id="div1" contenteditable></div>
   </body>
 </html>
--- a/layout/forms/nsProgressFrame.cpp
+++ b/layout/forms/nsProgressFrame.cpp
@@ -244,16 +244,17 @@ nsProgressFrame::AttributeChanged(PRInt3
   NS_ASSERTION(mBarDiv, "Progress bar div must exist!");
 
   if (aNameSpaceID == kNameSpaceID_None &&
       (aAttribute == nsGkAtoms::value || aAttribute == nsGkAtoms::max)) {
     nsIFrame* barFrame = mBarDiv->GetPrimaryFrame();
     NS_ASSERTION(barFrame, "The progress frame should have a child with a frame!");
     PresContext()->PresShell()->FrameNeedsReflow(barFrame, nsIPresShell::eResize,
                                                  NS_FRAME_IS_DIRTY);
+    Invalidate(GetVisualOverflowRectRelativeToSelf());
   }
 
   return nsHTMLContainerFrame::AttributeChanged(aNameSpaceID, aAttribute,
                                                 aModType);
 }
 
 nsSize
 nsProgressFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
@@ -273,16 +274,38 @@ nsProgressFrame::ComputeAutoSize(nsRende
     autoSize.height *= 10; // 10em
   } else {
     autoSize.width *= 10; // 10em
   }
 
   return autoSize;
 }
 
+nscoord
+nsProgressFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
+{
+  nsRefPtr<nsFontMetrics> fontMet;
+  NS_ENSURE_SUCCESS(
+      nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fontMet)), 0);
+
+  nscoord minWidth = fontMet->Font().size; // 1em
+
+  if (GetStyleDisplay()->mOrient == NS_STYLE_ORIENT_HORIZONTAL) {
+    minWidth *= 10; // 10em
+  }
+
+  return minWidth;
+}
+
+nscoord
+nsProgressFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
+{
+  return GetMinWidth(aRenderingContext);
+}
+
 bool
 nsProgressFrame::ShouldUseNativeStyle() const
 {
   // Use the native style if these conditions are satisfied:
   // - both frames use the native appearance;
   // - neither frame has author specified rules setting the border or the
   //   background.
   return GetStyleDisplay()->mAppearance == NS_THEME_PROGRESSBAR &&
--- a/layout/forms/nsProgressFrame.h
+++ b/layout/forms/nsProgressFrame.h
@@ -79,16 +79,19 @@ public:
                               nsIAtom* aAttribute,
                               PRInt32  aModType);
 
   virtual nsSize ComputeAutoSize(nsRenderingContext *aRenderingContext,
                                  nsSize aCBSize, nscoord aAvailableWidth,
                                  nsSize aMargin, nsSize aBorder,
                                  nsSize aPadding, PRBool aShrinkWrap);
 
+  virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext);
+  virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext);
+
   virtual PRBool IsFrameOfType(PRUint32 aFlags) const
   {
     return nsHTMLContainerFrame::IsFrameOfType(aFlags &
       ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
   }
 
   /**
    * Returns whether the frame and its child should use the native style.
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/progress/block-invalidate-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <style>
+    progress { display: block; }
+  </style>
+  <body>
+    <progress value='0.5'></progress>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/progress/block-invalidate.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <style>
+    progress { display: block; }
+  </style>
+  <script>
+    function loadHandler() {
+      setTimeout(function() {
+        var p = document.getElementsByTagName('progress')[0];
+        p.value = '0.5';
+        document.documentElement.className = '';
+      }, 0);
+    }
+  </script>
+  <body onload="loadHandler();">
+    <progress value='0'></progress>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/progress/in-cells-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <style>
+    progress { width: 10em; height: 1em; }
+    progress.vertical { -moz-orient: vertical; width: 1em; height: 10em; }
+  </style>
+  <body>
+    <table>
+      <tr>
+        <td>foo</td>
+        <td><progress value='0.5'></td>
+        <td>bar</td>
+      </tr>
+      <tr>
+        <td>foo</td>
+        <td><progress class='vertical' value='0.5'></td>
+        <td>bar</td>
+      </tr>
+    </table>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/progress/in-cells.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <style>
+    progress.vertical { -moz-orient: vertical; }
+  </style>
+  <body>
+    <table>
+      <tr>
+        <td>foo</td>
+        <td><progress value='0.5'></td>
+        <td>bar</td>
+      </tr>
+      <tr>
+        <td>foo</td>
+        <td><progress class='vertical' value='0.5'></td>
+        <td>bar</td>
+      </tr>
+    </table>
+  </body>
+</html>
--- a/layout/reftests/forms/progress/reftest.list
+++ b/layout/reftests/forms/progress/reftest.list
@@ -14,8 +14,12 @@
 == bar-pseudo-element-vertical.html bar-pseudo-element-vertical-ref.html
 == bar-pseudo-element-vertical-rtl.html bar-pseudo-element-vertical-rtl-ref.html
 == indeterminate-style-height.html indeterminate-style-height-ref.html
 
 # The following test is disabled but kept in the repository because the
 # transformations will not behave exactly the same for <progress> and two divs.
 # However, it would be possible to manually check those.
 # == transformations.html transformations-ref.html
+
+# Tests for bugs:
+== block-invalidate.html block-invalidate-ref.html
+== in-cells.html in-cells-ref.html
--- a/layout/style/Declaration.cpp
+++ b/layout/style/Declaration.cpp
@@ -764,16 +764,25 @@ Declaration::GetValue(nsCSSProperty aPro
       const nsCSSValue &midValue =
         *data->ValueFor(eCSSProperty_marker_mid);
       const nsCSSValue &startValue =
         *data->ValueFor(eCSSProperty_marker_start);
       if (endValue == midValue && midValue == startValue)
         AppendValueToString(eCSSProperty_marker_end, aValue);
       break;
     }
+    case eCSSProperty__moz_columns: {
+      // Two values, column-count and column-width, separated by a space.
+      const nsCSSProperty* subprops =
+        nsCSSProps::SubpropertyEntryFor(aProperty);
+      AppendValueToString(subprops[0], aValue);
+      aValue.Append(PRUnichar(' '));
+      AppendValueToString(subprops[1], aValue);
+      break;
+    }
     default:
       NS_ABORT_IF_FALSE(false, "no other shorthands");
       break;
   }
 }
 
 PRBool
 Declaration::GetValueIsImportant(const nsAString& aProperty) const
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -487,16 +487,17 @@ protected:
   PRBool ParseCalcMultiplicativeExpression(nsCSSValue& aValue,
                                            PRInt32& aVariantMask,
                                            PRBool *aHadFinalWS);
   PRBool ParseCalcTerm(nsCSSValue& aValue, PRInt32& aVariantMask);
   PRBool RequireWhitespace();
 
   // for 'clip' and '-moz-image-region'
   PRBool ParseRect(nsCSSProperty aPropID);
+  PRBool ParseColumns();
   PRBool ParseContent();
   PRBool ParseCounterData(nsCSSProperty aPropID);
   PRBool ParseCursor();
   PRBool ParseFont();
   PRBool ParseFontWeight(nsCSSValue& aValue);
   PRBool ParseOneFamily(nsAString& aValue);
   PRBool ParseFamily(nsCSSValue& aValue);
   PRBool ParseFontSrc(nsCSSValue& aValue);
@@ -5487,16 +5488,18 @@ CSSParserImpl::ParsePropertyByFunction(n
     return ParseBoxCornerRadius(aPropID);
 
   case eCSSProperty_box_shadow:
   case eCSSProperty_text_shadow:
     return ParseShadowList(aPropID);
 
   case eCSSProperty_clip:
     return ParseRect(eCSSProperty_clip);
+  case eCSSProperty__moz_columns:
+    return ParseColumns();
   case eCSSProperty__moz_column_rule:
     return ParseBorderSide(kColumnRuleIDs, PR_FALSE);
   case eCSSProperty_content:
     return ParseContent();
   case eCSSProperty_counter_increment:
   case eCSSProperty_counter_reset:
     return ParseCounterData(aPropID);
   case eCSSProperty_cursor:
@@ -5582,16 +5585,20 @@ CSSParserImpl::ParsePropertyByFunction(n
 PRBool
 CSSParserImpl::ParseSingleValueProperty(nsCSSValue& aValue,
                                         nsCSSProperty aPropID)
 {
   if (aPropID == eCSSPropertyExtra_x_none_value) {
     return ParseVariant(aValue, VARIANT_NONE | VARIANT_INHERIT, nsnull);
   }
 
+  if (aPropID == eCSSPropertyExtra_x_auto_value) {
+    return ParseVariant(aValue, VARIANT_AUTO | VARIANT_INHERIT, nsnull);
+  }
+
   if (aPropID < 0 || aPropID >= eCSSProperty_COUNT_no_shorthands) {
     NS_ABORT_IF_FALSE(PR_FALSE, "not a single value property");
     return PR_FALSE;
   }
 
   if (nsCSSProps::PropHasFlags(aPropID, CSS_PROPERTY_VALUE_PARSER_FUNCTION)) {
     switch (aPropID) {
       case eCSSProperty_font_family:
@@ -6841,16 +6848,58 @@ CSSParserImpl::ParseRect(nsCSSProperty a
     UngetToken();
     return PR_FALSE;
   }
 
   AppendValue(aPropID, val);
   return PR_TRUE;
 }
 
+PRBool
+CSSParserImpl::ParseColumns()
+{
+  // We use a similar "fake value" hack to ParseListStyle, because
+  // "auto" is acceptable for both column-count and column-width.
+  // If the fake "auto" value is found, and one of the real values isn't,
+  // that means the fake auto value is meant for the real value we didn't
+  // find.
+  static const nsCSSProperty columnIDs[] = {
+    eCSSPropertyExtra_x_auto_value,
+    eCSSProperty__moz_column_count,
+    eCSSProperty__moz_column_width
+  };
+  const PRInt32 numProps = NS_ARRAY_LENGTH(columnIDs);
+
+  nsCSSValue values[numProps];
+  PRInt32 found = ParseChoice(values, columnIDs, numProps);
+  if (found < 1 || !ExpectEndProperty()) {
+    return PR_FALSE;
+  }
+  if ((found & (1|2|4)) == (1|2|4) &&
+      values[0].GetUnit() ==  eCSSUnit_Auto) {
+    // We filled all 3 values, which is invalid
+    return PR_FALSE;
+  }
+
+  if ((found & 2) == 0) {
+    // Provide auto column-count
+    values[1].SetAutoValue();
+  }
+  if ((found & 4) == 0) {
+    // Provide auto column-width
+    values[2].SetAutoValue();
+  }
+
+  // Start at index 1 to skip the fake auto value.
+  for (PRInt32 index = 1; index < numProps; index++) {
+    AppendValue(columnIDs[index], values[index]);
+  }
+  return PR_TRUE;
+}
+
 #define VARIANT_CONTENT (VARIANT_STRING | VARIANT_URL | VARIANT_COUNTER | VARIANT_ATTR | \
                          VARIANT_KEYWORD)
 PRBool
 CSSParserImpl::ParseContent()
 {
   // We need to divide the 'content' keywords into two classes for
   // ParseVariant's sake, so we can't just use nsCSSProps::kContentKTable.
   static const PRInt32 kContentListKWs[] = {
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -1234,16 +1234,21 @@ CSS_PROP_COLOR(
     Color,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE |
         CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED,
     VARIANT_HC,
     nsnull,
     offsetof(nsStyleColor, mColor),
     eStyleAnimType_Color)
+CSS_PROP_SHORTHAND(
+    -moz-columns,
+    _moz_columns,
+    CSS_PROP_DOMPROP_PREFIXED(Columns),
+    CSS_PROPERTY_PARSE_FUNCTION)
 CSS_PROP_COLUMN(
     -moz-column-count,
     _moz_column_count,
     CSS_PROP_DOMPROP_PREFIXED(ColumnCount),
     CSS_PROPERTY_PARSE_VALUE |
         // Need to reject 0 in addition to negatives.  If we accept 0, we
         // need to change NS_STYLE_COLUMN_COUNT_AUTO to something else.
         CSS_PROPERTY_VALUE_AT_LEAST_ONE,
--- a/layout/style/nsCSSProperty.h
+++ b/layout/style/nsCSSProperty.h
@@ -71,17 +71,18 @@ enum nsCSSProperty {
   // with eCSSProperty_COUNT if we had a need for them to do so.
 
   // Extra values for use in the values of the 'transition-property'
   // property.
   eCSSPropertyExtra_no_properties,
   eCSSPropertyExtra_all_properties,
 
   // Extra dummy values for nsCSSParser internal use.
-  eCSSPropertyExtra_x_none_value
+  eCSSPropertyExtra_x_none_value,
+  eCSSPropertyExtra_x_auto_value
 };
 
 // The "descriptors" that can appear in a @font-face rule.
 // They have the syntax of properties but different value rules.
 // Keep in sync with kCSSRawFontDescs in nsCSSProps.cpp and
 // nsCSSFontFaceStyleDecl::Fields in nsCSSRules.cpp.
 enum nsCSSFontDesc {
   eCSSFontDesc_UNKNOWN = -1,
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -1963,16 +1963,22 @@ static const nsCSSProperty gOutlineSubpr
   // nsCSSDeclaration.cpp outputs the subproperties in this order.
   // It also depends on the color being third.
   eCSSProperty_outline_width,
   eCSSProperty_outline_style,
   eCSSProperty_outline_color,
   eCSSProperty_UNKNOWN
 };
 
+static const nsCSSProperty gColumnsSubpropTable[] = {
+  eCSSProperty__moz_column_count,
+  eCSSProperty__moz_column_width,
+  eCSSProperty_UNKNOWN
+};
+
 static const nsCSSProperty gColumnRuleSubpropTable[] = {
   // nsCSSDeclaration.cpp outputs the subproperties in this order.
   // It also depends on the color being third.
   eCSSProperty__moz_column_rule_width,
   eCSSProperty__moz_column_rule_style,
   eCSSProperty__moz_column_rule_color,
   eCSSProperty_UNKNOWN
 };
--- a/layout/style/nsRuleNode.h
+++ b/layout/style/nsRuleNode.h
@@ -739,11 +739,15 @@ public:
   // Return whether the rule tree for which this node is the root has
   // cached data such that we need to do dynamic change handling for
   // changes that change the results of media queries or require
   // rebuilding all style data.
   PRBool TreeHasCachedData() const {
     NS_ASSERTION(IsRoot(), "should only be called on root of rule tree");
     return HaveChildren() || mStyleData.mInheritedData || mStyleData.mResetData;
   }
+
+  PRBool NodeHasCachedData(const nsStyleStructID aSID) {
+    return !!mStyleData.GetStyleData(aSID);
+  }
 };
 
 #endif
--- a/layout/style/nsStyleAnimation.cpp
+++ b/layout/style/nsStyleAnimation.cpp
@@ -1921,98 +1921,99 @@ LookupStyleContext(dom::Element* aElemen
   nsIDocument* doc = aElement->GetCurrentDoc();
   nsIPresShell* shell = doc->GetShell();
   if (!shell) {
     return nsnull;
   }
   return nsComputedDOMStyle::GetStyleContextForElement(aElement, nsnull, shell);
 }
 
-
-/**
- * Helper function: StyleWithDeclarationAdded
- * Creates a nsStyleRule with the specified property set to the specified
- * value, and returns a nsStyleContext for this rule, as a sibling of the
- * given element's nsStyleContext.
- *
- * If we fail to parse |aSpecifiedValue| for |aProperty|, this method will
- * return nsnull.
- *
- * @param aProperty       The property whose value we're customizing in the
- *                        custom style context.
- * @param aTargetElement  The element whose style context we'll use as a
- *                        sibling for our custom style context.
- * @param aSpecifiedValue The value for |aProperty| in our custom style
- *                        context.
- * @param aUseSVGMode     A flag to indicate whether we should parse
- *                        |aSpecifiedValue| in SVG mode.
- * @return The generated custom nsStyleContext, or nsnull on failure.
- */
-already_AddRefed<nsStyleContext>
-StyleWithDeclarationAdded(nsCSSProperty aProperty,
-                          dom::Element* aTargetElement,
-                          const nsAString& aSpecifiedValue,
-                          PRBool aUseSVGMode)
-{
-  NS_ABORT_IF_FALSE(aTargetElement, "null target element");
-  NS_ABORT_IF_FALSE(aTargetElement->GetCurrentDoc(),
-                    "element needs to be in a document "
-                    "if we're going to look up its style context");
-
-  // Look up style context for our target element
-  nsRefPtr<nsStyleContext> styleContext = LookupStyleContext(aTargetElement);
-  if (!styleContext) {
-    return nsnull;
-  }
-
-  // Parse specified value into a temporary StyleRule
-  nsRefPtr<css::StyleRule> styleRule =
-    BuildStyleRule(aProperty, aTargetElement, aSpecifiedValue, aUseSVGMode);
-  if (!styleRule) {
-    return nsnull;
-  }
-
-  styleRule->RuleMatched();
-
-  // Create a temporary nsStyleContext for the style rule
-  nsCOMArray<nsIStyleRule> ruleArray;
-  ruleArray.AppendObject(styleRule);
-  nsStyleSet* styleSet = styleContext->PresContext()->StyleSet();
-  return styleSet->ResolveStyleByAddingRules(styleContext, ruleArray);
-}
-
 PRBool
 nsStyleAnimation::ComputeValue(nsCSSProperty aProperty,
                                dom::Element* aTargetElement,
                                const nsAString& aSpecifiedValue,
                                PRBool aUseSVGMode,
-                               Value& aComputedValue)
+                               Value& aComputedValue,
+                               PRBool* aIsContextSensitive)
 {
   NS_ABORT_IF_FALSE(aTargetElement, "null target element");
   NS_ABORT_IF_FALSE(aTargetElement->GetCurrentDoc(),
                     "we should only be able to actively animate nodes that "
                     "are in a document");
 
   nsCSSProperty propToParse =
     nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_REPORT_OTHER_NAME)
       ? nsCSSProps::OtherNameFor(aProperty) : aProperty;
 
-  nsRefPtr<nsStyleContext> tmpStyleContext =
-    StyleWithDeclarationAdded(propToParse, aTargetElement,
-                              aSpecifiedValue, aUseSVGMode);
-  if (!tmpStyleContext) {
+  // Parse specified value into a temporary css::StyleRule
+  nsRefPtr<css::StyleRule> styleRule =
+    BuildStyleRule(propToParse, aTargetElement, aSpecifiedValue, aUseSVGMode);
+  if (!styleRule) {
     return PR_FALSE;
   }
 
- if (nsCSSProps::IsShorthand(aProperty) ||
-     nsCSSProps::kAnimTypeTable[aProperty] == eStyleAnimType_None) {
+  if (nsCSSProps::IsShorthand(aProperty) ||
+      nsCSSProps::kAnimTypeTable[aProperty] == eStyleAnimType_None) {
     // Just capture the specified value
     aComputedValue.SetUnparsedStringValue(nsString(aSpecifiedValue));
+    if (aIsContextSensitive) {
+      // Since we're just returning the string as-is, aComputedValue isn't going
+      // to change depending on the context
+      *aIsContextSensitive = PR_FALSE;
+    }
     return PR_TRUE;
   }
+
+  // Look up style context for our target element
+  nsRefPtr<nsStyleContext> styleContext = LookupStyleContext(aTargetElement);
+  if (!styleContext) {
+    return PR_FALSE;
+  }
+  nsStyleSet* styleSet = styleContext->PresContext()->StyleSet();
+
+  nsRefPtr<nsStyleContext> tmpStyleContext;
+  if (aIsContextSensitive) {
+    nsCOMArray<nsIStyleRule> ruleArray;
+    ruleArray.AppendObject(styleSet->InitialStyleRule());
+    ruleArray.AppendObject(styleRule);
+    styleRule->RuleMatched();
+    tmpStyleContext =
+      styleSet->ResolveStyleByAddingRules(styleContext, ruleArray);
+    if (!tmpStyleContext) {
+      return PR_FALSE;
+    }
+
+    // Force walk of rule tree
+    nsStyleStructID sid = nsCSSProps::kSIDTable[aProperty];
+    tmpStyleContext->GetStyleData(sid);
+
+    // If the rule node will have cached style data if the value is not
+    // context-sensitive. So if there's nothing cached, it's not context
+    // sensitive.
+    *aIsContextSensitive =
+      !tmpStyleContext->GetRuleNode()->NodeHasCachedData(sid);
+  }
+
+  // If we're not concerned whether the property is context sensitive then just
+  // add the rule to a new temporary style context alongside the target
+  // element's style context.
+  // Also, if we previously discovered that this property IS context-sensitive
+  // then we need to throw the temporary style context out since the property's
+  // value may have been biased by the 'initial' values supplied.
+  if (!aIsContextSensitive || *aIsContextSensitive) {
+    nsCOMArray<nsIStyleRule> ruleArray;
+    ruleArray.AppendObject(styleRule);
+    styleRule->RuleMatched();
+    tmpStyleContext =
+      styleSet->ResolveStyleByAddingRules(styleContext, ruleArray);
+    if (!tmpStyleContext) {
+      return PR_FALSE;
+    }
+  }
+
   // Extract computed value of our property from the temporary style rule
   return ExtractComputedValue(aProperty, tmpStyleContext, aComputedValue);
 }
 
 PRBool
 nsStyleAnimation::UncomputeValue(nsCSSProperty aProperty,
                                  nsPresContext* aPresContext,
                                  const Value& aComputedValue,
--- a/layout/style/nsStyleAnimation.h
+++ b/layout/style/nsStyleAnimation.h
@@ -170,23 +170,32 @@ public:
    * @param aProperty       The property whose value we're computing.
    * @param aTargetElement  The content node to which our computed value is
    *                        applicable.
    * @param aSpecifiedValue The specified value, from which we'll build our
    *                        computed value.
    * @param aUseSVGMode     A flag to indicate whether we should parse
    *                        |aSpecifiedValue| in SVG mode.
    * @param [out] aComputedValue The resulting computed value.
+   * @param [out] aIsContextSensitive
+   *                        Set to PR_TRUE if |aSpecifiedValue| may produce
+   *                        a different |aComputedValue| depending on other CSS
+   *                        properties on |aTargetElement| or its ancestors.
+   *                        PR_FALSE otherwise.
+   *                        Note that the operation of this method is
+   *                        significantly faster when |aIsContextSensitive| is
+   *                        nsnull.
    * @return PR_TRUE on success, PR_FALSE on failure.
    */
   static PRBool ComputeValue(nsCSSProperty aProperty,
-                             mozilla::dom::Element* aElement,
+                             mozilla::dom::Element* aTargetElement,
                              const nsAString& aSpecifiedValue,
                              PRBool aUseSVGMode,
-                             Value& aComputedValue);
+                             Value& aComputedValue,
+                             PRBool* aIsContextSensitive = nsnull);
 
   /**
    * Creates a specified value for the given computed value.
    *
    * The first overload fills in an nsCSSValue object; the second
    * produces a string.  The nsCSSValue result may depend on objects
    * owned by the |aComputedValue| object, so users of that variant
    * must keep |aComputedValue| alive longer than |aSpecifiedValue|.
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -52,16 +52,17 @@
 #include "nsStyleContext.h"
 #include "mozilla/css/StyleRule.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsCSSPseudoElements.h"
 #include "nsCSSRuleProcessor.h"
 #include "nsIContent.h"
 #include "nsIFrame.h"
 #include "nsContentUtils.h"
+#include "nsRuleData.h"
 #include "nsRuleProcessorData.h"
 #include "nsTransitionManager.h"
 #include "nsAnimationManager.h"
 #include "nsEventStates.h"
 #include "mozilla/dom/Element.h"
 
 using namespace mozilla::dom;
 namespace css = mozilla::css;
@@ -75,16 +76,60 @@ nsEmptyStyleRule::MapRuleInfoInto(nsRule
 
 #ifdef DEBUG
 /* virtual */ void
 nsEmptyStyleRule::List(FILE* out, PRInt32 aIndent) const
 {
 }
 #endif
 
+NS_IMPL_ISUPPORTS1(nsInitialStyleRule, nsIStyleRule)
+
+/* virtual */ void
+nsInitialStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
+{
+  // Iterate over the property groups
+  for (nsStyleStructID sid = nsStyleStructID(0);
+       sid < nsStyleStructID_Length; sid = nsStyleStructID(sid + 1)) {
+    if (aRuleData->mSIDs & (1 << sid)) {
+      // Iterate over nsCSSValues within the property group
+      nsCSSValue * const value_start =
+        aRuleData->mValueStorage + aRuleData->mValueOffsets[sid];
+      for (nsCSSValue *value = value_start,
+           *value_end = value + nsCSSProps::PropertyCountInStruct(sid);
+           value != value_end; ++value) {
+        // If MathML is disabled take care not to set MathML properties (or we
+        // will trigger assertions in nsRuleNode)
+        if (sid == eStyleStruct_Font &&
+            !aRuleData->mPresContext->Document()->GetMathMLEnabled()) {
+          size_t index = value - value_start;
+          if (index == nsCSSProps::PropertyIndexInStruct(
+                          eCSSProperty_script_level) ||
+              index == nsCSSProps::PropertyIndexInStruct(
+                          eCSSProperty_script_size_multiplier) ||
+              index == nsCSSProps::PropertyIndexInStruct(
+                          eCSSProperty_script_min_size)) {
+            continue;
+          }
+        }
+        if (value->GetUnit() == eCSSUnit_Null) {
+          value->SetInitialValue();
+        }
+      }
+    }
+  }
+}
+
+#ifdef DEBUG
+/* virtual */ void
+nsInitialStyleRule::List(FILE* out, PRInt32 aIndent) const
+{
+}
+#endif
+
 static const nsStyleSet::sheetType gCSSSheetTypes[] = {
   nsStyleSet::eAgentSheet,
   nsStyleSet::eUserSheet,
   nsStyleSet::eDocSheet,
   nsStyleSet::eOverrideSheet
 };
 
 nsStyleSet::nsStyleSet()
@@ -1560,8 +1605,17 @@ nsStyleSet::EnsureUniqueInnerOnCSSSheets
 
     // Enqueue all the sheet's children.
     if (!sheet->AppendAllChildSheets(queue)) {
       return nsCSSStyleSheet::eUniqueInner_CloneFailed;
     }
   }
   return res;
 }
+
+nsIStyleRule*
+nsStyleSet::InitialStyleRule()
+{
+  if (!mInitialStyleRule) {
+    mInitialStyleRule = new nsInitialStyleRule;
+  }
+  return mInitialStyleRule;
+}
--- a/layout/style/nsStyleSet.h
+++ b/layout/style/nsStyleSet.h
@@ -69,16 +69,25 @@ class nsEmptyStyleRule : public nsIStyle
 {
   NS_DECL_ISUPPORTS
   virtual void MapRuleInfoInto(nsRuleData* aRuleData);
 #ifdef DEBUG
   virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const;
 #endif
 };
 
+class nsInitialStyleRule : public nsIStyleRule
+{
+  NS_DECL_ISUPPORTS
+  virtual void MapRuleInfoInto(nsRuleData* aRuleData);
+#ifdef DEBUG
+  virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const;
+#endif
+};
+
 // The style set object is created by the document viewer and ownership is
 // then handed off to the PresShell.  Only the PresShell should delete a
 // style set.
 
 class nsStyleSet
 {
  public:
   nsStyleSet();
@@ -304,16 +313,18 @@ class nsStyleSet
 
   // Notify the style set that a rulenode that wasn't in use now is
   void RuleNodeInUse() {
     --mUnusedRuleNodeCount;
   }
 
   nsCSSStyleSheet::EnsureUniqueInnerResult EnsureUniqueInnerOnCSSSheets();
 
+  nsIStyleRule* InitialStyleRule();
+
  private:
   // Not to be implemented
   nsStyleSet(const nsStyleSet& aCopy);
   nsStyleSet& operator=(const nsStyleSet& aCopy);
 
   // Returns false on out-of-memory.
   PRBool BuildDefaultStyleData(nsPresContext* aPresContext);
 
@@ -395,16 +406,20 @@ class nsStyleSet
 
   PRUint32 mUnusedRuleNodeCount; // used to batch rule node GC
   nsTArray<nsStyleContext*> mRoots; // style contexts with no parent
 
   // Empty style rules to force things that restrict which properties
   // apply into different branches of the rule tree.
   nsRefPtr<nsEmptyStyleRule> mFirstLineRule, mFirstLetterRule;
 
+  // Style rule which sets all properties to their initial values for
+  // determining when context-sensitive values are in use.
+  nsRefPtr<nsInitialStyleRule> mInitialStyleRule;
+
   PRUint16 mBatching;
 
   // Old rule trees, which should only be non-empty between
   // BeginReconstruct and EndReconstruct, but in case of bugs that cause
   // style contexts to exist too long, may last longer.
   nsTArray<nsRuleNode*> mOldRuleTrees;
 
   unsigned mInShutdown : 1;
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -467,16 +467,26 @@ var gCSSProperties = {
 	"-moz-box-sizing": {
 		domProp: "MozBoxSizing",
 		inherited: false,
 		type: CSS_TYPE_LONGHAND,
 		initial_values: [ "content-box" ],
 		other_values: [ "border-box", "padding-box" ],
 		invalid_values: [ "margin-box", "content", "padding", "border", "margin" ]
 	},
+	"-moz-columns": {
+		domProp: "MozColumns",
+		inherited: false,
+		type: CSS_TYPE_TRUE_SHORTHAND,
+		subproperties: [ "-moz-column-count", "-moz-column-width" ],
+		initial_values: [ "auto", "auto auto" ],
+		other_values: [ "3", "20px", "2 10px", "10px 2", "2 auto", "auto 2", "auto 50px", "50px auto" ],
+		invalid_values: [ "5%", "-1px", "-1", "3 5", "10px 4px", "10 2px 5in", "30px -1",
+		                  "auto 3 5px", "5 auto 20px", "auto auto auto" ]
+	},
 	"-moz-column-count": {
 		domProp: "MozColumnCount",
 		inherited: false,
 		type: CSS_TYPE_LONGHAND,
 		initial_values: [ "auto" ],
 		other_values: [ "1", "17" ],
 		// negative and zero invalid per editor's draft
 		invalid_values: [ "-1", "0", "3px" ]
--- a/mobile/chrome/content/browser.js
+++ b/mobile/chrome/content/browser.js
@@ -317,16 +317,22 @@ var Browser = {
     window.controllers.appendController(BrowserUI);
 
     var os = Services.obs;
     os.addObserver(XPInstallObserver, "addon-install-blocked", false);
     os.addObserver(XPInstallObserver, "addon-install-started", false);
     os.addObserver(SessionHistoryObserver, "browser:purge-session-history", false);
     os.addObserver(ContentCrashObserver, "ipc:content-shutdown", false);
     os.addObserver(MemoryObserver, "memory-pressure", false);
+    os.addObserver(ActivityObserver, "application-background", false);
+    os.addObserver(ActivityObserver, "application-foreground", false);
+    os.addObserver(ActivityObserver, "system-active", false);
+    os.addObserver(ActivityObserver, "system-idle", false);
+    os.addObserver(ActivityObserver, "system-display-on", false);
+    os.addObserver(ActivityObserver, "system-display-off", false);
 
     // Listens for change in the viewable area
 #if MOZ_PLATFORM_MAEMO == 6
     os.addObserver(ViewableAreaObserver, "softkb-change", false);
 #endif
    messageManager.addMessageListener("Content:IsKeyboardOpened", ViewableAreaObserver);
 
     window.QueryInterface(Ci.nsIDOMChromeWindow).browserDOMWindow = new nsBrowserAccess();
@@ -481,16 +487,22 @@ var Browser = {
     messageManager.removeMessageListener("Browser:ErrorPage", this);
 
     var os = Services.obs;
     os.removeObserver(XPInstallObserver, "addon-install-blocked");
     os.removeObserver(XPInstallObserver, "addon-install-started");
     os.removeObserver(SessionHistoryObserver, "browser:purge-session-history");
     os.removeObserver(ContentCrashObserver, "ipc:content-shutdown");
     os.removeObserver(MemoryObserver, "memory-pressure");
+    os.removeObserver(ActivityObserver, "application-background", false);
+    os.removeObserver(ActivityObserver, "application-foreground", false);
+    os.removeObserver(ActivityObserver, "system-active", false);
+    os.removeObserver(ActivityObserver, "system-idle", false);
+    os.removeObserver(ActivityObserver, "system-display-on", false);
+    os.removeObserver(ActivityObserver, "system-display-off", false);
 
     window.controllers.removeController(this);
     window.controllers.removeController(BrowserUI);
   },
 
   getHomePage: function getHomePage(aOptions) {
     aOptions = aOptions || { useDefault: false };
 
@@ -2580,16 +2592,44 @@ var MemoryObserver = {
     // Bug 637582 - The low memory condition throws out some stuff that we still
     // need, re-selecting the active tab gets us back to where we need to be.
     let sTab = Browser.selectedTab;
     Browser._selectedTab = null;
     Browser.selectedTab = sTab;
   }
 };
 
+var ActivityObserver = {
+  _inBackground : false,
+  _notActive : false,
+  _isDisplayOff : false,
+  observe: function ao_observe(aSubject, aTopic, aData) {
+    if (aTopic == "application-background") {
+      this._inBackground = true;
+    } else if (aTopic == "application-foreground") {
+      this._inBackground = false;
+    } else if (aTopic == "system-idle") {
+      this._notActive = true;
+    } else if (aTopic == "system-active") {
+      this._notActive = false;
+    } else if (aTopic == "system-display-on") {
+      this._isDisplayOff = false;
+    } else if (aTopic == "system-display-off") {
+      this._isDisplayOff = true;
+    }
+    let activeTabState = !this._inBackground && !this._notActive && !this._isDisplayOff;
+    if (Browser.selectedTab.active != activeTabState) {
+      // On Maemo all backgrounded applications getting portrait orientation
+      // so if browser had landscape mode then we need timeout in order
+      // to finish last rotate/paint operation and have nice lookine browser in TS
+      setTimeout(function() { Browser.selectedTab.active = activeTabState; }, 0);
+    }
+  }
+};
+
 function getNotificationBox(aBrowser) {
   return Browser.getNotificationBox(aBrowser);
 }
 
 function importDialog(aParent, aSrc, aArguments) {
   // load the dialog with a synchronous XHR
   let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance();
   xhr.open("GET", aSrc, false);
--- a/mobile/chrome/content/common-ui.js
+++ b/mobile/chrome/content/common-ui.js
@@ -1485,17 +1485,26 @@ var BadgeHandlers = {
   ],
 
   register: function(aPopup) {
     let handlers = this._handlers;
     for (let i = 0; i < handlers.length; i++)
       aPopup.registerBadgeHandler(handlers[i].url, handlers[i]);
   },
 
+  get _pk11DB() {
+    delete this._pk11DB;
+    return this._pk11DB = Cc["@mozilla.org/security/pk11tokendb;1"].getService(Ci.nsIPK11TokenDB);
+  },
+
   getLogin: function(aURL) {
+    let token = this._pk11DB.getInternalKeyToken();
+    if (!token.isLoggedIn())
+      return {username: "", password: ""};
+
     let lm = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
     let logins = lm.findLogins({}, aURL, aURL, null);
     let username = logins.length > 0 ? logins[0].username : "";
     let password = logins.length > 0 ? logins[0].password : "";
     return { username: username, password: password };
   },
 
   clampBadge: function(aValue) {
--- a/mobile/chrome/content/sync.js
+++ b/mobile/chrome/content/sync.js
@@ -377,35 +377,39 @@ let WeaveGlue = {
     });
 
     // Replace the getter with the collection of settings
     delete this._elements;
     return this._elements = elements;
   },
 
   observe: function observe(aSubject, aTopic, aData) {
-    let loggedIn = Weave.Service.isLoggedIn;
-
     // Make sure we're online when connecting/syncing
     Util.forceOnline();
 
     // Can't do anything before settings are loaded
     if (this._elements == null)
       return;
 
     // Make some aliases
     let connect = this._elements.connect;
     let connected = this._elements.connected;
     let autosync = this._elements.autosync;
     let details = this._elements.details;
     let device = this._elements.device;
     let disconnect = this._elements.disconnect;
     let sync = this._elements.sync;
 
-    let syncEnabled = this._elements.autosync.value;
+    let syncEnabled = autosync.value;
+    let loggedIn = Weave.Service.isLoggedIn;
+
+    // Sync may successfully log in after it was temporarily disabled by a
+    // canceled master password entry.  If so, then re-enable it.
+    if (loggedIn && !syncEnabled)
+      syncEnabled = autosync.value = true;
 
     // If Sync is not enabled, hide the connection row visibility
     if (syncEnabled) {
       connect.collapsed = loggedIn;
       connected.collapsed = !loggedIn;
     } else {
       connect.collapsed = true;
       connected.collapsed = true;
@@ -446,20 +450,28 @@ let WeaveGlue = {
     let lastSync = Weave.Svc.Prefs.get("lastSync");
     if (lastSync != null) {
       let syncDate = new Date(lastSync).toLocaleFormat("%a %R");
       let dateStr = this._bundle.formatStringFromName("lastSync2.label", [syncDate], 1);
       sync.setAttribute("title", dateStr);
     }
 
     // Show what went wrong with login if necessary
-    if (aTopic == "weave:service:login:error")
-      connect.setAttribute("desc", Weave.Utils.getErrorString(Weave.Status.login));
-    else
+    if (aTopic == "weave:service:login:error") {
+      if (Weave.Status.login == "service.master_password_locked") {
+        // Disable sync temporarily. Sync will try again after a set interval,
+        // or if the user presses the button to enable it again.
+        autosync.value = false;
+        this.toggleSyncEnabled();
+      } else {
+        connect.setAttribute("desc", Weave.Utils.getErrorString(Weave.Status.login));
+      }
+    } else {
       connect.removeAttribute("desc");
+    }
 
     // Init the setup data if we just logged in
     if (!this.setupData && aTopic == "weave:service:login:finish")
       this.loadSetupData();
 
     // Check for a storage format update, update the user and load the Sync update page
     if (aTopic =="weave:service:sync:error") {
       let clientOutdated = false, remoteOutdated = false;
--- a/mobile/installer/Makefile.in
+++ b/mobile/installer/Makefile.in
@@ -174,26 +174,23 @@ PP_DEB_FILES =	debian/control \
 		debian/compat \
 		debian/files \
 		debian/menu \
 		debian/fennec.preinst \
 		debian/fennec.prerm \
 		debian/fennec.postinst \
 		$(NULL)
 
-ifdef MOZ_ENABLE_CONTENTMANAGER
+ifeq ($(MOZ_PLATFORM_MAEMO),6)
 PP_DEB_FILES += debian/fennec.aegis \
-               $(NULL)
-endif
-ifeq ($(MOZ_PLATFORM_MAEMO),6)
-PP_DEB_FILES += debian/backup \
-                debian/restore \
-		 debian/fennec.conf \
-		 debian/fennec-cud.sh \
-		 debian/fennec-rfs.sh \
+		debian/backup \
+		debian/restore \
+		debian/fennec.conf \
+		debian/fennec-cud.sh \
+		debian/fennec-rfs.sh \
 		 debian/fennec.policy \
                 $(NULL)
 endif
 
 $(PP_DEB_FILES):
 	@$(EXIT_ON_ERROR) \
 	for f in $(PP_DEB_FILES); do \
            src=$(srcdir)/debian/`basename $$f`.in; \
@@ -237,17 +234,17 @@ else
 	cp $(DIST)/branding/$(MOZ_APP_NAME)_26x26.png $(DEBDESTDIR)/usr/share/icons/hicolor/26x26/hildon/$(MOZ_APP_NAME).png
 	$(NSINSTALL) -D $(DEBDESTDIR)/usr/share/icons/hicolor/40x40/hildon/
 	cp $(DIST)/branding/$(MOZ_APP_NAME)_40x40.png $(DEBDESTDIR)/usr/share/icons/hicolor/40x40/hildon/$(MOZ_APP_NAME).png
 endif
 	fakeroot dh_link; fakeroot dh_fixperms; fakeroot dh_installdeb; fakeroot dh_shlibdeps; fakeroot dh_gencontrol; fakeroot dh_md5sums; fakeroot dh_builddeb;
 
 # a defined CONTENTMANAGER implicitly means MOZ_PLATFORM_MAEMO is equals 6
 # in case you use CONTENTMANGER you need to sign your package to gain tracker access.
-ifdef MOZ_ENABLE_CONTENTMANAGER
+ifeq ($(MOZ_PLATFORM_MAEMO),6)
 	if test -e "/usr/bin/aegis-deb-add"; then \
 	   fakeroot aegis-deb-add -control $(DEBDESTDIR)/DEBIAN/control .. debian/fennec.aegis=_aegis; \
 	else \
 	   echo aegis-builder not found, security signing failed!; \
 	fi
 endif
 
 	echo $(DEB_PKG_NAME) > $(DIST)/deb_name.txt
--- a/mobile/installer/debian/fennec.aegis.in
+++ b/mobile/installer/debian/fennec.aegis.in
@@ -1,8 +1,9 @@
+#filter substitution
 <aegis>
   <request>
     <credential name="TrackerReadAccess" />
     <credential name="TrackerWriteAccess" />
     <credential name="Location" />
     <for path="@installdir@/@MOZ_APP_NAME@" />
     <for path="@installdir@/plugin-container" />
   </request>
--- a/modules/libjar/nsJARURI.cpp
+++ b/modules/libjar/nsJARURI.cpp
@@ -580,29 +580,16 @@ nsJARURI::GetFilePath(nsACString& filePa
 
 NS_IMETHODIMP
 nsJARURI::SetFilePath(const nsACString& filePath)
 {
     return mJAREntry->SetFilePath(filePath);
 }
 
 NS_IMETHODIMP
-nsJARURI::GetParam(nsACString& param)
-{
-    param.Truncate();
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsJARURI::SetParam(const nsACString& param)
-{
-    return NS_ERROR_NOT_AVAILABLE;
-}
-
-NS_IMETHODIMP
 nsJARURI::GetQuery(nsACString& query)
 {
     return mJAREntry->GetQuery(query);
 }
 
 NS_IMETHODIMP
 nsJARURI::SetQuery(const nsACString& query)
 {
--- a/modules/libpr0n/test/unit/xpcshell.ini
+++ b/modules/libpr0n/test/unit/xpcshell.ini
@@ -3,9 +3,11 @@ head =
 tail = 
 
 [test_async_notification.js]
 [test_async_notification_404.js]
 [test_async_notification_animated.js]
 [test_encoder_apng.js]
 [test_encoder_png.js]
 [test_imgtools.js]
+# Bug 676968: test fails consistently on Android
+fail-if = os == "android"
 [test_moz_icon_uri.js]
--- a/modules/libpref/public/nsIPrefBranch.idl
+++ b/modules/libpref/public/nsIPrefBranch.idl
@@ -50,17 +50,17 @@
  * For example, if this object is created with the root "browser.startup.",
  * the preferences "browser.startup.page", "browser.startup.homepage",
  * and "browser.startup.homepage_override" can be accessed by simply passing
  * "page", "homepage", or "homepage_override" to the various Get/Set methods.
  *
  * @see nsIPrefService
  */
 
-[scriptable, uuid(e0b6e170-691b-11e0-ae3e-0800200c9a66)]
+[scriptable, uuid(e162bfa0-01bd-4e9f-9843-8fb2efcd6d1f)]
 interface nsIPrefBranch : nsISupports
 {
 
   /**
    * Values describing the basic preference types.
    *
    * @see getPrefType
    */
@@ -102,17 +102,17 @@ interface nsIPrefBranch : nsISupports
    * @param aPrefName The boolean preference to set the state of.
    * @param aValue    The boolean value to set the preference to.
    *
    * @return NS_OK The value was successfully set.
    * @return Other The value was not set or is the wrong type.
    *
    * @see getBoolPref
    */
-  void setBoolPref(in string aPrefName, in long aValue);
+  void setBoolPref(in string aPrefName, in boolean aValue);
 
   /**
    * Called to get the state of an individual string preference.
    *
    * @param aPrefName The string preference to retrieve.
    *
    * @return string   The value of the requested string preference.
    *
--- a/modules/libpref/public/nsIPrefBranch2.idl
+++ b/modules/libpref/public/nsIPrefBranch2.idl
@@ -42,17 +42,17 @@
 
 interface nsIObserver;
 
 /**
  * nsIPrefBranch2 allows clients to observe changes to pref values.
  *
  * @see nsIPrefBranch
  */
-[scriptable, uuid(784de8e2-e72f-441a-ae74-9d5fdfe13be3)]
+[scriptable, uuid(d9bb54df-daac-4ce6-a70c-95d87b770cd8)]
 interface nsIPrefBranch2 : nsIPrefBranch
 {
   /**
    * Add a preference change observer. On preference changes, the following
    * arguments will be passed to the nsIObserver.observe() method:
    *   aSubject - The nsIPrefBranch object (this)
    *   aTopic   - The string defined by NS_PREFBRANCH_PREFCHANGE_TOPIC_ID
    *   aData    - The name of the preference which has changed, relative to
--- a/modules/libpref/public/nsIPrefBranchInternal.idl
+++ b/modules/libpref/public/nsIPrefBranchInternal.idl
@@ -39,12 +39,12 @@
 
 /**
  * An empty interface to provide backwards compatibility for existing code that
  * bsmedberg didn't want to break all at once. Don't use me!
  *
  * @status NON-FROZEN interface WHICH WILL PROBABLY GO AWAY.
  */
 
-[scriptable, uuid(d1d412d9-15d6-4a6a-9533-b949dc175ff5)]
+[scriptable, uuid(355bd1e9-248a-438b-809d-e0db1b287882)]
 interface nsIPrefBranchInternal : nsIPrefBranch2
 {
 };
--- a/modules/libpref/src/nsPrefBranch.cpp
+++ b/modules/libpref/src/nsPrefBranch.cpp
@@ -159,17 +159,17 @@ NS_IMETHODIMP nsPrefBranch::GetPrefType(
 
 NS_IMETHODIMP nsPrefBranch::GetBoolPref(const char *aPrefName, PRBool *_retval)
 {
   NS_ENSURE_ARG(aPrefName);
   const char *pref = getPrefName(aPrefName);
   return PREF_GetBoolPref(pref, _retval, mIsDefault);
 }
 
-NS_IMETHODIMP nsPrefBranch::SetBoolPref(const char *aPrefName, PRInt32 aValue)
+NS_IMETHODIMP nsPrefBranch::SetBoolPref(const char *aPrefName, PRBool aValue)
 {
   if (GetContentChild()) {
     NS_ERROR("cannot set pref from content process");
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   NS_ENSURE_ARG(aPrefName);
   const char *pref = getPrefName(aPrefName);
--- a/modules/libpref/src/prefapi.cpp
+++ b/modules/libpref/src/prefapi.cpp
@@ -63,19 +63,16 @@
 #include "nsPrintfCString.h"
 #include "prlink.h"
 
 #ifdef XP_OS2
 #define INCL_DOS
 #include <os2.h>
 #endif
 
-#define BOGUS_DEFAULT_INT_PREF_VALUE (-5632)
-#define BOGUS_DEFAULT_BOOL_PREF_VALUE (-2)
-
 static void
 clearPrefEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
 {
     PrefHashEntry *pref = static_cast<PrefHashEntry *>(entry);
     if (pref->flags & PREF_STRING)
     {
         if (pref->defaultPref.stringVal)
             PL_strfree(pref->defaultPref.stringVal);
@@ -293,17 +290,17 @@ PREF_SetIntPref(const char *pref_name, P
 
     return pref_HashPref(pref_name, pref, PREF_INT, set_default);
 }
 
 nsresult
 PREF_SetBoolPref(const char *pref_name, PRBool value, PRBool set_default)
 {
     PrefValue pref;
-    pref.boolVal = value ? PR_TRUE : PR_FALSE;
+    pref.boolVal = value;
 
     return pref_HashPref(pref_name, pref, PREF_BOOL, set_default);
 }
 
 nsresult
 pref_SetPrefTuple(const PrefTuple &aPref, PRBool set_default)
 {
     switch (aPref.type) {
@@ -334,19 +331,20 @@ pref_savePref(PLDHashTable *table, PLDHa
     nsCAutoString prefValue;
     nsCAutoString prefPrefix;
     prefPrefix.Assign(NS_LITERAL_CSTRING("user_pref(\""));
 
     // where we're getting our pref from
     PrefValue* sourcePref;
 
     if (PREF_HAS_USER_VALUE(pref) &&
-        pref_ValueChanged(pref->defaultPref,
-                          pref->userPref,
-                          (PrefType) PREF_TYPE(pref))) {
+        (pref_ValueChanged(pref->defaultPref,
+                           pref->userPref,
+                           (PrefType) PREF_TYPE(pref)) ||
+         !(pref->flags & PREF_HAS_DEFAULT))) {
         sourcePref = &pref->userPref;
     } else {
         if (argData->saveTypes == SAVE_ALL_AND_DEFAULTS) {
             prefPrefix.Assign(NS_LITERAL_CSTRING("pref(\""));
             sourcePref = &pref->defaultPref;
         }
         else
             // do not save default prefs that haven't changed
@@ -518,17 +516,17 @@ nsresult PREF_GetIntPref(const char *pre
     nsresult rv = NS_ERROR_UNEXPECTED;
     PrefHashEntry* pref = pref_HashTableLookup(pref_name);
     if (pref && (pref->flags & PREF_INT))
     {
         if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref))
         {
             PRInt32 tempInt = pref->defaultPref.intVal;
             /* check to see if we even had a default */
-            if (tempInt == ((PRInt32) BOGUS_DEFAULT_INT_PREF_VALUE))
+            if (!(pref->flags & PREF_HAS_DEFAULT))
                 return NS_ERROR_UNEXPECTED;
             *return_int = tempInt;
         }
         else
             *return_int = pref->userPref.intVal;
         rv = NS_OK;
     }
     return rv;
@@ -543,17 +541,17 @@ nsresult PREF_GetBoolPref(const char *pr
     PrefHashEntry* pref = pref_HashTableLookup(pref_name);
     //NS_ASSERTION(pref, pref_name);
     if (pref && (pref->flags & PREF_BOOL))
     {
         if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref))
         {
             PRBool tempBool = pref->defaultPref.boolVal;
             /* check to see if we even had a default */
-            if (tempBool != ((PRBool) BOGUS_DEFAULT_BOOL_PREF_VALUE)) {
+            if (pref->flags & PREF_HAS_DEFAULT) {
                 *return_value = tempBool;
                 rv = NS_OK;
             }
         }
         else {
             *return_value = pref->userPref.boolVal;
             rv = NS_OK;
         }
@@ -609,21 +607,17 @@ PREF_ClearUserPref(const char *pref_name
     if (!gHashTable.ops)
         return NS_ERROR_NOT_INITIALIZED;
 
     PrefHashEntry* pref = pref_HashTableLookup(pref_name);
     if (pref && PREF_HAS_USER_VALUE(pref))
     {
         pref->flags &= ~PREF_USERSET;
 
-        if ((pref->flags & PREF_INT && 
-             pref->defaultPref.intVal == ((PRInt32) BOGUS_DEFAULT_INT_PREF_VALUE)) ||
-            (pref->flags & PREF_BOOL && 
-             pref->defaultPref.boolVal == ((PRBool) BOGUS_DEFAULT_BOOL_PREF_VALUE)) ||
-            (pref->flags & PREF_STRING && !pref->defaultPref.stringVal)) {
+        if (!(pref->flags & PREF_HAS_DEFAULT)) {
             PL_DHashTableOperate(&gHashTable, pref_name, PL_DHASH_REMOVE);
         }
 
         pref_DoCallback(pref_name);
         gDirty = PR_TRUE;
     }
     return NS_OK;
 }
@@ -635,21 +629,17 @@ pref_ClearUserPref(PLDHashTable *table, 
     PrefHashEntry *pref = static_cast<PrefHashEntry*>(he);
 
     PLDHashOperator nextOp = PL_DHASH_NEXT;
 
     if (PREF_HAS_USER_VALUE(pref))
     {
         pref->flags &= ~PREF_USERSET;
 
-        if ((pref->flags & PREF_INT && 
-             pref->defaultPref.intVal == ((PRInt32) BOGUS_DEFAULT_INT_PREF_VALUE)) ||
-            (pref->flags & PREF_BOOL && 
-             pref->defaultPref.boolVal == ((PRBool) BOGUS_DEFAULT_BOOL_PREF_VALUE)) ||
-            (pref->flags & PREF_STRING && !pref->defaultPref.stringVal)) {
+        if (!(pref->flags & PREF_HAS_DEFAULT)) {
             nextOp = PL_DHASH_REMOVE;
         }
 
         pref_DoCallback(pref->key);
     }
     return nextOp;
 }
 
@@ -752,51 +742,45 @@ nsresult pref_HashPref(const char *key, 
     // new entry, better intialize
     if (!pref->key) {
 
         // initialize the pref entry
         pref->flags = type;
         pref->key = ArenaStrDup(key, &gPrefNameArena);
         memset(&pref->defaultPref, 0, sizeof(pref->defaultPref));
         memset(&pref->userPref, 0, sizeof(pref->userPref));
-
-        /* ugly hack -- define it to a default that no pref will ever
-           default to this should really get fixed right by some out
-           of band data
-        */
-        if (pref->flags & PREF_BOOL)
-            pref->defaultPref.boolVal = (PRBool) BOGUS_DEFAULT_BOOL_PREF_VALUE;
-        if (pref->flags & PREF_INT)
-            pref->defaultPref.intVal = (PRInt32) BOGUS_DEFAULT_INT_PREF_VALUE;
     }
     else if ((((PrefType)(pref->flags)) & PREF_VALUETYPE_MASK) !=
                  (type & PREF_VALUETYPE_MASK))
     {
         NS_WARNING(nsPrintfCString(192, "Trying to set pref %s to with the wrong type!", key).get());
         return NS_ERROR_UNEXPECTED;
     }
 
     PRBool valueChanged = PR_FALSE;
     if (set_default)
     {
         if (!PREF_IS_LOCKED(pref))
         {       /* ?? change of semantics? */
-            if (pref_ValueChanged(pref->defaultPref, value, type))
+            if (pref_ValueChanged(pref->defaultPref, value, type) ||
+                !(pref->flags & PREF_HAS_DEFAULT))
             {
                 pref_SetValue(&pref->defaultPref, value, type);
+                pref->flags |= PREF_HAS_DEFAULT;
                 if (!PREF_HAS_USER_VALUE(pref))
                     valueChanged = PR_TRUE;
             }
         }
     }
     else
     {
         /* If new value is same as the default value, then un-set the user value.
            Otherwise, set the user value only if it has changed */
-        if ( !pref_ValueChanged(pref->defaultPref, value, type) )
+        if (!pref_ValueChanged(pref->defaultPref, value, type) &&
+            pref->flags & PREF_HAS_DEFAULT)
         {
             if (PREF_HAS_USER_VALUE(pref))
             {
                 pref->flags &= ~PREF_USERSET;
                 if (!PREF_IS_LOCKED(pref))
                     valueChanged = PR_TRUE;
             }
         }
--- a/modules/libpref/src/prefapi.h
+++ b/modules/libpref/src/prefapi.h
@@ -53,17 +53,17 @@ typedef union
     PRBool      boolVal;
 } PrefValue;
 
 struct PrefHashEntry : PLDHashEntryHdr
 {
     const char *key;
     PrefValue defaultPref;
     PrefValue userPref;
-    PRUint8   flags;
+    PRUint16  flags;
 };
 
 /*
 // <font color=blue>
 // The Init function initializes the preference context and creates
 // the preference hashtable.
 // </font>
 */
@@ -79,19 +79,20 @@ void        PREF_CleanupPrefs();
 /*
 // <font color=blue>
 // Preference flags, including the native type of the preference
 // </font>
 */
 
 typedef enum { PREF_INVALID = 0,
                PREF_LOCKED = 1, PREF_USERSET = 2, PREF_CONFIG = 4, PREF_REMOTE = 8,
-			   PREF_LILOCAL = 16, PREF_STRING = 32, PREF_INT = 64, PREF_BOOL = 128,
-			   PREF_VALUETYPE_MASK = (PREF_STRING | PREF_INT | PREF_BOOL)
-			  } PrefType;
+               PREF_LILOCAL = 16, PREF_STRING = 32, PREF_INT = 64, PREF_BOOL = 128,
+               PREF_HAS_DEFAULT = 256,
+               PREF_VALUETYPE_MASK = (PREF_STRING | PREF_INT | PREF_BOOL)
+             } PrefType;
 
 /*
 // <font color=blue>
 // Set the various types of preferences.  These functions take a dotted
 // notation of the preference name (e.g. "browser.startup.homepage").  
 // Note that this will cause the preference to be saved to the file if
 // it is different from the default.  In other words, these are used
 // to set the _user_ preferences.
--- a/netwerk/base/public/nsIURL.idl
+++ b/netwerk/base/public/nsIURL.idl
@@ -40,17 +40,16 @@
 #include "nsIURI.idl"
 
 /**
  * The nsIURL interface provides convenience methods that further
  * break down the path portion of nsIURI:
  *
  * http://host/directory/fileBaseName.fileExtension?query
  * http://host/directory/fileBaseName.fileExtension#ref
- * http://host/directory/fileBaseName.fileExtension;param
  *            \          \                       /
  *             \          -----------------------
  *              \                   |          /
  *               \               fileName     /
  *                ----------------------------
  *                            |
  *                        filePath
  */
@@ -66,23 +65,16 @@ interface nsIURL : nsIURI
      * URL.  For example, the filePath of "http://host/foo/bar.html#baz"
      * is "/foo/bar.html".
      *
      * Some characters may be escaped.
      */
     attribute AUTF8String filePath;
 
     /**
-     * Returns the parameters specified after the ; in the URL. 
-     *
-     * Some characters may be escaped.
-     */
-    attribute AUTF8String param;
-
-    /**
      * Returns the query portion (the part after the "?") of the URL.
      * If there isn't one, an empty string is returned.
      *
      * Some characters may be escaped.
      */
     attribute AUTF8String query;
 
 
--- a/netwerk/base/public/nsIURLParser.idl
+++ b/netwerk/base/public/nsIURLParser.idl
@@ -90,24 +90,23 @@ interface nsIURLParser : nsISupports
     /**
      * serverinfo = <hostname>:<port>
      */
     void parseServerInfo (in string serverinfo,            in long serverinfoLen,
                           out unsigned long hostnamePos,  out long hostnameLen,
                           out long port);
 
     /**
-     * ParsePath breaks the path string up into its 4 major components: a file path,
-     * a param string, a query string, and a reference string.
+     * ParsePath breaks the path string up into its 3 major components: a file path,
+     * a query string, and a reference string.
      *
-     * path = <filepath>;<param>?<query>#<ref>
+     * path = <filepath>?<query>#<ref>
      */
     void parsePath       (in string path,                  in long pathLen,
                           out unsigned long filepathPos,  out long filepathLen,
-                          out unsigned long paramPos,     out long paramLen,
                           out unsigned long queryPos,     out long queryLen,
                           out unsigned long refPos,       out long refLen);
 
     /**
      * ParseFilePath breaks the file path string up into: the directory portion,
      * file base name, and file extension.
      *
      * filepath = <directory><basename>.<extension>
--- a/netwerk/base/src/nsProxyAutoConfig.js
+++ b/netwerk/base/src/nsProxyAutoConfig.js
@@ -70,17 +70,18 @@ nsProxyAutoConfig.prototype = {
     init: function(pacURI, pacText) {
         // remove PAC configuration if requested
         if (pacURI == "" || pacText == "") {
             this._sandBox = null;
             return;
         }
 
         // allocate a fresh Sandbox to clear global scope for new PAC script
-        this._sandBox = new Components.utils.Sandbox(pacURI);
+        this._sandBox = new Components.utils.Sandbox(pacURI, 
+                                                     {sandboxName: 'nsProxyAutoConfig'});
         Components.utils.evalInSandbox(pacUtils, this._sandBox);
 
         // add predefined functions to pac
         this._sandBox.importFunction(myIpAddress);
         this._sandBox.importFunction(dnsResolve);
         this._sandBox.importFunction(proxyAlert, "alert");
 
         // evaluate loaded js file
--- a/netwerk/base/src/nsStandardURL.cpp
+++ b/netwerk/base/src/nsStandardURL.cpp
@@ -395,17 +395,16 @@ nsStandardURL::Clear()
     mHostEncoding = eEncoding_ASCII;
 
     mPath.Reset();
     mFilepath.Reset();
     mDirectory.Reset();
     mBasename.Reset();
 
     mExtension.Reset();
-    mParam.Reset();
     mQuery.Reset();
     mRef.Reset();
 
     InvalidateCache();
 }
 
 void
 nsStandardURL::InvalidateCache(PRBool invalidateCachedFile)
@@ -506,26 +505,26 @@ nsresult
 nsStandardURL::BuildNormalizedSpec(const char *spec)
 {
     // Assumptions: all member URLSegments must be relative the |spec| argument
     // passed to this function.
 
     // buffers for holding escaped url segments (these will remain empty unless
     // escaping is required).
     nsCAutoString encUsername, encPassword, encHost, encDirectory,
-      encBasename, encExtension, encParam, encQuery, encRef;
+      encBasename, encExtension, encQuery, encRef;
     PRBool useEncUsername, useEncPassword, useEncHost, useEncDirectory,
-      useEncBasename, useEncExtension, useEncParam, useEncQuery, useEncRef;
+      useEncBasename, useEncExtension, useEncQuery, useEncRef;
     nsCAutoString portbuf;
 
     //
     // escape each URL segment, if necessary, and calculate approximate normalized
     // spec length.
     //
-    // [scheme://][username[:password]@]host[:port]/path[;param][?query_string][#ref]
+    // [scheme://][username[:password]@]host[:port]/path[?query_string][#ref]
 
     PRUint32 approxLen = 0;
 
     // the scheme is already ASCII
     if (mScheme.mLen > 0)
         approxLen += mScheme.mLen + 3; // includes room for "://";
 
     // encode URL segments; convert UTF-8 to origin charset and possibly escape.
@@ -551,19 +550,16 @@ nsStandardURL::BuildNormalizedSpec(const
         approxLen += 1; // reserve space for possible leading '/' - may not be needed
         // Should just use mPath?  These are pessimistic, and thus waste space
         approxLen += encoder.EncodeSegmentCount(spec, mDirectory, esc_Directory,     encDirectory, useEncDirectory, 1);
         approxLen += encoder.EncodeSegmentCount(spec, mBasename,  esc_FileBaseName,  encBasename,  useEncBasename);
         approxLen += encoder.EncodeSegmentCount(spec, mExtension, esc_FileExtension, encExtension, useEncExtension, 1);
 
         // These next ones *always* add their leading character even if length is 0
         // Handles items like "http://#"
-        // ;param
-        if (mParam.mLen >= 0)
-            approxLen += 1 + encoder.EncodeSegmentCount(spec, mParam,     esc_Param,         encParam,     useEncParam);
         // ?query
         if (mQuery.mLen >= 0)
             approxLen += 1 + queryEncoder.EncodeSegmentCount(spec, mQuery, esc_Query,        encQuery,     useEncQuery);
         // #ref
         if (mRef.mLen >= 0)
             approxLen += 1 + encoder.EncodeSegmentCount(spec, mRef,       esc_Ref,           encRef,       useEncRef);
     }
 
@@ -673,20 +669,16 @@ nsStandardURL::BuildNormalizedSpec(const
 
         if (mExtension.mLen >= 0) {
             buf[i++] = '.';
             i = AppendSegmentToBuf(buf, i, spec, mExtension, &encExtension, useEncExtension);
         }
         // calculate corrected filepath length
         mFilepath.mLen = i - mFilepath.mPos;
 
-        if (mParam.mLen >= 0) {
-            buf[i++] = ';';
-            i = AppendSegmentToBuf(buf, i, spec, mParam, &encParam, useEncParam);
-        }
         if (mQuery.mLen >= 0) {
             buf[i++] = '?';
             i = AppendSegmentToBuf(buf, i, spec, mQuery, &encQuery, useEncQuery);
         }
         if (mRef.mLen >= 0) {
             buf[i++] = '#';
             i = AppendSegmentToBuf(buf, i, spec, mRef, &encRef, useEncRef);
         }
@@ -833,23 +825,21 @@ nsStandardURL::ParseURL(const char *spec
 
 nsresult
 nsStandardURL::ParsePath(const char *spec, PRUint32 pathPos, PRInt32 pathLen)
 {
     LOG(("ParsePath: %s pathpos %d len %d\n",spec,pathPos,pathLen));
 
     nsresult rv = mParser->ParsePath(spec + pathPos, pathLen,
                                      &mFilepath.mPos, &mFilepath.mLen,
-                                     &mParam.mPos, &mParam.mLen,
                                      &mQuery.mPos, &mQuery.mLen,
                                      &mRef.mPos, &mRef.mLen);
     if (NS_FAILED(rv)) return rv;
 
     mFilepath.mPos += pathPos;
-    mParam.mPos += pathPos;
     mQuery.mPos += pathPos;
     mRef.mPos += pathPos;
 
     if (mFilepath.mLen > 0) {
         rv = mParser->ParseFilePath(spec + mFilepath.mPos, mFilepath.mLen,
                                     &mDirectory.mPos, &mDirectory.mLen,
                                     &mBasename.mPos, &mBasename.mLen,
                                     &mExtension.mPos, &mExtension.mLen);
@@ -1203,17 +1193,16 @@ nsStandardURL::SetSpec(const nsACString 
         LOG((" username  = (%u,%d)\n", mUsername.mPos,  mUsername.mLen));
         LOG((" password  = (%u,%d)\n", mPassword.mPos,  mPassword.mLen));
         LOG((" hostname  = (%u,%d)\n", mHost.mPos,      mHost.mLen));
         LOG((" path      = (%u,%d)\n", mPath.mPos,      mPath.mLen));
         LOG((" filepath  = (%u,%d)\n", mFilepath.mPos,  mFilepath.mLen));
         LOG((" directory = (%u,%d)\n", mDirectory.mPos, mDirectory.mLen));
         LOG((" basename  = (%u,%d)\n", mBasename.mPos,  mBasename.mLen));
         LOG((" extension = (%u,%d)\n", mExtension.mPos, mExtension.mLen));
-        LOG((" param     = (%u,%d)\n", mParam.mPos,     mParam.mLen));
         LOG((" query     = (%u,%d)\n", mQuery.mPos,     mQuery.mLen));
         LOG((" ref       = (%u,%d)\n", mRef.mPos,       mRef.mLen));
     }
 #endif
     return rv;
 }
 
 NS_IMETHODIMP
@@ -1628,17 +1617,16 @@ nsStandardURL::SetPath(const nsACString 
         mSpec.Cut(mPath.mPos + 1, mPath.mLen - 1);
         // these contain only a '/'
         mPath.mLen = 1;
         mDirectory.mLen = 1;
         mFilepath.mLen = 1;
         // these are no longer defined
         mBasename.mLen = -1;
         mExtension.mLen = -1;
-        mParam.mLen = -1;
         mQuery.mLen = -1;
         mRef.mLen = -1;
     }
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::Equals(nsIURI *unknownOther, PRBool *result)
@@ -1679,18 +1667,17 @@ nsStandardURL::EqualsInternal(nsIURI *un
     // URIs different
     if (!SegmentIs(mScheme, other->mSpec.get(), other->mScheme) ||
         // Check for host manually, since conversion to file will
         // ignore the host!
         !SegmentIs(mHost, other->mSpec.get(), other->mHost) ||
         !SegmentIs(mQuery, other->mSpec.get(), other->mQuery) ||
         !SegmentIs(mUsername, other->mSpec.get(), other->mUsername) ||
         !SegmentIs(mPassword, other->mSpec.get(), other->mPassword) ||
-        Port() != other->Port() ||
-        !SegmentIs(mParam, other->mSpec.get(), other->mParam)) {
+        Port() != other->Port()) {
         // No need to compare files or other URI parts -- these are different
         // beasties
         *result = PR_FALSE;
         return NS_OK;
     }
 
     if (refHandlingMode == eHonorRef &&
         !SegmentIs(mRef, other->mSpec.get(), other->mRef)) {
@@ -1790,17 +1777,16 @@ nsStandardURL::CloneInternal(nsStandardU
     clone->mUsername = mUsername;
     clone->mPassword = mPassword;
     clone->mHost = mHost;
     clone->mPath = mPath;
     clone->mFilepath = mFilepath;
     clone->mDirectory = mDirectory;
     clone->mBasename = mBasename;
     clone->mExtension = mExtension;
-    clone->mParam = mParam;
     clone->mQuery = mQuery;
     clone->mRef = mRef;
     clone->mOriginCharset = mOriginCharset;
     clone->mURLType = mURLType;
     clone->mParser = mParser;
     clone->mFile = mFile;
     clone->mHostA = mHostA ? nsCRT::strdup(mHostA) : nsnull;
     clone->mMutable = PR_TRUE;
@@ -2015,17 +2001,17 @@ nsStandardURL::GetCommonBaseSpec(nsIURI 
     while ((*thisIndex == *thatIndex) && *thisIndex)
     {
         thisIndex++;
         thatIndex++;
     }
 
     // backup to just after previous slash so we grab an appropriate path
     // segment such as a directory (not partial segments)
-    // todo:  also check for file matches which include '?', '#', and ';'
+    // todo:  also check for file matches which include '?' and '#'
     while ((thisIndex != startCharPos) && (*(thisIndex-1) != '/'))
         thisIndex--;
 
     // grab spec from beginning to thisIndex
     aResult = Substring(mSpec, mScheme.mPos, thisIndex - mSpec.get());
 
     NS_RELEASE(stdurl2);
     return rv;
@@ -2096,17 +2082,17 @@ nsStandardURL::GetRelativeSpec(nsIURI *u
     while ((*thisIndex == *thatIndex) && *thisIndex)
     {
         thisIndex++;
         thatIndex++;
     }
 
     // backup to just after previous slash so we grab an appropriate path
     // segment such as a directory (not partial segments)
-    // todo:  also check for file matches with '#', '?' and ';'
+    // todo:  also check for file matches with '#' and '?'
     while ((*(thatIndex-1) != '/') && (thatIndex != startCharPos))
         thatIndex--;
 
     const char *limit = mSpec.get() + mFilepath.mPos + mFilepath.mLen;
 
     // need to account for slashes and add corresponding "../"
     for (; thisIndex <= limit && *thisIndex; ++thisIndex)
     {
@@ -2132,24 +2118,16 @@ NS_IMETHODIMP
 nsStandardURL::GetFilePath(nsACString &result)
 {
     result = Filepath();
     return NS_OK;
 }
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
-nsStandardURL::GetParam(nsACString &result)
-{
-    result = Param();
-    return NS_OK;
-}
-
-// result may contain unescaped UTF-8 characters
-NS_IMETHODIMP
 nsStandardURL::GetQuery(nsACString &result)
 {
     result = Query();
     return NS_OK;
 }
 
 // result may contain unescaped UTF-8 characters
 NS_IMETHODIMP
@@ -2258,37 +2236,30 @@ nsStandardURL::SetFilePath(const nsACStr
             if (mSpec.Length() > end)
                 spec.Append(mSpec.get() + end, mSpec.Length() - end);
         }
 
         return SetSpec(spec);
     }
     else if (mPath.mLen > 1) {
         mSpec.Cut(mPath.mPos + 1, mFilepath.mLen - 1);
-        // left shift param, query, and ref
-        ShiftFromParam(1 - mFilepath.mLen);
+        // left shift query, and ref
+        ShiftFromQuery(1 - mFilepath.mLen);
         // these contain only a '/'
         mPath.mLen = 1;
         mDirectory.mLen = 1;
         mFilepath.mLen = 1;
         // these are no longer defined
         mBasename.mLen = -1;
         mExtension.mLen = -1;
     }
     return NS_OK;
 }
 
 NS_IMETHODIMP
-nsStandardURL::SetParam(const nsACString &input)
-{
-    NS_NOTYETIMPLEMENTED("");
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
 nsStandardURL::SetQuery(const nsACString &input)
 {
     ENSURE_MUTABLE();
 
     const nsPromiseFlatCString &flat = PromiseFlatCString(input);
     const char *query = flat.get();
 
     LOG(("nsStandardURL::SetQuery [query=%s]\n", query));
@@ -2498,17 +2469,17 @@ nsStandardURL::SetFileName(const nsACStr
             
             mBasename.mLen = basename.mLen;
             mExtension.mLen = extension.mLen;
             if (mExtension.mLen >= 0)
                 mExtension.mPos = mBasename.mPos + mBasename.mLen + 1;
         }
     }
     if (shift) {
-        ShiftFromParam(shift);
+        ShiftFromQuery(shift);
         mFilepath.mLen += shift;
         mPath.mLen += shift;
     }
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::SetFileBaseName(const nsACString &input)
@@ -2795,19 +2766,16 @@ nsStandardURL::Read(nsIObjectInputStream
     if (NS_FAILED(rv)) return rv;
 
     rv = ReadSegment(stream, mBasename);
     if (NS_FAILED(rv)) return rv;
 
     rv = ReadSegment(stream, mExtension);
     if (NS_FAILED(rv)) return rv;
 
-    rv = ReadSegment(stream, mParam);
-    if (NS_FAILED(rv)) return rv;
-
     rv = ReadSegment(stream, mQuery);
     if (NS_FAILED(rv)) return rv;
 
     rv = ReadSegment(stream, mRef);
     if (NS_FAILED(rv)) return rv;
 
     rv = NS_ReadOptionalCString(stream, mOriginCharset);
     if (NS_FAILED(rv)) return rv;
@@ -2884,19 +2852,16 @@ nsStandardURL::Write(nsIObjectOutputStre
     if (NS_FAILED(rv)) return rv;
 
     rv = WriteSegment(stream, mBasename);
     if (NS_FAILED(rv)) return rv;
 
     rv = WriteSegment(stream, mExtension);
     if (NS_FAILED(rv)) return rv;
 
-    rv = WriteSegment(stream, mParam);
-    if (NS_FAILED(rv)) return rv;
-
     rv = WriteSegment(stream, mQuery);
     if (NS_FAILED(rv)) return rv;
 
     rv = WriteSegment(stream, mRef);
     if (NS_FAILED(rv)) return rv;
 
     rv = NS_WriteOptionalStringZ(stream, mOriginCharset.get());
     if (NS_FAILED(rv)) return rv;
@@ -2959,17 +2924,16 @@ nsStandardURL::Read(const IPC::Message *
         !ReadSegment(aMsg, aIter, mUsername) ||
         !ReadSegment(aMsg, aIter, mPassword) ||
         !ReadSegment(aMsg, aIter, mHost) ||
         !ReadSegment(aMsg, aIter, mPath) ||
         !ReadSegment(aMsg, aIter, mFilepath) ||
         !ReadSegment(aMsg, aIter, mDirectory) ||
         !ReadSegment(aMsg, aIter, mBasename) ||
         !ReadSegment(aMsg, aIter, mExtension) ||
-        !ReadSegment(aMsg, aIter, mParam) ||
         !ReadSegment(aMsg, aIter, mQuery) ||
         !ReadSegment(aMsg, aIter, mRef) ||
         !ReadParam(aMsg, aIter, &mOriginCharset) ||
         !ReadParam(aMsg, aIter, &isMutable) ||
         !ReadParam(aMsg, aIter, &supportsFileURL) ||
         !ReadParam(aMsg, aIter, &hostEncoding))
         return PR_FALSE;
 
@@ -3000,17 +2964,16 @@ nsStandardURL::Write(IPC::Message *aMsg)
     WriteSegment(aMsg, mUsername);
     WriteSegment(aMsg, mPassword);
     WriteSegment(aMsg, mHost);
     WriteSegment(aMsg, mPath);
     WriteSegment(aMsg, mFilepath);
     WriteSegment(aMsg, mDirectory);
     WriteSegment(aMsg, mBasename);
     WriteSegment(aMsg, mExtension);
-    WriteSegment(aMsg, mParam);
     WriteSegment(aMsg, mQuery);
     WriteSegment(aMsg, mRef);
     WriteParam(aMsg, mOriginCharset);
     WriteParam(aMsg, bool(mMutable));
     WriteParam(aMsg, bool(mSupportsFileURL));
     WriteParam(aMsg, mHostEncoding);
     // mSpecEncoding and mHostA are just caches that can be recovered as needed.
 }
--- a/netwerk/base/src/nsStandardURL.h
+++ b/netwerk/base/src/nsStandardURL.h
@@ -218,31 +218,29 @@ private:
     const nsDependentCSubstring Hostport(); // see below
     const nsDependentCSubstring Host();     // see below
     const nsDependentCSubstring Path()      { return Segment(mPath); }
     const nsDependentCSubstring Filepath()  { return Segment(mFilepath); }
     const nsDependentCSubstring Directory() { return Segment(mDirectory); }
     const nsDependentCSubstring Filename(); // see below
     const nsDependentCSubstring Basename()  { return Segment(mBasename); }
     const nsDependentCSubstring Extension() { return Segment(mExtension); }
-    const nsDependentCSubstring Param()     { return Segment(mParam); }
     const nsDependentCSubstring Query()     { return Segment(mQuery); }
     const nsDependentCSubstring Ref()       { return Segment(mRef); }
 
     // shift the URLSegments to the right by diff
     void ShiftFromAuthority(PRInt32 diff) { mAuthority.mPos += diff; ShiftFromUsername(diff); }
     void ShiftFromUsername(PRInt32 diff)  { mUsername.mPos += diff; ShiftFromPassword(diff); }
     void ShiftFromPassword(PRInt32 diff)  { mPassword.mPos += diff; ShiftFromHost(diff); }
     void ShiftFromHost(PRInt32 diff)      { mHost.mPos += diff; ShiftFromPath(diff); }
     void ShiftFromPath(PRInt32 diff)      { mPath.mPos += diff; ShiftFromFilepath(diff); }
     void ShiftFromFilepath(PRInt32 diff)  { mFilepath.mPos += diff; ShiftFromDirectory(diff); }
     void ShiftFromDirectory(PRInt32 diff) { mDirectory.mPos += diff; ShiftFromBasename(diff); }
     void ShiftFromBasename(PRInt32 diff)  { mBasename.mPos += diff; ShiftFromExtension(diff); }
-    void ShiftFromExtension(PRInt32 diff) { mExtension.mPos += diff; ShiftFromParam(diff); }
-    void ShiftFromParam(PRInt32 diff)     { mParam.mPos += diff; ShiftFromQuery(diff); }
+    void ShiftFromExtension(PRInt32 diff) { mExtension.mPos += diff; ShiftFromQuery(diff); }
     void ShiftFromQuery(PRInt32 diff)     { mQuery.mPos += diff; ShiftFromRef(diff); }
     void ShiftFromRef(PRInt32 diff)       { mRef.mPos += diff; }
 
     // fastload helper functions
     nsresult ReadSegment(nsIBinaryInputStream *, URLSegment &);
     nsresult WriteSegment(nsIBinaryOutputStream *, const URLSegment &);
 
     // ipc helper functions
@@ -262,17 +260,16 @@ private:
     URLSegment mUsername;
     URLSegment mPassword;
     URLSegment mHost;
     URLSegment mPath;
     URLSegment mFilepath;
     URLSegment mDirectory;
     URLSegment mBasename;
     URLSegment mExtension;
-    URLSegment mParam;
     URLSegment mQuery;
     URLSegment mRef;
 
     nsCString              mOriginCharset;
     nsCOMPtr<nsIURLParser> mParser;
 
     // mFile is protected so subclasses can access it directly
 protected:
--- a/netwerk/base/src/nsURLHelper.cpp
+++ b/netwerk/base/src/nsURLHelper.cpp
@@ -216,17 +216,16 @@ net_ParseFileURL(const nsACString &inURL
                           nsnull, nsnull, // don't care about scheme
                           nsnull, nsnull, // don't care about authority
                           &pathPos, &pathLen);
     if (NS_FAILED(rv)) return rv;
 
     // invoke the parser to extract filepath from the path
     rv = parser->ParsePath(url + pathPos, pathLen,
                            &filepathPos, &filepathLen,
-                           nsnull, nsnull,  // don't care about param
                            nsnull, nsnull,  // don't care about query
                            nsnull, nsnull); // don't care about ref
     if (NS_FAILED(rv)) return rv;
 
     filepathPos += pathPos;
 
     // invoke the parser to extract the directory and filename from filepath
     rv = parser->ParseFilePath(url + filepathPos, filepathLen,
@@ -446,17 +445,16 @@ net_ResolveRelativePath(const nsACString
     PRBool stop = PR_FALSE;
     char c;
     for (; !stop; ++beg) {
         c = (beg == end) ? '\0' : *beg;
         //printf("%c [name=%s] [path=%s]\n", c, name.get(), path.get());
         switch (c) {
           case '\0':
           case '#':
-          case ';':
           case '?':
             stop = PR_TRUE;
             // fall through...
           case '/':
             // delimiter found
             if (name.EqualsLiteral("..")) {
                 // pop path
                 // If we already have the delim at end, then
--- a/netwerk/base/src/nsURLParsers.cpp
+++ b/netwerk/base/src/nsURLParsers.cpp
@@ -112,17 +112,16 @@ nsBaseURLParser::ParseURL(const char *sp
         switch (*p) {
             case ':':
                 if (!colon)
                     colon = p;
                 break;
             case '/': // start of filepath
             case '?': // start of query
             case '#': // start of ref
-            case ';': // start of param
                 if (!slash)
                     slash = p;
                 break;
             case '@': // username@hostname
             case '[': // start of IPv6 address literal
                 if (!stop)
                     stop = p;
                 break;
@@ -235,26 +234,25 @@ nsBaseURLParser::ParseServerInfo(const c
     if (port)
        *port = -1;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsBaseURLParser::ParsePath(const char *path, PRInt32 pathLen,
                            PRUint32 *filepathPos, PRInt32 *filepathLen,
-                           PRUint32 *paramPos, PRInt32 *paramLen,
                            PRUint32 *queryPos, PRInt32 *queryLen,
                            PRUint32 *refPos, PRInt32 *refLen)
 {
     NS_PRECONDITION(path, "null pointer");
 
     if (pathLen < 0)
         pathLen = strlen(path);
 
-    // path = [/]<segment1>/<segment2>/<...>/<segmentN>;<param>?<query>#<ref>
+    // path = [/]<segment1>/<segment2>/<...>/<segmentN>?<query>#<ref>
 
     // XXX PL_strnpbrk would be nice, but it's buggy
 
     // search for first occurrence of either ? or #
     const char *query_beg = 0, *query_end = 0;
     const char *ref_beg = 0;
     const char *p = 0;
     for (p = path; p < path + pathLen; ++p) {
@@ -278,39 +276,23 @@ nsBaseURLParser::ParsePath(const char *p
     else
         SET_RESULT(query, 0, -1);
 
     if (ref_beg)
         SET_RESULT(ref, ref_beg - path, pathLen - (ref_beg - path));
     else
         SET_RESULT(ref, 0, -1);
 
-    // search backwards for param
-    const char *param_beg = 0;
     const char *end;
     if (query_beg)
         end = query_beg - 1;
     else if (ref_beg)
         end = ref_beg - 1;
     else
         end = path + pathLen;
-    for (p = end - 1; p >= path && *p != '/'; --p) {
-        if (*p == ';') {
-            // found param
-            param_beg = p + 1;
-        }
-    }
-
-    if (param_beg) {
-        // found <filepath>;<param>
-        SET_RESULT(param, param_beg - path, end - param_beg);
-        end = param_beg - 1;
-    }
-    else
-        SET_RESULT(param, 0, -1);
 
     // an empty file path is no file path
     if (end != path)
         SET_RESULT(filepath, 0, end - path);
     else
         SET_RESULT(filepath, 0, -1);
     return NS_OK;
 }
@@ -432,17 +414,17 @@ nsNoAuthURLParser::ParseAfterScheme(cons
                     nsCRT::IsAsciiAlpha(spec[2]) &&
                     ((specLen == 4) || (spec[4] == '/') || (spec[4] == '\\'))) {
                     pos = 1;
                     break;  
                 } 
 #endif
                 // Ignore apparent authority; path is everything after it
                 for (p = spec + 2; p < spec + specLen; ++p) {
-                    if (*p == '/' || *p == '?' || *p == '#' || *p == ';')
+                    if (*p == '/' || *p == '?' || *p == '#')
                         break;
                 }
             }
             SET_RESULT(auth, 0, -1);
             if (p && p != spec+specLen)
                 SET_RESULT(path, p - spec, specLen - (p - spec));
             else
                 SET_RESULT(path, 0, -1);
@@ -662,17 +644,17 @@ nsAuthURLParser::ParseAfterScheme(const 
     NS_PRECONDITION(specLen >= 0, "unexpected");
 
     PRUint32 nslash = CountConsecutiveSlashes(spec, specLen);
 
     // search for the end of the authority section
     const char *end = spec + specLen;
     const char *p;
     for (p = spec + nslash; p < end; ++p) {
-        if (*p == '/' || *p == '?' || *p == '#' || *p == ';')
+        if (*p == '/' || *p == '?' || *p == '#')
             break;
     }
     if (p < end) {
         // spec = [/]<auth><path>
         SET_RESULT(auth, nslash, p - (spec + nslash));
         SET_RESULT(path, p - spec, specLen - (p - spec));
     }
     else {
--- a/netwerk/cache/nsDiskCacheMap.cpp
+++ b/netwerk/cache/nsDiskCacheMap.cpp
@@ -229,17 +229,20 @@ nsDiskCacheMap::FlushHeader()
     
     // write the header
     mHeader.Swap();
     PRInt32 bytesWritten = PR_Write(mMapFD, &mHeader, sizeof(nsDiskCacheHeader));
     mHeader.Unswap();
     if (sizeof(nsDiskCacheHeader) != bytesWritten) {
         return NS_ERROR_UNEXPECTED;
     }
-    
+
+    PRStatus err = PR_Sync(mMapFD);
+    if (err != PR_SUCCESS) return NS_ERROR_UNEXPECTED;
+
     return NS_OK;
 }
 
 
 nsresult
 nsDiskCacheMap::FlushRecords(PRBool unswap)
 {
     if (!mMapFD)  return NS_ERROR_NOT_AVAILABLE;
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -139,16 +139,58 @@ HttpChannelChild::AddIPDLReference()
 void
 HttpChannelChild::ReleaseIPDLReference()
 {
   NS_ABORT_IF_FALSE(mIPCOpen, "Attempt to release nonexistent IPDL reference");
   mIPCOpen = false;
   Release();
 }
 
+class AssociateApplicationCacheEvent : public ChannelEvent
+{
+  public:
+    AssociateApplicationCacheEvent(HttpChannelChild* child,
+                                   const nsCString &groupID,
+                                   const nsCString &clientID)
+    : mChild(child)
+    , groupID(groupID)
+    , clientID(clientID) {}
+
+    void Run() { mChild->AssociateApplicationCache(groupID, clientID); }
+  private:
+    HttpChannelChild* mChild;
+    nsCString groupID;
+    nsCString clientID;
+};
+
+bool
+HttpChannelChild::RecvAssociateApplicationCache(const nsCString &groupID,
+                                                const nsCString &clientID)
+{
+  if (mEventQ.ShouldEnqueue()) {
+    mEventQ.Enqueue(new AssociateApplicationCacheEvent(this, groupID, clientID));
+  } else {
+    AssociateApplicationCache(groupID, clientID);
+  }
+  return true;
+}
+
+void
+HttpChannelChild::AssociateApplicationCache(const nsCString &groupID,
+                                            const nsCString &clientID)
+{
+  nsresult rv;
+  mApplicationCache = do_CreateInstance(NS_APPLICATIONCACHE_CONTRACTID, &rv);
+  if (NS_FAILED(rv))
+    return;
+
+  mLoadedFromApplicationCache = PR_TRUE;
+  mApplicationCache->InitAsHandle(groupID, clientID);
+}
+
 class StartRequestEvent : public ChannelEvent
 {
  public:
   StartRequestEvent(HttpChannelChild* child,
                     const nsHttpResponseHead& responseHead,
                     const PRBool& useResponseHead,
                     const RequestHeaderTuples& requestHeaders,
                     const PRBool& isFromCache,
@@ -187,31 +229,16 @@ class StartRequestEvent : public Channel
   PRPackedBool mCacheEntryAvailable;
   PRUint32 mCacheExpirationTime;
   nsCString mCachedCharset;
   nsCString mSecurityInfoSerialization;
   PRNetAddr mSelfAddr;
   PRNetAddr mPeerAddr;
 };
 
-bool
-HttpChannelChild::RecvAssociateApplicationCache(const nsCString &groupID,
-                                                const nsCString &clientID)
-{
-  nsresult rv;
-  mApplicationCache = do_CreateInstance(
-    NS_APPLICATIONCACHE_CONTRACTID, &rv);
-  if (NS_FAILED(rv))
-    return true;
-
-  mLoadedFromApplicationCache = PR_TRUE;
-  mApplicationCache->InitAsHandle(groupID, clientID);
-  return true;
-}
-
 bool 
 HttpChannelChild::RecvOnStartRequest(const nsHttpResponseHead& responseHead,
                                      const PRBool& useResponseHead,
                                      const RequestHeaderTuples& requestHeaders,
                                      const PRBool& isFromCache,
                                      const PRBool& cacheEntryAvailable,
                                      const PRUint32& cacheExpirationTime,
                                      const nsCString& cachedCharset,
--- a/netwerk/protocol/http/HttpChannelChild.h
+++ b/netwerk/protocol/http/HttpChannelChild.h
@@ -168,16 +168,18 @@ private:
 
   // If ResumeAt is called before AsyncOpen, we need to send extra data upstream
   bool mSendResumeAt;
 
   bool mIPCOpen;
   bool mKeptAlive;
   ChannelEventQueue mEventQ;
 
+  void AssociateApplicationCache(const nsCString &groupID,
+                                 const nsCString &clientID);
   void OnStartRequest(const nsHttpResponseHead& responseHead,
                       const PRBool& useResponseHead,
                       const RequestHeaderTuples& requestHeaders,
                       const PRBool& isFromCache,
                       const PRBool& cacheEntryAvailable,
                       const PRUint32& cacheExpirationTime,
                       const nsCString& cachedCharset,
                       const nsCString& securityInfoSerialization,
@@ -199,16 +201,17 @@ private:
                       const PRUint32& redirectFlags,
                       const nsHttpResponseHead& responseHead);
   void Redirect3Complete();
   void DeleteSelf();
 
   // Called asynchronously from Resume: continues any pending calls into client.
   void CompleteResume();
 
+  friend class AssociateApplicationCacheEvent;
   friend class StartRequestEvent;
   friend class StopRequestEvent;
   friend class TransportAndDataEvent;
   friend class ProgressEvent;
   friend class StatusEvent;
   friend class FailedAsyncOpenEvent;
   friend class Redirect1Event;
   friend class Redirect3Event;
--- a/netwerk/test/TestURLParser.cpp
+++ b/netwerk/test/TestURLParser.cpp
@@ -65,28 +65,26 @@ parse_file_path(nsIURLParser *urlParser,
     PRINT_SUBFIELD(filepath, ext);
 }
 
 static void
 parse_path(nsIURLParser *urlParser, char *path, PRInt32 pathLen)
 {
     PRINT_FIELD(path);
 
-    PRUint32 filePos, paramPos, queryPos, refPos;
-    PRInt32 fileLen, paramLen, queryLen, refLen;
+    PRUint32 filePos, queryPos, refPos;
+    PRInt32 fileLen, queryLen, refLen;
 
     urlParser->ParsePath(path, pathLen,
                          &filePos, &fileLen,
-                         &paramPos, &paramLen,
                          &queryPos, &queryLen,
                          &refPos, &refLen);
 
     if (fileLen != -1)
         parse_file_path(urlParser, path + filePos, fileLen);
-    PRINT_SUBFIELD(path, param);
     PRINT_SUBFIELD(path, query);
     PRINT_SUBFIELD(path, ref);
 }
 
 int
 main(int argc, char **argv)
 {
     if (test_common_init(&argc, &argv) != 0)
--- a/netwerk/test/unit/test_bug429347.js
+++ b/netwerk/test/unit/test_bug429347.js
@@ -9,28 +9,34 @@ function run_test() {
   var uri1 = ios.newURI("http://example.com#bar", null, null);
   var uri2 = ios.newURI("http://example.com/#bar", null, null);
   do_check_true(uri1.equals(uri2));
 
   uri1.spec = "http://example.com?bar";
   uri2.spec = "http://example.com/?bar";
   do_check_true(uri1.equals(uri2));
 
+  // see https://bugzilla.mozilla.org/show_bug.cgi?id=665706
+  // ";" is not parsed as special anymore and thus ends up
+  // in the authority component (see RFC 3986)
   uri1.spec = "http://example.com;bar";
   uri2.spec = "http://example.com/;bar";
-  do_check_true(uri1.equals(uri2));
+  do_check_false(uri1.equals(uri2));
 
   uri1.spec = "http://example.com#";
   uri2.spec = "http://example.com/#";
   do_check_true(uri1.equals(uri2));
 
   uri1.spec = "http://example.com?";
   uri2.spec = "http://example.com/?";
   do_check_true(uri1.equals(uri2));
 
+  // see https://bugzilla.mozilla.org/show_bug.cgi?id=665706
+  // ";" is not parsed as special anymore and thus ends up
+  // in the authority component (see RFC 3986)
   uri1.spec = "http://example.com;";
   uri2.spec = "http://example.com/;";
-  do_check_true(uri1.equals(uri2));
+  do_check_false(uri1.equals(uri2));
 
   uri1.spec = "http://example.com";
   uri2.spec = "http://example.com/";
   do_check_true(uri1.equals(uri2));
 }
--- a/netwerk/test/unit/xpcshell.ini
+++ b/netwerk/test/unit/xpcshell.ini
@@ -3,16 +3,18 @@ head = head_channels.js
 tail = 
 
 [test_307_redirect.js]
 [test_NetUtil.js]
 [test_URIs.js]
 [test_aboutblank.js]
 [test_auth_proxy.js]
 [test_authentication.js]
+# Bug 675039: test hangs consistently on Android
+skip-if = os == "android"
 [test_authpromptwrapper.js]
 [test_bug203271.js]
 [test_bug248970_cache.js]
 [test_bug248970_cookie.js]
 [test_bug261425.js]
 [test_bug263127.js]
 [test_bug321706.js]
 [test_bug331825.js]
@@ -33,44 +35,58 @@ tail =
 [test_bug412945.js]
 [test_bug414122.js]
 [test_bug419157.js]
 [test_bug427957.js]
 [test_bug429347.js]
 [test_bug455311.js]
 [test_bug455598.js]
 [test_bug468426.js]
+# Bug 675039: test hangs consistently on Android 
+skip-if = os == "android"
 [test_bug468594.js]
 [test_bug470716.js]
 [test_bug479413.js]
 [test_bug479485.js]
 [test_bug482601.js]
 [test_bug484684.js]
 [test_bug490095.js]
 [test_bug504014.js]
 [test_bug510359.js]
+# Bug 675039: test hangs consistently on Android 
+skip-if = os == "android"
 [test_bug515583.js]
 [test_bug528292.js]
 [test_bug540566.js]
 [test_bug543805.js]
 [test_bug553970.js]
 [test_bug561042.js]
 [test_bug561276.js]
 [test_bug580508.js]
 [test_bug586908.js]
 [test_bug588389.js]
 [test_bug596443.js]
 [test_bug618835.js]
 [test_bug633743.js]
 [test_bug650955.js]
+# Bug 677427: test fails consistently on Android
+fail-if = os == "android"
 [test_bug652761.js]
 [test_bug651100.js]
+# Bug 675044: test fails consistently on Android
+fail-if = os == "android"  
 [test_bug654926.js]
+# Bug 675049: test fails consistently on Android
+fail-if = os == "android"  
 [test_bug654926_doom_and_read.js]
+# Bug 675049: test fails consistently on Android
+fail-if = os == "android"  
 [test_bug654926_test_seek.js]
+# Bug 675049: test fails consistently on Android
+fail-if = os == "android"  
 [test_bug659569.js]
 [test_bug660066.js]
 [test_bug651185.js]
 [test_bug667907.js]
 [test_bug670333.js]
 [test_bug667818.js]
 [test_cacheflags.js]
 [test_channel_close.js]
@@ -78,23 +94,39 @@ tail =
 [test_content_sniffer.js]
 [test_cookie_header.js]
 [test_data_protocol.js]
 [test_dns_service.js]
 [test_duplicate_headers.js]
 [test_event_sink.js]
 [test_extract_charset_from_content_type.js]
 [test_fallback_no-cache-entry_canceled.js]
+# Bug 675039: test hangs consistently on Android 
+skip-if = os == "android"
 [test_fallback_no-cache-entry_passing.js]
+# Bug 675039: test hangs consistently on Android 
+skip-if = os == "android"
 [test_fallback_redirect-to-different-origin_canceled.js]
+# Bug 675039: test hangs consistently on Android 
+skip-if = os == "android"
 [test_fallback_redirect-to-different-origin_passing.js]
+# Bug 675039: test hangs consistently on Android 
+skip-if = os == "android"
 [test_fallback_request-error_canceled.js]
+# Bug 675039: test hangs consistently on Android 
+skip-if = os == "android"
 [test_fallback_request-error_passing.js]
+# Bug 675039: test hangs consistently on Android 
+skip-if = os == "android"
 [test_fallback_response-error_canceled.js]
+# Bug 675039: test hangs consistently on Android 
+skip-if = os == "android"
 [test_fallback_response-error_passing.js]
+# Bug 675039: test hangs consistently on Android 
+skip-if = os == "android"
 [test_file_partial_inputstream.js]
 [test_file_protocol.js]
 [test_filestreams.js]
 [test_gre_resources.js]
 [test_gzipped_206.js]
 [test_head.js]
 [test_http_headers.js]
 [test_httpcancel.js]
@@ -126,14 +158,16 @@ tail =
 [test_reentrancy.js]
 [test_reopen.js]
 [test_resumable_channel.js]
 [test_resumable_truncate.js]
 [test_safeoutputstream.js]
 [test_simple.js]
 [test_sockettransportsvc_available.js]
 [test_socks.js]
+# Bug 675039: test hangs consistently on Android
+skip-if = os == "android"
 [test_standardurl.js]
 [test_standardurl_port.js]
 [test_streamcopier.js]
 [test_traceable_channel.js]
 [test_unescapestring.js]
 [test_xmlhttprequest.js]
--- a/netwerk/test/urltest.cpp
+++ b/netwerk/test/urltest.cpp
@@ -132,18 +132,19 @@ nsresult writeoutto(const char* i_pURL, 
         output += RESULT();
         output += ',';
         rv = tURL->GetFileBaseName(temp);
         output += RESULT();
         output += ',';
         rv = tURL->GetFileExtension(temp);
         output += RESULT();
         output += ',';
-        rv = tURL->GetParam(temp);
-        output += RESULT();
+        // removed with https://bugzilla.mozilla.org/show_bug.cgi?id=665706
+        // rv = tURL->GetParam(temp); 
+        // output += RESULT();
         output += ',';
         rv = tURL->GetQuery(temp);
         output += RESULT();
         output += ',';
         rv = tURL->GetRef(temp);
         output += RESULT();
         output += ',';
         rv = tURL->GetSpec(temp);
--- a/parser/html/nsHtml5TreeOperation.cpp
+++ b/parser/html/nsHtml5TreeOperation.cpp
@@ -135,17 +135,17 @@ nsHtml5TreeOperation::~nsHtml5TreeOperat
       break;
     default: // keep the compiler happy
       break;
   }
 }
 
 nsresult
 nsHtml5TreeOperation::AppendTextToTextNode(const PRUnichar* aBuffer,
-                                           PRInt32 aLength,
+                                           PRUint32 aLength,
                                            nsIContent* aTextNode,
                                            nsHtml5TreeOpExecutor* aBuilder)
 {
   NS_PRECONDITION(aTextNode, "Got null text node.");
 
   if (aBuilder->HaveNotified(aTextNode)) {
     // This text node has already been notified on, so it's necessary to
     // notify on the append
@@ -167,17 +167,17 @@ nsHtml5TreeOperation::AppendTextToTextNo
   }
 
   return aTextNode->AppendText(aBuffer, aLength, PR_FALSE);
 }
 
 
 nsresult
 nsHtml5TreeOperation::AppendText(const PRUnichar* aBuffer,
-                                 PRInt32 aLength,
+                                 PRUint32 aLength,
                                  nsIContent* aParent,
                                  nsHtml5TreeOpExecutor* aBuilder)
 {
   nsresult rv = NS_OK;
   nsIContent* lastChild = aParent->GetLastChild();
   if (lastChild && lastChild->IsNodeOfType(nsINode::eTEXT)) {
     nsHtml5OtherDocUpdate update(aParent->GetOwnerDoc(),
                                  aBuilder->GetDocument());
@@ -275,29 +275,29 @@ nsHtml5TreeOperation::Perform(nsHtml5Tre
     case eTreeOpAppend: {
       nsIContent* node = *(mOne.node);
       nsIContent* parent = *(mTwo.node);
       return Append(node, parent, aBuilder);
     }
     case eTreeOpDetach: {
       nsIContent* node = *(mOne.node);
       aBuilder->FlushPendingAppendNotifications();
-      nsIContent* parent = node->GetParent();
+      nsCOMPtr<nsIContent> parent = node->GetParent();
       if (parent) {
         nsHtml5OtherDocUpdate update(parent->GetOwnerDoc(),
                                      aBuilder->GetDocument());
         PRUint32 pos = parent->IndexOf(node);
         NS_ASSERTION((pos >= 0), "Element not found as child of its parent");
         rv = parent->RemoveChildAt(pos, PR_TRUE);
         NS_ENSURE_SUCCESS(rv, rv);
       }
       return rv;
     }
     case eTreeOpAppendChildrenToNewParent: {
-      nsIContent* node = *(mOne.node);
+      nsCOMPtr<nsIContent> node = *(mOne.node);
       nsIContent* parent = *(mTwo.node);
       aBuilder->FlushPendingAppendNotifications();
 
       nsHtml5OtherDocUpdate update(parent->GetOwnerDoc(),
                                    aBuilder->GetDocument());
 
       PRUint32 childCount = parent->GetChildCount();
       PRBool didAppend = PR_FALSE;
@@ -491,17 +491,17 @@ nsHtml5TreeOperation::Perform(nsHtml5Tre
           !node->HasAttr(kNameSpaceID_None, nsGkAtoms::form)) {
         formControl->SetForm(formElement);
       }
       return rv;
     }
     case eTreeOpAppendText: {
       nsIContent* parent = *mOne.node;
       PRUnichar* buffer = mTwo.unicharPtr;
-      PRInt32 length = mInt;
+      PRUint32 length = mInt;
       return AppendText(buffer, length, parent, aBuilder);
     }
     case eTreeOpAppendIsindexPrompt: {
       nsIContent* parent = *mOne.node;
       nsXPIDLString prompt;
       nsresult rv =
           nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
                                              "IsIndexPromptWithSpace", prompt);
@@ -513,17 +513,17 @@ nsHtml5TreeOperation::Perform(nsHtml5Tre
         // Don't bother appending a zero-length text node.
         return NS_OK;
       }
       return AppendText(prompt.BeginReading(), len, parent, aBuilder);
     }
     case eTreeOpFosterParentText: {
       nsIContent* stackParent = *mOne.node;
       PRUnichar* buffer = mTwo.unicharPtr;
-      PRInt32 length = mInt;
+      PRUint32 length = mInt;
       nsIContent* table = *mThree.node;
       
       nsIContent* foster = table->GetParent();
 
       if (foster && foster->IsElement()) {
         aBuilder->FlushPendingAppendNotifications();
 
         nsHtml5OtherDocUpdate update(foster->GetOwnerDoc(),
--- a/parser/html/nsHtml5TreeOperation.h
+++ b/parser/html/nsHtml5TreeOperation.h
@@ -312,22 +312,22 @@ class nsHtml5TreeOperation {
       nsAutoString str;
       aAtom->ToString(str);
       return do_GetAtom(str);
     }
 
   private:
 
     nsresult AppendTextToTextNode(const PRUnichar* aBuffer,
-                                  PRInt32 aLength,
+                                  PRUint32 aLength,
                                   nsIContent* aTextNode,
                                   nsHtml5TreeOpExecutor* aBuilder);
 
     nsresult AppendText(const PRUnichar* aBuffer,
-                        PRInt32 aLength,
+                        PRUint32 aLength,
                         nsIContent* aParent,
                         nsHtml5TreeOpExecutor* aBuilder);
 
     nsresult Append(nsIContent* aNode,
                     nsIContent* aParent,
                     nsHtml5TreeOpExecutor* aBuilder);
 
     nsresult AppendToDocument(nsIContent* aNode,
--- a/security/manager/ssl/tests/unit/xpcshell.ini
+++ b/security/manager/ssl/tests/unit/xpcshell.ini
@@ -1,7 +1,13 @@
 [DEFAULT]
 head = 
 tail = 
 
 [test_datasignatureverifier.js]
+# Bug 676972: test hangs consistently on Android
+skip-if = os == "android"
 [test_hash_algorithms.js]
+# Bug 676972: test hangs consistently on Android
+skip-if = os == "android"
 [test_hmac.js]
+# Bug 676972: test hangs consistently on Android
+skip-if = os == "android"
--- a/services/crypto/tests/unit/xpcshell.ini
+++ b/services/crypto/tests/unit/xpcshell.ini
@@ -1,7 +1,9 @@
 [DEFAULT]
 head = head_helpers.js
 tail = 
 
 [test_crypto_crypt.js]
 [test_crypto_deriveKey.js]
 [test_crypto_random.js]
+# Bug 676977: test hangs consistently on Android
+skip-if = os == "android"
--- a/services/sync/modules/engines/history.js
+++ b/services/sync/modules/engines/history.js
@@ -157,16 +157,17 @@ HistoryStore.prototype = {
 
     // Give the uri a GUID if it doesn't have one
     if (create)
       return this.setGUID(uri);
   },
 
   get _visitStm() {
     return this._getStmt(
+      "/* do not warn (bug 599936) */ " +
       "SELECT visit_type type, visit_date date " +
       "FROM moz_historyvisits " +
       "WHERE place_id = (SELECT id FROM moz_places WHERE url = :url) " +
       "ORDER BY date DESC LIMIT 10");
   },
   _visitCols: ["date", "type"],
 
   get _urlStm() {
--- a/services/sync/tests/unit/xpcshell.ini
+++ b/services/sync/tests/unit/xpcshell.ini
@@ -29,17 +29,18 @@ tail =
 [test_forms_tracker.js]
 [test_history_engine.js]
 [test_history_store.js]
 [test_history_tracker.js]
 [test_hmac_error.js]
 [test_interval_triggers.js]
 [test_jpakeclient.js]
 # Bug 618233: this test produces random failures on Windows 7.
-skip-if = os == "win"
+# Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini)
+skip-if = os == "win" || os == "android"
 [test_keys.js]
 [test_load_modules.js]
 [test_log4moz.js]
 [test_notifications.js]
 [test_password_store.js]
 [test_password_tracker.js]
 [test_places_guid_downgrade.js]
 [test_prefs_store.js]
@@ -55,44 +56,49 @@ skip-if = os == "win"
 [test_service_attributes.js]
 [test_service_changePassword.js]
 [test_service_checkAccount.js]
 [test_service_cluster.js]
 [test_service_createAccount.js]
 [test_service_detect_upgrade.js]
 [test_service_filelog.js]
 # Bug 664090: this test persistently fails on Windows opt builds.
-skip-if = os == "win" && !debug
+# Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini)
+skip-if = (os == "win" && !debug) || os == "android"
 [test_service_getStorageInfo.js]
 [test_service_login.js]
 [test_service_migratePrefs.js]
 [test_service_passwordUTF8.js]
 [test_service_persistLogin.js]
 [test_service_startOver.js]
 [test_service_startup.js]
 [test_service_sync_401.js]
 [test_service_sync_checkServerError.js]
 # Bug 604565: this test intermittently hangs on OS X debug builds.
-skip-if = os == "mac" && debug
+# Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini)
+skip-if = (os == "mac" && debug) || os == "android"
 [test_service_sync_locked.js]
 [test_service_sync_remoteSetup.js]
 # Bug 604565: this test intermittently hangs on OS X debug builds.
-skip-if = os == "mac" && debug
+# Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini)
+skip-if = (os == "mac" && debug) || os == "android"
 [test_service_sync_updateEnabledEngines.js]
 # Bug 604565: this test intermittently hangs on OS X debug builds.
-skip-if = os == "mac" && debug
+# Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini)
+skip-if = (os == "mac" && debug) || os == "android"
 [test_service_verifyLogin.js]
 [test_service_wipeClient.js]
 [test_service_wipeServer.js]
 [test_status.js]
 [test_status_checkSetup.js]
 [test_syncengine.js]
 [test_syncengine_sync.js]
 # Bug 604565: this test intermittently hangs on OS X debug builds.
-skip-if = os == "mac" && debug
+# Bug 676978: test hangs on Android (see also testing/xpcshell/xpcshell.ini)
+skip-if = (os == "mac" && debug) || os == "android"
 [test_syncscheduler.js]
 [test_syncstoragerequest.js]
 [test_tab_engine.js]
 [test_tab_store.js]
 [test_tab_tracker.js]
 [test_tracker_addChanged.js]
 [test_upgrade_old_sync_key.js]
 [test_utils_asyncChain.js]
--- a/storage/test/unit/xpcshell.ini
+++ b/storage/test/unit/xpcshell.ini
@@ -2,16 +2,18 @@
 head = head_storage.js
 tail = 
 
 [test_bug-365166.js]
 [test_bug-393952.js]
 [test_bug-429521.js]
 [test_bug-444233.js]
 [test_chunk_growth.js]
+# Bug 676981: test fails consistently on Android
+fail-if = os == "android"
 [test_connection_executeAsync.js]
 [test_js_helpers.js]
 [test_levenshtein.js]
 [test_like.js]
 [test_like_escape.js]
 [test_locale_collation.js]
 [test_page_size_is_32k.js]
 [test_sqlite_secure_delete.js]
@@ -25,8 +27,10 @@ tail =
 [test_storage_service.js]
 [test_storage_service_unshared.js]
 [test_storage_statement.js]
 [test_storage_statement_wrapper.js]
 [test_storage_value_array.js]
 [test_unicode.js]
 [test_vacuum.js]
 [test_telemetry_vfs.js]
+# Bug 676981: test fails consistently on Android
+# fail-if = os == "android"
--- a/testing/testsuite-targets.mk
+++ b/testing/testsuite-targets.mk
@@ -196,16 +196,39 @@ xpcshell-tests:
 	  $(topsrcdir)/testing/xpcshell/runxpcshelltests.py \
 	  --manifest=$(DEPTH)/_tests/xpcshell/xpcshell.ini \
 	  --build-info-json=$(DEPTH)/mozinfo.json \
 	  --no-logfiles \
           $(SYMBOLS_PATH) \
 	  $(TEST_PATH_ARG) $(EXTRA_TEST_ARGS) \
 	  $(LIBXUL_DIST)/bin/xpcshell
 
+REMOTE_XPCSHELL = \
+	rm -f ./$@.log && \
+	$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
+	  -I$(topsrcdir)/build \
+	  -I$(topsrcdir)/build/mobile \
+	  $(topsrcdir)/testing/xpcshell/remotexpcshelltests.py \
+	  --manifest=$(DEPTH)/_tests/xpcshell/xpcshell.ini \
+	  --build-info-json=$(DEPTH)/mozinfo.json \
+	  --no-logfiles \
+	  --dm_trans=$(DM_TRANS) \
+	  --deviceIP=${TEST_DEVICE} \
+	  --objdir=$(DEPTH) \
+	  $(SYMBOLS_PATH) \
+	  $(TEST_PATH_ARG) $(EXTRA_TEST_ARGS)
+
+xpcshell-tests-remote: DM_TRANS?=adb
+xpcshell-tests-remote:
+	@if [ "${TEST_DEVICE}" != "" -o "$(DM_TRANS)" = "adb" ]; \
+          then $(call REMOTE_XPCSHELL); $(CHECK_TEST_ERROR); \
+        else \
+          echo "please prepare your host with environment variables for TEST_DEVICE"; \
+        fi
+
 # install and run the mozmill tests
 $(DEPTH)/_tests/mozmill:
 	$(MAKE) -C $(DEPTH)/testing/mozmill install-develop PKG_STAGE=../../_tests
 	$(PYTHON) $(topsrcdir)/testing/mozmill/installmozmill.py --develop $(DEPTH)/_tests/mozmill
 
 MOZMILL_TEST_PATH = $(DEPTH)/_tests/mozmill/tests/firefox
 mozmill: TEST_PATH?=$(MOZMILL_TEST_PATH)
 mozmill: $(DEPTH)/_tests/mozmill
--- a/testing/xpcshell/remotexpcshelltests.py
+++ b/testing/xpcshell/remotexpcshelltests.py
@@ -31,270 +31,307 @@
 # use your version of this file under the terms of the MPL, indicate your
 # decision by deleting the provisions above and replace them with the notice
 # and other provisions required by the GPL or the LGPL. If you do not delete
 # the provisions above, a recipient may use your version of this file under
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ***** END LICENSE BLOCK ***** */
 
-import re, sys, os, os.path, logging, shutil, signal
-from glob import glob
-from optparse import OptionParser
-from subprocess import Popen, PIPE, STDOUT
-from tempfile import mkdtemp
-
+import re, sys, os
 import runxpcshelltests as xpcshell
 from automationutils import *
-import devicemanager
+import devicemanager, devicemanagerADB, devicemanagerSUT
 
+# A specialization of XPCShellTests that runs tests on an Android device
+# via devicemanager.
 class XPCShellRemote(xpcshell.XPCShellTests, object):
 
-    def __init__(self, devmgr):
+    def __init__(self, devmgr, options, args):
+        xpcshell.XPCShellTests.__init__(self)
+        self.options = options
         self.device = devmgr
-        self.testRoot = "/tests/xpcshell"
-        xpcshell.XPCShellTests.__init__(self)
-        self.profileDir = self.testRoot + '/profile'
-        self.device.mkDir(self.profileDir)
+        self.pathMapping = []
+        self.remoteTestRoot = self.device.getTestRoot("xpcshell")
+        # Terse directory names are used here ("b" for a binaries directory)
+        # to minimize the length of the command line used to execute
+        # xpcshell on the remote device. adb has a limit to the number
+        # of characters used in a shell command, and the xpcshell command
+        # line can be quite complex.
+        self.remoteBinDir = self.remoteJoin(self.remoteTestRoot, "b")
+        self.remoteScriptsDir = self.remoteTestRoot
+        self.remoteComponentsDir = self.remoteJoin(self.remoteTestRoot, "c")
+        self.profileDir = self.remoteJoin(self.remoteTestRoot, "p")
+        if options.setup:
+          self.setupUtilities()
+          self.setupTestDir()
+        self.remoteAPK = self.remoteJoin(self.remoteBinDir, os.path.basename(options.localAPK))
+        self.remoteDebugger = options.debugger
+        self.remoteDebuggerArgs = options.debuggerArgs  
 
-    #todo: figure out the remote version of this, only used for debuggerInfo
-    def getcwd(self):
-        return "/tests/"
-        
-    def readManifest(self, manifest):
-        """Given a manifest file containing a list of test directories,
-        return a list of absolute paths to the directories contained within."""
+    def remoteJoin(self, path1, path2):
+        joined = os.path.join(path1, path2)
+        joined = joined.replace('\\', '/')
+        return joined
+
+    def remoteForLocal(self, local):
+        for mapping in self.pathMapping:
+          if (os.path.abspath(mapping.local) == os.path.abspath(local)):
+            return mapping.remote
+        return local
 
-        manifestdir = self.testRoot + '/tests'
-        testdirs = []
-        try:
-            f = self.device.getFile(manifest, "temp.txt")
-            for line in f.split():
-                dir = line.rstrip()
-                path = manifestdir + '/' + dir
-                testdirs.append(path)
-            f.close()
-        except:
-            pass # just eat exceptions
-        return testdirs
+    def setupUtilities(self):
+        remotePrefDir = self.remoteJoin(self.remoteBinDir, "defaults/pref")
+        if (not self.device.dirExists(remotePrefDir)):
+          self.device.mkDirs(self.remoteJoin(remotePrefDir, "extra"))
+        if (not self.device.dirExists(self.remoteScriptsDir)):
+          self.device.mkDir(self.remoteScriptsDir)
+        if (not self.device.dirExists(self.remoteComponentsDir)):
+          self.device.mkDir(self.remoteComponentsDir)
+
+        local = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'head.js')
+        self.device.pushFile(local, self.remoteScriptsDir)
 
-    def verifyFilePath(self, fileName):
-        # approot - path to root of application - firefox or fennec
-        # xreroot - path to xulrunner binaries - firefox or fennec/xulrunner
-        # xpcshell - full or relative path to xpcshell binary
-        #given fileName, returns full path of existing file
-        if (self.device.fileExists(fileName)):
-            return fileName
-        
-        fileName = self.device.getAppRoot() + '/xulrunner/' + fileName.split('/')[-1]
-        if (self.device.fileExists(fileName)):
-            return fileName
-        
-        fileName = self.device.getAppRoot() + '/' + fileName.split('/')[-1]
-        if (not self.device.fileExists(fileName)):
-            raise devicemanager.FileError("No File found for: " + str(fileName))
+        localBin = os.path.join(self.options.objdir, "dist/bin")
+        if not os.path.exists(localBin):
+          localBin = os.path.join(self.options.objdir, "bin")
+          if not os.path.exists(localBin):
+            print >>sys.stderr, "Error: could not find bin in objdir"
+            sys.exit(1)
+
+        local = os.path.join(localBin, "xpcshell")
+        self.device.pushFile(local, self.remoteBinDir)
 
-        return fileName
+        local = os.path.join(localBin, "plugin-container")
+        self.device.pushFile(local, self.remoteBinDir)
+
+        local = os.path.join(localBin, "components/httpd.js")
+        self.device.pushFile(local, self.remoteComponentsDir)
+
+        local = os.path.join(localBin, "components/httpd.manifest")
+        self.device.pushFile(local, self.remoteComponentsDir)
+
+        local = os.path.join(localBin, "components/test_necko.xpt")
+        self.device.pushFile(local, self.remoteComponentsDir)
+
+        self.device.pushFile(self.options.localAPK, self.remoteBinDir)
 
-    def verifyDirPath(self, fileName):
-        # approot - path to root of application - firefox or fennec
-        # xreroot - path to xulrunner binaries - firefox or fennec/xulrunner
-        # xpcshell - full or relative path to xpcshell binary
-        #given fileName, returns full path of existing file
-        if (self.device.dirExists(fileName)):
-            return fileName
-        
-        fileName = self.device.getAppRoot() + '/' + fileName.split('/')[-1]
-        if (self.device.dirExists(fileName)):
-            return fileName
-        
-        fileName = self.device.getDeviceRoot() + '/' + fileName.split('/')[-1]
-        if (not self.device.dirExists(fileName)):
-            raise devicemanager.FileError("No Dir found for: " + str(fileName))
-        return fileName
+        localLib = os.path.join(self.options.objdir, "dist/fennec")
+        if not os.path.exists(localLib):
+          localLib = os.path.join(self.options.objdir, "fennec/lib")
+          if not os.path.exists(localLib):
+            print >>sys.stderr, "Error: could not find libs in objdir"
+            sys.exit(1)
+
+        for file in os.listdir(localLib):
+          if (file.endswith(".so")):
+            self.device.pushFile(os.path.join(localLib, file), self.remoteBinDir)
 
-    def setAbsPath(self):
-        #testharnessdir is used for head.js
-        self.testharnessdir = "/tests/xpcshell/"
+    def setupTestDir(self):
+        xpcDir = os.path.join(self.options.objdir, "_tests/xpcshell")
+        self.device.pushDir(xpcDir, self.remoteScriptsDir)
 
-        # If the file exists then we have a full path (no notion of cwd)
-        self.xpcshell = self.verifyFilePath(self.xpcshell)
-        if self.xrePath is None:
-            # If no xrePath, assume it is the directory containing xpcshell
-            self.xrePath = '/'.join(self.xpcshell.split('/')[:-1])
-        else:
-            self.xrePath = self.verifyDirPath(self.xrePath)
-
-        # we assume that httpd.js lives in components/ relative to xpcshell
-        self.httpdJSPath = self.xrePath + '/components/httpd.js'
+    def buildTestList(self):
+        xpcshell.XPCShellTests.buildTestList(self)
+        uniqueTestPaths = set([])
+        for test in self.alltests:
+          uniqueTestPaths.add(test['here'])
+        for testdir in uniqueTestPaths:
+          xpcDir = os.path.join(self.options.objdir, "_tests/xpcshell")
+          abbrevTestDir = os.path.relpath(testdir, xpcDir)
+          remoteScriptDir = self.remoteJoin(self.remoteScriptsDir, abbrevTestDir)
+          self.pathMapping.append(PathMapping(testdir, remoteScriptDir))
 
     def buildXpcsCmd(self, testdir):
-        # <head.js> has to be loaded by xpchell: it can't load itself.
-        self.env["XPCSHELL_TEST_PROFILE_DIR"] = self.profileDir
-        self.xpcsCmd = [self.xpcshell, '-g', self.xrePath, '-v', '170', '-j', '-s', \
-                        "--environ:CWD='" + testdir + "'", \
-                        "--environ:XPCSHELL_TEST_PROFILE_DIR='" + self.env["XPCSHELL_TEST_PROFILE_DIR"] + "'", \
-                        '-e', 'const _HTTPD_JS_PATH = \'%s\';' % self.httpdJSPath,
-                        '-f', self.testharnessdir + '/head.js']
+        self.xpcsCmd = [
+           self.remoteJoin(self.remoteBinDir, "xpcshell"),
+           '-r', self.remoteJoin(self.remoteComponentsDir, 'httpd.manifest'),
+           '--greomni', self.remoteAPK,
+           '-j', '-s',
+           '-e', 'const _HTTPD_JS_PATH = "%s";' % self.remoteJoin(self.remoteComponentsDir, 'httpd.js'),
+           '-e', 'const _HEAD_JS_PATH = "%s";' % self.remoteJoin(self.remoteScriptsDir, 'head.js'),
+           '-f', self.remoteScriptsDir+'/head.js']
 
-        if self.debuggerInfo:
-            self.xpcsCmd = [self.debuggerInfo["path"]] + self.debuggerInfo["args"] + self.xpcsCmd
+        if self.remoteDebugger:
+          # for example, "/data/local/gdbserver" "localhost:12345"
+          self.xpcsCmd = [
+            self.remoteDebugger, 
+            self.remoteDebuggerArgs, 
+            self.xpcsCmd]
 
-    def getHeadFiles(self, testdir):
-        # get the list of head and tail files from the directory
-        testHeadFiles = []
-        for f in self.device.listFiles(testdir):
-            hdmtch = re.compile("head_.*\.js")
-            if (hdmtch.match(f)):
-                testHeadFiles += [(testdir + '/' + f).replace('/', '//')]
-                
-        return sorted(testHeadFiles)
-                
-    def getTailFiles(self, testdir):
-        testTailFiles = []
-        # Tails are executed in the reverse order, to "match" heads order,
-        # as in "h1-h2-h3 then t3-t2-t1".
-        for f in self.device.listFiles(testdir):
-            tlmtch = re.compile("tail_.*\.js")
-            if (tlmtch.match(f)):
-                testTailFiles += [(testdir + '/' + f).replace('/', '//')]
-        return reversed(sorted(testTailFiles))
+    def getHeadFiles(self, test):
+        self.remoteHere = self.remoteForLocal(test['here'])
+        return [f.strip() for f in sorted(test['head'].split(' ')) if self.device.fileExists(self.remoteJoin(self.remoteHere, f))]
+    
+    def getTailFiles(self, test):
+        return [f.strip() for f in sorted(test['tail'].split(' ')) if self.device.fileExists(self.remoteJoin(self.remoteHere, f))]
         
-    def getTestFiles(self, testdir):
-        testfiles = []
-        # if a single test file was specified, we only want to execute that test
-        for f in self.device.listFiles(testdir):
-            tstmtch = re.compile("test_.*\.js")
-            if (tstmtch.match(f)):
-                testfiles += [(testdir + '/' + f).replace('/', '//')]
-        
-        for f in testfiles:
-            if (self.singleFile == f.split('/')[-1]):
-                return [(testdir + '/' + f).replace('/', '//')]
-            else:
-                pass
-        return testfiles
+    def buildCmdTestFile(self, name):
+        remoteDir = self.remoteForLocal(os.path.dirname(name))
+        if remoteDir == self.remoteHere:
+          remoteName = os.path.basename(name)
+        else:
+          remoteName = self.remoteJoin(remoteDir, os.path.basename(name))
+        return ['-e', 'const _TEST_FILE = ["%s"];' %
+                 replaceBackSlashes(remoteName)]
 
     def setupProfileDir(self):
         self.device.removeDir(self.profileDir)
         self.device.mkDir(self.profileDir)
-        self.env["XPCSHELL_TEST_PROFILE_DIR"] = self.profileDir
+        if self.interactive or self.singleFile:
+          self.log.info("TEST-INFO | profile dir is %s" % self.profileDir)
         return self.profileDir
 
-    def setupLeakLogging(self):
-        filename = "runxpcshelltests_leaks.log"
-        
-        # Enable leaks (only) detection to its own log file.
-        leakLogFile = self.profileDir + '/' + filename
-        self.env["XPCOM_MEM_LEAK_LOG"] = leakLogFile
-        return leakLogFile
+    def launchProcess(self, cmd, stdout, stderr, env, cwd):
+        # Some xpcshell arguments contain characters that are interpretted
+        # by the adb shell; enclose these arguments in quotes.
+        index = 0
+        for part in cmd:
+          if (part.find(" ")>=0 or part.find("(")>=0 or part.find(")")>=0 or part.find("\"")>=0):
+            part = '\''+part+'\''
+            cmd[index] = part
+          index = index + 1
+
+        xpcshell = self.remoteJoin(self.remoteBinDir, "xpcshell")
 
-    def launchProcess(self, cmd, stdout, stderr, env, cwd):
-        print "launching : " + " ".join(cmd)
-        proc = self.device.launchProcess(cmd, cwd=cwd)
+        shellArgs = "cd "+self.remoteHere
+        shellArgs += "; LD_LIBRARY_PATH="+self.remoteBinDir
+        shellArgs += "; export CACHE_PATH="+self.remoteBinDir
+        shellArgs += "; export GRE_HOME="+self.device.getAppRoot()
+        shellArgs += "; export XPCSHELL_TEST_PROFILE_DIR="+self.profileDir
+        shellArgs += "; "+xpcshell+" "
+        shellArgs += " ".join(cmd[1:])
+
+        if self.verbose:
+          self.log.info(shellArgs)
+
+        # If the adb version of devicemanager is used and the arguments passed
+        # to adb exceed ~1024 characters, the command may not execute.
+        if len(shellArgs) > 1000:
+          self.log.info("adb command length is excessive and may cause failure")
+
+        proc = self.device.runCmd(["shell", shellArgs])
         return proc
 
-    def setSignal(self, proc, sig1, sig2):
-        self.device.signal(proc, sig1, sig2)
-
     def communicate(self, proc):
-        return self.device.communicate(proc)
+        return proc.communicate()
 
     def removeDir(self, dirname):
         self.device.removeDir(dirname)
 
     def getReturnCode(self, proc):
-        return self.device.getReturnCode(proc)
+        return proc.returncode
 
     #TODO: consider creating a separate log dir.  We don't have the test file structure,
     #      so we use filename.log.  Would rather see ./logs/filename.log
-    def createLogFile(self, test, stdout):
+    def createLogFile(self, test, stdout, leakLogs):
         try:
             f = None
             filename = test.replace('\\', '/').split('/')[-1] + ".log"
             f = open(filename, "w")
             f.write(stdout)
 
-            if os.path.exists(self.leakLogFile):
-                leaks = open(self.leakLogFile, "r")
+            for leakLog in leakLogs:
+              if os.path.exists(leakLog):
+                leaks = open(leakLog, "r")
                 f.write(leaks.read())
                 leaks.close()
         finally:
             if f <> None:
                 f.close()
 
-    #NOTE: the only difference between this and parent is the " vs ' arond the filename
-    def buildCmdHead(self, headfiles, tailfiles, xpcscmd):
-        cmdH = ", ".join(['\'' + f.replace('\\', '/') + '\''
-                       for f in headfiles])
-        cmdT = ", ".join(['\'' + f.replace('\\', '/') + '\''
-                       for f in tailfiles])
-        cmdH = xpcscmd + \
-                ['-e', 'const _HEAD_FILES = [%s];' % cmdH] + \
-                ['-e', 'const _TAIL_FILES = [%s];' % cmdT]
-        return cmdH
-
 class RemoteXPCShellOptions(xpcshell.XPCShellOptions):
 
-  def __init__(self):
-    xpcshell.XPCShellOptions.__init__(self)
-    self.add_option("--device",
-                    type="string", dest="device", default='',
-                    help="ip address for the device")
+    def __init__(self):
+        xpcshell.XPCShellOptions.__init__(self)
+        defaults = {}
+
+        self.add_option("--deviceIP", action="store",
+                        type = "string", dest = "deviceIP",
+                        help = "ip address of remote device to test")
+        defaults["deviceIP"] = None
+ 
+        self.add_option("--devicePort", action="store",
+                        type = "string", dest = "devicePort",
+                        help = "port of remote device to test")
+        defaults["devicePort"] = 20701
 
+        self.add_option("--dm_trans", action="store",
+                        type = "string", dest = "dm_trans",
+                        help = "the transport to use to communicate with device: [adb|sut]; default=sut")
+        defaults["dm_trans"] = "sut"
+ 
+        self.add_option("--objdir", action="store",
+                        type = "string", dest = "objdir",
+                        help = "local objdir, containing xpcshell binaries")
+        defaults["objdir"] = None
+ 
+        self.add_option("--apk", action="store",
+                        type = "string", dest = "localAPK",
+                        help = "local path to Fennec APK")
+        defaults["localAPK"] = None
+
+        self.add_option("--noSetup", action="store_false",
+                        dest = "setup",
+                        help = "do not copy any files to device (to be used only if device is already setup)")
+        defaults["setup"] = True
+
+        self.set_defaults(**defaults)
+
+class PathMapping:
+
+    def __init__(self, localDir, remoteDir):
+        self.local = localDir
+        self.remote = remoteDir
 
 def main():
 
-  parser = RemoteXPCShellOptions()
-  options, args = parser.parse_args()
+    dm_none = devicemanagerADB.DeviceManagerADB(None, None)
+    parser = RemoteXPCShellOptions()
+    options, args = parser.parse_args()
 
-  if len(args) < 2 and options.manifest is None or \
-     (len(args) < 1 and options.manifest is not None):
-     print "len(args): " + str(len(args))
-     print >>sys.stderr, """Usage: %s <path to xpcshell> <test dirs>
-           or: %s --manifest=test.manifest <path to xpcshell>""" % (sys.argv[0],
-                                                           sys.argv[0])
-     sys.exit(1)
+    if len(args) < 1 and options.manifest is None:
+      print >>sys.stderr, """Usage: %s <test dirs>
+           or: %s --manifest=test.manifest """ % (sys.argv[0], sys.argv[0])
+      sys.exit(1)
 
-  if (options.device == ''):
-    print >>sys.stderr, "Error: Please provide an ip address for the remote device with the --device option"
-    sys.exit(1)
-
+    if (options.dm_trans == "adb"):
+      if (options.deviceIP):
+        dm = devicemanagerADB.DeviceManagerADB(options.deviceIP, options.devicePort)
+      else:
+        dm = dm_none
+    else:
+      dm = devicemanagerSUT.DeviceManagerSUT(options.deviceIP, options.devicePort)
+      if (options.deviceIP == None):
+        print "Error: you must provide a device IP to connect to via the --device option"
+        sys.exit(1)
 
-  dm = devicemanager.DeviceManager(options.device, 20701)
-  xpcsh = XPCShellRemote(dm)
-  debuggerInfo = getDebuggerInfo(xpcsh.oldcwd, options.debugger, options.debuggerArgs,
-    options.debuggerInteractive);
-
-  if options.interactive and not options.testPath:
-    print >>sys.stderr, "Error: You must specify a test filename in interactive mode!"
-    sys.exit(1)
+    if options.interactive and not options.testPath:
+      print >>sys.stderr, "Error: You must specify a test filename in interactive mode!"
+      sys.exit(1)
 
-  # Zip up the xpcshell directory: 7z a <zipName> xpcshell/*, assuming we are in the xpcshell directory
-  # TODO: ensure the system has 7z, this is adding a new dependency to the overall system
-  zipName = 'xpcshell.7z'
-  try:
-    Popen(['7z', 'a', zipName, '../xpcshell']).wait()
-  except:
-    print "to run these tests remotely, we require 7z to be installed and in your path"
-    sys.exit(1)
+    if not options.objdir:
+      print >>sys.stderr, "Error: You must specify an objdir"
+      sys.exit(1)
 
-  if dm.pushFile(zipName, '/tests/xpcshell.7z') == None:
-     raise devicemanager.FileError("failed to copy xpcshell.7z to device")
-  if dm.unpackFile('xpcshell.7z') == None:
-     raise devicemanager.FileError("failed to unpack xpcshell.7z on the device")
+    if not options.localAPK:
+      for file in os.listdir(os.path.join(options.objdir, "dist")):
+        if (file.endswith(".apk") and file.startswith("fennec")):
+          options.localAPK = os.path.join(options.objdir, "dist")
+          options.localAPK = os.path.join(options.localAPK, file)
+          print >>sys.stderr, "using APK: " + options.localAPK
+          break
+      
+    if not options.localAPK:
+      print >>sys.stderr, "Error: please specify an APK"
+      sys.exit(1)
 
-  if not xpcsh.runTests(args[0],
-                        xrePath=options.xrePath,
-                        symbolsPath=options.symbolsPath,
-                        manifest=options.manifest,
-                        testdirs=args[1:],
-                        testPath=options.testPath,
-                        interactive=options.interactive,
-                        logfiles=options.logfiles,
-                        debuggerInfo=debuggerInfo):
-    sys.exit(1)
+    xpcsh = XPCShellRemote(dm, options, args)
+
+    if not xpcsh.runTests(xpcshell='xpcshell', 
+                          testdirs=args[0:], 
+                          **options.__dict__):
+      sys.exit(1)
+
 
 if __name__ == '__main__':
   main()
 
-
-
--- a/testing/xpcshell/runxpcshelltests.py
+++ b/testing/xpcshell/runxpcshelltests.py
@@ -256,36 +256,36 @@ class XPCShellTests(object):
         self.testPath = self.testPath.rstrip("/")
 
 
   def getHeadFiles(self, test):
     """
       test['head'] is a whitespace delimited list of head files.
       return the list of head files as paths including the subdir if the head file exists
 
-      On a remote system, this is overloaded to list files in a remote directory structure.
+      On a remote system, this may be overloaded to list files in a remote directory structure.
     """
     return [os.path.join(test['here'], f).strip() for f in sorted(test['head'].split(' ')) if os.path.isfile(os.path.join(test['here'], f))]
 
   def getTailFiles(self, test):
     """
       test['tail'] is a whitespace delimited list of head files.
       return the list of tail files as paths including the subdir if the tail file exists
 
-      On a remote system, this is overloaded to list files in a remote directory structure.
+      On a remote system, this may be overloaded to list files in a remote directory structure.
     """
     return [os.path.join(test['here'], f).strip() for f in sorted(test['tail'].split(' ')) if os.path.isfile(os.path.join(test['here'], f))]
 
   def setupProfileDir(self):
     """
       Create a temporary folder for the profile and set appropriate environment variables.
       When running check-interactive and check-one, the directory is well-defined and
       retained for inspection once the tests complete.
 
-      On a remote system, we overload this to use a remote path structure.
+      On a remote system, this may be overloaded to use a remote path structure.
     """
     if self.interactive or self.singleFile:
       profileDir = os.path.join(gettempdir(), self.profileName, "xpcshellprofile")
       try:
         # This could be left over from previous runs
         self.removeDir(profileDir)
       except:
         pass
@@ -296,17 +296,17 @@ class XPCShellTests(object):
     if self.interactive or self.singleFile:
       self.log.info("TEST-INFO | profile dir is %s" % profileDir)
     return profileDir
 
   def setupLeakLogging(self):
     """
       Enable leaks (only) detection to its own log file and set environment variables.
 
-      On a remote system, we overload this to use a remote filename and path structure
+      On a remote system, this may be overloaded to use a remote filename and path structure
     """
     filename = "runxpcshelltests_leaks.log"
 
     leakLogFile = os.path.join(self.profileDir,  filename)
     self.env["XPCOM_MEM_LEAK_LOG"] = leakLogFile
     return leakLogFile
 
   def launchProcess(self, cmd, stdout, stderr, env, cwd):
@@ -376,22 +376,30 @@ class XPCShellTests(object):
                    for f in headfiles])
     cmdT = ", ".join(['"' + replaceBackSlashes(f) + '"'
                    for f in tailfiles])
     return xpcscmd + \
             ['-e', 'const _SERVER_ADDR = "localhost"',
              '-e', 'const _HEAD_FILES = [%s];' % cmdH,
              '-e', 'const _TAIL_FILES = [%s];' % cmdT]
 
+  def buildCmdTestFile(self, name):
+    """
+      Build the command line arguments for the test file.
+      On a remote system, this may be overloaded to use a remote path structure.
+    """
+    return ['-e', 'const _TEST_FILE = ["%s"];' %
+              replaceBackSlashes(name)]
+
   def runTests(self, xpcshell, xrePath=None, appPath=None, symbolsPath=None,
                manifest=None, testdirs=[], testPath=None,
                interactive=False, verbose=False, keepGoing=False, logfiles=True,
                thisChunk=1, totalChunks=1, debugger=None,
                debuggerArgs=None, debuggerInteractive=False,
-               profileName=None, mozInfo=None):
+               profileName=None, mozInfo=None, **otherOptions):
     """Run xpcshell tests.
 
     |xpcshell|, is the xpcshell executable to use to run the tests.
     |xrePath|, if provided, is the path to the XRE to use.
     |appPath|, if provided, is the path to an application directory.
     |symbolsPath|, if provided is the path to a directory containing
       breakpad symbols for processing crashes in tests.
     |manifest|, if provided, is a file containing a list of
@@ -405,16 +413,17 @@ class XPCShellTests(object):
       be printed always
     |logfiles|, if set to False, indicates not to save output to log files.
       Non-interactive only option.
     |debuggerInfo|, if set, specifies the debugger and debugger arguments
       that will be used to launch xpcshell.
     |profileName|, if set, specifies the name of the application for the profile
       directory if running only a subset of tests.
     |mozInfo|, if set, specifies specifies build configuration information, either as a filename containing JSON, or a dict.
+    |otherOptions| may be present for the convenience of subclasses
     """
 
     global gotSIGINT 
 
     self.xpcshell = xpcshell
     self.xrePath = xrePath
     self.appPath = appPath
     self.symbolsPath = symbolsPath
@@ -486,18 +495,17 @@ class XPCShellTests(object):
       testTailFiles = self.getTailFiles(test)
       cmdH = self.buildCmdHead(testHeadFiles, testTailFiles, self.xpcsCmd)
 
       # create a temp dir that the JS harness can stick a profile in
       self.profileDir = self.setupProfileDir()
       self.leakLogFile = self.setupLeakLogging()
 
       # The test file will have to be loaded after the head files.
-      cmdT = ['-e', 'const _TEST_FILE = ["%s"];' %
-                replaceBackSlashes(name)]
+      cmdT = self.buildCmdTestFile(name)
 
       try:
         self.log.info("TEST-INFO | %s | running test ..." % name)
         startTime = time.time()
 
         proc = self.launchProcess(cmdH + cmdT + self.xpcsRunArgs,
                     stdout=pStdout, stderr=pStderr, env=self.env, cwd=testdir)
 
@@ -510,18 +518,19 @@ class XPCShellTests(object):
 
         if interactive:
           # Not sure what else to do here...
           return True
 
         def print_stdout(stdout):
           """Print stdout line-by-line to avoid overflowing buffers."""
           self.log.info(">>>>>>>")
-          for line in stdout.splitlines():
-            self.log.info(line)
+          if (stdout):
+            for line in stdout.splitlines():
+              self.log.info(line)
           self.log.info("<<<<<<<")
 
         result = not ((self.getReturnCode(proc) != 0) or
                       (stdout and re.search("^((parent|child): )?TEST-UNEXPECTED-",
                                             stdout, re.MULTILINE)) or
                       (stdout and re.search(": SyntaxError:", stdout,
                                             re.MULTILINE)))
 
--- a/testing/xpcshell/xpcshell.ini
+++ b/testing/xpcshell/xpcshell.ini
@@ -1,25 +1,26 @@
 [include:chrome/test/unit/xpcshell.ini]
 [include:intl/locale/tests/unit/xpcshell.ini]
 [include:netwerk/cookie/test/unit/xpcshell.ini]
 [include:modules/libjar/zipwriter/test/unit/xpcshell.ini]
 [include:uriloader/exthandler/tests/unit/xpcshell.ini]
 [include:parser/xml/test/unit/xpcshell.ini]
 [include:modules/libpr0n/test/unit/xpcshell.ini]
-[include:modules/plugin/test/unit/xpcshell.ini]
 [include:dom/plugins/test/unit/xpcshell.ini]
 [include:dom/src/json/test/unit/xpcshell.ini]
 [include:dom/tests/unit/xpcshell.ini]
 [include:content/xtf/test/unit/xpcshell.ini]
 [include:docshell/test/unit/xpcshell.ini]
 [include:embedding/tests/unit/xpcshell.ini]
 [include:toolkit/components/commandlines/test/unit/xpcshell.ini]
 [include:toolkit/components/contentprefs/tests/unit/xpcshell.ini]
 [include:toolkit/components/passwordmgr/test/unit/xpcshell.ini]
+# Bug 676989: tests hang on Android
+skip-if = os == "android"
 [include:toolkit/components/places/tests/migration/xpcshell.ini]
 [include:toolkit/components/places/tests/autocomplete/xpcshell.ini]
 [include:toolkit/components/places/tests/expiration/xpcshell.ini]
 [include:toolkit/components/places/tests/sync/xpcshell.ini]
 [include:toolkit/components/places/tests/bookmarks/xpcshell.ini]
 [include:toolkit/components/places/tests/queries/xpcshell.ini]
 [include:toolkit/components/places/tests/unit/xpcshell.ini]
 [include:toolkit/components/places/tests/network/xpcshell.ini]
@@ -54,16 +55,18 @@
 [include:gfx/tests/unit/xpcshell.ini]
 [include:widget/tests/unit/xpcshell.ini]
 [include:content/base/test/unit/xpcshell.ini]
 [include:content/test/unit/xpcshell.ini]
 [include:toolkit/components/url-classifier/tests/unit/xpcshell.ini]
 [include:services/crypto/tests/unit/xpcshell.ini]
 [include:services/crypto/components/tests/unit/xpcshell.ini]
 [include:services/sync/tests/unit/xpcshell.ini]
+# Bug 676978: tests hang on Android 
+skip-if = os == "android"
 [include:browser/components/dirprovider/tests/unit/xpcshell.ini]
 [include:browser/components/feeds/test/unit/xpcshell.ini]
 [include:browser/components/places/tests/unit/xpcshell.ini]
 [include:browser/components/privatebrowsing/test/unit/xpcshell.ini]
 [include:browser/components/shell/test/unit/xpcshell.ini]
 [include:extensions/spellcheck/hunspell/tests/unit/xpcshell.ini]
 [include:toolkit/components/search/tests/xpcshell/xpcshell.ini]
 [include:toolkit/mozapps/shared/test/unit/xpcshell.ini]
--- a/toolkit/components/ctypes/tests/unit/xpcshell.ini
+++ b/toolkit/components/ctypes/tests/unit/xpcshell.ini
@@ -1,5 +1,7 @@
 [DEFAULT]
 head = 
 tail = 
 
 [test_jsctypes.js]
+# Bug 676989: test fails consistently on Android
+fail-if = os == "android"
--- a/toolkit/components/downloads/test/unit/xpcshell.ini
+++ b/toolkit/components/downloads/test/unit/xpcshell.ini
@@ -6,18 +6,22 @@ tail =
 [test_bug_384744.js]
 [test_bug_395092.js]
 [test_bug_401430.js]
 [test_bug_401582.js]
 [test_bug_406857.js]
 [test_bug_409179.js]
 [test_bug_420230.js]
 [test_cancel_download_files_removed.js]
+# Bug 676989: test hangs consistently on Android
+skip-if = os == "android"
 [test_download_manager.js]
 [test_download_samename.js]
+# Bug 676989: test hangs consistently on Android
+skip-if = os == "android" 
 [test_history_expiration.js]
 [test_memory_db_support.js]
 [test_offline_support.js]
 [test_old_download_files_removed.js]
 [test_privatebrowsing.js]
 [test_privatebrowsing_cancel.js]
 [test_removeDownloadsByTimeframe.js]
 [test_resume.js]
--- a/toolkit/components/places/nsNavBookmarks.cpp
+++ b/toolkit/components/places/nsNavBookmarks.cpp
@@ -62,16 +62,22 @@
 #include "mozilla/FunctionTimer.h"
 #include "mozilla/Util.h"
 
 #define BOOKMARKS_TO_KEYWORDS_INITIAL_CACHE_SIZE 64
 #define RECENT_BOOKMARKS_INITIAL_CACHE_SIZE 10
 // Threashold to expire old bookmarks if the initial cache size is exceeded.
 #define RECENT_BOOKMARKS_THRESHOLD PRTime((PRInt64)1 * 60 * PR_USEC_PER_SEC)
 
+#define BEGIN_CRITICAL_BOOKMARK_CACHE_SECTION(_itemId_) \
+  mRecentBookmarksCache.RemoveEntry(_itemId_)
+
+#define END_CRITICAL_BOOKMARK_CACHE_SECTION(_itemId_) \
+  MOZ_ASSERT(!mRecentBookmarksCache.GetEntry(_itemId_))
+
 #define TOPIC_PLACES_MAINTENANCE "places-maintenance-finished"
 
 const PRInt32 nsNavBookmarks::kFindURIBookmarksIndex_Id = 0;
 const PRInt32 nsNavBookmarks::kFindURIBookmarksIndex_Guid = 1;
 const PRInt32 nsNavBookmarks::kFindURIBookmarksIndex_ParentId = 2;
 const PRInt32 nsNavBookmarks::kFindURIBookmarksIndex_LastModified = 3;
 const PRInt32 nsNavBookmarks::kFindURIBookmarksIndex_ParentGuid = 4;
 const PRInt32 nsNavBookmarks::kFindURIBookmarksIndex_GrandParentId = 5;
@@ -1047,17 +1053,17 @@ nsNavBookmarks::InsertBookmark(PRInt64 a
 
 
 NS_IMETHODIMP
 nsNavBookmarks::RemoveItem(PRInt64 aItemId)
 {
   NS_ENSURE_ARG(aItemId != mRoot);
 
   BookmarkData bookmark;
-  nsresult rv = FetchItemInfo(aItemId, bookmark, true);
+  nsresult rv = FetchItemInfo(aItemId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
 
   NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
                    nsINavBookmarkObserver,
                    OnBeforeItemRemoved(bookmark.id,
                                        bookmark.type,
                                        bookmark.parentId,
                                        bookmark.guid,
@@ -1081,16 +1087,18 @@ nsNavBookmarks::RemoveItem(PRInt64 aItem
       }
     }
 
     // Remove all of the folder's children.
     rv = RemoveFolderChildren(bookmark.id);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
+  BEGIN_CRITICAL_BOOKMARK_CACHE_SECTION(bookmark.id);
+
   DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBRemoveItem);
   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), bookmark.id);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = stmt->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Fix indices in the parent.
   if (bookmark.position != DEFAULT_INDEX) {
@@ -1102,16 +1110,18 @@ nsNavBookmarks::RemoveItem(PRInt64 aItem
   bookmark.lastModified = PR_Now();
   rv = SetItemDateInternal(GetStatement(mDBSetItemLastModified),
                            bookmark.parentId, bookmark.lastModified);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = transaction.Commit();
   NS_ENSURE_SUCCESS(rv, rv);
 
+  END_CRITICAL_BOOKMARK_CACHE_SECTION(bookmark.id);
+
   if (!mBatching) {
     ForceWALCheckpoint(mDBConn);
   }
 
   nsCOMPtr<nsIURI> uri;
   if (bookmark.type == TYPE_BOOKMARK) {
     nsNavHistory* history = nsNavHistory::GetHistoryService();
     NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
@@ -1496,34 +1506,31 @@ nsNavBookmarks::GetDescendantChildren(PR
 
 
 NS_IMETHODIMP
 nsNavBookmarks::RemoveFolderChildren(PRInt64 aFolderId)
 {
   NS_ENSURE_ARG_MIN(aFolderId, 1);
 
   BookmarkData folder;
-  nsresult rv = FetchItemInfo(aFolderId, folder, true);
+  nsresult rv = FetchItemInfo(aFolderId, folder);
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_ARG(folder.type == TYPE_FOLDER);
 
   // Fill folder children array recursively.
   nsTArray<BookmarkData> folderChildrenArray;
   rv = GetDescendantChildren(folder.id, folder.guid, folder.parentId,
                              folderChildrenArray);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Build a string of folders whose children will be removed.
   nsCString foldersToRemove;
   for (PRUint32 i = 0; i < folderChildrenArray.Length(); ++i) {
     BookmarkData& child = folderChildrenArray[i];
 
-    // Invalidate the bookmark cache.
-    mRecentBookmarksCache.RemoveEntry(child.id);
-
     // Notify observers that we are about to remove this child.
     NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
                      nsINavBookmarkObserver,
                      OnBeforeItemRemoved(child.id,
                                          child.type,
                                          child.parentId,
                                          child.guid,
                                          child.parentGuid));
@@ -1538,16 +1545,18 @@ nsNavBookmarks::RemoveFolderChildren(PRI
       if (!child.serviceCID.IsEmpty()) {
         nsCOMPtr<nsIDynamicContainer> svc =
           do_GetService(child.serviceCID.get());
         if (svc) {
           (void)svc->OnContainerRemoving(child.id);
         }
       }
     }
+
+    BEGIN_CRITICAL_BOOKMARK_CACHE_SECTION(child.id);
   }
 
   // Delete items from the database now.
   mozStorageTransaction transaction(mDBConn, PR_FALSE);
 
   nsCOMPtr<mozIStorageStatement> deleteStatement;
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "DELETE FROM moz_bookmarks "
@@ -1582,16 +1591,17 @@ nsNavBookmarks::RemoveFolderChildren(PRI
       nsNavHistory* history = nsNavHistory::GetHistoryService();
       NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
       rv = history->UpdateFrecency(child.placeId);
       NS_ENSURE_SUCCESS(rv, rv);
 
       rv = UpdateKeywordsHashForRemovedBookmark(child.id);
       NS_ENSURE_SUCCESS(rv, rv);
     }
+    END_CRITICAL_BOOKMARK_CACHE_SECTION(child.id);
   }
 
   rv = transaction.Commit();
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!mBatching) {
     ForceWALCheckpoint(mDBConn);
   }
@@ -1653,17 +1663,17 @@ nsNavBookmarks::MoveItem(PRInt64 aItemId
   // -1 is append, but no other negative number is allowed.
   NS_ENSURE_ARG_MIN(aIndex, -1);
   // Disallow making an item its own parent.
   NS_ENSURE_TRUE(aItemId != aNewParent, NS_ERROR_INVALID_ARG);
 
   mozStorageTransaction transaction(mDBConn, PR_FALSE);
 
   BookmarkData bookmark;
-  nsresult rv = FetchItemInfo(aItemId, bookmark, true);
+  nsresult rv = FetchItemInfo(aItemId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // if parent and index are the same, nothing to do
   if (bookmark.parentId == aNewParent && bookmark.position == aIndex)
     return NS_OK;
 
   // Make sure aNewParent is not aFolder or a subfolder of aFolder.
   // TODO: make this performant, maybe with a nested tree (bug 408991).
@@ -1734,16 +1744,18 @@ nsNavBookmarks::MoveItem(PRInt64 aItemId
     // First, fill the hole from the removal from the old parent.
     rv = AdjustIndices(bookmark.parentId, bookmark.position + 1, PR_INT32_MAX, -1);
     NS_ENSURE_SUCCESS(rv, rv);
     // Now, make room in the new parent for the insertion.
     rv = AdjustIndices(aNewParent, newIndex, PR_INT32_MAX, 1);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
+  BEGIN_CRITICAL_BOOKMARK_CACHE_SECTION(bookmark.id);
+
   {
     // Update parent and position.
     DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBMoveItem);
     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("parent"), aNewParent);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("item_index"), newIndex);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), bookmark.id);
@@ -1758,16 +1770,18 @@ nsNavBookmarks::MoveItem(PRInt64 aItemId
   NS_ENSURE_SUCCESS(rv, rv);
   rv = SetItemDateInternal(GetStatement(mDBSetItemLastModified),
                            aNewParent, now);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = transaction.Commit();
   NS_ENSURE_SUCCESS(rv, rv);
 
+  END_CRITICAL_BOOKMARK_CACHE_SECTION(bookmark.id);
+
   NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
                    nsINavBookmarkObserver,
                    OnItemMoved(bookmark.id,
                                bookmark.parentId,
                                bookmark.position,
                                aNewParent,
                                newIndex,
                                bookmark.type,
@@ -1783,27 +1797,23 @@ nsNavBookmarks::MoveItem(PRInt64 aItemId
       (void)svc->OnContainerMoved(bookmark.id, aNewParent, newIndex);
     }
   }
   return NS_OK;
 }
 
 nsresult
 nsNavBookmarks::FetchItemInfo(PRInt64 aItemId,
-                              BookmarkData& _bookmark,
-                              bool aInvalidateCache)
+                              BookmarkData& _bookmark)
 {
   // Check if the requested id is in the recent cache and avoid the database
   // lookup if so.  Invalidate the cache after getting data if requested.
   BookmarkKeyClass* key = mRecentBookmarksCache.GetEntry(aItemId);
   if (key) {
     _bookmark = key->bookmark;
-    if (aInvalidateCache) {
-      mRecentBookmarksCache.RemoveEntry(aItemId);
-    }
     return NS_OK;
   }
 
   DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBGetItemProperties);
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
   NS_ENSURE_SUCCESS(rv, rv);
 
   PRBool hasResult;
@@ -1859,58 +1869,61 @@ nsNavBookmarks::FetchItemInfo(PRInt64 aI
     rv = stmt->GetInt64(kGetItemPropertiesIndex_GrandParentId,
                         &_bookmark.grandParentId);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   else {
     _bookmark.grandParentId = -1;
   }
 
-  if (!aInvalidateCache) {
-    // Make space for the new entry.
-    ExpireNonrecentBookmarks(&mRecentBookmarksCache);
-    // Update the recent bookmarks cache.
-    BookmarkKeyClass* key = mRecentBookmarksCache.PutEntry(aItemId);
-    if (key) {
-      key->bookmark = _bookmark;
-    }
+  // Make space for the new entry.
+  ExpireNonrecentBookmarks(&mRecentBookmarksCache);
+  // Update the recent bookmarks cache.
+  key = mRecentBookmarksCache.PutEntry(aItemId);
+  if (key) {
+    key->bookmark = _bookmark;
   }
+
   return NS_OK;
 }
 
 nsresult
 nsNavBookmarks::SetItemDateInternal(mozIStorageStatement* aStatement,
                                     PRInt64 aItemId,
                                     PRTime aValue)
 {
+  BEGIN_CRITICAL_BOOKMARK_CACHE_SECTION(aItemId);
+
   NS_ENSURE_STATE(aStatement);
   mozStorageStatementScoper scoper(aStatement);
 
   nsresult rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("date"), aValue);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = aStatement->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
 
+  END_CRITICAL_BOOKMARK_CACHE_SECTION(aItemId);
+
   // note, we are not notifying the observers
   // that the item has changed.
 
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsNavBookmarks::SetItemDateAdded(PRInt64 aItemId, PRTime aDateAdded)
 {
   NS_ENSURE_ARG_MIN(aItemId, 1);
 
   BookmarkData bookmark;
-  nsresult rv = FetchItemInfo(aItemId, bookmark, true);
+  nsresult rv = FetchItemInfo(aItemId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
   bookmark.dateAdded = aDateAdded;
 
   rv = SetItemDateInternal(GetStatement(mDBSetItemDateAdded),
                            bookmark.id, bookmark.dateAdded);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Note: mDBSetItemDateAdded also sets lastModified to aDateAdded.
@@ -1931,31 +1944,31 @@ nsNavBookmarks::SetItemDateAdded(PRInt64
 
 NS_IMETHODIMP
 nsNavBookmarks::GetItemDateAdded(PRInt64 aItemId, PRTime* _dateAdded)
 {
   NS_ENSURE_ARG_MIN(aItemId, 1);
   NS_ENSURE_ARG_POINTER(_dateAdded);
 
   BookmarkData bookmark;
-  nsresult rv = FetchItemInfo(aItemId, bookmark, false);
+  nsresult rv = FetchItemInfo(aItemId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
 
   *_dateAdded = bookmark.dateAdded;
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsNavBookmarks::SetItemLastModified(PRInt64 aItemId, PRTime aLastModified)
 {
   NS_ENSURE_ARG_MIN(aItemId, 1);
 
   BookmarkData bookmark;
-  nsresult rv = FetchItemInfo(aItemId, bookmark, true);
+  nsresult rv = FetchItemInfo(aItemId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
   bookmark.lastModified = aLastModified;
 
   rv = SetItemDateInternal(GetStatement(mDBSetItemLastModified),
                            bookmark.id, bookmark.lastModified);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Note: mDBSetItemDateAdded also sets lastModified to aDateAdded.
@@ -1976,17 +1989,17 @@ nsNavBookmarks::SetItemLastModified(PRIn
 
 NS_IMETHODIMP
 nsNavBookmarks::GetItemLastModified(PRInt64 aItemId, PRTime* _lastModified)
 {
   NS_ENSURE_ARG_MIN(aItemId, 1);
   NS_ENSURE_ARG_POINTER(_lastModified);
 
   BookmarkData bookmark;
-  nsresult rv = FetchItemInfo(aItemId, bookmark, false);
+  nsresult rv = FetchItemInfo(aItemId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
 
   *_lastModified = bookmark.lastModified;
   return NS_OK;
 }
 
 
 nsresult
@@ -2081,19 +2094,21 @@ nsNavBookmarks::GetItemIdForGUID(const n
 
 
 NS_IMETHODIMP
 nsNavBookmarks::SetItemTitle(PRInt64 aItemId, const nsACString& aTitle)
 {
   NS_ENSURE_ARG_MIN(aItemId, 1);
 
   BookmarkData bookmark;
-  nsresult rv = FetchItemInfo(aItemId, bookmark, true);
+  nsresult rv = FetchItemInfo(aItemId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  BEGIN_CRITICAL_BOOKMARK_CACHE_SECTION(bookmark.id);
+
   DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(statement, mDBSetItemTitle);
   // Support setting a null title, we support this in insertBookmark.
   if (aTitle.IsVoid()) {
     rv = statement->BindNullByName(NS_LITERAL_CSTRING("item_title"));
   }
   else {
     rv = statement->BindUTF8StringByName(NS_LITERAL_CSTRING("item_title"),
                                          aTitle);
@@ -2104,16 +2119,18 @@ nsNavBookmarks::SetItemTitle(PRInt64 aIt
                                   bookmark.lastModified);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), bookmark.id);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = statement->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
 
+  END_CRITICAL_BOOKMARK_CACHE_SECTION(bookmark.id);
+
   NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
                    nsINavBookmarkObserver,
                    OnItemChanged(bookmark.id,
                                  NS_LITERAL_CSTRING("title"),
                                  PR_FALSE,
                                  aTitle,
                                  bookmark.lastModified,
                                  bookmark.type,
@@ -2126,79 +2143,79 @@ nsNavBookmarks::SetItemTitle(PRInt64 aIt
 
 NS_IMETHODIMP
 nsNavBookmarks::GetItemTitle(PRInt64 aItemId,
                              nsACString& _title)
 {
   NS_ENSURE_ARG_MIN(aItemId, 1);
 
   BookmarkData bookmark;
-  nsresult rv = FetchItemInfo(aItemId, bookmark, false);
+  nsresult rv = FetchItemInfo(aItemId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
 
   _title = bookmark.title;
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsNavBookmarks::GetBookmarkURI(PRInt64 aItemId,
                                nsIURI** _URI)
 {
   NS_ENSURE_ARG_MIN(aItemId, 1);
   NS_ENSURE_ARG_POINTER(_URI);
 
   BookmarkData bookmark;
-  nsresult rv = FetchItemInfo(aItemId, bookmark, false);
+  nsresult rv = FetchItemInfo(aItemId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = NS_NewURI(_URI, bookmark.url);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsNavBookmarks::GetItemType(PRInt64 aItemId, PRUint16* _type)
 {
   NS_ENSURE_ARG_MIN(aItemId, 1);
   NS_ENSURE_ARG_POINTER(_type);
 
   BookmarkData bookmark;
-  nsresult rv = FetchItemInfo(aItemId, bookmark, false);
+  nsresult rv = FetchItemInfo(aItemId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
 
   *_type = static_cast<PRUint16>(bookmark.type);
   return NS_OK;
 }
 
 
 nsresult
 nsNavBookmarks::GetFolderType(PRInt64 aItemId,
                               nsACString& _type)
 {
   NS_ENSURE_ARG_MIN(aItemId, 1);
 
   BookmarkData bookmark;
-  nsresult rv = FetchItemInfo(aItemId, bookmark, false);
+  nsresult rv = FetchItemInfo(aItemId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
 
   _type = bookmark.serviceCID;
   return NS_OK;
 }
 
 
 nsresult
 nsNavBookmarks::ResultNodeForContainer(PRInt64 aItemId,
                                        nsNavHistoryQueryOptions* aOptions,
                                        nsNavHistoryResultNode** aNode)
 {
   BookmarkData bookmark;
-  nsresult rv = FetchItemInfo(aItemId, bookmark, false);
+  nsresult rv = FetchItemInfo(aItemId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (bookmark.type == TYPE_DYNAMIC_CONTAINER) {
     *aNode = new nsNavHistoryContainerResultNode(EmptyCString(),
                                                  bookmark.title,
                                                  EmptyCString(),
                                                  nsINavHistoryResultNode::RESULT_TYPE_DYNAMIC_CONTAINER,
                                                  PR_TRUE,
@@ -2456,46 +2473,50 @@ nsNavBookmarks::GetBookmarkedURIFor(nsIU
 
 NS_IMETHODIMP
 nsNavBookmarks::ChangeBookmarkURI(PRInt64 aBookmarkId, nsIURI* aNewURI)
 {
   NS_ENSURE_ARG_MIN(aBookmarkId, 1);
   NS_ENSURE_ARG(aNewURI);
 
   BookmarkData bookmark;
-  nsresult rv = FetchItemInfo(aBookmarkId, bookmark, true);
+  nsresult rv = FetchItemInfo(aBookmarkId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_ARG(bookmark.type == TYPE_BOOKMARK);
 
   mozStorageTransaction transaction(mDBConn, PR_FALSE);
 
   nsNavHistory* history = nsNavHistory::GetHistoryService();
   NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
   PRInt64 newPlaceId;
   nsCAutoString newPlaceGuid;
   rv = history->GetOrCreateIdForPage(aNewURI, &newPlaceId, newPlaceGuid);
   NS_ENSURE_SUCCESS(rv, rv);
   if (!newPlaceId)
     return NS_ERROR_INVALID_ARG;
 
+  BEGIN_CRITICAL_BOOKMARK_CACHE_SECTION(bookmark.id);
+
   DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(statement, mDBChangeBookmarkURI);
   rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), newPlaceId);
   NS_ENSURE_SUCCESS(rv, rv);
   bookmark.lastModified = PR_Now();
   rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("date"),
                                   bookmark.lastModified);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), bookmark.id);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = statement->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = transaction.Commit();
   NS_ENSURE_SUCCESS(rv, rv);
 
+  END_CRITICAL_BOOKMARK_CACHE_SECTION(bookmark.id);
+
   rv = history->UpdateFrecency(newPlaceId);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Upon changing the URI for a bookmark, update the frecency for the old
   // place as well.
   rv = history->UpdateFrecency(bookmark.placeId);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -2520,17 +2541,17 @@ nsNavBookmarks::ChangeBookmarkURI(PRInt6
 
 NS_IMETHODIMP
 nsNavBookmarks::GetFolderIdForItem(PRInt64 aItemId, PRInt64* _parentId)
 {
   NS_ENSURE_ARG_MIN(aItemId, 1);
   NS_ENSURE_ARG_POINTER(_parentId);
 
   BookmarkData bookmark;
-  nsresult rv = FetchItemInfo(aItemId, bookmark, false);
+  nsresult rv = FetchItemInfo(aItemId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // this should not happen, but see bug #400448 for details
   NS_ENSURE_TRUE(bookmark.id != bookmark.parentId, NS_ERROR_UNEXPECTED);
 
   *_parentId = bookmark.parentId;
   return NS_OK;
 }
@@ -2646,17 +2667,17 @@ nsNavBookmarks::GetBookmarkIdsForURI(nsI
 
 NS_IMETHODIMP
 nsNavBookmarks::GetItemIndex(PRInt64 aItemId, PRInt32* _index)
 {
   NS_ENSURE_ARG_MIN(aItemId, 1);
   NS_ENSURE_ARG_POINTER(_index);
 
   BookmarkData bookmark;
-  nsresult rv = FetchItemInfo(aItemId, bookmark, false);
+  nsresult rv = FetchItemInfo(aItemId, bookmark);
   // With respect to the API.
   if (NS_FAILED(rv)) {
     *_index = -1;
     return NS_OK;
   }
 
   *_index = bookmark.position;
   return NS_OK;
@@ -2665,38 +2686,42 @@ nsNavBookmarks::GetItemIndex(PRInt64 aIt
 
 NS_IMETHODIMP
 nsNavBookmarks::SetItemIndex(PRInt64 aItemId, PRInt32 aNewIndex)
 {
   NS_ENSURE_ARG_MIN(aItemId, 1);
   NS_ENSURE_ARG_MIN(aNewIndex, 0);
 
   BookmarkData bookmark;
-  nsresult rv = FetchItemInfo(aItemId, bookmark, true);
+  nsresult rv = FetchItemInfo(aItemId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Ensure we are not going out of range.
   PRInt32 folderCount;
   PRInt64 grandParentId;
   nsCAutoString folderGuid;
   rv = FetchFolderInfo(bookmark.parentId, &folderCount, folderGuid, &grandParentId);
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(aNewIndex < folderCount, NS_ERROR_INVALID_ARG);
   // Check the parent's guid is the expected one.
   MOZ_ASSERT(bookmark.parentGuid == folderGuid);
 
+  BEGIN_CRITICAL_BOOKMARK_CACHE_SECTION(bookmark.id);
+
   DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBSetItemIndex);
   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("item_index"), aNewIndex);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = stmt->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
 
+  END_CRITICAL_BOOKMARK_CACHE_SECTION(bookmark.id);
+
   NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
                    nsINavBookmarkObserver,
                    OnItemMoved(bookmark.id,
                                bookmark.parentId,
                                bookmark.position,
                                bookmark.parentId,
                                aNewIndex,
                                bookmark.type,
@@ -2724,17 +2749,17 @@ nsNavBookmarks::UpdateKeywordsHashForRem
 NS_IMETHODIMP
 nsNavBookmarks::SetKeywordForBookmark(PRInt64 aBookmarkId,
                                       const nsAString& aUserCasedKeyword)
 {
   NS_ENSURE_ARG_MIN(aBookmarkId, 1);
 
   // This also ensures the bookmark is valid.
   BookmarkData bookmark;
-  nsresult rv = FetchItemInfo(aBookmarkId, bookmark, true);
+  nsresult rv = FetchItemInfo(aBookmarkId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = EnsureKeywordsHash();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Shortcuts are always lowercased internally.
   nsAutoString keyword(aUserCasedKeyword);
   ToLowerCase(keyword);
@@ -2743,16 +2768,18 @@ nsNavBookmarks::SetKeywordForBookmark(PR
   nsAutoString oldKeyword;
   rv = GetKeywordForBookmark(bookmark.id, oldKeyword);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Trying to set the same value or to remove a nonexistent keyword is a no-op.
   if (keyword.Equals(oldKeyword) || (keyword.IsEmpty() && oldKeyword.IsEmpty()))
     return NS_OK;
 
+  BEGIN_CRITICAL_BOOKMARK_CACHE_SECTION(bookmark.id);
+
   mozStorageTransaction transaction(mDBConn, PR_FALSE);
 
   nsCOMPtr<mozIStorageStatement> updateBookmarkStmt;
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
     "UPDATE moz_bookmarks "
     "SET keyword_id = (SELECT id FROM moz_keywords WHERE keyword = :keyword), "
         "lastModified = :date "
     "WHERE id = :item_id "
@@ -2793,16 +2820,18 @@ nsNavBookmarks::SetKeywordForBookmark(PR
                                            bookmark.id);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = updateBookmarkStmt->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = transaction.Commit();
   NS_ENSURE_SUCCESS(rv, rv);
 
+  END_CRITICAL_BOOKMARK_CACHE_SECTION(bookmark.id);
+
   NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
                    nsINavBookmarkObserver,
                    OnItemChanged(bookmark.id,
                                  NS_LITERAL_CSTRING("keyword"),
                                  PR_FALSE,
                                  NS_ConvertUTF16toUTF8(keyword),
                                  bookmark.lastModified,
                                  bookmark.type,
@@ -3138,17 +3167,17 @@ nsNavBookmarks::OnPageChanged(nsIURI* aU
       nsCOMArray<nsNavHistoryQuery> queries;
       nsCOMPtr<nsNavHistoryQueryOptions> options;
       rv = history->QueryStringToQueryArray(changeData.bookmark.url,
                                             &queries, getter_AddRefs(options));
       NS_ENSURE_SUCCESS(rv, rv);
 
       if (queries.Count() == 1 && queries[0]->Folders().Length() == 1) {
         // Fetch missing data.
-        rv = FetchItemInfo(queries[0]->Folders()[0], changeData.bookmark, false);
+        rv = FetchItemInfo(queries[0]->Folders()[0], changeData.bookmark);
         NS_ENSURE_SUCCESS(rv, rv);        
         NotifyItemChanged(changeData);
       }
     }
     else {
       nsRefPtr< AsyncGetBookmarksForURI<ItemChangeMethod, ItemChangeData> > notifier =
         new AsyncGetBookmarksForURI<ItemChangeMethod, ItemChangeData>(this, &nsNavBookmarks::NotifyItemChanged, changeData);
       notifier->Init();
@@ -3190,17 +3219,17 @@ nsNavBookmarks::OnPageAnnotationSet(nsIU
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsNavBookmarks::OnItemAnnotationSet(PRInt64 aItemId, const nsACString& aName)
 {
   BookmarkData bookmark;
-  nsresult rv = FetchItemInfo(aItemId, bookmark, true);
+  nsresult rv = FetchItemInfo(aItemId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bookmark.lastModified = PR_Now();
   rv = SetItemDateInternal(GetStatement(mDBSetItemLastModified),
                            bookmark.id, bookmark.lastModified);
   NS_ENSURE_SUCCESS(rv, rv);
 
   NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
--- a/toolkit/components/places/nsNavBookmarks.h
+++ b/toolkit/components/places/nsNavBookmarks.h
@@ -223,22 +223,19 @@ public:
 
   /**
    * Fetches information about the specified id from the database.
    *
    * @param aItemId
    *        Id of the item to fetch information for.
    * @param aBookmark
    *        BookmarkData to store the information.
-   * @param aInvalidateCache
-   *        True if the cache should discard its entry after the fetching.
    */
   nsresult FetchItemInfo(PRInt64 aItemId,
-                         BookmarkData& _bookmark,
-                         bool aInvalidateCache);
+                         BookmarkData& _bookmark);
 
   /**
    * Finalize all internal statements.
    */
   nsresult FinalizeStatements();
 
   mozIStorageStatement* GetStatementById(BookmarkStatementId aStatementId)
   {
@@ -516,17 +513,17 @@ private:
     RemoveFolderTransaction(PRInt64 aID) : mID(aID) {}
 
     NS_DECL_ISUPPORTS
 
     NS_IMETHOD DoTransaction() {
       nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService();
       NS_ENSURE_TRUE(bookmarks, NS_ERROR_OUT_OF_MEMORY);
       BookmarkData folder;
-      nsresult rv = bookmarks->FetchItemInfo(mID, folder, true);
+      nsresult rv = bookmarks->FetchItemInfo(mID, folder);
       // TODO (Bug 656935): store the BookmarkData struct instead.
       mParent = folder.parentId;
       mIndex = folder.position;
 
       rv = bookmarks->GetItemTitle(mID, mTitle);
       NS_ENSURE_SUCCESS(rv, rv);
 
       nsCAutoString type;
--- a/toolkit/components/places/tests/autocomplete/xpcshell.ini
+++ b/toolkit/components/places/tests/autocomplete/xpcshell.ini
@@ -3,18 +3,24 @@ head = head_autocomplete.js
 tail = 
 
 [test_416211.js]
 [test_416214.js]
 [test_417798.js]
 [test_418257.js]
 [test_422277.js]
 [test_autocomplete_on_value_removed_479089.js]
+# Bug 676989: test fails consistently on Android
+fail-if = os == "android"
 [test_download_embed_bookmarks.js]
+# Bug 676989: test fails consistently on Android
+fail-if = os == "android"
 [test_empty_search.js]
+# Bug 676989: test fails consistently on Android
+fail-if = os == "android"
 [test_enabled.js]
 [test_escape_self.js]
 [test_ignore_protocol.js]
 [test_keyword_search.js]
 [test_livemarks.js]
 [test_match_beginning.js]
 [test_multi_word_search.js]
 [test_special_search.js]
new file mode 100644
--- /dev/null
+++ b/toolkit/components/places/tests/bookmarks/test_675416.js
@@ -0,0 +1,57 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function run_test() {
+  /**
+   * Requests information to the service, so that bookmark's data is cached.
+   * @param aItemId
+   *        Id of the bookmark to be cached.
+   */
+  function forceBookmarkCaching(aItemId) {
+    PlacesUtils.bookmarks.getFolderIdForItem(aItemId);
+  }
+
+  let observer = {
+    onBeginUpdateBatch: function() forceBookmarkCaching(itemId1),
+    onEndUpdateBatch: function() forceBookmarkCaching(itemId1),
+    onItemAdded: forceBookmarkCaching,
+    onItemChanged: forceBookmarkCaching,
+    onItemMoved: forceBookmarkCaching,
+    onBeforeItemRemoved: forceBookmarkCaching,
+    onItemRemoved: function(id) {
+      try {
+        forceBookmarkCaching(id);
+        do_throw("trying to fetch a removed bookmark should throw");
+      } catch (ex) {}
+    },
+    onItemVisited: forceBookmarkCaching,
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsINavBookmarkObserver])
+  };
+  PlacesUtils.bookmarks.addObserver(observer, false);
+
+  let folderId1 = PlacesUtils.bookmarks
+                             .createFolder(PlacesUtils.bookmarksMenuFolderId,
+                                           "Bookmarks",
+                                           PlacesUtils.bookmarks.DEFAULT_INDEX);
+  let itemId1 = PlacesUtils.bookmarks
+                           .insertBookmark(folderId1,
+                                           NetUtil.newURI("http:/www.wired.com/wiredscience"),
+                                           PlacesUtils.bookmarks.DEFAULT_INDEX,
+                                           "Wired Science");
+
+  PlacesUtils.bookmarks.removeItem(folderId1);
+
+  let folderId2 = PlacesUtils.bookmarks
+                             .createFolder(PlacesUtils.bookmarksMenuFolderId,
+                                           "Science",
+                                           PlacesUtils.bookmarks.DEFAULT_INDEX);
+  let folderId3 = PlacesUtils.bookmarks
+                             .createFolder(folderId2,
+                                           "Blogs",
+                                           PlacesUtils.bookmarks.DEFAULT_INDEX);
+  // Check title is correctly reported.
+  do_check_eq(PlacesUtils.bookmarks.getItemTitle(folderId3), "Blogs");
+  do_check_eq(PlacesUtils.bookmarks.getItemTitle(folderId2), "Science");
+
+  PlacesUtils.bookmarks.removeObserver(observer, false);
+}
--- a/toolkit/components/places/tests/bookmarks/xpcshell.ini
+++ b/toolkit/components/places/tests/bookmarks/xpcshell.ini
@@ -26,9 +26,10 @@ tail =
 [test_getBookmarkedURIFor.js]
 [test_keywords.js]
 [test_livemarks.js]
 [test_nsINavBookmarkObserver.js]
 [test_onBeforeItemRemoved_observer.js]
 [test_removeItem.js]
 [test_restore_guids.js]
 [test_savedsearches.js]
+[test_675416.js]
 
--- a/toolkit/components/places/tests/expiration/xpcshell.ini
+++ b/toolkit/components/places/tests/expiration/xpcshell.ini
@@ -1,16 +1,26 @@
 [DEFAULT]
 head = head_expiration.js
 tail = 
 
 [test_analyze_runs.js]
+# Bug 676989: test hangs consistently on Android
+skip-if = os == "android"
 [test_annos_expire_history.js]
 [test_annos_expire_never.js]
 [test_annos_expire_policy.js]
 [test_annos_expire_session.js]
+# Bug 676989: test fails consistently on Android
+fail-if = os == "android"
 [test_notifications.js]
+# Bug 676989: test fails consistently on Android
+fail-if = os == "android"
 [test_notifications_onDeleteURI.js]
 [test_notifications_onDeleteVisits.js]
 [test_pref_interval.js]
+# Bug 676989: test fails consistently on Android
+fail-if = os == "android"
 [test_pref_maxpages.js]
+# Bug 676989: test fails consistently on Android
+fail-if = os == "android" 
 [test_removeAllPages.js]
 [test_debug_expiration.js]
--- a/toolkit/components/places/tests/queries/xpcshell.ini
+++ b/toolkit/components/places/tests/queries/xpcshell.ini
@@ -8,17 +8,25 @@ tail =
 [test_async.js]
 [test_containersQueries_sorting.js]
 [test_excludeReadOnlyFolders.js]
 [test_history_queries_tags_liveUpdate.js]
 [test_history_queries_titles_liveUpdate.js]
 [test_onlyBookmarked.js]
 [test_querySerialization.js]
 [test_redirectsMode.js]
+# Bug 676989: test hangs consistently on Android
+skip-if = os == "android"
 [test_results-as-tag-contents-query.js]
 [test_results-as-visit.js]
 [test_searchterms-domain.js]
 [test_searchterms-uri.js]
 [test_searchterms-bookmarklets.js]
 [test_sort-date-site-grouping.js]
 [test_sorting.js]
+# Bug 676989: test hangs consistently on Android
+skip-if = os == "android" 
 [test_tags.js]
+# Bug 676989: test hangs consistently on Android
+skip-if = os == "android"
 [test_transitions.js]
+# Bug 676989: test hangs consistently on Android
+skip-if = os == "android"
--- a/toolkit/components/places/tests/unit/xpcshell.ini
+++ b/toolkit/components/places/tests/unit/xpcshell.ini
@@ -1,26 +1,30 @@
 [DEFAULT]
 head = head_bookmarks.js
 tail = 
 
 [test_000_frecency.js]
 [test_248970.js]
 [test_317472.js]
+# Bug 676989: test hangs consistently on Android
+skip-if = os == "android"
 [test_331487.js]
 [test_385397.js]
 [test_399264_query_to_string.js]
 [test_399264_string_to_query.js]
 [test_399266.js]
 [test_399606.js]
 [test_402799.js]
 [test_404630.js]
 [test_405497.js]
 [test_408221.js]
 [test_412132.js]
+# Bug 676989: test hangs consistently on Android
+skip-if = os == "android"
 [test_413784.js]
 [test_415460.js]
 [test_415757.js]
 [test_418643_removeFolderChildren.js]
 [test_419731.js]
 [test_419792_node_tags_property.js]
 [test_420331_wyciwyg.js]
 [test_421180.js]
@@ -32,64 +36,86 @@ tail =
 [test_452777.js]
 [test_454977.js]
 [test_457698_crash.js]
 [test_463863.js]
 [test_485442_crash_bug_nsNavHistoryQuery_GetUri.js]
 [test_486978_sort_by_date_queries.js]
 [test_536081.js]
 [test_adaptive.js]
+# Bug 676989: test hangs consistently on Android
+skip-if = os == "android"
 [test_adaptive_bug527311.js]
 [test_annotations.js]
 [test_asyncExecuteLegacyQueries.js]
+# Bug 676989: test hangs consistently on Android
+skip-if = os == "android"
 [test_async_history_api.js]
 [test_autocomplete_stopSearch_no_throw.js]
 [test_bookmark_catobs.js]
 [test_bookmarks_setNullTitle.js]
 [test_broken_folderShortcut_result.js]
 [test_browserhistory.js]
 [test_bug636917_isLivemark.js]
 [test_childlessTags.js]
 [test_crash_476292.js]
 [test_database_replaceOnStartup.js]
 [test_doSetAndLoadFaviconForPage.js]
 [test_doSetAndLoadFaviconForPage_failures.js]
+# Bug 676989: test fails consistently on Android
+fail-if = os == "android"
 [test_download_history.js]
+# Bug 676989: test fails consistently on Android
+fail-if = os == "android"
 [test_dynamic_containers.js]
 [test_exclude_livemarks.js]
 [test_faviconService_expireAllFavicons.js]
 [test_favicons.js]
+# Bug 676989: test fails consistently on Android
+fail-if = os == "android"
 [test_frecency.js]
+# Bug 676989: test hangs consistently on Android
+skip-if = os == "android"
 [test_getChildIndex.js]
 [test_history.js]
 [test_history_autocomplete_tags.js]
 [test_history_catobs.js]
 [test_history_notifications.js]
 [test_history_observer.js]
 [test_history_removeAllPages.js]
+# Bug 676989: test hangs consistently on Android
+skip-if = os == "android"
 [test_history_sidebar.js]
 [test_isvisited.js]
 [test_lastModified.js]
 [test_livemarkService_getLivemarkIdForFeedURI.js]
 [test_markpageas.js]
 [test_moz-anno_favicon_mime_type.js]
 [test_multi_queries.js]
 [test_multi_word_tags.js]
 [test_nsINavHistoryViewer.js]
 [test_null_interfaces.js]
 [test_onBeforeDeleteURI_observer.js]
 [test_onItemChanged_tags.js]
 [test_placeURIs.js]
 [test_preventive_maintenance.js]
+# Bug 676989: test hangs consistently on Android
+skip-if = os == "android"
 [test_preventive_maintenance_checkAndFixDatabase.js]
+# Bug 676989: test hangs consistently on Android
+skip-if = os == "android"
 [test_preventive_maintenance_console.js]
 [test_removeVisitsByTimeframe.js]
+# Bug 676989: test hangs consistently on Android
+skip-if = os == "android"
 [test_resolveNullBookmarkTitles.js]
 [test_result_sort.js]
 [test_sql_guid_functions.js]
 [test_tag_autocomplete_search.js]
 [test_tagging.js]
 [test_update_frecency_after_delete.js]
+# Bug 676989: test hangs consistently on Android
+skip-if = os == "android"
 [test_utils_backups_create.js]
 [test_utils_getURLsForContainerNode.js]
 [test_utils_setAnnotationsFor.js]
 [test_PlacesUtils_asyncGetBookmarkIds.js]
 [test_telemetry.js]
--- a/toolkit/components/satchel/test/unit/xpcshell.ini
+++ b/toolkit/components/satchel/test/unit/xpcshell.ini
@@ -1,14 +1,16 @@
 [DEFAULT]
 head = head_satchel.js
 tail = 
 
 [test_autocomplete.js]
 [test_bug_248970.js]
+# Bug 676989: test hangs on Android
+skip-if = os == "android"
 [test_db_corrupt.js]
 [test_db_update_v1.js]
 [test_db_update_v1b.js]
 [test_db_update_v2.js]
 [test_db_update_v2b.js]
 [test_db_update_v3.js]
 [test_db_update_v3b.js]
 [test_db_update_v999a.js]
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -254,17 +254,17 @@ WrapAndReturnHistogram(Histogram *h, JSC
     return NS_ERROR_FAILURE;
   *ret = OBJECT_TO_JSVAL(obj);
   return (JS_SetPrivate(cx, obj, h)
           && JS_DefineFunction (cx, obj, "add", JSHistogram_Add, 1, 0)
           && JS_DefineFunction (cx, obj, "snapshot", JSHistogram_Snapshot, 1, 0)) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 TelemetryImpl::TelemetryImpl():
-mCanRecord(true)
+mCanRecord(XRE_GetProcessType() == GeckoProcessType_Default)
 {
   mHistogramMap.Init(Telemetry::HistogramCount);
 }
 
 TelemetryImpl::~TelemetryImpl() {
   mHistogramMap.Clear();
 }
 
--- a/toolkit/components/telemetry/TelemetryHistograms.h
+++ b/toolkit/components/telemetry/TelemetryHistograms.h
@@ -37,16 +37,19 @@
  * ***** END LICENSE BLOCK ***** */
 
 /**
  * This file lists Telemetry histograms collected by Firefox.  The format is
  *
  *    HISTOGRAM(id, minimum, maximum, bucket count, histogram kind,
  *              human-readable description for about:telemetry)
  *
+ * This file is the master list of telemetry histograms reported to Mozilla servers.
+ * The other data reported by telemetry is listed on https://wiki.mozilla.org/Privacy/Reviews/Telemetry/Measurements
+ *
  */
 
 /**
  * a11y telemetry
  */
 HISTOGRAM(A11Y_INSTANTIATED, 0, 1, 2, BOOLEAN, "has accessibility support been instantiated")
 
 HISTOGRAM(CYCLE_COLLECTOR, 1, 10000, 50, EXPONENTIAL, "Time spent on one cycle collection (ms)")
--- a/toolkit/components/telemetry/tests/unit/xpcshell.ini
+++ b/toolkit/components/telemetry/tests/unit/xpcshell.ini
@@ -1,6 +1,8 @@
 [DEFAULT]
 head = 
 tail = 
 
 [test_nsITelemetry.js]
 [test_TelemetryPing.js]
+# Bug 676989: test fails consistently on Android
+# fail-if = os == "android"
--- a/toolkit/mozapps/extensions/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/XPIProvider.jsm
@@ -3456,32 +3456,36 @@ var XPIProvider = {
     this.bootstrappedAddons[aId] = {
       version: aVersion,
       descriptor: aFile.persistentDescriptor
     };
     this.addAddonsToCrashReporter();
 
     let principal = Cc["@mozilla.org/systemprincipal;1"].
                     createInstance(Ci.nsIPrincipal);
-    this.bootstrapScopes[aId] = new Components.utils.Sandbox(principal);
 
     if (!aFile.exists()) {
+      this.bootstrapScopes[aId] = new Components.utils.Sandbox(principal,
+                                                               {sandboxName: aFile.path});
       ERROR("Attempted to load bootstrap scope from missing directory " + bootstrap.path);
       return;
     }
 
+    let uri = getURIForResourceInFile(aFile, "bootstrap.js").spec;
+    this.bootstrapScopes[aId] = new Components.utils.Sandbox(principal,
+                                                             {sandboxName: uri});
+
     let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
                  createInstance(Ci.mozIJSSubScriptLoader);
 
     try {
       // As we don't want our caller to control the JS version used for the
       // bootstrap file, we run loadSubScript within the context of the
       // sandbox with the latest JS version set explicitly.
-      this.bootstrapScopes[aId].__SCRIPT_URI_SPEC__ =
-          getURIForResourceInFile(aFile, "bootstrap.js").spec;
+      this.bootstrapScopes[aId].__SCRIPT_URI_SPEC__ = uri;
       Components.utils.evalInSandbox(
         "Components.classes['@mozilla.org/moz/jssubscript-loader;1'] \
                    .createInstance(Components.interfaces.mozIJSSubScriptLoader) \
                    .loadSubScript(__SCRIPT_URI_SPEC__);", this.bootstrapScopes[aId], "ECMAv5");
     }
     catch (e) {
       WARN("Error loading bootstrap.js for " + aId, e);
     }
--- a/toolkit/mozapps/extensions/content/selectAddons.xul
+++ b/toolkit/mozapps/extensions/content/selectAddons.xul
@@ -143,17 +143,16 @@
         <label id="errors-heading" class="heading">&errors.heading;</label>
       </vbox>
       <description id="errors-description" value="&errors.description;"/>
       <spacer flex="1"/>
     </vbox>
   </deck>
 
   <hbox id="footer" align="center">
-    <label id="footer-label">&footer.label;</label>
-    <spacer flex="1"/>
+    <label id="footer-label" flex="1">&footer.label;</label>
     <button id="cancel" label="&cancel.label;" oncommand="window.close()"/>
     <button id="back" label="&back.label;" oncommand="gView.back()" hidden="true"/>
     <button id="next" label="&next.label;" oncommand="gView.next()" hidden="true"/>
     <button id="done" label="&done.label;" oncommand="gView.done()" hidden="true"/>
   </hbox>
 
 </window>
--- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
+++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
@@ -1,76 +1,142 @@
 [DEFAULT]
 head = head_addons.js
 tail = 
 
 [test_AddonRepository.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_AddonRepository_cache.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_LightweightThemeManager.js]
 [test_badschema.js]
 [test_blocklistchange.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bootstrap.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bug299716.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bug299716_2.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bug324121.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bug335238.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bug371495.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bug384052.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bug393285.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bug394300.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bug397778.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bug406118.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bug424262.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bug425657.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bug430120.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bug449027.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bug455906.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bug465190.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bug468528.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bug470377_1.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bug470377_2.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bug470377_3.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bug470377_4.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bug514327_1.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bug514327_2.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bug514327_3.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_bug521905.js]
 [test_bug526598.js]
 [test_bug541420.js]
 [test_bug542391.js]
 [test_bug554133.js]
 [test_bug559800.js]
 [test_bug563256.js]
+# Bug 676992: test consistently fails on Android
+fail-if = os == "android"
 [test_bug564030.js]
 [test_bug566626.js]
 [test_bug567184.js]
 [test_bug569138.js]
 [test_bug570173.js]
 [test_bug576735.js]
 [test_bug578467.js]
 [test_bug587088.js]
 [test_bug594058.js]
 [test_bug595081.js]
 [test_bug595573.js]
 [test_bug596343.js]
 [test_bug596607.js]
 [test_bug616841.js]
+# Bug 676992: test consistently fails on Android
+fail-if = os == "android"
 [test_bug619730.js]
 [test_bug620837.js]
 [test_bug655254.js]
 [test_bug659772.js]
 [test_cacheflush.js]
 [test_checkcompatibility.js]
 [test_corrupt.js]
 [test_disable.js]
 [test_distribution.js]
 [test_dss.js]
+# Bug 676992: test consistently fails on Android
+fail-if = os == "android"
 [test_duplicateplugins.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_error.js]
 [test_filepointer.js]
+# Bug 676992: test consistently hangs on Android
+skip-if = os == "android"
 [test_fuel.js]
 [test_general.js]
 [test_getresource.js]
 [test_gfxBlacklist_AllOS1.js]
 [test_gfxBlacklist_AllOS2.js]
 [test_gfxBlacklist_Device.js]
 [test_gfxBlacklist_DriverNew.js]
 [test_gfxBlacklist_Equal_DriverNew.js]
@@ -78,28 +144,44 @@ tail =
 [test_gfxBlacklist_Equal_OK.js]