Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Thu, 26 Jan 2012 11:58:33 -0800
changeset 105617 ed3aa00fc18196061909191f490ecdb63e8fdec0
parent 105616 7808b040fbe6ca978ab7161b7fa2679fe5038efa (current diff)
parent 85457 7cdb5f5d38c6bfe4e0f3c819bee95a119665be38 (diff)
child 105618 f59064acba0aa5d4666aba63d367b3d471a78fa1
push id23447
push userdanderson@mozilla.com
push dateTue, 11 Sep 2012 17:34:27 +0000
treeherderautoland@fdfaef738a00 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone12.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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);