Merge from mozilla-central.
authorJan de Mooij <jdemooij@mozilla.com>
Sat, 21 Jan 2012 17:30:53 +0100
changeset 105648 6ba07330f431d6f08ea4bc8ad067e6fee2e4a979
parent 105647 5f543808812a1625418bfaa18bd90bdccdcb3afe (current diff)
parent 85073 d43360499b86d66d82ed0e585b75bb3237864ad2 (diff)
child 105649 66c3c687e1aaac034df67f3350ba8709bcab5ac7
push id14706
push usereakhgari@mozilla.com
push dateTue, 11 Sep 2012 20:39:52 +0000
treeherdermozilla-inbound@d50bf1edaabe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone12.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge from mozilla-central.
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!");
<