Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Thu, 26 Jan 2012 11:58:33 -0800
changeset 109213 ed3aa00fc18196061909191f490ecdb63e8fdec0
parent 109212 7808b040fbe6ca978ab7161b7fa2679fe5038efa (current diff)
parent 86682 7cdb5f5d38c6bfe4e0f3c819bee95a119665be38 (diff)
child 109214 f59064acba0aa5d4666aba63d367b3d471a78fa1
push id2248
push userakeybl@mozilla.com
push dateMon, 08 Oct 2012 19:23:44 +0000
treeherdermozilla-aurora@118a3b748323 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone12.0a1
Merge from mozilla-central.
browser/app/profile/firefox.js
browser/base/content/browser.js
browser/base/content/tabbrowser.xml
browser/base/jar.mn
browser/devtools/webconsole/HUDService.jsm
config/system-headers
configure.in
content/base/public/nsContentUtils.h
content/base/public/nsIFrameMessageManager.idl
content/base/src/nsCCUncollectableMarker.h
content/base/src/nsContentUtils.cpp
content/base/src/nsDocument.cpp
content/base/src/nsEventSource.cpp
content/base/src/nsEventSource.h
content/base/src/nsFrameMessageManager.cpp
content/base/src/nsFrameMessageManager.h
content/base/src/nsImageLoadingContent.cpp
content/base/src/nsImageLoadingContent.h
content/base/src/nsNodeIterator.cpp
content/base/src/nsNodeIterator.h
content/base/src/nsTraversal.cpp
content/base/src/nsTraversal.h
content/base/src/nsTreeWalker.cpp
content/base/src/nsTreeWalker.h
content/base/src/nsWebSocket.cpp
content/base/src/nsWebSocket.h
content/base/src/nsXMLHttpRequest.cpp
content/base/src/nsXMLHttpRequest.h
content/base/test/Makefile.in
content/canvas/src/WebGLContextGL.cpp
content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
content/events/src/nsDOMEventTargetHelper.h
content/events/src/nsEventListenerManager.cpp
content/events/src/nsEventListenerManager.h
content/html/content/public/nsHTMLMediaElement.h
content/html/content/src/nsGenericHTMLElement.cpp
content/html/content/src/nsGenericHTMLElement.h
content/html/content/src/nsHTMLImageElement.cpp
content/html/content/src/nsHTMLMediaElement.cpp
content/xslt/src/xpath/txRelationalExpr.cpp
dom/base/nsDOMWindowUtils.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/base/nsIScriptContext.h
dom/base/nsIScriptGlobalObject.h
dom/base/nsJSEnvironment.cpp
dom/base/nsJSEnvironment.h
dom/interfaces/core/nsIDOMDocument.idl
dom/interfaces/traversal/nsIDOMDocumentTraversal.idl
dom/ipc/ContentChild.cpp
dom/src/events/nsJSEventListener.cpp
dom/src/json/nsJSON.cpp
dom/workers/WorkerPrivate.cpp
editor/libeditor/text/nsTextEditRules.cpp
gfx/layers/opengl/ContainerLayerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.h
gfx/thebes/gfxPlatformGtk.cpp
gfx/thebes/gfxPlatformGtk.h
js/src/assembler/assembler/AssemblerBuffer.h
js/src/assembler/assembler/X86Assembler.h
js/src/config/system-headers
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/Parser.cpp
js/src/gc/Statistics.h
js/src/jsapi.cpp
js/src/jsarray.cpp
js/src/jsatom.cpp
js/src/jsbool.cpp
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jsdate.cpp
js/src/jsdbgapi.cpp
js/src/jsexn.cpp
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/jsfun.cpp
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsinterp.cpp
js/src/jsiter.cpp
js/src/jsnum.cpp
js/src/jsnum.h
js/src/jsobj.cpp
js/src/json.cpp
js/src/jsopcode.cpp
js/src/jsscope.cpp
js/src/jsscript.cpp
js/src/jsstr.cpp
js/src/jstypedarray.cpp
js/src/jsxml.cpp
js/src/methodjit/BaseAssembler.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/StubCalls.cpp
js/src/shell/js.cpp
js/src/shell/jsworkers.cpp
js/xpconnect/idl/nsIXPConnect.idl
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/XPCVariant.cpp
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/src/xpcprivate.h
js/xpconnect/src/xpcpublic.h
layout/base/nsDocumentViewer.cpp
layout/base/nsLayoutUtils.cpp
layout/build/nsContentDLF.cpp
layout/style/nsRuleNode.cpp
mobile/android/base/AndroidManifest.xml.in
mobile/android/base/GeckoApp.java
mobile/android/base/Makefile.in
mobile/android/base/SyncPreference.java.in
mobile/android/base/resources/drawable/favicon.png
modules/libpref/src/init/all.js
netwerk/base/src/nsSocketTransport2.cpp
netwerk/cache/nsCacheEntryDescriptor.cpp
netwerk/protocol/http/SpdySession.cpp
netwerk/protocol/http/SpdySession.h
netwerk/protocol/http/SpdyStream.cpp
netwerk/protocol/http/nsAHttpConnection.h
netwerk/protocol/http/nsAHttpTransaction.h
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/protocol/http/nsHttpConnection.cpp
netwerk/protocol/http/nsHttpConnection.h
netwerk/protocol/http/nsHttpConnectionMgr.cpp
netwerk/protocol/http/nsHttpConnectionMgr.h
netwerk/protocol/http/nsHttpHandler.cpp
netwerk/protocol/http/nsHttpHandler.h
netwerk/protocol/http/nsHttpPipeline.cpp
netwerk/protocol/http/nsHttpTransaction.cpp
toolkit/components/autocomplete/nsAutoCompleteController.cpp
toolkit/components/telemetry/TelemetryHistograms.h
toolkit/components/telemetry/TelemetryPing.js
toolkit/crashreporter/nsExceptionHandler.cpp
toolkit/crashreporter/nsExceptionHandler.h
toolkit/mozapps/extensions/XPIProvider.jsm
widget/nsIWidget.h
widget/xpwidgets/nsBaseWidget.cpp
widget/xpwidgets/nsBaseWidget.h
xpcom/base/nsCycleCollector.cpp
--- a/browser/base/content/browser-appmenu.inc
+++ b/browser/base/content/browser-appmenu.inc
@@ -171,17 +171,18 @@
             <menuitem id="appmenu_printSetup"
                       label="&printSetupCmd.label;"
                       command="cmd_pageSetup"/>
           </menupopup>
       </splitmenu>
       <menuseparator class="appmenu-menuseparator"/>
       <menu id="appmenu_webDeveloper"
             label="&appMenuWebDeveloper.label;">
-        <menupopup id="appmenu_webDeveloper_popup">
+        <menupopup id="appmenu_webDeveloper_popup"
+                   onpopupshowing="onWebDeveloperMenuShowing();">
           <menuitem id="appmenu_webConsole"
                     label="&webConsoleCmd.label;"
                     type="checkbox"
                     command="Tools:WebConsole"
                     key="key_webConsole"/>
           <menuitem id="appmenu_pageInspect"
                     hidden="true"
                     label="&inspectMenu.label;"
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -526,17 +526,18 @@
                         accesskey="&syncSyncNowItem.accesskey;"
                         observes="sync-syncnow-state"
                         oncommand="gSyncUI.doSync(event);"/>
 #endif
               <menuseparator id="devToolsSeparator"/>
               <menu id="webDeveloperMenu"
                     label="&webDeveloperMenu.label;"
                     accesskey="&webDeveloperMenu.accesskey;">
-                <menupopup id="menuWebDeveloperPopup">
+                <menupopup id="menuWebDeveloperPopup"
+                           onpopupshowing="onWebDeveloperMenuShowing();">
                   <menuitem id="webConsole"
                             type="checkbox"
                             label="&webConsoleCmd.label;"
                             accesskey="&webConsoleCmd.accesskey;"
                             key="key_webConsole"
                             command="Tools:WebConsole"/>
                   <menuitem id="menu_pageinspect"
                             type="checkbox"
new file mode 100644
--- /dev/null
+++ b/browser/base/content/browser-thumbnails.js
@@ -0,0 +1,137 @@
+#ifdef 0
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+#endif
+
+/**
+ * Keeps thumbnails of open web pages up-to-date.
+ */
+let gBrowserThumbnails = {
+  _captureDelayMS: 2000,
+
+  /**
+   * Map of capture() timeouts assigned to their browsers.
+   */
+  _timeouts: null,
+
+  /**
+   * Cache for the PageThumbs module.
+   */
+  _pageThumbs: null,
+
+  /**
+   * List of tab events we want to listen for.
+   */
+  _tabEvents: ["TabClose", "TabSelect"],
+
+  init: function Thumbnails_init() {
+    gBrowser.addTabsProgressListener(this);
+
+    this._tabEvents.forEach(function (aEvent) {
+      gBrowser.tabContainer.addEventListener(aEvent, this, false);
+    }, this);
+
+    this._timeouts = new WeakMap();
+
+    XPCOMUtils.defineLazyModuleGetter(this, "_pageThumbs",
+      "resource:///modules/PageThumbs.jsm", "PageThumbs");
+  },
+
+  uninit: function Thumbnails_uninit() {
+    gBrowser.removeTabsProgressListener(this);
+
+    this._tabEvents.forEach(function (aEvent) {
+      gBrowser.tabContainer.removeEventListener(aEvent, this, false);
+    }, this);
+
+    this._timeouts = null;
+    this._pageThumbs = null;
+  },
+
+  handleEvent: function Thumbnails_handleEvent(aEvent) {
+    switch (aEvent.type) {
+      case "scroll":
+        let browser = aEvent.currentTarget;
+        if (this._timeouts.has(browser))
+          this._delayedCapture(browser);
+        break;
+      case "TabSelect":
+        this._delayedCapture(aEvent.target.linkedBrowser);
+        break;
+      case "TabClose": {
+        this._clearTimeout(aEvent.target.linkedBrowser);
+        break;
+      }
+    }
+  },
+
+  /**
+   * State change progress listener for all tabs.
+   */
+  onStateChange: function Thumbnails_onStateChange(aBrowser, aWebProgress,
+                                                   aRequest, aStateFlags, aStatus) {
+    if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
+        aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK)
+      this._delayedCapture(aBrowser);
+  },
+
+  _capture: function Thumbnails_capture(aBrowser) {
+    if (this._shouldCapture(aBrowser)) {
+      let canvas = this._pageThumbs.capture(aBrowser.contentWindow);
+      this._pageThumbs.store(aBrowser.currentURI.spec, canvas);
+    }
+  },
+
+  _delayedCapture: function Thumbnails_delayedCapture(aBrowser) {
+    if (this._timeouts.has(aBrowser))
+      clearTimeout(this._timeouts.get(aBrowser));
+    else
+      aBrowser.addEventListener("scroll", this, true);
+
+    let timeout = setTimeout(function () {
+      this._clearTimeout(aBrowser);
+      this._capture(aBrowser);
+    }.bind(this), this._captureDelayMS);
+
+    this._timeouts.set(aBrowser, timeout);
+  },
+
+  _shouldCapture: function Thumbnails_shouldCapture(aBrowser) {
+    let doc = aBrowser.contentDocument;
+
+    // FIXME Bug 720575 - Don't capture thumbnails for SVG or XML documents as
+    //       that currently regresses Talos SVG tests.
+    if (doc instanceof SVGDocument || doc instanceof XMLDocument)
+      return false;
+
+    // There's no point in taking screenshot of loading pages.
+    if (aBrowser.docShell.busyFlags != Ci.nsIDocShell.BUSY_FLAGS_NONE)
+      return false;
+
+    // Don't take screenshots of about: pages.
+    if (aBrowser.currentURI.schemeIs("about"))
+      return false;
+
+    let channel = aBrowser.docShell.currentDocumentChannel;
+
+    try {
+      // If the channel is a nsIHttpChannel get its http status code.
+      let httpChannel = channel.QueryInterface(Ci.nsIHttpChannel);
+
+      // Continue only if we have a 2xx status code.
+      return Math.floor(httpChannel.responseStatus / 100) == 2;
+    } catch (e) {
+      // Not a http channel, we just assume a success status code.
+      return true;
+    }
+  },
+
+  _clearTimeout: function Thumbnails_clearTimeout(aBrowser) {
+    if (this._timeouts.has(aBrowser)) {
+      aBrowser.removeEventListener("scroll", this, false);
+      clearTimeout(this._timeouts.get(aBrowser));
+      this._timeouts.delete(aBrowser);
+    }
+  }
+};
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -191,16 +191,17 @@ let gInitialPages = [
   "about:privatebrowsing",
   "about:sessionrestore"
 ];
 
 #include browser-fullZoom.js
 #include browser-places.js
 #include browser-tabPreviews.js
 #include browser-tabview.js
+#include browser-thumbnails.js
 
 #ifdef MOZ_SERVICES_SYNC
 #include browser-syncui.js
 #endif
 
 XPCOMUtils.defineLazyGetter(this, "Win7Features", function () {
 #ifdef XP_WIN
   const WINTASKBAR_CONTRACTID = "@mozilla.org/windows-taskbar;1";
@@ -1700,16 +1701,17 @@ function delayedStartup(isLoadingBlank, 
   if (document.mozFullScreen)
     onMozFullScreenChange();
 
 #ifdef MOZ_SERVICES_SYNC
   // initialize the sync UI
   gSyncUI.init();
 #endif
 
+  gBrowserThumbnails.init();
   TabView.init();
 
   setUrlAndSearchBarWidthForConditionalForwardButton();
   window.addEventListener("resize", function resizeHandler(event) {
     if (event.target == window)
       setUrlAndSearchBarWidthForConditionalForwardButton();
   });
 
@@ -1822,16 +1824,17 @@ function BrowserShutdown() {
   } else {
     if (Win7Features)
       Win7Features.onCloseWindow();
 
     gPrefService.removeObserver(ctrlTab.prefName, ctrlTab);
     gPrefService.removeObserver(allTabs.prefName, allTabs);
     ctrlTab.uninit();
     TabView.uninit();
+    gBrowserThumbnails.uninit();
 
     try {
       FullZoom.destroy();
     }
     catch(ex) {
       Components.utils.reportError(ex);
     }
 
@@ -4780,16 +4783,17 @@ var XULBrowserWindow = {
       this.asyncUpdateUI();
   },
 
   asyncUpdateUI: function () {
     FeedHandler.updateFeeds();
   },
 
   hideChromeForLocation: function(aLocation) {
+    aLocation = aLocation.toLowerCase();
     return this.inContentWhitelist.some(function(aSpec) {
       return aSpec == aLocation;
     });
   },
 
   onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) {
     this.status = aMessage;
     this.updateStatusField();
@@ -9055,16 +9059,21 @@ var StyleEditor = {
     let chromeWindow = Services.ww.openWindow(null, CHROME_URL, "_blank",
                                               CHROME_WINDOW_FLAGS,
                                               contentWindow);
     chromeWindow.focus();
     return chromeWindow;
   }
 };
 
+function onWebDeveloperMenuShowing() {
+  document.getElementById("Tools:WebConsole").setAttribute("checked", HUDConsoleUI.getOpenHUD() != null);
+}
+
+
 XPCOMUtils.defineLazyGetter(window, "gShowPageResizers", function () {
 #ifdef XP_WIN
   // Only show resizers on Windows 2000 and XP
   let sysInfo = Components.classes["@mozilla.org/system-info;1"]
                           .getService(Components.interfaces.nsIPropertyBag2);
   return parseFloat(sysInfo.getProperty("version")) < 6;
 #else
   return false;
@@ -9129,15 +9138,16 @@ var MousePosTracker = {
       if (listener.onMouseEnter)
         listener.onMouseEnter();
     } else {
       if (listener.onMouseLeave)
         listener.onMouseLeave();
     }
   }
 };
+
 function focusNextFrame(event) {
   let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
   let dir = event.shiftKey ? fm.MOVEFOCUS_BACKWARDDOC : fm.MOVEFOCUS_FORWARDDOC;
   let element = fm.moveFocus(window, null, dir, fm.FLAG_BYKEY);
   if (element.ownerDocument == document)
     focusAndSelectUrlBar();
 }
--- a/browser/base/content/test/browser_disablechrome.js
+++ b/browser/base/content/test/browser_disablechrome.js
@@ -99,17 +99,16 @@ function test() {
 
 function end_test() {
   gBrowser.removeTab(gNewTab);
   finish();
 }
 
 function test_url(aURL, aCanHide, aNextTest) {
   is_chrome_visible();
-
   info("Page load");
   load_page(aURL, aCanHide, function() {
     info("Switch away");
     gBrowser.selectedTab = gOldTab;
     is_chrome_visible();
 
     info("Switch back");
     gBrowser.selectedTab = gNewTab;
@@ -158,10 +157,35 @@ function run_chrome_about_test() {
 function run_http_test_2() {
   info("HTTP tests");
   test_url(HTTPSRC + "disablechrome.html", false, run_chrome_about_test_2);
 }
 
 // Should not hide the chrome
 function run_chrome_about_test_2() {
   info("Chrome about: tests");
-  test_url("about:addons", true, end_test);
+  test_url("about:addons", true, run_http_test3);
+}
+
+function run_http_test3() {
+  info("HTTP tests");
+  test_url(HTTPSRC + "disablechrome.html", false, run_chrome_about_test_3);
 }
+
+// Should not hide the chrome
+function run_chrome_about_test_3() {
+  info("Chrome about: tests");
+  test_url("about:Addons", true, function(){
+    info("Tabs on top");
+    TabsOnTop.enabled = true;
+    run_http_test4();
+  });
+}
+
+function run_http_test4() {
+  info("HTTP tests");
+  test_url(HTTPSRC + "disablechrome.html", false, run_chrome_about_test_4);
+}
+
+function run_chrome_about_test_4() {
+  info("Chrome about: tests");
+  test_url("about:Addons", true, end_test);
+}
--- a/browser/components/Makefile.in
+++ b/browser/components/Makefile.in
@@ -66,16 +66,17 @@ PARALLEL_DIRS = \
   places \
   preferences \
   privatebrowsing \
   search \
   sessionstore \
   shell \
   sidebar \
   tabview \
+  thumbnails \
   migration \
   $(NULL)
 
 ifdef MOZ_SAFE_BROWSING
 PARALLEL_DIRS += safebrowsing
 endif
 
 TEST_DIRS += test
--- a/browser/components/migration/src/Makefile.in
+++ b/browser/components/migration/src/Makefile.in
@@ -44,26 +44,25 @@ include $(DEPTH)/config/autoconf.mk
 MODULE		= migration
 LIBRARY_NAME	= migration_s
 FORCE_STATIC_LIB = 1
 ifndef MOZ_MEMORY
 USE_STATIC_LIBS = 1
 endif
 
 
-CPPSRCS  = nsBrowserProfileMigratorUtils.cpp \
-           $(NULL)
-
 ifeq ($(OS_ARCH)_$(GNU_CXX),WINNT_)
 CPPSRCS += nsIEProfileMigrator.cpp \
+           nsBrowserProfileMigratorUtils.cpp \
            $(NULL)
 endif
 
 ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 CPPSRCS += nsSafariProfileMigrator.cpp \
+           nsBrowserProfileMigratorUtils.cpp \
            $(NULL)
 endif            
 
 EXTRA_PP_COMPONENTS = \
   ProfileMigrator.js \
   ChromeProfileMigrator.js \
   FirefoxProfileMigrator.js \
   $(NULL)
--- a/browser/components/tabview/iq.js
+++ b/browser/components/tabview/iq.js
@@ -736,16 +736,21 @@ iQClass.prototype = {
       let handler = func;
       if (elem.iQEventData && elem.iQEventData[type]) {
         let count = elem.iQEventData[type].length;
         for (let a = 0; a < count; a++) {
           let pair = elem.iQEventData[type][a];
           if (pair.original == func) {
             handler = pair.modified;
             elem.iQEventData[type].splice(a, 1);
+            if (!elem.iQEventData[type].length) {
+              delete elem.iQEventData[type];
+              if (!Object.keys(elem.iQEventData).length)
+                delete elem.iQEventData;
+            }
             break;
           }
         }
       }
 
       elem.removeEventListener(type, handler, false);
     }
 
@@ -760,20 +765,20 @@ iQClass.prototype = {
       let elem = this[i];
 
       for (let j = 0; j < elem.childElementCount; j++)
         iQ(elem.children[j]).unbindAll();
 
       if (!elem.iQEventData)
         continue;
 
-      for (let type in elem.iQEventData) {
-        while (elem.iQEventData[type].length)
+      Object.keys(elem.iQEventData).forEach(function (type) {
+        while (elem.iQEventData && elem.iQEventData[type])
           this.unbind(type, elem.iQEventData[type][0].original);
-      }
+      }, this);
     }
 
     return this;
   }
 };
 
 // ----------
 // Create various event aliases
new file mode 100644
--- /dev/null
+++ b/browser/components/thumbnails/BrowserPageThumbs.manifest
@@ -0,0 +1,2 @@
+component {5a4ae9b5-f475-48ae-9dce-0b4c1d347884} PageThumbsProtocol.js
+contract @mozilla.org/network/protocol;1?name=moz-page-thumb {5a4ae9b5-f475-48ae-9dce-0b4c1d347884}
new file mode 100644
--- /dev/null
+++ b/browser/components/thumbnails/Makefile.in
@@ -0,0 +1,28 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+# You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DEPTH		= ../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+EXTRA_COMPONENTS = \
+	BrowserPageThumbs.manifest \
+	PageThumbsProtocol.js \
+	$(NULL)
+
+EXTRA_PP_JS_MODULES = \
+	PageThumbs.jsm \
+	$(NULL)
+
+# FIXME Bug 721422 - Re-enable tests and make them work with URI_DANGEROUS_TO_LOAD
+#ifdef ENABLE_TESTS
+#	DIRS += test
+#endif
+
+include $(topsrcdir)/config/rules.mk
+
+XPIDL_FLAGS += -I$(topsrcdir)/browser/components/
new file mode 100644
--- /dev/null
+++ b/browser/components/thumbnails/PageThumbs.jsm
@@ -0,0 +1,259 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+let EXPORTED_SYMBOLS = ["PageThumbs", "PageThumbsCache"];
+
+const Cu = Components.utils;
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
+
+/**
+ * The default width for page thumbnails.
+ *
+ * Hint: This is the default value because the 'New Tab Page' is the only
+ *       client for now.
+ */
+const THUMBNAIL_WIDTH = 201;
+
+/**
+ * The default height for page thumbnails.
+ *
+ * Hint: This is the default value because the 'New Tab Page' is the only
+ *       client for now.
+ */
+const THUMBNAIL_HEIGHT = 127;
+
+/**
+ * The default background color for page thumbnails.
+ */
+const THUMBNAIL_BG_COLOR = "#fff";
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
+  "resource://gre/modules/NetUtil.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "Services",
+  "resource://gre/modules/Services.jsm");
+
+/**
+ * Singleton providing functionality for capturing web page thumbnails and for
+ * accessing them if already cached.
+ */
+let PageThumbs = {
+  /**
+   * The scheme to use for thumbnail urls.
+   */
+  get scheme() "moz-page-thumb",
+
+  /**
+   * The static host to use for thumbnail urls.
+   */
+  get staticHost() "thumbnail",
+
+  /**
+   * The thumbnails' image type.
+   */
+  get contentType() "image/png",
+
+  /**
+   * Gets the thumbnail image's url for a given web page's url.
+   * @param aUrl The web page's url that is depicted in the thumbnail.
+   * @return The thumbnail image's url.
+   */
+  getThumbnailURL: function PageThumbs_getThumbnailURL(aUrl) {
+    return this.scheme + "://" + this.staticHost +
+           "?url=" + encodeURIComponent(aUrl);
+  },
+
+  /**
+   * Creates a canvas containing a thumbnail depicting the given window.
+   * @param aWindow The DOM window to capture a thumbnail from.
+   * @return The newly created canvas containing the image data.
+   */
+  capture: function PageThumbs_capture(aWindow) {
+    let [sw, sh, scale] = this._determineCropSize(aWindow);
+
+    let canvas = this._createCanvas();
+    let ctx = canvas.getContext("2d");
+
+    // Scale the canvas accordingly.
+    ctx.scale(scale, scale);
+
+    try {
+      // Draw the window contents to the canvas.
+      ctx.drawWindow(aWindow, 0, 0, sw, sh, THUMBNAIL_BG_COLOR,
+                     ctx.DRAWWINDOW_DO_NOT_FLUSH);
+    } catch (e) {
+      // We couldn't draw to the canvas for some reason.
+    }
+
+    return canvas;
+  },
+
+  /**
+   * Stores the image data contained in the given canvas to the underlying
+   * storage.
+   * @param aKey The key to use for the storage.
+   * @param aCanvas The canvas containing the thumbnail's image data.
+   * @param aCallback The function to be called when the canvas data has been
+   *                  stored (optional).
+   */
+  store: function PageThumbs_store(aKey, aCanvas, aCallback) {
+    let self = this;
+
+    function finish(aSuccessful) {
+      if (aCallback)
+        aCallback(aSuccessful);
+    }
+
+    // Get a writeable cache entry.
+    PageThumbsCache.getWriteEntry(aKey, function (aEntry) {
+      if (!aEntry) {
+        finish(false);
+        return;
+      }
+
+      // Extract image data from the canvas.
+      self._readImageData(aCanvas, function (aData) {
+        let outputStream = aEntry.openOutputStream(0);
+
+        // Write the image data to the cache entry.
+        NetUtil.asyncCopy(aData, outputStream, function (aResult) {
+          let success = Components.isSuccessCode(aResult);
+          if (success)
+            aEntry.markValid();
+
+          aEntry.close();
+          finish(success);
+        });
+      });
+    });
+  },
+
+  /**
+   * Reads the image data from a given canvas and passes it to the callback.
+   * @param aCanvas The canvas to read the image data from.
+   * @param aCallback The function that the image data is passed to.
+   */
+  _readImageData: function PageThumbs_readImageData(aCanvas, aCallback) {
+    let dataUri = aCanvas.toDataURL(PageThumbs.contentType, "");
+    let uri = Services.io.newURI(dataUri, "UTF8", null);
+
+    NetUtil.asyncFetch(uri, function (aData, aResult) {
+      if (Components.isSuccessCode(aResult) && aData && aData.available())
+        aCallback(aData);
+    });
+  },
+
+  /**
+   * Determines the crop size for a given content window.
+   * @param aWindow The content window.
+   * @return An array containing width, height and scale.
+   */
+  _determineCropSize: function PageThumbs_determineCropSize(aWindow) {
+    let sw = aWindow.innerWidth;
+    let sh = aWindow.innerHeight;
+
+    let scale = Math.max(THUMBNAIL_WIDTH / sw, THUMBNAIL_HEIGHT / sh);
+    let scaledWidth = sw * scale;
+    let scaledHeight = sh * scale;
+
+    if (scaledHeight > THUMBNAIL_HEIGHT)
+      sh -= Math.floor(Math.abs(scaledHeight - THUMBNAIL_HEIGHT) * scale);
+
+    if (scaledWidth > THUMBNAIL_WIDTH)
+      sw -= Math.floor(Math.abs(scaledWidth - THUMBNAIL_WIDTH) * scale);
+
+    return [sw, sh, scale];
+  },
+
+  /**
+   * Creates a new hidden canvas element.
+   * @return The newly created canvas.
+   */
+  _createCanvas: function PageThumbs_createCanvas() {
+    let doc = Services.appShell.hiddenDOMWindow.document;
+    let canvas = doc.createElementNS(HTML_NAMESPACE, "canvas");
+    canvas.mozOpaque = true;
+    canvas.mozImageSmoothingEnabled = true;
+    canvas.width = THUMBNAIL_WIDTH;
+    canvas.height = THUMBNAIL_HEIGHT;
+    return canvas;
+  }
+};
+
+/**
+ * A singleton handling the storage of page thumbnails.
+ */
+let PageThumbsCache = {
+  /**
+   * Calls the given callback with a cache entry opened for reading.
+   * @param aKey The key identifying the desired cache entry.
+   * @param aCallback The callback that is called when the cache entry is ready.
+   */
+  getReadEntry: function Cache_getReadEntry(aKey, aCallback) {
+    // Try to open the desired cache entry.
+    this._openCacheEntry(aKey, Ci.nsICache.ACCESS_READ, aCallback);
+  },
+
+  /**
+   * Calls the given callback with a cache entry opened for writing.
+   * @param aKey The key identifying the desired cache entry.
+   * @param aCallback The callback that is called when the cache entry is ready.
+   */
+  getWriteEntry: function Cache_getWriteEntry(aKey, aCallback) {
+    // Try to open the desired cache entry.
+    this._openCacheEntry(aKey, Ci.nsICache.ACCESS_WRITE, aCallback);
+  },
+
+  /**
+   * Opens the cache entry identified by the given key.
+   * @param aKey The key identifying the desired cache entry.
+   * @param aAccess The desired access mode (see nsICache.ACCESS_* constants).
+   * @param aCallback The function to be called when the cache entry was opened.
+   */
+  _openCacheEntry: function Cache_openCacheEntry(aKey, aAccess, aCallback) {
+    function onCacheEntryAvailable(aEntry, aAccessGranted, aStatus) {
+      let validAccess = aAccess == aAccessGranted;
+      let validStatus = Components.isSuccessCode(aStatus);
+
+      // Check if a valid entry was passed and if the
+      // access we requested was actually granted.
+      if (aEntry && !(validAccess && validStatus)) {
+        aEntry.close();
+        aEntry = null;
+      }
+
+      aCallback(aEntry);
+    }
+
+    let listener = this._createCacheListener(onCacheEntryAvailable);
+    this._cacheSession.asyncOpenCacheEntry(aKey, aAccess, listener);
+  },
+
+  /**
+   * Returns a cache listener implementing the nsICacheListener interface.
+   * @param aCallback The callback to be called when the cache entry is available.
+   * @return The new cache listener.
+   */
+  _createCacheListener: function Cache_createCacheListener(aCallback) {
+    return {
+      onCacheEntryAvailable: aCallback,
+      QueryInterface: XPCOMUtils.generateQI([Ci.nsICacheListener])
+    };
+  }
+};
+
+/**
+ * Define a lazy getter for the cache session.
+ */
+XPCOMUtils.defineLazyGetter(PageThumbsCache, "_cacheSession", function () {
+  return Services.cache.createSession(PageThumbs.scheme,
+                                     Ci.nsICache.STORE_ON_DISK, true);
+});
new file mode 100644
--- /dev/null
+++ b/browser/components/thumbnails/PageThumbsProtocol.js
@@ -0,0 +1,448 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * PageThumbsProtocol.js
+ *
+ * This file implements the moz-page-thumb:// protocol and the corresponding
+ * channel delivering cached thumbnails.
+ *
+ * URL structure:
+ *
+ * moz-page-thumb://thumbnail?url=http%3A%2F%2Fwww.mozilla.org%2F
+ *
+ * This URL requests an image for 'http://www.mozilla.org/'.
+ */
+
+"use strict";
+
+const Cu = Components.utils;
+const Cc = Components.classes;
+const Cr = Components.results;
+const Ci = Components.interfaces;
+
+Cu.import("resource:///modules/PageThumbs.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
+  "resource://gre/modules/NetUtil.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "Services",
+  "resource://gre/modules/Services.jsm");
+
+/**
+ * Implements the thumbnail protocol handler responsible for moz-page-thumb: URIs.
+ */
+function Protocol() {
+}
+
+Protocol.prototype = {
+  /**
+   * The scheme used by this protocol.
+   */
+  get scheme() PageThumbs.scheme,
+
+  /**
+   * The default port for this protocol (we don't support ports).
+   */
+  get defaultPort() -1,
+
+  /**
+   * The flags specific to this protocol implementation.
+   */
+  get protocolFlags() {
+    return Ci.nsIProtocolHandler.URI_DANGEROUS_TO_LOAD |
+           Ci.nsIProtocolHandler.URI_NORELATIVE |
+           Ci.nsIProtocolHandler.URI_NOAUTH;
+  },
+
+  /**
+   * Creates a new URI object that is suitable for loading by this protocol.
+   * @param aSpec The URI string in UTF8 encoding.
+   * @param aOriginCharset The charset of the document from which the URI originated.
+   * @return The newly created URI.
+   */
+  newURI: function Proto_newURI(aSpec, aOriginCharset) {
+    let uri = Cc["@mozilla.org/network/simple-uri;1"].createInstance(Ci.nsIURI);
+    uri.spec = aSpec;
+    return uri;
+  },
+
+  /**
+   * Constructs a new channel from the given URI for this protocol handler.
+   * @param aURI The URI for which to construct a channel.
+   * @return The newly created channel.
+   */
+  newChannel: function Proto_newChannel(aURI) {
+    return new Channel(aURI);
+  },
+
+  /**
+   * Decides whether to allow a blacklisted port.
+   * @return Always false, we'll never allow ports.
+   */
+  allowPort: function () false,
+
+  classID: Components.ID("{5a4ae9b5-f475-48ae-9dce-0b4c1d347884}"),
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIProtocolHandler])
+};
+
+let NSGetFactory = XPCOMUtils.generateNSGetFactory([Protocol]);
+
+/**
+ * A channel implementation responsible for delivering cached thumbnails.
+ */
+function Channel(aURI) {
+  this._uri = aURI;
+
+  // nsIChannel
+  this.originalURI = aURI;
+
+  // nsIHttpChannel
+  this._responseHeaders = {"content-type": PageThumbs.contentType};
+}
+
+Channel.prototype = {
+  /**
+   * Tracks if the channel has been opened, yet.
+   */
+  _wasOpened: false,
+
+  /**
+   * Opens this channel asynchronously.
+   * @param aListener The listener that receives the channel data when available.
+   * @param aContext A custom context passed to the listener's methods.
+   */
+  asyncOpen: function Channel_asyncOpen(aListener, aContext) {
+    if (this._wasOpened)
+      throw Cr.NS_ERROR_ALREADY_OPENED;
+
+    if (this.canceled)
+      return;
+
+    this._listener = aListener;
+    this._context = aContext;
+
+    this._isPending = true;
+    this._wasOpened = true;
+
+    // Try to read the data from the thumbnail cache.
+    this._readCache(function (aData) {
+      // Update response if there's no data.
+      if (!aData) {
+        this._responseStatus = 404;
+        this._responseText = "Not Found";
+      }
+
+      this._startRequest();
+
+      if (!this.canceled) {
+        this._addToLoadGroup();
+
+        if (aData)
+          this._serveData(aData);
+
+        if (!this.canceled)
+          this._stopRequest();
+      }
+    }.bind(this));
+  },
+
+  /**
+   * Reads a data stream from the cache entry.
+   * @param aCallback The callback the data is passed to.
+   */
+  _readCache: function Channel_readCache(aCallback) {
+    let {url} = parseURI(this._uri);
+
+    // Return early if there's no valid URL given.
+    if (!url) {
+      aCallback(null);
+      return;
+    }
+
+    // Try to get a cache entry.
+    PageThumbsCache.getReadEntry(url, function (aEntry) {
+      let inputStream = aEntry && aEntry.openInputStream(0);
+
+      function closeEntryAndFinish(aData) {
+        if (aEntry) {
+          aEntry.close();
+        }
+        aCallback(aData);
+      }
+
+      // Check if we have a valid entry and if it has any data.
+      if (!inputStream || !inputStream.available()) {
+        closeEntryAndFinish();
+        return;
+      }
+
+      try {
+        // Read the cache entry's data.
+        NetUtil.asyncFetch(inputStream, function (aData, aStatus) {
+          // We might have been canceled while waiting.
+          if (this.canceled)
+            return;
+
+          // Check if we have a valid data stream.
+          if (!Components.isSuccessCode(aStatus) || !aData.available())
+            aData = null;
+
+          closeEntryAndFinish(aData);
+        }.bind(this));
+      } catch (e) {
+        closeEntryAndFinish();
+      }
+    }.bind(this));
+  },
+
+  /**
+   * Calls onStartRequest on the channel listener.
+   */
+  _startRequest: function Channel_startRequest() {
+    try {
+      this._listener.onStartRequest(this, this._context);
+    } catch (e) {
+      // The listener might throw if the request has been canceled.
+      this.cancel(Cr.NS_BINDING_ABORTED);
+    }
+  },
+
+  /**
+   * Calls onDataAvailable on the channel listener and passes the data stream.
+   * @param aData The data to be delivered.
+   */
+  _serveData: function Channel_serveData(aData) {
+    try {
+      let available = aData.available();
+      this._listener.onDataAvailable(this, this._context, aData, 0, available);
+    } catch (e) {
+      // The listener might throw if the request has been canceled.
+      this.cancel(Cr.NS_BINDING_ABORTED);
+    }
+  },
+
+  /**
+   * Calls onStopRequest on the channel listener.
+   */
+  _stopRequest: function Channel_stopRequest() {
+    try {
+      this._listener.onStopRequest(this, this._context, this.status);
+    } catch (e) {
+      // This might throw but is generally ignored.
+    }
+
+    // The request has finished, clean up after ourselves.
+    this._cleanup();
+  },
+
+  /**
+   * Adds this request to the load group, if any.
+   */
+  _addToLoadGroup: function Channel_addToLoadGroup() {
+    if (this.loadGroup)
+      this.loadGroup.addRequest(this, this._context);
+  },
+
+  /**
+   * Removes this request from its load group, if any.
+   */
+  _removeFromLoadGroup: function Channel_removeFromLoadGroup() {
+    if (!this.loadGroup)
+      return;
+
+    try {
+      this.loadGroup.removeRequest(this, this._context, this.status);
+    } catch (e) {
+      // This might throw but is ignored.
+    }
+  },
+
+  /**
+   * Cleans up the channel when the request has finished.
+   */
+  _cleanup: function Channel_cleanup() {
+    this._removeFromLoadGroup();
+    this.loadGroup = null;
+
+    this._isPending = false;
+
+    delete this._listener;
+    delete this._context;
+  },
+
+  /* :::::::: nsIChannel ::::::::::::::: */
+
+  contentType: PageThumbs.contentType,
+  contentLength: -1,
+  owner: null,
+  contentCharset: null,
+  notificationCallbacks: null,
+
+  get URI() this._uri,
+  get securityInfo() null,
+
+  /**
+   * Opens this channel synchronously. Not supported.
+   */
+  open: function Channel_open() {
+    // Synchronous data delivery is not implemented.
+    throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+  },
+
+  /* :::::::: nsIHttpChannel ::::::::::::::: */
+
+  redirectionLimit: 10,
+  requestMethod: "GET",
+  allowPipelining: true,
+  referrer: null,
+
+  get requestSucceeded() true,
+
+  _responseStatus: 200,
+  get responseStatus() this._responseStatus,
+
+  _responseText: "OK",
+  get responseStatusText() this._responseText,
+
+  /**
+   * Checks if the server sent the equivalent of a "Cache-control: no-cache"
+   * response header.
+   * @return Always false.
+   */
+  isNoCacheResponse: function () false,
+
+  /**
+   * Checks if the server sent the equivalent of a "Cache-control: no-cache"
+   * response header.
+   * @return Always false.
+   */
+  isNoStoreResponse: function () false,
+
+  /**
+   * Returns the value of a particular request header. Not implemented.
+   */
+  getRequestHeader: function Channel_getRequestHeader() {
+    throw Cr.NS_ERROR_NOT_AVAILABLE;
+  },
+
+  /**
+   * This method is called to set the value of a particular request header.
+   * Not implemented.
+   */
+  setRequestHeader: function Channel_setRequestHeader() {
+    if (this._wasOpened)
+      throw Cr.NS_ERROR_IN_PROGRESS;
+  },
+
+  /**
+   * Call this method to visit all request headers. Not implemented.
+   */
+  visitRequestHeaders: function () {},
+
+  /**
+   * Gets the value of a particular response header.
+   * @param aHeader The case-insensitive name of the response header to query.
+   * @return The header value.
+   */
+  getResponseHeader: function Channel_getResponseHeader(aHeader) {
+    let name = aHeader.toLowerCase();
+    if (name in this._responseHeaders)
+      return this._responseHeaders[name];
+
+    throw Cr.NS_ERROR_NOT_AVAILABLE;
+  },
+
+  /**
+   * This method is called to set the value of a particular response header.
+   * @param aHeader The case-insensitive name of the response header to query.
+   * @param aValue The response header value to set.
+   */
+  setResponseHeader: function Channel_setResponseHeader(aHeader, aValue, aMerge) {
+    let name = aHeader.toLowerCase();
+    if (!aValue && !aMerge)
+      delete this._responseHeaders[name];
+    else
+      this._responseHeaders[name] = aValue;
+  },
+
+  /**
+   * Call this method to visit all response headers.
+   * @param aVisitor The header visitor.
+   */
+  visitResponseHeaders: function Channel_visitResponseHeaders(aVisitor) {
+    for (let name in this._responseHeaders) {
+      let value = this._responseHeaders[name];
+
+      try {
+        aVisitor.visitHeader(name, value);
+      } catch (e) {
+        // The visitor can throw to stop the iteration.
+        return;
+      }
+    }
+  },
+
+  /* :::::::: nsIRequest ::::::::::::::: */
+
+  loadFlags: Ci.nsIRequest.LOAD_NORMAL,
+  loadGroup: null,
+
+  get name() this._uri.spec,
+
+  _status: Cr.NS_OK,
+  get status() this._status,
+
+  _isPending: false,
+  isPending: function () this._isPending,
+
+  resume: function () {},
+  suspend: function () {},
+
+  /**
+   * Cancels this request.
+   * @param aStatus The reason for cancelling.
+   */
+  cancel: function Channel_cancel(aStatus) {
+    if (this.canceled)
+      return;
+
+    this._isCanceled = true;
+    this._status = aStatus;
+
+    this._cleanup();
+  },
+
+  /* :::::::: nsIHttpChannelInternal ::::::::::::::: */
+
+  documentURI: null,
+
+  _isCanceled: false,
+  get canceled() this._isCanceled,
+
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIChannel,
+                                         Ci.nsIHttpChannel,
+                                         Ci.nsIHttpChannelInternal,
+                                         Ci.nsIRequest])
+};
+
+/**
+ * Parses a given URI and extracts all parameters relevant to this protocol.
+ * @param aURI The URI to parse.
+ * @return The parsed parameters.
+ */
+function parseURI(aURI) {
+  let {scheme, staticHost} = PageThumbs;
+  let re = new RegExp("^" + scheme + "://" + staticHost + ".*?\\?");
+  let query = aURI.spec.replace(re, "");
+  let params = {};
+
+  query.split("&").forEach(function (aParam) {
+    let [key, value] = aParam.split("=").map(decodeURIComponent);
+    params[key.toLowerCase()] = value;
+  });
+
+  return params;
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/thumbnails/test/Makefile.in
@@ -0,0 +1,21 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+# You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DEPTH		= ../../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+relativesrcdir  = browser/components/thumbnails/test
+
+include $(DEPTH)/config/autoconf.mk
+include $(topsrcdir)/config/rules.mk
+
+_BROWSER_FILES = \
+	browser_thumbnails_cache.js \
+	browser_thumbnails_capture.js \
+	head.js \
+	$(NULL)
+
+libs::	$(_BROWSER_FILES)
+	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/components/thumbnails/test/browser_thumbnails_cache.js
@@ -0,0 +1,34 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * These tests ensure that saving a thumbnail to the cache works. They also
+ * retrieve the thumbnail and display it using an <img> element to compare
+ * its pixel colors.
+ */
+function runTests() {
+  // Create a new tab with a red background.
+  yield addTab("data:text/html,<body bgcolor=ff0000></body>");
+  let cw = gBrowser.selectedTab.linkedBrowser.contentWindow;
+
+  // Capture a thumbnail for the tab.
+  let canvas = PageThumbs.capture(cw);
+
+  // Store the tab into the thumbnail cache.
+  yield PageThumbs.store("key", canvas, next);
+
+  let {width, height} = canvas;
+  let thumb = PageThumbs.getThumbnailURL("key", width, height);
+
+  // Create a new tab with an image displaying the previously stored thumbnail.
+  yield addTab("data:text/html,<img src='" + thumb + "'/>" + 
+               "<canvas width=" + width + " height=" + height + "/>");
+
+  cw = gBrowser.selectedTab.linkedBrowser.contentWindow;
+  let [img, canvas] = cw.document.querySelectorAll("img, canvas");
+
+  // Draw the image to a canvas and compare the pixel color values.
+  let ctx = canvas.getContext("2d");
+  ctx.drawImage(img, 0, 0, width, height);
+  checkCanvasColor(ctx, 255, 0, 0, "we have a red image and canvas");
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/thumbnails/test/browser_thumbnails_capture.js
@@ -0,0 +1,38 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * These tests ensure that capturing a site's screenshot to a canvas actually
+ * works.
+ */
+function runTests() {
+  // Create a tab with a red background.
+  yield addTab("data:text/html,<body bgcolor=ff0000></body>");
+  checkCurrentThumbnailColor(255, 0, 0, "we have a red thumbnail");
+
+  // Load a page with a green background.
+  yield navigateTo("data:text/html,<body bgcolor=00ff00></body>");
+  checkCurrentThumbnailColor(0, 255, 0, "we have a green thumbnail");
+
+  // Load a page with a blue background.
+  yield navigateTo("data:text/html,<body bgcolor=0000ff></body>");
+  checkCurrentThumbnailColor(0, 0, 255, "we have a blue thumbnail");
+}
+
+/**
+ * Captures a thumbnail of the currently selected tab and checks the color of
+ * the resulting canvas.
+ * @param aRed The red component's intensity.
+ * @param aGreen The green component's intensity.
+ * @param aBlue The blue component's intensity.
+ * @param aMessage The info message to print when checking the pixel color.
+ */
+function checkCurrentThumbnailColor(aRed, aGreen, aBlue, aMessage) {
+  let tab = gBrowser.selectedTab;
+  let cw = tab.linkedBrowser.contentWindow;
+
+  let canvas = PageThumbs.capture(cw);
+  let ctx = canvas.getContext("2d");
+
+  checkCanvasColor(ctx, aRed, aGreen, aBlue, aMessage);
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/thumbnails/test/head.js
@@ -0,0 +1,93 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+Cu.import("resource:///modules/PageThumbs.jsm");
+
+registerCleanupFunction(function () {
+  while (gBrowser.tabs.length > 1)
+    gBrowser.removeTab(gBrowser.tabs[1]);
+});
+
+/**
+ * Provide the default test function to start our test runner.
+ */
+function test() {
+  TestRunner.run();
+}
+
+/**
+ * The test runner that controls the execution flow of our tests.
+ */
+let TestRunner = {
+  /**
+   * Starts the test runner.
+   */
+  run: function () {
+    waitForExplicitFinish();
+
+    this._iter = runTests();
+    this.next();
+  },
+
+  /**
+   * Runs the next available test or finishes if there's no test left.
+   */
+  next: function () {
+    try {
+      TestRunner._iter.next();
+    } catch (e if e instanceof StopIteration) {
+      finish();
+    }
+  }
+};
+
+/**
+ * Continues the current test execution.
+ */
+function next() {
+  TestRunner.next();
+}
+
+/**
+ * Creates a new tab with the given URI.
+ * @param aURI The URI that's loaded in the tab.
+ */
+function addTab(aURI) {
+  let tab = gBrowser.selectedTab = gBrowser.addTab(aURI);
+  whenBrowserLoaded(tab.linkedBrowser);
+}
+
+/**
+ * Loads a new URI into the currently selected tab.
+ * @param aURI The URI to load.
+ */
+function navigateTo(aURI) {
+  let browser = gBrowser.selectedTab.linkedBrowser;
+  whenBrowserLoaded(browser);
+  browser.loadURI(aURI);
+}
+
+/**
+ * Continues the current test execution when a load event for the given browser
+ * has been received
+ * @param aBrowser The browser to listen on.
+ */
+function whenBrowserLoaded(aBrowser) {
+  aBrowser.addEventListener("load", function onLoad() {
+    aBrowser.removeEventListener("load", onLoad, true);
+    executeSoon(next);
+  }, true);
+}
+
+/**
+ * Checks the top-left pixel of a given canvas' 2d context for a given color.
+ * @param aContext The 2D context of a canvas.
+ * @param aRed The red component's intensity.
+ * @param aGreen The green component's intensity.
+ * @param aBlue The blue component's intensity.
+ * @param aMessage The info message to print when comparing the pixel color.
+ */
+function checkCanvasColor(aContext, aRed, aGreen, aBlue, aMessage) {
+  let [r, g, b] = aContext.getImageData(0, 0, 1, 1).data;
+  ok(r == aRed && g == aGreen && b == aBlue, aMessage);
+}
--- a/browser/devtools/tilt/Tilt.jsm
+++ b/browser/devtools/tilt/Tilt.jsm
@@ -151,20 +151,25 @@ Tilt.prototype = {
 
       if (!aAnimateFlag) {
         finalize.call(this, aId);
         return;
       }
 
       let controller = this.visualizers[aId].controller;
       let presenter = this.visualizers[aId].presenter;
+
+      TiltUtils.setDocumentZoom(presenter.transforms.zoom);
+
       let content = presenter.contentWindow;
+      let pageXOffset = content.pageXOffset * TiltUtils.getDocumentZoom();
+      let pageYOffset = content.pageYOffset * TiltUtils.getDocumentZoom();
 
       controller.removeEventListeners();
-      controller.arcball.reset([-content.pageXOffset, -content.pageYOffset]);
+      controller.arcball.reset([-pageXOffset, -pageYOffset]);
       presenter.executeDestruction(finalize.bind(this, aId));
     }
   },
 
   /**
    * Handles any supplementary post-initialization work, done immediately
    * after a TILT_NOTIFICATIONS.INITIALIZED notification.
    */
--- a/browser/devtools/tilt/TiltUtils.jsm
+++ b/browser/devtools/tilt/TiltUtils.jsm
@@ -668,16 +668,26 @@ TiltUtils.getWindowId = function TU_getW
  * @return {Number} the zoom ammount
  */
 TiltUtils.getDocumentZoom = function TU_getDocumentZoom() {
   return TiltUtils.getBrowserWindow()
                   .gBrowser.selectedBrowser.markupDocumentViewer.fullZoom;
 };
 
 /**
+ * Sets the markup document viewer zoom for the currently selected browser.
+ *
+ * @param {Number} the zoom ammount
+ */
+TiltUtils.setDocumentZoom = function TU_getDocumentZoom(aZoom) {
+  TiltUtils.getBrowserWindow()
+           .gBrowser.selectedBrowser.markupDocumentViewer.fullZoom = aZoom;
+};
+
+/**
  * Performs a garbage collection.
  */
 TiltUtils.gc = function TU_gc()
 {
   TiltUtils.getBrowserWindow()
            .QueryInterface(Ci.nsIInterfaceRequestor)
            .getInterface(Ci.nsIDOMWindowUtils)
            .garbageCollect();
--- a/browser/devtools/tilt/TiltVisualizer.jsm
+++ b/browser/devtools/tilt/TiltVisualizer.jsm
@@ -55,21 +55,22 @@ const INVISIBLE_ELEMENTS = {
   "option": true,
   "script": true,
   "style": true,
   "title": true
 };
 
 const STACK_THICKNESS = 15;
 const WIREFRAME_COLOR = [0, 0, 0, 0.25];
-const INTRO_TRANSITION_DURATION = 80;
-const OUTRO_TRANSITION_DURATION = 50;
+const INTRO_TRANSITION_DURATION = 50;
+const OUTRO_TRANSITION_DURATION = 40;
 const INITIAL_Z_TRANSLATION = 400;
 
 const MOUSE_CLICK_THRESHOLD = 10;
+const MOUSE_INTRO_DELAY = 10;
 const ARCBALL_SENSITIVITY = 0.5;
 const ARCBALL_ROTATION_STEP = 0.15;
 const ARCBALL_TRANSLATION_STEP = 35;
 const ARCBALL_ZOOM_STEP = 0.1;
 const ARCBALL_ZOOM_MIN = -3000;
 const ARCBALL_ZOOM_MAX = 500;
 const ARCBALL_RESET_FACTOR = 0.9;
 const ARCBALL_RESET_INTERVAL = 1000 / 60;
@@ -291,17 +292,17 @@ TiltVisualizer.Presenter = function TV_P
     // only redraw if we really have to
     if (this.redraw) {
       this.redraw = false;
       this.drawVisualization();
     }
 
     // call the attached ondraw event handler if specified (by the controller)
     if ("function" === typeof this.ondraw) {
-      this.ondraw();
+      this.ondraw(this.frames);
     }
 
     if (!TiltVisualizer.Prefs.introTransition && !this.isExecutingDestruction) {
       this.frames = INTRO_TRANSITION_DURATION;
     }
     if (!TiltVisualizer.Prefs.outroTransition && this.isExecutingDestruction) {
       this.frames = OUTRO_TRANSITION_DURATION;
     }
@@ -475,16 +476,21 @@ TiltVisualizer.Presenter.prototype = {
     // this will be removed once the MOZ_window_region_texture bug #653656
     // is finished; currently just converting the document image to a texture
     // applied to the mesh
     this.texture = new renderer.Texture({
       source: TiltGL.TextureUtils.createContentImage(this.contentWindow,
                                                      this.maxTextureSize),
       format: "RGB"
     });
+
+    if ("function" === typeof this.onSetupTexture) {
+      this.onSetupTexture();
+      this.onSetupTexture = null;
+    }
   },
 
   /**
    * Create the combined mesh representing the document visualization by
    * traversing the document & adding a stack for each node that is drawable.
    *
    * @param {Object} aData
    *                 object containing the necessary mesh verts, texcoord etc.
@@ -497,16 +503,19 @@ TiltVisualizer.Presenter.prototype = {
     TiltUtils.destroyObject(this.meshStacks);
     TiltUtils.destroyObject(this.meshWireframe);
 
     // if the renderer was destroyed, don't continue setup
     if (!renderer || !renderer.context) {
       return;
     }
 
+    // save the mesh data for future use
+    this.meshData = aData;
+
     // create the visualization mesh using the vertices, texture coordinates
     // and indices computed when traversing the document object model
     this.meshStacks = {
       vertices: new renderer.VertexBuffer(aData.vertices, 3),
       texCoord: new renderer.VertexBuffer(aData.texCoord, 2),
       color: new renderer.VertexBuffer(aData.color, 3),
       indices: new renderer.IndexBuffer(aData.stacksIndices)
     };
@@ -519,29 +528,38 @@ TiltVisualizer.Presenter.prototype = {
     };
 
     // if there's no initial selection made, highlight the required node
     if (!this._initialSelection) {
       this._initialSelection = true;
       this.highlightNode(this.inspectorUI.selection);
     }
 
-    let zoom = TiltUtils.getDocumentZoom();
-    let width = Math.min(aData.meshWidth * zoom, renderer.width);
-    let height = Math.min(aData.meshHeight * zoom, renderer.height);
+    if (!this._initialMeshConfiguration) {
+      this._initialMeshConfiguration = true;
+
+      let zoom = TiltUtils.getDocumentZoom();
+      let width = Math.min(aData.meshWidth * zoom, renderer.width);
+      let height = Math.min(aData.meshHeight * zoom, renderer.height);
+
+      // set the necessary mesh offsets
+      this.transforms.offset[0] = -width * 0.5;
+      this.transforms.offset[1] = -height * 0.5;
 
-    // set the necessary mesh offsets
-    this.transforms.offset[0] = -width * 0.5;
-    this.transforms.offset[1] = -height * 0.5;
+      // make sure the canvas is opaque now that the initialization is finished
+      this.canvas.style.background = TiltVisualizerStyle.canvas.background;
 
-    // make sure the canvas is opaque now that the initialization is finished
-    this.canvas.style.background = TiltVisualizerStyle.canvas.background;
+      this.drawVisualization();
+      this.redraw = true;
+    }
 
-    this.drawVisualization();
-    this.redraw = true;
+    if ("function" === typeof this.onSetupMesh) {
+      this.onSetupMesh();
+      this.onSetupMesh = null;
+    }
   },
 
   /**
    * Computes the mesh vertices, texture coordinates etc.
    */
   setupMeshData: function TVP_setupMeshData()
   {
     let renderer = this.renderer;
@@ -621,39 +639,54 @@ TiltVisualizer.Presenter.prototype = {
   /**
    * Picks a stacked dom node at the x and y screen coordinates and highlights
    * the selected node in the mesh.
    *
    * @param {Number} x
    *                 the current horizontal coordinate of the mouse
    * @param {Number} y
    *                 the current vertical coordinate of the mouse
+   * @param {Object} aProperties
+   *                 an object containing the following properties:
+   *      {Function} onpick: function to be called after picking succeeded
+   *      {Function} onfail: function to be called after picking failed
    */
-  highlightNodeAt: function TVP_highlightNodeAt(x, y)
+  highlightNodeAt: function TVP_highlightNodeAt(x, y, aProperties)
   {
+    // make sure the properties parameter is a valid object
+    aProperties = aProperties || {};
+
     // try to pick a mesh node using the current x, y coordinates
     this.pickNode(x, y, {
 
       /**
        * Mesh picking failed (nothing was found for the picked point).
        */
       onfail: function TVP_onHighlightFail()
       {
         this.highlightNodeFor(-1);
+
+        if ("function" === typeof aProperties.onfail) {
+          aProperties.onfail();
+        }
       }.bind(this),
 
       /**
        * Mesh picking succeeded.
        *
        * @param {Object} aIntersection
        *                 object containing the intersection details
        */
       onpick: function TVP_onHighlightPick(aIntersection)
       {
         this.highlightNodeFor(aIntersection.index);
+
+        if ("function" === typeof aProperties.onpick) {
+          aProperties.onpick();
+        }
       }.bind(this)
     });
   },
 
   /**
    * Sets the corresponding highlight coordinates and color based on the
    * information supplied.
    *
@@ -697,16 +730,42 @@ TiltVisualizer.Presenter.prototype = {
     vec3.set([x,     y + h, z * STACK_THICKNESS], highlight.v3);
 
     this._currentSelection = aNodeIndex;
     this.inspectorUI.inspectNode(node, this.contentWindow.innerHeight < y ||
                                        this.contentWindow.pageYOffset > 0);
   },
 
   /**
+   * Deletes a node from the visualization mesh.
+   *
+   * @param {Number} aNodeIndex
+   *                 the index of the node in the this.traverseData array;
+   *                 if not specified, it will default to the current selection
+   */
+  deleteNode: function TVP_deleteNode(aNodeIndex)
+  {
+    // we probably don't want to delete the html or body node.. just sayin'
+    if ((aNodeIndex = aNodeIndex || this._currentSelection) < 1) {
+      return;
+    }
+
+    let renderer = this.renderer;
+    let meshData = this.meshData;
+
+    for (let i = 0, k = 36 * aNodeIndex; i < 36; i++) {
+      meshData.vertices[i + k] = 0;
+    }
+
+    this.meshStacks.vertices = new renderer.VertexBuffer(meshData.vertices, 3);
+    this.highlight.disabled = true;
+    this.redraw = true;
+  },
+
+  /**
    * Picks a stacked dom node at the x and y screen coordinates and issues
    * a callback function with the found intersection.
    *
    * @param {Number} x
    *                 the current horizontal coordinate of the mouse
    * @param {Number} y
    *                 the current vertical coordinate of the mouse
    * @param {Object} aProperties
@@ -882,16 +941,19 @@ TiltVisualizer.Controller = function TV_
   /**
    * The initial controller dimensions and offset, in pixels.
    */
   this.left = aPresenter.contentWindow.pageXOffset || 0;
   this.top = aPresenter.contentWindow.pageYOffset || 0;
   this.width = aCanvas.width;
   this.height = aCanvas.height;
 
+  this.left *= TiltUtils.getDocumentZoom();
+  this.top *= TiltUtils.getDocumentZoom();
+
   /**
    * Arcball used to control the visualization using the mouse.
    */
   this.arcball = new TiltVisualizer.Arcball(this.width, this.height, 0,
     [this.width + this.left < aPresenter.maxTextureSize ? -this.left : 0,
      this.height + this.top < aPresenter.maxTextureSize ? -this.top : 0]);
 
   /**
@@ -918,17 +980,16 @@ TiltVisualizer.Controller.prototype = {
   addEventListeners: function TVC_addEventListeners()
   {
     let canvas = this.canvas;
     let presenter = this.presenter;
 
     // bind commonly used mouse and keyboard events with the controller
     canvas.addEventListener("mousedown", this.onMouseDown, false);
     canvas.addEventListener("mouseup", this.onMouseUp, false);
-    canvas.addEventListener("click", this.onMouseClick, false);
     canvas.addEventListener("mousemove", this.onMouseMove, false);
     canvas.addEventListener("mouseover", this.onMouseOver, false);
     canvas.addEventListener("mouseout", this.onMouseOut, false);
     canvas.addEventListener("MozMousePixelScroll", this.onMozScroll, false);
     canvas.addEventListener("keydown", this.onKeyDown, false);
     canvas.addEventListener("keyup", this.onKeyUp, false);
     canvas.addEventListener("blur", this.onBlur, false);
 
@@ -941,101 +1002,103 @@ TiltVisualizer.Controller.prototype = {
    */
   removeEventListeners: function TVC_removeEventListeners()
   {
     let canvas = this.canvas;
     let presenter = this.presenter;
 
     canvas.removeEventListener("mousedown", this.onMouseDown, false);
     canvas.removeEventListener("mouseup", this.onMouseUp, false);
-    canvas.removeEventListener("click", this.onMouseClick, false);
     canvas.removeEventListener("mousemove", this.onMouseMove, false);
     canvas.removeEventListener("mouseover", this.onMouseOver, false);
     canvas.removeEventListener("mouseout", this.onMouseOut, false);
     canvas.removeEventListener("MozMousePixelScroll", this.onMozScroll, false);
     canvas.removeEventListener("keydown", this.onKeyDown, false);
     canvas.removeEventListener("keyup", this.onKeyUp, false);
     canvas.removeEventListener("blur", this.onBlur, false);
 
     presenter.contentWindow.removeEventListener("resize", this.onResize,false);
   },
 
   /**
    * Function called each frame, updating the visualization camera transforms.
+   *
+   * @param {Number} aFrames
+   *                 the current animation frame count
    */
-  update: function TVC_update()
+  update: function TVC_update(aFrames)
   {
+    this.frames = aFrames;
     this.coordinates = this.arcball.update();
 
     this.presenter.setRotation(this.coordinates.rotation);
     this.presenter.setTranslation(this.coordinates.translation);
   },
 
   /**
    * Called once after every time a mouse button is pressed.
    */
   onMouseDown: function TVC_onMouseDown(e)
   {
     e.target.focus();
     e.preventDefault();
     e.stopPropagation();
 
+    if (this.frames < MOUSE_INTRO_DELAY) {
+      return;
+    }
+
     // calculate x and y coordinates using using the client and target offset
+    let button = e.which;
     this._downX = e.clientX - e.target.offsetLeft;
     this._downY = e.clientY - e.target.offsetTop;
 
-    this.arcball.mouseDown(this._downX, this._downY, e.which);
+    this.arcball.mouseDown(this._downX, this._downY, button);
   },
 
   /**
    * Called every time a mouse button is released.
    */
   onMouseUp: function TVC_onMouseUp(e)
   {
     e.preventDefault();
     e.stopPropagation();
 
+    if (this.frames < MOUSE_INTRO_DELAY) {
+      return;
+    }
+
     // calculate x and y coordinates using using the client and target offset
     let button = e.which;
     let upX = e.clientX - e.target.offsetLeft;
     let upY = e.clientY - e.target.offsetTop;
 
-    this.arcball.mouseUp(upX, upY, button);
-  },
-
-  /**
-   * Called every time a mouse button is clicked.
-   */
-  onMouseClick: function TVC_onMouseClick(e)
-  {
-    e.preventDefault();
-    e.stopPropagation();
-
-    // calculate x and y coordinates using using the client and target offset
-    let button = e.which;
-    let clickX = e.clientX - e.target.offsetLeft;
-    let clickY = e.clientY - e.target.offsetTop;
-
     // a click in Tilt is issued only when the mouse pointer stays in
     // relatively the same position
-    if (Math.abs(this._downX - clickX) < MOUSE_CLICK_THRESHOLD &&
-        Math.abs(this._downY - clickY) < MOUSE_CLICK_THRESHOLD) {
+    if (Math.abs(this._downX - upX) < MOUSE_CLICK_THRESHOLD &&
+        Math.abs(this._downY - upY) < MOUSE_CLICK_THRESHOLD) {
 
-      this.presenter.highlightNodeAt(clickX, clickY);
+      this.presenter.highlightNodeAt(upX, upY);
     }
+
+    this.arcball.mouseUp(upX, upY, button);
   },
 
   /**
    * Called every time the mouse moves.
    */
   onMouseMove: function TVC_onMouseMove(e)
   {
     e.preventDefault();
     e.stopPropagation();
 
+    if (this.frames < MOUSE_INTRO_DELAY) {
+      return;
+    }
+
     // calculate x and y coordinates using using the client and target offset
     let moveX = e.clientX - e.target.offsetLeft;
     let moveY = e.clientY - e.target.offsetTop;
 
     this.arcball.mouseMove(moveX, moveY);
   },
 
   /**
@@ -1093,16 +1156,19 @@ TiltVisualizer.Controller.prototype = {
   onKeyUp: function TVC_onKeyUp(e)
   {
     let code = e.keyCode || e.which;
 
     if (code === e.DOM_VK_ESCAPE) {
       this.presenter.tiltUI.destroy(this.presenter.tiltUI.currentWindowId, 1);
       return;
     }
+    if (code === e.DOM_VK_X) {
+      this.presenter.deleteNode();
+    }
 
     if (!e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey) {
       e.preventDefault();
       e.stopPropagation();
       this.arcball.keyUp(code);
     }
   },
 
@@ -1190,31 +1256,31 @@ TiltVisualizer.Arcball = function TV_Arc
   this._endVec = vec3.create();
   this._pVec = vec3.create();
 
   /**
    * The corresponding rotation quaternions.
    */
   this._lastRot = quat4.create();
   this._deltaRot = quat4.create();
-  this._currentRot = quat4.create();
+  this._currentRot = quat4.create(aInitialRot);
 
   /**
    * The current camera translation coordinates.
    */
   this._lastTrans = vec3.create();
   this._deltaTrans = vec3.create();
-  this._currentTrans = vec3.create();
+  this._currentTrans = vec3.create(aInitialTrans);
   this._zoomAmount = 0;
 
   /**
    * Additional rotation and translation vectors.
    */
-  this._additionalRot = vec3.create(aInitialRot);
-  this._additionalTrans = vec3.create(aInitialTrans);
+  this._additionalRot = vec3.create();
+  this._additionalTrans = vec3.create();
   this._deltaAdditionalRot = quat4.create();
   this._deltaAdditionalTrans = vec3.create();
 
   // load the keys controlling the arcball
   this._loadKeys();
 
   // set the current dimensions of the arcball
   this.resize(aWidth, aHeight, aRadius);
@@ -1612,31 +1678,32 @@ TiltVisualizer.Arcball.prototype = {
    *
    * @param {Array} aFinalTranslation
    *                optional, final vector translation
    * @param {Array} aFinalRotation
    *                optional, final quaternion rotation
    */
   reset: function TVA_reset(aFinalTranslation, aFinalRotation)
   {
+    if ("function" === typeof this.onResetStart) {
+      this.onResetStart();
+      this.onResetStart = null;
+    }
+
     this.cancelMouseEvents();
     this.cancelKeyEvents();
+    this._cancelResetInterval();
 
-    if (!this._resetInterval) {
-      let window = TiltUtils.getBrowserWindow();
-      let func = this._nextResetIntervalStep.bind(this);
+    let window = TiltUtils.getBrowserWindow();
+    let func = this._nextResetIntervalStep.bind(this);
 
-      vec3.zero(this._additionalTrans);
-      vec3.zero(this._additionalRot);
-
-      this._save();
-      this._resetFinalTranslation = vec3.create(aFinalTranslation);
-      this._resetFinalRotation = quat4.create(aFinalRotation);
-      this._resetInterval = window.setInterval(func, ARCBALL_RESET_INTERVAL);
-    }
+    this._save();
+    this._resetFinalTranslation = vec3.create(aFinalTranslation);
+    this._resetFinalRotation = quat4.create(aFinalRotation);
+    this._resetInterval = window.setInterval(func, ARCBALL_RESET_INTERVAL);
   },
 
   /**
    * Cancels the current arcball reset animation if there is one.
    */
   _cancelResetInterval: function TVA__cancelResetInterval()
   {
     if (this._resetInterval) {
@@ -1661,29 +1728,33 @@ TiltVisualizer.Arcball.prototype = {
     let fDelta = EPSILON * EPSILON;
     let fTran = this._resetFinalTranslation;
     let fRot = this._resetFinalRotation;
 
     let t = vec3.create(fTran);
     let r = quat4.multiply(quat4.inverse(quat4.create(this._currentRot)), fRot);
 
     // reset the rotation quaternion and translation vector
-    vec3.lerp(this._currentTrans, t, ARCBALL_RESET_FACTOR);
+    vec3.lerp(this._currentTrans, t, ARCBALL_RESET_FACTOR / 4);
     quat4.slerp(this._currentRot, r, 1 - ARCBALL_RESET_FACTOR);
 
     // also reset any additional transforms by the keyboard or mouse
+    vec3.scale(this._additionalTrans, ARCBALL_RESET_FACTOR);
+    vec3.scale(this._additionalRot, ARCBALL_RESET_FACTOR);
     this._zoomAmount *= ARCBALL_RESET_FACTOR;
 
     // clear the loop if the all values are very close to zero
     if (vec3.length(vec3.subtract(this._lastRot, fRot, [])) < fDelta &&
         vec3.length(vec3.subtract(this._deltaRot, fRot, [])) < fDelta &&
         vec3.length(vec3.subtract(this._currentRot, fRot, [])) < fDelta &&
         vec3.length(vec3.subtract(this._lastTrans, fTran, [])) < fDelta &&
         vec3.length(vec3.subtract(this._deltaTrans, fTran, [])) < fDelta &&
-        vec3.length(vec3.subtract(this._currentTrans, fTran, [])) < fDelta) {
+        vec3.length(vec3.subtract(this._currentTrans, fTran, [])) < fDelta &&
+        vec3.length(this._additionalRot) < fDelta &&
+        vec3.length(this._additionalTrans) < fDelta) {
 
       this._cancelResetInterval();
     }
   },
 
   /**
    * Loads the keys to control this arcball.
    */
--- a/browser/devtools/tilt/TiltWorkerPicker.js
+++ b/browser/devtools/tilt/TiltWorkerPicker.js
@@ -76,16 +76,21 @@ self.onmessage = function TWP_onMessage(
     let v3f = [vertices[i + 9], vertices[i + 10], vertices[i + 11]];
 
     // the back quad
     let v0b = [v0f[0], v0f[1], v0f[2] - thickness];
     let v1b = [v1f[0], v1f[1], v1f[2] - thickness];
     let v2b = [v2f[0], v2f[1], v2f[2] - thickness];
     let v3b = [v3f[0], v3f[1], v3f[2] - thickness];
 
+    // don't do anything with degenerate quads
+    if (!v0f[0] && !v1f[0] && !v2f[0] && !v3f[0]) {
+      continue;
+    }
+
     // for each triangle in the stack box, check for the intersections
     if (self.intersect(v0f, v1f, v2f, ray, hit) || // front left
         self.intersect(v0f, v2f, v3f, ray, hit) || // front right
         self.intersect(v0b, v1b, v1f, ray, hit) || // left back
         self.intersect(v0b, v1f, v0f, ray, hit) || // left front
         self.intersect(v3f, v2b, v3b, ray, hit) || // right back
         self.intersect(v3f, v2f, v2b, ray, hit) || // right front
         self.intersect(v0b, v0f, v3f, ray, hit) || // top left
--- a/browser/devtools/tilt/test/Makefile.in
+++ b/browser/devtools/tilt/test/Makefile.in
@@ -68,16 +68,21 @@ include $(topsrcdir)/config/rules.mk
 	browser_tilt_gl08.js \
 	browser_tilt_math01.js \
 	browser_tilt_math02.js \
 	browser_tilt_math03.js \
 	browser_tilt_math04.js \
 	browser_tilt_math05.js \
 	browser_tilt_math06.js \
 	browser_tilt_math07.js \
+	browser_tilt_picking.js \
+	browser_tilt_picking_delete.js \
+	browser_tilt_picking_highlight01.js \
+	browser_tilt_picking_highlight02.js \
+	browser_tilt_picking_highlight03.js \
 	browser_tilt_utils01.js \
 	browser_tilt_utils02.js \
 	browser_tilt_utils03.js \
 	browser_tilt_utils04.js \
 	browser_tilt_utils05.js \
 	browser_tilt_utils06.js \
 	browser_tilt_visualizer.js \
 	browser_tilt_zoom.js \
--- a/browser/devtools/tilt/test/browser_tilt_arcball-reset-typeahead.js
+++ b/browser/devtools/tilt/test/browser_tilt_arcball-reset-typeahead.js
@@ -11,16 +11,17 @@ function test() {
     info("Skipping part of the arcball test because Tilt isn't enabled.");
     return;
   }
   if (!isWebGLSupported()) {
     info("Skipping part of the arcball test because WebGL isn't supported.");
     return;
   }
 
+  requestLongerTimeout(10);
   waitForExplicitFinish();
   Services.prefs.setBoolPref("accessibility.typeaheadfind", true);
 
   createTab(function() {
     createTilt({
       onTiltOpen: function(instance)
       {
         performTest(instance.presenter.canvas,
@@ -60,16 +61,20 @@ function performTest(canvas, arcball, ca
       EventUtils.synthesizeKey("VK_W", { type: "keyup" });
       EventUtils.synthesizeKey("VK_LEFT", { type: "keyup" });
 
       // ok, transformations finished, we can now try to reset the model view
 
       executeSoon(function() {
         info("Synthesizing arcball reset key press.");
 
+        arcball.onResetStart = function() {
+          info("Starting arcball reset animation.");
+        };
+
         arcball.onResetFinish = function() {
           ok(isApproxVec(arcball._lastRot, [0, 0, 0, 1]),
             "The arcball _lastRot field wasn't reset correctly.");
           ok(isApproxVec(arcball._deltaRot, [0, 0, 0, 1]),
             "The arcball _deltaRot field wasn't reset correctly.");
           ok(isApproxVec(arcball._currentRot, [0, 0, 0, 1]),
             "The arcball _currentRot field wasn't reset correctly.");
 
--- a/browser/devtools/tilt/test/browser_tilt_arcball-reset.js
+++ b/browser/devtools/tilt/test/browser_tilt_arcball-reset.js
@@ -11,16 +11,17 @@ function test() {
     info("Skipping part of the arcball test because Tilt isn't enabled.");
     return;
   }
   if (!isWebGLSupported()) {
     info("Skipping part of the arcball test because WebGL isn't supported.");
     return;
   }
 
+  requestLongerTimeout(10);
   waitForExplicitFinish();
 
   createTab(function() {
     createTilt({
       onTiltOpen: function(instance)
       {
         performTest(instance.presenter.canvas,
                     instance.controller.arcball, function() {
@@ -58,16 +59,20 @@ function performTest(canvas, arcball, ca
       EventUtils.synthesizeKey("VK_W", { type: "keyup" });
       EventUtils.synthesizeKey("VK_LEFT", { type: "keyup" });
 
       // ok, transformations finished, we can now try to reset the model view
 
       executeSoon(function() {
         info("Synthesizing arcball reset key press.");
 
+        arcball.onResetStart = function() {
+          info("Starting arcball reset animation.");
+        };
+
         arcball.onResetFinish = function() {
           ok(isApproxVec(arcball._lastRot, [0, 0, 0, 1]),
             "The arcball _lastRot field wasn't reset correctly.");
           ok(isApproxVec(arcball._deltaRot, [0, 0, 0, 1]),
             "The arcball _deltaRot field wasn't reset correctly.");
           ok(isApproxVec(arcball._currentRot, [0, 0, 0, 1]),
             "The arcball _currentRot field wasn't reset correctly.");
 
new file mode 100644
--- /dev/null
+++ b/browser/devtools/tilt/test/browser_tilt_picking.js
@@ -0,0 +1,52 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/*global ok, is, info, waitForExplicitFinish, finish, gBrowser */
+/*global isTiltEnabled, isWebGLSupported, createTab, createTilt */
+/*global Services, InspectorUI, TILT_DESTROYED */
+"use strict";
+
+function test() {
+  if (!isTiltEnabled()) {
+    info("Skipping picking test because Tilt isn't enabled.");
+    return;
+  }
+  if (!isWebGLSupported()) {
+    info("Skipping picking test because WebGL isn't supported.");
+    return;
+  }
+
+  waitForExplicitFinish();
+
+  createTab(function() {
+    createTilt({
+      onTiltOpen: function(instance)
+      {
+        let presenter = instance.presenter;
+        let canvas = presenter.canvas;
+
+        presenter.onSetupMesh = function() {
+
+          presenter.pickNode(canvas.width / 2, canvas.height / 2, {
+            onpick: function(data)
+            {
+              ok(data.index > 0,
+                "Simply picking a node didn't work properly.");
+              ok(!presenter.highlight.disabled,
+                "After only picking a node, it shouldn't be highlighted.");
+
+              Services.obs.addObserver(cleanup, TILT_DESTROYED, false);
+              InspectorUI.closeInspectorUI();
+            }
+          });
+        };
+      }
+    });
+  });
+}
+
+function cleanup() {
+  Services.obs.removeObserver(cleanup, TILT_DESTROYED);
+  gBrowser.removeCurrentTab();
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/tilt/test/browser_tilt_picking_delete.js
@@ -0,0 +1,67 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/*global ok, is, info, waitForExplicitFinish, finish, gBrowser */
+/*global isTiltEnabled, isWebGLSupported, createTab, createTilt */
+/*global Services, InspectorUI, TILT_DESTROYED */
+"use strict";
+
+function test() {
+  if (!isTiltEnabled()) {
+    info("Skipping picking delete test because Tilt isn't enabled.");
+    return;
+  }
+  if (!isWebGLSupported()) {
+    info("Skipping picking delete test because WebGL isn't supported.");
+    return;
+  }
+
+  waitForExplicitFinish();
+
+  createTab(function() {
+    createTilt({
+      onTiltOpen: function(instance)
+      {
+        let presenter = instance.presenter;
+        let canvas = presenter.canvas;
+
+        presenter.onSetupMesh = function() {
+
+          presenter.highlightNodeAt(canvas.width / 2, canvas.height / 2, {
+            onpick: function()
+            {
+              ok(presenter._currentSelection > 0,
+                "Highlighting a node didn't work properly.");
+              ok(!presenter.highlight.disabled,
+                "After highlighting a node, it should be highlighted. D'oh.");
+
+              presenter.deleteNode();
+
+              ok(presenter._currentSelection > 0,
+                "Deleting a node shouldn't change the current selection.");
+              ok(presenter.highlight.disabled,
+                "After deleting a node, it shouldn't be highlighted.");
+
+              let nodeIndex = presenter._currentSelection;
+              let meshData = presenter.meshData;
+
+              for (let i = 0, k = 36 * nodeIndex; i < 36; i++) {
+                is(meshData.vertices[i + k], 0,
+                  "The stack vertices weren't degenerated properly.");
+              }
+
+              Services.obs.addObserver(cleanup, TILT_DESTROYED, false);
+              InspectorUI.closeInspectorUI();
+            }
+          });
+        };
+      }
+    });
+  });
+}
+
+function cleanup() {
+  Services.obs.removeObserver(cleanup, TILT_DESTROYED);
+  gBrowser.removeCurrentTab();
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/tilt/test/browser_tilt_picking_highlight01.js
@@ -0,0 +1,50 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/*global ok, is, info, waitForExplicitFinish, finish, gBrowser */
+/*global isTiltEnabled, isWebGLSupported, createTab, createTilt */
+/*global Services, InspectorUI, TILT_DESTROYED */
+"use strict";
+
+function test() {
+  if (!isTiltEnabled()) {
+    info("Skipping highlight test because Tilt isn't enabled.");
+    return;
+  }
+  if (!isWebGLSupported()) {
+    info("Skipping highlight test because WebGL isn't supported.");
+    return;
+  }
+
+  waitForExplicitFinish();
+
+  createTab(function() {
+    createTilt({
+      onTiltOpen: function(instance)
+      {
+        let presenter = instance.presenter;
+
+        presenter.onSetupMesh = function() {
+          let contentDocument = presenter.contentWindow.document;
+          let body = contentDocument.getElementsByTagName("body")[0];
+
+          presenter.highlightNode(body);
+
+          ok(presenter._currentSelection > 0,
+            "Highlighting a node didn't work properly.");
+          ok(!presenter.highlight.disabled,
+            "After highlighting a node, it should be highlighted. D'oh.");
+
+          Services.obs.addObserver(cleanup, TILT_DESTROYED, false);
+          InspectorUI.closeInspectorUI();
+        };
+      }
+    });
+  });
+}
+
+function cleanup() {
+  Services.obs.removeObserver(cleanup, TILT_DESTROYED);
+  gBrowser.removeCurrentTab();
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/tilt/test/browser_tilt_picking_highlight02.js
@@ -0,0 +1,52 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/*global ok, is, info, waitForExplicitFinish, finish, gBrowser */
+/*global isTiltEnabled, isWebGLSupported, createTab, createTilt */
+/*global Services, InspectorUI, TILT_DESTROYED */
+"use strict";
+
+function test() {
+  if (!isTiltEnabled()) {
+    info("Skipping highlight test because Tilt isn't enabled.");
+    return;
+  }
+  if (!isWebGLSupported()) {
+    info("Skipping highlight test because WebGL isn't supported.");
+    return;
+  }
+
+  waitForExplicitFinish();
+
+  createTab(function() {
+    createTilt({
+      onTiltOpen: function(instance)
+      {
+        let presenter = instance.presenter;
+        let canvas = presenter.canvas;
+
+        presenter.onSetupMesh = function() {
+
+          presenter.highlightNodeAt(canvas.width / 2, canvas.height / 2, {
+            onpick: function()
+            {
+              ok(presenter._currentSelection > 0,
+                "Highlighting a node didn't work properly.");
+              ok(!presenter.highlight.disabled,
+                "After highlighting a node, it should be highlighted. D'oh.");
+
+              Services.obs.addObserver(cleanup, TILT_DESTROYED, false);
+              InspectorUI.closeInspectorUI();
+            }
+          });
+        };
+      }
+    });
+  });
+}
+
+function cleanup() {
+  Services.obs.removeObserver(cleanup, TILT_DESTROYED);
+  gBrowser.removeCurrentTab();
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/tilt/test/browser_tilt_picking_highlight03.js
@@ -0,0 +1,47 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/*global ok, is, info, waitForExplicitFinish, finish, gBrowser */
+/*global isTiltEnabled, isWebGLSupported, createTab, createTilt */
+/*global Services, InspectorUI, TILT_DESTROYED */
+"use strict";
+
+function test() {
+  if (!isTiltEnabled()) {
+    info("Skipping highlight test because Tilt isn't enabled.");
+    return;
+  }
+  if (!isWebGLSupported()) {
+    info("Skipping highlight test because WebGL isn't supported.");
+    return;
+  }
+
+  waitForExplicitFinish();
+
+  createTab(function() {
+    createTilt({
+      onTiltOpen: function(instance)
+      {
+        let presenter = instance.presenter;
+
+        presenter.onSetupMesh = function() {
+          presenter.highlightNodeFor(1);
+
+          ok(presenter._currentSelection > 0,
+            "Highlighting a node didn't work properly.");
+          ok(!presenter.highlight.disabled,
+            "After highlighting a node, it should be highlighted. D'oh.");
+
+          Services.obs.addObserver(cleanup, TILT_DESTROYED, false);
+          InspectorUI.closeInspectorUI();
+        };
+      }
+    });
+  });
+}
+
+function cleanup() {
+  Services.obs.removeObserver(cleanup, TILT_DESTROYED);
+  gBrowser.removeCurrentTab();
+  finish();
+}
--- a/browser/devtools/tilt/test/browser_tilt_zoom.js
+++ b/browser/devtools/tilt/test/browser_tilt_zoom.js
@@ -13,20 +13,21 @@ function setZoom(value) {
   gBrowser.selectedBrowser.markupDocumentViewer.fullZoom = value;
 }
 
 function getZoom() {
   return gBrowser.selectedBrowser.markupDocumentViewer.fullZoom;
 }
 
 function test() {
-  setZoom(Math.random());
+  TiltUtils.setDocumentZoom(Math.random());
   is(getZoom(), TiltUtils.getDocumentZoom(),
     "The getDocumentZoom utility function didn't return the expected results.");
 
+
   if (!isTiltEnabled()) {
     info("Skipping controller test because Tilt isn't enabled.");
     return;
   }
   if (!isWebGLSupported()) {
     info("Skipping controller test because WebGL isn't supported.");
     return;
   }
--- a/browser/devtools/webconsole/HUDService.jsm
+++ b/browser/devtools/webconsole/HUDService.jsm
@@ -1547,18 +1547,16 @@ HUD_SERVICE.prototype =
 
     let hudId = "hud_" + nBox.id;
     let hudRef = this.hudReferences[hudId];
 
     if (!aAnimated || hudRef.consolePanel) {
       this.disableAnimation(hudId);
     }
 
-    chromeDocument.getElementById("Tools:WebConsole").setAttribute("checked", "true");
-
     // Create a processing instruction for GCLIs CSS stylesheet, but only if
     // we don't have one for this document. Also record the context we're
     // adding this for so we know when to remove it.
     let procInstr = aContext.ownerDocument.gcliCssProcInstr;
     if (!procInstr) {
       procInstr = aContext.ownerDocument.createProcessingInstruction(
               "xml-stylesheet",
               "href='chrome://browser/skin/devtools/gcli.css' type='text/css'");
@@ -1598,18 +1596,16 @@ HUD_SERVICE.prototype =
       browser.webProgress.removeProgressListener(hud.progressListener);
       delete hud.progressListener;
 
       this.unregisterDisplay(hudId);
 
       window.focus();
     }
 
-    chromeDocument.getElementById("Tools:WebConsole").setAttribute("checked", "false");
-
     // Remove this context from the list of contexts that need the GCLI CSS
     // processing instruction and then remove the processing instruction if it
     // isn't needed any more.
     let procInstr = aContext.ownerDocument.gcliCssProcInstr;
     if (procInstr) {
       procInstr.contexts = procInstr.contexts.filter(function(id) {
         return id !== hudId;
       });
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -280,16 +280,17 @@
 @BINPATH@/components/fuelApplication.js
 @BINPATH@/components/WebContentConverter.js
 @BINPATH@/components/BrowserComponents.manifest
 @BINPATH@/components/nsBrowserContentHandler.js
 @BINPATH@/components/nsBrowserGlue.js
 @BINPATH@/components/nsSetDefaultBrowser.manifest
 @BINPATH@/components/nsSetDefaultBrowser.js
 @BINPATH@/components/BrowserPlaces.manifest
+@BINPATH@/components/BrowserPageThumbs.manifest
 @BINPATH@/components/nsPrivateBrowsingService.manifest
 @BINPATH@/components/nsPrivateBrowsingService.js
 @BINPATH@/components/toolkitsearch.manifest
 @BINPATH@/components/nsSearchService.js
 @BINPATH@/components/nsSearchSuggestions.js
 @BINPATH@/components/passwordmgr.manifest
 @BINPATH@/components/nsLoginInfo.js
 @BINPATH@/components/nsLoginManager.js
@@ -343,16 +344,17 @@
 @BINPATH@/components/toolkitplaces.manifest
 @BINPATH@/components/nsLivemarkService.js
 @BINPATH@/components/nsTaggingService.js
 @BINPATH@/components/nsPlacesAutoComplete.manifest
 @BINPATH@/components/nsPlacesAutoComplete.js
 @BINPATH@/components/nsPlacesExpiration.js
 @BINPATH@/components/PlacesProtocolHandler.js
 @BINPATH@/components/PlacesCategoriesStarter.js
+@BINPATH@/components/PageThumbsProtocol.js
 @BINPATH@/components/nsDefaultCLH.manifest
 @BINPATH@/components/nsDefaultCLH.js
 @BINPATH@/components/nsContentPrefService.manifest
 @BINPATH@/components/nsContentPrefService.js
 @BINPATH@/components/nsContentDispatchChooser.manifest
 @BINPATH@/components/nsContentDispatchChooser.js
 @BINPATH@/components/nsHandlerService.manifest
 @BINPATH@/components/nsHandlerService.js
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2527df6e72b5c80b91e180af9644ba96a5c148d6
GIT binary patch
literal 2552
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
O0000<MNUMnLSTaa5%5U>
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..389f689aa2a7611f53977594c048f79c4991affd
GIT binary patch
literal 1538
zc$@(O2L1VoP)<h;3K|Lk000e1NJLTq001BW001Ni1^@s6=<7J*00001b5ch_0Itp)
z=>Px#32;bRa{vGf6951U69E94oEQKA1*b_wK~z}7z1Lk#Q)e8<@o%-;l_RE+GhM_8
z&Z*1|BRcVpq)WWhXf)~+B`Co`d;xW!BVJ5kIGwy`!52``xw)t_CD}4`B+G6vOo(iX
zAqGoCN3E_gn~4eZ{GVOW9(rnfS}x{EPSW4gp8lWbJkL3wb8G-7F1F?XH@0n9?j>wH
zak13_tlYL?d9&;MH5F<v+O*OZFO$I5_>H^6-f+R4E27Q<y$u)K&cd7(UVw%RZik4v
z4rDf5a8DA^O$RHbEHi-X{I$7&8<-8)fMK8?SO=UGku1B2{xi@Aqyz28TYhi?!y@{1
zAQN~9v?`@)$J2ph=dPBDNEI+4tocn~9?%nNumRMaxjYs46_^9`0x!dgXYb5g<6#_I
z-I>dCfxE%t1Hjgud28D1&Ros{egobxbpYV#=}Y0AAXL00f1L-Qw)uNwh`Y9|wOM7Q
z)V<(H2a30@OAWQxG+pWdvcfxS4}H+}z%cM4?7J7iGXa2zm_})pm8kcEAJ>Q4zCQVF
zhv<?OdA95T)vgwYuAAokWoS)QyIP!OMVq}UqM%h4k%<6%Kh3!rYTI4#$<k=kWvi-h
zb^zhUvx6N7UlY##JGOWeT?5swmXYA#J}xWT+-~(-yXdkuym)zWz6YS9=5%(j6X`(i
zp@x<(LkE=>Znhn2Xi>4U9?<^)J_ODIDUn61>d!d#@5u85OeinTZxkiFMTt=ypu9NW
zD@w9O$-eU9{AwjaXb+w8SXqhWDG{YardQTBJ+7>6S_M#9+qAK=wrNO-JgKa0sxa2T
zfs%rw(N52Sk^(PKoyc_`o<HBUwd-KbslC8q;2q%V!J1QuGS-O#{xV&L|Ht;l(UVy~
zV{jVZ1pW@*A4(3C6m%IKNNe-w05={ibC?!dTASYitbDM{(VW)iH-`9NnZp(@C(^-p
ze|g?vPiyn%0%w8Vv^Kvp)QMp6>p*5&n|~4!mtEXE`XAO7=#phuy4ix%pPo8_VP(EA
zv?37}=n?mUh@ASPuT%vBiCK{99<sE+vtrt~ESTvYdc}f)71P>hx`$$0F!Rb_R0{@H
zr+9+j8*@CcI>ly{1q=%wu1+y5m~mw=wgqZ<#L@y4h<F~b$f91gVET8S4jBnVw_wJ(
zK8G3}iE6=&bA8T-xpTY(0_GzvvJy2B;PIx}h6Rt-r$)CR<@B9|EEvq6pRfhfn(rAF
z3~iZbZ2=>?$%4Vc3=cp`LyyUVl%~6e1%q4Px1}`QRk89&91EtNyyNf|%pbL2urQ-h
z>H2P^>qc>a!NLr$()Dbm>-z=^GpY&b7&~B<C7|a?Kvxpbr)#dB$C|5W6@cdI*{HdC
zh9sar(Of-a7ChR%FscQQwl5sBAkK9ko_$3Nx{~X<O%^2Ab%!t1*JHtynp-g~cvie<
z%mU5Tp99?R70og&G|koT09N{nW;JWBel<42S+;mNkq*Ay=;^R)u71M;&DHM=bs|{&
zI*_Tk`X>?j+#fHG{)eRnN+ipU5|ahm@%v6-7$s&4BHjy75%@&p<YV_sRif_&T793T
z1->0~#$`crecvk<Jl!#;J-NOwwgp;UZ&V9>JJUVE@5knNXS&TQiyE`w*{*cMf+@AV
zu`NK?EiD+&^FTBU97q4`5YeMspdGpGK%&1FXh&{4eR~#o<ITA#2QBdL$uKPNmwXW2
z0_|{DLKgV;W+rUG<gdC73!Z<rFpdRcelPHqE*_opL%*9W&<=MS7Wnoqv}uRCRjfR$
zi=_pVt8Y1;mn|B#z*oAs5hc4(ViX7Pl`i(8BpW6Be5H%4QG&6DPI-(hB6%XBL}YqW
zRp;ZRs?JpaNmZR2ld3w0MC3_QRp*!mzOp4zE%22sF)SF*8u(}bM_ox3H%%5KRoo0;
osISL@w<<bfTJUfA(k_7i0M-VmrtThlf&c&j07*qoM6N<$f_IMEO8@`>
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2527df6e72b5c80b91e180af9644ba96a5c148d6
GIT binary patch
literal 2552
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
O0000<MNUMnLSTaa5%5U>
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..75d6f13d8c6e6a1cfc0d5766cfec91378e0b60c0
GIT binary patch
literal 1568
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
Su_w;}0000<MNUMnLSTY9P~RW`
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2527df6e72b5c80b91e180af9644ba96a5c148d6
GIT binary patch
literal 2552
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
O0000<MNUMnLSTaa5%5U>
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..33bb4a320e76cc7a346ca4beb60e89a85a48aa2c
GIT binary patch
literal 1704
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
--- a/build/unix/build-toolchain/build-gcc.py
+++ b/build/unix/build-toolchain/build-gcc.py
@@ -93,17 +93,24 @@ def build_one_stage(env, stage_dir):
 
 def build_tar_package(tar, name, base, directory):
     name = os.path.realpath(name)
     run_in(base, [tar, "-cf", name, "--mtime=2012-01-01", "--owner=root",
                   directory])
 
 ##############################################
 
-source_dir = os.path.realpath('src')
+# The directories end up in the debug info, so the easy way of getting
+# a reproducible build is to run it in a know absolute directory.
+# We use a directory in /builds/slave because the mozilla infrastructure
+# cleans it up automatically.
+base_dir = "/builds/slave/moz-toolschain"
+
+source_dir = base_dir + "/src"
+build_dir  = base_dir + "/build"
 
 def build_source_dir(prefix, version):
     return source_dir + '/' + prefix + version
 
 binutils_version = "2.21.1"
 glibc_version = "2.13" #FIXME: should probably use 2.5.1
 tar_version = "1.26"
 gcc_version = "4.5.2"
@@ -128,44 +135,42 @@ mpc_source_uri = "http://www.multiprecis
 binutils_source_tar = download_uri(binutils_source_uri)
 glibc_source_tar = download_uri(glibc_source_uri)
 tar_source_tar = download_uri(tar_source_uri)
 mpc_source_tar = download_uri(mpc_source_uri)
 mpfr_source_tar = download_uri(mpfr_source_uri)
 gmp_source_tar = download_uri(gmp_source_uri)
 gcc_source_tar = download_uri(gcc_source_uri)
 
-build_dir = os.path.realpath('build')
-
 binutils_source_dir  = build_source_dir('binutils-', binutils_version)
 glibc_source_dir  = build_source_dir('glibc-', glibc_version)
 tar_source_dir  = build_source_dir('tar-', tar_version)
 mpc_source_dir  = build_source_dir('mpc-', mpc_version)
 mpfr_source_dir = build_source_dir('mpfr-', mpfr_version)
 gmp_source_dir  = build_source_dir('gmp-', gmp_version)
 gcc_source_dir  = build_source_dir('gcc-', gcc_version)
 
 if not os.path.exists(source_dir):
-    os.mkdir(source_dir)
+    os.makedirs(source_dir)
     extract(binutils_source_tar, source_dir)
     patch('binutils-deterministic.patch', 1, binutils_source_dir)
     extract(glibc_source_tar, source_dir)
     patch('glibc-deterministic.patch', 1, glibc_source_dir)
     extract(tar_source_tar, source_dir)
     extract(mpc_source_tar, source_dir)
     extract(mpfr_source_tar, source_dir)
     extract(gmp_source_tar, source_dir)
     extract(gcc_source_tar, source_dir)
     patch('plugin_finish_decl.diff', 0, gcc_source_dir)
     patch('pr49911.diff', 1, gcc_source_dir)
     patch('r159628-r163231-r171807.patch', 1, gcc_source_dir)
 
 if os.path.exists(build_dir):
     shutil.rmtree(build_dir)
-os.mkdir(build_dir)
+os.makedirs(build_dir)
 
 tar_inst_dir = build_dir + '/tar_inst'
 build_tar(build_dir, tar_inst_dir)
 
 stage1_dir = build_dir + '/stage1'
 build_one_stage({"CC": "gcc", "CXX" : "g++"}, stage1_dir)
 
 stage1_tool_inst_dir = stage1_dir + '/inst'
--- a/config/system-headers
+++ b/config/system-headers
@@ -263,16 +263,21 @@ frame/req.h
 freetype/freetype.h
 freetype/ftcache.h
 freetype/ftglyph.h
 freetype/ftsynth.h
 freetype/ftoutln.h
 freetype/ttnameid.h
 freetype/tttables.h
 freetype/t1tables.h
+freetype/ftlcdfil.h
+freetype/ftsizes.h
+freetype/ftadvanc.h
+freetype/ftbitmap.h
+freetype/ftxf86.h
 fribidi/fribidi.h
 FSp_fopen.h
 fstream
 fstream.h
 ft2build.h
 fts.h
 gconf/gconf-client.h
 Gdiplus.h
--- a/configure.in
+++ b/configure.in
@@ -332,16 +332,17 @@ if test -n "$gonkdir" ; then
         HOST_CXXFLAGS=" "
     fi
     if test -z "$HOST_LDFLAGS" ; then
         HOST_LDFLAGS=" "
     fi
 
     AC_DEFINE(ANDROID)
     AC_DEFINE(HAVE_SYS_UIO_H)
+    AC_DEFINE(HAVE_PTHREADS)
     CROSS_COMPILE=1
     MOZ_CHROME_FILE_FORMAT=omni
     ZLIB_DIR=yes
     direct_nspr_config=1
 else
 case "$target" in
 *-android*|*-linuxandroid*)
     if test -z "$android_ndk" ; then
@@ -8050,17 +8051,17 @@ fi
 AC_SUBST(GLIB_CFLAGS)
 AC_SUBST(GLIB_LIBS)
 AC_SUBST(GLIB_GMODULE_LIBS)
 
 dnl ========================================================
 dnl Graphics checks.
 dnl ========================================================
 
-if test "${OS_ARCH}" = "Darwin" -o "${MOZ_WIDGET_TOOLKIT}" = "android"; then
+if test "${OS_ARCH}" = "Darwin" -o "${MOZ_WIDGET_TOOLKIT}" = "android" -o "${MOZ_WIDGET_TOOLKIT}" = "gtk2"; then
 MOZ_ENABLE_SKIA=1
 else
 MOZ_ENABLE_SKIA=
 fi
 
 MOZ_ARG_ENABLE_BOOL(skia,
 [  --enable-skia   Enable use of Skia],
 MOZ_ENABLE_SKIA=1,
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -989,16 +989,18 @@ public:
    *
    * @param aNode The node for which to get the eventlistener manager.
    * @param aCreateIfNotFound If false, returns a listener manager only if
    *                          one already exists.
    */
   static nsEventListenerManager* GetListenerManager(nsINode* aNode,
                                                     bool aCreateIfNotFound);
 
+  static void UnmarkGrayJSListenersInCCGenerationDocuments(PRUint32 aGeneration);
+
   /**
    * Remove the eventlistener manager for aNode.
    *
    * @param aNode The node for which to remove the eventlistener manager.
    */
   static void RemoveListenerManager(nsINode *aNode);
 
   static bool IsInitialized()
@@ -2119,23 +2121,16 @@ public:
 #ifdef IS_BIG_ENDIAN
 #define DOUBLE_NaN {{DOUBLE_HI32_EXPMASK | DOUBLE_HI32_MANTMASK,   \
                         0xffffffff}}
 #else
 #define DOUBLE_NaN {{0xffffffff,                                         \
                         DOUBLE_HI32_EXPMASK | DOUBLE_HI32_MANTMASK}}
 #endif
 
-#if defined(XP_WIN)
-#define DOUBLE_COMPARE(LVAL, OP, RVAL)                                  \
-    (!DOUBLE_IS_NaN(LVAL) && !DOUBLE_IS_NaN(RVAL) && (LVAL) OP (RVAL))
-#else
-#define DOUBLE_COMPARE(LVAL, OP, RVAL) ((LVAL) OP (RVAL))
-#endif
-
 /*
  * In the following helper macros we exploit the fact that the result of a
  * series of additions will not be finite if any one of the operands in the
  * series is not finite.
  */
 #define NS_ENSURE_FINITE(f, rv)                                               \
   if (!NS_finite(f)) {                                                        \
     return (rv);                                                              \
--- a/content/base/public/nsIFrameMessageManager.idl
+++ b/content/base/public/nsIFrameMessageManager.idl
@@ -59,36 +59,37 @@ interface nsIFrameMessageListener : nsIS
    * if the message is synchronous, possible return value is sent back
    * as JSON.
    *
    * When the listener is called, 'this' value is the target of the message.
    */
   void receiveMessage();
 };
 
-[scriptable, uuid(a27d8fcd-8de9-4a51-87f4-2b83bba901d5)]
+[scriptable, builtinclass, uuid(9be42627-a5db-456f-8de2-9097da45a8c3)]
 interface nsIFrameMessageManager : nsISupports
 {
   void addMessageListener(in AString aMessage, in nsIFrameMessageListener aListener);
   void removeMessageListener(in AString aMessage, in nsIFrameMessageListener aListener);
   [implicit_jscontext,optional_argc]
   void sendAsyncMessage([optional] in AString messageName, [optional] in jsval obj);
+  [notxpcom] boolean markForCC();
 };
 
-[scriptable, uuid(21e5d940-d457-4c0f-bb5e-35c159ed19e3)]
+[scriptable, builtinclass, uuid(28a36ac7-2868-4fa0-ae24-be957d7dce10)]
 interface nsISyncMessageSender : nsIFrameMessageManager
 {
   /**
    * Returns an array of JSON objects.
    */
   [implicit_jscontext,optional_argc]
   jsval sendSyncMessage([optional] in AString messageName, [optional] in jsval obj);
 };
 
-[scriptable, uuid(78a1d024-60e3-4b7b-98cd-4c6b84b4f060)]
+[scriptable, builtinclass, uuid(a83f4393-e3cf-44da-8867-1f9174c2c595)]
 interface nsIContentFrameMessageManager : nsISyncMessageSender
 {
   /**
    * The current top level window in the frame or null.
    */
   readonly attribute nsIDOMWindow content;
 
   /**
@@ -109,30 +110,30 @@ interface nsIContentFrameMessageManager 
 
    /**
     * Ascii base64 data to binary data and vice versa
     */
    DOMString atob(in DOMString aAsciiString);
    DOMString btoa(in DOMString aBase64Data);
 };
 
-[uuid(1f7af930-a232-4a84-a049-73eaa45f2db5)]
+[uuid(f0936c56-e92c-4927-a85b-e289c3d4a01c)]
 interface nsIInProcessContentFrameMessageManager : nsIContentFrameMessageManager
 {
   [notxpcom] nsIContent getOwnerContent();
 };
 
-[scriptable, uuid(e91b0939-a74a-4c4f-8cfd-17dd42e8642a)]
+[scriptable, builtinclass, uuid(09f79e8c-101b-432b-a494-02f9b5e111c0)]
 interface nsITreeItemFrameMessageManager : nsIFrameMessageManager
 {
   readonly attribute unsigned long childCount;
   nsITreeItemFrameMessageManager getChildAt(in unsigned long aIndex);
 };
 
-[scriptable, uuid(14e1f147-793d-4788-bbbb-ae806ecdddbb)]
+[scriptable, builtinclass, uuid(a51597f0-d669-4260-83e6-1d426a8ac802)]
 interface nsIChromeFrameMessageManager : nsITreeItemFrameMessageManager
 {
   /**
    * Load a script in the (remote) frame. aURL must be the absolute URL.
    * data: URLs are also supported. For example data:,dump("foo\n");
    * If aAllowDelayedLoad is true, script will be loaded when the
    * remote frame becomes available. Otherwise the script will be loaded
    * only if the frame is already available.
--- a/content/base/src/nsCCUncollectableMarker.h
+++ b/content/base/src/nsCCUncollectableMarker.h
@@ -46,21 +46,25 @@ class nsCCUncollectableMarker : public n
   /**
    * Inits a global nsCCUncollectableMarker. Should only be called once.
    */
   static nsresult Init();
 
   /**
    * Checks if we're collecting during a given generation
    */
+  static bool InGeneration(PRUint32 aGeneration)
+  {
+    return aGeneration && aGeneration == sGeneration;
+  }
+
   static bool InGeneration(nsCycleCollectionTraversalCallback &cb,
-                             PRUint32 aGeneration) {
-    return !cb.WantAllTraces() &&
-           aGeneration &&
-           aGeneration == sGeneration;
+                           PRUint32 aGeneration)
+  {
+    return InGeneration(aGeneration) && !cb.WantAllTraces();
   }
 
   static PRUint32 sGeneration;
 
 private:
   nsCCUncollectableMarker() {}
 
 };
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -201,17 +201,17 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_
 #include "nsContentDLF.h"
 #ifdef MOZ_MEDIA
 #include "nsHTMLMediaElement.h"
 #endif
 #include "nsDOMTouchEvent.h"
 #include "nsIScriptElement.h"
 #include "nsIContentViewer.h"
 #include "nsIObjectLoadingContent.h"
-
+#include "nsCCUncollectableMarker.h"
 #include "mozilla/Base64.h"
 #include "mozilla/Preferences.h"
 
 #include "nsWrapperCacheInlines.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsUnicharUtils.h"
 
 using namespace mozilla::dom;
@@ -3385,16 +3385,42 @@ nsContentUtils::MaybeFireNodeRemoved(nsI
     nsMutationEvent mutation(true, NS_MUTATION_NODEREMOVED);
     mutation.mRelatedNode = do_QueryInterface(aParent);
 
     mozAutoSubtreeModified subtree(aOwnerDoc, aParent);
     nsEventDispatcher::Dispatch(aChild, nsnull, &mutation);
   }
 }
 
+PLDHashOperator
+ListenerEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aEntry,
+                   PRUint32 aNumber, void* aArg)
+{
+  PRUint32* gen = static_cast<PRUint32*>(aArg);
+  EventListenerManagerMapEntry* entry =
+    static_cast<EventListenerManagerMapEntry*>(aEntry);
+  if (entry) {
+    nsINode* n = static_cast<nsINode*>(entry->mListenerManager->GetTarget());
+    if (n && n->IsInDoc() &&
+        nsCCUncollectableMarker::InGeneration(n->OwnerDoc()->GetMarkedCCGeneration())) {
+      entry->mListenerManager->UnmarkGrayJSListeners();
+    }
+  }
+  return PL_DHASH_NEXT;
+}
+
+void
+nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments(PRUint32 aGeneration)
+{
+  if (sEventListenerManagersHash.ops) {
+    PL_DHashTableEnumerate(&sEventListenerManagersHash, ListenerEnumerator,
+                           &aGeneration);
+  }
+}
+
 /* static */
 void
 nsContentUtils::TraverseListenerManager(nsINode *aNode,
                                         nsCycleCollectionTraversalCallback &cb)
 {
   if (!sEventListenerManagersHash.ops) {
     // We're already shut down, just return.
     return;
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -68,16 +68,17 @@
 #include "mozilla/css/Loader.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIScriptRuntime.h"
 #include "nsCOMArray.h"
 
 #include "nsGUIEvent.h"
 #include "nsAsyncDOMEvent.h"
+#include "nsIDOMNodeFilter.h"
 
 #include "nsIDOMStyleSheet.h"
 #include "nsDOMAttribute.h"
 #include "nsIDOMDOMStringList.h"
 #include "nsIDOMDOMImplementation.h"
 #include "nsIDOMDocumentXBL.h"
 #include "mozilla/FunctionTimer.h"
 #include "nsGenericElement.h"
@@ -5019,67 +5020,73 @@ nsDocument::CreateRange(nsIDOMRange** aR
   range.forget(aReturn);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocument::CreateNodeIterator(nsIDOMNode *aRoot,
                                PRUint32 aWhatToShow,
                                nsIDOMNodeFilter *aFilter,
-                               bool aEntityReferenceExpansion,
+                               PRUint8 aOptionalArgc,
                                nsIDOMNodeIterator **_retval)
 {
   *_retval = nsnull;
 
+  if (!aOptionalArgc) {
+    aWhatToShow = nsIDOMNodeFilter::SHOW_ALL;
+  }
+
   if (!aRoot)
     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
 
   nsresult rv = nsContentUtils::CheckSameOrigin(this, aRoot);
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ENSURE_ARG_POINTER(_retval);
 
   nsCOMPtr<nsINode> root = do_QueryInterface(aRoot);
   NS_ENSURE_TRUE(root, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
 
   nsNodeIterator *iterator = new nsNodeIterator(root,
                                                 aWhatToShow,
-                                                aFilter,
-                                                aEntityReferenceExpansion);
+                                                aFilter);
   NS_ENSURE_TRUE(iterator, NS_ERROR_OUT_OF_MEMORY);
 
   NS_ADDREF(*_retval = iterator);
 
-  return NS_OK; 
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocument::CreateTreeWalker(nsIDOMNode *aRoot,
                              PRUint32 aWhatToShow,
                              nsIDOMNodeFilter *aFilter,
-                             bool aEntityReferenceExpansion,
+                             PRUint8 aOptionalArgc,
                              nsIDOMTreeWalker **_retval)
 {
   *_retval = nsnull;
 
+  if (!aOptionalArgc) {
+    aWhatToShow = nsIDOMNodeFilter::SHOW_ALL;
+  }
+
   if (!aRoot)
     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
 
   nsresult rv = nsContentUtils::CheckSameOrigin(this, aRoot);
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ENSURE_ARG_POINTER(_retval);
 
   nsCOMPtr<nsINode> root = do_QueryInterface(aRoot);
   NS_ENSURE_TRUE(root, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
 
   nsTreeWalker* walker = new nsTreeWalker(root,
                                           aWhatToShow,
-                                          aFilter,
-                                          aEntityReferenceExpansion);
+                                          aFilter);
   NS_ENSURE_TRUE(walker, NS_ERROR_OUT_OF_MEMORY);
 
   NS_ADDREF(*_retval = walker);
 
   return NS_OK;
 }
 
 
--- a/content/base/src/nsEventSource.cpp
+++ b/content/base/src/nsEventSource.cpp
@@ -58,16 +58,17 @@
 #include "nsIScriptError.h"
 #include "nsICharsetConverterManager.h"
 #include "nsIChannelPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsContentUtils.h"
 #include "mozilla/Preferences.h"
 #include "xpcpublic.h"
 #include "nsCrossSiteListenerProxy.h"
+#include "nsWrapperCacheInlines.h"
 
 using namespace mozilla;
 
 #define REPLACEMENT_CHAR     (PRUnichar)0xFFFD
 #define BOM_CHAR             (PRUnichar)0xFEFF
 #define SPACE_CHAR           (PRUnichar)0x0020
 #define CR_CHAR              (PRUnichar)0x000D
 #define LF_CHAR              (PRUnichar)0x000A
@@ -100,16 +101,40 @@ nsEventSource::~nsEventSource()
 }
 
 //-----------------------------------------------------------------------------
 // nsEventSource::nsISupports
 //-----------------------------------------------------------------------------
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsEventSource)
 
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsEventSource)
+  if (tmp->IsBlack()) {
+    if (tmp->mListenerManager) {
+      tmp->mListenerManager->UnmarkGrayJSListeners();
+      NS_UNMARK_LISTENER_WRAPPER(Open)
+      NS_UNMARK_LISTENER_WRAPPER(Message)
+      NS_UNMARK_LISTENER_WRAPPER(Error)
+    }
+    return true;
+  }
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsEventSource)
+  return tmp->IsBlack();
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsEventSource)
+  return tmp->IsBlack();
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(nsEventSource,
+                                               nsDOMEventTargetWrapperCache)
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsEventSource,
                                                   nsDOMEventTargetWrapperCache)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSrc)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mNotificationCallbacks)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLoadGroup)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChannelEventSink)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mHttpChannel)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTimer)
--- a/content/base/src/nsEventSource.h
+++ b/content/base/src/nsEventSource.h
@@ -79,18 +79,18 @@ class nsEventSource: public nsDOMEventTa
                      public nsSupportsWeakReference
 {
 friend class AsyncVerifyRedirectCallbackFwr;
 
 public:
   nsEventSource();
   virtual ~nsEventSource();
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsEventSource,
-                                           nsDOMEventTargetWrapperCache)
+  NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_INHERITED(nsEventSource,
+                                                                   nsDOMEventTargetWrapperCache)
 
   NS_DECL_NSIEVENTSOURCE
 
   // nsIJSNativeInitializer
   NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* cx, JSObject* obj,
                         PRUint32 argc, jsval* argv);
 
   NS_DECL_NSIOBSERVER
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -1105,8 +1105,20 @@ NS_NewChildProcessMessageManager(nsISync
                                                         nsnull,
                                                         nsnull,
                                                         false,
                                                         true);
   NS_ENSURE_TRUE(mm, NS_ERROR_OUT_OF_MEMORY);
   nsFrameMessageManager::sChildProcessManager = mm;
   return CallQueryInterface(mm, aResult);
 }
+
+bool
+nsFrameMessageManager::MarkForCC()
+{
+  PRUint32 len = mListeners.Length();
+  for (PRUint32 i = 0; i < len; ++i) {
+    nsCOMPtr<nsIXPConnectWrappedJS> wjs =
+      do_QueryInterface(mListeners[i].mListener);
+    xpc_UnmarkGrayObject(wjs);
+  }
+  return true;
+}
--- a/content/base/src/nsFrameMessageManager.h
+++ b/content/base/src/nsFrameMessageManager.h
@@ -151,16 +151,17 @@ public:
                        bool aLoadScripts = true);
   void RemoveChildManager(nsFrameMessageManager* aManager)
   {
     mChildManagers.RemoveObject(aManager);
   }
 
   void Disconnect(bool aRemoveFromParent = true);
   void SetCallbackData(void* aData, bool aLoadScripts = true);
+  void* GetCallbackData() { return mCallbackData; }
   void GetParamsForMessage(const jsval& aObject,
                            JSContext* aCx,
                            nsAString& aJSON);
   nsresult SendAsyncMessageInternal(const nsAString& aMessage,
                                     const nsAString& aJSON);
   JSContext* GetJSContext() { return mContext; }
   void SetJSContext(JSContext* aCx) { mContext = aCx; }
   void RemoveFromParent();
--- a/content/base/src/nsImageLoadingContent.cpp
+++ b/content/base/src/nsImageLoadingContent.cpp
@@ -55,16 +55,17 @@
 #include "nsContentPolicyUtils.h"
 #include "nsIURI.h"
 #include "nsILoadGroup.h"
 #include "imgIContainer.h"
 #include "imgILoader.h"
 #include "nsThreadUtils.h"
 #include "nsNetUtil.h"
 #include "nsAsyncDOMEvent.h"
+#include "nsGenericHTMLElement.h"
 
 #include "nsIPresShell.h"
 #include "nsEventStates.h"
 #include "nsGUIEvent.h"
 
 #include "nsIChannel.h"
 #include "nsIStreamListener.h"
 
@@ -769,19 +770,19 @@ nsImageLoadingContent::LoadImage(nsIURI*
   if (!NS_CP_ACCEPTED(cpDecision)) {
     FireEvent(NS_LITERAL_STRING("error"));
     SetBlockedRequest(aNewURI, cpDecision);
     return NS_OK;
   }
 
   nsLoadFlags loadFlags = aLoadFlags;
   PRInt32 corsmode = GetCORSMode();
-  if (corsmode == nsImageLoadingContent::CORS_ANONYMOUS) {
+  if (corsmode == nsGenericHTMLElement::CORS_ANONYMOUS) {
     loadFlags |= imgILoader::LOAD_CORS_ANONYMOUS;
-  } else if (corsmode == nsImageLoadingContent::CORS_USE_CREDENTIALS) {
+  } else if (corsmode == nsGenericHTMLElement::CORS_USE_CREDENTIALS) {
     loadFlags |= imgILoader::LOAD_CORS_USE_CREDENTIALS;
   }
 
   // Not blocked. Do the load.
   nsCOMPtr<imgIRequest>& req = PrepareNextRequest();
   nsresult rv;
   rv = nsContentUtils::LoadImage(aNewURI, aDocument,
                                  aDocument->NodePrincipal(),
@@ -1181,13 +1182,13 @@ nsImageLoadingContent::CreateStaticImage
   aDest->mStateChangerDepth = mStateChangerDepth;
   aDest->mIsImageStateForced = mIsImageStateForced;
   aDest->mLoading = mLoading;
   aDest->mBroken = mBroken;
   aDest->mUserDisabled = mUserDisabled;
   aDest->mSuppressed = mSuppressed;
 }
 
-nsImageLoadingContent::CORSMode
+nsGenericHTMLElement::CORSMode
 nsImageLoadingContent::GetCORSMode()
 {
-  return CORS_NONE;
+  return nsGenericHTMLElement::CORS_NONE;
 }
--- a/content/base/src/nsImageLoadingContent.h
+++ b/content/base/src/nsImageLoadingContent.h
@@ -48,16 +48,17 @@
 #include "nsIImageLoadingContent.h"
 #include "nsINode.h"
 #include "imgIRequest.h"
 #include "prtypes.h"
 #include "nsCOMPtr.h"
 #include "nsContentUtils.h" // NS_CONTENT_DELETE_LIST_MEMBER
 #include "nsString.h"
 #include "nsEventStates.h"
+#include "nsGenericHTMLElement.h"
 
 class nsIURI;
 class nsIDocument;
 class imgILoader;
 class nsIIOService;
 
 class nsImageLoadingContent : public nsIImageLoadingContent
 {
@@ -65,35 +66,16 @@ class nsImageLoadingContent : public nsI
 public:
   nsImageLoadingContent();
   virtual ~nsImageLoadingContent();
 
   NS_DECL_IMGICONTAINEROBSERVER
   NS_DECL_IMGIDECODEROBSERVER
   NS_DECL_NSIIMAGELOADINGCONTENT
 
-  enum CORSMode {
-    /**
-     * The default of not using CORS to validate cross-origin loads.
-     */
-    CORS_NONE,
-
-    /**
-     * Validate cross-site loads using CORS, but do not send any credentials
-     * (cookies, HTTP auth logins, etc) along with the request.
-     */
-    CORS_ANONYMOUS,
-
-    /**
-     * Validate cross-site loads using CORS, and send credentials such as cookies
-     * and HTTP auth logins along with the request.
-     */
-    CORS_USE_CREDENTIALS
-  };
-
 protected:
   /**
    * LoadImage is called by subclasses when the appropriate
    * attributes (eg 'src' for <img> tags) change.  The string passed
    * in is the new uri string; this consolidates the code for getting
    * the charset, constructing URI objects, and any other incidentals
    * into this superclass.   
    *
@@ -196,17 +178,17 @@ protected:
   // Sets blocking state only if the desired state is different from the
   // current one. See the comment for mBlockingOnload for more information.
   void SetBlockingOnload(bool aBlocking);
 
   /**
    * Returns the CORS mode that will be used for all future image loads. The
    * default implementation returns CORS_NONE unconditionally.
    */
-  virtual CORSMode GetCORSMode();
+  virtual nsGenericHTMLElement::CORSMode GetCORSMode();
 
 private:
   /**
    * Struct used to manage the image observers.
    */
   struct ImageObserver {
     ImageObserver(imgIDecoderObserver* aObserver) :
       mObserver(aObserver),
--- a/content/base/src/nsNodeIterator.cpp
+++ b/content/base/src/nsNodeIterator.cpp
@@ -165,19 +165,18 @@ void nsNodeIterator::NodePointer::MoveBa
 }
 
 /*
  * Factories, constructors and destructors
  */
 
 nsNodeIterator::nsNodeIterator(nsINode *aRoot,
                                PRUint32 aWhatToShow,
-                               nsIDOMNodeFilter *aFilter,
-                               bool aExpandEntityReferences) :
-    nsTraversal(aRoot, aWhatToShow, aFilter, aExpandEntityReferences),
+                               nsIDOMNodeFilter *aFilter) :
+    nsTraversal(aRoot, aWhatToShow, aFilter),
     mDetached(false),
     mPointer(mRoot, true)
 {
     aRoot->AddMutationObserver(this);
 }
 
 nsNodeIterator::~nsNodeIterator()
 {
@@ -242,17 +241,17 @@ NS_IMETHODIMP nsNodeIterator::GetFilter(
     NS_IF_ADDREF(*aFilter = mFilter);
 
     return NS_OK;
 }
 
 /* readonly attribute boolean expandEntityReferences; */
 NS_IMETHODIMP nsNodeIterator::GetExpandEntityReferences(bool *aExpandEntityReferences)
 {
-    *aExpandEntityReferences = mExpandEntityReferences;
+    *aExpandEntityReferences = false;
     return NS_OK;
 }
 
 /* nsIDOMNode nextNode ()  raises (DOMException); */
 NS_IMETHODIMP nsNodeIterator::NextNode(nsIDOMNode **_retval)
 {
     return NextOrPrevNode(&NodePointer::MoveToNext, _retval);
 }
--- a/content/base/src/nsNodeIterator.h
+++ b/content/base/src/nsNodeIterator.h
@@ -58,18 +58,17 @@ class nsNodeIterator : public nsIDOMNode
                        public nsStubMutationObserver2
 {
 public:
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_NSIDOMNODEITERATOR
 
     nsNodeIterator(nsINode *aRoot,
                    PRUint32 aWhatToShow,
-                   nsIDOMNodeFilter *aFilter,
-                   bool aExpandEntityReferences);
+                   nsIDOMNodeFilter *aFilter);
     virtual ~nsNodeIterator();
 
     NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
     NS_DECL_NSIMUTATIONOBSERVER2_ATTRIBUTECHILDREMOVED
 
     NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsNodeIterator, nsIDOMNodeIterator)
 
 private:
--- a/content/base/src/nsTraversal.cpp
+++ b/content/base/src/nsTraversal.cpp
@@ -44,22 +44,20 @@
 #include "nsDOMError.h"
 
 #include "nsIContent.h"
 
 #include "nsGkAtoms.h"
 
 nsTraversal::nsTraversal(nsINode *aRoot,
                          PRUint32 aWhatToShow,
-                         nsIDOMNodeFilter *aFilter,
-                         bool aExpandEntityReferences) :
+                         nsIDOMNodeFilter *aFilter) :
     mRoot(aRoot),
     mWhatToShow(aWhatToShow),
     mFilter(aFilter),
-    mExpandEntityReferences(aExpandEntityReferences),
     mInAcceptNode(false)
 {
     NS_ASSERTION(aRoot, "invalid root in call to nsTraversal constructor");
 }
 
 nsTraversal::~nsTraversal()
 {
     /* destructor code */
--- a/content/base/src/nsTraversal.h
+++ b/content/base/src/nsTraversal.h
@@ -49,25 +49,23 @@
 class nsINode;
 class nsIDOMNodeFilter;
 
 class nsTraversal
 {
 public:
     nsTraversal(nsINode *aRoot,
                 PRUint32 aWhatToShow,
-                nsIDOMNodeFilter *aFilter,
-                bool aExpandEntityReferences);
+                nsIDOMNodeFilter *aFilter);
     virtual ~nsTraversal();
 
 protected:
     nsCOMPtr<nsINode> mRoot;
     PRUint32 mWhatToShow;
     nsCOMPtr<nsIDOMNodeFilter> mFilter;
-    bool mExpandEntityReferences;
     bool mInAcceptNode;
 
     /*
      * Tests if and how a node should be filtered. Uses mWhatToShow and
      * mFilter to test the node.
      * @param aNode     Node to test
      * @param _filtered Returned filtervalue. See nsIDOMNodeFilter.idl
      * @returns         Errorcode
--- a/content/base/src/nsTreeWalker.cpp
+++ b/content/base/src/nsTreeWalker.cpp
@@ -53,19 +53,18 @@
 #include "nsContentUtils.h"
 
 /*
  * Factories, constructors and destructors
  */
 
 nsTreeWalker::nsTreeWalker(nsINode *aRoot,
                            PRUint32 aWhatToShow,
-                           nsIDOMNodeFilter *aFilter,
-                           bool aExpandEntityReferences) :
-    nsTraversal(aRoot, aWhatToShow, aFilter, aExpandEntityReferences),
+                           nsIDOMNodeFilter *aFilter) :
+    nsTraversal(aRoot, aWhatToShow, aFilter),
     mCurrentNode(aRoot)
 {
 }
 
 nsTreeWalker::~nsTreeWalker()
 {
     /* destructor code */
 }
@@ -122,17 +121,17 @@ NS_IMETHODIMP nsTreeWalker::GetFilter(ns
 
     return NS_OK;
 }
 
 /* readonly attribute boolean expandEntityReferences; */
 NS_IMETHODIMP
 nsTreeWalker::GetExpandEntityReferences(bool *aExpandEntityReferences)
 {
-    *aExpandEntityReferences = mExpandEntityReferences;
+    *aExpandEntityReferences = false;
     return NS_OK;
 }
 
 /* attribute nsIDOMNode currentNode; */
 NS_IMETHODIMP nsTreeWalker::GetCurrentNode(nsIDOMNode * *aCurrentNode)
 {
     if (mCurrentNode) {
         return CallQueryInterface(mCurrentNode, aCurrentNode);
--- a/content/base/src/nsTreeWalker.h
+++ b/content/base/src/nsTreeWalker.h
@@ -58,18 +58,17 @@ class nsIDOMNodeFilter;
 class nsTreeWalker : public nsIDOMTreeWalker, public nsTraversal
 {
 public:
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_NSIDOMTREEWALKER
 
     nsTreeWalker(nsINode *aRoot,
                  PRUint32 aWhatToShow,
-                 nsIDOMNodeFilter *aFilter,
-                 bool aExpandEntityReferences);
+                 nsIDOMNodeFilter *aFilter);
     virtual ~nsTreeWalker();
 
     NS_DECL_CYCLE_COLLECTION_CLASS(nsTreeWalker)
 
 private:
     nsCOMPtr<nsINode> mCurrentNode;
 
     /*
--- a/content/base/src/nsWebSocket.cpp
+++ b/content/base/src/nsWebSocket.cpp
@@ -77,16 +77,17 @@
 #include "mozilla/Preferences.h"
 #include "nsDOMLists.h"
 #include "xpcpublic.h"
 #include "nsContentPolicyUtils.h"
 #include "nsContentErrors.h"
 #include "jstypedarray.h"
 #include "prmem.h"
 #include "nsDOMFile.h"
+#include "nsWrapperCacheInlines.h"
 
 using namespace mozilla;
 
 #define UTF_8_REPLACEMENT_CHAR    static_cast<PRUnichar>(0xFFFD)
 
 #define TRUE_OR_FAIL_WEBSOCKET(x, ret)                                    \
   PR_BEGIN_MACRO                                                          \
     if (NS_UNLIKELY(!(x))) {                                              \
@@ -424,16 +425,41 @@ nsWebSocket::~nsWebSocket()
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
 
   Disconnect();
   nsLayoutStatics::Release();
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsWebSocket)
 
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsWebSocket)
+  if (tmp->IsBlack()) {
+    if (tmp->mListenerManager) {
+      tmp->mListenerManager->UnmarkGrayJSListeners();
+      NS_UNMARK_LISTENER_WRAPPER(Open)
+      NS_UNMARK_LISTENER_WRAPPER(Error)
+      NS_UNMARK_LISTENER_WRAPPER(Message)
+      NS_UNMARK_LISTENER_WRAPPER(Close)
+    }
+    return true;
+  }
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsWebSocket)
+  return tmp->IsBlack();
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsWebSocket)
+  return tmp->IsBlack();
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(nsWebSocket,
+                                               nsDOMEventTargetWrapperCache)
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsWebSocket,
                                                   nsDOMEventTargetWrapperCache)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnOpenListener)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnMessageListener)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnCloseListener)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnErrorListener)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mPrincipal)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mURI)
--- a/content/base/src/nsWebSocket.h
+++ b/content/base/src/nsWebSocket.h
@@ -78,18 +78,18 @@ class nsWebSocket: public nsDOMEventTarg
 {
 friend class nsWSCloseEvent;
 friend class nsAutoCloseWS;
 
 public:
   nsWebSocket();
   virtual ~nsWebSocket();
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsWebSocket,
-                                           nsDOMEventTargetWrapperCache)
+  NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_INHERITED(nsWebSocket,
+                                                                   nsDOMEventTargetWrapperCache)
   NS_DECL_NSIWEBSOCKET
   NS_DECL_NSIINTERFACEREQUESTOR
   NS_DECL_NSIWEBSOCKETLISTENER
   NS_DECL_NSIREQUEST
 
   // nsIJSNativeInitializer
   NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* aContext,
                         JSObject* aObject, PRUint32 aArgc, jsval* aArgv);
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -100,16 +100,17 @@
 #include "nsIContentSecurityPolicy.h"
 #include "nsAsyncRedirectVerifyHelper.h"
 #include "jstypedarray.h"
 #include "nsStringBuffer.h"
 #include "nsDOMFile.h"
 #include "nsIFileChannel.h"
 #include "mozilla/Telemetry.h"
 #include "sampler.h"
+#include "nsWrapperCacheInlines.h"
 
 using namespace mozilla;
 
 #define LOAD_STR "load"
 #define ERROR_STR "error"
 #define ABORT_STR "abort"
 #define LOADSTART_STR "loadstart"
 #define PROGRESS_STR "progress"
@@ -573,16 +574,41 @@ nsXMLHttpRequest::ResetResponse()
 void
 nsXMLHttpRequest::SetRequestObserver(nsIRequestObserver* aObserver)
 {
   mRequestObserver = aObserver;
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLHttpRequest)
 
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsXMLHttpRequest)
+  if (tmp->IsBlack()) {
+    if (tmp->mListenerManager) {
+      tmp->mListenerManager->UnmarkGrayJSListeners();
+      NS_UNMARK_LISTENER_WRAPPER(Load)
+      NS_UNMARK_LISTENER_WRAPPER(Error)
+      NS_UNMARK_LISTENER_WRAPPER(Abort)
+      NS_UNMARK_LISTENER_WRAPPER(LoadStart)
+      NS_UNMARK_LISTENER_WRAPPER(Progress)
+      NS_UNMARK_LISTENER_WRAPPER(Loadend)
+      NS_UNMARK_LISTENER_WRAPPER(UploadProgress)
+      NS_UNMARK_LISTENER_WRAPPER(Readystatechange)
+    }
+    return true;
+  }
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsXMLHttpRequest)
+  return tmp->IsBlack();
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsXMLHttpRequest)
+  return tmp->IsBlack();
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
+
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLHttpRequest,
                                                   nsXHREventTarget)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChannel)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mReadRequest)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mResponseXML)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCORSPreflightChannel)
 
--- a/content/base/src/nsXMLHttpRequest.h
+++ b/content/base/src/nsXMLHttpRequest.h
@@ -194,18 +194,18 @@ public:
   // "uploadprogress" as needed.
   void MaybeDispatchProgressEvents(bool aFinalProgress);
 
   // This is called by the factory constructor.
   nsresult Init();
 
   void SetRequestObserver(nsIRequestObserver* aObserver);
 
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(nsXMLHttpRequest,
-                                           nsXHREventTarget)
+  NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_INHERITED(nsXMLHttpRequest,
+                                                                   nsXHREventTarget)
   bool AllowUploadProgress();
   void RootResultArrayBuffer();
   
 protected:
   friend class nsMultipartProxyListener;
 
   nsresult DetectCharset();
   nsresult AppendToResponseText(const char * aBuffer, PRUint32 aBufferLen);
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -537,16 +537,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug707142.html \
 		file_bug707142_baseline.json \
 		file_bug707142_bom.json \
 		file_bug707142_utf-16.json \
 		test_reentrant_flush.html \
 		test_bug708620.html \
 		file_bug708620.html \
 		file_bug708620-2.html \
+		test_bug698384.html \
 		$(NULL)
 
 _CHROME_FILES =	\
 		test_bug357450.js \
 		$(NULL)
 
 # This test fails on the Mac for some reason
 ifneq (,$(filter gtk2 windows,$(MOZ_WIDGET_TOOLKIT)))
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug698384.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+  <!--
+    https://bugzilla.mozilla.org/show_bug.cgi?id=698384
+  -->
+  <head>
+    <title>Test for Bug 698384</title>
+    <script type="text/javascript"
+      src="/tests/SimpleTest/SimpleTest.js"></script>
+    <script src="/tests/SimpleTest/EventUtils.js"
+      type="text/javascript"></script>
+    <link rel="stylesheet" type="text/css"
+      href="/tests/SimpleTest/test.css" />
+  </head>
+  <body onload="runTests();">
+    <a target="_blank"
+      href="https://bugzilla.mozilla.org/show_bug.cgi?id=698384">
+      Mozilla Bug 698384</a>
+    <p id="display"></p>
+    <div id="content" style="display: none"></div>
+    <pre id="test">
+      <script type="text/javascript">
+        /*
+          Checks to see if default parameter handling is correct when 0, 1
+          or 2 parameters are passed.
+
+          If one is only passed, aFilter should default to null
+          If none are passed, aFilter should be null and aWhatToShow should
+          be NodeFilter.SHOW_ALL
+        */
+        SimpleTest.waitForExplicitFinish();
+
+        var content = $('content'),
+            ni;
+
+        content.innerHTML = ('<span id="A"><\/span><span id="B"><\/span>'
+          + '<span id="C"><\/span>');
+
+        function runTests() {
+
+          // Test NodeIterator when no optional arguments are given
+          ni = document.createNodeIterator(content);
+          is(ni.whatToShow, NodeFilter.SHOW_ALL, "whatToShow should be " +
+            "NodeFilter.SHOW_ALL when both " +
+            " optionals are not given");
+          is(ni.filter, null, "filter should be defaulted to null when both " +
+            " optionals are not given");
+
+          // Test NodeIterator when first optional is passed
+          ni = document.createNodeIterator(content, NodeFilter.SHOW_ELEMENT);
+          is(ni.filter, null, "filter should be defaulted to null when only " +
+            " first argument is passed");
+          is(ni.whatToShow, NodeFilter.SHOW_ELEMENT, "whatToShow should " +
+            "properly be set to NodeFilter.SHOW_ELEMENT when whatToShow is " +
+            "provided and filter is not");
+
+          SimpleTest.finish();
+        }
+      </script>
+    </pre>
+  </body>
+</html>
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -3945,17 +3945,17 @@ WebGLContext::DOMElementToImageSurface(n
         nsLayoutUtils::SurfaceFromElement(content->AsElement(), flags);
     if (!res.mSurface)
         return NS_ERROR_FAILURE;
     if (res.mSurface->GetType() != gfxASurface::SurfaceTypeImage) {
         // SurfaceFromElement lied!
         return NS_ERROR_FAILURE;
     }
 
-    // We disallow loading cross-domain images that have not been validated
+    // We disallow loading cross-domain images and videos that have not been validated
     // with CORS as WebGL textures. The reason for doing that is that timing
     // attacks on WebGL shaders are able to retrieve approximations of the
     // pixel values in WebGL textures; see bug 655987.
     //
     // To prevent a loophole where a Canvas2D would be used as a proxy to load
     // cross-domain textures, we also disallow loading textures from write-only
     // Canvas2D's.
 
--- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
@@ -990,17 +990,17 @@ NS_NewCanvasRenderingContext2DAzure(nsID
 {
 #ifdef XP_WIN
   if ((gfxWindowsPlatform::GetPlatform()->GetRenderMode() !=
       gfxWindowsPlatform::RENDER_DIRECT2D ||
       !gfxWindowsPlatform::GetPlatform()->DWriteEnabled()) &&
       !Preferences::GetBool("gfx.canvas.azure.prefer-skia", false)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
-#elif !defined(XP_MACOSX) && !defined(ANDROID)
+#elif !defined(XP_MACOSX) && !defined(ANDROID) && !defined(XP_LINUX)
   return NS_ERROR_NOT_AVAILABLE;
 #endif
 
   nsRefPtr<nsIDOMCanvasRenderingContext2D> ctx = new nsCanvasRenderingContext2DAzure();
   if (!ctx)
     return NS_ERROR_OUT_OF_MEMORY;
 
   *aResult = ctx.forget().get();
--- a/content/canvas/test/crossorigin/Makefile.in
+++ b/content/canvas/test/crossorigin/Makefile.in
@@ -46,12 +46,14 @@ include $(topsrcdir)/config/rules.mk
 _TEST_FILES = \
 	image-allow-credentials.png \
 	image-allow-credentials.png^headers^ \
 	image-allow-star.png \
 	image-allow-star.png^headers^ \
 	image.png \
 	test_canvas2d_crossorigin.html \
 	test_webgl_crossorigin_textures.html \
+	video.sjs \
+	test_video_crossorigin.html \
 	$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/crossorigin/test_video_crossorigin.html
@@ -0,0 +1,196 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=682299
+-->
+<head>
+  <title>Test for Bug 682299</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript" src="/tests/content/media/test/manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=682299">Mozilla Bug 682299</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 682299 **/
+
+const MEDIA_ERR_SRC_NOT_SUPPORTED = 4;
+const SECURITY_ERR = 0x805303e8;
+
+function createCanvas(width, height) {
+  var c = document.createElement("canvas");
+  c.width = width;
+  c.height = height;
+  return c;
+}
+
+function testCanvasDrawImage(v) {
+  var c = createCanvas(v.width, v.height);
+  var ctx = c.getContext("2d");
+  ctx.drawImage(v, 0, 0);
+
+  try {
+    var data = ctx.getImageData(0, 0, 1, 1);
+    ok(true, "drawImage '" + v.src + "' then getImageData with crossorigin='" + v.crossorigin + "' worked");
+  } catch(error) {
+    ok(!v.crossorigin && error.result === SECURITY_ERR, "drawImage '" + v.src + "' then getImageData with crossorigin='" + v.crossorigin + "' failed");
+    v.tainted = true;
+  }
+}
+
+function testCanvasCreatePattern(v) {
+  var c = createCanvas(v.width, v.height);
+  var ctx = c.getContext("2d");
+  ctx.fillStyle = ctx.createPattern(v, "");
+  ctx.fillRect(0, 0, c.width, c.height);
+
+  try {
+    var data = ctx.getImageData(0, 0, 1, 1);
+    ok(true, "createPattern '" + v.src + "' then getImageData with crossorigin='" + v.crossorigin + "' worked");
+  } catch(error) {
+    ok(!v.crossorigin && error.result === SECURITY_ERR, "createPattern '" + v.src + "' then getImageData with crossorigin='" + v.crossorigin + "' failed");
+    v.tainted = true;
+  }
+}
+
+function testWebGL(v) {
+  var tex = gl.createTexture();
+  gl.bindTexture(gl.TEXTURE_2D, tex);
+
+  try {
+    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, v);
+    ok(true, "createTexture from '" + v.src + "' with crossorigin='" + v.crossorigin + "' worked");
+  } catch (error) {
+    ok(!v.crossorigin && error.result === SECURITY_ERR, "createTexture from '" + v.src + "' with crossorigin='" + v.crossorigin + "' failed");
+    v.tainted = true;
+  }
+}
+
+function testTaintedCanvas(v) {
+  var c = createCanvas(v.width, v.height);
+  var ctx = c.getContext("2d");
+  ctx.drawImage(v, 0, 0);
+
+  try {
+    var data = ctx.getImageData(0, 0, 1, 1);
+    ok(false, "changing the CORS mode should not allow reading data from remote videos");
+  } catch (error) {
+    ok(error.result === SECURITY_ERR, "changing the CORS mode, drawImage '" + v.src + "' then getImageData with crossorigin='" + v.crossorigin + "' failed");
+  }
+}
+
+function vidDataSuccess(e) {
+  ok(!e.target.error, "Load '" + e.target.src + "' with crossorigin='" + e.target.crossorigin + "'");
+
+  testCanvasDrawImage(e.target);
+  testCanvasCreatePattern(e.target);
+  if (gl) {
+    testWebGL(e.target);
+  }
+  // If we change the CORS mode after loading the file without CORS it should still throw a security error
+  if (e.target.tainted) {
+    e.target.crossorigin = "anonymous";
+    testTaintedCanvas(e.target);
+  }
+
+  doneTest(e);
+}
+
+function vidLoadFailure(e) {
+  ok(false, "Load '" + e.target.src + "' with crossorigin='" + e.target.crossorigin + "'");
+  doneTest(e);
+}
+
+function vidErrorSuccess(e) {
+  ok(e.target.error.code === MEDIA_ERR_SRC_NOT_SUPPORTED, 
+    "Load '" + e.target.src + "' with crossorigin='" + e.target.crossorigin + "'");
+  doneTest(e);
+}
+
+function startTest(test, token) {
+  var v = document.createElement('video');
+  if (test.cors === "just-crossOrigin-without-value") {
+    var div = document.createElement('div');
+    div.innerHTML="<video crossorigin>";
+    v = div.children[0];
+  } else if (test.cors !== "missing-value-default") {
+    v.crossorigin = test.cors;
+  }
+  v.token = token;
+  manager.started(token);
+  v.autoplay = true;
+  v.preload = "auto";
+  v.style.display = "none";
+  if (test.nameIntent === test.corsIntent || test.corsIntent === "none" ||
+      (test.nameIntent === "use-credentials" && test.corsIntent === "anonymous")) {
+    v.addEventListener("loadeddata", vidDataSuccess, false);
+    v.addEventListener("error", vidLoadFailure, false);
+  } else {
+    v.addEventListener("loadeddata", vidLoadFailure, false);
+    v.addEventListener("error", vidErrorSuccess, false);
+  }
+  v.src = test.name;
+  document.body.appendChild(v);
+}
+
+function doneTest(e) {
+  var v = e.target;
+  v.parentNode.removeChild(v);
+  manager.finished(v.token);
+}
+
+var videoFile = getPlayableVideo(gSmallTests);
+if (!videoFile) {
+  SimpleTest.finish();
+}
+videoFile = "?name=tests/content/media/test/" + videoFile.name + "&type=" + videoFile.type;
+
+var gl;
+try {
+  gl = createCanvas(16, 16).getContext("experimental-webgl");
+} catch (ex) {
+  // Mac OS X 10.5 doesn't support WebGL, so we won't run the WebGL tests
+}
+
+var manager = new MediaTestManager;
+var corsTests = [];
+
+const host = "http://example.com/tests/content/canvas/test/crossorigin/video.sjs";
+const serverAttrValues = [
+  [ "&cors=none", "none" ],
+  [ "&cors=anonymous", "anonymous" ],
+  [ "&cors=use-credentials", "use-credentials" ]
+];
+const clientAttrValues = [
+  [ "missing-value-default", "none" ],
+  [ "", "anonymous" ],
+  [ "just-crossOrigin-without-value", "anonymous" ],
+  [ "anonymous", "anonymous" ],
+  [ "use-credentials", "use-credentials" ],
+  [ "foobar", "anonymous" ]
+];
+
+// Build the video file test array
+for (var i = 0; i < serverAttrValues.length; i++) {
+	for (var n = 0; n < clientAttrValues.length; n++) {
+		corsTests.push({
+      name: host + videoFile + serverAttrValues[i][0],
+      nameIntent: serverAttrValues[i][1],
+      cors: clientAttrValues[n][0],
+      corsIntent: clientAttrValues[n][1]
+    });
+	}
+}
+
+manager.runTests(corsTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/crossorigin/video.sjs
@@ -0,0 +1,43 @@
+function parseQuery(request, key) {
+  var params = request.queryString.split('&');
+  for (var j = 0; j < params.length; ++j) {
+    var p = params[j];
+	if (p == key)
+	  return true;
+    if (p.indexOf(key + "=") == 0)
+	  return p.substring(key.length + 1);
+	if (p.indexOf("=") < 0 && key == "")
+	  return p;
+  }
+  return false;
+}
+
+function handleRequest(request, response) {
+  var name = parseQuery(request, "name");
+  var type = parseQuery(request, "type");
+  var cors = parseQuery(request, "cors");
+  var file = Components.classes["@mozilla.org/file/directory_service;1"].
+                        getService(Components.interfaces.nsIProperties).
+                        get("CurWorkD", Components.interfaces.nsILocalFile);
+  var fis = Components.classes['@mozilla.org/network/file-input-stream;1'].
+                        createInstance(Components.interfaces.nsIFileInputStream);
+  var bis = Components.classes["@mozilla.org/binaryinputstream;1"].
+                        createInstance(Components.interfaces.nsIBinaryInputStream);
+  var split = name.split("/");
+  for(var i = 0; i < split.length; ++i) {
+    file.append(split[i]);
+  }
+  fis.init(file, -1, -1, false);
+  bis.setInputStream(fis);
+  var bytes = bis.readBytes(bis.available());
+  response.setHeader("Content-Length", ""+bytes.length, false);
+  response.setHeader("Content-Type", type, false);
+  if (cors == "anonymous") {
+    response.setHeader("Access-Control-Allow-Origin", "*", false);
+  } else if (cors == "use-credentials") {
+    response.setHeader("Access-Control-Allow-Origin", "http://mochi.test:8888", false);
+    response.setHeader("Access-Control-Allow-Credentials", "true", false);
+  }
+  response.write(bytes, bytes.length);
+  bis.close();
+}
--- a/content/events/src/nsDOMEventTargetHelper.h
+++ b/content/events/src/nsDOMEventTargetHelper.h
@@ -99,9 +99,16 @@ public:
   }
 protected:
   nsRefPtr<nsEventListenerManager> mListenerManager;
   // These may be null (native callers or xpcshell).
   nsCOMPtr<nsIScriptContext> mScriptContext;
   nsCOMPtr<nsPIDOMWindow>    mOwner; // Inner window.
 };
 
+#define NS_UNMARK_LISTENER_WRAPPER(_event)                       \
+  if (tmp->mOn##_event##Listener) {                              \
+    nsCOMPtr<nsIXPConnectWrappedJS> wjs =                        \
+      do_QueryInterface(tmp->mOn##_event##Listener->GetInner()); \
+    xpc_UnmarkGrayObject(wjs);                                   \
+  }
+
 #endif // nsDOMEventTargetHelper_h_
--- a/content/events/src/nsEventListenerManager.cpp
+++ b/content/events/src/nsEventListenerManager.cpp
@@ -77,16 +77,17 @@
 #include "nsDOMJSUtils.h"
 #include "nsDOMScriptObjectHolder.h"
 #include "nsDataHashtable.h"
 #include "nsCOMArray.h"
 #include "nsEventListenerService.h"
 #include "nsDOMEvent.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsJSEnvironment.h"
+#include "xpcpublic.h"
 #include "sampler.h"
 
 using namespace mozilla::dom;
 
 #define EVENT_TYPE_EQUALS( ls, type, userType ) \
   (ls->mEventType == type && \
   (ls->mEventType != NS_USER_DEFINED_EVENT || ls->mTypeAtom == userType))
 
@@ -235,19 +236,24 @@ nsEventListenerManager::AddEventListener
 
   mNoListenerForEvent = NS_EVENT_TYPE_NULL;
   mNoListenerForEventAtom = nsnull;
 
   ls = mListeners.AppendElement();
   ls->mListener = aListener;
   ls->mEventType = aType;
   ls->mTypeAtom = aTypeAtom;
+  ls->mWrappedJS = false;
   ls->mFlags = aFlags;
   ls->mHandlerIsString = false;
 
+  nsCOMPtr<nsIXPConnectWrappedJS> wjs = do_QueryInterface(aListener);
+  if (wjs) {
+    ls->mWrappedJS = true;
+  }
   if (aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) {
     mMayHaveSystemGroupListeners = true;
   }
   if (aFlags & NS_EVENT_FLAG_CAPTURE) {
     mMayHaveCapturingListeners = true;
   }
 
   if (aType == NS_AFTERPAINT) {
@@ -1008,8 +1014,25 @@ nsEventListenerManager::SizeOf() const
     size += sizeof(ls);
     nsIJSEventListener* jsl = ls.GetJSListener();
     if (jsl) {
       size += jsl->SizeOf();
     }
   }
   return size;
 }
+
+void
+nsEventListenerManager::UnmarkGrayJSListeners()
+{
+  PRUint32 count = mListeners.Length();
+  for (PRUint32 i = 0; i < count; ++i) {
+    const nsListenerStruct& ls = mListeners.ElementAt(i);
+    nsIJSEventListener* jsl = ls.GetJSListener();
+    if (jsl) {
+      xpc_UnmarkGrayObject(jsl->GetHandler());
+      xpc_UnmarkGrayObject(jsl->GetEventScope());
+    } else if (ls.mWrappedJS) {
+      nsCOMPtr<nsIXPConnectWrappedJS> wjs = do_QueryInterface(ls.mListener);
+      xpc_UnmarkGrayObject(wjs);
+    }
+  }
+}
--- a/content/events/src/nsEventListenerManager.h
+++ b/content/events/src/nsEventListenerManager.h
@@ -65,16 +65,17 @@ class nsIDocument;
 
 struct nsListenerStruct
 {
   nsRefPtr<nsIDOMEventListener> mListener;
   PRUint32                      mEventType;
   nsCOMPtr<nsIAtom>             mTypeAtom;
   PRUint16                      mFlags;
   bool                          mHandlerIsString;
+  bool                          mWrappedJS;
 
   nsIJSEventListener* GetJSListener() const {
     return (mFlags & NS_PRIV_EVENT_FLAG_SCRIPT) ?
       static_cast<nsIJSEventListener *>(mListener.get()) : nsnull;
   }
 
   ~nsListenerStruct()
   {
@@ -238,16 +239,20 @@ public:
    * Returns true if there may be a touch event listener registered,
    * false if there definitely isn't.
    */
   bool MayHaveTouchEventListener() { return mMayHaveTouchEventListener; }
 
   bool MayHaveMouseEnterLeaveEventListener() { return mMayHaveMouseEnterLeaveEventListener; }
 
   PRInt64 SizeOf() const;
+
+  void UnmarkGrayJSListeners();
+
+  nsISupports* GetTarget() { return mTarget; }
 protected:
   nsresult HandleEventSubType(nsListenerStruct* aListenerStruct,
                               nsIDOMEventListener* aListener,
                               nsIDOMEvent* aDOMEvent,
                               nsIDOMEventTarget* aCurrentTarget,
                               PRUint32 aPhaseFlags,
                               nsCxPusher* aPusher);
 
--- a/content/html/content/public/nsHTMLMediaElement.h
+++ b/content/html/content/public/nsHTMLMediaElement.h
@@ -68,16 +68,20 @@ public:
   typedef mozilla::TimeDuration TimeDuration;
 
   enum CanPlayStatus {
     CANPLAY_NO,
     CANPLAY_MAYBE,
     CANPLAY_YES
   };
 
+  CORSMode GetCORSMode() {
+    return mCORSMode;
+  }
+
   nsHTMLMediaElement(already_AddRefed<nsINodeInfo> aNodeInfo);
   virtual ~nsHTMLMediaElement();
 
   /**
    * This is used when the browser is constructing a video element to play
    * a channel that we've already started loading. The src attribute and
    * <source> children are ignored.
    * @param aChannel the channel to use
@@ -228,18 +232,17 @@ public:
   // Return true if we can activate autoplay assuming enough data has arrived.
   bool CanActivateAutoplay();
 
   // Notify that enough data has arrived to start autoplaying.
   // If the element is 'autoplay' and is ready to play back (not paused,
   // autoplay pref enabled, etc), it should start playing back.
   void NotifyAutoplayDataReady();
 
-  // Gets the pref media.enforce_same_site_origin, which determines
-  // if we should check Access Controls, or allow cross domain loads.
+  // Check if the media element had crossorigin set when loading started
   bool ShouldCheckAllowOrigin();
 
   // Is the media element potentially playing as defined by the HTML 5 specification.
   // http://www.whatwg.org/specs/web-apps/current-work/#potentially-playing
   bool IsPotentiallyPlaying() const;
 
   // Has playback ended as defined by the HTML 5 specification.
   // http://www.whatwg.org/specs/web-apps/current-work/#ended
@@ -756,11 +759,14 @@ protected:
   // True if we've suspended a load in the resource selection algorithm
   // due to loading a preload:none media. When true, the resource we'll
   // load when the user initiates either playback or an explicit load is
   // stored in mPreloadURI.
   bool mLoadIsSuspended;
 
   // True if a same-origin check has been done for the media element and resource.
   bool mMediaSecurityVerified;
+
+  // The CORS mode when loading the media element
+  CORSMode mCORSMode;
 };
 
 #endif
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -2879,16 +2879,24 @@ nsGenericHTMLFormElement::PreHandleEvent
         break;
       }
     }
   }
 
   return nsGenericHTMLElement::PreHandleEvent(aVisitor);
 }
 
+const nsAttrValue::EnumTable nsGenericHTMLElement::kCORSAttributeTable[] = {
+  // Order matters here
+  // See ParseAttribute in nsHTMLImageElement or nsHTMLMediaElement
+  { "anonymous",       nsGenericHTMLElement::CORS_ANONYMOUS       },
+  { "use-credentials", nsGenericHTMLElement::CORS_USE_CREDENTIALS },
+  { 0 }
+};
+
 /* virtual */
 bool
 nsGenericHTMLFormElement::IsDisabled() const
 {
   return HasAttr(kNameSpaceID_None, nsGkAtoms::disabled) ||
          (mFieldSet && mFieldSet->IsDisabled());
 }
 
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -537,16 +537,42 @@ public:
     return HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
   }
 
   bool IsHidden() const
   {
     return HasAttr(kNameSpaceID_None, nsGkAtoms::hidden);
   }
 
+  /**
+   * Shared cross-origin resource sharing attributes so they don't get
+   * duplicated on every CORS-enabled element
+   */
+
+  enum CORSMode {
+    /**
+     * The default of not using CORS to validate cross-origin loads.
+     */
+    CORS_NONE,
+
+    /**
+     * Validate cross-site loads using CORS, but do not send any credentials
+     * (cookies, HTTP auth logins, etc) along with the request.
+     */
+    CORS_ANONYMOUS,
+
+    /**
+     * Validate cross-site loads using CORS, and send credentials such as cookies
+     * and HTTP auth logins along with the request.
+     */
+    CORS_USE_CREDENTIALS
+  };
+
+  const static nsAttrValue::EnumTable kCORSAttributeTable[];
+
 protected:
   /**
    * Add/remove this element to the documents name cache
    */
   void AddToNameTable(nsIAtom* aName) {
     NS_ASSERTION(HasName(), "Node doesn't have name?");
     nsIDocument* doc = GetCurrentDoc();
     if (doc && !IsInAnonymousSubtree()) {
--- a/content/html/content/src/nsHTMLImageElement.cpp
+++ b/content/html/content/src/nsHTMLImageElement.cpp
@@ -121,17 +121,17 @@ public:
   NS_SCRIPTABLE NS_IMETHOD SetInnerHTML(const nsAString& aInnerHTML) {
     return nsGenericHTMLElement::SetInnerHTML(aInnerHTML);
   }
 
   // nsIDOMHTMLImageElement
   NS_DECL_NSIDOMHTMLIMAGEELEMENT
 
   // override from nsImageLoadingContent
-  nsImageLoadingContent::CORSMode GetCORSMode();
+  CORSMode GetCORSMode();
 
   // nsIJSNativeInitializer
   NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* aContext,
                         JSObject* aObj, PRUint32 argc, jsval* argv);
 
   // nsIContent
   virtual bool ParseAttribute(PRInt32 aNamespaceID,
                                 nsIAtom* aAttribute,
@@ -240,23 +240,16 @@ NS_IMPL_STRING_ATTR(nsHTMLImageElement, 
 NS_IMPL_INT_ATTR(nsHTMLImageElement, Hspace, hspace)
 NS_IMPL_BOOL_ATTR(nsHTMLImageElement, IsMap, ismap)
 NS_IMPL_URI_ATTR(nsHTMLImageElement, LongDesc, longdesc)
 NS_IMPL_STRING_ATTR(nsHTMLImageElement, Lowsrc, lowsrc)
 NS_IMPL_URI_ATTR(nsHTMLImageElement, Src, src)
 NS_IMPL_STRING_ATTR(nsHTMLImageElement, UseMap, usemap)
 NS_IMPL_INT_ATTR(nsHTMLImageElement, Vspace, vspace)
 
-static const nsAttrValue::EnumTable kCrossOriginTable[] = {
-  // Order matters here; see ParseAttribute
-  { "anonymous",       nsImageLoadingContent::CORS_ANONYMOUS },
-  { "use-credentials", nsImageLoadingContent::CORS_USE_CREDENTIALS },
-  { 0 }
-};
-
 // crossorigin is not "limited to only known values" per spec, so it's
 // just a string attr purposes of the DOM crossOrigin property.
 NS_IMPL_STRING_ATTR(nsHTMLImageElement, CrossOrigin, crossorigin)
 
 NS_IMETHODIMP
 nsHTMLImageElement::GetDraggable(bool* aDraggable)
 {
   // images may be dragged unless the draggable attribute is false
@@ -365,20 +358,20 @@ nsHTMLImageElement::ParseAttribute(PRInt
                                    const nsAString& aValue,
                                    nsAttrValue& aResult)
 {
   if (aNamespaceID == kNameSpaceID_None) {
     if (aAttribute == nsGkAtoms::align) {
       return ParseAlignValue(aValue, aResult);
     }
     if (aAttribute == nsGkAtoms::crossorigin) {
-      return aResult.ParseEnumValue(aValue, kCrossOriginTable, false,
+      return aResult.ParseEnumValue(aValue, nsGenericHTMLElement::kCORSAttributeTable, false,
                                     // default value is anonymous if aValue is
                                     // not a value we understand
-                                    &kCrossOriginTable[0]);
+                                    &nsGenericHTMLElement::kCORSAttributeTable[0]);
     }
     if (ParseImageAttribute(aAttribute, aValue, aResult)) {
       return true;
     }
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
@@ -664,22 +657,22 @@ nsresult
 nsHTMLImageElement::CopyInnerTo(nsGenericElement* aDest) const
 {
   if (aDest->OwnerDoc()->IsStaticDocument()) {
     CreateStaticImageClone(static_cast<nsHTMLImageElement*>(aDest));
   }
   return nsGenericHTMLElement::CopyInnerTo(aDest);
 }
 
-nsImageLoadingContent::CORSMode
+nsGenericHTMLElement::CORSMode
 nsHTMLImageElement::GetCORSMode()
 {
-  nsImageLoadingContent::CORSMode ret = nsImageLoadingContent::CORS_NONE;
+  nsGenericHTMLElement::CORSMode ret = nsGenericHTMLElement::CORS_NONE;
 
   const nsAttrValue* value = GetParsedAttr(nsGkAtoms::crossorigin);
   if (value) {
     NS_ASSERTION(value->Type() == nsAttrValue::eEnum,
                  "Why is this not an enum value?");
-    ret = nsImageLoadingContent::CORSMode(value->GetEnumValue());
+    ret = nsGenericHTMLElement::CORSMode(value->GetEnumValue());
   }
 
   return ret;
 }
--- a/content/html/content/src/nsHTMLMediaElement.cpp
+++ b/content/html/content/src/nsHTMLMediaElement.cpp
@@ -935,16 +935,26 @@ nsresult nsHTMLMediaElement::LoadResourc
     mAudioStream = nsnull;
   }
 
   if (mChannel) {
     mChannel->Cancel(NS_BINDING_ABORTED);
     mChannel = nsnull;
   }
 
+  // Set the media element's CORS mode only when loading a resource
+  // By default, it's CORS_NONE
+  mCORSMode = CORS_NONE;
+  const nsAttrValue* value = GetParsedAttr(nsGkAtoms::crossorigin);
+  if (value) {
+    NS_ASSERTION(value->Type() == nsAttrValue::eEnum,
+                 "Why is this not an enum value?");
+    mCORSMode = CORSMode(value->GetEnumValue());
+  }
+
   nsHTMLMediaElement* other = LookupMediaElementURITable(mLoadingSrc);
   if (other) {
     // Clone it.
     nsresult rv = InitializeDecoderAsClone(other->mDecoder);
     if (NS_SUCCEEDED(rv))
       return rv;
   }
 
@@ -997,17 +1007,17 @@ nsresult nsHTMLMediaElement::LoadResourc
   channel->SetNotificationCallbacks(loadListener);
 
   nsCOMPtr<nsIStreamListener> listener;
   if (ShouldCheckAllowOrigin()) {
     listener =
       new nsCORSListenerProxy(loadListener,
                               NodePrincipal(),
                               channel,
-                              false,
+                              GetCORSMode() == CORS_USE_CREDENTIALS,
                               &rv);
   } else {
     rv = nsContentUtils::GetSecurityManager()->
            CheckLoadURIWithPrincipal(NodePrincipal(),
                                      mLoadingSrc,
                                      nsIScriptSecurityManager::STANDARD);
     listener = loadListener;
   }
@@ -1387,21 +1397,20 @@ nsHTMLMediaElement::LookupMediaElementUR
   if (!gElementTable)
     return nsnull;
   MediaElementSetForURI* entry = gElementTable->GetEntry(aURI);
   if (!entry)
     return nsnull;
   for (PRUint32 i = 0; i < entry->mElements.Length(); ++i) {
     nsHTMLMediaElement* elem = entry->mElements[i];
     bool equal;
-    // Look for elements that have the same principal.
-    // XXX when we implement crossorigin for video, we'll also need to check
-    // for the same crossorigin mode here. Ditto for anything else that could
-    // cause us to send different headers.
-    if (NS_SUCCEEDED(elem->NodePrincipal()->Equals(NodePrincipal(), &equal)) && equal) {
+    // Look for elements that have the same principal and CORS mode.
+    // Ditto for anything else that could cause us to send different headers.
+    if (NS_SUCCEEDED(elem->NodePrincipal()->Equals(NodePrincipal(), &equal)) && equal &&
+        elem->mCORSMode == mCORSMode) {
       NS_ASSERTION(elem->mDecoder && elem->mDecoder->GetStream(), "Decoder gone");
       return elem;
     }
   }
   return nsnull;
 }
 
 nsHTMLMediaElement::nsHTMLMediaElement(already_AddRefed<nsINodeInfo> aNodeInfo)
@@ -1433,17 +1442,18 @@ nsHTMLMediaElement::nsHTMLMediaElement(a
     mDelayingLoadEvent(false),
     mIsRunningSelectResource(false),
     mSuspendedAfterFirstFrame(false),
     mAllowSuspendAfterFirstFrame(true),
     mHasPlayedOrSeeked(false),
     mHasSelfReference(false),
     mShuttingDown(false),
     mLoadIsSuspended(false),
-    mMediaSecurityVerified(false)
+    mMediaSecurityVerified(false),
+    mCORSMode(CORS_NONE)
 {
 #ifdef PR_LOGGING
   if (!gMediaElementLog) {
     gMediaElementLog = PR_NewLogModule("nsMediaElement");
   }
   if (!gMediaElementEventsLog) {
     gMediaElementEventsLog = PR_NewLogModule("nsMediaElementEvents");
   }
@@ -1554,16 +1564,18 @@ NS_IMETHODIMP nsHTMLMediaElement::Play()
   // We changed mPaused and mAutoplaying which can affect AddRemoveSelfReference
   // and our preload status.
   AddRemoveSelfReference();
   UpdatePreloadAction();
 
   return NS_OK;
 }
 
+NS_IMPL_STRING_ATTR(nsHTMLMediaElement, Crossorigin, crossorigin)
+
 bool nsHTMLMediaElement::ParseAttribute(PRInt32 aNamespaceID,
                                           nsIAtom* aAttribute,
                                           const nsAString& aValue,
                                           nsAttrValue& aResult)
 {
   // Mappings from 'preload' attribute strings to an enumeration.
   static const nsAttrValue::EnumTable kPreloadTable[] = {
     { "",         nsHTMLMediaElement::PRELOAD_ATTR_EMPTY },
@@ -1572,16 +1584,22 @@ bool nsHTMLMediaElement::ParseAttribute(
     { "auto",     nsHTMLMediaElement::PRELOAD_ATTR_AUTO },
     { 0 }
   };
 
   if (aNamespaceID == kNameSpaceID_None) {
     if (ParseImageAttribute(aAttribute, aValue, aResult)) {
       return true;
     }
+    if (aAttribute == nsGkAtoms::crossorigin) {
+      return aResult.ParseEnumValue(aValue, kCORSAttributeTable, false,
+                                    // default value is anonymous if aValue is
+                                    // not a value we understand
+                                    &kCORSAttributeTable[0]);
+    }
     if (aAttribute == nsGkAtoms::preload) {
       return aResult.ParseEnumValue(aValue, kPreloadTable, false);
     }
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
@@ -2325,17 +2343,17 @@ void nsHTMLMediaElement::DownloadStalled
 {
   if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING) {
     DispatchAsyncEvent(NS_LITERAL_STRING("stalled"));
   }
 }
 
 bool nsHTMLMediaElement::ShouldCheckAllowOrigin()
 {
-  return Preferences::GetBool("media.enforce_same_site_origin", true);
+  return mCORSMode != CORS_NONE;
 }
 
 void nsHTMLMediaElement::UpdateReadyStateForData(NextFrameStatus aNextFrame)
 {
   if (mReadyState < nsIDOMHTMLMediaElement::HAVE_METADATA) {
     // aNextFrame might have a next frame because the decoder can advance
     // on its own thread before ResourceLoaded or MetadataLoaded gets
     // a chance to run.
--- a/content/media/test/file_access_controls.html
+++ b/content/media/test/file_access_controls.html
@@ -71,51 +71,42 @@ var gTests = [
     result: "error",
     description: "Won't load from subdomain",
   }
 ];
 
 var gTestNum = 0;
 var gVideo = null;
 var gTestedRemoved = false;
-var gOldPref;
 
 function eventHandler(event) {
   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
   //dump((gTestNum - 1) + ": " + event.type + "\n");
   var video = event.target;
   opener.is(event.type, video.expectedResult, video.testDescription +
     (gTestedRemoved ? " (element not in document)" : " (element in document)"));
   // Make sure any extra events cause an error
   video.expectedResult = "<none>";
   nextTest();
 }
 
 function createVideo() {
   var v = document.createElement('video');
   v.addEventListener('loadeddata', eventHandler, false);
   v.addEventListener('error', eventHandler, false);
+  v.crossorigin = 'anonymous';
   return v;
 }
 
 function load() {
   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
   opener.is(window.location.href,
             "http://example.org/tests/content/media/test/file_access_controls.html",
             "We must be on a example.org:80");
- 
-  // Ensure access control check pref is on.
-  // media.enforce_same_site_origin
-  var prefService = Components.classes["@mozilla.org/preferences-service;1"]
-                               .getService(Components.interfaces.nsIPrefService);
-  opener.ok(prefService!=null, "Get pref service");
-  var branch = prefService.getBranch("media.");
-  opener.ok(branch!=null, "Get media pref branch");
-  gOldPref = branch.getBoolPref("enforce_same_site_origin");
-  branch.setBoolPref("enforce_same_site_origin", true);
+
   nextTest();
 }
 
 function nextTest() {
   //dump("nextTest() called, gTestNum="+gTestNum+" gTestedRemoved="+gTestedRemoved+"\n");
   if (gTestNum == gTests.length) {
     //dump("gTestNum == gTests.length\n");
     if (!gTestedRemoved) {
@@ -154,21 +145,16 @@ function nextTest() {
   } else {
     gVideo.load();
   }
   gTestNum++;
 }
 
 function done() {
   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  // Undo change to access control check pref.
-  var prefService = Components.classes["@mozilla.org/preferences-service;1"]
-                               .getService(Components.interfaces.nsIPrefService);
-  var branch = prefService.getBranch("media.");
-  branch.setBoolPref("enforce_same_site_origin", gOldPref);
   mediaTestCleanup();
   opener.done();
 }
 
 </script>
 </body>
 </html>
 
--- a/content/xslt/src/xpath/txRelationalExpr.cpp
+++ b/content/xslt/src/xpath/txRelationalExpr.cpp
@@ -114,17 +114,17 @@ RelationalExpr::compareResults(txIEvalCo
             result = aLeft->booleanValue() == aRight->booleanValue();
         }
 
         // If either is a number, compare as numbers.
         else if (ltype == txAExprResult::NUMBER ||
                  rtype == txAExprResult::NUMBER) {
             double lval = aLeft->numberValue();
             double rval = aRight->numberValue();
-            result = DOUBLE_COMPARE(lval, ==, rval);
+            result = (lval == rval);
         }
 
         // Otherwise compare as strings. Try to use the stringobject in
         // StringResult if possible since that is a common case.
         else if ((lString = aLeft->stringValuePointer())) {
             if ((rString = aRight->stringValuePointer())) {
                 result = lString->Equals(*rString);
             }
@@ -149,29 +149,29 @@ RelationalExpr::compareResults(txIEvalCo
         return mOp == EQUAL ? result : !result;
     }
 
     double leftDbl = aLeft->numberValue();
     double rightDbl = aRight->numberValue();
     switch (mOp) {
         case LESS_THAN:
         {
-            return DOUBLE_COMPARE(leftDbl, <, rightDbl);
+            return (leftDbl < rightDbl);
         }
         case LESS_OR_EQUAL:
         {
-            return DOUBLE_COMPARE(leftDbl, <=, rightDbl);
+            return (leftDbl <= rightDbl);
         }
         case GREATER_THAN:
         {
-            return DOUBLE_COMPARE(leftDbl, >, rightDbl);
+            return (leftDbl > rightDbl);
         }
         case GREATER_OR_EQUAL:
         {
-            return DOUBLE_COMPARE(leftDbl, >=, rightDbl);
+            return (leftDbl >= rightDbl);
         }
         default:
         {
             NS_NOTREACHED("We should have caught all cases");
         }
     }
 
     return false;
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -811,17 +811,17 @@ nsDOMWindowUtils::GarbageCollect(nsICycl
   SAMPLE_LABEL("GC", "GarbageCollect");
   // Always permit this in debug builds.
 #ifndef DEBUG
   if (!IsUniversalXPConnectCapable()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 #endif
 
-  nsJSContext::GarbageCollectNow();
+  nsJSContext::GarbageCollectNow(js::gcreason::DOM_UTILS);
   nsJSContext::CycleCollectNow(aListener);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::CycleCollect(nsICycleCollectorListener *aListener)
 {
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1400,21 +1400,42 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
     NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   END_OUTER_WINDOW_ONLY
 NS_INTERFACE_MAP_END
 
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindow)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGlobalWindow)
 
+static PLDHashOperator
+MarkXBLHandlers(const void* aKey, JSObject* aData, void* aClosure)
+{
+  xpc_UnmarkGrayObject(aData);
+  return PL_DHASH_NEXT;
+}
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindow)
+  if (tmp->IsBlackForCC()) {
+    if (tmp->mCachedXBLPrototypeHandlers.IsInitialized()) {
+      tmp->mCachedXBLPrototypeHandlers.EnumerateRead(MarkXBLHandlers, nsnull);
+    }
+    return true;
+  }
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGlobalWindow)
+  return tmp->IsBlackForCC();
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGlobalWindow)
+  return tmp->IsBlackForCC();
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGlobalWindow)
-  if ((tmp->mDoc && nsCCUncollectableMarker::InGeneration(
-                      cb, tmp->mDoc->GetMarkedCCGeneration())) ||
-      (nsCCUncollectableMarker::sGeneration && tmp->IsBlack())) {
+  if (!cb.WantAllTraces() && tmp->IsBlackForCC()) {
     return NS_SUCCESS_INTERRUPTED_TRAVERSE;
   }
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mControllers)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mArguments)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mArgumentsLast)
@@ -1513,16 +1534,38 @@ TraceXBLHandlers(const void* aKey, JSObj
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindow)
   if (tmp->mCachedXBLPrototypeHandlers.IsInitialized()) {
     TraceData data(aCallback, aClosure);
     tmp->mCachedXBLPrototypeHandlers.EnumerateRead(TraceXBLHandlers, &data);
   }
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
+bool
+nsGlobalWindow::IsBlackForCC()
+{
+  return
+    (mDoc &&
+     nsCCUncollectableMarker::InGeneration(mDoc->GetMarkedCCGeneration())) ||
+    (nsCCUncollectableMarker::sGeneration && IsBlack());
+}
+
+void
+nsGlobalWindow::UnmarkGrayTimers()
+{
+  for (nsTimeout* timeout = FirstTimeout();
+       timeout && IsTimeout(timeout);
+       timeout = timeout->Next()) {
+    if (timeout->mScriptHandler) {
+      JSObject* o = timeout->mScriptHandler->GetScriptObject();
+      xpc_UnmarkGrayObject(o);
+    }
+  }
+}
+
 //*****************************************************************************
 // nsGlobalWindow::nsIScriptGlobalObject
 //*****************************************************************************
 
 nsresult
 nsGlobalWindow::SetScriptContext(PRUint32 lang_id, nsIScriptContext *aScriptContext)
 {
   NS_ASSERTION(lang_id == nsIProgrammingLanguage::JAVASCRIPT,
@@ -2267,17 +2310,17 @@ nsGlobalWindow::SetNewDocument(nsIDocume
       mArgumentsOrigin = nsnull;
     }
 
     // Give the new inner window our chrome event handler (since it
     // doesn't have one).
     newInnerWindow->mChromeEventHandler = mChromeEventHandler;
   }
 
-  mContext->GC();
+  mContext->GC(js::gcreason::SET_NEW_DOCUMENT);
   mContext->DidInitializeContext();
 
   if (newInnerWindow && !newInnerWindow->mHasNotifiedGlobalCreated && mDoc) {
     // We should probably notify. However if this is the, arguably bad,
     // situation when we're creating a temporary non-chrome-about-blank
     // document in a chrome docshell, don't notify just yet. Instead wait
     // until we have a real chrome doc.
     nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(mDocShell));
@@ -2424,17 +2467,17 @@ nsGlobalWindow::SetDocShell(nsIDocShell*
       // We got no new document after someone called
       // SetArguments(), drop our reference to the arguments.
       mArguments = nsnull;
       mArgumentsLast = nsnull;
       mArgumentsOrigin = nsnull;
     }
 
     if (mContext) {
-      mContext->GC();
+      mContext->GC(js::gcreason::SET_DOC_SHELL);
       mContext->FinalizeContext();
       mContext = nsnull;
     }
 
 #ifdef DEBUG
     nsCycleCollector_DEBUG_shouldBeFreed(mContext);
     nsCycleCollector_DEBUG_shouldBeFreed(static_cast<nsIScriptGlobalObject*>(this));
 #endif
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -322,16 +322,18 @@ public:
 
   // Set a new script language context for this global.  The native global
   // for the context is created by the context's GetNativeGlobal() method.
   virtual nsresult SetScriptContext(PRUint32 lang, nsIScriptContext *aContext);
   
   virtual void OnFinalize(JSObject* aObject);
   virtual void SetScriptsEnabled(bool aEnabled, bool aFireTimeouts);
 
+  virtual bool IsBlackForCC();
+
   // nsIScriptObjectPrincipal
   virtual nsIPrincipal* GetPrincipal();
 
   // nsIDOMWindow
   NS_DECL_NSIDOMWINDOW
 
   // nsIDOMWindowPerformance
   NS_DECL_NSIDOMWINDOWPERFORMANCE
@@ -503,18 +505,18 @@ public:
   static bool IsCallerChrome();
   static void CloseBlockScriptTerminationFunc(nsISupports *aRef);
 
   static void RunPendingTimeoutsRecursive(nsGlobalWindow *aTopWindow,
                                           nsGlobalWindow *aWindow);
 
   friend class WindowStateHolder;
 
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsGlobalWindow,
-                                                         nsIScriptGlobalObject)
+  NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsGlobalWindow,
+                                                                   nsIScriptGlobalObject)
 
   void InitJavaProperties();
 
   virtual NS_HIDDEN_(JSObject*)
     GetCachedXBLPrototypeHandler(nsXBLPrototypeHandler* aKey);
 
   virtual NS_HIDDEN_(void)
     CacheXBLPrototypeHandler(nsXBLPrototypeHandler* aKey,
@@ -570,16 +572,17 @@ public:
   static bool HasPerformanceSupport();
 
   static WindowByIdTable* GetWindowsTable() {
     return sWindowsById;
   }
 
   PRInt64 SizeOf() const;
 
+  void UnmarkGrayTimers();
 private:
   // Enable updates for the accelerometer.
   void EnableDeviceMotionUpdates();
 
   // Disables updates for the accelerometer.
   void DisableDeviceMotionUpdates();
 
 protected:
--- a/dom/base/nsIScriptContext.h
+++ b/dom/base/nsIScriptContext.h
@@ -38,16 +38,17 @@
 #ifndef nsIScriptContext_h__
 #define nsIScriptContext_h__
 
 #include "nscore.h"
 #include "nsStringGlue.h"
 #include "nsISupports.h"
 #include "nsCOMPtr.h"
 #include "nsIProgrammingLanguage.h"
+#include "jsfriendapi.h"
 #include "jspubtd.h"
 
 class nsIScriptGlobalObject;
 class nsIScriptSecurityManager;
 class nsIPrincipal;
 class nsIAtom;
 class nsIArray;
 class nsIVariant;
@@ -349,17 +350,17 @@ public:
   virtual void FinalizeContext() = 0;
 
   /**
    * For garbage collected systems, do a synchronous collection pass.
    * May be a no-op on other systems
    *
    * @return NS_OK if the method is successful
    */
-  virtual void GC() = 0;
+  virtual void GC(js::gcreason::Reason aReason) = 0;
 
   /**
    * Inform the context that a script was evaluated.
    * A GC may be done if "necessary."
    * This call is necessary if script evaluation is done
    * without using the EvaluateScript method.
    * @param aTerminated If true then call termination function if it was 
    *    previously set. Within DOM this will always be true, but outside 
--- a/dom/base/nsIScriptGlobalObject.h
+++ b/dom/base/nsIScriptGlobalObject.h
@@ -95,18 +95,18 @@ struct JSObject; // until we finally rem
 // aStatus will be filled in with the status.
 bool
 NS_HandleScriptError(nsIScriptGlobalObject *aScriptGlobal,
                      nsScriptErrorEvent *aErrorEvent,
                      nsEventStatus *aStatus);
 
 
 #define NS_ISCRIPTGLOBALOBJECT_IID \
-{ 0x08f73284, 0x26e3, 0x4fa6, \
-  { 0xbf, 0x89, 0x83, 0x26, 0xf9, 0x2a, 0x94, 0xb3 } }
+{ 0x8f19a761, 0x0717, 0x4b3f, \
+  { 0x80, 0xc5, 0xed, 0x7e, 0x9c, 0xbc, 0x40, 0xb1 } }
 
 /**
  * The global object which keeps a script context for each supported script
  * language. This often used to store per-window global state.
  */
 
 class nsIScriptGlobalObject : public nsISupports
 {
@@ -157,14 +157,16 @@ public:
 
   /**
    * Handle a script error.  Generally called by a script context.
    */
   virtual nsresult HandleScriptError(nsScriptErrorEvent *aErrorEvent,
                                      nsEventStatus *aEventStatus) {
     return NS_HandleScriptError(this, aErrorEvent, aEventStatus);
   }
+
+  virtual bool IsBlackForCC() { return false; }
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptGlobalObject,
                               NS_ISCRIPTGLOBALOBJECT_IID)
 
 #endif
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -198,17 +198,17 @@ public:
 
 NS_IMPL_ISUPPORTS1(nsMemoryPressureObserver, nsIObserver)
 
 NS_IMETHODIMP
 nsMemoryPressureObserver::Observe(nsISupports* aSubject, const char* aTopic,
                                   const PRUnichar* aData)
 {
   if (sGCOnMemoryPressure) {
-    nsJSContext::GarbageCollectNow(true);
+    nsJSContext::GarbageCollectNow(js::gcreason::MEM_PRESSURE, nsGCShrinking);
     nsJSContext::CycleCollectNow();
   }
   return NS_OK;
 }
 
 class nsRootedJSValueArray {
 public:
   explicit nsRootedJSValueArray(JSContext *cx) : avr(cx, vals.Length(), vals.Elements()) {}
@@ -1106,17 +1106,17 @@ nsJSContext::DestroyJSContext()
   // Clear our entry in the JSContext, bugzilla bug 66413
   ::JS_SetContextPrivate(mContext, nsnull);
 
   // Unregister our "javascript.options.*" pref-changed callback.
   Preferences::UnregisterCallback(JSOptionChangedCallback,
                                   js_options_dot_str, this);
 
   if (mGCOnDestruction) {
-    PokeGC();
+    PokeGC(js::gcreason::NSJSCONTEXT_DESTROY);
   }
         
   // Let xpconnect destroy the JSContext when it thinks the time is right.
   nsIXPConnect *xpc = nsContentUtils::XPConnect();
   if (xpc) {
     xpc->ReleaseJSContext(mContext, true);
   } else {
     ::JS_DestroyContextNoGC(mContext);
@@ -3215,17 +3215,17 @@ nsJSContext::ScriptExecuted()
 {
   ScriptEvaluated(!::JS_IsRunning(mContext));
 
   return NS_OK;
 }
 
 //static
 void
-nsJSContext::GarbageCollectNow(bool shrinkingGC)
+nsJSContext::GarbageCollectNow(js::gcreason::Reason reason, PRUint32 gckind)
 {
   NS_TIME_FUNCTION_MIN(1.0);
   SAMPLE_LABEL("GC", "GarbageCollectNow");
 
   KillGCTimer();
   KillShrinkGCBuffersTimer();
 
   // Reset sPendingLoadCount in case the timer that fired was a
@@ -3233,17 +3233,17 @@ nsJSContext::GarbageCollectNow(bool shri
   // documents were loading. If this happens we're waiting for a
   // document that is taking a long time to load, and we effectively
   // ignore the fact that the currently loading documents are still
   // loading and move on as if they weren't.
   sPendingLoadCount = 0;
   sLoadingInProgress = false;
 
   if (nsContentUtils::XPConnect()) {
-    nsContentUtils::XPConnect()->GarbageCollect(shrinkingGC);
+    nsContentUtils::XPConnect()->GarbageCollect(reason, gckind);
   }
 }
 
 //static
 void
 nsJSContext::ShrinkGCBuffersNow()
 {
   NS_TIME_FUNCTION_MIN(1.0);
@@ -3271,17 +3271,17 @@ nsJSContext::CycleCollectNow(nsICycleCol
 
   PRUint32 suspected = nsCycleCollector_suspectedCount();
   PRUint32 collected = nsCycleCollector_collect(aListener);
   sCCollectedWaitingForGC += collected;
 
   // If we collected a substantial amount of cycles, poke the GC since more objects
   // might be unreachable now.
   if (sCCollectedWaitingForGC > 250) {
-    PokeGC();
+    PokeGC(js::gcreason::CC_WAITING);
   }
 
   PRTime now = PR_Now();
 
   if (sLastCCEndTime) {
     PRUint32 timeBetween = (PRUint32)(start - sLastCCEndTime) / PR_USEC_PER_SEC;
     Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_TIME_BETWEEN, timeBetween);
   }
@@ -3310,17 +3310,18 @@ nsJSContext::CycleCollectNow(nsICycleCol
 }
 
 // static
 void
 GCTimerFired(nsITimer *aTimer, void *aClosure)
 {
   NS_RELEASE(sGCTimer);
 
-  nsJSContext::GarbageCollectNow();
+  uintptr_t reason = reinterpret_cast<uintptr_t>(aClosure);
+  nsJSContext::GarbageCollectNow(static_cast<js::gcreason::Reason>(reason), nsGCNormal);
 }
 
 void
 ShrinkGCBuffersTimerFired(nsITimer *aTimer, void *aClosure)
 {
   NS_RELEASE(sShrinkGCBuffersTimer);
 
   nsJSContext::ShrinkGCBuffersNow();
@@ -3354,38 +3355,38 @@ nsJSContext::LoadEnd()
   // need to be), so make sure we don't make it wrap backwards here.
   if (sPendingLoadCount > 0) {
     --sPendingLoadCount;
     return;
   }
 
   // Its probably a good idea to GC soon since we have finished loading.
   sLoadingInProgress = false;
-  PokeGC();
+  PokeGC(js::gcreason::LOAD_END);
 }
 
 // static
 void
-nsJSContext::PokeGC()
+nsJSContext::PokeGC(js::gcreason::Reason aReason)
 {
   if (sGCTimer) {
     // There's already a timer for GC'ing, just return
     return;
   }
 
   CallCreateInstance("@mozilla.org/timer;1", &sGCTimer);
 
   if (!sGCTimer) {
     // Failed to create timer (probably because we're in XPCOM shutdown)
     return;
   }
 
   static bool first = true;
 
-  sGCTimer->InitWithFuncCallback(GCTimerFired, nsnull,
+  sGCTimer->InitWithFuncCallback(GCTimerFired, reinterpret_cast<void *>(aReason),
                                  first
                                  ? NS_FIRST_GC_DELAY
                                  : NS_GC_DELAY,
                                  nsITimer::TYPE_ONE_SHOT);
 
   first = false;
 }
 
@@ -3468,19 +3469,19 @@ nsJSContext::KillCCTimer()
   if (sCCTimer) {
     sCCTimer->Cancel();
 
     NS_RELEASE(sCCTimer);
   }
 }
 
 void
-nsJSContext::GC()
+nsJSContext::GC(js::gcreason::Reason aReason)
 {
-  PokeGC();
+  PokeGC(aReason);
 }
 
 static void
 DOMGCFinishedCallback(JSRuntime *rt, JSCompartment *comp, const char *status)
 {
   NS_ASSERTION(NS_IsMainThread(), "GCs must run on the main thread");
 
   if (sPostGCEventsToConsole) {
@@ -3508,17 +3509,17 @@ DOMGCFinishedCallback(JSRuntime *rt, JSC
     nsJSContext::KillGCTimer();
 
     // If this is a compartment GC, restart it. We still want
     // a full GC to happen. Compartment GCs usually happen as a
     // result of last-ditch or MaybeGC. In both cases its
     // probably a time of heavy activity and we want to delay
     // the full GC, but we do want it to happen eventually.
     if (comp) {
-      nsJSContext::PokeGC();
+      nsJSContext::PokeGC(js::gcreason::POST_COMPARTMENT);
 
       // We poked the GC, so we can kill any pending CC here.
       nsJSContext::KillCCTimer();
     }
   } else {
     // If this was a full GC, poke the CC to run soon.
     if (!comp) {
       sGCHasRun = true;
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -36,20 +36,22 @@
  * ***** END LICENSE BLOCK ***** */
 #ifndef nsJSEnvironment_h
 #define nsJSEnvironment_h
 
 #include "nsIScriptContext.h"
 #include "nsIScriptRuntime.h"
 #include "nsCOMPtr.h"
 #include "jsapi.h"
+#include "jsfriendapi.h"
 #include "nsIObserver.h"
 #include "nsIXPCScriptNotify.h"
 #include "prtime.h"
 #include "nsCycleCollectionParticipant.h"
+#include "nsIXPConnect.h"
 
 class nsIXPConnectJSObjectHolder;
 class nsRootedJSValueArray;
 class nsScriptNameSpaceManager;
 namespace mozilla {
 template <class> class Maybe;
 }
 
@@ -174,32 +176,39 @@ public:
   virtual void EnterModalState();
   virtual void LeaveModalState();
 
   NS_DECL_NSIXPCSCRIPTNOTIFY
 
   static void LoadStart();
   static void LoadEnd();
 
-  static void GarbageCollectNow(bool shrinkingGC = false);
+  static void GarbageCollectNow(js::gcreason::Reason reason, PRUint32 gckind = nsGCNormal);
   static void ShrinkGCBuffersNow();
   static void CycleCollectNow(nsICycleCollectorListener *aListener = nsnull);
 
-  static void PokeGC();
+  static void PokeGC(js::gcreason::Reason aReason);
   static void KillGCTimer();
 
   static void PokeShrinkGCBuffers();
   static void KillShrinkGCBuffersTimer();
 
   static void PokeCC();
   static void MaybePokeCC();
   static void KillCCTimer();
 
-  virtual void GC();
+  virtual void GC(js::gcreason::Reason aReason);
 
+  nsIScriptGlobalObject* GetCachedGlobalObject()
+  {
+    // Verify that we have a global so that this
+    // does always return a null when GetGlobalObject() is null.
+    JSObject* global = JS_GetGlobalObject(mContext);
+    return global ? mGlobalObjectRef.get() : nsnull;
+  }
 protected:
   nsresult InitializeExternalClasses();
 
   // Helper to convert xpcom datatypes to jsvals.
   nsresult ConvertSupportsTojsvals(nsISupports *aArgs,
                                    JSObject *aScope,
                                    PRUint32 *aArgc,
                                    jsval **aArgv,
--- a/dom/interfaces/core/nsIDOMDocument.idl
+++ b/dom/interfaces/core/nsIDOMDocument.idl
@@ -61,17 +61,17 @@ interface nsIDOMLocation;
  * cannot exist outside the context of a Document, the nsIDOMDocument 
  * interface also contains the factory methods needed to create these 
  * objects.
  *
  * For more information on this interface please see 
  * http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html
  */
 
-[scriptable, uuid(5c3bff4d-ae7f-4c93-948c-519589672c30)]
+[scriptable, uuid(d7cdd08e-1bfd-4bc3-9742-d66586781ee2)]
 interface nsIDOMDocument : nsIDOMNode
 {
   readonly attribute nsIDOMDocumentType         doctype;
   readonly attribute nsIDOMDOMImplementation    implementation;
   readonly attribute nsIDOMElement              documentElement;
   nsIDOMElement                 createElement(in DOMString tagName)
                                   raises(DOMException);
   nsIDOMDocumentFragment        createDocumentFragment();
@@ -113,26 +113,24 @@ interface nsIDOMDocument : nsIDOMNode
 
   /**
    * Create a range
    *
    * @see http://html5.org/specs/dom-range.html#dom-document-createrange
    */
   nsIDOMRange              createRange();
 
-  nsIDOMNodeIterator createNodeIterator(in nsIDOMNode root,
-                                        in unsigned long whatToShow,
-                                        in nsIDOMNodeFilter filter,
-                                        in boolean entityReferenceExpansion)
-                                        raises(DOMException);
-  nsIDOMTreeWalker   createTreeWalker(in nsIDOMNode root,
-                                      in unsigned long whatToShow,
-                                      in nsIDOMNodeFilter filter,
-                                      in boolean entityReferenceExpansion)
-                                        raises(DOMException);
+  [optional_argc] nsIDOMNodeIterator createNodeIterator(in nsIDOMNode root,
+                                                        [optional] in unsigned long whatToShow,
+                                                        [optional] in nsIDOMNodeFilter filter)
+                                                          raises(DOMException);
+  [optional_argc] nsIDOMTreeWalker   createTreeWalker(in nsIDOMNode root,
+                                                      [optional] in unsigned long whatToShow,
+                                                      [optional] in nsIDOMNodeFilter filter)
+                                                        raises(DOMException);
 
   nsIDOMEvent               createEvent(in DOMString eventType)
                                                raises(DOMException);
 
 
   // HTML
   /**
    * The window associated with this document.
--- a/dom/interfaces/html/nsIDOMHTMLAudioElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLAudioElement.idl
@@ -47,17 +47,17 @@
  * <audio> element.
  *
  * For more information on this interface, please see
  * http://www.whatwg.org/specs/web-apps/current-work/#audio
  *
  * @status UNDER_DEVELOPMENT
  */
 
-[scriptable, uuid(c74b835f-bb68-4ab3-a02c-08152cbb09fa)]
+[scriptable, uuid(390c059a-0a26-4a44-96b6-3f8817bf92e9)]
 interface nsIDOMHTMLAudioElement : nsIDOMHTMLMediaElement
 {
   // Setup the audio stream for writing
   void mozSetup(in PRUint32 channels, in PRUint32 rate);
 
   // Write audio to the audio stream
   [implicit_jscontext]
   unsigned long mozWriteAudio(in jsval data);
--- a/dom/interfaces/html/nsIDOMHTMLMediaElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLMediaElement.idl
@@ -52,25 +52,26 @@
 
 // undef the GetCurrentTime macro defined in WinBase.h from the MS Platform SDK
 %{C++
 #ifdef GetCurrentTime
 #undef GetCurrentTime
 #endif
 %}
 
-[scriptable, uuid(1f312b70-c1e1-40ca-94d4-5f70cac773da)]  
+[scriptable, uuid(6733a409-fab3-45e1-af23-9af8c361bdfd)]
 interface nsIDOMHTMLMediaElement : nsIDOMHTMLElement
 {
   // error state
   readonly attribute nsIDOMMediaError error;
 
   // network state
            attribute DOMString src;
   readonly attribute DOMString currentSrc;
+           attribute DOMString crossorigin;
   const unsigned short NETWORK_EMPTY = 0;
   const unsigned short NETWORK_IDLE = 1;
   const unsigned short NETWORK_LOADING = 2;
   const unsigned short NETWORK_NO_SOURCE = 3;
   readonly attribute unsigned short networkState;
            attribute DOMString preload;  
   readonly attribute nsIDOMTimeRanges buffered;
   void load();
--- a/dom/interfaces/html/nsIDOMHTMLVideoElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLVideoElement.idl
@@ -43,17 +43,17 @@
  * <video> element.
  *
  * For more information on this interface, please see
  * http://www.whatwg.org/specs/web-apps/current-work/#video
  *
  * @status UNDER_DEVELOPMENT
  */
 
-[scriptable, uuid(8e6d81a9-a6e1-44af-95be-cbe86de36ede)]
+[scriptable, uuid(2274055b-8b3a-4a5a-8d72-5d5aea07021a)]
 interface nsIDOMHTMLVideoElement : nsIDOMHTMLMediaElement
 {
            attribute long width; 
            attribute long height;
   readonly attribute unsigned long videoWidth;
   readonly attribute unsigned long videoHeight;
            attribute DOMString poster;
            
deleted file mode 100644
--- a/dom/interfaces/traversal/nsIDOMDocumentTraversal.idl
+++ /dev/null
@@ -1,61 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * ***** 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 this file as it was released on May 1 2001.
- *
- * The Initial Developer of the Original Code is
- * Jonas Sicking.
- * Portions created by the Initial Developer are Copyright (C) 2001
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Jonas Sicking <sicking@bigfoot.com> (Original Author)
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of 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 ***** */
-
-#include "domstubs.idl"
-
-interface nsIDOMNodeIterator;
-interface nsIDOMNodeFilter;
-interface nsIDOMTreeWalker;
-
-
-[scriptable, uuid(13f236c0-47f8-11d5-b6a3-009027446e84)]
-// Introduced in DOM Level 2:
-interface nsIDOMDocumentTraversal : nsISupports
-{
-  nsIDOMNodeIterator createNodeIterator(in nsIDOMNode root,
-                                        in unsigned long whatToShow,
-                                        in nsIDOMNodeFilter filter,
-                                        in boolean entityReferenceExpansion)
-                                        raises(DOMException);
-  nsIDOMTreeWalker   createTreeWalker(in nsIDOMNode root,
-                                      in unsigned long whatToShow,
-                                      in nsIDOMNodeFilter filter,
-                                      in boolean entityReferenceExpansion)
-                                        raises(DOMException);
-};
--- a/dom/interfaces/traversal/nsIDOMNodeIterator.idl
+++ b/dom/interfaces/traversal/nsIDOMNodeIterator.idl
@@ -39,17 +39,17 @@
 
 #include "domstubs.idl"
 
 interface nsIDOMNodeIterator;
 interface nsIDOMNodeFilter;
 
 
 [scriptable, uuid(5af83f50-c8d5-4824-be29-1aa9d640bacb)]
-// Introduced in DOM Level 2:
+// Introduced in DOM Level 2, updated to DOM Level 4:
 interface nsIDOMNodeIterator : nsISupports
 {
   readonly attribute nsIDOMNode       root;
   readonly attribute unsigned long    whatToShow;
   readonly attribute nsIDOMNodeFilter filter;
   readonly attribute boolean          expandEntityReferences;
   nsIDOMNode         nextNode()
                                         raises(DOMException);
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -795,24 +795,24 @@ ContentChild::GetIndexedDBPath()
     }
 
     return *gIndexedDBPath;
 }
 
 bool
 ContentChild::RecvGarbageCollect()
 {
-    nsJSContext::GarbageCollectNow();
+    nsJSContext::GarbageCollectNow(js::gcreason::DOM_IPC);
     return true;
 }
 
 bool
 ContentChild::RecvCycleCollect()
 {
-    nsJSContext::GarbageCollectNow();
+    nsJSContext::GarbageCollectNow(js::gcreason::DOM_IPC);
     nsJSContext::CycleCollectNow();
     return true;
 }
 
 bool
 ContentChild::RecvAppInfo(const nsCString& version, const nsCString& buildID)
 {
     mAppInfo.version.Assign(version);
--- a/dom/src/events/nsJSEventListener.cpp
+++ b/dom/src/events/nsJSEventListener.cpp
@@ -49,18 +49,20 @@
 #include "nsContentUtils.h"
 #include "nsDOMScriptObjectHolder.h"
 #include "nsIMutableArray.h"
 #include "nsVariant.h"
 #include "nsIDOMBeforeUnloadEvent.h"
 #include "nsGkAtoms.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIJSContextStack.h"
+#include "xpcpublic.h"
+#include "nsJSEnvironment.h"
+#include "nsDOMJSUtils.h"
 #ifdef NS_DEBUG
-#include "nsDOMJSUtils.h"
 
 #include "nspr.h" // PR_fprintf
 
 class EventListenerCounter
 {
 public:
   ~EventListenerCounter() {
   }
@@ -122,25 +124,51 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSEventListener)
   NS_IMPL_CYCLE_COLLECTION_TRACE_MEMBER_CALLBACK(tmp->mContext->GetScriptTypeID(),
                                                  mScopeObject)
   NS_IMPL_CYCLE_COLLECTION_TRACE_MEMBER_CALLBACK(tmp->mContext->GetScriptTypeID(),
                                                  mHandler)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsJSEventListener)
+  return tmp->IsBlackForCC();
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsJSEventListener)
+  return tmp->IsBlackForCC();
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsJSEventListener)
+  return tmp->IsBlackForCC();
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
+
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSEventListener)
   NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
   NS_INTERFACE_MAP_ENTRY(nsIJSEventListener)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsJSEventListener)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsJSEventListener)
 
+bool
+nsJSEventListener::IsBlackForCC()
+{
+  if ((mContext && mContext->GetScriptTypeID() ==
+         nsIProgrammingLanguage::JAVASCRIPT) &&
+      (!mScopeObject || !xpc_IsGrayGCThing(mScopeObject)) &&
+      (!mHandler || !xpc_IsGrayGCThing(mHandler))) {
+    nsIScriptGlobalObject* sgo =
+      static_cast<nsJSContext*>(mContext.get())->GetCachedGlobalObject();
+    return sgo && sgo->IsBlackForCC();
+  }
+  return false;
+}
+
 nsresult
 nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent)
 {
   nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mTarget);
   if (!target || !mContext || !mHandler)
     return NS_ERROR_FAILURE;
 
   nsresult rv;
--- a/dom/src/events/nsJSEventListener.h
+++ b/dom/src/events/nsJSEventListener.h
@@ -64,15 +64,18 @@ public:
   // nsIJSEventListener
   virtual void SetHandler(JSObject *aHandler);
 
   virtual PRInt64 SizeOf() const
   {
     return sizeof(*this);
   }
 
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsJSEventListener)
+  NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(nsJSEventListener)
+
 protected:
+  bool IsBlackForCC();
+
   nsCOMPtr<nsIAtom> mEventName;
 };
 
 #endif //nsJSEventListener_h__
 
--- a/dom/src/json/nsJSON.cpp
+++ b/dom/src/json/nsJSON.cpp
@@ -629,18 +629,16 @@ nsJSONListener::OnStopRequest(nsIRequest
   return ok ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsJSONListener::OnDataAvailable(nsIRequest *aRequest, nsISupports *aContext,
                                 nsIInputStream *aStream,
                                 PRUint32 aOffset, PRUint32 aLength)
 {
-  PRUint32 contentLength;
-  aStream->Available(&contentLength);
   nsresult rv = NS_OK;
 
   if (mNeedsConverter && mSniffBuffer.Length() < 4) {
     PRUint32 readCount = (aLength < 4) ? aLength : 4;
     rv = NS_ConsumeStream(aStream, readCount, mSniffBuffer);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (mSniffBuffer.Length() < 4)
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -3789,20 +3789,20 @@ WorkerPrivate::UpdateGCZealInternal(JSCo
 
 void
 WorkerPrivate::GarbageCollectInternal(JSContext* aCx, bool aShrinking,
                                       bool aCollectChildren)
 {
   AssertIsOnWorkerThread();
 
   if (aShrinking) {
-    JS_ShrinkingGC(aCx);
+    js::ShrinkingGC(aCx, js::gcreason::DOM_WORKER);
   }
   else {
-    JS_GC(aCx);
+    js::GCForReason(aCx, js::gcreason::DOM_WORKER);
   }
 
   if (aCollectChildren) {
     for (PRUint32 index = 0; index < mChildWorkers.Length(); index++) {
       mChildWorkers[index]->GarbageCollect(aCx, aShrinking);
     }
   }
 }
--- a/editor/libeditor/text/nsTextEditRules.cpp
+++ b/editor/libeditor/text/nsTextEditRules.cpp
@@ -481,17 +481,17 @@ GetTextNode(nsISelection *selection, nsE
   nsresult res = editor->GetStartNodeAndOffset(selection, getter_AddRefs(selNode), &selOffset);
   NS_ENSURE_SUCCESS(res, nsnull);
   if (!editor->IsTextNode(selNode)) {
     // Get an nsINode from the nsIDOMNode
     nsCOMPtr<nsINode> node = do_QueryInterface(selNode);
     // if node is null, return it to indicate there's no text
     NS_ENSURE_TRUE(node, nsnull);
     // This should be the root node, walk the tree looking for text nodes
-    nsNodeIterator iter(node, nsIDOMNodeFilter::SHOW_TEXT, nsnull, true);
+    nsNodeIterator iter(node, nsIDOMNodeFilter::SHOW_TEXT, nsnull);
     while (!editor->IsTextNode(selNode)) {
       if (NS_FAILED(res = iter.NextNode(getter_AddRefs(selNode))) || !selNode) {
         return nsnull;
       }
     }
   }
   return selNode.forget();
 }
--- a/gfx/layers/opengl/ContainerLayerOGL.cpp
+++ b/gfx/layers/opengl/ContainerLayerOGL.cpp
@@ -209,16 +209,17 @@ ContainerRender(Container* aContainer,
         aContainer->mSupportsComponentAlphaChildren = true;
       }
     }
 
     aContainer->gl()->PushViewportRect();
     framebufferRect -= childOffset; 
     aManager->CreateFBOWithTexture(framebufferRect,
                                    mode,
+                                   aPreviousFrameBuffer,
                                    &frameBuffer,
                                    &containerSurface);
     childOffset.x = visibleRect.x;
     childOffset.y = visibleRect.y;
   } else {
     frameBuffer = aPreviousFrameBuffer;
     aContainer->mSupportsComponentAlphaChildren = (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE) ||
       (aContainer->GetParent() && aContainer->GetParent()->SupportsComponentAlphaChildren());
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -1127,32 +1127,85 @@ void
 LayerManagerOGL::SetLayerProgramProjectionMatrix(const gfx3DMatrix& aMatrix)
 {
   FOR_EACH_LAYER_PROGRAM(lp) {
     lp->Activate();
     lp->SetProjectionMatrix(aMatrix);
   } FOR_EACH_LAYER_PROGRAM_END
 }
 
+static GLenum
+GetFrameBufferInternalFormat(GLContext* gl,
+                             GLuint aCurrentFrameBuffer,
+                             nsIWidget* aWidget)
+{
+  if (aCurrentFrameBuffer == 0) { // default framebuffer
+    return aWidget->GetGLFrameBufferFormat();
+  }
+  return LOCAL_GL_RGBA;
+}
+
+static bool
+AreFormatsCompatibleForCopyTexImage2D(GLenum aF1, GLenum aF2)
+{
+  // GL requires that the implementation has to handle copies between
+  // different formats, so all are "compatible".  GLES does not
+  // require that.
+#ifdef USE_GLES2
+  return (aF1 == aF2);
+#else
+  return true;
+#endif
+}
+
 void
 LayerManagerOGL::CreateFBOWithTexture(const nsIntRect& aRect, InitMode aInit,
+                                      GLuint aCurrentFrameBuffer,
                                       GLuint *aFBO, GLuint *aTexture)
 {
   GLuint tex, fbo;
 
   mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
   mGLContext->fGenTextures(1, &tex);
   mGLContext->fBindTexture(mFBOTextureTarget, tex);
   if (aInit == InitModeCopy) {
-    mGLContext->fCopyTexImage2D(mFBOTextureTarget,
-                                0,
-                                LOCAL_GL_RGBA,
-                                aRect.x, aRect.y,
-                                aRect.width, aRect.height,
-                                0);
+    // We're going to create an RGBA temporary fbo.  But to
+    // CopyTexImage() from the current framebuffer, the framebuffer's
+    // format has to be compatible with the new texture's.  So we
+    // check the format of the framebuffer here and take a slow path
+    // if it's incompatible.
+    GLenum format =
+      GetFrameBufferInternalFormat(gl(), aCurrentFrameBuffer, mWidget);
+    if (AreFormatsCompatibleForCopyTexImage2D(format, LOCAL_GL_RGBA)) {
+      mGLContext->fCopyTexImage2D(mFBOTextureTarget,
+                                  0,
+                                  LOCAL_GL_RGBA,
+                                  aRect.x, aRect.y,
+                                  aRect.width, aRect.height,
+                                  0);
+    } else {
+      // Curses, incompatible formats.  Take a slow path.
+      //
+      // XXX Technically CopyTexSubImage2D also has the requirement of
+      // matching formats, but it doesn't seem to affect us in the
+      // real world.
+      mGLContext->fTexImage2D(mFBOTextureTarget,
+                              0,
+                              LOCAL_GL_RGBA,
+                              aRect.width, aRect.height,
+                              0,
+                              LOCAL_GL_RGBA,
+                              LOCAL_GL_UNSIGNED_BYTE,
+                              NULL);
+      mGLContext->fCopyTexSubImage2D(mFBOTextureTarget,
+                                     0,    // level
+                                     0, 0, // offset
+                                     aRect.x, aRect.y,
+                                     aRect.width, aRect.height);
+    }
   } else {
     mGLContext->fTexImage2D(mFBOTextureTarget,
                             0,
                             LOCAL_GL_RGBA,
                             aRect.width, aRect.height,
                             0,
                             LOCAL_GL_RGBA,
                             LOCAL_GL_UNSIGNED_BYTE,
--- a/gfx/layers/opengl/LayerManagerOGL.h
+++ b/gfx/layers/opengl/LayerManagerOGL.h
@@ -303,16 +303,17 @@ public:
 
   /* Create a FBO backed by a texture; will leave the FBO
    * bound.  Note that the texture target type will be
    * of the type returned by FBOTextureTarget; different
    * shaders are required to sample from the different
    * texture types.
    */
   void CreateFBOWithTexture(const nsIntRect& aRect, InitMode aInit,
+                            GLuint aCurrentFrameBuffer,
                             GLuint *aFBO, GLuint *aTexture);
 
   GLuint QuadVBO() { return mQuadVBO; }
   GLintptr QuadVBOVertexOffset() { return 0; }
   GLintptr QuadVBOTexCoordOffset() { return sizeof(float)*4*2; }
   GLintptr QuadVBOFlippedTexCoordOffset() { return sizeof(float)*8*2; }
 
   void BindQuadVBO() {
--- a/gfx/skia/Makefile.in
+++ b/gfx/skia/Makefile.in
@@ -63,16 +63,17 @@ LOCAL_INCLUDES += \
 	-I$(srcdir)/include/effects \
 	$(NULL)
 
 VPATH += \
 	$(srcdir)/src/core \
 	$(srcdir)/src/ports \
 	$(srcdir)/src/opts \
 	$(srcdir)/src/effects \
+	$(srcdir)/src/utils \
 	$(NULL)
 
 EXPORTS_skia = \
 	include/core/Sk64.h \
 	include/core/SkAutoKern.h \
 	include/core/SkBitmap.h \
 	include/core/SkBlitRow.h \
 	include/core/SkBlitter.h \
@@ -312,16 +313,29 @@ CPPSRCS += \
 	SkMMapStream.cpp \
 	SkTime_Unix.cpp \
 	$(NULL)
 
 DEFINES += -DSK_BUILD_FOR_ANDROID_NDK
 OS_CXXFLAGS += $(CAIRO_FT_CFLAGS)
 endif
 
+ifeq (gtk2,$(MOZ_WIDGET_TOOLKIT))
+CPPSRCS += \
+	SkFontHost_FreeType.cpp \
+	SkFontHost_linux.cpp \
+	SkFontHost_gamma.cpp \
+	SkTime_Unix.cpp \
+	SkMMapStream.cpp \
+	SkOSFile.cpp \
+	$(NULL)
+
+OS_CXXFLAGS += $(MOZ_PANGO_CFLAGS)
+endif
+
 ifeq (windows,$(MOZ_WIDGET_TOOLKIT))
 EXPORTS_skia += \
 	include/config/sk_stdint.h \
 	include/ports/SkTypeface_win.h \
 	$(NULL)
 CPPSRCS += \
 	SkFontHost_win.cpp \
 	SkFontHost_sandbox_none.cpp \
--- a/gfx/thebes/gfxPlatformGtk.cpp
+++ b/gfx/thebes/gfxPlatformGtk.cpp
@@ -51,16 +51,18 @@
 #include "gfxContext.h"
 #include "gfxUserFontSet.h"
 #else
 #include <ft2build.h>
 #include FT_FREETYPE_H
 #include "gfxFT2Fonts.h"
 #endif
 
+#include "mozilla/gfx/2D.h"
+
 #include "cairo.h"
 #include <gtk/gtk.h>
 
 #include "gfxImageSurface.h"
 #ifdef MOZ_X11
 #include <gdk/gdkx.h>
 #include "gfxXlibSurface.h"
 #include "cairo-xlib.h"
@@ -78,16 +80,19 @@
 
 #define GDK_PIXMAP_SIZE_MAX 32767
 
 #ifndef MOZ_PANGO
 #include <ft2build.h>
 #include FT_FREETYPE_H
 #endif
 
+using namespace mozilla;
+using namespace mozilla::gfx;
+
 gfxFontconfigUtils *gfxPlatformGtk::sFontconfigUtils = nsnull;
 
 #ifndef MOZ_PANGO
 typedef nsDataHashtable<nsStringHashKey, nsRefPtr<FontFamily> > FontTable;
 typedef nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<gfxFontEntry> > > PrefFontTable;
 static FontTable *gPlatformFonts = NULL;
 static FontTable *gPlatformFontAliases = NULL;
 static PrefFontTable *gPrefFonts = NULL;
@@ -756,8 +761,28 @@ gfxPlatformGtk::GetGdkDrawable(gfxASurfa
     if (result) {
         SetGdkDrawable(target, result);
         return result;
     }
 #endif
 
     return NULL;
 }
+
+RefPtr<ScaledFont>
+gfxPlatformGtk::GetScaledFontForFont(gfxFont *aFont)
+{
+  NativeFont nativeFont;
+  nativeFont.mType = NATIVE_FONT_SKIA_FONT_FACE;
+  nativeFont.mFont = aFont;
+  RefPtr<ScaledFont> scaledFont =
+    Factory::CreateScaledFontForNativeFont(nativeFont, aFont->GetAdjustedSize());
+
+  return scaledFont;
+}
+
+bool
+gfxPlatformGtk::SupportsAzure(BackendType& aBackend)
+{
+  aBackend = BACKEND_SKIA;
+  return true;
+}
+
--- a/gfx/thebes/gfxPlatformGtk.h
+++ b/gfx/thebes/gfxPlatformGtk.h
@@ -61,16 +61,21 @@ public:
 
     static gfxPlatformGtk *GetPlatform() {
         return (gfxPlatformGtk*) gfxPlatform::GetPlatform();
     }
 
     already_AddRefed<gfxASurface> CreateOffscreenSurface(const gfxIntSize& size,
                                                          gfxASurface::gfxContentType contentType);
 
+    mozilla::RefPtr<mozilla::gfx::ScaledFont>
+      GetScaledFontForFont(gfxFont *aFont);
+
+    virtual bool SupportsAzure(mozilla::gfx::BackendType& aBackend);
+
     nsresult GetFontList(nsIAtom *aLangGroup,
                          const nsACString& aGenericFamily,
                          nsTArray<nsString>& aListOfFonts);
 
     nsresult UpdateFontList();
 
     nsresult ResolveFontName(const nsAString& aFontName,
                              FontResolverCallback aCallback,
--- a/ipc/glue/IPCMessageUtils.h
+++ b/ipc/glue/IPCMessageUtils.h
@@ -479,20 +479,18 @@ struct ParamTraits<mozilla::GraphicsFilt
     case gfxPattern::FILTER_GOOD:
     case gfxPattern::FILTER_BEST:
     case gfxPattern::FILTER_NEAREST:
     case gfxPattern::FILTER_BILINEAR:
     case gfxPattern::FILTER_GAUSSIAN:
       WriteParam(msg, int32(param));
       return;
 
-    default:
-      NS_RUNTIMEABORT("not reached");
-      return;
     }
+    NS_RUNTIMEABORT("not reached");
   }
 
   static bool Read(const Message* msg, void** iter, paramType* result)
   {
     int32 filter;
     if (!ReadParam(msg, iter, &filter))
       return false;
 
--- a/js/src/assembler/assembler/AbstractMacroAssembler.h
+++ b/js/src/assembler/assembler/AbstractMacroAssembler.h
@@ -28,17 +28,16 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef AbstractMacroAssembler_h
 #define AbstractMacroAssembler_h
 
 #include "assembler/wtf/Platform.h"
 #include "assembler/assembler/MacroAssemblerCodeRef.h"
 #include "assembler/assembler/CodeLocation.h"
-#include "jsstdint.h"
 
 #if ENABLE_ASSEMBLER
 
 namespace JSC {
 
 class LinkBuffer;
 class RepatchBuffer;
 
--- a/js/src/assembler/assembler/AssemblerBuffer.h
+++ b/js/src/assembler/assembler/AssemblerBuffer.h
@@ -33,17 +33,16 @@
 #include "assembler/wtf/Platform.h"
 
 #if ENABLE_ASSEMBLER
 
 #include <string.h>
 #include <limits.h>
 #include "assembler/jit/ExecutableAllocator.h"
 #include "assembler/wtf/Assertions.h"
-#include "jsstdint.h"
 
 namespace JSC {
 
     class AssemblerBuffer {
         static const int inlineCapacity = 256;
     public:
         AssemblerBuffer()
             : m_buffer(m_inlineBuffer)
--- a/js/src/assembler/assembler/X86Assembler.h
+++ b/js/src/assembler/assembler/X86Assembler.h
@@ -30,17 +30,16 @@
 #ifndef X86Assembler_h
 #define X86Assembler_h
 
 #include "assembler/wtf/Platform.h"
 
 #if ENABLE_ASSEMBLER && (WTF_CPU_X86 || WTF_CPU_X86_64)
 
 #include "AssemblerBuffer.h"
-#include "jsstdint.h"
 #include "assembler/wtf/Assertions.h"
 #include "js/Vector.h"
 
 #include "methodjit/Logging.h"
 #define IPFX  "        %s"
 #define ISPFX "        "
 #ifdef JS_METHODJIT_SPEW
 # define MAYBE_PAD (isOOLPath ? ">  " : "")
--- a/js/src/config/system-headers
+++ b/js/src/config/system-headers
@@ -263,16 +263,21 @@ frame/req.h
 freetype/freetype.h
 freetype/ftcache.h
 freetype/ftglyph.h
 freetype/ftsynth.h
 freetype/ftoutln.h
 freetype/ttnameid.h
 freetype/tttables.h
 freetype/t1tables.h
+freetype/ftlcdfil.h
+freetype/ftsizes.h
+freetype/ftadvanc.h
+freetype/ftbitmap.h
+freetype/ftxf86.h
 fribidi/fribidi.h
 FSp_fopen.h
 fstream
 fstream.h
 ft2build.h
 fts.h
 gconf/gconf-client.h
 Gdiplus.h
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -43,17 +43,16 @@
  */
 #ifdef HAVE_MEMORY_H
 #include <memory.h>
 #endif
 #include <new>
 #include <string.h>
 
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsutil.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsfun.h"
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -52,17 +52,16 @@
  * This parser attempts no error recovery.
  */
 
 #include "frontend/Parser.h"
 
 #include <stdlib.h>
 #include <string.h>
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsutil.h"
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsfun.h"
 #include "jsgc.h"
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -48,17 +48,16 @@
 #include <math.h>
 #ifdef HAVE_MEMORY_H
 #include <memory.h>
 #endif
 #include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsutil.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsexn.h"
 #include "jsnum.h"
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -33,30 +33,47 @@
  * 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 ***** */
 
 #include <stdio.h>
+#include <ctype.h>
 
 #include "jscntxt.h"
 #include "jscrashformat.h"
 #include "jscrashreport.h"
 #include "jsprf.h"
 #include "jsprobes.h"
 #include "jsutil.h"
 #include "prmjtime.h"
 
 #include "gc/Statistics.h"
 
 namespace js {
 namespace gcstats {
 
+static const char *
+ExplainReason(gcreason::Reason reason)
+{
+    switch (reason) {
+#define SWITCH_REASON(name)                     \
+        case gcreason::name:                    \
+          return #name;
+        GCREASONS(SWITCH_REASON)
+
+        default:
+          JS_NOT_REACHED("bad GC reason");
+          return "?";
+#undef SWITCH_REASON
+    }
+}
+
 Statistics::ColumnInfo::ColumnInfo(const char *title, double t, double total)
   : title(title)
 {
     JS_snprintf(str, sizeof(str), "%.1f", t);
     JS_snprintf(totalStr, sizeof(totalStr), "%.1f", total);
     width = 6;
 }
 
@@ -112,18 +129,18 @@ Statistics::makeTable(ColumnInfo *cols)
     cols[i++] = ColumnInfo("-Chu", counts[STAT_DESTROY_CHUNK]);
 
     cols[i++] = ColumnInfo("Reason", ExplainReason(triggerReason));
 
     JS_ASSERT(i == NUM_COLUMNS);
 }
 
 Statistics::Statistics(JSRuntime *rt)
-  : runtime(rt)
-  , triggerReason(PUBLIC_API) //dummy reason to satisfy makeTable
+  : runtime(rt),
+    triggerReason(gcreason::NO_REASON)
 {
     PodArrayZero(counts);
     PodArrayZero(totals);
 
     startupTime = PRMJ_Now();
 
     char *env = getenv("MOZ_GCTIMER");
     if (!env || strcmp(env, "none") == 0) {
@@ -173,17 +190,17 @@ Statistics::~Statistics()
 
 struct GCCrashData
 {
     int isRegen;
     int isCompartment;
 };
 
 void
-Statistics::beginGC(JSCompartment *comp, Reason reason)
+Statistics::beginGC(JSCompartment *comp, gcreason::Reason reason)
 {
     compartment = comp;
 
     PodArrayZero(phaseStarts);
     PodArrayZero(phaseEnds);
     PodArrayZero(phaseTimes);
 
     triggerReason = reason;
@@ -271,17 +288,16 @@ Statistics::endGC()
     crash::SnapshotGCStack();
 
     for (int i = 0; i < PHASE_LIMIT; i++)
         totals[i] += phaseTimes[i];
 
     if (JSAccumulateTelemetryDataCallback cb = runtime->telemetryCallback) {
         (*cb)(JS_TELEMETRY_GC_REASON, triggerReason);
         (*cb)(JS_TELEMETRY_GC_IS_COMPARTMENTAL, compartment ? 1 : 0);
-        (*cb)(JS_TELEMETRY_GC_IS_SHAPE_REGEN, 0);
         (*cb)(JS_TELEMETRY_GC_MS, t(PHASE_GC));
         (*cb)(JS_TELEMETRY_GC_MARK_MS, t(PHASE_MARK));
         (*cb)(JS_TELEMETRY_GC_SWEEP_MS, t(PHASE_SWEEP));
     }
 
     if (JSGCFinishedCallback cb = runtime->gcFinishedCallback) {
         char buffer[1024];
         statsToString(buffer, sizeof(buffer));
--- a/js/src/gc/Statistics.h
+++ b/js/src/gc/Statistics.h
@@ -37,50 +37,25 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jsgc_statistics_h___
 #define jsgc_statistics_h___
 
 #include <string.h>
 
+#include "jsfriendapi.h"
 #include "jspubtd.h"
 #include "jsutil.h"
 
 struct JSCompartment;
 
 namespace js {
 namespace gcstats {
 
-enum Reason {
-    PUBLIC_API,
-    MAYBEGC,
-    LASTCONTEXT,
-    DESTROYCONTEXT,
-    LASTDITCH,
-    TOOMUCHMALLOC,
-    ALLOCTRIGGER,
-    CHUNK,
-    SHAPE,
-    REFILL
-};
-static const int NUM_REASONS = REFILL + 1;
-
-static inline const char *
-ExplainReason(Reason r)
-{
-    static const char *strs[] = {"  API", "Maybe", "LastC", "DestC", "LastD",
-                                 "Mallc", "Alloc", "Chunk", "Shape", "Refil"};
-
-    JS_ASSERT(strcmp(strs[SHAPE], "Shape") == 0 &&
-              sizeof(strs) / sizeof(strs[0]) == NUM_REASONS);
-
-    return strs[r];
-}
-
 enum Phase {
     PHASE_GC,
     PHASE_MARK,
     PHASE_SWEEP,
     PHASE_SWEEP_OBJECT,
     PHASE_SWEEP_STRING,
     PHASE_SWEEP_SCRIPT,
     PHASE_SWEEP_SHAPE,
@@ -99,17 +74,17 @@ enum Stat {
 
     STAT_LIMIT
 };
 
 struct Statistics {
     Statistics(JSRuntime *rt);
     ~Statistics();
 
-    void beginGC(JSCompartment *comp, Reason reason);
+    void beginGC(JSCompartment *comp, gcreason::Reason reason);
     void endGC();
 
     void beginPhase(Phase phase);
     void endPhase(Phase phase);
 
     void count(Stat s) {
         JS_ASSERT(s < STAT_LIMIT);
         counts[s]++;
@@ -118,17 +93,17 @@ struct Statistics {
   private:
     JSRuntime *runtime;
 
     uint64_t startupTime;
 
     FILE *fp;
     bool fullFormat;
 
-    Reason triggerReason;
+    gcreason::Reason triggerReason;
     JSCompartment *compartment;
 
     uint64_t phaseStarts[PHASE_LIMIT];
     uint64_t phaseEnds[PHASE_LIMIT];
     uint64_t phaseTimes[PHASE_LIMIT];
     uint64_t totals[PHASE_LIMIT];
     unsigned int counts[STAT_LIMIT];
 
@@ -136,32 +111,33 @@ struct Statistics {
     double total(Phase phase);
     double beginDelay(Phase phase1, Phase phase2);
     double endDelay(Phase phase1, Phase phase2);
     void printStats();
     void statsToString(char *buffer, size_t size);
 
     struct ColumnInfo {
         const char *title;
-        char str[12];
-        char totalStr[12];
+        char str[32];
+        char totalStr[32];
         int width;
 
         ColumnInfo() {}
         ColumnInfo(const char *title, double t, double total);
         ColumnInfo(const char *title, double t);
         ColumnInfo(const char *title, unsigned int data);
         ColumnInfo(const char *title, const char *data);
     };
 
     void makeTable(ColumnInfo *cols);
 };
 
 struct AutoGC {
-    AutoGC(Statistics &stats, JSCompartment *comp, Reason reason JS_GUARD_OBJECT_NOTIFIER_PARAM)
+    AutoGC(Statistics &stats, JSCompartment *comp, gcreason::Reason reason
+           JS_GUARD_OBJECT_NOTIFIER_PARAM)
       : stats(stats) { JS_GUARD_OBJECT_NOTIFIER_INIT; stats.beginGC(comp, reason); }
     ~AutoGC() { stats.endGC(); }
 
     Statistics &stats;
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 struct AutoPhase {
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/regress-bug720680.js
@@ -0,0 +1,15 @@
+// |jit-test| error: InternalError
+version(0);
+eval("\
+function TimeFromYear( y ) {}\
+addTestCase( -2208988800000 );\
+function addTestCase( t ) {\
+  var start = TimeFromYear((addTestCase(addTestCase << t, 0)));\
+    new TestCase( \
+                  SECTION,\
+                  '(new Date('+d+')).getUTCDay()',\
+                  WeekDay((d)),\
+                  (new Date(let ({ stop } = 'properties.length' )('/ab[c\\\n]/'))).getUTCDay() \
+                );\
+}\
+");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testTypedArraySetConversion.js
@@ -0,0 +1,15 @@
+var n = 16;
+var a = new Int32Array(n);
+for (var i = 0; i < n; ++i) {
+    a[i] = i;
+}
+var b = new Int32Array(n);
+for (var i = 0; i < n; ++i) {
+    b[i] = i * 2;
+}
+
+a.set(b, 0.99);
+
+for (var i = 0; i < n; ++i) {
+    assertEq(a[i], b[i]);
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/in.js
@@ -0,0 +1,21 @@
+function f(arr, b) {
+    var res = "";
+    var a;
+    if (b)
+        a = arr;
+    for (var i=100; i>-200; i--) {
+        if (i in a) {
+            res += i;
+        }
+    }
+    return res;
+}
+
+assertEq(f([1, , 2, 3], true), "320");
+
+try {
+    f([1, , 2, 3], false);
+    assertEq(0, 1);
+} catch(e) {
+    assertEq(e instanceof TypeError, true);
+}
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -42,17 +42,16 @@
  * JavaScript API.
  */
 #include <ctype.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsutil.h"
 #include "jsclist.h"
 #include "jsdhash.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
@@ -734,16 +733,17 @@ JSRuntime::JSRuntime()
     gcVerifyData(NULL),
     gcChunkAllocationSinceLastGC(false),
     gcNextFullGCTime(0),
     gcJitReleaseTime(0),
     gcMode(JSGC_MODE_GLOBAL),
     gcIsNeeded(0),
     gcWeakMapList(NULL),
     gcStats(thisFromCtor()),
+    gcTriggerReason(gcreason::NO_REASON),
     gcTriggerCompartment(NULL),
     gcCurrentCompartment(NULL),
     gcCheckCompartment(NULL),
     gcPoke(false),
     gcMarkAndSweep(false),
     gcRunning(false),
 #ifdef JS_GC_ZEAL
     gcZeal_(0),
@@ -2870,17 +2870,17 @@ JS_PUBLIC_API(void)
 JS_CompartmentGC(JSContext *cx, JSCompartment *comp)
 {
     AssertNoGC(cx);
 
     /* We cannot GC the atoms compartment alone; use a full GC instead. */
     JS_ASSERT(comp != cx->runtime->atomsCompartment);
 
     js::gc::VerifyBarriers(cx, true);
-    js_GC(cx, comp, GC_NORMAL, gcstats::PUBLIC_API);
+    js_GC(cx, comp, GC_NORMAL, gcreason::API);
 }
 
 JS_PUBLIC_API(void)
 JS_GC(JSContext *cx)
 {
     JS_CompartmentGC(cx, NULL);
 }
 
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -98,17 +98,16 @@
  */
 #include <limits.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "mozilla/RangedPtr.h"
 
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsutil.h"
 
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsversion.h"
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -42,17 +42,16 @@
  */
 #include <stdlib.h>
 #include <string.h>
 
 #include "mozilla/RangedPtr.h"
 #include "mozilla/Util.h"
 
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsutil.h"
 #include "jshash.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsgc.h"
 #include "jsgcmark.h"
--- a/js/src/jsbool.cpp
+++ b/js/src/jsbool.cpp
@@ -36,17 +36,16 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 /*
  * JS boolean implementation.
  */
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsutil.h"
 #include "jsapi.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsinfer.h"
 #include "jsversion.h"
 #include "jslock.h"
--- a/js/src/jsclone.h
+++ b/js/src/jsclone.h
@@ -36,17 +36,16 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jsclone_h___
 #define jsclone_h___
 
 #include "jsapi.h"
 #include "jscntxt.h"
-#include "jsstdint.h"
 
 #include "js/HashTable.h"
 #include "js/Vector.h"
 
 namespace js {
 
 bool
 WriteStructuredClone(JSContext *cx, const Value &v, uint64_t **bufp, size_t *nbytesp,
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -49,18 +49,16 @@
 #include <stdlib.h>
 #include <string.h>
 #ifdef ANDROID
 # include <android/log.h>
 # include <fstream>
 # include <string>
 #endif  // ANDROID
 
-#include "jsstdint.h"
-
 #include "jstypes.h"
 #include "jsutil.h"
 #include "jsclist.h"
 #include "jsprf.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsdbgapi.h"
@@ -318,23 +316,23 @@ js_DestroyContext(JSContext *cx, JSDestr
 
 #ifdef JS_THREADSAFE
         /* Destroying a context implicitly calls JS_EndRequest(). */
         while (cx->outstandingRequests != 0)
             JS_EndRequest(cx);
 #endif
 
         if (last) {
-            js_GC(cx, NULL, GC_NORMAL, gcstats::LASTCONTEXT);
+            js_GC(cx, NULL, GC_NORMAL, gcreason::LAST_CONTEXT);
 
             /* Take the runtime down, now that it has no contexts or atoms. */
             JS_LOCK_GC(rt);
         } else {
             if (mode == JSDCM_FORCE_GC)
-                js_GC(cx, NULL, GC_NORMAL, gcstats::DESTROYCONTEXT);
+                js_GC(cx, NULL, GC_NORMAL, gcreason::DESTROY_CONTEXT);
             else if (mode == JSDCM_MAYBE_GC)
                 JS_MaybeGC(cx);
 
             JS_LOCK_GC(rt);
         }
     }
 #ifdef JS_THREADSAFE
     rt->gcHelperThread.waitBackgroundSweepEnd();
@@ -1174,17 +1172,17 @@ bool
 JSContext::runningWithTrustedPrincipals() const
 {
     return !compartment || compartment->principals == runtime->trustedPrincipals();
 }
 
 JS_FRIEND_API(void)
 JSRuntime::onTooMuchMalloc()
 {
-    TriggerGC(this, gcstats::TOOMUCHMALLOC);
+    TriggerGC(this, gcreason::TOO_MUCH_MALLOC);
 }
 
 JS_FRIEND_API(void *)
 JSRuntime::onOutOfMemory(void *p, size_t nbytes, JSContext *cx)
 {
     /*
      * Retry when we are done with the background sweeping and have stopped
      * all the allocations and released the empty GC chunks.
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -317,17 +317,17 @@ struct JSRuntime
     int64_t             gcJitReleaseTime;
     JSGCMode            gcMode;
     volatile uintptr_t  gcBarrierFailed;
     volatile uintptr_t  gcIsNeeded;
     js::WeakMapBase     *gcWeakMapList;
     js::gcstats::Statistics gcStats;
 
     /* The reason that an interrupt-triggered GC should be called. */
-    js::gcstats::Reason gcTriggerReason;
+    js::gcreason::Reason gcTriggerReason;
 
     /* Pre-allocated space for the GC mark stack. */
     uintptr_t           gcMarkStackArray[js::MARK_STACK_LENGTH];
 
     /*
      * Compartment that triggered GC. If more than one Compatment need GC,
      * gcTriggerCompartment is reset to NULL and a global GC is performed.
      */
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -55,17 +55,16 @@
 #include <locale.h>
 #include <math.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "mozilla/Util.h"
 
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsprf.h"
 #include "prmjtime.h"
 #include "jsutil.h"
 #include "jsapi.h"
 #include "jsversion.h"
 #include "jscntxt.h"
 #include "jsdate.h"
 #include "jsinterp.h"
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -41,17 +41,16 @@
 
 /*
  * JS debugging API.
  */
 #include <string.h>
 #include <stdarg.h>
 #include "jsprvtd.h"
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsutil.h"
 #include "jsclist.h"
 #include "jsapi.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsdbgapi.h"
 #include "jsfun.h"
 #include "jsgc.h"
--- a/js/src/jsdhash.cpp
+++ b/js/src/jsdhash.cpp
@@ -41,17 +41,16 @@
 /*
  * Double hashing implementation.
  *
  * Try to keep this file in sync with xpcom/glue/pldhash.cpp.
  */
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include "jsstdint.h"
 #include "jsdhash.h"
 #include "jsutil.h"
 
 using namespace js;
 
 #ifdef JS_DHASHMETER
 # if defined MOZILLA_CLIENT && defined DEBUG_XXXbrendan
 #  include "nsTraceMalloc.h"
--- a/js/src/jsdtoa.cpp
+++ b/js/src/jsdtoa.cpp
@@ -36,17 +36,16 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 /*
  * Portable double to alphanumeric string and back converters.
  */
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsdtoa.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jsprvtd.h"
 #include "jsnum.h"
 #include "jslibmath.h"
 #include "jscntxt.h"
 
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -42,17 +42,16 @@
  * JS standard exception implementation.
  */
 #include <stdlib.h>
 #include <string.h>
 
 #include "mozilla/Util.h"
 
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsutil.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsexn.h"
 #include "jsfun.h"
 #include "jsgc.h"
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -123,19 +123,25 @@ JS_NewObjectWithUniqueType(JSContext *cx
 {
     JSObject *obj = JS_NewObject(cx, clasp, proto, parent);
     if (!obj || !obj->setSingletonType(cx))
         return NULL;
     return obj;
 }
 
 JS_FRIEND_API(void)
-JS_ShrinkingGC(JSContext *cx)
+js::GCForReason(JSContext *cx, gcreason::Reason reason)
 {
-    js_GC(cx, NULL, GC_SHRINK, gcstats::PUBLIC_API);
+    js_GC(cx, NULL, GC_NORMAL, reason);
+}
+
+JS_FRIEND_API(void)
+js::ShrinkingGC(JSContext *cx, gcreason::Reason reason)
+{
+    js_GC(cx, NULL, GC_SHRINK, reason);
 }
 
 JS_FRIEND_API(void)
 JS_ShrinkGCBuffers(JSRuntime *rt)
 {
     ShrinkGCBuffers(rt);
 }
 
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -68,19 +68,16 @@ JS_SplicePrototype(JSContext *cx, JSObje
 
 extern JS_FRIEND_API(JSObject *)
 JS_NewObjectWithUniqueType(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent);
 
 extern JS_FRIEND_API(uint32_t)
 JS_ObjectCountDynamicSlots(JSObject *obj);
 
 extern JS_FRIEND_API(void)
-JS_ShrinkingGC(JSContext *cx);
-
-extern JS_FRIEND_API(void)
 JS_ShrinkGCBuffers(JSRuntime *rt);
 
 extern JS_FRIEND_API(size_t)
 JS_GetE4XObjectsCreated(JSContext *cx);
 
 extern JS_FRIEND_API(size_t)
 JS_SetProtoCalled(JSContext *cx);
 
@@ -96,17 +93,16 @@ JS_NondeterministicGetWeakMapKeys(JSCont
  * process. Uses bounded stack space.
  */
 extern JS_FRIEND_API(void)
 JS_TraceShapeCycleCollectorChildren(JSTracer *trc, void *shape);
 
 enum {
     JS_TELEMETRY_GC_REASON,
     JS_TELEMETRY_GC_IS_COMPARTMENTAL,
-    JS_TELEMETRY_GC_IS_SHAPE_REGEN,
     JS_TELEMETRY_GC_MS,
     JS_TELEMETRY_GC_MARK_MS,
     JS_TELEMETRY_GC_SWEEP_MS
 };
 
 typedef void
 (* JSAccumulateTelemetryDataCallback)(int id, uint32_t sample);
 
@@ -567,16 +563,66 @@ TriggerOperationCallback(JSRuntime *rt);
 class SystemAllocPolicy;
 typedef Vector<JSCompartment*, 0, SystemAllocPolicy> CompartmentVector;
 extern JS_FRIEND_API(const CompartmentVector&)
 GetRuntimeCompartments(JSRuntime *rt);
 
 extern JS_FRIEND_API(size_t)
 SizeOfJSContext();
 
+#define GCREASONS(D)                            \
+    /* Reasons internal to the JS engine */     \
+    D(API)                                      \
+    D(MAYBEGC)                                  \
+    D(LAST_CONTEXT)                             \
+    D(DESTROY_CONTEXT)                          \
+    D(LAST_DITCH)                               \
+    D(TOO_MUCH_MALLOC)                          \
+    D(ALLOC_TRIGGER)                            \
+    D(UNUSED1) /* was CHUNK */                  \
+    D(UNUSED2) /* was SHAPE */                  \
+    D(UNUSED3) /* was REFILL */                 \
+                                                \
+    /* Reasons from Firefox */                  \
+    D(DOM_WINDOW_UTILS)                         \
+    D(COMPONENT_UTILS)                          \
+    D(MEM_PRESSURE)                             \
+    D(CC_WAITING)                               \
+    D(CC_FORCED)                                \
+    D(LOAD_END)                                 \
+    D(POST_COMPARTMENT)                         \
+    D(PAGE_HIDE)                                \
+    D(NSJSCONTEXT_DESTROY)                      \
+    D(SET_NEW_DOCUMENT)                         \
+    D(SET_DOC_SHELL)                            \
+    D(DOM_UTILS)                                \
+    D(DOM_IPC)                                  \
+    D(DOM_WORKER)                               \
+    D(INTER_SLICE_GC)                           \
+    D(REFRESH_FRAME)
+
+namespace gcreason {
+
+/* GCReasons will end up looking like JSGC_MAYBEGC */
+enum Reason {
+#define MAKE_REASON(name) name,
+    GCREASONS(MAKE_REASON)
+#undef MAKE_REASON
+    NO_REASON,
+    NUM_REASONS
+};
+
+} /* namespace gcreason */
+
+extern JS_FRIEND_API(void)
+GCForReason(JSContext *cx, gcreason::Reason reason);
+
+extern JS_FRIEND_API(void)
+ShrinkingGC(JSContext *cx, gcreason::Reason reason);
+
 extern JS_FRIEND_API(bool)
 IsIncrementalBarrierNeeded(JSRuntime *rt);
 
 extern JS_FRIEND_API(bool)
 IsIncrementalBarrierNeeded(JSContext *cx);
 
 extern JS_FRIEND_API(void)
 IncrementalReferenceBarrier(void *ptr);
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -41,17 +41,16 @@
 /*
  * JS function support.
  */
 #include <string.h>
 
 #include "mozilla/Util.h"
 
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsutil.h"
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsfun.h"
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -50,17 +50,16 @@
  * mark bit, finalizer type index, etc.
  *
  * XXX swizzle page to freelist for better locality of reference
  */
 #include <math.h>
 #include <string.h>     /* for memset used when DEBUG */
 
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsutil.h"
 #include "jshash.h"
 #include "jsclist.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jsatom.h"
 #include "jscompartment.h"
 #include "jscrashreport.h"
@@ -748,17 +747,17 @@ Chunk::allocateArena(JSCompartment *comp
     aheader->init(comp, thingKind);
     if (JS_UNLIKELY(!hasAvailableArenas()))
         removeFromAvailableList();
 
     Probes::resizeHeap(comp, rt->gcBytes, rt->gcBytes + ArenaSize);
     rt->gcBytes += ArenaSize;
     comp->gcBytes += ArenaSize;
     if (comp->gcBytes >= comp->gcTriggerBytes)
-        TriggerCompartmentGC(comp, gcstats::ALLOCTRIGGER);
+        TriggerCompartmentGC(comp, gcreason::ALLOC_TRIGGER);
 
     return aheader;
 }
 
 inline void
 Chunk::addArenaToFreeList(JSRuntime *rt, ArenaHeader *aheader)
 {
     JS_ASSERT(!aheader->allocated());
@@ -1686,17 +1685,17 @@ ArenaLists::finalizeIonCode(JSContext *c
 
 static void
 RunLastDitchGC(JSContext *cx)
 {
     JSRuntime *rt = cx->runtime;
 
     /* The last ditch GC preserves all atoms. */
     AutoKeepAtoms keep(rt);
-    js_GC(cx, rt->gcTriggerCompartment, GC_NORMAL, gcstats::LASTDITCH);
+    js_GC(cx, rt->gcTriggerCompartment, GC_NORMAL, gcreason::LAST_DITCH);
 }
 
 /* static */ void *
 ArenaLists::refillFreeList(JSContext *cx, AllocKind thingKind)
 {
     JS_ASSERT(cx->compartment->arenas.freeLists[thingKind].isEmpty());
 
     JSCompartment *comp = cx->compartment;
@@ -2189,32 +2188,32 @@ MarkRuntime(JSTracer *trc)
     if (!IS_GC_MARKING_TRACER(trc)) {
         /* We don't want to miss these when called from TraceRuntime. */
         if (JSTraceDataOp op = rt->gcGrayRootsTraceOp)
             (*op)(trc, rt->gcGrayRootsData);
     }
 }
 
 void
-TriggerGC(JSRuntime *rt, gcstats::Reason reason)
+TriggerGC(JSRuntime *rt, gcreason::Reason reason)
 {
     JS_ASSERT(rt->onOwnerThread());
 
     if (rt->gcRunning || rt->gcIsNeeded)
         return;
 
     /* Trigger the GC when it is safe to call an operation callback. */
     rt->gcIsNeeded = true;
     rt->gcTriggerCompartment = NULL;
     rt->gcTriggerReason = reason;
     rt->triggerOperationCallback();
 }
 
 void
-TriggerCompartmentGC(JSCompartment *comp, gcstats::Reason reason)
+TriggerCompartmentGC(JSCompartment *comp, gcreason::Reason reason)
 {
     JSRuntime *rt = comp->rt;
     JS_ASSERT(!rt->gcRunning);
 
     if (rt->gcZeal()) {
         TriggerGC(rt, reason);
         return;
     }
@@ -2250,42 +2249,42 @@ TriggerCompartmentGC(JSCompartment *comp
 
 void
 MaybeGC(JSContext *cx)
 {
     JSRuntime *rt = cx->runtime;
     JS_ASSERT(rt->onOwnerThread());
 
     if (rt->gcZeal()) {
-        js_GC(cx, NULL, GC_NORMAL, gcstats::MAYBEGC);
+        js_GC(cx, NULL, GC_NORMAL, gcreason::MAYBEGC);
         return;
     }
 
     JSCompartment *comp = cx->compartment;
     if (rt->gcIsNeeded) {
-        js_GC(cx, (comp == rt->gcTriggerCompartment) ? comp : NULL, GC_NORMAL, gcstats::MAYBEGC);
+        js_GC(cx, (comp == rt->gcTriggerCompartment) ? comp : NULL, GC_NORMAL, gcreason::MAYBEGC);
         return;
     }
 
     if (comp->gcBytes > 8192 && comp->gcBytes >= 3 * (comp->gcTriggerBytes / 4)) {
-        js_GC(cx, (rt->gcMode == JSGC_MODE_COMPARTMENT) ? comp : NULL, GC_NORMAL, gcstats::MAYBEGC);
+        js_GC(cx, (rt->gcMode == JSGC_MODE_COMPARTMENT) ? comp : NULL, GC_NORMAL, gcreason::MAYBEGC);
         return;
     }
 
     /*
      * Access to the counters and, on 32 bit, setting gcNextFullGCTime below
      * is not atomic and a race condition could trigger or suppress the GC. We
      * tolerate this.
      */
     int64_t now = PRMJ_Now();
     if (rt->gcNextFullGCTime && rt->gcNextFullGCTime <= now) {
         if (rt->gcChunkAllocationSinceLastGC ||
             rt->gcNumArenasFreeCommitted > FreeCommittedArenasThreshold)
         {
-            js_GC(cx, NULL, GC_SHRINK, gcstats::MAYBEGC);
+            js_GC(cx, NULL, GC_SHRINK, gcreason::MAYBEGC);
         } else {
             rt->gcNextFullGCTime = now + GC_IDLE_FULL_SPAN;
         }
     }
 }
 
 static void
 DecommitArenasFromAvailableList(JSRuntime *rt, Chunk **availableListHeadp)
@@ -3024,17 +3023,17 @@ GCCycle(JSContext *cx, JSCompartment *co
     rt->setGCLastBytes(rt->gcBytes, gckind);
     rt->gcCurrentCompartment = NULL;
 
     for (CompartmentsIter c(rt); !c.done(); c.next())
         c->setGCLastBytes(c->gcBytes, gckind);
 }
 
 void
-js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind, gcstats::Reason reason)
+js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind, gcreason::Reason reason)
 {
     JSRuntime *rt = cx->runtime;
     JS_AbortIfWrongThread(rt);
 
 #ifdef JS_GC_ZEAL
     struct AutoVerifyBarriers {
         JSContext *cx;
         bool inVerify;
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -1383,21 +1383,21 @@ namespace js {
 extern void
 TraceRuntime(JSTracer *trc);
 
 extern JS_FRIEND_API(void)
 MarkContext(JSTracer *trc, JSContext *acx);
 
 /* Must be called with GC lock taken. */
 extern void
-TriggerGC(JSRuntime *rt, js::gcstats::Reason reason);
+TriggerGC(JSRuntime *rt, js::gcreason::Reason reason);
 
 /* Must be called with GC lock taken. */
 extern void
-TriggerCompartmentGC(JSCompartment *comp, js::gcstats::Reason reason);
+TriggerCompartmentGC(JSCompartment *comp, js::gcreason::Reason reason);
 
 extern void
 MaybeGC(JSContext *cx);
 
 extern void
 ShrinkGCBuffers(JSRuntime *rt);
 
 } /* namespace js */
@@ -1410,17 +1410,17 @@ typedef enum JSGCInvocationKind {
     GC_NORMAL           = 0,
 
     /* Minimize GC triggers and release empty GC chunks right away. */
     GC_SHRINK             = 1
 } JSGCInvocationKind;
 
 /* Pass NULL for |comp| to get a full GC. */
 extern void
-js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind, js::gcstats::Reason r);
+js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind, js::gcreason::Reason r);
 
 namespace js {
 
 #ifdef JS_THREADSAFE
 
 class GCHelperThread {
     enum State {
         IDLE,
--- a/js/src/jsgcchunk.cpp
+++ b/js/src/jsgcchunk.cpp
@@ -28,17 +28,16 @@
  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include <stdlib.h>
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsgcchunk.h"
 
 #ifdef XP_WIN
 # include "jswin.h"
 
 # ifdef _MSC_VER
 #  pragma warning( disable: 4267 4996 4146 )
 # endif
--- a/js/src/jshash.cpp
+++ b/js/src/jshash.cpp
@@ -38,17 +38,16 @@
  * ***** END LICENSE BLOCK ***** */
 
 /*
  * PR hash table package.
  */
 #include <stdlib.h>
 #include <string.h>
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsutil.h"
 #include "jshash.h"
 
 using namespace js;
 
 /* Compute the number of buckets in ht */
 #define NBUCKETS(ht)    JS_BIT(JS_HASH_BITS - (ht)->shift)
 
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -40,17 +40,16 @@
 
 /*
  * JavaScript bytecode interpreter.
  */
 #include <stdio.h>
 #include <string.h>
 #include <math.h>
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsutil.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsdate.h"
@@ -828,17 +827,17 @@ js::LooselyEqual(JSContext *cx, const Va
         if (lval.isString()) {
             JSString *l = lval.toString();
             JSString *r = rval.toString();
             return EqualStrings(cx, l, r, result);
         }
 
         if (lval.isDouble()) {
             double l = lval.toDouble(), r = rval.toDouble();
-            *result = JSDOUBLE_COMPARE(l, ==, r, false);
+            *result = (l == r);
             return true;
         }
 
         if (lval.isObject()) {
             JSObject *l = &lval.toObject();
             JSObject *r = &rval.toObject();
 
             if (JSEqualityOp eq = l->getClass()->ext.equality) {
@@ -879,29 +878,29 @@ js::LooselyEqual(JSContext *cx, const Va
         JSString *l = lvalue.toString();
         JSString *r = rvalue.toString();
         return EqualStrings(cx, l, r, result);
     }
 
     double l, r;
     if (!ToNumber(cx, lvalue, &l) || !ToNumber(cx, rvalue, &r))
         return false;
-    *result = JSDOUBLE_COMPARE(l, ==, r, false);
+    *result = (l == r);
     return true;
 }
 
 bool
 js::StrictlyEqual(JSContext *cx, const Value &lref, const Value &rref, bool *equal)
 {
     Value lval = lref, rval = rref;
     if (SameType(lval, rval)) {
         if (lval.isString())
             return EqualStrings(cx, lval.toString(), rval.toString(), equal);
         if (lval.isDouble()) {
-            *equal = JSDOUBLE_COMPARE(lval.toDouble(), ==, rval.toDouble(), JS_FALSE);
+            *equal = (lval.toDouble() == rval.toDouble());
             return true;
         }
         if (lval.isObject()) {
             *equal = lval.toObject() == rval.toObject();
             return true;
         }
         if (lval.isUndefined()) {
             *equal = true;
@@ -909,23 +908,23 @@ js::StrictlyEqual(JSContext *cx, const V
         }
         *equal = lval.payloadAsRawUint32() == rval.payloadAsRawUint32();
         return true;
     }
 
     if (lval.isDouble() && rval.isInt32()) {
         double ld = lval.toDouble();
         double rd = rval.toInt32();
-        *equal = JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE);
+        *equal = (ld == rd);
         return true;
     }
     if (lval.isInt32() && rval.isDouble()) {
         double ld = lval.toInt32();
         double rd = rval.toDouble();
-        *equal = JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE);
+        *equal = (ld == rd);
         return true;
     }
 
     *equal = false;
     return true;
 }
 
 static inline bool
@@ -2348,17 +2347,17 @@ END_CASE(JSOP_CASE)
                 int32_t result;                                               \
                 if (!CompareStrings(cx, l, r, &result))                       \
                     goto error;                                               \
                 cond = result OP 0;                                           \
             } else {                                                          \
                 double l, r;                                                  \
                 if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))       \
                     goto error;                                               \
-                cond = JSDOUBLE_COMPARE(l, OP, r, false);                     \
+                cond = (l OP r);                                              \
             }                                                                 \
         }                                                                     \
         TRY_BRANCH_AFTER_COND(cond, 2);                                       \
         regs.sp[-2].setBoolean(cond);                                         \
         regs.sp--;                                                            \
     JS_END_MACRO
 
 BEGIN_CASE(JSOP_LT)
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -39,17 +39,16 @@
  * ***** END LICENSE BLOCK ***** */
 
 /*
  * JavaScript iterators.
  */
 #include "mozilla/Util.h"
 
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsutil.h"
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsexn.h"
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -37,17 +37,16 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 /*
  * JS math package.
  */
 #include <stdlib.h>
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "prmjtime.h"
 #include "jsapi.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jslock.h"
 #include "jsmath.h"
 #include "jsnum.h"
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -50,17 +50,16 @@
 #include <limits.h>
 #include <math.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "mozilla/RangedPtr.h"
 
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsutil.h"
 #include "jsapi.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsdtoa.h"
 #include "jsgc.h"
 #include "jsinterp.h"
--- a/js/src/jsnum.h
+++ b/js/src/jsnum.h
@@ -37,17 +37,16 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jsnum_h___
 #define jsnum_h___
 
 #include <math.h>
 
-#include "jsstdint.h"
 #include "jsobj.h"
 
 /*
  * JS number (IEEE double) interface.
  *
  * JS numbers are optimistically stored in the top 31 bits of 32-bit integers,
  * but floating point literals, results that overflow 31 bits, and division and
  * modulus operands and results require a 64-bit IEEE double.  These are GC'ed
@@ -124,25 +123,16 @@ JSDOUBLE_IS_NEG(jsdouble d)
 static inline uint32_t
 JS_HASH_DOUBLE(jsdouble d)
 {
     jsdpun u;
     u.d = d;
     return u.s.lo ^ u.s.hi;
 }
 
-#if defined(XP_WIN)
-#define JSDOUBLE_COMPARE(LVAL, OP, RVAL, IFNAN)                               \
-    ((JSDOUBLE_IS_NaN(LVAL) || JSDOUBLE_IS_NaN(RVAL))                         \
-     ? (IFNAN)                                                                \
-     : (LVAL) OP (RVAL))
-#else
-#define JSDOUBLE_COMPARE(LVAL, OP, RVAL, IFNAN) ((LVAL) OP (RVAL))
-#endif
-
 extern jsdouble js_NaN;
 extern jsdouble js_PositiveInfinity;
 extern jsdouble js_NegativeInfinity;
 
 namespace js {
 
 extern bool
 InitRuntimeNumberState(JSRuntime *rt);
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -42,17 +42,16 @@
  * JS object implementation.
  */
 #include <stdlib.h>
 #include <string.h>
 
 #include "mozilla/Util.h"
 
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsutil.h"
 #include "jshash.h"
 #include "jsdhash.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
@@ -67,17 +66,16 @@
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsonparser.h"
 #include "jsopcode.h"
 #include "jsprobes.h"
 #include "jsproxy.h"
 #include "jsscope.h"
 #include "jsscript.h"
-#include "jsstdint.h"
 #include "jsstr.h"
 #include "jsdbgapi.h"
 #include "json.h"
 #include "jswatchpoint.h"
 #include "jswrapper.h"
 
 #include "builtin/MapObject.h"
 #include "frontend/BytecodeCompiler.h"
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -50,17 +50,16 @@
 #include "jsiter.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "json.h"
 #include "jsonparser.h"
 #include "jsprf.h"
 #include "jsstr.h"
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsutil.h"
 #include "jsxml.h"
 
 #include "frontend/TokenStream.h"
 
 #include "jsatominlines.h"
 #include "jsboolinlines.h"
 #include "jsinferinlines.h"
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -47,17 +47,16 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "mozilla/Util.h"
 
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsutil.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsfun.h"
@@ -851,18 +850,17 @@ Sprinter::put(const char *s, size_t len)
 
     /* s is within the buffer already */
     if (s >= oldBase && s < oldEnd) {
         /* buffer was realloc'ed */
         if (base != oldBase)
             s = stringAt(s - oldBase);  /* this is where it lives now */
         memmove(bp, s, len);
     } else {
-        JS_ASSERT(s < base || s >= base + size);
-        memcpy(bp, s, len);
+        js_memcpy(bp, s, len);
     }
 
     bp[len] = 0;
     return oldOffset;
 }
 
 ptrdiff_t
 Sprinter::putString(JSString *s)
@@ -2055,17 +2053,17 @@ DecompileDestructuringLHS(SprintStack *s
         /*
          * We may need to auto-parenthesize the left-most value decompiled
          * here, so add back PAREN_SLOP temporarily.  Then decompile until the
          * opcode that would reduce the stack depth to (ss->top-1), which we
          * pass to Decompile encoded as -(ss->top-1) - 1 or just -ss->top for
          * the nb parameter.
          */
         ptrdiff_t todo = ss->sprinter.getOffset();
-        ss->sprinter.setOffset(todo + PAREN_SLOP);
+        ss->sprinter.reserve(PAREN_SLOP);
         pc = Decompile(ss, pc, -((intN)ss->top));
         if (!pc)
             return NULL;
         if (pc == endpc)
             return pc;
         LOAD_OP_DATA(pc);
         LOCAL_ASSERT(op == JSOP_ENUMELEM || op == JSOP_ENUMCONSTELEM);
         xval = PopStr(ss, JSOP_NOP);
--- a/js/src/jsprf.cpp
+++ b/js/src/jsprf.cpp
@@ -41,17 +41,16 @@
 **
 ** Author: Kipp E.B. Hickman
 */
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include "jsprf.h"
-#include "jsstdint.h"
 #include "jsutil.h"
 #include "jspubtd.h"
 #include "jsstr.h"
 
 using namespace js;
 
 /*
 ** Note: on some platforms va_list is defined as an array,
--- a/js/src/jsscope.cpp
+++ b/js/src/jsscope.cpp
@@ -40,17 +40,16 @@
 
 /*
  * JS symbol tables.
  */
 #include <new>
 #include <stdlib.h>
 #include <string.h>
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsclist.h"
 #include "jsdhash.h"
 #include "jsutil.h"
 #include "jsapi.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsdbgapi.h"
 #include "jslock.h"
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -37,19 +37,19 @@
  * 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 ***** */
 
 /*
  * JS script operations.
  */
+
 #include <string.h>
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsutil.h"
 #include "jscrashreport.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsdbgapi.h"
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -49,17 +49,16 @@
  * allocations in the same native method.
  */
 
 #include "mozilla/Attributes.h"
 
 #include <stdlib.h>
 #include <string.h>
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsutil.h"
 #include "jshash.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -37,17 +37,16 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include <string.h>
 
 #include "mozilla/Util.h"
 
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsutil.h"
 #include "jshash.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
@@ -1539,26 +1538,26 @@ class TypedArrayTemplate
             return obj;
         }
 
         /* (obj, byteOffset, length). */
         int32_t byteOffset = -1;
         int32_t length = -1;
 
         if (argc > 1) {
-            if (!NonstandardToInt32(cx, argv[1], &byteOffset))
+            if (!ToInt32(cx, argv[1], &byteOffset))
                 return NULL;
             if (byteOffset < 0) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_TYPED_ARRAY_NEGATIVE_ARG, "1");
                 return NULL;
             }
 
             if (argc > 2) {
-                if (!NonstandardToInt32(cx, argv[2], &length))
+                if (!ToInt32(cx, argv[2], &length))
                     return NULL;
                 if (length < 0) {
                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                          JSMSG_TYPED_ARRAY_NEGATIVE_ARG, "2");
                     return NULL;
                 }
             }
         }
@@ -1620,17 +1619,17 @@ class TypedArrayTemplate
         JSObject *tarray = getTypedArray(obj);
         if (!tarray)
             return true;
 
         // these are the default values
         int32_t off = 0;
 
         if (args.length() > 1) {
-            if (!NonstandardToInt32(cx, args[1], &off))
+            if (!ToInt32(cx, args[1], &off))
                 return false;
 
             if (off < 0 || uint32_t(off) > getLength(tarray)) {
                 // the given offset is bogus
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
                 return false;
             }
--- a/js/src/jsutil.cpp
+++ b/js/src/jsutil.cpp
@@ -40,17 +40,16 @@
 
 /* Various JS utility functions. */
 
 #include "mozilla/Attributes.h"
 
 #include <stdio.h>
 #include <stdlib.h>
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsutil.h"
 
 #ifdef WIN32
 #    include "jswin.h"
 #else
 #    include <signal.h>
 #endif
 
--- a/js/src/jsxdrapi.cpp
+++ b/js/src/jsxdrapi.cpp
@@ -40,17 +40,16 @@
 #include "mozilla/Util.h"
 
 #include "jsversion.h"
 
 #if JS_HAS_XDR
 
 #include <string.h>
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsutil.h"
 #include "jsdhash.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jscntxt.h"
 #include "jsnum.h"
 #include "jsobj.h"              /* js_XDRObject */
 #include "jsscript.h"           /* js_XDRScript */
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -43,17 +43,16 @@
 
 #include <math.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "mozilla/Util.h"
 
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsprf.h"
 #include "jsutil.h"
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsfun.h"
@@ -5310,17 +5309,17 @@ js_TestXMLEquality(JSContext *cx, const 
                     ok = EqualStrings(cx, str, JSVAL_TO_STRING(v), &equal);
                     if (ok)
                         *bp = equal;
                 } else {
                     ok = JS_ValueToNumber(cx, STRING_TO_JSVAL(str), &d);
                     if (ok) {
                         d2 = JSVAL_IS_INT(v) ? JSVAL_TO_INT(v)
                                              : JSVAL_TO_DOUBLE(v);
-                        *bp = JSDOUBLE_COMPARE(d, ==, d2, JS_FALSE);
+                        *bp = (d == d2);
                     }
                 }
             } else {
                 *bp = JS_FALSE;
             }
             js_LeaveLocalRootScope(cx);
         }
     }
--- a/js/src/methodjit/BaseAssembler.h
+++ b/js/src/methodjit/BaseAssembler.h
@@ -786,16 +786,30 @@ static const JSC::MacroAssembler::Regist
         Address extent(reg, offset);
         if (key.isConstant()) {
             JS_ASSERT(key.index() >= 0);
             return branch32(cond, extent, Imm32(key.index()));
         }
         return branch32(cond, extent, key.reg());
     }
 
+    Jump guardElementNotHole(RegisterID elements, const Int32Key &key) {
+        Jump jmp;
+
+        if (key.isConstant()) {
+            Address slot(elements, key.index() * sizeof(Value));
+            jmp = guardNotHole(slot);
+        } else {
+            BaseIndex slot(elements, key.reg(), JSVAL_SCALE);
+            jmp = guardNotHole(slot);
+        }
+
+        return jmp;
+    }
+
     // Load a jsval from an array slot, given a key. |objReg| is clobbered.
     FastArrayLoadFails fastArrayLoad(RegisterID objReg, const Int32Key &key,
                                      RegisterID typeReg, RegisterID dataReg) {
         JS_ASSERT(objReg != typeReg);
 
         RegisterID elementsReg = objReg;
         loadPtr(Address(objReg, JSObject::offsetOfElements()), elementsReg);
 
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -2964,21 +2964,17 @@ mjit::Compiler::generateMethod()
             prepareStubCall(Uses(1));
             INLINE_STUBCALL(stubs::Throw, REJOIN_NONE);
             frame.pop();
             fallthrough = false;
           END_CASE(JSOP_THROW)
 
           BEGIN_CASE(JSOP_IN)
           {
-            prepareStubCall(Uses(2));
-            INLINE_STUBCALL(stubs::In, REJOIN_PUSH_BOOLEAN);
-            frame.popn(2);
-            frame.takeReg(Registers::ReturnReg);
-            frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, Registers::ReturnReg);
+            jsop_in();
           }
           END_CASE(JSOP_IN)
 
           BEGIN_CASE(JSOP_INSTANCEOF)
             if (!jsop_instanceof())
                 return Compile_Error;
           END_CASE(JSOP_INSTANCEOF)
 
@@ -7446,16 +7442,86 @@ mjit::Compiler::jsop_toid()
     OOL_STUBCALL(stubs::ToId, REJOIN_FALLTHROUGH);
 
     frame.pop();
     pushSyncedEntry(0);
 
     stubcc.rejoin(Changes(1));
 }
 
+void
+mjit::Compiler::jsop_in()
+{
+    FrameEntry *obj = frame.peek(-1);
+    FrameEntry *id = frame.peek(-2);
+
+    if (cx->typeInferenceEnabled() && id->isType(JSVAL_TYPE_INT32)) {
+        types::TypeSet *types = analysis->poppedTypes(PC, 0);
+
+        if (obj->mightBeType(JSVAL_TYPE_OBJECT) &&
+            !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
+            !types::ArrayPrototypeHasIndexedProperty(cx, outerScript))
+        {
+            bool isPacked = !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED_ARRAY);
+
+            if (!obj->isTypeKnown()) {
+                Jump guard = frame.testObject(Assembler::NotEqual, obj);
+                stubcc.linkExit(guard, Uses(2));
+            }
+
+            RegisterID dataReg = frame.copyDataIntoReg(obj);
+
+            Int32Key key = id->isConstant()
+                         ? Int32Key::FromConstant(id->getValue().toInt32())
+                         : Int32Key::FromRegister(frame.tempRegForData(id));
+
+            masm.loadPtr(Address(dataReg, JSObject::offsetOfElements()), dataReg);
+
+            // Guard on the array's initialized length.
+            Jump initlenGuard = masm.guardArrayExtent(ObjectElements::offsetOfInitializedLength(),
+                                                      dataReg, key, Assembler::BelowOrEqual);
+
+            // Guard to make sure we don't have a hole. Skip it if the array is packed.
+            MaybeJump holeCheck;
+            if (!isPacked)
+                holeCheck = masm.guardElementNotHole(dataReg, key);
+
+            masm.move(Imm32(1), dataReg);
+            Jump done = masm.jump();
+
+            Label falseBranch = masm.label();
+            initlenGuard.linkTo(falseBranch, &masm);
+            if (!isPacked)
+                holeCheck.getJump().linkTo(falseBranch, &masm);
+            masm.move(Imm32(0), dataReg);
+
+            done.linkTo(masm.label(), &masm);
+
+            stubcc.leave();
+            OOL_STUBCALL_USES(stubs::In, REJOIN_PUSH_BOOLEAN, Uses(2));
+
+            frame.popn(2);
+            if (dataReg != Registers::ReturnReg)
+                stubcc.masm.move(Registers::ReturnReg, dataReg);
+
+            frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, dataReg);
+
+            stubcc.rejoin(Changes(2));
+
+            return;
+        }
+    }
+
+    prepareStubCall(Uses(2));
+    INLINE_STUBCALL(stubs::In, REJOIN_PUSH_BOOLEAN);
+    frame.popn(2);
+    frame.takeReg(Registers::ReturnReg);
+    frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, Registers::ReturnReg);
+}
+
 /*
  * For any locals or args which we know to be integers but are treated as
  * doubles by the type inference, convert to double. These will be assumed to be
  * doubles at control flow join points. This function must be called before
  * branching to another opcode.
  *
  * We can only carry entries as doubles when we can track all incoming edges to
  * a join point (no try blocks etc.) and when we can track all writes to the
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -748,16 +748,17 @@ private:
 #endif
     void jsop_toid();
     bool isCacheableBaseAndIndex(FrameEntry *obj, FrameEntry *id);
     void jsop_stricteq(JSOp op);
     bool jsop_equality(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
     CompileStatus jsop_equality_obj_obj(JSOp op, jsbytecode *target, JSOp fused);
     bool jsop_equality_int_string(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
     void jsop_pos();
+    void jsop_in();
 
     static inline Assembler::Condition
     GetCompareCondition(JSOp op, JSOp fused)
     {
         bool ifeq = fused == JSOP_IFEQ;
         switch (op) {
           case JSOP_GT:
             return ifeq ? Assembler::LessThanOrEqual : Assembler::GreaterThan;
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -520,17 +520,17 @@ template void JS_FASTCALL stubs::DefFun<
             int32_t cmp;                                                      \
             if (!CompareStrings(cx, l, r, &cmp))                              \
                 THROWV(JS_FALSE);                                             \
             cond = cmp OP 0;                                                  \
         } else {                                                              \
             double l, r;                                                      \
             if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))           \
                 THROWV(JS_FALSE);                                             \
-            cond = JSDOUBLE_COMPARE(l, OP, r, false);                         \
+            cond = (l OP r);                                                  \
         }                                                                     \
         regs.sp[-2].setBoolean(cond);                                         \
         return cond;                                                          \
     JS_END_MACRO
 
 JSBool JS_FASTCALL
 stubs::LessThan(VMFrame &f)
 {
@@ -563,17 +563,17 @@ stubs::ValueToBoolean(VMFrame &f)
 
 void JS_FASTCALL
 stubs::Not(VMFrame &f)
 {
     JSBool b = !js_ValueToBoolean(f.regs.sp[-1]);
     f.regs.sp[-1].setBoolean(b);
 }
 
-template <bool EQ, bool IFNAN>
+template <bool EQ>
 static inline bool
 StubEqualityOp(VMFrame &f)
 {
     JSContext *cx = f.cx;
     FrameRegs &regs = f.regs;
 
     Value rval = regs.sp[-1];
     Value lval = regs.sp[-2];
@@ -601,19 +601,19 @@ StubEqualityOp(VMFrame &f)
 #endif
 
     if (SameType(lval, rval)) {
         JS_ASSERT(!lval.isString());    /* this case is handled above */
         if (lval.isDouble()) {
             double l = lval.toDouble();
             double r = rval.toDouble();
             if (EQ)
-                cond = JSDOUBLE_COMPARE(l, ==, r, IFNAN);
+                cond = (l == r);
             else
-                cond = JSDOUBLE_COMPARE(l, !=, r, IFNAN);
+                cond = (l != r);
         } else if (lval.isObject()) {
             JSObject *l = &lval.toObject(), *r = &rval.toObject();
             if (JSEqualityOp eq = l->getClass()->ext.equality) {
                 JSBool equal;
                 if (!eq(cx, l, &rval, &equal))
                     return false;
                 cond = !!equal == EQ;
             } else {
@@ -647,39 +647,39 @@ StubEqualityOp(VMFrame &f)
                     return false;
                 cond = equal == EQ;
             } else {
                 double l, r;
                 if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))
                     return false;
 
                 if (EQ)
-                    cond = JSDOUBLE_COMPARE(l, ==, r, false);
+                    cond = (l == r);
                 else
-                    cond = JSDOUBLE_COMPARE(l, !=, r, true);
+                    cond = (l != r);
             }
         }
     }
 
     regs.sp[-2].setBoolean(cond);
     return true;
 }
 
 JSBool JS_FASTCALL
 stubs::Equal(VMFrame &f)
 {
-    if (!StubEqualityOp<true, false>(f))
+    if (!StubEqualityOp<true>(f))
         THROWV(JS_FALSE);
     return f.regs.sp[-2].toBoolean();
 }
 
 JSBool JS_FASTCALL
 stubs::NotEqual(VMFrame &f)
 {
-    if (!StubEqualityOp<false, true>(f))
+    if (!StubEqualityOp<false>(f))
         THROWV(JS_FALSE);
     return f.regs.sp[-2].toBoolean();
 }
 
 void JS_FASTCALL
 stubs::Add(VMFrame &f)
 {
     JSContext *cx = f.cx;
--- a/js/src/prmjtime.cpp
+++ b/js/src/prmjtime.cpp
@@ -41,17 +41,16 @@
  * PR time code.
  */
 #ifdef SOLARIS
 #define _REENTRANT 1
 #endif
 #include <string.h>
 #include <time.h>
 
-#include "jsstdint.h"
 #include "jstypes.h"
 #include "jsutil.h"
 
 #include "jsprf.h"
 #include "jslock.h"
 #include "prmjtime.h"
 
 #define PRMJ_DO_MILLISECONDS 1
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -47,17 +47,16 @@
 #include <stdlib.h>
 #include <string.h>
 #include <signal.h>
 #include <locale.h>
 
 #include "mozilla/Util.h"
 
 #include "jstypes.h"
-#include "jsstdint.h"
 #include "jsutil.h"
 #include "jsprf.h"
 #include "jswrapper.h"
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsdate.h"
--- a/js/src/shell/jsworkers.cpp
+++ b/js/src/shell/jsworkers.cpp
@@ -44,17 +44,16 @@
 
 #include <string.h>
 #include "prthread.h"
 #include "prlock.h"
 #include "prcvar.h"
 #include "jsapi.h"
 #include "jscntxt.h"
 #include "jsdbgapi.h"
-#include "jsstdint.h"
 #include "jslock.h"
 #include "jsworkers.h"
 
 extern size_t gMaxStackSize;
 
 class AutoLock
 {
   private:
--- a/js/src/yarr/PageBlock.h
+++ b/js/src/yarr/PageBlock.h
@@ -25,18 +25,19 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  * THE POSSIBILITY OF SUCH DAMAGE.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef PageBlock_h
 #define PageBlock_h
 
+#include "mozilla/StdInt.h"
+
 #include <stdlib.h>
-#include "jsstdint.h"
 #include "assembler/wtf/Platform.h"
 
 namespace WTF {
 
 size_t pageSize();
 inline bool isPageAligned(void* address) { return !(reinterpret_cast<intptr_t>(address) & (pageSize() - 1)); }
 inline bool isPageAligned(size_t size) { return !(size & (pageSize() - 1)); }
 inline bool isPowerOfTwo(size_t size) { return !(size & (size - 1)); }
--- a/js/xpconnect/idl/nsIXPConnect.idl
+++ b/js/xpconnect/idl/nsIXPConnect.idl
@@ -385,19 +385,25 @@ interface nsIXPCFunctionThisTranslator :
 /***************************************************************************/
 
 %{ C++
 // For use with the service manager
 // {CB6593E0-F9B2-11d2-BDD6-000064657374}
 #define NS_XPCONNECT_CID \
 { 0xcb6593e0, 0xf9b2, 0x11d2, \
     { 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } }
+
+enum nsGCType {
+    nsGCNormal,
+    nsGCShrinking,
+    nsGCIncremental
+};
 %}
 
-[uuid(241e6db3-e018-4d99-b976-c782a05f9c77)]
+[uuid(686bb1d0-4711-11e1-b86c-0800200c9a66)]
 interface nsIXPConnect : nsISupports
 {
 %{ C++
   NS_DEFINE_STATIC_CID_ACCESSOR(NS_XPCONNECT_CID)
 %}
 
     /**
      * Initializes classes on a global object that has already been created.
@@ -718,18 +724,20 @@ interface nsIXPConnect : nsISupports
      * from JS into C++. False by default, although any value set in the
      * MOZ_REPORT_ALL_JS_EXCEPTIONS environment variable will override the value
      * passed here.
      */
     void setReportAllJSExceptions(in boolean reportAllJSExceptions);
 
     /**
      * Trigger a JS garbage collection.
+     * Use a js::gcreason::Reason from jsfriendapi.h for the kind.
+     * Use the nsGCType enum for the kind.
      */
-    void GarbageCollect(in boolean shrinkingGC);
+    void GarbageCollect(in PRUint32 reason, in PRUint32 kind);
 
     /**
      * Define quick stubs on the given object, @a proto.
      *
      * @param cx
      *     A context.  Requires request.
      * @param proto
      *     The (newly created) prototype object for a DOM class.  The JS half
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -3595,25 +3595,25 @@ nsXPCComponents_Utils::GetWeakReference(
     ref.forget(_retval);
     return NS_OK;
 }
 
 /* void forceGC (); */
 NS_IMETHODIMP
 nsXPCComponents_Utils::ForceGC(JSContext *cx)
 {
-    JS_GC(cx);
+    js::GCForReason(cx, js::gcreason::COMPONENT_UTILS);
     return NS_OK;
 }
 
 /* void forceShrinkingGC (); */
 NS_IMETHODIMP
 nsXPCComponents_Utils::ForceShrinkingGC(JSContext *cx)
 {
-    JS_ShrinkingGC(cx);
+    js::ShrinkingGC(cx, js::gcreason::COMPONENT_UTILS);
     return NS_OK;
 }
 
 class PreciseGCRunnable : public nsRunnable
 {
   public:
     PreciseGCRunnable(JSContext *aCx, ScheduledGCCallback* aCallback, bool aShrinking)
     : mCallback(aCallback), mCx(aCx), mShrinking(aShrinking) {}
@@ -3631,19 +3631,19 @@ class PreciseGCRunnable : public nsRunna
         JSContext *iter = nsnull;
         while ((cx = JS_ContextIterator(rt, &iter)) != NULL) {
             if (JS_IsRunning(cx)) {
                 return NS_DispatchToMainThread(this);
             }
         }
 
         if (mShrinking)
-            JS_ShrinkingGC(mCx);
+            js::ShrinkingGC(mCx, js::gcreason::COMPONENT_UTILS);
         else
-            JS_GC(mCx);
+            js::GCForReason(mCx, js::gcreason::COMPONENT_UTILS);
 
         mCallback->Callback();
         return NS_OK;
     }
 
   private:
     nsRefPtr<ScheduledGCCallback> mCallback;
     JSContext *mCx;
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -51,17 +51,17 @@
 #include "nsIMemoryReporter.h"
 #include "nsPrintfCString.h"
 #include "mozilla/FunctionTimer.h"
 #include "prsystem.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 
 #include "nsContentUtils.h"
-
+#include "nsCCUncollectableMarker.h"
 #include "jsfriendapi.h"
 #include "js/MemoryMetrics.h"
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 
 using namespace mozilla;
@@ -568,22 +568,40 @@ XPCJSRuntime::AddXPConnectRoots(JSContex
         cb.NoteRoot(nsIProgrammingLanguage::CPLUSPLUS, acx,
                     nsXPConnect::JSContextParticipant());
     }
 
     XPCAutoLock lock(mMapLock);
 
     XPCWrappedNativeScope::SuspectAllWrappers(this, cx, cb);
 
-    for (XPCRootSetElem *e = mVariantRoots; e ; e = e->GetNextRoot())
-        cb.NoteXPCOMRoot(static_cast<XPCTraceableVariant*>(e));
+    for (XPCRootSetElem *e = mVariantRoots; e ; e = e->GetNextRoot()) {
+        XPCTraceableVariant* v = static_cast<XPCTraceableVariant*>(e);
+        if (nsCCUncollectableMarker::InGeneration(cb,
+                                                  v->CCGeneration())) {
+           jsval val = v->GetJSValPreserveColor();
+           if (val.isObject() && !xpc_IsGrayGCThing(&val.toObject()))
+               continue;
+        }
+        cb.NoteXPCOMRoot(v);
+    }
 
     for (XPCRootSetElem *e = mWrappedJSRoots; e ; e = e->GetNextRoot()) {
         nsXPCWrappedJS *wrappedJS = static_cast<nsXPCWrappedJS*>(e);
         JSObject *obj = wrappedJS->GetJSObjectPreserveColor();
+        // If traversing wrappedJS wouldn't release it, nor
+        // cause any other objects to be added to the graph, no
+        // need to add it to the graph at all.
+        if (nsCCUncollectableMarker::sGeneration &&
+            !cb.WantAllTraces() && (!obj || !xpc_IsGrayGCThing(obj)) &&
+            !wrappedJS->IsSubjectToFinalization() &&
+            wrappedJS->GetRootWrapper() == wrappedJS &&
+            !wrappedJS->IsAggregatedToNative()) {
+            continue;
+        }
 
         // Only suspect wrappedJSObjects that are in a compartment that
         // participates in cycle collection.
         if (!xpc::ParticipatesInCycleCollection(cx, js::gc::AsCell(obj)))
             continue;
 
         cb.NoteXPCOMRoot(static_cast<nsIXPConnectWrappedJS *>(wrappedJS));
     }
@@ -1865,19 +1883,16 @@ AccumulateTelemetryCallback(int id, uint
 {
     switch (id) {
       case JS_TELEMETRY_GC_REASON:
         Telemetry::Accumulate(Telemetry::GC_REASON, sample);
         break;
       case JS_TELEMETRY_GC_IS_COMPARTMENTAL:
         Telemetry::Accumulate(Telemetry::GC_IS_COMPARTMENTAL, sample);
         break;
-      case JS_TELEMETRY_GC_IS_SHAPE_REGEN:
-        Telemetry::Accumulate(Telemetry::GC_IS_SHAPE_REGEN, sample);
-        break;
       case JS_TELEMETRY_GC_MS:
         Telemetry::Accumulate(Telemetry::GC_MS, sample);
         break;
       case JS_TELEMETRY_GC_MARK_MS:
         Telemetry::Accumulate(Telemetry::GC_MARK_MS, sample);
         break;
       case JS_TELEMETRY_GC_SWEEP_MS:
         Telemetry::Accumulate(Telemetry::GC_SWEEP_MS, sample);
--- a/js/xpconnect/src/XPCVariant.cpp
+++ b/js/xpconnect/src/XPCVariant.cpp
@@ -55,17 +55,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_IMPL_QUERY_CLASSINFO(XPCVariant)
 NS_INTERFACE_MAP_END
 NS_IMPL_CI_INTERFACE_GETTER2(XPCVariant, XPCVariant, nsIVariant)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(XPCVariant)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(XPCVariant)
 
 XPCVariant::XPCVariant(XPCCallContext& ccx, jsval aJSVal)
-    : mJSVal(aJSVal)
+    : mJSVal(aJSVal), mCCGeneration(0)
 {
     nsVariant::Initialize(&mData);
     if (!JSVAL_IS_PRIMITIVE(mJSVal)) {
         JSObject *obj = JS_ObjectToInnerObject(ccx, JSVAL_TO_OBJECT(mJSVal));
 
         mJSVal = OBJECT_TO_JSVAL(obj);
 
         // If the incoming object is an XPCWrappedNative, then it could be a
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -360,17 +360,17 @@ nsXPConnect::GetInfoForName(const char *
 
 bool
 nsXPConnect::NeedCollect()
 {
     return !!mNeedGCBeforeCC;
 }
 
 void
-nsXPConnect::Collect(bool shrinkingGC)
+nsXPConnect::Collect(PRUint32 reason, PRUint32 kind)
 {
     // We're dividing JS objects into 2 categories:
     //
     // 1. "real" roots, held by the JS engine itself or rooted through the root
     //    and lock JS APIs. Roots from this category are considered black in the
     //    cycle collector, any cycle they participate in is uncollectable.
     //
     // 2. roots held by C++ objects that participate in cycle collection,
@@ -419,26 +419,30 @@ nsXPConnect::Collect(bool shrinkingGC)
     JSContext *cx = ccx.GetJSContext();
 
     // We want to scan the current thread for GC roots only if it was in a
     // request prior to the Collect call to avoid false positives during the
     // cycle collection. So to compensate for JS_BeginRequest in
     // XPCCallContext::Init we disable the conservative scanner if that call
     // has started the request on this thread.
     js::AutoSkipConservativeScan ascs(cx);
-    if (shrinkingGC)
-        JS_ShrinkingGC(cx);
-    else
-        JS_GC(cx);
+    MOZ_ASSERT(reason < js::gcreason::NUM_REASONS);
+    js::gcreason::Reason gcreason = (js::gcreason::Reason)reason;
+    if (kind == nsGCShrinking) {
+        js::ShrinkingGC(cx, gcreason);
+    } else {
+        MOZ_ASSERT(kind == nsGCNormal);
+        js::GCForReason(cx, gcreason);
+    }
 }
 
 NS_IMETHODIMP
-nsXPConnect::GarbageCollect(bool shrinkingGC)
+nsXPConnect::GarbageCollect(PRUint32 reason, PRUint32 kind)
 {
-    Collect(shrinkingGC);
+    Collect(reason, kind);
     return NS_OK;
 }
 
 #ifdef DEBUG_CC
 struct NoteJSRootTracer : public JSTracer
 {
     NoteJSRootTracer(PLDHashTable *aObjects,
                      nsCycleCollectionTraversalCallback& cb)
@@ -814,16 +818,40 @@ NoteJSChild(JSTracer *trc, void *thing, 
         tracer->cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, thing);
     } else if (kind == JSTRACE_SHAPE) {
         JS_TraceShapeCycleCollectorChildren(trc, thing);
     } else if (kind != JSTRACE_STRING) {
         JS_TraceChildren(trc, thing, kind);
     }
 }
 
+void
+xpc_MarkInCCGeneration(nsISupports* aVariant, PRUint32 aGeneration)
+{
+    nsCOMPtr<XPCVariant> variant = do_QueryInterface(aVariant);
+    if (variant) {
+        variant->SetCCGeneration(aGeneration);
+        variant->GetJSVal(); // Unmarks gray JSObject.
+        XPCVariant* weak = variant.get();
+        variant = nsnull;
+        if (weak->IsPurple()) {
+          weak->RemovePurple();
+        }
+    }
+}
+
+void
+xpc_UnmarkGrayObject(nsIXPConnectWrappedJS* aWrappedJS)
+{
+    if (aWrappedJS) {
+        // Unmarks gray JSObject.
+        static_cast<nsXPCWrappedJS*>(aWrappedJS)->GetJSObject();
+    }
+}
+
 static JSBool
 WrapperIsNotMainThreadOnly(XPCWrappedNative *wrapper)
 {
     XPCWrappedNativeProto *proto = wrapper->GetProto();
     if (proto && proto->ClassIsMainThreadOnly())
         return false;
 
     // If the native participates in cycle collection then we know it can only
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -544,17 +544,17 @@ public:
     virtual void NotifyLeaveCycleCollectionThread();
     virtual void NotifyEnterMainThread();
     virtual nsresult BeginCycleCollection(nsCycleCollectionTraversalCallback &cb,
                                           bool explainExpectedLiveGarbage);
     virtual nsresult FinishTraverse();
     virtual nsresult FinishCycleCollection();
     virtual nsCycleCollectionParticipant *ToParticipant(void *p);
     virtual bool NeedCollect();
-    virtual void Collect(bool shrinkingGC=false);
+    virtual void Collect(PRUint32 reason, PRUint32 kind);
 #ifdef DEBUG_CC
     virtual void PrintAllReferencesTo(void *p);
 #endif
 
     XPCCallContext *GetCycleCollectionContext()
     {
         return mCycleCollectionContext;
     }
@@ -4274,25 +4274,42 @@ public:
      * @param scope the default scope to put on the new JSObject's parent chain
      * @param pErr [out] relevant error code, if any.
      * @param pJSVal [out] the resulting jsval.
      */
     static JSBool VariantDataToJS(XPCLazyCallContext& lccx,
                                   nsIVariant* variant,
                                   nsresult* pErr, jsval* pJSVal);
 
+    bool IsPurple()
+    {
+        return mRefCnt.IsPurple();
+    }
+
+    void RemovePurple()
+    {
+        mRefCnt.RemovePurple();
+    }
+
+    void SetCCGeneration(PRUint32 aGen)
+    {
+        mCCGeneration = aGen;
+    }
+
+    PRUint32 CCGeneration() { return mCCGeneration; }
 protected:
     virtual ~XPCVariant() { }
 
     JSBool InitializeData(XPCCallContext& ccx);
 
 protected:
     nsDiscriminatedUnion mData;
     jsval                mJSVal;
-    JSBool               mReturnRawObject;
+    bool                 mReturnRawObject : 1;
+    PRUint32             mCCGeneration : 31;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(XPCVariant, XPCVARIANT_IID)
 
 class XPCTraceableVariant: public XPCVariant,
                            public XPCRootSetElem
 {
 public:
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -50,16 +50,17 @@
 
 #include "nsISupports.h"
 #include "nsIPrincipal.h"
 #include "nsWrapperCache.h"
 #include "nsStringGlue.h"
 #include "nsTArray.h"
 
 class nsIPrincipal;
+class nsIXPConnectWrappedJS;
 struct nsDOMClassInfoData;
 
 #ifndef BAD_TLS_INDEX
 #define BAD_TLS_INDEX ((PRUint32) -1)
 #endif
 
 nsresult
 xpc_CreateGlobalObject(JSContext *cx, JSClass *clasp,
@@ -184,16 +185,25 @@ xpc_UnmarkGrayObjectRecursive(JSObject* 
 // be reached through it.
 inline void
 xpc_UnmarkGrayObject(JSObject *obj)
 {
     if (obj && xpc_IsGrayGCThing(obj))
         xpc_UnmarkGrayObjectRecursive(obj);
 }
 
+// If aVariant is an XPCVariant, this marks the object to be in aGeneration.
+// This also unmarks the gray JSObject.
+extern void
+xpc_MarkInCCGeneration(nsISupports* aVariant, PRUint32 aGeneration);
+
+// Unmarks aWrappedJS's JSObject.
+extern void
+xpc_UnmarkGrayObject(nsIXPConnectWrappedJS* aWrappedJS);
+
 // No JS can be on the stack when this is called. Probably only useful from
 // xpcshell.
 NS_EXPORT_(void)
 xpc_ActivateDebugMode();
 
 namespace xpc {
 
 // If these functions return false, then an exception will be set on cx.
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -193,16 +193,18 @@ static const char sPrintOptionsContractI
 
 //switch to page layout
 #include "nsGfxCIID.h"
 
 #include "nsObserverService.h"
 
 #include "mozilla/dom/Element.h"
 
+#include "jsfriendapi.h"
+
 using namespace mozilla;
 
 #ifdef NS_DEBUG
 
 #undef NOISY_VIEWER
 #else
 #undef NOISY_VIEWER
 #endif
@@ -1282,17 +1284,17 @@ DocumentViewerImpl::PageHide(bool aIsUnl
   // inform the window so that the focus state is reset.
   NS_ENSURE_STATE(mDocument);
   nsPIDOMWindow *window = mDocument->GetWindow();
   if (window)
     window->PageHidden();
 
   if (aIsUnload) {
     // Poke the GC. The window might be collectable garbage now.
-    nsJSContext::PokeGC();
+    nsJSContext::PokeGC(js::gcreason::PAGE_HIDE);
 
     // if Destroy() was called during OnPageHide(), mDocument is nsnull.
     NS_ENSURE_STATE(mDocument);
 
     // First, get the window from the document...
     nsPIDOMWindow *window = mDocument->GetWindow();
 
     if (!window) {
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -85,16 +85,17 @@
 #include "nsTArray.h"
 #include "nsHTMLCanvasElement.h"
 #include "nsICanvasRenderingContextInternal.h"
 #include "gfxPlatform.h"
 #include "nsClientRect.h"
 #ifdef MOZ_MEDIA
 #include "nsHTMLVideoElement.h"
 #endif
+#include "nsGenericHTMLElement.h"
 #include "imgIRequest.h"
 #include "imgIContainer.h"
 #include "nsIImageLoadingContent.h"
 #include "nsCOMPtr.h"
 #include "nsListControlFrame.h"
 #include "ImageLayers.h"
 #include "mozilla/arm.h"
 #include "mozilla/dom/Element.h"
@@ -4146,16 +4147,17 @@ nsLayoutUtils::SurfaceFromElement(dom::E
         new gfxImageSurface(size, gfxASurface::ImageFormatARGB32);
 
       nsRefPtr<gfxContext> ctx = new gfxContext(imgSurf);
       ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
       ctx->DrawSurface(surf, size);
       surf = imgSurf;
     }
 
+    result.mCORSUsed = video->GetCORSMode() != nsGenericHTMLElement::CORS_NONE;
     result.mSurface = surf;
     result.mSize = size;
     result.mPrincipal = principal.forget();
     result.mIsWriteOnly = false;
 
     return result;
   }
 #endif
--- a/layout/build/nsContentDLF.cpp
+++ b/layout/build/nsContentDLF.cpp
@@ -305,17 +305,17 @@ nsContentDLF::CreateInstance(const char*
                           aChannel, aLoadGroup,
                           aContainer, kImageDocumentCID,
                           aDocListener, aDocViewer);
   }
 
   nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
   nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
   if(pluginHost &&
-     NS_SUCCEEDED(pluginHost->IsPluginEnabledForType(aContentType))) {
+     NS_SUCCEEDED(pluginHost->IsPluginEnabledForType(aContentType, true))) {
     return CreateDocument(aCommand,
                           aChannel, aLoadGroup,
                           aContainer, kPluginDocumentCID,
                           aDocListener, aDocViewer);
   }
 
   // If we get here, then we weren't able to create anything. Sorry!
   return NS_ERROR_FAILURE;
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -6577,20 +6577,20 @@ nsRuleNode::ComputeColumnData(void* aSta
   }
   else if (SetColor(colorValue, 0, mPresContext, aContext,
                     column->mColumnRuleColor, canStoreInRuleTree)) {
     column->mColumnRuleColorIsForeground = false;
   }
 
   // column-fill: enum
   SetDiscrete(*aRuleData->ValueForColumnFill(),
-                column->mColumnFill, canStoreInRuleTree,
-                SETDSC_ENUMERATED, parent->mColumnFill,
-                NS_STYLE_COLUMN_FILL_BALANCE,
-                0, 0, 0, 0);
+              column->mColumnFill, canStoreInRuleTree,
+              SETDSC_ENUMERATED, parent->mColumnFill,
+              NS_STYLE_COLUMN_FILL_BALANCE,
+              0, 0, 0, 0);
 
   COMPUTE_END_RESET(Column, column)
 }
 
 static void
 SetSVGPaint(const nsCSSValue& aValue, const nsStyleSVGPaint& parentPaint,
             nsPresContext* aPresContext, nsStyleContext *aContext,
             nsStyleSVGPaint& aResult, nsStyleSVGPaintType aInitialPaintType,
--- a/layout/svg/base/src/Makefile.in
+++ b/layout/svg/base/src/Makefile.in
@@ -101,16 +101,17 @@ include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES	= \
 		-I$(srcdir)/../../../base \
 		-I$(srcdir)/../../../generic \
 		-I$(srcdir)/../../../style \
 		-I$(srcdir)/../../../xul/base/src \
 		-I$(srcdir)/../../../../content/svg/content/src \
 		-I$(srcdir)/../../../../content/base/src \
+		-I$(srcdir)/../../../../content/html/content/src \
 		$(NULL)
 
 libs::
 	$(INSTALL) $(srcdir)/svg.css $(DIST)/bin/res
 
 install::
 	$(SYSINSTALL) $(IFLAGS1) $(srcdir)/svg.css $(DESTDIR)$(mozappdir)/res
 
--- a/mobile/android/base/AndroidManifest.xml.in
+++ b/mobile/android/base/AndroidManifest.xml.in
@@ -56,16 +56,20 @@
                   android:configChanges="keyboard|keyboardHidden|mcc|mnc|orientation"
                   android:windowSoftInputMode="stateUnspecified|adjustResize"
                   android:launchMode="singleTask"
                   android:theme="@style/Gecko">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
+            <intent-filter>
+                <action android:name="org.mozilla.gecko.UPDATE"/>
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
 
             <!-- Default browser intents -->
             <intent-filter>
                 <action android:name="android.intent.action.VIEW" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <category android:name="android.intent.category.BROWSABLE" />
                 <data android:scheme="http" />
                 <data android:scheme="https" />
@@ -107,16 +111,17 @@
         </receiver>
 
         <activity android:name="Restarter"
                   android:process="@ANDROID_PACKAGE_NAME@Restarter"
                   android:theme="@style/Gecko"
                   android:excludeFromRecents="true">
           <intent-filter>
             <action android:name="org.mozilla.gecko.restart"/>
+            <action android:name="org.mozilla.gecko.restart_update"/>
           </intent-filter>
         </activity>
 
 #include ../sync/manifests/SyncAndroidManifest_activities.xml.in
 
 #if MOZ_CRASHREPORTER
   <activity android:name="CrashReporter"
             android:label="@string/crash_reporter_title"
--- a/mobile/android/base/AwesomeBar.java
+++ b/mobile/android/base/AwesomeBar.java
@@ -400,16 +400,21 @@ public class AwesomeBar extends Activity
             if (! (menuInfo instanceof ExpandableListView.ExpandableListContextMenuInfo)) {
                 Log.e(LOGTAG, "menuInfo is not ExpandableListContextMenuInfo");
                 return;
             }
             ExpandableListView.ExpandableListContextMenuInfo info = (ExpandableListView.ExpandableListContextMenuInfo) menuInfo;
             ExpandableListView exList = (ExpandableListView)list;
             int childPosition = ExpandableListView.getPackedPositionChild(info.packedPosition);
             int groupPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition);
+
+            // Check if long tap is on a header row
+            if (groupPosition < 0 || childPosition < 0)
+                return;
+
             selectedItem = exList.getExpandableListAdapter().getChild(groupPosition, childPosition);
 
             Map map = (Map)selectedItem;
             title = (String)map.get(URLColumns.TITLE);
         } else {
             if (! (menuInfo instanceof AdapterView.AdapterContextMenuInfo)) {
                 Log.e(LOGTAG, "menuInfo is not AdapterContextMenuInfo");
                 return;
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -100,16 +100,17 @@ abstract public class GeckoApp
     }
 
     public static final String ACTION_ALERT_CLICK   = "org.mozilla.gecko.ACTION_ALERT_CLICK";
     public static final String ACTION_ALERT_CLEAR   = "org.mozilla.gecko.ACTION_ALERT_CLEAR";
     public static final String ACTION_WEBAPP        = "org.mozilla.gecko.WEBAPP";
     public static final String ACTION_DEBUG         = "org.mozilla.gecko.DEBUG";
     public static final String ACTION_BOOKMARK      = "org.mozilla.gecko.BOOKMARK";
     public static final String ACTION_LOAD          = "org.mozilla.gecko.LOAD";
+    public static final String ACTION_UPDATE        = "org.mozilla.gecko.UPDATE";
     public static final String SAVED_STATE_URI      = "uri";
     public static final String SAVED_STATE_TITLE    = "title";
     public static final String SAVED_STATE_VIEWPORT = "viewport";
     public static final String SAVED_STATE_SCREEN   = "screen";
     public static final String SAVED_STATE_SESSION  = "session";
 
     StartupMode mStartupMode = null;
     private LinearLayout mMainLayout;
@@ -588,21 +589,20 @@ abstract public class GeckoApp
 
                 mLastUri = lastHistoryEntry.mUri;
                 mLastTitle = lastHistoryEntry.mTitle;
                 getAndProcessThumbnailForTab(tab);
             }
         }
     }
 
-    void getAndProcessThumbnailForTab(Tab tab) {
-        Bitmap bitmap = null;
-        if (Tabs.getInstance().isSelectedTab(tab))
-            bitmap = mSoftwareLayerClient.getBitmap();
-
+    void getAndProcessThumbnailForTab(final Tab tab) {
+        final Bitmap bitmap = Tabs.getInstance().isSelectedTab(tab) ?
+            mSoftwareLayerClient.getBitmap() : null;
+        
         if (bitmap != null) {
             ByteArrayOutputStream bos = new ByteArrayOutputStream();
             bitmap.compress(Bitmap.CompressFormat.PNG, 0, bos);
             processThumbnail(tab, bitmap, bos.toByteArray());
         } else {
             mLastScreen = null;
             GeckoAppShell.sendEventToGecko(
                 new GeckoEvent("Tab:Screenshot", 
@@ -1047,16 +1047,18 @@ abstract public class GeckoApp
                 GeckoPreferences.setCharEncodingState(visible);
                 if (sMenu != null) {
                     mMainHandler.post(new Runnable() {
                         public void run() {
                             sMenu.findItem(R.id.char_encoding).setVisible(visible);
                         }
                     });
                 }
+            } else if (event.equals("Update:Restart")) {
+                doRestart("org.mozilla.gecko.restart_update");
             }
         } catch (Exception e) {
             Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
         }
     }
 
     public void showAboutHome() {
         Runnable r = new AboutHomeRunnable(true);
@@ -1453,16 +1455,21 @@ abstract public class GeckoApp
                 mProfileDir = new File(m.group(1));
                 mLastUri = null;
                 mLastTitle = null;
                 mLastViewport = null;
                 mLastScreen = null;
             }
         }
 
+        if (ACTION_UPDATE.equals(intent.getAction()) || args != null && args.contains("-alert update-app")) {
+            Log.i(LOGTAG,"onCreate: Update request");
+            checkAndLaunchUpdate();
+        }
+
         String uri = intent.getDataString();
         String title = uri;
         if (uri != null && uri.length() > 0) {
             mLastUri = uri;
             mLastTitle = title;
         }
 
         if (mLastUri == null || mLastUri.equals("") ||
@@ -1601,16 +1608,17 @@ abstract public class GeckoApp
         GeckoAppShell.registerGeckoEventListener("Toast:Show", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("ToggleChrome:Hide", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("ToggleChrome:Show", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("FormAssist:AutoComplete", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("Permissions:Data", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("Downloads:Done", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("CharEncoding:Data", GeckoApp.mAppContext);
         GeckoAppShell.registerGeckoEventListener("CharEncoding:State", GeckoApp.mAppContext);
+        GeckoAppShell.registerGeckoEventListener("Update:Restart", GeckoApp.mAppContext);
 
         mConnectivityFilter = new IntentFilter();
         mConnectivityFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
         mConnectivityReceiver = new GeckoConnectivityReceiver();
 
         IntentFilter batteryFilter = new IntentFilter();
         batteryFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
         mBatteryReceiver = new GeckoBatteryManager();
@@ -1636,20 +1644,16 @@ abstract public class GeckoApp
                 if (localeCode != null && localeCode.length() > 0)
                     GeckoAppShell.setSelectedLocale(localeCode);
                 */
 
                 if (!checkLaunchState(LaunchState.Launched)) {
                     return;
                 }
 
-                // it would be good only to do this if MOZ_UPDATER was defined
-                long startTime = SystemClock.uptimeMillis();
-                checkAndLaunchUpdate();
-                Log.w(LOGTAG, "checking for an update took " + (SystemClock.uptimeMillis() - startTime) + "ms");
                 checkMigrateProfile();
             }
         }, 50);
 
         mOrientation = getResources().getConfiguration().orientation;
     }
 
     /**
@@ -2007,18 +2011,22 @@ abstract public class GeckoApp
             Map.Entry<String,String> entry = envIter.next();
             intent.putExtra("env" + c, entry.getKey() + "="
                             + entry.getValue());
             c++;
         }
     }
 
     public void doRestart() {
+        doRestart("org.mozilla.gecko.restart");
+    }
+
+    public void doRestart(String action) {
+        Log.i(LOGTAG, "doRestart(\"" + action + "\")");
         try {
-            String action = "org.mozilla.gecko.restart";
             Intent intent = new Intent(action);
             intent.setClassName(getPackageName(),
                                 getPackageName() + ".Restarter");
             /* TODO: addEnvToIntent(intent); */
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                             Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
             Log.i(LOGTAG, intent.toString());
             GeckoAppShell.killAnyZombies();
@@ -2103,22 +2111,29 @@ abstract public class GeckoApp
             Log.i(LOGTAG, "error reading update status", e);
         }
         return status;
     }
 
     private void checkMigrateProfile() {
         File profileDir = getProfileDir();
         if (profileDir != null) {
+            long currentTime = SystemClock.uptimeMillis();
             Log.i(LOGTAG, "checking profile migration in: " + profileDir.getAbsolutePath());
             final GeckoApp app = GeckoApp.mAppContext;
+            final SetupScreen setupScreen = new SetupScreen(app);
+            // don't show unless we take a while
+            setupScreen.showDelayed(mMainHandler);
             GeckoAppShell.ensureSQLiteLibsLoaded(app.getApplication().getPackageResourcePath());
             ProfileMigrator profileMigrator =
                 new ProfileMigrator(app.getContentResolver(), profileDir);
-            profileMigrator.launchBackground();
+            profileMigrator.launch();
+            setupScreen.dismiss();
+            long timeDiff = SystemClock.uptimeMillis() - currentTime;
+            Log.i(LOGTAG, "Profile migration took " + timeDiff + " ms");
         }
     }
 
     private SynchronousQueue<String> mFilePickerResult = new SynchronousQueue<String>();
     public String showFilePicker(String aMimeType) {
         Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
         intent.addCategory(Intent.CATEGORY_OPENABLE);
         intent.setType(aMimeType);
@@ -2358,17 +2373,17 @@ abstract public class GeckoApp
      */
     public void loadUrlInTab(String url) {
         ArrayList<Tab> tabs = Tabs.getInstance().getTabsInOrder();
         if (tabs != null) {
             Iterator<Tab> tabsIter = tabs.iterator();
             while (tabsIter.hasNext()) {
                 Tab tab = tabsIter.next();
                 if (url.equals(tab.getURL())) {
-                    GeckoAppShell.sendEventToGecko(new GeckoEvent("Tab:Select", String.valueOf(tab.getId())));
+                    Tabs.getInstance().selectTab(tab.getId());
                     return;
                 }
             }
         }
 
         JSONObject args = new JSONObject();
         try {
             args.put("url", url);
--- a/mobile/android/base/GeckoInputConnection.java
+++ b/mobile/android/base/GeckoInputConnection.java
@@ -430,28 +430,35 @@ public class GeckoInputConnection
         if (imm != null && imm.isFullscreenMode()) {
             View v = GeckoApp.mAppContext.getLayerController().getView();
             imm.updateSelection(v, start, end, -1, -1);
         }
     }
 
     public void reset() {
         mComposing = false;
+        mCompositionStart = -1;
         mBatchMode = false;
         mUpdateRequest = null;
     }
 
     // TextWatcher
     public void onTextChanged(CharSequence s, int start, int before, int count)
     {
+        if (mComposing && mCompositionStart != start) {
+            // Changed range is different from the composition, need to reset the composition
+            endComposition();
+        }
+
         if (!mComposing) {
             if (DEBUG) Log.d(LOGTAG, ". . . onTextChanged: IME_COMPOSITION_BEGIN");
             GeckoAppShell.sendEventToGecko(
                 new GeckoEvent(GeckoEvent.IME_COMPOSITION_BEGIN, 0, 0));
             mComposing = true;
+            mCompositionStart = start;
 
             if (DEBUG) Log.d(LOGTAG, ". . . onTextChanged: IME_SET_SELECTION, start=" + start + ", len=" + before);
             GeckoAppShell.sendEventToGecko(
                 new GeckoEvent(GeckoEvent.IME_SET_SELECTION, start, before));
         }
 
         if (count == 0) {
             if (DEBUG) Log.d(LOGTAG, ". . . onTextChanged: IME_DELETE_TEXT");
@@ -469,16 +476,17 @@ public class GeckoInputConnection
         GeckoAppShell.geckoEventSync();
     }
 
     private void endComposition() {
         if (DEBUG) Log.d(LOGTAG, "IME: endComposition: IME_COMPOSITION_END");
         GeckoAppShell.sendEventToGecko(
             new GeckoEvent(GeckoEvent.IME_COMPOSITION_END, 0, 0));
         mComposing = false;
+        mCompositionStart = -1;
     }
 
     private void sendTextToGecko(CharSequence text, int caretPos) {
         if (DEBUG) Log.d(LOGTAG, "IME: sendTextToGecko(\"" + text + "\")");
 
         // Handle composition text styles
         if (text != null && text instanceof Spanned) {
             Spanned span = (Spanned) text;
@@ -883,17 +891,18 @@ public class GeckoInputConnection
     public void initEditable(String contents)
     {
         mEditable = mEditableFactory.newEditable(contents);
         mEditable.setSpan(this, 0, contents.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
         Selection.setSelection(mEditable, contents.length());
     }
 
     // Is a composition active?
-    boolean mComposing;
+    private boolean mComposing;
+    private int mCompositionStart = -1;
 
     // IME stuff
     public static final int IME_STATE_DISABLED = 0;
     public static final int IME_STATE_ENABLED = 1;
     public static final int IME_STATE_PASSWORD = 2;
     public static final int IME_STATE_PLUGIN = 3;
 
     final CharacterStyle COMPOSING_SPAN = new UnderlineSpan();
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -47,29 +47,33 @@ include $(topsrcdir)/ipc/app/defs.mk
 DIRS = locales
 
 DIST_FILES = package-name.txt
 
 SYNC_JAVA_FILES=$(shell cat $(topsrcdir)/mobile/android/sync/java-sources.mn | tr '\n' ' ';)
 SYNC_PP_JAVA_FILES=$(shell cat $(topsrcdir)/mobile/android/sync/preprocess-sources.mn | tr '\n' ' ';)
 SYNC_THIRDPARTY_JAVA_FILES=$(shell cat $(topsrcdir)/mobile/android/sync/java-third-party-sources.mn | tr '\n' ' ';)
 SYNC_RES_DRAWABLE=$(shell cat $(topsrcdir)/mobile/android/sync/android-drawable-resources.mn | tr '\n' ' ';)
+SYNC_RES_DRAWABLE_LDPI=$(shell cat $(topsrcdir)/mobile/android/sync/android-drawable-ldpi-resources.mn | tr '\n' ' ';)
+SYNC_RES_DRAWABLE_MDPI=$(shell cat $(topsrcdir)/mobile/android/sync/android-drawable-mdpi-resources.mn | tr '\n' ' ';)
+SYNC_RES_DRAWABLE_HDPI=$(shell cat $(topsrcdir)/mobile/android/sync/android-drawable-hdpi-resources.mn | tr '\n' ' ';)
 SYNC_RES_LAYOUT=$(shell cat $(topsrcdir)/mobile/android/sync/android-layout-resources.mn | tr '\n' ' ';)
 SYNC_RES_VALUES=$(shell cat $(topsrcdir)/mobile/android/sync/android-values-resources.mn | tr '\n' ' ';)
 SYNC_RES_XML=res/xml/sync_authenticator.xml res/xml/sync_options.xml
 SYNC_PP_RES_XML=res/xml/sync_syncadapter.xml
 
 FENNEC_JAVA_FILES = \
   AboutHomeContent.java \
   AlertNotification.java \
   AutoCompletePopup.java \
   AwesomeBar.java \
   AwesomeBarTabs.java \
   BrowserToolbar.java \
   ConfirmPreference.java \
+  SyncPreference.java \
   db/AndroidBrowserDB.java \
   db/BrowserDB.java \
   db/LocalBrowserDB.java \
   DoorHanger.java \
   DoorHangerPopup.java \
   Favicons.java \
   FloatUtils.java \
   GeckoActionBar.java \
@@ -87,16 +91,17 @@ FENNEC_JAVA_FILES = \
   GeckoThread.java \
   GlobalHistory.java \
   LinkPreference.java \
   ProfileMigrator.java \
   PromptService.java \
   sqlite/ByteBufferInputStream.java \
   sqlite/SQLiteBridge.java \
   sqlite/SQLiteBridgeException.java \
+  SetupScreen.java \
   SurfaceLockInfo.java \
   Tab.java \
   Tabs.java \
   TabsTray.java \
   gfx/BitmapUtils.java \
   gfx/BufferedCairoImage.java \
   gfx/CairoGLInfo.java \
   gfx/CairoImage.java \
@@ -138,17 +143,16 @@ endif
 FENNEC_PP_JAVA_FILES = \
   App.java \
   LauncherShortcuts.java \
   NotificationHandler.java \
   Restarter.java \
   db/BrowserContract.java \
   db/BrowserProvider.java \
   SmsManager.java \
-  SyncPreference.java \
   $(NULL)
 
 
 ifneq (,$(findstring -march=armv7,$(OS_CFLAGS)))
 MIN_CPU_VERSION=7
 else
 MIN_CPU_VERSION=5
 endif
@@ -224,16 +228,17 @@ RES_LAYOUT = \
   res/layout/gecko_app.xml \
   res/layout/gecko_menu.xml \
   res/layout/launch_app_list.xml \
   res/layout/launch_app_listitem.xml \
   res/layout/notification_icon_text.xml \
   res/layout/notification_progress.xml \
   res/layout/notification_progress_text.xml \
   res/layout/site_setting_title.xml \
+  res/layout/setup_screen.xml \
   res/layout/tabs_row.xml \
   res/layout/tabs_tray.xml \
   res/layout/list_item_header.xml \
   res/layout/select_dialog_list.xml \
   res/layout/abouthome_content.xml \
   res/layout/abouthome_topsite_item.xml \
   res/layout/abouthome_addon_row.xml \
   res/layout/abouthome_last_tabs_row.xml \
@@ -270,16 +275,17 @@ RES_ANIM = \
 RES_DRAWABLE_NODPI = \
   res/drawable-nodpi/abouthome_bg.png \
   res/drawable-nodpi/abouthome_topsites_bg.png \
   res/drawable-nodpi/tabs_tray_bg.png \
   res/drawable-nodpi/tabs_tray_pressed_bg.png \
   $(NULL)
 
 RES_DRAWABLE_MDPI_V8 = \
+  res/drawable-mdpi-v8/favicon.png \
   res/drawable-mdpi-v8/abouthome_icon.png \
   res/drawable-mdpi-v8/abouthome_logo.png \
   res/drawable-mdpi-v8/abouthome_separator.9.png \
   res/drawable-mdpi-v8/abouthome_sync_logo.png \
   res/drawable-mdpi-v8/abouthome_sync_bg.9.png \
   res/drawable-mdpi-v8/abouthome_sync_pressed_bg.9.png \
   res/drawable-mdpi-v8/abouthome_topsite_placeholder.png \
   res/drawable-mdpi-v8/abouthome_topsite_shadow.9.png \
@@ -312,16 +318,17 @@ RES_DRAWABLE_MDPI_V8 = \
   res/drawable-mdpi-v8/doorhanger_shadow_bg.9.png \
   res/drawable-mdpi-v8/doorhanger_popup_bg.9.png \
   res/drawable-mdpi-v8/site_security_identified.png \
   res/drawable-mdpi-v8/site_security_verified.png \
   res/drawable-mdpi-v8/urlbar_stop.png \
   $(NULL)
 
 RES_DRAWABLE_HDPI_V8 = \
+  res/drawable-hdpi-v8/favicon.png \
   res/drawable-hdpi-v8/home_bg.png \
   res/drawable-hdpi-v8/home_star.png \
   res/drawable-hdpi-v8/abouthome_icon.png \
   res/drawable-hdpi-v8/abouthome_logo.png \
   res/drawable-hdpi-v8/abouthome_separator.9.png \
   res/drawable-hdpi-v8/abouthome_sync_logo.png \
   res/drawable-hdpi-v8/abouthome_sync_bg.9.png \
   res/drawable-hdpi-v8/abouthome_sync_pressed_bg.9.png \
@@ -376,16 +383,17 @@ RES_DRAWABLE_HDPI_V11 = \
   res/drawable-hdpi-v11/ic_menu_find_in_page.png \
   res/drawable-hdpi-v11/ic_menu_reload.png \
   res/drawable-hdpi-v11/ic_menu_save_as_pdf.png \
   res/drawable-hdpi-v11/ic_menu_share.png \
   res/drawable-hdpi-v11/ic_menu_forward.png \
   $(NULL)
 
 RES_DRAWABLE_XHDPI_V11 = \
+  res/drawable-xhdpi-v11/favicon.png \
   res/drawable-xhdpi-v11/abouthome_icon.png \
   res/drawable-xhdpi-v11/abouthome_logo.png \
   res/drawable-xhdpi-v11/abouthome_separator.9.png \
   res/drawable-xhdpi-v11/abouthome_sync_logo.png \
   res/drawable-xhdpi-v11/abouthome_sync_bg.9.png \
   res/drawable-xhdpi-v11/abouthome_sync_pressed_bg.9.png \
   res/drawable-xhdpi-v11/abouthome_topsite_placeholder.png \
   res/drawable-xhdpi-v11/abouthome_topsite_shadow.9.png \
@@ -489,17 +497,16 @@ MOZ_ANDROID_DRAWABLES += \
   mobile/android/base/resources/drawable/autocomplete_list_bg.9.png             \
   mobile/android/base/resources/drawable/awesomebar_tab_indicator.xml           \
   mobile/android/base/resources/drawable/awesomebar_tab_press.xml               \
   mobile/android/base/resources/drawable/awesomebar_tab_press_selected.xml      \
   mobile/android/base/resources/drawable/awesomebar_tab_selected.xml            \
   mobile/android/base/resources/drawable/awesomebar_tab_unselected.xml          \
   mobile/android/base/resources/drawable/background.png                         \
   mobile/android/base/resources/drawable/desktop_notification.png               \
-  mobile/android/base/resources/drawable/favicon.png                            \
   mobile/android/base/resources/drawable/gecko_actionbar_bg.xml                 \
   mobile/android/base/resources/drawable/progress_spinner.xml                   \
   mobile/android/base/resources/drawable/progress_spinner_1.png                 \
   mobile/android/base/resources/drawable/progress_spinner_2.png                 \
   mobile/android/base/resources/drawable/progress_spinner_3.png                 \
   mobile/android/base/resources/drawable/progress_spinner_4.png                 \
   mobile/android/base/resources/drawable/progress_spinner_5.png                 \
   mobile/android/base/resources/drawable/progress_spinner_6.png                 \
@@ -534,16 +541,19 @@ RESOURCES=$(RES_LAYOUT) $(RES_LAYOUT_V11
 RES_DIRS= \
   res/layout              \
   res/layout-v11          \
   res/values              \
   res/values-v11          \
   res/xml                 \
   res/anim                \
   res/drawable-nodpi      \
+  res/drawable-ldpi       \
+  res/drawable-mdpi       \
+  res/drawable-hdpi       \
   res/drawable-mdpi-v8    \
   res/drawable-hdpi-v8    \
   res/drawable-mdpi-v9    \
   res/drawable-hdpi-v9    \
   res/drawable-mdpi-v11   \
   res/drawable-hdpi-v11   \
   res/drawable-xhdpi-v11  \
   res/drawable-land-mdpi-v14  \
@@ -571,17 +581,20 @@ classes.dex: $(FENNEC_JAVA_FILES) $(FENN
 	$(DX) --dex --output=$@ classes
 
 PP_RES_XML=$(SYNC_PP_RES_XML)
 
 $(PP_RES_XML): $(subst res/,$(srcdir)/resources/, $(PP_RES_XML).in)
 	$(PYTHON) $(topsrcdir)/config/Preprocessor.py \
              $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $< > $@
 
-AndroidManifest.xml $(FENNEC_PP_JAVA_FILES) $(SYNC_PP_JAVA_FILES) package-name.txt: % : %.in Makefile.in
+# AndroidManifest.xml includes these files, so they need to be marked as dependencies.
+SYNC_MANIFEST_FRAGMENTS = $(wildcard $(topsrcdir)/mobile/android/sync/manifests/*.in)
+
+AndroidManifest.xml $(FENNEC_PP_JAVA_FILES) $(SYNC_PP_JAVA_FILES) package-name.txt: % : %.in Makefile.in $(SYNC_MANIFEST_FRAGMENTS)
 	mkdir -p db sync/repositories/android
 	$(PYTHON) $(topsrcdir)/config/Preprocessor.py \
              $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $< > $@
 
 res/drawable/icon.png: $(MOZ_APP_ICON)
 	$(NSINSTALL) -D res/drawable
 	cp $(ICON_PATH) $@
 
@@ -589,30 +602,45 @@ res/drawable-hdpi/icon.png: $(MOZ_APP_IC
 	$(NSINSTALL) -D res/drawable-hdpi
 	cp $(ICON_PATH_HDPI) $@
 
 RES_DRAWABLE = $(addprefix res/drawable/,$(notdir $(MOZ_ANDROID_DRAWABLES)))
 $(RES_DRAWABLE): $(addprefix $(topsrcdir)/,$(MOZ_ANDROID_DRAWABLES))
 	$(NSINSTALL) -D res/drawable
 	$(NSINSTALL) $^ res/drawable/
 
+RES_DRAWABLE_LDPI = $(addprefix res/drawable-ldpi/,$(notdir $(SYNC_RES_DRAWABLE_LDPI)))
+$(RES_DRAWABLE_LDPI): $(addprefix $(topsrcdir)/,$(SYNC_RES_DRAWABLE_LDPI))
+	$(NSINSTALL) -D res/drawable-ldpi
+	$(NSINSTALL) $^ res/drawable-ldpi/
+
+RES_DRAWABLE_MDPI = $(addprefix res/drawable-mdpi/,$(notdir $(SYNC_RES_DRAWABLE_MDPI)))
+$(RES_DRAWABLE_MDPI): $(addprefix $(topsrcdir)/,$(SYNC_RES_DRAWABLE_MDPI))
+	$(NSINSTALL) -D res/drawable-mdpi
+	$(NSINSTALL) $^ res/drawable-mdpi/
+
+RES_DRAWABLE_HDPI = $(addprefix res/drawable-hdpi/,$(notdir $(SYNC_RES_DRAWABLE_HDPI)))
+$(RES_DRAWABLE_HDPI): $(addprefix $(topsrcdir)/,$(SYNC_RES_DRAWABLE_HDPI))
+	$(NSINSTALL) -D res/drawable-hdpi
+	$(NSINSTALL) $^ res/drawable-hdpi/
+
 res/values/defaults.xml: $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/res/values/defaults.xml
 	$(NSINSTALL) -D res/values
 	$(NSINSTALL) $^  res/values
 
 $(RES_DIRS):
 	rm -rf $@
 	$(NSINSTALL) -D $@
 
 $(RESOURCES): $(RES_DIRS) $(subst res/,$(srcdir)/resources/,$(RESOURCES))
 	@echo "creating $@"
 	$(NSINSTALL) $(subst res/,$(srcdir)/resources/,$@) $(dir $@)
 
 
-R.java: $(MOZ_APP_ICON) $(RESOURCES) $(RES_DRAWABLE) $(PP_RES_XML) res/values/defaults.xml res/drawable/sync_icon.png res/drawable/icon.png res/drawable-hdpi/icon.png res/values/strings.xml AndroidManifest.xml FORCE
+R.java: $(MOZ_APP_ICON) $(RESOURCES) $(RES_DRAWABLE) $(RES_DRAWABLE_LDPI) $(RES_DRAWABLE_MDPI) $(RES_DRAWABLE_HDPI) $(PP_RES_XML) res/values/defaults.xml res/drawable/sync_icon.png res/drawable/icon.png res/drawable-hdpi/icon.png res/values/strings.xml AndroidManifest.xml FORCE
 	$(AAPT) package -f -M AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -J . --custom-package org.mozilla.gecko
 
-gecko.ap_: AndroidManifest.xml res/drawable/sync_icon.png res/drawable/icon.png res/drawable-hdpi/icon.png $(RESOURCES) $(RES_DRAWABLE) $(PP_RES_XML) res/values/defaults.xml res/values/strings.xml FORCE
+gecko.ap_: AndroidManifest.xml res/drawable/sync_icon.png res/drawable/icon.png res/drawable-hdpi/icon.png $(RESOURCES) $(RES_DRAWABLE) $(RES_DRAWABLE_LDPI) $(RES_DRAWABLE_MDPI) $(RES_DRAWABLE_HDPI) $(PP_RES_XML) res/values/defaults.xml res/values/strings.xml FORCE
 	$(AAPT) package -f -M AndroidManifest.xml -I $(ANDROID_SDK)/android.jar  -S res -F $@
 
 libs:: classes.dex package-name.txt
 	$(INSTALL) classes.dex $(FINAL_TARGET)
 	$(INSTALL) package-name.txt $(FINAL_TARGET)
--- a/mobile/android/base/ProfileMigrator.java
+++ b/mobile/android/base/ProfileMigrator.java
@@ -65,69 +65,70 @@ import java.util.Iterator;
 
 
 public class ProfileMigrator {
     private static final String LOGTAG = "ProfMigr";
     private File mProfileDir;
     private ContentResolver mCr;
 
     /*
-      Amount of Android history entries we will remember
-      to prevent moving their last access date backwards.
-    */
-    private static final int MAX_HISTORY_TO_CHECK = 1000;
-
-    /*
        These queries are derived from the low-level Places schema
        https://developer.mozilla.org/en/The_Places_database
     */
     private final String bookmarkQuery = "SELECT places.url AS a_url, "
         + "places.title AS a_title FROM "
         + "(moz_places as places JOIN moz_bookmarks as bookmarks ON "
         + "places.id = bookmarks.fk) WHERE places.hidden <> 1 "
         + "ORDER BY bookmarks.dateAdded";
     // Result column of relevant data
     private final String bookmarkUrl   = "a_url";
     private final String bookmarkTitle = "a_title";
 
+    /*
+      The sort criterion here corresponds to the one used for the
+      Awesomebar results. It's an simplification of Frecency.
+      We must divide date by 1000 due to the micro (Places)
+      vs milli (Android) distiction.
+    */
     private final String historyQuery =
-        "SELECT places.url AS a_url, places.title AS a_title, "
-        + "history.visit_date AS a_date FROM "
-        + "(moz_historyvisits AS history JOIN moz_places AS places ON "
-        + "places.id = history.place_id) WHERE places.hidden <> 1 "
-        + "ORDER BY history.visit_date DESC";
-    private final String historyUrl   = "a_url";
-    private final String historyTitle = "a_title";
-    private final String historyDate  = "a_date";
-
-    private final String faviconQuery =
-        "SELECT places.url AS a_url, favicon.data AS a_data, "
-        + "favicon.mime_type AS a_mime FROM (moz_places AS places JOIN "
-        + "moz_favicons AS favicon ON places.favicon_id = favicon.id)";
-    private final String faviconUrl  = "a_url";
-    private final String faviconData = "a_data";
-    private final String faviconMime = "a_mime";
+        "SELECT places.url AS a_url, places.title AS a_title,"
+        + "MAX(history.visit_date) AS a_date, COUNT(*) AS a_visits, "
+        // see BrowserDB.filterAllSites for this formula
+        + "MAX(1, (((MAX(history.visit_date)/1000) - ?) / 86400000 + 120)) AS a_recent, "
+        + "favicon.data AS a_favicon_data, favicon.mime_type AS a_favicon_mime "
+        + "FROM (moz_historyvisits AS history JOIN moz_places AS places "
+        + "ON places.id = history.place_id "
+        // Add favicon data if a favicon is present for this URL.
+        + "LEFT OUTER JOIN moz_favicons AS favicon "
+        + "ON places.favicon_id = favicon.id) "
+        + "WHERE places.hidden <> 1 "
+        + "GROUP BY a_url ORDER BY a_visits * a_recent DESC LIMIT ?";
+    private final String historyUrl    = "a_url";
+    private final String historyTitle  = "a_title";
+    private final String historyDate   = "a_date";
+    private final String historyVisits = "a_visits";
+    private final String faviconData   = "a_favicon_data";
+    private final String faviconMime   = "a_favicon_mime";
 
     public ProfileMigrator(ContentResolver cr, File profileDir) {
         mProfileDir = profileDir;
         mCr = cr;
     }
 
-    public void launchBackground() {
-        // Work around http://code.google.com/p/android/issues/detail?id=11291
-        // WebIconDatabase needs to be initialized within a looper thread.
-        GeckoAppShell.getHandler().post(new PlacesTask());
+    public void launch() {
+        new PlacesTask().run();
     }
 
     private class PlacesTask implements Runnable {
         // Get a list of the last times an URL was accessed
-        protected Map<String, Long> gatherAndroidHistory() {
+        protected Map<String, Long> gatherBrowserDBHistory() {
             Map<String, Long> history = new HashMap<String, Long>();
 
-            Cursor cursor = BrowserDB.getRecentHistory(mCr, MAX_HISTORY_TO_CHECK);
+            Cursor cursor =
+                BrowserDB.getRecentHistory(mCr, BrowserDB.getMaxHistoryCount());
             final int urlCol =
                 cursor.getColumnIndexOrThrow(BrowserDB.URLColumns.URL);
             final int dateCol =
                 cursor.getColumnIndexOrThrow(BrowserDB.URLColumns.DATE_LAST_VISITED);
 
             cursor.moveToFirst();
             while (!cursor.isAfterLast()) {
                 String url = cursor.getString(urlCol);
@@ -139,58 +140,81 @@ public class ProfileMigrator {
                 }
                 cursor.moveToNext();
             }
             cursor.close();
 
             return history;
         }
 
-        protected void addHistory(Map<String, Long> androidHistory,
-                                  String url, String title, long date) {
+        protected void addHistory(Map<String, Long> browserDBHistory,
+                                  String url, String title, long date, int visits) {
             boolean allowUpdate = false;
 
-            if (!androidHistory.containsKey(url)) {
-                // Android doesn't know the URL, allow it to be
-                // inserted with places date
+            if (!browserDBHistory.containsKey(url)) {
+                // BrowserDB doesn't know the URL, allow it to be
+                // inserted with places date.
                 allowUpdate = true;
             } else {
-                long androidDate = androidHistory.get(url);
+                long androidDate = browserDBHistory.get(url);
                 if (androidDate < date) {
-                    // Places URL hit is newer than Android,
-                    // allow it to be updated with places date
+                    // Places URL hit is newer than BrowserDB,
+                    // allow it to be updated with places date.
                     allowUpdate = true;
                 }
             }
 
             if (allowUpdate) {
                 BrowserDB.updateVisitedHistory(mCr, url);
-                BrowserDB.updateHistoryDate(mCr, url, date);
-                if (title != null) {
-                    BrowserDB.updateHistoryTitle(mCr, url, title);
-                }
+                // The above records one visit. Subtract that one visit here.
+                BrowserDB.updateHistoryEntry(mCr, url, title, date, visits - 1);
             }
         }
 
         protected void migrateHistory(SQLiteBridge db) {
-            Map<String, Long> androidHistory = gatherAndroidHistory();
+            Map<String, Long> browserDBHistory = gatherBrowserDBHistory();
             final ArrayList<String> placesHistory = new ArrayList<String>();
 
             try {
-                ArrayList<Object[]> queryResult = db.query(historyQuery);
+                final String[] queryParams = new String[] {
+                    /* current time */
+                    Long.toString(System.currentTimeMillis()),
+                    /*
+                       History entries to return. No point
+                       in retrieving more than we can store.
+                     */
+                    Integer.toString(BrowserDB.getMaxHistoryCount())
+                };
+                ArrayList<Object[]> queryResult =
+                    db.query(historyQuery, queryParams);
                 final int urlCol = db.getColumnIndex(historyUrl);
                 final int titleCol = db.getColumnIndex(historyTitle);
                 final int dateCol = db.getColumnIndex(historyDate);
+                final int visitsCol = db.getColumnIndex(historyVisits);
+                final int faviconMimeCol = db.getColumnIndex(faviconMime);
+                final int faviconDataCol = db.getColumnIndex(faviconData);
 
                 for (Object[] resultRow: queryResult) {
                     String url = (String)resultRow[urlCol];
                     String title = (String)resultRow[titleCol];
                     long date = Long.parseLong((String)(resultRow[dateCol])) / (long)1000;
-                    addHistory(androidHistory, url, title, date);
+                    int visits = Integer.parseInt((String)(resultRow[visitsCol]));
+                    addHistory(browserDBHistory, url, title, date, visits);
                     placesHistory.add(url);
+
+                    String mime = (String)resultRow[faviconMimeCol];
+                    if (mime != null) {
+                        // Some GIFs can cause us to lock up completely
+                        // without exceptions or anything. Not cool.
+                        if (mime.compareTo("image/gif") != 0) {
+                            ByteBuffer dataBuff =
+                                (ByteBuffer)resultRow[faviconDataCol];
+                            addFavicon(url, mime, dataBuff);
+                        }
+                    }
                 }
             } catch (SQLiteBridgeException e) {
                 Log.i(LOGTAG, "Failed to get bookmarks: " + e.getMessage());
                 return;
             }
             // GlobalHistory access communicates with Gecko
             // and must run on its thread
             GeckoAppShell.getHandler().post(new Runnable() {
@@ -236,35 +260,16 @@ public class ProfileMigrator {
                     BrowserDB.updateFaviconForUrl(mCr, url, image);
                 } catch (SQLException e) {
                     Log.i(LOGTAG, "Migrating favicon failed: " + mime + " URL: " + url
                           + " error:" + e.getMessage());
                 }
             }
         }
 
-        protected void migrateFavicons(SQLiteBridge db) {
-            try {
-                ArrayList<Object[]> queryResult = db.query(faviconQuery);
-                final int urlCol = db.getColumnIndex(faviconUrl);
-                final int mimeCol = db.getColumnIndex(faviconMime);
-                final int dataCol = db.getColumnIndex(faviconData);
-
-                for (Object[] resultRow: queryResult) {
-                    String url = (String)resultRow[urlCol];
-                    String mime = (String)resultRow[mimeCol];
-                    ByteBuffer dataBuff = (ByteBuffer)resultRow[dataCol];
-                    addFavicon(url, mime, dataBuff);
-                }
-            } catch (SQLiteBridgeException e) {
-                Log.i(LOGTAG, "Failed to get favicons: " + e.getMessage());
-                return;
-            }
-        }
-
         protected void migratePlaces(File aFile) {
             String dbPath = aFile.getPath() + "/places.sqlite";
             String dbPathWal = aFile.getPath() + "/places.sqlite-wal";
             String dbPathShm = aFile.getPath() + "/places.sqlite-shm";
             Log.i(LOGTAG, "Opening path: " + dbPath);
 
             File dbFile = new File(dbPath);
             if (!dbFile.exists()) {
@@ -274,17 +279,16 @@ public class ProfileMigrator {
             File dbFileWal = new File(dbPathWal);
             File dbFileShm = new File(dbPathShm);
 
             SQLiteBridge db = null;
             try {
                 db = new SQLiteBridge(dbPath);
                 migrateBookmarks(db);
                 migrateHistory(db);
-                migrateFavicons(db);
                 db.close();
 
                 // Clean up
                 dbFile.delete();
                 dbFileWal.delete();
                 dbFileShm.delete();
 
                 Log.i(LOGTAG, "Profile migration finished");
--- a/mobile/android/base/Restarter.java.in
+++ b/mobile/android/base/Restarter.java.in
@@ -70,17 +70,19 @@ public class Restarter extends Activity 
                         Thread.currentThread().sleep(100);
                     } catch (InterruptedException ie) {}
                 }
             }
         } catch (Exception e) {
             Log.i(LOGTAG, e.toString());
         }
         try {
-            String action = "android.intent.action.MAIN";
+            String action = "org.mozilla.gecko.restart_update".equals(getIntent().getAction()) ?
+                            App.ACTION_UPDATE : Intent.ACTION_MAIN;
+
             Intent intent = new Intent(action);
             intent.setClassName("@ANDROID_PACKAGE_NAME@",
                                 "@ANDROID_PACKAGE_NAME@.App");
             Bundle b = getIntent().getExtras();
             if (b != null)
                 intent.putExtras(b);
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             Log.i(LOGTAG, intent.toString());
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/SetupScreen.java
@@ -0,0 +1,148 @@
+/* -*- Mode: Java; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** 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 Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Gian-Carlo Pascutto <gpascutto@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.graphics.drawable.AnimationDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import android.widget.ImageView;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.mozilla.gecko.R;
+
+public class SetupScreen extends Dialog
+{
+    private static final String LOGTAG = "SetupScreen";
+    // Default delay before showing dialog, in milliseconds
+    private static final int DEFAULT_DELAY = 100;
+    private AnimationDrawable mProgressSpinner;
+    private Context mContext;
+    private Timer mTimer;
+    private TimerTask mShowTask;
+
+    public class ShowTask extends TimerTask {
+        private Handler mHandler;
+
+        public ShowTask(Handler aHandler) {
+            mHandler = aHandler;
+        }
+
+        @Override
+        public void run() {
+            mHandler.post(new Runnable() {
+                    public void run() {
+                        SetupScreen.this.show();
+                    }
+            });
+
+        }
+
+        @Override
+        public boolean cancel() {
+            boolean stillInQueue = super.cancel();
+            if (!stillInQueue) {
+                mHandler.post(new Runnable() {
+                        public void run() {
+                            // SetupScreen.dismiss calls us,
+                            // we need to call the real Dialog.dismiss.
+                            SetupScreen.super.dismiss();
+                        }
+                });
+            }
+            return stillInQueue;
+        }
+    }
+
+    public SetupScreen(Context aContext) {
+        super(aContext, android.R.style.Theme_NoTitleBar_Fullscreen);
+        mContext = aContext;
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.setup_screen);
+        setCancelable(false);
+
+        setTitle(R.string.splash_firstrun);
+
+        ImageView spinnerImage = (ImageView)findViewById(R.id.spinner_image);
+        mProgressSpinner = (AnimationDrawable)spinnerImage.getBackground();
+        spinnerImage.setImageDrawable(mProgressSpinner);
+    }
+
+    @Override
+    public void onWindowFocusChanged (boolean hasFocus) {
+        mProgressSpinner.start();
+    }
+
+    public void showDelayed(Handler aHandler) {
+        showDelayed(aHandler, DEFAULT_DELAY);
+    }
+
+    // Delay showing the dialog until at least aDelay ms have
+    // passed. We need to know the handler to (eventually) post the UI
+    // actions on.
+    public void showDelayed(Handler aHandler, int aDelay) {
+        mTimer = new Timer("SetupScreen");
+        mShowTask = new ShowTask(aHandler);
+        mTimer.schedule(mShowTask, aDelay);
+    }
+
+    @Override
+    public void dismiss() {
+        // Cancel the timers/tasks if we were using showDelayed,
+        // and post to the correct handler.
+        if (mShowTask != null) {
+            mShowTask.cancel();
+            mShowTask = null;
+        } else {
+            // If not using showDelayed, just dismiss here.
+            super.dismiss();
+        }
+        if (mTimer != null) {
+            mTimer.cancel();
+            mTimer = null;
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/SyncPreference.java
@@ -0,0 +1,73 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
+ * ***** 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 Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009-2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brian Nicholson <bnicholson@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.preference.Preference;
+import android.util.AttributeSet;
+import android.util.Log;
+
+import org.mozilla.gecko.sync.setup.activities.SetupSyncActivity;
+
+class SyncPreference extends Preference {
+    private static final String FENNEC_ACCOUNT_TYPE = "org.mozilla.firefox_sync";
+    private static final String SYNC_SETTINGS = "android.settings.SYNC_SETTINGS";
+
+    private Context mContext;
+
+    public SyncPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mContext = context;
+    }
+
+    @Override
+    protected void onClick() {
+        // show sync setup if no accounts exist; otherwise, show account settings
+        Account[] accounts = AccountManager.get(mContext).getAccountsByType(FENNEC_ACCOUNT_TYPE);
+        Intent intent;
+        if (accounts.length > 0)
+            intent = new Intent(SYNC_SETTINGS);
+        else
+            intent = new Intent(mContext, SetupSyncActivity.class);
+        mContext.startActivity(intent);
+    }
+}
deleted file mode 100644
--- a/mobile/android/base/SyncPreference.java.in
+++ /dev/null
@@ -1,81 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
- * ***** 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