Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Thu, 10 May 2012 13:44:10 -0700
changeset 106169 9d44cdf696eefdc936bf3a6cf37cb038e729c0f7
parent 106168 c68a877d643e8c45ba1703cf519b174f218ac188 (current diff)
parent 93716 d37d4edce6dd592f04afa606deb1ae327c07b4a4 (diff)
child 106170 41ccd541814046e7d47a1240b89772c8014a2826
child 106171 703d101ea135ee0a7118092183b2d4114b3c892d
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
milestone15.0a1
Merge from mozilla-central.
accessible/src/base/nsAccessible.cpp
browser/base/content/browser.js
browser/components/sessionstore/test/Makefile.in
browser/locales/en-US/chrome/browser/browser.properties
config/autoconf.mk.in
configure.in
content/base/src/nsContentAreaDragDrop.cpp
content/base/src/nsDocument.cpp
content/base/src/nsDocument.h
content/base/src/nsGenericElement.cpp
content/base/src/nsScriptLoader.cpp
content/base/test/Makefile.in
content/events/src/nsDOMUIEvent.cpp
content/events/src/nsDOMUIEvent.h
content/html/content/public/nsHTMLCanvasElement.h
content/html/content/public/nsIRadioGroupContainer.h
content/html/content/public/nsITextControlElement.h
content/html/content/src/nsGenericHTMLElement.cpp
content/html/content/src/nsGenericHTMLElement.h
content/html/content/src/nsHTMLButtonElement.cpp
content/html/content/src/nsHTMLCanvasElement.cpp
content/html/content/src/nsHTMLFormElement.cpp
content/html/content/src/nsHTMLFormElement.h
content/html/content/src/nsHTMLInputElement.cpp
content/html/content/src/nsHTMLInputElement.h
content/html/content/src/nsHTMLSelectElement.cpp
content/html/content/src/nsHTMLSelectElement.h
content/html/content/src/nsHTMLTextAreaElement.cpp
content/html/content/src/nsTextEditorState.cpp
content/media/nsBuiltinDecoderStateMachine.cpp
content/xbl/src/nsXBLService.cpp
content/xul/document/src/nsXULContentSink.cpp
docshell/base/nsDownloadHistory.cpp
docshell/base/nsIGlobalHistory.idl
dom/base/nsDOMWindowUtils.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsJSEnvironment.cpp
dom/base/nsJSEnvironment.h
dom/ipc/ContentChild.cpp
dom/workers/WorkerScope.cpp
editor/libeditor/base/nsEditor.h
editor/libeditor/base/nsEditorCommands.cpp
editor/libeditor/html/nsHTMLDataTransfer.cpp
editor/libeditor/html/nsHTMLEditor.cpp
editor/libeditor/html/nsHTMLEditor.h
embedding/browser/webBrowser/nsWebBrowser.cpp
extensions/spellcheck/src/mozInlineSpellWordUtil.cpp
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/gl/GLContextProviderCGL.mm
gfx/gl/GLContextProviderEGL.cpp
gfx/gl/GLContextProviderGLX.cpp
gfx/layers/opengl/CanvasLayerOGL.cpp
gfx/src/nsDeviceContext.cpp
js/src/Makefile.in
js/src/config/autoconf.mk.in
js/src/configure.in
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeEmitter-inl.h
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/FoldConstants.cpp
js/src/frontend/ParseNode.cpp
js/src/frontend/ParseNode.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/frontend/SemanticAnalysis.cpp
js/src/gc/Statistics.h
js/src/jit-test/tests/basic/bug740509.js
js/src/jsapi.cpp
js/src/jscntxt.h
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/jsfun.cpp
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsinfer.cpp
js/src/jsinfer.h
js/src/jsinferinlines.h
js/src/jsinterp.cpp
js/src/jsobj.cpp
js/src/jsreflect.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/methodjit/BaseAssembler.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/FastOps.cpp
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/MethodJIT.h
js/src/methodjit/MonoIC.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls.cpp
js/src/shell/js.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/RegExpObject.h
js/src/vm/Stack-inl.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
layout/base/FrameLayerBuilder.cpp
layout/base/FrameLayerBuilder.h
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsCSSFrameConstructor.h
layout/base/nsDisplayList.cpp
layout/base/nsFrameManager.cpp
layout/base/nsFrameManager.h
layout/base/nsIPresShell.h
layout/base/nsPresShell.cpp
layout/base/nsPresShell.h
layout/forms/nsListControlFrame.cpp
layout/generic/crashtests/crashtests.list
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsGfxScrollFrame.h
layout/generic/nsIScrollableFrame.h
layout/generic/nsSelection.cpp
layout/inspector/src/inDOMUtils.cpp
layout/reftests/bugs/reftest.list
layout/style/nsCSSParser.cpp
layout/style/nsCSSProps.cpp
layout/style/nsDOMCSSDeclaration.cpp
layout/style/nsRuleData.h
layout/style/nsRuleNode.cpp
layout/style/test/ListCSSProperties.cpp
layout/xul/base/src/nsMenuBarListener.cpp
layout/xul/base/src/nsScrollBoxObject.cpp
mobile/android/base/Makefile.in
mobile/android/branding/aurora/content/fennec_26x26.png
mobile/android/branding/aurora/content/fennec_40x40.png
mobile/android/branding/aurora/content/fennec_maemo_icon26.txt
mobile/android/branding/aurora/content/fennec_scalable.png
mobile/android/branding/aurora/content/splash.png
mobile/android/branding/aurora/content/splash_v8.9.png
mobile/android/branding/aurora/content/splash_v9.9.png
mobile/android/branding/beta/content/fennec_26x26.png
mobile/android/branding/beta/content/fennec_40x40.png
mobile/android/branding/beta/content/fennec_maemo_icon26.txt
mobile/android/branding/beta/content/fennec_scalable.png
mobile/android/branding/beta/content/splash.png
mobile/android/branding/beta/content/splash_v8.9.png
mobile/android/branding/beta/content/splash_v9.9.png
mobile/android/branding/nightly/content/fennec_26x26.png
mobile/android/branding/nightly/content/fennec_40x40.png
mobile/android/branding/nightly/content/fennec_maemo_icon26.txt
mobile/android/branding/nightly/content/fennec_scalable.png
mobile/android/branding/nightly/content/splash.png
mobile/android/branding/nightly/content/splash_v8.9.png
mobile/android/branding/nightly/content/splash_v9.9.png
mobile/android/branding/official/content/fennec_26x26.png
mobile/android/branding/official/content/fennec_40x40.png
mobile/android/branding/official/content/fennec_maemo_icon26.txt
mobile/android/branding/official/content/fennec_scalable.png
mobile/android/branding/official/content/splash.png
mobile/android/branding/official/content/splash_v8.9.png
mobile/android/branding/official/content/splash_v9.9.png
mobile/android/branding/unofficial/content/fennec_26x26.png
mobile/android/branding/unofficial/content/fennec_40x40.png
mobile/android/branding/unofficial/content/fennec_maemo_icon26.txt
mobile/android/branding/unofficial/content/fennec_scalable.png
mobile/android/branding/unofficial/content/splash.png
mobile/android/branding/unofficial/content/splash_v8.9.png
mobile/android/branding/unofficial/content/splash_v9.9.png
mobile/android/installer/debian/backup.in
mobile/android/installer/debian/changelog.in
mobile/android/installer/debian/compat.in
mobile/android/installer/debian/control.in
mobile/android/installer/debian/fennec-cud.sh.in
mobile/android/installer/debian/fennec-rfs.sh.in
mobile/android/installer/debian/fennec.aegis.in
mobile/android/installer/debian/fennec.conf.in
mobile/android/installer/debian/fennec.desktop.in
mobile/android/installer/debian/fennec.links.in
mobile/android/installer/debian/fennec.policy.in
mobile/android/installer/debian/fennec.postinst.in
mobile/android/installer/debian/fennec.preinst.in
mobile/android/installer/debian/fennec.prerm.in
mobile/android/installer/debian/fennec.service.in
mobile/android/installer/debian/files.in
mobile/android/installer/debian/menu.in
mobile/android/installer/debian/restore.in
netwerk/protocol/file/nsFileChannel.cpp
netwerk/protocol/http/nsHttpConnection.cpp
nsprpub/TAG-INFO
nsprpub/config/prdepend.h
nsprpub/pr/include/prinet.h
nsprpub/pr/src/pthreads/ptio.c
nsprpub/pr/tests/suspend.c
nsprpub/pr/tests/thruput.c
storage/public/mozIStorageStatementWrapper.idl
storage/src/mozStorageConnection.cpp
storage/src/mozStorageConnection.h
storage/src/mozStorageStatementWrapper.cpp
storage/src/mozStorageStatementWrapper.h
storage/test/unit/test_storage_statement_wrapper.js
toolkit/components/places/nsNavHistory.h
toolkit/components/telemetry/Telemetry.cpp
toolkit/components/telemetry/TelemetryPing.js
toolkit/mozapps/extensions/AddonRepository.jsm
toolkit/mozapps/extensions/AddonUpdateChecker.jsm
toolkit/mozapps/extensions/XPIProvider.jsm
toolkit/mozapps/extensions/content/extensions.js
toolkit/mozapps/extensions/nsBlocklistService.js
tools/trace-malloc/Makefile.in
widget/cocoa/nsChildView.mm
widget/gtk2/nsDragService.cpp
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -2233,16 +2233,19 @@ nsAccessible::DispatchClickEvent(nsICont
     return;
 
   nsCoreUtils::DispatchMouseEvent(NS_MOUSE_BUTTON_UP, presShell, aContent);
 }
 
 NS_IMETHODIMP
 nsAccessible::ScrollTo(PRUint32 aHow)
 {
+  if (IsDefunct())
+    return NS_ERROR_FAILURE;
+
   nsCoreUtils::ScrollTo(mDoc->PresShell(), mContent, aHow);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAccessible::ScrollToPoint(PRUint32 aCoordinateType, PRInt32 aX, PRInt32 aY)
 {
   nsIFrame *frame = GetFrame();
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -507,8 +507,10 @@ pref("app.update.log", true);
 // Extensions preferences
 pref("extensions.update.enabled", false);
 pref("extensions.getAddons.cache.enabled", false);
 
 // Context Menu
 pref("ui.click_hold_context_menus", true);
 pref("ui.click_hold_context_menus.delay", 1000);
 
+// Enable device storage
+pref("device.storage.enabled", true);
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -49,17 +49,17 @@ XPCOMUtils.defineLazyGetter(this, 'Debug
 // until we have a proper security model, add some rights to
 // the pre-installed web applications
 // XXX never grant 'content-camera' to non-gaia apps
 function addPermissions(urls) {
   let permissions = [
     'indexedDB', 'indexedDB-unlimited', 'webapps-manage', 'offline-app', 'pin-app',
     'websettings-read', 'websettings-readwrite',
     'content-camera', 'webcontacts-manage', 'wifi-manage', 'desktop-notification',
-    'geolocation'
+    'geolocation', 'device-storage'
   ];
   urls.forEach(function(url) {
     url = url.trim();
     let uri = Services.io.newURI(url, null, null);
     let allow = Ci.nsIPermissionManager.ALLOW_ACTION;
 
     permissions.forEach(function(permission) {
       Services.perms.add(uri, permission, allow);
--- a/browser/base/content/aboutDialog.js
+++ b/browser/base/content/aboutDialog.js
@@ -148,17 +148,17 @@ function appUpdater()
 
   if (this.updateDisabledAndLocked) {
     this.selectPanel("adminDisabled");
     return;
   }
 
   if (this.isPending) {
     this.setupUpdateButton("update.restart." +
-                           (this.isMajor ? "upgradeButton" : "applyButton"));
+                           (this.isMajor ? "upgradeButton" : "updateButton"));
     return;
   }
 
   if (this.isDownloading) {
     this.startDownload();
     return;
   }
 
@@ -537,17 +537,17 @@ appUpdater.prototype =
       break;
     case Components.results.NS_BINDING_ABORTED:
       // Do not remove UI listener since the user may resume downloading again.
       break;
     case Components.results.NS_OK:
       this.removeDownloadListener();
       this.selectPanel("updateButtonBox");
       this.setupUpdateButton("update.restart." +
-                             (this.isMajor ? "upgradeButton" : "applyButton"));
+                             (this.isMajor ? "upgradeButton" : "updateButton"));
       break;
     default:
       this.removeDownloadListener();
       this.selectPanel("downloadFailed");
       break;
     }
 
   },
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -7343,24 +7343,35 @@ var gPluginHandler = {
     },{
       label: gNavigatorBundle.getString("activatePluginsMessage.never"),
       accessKey: gNavigatorBundle.getString("activatePluginsMessage.never.accesskey"),
       callback: function () {
         Services.perms.add(aBrowser.currentURI, "plugins", Ci.nsIPermissionManager.DENY_ACTION);
         let notification = PopupNotifications.getNotification("click-to-play-plugins", aBrowser);
         if (notification)
           notification.remove();
+        gPluginHandler._removeClickToPlayOverlays(contentWindow);
       }
     }];
     let options = { dismissed: true };
     PopupNotifications.show(aBrowser, "click-to-play-plugins",
                             messageString, "plugins-notification-icon",
                             mainAction, secondaryActions, options);
   },
 
+  _removeClickToPlayOverlays: function PH_removeClickToPlayOverlays(aContentWindow) {
+    let doc = aContentWindow.document;
+    let cwu = aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                            .getInterface(Ci.nsIDOMWindowUtils);
+    for (let plugin of cwu.plugins) {
+      let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
+      overlay.style.visibility = "hidden";
+    }
+  },
+
   // event listener for missing/blocklisted/outdated/carbonFailure plugins.
   pluginUnavailable: function (plugin, eventType) {
     let browser = gBrowser.getBrowserForDocument(plugin.ownerDocument
                                                        .defaultView.top.document);
     if (!browser.missingPlugins)
       browser.missingPlugins = {};
 
     var pluginInfo = getPluginInfo(plugin);
--- a/browser/base/content/test/browser_pluginnotification.js
+++ b/browser/base/content/test/browser_pluginnotification.js
@@ -378,28 +378,32 @@ function test13a() {
 
 // Tests that the "Deny Always" permission works for click-to-play plugins (part 2/3)
 function test13b() {
   var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
   ok(!popupNotification, "Test 13b, Should not have a click-to-play notification");
   var plugin = gTestBrowser.contentDocument.getElementById("test");
   var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(!objLoadingContent.activated, "Test 13b, Plugin should not be activated");
+  var overlay = gTestBrowser.contentDocument.getAnonymousElementByAttribute(plugin, "class", "mainBox");
+  ok(overlay.style.visibility == "hidden", "Test 13b, Plugin should not have visible overlay");
 
   gNextTest = test13c;
   gTestBrowser.reload();
 }
 
 // Tests that the "Deny Always" permission works for click-to-play plugins (part 3/3)
 function test13c() {
   var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
   ok(!popupNotification, "Test 13c, Should not have a click-to-play notification");
   var plugin = gTestBrowser.contentDocument.getElementById("test");
   var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(!objLoadingContent.activated, "Test 13c, Plugin should not be activated");
+  var overlay = gTestBrowser.contentDocument.getAnonymousElementByAttribute(plugin, "class", "mainBox");
+  ok(overlay.style.visibility == "hidden", "Test 13c, Plugin should not have visible overlay");
 
   Services.perms.removeAll();
   Services.prefs.setBoolPref("plugins.click_to_play", false);
   prepareTest(test14, gTestRoot + "plugin_test2.html");
 }
 
 // Tests that the plugin's "activated" property is true for working plugins with click-to-play disabled.
 function test14() {
--- a/browser/base/content/test/browser_popupNotification.js
+++ b/browser/base/content/test/browser_popupNotification.js
@@ -256,17 +256,16 @@ var tests = [
       gBrowser.selectedTab = gNewTab;
     },
     onShown: function (popup) {
       checkPopup(popup, wrongBrowserNotificationObject);
       is(PopupNotifications.isPanelOpen, true, "isPanelOpen getter doesn't lie");
 
       // switch back to the old browser
       gBrowser.selectedTab = this.oldSelectedTab;
-
     },
     onHidden: function (popup) {
       // actually remove the notification to prevent it from reappearing
       ok(wrongBrowserNotificationObject.dismissalCallbackTriggered, "dismissal callback triggered due to tab switch");
       wrongBrowserNotification.remove();
       ok(wrongBrowserNotificationObject.removedCallbackTriggered, "removed callback triggered");
       wrongBrowserNotification = null;
     }
@@ -596,37 +595,30 @@ var tests = [
       ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered");
       this.notification.remove();
       ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
     }
   },
   // Test notification when chrome is hidden
   { // Test #19
     run: function () {
-      this.oldSelectedTab = gBrowser.selectedTab;
-      gBrowser.selectedTab = gBrowser.addTab("about:blank");
-
-      let self = this;
-      loadURI("about:addons", function() {
-        self.notifyObj = new basicNotification();
-        self.notification = showNotification(self.notifyObj);
-      });
+      window.locationbar.visible = false;
+      this.notifyObj = new basicNotification();
+      this.notification = showNotification(this.notifyObj);
+      window.locationbar.visible = true;
     },
     onShown: function (popup) {
       checkPopup(popup, this.notifyObj);
       is(popup.anchorNode.className, "tabbrowser-tab", "notification anchored to tab");
       dismissNotification(popup);
     },
     onHidden: function (popup) {
       ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered");
       this.notification.remove();
       ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
-
-      gBrowser.removeTab(gBrowser.selectedTab);
-      gBrowser.selectedTab = this.oldSelectedTab;
     }
   },
   // Test notification is removed when dismissed if removeOnDismissal is true
   { // Test #20
     run: function () {
       this.notifyObj = new basicNotification();
       this.notifyObj.addOptions({
         removeOnDismissal: true
--- a/browser/components/sessionstore/test/Makefile.in
+++ b/browser/components/sessionstore/test/Makefile.in
@@ -42,16 +42,18 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = browser/components/sessionstore/test
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 # browser_506482.js is disabled because of frequent failures (bug 538672)
 # browser_526613.js is disabled because of frequent failures (bug 534489)
+# browser_589246.js is disabled for leaking browser windows (bug 752467)
+# browser_580512.js is disabled for leaking browser windows (bug 752467)
 
 _BROWSER_TEST_FILES = \
 	head.js \
 	browser_form_restore_events.js \
 	browser_form_restore_events_sample.html \
 	browser_248970_a.js \
 	browser_248970_b.js \
 	browser_248970_b_sample.html \
@@ -116,23 +118,21 @@ include $(topsrcdir)/config/rules.mk
 	browser_500328.js \
 	browser_514751.js \
 	browser_522375.js \
 	browser_522545.js \
 	browser_524745.js \
 	browser_528776.js \
 	browser_579868.js \
 	browser_579879.js \
-	browser_580512.js \
 	browser_581593.js \
 	browser_581937.js \
 	browser_586147.js \
 	browser_586068-cascaded_restore.js \
 	browser_588426.js \
-	browser_589246.js \
 	browser_590268.js \
 	browser_590563.js \
 	browser_595601-restore_hidden.js \
 	browser_597315.js \
 	browser_597315_index.html \
 	browser_597315_a.html \
 	browser_597315_b.html \
 	browser_597315_c.html \
--- a/browser/devtools/debugger/debugger-view.js
+++ b/browser/devtools/debugger/debugger-view.js
@@ -506,37 +506,32 @@ function StackFramesView() {
 StackFramesView.prototype = {
 
   /**
    * Sets the current frames state based on the debugger active thread state.
    *
    * @param string aState
    *        Either "paused" or "attached".
    */
-  updateState: function DVF_updateState(aState) {
-    let resume = document.getElementById("resume");
-    let status = document.getElementById("status");
+   updateState: function DVF_updateState(aState) {
+     let resume = document.getElementById("resume");
 
-    // If we're paused, show a pause label and a resume label on the button.
-    if (aState == "paused") {
-      status.textContent = L10N.getStr("pausedState");
-      resume.label = L10N.getStr("resumeLabel");
-    }
-    // If we're attached, do the opposite.
-    else if (aState == "attached") {
-      status.textContent = L10N.getStr("runningState");
-      resume.label = L10N.getStr("pauseLabel");
-    }
-    // No valid state parameter.
-    else {
-      status.textContent = "";
-    }
+     // If we're paused, show a pause label and a resume label on the button.
+     if (aState == "paused") {
+       resume.label = L10N.getStr("resumeLabel");
+       resume.setAttribute("checked", true);
+     }
+     // If we're attached, do the opposite.
+     else if (aState == "attached") {
+       resume.label = L10N.getStr("pauseLabel");
+       resume.removeAttribute("checked");
+     }
 
-    DebuggerView.Scripts.clearSearch();
-  },
+     DebuggerView.Scripts.clearSearch();
+   },
 
   /**
    * Removes all elements from the stackframes container, leaving it empty.
    */
   empty: function DVF_empty() {
     while (this._frames.firstChild) {
       this._frames.removeChild(this._frames.firstChild);
     }
--- a/browser/devtools/debugger/debugger.css
+++ b/browser/devtools/debugger/debugger.css
@@ -38,29 +38,21 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 /**
  * Debugger content
  */
 
-#dbg-content > * > .vbox {
+.dbg-default {
   cursor: default;
 }
 
 /**
- * Debugger statusbar
- */
-
-#dbg-statusbar {
-  -moz-appearance: statusbar;
-}
-
-/**
  * Stack frames
  */
 
 #stack {
   width: 200px;
 }
 
 #stackframes {
@@ -168,26 +160,12 @@
   display: -moz-box;
   -moz-box-orient: vertical;
 }
 
 /**
  * Display helpers
  */
 
-.hbox {
-  display: -moz-box;
-  -moz-box-orient: horizontal;
-}
-
-.vbox {
-  display: -moz-box;
-  -moz-box-orient: vertical;
-}
-
-.flex {
-  -moz-box-flex: 1;
-}
-
 .unselectable {
   -moz-user-select: -moz-none;
   cursor: default;
 }
--- a/browser/devtools/debugger/debugger.xul
+++ b/browser/devtools/debugger/debugger.xul
@@ -18,16 +18,17 @@
    -   Mozilla Foundation.
    - Portions created by the Initial Developer are Copyright (C) 2011
    - the Initial Developer. All Rights Reserved.
    -
    - Contributor(s):
    -   Dave Camp <dcamp@mozilla.com>
    -   Panos Astithas <past@mozilla.com>
    -   Victor Porof <vporof@mozilla.com>
+   -   Rob Campbell <rcampbell@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
@@ -35,72 +36,86 @@
    - 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 ***** -->
 <?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/content/orion.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/content/debugger.css" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/skin/devtools/common.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/debugger.css" type="text/css"?>
 <!DOCTYPE window [
 <!ENTITY % debuggerDTD SYSTEM "chrome://browser/locale/devtools/debugger.dtd" >
  %debuggerDTD;
 ]>
 <?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
 <?xul-overlay href="chrome://browser/content/source-editor-overlay.xul"?>
 
-<xul:window xmlns="http://www.w3.org/1999/xhtml"
-            xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
-  <xul:script type="text/javascript" src="chrome://global/content/globalOverlay.js"/>
-  <xul:script type="text/javascript" src="debugger-controller.js"/>
-  <xul:script type="text/javascript" src="debugger-view.js"/>
+  <script type="text/javascript" src="chrome://global/content/globalOverlay.js"/>
+  <script type="text/javascript" src="debugger-controller.js"/>
+  <script type="text/javascript" src="debugger-view.js"/>
 
-  <xul:popupset id="debugger-popups">
-    <xul:menupopup id="sourceEditorContextMenu"
-                   onpopupshowing="goUpdateSourceEditorMenuItems()">
-      <xul:menuitem id="se-cMenu-copy"/>
-      <xul:menuseparator/>
-      <xul:menuitem id="se-cMenu-selectAll"/>
-      <xul:menuseparator/>
-      <xul:menuitem id="se-cMenu-find"/>
-      <xul:menuitem id="se-cMenu-findAgain"/>
-      <xul:menuseparator/>
-      <xul:menuitem id="se-cMenu-gotoLine"/>
-    </xul:menupopup>
-  </xul:popupset>
+  <popupset id="debugger-popups">
+    <menupopup id="sourceEditorContextMenu"
+               onpopupshowing="goUpdateSourceEditorMenuItems()">
+      <menuitem id="se-cMenu-copy"/>
+      <menuseparator/>
+      <menuitem id="se-cMenu-selectAll"/>
+      <menuseparator/>
+      <menuitem id="se-cMenu-find"/>
+      <menuitem id="se-cMenu-findAgain"/>
+      <menuseparator/>
+      <menuitem id="se-cMenu-gotoLine"/>
+    </menupopup>
+  </popupset>
 
-  <xul:commandset id="editMenuCommands"/>
-  <xul:commandset id="sourceEditorCommands"/>
-  <xul:keyset id="sourceEditorKeys"/>
+  <commandset id="editMenuCommands"/>
+  <commandset id="sourceEditorCommands"/>
+  <keyset id="sourceEditorKeys"/>
 
-  <div id="body" class="vbox flex">
-    <xul:toolbar id="dbg-toolbar">
-      <xul:button id="close" hidden="false">&debuggerUI.closeButton;</xul:button>
-      <xul:button id="resume"/>
-      <xul:button id="step-over">&debuggerUI.stepOverButton;</xul:button>
-      <xul:button id="step-in">&debuggerUI.stepInButton;</xul:button>
-      <xul:button id="step-out">&debuggerUI.stepOutButton;</xul:button>
-      <xul:menulist id="scripts"/>
-      <xul:textbox id="scripts-search" type="search"
-                   emptytext="&debuggerUI.emptyFilterText;"/>
-    </xul:toolbar>
-    <div id="dbg-content" class="hbox flex">
-      <div id="stack" class="vbox">
-        <div class="title unselectable">&debuggerUI.stackTitle;</div>
-        <div id="stackframes" class="vbox flex"></div>
-      </div>
-      <div id="script" class="vbox flex">
-        <div class="title unselectable">&debuggerUI.scriptTitle;</div>
-        <div id="editor" class="vbox flex"></div>
-      </div>
-      <div id="properties" class="vbox">
-        <div class="title unselectable">&debuggerUI.propertiesTitle;</div>
-        <div id="variables" class="vbox flex"></div>
-      </div>
-    </div>
-    <div id="dbg-statusbar">
-      <span id="status"></span>
-    </div>
-  </div>
-
-</xul:window>
+  <vbox id="body" flex="1">
+    <toolbar id="dbg-toolbar" class="devtools-toolbar">
+#ifdef XP_MACOSX
+      <toolbarbutton id="close" class="devtools-closebutton"/>
+#endif
+      <toolbarbutton id="resume"
+              class="devtools-toolbarbutton"
+              type="checkbox"
+              tabindex="0"/>
+      <toolbarbutton id="step-over"
+              class="devtools-toolbarbutton"
+              label="&debuggerUI.stepOverButton;"
+              tabindex="0"/>
+      <toolbarbutton id="step-in"
+              class="devtools-toolbarbutton"
+              label="&debuggerUI.stepInButton;"
+              tabindex="0"/>
+      <toolbarbutton id="step-out"
+              class="devtools-toolbarbutton"
+              label="&debuggerUI.stepOutButton;"
+              tabindex="0"/>
+      <menulist id="scripts" class="devtools-menulist"
+                label="&debuggerUI.emptyScriptText;"/>
+      <textbox id="scripts-search" type="search"
+               emptytext="&debuggerUI.emptyFilterText;"/>
+      <spacer flex="1"/>
+#ifndef XP_MACOSX
+      <toolbarbutton id="close" class="devtools-closebutton"/>
+#endif
+    </toolbar>
+    <hbox id="dbg-content" flex="1">
+      <vbox id="stack" flex="1">
+        <vbox id="stackframes" class="dbg-default" flex="1"/>
+      </vbox>
+      <splitter id="stack-script-splitter"
+                class="devtools-side-splitter"/>
+      <vbox id="editor" class="dbg-default" flex="1"/>
+      <splitter id="script-properties-splitter"
+                class="devtools-side-splitter"/>
+      <vbox id="properties" flex="1">
+        <vbox id="variables" class="dbg-default" flex="1"/>
+      </vbox>
+    </hbox>
+  </vbox>
+</window>
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -145,18 +145,18 @@ sanitizeSelectedWarning=All selected ite
 # directly under the Firefox version in the about dialog (see bug 596813 for
 # screenshots).
 update.checkInsideButton.label=Check for Updates
 update.checkInsideButton.accesskey=C
 update.resumeButton.label=Resume Downloading %S…
 update.resumeButton.accesskey=D
 update.openUpdateUI.applyButton.label=Apply Update…
 update.openUpdateUI.applyButton.accesskey=A
-update.restart.applyButton.label=Apply Update
-update.restart.applyButton.accesskey=A
+update.restart.updateButton.label=Restart to Update
+update.restart.updateButton.accesskey=R
 update.openUpdateUI.upgradeButton.label=Upgrade Now…
 update.openUpdateUI.upgradeButton.accesskey=U
 update.restart.upgradeButton.label=Upgrade Now
 update.restart.upgradeButton.accesskey=U
 
 # RSS Pretty Print
 feedShowFeedNew=Subscribe to '%S'…
 
--- a/browser/locales/en-US/chrome/browser/devtools/debugger.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/debugger.dtd
@@ -51,8 +51,12 @@
 <!-- LOCALIZATION NOTE (debuggerUI.propertiesTitle): This is the label for the
   -  widget that displays the variables in the various available scopes in the
   -  debugger. -->
 <!ENTITY debuggerUI.propertiesTitle  "Scope variables">
 
 <!-- LOCALIZATION NOTE (debuggerUI.emptyFilterText): This is the text that
   -  appears in the filter text box when it is empty. -->
 <!ENTITY debuggerUI.emptyFilterText  "Filter scripts">
+
+<!-- LOCALIZATION NOTE (emptyScriptText): The text to display in the menulist when
+  - there are no scripts. -->
+<!ENTITY debuggerUI.emptyScriptText  "No scripts.">
--- a/browser/themes/gnomestripe/browser.css
+++ b/browser/themes/gnomestripe/browser.css
@@ -1046,16 +1046,20 @@ toolbar[iconsize="small"] #feed-button {
 .verifiedDomain > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon {
   list-style-image: url(chrome://browser/skin/identity-icons-https.png);
 }
 
 .verifiedIdentity > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon {
   list-style-image: url(chrome://browser/skin/identity-icons-https-ev.png);
 }
 
+.mixedContent > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon {
+  list-style-image: url(chrome://browser/skin/identity-icons-https-mixed.png);
+}
+
 #identity-box:hover > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon {
   -moz-image-region: rect(0, 32px, 16px, 16px);
 }
 
 #identity-box:hover:active > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon,
 #identity-box[open=true] > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon {
   -moz-image-region: rect(0, 48px, 16px, 32px);
 }
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3c77bc84dbd1912d7dd5a654db126bb49f669c0e
GIT binary patch
literal 984
zc$@*)11J26P)<h;3K|Lk000e1NJLTq001xm000mO1^@s6P_F#3000A@Nkl<Zc-pPj
z+e;Kt90%|-yXkJOV>`PdsZr5oBhpIop`h%=9-^e4lF-*)dg_1ZLS+^~MQP;))5_Fz
zt<<!OL|A`7k3mFqfgWbk-R-#UukR0!G&?)hNIiVucYYT*zcY#oBKjxtMbwQ30Wg?~
zHMd@RRpv&602oZgnp^L0FJ=vIFNL>C`4Sh%lT*<uc&F5GZV3zIrQ&*(*`>W>h-)~v
zv;~H?-2zfNmau>Z1`Giyah20NETDm5b^C|R4nYiYoO7UgTEH6I8iP3?rs7Q=7s!{-
zBX#mwBn_mbk=x5P4-4cc2Sat{O_2st(#Y-Qnzse|D|&$77#vq|uZIORh{(yvD3E*_
zIRh;m!x+~bU%~D5BUZbA)NB(p)17~2raP~NW8}uT2HGDNu==)afq6))vmZ$1D*v)T
zJ}$gZP8jnH=k*XnOngRdzxst1O78355A8Fri+P6g`pneI7-Hgcvaeu2a)CcDaCh^4
zASDcj?cDF^&wc$T;Ym3jCWZ@FK;`0@Yv_sEzC!NnxB4c{tAdyuF)HLpxN`B#HS|P5
zb6vpdja5MgNLd4`ftadQyDxy3ePSGxqbo8%z^}d=c5$p^&~u1;T^0x=dJ7JkmqiAM
zrTX>Vu#00QgPud&>%PG44RIiwt+2t7d+4%&22nX$G$kJwk-{%tFDJrv_8fX%+P;GQ
z^`q7m-;{Yt(4u5ds6KVCu+E-C&rADP_;vZNbvu9@YN664ztgcmK#qkE%ZEjjWjuTo
zOEft1=xxAE5PrRW*Yd;W1wnR+?t-JKyLv-TzH@m4W`fxZbgUf*@@T@gfDel0h(0aj
zI(dQK*E|D0T!Ix_7k$%avmh_f`<iFKw{ZDet80NAK0pjM!h4tc9<@MFJ}PRGLxtq<
z1utC>2M~X9)_I0!`6UxKgH7gHL0Ou$FR43vJsd#%$yuMh5p3ewg#~V`ngnua=bEaw
zy41(j0tPPhMm`8pmf^x-)XEs*0cRaE(>zQ3SNELnjd@y-oz>zWMy-r}Z}AW0)SG?N
zJiBng)^ZET;WN}gHGFib&!`28<v?f_$l)7axluk^aRl*KmwJL{`A5M#C1%Z&g0h^_
zz9l<Cjmgf?5yW3}>mtFk3kzH?Jpn&}Jd$u)EuiB?ugU%b3FOfnX4-fbm(ahTUv|wr
zAtaDTbC_x4+5hqHv>$XRfl`l3)QlgOU^<jQsYfMh#{Uz42otVIyrNV90000<MNUMn
GLSTaaO3}9f
--- a/browser/themes/gnomestripe/jar.mn
+++ b/browser/themes/gnomestripe/jar.mn
@@ -17,16 +17,17 @@ browser.jar:
 * skin/classic/browser/engineManager.css              (engineManager.css)
   skin/classic/browser/Geolocation-16.png
   skin/classic/browser/Geolocation-64.png
   skin/classic/browser/Go-arrow.png
   skin/classic/browser/identity.png
   skin/classic/browser/identity-icons-generic.png
   skin/classic/browser/identity-icons-https.png
   skin/classic/browser/identity-icons-https-ev.png
+  skin/classic/browser/identity-icons-https-mixed.png
   skin/classic/browser/Info.png
   skin/classic/browser/KUI-close.png
   skin/classic/browser/monitor.png
   skin/classic/browser/monitor_16-10.png
 * skin/classic/browser/pageInfo.css
   skin/classic/browser/pageInfo.png
   skin/classic/browser/page-livemarks.png
   skin/classic/browser/Privacy-16.png
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -1103,16 +1103,20 @@ toolbar[mode="icons"] #zoom-in-button {
 .verifiedDomain > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon {
   list-style-image: url(chrome://browser/skin/identity-icons-https.png);
 }
 
 .verifiedIdentity > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon {
   list-style-image: url(chrome://browser/skin/identity-icons-https-ev.png);
 }
 
+.mixedContent > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon {
+  list-style-image: url(chrome://browser/skin/identity-icons-https-mixed.png);
+}
+
 #identity-box:hover:active > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon,
 #identity-box[open=true] > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon {
   -moz-image-region: rect(0, 32px, 16px, 16px);
 }
 
 #page-proxy-favicon[pageproxystate="invalid"] {
   opacity: 0.5;
 }
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..83ba37c2461fce9e9b0bac4a63bbfc9336263f1e
GIT binary patch
literal 679
zc$@*J0$BZtP)<h;3K|Lk000e1NJLTq001BW000mO1^@s6cL04^0007RNkl<Zc-pPi
z-Ahw(7zgm*IVat84P1&e4U4ix_)>}&1!XsO5hZn%MBaAORsVx2m01K8Ip3x%m+2B;
zf|9(E2<s2%GKh#Q=;C+OZB5<N_hG;2cy=6T)Wrv$^StbQx0?wf`Zw>YoM_;I08_Q*
zw7cU6o3qD*@KLEQFhEgi&fg@*v`-9m3-<~OFmr4eNQo2>K!bo8HD+W)5JNr3J<wbQ
zFsB<sumQwWeZ*ye;^efiO%91oAY~K1vpjPbAYMNX1lQq)s$(t!Xt2i|F<!|5L2J?C
zTWisxKCaPw%`?#Q1~4b<>R<~t)w2PldJXvl;M-66&dGkU#qfM6v$Qvan)o?6S$ZBl
zPyPTCN2h?4G6(=Eaoc|Gw-4)!^06S6o)6Tg=gS(nW<0}AIcSan%vh)iGC<0Hr~zVX
z*1SUiPa;-&Q9cwIAeM^zPs1s$l?-++@vd`#r?qoH7L8DA>%DXcph3C$NMDi<1pSd5
z_qC^<?{2g9u=CdXEBt-=*ufJ(Hm%U$&_8Jl;7N>?T$c9)StX*S*HRPyj-38zNe6Dc
z+XF-nEC9Lm#u7k>3iH0cEPDmHf!+6f1A6x5!!@lyHeVnFhvBos{EQ0VO$>QE<!wRR
z^lINz&;0Fh0rfZge0|W{$+y`6gZmbNY({vd=3$5Vf(j5Y@8}<7k02|v&zQxmimmn;
zFLLI+`ZC{UUl6V~foxWw1)AZj!+cEzsF2-aUEUP5O}F+l8S!0Bj{2^k{*gNu3BJt+
z=nr<mFCdrF(4zwQSMTn6BD+Ky$fXV34Djv$_&YYh50wyfsZ!k-zX7A*-Ro;sLOuWh
N002ovPDHLkV1oZgJv0CS
--- a/browser/themes/pinstripe/jar.mn
+++ b/browser/themes/pinstripe/jar.mn
@@ -23,16 +23,17 @@ browser.jar:
   skin/classic/browser/hud-style-expander-closed.png
   skin/classic/browser/hud-style-expander-open.png
   skin/classic/browser/hud-style-new-folder-plus-sign.png
   skin/classic/browser/hud-style-twisties.png
   skin/classic/browser/identity.png
   skin/classic/browser/identity-icons-generic.png
   skin/classic/browser/identity-icons-https.png
   skin/classic/browser/identity-icons-https-ev.png
+  skin/classic/browser/identity-icons-https-mixed.png
   skin/classic/browser/Info.png
   skin/classic/browser/KUI-background.png
   skin/classic/browser/KUI-close.png
   skin/classic/browser/menu-back.png
   skin/classic/browser/menu-forward.png
   skin/classic/browser/page-livemarks.png
   skin/classic/browser/pageInfo.css
   skin/classic/browser/Privacy-16.png
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -1476,16 +1476,20 @@ html|*.urlbar-input:-moz-lwtheme:-moz-pl
 .verifiedDomain > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon {
   list-style-image: url(chrome://browser/skin/identity-icons-https.png);
 }
 
 .verifiedIdentity > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon {
   list-style-image: url(chrome://browser/skin/identity-icons-https-ev.png);
 }
 
+.mixedContent > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon {
+  list-style-image: url(chrome://browser/skin/identity-icons-https-mixed.png);
+}
+
 #identity-box:hover > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon {
   -moz-image-region: rect(0, 32px, 16px, 16px);
 }
 
 #identity-box:hover:active > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon,
 #identity-box[open=true] > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon {
   -moz-image-region: rect(0, 48px, 16px, 32px);
 }
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3c77bc84dbd1912d7dd5a654db126bb49f669c0e
GIT binary patch
literal 984
zc$@*)11J26P)<h;3K|Lk000e1NJLTq001xm000mO1^@s6P_F#3000A@Nkl<Zc-pPj
z+e;Kt90%|-yXkJOV>`PdsZr5oBhpIop`h%=9-^e4lF-*)dg_1ZLS+^~MQP;))5_Fz
zt<<!OL|A`7k3mFqfgWbk-R-#UukR0!G&?)hNIiVucYYT*zcY#oBKjxtMbwQ30Wg?~
zHMd@RRpv&602oZgnp^L0FJ=vIFNL>C`4Sh%lT*<uc&F5GZV3zIrQ&*(*`>W>h-)~v
zv;~H?-2zfNmau>Z1`Giyah20NETDm5b^C|R4nYiYoO7UgTEH6I8iP3?rs7Q=7s!{-
zBX#mwBn_mbk=x5P4-4cc2Sat{O_2st(#Y-Qnzse|D|&$77#vq|uZIORh{(yvD3E*_
zIRh;m!x+~bU%~D5BUZbA)NB(p)17~2raP~NW8}uT2HGDNu==)afq6))vmZ$1D*v)T
zJ}$gZP8jnH=k*XnOngRdzxst1O78355A8Fri+P6g`pneI7-Hgcvaeu2a)CcDaCh^4
zASDcj?cDF^&wc$T;Ym3jCWZ@FK;`0@Yv_sEzC!NnxB4c{tAdyuF)HLpxN`B#HS|P5
zb6vpdja5MgNLd4`ftadQyDxy3ePSGxqbo8%z^}d=c5$p^&~u1;T^0x=dJ7JkmqiAM
zrTX>Vu#00QgPud&>%PG44RIiwt+2t7d+4%&22nX$G$kJwk-{%tFDJrv_8fX%+P;GQ
z^`q7m-;{Yt(4u5ds6KVCu+E-C&rADP_;vZNbvu9@YN664ztgcmK#qkE%ZEjjWjuTo
zOEft1=xxAE5PrRW*Yd;W1wnR+?t-JKyLv-TzH@m4W`fxZbgUf*@@T@gfDel0h(0aj
zI(dQK*E|D0T!Ix_7k$%avmh_f`<iFKw{ZDet80NAK0pjM!h4tc9<@MFJ}PRGLxtq<
z1utC>2M~X9)_I0!`6UxKgH7gHL0Ou$FR43vJsd#%$yuMh5p3ewg#~V`ngnua=bEaw
zy41(j0tPPhMm`8pmf^x-)XEs*0cRaE(>zQ3SNELnjd@y-oz>zWMy-r}Z}AW0)SG?N
zJiBng)^ZET;WN}gHGFib&!`28<v?f_$l)7axluk^aRl*KmwJL{`A5M#C1%Z&g0h^_
zz9l<Cjmgf?5yW3}>mtFk3kzH?Jpn&}Jd$u)EuiB?ugU%b3FOfnX4-fbm(ahTUv|wr
zAtaDTbC_x4+5hqHv>$XRfl`l3)QlgOU^<jQsYfMh#{Uz42otVIyrNV90000<MNUMn
GLSTaaO3}9f
--- a/browser/themes/winstripe/jar.mn
+++ b/browser/themes/winstripe/jar.mn
@@ -23,16 +23,17 @@ browser.jar:
         skin/classic/browser/Geolocation-64.png
         skin/classic/browser/webapps-16.png
         skin/classic/browser/webapps-64.png
         skin/classic/browser/Info.png                                (Info.png)
         skin/classic/browser/identity.png                            (identity.png)
         skin/classic/browser/identity-icons-generic.png
         skin/classic/browser/identity-icons-https.png
         skin/classic/browser/identity-icons-https-ev.png
+        skin/classic/browser/identity-icons-https-mixed.png
         skin/classic/browser/keyhole-forward-mask.svg
         skin/classic/browser/KUI-background.png
         skin/classic/browser/KUI-close.png
         skin/classic/browser/pageInfo.css
         skin/classic/browser/pageInfo.png                            (pageInfo.png)
         skin/classic/browser/page-livemarks.png                      (feeds/feedIcon16.png)
         skin/classic/browser/livemark-folder.png                     (livemark-folder.png)
         skin/classic/browser/Privacy-16.png
@@ -210,16 +211,17 @@ browser.jar:
         skin/classic/aero/browser/Geolocation-64.png
         skin/classic/aero/browser/webapps-16.png
         skin/classic/aero/browser/webapps-64.png
         skin/classic/aero/browser/Info.png                           (Info-aero.png)
         skin/classic/aero/browser/identity.png                       (identity-aero.png)
         skin/classic/aero/browser/identity-icons-generic.png
         skin/classic/aero/browser/identity-icons-https.png
         skin/classic/aero/browser/identity-icons-https-ev.png
+        skin/classic/aero/browser/identity-icons-https-mixed.png
         skin/classic/aero/browser/keyhole-forward-mask.svg
         skin/classic/aero/browser/KUI-background.png
         skin/classic/aero/browser/KUI-close.png
         skin/classic/aero/browser/pageInfo.css
         skin/classic/aero/browser/pageInfo.png                       (pageInfo-aero.png)
         skin/classic/aero/browser/page-livemarks.png                 (feeds/feedIcon16-aero.png)
         skin/classic/aero/browser/livemark-folder.png                (livemark-folder-aero.png)
         skin/classic/aero/browser/Privacy-16.png                     (Privacy-16-aero.png)
--- a/build/automationutils.py
+++ b/build/automationutils.py
@@ -454,17 +454,17 @@ def wrapCommand(cmd):
   return cmd
 
 class ShutdownLeakLogger(object):
   """
   Parses the mochitest run log when running a debug build, assigns all leaked
   DOM windows (that are still around after test suite shutdown, despite running
   the GC) to the tests that created them and prints leak statistics.
   """
-  MAX_LEAK_COUNT = 21
+  MAX_LEAK_COUNT = 11
 
   def __init__(self, logger):
     self.logger = logger
     self.tests = []
     self.leakedWindows = {}
     self.leakedDocShells = set()
     self.currentTest = None
     self.seenShutdown = False
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -634,17 +634,16 @@ MOZ_PSM=@MOZ_PSM@
 GSSAPI_INCLUDES = @GSSAPI_INCLUDES@
 USE_GSSAPI	= @USE_GSSAPI@
 
 MOZILLA_OFFICIAL = @MOZILLA_OFFICIAL@
 
 # Win32 options
 MOZ_BROWSE_INFO	= @MOZ_BROWSE_INFO@
 MOZ_TOOLS_DIR	= @MOZ_TOOLS_DIR@
-MOZ_QUANTIFY	= @MOZ_QUANTIFY@
 MSMANIFEST_TOOL = @MSMANIFEST_TOOL@
 WIN32_REDIST_DIR = @WIN32_REDIST_DIR@
 MOZ_GLUE_LDFLAGS = @MOZ_GLUE_LDFLAGS@
 MOZ_GLUE_PROGRAM_LDFLAGS = @MOZ_GLUE_PROGRAM_LDFLAGS@
 WIN32_CRT_LIBS = @WIN32_CRT_LIBS@
 
 # This is used to pass jemalloc flags to NSS
 DLLFLAGS = @DLLFLAGS@
--- a/config/config.mk
+++ b/config/config.mk
@@ -216,27 +216,16 @@ OS_CXXFLAGS += -UDEBUG -DNDEBUG
 OS_CFLAGS += -UDEBUG -DNDEBUG
 ifdef HAVE_64BIT_OS
 OS_LDFLAGS += -DEBUG -OPT:REF,ICF
 else
 OS_LDFLAGS += -DEBUG -OPT:REF
 endif
 endif
 
-ifdef MOZ_QUANTIFY
-# -FIXED:NO is needed for Quantify to work, but it increases the size
-# of executables, so only use it if building for Quantify.
-WIN32_EXE_LDFLAGS += -FIXED:NO
-
-# We need -OPT:NOICF to prevent identical methods from being merged together.
-# Otherwise, Quantify doesn't know which method was actually called when it's
-# showing you the profile.
-OS_LDFLAGS += -OPT:NOICF
-endif
-
 #
 # Handle trace-malloc in optimized builds.
 # No opt to give sane callstacks.
 #
 ifdef NS_TRACE_MALLOC
 MOZ_OPTIMIZE_FLAGS=-Zi -Od -UDEBUG -DNDEBUG
 ifdef HAVE_64BIT_OS
 OS_LDFLAGS = -DEBUG -PDB:NONE -OPT:REF,ICF
@@ -398,18 +387,16 @@ endif
 #
 MY_CONFIG	:= $(DEPTH)/config/myconfig.mk
 MY_RULES	:= $(DEPTH)/config/myrules.mk
 
 #
 # Default command macros; can be overridden in <arch>.mk.
 #
 CCC = $(CXX)
-PURIFY = purify $(PURIFYOPTIONS)
-QUANTIFY = quantify $(QUANTIFYOPTIONS)
 XPIDL_LINK = $(PYTHON) $(LIBXUL_DIST)/sdk/bin/xpt.py link
 
 # Java macros
 JAVA_GEN_DIR  = _javagen
 JAVA_DIST_DIR = $(DEPTH)/$(JAVA_GEN_DIR)
 JAVA_IFACES_PKG_NAME = org/mozilla/interfaces
 
 INCLUDES = \
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -490,19 +490,16 @@ endif
 #
 TAG_PROGRAM		= xargs etags -a
 
 #
 # Turn on C++ linking if we have any .cpp or .mm files
 # (moved this from config.mk so that config.mk can be included
 #  before the CPPSRCS are defined)
 #
-ifneq ($(CPPSRCS)$(CMMSRCS),)
-CPP_PROG_LINK		= 1
-endif
 ifneq ($(HOST_CPPSRCS)$(HOST_CMMSRCS),)
 HOST_CPP_PROG_LINK	= 1
 endif
 
 #
 # This will strip out symbols that the component should not be
 # exporting from the .dynsym section.
 #
@@ -949,41 +946,16 @@ ifeq (WINNT_,$(HOST_OS_ARCH)_$(GNU_CC))
 else
 ifneq (,$(HOST_CPPSRCS)$(USE_HOST_CXX))
 	$(HOST_CXX) $(HOST_OUTOPTION)$@ $(HOST_CXXFLAGS) $(INCLUDES) $< $(HOST_LIBS) $(HOST_EXTRA_LIBS)
 else
 	$(HOST_CC) $(HOST_OUTOPTION)$@ $(HOST_CFLAGS) $(INCLUDES) $< $(HOST_LIBS) $(HOST_EXTRA_LIBS)
 endif
 endif
 
-#
-# Purify target.  Solaris/sparc only to start.
-# Purify does not recognize "egcs" or "c++" so we go with
-# "gcc" and "g++" for now.
-#
-pure:	$(PROGRAM)
-ifeq ($(CPP_PROG_LINK),1)
-	$(PURIFY) $(CCC) -o $^.pure $(CXXFLAGS) $(PROGOBJS) $(LDFLAGS) $(LIBS_DIR) $(LIBS) $(OS_LIBS) $(EXTRA_LIBS)
-else
-	$(PURIFY) $(CC) -o $^.pure $(CFLAGS) $(PROGOBJS) $(LDFLAGS) $(LIBS_DIR) $(LIBS) $(OS_LIBS) $(EXTRA_LIBS)
-endif
-ifndef NO_DIST_INSTALL
-	$(INSTALL) $(IFLAGS2) $^.pure $(FINAL_TARGET)
-endif
-
-quantify: $(PROGRAM)
-ifeq ($(CPP_PROG_LINK),1)
-	$(QUANTIFY) $(CCC) -o $^.quantify $(CXXFLAGS) $(PROGOBJS) $(LDFLAGS) $(LIBS_DIR) $(LIBS) $(OS_LIBS) $(EXTRA_LIBS)
-else
-	$(QUANTIFY) $(CC) -o $^.quantify $(CFLAGS) $(PROGOBJS) $(LDFLAGS) $(LIBS_DIR) $(LIBS) $(OS_LIBS) $(EXTRA_LIBS)
-endif
-ifndef NO_DIST_INSTALL
-	$(INSTALL) $(IFLAGS2) $^.quantify $(FINAL_TARGET)
-endif
-
 ifdef DTRACE_PROBE_OBJ
 EXTRA_DEPS += $(DTRACE_PROBE_OBJ)
 OBJS += $(DTRACE_PROBE_OBJ)
 endif
 
 $(filter %.$(LIB_SUFFIX),$(LIBRARY)): $(OBJS) $(LOBJS) $(SHARED_LIBRARY_LIBS_DEPS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
 	$(RM) $(LIBRARY)
 	$(EXPAND_AR) $(AR_FLAGS) $(OBJS) $(LOBJS) $(SHARED_LIBRARY_LIBS)
--- a/configure.in
+++ b/configure.in
@@ -7567,24 +7567,16 @@ if test -n "$_ENABLE_CODESIGHS"; then
     if test -d $srcdir/tools/codesighs; then
         MOZ_MAPINFO=1
     else
         AC_MSG_ERROR([Codesighs directory $srcdir/tools/codesighs required.])
     fi
 fi
 
 dnl ========================================================
-dnl = Support for Quantify (Windows)
-dnl ========================================================
-MOZ_ARG_ENABLE_BOOL(quantify,
-[  --enable-quantify       Enable Quantify support (Windows only) ],
-    MOZ_QUANTIFY=1,
-    MOZ_QUANTIFY= )
-
-dnl ========================================================
 dnl = Enable Radio Interface for B2G (Gonk usually)
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(b2g-ril,
 [  --enable-b2g-ril      Set compile flags necessary for testing B2G Radio Interface Layer via network sockets ],
     MOZ_B2G_RIL=1,
     MOZ_B2G_RIL= )
 if test -n "$MOZ_B2G_RIL"; then
    AC_DEFINE(MOZ_B2G_RIL)
--- a/content/base/src/nsContentAreaDragDrop.cpp
+++ b/content/base/src/nsContentAreaDragDrop.cpp
@@ -399,17 +399,18 @@ DragDataProducer::Produce(nsDOMDataTrans
   *aSelection = nsnull;
 
   // Find the selection to see what we could be dragging and if what we're
   // dragging is in what is selected. If this is an editable textbox, use
   // the textbox's selection, otherwise use the window's selection.
   nsCOMPtr<nsISelection> selection;
   nsIContent* editingElement = mSelectionTargetNode->IsEditable() ?
                                mSelectionTargetNode->GetEditingHost() : nsnull;
-  nsCOMPtr<nsITextControlElement> textControl(do_QueryInterface(editingElement));
+  nsCOMPtr<nsITextControlElement> textControl =
+    nsITextControlElement::GetTextControlElementFromEditingHost(editingElement);
   if (textControl) {
     nsISelectionController* selcon = textControl->GetSelectionController();
     if (selcon) {
       selcon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
     }
 
     if (!selection)
       return NS_OK;
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -6526,41 +6526,16 @@ nsDocument::GetCurrentRadioButton(const 
   NS_ENSURE_TRUE(radioGroup, NS_OK);
 
   *aRadio = radioGroup->mSelectedRadioButton;
   NS_IF_ADDREF(*aRadio);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDocument::GetPositionInGroup(nsIDOMHTMLInputElement *aRadio,
-                               PRInt32 *aPositionIndex,
-                               PRInt32 *aItemsInGroup)
-{
-  *aPositionIndex = 0;
-  *aItemsInGroup = 1;
-  nsAutoString name;
-  aRadio->GetName(name);
-  if (name.IsEmpty()) {
-    return NS_OK;
-  }
-
-  nsRadioGroupStruct* radioGroup = GetRadioGroup(name);
-  NS_ENSURE_TRUE(radioGroup, NS_ERROR_OUT_OF_MEMORY);
-
-  nsCOMPtr<nsIFormControl> radioControl(do_QueryInterface(aRadio));
-  NS_ASSERTION(radioControl, "Radio button should implement nsIFormControl");
-  *aPositionIndex = radioGroup->mRadioButtons.IndexOf(radioControl);
-  NS_ASSERTION(*aPositionIndex >= 0, "Radio button not found in its own group");
-  *aItemsInGroup = radioGroup->mRadioButtons.Count();
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 nsDocument::GetNextRadioButton(const nsAString& aName,
                                const bool aPrevious,
                                nsIDOMHTMLInputElement*  aFocusedRadio,
                                nsIDOMHTMLInputElement** aRadioOut)
 {
   // XXX Can we combine the HTML radio button method impls of 
   //     nsDocument and nsHTMLFormControl?
   // XXX Why is HTML radio button stuff in nsDocument, as 
@@ -9693,17 +9668,18 @@ nsIDocument::DocSizeOfExcludingThis(nsWi
 {
   aWindowSizes->mDOM +=
     nsINode::SizeOfExcludingThis(aWindowSizes->mMallocSizeOf);
 
   if (mPresShell) {
     mPresShell->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf,
                                     &aWindowSizes->mLayoutArenas,
                                     &aWindowSizes->mLayoutStyleSets,
-                                    &aWindowSizes->mLayoutTextRuns);
+                                    &aWindowSizes->mLayoutTextRuns,
+                                    &aWindowSizes->mLayoutPresContext);
   }
 
   // Measurement of the following members may be added later if DMD finds it
   // is worthwhile:
   // - many!
 }
 
 void
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -732,19 +732,16 @@ public:
   // nsIRadioGroupContainer
   NS_IMETHOD WalkRadioGroup(const nsAString& aName,
                             nsIRadioVisitor* aVisitor,
                             bool aFlushContent);
   NS_IMETHOD SetCurrentRadioButton(const nsAString& aName,
                                    nsIDOMHTMLInputElement* aRadio);
   NS_IMETHOD GetCurrentRadioButton(const nsAString& aName,
                                    nsIDOMHTMLInputElement** aRadio);
-  NS_IMETHOD GetPositionInGroup(nsIDOMHTMLInputElement *aRadio,
-                                PRInt32 *aPositionIndex,
-                                PRInt32 *aItemsInGroup);
   NS_IMETHOD GetNextRadioButton(const nsAString& aName,
                                 const bool aPrevious,
                                 nsIDOMHTMLInputElement*  aFocusedRadio,
                                 nsIDOMHTMLInputElement** aRadioOut);
   NS_IMETHOD AddToRadioGroup(const nsAString& aName,
                              nsIFormControl* aRadio);
   NS_IMETHOD RemoveFromRadioGroup(const nsAString& aName,
                                   nsIFormControl* aRadio);
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -2137,17 +2137,20 @@ nsGenericElement::GetScrollTop(PRInt32* 
 
 NS_IMETHODIMP
 nsGenericElement::SetScrollTop(PRInt32 aScrollTop)
 {
   nsIScrollableFrame* sf = GetScrollFrame();
   if (sf) {
     nsPoint pt = sf->GetScrollPosition();
     pt.y = nsPresContext::CSSPixelsToAppUnits(aScrollTop);
-    sf->ScrollTo(pt, nsIScrollableFrame::INSTANT);
+    nscoord halfPixel = nsPresContext::CSSPixelsToAppUnits(0.5f);
+    // Don't allow pt.y + halfPixel since that would round up to the next CSS pixel.
+    nsRect range(pt.x, pt.y - halfPixel, 0, halfPixel*2 - 1);
+    sf->ScrollTo(pt, nsIScrollableFrame::INSTANT, &range);
   }
   return NS_OK;
 }
 
 PRInt32
 nsGenericElement::GetScrollLeft()
 {
   nsIScrollableFrame* sf = GetScrollFrame();
@@ -2167,17 +2170,20 @@ nsGenericElement::GetScrollLeft(PRInt32*
 
 NS_IMETHODIMP
 nsGenericElement::SetScrollLeft(PRInt32 aScrollLeft)
 {
   nsIScrollableFrame* sf = GetScrollFrame();
   if (sf) {
     nsPoint pt = sf->GetScrollPosition();
     pt.x = nsPresContext::CSSPixelsToAppUnits(aScrollLeft);
-    sf->ScrollTo(pt, nsIScrollableFrame::INSTANT);
+    nscoord halfPixel = nsPresContext::CSSPixelsToAppUnits(0.5f);
+    // Don't allow pt.x + halfPixel since that would round up to the next CSS pixel.
+    nsRect range(pt.x - halfPixel, pt.y, halfPixel*2 - 1, 0);
+    sf->ScrollTo(pt, nsIScrollableFrame::INSTANT, &range);
   }
   return NS_OK;
 }
 
 PRInt32
 nsGenericElement::GetScrollHeight()
 {
   if (IsSVG())
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -460,28 +460,18 @@ nsScriptLoader::ProcessScriptElement(nsI
     bool isJavaScript = false;
     for (PRInt32 i = 0; jsTypes[i]; i++) {
       if (mimeType.LowerCaseEqualsASCII(jsTypes[i])) {
         isJavaScript = true;
         break;
       }
     }
 
-    if (isJavaScript)
-      typeID = nsIProgrammingLanguage::JAVASCRIPT;
-    else {
-      // Use the object factory to locate a matching language.
-      nsCOMPtr<nsIScriptRuntime> runtime;
-      rv = NS_GetJSRuntime(getter_AddRefs(runtime));
-      if (NS_FAILED(rv) || runtime == nsnull) {
-        // Failed to get the explicitly specified language
-        NS_WARNING("Failed to find a scripting language");
-        typeID = nsIProgrammingLanguage::UNKNOWN;
-      } else
-        typeID = nsIProgrammingLanguage::JAVASCRIPT;
+    if (!isJavaScript) {
+      typeID = nsIProgrammingLanguage::UNKNOWN;
     }
 
     if (typeID != nsIProgrammingLanguage::UNKNOWN) {
       // Get the version string, and ensure the language supports it.
       nsAutoString versionName;
       rv = parser.GetParameter("version", versionName);
       if (NS_FAILED(rv)) {
         // no version attribute - version remains 0.
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -573,16 +573,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug650386_redirect_302.html \
 		test_bug650386_redirect_303.html \
 		test_bug650386_redirect_307.html \
 		file_bug650386_content.sjs \
 		file_bug650386_report.sjs \
 		test_bug719533.html \
 		test_bug737087.html \
 		test_bug433662.html \
+		test_bug749367.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_bug749367.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=749367
+-->
+
+<head>
+  <title>Test for Bug 749367</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=749367">Mozilla Bug 749367</a>
+<div id="content" style="display: none"></div>
+  <pre id="test">
+
+  <script type="text/template">
+  ok(false, "Shouldn't execute");
+  </script>
+
+  <script type="text/javascript">
+  ok(true, "Should execute");
+  </script>
+
+  </pre>
+</body>
+
+</html>
--- a/content/events/src/nsDOMUIEvent.cpp
+++ b/content/events/src/nsDOMUIEvent.cpp
@@ -55,17 +55,17 @@
 #include "mozilla/Assertions.h"
 
 using namespace mozilla;
 
 nsDOMUIEvent::nsDOMUIEvent(nsPresContext* aPresContext, nsGUIEvent* aEvent)
   : nsDOMEvent(aPresContext, aEvent ?
                static_cast<nsEvent *>(aEvent) :
                static_cast<nsEvent *>(new nsUIEvent(false, 0, 0)))
-  , mClientPoint(0, 0), mLayerPoint(0, 0), mPagePoint(0, 0)
+  , mClientPoint(0, 0), mLayerPoint(0, 0), mPagePoint(0, 0), mMovementPoint(0, 0)
   , mIsPointerLocked(nsEventStateManager::sIsPointerLocked)
   , mLastScreenPoint(nsEventStateManager::sLastScreenPoint)
   , mLastClientPoint(nsEventStateManager::sLastClientPoint)
 {
   if (aEvent) {
     mEventIsInternal = false;
   }
   else {
@@ -127,16 +127,20 @@ DOMCI_DATA(UIEvent, nsDOMUIEvent)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMUIEvent)
   NS_INTERFACE_MAP_ENTRY(nsIDOMUIEvent)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(UIEvent)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
 
 nsIntPoint
 nsDOMUIEvent::GetMovementPoint()
 {
+  if (mPrivateDataDuplicated) {
+    return mMovementPoint;
+  }
+
   if (!mEvent ||
        (mEvent->eventStructType != NS_MOUSE_EVENT &&
         mEvent->eventStructType != NS_POPUP_EVENT &&
         mEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
         mEvent->eventStructType != NS_MOZTOUCH_EVENT &&
         mEvent->eventStructType != NS_DRAG_EVENT &&
         mEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT)) {
     return nsIntPoint(0, 0);
@@ -408,16 +412,17 @@ nsDOMUIEvent::GetIsChar(bool* aIsChar)
 
 NS_METHOD
 nsDOMUIEvent::DuplicatePrivateData()
 {
   mClientPoint = nsDOMEvent::GetClientCoords(mPresContext,
                                              mEvent,
                                              mEvent->refPoint,
                                              mClientPoint);
+  mMovementPoint = GetMovementPoint();
   mLayerPoint = GetLayerPoint();
   mPagePoint = nsDOMEvent::GetPageCoords(mPresContext,
                                          mEvent,
                                          mEvent->refPoint,
                                          mClientPoint);
   // GetScreenPoint converts mEvent->refPoint to right coordinates.
   nsIntPoint screenPoint = nsDOMEvent::GetScreenCoords(mPresContext,
                                                        mEvent,
--- a/content/events/src/nsDOMUIEvent.h
+++ b/content/events/src/nsDOMUIEvent.h
@@ -142,17 +142,17 @@ protected:
   }
 
   nsCOMPtr<nsIDOMWindow> mView;
   PRInt32 mDetail;
   nsIntPoint mClientPoint;
   // Screenpoint is mEvent->refPoint.
   nsIntPoint mLayerPoint;
   nsIntPoint mPagePoint;
-  nsIntPoint mMovement;
+  nsIntPoint mMovementPoint;
   bool mIsPointerLocked;
   nsIntPoint mLastScreenPoint;
   nsIntPoint mLastClientPoint;
 
   typedef mozilla::widget::Modifiers Modifiers;
   static Modifiers ComputeModifierState(const nsAString& aModifiersList);
   bool GetModifierStateInternal(const nsAString& aKey);
 };
--- a/content/html/content/public/nsHTMLCanvasElement.h
+++ b/content/html/content/public/nsHTMLCanvasElement.h
@@ -90,21 +90,16 @@ public:
   // nsIDOMHTMLCanvasElement
   NS_DECL_NSIDOMHTMLCANVASELEMENT
 
   // CC
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHTMLCanvasElement,
                                            nsGenericHTMLElement)
 
   /**
-   * Ask the canvas Element to return the primary frame, if any
-   */
-  nsIFrame *GetPrimaryCanvasFrame();
-
-  /**
    * Get the size in pixels of this canvas element
    */
   nsIntSize GetSize();
 
   /**
    * Determine whether the canvas is write-only.
    */
   bool IsWriteOnly();
--- a/content/html/content/public/nsIRadioGroupContainer.h
+++ b/content/html/content/public/nsIRadioGroupContainer.h
@@ -115,29 +115,16 @@ public:
    * store radio groups on their own.
    *
    * @param aName radio group's name
    * @param aRadio radio button's pointer
    */
   NS_IMETHOD RemoveFromRadioGroup(const nsAString& aName,
                                   nsIFormControl* aRadio) = 0;
 
-  /**
-   * Get the radio group position and the number of radio buttons in the group.
-   * that the radio button is in. If the radio button not grouped with any other
-   * radio buttons this method will treat it as being in a group of one.
-   * @param aRadio radio button's pointer
-   * @param aPositionIndex out indicates 0-indexed position in the radio group,
-   *                           or just 0 if a group cannot be found
-   * @param aItemsInGroup the number of radio buttons in the group
-   */
-  NS_IMETHOD GetPositionInGroup(nsIDOMHTMLInputElement *aRadio,
-                                PRInt32 *aPositionIndex,
-                                PRInt32 *aItemsInGroup) = 0;
-
   virtual PRUint32 GetRequiredRadioCount(const nsAString& aName) const = 0;
   virtual void RadioRequiredChanged(const nsAString& aName,
                                     nsIFormControl* aRadio) = 0;
   virtual bool GetValueMissingState(const nsAString& aName) const = 0;
   virtual void SetValueMissingState(const nsAString& aName, bool aValue) = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIRadioGroupContainer,
--- a/content/html/content/public/nsITextControlElement.h
+++ b/content/html/content/public/nsITextControlElement.h
@@ -35,27 +35,28 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsITextControlElement_h___
 #define nsITextControlElement_h___
 
 #include "nsISupports.h"
+#include "nsCOMPtr.h"
 class nsIContent;
 class nsAString;
 class nsIEditor;
 class nsISelectionController;
 class nsFrameSelection;
 class nsTextControlFrame;
 
 // IID for the nsITextControl interface
 #define NS_ITEXTCONTROLELEMENT_IID    \
-{ 0x2e758eee, 0xd023, 0x4fd1,    \
-  { 0x97, 0x93, 0xae, 0xeb, 0xbb, 0xf3, 0xa8, 0x3f } }
+{ 0xe0a05008, 0xef02, 0x4fa2,    \
+  { 0x93, 0xf2, 0x78, 0xe1, 0xec, 0xf7, 0x5b, 0x79 } }
 
 /**
  * This interface is used for the text control frame to get the editor and
  * selection controller objects, and some helper properties.
  */
 class nsITextControlElement : public nsISupports {
 public:
 
@@ -122,24 +123,16 @@ public:
    *
    * @param aValue the buffer to retrieve the value in
    * @param aIgnoreWrap whether to ignore the text wrapping behavior specified
    * for the element.
    */
   NS_IMETHOD_(void) GetTextEditorValue(nsAString& aValue, bool aIgnoreWrap) const = 0;
 
   /**
-   * Set the current value of the text editor.
-   *
-   * @param aValue the new value for the text control.
-   * @param aUserInput whether this value is coming from user input.
-   */
-  NS_IMETHOD_(void) SetTextEditorValue(const nsAString& aValue, bool aUserInput) = 0;
-
-  /**
    * Get the editor object associated with the text editor.
    * The return value is null if the control does not support an editor
    * (for example, if it is a checkbox.)
    */
   NS_IMETHOD_(nsIEditor*) GetTextEditor() = 0;
 
   /**
    * Get the selection controller object associated with the text editor.
@@ -185,21 +178,16 @@ public:
   NS_IMETHOD_(nsIContent*) GetPlaceholderNode() = 0;
 
   /**
    * Initialize the keyboard event listeners.
    */
   NS_IMETHOD_(void) InitializeKeyboardEventListeners() = 0;
 
   /**
-   * Notify the text control that the placeholder text needs to be updated.
-   */
-  NS_IMETHOD_(void) UpdatePlaceholderText(bool aNotify) = 0;
-
-  /**
    * Show/hide the placeholder for the control.
    */
   NS_IMETHOD_(void) SetPlaceholderClass(bool aVisible, bool aNotify) = 0;
 
   /**
    * Callback called whenever the value is changed.
    */
   NS_IMETHOD_(void) OnValueChanged(bool aNotify) = 0;
@@ -221,15 +209,18 @@ public:
 
   /**
    * Does the editor have a selection cache?
    *
    * Note that this function has the side effect of making the editor for input
    * elements be initialized eagerly.
    */
   NS_IMETHOD_(bool) HasCachedSelection() = 0;
+
+  static already_AddRefed<nsITextControlElement>
+  GetTextControlElementFromEditingHost(nsIContent* aHost);
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsITextControlElement,
                               NS_ITEXTCONTROLELEMENT_IID)
 
 #endif // nsITextControlElement_h___
 
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -1871,47 +1871,16 @@ nsGenericHTMLElement::MapCommonAttribute
     if (display->GetUnit() == eCSSUnit_Null) {
       if (aAttributes->IndexOfAttr(nsGkAtoms::hidden, kNameSpaceID_None) >= 0) {
         display->SetIntValue(NS_STYLE_DISPLAY_NONE, eCSSUnit_Enumerated);
       }
     }
   }
 }
 
-void
-nsGenericHTMLFormElement::UpdateEditableFormControlState(bool aNotify)
-{
-  // nsCSSFrameConstructor::MaybeConstructLazily is based on the logic of this
-  // function, so should be kept in sync with that.
-
-  ContentEditableTristate value = GetContentEditableValue();
-  if (value != eInherit) {
-    DoSetEditableFlag(!!value, aNotify);
-    return;
-  }
-
-  nsIContent *parent = GetParent();
-
-  if (parent && parent->HasFlag(NODE_IS_EDITABLE)) {
-    DoSetEditableFlag(true, aNotify);
-    return;
-  }
-
-  if (!IsTextControl(false)) {
-    DoSetEditableFlag(false, aNotify);
-    return;
-  }
-
-  // If not contentEditable we still need to check the readonly attribute.
-  bool roState;
-  GetBoolAttr(nsGkAtoms::readonly, &roState);
-
-  DoSetEditableFlag(!roState, aNotify);
-}
-
 
 /* static */ const nsGenericHTMLElement::MappedAttributeEntry
 nsGenericHTMLElement::sCommonAttributeMap[] = {
   { &nsGkAtoms::contenteditable },
   { &nsGkAtoms::lang },
   { &nsGkAtoms::hidden },
   { nsnull }
 };
@@ -2338,29 +2307,16 @@ nsGenericHTMLElement::SetUnsignedIntAttr
 {
   nsAutoString value;
   value.AppendInt(aValue);
 
   return SetAttr(kNameSpaceID_None, aAttr, value, true);
 }
 
 nsresult
-nsGenericHTMLElement::GetDoubleAttr(nsIAtom* aAttr, double aDefault, double* aResult)
-{
-  const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(aAttr);
-  if (attrVal && attrVal->Type() == nsAttrValue::eDoubleValue) {
-    *aResult = attrVal->GetDoubleValue();
-  }
-  else {
-    *aResult = aDefault;
-  }
-  return NS_OK;
-}
-
-nsresult
 nsGenericHTMLElement::SetDoubleAttr(nsIAtom* aAttr, double aValue)
 {
   nsAutoString value;
   value.AppendFloat(aValue);
 
   return SetAttr(kNameSpaceID_None, aAttr, value, true);
 }
 
@@ -2969,16 +2925,28 @@ nsGenericHTMLFormElement::IntrinsicState
   
   if (mForm && mForm->IsDefaultSubmitElement(this)) {
       NS_ASSERTION(IsSubmitControl(),
                    "Default submit element that isn't a submit control.");
       // We are the default submit element (:default)
       state |= NS_EVENT_STATE_DEFAULT;
   }
 
+  // Make the text controls read-write
+  if (!state.HasState(NS_EVENT_STATE_MOZ_READWRITE) &&
+      IsTextControl(false)) {
+    bool roState;
+    GetBoolAttr(nsGkAtoms::readonly, &roState);
+
+    if (!roState) {
+      state |= NS_EVENT_STATE_MOZ_READWRITE;
+      state &= ~NS_EVENT_STATE_MOZ_READONLY;
+    }
+  }
+
   return state;
 }
 
 nsGenericHTMLFormElement::FocusTristate
 nsGenericHTMLFormElement::FocusState()
 {
   // We can't be focused if we aren't in a document
   nsIDocument* doc = GetCurrentDoc();
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -687,29 +687,16 @@ protected:
    * attributes in null namespace.
    *
    * @param aAttr    name of attribute.
    * @param aValue   Integer value of attribute.
    */
   NS_HIDDEN_(nsresult) SetUnsignedIntAttr(nsIAtom* aAttr, PRUint32 aValue);
 
   /**
-   * Helper method for NS_IMPL_DOUBLE_ATTR macro.
-   * Gets the double-value of an attribute, returns specified default value
-   * if the attribute isn't set or isn't set to a double. Only works for
-   * attributes in null namespace.
-   *
-   * @param aAttr    name of attribute.
-   * @param aDefault default-value to return if attribute isn't set.
-   * @param aResult  result value [out]
-   */
-  NS_HIDDEN_(nsresult) GetDoubleAttr(nsIAtom* aAttr, double aDefault, double* aValue);
-
-  /**
-   * Helper method for NS_IMPL_DOUBLE_ATTR macro.
    * Sets value of attribute to specified double. Only works for attributes
    * in null namespace.
    *
    * @param aAttr    name of attribute.
    * @param aValue   Double value of attribute.
    */
   NS_HIDDEN_(nsresult) SetDoubleAttr(nsIAtom* aAttr, double aValue);
 
@@ -905,18 +892,16 @@ public:
 protected:
   virtual nsresult BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                  const nsAttrValueOrString* aValue,
                                  bool aNotify);
 
   virtual nsresult AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                 const nsAttrValue* aValue, bool aNotify);
 
-  void UpdateEditableFormControlState(bool aNotify);
-
   /**
    * This method will update the form owner, using @form or looking to a parent.
    *
    * @param aBindToTree Whether the element is being attached to the tree.
    * @param aFormIdElement The element associated with the id in @form. If
    * aBindToTree is false, aFormIdElement *must* contain the element associated
    * with the id in @form. Otherwise, it *must* be null.
    *
@@ -1090,36 +1075,16 @@ PR_STATIC_ASSERT(ELEMENT_TYPE_SPECIFIC_B
   {                                                                       \
     if (aValue == 0) {                                                    \
       return NS_ERROR_DOM_INDEX_SIZE_ERR;                                 \
     }                                                                     \
     return SetUnsignedIntAttr(nsGkAtoms::_atom, aValue);                  \
   }
 
 /**
- * A macro to implement the getter and setter for a given double-precision
- * floating point valued content property. The method uses GetDoubleAttr and
- * SetDoubleAttr methods.
- */
-#define NS_IMPL_DOUBLE_ATTR(_class, _method, _atom)                    \
-  NS_IMPL_DOUBLE_ATTR_DEFAULT_VALUE(_class, _method, _atom, 0.0)
-
-#define NS_IMPL_DOUBLE_ATTR_DEFAULT_VALUE(_class, _method, _atom, _default) \
-  NS_IMETHODIMP                                                             \
-  _class::Get##_method(double* aValue)                                      \
-  {                                                                         \
-    return GetDoubleAttr(nsGkAtoms::_atom, _default, aValue);               \
-  }                                                                         \
-  NS_IMETHODIMP                                                             \
-  _class::Set##_method(double aValue)                                       \
-  {                                                                         \
-    return SetDoubleAttr(nsGkAtoms::_atom, aValue);                         \
-  }
-
-/**
  * A macro to implement the getter and setter for a given content
  * property that needs to return a URI in string form.  The method
  * uses the generic GetAttr and SetAttr methods.  This macro is much
  * like the NS_IMPL_STRING_ATTR macro, except we make sure the URI is
  * absolute.
  */
 #define NS_IMPL_URI_ATTR(_class, _method, _atom)                    \
   NS_IMETHODIMP                                                     \
--- a/content/html/content/src/nsHTMLButtonElement.cpp
+++ b/content/html/content/src/nsHTMLButtonElement.cpp
@@ -162,21 +162,16 @@ public:
   virtual void DoneCreatingElement();
   virtual nsXPCClassInfo* GetClassInfo();
   virtual nsIDOMNode* AsDOMNode() { return this; }
 protected:
   PRUint8 mType;
   bool mDisabledChanged;
   bool mInInternalActivate;
   bool mInhibitStateRestoration;
-
-private:
-  // The analogue of defaultValue in the DOM for input and textarea
-  nsresult SetDefaultValue(const nsAString& aDefaultValue);
-  nsresult GetDefaultValue(nsAString& aDefaultValue);
 };
 
 
 // Construction, destruction
 
 
 NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Button)
 
@@ -525,29 +520,16 @@ void
 nsHTMLButtonElement::UnbindFromTree(bool aDeep, bool aNullParent)
 {
   nsGenericHTMLFormElement::UnbindFromTree(aDeep, aNullParent);
 
   // Update our state; we may no longer be the default submit element
   UpdateState(false);
 }
 
-nsresult
-nsHTMLButtonElement::GetDefaultValue(nsAString& aDefaultValue)
-{
-  GetAttr(kNameSpaceID_None, nsGkAtoms::value, aDefaultValue);
-  return NS_OK;
-}
-
-nsresult
-nsHTMLButtonElement::SetDefaultValue(const nsAString& aDefaultValue)
-{
-  return SetAttr(kNameSpaceID_None, nsGkAtoms::value, aDefaultValue, true);
-}
-
 NS_IMETHODIMP
 nsHTMLButtonElement::Reset()
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLButtonElement::SubmitNamesValues(nsFormSubmission* aFormSubmission)
--- a/content/html/content/src/nsHTMLCanvasElement.cpp
+++ b/content/html/content/src/nsHTMLCanvasElement.cpp
@@ -654,22 +654,16 @@ nsHTMLCanvasElement::UpdateContext(nsIPr
     mCurrentContext = nsnull;
     mCurrentContextId.Truncate();
     return rv;
   }
 
   return rv;
 }
 
-nsIFrame *
-nsHTMLCanvasElement::GetPrimaryCanvasFrame()
-{
-  return GetPrimaryFrame(Flush_Frames);
-}
-
 nsIntSize
 nsHTMLCanvasElement::GetSize()
 {
   return GetWidthHeight();
 }
 
 bool
 nsHTMLCanvasElement::IsWriteOnly()
--- a/content/html/content/src/nsHTMLFormElement.cpp
+++ b/content/html/content/src/nsHTMLFormElement.cpp
@@ -1905,51 +1905,16 @@ nsHTMLFormElement::GetCurrentRadioButton
                                          nsIDOMHTMLInputElement** aRadio)
 {
   mSelectedRadioButtons.Get(aName, aRadio);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsHTMLFormElement::GetPositionInGroup(nsIDOMHTMLInputElement *aRadio,
-                                      PRInt32 *aPositionIndex,
-                                      PRInt32 *aItemsInGroup)
-{
-  *aPositionIndex = 0;
-  *aItemsInGroup = 1;
-
-  nsAutoString name;
-  aRadio->GetName(name);
-  if (name.IsEmpty()) {
-    return NS_OK;
-  }
-
-  nsCOMPtr<nsISupports> itemWithName;
-  itemWithName = ResolveName(name);
-  NS_ENSURE_TRUE(itemWithName, NS_ERROR_FAILURE);
-  nsCOMPtr<nsINodeList> radioGroup(do_QueryInterface(itemWithName));
-
-  NS_ASSERTION(radioGroup, "No such radio group in this container");
-  if (!radioGroup) {
-    return NS_OK;
-  }
-
-  nsCOMPtr<nsIContent> currentRadioNode(do_QueryInterface(aRadio));
-  NS_ASSERTION(currentRadioNode, "No nsIContent for current radio button");
-  *aPositionIndex = radioGroup->IndexOf(currentRadioNode);
-  NS_ASSERTION(*aPositionIndex >= 0, "Radio button not found in its own group");
-  PRUint32 itemsInGroup;
-  radioGroup->GetLength(&itemsInGroup);
-  *aItemsInGroup = itemsInGroup;
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 nsHTMLFormElement::GetNextRadioButton(const nsAString& aName,
                                       const bool aPrevious,
                                       nsIDOMHTMLInputElement*  aFocusedRadio,
                                       nsIDOMHTMLInputElement** aRadioOut)
 {
   // Return the radio button relative to the focused radio button.
   // If no radio is focused, get the radio relative to the selected one.
   *aRadioOut = nsnull;
--- a/content/html/content/src/nsHTMLFormElement.h
+++ b/content/html/content/src/nsHTMLFormElement.h
@@ -93,19 +93,16 @@ public:
   NS_IMETHOD_(PRInt32) IndexOfControl(nsIFormControl* aControl);
   NS_IMETHOD_(nsIFormControl*) GetDefaultSubmitElement() const;
 
   // nsIRadioGroupContainer
   NS_IMETHOD SetCurrentRadioButton(const nsAString& aName,
                                    nsIDOMHTMLInputElement* aRadio);
   NS_IMETHOD GetCurrentRadioButton(const nsAString& aName,
                                    nsIDOMHTMLInputElement** aRadio);
-  NS_IMETHOD GetPositionInGroup(nsIDOMHTMLInputElement *aRadio,
-                                PRInt32 *aPositionIndex,
-                                PRInt32 *aItemsInGroup);
   NS_IMETHOD GetNextRadioButton(const nsAString& aName,
                                 const bool aPrevious,
                                 nsIDOMHTMLInputElement*  aFocusedRadio,
                                 nsIDOMHTMLInputElement** aRadioOut);
   NS_IMETHOD WalkRadioGroup(const nsAString& aName, nsIRadioVisitor* aVisitor,
                             bool aFlushContent);
   NS_IMETHOD AddToRadioGroup(const nsAString& aName,
                              nsIFormControl* aRadio);
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -855,21 +855,16 @@ nsHTMLInputElement::AfterSetAttr(PRInt32
     } else if (MaxLengthApplies() && aName == nsGkAtoms::maxlength) {
       UpdateTooLongValidityState();
     } else if (aName == nsGkAtoms::pattern) {
       UpdatePatternMismatchValidityState();
     } else if (aName == nsGkAtoms::multiple) {
       UpdateTypeMismatchValidityState();
     }
 
-    UpdateEditableState(aNotify);
-    nsTextEditorState *state = GetEditorState();
-    if (state) {
-      state->UpdateEditableState(aNotify);
-    }
     UpdateState(aNotify);
   }
 
   return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName,
                                                 aValue, aNotify);
 }
 
 // nsIDOMHTMLInputElement
@@ -1239,25 +1234,16 @@ nsHTMLInputElement::GetPlaceholderNode()
   nsTextEditorState *state = GetEditorState();
   if (state) {
     return state->GetPlaceholderNode();
   }
   return nsnull;
 }
 
 NS_IMETHODIMP_(void)
-nsHTMLInputElement::UpdatePlaceholderText(bool aNotify)
-{
-  nsTextEditorState *state = GetEditorState();
-  if (state) {
-    state->UpdatePlaceholderText(aNotify);
-  }
-}
-
-NS_IMETHODIMP_(void)
 nsHTMLInputElement::SetPlaceholderClass(bool aVisible, bool aNotify)
 {
   nsTextEditorState *state = GetEditorState();
   if (state) {
     state->SetPlaceholderClass(aVisible, aNotify);
   }
 }
 
@@ -4100,26 +4086,16 @@ nsHTMLInputElement::GetTextEditorValue(n
 {
   nsTextEditorState *state = GetEditorState();
   if (state) {
     state->GetValue(aValue, aIgnoreWrap);
   }
 }
 
 NS_IMETHODIMP_(void)
-nsHTMLInputElement::SetTextEditorValue(const nsAString& aValue,
-                                       bool aUserInput)
-{
-  nsTextEditorState *state = GetEditorState();
-  if (state) {
-    state->SetValue(aValue, aUserInput);
-  }
-}
-
-NS_IMETHODIMP_(void)
 nsHTMLInputElement::InitializeKeyboardEventListeners()
 {
   nsTextEditorState *state = GetEditorState();
   if (state) {
     state->InitializeKeyboardEventListeners();
   }
 }
 
--- a/content/html/content/src/nsHTMLInputElement.h
+++ b/content/html/content/src/nsHTMLInputElement.h
@@ -177,27 +177,25 @@ public:
   NS_IMETHOD_(bool) IsPlainTextControl() const;
   NS_IMETHOD_(bool) IsPasswordTextControl() const;
   NS_IMETHOD_(PRInt32) GetCols();
   NS_IMETHOD_(PRInt32) GetWrapCols();
   NS_IMETHOD_(PRInt32) GetRows();
   NS_IMETHOD_(void) GetDefaultValueFromContent(nsAString& aValue);
   NS_IMETHOD_(bool) ValueChanged() const;
   NS_IMETHOD_(void) GetTextEditorValue(nsAString& aValue, bool aIgnoreWrap) const;
-  NS_IMETHOD_(void) SetTextEditorValue(const nsAString& aValue, bool aUserInput);
   NS_IMETHOD_(nsIEditor*) GetTextEditor();
   NS_IMETHOD_(nsISelectionController*) GetSelectionController();
   NS_IMETHOD_(nsFrameSelection*) GetConstFrameSelection();
   NS_IMETHOD BindToFrame(nsTextControlFrame* aFrame);
   NS_IMETHOD_(void) UnbindFromFrame(nsTextControlFrame* aFrame);
   NS_IMETHOD CreateEditor();
   NS_IMETHOD_(nsIContent*) GetRootEditorNode();
   NS_IMETHOD_(nsIContent*) CreatePlaceholderNode();
   NS_IMETHOD_(nsIContent*) GetPlaceholderNode();
-  NS_IMETHOD_(void) UpdatePlaceholderText(bool aNotify);
   NS_IMETHOD_(void) SetPlaceholderClass(bool aVisible, bool aNotify);
   NS_IMETHOD_(void) InitializeKeyboardEventListeners();
   NS_IMETHOD_(void) OnValueChanged(bool aNotify);
   NS_IMETHOD_(bool) HasCachedSelection();
 
   void GetDisplayFileName(nsAString& aFileName) const;
   const nsCOMArray<nsIDOMFile>& GetFiles() const;
   void SetFiles(const nsCOMArray<nsIDOMFile>& aFiles, bool aSetValueChanged);
@@ -218,21 +216,16 @@ public:
    * @return the selected button (or null).
    */
   already_AddRefed<nsIDOMHTMLInputElement> GetSelectedRadioButton();
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
   NS_IMETHOD FireAsyncClickHandler();
 
-  virtual void UpdateEditableState(bool aNotify)
-  {
-    return UpdateEditableFormControlState(aNotify);
-  }
-
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHTMLInputElement,
                                            nsGenericHTMLFormElement)
 
   static UploadLastDir* gUploadLastDir;
   // create and destroy the static UploadLastDir object for remembering
   // which directory was last used on a site-by-site basis
   static void InitUploadLastDir();
   static void DestroyUploadLastDir();
--- a/content/html/content/src/nsHTMLSelectElement.cpp
+++ b/content/html/content/src/nsHTMLSelectElement.cpp
@@ -1810,23 +1810,16 @@ nsHTMLSelectElement::SubmitNamesValues(n
     }
 
     rv = aFormSubmission->AddNameValuePair(name, value);
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsHTMLSelectElement::GetHasOptGroups(bool* aHasGroups)
-{
-  *aHasGroups = (mOptGroupCount > 0);
-  return NS_OK;
-}
-
 void
 nsHTMLSelectElement::DispatchContentReset()
 {
   nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
   if (formControlFrame) {
     // Only dispatch content reset notification if this is a list control
     // frame or combo box control frame.
     if (IsCombobox()) {
--- a/content/html/content/src/nsHTMLSelectElement.h
+++ b/content/html/content/src/nsHTMLSelectElement.h
@@ -378,19 +378,16 @@ public:
    * @param aForward TRUE to look forward, FALSE to look backward
    * @return the option index
    */
   NS_IMETHOD GetOptionIndex(nsIDOMHTMLOptionElement* aOption,
                             PRInt32 aStartIndex,
                             bool aForward,
                             PRInt32* aIndex NS_OUTPARAM);
 
-  /** Whether or not there are optgroups in this select */
-  NS_IMETHOD GetHasOptGroups(bool* aHasGroups);
-
   /**
    * Called when an attribute is about to be changed
    */
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                                nsIContent* aBindingParent,
                                bool aCompileEventHandlers);
   virtual void UnbindFromTree(bool aDeep, bool aNullParent);
   virtual nsresult BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
--- a/content/html/content/src/nsHTMLTextAreaElement.cpp
+++ b/content/html/content/src/nsHTMLTextAreaElement.cpp
@@ -158,27 +158,25 @@ public:
   NS_IMETHOD_(bool) IsPlainTextControl() const;
   NS_IMETHOD_(bool) IsPasswordTextControl() const;
   NS_IMETHOD_(PRInt32) GetCols();
   NS_IMETHOD_(PRInt32) GetWrapCols();
   NS_IMETHOD_(PRInt32) GetRows();
   NS_IMETHOD_(void) GetDefaultValueFromContent(nsAString& aValue);
   NS_IMETHOD_(bool) ValueChanged() const;
   NS_IMETHOD_(void) GetTextEditorValue(nsAString& aValue, bool aIgnoreWrap) const;
-  NS_IMETHOD_(void) SetTextEditorValue(const nsAString& aValue, bool aUserInput);
   NS_IMETHOD_(nsIEditor*) GetTextEditor();
   NS_IMETHOD_(nsISelectionController*) GetSelectionController();
   NS_IMETHOD_(nsFrameSelection*) GetConstFrameSelection();
   NS_IMETHOD BindToFrame(nsTextControlFrame* aFrame);
   NS_IMETHOD_(void) UnbindFromFrame(nsTextControlFrame* aFrame);
   NS_IMETHOD CreateEditor();
   NS_IMETHOD_(nsIContent*) GetRootEditorNode();
   NS_IMETHOD_(nsIContent*) CreatePlaceholderNode();
   NS_IMETHOD_(nsIContent*) GetPlaceholderNode();
-  NS_IMETHOD_(void) UpdatePlaceholderText(bool aNotify);
   NS_IMETHOD_(void) SetPlaceholderClass(bool aVisible, bool aNotify);
   NS_IMETHOD_(void) InitializeKeyboardEventListeners();
   NS_IMETHOD_(void) OnValueChanged(bool aNotify);
   NS_IMETHOD_(bool) HasCachedSelection();
 
   // nsIContent
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                                nsIContent* aBindingParent,
@@ -214,21 +212,16 @@ public:
                                  bool aNotify);
 
   // nsIMutationObserver
   NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
 
-  virtual void UpdateEditableState(bool aNotify)
-  {
-    return UpdateEditableFormControlState(aNotify);
-  }
-
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHTMLTextAreaElement,
                                            nsGenericHTMLFormElement)
 
   virtual nsXPCClassInfo* GetClassInfo();
 
   virtual nsIDOMNode* AsDOMNode() { return this; }
 
   // nsIConstraintValidation
@@ -561,22 +554,16 @@ nsHTMLTextAreaElement::CreatePlaceholder
 
 NS_IMETHODIMP_(nsIContent*)
 nsHTMLTextAreaElement::GetPlaceholderNode()
 {
   return mState.GetPlaceholderNode();
 }
 
 NS_IMETHODIMP_(void)
-nsHTMLTextAreaElement::UpdatePlaceholderText(bool aNotify)
-{
-  mState.UpdatePlaceholderText(aNotify);
-}
-
-NS_IMETHODIMP_(void)
 nsHTMLTextAreaElement::SetPlaceholderClass(bool aVisible, bool aNotify)
 {
   mState.SetPlaceholderClass(aVisible, aNotify);
 }
 
 nsresult
 nsHTMLTextAreaElement::SetValueInternal(const nsAString& aValue,
                                         bool aUserInput)
@@ -1308,20 +1295,16 @@ nsHTMLTextAreaElement::AfterSetAttr(PRIn
       // This *has* to be called *after* validity has changed.
       if (aName == nsGkAtoms::readonly || aName == nsGkAtoms::disabled) {
         UpdateBarredFromConstraintValidation();
       }
     } else if (aName == nsGkAtoms::maxlength) {
       UpdateTooLongValidityState();
     }
 
-    if (aName == nsGkAtoms::readonly) {
-      UpdateEditableState(aNotify);
-      mState.UpdateEditableState(aNotify);
-    }
     UpdateState(aNotify);
   }
 
   return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName, aValue,
                                                 aNotify);
 }
 
 nsresult
@@ -1546,23 +1529,16 @@ nsHTMLTextAreaElement::ValueChanged() co
 NS_IMETHODIMP_(void)
 nsHTMLTextAreaElement::GetTextEditorValue(nsAString& aValue,
                                           bool aIgnoreWrap) const
 {
   mState.GetValue(aValue, aIgnoreWrap);
 }
 
 NS_IMETHODIMP_(void)
-nsHTMLTextAreaElement::SetTextEditorValue(const nsAString& aValue,
-                                          bool aUserInput)
-{
-  mState.SetValue(aValue, aUserInput);
-}
-
-NS_IMETHODIMP_(void)
 nsHTMLTextAreaElement::InitializeKeyboardEventListeners()
 {
   mState.InitializeKeyboardEventListeners();
 }
 
 NS_IMETHODIMP_(void)
 nsHTMLTextAreaElement::OnValueChanged(bool aNotify)
 {
--- a/content/html/content/src/nsTextEditorState.cpp
+++ b/content/html/content/src/nsTextEditorState.cpp
@@ -140,16 +140,30 @@ nsITextControlElement::GetWrapPropertyEn
     }
 
     return true;
   }
 
   return false;
 }
 
+/*static*/
+already_AddRefed<nsITextControlElement>
+nsITextControlElement::GetTextControlElementFromEditingHost(nsIContent* aHost)
+{
+  if (!aHost) {
+    return nsnull;
+  }
+
+  nsCOMPtr<nsITextControlElement> parent =
+    do_QueryInterface(aHost->GetParent());
+
+  return parent.forget();
+}
+
 static bool
 SuppressEventHandlers(nsPresContext* aPresContext)
 {
   bool suppressHandlers = false;
 
   if (aPresContext)
   {
     // Right now we only suppress event handlers and controller manipulation
@@ -1561,16 +1575,19 @@ nsTextEditorState::CreateRootNode()
   }
 
   return rv;
 }
 
 nsresult
 nsTextEditorState::InitializeRootNode()
 {
+  // Make our root node editable
+  mRootNode->SetFlags(NODE_IS_EDITABLE);
+
   // Set the necessary classes on the text control. We use class values
   // instead of a 'style' attribute so that the style comes from a user-agent
   // style sheet and is still applied even if author styles are disabled.
   nsAutoString classValue;
   classValue.AppendLiteral("anonymous-div");
   PRInt32 wrapCols = GetWrapCols();
   if (wrapCols >= 0) {
     classValue.AppendLiteral(" wrap");
--- a/content/html/content/test/test_bug388794.html
+++ b/content/html/content/test/test_bug388794.html
@@ -63,17 +63,24 @@ var hrefs = {
 function submitForm(idNum) {
   $("test"+idNum).setAttribute("onload", "frameLoaded(this)");
   $("test" + idNum + "image").focus();
   sendKey("return");
 }
 
 function submitFormMouse(idNum) {
   $("test"+idNum).setAttribute("onload", "frameLoaded(this)");
-  synthesizeMouse($("test" + idNum + "image"), 5, 5, {});
+  // Use 4.999 instead of 5 to guard against the possibility that the
+  // image's 'top' is exactly N + 0.5 pixels from the root. In that case
+  // we'd round up the widget mouse coordinate to N + 6, which relative
+  // to the image would be 5.5, which would get rounded up to 6 when
+  // submitting the form. Instead we round the widget mouse coordinate to
+  // N + 5, which relative to the image would be 4.5 which gets rounded up
+  // to 5.
+  synthesizeMouse($("test" + idNum + "image"), 4.999, 4.999, {});
 }
 
 addLoadEvent(function() {
   // Need the timeout so painting has a chance to be unsuppressed.
   setTimeout(function() {
     submitForm(++pendingLoads);
     submitForm(++pendingLoads);
     submitForm(++pendingLoads);
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -1889,19 +1889,25 @@ SourceMediaStream::Finish()
   }
   GraphImpl()->EnsureNextIteration();
 }
 
 static const PRUint32 kThreadLimit = 4;
 static const PRUint32 kIdleThreadLimit = 4;
 static const PRUint32 kIdleThreadTimeoutMs = 2000;
 
+/**
+ * We make the initial mCurrentTime nonzero so that zero times can have
+ * special meaning if necessary.
+ */
+static const PRInt32 INITIAL_CURRENT_TIME = 1;
+
 MediaStreamGraphImpl::MediaStreamGraphImpl()
-  : mLastActionTime(1)
-  , mCurrentTime(1)
+  : mLastActionTime(INITIAL_CURRENT_TIME)
+  , mCurrentTime(INITIAL_CURRENT_TIME)
   , mBlockingDecisionsMadeUntilTime(1)
   , mProcessingGraphUpdateIndex(0)
   , mMonitor("MediaStreamGraphImpl")
   , mLifecycleState(LIFECYCLE_THREAD_NOT_STARTED)
   , mWaitState(WAITSTATE_RUNNING)
   , mNeedAnotherIteration(false)
   , mForceShutDown(false)
   , mPostedRunInStableStateEvent(false)
--- a/content/media/nsBuiltinDecoderStateMachine.cpp
+++ b/content/media/nsBuiltinDecoderStateMachine.cpp
@@ -767,28 +767,28 @@ bool nsBuiltinDecoderStateMachine::HaveE
   }
   if (!mAudioCaptured) {
     return true;
   }
 
   nsTArray<OutputMediaStream>& streams = mDecoder->OutputStreams();
   for (PRUint32 i = 0; i < streams.Length(); ++i) {
     OutputMediaStream* stream = &streams[i];
-    if (!stream->mHaveSentFinishAudio &&
+    if (stream->mStreamInitialized && !stream->mHaveSentFinishAudio &&
         !stream->mStream->HaveEnoughBuffered(TRACK_AUDIO)) {
       return false;
     }
   }
 
   nsIThread* thread = GetStateMachineThread();
   nsCOMPtr<nsIRunnable> callback = NS_NewRunnableMethod(this,
       &nsBuiltinDecoderStateMachine::ScheduleStateMachineWithLockAndWakeDecoder);
   for (PRUint32 i = 0; i < streams.Length(); ++i) {
     OutputMediaStream* stream = &streams[i];
-    if (!stream->mHaveSentFinishAudio) {
+    if (stream->mStreamInitialized && !stream->mHaveSentFinishAudio) {
       stream->mStream->DispatchWhenNotEnoughBuffered(TRACK_AUDIO, thread, callback);
     }
   }
   return true;
 }
 
 bool nsBuiltinDecoderStateMachine::HaveEnoughDecodedVideo()
 {
@@ -800,28 +800,28 @@ bool nsBuiltinDecoderStateMachine::HaveE
 
   nsTArray<OutputMediaStream>& streams = mDecoder->OutputStreams();
   if (streams.IsEmpty()) {
     return true;
   }
 
   for (PRUint32 i = 0; i < streams.Length(); ++i) {
     OutputMediaStream* stream = &streams[i];
-    if (!stream->mHaveSentFinishVideo &&
+    if (stream->mStreamInitialized && !stream->mHaveSentFinishVideo &&
         !stream->mStream->HaveEnoughBuffered(TRACK_VIDEO)) {
       return false;
     }
   }
 
   nsIThread* thread = GetStateMachineThread();
   nsCOMPtr<nsIRunnable> callback = NS_NewRunnableMethod(this,
       &nsBuiltinDecoderStateMachine::ScheduleStateMachineWithLockAndWakeDecoder);
   for (PRUint32 i = 0; i < streams.Length(); ++i) {
     OutputMediaStream* stream = &streams[i];
-    if (!stream->mHaveSentFinishVideo) {
+    if (stream->mStreamInitialized && !stream->mHaveSentFinishVideo) {
       stream->mStream->DispatchWhenNotEnoughBuffered(TRACK_VIDEO, thread, callback);
     }
   }
   return true;
 }
 
 void nsBuiltinDecoderStateMachine::DecodeLoop()
 {
new file mode 100644
--- /dev/null
+++ b/content/media/test/crashtests/752784-1.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function boom()
+{
+  document.getElementById("a").mozCaptureStream();
+}
+</script>
+</head>
+
+<body onload="boom();">
+<audio id="a" src="sound.ogg">
+</body>
+</html>
--- a/content/media/test/crashtests/crashtests.list
+++ b/content/media/test/crashtests/crashtests.list
@@ -4,8 +4,9 @@ load 466945-1.html
 load 468763-1.html
 load 474744-1.html
 HTTP load 481136-1.html # needs to be HTTP to recognize the ogg as an audio file?
 load 493915-1.html
 skip-if(Android) load 495794-1.html
 load 492286-1.xhtml
 load 576612-1.html
 skip-if(Android) load 691096-1.html # Android sound API can't handle playing large number of sounds at once.
+load 752784-1.html
--- a/content/media/test/test_streams_element_capture_reset.html
+++ b/content/media/test/test_streams_element_capture_reset.html
@@ -14,23 +14,19 @@
 SimpleTest.waitForExplicitFinish();
 
 var v = document.getElementById('v');
 var vout = document.getElementById('vout');
 var stream = v.mozCaptureStream();
 vout.src = stream;
 
 function dumpEvent(event) {
-  var detail;
-  if (event.type == "timeupdate") {
-    detail = " currentTime=" + event.target.currentTime;
-  } else {
-    detail = "";
-  }
-  dump("GOT EVENT " + event.type + detail + "\n");
+  dump("GOT EVENT " + event.type + " currentTime=" + event.target.currentTime +
+       " paused=" + event.target.paused + " ended=" + event.target.ended +
+       " readyState=" + event.target.readyState + "\n");
 }
 var events = ["timeupdate", "seeking", "seeked", "ended", "playing", "pause"];
 for (var i = 0; i < events.length; ++i) {
   v.addEventListener(events[i], dumpEvent, false);
 }
 
 function startTest(test) {
   var seekTime = test.duration/2;
--- a/content/xbl/src/nsXBLService.cpp
+++ b/content/xbl/src/nsXBLService.cpp
@@ -831,19 +831,30 @@ nsXBLService::GetBinding(nsIContent* aBo
                                         false, getter_AddRefs(docInfo));
   NS_ENSURE_SUCCESS(rv, rv);
   
   if (!docInfo)
     return NS_ERROR_FAILURE;
 
   nsXBLPrototypeBinding* protoBinding = docInfo->GetPrototypeBinding(ref);
 
-  NS_WARN_IF_FALSE(protoBinding, "Unable to locate an XBL binding");
-  if (!protoBinding)
+  if (!protoBinding) {
+#ifdef DEBUG
+    nsCAutoString uriSpec;
+    aURI->GetSpec(uriSpec);
+    nsCAutoString doc;
+    boundDocument->GetDocumentURI()->GetSpec(doc);
+    nsCAutoString message("Unable to locate an XBL binding for URI ");
+    message += uriSpec;
+    message += " in document ";
+    message += doc;
+    NS_WARNING(message.get());
+#endif
     return NS_ERROR_FAILURE;
+  }
 
   NS_ENSURE_TRUE(aDontExtendURIs.AppendElement(protoBinding->BindingURI()),
                  NS_ERROR_OUT_OF_MEMORY);
   nsCOMPtr<nsIURI> altBindingURI = protoBinding->AlternateBindingURI();
   if (altBindingURI) {
     NS_ENSURE_TRUE(aDontExtendURIs.AppendElement(altBindingURI),
                    NS_ERROR_OUT_OF_MEMORY);
   }
--- a/content/xul/content/test/Makefile.in
+++ b/content/xul/content/test/Makefile.in
@@ -41,16 +41,17 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = content/xul/content/test
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES = 	\
 		test_bug486990.xul \
+		test_bug749367.xul \
 		$(NULL)
 
 _CHROME_FILES = \
 		test_bug330705-2.xul \
 		test_bug233643.xul \
  		test_bug398289.html \
  		398289-resource.xul \
  		$(NULL)
new file mode 100644
--- /dev/null
+++ b/content/xul/content/test/test_bug749367.xul
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=749367
+-->
+<window title="Mozilla Bug 749367"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="setTimeout(runTests, 0);">
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"/>
+
+  <!-- test results are displayed in the html:body -->
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=486990"
+     target="_blank">Mozilla Bug 486990</a>
+  </body>
+
+  <!-- test code goes here -->
+  <script type="text/template">
+  <![CDATA[
+  SimpleTest.waitForExplicitFinish();
+  function runTests() {
+  ok(false, "Shouldn't execute");
+  SimpleTest.finish();
+  }
+  ]]>
+  </script>
+
+  <script type="text/javascript">
+  <![CDATA[
+  SimpleTest.waitForExplicitFinish();
+  function runTests() {
+  ok(true, "Should execute");
+  SimpleTest.finish();
+  }
+  ]]>
+  </script>
+
+</window>
--- a/content/xul/document/src/nsXULContentSink.cpp
+++ b/content/xul/document/src/nsXULContentSink.cpp
@@ -923,25 +923,17 @@ XULContentSinkImpl::OpenScript(const PRU
                   break;
               }
           }
 
           if (isJavaScript) {
               langID = nsIProgrammingLanguage::JAVASCRIPT;
               version = JSVERSION_LATEST;
           } else {
-              // Use the script object factory to locate the language.
-              nsCOMPtr<nsIScriptRuntime> runtime;
-              rv = NS_GetJSRuntime(getter_AddRefs(runtime));
-              if (NS_FAILED(rv) || runtime == nsnull) {
-                  // Failed to get the explicitly specified language
-                  NS_WARNING("Failed to find a scripting language");
-                  langID = nsIProgrammingLanguage::UNKNOWN;
-              } else
-                  langID = nsIProgrammingLanguage::JAVASCRIPT;
+              langID = nsIProgrammingLanguage::UNKNOWN;
           }
 
           if (langID != nsIProgrammingLanguage::UNKNOWN) {
             // Get the version string, and ensure the language supports it.
             nsAutoString versionName;
             rv = parser.GetParameter("version", versionName);
             if (NS_FAILED(rv)) {
               if (rv != NS_ERROR_INVALID_ARG)
--- a/docshell/base/Makefile.in
+++ b/docshell/base/Makefile.in
@@ -48,17 +48,16 @@ LIBRARY_NAME   = basedocshell_s
 GRE_MODULE     = 1
 LIBXUL_LIBRARY = 1
 
 ifdef MOZ_TOOLKIT_SEARCH
 DEFINES += -DMOZ_TOOLKIT_SEARCH
 endif
 
 SDK_XPIDLSRCS = \
-  nsIGlobalHistory.idl \
   nsIClipboardCommands.idl \
   $(NULL)
 
 XPIDLSRCS = \
   nsCDefaultURIFixup.idl \
   nsIDocShell.idl \
   nsIDocShellLoadInfo.idl \
   nsIDocShellTreeItem.idl \
--- a/docshell/base/nsDownloadHistory.cpp
+++ b/docshell/base/nsDownloadHistory.cpp
@@ -35,17 +35,16 @@
  * 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 "nsDownloadHistory.h"
 #include "nsCOMPtr.h"
 #include "nsServiceManagerUtils.h"
-#include "nsIGlobalHistory.h"
 #include "nsIGlobalHistory2.h"
 #include "nsIObserverService.h"
 #include "nsIURI.h"
 #include "nsIComponentRegistrar.h"
 #include "nsDocShellCID.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 //// nsDownloadHistory
deleted file mode 100644
--- a/docshell/base/nsIGlobalHistory.idl
+++ /dev/null
@@ -1,75 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * 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 ***** */
-
-/**
- *
- * The interface to global history.
- *
- * @status DEPRECATED. This interface is still accepted, but new
- *         implementations should use nsIGlobalHistory2.
- * @version 1.0
- */
-
-#include "nsISupports.idl"
-
-[scriptable, uuid(9491C383-E3C4-11d2-BDBE-0050040A9B44)]
-interface nsIGlobalHistory : nsISupports
-{
-    /**
-     * addPage
-     * Add a page to the history
-     *
-     * @param aURL the url to the page
-     */
-
-    void addPage(in string aURL);
-
-    /**
-     * isVisited
-     * Checks to see if the given page is in history
-     *
-     * @return true if a page has been passed into addPage().
-     * @param aURL the url to the page
-     */
-    boolean isVisited(in string aURL);
-};
-
-%{ C++
-#define NS_GLOBALHISTORY_CONTRACTID \
-    "@mozilla.org/browser/global-history;1"
-%}
-
--- a/dom/base/BrowserElementChild.js
+++ b/dom/base/BrowserElementChild.js
@@ -40,32 +40,56 @@ BrowserElementChild.prototype = {
             .addProgressListener(this._progressListener,
                                  Ci.nsIWebProgress.NOTIFY_LOCATION |
                                  Ci.nsIWebProgress.NOTIFY_STATE_WINDOW);
 
     addEventListener('DOMTitleChanged',
                      this._titleChangedHandler.bind(this),
                      /* useCapture = */ true,
                      /* wantsUntrusted = */ false);
+
+    addEventListener('DOMLinkAdded',
+                     this._iconChangedHandler.bind(this),
+                     /* useCapture = */ true,
+                     /* wantsUntrusted = */ false);
   },
 
   _titleChangedHandler: function(e) {
     debug("Got titlechanged: (" + e.target.title + ")");
     var win = e.target.defaultView;
 
     // Ignore titlechanges which don't come from the top-level
     // <iframe mozbrowser> window.
     if (win == content) {
       sendAsyncMsg('titlechange', e.target.title);
     }
     else {
       debug("Not top level!");
     }
   },
 
+  _iconChangedHandler: function(e) {
+    debug("Got iconchanged: (" + e.target.href + ")");
+    var hasIcon = e.target.rel.split(' ').some(function(x) {
+      return x.toLowerCase() === 'icon';
+    });
+
+    if (hasIcon) {
+      var win = e.target.ownerDocument.defaultView;
+      // Ignore iconchanges which don't come from the top-level
+      // <iframe mozbrowser> window.
+      if (win == content) {
+        sendAsyncMsg('iconchange', e.target.href);
+      }
+      else {
+        debug("Not top level!");
+      }
+    }
+  },
+
   // The docShell keeps a weak reference to the progress listener, so we need
   // to keep a strong ref to it ourselves.
   _progressListener: {
     QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
                                            Ci.nsISupportsWeakReference,
                                            Ci.nsISupports]),
     _seenLoadStart: false,
 
--- a/dom/base/BrowserElementParent.js
+++ b/dom/base/BrowserElementParent.js
@@ -93,16 +93,17 @@ BrowserElementParent.prototype = {
       mm.addMessageListener('browser-element-api:' + msg, handler.bind(this, frameElement));
     }
 
     addMessageListener("hello", this._recvHello);
     addMessageListener("locationchange", this._fireEventFromMsg);
     addMessageListener("loadstart", this._fireEventFromMsg);
     addMessageListener("loadend", this._fireEventFromMsg);
     addMessageListener("titlechange", this._fireEventFromMsg);
+    addMessageListener("iconchange", this._fireEventFromMsg);
 
     mm.loadFrameScript("chrome://global/content/BrowserElementChild.js",
                        /* allowDelayedLoad = */ true);
   },
 
   _recvHello: function(frameElement, data) {
     debug("recvHello " + frameElement);
   },
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -303,19 +303,18 @@ MaybeReflowForInflationScreenWidthChange
         nsCOMPtr<nsIMarkupDocumentViewer> mudv = do_QueryInterface(cv);
         if (mudv) {
           nsTArray<nsCOMPtr<nsIMarkupDocumentViewer> > array;
           mudv->AppendSubtree(array);
           for (PRUint32 i = 0, iEnd = array.Length(); i < iEnd; ++i) {
             nsCOMPtr<nsIPresShell> shell;
             nsCOMPtr<nsIContentViewer> cv = do_QueryInterface(array[i]);
             cv->GetPresShell(getter_AddRefs(shell));
-            nsFrameManager *fm = shell->FrameManager();
-            if (fm) {
-              nsIFrame *rootFrame = fm->GetRootFrame();
+            if (shell) {
+              nsIFrame *rootFrame = shell->GetRootFrame();
               if (rootFrame) {
                 shell->FrameNeedsReflow(rootFrame, nsIPresShell::eResize,
                                         NS_FRAME_IS_DIRTY);
               }
             }
           }
         }
       }
@@ -519,16 +518,26 @@ nsDOMWindowUtils::SendMouseEventToWindow
                                          PRInt32 aClickCount,
                                          PRInt32 aModifiers,
                                          bool aIgnoreRootScrollFrame)
 {
   return SendMouseEventCommon(aType, aX, aY, aButton, aClickCount, aModifiers,
                               aIgnoreRootScrollFrame, true);
 }
 
+static nsIntPoint
+ToWidgetPoint(float aX, float aY, const nsPoint& aOffset,
+              nsPresContext* aPresContext)
+{
+  double appPerDev = aPresContext->AppUnitsPerDevPixel();
+  nscoord appPerCSS = nsPresContext::AppUnitsPerCSSPixel();
+  return nsIntPoint(NSToIntRound((aX*appPerCSS + aOffset.x)/appPerDev),
+                    NSToIntRound((aY*appPerCSS + aOffset.y)/appPerDev));
+}
+
 NS_IMETHODIMP
 nsDOMWindowUtils::SendMouseEventCommon(const nsAString& aType,
                                        float aX,
                                        float aY,
                                        PRInt32 aButton,
                                        PRInt32 aClickCount,
                                        PRInt32 aModifiers,
                                        bool aIgnoreRootScrollFrame,
@@ -572,23 +581,17 @@ nsDOMWindowUtils::SendMouseEventCommon(c
   event.clickCount = aClickCount;
   event.time = PR_IntervalNow();
   event.flags |= NS_EVENT_FLAG_SYNTHETIC_TEST_EVENT;
 
   nsPresContext* presContext = GetPresContext();
   if (!presContext)
     return NS_ERROR_FAILURE;
 
-  PRInt32 appPerDev = presContext->AppUnitsPerDevPixel();
-  event.refPoint.x =
-    NSAppUnitsToIntPixels(nsPresContext::CSSPixelsToAppUnits(aX) + offset.x,
-                          appPerDev);
-  event.refPoint.y =
-    NSAppUnitsToIntPixels(nsPresContext::CSSPixelsToAppUnits(aY) + offset.y,
-                          appPerDev);
+  event.refPoint = ToWidgetPoint(aX, aY, offset, presContext);
   event.ignoreRootScrollFrame = aIgnoreRootScrollFrame;
 
   nsEventStatus status;
   if (aToWindow) {
     nsCOMPtr<nsIPresShell> presShell = presContext->PresShell();
     if (!presShell)
       return NS_ERROR_FAILURE;
     nsIViewManager* viewManager = presShell->GetViewManager();
@@ -639,23 +642,17 @@ nsDOMWindowUtils::SendMouseScrollEvent(c
   event.scrollFlags = aScrollFlags;
 
   event.time = PR_IntervalNow();
 
   nsPresContext* presContext = GetPresContext();
   if (!presContext)
     return NS_ERROR_FAILURE;
 
-  PRInt32 appPerDev = presContext->AppUnitsPerDevPixel();
-  event.refPoint.x =
-    NSAppUnitsToIntPixels(nsPresContext::CSSPixelsToAppUnits(aX) + offset.x,
-                          appPerDev);
-  event.refPoint.y =
-    NSAppUnitsToIntPixels(nsPresContext::CSSPixelsToAppUnits(aY) + offset.y,
-                          appPerDev);
+  event.refPoint = ToWidgetPoint(aX, aY, offset, presContext);
 
   nsEventStatus status;
   return widget->DispatchEvent(&event, status);
 }
 
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SendTouchEvent(const nsAString& aType,
@@ -698,25 +695,18 @@ nsDOMWindowUtils::SendTouchEvent(const n
   event.widget = widget;
   event.time = PR_Now();
 
   nsPresContext* presContext = GetPresContext();
   if (!presContext) {
     return NS_ERROR_FAILURE;
   }
   event.touches.SetCapacity(aCount);
-  PRInt32 appPerDev = presContext->AppUnitsPerDevPixel();
   for (PRUint32 i = 0; i < aCount; ++i) {
-    nsIntPoint pt(0, 0);
-    pt.x =
-      NSAppUnitsToIntPixels(nsPresContext::CSSPixelsToAppUnits(aXs[i]) + offset.x,
-                            appPerDev);
-    pt.y =
-      NSAppUnitsToIntPixels(nsPresContext::CSSPixelsToAppUnits(aYs[i]) + offset.y,
-                            appPerDev);
+    nsIntPoint pt = ToWidgetPoint(aXs[i], aYs[i], offset, presContext);
     nsCOMPtr<nsIDOMTouch> t(new nsDOMTouch(aIdentifiers[i],
                                            pt,
                                            nsIntPoint(aRxs[i], aRys[i]),
                                            aRotationAngles[i],
                                            aForces[i]));
     event.touches.AppendElement(t);
   }
 
@@ -1007,17 +997,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(js::gcreason::DOM_UTILS);
+  nsJSContext::GarbageCollectNow(js::gcreason::DOM_UTILS, nsGCNormal, true);
   nsJSContext::CycleCollectNow(aListener, aExtraForgetSkippableCalls);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::CycleCollect(nsICycleCollectorListener *aListener,
                                PRInt32 aExtraForgetSkippableCalls)
@@ -1076,23 +1066,17 @@ nsDOMWindowUtils::SendSimpleGestureEvent
   nsSimpleGestureEvent event(true, msg, widget, aDirection, aDelta);
   event.modifiers = GetWidgetModifiers(aModifiers);
   event.time = PR_IntervalNow();
 
   nsPresContext* presContext = GetPresContext();
   if (!presContext)
     return NS_ERROR_FAILURE;
 
-  PRInt32 appPerDev = presContext->AppUnitsPerDevPixel();
-  event.refPoint.x =
-    NSAppUnitsToIntPixels(nsPresContext::CSSPixelsToAppUnits(aX) + offset.x,
-                          appPerDev);
-  event.refPoint.y =
-    NSAppUnitsToIntPixels(nsPresContext::CSSPixelsToAppUnits(aY) + offset.y,
-                          appPerDev);
+  event.refPoint = ToWidgetPoint(aX, aY, offset, presContext);
 
   nsEventStatus status;
   return widget->DispatchEvent(&event, status);
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::ElementFromPoint(float aX, float aY,
                                    bool aIgnoreRootScrollFrame,
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -3748,16 +3748,19 @@ nsGlobalWindow::MozRequestAnimationFrame
     return NS_OK;
   }
 
   if (!aCallback) {
     mDoc->WarnOnceAbout(nsIDocument::eMozBeforePaint);
     return NS_ERROR_XPC_BAD_CONVERT_JS;
   }
 
+  if (mJSObject)
+    js::NotifyAnimationActivity(mJSObject);
+
   return mDoc->ScheduleFrameRequestCallback(aCallback, aHandle);
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::MozCancelRequestAnimationFrame(PRInt32 aHandle)
 {
   return MozCancelAnimationFrame(aHandle);
 }
@@ -5321,19 +5324,22 @@ nsGlobalWindow::ScrollTo(PRInt32 aXScrol
 
     if (aXScroll > maxpx) {
       aXScroll = maxpx;
     }
 
     if (aYScroll > maxpx) {
       aYScroll = maxpx;
     }
-    sf->ScrollTo(nsPoint(nsPresContext::CSSPixelsToAppUnits(aXScroll),
-                         nsPresContext::CSSPixelsToAppUnits(aYScroll)),
-                 nsIScrollableFrame::INSTANT);
+    nsPoint pt(nsPresContext::CSSPixelsToAppUnits(aXScroll),
+               nsPresContext::CSSPixelsToAppUnits(aYScroll));
+    nscoord halfPixel = nsPresContext::CSSPixelsToAppUnits(0.5f);
+    // Don't allow pt.x/y + halfPixel since that would round up to the next CSS pixel.
+    nsRect range(pt.x - halfPixel, pt.y - halfPixel, halfPixel*2 - 1, halfPixel*2 - 1);
+    sf->ScrollTo(pt, nsIScrollableFrame::INSTANT, &range);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::ScrollBy(PRInt32 aXScrollDif, PRInt32 aYScrollDif)
 {
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -129,16 +129,20 @@ static PRLogModuleInfo* gJSDiagnostics;
 #endif
 
 #define NS_SHRINK_GC_BUFFERS_DELAY  4000 // ms
 
 // The amount of time we wait from the first request to GC to actually
 // doing the first GC.
 #define NS_FIRST_GC_DELAY           10000 // ms
 
+#define NS_FULL_GC_DELAY            60000 // ms
+
+#define NS_MAX_COMPARTMENT_GC_COUNT 20
+
 // Maximum amount of time that should elapse between incremental GC slices
 #define NS_INTERSLICE_GC_DELAY      100 // ms
 
 // The amount of time we wait between a request to CC (after GC ran)
 // and doing the actual CC.
 #define NS_CC_DELAY                 6000 // ms
 
 #define NS_CC_SKIPPABLE_DELAY       400 // ms
@@ -154,16 +158,17 @@ static PRLogModuleInfo* gJSDiagnostics;
 
 #define JAVASCRIPT nsIProgrammingLanguage::JAVASCRIPT
 
 // if you add statics here, add them to the list in nsJSRuntime::Startup
 
 static nsITimer *sGCTimer;
 static nsITimer *sShrinkGCBuffersTimer;
 static nsITimer *sCCTimer;
+static nsITimer *sFullGCTimer;
 
 static PRTime sLastCCEndTime;
 
 static bool sCCLockedOut;
 static PRTime sCCLockedOutTime;
 
 static js::GCSliceCallback sPrevGCSliceCallback;
 
@@ -173,26 +178,28 @@ static js::GCSliceCallback sPrevGCSliceC
 // all cases. This counter also gets reset if we end up GC'ing while
 // we're waiting for a slow page to load. IOW, this count may be 0
 // even when there are pending loads.
 static PRUint32 sPendingLoadCount;
 static bool sLoadingInProgress;
 
 static PRUint32 sCCollectedWaitingForGC;
 static bool sPostGCEventsToConsole;
+static bool sDisableExplicitCompartmentGC;
 static PRUint32 sCCTimerFireCount = 0;
 static PRUint32 sMinForgetSkippableTime = PR_UINT32_MAX;
 static PRUint32 sMaxForgetSkippableTime = 0;
 static PRUint32 sTotalForgetSkippableTime = 0;
 static PRUint32 sRemovedPurples = 0;
 static PRUint32 sForgetSkippableBeforeCC = 0;
 static PRUint32 sPreviousSuspectedCount = 0;
-
+static PRUint32 sCompartmentGCCount = NS_MAX_COMPARTMENT_GC_COUNT;
 static PRUint32 sCleanupsSinceLastGC = PR_UINT32_MAX;
 static bool sNeedsFullCC = false;
+static nsJSContext *sContextList = nsnull;
 
 nsScriptNameSpaceManager *gNameSpaceManager;
 
 static nsIJSRuntimeService *sRuntimeService;
 JSRuntime *nsJSRuntime::sRuntime;
 
 static const char kJSRuntimeServiceContractID[] =
   "@mozilla.org/js/xpc/RuntimeService;1";
@@ -224,17 +231,18 @@ public:
 
 NS_IMPL_ISUPPORTS1(nsMemoryPressureObserver, nsIObserver)
 
 NS_IMETHODIMP
 nsMemoryPressureObserver::Observe(nsISupports* aSubject, const char* aTopic,
                                   const PRUnichar* aData)
 {
   if (sGCOnMemoryPressure) {
-    nsJSContext::GarbageCollectNow(js::gcreason::MEM_PRESSURE, nsGCShrinking);
+    nsJSContext::GarbageCollectNow(js::gcreason::MEM_PRESSURE, nsGCShrinking,
+                                   true);
     nsJSContext::CycleCollectNow();
   }
   return NS_OK;
 }
 
 class nsRootedJSValueArray {
 public:
   explicit nsRootedJSValueArray(JSContext *cx) : avr(cx, vals.Length(), vals.Elements()) {}
@@ -924,26 +932,30 @@ static const char js_zeal_frequency_str[
 static const char js_methodjit_content_str[]  = JS_OPTIONS_DOT_STR "methodjit.content";
 static const char js_methodjit_chrome_str[]   = JS_OPTIONS_DOT_STR "methodjit.chrome";
 static const char js_methodjit_always_str[]   = JS_OPTIONS_DOT_STR "methodjit_always";
 static const char js_typeinfer_str[]          = JS_OPTIONS_DOT_STR "typeinference";
 static const char js_pccounts_content_str[]   = JS_OPTIONS_DOT_STR "pccounts.content";
 static const char js_pccounts_chrome_str[]    = JS_OPTIONS_DOT_STR "pccounts.chrome";
 static const char js_jit_hardening_str[]      = JS_OPTIONS_DOT_STR "jit_hardening";
 static const char js_memlog_option_str[] = JS_OPTIONS_DOT_STR "mem.log";
+static const char js_disable_explicit_compartment_gc[] =
+  JS_OPTIONS_DOT_STR "disable_explicit_compartment_gc";
 static const char js_ion_content_str[]        = JS_OPTIONS_DOT_STR "ion.content";
 
 int
 nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
 {
   nsJSContext *context = reinterpret_cast<nsJSContext *>(data);
   PRUint32 oldDefaultJSOptions = context->mDefaultJSOptions;
   PRUint32 newDefaultJSOptions = oldDefaultJSOptions;
 
   sPostGCEventsToConsole = Preferences::GetBool(js_memlog_option_str);
+  sDisableExplicitCompartmentGC =
+    Preferences::GetBool(js_disable_explicit_compartment_gc);
 
   bool strict = Preferences::GetBool(js_strict_option_str);
   if (strict)
     newDefaultJSOptions |= JSOPTION_STRICT;
   else
     newDefaultJSOptions &= ~JSOPTION_STRICT;
 
   // The vanilla GetGlobalObject returns null if a global isn't set up on
@@ -1041,19 +1053,26 @@ nsJSContext::JSOptionChangedCallback(con
   if (zeal >= 0)
     ::JS_SetGCZeal(context->mContext, (PRUint8)zeal, frequency);
 #endif
 
   return 0;
 }
 
 nsJSContext::nsJSContext(JSRuntime *aRuntime)
-  : mGCOnDestruction(true),
+  : mActive(false),
+    mGCOnDestruction(true),
     mExecuteDepth(0)
 {
+  mNext = sContextList;
+  mPrev = &sContextList;
+  if (sContextList) {
+    sContextList->mPrev = &mNext;
+  }
+  sContextList = this;
 
   ++sContextCount;
 
   mDefaultJSOptions = JSOPTION_PRIVATE_IS_NSISUPPORTS;
 
   mContext = ::JS_NewContext(aRuntime, gStackSize);
   if (mContext) {
     ::JS_SetContextPrivate(mContext, static_cast<nsIScriptContext *>(this));
@@ -1082,16 +1101,21 @@ nsJSContext::nsJSContext(JSRuntime *aRun
 }
 
 nsJSContext::~nsJSContext()
 {
 #ifdef DEBUG
   nsCycleCollector_DEBUG_wasFreed(static_cast<nsIScriptContext*>(this));
 #endif
 
+  *mPrev = mNext;
+  if (mNext) {
+    mNext->mPrev = mPrev;
+  }
+
   // We may still have pending termination functions if the context is destroyed
   // before they could be executed. In this case, free the references to their
   // parameters, but don't execute the functions (see bug 622326).
   delete mTerminations;
 
   mGlobalObjectRef = nsnull;
 
   DestroyJSContext();
@@ -2852,16 +2876,17 @@ nsJSContext::ScriptEvaluated(bool aTermi
     delete start;
   }
 
   JS_MaybeGC(mContext);
 
   if (aTerminated) {
     mOperationCallbackTime = 0;
     mModalStateTime = 0;
+    mActive = true;
   }
 }
 
 void
 nsJSContext::SetTerminationFunction(nsScriptTerminationFunc aFunc,
                                     nsIDOMWindow* aRef)
 {
   NS_PRECONDITION(GetExecutingScript(), "should be executing script");
@@ -2919,38 +2944,75 @@ nsJSContext::SetGCOnDestruction(bool aGC
 NS_IMETHODIMP
 nsJSContext::ScriptExecuted()
 {
   ScriptEvaluated(!::JS_IsRunning(mContext));
 
   return NS_OK;
 }
 
+void
+FullGCTimerFired(nsITimer* aTimer, void* aClosure)
+{
+  NS_RELEASE(sFullGCTimer);
+
+  uintptr_t reason = reinterpret_cast<uintptr_t>(aClosure);
+  nsJSContext::GarbageCollectNow(static_cast<js::gcreason::Reason>(reason),
+                                 nsGCNormal, true);
+}
+
 //static
 void
-nsJSContext::GarbageCollectNow(js::gcreason::Reason reason, PRUint32 gckind)
+nsJSContext::GarbageCollectNow(js::gcreason::Reason aReason, PRUint32 aGckind,
+                               bool aGlobal)
 {
   NS_TIME_FUNCTION_MIN(1.0);
   SAMPLE_LABEL("GC", "GarbageCollectNow");
 
   KillGCTimer();
   KillShrinkGCBuffersTimer();
 
   // Reset sPendingLoadCount in case the timer that fired was a
   // timer we scheduled due to a normal GC timer firing while
   // 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(reason, gckind);
+  if (!nsContentUtils::XPConnect()) {
+    return;
   }
+  
+  // Use compartment GC when we're not asked to do a shrinking GC nor
+  // global GC and compartment GC has been called less than
+  // NS_MAX_COMPARTMENT_GC_COUNT times after the previous global GC.
+  if (!sDisableExplicitCompartmentGC &&
+      aGckind != nsGCShrinking && !aGlobal &&
+      sCompartmentGCCount < NS_MAX_COMPARTMENT_GC_COUNT) {  
+    js::PrepareForFullGC(nsJSRuntime::sRuntime);
+    for (nsJSContext* cx = sContextList; cx; cx = cx->mNext) {
+      if (!cx->mActive && cx->mContext) {
+        if (JSObject* global = cx->GetNativeGlobal()) {
+          js::SkipCompartmentForGC(js::GetObjectCompartment(global));
+        }
+      }
+      cx->mActive = false;
+    }
+    if (js::IsGCScheduled(nsJSRuntime::sRuntime)) {
+      js::IncrementalGC(nsJSRuntime::sRuntime, aReason);
+    }
+    return;
+  }
+
+  for (nsJSContext* cx = sContextList; cx; cx = cx->mNext) {
+    cx->mActive = false;
+  }
+  nsContentUtils::XPConnect()->GarbageCollect(aReason, aGckind);
 }
 
 //static
 void
 nsJSContext::ShrinkGCBuffersNow()
 {
   NS_TIME_FUNCTION_MIN(1.0);
   SAMPLE_LABEL("GC", "ShrinkGCBuffersNow");
@@ -2966,17 +3028,17 @@ nsJSContext::CycleCollectNow(nsICycleCol
                              PRInt32 aExtraForgetSkippableCalls)
 {
   if (!NS_IsMainThread()) {
     return;
   }
 
   if (sCCLockedOut) {
     // We're in the middle of an incremental GC; finish it first
-    nsJSContext::GarbageCollectNow(js::gcreason::CC_FORCED, nsGCNormal);
+    nsJSContext::GarbageCollectNow(js::gcreason::CC_FORCED, nsGCNormal, true);
   }
 
   SAMPLE_LABEL("GC", "CycleCollectNow");
   NS_TIME_FUNCTION_MIN(1.0);
 
   KillCCTimer();
 
   PRTime start = PR_Now();
@@ -3103,17 +3165,18 @@ nsJSContext::CycleCollectNow(nsICycleCol
 
 // static
 void
 GCTimerFired(nsITimer *aTimer, void *aClosure)
 {
   NS_RELEASE(sGCTimer);
 
   uintptr_t reason = reinterpret_cast<uintptr_t>(aClosure);
-  nsJSContext::GarbageCollectNow(static_cast<js::gcreason::Reason>(reason), nsGCIncremental);
+  nsJSContext::GarbageCollectNow(static_cast<js::gcreason::Reason>(reason),
+                                 nsGCNormal, false);
 }
 
 void
 ShrinkGCBuffersTimerFired(nsITimer *aTimer, void *aClosure)
 {
   NS_RELEASE(sShrinkGCBuffersTimer);
 
   nsJSContext::ShrinkGCBuffersNow();
@@ -3159,17 +3222,17 @@ CCTimerFired(nsITimer *aTimer, void *aCl
       sCCLockedOutTime = now;
       return;
     }
     if (now - sCCLockedOutTime < NS_MAX_CC_LOCKEDOUT_TIME) {
       return;
     }
 
     // Finish the current incremental GC
-    nsJSContext::GarbageCollectNow(js::gcreason::CC_FORCED, nsGCNormal);
+    nsJSContext::GarbageCollectNow(js::gcreason::CC_FORCED, nsGCNormal, true);
   }
 
   ++sCCTimerFireCount;
 
   // During early timer fires, we only run forgetSkippable. During the first
   // late timer fire, we decide if we are going to have a second and final
   // late timer fire, where we may run the CC.
   const PRUint32 numEarlyTimerFires = NS_CC_DELAY / NS_CC_SKIPPABLE_DELAY - 2;
@@ -3312,16 +3375,25 @@ nsJSContext::KillGCTimer()
 {
   if (sGCTimer) {
     sGCTimer->Cancel();
 
     NS_RELEASE(sGCTimer);
   }
 }
 
+void
+nsJSContext::KillFullGCTimer()
+{
+  if (sFullGCTimer) {
+    sFullGCTimer->Cancel();
+    NS_RELEASE(sFullGCTimer);
+  }
+}
+
 //static
 void
 nsJSContext::KillShrinkGCBuffersTimer()
 {
   if (sShrinkGCBuffersTimer) {
     sShrinkGCBuffersTimer->Cancel();
 
     NS_RELEASE(sShrinkGCBuffersTimer);
@@ -3339,16 +3411,17 @@ nsJSContext::KillCCTimer()
 
     NS_RELEASE(sCCTimer);
   }
 }
 
 void
 nsJSContext::GC(js::gcreason::Reason aReason)
 {
+  mActive = true;
   PokeGC(aReason);
 }
 
 class NotifyGCEndRunnable : public nsRunnable
 {
   nsString mMessage;
 
 public:
@@ -3420,30 +3493,33 @@ DOMGCSliceCallback(JSRuntime *aRt, js::G
   }
 
   if (aProgress == js::GC_CYCLE_END) {
     // May need to kill the inter-slice GC timer
     nsJSContext::KillGCTimer();
 
     sCCollectedWaitingForGC = 0;
     sCleanupsSinceLastGC = 0;
+    sNeedsFullCC = true;
+    nsJSContext::MaybePokeCC();
 
     if (aDesc.isCompartment) {
-      // 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 it is
-      // probably a time of heavy activity and we want to delay
-      // the full GC, but we do want it to happen eventually.
-      nsJSContext::PokeGC(js::gcreason::POST_COMPARTMENT);
-    }
-
-    sNeedsFullCC = true;
-    nsJSContext::MaybePokeCC();
-
-    if (!aDesc.isCompartment) {
+      ++sCompartmentGCCount;
+      if (!sFullGCTimer) {
+        CallCreateInstance("@mozilla.org/timer;1", &sFullGCTimer);
+        js::gcreason::Reason reason = js::gcreason::FULL_GC_TIMER;
+        sFullGCTimer->InitWithFuncCallback(FullGCTimerFired,
+                                           reinterpret_cast<void *>(reason),
+                                           NS_FULL_GC_DELAY,
+                                           nsITimer::TYPE_ONE_SHOT);
+      }
+    } else {
+      sCompartmentGCCount = 0;
+      nsJSContext::KillFullGCTimer();
+
       // Avoid shrinking during heavy activity, which is suggested by
       // compartment GC.
       nsJSContext::PokeShrinkGCBuffers();
     }
   }
 
   if (sPrevGCSliceCallback)
     (*sPrevGCSliceCallback)(aRt, aProgress, aDesc);
@@ -3533,24 +3609,25 @@ nsJSRuntime::ParseVersion(const nsString
     return NS_OK;
 }
 
 //static
 void
 nsJSRuntime::Startup()
 {
   // initialize all our statics, so that we can restart XPCOM
-  sGCTimer = sCCTimer = nsnull;
+  sGCTimer = sFullGCTimer = sCCTimer = nsnull;
   sCCLockedOut = false;
   sCCLockedOutTime = 0;
   sLastCCEndTime = 0;
   sPendingLoadCount = 0;
   sLoadingInProgress = false;
   sCCollectedWaitingForGC = 0;
   sPostGCEventsToConsole = false;
+  sDisableExplicitCompartmentGC = false;
   sNeedsFullCC = false;
   gNameSpaceManager = nsnull;
   sRuntimeService = nsnull;
   sRuntime = nsnull;
   sIsInitialized = false;
   sDidShutdown = false;
   sContextCount = 0;
   sSecurityManager = nsnull;
@@ -3832,16 +3909,17 @@ nsJSRuntime::GetNameSpaceManager()
 
 /* static */
 void
 nsJSRuntime::Shutdown()
 {
   nsJSContext::KillGCTimer();
   nsJSContext::KillShrinkGCBuffersTimer();
   nsJSContext::KillCCTimer();
+  nsJSContext::KillFullGCTimer();
 
   NS_IF_RELEASE(gNameSpaceManager);
 
   if (!sContextCount) {
     // We're being shutdown, and there are no more contexts
     // alive, release the JS runtime service and the security manager.
 
     NS_IF_RELEASE(sRuntimeService);
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -179,31 +179,34 @@ public:
   virtual void EnterModalState();
   virtual void LeaveModalState();
 
   NS_DECL_NSIXPCSCRIPTNOTIFY
 
   static void LoadStart();
   static void LoadEnd();
 
-  static void GarbageCollectNow(js::gcreason::Reason reason, PRUint32 gckind = nsGCNormal);
+  static void GarbageCollectNow(js::gcreason::Reason reason,
+                                PRUint32 aGckind,
+                                bool aGlobal);
   static void ShrinkGCBuffersNow();
   // If aExtraForgetSkippableCalls is -1, forgetSkippable won't be
   // called even if the previous collection was GC.
   static void CycleCollectNow(nsICycleCollectorListener *aListener = nsnull,
                               PRInt32 aExtraForgetSkippableCalls = 0);
 
   static void PokeGC(js::gcreason::Reason aReason, int aDelay = 0);
   static void KillGCTimer();
 
   static void PokeShrinkGCBuffers();
   static void KillShrinkGCBuffersTimer();
 
   static void MaybePokeCC();
   static void KillCCTimer();
+  static void KillFullGCTimer();
 
   virtual void GC(js::gcreason::Reason aReason);
 
   static PRUint32 CleanupsSinceLastGC();
 
   nsIScriptGlobalObject* GetCachedGlobalObject()
   {
     // Verify that we have a global so that this
@@ -233,17 +236,17 @@ protected:
   // reporting.
   void ReportPendingException();
 private:
   void DestroyJSContext();
 
   nsrefcnt GetCCRefcnt();
 
   JSContext *mContext;
-  PRUint32 mNumEvaluations;
+  bool mActive;
 
 protected:
   struct TerminationFuncHolder;
   friend struct TerminationFuncHolder;
   
   struct TerminationFuncClosure
   {
     TerminationFuncClosure(nsScriptTerminationFunc aFunc,
@@ -302,16 +305,19 @@ private:
 
   PRUint32 mExecuteDepth;
   PRUint32 mDefaultJSOptions;
   PRTime mOperationCallbackTime;
 
   PRTime mModalStateTime;
   PRUint32 mModalStateDepth;
 
+  nsJSContext *mNext;
+  nsJSContext **mPrev;
+
   // mGlobalObjectRef ensures that the outer window stays alive as long as the
   // context does. It is eventually collected by the cycle collector.
   nsCOMPtr<nsIScriptGlobalObject> mGlobalObjectRef;
 
   static int JSOptionChangedCallback(const char *pref, void *data);
 
   static JSBool DOMOperationCallback(JSContext *cx);
 };
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -205,16 +205,21 @@ CollectWindowReports(nsGlobalWindow *aWi
          "Memory used by style sets within a window.");
   aWindowTotalSizes->mLayoutStyleSets += windowSizes.mLayoutStyleSets;
 
   REPORT("/layout/text-runs", windowSizes.mLayoutTextRuns,
          "Memory used for text-runs (glyph layout) in the PresShell's frame "
          "tree, within a window.");
   aWindowTotalSizes->mLayoutTextRuns += windowSizes.mLayoutTextRuns;
 
+  REPORT("/layout/pres-contexts", windowSizes.mLayoutPresContext,
+         "Memory used for the PresContext in the PresShell's frame "
+         "within a window.");
+  aWindowTotalSizes->mLayoutPresContext += windowSizes.mLayoutPresContext;
+
 #undef REPORT
 
   return NS_OK;
 }
 
 typedef nsTArray< nsRefPtr<nsGlobalWindow> > WindowArray;
 
 static
--- a/dom/base/nsWindowMemoryReporter.h
+++ b/dom/base/nsWindowMemoryReporter.h
@@ -59,16 +59,17 @@ public:
     mMallocSizeOf = aMallocSizeOf;
   }
   nsMallocSizeOfFun mMallocSizeOf;
   size_t mDOM;
   size_t mStyleSheets;
   size_t mLayoutArenas;
   size_t mLayoutStyleSets;
   size_t mLayoutTextRuns;
+  size_t mLayoutPresContext;
 };
 
 /**
  * nsWindowMemoryReporter is responsible for the 'explicit/window-objects'
  * memory reporter.
  *
  * We classify DOM window objects into one of three categories:
  *
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -4,17 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BindingUtils.h"
 
 namespace mozilla {
 namespace dom {
 
-static bool
+bool
 DefineConstants(JSContext* cx, JSObject* obj, ConstantSpec* cs)
 {
   for (; cs->name; ++cs) {
     JSBool ok =
       JS_DefineProperty(cx, obj, cs->name, cs->value, NULL, NULL,
                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
     if (!ok) {
       return false;
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -228,16 +228,22 @@ DestroyProtoOrIfaceCache(JSObject* obj)
 }
 
 struct ConstantSpec
 {
   const char* name;
   JS::Value value;
 };
 
+/**
+ * Add constants to an object.
+ */
+bool
+DefineConstants(JSContext* cx, JSObject* obj, ConstantSpec* cs);
+
 /*
  * Create a DOM interface object (if constructorClass is non-null) and/or a
  * DOM interface prototype object (if protoClass is non-null).
  *
  * global is used as the parent of the interface object and the interface
  *        prototype object
  * receiver is the object on which we need to define the interface object as a
  *          property
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -786,24 +786,24 @@ ContentChild::GetIndexedDBPath()
     }
 
     return *gIndexedDBPath;
 }
 
 bool
 ContentChild::RecvGarbageCollect()
 {
-    nsJSContext::GarbageCollectNow(js::gcreason::DOM_IPC);
+    nsJSContext::GarbageCollectNow(js::gcreason::DOM_IPC, nsGCNormal, true);
     return true;
 }
 
 bool
 ContentChild::RecvCycleCollect()
 {
-    nsJSContext::GarbageCollectNow(js::gcreason::DOM_IPC);
+    nsJSContext::GarbageCollectNow(js::gcreason::DOM_IPC, nsGCNormal, true);
     nsJSContext::CycleCollectNow();
     return true;
 }
 
 bool
 ContentChild::RecvAppInfo(const nsCString& version, const nsCString& buildID)
 {
     mAppInfo.version.Assign(version);
--- a/dom/system/Makefile.in
+++ b/dom/system/Makefile.in
@@ -58,36 +58,50 @@ DIRS = android
 endif
 
 ifdef MOZ_B2G_RIL
 DIRS += gonk
 endif
 
 CPPSRCS     = \
   nsDeviceSensors.cpp \
+  OSFileConstants.cpp \
   $(NULL)
 
 # We fire the nsDOMDeviceAcceleration
 LOCAL_INCLUDES += -I$(topsrcdir)/content/events/src
 
+LOCAL_INCLUDES += \
+  -I$(topsrcdir)/dom/base \
+  -I$(topsrcdir)/dom/bindings \
+  -I$(topsrcdir)/js/xpconnect/src \
+  -I$(topsrcdir)/js/xpconnect/wrappers \
+  $(NULL)
+
 # On Systems that have build in geolocation providers,
 # we really do not need these.
 ifneq (Android,$(OS_TARGET))
 EXTRA_COMPONENTS = \
   NetworkGeolocationProvider.js \
   NetworkGeolocationProvider.manifest \
   GPSDGeolocationProvider.js \
   GPSDGeolocationProvider.manifest \
   $(NULL)
 endif
 
+EXPORTS_NAMESPACES = mozilla
+
 EXPORTS     = \
   nsDeviceSensors.h \
   $(NULL)
 
+EXPORTS_mozilla = \
+  OSFileConstants.h \
+  $(NULL)
+
 # We fire the nsDOMDeviceAcceleration
 LOCAL_INCLUDES += -I$(topsrcdir)/content/events/src
 
 include $(topsrcdir)/config/config.mk
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 LIBXUL_LIBRARY   = 1
 FORCE_STATIC_LIB = 1
new file mode 100644
--- /dev/null
+++ b/dom/system/OSFileConstants.cpp
@@ -0,0 +1,222 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "fcntl.h"
+#include "errno.h"
+
+#if defined(XP_UNIX)
+#include "unistd.h"
+#endif // defined(XP_UNIX)
+
+#include "jsapi.h"
+#include "jsfriendapi.h"
+#include "BindingUtils.h"
+#include "OSFileConstants.h"
+
+/**
+ * This module defines the basic libc constants (error numbers, open modes,
+ * etc.) used by OS.File and possibly other OS-bound JavaScript libraries.
+ */
+
+namespace mozilla {
+
+/**
+ * Define a simple read-only property holding an integer.
+ *
+ * @param name The name of the constant. Used both as the JS name for the
+ * constant and to access its value. Must be defined.
+ *
+ * Produces a |ConstantSpec|.
+ */
+#define INT_CONSTANT(name)      \
+  { #name, INT_TO_JSVAL(name) }
+
+/**
+ * End marker for ConstantSpec
+ */
+#define PROP_END { NULL, JSVAL_VOID }
+
+
+// Define missing constants for Android
+#if !defined(S_IRGRP)
+#define S_IXOTH 0001
+#define S_IWOTH 0002
+#define S_IROTH 0004
+#define S_IRWXO 0007
+#define S_IXGRP 0010
+#define S_IWGRP 0020
+#define S_IRGRP 0040
+#define S_IRWXG 0070
+#define S_IXUSR 0100
+#define S_IWUSR 0200
+#define S_IRUSR 0400
+#define S_IRWXU 0700
+#endif // !defined(S_IRGRP)
+
+/**
+ * The properties defined in libc.
+ *
+ * If you extend this list of properties, please
+ * separate categories ("errors", "open", etc.),
+ * keep properties organized by alphabetical order
+ * and #ifdef-away properties that are not portable.
+ */
+static dom::ConstantSpec gLibcProperties[] =
+{
+  // Arguments for open
+  INT_CONSTANT(O_APPEND),
+  INT_CONSTANT(O_CREAT),
+#if defined(O_DIRECTORY)
+  INT_CONSTANT(O_DIRECTORY),
+#endif // defined(O_DIRECTORY)
+#if defined(O_EVTONLY)
+  INT_CONSTANT(O_EVTONLY),
+#endif // defined(O_EVTONLY)
+  INT_CONSTANT(O_EXCL),
+#if defined(O_EXLOCK)
+  INT_CONSTANT(O_EXLOCK),
+#endif // defined(O_EXLOCK)
+#if defined(O_LARGEFILE)
+  INT_CONSTANT(O_LARGEFILE),
+#endif // defined(O_LARGEFILE)
+#if defined(O_NOFOLLOW)
+  INT_CONSTANT(O_NOFOLLOW),
+#endif // defined(O_NOFOLLOW)
+#if defined(O_NONBLOCK)
+  INT_CONSTANT(O_NONBLOCK),
+#endif // defined(O_NONBLOCK)
+  INT_CONSTANT(O_RDONLY),
+  INT_CONSTANT(O_RDWR),
+#if defined(O_RSYNC)
+  INT_CONSTANT(O_RSYNC),
+#endif // defined(O_RSYNC)
+#if defined(O_SHLOCK)
+  INT_CONSTANT(O_SHLOCK),
+#endif // defined(O_SHLOCK)
+#if defined(O_SYMLINK)
+  INT_CONSTANT(O_SYMLINK),
+#endif // defined(O_SYMLINK)
+#if defined(O_SYNC)
+  INT_CONSTANT(O_SYNC),
+#endif // defined(O_SYNC)
+  INT_CONSTANT(O_TRUNC),
+  INT_CONSTANT(O_WRONLY),
+
+#if defined(AT_EACCESS)
+  INT_CONSTANT(AT_EACCESS),
+#endif //defined(AT_EACCESS)
+#if defined(AT_FDCWD)
+  INT_CONSTANT(AT_FDCWD),
+#endif //defined(AT_FDCWD)
+#if defined(AT_SYMLINK_NOFOLLOW)
+  INT_CONSTANT(AT_SYMLINK_NOFOLLOW),
+#endif //defined(AT_SYMLINK_NOFOLLOW)
+
+  // access
+#if defined(F_OK)
+  INT_CONSTANT(F_OK),
+  INT_CONSTANT(R_OK),
+  INT_CONSTANT(W_OK),
+  INT_CONSTANT(X_OK),
+#endif // defined(F_OK)
+
+  // modes
+  INT_CONSTANT(S_IRGRP),
+  INT_CONSTANT(S_IROTH),
+  INT_CONSTANT(S_IRUSR),
+  INT_CONSTANT(S_IRWXG),
+  INT_CONSTANT(S_IRWXO),
+  INT_CONSTANT(S_IRWXU),
+  INT_CONSTANT(S_IWGRP),
+  INT_CONSTANT(S_IWOTH),
+  INT_CONSTANT(S_IWUSR),
+  INT_CONSTANT(S_IXOTH),
+  INT_CONSTANT(S_IXGRP),
+  INT_CONSTANT(S_IXUSR),
+
+  // seek
+  INT_CONSTANT(SEEK_CUR),
+  INT_CONSTANT(SEEK_END),
+  INT_CONSTANT(SEEK_SET),
+
+  // error values
+  INT_CONSTANT(EACCES),
+  INT_CONSTANT(EAGAIN),
+  INT_CONSTANT(EBADF),
+  INT_CONSTANT(EEXIST),
+  INT_CONSTANT(EFAULT),
+  INT_CONSTANT(EFBIG),
+  INT_CONSTANT(EINVAL),
+  INT_CONSTANT(EIO),
+  INT_CONSTANT(EISDIR),
+  INT_CONSTANT(ELOOP),
+  INT_CONSTANT(EMFILE),
+  INT_CONSTANT(ENAMETOOLONG),
+  INT_CONSTANT(ENFILE),
+  INT_CONSTANT(ELOOP),
+  INT_CONSTANT(ENOENT),
+  INT_CONSTANT(ENOMEM),
+  INT_CONSTANT(ENOSPC),
+  INT_CONSTANT(ENOTDIR),
+  INT_CONSTANT(ENXIO),
+  INT_CONSTANT(EOPNOTSUPP),
+  INT_CONSTANT(EOVERFLOW),
+  INT_CONSTANT(EPERM),
+  INT_CONSTANT(ERANGE),
+  INT_CONSTANT(ETIMEDOUT),
+  INT_CONSTANT(EWOULDBLOCK),
+  INT_CONSTANT(EXDEV),
+
+  PROP_END
+};
+
+/**
+ * Get a field of an object as an object.
+ *
+ * If the field does not exist, create it. If it exists but is not an
+ * object, throw a JS error.
+ */
+JSObject *GetOrCreateObjectProperty(JSContext *cx, JSObject *aObject,
+                                    const char *aProperty)
+{
+  jsval val;
+  if (JS_GetProperty(cx, aObject, aProperty, &val)
+      && !JSVAL_IS_VOID(val)) {
+    if (JSVAL_IS_OBJECT(val)) {
+      return JSVAL_TO_OBJECT(val);
+    }
+    else {
+      JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+         JSMSG_UNEXPECTED_TYPE, aProperty, "not an object");
+      return NULL;
+    }
+  }
+  return JS_DefineObject(cx, aObject, aProperty, NULL, NULL, JSPROP_ENUMERATE);
+}
+
+/**
+ * Define OS-specific constants.
+ *
+ * This function creates or uses JS object |OS.Constants| to store
+ * all its constants.
+ */
+bool DefineOSFileConstants(JSContext *cx, JSObject *global)
+{
+  JSObject *objOS;
+  if (!(objOS = GetOrCreateObjectProperty(cx, global, "OS"))) {
+    return false;
+  }
+  JSObject *objConstants;
+  if (!(objConstants = GetOrCreateObjectProperty(cx, objOS, "Constants"))) {
+    return false;
+  }
+  JSObject *objLibc;
+  if (!(objLibc = GetOrCreateObjectProperty(cx, objConstants, "libc"))) {
+    return false;
+  }
+  return dom::DefineConstants(cx, objLibc, gLibcProperties);
+}
+
+} // namespace mozilla
+
new file mode 100644
--- /dev/null
+++ b/dom/system/OSFileConstants.h
@@ -0,0 +1,22 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_osfileconstants_h__
+#define mozilla_osfileconstants_h__
+
+#include "jspubtd.h"
+
+namespace mozilla {
+
+/**
+ * Define OS-specific constants.
+ *
+ * This function creates or uses JS object |OS.Constants| to store
+ * all its constants.
+ */
+bool DefineOSFileConstants(JSContext *cx, JSObject *global);
+
+}
+
+#endif // mozilla_osfileconstants_h__
--- a/dom/telephony/test/marionette/test_dial_answer.py
+++ b/dom/telephony/test/marionette/test_dial_answer.py
@@ -76,14 +76,15 @@ waitFor(function() {
 }, function() {
     return window.wrappedJSObject.callstate == "connected";
 });
 """)
 
         # Verify that the callstate changes to connected on the caller as well.
         self.assertTrue(receiver.execute_async_script("""
 waitFor(function() {
+    window.wrappedJSObject.incoming.hangUp();
     marionetteScriptFinished(true);
 }, function() {
     return window.wrappedJSObject.callstate == "connected";
 });
 """))
 
--- a/dom/telephony/test/marionette/test_dial_between_emulators.py
+++ b/dom/telephony/test/marionette/test_dial_between_emulators.py
@@ -47,9 +47,11 @@ window.navigator.mozTelephony.dial("%s")
                 setTimeout(check_incoming, 500);
             }
         }
         setTimeout(check_incoming, 0);
     """)
         # Verify the phone number of the incoming call.
         self.assertEqual(received, fromPhoneNumber)
 
+        sender.execute_script("window.navigator.mozTelephony.calls[0].hangUp();")
+        receiver.execute_script("window.navigator.mozTelephony.calls[0].hangUp();")
 
--- a/dom/tests/mochitest/browser-frame/Makefile.in
+++ b/dom/tests/mochitest/browser-frame/Makefile.in
@@ -49,12 +49,13 @@ include $(topsrcdir)/config/rules.mk
 		browserFrameHelpers.js \
 		test_browserFrame1.html \
 		test_browserFrame2.html \
 		test_browserFrame3.html \
 		test_browserFrame4.html \
 		test_browserFrame5.html \
 		test_browserFrame6.html \
 		test_browserFrame7.html \
+		test_browserFrame8.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/browser-frame/test_browserFrame8.html
@@ -0,0 +1,130 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=719461
+-->
+<head>
+  <title>Test for Bug 719461</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="browserFrameHelpers.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=719461">Mozilla Bug 719461</a>
+
+<!--
+  Test that the onmozbrowsericonchange event works.
+-->
+
+<script type="application/javascript;version=1.7">
+
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+
+function createHtml(link) {
+  return 'data:text/html,<html><head>' + link + '<body></body></html>';
+}
+
+function createLink(name) {
+  return '<link rel="icon" type="image/png" href="http://example.com/' + name + '.png">';
+}
+
+function runTest() {
+  browserFrameHelpers.setEnabledPref(true);
+  browserFrameHelpers.addToWhitelist();
+
+  var iframe1 = document.createElement('iframe');
+  iframe1.mozbrowser = true;
+  document.body.appendChild(iframe1);
+
+  // iframe2 is a red herring; we modify its favicon but don't listen for
+  // iconchanges; we want to make sure that its iconchange events aren't
+  // picked up by the listener on iframe1.
+  var iframe2 = document.createElement('iframe');
+  iframe2.mozbrowser = true;
+  document.body.appendChild(iframe2);
+
+  // iframe3 is another red herring.  It's not a mozbrowser, so we shouldn't
+  // get any iconchange events on it.
+  var iframe3 = document.createElement('iframe');
+  document.body.appendChild(iframe3);
+
+  var numIconChanges = 0;
+
+  iframe1.addEventListener('mozbrowsericonchange', function(e) {
+
+    numIconChanges++;
+
+    if (numIconChanges == 1) {
+      is(e.detail, 'http://example.com/myicon.png');
+
+      // We should recieve iconchange events when the user creates new links
+      // to a favicon, but only when we listen for them
+      SpecialPowers.getBrowserFrameMessageManager(iframe1)
+                   .loadFrameScript("data:,content.document.title='New title';",
+                                    /* allowDelayedLoad = */ false);
+
+      SpecialPowers.getBrowserFrameMessageManager(iframe1)
+                   .loadFrameScript("data:,content.document.head.insertAdjacentHTML('beforeend', '<link rel=ICON href=http://example.com/newicon.png>')",
+                                    /* allowDelayedLoad = */ false);
+
+      SpecialPowers.getBrowserFrameMessageManager(iframe2)
+                   .loadFrameScript("data:,content.document.head.insertAdjacentHTML('beforeend', '<link rel=ICON href=http://example.com/newicon.png>')",
+                                    /* allowDelayedLoad = */ false);
+    }
+    else if (numIconChanges == 2) {
+      is(e.detail, 'http://example.com/newicon.png');
+
+      // Full new pages should trigger iconchange events
+      iframe1.src = createHtml(createLink('3rdicon'));
+    }
+    else if (numIconChanges == 3) {
+      is(e.detail, 'http://example.com/3rdicon.png');
+
+      // the rel attribute can have various space seperated values, make
+      // sure we only pick up correct values for 'icon'
+      SpecialPowers.getBrowserFrameMessageManager(iframe1)
+                   .loadFrameScript("data:,content.document.head.insertAdjacentHTML('beforeend', '<link rel=shortcuticon href=http://example.com/newicon.png>')",
+                                    /* allowDelayedLoad = */ false);
+      // Test setting a page with multiple links elements
+      iframe1.src = createHtml(createLink('another') + createLink('icon'));
+    }
+    else if (numIconChanges == 4) {
+      is(e.detail, 'http://example.com/another.png');
+      // 2 events will be triggered by previous test, wait for next
+    }
+    else if (numIconChanges == 5) {
+      is(e.detail, 'http://example.com/icon.png');
+
+      // Make sure icon check is case insensitive
+      SpecialPowers.getBrowserFrameMessageManager(iframe1)
+                   .loadFrameScript("data:,content.document.head.insertAdjacentHTML('beforeend', '<link rel=ICON href=http://example.com/ucaseicon.png>')",
+                                    /* allowDelayedLoad = */ false);
+    }
+    else if (numIconChanges == 6) {
+      is(e.detail, 'http://example.com/ucaseicon.png');
+      SimpleTest.finish();
+    } else {
+      ok(false, 'Too many iconchange events.');
+    }
+  });
+
+  iframe3.addEventListener('mozbrowsericonchange', function(e) {
+    ok(false, 'Should not get a iconchange event for iframe3.');
+  });
+
+
+  iframe1.src = createHtml(createLink('myicon'));
+  // We should not recieve icon change events for either of the below iframes
+  iframe2.src = createHtml(createLink('myicon'));
+  iframe3.src = createHtml(createLink('myicon'));
+
+}
+
+addEventListener('load', function() { SimpleTest.executeSoon(runTest); });
+
+</script>
+
+</body>
+</html>
--- a/dom/tests/mochitest/general/test_offsets.js
+++ b/dom/tests/mochitest/general/test_offsets.js
@@ -27,21 +27,16 @@ function testElements(baseid, callback)
 }
 
 function toNearestAppunit(v)
 {
   // 60 appunits per CSS pixel; round result to the nearest appunit
   return Math.round(v*60)/60;
 }
 
-function floorToNearestAppunit(v)
-{
-  return Math.floor(toNearestAppunit(v));
-}
-
 function isEqualAppunits(a, b, msg)
 {
   is(toNearestAppunit(a), toNearestAppunit(b), msg);
 }
 
 function testElement(element)
 {
   var offsetParent = element.getAttribute("_offsetParent");
@@ -62,21 +57,21 @@ function testElement(element)
     checkOffsetState(element, -10000, -10000,
                               borderLeft + paddingLeft + width + paddingRight + borderRight,
                               borderTop + paddingTop + height + paddingBottom + borderBottom,
                               offsetParent, element.id);
 
   var scrollWidth, scrollHeight, clientWidth, clientHeight;
   if (element.id == "scrollbox") {
     var lastchild = $("lastline");
-    scrollWidth = floorToNearestAppunit(lastchild.getBoundingClientRect().width + paddingLeft + paddingRight);
+    scrollWidth = lastchild.getBoundingClientRect().width + paddingLeft + paddingRight;
     var top = element.firstChild.getBoundingClientRect().top;
     var bottom = element.lastChild.getBoundingClientRect().bottom;
     var contentsHeight = bottom - top;
-    scrollHeight = floorToNearestAppunit(contentsHeight + paddingTop + paddingBottom);
+    scrollHeight = contentsHeight + paddingTop + paddingBottom;
     clientWidth = paddingLeft + width + paddingRight - scrollbarWidth;
     clientHeight = paddingTop + height + paddingBottom - scrollbarHeight;
   }
   else {
     // XXXndeakin note that Mozilla adds borders here, although the spec does not
     scrollWidth = paddingLeft + width + paddingRight + borderLeft + borderRight;
     scrollHeight = paddingTop + height + paddingBottom + borderTop + borderBottom;
     clientWidth = paddingLeft + width + paddingRight;
--- a/dom/tests/mochitest/webapps/apphelper.js
+++ b/dom/tests/mochitest/webapps/apphelper.js
@@ -5,18 +5,16 @@ const MODE_READONLY = 0x01;
 const PERMS_FILE = 0644;
 
 var popupNotifications = getPopupNotifications(window.top);
 
 var event_listener_loaded = {};
 
 Components.utils.import("resource://gre/modules/Services.jsm");
 
-netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-
 Components.classes["@mozilla.org/permissionmanager;1"]
           .getService(Components.interfaces.nsIPermissionManager)
           .add(SpecialPowers.getDocumentURIObject(window.document),
                "webapps-manage",
                Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
 
 SpecialPowers.setCharPref("dom.mozApps.whitelist", "http://mochi.test:8888");
 SpecialPowers.setBoolPref('dom.mozBrowserFramesEnabled', true);
--- a/dom/workers/Makefile.in
+++ b/dom/workers/Makefile.in
@@ -56,15 +56,16 @@ EXPORTS_mozilla/dom/workers/bindings = \
   XMLHttpRequestUpload.h \
   XMLHttpRequest.h \
   $(NULL)
 
 LOCAL_INCLUDES = \
   -I$(topsrcdir)/content/base/src \
   -I$(topsrcdir)/content/events/src \
   -I$(topsrcdir)/dom/base \
+  -I$(topsrcdir)/dom/system \
   -I$(topsrcdir)/xpcom/build \
   -I$(topsrcdir)/js/xpconnect/src \
   $(NULL)
 
 TEST_DIRS += test
 
 include $(topsrcdir)/config/rules.mk
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -42,16 +42,17 @@
 #include "jsapi.h"
 #include "jsdbgapi.h"
 #include "mozilla/Util.h"
 #include "mozilla/dom/DOMJSClass.h"
 #include "mozilla/dom/EventTargetBinding.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/XMLHttpRequestBinding.h"
 #include "mozilla/dom/XMLHttpRequestUploadBinding.h"
+#include "mozilla/OSFileConstants.h"
 #include "nsTraceRefcnt.h"
 #include "xpcpublic.h"
 
 #ifdef ANDROID
 #include <android/log.h>
 #endif
 
 #include "ChromeWorkerScope.h"
@@ -983,17 +984,18 @@ CreateDedicatedWorkerGlobalScope(JSConte
   JSObject* workerProto = worker::InitClass(aCx, global, eventTargetProto,
                                             false);
   if (!workerProto) {
     return NULL;
   }
 
   if (worker->IsChromeWorker() &&
       (!chromeworker::InitClass(aCx, global, workerProto, false) ||
-       !DefineChromeWorkerFunctions(aCx, global))) {
+       !DefineChromeWorkerFunctions(aCx, global)) ||
+       !DefineOSFileConstants(aCx, global)) {
     return NULL;
   }
 
   // Init other classes we care about.
   if (!events::InitClasses(aCx, global, false) ||
       !file::InitClasses(aCx, global) ||
       !filereadersync::InitClass(aCx, global) ||
       !exceptions::InitClasses(aCx, global) ||
--- a/editor/libeditor/base/crashtests/382527-1.html
+++ b/editor/libeditor/base/crashtests/382527-1.html
@@ -31,17 +31,19 @@ function init2()
 
 function init3()
 {
   var rng = targetDocument.createRange(); 
   rng.setStart(textNode, 1);
   rng.setEnd(textNode, 1);
   targetWindow.getSelection().addRange(rng);
 
-  targetDocument.execCommand("inserthtml", false, "<p>");
+  try {
+    targetDocument.execCommand("inserthtml", false, "<p>");
+  } catch(e) {}
   
   document.documentElement.removeAttribute("class");
 }
 
 
 </script>
 
 </head>
--- a/editor/libeditor/base/nsEditor.h
+++ b/editor/libeditor/base/nsEditor.h
@@ -576,17 +576,17 @@ public:
   bool IsDescendantOfEditorRoot(nsIDOMNode* aNode);
   bool IsDescendantOfEditorRoot(nsINode* aNode);
 
   /** returns true if aNode is a container */
   virtual bool IsContainer(nsIDOMNode *aNode);
 
   /** returns true if aNode is an editable node */
   bool IsEditable(nsIDOMNode *aNode);
-  bool IsEditable(nsIContent *aNode);
+  virtual bool IsEditable(nsIContent *aNode);
 
   /**
    * aNode must be a non-null text node.
    */
   virtual bool IsTextInDirtyFrameVisible(nsIContent *aNode);
 
   /** returns true if aNode is a MozEditorBogus node */
   bool IsMozEditorBogusNode(nsIContent *aNode);
--- a/editor/libeditor/base/nsEditorCommands.cpp
+++ b/editor/libeditor/base/nsEditorCommands.cpp
@@ -651,26 +651,28 @@ nsDeleteCommand::GetCommandStateParams(c
 NS_IMETHODIMP
 nsSelectAllCommand::IsCommandEnabled(const char * aCommandName,
                                      nsISupports *aCommandRefCon,
                                      bool *outCmdEnabled)
 {
   NS_ENSURE_ARG_POINTER(outCmdEnabled);
 
   nsresult rv = NS_OK;
-  *outCmdEnabled = false;
+  // You can always select all, unless the selection is editable,
+  // and the editable region is empty!
+  *outCmdEnabled = true;
   bool docIsEmpty;
- 
+
   // you can select all if there is an editor which is non-empty
   nsCOMPtr<nsIEditor> editor = do_QueryInterface(aCommandRefCon);
   if (editor) {
     rv = editor->GetDocumentIsEmpty(&docIsEmpty);
     NS_ENSURE_SUCCESS(rv, rv);
     *outCmdEnabled = !docIsEmpty;
-  } 
+  }
 
   return rv;
 }
 
 
 NS_IMETHODIMP
 nsSelectAllCommand::DoCommand(const char *aCommandName,
                               nsISupports *aCommandRefCon)
--- a/editor/libeditor/html/crashtests/716456-1.html
+++ b/editor/libeditor/html/crashtests/716456-1.html
@@ -9,16 +9,17 @@ function boom()
   div.contentEditable = "true";
   div.focus();
 
   var r = document.documentElement;
   document["removeChild"](r);
   document["appendChild"](r);
 
   setTimeout(function() {
+    getSelection().collapse(div, 0);
     document.execCommand("inserthtml", false, "a");
     setTimeout(function() {
       document.documentElement.removeAttribute("class");
     }, 0);
   }, 0);
 }
 
 </script>
--- a/editor/libeditor/html/nsHTMLDataTransfer.cpp
+++ b/editor/libeditor/html/nsHTMLDataTransfer.cpp
@@ -309,17 +309,19 @@ nsHTMLEditor::DoInsertHTMLWithContext(co
   PRInt32 targetOffset=0;
 
   if (!aDestNode)
   {
     // if caller didn't provide the destination/target node,
     // fetch the paste insertion point from our selection
     rv = GetStartNodeAndOffset(selection, getter_AddRefs(targetNode), &targetOffset);
     NS_ENSURE_SUCCESS(rv, rv);
-    NS_ENSURE_TRUE(targetNode, NS_ERROR_FAILURE);
+    if (!targetNode || !IsEditable(targetNode)) {
+      return NS_ERROR_FAILURE;
+    }
   }
   else
   {
     targetNode = aDestNode;
     targetOffset = aDestOffset;
   }
 
   bool doContinue = true;
--- a/editor/libeditor/html/nsHTMLEditor.cpp
+++ b/editor/libeditor/html/nsHTMLEditor.cpp
@@ -412,16 +412,22 @@ nsHTMLEditor::FindSelectionRoot(nsINode 
   // permission script.
   if (IsReadonly()) {
     // We still want to allow selection in a readonly editor.
     content = do_QueryInterface(GetRoot());
     return content.forget();
   }
 
   if (!content->HasFlag(NODE_IS_EDITABLE)) {
+    // If the content is in read-write state but is not editable itself,
+    // return it as the selection root.
+    if (content->IsElement() &&
+        content->AsElement()->State().HasState(NS_EVENT_STATE_MOZ_READWRITE)) {
+      return content.forget();
+    }
     return nsnull;
   }
 
   // For non-readonly editors we want to find the root of the editable subtree
   // containing aContent.
   content = content->GetEditingHost();
   return content.forget();
 }
@@ -5696,14 +5702,28 @@ nsHTMLEditor::GetPreferredIMEState(IMESt
 
 already_AddRefed<nsIContent>
 nsHTMLEditor::GetInputEventTargetContent()
 {
   nsCOMPtr<nsIContent> target = GetActiveEditingHost();
   return target.forget();
 }
 
+bool
+nsHTMLEditor::IsEditable(nsIContent* aNode) {
+  if (!nsPlaintextEditor::IsEditable(aNode)) {
+    return false;
+  }
+  if (aNode->IsElement()) {
+    // If we're dealing with an element, then ask it whether it's editable.
+    return aNode->IsEditable();
+  }
+  // We might be dealing with a text node for example, which we always consider
+  // to be editable.
+  return true;
+}
+
 // virtual MOZ_OVERRIDE
 dom::Element*
 nsHTMLEditor::GetEditorRoot()
 {
   return GetActiveEditingHost();
 }
--- a/editor/libeditor/html/nsHTMLEditor.h
+++ b/editor/libeditor/html/nsHTMLEditor.h
@@ -135,16 +135,18 @@ public:
   virtual nsresult HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent);
   virtual already_AddRefed<nsIContent> GetFocusedContent();
   virtual bool IsActiveInDOMWindow();
   virtual already_AddRefed<nsIDOMEventTarget> GetDOMEventTarget();
   virtual mozilla::dom::Element* GetEditorRoot() MOZ_OVERRIDE;
   virtual already_AddRefed<nsIContent> FindSelectionRoot(nsINode *aNode);
   virtual bool IsAcceptableInputEvent(nsIDOMEvent* aEvent);
   virtual already_AddRefed<nsIContent> GetInputEventTargetContent();
+  virtual bool IsEditable(nsIContent *aNode);
+  using nsEditor::IsEditable;
 
   /* ------------ nsStubMutationObserver overrides --------- */
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
 
   /* ------------ nsIEditorIMESupport overrides ------------ */
   NS_IMETHOD GetPreferredIMEState(mozilla::widget::IMEState *aState);
--- a/editor/libeditor/html/tests/Makefile.in
+++ b/editor/libeditor/html/tests/Makefile.in
@@ -79,16 +79,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug552782.html \
 		test_bug570144.html \
 		test_bug578771.html \
 		test_bug592592.html \
 		test_bug597784.html \
 		test_bug599322.html \
 		test_bug607584.html \
 		test_bug611182.html \
+		test_bug612128.html \
 		test_bug612447.html \
 		test_bug620906.html \
 		test_bug622371.html \
 		test_bug629845.html \
 		test_bug640321.html \
 		test_bug668599.html \
 		test_bug674770-1.html \
 		file_bug674770-1.html \
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/html/tests/test_bug612128.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=612128
+-->
+<head>
+  <title>Test for Bug 612128</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=612128">Mozilla Bug 612128</a>
+<p id="display"></p>
+<div id="content">
+<input>
+<div contenteditable></div>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 612128 **/
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+  document.querySelector("input").focus();
+  var threw = false;
+  try {
+    document.execCommand("inserthtml", null, "<span>f" + "oo</span>");
+  } catch (e) {
+    threw = true;
+  }
+  ok(threw, "The inserthtml command should fail");
+  is(document.querySelectorAll("span").length, 0, "No span element should be injected inside the page");
+  is(document.body.innerHTML.indexOf("f" + "oo"), -1, "No text should be injected inside the page");
+  SimpleTest.finish();
+});
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/editor/reftests/readonly-editable-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <input>
+    <input readonly>
+    <input type=password>
+    <input type=password readonly>
+    <input type=email>
+    <input type=email readonly>
+    <textarea></textarea>
+    <textarea readonly></textarea>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/editor/reftests/readonly-editable.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <style>
+      :-moz-read-write + span {
+        display: none;
+      }
+      span {
+        color: transparent; /* workaround for bug 617524 */
+        outline: 1px solid green;
+      }
+    </style>
+  </head>
+  <body contenteditable>
+    <input><span>hide me</span>
+    <input readonly><span>hide me</span>
+    <input type=password><span>hide me</span>
+    <input type=password readonly><span>hide me</span>
+    <input type=email><span>hide me</span>
+    <input type=email readonly><span>hide me</span>
+    <textarea></textarea><span>hide me</span>
+    <textarea readonly></textarea><span>hide me</span>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/editor/reftests/readonly-non-editable-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <style>
+      span {
+        color: transparent; /* workaround for bug 617524 */
+        outline: 1px solid green;
+      }
+    </style>
+  </head>
+  <body>
+    <input><span>hide me</span>
+    <input readonly>
+    <input type=password><span>hide me</span>
+    <input type=password readonly>
+    <input type=email><span>hide me</span>
+    <input type=email readonly>
+    <textarea></textarea><span>hide me</span>
+    <textarea readonly></textarea>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/editor/reftests/readonly-non-editable.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <style>
+      :-moz-read-only + span {
+        display: none;
+      }
+      span {
+        color: transparent; /* workaround for bug 617524 */
+        outline: 1px solid green;
+      }
+    </style>
+  </head>
+  <body>
+    <input><span>hide me</span>
+    <input readonly><span>hide me</span>
+    <input type=password><span>hide me</span>
+    <input type=password readonly><span>hide me</span>
+    <input type=email><span>hide me</span>
+    <input type=email readonly><span>hide me</span>
+    <textarea></textarea><span>hide me</span>
+    <textarea readonly></textarea><span>hide me</span>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/editor/reftests/readwrite-editable-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <input>
+    <input readonly>
+    <input type=password>
+    <input type=password readonly>
+    <input type=email>
+    <input type=email readonly>
+    <textarea></textarea>
+    <textarea readonly></textarea>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/editor/reftests/readwrite-editable.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <style>
+      :-moz-read-write + span {
+        display: none;
+      }
+      span {
+        color: transparent; /* workaround for bug 617524 */
+        outline: 1px solid green;
+      }
+    </style>
+  </head>
+  <body contenteditable>
+    <input><span>hide me</span>
+    <input readonly><span>hide me</span>
+    <input type=password><span>hide me</span>
+    <input type=password readonly><span>hide me</span>
+    <input type=email><span>hide me</span>
+    <input type=email readonly><span>hide me</span>
+    <textarea></textarea><span>hide me</span>
+    <textarea readonly></textarea><span>hide me</span>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/editor/reftests/readwrite-non-editable-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <style>
+      span {
+        color: transparent; /* workaround for bug 617524 */
+        outline: 1px solid green;
+      }
+    </style>
+  </head>
+  <body>
+    <input>
+    <input readonly><span>hide me</span>
+    <input type=password>
+    <input type=password readonly><span>hide me</span>
+    <input type=email>
+    <input type=email readonly><span>hide me</span>
+    <textarea></textarea>
+    <textarea readonly></textarea><span>hide me</span>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/editor/reftests/readwrite-non-editable.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <style>
+      :-moz-read-write + span {
+        display: none;
+      }
+      span {
+        color: transparent; /* workaround for bug 617524 */
+        outline: 1px solid green;
+      }
+    </style>
+  </head>
+  <body>
+    <input><span>hide me</span>
+    <input readonly><span>hide me</span>
+    <input type=password><span>hide me</span>
+    <input type=password readonly><span>hide me</span>
+    <input type=email><span>hide me</span>
+    <input type=email readonly><span>hide me</span>
+    <textarea></textarea><span>hide me</span>
+    <textarea readonly></textarea><span>hide me</span>
+  </body>
+</html>
--- a/editor/reftests/reftest.list
+++ b/editor/reftests/reftest.list
@@ -67,26 +67,31 @@ needs-focus == caret_after_reframe.html 
 fails-if(Android) != spellcheck-hyphen-invalid.html spellcheck-hyphen-invalid-ref.html
 == spellcheck-slash-valid.html spellcheck-slash-valid-ref.html
 == spellcheck-period-valid.html spellcheck-period-valid-ref.html
 == spellcheck-space-valid.html spellcheck-space-valid-ref.html
 == spellcheck-comma-valid.html spellcheck-comma-valid-ref.html
 == spellcheck-hyphen-multiple-valid.html spellcheck-hyphen-multiple-valid-ref.html
 fails-if(Android) != spellcheck-hyphen-multiple-invalid.html spellcheck-hyphen-multiple-invalid-ref.html
 == spellcheck-dotafterquote-valid.html spellcheck-dotafterquote-valid-ref.html
+== spellcheck-url-valid.html spellcheck-url-valid-ref.html
 == unneeded_scroll.html unneeded_scroll-ref.html
 == caret_on_presshell_reinit.html caret_on_presshell_reinit-ref.html
 == caret_on_presshell_reinit-2.html caret_on_presshell_reinit-ref.html
 == 642800.html 642800-ref.html
 == selection_visibility_after_reframe.html selection_visibility_after_reframe-ref.html
 != selection_visibility_after_reframe-2.html selection_visibility_after_reframe-ref.html
 != selection_visibility_after_reframe-3.html selection_visibility_after_reframe-ref.html
 == 672709.html 672709-ref.html
 == 338427-1.html 338427-1-ref.html
 skip-if(Android) == 674212-spellcheck.html 674212-spellcheck-ref.html
 skip-if(Android) == 338427-2.html 338427-2-ref.html
 skip-if(Android) needs-focus == 338427-3.html 338427-3-ref.html
 skip-if(Android) == 462758-grabbers-resizers.html 462758-grabbers-resizers-ref.html
+== readwrite-non-editable.html readwrite-non-editable-ref.html
+== readwrite-editable.html readwrite-editable-ref.html
+== readonly-non-editable.html readonly-non-editable-ref.html
+== readonly-editable.html readonly-editable-ref.html
 == dynamic-overflow-change.html dynamic-overflow-change-ref.html
 == 694880-1.html 694880-ref.html
 == 694880-2.html 694880-ref.html
 == 694880-3.html 694880-ref.html
 == 388980-1.html 388980-1-ref.html
new file mode 100644
--- /dev/null
+++ b/editor/reftests/spellcheck-url-valid-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <textarea autofocus rows=10 cols=60 spellcheck=false>
+http://fooi.barj/bazk
+https://fooi.barj/bazk
+news://fooi.barj/bazk
+ftp://fooi.barj/bazk
+data:fooi/barj,bazk
+javascript:fooi.barj.bazk();
+fooi@barj.bazk
+</textarea>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/editor/reftests/spellcheck-url-valid.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <textarea autofocus rows=10 cols=60>
+http://fooi.barj/bazk
+https://fooi.barj/bazk
+news://fooi.barj/bazk
+ftp://fooi.barj/bazk
+data:fooi/barj,bazk
+javascript:fooi.barj.bazk();
+fooi@barj.bazk
+</textarea>
+  </body>
+</html>
--- a/embedding/browser/webBrowser/nsWebBrowser.cpp
+++ b/embedding/browser/webBrowser/nsWebBrowser.cpp
@@ -55,17 +55,16 @@
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsPIDOMWindow.h"
 #include "nsIWebProgress.h"
 #include "nsIWebProgressListener.h"
 #include "nsIWebBrowserFocus.h"
 #include "nsIWebBrowserStream.h"
 #include "nsIPresShell.h"
-#include "nsIGlobalHistory.h"
 #include "nsIDocShellHistory.h"
 #include "nsIURIContentListener.h"
 #include "nsGUIEvent.h"
 #include "nsISHistoryListener.h"
 #include "nsIURI.h"
 #include "nsIWebBrowserPersist.h"
 #include "nsCWebBrowserPersist.h"
 #include "nsIServiceManager.h"
--- a/extensions/spellcheck/src/mozInlineSpellWordUtil.cpp
+++ b/extensions/spellcheck/src/mozInlineSpellWordUtil.cpp
@@ -967,16 +967,17 @@ WordSplitState::FindSpecialWord()
   if (firstColon > mDOMWordOffset) {
     nsString protocol(Substring(mDOMWordText, mDOMWordOffset,
                       firstColon - mDOMWordOffset));
     if (protocol.EqualsIgnoreCase("http") ||
         protocol.EqualsIgnoreCase("https") ||
         protocol.EqualsIgnoreCase("news") ||
         protocol.EqualsIgnoreCase("file") ||
         protocol.EqualsIgnoreCase("javascript") ||
+        protocol.EqualsIgnoreCase("data") ||
         protocol.EqualsIgnoreCase("ftp")) {
       return mDOMWordText.Length() - mDOMWordOffset;
     }
   }
 
   // not anything special
   return -1;
 }
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -799,16 +799,18 @@ protected:
   bool mTransformDirty : 1;
 
   SurfaceFormat mFormat;
 };
 
 class GFX2D_API Factory
 {
 public:
+  static bool HasSSE2();
+
   static TemporaryRef<DrawTarget> CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface);
 
   static TemporaryRef<DrawTarget>
     CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat);
   
   static TemporaryRef<DrawTarget>
     CreateDrawTargetForData(BackendType aBackend, unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat);
 
--- a/gfx/2d/BaseRect.h
+++ b/gfx/2d/BaseRect.h
@@ -410,16 +410,26 @@ struct BaseRect {
     T right = static_cast<T>(ceil(double(XMost()) / aXScale));
     T bottom = static_cast<T>(ceil(double(YMost()) / aYScale));
     x = static_cast<T>(floor(double(x) / aXScale));
     y = static_cast<T>(floor(double(y) / aYScale));
     width = right - x;
     height = bottom - y;
   }
 
+  /**
+   * Clamp aPoint to this rectangle. It is allowed to end up on any
+   * edge of the rectangle.
+   */
+  Point ClampPoint(const Point& aPoint) const
+  {
+    return Point(NS_MAX(x, NS_MIN(XMost(), aPoint.x)),
+                 NS_MAX(y, NS_MIN(YMost(), aPoint.y)));
+  }
+
 private:
   // Do not use the default operator== or operator!= !
   // Use IsEqualEdges or IsEqualInterior explicitly.
   bool operator==(const Sub& aRect) const { return false; }
   bool operator!=(const Sub& aRect) const { return false; }
 };
 
 }
--- a/gfx/2d/DrawTargetD2D.cpp
+++ b/gfx/2d/DrawTargetD2D.cpp
@@ -37,16 +37,17 @@
 
 #include "DrawTargetD2D.h"
 #include "SourceSurfaceD2D.h"
 #include "SourceSurfaceD2DTarget.h"
 #include "ShadersD2D.h"
 #include "PathD2D.h"
 #include "GradientStopsD2D.h"
 #include "ScaledFontDWrite.h"
+#include "ImageScaling.h"
 #include "Logging.h"
 #include "Tools.h"
 #include <algorithm>
 
 #ifndef M_PI
 #define M_PI 3.14159265358979323846
 #endif
 
@@ -284,17 +285,17 @@ DrawTargetD2D::DrawSurface(SourceSurface
             aSource.height > rt->GetMaximumBitmapSize()) {
           gfxDebug() << "Bitmap source larger than texture size specified. DrawBitmap will silently fail.";
           // Don't know how to deal with this yet.
           return;
         }
 
         int stride = srcSurf->GetSize().width * BytesPerPixel(srcSurf->GetFormat());
 
-        unsigned char *data = &srcSurf->mRawData.front() +
+        unsigned char *data = srcSurf->mRawData +
                               (uint32_t)aSource.y * stride +
                               (uint32_t)aSource.x * BytesPerPixel(srcSurf->GetFormat());
 
         D2D1_BITMAP_PROPERTIES props =
           D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(srcSurf->GetFormat()), AlphaMode(srcSurf->GetFormat())));
         mRT->CreateBitmap(D2D1::SizeU(UINT32(aSource.width), UINT32(aSource.height)), data, stride, props, byRef(bitmap));
 
         srcRect.x -= (uint32_t)aSource.x;
@@ -1977,26 +1978,26 @@ DrawTargetD2D::CreatePartialBitmapForSur
   RefPtr<ID2D1Bitmap> bitmap;
 
   // This is where things get complicated. The source surface was
   // created for a surface that was too large to fit in a texture.
   // We'll need to figure out if we can work with a partial upload
   // or downsample in software.
 
   Matrix transform = mTransform;
-  transform = aMatrix * transform;
-  if (!transform.Invert()) {
+  Matrix invTransform = transform = aMatrix * transform;
+  if (!invTransform.Invert()) {
     // Singular transform, nothing to be drawn.
     return NULL;
   }
 
   Rect rect(0, 0, mSize.width, mSize.height);
 
   // Calculate the rectangle of the source mapped to our surface.
-  rect = transform.TransformBounds(rect);
+  rect = invTransform.TransformBounds(rect);
   rect.RoundOut();
 
   Rect uploadRect(0, 0, aSurface->mSize.width, aSurface->mSize.height);
 
   // Calculate the rectangle on the source bitmap that touches our
   // surface.
   uploadRect = uploadRect.Intersect(rect);
 
@@ -2009,29 +2010,69 @@ DrawTargetD2D::CreatePartialBitmapForSur
   if (uploadRect.width <= mRT->GetMaximumBitmapSize() &&
       uploadRect.height <= mRT->GetMaximumBitmapSize()) {
             
     int Bpp = BytesPerPixel(aSurface->mFormat);
     int stride = Bpp * aSurface->mSize.width;
 
     // A partial upload will suffice.
     mRT->CreateBitmap(D2D1::SizeU(uint32_t(uploadRect.width), uint32_t(uploadRect.height)),
-                      &aSurface->mRawData.front() + int(uploadRect.x) + int(uploadRect.y) * stride,
+                      aSurface->mRawData + int(uploadRect.x) * 4 + int(uploadRect.y) * stride,
                       stride,
                       D2D1::BitmapProperties(D2DPixelFormat(aSurface->mFormat)),
                       byRef(bitmap));
 
-    aMatrix.Translate(-uploadRect.x, -uploadRect.y);
+    aMatrix.Translate(uploadRect.x, uploadRect.y);
 
     return bitmap;
   } else {
-    // XXX - FIX ME!!
-    MOZ_ASSERT(false);
-    gfxDebug() << "Source surface used for pattern too large!";
-    return NULL;
+    int Bpp = BytesPerPixel(aSurface->mFormat);
+
+    if (Bpp != 4) {
+      // This shouldn't actually happen in practice!
+      MOZ_ASSERT(false);
+      return NULL;
+    }
+
+    int stride = Bpp * aSurface->mSize.width;
+
+    ImageHalfScaler scaler(aSurface->mRawData, stride, IntSize(aSurface->mSize));
+
+    // Calculate the maximum width/height of the image post transform.
+    Point topRight = transform * Point(aSurface->mSize.width, 0);
+    Point topLeft = transform * Point(0, 0);
+    Point bottomRight = transform * Point(aSurface->mSize.width, aSurface->mSize.height);
+    Point bottomLeft = transform * Point(0, aSurface->mSize.height);
+    
+    IntSize scaleSize;
+
+    scaleSize.width = max(Distance(topRight, topLeft), Distance(bottomRight, bottomLeft));
+    scaleSize.height = max(Distance(topRight, bottomRight), Distance(topLeft, bottomLeft));
+
+    if (scaleSize.width > mRT->GetMaximumBitmapSize()) {
+      // Ok, in this case we'd really want a downscale of a part of the bitmap,
+      // perhaps we can do this later but for simplicity let's do something
+      // different here and assume it's good enough, this should be rare!
+      scaleSize.width = 4095;
+    }
+    if (scaleSize.height > mRT->GetMaximumBitmapSize()) {
+      scaleSize.height = 4095;
+    }
+
+    scaler.ScaleForSize(scaleSize);
+
+    IntSize newSize = scaler.GetSize();
+    
+    mRT->CreateBitmap(D2D1::SizeU(newSize.width, newSize.height),
+                      scaler.GetScaledData(), scaler.GetStride(),
+                      D2D1::BitmapProperties(D2DPixelFormat(aSurface->mFormat)),
+                      byRef(bitmap));
+
+    aMatrix.Scale(aSurface->mSize.width / newSize.width, aSurface->mSize.height / newSize.height);
+    return bitmap;
   }
 }
 
 void
 DrawTargetD2D::SetupEffectForRadialGradient(const RadialGradientPattern *aPattern)
 {
   mPrivateData->mEffect->GetTechniqueByName("SampleRadialGradient")->GetPassByIndex(0)->Apply(0);
   mPrivateData->mEffect->GetVariableByName("MaskTexCoords")->AsVector()->
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -70,26 +70,123 @@
 #include "DrawTargetDual.h"
 
 #include "Logging.h"
 
 #ifdef PR_LOGGING
 PRLogModuleInfo *sGFX2DLog = PR_NewLogModule("gfx2d");
 #endif
 
+// The following code was largely taken from xpcom/glue/SSE.cpp and
+// made a little simpler.
+enum CPUIDRegister { eax = 0, ebx = 1, ecx = 2, edx = 3 };
+
+#ifdef HAVE_CPUID_H
+
+// cpuid.h is available on gcc 4.3 and higher on i386 and x86_64
+#include <cpuid.h>
+
+static bool
+HasCPUIDBit(unsigned int level, CPUIDRegister reg, unsigned int bit)
+{
+  unsigned int regs[4];
+  return __get_cpuid(level, &regs[0], &regs[1], &regs[2], &regs[3]) &&
+         (regs[reg] & bit);
+}
+
+#define HAVE_CPU_DETECTION
+#else
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400 && (defined(_M_IX86) || defined(_M_AMD64))
+// MSVC 2005 or newer on x86-32 or x86-64
+#include <intrin.h>
+
+#define HAVE_CPU_DETECTION
+#elif defined(__SUNPRO_CC) && (defined(__i386) || defined(__x86_64__))
+
+// Define a function identical to MSVC function.
+#ifdef __i386
+static void
+__cpuid(int CPUInfo[4], int InfoType)
+{
+  asm (
+    "xchg %esi, %ebx\n"
+    "cpuid\n"
+    "movl %eax, (%edi)\n"
+    "movl %ebx, 4(%edi)\n"
+    "movl %ecx, 8(%edi)\n"
+    "movl %edx, 12(%edi)\n"
+    "xchg %esi, %ebx\n"
+    :
+    : "a"(InfoType), // %eax
+      "D"(CPUInfo) // %edi
+    : "%ecx", "%edx", "%esi"
+  );
+}
+#else
+static void
+__cpuid(int CPUInfo[4], int InfoType)
+{
+  asm (
+    "xchg %rsi, %rbx\n"
+    "cpuid\n"
+    "movl %eax, (%rdi)\n"
+    "movl %ebx, 4(%rdi)\n"
+    "movl %ecx, 8(%rdi)\n"
+    "movl %edx, 12(%rdi)\n"
+    "xchg %rsi, %rbx\n"
+    :
+    : "a"(InfoType), // %eax
+      "D"(CPUInfo) // %rdi
+    : "%ecx", "%edx", "%rsi"
+  );
+}
+
+#define HAVE_CPU_DETECTION
+#endif
+#endif
+
+#ifdef HAVE_CPU_DETECTION
+static bool
+HasCPUIDBit(unsigned int level, CPUIDRegister reg, unsigned int bit)
+{
+  // Check that the level in question is supported.
+  volatile int regs[4];
+  __cpuid((int *)regs, level & 0x80000000u);
+  if (unsigned(regs[0]) < level)
+    return false;
+  __cpuid((int *)regs, level);
+  return !!(unsigned(regs[reg]) & bit);
+}
+#endif
+#endif
+
 namespace mozilla {
 namespace gfx {
 
 // XXX - Need to define an API to set this.
 int sGfxLogLevel = LOG_DEBUG;
 
 #ifdef WIN32
 ID3D10Device1 *Factory::mD3D10Device;
 #endif
 
+bool
+Factory::HasSSE2()
+{
+#if defined(HAVE_CPU_DETECTION)
+  return HasCPUIDBit(1u, edx, (1u<<26));
+#elif defined(XP_MACOSX)
+  // Intel macs always have SSE2.
+  return true;
+#else
+  return false;
+#endif
+}
+
 TemporaryRef<DrawTarget>
 Factory::CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat)
 {
   switch (aBackend) {
 #ifdef WIN32
   case BACKEND_DIRECT2D:
     {
       RefPtr<DrawTargetD2D> newTarget;
new file mode 100644
--- /dev/null
+++ b/gfx/2d/ImageScaling.cpp
@@ -0,0 +1,276 @@
+/* -*- Mode: C++; tab-width: 20; 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 Mozilla Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Bas Schouten <bschouten@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 ***** */
+
+#include "ImageScaling.h"
+#include "2D.h"
+
+#include <math.h>
+#include <algorithm>
+
+using namespace std;
+
+namespace mozilla {
+namespace gfx {
+
+inline uint32_t Avg2x2(uint32_t a, uint32_t b, uint32_t c, uint32_t d)
+{
+  // Prepare half-adder work
+  uint32_t sum = a ^ b ^ c;
+  uint32_t carry = (a & b) | (a & c) | (b & c);
+
+  // Before shifting, mask lower order bits of each byte to avoid underflow.
+  uint32_t mask = 0xfefefefe;
+
+  // Add d to sum and divide by 2.
+  sum = (((sum ^ d) & mask) >> 1) + (sum & d);
+
+  // Sum is now shifted into place relative to carry, add them together.
+  return (((sum ^ carry) & mask) >> 1) + (sum & carry);
+}
+
+inline uint32_t Avg2(uint32_t a, uint32_t b)
+{
+  // Prepare half-adder work
+  uint32_t sum = a ^ b;
+  uint32_t carry = (a & b);
+
+  // Before shifting, mask lower order bits of each byte to avoid underflow.
+  uint32_t mask = 0xfefefefe;
+
+  // Add d to sum and divide by 2.
+  return ((sum & mask) >> 1) + carry;
+}
+
+void
+ImageHalfScaler::ScaleForSize(const IntSize &aSize)
+{
+  uint32_t horizontalDownscales = 0;
+  uint32_t verticalDownscales = 0;
+
+  IntSize scaleSize = mOrigSize;
+  while ((scaleSize.height / 2) > aSize.height) {
+    verticalDownscales++;
+    scaleSize.height /= 2;
+  }
+
+  while ((scaleSize.width / 2) > aSize.width) {
+    horizontalDownscales++;
+    scaleSize.width /= 2;
+  }
+
+  if (scaleSize == mOrigSize) {
+    return;
+  }
+
+  IntSize internalSurfSize;
+
+  internalSurfSize.width = max(scaleSize.width, mOrigSize.width / 2);
+  internalSurfSize.height = max(scaleSize.height, mOrigSize.height / 2);
+
+  mStride = internalSurfSize.width * 4;
+  if (mStride % 16) {
+    mStride += 16 - (mStride % 16);
+  }
+
+  delete [] mDataStorage;
+  // Allocate 15 bytes extra to make sure we can get 16 byte alignment. We
+  // should add tools for this, see bug 751696.
+  mDataStorage = new uint8_t[internalSurfSize.height * mStride + 15];
+
+  if (uintptr_t(mDataStorage) % 16) {
+    // Our storage does not start at a 16-byte boundary. Make sure mData does!
+    mData = (uint8_t*)(uintptr_t(mDataStorage) +
+      (16 - (uintptr_t(mDataStorage) % 16)));
+  } else {
+    mData = mDataStorage;
+  }
+
+  mSize = scaleSize;
+
+  /* The surface we sample from might not be even sized, if it's not we will
+   * ignore the last row/column. This means we lose some data but it keeps the
+   * code very simple. There's also no perfect answer that provides a better
+   * solution.
+   */
+  IntSize currentSampledSize = mOrigSize;
+  uint32_t currentSampledStride = mOrigStride;
+  uint8_t *currentSampledData = mOrigData;
+  
+  while (verticalDownscales && horizontalDownscales) {
+    if (currentSampledSize.width % 2) {
+      currentSampledSize.width -= 1;
+    }
+    if (currentSampledSize.height % 2) {
+      currentSampledSize.height -= 1;
+    }
+
+    HalfImage2D(currentSampledData, currentSampledStride, currentSampledSize,
+                mData, mStride);
+
+    verticalDownscales--;
+    horizontalDownscales--;
+    currentSampledSize.width /= 2;
+    currentSampledSize.height /= 2;
+    currentSampledData = mData;
+    currentSampledStride = mStride;
+  }
+
+  while (verticalDownscales) {
+    if (currentSampledSize.height % 2) {
+      currentSampledSize.height -= 1;
+    }
+
+    HalfImageVertical(currentSampledData, currentSampledStride, currentSampledSize,
+                      mData, mStride);
+
+    verticalDownscales--;
+    currentSampledSize.height /= 2;
+    currentSampledData = mData;
+    currentSampledStride = mStride;
+  }
+
+
+  while (horizontalDownscales) {
+    if (currentSampledSize.width % 2) {
+      currentSampledSize.width -= 1;
+    }
+
+    HalfImageHorizontal(currentSampledData, currentSampledStride, currentSampledSize,
+                        mData, mStride);
+
+    horizontalDownscales--;
+    currentSampledSize.width /= 2;
+    currentSampledData = mData;
+    currentSampledStride = mStride;
+  }
+}
+
+void
+ImageHalfScaler::HalfImage2D(uint8_t *aSource, int32_t aSourceStride,
+                             const IntSize &aSourceSize, uint8_t *aDest,
+                             uint32_t aDestStride)
+{
+#ifdef USE_SSE2
+  if (Factory::HasSSE2()) {
+    HalfImage2D_SSE2(aSource, aSourceStride, aSourceSize, aDest, aDestStride);
+  } else
+#endif
+  {
+    HalfImage2D_C(aSource, aSourceStride, aSourceSize, aDest, aDestStride);
+  }
+}
+
+void
+ImageHalfScaler::HalfImageVertical(uint8_t *aSource, int32_t aSourceStride,
+                                   const IntSize &aSourceSize, uint8_t *aDest,
+                                   uint32_t aDestStride)
+{
+#ifdef USE_SSE2
+  if (Factory::HasSSE2()) {
+    HalfImageVertical_SSE2(aSource, aSourceStride, aSourceSize, aDest, aDestStride);
+  } else
+#endif
+  {
+    HalfImageVertical_C(aSource, aSourceStride, aSourceSize, aDest, aDestStride);
+  }
+}
+
+void
+ImageHalfScaler::HalfImageHorizontal(uint8_t *aSource, int32_t aSourceStride,
+                                     const IntSize &aSourceSize, uint8_t *aDest,
+                                     uint32_t aDestStride)
+{
+#ifdef USE_SSE2
+  if (Factory::HasSSE2()) {
+    HalfImageHorizontal_SSE2(aSource, aSourceStride, aSourceSize, aDest, aDestStride);
+  } else
+#endif
+  {
+    HalfImageHorizontal_C(aSource, aSourceStride, aSourceSize, aDest, aDestStride);
+  }
+}
+
+void
+ImageHalfScaler::HalfImage2D_C(uint8_t *aSource, int32_t aSourceStride,
+                               const IntSize &aSourceSize, uint8_t *aDest,
+                               uint32_t aDestStride)
+{
+  for (int y = 0; y < aSourceSize.height; y += 2) {
+    uint32_t *storage = (uint32_t*)(aDest + (y / 2) * aDestStride);
+    for (int x = 0; x < aSourceSize.width; x += 2) {
+      uint8_t *upperRow = aSource + (y * aSourceStride + x * 4);
+      uint8_t *lowerRow = aSource + ((y + 1) * aSourceStride + x * 4);
+
+      *storage++ = Avg2x2(*(uint32_t*)upperRow, *((uint32_t*)upperRow + 1),
+                          *(uint32_t*)lowerRow, *((uint32_t*)lowerRow + 1));
+    }
+  }
+}
+
+void
+ImageHalfScaler::HalfImageVertical_C(uint8_t *aSource, int32_t aSourceStride,
+                                     const IntSize &aSourceSize, uint8_t *aDest,
+                                     uint32_t aDestStride)
+{
+  for (int y = 0; y < aSourceSize.height; y += 2) {
+    uint32_t *storage = (uint32_t*)(aDest + (y / 2) * aDestStride);
+    for (int x = 0; x < aSourceSize.width; x++) {
+      uint32_t *upperRow = (uint32_t*)(aSource + (y * aSourceStride + x * 4));
+      uint32_t *lowerRow = (uint32_t*)(aSource + ((y + 1) * aSourceStride + x * 4));
+
+      *storage++ = Avg2(*upperRow, *lowerRow);
+    }
+  }
+}
+
+void
+ImageHalfScaler::HalfImageHorizontal_C(uint8_t *aSource, int32_t aSourceStride,
+                                       const IntSize &aSourceSize, uint8_t *aDest,
+                                       uint32_t aDestStride)
+{
+  for (int y = 0; y < aSourceSize.height; y++) {
+    uint32_t *storage = (uint32_t*)(aDest + y * aDestStride);
+    for (int x = 0; x < aSourceSize.width;  x+= 2) {
+      uint32_t *pixels = (uint32_t*)(aSource + (y * aSourceStride + x * 4));
+
+      *storage++ = Avg2(*pixels, *(pixels + 1));
+    }
+  }
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/gfx/2d/ImageScaling.h
@@ -0,0 +1,108 @@
+/* -*- Mode: C++; tab-width: 20; 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 Mozilla Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Bas Schouten <bschouten@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 ***** */
+
+#ifndef _MOZILLA_GFX_IMAGESCALING_H
+#define _MOZILLA_GFX_IMAGESCALING_H
+
+#include "Types.h"
+
+#include <vector>
+#include "Point.h"
+
+namespace mozilla {
+namespace gfx {
+
+class ImageHalfScaler
+{
+public:
+  ImageHalfScaler(uint8_t *aData, int32_t aStride, const IntSize &aSize)
+    : mOrigData(aData), mOrigStride(aStride), mOrigSize(aSize)
+    , mDataStorage(NULL)
+  {
+  }
+
+  ~ImageHalfScaler()
+  {
+    delete [] mDataStorage;
+  }
+
+  void ScaleForSize(const IntSize &aSize);
+
+  uint8_t *GetScaledData() const { return mData; }
+  IntSize GetSize() const { return mSize; }
+  uint32_t GetStride() const { return mStride; }
+
+private:
+  void HalfImage2D(uint8_t *aSource, int32_t aSourceStride, const IntSize &aSourceSize,
+                   uint8_t *aDest, uint32_t aDestStride);
+  void HalfImageVertical(uint8_t *aSource, int32_t aSourceStride, const IntSize &aSourceSize,
+                         uint8_t *aDest, uint32_t aDestStride);
+  void HalfImageHorizontal(uint8_t *aSource, int32_t aSourceStride, const IntSize &aSourceSize,
+                           uint8_t *aDest, uint32_t aDestStride);
+
+  // This is our SSE2 scaling function. Our destination must always be 16-byte
+  // aligned and use a 16-byte aligned stride.
+  void HalfImage2D_SSE2(uint8_t *aSource, int32_t aSourceStride, const IntSize &aSourceSize,
+                        uint8_t *aDest, uint32_t aDestStride);
+  void HalfImageVertical_SSE2(uint8_t *aSource, int32_t aSourceStride, const IntSize &aSourceSize,
+                              uint8_t *aDest, uint32_t aDestStride);
+  void HalfImageHorizontal_SSE2(uint8_t *aSource, int32_t aSourceStride, const IntSize &aSourceSize,
+                                uint8_t *aDest, uint32_t aDestStride);
+
+  void HalfImage2D_C(uint8_t *aSource, int32_t aSourceStride, const IntSize &aSourceSize,
+                     uint8_t *aDest, uint32_t aDestStride);
+  void HalfImageVertical_C(uint8_t *aSource, int32_t aSourceStride, const IntSize &aSourceSize,
+                           uint8_t *aDest, uint32_t aDestStride);
+  void HalfImageHorizontal_C(uint8_t *aSource, int32_t aSourceStride, const IntSize &aSourceSize,
+                             uint8_t *aDest, uint32_t aDestStride);
+
+  uint8_t *mOrigData;
+  int32_t mOrigStride;
+  IntSize mOrigSize;
+
+  uint8_t *mDataStorage;
+  // Guaranteed 16-byte aligned
+  uint8_t *mData;
+  IntSize mSize;
+  // Guaranteed 16-byte aligned
+  uint32_t mStride;
+};
+
+}
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/2d/ImageScalingSSE2.cpp
@@ -0,0 +1,379 @@
+/* -*- Mode: C++; tab-width: 20; 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 Mozilla Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Bas Schouten <bschouten@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 ***** */
+
+#include "ImageScaling.h"
+#include "mozilla/Attributes.h"
+
+#include <xmmintrin.h>
+
+/* The functions below use the following system for averaging 4 pixels:
+ *
+ * The first observation is that a half-adder is implemented as follows:
+ * R = S + 2C or in the case of a and b (a ^ b) + ((a & b) << 1);
+ *
+ * This can be trivially extended to three pixels by observaring that when
+ * doing (a ^ b ^ c) as the sum, the carry is simply the bitwise-or of the
+ * carries of the individual numbers, since the sum of 3 bits can only ever
+ * have a carry of one.
+ *
+ * We then observe that the average is then ((carry << 1) + sum) >> 1, or,
+ * assuming eliminating overflows and underflows, carry + (sum >> 1).
+ *
+ * We now average our existing sum with the fourth number, so we get:
+ * sum2 = (sum + d) >> 1 or (sum >> 1) + (d >> 1).
+ *
+ * We now observe that our sum has been moved into place relative to the
+ * carry, so we can now average with the carry to get the final 4 input
+ * average: avg = (sum2 + carry) >> 1;
+ *
+ * Or to reverse the proof:
+ * avg = ((sum >> 1) + carry + d >> 1) >> 1
+ * avg = ((a + b + c) >> 1 + d >> 1) >> 1
+ * avg = ((a + b + c + d) >> 2)
+ *
+ * An additional fact used in the SSE versions is the concept that we can
+ * trivially convert a rounded average to a truncated average:
+ *
+ * We have:
+ * f(a, b) = (a + b + 1) >> 1
+ *
+ * And want:
+ * g(a, b) = (a + b) >> 1
+ *
+ * Observe:
+ * ~f(~a, ~b) == ~((~a + ~b + 1) >> 1)
+ *            == ~((-a - 1 + -b - 1 + 1) >> 1)
+ *            == ~((-a - 1 + -b) >> 1)
+ *            == ~((-(a + b) - 1) >> 1)
+ *            == ~((~(a + b)) >> 1)
+ *            == (a + b) >> 1
+ *            == g(a, b)
+ */
+
+MOZ_ALWAYS_INLINE __m128i _mm_not_si128(__m128i arg)
+{
+  __m128i minusone = _mm_set1_epi32(0xffffffff);
+  return _mm_xor_si128(arg, minusone);
+}
+
+/* We have to pass pointers here, MSVC does not allow passing more than 3
+ * __m128i arguments on the stack. And it does not allow 16-byte aligned
+ * stack variables. This inlines properly on MSVC 2010. It does -not- inline
+ * with just the inline directive.
+ */
+MOZ_ALWAYS_INLINE __m128i avg_sse2_8x2(__m128i *a, __m128i *b, __m128i *c, __m128i *d)
+{
+#define shuf1 _MM_SHUFFLE(2, 0, 2, 0)
+#define shuf2 _MM_SHUFFLE(3, 1, 3, 1)
+
+// This cannot be an inline function as the __Imm argument to _mm_shuffle_ps
+// needs to be a compile time constant.
+#define shuffle_si128(arga, argb, imm) \
+  _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps((arga)), _mm_castsi128_ps((argb)), (imm)));
+
+  __m128i t = shuffle_si128(*a, *b, shuf1);
+  *b = shuffle_si128(*a, *b, shuf2);
+  *a = t;
+  t = shuffle_si128(*c, *d, shuf1);
+  *d = shuffle_si128(*c, *d, shuf2);
+  *c = t;
+
+#undef shuf1
+#undef shuf2
+#undef shuffle_si128
+
+  __m128i sum = _mm_xor_si128(*a, _mm_xor_si128(*b, *c));
+
+  __m128i carry = _mm_or_si128(_mm_and_si128(*a, *b), _mm_or_si128(_mm_and_si128(*a, *c), _mm_and_si128(*b, *c)));
+
+  __m128i minusone = _mm_set1_epi32(0xffffffff);
+
+  sum = _mm_avg_epu8(_mm_not_si128(sum), _mm_not_si128(*d));
+
+  return _mm_not_si128(_mm_avg_epu8(sum, _mm_not_si128(carry)));
+}
+
+MOZ_ALWAYS_INLINE __m128i avg_sse2_4x2_4x1(__m128i a, __m128i b)
+{
+  __m128i minusone = _mm_set1_epi32(0xffffffff);
+
+  return _mm_not_si128(_mm_avg_epu8(_mm_not_si128(a), _mm_not_si128(b)));
+}
+
+MOZ_ALWAYS_INLINE __m128i avg_sse2_8x1_4x1(__m128i a, __m128i b)
+{
+  __m128i t = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(b), _mm_castsi128_ps(a), _MM_SHUFFLE(3, 1, 3, 1)));
+  b = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(b), _mm_castsi128_ps(a), _MM_SHUFFLE(2, 0, 2, 0)));
+  a = t;
+
+  __m128i minusone = _mm_set1_epi32(0xffffffff);
+
+  return _mm_not_si128(_mm_avg_epu8(_mm_not_si128(a), _mm_not_si128(b)));
+}
+
+/* Before Nehalem _mm_loadu_si128 could be very slow, this trick is a little
+ * faster. Once enough people are on architectures where _mm_loadu_si128 is
+ * fast we can migrate to it.
+ */
+MOZ_ALWAYS_INLINE __m128i loadUnaligned128(const __m128i *aSource)
+{
+  // Yes! We use uninitialized memory here, we'll overwrite it though!
+  __m128 res = _mm_loadl_pi(_mm_set1_ps(0), (const __m64*)aSource);
+  return _mm_castps_si128(_mm_loadh_pi(res, ((const __m64*)(aSource)) + 1));
+}
+
+MOZ_ALWAYS_INLINE uint32_t Avg2x2(uint32_t a, uint32_t b, uint32_t c, uint32_t d)
+{
+  uint32_t sum = a ^ b ^ c;
+  uint32_t carry = (a & b) | (a & c) | (b & c);
+
+  uint32_t mask = 0xfefefefe;
+
+  // Not having a byte based average instruction means we should mask to avoid
+  // underflow.
+  sum = (((sum ^ d) & mask) >> 1) + (sum & d);
+
+  return (((sum ^ carry) & mask) >> 1) + (sum & carry);
+}
+
+// Simple 2 pixel average version of the function above.
+MOZ_ALWAYS_INLINE uint32_t Avg2(uint32_t a, uint32_t b)
+{
+  uint32_t sum = a ^ b;
+  uint32_t carry = (a & b);
+
+  uint32_t mask = 0xfefefefe;
+
+  return ((sum & mask) >> 1) + carry;
+}
+
+namespace mozilla {
+namespace gfx {
+
+void
+ImageHalfScaler::HalfImage2D_SSE2(uint8_t *aSource, int32_t aSourceStride,
+                                  const IntSize &aSourceSize, uint8_t *aDest,
+                                  uint32_t aDestStride)
+{
+  const int Bpp = 4;
+
+  for (int y = 0; y < aSourceSize.height; y += 2) {
+    __m128i *storage = (__m128i*)(aDest + (y / 2) * aDestStride);
+    int x = 0;
+    // Run a loop depending on alignment.
+    if (!(uintptr_t(aSource + (y * aSourceStride)) % 16) &&
+        !(uintptr_t(aSource + ((y + 1) * aSourceStride)) % 16)) {
+      for (; x < (aSourceSize.width - 7); x += 8) {
+        __m128i *upperRow = (__m128i*)(aSource + (y * aSourceStride + x * Bpp));
+        __m128i *lowerRow = (__m128i*)(aSource + ((y + 1) * aSourceStride + x * Bpp));
+
+        __m128i a = _mm_load_si128(upperRow);
+        __m128i b = _mm_load_si128(upperRow + 1);
+        __m128i c = _mm_load_si128(lowerRow);
+        __m128i d = _mm_load_si128(lowerRow + 1);
+
+        *storage++ = avg_sse2_8x2(&a, &b, &c, &d);
+      }
+    } else if (!(uintptr_t(aSource + (y * aSourceStride)) % 16)) {
+      for (; x < (aSourceSize.width - 7); x += 8) {
+        __m128i *upperRow = (__m128i*)(aSource + (y * aSourceStride + x * Bpp));
+        __m128i *lowerRow = (__m128i*)(aSource + ((y + 1) * aSourceStride + x * Bpp));
+
+        __m128i a = _mm_load_si128(upperRow);
+        __m128i b = _mm_load_si128(upperRow + 1);
+        __m128i c = loadUnaligned128(lowerRow);
+        __m128i d = loadUnaligned128(lowerRow + 1);
+
+        *storage++ = avg_sse2_8x2(&a, &b, &c, &d);
+      }
+    } else if (!(uintptr_t(aSource + ((y + 1) * aSourceStride)) % 16)) {
+      for (; x < (aSourceSize.width - 7); x += 8) {
+        __m128i *upperRow = (__m128i*)(aSource + (y * aSourceStride + x * Bpp));
+        __m128i *lowerRow = (__m128i*)(aSource + ((y + 1) * aSourceStride + x * Bpp));
+
+        __m128i a = loadUnaligned128((__m128i*)upperRow);
+        __m128i b = loadUnaligned128((__m128i*)upperRow + 1);
+        __m128i c = _mm_load_si128((__m128i*)lowerRow);
+        __m128i d = _mm_load_si128((__m128i*)lowerRow + 1);
+
+        *storage++ = avg_sse2_8x2(&a, &b, &c, &d);
+      }
+    } else {
+      for (; x < (aSourceSize.width - 7); x += 8) {
+        __m128i *upperRow = (__m128i*)(aSource + (y * aSourceStride + x * Bpp));
+        __m128i *lowerRow = (__m128i*)(aSource + ((y + 1) * aSourceStride + x * Bpp));
+
+        __m128i a = loadUnaligned128(upperRow);
+        __m128i b = loadUnaligned128(upperRow + 1);
+        __m128i c = loadUnaligned128(lowerRow);
+        __m128i d = loadUnaligned128(lowerRow + 1);
+
+        *storage++ = avg_sse2_8x2(&a, &b, &c, &d);
+      }
+    }
+
+    uint32_t *unalignedStorage = (uint32_t*)storage;
+    // Take care of the final pixels, we know there's an even number of pixels
+    // in the source rectangle. We use a 2x2 'simd' implementation for this.
+    //
+    // Potentially we only have to do this in the last row since overflowing 
+    // 8 pixels in an earlier row would appear to be harmless as it doesn't
+    // touch invalid memory. Even when reading and writing to the same surface.
+    // in practice we only do this when doing an additional downscale pass, and
+    // in this situation we have unused stride to write into harmlessly.
+    // I do not believe the additional code complexity would be worth it though.
+    for (; x < aSourceSize.width; x += 2) {
+      uint8_t *upperRow = aSource + (y * aSourceStride + x * Bpp);
+      uint8_t *lowerRow = aSource + ((y + 1) * aSourceStride + x * Bpp);
+
+      *unalignedStorage++ = Avg2x2(*(uint32_t*)upperRow, *((uint32_t*)upperRow + 1),
+                                   *(uint32_t*)lowerRow, *((uint32_t*)lowerRow + 1));
+    }
+  }
+}
+
+void
+ImageHalfScaler::HalfImageVertical_SSE2(uint8_t *aSource, int32_t aSourceStride,
+                                        const IntSize &aSourceSize, uint8_t *aDest,
+                                        uint32_t aDestStride)
+{
+  for (int y = 0; y < aSourceSize.height; y += 2) {
+    __m128i *storage = (__m128i*)(aDest + (y / 2) * aDestStride);
+    int x = 0;
+    // Run a loop depending on alignment.
+    if (!(uintptr_t(aSource + (y * aSourceStride)) % 16) &&
+        !(uintptr_t(aSource + ((y + 1) * aSourceStride)) % 16)) {
+      for (; x < (aSourceSize.width - 3); x += 4) {
+        uint8_t *upperRow = aSource + (y * aSourceStride + x * 4);
+        uint8_t *lowerRow = aSource + ((y + 1) * aSourceStride + x * 4);
+
+        __m128i a = _mm_load_si128((__m128i*)upperRow);
+        __m128i b = _mm_load_si128((__m128i*)lowerRow);
+
+        *storage++ = avg_sse2_4x2_4x1(a, b);
+      }
+    } else if (!(uintptr_t(aSource + (y * aSourceStride)) % 16)) {
+      // This line doesn't align well.
+      for (; x < (aSourceSize.width - 3); x += 4) {
+        uint8_t *upperRow = aSource + (y * aSourceStride + x * 4);
+        uint8_t *lowerRow = aSource + ((y + 1) * aSourceStride + x * 4);
+
+        __m128i a = _mm_load_si128((__m128i*)upperRow);
+        __m128i b = loadUnaligned128((__m128i*)lowerRow);
+
+        *storage++ = avg_sse2_4x2_4x1(a, b);
+      }
+    } else if (!(uintptr_t(aSource + (y * aSourceStride)) % 16)) {
+      for (; x < (aSourceSize.width - 3); x += 4) {
+        uint8_t *upperRow = aSource + (y * aSourceStride + x * 4);
+        uint8_t *lowerRow = aSource + ((y + 1) * aSourceStride + x * 4);
+
+        __m128i a = loadUnaligned128((__m128i*)upperRow);
+        __m128i b = _mm_load_si128((__m128i*)lowerRow);
+
+        *storage++ = avg_sse2_4x2_4x1(a, b);
+      }
+    } else {
+      for (; x < (aSourceSize.width - 3); x += 4) {
+        uint8_t *upperRow = aSource + (y * aSourceStride + x * 4);
+        uint8_t *lowerRow = aSource + ((y + 1) * aSourceStride + x * 4);
+
+        __m128i a = loadUnaligned128((__m128i*)upperRow);
+        __m128i b = loadUnaligned128((__m128i*)lowerRow);
+
+        *storage++ = avg_sse2_4x2_4x1(a, b);
+      }
+    }
+
+    uint32_t *unalignedStorage = (uint32_t*)storage;
+    // Take care of the final pixels, we know there's an even number of pixels
+    // in the source rectangle.
+    //
+    // Similar overflow considerations are valid as in the previous function.
+    for (; x < aSourceSize.width; x++) {
+      uint8_t *upperRow = aSource + (y * aSourceStride + x * 4);
+      uint8_t *lowerRow = aSource + ((y + 1) * aSourceStride + x * 4);
+
+      *unalignedStorage++ = Avg2(*(uint32_t*)upperRow, *(uint32_t*)lowerRow);
+    }
+  }
+}
+
+void
+ImageHalfScaler::HalfImageHorizontal_SSE2(uint8_t *aSource, int32_t aSourceStride,
+                                          const IntSize &aSourceSize, uint8_t *aDest,
+                                          uint32_t aDestStride)
+{
+  for (int y = 0; y < aSourceSize.height; y++) {
+    __m128i *storage = (__m128i*)(aDest + (y * aDestStride));
+    int x = 0;
+    // Run a loop depending on alignment.
+    if (!(uintptr_t(aSource + (y * aSourceStride)) % 16)) {
+      for (; x < (aSourceSize.width - 7); x += 8) {
+        __m128i* pixels = (__m128i*)(aSource + (y * aSourceStride + x * 4));
+
+        __m128i a = _mm_load_si128(pixels);
+        __m128i b = _mm_load_si128(pixels + 1);
+
+        *storage++ = avg_sse2_8x1_4x1(a, b);
+      }
+    } else {
+      for (; x < (aSourceSize.width - 7); x += 8) {
+        __m128i* pixels = (__m128i*)(aSource + (y * aSourceStride + x * 4));
+
+        __m128i a = loadUnaligned128(pixels);
+        __m128i b = loadUnaligned128(pixels + 1);
+
+        *storage++ = avg_sse2_8x1_4x1(a, b);
+      }
+    }
+
+    uint32_t *unalignedStorage = (uint32_t*)storage;
+    // Take care of the final pixels, we know there's an even number of pixels
+    // in the source rectangle.
+    //
+    // Similar overflow considerations are valid as in the previous function.
+    for (; x < aSourceSize.width; x += 2) {
+      uint32_t *pixels = (uint32_t*)(aSource + (y * aSourceStride + x * 4));
+
+      *unalignedStorage++ = Avg2(*pixels, *(pixels + 1));
+    }
+  }
+}
+
+}
+}
--- a/gfx/2d/Makefile.in
+++ b/gfx/2d/Makefile.in
@@ -69,16 +69,17 @@ CPPSRCS	= \
 	Factory.cpp \
         Matrix.cpp \
         DrawTargetCairo.cpp \
         SourceSurfaceCairo.cpp \
         PathCairo.cpp \
         Blur.cpp \
         ScaledFontBase.cpp \
         DrawTargetDual.cpp \
+        ImageScaling.cpp \
         $(NULL)
 
 ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 CPPSRCS	+= \
 	   SourceSurfaceCG.cpp \
 	   DrawTargetCG.cpp \
 	   PathCG.cpp \
 	   $(NULL)
@@ -112,16 +113,22 @@ DEFINES += -DSK_BUILD_FOR_ANDROID_NDK
 endif
 
 DEFINES += -DSK_A32_SHIFT=24 -DSK_R32_SHIFT=16 -DSK_G32_SHIFT=8 -DSK_B32_SHIFT=0
 
 ifdef MOZ_DEBUG
 DEFINES += -DGFX_LOG_DEBUG -DGFX_LOG_WARNING
 endif
 
+# Are we targeting x86 or x64?  If so, build SSE2 files.
+ifneq (,$(INTEL_ARCHITECTURE))
+CPPSRCS += ImageScalingSSE2.cpp
+DEFINES += -DUSE_SSE2
+endif
+
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 CPPSRCS	+= \
         DrawTargetD2D.cpp \
         SourceSurfaceD2D.cpp \
         SourceSurfaceD2DTarget.cpp \
         PathD2D.cpp \
         ScaledFontDWrite.cpp \
         $(NULL)
@@ -129,21 +136,33 @@ DEFINES += -DWIN32 -DINITGUID
 
 ifdef MOZ_ENABLE_SKIA
 CPPSRCS += \
         ScaledFontWin.cpp \
         $(NULL)
 endif
 endif
 
+include $(topsrcdir)/config/rules.mk
+
 #ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 #CPPSRCS	+= \
 #        DrawTargetCG.cpp \
 #        SourceSurfaceCG.cpp \
 #	$(NULL)
 #
 ## Always link with OpenGL/AGL
 #EXTRA_DSO_LDOPTS += -framework OpenGL -framework AGL -framework QuickTime -framework AppKit -framework QuartzCore
 #endif
 
-include $(topsrcdir)/config/rules.mk
+# The file uses SSE2 intrinsics, so it needs special compile flags on some
+# compilers.
+ifneq (,$(INTEL_ARCHITECTURE))
+ifdef GNU_CC
+ImageScalingSSE2.$(OBJ_SUFFIX): CXXFLAGS+=-msse2
+endif
+
+ifdef SOLARIS_SUNPRO_CXX
+ImageScalingSSE2.$(OBJ_SUFFIX): OS_CXXFLAGS += -xarch=sse2 -xO4
+endif
+endif
 
 CXXFLAGS += $(MOZ_CAIRO_CFLAGS)
--- a/gfx/2d/SourceSurfaceD2D.cpp
+++ b/gfx/2d/SourceSurfaceD2D.cpp
@@ -37,21 +37,23 @@
 
 #include "SourceSurfaceD2D.h"
 #include "Logging.h"
 
 namespace mozilla {
 namespace gfx {
 
 SourceSurfaceD2D::SourceSurfaceD2D()
+  : mRawData(NULL)
 {
 }
 
 SourceSurfaceD2D::~SourceSurfaceD2D()
 {
+  delete [] mRawData;
 }
 
 IntSize
 SourceSurfaceD2D::GetSize() const
 {
   return mSize;
 }
 
@@ -77,19 +79,21 @@ SourceSurfaceD2D::InitFromData(unsigned 
   HRESULT hr;
 
   mFormat = aFormat;
   mSize = aSize;
 
   if ((uint32_t)aSize.width > aRT->GetMaximumBitmapSize() ||
       (uint32_t)aSize.height > aRT->GetMaximumBitmapSize()) {
     int newStride = BytesPerPixel(aFormat) * aSize.width;
-    mRawData.resize(aSize.height * newStride);
+    // This should only be called once!
+    MOZ_ASSERT(!mRawData);
+    mRawData = new uint8_t[aSize.height * newStride];
     for (int y = 0; y < aSize.height; y++) {
-      memcpy(&mRawData.front() + y * newStride, aData + y * aStride, newStride);
+      memcpy(mRawData + y * newStride, aData + y * aStride, newStride);
     }
     gfxDebug() << "Bitmap does not fit in texture, saving raw data.";
     return true;
   }
 
   D2D1_BITMAP_PROPERTIES props =
     D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(aFormat), AlphaMode(aFormat)));
   hr = aRT->CreateBitmap(D2DIntSize(aSize), aData, aStride, props, byRef(mBitmap));
--- a/gfx/2d/SourceSurfaceD2D.h
+++ b/gfx/2d/SourceSurfaceD2D.h
@@ -66,17 +66,17 @@ public:
   bool InitFromTexture(ID3D10Texture2D *aTexture,
                        SurfaceFormat aFormat,
                        ID2D1RenderTarget *aRT);
 
 private:
   friend class DrawTargetD2D;
 
   RefPtr<ID2D1Bitmap> mBitmap;
-  std::vector<unsigned char> mRawData;
+  uint8_t *mRawData;
   SurfaceFormat mFormat;
   IntSize mSize;
 };
 
 }
 }
 
 #endif /* MOZILLA_GFX_SOURCESURFACED2D_H_ */
--- a/gfx/2d/Tools.h
+++ b/gfx/2d/Tools.h
@@ -61,12 +61,27 @@ template <class T>
 struct ClassStorage
 {
   char bytes[sizeof(T)];
 
   const T *addr() const { return (const T *)bytes; }
   T *addr() { return (T *)(void *)bytes; }
 };
 
+static inline bool
+FuzzyEqual(Float aA, Float aB, Float aErr)
+{
+  if ((aA + aErr > aB) && (aA - aErr < aB)) {
+    return true;
+  }
+  return false;
+}
+
+static inline Float
+Distance(Point aA, Point aB)
+{
+  return hypotf(aB.x - aA.x, aB.y - aA.y);
+}
+
 }
 }
 
 #endif /* MOZILLA_GFX_TOOLS_H_ */
--- a/gfx/2d/gfx2d.vcxproj
+++ b/gfx/2d/gfx2d.vcxproj
@@ -36,17 +36,17 @@
     <LinkIncremental>true</LinkIncremental>
     <ExecutablePath>$(DXSDK_DIR)\Utilities\bin\x86;$(ExecutablePath)</ExecutablePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     <LinkIncremental>true</LinkIncremental>
   </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <ClCompile>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);GFX_LOG_DEBUG;GFX_LOG_WARNING;MFBT_STAND_ALONE;XP_WIN</PreprocessorDefinitions>
+      <PreprocessorDefinitions>USE_SSE2;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);GFX_LOG_DEBUG;GFX_LOG_WARNING;MFBT_STAND_ALONE;XP_WIN</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
       <WarningLevel>Level3</WarningLevel>
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
       <Optimization>Disabled</Optimization>
     </ClCompile>
     <Link>
       <TargetMachine>MachineX86</TargetMachine>
       <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -75,32 +75,35 @@
     <ClInclude Include="BaseMargin.h" />
     <ClInclude Include="BasePoint.h" />
     <ClInclude Include="BaseRect.h" />
     <ClInclude Include="BaseSize.h" />
     <ClInclude Include="DrawTargetD2D.h" />
     <ClInclude Include="DrawTargetDual.h" />
     <ClInclude Include="GradientStopsD2D.h" />
     <ClInclude Include="HelpersD2D.h" />
+    <ClInclude Include="ImageScaling.h" />
     <ClInclude Include="Logging.h" />
     <ClInclude Include="Matrix.h" />
     <ClInclude Include="PathD2D.h" />
     <ClInclude Include="Point.h" />
     <ClInclude Include="Rect.h" />
     <ClInclude Include="ScaledFontDWrite.h" />
     <ClInclude Include="SourceSurfaceD2D.h" />
     <ClInclude Include="SourceSurfaceD2DTarget.h" />
     <ClInclude Include="Tools.h" />
     <ClInclude Include="Types.h" />
     <ClInclude Include="UserData.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="DrawTargetD2D.cpp" />
     <ClCompile Include="DrawTargetDual.cpp" />
     <ClCompile Include="Factory.cpp" />
+    <ClCompile Include="ImageScaling.cpp" />
+    <ClCompile Include="ImageScalingSSE2.cpp" />
     <ClCompile Include="Matrix.cpp" />
     <ClCompile Include="PathD2D.cpp" />
     <ClCompile Include="ScaledFontDWrite.cpp" />
     <ClCompile Include="SourceSurfaceD2D.cpp" />
     <ClCompile Include="SourceSurfaceD2DTarget.cpp" />
   </ItemGroup>
   <ItemGroup>
     <None Include="Makefile.in" />
--- a/gfx/2d/unittest/Main.cpp
+++ b/gfx/2d/unittest/Main.cpp
@@ -32,16 +32,17 @@
  * 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 "SanityChecks.h"
 #include "TestPoint.h"
+#include "TestScaling.h"
 #ifdef WIN32
 #include "TestDrawTargetD2D.h"
 #endif
 
 #include <string>
 #include <sstream>
 
 struct TestObject {
@@ -56,17 +57,18 @@ int
 main()
 {
   TestObject tests[] = 
   {
     { new SanityChecks(), "Sanity Checks" },
   #ifdef WIN32
     { new TestDrawTargetD2D(), "DrawTarget (D2D)" },
   #endif
-    { new TestPoint(), "Point Tests" }
+    { new TestPoint(), "Point Tests" },
+    { new TestScaling(), "Scaling Tests" }
   };
 
   int totalFailures = 0;
   int totalTests = 0;
   stringstream message;
   printf("------ STARTING RUNNING TESTS ------\n");
   for (int i = 0; i < sizeof(tests) / sizeof(TestObject); i++) {
     message << "--- RUNNING TESTS: " << tests[i].name << " ---\n";
--- a/gfx/2d/unittest/TestPoint.h
+++ b/gfx/2d/unittest/TestPoint.h
@@ -30,16 +30,18 @@
  * 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 ***** */
 
+#pragma once
+
 #include "TestBase.h"
 
 class TestPoint : public TestBase
 {
 public:
   TestPoint();
 
   void Addition();
new file mode 100644
--- /dev/null
+++ b/gfx/2d/unittest/TestScaling.cpp
@@ -0,0 +1,275 @@
+/* -*- Mode: C++; tab-width: 20; 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 Mozilla Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Bas Schouten <bschouten@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 ***** */
+
+#include "TestScaling.h"
+
+#include "ImageScaling.h"
+
+using namespace mozilla::gfx;
+
+TestScaling::TestScaling()
+{
+  REGISTER_TEST(TestScaling, BasicHalfScale);
+  REGISTER_TEST(TestScaling, DoubleHalfScale);
+  REGISTER_TEST(TestScaling, UnevenHalfScale);
+  REGISTER_TEST(TestScaling, OddStrideHalfScale);
+  REGISTER_TEST(TestScaling, VerticalHalfScale);
+  REGISTER_TEST(TestScaling, HorizontalHalfScale);
+  REGISTER_TEST(TestScaling, MixedHalfScale);
+}
+
+void
+TestScaling::BasicHalfScale()
+{
+  std::vector<uint8_t> data;
+  data.resize(500 * 500 * 4);
+
+  uint32_t *pixels = (uint32_t*)data.data();
+  for (int y = 0; y < 500; y += 2) {
+    for (int x = 0; x < 500; x += 2) {
+      pixels[y * 500 + x] = 0xff00ff00;
+      pixels[y * 500 + x + 1] = 0xff00ffff;
+      pixels[(y + 1) * 500 + x] = 0xff000000;
+      pixels[(y + 1) * 500 + x + 1] = 0xff0000ff;
+    }
+  }
+  ImageHalfScaler scaler(data.data(), 500 * 4, IntSize(500, 500));
+
+  scaler.ScaleForSize(IntSize(220, 240));
+
+  VERIFY(scaler.GetSize().width == 250);
+  VERIFY(scaler.GetSize().height == 250);
+
+  pixels = (uint32_t*)scaler.GetScaledData();
+
+  for (int y = 0; y < 250; y++) {
+    for (int x = 0; x < 250; x++) {
+      VERIFY(pixels[y * (scaler.GetStride() / 4) + x] == 0xff007f7f);
+    }
+  }
+}
+
+void
+TestScaling::DoubleHalfScale()
+{
+  std::vector<uint8_t> data;
+  data.resize(500 * 500 * 4);
+
+  uint32_t *pixels = (uint32_t*)data.data();
+  for (int y = 0; y < 500; y += 2) {
+    for (int x = 0; x < 500; x += 2) {
+      pixels[y * 500 + x] = 0xff00ff00;
+      pixels[y * 500 + x + 1] = 0xff00ffff;
+      pixels[(y + 1) * 500 + x] = 0xff000000;
+      pixels[(y + 1) * 500 + x + 1] = 0xff0000ff;
+    }
+  }
+  ImageHalfScaler scaler(data.data(), 500 * 4, IntSize(500, 500));
+
+  scaler.ScaleForSize(IntSize(120, 110));
+  VERIFY(scaler.GetSize().width == 125);
+  VERIFY(scaler.GetSize().height == 125);
+
+  pixels = (uint32_t*)scaler.GetScaledData();
+
+  for (int y = 0; y < 125; y++) {
+    for (int x = 0; x < 125; x++) {
+      VERIFY(pixels[y * (scaler.GetStride() / 4) + x] == 0xff007f7f);
+    }
+  }
+}
+
+void
+TestScaling::UnevenHalfScale()
+{
+  std::vector<uint8_t> data;
+  // Use a 16-byte aligned stride still, we test none-aligned strides
+  // separately.
+  data.resize(499 * 500 * 4);
+
+  uint32_t *pixels = (uint32_t*)data.data();
+  for (int y = 0; y < 500; y += 2) {
+    for (int x = 0; x < 500; x += 2) {
+      pixels[y * 500 + x] = 0xff00ff00;
+      if (x < 498) {
+        pixels[y * 500 + x + 1] = 0xff00ffff;
+      }
+      if (y < 498) {
+        pixels[(y + 1) * 500 + x] = 0xff000000;
+        if (x < 498) {
+          pixels[(y + 1) * 500 + x + 1] = 0xff0000ff;
+        }
+      }
+    }
+  }
+  ImageHalfScaler scaler(data.data(), 500 * 4, IntSize(499, 499));
+
+  scaler.ScaleForSize(IntSize(220, 220));
+  VERIFY(scaler.GetSize().width == 249);
+  VERIFY(scaler.GetSize().height == 249);
+
+  pixels = (uint32_t*)scaler.GetScaledData();
+
+  for (int y = 0; y < 249; y++) {
+    for (int x = 0; x < 249; x++) {
+      VERIFY(pixels[y * (scaler.GetStride() / 4) + x] == 0xff007f7f);
+    }
+  }
+}
+
+void
+TestScaling::OddStrideHalfScale()
+{
+  std::vector<uint8_t> data;
+  // Use a 4-byte aligned stride to test if that doesn't cause any issues.
+  data.resize(499 * 499 * 4);
+
+  uint32_t *pixels = (uint32_t*)data.data();
+  for (int y = 0; y < 500; y += 2) {
+    for (int x = 0; x < 500; x += 2) {
+      pixels[y * 499 + x] = 0xff00ff00;
+      if (x < 498) {
+        pixels[y * 499 + x + 1] = 0xff00ffff;
+      }
+      if (y < 498) {
+        pixels[(y + 1) * 499 + x] = 0xff000000;
+        if (x < 498) {
+          pixels[(y + 1) * 499 + x + 1] = 0xff0000ff;
+        }
+      }
+    }
+  }
+  ImageHalfScaler scaler(data.data(), 499 * 4, IntSize(499, 499));
+
+  scaler.ScaleForSize(IntSize(220, 220));
+  VERIFY(scaler.GetSize().width == 249);
+  VERIFY(scaler.GetSize().height == 249);
+
+  pixels = (uint32_t*)scaler.GetScaledData();
+
+  for (int y = 0; y < 249; y++) {
+    for (int x = 0; x < 249; x++) {
+      VERIFY(pixels[y * (scaler.GetStride() / 4) + x] == 0xff007f7f);
+    }
+  }
+}
+void
+TestScaling::VerticalHalfScale()
+{
+  std::vector<uint8_t> data;
+  data.resize(500 * 500 * 4);
+
+  uint32_t *pixels = (uint32_t*)data.data();
+  for (int y = 0; y < 500; y += 2) {
+    for (int x = 0; x < 500; x += 2) {
+      pixels[y * 500 + x] = 0xff00ff00;
+      pixels[y * 500 + x + 1] = 0xff00ffff;
+      pixels[(y + 1) * 500 + x] = 0xff000000;
+      pixels[(y + 1) * 500 + x + 1] = 0xff0000ff;
+    }
+  }
+  ImageHalfScaler scaler(data.data(), 500 * 4, IntSize(500, 500));
+
+  scaler.ScaleForSize(IntSize(400, 240));
+  VERIFY(scaler.GetSize().width == 500);
+  VERIFY(scaler.GetSize().height == 250);
+
+  pixels = (uint32_t*)scaler.GetScaledData();
+
+  for (int y = 0; y < 250; y++) {
+    for (int x = 0; x < 500; x += 2) {
+      VERIFY(pixels[y * (scaler.GetStride() / 4) + x] == 0xff007f00);
+      VERIFY(pixels[y * (scaler.GetStride() / 4) + x + 1] == 0xff007fff);
+    }
+  }
+}
+
+void
+TestScaling::HorizontalHalfScale()
+{
+  std::vector<uint8_t> data;
+  data.resize(500 * 500 * 4);
+
+  uint32_t *pixels = (uint32_t*)data.data();
+  for (int y = 0; y < 500; y += 2) {
+    for (int x = 0; x < 500; x += 2) {
+      pixels[y * 500 + x] = 0xff00ff00;
+      pixels[y * 500 + x + 1] = 0xff00ffff;
+      pixels[(y + 1) * 500 + x] = 0xff000000;
+      pixels[(y + 1) * 500 + x + 1] = 0xff0000ff;
+    }
+  }
+  ImageHalfScaler scaler(data.data(), 500 * 4, IntSize(500, 500));
+
+  scaler.ScaleForSize(IntSize(240, 400));
+  VERIFY(scaler.GetSize().width == 250);
+  VERIFY(scaler.GetSize().height == 500);
+
+  pixels = (uint32_t*)scaler.GetScaledData();
+
+  for (int y = 0; y < 500; y += 2) {
+    for (int x = 0; x < 250; x++) {
+      VERIFY(pixels[y * (scaler.GetStride() / 4) + x] == 0xff00ff7f);
+      VERIFY(pixels[(y + 1) * (scaler.GetStride() / 4) + x] == 0xff00007f);
+    }
+  }
+}
+
+void
+TestScaling::MixedHalfScale()
+{
+  std::vector<uint8_t> data;
+  data.resize(500 * 500 * 4);
+
+  uint32_t *pixels = (uint32_t*)data.data();
+  for (int y = 0; y < 500; y += 2) {
+    for (int x = 0; x < 500; x += 2) {
+      pixels[y * 500 + x] = 0xff00ff00;
+      pixels[y * 500 + x + 1] = 0xff00ffff;
+      pixels[(y + 1) * 500 + x] = 0xff000000;
+      pixels[(y + 1) * 500 + x + 1] = 0xff0000ff;
+    }
+  }
+  ImageHalfScaler scaler(data.data(), 500 * 4, IntSize(500, 500));
+
+  scaler.ScaleForSize(IntSize(120, 240));
+  VERIFY(scaler.GetSize().width == 125);
+  VERIFY(scaler.GetSize().height == 250);
+  scaler.ScaleForSize(IntSize(240, 120));
+  VERIFY(scaler.GetSize().width == 250);
+  VERIFY(scaler.GetSize().height == 125);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/2d/unittest/TestScaling.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 20; 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 Mozilla Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Bas Schouten <bschouten@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 ***** */
+
+#pragma once
+
+#include "TestBase.h"
+
+class TestScaling : public TestBase
+{
+public:
+  TestScaling();
+
+  void BasicHalfScale();
+  void DoubleHalfScale();
+  void UnevenHalfScale();
+  void OddStrideHalfScale();
+  void VerticalHalfScale();
+  void HorizontalHalfScale();
+  void MixedHalfScale();
+};
--- a/gfx/2d/unittest/unittest.vcxproj
+++ b/gfx/2d/unittest/unittest.vcxproj
@@ -72,20 +72,22 @@
   </ItemDefinitionGroup>
   <ItemGroup>
     <ClCompile Include="Main.cpp" />
     <ClCompile Include="SanityChecks.cpp" />
     <ClCompile Include="TestBase.cpp" />
     <ClCompile Include="TestDrawTargetBase.cpp" />
     <ClCompile Include="TestDrawTargetD2D.cpp" />
     <ClCompile Include="TestPoint.cpp" />
+    <ClCompile Include="TestScaling.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="TestDrawTargetBase.h" />
     <ClInclude Include="SanityChecks.h" />
     <ClInclude Include="TestBase.h" />
     <ClInclude Include="TestDrawTargetD2D.h" />
     <ClInclude Include="TestPoint.h" />
+    <ClInclude Include="TestScaling.h" />
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
 </Project>
\ No newline at end of file
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -736,33 +736,34 @@ GLContext::ListHasExtension(const GLubyt
     }
     return false;
 }
 
 already_AddRefed<TextureImage>
 GLContext::CreateTextureImage(const nsIntSize& aSize,
                               TextureImage::ContentType aContentType,
                               GLenum aWrapMode,
-                              bool aUseNearestFilter)
+                              TextureImage::Flags aFlags)
 {
+    bool useNearestFilter = aFlags & TextureImage::UseNearestFilter;
     MakeCurrent();
 
     GLuint texture;
     fGenTextures(1, &texture);
 
     fActiveTexture(LOCAL_GL_TEXTURE0);
     fBindTexture(LOCAL_GL_TEXTURE_2D, texture);
 
-    GLint texfilter = aUseNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR;
+    GLint texfilter = useNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR;
     fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter);
     fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter);
     fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, aWrapMode);
     fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, aWrapMode);
 
-    return CreateBasicTextureImage(texture, aSize, aWrapMode, aContentType, this);
+    return CreateBasicTextureImage(texture, aSize, aWrapMode, aContentType, this, aFlags);
 }
 
 void GLContext::ApplyFilterToBoundTexture(gfxPattern::GraphicsFilter aFilter)
 {
     if (aFilter == gfxPattern::FILTER_NEAREST) {
         fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST);
         fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST);
     } else {
@@ -935,24 +936,23 @@ BasicTextureImage::Resize(const nsIntSiz
 
     mTextureState = Allocated;
     mSize = aSize;
 }
 
 TiledTextureImage::TiledTextureImage(GLContext* aGL,
                                      nsIntSize aSize,
                                      TextureImage::ContentType aContentType,
-                                     bool aUseNearestFilter)
-    : TextureImage(aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, aUseNearestFilter)
+                                     TextureImage::Flags aFlags)
+    : TextureImage(aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, aFlags)
     , mCurrentImage(0)
     , mInUpdate(false)
     , mRows(0)
     , mColumns(0)
     , mGL(aGL)
-    , mUseNearestFilter(aUseNearestFilter)
     , mTextureState(Created)
     , mIterationCallback(nsnull)
 {
     mTileSize = mGL->WantsSmallTiles() ? 256 : mGL->GetMaxTextureSize();
     if (aSize != nsIntSize(0,0)) {
         Resize(aSize);
     }
 }
@@ -972,17 +972,17 @@ TiledTextureImage::DirectUpdate(gfxASurf
     } else {
         region = aRegion;
     }
 
     bool result = true;
     int oldCurrentImage = mCurrentImage;
     BeginTileIteration();
     do {
-        nsIntRect tileRect = GetTileRect();
+        nsIntRect tileRect = GetSrcTileRect();
         int xPos = tileRect.x;
         int yPos = tileRect.y;
 
         nsIntRegion tileRegion;
         tileRegion.And(region, tileRect); // intersect with tile
 
         if (tileRegion.IsEmpty())
             continue;
@@ -1184,16 +1184,25 @@ nsIntRect TiledTextureImage::GetTileRect
 {
     nsIntRect rect = mImages[mCurrentImage]->GetTileRect();
     unsigned int xPos = (mCurrentImage % mColumns) * mTileSize;
     unsigned int yPos = (mCurrentImage / mColumns) * mTileSize;
     rect.MoveBy(xPos, yPos);
     return rect;
 }
 
+nsIntRect TiledTextureImage::GetSrcTileRect()
+{
+    nsIntRect rect = GetTileRect();
+    unsigned int srcY = mFlags & NeedsYFlip
+                        ? mSize.height - rect.height - rect.y
+                        : rect.y;
+    return nsIntRect(rect.x, srcY, rect.width, rect.height);
+}
+
 void
 TiledTextureImage::BindTexture(GLenum aTextureUnit)
 {
     mImages[mCurrentImage]->BindTexture(aTextureUnit);
 }
 
 void
 TiledTextureImage::ApplyFilter()
@@ -1264,17 +1273,17 @@ void TiledTextureImage::Resize(const nsI
                     // Width hasn't changed, reuse existing tile.
                     i++;
                     continue;
                 }
             }
 
             // Create a new tile.
             nsRefPtr<TextureImage> teximg =
-                    mGL->TileGenFunc(size, mContentType, mUseNearestFilter);
+                    mGL->TileGenFunc(size, mContentType, mFlags);
             if (replace)
                 mImages.ReplaceElementAt(i, teximg.forget());
             else
                 mImages.InsertElementAt(i, teximg.forget());
             i++;
         }
 
         // Prune any unused tiles on the end of the column.
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -123,16 +123,22 @@ class TextureImage
 public:
     enum TextureState
     {
       Created, // Texture created, but has not had glTexImage called to initialize it.
       Allocated,  // Texture memory exists, but contents are invalid.
       Valid  // Texture fully ready to use.
     };
 
+    enum Flags {
+        NoFlags          = 0x0,
+        UseNearestFilter = 0x1,
+        NeedsYFlip       = 0x2
+    };
+
     typedef gfxASurface::gfxContentType ContentType;
 
     virtual ~TextureImage() {}
 
     /**
      * Returns a gfxASurface for updating |aRegion| of the client's
      * image if successul, NULL if not.  |aRegion|'s bounds must fit
      * within Size(); its coordinate space (if any) is ignored.  If
@@ -314,28 +320,34 @@ protected:
     /**
      * After the ctor, the TextureImage is invalid.  Implementations
      * must allocate resources successfully before returning the new
      * TextureImage from GLContext::CreateTextureImage().  That is,
      * clients must not be given partially-constructed TextureImages.
      */
     TextureImage(const nsIntSize& aSize,
                  GLenum aWrapMode, ContentType aContentType,
-                 bool aIsRGB = false)
+                 Flags aFlags = NoFlags)
         : mSize(aSize)
         , mWrapMode(aWrapMode)
         , mContentType(aContentType)
         , mFilter(gfxPattern::FILTER_GOOD)
+        , mFlags(aFlags)
     {}
 
+    virtual nsIntRect GetSrcTileRect() {
+        return nsIntRect(nsIntPoint(0,0), mSize);
+    };
+
     nsIntSize mSize;
     GLenum mWrapMode;
     ContentType mContentType;
     ShaderProgramType mShaderType;
     gfxPattern::GraphicsFilter mFilter;
+    Flags mFlags;
 };
 
 /**
  * BasicTextureImage is the baseline TextureImage implementation ---
  * it updates its texture by allocating a scratch buffer for the
  * client to draw into, then using glTexSubImage2D() to upload the new
  * pixels.  Platforms must provide the code to create a new surface
  * into which the updated pixels will be drawn, and the code to
@@ -348,18 +360,19 @@ class BasicTextureImage
 public:
     typedef gfxASurface::gfxImageFormat ImageFormat;
     virtual ~BasicTextureImage();
 
     BasicTextureImage(GLuint aTexture,
                       const nsIntSize& aSize,
                       GLenum aWrapMode,
                       ContentType aContentType,
-                      GLContext* aContext)
-        : TextureImage(aSize, aWrapMode, aContentType)
+                      GLContext* aContext,
+                      TextureImage::Flags aFlags = TextureImage::NoFlags)
+        : TextureImage(aSize, aWrapMode, aContentType, aFlags)
         , mTexture(aTexture)
         , mTextureState(Created)
         , mGLContext(aContext)
         , mUpdateOffset(0, 0)
     {}
 
     virtual void BindTexture(GLenum aTextureUnit);
 
@@ -404,17 +417,17 @@ protected:
  * Aims to behave just like the real thing.
  */
 
 class TiledTextureImage
     : public TextureImage
 {
 public:
     TiledTextureImage(GLContext* aGL, nsIntSize aSize,
-        TextureImage::ContentType, bool aUseNearestFilter = false);
+        TextureImage::ContentType, TextureImage::Flags aFlags = TextureImage::NoFlags);
     ~TiledTextureImage();
     void DumpDiv();
     virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion);
     virtual void GetUpdateRegion(nsIntRegion& aForRegion);
     virtual void EndUpdate();
     virtual void Resize(const nsIntSize& aSize);
     virtual PRUint32 GetTileCount();
     virtual void BeginTileIteration();
@@ -424,27 +437,29 @@ public:
     virtual nsIntRect GetTileRect();
     virtual GLuint GetTextureID() {
         return mImages[mCurrentImage]->GetTextureID();
     };
     virtual bool DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom = nsIntPoint(0,0));
     virtual bool InUpdate() const { return mInUpdate; };
     virtual void BindTexture(GLenum);
     virtual void ApplyFilter();
+
 protected:
+    virtual nsIntRect GetSrcTileRect();
+
     unsigned int mCurrentImage;
     TileIterationCallback mIterationCallback;
     void* mIterationCallbackData;
     nsTArray< nsRefPtr<TextureImage> > mImages;
     bool mInUpdate;
     nsIntSize mSize;
     unsigned int mTileSize;
     unsigned int mRows, mColumns;
     GLContext* mGL;
-    bool mUseNearestFilter;
     // A temporary surface to faciliate cross-tile updates.
     nsRefPtr<gfxASurface> mUpdateSurface;
     // The region of update requested
     nsIntRegion mUpdateRegion;
     TextureState mTextureState;
 };
 
 struct THEBES_API ContextFormat
@@ -1377,41 +1392,42 @@ public:
 
     virtual bool RenewSurface() { return false; }
 
     /**`
      * Return a valid, allocated TextureImage of |aSize| with
      * |aContentType|.  The TextureImage's texture is configured to
      * use |aWrapMode| (usually GL_CLAMP_TO_EDGE or GL_REPEAT) and by
      * default, GL_LINEAR filtering.  Specify
-     * |aUseNearestFilter=true| for GL_NEAREST filtering.  Return
+     * |aFlags=UseNearestFilter| for GL_NEAREST filtering. Specify
+     * |aFlags=NeedsYFlip| if the image is flipped. Return
      * NULL if creating the TextureImage fails.
      *
      * The returned TextureImage may only be used with this GLContext.
      * Attempting to use the returned TextureImage after this
      * GLContext is destroyed will result in undefined (and likely
      * crashy) behavior.
      */
     virtual already_AddRefed<TextureImage>
     CreateTextureImage(const nsIntSize& aSize,
                        TextureImage::ContentType aContentType,
                        GLenum aWrapMode,
-                       bool aUseNearestFilter=false);
+                       TextureImage::Flags aFlags = TextureImage::NoFlags);
 
     /**
      * In EGL we want to use Tiled Texture Images, which we return
      * from CreateTextureImage above.
      * Inside TiledTextureImage we need to create actual images and to
      * prevent infinite recursion we need to differentiate the two
      * functions.
      **/
     virtual already_AddRefed<TextureImage>
     TileGenFunc(const nsIntSize& aSize,
                 TextureImage::ContentType aContentType,
-                bool aUseNearestFilter = false)
+                TextureImage::Flags aFlags = TextureImage::NoFlags)
     {
         return nsnull;
     };
 
     /**
      * Read the image data contained in aTexture, and return it as an ImageSurface.
      * If GL_RGBA is given as the format, a ImageFormatARGB32 surface is returned.
      * Not implemented yet:
@@ -1825,20 +1841,21 @@ protected:
 
     void InitExtensions();
 
     virtual already_AddRefed<TextureImage>
     CreateBasicTextureImage(GLuint aTexture,
                             const nsIntSize& aSize,
                             GLenum aWrapMode,
                             TextureImage::ContentType aContentType,
-                            GLContext* aContext)
+                            GLContext* aContext,
+                            TextureImage::Flags aFlags = TextureImage::NoFlags)
     {
         nsRefPtr<BasicTextureImage> teximage(
-            new BasicTextureImage(aTexture, aSize, aWrapMode, aContentType, aContext));
+            new BasicTextureImage(aTexture, aSize, aWrapMode, aContentType, aContext, aFlags));
         return teximage.forget();
     }
 
     bool IsOffscreenSizeAllowed(const gfxIntSize& aSize) const {
         PRInt32 biggerDimension = NS_MAX(aSize.width, aSize.height);
         PRInt32 maxAllowed = NS_MIN(mMaxRenderbufferSize, mMaxTextureSize);
         return biggerDimension <= maxAllowed;
     }
--- a/gfx/gl/GLContextProviderCGL.mm
+++ b/gfx/gl/GLContextProviderCGL.mm
@@ -205,17 +205,18 @@ public:
     void UnbindTex2DOffscreen(GLContext *aOffscreen);
     bool ResizeOffscreen(const gfxIntSize& aNewSize);
 
     virtual already_AddRefed<TextureImage>
     CreateBasicTextureImage(GLuint aTexture,
                             const nsIntSize& aSize,
                             GLenum aWrapMode,
                             TextureImage::ContentType aContentType,
-                            GLContext* aContext);
+                            GLContext* aContext,
+                            TextureImage::Flags aFlags = TextureImage::NoFlags);
 
     NSOpenGLContext *mContext;
     NSOpenGLPixelBuffer *mPBuffer;
     GLuint mTempTextureName;
 };
 
 bool
 GLContextCGL::BindTex2DOffscreen(GLContext *aOffscreen)
@@ -310,17 +311,18 @@ GLContextCGL::ResizeOffscreen(const gfxI
 
 class TextureImageCGL : public BasicTextureImage
 {
     friend already_AddRefed<TextureImage>
     GLContextCGL::CreateBasicTextureImage(GLuint,
                                           const nsIntSize&,
                                           GLenum,
                                           TextureImage::ContentType,
-                                          GLContext*);
+                                          GLContext*,
+                                          TextureImage::Flags);
 public:
     ~TextureImageCGL()
     {
         if (mPixelBuffer) {
             mGLContext->MakeCurrent();
             mGLContext->fDeleteBuffers(1, &mPixelBuffer);
         }
     }
@@ -396,37 +398,39 @@ protected:
         }
     }
 
 private:
     TextureImageCGL(GLuint aTexture,
                     const nsIntSize& aSize,
                     GLenum aWrapMode,
                     ContentType aContentType,
-                    GLContext* aContext)
-        : BasicTextureImage(aTexture, aSize, aWrapMode, aContentType, aContext)
+                    GLContext* aContext,
+                    TextureImage::Flags aFlags = TextureImage::NoFlags)
+        : BasicTextureImage(aTexture, aSize, aWrapMode, aContentType, aContext, aFlags)
         , mPixelBuffer(0)
         , mPixelBufferSize(0)
         , mBoundPixelBuffer(false)
     {}
     
     GLuint mPixelBuffer;
     PRInt32 mPixelBufferSize;
     bool mBoundPixelBuffer;
 };
 
 already_AddRefed<TextureImage>
 GLContextCGL::CreateBasicTextureImage(GLuint aTexture,
                                       const nsIntSize& aSize,
                                       GLenum aWrapMode,
                                       TextureImage::ContentType aContentType,
-                                      GLContext* aContext)
+                                      GLContext* aContext,
+                                      TextureImage::Flags aFlags)
 {
     nsRefPtr<TextureImageCGL> teximage
-        (new TextureImageCGL(aTexture, aSize, aWrapMode, aContentType, aContext));
+        (new TextureImageCGL(aTexture, aSize, aWrapMode, aContentType, aContext, aFlags));
     return teximage.forget();
 }
 
 static GLContextCGL *
 GetGlobalContextCGL()
 {
     return static_cast<GLContextCGL*>(GLContextProviderCGL::GetGlobalContext());
 }
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -519,23 +519,23 @@ public:
             return false;
         }
     }
     // GLContext interface - returns Tiled Texture Image in our case
     virtual already_AddRefed<TextureImage>
     CreateTextureImage(const nsIntSize& aSize,
                        TextureImage::ContentType aContentType,
                        GLenum aWrapMode,
-                       bool aUseNearestFilter=false);
+                       TextureImage::Flags aFlags = TextureImage::NoFlags);
 
     // a function to generate Tiles for Tiled Texture Image
     virtual already_AddRefed<TextureImage>
     TileGenFunc(const nsIntSize& aSize,
                 TextureImage::ContentType aContentType,
-                bool aUseNearestFilter = false);
+                TextureImage::Flags aFlags = TextureImage::NoFlags);
     // hold a reference to the given surface
     // for the lifetime of this context.
     void HoldSurface(gfxASurface *aSurf) {
         mThebesSurface = aSurf;
     }
 
     void SetPlatformContext(void *context) {
         mPlatformContext = context;
@@ -794,18 +794,19 @@ GLTypeForImage(gfxASurface::gfxImageForm
 class TextureImageEGL
     : public TextureImage
 {
 public:
     TextureImageEGL(GLuint aTexture,
                     const nsIntSize& aSize,
                     GLenum aWrapMode,
                     ContentType aContentType,
-                    GLContext* aContext)
-        : TextureImage(aSize, aWrapMode, aContentType)
+                    GLContext* aContext,
+                    TextureImage::Flags aFlags = TextureImage::NoFlags)
+        : TextureImage(aSize, aWrapMode, aContentType, aFlags)
         , mGLContext(aContext)
         , mUpdateFormat(gfxASurface::ImageFormatUnknown)
         , mSurface(nsnull)
         , mConfig(nsnull)
         , mTexture(aTexture)
         , mImageKHR(nsnull)
         , mTextureState(Created)
         , mBound(false)
@@ -1288,39 +1289,39 @@ protected:
         mGLContext->ApplyFilterToBoundTexture(mFilter);
     }
 };
 
 already_AddRefed<TextureImage>
 GLContextEGL::CreateTextureImage(const nsIntSize& aSize,
                                  TextureImage::ContentType aContentType,
                                  GLenum aWrapMode,
-                                 bool aUseNearestFilter)
+                                 TextureImage::Flags aFlags)
 {
-    nsRefPtr<TextureImage> t = new gl::TiledTextureImage(this, aSize, aContentType, aUseNearestFilter);
+    nsRefPtr<TextureImage> t = new gl::TiledTextureImage(this, aSize, aContentType, aFlags);
     return t.forget();
 }
 
 already_AddRefed<TextureImage>
 GLContextEGL::TileGenFunc(const nsIntSize& aSize,
                                  TextureImage::ContentType aContentType,
-                                 bool aUseNearestFilter)
+                                 TextureImage::Flags aFlags)
 {
   MakeCurrent();
 
   GLuint texture;
   fGenTextures(1, &texture);
 
   fActiveTexture(LOCAL_GL_TEXTURE0);
   fBindTexture(LOCAL_GL_TEXTURE_2D, texture);
 
   nsRefPtr<TextureImageEGL> teximage =
-      new TextureImageEGL(texture, aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, this);
+      new TextureImageEGL(texture, aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, this, aFlags);
 
-  GLint texfilter = aUseNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR;
+  GLint texfilter = aFlags & TextureImage::UseNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR;
   fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter);
   fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter);
   fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
   fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
 
   return teximage.forget();
 }
 
--- a/gfx/gl/GLContextProviderGLX.cpp
+++ b/gfx/gl/GLContextProviderGLX.cpp
@@ -844,17 +844,17 @@ TRY_AGAIN_NO_SHARING:
     {
         return sGLXLibrary.UseTextureFromPixmap();
     }
 
     virtual already_AddRefed<TextureImage>
     CreateTextureImage(const nsIntSize& aSize,
                        TextureImage::ContentType aContentType,
                        GLenum aWrapMode,
-                       bool aUseNearestFilter = false);
+                       TextureImage::Flags aFlags = TextureImage::NoFlags);
 
 private:
     friend class GLContextProviderGLX;
 
     GLContextGLX(const ContextFormat& aFormat,
                  GLContext *aShareContext,
                  Display *aDisplay,
                  GLXDrawable aDrawable,
@@ -881,17 +881,17 @@ private:
 };
 
 class TextureImageGLX : public TextureImage
 {
     friend already_AddRefed<TextureImage>
     GLContextGLX::CreateTextureImage(const nsIntSize&,
                                      ContentType,
                                      GLenum,
-                                     bool);
+                                     TextureImage::Flags);
 
 public:
     virtual ~TextureImageGLX()
     {
         mGLContext->MakeCurrent();
         mGLContext->fDeleteTextures(1, &mTexture);
         sGLXLibrary.DestroyPixmap(mPixmap);
     }
@@ -945,18 +945,19 @@ public:
 
 private:
    TextureImageGLX(GLuint aTexture,
                    const nsIntSize& aSize,
                    GLenum aWrapMode,
                    ContentType aContentType,
                    GLContext* aContext,
                    gfxASurface* aSurface,
-                   GLXPixmap aPixmap)
-        : TextureImage(aSize, aWrapMode, aContentType)
+                   GLXPixmap aPixmap,
+                   TextureImage::Flags aFlags = TextureImage::NoFlags)
+        : TextureImage(aSize, aWrapMode, aContentType, aFlags)
         , mGLContext(aContext)
         , mUpdateSurface(aSurface)
         , mPixmap(aPixmap)
         , mInUpdate(false)
         , mTexture(aTexture)
     {
         if (aSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA) {
             mShaderType = gl::RGBALayerProgramType;
@@ -976,23 +977,23 @@ private:
         mGLContext->ApplyFilterToBoundTexture(mFilter);
     }
 };
 
 already_AddRefed<TextureImage>
 GLContextGLX::CreateTextureImage(const nsIntSize& aSize,
                                  TextureImage::ContentType aContentType,
                                  GLenum aWrapMode,
-                                 bool aUseNearestFilter)
+                                 TextureImage::Flags aFlags)
 {
     if (!TextureImageSupportsGetBackingSurface()) {
         return GLContext::CreateTextureImage(aSize, 
                                              aContentType, 
                                              aWrapMode, 
-                                             aUseNearestFilter);
+                                             aFlags);
     }
 
     Display *display = DefaultXDisplay();
     int xscreen = DefaultScreen(display);
     gfxASurface::gfxImageFormat imageFormat = gfxASurface::FormatFromContent(aContentType);
 
     XRenderPictFormat* xrenderFormat =
         gfxXlibSurface::FindRenderFormat(display, imageFormat);
@@ -1017,19 +1018,19 @@ GLContextGLX::CreateTextureImage(const n
 
     GLuint texture;
     fGenTextures(1, &texture);
 
     fActiveTexture(LOCAL_GL_TEXTURE0);
     fBindTexture(LOCAL_GL_TEXTURE_2D, texture);
 
     nsRefPtr<TextureImageGLX> teximage =
-        new TextureImageGLX(texture, aSize, aWrapMode, aContentType, this, surface, pixmap);
+        new TextureImageGLX(texture, aSize, aWrapMode, aContentType, this, surface, pixmap, aFlags);
 
-    GLint texfilter = aUseNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR;
+    GLint texfilter = aFlags & TextureImage::UseNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR;
     fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter);
     fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter);
     fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, aWrapMode);
     fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, aWrapMode);
 
     return teximage.forget();
 }
 
--- a/gfx/graphite2/src/Silf.cpp
+++ b/gfx/graphite2/src/Silf.cpp
@@ -106,16 +106,17 @@ bool Silf::readGraphite(const byte * con
     m_aUser     = be::read<uint8>(p);
     m_iMaxComp  = be::read<uint8>(p);
     be::skip<byte>(p,5); 						// direction and 4 reserved bytes
     be::skip<uint16>(p, be::read<uint8>(p)); 	// don't need critical features yet
     be::skip<byte>(p);							// reserved
     if (p >= silf_end)   { releaseBuffers(); return false; }
     be::skip<uint32>(p, be::read<uint8>(p));	// don't use scriptTag array.
     be::skip<uint16>(p); // lbGID
+    if (p >= silf_end)   { releaseBuffers(); return false; }
     const byte * o_passes = p,
                * const passes_start = silf_start + be::read<uint32>(p);
 
     if (m_numPasses > 128 || passes_start >= silf_end
     	|| m_pPass < m_sPass
     	|| m_jPass < m_pPass
     	|| (m_bPass != 0xFF && (m_bPass < m_jPass || m_bPass > m_numPasses))
     	|| m_aLig > 127) {
--- a/gfx/layers/opengl/CanvasLayerOGL.cpp
+++ b/gfx/layers/opengl/CanvasLayerOGL.cpp
@@ -334,20 +334,22 @@ ShadowCanvasLayerOGL::Initialize(const D
   NS_RUNTIMEABORT("Incompatibe surface type");
 }
 
 void
 ShadowCanvasLayerOGL::Init(const CanvasSurface& aNewFront, bool needYFlip)
 {
   nsRefPtr<gfxASurface> surf = ShadowLayerForwarder::OpenDescriptor(aNewFront);
 
+  mNeedsYFlip = needYFlip;
+
   mTexImage = gl()->CreateTextureImage(surf->GetSize(),
                                        surf->GetContentType(),
-                                       LOCAL_GL_CLAMP_TO_EDGE);
-  mNeedsYFlip = needYFlip;
+                                       LOCAL_GL_CLAMP_TO_EDGE,
+                                       mNeedsYFlip ? TextureImage::NeedsYFlip : TextureImage::NoFlags);
 }
 
 void
 ShadowCanvasLayerOGL::Swap(const CanvasSurface& aNewFront,
                            bool needYFlip,
                            CanvasSurface* aNewBack)
 {
   if (!mDestroyed) {
--- a/gfx/src/nsDeviceContext.cpp
+++ b/gfx/src/nsDeviceContext.cpp
@@ -36,17 +36,16 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsDeviceContext.h"
 #include "nsCRT.h"
 #include "nsFontMetrics.h"
 #include "nsRenderingContext.h"
-#include "nsIView.h"
 #include "nsIWidget.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/Services.h"
 #include "mozilla/Preferences.h"
 #include "nsIServiceManager.h"
 #include "nsILanguageAtomService.h"
 #include "nsIObserver.h"
--- a/hal/gonk/GonkHal.cpp
+++ b/hal/gonk/GonkHal.cpp
@@ -12,16 +12,17 @@
 #include <time.h>
 
 #include "android/log.h"
 #include "cutils/properties.h"
 #include "hardware/hardware.h"
 #include "hardware/lights.h"
 #include "hardware_legacy/uevent.h"
 #include "hardware_legacy/vibrator.h"
+#include "hardware_legacy/power.h"
 
 #include "base/message_loop.h"
 
 #include "Hal.h"
 #include "HalImpl.h"
 #include "mozilla/dom/battery/Constants.h"
 #include "mozilla/FileUtils.h"
 #include "mozilla/Monitor.h"
@@ -326,17 +327,16 @@ GetCurrentBatteryInformation(hal::Batter
   aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime;
 }
 
 namespace {
 
 /**
  * RAII class to help us remember to close file descriptors.
  */
-const char *screenEnabledFilename = "/sys/power/state";
 const char *wakeLockFilename = "/sys/power/wake_lock";
 const char *wakeUnlockFilename = "/sys/power/wake_unlock";
 
 template<ssize_t n>
 bool ReadFromFile(const char *filename, char (&buf)[n])
 {
   int fd = open(filename, O_RDONLY);
   ScopedClose autoClose(fd);
@@ -387,17 +387,17 @@ bool
 GetScreenEnabled()
 {
   return sScreenEnabled;
 }
 
 void
 SetScreenEnabled(bool enabled)
 {
-  WriteToFile(screenEnabledFilename, enabled ? "on" : "mem");
+  set_screen_state(enabled);
   sScreenEnabled = enabled;
 }
 
 double
 GetScreenBrightness()
 {
   hal::LightConfiguration aConfig;
   hal::LightType light = hal::eHalLightID_Backlight;
--- a/hal/gonk/GonkSensor.cpp
+++ b/hal/gonk/GonkSensor.cpp
@@ -181,19 +181,16 @@ class PollSensor {
 
       int n = device.poll(buffer, numEventMax);
       if (n < 0) {
         LOG("Error polling for sensor data (err=%d)", n);
         return;
       }
 
       for (int i = 0; i < n; ++i) {
-        if (SensorseventStatus(buffer[i]) == SENSOR_STATUS_UNRELIABLE) {
-          continue;
-        }
         NS_DispatchToMainThread(new SensorRunnable(buffer[i]));
       }
 
       if (sActivatedSensors) {
         sSwitchThread->Dispatch(GetRunnable(), NS_DISPATCH_NORMAL);
       }
     }
   private:
--- a/image/test/reftest/reftest.list
+++ b/image/test/reftest/reftest.list
@@ -15,20 +15,20 @@ include pngsuite-corrupted/reftest.list
 include pngsuite-filtering/reftest.list
 include pngsuite-gamma/reftest.list
 include pngsuite-oddsizes/reftest.list
 include pngsuite-palettes/reftest.list
 include pngsuite-transparency/reftest.list
 include pngsuite-zlib/reftest.list
 
 # BMP tests
-skip-if(Android) include bmp/reftest.list
+include bmp/reftest.list
 
 # ICO tests
-skip-if(Android) include ico/reftest.list
+include ico/reftest.list
 
 # JPEG tests
 include jpeg/reftest.list
 
 # GIF tests
 include gif/reftest.list
 
 # APNG tests
@@ -39,10 +39,10 @@ include icon/win/reftest.list
 
 # Generic image tests
 include generic/reftest.list
 
 # Color management test
 include color-management/reftest.list
 
 # Lossless encoders
-skip-if(Android) include encoders-lossless/reftest.list
+include encoders-lossless/reftest.list
 
--- a/ipc/chromium/src/base/histogram.cc
+++ b/ipc/chromium/src/base/histogram.cc
@@ -144,16 +144,22 @@ void Histogram::Subtract(int value) {
 void Histogram::AddBoolean(bool value) {
   DCHECK(false);
 }
 
 void Histogram::AddSampleSet(const SampleSet& sample) {
   sample_.Add(sample);
 }
 
+void Histogram::Clear() {
+  SampleSet ss;
+  ss.Resize(*this);
+  sample_ = ss;
+}
+
 void Histogram::SetRangeDescriptions(const DescriptionPair descriptions[]) {
   DCHECK(false);
 }
 
 // The following methods provide a graphical histogram display.
 void Histogram::WriteHTMLGraph(std::string* output) const {
   // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc.
   output->append("<PRE>");
--- a/ipc/chromium/src/base/histogram.h
+++ b/ipc/chromium/src/base/histogram.h
@@ -390,16 +390,18 @@ class Histogram {
 
   // Accept a TimeDelta to increment.
   void AddTime(TimeDelta time) {
     Add(static_cast<int>(time.InMilliseconds()));
   }
 
   virtual void AddSampleSet(const SampleSet& sample);
 
+  void Clear();
+
   // This method is an interface, used only by LinearHistogram.
   virtual void SetRangeDescriptions(const DescriptionPair descriptions[]);
 
   // The following methods provide graphical histogram displays.
   void WriteHTMLGraph(std::string* output) const;
   void WriteAscii(bool graph_it, const std::string& newline,
                   std::string* output) const;
 
--- a/ipc/dbus/DBusThread.cpp
+++ b/ipc/dbus/DBusThread.cpp
@@ -271,16 +271,24 @@ static void HandleWatchRemove(DBusThread
     LOG("Cannot read DBus watch remove flag data from socket!\n");
     return;
   }
   short events = DBusFlagsToUnixEvents(flags);
   pollfd p;
   p.fd = removeFD;
   p.events = events;
   int index = aDbt->mPollData.IndexOf(p, 0, PollFdComparator());
+  // There are times where removes can be requested for watches that
+  // haven't been added (for example, whenever gecko comes up after
+  // adapters have already been enabled), so check to make sure we're
+  // using the watch in the first place
+  if(index < 0) {
+    LOG("DBus requested watch removal of non-existant socket, ignoring...");
+    return;
+  }
   aDbt->mPollData.RemoveElementAt(index);
 
   // DBusWatch pointers are maintained by DBus, so we won't leak by
   // removing.
   aDbt->mWatchData.RemoveElementAt(index);
 }
 
 // Called by dbus during WaitForAndDispatchEventNative()
--- a/js/public/HashTable.h
+++ b/js/public/HashTable.h
@@ -242,27 +242,31 @@ class HashTable : private AllocPolicy
             removed = true;
         }
 
         /*
          * Removes the |front()| element and re-inserts it into the table with
          * a new key at the new Lookup position.  |front()| is invalid after
          * this operation until the next call to |popFront()|.
          */
-        void rekeyFront(const Key &k) {
+        void rekeyFront(const Lookup &l, const Key &k) {
             JS_ASSERT(&k != &HashPolicy::getKey(this->cur->t));
-            if (table.match(*this->cur, k))
+            if (match(*this->cur, l))
                 return;
             Entry e = *this->cur;
             HashPolicy::setKey(e.t, const_cast<Key &>(k));
             table.remove(*this->cur);
-            table.add(k, e);
+            table.add(l, e);
             added = true;
         }
 
+        void rekeyFront(const Key &k) {
+            rekeyFront(k, k);
+        }
+
         /* Potentially rehashes the table. */
         ~Enum() {
             if (added)
                 table.checkOverloaded();
             if (removed)
                 table.checkUnderloaded();
         }
 
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -160,16 +160,17 @@ CPPSRCS		= \
 		BytecodeEmitter.cpp \
 		FoldConstants.cpp \
 		ParallelArray.cpp \
 		ParseMaps.cpp \
 		ParseNode.cpp \
 		Parser.cpp \
 		SemanticAnalysis.cpp \
 		TokenStream.cpp \
+		TreeContext.cpp \
 		TestingFunctions.cpp \
 		LifoAlloc.cpp \
 		MapObject.cpp \
 		MemoryMetrics.cpp \
 		RegExpObject.cpp \
 		RegExpStatics.cpp \
 		RegExp.cpp \
 		Marking.cpp \
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -258,16 +258,30 @@ GCSlice(JSContext *cx, unsigned argc, js
     }
 
     GCDebugSlice(cx->runtime, limit, budget);
     *vp = JSVAL_VOID;
     return JS_TRUE;
 }
 
 static JSBool
+GCPreserveCode(JSContext *cx, unsigned argc, jsval *vp)
+{
+    if (argc != 0) {
+        ReportUsageError(cx, &JS_CALLEE(cx, vp).toObject(), "Wrong number of arguments");
+        return JS_FALSE;
+    }
+
+    cx->runtime->alwaysPreserveCode = true;
+
+    *vp = JSVAL_VOID;
+    return JS_TRUE;
+}
+
+static JSBool
 DeterministicGC(JSContext *cx, unsigned argc, jsval *vp)
 {
     if (argc != 1) {
         ReportUsageError(cx, &JS_CALLEE(cx, vp).toObject(), "Wrong number of arguments");
         return JS_FALSE;
     }
 
     gc::SetDeterministicGC(cx, js_ValueToBoolean(vp[2]));
@@ -548,16 +562,20 @@ static JSFunctionSpecWithHelp TestingFun
     JS_FN_HELP("verifybarriers", VerifyBarriers, 0, 0,
 "verifybarriers()",
 "  Start or end a run of the write barrier verifier."),
 
     JS_FN_HELP("gcslice", GCSlice, 1, 0,
 "gcslice(n)",
 "  Run an incremental GC slice that marks about n objects."),
 
+    JS_FN_HELP("gcPreserveCode", GCPreserveCode, 0, 0,
+"gcPreserveCode()",
+"  Preserve JIT code during garbage collections."),
+
     JS_FN_HELP("deterministicgc", DeterministicGC, 1, 0,
 "deterministicgc(true|false)",
 "  If true, only allow determinstic GCs to run."),
 #endif
 
     JS_FN_HELP("internalConst", InternalConst, 1, 0,
 "internalConst(name)",
 "  Query an internal constant for the engine. See InternalConst source for\n"
--- a/js/src/config/autoconf.mk.in
+++ b/js/src/config/autoconf.mk.in
@@ -304,17 +304,16 @@ AIX_OBJMODEL = @AIX_OBJMODEL@
 MOZ_OS2_TOOLS = @MOZ_OS2_TOOLS@
 MOZ_OS2_HIGH_MEMORY = @MOZ_OS2_HIGH_MEMORY@
 
 MOZILLA_OFFICIAL = @MOZILLA_OFFICIAL@
 
 # Win32 options
 MOZ_BROWSE_INFO	= @MOZ_BROWSE_INFO@
 MOZ_TOOLS_DIR	= @MOZ_TOOLS_DIR@
-MOZ_QUANTIFY	= @MOZ_QUANTIFY@
 MSMANIFEST_TOOL = @MSMANIFEST_TOOL@
 MOZ_GLUE_LDFLAGS = @MOZ_GLUE_LDFLAGS@
 MOZ_GLUE_PROGRAM_LDFLAGS = @MOZ_GLUE_PROGRAM_LDFLAGS@
 
 # Codesighs tools option, enables win32 mapfiles.
 MOZ_MAPINFO	= @MOZ_MAPINFO@
 
 QEMU_CANT_RUN_JS_SHELL = @QEMU_CANT_RUN_JS_SHELL@
--- a/js/src/config/config.mk
+++ b/js/src/config/config.mk
@@ -216,27 +216,16 @@ OS_CXXFLAGS += -UDEBUG -DNDEBUG
 OS_CFLAGS += -UDEBUG -DNDEBUG
 ifdef HAVE_64BIT_OS
 OS_LDFLAGS += -DEBUG -OPT:REF,ICF
 else
 OS_LDFLAGS += -DEBUG -OPT:REF
 endif
 endif
 
-ifdef MOZ_QUANTIFY
-# -FIXED:NO is needed for Quantify to work, but it increases the size
-# of executables, so only use it if building for Quantify.
-WIN32_EXE_LDFLAGS += -FIXED:NO
-
-# We need -OPT:NOICF to prevent identical methods from being merged together.
-# Otherwise, Quantify doesn't know which method was actually called when it's
-# showing you the profile.
-OS_LDFLAGS += -OPT:NOICF
-endif
-
 #
 # Handle trace-malloc in optimized builds.
 # No opt to give sane callstacks.
 #
 ifdef NS_TRACE_MALLOC
 MOZ_OPTIMIZE_FLAGS=-Zi -Od -UDEBUG -DNDEBUG
 ifdef HAVE_64BIT_OS
 OS_LDFLAGS = -DEBUG -PDB:NONE -OPT:REF,ICF
@@ -398,18 +387,16 @@ endif
 #
 MY_CONFIG	:= $(DEPTH)/config/myconfig.mk
 MY_RULES	:= $(DEPTH)/config/myrules.mk
 
 #
 # Default command macros; can be overridden in <arch>.mk.
 #
 CCC = $(CXX)
-PURIFY = purify $(PURIFYOPTIONS)
-QUANTIFY = quantify $(QUANTIFYOPTIONS)
 XPIDL_LINK = $(PYTHON) $(LIBXUL_DIST)/sdk/bin/xpt.py link
 
 # Java macros
 JAVA_GEN_DIR  = _javagen
 JAVA_DIST_DIR = $(DEPTH)/$(JAVA_GEN_DIR)
 JAVA_IFACES_PKG_NAME = org/mozilla/interfaces
 
 INCLUDES = \
--- a/js/src/config/rules.mk
+++ b/js/src/config/rules.mk
@@ -490,19 +490,16 @@ endif
 #
 TAG_PROGRAM		= xargs etags -a
 
 #
 # Turn on C++ linking if we have any .cpp or .mm files
 # (moved this from config.mk so that config.mk can be included
 #  before the CPPSRCS are defined)
 #
-ifneq ($(CPPSRCS)$(CMMSRCS),)
-CPP_PROG_LINK		= 1
-endif
 ifneq ($(HOST_CPPSRCS)$(HOST_CMMSRCS),)
 HOST_CPP_PROG_LINK	= 1
 endif
 
 #
 # This will strip out symbols that the component should not be
 # exporting from the .dynsym section.
 #
@@ -949,41 +946,16 @@ ifeq (WINNT_,$(HOST_OS_ARCH)_$(GNU_CC))
 else
 ifneq (,$(HOST_CPPSRCS)$(USE_HOST_CXX))
 	$(HOST_CXX) $(HOST_OUTOPTION)$@ $(HOST_CXXFLAGS) $(INCLUDES) $< $(HOST_LIBS) $(HOST_EXTRA_LIBS)
 else
 	$(HOST_CC) $(HOST_OUTOPTION)$@ $(HOST_CFLAGS) $(INCLUDES) $< $(HOST_LIBS) $(HOST_EXTRA_LIBS)
 endif
 endif
 
-#
-# Purify target.  Solaris/sparc only to start.
-# Purify does not recognize "egcs" or "c++" so we go with
-# "gcc" and "g++" for now.
-#
-pure:	$(PROGRAM)
-ifeq ($(CPP_PROG_LINK),1)
-	$(PURIFY) $(CCC) -o $^.pure $(CXXFLAGS) $(PROGOBJS) $(LDFLAGS) $(LIBS_DIR) $(LIBS) $(OS_LIBS) $(EXTRA_LIBS)
-else
-	$(PURIFY) $(CC) -o $^.pure $(CFLAGS) $(PROGOBJS) $(LDFLAGS) $(LIBS_DIR) $(LIBS) $(OS_LIBS) $(EXTRA_LIBS)
-endif
-ifndef NO_DIST_INSTALL
-	$(INSTALL) $(IFLAGS2) $^.pure $(FINAL_TARGET)
-endif
-
-quantify: $(PROGRAM)
-ifeq ($(CPP_PROG_LINK),1)
-	$(QUANTIFY) $(CCC) -o $^.quantify $(CXXFLAGS) $(PROGOBJS) $(LDFLAGS) $(LIBS_DIR) $(LIBS) $(OS_LIBS) $(EXTRA_LIBS)
-else
-	$(QUANTIFY) $(CC) -o $^.quantify $(CFLAGS) $(PROGOBJS) $(LDFLAGS) $(LIBS_DIR) $(LIBS) $(OS_LIBS) $(EXTRA_LIBS)
-endif
-ifndef NO_DIST_INSTALL
-	$(INSTALL) $(IFLAGS2) $^.quantify $(FINAL_TARGET)
-endif
-
 ifdef DTRACE_PROBE_OBJ
 EXTRA_DEPS += $(DTRACE_PROBE_OBJ)
 OBJS += $(DTRACE_PROBE_OBJ)
 endif
 
 $(filter %.$(LIB_SUFFIX),$(LIBRARY)): $(OBJS) $(LOBJS) $(SHARED_LIBRARY_LIBS_DEPS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
 	$(RM) $(LIBRARY)
 	$(EXPAND_AR) $(AR_FLAGS) $(OBJS) $(LOBJS) $(SHARED_LIBRARY_LIBS)
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -4384,24 +4384,16 @@ MOZ_ARG_ENABLE_BOOL(install-strip,
 dnl ========================================================
 dnl =
 dnl = Profiling and Instrumenting
 dnl =
 dnl ========================================================
 MOZ_ARG_HEADER(Profiling and Instrumenting)
 
 dnl ========================================================
-dnl = Support for Quantify (Windows)
-dnl ========================================================
-MOZ_ARG_ENABLE_BOOL(quantify,
-[  --enable-quantify       Enable Quantify support (Windows only) ],
-    MOZ_QUANTIFY=1,
-    MOZ_QUANTIFY= )
-
-dnl ========================================================
 dnl = Support for demangling undefined symbols
 dnl ========================================================
 if test -z "$SKIP_LIBRARY_CHECKS"; then
     AC_LANG_SAVE
     AC_LANG_CPLUSPLUS
     AC_CHECK_FUNCS(__cxa_demangle, HAVE_DEMANGLE=1, HAVE_DEMANGLE=)
     AC_LANG_RESTORE
 fi
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -6616,20 +6616,38 @@ CDataFinalizer::Construct(JSContext* cx,
 
   // 5. Create |objResult|
 
   JSObject *objResult = JS_NewObject(cx, &sCDataFinalizerClass, objProto, NULL);
   if (!objResult) {
     return JS_FALSE;
   }
 
+  // If our argument is a CData, it holds a type.
+  // This is the type that we should capture, not that
+  // of the function, which may be less precise.
+  JSObject *objBestArgType = objArgType;
+  if (!JSVAL_IS_PRIMITIVE(valData)) {
+    JSObject *objData = JSVAL_TO_OBJECT(valData);
+    if (CData::IsCData(objData)) {
+      objBestArgType = CData::GetCType(objData);
+      size_t sizeBestArg;
+      if (!CType::GetSafeSize(objBestArgType, &sizeBestArg)) {
+        JS_NOT_REACHED("object with unknown size");
+      }
+      if (sizeBestArg != sizeArg) {
+        return TypeError(cx, "(an object with the same size as that expected by the C finalization function)", valData);
+      }
+    }
+  }
+
   // Used by GetCType
   JS_SetReservedSlot(objResult,
                      SLOT_DATAFINALIZER_VALTYPE,
-                     OBJECT_TO_JSVAL(objArgType));
+                     OBJECT_TO_JSVAL(objBestArgType));
 
   // Used by ToSource
   JS_SetReservedSlot(objResult,
                      SLOT_DATAFINALIZER_CODETYPE,
                      OBJECT_TO_JSVAL(objCodePtrType));
 
   ffi_abi abi;
   if (!GetABI(cx, OBJECT_TO_JSVAL(funInfoFinalizer->mABI), &abi)) {
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -44,75 +44,30 @@
 
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/FoldConstants.h"
 #include "frontend/SemanticAnalysis.h"
 #include "vm/GlobalObject.h"
 
 #include "jsinferinlines.h"
 
+#include "frontend/TreeContext-inl.h"
+
 using namespace js;
 using namespace js::frontend;
 
 bool
-DefineGlobals(JSContext *cx, GlobalScope &globalScope, JSScript* script)
+MarkInnerAndOuterFunctions(JSContext *cx, JSScript* script)
 {
     Root<JSScript*> root(cx, &script);
 
-    HandleObject globalObj = globalScope.globalObj;
-
-    /* Define and update global properties. */
-    for (size_t i = 0; i < globalScope.defs.length(); i++) {
-        GlobalScope::GlobalDef &def = globalScope.defs[i];
-
-        /* Names that could be resolved ahead of time can be skipped. */
-        if (!def.atom)
-            continue;
-
-        jsid id = AtomToId(def.atom);
-        Value rval;
-
-        if (def.funbox) {
-            JSFunction *fun = def.funbox->function();
-
-            /*
-             * No need to check for redeclarations or anything, global
-             * optimizations only take place if the property is not defined.
-             */
-            rval.setObject(*fun);
-            types::AddTypePropertyId(cx, globalObj, id, rval);
-        } else {
-            rval.setUndefined();
-        }
-
-        /*
-         * Don't update the type information when defining the property for the
-         * global object, per the consistency rules for type properties. If the
-         * property is only undefined before it is ever written, we can check
-         * the global directly during compilation and avoid having to emit type
-         * checks every time it is accessed in the script.
-         */
-        const Shape *shape =
-            DefineNativeProperty(cx, globalObj, id, rval, JS_PropertyStub, JS_StrictPropertyStub,
-                                 JSPROP_ENUMERATE | JSPROP_PERMANENT, 0, 0, DNP_SKIP_TYPE);
-        if (!shape)
-            return false;
-        def.knownSlot = shape->slot();
-    }
-
     Vector<JSScript *, 16> worklist(cx);
     if (!worklist.append(script))
         return false;
 
-    /*
-     * Recursively walk through all scripts we just compiled. For each script,
-     * go through all global uses. Each global use indexes into globalScope->defs.
-     * Use this information to repoint each use to the correct slot in the global
-     * object.
-     */
     while (worklist.length()) {
         JSScript *outer = worklist.back();
         worklist.popBack();
 
         if (outer->hasObjects()) {
             ObjectArray *arr = outer->objects();
 
             /*
@@ -127,33 +82,22 @@ DefineGlobals(JSContext *cx, GlobalScope
                     continue;
                 JSFunction *fun = obj->toFunction();
                 JS_ASSERT(fun->isInterpreted());
                 JSScript *inner = fun->script();
                 if (outer->function() && outer->function()->isHeavyweight()) {
                     outer->isOuterFunction = true;
                     inner->isInnerFunction = true;
                 }
-                if (!inner->hasGlobals() && !inner->hasObjects())
+                if (!inner->hasObjects())
                     continue;
                 if (!worklist.append(inner))
                     return false;
             }
         }
-
-        if (!outer->hasGlobals())
-            continue;
-
-        GlobalSlotArray *globalUses = outer->globals();
-        uint32_t nGlobalUses = globalUses->length;
-        for (uint32_t i = 0; i < nGlobalUses; i++) {
-            uint32_t index = globalUses->vector[i].slot;
-            JS_ASSERT(index < globalScope.defs.length());
-            globalUses->vector[i].slot = globalScope.defs[index].knownSlot;
-        }
     }
 
     return true;
 }
 
 JSScript *
 frontend::CompileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerFrame,
                         JSPrincipals *principals, JSPrincipals *originPrincipals,
@@ -195,17 +139,17 @@ frontend::CompileScript(JSContext *cx, J
                           ? &scopeChain->global()
                           : NULL;
 
     JS_ASSERT_IF(globalObj, globalObj->isNative());
     JS_ASSERT_IF(globalObj, JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(globalObj->getClass()));
 
     RootedVar<JSScript*> script(cx);
 
-    GlobalScope globalScope(cx, globalObj, &bce);
+    GlobalScope globalScope(cx, globalObj);
     bce.flags |= tcflags;
     bce.setScopeChain(scopeChain);
     bce.globalScope = &globalScope;
     if (!SetStaticLevel(&bce, staticLevel))
         goto out;
 
     /* If this is a direct call to eval, inherit the caller's strictness.  */
     if (callerFrame &&
@@ -278,31 +222,31 @@ frontend::CompileScript(JSContext *cx, J
         pn = parser.statement();
         if (!pn)
             goto out;
         JS_ASSERT(!bce.blockNode);
 
         if (inDirectivePrologue && !parser.recognizeDirectivePrologue(pn, &inDirectivePrologue))
             goto out;
 
-        if (!FoldConstants(cx, pn, &bce))
+        if (!FoldConstants(cx, pn, bce.parser))
             goto out;
 
-        if (!AnalyzeFunctions(&bce))
+        if (!AnalyzeFunctions(bce.parser))
             goto out;
         bce.functionList = NULL;
 
         if (!EmitTree(cx, &bce, pn))
             goto out;
 
 #if JS_HAS_XML_SUPPORT
         if (!pn->isKind(PNK_SEMI) || !pn->pn_kid || !pn->pn_kid->isXMLItem())
             onlyXML = false;
 #endif
-        bce.freeTree(pn);
+        bce.parser->freeTree(pn);
     }
 
 #if JS_HAS_XML_SUPPORT
     /*
      * Prevent XML data theft via <script src="http://victim.com/foo.xml">.
      * For background, see:
      *
      * https://bugzilla.mozilla.org/show_bug.cgi?id=336551
@@ -323,17 +267,17 @@ frontend::CompileScript(JSContext *cx, J
     JS_ASSERT(bce.version() == version);
 
     script = JSScript::NewScriptFromEmitter(cx, &bce);
     if (!script)
         goto out;
 
     JS_ASSERT(script->savedCallerFun == savedCallerFun);
 
-    if (!DefineGlobals(cx, globalScope, script))
+    if (!MarkInnerAndOuterFunctions(cx, script))
         script = NULL;
 
   out:
     Probes::compileScriptEnd(cx, script, filename, lineno);
     return script;
 }
 
 /*
@@ -359,33 +303,33 @@ frontend::CompileFunctionBody(JSContext 
     funbce.flags |= TCF_IN_FUNCTION;
     funbce.setFunction(fun);
     funbce.bindings.transfer(cx, bindings);
     fun->setArgCount(funbce.bindings.numArgs());
     if (!GenerateBlockId(&funbce, funbce.bodyid))
         return false;
 
     /* FIXME: make Function format the source for a function definition. */
-    ParseNode *fn = FunctionNode::create(PNK_NAME, &funbce);
+    ParseNode *fn = FunctionNode::create(PNK_NAME, funbce.parser);
     if (fn) {
         fn->pn_body = NULL;
         fn->pn_cookie.makeFree();
 
         unsigned nargs = fun->nargs;
         if (nargs) {
             /*
              * NB: do not use AutoLocalNameArray because it will release space
              * allocated from cx->tempLifoAlloc by DefineArg.
              */
             BindingNames names(cx);
             if (!funbce.bindings.getLocalNameArray(cx, &names)) {
                 fn = NULL;
             } else {
                 for (unsigned i = 0; i < nargs; i++) {
-                    if (!DefineArg(fn, names[i].maybeAtom, i, &funbce)) {
+                    if (!DefineArg(fn, names[i].maybeAtom, i, funbce.parser)) {
                         fn = NULL;
                         break;
                     }
                 }
             }
         }
     }
 
@@ -394,20 +338,20 @@ frontend::CompileFunctionBody(JSContext 
      * functions, and generate code for this function, including a stop opcode
      * at the end.
      */
     ParseNode *pn = fn ? parser.functionBody(Parser::StatementListBody) : NULL;
     if (pn) {
         if (!tokenStream.matchToken(TOK_EOF)) {
             parser.reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
             pn = NULL;
-        } else if (!FoldConstants(cx, pn, &funbce)) {
+        } else if (!FoldConstants(cx, pn, funbce.parser)) {
             /* FoldConstants reported the error already. */
             pn = NULL;
-        } else if (!AnalyzeFunctions(&funbce)) {
+        } else if (!AnalyzeFunctions(funbce.parser)) {
             pn = NULL;
         } else {
             if (fn->pn_body) {
                 JS_ASSERT(fn->pn_body->isKind(PNK_ARGSBODY));
                 fn->pn_body->append(pn);
                 fn->pn_body->pn_pos = pn->pn_pos;
                 pn = fn->pn_body;
             }
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -70,19 +70,19 @@
 #include "frontend/Parser.h"
 #include "frontend/TokenStream.h"
 #include "vm/RegExpObject.h"
 
 #include "jsatominlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 
-#include "frontend/BytecodeEmitter-inl.h"
 #include "frontend/ParseMaps-inl.h"
 #include "frontend/ParseNode-inl.h"
+#include "frontend/TreeContext-inl.h"
 
 /* Allocation chunk counts, must be powers of two in general. */
 #define BYTECODE_CHUNK_LENGTH  1024    /* initial bytecode chunk length */
 #define SRCNOTE_CHUNK_LENGTH   1024    /* initial srcnote chunk length */
 
 /* Macros to compute byte sizes from typed element counts. */
 #define BYTECODE_SIZE(n)        ((n) * sizeof(jsbytecode))
 #define SRCNOTE_SIZE(n)         ((n) * sizeof(jssrcnote))
@@ -93,39 +93,31 @@ using namespace js::frontend;
 
 static JSBool
 NewTryNote(JSContext *cx, BytecodeEmitter *bce, JSTryNoteKind kind, unsigned stackDepth,
            size_t start, size_t end);
 
 static JSBool
 SetSrcNoteOffset(JSContext *cx, BytecodeEmitter *bce, unsigned index, unsigned which, ptrdiff_t offset);
 
-void
-TreeContext::trace(JSTracer *trc)
-{
-    bindings.trace(trc);
-}
-
 BytecodeEmitter::BytecodeEmitter(Parser *parser, unsigned lineno)
   : TreeContext(parser),
+    parser(parser),
     atomIndices(parser->context),
     stackDepth(0), maxStackDepth(0),
     ntrynotes(0), lastTryNode(NULL),
     arrayCompDepth(0),
     emitLevel(0),
     constMap(parser->context),
     constList(parser->context),
     globalScope(NULL),
-    globalUses(parser->context),
-    globalMap(parser->context),
     closedArgs(parser->context),
     closedVars(parser->context),
     typesetCount(0)
 {
-    flags = TCF_COMPILING;
     memset(&prolog, 0, sizeof prolog);
     memset(&main, 0, sizeof main);
     current = &main;
     firstLine = prolog.currentLine = main.currentLine = lineno;
 }
 
 bool
 BytecodeEmitter::init(JSContext *cx, TreeContext::InitBehavior ib)
@@ -361,75 +353,16 @@ StatementName(BytecodeEmitter *bce)
 
 static void
 ReportStatementTooLarge(JSContext *cx, BytecodeEmitter *bce)
 {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NEED_DIET,
                          StatementName(bce));
 }
 
-bool
-frontend::SetStaticLevel(TreeContext *tc, unsigned staticLevel)
-{
-    /*
-     * This is a lot simpler than error-checking every UpvarCookie::set, and
-     * practically speaking it leaves more than enough room for upvars.
-     */
-    if (UpvarCookie::isLevelReserved(staticLevel)) {
-        JS_ReportErrorNumber(tc->parser->context, js_GetErrorMessage, NULL,
-                             JSMSG_TOO_DEEP, js_function_str);
-        return false;
-    }
-    tc->staticLevel = staticLevel;
-    return true;
-}
-
-bool
-frontend::GenerateBlockId(TreeContext *tc, uint32_t &blockid)
-{
-    if (tc->blockidGen == JS_BIT(20)) {
-        JS_ReportErrorNumber(tc->parser->context, js_GetErrorMessage, NULL,
-                             JSMSG_NEED_DIET, "program");
-        return false;
-    }
-    blockid = tc->blockidGen++;
-    return true;
-}
-
-void
-frontend::PushStatement(TreeContext *tc, StmtInfo *stmt, StmtType type, ptrdiff_t top)
-{
-    stmt->type = type;
-    stmt->flags = 0;
-    stmt->blockid = tc->blockid();
-    SET_STATEMENT_TOP(stmt, top);
-    stmt->label = NULL;
-    stmt->blockObj = NULL;
-    stmt->down = tc->topStmt;
-    tc->topStmt = stmt;
-    if (STMT_LINKS_SCOPE(stmt)) {
-        stmt->downScope = tc->topScopeStmt;
-        tc->topScopeStmt = stmt;
-    } else {
-        stmt->downScope = NULL;
-    }
-}
-
-void
-frontend::PushBlockScope(TreeContext *tc, StmtInfo *stmt, StaticBlockObject &blockObj, ptrdiff_t top)
-{
-    PushStatement(tc, stmt, STMT_BLOCK, top);
-    stmt->flags |= SIF_SCOPE;
-    blockObj.setEnclosingBlock(tc->blockChain);
-    stmt->downScope = tc->topScopeStmt;
-    tc->topScopeStmt = stmt;
-    tc->blockChain = &blockObj;
-    stmt->blockObj = &blockObj;
-}
-
 /*
  * Emit a backpatch op with offset pointing to the previous jump of this type,
  * so that we can walk back up the chain fixing up the op and jump offset.
  */
 static ptrdiff_t
 EmitBackPatchOp(JSContext *cx, BytecodeEmitter *bce, JSOp op, ptrdiff_t *lastp)
 {
     ptrdiff_t offset, delta;
@@ -712,28 +645,16 @@ BackPatch(JSContext *cx, BytecodeEmitter
         span = target - pc;
         SET_JUMP_OFFSET(pc, span);
         *pc = op;
         pc -= delta;
     }
     return JS_TRUE;
 }
 
-void
-frontend::PopStatementTC(TreeContext *tc)
-{
-    StmtInfo *stmt = tc->topStmt;
-    tc->topStmt = stmt->down;
-    if (STMT_LINKS_SCOPE(stmt)) {
-        tc->topScopeStmt = stmt->downScope;
-        if (stmt->flags & SIF_SCOPE)
-            tc->blockChain = stmt->blockObj->enclosingBlock();
-    }
-}
-
 JSBool
 frontend::PopStatementBCE(JSContext *cx, BytecodeEmitter *bce)
 {
     StmtInfo *stmt = bce->topStmt;
     if (!STMT_IS_TRYING(stmt) &&
         (!BackPatch(cx, bce, stmt->breaks, bce->next(), JSOP_GOTO) ||
          !BackPatch(cx, bce, stmt->continues, bce->code(stmt->update), JSOP_GOTO)))
     {
@@ -749,45 +670,16 @@ frontend::DefineCompileTimeConstant(JSCo
     /* XXX just do numbers for now */
     if (pn->isKind(PNK_NUMBER)) {
         if (!bce->constMap.put(atom, NumberValue(pn->pn_dval)))
             return JS_FALSE;
     }
     return JS_TRUE;
 }
 
-StmtInfo *
-frontend::LexicalLookup(TreeContext *tc, JSAtom *atom, int *slotp, StmtInfo *stmt)
-{
-    if (!stmt)
-        stmt = tc->topScopeStmt;
-    for (; stmt; stmt = stmt->downScope) {
-        if (stmt->type == STMT_WITH)
-            break;
-
-        /* Skip "maybe scope" statements that don't contain let bindings. */
-        if (!(stmt->flags & SIF_SCOPE))
-            continue;
-
-        StaticBlockObject &blockObj = *stmt->blockObj;
-        const Shape *shape = blockObj.nativeLookup(tc->parser->context, AtomToId(atom));
-        if (shape) {
-            JS_ASSERT(shape->hasShortID());
-
-            if (slotp)
-                *slotp = blockObj.stackDepth() + shape->shortid();
-            return stmt;
-        }
-    }
-
-    if (slotp)
-        *slotp = -1;
-    return stmt;
-}
-
 /*
  * The function sets vp to NO_CONSTANT when the atom does not corresponds to a
  * name defining a constant.
  */
 static JSBool
 LookupCompileTimeConstant(JSContext *cx, BytecodeEmitter *bce, JSAtom *atom, Value *constp)
 {
     /*
@@ -836,17 +728,19 @@ LookupCompileTimeConstant(JSContext *cx,
                         *constp = obj->nativeGetSlot(shape->slot());
                     }
                 }
 
                 if (shape)
                     break;
             }
         }
-    } while (bce->parent && (bce = bce->parent->asBytecodeEmitter()));
+        bce = bce->parentBCE();
+    } while (bce);
+
     return JS_TRUE;
 }
 
 static bool
 EmitIndex32(JSContext *cx, JSOp op, uint32_t index, BytecodeEmitter *bce)
 {
     const size_t len = 1 + UINT32_INDEX_LEN;
     JS_ASSERT(len == size_t(js_CodeSpec[op].length));
@@ -1221,21 +1115,21 @@ EmitEnterBlock(JSContext *cx, BytecodeEm
  *   {
  *     undeclared = 17; // throws ReferenceError
  *   }
  *   foo();
  */
 static bool
 TryConvertToGname(BytecodeEmitter *bce, ParseNode *pn, JSOp *op)
 {
-    if (bce->compileAndGo() && 
+    if (bce->compileAndGo() &&
         bce->globalScope->globalObj &&
         !bce->mightAliasLocals() &&
         !pn->isDeoptimized() &&
-        !(bce->flags & TCF_STRICT_MODE_CODE)) { 
+        !(bce->flags & TCF_STRICT_MODE_CODE)) {
         switch (*op) {
           case JSOP_NAME:     *op = JSOP_GETGNAME; break;
           case JSOP_SETNAME:  *op = JSOP_SETGNAME; break;
           case JSOP_INCNAME:  *op = JSOP_INCGNAME; break;
           case JSOP_NAMEINC:  *op = JSOP_GNAMEINC; break;
           case JSOP_DECNAME:  *op = JSOP_DECGNAME; break;
           case JSOP_NAMEDEC:  *op = JSOP_GNAMEDEC; break;
           case JSOP_SETCONST:
@@ -1244,84 +1138,16 @@ TryConvertToGname(BytecodeEmitter *bce, 
             return false;
           default: JS_NOT_REACHED("gname");
         }
         return true;
     }
     return false;
 }
 
-// Binds a global, given a |dn| that is known to have the PND_GVAR bit, and a pn
-// that is |dn| or whose definition is |dn|. |pn->pn_cookie| is an outparam
-// that will be free (meaning no binding), or a slot number.
-static bool
-BindKnownGlobal(JSContext *cx, BytecodeEmitter *bce, ParseNode *dn, ParseNode *pn, JSAtom *atom)
-{
-    // Cookie is an outparam; make sure caller knew to clear it.
-    JS_ASSERT(pn->pn_cookie.isFree());
-
-    if (bce->mightAliasLocals())
-        return true;
-
-    GlobalScope *globalScope = bce->globalScope;
-
-    jsatomid index;
-    if (dn->pn_cookie.isFree()) {
-        // The definition wasn't bound, so find its atom's index in the
-        // mapping of defined globals.
-        AtomIndexPtr p = globalScope->names.lookup(atom);
-        JS_ASSERT(!!p);
-        index = p.value();
-    } else {
-        BytecodeEmitter *globalbce = globalScope->bce;
-
-        // If the definition is bound, and we're in the same bce, we can re-use
-        // its cookie.
-        if (globalbce == bce) {
-            pn->pn_cookie = dn->pn_cookie;
-            pn->pn_dflags |= PND_BOUND;
-            return true;
-        }
-
-        // Otherwise, find the atom's index by using the originating bce's
-        // global use table.
-        index = globalbce->globalUses[dn->pn_cookie.slot()].slot;
-    }
-
-    if (!bce->addGlobalUse(atom, index, &pn->pn_cookie))
-        return false;
-
-    if (!pn->pn_cookie.isFree())
-        pn->pn_dflags |= PND_BOUND;
-
-    return true;
-}
-
-// See BindKnownGlobal()'s comment.
-static bool
-BindGlobal(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSAtom *atom)
-{
-    pn->pn_cookie.makeFree();
-
-    Definition *dn;
-    if (pn->isUsed()) {
-        dn = pn->pn_lexdef;
-    } else {
-        if (!pn->isDefn())
-            return true;
-        dn = (Definition *)pn;
-    }
-
-    // Only optimize for defined globals.
-    if (!dn->isGlobal())
-        return true;
-
-    return BindKnownGlobal(cx, bce, dn, pn, atom);
-}
-
 /*
  * BindNameToSlot attempts to optimize name gets and sets to stack slot loads
  * and stores, given the compile-time information in bce and a PNK_NAME node pn.
  * It returns false on error, true on success.
  *
  * The caller can inspect pn->pn_cookie for FREE_UPVAR_COOKIE to tell whether
  * optimization occurred, in which case BindNameToSlot also updated pn->pn_op.
  * If pn->pn_cookie is still FREE_UPVAR_COOKIE on return, pn->pn_op still may
@@ -1408,39 +1234,16 @@ BindNameToSlot(JSContext *cx, BytecodeEm
                                            name.ptr())) {
                     return JS_FALSE;
                 }
             }
             pn->setOp(op = JSOP_NAME);
         }
     }
 
-    if (dn->isGlobal()) {
-        if (op == JSOP_NAME) {
-            /*
-             * If the definition is a defined global, not potentially aliased
-             * by a local variable, and not mutating the variable, try and
-             * optimize to a fast, unguarded global access.
-             */
-            if (!pn->pn_cookie.isFree()) {
-                pn->setOp(JSOP_GETGNAME);
-                pn->pn_dflags |= PND_BOUND;
-                return JS_TRUE;
-            }
-        }
-
-        /*
-         * The locally stored cookie here should really come from |pn|, not
-         * |dn|. For example, we could have a SETGNAME op's lexdef be a
-         * GETGNAME op, and their cookies have very different meanings. As
-         * a workaround, just make the cookie free.
-         */
-        cookie.makeFree();
-    }
-
     if (cookie.isFree()) {
         StackFrame *caller = bce->parser->callerFrame;
         if (caller) {
             JS_ASSERT(bce->compileAndGo());
 
             /*
              * Don't generate upvars on the left side of a for loop. See
              * bug 470758.
@@ -1579,50 +1382,16 @@ BindNameToSlot(JSContext *cx, BytecodeEm
 
     JS_ASSERT(!pn->isOp(op));
     pn->setOp(op);
     pn->pn_cookie.set(0, cookie.slot());
     pn->pn_dflags |= PND_BOUND;
     return JS_TRUE;
 }
 
-bool
-BytecodeEmitter::addGlobalUse(JSAtom *atom, uint32_t slot, UpvarCookie *cookie)
-{
-    if (!globalMap.ensureMap(context()))
-        return false;
-
-    AtomIndexAddPtr p = globalMap->lookupForAdd(atom);
-    if (p) {
-        jsatomid index = p.value();
-        cookie->set(0, index);
-        return true;
-    }
-
-    /* Don't bother encoding indexes >= uint16_t */
-    if (globalUses.length() >= UINT16_LIMIT) {
-        cookie->makeFree();
-        return true;
-    }
-
-    /* Find or add an existing atom table entry. */
-    jsatomid allAtomIndex;
-    if (!makeAtomIndex(atom, &allAtomIndex))
-        return false;
-
-    jsatomid globalUseIndex = globalUses.length();
-    cookie->set(0, globalUseIndex);
-
-    GlobalSlotArray::Entry entry = { allAtomIndex, slot };
-    if (!globalUses.append(entry))
-        return false;
-
-    return globalMap->add(p, atom, globalUseIndex);
-}
-
 /*
  * If pn contains a useful expression, return true with *answer set to true.
  * If pn contains a useless expression, return true with *answer set to false.
  * Return false on error.
  *
  * The caller should initialize *answer to false and invoke this function on
  * an expression statement or similar subtree to decide whether the tree could
  * produce code that has any side effects.  For an expression statement, we
@@ -2169,24 +1938,24 @@ EmitElemOp(JSContext *cx, ParseNode *pn,
          * Set left and right so pn appears to be a PNK_LB node, instead
          * of a PNK_DOT node.  See the PNK_FOR/IN case in EmitTree, and
          * EmitDestructuringOps nearer below.  In the destructuring case,
          * the base expression (pn_expr) of the name may be null, which
          * means we have to emit a JSOP_BINDNAME.
          */
         left = pn->maybeExpr();
         if (!left) {
-            left = NullaryNode::create(PNK_STRING, bce);
+            left = NullaryNode::create(PNK_STRING, bce->parser);
             if (!left)
                 return false;
             left->setOp(JSOP_BINDNAME);
             left->pn_pos = pn->pn_pos;
             left->pn_atom = pn->pn_atom;
         }
-        right = NullaryNode::create(PNK_STRING, bce);
+        right = NullaryNode::create(PNK_STRING, bce->parser);
         if (!right)
             return false;
         right->setOp(IsIdentifier(pn->pn_atom) ? JSOP_QNAMEPART : JSOP_STRING);
         right->pn_pos = pn->pn_pos;
         right->pn_atom = pn->pn_atom;
     } else {
         JS_ASSERT(pn->isArity(PN_BINARY));
         left = pn->pn_left;
@@ -2894,18 +2663,17 @@ MaybeEmitVarDecl(JSContext *cx, Bytecode
     if (!pn->pn_cookie.isFree()) {
         atomIndex = pn->pn_cookie.slot();
     } else {
         if (!bce->makeAtomIndex(pn->pn_atom, &atomIndex))
             return false;
     }
 
     if (JOF_OPTYPE(pn->getOp()) == JOF_ATOM &&
-        (!bce->inFunction() || (bce->flags & TCF_FUN_HEAVYWEIGHT)) &&
-        !(pn->pn_dflags & PND_GVAR))
+        (!bce->inFunction() || (bce->flags & TCF_FUN_HEAVYWEIGHT)))
     {
         bce->switchToProlog();
         if (!UpdateLineNumberNotes(cx, bce, pn->pn_pos.begin.lineno))
             return false;
         if (!EmitIndexOp(cx, prologOp, atomIndex, bce))
             return false;
         bce->switchToMain();
     }
@@ -3760,18 +3528,17 @@ EmitAssignment(JSContext *cx, BytecodeEm
                         return false;
                 }
             } else if (lhs->isOp(JSOP_SETNAME)) {
                 if (Emit1(cx, bce, JSOP_DUP) < 0)
                     return false;
                 if (!EmitIndex32(cx, JSOP_GETXPROP, atomIndex, bce))
                     return false;
             } else if (lhs->isOp(JSOP_SETGNAME)) {
-                if (!BindGlobal(cx, bce, lhs, lhs->pn_atom))
-                    return false;
+                JS_ASSERT(lhs->pn_cookie.isFree());
                 if (!EmitAtomOp(cx, lhs, JSOP_GETGNAME, bce))
                     return false;
             } else {
                 JSOp op = lhs->isOp(JSOP_SETARG) ? JSOP_GETARG : JSOP_GETLOCAL;
                 if (!EmitVarOp(cx, lhs, op, bce))
                     return false;
             }
             break;
@@ -5068,17 +4835,17 @@ EmitFunc(JSContext *cx, BytecodeEmitter 
     JS_ASSERT_IF(pn->pn_funbox->tcflags & TCF_FUN_HEAVYWEIGHT,
                  fun->kind() == JSFUN_INTERPRETED);
 
     {
         BytecodeEmitter bce2(bce->parser, pn->pn_pos.begin.lineno);
         if (!bce2.init(cx))
             return false;
 
-        bce2.flags = pn->pn_funbox->tcflags | TCF_COMPILING | TCF_IN_FUNCTION |
+        bce2.flags = pn->pn_funbox->tcflags | TCF_IN_FUNCTION |
                      (bce->flags & TCF_FUN_MIGHT_ALIAS_LOCALS);
         bce2.bindings.transfer(cx, &pn->pn_funbox->bindings);
         bce2.setFunction(fun);
         bce2.funbox = pn->pn_funbox;
         bce2.parent = bce;
         bce2.globalScope = bce->globalScope;
 
         /*
@@ -5115,18 +4882,17 @@ EmitFunc(JSContext *cx, BytecodeEmitter 
      * names in the variable object before the already-generated main code
      * is executed. This extra work for top-level scripts is not necessary
      * when we emit the code for a function. It is fully parsed prior to
      * invocation of the emitter and calls to EmitTree for function
      * definitions can be scheduled before generating the rest of code.
      */
     if (!bce->inFunction()) {
         JS_ASSERT(!bce->topStmt);
-        if (!BindGlobal(cx, bce, pn, fun->atom))
-            return false;
+        JS_ASSERT(pn->pn_cookie.isFree());
         if (pn->pn_cookie.isFree()) {
             bce->switchToProlog();
             if (!EmitFunctionOp(cx, JSOP_DEFFUN, index, bce))
                 return false;
             if (!UpdateLineNumberNotes(cx, bce, pn->pn_pos.begin.lineno))
                 return false;
             bce->switchToMain();
         }
@@ -5579,18 +5345,18 @@ EmitCallOrNew(JSContext *cx, BytecodeEmi
      * constructable object expression.
      *
      * For operator new applied to other expressions than E4X ones, we emit
      * JSOP_GETPROP instead of JSOP_CALLPROP, etc. This is necessary to
      * interpose the lambda-initialized method read barrier -- see the code
      * in jsinterp.cpp for JSOP_LAMBDA followed by JSOP_{SET,INIT}PROP.
      *
      * Then (or in a call case that has no explicit reference-base
-     * object) we emit JSOP_UNDEFINED to produce the undefined |this| 
-     * value required for calls (which non-strict mode functions 
+     * object) we emit JSOP_UNDEFINED to produce the undefined |this|
+     * value required for calls (which non-strict mode functions
      * will box into the global object).
      */
     ParseNode *pn2 = pn->pn_head;
     switch (pn2->getKind()) {
       case PNK_NAME:
         if (!EmitNameOp(cx, bce, pn2, callop))
             return false;
         break;
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -48,490 +48,34 @@
 #include "jsatom.h"
 #include "jsopcode.h"
 #include "jsscript.h"
 #include "jsprvtd.h"
 #include "jspubtd.h"
 
 #include "frontend/Parser.h"
 #include "frontend/ParseMaps.h"
+#include "frontend/TreeContext.h"
 
 #include "vm/ScopeObject.h"
 
 namespace js {
 
-typedef HashSet<JSAtom *> FuncStmtSet;
-
-/*
- * NB: If you add enumerators for scope statements, add them between STMT_WITH
- * and STMT_CATCH, or you will break the STMT_TYPE_IS_SCOPE macro. If you add
- * non-looping statement enumerators, add them before STMT_DO_LOOP or you will
- * break the STMT_TYPE_IS_LOOP macro.
- *
- * Also remember to keep the statementName array in BytecodeEmitter.cpp in
- * sync.
- */
-enum StmtType {
-    STMT_LABEL,                 /* labeled statement:  L: s */
-    STMT_IF,                    /* if (then) statement */
-    STMT_ELSE,                  /* else clause of if statement */
-    STMT_SEQ,                   /* synthetic sequence of statements */
-    STMT_BLOCK,                 /* compound statement: { s1[;... sN] } */
-    STMT_SWITCH,                /* switch statement */
-    STMT_WITH,                  /* with statement */
-    STMT_CATCH,                 /* catch block */
-    STMT_TRY,                   /* try block */
-    STMT_FINALLY,               /* finally block */
-    STMT_SUBROUTINE,            /* gosub-target subroutine body */
-    STMT_DO_LOOP,               /* do/while loop statement */
-    STMT_FOR_LOOP,              /* for loop statement */
-    STMT_FOR_IN_LOOP,           /* for/in loop statement */
-    STMT_WHILE_LOOP,            /* while loop statement */
-    STMT_LIMIT
-};
-
-inline bool
-STMT_TYPE_IN_RANGE(uint16_t type, StmtType begin, StmtType end)
-{
-    return begin <= type && type <= end;
-}
-
-/*
- * A comment on the encoding of the js::StmtType enum and type-testing macros:
- *
- * STMT_TYPE_MAYBE_SCOPE tells whether a statement type is always, or may
- * become, a lexical scope.  It therefore includes block and switch (the two
- * low-numbered "maybe" scope types) and excludes with (with has dynamic scope
- * pending the "reformed with" in ES4/JS2).  It includes all try-catch-finally
- * types, which are high-numbered maybe-scope types.
- *
- * STMT_TYPE_LINKS_SCOPE tells whether a js::StmtInfo of the given type eagerly
- * links to other scoping statement info records.  It excludes the two early
- * "maybe" types, block and switch, as well as the try and both finally types,
- * since try and the other trailing maybe-scope types don't need block scope
- * unless they contain let declarations.
- *
- * We treat WITH as a static scope because it prevents lexical binding from
- * continuing further up the static scope chain. With the lost "reformed with"
- * proposal for ES4, we would be able to model it statically, too.
- */
-#define STMT_TYPE_MAYBE_SCOPE(type)                                           \
-    (type != STMT_WITH &&                                                     \
-     STMT_TYPE_IN_RANGE(type, STMT_BLOCK, STMT_SUBROUTINE))
-
-#define STMT_TYPE_LINKS_SCOPE(type)                                           \
-    STMT_TYPE_IN_RANGE(type, STMT_WITH, STMT_CATCH)
-
-#define STMT_TYPE_IS_TRYING(type)                                             \
-    STMT_TYPE_IN_RANGE(type, STMT_TRY, STMT_SUBROUTINE)
-
-#define STMT_TYPE_IS_LOOP(type) ((type) >= STMT_DO_LOOP)
-
-#define STMT_MAYBE_SCOPE(stmt)  STMT_TYPE_MAYBE_SCOPE((stmt)->type)
-#define STMT_LINKS_SCOPE(stmt)  (STMT_TYPE_LINKS_SCOPE((stmt)->type) ||       \
-                                 ((stmt)->flags & SIF_SCOPE))
-#define STMT_IS_TRYING(stmt)    STMT_TYPE_IS_TRYING((stmt)->type)
-#define STMT_IS_LOOP(stmt)      STMT_TYPE_IS_LOOP((stmt)->type)
-
-struct StmtInfo {
-    uint16_t        type;           /* statement type */
-    uint16_t        flags;          /* flags, see below */
-    uint32_t        blockid;        /* for simplified dominance computation */
-    ptrdiff_t       update;         /* loop update offset (top if none) */
-    ptrdiff_t       breaks;         /* offset of last break in loop */
-    ptrdiff_t       continues;      /* offset of last continue in loop */
-    RootedVarAtom   label;          /* name of LABEL */
-    RootedVar<StaticBlockObject *> blockObj; /* block scope object */
-    StmtInfo        *down;          /* info for enclosing statement */
-    StmtInfo        *downScope;     /* next enclosing lexical scope */
-
-    StmtInfo(JSContext *cx) : label(cx), blockObj(cx) {}
-};
-
-#define SIF_SCOPE        0x0001     /* statement has its own lexical scope */
-#define SIF_BODY_BLOCK   0x0002     /* STMT_BLOCK type is a function body */
-#define SIF_FOR_BLOCK    0x0004     /* for (let ...) induced block scope */
-
 /*
  * To reuse space in StmtInfo, rename breaks and continues for use during
  * try/catch/finally code generation and backpatching. To match most common
  * use cases, the macro argument is a struct, not a struct pointer. Only a
  * loop, switch, or label statement info record can have breaks and continues,
  * and only a for loop has an update backpatch chain, so it's safe to overlay
  * these for the "trying" StmtTypes.
  */
 #define CATCHNOTE(stmt)  ((stmt).update)
 #define GOSUBS(stmt)     ((stmt).breaks)
 #define GUARDJUMP(stmt)  ((stmt).continues)
 
-#define SET_STATEMENT_TOP(stmt, top)                                          \
-    ((stmt)->update = (top), (stmt)->breaks = (stmt)->continues = (-1))
-
-JS_ENUM_HEADER(TreeContextFlags, uint32_t)
-{
-    /*
-     * There are two parsing modes.
-     * - If we are parsing only to get the parse tree, all TreeContexts used
-     *   are truly TreeContexts, and this flag is clear for each of them.
-     * - If we are parsing to do bytecode compilation, all TreeContexts are
-     *   actually BytecodeEmitters and this flag is set for each of them.
-     */
-    TCF_COMPILING =                            0x1,
-
-    /* parsing inside function body */
-    TCF_IN_FUNCTION =                          0x2,
-
-    /* function has 'return expr;' */
-    TCF_RETURN_EXPR =                          0x4,
-
-    /* function has 'return;' */
-    TCF_RETURN_VOID =                          0x8,
-
-    /* parsing init expr of for; exclude 'in' */
-    TCF_IN_FOR_INIT =                         0x10,
-
-    /* function needs Call object per call */
-    TCF_FUN_HEAVYWEIGHT =                     0x20,
-
-    /* parsed yield statement in function */
-    TCF_FUN_IS_GENERATOR =                    0x40,
-
-    /* block contains a function statement */
-    TCF_HAS_FUNCTION_STMT =                   0x80,
-
-    /* flag lambda from generator expression */
-    TCF_GENEXP_LAMBDA =                      0x100,
-
-    /* script can optimize name references based on scope chain */
-    TCF_COMPILE_N_GO =                       0x200,
-
-    /* API caller does not want result value from global script */
-    TCF_NO_SCRIPT_RVAL =                     0x400,
-
-    /*
-     * Set when parsing a declaration-like destructuring pattern.  This flag
-     * causes PrimaryExpr to create PN_NAME parse nodes for variable references
-     * which are not hooked into any definition's use chain, added to any tree
-     * context's AtomList, etc. etc.  CheckDestructuring will do that work
-     * later.
-     *
-     * The comments atop CheckDestructuring explain the distinction between
-     * assignment-like and declaration-like destructuring patterns, and why
-     * they need to be treated differently.
-     */
-    TCF_DECL_DESTRUCTURING =                 0x800,
-
-    /*
-     * This function/global/eval code body contained a Use Strict Directive.
-     * Treat certain strict warnings as errors, and forbid the use of 'with'.
-     * See also TSF_STRICT_MODE_CODE, JSScript::strictModeCode, and
-     * JSREPORT_STRICT_ERROR.
-     */
-    TCF_STRICT_MODE_CODE =                  0x1000,
-
-    /*
-     * The (static) bindings of this script need to support dynamic name
-     * read/write access. Here, 'dynamic' means dynamic dictionary lookup on
-     * the scope chain for a dynamic set of keys. The primary examples are:
-     *  - direct eval
-     *  - function::
-     *  - with
-     * since both effectively allow any name to be accessed. Non-exmaples are:
-     *  - upvars of nested functions
-     *  - function statement
-     * since the set of assigned name is known dynamically. 'with' could be in
-     * the non-example category, provided the set of all free variables within
-     * the with block was noted. However, we do not optimize 'with' so, for
-     * simplicity, 'with' is treated like eval.
-     *
-     * Note: access through the arguments object is not considered dynamic
-     * binding access since it does not go through the normal name lookup
-     * mechanism. This is debatable and could be changed (although care must be
-     * taken not to turn off the whole 'arguments' optimization). To answer the
-     * more general "is this argument aliased" question, script->needsArgsObj
-     * should be tested (see JSScript::argIsAlised).
-     */
-    TCF_BINDINGS_ACCESSED_DYNAMICALLY =     0x2000,
-
-    /* Compiling an eval() script. */
-    TCF_COMPILE_FOR_EVAL =                  0x4000,
-
-    /*
-     * The function or a function that encloses it may define new local names
-     * at runtime through means other than calling eval.
-     */
-    TCF_FUN_MIGHT_ALIAS_LOCALS =            0x8000,
-
-    /* The script contains singleton initialiser JSOP_OBJECT. */
-    TCF_HAS_SINGLETONS =                   0x10000,
-
-    /* Some enclosing scope is a with-statement or E4X filter-expression. */
-    TCF_IN_WITH =                          0x20000,
-
-    /*
-     * This function does something that can extend the set of bindings in its
-     * call objects --- it does a direct eval in non-strict code, or includes a
-     * function statement (as opposed to a function definition).
-     *
-     * This flag is *not* inherited by enclosed or enclosing functions; it
-     * applies only to the function in whose flags it appears.
-     */
-    TCF_FUN_EXTENSIBLE_SCOPE =             0x40000,
-
-    /* The caller is JS_Compile*Script*. */
-    TCF_NEED_SCRIPT_GLOBAL =               0x80000,
-
-    /*
-     * Technically, every function has a binding named 'arguments'. Internally,
-     * this binding is only added when 'arguments' is mentioned by the function
-     * body. This flag indicates whether 'arguments' has been bound either
-     * through implicit use:
-     *   function f() { return arguments }
-     * or explicit redeclaration:
-     *   function f() { var arguments; return arguments }
-     *
-     * Note 1: overwritten arguments (function() { arguments = 3 }) will cause
-     * this flag to be set but otherwise require no special handling:
-     * 'arguments' is just a local variable and uses of 'arguments' will just
-     * read the local's current slot which may have been assigned. The only
-     * special semantics is that the initial value of 'arguments' is the
-     * arguments object (not undefined, like normal locals).
-     *
-     * Note 2: if 'arguments' is bound as a formal parameter, there will be an
-     * 'arguments' in Bindings, but, as the "LOCAL" in the name indicates, this
-     * flag will not be set. This is because, as a formal, 'arguments' will
-     * have no special semantics: the initial value is unconditionally the
-     * actual argument (or undefined if nactual < nformal).
-     */
-    TCF_ARGUMENTS_HAS_LOCAL_BINDING =     0x100000,
-
-    /*
-     * In many cases where 'arguments' has a local binding (as described above)
-     * we do not need to actually create an arguments object in the function
-     * prologue: instead we can analyze how 'arguments' is used (using the
-     * simple dataflow analysis in analyzeSSA) to determine that uses of
-     * 'arguments' can just read from the stack frame directly. However, the
-     * dataflow analysis only looks at how JSOP_ARGUMENTS is used, so it will
-     * be unsound in several cases. The frontend filters out such cases by
-     * setting this flag which eagerly sets script->needsArgsObj to true.
-     */
-    TCF_DEFINITELY_NEEDS_ARGS_OBJ =       0x200000
-
-} JS_ENUM_FOOTER(TreeContextFlags);
-
-/* Flags to check for return; vs. return expr; in a function. */
-static const uint32_t TCF_RETURN_FLAGS = TCF_RETURN_EXPR | TCF_RETURN_VOID;
-
-/*
- * Sticky deoptimization flags to propagate from FunctionBody.
- */
-static const uint32_t TCF_FUN_FLAGS = TCF_FUN_HEAVYWEIGHT |
-                                      TCF_FUN_IS_GENERATOR |
-                                      TCF_BINDINGS_ACCESSED_DYNAMICALLY |
-                                      TCF_FUN_MIGHT_ALIAS_LOCALS |
-                                      TCF_STRICT_MODE_CODE |
-                                      TCF_FUN_EXTENSIBLE_SCOPE |
-                                      TCF_ARGUMENTS_HAS_LOCAL_BINDING |
-                                      TCF_DEFINITELY_NEEDS_ARGS_OBJ;
-
-struct BytecodeEmitter;
-
-struct TreeContext {                /* tree context for semantic checks */
-    uint32_t        flags;          /* statement state flags, see above */
-    uint32_t        bodyid;         /* block number of program/function body */
-    uint32_t        blockidGen;     /* preincremented block number generator */
-    uint32_t        parenDepth;     /* nesting depth of parens that might turn out
-                                       to be generator expressions */
-    uint32_t        yieldCount;     /* number of |yield| tokens encountered at
-                                       non-zero depth in current paren tree */
-    StmtInfo        *topStmt;       /* top of statement info stack */
-    StmtInfo        *topScopeStmt;  /* top lexical scope statement */
-    RootedVar<StaticBlockObject *> blockChain;
-                                    /* compile time block scope chain (NB: one
-                                       deeper than the topScopeStmt/downScope
-                                       chain when in head of let block/expr) */
-    ParseNode       *blockNode;     /* parse node for a block with let declarations
-                                       (block with its own lexical scope)  */
-    AtomDecls       decls;          /* function, const, and var declarations */
-    Parser          *parser;        /* ptr to common parsing and lexing data */
-    ParseNode       *yieldNode;     /* parse node for a yield expression that might
-                                       be an error if we turn out to be inside a
-                                       generator expression */
-    ParseNode       *argumentsNode; /* parse node for an arguments variable that
-                                       might be an error if we turn out to be
-                                       inside a generator expression */
-
-  private:
-    RootedVarFunction fun_;         /* function to store argument and variable
-                                       names when flags & TCF_IN_FUNCTION */
-    RootedVarObject   scopeChain_;  /* scope chain object for the script */
-
-  public:
-    JSFunction *fun() const {
-        JS_ASSERT(inFunction());
-        return fun_;
-    }
-    void setFunction(JSFunction *fun) {
-        JS_ASSERT(inFunction());
-        fun_ = fun;
-    }
-    JSObject *scopeChain() const {
-        JS_ASSERT(!inFunction());
-        return scopeChain_;
-    }
-    void setScopeChain(JSObject *scopeChain) {
-        JS_ASSERT(!inFunction());
-        scopeChain_ = scopeChain;
-    }
-
-    OwnedAtomDefnMapPtr lexdeps;    /* unresolved lexical name dependencies */
-
-    /*
-     * Enclosing function or global context.  If |this| is truly a TreeContext,
-     * then |parent| will also be a TreeContext.  If |this| is a
-     * BytecodeEmitter, then |parent| will also be a BytecodeEmitter.  See the
-     * comment on TCF_COMPILING.
-     */
-    TreeContext     *parent;
-
-    unsigned        staticLevel;    /* static compilation unit nesting level */
-
-    FunctionBox     *funbox;        /* null or box for function we're compiling
-                                       if (flags & TCF_IN_FUNCTION) and not in
-                                       js::frontend::CompileFunctionBody */
-    FunctionBox     *functionList;
-
-    ParseNode       *innermostWith; /* innermost WITH parse node */
-
-    Bindings        bindings;       /* bindings in this code, including
-                                       arguments if we're compiling a function */
-    Bindings::StackRoot bindingsRoot; /* root for stack allocated bindings. */
-
-    FuncStmtSet *funcStmts;         /* Set of (non-top-level) function statements
-                                       that will alias any top-level bindings with
-                                       the same name. */
-
-    void trace(JSTracer *trc);
-
-    inline TreeContext(Parser *prs);
-    inline ~TreeContext();
-
-    /*
-     * js::BytecodeEmitter derives from js::TreeContext; however, only the
-     * top-level BytecodeEmitters are actually used as full-fledged tree contexts
-     * (to hold decls and lexdeps). We can avoid allocation overhead by making
-     * this distinction explicit.
-     */
-    enum InitBehavior {
-        USED_AS_TREE_CONTEXT,
-        USED_AS_CODE_GENERATOR
-    };
-
-    bool init(JSContext *cx, InitBehavior ib = USED_AS_TREE_CONTEXT) {
-        if (cx->hasRunOption(JSOPTION_STRICT_MODE))
-            flags |= TCF_STRICT_MODE_CODE;
-        if (ib == USED_AS_CODE_GENERATOR)
-            return true;
-        return decls.init() && lexdeps.ensureMap(cx);
-    }
-
-    unsigned blockid() { return topStmt ? topStmt->blockid : bodyid; }
-
-    /*
-     * True if we are at the topmost level of a entire script or function body.
-     * For example, while parsing this code we would encounter f1 and f2 at
-     * body level, but we would not encounter f3 or f4 at body level:
-     *
-     *   function f1() { function f2() { } }
-     *   if (cond) { function f3() { if (cond) { function f4() { } } } }
-     */
-    bool atBodyLevel() { return !topStmt || (topStmt->flags & SIF_BODY_BLOCK); }
-
-    bool inStrictMode() const {
-        return flags & TCF_STRICT_MODE_CODE;
-    }
-
-    inline bool needStrictChecks();
-
-    bool compileAndGo() const { return flags & TCF_COMPILE_N_GO; }
-    bool inFunction() const { return flags & TCF_IN_FUNCTION; }
-
-    bool compiling() const { return flags & TCF_COMPILING; }
-    inline BytecodeEmitter *asBytecodeEmitter();
-
-    void noteBindingsAccessedDynamically() {
-        flags |= TCF_BINDINGS_ACCESSED_DYNAMICALLY;
-    }
-
-    bool bindingsAccessedDynamically() const {
-        return flags & TCF_BINDINGS_ACCESSED_DYNAMICALLY;
-    }
-
-    void noteMightAliasLocals() {
-        flags |= TCF_FUN_MIGHT_ALIAS_LOCALS;
-    }
-
-    bool mightAliasLocals() const {
-        return flags & TCF_FUN_MIGHT_ALIAS_LOCALS;
-    }
-
-    void noteArgumentsHasLocalBinding() {
-        flags |= TCF_ARGUMENTS_HAS_LOCAL_BINDING;
-    }
-
-    bool argumentsHasLocalBinding() const {
-        return flags & TCF_ARGUMENTS_HAS_LOCAL_BINDING;
-    }
-
-    unsigned argumentsLocalSlot() const {
-        PropertyName *arguments = parser->context->runtime->atomState.argumentsAtom;
-        unsigned slot;
-        DebugOnly<BindingKind> kind = bindings.lookup(parser->context, arguments, &slot);
-        JS_ASSERT(kind == VARIABLE || kind == CONSTANT);
-        return slot;
-    }
-
-    void noteDefinitelyNeedsArgsObj() {
-        JS_ASSERT(argumentsHasLocalBinding());
-        flags |= TCF_DEFINITELY_NEEDS_ARGS_OBJ;
-    }
-
-    bool definitelyNeedsArgsObj() const {
-        return flags & TCF_DEFINITELY_NEEDS_ARGS_OBJ;
-    }
-
-    void noteHasExtensibleScope() {
-        flags |= TCF_FUN_EXTENSIBLE_SCOPE;
-    }
-
-    bool hasExtensibleScope() const {
-        return flags & TCF_FUN_EXTENSIBLE_SCOPE;
-    }
-
-    ParseNode *freeTree(ParseNode *pn) { return parser->freeTree(pn); }
-};
-
-/*
- * Return true if we need to check for conditions that elicit
- * JSOPTION_STRICT warnings or strict mode errors.
- */
-inline bool TreeContext::needStrictChecks() {
-    return parser->context->hasStrictOption() || inStrictMode();
-}
-
-namespace frontend {
-
-bool
-SetStaticLevel(TreeContext *tc, unsigned staticLevel);
-
-bool
-GenerateBlockId(TreeContext *tc, uint32_t &blockid);
-
-} /* namespace frontend */
-
 struct TryNode {
     JSTryNote       note;
     TryNode       *prev;
 };
 
 struct CGObjectList {
     uint32_t            length;     /* number of emitted so far objects */
     ObjectBox           *lastbox;   /* last emitted object */
@@ -547,67 +91,38 @@ class GCConstList {
   public:
     GCConstList(JSContext *cx) : list(cx) {}
     bool append(Value v) { JS_ASSERT_IF(v.isString(), v.toString()->isAtom()); return list.append(v); }
     size_t length() const { return list.length(); }
     void finish(ConstArray *array);
 };
 
 struct GlobalScope {
-    GlobalScope(JSContext *cx, JSObject *globalObj, BytecodeEmitter *bce)
-      : globalObj(cx, globalObj), bce(bce), defs(cx), names(cx),
-        defsRoot(cx, &defs), namesRoot(cx, &names)
+    GlobalScope(JSContext *cx, JSObject *globalObj)
+      : globalObj(cx, globalObj)
     { }
 
-    struct GlobalDef {
-        JSAtom        *atom;        // If non-NULL, specifies the property name to add.
-        FunctionBox   *funbox;      // If non-NULL, function value for the property.
-                                    // This value is only set/used if atom is non-NULL.
-        uint32_t      knownSlot;    // If atom is NULL, this is the known shape slot.
-
-        GlobalDef() { }
-        GlobalDef(uint32_t knownSlot) : atom(NULL), knownSlot(knownSlot) { }
-        GlobalDef(JSAtom *atom, FunctionBox *box) : atom(atom), funbox(box) { }
-    };
-
     RootedVarObject globalObj;
-    BytecodeEmitter *bce;
-
-    /*
-     * This is the table of global names encountered during parsing. Each
-     * global name appears in the list only once, and the |names| table
-     * maps back into |defs| for fast lookup.
-     *
-     * A definition may either specify an existing global property, or a new
-     * one that must be added after compilation succeeds.
-     */
-    Vector<GlobalDef, 16> defs;
-    AtomIndexMap      names;
-
-    /*
-     * Protect the inline elements within defs/names from being clobbered by
-     * root analysis. The atoms in this structure must be separately rooted.
-     */
-    JS::SkipRoot      defsRoot;
-    JS::SkipRoot      namesRoot;
 };
 
 struct BytecodeEmitter : public TreeContext
 {
     struct {
         jsbytecode  *base;          /* base of JS bytecode vector */
         jsbytecode  *limit;         /* one byte beyond end of bytecode */
         jsbytecode  *next;          /* pointer to next free bytecode */
         jssrcnote   *notes;         /* source notes, see below */
         unsigned    noteCount;      /* number of source notes so far */
         unsigned    noteLimit;      /* limit number for source notes in notePool */
         ptrdiff_t   lastNoteOffset; /* code offset for last source note */
         unsigned    currentLine;    /* line number for tree-based srcnote gen */
     } prolog, main, *current;
 
+    Parser          *parser;        /* the parser */
+
     OwnedAtomIndexMapPtr atomIndices; /* literals indexed for mapping */
     AtomDefnMapPtr  roLexdeps;
     unsigned        firstLine;      /* first line, for JSScript::NewScriptFromEmitter */
 
     int             stackDepth;     /* current stack depth in script frame */
     unsigned        maxStackDepth;  /* maximum stack depth so far */
 
     unsigned        ntrynotes;      /* number of allocated so far try notes */
@@ -623,59 +138,41 @@ struct BytecodeEmitter : public TreeCont
     GCConstList     constList;      /* constants to be included with the script */
 
     CGObjectList    objectList;     /* list of emitted objects */
     CGObjectList    regexpList;     /* list of emitted regexp that will be
                                        cloned during execution */
 
     GlobalScope     *globalScope;   /* frontend::CompileScript global scope, or null */
 
-    typedef Vector<GlobalSlotArray::Entry, 16> GlobalUseVector;
-
-    GlobalUseVector globalUses;     /* per-script global uses */
-    OwnedAtomIndexMapPtr globalMap; /* per-script map of global name to globalUses vector */
-
     /* Vectors of pn_cookie slot values. */
     typedef Vector<uint32_t, 8> SlotVector;
     SlotVector      closedArgs;
     SlotVector      closedVars;
 
     uint16_t        typesetCount;   /* Number of JOF_TYPESET opcodes generated */
 
     BytecodeEmitter(Parser *parser, unsigned lineno);
     bool init(JSContext *cx, TreeContext::InitBehavior ib = USED_AS_CODE_GENERATOR);
 
-    JSContext *context() {
-        return parser->context;
+    // This is a down-cast.  It's necessary and safe -- although
+    // TreeContext::parent is a |TreeContext *|, a BytecodeEmitter's parent is
+    // always itself a BytecodeEmitter.
+    BytecodeEmitter *parentBCE() {
+        return static_cast<BytecodeEmitter *>(parent);
     }
 
     /*
      * Note that BytecodeEmitters are magic: they own the arena "top-of-stack"
      * space above their tempMark points. This means that you cannot alloc from
      * tempLifoAlloc and save the pointer beyond the next BytecodeEmitter
      * destructor call.
      */
     ~BytecodeEmitter();
 
-    /*
-     * Adds a use of a variable that is statically known to exist on the
-     * global object.
-     *
-     * The actual slot of the variable on the global object is not known
-     * until after compilation. Properties must be resolved before being
-     * added, to avoid aliasing properties that should be resolved. This makes
-     * slot prediction based on the global object's free slot impossible. So,
-     * we use the slot to index into bce->globalScope->defs, and perform a
-     * fixup of the script at the very end of compilation.
-     *
-     * If the global use can be cached, |cookie| will be set to |slot|.
-     * Otherwise, |cookie| is set to the free cookie value.
-     */
-    bool addGlobalUse(JSAtom *atom, uint32_t slot, UpvarCookie *cookie);
-
     bool compilingForEval() const { return !!(flags & TCF_COMPILE_FOR_EVAL); }
     JSVersion version() const { return parser->versionWithFlags(); }
 
     bool isAliasedName(ParseNode *pn);
     bool shouldNoteClosedName(ParseNode *pn);
     bool noteClosedVar(ParseNode *pn);
     bool noteClosedArg(ParseNode *pn);
 
@@ -724,23 +221,16 @@ struct BytecodeEmitter : public TreeCont
     unsigned noteCount() const { return current->noteCount; }