Merge from mozilla-central.
authorJan de Mooij <jdemooij@mozilla.com>
Sat, 21 Jan 2012 17:30:53 +0100
changeset 109197 6ba07330f431d6f08ea4bc8ad067e6fee2e4a979
parent 109196 5f543808812a1625418bfaa18bd90bdccdcb3afe (current diff)
parent 86273 d43360499b86d66d82ed0e585b75bb3237864ad2 (diff)
child 109198 66c3c687e1aaac034df67f3350ba8709bcab5ac7
push id2248
push userakeybl@mozilla.com
push dateMon, 08 Oct 2012 19:23:44 +0000
treeherdermozilla-aurora@118a3b748323 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone12.0a1
Merge from mozilla-central.
accessible/src/base/Statistics.h
accessible/src/base/nsAccessibilityService.cpp
accessible/src/base/nsAccessible.cpp
accessible/src/base/nsAccessible.h
browser/app/profile/firefox.js
browser/base/content/browser.js
browser/base/content/browser.xul
browser/base/content/highlighter.css
browser/components/privatebrowsing/test/browser/browser_privatebrowsing_beforeunload_enter.js
browser/components/privatebrowsing/test/browser/browser_privatebrowsing_beforeunload_exit.js
browser/components/sessionstore/src/nsSessionStore.js
browser/components/shell/src/nsWindowsShellService.cpp
browser/devtools/jar.mn
browser/devtools/styleeditor/SplitView.jsm
browser/devtools/styleeditor/splitview.css
build/unix/build-toolchain/det-ar.sh
configure.in
content/base/public/nsContentUtils.h
content/base/public/nsIScriptElement.h
content/base/src/mozSanitizingSerializer.h
content/base/src/nsContentSink.cpp
content/base/src/nsContentSink.h
content/base/src/nsContentUtils.cpp
content/base/src/nsDOMParser.cpp
content/base/src/nsDOMParser.h
content/base/src/nsGkAtomList.h
content/base/src/nsPlainTextSerializer.h
content/base/src/nsScriptLoader.cpp
content/base/src/nsScriptLoader.h
content/html/content/src/nsGenericHTMLElement.cpp
content/html/content/src/nsGenericHTMLElement.h
content/html/content/src/nsHTMLFrameElement.cpp
content/html/content/src/nsHTMLIFrameElement.cpp
content/html/document/src/nsHTMLContentSink.cpp
content/html/document/src/nsHTMLDocument.cpp
content/html/document/src/nsHTMLDocument.h
content/html/document/src/nsIHTMLDocument.h
content/xml/document/src/nsXMLContentSink.cpp
content/xml/document/src/nsXMLContentSink.h
content/xml/document/src/nsXMLFragmentContentSink.cpp
content/xslt/src/xslt/txMozillaStylesheetCompiler.cpp
content/xslt/src/xslt/txMozillaXMLOutput.cpp
content/xul/document/src/nsXULContentSink.cpp
content/xul/document/src/nsXULContentSink.h
dom/base/nsDOMClassInfo.cpp
dom/base/nsJSEnvironment.cpp
dom/interfaces/html/nsIDOMMozBrowserFrameElement.idl
dom/src/storage/nsDOMStorage.cpp
dom/src/storage/nsDOMStoragePersistentDB.cpp
dom/tests/mochitest/general/test_getContentState.html
gfx/gl/GLContextProviderEGL.cpp
gfx/thebes/gfxHarfBuzzShaper.cpp
image/decoders/nsBMPDecoder.cpp
image/decoders/nsBMPDecoder.h
image/decoders/nsGIFDecoder2.cpp
image/decoders/nsGIFDecoder2.h
image/decoders/nsICODecoder.cpp
image/decoders/nsICODecoder.h
image/decoders/nsIconDecoder.cpp
image/decoders/nsIconDecoder.h
image/decoders/nsJPEGDecoder.cpp
image/decoders/nsJPEGDecoder.h
image/decoders/nsPNGDecoder.cpp
image/decoders/nsPNGDecoder.h
image/encoders/bmp/nsBMPEncoder.cpp
image/encoders/bmp/nsBMPEncoder.h
image/encoders/ico/nsICOEncoder.cpp
image/encoders/ico/nsICOEncoder.h
image/src/Decoder.cpp
image/src/Decoder.h
image/src/DiscardTracker.cpp
image/src/Image.h
image/src/RasterImage.cpp
image/src/RasterImage.h
image/src/SVGDocumentWrapper.cpp
image/src/SVGDocumentWrapper.h
image/src/VectorImage.cpp
image/src/VectorImage.h
image/src/imgLoader.cpp
image/src/imgRequest.cpp
image/src/imgRequest.h
image/src/imgRequestProxy.cpp
image/src/imgRequestProxy.h
image/src/imgStatusTracker.cpp
image/src/imgStatusTracker.h
image/src/imgTools.cpp
js/src/Makefile.in
js/src/frontend/BytecodeEmitter.cpp
js/src/gc/Barrier.h
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsarray.h
js/src/jsinfer.cpp
js/src/jsinfer.h
js/src/jsinferinlines.h
js/src/jsinterp.cpp
js/src/jsinterpinlines.h
js/src/jsobj.cpp
js/src/jsobjinlines.h
js/src/jsutil.h
js/src/methodjit/PolyIC.cpp
js/src/vm/Debugger.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/Stack.cpp
js/src/vm/Stack.h
js/xpconnect/src/XPCComponents.cpp
media/libvorbis/lib/vorbis_floor1.c
media/libvorbis/update.sh
mobile/android/base/GeckoApp.java
mobile/android/base/GeckoAppShell.java
mobile/android/base/Makefile.in
mozglue/android/APKOpen.cpp
mozglue/android/Makefile.in
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/HttpChannelChild.h
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/protocol/http/HttpChannelParent.h
netwerk/protocol/http/PHttpChannel.ipdl
netwerk/protocol/http/nsHttpHeaderArray.cpp
netwerk/protocol/http/nsHttpHeaderArray.h
netwerk/test/TestSTSParser.cpp
parser/html/nsHtml5Parser.cpp
parser/html/nsHtml5Parser.h
parser/html/nsHtml5TreeOpExecutor.cpp
parser/html/nsHtml5TreeOpExecutor.h
parser/html/nsHtml5TreeOperation.cpp
parser/htmlparser/public/nsIContentSink.h
parser/htmlparser/public/nsIDTD.h
parser/htmlparser/public/nsIParser.h
parser/htmlparser/src/CNavDTD.cpp
parser/htmlparser/src/nsExpatDriver.cpp
parser/htmlparser/src/nsLoggingSink.cpp
parser/htmlparser/src/nsLoggingSink.h
parser/htmlparser/src/nsParser.cpp
parser/htmlparser/src/nsParser.h
parser/xml/src/nsSAXXMLReader.cpp
parser/xml/src/nsSAXXMLReader.h
rdf/base/src/nsRDFContentSink.cpp
toolkit/components/passwordmgr/nsLoginManager.js
toolkit/components/places/History.cpp
toolkit/components/places/nsNavHistory.cpp
toolkit/components/places/nsNavHistory.h
toolkit/components/places/nsPlacesImportExportService.cpp
toolkit/components/places/tests/cpp/places_test_harness.h
toolkit/components/places/tests/head_common.js
toolkit/components/telemetry/TelemetryHistograms.h
toolkit/mozapps/extensions/AddonRepository.jsm
toolkit/xre/nsWindowsRestart.cpp
widget/android/nsWindow.cpp
xpcom/glue/standalone/nsGlueLinkingDlopen.cpp
xpcom/tests/TestHarness.h
--- a/accessible/src/base/Statistics.h
+++ b/accessible/src/base/Statistics.h
@@ -44,16 +44,19 @@
 
 namespace mozilla {
 namespace a11y {
 namespace statistics {
 
   inline void A11yInitialized()
     { Telemetry::Accumulate(Telemetry::A11Y_INSTANTIATED, true); }
 
+  inline void A11yConsumers(PRUint32 aConsumer)
+    { Telemetry::Accumulate(Telemetry::A11Y_CONSUMERS, aConsumer); }
+
   /**
    * Report that ISimpleDOM* has been used.
    */
   inline void ISimpleDOMUsed()
     { Telemetry::Accumulate(Telemetry::ISIMPLE_DOM_USAGE, 1); }
 
   /**
    * Report that IAccessibleTable has been used.
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -904,29 +904,18 @@ static bool HasRelatedContent(nsIContent
 {
   nsAutoString id;
   if (!aContent || !nsCoreUtils::GetID(aContent, id) || id.IsEmpty()) {
     return false;
   }
 
   // If the given ID is referred by relation attribute then create an accessible
   // for it. Take care of HTML elements only for now.
-  if (aContent->IsHTML() &&
-      nsAccUtils::GetDocAccessibleFor(aContent)->IsDependentID(id))
-    return true;
-
-  nsIContent *ancestorContent = aContent;
-  while ((ancestorContent = ancestorContent->GetParent()) != nsnull) {
-    if (ancestorContent->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_activedescendant)) {
-        // ancestor has activedescendant property, this content could be active
-      return true;
-    }
-  }
-
-  return false;
+  return aContent->IsHTML() &&
+    nsAccUtils::GetDocAccessibleFor(aContent)->IsDependentID(id);
 }
 
 nsAccessible*
 nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
                                               nsIPresShell* aPresShell,
                                               nsIWeakReference* aWeakShell,
                                               bool* aIsSubtreeHidden)
 {
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -2909,31 +2909,28 @@ nsAccessible::SetCurrentItem(nsAccessibl
     mContent->SetAttr(kNameSpaceID_None,
                       nsGkAtoms::aria_activedescendant, idStr, true);
   }
 }
 
 nsAccessible*
 nsAccessible::ContainerWidget() const
 {
-  nsIAtom* idAttribute = mContent->GetIDAttributeName();
-  if (idAttribute) {
-    if (mContent->HasAttr(kNameSpaceID_None, idAttribute)) {
-      for (nsAccessible* parent = Parent(); parent; parent = parent->Parent()) {
-        nsIContent* parentContent = parent->GetContent();
-        if (parentContent &&
-            parentContent->HasAttr(kNameSpaceID_None,
-                                   nsGkAtoms::aria_activedescendant)) {
-          return parent;
-        }
-
-        // Don't cross DOM document boundaries.
-        if (parent->IsDocumentNode())
-          break;
+  if (HasARIARole() && mContent->HasID()) {
+    for (nsAccessible* parent = Parent(); parent; parent = parent->Parent()) {
+      nsIContent* parentContent = parent->GetContent();
+      if (parentContent &&
+        parentContent->HasAttr(kNameSpaceID_None,
+                               nsGkAtoms::aria_activedescendant)) {
+        return parent;
       }
+
+      // Don't cross DOM document boundaries.
+      if (parent->IsDocumentNode())
+        break;
     }
   }
   return nsnull;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessible protected methods
 
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -162,16 +162,24 @@ public:
   {
     if (!mRoleMapEntry || mRoleMapEntry->roleRule != kUseMapRole)
       return NativeRole();
 
     return ARIARoleInternal();
   }
 
   /**
+   * Return true if ARIA role is specified on the element.
+   */
+  inline bool HasARIARole() const
+  {
+    return mRoleMapEntry;
+  }
+
+  /**
    * Return accessible role specified by ARIA (see constants in
    * roles).
    */
   inline mozilla::a11y::role ARIARole()
   {
     if (!mRoleMapEntry || mRoleMapEntry->roleRule != kUseMapRole)
       return mozilla::a11y::roles::NOTHING;
 
--- a/accessible/src/msaa/Compatibility.cpp
+++ b/accessible/src/msaa/Compatibility.cpp
@@ -35,16 +35,17 @@
  * 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 "Compatibility.h"
 
 #include "nsWinUtils.h"
+#include "Statistics.h"
 
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 /**
  * Return true if module version is lesser than the given version.
@@ -79,28 +80,47 @@ IsModuleVersionLessThan(HMODULE aModuleH
 // Compatibility
 ////////////////////////////////////////////////////////////////////////////////
 
 PRUint32 Compatibility::sMode = Compatibility::NoCompatibilityMode;
 
 void
 Compatibility::Init()
 {
+  // Note we collect some AT statistics/telemetry here for convenience.
+
   HMODULE jawsHandle = ::GetModuleHandleW(L"jhook");
   if (jawsHandle) {
     sMode |= JAWSMode;
     // IA2 off mode for JAWS versions below 8.0.2173.
-    if (IsModuleVersionLessThan(jawsHandle, 8, 2173))
+    if (IsModuleVersionLessThan(jawsHandle, 8, 2173)) {
       sMode |= IA2OffMode;
+      statistics::A11yConsumers(OLDJAWS);
+    } else {
+      statistics::A11yConsumers(JAWS);
+    }
   }
 
-  if (::GetModuleHandleW(L"gwm32inc"))
+  if (::GetModuleHandleW(L"gwm32inc")) {
     sMode |= WEMode;
-  if (::GetModuleHandleW(L"dolwinhk"))
+    statistics::A11yConsumers(WE);
+  }
+  if (::GetModuleHandleW(L"dolwinhk")) {
     sMode |= DolphinMode;
+    statistics::A11yConsumers(DOLPHIN);
+  }
+
+  if (::GetModuleHandleW(L"STSA32"))
+    statistics::A11yConsumers(SEROTEK);
+
+  if (::GetModuleHandleW(L"nvdaHelperRemote"))
+    statistics::A11yConsumers(NVDA);
+
+  if (::GetModuleHandleW(L"OsmHooks"))
+    statistics::A11yConsumers(COBRA);
 
   // Turn off new tab switching for Jaws and WE.
   if (sMode & JAWSMode || sMode & WEMode) {
     // Check to see if the pref for disallowing CtrlTab is already set. If so,
     // bail out (respect the user settings). If not, set it.
     if (!Preferences::HasUserValue("browser.ctrlTab.disallowForScreenReaders"))
       Preferences::SetBool("browser.ctrlTab.disallowForScreenReaders", true);
   }
--- a/accessible/src/msaa/Compatibility.h
+++ b/accessible/src/msaa/Compatibility.h
@@ -92,16 +92,29 @@ private:
   enum {
     NoCompatibilityMode = 0,
     JAWSMode = 1 << 0,
     WEMode = 1 << 1,
     DolphinMode = 1 << 2,
     IA2OffMode = 1 << 3
   };
 
+  /**
+   * List of detected consumers of a11y (used for statistics/telemetry)
+   */
+  enum {
+    NVDA = 0,
+    JAWS = 1,
+    OLDJAWS = 2,
+    WE = 3,
+    DOLPHIN = 4,
+    SEROTEK = 5,
+    COBRA = 6
+  };
+
 private:
   static PRUint32 sMode;
 };
 
 } // a11y namespace
 } // mozilla namespace
 
 #endif
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -389,16 +389,20 @@ pref("security.fileuri.strict_origin_pol
 // deep within the bowels of the widgetry system.  Remove me when GL
 // compositing isn't default disabled in widget/android.
 pref("layers.acceleration.force-enabled", true);
 
 // screen.enabled and screen.brightness properties.
 pref("dom.screenEnabledProperty.enabled", true);
 pref("dom.screenBrightnessProperty.enabled", true);
 
+// Enable browser frame
+pref("dom.mozBrowserFramesEnabled", true);
+pref("dom.mozBrowserFramesWhitelist", "http://localhost:6666");
+
 // Temporary permission hack for WebSMS
 pref("dom.sms.enabled", true);
 pref("dom.sms.whitelist", "file://,http://localhost:6666");
 // Ignore X-Frame-Options headers.
 pref("b2g.ignoreXFrameOptions", true);
 
 // "Preview" landing of bug 710563, which is bogged down in analysis
 // of talos regression.  This is a needed change for higher-framerate
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -78,16 +78,20 @@ LOCAL_INCLUDES += -I$(DEPTH)/build
 DEFINES += -DXPCOM_GLUE
 STL_FLAGS=
 
 LIBS += \
 	$(EXTRA_DSO_LIBS) \
 	$(XPCOM_STANDALONE_GLUE_LDOPTS) \
 	$(NULL)
 
+ifdef MOZ_LINKER
+LIBS += $(ZLIB_LIBS)
+endif
+
 ifndef MOZ_WINCONSOLE
 ifdef MOZ_DEBUG
 MOZ_WINCONSOLE = 1
 else
 MOZ_WINCONSOLE = 0
 endif
 endif
 
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
-<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1325894427000">
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1327073984000">
   <emItems>
       <emItem  blockID="i41" id="{99079a25-328f-4bd4-be04-00955acaa0a7}">
                         <versionRange  minVersion="0.1" maxVersion="4.3.1.00" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i8" id="{B13721C7-F507-4982-B2E5-502A71474FED}">
                         <versionRange  minVersion=" " severity="1">
                     </versionRange>
@@ -34,16 +34,20 @@
       <emItem  blockID="i39" id="{c2d64ff7-0ab8-4263-89c9-ea3b0f8f050c}">
                         <versionRange  minVersion="0.1" maxVersion="4.3.1.00" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i42" id="{D19CA586-DD6C-4a0a-96F8-14644F340D60}">
                         <versionRange  minVersion="0.1" maxVersion="14.4.0" severity="1">
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i53" id="{a3a5c777-f583-4fef-9380-ab4add1bc2a8}">
+                        <versionRange  minVersion="2.0.3" maxVersion="2.0.3">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i10" id="{8CE11043-9A15-4207-A565-0C94C42D590D}">
                         </emItem>
       <emItem  blockID="i1" id="mozilla_cc@internetdownloadmanager.com">
                         <versionRange  minVersion="2.1" maxVersion="3.3">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="3.0a1" maxVersion="*" />
                           </targetApplication>
                     </versionRange>
@@ -61,20 +65,31 @@
                         </emItem>
       <emItem  blockID="i4" id="{4B3803EA-5230-4DC3-A7FC-33638F3D3542}">
                         <versionRange  minVersion="1.2" maxVersion="1.2">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="3.0a1" maxVersion="*" />
                           </targetApplication>
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i50" id="firebug@software.joehewitt.com">
+                        <versionRange  minVersion="0" maxVersion="0">
+                      <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+                              <versionRange  minVersion="9.0a1" maxVersion="9.*" />
+                          </targetApplication>
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i40" id="{28387537-e3f9-4ed7-860c-11e69af4a8a0}">
                         <versionRange  minVersion="0.1" maxVersion="4.3.1.00" severity="1">
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i51" id="admin@youtubeplayer.com">
+                        <versionRange  minVersion="0" maxVersion="*">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i46" id="{841468a1-d7f4-4bd3-84e6-bb0f13a06c64}">
                         <versionRange  minVersion="0.1" maxVersion="*">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="9.0a1" maxVersion="9.0" />
                           </targetApplication>
                     </versionRange>
                   </emItem>
       <emItem  blockID="i23" id="firefox@bandoo.com">
@@ -134,20 +149,22 @@
                               <versionRange  minVersion="8.0a1" maxVersion="*" />
                           </targetApplication>
                     </versionRange>
                   </emItem>
       <emItem  blockID="i3" id="langpack-vi-VN@firefox.mozilla.org">
                         <versionRange  minVersion="2.0" maxVersion="2.0">
                     </versionRange>
                   </emItem>
-      <emItem  blockID="i49" id="{ADFA33FD-16F5-4355-8504-DF4D664CFE63}">
-                        </emItem>
       <emItem  blockID="i7" id="{2224e955-00e9-4613-a844-ce69fccaae91}">
                         </emItem>
+      <emItem  blockID="i52" id="ff-ext@youtube">
+                        <versionRange  minVersion="0" maxVersion="*">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i24" id="{6E19037A-12E3-4295-8915-ED48BC341614}">
                         <versionRange  minVersion="0.1" maxVersion="1.3.328.4" severity="1">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="3.7a1pre" maxVersion="*" />
                           </targetApplication>
                     </versionRange>
                   </emItem>
       <emItem  blockID="i15" id="personas@christopher.beard">
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -799,16 +799,20 @@ pref("browser.sessionstore.max_resumed_c
 // restore_on_demand overrides MAX_CONCURRENT_TAB_RESTORES (sessionstore constant)
 // and restore_hidden_tabs. When true, tabs will not be restored until they are
 // focused (also applies to tabs that aren't visible). When false, the values
 // for MAX_CONCURRENT_TAB_RESTORES and restore_hidden_tabs are respected.
 // Selected tabs are always restored regardless of this pref.
 pref("browser.sessionstore.restore_on_demand", false);
 // Whether to automatically restore hidden tabs (i.e., tabs in other tab groups) or not
 pref("browser.sessionstore.restore_hidden_tabs", false);
+// If restore_on_demand is set, pinned tabs are restored on startup by default.
+// When set to true, this pref overrides that behavior, and pinned tabs will only
+// be restored when they are focused.
+pref("browser.sessionstore.restore_pinned_tabs_on_demand", false);
 
 // allow META refresh by default
 pref("accessibility.blockautorefresh", false);
 
 // Whether history is enabled or not.
 pref("places.history.enabled", true);
 
 // the (maximum) number of the recent visits to sample
@@ -1027,32 +1031,34 @@ pref("devtools.errorconsole.enabled", fa
 pref("devtools.inspector.enabled", true);
 pref("devtools.inspector.htmlHeight", 112);
 
 // Enable the style inspector
 pref("devtools.styleinspector.enabled", true);
 
 // Enable the Tilt inspector
 pref("devtools.tilt.enabled", true);
+pref("devtools.tilt.intro_transition", true);
+pref("devtools.tilt.outro_transition", true);
 
 // Enable the rules view
 pref("devtools.ruleview.enabled", true);
 
 // Enable the Scratchpad tool.
 pref("devtools.scratchpad.enabled", true);
 
 // Enable the Style Editor.
 pref("devtools.styleeditor.enabled", true);
 pref("devtools.styleeditor.transitions", true);
 
 // Enable tools for Chrome development.
 pref("devtools.chrome.enabled", false);
 
 // Disable the GCLI enhanced command line.
-pref("devtools.gcli.enable", true);
+pref("devtools.gcli.enable", false);
 
 // The last Web Console height. This is initially 0 which means that the Web
 // Console will use the default height next time it shows.
 // Change to -1 if you do not want the Web Console to remember its last height.
 pref("devtools.hud.height", 0);
 
 // Remember the Web Console position. Possible values:
 //   above - above the web page,
--- a/browser/base/content/browser-fullZoom.js
+++ b/browser/base/content/browser-fullZoom.js
@@ -227,18 +227,18 @@ var FullZoom = {
     // Avoid the cps roundtrip and apply the default/global pref.
     if (aURI.spec == "about:blank") {
       this._applyPrefToSetting(undefined, aBrowser);
       return;
     }
 
     let browser = aBrowser || gBrowser.selectedBrowser;
 
-    // Image documents should always start at 1, and are not affected by prefs.
-    if (!aIsTabSwitch && browser.contentDocument instanceof ImageDocument) {
+    // Media documents should always start at 1, and are not affected by prefs.
+    if (!aIsTabSwitch && browser.contentDocument.mozSyntheticDocument) {
       ZoomManager.setZoomForBrowser(browser, 1);
       return;
     }
 
     if (Services.contentPrefs.hasCachedPref(aURI, this.name)) {
       let zoomValue = Services.contentPrefs.getPref(aURI, this.name);
       this._applyPrefToSetting(zoomValue, browser);
     } else {
@@ -304,40 +304,40 @@ var FullZoom = {
    * one.
    **/
   _applyPrefToSetting: function FullZoom__applyPrefToSetting(aValue, aBrowser) {
     if ((!this.siteSpecific) || gInPrintPreviewMode)
       return;
 
     var browser = aBrowser || (gBrowser && gBrowser.selectedBrowser);
     try {
-      if (browser.contentDocument instanceof ImageDocument)
+      if (browser.contentDocument.mozSyntheticDocument)
         return;
 
       if (typeof aValue != "undefined")
         ZoomManager.setZoomForBrowser(browser, this._ensureValid(aValue));
       else if (typeof this.globalValue != "undefined")
         ZoomManager.setZoomForBrowser(browser, this.globalValue);
       else
         ZoomManager.setZoomForBrowser(browser, 1);
     }
     catch(ex) {}
   },
 
   _applySettingToPref: function FullZoom__applySettingToPref() {
     if (!this.siteSpecific || gInPrintPreviewMode ||
-        content.document instanceof ImageDocument)
+        content.document.mozSyntheticDocument)
       return;
 
     var zoomLevel = ZoomManager.zoom;
     Services.contentPrefs.setPref(gBrowser.currentURI, this.name, zoomLevel);
   },
 
   _removePref: function FullZoom__removePref() {
-    if (!(content.document instanceof ImageDocument))
+    if (!(content.document.mozSyntheticDocument))
       Services.contentPrefs.removePref(gBrowser.currentURI, this.name);
   },
 
 
   //**************************************************************************//
   // Utilities
 
   _ensureValid: function FullZoom__ensureValid(aValue) {
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -3035,17 +3035,17 @@ function getMarkupDocumentViewer()
  *       (pinkerton)
  **/
 function FillInHTMLTooltip(tipElement)
 {
   var retVal = false;
   // Don't show the tooltip if the tooltip node is a XUL element, a document or is disconnected.
   if (tipElement.namespaceURI == "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" ||
       !tipElement.ownerDocument ||
-      tipElement.ownerDocument.compareDocumentPosition(tipElement) == document.DOCUMENT_POSITION_DISCONNECTED)
+      (tipElement.ownerDocument.compareDocumentPosition(tipElement) & document.DOCUMENT_POSITION_DISCONNECTED))
     return retVal;
 
   const XLinkNS = "http://www.w3.org/1999/xlink";
 
 
   var titleText = null;
   var XLinkTitleText = null;
   var SVGTitleText = null;
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -988,17 +988,16 @@
 
   <vbox id="browser-bottombox" layer="true">
     <toolbar id="inspector-toolbar"
              class="devtools-toolbar"
              nowindowdrag="true"
              hidden="true">
       <vbox flex="1">
         <resizer id="inspector-top-resizer" flex="1" 
-                 class="inspector-resizer"
                  dir="top" disabled="true"
                  element="inspector-tree-box"/>
         <hbox>
 #ifdef XP_MACOSX
           <toolbarbutton id="highlighter-closebutton"
                          oncommand="InspectorUI.closeInspectorUI(false);"
                          tooltiptext="&inspectCloseButton.tooltiptext;"/>
 #endif
@@ -1024,20 +1023,16 @@
                            command="Inspector:Sidebar"/>
             <!-- registered tools go here -->
           </hbox>
 #ifndef XP_MACOSX
           <toolbarbutton id="highlighter-closebutton"
                          oncommand="InspectorUI.closeInspectorUI(false);"
                          tooltiptext="&inspectCloseButton.tooltiptext;"/>
 #endif
-          <resizer id="inspector-end-resizer"
-                   class="inspector-resizer"
-                   dir="top" disabled="true"
-                   element="inspector-tree-box"/>
         </hbox>
       </vbox>
     </toolbar>
     <toolbar id="addon-bar"
              toolbarname="&addonBarCmd.label;" accesskey="&addonBarCmd.accesskey;"
              collapsed="true"
              class="toolbar-primary chromeclass-toolbar"
              context="toolbar-context-menu" toolboxid="navigator-toolbox"
--- a/browser/base/content/highlighter.css
+++ b/browser/base/content/highlighter.css
@@ -29,22 +29,21 @@
 #highlighter-veil-middlebox:-moz-locale-dir(rtl) {
   -moz-box-direction: reverse;
 }
 
 .inspector-breadcrumbs-button {
   direction: ltr;
 }
 
-.inspector-resizer {
+#inspector-top-resizer {
   display: none;
 }
 
-#inspector-toolbar[treepanel-open] > vbox > #inspector-top-resizer,
-#inspector-toolbar[treepanel-open] > vbox > hbox > #inspector-end-resizer {
+#inspector-toolbar[treepanel-open] > vbox > #inspector-top-resizer {
   display: -moz-box;
 }
 
 /*
  * Node Infobar
  */
 
 #highlighter-nodeinfobar-container {
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -169,16 +169,17 @@ endif
                  browser_bug616836.js \
                  browser_bug623155.js \
                  browser_bug623893.js \
                  browser_bug624734.js \
                  browser_bug647886.js \
                  browser_bug655584.js \
                  browser_bug664672.js \
                  browser_bug710878.js \
+                 browser_bug719271.js \
                  browser_canonizeURL.js \
                  browser_findbarClose.js \
                  browser_keywordBookmarklets.js \
                  browser_contextSearchTabPosition.js \
                  browser_ctrlTab.js \
                  browser_customize_popupNotification.js \
                  browser_disablechrome.js \
                  browser_discovery.js \
@@ -226,16 +227,17 @@ endif
                  browser_visibleTabs_bookmarkAllPages.js \
                  browser_visibleTabs_bookmarkAllTabs.js \
                  browser_visibleTabs_tabPreview.js \
                  bug592338.html \
                  disablechrome.html \
                  discovery.html \
                  domplate_test.js \
                  moz.png \
+                 video.ogg \
                  test_bug435035.html \
                  test_bug462673.html \
                  page_style_sample.html \
                  feed_tab.html \
                  plugin_unknown.html \
                  plugin_test.html \
                  plugin_both.html \
                  plugin_both2.html \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_bug719271.js
@@ -0,0 +1,141 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+const TEST_PAGE = "http://example.org/browser/browser/base/content/test/zoom_test.html";
+const TEST_VIDEO = "http://example.org/browser/browser/base/content/test/video.ogg";
+
+var gTab1, gTab2, gLevel1, gLevel2;
+
+function test() {
+  waitForExplicitFinish();
+
+  gTab1 = gBrowser.addTab();
+  gTab2 = gBrowser.addTab();
+  gBrowser.selectedTab = gTab1;
+
+  load(gTab1, TEST_PAGE, function() {
+    load(gTab2, TEST_VIDEO, zoomTab1);
+  });
+}
+
+function zoomTab1() {
+  is(gBrowser.selectedTab, gTab1, "Tab 1 is selected");
+  zoomTest(gTab1, 1, "Initial zoom of tab 1 should be 1");
+  zoomTest(gTab2, 1, "Initial zoom of tab 2 should be 1");
+
+  FullZoom.enlarge();
+  gLevel1 = ZoomManager.getZoomForBrowser(gBrowser.getBrowserForTab(gTab1));
+
+  ok(gLevel1 > 1, "New zoom for tab 1 should be greater than 1");
+  zoomTest(gTab2, 1, "Zooming tab 1 should not affect tab 2");
+
+  gBrowser.selectedTab = gTab2;
+  zoomTest(gTab2, 1, "Tab 2 is still unzoomed after it is selected");
+  zoomTest(gTab1, gLevel1, "Tab 1 is still zoomed");
+
+  zoomTab2();
+}
+
+function zoomTab2() {
+  is(gBrowser.selectedTab, gTab2, "Tab 2 is selected");
+
+  FullZoom.reduce();
+  let gLevel2 = ZoomManager.getZoomForBrowser(gBrowser.getBrowserForTab(gTab2));
+
+  ok(gLevel2 < 1, "New zoom for tab 2 should be less than 1");
+  zoomTest(gTab1, gLevel1, "Zooming tab 2 should not affect tab 1");
+
+  afterZoom(function() {
+    zoomTest(gTab1, gLevel1, "Tab 1 should have the same zoom after it's selected");
+
+    testNavigation();
+  });
+  gBrowser.selectedTab = gTab1;
+}
+
+function testNavigation() {
+  load(gTab1, TEST_VIDEO, function() {
+    zoomTest(gTab1, 1, "Zoom should be 1 when a video was loaded");
+    navigate(BACK, function() {
+      zoomTest(gTab1, gLevel1, "Zoom should be restored when a page is loaded");
+      navigate(FORWARD, function() {
+        zoomTest(gTab1, 1, "Zoom should be 1 again when navigating back to a video");
+        finishTest();
+      });
+    });
+  });
+}
+
+var finishTestStarted  = false;
+function finishTest() {
+  ok(!finishTestStarted, "finishTest called more than once");
+  finishTestStarted = true;
+
+  gBrowser.selectedTab = gTab1;
+  FullZoom.reset();
+  gBrowser.removeTab(gTab1);
+
+  gBrowser.selectedTab = gTab2;
+  FullZoom.reset();
+  gBrowser.removeTab(gTab2);
+
+  finish();
+}
+
+function zoomTest(tab, val, msg) {
+  is(ZoomManager.getZoomForBrowser(tab.linkedBrowser), val, msg);
+}
+
+function load(tab, url, cb) {
+  let didLoad = false;
+  let didZoom = false;
+  tab.linkedBrowser.addEventListener("load", function onload(event) {
+    event.currentTarget.removeEventListener("load", onload, true);
+    didLoad = true;
+    if (didZoom)
+      executeSoon(cb);
+  }, true);
+
+  afterZoom(function() {
+    didZoom = true;
+    if (didLoad)
+      executeSoon(cb);
+  });
+
+  tab.linkedBrowser.loadURI(url);
+}
+
+const BACK = 0;
+const FORWARD = 1;
+function navigate(direction, cb) {
+  let didPs = false;
+  let didZoom = false;
+  gBrowser.addEventListener("pageshow", function onpageshow(event) {
+    gBrowser.removeEventListener("pageshow", onpageshow, true);
+    didPs = true;
+    if (didZoom)
+      executeSoon(cb);
+  }, true);
+
+  afterZoom(function() {
+    didZoom = true;
+    if (didPs)
+      executeSoon(cb);
+  });
+
+  if (direction == BACK)
+    gBrowser.goBack();
+  else if (direction == FORWARD)
+    gBrowser.goForward();
+}
+
+function afterZoom(cb) {
+  let oldSZFB = ZoomManager.setZoomForBrowser;
+  ZoomManager.setZoomForBrowser = function(browser, value) {
+    oldSZFB.call(ZoomManager, browser, value);
+    ZoomManager.setZoomForBrowser = oldSZFB;
+    executeSoon(cb);
+  };
+}
--- a/browser/components/privatebrowsing/test/browser/Makefile.in
+++ b/browser/components/privatebrowsing/test/browser/Makefile.in
@@ -51,16 +51,19 @@ include $(topsrcdir)/config/rules.mk
 		browser_privatebrowsing_commandline_toggle.js \
 		browser_privatebrowsing_crh.js \
 		browser_privatebrowsing_fastswitch.js \
 		browser_privatebrowsing_findbar.js \
 		browser_privatebrowsing_forgetthissite.js \
 		browser_privatebrowsing_geoprompt.js \
 		browser_privatebrowsing_geoprompt_page.html \
 		browser_privatebrowsing_import.js \
+		browser_privatebrowsing_localStorage.js \
+		browser_privatebrowsing_localStorage_page1.html \
+		browser_privatebrowsing_localStorage_page2.html \
 		browser_privatebrowsing_newwindow_stopcmd.js \
 		browser_privatebrowsing_opendir.js \
 		browser_privatebrowsing_openlocation.js \
 		browser_privatebrowsing_pageinfo.js \
 		browser_privatebrowsing_placestitle.js \
 		browser_privatebrowsing_popupblocker.js \
 		browser_privatebrowsing_popupmode.js \
 		browser_privatebrowsing_protocolhandler.js \
@@ -87,16 +90,15 @@ include $(topsrcdir)/config/rules.mk
 		$(NULL)
 
 # Disabled until bug 564934 is fixed:
 #		browser_privatebrowsing_downloadmonitor.js \
 
 # Turn off private browsing tests that perma-timeout on Linux.
 ifneq (Linux,$(OS_ARCH))
 _BROWSER_TEST_FILES += \
-		browser_privatebrowsing_beforeunload_enter.js \
-		browser_privatebrowsing_beforeunload_exit.js \
+		browser_privatebrowsing_beforeunload.js \
 		browser_privatebrowsing_cookieacceptdialog.js \
 		$(NULL)
 endif
 
 libs:: $(_BROWSER_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_beforeunload.js
@@ -0,0 +1,166 @@
+/* ***** 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 Private Browsing Tests.
+ *
+ * The Initial Developer of the Original Code is
+ * Nochum Sossonko.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Nochum Sossonko <highmind63@gmail.com> (Original Author)
+ *   Ehsan Akhgari <ehsan@mozilla.com>
+ *
+ * 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 ***** */
+
+// This test makes sure that cancelling the unloading of a page with a beforeunload
+// handler prevents the private browsing mode transition.
+
+function test() {
+  const TEST_PAGE_1 = "data:text/html,<body%20onbeforeunload='return%20false;'>first</body>";
+  const TEST_PAGE_2 = "data:text/html,<body%20onbeforeunload='return%20false;'>second</body>";
+  let pb = Cc["@mozilla.org/privatebrowsing;1"]
+             .getService(Ci.nsIPrivateBrowsingService);
+
+  let rejectDialog = 0;
+  let acceptDialog = 0;
+  let confirmCalls = 0;
+  function promptObserver(aSubject, aTopic, aData) {
+    let dialogWin = aSubject.QueryInterface(Ci.nsIDOMWindow);
+    confirmCalls++;
+    if (acceptDialog-- > 0)
+      dialogWin.document.documentElement.getButton("accept").click();
+    else if (rejectDialog-- > 0)
+      dialogWin.document.documentElement.getButton("cancel").click();
+  }
+
+  Services.obs.addObserver(promptObserver, "common-dialog-loaded", false);
+
+  waitForExplicitFinish();
+  let browser1 = gBrowser.getBrowserForTab(gBrowser.addTab());
+  browser1.addEventListener("load", function() {
+    browser1.removeEventListener("load", arguments.callee, true);
+
+    let browser2 = gBrowser.getBrowserForTab(gBrowser.addTab());
+    browser2.addEventListener("load", function() {
+      browser2.removeEventListener("load", arguments.callee, true);
+
+      rejectDialog = 1;
+      pb.privateBrowsingEnabled = true;
+
+      ok(!pb.privateBrowsingEnabled, "Private browsing mode should not have been activated");
+      is(confirmCalls, 1, "Only one confirm box should be shown");
+      is(gBrowser.tabs.length, 3,
+         "No tabs should be closed because private browsing mode transition was canceled");
+      is(gBrowser.getBrowserForTab(gBrowser.tabContainer.firstChild).currentURI.spec, "about:blank",
+         "The first tab should be a blank tab");
+      is(gBrowser.getBrowserForTab(gBrowser.tabContainer.firstChild.nextSibling).currentURI.spec, TEST_PAGE_1,
+         "The middle tab should be the same one we opened");
+      is(gBrowser.getBrowserForTab(gBrowser.tabContainer.lastChild).currentURI.spec, TEST_PAGE_2,
+         "The last tab should be the same one we opened");
+      is(rejectDialog, 0, "Only one confirm dialog should have been rejected");
+
+      confirmCalls = 0;
+      acceptDialog = 2;
+      pb.privateBrowsingEnabled = true;
+
+      ok(pb.privateBrowsingEnabled, "Private browsing mode should have been activated");
+      is(confirmCalls, 2, "Only two confirm boxes should be shown");
+      is(gBrowser.tabs.length, 1,
+         "Incorrect number of tabs after transition into private browsing");
+      gBrowser.selectedBrowser.addEventListener("load", function() {
+        gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
+
+        is(gBrowser.currentURI.spec, "about:privatebrowsing",
+           "Incorrect page displayed after private browsing transition");
+        is(acceptDialog, 0, "Two confirm dialogs should have been accepted");
+
+        gBrowser.selectedBrowser.addEventListener("load", function() {
+          gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
+
+          gBrowser.selectedTab = gBrowser.addTab();
+          gBrowser.selectedBrowser.addEventListener("load", function() {
+            gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
+
+            confirmCalls = 0;
+            rejectDialog = 1;
+            pb.privateBrowsingEnabled = false;
+
+            ok(pb.privateBrowsingEnabled, "Private browsing mode should not have been deactivated");
+            is(confirmCalls, 1, "Only one confirm box should be shown");
+            is(gBrowser.tabs.length, 2,
+               "No tabs should be closed because private browsing mode transition was canceled");
+            is(gBrowser.getBrowserForTab(gBrowser.tabContainer.firstChild).currentURI.spec, TEST_PAGE_1,
+               "The first tab should be the same one we opened");
+            is(gBrowser.getBrowserForTab(gBrowser.tabContainer.lastChild).currentURI.spec, TEST_PAGE_2,
+               "The last tab should be the same one we opened");
+            is(rejectDialog, 0, "Only one confirm dialog should have been rejected");
+
+            confirmCalls = 0;
+            acceptDialog = 2;
+            pb.privateBrowsingEnabled = false;
+
+            ok(!pb.privateBrowsingEnabled, "Private browsing mode should have been deactivated");
+            is(confirmCalls, 2, "Only two confirm boxes should be shown");
+            is(gBrowser.tabs.length, 3,
+               "Incorrect number of tabs after transition into private browsing");
+
+            let loads = 0;
+            function waitForLoad(event) {
+              gBrowser.removeEventListener("load", arguments.callee, true);
+
+              if (++loads != 3)
+                return;
+
+              is(gBrowser.getBrowserForTab(gBrowser.tabContainer.firstChild).currentURI.spec, "about:blank",
+                 "The first tab should be a blank tab");
+              is(gBrowser.getBrowserForTab(gBrowser.tabContainer.firstChild.nextSibling).currentURI.spec, TEST_PAGE_1,
+                 "The middle tab should be the same one we opened");
+              is(gBrowser.getBrowserForTab(gBrowser.tabContainer.lastChild).currentURI.spec, TEST_PAGE_2,
+                 "The last tab should be the same one we opened");
+              is(acceptDialog, 0, "Two confirm dialogs should have been accepted");
+              is(acceptDialog, 0, "Two prompts should have been raised");
+
+              acceptDialog = 2;
+              gBrowser.removeTab(gBrowser.tabContainer.lastChild);
+              gBrowser.removeTab(gBrowser.tabContainer.lastChild);
+              gBrowser.getBrowserAtIndex(gBrowser.tabContainer.selectedIndex).contentWindow.focus();
+
+              Services.obs.removeObserver(promptObserver, "common-dialog-loaded", false);
+              finish();
+            }
+            for (let i = 0; i < gBrowser.browsers.length; ++i)
+              gBrowser.browsers[i].addEventListener("load", waitForLoad, true);
+          }, true);
+          gBrowser.selectedBrowser.loadURI(TEST_PAGE_2);
+        }, true);
+        gBrowser.selectedBrowser.loadURI(TEST_PAGE_1);
+      }, true);
+    }, true);
+    browser2.loadURI(TEST_PAGE_2);
+  }, true);
+  browser1.loadURI(TEST_PAGE_1);
+}
deleted file mode 100644
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_beforeunload_enter.js
+++ /dev/null
@@ -1,114 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Private Browsing Tests.
- *
- * The Initial Developer of the Original Code is
- * Nochum Sossonko.
- * Portions created by the Initial Developer are Copyright (C) 2009
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Nochum Sossonko <highmind63@gmail.com> (Original Author)
- *   Ehsan Akhgari <ehsan@mozilla.com>
- *
- * 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 ***** */
-
-// This test makes sure that cancelling the unloading of a page with a beforeunload
-// handler prevents the private browsing mode transition.
-
-function test() {
-  const TEST_PAGE_1 = "data:text/html,<body%20onbeforeunload='return%20false;'>first</body>";
-  const TEST_PAGE_2 = "data:text/html,<body%20onbeforeunload='return%20false;'>second</body>";
-  let pb = Cc["@mozilla.org/privatebrowsing;1"]
-             .getService(Ci.nsIPrivateBrowsingService);
-
-  let rejectDialog = 0;
-  let acceptDialog = 0;
-  let confirmCalls = 0;
-  function promptObserver(aSubject, aTopic, aData) {
-    let dialogWin = aSubject.QueryInterface(Ci.nsIDOMWindow);
-    confirmCalls++;
-    if (acceptDialog-- > 0)
-      dialogWin.document.documentElement.getButton("accept").click();
-    else if (rejectDialog-- > 0)
-      dialogWin.document.documentElement.getButton("cancel").click();
-  }
-
-  Services.obs.addObserver(promptObserver, "common-dialog-loaded", false);
-
-  waitForExplicitFinish();
-  let browser1 = gBrowser.getBrowserForTab(gBrowser.addTab());
-  browser1.addEventListener("load", function() {
-    browser1.removeEventListener("load", arguments.callee, true);
-
-    let browser2 = gBrowser.getBrowserForTab(gBrowser.addTab());
-    browser2.addEventListener("load", function() {
-      browser2.removeEventListener("load", arguments.callee, true);
-
-      rejectDialog = 1;
-      pb.privateBrowsingEnabled = true;
-
-      ok(!pb.privateBrowsingEnabled, "Private browsing mode should not have been activated");
-      is(confirmCalls, 1, "Only one confirm box should be shown");
-      is(gBrowser.tabs.length, 3,
-         "No tabs should be closed because private browsing mode transition was canceled");
-      is(gBrowser.getBrowserForTab(gBrowser.tabContainer.firstChild).currentURI.spec, "about:blank",
-         "The first tab should be a blank tab");
-      is(gBrowser.getBrowserForTab(gBrowser.tabContainer.firstChild.nextSibling).currentURI.spec, TEST_PAGE_1,
-         "The middle tab should be the same one we opened");
-      is(gBrowser.getBrowserForTab(gBrowser.tabContainer.lastChild).currentURI.spec, TEST_PAGE_2,
-         "The last tab should be the same one we opened");
-      is(rejectDialog, 0, "Only one confirm dialog should have been rejected");
-
-      confirmCalls = 0;
-      acceptDialog = 2;
-      pb.privateBrowsingEnabled = true;
-
-      ok(pb.privateBrowsingEnabled, "Private browsing mode should have been activated");
-      is(confirmCalls, 2, "Only two confirm boxes should be shown");
-      is(gBrowser.tabs.length, 1,
-         "Incorrect number of tabs after transition into private browsing");
-      gBrowser.selectedBrowser.addEventListener("load", function() {
-        gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-
-        is(gBrowser.currentURI.spec, "about:privatebrowsing",
-           "Incorrect page displayed after private browsing transition");
-        is(acceptDialog, 0, "Two confirm dialogs should have been accepted");
-
-        gBrowser.addTab();
-        gBrowser.removeTab(gBrowser.selectedTab);
-        Services.prefs.setBoolPref("browser.privatebrowsing.keep_current_session", true);
-        pb.privateBrowsingEnabled = false;
-        Services.prefs.clearUserPref("browser.privatebrowsing.keep_current_session");
-        Services.obs.removeObserver(promptObserver, "common-dialog-loaded", false);
-        gBrowser.getBrowserAtIndex(gBrowser.tabContainer.selectedIndex).contentWindow.focus();
-        finish();
-      }, true);
-    }, true);
-    browser2.loadURI(TEST_PAGE_2);
-  }, true);
-  browser1.loadURI(TEST_PAGE_1);
-}
deleted file mode 100644
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_beforeunload_exit.js
+++ /dev/null
@@ -1,125 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Private Browsing Tests.
- *
- * The Initial Developer of the Original Code is
- * Nochum Sossonko.
- * Portions created by the Initial Developer are Copyright (C) 2009
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Nochum Sossonko <highmind63@gmail.com> (Original Author)
- *   Ehsan Akhgari <ehsan@mozilla.com>
- *
- * 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 ***** */
-
-// This test makes sure that cancelling the unloading of a page with a beforeunload
-// handler prevents the private browsing mode transition.
-
-function test() {
-  const TEST_PAGE_1 = "data:text/html,<body%20onbeforeunload='return%20false;'>first</body>";
-  const TEST_PAGE_2 = "data:text/html,<body%20onbeforeunload='return%20false;'>second</body>";
-  let pb = Cc["@mozilla.org/privatebrowsing;1"]
-             .getService(Ci.nsIPrivateBrowsingService);
-
-  let rejectDialog = 0;
-  let acceptDialog = 0;
-  let confirmCalls = 0;
-  function promptObserver(aSubject, aTopic, aData) {
-    let dialogWin = aSubject.QueryInterface(Ci.nsIDOMWindow);
-    confirmCalls++;
-    if (acceptDialog-- > 0)
-      dialogWin.document.documentElement.getButton("accept").click();
-    else if (rejectDialog-- > 0)
-      dialogWin.document.documentElement.getButton("cancel").click();
-  }
-
-  Services.obs.addObserver(promptObserver, "common-dialog-loaded", false);
-  pb.privateBrowsingEnabled = true;
-
-  waitForExplicitFinish();
-  let browser1 = gBrowser.getBrowserForTab(gBrowser.addTab());
-  browser1.addEventListener("load", function() {
-    browser1.removeEventListener("load", arguments.callee, true);
-
-    let browser2 = gBrowser.getBrowserForTab(gBrowser.addTab());
-    browser2.addEventListener("load", function() {
-      browser2.removeEventListener("load", arguments.callee, true);
-
-      confirmCalls = 0;
-      rejectDialog = 1;
-      pb.privateBrowsingEnabled = false;
-
-      ok(pb.privateBrowsingEnabled, "Private browsing mode should not have been deactivated");
-      is(confirmCalls, 1, "Only one confirm box should be shown");
-      is(gBrowser.tabs.length, 3,
-         "No tabs should be closed because private browsing mode transition was canceled");
-      is(gBrowser.getBrowserForTab(gBrowser.tabContainer.firstChild).currentURI.spec, "about:privatebrowsing",
-         "The first tab should be the same one we opened");
-      is(gBrowser.getBrowserForTab(gBrowser.tabContainer.lastChild).currentURI.spec, TEST_PAGE_2,
-         "The last tab should be the same one we opened");
-      is(rejectDialog, 0, "Only one confirm dialog should have been rejected");
-
-      confirmCalls = 0;
-      acceptDialog = 2;
-      pb.privateBrowsingEnabled = false;
-
-      ok(!pb.privateBrowsingEnabled, "Private browsing mode should have been deactivated");
-      is(confirmCalls, 2, "Only two confirm boxes should be shown");
-      is(gBrowser.tabs.length, 3,
-         "Incorrect number of tabs after transition into private browsing");
-
-      let loads = 0;
-      function waitForLoad(event) {
-        gBrowser.removeEventListener("load", arguments.callee, true);
-
-        if (++loads != 3)
-          return;
-
-        is(gBrowser.getBrowserForTab(gBrowser.tabContainer.firstChild).currentURI.spec, "about:blank",
-           "The first tab should be a blank tab");
-        is(gBrowser.getBrowserForTab(gBrowser.tabContainer.firstChild.nextSibling).currentURI.spec, TEST_PAGE_1,
-           "The middle tab should be the same one we opened");
-        is(gBrowser.getBrowserForTab(gBrowser.tabContainer.lastChild).currentURI.spec, TEST_PAGE_2,
-           "The last tab should be the same one we opened");
-        is(acceptDialog, 0, "Two confirm dialogs should have been accepted");
-        is(acceptDialog, 0, "Two prompts should have been raised");
-
-        acceptDialog = 2;
-        gBrowser.removeTab(gBrowser.tabContainer.lastChild);
-        gBrowser.removeTab(gBrowser.tabContainer.lastChild);
-        gBrowser.getBrowserAtIndex(gBrowser.tabContainer.selectedIndex).contentWindow.focus();
-
-        Services.obs.removeObserver(promptObserver, "common-dialog-loaded", false);
-        finish();
-      }
-      for (let i = 0; i < gBrowser.browsers.length; ++i)
-        gBrowser.browsers[i].addEventListener("load", waitForLoad, true);
-    }, true);
-    browser2.loadURI(TEST_PAGE_2);
-  }, true);
-  browser1.loadURI(TEST_PAGE_1);
-}
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage.js
@@ -0,0 +1,59 @@
+/* ***** 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 Private Browsing Tests.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2012
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Josh Matthews <josh@joshmatthews.net> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+function test() {
+  let pb = Cc["@mozilla.org/privatebrowsing;1"].
+           getService(Ci.nsIPrivateBrowsingService);
+  waitForExplicitFinish();
+  pb.privateBrowsingEnabled = true;
+  let tab = gBrowser.selectedTab = gBrowser.addTab();
+  let browser = gBrowser.selectedBrowser;
+  browser.addEventListener('load', function() {
+    browser.removeEventListener('load', arguments.callee, true);
+    let tab2 = gBrowser.selectedTab = gBrowser.addTab();
+    browser.contentWindow.location = 'http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/' +
+                     'browser_privatebrowsing_localStorage_page2.html';
+    browser.addEventListener('load', function() {
+      browser.removeEventListener('load', arguments.callee, true);
+      is(browser.contentWindow.document.title, '2', "localStorage should contain 2 items");
+      pb.privateBrowsingEnabled = false;
+      finish();
+    }, true);
+  }, true);
+  browser.loadURI('http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/' +
+                  'browser_privatebrowsing_localStorage_page1.html');
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_page1.html
@@ -0,0 +1,10 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<script type="text/javascript">
+  localStorage.clear();
+  localStorage.setItem('test1', 'value1');
+</script>
+</head>
+<body>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_page2.html
@@ -0,0 +1,10 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<script type="text/javascript">
+  localStorage.setItem('test2', 'value2');
+  document.title = localStorage.length;
+</script>
+</head>
+<body>
+</body>
+</html>
--- a/browser/components/sessionstore/src/nsSessionStore.js
+++ b/browser/components/sessionstore/src/nsSessionStore.js
@@ -246,16 +246,19 @@ SessionStoreService.prototype = {
   _tabsToRestore: { priority: [], visible: [], hidden: [] },
   _tabsRestoringCount: 0,
 
   // overrides MAX_CONCURRENT_TAB_RESTORES and _restoreHiddenTabs when true
   _restoreOnDemand: false,
 
   // whether to restore hidden tabs or not, pref controlled.
   _restoreHiddenTabs: null,
+  
+  // whether to restore app tabs on demand or not, pref controlled.
+  _restorePinnedTabsOnDemand: null,
 
   // The state from the previous session (after restoring pinned tabs). This
   // state is persisted and passed through to the next session during an app
   // restart to make the third party add-on warning not trash the deferred
   // session
   _lastSessionState: null,
 
   // Whether we've been initialized
@@ -308,16 +311,20 @@ SessionStoreService.prototype = {
 
     this._restoreOnDemand =
       this._prefBranch.getBoolPref("sessionstore.restore_on_demand");
     this._prefBranch.addObserver("sessionstore.restore_on_demand", this, true);
 
     this._restoreHiddenTabs =
       this._prefBranch.getBoolPref("sessionstore.restore_hidden_tabs");
     this._prefBranch.addObserver("sessionstore.restore_hidden_tabs", this, true);
+    
+    this._restorePinnedTabsOnDemand =
+      this._prefBranch.getBoolPref("sessionstore.restore_pinned_tabs_on_demand");
+    this._prefBranch.addObserver("sessionstore.restore_pinned_tabs_on_demand", this, true);
 
     // Make sure gRestoreTabsProgressListener has a reference to sessionstore
     // so that it can make calls back in
     gRestoreTabsProgressListener.ss = this;
 
     // get file references
     this._sessionFile = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
     this._sessionFileBackup = this._sessionFile.clone();
@@ -683,16 +690,20 @@ SessionStoreService.prototype = {
       case "sessionstore.restore_on_demand":
         this._restoreOnDemand =
           this._prefBranch.getBoolPref("sessionstore.restore_on_demand");
         break;
       case "sessionstore.restore_hidden_tabs":
         this._restoreHiddenTabs =
           this._prefBranch.getBoolPref("sessionstore.restore_hidden_tabs");
         break;
+      case "sessionstore.restore_pinned_tabs_on_demand":
+        this._restorePinnedTabsOnDemand =
+          this._prefBranch.getBoolPref("sessionstore.restore_pinned_tabs_on_demand");
+        break;
       }
       break;
     case "timer-callback": // timer call back for delayed saving
       this._saveTimer = null;
       this.saveState();
       break;
     case "private-browsing":
       switch (aData) {
@@ -3182,17 +3193,18 @@ SessionStoreService.prototype = {
    *   if we have already reached the limit for number of tabs to restore
    */
   restoreNextTab: function sss_restoreNextTab() {
     // If we call in here while quitting, we don't actually want to do anything
     if (this._loadState == STATE_QUITTING)
       return;
 
     // If it's not possible to restore anything, then just bail out.
-    if ((!this._tabsToRestore.priority.length && this._restoreOnDemand) ||
+    if ((this._restoreOnDemand &&
+        (this._restorePinnedTabsOnDemand || !this._tabsToRestore.priority.length)) ||
         this._tabsRestoringCount >= MAX_CONCURRENT_TAB_RESTORES)
       return;
 
     // Look in priority, then visible, then hidden
     let nextTabArray;
     if (this._tabsToRestore.priority.length) {
       nextTabArray = this._tabsToRestore.priority
     }
--- a/browser/components/sessionstore/test/browser_586068-cascaded_restore.js
+++ b/browser/components/sessionstore/test/browser_586068-cascaded_restore.js
@@ -51,21 +51,23 @@ function test() {
 
 // test_reloadCascade, test_reloadReload are generated tests that are run out
 // of cycle (since they depend on current state). They're listed in [tests] here
 // so that it is obvious when they run in respect to the other tests.
 let tests = [test_cascade, test_select, test_multiWindowState,
              test_setWindowStateNoOverwrite, test_setWindowStateOverwrite,
              test_setBrowserStateInterrupted, test_reload,
              /* test_reloadReload, */ test_reloadCascadeSetup,
-             /* test_reloadCascade, */ test_apptabs_only];
+             /* test_reloadCascade, */ test_apptabs_only,
+             test_restore_apptabs_ondemand];
 function runNextTest() {
   // Reset the pref
   try {
     Services.prefs.clearUserPref("browser.sessionstore.restore_on_demand");
+    Services.prefs.clearUserPref("browser.sessionstore.restore_pinned_tabs_on_demand");
   } catch (e) {}
 
   // set an empty state & run the next test, or finish
   if (tests.length) {
     // Enumerate windows and close everything but our primary window. We can't
     // use waitForFocus() because apparently it's buggy. See bug 599253.
     var windowsEnum = Services.wm.getEnumerator("navigator:browser");
     while (windowsEnum.hasMoreElements()) {
@@ -772,16 +774,79 @@ function test_apptabs_only() {
     runNextTest();
   }
 
   window.gBrowser.addTabsProgressListener(progressListener);
   ss.setBrowserState(JSON.stringify(state));
 }
 
 
+// This test ensures that app tabs are not restored when restore_pinned_tabs_on_demand is set
+function test_restore_apptabs_ondemand() {
+  Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", true);
+  Services.prefs.setBoolPref("browser.sessionstore.restore_pinned_tabs_on_demand", true);
+
+  // We have our own progress listener for this test, which we'll attach before our state is set
+  let progressListener = {
+    onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
+      if (aBrowser.__SS_restoreState == TAB_STATE_RESTORING &&
+          aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
+          aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
+          aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW)
+        test_restore_apptabs_ondemand_progressCallback(aBrowser);
+    }
+  }
+
+  let state = { windows: [{ tabs: [
+    { entries: [{ url: "http://example.org/#1" }], extData: { "uniq": r() }, pinned: true },
+    { entries: [{ url: "http://example.org/#2" }], extData: { "uniq": r() }, pinned: true },
+    { entries: [{ url: "http://example.org/#3" }], extData: { "uniq": r() }, pinned: true },
+    { entries: [{ url: "http://example.org/#4" }], extData: { "uniq": r() } },
+    { entries: [{ url: "http://example.org/#5" }], extData: { "uniq": r() } },
+    { entries: [{ url: "http://example.org/#6" }], extData: { "uniq": r() } },
+    { entries: [{ url: "http://example.org/#7" }], extData: { "uniq": r() } },
+  ], selected: 5 }] };
+
+  let loadCount = 0;
+  let nextTestTimer;
+  function test_restore_apptabs_ondemand_progressCallback(aBrowser) {
+    loadCount++;
+
+    // get the tab
+    let tab;
+    for (let i = 0; i < window.gBrowser.tabs.length; i++) {
+      if (!tab && window.gBrowser.tabs[i].linkedBrowser == aBrowser)
+        tab = window.gBrowser.tabs[i];
+    }
+
+    // Check that the load only comes from the selected tab.
+    ok(gBrowser.selectedTab == tab,
+       "test_restore_apptabs_ondemand: load came from selected tab");
+
+    // We should get only 1 load: the selected tab
+    if (loadCount == 1) {
+      nextTestTimer = setTimeout(nextTest, 1000);
+      return;
+    }
+    else if (loadCount > 1) {
+      clearTimeout(nextTestTimer);
+    }
+
+    function nextTest() {
+      window.gBrowser.removeTabsProgressListener(progressListener);
+      runNextTest();
+    }
+    nextTest();
+  }
+
+  window.gBrowser.addTabsProgressListener(progressListener);
+  ss.setBrowserState(JSON.stringify(state));
+}
+
+
 function countTabs() {
   let needsRestore = 0,
       isRestoring = 0,
       wasRestored = 0;
 
   let windowsEnum = Services.wm.getEnumerator("navigator:browser");
 
   while (windowsEnum.hasMoreElements()) {
--- a/browser/components/shell/src/nsWindowsShellService.cpp
+++ b/browser/components/shell/src/nsWindowsShellService.cpp
@@ -184,17 +184,16 @@ typedef struct {
   char* keyName;
   char* valueName;
   char* valueData;
 } SETTING;
 
 #define APP_REG_NAME L"Firefox"
 #define CLS_HTML "FirefoxHTML"
 #define CLS_URL "FirefoxURL"
-#define CPL_DESKTOP L"Control Panel\\Desktop"
 #define VAL_OPEN "\"%APPPATH%\" -requestPending -osint -url \"%1\""
 #define VAL_FILE_ICON "%APPPATH%,1"
 #define DI "\\DefaultIcon"
 #define SOP "\\shell\\open\\command"
 
 #define MAKE_KEY_NAME1(PREFIX, MID) \
   PREFIX MID
 
@@ -612,54 +611,51 @@ nsWindowsShellService::SetDesktopBackgro
   rv = file->GetPath(path);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // write the bitmap to a file in the profile directory
   rv = WriteBitmap(file, container);
 
   // if the file was written successfully, set it as the system wallpaper
   if (NS_SUCCEEDED(rv)) {
-     bool result = false;
-     DWORD  dwDisp = 0;
-     HKEY   key;
-     // Try to create/open a subkey under HKCU.
-     DWORD res = ::RegCreateKeyExW(HKEY_CURRENT_USER, CPL_DESKTOP,
-                                   0, NULL, REG_OPTION_NON_VOLATILE,
-                                   KEY_WRITE, NULL, &key, &dwDisp);
-    if (REG_SUCCEEDED(res)) {
-      PRUnichar tile[2], style[2];
-      switch (aPosition) {
-        case BACKGROUND_TILE:
-          tile[0] = '1';
-          style[0] = '1';
-          break;
-        case BACKGROUND_CENTER:
-          tile[0] = '0';
-          style[0] = '0';
-          break;
-        case BACKGROUND_STRETCH:
-          tile[0] = '0';
-          style[0] = '2';
-          break;
-      }
-      tile[1] = '\0';
-      style[1] = '\0';
+    nsCOMPtr<nsIWindowsRegKey> regKey =
+      do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
+                        NS_LITERAL_STRING("Control Panel\\Desktop"),
+                        nsIWindowsRegKey::ACCESS_SET_VALUE);
+    NS_ENSURE_SUCCESS(rv, rv);
 
-      // The size is always 3 unicode characters.
-      PRInt32 size = 3 * sizeof(PRUnichar);
-      ::RegSetValueExW(key, L"TileWallpaper",
-                       0, REG_SZ, (const BYTE *)tile, size);
-      ::RegSetValueExW(key, L"WallpaperStyle",
-                       0, REG_SZ, (const BYTE *)style, size);
-      ::SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, (PVOID)path.get(),
-                              SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
+    nsAutoString tile;
+    nsAutoString style;
+    switch (aPosition) {
+      case BACKGROUND_TILE:
+        style.AssignLiteral("0");
+        tile.AssignLiteral("1");
+        break;
+      case BACKGROUND_CENTER:
+        style.AssignLiteral("0");
+        tile.AssignLiteral("0");
+        break;
+      case BACKGROUND_STRETCH:
+        style.AssignLiteral("2");
+        tile.AssignLiteral("0");
+        break;
+    }
 
-      // Close the key we opened.
-      ::RegCloseKey(key);
-    }
+    rv = regKey->WriteStringValue(NS_LITERAL_STRING("TileWallpaper"), tile);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = regKey->WriteStringValue(NS_LITERAL_STRING("WallpaperStyle"), style);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = regKey->Close();
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    ::SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, (PVOID)path.get(),
+                            SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
   }
   return rv;
 }
 
 NS_IMETHODIMP
 nsWindowsShellService::OpenApplication(PRInt32 aApplication)
 {
   nsAutoString application;
@@ -774,38 +770,34 @@ nsWindowsShellService::SetDesktopBackgro
   int aParameters[2] = { COLOR_BACKGROUND, COLOR_DESKTOP };
   BYTE r = (aColor >> 16);
   BYTE g = (aColor << 16) >> 24;
   BYTE b = (aColor << 24) >> 24;
   COLORREF colors[2] = { RGB(r,g,b), RGB(r,g,b) };
 
   ::SetSysColors(sizeof(aParameters) / sizeof(int), aParameters, colors);
 
-  bool result = false;
-  DWORD  dwDisp = 0;
-  HKEY   key;
-  // Try to create/open a subkey under HKCU.
-  DWORD rv = ::RegCreateKeyExW(HKEY_CURRENT_USER,
-                               L"Control Panel\\Colors", 0, NULL,
-                               REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
-                               &key, &dwDisp);
+  nsresult rv;
+  nsCOMPtr<nsIWindowsRegKey> regKey =
+    do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  if (REG_SUCCEEDED(rv)) {
-    char rgb[12];
-    sprintf((char*)rgb, "%u %u %u\0", r, g, b);
-    NS_ConvertUTF8toUTF16 backColor(rgb);
+  rv = regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
+                      NS_LITERAL_STRING("Control Panel\\Colors"),
+                      nsIWindowsRegKey::ACCESS_SET_VALUE);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-    ::RegSetValueExW(key, L"Background",
-                     0, REG_SZ, (const BYTE *)backColor.get(),
-                     (backColor.Length() + 1) * sizeof(PRUnichar));
-  }
-  
-  // Close the key we opened.
-  ::RegCloseKey(key);
-  return NS_OK;
+  PRUnichar rgb[12];
+  _snwprintf(rgb, 12, L"%u %u %u", r, g, b);
+
+  rv = regKey->WriteStringValue(NS_LITERAL_STRING("Background"),
+                                nsDependentString(rgb));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return regKey->Close();
 }
 
 NS_IMETHODIMP
 nsWindowsShellService::OpenApplicationWithURI(nsILocalFile* aApplication,
                                               const nsACString& aURI)
 {
   nsresult rv;
   nsCOMPtr<nsIProcess> process = 
--- a/browser/devtools/jar.mn
+++ b/browser/devtools/jar.mn
@@ -1,15 +1,15 @@
 browser.jar:
 *   content/browser/inspector.html                (highlighter/inspector.html)
     content/browser/NetworkPanel.xhtml            (webconsole/NetworkPanel.xhtml)
 *   content/browser/scratchpad.xul                (scratchpad/scratchpad.xul)
     content/browser/scratchpad.js                 (scratchpad/scratchpad.js)
+    content/browser/splitview.css                 (shared/splitview.css)
 *   content/browser/styleeditor.xul               (styleeditor/styleeditor.xul)
-    content/browser/splitview.css                 (styleeditor/splitview.css)
     content/browser/styleeditor.css               (styleeditor/styleeditor.css)
     content/browser/devtools/csshtmltree.xul      (styleinspector/csshtmltree.xul)
     content/browser/devtools/cssruleview.xul      (styleinspector/cssruleview.xul)
     content/browser/devtools/styleinspector.css   (styleinspector/styleinspector.css)
     content/browser/orion.js                      (sourceeditor/orion/orion.js)
     content/browser/orion.css                     (sourceeditor/orion/orion.css)
     content/browser/orion-mozilla.css             (sourceeditor/orion/mozilla.css)
     content/browser/source-editor-overlay.xul     (sourceeditor/source-editor-overlay.xul)
--- a/browser/devtools/shared/Makefile.in
+++ b/browser/devtools/shared/Makefile.in
@@ -47,11 +47,9 @@ include $(DEPTH)/config/autoconf.mk
 
 ifdef ENABLE_TESTS
 	DIRS += test
 endif
 
 include $(topsrcdir)/config/rules.mk
 
 libs::
-	$(NSINSTALL) $(srcdir)/Templater.jsm $(FINAL_TARGET)/modules/devtools
-	$(NSINSTALL) $(srcdir)/Promise.jsm $(FINAL_TARGET)/modules/devtools
-	$(NSINSTALL) $(srcdir)/LayoutHelpers.jsm $(FINAL_TARGET)/modules/devtools
+	$(NSINSTALL) $(srcdir)/*.jsm $(FINAL_TARGET)/modules/devtools
new file mode 100644
--- /dev/null
+++ b/browser/devtools/shared/SplitView.jsm
@@ -0,0 +1,453 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** 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 Style Editor 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):
+ *   Cedric Vivier <cedricv@neonux.com> (original author)
+ *   Paul Rouget <paul@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+"use strict";
+
+const EXPORTED_SYMBOLS = ["SplitView"];
+
+/* this must be kept in sync with CSS (ie. splitview.css) */
+const LANDSCAPE_MEDIA_QUERY = "(min-aspect-ratio: 5/3)";
+
+const BINDING_USERDATA = "splitview-binding";
+
+
+/**
+ * SplitView constructor
+ *
+ * Initialize the split view UI on an existing DOM element.
+ *
+ * A split view contains items, each of those having one summary and one details
+ * elements.
+ * It is adaptive as it behaves similarly to a richlistbox when there the aspect
+ * ratio is narrow or as a pair listbox-box otherwise.
+ *
+ * @param DOMElement aRoot
+ * @see appendItem
+ */
+function SplitView(aRoot)
+{
+  this._root = aRoot;
+  this._controller = aRoot.querySelector(".splitview-controller");
+  this._nav = aRoot.querySelector(".splitview-nav");
+  this._side = aRoot.querySelector(".splitview-side-details");
+  this._activeSummary = null
+
+  this._mql = aRoot.ownerDocument.defaultView.matchMedia(LANDSCAPE_MEDIA_QUERY);
+
+  this._filter = aRoot.querySelector(".splitview-filter");
+  if (this._filter) {
+    this._setupFilterBox();
+  }
+
+  // items list focus and search-on-type handling
+  this._nav.addEventListener("keydown", function onKeyCatchAll(aEvent) {
+    function getFocusedItemWithin(nav) {
+      let node = nav.ownerDocument.activeElement;
+      while (node && node.parentNode != nav) {
+        node = node.parentNode;
+      }
+      return node;
+    }
+
+    // do not steal focus from inside iframes or textboxes
+    if (aEvent.target.ownerDocument != this._nav.ownerDocument ||
+        aEvent.target.tagName == "input" ||
+        aEvent.target.tagName == "textbox" ||
+        aEvent.target.tagName == "textarea" ||
+        aEvent.target.classList.contains("textbox")) {
+      return false;
+    }
+
+    // handle keyboard navigation within the items list
+    let newFocusOrdinal;
+    if (aEvent.keyCode == aEvent.DOM_VK_PAGE_UP ||
+        aEvent.keyCode == aEvent.DOM_VK_HOME) {
+      newFocusOrdinal = 0;
+    } else if (aEvent.keyCode == aEvent.DOM_VK_PAGE_DOWN ||
+               aEvent.keyCode == aEvent.DOM_VK_END) {
+      newFocusOrdinal = this._nav.childNodes.length - 1;
+    } else if (aEvent.keyCode == aEvent.DOM_VK_UP) {
+      newFocusOrdinal = getFocusedItemWithin(this._nav).getAttribute("data-ordinal");
+      newFocusOrdinal--;
+    } else if (aEvent.keyCode == aEvent.DOM_VK_DOWN) {
+      newFocusOrdinal = getFocusedItemWithin(this._nav).getAttribute("data-ordinal");
+      newFocusOrdinal++;
+    }
+    if (newFocusOrdinal !== undefined) {
+      aEvent.stopPropagation();
+      let el = this.getSummaryElementByOrdinal(newFocusOrdinal);
+      if (el) {
+        el.focus();
+      }
+      return false;
+    }
+
+    // search-on-type when any non-whitespace character is pressed while list
+    // has the focus
+    if (this._filter &&
+        !/\s/.test(String.fromCharCode(aEvent.which))) {
+      this._filter.focus();
+    }
+  }.bind(this), false);
+}
+
+SplitView.prototype = {
+  /**
+    * Retrieve whether the UI currently has a landscape orientation.
+    *
+    * @return boolean
+    */
+  get isLandscape() this._mql.matches,
+
+  /**
+    * Retrieve the root element.
+    *
+    * @return DOMElement
+    */
+  get rootElement() this._root,
+
+  /**
+    * Retrieve the active item's summary element or null if there is none.
+    *
+    * @return DOMElement
+    */
+  get activeSummary() this._activeSummary,
+
+  /**
+    * Set the active item's summary element.
+    *
+    * @param DOMElement aSummary
+    */
+  set activeSummary(aSummary)
+  {
+    if (aSummary == this._activeSummary) {
+      return;
+    }
+
+    if (this._activeSummary) {
+      let binding = this._activeSummary.getUserData(BINDING_USERDATA);
+
+      if (binding.onHide) {
+        binding.onHide(this._activeSummary, binding._details, binding.data);
+      }
+
+      this._activeSummary.classList.remove("splitview-active");
+      binding._details.classList.remove("splitview-active");
+    }
+
+    if (!aSummary) {
+      return;
+    }
+
+    let binding = aSummary.getUserData(BINDING_USERDATA);
+    aSummary.classList.add("splitview-active");
+    binding._details.classList.add("splitview-active");
+
+    this._activeSummary = aSummary;
+
+    if (binding.onShow) {
+      binding.onShow(aSummary, binding._details, binding.data);
+    }
+    aSummary.scrollIntoView();
+  },
+
+  /**
+    * Retrieve the active item's details element or null if there is none.
+    * @return DOMElement
+    */
+  get activeDetails()
+  {
+    let summary = this.activeSummary;
+    return summary ? summary.getUserData(BINDING_USERDATA)._details : null;
+  },
+
+  /**
+   * Retrieve the summary element for a given ordinal.
+   *
+   * @param number aOrdinal
+   * @return DOMElement
+   *         Summary element with given ordinal or null if not found.
+   * @see appendItem
+   */
+  getSummaryElementByOrdinal: function SEC_getSummaryElementByOrdinal(aOrdinal)
+  {
+    return this._nav.querySelector("* > li[data-ordinal='" + aOrdinal + "']");
+  },
+
+  /**
+   * Append an item to the split view.
+   *
+   * @param DOMElement aSummary
+   *        The summary element for the item.
+   * @param DOMElement aDetails
+   *        The details element for the item.
+   * @param object aOptions
+   *     Optional object that defines custom behavior and data for the item.
+   *     All properties are optional :
+   *     - function(DOMElement summary, DOMElement details, object data) onCreate
+   *         Called when the item has been added.
+   *     - function(summary, details, data) onShow
+   *         Called when the item is shown/active.
+   *     - function(summary, details, data) onHide
+   *         Called when the item is hidden/inactive.
+   *     - function(summary, details, data) onDestroy
+   *         Called when the item has been removed.
+   *     - function(summary, details, data, query) onFilterBy
+   *         Called when the user performs a filtering search.
+   *         If the function returns false, the item does not match query
+   *         string and will be hidden.
+   *     - object data
+   *         Object to pass to the callbacks above.
+   *     - number ordinal
+   *         Items with a lower ordinal are displayed before those with a
+   *         higher ordinal.
+   */
+  appendItem: function ASV_appendItem(aSummary, aDetails, aOptions)
+  {
+    let binding = aOptions || {};
+
+    binding._summary = aSummary;
+    binding._details = aDetails;
+    aSummary.setUserData(BINDING_USERDATA, binding, null);
+
+    this._nav.appendChild(aSummary);
+
+    aSummary.addEventListener("click", function onSummaryClick(aEvent) {
+      aEvent.stopPropagation();
+      this.activeSummary = aSummary;
+    }.bind(this), false);
+
+    this._side.appendChild(aDetails);
+
+    if (binding.onCreate) {
+      // queue onCreate handler
+      this._root.ownerDocument.defaultView.setTimeout(function () {
+        binding.onCreate(aSummary, aDetails, binding.data);
+      }, 0);
+    }
+  },
+
+  /**
+   * Append an item to the split view according to two template elements
+   * (one for the item's summary and the other for the item's details).
+   *
+   * @param string aName
+   *        Name of the template elements to instantiate.
+   *        Requires two (hidden) DOM elements with id "splitview-tpl-summary-"
+   *        and "splitview-tpl-details-" suffixed with aName.
+   * @param object aOptions
+   *        Optional object that defines custom behavior and data for the item.
+   *        See appendItem for full description.
+   * @return object{summary:,details:}
+   *         Object with the new DOM elements created for summary and details.
+   * @see appendItem
+   */
+  appendTemplatedItem: function ASV_appendTemplatedItem(aName, aOptions)
+  {
+    aOptions = aOptions || {};
+    let summary = this._root.querySelector("#splitview-tpl-summary-" + aName);
+    let details = this._root.querySelector("#splitview-tpl-details-" + aName);
+
+    summary = summary.cloneNode(true);
+    summary.id = "";
+    if (aOptions.ordinal !== undefined) { // can be zero
+      summary.style.MozBoxOrdinalGroup = aOptions.ordinal;
+      summary.setAttribute("data-ordinal", aOptions.ordinal);
+    }
+    details = details.cloneNode(true);
+    details.id = "";
+
+    this.appendItem(summary, details, aOptions);
+    return {summary: summary, details: details};
+  },
+
+  /**
+    * Remove an item from the split view.
+    *
+    * @param DOMElement aSummary
+    *        Summary element of the item to remove.
+    */
+  removeItem: function ASV_removeItem(aSummary)
+  {
+    if (aSummary == this._activeSummary) {
+      this.activeSummary = null;
+    }
+
+    let binding = aSummary.getUserData(BINDING_USERDATA);
+    aSummary.parentNode.removeChild(aSummary);
+    binding._details.parentNode.removeChild(binding._details);
+
+    if (binding.onDestroy) {
+      binding.onDestroy(aSummary, binding._details, binding.data);
+    }
+  },
+
+  /**
+   * Remove all items from the split view.
+   */
+  removeAll: function ASV_removeAll()
+  {
+    while (this._nav.hasChildNodes()) {
+      this.removeItem(this._nav.firstChild);
+    }
+  },
+
+  /**
+    * Filter items by given string.
+    * Matching is performed on every item by calling onFilterBy when defined
+    * and then by searching aQuery in the summary element's text item.
+    * Non-matching item is hidden.
+    *
+    * If no item matches, 'splitview-all-filtered' class is set on the filter
+    * input element and the splitview-nav element.
+    *
+    * @param string aQuery
+    *        The query string. Use null to reset (no filter).
+    * @return number
+    *         The number of filtered (non-matching) item.
+    */
+  filterItemsBy: function ASV_filterItemsBy(aQuery)
+  {
+    if (!this._nav.hasChildNodes()) {
+      return 0;
+    }
+    if (aQuery) {
+      aQuery = aQuery.trim();
+    }
+    if (!aQuery) {
+      for (let i = 0; i < this._nav.childNodes.length; ++i) {
+        this._nav.childNodes[i].classList.remove("splitview-filtered");
+      }
+      this._filter.classList.remove("splitview-all-filtered");
+      this._nav.classList.remove("splitview-all-filtered");
+      return 0;
+    }
+
+    let count = 0;
+    let filteredCount = 0;
+    for (let i = 0; i < this._nav.childNodes.length; ++i) {
+      let summary = this._nav.childNodes[i];
+
+      let matches = false;
+      let binding = summary.getUserData(BINDING_USERDATA);
+      if (binding.onFilterBy) {
+        matches = binding.onFilterBy(summary, binding._details, binding.data, aQuery);
+      }
+      if (!matches) { // try text content
+        let content = summary.textContent.toUpperCase();
+        matches = (content.indexOf(aQuery.toUpperCase()) > -1);
+      }
+
+      count++;
+      if (!matches) {
+        summary.classList.add("splitview-filtered");
+        filteredCount++;
+      } else {
+        summary.classList.remove("splitview-filtered");
+      }
+    }
+
+    if (count > 0 && filteredCount == count) {
+      this._filter.classList.add("splitview-all-filtered");
+      this._nav.classList.add("splitview-all-filtered");
+    } else {
+      this._filter.classList.remove("splitview-all-filtered");
+      this._nav.classList.remove("splitview-all-filtered");
+    }
+    return filteredCount;
+  },
+
+  /**
+   * Set the item's CSS class name.
+   * This sets the class on both the summary and details elements, retaining
+   * any SplitView-specific classes.
+   *
+   * @param DOMElement aSummary
+   *        Summary element of the item to set.
+   * @param string aClassName
+   *        One or more space-separated CSS classes.
+   */
+  setItemClassName: function ASV_setItemClassName(aSummary, aClassName)
+  {
+    let binding = aSummary.getUserData(BINDING_USERDATA);
+    let viewSpecific;
+
+    viewSpecific = aSummary.className.match(/(splitview\-[\w-]+)/g);
+    viewSpecific = viewSpecific ? viewSpecific.join(" ") : "";
+    aSummary.className = viewSpecific + " " + aClassName;
+
+    viewSpecific = binding._details.className.match(/(splitview\-[\w-]+)/g);
+    viewSpecific = viewSpecific ? viewSpecific.join(" ") : "";
+    binding._details.className = viewSpecific + " " + aClassName;
+  },
+
+  /**
+   * Set up filter search box.
+   */
+  _setupFilterBox: function ASV__setupFilterBox()
+  {
+    let clearFilter = function clearFilter(aEvent) {
+      this._filter.value = "";
+      this.filterItemsBy("");
+      return false;
+    }.bind(this);
+
+    this._filter.addEventListener("command", function onFilterInput(aEvent) {
+      this.filterItemsBy(this._filter.value);
+    }.bind(this), false);
+
+    this._filter.addEventListener("keyup", function onFilterKeyUp(aEvent) {
+      if (aEvent.keyCode == aEvent.DOM_VK_ESCAPE) {
+        clearFilter();
+      }
+      if (aEvent.keyCode == aEvent.DOM_VK_ENTER ||
+          aEvent.keyCode == aEvent.DOM_VK_RETURN) {
+        // autofocus matching item if there is only one
+        let matches = this._nav.querySelectorAll("* > li:not(.splitview-filtered)");
+        if (matches.length == 1) {
+          this.activeSummary = matches[0];
+        }
+      }
+    }.bind(this), false);
+
+    let clearButtons = this._root.querySelectorAll(".splitview-filter-clearButton");
+    for (let i = 0; i < clearButtons.length; ++i) {
+      clearButtons[i].addEventListener("click", clearFilter, false);
+    }
+  }
+};
new file mode 100644
--- /dev/null
+++ b/browser/devtools/shared/splitview.css
@@ -0,0 +1,126 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** 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 Style Editor 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):
+ *   Cedric Vivier <cedricv@neonux.com> (original author)
+ *   Paul Rouget <paul@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 ***** */
+
+box,
+.splitview-nav {
+  -moz-box-flex: 1;
+  -moz-box-orient: vertical;
+}
+
+.splitview-nav-container {
+  -moz-box-pack: center;
+}
+
+.loading .splitview-nav-container > .placeholder {
+  display: none !important;
+}
+
+.splitview-controller,
+.splitview-main {
+  -moz-box-flex: 0;
+}
+
+.splitview-controller {
+  min-height: 3em;
+  max-height: 14em;
+}
+
+.splitview-nav {
+  display: -moz-box;
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+
+/* only the active details pane is shown */
+.splitview-side-details > * {
+  display: none;
+}
+.splitview-side-details > .splitview-active {
+  display: -moz-box;
+}
+
+.splitview-landscape-resizer {
+  cursor: ew-resize;
+}
+
+/* this is to keep in sync with SplitView.jsm's LANDSCAPE_MEDIA_QUERY */
+@media (min-aspect-ratio: 5/3) {
+  .splitview-root {
+    -moz-box-orient: horizontal;
+  }
+  .splitview-controller {
+    max-height: none;
+  }
+  .splitview-details {
+    display: none;
+  }
+  .splitview-details.splitview-active {
+    display: -moz-box;
+  }
+}
+
+/* filtered items are hidden */
+ol.splitview-nav > li.splitview-filtered {
+  display: none;
+}
+
+/* "empty list" and "all filtered" placeholders are hidden */
+.splitview-nav:empty,
+.splitview-nav.splitview-all-filtered,
+.splitview-nav + .splitview-nav.placeholder {
+  display: none;
+}
+.splitview-nav.splitview-all-filtered ~ .splitview-nav.placeholder.all-filtered,
+.splitview-nav:empty ~ .splitview-nav.placeholder.empty {
+  display: -moz-box;
+}
+
+.splitview-portrait-resizer {
+  display: none;
+}
+
+/* portrait mode */
+@media (max-aspect-ratio: 5/3) {
+  #splitview-details-toolbar {
+    display: none;
+  }
+
+  .splitview-portrait-resizer {
+    display: -moz-box;
+  }
+}
deleted file mode 100644
--- a/browser/devtools/styleeditor/SplitView.jsm
+++ /dev/null
@@ -1,453 +0,0 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
-/* ***** 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 Style Editor 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):
- *   Cedric Vivier <cedricv@neonux.com> (original author)
- *   Paul Rouget <paul@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-"use strict";
-
-const EXPORTED_SYMBOLS = ["SplitView"];
-
-/* this must be kept in sync with CSS (ie. splitview.css) */
-const LANDSCAPE_MEDIA_QUERY = "(min-aspect-ratio: 5/3)";
-
-const BINDING_USERDATA = "splitview-binding";
-
-
-/**
- * SplitView constructor
- *
- * Initialize the split view UI on an existing DOM element.
- *
- * A split view contains items, each of those having one summary and one details
- * elements.
- * It is adaptive as it behaves similarly to a richlistbox when there the aspect
- * ratio is narrow or as a pair listbox-box otherwise.
- *
- * @param DOMElement aRoot
- * @see appendItem
- */
-function SplitView(aRoot)
-{
-  this._root = aRoot;
-  this._controller = aRoot.querySelector(".splitview-controller");
-  this._nav = aRoot.querySelector(".splitview-nav");
-  this._side = aRoot.querySelector(".splitview-side-details");
-  this._activeSummary = null
-
-  this._mql = aRoot.ownerDocument.defaultView.matchMedia(LANDSCAPE_MEDIA_QUERY);
-
-  this._filter = aRoot.querySelector(".splitview-filter");
-  if (this._filter) {
-    this._setupFilterBox();
-  }
-
-  // items list focus and search-on-type handling
-  this._nav.addEventListener("keydown", function onKeyCatchAll(aEvent) {
-    function getFocusedItemWithin(nav) {
-      let node = nav.ownerDocument.activeElement;
-      while (node && node.parentNode != nav) {
-        node = node.parentNode;
-      }
-      return node;
-    }
-
-    // do not steal focus from inside iframes or textboxes
-    if (aEvent.target.ownerDocument != this._nav.ownerDocument ||
-        aEvent.target.tagName == "input" ||
-        aEvent.target.tagName == "textbox" ||
-        aEvent.target.tagName == "textarea" ||
-        aEvent.target.classList.contains("textbox")) {
-      return false;
-    }
-
-    // handle keyboard navigation within the items list
-    let newFocusOrdinal;
-    if (aEvent.keyCode == aEvent.DOM_VK_PAGE_UP ||
-        aEvent.keyCode == aEvent.DOM_VK_HOME) {
-      newFocusOrdinal = 0;
-    } else if (aEvent.keyCode == aEvent.DOM_VK_PAGE_DOWN ||
-               aEvent.keyCode == aEvent.DOM_VK_END) {
-      newFocusOrdinal = this._nav.childNodes.length - 1;
-    } else if (aEvent.keyCode == aEvent.DOM_VK_UP) {
-      newFocusOrdinal = getFocusedItemWithin(this._nav).getAttribute("data-ordinal");
-      newFocusOrdinal--;
-    } else if (aEvent.keyCode == aEvent.DOM_VK_DOWN) {
-      newFocusOrdinal = getFocusedItemWithin(this._nav).getAttribute("data-ordinal");
-      newFocusOrdinal++;
-    }
-    if (newFocusOrdinal !== undefined) {
-      aEvent.stopPropagation();
-      let el = this.getSummaryElementByOrdinal(newFocusOrdinal);
-      if (el) {
-        el.focus();
-      }
-      return false;
-    }
-
-    // search-on-type when any non-whitespace character is pressed while list
-    // has the focus
-    if (this._filter &&
-        !/\s/.test(String.fromCharCode(aEvent.which))) {
-      this._filter.focus();
-    }
-  }.bind(this), false);
-}
-
-SplitView.prototype = {
-  /**
-    * Retrieve whether the UI currently has a landscape orientation.
-    *
-    * @return boolean
-    */
-  get isLandscape() this._mql.matches,
-
-  /**
-    * Retrieve the root element.
-    *
-    * @return DOMElement
-    */
-  get rootElement() this._root,
-
-  /**
-    * Retrieve the active item's summary element or null if there is none.
-    *
-    * @return DOMElement
-    */
-  get activeSummary() this._activeSummary,
-
-  /**
-    * Set the active item's summary element.
-    *
-    * @param DOMElement aSummary
-    */
-  set activeSummary(aSummary)
-  {
-    if (aSummary == this._activeSummary) {
-      return;
-    }
-
-    if (this._activeSummary) {
-      let binding = this._activeSummary.getUserData(BINDING_USERDATA);
-
-      if (binding.onHide) {
-        binding.onHide(this._activeSummary, binding._details, binding.data);
-      }
-
-      this._activeSummary.classList.remove("splitview-active");
-      binding._details.classList.remove("splitview-active");
-    }
-
-    if (!aSummary) {
-      return;
-    }
-
-    let binding = aSummary.getUserData(BINDING_USERDATA);
-    aSummary.classList.add("splitview-active");
-    binding._details.classList.add("splitview-active");
-
-    this._activeSummary = aSummary;
-
-    if (binding.onShow) {
-      binding.onShow(aSummary, binding._details, binding.data);
-    }
-    aSummary.scrollIntoView();
-  },
-
-  /**
-    * Retrieve the active item's details element or null if there is none.
-    * @return DOMElement
-    */
-  get activeDetails()
-  {
-    let summary = this.activeSummary;
-    return summary ? summary.getUserData(BINDING_USERDATA)._details : null;
-  },
-
-  /**
-   * Retrieve the summary element for a given ordinal.
-   *
-   * @param number aOrdinal
-   * @return DOMElement
-   *         Summary element with given ordinal or null if not found.
-   * @see appendItem
-   */
-  getSummaryElementByOrdinal: function SEC_getSummaryElementByOrdinal(aOrdinal)
-  {
-    return this._nav.querySelector("* > li[data-ordinal='" + aOrdinal + "']");
-  },
-
-  /**
-   * Append an item to the split view.
-   *
-   * @param DOMElement aSummary
-   *        The summary element for the item.
-   * @param DOMElement aDetails
-   *        The details element for the item.
-   * @param object aOptions
-   *     Optional object that defines custom behavior and data for the item.
-   *     All properties are optional :
-   *     - function(DOMElement summary, DOMElement details, object data) onCreate
-   *         Called when the item has been added.
-   *     - function(summary, details, data) onShow
-   *         Called when the item is shown/active.
-   *     - function(summary, details, data) onHide
-   *         Called when the item is hidden/inactive.
-   *     - function(summary, details, data) onDestroy
-   *         Called when the item has been removed.
-   *     - function(summary, details, data, query) onFilterBy
-   *         Called when the user performs a filtering search.
-   *         If the function returns false, the item does not match query
-   *         string and will be hidden.
-   *     - object data
-   *         Object to pass to the callbacks above.
-   *     - number ordinal
-   *         Items with a lower ordinal are displayed before those with a
-   *         higher ordinal.
-   */
-  appendItem: function ASV_appendItem(aSummary, aDetails, aOptions)
-  {
-    let binding = aOptions || {};
-
-    binding._summary = aSummary;
-    binding._details = aDetails;
-    aSummary.setUserData(BINDING_USERDATA, binding, null);
-
-    this._nav.appendChild(aSummary);
-
-    aSummary.addEventListener("click", function onSummaryClick(aEvent) {
-      aEvent.stopPropagation();
-      this.activeSummary = aSummary;
-    }.bind(this), false);
-
-    this._side.appendChild(aDetails);
-
-    if (binding.onCreate) {
-      // queue onCreate handler
-      this._root.ownerDocument.defaultView.setTimeout(function () {
-        binding.onCreate(aSummary, aDetails, binding.data);
-      }, 0);
-    }
-  },
-
-  /**
-   * Append an item to the split view according to two template elements
-   * (one for the item's summary and the other for the item's details).
-   *
-   * @param string aName
-   *        Name of the template elements to instantiate.
-   *        Requires two (hidden) DOM elements with id "splitview-tpl-summary-"
-   *        and "splitview-tpl-details-" suffixed with aName.
-   * @param object aOptions
-   *        Optional object that defines custom behavior and data for the item.
-   *        See appendItem for full description.
-   * @return object{summary:,details:}
-   *         Object with the new DOM elements created for summary and details.
-   * @see appendItem
-   */
-  appendTemplatedItem: function ASV_appendTemplatedItem(aName, aOptions)
-  {
-    aOptions = aOptions || {};
-    let summary = this._root.querySelector("#splitview-tpl-summary-" + aName);
-    let details = this._root.querySelector("#splitview-tpl-details-" + aName);
-
-    summary = summary.cloneNode(true);
-    summary.id = "";
-    if (aOptions.ordinal !== undefined) { // can be zero
-      summary.style.MozBoxOrdinalGroup = aOptions.ordinal;
-      summary.setAttribute("data-ordinal", aOptions.ordinal);
-    }
-    details = details.cloneNode(true);
-    details.id = "";
-
-    this.appendItem(summary, details, aOptions);
-    return {summary: summary, details: details};
-  },
-
-  /**
-    * Remove an item from the split view.
-    *
-    * @param DOMElement aSummary
-    *        Summary element of the item to remove.
-    */
-  removeItem: function ASV_removeItem(aSummary)
-  {
-    if (aSummary == this._activeSummary) {
-      this.activeSummary = null;
-    }
-
-    let binding = aSummary.getUserData(BINDING_USERDATA);
-    aSummary.parentNode.removeChild(aSummary);
-    binding._details.parentNode.removeChild(binding._details);
-
-    if (binding.onDestroy) {
-      binding.onDestroy(aSummary, binding._details, binding.data);
-    }
-  },
-
-  /**
-   * Remove all items from the split view.
-   */
-  removeAll: function ASV_removeAll()
-  {
-    while (this._nav.hasChildNodes()) {
-      this.removeItem(this._nav.firstChild);
-    }
-  },
-
-  /**
-    * Filter items by given string.
-    * Matching is performed on every item by calling onFilterBy when defined
-    * and then by searching aQuery in the summary element's text item.
-    * Non-matching item is hidden.
-    *
-    * If no item matches, 'splitview-all-filtered' class is set on the filter
-    * input element and the splitview-nav element.
-    *
-    * @param string aQuery
-    *        The query string. Use null to reset (no filter).
-    * @return number
-    *         The number of filtered (non-matching) item.
-    */
-  filterItemsBy: function ASV_filterItemsBy(aQuery)
-  {
-    if (!this._nav.hasChildNodes()) {
-      return 0;
-    }
-    if (aQuery) {
-      aQuery = aQuery.trim();
-    }
-    if (!aQuery) {
-      for (let i = 0; i < this._nav.childNodes.length; ++i) {
-        this._nav.childNodes[i].classList.remove("splitview-filtered");
-      }
-      this._filter.classList.remove("splitview-all-filtered");
-      this._nav.classList.remove("splitview-all-filtered");
-      return 0;
-    }
-
-    let count = 0;
-    let filteredCount = 0;
-    for (let i = 0; i < this._nav.childNodes.length; ++i) {
-      let summary = this._nav.childNodes[i];
-
-      let matches = false;
-      let binding = summary.getUserData(BINDING_USERDATA);
-      if (binding.onFilterBy) {
-        matches = binding.onFilterBy(summary, binding._details, binding.data, aQuery);
-      }
-      if (!matches) { // try text content
-        let content = summary.textContent.toUpperCase();
-        matches = (content.indexOf(aQuery.toUpperCase()) > -1);
-      }
-
-      count++;
-      if (!matches) {
-        summary.classList.add("splitview-filtered");
-        filteredCount++;
-      } else {
-        summary.classList.remove("splitview-filtered");
-      }
-    }
-
-    if (count > 0 && filteredCount == count) {
-      this._filter.classList.add("splitview-all-filtered");
-      this._nav.classList.add("splitview-all-filtered");
-    } else {
-      this._filter.classList.remove("splitview-all-filtered");
-      this._nav.classList.remove("splitview-all-filtered");
-    }
-    return filteredCount;
-  },
-
-  /**
-   * Set the item's CSS class name.
-   * This sets the class on both the summary and details elements, retaining
-   * any SplitView-specific classes.
-   *
-   * @param DOMElement aSummary
-   *        Summary element of the item to set.
-   * @param string aClassName
-   *        One or more space-separated CSS classes.
-   */
-  setItemClassName: function ASV_setItemClassName(aSummary, aClassName)
-  {
-    let binding = aSummary.getUserData(BINDING_USERDATA);
-    let viewSpecific;
-
-    viewSpecific = aSummary.className.match(/(splitview\-[\w-]+)/g);
-    viewSpecific = viewSpecific ? viewSpecific.join(" ") : "";
-    aSummary.className = viewSpecific + " " + aClassName;
-
-    viewSpecific = binding._details.className.match(/(splitview\-[\w-]+)/g);
-    viewSpecific = viewSpecific ? viewSpecific.join(" ") : "";
-    binding._details.className = viewSpecific + " " + aClassName;
-  },
-
-  /**
-   * Set up filter search box.
-   */
-  _setupFilterBox: function ASV__setupFilterBox()
-  {
-    let clearFilter = function clearFilter(aEvent) {
-      this._filter.value = "";
-      this.filterItemsBy("");
-      return false;
-    }.bind(this);
-
-    this._filter.addEventListener("command", function onFilterInput(aEvent) {
-      this.filterItemsBy(this._filter.value);
-    }.bind(this), false);
-
-    this._filter.addEventListener("keyup", function onFilterKeyUp(aEvent) {
-      if (aEvent.keyCode == aEvent.DOM_VK_ESCAPE) {
-        clearFilter();
-      }
-      if (aEvent.keyCode == aEvent.DOM_VK_ENTER ||
-          aEvent.keyCode == aEvent.DOM_VK_RETURN) {
-        // autofocus matching item if there is only one
-        let matches = this._nav.querySelectorAll("* > li:not(.splitview-filtered)");
-        if (matches.length == 1) {
-          this.activeSummary = matches[0];
-        }
-      }
-    }.bind(this), false);
-
-    let clearButtons = this._root.querySelectorAll(".splitview-filter-clearButton");
-    for (let i = 0; i < clearButtons.length; ++i) {
-      clearButtons[i].addEventListener("click", clearFilter, false);
-    }
-  }
-};
deleted file mode 100644
--- a/browser/devtools/styleeditor/splitview.css
+++ /dev/null
@@ -1,126 +0,0 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
-/* ***** 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 Style Editor 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):
- *   Cedric Vivier <cedricv@neonux.com> (original author)
- *   Paul Rouget <paul@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 ***** */
-
-box,
-.splitview-nav {
-  -moz-box-flex: 1;
-  -moz-box-orient: vertical;
-}
-
-.splitview-nav-container {
-  -moz-box-pack: center;
-}
-
-.loading .splitview-nav-container > .placeholder {
-  display: none !important;
-}
-
-.splitview-controller,
-.splitview-main {
-  -moz-box-flex: 0;
-}
-
-.splitview-controller {
-  min-height: 3em;
-  max-height: 14em;
-}
-
-.splitview-nav {
-  display: -moz-box;
-  overflow-x: hidden;
-  overflow-y: auto;
-}
-
-/* only the active details pane is shown */
-.splitview-side-details > * {
-  display: none;
-}
-.splitview-side-details > .splitview-active {
-  display: -moz-box;
-}
-
-.splitview-landscape-resizer {
-  cursor: ew-resize;
-}
-
-/* this is to keep in sync with SplitView.jsm's LANDSCAPE_MEDIA_QUERY */
-@media (min-aspect-ratio: 5/3) {
-  .splitview-root {
-    -moz-box-orient: horizontal;
-  }
-  .splitview-controller {
-    max-height: none;
-  }
-  .splitview-details {
-    display: none;
-  }
-  .splitview-details.splitview-active {
-    display: -moz-box;
-  }
-}
-
-/* filtered items are hidden */
-ol.splitview-nav > li.splitview-filtered {
-  display: none;
-}
-
-/* "empty list" and "all filtered" placeholders are hidden */
-.splitview-nav:empty,
-.splitview-nav.splitview-all-filtered,
-.splitview-nav + .splitview-nav.placeholder {
-  display: none;
-}
-.splitview-nav.splitview-all-filtered ~ .splitview-nav.placeholder.all-filtered,
-.splitview-nav:empty ~ .splitview-nav.placeholder.empty {
-  display: -moz-box;
-}
-
-.splitview-portrait-resizer {
-  display: none;
-}
-
-/* portrait mode */
-@media (max-aspect-ratio: 5/3) {
-  #splitview-details-toolbar {
-    display: none;
-  }
-
-  .splitview-portrait-resizer {
-    display: -moz-box;
-  }
-}
--- a/browser/devtools/tilt/Tilt.jsm
+++ b/browser/devtools/tilt/Tilt.jsm
@@ -95,17 +95,17 @@ Tilt.prototype = {
    * Initializes a visualizer for the current tab.
    */
   initialize: function T_initialize()
   {
     let id = this.currentWindowId;
 
     // if the visualizer for the current tab is already open, destroy it now
     if (this.visualizers[id]) {
-      this.destroy(id);
+      this.destroy(id, true);
       return;
     }
 
     // create a visualizer instance for the current tab
     this.visualizers[id] = new TiltVisualizer({
       parentNode: this.chromeWindow.gBrowser.selectedBrowser.parentNode,
       contentWindow: this.chromeWindow.gBrowser.selectedBrowser.contentWindow,
       requestAnimationFrame: this.chromeWindow.mozRequestAnimationFrame,
@@ -121,30 +121,52 @@ Tilt.prototype = {
     Services.obs.notifyObservers(null, TILT_NOTIFICATIONS.INITIALIZED, null);
   },
 
   /**
    * Destroys a specific instance of the visualizer.
    *
    * @param {String} aId
    *                 the identifier of the instance in the visualizers array
+   * @param {Boolean} aAnimateFlag
+   *                  optional, set to true to display a destruction transition
    */
-  destroy: function T_destroy(aId)
+  destroy: function T_destroy(aId, aAnimateFlag)
   {
     // if the visualizer is already destroyed, don't do anything
     if (!this.visualizers[aId]) {
       return;
     }
 
-    this.visualizers[aId].removeOverlay();
-    this.visualizers[aId].cleanup();
-    this.visualizers[aId] = null;
+    if (!this.isDestroying) {
+      this.isDestroying = true;
+
+      let finalize = function T_finalize(aId) {
+        this.visualizers[aId].removeOverlay();
+        this.visualizers[aId].cleanup();
+        this.visualizers[aId] = null;
+
+        this.isDestroying = false;
+        this.chromeWindow.gBrowser.selectedBrowser.focus();
+        Services.obs.notifyObservers(null, TILT_NOTIFICATIONS.DESTROYED, null);
+      };
 
-    this.chromeWindow.gBrowser.selectedBrowser.contentWindow.focus();
-    Services.obs.notifyObservers(null, TILT_NOTIFICATIONS.DESTROYED, null);
+      if (!aAnimateFlag) {
+        finalize.call(this, aId);
+        return;
+      }
+
+      let controller = this.visualizers[aId].controller;
+      let presenter = this.visualizers[aId].presenter;
+      let content = presenter.contentWindow;
+
+      controller.removeEventListeners();
+      controller.arcball.reset([-content.pageXOffset, -content.pageYOffset]);
+      presenter.executeDestruction(finalize.bind(this, aId));
+    }
   },
 
   /**
    * Handles any supplementary post-initialization work, done immediately
    * after a TILT_NOTIFICATIONS.INITIALIZED notification.
    */
   _whenInitialized: function T__whenInitialized()
   {
--- a/browser/devtools/tilt/TiltUtils.jsm
+++ b/browser/devtools/tilt/TiltUtils.jsm
@@ -627,16 +627,28 @@ TiltUtils.destroyObject = function TU_de
   for (let i in aScope) {
     if (aScope.hasOwnProperty(i)) {
       delete aScope[i];
     }
   }
 };
 
 /**
+ * Gets the most recent browser window.
+ *
+ * @return {Window} the window
+ */
+TiltUtils.getBrowserWindow = function TU_getBrowserWindow()
+{
+  return Cc["@mozilla.org/appshell/window-mediator;1"]
+    .getService(Ci.nsIWindowMediator)
+    .getMostRecentWindow("navigator:browser");
+};
+
+/**
  * Retrieve the unique ID of a window object.
  *
  * @param {Window} aWindow
  *                 the window to get the ID from
  *
  * @return {Number} the window ID
  */
 TiltUtils.getWindowId = function TU_getWindowId(aWindow)
@@ -651,35 +663,29 @@ TiltUtils.getWindowId = function TU_getW
 };
 
 /**
  * Gets the markup document viewer zoom for the currently selected browser.
  *
  * @return {Number} the zoom ammount
  */
 TiltUtils.getDocumentZoom = function TU_getDocumentZoom() {
-  let browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"]
-    .getService(Ci.nsIWindowMediator)
-    .getMostRecentWindow("navigator:browser");
-
-  return browserWindow.gBrowser.selectedBrowser.markupDocumentViewer.fullZoom;
+  return TiltUtils.getBrowserWindow()
+                  .gBrowser.selectedBrowser.markupDocumentViewer.fullZoom;
 };
 
 /**
  * Performs a garbage collection.
  */
 TiltUtils.gc = function TU_gc()
 {
-  let browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"]
-    .getService(Ci.nsIWindowMediator)
-    .getMostRecentWindow("navigator:browser");
-
-  browserWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-               .getInterface(Ci.nsIDOMWindowUtils)
-               .garbageCollect();
+  TiltUtils.getBrowserWindow()
+           .QueryInterface(Ci.nsIInterfaceRequestor)
+           .getInterface(Ci.nsIDOMWindowUtils)
+           .garbageCollect();
 };
 
 /**
  * Clears the cache and sets all the variables to null.
  */
 TiltUtils.clearCache = function TU_clearCache()
 {
   TiltUtils.DOM.parentNode = null;
--- a/browser/devtools/tilt/TiltVisualizer.jsm
+++ b/browser/devtools/tilt/TiltVisualizer.jsm
@@ -33,17 +33,17 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the LGPL or the GPL. 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 *****/
 
 /*global Components, ChromeWorker */
-/*global TiltGL, TiltMath, vec3, mat4, quat4, TiltUtils, TiltVisualizerStyle */
+/*global TiltGL, TiltMath, EPSILON, vec3, mat4, quat4, TiltUtils */
 "use strict";
 
 const Cu = Components.utils;
 const Ci = Components.interfaces;
 
 const ELEMENT_MIN_SIZE = 4;
 const INVISIBLE_ELEMENTS = {
   "head": true,
@@ -55,26 +55,29 @@ const INVISIBLE_ELEMENTS = {
   "option": true,
   "script": true,
   "style": true,
   "title": true
 };
 
 const STACK_THICKNESS = 15;
 const WIREFRAME_COLOR = [0, 0, 0, 0.25];
-const INITIAL_TRANSITION_DURATION = 100;
+const INTRO_TRANSITION_DURATION = 80;
+const OUTRO_TRANSITION_DURATION = 50;
 const INITIAL_Z_TRANSLATION = 400;
 
 const MOUSE_CLICK_THRESHOLD = 10;
-const ARCBALL_SENSITIVITY = 0.3;
+const ARCBALL_SENSITIVITY = 0.5;
 const ARCBALL_ROTATION_STEP = 0.15;
 const ARCBALL_TRANSLATION_STEP = 35;
 const ARCBALL_ZOOM_STEP = 0.1;
 const ARCBALL_ZOOM_MIN = -3000;
 const ARCBALL_ZOOM_MAX = 500;
+const ARCBALL_RESET_FACTOR = 0.9;
+const ARCBALL_RESET_INTERVAL = 1000 / 60;
 
 const TILT_CRAFTER = "resource:///modules/devtools/TiltWorkerCrafter.js";
 const TILT_PICKER = "resource:///modules/devtools/TiltWorkerPicker.js";
 
 Cu.import("resource:///modules/devtools/TiltGL.jsm");
 Cu.import("resource:///modules/devtools/TiltMath.jsm");
 Cu.import("resource:///modules/devtools/TiltUtils.jsm");
 Cu.import("resource:///modules/devtools/TiltVisualizerStyle.jsm");
@@ -290,46 +293,71 @@ TiltVisualizer.Presenter = function TV_P
       this.redraw = false;
       this.drawVisualization();
     }
 
     // call the attached ondraw event handler if specified (by the controller)
     if ("function" === typeof this.ondraw) {
       this.ondraw();
     }
+
+    if (!TiltVisualizer.Prefs.introTransition && !this.isExecutingDestruction) {
+      this.frames = INTRO_TRANSITION_DURATION;
+    }
+    if (!TiltVisualizer.Prefs.outroTransition && this.isExecutingDestruction) {
+      this.frames = OUTRO_TRANSITION_DURATION;
+    }
+
+    if ("function" === typeof this.onInitializationFinished &&
+        this.frames === INTRO_TRANSITION_DURATION &&
+       !this.isExecutingDestruction) {
+      this.onInitializationFinished();
+    }
+    if ("function" === typeof this.onDestructionFinished &&
+        this.frames === OUTRO_TRANSITION_DURATION &&
+        this.isExecutingDestruction) {
+      this.onDestructionFinished();
+    }
   }.bind(this);
 
   setup();
   loop();
 };
 
 TiltVisualizer.Presenter.prototype = {
 
   /**
    * Draws the visualization mesh and highlight quad.
    */
   drawVisualization: function TVP_drawVisualization()
   {
     let renderer = this.renderer;
     let transforms = this.transforms;
+    let w = renderer.width;
+    let h = renderer.height;
 
     // if the mesh wasn't created yet, don't continue rendering
     if (!this.meshStacks || !this.meshWireframe) {
       return;
     }
 
     // clear the context to an opaque black background
     renderer.clear();
     renderer.perspective();
 
     // apply a transition transformation using an ortho and perspective matrix
-    let f = this.frames / INITIAL_TRANSITION_DURATION;
-    let w = renderer.width;
-    let h = renderer.height;
-    renderer.lerp(renderer.projMatrix, mat4.ortho(0, w, h, 0, -1, 1000), f, 8);
+    let ortho = mat4.ortho(0, w, h, 0, -1000, 1000);
+
+    if (!this.isExecutingDestruction) {
+      let f = this.frames / INTRO_TRANSITION_DURATION;
+      renderer.lerp(renderer.projMatrix, ortho, f, 8);
+    } else {
+      let f = this.frames / OUTRO_TRANSITION_DURATION;
+      renderer.lerp(renderer.projMatrix, ortho, 1 - f, 8);
+    }
 
     // apply the preliminary transformations to the model view
     renderer.translate(w * 0.5, h * 0.5, -INITIAL_Z_TRANSLATION);
 
     // calculate the camera matrix using the rotation and translation
     renderer.translate(transforms.translation[0], 0,
                        transforms.translation[2]);
 
@@ -344,17 +372,18 @@ TiltVisualizer.Presenter.prototype = {
     // draw the visualization mesh
     renderer.strokeWeight(2);
     renderer.depthTest(true);
     this.drawMeshStacks();
     this.drawMeshWireframe();
     this.drawHighlight();
 
     // make sure the initial transition is drawn until finished
-    if (this.frames < INITIAL_TRANSITION_DURATION) {
+    if (this.frames < INTRO_TRANSITION_DURATION ||
+        this.frames < OUTRO_TRANSITION_DURATION) {
       this.redraw = true;
     }
     this.frames++;
   },
 
   /**
    * Draws the meshStacks object.
    */
@@ -455,17 +484,17 @@ TiltVisualizer.Presenter.prototype = {
 
   /**
    * Create the combined mesh representing the document visualization by
    * traversing the document & adding a stack for each node that is drawable.
    *
    * @param {Object} aData
    *                 object containing the necessary mesh verts, texcoord etc.
    */
-  setupMesh: function TVP_setupMesh(aData)
+  setupMesh: function TVP_setupMesh(aData) /*global TiltVisualizerStyle */
   {
     let renderer = this.renderer;
 
     // destroy any previously created mesh
     TiltUtils.destroyObject(this.meshStacks);
     TiltUtils.destroyObject(this.meshWireframe);
 
     // if the renderer was destroyed, don't continue setup
@@ -663,17 +692,18 @@ TiltVisualizer.Presenter.prototype = {
     let z = info.depth;
 
     vec3.set([x,     y,     z * STACK_THICKNESS], highlight.v0);
     vec3.set([x + w, y,     z * STACK_THICKNESS], highlight.v1);
     vec3.set([x + w, y + h, z * STACK_THICKNESS], highlight.v2);
     vec3.set([x,     y + h, z * STACK_THICKNESS], highlight.v3);
 
     this._currentSelection = aNodeIndex;
-    this.inspectorUI.inspectNode(node);
+    this.inspectorUI.inspectNode(node, this.contentWindow.innerHeight < y ||
+                                       this.contentWindow.pageYOffset > 0);
   },
 
   /**
    * Picks a stacked dom node at the x and y screen coordinates and issues
    * a callback function with the found intersection.
    *
    * @param {Number} x
    *                 the current horizontal coordinate of the mouse
@@ -783,16 +813,38 @@ TiltVisualizer.Presenter.prototype = {
    * @return {Boolean} true if the object was initialized properly
    */
   isInitialized: function TVP_isInitialized()
   {
     return this.renderer && this.renderer.context;
   },
 
   /**
+   * Starts executing a destruction animation and executes a callback function
+   * when finished.
+   *
+   * @param {Function} aCallback
+   *                   the destruction finished callback
+   */
+  executeDestruction: function TV_executeDestruction(aCallback)
+  {
+    if (!this.isExecutingDestruction) {
+      this.isExecutingDestruction = true;
+      this.onDestructionFinished = aCallback;
+
+      if (this.frames > OUTRO_TRANSITION_DURATION) {
+        this.frames = 0;
+        this.redraw = true;
+      } else {
+        aCallback();
+      }
+    }
+  },
+
+  /**
    * Function called when this object is destroyed.
    */
   finalize: function TVP_finalize()
   {
     TiltUtils.destroyObject(this.visualizationProgram);
     TiltUtils.destroyObject(this.texture);
 
     if (this.meshStacks) {
@@ -846,38 +898,72 @@ TiltVisualizer.Controller = function TV_
    * Object containing the rotation quaternion and the translation amount.
    */
   this.coordinates = null;
 
   // bind the owner object to the necessary functions
   TiltUtils.bindObjectFunc(this, "update");
   TiltUtils.bindObjectFunc(this, "^on");
 
-  // bind commonly used mouse and keyboard events with the controller
-  aCanvas.addEventListener("mousedown", this.onMouseDown, false);
-  aCanvas.addEventListener("mouseup", this.onMouseUp, false);
-  aCanvas.addEventListener("click", this.onMouseClick, false);
-  aCanvas.addEventListener("mousemove", this.onMouseMove, false);
-  aCanvas.addEventListener("mouseover", this.onMouseOver, false);
-  aCanvas.addEventListener("mouseout", this.onMouseOut, false);
-  aCanvas.addEventListener("MozMousePixelScroll", this.onMozScroll, false);
-  aCanvas.addEventListener("keydown", this.onKeyDown, false);
-  aCanvas.addEventListener("keyup", this.onKeyUp, false);
-  aCanvas.addEventListener("blur", this.onBlur, false);
-
-  // handle resize events to change the arcball dimensions
-  aPresenter.contentWindow.addEventListener("resize", this.onResize, false);
+  // add the necessary event listeners
+  this.addEventListeners();
 
   // attach this controller's update function to the presenter ondraw event
   aPresenter.ondraw = this.update;
 };
 
 TiltVisualizer.Controller.prototype = {
 
   /**
+   * Adds all added events listeners required by this controller.
+   */
+  addEventListeners: function TVC_addEventListeners()
+  {
+    let canvas = this.canvas;
+    let presenter = this.presenter;
+
+    // bind commonly used mouse and keyboard events with the controller
+    canvas.addEventListener("mousedown", this.onMouseDown, false);
+    canvas.addEventListener("mouseup", this.onMouseUp, false);
+    canvas.addEventListener("click", this.onMouseClick, false);
+    canvas.addEventListener("mousemove", this.onMouseMove, false);
+    canvas.addEventListener("mouseover", this.onMouseOver, false);
+    canvas.addEventListener("mouseout", this.onMouseOut, false);
+    canvas.addEventListener("MozMousePixelScroll", this.onMozScroll, false);
+    canvas.addEventListener("keydown", this.onKeyDown, false);
+    canvas.addEventListener("keyup", this.onKeyUp, false);
+    canvas.addEventListener("blur", this.onBlur, false);
+
+    // handle resize events to change the arcball dimensions
+    presenter.contentWindow.addEventListener("resize", this.onResize, false);
+  },
+
+  /**
+   * Removes all added events listeners required by this controller.
+   */
+  removeEventListeners: function TVC_removeEventListeners()
+  {
+    let canvas = this.canvas;
+    let presenter = this.presenter;
+
+    canvas.removeEventListener("mousedown", this.onMouseDown, false);
+    canvas.removeEventListener("mouseup", this.onMouseUp, false);
+    canvas.removeEventListener("click", this.onMouseClick, false);
+    canvas.removeEventListener("mousemove", this.onMouseMove, false);
+    canvas.removeEventListener("mouseover", this.onMouseOver, false);
+    canvas.removeEventListener("mouseout", this.onMouseOut, false);
+    canvas.removeEventListener("MozMousePixelScroll", this.onMozScroll, false);
+    canvas.removeEventListener("keydown", this.onKeyDown, false);
+    canvas.removeEventListener("keyup", this.onKeyUp, false);
+    canvas.removeEventListener("blur", this.onBlur, false);
+
+    presenter.contentWindow.removeEventListener("resize", this.onResize,false);
+  },
+
+  /**
    * Function called each frame, updating the visualization camera transforms.
    */
   update: function TVC_update()
   {
     this.coordinates = this.arcball.update();
 
     this.presenter.setRotation(this.coordinates.rotation);
     this.presenter.setTranslation(this.coordinates.translation);
@@ -987,43 +1073,42 @@ TiltVisualizer.Controller.prototype = {
 
   /**
    * Called when a key is pressed.
    */
   onKeyDown: function TVC_onKeyDown(e)
   {
     let code = e.keyCode || e.which;
 
-    if (code >= e.DOM_VK_LEFT && code <= e.DOM_VK_DOWN) {
+    if (!e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey) {
       e.preventDefault();
       e.stopPropagation();
-    }
-    if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) {
+      this.arcball.keyDown(code);
+    } else {
       this.arcball.cancelKeyEvents();
-    } else {
-      this.arcball.keyDown(code);
     }
   },
 
   /**
    * Called when a key is released.
    */
   onKeyUp: function TVC_onKeyUp(e)
   {
     let code = e.keyCode || e.which;
 
-    if (code >= e.DOM_VK_LEFT && code <= e.DOM_VK_DOWN) {
+    if (code === e.DOM_VK_ESCAPE) {
+      this.presenter.tiltUI.destroy(this.presenter.tiltUI.currentWindowId, 1);
+      return;
+    }
+
+    if (!e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey) {
       e.preventDefault();
       e.stopPropagation();
+      this.arcball.keyUp(code);
     }
-    if (code === e.DOM_VK_ESCAPE) {
-      this.presenter.tiltUI.destroy(this.presenter.tiltUI.currentWindowId);
-      return;
-    }
-    this.arcball.keyUp(code);
   },
 
   /**
    * Called when the canvas looses focus.
    */
   onBlur: function TVC_onBlur(e) {
     this.arcball.cancelKeyEvents();
   },
@@ -1050,34 +1135,21 @@ TiltVisualizer.Controller.prototype = {
     return this.arcball ? true : false;
   },
 
   /**
    * Function called when this object is destroyed.
    */
   finalize: function TVC_finalize()
   {
-    let canvas = this.canvas;
-    let presenter = this.presenter;
-
     TiltUtils.destroyObject(this.arcball);
     TiltUtils.destroyObject(this.coordinates);
 
-    canvas.removeEventListener("mousedown", this.onMouseDown, false);
-    canvas.removeEventListener("mouseup", this.onMouseUp, false);
-    canvas.removeEventListener("click", this.onMouseClick, false);
-    canvas.removeEventListener("mousemove", this.onMouseMove, false);
-    canvas.removeEventListener("mouseover", this.onMouseOver, false);
-    canvas.removeEventListener("mouseout", this.onMouseOut, false);
-    canvas.removeEventListener("MozMousePixelScroll", this.onMozScroll, false);
-    canvas.removeEventListener("keydown", this.onKeyDown, false);
-    canvas.removeEventListener("keyup", this.onKeyUp, false);
-    canvas.removeEventListener("blur", this.onBlur, false);
-    presenter.contentWindow.removeEventListener("resize", this.onResize,false);
-    presenter.ondraw = null;
+    this.removeEventListeners();
+    this.presenter.ondraw = null;
   }
 };
 
 /**
  * This is a general purpose 3D rotation controller described by Ken Shoemake
  * in the Graphics Interface ’92 Proceedings. It features good behavior
  * easy implementation, cheap execution.
  *
@@ -1118,33 +1190,36 @@ TiltVisualizer.Arcball = function TV_Arc
   this._endVec = vec3.create();
   this._pVec = vec3.create();
 
   /**
    * The corresponding rotation quaternions.
    */
   this._lastRot = quat4.create();
   this._deltaRot = quat4.create();
-  this._currentRot = quat4.create(aInitialRot);
+  this._currentRot = quat4.create();
 
   /**
    * The current camera translation coordinates.
    */
   this._lastTrans = vec3.create();
   this._deltaTrans = vec3.create();
-  this._currentTrans = vec3.create(aInitialTrans);
+  this._currentTrans = vec3.create();
   this._zoomAmount = 0;
 
   /**
    * Additional rotation and translation vectors.
    */
-  this._addKeyRot = vec3.create();
-  this._addKeyTrans = vec3.create();
-  this._deltaKeyRot = quat4.create();
-  this._deltaKeyTrans = vec3.create();
+  this._additionalRot = vec3.create(aInitialRot);
+  this._additionalTrans = vec3.create(aInitialTrans);
+  this._deltaAdditionalRot = quat4.create();
+  this._deltaAdditionalTrans = vec3.create();
+
+  // load the keys controlling the arcball
+  this._loadKeys();
 
   // set the current dimensions of the arcball
   this.resize(aWidth, aHeight, aRadius);
 };
 
 TiltVisualizer.Arcball.prototype = {
 
   /**
@@ -1242,78 +1317,85 @@ TiltVisualizer.Arcball.prototype = {
 
     let zoomAmount = this._zoomAmount;
     let keyCode = this._keyCode;
 
     // mouse wheel handles zooming
     deltaTrans[2] = (zoomAmount - currentTrans[2]) * ARCBALL_ZOOM_STEP;
     currentTrans[2] += deltaTrans[2];
 
-    let addKeyRot = this._addKeyRot;
-    let addKeyTrans = this._addKeyTrans;
-    let deltaKeyRot = this._deltaKeyRot;
-    let deltaKeyTrans = this._deltaKeyTrans;
+    let additionalRot = this._additionalRot;
+    let additionalTrans = this._additionalTrans;
+    let deltaAdditionalRot = this._deltaAdditionalRot;
+    let deltaAdditionalTrans = this._deltaAdditionalTrans;
+
+    let rotateKeys = this.rotateKeys;
+    let panKeys = this.panKeys;
+    let zoomKeys = this.zoomKeys;
+    let resetKey = this.resetKey;
 
     // handle additional rotation and translation by the keyboard
-    if (keyCode[Ci.nsIDOMKeyEvent.DOM_VK_A]) {
-      addKeyRot[0] -= ARCBALL_SENSITIVITY * ARCBALL_ROTATION_STEP;
+    if (keyCode[rotateKeys.left]) {
+      additionalRot[0] -= ARCBALL_SENSITIVITY * ARCBALL_ROTATION_STEP;
     }
-    if (keyCode[Ci.nsIDOMKeyEvent.DOM_VK_D]) {
-      addKeyRot[0] += ARCBALL_SENSITIVITY * ARCBALL_ROTATION_STEP;
+    if (keyCode[rotateKeys.right]) {
+      additionalRot[0] += ARCBALL_SENSITIVITY * ARCBALL_ROTATION_STEP;
     }
-    if (keyCode[Ci.nsIDOMKeyEvent.DOM_VK_W]) {
-      addKeyRot[1] += ARCBALL_SENSITIVITY * ARCBALL_ROTATION_STEP;
+    if (keyCode[rotateKeys.up]) {
+      additionalRot[1] += ARCBALL_SENSITIVITY * ARCBALL_ROTATION_STEP;
     }
-    if (keyCode[Ci.nsIDOMKeyEvent.DOM_VK_S]) {
-      addKeyRot[1] -= ARCBALL_SENSITIVITY * ARCBALL_ROTATION_STEP;
+    if (keyCode[rotateKeys.down]) {
+      additionalRot[1] -= ARCBALL_SENSITIVITY * ARCBALL_ROTATION_STEP;
     }
-    if (keyCode[Ci.nsIDOMKeyEvent.DOM_VK_LEFT]) {
-      addKeyTrans[0] -= ARCBALL_SENSITIVITY * ARCBALL_TRANSLATION_STEP;
+    if (keyCode[panKeys.left]) {
+      additionalTrans[0] -= ARCBALL_SENSITIVITY * ARCBALL_TRANSLATION_STEP;
     }
-    if (keyCode[Ci.nsIDOMKeyEvent.DOM_VK_RIGHT]) {
-      addKeyTrans[0] += ARCBALL_SENSITIVITY * ARCBALL_TRANSLATION_STEP;
+    if (keyCode[panKeys.right]) {
+      additionalTrans[0] += ARCBALL_SENSITIVITY * ARCBALL_TRANSLATION_STEP;
     }
-    if (keyCode[Ci.nsIDOMKeyEvent.DOM_VK_UP]) {
-      addKeyTrans[1] -= ARCBALL_SENSITIVITY * ARCBALL_TRANSLATION_STEP;
+    if (keyCode[panKeys.up]) {
+      additionalTrans[1] -= ARCBALL_SENSITIVITY * ARCBALL_TRANSLATION_STEP;
     }
-    if (keyCode[Ci.nsIDOMKeyEvent.DOM_VK_DOWN]) {
-      addKeyTrans[1] += ARCBALL_SENSITIVITY * ARCBALL_TRANSLATION_STEP;
+    if (keyCode[panKeys.down]) {
+      additionalTrans[1] += ARCBALL_SENSITIVITY * ARCBALL_TRANSLATION_STEP;
     }
-    if (keyCode[Ci.nsIDOMKeyEvent.DOM_VK_I] ||
-        keyCode[Ci.nsIDOMKeyEvent.DOM_VK_ADD] ||
-        keyCode[Ci.nsIDOMKeyEvent.DOM_VK_EQUALS]) {
+    if (keyCode[zoomKeys["in"][0]] ||
+        keyCode[zoomKeys["in"][1]] ||
+        keyCode[zoomKeys["in"][2]]) {
       this.zoom(-ARCBALL_TRANSLATION_STEP);
     }
-    if (keyCode[Ci.nsIDOMKeyEvent.DOM_VK_O] ||
-        keyCode[Ci.nsIDOMKeyEvent.DOM_VK_SUBTRACT]) {
+    if (keyCode[zoomKeys["out"][0]] ||
+        keyCode[zoomKeys["out"][1]]) {
       this.zoom(ARCBALL_TRANSLATION_STEP);
     }
-    if (keyCode[Ci.nsIDOMKeyEvent.DOM_VK_R] ||
-        keyCode[Ci.nsIDOMKeyEvent.DOM_VK_0]) {
+    if (keyCode[zoomKeys["unzoom"]]) {
       this._zoomAmount = 0;
     }
+    if (keyCode[resetKey]) {
+      this.reset();
+    }
 
     // update the delta key rotations and translations
-    deltaKeyRot[0] +=
-      (addKeyRot[0] - deltaKeyRot[0]) * ARCBALL_SENSITIVITY;
-    deltaKeyRot[1] +=
-      (addKeyRot[1] - deltaKeyRot[1]) * ARCBALL_SENSITIVITY;
+    deltaAdditionalRot[0] +=
+      (additionalRot[0] - deltaAdditionalRot[0]) * ARCBALL_SENSITIVITY;
+    deltaAdditionalRot[1] +=
+      (additionalRot[1] - deltaAdditionalRot[1]) * ARCBALL_SENSITIVITY;
+    deltaAdditionalRot[2] +=
+      (additionalRot[2] - deltaAdditionalRot[2]) * ARCBALL_SENSITIVITY;
 
-    deltaKeyTrans[0] +=
-      (addKeyTrans[0] - deltaKeyTrans[0]) * ARCBALL_SENSITIVITY;
-    deltaKeyTrans[1] +=
-      (addKeyTrans[1] - deltaKeyTrans[1]) * ARCBALL_SENSITIVITY;
+    deltaAdditionalTrans[0] +=
+      (additionalTrans[0] - deltaAdditionalTrans[0]) * ARCBALL_SENSITIVITY;
+    deltaAdditionalTrans[1] +=
+      (additionalTrans[1] - deltaAdditionalTrans[1]) * ARCBALL_SENSITIVITY;
 
     // create an additional rotation based on the key events
-    quat4.fromEuler(deltaKeyRot[0], deltaKeyRot[1], 0, deltaRot);
+    quat4.fromEuler(deltaAdditionalRot[0], deltaAdditionalRot[1], 0, deltaRot);
 
     // create an additional translation based on the key events
-    deltaTrans[0] = deltaKeyTrans[0];
-    deltaTrans[1] = deltaKeyTrans[1];
-    deltaTrans[2] = 0;
+    vec3.set([deltaAdditionalTrans[0], deltaAdditionalTrans[1], 0], deltaTrans);
 
     // return the current rotation and translation
     return {
       rotation: quat4.multiply(deltaRot, currentRot),
       translation: vec3.add(deltaTrans, currentTrans)
     };
   },
 
@@ -1329,16 +1411,17 @@ TiltVisualizer.Arcball.prototype = {
    *                 which mouse button was pressed
    */
   mouseDown: function TVA_mouseDown(x, y, aButton)
   {
     // save the mouse down state and prepare for rotations or translations
     this._mousePress[0] = x;
     this._mousePress[1] = y;
     this._mouseButton = aButton;
+    this._cancelResetInterval();
     this._save();
 
     // find the sphere coordinates of the mouse positions
     this.pointToSphere(
       x, y, this.width, this.height, this.radius, this._startVec);
 
     quat4.set(this._currentRot, this._lastRot);
   },
@@ -1404,29 +1487,31 @@ TiltVisualizer.Arcball.prototype = {
    * Call this, for example, when the mouse wheel was scrolled or zoom keys
    * were pressed.
    *
    * @param {Number} aZoom
    *                 the zoom direction and speed
    */
   zoom: function TVA_zoom(aZoom)
   {
+    this._cancelResetInterval();
     this._zoomAmount = TiltMath.clamp(this._zoomAmount - aZoom,
       ARCBALL_ZOOM_MIN, ARCBALL_ZOOM_MAX);
   },
 
   /**
    * Function handling the keyDown event.
    * Call this when a key was pressed.
    *
    * @param {Number} aCode
    *                 the code corresponding to the key pressed
    */
   keyDown: function TVA_keyDown(aCode)
   {
+    this._cancelResetInterval();
     this._keyCode[aCode] = true;
   },
 
   /**
    * Function handling the keyUp event.
    * Call this when a key was released.
    *
    * @param {Number} aCode
@@ -1479,21 +1564,31 @@ TiltVisualizer.Arcball.prototype = {
       aSphereVec[1] = y;
       aSphereVec[2] = Math.sqrt(1 - sqlength);
     }
   },
 
   /**
    * Cancels all pending transformations caused by key events.
    */
-  cancelKeyEvents: function TVA_cancelKeyEvents() {
+  cancelKeyEvents: function TVA_cancelKeyEvents()
+  {
     this._keyCode = {};
   },
 
   /**
+   * Cancels all pending transformations caused by mouse events.
+   */
+  cancelMouseEvents: function TVA_cancelMouseEvents()
+  {
+    this._rotating = false;
+    this._mouseButton = -1;
+  },
+
+  /**
    * Resize this implementation to use different bounds.
    * This function is automatically called when the arcball is created.
    *
    * @param {Number} newWidth
    *                 the new width of canvas
    * @param {Number} newHeight
    *                 the new  height of canvas
    * @param {Number} newRadius
@@ -1508,29 +1603,148 @@ TiltVisualizer.Arcball.prototype = {
     // set the new width, height and radius dimensions
     this.width = newWidth;
     this.height = newHeight;
     this.radius = newRadius ? newRadius : Math.min(newWidth, newHeight);
     this._save();
   },
 
   /**
+   * Starts an animation resetting the arcball transformations to identity.
+   *
+   * @param {Array} aFinalTranslation
+   *                optional, final vector translation
+   * @param {Array} aFinalRotation
+   *                optional, final quaternion rotation
+   */
+  reset: function TVA_reset(aFinalTranslation, aFinalRotation)
+  {
+    this.cancelMouseEvents();
+    this.cancelKeyEvents();
+
+    if (!this._resetInterval) {
+      let window = TiltUtils.getBrowserWindow();
+      let func = this._nextResetIntervalStep.bind(this);
+
+      vec3.zero(this._additionalTrans);
+      vec3.zero(this._additionalRot);
+
+      this._save();
+      this._resetFinalTranslation = vec3.create(aFinalTranslation);
+      this._resetFinalRotation = quat4.create(aFinalRotation);
+      this._resetInterval = window.setInterval(func, ARCBALL_RESET_INTERVAL);
+    }
+  },
+
+  /**
+   * Cancels the current arcball reset animation if there is one.
+   */
+  _cancelResetInterval: function TVA__cancelResetInterval()
+  {
+    if (this._resetInterval) {
+      let window = TiltUtils.getBrowserWindow();
+
+      window.clearInterval(this._resetInterval);
+      this._resetInterval = null;
+      this._save();
+
+      if ("function" === typeof this.onResetFinish) {
+        this.onResetFinish();
+        this.onResetFinish = null;
+      }
+    }
+  },
+
+  /**
+   * Executes the next step in the arcball reset animation.
+   */
+  _nextResetIntervalStep: function TVA__nextResetIntervalStep()
+  {
+    let fDelta = EPSILON * EPSILON;
+    let fTran = this._resetFinalTranslation;
+    let fRot = this._resetFinalRotation;
+
+    let t = vec3.create(fTran);
+    let r = quat4.multiply(quat4.inverse(quat4.create(this._currentRot)), fRot);
+
+    // reset the rotation quaternion and translation vector
+    vec3.lerp(this._currentTrans, t, ARCBALL_RESET_FACTOR);
+    quat4.slerp(this._currentRot, r, 1 - ARCBALL_RESET_FACTOR);
+
+    // also reset any additional transforms by the keyboard or mouse
+    this._zoomAmount *= ARCBALL_RESET_FACTOR;
+
+    // clear the loop if the all values are very close to zero
+    if (vec3.length(vec3.subtract(this._lastRot, fRot, [])) < fDelta &&
+        vec3.length(vec3.subtract(this._deltaRot, fRot, [])) < fDelta &&
+        vec3.length(vec3.subtract(this._currentRot, fRot, [])) < fDelta &&
+        vec3.length(vec3.subtract(this._lastTrans, fTran, [])) < fDelta &&
+        vec3.length(vec3.subtract(this._deltaTrans, fTran, [])) < fDelta &&
+        vec3.length(vec3.subtract(this._currentTrans, fTran, [])) < fDelta) {
+
+      this._cancelResetInterval();
+    }
+  },
+
+  /**
+   * Loads the keys to control this arcball.
+   */
+  _loadKeys: function TVA__loadKeys() {
+
+    this.rotateKeys = {
+      "up": Ci.nsIDOMKeyEvent["DOM_VK_W"],
+      "down": Ci.nsIDOMKeyEvent["DOM_VK_S"],
+      "left": Ci.nsIDOMKeyEvent["DOM_VK_A"],
+      "right": Ci.nsIDOMKeyEvent["DOM_VK_D"],
+    };
+    this.panKeys = {
+      "up": Ci.nsIDOMKeyEvent["DOM_VK_UP"],
+      "down": Ci.nsIDOMKeyEvent["DOM_VK_DOWN"],
+      "left": Ci.nsIDOMKeyEvent["DOM_VK_LEFT"],
+      "right": Ci.nsIDOMKeyEvent["DOM_VK_RIGHT"],
+    };
+    this.zoomKeys = {
+      "in": [
+        Ci.nsIDOMKeyEvent["DOM_VK_I"],
+        Ci.nsIDOMKeyEvent["DOM_VK_ADD"],
+        Ci.nsIDOMKeyEvent["DOM_VK_EQUALS"],
+      ],
+      "out": [
+        Ci.nsIDOMKeyEvent["DOM_VK_O"],
+        Ci.nsIDOMKeyEvent["DOM_VK_SUBTRACT"],
+      ],
+      "unzoom": Ci.nsIDOMKeyEvent["DOM_VK_0"]
+    };
+    this.resetKey = Ci.nsIDOMKeyEvent["DOM_VK_R"];
+  },
+
+  /**
    * Saves the current arcball state, typically after resize or mouse events.
    */
   _save: function TVA__save()
   {
-    let x = this._mousePress[0];
-    let y = this._mousePress[1];
+    if (this._mousePress) {
+      let x = this._mousePress[0];
+      let y = this._mousePress[1];
 
-    this._mouseMove[0] = x;
-    this._mouseMove[1] = y;
-    this._mouseRelease[0] = x;
-    this._mouseRelease[1] = y;
-    this._mouseLerp[0] = x;
-    this._mouseLerp[1] = y;
+      this._mouseMove[0] = x;
+      this._mouseMove[1] = y;
+      this._mouseRelease[0] = x;
+      this._mouseRelease[1] = y;
+      this._mouseLerp[0] = x;
+      this._mouseLerp[1] = y;
+    }
+  },
+
+  /**
+   * Function called when this object is destroyed.
+   */
+  finalize: function TVA_finalize()
+  {
+    this._cancelResetInterval();
   }
 };
 
 /**
  * Tilt configuration preferences.
  */
 TiltVisualizer.Prefs = {
 
@@ -1543,24 +1757,49 @@ TiltVisualizer.Prefs = {
   },
 
   set enabled(value)
   {
     TiltUtils.Preferences.set("enabled", "boolean", value);
     this._enabled = value;
   },
 
+  get introTransition()
+  {
+    return this._introTransition;
+  },
+
+  set introTransition(value)
+  {
+    TiltUtils.Preferences.set("intro_transition", "boolean", value);
+    this._introTransition = value;
+  },
+
+  get outroTransition()
+  {
+    return this._outroTransition;
+  },
+
+  set outroTransition(value)
+  {
+    TiltUtils.Preferences.set("outro_transition", "boolean", value);
+    this._outroTransition = value;
+  },
+
   /**
    * Loads the preferences.
    */
   load: function TVC_load()
   {
-    let prefs = TiltUtils.Preferences;
+    let prefs = TiltVisualizer.Prefs;
+    let get = TiltUtils.Preferences.get;
 
-    TiltVisualizer.Prefs._enabled = prefs.get("enabled", "boolean");
+    prefs._enabled = get("enabled", "boolean");
+    prefs._introTransition = get("intro_transition", "boolean");
+    prefs._outroTransition = get("outro_transition", "boolean");
   }
 };
 
 /**
  * A custom visualization shader.
  *
  * @param {Attribute} vertexPosition: the vertex position
  * @param {Attribute} vertexTexCoord: texture coordinates used by the sampler
--- a/browser/devtools/tilt/test/Makefile.in
+++ b/browser/devtools/tilt/test/Makefile.in
@@ -44,20 +44,23 @@ relativesrcdir 	= browser/devtools/tilt/
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _BROWSER_TEST_FILES = \
 	head.js \
 	browser_tilt_01_lazy_getter.js \
 	browser_tilt_02_notifications.js \
 	browser_tilt_03_tab_switch.js \
+	browser_tilt_04_initialization-key.js \
 	browser_tilt_04_initialization.js \
 	browser_tilt_05_destruction-esc.js \
 	browser_tilt_05_destruction-url.js \
 	browser_tilt_05_destruction.js \
+	browser_tilt_arcball-reset-typeahead.js \
+	browser_tilt_arcball-reset.js \
 	browser_tilt_arcball.js \
 	browser_tilt_controller.js \
 	browser_tilt_gl01.js \
 	browser_tilt_gl02.js \
 	browser_tilt_gl03.js \
 	browser_tilt_gl04.js \
 	browser_tilt_gl05.js \
 	browser_tilt_gl06.js \
--- a/browser/devtools/tilt/test/browser_tilt_02_notifications.js
+++ b/browser/devtools/tilt/test/browser_tilt_02_notifications.js
@@ -25,16 +25,17 @@ function test() {
   gBrowser.tabContainer.addEventListener("TabSelect", tabSelect, false);
   createNewTab();
 }
 
 function createNewTab() {
   tab0 = gBrowser.selectedTab;
 
   tab1 = createTab(function() {
+    Services.obs.addObserver(cleanup, TILT_DESTROYED, false);
     Services.obs.addObserver(tab_TILT_INITIALIZED, TILT_INITIALIZED, false);
     Services.obs.addObserver(tab_TILT_DESTROYED, TILT_DESTROYED, false);
     Services.obs.addObserver(tab_TILT_SHOWN, TILT_SHOWN, false);
     Services.obs.addObserver(tab_TILT_HIDDEN, TILT_HIDDEN, false);
 
     createTilt({
       onTiltOpen: function()
       {
@@ -65,33 +66,35 @@ let testSteps = [
   function step0() {
     gBrowser.selectedTab = tab0;
   },
   function step1() {
     gBrowser.selectedTab = tab1;
   },
   function step2() {
     Tilt.destroy(Tilt.currentWindowId);
-
-    Services.obs.removeObserver(tab_TILT_INITIALIZED, TILT_INITIALIZED, false);
-    Services.obs.removeObserver(tab_TILT_DESTROYED, TILT_DESTROYED, false);
-    Services.obs.removeObserver(tab_TILT_SHOWN, TILT_SHOWN, false);
-    Services.obs.removeObserver(tab_TILT_HIDDEN, TILT_HIDDEN, false);
-    gBrowser.removeCurrentTab();
-  },
-  function step3_cleanup() {
-    is(tabEvents, "ti;th;ts;td;",
-      "The notifications weren't fired in the correct order.");
-
-    tab0 = null;
-    tab1 = null;
-
-    gBrowser.tabContainer.removeEventListener("TabSelect", tabSelect, false);
-    finish();
   }
 ];
 
+function cleanup() {
+  is(tabEvents, "ti;th;ts;td;",
+    "The notifications weren't fired in the correct order.");
+
+  tab0 = null;
+  tab1 = null;
+
+  Services.obs.removeObserver(cleanup, TILT_DESTROYED);
+  Services.obs.removeObserver(tab_TILT_INITIALIZED, TILT_INITIALIZED, false);
+  Services.obs.removeObserver(tab_TILT_DESTROYED, TILT_DESTROYED, false);
+  Services.obs.removeObserver(tab_TILT_SHOWN, TILT_SHOWN, false);
+  Services.obs.removeObserver(tab_TILT_HIDDEN, TILT_HIDDEN, false);
+
+  gBrowser.tabContainer.removeEventListener("TabSelect", tabSelect, false);
+  gBrowser.removeCurrentTab();
+  finish();
+}
+
 function tabSelect() {
   if (testStep !== -1) {
     executeSoon(testSteps[testStep]);
     testStep++;
   }
 }
new file mode 100644
--- /dev/null
+++ b/browser/devtools/tilt/test/browser_tilt_04_initialization-key.js
@@ -0,0 +1,75 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/*global ok, is, info, waitForExplicitFinish, finish, executeSoon, gBrowser */
+/*global isTiltEnabled, isWebGLSupported, createTab, createTilt */
+/*global Services, EventUtils, Tilt, TiltUtils, TiltVisualizer, InspectorUI */
+/*global Ci, TILT_INITIALIZED, TILT_DESTROYED, INSPECTOR_OPENED */
+"use strict";
+
+let id;
+let tiltKey;
+let eventType;
+
+function test() {
+  if (!isTiltEnabled()) {
+    info("Skipping initialization key test because Tilt isn't enabled.");
+    return;
+  }
+  if (!isWebGLSupported()) {
+    info("Skipping initialization key test because WebGL isn't supported.");
+    return;
+  }
+
+  waitForExplicitFinish();
+
+  id = TiltUtils.getWindowId(gBrowser.selectedBrowser.contentWindow);
+  tiltKey = Tilt.tiltButton.getAttribute("accesskey");
+
+  if ("nsILocalFileMac" in Ci) {
+    eventType = { type: "keypress", ctrlKey: true };
+  } else {
+    eventType = { type: "keypress", altKey: true };
+  }
+
+  Services.obs.addObserver(onInspectorOpen, INSPECTOR_OPENED, false);
+  InspectorUI.toggleInspectorUI();
+}
+
+function onInspectorOpen() {
+  Services.obs.removeObserver(onInspectorOpen, INSPECTOR_OPENED);
+
+  executeSoon(function() {
+    is(Tilt.visualizers[id], null,
+      "A instance of the visualizer shouldn't be initialized yet.");
+
+    info("Pressing the accesskey should open Tilt.");
+
+    Services.obs.addObserver(onTiltOpen, TILT_INITIALIZED, false);
+    EventUtils.synthesizeKey(tiltKey, eventType);
+  });
+}
+
+function onTiltOpen() {
+  Services.obs.removeObserver(onTiltOpen, TILT_INITIALIZED);
+
+  executeSoon(function() {
+    ok(Tilt.visualizers[id] instanceof TiltVisualizer,
+      "A new instance of the visualizer wasn't created properly.");
+    ok(Tilt.visualizers[id].isInitialized(),
+      "The new instance of the visualizer wasn't initialized properly.");
+
+    info("Pressing the accesskey again should close Tilt.");
+
+    Services.obs.addObserver(onTiltClose, TILT_DESTROYED, false);
+    EventUtils.synthesizeKey(tiltKey, eventType);
+  });
+}
+
+function onTiltClose() {
+  is(Tilt.visualizers[id], null,
+    "The current instance of the visualizer wasn't destroyed properly.");
+
+  InspectorUI.closeInspectorUI();
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/tilt/test/browser_tilt_arcball-reset-typeahead.js
@@ -0,0 +1,107 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/*global ok, is, info, isApproxVec, waitForExplicitFinish, executeSoon, finish */
+/*global isTiltEnabled, isWebGLSupported, createTab, createTilt */
+/*global Services, EventUtils, InspectorUI, TiltVisualizer, TILT_DESTROYED */
+"use strict";
+
+function test() {
+  if (!isTiltEnabled()) {
+    info("Skipping part of the arcball test because Tilt isn't enabled.");
+    return;
+  }
+  if (!isWebGLSupported()) {
+    info("Skipping part of the arcball test because WebGL isn't supported.");
+    return;
+  }
+
+  waitForExplicitFinish();
+  Services.prefs.setBoolPref("accessibility.typeaheadfind", true);
+
+  createTab(function() {
+    createTilt({
+      onTiltOpen: function(instance)
+      {
+        performTest(instance.presenter.canvas,
+                    instance.controller.arcball, function() {
+
+          info("Killing arcball reset test.");
+
+          Services.prefs.setBoolPref("accessibility.typeaheadfind", false);
+          Services.obs.addObserver(cleanup, TILT_DESTROYED, false);
+          InspectorUI.closeInspectorUI();
+        });
+      }
+    });
+  });
+}
+
+function performTest(canvas, arcball, callback) {
+  is(document.activeElement, canvas,
+    "The visualizer canvas should be focused when performing this test.");
+
+
+  info("Starting arcball reset test.");
+
+  // start translating and rotating sometime at random
+
+  executeSoon(function() {
+    info("Synthesizing key down events.");
+
+    EventUtils.synthesizeKey("VK_W", { type: "keydown" });
+    EventUtils.synthesizeKey("VK_LEFT", { type: "keydown" });
+
+    // wait for some arcball translations and rotations to happen
+
+    executeSoon(function() {
+      info("Synthesizing key up events.");
+
+      EventUtils.synthesizeKey("VK_W", { type: "keyup" });
+      EventUtils.synthesizeKey("VK_LEFT", { type: "keyup" });
+
+      // ok, transformations finished, we can now try to reset the model view
+
+      executeSoon(function() {
+        info("Synthesizing arcball reset key press.");
+
+        arcball.onResetFinish = function() {
+          ok(isApproxVec(arcball._lastRot, [0, 0, 0, 1]),
+            "The arcball _lastRot field wasn't reset correctly.");
+          ok(isApproxVec(arcball._deltaRot, [0, 0, 0, 1]),
+            "The arcball _deltaRot field wasn't reset correctly.");
+          ok(isApproxVec(arcball._currentRot, [0, 0, 0, 1]),
+            "The arcball _currentRot field wasn't reset correctly.");
+
+          ok(isApproxVec(arcball._lastTrans, [0, 0, 0]),
+            "The arcball _lastTrans field wasn't reset correctly.");
+          ok(isApproxVec(arcball._deltaTrans, [0, 0, 0]),
+            "The arcball _deltaTrans field wasn't reset correctly.");
+          ok(isApproxVec(arcball._currentTrans, [0, 0, 0]),
+            "The arcball _currentTrans field wasn't reset correctly.");
+
+          ok(isApproxVec(arcball._additionalRot, [0, 0, 0]),
+            "The arcball _additionalRot field wasn't reset correctly.");
+          ok(isApproxVec(arcball._additionalTrans, [0, 0, 0]),
+            "The arcball _additionalTrans field wasn't reset correctly.");
+
+          ok(isApproxVec([arcball._zoomAmount], [0]),
+            "The arcball _zoomAmount field wasn't reset correctly.");
+
+          info("Finishing arcball reset test.");
+          callback();
+        };
+
+        EventUtils.synthesizeKey("VK_R", { type: "keydown" });
+      });
+    });
+  });
+}
+
+function cleanup() { /*global gBrowser */
+  info("Cleaning up arcball reset test.");
+
+  Services.obs.removeObserver(cleanup, TILT_DESTROYED);
+  gBrowser.removeCurrentTab();
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/tilt/test/browser_tilt_arcball-reset.js
@@ -0,0 +1,105 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/*global ok, is, info, isApproxVec, waitForExplicitFinish, executeSoon, finish */
+/*global isTiltEnabled, isWebGLSupported, createTab, createTilt */
+/*global Services, EventUtils, InspectorUI, TiltVisualizer, TILT_DESTROYED */
+"use strict";
+
+function test() {
+  if (!isTiltEnabled()) {
+    info("Skipping part of the arcball test because Tilt isn't enabled.");
+    return;
+  }
+  if (!isWebGLSupported()) {
+    info("Skipping part of the arcball test because WebGL isn't supported.");
+    return;
+  }
+
+  waitForExplicitFinish();
+
+  createTab(function() {
+    createTilt({
+      onTiltOpen: function(instance)
+      {
+        performTest(instance.presenter.canvas,
+                    instance.controller.arcball, function() {
+
+          info("Killing arcball reset test.");
+
+          Services.obs.addObserver(cleanup, TILT_DESTROYED, false);
+          InspectorUI.closeInspectorUI();
+        });
+      }
+    });
+  });
+}
+
+function performTest(canvas, arcball, callback) {
+  is(document.activeElement, canvas,
+    "The visualizer canvas should be focused when performing this test.");
+
+
+  info("Starting arcball reset test.");
+
+  // start translating and rotating sometime at random
+
+  executeSoon(function() {
+    info("Synthesizing key down events.");
+
+    EventUtils.synthesizeKey("VK_W", { type: "keydown" });
+    EventUtils.synthesizeKey("VK_LEFT", { type: "keydown" });
+
+    // wait for some arcball translations and rotations to happen
+
+    executeSoon(function() {
+      info("Synthesizing key up events.");
+
+      EventUtils.synthesizeKey("VK_W", { type: "keyup" });
+      EventUtils.synthesizeKey("VK_LEFT", { type: "keyup" });
+
+      // ok, transformations finished, we can now try to reset the model view
+
+      executeSoon(function() {
+        info("Synthesizing arcball reset key press.");
+
+        arcball.onResetFinish = function() {
+          ok(isApproxVec(arcball._lastRot, [0, 0, 0, 1]),
+            "The arcball _lastRot field wasn't reset correctly.");
+          ok(isApproxVec(arcball._deltaRot, [0, 0, 0, 1]),
+            "The arcball _deltaRot field wasn't reset correctly.");
+          ok(isApproxVec(arcball._currentRot, [0, 0, 0, 1]),
+            "The arcball _currentRot field wasn't reset correctly.");
+
+          ok(isApproxVec(arcball._lastTrans, [0, 0, 0]),
+            "The arcball _lastTrans field wasn't reset correctly.");
+          ok(isApproxVec(arcball._deltaTrans, [0, 0, 0]),
+            "The arcball _deltaTrans field wasn't reset correctly.");
+          ok(isApproxVec(arcball._currentTrans, [0, 0, 0]),
+            "The arcball _currentTrans field wasn't reset correctly.");
+
+          ok(isApproxVec(arcball._additionalRot, [0, 0, 0]),
+            "The arcball _additionalRot field wasn't reset correctly.");
+          ok(isApproxVec(arcball._additionalTrans, [0, 0, 0]),
+            "The arcball _additionalTrans field wasn't reset correctly.");
+
+          ok(isApproxVec([arcball._zoomAmount], [0]),
+            "The arcball _zoomAmount field wasn't reset correctly.");
+
+          info("Finishing arcball reset test.");
+          callback();
+        };
+
+        EventUtils.synthesizeKey("VK_R", { type: "keydown" });
+      });
+    });
+  });
+}
+
+function cleanup() { /*global gBrowser */
+  info("Cleaning up arcball reset test.");
+
+  Services.obs.removeObserver(cleanup, TILT_DESTROYED);
+  gBrowser.removeCurrentTab();
+  finish();
+}
--- a/browser/devtools/tilt/test/browser_tilt_arcball.js
+++ b/browser/devtools/tilt/test/browser_tilt_arcball.js
@@ -1,29 +1,31 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-/*global ok, is, isApproxVec, vec3, quat4, TiltVisualizer */
-/*global Cc, Ci, Cu */
+/*global ok, is, info, isApprox, isApproxVec, vec3, quat4 */
+/*global TiltVisualizer */
 "use strict";
 
 function cloneUpdate(update) {
   return {
     rotation: quat4.create(update.rotation),
     translation: vec3.create(update.translation)
   };
 }
 
 function isExpectedUpdate(update1, update2) {
   if (update1.length !== update2.length) {
     return false;
   }
   for (let i = 0, len = update1.length; i < len; i++) {
     if (!isApproxVec(update1[i].rotation, update2[i].rotation) ||
         !isApproxVec(update1[i].translation, update2[i].translation)) {
+      info("isExpectedUpdate expected " + JSON.stringify(update1), ", got " +
+                                          JSON.stringify(update2) + " instead.");
       return false;
     }
   }
   return true;
 }
 
 function test() {
   let arcball1 = new TiltVisualizer.Arcball(123, 456);
@@ -52,54 +54,54 @@ function test() {
   arcball3.pointToSphere(123, 456, 256, 512, 512, sphereVec);
 
   ok(isApproxVec(sphereVec, [-0.009765625, 0.390625, 0.9204980731010437]),
     "The pointToSphere() function didn't map the coordinates correctly.");
 
   let stack1 = [];
   let expect1 = [
     { rotation: [
-      -0.054038457572460175, 0.015347825363278389,
-      -0.02533721923828125, -0.9980993270874023],
+      -0.08877250552177429, 0.0242881178855896,
+      -0.04222869873046875, -0.9948599338531494],
       translation: [0, 0, 0] },
     { rotation: [
-      -0.09048379212617874, 0.024709727615118027,
-      -0.04307326674461365, -0.9946591854095459],
+      -0.13086390495300293, 0.03413732722401619,
+      -0.06334304809570312, -0.9887855648994446],
       translation: [0, 0, 0] },
     { rotation: [
-      -0.11537143588066101, 0.03063894622027874,
-      -0.05548851564526558, -0.9912980198860168],
+      -0.15138940513134003, 0.03854173421859741,
+      -0.07390022277832031, -0.9849540591239929],
       translation: [0, 0, 0] },
     { rotation: [
-      -0.13250185549259186, 0.03449848294258118,
-      -0.0641791820526123, -0.9885009527206421],
+      -0.1615273654460907, 0.040619146078825,
+      -0.0791788101196289, -0.9828477501869202],
       translation: [0, 0, 0] },
     { rotation: [
-      -0.14435507357120514, 0.037062086164951324,
-      -0.07026264816522598, -0.9863321781158447],
+      -0.16656573116779327, 0.04162723943591118,
+      -0.0818181037902832, -0.9817478656768799],
       translation: [0, 0, 0] },
     { rotation: [
-      -0.15258607268333435, 0.03879034146666527,
-      -0.07452107220888138, -0.9847128391265869],
+      -0.16907735168933868, 0.042123712599277496,
+      -0.08313775062561035, -0.9811863303184509],
       translation: [0, 0, 0] },
     { rotation: [
-      -0.1583157479763031, 0.03996811807155609,
-      -0.07750196009874344, -0.9835304617881775],
+      -0.17033125460147858, 0.042370058596134186,
+      -0.08379757404327393, -0.9809026718139648],
       translation: [0, 0, 0] },
     { rotation: [
-      -0.16231097280979156, 0.04077700152993202,
-      -0.07958859205245972, -0.982679009437561],
+      -0.17095772922039032, 0.04249274358153343,
+      -0.08412748575210571, -0.9807600975036621],
       translation: [0, 0, 0] },
     { rotation: [
-      -0.16510005295276642, 0.04133564606308937,
-      -0.08104922622442245, -0.9820714592933655],
+      -0.17127084732055664, 0.04255397245287895,
+      -0.0842924416065216, -0.9806886315345764],
       translation: [0, 0, 0] },
     { rotation: [
-      -0.16704875230789185, 0.04172303527593613,
-      -0.08207167685031891, -0.9816405177116394],
+      -0.171427384018898, 0.042584557086229324,
+      -0.08437491953372955, -0.9806528687477112],
       translation: [0, 0, 0] }];
 
   arcball3.mouseDown(10, 10, 1);
   arcball3.mouseMove(10, 100);
   for (let i1 = 0; i1 < 10; i1++) {
     stack1.push(cloneUpdate(arcball3.update()));
   }
 
@@ -246,24 +248,24 @@ function test() {
       -0.17158377170562744, 0.04261511191725731,
       -0.08445732295513153, -0.980617105960846],
       translation: [0, 0, -8.649148941040039] },
     { rotation: [
       -0.17158380150794983, 0.04261511191725731,
       -0.08445733785629272, -0.980617105960846],
       translation: [0, 0, -8.784234046936035] }];
 
-  arcball3.keyDown(Ci.nsIDOMKeyEvent.DOM_VK_A);
-  arcball3.keyDown(Ci.nsIDOMKeyEvent.DOM_VK_D);
-  arcball3.keyDown(Ci.nsIDOMKeyEvent.DOM_VK_W);
-  arcball3.keyDown(Ci.nsIDOMKeyEvent.DOM_VK_S);
-  arcball3.keyDown(Ci.nsIDOMKeyEvent.DOM_VK_LEFT);
-  arcball3.keyDown(Ci.nsIDOMKeyEvent.DOM_VK_RIGHT);
-  arcball3.keyDown(Ci.nsIDOMKeyEvent.DOM_VK_UP);
-  arcball3.keyDown(Ci.nsIDOMKeyEvent.DOM_VK_DOWN);
+  arcball3.keyDown(arcball3.rotateKeys.left);
+  arcball3.keyDown(arcball3.rotateKeys.right);
+  arcball3.keyDown(arcball3.rotateKeys.up);
+  arcball3.keyDown(arcball3.rotateKeys.down);
+  arcball3.keyDown(arcball3.panKeys.left);
+  arcball3.keyDown(arcball3.panKeys.right);
+  arcball3.keyDown(arcball3.panKeys.up);
+  arcball3.keyDown(arcball3.panKeys.down);
   for (let i4 = 0; i4 < 10; i4++) {
     stack4.push(cloneUpdate(arcball3.update()));
   }
 
   ok(isExpectedUpdate(stack4, expect4),
     "Key down events didn't create the expected transformation results.");
 
   let stack5 = [];
@@ -304,24 +306,24 @@ function test() {
       -0.17158392071723938, 0.0426151417195797,
       -0.0844573974609375, -0.980617105960846],
       translation: [0, 0, -9.528986930847168] },
     { rotation: [
       -0.17158392071723938, 0.0426151417195797,
       -0.0844573974609375, -0.980617105960846],
       translation: [0, 0, -9.576087951660156] }];
 
-  arcball3.keyUp(Ci.nsIDOMKeyEvent.DOM_VK_A);
-  arcball3.keyUp(Ci.nsIDOMKeyEvent.DOM_VK_D);
-  arcball3.keyUp(Ci.nsIDOMKeyEvent.DOM_VK_W);
-  arcball3.keyUp(Ci.nsIDOMKeyEvent.DOM_VK_S);
-  arcball3.keyUp(Ci.nsIDOMKeyEvent.DOM_VK_LEFT);
-  arcball3.keyUp(Ci.nsIDOMKeyEvent.DOM_VK_RIGHT);
-  arcball3.keyUp(Ci.nsIDOMKeyEvent.DOM_VK_UP);
-  arcball3.keyUp(Ci.nsIDOMKeyEvent.DOM_VK_DOWN);
+  arcball3.keyUp(arcball3.rotateKeys.left);
+  arcball3.keyUp(arcball3.rotateKeys.right);
+  arcball3.keyUp(arcball3.rotateKeys.up);
+  arcball3.keyUp(arcball3.rotateKeys.down);
+  arcball3.keyUp(arcball3.panKeys.left);
+  arcball3.keyUp(arcball3.panKeys.right);
+  arcball3.keyUp(arcball3.panKeys.up);
+  arcball3.keyUp(arcball3.panKeys.down);
   for (let i5 = 0; i5 < 10; i5++) {
     stack5.push(cloneUpdate(arcball3.update()));
   }
 
   ok(isExpectedUpdate(stack5, expect5),
     "Key up events didn't create the expected transformation results.");
 
   let stack6 = [];
@@ -362,25 +364,25 @@ function test() {
       -0.17158392071723938, 0.0426151417195797,
       -0.0844573974609375, -0.980617105960846],
       translation: [0, 0, 90.76139831542969] },
     { rotation: [
       -0.17158392071723938, 0.0426151417195797,
       -0.0844573974609375, -0.980617105960846],
       translation: [0, 0, 112.18525695800781] }];
 
-  arcball3.keyDown(Ci.nsIDOMKeyEvent.DOM_VK_I);
-  arcball3.keyDown(Ci.nsIDOMKeyEvent.DOM_VK_ADD);
-  arcball3.keyDown(Ci.nsIDOMKeyEvent.DOM_VK_EQUALS);
+  arcball3.keyDown(arcball3.zoomKeys["in"][0]);
+  arcball3.keyDown(arcball3.zoomKeys["in"][1]);
+  arcball3.keyDown(arcball3.zoomKeys["in"][2]);
   for (let i6 = 0; i6 < 10; i6++) {
     stack6.push(cloneUpdate(arcball3.update()));
   }
-  arcball3.keyUp(Ci.nsIDOMKeyEvent.DOM_VK_I);
-  arcball3.keyUp(Ci.nsIDOMKeyEvent.DOM_VK_ADD);
-  arcball3.keyUp(Ci.nsIDOMKeyEvent.DOM_VK_EQUALS);
+  arcball3.keyUp(arcball3.zoomKeys["in"][0]);
+  arcball3.keyUp(arcball3.zoomKeys["in"][1]);
+  arcball3.keyUp(arcball3.zoomKeys["in"][2]);
 
   ok(isExpectedUpdate(stack6, expect6),
     "Key zoom in events didn't create the expected transformation results.");
 
   let stack7 = [];
   let expect7 = [
     { rotation: [
       -0.17158392071723938, 0.0426151417195797,
@@ -418,23 +420,23 @@ function test() {
       -0.17158392071723938, 0.0426151417195797,
       -0.0844573974609375, -0.980617105960846],
       translation: [0, 0, 151.1427459716797] },
     { rotation: [
       -0.17158392071723938, 0.0426151417195797,
       -0.0844573974609375, -0.980617105960846],
       translation: [0, 0, 138.52847290039062] }];
 
-  arcball3.keyDown(Ci.nsIDOMKeyEvent.DOM_VK_O);
-  arcball3.keyDown(Ci.nsIDOMKeyEvent.DOM_VK_SUBTRACT);
+  arcball3.keyDown(arcball3.zoomKeys["out"][0]);
+  arcball3.keyDown(arcball3.zoomKeys["out"][1]);
   for (let i7 = 0; i7 < 10; i7++) {
     stack7.push(cloneUpdate(arcball3.update()));
   }
-  arcball3.keyUp(Ci.nsIDOMKeyEvent.DOM_VK_O);
-  arcball3.keyUp(Ci.nsIDOMKeyEvent.DOM_VK_SUBTRACT);
+  arcball3.keyUp(arcball3.zoomKeys["out"][0]);
+  arcball3.keyUp(arcball3.zoomKeys["out"][1]);
 
   ok(isExpectedUpdate(stack7, expect7),
     "Key zoom out events didn't create the expected transformation results.");
 
   let stack8 = [];
   let expect8 = [
     { rotation: [
       -0.17158392071723938, 0.0426151417195797,
@@ -472,28 +474,26 @@ function test() {
       -0.17158392071723938, 0.0426151417195797,
       -0.0844573974609375, -0.980617105960846],
       translation: [0, 0, 53.238304138183594] },
     { rotation: [
       -0.17158392071723938, 0.0426151417195797,
       -0.0844573974609375, -0.980617105960846],
       translation: [0, 0, 47.91447448730469] }];
 
-  arcball3.keyDown(Ci.nsIDOMKeyEvent.DOM_VK_R);
-  arcball3.keyDown(Ci.nsIDOMKeyEvent.DOM_VK_0);
+  arcball3.keyDown(arcball3.zoomKeys["unzoom"]);
   for (let i8 = 0; i8 < 10; i8++) {
     stack8.push(cloneUpdate(arcball3.update()));
   }
-  arcball3.keyUp(Ci.nsIDOMKeyEvent.DOM_VK_R);
-  arcball3.keyUp(Ci.nsIDOMKeyEvent.DOM_VK_0);
+  arcball3.keyUp(arcball3.zoomKeys["unzoom"]);
 
   ok(isExpectedUpdate(stack8, expect8),
     "Key zoom reset events didn't create the expected transformation results.");
 
 
   arcball3.resize(123, 456);
   is(arcball3.width, 123,
-    "The arcball width wasn't updated correctly.");
+    "The third arcball width wasn't updated correctly.");
   is(arcball3.height, 456,
-    "The arcball height wasn't updated correctly.");
+    "The third arcball height wasn't updated correctly.");
   is(arcball3.radius, 123,
-    "The arcball radius wasn't implicitly updated correctly.");
+    "The third arcball radius wasn't implicitly updated correctly.");
 }
--- a/browser/devtools/tilt/test/browser_tilt_controller.js
+++ b/browser/devtools/tilt/test/browser_tilt_controller.js
@@ -1,14 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /*global ok, is, info, waitForExplicitFinish, finish, executeSoon, gBrowser */
 /*global isEqualVec, isTiltEnabled, isWebGLSupported, createTab, createTilt */
-/*global EventUtils, vec3, mat4, quat4 */
+/*global Services, EventUtils, vec3, mat4, quat4 */
 "use strict";
 
 function test() {
   if (!isTiltEnabled()) {
     info("Skipping controller test because Tilt isn't enabled.");
     return;
   }
   if (!isWebGLSupported()) {
@@ -41,16 +41,19 @@ function test() {
 
         ok(isEqualVec(tran(), prev_tran),
           "At init, the translation should be zero.");
         ok(isEqualVec(rot(), prev_rot),
           "At init, the rotation should be zero.");
 
 
         function testEventCancel(cancellingEvent) {
+          is(document.activeElement, canvas,
+            "The visualizer canvas should be focused when performing this test.");
+
           EventUtils.synthesizeKey("VK_A", { type: "keydown" });
           EventUtils.synthesizeKey("VK_LEFT", { type: "keydown" });
           instance.controller.update();
 
           ok(!isEqualVec(tran(), prev_tran),
             "After a translation key is pressed, the vector should change.");
           ok(!isEqualVec(rot(), prev_rot),
             "After a rotation key is pressed, the quaternion should change.");
@@ -74,28 +77,50 @@ function test() {
             instance.controller.update();
             save();
           }
 
           ok(isEqualVec(tran(), prev_tran) && isEqualVec(rot(), prev_rot),
             "After focus lost, the transforms inertia eventually stops.");
         }
 
+        info("Setting typeaheadfind to true.");
+
+        Services.prefs.setBoolPref("accessibility.typeaheadfind", true);
         testEventCancel(function() {
           EventUtils.synthesizeKey("T", { type: "keydown", altKey: 1 });
         });
         testEventCancel(function() {
           EventUtils.synthesizeKey("I", { type: "keydown", ctrlKey: 1 });
         });
         testEventCancel(function() {
           EventUtils.synthesizeKey("L", { type: "keydown", metaKey: 1 });
         });
         testEventCancel(function() {
           EventUtils.synthesizeKey("T", { type: "keydown", shiftKey: 1 });
         });
+
+        info("Setting typeaheadfind to false.");
+
+        Services.prefs.setBoolPref("accessibility.typeaheadfind", false);
+        testEventCancel(function() {
+          EventUtils.synthesizeKey("T", { type: "keydown", altKey: 1 });
+        });
+        testEventCancel(function() {
+          EventUtils.synthesizeKey("I", { type: "keydown", ctrlKey: 1 });
+        });
+        testEventCancel(function() {
+          EventUtils.synthesizeKey("L", { type: "keydown", metaKey: 1 });
+        });
+        testEventCancel(function() {
+          EventUtils.synthesizeKey("T", { type: "keydown", shiftKey: 1 });
+        });
+
+        info("Testing if loosing focus halts any stacked arcball animations.");
+
         testEventCancel(function() {
           gBrowser.selectedBrowser.contentWindow.focus();
         });
       },
       onEnd: function()
       {
         gBrowser.removeCurrentTab();
         finish();
--- a/browser/devtools/tilt/test/browser_tilt_utils06.js
+++ b/browser/devtools/tilt/test/browser_tilt_utils06.js
@@ -38,9 +38,13 @@ function test() {
     "The finalize function wasn't called when an object was destroyed.");
 
 
   TiltUtils.destroyObject(someObject);
   is(typeof someObject.a, "undefined",
     "Not all members of the destroyed object were deleted.");
   is(typeof someObject.func, "undefined",
     "Not all function members of the destroyed object were deleted.");
+
+
+  is(TiltUtils.getBrowserWindow(), window,
+    "The getBrowserWindow() function didn't return the correct window.");
 }
--- a/browser/themes/gnomestripe/browser.css
+++ b/browser/themes/gnomestripe/browser.css
@@ -1984,17 +1984,16 @@ panel[dimmed="true"] {
 /* Highlighter toolbar */
 
 #inspector-toolbar {
   border-top: 1px solid hsla(210, 8%, 5%, .65);
 }
 
 #inspector-toolbar[treepanel-open] {
   padding-top: 0;
-  -moz-padding-end: 0;
 }
 
 #devtools-side-splitter {
   -moz-appearance: none;
   border: 0;
   -moz-border-start: 1px solid #242b33;
   min-width: 0;
   width: 3px;
@@ -2002,41 +2001,25 @@ panel[dimmed="true"] {
   -moz-margin-end: -3px;
   position: relative;
 }
 
 #devtools-sidebar-box {
   background-color: -moz-Field;
 }
 
-/* Highlighter - toolbar resizers */
+/* Highlighter - toolbar resizer */
 
-.inspector-resizer {
+#inspector-top-resizer {
   -moz-appearance: none;
   cursor: n-resize;
-}
-
-#inspector-top-resizer {
   background: none;
   height: 4px;
 }
 
-#inspector-end-resizer {
-  width: 12px;
-  height: 8px;
-  background-image: -moz-linear-gradient(top, black 1px, rgba(255,255,255,0.2) 1px);
-  background-size: 10px 2px;
-  background-clip: padding-box;
-  background-repeat: repeat-y;
-  border-width: 1px 1px 0;
-  border-style: solid;
-  border-color: rgba(255, 255, 255, 0.05);
-  margin: 7px 7px 8px;
-}
-
 /* Highlighter - Node Infobar */
 
 /* Highlighter - Node Infobar - text */
 
 #highlighter-nodeinfobar-tagname {
   color: white;
 }
 
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -2715,21 +2715,34 @@ panel[dimmed="true"] {
   box-shadow: 0 0 0 1px black;
   outline-color: white;
 }
 
 /* Highlighter toolbar */
 
 #inspector-toolbar {
   border-top: 1px solid hsla(210, 8%, 5%, .65);
-  padding: 4px 16px 4px 0; /* use -moz-padding-end: 16px when/if bug 631729 gets fixed */
+  padding-top: 4px;
+  padding-bottom: 4px;
+}
+
+#inspector-toolbar:-moz-locale-dir(ltr) {
+  padding-left: 2px;
+  padding-right: 16px; /* use -moz-padding-end when/if bug 631729 gets fixed */
+}
+
+#inspector-toolbar:-moz-locale-dir(rtl) {
+  padding-left: 4px;
+  padding-right: 18px; /* use -moz-padding-end when/if bug 631729 gets fixed */
 }
 
 #inspector-toolbar[treepanel-open] {
-  padding: 0 0 4px;
+  padding-top: 0;
+  padding-right: 0;
+  -moz-padding-end: 4px;
 }
 
 #devtools-side-splitter {
   background-image: none !important;
   border: 0;
   -moz-border-start: 1px solid #242b33;
   min-width: 0;
   width: 3px;
@@ -2737,41 +2750,25 @@ panel[dimmed="true"] {
   -moz-margin-end: -3px;
   position: relative;
 }
 
 #devtools-sidebar-box {
   background-color: -moz-Field;
 }
 
-/* Highlighter - toolbar resizers */
-
-.inspector-resizer {
+/* Highlighter - toolbar resizer */
+
+#inspector-top-resizer {
   -moz-appearance: none;
   cursor: n-resize;
-}
-
-#inspector-top-resizer {
   background: none;
   height: 4px;
 }
 
-#inspector-end-resizer {
-  width: 12px;
-  height: 8px;
-  background-image: -moz-linear-gradient(top, black 1px, rgba(255,255,255,0.2) 1px);
-  background-size: 10px 2px;
-  background-clip: padding-box;
-  background-repeat: repeat-y;
-  border-width: 1px 1px 0;
-  border-style: solid;
-  border-color: rgba(255, 255, 255, 0.05);
-  margin: 7px 7px 8px;
-}
-
 /* Highlighter - Node Infobar */
 
 /* Highlighter - Node Infobar - text */
 
 #highlighter-nodeinfobar-tagname {
   color: white;
 }
 
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -2665,58 +2665,41 @@ panel[dimmed="true"] {
 /* Highlighter toolbar */
 
 #inspector-toolbar {
   border-top: 1px solid hsla(211,68%,6%,.65) !important;
 }
 
 #inspector-toolbar[treepanel-open] {
   padding-top: 0;
-  -moz-padding-end: 0;
 }
 
 #devtools-side-splitter {
   border: 0;
   -moz-border-start: 1px solid #242b33;
   min-width: 0;
   width: 3px;
   background-color: transparent;
   -moz-margin-end: -3px;
   position: relative;
 }
 
 #devtools-sidebar-box {
   background-color: -moz-Field;
 }
 
-/* Highlighter - toolbar resizers */
-
-.inspector-resizer {
+/* Highlighter - toolbar resizer */
+
+#inspector-top-resizer {
   -moz-appearance: none;
   cursor: n-resize;
-}
-
-#inspector-top-resizer {
   background: none;
   height: 4px;
 }
 
-#inspector-end-resizer {
-  width: 12px;
-  height: 8px;
-  background-image: -moz-linear-gradient(top, black 1px, rgba(255,255,255,0.2) 1px);
-  background-size: 10px 2px;
-  background-clip: padding-box;
-  background-repeat: repeat-y;
-  border-width: 1px 1px 0;
-  border-style: solid;
-  border-color: rgba(255, 255, 255, 0.05);
-  margin: 7px 7px 8px;
-}
-
 /* Highlighter - Node Infobar */
 
 /* Highlighter - Node Infobar - text */
 
 #highlighter-nodeinfobar-tagname {
   color: white;
 }
 
new file mode 100644
--- /dev/null
+++ b/build/unix/build-toolchain/binutils-deterministic.patch
@@ -0,0 +1,22 @@
+diff -ru a/binutils/ar.c b/binutils/ar.c
+--- a/binutils/ar.c	2011-03-16 04:35:58.000000000 -0400
++++ b/binutils/ar.c	2012-01-19 15:44:46.211226017 -0500
+@@ -98,7 +98,7 @@
+ /* Operate in deterministic mode: write zero for timestamps, uids,
+    and gids for archive members and the archive symbol table, and write
+    consistent file modes.  */
+-int deterministic = 0;
++int deterministic = TRUE;
+ 
+ /* Nonzero means it's the name of an existing member; position new or moved
+    files with respect to this one.  */
+@@ -634,9 +634,6 @@
+       if (newer_only && operation != replace)
+ 	fatal (_("`u' is only meaningful with the `r' option."));
+ 
+-      if (newer_only && deterministic)
+-	fatal (_("`u' is not meaningful with the `D' option."));
+-
+       if (postype != pos_default)
+ 	posname = argv[arg_index++];
+ 
--- a/build/unix/build-toolchain/build-gcc.py
+++ b/build/unix/build-toolchain/build-gcc.py
@@ -35,22 +35,16 @@ def patch(patch, plevel, srcdir):
 
 def build_package(package_source_dir, package_build_dir, configure_args):
     os.mkdir(package_build_dir)
     run_in(package_build_dir,
            ["%s/configure" % package_source_dir] + configure_args)
     run_in(package_build_dir, ["make", "-j8"])
     run_in(package_build_dir, ["make", "install"])
 
-def build_binutils(base_dir, binutils_inst_dir):
-    binutils_build_dir = base_dir + '/binutils_build'
-    build_package(binutils_source_dir, binutils_build_dir,
-                  ["--prefix=%s" % binutils_inst_dir])
-
-# FIXME: factor this with build_binutils
 def build_tar(base_dir, tar_inst_dir):
     tar_build_dir = base_dir + '/tar_build'
     build_package(tar_source_dir, tar_build_dir,
                   ["--prefix=%s" % tar_inst_dir])
 
 def build_one_stage(env, stage_dir):
     old_env = os.environ.copy()
     os.environ.update(env)
@@ -66,20 +60,25 @@ def build_one_stage(env, stage_dir):
                   ["--prefix=%s" % lib_inst_dir, "--disable-shared",
                    "--with-gmp=%s" % lib_inst_dir])
     mpc_build_dir = stage_dir + '/mpc'
     build_package(mpc_source_dir, mpc_build_dir,
                   ["--prefix=%s" % lib_inst_dir, "--disable-shared",
                    "--with-gmp=%s" % lib_inst_dir,
                    "--with-mpfr=%s" % lib_inst_dir])
 
+    tool_inst_dir = stage_dir + '/inst'
+
+    binutils_build_dir = stage_dir + '/binutils'
+    build_package(binutils_source_dir, binutils_build_dir,
+                  ["--prefix=%s" % tool_inst_dir])
+
     gcc_build_dir = stage_dir + '/gcc'
-    gcc_inst_dir = stage_dir + '/inst'
     build_package(gcc_source_dir, gcc_build_dir,
-                  ["--prefix=%s" % gcc_inst_dir,
+                  ["--prefix=%s" % tool_inst_dir,
                    "--enable-__cxa_atexit",
                    "--with-gmp=%s" % lib_inst_dir,
                    "--with-mpfr=%s" % lib_inst_dir,
                    "--with-mpc=%s" % lib_inst_dir,
                    "--enable-languages=c,c++",
                    "--disable-bootstrap"])
     os.environ.clear()
     os.environ.update(old_env)
@@ -129,39 +128,37 @@ tar_source_dir  = build_source_dir('tar-
 mpc_source_dir  = build_source_dir('mpc-', mpc_version)
 mpfr_source_dir = build_source_dir('mpfr-', mpfr_version)
 gmp_source_dir  = build_source_dir('gmp-', gmp_version)
 gcc_source_dir  = build_source_dir('gcc-', gcc_version)
 
 if not os.path.exists(source_dir):
     os.mkdir(source_dir)
     extract(binutils_source_tar, source_dir)
+    patch('binutils-deterministic.patch', 1, binutils_source_dir)
     extract(tar_source_tar, source_dir)
     extract(mpc_source_tar, source_dir)
     extract(mpfr_source_tar, source_dir)
     extract(gmp_source_tar, source_dir)
     extract(gcc_source_tar, source_dir)
     patch('plugin_finish_decl.diff', 0, gcc_source_dir)
     patch('pr49911.diff', 1, gcc_source_dir)
     patch('r159628-r163231-r171807.patch', 1, gcc_source_dir)
 
 if os.path.exists(build_dir):
     shutil.rmtree(build_dir)
 os.mkdir(build_dir)
 
-tools_inst_dir = build_dir + '/tools_inst'
-build_binutils(build_dir, tools_inst_dir)
-build_tar(build_dir, tools_inst_dir)
-
-os.environ["AR"] = os.path.realpath('det-ar.sh')
-os.environ["MOZ_AR"] = tools_inst_dir + '/bin/ar'
-os.environ["RANLIB"] = "true"
+tar_inst_dir = build_dir + '/tar_inst'
+build_tar(build_dir, tar_inst_dir)
 
 stage1_dir = build_dir + '/stage1'
 build_one_stage({"CC": "gcc", "CXX" : "g++"}, stage1_dir)
 
-stage1_gcc_inst_dir = stage1_dir + '/inst'
+stage1_tool_inst_dir = stage1_dir + '/inst'
 stage2_dir = build_dir + '/stage2'
-build_one_stage({"CC"  : stage1_gcc_inst_dir + "/bin/gcc",
-                 "CXX" : stage1_gcc_inst_dir + "/bin/g++"}, stage2_dir)
+build_one_stage({"CC"     : stage1_tool_inst_dir + "/bin/gcc",
+                 "CXX"    : stage1_tool_inst_dir + "/bin/g++",
+                 "AR"     : stage1_tool_inst_dir + "/bin/ar",
+                 "RANLIB" : "true" })
 
-build_tar_package(tools_inst_dir + "/bin/tar",
+build_tar_package(tar_inst_dir + "/bin/tar",
                   "toolchain.tar", stage2_dir, "inst")
deleted file mode 100755
--- a/build/unix/build-toolchain/det-ar.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-
-shift
-echo $MOZ_AR "crD" "$@"
-exec $MOZ_AR "crD" "$@"
new file mode 100644
--- /dev/null
+++ b/build/unix/build-toolchain/plugin_finish_decl.diff
@@ -0,0 +1,179 @@
+Index: gcc/doc/plugins.texi
+===================================================================
+--- gcc/doc/plugins.texi	(revision 162126)
++++ gcc/doc/plugins.texi	(working copy)
+@@ -144,6 +144,7 @@
+ @{
+   PLUGIN_PASS_MANAGER_SETUP,    /* To hook into pass manager.  */
+   PLUGIN_FINISH_TYPE,           /* After finishing parsing a type.  */
++  PLUGIN_FINISH_DECL,           /* After finishing parsing a declaration. */
+   PLUGIN_FINISH_UNIT,           /* Useful for summary processing.  */
+   PLUGIN_PRE_GENERICIZE,        /* Allows to see low level AST in C and C++ frontends.  */
+   PLUGIN_FINISH,                /* Called before GCC exits.  */
+Index: gcc/plugin.def
+===================================================================
+--- gcc/plugin.def	(revision 162126)
++++ gcc/plugin.def	(working copy)
+@@ -24,6 +24,9 @@
+ /* After finishing parsing a type.  */
+ DEFEVENT (PLUGIN_FINISH_TYPE)
+ 
++/* After finishing parsing a declaration. */
++DEFEVENT (PLUGIN_FINISH_DECL)
++
+ /* Useful for summary processing.  */
+ DEFEVENT (PLUGIN_FINISH_UNIT)
+ 
+Index: gcc/testsuite/g++.dg/plugin/plugin.exp
+===================================================================
+--- gcc/testsuite/g++.dg/plugin/plugin.exp	(revision 162126)
++++ gcc/testsuite/g++.dg/plugin/plugin.exp	(working copy)
+@@ -51,7 +51,8 @@
+     { pragma_plugin.c pragma_plugin-test-1.C } \
+     { selfassign.c self-assign-test-1.C self-assign-test-2.C self-assign-test-3.C } \
+     { dumb_plugin.c dumb-plugin-test-1.C } \
+-    { header_plugin.c header-plugin-test.C } ]
++    { header_plugin.c header-plugin-test.C } \
++    { decl_plugin.c decl-plugin-test.C } ]
+ 
+ foreach plugin_test $plugin_test_list {
+     # Replace each source file with its full-path name
+Index: gcc/testsuite/g++.dg/plugin/decl-plugin-test.C
+===================================================================
+--- gcc/testsuite/g++.dg/plugin/decl-plugin-test.C	(revision 0)
++++ gcc/testsuite/g++.dg/plugin/decl-plugin-test.C	(revision 0)
+@@ -0,0 +1,32 @@
++
++
++extern int global; // { dg-warning "Decl Global global" }
++int global_array[] = { 1, 2, 3 }; // { dg-warning "Decl Global global_array" }
++
++int takes_args(int arg1, int arg2)
++{
++  int local = arg1 + arg2 + global; // { dg-warning "Decl Local local" }
++  return local + 1;
++}
++
++int global = 12; // { dg-warning "Decl Global global" }
++
++struct test_str {
++  int field; // { dg-warning "Decl Field field" }
++};
++
++class test_class {
++  int class_field1; // { dg-warning "Decl Field class_field1" }
++  int class_field2; // { dg-warning "Decl Field class_field2" }
++
++  test_class() // { dg-warning "Decl Function test_class" }
++    : class_field1(0), class_field2(0)
++  {}
++
++  void swap_fields(int bias) // { dg-warning "Decl Function swap_fields" }
++  {
++    int temp = class_field1 + bias; // { dg-warning "Decl Local temp" }
++    class_field1 = class_field2 - bias;
++    class_field2 = temp;
++  }
++};
+Index: gcc/testsuite/g++.dg/plugin/decl_plugin.c
+===================================================================
+--- gcc/testsuite/g++.dg/plugin/decl_plugin.c	(revision 0)
++++ gcc/testsuite/g++.dg/plugin/decl_plugin.c	(revision 0)
+@@ -0,0 +1,51 @@
++/* A plugin example that shows which declarations are caught by FINISH_DECL */
++
++#include "gcc-plugin.h"
++#include <stdlib.h>
++#include "config.h"
++#include "system.h"
++#include "coretypes.h"
++#include "tree.h"
++#include "tree-pass.h"
++#include "intl.h"
++
++int plugin_is_GPL_compatible;
++
++/* Callback function to invoke after GCC finishes a declaration. */
++
++void plugin_finish_decl (void *event_data, void *data)
++{
++  tree decl = (tree) event_data;
++
++  const char *kind = NULL;
++  switch (TREE_CODE(decl)) {
++  case FUNCTION_DECL:
++    kind = "Function"; break;
++  case PARM_DECL:
++    kind = "Parameter"; break;
++  case VAR_DECL:
++    if (DECL_CONTEXT(decl) != NULL)
++      kind = "Local";
++    else
++      kind = "Global";
++    break;
++  case FIELD_DECL:
++    kind = "Field"; break;
++  default:
++    kind = "Unknown";
++  }
++
++  warning (0, G_("Decl %s %s"),
++           kind, IDENTIFIER_POINTER (DECL_NAME (decl)));
++}
++
++int
++plugin_init (struct plugin_name_args *plugin_info,
++             struct plugin_gcc_version *version)
++{
++  const char *plugin_name = plugin_info->base_name;
++
++  register_callback (plugin_name, PLUGIN_FINISH_DECL,
++                     plugin_finish_decl, NULL);
++  return 0;
++}
+Index: gcc/cp/decl.c
+===================================================================
+--- gcc/cp/decl.c	(revision 162126)
++++ gcc/cp/decl.c	(working copy)
+@@ -5967,6 +5967,8 @@
+   /* If this was marked 'used', be sure it will be output.  */
+   if (lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
+     mark_decl_referenced (decl);
++
++  invoke_plugin_callbacks (PLUGIN_FINISH_DECL, decl);
+ }
+ 
+ /* Returns a declaration for a VAR_DECL as if:
+Index: gcc/c-decl.c
+===================================================================
+--- gcc/c-decl.c	(revision 162126)
++++ gcc/c-decl.c	(working copy)
+@@ -4392,6 +4392,8 @@
+       && DECL_INITIAL (decl) == NULL_TREE)
+     warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc___compat,
+ 		"uninitialized const %qD is invalid in C++", decl);
++
++  invoke_plugin_callbacks (PLUGIN_FINISH_DECL, decl);
+ }
+ 
+ /* Given a parsed parameter declaration, decode it into a PARM_DECL.  */
+Index: gcc/plugin.c
+===================================================================
+--- gcc/plugin.c	(revision 162126)
++++ gcc/plugin.c	(working copy)
+@@ -400,6 +400,7 @@
+ 	  }
+       /* Fall through.  */
+       case PLUGIN_FINISH_TYPE:
++      case PLUGIN_FINISH_DECL:
+       case PLUGIN_START_UNIT:
+       case PLUGIN_FINISH_UNIT:
+       case PLUGIN_PRE_GENERICIZE:
+@@ -481,6 +482,7 @@
+ 	gcc_assert (event < event_last);
+       /* Fall through.  */
+       case PLUGIN_FINISH_TYPE:
++      case PLUGIN_FINISH_DECL:
+       case PLUGIN_START_UNIT:
+       case PLUGIN_FINISH_UNIT:
+       case PLUGIN_PRE_GENERICIZE:
new file mode 100644
--- /dev/null
+++ b/build/unix/build-toolchain/pr49911.diff
@@ -0,0 +1,274 @@
+diff -ru gcc-4.5.2/gcc/double-int.c gcc-4.5.2-new/gcc/double-int.c
+--- gcc-4.5.2/gcc/double-int.c	2009-11-25 05:55:54.000000000 -0500
++++ gcc-4.5.2-new/gcc/double-int.c	2011-11-29 10:20:27.625583810 -0500
+@@ -296,7 +296,12 @@
+ tree
+ double_int_to_tree (tree type, double_int cst)
+ {
+-  cst = double_int_ext (cst, TYPE_PRECISION (type), TYPE_UNSIGNED (type));
++  /* Size types *are* sign extended.  */
++  bool sign_extended_type = (!TYPE_UNSIGNED (type)
++			     || (TREE_CODE (type) == INTEGER_TYPE
++				 && TYPE_IS_SIZETYPE (type)));
++
++  cst = double_int_ext (cst, TYPE_PRECISION (type), !sign_extended_type);
+ 
+   return build_int_cst_wide (type, cst.low, cst.high);
+ }
+diff -ru gcc-4.5.2/gcc/tree.c gcc-4.5.2-new/gcc/tree.c
+--- gcc-4.5.2/gcc/tree.c	2010-07-07 11:24:27.000000000 -0400
++++ gcc-4.5.2-new/gcc/tree.c	2011-11-29 10:20:27.626583813 -0500
+@@ -9750,7 +9750,7 @@
+ tree
+ upper_bound_in_type (tree outer, tree inner)
+ {
+-  unsigned HOST_WIDE_INT lo, hi;
++  double_int high;
+   unsigned int det = 0;
+   unsigned oprec = TYPE_PRECISION (outer);
+   unsigned iprec = TYPE_PRECISION (inner);
+@@ -9797,18 +9797,18 @@
+   /* Compute 2^^prec - 1.  */
+   if (prec <= HOST_BITS_PER_WIDE_INT)
+     {
+-      hi = 0;
+-      lo = ((~(unsigned HOST_WIDE_INT) 0)
++      high.high = 0;
++      high.low = ((~(unsigned HOST_WIDE_INT) 0)
+ 	    >> (HOST_BITS_PER_WIDE_INT - prec));
+     }
+   else
+     {
+-      hi = ((~(unsigned HOST_WIDE_INT) 0)
++      high.high = ((~(unsigned HOST_WIDE_INT) 0)
+ 	    >> (2 * HOST_BITS_PER_WIDE_INT - prec));
+-      lo = ~(unsigned HOST_WIDE_INT) 0;
++      high.low = ~(unsigned HOST_WIDE_INT) 0;
+     }
+ 
+-  return build_int_cst_wide (outer, lo, hi);
++  return double_int_to_tree (outer, high);
+ }
+ 
+ /* Returns the smallest value obtainable by casting something in INNER type to
+diff -ru gcc-4.5.2/gcc/tree-vrp.c gcc-4.5.2-new/gcc/tree-vrp.c
+--- gcc-4.5.2/gcc/tree-vrp.c	2010-06-14 11:23:31.000000000 -0400
++++ gcc-4.5.2-new/gcc/tree-vrp.c	2011-11-29 10:20:27.628583820 -0500
+@@ -127,10 +127,10 @@
+ static inline tree
+ vrp_val_max (const_tree type)
+ {
+-  if (!INTEGRAL_TYPE_P (type))
+-    return NULL_TREE;
++  if (INTEGRAL_TYPE_P (type))
++    return upper_bound_in_type (CONST_CAST_TREE (type), CONST_CAST_TREE (type));
+ 
+-  return TYPE_MAX_VALUE (type);
++  return NULL_TREE;
+ }
+ 
+ /* Return the minimum value for TYPE.  */
+@@ -138,10 +138,10 @@
+ static inline tree
+ vrp_val_min (const_tree type)
+ {
+-  if (!INTEGRAL_TYPE_P (type))
+-    return NULL_TREE;
++  if (INTEGRAL_TYPE_P (type))
++    return lower_bound_in_type (CONST_CAST_TREE (type), CONST_CAST_TREE (type));
+ 
+-  return TYPE_MIN_VALUE (type);
++  return NULL_TREE;
+ }
+ 
+ /* Return whether VAL is equal to the maximum value of its type.  This
+@@ -539,7 +539,7 @@
+   set_value_range (vr, VR_RANGE, zero,
+ 		   (overflow_infinity
+ 		    ? positive_overflow_infinity (type)
+-		    : TYPE_MAX_VALUE (type)),
++		    : vrp_val_max (type)),
+ 		   vr->equiv);
+ }
+ 
+@@ -1595,7 +1595,7 @@
+     }
+   else if (cond_code == LE_EXPR || cond_code == LT_EXPR)
+     {
+-      min = TYPE_MIN_VALUE (type);
++      min = vrp_val_min (type);
+ 
+       if (limit_vr == NULL || limit_vr->type == VR_ANTI_RANGE)
+ 	max = limit;
+@@ -1630,7 +1630,7 @@
+     }
+   else if (cond_code == GE_EXPR || cond_code == GT_EXPR)
+     {
+-      max = TYPE_MAX_VALUE (type);
++      max = vrp_val_max (type);
+ 
+       if (limit_vr == NULL || limit_vr->type == VR_ANTI_RANGE)
+ 	min = limit;
+@@ -2047,11 +2047,11 @@
+ 	  || code == ROUND_DIV_EXPR)
+ 	return (needs_overflow_infinity (TREE_TYPE (res))
+ 		? positive_overflow_infinity (TREE_TYPE (res))
+-		: TYPE_MAX_VALUE (TREE_TYPE (res)));
++		: vrp_val_max (TREE_TYPE (res)));
+       else
+ 	return (needs_overflow_infinity (TREE_TYPE (res))
+ 		? negative_overflow_infinity (TREE_TYPE (res))
+-		: TYPE_MIN_VALUE (TREE_TYPE (res)));
++		: vrp_val_min (TREE_TYPE (res)));
+     }
+ 
+   return res;
+@@ -2750,8 +2750,8 @@
+ 	  && TYPE_PRECISION (inner_type) < TYPE_PRECISION (outer_type))
+ 	{
+ 	  vr0.type = VR_RANGE;
+-	  vr0.min = TYPE_MIN_VALUE (inner_type);
+-	  vr0.max = TYPE_MAX_VALUE (inner_type);
++	  vr0.min = vrp_val_min (inner_type);
++	  vr0.max = vrp_val_max (inner_type);
+ 	}
+ 
+       /* If VR0 is a constant range or anti-range and the conversion is
+@@ -2836,7 +2836,7 @@
+ 	    }
+ 	}
+       else
+-	min = TYPE_MIN_VALUE (type);
++	min = vrp_val_min (type);
+ 
+       if (is_positive_overflow_infinity (vr0.min))
+ 	max = negative_overflow_infinity (type);
+@@ -2855,7 +2855,7 @@
+ 	    }
+ 	}
+       else
+-	max = TYPE_MIN_VALUE (type);
++	max = vrp_val_min (type);
+     }
+   else if (code == NEGATE_EXPR
+ 	   && TYPE_UNSIGNED (type))
+@@ -2897,7 +2897,7 @@
+       else if (!vrp_val_is_min (vr0.min))
+ 	min = fold_unary_to_constant (code, type, vr0.min);
+       else if (!needs_overflow_infinity (type))
+-	min = TYPE_MAX_VALUE (type);
++	min = vrp_val_max (type);
+       else if (supports_overflow_infinity (type))
+ 	min = positive_overflow_infinity (type);
+       else
+@@ -2911,7 +2911,7 @@
+       else if (!vrp_val_is_min (vr0.max))
+ 	max = fold_unary_to_constant (code, type, vr0.max);
+       else if (!needs_overflow_infinity (type))
+-	max = TYPE_MAX_VALUE (type);
++	max = vrp_val_max (type);
+       else if (supports_overflow_infinity (type)
+ 	       /* We shouldn't generate [+INF, +INF] as set_value_range
+ 		  doesn't like this and ICEs.  */
+@@ -2941,7 +2941,7 @@
+ 	         TYPE_MIN_VALUE, remember -TYPE_MIN_VALUE = TYPE_MIN_VALUE.  */
+ 	      if (TYPE_OVERFLOW_WRAPS (type))
+ 		{
+-		  tree type_min_value = TYPE_MIN_VALUE (type);
++		  tree type_min_value = vrp_val_min (type);
+ 
+ 		  min = (vr0.min != type_min_value
+ 			 ? int_const_binop (PLUS_EXPR, type_min_value,
+@@ -2953,7 +2953,7 @@
+ 		  if (overflow_infinity_range_p (&vr0))
+ 		    min = negative_overflow_infinity (type);
+ 		  else
+-		    min = TYPE_MIN_VALUE (type);
++		    min = vrp_val_min (type);
+ 		}
+ 	    }
+ 	  else
+@@ -2974,7 +2974,7 @@
+ 		    }
+ 		}
+ 	      else
+-		max = TYPE_MAX_VALUE (type);
++		max = vrp_val_max (type);
+ 	    }
+ 	}
+ 
+@@ -3258,11 +3258,11 @@
+   if (POINTER_TYPE_P (type) || !TYPE_MIN_VALUE (type))
+     tmin = lower_bound_in_type (type, type);
+   else
+-    tmin = TYPE_MIN_VALUE (type);
++    tmin = vrp_val_min (type);
+   if (POINTER_TYPE_P (type) || !TYPE_MAX_VALUE (type))
+     tmax = upper_bound_in_type (type, type);
+   else
+-    tmax = TYPE_MAX_VALUE (type);
++    tmax = vrp_val_max (type);
+ 
+   if (vr->type == VR_VARYING || vr->type == VR_UNDEFINED)
+     {
+@@ -4146,8 +4146,8 @@
+   if ((comp_code == GT_EXPR || comp_code == LT_EXPR)
+       && INTEGRAL_TYPE_P (TREE_TYPE (val)))
+     {
+-      tree min = TYPE_MIN_VALUE (TREE_TYPE (val));
+-      tree max = TYPE_MAX_VALUE (TREE_TYPE (val));
++      tree min = vrp_val_min (TREE_TYPE (val));
++      tree max = vrp_val_max (TREE_TYPE (val));
+ 
+       if (comp_code == GT_EXPR
+ 	  && (!max
+@@ -6426,13 +6426,13 @@
+ 		 VARYING.  Same if the previous max value was invalid for
+ 		 the type and we'd end up with vr_result.min > vr_result.max.  */
+ 	      if (vrp_val_is_max (vr_result.max)
+-		  || compare_values (TYPE_MIN_VALUE (TREE_TYPE (vr_result.min)),
++		  || compare_values (vrp_val_min (TREE_TYPE (vr_result.min)),
+ 				     vr_result.max) > 0)
+ 		goto varying;
+ 
+ 	      if (!needs_overflow_infinity (TREE_TYPE (vr_result.min))
+ 		  || !vrp_var_may_overflow (lhs, phi))
+-		vr_result.min = TYPE_MIN_VALUE (TREE_TYPE (vr_result.min));
++		vr_result.min = vrp_val_min (TREE_TYPE (vr_result.min));
+ 	      else if (supports_overflow_infinity (TREE_TYPE (vr_result.min)))
+ 		vr_result.min =
+ 		  negative_overflow_infinity (TREE_TYPE (vr_result.min));
+@@ -6448,13 +6448,13 @@
+ 		 VARYING.  Same if the previous min value was invalid for
+ 		 the type and we'd end up with vr_result.max < vr_result.min.  */
+ 	      if (vrp_val_is_min (vr_result.min)
+-		  || compare_values (TYPE_MAX_VALUE (TREE_TYPE (vr_result.max)),
++		  || compare_values (vrp_val_max (TREE_TYPE (vr_result.max)),
+ 				     vr_result.min) < 0)
+ 		goto varying;
+ 
+ 	      if (!needs_overflow_infinity (TREE_TYPE (vr_result.max))
+ 		  || !vrp_var_may_overflow (lhs, phi))
+-		vr_result.max = TYPE_MAX_VALUE (TREE_TYPE (vr_result.max));
++		vr_result.max = vrp_val_max (TREE_TYPE (vr_result.max));
+ 	      else if (supports_overflow_infinity (TREE_TYPE (vr_result.max)))
+ 		vr_result.max =
+ 		  positive_overflow_infinity (TREE_TYPE (vr_result.max));
+@@ -6782,7 +6782,7 @@
+     {
+       /* This should not be negative infinity; there is no overflow
+ 	 here.  */
+-      min = TYPE_MIN_VALUE (TREE_TYPE (op0));
++      min = vrp_val_min (TREE_TYPE (op0));
+ 
+       max = op1;
+       if (cond_code == LT_EXPR && !is_overflow_infinity (max))
+@@ -6797,7 +6797,7 @@
+     {
+       /* This should not be positive infinity; there is no overflow
+ 	 here.  */
+-      max = TYPE_MAX_VALUE (TREE_TYPE (op0));
++      max = vrp_val_max (TREE_TYPE (op0));
+ 
+       min = op1;
+       if (cond_code == GT_EXPR && !is_overflow_infinity (min))
new file mode 100644
--- /dev/null
+++ b/build/unix/build-toolchain/r159628-r163231-r171807.patch
@@ -0,0 +1,98 @@
+diff -ru gcc-4.5.2/libstdc++-v3/include/bits/stl_pair.h gcc-4.5.2-new/libstdc++-v3/include/bits/stl_pair.h
+--- gcc-4.5.2/libstdc++-v3/include/bits/stl_pair.h	2010-06-10 06:26:14.000000000 -0400
++++ gcc-4.5.2-new/libstdc++-v3/include/bits/stl_pair.h	2011-11-29 10:25:51.203597393 -0500
+@@ -88,6 +88,8 @@
+       : first(__a), second(__b) { }
+ 
+ #ifdef __GXX_EXPERIMENTAL_CXX0X__
++      pair(const pair&) = default;
++
+       // DR 811.
+       template<class _U1, class = typename
+ 	       std::enable_if<std::is_convertible<_U1, _T1>::value>::type>
+@@ -131,6 +133,15 @@
+ 
+       template<class _U1, class _U2>
+         pair&
++        operator=(const pair<_U1, _U2>& __p)
++	{
++	  first = __p.first;
++	  second = __p.second;
++	  return *this;
++	}
++
++      template<class _U1, class _U2>
++        pair&
+         operator=(pair<_U1, _U2>&& __p)
+ 	{
+ 	  first = std::move(__p.first);
+diff -ru gcc-4.5.2/libstdc++-v3/include/bits/stl_queue.h gcc-4.5.2-new/libstdc++-v3/include/bits/stl_queue.h
+--- gcc-4.5.2/libstdc++-v3/include/bits/stl_queue.h	2010-02-04 13:20:34.000000000 -0500
++++ gcc-4.5.2-new/libstdc++-v3/include/bits/stl_queue.h	2011-11-29 10:26:22.511695475 -0500
+@@ -1,6 +1,6 @@
+ // Queue implementation -*- C++ -*-
+ 
+-// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
++// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ // Free Software Foundation, Inc.
+ //
+ // This file is part of the GNU ISO C++ Library.  This library is free
+@@ -137,16 +137,6 @@
+       explicit
+       queue(_Sequence&& __c = _Sequence())
+       : c(std::move(__c)) { }
+-
+-      queue(queue&& __q)
+-      : c(std::move(__q.c)) { }
+-
+-      queue&
+-      operator=(queue&& __q)
+-      {
+-	c = std::move(__q.c);
+-	return *this;
+-      }
+ #endif
+ 
+       /**
+@@ -451,17 +441,6 @@
+ 	  c.insert(c.end(), __first, __last);
+ 	  std::make_heap(c.begin(), c.end(), comp);
+ 	}
+-
+-      priority_queue(priority_queue&& __pq)
+-      : c(std::move(__pq.c)), comp(std::move(__pq.comp)) { }
+-
+-      priority_queue&
+-      operator=(priority_queue&& __pq)
+-      {
+-	c = std::move(__pq.c);
+-	comp = std::move(__pq.comp);
+-	return *this;
+-      }
+ #endif
+ 
+       /**
+diff -ru gcc-4.5.2/libstdc++-v3/libsupc++/exception_ptr.h gcc-4.5.2-new/libstdc++-v3/libsupc++/exception_ptr.h
+--- gcc-4.5.2/libstdc++-v3/libsupc++/exception_ptr.h	2009-11-09 17:09:30.000000000 -0500
++++ gcc-4.5.2-new/libstdc++-v3/libsupc++/exception_ptr.h	2011-11-29 10:26:10.878659023 -0500
+@@ -129,7 +129,7 @@
+       operator==(const exception_ptr&, const exception_ptr&) throw() 
+       __attribute__ ((__pure__));
+ 
+-      const type_info*
++      const class type_info*
+       __cxa_exception_type() const throw() __attribute__ ((__pure__));
+     };
+ 
+diff -ru gcc-4.5.2/libstdc++-v3/libsupc++/nested_exception.h gcc-4.5.2-new/libstdc++-v3/libsupc++/nested_exception.h
+--- gcc-4.5.2/libstdc++-v3/libsupc++/nested_exception.h	2010-02-18 12:20:16.000000000 -0500
++++ gcc-4.5.2-new/libstdc++-v3/libsupc++/nested_exception.h	2011-11-29 10:26:10.879659026 -0500
+@@ -119,7 +119,7 @@
+   // with a type that has an accessible nested_exception base.
+   template<typename _Ex>
+     inline void
+-    __throw_with_nested(_Ex&& __ex, const nested_exception* = 0)
++    __throw_with_nested(_Ex&& __ex, const nested_exception*)
+     { throw __ex; }
+ 
+   template<typename _Ex>
--- a/config/config.mk
+++ b/config/config.mk
@@ -773,18 +773,18 @@ OPTIMIZE_JARS_CMD = $(PYTHON) $(call cor
 CREATE_PRECOMPLETE_CMD = $(PYTHON) $(call core_abspath,$(topsrcdir)/config/createprecomplete.py)
 
 EXPAND_LIBS = $(PYTHON) -I$(DEPTH)/config $(topsrcdir)/config/expandlibs.py
 EXPAND_LIBS_EXEC = $(PYTHON) $(topsrcdir)/config/pythonpath.py -I$(DEPTH)/config $(topsrcdir)/config/expandlibs_exec.py
 EXPAND_LIBS_GEN = $(PYTHON) $(topsrcdir)/config/pythonpath.py -I$(DEPTH)/config $(topsrcdir)/config/expandlibs_gen.py
 EXPAND_AR = $(EXPAND_LIBS_EXEC) --extract -- $(AR)
 EXPAND_CC = $(EXPAND_LIBS_EXEC) --uselist -- $(CC)
 EXPAND_CCC = $(EXPAND_LIBS_EXEC) --uselist -- $(CCC)
-EXPAND_LD = $(EXPAND_LIBS_EXEC) --uselist -- $(LD)
-EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) --uselist -- $(MKSHLIB)
+EXPAND_LD = $(EXPAND_LIBS_EXEC) --uselist $(if $(REORDER),--reorder $(REORDER))-- $(LD)
+EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) --uselist $(if $(REORDER),--reorder $(REORDER))-- $(MKSHLIB)
 
 ifdef STDCXX_COMPAT
 CHECK_STDCXX = objdump -p $(1) | grep -e 'GLIBCXX_3\.4\.\(9\|[1-9][0-9]\)' > /dev/null && echo "TEST-UNEXPECTED-FAIL | | We don't want these libstdc++ symbols to be used:" && objdump -T $(1) | grep -e 'GLIBCXX_3\.4\.\(9\|[1-9][0-9]\)' && exit 1 || exit 0
 endif
 
 # autoconf.mk sets OBJ_SUFFIX to an error to avoid use before including
 # this file
 OBJ_SUFFIX := $(_OBJ_SUFFIX)
--- a/config/expandlibs_exec.py
+++ b/config/expandlibs_exec.py
@@ -43,16 +43,20 @@ With the --extract argument (useful for 
 from static libraries (or use those listed in library descriptors directly).
 
 With the --uselist argument (useful for e.g. $(CC)), it replaces all object
 files with a list file. This can be used to avoid limitations in the length
 of a command line. The kind of list file format used depends on the
 EXPAND_LIBS_LIST_STYLE variable: 'list' for MSVC style lists (@file.list)
 or 'linkerscript' for GNU ld linker scripts.
 See https://bugzilla.mozilla.org/show_bug.cgi?id=584474#c59 for more details.
+
+With the --reorder argument, followed by a file name, it will reorder the
+object files from the command line according to the order given in the file.
+Implies --extract.
 '''
 from __future__ import with_statement
 import sys
 import os
 from expandlibs import ExpandArgs, relativize
 import expandlibs_config as conf
 from optparse import OptionParser
 import subprocess
@@ -120,30 +124,51 @@ class ExpandArgsMore(ExpandArgs):
         self.tmp.append(tmp)
         f = os.fdopen(fd, "w")
         f.writelines(content)
         f.close()
         idx = self.index(objs[0])
         newlist = self[0:idx] + [ref] + [item for item in self[idx:] if item not in objs]
         self[0:] = newlist
 
+    def reorder(self, order_list):
+        '''Given a list of file names without OBJ_SUFFIX, rearrange self
+        so that the object file names it contains are ordered according to
+        that list.
+        '''
+        objs = [o for o in self if o.endswith(conf.OBJ_SUFFIX)]
+        if not objs: return
+        idx = self.index(objs[0])
+        # Keep everything before the first object, then the ordered objects,
+        # then any other objects, then any non-objects after the first object
+        objnames = dict([(os.path.splitext(os.path.basename(o))[0], o) for o in objs])
+        self[0:] = self[0:idx] + [objnames[o] for o in order_list if o in objnames] + \
+                   [o for o in objs if os.path.splitext(os.path.basename(o))[0] not in order_list] + \
+                   [x for x in self[idx:] if not x.endswith(conf.OBJ_SUFFIX)]
+
+
 def main():
     parser = OptionParser()
     parser.add_option("--extract", action="store_true", dest="extract",
         help="when a library has no descriptor file, extract it first, when possible")
     parser.add_option("--uselist", action="store_true", dest="uselist",
         help="use a list file for objects when executing a command")
     parser.add_option("--verbose", action="store_true", dest="verbose",
         help="display executed command and temporary files content")
+    parser.add_option("--reorder", dest="reorder",
+        help="reorder the objects according to the given list", metavar="FILE")
 
     (options, args) = parser.parse_args()
 
     with ExpandArgsMore(args) as args:
-        if options.extract:
+        if options.extract or options.reorder:
             args.extract()
+        if options.reorder:
+            with open(options.reorder) as file:
+                args.reorder([l.strip() for l in file.readlines()])
         if options.uselist:
             args.makelist()
 
         if options.verbose:
             print >>sys.stderr, "Executing: " + " ".join(args)
             for tmp in [f for f in args.tmp if os.path.isfile(f)]:
                 print >>sys.stderr, tmp + ":"
                 with open(tmp) as file:
--- a/config/tests/unit-expandlibs.py
+++ b/config/tests/unit-expandlibs.py
@@ -262,10 +262,33 @@ class TestExpandArgsMore(TestExpandInit)
 
             tmp = args.tmp
         # Check that all temporary files are properly removed
         self.assertEqual(True, all([not os.path.exists(f) for f in tmp]))
 
         # Restore subprocess.call
         subprocess.call = subprocess_call
 
+    def test_reorder(self):
+        '''Test object reordering'''
+        # We don't care about AR_EXTRACT testing, which is done in test_extract
+        config.AR_EXTRACT = ''
+
+        # ExpandArgsMore does the same as ExpandArgs
+        with ExpandArgsMore(['foo', '-bar'] + self.arg_files + [self.tmpfile('liby', Lib('y'))]) as args:
+            self.assertRelEqual(args, ['foo', '-bar'] + self.files + self.liby_files + self.libx_files) 
+
+            # Use an order containing object files from libraries
+            order_files = [self.libx_files[1], self.libx_files[0], self.liby_files[2], self.files[1]]
+            order = [os.path.splitext(os.path.basename(f))[0] for f in order_files]
+            args.reorder(order[:2] + ['unknown'] + order[2:])
+
+            # self.files has objects at #1, #2, #4
+            self.assertRelEqual(args[:3], ['foo', '-bar'] + self.files[:1])
+            self.assertRelEqual(args[3:7], order_files)
+            self.assertRelEqual(args[7:9], [self.files[2], self.files[4]])
+            self.assertRelEqual(args[9:11], self.liby_files[:2])
+            self.assertRelEqual(args[11:12], [self.libx_files[2]])
+            self.assertRelEqual(args[12:14], [self.files[3], self.files[5]])
+            self.assertRelEqual(args[14:], [self.liby_files[3]])
+
 if __name__ == '__main__':
     unittest.main(testRunner=MozTestRunner())
--- a/configure.in
+++ b/configure.in
@@ -4904,17 +4904,19 @@ cairo-android)
     AC_DEFINE(MOZ_WIDGET_ANDROID)
     AC_DEFINE(MOZ_TOUCH)
     MOZ_WIDGET_TOOLKIT=android
     TK_CFLAGS='$(MOZ_CAIRO_CFLAGS)'
     TK_LIBS='$(MOZ_CAIRO_LIBS)'
     MOZ_WEBGL=1
     MOZ_PDF_PRINTING=1
     MOZ_INSTRUMENT_EVENT_LOOP=1
-    MOZ_OLD_LINKER=1
+    if test "$MOZ_BUILD_APP" = "mobile/xul"; then
+        MOZ_OLD_LINKER=1
+    fi
     MOZ_TOUCH=1
     ;;
 
 cairo-gonk)
     AC_DEFINE(MOZ_WIDGET_GONK)
     MOZ_WIDGET_TOOLKIT=gonk
     TK_CFLAGS='$(MOZ_CAIRO_CFLAGS)'
     TK_LIBS='$(MOZ_CAIRO_LIBS)'
@@ -7154,16 +7156,19 @@ elif test "${OS_TARGET}" = "WINNT" -o "$
   MOZ_GLUE_LDFLAGS='$(call EXPAND_LIBNAME_PATH,mozglue,$(LIBXUL_DIST)/lib)'
 else
   dnl On other Unix systems, we only want to link executables against mozglue
   MOZ_GLUE_PROGRAM_LDFLAGS='$(MKSHLIB_FORCE_ALL) $(call EXPAND_LIBNAME_PATH,mozglue,$(LIBXUL_DIST)/lib) $(MKSHLIB_UNFORCE_ALL)'
   if test -n "$GNU_CC"; then
     dnl And we need mozglue symbols to be exported.
     MOZ_GLUE_PROGRAM_LDFLAGS="$MOZ_GLUE_PROGRAM_LDFLAGS -rdynamic"
   fi
+  if test "$MOZ_LINKER" = 1; then
+    MOZ_GLUE_PROGRAM_LDFLAGS="$MOZ_GLUE_PROGRAM_LDFLAGS $ZLIB_LIBS"
+  fi
 fi
 
 if test -z "$MOZ_MEMORY"; then
   case "${target}" in
     *-mingw*)
       if test -z "$WIN32_REDIST_DIR" -a -z "$MOZ_DEBUG"; then
         AC_MSG_WARN([When not building jemalloc, you need to set WIN32_REDIST_DIR to the path to the Visual C++ Redist (usually VCINSTALLDIR\redist\x86\Microsoft.VC80.CRT, for VC++ v8) if you intend to distribute your build.])
       fi
@@ -9043,17 +9048,27 @@ if test -z "$MOZ_NATIVE_NSPR"; then
         ac_configure_args="$ac_configure_args --disable-optimize"
     fi
     if test -n "$HAVE_64BIT_OS"; then
         ac_configure_args="$ac_configure_args --enable-64bit"
     fi
     if test -n "$USE_ARM_KUSER"; then
         ac_configure_args="$ac_configure_args --with-arm-kuser"
     fi
+    if test -n "$MOZ_LINKER" -a -z "$MOZ_OLD_LINKER" -a $ac_cv_func_dladdr = no ; then
+      # dladdr is supported by the new linker, even when the system linker doesn't
+      # support it. Trick nspr into using dladdr when it's not supported.
+      _SAVE_CPPFLAGS="$CPPFLAGS"
+      export CPPFLAGS="-include $_topsrcdir/mozglue/linker/dladdr.h $CPPFLAGS"
+    fi
     AC_OUTPUT_SUBDIRS(nsprpub)
+    if test -n "$MOZ_LINKER" -a -z "$MOZ_OLD_LINKER" -a $ac_cv_func_dladdr = no; then
+      unset CPPFLAGS
+      CPPFLAGS="$_SAVE_CFLAGS"
+    fi
     ac_configure_args="$_SUBDIR_CONFIG_ARGS"
 fi
 
 if test -z "$MOZ_NATIVE_NSPR"; then
     # Hack to deal with the fact that we use NSPR_CFLAGS everywhere
     AC_MSG_WARN([Recreating autoconf.mk with updated nspr-config output])
     if test "$OS_ARCH" != "WINNT"; then
        NSPR_LIBS=`./nsprpub/config/nspr-config --prefix=$LIBXUL_DIST --exec-prefix=$MOZ_BUILD_ROOT/dist --libdir=$LIBXUL_DIST/lib --libs`
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -74,19 +74,24 @@ static fp_except_t oldmask = fpsetmask(~
 #include "nsIScriptGlobalObject.h"
 #include "nsIDOMEvent.h"
 #include "nsTArray.h"
 #include "nsTextFragment.h"
 #include "nsReadableUtils.h"
 #include "nsINode.h"
 #include "nsHashtable.h"
 #include "nsIDOMNode.h"
-#include "nsHtml5Parser.h"
+#include "nsHtml5StringParser.h"
+#include "nsIParser.h"
+#include "nsIDocument.h"
 #include "nsIFragmentContentSink.h"
+#include "nsContentSink.h"
 #include "nsMathUtils.h"
+#include "nsThreadUtils.h"
+#include "nsIContent.h"
 #include "nsCharSeparatedTokenizer.h"
 
 #include "mozilla/AutoRestore.h"
 #include "mozilla/GuardObjects.h"
 #include "mozilla/TimeStamp.h"
 
 struct nsNativeKeyEvent; // Don't include nsINativeKeyBindings.h here: it will force strange compilation error!
 
@@ -1039,17 +1044,18 @@ public:
    * @param aTargetNode the target container
    * @param aContextLocalName local name of context node
    * @param aContextNamespace namespace of context node
    * @param aQuirks true to make <table> not close <p>
    * @param aPreventScriptExecution true to prevent scripts from executing;
    *        don't set to false when parsing into a target node that has been
    *        bound to tree.
    * @return NS_ERROR_DOM_INVALID_STATE_ERR if a re-entrant attempt to parse
-   *         fragments is made and NS_OK otherwise.
+   *         fragments is made, NS_ERROR_OUT_OF_MEMORY if aSourceBuffer is too
+   *         long and NS_OK otherwise.
    */
   static nsresult ParseFragmentHTML(const nsAString& aSourceBuffer,
                                     nsIContent* aTargetNode,
                                     nsIAtom* aContextLocalName,
                                     PRInt32 aContextNamespace,
                                     bool aQuirks,
                                     bool aPreventScriptExecution);
 
@@ -1066,16 +1072,30 @@ public:
    */
   static nsresult ParseFragmentXML(const nsAString& aSourceBuffer,
                                    nsIDocument* aDocument,
                                    nsTArray<nsString>& aTagStack,
                                    bool aPreventScriptExecution,
                                    nsIDOMDocumentFragment** aReturn);
 
   /**
+   * Parse a string into a document using the HTML parser.
+   * Script elements are marked unexecutable.
+   *
+   * @param aSourceBuffer the string to parse as an HTML document
+   * @param aTargetDocument the document object to parse into. Must not have
+   *                        child nodes.
+   * @return NS_ERROR_DOM_INVALID_STATE_ERR if a re-entrant attempt to parse
+   *         fragments is made, NS_ERROR_OUT_OF_MEMORY if aSourceBuffer is too
+   *         long and NS_OK otherwise.
+   */
+  static nsresult ParseDocumentHTML(const nsAString& aSourceBuffer,
+                                    nsIDocument* aTargetDocument);
+
+  /**
    * Creates a new XML document, which is marked to be loaded as data.
    *
    * @param aNamespaceURI Namespace for the root element to create and insert in
    *                      the document. Only used if aQualifiedName is not
    *                      empty.
    * @param aQualifiedName Qualified name for the root element to create and
    *                       insert in the document. If empty no root element will
    *                       be created.
@@ -1934,17 +1954,17 @@ private:
 
   static bool sIsHandlingKeyBoardEvent;
   static bool sAllowXULXBL_for_file;
   static bool sIsFullScreenApiEnabled;
   static bool sTrustedFullScreenOnly;
   static bool sFullScreenKeyInputRestricted;
   static PRUint32 sHandlingInputTimeout;
 
-  static nsHtml5Parser* sHTMLFragmentParser;
+  static nsHtml5StringParser* sHTMLFragmentParser;
   static nsIParser* sXMLFragmentParser;
   static nsIFragmentContentSink* sXMLFragmentSink;
 
   /**
    * True if there's a fragment parser activation on the stack.
    */
   static bool sFragmentParsingActive;
 
--- a/content/base/public/nsIScriptElement.h
+++ b/content/base/public/nsIScriptElement.h
@@ -44,18 +44,18 @@
 #include "nsCOMPtr.h"
 #include "nsIScriptLoaderObserver.h"
 #include "nsWeakPtr.h"
 #include "nsIParser.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsIDOMHTMLScriptElement.h"
 
 #define NS_ISCRIPTELEMENT_IID \
-{ 0x5bb3b905, 0x5988, 0x476f, \
-  { 0x95, 0x4f, 0x99, 0x02, 0x59, 0x82, 0x24, 0x67 } }
+{ 0x24ab3ff2, 0xd75e, 0x4be4, \
+  { 0x8d, 0x50, 0xd6, 0x75, 0x31, 0x29, 0xab, 0x65 } }
 
 /**
  * Internal interface implemented by script elements
  */
 class nsIScriptElement : public nsIScriptLoaderObserver {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTELEMENT_IID)
 
@@ -182,16 +182,38 @@ public:
   }
 
   void SetCreatorParser(nsIParser* aParser)
   {
     mCreatorParser = getter_AddRefs(NS_GetWeakReference(aParser));
   }
 
   /**
+   * Unblocks the creator parser
+   */
+  void UnblockParser()
+  {
+    nsCOMPtr<nsIParser> parser = do_QueryReferent(mCreatorParser);
+    if (parser) {
+      parser->UnblockParser();
+    }
+  }
+
+  /**
+   * Attempts to resume parsing asynchronously
+   */
+  void ContinueParserAsync()
+  {
+    nsCOMPtr<nsIParser> parser = do_QueryReferent(mCreatorParser);
+    if (parser) {
+      parser->ContinueInterruptedParsingAsync();
+    }
+  }
+
+  /**
    * Informs the creator parser that the evaluation of this script is starting
    */
   void BeginEvaluating()
   {
     nsCOMPtr<nsIParser> parser = do_QueryReferent(mCreatorParser);
     if (parser) {
       parser->BeginEvaluatingParserInsertedScript();
     }
--- a/content/base/src/mozSanitizingSerializer.h
+++ b/content/base/src/mozSanitizingSerializer.h
@@ -98,17 +98,17 @@ public:
 
   NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument,
                                  nsAString& aStr);
 
   // nsIContentSink
   NS_IMETHOD WillParse(void) { return NS_OK; }
   NS_IMETHOD WillInterrupt(void) { return NS_OK; }
   NS_IMETHOD WillResume(void) { return NS_OK; }
-  NS_IMETHOD SetParser(nsIParser* aParser) { return NS_OK; }
+  NS_IMETHOD SetParser(nsParserBase* aParser) { return NS_OK; }
   NS_IMETHOD OpenContainer(const nsIParserNode& aNode);
   NS_IMETHOD CloseContainer(const nsHTMLTag aTag);
   NS_IMETHOD AddLeaf(const nsIParserNode& aNode);
   NS_IMETHOD AddComment(const nsIParserNode& aNode) { return NS_OK; }
   NS_IMETHOD AddProcessingInstruction(const nsIParserNode& aNode)
                                                     { return NS_OK; }
   NS_IMETHOD AddDocTypeDecl(const nsIParserNode& aNode);
   virtual void FlushPendingNotifications(mozFlushType aType) { }
--- a/content/base/src/nsContentSink.cpp
+++ b/content/base/src/nsContentSink.cpp
@@ -104,98 +104,44 @@
 #include "nsISupportsPrimitives.h"
 #include "mozilla/Preferences.h"
 #include "nsParserConstants.h"
 
 using namespace mozilla;
 
 PRLogModuleInfo* gContentSinkLogModuleInfo;
 
-class nsScriptLoaderObserverProxy : public nsIScriptLoaderObserver
-{
-public:
-  nsScriptLoaderObserverProxy(nsIScriptLoaderObserver* aInner)
-    : mInner(do_GetWeakReference(aInner))
-  {
-  }
-  virtual ~nsScriptLoaderObserverProxy()
-  {
-  }
-  
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSISCRIPTLOADEROBSERVER
-
-  nsWeakPtr mInner;
-};
-
-NS_IMPL_ISUPPORTS1(nsScriptLoaderObserverProxy, nsIScriptLoaderObserver)
-
-NS_IMETHODIMP
-nsScriptLoaderObserverProxy::ScriptAvailable(nsresult aResult,
-                                             nsIScriptElement *aElement,
-                                             bool aIsInline,
-                                             nsIURI *aURI,
-                                             PRInt32 aLineNo)
-{
-  nsCOMPtr<nsIScriptLoaderObserver> inner = do_QueryReferent(mInner);
-
-  if (inner) {
-    return inner->ScriptAvailable(aResult, aElement, aIsInline, aURI,
-                                  aLineNo);
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsScriptLoaderObserverProxy::ScriptEvaluated(nsresult aResult,
-                                             nsIScriptElement *aElement,
-                                             bool aIsInline)
-{
-  nsCOMPtr<nsIScriptLoaderObserver> inner = do_QueryReferent(mInner);
-
-  if (inner) {
-    return inner->ScriptEvaluated(aResult, aElement, aIsInline);
-  }
-
-  return NS_OK;
-}
-
-
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsContentSink)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsContentSink)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsContentSink)
   NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
-  NS_INTERFACE_MAP_ENTRY(nsIScriptLoaderObserver)
   NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver)
   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
   NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIScriptLoaderObserver)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocumentObserver)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsContentSink)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsContentSink)
   if (tmp->mDocument) {
     tmp->mDocument->RemoveObserver(tmp);
   }
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mParser)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mNodeInfoManager)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mScriptLoader)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mScriptElements)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsContentSink)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocument)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mParser)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mNodeInfoManager,
                                                   nsNodeInfoManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptLoader)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mScriptElements)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 
 nsContentSink::nsContentSink()
 {
   // We have a zeroing operator new
   NS_ASSERTION(!mLayoutStarted, "What?");
   NS_ASSERTION(!mDynamicLowerValue, "What?");
@@ -230,17 +176,16 @@ PRInt32 nsContentSink::sInteractiveDefle
 PRInt32 nsContentSink::sPerfDeflectCount;
 PRInt32 nsContentSink::sPendingEventMode;
 PRInt32 nsContentSink::sEventProbeRate;
 PRInt32 nsContentSink::sInteractiveParseTime;
 PRInt32 nsContentSink::sPerfParseTime;
 PRInt32 nsContentSink::sInteractiveTime;
 PRInt32 nsContentSink::sInitialPerfTime;
 PRInt32 nsContentSink::sEnablePerfMode;
-bool    nsContentSink::sCanInterruptParser;
 
 void
 nsContentSink::InitializeStatics()
 {
   Preferences::AddBoolVarCache(&sNotifyOnTimer,
                                "content.notify.ontimer", true);
   // -1 means never.
   Preferences::AddIntVarCache(&sBackoffCount,
@@ -267,18 +212,16 @@ nsContentSink::InitializeStatics()
   Preferences::AddIntVarCache(&sPerfParseTime,
                               "content.sink.perf_parse_time", 360000);
   Preferences::AddIntVarCache(&sInteractiveTime,
                               "content.sink.interactive_time", 750000);
   Preferences::AddIntVarCache(&sInitialPerfTime,
                               "content.sink.initial_perf_time", 2000000);
   Preferences::AddIntVarCache(&sEnablePerfMode,
                               "content.sink.enable_perf_mode", 0);
-  Preferences::AddBoolVarCache(&sCanInterruptParser,
-                               "content.interrupt.parsing", true);
 }
 
 nsresult
 nsContentSink::Init(nsIDocument* aDoc,
                     nsIURI* aURI,
                     nsISupports* aContainer,
                     nsIChannel* aChannel)
 {
@@ -290,58 +233,47 @@ nsContentSink::Init(nsIDocument* aDoc,
   }
 
   mDocument = aDoc;
 
   mDocumentURI = aURI;
   mDocShell = do_QueryInterface(aContainer);
   mScriptLoader = mDocument->ScriptLoader();
 
-  if (!mFragmentMode) {
+  if (!mRunsToCompletion) {
     if (mDocShell) {
       PRUint32 loadType = 0;
       mDocShell->GetLoadType(&loadType);
       mDocument->SetChangeScrollPosWhenScrollingToRef(
         (loadType & nsIDocShell::LOAD_CMD_HISTORY) == 0);
     }
 
-    // use this to avoid a circular reference sink->document->scriptloader->sink
-    nsCOMPtr<nsIScriptLoaderObserver> proxy =
-      new nsScriptLoaderObserverProxy(this);
-    NS_ENSURE_TRUE(proxy, NS_ERROR_OUT_OF_MEMORY);
-
-    mScriptLoader->AddObserver(proxy);
-
     ProcessHTTPHeaders(aChannel);
   }
 
   mCSSLoader = aDoc->CSSLoader();
 
   mNodeInfoManager = aDoc->NodeInfoManager();
 
   mBackoffCount = sBackoffCount;
 
   if (sEnablePerfMode != 0) {
     mDynamicLowerValue = sEnablePerfMode == 1;
     FavorPerformanceHint(!mDynamicLowerValue, 0);
   }
 
-  // prevent DropParserAndPerfHint from unblocking onload in the fragment
-  // case
-  mCanInterruptParser = !mFragmentMode && sCanInterruptParser;
-
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsContentSink::StyleSheetLoaded(nsCSSStyleSheet* aSheet,
                                 bool aWasAlternate,
                                 nsresult aStatus)
 {
-  NS_ASSERTION(!mFragmentMode, "How come a fragment parser observed sheets?");
+  NS_ASSERTION(!mRunsToCompletion, "How come a fragment parser observed sheets?");
   if (!aWasAlternate) {
     NS_ASSERTION(mPendingSheetCount > 0, "How'd that happen?");
     --mPendingSheetCount;
 
     if (mPendingSheetCount == 0 &&
         (mDeferredLayoutStart || mDeferredFlushTags)) {
       if (mDeferredFlushTags) {
         FlushTags();
@@ -361,100 +293,16 @@ nsContentSink::StyleSheetLoaded(nsCSSSty
     }
     
     mScriptLoader->RemoveExecuteBlocker();
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsContentSink::ScriptAvailable(nsresult aResult,
-                               nsIScriptElement *aElement,
-                               bool aIsInline,
-                               nsIURI *aURI,
-                               PRInt32 aLineNo)
-{
-  PRUint32 count = mScriptElements.Count();
-
-  // aElement will not be in mScriptElements if a <script> was added
-  // using the DOM during loading or if DoneAddingChildren did not return
-  // NS_ERROR_HTMLPARSER_BLOCK.
-  NS_ASSERTION(count == 0 ||
-               mScriptElements.IndexOf(aElement) == PRInt32(count - 1) ||
-               mScriptElements.IndexOf(aElement) == -1,
-               "script found at unexpected position");
-
-  // Check if this is the element we were waiting for
-  if (count == 0 || aElement != mScriptElements[count - 1]) {
-    return NS_OK;
-  }
-
-  NS_ASSERTION(!aElement->GetScriptDeferred(), "defer script was in mScriptElements");
-  NS_ASSERTION(!aElement->GetScriptAsync(), "async script was in mScriptElements");
-
-  if (mParser && !mParser->IsParserEnabled()) {
-    // make sure to unblock the parser before evaluating the script,
-    // we must unblock the parser even if loading the script failed or
-    // if the script was empty, if we don't, the parser will never be
-    // unblocked.
-    mParser->UnblockParser();
-  }
-
-  if (NS_SUCCEEDED(aResult)) {
-    PreEvaluateScript();
-  } else {
-    mScriptElements.RemoveObjectAt(count - 1);
-
-    if (mParser && aResult != NS_BINDING_ABORTED) {
-      // Loading external script failed!. So, resume parsing since the parser
-      // got blocked when loading external script. See
-      // http://bugzilla.mozilla.org/show_bug.cgi?id=94903.
-      //
-      // XXX We don't resume parsing if we get NS_BINDING_ABORTED from the
-      //     script load, assuming that that error code means that the user
-      //     stopped the load through some action (like clicking a link). See
-      //     http://bugzilla.mozilla.org/show_bug.cgi?id=243392.
-      ContinueInterruptedParsingAsync();
-    }
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsContentSink::ScriptEvaluated(nsresult aResult,
-                               nsIScriptElement *aElement,
-                               bool aIsInline)
-{
-  mDeflectedCount = sPerfDeflectCount;
-
-  // Check if this is the element we were waiting for
-  PRInt32 count = mScriptElements.Count();
-  if (count == 0 || aElement != mScriptElements[count - 1]) {
-    return NS_OK;
-  }
-
-  NS_ASSERTION(!aElement->GetScriptDeferred(), "defer script was in mScriptElements");
-  NS_ASSERTION(!aElement->GetScriptAsync(), "async script was in mScriptElements");
-
-  // Pop the script element stack
-  mScriptElements.RemoveObjectAt(count - 1); 
-
-  if (NS_SUCCEEDED(aResult)) {
-    PostEvaluateScript(aElement);
-  }
-
-  if (mParser && mParser->IsParserEnabled()) {
-    ContinueInterruptedParsingAsync();
-  }
-
-  return NS_OK;
-}
-
 nsresult
 nsContentSink::ProcessHTTPHeaders(nsIChannel* aChannel)
 {
   nsCOMPtr<nsIHttpChannel> httpchannel(do_QueryInterface(aChannel));
   
   if (!httpchannel) {
     return NS_OK;
   }
@@ -879,20 +727,20 @@ nsContentSink::ProcessStyleLink(nsIConte
   if (NS_FAILED(rv)) {
     // The URI is bad, move along, don't propagate the error (for now)
     return NS_OK;
   }
 
   // If this is a fragment parser, we don't want to observe.
   bool isAlternate;
   rv = mCSSLoader->LoadStyleLink(aElement, url, aTitle, aMedia, aAlternate,
-                                 mFragmentMode ? nsnull : this, &isAlternate);
+                                 mRunsToCompletion ? nsnull : this, &isAlternate);
   NS_ENSURE_SUCCESS(rv, rv);
   
-  if (!isAlternate && !mFragmentMode) {
+  if (!isAlternate && !mRunsToCompletion) {
     ++mPendingSheetCount;
     mScriptLoader->AddExecuteBlocker();
   }
 
   return NS_OK;
 }
 
 
@@ -1494,17 +1342,17 @@ nsContentSink::WillResumeImpl()
   mParsing = true;
 
   return NS_OK;
 }
 
 nsresult
 nsContentSink::DidProcessATokenImpl()
 {
-  if (!mCanInterruptParser || !mParser || !mParser->CanInterrupt()) {
+  if (mRunsToCompletion || !mParser) {
     return NS_OK;
   }
 
   // Get the current user event time
   nsIPresShell *shell = mDocument->GetShell();
   if (!shell) {
     // If there's no pres shell in the document, return early since
     // we're not laying anything out here.
@@ -1623,39 +1471,39 @@ nsContentSink::DropParserAndPerfHint(voi
   
   // Ref. Bug 49115
   // Do this hack to make sure that the parser
   // doesn't get destroyed, accidently, before
   // the circularity, between sink & parser, is
   // actually broken.
   // Drop our reference to the parser to get rid of a circular
   // reference.
-  nsCOMPtr<nsIParser> kungFuDeathGrip(mParser.forget());
+  nsRefPtr<nsParserBase> kungFuDeathGrip(mParser.forget());
 
   if (mDynamicLowerValue) {
     // Reset the performance hint which was set to FALSE
     // when mDynamicLowerValue was set.
     FavorPerformanceHint(true, 0);
   }
 
-  if (mCanInterruptParser) {
+  if (!mRunsToCompletion) {
     mDocument->UnblockOnload(true);
   }
 }
 
 bool
 nsContentSink::IsScriptExecutingImpl()
 {
   return !!mScriptLoader->GetCurrentScript();
 }
 
 nsresult
 nsContentSink::WillParseImpl(void)
 {
-  if (!mCanInterruptParser) {
+  if (mRunsToCompletion) {
     return NS_OK;
   }
 
   nsIPresShell *shell = mDocument->GetShell();
   if (!shell) {
     return NS_OK;
   }
 
@@ -1684,50 +1532,31 @@ nsContentSink::WillParseImpl(void)
     (mDynamicLowerValue ? sInteractiveParseTime : sPerfParseTime);
 
   return NS_OK;
 }
 
 void
 nsContentSink::WillBuildModelImpl()
 {
-  if (mCanInterruptParser) {
+  if (!mRunsToCompletion) {
     mDocument->BlockOnload();
 
     mBeginLoadTime = PR_IntervalToMicroseconds(PR_IntervalNow());
   }
 
   mDocument->ResetScrolledToRefAlready();
 
   if (mProcessLinkHeaderEvent.get()) {
     mProcessLinkHeaderEvent.Revoke();
 
     DoProcessLinkHeader();
   }
 }
 
-void
-nsContentSink::ContinueInterruptedParsingIfEnabled()
-{
-  // This shouldn't be called in the HTML5 case.
-  if (mParser && mParser->IsParserEnabled()) {
-    mParser->ContinueInterruptedParsing();
-  }
-}
-
-// Overridden in the HTML5 case
-void
-nsContentSink::ContinueInterruptedParsingAsync()
-{
-  nsCOMPtr<nsIRunnable> ev = NS_NewRunnableMethod(this,
-    &nsContentSink::ContinueInterruptedParsingIfEnabled);
-
-  NS_DispatchToCurrentThread(ev);
-}
-
 /* static */
 void
 nsContentSink::NotifyDocElementCreated(nsIDocument* aDoc)
 {
   nsCOMPtr<nsIObserverService> observerService =
     mozilla::services::GetObserverService();
   if (observerService) {
     nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDoc);
--- a/content/base/src/nsContentSink.h
+++ b/content/base/src/nsContentSink.h
@@ -41,17 +41,16 @@
  */
 
 #ifndef _nsContentSink_h_
 #define _nsContentSink_h_
 
 // Base class for contentsink implementations.
 
 #include "nsICSSLoaderObserver.h"
-#include "nsIScriptLoaderObserver.h"
 #include "nsWeakReference.h"
 #include "nsCOMPtr.h"
 #include "nsCOMArray.h"
 #include "nsString.h"
 #include "nsAutoPtr.h"
 #include "nsGkAtoms.h"
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
@@ -59,16 +58,17 @@
 #include "nsITimer.h"
 #include "nsStubDocumentObserver.h"
 #include "nsIParserService.h"
 #include "nsIContentSink.h"
 #include "prlog.h"
 #include "nsIRequest.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsThreadUtils.h"
+#include "nsIScriptElement.h"
 
 class nsIDocument;
 class nsIURI;
 class nsIChannel;
 class nsIDocShell;
 class nsIParser;
 class nsIAtom;
 class nsIChannel;
@@ -108,26 +108,23 @@ extern PRLogModuleInfo* gContentSinkLogM
 #undef SINK_NO_INCREMENTAL
 
 //----------------------------------------------------------------------
 
 // 1/2 second fudge factor for window creation
 #define NS_DELAY_FOR_WINDOW_CREATION  500000
 
 class nsContentSink : public nsICSSLoaderObserver,
-                      public nsIScriptLoaderObserver,
                       public nsSupportsWeakReference,
                       public nsStubDocumentObserver,
                       public nsITimerCallback
 {
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsContentSink,
-                                           nsIScriptLoaderObserver)
-  NS_DECL_NSISCRIPTLOADEROBSERVER
-
+                                           nsICSSLoaderObserver)
     // nsITimerCallback
   NS_DECL_NSITIMERCALLBACK
 
   // nsICSSLoaderObserver
   NS_IMETHOD StyleSheetLoaded(nsCSSStyleSheet* aSheet, bool aWasAlternate,
                               nsresult aStatus);
 
   virtual nsresult ProcessMETATag(nsIContent* aContent);
@@ -285,75 +282,70 @@ protected:
   {
     if (mDynamicLowerValue) {
       return 1000;
     }
 
     return sNotificationInterval;
   }
 
-  // Overridable hooks into script evaluation
-  virtual void PreEvaluateScript()                            {return;}
-  virtual void PostEvaluateScript(nsIScriptElement *aElement) {return;}
-
   virtual nsresult FlushTags() = 0;
 
   // Later on we might want to make this more involved somehow
   // (e.g. stop waiting after some timeout or whatnot).
   bool WaitForPendingSheets() { return mPendingSheetCount > 0; }
 
   void DoProcessLinkHeader();
 
+  void StopDeflecting() {
+    mDeflectedCount = sPerfDeflectCount;
+  }
+
 private:
   // People shouldn't be allocating this class directly.  All subclasses should
   // be allocated using a zeroing operator new.
   void* operator new(size_t sz) CPP_THROW_NEW;  // Not to be implemented
 
 protected:
 
-  virtual void ContinueInterruptedParsingAsync();
-  void ContinueInterruptedParsingIfEnabled();
-
   nsCOMPtr<nsIDocument>         mDocument;
-  nsCOMPtr<nsIParser>           mParser;
+  nsRefPtr<nsParserBase>        mParser;
   nsCOMPtr<nsIURI>              mDocumentURI;
   nsCOMPtr<nsIDocShell>         mDocShell;
   nsRefPtr<mozilla::css::Loader> mCSSLoader;
   nsRefPtr<nsNodeInfoManager>   mNodeInfoManager;
   nsRefPtr<nsScriptLoader>      mScriptLoader;
 
-  nsCOMArray<nsIScriptElement> mScriptElements;
-
   // back off timer notification after count
   PRInt32 mBackoffCount;
 
   // Time of last notification
   // Note: mLastNotificationTime is only valid once mLayoutStarted is true.
   PRTime mLastNotificationTime;
 
   // Timer used for notification
   nsCOMPtr<nsITimer> mNotificationTimer;
 
   // Have we already called BeginUpdate for this set of content changes?
   PRUint8 mBeganUpdate : 1;
   PRUint8 mLayoutStarted : 1;
-  PRUint8 mCanInterruptParser : 1;
   PRUint8 mDynamicLowerValue : 1;
   PRUint8 mParsing : 1;
   PRUint8 mDroppedTimer : 1;
   // If true, we deferred starting layout until sheets load
   PRUint8 mDeferredLayoutStart : 1;
   // If true, we deferred notifications until sheets load
   PRUint8 mDeferredFlushTags : 1;
   // If false, we're not ourselves a document observer; that means we
   // shouldn't be performing any more content model notifications,
   // since we're not longer updating our child counts.
   PRUint8 mIsDocumentObserver : 1;
-  // True if this is a fragment parser
-  PRUint8 mFragmentMode : 1;
+  // True if this is parser is a fragment parser or an HTML DOMParser.
+  // XML DOMParser leaves this to false for now!
+  PRUint8 mRunsToCompletion : 1;
   // True to call prevent script execution in the fragment mode.
   PRUint8 mPreventScriptExecution : 1;
   
   //
   // -- Can interrupt parsing members --
   //
 
   // The number of tokens that have been processed since we measured
@@ -401,12 +393,11 @@ protected:
   static PRInt32 sInteractiveParseTime;
   static PRInt32 sPerfParseTime;
   // How long to be in interactive mode after an event
   static PRInt32 sInteractiveTime;
   // How long to stay in perf mode after initial loading
   static PRInt32 sInitialPerfTime;
   // Should we switch between perf-mode and interactive-mode
   static PRInt32 sEnablePerfMode;
-  static bool sCanInterruptParser;
 };
 
 #endif // _nsContentSink_h_
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -274,17 +274,17 @@ nsString* nsContentUtils::sModifierSepar
 
 bool nsContentUtils::sInitialized = false;
 bool nsContentUtils::sIsFullScreenApiEnabled = false;
 bool nsContentUtils::sTrustedFullScreenOnly = true;
 bool nsContentUtils::sFullScreenKeyInputRestricted = true;
 
 PRUint32 nsContentUtils::sHandlingInputTimeout = 1000;
 
-nsHtml5Parser* nsContentUtils::sHTMLFragmentParser = nsnull;
+nsHtml5StringParser* nsContentUtils::sHTMLFragmentParser = nsnull;
 nsIParser* nsContentUtils::sXMLFragmentParser = nsnull;
 nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nsnull;
 bool nsContentUtils::sFragmentParsingActive = false;
 
 static PLDHashTable sEventListenerManagersHash;
 
 class EventListenerManagerMapEntry : public PLDHashEntryHdr
 {
@@ -3658,28 +3658,47 @@ nsContentUtils::ParseFragmentHTML(const 
 {
   if (nsContentUtils::sFragmentParsingActive) {
     NS_NOTREACHED("Re-entrant fragment parsing attempted.");
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
   mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive);
   nsContentUtils::sFragmentParsingActive = true;
   if (!sHTMLFragmentParser) {
-    sHTMLFragmentParser =
-      static_cast<nsHtml5Parser*>(nsHtml5Module::NewHtml5Parser().get());
+    NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser());
     // Now sHTMLFragmentParser owns the object
   }
   nsresult rv =
-    sHTMLFragmentParser->ParseHtml5Fragment(aSourceBuffer,
-                                            aTargetNode,
-                                            aContextLocalName,
-                                            aContextNamespace,
-                                            aQuirks,
-                                            aPreventScriptExecution);
-  sHTMLFragmentParser->Reset();
+    sHTMLFragmentParser->ParseFragment(aSourceBuffer,
+                                       aTargetNode,
+                                       aContextLocalName,
+                                       aContextNamespace,
+                                       aQuirks,
+                                       aPreventScriptExecution);
+  return rv;
+}
+
+/* static */
+nsresult
+nsContentUtils::ParseDocumentHTML(const nsAString& aSourceBuffer,
+                                  nsIDocument* aTargetDocument)
+{
+  if (nsContentUtils::sFragmentParsingActive) {
+    NS_NOTREACHED("Re-entrant fragment parsing attempted.");
+    return NS_ERROR_DOM_INVALID_STATE_ERR;
+  }
+  mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive);
+  nsContentUtils::sFragmentParsingActive = true;
+  if (!sHTMLFragmentParser) {
+    NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser());
+    // Now sHTMLFragmentParser owns the object
+  }
+  nsresult rv =
+    sHTMLFragmentParser->ParseDocument(aSourceBuffer,
+                                       aTargetDocument);
   return rv;
 }
 
 /* static */
 nsresult
 nsContentUtils::ParseFragmentXML(const nsAString& aSourceBuffer,
                                  nsIDocument* aDocument,
                                  nsTArray<nsString>& aTagStack,
--- a/content/base/src/nsDOMParser.cpp
+++ b/content/base/src/nsDOMParser.cpp
@@ -38,17 +38,16 @@
 #include "jsapi.h"
 #include "nsDOMParser.h"
 #include "nsIURI.h"
 #include "nsIChannel.h"
 #include "nsILoadGroup.h"
 #include "nsIInputStream.h"
 #include "nsNetUtil.h"
 #include "nsStringStream.h"
-#include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIPrincipal.h"
 #include "nsDOMClassInfoID.h"
 #include "nsReadableUtils.h"
 #include "nsCRT.h"
 #include "nsStreamUtils.h"
 #include "nsThreadUtils.h"
@@ -90,23 +89,50 @@ NS_IMPL_RELEASE(nsDOMParser)
 NS_IMETHODIMP 
 nsDOMParser::ParseFromString(const PRUnichar *str, 
                              const char *contentType,
                              nsIDOMDocument **aResult)
 {
   NS_ENSURE_ARG(str);
   NS_ENSURE_ARG_POINTER(aResult);
 
+  nsresult rv;
+
+  if (!nsCRT::strcmp(contentType, "text/html")) {
+    nsCOMPtr<nsIDOMDocument> domDocument;
+    rv = SetUpDocument(DocumentFlavorHTML, getter_AddRefs(domDocument));
+    NS_ENSURE_SUCCESS(rv, rv);
+    nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument);
+    nsDependentString sourceBuffer(str);
+    rv = nsContentUtils::ParseDocumentHTML(sourceBuffer, document);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // Keep the XULXBL state, base URL and principal setting in sync with the
+    // XML case
+
+    if (nsContentUtils::IsSystemPrincipal(mOriginalPrincipal)) {
+      document->ForceEnableXULXBL();
+    }
+
+    // Make sure to give this document the right base URI
+    document->SetBaseURI(mBaseURI);
+    // And the right principal
+    document->SetPrincipal(mPrincipal);
+
+    domDocument.forget(aResult);
+    return rv;
+  }
+
   NS_ConvertUTF16toUTF8 data(str);
 
   // The new stream holds a reference to the buffer
   nsCOMPtr<nsIInputStream> stream;
-  nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream),
-                                      data.get(), data.Length(),
-                                      NS_ASSIGNMENT_DEPEND);
+  rv = NS_NewByteInputStream(getter_AddRefs(stream),
+                             data.get(), data.Length(),
+                             NS_ASSIGNMENT_DEPEND);
   if (NS_FAILED(rv))
     return rv;
 
   return ParseFromStream(stream, "UTF-8", data.Length(), contentType, aResult);
 }
 
 NS_IMETHODIMP 
 nsDOMParser::ParseFromBuffer(const PRUint8 *buf,
@@ -147,56 +173,31 @@ nsDOMParser::ParseFromStream(nsIInputStr
   //XXXsmaug Should we create an HTMLDocument (in XHTML mode)
   //         for "application/xhtml+xml"?
   if ((nsCRT::strcmp(contentType, "text/xml") != 0) &&
       (nsCRT::strcmp(contentType, "application/xml") != 0) &&
       (nsCRT::strcmp(contentType, "application/xhtml+xml") != 0) &&
       !svg)
     return NS_ERROR_NOT_IMPLEMENTED;
 
-  nsCOMPtr<nsIScriptGlobalObject> scriptHandlingObject =
-    do_QueryReferent(mScriptHandlingObject);
   nsresult rv;
-  if (!mPrincipal) {
-    NS_ENSURE_TRUE(!mAttemptedInit, NS_ERROR_NOT_INITIALIZED);
-    AttemptedInitMarker marker(&mAttemptedInit);
-    
-    nsCOMPtr<nsIPrincipal> prin =
-      do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-    
-    rv = Init(prin, nsnull, nsnull, scriptHandlingObject);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
 
-  NS_ASSERTION(mPrincipal, "Must have principal by now");
-  NS_ASSERTION(mDocumentURI, "Must have document URI by now");
-  
   // Put the nsCOMPtr out here so we hold a ref to the stream as needed
   nsCOMPtr<nsIInputStream> bufferedStream;
   if (!NS_InputStreamIsBuffered(stream)) {
     rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream), stream,
                                    4096);
     NS_ENSURE_SUCCESS(rv, rv);
 
     stream = bufferedStream;
   }
 
-  // Here we have to cheat a little bit...  Setting the base URI won't
-  // work if the document has a null principal, so use
-  // mOriginalPrincipal when creating the document, then reset the
-  // principal.
   nsCOMPtr<nsIDOMDocument> domDocument;
-  rv = nsContentUtils::CreateDocument(EmptyString(), EmptyString(), nsnull,
-                                      mDocumentURI, mBaseURI,
-                                      mOriginalPrincipal,
-                                      scriptHandlingObject,
-                                      svg ? DocumentFlavorSVG :
-                                            DocumentFlavorLegacyGuess,
-                                      getter_AddRefs(domDocument));
+  rv = SetUpDocument(svg ? DocumentFlavorSVG : DocumentFlavorLegacyGuess,
+                     getter_AddRefs(domDocument));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Create a fake channel 
   nsCOMPtr<nsIChannel> parserChannel;
   NS_NewInputStreamChannel(getter_AddRefs(parserChannel), mDocumentURI, nsnull,
                            nsDependentCString(contentType), nsnull);
   NS_ENSURE_STATE(parserChannel);
 
@@ -212,16 +213,19 @@ nsDOMParser::ParseFromStream(nsIInputStr
 
   // Have to pass false for reset here, else the reset will remove
   // our event listener.  Should that listener addition move to later
   // than this call?  Then we wouldn't need to mess around with
   // SetPrincipal, etc, probably!
   nsCOMPtr<nsIDocument> document(do_QueryInterface(domDocument));
   if (!document) return NS_ERROR_FAILURE;
 
+  // Keep the XULXBL state, base URL and principal setting in sync with the
+  // HTML case
+
   if (nsContentUtils::IsSystemPrincipal(mOriginalPrincipal)) {
     document->ForceEnableXULXBL();
   }
 
   rv = document->StartDocumentLoad(kLoadAsData, parserChannel, 
                                    nsnull, nsnull, 
                                    getter_AddRefs(listener),
                                    false);
@@ -476,8 +480,41 @@ nsDOMParser::Init(nsIPrincipal *aPrincip
 
     // We're called from JS; there better be a subject principal, really.
     NS_ENSURE_TRUE(principal, NS_ERROR_UNEXPECTED);
   }
 
   return Init(principal, aDocumentURI, aBaseURI,
               scriptContext ? scriptContext->GetGlobalObject() : nsnull);
 }
+
+nsresult
+nsDOMParser::SetUpDocument(DocumentFlavor aFlavor, nsIDOMDocument** aResult)
+{
+  nsCOMPtr<nsIScriptGlobalObject> scriptHandlingObject =
+    do_QueryReferent(mScriptHandlingObject);
+  nsresult rv;
+  if (!mPrincipal) {
+    NS_ENSURE_TRUE(!mAttemptedInit, NS_ERROR_NOT_INITIALIZED);
+    AttemptedInitMarker marker(&mAttemptedInit);
+
+    nsCOMPtr<nsIPrincipal> prin =
+      do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = Init(prin, nsnull, nsnull, scriptHandlingObject);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  NS_ASSERTION(mPrincipal, "Must have principal by now");
+  NS_ASSERTION(mDocumentURI, "Must have document URI by now");
+
+  // Here we have to cheat a little bit...  Setting the base URI won't
+  // work if the document has a null principal, so use
+  // mOriginalPrincipal when creating the document, then reset the
+  // principal.
+  return nsContentUtils::CreateDocument(EmptyString(), EmptyString(), nsnull,
+                                        mDocumentURI, mBaseURI,
+                                        mOriginalPrincipal,
+                                        scriptHandlingObject,
+                                        aFlavor,
+                                        aResult);
+}
--- a/content/base/src/nsDOMParser.h
+++ b/content/base/src/nsDOMParser.h
@@ -38,16 +38,17 @@
 #ifndef nsDOMParser_h__
 #define nsDOMParser_h__
 
 #include "nsIDOMParser.h"
 #include "nsCOMPtr.h"
 #include "nsIURI.h"
 #include "nsWeakReference.h"
 #include "nsIJSNativeInitializer.h"
+#include "nsIDocument.h"
 
 class nsDOMParser : public nsIDOMParser,
                     public nsIDOMParserJS,
                     public nsIJSNativeInitializer,
                     public nsSupportsWeakReference
 {
 public: 
   nsDOMParser();
@@ -61,16 +62,18 @@ public:
   // nsIDOMParserJS
   NS_DECL_NSIDOMPARSERJS
 
   // nsIJSNativeInitializer
   NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* cx, JSObject* obj,
                         PRUint32 argc, jsval *argv);
 
 private:
+  nsresult SetUpDocument(DocumentFlavor aFlavor, nsIDOMDocument** aResult);
+
   class AttemptedInitMarker {
   public:
     AttemptedInitMarker(bool* aAttemptedInit) :
       mAttemptedInit(aAttemptedInit)
     {}
 
     ~AttemptedInitMarker() {
       *mAttemptedInit = true;
--- a/content/base/src/nsPlainTextSerializer.h
+++ b/content/base/src/nsPlainTextSerializer.h
@@ -99,17 +99,17 @@ public:
 
   NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument,
                                  nsAString& aStr);
 
   // nsIContentSink
   NS_IMETHOD WillParse(void) { return NS_OK; }
   NS_IMETHOD WillInterrupt(void) { return NS_OK; }
   NS_IMETHOD WillResume(void) { return NS_OK; }
-  NS_IMETHOD SetParser(nsIParser* aParser) { return NS_OK; }
+  NS_IMETHOD SetParser(nsParserBase* aParser) { return NS_OK; }
   NS_IMETHOD OpenContainer(const nsIParserNode& aNode);
   NS_IMETHOD CloseContainer(const nsHTMLTag aTag);
   NS_IMETHOD AddLeaf(const nsIParserNode& aNode);
   NS_IMETHOD AddComment(const nsIParserNode& aNode) { return NS_OK; }
   NS_IMETHOD AddProcessingInstruction(const nsIParserNode& aNode) { return NS_OK; }
   NS_IMETHOD AddDocTypeDecl(const nsIParserNode& aNode) { return NS_OK; }
   virtual void FlushPendingNotifications(mozFlushType aType) { }
   NS_IMETHOD SetDocumentCharset(nsACString& aCharset) { return NS_OK; }
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -937,18 +937,19 @@ nsScriptLoader::ProcessPendingRequestsAs
 void
 nsScriptLoader::ProcessPendingRequests()
 {
   nsRefPtr<nsScriptLoadRequest> request;
   if (mParserBlockingRequest &&
       !mParserBlockingRequest->mLoading &&
       ReadyToExecuteScripts()) {
     request.swap(mParserBlockingRequest);
-    // nsContentSink::ScriptAvailable unblocks the parser
+    UnblockParser(request);
     ProcessRequest(request);
+    ContinueParserAsync(request);
   }
 
   while (ReadyToExecuteScripts() && 
          !mXSLTRequests.IsEmpty() && 
          !mXSLTRequests[0]->mLoading) {
     request.swap(mXSLTRequests[0]);
     mXSLTRequests.RemoveElementAt(0);
     ProcessRequest(request);
@@ -1164,29 +1165,42 @@ nsScriptLoader::OnStreamComplete(nsIStre
   if (NS_FAILED(rv)) {
     if (mDeferRequests.RemoveElement(request) ||
         mAsyncRequests.RemoveElement(request) ||
         mNonAsyncExternalScriptInsertedRequests.RemoveElement(request) ||
         mXSLTRequests.RemoveElement(request)) {
       FireScriptAvailable(rv, request);
     } else if (mParserBlockingRequest == request) {
       mParserBlockingRequest = nsnull;
-      // nsContentSink::ScriptAvailable unblocks the parser
+      UnblockParser(request);
       FireScriptAvailable(rv, request);
+      ContinueParserAsync(request);
     } else {
       mPreloads.RemoveElement(request, PreloadRequestComparator());
     }
   }
 
   // Process our request and/or any pending ones
   ProcessPendingRequests();
 
   return NS_OK;
 }
 
+void
+nsScriptLoader::UnblockParser(nsScriptLoadRequest* aParserBlockingRequest)
+{
+  aParserBlockingRequest->mElement->UnblockParser();
+}
+
+void
+nsScriptLoader::ContinueParserAsync(nsScriptLoadRequest* aParserBlockingRequest)
+{
+  aParserBlockingRequest->mElement->ContinueParserAsync();
+}
+
 nsresult
 nsScriptLoader::PrepareLoadedRequest(nsScriptLoadRequest* aRequest,
                                      nsIStreamLoader* aLoader,
                                      nsresult aStatus,
                                      PRUint32 aStringLen,
                                      const PRUint8* aString)
 {
   if (NS_FAILED(aStatus)) {
--- a/content/base/src/nsScriptLoader.h
+++ b/content/base/src/nsScriptLoader.h
@@ -239,16 +239,27 @@ public:
    * @param aCharset The charset parameter for the script.
    * @param aType The type parameter for the script.
    */
   virtual void PreloadURI(nsIURI *aURI, const nsAString &aCharset,
                           const nsAString &aType);
 
 private:
   /**
+   * Unblocks the creator parser of the parser-blocking scripts.
+   */
+  void UnblockParser(nsScriptLoadRequest* aParserBlockingRequest);
+
+  /**
+   * Asynchronously resumes the creator parser of the parser-blocking scripts.
+   */
+  void ContinueParserAsync(nsScriptLoadRequest* aParserBlockingRequest);
+
+
+  /**
    * Helper function to check the content policy for a given request.
    */
   static nsresult CheckContentPolicy(nsIDocument* aDocument,
                                      nsISupports *aContext,
                                      nsIURI *aURI,
                                      const nsAString &aType);
 
   /**
--- a/content/html/content/src/Makefile.in
+++ b/content/html/content/src/Makefile.in
@@ -52,16 +52,17 @@ EXPORTS		= \
 		nsClientRect.h \
 		nsHTMLDNSPrefetch.h \
 		$(NULL)
 
 CPPSRCS		= \
 		nsClientRect.cpp \
 		nsHTMLDNSPrefetch.cpp \
 		nsGenericHTMLElement.cpp \
+		nsGenericHTMLFrameElement.cpp \
 		nsFormSubmission.cpp \
 		nsTextEditorState.cpp \
 		nsHTMLElement.cpp \
 		nsHTMLAnchorElement.cpp \
 		nsHTMLAreaElement.cpp \
 		nsHTMLBRElement.cpp \
 		nsHTMLBodyElement.cpp \
 		nsHTMLButtonElement.cpp \
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -2547,19 +2547,16 @@ nsGenericHTMLElement::GetContextMenu(nsI
     element.forget(aContextMenu);
   }
 
   return NS_OK;
 }
 
 //----------------------------------------------------------------------
 
-NS_IMPL_INT_ATTR(nsGenericHTMLFrameElement, TabIndex, tabindex)
-NS_IMPL_BOOL_ATTR(nsGenericHTMLFrameElement, MozBrowser, mozbrowser)
-
 nsGenericHTMLFormElement::nsGenericHTMLFormElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo)
   , mForm(nsnull)
   , mFieldSet(nsnull)
 {
   // We should add the NS_EVENT_STATE_ENABLED bit here as needed, but
   // that depends on our type, which is not initialized yet.  So we
   // have to do this in subclasses.
@@ -2660,34 +2657,16 @@ nsGenericHTMLFormElement::GetDesiredIMES
     return nsGenericHTMLElement::GetDesiredIMEState();
   IMEState state;
   rv = imeEditor->GetPreferredIMEState(&state);
   if (NS_FAILED(rv))
     return nsGenericHTMLElement::GetDesiredIMEState();
   return state;
 }
 
-bool
-nsGenericHTMLFrameElement::IsHTMLFocusable(bool aWithMouse,
-                                           bool *aIsFocusable,
-                                           PRInt32 *aTabIndex)
-{
-  if (nsGenericHTMLElement::IsHTMLFocusable(aWithMouse, aIsFocusable, aTabIndex)) {
-    return true;
-  }
-
-  *aIsFocusable = nsContentUtils::IsSubDocumentTabbable(this);
-
-  if (!*aIsFocusable && aTabIndex) {
-    *aTabIndex = -1;
-  }
-
-  return false;
-}
-
 nsresult
 nsGenericHTMLFormElement::BindToTree(nsIDocument* aDocument,
                                      nsIContent* aParent,
                                      nsIContent* aBindingParent,
                                      bool aCompileEventHandlers)
 {
   nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
                                                  aBindingParent,
@@ -3203,343 +3182,16 @@ nsGenericHTMLFormElement::UpdateFieldSet
 void
 nsGenericHTMLFormElement::FieldSetDisabledChanged(bool aNotify)
 {
   UpdateState(aNotify);
 }
 
 //----------------------------------------------------------------------
 
-nsGenericHTMLFrameElement::~nsGenericHTMLFrameElement()
-{
-  if (mFrameLoader) {
-    mFrameLoader->Destroy();
-  }
-}
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericHTMLFrameElement)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGenericHTMLFrameElement,
-                                                  nsGenericHTMLElement)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mFrameLoader, nsIFrameLoader)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_INTERFACE_TABLE_HEAD(nsGenericHTMLFrameElement)
-  NS_INTERFACE_TABLE_INHERITED2(nsGenericHTMLFrameElement,
-                                nsIFrameLoaderOwner,
-                                nsIDOMMozBrowserFrameElement)
-  NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsGenericHTMLFrameElement)
-NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
-
-nsresult
-nsGenericHTMLFrameElement::GetContentDocument(nsIDOMDocument** aContentDocument)
-{
-  NS_PRECONDITION(aContentDocument, "Null out param");
-  *aContentDocument = nsnull;
-
-  nsCOMPtr<nsIDOMWindow> win;
-  GetContentWindow(getter_AddRefs(win));
-
-  if (!win) {
-    return NS_OK;
-  }
-
-  return win->GetDocument(aContentDocument);
-}
-
-nsresult
-nsGenericHTMLFrameElement::GetContentWindow(nsIDOMWindow** aContentWindow)
-{
-  NS_PRECONDITION(aContentWindow, "Null out param");
-  *aContentWindow = nsnull;
-
-  nsresult rv = EnsureFrameLoader();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (!mFrameLoader) {
-    return NS_OK;
-  }
-
-  bool depthTooGreat = false;
-  mFrameLoader->GetDepthTooGreat(&depthTooGreat);
-  if (depthTooGreat) {
-    // Claim to have no contentWindow
-    return NS_OK;
-  }
-  
-  nsCOMPtr<nsIDocShell> doc_shell;
-  mFrameLoader->GetDocShell(getter_AddRefs(doc_shell));
-
-  nsCOMPtr<nsPIDOMWindow> win(do_GetInterface(doc_shell));
-
-  if (!win) {
-    return NS_OK;
-  }
-
-  NS_ASSERTION(win->IsOuterWindow(),
-               "Uh, this window should always be an outer window!");
-
-  return CallQueryInterface(win, aContentWindow);
-}
-
-nsresult
-nsGenericHTMLFrameElement::EnsureFrameLoader()
-{
-  if (!GetParent() || !IsInDoc() || mFrameLoader) {
-    // If frame loader is there, we just keep it around, cached
-    return NS_OK;
-  }
-
-  mFrameLoader = nsFrameLoader::Create(this, mNetworkCreated);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsGenericHTMLFrameElement::GetFrameLoader(nsIFrameLoader **aFrameLoader)
-{
-  NS_IF_ADDREF(*aFrameLoader = mFrameLoader);
-  return NS_OK;
-}
-
-NS_IMETHODIMP_(already_AddRefed<nsFrameLoader>)
-nsGenericHTMLFrameElement::GetFrameLoader()
-{
-  nsRefPtr<nsFrameLoader> loader = mFrameLoader;
-  return loader.forget();
-}
-
-NS_IMETHODIMP
-nsGenericHTMLFrameElement::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherOwner)
-{
-  // We don't support this yet
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-nsresult
-nsGenericHTMLFrameElement::LoadSrc()
-{
-  nsresult rv = EnsureFrameLoader();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (!mFrameLoader) {
-    return NS_OK;
-  }
-
-  rv = mFrameLoader->LoadFrame();
-#ifdef DEBUG
-  if (NS_FAILED(rv)) {
-    NS_WARNING("failed to load URL");
-  }
-#endif
-
-  return rv;
-}
-
-nsresult
-nsGenericHTMLFrameElement::BindToTree(nsIDocument* aDocument,
-                                      nsIContent* aParent,
-                                      nsIContent* aBindingParent,
-                                      bool aCompileEventHandlers)
-{
-  nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
-                                                 aBindingParent,
-                                                 aCompileEventHandlers);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (aDocument) {
-    NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
-                 "Missing a script blocker!");
-    // We're in a document now.  Kick off the frame load.
-    LoadSrc();
-  }
-
-  // We're now in document and scripts may move us, so clear
-  // the mNetworkCreated flag.
-  mNetworkCreated = false;
-  return rv;
-}
-
-void
-nsGenericHTMLFrameElement::UnbindFromTree(bool aDeep, bool aNullParent)
-{
-  if (mFrameLoader) {
-    // This iframe is being taken out of the document, destroy the
-    // iframe's frame loader (doing that will tear down the window in
-    // this iframe).
-    // XXXbz we really want to only partially destroy the frame
-    // loader... we don't want to tear down the docshell.  Food for
-    // later bug.
-    mFrameLoader->Destroy();
-    mFrameLoader = nsnull;
-  }
-
-  nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
-}
-
-nsresult
-nsGenericHTMLFrameElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                                   nsIAtom* aPrefix, const nsAString& aValue,
-                                   bool aNotify)
-{
-  nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix,
-                                              aValue, aNotify);
-  NS_ENSURE_SUCCESS(rv, rv);
-  
-  if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::src) {
-    // Don't propagate error here. The attribute was successfully set, that's
-    // what we should reflect.
-    LoadSrc();
-  }
-
-  return NS_OK;
-}
-
-void
-nsGenericHTMLFrameElement::DestroyContent()
-{
-  if (mFrameLoader) {
-    mFrameLoader->Destroy();
-    mFrameLoader = nsnull;
-  }
-
-  nsGenericHTMLElement::DestroyContent();
-}
-
-nsresult
-nsGenericHTMLFrameElement::CopyInnerTo(nsGenericElement* aDest) const
-{
-  nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsIDocument* doc = aDest->OwnerDoc();
-  if (doc->IsStaticDocument() && mFrameLoader) {
-    nsGenericHTMLFrameElement* dest =
-      static_cast<nsGenericHTMLFrameElement*>(aDest);
-    nsFrameLoader* fl = nsFrameLoader::Create(dest, false);
-    NS_ENSURE_STATE(fl);
-    dest->mFrameLoader = fl;
-    static_cast<nsFrameLoader*>(mFrameLoader.get())->CreateStaticClone(fl);
-  }
-
-  return rv;
-}
-
-PRInt64
-nsGenericHTMLFrameElement::SizeOf() const
-{
-  PRInt64 size = MemoryReporter::GetBasicSize<nsGenericHTMLFrameElement,
-                                              nsGenericHTMLElement>(this);
-  // TODO: need to implement SizeOf() in nsFrameLoader, bug 672539.
-  size += mFrameLoader ? sizeof(*mFrameLoader.get()) : 0;
-  return size;
-}
-
-namespace {
-
-// GetContentStateCallbackRunnable is used by MozGetContentState to fire its callback
-// asynchronously.
-class GetContentStateCallbackRunnable : public nsRunnable
-{
-public:
-  GetContentStateCallbackRunnable(nsIDOMMozGetContentStateCallback *aCallback,
-                             nsIDOMEventTarget *aEventTarget,
-                             const nsAString &aResult)
-    : mCallback(aCallback)
-    , mEventTarget(aEventTarget)
-    , mResult(aResult)
-  {
-  }
-
-  NS_IMETHOD Run()
-  {
-    FireCallback();
-
-    // Break cycles.
-    mCallback = NULL;
-    mEventTarget = NULL;
-    return NS_OK;
-  }
-
-private:
-  void FireCallback()
-  {
-    nsCxPusher pusher;
-    if (!pusher.Push(mEventTarget)) {
-      return;
-    }
-
-    mCallback->Callback(mResult);
-  }
-
-  nsCOMPtr<nsIDOMMozGetContentStateCallback> mCallback;
-  nsCOMPtr<nsIDOMEventTarget> mEventTarget;
-  const nsString mResult;
-};
-
-} // anonymous namespace
-
-nsresult
-nsGenericHTMLFrameElement::BrowserFrameSecurityCheck()
-{
-  if (!Preferences::GetBool("dom.mozBrowserFramesEnabled")) {
-    return NS_ERROR_FAILURE;
-  }
-
-  bool browser;
-  GetMozBrowser(&browser);
-  if (!browser) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsIPrincipal *principal = NodePrincipal();
-  nsCOMPtr<nsIURI> principalURI;
-  principal->GetURI(getter_AddRefs(principalURI));
-  if (!nsContentUtils::URIIsChromeOrInPref(principalURI,
-                                           "dom.mozBrowserFramesWhitelist")) {
-    return NS_ERROR_DOM_SECURITY_ERR;
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsGenericHTMLFrameElement::MozGetContentState(const nsAString &aProperty,
-                                              nsIDOMMozGetContentStateCallback *aCallback)
-{
-  nsresult rv = BrowserFrameSecurityCheck();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (!aProperty.EqualsLiteral("location")) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsCOMPtr<nsIDOMWindow> contentWindow;
-  GetContentWindow(getter_AddRefs(contentWindow));
-  NS_ENSURE_TRUE(contentWindow, NS_ERROR_FAILURE);
-
-  nsCOMPtr<nsIDOMLocation> location;
-  rv = contentWindow->GetLocation(getter_AddRefs(location));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsAutoString href;
-  rv = location->ToString(href);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIDOMEventTarget> eventTarget =
-    do_QueryInterface(nsContentUtils::GetWindowFromCaller());
-  NS_ENSURE_TRUE(eventTarget, NS_ERROR_FAILURE);
-
-  // Asynchronously fire the callback.
-  nsRefPtr<GetContentStateCallbackRunnable> runnable =
-    new GetContentStateCallbackRunnable(aCallback, eventTarget, href);
-  NS_DispatchToMainThread(runnable);
-  return NS_OK;
-}
-
-//----------------------------------------------------------------------
-
 nsresult
 nsGenericHTMLElement::Blur()
 {
   if (!ShouldBlur(this)) {
     return NS_OK;
   }
 
   nsIDocument* doc = GetCurrentDoc();
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -37,22 +37,20 @@
  * ***** END LICENSE BLOCK ***** */
 #ifndef nsGenericHTMLElement_h___
 #define nsGenericHTMLElement_h___
 
 #include "nsMappedAttributeElement.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsINameSpaceManager.h"  // for kNameSpaceID_None
 #include "nsIFormControl.h"
-#include "nsIDOMHTMLFrameElement.h"
 #include "nsFrameLoader.h"
 #include "nsGkAtoms.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsDOMMemoryReporter.h"
-#include "nsIDOMMozBrowserFrameElement.h"
 
 class nsIDOMAttr;
 class nsIDOMEventListener;
 class nsIDOMNodeList;
 class nsIFrame;
 class nsIStyleRule;
 class nsChildContentList;
 class nsDOMCSSDeclaration;
@@ -1011,89 +1009,16 @@ protected:
 // same bit.  --bz
 
 // Make sure we have enough space for those bits
 PR_STATIC_ASSERT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 1 < 32);
 
 //----------------------------------------------------------------------
 
 /**
- * A helper class for frame elements
- */
-
-class nsGenericHTMLFrameElement : public nsGenericHTMLElement,
-                                  public nsIFrameLoaderOwner,
-                                  public nsIDOMMozBrowserFrameElement
-{
-public:
-  nsGenericHTMLFrameElement(already_AddRefed<nsINodeInfo> aNodeInfo,
-                            mozilla::dom::FromParser aFromParser)
-    : nsGenericHTMLElement(aNodeInfo)
-  {
-    mNetworkCreated = aFromParser == mozilla::dom::FROM_PARSER_NETWORK;
-  }
-  virtual ~nsGenericHTMLFrameElement();
-
-  NS_DECL_DOM_MEMORY_REPORTER_SIZEOF
-
-  // nsISupports
-  NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
-
-  // nsIFrameLoaderOwner
-  NS_DECL_NSIFRAMELOADEROWNER
-
-  // nsIContent
-  virtual bool IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, PRInt32 *aTabIndex);
-  virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
-                              nsIContent* aBindingParent,
-                              bool aCompileEventHandlers);
-  virtual void UnbindFromTree(bool aDeep = true,
-                              bool aNullParent = true);
-  nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                   const nsAString& aValue, bool aNotify)
-  {
-    return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify);
-  }
-  virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                           nsIAtom* aPrefix, const nsAString& aValue,
-                           bool aNotify);
-  virtual void DestroyContent();
-
-  nsresult CopyInnerTo(nsGenericElement* aDest) const;
-
-  // nsIDOMHTMLElement 
-  NS_IMETHOD GetTabIndex(PRInt32 *aTabIndex);
-  NS_IMETHOD SetTabIndex(PRInt32 aTabIndex);
-
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsGenericHTMLFrameElement,
-                                                     nsGenericHTMLElement)
-
-  // nsIDOMMozBrowserFrameElement
-  NS_DECL_NSIDOMMOZBROWSERFRAMEELEMENT
-
-protected:
-  // This doesn't really ensure a frame loade in all cases, only when
-  // it makes sense.
-  nsresult EnsureFrameLoader();
-  nsresult LoadSrc();
-  nsresult GetContentDocument(nsIDOMDocument** aContentDocument);
-  nsresult GetContentWindow(nsIDOMWindow** aContentWindow);
-
-  nsresult BrowserFrameSecurityCheck();
-
-  nsRefPtr<nsFrameLoader> mFrameLoader;
-  // True when the element is created by the parser
-  // using NS_FROM_PARSER_NETWORK flag.
-  // If the element is modified, it may lose the flag.
-  bool                    mNetworkCreated;
-};
-
-//----------------------------------------------------------------------
-
-/**
  * A macro to implement the getter and setter for a given string
  * valued content property. The method uses the generic GetAttr and
  * SetAttr methods.
  */
 #define NS_IMPL_STRING_ATTR(_class, _method, _atom)                  \
   NS_IMETHODIMP                                                      \
   _class::Get##_method(nsAString& aValue)                            \
   {                                                                  \
new file mode 100644
--- /dev/null
+++ b/content/html/content/src/nsGenericHTMLFrameElement.cpp
@@ -0,0 +1,446 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set tw=80 expandtab softtabstop=2 ts=2 sw=2: */
+
+/* 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 "nsGenericHTMLFrameElement.h"
+#include "nsIWebProgress.h"
+#include "nsIPrivateDOMEvent.h"
+#include "nsIDOMCustomEvent.h"
+#include "nsIVariant.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsVariant.h"
+#include "nsContentUtils.h"
+#include "nsDOMMemoryReporter.h"
+#include "nsEventDispatcher.h"
+#include "nsContentUtils.h"
+#include "nsAsyncDOMEvent.h"
+#include "mozilla/Preferences.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericHTMLFrameElement)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGenericHTMLFrameElement,
+                                                  nsGenericHTMLElement)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mFrameLoader, nsIFrameLoader)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_INTERFACE_TABLE_HEAD(nsGenericHTMLFrameElement)
+  NS_INTERFACE_TABLE_INHERITED3(nsGenericHTMLFrameElement,
+                                nsIFrameLoaderOwner,
+                                nsIDOMMozBrowserFrame,
+                                nsIWebProgressListener)
+  NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsGenericHTMLFrameElement)
+NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
+
+NS_IMPL_INT_ATTR(nsGenericHTMLFrameElement, TabIndex, tabindex)
+NS_IMPL_BOOL_ATTR(nsGenericHTMLFrameElement, Mozbrowser, mozbrowser)
+
+nsGenericHTMLFrameElement::~nsGenericHTMLFrameElement()
+{
+  if (mFrameLoader) {
+    mFrameLoader->Destroy();
+  }
+}
+
+nsresult
+nsGenericHTMLFrameElement::GetContentDocument(nsIDOMDocument** aContentDocument)
+{
+  NS_PRECONDITION(aContentDocument, "Null out param");
+  *aContentDocument = nsnull;
+
+  nsCOMPtr<nsIDOMWindow> win;
+  GetContentWindow(getter_AddRefs(win));
+
+  if (!win) {
+    return NS_OK;
+  }
+
+  return win->GetDocument(aContentDocument);
+}
+
+nsresult
+nsGenericHTMLFrameElement::GetContentWindow(nsIDOMWindow** aContentWindow)
+{
+  NS_PRECONDITION(aContentWindow, "Null out param");
+  *aContentWindow = nsnull;
+
+  nsresult rv = EnsureFrameLoader();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!mFrameLoader) {
+    return NS_OK;
+  }
+
+  bool depthTooGreat = false;
+  mFrameLoader->GetDepthTooGreat(&depthTooGreat);
+  if (depthTooGreat) {
+    // Claim to have no contentWindow
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIDocShell> doc_shell;
+  mFrameLoader->GetDocShell(getter_AddRefs(doc_shell));
+
+  nsCOMPtr<nsPIDOMWindow> win(do_GetInterface(doc_shell));
+
+  if (!win) {
+    return NS_OK;
+  }
+
+  NS_ASSERTION(win->IsOuterWindow(),
+               "Uh, this window should always be an outer window!");
+
+  return CallQueryInterface(win, aContentWindow);
+}
+
+nsresult
+nsGenericHTMLFrameElement::EnsureFrameLoader()
+{
+  if (!GetParent() || !IsInDoc() || mFrameLoader) {
+    // If frame loader is there, we just keep it around, cached
+    return NS_OK;
+  }
+
+  mFrameLoader = nsFrameLoader::Create(this, mNetworkCreated);
+  if (!mFrameLoader) {
+    // Strangely enough, this method doesn't actually ensure that the
+    // frameloader exists.  It's more of a best-effort kind of thing.
+    return NS_OK;
+  }
+
+  // Register ourselves as a web progress listener on the frameloader's
+  // docshell.
+  nsCOMPtr<nsIDocShell> docShell;
+  mFrameLoader->GetDocShell(getter_AddRefs(docShell));
+  nsCOMPtr<nsIWebProgress> webProgress = do_QueryInterface(docShell);
+  NS_ENSURE_TRUE(webProgress, NS_OK);
+
+  // This adds a weak ref, so we don't have to worry about unregistering.
+  webProgress->AddProgressListener(this,
+    nsIWebProgress::NOTIFY_LOCATION |
+    nsIWebProgress::NOTIFY_STATE_WINDOW);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGenericHTMLFrameElement::GetFrameLoader(nsIFrameLoader **aFrameLoader)
+{
+  NS_IF_ADDREF(*aFrameLoader = mFrameLoader);
+  return NS_OK;
+}
+
+NS_IMETHODIMP_(already_AddRefed<nsFrameLoader>)
+nsGenericHTMLFrameElement::GetFrameLoader()
+{
+  nsRefPtr<nsFrameLoader> loader = mFrameLoader;
+  return loader.forget();
+}
+
+NS_IMETHODIMP
+nsGenericHTMLFrameElement::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherOwner)
+{
+  // We don't support this yet
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
+nsGenericHTMLFrameElement::LoadSrc()
+{
+  nsresult rv = EnsureFrameLoader();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!mFrameLoader) {
+    return NS_OK;
+  }
+
+  rv = mFrameLoader->LoadFrame();
+#ifdef DEBUG
+  if (NS_FAILED(rv)) {
+    NS_WARNING("failed to load URL");
+  }
+#endif
+
+  return rv;
+}
+
+nsresult
+nsGenericHTMLFrameElement::BindToTree(nsIDocument* aDocument,
+                                      nsIContent* aParent,
+                                      nsIContent* aBindingParent,
+                                      bool aCompileEventHandlers)
+{
+  nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
+                                                 aBindingParent,
+                                                 aCompileEventHandlers);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (aDocument) {
+    NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
+                 "Missing a script blocker!");
+    // We're in a document now.  Kick off the frame load.
+    LoadSrc();
+  }
+
+  // We're now in document and scripts may move us, so clear
+  // the mNetworkCreated flag.
+  mNetworkCreated = false;
+  return rv;
+}
+
+void
+nsGenericHTMLFrameElement::UnbindFromTree(bool aDeep, bool aNullParent)
+{
+  if (mFrameLoader) {
+    // This iframe is being taken out of the document, destroy the
+    // iframe's frame loader (doing that will tear down the window in
+    // this iframe).
+    // XXXbz we really want to only partially destroy the frame
+    // loader... we don't want to tear down the docshell.  Food for
+    // later bug.
+    mFrameLoader->Destroy();
+    mFrameLoader = nsnull;
+  }
+
+  nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
+}
+
+nsresult
+nsGenericHTMLFrameElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
+                                   nsIAtom* aPrefix, const nsAString& aValue,
+                                   bool aNotify)
+{
+  nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix,
+                                              aValue, aNotify);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::src) {
+    // Don't propagate error here. The attribute was successfully set, that's
+    // what we should reflect.
+    LoadSrc();
+  }
+
+  return NS_OK;
+}
+
+void
+nsGenericHTMLFrameElement::DestroyContent()
+{
+  if (mFrameLoader) {
+    mFrameLoader->Destroy();
+    mFrameLoader = nsnull;
+  }
+
+  nsGenericHTMLElement::DestroyContent();
+}
+
+nsresult
+nsGenericHTMLFrameElement::CopyInnerTo(nsGenericElement* aDest) const
+{
+  nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsIDocument* doc = aDest->OwnerDoc();
+  if (doc->IsStaticDocument() && mFrameLoader) {
+    nsGenericHTMLFrameElement* dest =
+      static_cast<nsGenericHTMLFrameElement*>(aDest);
+    nsFrameLoader* fl = nsFrameLoader::Create(dest, false);
+    NS_ENSURE_STATE(fl);
+    dest->mFrameLoader = fl;
+    static_cast<nsFrameLoader*>(mFrameLoader.get())->CreateStaticClone(fl);
+  }
+
+  return rv;
+}
+
+bool
+nsGenericHTMLFrameElement::IsHTMLFocusable(bool aWithMouse,
+                                           bool *aIsFocusable,
+                                           PRInt32 *aTabIndex)
+{
+  if (nsGenericHTMLElement::IsHTMLFocusable(aWithMouse, aIsFocusable, aTabIndex)) {
+    return true;
+  }
+
+  *aIsFocusable = nsContentUtils::IsSubDocumentTabbable(this);
+
+  if (!*aIsFocusable && aTabIndex) {
+    *aTabIndex = -1;
+  }
+
+  return false;
+}
+
+PRInt64
+nsGenericHTMLFrameElement::SizeOf() const
+{
+  PRInt64 size = MemoryReporter::GetBasicSize<nsGenericHTMLFrameElement,
+                                              nsGenericHTMLElement>(this);
+  // TODO: need to implement SizeOf() in nsFrameLoader, bug 672539.
+  size += mFrameLoader ? sizeof(*mFrameLoader.get()) : 0;
+  return size;
+}
+
+/**
+ * Return true if this frame element has permission to send mozbrowser
+ * events, and false otherwise.
+ */
+bool
+nsGenericHTMLFrameElement::BrowserFrameSecurityCheck()
+{
+  // Fail if browser frames are globally disabled.
+  if (!Preferences::GetBool("dom.mozBrowserFramesEnabled")) {
+    return false;
+  }
+
+  // Fail if this frame doesn't have the mozbrowser attribute.
+  bool isBrowser = false;
+  GetMozbrowser(&isBrowser);
+  if (!isBrowser) {
+    return false;
+  }
+
+  // Fail if the node principal isn't trusted.
+  nsIPrincipal *principal = NodePrincipal();
+  nsCOMPtr<nsIURI> principalURI;
+  principal->GetURI(getter_AddRefs(principalURI));
+  if (!nsContentUtils::URIIsChromeOrInPref(principalURI,
+                                           "dom.mozBrowserFramesWhitelist")) {
+    return false;
+  }
+
+  // Otherwise, succeed.
+  return true;
+}
+
+/**
+ * Fire a mozbrowser event, if we have permission.
+ *
+ * @param aEventName the event name (e.g. "locationchange").  "mozbrowser" is
+ *        added to the beginning of aEventName automatically.
+ * @param aEventType the event type.  Must be either "event" or "customevent".
+ * @param aValue the value passed along with the event.  This value will be
+ *        set as the event's "detail" property.  This must be empty if
+ *        aEventType is "event".
+ */
+nsresult
+nsGenericHTMLFrameElement::MaybeFireBrowserEvent(
+  const nsAString &aEventName,
+  const nsAString &aEventType,
+  const nsAString &aValue /* = EmptyString() */)
+{
+  MOZ_ASSERT(aEventType.EqualsLiteral("event") ||
+             aEventType.EqualsLiteral("customevent"));
+  MOZ_ASSERT_IF(aEventType.EqualsLiteral("event"),
+                aValue.IsEmpty());
+
+  if (!BrowserFrameSecurityCheck()) {
+    return NS_OK;
+  }
+
+  nsAutoString eventName;
+  eventName.AppendLiteral("mozbrowser");
+  eventName.Append(aEventName);
+
+  nsCOMPtr<nsIDOMEvent> domEvent;
+  nsEventDispatcher::CreateEvent(GetPresContext(), nsnull,
+                                 aEventType, getter_AddRefs(domEvent));
+
+  nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(domEvent);
+  NS_ENSURE_STATE(privateEvent);
+
+  nsresult rv = privateEvent->SetTrusted(true);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (aEventType.EqualsLiteral("customevent")) {
+    nsCOMPtr<nsIDOMCustomEvent> customEvent = do_QueryInterface(domEvent);
+    NS_ENSURE_STATE(customEvent);
+
+    nsCOMPtr<nsIWritableVariant> value = new nsVariant();
+    value->SetAsAString(aValue);
+
+    rv = customEvent->InitCustomEvent(eventName,
+                                      /* bubbles = */ false,
+                                      /* cancelable = */ false,
+                                      value);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+  else {
+    rv = domEvent->InitEvent(eventName,
+                             /* bubbles = */ false,
+                             /* cancelable = */ false);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  return (new nsAsyncDOMEvent(this, domEvent))->PostDOMEvent();
+}
+
+NS_IMETHODIMP
+nsGenericHTMLFrameElement::OnLocationChange(nsIWebProgress* aWebProgress,
+                                            nsIRequest* aRequest,
+                                            nsIURI* aURI,
+                                            PRUint32 aFlags)
+{
+  nsCAutoString spec;
+  aURI->GetSpec(spec);
+
+  MaybeFireBrowserEvent(NS_LITERAL_STRING("locationchange"),
+                        NS_LITERAL_STRING("customevent"),
+                        NS_ConvertUTF8toUTF16(spec));
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGenericHTMLFrameElement::OnStateChange(nsIWebProgress* aProgress,
+                                         nsIRequest* aRequest,
+                                         PRUint32 aProgressStateFlags,
+                                         nsresult aStatus)
+{
+  if (!(aProgressStateFlags & STATE_IS_WINDOW)) {
+    return NS_OK;
+  }
+
+  nsAutoString status;
+  if (aProgressStateFlags & STATE_START) {
+    MaybeFireBrowserEvent(NS_LITERAL_STRING("loadstart"),
+                          NS_LITERAL_STRING("event"));
+  }
+  else if (aProgressStateFlags & STATE_STOP) {
+    MaybeFireBrowserEvent(NS_LITERAL_STRING("loadend"),
+                          NS_LITERAL_STRING("event"));
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGenericHTMLFrameElement::OnProgressChange(nsIWebProgress* aProgress,
+                                            nsIRequest* aRequest,
+                                            PRInt32 aCurSelfProgress,
+                                            PRInt32 aMaxSelfProgress,
+                                            PRInt32 aCurTotalProgress,
+                                            PRInt32 aMaxTotalProgress)
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGenericHTMLFrameElement::OnStatusChange(nsIWebProgress* aWebProgress,
+                                          nsIRequest* aRequest,
+                                          nsresult aStatus,
+                                          const PRUnichar* aMessage)
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGenericHTMLFrameElement::OnSecurityChange(nsIWebProgress *aWebProgress,
+                                            nsIRequest *aRequest,
+                                            PRUint32 state)
+{
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/content/html/content/src/nsGenericHTMLFrameElement.h
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set tw=80 expandtab softtabstop=2 ts=2 sw=2: */
+
+/* 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 "nsGenericHTMLElement.h"
+#include "nsIDOMHTMLFrameElement.h"
+#include "nsIDOMMozBrowserFrame.h"
+#include "nsIWebProgressListener.h"
+
+/**
+ * A helper class for frame elements
+ */
+class nsGenericHTMLFrameElement : public nsGenericHTMLElement,
+                                  public nsIFrameLoaderOwner,
+                                  public nsIDOMMozBrowserFrame,
+                                  public nsIWebProgressListener
+{
+public:
+  nsGenericHTMLFrameElement(already_AddRefed<nsINodeInfo> aNodeInfo,
+                            mozilla::dom::FromParser aFromParser)
+    : nsGenericHTMLElement(aNodeInfo)
+  {
+    mNetworkCreated = aFromParser == mozilla::dom::FROM_PARSER_NETWORK;
+  }
+  virtual ~nsGenericHTMLFrameElement();
+
+  NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
+  NS_DECL_NSIFRAMELOADEROWNER
+  NS_DECL_NSIDOMMOZBROWSERFRAME
+  NS_DECL_NSIWEBPROGRESSLISTENER
+  NS_DECL_DOM_MEMORY_REPORTER_SIZEOF
+
+  // nsIContent
+  virtual bool IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, PRInt32 *aTabIndex);
+  virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+                              nsIContent* aBindingParent,
+                              bool aCompileEventHandlers);
+  virtual void UnbindFromTree(bool aDeep = true,
+                              bool aNullParent = true);
+  nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
+                   const nsAString& aValue, bool aNotify)
+  {
+    return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify);
+  }
+  virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
+                           nsIAtom* aPrefix, const nsAString& aValue,
+                           bool aNotify);
+  virtual void DestroyContent();
+
+  nsresult CopyInnerTo(nsGenericElement* aDest) const;
+
+  // nsIDOMHTMLElement
+  NS_IMETHOD GetTabIndex(PRInt32 *aTabIndex);
+  NS_IMETHOD SetTabIndex(PRInt32 aTabIndex);
+
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsGenericHTMLFrameElement,
+                                                     nsGenericHTMLElement)
+
+protected:
+  // This doesn't really ensure a frame loade in all cases, only when
+  // it makes sense.
+  nsresult EnsureFrameLoader();
+  nsresult LoadSrc();
+  nsresult GetContentDocument(nsIDOMDocument** aContentDocument);
+  nsresult GetContentWindow(nsIDOMWindow** aContentWindow);
+
+  bool BrowserFrameSecurityCheck();
+  nsresult MaybeFireBrowserEvent(const nsAString &aEventName,
+                                 const nsAString &aEventType,
+                                 const nsAString &aValue = EmptyString());
+
+  nsRefPtr<nsFrameLoader> mFrameLoader;
+  // True when the element is created by the parser
+  // using NS_FROM_PARSER_NETWORK flag.
+  // If the element is modified, it may lose the flag.
+  bool                    mNetworkCreated;
+};
--- a/content/html/content/src/nsHTMLFrameElement.cpp
+++ b/content/html/content/src/nsHTMLFrameElement.cpp
@@ -33,17 +33,17 @@
  * 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 "mozilla/Util.h"
 
 #include "nsIDOMHTMLFrameElement.h"
-#include "nsGenericHTMLElement.h"
+#include "nsGenericHTMLFrameElement.h"
 #include "nsGkAtoms.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsDOMError.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
--- a/content/html/content/src/nsHTMLIFrameElement.cpp
+++ b/content/html/content/src/nsHTMLIFrameElement.cpp
@@ -33,17 +33,17 @@
  * 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 "mozilla/Util.h"
 
 #include "nsIDOMHTMLIFrameElement.h"
-#include "nsGenericHTMLElement.h"
+#include "nsGenericHTMLFrameElement.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMGetSVGDocument.h"
 #include "nsIDOMSVGDocument.h"
 #include "nsGkAtoms.h"
 #include "nsIDocument.h"
 #include "nsMappedAttributes.h"
 #include "nsDOMError.h"
 #include "nsRuleData.h"
--- a/content/html/content/test/test_bug389797.html
+++ b/content/html/content/test/test_bug389797.html
@@ -138,31 +138,31 @@ HTML_TAG("dt", "");
 HTML_TAG("em", "");
 HTML_TAG("embed", "Embed", [ "nsIDOMGetSVGDocument" ], objectIfaces);
 HTML_TAG("fieldset", "FieldSet");
 HTML_TAG("figcaption", "")
 HTML_TAG("figure", "")
 HTML_TAG("font", "Font");
 HTML_TAG("footer", "")
 HTML_TAG("form", "Form", [], [ "nsIWebProgressListener" ]);
-HTML_TAG("frame", "Frame", [ "nsIDOMMozBrowserFrameElement" ], [ "nsIFrameLoaderOwner" ]);
+HTML_TAG("frame", "Frame", [ "nsIDOMMozBrowserFrame" ], [ "nsIFrameLoaderOwner" ]);
 HTML_TAG("frameset", "FrameSet");
 HTML_TAG("h1", "Heading");
 HTML_TAG("h2", "Heading");
 HTML_TAG("h3", "Heading");
 HTML_TAG("h4", "Heading");
 HTML_TAG("h5", "Heading");
 HTML_TAG("h6", "Heading");
 HTML_TAG("head", "Head");
 HTML_TAG("header", "")
 HTML_TAG("hgroup", "")
 HTML_TAG("hr", "HR");
 HTML_TAG("html", "Html");
 HTML_TAG("i", "");
-HTML_TAG("iframe", "IFrame", [ "nsIDOMGetSVGDocument", "nsIDOMMozBrowserFrameElement" ],
+HTML_TAG("iframe", "IFrame", [ "nsIDOMGetSVGDocument", "nsIDOMMozBrowserFrame" ],
                              [ "nsIFrameLoaderOwner" ]);
 HTML_TAG("image", "Span");
 HTML_TAG("img", "Image", [], [ "imgIDecoderObserver",
                                "nsIImageLoadingContent" ]);
 HTML_TAG("input", "Input", [], [ "imgIDecoderObserver",
                                  "nsIImageLoadingContent",
                                  "nsIDOMNSEditableElement" ]);
 HTML_TAG("ins", "Mod");
--- a/content/html/document/src/nsHTMLContentSink.cpp
+++ b/content/html/document/src/nsHTMLContentSink.cpp
@@ -186,17 +186,17 @@ public:
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLContentSink, nsContentSink)
 
   // nsIContentSink
   NS_IMETHOD WillParse(void);
   NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode);
   NS_IMETHOD DidBuildModel(bool aTerminated);
   NS_IMETHOD WillInterrupt(void);
   NS_IMETHOD WillResume(void);
-  NS_IMETHOD SetParser(nsIParser* aParser);
+  NS_IMETHOD SetParser(nsParserBase* aParser);
   virtual void FlushPendingNotifications(mozFlushType aType);
   NS_IMETHOD SetDocumentCharset(nsACString& aCharset);
   virtual nsISupports *GetTarget();
   virtual bool IsScriptExecuting();
 
   // nsIHTMLContentSink
   NS_IMETHOD OpenContainer(const nsIParserNode& aNode);
   NS_IMETHOD CloseContainer(const nsHTMLTag aTag);
@@ -290,19 +290,16 @@ protected:
   nsresult ProcessSCRIPTEndTag(nsGenericHTMLElement* content,
                                bool aMalformed);
   nsresult ProcessSTYLEEndTag(nsGenericHTMLElement* content);
 
   nsresult OpenHeadContext();
   void CloseHeadContext();
 
   // nsContentSink overrides
-  virtual void PreEvaluateScript();
-  virtual void PostEvaluateScript(nsIScriptElement *aElement);
-
   void UpdateChildCounts();
 
   void NotifyInsert(nsIContent* aContent,
                     nsIContent* aChildContent,
                     PRInt32 aIndexInContainer);
   void NotifyRootInsertion();
   
   bool IsMonolithicContainer(nsHTMLTag aTag);
@@ -800,21 +797,23 @@ SinkContext::OpenContainer(const nsIPars
       {
         nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(content);
         NS_ASSERTION(sele, "Script content isn't a script element?");
         sele->SetScriptLineNumber(aNode.GetSourceLineNumber());
       }
       break;
 
     case eHTMLTag_button:
+#ifdef MOZ_MEDIA
     case eHTMLTag_audio:
     case eHTMLTag_video:
+#endif
       content->DoneCreatingElement();
       break;
-      
+
     default:
       break;
   }
 
   return NS_OK;
 }
 
 bool
@@ -1697,18 +1696,16 @@ HTMLContentSink::DidBuildModel(bool aTer
 
     if (!bDestroying) {
       StartLayout(false);
     }
   }
 
   ScrollToRef();
 
-  mDocument->ScriptLoader()->RemoveObserver(this);
-
   // Make sure we no longer respond to document mutations.  We've flushed all
   // our notifications out, so there's no need to do anything else here.
 
   // XXXbz I wonder whether we could End() our contexts here too, or something,
   // just to make sure we no longer notify...  Or is the mIsDocumentObserver
   // thing sufficient?
   mDocument->RemoveObserver(this);
   mIsDocumentObserver = false;
@@ -1716,17 +1713,17 @@ HTMLContentSink::DidBuildModel(bool aTer
   mDocument->EndLoad();
 
   DropParserAndPerfHint();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-HTMLContentSink::SetParser(nsIParser* aParser)
+HTMLContentSink::SetParser(nsParserBase* aParser)
 {
   NS_PRECONDITION(aParser, "Should have a parser here!");
   mParser = aParser;
   return NS_OK;
 }
 
 NS_IMETHODIMP_(bool)
 HTMLContentSink::IsFormOnStack()
@@ -2555,88 +2552,18 @@ HTMLContentSink::CloseHeadContext()
     mCurrentContext = mContextStack.ElementAt(n);
     mContextStack.RemoveElementAt(n);
   }
 }
 
 nsresult
 HTMLContentSink::ProcessLINKTag(const nsIParserNode& aNode)
 {
-  nsresult  result = NS_OK;
-
-  if (mCurrentContext) {
-    // Create content object
-    nsCOMPtr<nsIContent> element;
-    nsCOMPtr<nsINodeInfo> nodeInfo;
-    nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::link, nsnull,
-                                             kNameSpaceID_XHTML,
-                                             nsIDOMNode::ELEMENT_NODE);
-
-    result = NS_NewHTMLElement(getter_AddRefs(element), nodeInfo.forget(),
-                               NOT_FROM_PARSER);
-    NS_ENSURE_SUCCESS(result, result);
-
-    nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(element));
-
-    if (ssle) {
-      // XXX need prefs. check here.
-      if (!mInsideNoXXXTag) {
-        ssle->InitStyleLinkElement(false);
-        ssle->SetEnableUpdates(false);
-      } else {
-        ssle->InitStyleLinkElement(true);
-      }
-    }
-
-    // Add in the attributes and add the style content object to the
-    // head container.
-    result = AddAttributes(aNode, element);
-    if (NS_FAILED(result)) {
-      return result;
-    }
-
-    mCurrentContext->AddLeaf(element); // <link>s are leaves
-
-    if (ssle) {
-      ssle->SetEnableUpdates(true);
-      bool willNotify;
-      bool isAlternate;
-      result = ssle->UpdateStyleSheet(mFragmentMode ? nsnull : this,
-                                      &willNotify,
-                                      &isAlternate);
-      if (NS_SUCCEEDED(result) && willNotify && !isAlternate && !mFragmentMode) {
-        ++mPendingSheetCount;
-        mScriptLoader->AddExecuteBlocker();
-      }
-
-      // look for <link rel="next" href="url">
-      nsAutoString relVal;
-      element->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, relVal);
-      if (!relVal.IsEmpty()) {
-        PRUint32 linkTypes = nsStyleLinkElement::ParseLinkTypes(relVal);
-        bool hasPrefetch = linkTypes & PREFETCH;
-        if (hasPrefetch || (linkTypes & NEXT)) {
-          nsAutoString hrefVal;
-          element->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
-          if (!hrefVal.IsEmpty()) {
-            PrefetchHref(hrefVal, element, hasPrefetch);
-          }
-        }
-        if (linkTypes & DNS_PREFETCH) {
-          nsAutoString hrefVal;
-          element->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
-          if (!hrefVal.IsEmpty()) {
-            PrefetchDNS(hrefVal);
-          }
-        }
-      }
-    }
-  }
-
-  return result;
+  MOZ_NOT_REACHED("Old HTMLContentSink used for processing links.");
+  return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 #ifdef DEBUG
 void
 HTMLContentSink::ForceReflow()
 {
   mCurrentContext->FlushTags();
 }
@@ -2711,120 +2638,32 @@ HTMLContentSink::UpdateChildCounts()
     SinkContext* sc = mContextStack.ElementAt(i);
 
     sc->UpdateChildCounts();
   }
 
   mCurrentContext->UpdateChildCounts();
 }
 
-void
-HTMLContentSink::PreEvaluateScript()
-{
-  // Eagerly append all pending elements (including the current body child)
-  // to the body (so that they can be seen by scripts) and force reflow.
-  SINK_TRACE(gSinkLogModuleInfo, SINK_TRACE_CALLS,
-             ("HTMLContentSink::PreEvaluateScript: flushing tags before "
-              "evaluating script"));
-
-  // XXX Should this call FlushTags()?
-  mCurrentContext->FlushText();
-}
-
-void
-HTMLContentSink::PostEvaluateScript(nsIScriptElement *aElement)
-{
-  mHTMLDocument->ScriptExecuted(aElement);
-}
-
 nsresult
 HTMLContentSink::ProcessSCRIPTEndTag(nsGenericHTMLElement *content,
                                      bool aMalformed)
 {
-  // Flush all tags up front so that we are in as stable state as possible
-  // when calling DoneAddingChildren. This may not be strictly needed since
-  // any ScriptAvailable calls will cause us to flush anyway. But it gives a
-  // warm fuzzy feeling to be in a stable state before even attempting to
-  // run scripts.
-  // It would however be needed if we properly called BeginUpdate and
-  // EndUpdate while we were inserting stuff into the DOM.
-
-  // XXX Should this call FlushTags()?
-  mCurrentContext->FlushText();
-
-  nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(content);
-  NS_ASSERTION(sele, "Not really closing a script tag?");
-
-  if (aMalformed) {
-    // Make sure to serialize this script correctly, for nice round tripping.
-    sele->SetIsMalformed();
-  }
-  if (mFrameset) {
-    sele->PreventExecution();
-  }
-
-  // Notify our document that we're loading this script.
-  mHTMLDocument->ScriptLoading(sele);
-
-  // Now tell the script that it's ready to go. This may execute the script
-  // or return true, or neither if the script doesn't need executing.
-  bool block = sele->AttemptToExecute();
-
-  // If the act of insertion evaluated the script, we're fine.
-  // Else, block the parser till the script has loaded.
-  if (block) {
-    // If this append fails we'll never unblock the parser, but the UI will
-    // still remain responsive. There are other ways to deal with this, but
-    // the end result is always that the page gets botched, so there is no
-    // real point in making it more complicated.
-    mScriptElements.AppendObject(sele);
-  } else {
-    // This may have already happened if the script executed, but in case
-    // it didn't then remove the element so that it doesn't get stuck forever.
-    mHTMLDocument->ScriptExecuted(sele);
-  }
-
-  // If the parser got blocked, make sure to return the appropriate rv.
-  // I'm not sure if this is actually needed or not.
-  if (mParser && !mParser->IsParserEnabled()) {
-    block = true;
-  }
-
-  return block ? NS_ERROR_HTMLPARSER_BLOCK : NS_OK;
+  MOZ_NOT_REACHED("Must not use HTMLContentSink to run scripts.");
+  return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 // 3 ways to load a style sheet: inline, style src=, link tag
 // XXX What does nav do if we have SRC= and some style data inline?
 
 nsresult
 HTMLContentSink::ProcessSTYLEEndTag(nsGenericHTMLElement* content)
 {
-  nsCOMPtr<nsIStyleSheetLinkingElement> ssle = do_QueryInterface(content);
-
-  NS_ASSERTION(ssle,
-               "html:style doesn't implement nsIStyleSheetLinkingElement");
-
-  nsresult rv = NS_OK;
-
-  if (ssle) {
-    // Note: if we are inside a noXXX tag, then we init'ed this style element
-    // with mDontLoadStyle = true, so these two calls will have no effect.
-    ssle->SetEnableUpdates(true);
-    bool willNotify;
-    bool isAlternate;
-    rv = ssle->UpdateStyleSheet(mFragmentMode ? nsnull : this,
-                                &willNotify,
-                                &isAlternate);
-    if (NS_SUCCEEDED(rv) && willNotify && !isAlternate && !mFragmentMode) {
-      ++mPendingSheetCount;
-      mScriptLoader->AddExecuteBlocker();
-    }
-  }
-
-  return rv;
+  MOZ_NOT_REACHED("Old HTMLContentSink used for processing style elements.");
+  return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 void
 HTMLContentSink::FlushPendingNotifications(mozFlushType aType)
 {
   // Only flush tags if we're not doing the notification ourselves
   // (since we aren't reentrant)
   if (!mInNotification) {
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -901,88 +901,27 @@ nsHTMLDocument::StartDocumentLoad(const 
   }
 
   return rv;
 }
 
 void
 nsHTMLDocument::StopDocumentLoad()
 {
-  if (nsHtml5Module::sEnabled) {
-    BlockOnload();
-    if (mWriteState == eDocumentOpened) {
-      NS_ASSERTION(IsHTML(), "document.open()ed doc is not HTML?");
-
-      // Marking the document as closed, since pending scripts will be
-      // stopped by nsDocument::StopDocumentLoad() below
-      mWriteState = eDocumentClosed;
-
-      // Remove the wyciwyg channel request from the document load group
-      // that we added in Open().
-      NS_ASSERTION(mWyciwygChannel, "nsHTMLDocument::StopDocumentLoad(): "
-                   "Trying to remove nonexistent wyciwyg channel!");
-      RemoveWyciwygChannel();
-      NS_ASSERTION(!mWyciwygChannel, "nsHTMLDocument::StopDocumentLoad(): "
-                   "nsIWyciwygChannel could not be removed!");
-    }
-    nsDocument::StopDocumentLoad();
-    UnblockOnload(false);
-    return;
-  }
-  // Code for the old parser:
-
-  // If we're writing (i.e., there's been a document.open call), then
-  // nsDocument::StopDocumentLoad will do the wrong thing and simply terminate
-  // our parser.
-  if (mWriteState != eNotWriting) {
-    Close();
-  } else {
-    nsDocument::StopDocumentLoad();
-  }
-}
-
-// static
-void
-nsHTMLDocument::DocumentWriteTerminationFunc(nsISupports *aRef)
-{
-  nsCOMPtr<nsIArray> arr = do_QueryInterface(aRef);
-  NS_ASSERTION(arr, "Must have array!");
-
-  nsCOMPtr<nsIDocument> doc = do_QueryElementAt(arr, 0);
-  NS_ASSERTION(doc, "Must have document!");
-  
-  nsCOMPtr<nsIParser> parser = do_QueryElementAt(arr, 1);
-  NS_ASSERTION(parser, "Must have parser!");
-
-  nsHTMLDocument *htmldoc = static_cast<nsHTMLDocument*>(doc.get());
-
-  // Check whether htmldoc still has the same parser.  If not, it's
-  // not for us to mess with it.
-  if (htmldoc->mParser != parser) {
-    return;
-  }
-
-  // If the document is in the middle of a document.write() call, this
-  // most likely means that script on a page document.write()'d out a
-  // script tag that did location="..." and we're right now finishing
-  // up executing the script that was written with
-  // document.write(). Since there's still script on the stack (the
-  // script that called document.write()) we don't want to release the
-  // parser now, that would cause the next document.write() call to
-  // cancel the load that was initiated by the location="..." in the
-  // script that was written out by document.write().
-
-  if (!htmldoc->mWriteLevel && htmldoc->mWriteState != eDocumentOpened) {
-    // Release the document's parser so that the call to EndLoad()
-    // doesn't just return early and set the termination function again.
-
-    htmldoc->mParser = nsnull;
-  }
-
-  htmldoc->EndLoad();
+  BlockOnload();
+
+  // Remove the wyciwyg channel request from the document load group
+  // that we added in Open() if Open() was called on this doc.
+  RemoveWyciwygChannel();
+  NS_ASSERTION(!mWyciwygChannel, "nsHTMLDocument::StopDocumentLoad(): "
+               "nsIWyciwygChannel could not be removed!");
+
+  nsDocument::StopDocumentLoad();
+  UnblockOnload(false);
+  return;
 }
 
 void
 nsHTMLDocument::BeginLoad()
 {
   if (IsEditingOn()) {
     // Reset() blows away all event listeners in the document, and our
     // editor relies heavily on those. Midas is turned on, to make it
@@ -993,75 +932,16 @@ nsHTMLDocument::BeginLoad()
     EditingStateChanged();
   }
   nsDocument::BeginLoad();
 }
 
 void
 nsHTMLDocument::EndLoad()
 {
-  if (mParser && mWriteState != eDocumentClosed) {
-    nsCOMPtr<nsIJSContextStack> stack =
-      do_GetService("@mozilla.org/js/xpc/ContextStack;1");
-
-    if (stack) {
-      JSContext *cx = nsnull;
-      stack->Peek(&cx);
-
-      if (cx) {
-        nsIScriptContext *scx = nsJSUtils::GetDynamicScriptContext(cx);
-
-        if (scx) {
-          // The load of the document was terminated while we're
-          // called from within JS and we have a parser (i.e. we're in
-          // the middle of doing document.write()). In stead of
-          // releasing the parser and ending the document load
-          // directly, we'll make that happen once the script is done
-          // executing. This way subsequent document.write() calls
-          // won't end up creating a new parser and interrupting other
-          // loads that were started while the script was
-          // running. I.e. this makes the following case work as
-          // expected:
-          //
-          //   document.write("foo");
-          //   location.href = "http://www.mozilla.org";
-          //   document.write("bar");
-
-          nsresult rv;
-
-          nsCOMPtr<nsIMutableArray> arr =
-            do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
-          if (NS_SUCCEEDED(rv)) {
-            rv = arr->AppendElement(static_cast<nsIDocument*>(this),
-                                    false);
-            if (NS_SUCCEEDED(rv)) {
-              rv = arr->AppendElement(mParser, false);
-              if (NS_SUCCEEDED(rv)) {
-                rv = scx->SetTerminationFunction(DocumentWriteTerminationFunc,
-                                                 arr);
-                // If we fail to set the termination function, just go ahead
-                // and EndLoad now.  The slight bugginess involved is better
-                // than leaking.
-                if (NS_SUCCEEDED(rv)) {
-                  return;
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-
-  // Reset this now, since we're really done "loading" this document.written
-  // document.
-  NS_ASSERTION(mWriteState == eNotWriting || mWriteState == ePendingClose ||
-               mWriteState == eDocumentClosed, "EndLoad called early");
-  mWriteState = eNotWriting;
-
   bool turnOnEditing =
     mParser && (HasFlag(NODE_IS_EDITABLE) || mContentEditableCount > 0);
   // Note: nsDocument::EndLoad nulls out mParser.
   nsDocument::EndLoad();
   if (turnOnEditing) {
     EditingStateChanged();
   }
 }
@@ -1668,30 +1548,27 @@ nsHTMLDocument::Open(const nsAString& aC
     rv = NS_OK;
   } else {
     mParser = do_CreateInstance(kCParserCID, &rv);  
   }
 
   // This will be propagated to the parser when someone actually calls write()
   SetContentTypeInternal(contentType);
 
-  mWriteState = eDocumentOpened;
-
   if (NS_SUCCEEDED(rv)) {
     if (loadAsHtml5) {
       nsHtml5Module::Initialize(mParser, this, uri, shell, channel);
     } else {
       nsCOMPtr<nsIHTMLContentSink> sink;
 
       rv = NS_NewHTMLContentSink(getter_AddRefs(sink), this, uri, shell,
                                  channel);
       if (NS_FAILED(rv)) {
         // Don't use a parser without a content sink.
         mParser = nsnull;
-        mWriteState = eNotWriting;
         return rv;
       }
 
       mParser->SetContentSink(sink);
     }
   }
 
   // Prepare the docshell and the document viewer for the impending
@@ -1741,65 +1618,61 @@ NS_IMETHODIMP
 nsHTMLDocument::Close()
 {
   if (!IsHTML()) {
     // No calling document.close() on XHTML!
 
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
-  nsresult rv = NS_OK;
-
-  if (mParser && mWriteState == eDocumentOpened) {
-    mPendingScripts.RemoveElement(GenerateParserKey());
-
-    mWriteState = mPendingScripts.IsEmpty() ? eDocumentClosed : ePendingClose;
-
-    ++mWriteLevel;
-    rv = mParser->Parse(EmptyString(), mParser->GetRootContextKey(),
-                        GetContentTypeInternal(), true);
-    --mWriteLevel;
-
-    // XXX Make sure that all the document.written content is
-    // reflowed.  We should remove this call once we change
-    // nsHTMLDocument::OpenCommon() so that it completely destroys the
-    // earlier document's content and frame hierarchy.  Right now, it
-    // re-uses the earlier document's root content object and
-    // corresponding frame objects.  These re-used frame objects think
-    // that they have already been reflowed, so they drop initial
-    // reflows.  For certain cases of document.written content, like a
-    // frameset document, the dropping of the initial reflow means
-    // that we end up in document.close() without appended any reflow
-    // commands to the reflow queue and, consequently, without adding
-    // the dummy layout request to the load group.  Since the dummy
-    // layout request is not added to the load group, the onload
-    // handler of the frameset fires before the frames get reflowed
-    // and loaded.  That is the long explanation for why we need this
-    // one line of code here!
-    // XXXbz as far as I can tell this may not be needed anymore; all
-    // the testcases in bug 57636 pass without this line...  Leaving
-    // it be for now, though.  In any case, there's no reason to do
-    // this if we have no presshell, since in that case none of the
-    // above about reusing frames applies.
-    if (GetShell()) {
-      FlushPendingNotifications(Flush_Layout);
-    }
-
-    // Remove the wyciwyg channel request from the document load group
-    // that we added in OpenCommon().  If all other requests between
-    // document.open() and document.close() have completed, then this
-    // method should cause the firing of an onload event.
-    NS_ASSERTION(mWyciwygChannel, "nsHTMLDocument::Close(): Trying to remove "
-                 "nonexistent wyciwyg channel!");
-    RemoveWyciwygChannel();
-    NS_ASSERTION(!mWyciwygChannel, "nsHTMLDocument::Close(): "
-                 "nsIWyciwygChannel could not be removed!");
+  if (!mParser || !mParser->IsScriptCreated()) {
+    return NS_OK;
   }
 
-  return NS_OK;
+  ++mWriteLevel;
+  nsresult rv = mParser->Parse(EmptyString(), nsnull,
+                               GetContentTypeInternal(), true);
+  --mWriteLevel;
+
+  // XXX Make sure that all the document.written content is
+  // reflowed.  We should remove this call once we change
+  // nsHTMLDocument::OpenCommon() so that it completely destroys the
+  // earlier document's content and frame hierarchy.  Right now, it
+  // re-uses the earlier document's root content object and
+  // corresponding frame objects.  These re-used frame objects think
+  // that they have already been reflowed, so they drop initial
+  // reflows.  For certain cases of document.written content, like a
+  // frameset document, the dropping of the initial reflow means
+  // that we end up in document.close() without appended any reflow
+  // commands to the reflow queue and, consequently, without adding
+  // the dummy layout request to the load group.  Since the dummy
+  // layout request is not added to the load group, the onload
+  // handler of the frameset fires before the frames get reflowed
+  // and loaded.  That is the long explanation for why we need this
+  // one line of code here!
+  // XXXbz as far as I can tell this may not be needed anymore; all
+  // the testcases in bug 57636 pass without this line...  Leaving
+  // it be for now, though.  In any case, there's no reason to do
+  // this if we have no presshell, since in that case none of the
+  // above about reusing frames applies.
+  //
+  // XXXhsivonen keeping this around for bug 577508 / 253951 still :-(
+  if (GetShell()) {
+    FlushPendingNotifications(Flush_Layout);
+  }
+
+  // Removing the wyciwygChannel here is wrong when document.close() is
+  // called from within the document itself. However, legacy requires the
+  // channel to be removed here. Otherwise, the load event never fires.
+  NS_ASSERTION(mWyciwygChannel, "nsHTMLDocument::Close(): Trying to remove "
+               "nonexistent wyciwyg channel!");
+  RemoveWyciwygChannel();
+  NS_ASSERTION(!mWyciwygChannel, "nsHTMLDocument::Close(): "
+               "nsIWyciwygChannel could not be removed!");
+  return rv;
 }
 
 nsresult
 nsHTMLDocument::WriteCommon(JSContext *cx,
                             const nsAString& aText,
                             bool aNewlineTerminate)
 {
   mTooDeepWriteRecursion =
@@ -1810,31 +1683,27 @@ nsHTMLDocument::WriteCommon(JSContext *c
     // No calling document.write*() on XHTML!
 
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
   nsresult rv = NS_OK;
 
   void *key = GenerateParserKey();
-  if (mWriteState == eDocumentClosed ||
-      (mWriteState == ePendingClose &&
-       !mPendingScripts.Contains(key)) ||
-      (mParser && !mParser->IsInsertionPointDefined())) {
+  if (mParser && !mParser->IsInsertionPointDefined()) {
     if (mExternalScriptsBeingEvaluated) {
       // Instead of implying a call to document.open(), ignore the call.
       nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
                                       "DOM Events", this,
                                       nsContentUtils::eDOM_PROPERTIES,
                                       "DocumentWriteIgnored",
                                       nsnull, 0,
                                       mDocumentURI);
       return NS_OK;
     }
-    mWriteState = eDocumentClosed;
     mParser->Terminate();
     NS_ASSERTION(!mParser, "mParser should have been null'd out");
   }
 
   if (!mParser) {
     if (mExternalScriptsBeingEvaluated) {
       // Instead of implying a call to document.open(), ignore the call.
       nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
@@ -1856,18 +1725,18 @@ nsHTMLDocument::WriteCommon(JSContext *c
       return rv;
     }
     NS_ABORT_IF_FALSE(!JS_IsExceptionPending(cx),
                       "Open() succeeded but JS exception is pending");
   }
 
   static NS_NAMED_LITERAL_STRING(new_line, "\n");
 
-  // Save the data in cache
-  if (mWyciwygChannel) {
+  // Save the data in cache if the write isn't from within the doc
+  if (mWyciwygChannel && !key) {
     if (!aText.IsEmpty()) {
       mWyciwygChannel->WriteToCacheEntry(aText);
     }
 
     if (aNewlineTerminate) {
       mWyciwygChannel->WriteToCacheEntry(new_line);
     }
   }
@@ -1876,21 +1745,21 @@ nsHTMLDocument::WriteCommon(JSContext *c
 
   // This could be done with less code, but for performance reasons it
   // makes sense to have the code for two separate Parse() calls here
   // since the concatenation of strings costs more than we like. And
   // why pay that price when we don't need to?
   if (aNewlineTerminate) {
     rv = mParser->Parse(aText + new_line,
                         key, GetContentTypeInternal(),
-                        (mWriteState == eNotWriting || (mWriteLevel > 1)));
+                        false);
   } else {
     rv = mParser->Parse(aText,
                         key, GetContentTypeInternal(),
-                        (mWriteState == eNotWriting || (mWriteLevel > 1)));
+                        false);
   }
 
   --mWriteLevel;
 
   mTooDeepWriteRecursion = (mWriteLevel != 0 && mTooDeepWriteRecursion);
 
   return rv;
 }
@@ -1935,40 +1804,16 @@ nsHTMLDocument::GetElementsByName(const 
 
   // Transfer ownership
   list.forget(aReturn);
 
   return NS_OK;
 }
 
 void
-nsHTMLDocument::ScriptLoading(nsIScriptElement *aScript)
-{
-  if (mWriteState == eNotWriting) {
-    return;
-  }
-
-  mPendingScripts.AppendElement(aScript);
-}
-
-void
-nsHTMLDocument::ScriptExecuted(nsIScriptElement *aScript)
-{
-  if (mWriteState == eNotWriting) {
-    return;
-  }
-
-  mPendingScripts.RemoveElement(aScript);
-  if (mPendingScripts.IsEmpty() && mWriteState == ePendingClose) {
-    // The last pending script just finished, terminate our parser now.
-    mWriteState = eDocumentClosed;
-  }
-}
-
-void
 nsHTMLDocument::AddedForm()
 {
   ++mNumForms;
 }
 
 void
 nsHTMLDocument::RemovedForm()
 {
@@ -2406,17 +2251,17 @@ nsHTMLDocument::GenerateParserKey(void)
   if (nsHtml5Module::sEnabled) {
     nsIScriptElement* script = mScriptLoader->GetCurrentParserInsertedScript();
     if (script && mParser && mParser->IsScriptCreated()) {
       nsCOMPtr<nsIParser> creatorParser = script->GetCreatorParser();
       if (creatorParser != mParser) {
         // Make scripts that aren't inserted by the active parser of this document
         // participate in the context of the script that document.open()ed 
         // this document.
-        return mParser->GetRootContextKey();
+        return nsnull;
       }
     }
     return script;
   } else {
     return mScriptLoader->GetCurrentScript();
   }
 }
 
--- a/content/html/document/src/nsHTMLDocument.h
+++ b/content/html/document/src/nsHTMLDocument.h
@@ -144,19 +144,16 @@ public:
   }
 
 
   virtual nsresult ResolveName(const nsAString& aName,
                                nsIContent *aForm,
                                nsISupports **aResult,
                                nsWrapperCache **aCache);
 
-  virtual void ScriptLoading(nsIScriptElement *aScript);
-  virtual void ScriptExecuted(nsIScriptElement *aScript);
-
   virtual void AddedForm();
   virtual void RemovedForm();
   virtual PRInt32 GetNumFormsSynchronous();
   virtual void TearingDownEditor(nsIEditor *aEditor);
   virtual void SetIsXHTML(bool aXHTML) { mIsRegularHTML = !aXHTML; }
   virtual void SetDocWriteDisabled(bool aDisabled)
   {
     mDisableDocWrite = aDisabled;
@@ -270,39 +267,22 @@ protected:
                                       nsACString& aCharset);
   static bool TryDefaultCharset(nsIMarkupDocumentViewer* aMarkupDV,
                                   PRInt32& aCharsetSource,
                                   nsACString& aCharset);
 
   // Override so we can munge the charset on our wyciwyg channel as needed.
   virtual void SetDocumentCharacterSet(const nsACString& aCharSetID);
 
-  // mWriteState tracks the status of this document if the document is being
-  // entirely created by script. In the normal load case, mWriteState will be
-  // eNotWriting. Once document.open has been called (either implicitly or
-  // explicitly), mWriteState will be eDocumentOpened. When document.close has
-  // been called, mWriteState will become eDocumentClosed if there have been no
-  // external script loads in the meantime. If there have been, then mWriteState
-  // becomes ePendingClose, indicating that we might still be writing, but that
-  // we shouldn't process any further close() calls.
-  enum {
-    eNotWriting,
-    eDocumentOpened,
-    ePendingClose,
-    eDocumentClosed
-  } mWriteState;
-
   // Tracks if we are currently processing any document.write calls (either
   // implicit or explicit). Note that if a write call writes out something which
   // would block the parser, then mWriteLevel will be incorrect until the parser
   // finishes processing that script.
   PRUint32 mWriteLevel;
 
-  nsAutoTArray<nsIScriptElement*, 1> mPendingScripts;
-
   // Load flags of the document's channel
   PRUint32 mLoadFlags;
 
   bool mIsFrameset;
 
   bool mTooDeepWriteRecursion;
 
   bool mDisableDocWrite;
--- a/content/html/document/src/nsIHTMLDocument.h
+++ b/content/html/document/src/nsIHTMLDocument.h
@@ -44,19 +44,18 @@
 class nsIDOMHTMLFormElement;
 class nsIContent;
 class nsIScriptElement;
 class nsIEditor;
 class nsContentList;
 class nsWrapperCache;
 
 #define NS_IHTMLDOCUMENT_IID \
-{ 0x51a360fa, 0xd659, 0x4d85, \
-  { 0xa5, 0xc5, 0x4a, 0xbb, 0x0d, 0x97, 0x0f, 0x7a } }
-
+{ 0xa921276f, 0x5e70, 0x42e0, \
+  { 0xb8, 0x36, 0x7e, 0x6a, 0xb8, 0x30, 0xb3, 0xc0 } }
 
 /**
  * HTML document extensions to nsIDocument.
  */
 class nsIHTMLDocument : public nsISupports
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IHTMLDOCUMENT_IID)
@@ -67,28 +66,16 @@ public:
   virtual void SetCompatibilityMode(nsCompatibility aMode) = 0;
 
   virtual nsresult ResolveName(const nsAString& aName,
                                nsIContent *aForm,
                                nsISupports **aResult,
                                nsWrapperCache **aCache) = 0;
 
   /**
-   * Called from the script loader to notify this document that a new
-   * script is being loaded.
-   */
-  virtual void ScriptLoading(nsIScriptElement *aScript) = 0;
-
-  /**
-   * Called from the script loader to notify this document that a script
-   * just finished executing.
-   */
-  virtual void ScriptExecuted(nsIScriptElement *aScript) = 0;
-
-  /**
    * Called when form->BindToTree() is called so that document knows
    * immediately when a form is added
    */
   virtual void AddedForm() = 0;
   /**
    * Called when form->SetDocument() is called so that document knows
    * immediately when a form is removed
    */
--- a/content/xml/document/src/nsXMLContentSink.cpp
+++ b/content/xml/document/src/nsXMLContentSink.cpp
@@ -202,17 +202,17 @@ nsXMLContentSink::WillBuildModel(nsDTDMo
   WillBuildModelImpl();
 
   // Notify document that the load is beginning
   mDocument->BeginLoad();
 
   // Check for correct load-command for maybe prettyprinting
   if (mPrettyPrintXML) {
     nsCAutoString command;
-    mParser->GetCommand(command);
+    GetParser()->GetCommand(command);
     if (!command.EqualsLiteral("view")) {
       mPrettyPrintXML = false;
     }
   }
   
   return NS_OK;
 }
 
@@ -322,17 +322,16 @@ nsXMLContentSink::DidBuildModel(bool aTe
     nsCOMPtr<nsIDOMDocument> currentDOMDoc(do_QueryInterface(mDocument));
     mXSLTProcessor->SetSourceContentModel(currentDOMDoc);
     // Since the processor now holds a reference to us we drop our reference
     // to it to avoid owning cycles
     mXSLTProcessor = nsnull;
   }
   else {
     // Kick off layout for non-XSLT transformed documents.
-    mDocument->ScriptLoader()->RemoveObserver(this);
 
     // Check if we want to prettyprint
     MaybePrettyPrint();
 
     bool startLayout = true;
     
     if (mPrettyPrinting) {
       NS_ASSERTION(!mPendingSheetCount, "Shouldn't have pending sheets here!");
@@ -414,18 +413,16 @@ nsXMLContentSink::OnTransformDone(nsresu
     // document to display.
     mDocument = aResultDocument;
     nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
     if (htmlDoc) {
       htmlDoc->SetDocWriteDisabled(false);
     }
   }
 
-  originalDocument->ScriptLoader()->RemoveObserver(this);
-
   // Notify document observers that all the content has been stuck
   // into the document.  
   // XXX do we need to notify for things like PIs?  Or just the
   // documentElement?
   nsIContent *rootElement = mDocument->GetRootElement();
   if (rootElement) {
     NS_ASSERTION(mDocument->IndexOf(rootElement) != -1,
                  "rootElement not in doc?");
@@ -471,17 +468,17 @@ nsXMLContentSink::WillInterrupt(void)
 
 NS_IMETHODIMP
 nsXMLContentSink::WillResume(void)
 {
   return WillResumeImpl();
 }
 
 NS_IMETHODIMP
-nsXMLContentSink::SetParser(nsIParser* aParser)
+nsXMLContentSink::SetParser(nsParserBase* aParser)
 {
   NS_PRECONDITION(aParser, "Should have a parser here!");
   mParser = aParser;
   return NS_OK;
 }
 
 nsresult
 nsXMLContentSink::CreateElement(const PRUnichar** aAtts, PRUint32 aAttsCount,
@@ -500,17 +497,17 @@ nsXMLContentSink::CreateElement(const PR
   rv = NS_NewElement(getter_AddRefs(content), ni.forget(), aFromParser);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML)
       || aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)
     ) {
     nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(content);
     sele->SetScriptLineNumber(aLineNumber);
-    sele->SetCreatorParser(mParser);
+    sele->SetCreatorParser(GetParser());
     mConstrainSize = false;
   }
 
   // XHTML needs some special attention
   if (aNodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
     mPrettyPrintHasFactoredElements = true;
   }
   else {
@@ -591,31 +588,28 @@ nsXMLContentSink::CloseElement(nsIConten
     mConstrainSize = true; 
     nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aContent);
 
     if (mPreventScriptExecution) {
       sele->PreventExecution();
       return NS_OK;
     }
 
+    // Always check the clock in nsContentSink right after a script
+    StopDeflecting();
+
     // Now tell the script that it's ready to go. This may execute the script
     // or return true, or neither if the script doesn't need executing.
     bool block = sele->AttemptToExecute();
 
-    // If the act of insertion evaluated the script, we're fine.
-    // Else, block the parser till the script has loaded.
-    if (block) {
-      mScriptElements.AppendObject(sele);
-    }
-
     // If the parser got blocked, make sure to return the appropriate rv.
     // I'm not sure if this is actually needed or not.
     if (mParser && !mParser->IsParserEnabled()) {
       // XXX The HTML sink doesn't call BlockParser here, why do we?
-      mParser->BlockParser();
+      GetParser()->BlockParser();
       block = true;
     }
 
     return block ? NS_ERROR_HTMLPARSER_BLOCK : NS_OK;
   }
   
   nsresult rv = NS_OK;
   if (nodeInfo->Equals(nsGkAtoms::meta, kNameSpaceID_XHTML) &&
@@ -627,20 +621,20 @@ nsXMLContentSink::CloseElement(nsIConten