Merge mozilla-central into tracemonkey
authorVladimir Vukicevic <vladimir@pobox.com>
Tue, 18 Nov 2008 13:54:21 -0800
changeset 21810 e8ed5d4bf5317e402a8b34e1937ab333395dd87f
parent 21809 650f311bec84881cfa6163ffc75e64bdbee199ca (current diff)
parent 21766 5b9f7cddadcb83b7c397fbe347c78b8d23814b5b (diff)
child 21811 b2fbc259ee2baeaec49bd9a08a6874438aa8011c
child 22601 19c01c29041995c4a06697bee0caeca35249f167
push id3689
push uservladimir@mozilla.com
push dateTue, 18 Nov 2008 22:11:14 +0000
treeherdermozilla-central@e8ed5d4bf531 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9.1b2pre
Merge mozilla-central into tracemonkey
js/src/jsinterp.cpp
js/src/jsopcode.cpp
js/src/jstracer.cpp
js/src/xpconnect/loader/JSON.jsm
js/src/xpconnect/tests/unit/test_json.js
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1106,16 +1106,17 @@ function prepareForStartup() {
   // though it had done this work itself
   gBrowser.browsers[0].removeAttribute("disablehistory");
 
   // enable global history
   gBrowser.docShell.QueryInterface(Components.interfaces.nsIDocShellHistory).useGlobalHistory = true;
 
   // hook up UI through progress listener
   gBrowser.addProgressListener(window.XULBrowserWindow, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
+  gBrowser.addTabsProgressListener(window.TabsProgressListener);
 
   // setup our common DOMLinkAdded listener
   gBrowser.addEventListener("DOMLinkAdded", DOMLinkHandler, false);
 
   // setup simple gestures support
   gGestureSupport.init(true);
 }
 
@@ -1334,16 +1335,17 @@ function BrowserShutdown()
 
   var os = Components.classes["@mozilla.org/observer-service;1"]
     .getService(Components.interfaces.nsIObserverService);
   os.removeObserver(gSessionHistoryObserver, "browser:purge-session-history");
   os.removeObserver(gXPInstallObserver, "xpinstall-install-blocked");
 
   try {
     gBrowser.removeProgressListener(window.XULBrowserWindow);
+    gBrowser.removeTabsProgressListener(window.TabsProgressListener);
   } catch (ex) {
   }
 
   PlacesStarButton.uninit();
 
   try {
     gPrefService.removeObserver(gAutoHideTabbarPrefListener.domain,
                                 gAutoHideTabbarPrefListener);
@@ -3791,18 +3793,17 @@ var XULBrowserWindow = {
     // and cause needless (slow!) UI updates
     if (this.statusText != text) {
       this.statusTextField.label = text;
       this.statusText = text;
     }
   },
   
   onLinkIconAvailable: function (aBrowser) {
-    if (gProxyFavIcon && gBrowser.mCurrentBrowser == aBrowser &&
-        gBrowser.userTypedValue === null)
+    if (gProxyFavIcon && gBrowser.userTypedValue === null)
       PageProxySetIcon(aBrowser.mIconURL); // update the favicon in the URL bar
   },
 
   onProgressChange: function (aWebProgress, aRequest,
                               aCurSelfProgress, aMaxSelfProgress,
                               aCurTotalProgress, aMaxTotalProgress) {
     if (aMaxTotalProgress > 0) {
       // This is highly optimized.  Don't touch this code unless
@@ -3853,18 +3854,16 @@ var XULBrowserWindow = {
       // XXX: This needs to be based on window activity...
       this.stopCommand.removeAttribute("disabled");
     }
     else if (aStateFlags & nsIWebProgressListener.STATE_STOP) {
       if (aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) {
         if (aWebProgress.DOMWindow == content) {
           if (aRequest)
             this.endDocumentLoad(aRequest, aStatus);
-          if (!gBrowser.mTabbedMode && !gBrowser.mCurrentBrowser.mIconURL)
-            gBrowser.useDefaultIcon(gBrowser.mCurrentTab);
 
           if (Components.isSuccessCode(aStatus) &&
               content.document.documentElement.getAttribute("manifest"))
             OfflineApps.offlineAppRequested(content);
         }
       }
 
       // This (thanks to the filter) is a network stop or the last
@@ -3991,19 +3990,16 @@ var XULBrowserWindow = {
       if ((location == "about:blank" && !content.opener) ||
           location == "") {  // Second condition is for new tabs, otherwise
                              // reload function is enabled until tab is refreshed.
         this.reloadCommand.setAttribute("disabled", "true");
       } else {
         this.reloadCommand.removeAttribute("disabled");
       }
 
-      if (!gBrowser.mTabbedMode && aWebProgress.isLoadingDocument)
-        gBrowser.setIcon(gBrowser.mCurrentTab, null);
-
       if (gURLBar) {
         // Strip off "wyciwyg://" and passwords for the location bar
         let uri = aLocationURI;
         try {
           uri = this._uriFixup.createExposableURI(uri);
         } catch (e) {}
         URLBarSetURI(uri, true);
 
@@ -4039,65 +4035,16 @@ var XULBrowserWindow = {
     BrowserSearch.updateSearchButton();
   },
 
   onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) {
     this.status = aMessage;
     this.updateStatusField();
   },
 
-  onRefreshAttempted: function (aWebProgress, aURI, aDelay, aSameURI) {
-    if (gPrefService.getBoolPref("accessibility.blockautorefresh")) {
-      let brandBundle = document.getElementById("bundle_brand");
-      let brandShortName = brandBundle.getString("brandShortName");
-      let refreshButtonText =
-        gNavigatorBundle.getString("refreshBlocked.goButton");
-      let refreshButtonAccesskey =
-        gNavigatorBundle.getString("refreshBlocked.goButton.accesskey");
-      let message =
-        gNavigatorBundle.getFormattedString(aSameURI ? "refreshBlocked.refreshLabel"
-                                                     : "refreshBlocked.redirectLabel",
-                                            [brandShortName]);
-      let topBrowser = getBrowserFromContentWindow(aWebProgress.DOMWindow.top);
-      let docShell = aWebProgress.DOMWindow
-                                 .QueryInterface(Ci.nsIInterfaceRequestor)
-                                 .getInterface(Ci.nsIWebNavigation)
-                                 .QueryInterface(Ci.nsIDocShell);
-      let notificationBox = gBrowser.getNotificationBox(topBrowser);
-      let notification = notificationBox.getNotificationWithValue("refresh-blocked");
-      if (notification) {
-        notification.label = message;
-        notification.refreshURI = aURI;
-        notification.delay = aDelay;
-        notification.docShell = docShell;
-      } else {
-        let buttons = [{
-          label: refreshButtonText,
-          accessKey: refreshButtonAccesskey,
-          callback: function (aNotification, aButton) {
-            var refreshURI = aNotification.docShell
-                                          .QueryInterface(Ci.nsIRefreshURI);
-            refreshURI.forceRefreshURI(aNotification.refreshURI,
-                                       aNotification.delay, true);
-          }
-        }];
-        notification =
-          notificationBox.appendNotification(message, "refresh-blocked",
-                                             "chrome://browser/skin/Info.png",
-                                             notificationBox.PRIORITY_INFO_MEDIUM,
-                                             buttons);
-        notification.refreshURI = aURI;
-        notification.delay = aDelay;
-        notification.docShell = docShell;
-      }
-      return false;
-    }
-    return true;
-  },
-
   // Properties used to cache security state used to update the UI
   _state: null,
   _host: undefined,
   _tooltipText: null,
   _hostChanged: false, // onLocationChange will flip this bit
 
   onSecurityChange: function (aWebProgress, aRequest, aState) {
     // Don't need to do anything if the data we use to update the UI hasn't
@@ -4154,19 +4101,25 @@ var XULBrowserWindow = {
       case wpl.STATE_IS_BROKEN:
         level = "broken";
         break;
     }
 
     if (level) {
       this.securityButton.setAttribute("level", level);
       this.securityButton.hidden = false;
+      // We don't style the Location Bar based on the the 'level' attribute
+      // anymore, but still set it for third-party themes.
+      if (gURLBar)
+        gURLBar.setAttribute("level", level);
     } else {
       this.securityButton.hidden = true;
       this.securityButton.removeAttribute("level");
+      if (gURLBar)
+        gURLBar.removeAttribute("level");
     }
 
     if (setHost && this._host)
       this.securityButton.setAttribute("label", this._host);
     else
       this.securityButton.removeAttribute("label");
 
     this.securityButton.setAttribute("tooltiptext", this._tooltipText);
@@ -4239,16 +4192,83 @@ var XULBrowserWindow = {
     var notification = Components.isSuccessCode(aStatus) ? "EndDocumentLoad" : "FailDocumentLoad";
     try {
       observerService.notifyObservers(content, notification, urlStr);
     } catch (e) {
     }
   }
 }
 
+var TabsProgressListener = {
+  onProgressChange: function (aBrowser, aWebProgress, aRequest,
+                              aCurSelfProgress, aMaxSelfProgress,
+                              aCurTotalProgress, aMaxTotalProgress) {
+  },
+
+  onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
+  },
+
+  onLocationChange: function (aBrowser, aWebProgress, aRequest, aLocationURI) {
+  },
+  
+  onStatusChange: function (aBrowser, aWebProgress, aRequest, aStatus, aMessage) {
+  },
+
+  onRefreshAttempted: function (aBrowser, aWebProgress, aURI, aDelay, aSameURI) {
+    if (gPrefService.getBoolPref("accessibility.blockautorefresh")) {
+      let brandBundle = document.getElementById("bundle_brand");
+      let brandShortName = brandBundle.getString("brandShortName");
+      let refreshButtonText =
+        gNavigatorBundle.getString("refreshBlocked.goButton");
+      let refreshButtonAccesskey =
+        gNavigatorBundle.getString("refreshBlocked.goButton.accesskey");
+      let message =
+        gNavigatorBundle.getFormattedString(aSameURI ? "refreshBlocked.refreshLabel"
+                                                     : "refreshBlocked.redirectLabel",
+                                            [brandShortName]);
+      let docShell = aWebProgress.DOMWindow
+                                 .QueryInterface(Ci.nsIInterfaceRequestor)
+                                 .getInterface(Ci.nsIWebNavigation)
+                                 .QueryInterface(Ci.nsIDocShell);
+      let notificationBox = gBrowser.getNotificationBox(aBrowser);
+      let notification = notificationBox.getNotificationWithValue("refresh-blocked");
+      if (notification) {
+        notification.label = message;
+        notification.refreshURI = aURI;
+        notification.delay = aDelay;
+        notification.docShell = docShell;
+      } else {
+        let buttons = [{
+          label: refreshButtonText,
+          accessKey: refreshButtonAccesskey,
+          callback: function (aNotification, aButton) {
+            var refreshURI = aNotification.docShell
+                                          .QueryInterface(Ci.nsIRefreshURI);
+            refreshURI.forceRefreshURI(aNotification.refreshURI,
+                                       aNotification.delay, true);
+          }
+        }];
+        notification =
+          notificationBox.appendNotification(message, "refresh-blocked",
+                                             "chrome://browser/skin/Info.png",
+                                             notificationBox.PRIORITY_INFO_MEDIUM,
+                                             buttons);
+        notification.refreshURI = aURI;
+        notification.delay = aDelay;
+        notification.docShell = docShell;
+      }
+      return false;
+    }
+    return true;
+  },
+
+  onSecurityChange: function (aBrowser, aWebProgress, aRequest, aState) {
+  }
+}
+
 function nsBrowserAccess()
 {
 }
 
 nsBrowserAccess.prototype =
 {
   QueryInterface : function(aIID)
   {
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -266,19 +266,19 @@
            onpopupshowing="return BookmarksEventHandler.fillInBTTooltip(document.tooltipNode)">
     <vbox id="btTooltipTextBox" flex="1">
       <label id="btTitleText" class="tooltip-label" />
       <label id="btUrlText" crop="center" class="tooltip-label" />
     </vbox>
   </tooltip>
 
   <toolbox id="navigator-toolbox" class="toolbox-top" mode="icons"
-           ondragover="gBrowser._onDragOver(event); event.stopPropagation();"
-           ondrop="gBrowser._onDrop(event); event.stopPropagation();"
-           ondragleave="gBrowser._onDragLeave(event); event.stopPropagation();"
+           ondragover="gBrowser._onDragOver(event);"
+           ondrop="gBrowser._onDrop(event);"
+           ondragleave="gBrowser._onDragLeave(event);"
            defaultmode="icons">
     <!-- Menu -->
     <toolbar type="menubar" id="toolbar-menubar" class="chromeclass-menubar" customizable="true"
              defaultset="menubar-items"
              mode="icons" iconsize="small" defaulticonsize="small"
              context="toolbar-context-menu">
       <toolbaritem id="menubar-items" align="center">
 # The entire main menubar is placed into browser-menubar.inc, so that it can be shared by 
--- a/browser/base/content/sanitize.js
+++ b/browser/base/content/sanitize.js
@@ -225,17 +225,20 @@ Sanitizer.prototype = {
           if (searchBar) {
             searchBar.value = "";
             searchBar.textbox.editor.transactionManager.clear();
           }
         }
 
         var formHistory = Components.classes["@mozilla.org/satchel/form-history;1"]
                                     .getService(Components.interfaces.nsIFormHistory2);
-        formHistory.removeAllEntries();
+        if (this.range)
+          formHistory.removeEntriesByTimeframe(this.range[0], this.range[1]);
+        else
+          formHistory.removeAllEntries();
       },
 
       get canClear()
       {
         var windowManager = Components.classes['@mozilla.org/appshell/window-mediator;1']
                                       .getService(Components.interfaces.nsIWindowMediator);
         var windows = windowManager.getEnumerator("navigator:browser");
         while (windows.hasMoreElements()) {
--- a/browser/base/content/sanitize.xul
+++ b/browser/base/content/sanitize.xul
@@ -192,17 +192,17 @@
     <preferences id="nonItemPreferences">
       <preference id="privacy.sanitize.timeSpan"
                   name="privacy.sanitize.timeSpan"
                   type="int"/>
     </preferences>
 
     <groupbox orient="vertical">
       <caption label="&historySection.label;"/>
-      <hbox id="SanitizeDurationBox">
+      <hbox id="SanitizeDurationBox" align="center">
         <label value="&clearDuration.label;" control="sanitizeDurationChoice" id="sanitizeDurationLabel"/>
         <menulist id="sanitizeDurationChoice"
                   preference="privacy.sanitize.timeSpan">
           <menupopup>
             <menuitem label="&clearDuration.lastHour;" value="1"/>
             <menuitem label="&clearDuration.last2Hours;" value="2"/>
             <menuitem label="&clearDuration.last4Hours;" value="3"/>
             <menuitem label="&clearDuration.today;" value="4"/>
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -64,28 +64,28 @@
       <stylesheet src="chrome://browser/content/tabbrowser.css"/>
     </resources>
 
     <content>
       <xul:stringbundle anonid="tbstringbundle" src="chrome://browser/locale/tabbrowser.properties"/>
       <xul:tabbox anonid="tabbox" flex="1" eventnode="document" xbl:inherits="handleCtrlPageUpDown"
                   onselect="if (!('updateCurrentBrowser' in this.parentNode) || event.target.localName != 'tabpanels') return; this.parentNode.updateCurrentBrowser();">
         <xul:hbox class="tab-drop-indicator-bar" collapsed="true" chromedir="&locale.dir;"
-                  ondragover="this.parentNode.parentNode._onDragOver(event); event.stopPropagation();"
-                  ondragleave="this.parentNode.parentNode._onDragLeave(event); event.stopPropagation();"
-                  ondrop="this.parentNode.parentNode._onDrop(event); event.stopPropagation();">
+                  ondragover="this.parentNode.parentNode._onDragOver(event);"
+                  ondragleave="this.parentNode.parentNode._onDragLeave(event);"
+                  ondrop="this.parentNode.parentNode._onDrop(event);">
           <xul:hbox class="tab-drop-indicator" mousethrough="always"/>
         </xul:hbox>
         <xul:hbox class="tabbrowser-strip" collapsed="true" tooltip="_child" context="_child"
                   anonid="strip"
-                  ondragstart="this.parentNode.parentNode._onDragStart(event); event.stopPropagation();"
-                  ondragover="this.parentNode.parentNode._onDragOver(event); event.stopPropagation();"
-                  ondrop="this.parentNode.parentNode._onDrop(event); event.stopPropagation();"
-                  ondragend="this.parentNode.parentNode._onDragEnd(event); event.stopPropagation();"
-                  ondragleave="this.parentNode.parentNode._onDragLeave(event); event.stopPropagation();">
+                  ondragstart="this.parentNode.parentNode._onDragStart(event);"
+                  ondragover="this.parentNode.parentNode._onDragOver(event);"
+                  ondrop="this.parentNode.parentNode._onDrop(event);"
+                  ondragend="this.parentNode.parentNode._onDragEnd(event);"
+                  ondragleave="this.parentNode.parentNode._onDragLeave(event);">
           <xul:tooltip onpopupshowing="return this.parentNode.parentNode.parentNode.createTooltip(event);"/>
           <xul:menupopup anonid="tabContextMenu" onpopupshowing="this.parentNode.parentNode.parentNode.updatePopupMenu(this);">
             <xul:menuitem id="context_newTab" label="&newTab.label;" accesskey="&newTab.accesskey;"
                           xbl:inherits="oncommand=onnewtab"/>
             <xul:menuseparator/>
             <xul:menuitem id="context_reloadTab" label="&reloadTab.label;" accesskey="&reloadTab.accesskey;"
                           oncommand="var tabbrowser = this.parentNode.parentNode.parentNode.parentNode;
                                      tabbrowser.reloadTab(tabbrowser.mContextTab);"/>
@@ -189,24 +189,29 @@
         null
       </field>
       <field name="mCurrentBrowser">
         null
       </field>
       <field name="mProgressListeners">
         []
       </field>
+      <field name="mTabsProgressListeners">
+        []
+      </field>
       <field name="mTabListeners">
-        new Array()
+        []
       </field>
       <field name="mTabFilters">
-        new Array()
+        []
       </field>
+      <!-- This field is obsolete and will be removed in a future release
+           FIXME: Remove for Firefox 4 -->
       <field name="mTabbedMode">
-        false
+        true
       </field>
       <field name="mIsBusy">
         false
       </field>
       <field name="mContextTab">
         null
       </field>
       <field name="arrowKeysShouldWrap" readonly="true">
@@ -298,32 +303,48 @@
 
             // count of open requests (should always be 0 or 1)
             mRequestCount: 0,
 
             onProgressChange : function (aWebProgress, aRequest,
                                          aCurSelfProgress, aMaxSelfProgress,
                                          aCurTotalProgress, aMaxTotalProgress)
             {
-              if (!this.mBlank && this.mTabBrowser.mCurrentTab == this.mTab) {
+              this.mTotalProgress = aMaxTotalProgress ? aCurTotalProgress / aMaxTotalProgress : 0;
+
+              if (this.mBlank)
+                return;
+
+              if (this.mTabBrowser.mCurrentTab == this.mTab) {
                 for (var i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) {
                   var p = this.mTabBrowser.mProgressListeners[i];
                   if (p)
                     try {
                       p.onProgressChange(aWebProgress, aRequest,
                                          aCurSelfProgress, aMaxSelfProgress,
                                          aCurTotalProgress, aMaxTotalProgress);
                     } catch (e) {
                       // don't inhibit other listeners or following code
                       Components.utils.reportError(e);
                     }
                 }
               }
 
-              this.mTotalProgress = aMaxTotalProgress ? aCurTotalProgress / aMaxTotalProgress : 0;
+              for (var i = 0; i < this.mTabBrowser.mTabsProgressListeners.length; i++) {
+                var p = this.mTabBrowser.mTabsProgressListeners[i];
+                if (p)
+                  try {
+                    p.onProgressChange(this.mBrowser, aWebProgress, aRequest,
+                                       aCurSelfProgress, aMaxSelfProgress,
+                                       aCurTotalProgress, aMaxTotalProgress);
+                  } catch (e) {
+                    // don't inhibit other listeners or following code
+                    Components.utils.reportError(e);
+                  }
+              }
             },
 
             onProgressChange64 : function (aWebProgress, aRequest,
                                          aCurSelfProgress, aMaxSelfProgress,
                                          aCurTotalProgress, aMaxTotalProgress)
             {
               return this.onProgressChange(aWebProgress, aRequest,
                 aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress,
@@ -422,16 +443,27 @@
                         p.onUpdateCurrentBrowser(aStateFlags, aStatus, "", 0);
                     } catch (e) {
                       // don't inhibit other listeners or following code
                       Components.utils.reportError(e);
                     }
                 }
               }
 
+              for (var i = 0; i < this.mTabBrowser.mTabsProgressListeners.length; i++) {
+                var p = this.mTabBrowser.mTabsProgressListeners[i];
+                if (p)
+                  try {
+                    p.onStateChange(this.mBrowser, aWebProgress, aRequest, aStateFlags, aStatus);
+                  } catch (e) {
+                    // don't inhibit other listeners or following code
+                    Components.utils.reportError(e);
+                  }
+              }
+
               if (aStateFlags & (nsIWebProgressListener.STATE_START |
                                  nsIWebProgressListener.STATE_STOP)) {
                 // reset cached temporary values at beginning and end
                 this.mMessage = "";
                 this.mTotalProgress = 0;
               }
               this.mStateFlags = aStateFlags;
               this.mStatus = aStatus;
@@ -445,28 +477,42 @@
 
               if (aWebProgress.DOMWindow == this.mBrowser.contentWindow &&
                   aWebProgress.isLoadingDocument)
                 this.mTabBrowser.setIcon(this.mTab, null);
 
               // changing location, clear out the missing plugins list
               this.mBrowser.missingPlugins = null;
 
-              if (!this.mBlank && this.mTabBrowser.mCurrentTab == this.mTab) {
+              if (this.mBlank)
+                return;
+
+              if (this.mTabBrowser.mCurrentTab == this.mTab) {
                 for (var i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) {
                   var p = this.mTabBrowser.mProgressListeners[i];
                   if (p)
                     try {
                       p.onLocationChange(aWebProgress, aRequest, aLocation);
                     } catch (e) {
                       // don't inhibit other listeners
                       Components.utils.reportError(e);
                     }
                 }
               }
+
+              for (var i = 0; i < this.mTabBrowser.mTabsProgressListeners.length; i++) {
+                var p = this.mTabBrowser.mTabsProgressListeners[i];
+                if (p)
+                  try {
+                    p.onLocationChange(this.mBrowser, aWebProgress, aRequest, aLocation);
+                  } catch (e) {
+                    // don't inhibit other listeners
+                    Components.utils.reportError(e);
+                  }
+              }
             },
 
             onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage)
             {
               if (this.mBlank)
                 return;
 
               if (this.mTabBrowser.mCurrentTab == this.mTab) {
@@ -477,16 +523,27 @@
                       p.onStatusChange(aWebProgress, aRequest, aStatus, aMessage);
                     } catch (e) {
                       // don't inhibit other listeners or following code
                       Components.utils.reportError(e);
                     }
                 }
               }
 
+              for (var i = 0; i < this.mTabBrowser.mTabsProgressListeners.length; i++) {
+                var p = this.mTabBrowser.mTabsProgressListeners[i];
+                if (p)
+                  try {
+                    p.onStatusChange(this.mBrowser, aWebProgress, aRequest, aStatus, aMessage);
+                  } catch (e) {
+                    // don't inhibit other listeners or following code
+                    Components.utils.reportError(e);
+                  }
+              }
+
               this.mMessage = aMessage;
             },
 
             onSecurityChange : function(aWebProgress, aRequest, aState)
             {
               if (this.mTabBrowser.mCurrentTab == this.mTab) {
                 for (var i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) {
                   var p = this.mTabBrowser.mProgressListeners[i];
@@ -494,36 +551,62 @@
                     try {
                       p.onSecurityChange(aWebProgress, aRequest, aState);
                     } catch (e) {
                       // don't inhibit other listeners
                       Components.utils.reportError(e);
                     }
                 }
               }
+
+              for (var i = 0; i < this.mTabBrowser.mTabsProgressListeners.length; i++) {
+                var p = this.mTabBrowser.mTabsProgressListeners[i];
+                if (p)
+                  try {
+                    p.onSecurityChange(this.mBrowser, aWebProgress, aRequest, aState);
+                  } catch (e) {
+                    // don't inhibit other listeners
+                    Components.utils.reportError(e);
+                  }
+              }
             },
 
-             onRefreshAttempted : function(aWebProgress, aURI, aDelay, aSameURI)
-             {
-               var allowRefresh = true;
-               for (var i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) {
-                 var p = this.mTabBrowser.mProgressListeners[i];
-                 if (p && "onRefreshAttempted" in p) {
-                   try {
-                     if (!p.onRefreshAttempted(aWebProgress, aURI, aDelay, aSameURI))
-                       allowRefresh = false;
-                    } catch (e) {
-                      // don't inhibit other listeners or following code
-                      Components.utils.reportError(e);
-                    }
-                 }
-               }
-               return allowRefresh;
-             },
- 
+            onRefreshAttempted : function(aWebProgress, aURI, aDelay, aSameURI)
+            {
+              var allowRefresh = true;
+              if (this.mTabBrowser.mCurrentTab == this.mTab) {
+                for (var i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) {
+                  var p = this.mTabBrowser.mProgressListeners[i];
+                  if (p && "onRefreshAttempted" in p) {
+                    try {
+                      if (!p.onRefreshAttempted(aWebProgress, aURI, aDelay, aSameURI))
+                        allowRefresh = false;
+                     } catch (e) {
+                       // don't inhibit other listeners or following code
+                       Components.utils.reportError(e);
+                     }
+                  }
+                }
+              }
+
+              for (var i = 0; i < this.mTabBrowser.mTabsProgressListeners.length; i++) {
+                var p = this.mTabBrowser.mTabsProgressListeners[i];
+                if (p && "onRefreshAttempted" in p) {
+                  try {
+                    if (!p.onRefreshAttempted(this.mBrowser, aWebProgress, aURI, aDelay, aSameURI))
+                      allowRefresh = false;
+                   } catch (e) {
+                     // don't inhibit other listeners or following code
+                     Components.utils.reportError(e);
+                   }
+                }
+              }
+              return allowRefresh;
+            },
+
             QueryInterface : function(aIID)
             {
               if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
                   aIID.equals(Components.interfaces.nsIWebProgressListener2) ||
                   aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
                   aIID.equals(Components.interfaces.nsISupports))
                 return this;
               throw Components.results.NS_NOINTERFACE;
@@ -548,18 +631,31 @@
                 aURI = ios.newURI(aURI, null, null);
               }
               this.mFaviconService.setAndLoadFaviconForPage(browser.currentURI,
                                                             aURI, false);
             }
 
             this.updateIcon(aTab);
 
-            for (var i = 0; i < this.mProgressListeners.length; i++) {
-              var p = this.mProgressListeners[i];
+            if (browser == this.mCurrentBrowser) {
+              for (var i = 0; i < this.mProgressListeners.length; i++) {
+                var p = this.mProgressListeners[i];
+                if ('onLinkIconAvailable' in p)
+                  try {
+                    p.onLinkIconAvailable(browser);
+                  } catch (e) {
+                    // don't inhibit other listeners
+                    Components.utils.reportError(e);
+                  }
+              }
+            }
+
+            for (var i = 0; i < this.mTabsProgressListeners.length; i++) {
+              var p = this.mTabsProgressListeners[i];
               if ('onLinkIconAvailable' in p)
                 try {
                   p.onLinkIconAvailable(browser);
                 } catch (e) {
                   // don't inhibit other listeners
                   Components.utils.reportError(e);
                 }
             }
@@ -1002,78 +1098,38 @@
         <parameter name="aShow"/>
         <body>
         <![CDATA[
           this.mStrip.collapsed = !aShow;
           if (aShow) {
             // XXXdwh temporary unclean dependency on specific menu items in navigator.xul
             document.getElementById("menu_closeWindow").hidden = false;
             document.getElementById("menu_close").setAttribute("label", this.mStringBundle.getString("tabs.closeTab"));
-            if (!this.mTabbedMode)
-              this.enterTabbedMode();
           }
           else {
             // XXXdwh temporary unclean dependency on specific menu items in navigator.xul
             document.getElementById("menu_closeWindow").hidden = true;
             document.getElementById("menu_close").setAttribute("label", this.mStringBundle.getString("tabs.close"));
           }
         ]]>
         </body>
       </method>
 
       <method name="getStripVisibility">
         <body>
           return !this.mStrip.collapsed;
         </body>
       </method>
 
+      <!-- This method is obsolete and will be removed in a future release
+           FIXME: Remove for Firefox 4 -->
       <method name="enterTabbedMode">
         <body>
-          <![CDATA[
-            this.mTabbedMode = true; // Welcome to multi-tabbed mode.
-
-            // Get the first tab all hooked up with a title listener and popup blocking listener.
-            this.mCurrentBrowser.addEventListener("DOMTitleChanged", this.onTitleChanged, true);
-
-            if (XULBrowserWindow.isBusy) {
-              this.mCurrentTab.setAttribute("busy", "true");
-              this.mIsBusy = true;
-              this.setTabTitleLoading(this.mCurrentTab);
-              this.updateIcon(this.mCurrentTab);
-            } else {
-              this.setTabTitle(this.mCurrentTab);
-              this.setIcon(this.mCurrentTab, this.mCurrentBrowser.mIconURL);
-            }
-
-            var filter;
-            if (this.mTabFilters.length > 0) {
-              // Use the filter hooked up in our addProgressListener
-              filter = this.mTabFilters[0];
-            } else {
-              // create a filter and hook it up to our first browser
-              filter = Components.classes["@mozilla.org/appshell/component/browser-status-filter;1"]
-                                 .createInstance(Components.interfaces.nsIWebProgress);
-              this.mTabFilters[0] = filter;
-              this.mCurrentBrowser.webProgress.addProgressListener(filter, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
-            }
-
-            // Remove all our progress listeners from the active browser's filter.
-            for (var i = 0; i < this.mProgressListeners.length; i++) {
-              var p = this.mProgressListeners[i];
-              if (p)
-                filter.removeProgressListener(p);
-            }
-
-            // Wire up a progress listener to our filter.
-            const listener = this.mTabProgressListener(this.mCurrentTab,
-                                                       this.mCurrentBrowser,
-                                                       false);
-            filter.addProgressListener(listener, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
-            this.mTabListeners[0] = listener;
-          ]]>
+          Application.console.log("enterTabbedMode is an obsolete method and " +
+                                  "will be removed in a future release.");
         </body>
       </method>
 
       <method name="loadOneTab">
         <parameter name="aURI"/>
         <parameter name="aReferrerURI"/>
         <parameter name="aCharset"/>
         <parameter name="aPostData"/>
@@ -1141,19 +1197,16 @@
         <parameter name="aCharset"/>
         <parameter name="aPostData"/>
         <parameter name="aOwner"/>
         <parameter name="aAllowThirdPartyFixup"/>
         <body>
           <![CDATA[
             this._browsers = null; // invalidate cache
 
-            if (!this.mTabbedMode)
-              this.enterTabbedMode();
-
             // if we're adding tabs, we're past interrupt mode, ditch the owner
             if (this.mCurrentTab.owner)
               this.mCurrentTab.owner = null;
 
             var t = document.createElementNS(
               "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
                                              "tab");
 
@@ -1680,62 +1733,53 @@
             if (!this.mAddProgressListenerWasCalled) {
               this.mAddProgressListenerWasCalled = true;
               var autoHide = this.mPrefs.getBoolPref("browser.tabs.autoHide");
               var tabStripHide = !window.toolbar.visible;
               if (!autoHide && !tabStripHide)
                 this.setStripVisibilityTo(true);
             }
 
-            if (!this.mTabbedMode && this.mProgressListeners.length == 1) {
-              // If we are adding a 2nd progress listener, we need to enter tabbed mode
-              // because the browser status filter can only handle one progress listener.
-              // In tabbed mode, mTabProgressListener is used which will iterate over all listeners.
-              this.enterTabbedMode();
-            }
-
             this.mProgressListeners.push(aListener);
-
-            if (!this.mTabbedMode) {
-              // If someone does this:
-              // addProgressListener, removeProgressListener, addProgressListener
-              // don't create a new filter; reuse the existing filter.
-              if (this.mTabFilters.length == 0) {
-                // hook a filter up to our first browser
-                const filter = Components.classes["@mozilla.org/appshell/component/browser-status-filter;1"]
-                                         .createInstance(Components.interfaces.nsIWebProgress);
-                this.mTabFilters[0] = filter;
-                this.mCurrentBrowser.webProgress.addProgressListener(filter, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
-              }
-
-              // Directly hook the listener up to the filter for better performance
-              this.mTabFilters[0].addProgressListener(aListener, aMask);
-            }
           ]]>
         </body>
       </method>
 
       <method name="removeProgressListener">
         <parameter name="aListener"/>
         <body>
           <![CDATA[
             for (var i = 0; i < this.mProgressListeners.length; i++) {
               if (this.mProgressListeners[i] == aListener) {
                 this.mProgressListeners.splice(i, 1);
                 break;
               }
             }
-
-            if (!this.mTabbedMode)
-              // Don't forget to remove it from the filter we hooked it up to
-              this.mTabFilters[0].removeProgressListener(aListener);
          ]]>
         </body>
       </method>
 
+      <method name="addTabsProgressListener">
+        <parameter name="aListener"/>
+        <body>
+          this.mTabsProgressListeners.push(aListener);
+        </body>
+      </method>
+
+      <method name="removeTabsProgressListener">
+        <parameter name="aListener"/>
+        <body>
+        <![CDATA[
+          var pos = this.mTabsProgressListeners.indexOf(aListener);
+          if (pos >= 0)
+            this.mTabsProgressListeners.splice(pos, 1);
+        ]]>
+        </body>
+      </method>
+
       <method name="getBrowserForTab">
         <parameter name="aTab"/>
         <body>
         <![CDATA[
           return aTab.linkedBrowser;
         ]]>
         </body>
       </method>
@@ -1793,114 +1837,130 @@
           ]]>
         </getter>
       </property>
 
       <method name="_onDragStart">
         <parameter name="aEvent"/>
         <body>
         <![CDATA[
+          // don't interfere with toolbar customization
+          if (gNavToolbox.customizing)
+            return;
+
           var target = aEvent.target;
           if (target.localName == "tab" &&
               aEvent.originalTarget.localName != "toolbarbutton") {
             var dt = aEvent.dataTransfer;
             // We're internetionally not setting any other data-type, otherwise
             // applications may override our drop-as-window behavior
             dt.mozSetDataAt("application/x-moz-tabbrowser-tab", target, 0);
 
             var canvas = tabPreviews.capture(target, false);
             dt.setDragImage(canvas, 0, 0);
+            aEvent.stopPropagation();
           }
         ]]>
         </body>
       </method>
 
       <field name="mDragTime">0</field>
       <field name="mDragOverDelay">350</field>
 
       <field name="_supportedLinkDropTypes"><![CDATA[
         ["text/x-moz-url", "text/uri-list", "text/plain", "application/x-moz-file"]
       ]]></field>
 
       <field name="_cachedTargetInToolbox">null</field>
+      <field name="_draggingOnItself">false</field>
       <method name="_setEffectAllowedForDataTransfer">
         <parameter name="aEvent"/>
         <body>
           <![CDATA[
+            this._draggingOnItself = false;
+
             // Find out if the we're dragged over the toolbox
             var target = aEvent.target;
             var isInToolbox = target == this._cachedTargetInToolbox;
             while (target && !isInToolbox) {
               if (target == gNavToolbox) {
                 isInToolbox = true;
                 this._cachedTargetInToolbox = target;
               }
               else
                 target = target.parentNode;
             }
 
+            // NOTE: within the toolbox, we don't touch effectAllowed for
+            // anything but tabs
             var dt = aEvent.dataTransfer;
             // Disallow dropping multiple items
             if (dt.mozItemCount > 1)
-              return dt.effectAllowed = "none";
+              return isInToolbox ? "" : dt.effectAllowed = "none";
 
             var types = dt.mozTypesAt(0);
             var sourceNode = null;
             // tabs are always added as the first type
             if (types[0] == "application/x-moz-tabbrowser-tab") {
               var sourceNode = dt.mozGetDataAt("application/x-moz-tabbrowser-tab", 0);
               if (sourceNode instanceof XULElement &&
                   sourceNode.localName == "tab" &&
                   (sourceNode.parentNode == this.mTabContainer ||
                    (sourceNode.ownerDocument.defaultView instanceof ChromeWindow &&
                     sourceNode.ownerDocument.documentElement.getAttribute("windowtype") == "navigator:browser"))) {
                 if (sourceNode.parentNode == this.mTabContainer &&
                     (aEvent.screenX >= sourceNode.boxObject.screenX &&
                       aEvent.screenX <= (sourceNode.boxObject.screenX +
                                          sourceNode.boxObject.width))) {
+                  this._draggingOnItself = true;
                   return dt.effectAllowed = "none";
                 }
 
                 // Within the toolbox, allow dropping by the height of a tab off
                 // the tabbar
                 if (isInToolbox &&
                     aEvent.screenY < sourceNode.boxObject.screenY -
                                      sourceNode.boxObject.height)
                   return dt.effectAllowed = "none";
                 return dt.effectAllowed = "copyMove";
               }
             }
 
-            // only tab-drags are taken care off within the toolbox
-            if (!isInToolbox)
-              return dt.effectAllowed = "none";
+            // only tab-drags are taken care of within the toolbox
+            if (isInToolbox)
+              return ""; // see note above the tab-drags block
 
             for (var i=0; i < this._supportedLinkDropTypes.length; i++) {
               if (types.contains(this._supportedLinkDropTypes[i])) {
                 // Here we need to to do this manually
                 return dt.effectAllowed = dt.dropEffect = "link";
               }
             }
             return dt.effectAllowed = "none";
           ]]>
         </body>
       </method>
 
       <method name="_onDragOver">
         <parameter name="aEvent"/>
         <body>
           <![CDATA[
+            // don't interfere with toolbar customization
+            if (gNavToolbox.customizing)
+              return;
+
             var effects = this._setEffectAllowedForDataTransfer(aEvent);
 
             var ib = this.mTabDropIndicatorBar;
-            if (effects == "none") {
+            if (effects == "" || effects == "none") {
               ib.collapsed = "true";
               return;
             }
             aEvent.preventDefault();
+            aEvent.stopPropagation();
 
             var tabStrip = this.mTabContainer.mTabstrip;
             var ltr = (window.getComputedStyle(this.parentNode, null).direction
                        == "ltr");
 
             // autoscroll the tab strip if we drag over the scroll
             // buttons, even if we aren't dragging a tab, but then
             // return to avoid drawing the drop indicator
@@ -1984,26 +2044,32 @@
           ]]>
         </body>
       </method>
 
       <method name="_onDrop">
         <parameter name="aEvent"/>
         <body>
           <![CDATA[
+            // don't interfere with toolbar customization
+            if (gNavToolbox.customizing)
+              return;
+
             var dt = aEvent.dataTransfer;
             var dropEffect = dt.dropEffect;
             var draggedTab;
             if (dropEffect != "link") { // copy or move
               draggedTab = dt.mozGetDataAt("application/x-moz-tabbrowser-tab", 0);
-              NS_ASSERT(draggedTab && draggedTab.localName == "tab",
-                        "copy or move action without a tab");
+              // not our drop then
+              if (!draggedTab)
+                return;
             }
 
             this.mTabDropIndicatorBar.collapsed = true;
+            aEvent.stopPropagation();
 
             if (draggedTab && (dropEffect == "copy" ||
                 draggedTab.parentNode == this.mTabContainer)) {
               var newIndex = this.getNewIndex(aEvent);
               if (dropEffect == "copy") {
                 // copy the dropped tab (wherever it's from)
                 var newTab = this.duplicateTab(draggedTab);
                 this.moveTabTo(newTab, newIndex);
@@ -2102,20 +2168,21 @@
       <method name="_onDragEnd">
         <parameter name="aEvent"/>
         <body>
           <![CDATA[
             if (this.mTabs.length == 1)
               return;
 
             var dt = aEvent.dataTransfer;
-            if (dt.dropEffect == "none") {
+            if (dt.dropEffect == "none" && !this._draggingOnItself) {
               var draggedTab = dt.mozGetDataAt("application/x-moz-tabbrowser-tab", 0);
               this._replaceTabWithWindow(draggedTab);
             }
+            aEvent.stopPropagation();
           ]]>
         </body>
       </method>
 
       <method name="_replaceTabWithWindow">
         <parameter name="aTab"/>
         <body>
           <![CDATA[
@@ -2140,16 +2207,18 @@
             // This does not work at all (see bug 458613)
             var target = aEvent.relatedTarget;
             while (target && (target != this && target != gNavToolbox))
               target = target.parentNode;
             if (target)
               return;
 
             this.mTabDropIndicatorBar.collapsed = true;
+            this._draggingOnItself = false;
+            aEvent.stopPropagation();
           ]]>
         </body>
       </method>
 
       <method name="moveTabTo">
         <parameter name="aTab"/>
         <parameter name="aIndex"/>
         <body>
@@ -2617,16 +2686,26 @@
           this.mTabContainer.childNodes[0].linkedPanel = uniqueId;
           this.mTabContainer.childNodes[0]._tPos = 0;
           this.mTabContainer.childNodes[0].linkedBrowser = this.mPanelContainer.childNodes[0].firstChild;
 
           // set up the shared autoscroll popup
           this._autoScrollPopup = this.mCurrentBrowser._createAutoScrollPopup();
           this.appendChild(this._autoScrollPopup);
           this.mCurrentBrowser.setAttribute("autoscrollpopup", this._autoScrollPopup.id);
+
+          // Hook up the event listeners to the first browser
+          this.mCurrentBrowser.addEventListener("DOMTitleChanged", this.onTitleChanged, true);
+          var tabListener = this.mTabProgressListener(this.mCurrentTab, this.mCurrentBrowser, true);
+          const filter = Components.classes["@mozilla.org/appshell/component/browser-status-filter;1"]
+                                   .createInstance(Components.interfaces.nsIWebProgress);
+          filter.addProgressListener(tabListener, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
+          this.mCurrentBrowser.webProgress.addProgressListener(filter, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
+          this.mTabListeners[0] = tabListener;
+          this.mTabFilters[0] = filter;
         ]]>
       </constructor>
 
       <destructor>
         <![CDATA[
           for (var i = 0; i < this.mTabListeners.length; ++i) {
             this.getBrowserAtIndex(i).webProgress.removeProgressListener(this.mTabFilters[i]);
             this.mTabFilters[i].removeProgressListener(this.mTabListeners[i]);
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -73,16 +73,18 @@ include $(topsrcdir)/config/rules.mk
                  browser_gestureSupport.js \
                  browser_feed_tab.js \
                  feed_tab.html \
                  browser_pluginnotification.js \
                  plugin_unknown.html \
                  plugin_test.html \
                  plugin_both.html \
                  plugin_both2.html \
+                 browser_alltabslistener.js \
+                 alltabslistener.html \
     $(NULL)
 
 ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT)))
 _BROWSER_FILES += browser_customize.js \
     $(NULL)
 endif
 
 libs:: $(_TEST_FILES)
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/alltabslistener.html
@@ -0,0 +1,8 @@
+<html>
+<head>
+<title>Test page for bug 463387</title>
+</head>
+<body>
+<p>Test page for bug 463387</p>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_alltabslistener.js
@@ -0,0 +1,196 @@
+const Ci = Components.interfaces;
+
+const gCompleteState = Ci.nsIWebProgressListener.STATE_STOP +
+                       Ci.nsIWebProgressListener.STATE_IS_NETWORK;
+
+var gFrontProgressListener = {
+  onProgressChange: function (aWebProgress, aRequest,
+                              aCurSelfProgress, aMaxSelfProgress,
+                              aCurTotalProgress, aMaxTotalProgress) {
+  },
+
+  onStateChange: function (aWebProgress, aRequest, aStateFlags, aStatus) {
+    var state = "onStateChange";
+    ok(gFrontNotificationsPos < gFrontNotifications.length, "Got an expected notification for the front notifications listener");
+    is(state, gFrontNotifications[gFrontNotificationsPos], "Got a notification for the front notifications listener");
+    gFrontNotificationsPos++;
+  },
+
+  onLocationChange: function (aWebProgress, aRequest, aLocationURI) {
+    var state = "onLocationChange";
+    ok(gFrontNotificationsPos < gFrontNotifications.length, "Got an expected notification for the front notifications listener");
+    is(state, gFrontNotifications[gFrontNotificationsPos], "Got a notification for the front notifications listener");
+    gFrontNotificationsPos++;
+  },
+  
+  onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) {
+  },
+
+  onSecurityChange: function (aWebProgress, aRequest, aState) {
+    var state = "onSecurityChange";
+    ok(gFrontNotificationsPos < gFrontNotifications.length, "Got an expected notification for the front notifications listener");
+    is(state, gFrontNotifications[gFrontNotificationsPos], "Got a notification for the front notifications listener");
+    gFrontNotificationsPos++;
+  }
+}
+
+var gAllProgressListener = {
+  onProgressChange: function (aBrowser, aWebProgress, aRequest,
+                              aCurSelfProgress, aMaxSelfProgress,
+                              aCurTotalProgress, aMaxTotalProgress) {
+  },
+
+  onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
+    var state = "onStateChange";
+    ok(aBrowser == gTestBrowser, state + " notification came from the correct browser");
+    ok(gAllNotificationsPos < gAllNotifications.length, "Got an expected notification for the all notifications listener");
+    is(state, gAllNotifications[gAllNotificationsPos], "Got a notification for the all notifications listener");
+    gAllNotificationsPos++;
+
+    if ((aStateFlags & gCompleteState) == gCompleteState) {
+      ok(gAllNotificationsPos == gAllNotifications.length, "Saw the expected number of notifications");
+      ok(gFrontNotificationsPos == gFrontNotifications.length, "Saw the expected number of frontnotifications");
+      executeSoon(gNextTest);
+    }
+  },
+
+  onLocationChange: function (aBrowser, aWebProgress, aRequest, aLocationURI) {
+    var state = "onLocationChange";
+    ok(aBrowser == gTestBrowser, state + " notification came from the correct browser");
+    ok(gAllNotificationsPos < gAllNotifications.length, "Got an expected notification for the all notifications listener");
+    is(state, gAllNotifications[gAllNotificationsPos], "Got a notification for the all notifications listener");
+    gAllNotificationsPos++;
+  },
+  
+  onStatusChange: function (aBrowser, aWebProgress, aRequest, aStatus, aMessage) {
+    var state = "onStatusChange";
+    ok(aBrowser == gTestBrowser, state + " notification came from the correct browser");
+  },
+
+  onSecurityChange: function (aBrowser, aWebProgress, aRequest, aState) {
+    var state = "onSecurityChange";
+    ok(aBrowser == gTestBrowser, state + " notification came from the correct browser");
+    ok(gAllNotificationsPos < gAllNotifications.length, "Got an expected notification for the all notifications listener");
+    is(state, gAllNotifications[gAllNotificationsPos], "Got a notification for the all notifications listener");
+    gAllNotificationsPos++;
+  }
+}
+
+var gFrontNotifications, gAllNotifications, gFrontNotificationsPos, gAllNotificationsPos;
+var gBackgroundTab, gForegroundTab, gBackgroundBrowser, gForegroundBrowser, gTestBrowser;
+var gTestPage = "/browser/browser/base/content/test/alltabslistener.html";
+var gNextTest;
+
+function test() {
+  waitForExplicitFinish();
+
+  gBackgroundTab = gBrowser.addTab("about:blank");
+  gForegroundTab = gBrowser.addTab("about:blank");
+  gBackgroundBrowser = gBrowser.getBrowserForTab(gBackgroundTab);
+  gForegroundBrowser = gBrowser.getBrowserForTab(gForegroundTab);
+  gBrowser.selectedTab = gForegroundTab;
+
+  // We must wait until the about:blank page has completed loading before
+  // starting tests or we get notifications from that
+  gForegroundBrowser.addEventListener("load", startTests, true);
+}
+
+function runTest(browser, url, next) {
+  gFrontNotificationsPos = 0;
+  gAllNotificationsPos = 0;
+  gNextTest = next;
+  gTestBrowser = browser;
+  browser.loadURI(url);
+}
+
+function startTests() {
+  gForegroundBrowser.removeEventListener("load", startTests, true);
+  executeSoon(startTest1);
+}
+
+function startTest1() {
+  gBrowser.addProgressListener(gFrontProgressListener);
+  gBrowser.addTabsProgressListener(gAllProgressListener);
+
+  gAllNotifications = [
+    "onStateChange",
+    "onLocationChange",
+    "onSecurityChange",
+    "onStateChange"
+  ];
+  gFrontNotifications = gAllNotifications;
+  runTest(gForegroundBrowser, "http://example.org" + gTestPage, startTest2);
+}
+
+function startTest2() {
+  gAllNotifications = [
+    "onStateChange",
+    "onLocationChange",
+    "onSecurityChange",
+    "onSecurityChange",
+    "onStateChange"
+  ];
+  gFrontNotifications = gAllNotifications;
+  runTest(gForegroundBrowser, "https://example.com" + gTestPage, startTest3);
+}
+
+function startTest3() {
+  gAllNotifications = [
+    "onStateChange",
+    "onLocationChange",
+    "onSecurityChange",
+    "onStateChange"
+  ];
+  gFrontNotifications = [];
+  runTest(gBackgroundBrowser, "http://example.org" + gTestPage, startTest4);
+}
+
+function startTest4() {
+  gAllNotifications = [
+    "onStateChange",
+    "onLocationChange",
+    "onSecurityChange",
+    "onSecurityChange",
+    "onStateChange"
+  ];
+  gFrontNotifications = [];
+  runTest(gBackgroundBrowser, "https://example.com" + gTestPage, startTest5);
+}
+
+function startTest5() {
+  // Switch the foreground browser
+  [gForegroundBrowser, gBackgroundBrowser] = [gBackgroundBrowser, gForegroundBrowser];
+  [gForegroundTab, gBackgroundTab] = [gBackgroundTab, gForegroundTab];
+  // Avoid the onLocationChange this will fire
+  gBrowser.removeProgressListener(gFrontProgressListener);
+  gBrowser.selectedTab = gForegroundTab;
+  gBrowser.addProgressListener(gFrontProgressListener);
+
+  gAllNotifications = [
+    "onStateChange",
+    "onLocationChange",
+    "onSecurityChange",
+    "onStateChange"
+  ];
+  gFrontNotifications = gAllNotifications;
+  runTest(gForegroundBrowser, "http://example.org" + gTestPage, startTest6);
+}
+
+function startTest6() {
+  gAllNotifications = [
+    "onStateChange",
+    "onLocationChange",
+    "onSecurityChange",
+    "onStateChange"
+  ];
+  gFrontNotifications = [];
+  runTest(gBackgroundBrowser, "http://example.org" + gTestPage, finishTest);
+}
+
+function finishTest() {
+  gBrowser.removeProgressListener(gFrontProgressListener);
+  gBrowser.removeTabsProgressListener(gAllProgressListener);
+  gBrowser.removeTab(gBackgroundTab);
+  gBrowser.removeTab(gForegroundTab);
+  finish();
+}
--- a/browser/base/content/test/browser_sanitize-timespans.js
+++ b/browser/base/content/test/browser_sanitize-timespans.js
@@ -1,39 +1,41 @@
 // Bug 453440 - Test the timespan-based logic of the sanitizer code
 var now_uSec = Date.now() * 1000;
 
 const dm = Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager);
 const bhist = Cc["@mozilla.org/browser/global-history;2"].getService(Ci.nsIBrowserHistory);
 const iosvc = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
+const formhist = Cc["@mozilla.org/satchel/form-history;1"].getService(Ci.nsIFormHistory2);
 
 Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Components.interfaces.mozIJSSubScriptLoader)
                                            .loadSubScript("chrome://browser/content/sanitize.js");
 
 function test() {
   
   var hoursSinceMidnight = new Date().getHours();
 
   setupHistory();
+  setupFormHistory();
   setupDownloads();
   
   // Should test cookies here, but nsICookieManager/nsICookieService
   // doesn't let us fake creation times.  bug 463127
   
   let s = new Sanitizer();
   s.ignoreTimespan = false;
   s.prefDomain = "privacy.cpd.";
   var itemPrefs = Cc["@mozilla.org/preferences-service;1"]
                   .getService(Components.interfaces.nsIPrefService)
                   .getBranch(s.prefDomain);
   itemPrefs.setBoolPref("history", true);
   itemPrefs.setBoolPref("downloads", true);
   itemPrefs.setBoolPref("cache", false);
   itemPrefs.setBoolPref("cookies", false);
-  itemPrefs.setBoolPref("formdata", false);
+  itemPrefs.setBoolPref("formdata", true);
   itemPrefs.setBoolPref("offlineApps", false);
   itemPrefs.setBoolPref("passwords", false);
   itemPrefs.setBoolPref("sessions", false);
   itemPrefs.setBoolPref("siteprefs", false);
   
   // Clear 1 hour
   Sanitizer.prefs.setIntPref("timeSpan", 1);
   s.sanitize();
@@ -41,16 +43,23 @@ function test() {
   ok(!bhist.isVisited(uri("http://1hour.com")), "1hour.com should now be deleted");
   ok(bhist.isVisited(uri("http://2hour.com")), "Pretend visit to 2hour.com should still exist");
   ok(bhist.isVisited(uri("http://4hour.com")), "Pretend visit to 4hour.com should still exist");
   
   if(hoursSinceMidnight > 1)
     ok(bhist.isVisited(uri("http://today.com")), "Pretend visit to today.com should still exist");
   ok(bhist.isVisited(uri("http://before-today.com")), "Pretend visit to before-today.com should still exist");
   
+  ok(!formhist.nameExists("1hour"), "1hour form entry should be deleted");
+  ok(formhist.nameExists("2hour"), "2hour form entry should still exist");
+  ok(formhist.nameExists("4hour"), "4hour form entry should still exist");
+  if(hoursSinceMidnight > 1)
+    ok(formhist.nameExists("today"), "today form entry should still exist");
+  ok(formhist.nameExists("b4today"), "b4today form entry should still exist");
+
   ok(!downloadExists(5555551), "<1 hour download should now be deleted");
   ok(downloadExists(5555550), "Year old download should still be present");
   ok(downloadExists(5555552), "<2 hour old download should still be present");
   ok(downloadExists(5555553), "<4 hour old download should still be present");
 
   if(hoursSinceMidnight > 1)
     ok(downloadExists(5555554), "'Today' download should still be present");
   
@@ -59,51 +68,68 @@ function test() {
   s.sanitize();
   
   ok(!bhist.isVisited(uri("http://2hour.com")), "Pretend visit to 2hour.com should now be deleted");
   ok(bhist.isVisited(uri("http://4hour.com")), "Pretend visit to 4hour.com should still exist");
   if(hoursSinceMidnight > 2)
     ok(bhist.isVisited(uri("http://today.com")), "Pretend visit to today.com should still exist");
   ok(bhist.isVisited(uri("http://before-today.com")), "Pretend visit to before-today.com should still exist");
   
+  ok(!formhist.nameExists("2hour"), "2hour form entry should be deleted");
+  ok(formhist.nameExists("4hour"), "4hour form entry should still exist");
+  if(hoursSinceMidnight > 2)
+    ok(formhist.nameExists("today"), "today form entry should still exist");
+  ok(formhist.nameExists("b4today"), "b4today form entry should still exist");
+
+  ok(formhist.nameExists("b4today"), "b4today form entry should still exist");
   ok(!downloadExists(5555552), "<2 hour old download should now be deleted");
   ok(downloadExists(5555550), "Year old download should still be present");
   ok(downloadExists(5555553), "<4 hour old download should still be present");
   if(hoursSinceMidnight > 2)
     ok(downloadExists(5555554), "'Today' download should still be present");
   
   // Clear 4 hours
   Sanitizer.prefs.setIntPref("timeSpan", 3);
   s.sanitize();
   
   ok(!bhist.isVisited(uri("http://4hour.com")), "Pretend visit to 4hour.com should now be deleted");
   if(hoursSinceMidnight > 4)
     ok(bhist.isVisited(uri("http://today.com")), "Pretend visit to today.com should still exist");
   ok(bhist.isVisited(uri("http://before-today.com")), "Pretend visit to before-today.com should still exist");
   
+  ok(!formhist.nameExists("4hour"), "4hour form entry should be deleted");
+  if(hoursSinceMidnight > 4)
+    ok(formhist.nameExists("today"), "today form entry should still exist");
+  ok(formhist.nameExists("b4today"), "b4today form entry should still exist");
+
   ok(!downloadExists(5555553), "<4 hour old download should now be deleted");
   ok(downloadExists(5555550), "Year old download should still be present");
   if(hoursSinceMidnight > 4)
     ok(downloadExists(5555554), "'Today' download should still be present");
 
   // Clear Today
   Sanitizer.prefs.setIntPref("timeSpan", 4);
   s.sanitize();
   
   ok(!bhist.isVisited(uri("http://today.com")), "Pretend visit to today.com should now be deleted");
   ok(bhist.isVisited(uri("http://before-today.com")), "Pretend visit to before-today.com should still exist");
 
+  ok(!formhist.nameExists("today"), "today form entry should be deleted");
+  ok(formhist.nameExists("b4today"), "b4today form entry should still exist");
+
   ok(!downloadExists(5555554), "'Today' download should now be deleted");
   ok(downloadExists(5555550), "Year old download should still be present");
 
   // Choose everything
   Sanitizer.prefs.setIntPref("timeSpan", 0);
   s.sanitize();
   
   ok(!bhist.isVisited(uri("http://before-today.com")), "Pretend visit to before-today.com should now be deleted");
+
+  ok(!formhist.nameExists("b4today"), "b4today form entry should be deleted");
   
   ok(!downloadExists(5555550), "Year old download should now be deleted");
 
 }
 
 function setupHistory() {
   bhist.addPageWithDetails(uri("http://1hour.com/"), "Less than 1 hour ago", now_uSec - 45*60*1000000);
   bhist.addPageWithDetails(uri("http://2hour.com/"), "Less than 2 hours ago", now_uSec - 90*60*1000000);
@@ -111,27 +137,72 @@ function setupHistory() {
   
   let today = new Date();
   today.setHours(0);
   today.setMinutes(0);
   today.setSeconds(30);
   bhist.addPageWithDetails(uri("http://today.com/"), "Today", today.valueOf() * 1000);
   
   let lastYear = new Date();
-  lastYear.setFullYear(lastYear.year - 1);
+  lastYear.setFullYear(lastYear.getFullYear() - 1);
   bhist.addPageWithDetails(uri("http://before-today.com/"), "Before Today", lastYear.valueOf() * 1000);
   
   // Confirm everything worked
   ok(bhist.isVisited(uri("http://1hour.com")), "Pretend visit to 1hour.com should exist");
   ok(bhist.isVisited(uri("http://2hour.com")), "Pretend visit to 2hour.com should exist");
   ok(bhist.isVisited(uri("http://4hour.com")), "Pretend visit to 4hour.com should exist");
   ok(bhist.isVisited(uri("http://today.com")), "Pretend visit to today.com should exist");
   ok(bhist.isVisited(uri("http://before-today.com")), "Pretend visit to before-today.com should exist");
 }
 
+function setupFormHistory() {
+  // Make sure we've got a clean DB to start with.
+  formhist.removeAllEntries();
+
+  // Add the entries we'll be testing.
+  formhist.addEntry("1hour", "1h");
+  formhist.addEntry("2hour", "2h");
+  formhist.addEntry("4hour", "4h");
+  formhist.addEntry("today", "1d");
+  formhist.addEntry("b4today", "1y");
+
+  // Artifically age the entries to the proper vintage.
+  let db = formhist.DBConnection;
+  let timestamp = now_uSec - 45*60*1000000;
+  db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
+                      timestamp +  " WHERE fieldname = '1hour'");
+  timestamp = now_uSec - 90*60*1000000;
+  db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
+                      timestamp +  " WHERE fieldname = '2hour'");
+  timestamp = now_uSec - 180*60*1000000;
+  db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
+                      timestamp +  " WHERE fieldname = '4hour'");
+
+  let today = new Date();
+  today.setHours(0);
+  today.setMinutes(0);
+  today.setSeconds(1);
+  timestamp = today.valueOf() * 1000;
+  db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
+                      timestamp +  " WHERE fieldname = 'today'");
+
+  let lastYear = new Date();
+  lastYear.setFullYear(lastYear.getFullYear() - 1);
+  timestamp = lastYear.valueOf() * 1000;
+  db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
+                      timestamp +  " WHERE fieldname = 'b4today'");
+
+  // Sanity check.
+  ok(formhist.nameExists("1hour"), "Checking for 1hour form history entry creation");
+  ok(formhist.nameExists("2hour"), "Checking for 2hour form history entry creation");
+  ok(formhist.nameExists("4hour"), "Checking for 4hour form history entry creation");
+  ok(formhist.nameExists("today"), "Checking for today form history entry creation");
+  ok(formhist.nameExists("b4today"), "Checking for b4today form history entry creation");
+}
+
 function setupDownloads() {
 
   // Add within-1-hour download to DB
   let data = {
     id:   "5555551",
     name: "fakefile-1-hour",
     source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440",
     target: "fakefile-1-hour",
@@ -221,17 +292,17 @@ function setupDownloads() {
     stmt.execute();
   }
   finally {
     stmt.reset();
   }
   
   // Add "before today" download
   let lastYear = new Date();
-  lastYear.setFullYear(lastYear.year - 1);
+  lastYear.setFullYear(lastYear.getFullYear() - 1);
   data = {
     id:   "5555550",
     name: "fakefile-old",
     source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440",
     target: "fakefile-old",
     startTime: lastYear.valueOf() * 1000,  // 1 year ago, in uSec
     endTime: (lastYear.valueOf() + 1000) * 1000, // 1 second later
     state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -534,37 +534,42 @@ BrowserGlue.prototype = {
     else {
       // Create a new Organizer left pane folder root, the old will not be
       // valid anymore.
       this._prefs.setIntPref("browser.places.leftPaneFolderId", -1);
 
       // ensurePlacesDefaultQueriesInitialized() is called by import.
       this._prefs.setIntPref("browser.places.smartBookmarksVersion", 0);
 
-      // Get bookmarks folder
+      // Get bookmarks.html file location
       var dirService = Cc["@mozilla.org/file/directory_service;1"].
                        getService(Ci.nsIProperties);
-      var bookmarksFile = dirService.get("BMarks", Ci.nsILocalFile);
 
-      // User wants to restore default bookmarks
-      if (restoreDefaultBookmarks || !bookmarksFile.exists()) {
-        // get bookmarks.html file from default profile folder
-        bookmarksFile = dirService.get("profDef", Ci.nsILocalFile);
-        bookmarksFile.append("bookmarks.html");
+      var bookmarksFile = null;
+      if (restoreDefaultBookmarks) {
+        // User wants to restore bookmarks.html file from default profile folder
+        bookmarksFile = dirService.get("profDef", Ci.nsILocalFile)
+                                      .append("bookmarks.html");
       }
+      else
+        bookmarksFile = dirService.get("BMarks", Ci.nsILocalFile);
 
-      // import the file
-      try {
-        var importer = Cc["@mozilla.org/browser/places/import-export-service;1"].
-                       getService(Ci.nsIPlacesImportExportService);
-        importer.importHTMLFromFile(bookmarksFile, true /* overwrite existing */);
-      } catch (err) {
-        // Report the error, but ignore it.
-        Cu.reportError(err);
+      if (bookmarksFile.exists()) {
+        // import the file
+        try {
+          var importer = Cc["@mozilla.org/browser/places/import-export-service;1"].
+                         getService(Ci.nsIPlacesImportExportService);
+          importer.importHTMLFromFile(bookmarksFile, true /* overwrite existing */);
+        } catch (err) {
+          // Report the error, but ignore it.
+          Cu.reportError("Bookmarks.html file could be corrupt. " + err);
+        }
       }
+      else
+        Cu.reportError("Unable to find bookmarks.html file.");
 
       // Reset preferences, so we won't try to import again at next run
       if (importBookmarksHTML)
         this._prefs.setBoolPref("browser.places.importBookmarksHTML", false);
       if (restoreDefaultBookmarks)
         this._prefs.setBoolPref("browser.bookmarks.restore_default_bookmarks",
                                 false);
     }
--- a/browser/components/places/content/menu.xml
+++ b/browser/components/places/content/menu.xml
@@ -149,16 +149,17 @@
           }
           else if (scrollDir == 1)
             newMarginTop = sbo.height;
 
           // set the new marginTop based on arrowscrollbox
           newMarginTop += sbo.y - this._scrollBox.boxObject.y;
           this._indicatorBar.firstChild.style.marginTop = newMarginTop + "px";
           this._indicatorBar.hidden = false;
+          aEvent.stopPropagation();
         ]]></body>
       </method>
 
       <method name="onDragExit">
         <parameter name="aEvent"/>
         <parameter name="aDragSession"/>
         <body><![CDATA[
           PlacesControllerDragHelper.currentDropTarget = null;
@@ -207,32 +208,34 @@
           // activate the view and cache the dragged node
           this._rootView._draggedNode = draggedNode;
           this._rootView.focus();
 
           // Fill the dataTransfer
           this._rootView._controller.setDataTransfer(aEvent);
 
           this.setAttribute("dragstart", "true");
+          aEvent.stopPropagation();
         ]]></body>
       </method>
 
       <method name="onDrop">
         <parameter name="aEvent"/>
         <parameter name="aDropData"/>
         <parameter name="aSession"/>
         <body><![CDATA[
           // Cache the dataTransfer
           PlacesControllerDragHelper.currentDataTransfer = aEvent.dataTransfer;
 
           var dropPoint = this._getDropPoint(aEvent);
           if (!dropPoint)
             return;
 
           PlacesControllerDragHelper.onDrop(dropPoint.ip);
+          aEvent.stopPropagation();
         ]]></body>
       </method>
 
       <!-- This returns the FavourSet accepted by this popup -->
       <method name="getSupportedFlavours">
         <body><![CDATA[
           return PlacesControllerDragHelper.flavourSet;
         ]]></body>
@@ -516,17 +519,17 @@
         var node = event.target;
         if (node.parentNode != this)
           return;
 
         if (window.XULBrowserWindow)
           window.XULBrowserWindow.setOverLink("", null);
       ]]></handler>
       <handler event="draggesture" action="if (event.target.node) nsDragAndDrop.startDrag(event, this);"/>
-      <handler event="dragdrop" action="nsDragAndDrop.drop(event, this);"/>
+      <handler event="drop" action="nsDragAndDrop.drop(event, this);"/>
       <handler event="dragover" action="nsDragAndDrop.dragOver(event, this);"/>
       <handler event="dragexit" action="nsDragAndDrop.dragExit(event, this);"/>
     </handlers>
   </binding>
 
 
   <binding id="places-menupopup"
            extends="chrome://browser/content/places/menu.xml#places-popup-base">
--- a/browser/components/places/content/toolbar.xml
+++ b/browser/components/places/content/toolbar.xml
@@ -1017,39 +1017,40 @@
           draggedDOMNode.firstChild.hidePopup();
         }
 
         // activate the view and cache the dragged node
         this._draggedNode = draggedDOMNode.node;
         this.focus();
 
         this._controller.setDataTransfer(event);
+        event.stopPropagation();
       ]]></handler>
 
       <handler event="dragover"><![CDATA[
         // Cache the dataTransfer
         var dt = PlacesControllerDragHelper.currentDataTransfer =
                  event.dataTransfer;
 
+        var ib = this._dropIndicatorBar;
         var ip = this.insertionPoint;
         if (!ip || !PlacesControllerDragHelper.canDrop(ip)) {
           ib.removeAttribute("dragging");
           PlacesControllerDragHelper.currentDataTransfer = null;
           return;
         }
 
         PlacesControllerDragHelper.currentDropTarget = event.target;
         var dropPoint = this._getDropPoint(event);
 
         if (this._ibTimer) {
           this._ibTimer.cancel();
           this._ibTimer = null;
         }
 
-        var ib = this._dropIndicatorBar;
         if (dropPoint.folderNode ||
             event.originalTarget == this._chevron) {
           // Dropping over a menubutton or chevron button
           // set styles and timer to open relative menupopup
           var overNode = dropPoint.folderNode || this._chevron;
           if (this._overFolder.node != overNode) {
             this._clearOverFolder();
             this._overFolder.node = overNode;
@@ -1096,31 +1097,41 @@
             }
           }
           // Clear out old folder information
           this._clearOverFolder();
         }
 
         dt.effectAllowed = "all";
         event.preventDefault();
+        event.stopPropagation();
       ]]></handler>
 
       <handler event="drop"><![CDATA[
-        // If the data-transfer isn't cached, it's not ours
-        // This happens when dropping tabs
-        if (event.dataTransfer != PlacesControllerDragHelper.currentDataTransfer)
+        PlacesControllerDragHelper.currentDataTransfer = event.dataTransfer;
+        PlacesControllerDragHelper.currentDropTarget = event.target;
+
+        var ip = this.insertionPoint;
+        if (!ip || !PlacesControllerDragHelper.canDrop(ip))
           return;
 
         var dropPoint = this._getDropPoint(event);
         if (!dropPoint)
           return;
+
         PlacesControllerDragHelper.onDrop(dropPoint.ip);
+        event.stopPropagation();
       ]]></handler>
 
       <handler event="dragleave"><![CDATA[
+        // Only handle dragleaves for the toolbar itself (and not for its child
+        // nodes)
+        if (event.target != this)
+          return;
+
         PlacesControllerDragHelper.currentDropTarget = null;
         PlacesControllerDragHelper.currentDataTransfer = null;
 
         // Set timer to turn off indicator bar (if we turn it off
         // here, dragenter might be called immediately after, creating
         // flicker.)
         if (this._ibTimer)
           this._ibTimer.cancel();
--- a/browser/components/sessionstore/src/nsSessionStore.js
+++ b/browser/components/sessionstore/src/nsSessionStore.js
@@ -1948,36 +1948,44 @@ SessionStoreService.prototype = {
    * Restore properties to a loaded document
    */
   restoreDocument_proxy: function sss_restoreDocument_proxy(aEvent) {
     // wait for the top frame to be loaded completely
     if (!aEvent || !aEvent.originalTarget || !aEvent.originalTarget.defaultView || aEvent.originalTarget.defaultView != aEvent.originalTarget.defaultView.top) {
       return;
     }
     
+    // always call this before injecting content into a document!
+    function hasExpectedURL(aDocument, aURL)
+      !aURL || aURL.replace(/#.*/, "") == aDocument.location.href.replace(/#.*/, "");
+    
     // restore text data saved by Firefox 2.0/3.0
     var textArray = this.__SS_restore_text ? this.__SS_restore_text.split(" ") : [];
-    function restoreTextData(aContent, aPrefix) {
+    function restoreTextData(aContent, aPrefix, aURL) {
       textArray.forEach(function(aEntry) {
-        if (/^((?:\d+\|)*)(#?)([^\s=]+)=(.*)$/.test(aEntry) && RegExp.$1 == aPrefix) {
+        if (/^((?:\d+\|)*)(#?)([^\s=]+)=(.*)$/.test(aEntry) &&
+            RegExp.$1 == aPrefix && hasExpectedURL(aContent.document, aURL)) {
           var document = aContent.document;
           var node = RegExp.$2 ? document.getElementById(RegExp.$3) : document.getElementsByName(RegExp.$3)[0] || null;
           if (node && "value" in node) {
             node.value = decodeURI(RegExp.$4);
             
             var event = document.createEvent("UIEvents");
             event.initUIEvent("input", true, true, aContent, 0);
             node.dispatchEvent(event);
           }
         }
       });
     }
     
-    function restoreFormData(aDocument, aData) {
+    function restoreFormData(aDocument, aData, aURL) {
       for (let key in aData) {
+        if (!hasExpectedURL(aDocument, aURL))
+          return;
+        
         let node = key.charAt(0) == "#" ? aDocument.getElementById(key.slice(1)) :
                                           XPathHelper.resolve(aDocument, key);
         if (!node)
           continue;
         
         let value = aData[key];
         if (typeof value == "string") {
           node.value = value;
@@ -1997,46 +2005,47 @@ SessionStoreService.prototype = {
             aOpt.selected = value.indexOf(aIx) > -1;
           });
         }
         // NB: dispatching "change" events might have unintended side-effects
       }
     }
     
     let selectedPageStyle = this.__SS_restore_pageStyle;
+    let window = this.ownerDocument.defaultView;
     function restoreTextDataAndScrolling(aContent, aData, aPrefix) {
       if (aData.formdata)
-        restoreFormData(aContent.document, aData.formdata);
+        restoreFormData(aContent.document, aData.formdata, aData.url);
       else
-        restoreTextData(aContent, aPrefix);
+        restoreTextData(aContent, aPrefix, aData.url);
       if (aData.innerHTML) {
-        aContent.setTimeout(
-              function(aHTML) {
-                if (aContent.document.designMode == "on") {
-                  aContent.document.body.innerHTML = aHTML;
-                }
-              }, 0, aData.innerHTML);
+        window.setTimeout(function() {
+          if (aContent.document.designMode == "on" &&
+              hasExpectedURL(aContent.document, aData.url)) {
+            aContent.document.body.innerHTML = aData.innerHTML;
+          }
+        }, 0);
       }
       if (aData.scroll && /(\d+),(\d+)/.test(aData.scroll)) {
         aContent.scrollTo(RegExp.$1, RegExp.$2);
       }
       Array.forEach(aContent.document.styleSheets, function(aSS) {
         aSS.disabled = aSS.title && aSS.title != selectedPageStyle;
       });
       for (var i = 0; i < aContent.frames.length; i++) {
-        if (aData.children && aData.children[i]) {
+        if (aData.children && aData.children[i] &&
+          hasExpectedURL(aContent.document, aData.url)) {
           restoreTextDataAndScrolling(aContent.frames[i], aData.children[i], aPrefix + i + "|");
         }
       }
     }
     
     // don't restore text data and scrolling state if the user has navigated
     // away before the loading completed (except for in-page navigation)
-    if (!this.__SS_restore_data.url || this.currentURI.spec.replace(/#.*/, "") ==
-                                       this.__SS_restore_data.url.replace(/#.*/, "")) {
+    if (hasExpectedURL(aEvent.originalTarget, this.__SS_restore_data.url)) {
       var content = aEvent.originalTarget.defaultView;
       if (this.currentURI.spec == "about:config") {
         // unwrap the document for about:config because otherwise the properties
         // of the XBL bindings - as the textbox - aren't accessible (see bug 350718)
         content = content.wrappedJSObject;
       }
       restoreTextDataAndScrolling(content, this.__SS_restore_data, "");
       this.markupDocumentViewer.authorStyleDisabled = selectedPageStyle == "_nostyle";
--- a/browser/installer/removed-files.in
+++ b/browser/installer/removed-files.in
@@ -579,16 +579,17 @@ res/fonts/fontEncoding.properties
 res/fonts/pangoFontEncoding.properties
 res/fonts/fontNameMap.properties
 @DLL_PREFIX@xpcom_compat@DLL_SUFFIX@
 components/nsDictionary.js
 components/nsXmlRpcClient.js
 components/nsInterfaceInfoToIDL.js
 components/nsScriptableIO.js
 chrome/chromelist.txt
+modules/JSON.jsm
 #ifdef XP_MACOSX
 LICENSE
 extensions/inspector@mozilla.org/chrome/chromelist.txt
 components/accessibility.xpt
 components/crashreporter.xpt
 components/gksvgrenderer.xpt
 components/jsconsole.xpt
 components/necko_data.xpt
--- a/configure.in
+++ b/configure.in
@@ -5301,17 +5301,17 @@ if test -n "$MOZ_OGG"; then
     AC_DEFINE(MOZ_OGG)
     MOZ_SYDNEYAUDIO=1
     MOZ_MEDIA=1
 fi
 
 dnl ========================================================
 dnl = Disable Wave decoder support
 dnl ========================================================
-MOZ_ARG_ENABLE_BOOL(wave,
+MOZ_ARG_DISABLE_BOOL(wave,
 [  --disable-wave          Disable Wave decoder support],
     MOZ_WAVE=,
     MOZ_WAVE=1)
 
 AC_SUBST(MOZ_WAVE)
 
 if test -n "$MOZ_WAVE"; then
     AC_DEFINE(MOZ_WAVE)
--- a/content/events/src/nsEventStateManager.h
+++ b/content/events/src/nsEventStateManager.h
@@ -58,17 +58,19 @@ class nsIPresShell;
 class nsIDocShell;
 class nsIDocShellTreeNode;
 class nsIDocShellTreeItem;
 class nsIFocusController;
 class imgIContainer;
 class nsDOMDataTransfer;
 
 // mac uses click-hold context menus, a holdover from 4.x
-#ifdef XP_MACOSX
+// touch screens (like hildon) could use this also, 
+// perhaps we should move to NS_TOUCHSCREEN
+#if defined(XP_MACOSX) || defined(NS_HILDON)
 #define CLICK_HOLD_CONTEXT_MENUS 1
 #endif
 
 
 /*
  * Event listener manager
  */
 
--- a/content/media/video/public/nsOggDecoder.h
+++ b/content/media/video/public/nsOggDecoder.h
@@ -328,56 +328,60 @@ class nsOggDecoder : public nsMediaDecod
   virtual void UpdateBytesDownloaded(PRUint64 aBytes);
 
   // Called when the video file has completed downloading.
   // Call on the main thread only.
   void ResourceLoaded();
 
   // Called if the media file encounters a network error.
   // Call on the main thread only.
-  void NetworkError();
+  virtual void NetworkError();
 
   // Call from any thread safely. Return PR_TRUE if we are currently
   // seeking in the media resource.
   virtual PRBool IsSeeking() const;
 
   // Get the size of the media file in bytes. Called on the main thread only.
   virtual void SetTotalBytes(PRInt64 aBytes);
 
   // Set a flag indicating whether seeking is supported
   virtual void SetSeekable(PRBool aSeekable);
 
   // Return PR_TRUE if seeking is supported.
   virtual PRBool GetSeekable();
 
+  // Returns the channel reader.
+  nsChannelReader* GetReader() { return mReader; }
+
 protected:
-  // Change to a new play state. This updates the mState variable and
-  // notifies any thread blocking on this objects monitor of the
-  // change. Can be called on any thread.
-  void ChangeState(PlayState aState);
 
   // Returns the monitor for other threads to synchronise access to
-  // state
+  // state.
   PRMonitor* GetMonitor() 
   { 
     return mMonitor; 
   }
 
-  // Return the current state. The caller must have entered the
-  // monitor.
+  // Return the current state. Can be called on any thread. If called from
+  // a non-main thread, the decoder monitor must be held.
   PlayState GetState()
   {
     return mPlayState;
   }
 
   /****** 
    * The following methods must only be called on the main
    * thread.
    ******/
 
+  // Change to a new play state. This updates the mState variable and
+  // notifies any thread blocking on this object's monitor of the
+  // change. Call on the main thread only.
+  void ChangeState(PlayState aState);
+
   // Called when the metadata from the Ogg file has been read.
   // Call on the main thread only.
   void MetadataLoaded();
 
   // Called when the first frame has been loaded.
   // Call on the main thread only.
   void FirstFrameLoaded();
 
@@ -481,29 +485,34 @@ private:
   nsCOMPtr<nsOggDecodeStateMachine> mDecodeStateMachine;
 
   // OggPlay object used to read data from a channel. Created on main
   // thread. Passed to liboggplay and the locking for multithreaded
   // access is handled by that library. Some methods are called from
   // the decoder thread, and the state machine for that thread keeps
   // a pointer to this reader. This is safe as the only methods called
   // are threadsafe (via the threadsafe nsMediaStream).
-  nsChannelReader* mReader;
+  nsAutoPtr<nsChannelReader> mReader;
 
   // Monitor for detecting when the video play state changes. A call
   // to Wait on this monitor will block the thread until the next
   // state change.
   PRMonitor* mMonitor;
 
   // Set to one of the valid play states. It is protected by the
   // monitor mMonitor. This monitor must be acquired when reading or
   // writing the state. Any change to the state on the main thread
   // must call NotifyAll on the monitor so the decode thread can wake up.
   PlayState mPlayState;
 
-  // The state to change to after a seek or load operation. It is
-  // protected by the monitor mMonitor. This monitor must be acquired
-  // when reading or writing the state. Any change to the state must
-  // call NotifyAll on the monitor.
-  PlayState mNextState;
+  // The state to change to after a seek or load operation. It must only
+  // be changed from the main thread. The decoder monitor must be acquired
+  // when writing to the state, or when reading from a non-main thread.
+  // Any change to the state must call NotifyAll on the monitor.
+  PlayState mNextState;	
+
+  // Flags if we've called Stop(). Prevents multiple events being
+  // sent to call Shutdown(). Accessed on the main thread
+  // only.
+  PRPackedBool mIsStopping;
 };
 
 #endif
--- a/content/media/video/src/nsChannelReader.cpp
+++ b/content/media/video/src/nsChannelReader.cpp
@@ -66,17 +66,16 @@ float nsChannelReader::PlaybackRate()
 OggPlayErrorCode nsChannelReader::initialise(int aBlock)
 {
   return E_OGGPLAY_OK;
 }
 
 OggPlayErrorCode nsChannelReader::destroy()
 {
   mStream.Close();
-
   return E_OGGPLAY_OK;
 }
 
 size_t nsChannelReader::io_read(char* aBuffer, size_t aCount)
 {
   PRUint32 bytes = 0;
   nsresult rv = mStream.Read(aBuffer, aCount, &bytes);
   if (!NS_SUCCEEDED(rv)) {
@@ -108,19 +107,17 @@ static OggPlayErrorCode oggplay_channel_
     return E_OGGPLAY_BAD_READER;
   }
   return me->initialise(aBlock);
 }
 
 static OggPlayErrorCode oggplay_channel_reader_destroy(OggPlayReader* aReader) 
 {
   nsChannelReader* me = static_cast<nsChannelReader*>(aReader);
-  OggPlayErrorCode result = me->destroy();
-  delete me;
-  return result;
+  return me->destroy();
 }
 
 static size_t oggplay_channel_reader_io_read(void* aReader, void* aBuffer, size_t aCount) 
 {
   nsChannelReader* me = static_cast<nsChannelReader*>(aReader);
   return me->io_read(static_cast<char*>(aBuffer), aCount);
 }
 
--- a/content/media/video/src/nsMediaStream.cpp
+++ b/content/media/video/src/nsMediaStream.cpp
@@ -123,23 +123,22 @@ nsresult nsDefaultStreamStrategy::Open(n
 }
 
 nsresult nsDefaultStreamStrategy::Close()
 {
   nsAutoLock lock(mLock);
   if (mChannel) {
     mChannel->Cancel(NS_BINDING_ABORTED);
     mChannel = nsnull;
-
+  }
+  if (mPipeInput) {
     mPipeInput->Close();
     mPipeInput = nsnull;
-
-    mListener = nsnull;
   }
-
+  mListener = nsnull;
   return NS_OK;
 }
 
 nsresult nsDefaultStreamStrategy::Read(char* aBuffer, PRUint32 aCount, PRUint32* aBytes)
 {
   // The read request pulls from the pipe, not the channels input
   // stream. This allows calling from any thread as the pipe is
   // threadsafe.
@@ -461,23 +460,22 @@ nsresult nsHttpStreamStrategy::Open(nsIS
 }
 
 nsresult nsHttpStreamStrategy::Close()
 {
   nsAutoLock lock(mLock);
   if (mChannel) {
     mChannel->Cancel(NS_BINDING_ABORTED);
     mChannel = nsnull;
-
+  }
+  if (mPipeInput) {
     mPipeInput->Close();
     mPipeInput = nsnull;
-
-    mListener = nsnull;
   }
-
+  mListener = nsnull;
   return NS_OK;
 }
 
 nsresult nsHttpStreamStrategy::Read(char* aBuffer, PRUint32 aCount, PRUint32* aBytes)
 {
   // The read request pulls from the pipe, not the channels input
   // stream. This allows calling from any thread as the pipe is
   // threadsafe.
--- a/content/media/video/src/nsOggDecoder.cpp
+++ b/content/media/video/src/nsOggDecoder.cpp
@@ -210,17 +210,17 @@ public:
     DECODER_STATE_DECODING_FIRSTFRAME,
     DECODER_STATE_DECODING,
     DECODER_STATE_SEEKING,
     DECODER_STATE_BUFFERING,
     DECODER_STATE_COMPLETED,
     DECODER_STATE_SHUTDOWN
   };
 
-  nsOggDecodeStateMachine(nsOggDecoder* aDecoder, nsChannelReader* aReader);
+  nsOggDecodeStateMachine(nsOggDecoder* aDecoder);
   ~nsOggDecodeStateMachine();
 
   // Cause state transitions. These methods obtain the decoder monitor
   // to synchronise the change of state, and to notify other threads
   // that the state has changed.
   void Shutdown();
   void Decode();
   void Seek(float aTime);
@@ -384,23 +384,16 @@ private:
   float   mFramerate;
 
   // Audio data. These are initially set when the metadata is loaded.
   // They are only accessed from the decoder thread.
   PRInt32 mAudioRate;
   PRInt32 mAudioChannels;
   PRInt32 mAudioTrack;
 
-  // Channel Reader. Originally created by the mDecoder object, it is
-  // destroyed when we close the mPlayer handle in the
-  // destructor. Used to obtain download and playback rate information
-  // for buffering.  Synchronisation for those methods are handled by
-  // nsMediaStream.
-  nsChannelReader* mReader;
-
   // Time that buffering started. Used for buffering timeout and only
   // accessed in the decoder thread.
   PRIntervalTime mBufferingStart;
 
   // Number of bytes to buffer when buffering. Only accessed in the
   // decoder thread.
   PRUint32 mBufferingBytes;
 
@@ -456,30 +449,29 @@ private:
 
   // PR_TRUE if an event to notify about a change in the playback
   // position has been queued, but not yet run. It is set to PR_FALSE when
   // the event is run. This allows coalescing of these events as they can be
   // produced many times per second. Synchronised via decoder monitor.
   PRPackedBool mPositionChangeQueued;
 };
 
-nsOggDecodeStateMachine::nsOggDecodeStateMachine(nsOggDecoder* aDecoder, nsChannelReader* aReader) :
+nsOggDecodeStateMachine::nsOggDecodeStateMachine(nsOggDecoder* aDecoder) :
   mDecoder(aDecoder),
   mPlayer(0),
   mPlayStartTime(0),
   mPauseStartTime(0),
   mPauseDuration(0),
   mPlaying(PR_FALSE),
   mCallbackPeriod(1.0),
   mVideoTrack(-1),
   mFramerate(0.0),
   mAudioRate(0),
   mAudioChannels(0),
   mAudioTrack(-1),
-  mReader(aReader),
   mBufferingStart(0),
   mBufferingBytes(0),
   mLastFrameTime(0),
   mState(DECODER_STATE_DECODING_METADATA),
   mSeekTime(0.0),
   mCurrentFrameTime(0.0),
   mVolume(1.0),
   mDuration(-1),
@@ -489,21 +481,19 @@ nsOggDecodeStateMachine::nsOggDecodeStat
 {
 }
 
 nsOggDecodeStateMachine::~nsOggDecodeStateMachine()
 {
   while (!mDecodedFrames.IsEmpty()) {
     delete mDecodedFrames.Pop();
   }
-
   oggplay_close(mPlayer);
 }
 
-
 OggPlayErrorCode nsOggDecodeStateMachine::DecodeFrame()
 {
   NS_ASSERTION(mState > DECODER_STATE_DECODING_METADATA, "DecodeFrame() called during invalid state");
   return oggplay_step_decoding(mPlayer);
 }
 
 nsOggDecodeStateMachine::FrameData* nsOggDecodeStateMachine::NextFrame()
 {
@@ -848,16 +838,18 @@ void nsOggDecodeStateMachine::Seek(float
 {
   nsAutoMonitor mon(mDecoder->GetMonitor());
   mSeekTime = aTime;
   mState = DECODER_STATE_SEEKING;
 }
 
 nsresult nsOggDecodeStateMachine::Run()
 {
+  nsChannelReader* reader = mDecoder->GetReader();
+  NS_ENSURE_TRUE(reader, NS_ERROR_NULL_POINTER);
   while (PR_TRUE) {
    nsAutoMonitor mon(mDecoder->GetMonitor());
    switch(mState) {
     case DECODER_STATE_SHUTDOWN:
       return NS_OK;
 
     case DECODER_STATE_DECODING_METADATA:
       mon.Exit();
@@ -897,26 +889,26 @@ nsresult nsOggDecodeStateMachine::Run()
           mState = DECODER_STATE_DECODING;
         }
       }
       break;
 
     case DECODER_STATE_DECODING:
       {
         // Before decoding check if we should buffer more data
-        if (mReader->DownloadRate() >= 0 &&
-            mReader->Available() < mReader->PlaybackRate() * BUFFERING_SECONDS_LOW_WATER_MARK) {
+        if (reader->DownloadRate() >= 0 &&
+            reader->Available() < reader->PlaybackRate() * BUFFERING_SECONDS_LOW_WATER_MARK) {
           if (mDecoder->GetState() == nsOggDecoder::PLAY_STATE_PLAYING) {
             if (mPlaying) {
               StopPlayback();
             }
           }
 
           mBufferingStart = PR_IntervalNow();
-          mBufferingBytes = PRUint32(BUFFERING_RATE(mReader->PlaybackRate()) * BUFFERING_WAIT);
+          mBufferingBytes = PRUint32(BUFFERING_RATE(reader->PlaybackRate()) * BUFFERING_WAIT);
           mState = DECODER_STATE_BUFFERING;
 
           nsCOMPtr<nsIRunnable> event =
             NS_NEW_RUNNABLE_METHOD(nsOggDecoder, mDecoder, BufferingStarted);
           NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
         }
         else {
           if (!mDecodedFrames.IsFull()) {
@@ -1004,21 +996,21 @@ nsresult nsOggDecodeStateMachine::Run()
         if (mState == DECODER_STATE_SEEKING && mSeekTime == seekTime) {
           mState = DECODER_STATE_DECODING;
         }
       }
       break;
 
     case DECODER_STATE_BUFFERING:
       if ((PR_IntervalToMilliseconds(PR_IntervalNow() - mBufferingStart) < BUFFERING_WAIT*1000) &&
-          mReader->DownloadRate() >= 0 &&            
-          mReader->Available() < mBufferingBytes) {
+          reader->DownloadRate() >= 0 &&            
+          reader->Available() < mBufferingBytes) {
         LOG(PR_LOG_DEBUG, 
             ("Buffering data until %d bytes available or %d milliseconds", 
-             mBufferingBytes - mReader->Available(),
+             mBufferingBytes - reader->Available(),
              BUFFERING_WAIT*1000 - (PR_IntervalToMilliseconds(PR_IntervalNow() - mBufferingStart))));
         mon.Wait(PR_MillisecondsToInterval(1000));
         if (mState == DECODER_STATE_SHUTDOWN)
           continue;
       }
       else {
         mState = DECODER_STATE_DECODING;
       }
@@ -1064,17 +1056,17 @@ nsresult nsOggDecodeStateMachine::Run()
   }
 
   return NS_OK;
 }
 
 void nsOggDecodeStateMachine::LoadOggHeaders() 
 {
   LOG(PR_LOG_DEBUG, ("Loading Ogg Headers"));
-  mPlayer = oggplay_open_with_reader(mReader);
+  mPlayer = oggplay_open_with_reader(mDecoder->GetReader());
   if (mPlayer) {
     LOG(PR_LOG_DEBUG, ("There are %d tracks", oggplay_get_num_tracks(mPlayer)));
 
     for (int i = 0; i < oggplay_get_num_tracks(mPlayer); ++i) {
       LOG(PR_LOG_DEBUG, ("Tracks %d: %s", i, oggplay_get_track_typename(mPlayer, i)));
       if (mVideoTrack == -1 && oggplay_get_track_type(mPlayer, i) == OGGZ_CONTENT_THEORA) {
         oggplay_set_callback_num_frames(mPlayer, i, 1);
         mVideoTrack = i;
@@ -1179,17 +1171,18 @@ nsOggDecoder::nsOggDecoder() :
   mInitialVolume(0.0),
   mRequestedSeekTime(-1.0),
   mContentLength(-1),
   mNotifyOnShutdown(PR_FALSE),
   mSeekable(PR_TRUE),
   mReader(0),
   mMonitor(0),
   mPlayState(PLAY_STATE_PAUSED),
-  mNextState(PLAY_STATE_PAUSED)
+  mNextState(PLAY_STATE_PAUSED),
+  mIsStopping(PR_FALSE)
 {
   MOZ_COUNT_CTOR(nsOggDecoder);
 }
 
 PRBool nsOggDecoder::Init() 
 {
   mMonitor = nsAutoMonitor::NewMonitor("media.decoder");
   return mMonitor && nsMediaDecoder::Init();
@@ -1234,16 +1227,20 @@ nsOggDecoder::~nsOggDecoder()
 {
   MOZ_COUNT_DTOR(nsOggDecoder);
   nsAutoMonitor::DestroyMonitor(mMonitor);
 }
 
 nsresult nsOggDecoder::Load(nsIURI* aURI, nsIChannel* aChannel,
                             nsIStreamListener** aStreamListener)
 {
+  // Reset Stop guard flag flag, else shutdown won't occur properly when
+  // reusing decoder.
+  mIsStopping = PR_FALSE;
+
   if (aStreamListener) {
     *aStreamListener = nsnull;
   }
 
   if (aURI) {
     NS_ASSERTION(!aStreamListener, "No listener should be requested here");
     mURI = aURI;
   } else {
@@ -1265,17 +1262,17 @@ nsresult nsOggDecoder::Load(nsIURI* aURI
   NS_ENSURE_TRUE(mReader, NS_ERROR_OUT_OF_MEMORY);
 
   nsresult rv = mReader->Init(this, mURI, aChannel, aStreamListener);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = NS_NewThread(getter_AddRefs(mDecodeThread));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  mDecodeStateMachine = new nsOggDecodeStateMachine(this, mReader);
+  mDecodeStateMachine = new nsOggDecodeStateMachine(this);
   {
     nsAutoMonitor mon(mMonitor);
     mDecodeStateMachine->SetContentLength(mContentLength);
     mDecodeStateMachine->SetSeekable(mSeekable);
   }
 
   ChangeState(PLAY_STATE_LOADING);
 
@@ -1321,25 +1318,31 @@ nsresult nsOggDecoder::Seek(float aTime)
 
 nsresult nsOggDecoder::PlaybackRateChanged()
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 void nsOggDecoder::Stop()
 {
+  NS_ASSERTION(NS_IsMainThread(), 
+               "nsOggDecoder::Stop called on non-main thread");  
+  
+  if (mIsStopping)
+    return;
+  mIsStopping = PR_TRUE;
+
   ChangeState(PLAY_STATE_ENDED);
 
   StopProgress();
 
   // Force any outstanding seek and byterange requests to complete
   // to prevent shutdown from deadlocking.
   if (mReader) {
     mReader->Cancel();
-    mReader = nsnull;
   }
 
   // Shutdown must be on called the mDecodeStateMachine before deleting.
   // This is required to ensure that the state machine isn't running
   // in the thread and using internal objects when it is deleted.
   if (mDecodeStateMachine) {
     mDecodeStateMachine->Shutdown();
   }
@@ -1348,16 +1351,17 @@ void nsOggDecoder::Stop()
   // Shutdown. The Shutdown() on the state machine unblocks any
   // blocking calls preventing the thread Shutdown from deadlocking.
   if (mDecodeThread) {
     mDecodeThread->Shutdown();
     mDecodeThread = nsnull;
   }
 
   mDecodeStateMachine = nsnull;
+  mReader = nsnull;
   UnregisterShutdownObserver();
 }
 
 float nsOggDecoder::GetCurrentTime()
 {
   return mCurrentTime;
 }
 
@@ -1544,16 +1548,18 @@ void nsOggDecoder::UnregisterShutdownObs
       mNotifyOnShutdown = PR_FALSE;
       observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
     }
   }
 }
 
 void nsOggDecoder::ChangeState(PlayState aState)
 {
+  NS_ASSERTION(NS_IsMainThread(), 
+               "nsOggDecoder::ChangeState called on non-main thread");   
   nsAutoMonitor mon(mMonitor);
 
   if (mNextState == aState) {
     mNextState = PLAY_STATE_PAUSED;
   }
 
   if (mPlayState == PLAY_STATE_SHUTDOWN) {
     mon.NotifyAll();
--- a/dom/src/threads/nsDOMWorker.cpp
+++ b/dom/src/threads/nsDOMWorker.cpp
@@ -1020,17 +1020,17 @@ nsDOMWorker::CompileGlobalObject(JSConte
 
   NS_ASSERTION(!mScriptURL.IsEmpty(), "Must have a url here!");
 
   JSAutoRequest ar(aCx);
 
   NS_ASSERTION(!JS_GetGlobalObject(aCx), "Global object should be unset!");
 
   nsRefPtr<nsDOMWorkerScope> scope = new nsDOMWorkerScope(this);
-  NS_ENSURE_TRUE(scope, NS_ERROR_OUT_OF_MEMORY);
+  NS_ENSURE_TRUE(scope, PR_FALSE);
 
   nsISupports* scopeSupports = NS_ISUPPORTS_CAST(nsIWorkerScope*, scope);
 
   nsIXPConnect* xpc = nsContentUtils::XPConnect();
 
   nsCOMPtr<nsIXPConnectJSObjectHolder> globalWrapper;
   nsresult rv =
     xpc->InitClassesWithNewWrappedGlobal(aCx, scopeSupports,
--- a/extensions/reporter/resources/content/reporter/reporterOverlay.xul
+++ b/extensions/reporter/resources/content/reporter/reporterOverlay.xul
@@ -40,33 +40,32 @@
 
 <!DOCTYPE overlay SYSTEM "chrome://reporter/locale/reporterOverlay.dtd">
 
 <overlay id="reporterMenuOverlay"
          xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <script type="application/x-javascript" src="chrome://reporter/content/reporterOverlay.js"/>
 
-  <!-- Firefox -->
+  <!-- Firefox and SeaMonkey -->
   <broadcasterset id="mainBroadcasterSet">
     <broadcaster id="reporterItemsBroadcaster" disabled="true"/>
   </broadcasterset>
+
+  <!-- Firefox -->
   <menupopup id="menu_HelpPopup">
     <menuitem id="menu_HelpPopup_reportertoolmenu" 
               label="&reporterMenu2.title;" 
               accesskey="&reporterMenu.accesskey;"
               insertafter="releaseNotes"
               observes="reporterItemsBroadcaster"
               oncommand="loadReporterWizard()"/>
   </menupopup>
 
   <!-- SeaMonkey -->
-  <broadcasterset id="navBroadcasters">
-    <broadcaster id="reporterItemsBroadcaster" disabled="true"/>
-  </broadcasterset>
   <menupopup id="helpPopup">
     <menuseparator insertbefore="menu_HelpAboutSeparator"/>
     <menuitem id="helpPopup_reportertoolmenu"
               label="&reporterMenu2.title;"
               accesskey="&reporterMenu.accesskey;"
               insertbefore="menu_HelpAboutSeparator"
               oncommand="loadReporterWizard()"
               observes="reporterItemsBroadcaster"/>
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2791,18 +2791,16 @@ js_TraceStackFrame(JSTracer *trc, JSStac
         JS_CALL_OBJECT_TRACER(trc, fp->varobj, "variables");
     if (fp->script) {
         js_TraceScript(trc, fp->script);
         if (fp->regs) {
             /*
              * Don't mark what has not been pushed yet, or what has been
              * popped already.
              */
-            JS_ASSERT((size_t) (fp->regs->sp - fp->slots) <=
-                      fp->script->nslots);
             nslots = (uintN) (fp->regs->sp - fp->slots);
             TRACE_JSVALS(trc, nslots, fp->slots, "slot");
         }
     } else {
         JS_ASSERT(!fp->slots);
         JS_ASSERT(!fp->regs);
     }
 
@@ -3672,17 +3670,17 @@ out:
      */
     if (rt->gcLevel > 1 || rt->gcPoke) {
         rt->gcLevel = 1;
         rt->gcPoke = JS_FALSE;
         JS_UNLOCK_GC(rt);
         goto restart;
     }
 
-    if (rt->shapeGen & SHAPE_OVERFLOW_BIT) {
+    if (rt->shapeGen >= SHAPE_OVERFLOW_BIT - 1) {
         /*
          * FIXME bug 440834: The shape id space has overflowed. Currently we
          * cope badly with this. Every call to js_GenerateShape does GC, and
          * we never re-enable the property cache.
          */
         js_DisablePropertyCache(cx);
 #ifdef JS_THREADSAFE
         iter = NULL;
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -80,27 +80,32 @@
 #endif
 
 #include "jsautooplen.h"
 
 /* jsinvoke_cpp___ indicates inclusion from jsinvoke.cpp. */
 #if !JS_LONE_INTERPRET ^ defined jsinvoke_cpp___
 
 uint32
-js_GenerateShape(JSContext *cx, JSBool gcLocked)
+js_GenerateShape(JSContext *cx, JSBool gcLocked, JSScopeProperty *sprop)
 {
     JSRuntime *rt;
     uint32 shape;
+    JSTempValueRooter tvr;
 
     rt = cx->runtime;
     shape = JS_ATOMIC_INCREMENT(&rt->shapeGen);
     JS_ASSERT(shape != 0);
     if (shape & SHAPE_OVERFLOW_BIT) {
         rt->gcPoke = JS_TRUE;
+        if (sprop)
+            JS_PUSH_TEMP_ROOT_SPROP(cx, sprop, &tvr);
         js_GC(cx, gcLocked ? GC_LOCK_HELD : GC_NORMAL);
+        if (sprop)
+            JS_POP_TEMP_ROOT(cx, &tvr);
         shape = JS_ATOMIC_INCREMENT(&rt->shapeGen);
         JS_ASSERT(shape != 0);
         JS_ASSERT_IF(shape & SHAPE_OVERFLOW_BIT,
                      JS_PROPERTY_CACHE(cx).disabled);
     }
     return shape;
 }
 
--- a/js/src/jsinterp.h
+++ b/js/src/jsinterp.h
@@ -193,18 +193,22 @@ typedef struct JSInlineFrame {
 
 #define PCVCAP_MAKE(t,s,p)      (((t) << PCVCAP_TAGBITS) |                    \
                                  ((s) << PCVCAP_PROTOBITS) |                  \
                                  (p))
 #define PCVCAP_SHAPE(t)         ((t) >> PCVCAP_TAGBITS)
 
 #define SHAPE_OVERFLOW_BIT      JS_BIT(32 - PCVCAP_TAGBITS)
 
+/*
+ * When sprop is not null and the shape generation triggers the GC due to a
+ * shape overflow, the functions roots sprop.
+ */
 extern uint32
-js_GenerateShape(JSContext *cx, JSBool gcLocked);
+js_GenerateShape(JSContext *cx, JSBool gcLocked, JSScopeProperty *sprop);
 
 struct JSPropCacheEntry {
     jsbytecode          *kpc;           /* pc if vcap tag is <= 1, else atom */
     jsuword             kshape;         /* key shape if pc, else obj for atom */
     jsuword             vcap;           /* value capability, see above */
     jsuword             vword;          /* value word, see PCVAL_* below */
 };
 
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -4982,30 +4982,30 @@ js_DecompileValueGenerator(JSContext *cx
             pc = pcstack[pcdepth];
         } else {
             /*
              * We search from fp->sp to base to find the most recently
              * calculated value matching v under assumption that it is
              * it that caused exception, see bug 328664.
              */
             stackBase = StackBase(fp);
-            JS_ASSERT((size_t) (regs->sp - stackBase) <= StackDepth(script));
             sp = regs->sp;
             do {
                 if (sp == stackBase) {
                     pcdepth = -1;
                     goto release_pcstack;
                 }
             } while (*--sp != v);
 
             if (sp >= stackBase + pcdepth) {
                 /*
-                 * This happens when the value comes from a temporary slot
-                 * that the interpreter uses for GC roots. Assume that it is
-                 * fp->pc that caused the exception.
+                 * The value comes from a temporary slot that the interpreter
+                 * uses for GC roots or when JSOP_APPLY extended the stack to
+                 * fit the argument array elements. Assume that it is the
+                 * current PC that caused the exception.
                  */
                 pc = fp->imacpc ? fp->imacpc : regs->pc;
             } else {
                 pc = pcstack[sp - stackBase];
             }
         }
 
       release_pcstack:
--- a/js/src/jsscope.cpp
+++ b/js/src/jsscope.cpp
@@ -804,16 +804,17 @@ GetPropertyTreeChild(JSContext *cx, JSSc
                      JSScopeProperty *child)
 {
     JSRuntime *rt;
     JSDHashTable *table;
     JSPropertyTreeEntry *entry;
     JSScopeProperty *sprop;
     PropTreeKidsChunk *chunk;
     uintN i, n;
+    uint32 shape;
 
     rt = cx->runtime;
     if (!parent) {
         JS_LOCK_GC(rt);
 
         table = &rt->propertyTreeHash;
         entry = (JSPropertyTreeEntry *)
                 JS_DHashTableOperate(table, child, JS_DHASH_ADD);
@@ -890,29 +891,35 @@ GetPropertyTreeChild(JSContext *cx, JSSc
             }
         }
 
     not_found:
         JS_LOCK_GC(rt);
     }
 
 locked_not_found:
+    /*
+     * Call js_GenerateShape before the allocation to prevent collecting the
+     * new property when the shape generation triggers the GC.
+     */
+    shape = js_GenerateShape(cx, JS_TRUE, NULL);
+
     sprop = NewScopeProperty(rt);
     if (!sprop)
         goto out_of_memory;
 
     sprop->id = child->id;
     sprop->getter = child->getter;
     sprop->setter = child->setter;
     sprop->slot = child->slot;
     sprop->attrs = child->attrs;
     sprop->flags = child->flags;
     sprop->shortid = child->shortid;
     sprop->parent = sprop->kids = NULL;
-    sprop->shape = js_GenerateShape(cx, JS_TRUE);
+    sprop->shape = shape;
 
     if (!parent) {
         entry->child = sprop;
     } else {
         if (!InsertPropertyTreeChild(rt, parent, sprop, NULL))
             goto out_of_memory;
     }
 
--- a/js/src/jsscope.h
+++ b/js/src/jsscope.h
@@ -216,25 +216,25 @@ JS_STATIC_ASSERT(offsetof(JSScope, title
 #endif
 
 #define JS_IS_SCOPE_LOCKED(cx, scope)   JS_IS_TITLE_LOCKED(cx, &(scope)->title)
 
 #define OBJ_SCOPE(obj)                  ((JSScope *)(obj)->map)
 #define OBJ_SHAPE(obj)                  (OBJ_SCOPE(obj)->shape)
 
 #define SCOPE_MAKE_UNIQUE_SHAPE(cx,scope)                                     \
-    ((scope)->shape = js_GenerateShape((cx), JS_FALSE))
+    ((scope)->shape = js_GenerateShape((cx), JS_FALSE, NULL))
 
 #define SCOPE_EXTEND_SHAPE(cx,scope,sprop)                                    \
     JS_BEGIN_MACRO                                                            \
         if (!(scope)->lastProp ||                                             \
             (scope)->shape == (scope)->lastProp->shape) {                     \
             (scope)->shape = (sprop)->shape;                                  \
         } else {                                                              \
-            (scope)->shape = js_GenerateShape((cx), JS_FALSE);                \
+            (scope)->shape = js_GenerateShape((cx), JS_FALSE, sprop);         \
         }                                                                     \
     JS_END_MACRO
 
 /* By definition, hashShift = JS_DHASH_BITS - log2(capacity). */
 #define SCOPE_CAPACITY(scope)           JS_BIT(JS_DHASH_BITS-(scope)->hashShift)
 
 /* Scope flags and some macros to hide them from other files than jsscope.c. */
 #define SCOPE_MIDDLE_DELETE             0x0001
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -874,17 +874,16 @@ js_NativeStackSlots(JSContext *cx, unsig
 {
     JSStackFrame* fp = cx->fp;
     unsigned slots = 0;
 #if defined _DEBUG
     unsigned int origCallDepth = callDepth;
 #endif
     for (;;) {
         unsigned operands = fp->regs->sp - StackBase(fp);
-        JS_ASSERT(operands <= unsigned(fp->script->nslots - fp->script->nfixed));
         slots += operands;
         if (fp->callee)
             slots += fp->script->nfixed;
         if (callDepth-- == 0) {
             if (fp->callee)
                 slots += 2/*callee,this*/ + fp->fun->nargs;
 #if defined _DEBUG
             unsigned int m = 0;
@@ -4013,17 +4012,16 @@ TraceRecorder::varval(unsigned n) const
     JS_ASSERT(n < cx->fp->script->nslots);
     return cx->fp->slots[n];
 }
 
 jsval&
 TraceRecorder::stackval(int n) const
 {
     jsval* sp = cx->fp->regs->sp;
-    JS_ASSERT(size_t((sp + n) - StackBase(cx->fp)) < StackDepth(cx->fp->script));
     return sp[n];
 }
 
 LIns*
 TraceRecorder::scopeChain() const
 {
     return lir->insLoad(LIR_ldp,
                         lir->insLoad(LIR_ldp, cx_ins, offsetof(JSContext, fp)),
deleted file mode 100644
--- a/js/src/xpconnect/loader/JSON.jsm
+++ /dev/null
@@ -1,178 +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 Mozilla code.
- *
- * The Initial Developer of the Original Code is
- * Simon Bünzli <zeniko@gmail.com>
- * Portions created by the Initial Developer are Copyright (C) 2006-2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * 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 ***** */
-
-/**
- * Utilities for JavaScript code to handle JSON content.
- * See http://www.json.org/ for comprehensive information about JSON.
- *
- * Import this module through
- *
- * Components.utils.import("resource://gre/modules/JSON.jsm");
- *
- * Usage:
- *
- * var newJSONString = JSONModule.toString( GIVEN_JAVASCRIPT_OBJECT );
- * var newJavaScriptObject = JSONModule.fromString( GIVEN_JSON_STRING );
- *
- * Note: For your own safety, Objects/Arrays returned by
- *       JSONModule.fromString aren't instanceof Object/Array.
- */
-
-var EXPORTED_SYMBOLS = ["JSONModule"];
-
-// The following code is a loose adaption of Douglas Crockford's code
-// from http://www.json.org/json.js (public domain'd)
-
-// Notable differences:
-// * Unserializable values such as |undefined| or functions aren't
-//   silently dropped but always lead to a TypeError.
-// * An optional key blacklist has been added to JSON.toString
-
-var JSONModule = {
-  /**
-   * Converts a JavaScript object into a JSON string.
-   *
-   * @param aJSObject is the object to be converted
-   * @param aKeysToDrop is an optional array of keys which will be
-   *                    ignored in all objects during the serialization
-   * @return the object's JSON representation
-   *
-   * Note: aJSObject MUST not contain cyclic references.
-   */
-  toString: function JSON_toString(aJSObject, aKeysToDrop) {
-    // we use a single string builder for efficiency reasons
-    var pieces = [];
-    
-    // this recursive function walks through all objects and appends their
-    // JSON representation (in one or several pieces) to the string builder
-    function append_piece(aObj) {
-      if (typeof aObj == "string") {
-        aObj = aObj.replace(/[\\"\x00-\x1F\u0080-\uFFFF]/g, function($0) {
-          // use the special escape notation if one exists, otherwise
-          // produce a general unicode escape sequence
-          switch ($0) {
-          case "\b": return "\\b";
-          case "\t": return "\\t";
-          case "\n": return "\\n";
-          case "\f": return "\\f";
-          case "\r": return "\\r";
-          case '"':  return '\\"';
-          case "\\": return "\\\\";
-          }
-          return "\\u" + ("0000" + $0.charCodeAt(0).toString(16)).slice(-4);
-        });
-        pieces.push('"' + aObj + '"')
-      }
-      else if (typeof aObj == "boolean") {
-        pieces.push(aObj ? "true" : "false");
-      }
-      else if (typeof aObj == "number" && isFinite(aObj)) {
-        // there is no representation for infinite numbers or for NaN!
-        pieces.push(aObj.toString());
-      }
-      else if (aObj === null) {
-        pieces.push("null");
-      }
-      // if it looks like an array, treat it as such - this is required
-      // for all arrays from either outside this module or a sandbox
-      else if (aObj instanceof Array ||
-               typeof aObj == "object" && "length" in aObj &&
-               (aObj.length === 0 || aObj[aObj.length - 1] !== undefined)) {
-        pieces.push("[");
-        for (var i = 0; i < aObj.length; i++) {
-          arguments.callee(aObj[i]);
-          pieces.push(",");
-        }
-        if (aObj.length > 0)
-          pieces.pop(); // drop the trailing colon
-        pieces.push("]");
-      }
-      else if (typeof aObj == "object") {
-        pieces.push("{");
-        for (var key in aObj) {
-          // allow callers to pass objects containing private data which
-          // they don't want the JSON string to contain (so they don't
-          // have to manually pre-process the object)
-          if (aKeysToDrop && aKeysToDrop.indexOf(key) != -1)
-            continue;
-          
-          arguments.callee(key.toString());
-          pieces.push(":");
-          arguments.callee(aObj[key]);
-          pieces.push(",");
-        }
-        if (pieces[pieces.length - 1] == ",")
-          pieces.pop(); // drop the trailing colon
-        pieces.push("}");
-      }
-      else {
-        throw new TypeError("No JSON representation for this object!");
-      }
-    }
-    append_piece(aJSObject);
-    
-    return pieces.join("");
-  },
-
-  /**
-   * Converts a JSON string into a JavaScript object.
-   *
-   * @param aJSONString is the string to be converted
-   * @return a JavaScript object for the given JSON representation
-   */
-  fromString: function JSON_fromString(aJSONString) {
-    if (!this.isMostlyHarmless(aJSONString))
-      throw new SyntaxError("No valid JSON string!");
-    
-    var s = new Components.utils.Sandbox("about:blank");
-    return Components.utils.evalInSandbox("(" + aJSONString + ")", s);
-  },
-
-  /**
-   * Checks whether the given string contains potentially harmful
-   * content which might be executed during its evaluation
-   * (no parser, thus not 100% safe! Best to use a Sandbox for evaluation)
-   *
-   * @param aString is the string to be tested
-   * @return a boolean
-   */
-  isMostlyHarmless: function JSON_isMostlyHarmless(aString) {
-    const maybeHarmful = /[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/;
-    const jsonStrings = /"(\\.|[^"\\\n\r])*"/g;
-    
-    return !maybeHarmful.test(aString.replace(jsonStrings, ""));
-  }
-};
--- a/js/src/xpconnect/loader/Makefile.in
+++ b/js/src/xpconnect/loader/Makefile.in
@@ -51,13 +51,13 @@ REQUIRES	= xpcom \
 		  xpconnect \
 		  js \
 		  caps \
 		  necko \
 		  $(NULL)
 
 CPPSRCS		= mozJSComponentLoader.cpp mozJSSubScriptLoader.cpp
 
-EXTRA_JS_MODULES = XPCOMUtils.jsm JSON.jsm ISO8601DateUtils.jsm
+EXTRA_JS_MODULES = XPCOMUtils.jsm ISO8601DateUtils.jsm
 
 include $(topsrcdir)/config/rules.mk
 
 DEFINES		+= -DJSFILE -DJS_THREADSAFE
deleted file mode 100644
--- a/js/src/xpconnect/tests/unit/test_json.js
+++ /dev/null
@@ -1,131 +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 mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Simon Bünzli <zeniko@gmail.com>
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * 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 ***** */
-
-function run_test() {
-  // converts an object to a JSON string and tests its integrity
-  function toJSONString(a) {
-    var res = JSONModule.toString(a);
-    if (!JSONModule.isMostlyHarmless(res))
-      throw new SyntaxError("Invalid JSON string: " + res);
-    return res;
-  }
-  
-  // ensures that an object can't be converted to a JSON string
-  function isInvalidType(a) {
-    try {
-      JSONModule.toString(a);
-      return false;
-    } catch (ex) {
-      return ex.name == "TypeError";
-    }
-  }
-  // ensures that a string can't be converted back to a JavaScript object
-  function isInvalidSyntax(a) {
-    try {
-      JSONModule.fromString(a);
-      return false;
-    } catch (ex) {
-      return ex.name == "SyntaxError";
-    }
-  }
-  
-  Components.utils.import("resource://gre/modules/JSON.jsm");
-  do_check_eq(typeof(JSONModule), "object");
-  
-  // some of the tests are adapted from /testing/mochitest/tests/test_Base.js
-  do_check_eq(toJSONString(true), "true");
-  do_check_eq(toJSONString(false), "false");
-  
-  do_check_eq(toJSONString(1), "1");
-  do_check_eq(toJSONString(1.23), "1.23");
-  do_check_eq(toJSONString(1.23e-45), "1.23e-45");
-  
-  do_check_true(isInvalidType(Infinity));
-  do_check_true(isInvalidType(NaN));
-  
-  //XXXzeniko: using € instead of \u20ac fails because of encoding issues
-  do_check_eq(toJSONString("Foo-Bar \b\t\n\f\r\"\\ \x01\u20ac"),
-              '"Foo-Bar \\b\\t\\n\\f\\r\\"\\\\ \\u0001\\u20ac"');
-  
-  do_check_eq(toJSONString(null), "null");
-  do_check_true(isInvalidType(undefined));
-  
-  do_check_eq(toJSONString([1, "2", 3.3]), '[1,"2",3.3]');
-  // duck-typed Array (since we'll never really get something instanceof Array)
-  do_check_eq(toJSONString({ 0: 0, 1: "1", 2: -2.2, length: 3 }), '[0,"1",-2.2]');
-  
-  var obj = { a: 1, b: "2", c: [-3e+30] };
-  do_check_eq(toJSONString(obj), '{"a":1,"b":"2","c":[-3e+30]}');
-  do_check_eq(JSONModule.toString(obj, ["b", "c"] /* keys to drop */), '{"a":1}');
-  
-  do_check_true(isInvalidType(function() { }));
-  
-  // make sure that toJSONString actually works...
-  do_check_eq(toJSONString(obj), JSONModule.toString(obj));
-  
-  do_check_eq(JSONModule.fromString("true"), true);
-  do_check_eq(JSONModule.fromString("false"), false);
-  do_check_eq(JSONModule.fromString("1"), 1);
-  do_check_eq(JSONModule.fromString('"2.2"'), "2.2");
-  do_check_eq(JSONModule.fromString("1.23e-45"), 1.23e-45);
-  do_check_true(isInvalidSyntax("NaN"));
-  
-  do_check_eq(JSONModule.fromString('"Foo-Bar \\b\\t\\n\\f\\r\\"\\\\ \\u0001\\u20ac"'),
-                              "Foo-Bar \b\t\n\f\r\"\\ \x01\u20ac");
-  do_check_true(isInvalidSyntax('"multi\nline"'));
-  do_check_eq(JSONModule.fromString("null"), null);
-  do_check_true(isInvalidSyntax("."));
-  
-  var res = JSONModule.fromString('[1,"2",3.3]');
-  do_check_eq(res.length, 3);
-  do_check_eq(res[2], 3.3);
-  // res is an instance of the sandbox's array
-  do_check_false(res instanceof Array);
-  
-  res = JSONModule.fromString(toJSONString(obj));
-  do_check_eq(res.a, obj.a);
-  do_check_eq(res.b, obj.b);
-  do_check_eq(res.c.length, obj.c.length);
-  do_check_eq(res.c[0], obj.c[0]);
-  
-  // those would throw on JSONModule.fromString if there's no object |a|
-  do_check_true(JSONModule.isMostlyHarmless("a"));
-  do_check_true(JSONModule.isMostlyHarmless("a[0]"));
-  do_check_true(JSONModule.isMostlyHarmless('a["alert(\\"P0wn3d!\\");"]'));
-  
-  do_check_false(JSONModule.isMostlyHarmless('(function() { alert("P0wn3d!"); })()'));
-  do_check_false(JSONModule.isMostlyHarmless('{ get a() { return "P0wn3d!"; } }'));
-}
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -2657,24 +2657,48 @@ nsLayoutUtils::GetClosestLayer(nsIFrame*
           layer->GetParent()->GetType() == nsGkAtoms::scrollFrame))
       break;
   }
   if (layer)
     return layer;
   return aFrame->PresContext()->PresShell()->FrameManager()->GetRootFrame();
 }
 
+/**
+ * Given an image being drawn into an appunit coordinate system, and
+ * a point in that coordinate system, map the point back into image
+ * pixel space.
+ * @param aSize the size of the image, in pixels
+ * @param aDest the rectangle that the image is being mapped into
+ * @param aPt a point in the same coordinate system as the rectangle
+ */
 static gfxPoint
 MapToFloatImagePixels(const nsIntSize& aSize,
                       const nsRect& aDest, const nsPoint& aPt)
 {
   return gfxPoint((gfxFloat(aPt.x - aDest.x)*aSize.width)/aDest.width,
                   (gfxFloat(aPt.y - aDest.y)*aSize.height)/aDest.height);
 }
 
+/**
+ * Given an image being drawn into an pixel-based coordinate system, and
+ * a point in image space, map the point into the pixel-based coordinate
+ * system.
+ * @param aSize the size of the image, in pixels
+ * @param aDest the rectangle that the image is being mapped into
+ * @param aPt a point in image space
+ */
+static gfxPoint
+MapToFloatUserPixels(const nsIntSize& aSize,
+                     const gfxRect& aDest, const gfxPoint& aPt)
+{
+  return gfxPoint(aPt.x*aDest.size.width/aSize.width + aDest.pos.x,
+                  aPt.y*aDest.size.height/aSize.height + aDest.pos.y);
+}
+
 /* static */ nsresult
 nsLayoutUtils::DrawImage(nsIRenderingContext* aRenderingContext,
                          imgIContainer*       aImage,
                          const nsRect&        aDest,
                          const nsRect&        aFill,
                          const nsPoint&       aAnchor,
                          const nsRect&        aDirty)
 {
@@ -2728,25 +2752,32 @@ nsLayoutUtils::DrawImage(nsIRenderingCon
   intSubimage.SizeTo(NSToIntCeil(subimageBottomRight.x) - intSubimage.x,
                      NSToIntCeil(subimageBottomRight.y) - intSubimage.y);
 
   // Compute the anchor point and compute final fill rect.
   // This code assumes that pixel-based devices have one pixel per
   // device unit!
   gfxPoint anchorPoint(aAnchor.x/appUnitsPerDevPixel,
                        aAnchor.y/appUnitsPerDevPixel);
+  gfxPoint imageSpaceAnchorPoint =
+    MapToFloatImagePixels(imageSize, aDest, aAnchor);
   gfxMatrix currentMatrix = ctx->CurrentMatrix();
+
   gfxRect finalFillRect = fill;
   if (didSnap) {
     NS_ASSERTION(!currentMatrix.HasNonAxisAlignedTransform(),
                  "How did we snap, then?");
-    anchorPoint.x = fill.pos.x + 
-        (anchorPoint.x - devPixelFill.pos.x)*fill.size.width/devPixelFill.size.width;
-    anchorPoint.y = fill.pos.y +
-        (anchorPoint.y - devPixelFill.pos.y)*fill.size.height/devPixelFill.size.height;
+    imageSpaceAnchorPoint.Round();
+    anchorPoint = imageSpaceAnchorPoint;
+    gfxRect devPixelDest(aDest.x/appUnitsPerDevPixel,
+                         aDest.y/appUnitsPerDevPixel,
+                         aDest.width/appUnitsPerDevPixel,
+                         aDest.height/appUnitsPerDevPixel);
+    anchorPoint = MapToFloatUserPixels(imageSize, devPixelDest, anchorPoint);
+    anchorPoint = currentMatrix.Transform(anchorPoint);
     anchorPoint.Round();
 
     // This form of Transform is safe to call since non-axis-aligned
     // transforms wouldn't be snapped.
     dirty = currentMatrix.Transform(dirty);
     dirty.RoundOut();
     finalFillRect = fill.Intersect(dirty);
     if (finalFillRect.IsEmpty())
@@ -2754,19 +2785,16 @@ nsLayoutUtils::DrawImage(nsIRenderingCon
 
     ctx->IdentityMatrix();
   }
   // If we're not snapping, then we ignore the dirty rect. It's hard
   // to correctly use it with arbitrary transforms --- it really *has*
   // to be aligned perfectly with pixel boundaries or the choice of
   // dirty rect will affect the values of rendered pixels.
 
-  gfxPoint imageSpaceAnchorPoint =
-    MapToFloatImagePixels(imageSize, aDest, aAnchor);
-  imageSpaceAnchorPoint.Round();
   gfxFloat scaleX = imageSize.width*appUnitsPerDevPixel/aDest.width;
   gfxFloat scaleY = imageSize.height*appUnitsPerDevPixel/aDest.height;
   if (didSnap) {
     // ctx now has the identity matrix, so we need to adjust our
     // scales to match
     scaleX /= currentMatrix.xx;
     scaleY /= currentMatrix.yy;
   }
--- a/layout/reftests/bugs/413292-1.html
+++ b/layout/reftests/bugs/413292-1.html
@@ -23,17 +23,17 @@ function cp()
 {
   document.getElementById("iframe").setAttribute("src", src);
   setTimeout(looop, pause);
 }
 
 function looop()
 {
   loopCount++;
-  if (loopCount < 20) {
+  if (loopCount < 10) {
     ap();
   } else {
     document.body.textContent = "Done";
     document.documentElement.className = '';
   }
 }
 </script>
 
--- a/layout/reftests/bugs/433640-1-ref.html
+++ b/layout/reftests/bugs/433640-1-ref.html
@@ -23,27 +23,27 @@
 <div class="cell"><p>31.1  x 32</p><div style="width:31px; background-position:-16px -16px;"  class="image"></div></div>
 <div class="cell"><p>31.5  x 32</p><div style="width:32px; background-position:-16px -16px;"  class="image"></div></div>
 <div class="cell"><p>31.8  x 32</p><div style="width:32px; background-position:-16px -16px;"  class="image"></div></div>
 </div>
 
 <div>
 <div class="cell"><p>32    x 32</p><div style="width:32px; background-position:-16px -16px;"  class="image"></div></div>
 <div class="cell"><p>32.1  x 32</p><div style="width:32px; background-position:-16px -16px;"  class="image"></div></div>
-<div class="cell"><p>32.5  x 32</p><div style="width:33px; background-position:-15px -16px;"  class="image"></div></div>
-<div class="cell"><p>32.8  x 32</p><div style="width:33px; background-position:-15px -16px;"  class="image"></div></div>
+<div class="cell"><p>32.5  x 32</p><div style="width:33px; background-position:-16px -16px;"  class="image"></div></div>
+<div class="cell"><p>32.8  x 32</p><div style="width:33px; background-position:-16px -16px;"  class="image"></div></div>
 </div>
 
 <div>
 <div class="cell"><p>32 x 31   </p><div style="height:31px; background-position:-16px -16px;" class="image"></div></div>
 <div class="cell"><p>32 x 31.1 </p><div style="height:31px; background-position:-16px -16px;" class="image"></div></div>
 <div class="cell"><p>32 x 31.5 </p><div style="height:32px; background-position:-16px -16px;" class="image"></div></div>
 <div class="cell"><p>32 x 31.8 </p><div style="height:32px; background-position:-16px -16px;" class="image"></div></div>
 </div>
 
 <div>
 <div class="cell"><p>32 x 32   </p><div style="height:32px; background-position:-16px -16px;" class="image"></div></div>
 <div class="cell"><p>32 x 32.1 </p><div style="height:32px; background-position:-16px -16px;" class="image"></div></div>
-<div class="cell"><p>32 x 32.5 </p><div style="height:33px; background-position:-16px -15px;" class="image"></div></div>
-<div class="cell"><p>32 x 32.8 </p><div style="height:33px; background-position:-16px -15px;" class="image"></div></div>
+<div class="cell"><p>32 x 32.5 </p><div style="height:33px; background-position:-16px -16px;" class="image"></div></div>
+<div class="cell"><p>32 x 32.8 </p><div style="height:33px; background-position:-16px -16px;" class="image"></div></div>
 </div>
 
 </body></html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/464811-1-ref.html
@@ -0,0 +1,7 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<div style="background:url(mozilla-banner.gif); width:600px; height:58px;"></div>
+<div style="margin-left: 100px; background:url(mozilla-banner.gif) -100px 0px; width:1px; height:58px;"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/464811-1.html
@@ -0,0 +1,7 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<div style="background:url(mozilla-banner.gif); width:600px; height:58px;"></div>
+<div style="margin-left: 100.4px; background:url(mozilla-banner.gif) -100.4px 0px; width:0.2px; height:58px;"></div>
+</body>
+</html>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -955,8 +955,9 @@ fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") ==
 == 458487-4b.html 458487-4-ref.html
 == 458487-4c.html 458487-4-ref.html
 == 458487-5a.html 458487-5-ref.html
 == 458487-5b.html 458487-5-ref.html
 == 461266-1.html 461266-1-ref.html
 fails == 461512-1.html 461512-1-ref.html # Bug 461512
 == 463204-1.html 463204-1-ref.html
 == 463217-1.xul 463217-1-ref.xul
+== 464811-1.html 464811-1-ref.html
--- a/modules/libjar/nsJAR.cpp
+++ b/modules/libjar/nsJAR.cpp
@@ -371,25 +371,18 @@ nsJAR::GetInputStreamWithSpec(const nsAC
 NS_IMETHODIMP
 nsJAR::GetCertificatePrincipal(const char* aFilename, nsIPrincipal** aPrincipal)
 {
   //-- Parameter check
   if (!aPrincipal)
     return NS_ERROR_NULL_POINTER;
   *aPrincipal = nsnull;
 
-  //-- Get the signature verifier service
-  nsresult rv;
-  nsCOMPtr<nsISignatureVerifier> verifier = 
-           do_GetService(SIGNATURE_VERIFIER_CONTRACTID, &rv);
-  if (NS_FAILED(rv)) // No signature verifier available
-    return NS_OK;
-
   //-- Parse the manifest
-  rv = ParseManifest(verifier);
+  nsresult rv = ParseManifest();
   if (NS_FAILED(rv)) return rv;
   if (mGlobalStatus == JAR_NO_MANIFEST)
     return NS_OK;
 
   PRInt16 requestedStatus;
   if (aFilename)
   {
     //-- Find the item
@@ -520,17 +513,17 @@ nsJAR::ReadLine(const char** src)
 #define JAR_MF 1
 #define JAR_SF 2
 #define JAR_MF_SEARCH_STRING "(M|/M)ETA-INF/(M|m)(ANIFEST|anifest).(MF|mf)$"
 #define JAR_SF_SEARCH_STRING "(M|/M)ETA-INF/*.(SF|sf)$"
 #define JAR_MF_HEADER (const char*)"Manifest-Version: 1.0"
 #define JAR_SF_HEADER (const char*)"Signature-Version: 1.0"
 
 nsresult
-nsJAR::ParseManifest(nsISignatureVerifier* verifier)
+nsJAR::ParseManifest()
 {
   //-- Verification Step 1
   if (mParsedManifest)
     return NS_OK;
   //-- (1)Manifest (MF) file
   nsCOMPtr<nsIUTF8StringEnumerator> files;
   nsresult rv = FindEntries(JAR_MF_SEARCH_STRING, getter_AddRefs(files));
   if (!files) rv = NS_ERROR_FAILURE;
@@ -607,16 +600,26 @@ nsJAR::ParseManifest(nsISignatureVerifie
   }
   if (NS_FAILED(rv))
   {
     mGlobalStatus = JAR_NO_MANIFEST;
     mParsedManifest = PR_TRUE;
     return NS_OK;
   }
 
+  //-- Get the signature verifier service
+  nsCOMPtr<nsISignatureVerifier> verifier = 
+           do_GetService(SIGNATURE_VERIFIER_CONTRACTID, &rv);
+  if (NS_FAILED(rv)) // No signature verifier available
+  {
+    mGlobalStatus = JAR_NO_MANIFEST;
+    mParsedManifest = PR_TRUE;
+    return NS_OK;
+  }
+
   //-- Verify that the signature file is a valid signature of the SF file
   PRInt32 verifyError;
   rv = verifier->VerifySignature(sigBuffer, sigLen, manifestBuffer, manifestLen, 
                                  &verifyError, getter_AddRefs(mPrincipal));
   if (NS_FAILED(rv)) return rv;
   if (mPrincipal && verifyError == 0)
     mGlobalStatus = JAR_VALID_MANIFEST;
   else if (verifyError == nsISignatureVerifier::VERIFY_ERROR_UNKNOWN_CA)
--- a/modules/libjar/nsJAR.h
+++ b/modules/libjar/nsJAR.h
@@ -149,17 +149,17 @@ class nsJAR : public nsIZipReader, publi
     nsZipReaderCache*        mCache;          // if cached, this points to the cache it's contained in
     PRLock*                  mLock;	
     PRInt64                  mMtime;
     PRInt32                  mTotalItemsInManifest;
     
     //-- Private functions
     PRFileDesc* OpenFile();
 
-    nsresult ParseManifest(nsISignatureVerifier* verifier);
+    nsresult ParseManifest();
     void     ReportError(const char* aFilename, PRInt16 errorCode);
     nsresult LoadEntry(const char* aFilename, char** aBuf, 
                        PRUint32* aBufLen = nsnull);
     PRInt32  ReadLine(const char** src); 
     nsresult ParseOneFile(const char* filebuf, PRInt16 aFileType);
     nsresult VerifyEntry(nsJARManifestItem* aEntry, const char* aEntryData, 
                          PRUint32 aLen);
 
--- a/toolkit/components/satchel/public/nsIFormHistory.idl
+++ b/toolkit/components/satchel/public/nsIFormHistory.idl
@@ -45,17 +45,17 @@ interface mozIStorageConnection;
  * to values the user has submitted.  So, several values may exist for a single
  * name.
  *
  * Note: this interface provides no means to access stored values.
  * Stored values are used by the FormFillController to generate
  * autocomplete matches.
  */
 
-[scriptable, uuid(d73f5924-3e39-4c67-8f4a-290b85448480)]
+[scriptable, uuid(5d7d84d1-9798-4016-bf61-a32acf09b29d)]
 interface nsIFormHistory2 : nsISupports
 {
   /**
    * Returns true if the form history has any entries.
    */
   readonly attribute boolean hasEntries;
   
   /**
@@ -84,16 +84,26 @@ interface nsIFormHistory2 : nsISupports
   boolean nameExists(in AString name);
 
   /**
    * Gets whether a name and value pair exists in the form history.
    */
   boolean entryExists(in AString name, in AString value);
 
   /**
+   * Removes entries that were created between the specified times.
+   *
+   * @param aBeginTime
+   *        The beginning of the timeframe, in microseconds
+   * @param aEndTime
+   *        The end of the timeframe, in microseconds
+   */
+  void removeEntriesByTimeframe(in long long aBeginTime, in long long aEndTime);
+
+  /**
    * Returns the underlying DB connection the form history module is using.
    */
   readonly attribute mozIStorageConnection DBConnection;
 };
 
 /**
  * nsIFormHistoryImporter is an interface for importing a Mork formhistory.dat
  * file into the new form history storage.
--- a/toolkit/components/satchel/src/nsFormHistory.cpp
+++ b/toolkit/components/satchel/src/nsFormHistory.cpp
@@ -211,16 +211,22 @@ nsFormHistory::RemoveAllEntries()
     rv = InitByteOrder(PR_TRUE);
   
   rv |= Flush();
   
   return rv;
 }
 
 NS_IMETHODIMP
+nsFormHistory::RemoveEntriesByTimeframe(PRInt64 aStartTime, PRInt64 aEndTime)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
 nsFormHistory::GetDBConnection()
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 ////////////////////////////////////////////////////////////////////////
 //// nsIObserver
 
--- a/toolkit/components/satchel/src/nsStorageFormHistory.cpp
+++ b/toolkit/components/satchel/src/nsStorageFormHistory.cpp
@@ -408,16 +408,37 @@ nsFormHistory::RemoveAllEntries()
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return dbDeleteAll->Execute();
 }
 
 
 NS_IMETHODIMP
+nsFormHistory::RemoveEntriesByTimeframe(PRInt64 aStartTime, PRInt64 aEndTime)
+{
+  nsCOMPtr<mozIStorageStatement> stmt;
+  nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
+    "DELETE FROM moz_formhistory "
+    "WHERE firstUsed >= ?1 "
+    "AND firstUsed <= ?2"), getter_AddRefs(stmt));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Bind the times and execute statement.
+  rv = stmt->BindInt64Parameter(0, aStartTime);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = stmt->BindInt64Parameter(1, aEndTime);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = stmt->Execute();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsFormHistory::GetDBConnection(mozIStorageConnection **aResult)
 {
   NS_ADDREF(*aResult = mDBConn);
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////
 //// nsIObserver
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..43aa5c835b7ad9eec68b182cf63f7a18eecb7ae4
GIT binary patch
literal 4096
zc%1E4F>BjE6u!HsNO7p?P>eB6;D)5cI3Ah|9lAu4g)w%V)>R;(gHf<d1eOK1oW|YK
ztv{k<?OHMhvS&182^q4Q?CI2@cU3JbmOPiX_i@L4?|a|fJAoeDySFvRw`tq!xt342
zkc2Qs+ms@N2zm@)6Gvh^6VFAOZzg2~%jAMB0{<R*pk!Ya@aa>h+p<qw?_-nyQAbYS
z_j<!-k|^m7Lp2Rrsh5m>nz)1R)@KuRz3teYR@ZXve3Qu8LIHp9t;3GZeXW7(4x33K
z{4QpyTFsy{NxJT|*fmU}Y&7VbMrB8B9MGz9kUzDs!Yh0lhG#~uG82+miAUE?F0nzw
z&!MKVZ_@fMn|rm|20gYqgP7<$uHE13+tb6Qxwg~m`*U&~YfdW9doxAu5Zu5w_zZ{e
z8df1qzB5Tc;BQAJrJ&q1ObG9sVyW$USQ#m!%wkm5xhz$sYDS658j}f(nJh<TmAhdK
z<Fy4QKgY7n+qYQy)v(19M$-G+%9E3`$+{**ZF*qSW40H-Y%3F+7TC1SxQ`_HUdGGf
zXjwJzsWBVxe+)km8v+6X{}Bi#Xo;;U_=4a8?%@uu;R-I{9KJG1KtSM6VhM6Mc(|lO
csxO9AQ$niBoCXh(g^=n}NHv&J5>gfa1Sb^;A^-pY
new file mode 100644
--- /dev/null
+++ b/toolkit/components/satchel/test/unit/test_history_api.js
@@ -0,0 +1,158 @@
+/* ***** 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 Satchel Test Code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Justin Dolske <dolske@mozilla.com> (Original Author)
+ *
+ * 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 ***** */
+
+var testnum = 0;
+var fh;
+
+function run_test()
+{
+  try {
+
+  // ===== test init =====
+  var testfile = do_get_file("toolkit/components/satchel/test/unit/formhistory_apitest.sqlite");
+  var profileDir = dirSvc.get("ProfD", Ci.nsIFile);
+
+  // Cleanup from any previous tests or failures.
+  var destFile = profileDir.clone();
+  destFile.append("formhistory.sqlite");
+  if (destFile.exists())
+    destFile.remove(false);
+
+  testfile.copyTo(profileDir, "formhistory.sqlite");
+
+  fh = Cc["@mozilla.org/satchel/form-history;1"].
+       getService(Ci.nsIFormHistory2);
+
+
+  // ===== 1 =====
+  // Check initial state is as expected
+  testnum++;
+  do_check_true(fh.hasEntries);
+  do_check_true(fh.nameExists("name-A"));
+  do_check_true(fh.nameExists("name-B"));
+  do_check_true(fh.nameExists("name-C"));
+  do_check_true(fh.nameExists("name-D"));
+  do_check_true(fh.entryExists("name-A", "value-A"));
+  do_check_true(fh.entryExists("name-B", "value-B1"));
+  do_check_true(fh.entryExists("name-B", "value-B2"));
+  do_check_true(fh.entryExists("name-C", "value-C"));
+  do_check_true(fh.entryExists("name-D", "value-D"));
+  // time-A/B/C/D checked below.
+
+  // ===== 2 =====
+  // Test looking for non-existant / bogus data.
+  testnum++;
+  do_check_false(fh.nameExists("blah"));
+  do_check_false(fh.nameExists(""));
+  do_check_false(fh.nameExists(null));
+  do_check_false(fh.entryExists("name-A", "blah"));
+  do_check_false(fh.entryExists("name-A", ""));
+  do_check_false(fh.entryExists("name-A", null));
+  do_check_false(fh.entryExists("blah", "value-A"));
+  do_check_false(fh.entryExists("", "value-A"));
+  do_check_false(fh.entryExists(null, "value-A"));
+
+  // ===== 3 =====
+  // Test removeEntriesForName with a single matching value
+  testnum++;
+  fh.removeEntriesForName("name-A");
+  do_check_false(fh.entryExists("name-A", "value-A"));
+  do_check_true(fh.entryExists("name-B", "value-B1"));
+  do_check_true(fh.entryExists("name-B", "value-B2"));
+  do_check_true(fh.entryExists("name-C", "value-C"));
+  do_check_true(fh.entryExists("name-D", "value-D"));
+
+  // ===== 4 =====
+  // Test removeEntriesForName with multiple matching values
+  testnum++;
+  fh.removeEntriesForName("name-B");
+  do_check_false(fh.entryExists("name-A", "value-A"));
+  do_check_false(fh.entryExists("name-B", "value-B1"));
+  do_check_false(fh.entryExists("name-B", "value-B2"));
+  do_check_true(fh.entryExists("name-C", "value-C"));
+  do_check_true(fh.entryExists("name-D", "value-D"));
+
+  // ===== 5 =====
+  // Test removing by time range (single entry, not surrounding entries)
+  testnum++;
+  do_check_true(fh.nameExists("time-A")); // firstUsed=1000, lastUsed=1000
+  do_check_true(fh.nameExists("time-B")); // firstUsed=1000, lastUsed=1099
+  do_check_true(fh.nameExists("time-C")); // firstUsed=1099, lastUsed=1099
+  do_check_true(fh.nameExists("time-D")); // firstUsed=2001, lastUsed=2001
+  fh.removeEntriesByTimeframe(1050, 2000);
+  do_check_true(fh.nameExists("time-A"));
+  do_check_true(fh.nameExists("time-B"));
+  do_check_false(fh.nameExists("time-C"));
+  do_check_true(fh.nameExists("time-D"));
+
+  // ===== 6 =====
+  // Test removing by time range (multiple entries)
+  testnum++;
+  fh.removeEntriesByTimeframe(1000, 2000);
+  do_check_false(fh.nameExists("time-A"));
+  do_check_false(fh.nameExists("time-B"));
+  do_check_false(fh.nameExists("time-C"));
+  do_check_true(fh.nameExists("time-D"));
+
+  // ===== 7 =====
+  // test removeAllEntries
+  testnum++;
+  fh.removeAllEntries();
+  do_check_false(fh.hasEntries);
+  do_check_false(fh.nameExists("name-C"));
+  do_check_false(fh.nameExists("name-D"));
+  do_check_false(fh.entryExists("name-C", "value-C"));
+  do_check_false(fh.entryExists("name-D", "value-D"));
+
+  // ===== 8 =====
+  // Add a single entry back
+  testnum++;
+  fh.addEntry("newname-A", "newvalue-A");
+  do_check_true(fh.hasEntries);
+  do_check_true(fh.entryExists("newname-A", "newvalue-A"));
+
+  // ===== 9 =====
+  // Remove the single entry
+  testnum++;
+  fh.removeEntry("newname-A", "newvalue-A");
+  do_check_false(fh.hasEntries);
+  do_check_false(fh.entryExists("newname-A", "newvalue-A"));
+
+  } catch (e) {
+    throw "FAILED in test #" + testnum + " -- " + e;
+  }
+}
--- a/toolkit/mozapps/update/content/updates.js
+++ b/toolkit/mozapps/update/content/updates.js
@@ -199,16 +199,18 @@ var gUpdates = {
     // Set the labels for the next / finish, extra1, and extra2 buttons
     this._setButton(bnf, nextFinishButtonString);
     this._setButton(be1, extra1ButtonString);
     this._setButton(be2, extra2ButtonString);
 
     bnf.hidden = !nextFinishButtonString;
     be1.hidden = !extra1ButtonString;
     be2.hidden = !extra2ButtonString;
+    // Hide the back button each time setButtons is called (see bug 464765)
+    this.wiz.getButton("back").hidden = true;
   },
 
   getAUSString: function(key, strings) {
     if (strings)
       return this.strings.getFormattedString(key, strings);
     return this.strings.getString(key);
   },
 
@@ -323,17 +325,16 @@ var gUpdates = {
     }
 
     // Cache the standard button labels in case we need to restore them
     this._cacheButtonStrings("next");
     this._cacheButtonStrings("finish");
     this._cacheButtonStrings("extra1");
     this._cacheButtonStrings("extra2");
 
-    this.wiz.getButton("back").hidden = true;
     this.wiz.getButton("cancel").hidden = true;
 
     // Advance to the Start page.
     var startPage = this.startPage;
     LOG("gUpdates", "onLoad - setting current page to startpage " + startPage.id);
     gUpdates.wiz.currentPage = startPage;
   },
 
@@ -735,32 +736,31 @@ var gUpdatesAvailablePage = {
     if (gUpdates.update.channel == "nightly")
       updateName = updateName + " " + gUpdates.update.buildID + " nightly";
     var updateNameElement = document.getElementById("updateName");
     updateNameElement.value = updateName;
     var updateTypeElement = document.getElementById("updateType");
     updateTypeElement.setAttribute("severity", severity);
 
     var moreInfoContent = document.getElementById("moreInfoContent");
-    var moreInfoURL = document.getElementById("moreInfoURL");
     var intro;
     if (severity == "major") {
       // for major updates, use the brandName and the version for the intro
       intro = gUpdates.getAUSString("intro_major_app_and_version",
                                     [gUpdates.brandName, gUpdates.update.version]);
       var remoteContent = document.getElementById("updateMoreInfoContent");
       // update_name and update_version need to be set before url
       // so that when attempting to download the url, we can show
       // the formatted "Download..." string
       remoteContent.update_name = gUpdates.brandName;
       remoteContent.update_version = gUpdates.update.version;
       remoteContent.url = gUpdates.update.detailsURL;
 
-      moreInfoURL.hidden = true;
       moreInfoContent.hidden = false;
+      document.getElementById("moreInfoURL").hidden = true;
       document.getElementById("updateName").hidden = true;
       document.getElementById("updateNameSep").hidden = true;
       document.getElementById("upgradeEvangelism").hidden = true;
       document.getElementById("upgradeEvangelismSep").hidden = true;
 
       // Clear the "never" pref for this version.  this is to handle the
       // scenario where the user clicked "never" for a major update and then at
       // a later point, did "Check for Updates..." and then canceled.  If we
@@ -773,19 +773,18 @@ var gUpdatesAvailablePage = {
       gPref.setBoolPref(neverPrefName, false);
     }
     else {
       // for minor updates, just use the brandName for the intro
       intro = gUpdates.getAUSString("intro_minor_app", [gUpdates.brandName]);
       // This element when hidden still receives focus events which will
       // cause assertions with debug builds so remove it if it isn't used.
       moreInfoContent.parentNode.removeChild(moreInfoContent);
-      var moreInfoURL = document.getElementById("updateMoreInfoURL");
-      moreInfoURL.setAttribute("url", gUpdates.update.detailsURL);
-      moreInfoURL.hidden = false;
+      var updateMoreInfoURL = document.getElementById("updateMoreInfoURL");
+      updateMoreInfoURL.setAttribute("url", gUpdates.update.detailsURL);
     }
     updateTypeElement.textContent = intro;
 
     var updateTitle = gUpdates.getAUSString("updatesfound_" + severity +
                                             ".title");
     gUpdates.wiz.currentPage.setAttribute("label", updateTitle);
     // this is necessary to make this change to the label of the current
     // wizard page show up
index 34cabf8553d93fadbec47e294f87842f60358384..78881764adf03d8a4ee23f9f4cc685f8289c75d3
GIT binary patch
literal 927
zc$@*B17Q4#P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00004b3#c}2nYxW
zd<bNS00009a7bBm000fw000fw0YWI7cmMzZ8FWQhbW?9;ba!ELWdL_~cP?peYja~^
zaAhuUa%Y?FJQ@H10~|?2K~y-6Ws}=a8*~)MKfm9vUCDqtBruxFWiE_exYQ69P=kX>
zSj8;MlEnufyge*SOiY}~Tr!`=9&mpFnaR-1XrgH1B9%=*Ad753QnGf_k&Zgn%hYzP
zlwNH6`}v^MspsvSlYH|z-*b*I#sF}2(&H3Tj2mtC3L!Rtp%;4&4SqlM-5KDNF{V^V
zam#4a-`DF7@pp(T6JrBHh+$)lvt^%)n(Yn%X0A<<&1SIKO6Y#B2Y~2<2siy+gb*QP
z%<;Zn_qXEer00I;{^y<d?gfeb8bTK|N=Zsewz9vyiyMnSlF6hf6f{yv9Mw+h>l&Dw
zzZN=pp#Le0F~(U|T1MnSh=T|EH_4dzVVq1RO*)<WUw!YMX0+B$0Lx~>QRBq-lb6Ty
zq|b-Gc!_V`eixleQPS2**$dt9m|#(0NBvIHnG~698k@ARGIXB6=qS57I<WWjB8_2v
zb(NLjkC?hVhCcCD(L~eN>&6&^5CUTi-jgRuUBAxLU0sCd=7>k5Y^<+SQ&~xUT^*5V
zl)I1C$OeD0$W4Mk@D73C9d2I!n$^)!8d_V)UARDOX^E7S?EB(#{&=>N*_jzCayjhj
z3=&QiN3bY`5R%xJU(wjuNMv@FFot%AgWK^q!L#RR`S>E`%`Geso?|EQ5RMlKl(L|t
zVq;;EtwIos$Jyd?;Y~cE+2um|{P<pfliF8~k<=O;i%|f_KLS#rl!Zca1GBb9GMQx0
z`5~S>dKB;SGHq@*^44vZUV8(b&tm}un12%}h5Z>9YoQR^l_EUy2~C4%dE(^(7N@6a
zbGs2fKRTQJYXguddSJC!0jNHFn7h-{G;gGs9~q&vsfor9&ai9@^J5;`YHJDSazt!f
zAQT=K6I0{&JK8&)<>mI`aZGl1Q|k9qX|=MF&y&dKF<K*m9SsdsR8?_fVL|5-iE43W
z!ZV<x94_dBb5lV7_B)C9PE%EGXV>oCNSh6%6r!Sna3H|Xb937IQvc~Amp=PYY`*h<
z<5M9l65f|^LT%etEv;6ai^URX?a9MCuNw0Z;7_P9SY-Fl${GLw002ovPDHLkV1ls_
Bv19-M
index d9aef96a2bdbbfd9bdbe28171a739ae875afb062..06962c43544f903b6099e5825f232cf264fea5d3
GIT binary patch
literal 1688
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
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5eec70354acda3283ab0c7922ac7bf3bea088fd0
GIT binary patch
literal 732
zc$@*;0wev2P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00004b3#c}2nYxW
zd<bNS00009a7bBm000fw000fw0YWI7cmMzZ8FWQhbW?9;ba!ELWdL_~cP?peYja~^
zaAhuUa%Y?FJQ@H10$E8!K~y-6m6BUaR8bVie`}vJ%{k+B#?eNOrX@XO2~r?M5nd9L
zUecEy!oVV=PtZ$`z4Q@$slI~dCGQbPl1N5&ClPaS)No44Iit?mJ*b1%hyJi&?f+iu
z$6~K7T5A9XhI<`R(x*LLE+T({C)aAOKOP);`3QKZwaySFpR}hN>T4ULY)krwdTxkF
zyVlyNI9o~Ncp(6<M@L8|UHpEFtCwp4h%L<X;o~GC64hF_)z>z5%fN8&+{LOZ&g|?A
z^NUful!sv`EGt0Og-g7hc!TS%kxF?eLs3}ZP;#P_vGLJpU3Ei|skL@8GcuW9h*DSG
zurnD$uljJ^1c}7j0l)mrIXusE0L-0>!idAvmq~V?P1B?xKeER!$d9mFX~4;nG7|0@
zZZd)8x3R4Nrs<=kxD?k-klb+b`z$QWJ{(|K7Pf7pwMInJ1=-m-WM}83{hh5H0Q{Kw
zhKQs?iQ3AMJ-&!g7%4gkFbxCQZkn6>$@{5yY;JC%MB(=zqq5>W#l@w2rUOtrNl$k#
zZTBD0-PO(4@1MDStCgjtKPc_P+kokrX$-@lrRC1yfX<FCo;`m`XU7XHD?q>w5R1jg
z%L|j68^W?}lqlly_~CER)O?e>t@mhdZX%eQ%fMhi>&bP(;V@cz`21U?!C-I?K>CMz
zbbW0j%gevgX8d=Y*kTOOD5db3KJvo_WMyU{A_RkZ3=H>DU)w0Ap^WJ2>WUKzh0}mg
zC`{R@(;TJM)fEh7L;=i{=e3PbjJ2n{lyhXqJ{ii0raZ3=K=yx(|J6SZJ>3O1ex)h^
O0000<MNUMnLSTaDN>r2p
index d9aef96a2bdbbfd9bdbe28171a739ae875afb062..82f29c94f391cba517bd3f13bd98f9d12601409a
GIT binary patch
literal 1582
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
index 6956ffef8143d0dac1d898f6d1173bb465cf9641..1700ed11f285d6bcdd4d18997438624d25ba3718
GIT binary patch
literal 823
zc$@(@1IYY|P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!*-1n}RCwB?Q(Z`tVHAEozy0Vo=Qhzz
zaa!U~?4poBL?HsbXi_0wNL~m@Aa&i1;H^P7-DyNOyRfvbUF>G%#S{`rVPa}aXUwK<
zZMxsj@3-@g1%-Ik2j_c#p7%NLbIyAXr)e7g=i@Hf*A@N#PnG$6A6p1!bEs-?@HS25
z3kS<%MQ(NVA(u#8RaKSC%d&oZYO3$tW<!>-lF7cf&-Y9(ijpQt;9ah?V|e%lL260C
ztAPR6U5_VTO@s=bM?8_hk6;iPhXW}Ju{xPVZ+|~@=`_?r0fNbd^=#HV6bJ;E0>gc`
zduMBY9#L7wPa-&VIy{)3hPt~8C7%b^+KR}+0=D<}aX`3*&fW8R7l`X*3Tz+U?sQdc
zEo34J1X>jZdZV$Fpd!s#7)DV9PkWl#j4Kuk44DjE%gYX?K%bYSh|%F_v$VIPa&HeN
z0%JQnh!W|TZmgrQ?u?9}ZfFR~*KOq9zr(4bL|6`)167oythucXMyC^SyRknv2YpQq
zZd$D{+3m2lw4i=+5**zuH#9&Y2j`;5gsBzuQ__mECLA3h;`8BTWd-)GE~Mgdd?OWR
zy2I4dgWSdjq7xH1TUvrdd5N8!tuZchAS<$**0NbNQKnDV*HMhcz*FoTJsDw84F)7;
zXHnDJ3qxZgBtd|vs%ge8DTo$}o3T&`GRL8Hd>q!!PRK+CIgu#`dJ3<3W(KygG5qrT
zA*(75L~)aGc~*@fO-tTTRRbT1T(dMa8B~&32!~5m=4ft)#9n}E;*gx227~!8g7Esu
z@$nmiGhDfxEo2QI!1D-r?BTdUL%BrV-Q6f29+qnOyCf|>Po-XNi6VP}I9cvbNwZMQ
zWQ}CkZ*kn{Tb>UGbUN*GM~AlPa)k#>rcs8K&zQ@c3(dq-o5<{B^-py=uhHegbS(CP
z)+b~vafQE|io2vk_2sat%X`_fT*@r|>HpsX3;=y}Lr6=eHM0N!002ovPDHLkV1kiH
Bb{zl!
index 6ada1616bb125b42529b68bf3bb66298cccfce9b..6e8e1761bf87e41def9bc2567680c2ab0f4c6c4a
GIT binary patch
literal 2152
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
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..68cfae5eeea4380998cda73b8dd2d07c1c5811d8
GIT binary patch
literal 844
zc$@)D1GD^zP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!?ny*JRCwBKQ%g@8Q56109s>f(V?Z#7
zX@jWkLJj%@`bg-en?8R*_f2d14{X%9wkD>UG_gsOx@uFy!v27Eqd^xa6+w^!!hiw;
z&V!yyXws10%$Ix5+;hHj?s;(d|1!+a&-){h$Q%=*(df^Wm6Z$~<z7XuyXy!>X4sYO
zl}hDMr`KDVpejnuZnxj2W2Jkq5U$zIbxG{0RBDswd4Idz<`h-c?d`>;R8_&XEQ5?O
zJ{H_3O|`AHNxfZNUS58&y1JTVp3U#p)}GoOt~aWt4NJ|YuU4yh2L=XUGV!qVTi|rq
z!Eu~dmKC4WYWc{?4WrR0Zf}47!MuCpM~U3&X$tAHGc=n`ghFGOn+-#juc2ug3<d*|
z$rR2qS%{+8xt}1o-GZMHguZ@@#(CZdr_%|u*@Sw%jzYcw@&ZLs!1d|i9r92_CRnW&
zimIPQL{A$W*RzZi3i)`y#X4Rr7BM(zhakAfs1FwxrA`iphkfvP+#T|Asf-py*=RK4
z%$5<5+^X5EHe}Cplu{ik)hn3ETVQk)qX9omJm2xyl$wYg9AGvaMp-P^m@OlaFN($F
z(2zImaJf*-|3*WS;1b-pyu8BX#2AW&A`T8>6uylJ127U{I+ac`+dfuLu_9(<3YC@Z
zER%uFW~0Ozp|z=G^a+9h|HuduiDT#udbBCArBaDC)-@w&9UsMGjYb_Jz0c?KQY9p4
zs!WP<hlI+8daaJh$y>-~&p~~H!$S&*Y*`=R=qO&L&dZL4LN^7$?YO$EQUv-=`9i@U
za=9Gx`8=kkry)tw$=ij6rS<joD4CZ2cA|waOb9-H^6cTAyZ4?`S2`HMgUEf9%OVt6
z7PmfbeOg*v{6cyO!a1S-?@aIn4`GJz=;f=|JMT9?NQqx3(#FQ-4*S==^K^AN_O#A0
zu|tQ2<5*5i1ScUdJu@@Kn(O=S?mo$BLYdGceXVyIdl$<Mn?zezz9O)?tG$YU1Q-B(
WFiTsbv=biy0000<MNUMnLSTYsMUfc*
index 6ada1616bb125b42529b68bf3bb66298cccfce9b..0e58cad829db5766571bd20b96eadfa988eab12a
GIT binary patch
literal 2189
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
P00000NkvXXu0mjfLvB7v
index 5d796cc4c57dd3da1669fd4e51ba8d954ed4c866..4a66446e6256df3d7a836c2633a824ec0f8253b9
GIT binary patch
literal 638
zc$@)#0)hRBP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!AW1|)RCwB?Q%g%*K@|SxzH-}MW2q>O
z(MXImLco$mCG-afT?qLTZt7#NOIO_%gjUp@;6Awa2M8`x5lXe%iW>SLB%!&l={e)Q
zx3`tjMGwrKbI+XbJKvm{5mHM0j|nE|pPwgz_e)E!{dW7Mk<GrD+Spk6TZ}DJDEuNg
zSy-q`&wJHBJuU0mEP{3$&g`s8>>M5<j%A8PSLpgmd1q&n35=Lcx9vJiv#d=|L;61K
z@o@!Udr+w$==WibjzZIQ3!3(V!kfI75D42Yb&ihkg+Px?6F07lF(P66ba8<Z%feUB
z!w@OS)@r#JrzHv;r<9=zy)eYPUJu+_E0<G)eU9-O=NN;7r5KkexK}LZXyDo0+?`I(
zRI3O&9fU*@k_xZY8oEPpwY8;Y83go^2&h^p1VZvdiu24$eD-N=GQ9=vCIc0iw=*z+
z!s;q&%_g27A7gTD4VvR9@Sm0_2qG|BesK|F%gf1sfqakqu)eNTq%WT$s0vYeo6n<5
z$Hz2Iy^hB4Fg!~1qvR)zhH4_)eNDs6#6;yp%BCXtNHGSts6kBd;p`0GQi>4m`$t4(
z(tJsnL;;0$26v+hH&pHE!NG3?*L!;iA_7)MKs_O#T85jF`<arNYGi(1{kQh_ak;yj
z5V*Iqk^TtYS4@Cz7uVa{YNT(RM#mcWfIN}BMj^!Ghd|lCmG!UpEvR7d9iSe{tDgc4
Y063Ecv)0^v!~g&Q07*qoM6N<$f~!j=5C8xG
index d6dffb29b4f853a6f34a709ae5fb116d5b63a6a7..e5a5bc54c2402dca2724a7000227dbafff9a1516
GIT binary patch
literal 699
zc$@*d0!00ZP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!T}ebiRCwB?Q$1)CVHkeCyGt&AYMa!O
zM1x|qQ6p%p)`~bexkx+dpo7xI4y7On8H%7t6cH>=MR0I%ans!`LsfLqK(s|mp_NFj
zqPffc`@U!HG!=31<-Yrp_wRY$=lf20o`?T2g<orpdgy50sm?fB>y(^GKIxyTO#aQs
z)?3;O!3?;;N_Bb^mU%;OyeTQ0(y+gNM(Xe}Kk@tX8UkOuR5lTbPUb4tX1Re9bdxu1
z9Cfu;DLFI(&$bX1JK(vlA4}{%1Q3v_48U{jsEEZ+l6y8Bflb8YMf?3czPx;fcxE$<
z)g}_f0Y9cKyoH+Shrap=JwwAt3=ZdlIw=&RCtZx>3vdbP!^$!=(l)xK;4l8oK8|sY
zluQ-7MD!U*QZBY<AGYyYr}VBP$GiS}MmzIIgSE$xAY_^5x8YePJk#QN;Ti@&yJs5E
z92W+$XwiOR>`eCvBn(Jh2t|R?+lQ@F6%5wuIQU`#h09lfWD3EJiLAc|z7Z;$YnsTN
zpFsA)L>S6nyabC-Utg`jrjya!Uzg8kaCCRMEX5K&eL;=-#!h2yXBu<cQ>f*mc$$qM
ze|9`9RwRJ~R1-2-q@xC(xzUDgm>r>XAJwFSb_bD*4IY>FWv&StP*`@&HeAbQh0%O?
zA0tb8m-6+Qo3MC9!f}YV>_43b4(&|e(KR1=>FzC<gq}Y)&Ul!Aa1XC;U#Af$my(U&
z^b1~s)t6Kie0jarH!N1C@s1WZ(g{`~+A1Miw34KOfG7OZ<Bv%QkyU|`^OM%UzHdQE
h4zXxZ?Z+Pi3;=ZS6<8#Gc}f5P002ovPDHLkV1kheJ{kZ3
old mode 100755
new mode 100644
index d8b270ae522b700e1b84e642df8d386e4628070f..49997c06dbad50fbc994bee7518ac52aeedb2f94
GIT binary patch
literal 1200
zc$@*S1W)^kP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU$Qb|NXRCwCNS50UXSrGpEFY}X$&P*I<
zVM7xC@dwRpF3GY#y0Gj*Fb5YFyy(GGKoIeei`Tt*SXdzk@uGN8Ry+w3F$fDQ-c}G~
z!DOA_vbvj0lF3XmGu_i|)ywPHndzSCuu2Mw*Zr!xs$SJs)!mBYIM_;3vBk9I0qE{U
zb#^vT>E-$JXRO7=5y!H=q+0`u^1G2tKG-`kF(Kq*V`Jvx;`eZz&*|1wbp1CynY_RE
z>eU-THY2^g8v|%VKa;^!y;_B$s!%m;6skHx`yv2n+Al^brP=j59NUH#iTp^r-xA+w
zXIODT*qDJo&z<{$mS6e$?`O}D(sdX+b_khOD4<ZQ;nQQs;L6h-9njNhac|DeVZpN2
z<wQRnxPJZerZPZj{La1Z?(Brt)de*khrP1m)oBJ5>2RRk%gbK**KIM-WXLd12q&=^
z5(5J;i$yrAtI#tU#P;k#7oFHCmxXTM2~wquH0r?BQPsgsmtgwhMIk6Yc_L0^WV6r{
z30S2P%(rhvnzs!PBdiY5_Ct5?7DHuVW_)}=q3D_Zs#H*W{Tg8Q5K9L(p+hu8JQ->Z
zD2DM3F|UZL{-c8TS*}K-ZFMAn5gG%ku7BlT@5<#+nVG?V1ga%!vy`Txn*bT<?-z!d
z`U&mTSFbQnIt!$;opds!6WzU=ZMmj~LkB?U9Rg!RQ4rt1AMt|+(aoo!bSh+=S!L(6
zGR3H+Y^rsJ=KwPSlIH>V+BAVRoP8ELfQ6~4tZz=)5E~|DNA4a2*_L3oq^ix#viJAt
zeWBaX?+qy(3o$#Fjv*b{l&$q^x$nq8;90{3U|G#Ec}|=@c@mk^r?G8lNCdU?^eO(i
za|i$4yN9|PRD)C7w!;Uo?#z=B_q09Z<LJ3?VS_kz{J3BqJ}<9a5&E{rvAx;Xah(F#
zz+{ATk{lgva_*&Fmo6cD>eSll`5Eb)OHvQ`@bS%n<+H~|J~?}K?PWvAUZs&+p#j8P
z<1tKo7L~3{Em^*O8(w#=^CFGv7>#yAwr_9%KG6z5QHp12WdAWZD0D0j%9##4dW6W4
zBQOI_J45rNgIYO3<GQ!;Z5ZwAV;D!d%n!2fyU>!U<gDcLc`<xSc8jWVx&uVHT#h@D
z=XJ%ApwfLX(ZThr5m!m4>H*Zsix=oTdK8D~q(M}A{yZ=P^7Wv$0wHH1!sE0+T;`L@
zzGmh&Ye$8L57+e@nQcoSfdPmNRCv<Kx_f!y@ngKXbt};Mo0~ULn40o^)(Oaf-f(&m
zfYst(VfNZJl%}V#b7TaG!-vJ*GJTTGO-^E-oTK%Bh8uw5#-#g{z-afgGEW$oZ-Ijr
zWHgpQ_vtpr`gng!o@z7)zyj`|CHvzAuq1srP2YryB3@^lBL24Sk*o269Gl!Aat82f
zHqC)bKJU;lauv&d_4=QwXWLa?*_ST{JVBTr(787Vc%5%3!B){b0R{jox<`Gy7il2?
O0000<MNUMnLSTX%HcZR_
index 3e6d43c9ac1f12558eeb14aaab7a653655eab907..954036c1f099c58165878f5ab9349f0f9b705d3e
GIT binary patch
literal 1230
zc$@*w1Tp)GP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU$a7jc#RCwCNS4(VERT%!xy)$=aI`7({
zV{FtQD5(Y&1qy=3VL=zf2N)%~FtRamr7nfI5sW4T5*HdbR^kJJMiYV?Fwux&L>7uE
zJ{GMeD3vLtbg1pjeH{P)+<Waj?sR69q<?dAUjLl$JOAt43MnNPQ#35HEINUZKe+tM
zxu!~g?c4K=J$-o#q})JLDKzb*mdqUMeR1ajZ~tkhG_^%K&PJLF2=SGk%JTkDvoo`|
z_16+uNSyNAem$8<OWT6b)lVLywF31Ay#0MzBHhhnPiHHwZKCN=+ZL#o3$O0lM%}Qo
z&WU3Pr!olVmJomqYoZ8erqm5Df~P<G6k0rqP*0A)b(qDAFsG-|n2+#1*T1xTS4RZ2
zNOZG*qu5PLVPxon$s|xJK~~C;W`%W>t}r6dQz;nftkMZ5Qm9N#LWDxT#UAL`0tkm6
zbcsaJwQ4P#s{~x0g;<hDeCcw?xmk5vmQ-O7A{wjF=^`E8XN!^C({UDPVPhGCm%ccG
z*`Iy{%rZjR9@X=F=JY8DvH&+82kDePKhEcHixuD6pK99z6GLy_C8804Zcw~9j>?5U
zfwSM&=oq?&H0zKoq?0njpseBP0JY<75zr#Bf<KN3fl7c5uajO&9X%HJryJTPAR>|b
z{c(QqA!L3%hsy7xC{`@wj1UY8%IK~Atk<><$-4G~P}2tlB>f4*R@{NE{*@e*$ZLZ4
zlu0$ibrBqg(z6%w)$2fo2ziHs&Y|oxO*NOQGO27_)i#0258vt4;;!lV5cr3vL#4YW
zxwk1DO>a((QkLg7?OCMGuxd=MuxzJ${iEC4Bf#K#Vm@dci#%*u6jgL<PAk=@;#ow1
zEW$*ba+z3Cu#t6iBE+;!>OF8WitMls)Pt*{WUH1fY(~$+k0WvS8g=v1ci*5m{5~c=
zKB!z`N*CO$0xx$$z&Cpk_zllKkNl43YV^|^3#vtLz6E1@Um<Y20o-zAXN4&6=9>l^
zz^kS2g`K$WktYJdZKs1ur~<AIoPD0#_GHVKGq-hnAh@k{@)l4ebHG)D)2T?TbW8fT
z%evi&x6B%!7sgFw*W4EfZaFOobg#Ibk{tZJ^_{u%MiuGR;A-p#QUExcU0G}aaKczl
z-Fa$r(tD~y0WL9A5Y~Zns$Koz43ewYW9`^<Qx{x1{dFL?$K9xRyVl@-D&b1I4xICR
z{N1-(#=zL&4+6n0mq5hBXiC7dfZYJjgf1ODj6dFZy(##}-rX2Iaxf6QnFT_1w|5C}
zd9AK+RX!hm?PW}joJIbr9mw1};6BHvzQov}_b@vA5o{p?!R=ZCj1?FIyb)H9NC3DW
zaOaO6!Ec`&S}@uJz}0tFD;G%BsJu1<Z&qa50G~g<i3`-@MeT|;`!{p~YVxZ6S8$dq
z9>%{r!vAs>LM1Yrh`;aqygq!5{sA)imG^1@_hv&KnEZJ}Qlan_XM+6oKSX*Y%G@(n
sU@5L5VO~S<Y7(dhuW`X*$v*-N0L<n!sx8+FZ2$lO07*qoM6N<$f`L;<c>n+a
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..07496d6b633fdbd069bb33cf84f54900d13fc5db
GIT binary patch
literal 654
zc$@)_0&)F`P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!FiAu~RCwB?Q{8S7K@|RGcG+2tg#v1e
zf!LzK#PANhfQgsBg(kj)_g={>@DTNqa!Y_9vGh(98n7%{e&)wBQ+6qO=_F@&=KOqf
z&Uel*V+{Uhar<G6CDQNrKXp1CN&oszH>lt0zSP$niPdVA05F?@b?WtcZ?x7Qj5eo-
zxh$?{Gx({LbK1xavWHpxoX+S<rVKOht1qh`t<6u67<-+`WKM+$>7;R7IEE|FP!^n#
z%HXJQgw<MlQFQ%^ob~}c-+Q)Rukq{m0wTDF<;@Ka(g)5KE#?RX>6R-95y12OCwm;Y
zWpEOPA*3{*8=NW#1Of^$8kk3OD7B%pfbV%v<FF(HA;jZ+E{})#oWrF$i6B=S(&-F=
z7-*%Sq{O%R{J}o}<M9}AOSMrplCm;e9vl^bvRj28S66uPH^AM+ww0Nk!kt`JWb--S
zpM&^jv%PUR9HQB5Vmh5VvHOd!7sP>rB%xMfczL-4Xfzs+s8^slAQB~t#Uje(GP>Qa
zoe#G!l}gTT#iM%8KA$~L049@3$`G=hFe|p5_P<yxs3Va(+uLK&)RxJ3azEjK(q>Bv
z5TS5s4F&^@Mk7?KRd;T;+b9$Ys8lKmH$mW!cL3UOt<~1VoMY^4SFKjNLot=9B)Ind
z1b};-kq}|C9ko>Fc7p9F+|C9OY)$r!@DyhWz<H}RBI5}W$l>OWLZ~4$Ner49&9r?G
o)J5aKEWmlI`TZT<;*S6W0O=PmfVrhg`~Uy|07*qoM6N<$f}@r!zW@LL
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..6d0cd01fe5acf12650925cc3466fb226c0ed0ef5
GIT binary patch
literal 664
zc$@*40%!e+P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!I!Q!9RCwB?Q_YSNK@k4BXBd8lnS;>;
zqb6(?LO39gz}=e%-@?856yChaBe)OX9^h`c5JFf^7);0-{#*q%aoL&fwyH<QC401o
zqN}UBzN-4FTNq>TKST1L5F(Z7boy~JnOxD_zGrJsCSSi#zfId(X+&|H0tn8450TRw
zt@V3amxCa{ZnuT&dVB)$U4&u~;)ZNO%2*2d?zD3HfdSk!6)9hbVOY-jc_7vZibV)V
zB%9j6Xdn!V*zfo5X19Aq)&~F;r4-hSB|I;SeH5XP&C!m*@7r6ldAQr}kuMbBI?mH0
z4tO}ObCS>Jp()aKyMrQtTs}wQBZ^{dHXA6~<TC_NKKP{>K;yCR`|yiCY~sfLtR93X
zR<mm=XSclx9svCObqzO@EH#zF<Z8{Li2~w)$Yi^sY?iAPp1*i@T!M5QI8vrMwZ_iU
zk;D(_^a=hXujTPQ;An>W%Qf;CjYjBnI#@0jBujL=U0hy{pbnXlEEe;B0Oz01pGYTT
z4Sc9xucO&)qTlahFc{!vqk(F*`nN0%x(B%UeDNsdV6|Rl43u@Y9B|zvHZu~wc?V~u
zVk$&qwODy60BuU6OzJ!yk1?Cg(4fc+IvfsBDwR;FRKQP15xHJ2EAImk$0m(jtJUn`
zL(Q#LE7cR>78@r8kO|GWUjKkH%3fPdGe_dg4C&0Tp$!THhdbsb_uK;Xdc8S6qBxGl
yp*_hX<5?s#KM4Em$jQx^-k09|?Clx;2rvMqQc*v!a)zz|0000<MNUMnLSTYmLNE0I
old mode 100755
new mode 100644
index d8b270ae522b700e1b84e642df8d386e4628070f..d9d317657d05b8d41d2ef9baf72c1bb0524960e2
GIT binary patch
literal 1307
zc$@(n1?2jPP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU$y-7qtRCwCVSKUq<M-)CYyK8%GY%rUk
zmP#}ME+9c_1*(Xu25zHXRJrUc^s0A#iAsHfUY7@`@(7in;s&^gN-&W^)%L;$1orx8
zy*vHR+4aV_wjmM;9c#S1GqdM>=Q}?$tBf&pmrc_hw>t-5kD7?^YqeTr8AT^2C*L)L
z&U0m=FM(OZZNEE?^XtOG;!jFN^y*dR`!Ec@#%oW|+vvYx{>9SL($Ayh_gt^i7{ImL
z?ULW{0ZWrb20u+&5uN<`mtQJPxR!QgG{m}#dc!<i_!JB(dR?hRrHPWVZM=o`VK=0U
zi;MH+<>m4_0Kkh;ml}SPw5{mP>o?zGZc9VKrQe_#?;crMn>5ySf{@NmYn02oWFkZD
zW}CeG9@%zGXb=Q+dU{IPY&KS+=*P#8SAG}<;H?W({HHCAL8w*gn_{s@xtvRx%S&>y
z8L};#f-u0Gp?tw5&zlkHwOSPdBN1aIAUw~bd_FH=&d<-E-Y5p3lq>~S!K2ptSuX2R
z-nGebCdKLq)MqnUDi$ZO*rTA+5!Ze4(Z|#UdqL2pD2m9*IOMu{$WU>lYyJ7PSrCEB
zR=Z82-;&{S*2&P{|J10_2oM$qloy1h#-&fE)fy;w$brQ*(A|XVcrKI4hyl%}&z8$P
z0OSr24=2Ympj1er7YP1%`ErrzSB@dS)g&J=fM`LGXn->km~5R#(-eWVdK2??6T6Xp
zt5hOW)6~?IfPyQ&g5O_^sRNe0pzw2D_c^}=RxxTp85Sx_g41H*hO@&-LI-2omLQg%
zDCb+w3T{YAzC0bz01HxhgoT!6J!1eI6ZdC4(CbsnZ&N4iQpT|nm^pG0U?x%JO_#+5
zZMZN9+K7RyWB?2i87!;WY(5zafb+M_5gtbHxAR2?0&MuCP%KcfkcT^*m|o751agGP
zXU-T<X|g0Wf(3C#L}8SsTf)F+*DwIz8sUMeXVsDhdm;OX(@QDQ9f<-HyUN7=X5g$?
z#d$1QkQ$W~IBwNyb!u^Oaa<Zg1pAnwKuE-jM2Jcxky!iI$4Ss7?i;$RGQewg+beaz
zQj`k4u7vhK_mB1N2iNs8GZKK*{vjLWFr_yE!?uJY6c1+rL1z*Q28DA;tyC&>c6KJu
zD=RBhC=}$rUa!-^!GYYD%Vm1-;9;7A!+?!E4`{{tt%R<@j?|>Nxw%vzD`dso_xJbH
zb+faxQlzjwr@c2fmVq|*e%Vi?%nfzE<TLho+S}U`!8<!Usde1f*48Bd-{qK>0$6_Z
zNJ%*)Q~G6VD@Dv#7TCKo2&SKv_qX-+btycfEai9S=jW$!d%>Y`e0*$%9mzP)EG{B!
zA^W|99gnX)Dlf4$Z*Om3v79@P@!a5ee~%5knrHt3fOR&Xj94*W`vv$Y$-BF|>0+jw
zd#~{vuNectz7_x<3E0}fmzjm5qoeeBb#+y;fcwVAMmo-G_$+x-2JEZ!Qyd3FiV+{T
z*!QE_=H}*2V$SN*V@4gzHNC%Y75%^dE->;rK-6M?VfT6;`dWz&(--yeJ#thfjIf{X
zp}V)p5G&<FBU=^pYQWX+f}|xtoCL^iws27SPyl@()GY%LMK=QQA=|$K3;-)I&P=9g
R!2SRL002ovPDHLkV1mwbcnbgk
index 3e6d43c9ac1f12558eeb14aaab7a653655eab907..79818c3ffc6b192511e2c0ea25770c5860cfd99b
GIT binary patch
literal 1353
zc$@)A1-AN$P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU$>q$gGRCwCNSIbT#M-)Bv=x(}g^DqN5
z8i)jDOjZyHfgn<(fn79<EV9ZUB+CCpS>yw<iIjhc1c4wSC0QZ?0+JctgWuThuH0LG
zVEn=(p-jy*?XJ3g&wZSGt6CUi@G*zPM;;&D0Nrn~S`8sgh~v|LzN=QNU(wVTJTD-A
zSC0B+YHIo?VFXV9J^41QRKKQlehxvaz#qzSeof8J{?JQzBlV)417R4_D*cb>E)+}P
z=;)}BOpf_VX(-ZOt{U9jTopc<o{sUv@zF_sY&;n_+Oaw+VFj71n^Nl4od3ZFRKp08
zKo1U&zA;hsGrLnL<S{y$gi8P+d1%TN+`PYlA0K8_C}gu38y$!8T(;cmxW2eTJQ26+
zQ0m9|xw-GV8K65!VeDTi#GClY2!bGnOzu4#<-&Dcl*?t5DJ_Zk7$znsY>?iD0?O57
zpoZf(s8lL&UQA$kc$nlXxV^o7Jun9Z(J~?%gb*8^=Rqoo(Rk8^)sS~X-VlPA4>6(<
z(Laa?FQ%r+NrMV;CaPB9`5uCVPuU@NtfOXrpel$cbcRVpFG(q<T{pn><t1{(tPQ2_
z4q3TEu86D43piTA5gON57bxa(OdxBZG!pqt5trwe@LZ3K)B5kf{tO<CfRuu~H#j*x
z{)|H@WrSRz0OT^f2<D|!wX{|vfl0-Tmn4%#K6^{rG{T6YLMhSGfJE?Y0ycF)Jh4o9
z|E+HXjAf+_|Cjs{KPv(zbzFMniLgb;!*`T@A)<UaQd@AAaVYFs6H&<-O-?9B5-&8g
zQg0rO00CS56#jLae|nyroJ28SMDebGQn3tg$bmoP6Axl!tRk5Zlh2={kT2k_R7C!+
z1m6pYyhHGPpXm;d(o!njy?)dH+XHMFiWSFoh~WzH7%7X#AgzCb`%EoTq81GUh2eyQ
zL?U60XVTeqP6daP8kOg`%&o=8tALbBEpc{!F)mb%jE14<2iI*##<4;RWaCfv+B-v5
z$aZDR*a%A!YhY+<_jm8!2GcKJK0-nxtYS^<*2;O%G$Qgy>wC)ZGXp779!WO9gWw2q
zR7l=9!Wt%siII(l9H0->>JO%^V_5~Q<;vjoPR3Q!Dr4%;jk$YSGr(?WHxg6l`QzYb
zKyZ8YFrb424Y_XMdwY90KR>s>S65dNkH@V{miB_3ogMqm`1m*$78V|Y(<RIRov_Ah
z(bMyEI^8sGdwUz1Oa?jXfDLfIW@ctOz^y(L^^ZU$;=P|Ot#!k0VGn}9dd}cH$M@FI
zFE1}6M*X1!oMeR*{Uh+{tF)L;&+GJjI@wB?_MCIr*Vfh^kd!Z;>jiG*s6bMw*<>n}
z(sWP}y^dr|0@aUjw6$VuYpa8Fo12?9C0)V!H*ATjdX_sQaBy&7Y6b``On2}`z8iB(
zOG{W;S!n|8?(Q~?Xs--$fBq1r#e${*6q?3PqZ+l{UTXXM`^`B9<^u=wVq;^YDR+2y
z*a43FE}-hQ*0l_q2K1`)#l^**b-up7-qrKAp;~ZEuVcCV;3m^Uwm0cb|L=l^@+Ssw
z3wCD;_$}5_;)k=dv!*fa5orbPCevq>>KNvJ`>DTBCn2x!KK6_cJx}=M#GpmGF1hCs
zQBBY9g1RA2oiI;1!UlNP50m;%ZcjcfCHZ87fTMxFjQ;QOp8x{@?eng{m?YOB00000
LNkvXXu0mjfAz^;o
--- a/widget/src/windows/nsWindow.cpp
+++ b/widget/src/windows/nsWindow.cpp
@@ -7877,17 +7877,17 @@ nsWindow :: DealWithPopups ( HWND inWnd,
         inMsg == WM_NCRBUTTONDOWN || 
         inMsg == WM_MOVING || 
         inMsg == WM_SIZING || 
         inMsg == WM_NCLBUTTONDOWN || 
         inMsg == WM_NCMBUTTONDOWN ||
         inMsg == WM_MOUSEACTIVATE ||
         inMsg == WM_ACTIVATEAPP ||
         inMsg == WM_MENUSELECT ||
-        // Non-toplevel windows normally don't get WM_GETMINMAXINFO.
+        // Non-toplevel windows normally don't get WM_GETMINMAXINFO.
         // Therefore if a non-toplevel window gets this message, we should ignore it.
         (inMsg == WM_GETMINMAXINFO && !::GetParent(inWnd))
 #endif
         )
     {
       // Rollup if the event is outside the popup.
       PRBool rollup = !nsWindow::EventIsInsideWindow(inMsg, (nsWindow*)gRollupWidget);
 
@@ -7939,29 +7939,32 @@ nsWindow :: DealWithPopups ( HWND inWnd,
             }
           }
         }
       }
       // if we've still determined that we should still rollup everything, do it.
       else
 #endif
       if ( rollup ) {
+        // gRollupConsumeRollupEvent may be modified by
+        // nsIRollupListener::Rollup.
+        PRBool consumeRollupEvent = gRollupConsumeRollupEvent;
         // only need to deal with the last rollup for left mouse down events.
         gRollupListener->Rollup(inMsg == WM_LBUTTONDOWN ? &mLastRollup : nsnull);
 
         // Tell hook to stop processing messages
         gProcessHook = PR_FALSE;
         gRollupMsgId = 0;
         gRollupMsgWnd = NULL;
 
         // return TRUE tells Windows that the event is consumed,
         // false allows the event to be dispatched
         //
         // So if we are NOT supposed to be consuming events, let it go through
-        if (gRollupConsumeRollupEvent && inMsg != WM_RBUTTONDOWN) {
+        if (consumeRollupEvent && inMsg != WM_RBUTTONDOWN) {
           *outResult = TRUE;
           return TRUE;
         }
       }
     } // if event that might trigger a popup to rollup
   } // if rollup listeners registered
 
   return FALSE;
--- a/xpfe/appshell/src/nsXULWindow.cpp
+++ b/xpfe/appshell/src/nsXULWindow.cpp
@@ -86,16 +86,17 @@
 #include "nsIURI.h"
 #include "nsIDOMDocumentView.h"
 #include "nsIDOMViewCSS.h"
 #include "nsIDOMCSSStyleDeclaration.h"
 #include "nsITimelineService.h"
 #include "nsAppShellCID.h"
 #include "nsReadableUtils.h"
 #include "nsStyleConsts.h"
+#include "nsPresContext.h"
 
 #include "nsWebShellWindow.h" // get rid of this one, too...
 
 #define SIZEMODE_NORMAL    NS_LITERAL_STRING("normal")
 #define SIZEMODE_MAXIMIZED NS_LITERAL_STRING("maximized")
 #define SIZEMODE_MINIMIZED NS_LITERAL_STRING("minimized")
 
 #define WINDOWTYPE_ATTRIBUTE NS_LITERAL_STRING("windowtype")
@@ -572,18 +573,24 @@ NS_IMETHODIMP nsXULWindow::GetPosition(P
 NS_IMETHODIMP nsXULWindow::SetSize(PRInt32 aCX, PRInt32 aCY, PRBool aRepaint)
 {
   /* any attempt to set the window's size or position overrides the window's
      zoom state. this is important when these two states are competing while
      the window is being opened. but it should probably just always be so. */
   mWindow->SetSizeMode(nsSizeMode_Normal);
 
   mIntrinsicallySized = PR_FALSE;
+  PRInt32 devX = NSAppUnitsToIntPixels(nsPresContext::CSSPixelsToAppUnits(aCX),
+                                       float(mWindow->GetDeviceContext()->
+                                             AppUnitsPerDevPixel()));
+  PRInt32 devY = NSAppUnitsToIntPixels(nsPresContext::CSSPixelsToAppUnits(aCY),
+                                       float(mWindow->GetDeviceContext()->
+                                             AppUnitsPerDevPixel()));
 
-  NS_ENSURE_SUCCESS(mWindow->Resize(aCX, aCY, aRepaint), NS_ERROR_FAILURE);
+  NS_ENSURE_SUCCESS(mWindow->Resize(devX, devY, aRepaint), NS_ERROR_FAILURE);
   PersistentAttributesDirty(PAD_SIZE);
   SavePersistentAttributes();
   return NS_OK;
 }
 
 NS_IMETHODIMP nsXULWindow::GetSize(PRInt32* aCX, PRInt32* aCY)
 {
   return GetPositionAndSize(nsnull, nsnull, aCX, aCY);