Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Mon, 26 Sep 2011 13:24:58 -0700
changeset 112083 ef5f3216118471534d4950113a5fa49a1be257e0
parent 112082 c11c77e73480f4da194f8115ab67d2ffa63c7517 (current diff)
parent 78883 48df3b328875d17fb3d3eba9b230bb95e3541a0f (diff)
child 112084 1cc1a573bb994b531665dc1468011ec4221f531f
push id239
push userakeybl@mozilla.com
push dateThu, 03 Jan 2013 21:54:43 +0000
treeherdermozilla-release@3a7b66445659 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone9.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge from mozilla-central.
browser/base/content/browser.js
browser/base/content/domplate.jsm
browser/base/content/insideOutBox.js
browser/base/content/inspector.html
browser/base/content/inspector.js
browser/base/content/test/inspector/Makefile.in
browser/base/content/test/inspector/browser_inspector_bug_566084_location_changed.js
browser/base/content/test/inspector/browser_inspector_bug_665880.js
browser/base/content/test/inspector/browser_inspector_editor.js
browser/base/content/test/inspector/browser_inspector_highlighter.js
browser/base/content/test/inspector/browser_inspector_iframeTest.js
browser/base/content/test/inspector/browser_inspector_initialization.js
browser/base/content/test/inspector/browser_inspector_registertools.js
browser/base/content/test/inspector/browser_inspector_scrolling.js
browser/base/content/test/inspector/browser_inspector_store.js
browser/base/content/test/inspector/browser_inspector_tab_switch.js
browser/base/content/test/inspector/browser_inspector_treePanel_click.js
browser/base/content/test/inspector/browser_inspector_treePanel_input.html
browser/base/content/test/inspector/browser_inspector_treePanel_output.js
browser/base/content/test/inspector/browser_inspector_treePanel_result.html
browser/base/content/test/inspector/browser_inspector_treeSelection.js
browser/base/jar.mn
browser/themes/gnomestripe/browser/reload-stop-go.png
browser/themes/pinstripe/browser/Go-arrow.png
browser/themes/pinstripe/browser/places/pageStarred.png
browser/themes/winstripe/browser/Go-arrow-aero.png
browser/themes/winstripe/browser/Go-arrow.png
content/html/content/src/nsGenericHTMLElement.cpp
content/svg/content/src/nsSVGAnimatedTransformList.cpp
content/svg/content/src/nsSVGAnimatedTransformList.h
content/svg/content/src/nsSVGMatrix.cpp
content/svg/content/src/nsSVGMatrix.h
content/svg/content/src/nsSVGSMILTransform.h
content/svg/content/src/nsSVGTransform.cpp
content/svg/content/src/nsSVGTransform.h
content/svg/content/src/nsSVGTransformList.cpp
content/svg/content/src/nsSVGTransformList.h
content/svg/content/src/nsSVGTransformListParser.cpp
content/svg/content/src/nsSVGTransformListParser.h
content/svg/content/src/nsSVGTransformSMILAttr.cpp
content/svg/content/src/nsSVGTransformSMILAttr.h
content/svg/content/src/nsSVGTransformSMILType.cpp
content/svg/content/src/nsSVGTransformSMILType.h
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfoClasses.h
dom/base/nsGlobalWindow.cpp
dom/plugins/base/android_npapi.h
js/src/Makefile.in
js/src/ion/Bailouts.cpp
js/src/ion/IonCompartment.h
js/src/ion/x86/CodeGenerator-x86.cpp
js/src/ion/x86/MacroAssembler-x86.h
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsatom.cpp
js/src/jsbuiltins.h
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jscntxtinlines.h
js/src/jscompartment.cpp
js/src/jsdate.cpp
js/src/jsdbgapi.cpp
js/src/jsemit.cpp
js/src/jsexn.cpp
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsgcinlines.h
js/src/jsgcmark.cpp
js/src/jsinfer.cpp
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/jsiter.cpp
js/src/jsnum.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/jsopcode.cpp
js/src/jsopcode.h
js/src/jsopcode.tbl
js/src/jsparse.cpp
js/src/jsproxy.cpp
js/src/jsprvtd.h
js/src/jspubtd.h
js/src/jsreflect.cpp
js/src/jsregexp.cpp
js/src/jsregexpinlines.h
js/src/jsscope.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsstr.cpp
js/src/jstracer.cpp
js/src/jstracer.h
js/src/jstypedarray.cpp
js/src/jstypedarray.h
js/src/jstypedarrayinlines.h
js/src/jsutil.h
js/src/jsval.h
js/src/jsvalue.h
js/src/jswrapper.cpp
js/src/jsxdrapi.h
js/src/jsxml.cpp
js/src/methodjit/BaseAssembler.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/MethodJIT.h
js/src/methodjit/MonoIC.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls.cpp
js/src/resource.h
js/src/shell/js.cpp
js/src/t/3d-cube.js
js/src/t/3d-morph.js
js/src/t/3d-raytrace.js
js/src/t/access-binary-trees.js
js/src/t/access-fannkuch.js
js/src/t/access-nbody.js
js/src/t/access-nsieve.js
js/src/t/bitops-3bit-bits-in-byte.js
js/src/t/bitops-bits-in-byte.js
js/src/t/bitops-bitwise-and.js
js/src/t/bitops-nsieve-bits.js
js/src/t/controlflow-recursive.js
js/src/t/crypto-aes.js
js/src/t/crypto-md5.js
js/src/t/crypto-sha1.js
js/src/t/date-format-tofte.js
js/src/t/date-format-xparb.js
js/src/t/math-cordic.js
js/src/t/math-partial-sums.js
js/src/t/math-spectral-norm.js
js/src/t/regexp-dna.js
js/src/t/string-base64.js
js/src/t/string-fasta.js
js/src/t/string-tagcloud.js
js/src/t/string-unpack-code.js
js/src/t/string-validate-input.js
js/src/vm/GlobalObject.cpp
js/src/vm/Stack-inl.h
js/src/vm/Stack.h
js/src/xpconnect/src/nsXPConnect.cpp
js/src/xpconnect/src/xpcjsruntime.cpp
js/src/xpconnect/src/xpcprivate.h
js/src/xpconnect/tests/TestXPC.cpp
js/src/xpconnect/tests/components/Makefile.in
js/src/xpconnect/tests/components/xpctest_array.cpp
js/src/xpconnect/tests/components/xpctest_attributes.cpp
js/src/xpconnect/tests/components/xpctest_calljs.cpp
js/src/xpconnect/tests/components/xpctest_child.cpp
js/src/xpconnect/tests/components/xpctest_const.cpp
js/src/xpconnect/tests/components/xpctest_domstring.cpp
js/src/xpconnect/tests/components/xpctest_echo.cpp
js/src/xpconnect/tests/components/xpctest_in.cpp
js/src/xpconnect/tests/components/xpctest_inout.cpp
js/src/xpconnect/tests/components/xpctest_module.cpp
js/src/xpconnect/tests/components/xpctest_multiple.cpp
js/src/xpconnect/tests/components/xpctest_noisy.cpp
js/src/xpconnect/tests/components/xpctest_out.cpp
js/src/xpconnect/tests/components/xpctest_overloaded.cpp
js/src/xpconnect/tests/components/xpctest_private.h
js/src/xpconnect/tests/components/xpctest_string.cpp
js/src/xpconnect/tests/components/xpctest_variant.cpp
js/src/xpconnect/tests/idl/xpctest.idl
js/src/xpconnect/tests/idl/xpctest2.idl
js/src/xpconnect/tests/idl/xpctest_calljs.idl
js/src/xpconnect/tests/idl/xpctest_const.idl
js/src/xpconnect/tests/idl/xpctest_domstring.idl
js/src/xpconnect/tests/idl/xpctest_in.idl
js/src/xpconnect/tests/idl/xpctest_inout.idl
js/src/xpconnect/tests/idl/xpctest_multiple.idl
js/src/xpconnect/tests/idl/xpctest_out.idl
js/src/xpconnect/tests/js/readwriteattributes.js
media/libsydneyaudio/bug495558_alsa_endian.patch
media/libsydneyaudio/bug495794_closeAudio.patch
media/libsydneyaudio/bug525401_drain_deadlock.patch
media/libsydneyaudio/bug562488_oss_destroy_crash.patch
media/libsydneyaudio/bug564734-win32-drain.patch
media/libsydneyaudio/include-CoreServices.patch
media/libsydneyaudio/pause-resume.patch
media/libsydneyaudio/sydney_aix.patch
media/libsydneyaudio/sydney_android.patch
media/libsydneyaudio/sydney_os2_base.patch
media/libsydneyaudio/sydney_os2_moz.patch
media/libsydneyaudio/update.sh
mobile/components/WebappsSupport.idl
mobile/components/WebappsSupport.js
mobile/themes/core/honeycomb/images/endcap-active-bg.png
mobile/themes/core/honeycomb/images/endcap-default-bg.png
mobile/themes/core/honeycomb/images/endcap-ev-active-bg.png
mobile/themes/core/honeycomb/images/endcap-ev-default-bg.png
mobile/themes/core/honeycomb/images/endcap-ssl-active-bg.png
mobile/themes/core/honeycomb/images/endcap-ssl-default-bg.png
modules/libpref/src/init/all.js
modules/libreg/Makefile.in
modules/libreg/include/NSReg.h
modules/libreg/include/VerReg.h
modules/libreg/src/Makefile.in
modules/libreg/src/VerReg.c
modules/libreg/src/nr_bufio.c
modules/libreg/src/reg.c
modules/libreg/src/reg.h
modules/libreg/src/vr_stubs.c
modules/libreg/src/vr_stubs.h
modules/zlib/standalone/Makefile.in
netwerk/test/unit/test_bug477578.js
testing/mochitest/specialpowers/content/specialpowers.js
--- a/accessible/public/ia2/Makefile.in
+++ b/accessible/public/ia2/Makefile.in
@@ -44,17 +44,17 @@ LIBRARY_NAME  = IA2Marshal
 MODULE        = accessibility
 GRE_MODULE    = 1
 DEFFILE       = $(win_srcdir)/IA2Marshal.def
 
 IA2DIR        = $(topsrcdir)/other-licenses/ia2
 
 include $(DEPTH)/config/autoconf.mk
 
-DEFINES       += -DREGISTER_PROXY_DLL -D_WIN32_WINNT=0x400
+DEFINES       += -DREGISTER_PROXY_DLL
 
 GARBAGE       += $(MIDL_GENERATED_FILES)
 
 FORCE_SHARED_LIB = 1
 
 SRCS_IN_OBJDIR   = 1
 
 MIDL_INTERFACES = \
--- a/accessible/public/msaa/Makefile.in
+++ b/accessible/public/msaa/Makefile.in
@@ -48,17 +48,17 @@ DEFFILE = $(win_srcdir)/AccessibleMarsha
 
 include $(DEPTH)/config/autoconf.mk
 
 XPIDLSRCS = \
       nsIAccessibleWin32Object.idl \
       nsIWinAccessNode.idl \
       $(NULL)
 
-DEFINES		+= -DREGISTER_PROXY_DLL -D_WIN32_WINNT=0x400
+DEFINES += -DREGISTER_PROXY_DLL
 
 GARBAGE += $(MIDL_GENERATED_FILES) done_gen dlldata.c
 
 FORCE_SHARED_LIB = 1
 
 SRCS_IN_OBJDIR	= 1
 
 CSRCS	= \
--- a/browser/base/Makefile.in
+++ b/browser/base/Makefile.in
@@ -51,17 +51,16 @@ CHROME_DEPS += $(abs_srcdir)/content/ove
 
 ifdef ENABLE_TESTS
 DIRS += content/test
 endif
 
 EXTRA_JS_MODULES = \
 	content/openLocationLastURL.jsm \
 	content/NetworkPrioritizer.jsm \
-	content/domplate.jsm \
 	$(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
 PRE_RELEASE_SUFFIX := ""
 
 DEFINES += \
 	-DMOZ_APP_VERSION=$(MOZ_APP_VERSION) \
--- a/browser/base/content/browser-context.inc
+++ b/browser/base/content/browser-context.inc
@@ -16,16 +16,18 @@
 #
 # The Initial Developer of the Original Code is
 # Netscape Communications Corporation.
 # Portions created by the Initial Developer are Copyright (C) 2001
 # the Initial Developer. All Rights Reserved.
 #
 # Contributor(s):
 #   Ehsan Akhgari <ehsan.akhgari@gmail.com>
+#   Rob Campbell <rcampbell@mozilla.com>
+#   Panagiotis Astithas <past@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
@@ -335,8 +337,14 @@
       <menuitem hidden="true" id="context-bidi-text-direction-toggle"
                 label="&bidiSwitchTextDirectionItem.label;"
                 accesskey="&bidiSwitchTextDirectionItem.accesskey;"
                 command="cmd_switchTextDirection"/>
       <menuitem hidden="true" id="context-bidi-page-direction-toggle"
                 label="&bidiSwitchPageDirectionItem.label;"
                 accesskey="&bidiSwitchPageDirectionItem.accesskey;"
                 oncommand="gContextMenu.switchPageDirection();"/>
+      <menuseparator id="inspect-separator" hidden="true"/>
+      <menuitem id="context-inspect"
+                hidden="true"
+                label="&inspectContextMenu.label;"
+                accesskey="&inspectContextMenu.accesskey;"
+                oncommand="gContextMenu.inspectNode();"/>
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -522,14 +522,18 @@ statuspanel[label=""] {
 }
 
 .statuspanel-inner {
   height: 3em;
   width: 100%;
   -moz-box-align: end;
 }
 
+.styleInspector {
+  min-width: 350px;
+}
+
 .panel-inner-arrowcontentfooter[footertype="promobox"] {
   -moz-binding: url("chrome://browser/content/urlbarBindings.xml#promobox");
 }
 
 /* highlighter */
 %include highlighter.css
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -175,17 +175,17 @@ XPCOMUtils.defineLazyGetter(this, "Popup
 
 let gInitialPages = [
   "about:blank",
   "about:privatebrowsing",
   "about:sessionrestore"
 ];
 
 #include browser-fullZoom.js
-#include inspector.js
+#include ../../devtools/highlighter/inspector.js
 #include browser-places.js
 #include browser-tabPreviews.js
 #include browser-tabview.js
 
 #ifdef MOZ_SERVICES_SYNC
 #include browser-syncui.js
 #endif
 
@@ -1671,18 +1671,17 @@ function delayedStartup(isLoadingBlank, 
 #ifdef MOZ_SERVICES_SYNC
   // initialize the sync UI
   gSyncUI.init();
 #endif
 
   TabView.init();
 
   // Enable Inspector?
-  let enabled = gPrefService.getBoolPref(InspectorUI.prefEnabledName);
-  if (enabled) {
+  if (InspectorUI.enabled) {
     document.getElementById("menu_pageinspect").hidden = false;
     document.getElementById("Tools:Inspect").removeAttribute("disabled");
 #ifdef MENUBAR_CAN_AUTOHIDE
     document.getElementById("appmenu_pageInspect").hidden = false;
 #endif
   }
 
   // Enable Error Console?
deleted file mode 100644
--- a/browser/base/content/insideOutBox.js
+++ /dev/null
@@ -1,646 +0,0 @@
-/*
- * Software License Agreement (BSD License)
- *
- * Copyright (c) 2007, Parakey Inc.
- * All rights reserved.
- * 
- * Redistribution and use of this software in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * 
- * * Redistributions of source code must retain the above
- *   copyright notice, this list of conditions and the
- *   following disclaimer.
- * 
- * * Redistributions in binary form must reproduce the above
- *   copyright notice, this list of conditions and the
- *   following disclaimer in the documentation and/or other
- *   materials provided with the distribution.
- * 
- * * Neither the name of Parakey Inc. nor the names of its
- *   contributors may be used to endorse or promote products
- *   derived from this software without specific prior
- *   written permission of Parakey Inc.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * Creator:
- *  Joe Hewitt
- * Contributors
- *  John J. Barton (IBM Almaden)
- *  Jan Odvarko (Mozilla Corp.)
- *  Max Stepanov (Aptana Inc.)
- *  Rob Campbell (Mozilla Corp.)
- *  Hans Hillen (Paciello Group, Mozilla)
- *  Curtis Bartley (Mozilla Corp.)
- *  Mike Collins (IBM Almaden)
- *  Kevin Decker
- *  Mike Ratcliffe (Comartis AG)
- *  Hernan Rodríguez Colmeiro
- *  Austin Andrews
- *  Christoph Dorn
- *  Steven Roussey (AppCenter Inc, Network54)
- */
-
-///////////////////////////////////////////////////////////////////////////
-//// InsideOutBox
-
-/**
- * InsideOutBoxView is a simple interface definition for views implementing
- * InsideOutBox controls. All implementors must define these methods.
- * Implemented in InspectorUI.
- */
-
-/*
-InsideOutBoxView = {
-  //
-   * Retrieves the parent object for a given child object.
-   * @param aChild
-   *        The child node to retrieve the parent object for.
-   * @returns a DOM node | null
-   //
-  getParentObject: function(aChild) {},
-
-  //
-   * Retrieves a given child node.
-   *
-   * If both index and previousSibling are passed, the implementation
-   * may assume that previousSibling will be the return for getChildObject
-   * with index-1.
-   * @param aParent
-   *        The parent object of the child object to retrieve.
-   * @param aIndex
-   *        The index of the child object to retrieve from aParent.
-   * @param aPreviousSibling
-   *        The previous sibling of the child object to retrieve.
-   *        Supercedes aIndex.
-   * @returns a DOM object | null
-   //
-  getChildObject: function(aParent, aIndex, aPreviousSibling) {},
-
-  //
-   * Renders the HTML representation of the object. Should return an HTML
-   * object which will be displayed to the user.
-   * @param aObject
-   *        The object to create the box object for.
-   * @param aIsRoot
-   *        Is the object the root object. May not be used in all
-   *        implementations.
-   * @returns an object box | null
-   //
-  createObjectBox: function(aObject, aIsRoot) {},
-
-  //
-  * Convenience wrappers for classList API.
-  * @param aObject
-  *        DOM node to query/set.
-  * @param aClassName
-  *        String containing the class name to query/set.
-  //
-  hasClass: function(aObject, aClassName) {},
-  addClass: function(aObject, aClassName) {},
-  removeClass: function(aObject, aClassName) {}
-};
-*/
-
-/**
- * Creates a tree based on objects provided by a separate "view" object.
- *
- * Construction uses an "inside-out" algorithm, meaning that the view's job is
- * first to tell us the ancestry of each object, and secondarily its
- * descendants.
- *
- * Constructor
- * @param aView
- *        The view requiring the InsideOutBox.
- * @param aBox
- *        The box object containing the InsideOutBox. Required to add/remove
- *        children during box manipulation (toggling opened or closed).
- */
-function InsideOutBox(aView, aBox)
-{
-  this.view = aView;
-  this.box = aBox;
-
-  this.rootObject = null;
-
-  this.rootObjectBox = null;
-  this.selectedObjectBox = null;
-  this.highlightedObjectBox = null;
-  this.scrollIntoView = false;
-};
-
-InsideOutBox.prototype =
-{
-  /**
-   * Highlight the given object node in the tree.
-   * @param aObject
-   *        the object to highlight.
-   * @returns objectBox
-   */
-  highlight: function IOBox_highlight(aObject)
-  {
-    let objectBox = this.createObjectBox(aObject);
-    this.highlightObjectBox(objectBox);
-    return objectBox;
-  },
-
-  /**
-   * Open the given object node in the tree.
-   * @param aObject
-   *        The object node to open.
-   * @returns objectBox
-   */
-  openObject: function IOBox_openObject(aObject)
-  {
-    let object = aObject;
-    let firstChild = this.view.getChildObject(object, 0);
-    if (firstChild)
-      object = firstChild;
-
-    return this.openToObject(object);
-  },
-
-  /**
-   * Open the tree up to the given object node.
-   * @param aObject
-   *        The object in the tree to open to.
-   * @returns objectBox
-   */
-  openToObject: function IOBox_openToObject(aObject)
-  {
-    let objectBox = this.createObjectBox(aObject);
-    this.openObjectBox(objectBox);
-    return objectBox;
-  },
-
-  /**
-   * Select the given object node in the tree.
-   * @param aObject
-   *        The object node to select.
-   * @param makeBoxVisible
-   *        Boolean. Open the object box in the tree?
-   * @param forceOpen
-   *        Force the object box open by expanding all elements in the tree?
-   * @param scrollIntoView
-   *        Scroll the objectBox into view?
-   * @returns nsIDOMNode|null
-   *          A DOM node that represents the "object box", the element that
-   *          holds/displays the given aObject representation in the tree. If
-   *          the object cannot be selected, if it is a stale object, null is
-   *          returned.
-   */
-  select:
-  function IOBox_select(aObject, makeBoxVisible, forceOpen, scrollIntoView)
-  {
-    let objectBox = this.createObjectBox(aObject);
-    if (!objectBox) {
-      return null;
-    }
-    this.selectObjectBox(objectBox, forceOpen);
-    if (makeBoxVisible) {
-      this.openObjectBox(objectBox);
-      if (scrollIntoView) {
-        objectBox.scrollIntoView(true);
-      }
-    }
-    return objectBox;
-  },
-
-  /**
-   * Expands/contracts the given object, depending on its state.
-   * @param aObject
-   *        The tree node to expand/contract.
-   */
-  toggleObject: function IOBox_toggleObject(aObject)
-  {
-    let box = this.createObjectBox(aObject);
-    if (!(this.view.hasClass(box, "open")))
-      this.expandObjectBox(box);
-    else
-      this.contractObjectBox(box);
-  },
-
-  /**
-   * Expand the given object in the tree.
-   * @param aObject
-   *        The tree node to expand.
-   */
-  expandObject: function IOBox_expandObject(aObject)
-  {
-    let objectBox = this.createObjectBox(aObject);
-    if (objectBox)
-      this.expandObjectBox(objectBox);
-  },
-
-  /**
-   * Contract the given object in the tree.
-   * @param aObject
-   *        The tree node to contract.
-   */
-  contractObject: function IOBox_contractObject(aObject)
-  {
-    let objectBox = this.createObjectBox(aObject);
-    if (objectBox)
-      this.contractObjectBox(objectBox);
-  },
-
-  /**
-   * General method for iterating over an object's ancestors and performing
-   * some function.
-   * @param aObject
-   *        The object whose ancestors we wish to iterate over.
-   * @param aCallback
-   *        The function to call with the object as argument.
-   */
-
-  iterateObjectAncestors: function IOBox_iterateObjectAncesors(aObject, aCallback)
-  {
-    let object = aObject;
-    if (!(aCallback && typeof(aCallback) == "function")) {
-      this.view._log("Illegal argument in IOBox.iterateObjectAncestors");
-      return;
-    }
-    while ((object = this.getParentObjectBox(object)))
-      aCallback(object);
-  },
-
-  /**
-   * Highlight the given objectBox in the tree.
-   * @param aObjectBox
-   *        The objectBox to highlight.
-   */
-  highlightObjectBox: function IOBox_highlightObjectBox(aObjectBox)
-  {
-    let self = this;
-
-    if (!aObjectBox)
-      return;
-
-    if (this.highlightedObjectBox) {
-      this.view.removeClass(this.highlightedObjectBox, "highlighted");
-      this.iterateObjectAncestors(this.highlightedObjectBox, function (box) {
-        self.view.removeClass(box, "highlightOpen");
-      });
-    }
-
-    this.highlightedObjectBox = aObjectBox;
-
-    this.view.addClass(aObjectBox, "highlighted");
-    this.iterateObjectAncestors(this.highlightedObjectBox, function (box) {
-      self.view.addClass(box, "highlightOpen");
-    });
-
-    aObjectBox.scrollIntoView(true);
-  },
-
-  /**
-   * Select the given objectBox in the tree, forcing it to be open if necessary.
-   * @param aObjectBox
-   *        The objectBox to select.
-   * @param forceOpen
-   *        Force the box (subtree) to be open?
-   */
-  selectObjectBox: function IOBox_selectObjectBox(aObjectBox, forceOpen)
-  {
-    let isSelected = this.selectedObjectBox &&
-      aObjectBox == this.selectedObjectBox;
-
-    // aObjectBox is already selected, return
-    if (isSelected)
-      return;
-
-    if (this.selectedObjectBox)
-      this.view.removeClass(this.selectedObjectBox, "selected");
-
-    this.selectedObjectBox = aObjectBox;
-
-    if (aObjectBox) {
-      this.view.addClass(aObjectBox, "selected");
-
-      // Force it open the first time it is selected
-      if (forceOpen)
-        this.expandObjectBox(aObjectBox, true);
-    }
-  },
-
-  /**
-   * Open the ancestors of the given object box.
-   * @param aObjectBox
-   *        The object box to open.
-   */
-  openObjectBox: function IOBox_openObjectBox(aObjectBox)
-  {
-    if (!aObjectBox)
-      return;
-
-    let self = this;
-    this.iterateObjectAncestors(aObjectBox, function (box) {
-      self.view.addClass(box, "open");
-      let labelBox = box.querySelector(".nodeLabelBox");
-      if (labelBox)
-        labelBox.setAttribute("aria-expanded", "true");
-   });
-  },
-
-  /**
-   * Expand the given object box.
-   * @param aObjectBox
-   *        The object box to expand.
-   */
-  expandObjectBox: function IOBox_expandObjectBox(aObjectBox)
-  {
-    let nodeChildBox = this.getChildObjectBox(aObjectBox);
-
-    // no children means nothing to expand, return
-    if (!nodeChildBox)
-      return;
-
-    if (!aObjectBox.populated) {
-      let firstChild = this.view.getChildObject(aObjectBox.repObject, 0);
-      this.populateChildBox(firstChild, nodeChildBox);
-    }
-    let labelBox = aObjectBox.querySelector(".nodeLabelBox");
-    if (labelBox)
-      labelBox.setAttribute("aria-expanded", "true");
-    this.view.addClass(aObjectBox, "open");
-  },
-
-  /**
-   * Contract the given object box.
-   * @param aObjectBox
-   *        The object box to contract.
-   */
-  contractObjectBox: function IOBox_contractObjectBox(aObjectBox)
-  {
-    this.view.removeClass(aObjectBox, "open");
-    let nodeLabel = aObjectBox.querySelector(".nodeLabel");
-    let labelBox = nodeLabel.querySelector(".nodeLabelBox");
-    if (labelBox)
-      labelBox.setAttribute("aria-expanded", "false");
-  },
-
-  /**
-   * Toggle the given object box, forcing open if requested.
-   * @param aObjectBox
-   *        The object box to toggle.
-   * @param forceOpen
-   *        Force the objectbox open?
-   */
-  toggleObjectBox: function IOBox_toggleObjectBox(aObjectBox, forceOpen)
-  {
-    let isOpen = this.view.hasClass(aObjectBox, "open");
-
-    if (!forceOpen && isOpen)
-      this.contractObjectBox(aObjectBox);
-    else if (!isOpen)
-      this.expandObjectBox(aObjectBox);
-  },
-
-  /**
-   * Creates all of the boxes for an object, its ancestors, and siblings.
-   * @param aObject
-   *        The tree node to create the object boxes for.
-   * @returns anObjectBox or null
-   */
-  createObjectBox: function IOBox_createObjectBox(aObject)
-  {
-    if (!aObject)
-      return null;
-
-    this.rootObject = this.getRootNode(aObject) || aObject;
-
-    // Get or create all of the boxes for the target and its ancestors
-    let objectBox = this.createObjectBoxes(aObject, this.rootObject);
-
-    if (!objectBox)
-      return null;
-
-    if (aObject == this.rootObject)
-      return objectBox;
-
-    return this.populateChildBox(aObject, objectBox.parentNode);
-  },
-
-  /**
-   * Creates all of the boxes for an object, its ancestors, and siblings up to
-   * a root.
-   * @param aObject
-   *        The tree's object node to create the object boxes for.
-   * @param aRootObject
-   *        The root object at which to stop building object boxes.
-   * @returns an object box or null
-   */
-  createObjectBoxes: function IOBox_createObjectBoxes(aObject, aRootObject)
-  {
-    if (!aObject)
-      return null;
-
-    if (aObject == aRootObject) {
-      if (!this.rootObjectBox || this.rootObjectBox.repObject != aRootObject) {
-        if (this.rootObjectBox) {
-          try {
-            this.box.removeChild(this.rootObjectBox);
-          } catch (exc) {
-            InspectorUI._log("this.box.removeChild(this.rootObjectBox) FAILS " +
-              this.box + " must not contain " + this.rootObjectBox);
-          }
-        }
-
-        this.highlightedObjectBox = null;
-        this.selectedObjectBox = null;
-        this.rootObjectBox = this.view.createObjectBox(aObject, true);
-        this.box.appendChild(this.rootObjectBox);
-      }
-      return this.rootObjectBox;
-    }
-
-    let parentNode = this.view.getParentObject(aObject);
-    let parentObjectBox = this.createObjectBoxes(parentNode, aRootObject);
-
-    if (!parentObjectBox)
-      return null;
-
-    let parentChildBox = this.getChildObjectBox(parentObjectBox);
-
-    if (!parentChildBox)
-      return null;
-
-    let childObjectBox = this.findChildObjectBox(parentChildBox, aObject);
-
-    return childObjectBox ? childObjectBox
-      : this.populateChildBox(aObject, parentChildBox);
-  },
-
-  /**
-   * Locate the object box for a given object node.
-   * @param aObject
-   *        The given object node in the tree.
-   * @returns an object box or null.
-   */
-  findObjectBox: function IOBox_findObjectBox(aObject)
-  {
-    if (!aObject)
-      return null;
-
-    if (aObject == this.rootObject)
-      return this.rootObjectBox;
-
-    let parentNode = this.view.getParentObject(aObject);
-    let parentObjectBox = this.findObjectBox(parentNode);
-    if (!parentObjectBox)
-      return null;
-
-    let parentChildBox = this.getChildObjectBox(parentObjectBox);
-    if (!parentChildBox)
-      return null;
-
-    return this.findChildObjectBox(parentChildBox, aObject);
-  },
-
-  getAncestorByClass: function IOBox_getAncestorByClass(node, className)
-  {
-    for (let parent = node; parent; parent = parent.parentNode) {
-      if (this.view.hasClass(parent, className))
-        return parent;
-    }
-
-    return null;
-  },
-
-  /**
-   * We want all children of the parent of repObject.
-   */
-  populateChildBox: function IOBox_populateChildBox(repObject, nodeChildBox)
-  {
-    if (!repObject)
-      return null;
-
-    let parentObjectBox = this.getAncestorByClass(nodeChildBox, "nodeBox");
-
-    if (parentObjectBox.populated)
-      return this.findChildObjectBox(nodeChildBox, repObject);
-
-    let lastSiblingBox = this.getChildObjectBox(nodeChildBox);
-    let siblingBox = nodeChildBox.firstChild;
-    let targetBox = null;
-    let view = this.view;
-    let targetSibling = null;
-    let parentNode = view.getParentObject(repObject);
-
-    for (let i = 0; 1; ++i) {
-      targetSibling = view.getChildObject(parentNode, i, targetSibling);
-      if (!targetSibling)
-        break;
-
-      // Check if we need to start appending, or continue to insert before
-      if (lastSiblingBox && lastSiblingBox.repObject == targetSibling)
-        lastSiblingBox = null;
-
-      if (!siblingBox || siblingBox.repObject != targetSibling) {
-        let newBox = view.createObjectBox(targetSibling);
-        if (newBox) {
-          if (lastSiblingBox)
-            nodeChildBox.insertBefore(newBox, lastSiblingBox);
-          else
-            nodeChildBox.appendChild(newBox);
-        }
-
-        siblingBox = newBox;
-      }
-
-      if (targetSibling == repObject)
-        targetBox = siblingBox;
-
-      if (siblingBox && siblingBox.repObject == targetSibling)
-        siblingBox = siblingBox.nextSibling;
-    }
-
-    if (targetBox)
-      parentObjectBox.populated = true;
-
-    return targetBox;
-  },
-
-  /**
-   * Get the parent object box of a given object box.
-   * @params aObjectBox
-   *         The object box of the parent.
-   * @returns an object box or null
-   */
-  getParentObjectBox: function IOBox_getParentObjectBox(aObjectBox)
-  {
-    let parent = aObjectBox.parentNode ? aObjectBox.parentNode.parentNode : null;
-    return parent && parent.repObject ? parent : null;
-  },
-
-  /**
-   * Get the child object box of a given object box.
-   * @param aObjectBox
-   *        The object box whose child you want.
-   * @returns an object box or null
-   */
-  getChildObjectBox: function IOBox_getChildObjectBox(aObjectBox)
-  {
-    return aObjectBox.querySelector(".nodeChildBox");
-  },
-
-  /**
-   * Find the child object box for a given repObject within the subtree
-   * rooted at aParentNodeBox.
-   * @param aParentNodeBox
-   *        root of the subtree in which to search for repObject.
-   * @param aRepObject
-   *        The object you wish to locate in the subtree.
-   * @returns an object box or null
-   */
-  findChildObjectBox: function IOBox_findChildObjectBox(aParentNodeBox, aRepObject)
-  {
-    let childBox = aParentNodeBox.firstChild;
-    while (childBox) {
-      if (childBox.repObject == aRepObject)
-        return childBox;
-      childBox = childBox.nextSibling;
-    }
-    return null; // not found
-  },
-
-  /**
-   * Determines if the given node is an ancestor of the current root.
-   * @param aNode
-   *        The node to look for within the tree.
-   * @returns boolean
-   */
-  isInExistingRoot: function IOBox_isInExistingRoot(aNode)
-  {
-    let parentNode = aNode;
-    while (parentNode && parentNode != this.rootObject) {
-      parentNode = this.view.getParentObject(parentNode);
-    }
-    return parentNode == this.rootObject;
-  },
-
-  /**
-   * Get the root node of a given node.
-   * @param aNode
-   *        The node whose root you wish to retrieve.
-   * @returns a root node or null
-   */
-  getRootNode: function IOBox_getRootNode(aNode)
-  {
-    let node = aNode;
-    let tmpNode;
-    while ((tmpNode = this.view.getParentObject(node)))
-      node = tmpNode;
-
-    return node;
-  },
-};
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -41,16 +41,17 @@
 #   Simon Bünzli <zeniko@gmail.com>
 #   Gijs Kruitbosch <gijskruitbosch@gmail.com>
 #   Ehsan Akhgari <ehsan.akhgari@gmail.com>
 #   Dan Mosedale <dmose@mozilla.org>
 #   Justin Dolske <dolske@mozilla.com>
 #   Kathleen Brade <brade@pearlcrescent.com>
 #   Mark Smith <mcs@pearlcrescent.com>
 #   Kailas Patil <patilkr24@gmail.com>
+#   Rob Campbell <rcampbell@mozilla.com>
 #
 # Alternatively, the contents of this file may be used under the terms of
 # either the GNU General Public License Version 2 or later (the "GPL"), or
 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 # in which case the provisions of the GPL or the LGPL are applicable instead
 # of those above. If you wish to allow use of your version of this file only
 # under the terms of either the GPL or the LGPL, and not to allow others to
 # use your version of this file under the terms of the MPL, indicate your
@@ -239,18 +240,21 @@ nsContextMenu.prototype = {
                   this.isContentSelected);
     this.showItem("context-viewpartialsource-mathml",
                   this.onMathML && !this.isContentSelected);
 
     var shouldShow = !(this.isContentSelected ||
                        this.onImage || this.onCanvas ||
                        this.onVideo || this.onAudio ||
                        this.onLink || this.onTextInput);
+    var showInspect = gPrefService.getBoolPref("devtools.inspector.enabled");
     this.showItem("context-viewsource", shouldShow);
     this.showItem("context-viewinfo", shouldShow);
+    this.showItem("inspect-separator", showInspect);
+    this.showItem("context-inspect", showInspect);
 
     this.showItem("context-sep-viewsource", shouldShow);
 
     // Set as Desktop background depends on whether an image was clicked on,
     // and only works if we have a shell service.
     var haveSetDesktopBackground = false;
 #ifdef HAVE_SHELL_SERVICE
     // Only enable Set as Desktop Background if we can get the shell service.
@@ -424,16 +428,25 @@ nsContextMenu.prototype = {
       this.setItemAttr("context-media-showcontrols", "disabled", hasError);
       this.setItemAttr("context-media-hidecontrols", "disabled", hasError);
       if (this.onVideo)
         this.setItemAttr("context-video-fullscreen",  "disabled", hasError);
     }
     this.showItem("context-media-sep-commands",  onMedia);
   },
 
+  inspectNode: function CM_inspectNode() {
+    if (InspectorUI.isTreePanelOpen) {
+      InspectorUI.inspectNode(this.target);
+      InspectorUI.stopInspecting();
+    } else {
+      InspectorUI.openInspectorUI(this.target);
+    }
+  },
+
   // Set various context menu attributes based on the state of the world.
   setTarget: function (aNode, aRangeParent, aRangeOffset) {
     const xulNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
     if (aNode.namespaceURI == xulNS ||
         aNode.nodeType == Node.DOCUMENT_NODE ||
         this.isTargetAFormControl(aNode)) {
       this.shouldDisplay = false;
       return;
--- a/browser/base/content/syncSetup.js
+++ b/browser/base/content/syncSetup.js
@@ -595,16 +595,19 @@ var gSyncSetup = {
   },
 
   startEasySetup: function () {
     // Don't do anything if we have a client already (e.g. we went to
     // Sync Options and just came back).
     if (this._jpakeclient)
       return;
 
+    // When onAbort is called, Weave may already be gone
+    const JPAKE_ERROR_USERABORT = Weave.JPAKE_ERROR_USERABORT;
+
     let self = this;
     this._jpakeclient = new Weave.JPAKEClient({
       displayPIN: function displayPIN(pin) {
         document.getElementById("easySetupPIN1").value = pin.slice(0, 4);
         document.getElementById("easySetupPIN2").value = pin.slice(4, 8);
         document.getElementById("easySetupPIN3").value = pin.slice(8);
       },
 
@@ -614,18 +617,18 @@ var gSyncSetup = {
         Weave.Service.passphrase = credentials.synckey;
         Weave.Service.serverURL = credentials.serverURL;
         self.wizard.pageIndex = SETUP_SUCCESS_PAGE;
       },
 
       onAbort: function onAbort(error) {
         delete self._jpakeclient;
 
-        // No error means manual abort, e.g. wizard is aborted. Ignore.
-        if (!error)
+        // Ignore if wizard is aborted.
+        if (error == JPAKE_ERROR_USERABORT)
           return;
 
         // Automatically go to manual setup if we couldn't acquire a channel.
         if (error == Weave.JPAKE_ERROR_CHANNEL) {
           self.wizard.pageIndex = EXISTING_ACCOUNT_LOGIN_PAGE;
           return;
         }
 
--- a/browser/base/content/tabview/groupitems.js
+++ b/browser/base/content/tabview/groupitems.js
@@ -487,40 +487,39 @@ GroupItem.prototype = Utils.extend(new I
   // ----------
   // Function: getContentBounds
   // Returns a <Rect> for the groupItem's content area (which doesn't include the title, etc).
   //
   // Parameters:
   //   options - an object with additional parameters, see below
   //
   // Possible options:
-  //   forceStacked - true to force content bounds for stacked mode
+  //   stacked - true to get content bounds for stacked mode
   getContentBounds: function GroupItem_getContentBounds(options) {
-    var box = this.getBounds();
-    var titleHeight = this.$titlebar.height();
+    let box = this.getBounds();
+    let titleHeight = this.$titlebar.height();
     box.top += titleHeight;
     box.height -= titleHeight;
 
     let appTabTrayContainer = iQ(this.$appTabTray[0].parentNode);
-    var appTabTrayWidth = appTabTrayContainer.width();
+    let appTabTrayWidth = appTabTrayContainer.width();
     if (appTabTrayWidth)
       appTabTrayWidth += parseInt(appTabTrayContainer.css(UI.rtl ? "left" : "right"));
 
     box.width -= appTabTrayWidth;
     if (UI.rtl) {
       box.left += appTabTrayWidth;
     }
 
     // Make the computed bounds' "padding" and expand button margin actually be
     // themeable --OR-- compute this from actual bounds. Bug 586546
     box.inset(6, 6);
 
-    // make some room for the expand button if we're stacked
-    let isStacked = (options && options.forceStacked) || this.isStacked();
-    if (isStacked)
+    // make some room for the expand button in stacked mode
+    if (options && options.stacked)
       box.height -= this.$expander.height() + 9; // the button height plus padding
 
     return box;
   },
 
   // ----------
   // Function: setBounds
   // Sets the bounds with the given <Rect>, animating unless "immediately" is false.
@@ -1291,18 +1290,18 @@ GroupItem.prototype = Utils.extend(new I
   // ----------
   // Function: shouldStack
   // Returns true if the groupItem, given "count", should stack (instead of 
   // grid).
   shouldStack: function GroupItem_shouldStack(count) {
     if (count <= 1)
       return false;
 
-    var bb = this.getContentBounds();
-    var options = {
+    let bb = this.getContentBounds();
+    let options = {
       return: 'widthAndColumns',
       count: count || this._children.length,
       hideTitle: false
     };
     let arrObj = Items.arrange(this._children, bb, options);
 
     let shouldStack = arrObj.childWidth < TabItems.minTabWidth * 1.35;
     this._columns = shouldStack ? null : arrObj.columns;
@@ -1398,30 +1397,30 @@ GroupItem.prototype = Utils.extend(new I
       else
         childrenToArrange.push(child);
     });
 
     if (GroupItems._arrangePaused) {
       GroupItems.pushArrange(this, options);
       return false;
     }
-    
+
     let shouldStack = this.shouldStack(childrenToArrange.length + (options.addTab ? 1 : 0));
     let shouldStackArrange = (shouldStack && !this.expanded);
     let box;
 
     // if we should stack and we're not expanded
     if (shouldStackArrange) {
       this.showExpandControl();
-      box = this.getContentBounds({forceStacked: true});
+      box = this.getContentBounds({stacked: true});
       this._stackArrange(childrenToArrange, box, options);
       return false;
     } else {
       this.hideExpandControl();
-      box = this.getContentBounds({forceStacked: false});
+      box = this.getContentBounds();
       // a dropIndex is returned
       return this._gridArrange(childrenToArrange, box, options);
     }
   },
 
   // ----------
   // Function: _stackArrange
   // Arranges the children in a stack.
--- a/browser/base/content/tabview/tabitems.js
+++ b/browser/base/content/tabview/tabitems.js
@@ -218,21 +218,25 @@ TabItem.prototype = Utils.extend(new Ite
     if (this._cachedImageData)
       this._cachedImageData = null;
   },
 
   // ----------
   // Function: getStorageData
   // Get data to be used for persistent storage of this object.
   getStorageData: function TabItem_getStorageData() {
-    return {
+    let data = {
       url: this.tab.linkedBrowser.currentURI.spec,
       groupID: (this.parent ? this.parent.id : 0),
       title: this.tab.label
     };
+    if (this.parent.getActiveTab() == this)
+      data.active = true;
+
+    return data;
   },
 
   // ----------
   // Function: save
   // Store persistent for this object.
   save: function TabItem_save() {
     try {
       if (!this.tab || this.tab.parentNode == null || !this._reconnected) // too soon/late to save
@@ -334,50 +338,53 @@ TabItem.prototype = Utils.extend(new Ite
   // ----------
   // Function: _reconnect
   // Load the reciever's persistent data from storage. If there is none, 
   // treats it as a new tab. 
   _reconnect: function TabItem__reconnect() {
     Utils.assertThrow(!this._reconnected, "shouldn't already be reconnected");
     Utils.assertThrow(this.tab, "should have a xul:tab");
 
-    let self = this;
     let tabData = Storage.getTabData(this.tab);
 
     if (tabData && TabItems.storageSanity(tabData)) {
       this.loadThumbnail(tabData);
 
-      if (self.parent)
-        self.parent.remove(self, {immediately: true});
+      if (this.parent)
+        this.parent.remove(this, {immediately: true});
 
       let groupItem;
 
       if (tabData.groupID) {
         groupItem = GroupItems.groupItem(tabData.groupID);
       } else {
         groupItem = new GroupItem([], {immediately: true, bounds: tabData.bounds});
       }
 
       if (groupItem) {
-        groupItem.add(self, {immediately: true});
+        groupItem.add(this, {immediately: true});
+
+        // restore the active tab for each group between browser sessions
+        if (tabData.active)
+          groupItem.setActiveTab(this);
 
         // if it matches the selected tab or no active tab and the browser
         // tab is hidden, the active group item would be set.
-        if (self.tab == gBrowser.selectedTab ||
-            (!GroupItems.getActiveGroupItem() && !self.tab.hidden))
-          UI.setActive(self.parent);
+        if (this.tab == gBrowser.selectedTab ||
+            (!GroupItems.getActiveGroupItem() && !this.tab.hidden))
+          UI.setActive(this.parent);
       }
     } else {
       // create tab group by double click is handled in UI_init().
-      GroupItems.newTab(self, {immediately: true});
+      GroupItems.newTab(this, {immediately: true});
     }
 
-    self._reconnected = true;
-    self.save();
-    self._sendToSubscribers("reconnected");
+    this._reconnected = true;
+    this.save();
+    this._sendToSubscribers("reconnected");
   },
 
   // ----------
   // Function: setHidden
   // Hide/unhide this item
   setHidden: function TabItem_setHidden(val) {
     if (val)
       this.addClass("tabHidden");
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -37,27 +37,28 @@
 DEPTH		= ../../../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = browser/base/content/test
 
 DIRS += \
 		tabview \
-		inspector \
 		$(NULL)
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES = \
 		test_feed_discovery.html \
 		feed_discovery.html \
 		test_bug395533.html \
 		bug395533-data.txt \
+		test_contextmenu.html \
+		subtst_contextmenu.html \
 		ctxmenu-image.png \
 		video.ogg \
 		test_offlineNotification.html \
 		offlineChild.html \
 		offlineChild.cacheManifest \
 		offlineChild.cacheManifest^headers^ \
 		offlineChild2.html \
 		offlineChild2.cacheManifest \
@@ -70,26 +71,16 @@ include $(topsrcdir)/config/rules.mk
 		bug364677-data.xml^headers^ \
 		test_offline_gzip.html \
 		gZipOfflineChild.html \
 		gZipOfflineChild.html^headers^ \
 		gZipOfflineChild.cacheManifest \
 		gZipOfflineChild.cacheManifest^headers^ \
 		$(NULL)
 
-ifeq (,$(filter gtk2,$(MOZ_WIDGET_TOOLKIT)))
-_TEST_FILES += \
-		test_contextmenu.html \
-		subtst_contextmenu.html \
-		$(NULL)
-
-else
-$(warning test_contextmenu.html disabled because of intermittent failures; bug 513558)
-endif
-
 # The following tests are disabled because they are unreliable:
 #   browser_bug423833.js is bug 428712
 #   browser_sanitize-download-history.js is bug 432425
 #
 # browser_sanitizeDialog_treeView.js is disabled until the tree view is added
 # back to the clear recent history dialog (santize.xul), if it ever is (bug
 # 480169)
 
--- a/browser/base/content/test/browser_sanitizeDialog.js
+++ b/browser/base/content/test/browser_sanitizeDialog.js
@@ -733,25 +733,30 @@ function blankSlate() {
  *       this is a problem only across different connections.
  */
 function waitForAsyncUpdates(aCallback, aScope, aArguments)
 {
   let scope = aScope || this;
   let args = aArguments || [];
   let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
                               .DBConnection;
-  db.createAsyncStatement("BEGIN EXCLUSIVE").executeAsync();
-  db.createAsyncStatement("COMMIT").executeAsync({
+  let begin = db.createAsyncStatement("BEGIN EXCLUSIVE");
+  begin.executeAsync();
+  begin.finalize();
+
+  let commit = db.createAsyncStatement("COMMIT");
+  commit.executeAsync({
     handleResult: function() {},
     handleError: function() {},
     handleCompletion: function(aReason)
     {
       aCallback.apply(scope, args);
     }
   });
+  commit.finalize();
 }
 
 /**
  * Ensures that the given pref is the expected value.
  *
  * @param aPrefName
  *        The pref's sub-branch under the privacy branch
  * @param aExpectedVal
--- a/browser/base/content/test/browser_sanitizeDialog_treeView.js
+++ b/browser/base/content/test/browser_sanitizeDialog_treeView.js
@@ -537,25 +537,30 @@ function blankSlate() {
  *       this is a problem only across different connections.
  */
 function waitForAsyncUpdates(aCallback, aScope, aArguments)
 {
   let scope = aScope || this;
   let args = aArguments || [];
   let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
                               .DBConnection;
-  db.createAsyncStatement("BEGIN EXCLUSIVE").executeAsync();
-  db.createAsyncStatement("COMMIT").executeAsync({
+  let begin = db.createAsyncStatement("BEGIN EXCLUSIVE");
+  begin.executeAsync();
+  begin.finalize();
+
+  let commit = db.createAsyncStatement("COMMIT");
+  commit.executeAsync({
     handleResult: function() {},
     handleError: function() {},
     handleCompletion: function(aReason)
     {
       aCallback.apply(scope, args);
     }
   });
+  commit.finalize();
 }
 
 /**
  * Checks to see if the download with the specified ID exists.
  *
  * @param  aID
  *         The ID of the download to check
  * @return True if the download exists, false otherwise
--- a/browser/base/content/test/tabview/Makefile.in
+++ b/browser/base/content/test/tabview/Makefile.in
@@ -53,16 +53,17 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_bug587276.js \
                  browser_tabview_bug587351.js \
                  browser_tabview_bug587503.js \
                  browser_tabview_bug587990.js \
                  browser_tabview_bug588265.js \
                  browser_tabview_bug589324.js \
                  browser_tabview_bug590606.js \
                  browser_tabview_bug591706.js \
+                 browser_tabview_bug593283.js \
                  browser_tabview_bug594958.js \
                  browser_tabview_bug595020.js \
                  browser_tabview_bug595191.js \
                  browser_tabview_bug595436.js \
                  browser_tabview_bug595518.js \
                  browser_tabview_bug595521.js \
                  browser_tabview_bug595560.js \
                  browser_tabview_bug595601.js \
@@ -152,16 +153,17 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_bug663421.js \
                  browser_tabview_bug665502.js \
                  browser_tabview_bug669694.js \
                  browser_tabview_bug673196.js \
                  browser_tabview_bug673729.js \
                  browser_tabview_bug677310.js \
                  browser_tabview_bug679853.js \
                  browser_tabview_bug681599.js \
+                 browser_tabview_bug686654.js \
                  browser_tabview_click_group.js \
                  browser_tabview_dragdrop.js \
                  browser_tabview_exit_button.js \
                  browser_tabview_expander.js \
                  browser_tabview_firstrun_pref.js \
                  browser_tabview_group.js \
                  browser_tabview_launch.js \
                  browser_tabview_multiwindow_search.js \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug593283.js
@@ -0,0 +1,75 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const DUMMY_PAGE_URL = "http://example.com/";
+
+let state = {
+  windows: [{
+    tabs: [{
+      entries: [{ url: DUMMY_PAGE_URL }],
+      hidden: false, 
+      attributes: {},
+      extData: {
+        "tabview-tab": '{"url":"' + DUMMY_PAGE_URL + '","groupID":1,"title":null,"active":true}'
+      }
+    },{
+      entries: [{ url: DUMMY_PAGE_URL }],
+      hidden: false,
+      attributes: {},
+      extData: {
+        "tabview-tab": '{"url":"' + DUMMY_PAGE_URL + '","groupID":1,"title":null}'
+      }
+    },{
+      entries: [{ url: DUMMY_PAGE_URL }],
+      hidden: true,
+      attributes: {},
+      extData: {
+        "tabview-tab": '{"url":"' + DUMMY_PAGE_URL + '","groupID":2,"title":null}'
+      },
+    },{
+      entries: [{ url: DUMMY_PAGE_URL }],
+      hidden: true,
+      attributes: {},
+      extData: {
+        "tabview-tab": '{"url":"' + DUMMY_PAGE_URL + '","groupID":2,"title":null,"active":true}'
+      },
+    }],
+    selected:1,
+    _closedTabs: [],
+    extData: {
+      "tabview-groups": '{"nextID":3,"activeGroupId":2,"totalNumber":2}',
+      "tabview-group": 
+        '{"1":{"bounds":{"left":15,"top":28,"width":546,"height":218},' + 
+        '"userSize":{"x":546,"y":218},"title":"","id":1},' +
+        '"2":{"bounds":{"left":15,"top":261,"width":546,"height":199},' + 
+        '"userSize":{"x":546,"y":199},"title":"","id":2}}',
+      "tabview-ui": '{"pageBounds":{"left":0,"top":0,"width":976,"height":663}}'
+    }, sizemode:"normal"
+  }]
+};
+
+function test() {
+  waitForExplicitFinish();
+
+  newWindowWithState(state, function (win) {
+    registerCleanupFunction(function () win.close());
+
+    showTabView(function() {
+      let cw = win.TabView.getContentWindow();
+      let groupItems = cw.GroupItems.groupItems;
+      let groupOne = groupItems[0];
+      let groupTwo = groupItems[1];
+
+      // check the active tab of each group
+      is(groupOne.getActiveTab(), groupOne.getChild(0), "The active tab item of group one is the first one");
+      is(groupTwo.getActiveTab(), groupTwo.getChild(1), "The active tab item of group two is the second one");
+
+      is(cw.UI.getActiveTab(), groupOne.getChild(0), "The hightlighted tab item is the first one in group one");
+      // select a group and the second tab should be hightlighted
+      cw.UI.setActive(groupTwo);
+      is(cw.UI.getActiveTab(), groupTwo.getChild(1), "The hightlighted tab item is the second one in group two");
+
+      finish();
+    }, win);
+  });
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug686654.js
@@ -0,0 +1,46 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+  waitForExplicitFinish();
+
+  newWindowWithTabView(function(win) {
+    let cw = win.TabView.getContentWindow();
+    let groupItem = cw.GroupItems.groupItems[0];
+
+    // set the group to 180 x 100 so it shows two tab items without going into
+    // the stacked mode
+    groupItem.setBounds(new cw.Rect(100, 0, 180, 100));
+
+    hideTabView(function() {
+      groupItem.addSubscriber("childAdded", function onChildAdded(data) {
+        groupItem.removeSubscriber("childAdded", onChildAdded);
+
+        is(groupItem.getChildren().length, 3, "The number of children in group is 3");
+        ok(groupItem.isStacked(), "The group item is stacked after adding a new tab");
+
+        let tabItem = groupItem.getChild(2);
+        groupItem.addSubscriber("childRemoved", function onChildRemoved() {
+          tabItem.removeSubscriber("childRemoved", onChildRemoved);
+
+          is(groupItem.getChildren().length, 2, "The number of children in group is 2");
+          // give a delay for the active item to be set
+          executeSoon(function() {
+            showTabView(function() {
+              ok(!groupItem.isStacked(), "The group item is not stacked after removing a tab");
+              finish();
+            }, win);
+          });
+        });
+        win.BrowserCloseTabOrWindow();
+      });
+      win.gBrowser.loadOneTab("", {inBackground: true});
+    }, win);
+  }, function(win) {
+    registerCleanupFunction(function () {
+      win.close();
+    });
+
+    win.gBrowser.addTab();
+  });
+}
--- a/browser/base/content/test/test_contextmenu.html
+++ b/browser/base/content/test/test_contextmenu.html
@@ -22,16 +22,20 @@ netscape.security.PrivilegeManager.enabl
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 function openContextMenuFor(element, shiftkey) {
     // Context menu should be closed before we open it again.
     is(contextMenu.state, "closed", "checking if popup is closed");
 
+    if (lastElement)
+      lastElement.blur();
+    element.focus();
+    lastElement = element;
     var eventDetails = { type : "contextmenu", button : 2, shiftKey : shiftkey };
     synthesizeMouse(element, 2, 2, eventDetails, element.ownerDocument.defaultView);
 }
 
 function closeContextMenu() {
     contextMenu.hidePopup();
 }
 
@@ -242,125 +246,143 @@ function runTest(testNum) {
                           "context-bookmarkpage", true,
                           "context-savepage",     true,
                           "context-sendpage",     true,
                           "---",                  null,
                           "context-viewbgimage",  false,
                           "context-selectall",    true,
                           "---",                  null,
                           "context-viewsource",   true,
-                          "context-viewinfo",     true]);
+                          "context-viewinfo",     true,
+                          "---",                  null,
+                          "context-inspect",      true]);
         closeContextMenu();
         openContextMenuFor(link); // Invoke context menu for next test.
         break;
 
     case 3:
         // Context menu for text link
         checkContextMenu(["context-openlinkintab", true,
                           "context-openlink",      true,
                           "---",                   null,
                           "context-bookmarklink",  true,
                           "context-savelink",      true,
                           "context-sendlink",      true,
-                          "context-copylink",      true]);
+                          "context-copylink",      true,
+                          "---",                  null,
+                          "context-inspect",      true]);
         closeContextMenu();
         openContextMenuFor(mailto); // Invoke context menu for next test.
         break;
 
     case 4:
         // Context menu for text mailto-link
-        checkContextMenu(["context-copyemail", true]);
+        checkContextMenu(["context-copyemail", true,
+                          "---",                  null,
+                          "context-inspect",      true]);
         closeContextMenu();
         openContextMenuFor(input); // Invoke context menu for next test.
         break;
 
     case 5:
         // Context menu for text input field
         checkContextMenu(["context-undo",        false,
                           "---",                 null,
                           "context-cut",         false,
                           "context-copy",        false,
                           "context-paste",       null, // ignore clipboard state
                           "context-delete",      false,
                           "---",                 null,
-                          "context-selectall",   true,
+                          "context-selectall",   false,
                           "---",                 null,
-                          "spell-check-enabled", true]);
+                          "spell-check-enabled", true,
+                          "---",                  null,
+                          "context-inspect",      true]);
         closeContextMenu();
         openContextMenuFor(img); // Invoke context menu for next test.
         break;
 
     case 6:
         // Context menu for an image
         checkContextMenu(["context-viewimage",            true,
                           "context-copyimage-contents",   true,
                           "context-copyimage",            true,
                           "---",                          null,
                           "context-saveimage",            true,
                           "context-sendimage",            true,
                           "context-setDesktopBackground", true,
-                          "context-viewimageinfo",        true]);
+                          "context-viewimageinfo",        true,
+                          "---",                          null,
+                          "context-inspect",              true]);
         closeContextMenu();
         openContextMenuFor(canvas); // Invoke context menu for next test.
         break;
 
     case 7:
         // Context menu for a canvas
         checkContextMenu(["context-viewimage",    true,
                           "context-saveimage",    true,
                           "context-bookmarkpage", true,
-                          "context-selectall",    true]);
+                          "context-selectall",    true,
+                          "---",                  null,
+                          "context-inspect",      true]);
         closeContextMenu();
         openContextMenuFor(video_ok); // Invoke context menu for next test.
         break;
 
     case 8:
         // Context menu for a video (with a VALID media source)
         checkContextMenu(["context-media-play",         true,
                           "context-media-mute",         true,
                           "context-media-showcontrols", true,
                           "context-video-fullscreen",   true,
                           "---",                        null,
                           "context-viewvideo",          true,
                           "context-copyvideourl",       true,
                           "---",                        null,
                           "context-savevideo",          true,
-                          "context-sendvideo",          true]);
+                          "context-sendvideo",          true,
+                          "---",                        null,
+                          "context-inspect",            true]);
         closeContextMenu();
         openContextMenuFor(video_bad); // Invoke context menu for next test.
         break;
 
     case 9:
         // Context menu for a video (with an INVALID media source)
         checkContextMenu(["context-media-play",         false,
                           "context-media-mute",         false,
                           "context-media-showcontrols", false,
                           "context-video-fullscreen",   false,
                           "---",                        null,
                           "context-viewvideo",          true,
                           "context-copyvideourl",       true,
                           "---",                        null,
                           "context-savevideo",          true,
-                          "context-sendvideo",          true]);
+                          "context-sendvideo",          true,
+                          "---",                        null,
+                          "context-inspect",            true]);
         closeContextMenu();
         openContextMenuFor(video_bad2); // Invoke context menu for next test.
         break;
 
     case 10:
         // Context menu for a video (with an INVALID media source)
         checkContextMenu(["context-media-play",         false,
                           "context-media-mute",         false,
                           "context-media-showcontrols", false,
                           "context-video-fullscreen",   false,
                           "---",                        null,
                           "context-viewvideo",          false,
                           "context-copyvideourl",       false,
                           "---",                        null,
                           "context-savevideo",          false,
-                          "context-sendvideo",          false]);
+                          "context-sendvideo",          false,
+                          "---",                        null,
+                          "context-inspect",            true]);
         closeContextMenu();
         openContextMenuFor(iframe); // Invoke context menu for next test.
         break;
 
     case 11:
         // Context menu for an iframe
         checkContextMenu(["context-back",         false,
                           "context-forward",      false,
@@ -384,17 +406,19 @@ function runTest(testNum) {
                                "context-saveframe",         true,
                                "---",                       null,
                                "context-printframe",        true,
                                "---",                       null,
                                "context-viewframesource",   true,
                                "context-viewframeinfo",     true], null,
                           "---",                  null,
                           "context-viewsource",   true,
-                          "context-viewinfo",     true]);
+                          "context-viewinfo",     true,
+                          "---",                  null,
+                          "context-inspect",      true]);
         closeContextMenu();
         openContextMenuFor(textarea); // Invoke context menu for next test.
         break;
 
     case 12:
         // Context menu for textarea
         checkContextMenu(["*chubbiness",         true, // spelling suggestion
                           "spell-add-to-dictionary", true,
@@ -407,17 +431,19 @@ function runTest(testNum) {
                           "context-delete",      false,
                           "---",                 null,
                           "context-selectall",   true,
                           "---",                 null,
                           "spell-check-enabled", true,
                           "spell-dictionaries",  true,
                               ["spell-check-dictionary-en-US", true,
                                "---",                          null,
-                               "spell-add-dictionaries",       true], null]);
+                               "spell-add-dictionaries",       true], null,
+                          "---",                  null,
+                          "context-inspect",      true]);
 
         closeContextMenu();
         openContextMenuFor(contenteditable); // Invoke context menu for next test.
         break;
 
     case 13:
         // Context menu for contenteditable
         checkContextMenu(["spell-no-suggestions", false,
@@ -431,17 +457,19 @@ function runTest(testNum) {
                           "context-delete",      false,
                           "---",                 null,
                           "context-selectall",   true,
                           "---",                 null,
                           "spell-check-enabled", true,
                           "spell-dictionaries",  true,
                               ["spell-check-dictionary-en-US", true,
                                "---",                          null,
-                               "spell-add-dictionaries",       true], null]);
+                               "spell-add-dictionaries",       true], null,
+                          "---",                 null,
+                          "context-inspect",     true]);
 
         closeContextMenu();
         openContextMenuFor(inputspell); // Invoke context menu for next test.
         break;
 
     case 14:
         // Context menu for spell-check input
         checkContextMenu(["*prodigality",        true, // spelling suggestion
@@ -455,17 +483,19 @@ function runTest(testNum) {
                           "context-delete",      false,
                           "---",                 null,
                           "context-selectall",   true,
                           "---",                 null,
                           "spell-check-enabled", true,
                           "spell-dictionaries",  true,
                               ["spell-check-dictionary-en-US", true,
                                "---",                          null,
-                               "spell-add-dictionaries",       true], null]);
+                               "spell-add-dictionaries",       true], null,
+                          "---",                 null,
+                          "context-inspect",     true]);
 
         closeContextMenu();
         openContextMenuFor(link); // Invoke context menu for next test.
         break;
 
     case 15:
         executeCopyCommand("cmd_copyLink", "http://mozilla.com/");
         closeContextMenu();
@@ -502,17 +532,19 @@ function runTest(testNum) {
                           "context-bookmarkpage", true,
                           "context-savepage",     true,
                           "context-sendpage",     true,
                           "---",                  null,
                           "context-viewbgimage",  false,
                           "context-selectall",    true,
                           "---",                  null,
                           "context-viewsource",   true,
-                          "context-viewinfo",     true]);
+                          "context-viewinfo",     true,
+                          "---",                  null,
+                          "context-inspect",      true]);
 
         invokeItemAction("0");
         closeContextMenu();
         openContextMenuFor(pagemenu, true); // Invoke context menu for next test.
         break;
 
     case 17:
         // Context menu for element with assigned content context menu
@@ -525,17 +557,19 @@ function runTest(testNum) {
                           "context-bookmarkpage", true,
                           "context-savepage",     true,
                           "context-sendpage",     true,
                           "---",                  null,
                           "context-viewbgimage",  false,
                           "context-selectall",    true,
                           "---",                  null,
                           "context-viewsource",   true,
-                          "context-viewinfo",     true]);
+                          "context-viewinfo",     true,
+                          "---",                  null,
+                          "context-inspect",      true]);
 
         subwindow.close();
         SimpleTest.finish();
         return;
 
     /*
      * Other things that would be nice to test:
      *  - selected text
@@ -550,17 +584,17 @@ function runTest(testNum) {
         SimpleTest.finish();
         return;
   }
 
 }
 
 
 var testNum = 1;
-var subwindow, chromeWin, contextMenu;
+var subwindow, chromeWin, contextMenu, lastElement;
 var text, link, mailto, input, img, canvas, video_ok, video_bad, video_bad2,
     iframe, textarea, contenteditable, inputspell, pagemenu;
 
 function startTest() {
     netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
     chromeWin = subwindow
                     .QueryInterface(Ci.nsIInterfaceRequestor)
                     .getInterface(Ci.nsIWebNavigation)
@@ -572,16 +606,18 @@ function startTest() {
     contextMenu = chromeWin.document.getElementById("contentAreaContextMenu");
     ok(contextMenu, "Got context menu XUL");
 
     if (chromeWin.document.getElementById("Browser:Stop").getAttribute("disabled") != "true") {
       SimpleTest.executeSoon(startTest);
       return;
     }
 
+    lastElement = null;
+
     text   = subwindow.document.getElementById("test-text");
     link   = subwindow.document.getElementById("test-link");
     mailto = subwindow.document.getElementById("test-mailto");
     input  = subwindow.document.getElementById("test-input");
     img    = subwindow.document.getElementById("test-image");
     canvas = subwindow.document.getElementById("test-canvas");
     video_ok   = subwindow.document.getElementById("test-video-ok");
     video_bad  = subwindow.document.getElementById("test-video-bad");
--- a/browser/base/content/test/test_offlineNotification.html
+++ b/browser/base/content/test/test_offlineNotification.html
@@ -33,18 +33,18 @@ window.addEventListener("message", funct
     is(event.data, "success", "Child was successfully cached.");
 
     if (++numFinished == 3) {
       // Clean up after ourself
       netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
       var pm = Components.classes["@mozilla.org/permissionmanager;1"].
                getService(Components.interfaces.nsIPermissionManager);
 
-      pm.remove(frames.testFrame.document.documentURIObject.host, "offline-app");
-      pm.remove(frames.testFrame3.document.documentURIObject.host, "offline-app");
+      pm.remove(frames.testFrame.location.hostname, "offline-app");
+      pm.remove(frames.testFrame3.location.hostname, "offline-app");
 
       SimpleTest.finish();
     }
   }, false);
 
 var count = 0;
 var expectedEvent = "";
 function eventHandler(evt) {
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -26,17 +26,16 @@ browser.jar:
         content/browser/aboutRobots-icon.png          (content/aboutRobots-icon.png)
         content/browser/aboutRobots-widget-left.png   (content/aboutRobots-widget-left.png)
 *       content/browser/browser.css                   (content/browser.css)
 *       content/browser/browser.js                    (content/browser.js)
 *       content/browser/browser.xul                   (content/browser.xul)
 *       content/browser/browser-tabPreviews.xml       (content/browser-tabPreviews.xml)
 *       content/browser/content.js                    (content/content.js)
 *       content/browser/fullscreen-video.xhtml        (content/fullscreen-video.xhtml)
-*       content/browser/inspector.html                (content/inspector.html)
 *       content/browser/pageinfo/pageInfo.xul         (content/pageinfo/pageInfo.xul)
 *       content/browser/pageinfo/pageInfo.js          (content/pageinfo/pageInfo.js)
 *       content/browser/pageinfo/pageInfo.css         (content/pageinfo/pageInfo.css)
 *       content/browser/pageinfo/pageInfo.xml         (content/pageinfo/pageInfo.xml)
 *       content/browser/pageinfo/feeds.js             (content/pageinfo/feeds.js)
 *       content/browser/pageinfo/feeds.xml            (content/pageinfo/feeds.xml)
 *       content/browser/pageinfo/permissions.js       (content/pageinfo/permissions.js)
 *       content/browser/pageinfo/security.js          (content/pageinfo/security.js)
--- a/browser/components/places/content/editBookmarkOverlay.js
+++ b/browser/components/places/content/editBookmarkOverlay.js
@@ -72,17 +72,17 @@ var gEditItemOverlay = {
   /**
    * Determines the initial data for the item edited or added by this dialog
    */
   _determineInfo: function EIO__determineInfo(aInfo) {
     // hidden rows
     if (aInfo && aInfo.hiddenRows)
       this._hiddenRows = aInfo.hiddenRows;
     else
-      this._hiddenRows.splice(0);
+      this._hiddenRows.splice(0, this._hiddenRows.length);
     // force-read-only
     this._readOnly = aInfo && aInfo.forceReadOnly;
   },
 
   _showHideRows: function EIO__showHideRows() {
     var isBookmark = this._itemId != -1 &&
                      this._itemType == Ci.nsINavBookmarksService.TYPE_BOOKMARK;
     var isQuery = false;
--- a/browser/components/places/content/places.js
+++ b/browser/components/places/content/places.js
@@ -72,17 +72,17 @@ var PlacesOrganizer = {
     this._initFolderTree();
 
     var leftPaneSelection = "AllBookmarks"; // default to all-bookmarks
     if (window.arguments && window.arguments[0])
       leftPaneSelection = window.arguments[0];
 
     this.selectLeftPaneQuery(leftPaneSelection);
     // clear the back-stack
-    this._backHistory.splice(0);
+    this._backHistory.splice(0, this._backHistory.length);
     document.getElementById("OrganizerCommand:Back").setAttribute("disabled", true);
 
     var view = this._content.treeBoxObject.view;
     if (view.rowCount > 0)
       view.selection.select(0);
 
     this._content.focus();
 
@@ -157,17 +157,17 @@ var PlacesOrganizer = {
   },
 
   set location(aLocation) {
     if (!aLocation || this._location == aLocation)
       return aLocation;
 
     if (this.location) {
       this._backHistory.unshift(this.location);
-      this._forwardHistory.splice(0);
+      this._forwardHistory.splice(0, this._forwardHistory.length);
     }
 
     this._location = aLocation;
     this._places.selectPlaceURI(aLocation);
 
     if (!this._places.hasSelection) {
       // If no node was found for the given place: uri, just load it directly
       this._content.place = aLocation;
--- a/browser/components/places/tests/browser/head.js
+++ b/browser/components/places/tests/browser/head.js
@@ -62,18 +62,23 @@ function waitForClearHistory(aCallback) 
  *       this is a problem only across different connections.
  */
 function waitForAsyncUpdates(aCallback, aScope, aArguments)
 {
   let scope = aScope || this;
   let args = aArguments || [];
   let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
                               .DBConnection;
-  db.createAsyncStatement("BEGIN EXCLUSIVE").executeAsync();
-  db.createAsyncStatement("COMMIT").executeAsync({
+  let begin = db.createAsyncStatement("BEGIN EXCLUSIVE");
+  begin.executeAsync();
+  begin.finalize();
+
+  let commit = db.createAsyncStatement("COMMIT");
+  commit.executeAsync({
     handleResult: function() {},
     handleError: function() {},
     handleCompletion: function(aReason)
     {
       aCallback.apply(scope, args);
     }
   });
+  commit.finalize();
 }
--- a/browser/components/places/tests/unit/test_clearHistory_shutdown.js
+++ b/browser/components/places/tests/unit/test_clearHistory_shutdown.js
@@ -47,17 +47,16 @@ const URIS = [
 , "http://c.example3.com/"
 ];
 
 const TOPIC_CONNECTION_CLOSED = "places-connection-closed";
 
 let EXPECTED_NOTIFICATIONS = [
   "places-shutdown"
 , "places-will-close-connection"
-, "places-connection-closing"
 , "places-expiration-finished"
 , "places-connection-closed"
 ];
 
 const UNEXPECTED_NOTIFICATIONS = [
   "xpcom-shutdown"
 ];
 
--- a/browser/components/preferences/permissionsutils.js
+++ b/browser/components/preferences/permissionsutils.js
@@ -36,17 +36,17 @@
 #
 # ***** END LICENSE BLOCK *****
 
 var gTreeUtils = {
   deleteAll: function (aTree, aView, aItems, aDeletedItems)
   {
     for (var i = 0; i < aItems.length; ++i)
       aDeletedItems.push(aItems[i]);
-    aItems.splice(0);
+    aItems.splice(0, aItems.length);
     var oldCount = aView.rowCount;
     aView._rowCount = 0;
     aTree.treeBoxObject.rowCountChanged(0, -oldCount);
   },
   
   deleteSelectedItems: function (aTree, aView, aItems, aDeletedItems)
   {
     var selection = aTree.view.selection;
--- a/browser/components/sessionstore/src/nsSessionStore.js
+++ b/browser/components/sessionstore/src/nsSessionStore.js
@@ -624,17 +624,17 @@ SessionStoreService.prototype = {
       this._clearRestoringWindows();
       break;
     case "nsPref:changed": // catch pref changes
       switch (aData) {
       // if the user decreases the max number of closed tabs they want
       // preserved update our internal states to match that max
       case "sessionstore.max_tabs_undo":
         for (let ix in this._windows) {
-          this._windows[ix]._closedTabs.splice(this._prefBranch.getIntPref("sessionstore.max_tabs_undo"));
+          this._windows[ix]._closedTabs.splice(this._prefBranch.getIntPref("sessionstore.max_tabs_undo"), this._windows[ix]._closedTabs.length);
         }
         break;
       case "sessionstore.max_windows_undo":
         this._capClosedWindows();
         break;
       case "sessionstore.interval":
         this._interval = this._prefBranch.getIntPref("sessionstore.interval");
         // reset timer and save
@@ -1161,17 +1161,17 @@ SessionStoreService.prototype = {
       this._updateCrashReportURL(aWindow);
     }
   },
 
   onTabShow: function sss_onTabShow(aWindow, aTab) {
     // If the tab hasn't been restored yet, move it into the right _tabsToRestore bucket
     if (aTab.linkedBrowser.__SS_restoreState &&
         aTab.linkedBrowser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE) {
-      this._tabsToRestore.hidden.splice(this._tabsToRestore.hidden.indexOf(aTab));
+      this._tabsToRestore.hidden.splice(this._tabsToRestore.hidden.indexOf(aTab), this._tabsToRestore.hidden.length);
       // Just put it at the end of the list of visible tabs;
       this._tabsToRestore.visible.push(aTab);
 
       // let's kick off tab restoration again to ensure this tab gets restored
       // with "restore_hidden_tabs" == false (now that it has become visible)
       this.restoreNextTab();
     }
 
@@ -1179,17 +1179,17 @@ SessionStoreService.prototype = {
     // events due to changing groups in Panorama.
     this.saveStateDelayed(aWindow);
   },
 
   onTabHide: function sss_onTabHide(aWindow, aTab) {
     // If the tab hasn't been restored yet, move it into the right _tabsToRestore bucket
     if (aTab.linkedBrowser.__SS_restoreState &&
         aTab.linkedBrowser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE) {
-      this._tabsToRestore.visible.splice(this._tabsToRestore.visible.indexOf(aTab));
+      this._tabsToRestore.visible.splice(this._tabsToRestore.visible.indexOf(aTab), this._tabsToRestore.visible.length);
       // Just put it at the end of the list of hidden tabs;
       this._tabsToRestore.hidden.push(aTab);
     }
 
     // Default delay of 2 seconds gives enough time to catch multiple TabHide
     // events due to changing groups in Panorama.
     this.saveStateDelayed(aWindow);
   },
@@ -1545,17 +1545,17 @@ SessionStoreService.prototype = {
 
       // If there's a window already open that we can restore into, use that
       if (canUseWindow) {
         // Since we're not overwriting existing tabs, we want to merge _closedTabs,
         // putting existing ones first. Then make sure we're respecting the max pref.
         if (winState._closedTabs && winState._closedTabs.length) {
           let curWinState = this._windows[windowToUse.__SSi];
           curWinState._closedTabs = curWinState._closedTabs.concat(winState._closedTabs);
-          curWinState._closedTabs.splice(this._prefBranch.getIntPref("sessionstore.max_tabs_undo"));
+          curWinState._closedTabs.splice(this._prefBranch.getIntPref("sessionstore.max_tabs_undo"), curWinState._closedTabs.length);
         }
 
         // Restore into that window - pretend it's a followup since we'll already
         // have a focused window.
         //XXXzpao This is going to merge extData together (taking what was in
         //        winState over what is in the window already. The hack we have
         //        in _preWindowToRestoreInto will prevent most (all?) Panorama
         //        weirdness but we will still merge other extData.
@@ -2585,38 +2585,38 @@ SessionStoreService.prototype = {
       winData.tabs = [];
     }
     // don't restore a single blank tab when we've had an external
     // URL passed in for loading at startup (cf. bug 357419)
     else if (root._firstTabs && !aOverwriteTabs && winData.tabs.length == 1 &&
              (!winData.tabs[0].entries || winData.tabs[0].entries.length == 0)) {
       winData.tabs = [];
     }
-    
+
     var tabbrowser = aWindow.gBrowser;
     var openTabCount = aOverwriteTabs ? tabbrowser.browsers.length : -1;
     var newTabCount = winData.tabs.length;
     var tabs = [];
 
     // disable smooth scrolling while adding, moving, removing and selecting tabs
     var tabstrip = tabbrowser.tabContainer.mTabstrip;
     var smoothScroll = tabstrip.smoothScroll;
     tabstrip.smoothScroll = false;
-    
-    // make sure that the selected tab won't be closed in order to
-    // prevent unnecessary flickering
-    if (aOverwriteTabs && tabbrowser.selectedTab._tPos >= newTabCount)
-      tabbrowser.moveTabTo(tabbrowser.selectedTab, newTabCount - 1);
 
     // unpin all tabs to ensure they are not reordered in the next loop
     if (aOverwriteTabs) {
       for (let t = tabbrowser._numPinnedTabs - 1; t > -1; t--)
         tabbrowser.unpinTab(tabbrowser.tabs[t]);
     }
 
+    // make sure that the selected tab won't be closed in order to
+    // prevent unnecessary flickering
+    if (aOverwriteTabs && tabbrowser.selectedTab._tPos >= newTabCount)
+      tabbrowser.moveTabTo(tabbrowser.selectedTab, newTabCount - 1);
+
     for (var t = 0; t < newTabCount; t++) {
       tabs.push(t < openTabCount ?
                 tabbrowser.tabs[t] :
                 tabbrowser.addTab("about:blank", {skipAnimation: true}));
       // when resuming at startup: add additionally requested pages to the end
       if (!aOverwriteTabs && root._firstTabs) {
         tabbrowser.moveTabTo(tabs[t], t);
       }
@@ -3009,34 +3009,27 @@ SessionStoreService.prototype = {
     browser.__SS_restoreState = TAB_STATE_RESTORING;
 
     // Remove the history listener, since we no longer need it once we start restoring
     this._removeSHistoryListener(aTab);
 
     let activeIndex = (tabData.index || tabData.entries.length) - 1;
     if (activeIndex >= tabData.entries.length)
       activeIndex = tabData.entries.length - 1;
-
     // Reset currentURI.  This creates a new session history entry with a new
     // doc identifier, so we need to explicitly save and restore the old doc
     // identifier (corresponding to the SHEntry at activeIndex) below.
     browser.webNavigation.setCurrentURI(this._getURIFromString("about:blank"));
-
     // Attach data that will be restored on "load" event, after tab is restored.
     if (activeIndex > -1) {
-      let curSHEntry = browser.webNavigation.sessionHistory.
-                       getEntryAtIndex(activeIndex, false).
-                       QueryInterface(Ci.nsISHEntry);
-
       // restore those aspects of the currently active documents which are not
       // preserved in the plain history entries (mainly scroll state and text data)
       browser.__SS_restore_data = tabData.entries[activeIndex] || {};
       browser.__SS_restore_pageStyle = tabData.pageStyle || "";
       browser.__SS_restore_tab = aTab;
-
       didStartLoad = true;
       try {
         // In order to work around certain issues in session history, we need to
         // force session history to update its internal index and call reload
         // instead of gotoIndex. See bug 597315.
         browser.webNavigation.sessionHistory.getEntryAtIndex(activeIndex, true);
         browser.webNavigation.sessionHistory.reloadCurrentEntry();
       }
@@ -4139,17 +4132,17 @@ SessionStoreService.prototype = {
     let normalWindowIndex = 0;
     // try to find a non-popup window in this._closedWindows
     while (normalWindowIndex < this._closedWindows.length &&
            !!this._closedWindows[normalWindowIndex].isPopup)
       normalWindowIndex++;
     if (normalWindowIndex >= maxWindowsUndo)
       spliceTo = normalWindowIndex + 1;
 #endif
-    this._closedWindows.splice(spliceTo);
+    this._closedWindows.splice(spliceTo, this._closedWindows.length);
   },
 
   _clearRestoringWindows: function sss__clearRestoringWindows() {
     for (let i = 0; i < this._closedWindows.length; i++) {
       delete this._closedWindows[i]._shouldRestore;
     }
   },
 
--- a/browser/devtools/Makefile.in
+++ b/browser/devtools/Makefile.in
@@ -42,16 +42,17 @@ topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH   = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 include $(topsrcdir)/config/config.mk
 
 DIRS = \
+  highlighter \
   webconsole \
   scratchpad \
   sourceeditor \
   styleinspector \
   shared \
   $(NULL)
 
 ifdef ENABLE_TESTS
new file mode 100644
--- /dev/null
+++ b/browser/devtools/highlighter/Makefile.in
@@ -0,0 +1,55 @@
+#
+# ***** 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 Highlighter Build Code.
+#
+# The Initial Developer of the Original Code is The Mozilla Foundation.
+#
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Rob Campbell <rcampbell@mozilla.com>
+#   Mihai Sucan <mihai.sucan@gmail.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 *****
+
+DEPTH		= ../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+EXTRA_JS_MODULES = \
+	domplate.jsm \
+	$(NULL)
+
+ifdef ENABLE_TESTS
+ 	DIRS += test
+endif
+
+include $(topsrcdir)/config/rules.mk
rename from browser/base/content/domplate.jsm
rename to browser/devtools/highlighter/domplate.jsm
new file mode 100644
--- /dev/null
+++ b/browser/devtools/highlighter/insideOutBox.js
@@ -0,0 +1,646 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ * Copyright (c) 2007, Parakey Inc.
+ * All rights reserved.
+ * 
+ * Redistribution and use of this software in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 
+ * * Redistributions of source code must retain the above
+ *   copyright notice, this list of conditions and the
+ *   following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the
+ *   following disclaimer in the documentation and/or other
+ *   materials provided with the distribution.
+ * 
+ * * Neither the name of Parakey Inc. nor the names of its
+ *   contributors may be used to endorse or promote products
+ *   derived from this software without specific prior
+ *   written permission of Parakey Inc.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Creator:
+ *  Joe Hewitt
+ * Contributors
+ *  John J. Barton (IBM Almaden)
+ *  Jan Odvarko (Mozilla Corp.)
+ *  Max Stepanov (Aptana Inc.)
+ *  Rob Campbell (Mozilla Corp.)
+ *  Hans Hillen (Paciello Group, Mozilla)
+ *  Curtis Bartley (Mozilla Corp.)
+ *  Mike Collins (IBM Almaden)
+ *  Kevin Decker
+ *  Mike Ratcliffe (Comartis AG)
+ *  Hernan Rodríguez Colmeiro
+ *  Austin Andrews
+ *  Christoph Dorn
+ *  Steven Roussey (AppCenter Inc, Network54)
+ */
+
+///////////////////////////////////////////////////////////////////////////
+//// InsideOutBox
+
+/**
+ * InsideOutBoxView is a simple interface definition for views implementing
+ * InsideOutBox controls. All implementors must define these methods.
+ * Implemented in InspectorUI.
+ */
+
+/*
+InsideOutBoxView = {
+  //
+   * Retrieves the parent object for a given child object.
+   * @param aChild
+   *        The child node to retrieve the parent object for.
+   * @returns a DOM node | null
+   //
+  getParentObject: function(aChild) {},
+
+  //
+   * Retrieves a given child node.
+   *
+   * If both index and previousSibling are passed, the implementation
+   * may assume that previousSibling will be the return for getChildObject
+   * with index-1.
+   * @param aParent
+   *        The parent object of the child object to retrieve.
+   * @param aIndex
+   *        The index of the child object to retrieve from aParent.
+   * @param aPreviousSibling
+   *        The previous sibling of the child object to retrieve.
+   *        Supercedes aIndex.
+   * @returns a DOM object | null
+   //
+  getChildObject: function(aParent, aIndex, aPreviousSibling) {},
+
+  //
+   * Renders the HTML representation of the object. Should return an HTML
+   * object which will be displayed to the user.
+   * @param aObject
+   *        The object to create the box object for.
+   * @param aIsRoot
+   *        Is the object the root object. May not be used in all
+   *        implementations.
+   * @returns an object box | null
+   //
+  createObjectBox: function(aObject, aIsRoot) {},
+
+  //
+  * Convenience wrappers for classList API.
+  * @param aObject
+  *        DOM node to query/set.
+  * @param aClassName
+  *        String containing the class name to query/set.
+  //
+  hasClass: function(aObject, aClassName) {},
+  addClass: function(aObject, aClassName) {},
+  removeClass: function(aObject, aClassName) {}
+};
+*/
+
+/**
+ * Creates a tree based on objects provided by a separate "view" object.
+ *
+ * Construction uses an "inside-out" algorithm, meaning that the view's job is
+ * first to tell us the ancestry of each object, and secondarily its
+ * descendants.
+ *
+ * Constructor
+ * @param aView
+ *        The view requiring the InsideOutBox.
+ * @param aBox
+ *        The box object containing the InsideOutBox. Required to add/remove
+ *        children during box manipulation (toggling opened or closed).
+ */
+function InsideOutBox(aView, aBox)
+{
+  this.view = aView;
+  this.box = aBox;
+
+  this.rootObject = null;
+
+  this.rootObjectBox = null;
+  this.selectedObjectBox = null;
+  this.highlightedObjectBox = null;
+  this.scrollIntoView = false;
+};
+
+InsideOutBox.prototype =
+{
+  /**
+   * Highlight the given object node in the tree.
+   * @param aObject
+   *        the object to highlight.
+   * @returns objectBox
+   */
+  highlight: function IOBox_highlight(aObject)
+  {
+    let objectBox = this.createObjectBox(aObject);
+    this.highlightObjectBox(objectBox);
+    return objectBox;
+  },
+
+  /**
+   * Open the given object node in the tree.
+   * @param aObject
+   *        The object node to open.
+   * @returns objectBox
+   */
+  openObject: function IOBox_openObject(aObject)
+  {
+    let object = aObject;
+    let firstChild = this.view.getChildObject(object, 0);
+    if (firstChild)
+      object = firstChild;
+
+    return this.openToObject(object);
+  },
+
+  /**
+   * Open the tree up to the given object node.
+   * @param aObject
+   *        The object in the tree to open to.
+   * @returns objectBox
+   */
+  openToObject: function IOBox_openToObject(aObject)
+  {
+    let objectBox = this.createObjectBox(aObject);
+    this.openObjectBox(objectBox);
+    return objectBox;
+  },
+
+  /**
+   * Select the given object node in the tree.
+   * @param aObject
+   *        The object node to select.
+   * @param makeBoxVisible
+   *        Boolean. Open the object box in the tree?
+   * @param forceOpen
+   *        Force the object box open by expanding all elements in the tree?
+   * @param scrollIntoView
+   *        Scroll the objectBox into view?
+   * @returns nsIDOMNode|null
+   *          A DOM node that represents the "object box", the element that
+   *          holds/displays the given aObject representation in the tree. If
+   *          the object cannot be selected, if it is a stale object, null is
+   *          returned.
+   */
+  select:
+  function IOBox_select(aObject, makeBoxVisible, forceOpen, scrollIntoView)
+  {
+    let objectBox = this.createObjectBox(aObject);
+    if (!objectBox) {
+      return null;
+    }
+    this.selectObjectBox(objectBox, forceOpen);
+    if (makeBoxVisible) {
+      this.openObjectBox(objectBox);
+      if (scrollIntoView) {
+        objectBox.scrollIntoView(true);
+      }
+    }
+    return objectBox;
+  },
+
+  /**
+   * Expands/contracts the given object, depending on its state.
+   * @param aObject
+   *        The tree node to expand/contract.
+   */
+  toggleObject: function IOBox_toggleObject(aObject)
+  {
+    let box = this.createObjectBox(aObject);
+    if (!(this.view.hasClass(box, "open")))
+      this.expandObjectBox(box);
+    else
+      this.contractObjectBox(box);
+  },
+
+  /**
+   * Expand the given object in the tree.
+   * @param aObject
+   *        The tree node to expand.
+   */
+  expandObject: function IOBox_expandObject(aObject)
+  {
+    let objectBox = this.createObjectBox(aObject);
+    if (objectBox)
+      this.expandObjectBox(objectBox);
+  },
+
+  /**
+   * Contract the given object in the tree.
+   * @param aObject
+   *        The tree node to contract.
+   */
+  contractObject: function IOBox_contractObject(aObject)
+  {
+    let objectBox = this.createObjectBox(aObject);
+    if (objectBox)
+      this.contractObjectBox(objectBox);
+  },
+
+  /**
+   * General method for iterating over an object's ancestors and performing
+   * some function.
+   * @param aObject
+   *        The object whose ancestors we wish to iterate over.
+   * @param aCallback
+   *        The function to call with the object as argument.
+   */
+
+  iterateObjectAncestors: function IOBox_iterateObjectAncesors(aObject, aCallback)
+  {
+    let object = aObject;
+    if (!(aCallback && typeof(aCallback) == "function")) {
+      this.view._log("Illegal argument in IOBox.iterateObjectAncestors");
+      return;
+    }
+    while ((object = this.getParentObjectBox(object)))
+      aCallback(object);
+  },
+
+  /**
+   * Highlight the given objectBox in the tree.
+   * @param aObjectBox
+   *        The objectBox to highlight.
+   */
+  highlightObjectBox: function IOBox_highlightObjectBox(aObjectBox)
+  {
+    let self = this;
+
+    if (!aObjectBox)
+      return;
+
+    if (this.highlightedObjectBox) {
+      this.view.removeClass(this.highlightedObjectBox, "highlighted");
+      this.iterateObjectAncestors(this.highlightedObjectBox, function (box) {
+        self.view.removeClass(box, "highlightOpen");
+      });
+    }
+
+    this.highlightedObjectBox = aObjectBox;
+
+    this.view.addClass(aObjectBox, "highlighted");
+    this.iterateObjectAncestors(this.highlightedObjectBox, function (box) {
+      self.view.addClass(box, "highlightOpen");
+    });
+
+    aObjectBox.scrollIntoView(true);
+  },
+
+  /**
+   * Select the given objectBox in the tree, forcing it to be open if necessary.
+   * @param aObjectBox
+   *        The objectBox to select.
+   * @param forceOpen
+   *        Force the box (subtree) to be open?
+   */
+  selectObjectBox: function IOBox_selectObjectBox(aObjectBox, forceOpen)
+  {
+    let isSelected = this.selectedObjectBox &&
+      aObjectBox == this.selectedObjectBox;
+
+    // aObjectBox is already selected, return
+    if (isSelected)
+      return;
+
+    if (this.selectedObjectBox)
+      this.view.removeClass(this.selectedObjectBox, "selected");
+
+    this.selectedObjectBox = aObjectBox;
+
+    if (aObjectBox) {
+      this.view.addClass(aObjectBox, "selected");
+
+      // Force it open the first time it is selected
+      if (forceOpen)
+        this.expandObjectBox(aObjectBox, true);
+    }
+  },
+
+  /**
+   * Open the ancestors of the given object box.
+   * @param aObjectBox
+   *        The object box to open.
+   */
+  openObjectBox: function IOBox_openObjectBox(aObjectBox)
+  {
+    if (!aObjectBox)
+      return;
+
+    let self = this;
+    this.iterateObjectAncestors(aObjectBox, function (box) {
+      self.view.addClass(box, "open");
+      let labelBox = box.querySelector(".nodeLabelBox");
+      if (labelBox)
+        labelBox.setAttribute("aria-expanded", "true");
+   });
+  },
+
+  /**
+   * Expand the given object box.
+   * @param aObjectBox
+   *        The object box to expand.
+   */
+  expandObjectBox: function IOBox_expandObjectBox(aObjectBox)
+  {
+    let nodeChildBox = this.getChildObjectBox(aObjectBox);
+
+    // no children means nothing to expand, return
+    if (!nodeChildBox)
+      return;
+
+    if (!aObjectBox.populated) {
+      let firstChild = this.view.getChildObject(aObjectBox.repObject, 0);
+      this.populateChildBox(firstChild, nodeChildBox);
+    }
+    let labelBox = aObjectBox.querySelector(".nodeLabelBox");
+    if (labelBox)
+      labelBox.setAttribute("aria-expanded", "true");
+    this.view.addClass(aObjectBox, "open");
+  },
+
+  /**
+   * Contract the given object box.
+   * @param aObjectBox
+   *        The object box to contract.
+   */
+  contractObjectBox: function IOBox_contractObjectBox(aObjectBox)
+  {
+    this.view.removeClass(aObjectBox, "open");
+    let nodeLabel = aObjectBox.querySelector(".nodeLabel");
+    let labelBox = nodeLabel.querySelector(".nodeLabelBox");
+    if (labelBox)
+      labelBox.setAttribute("aria-expanded", "false");
+  },
+
+  /**
+   * Toggle the given object box, forcing open if requested.
+   * @param aObjectBox
+   *        The object box to toggle.
+   * @param forceOpen
+   *        Force the objectbox open?
+   */
+  toggleObjectBox: function IOBox_toggleObjectBox(aObjectBox, forceOpen)
+  {
+    let isOpen = this.view.hasClass(aObjectBox, "open");
+
+    if (!forceOpen && isOpen)
+      this.contractObjectBox(aObjectBox);
+    else if (!isOpen)
+      this.expandObjectBox(aObjectBox);
+  },
+
+  /**
+   * Creates all of the boxes for an object, its ancestors, and siblings.
+   * @param aObject
+   *        The tree node to create the object boxes for.
+   * @returns anObjectBox or null
+   */
+  createObjectBox: function IOBox_createObjectBox(aObject)
+  {
+    if (!aObject)
+      return null;
+
+    this.rootObject = this.getRootNode(aObject) || aObject;
+
+    // Get or create all of the boxes for the target and its ancestors
+    let objectBox = this.createObjectBoxes(aObject, this.rootObject);
+
+    if (!objectBox)
+      return null;
+
+    if (aObject == this.rootObject)
+      return objectBox;
+
+    return this.populateChildBox(aObject, objectBox.parentNode);
+  },
+
+  /**
+   * Creates all of the boxes for an object, its ancestors, and siblings up to
+   * a root.
+   * @param aObject
+   *        The tree's object node to create the object boxes for.
+   * @param aRootObject
+   *        The root object at which to stop building object boxes.
+   * @returns an object box or null
+   */
+  createObjectBoxes: function IOBox_createObjectBoxes(aObject, aRootObject)
+  {
+    if (!aObject)
+      return null;
+
+    if (aObject == aRootObject) {
+      if (!this.rootObjectBox || this.rootObjectBox.repObject != aRootObject) {
+        if (this.rootObjectBox) {
+          try {
+            this.box.removeChild(this.rootObjectBox);
+          } catch (exc) {
+            InspectorUI._log("this.box.removeChild(this.rootObjectBox) FAILS " +
+              this.box + " must not contain " + this.rootObjectBox);
+          }
+        }
+
+        this.highlightedObjectBox = null;
+        this.selectedObjectBox = null;
+        this.rootObjectBox = this.view.createObjectBox(aObject, true);
+        this.box.appendChild(this.rootObjectBox);
+      }
+      return this.rootObjectBox;
+    }
+
+    let parentNode = this.view.getParentObject(aObject);
+    let parentObjectBox = this.createObjectBoxes(parentNode, aRootObject);
+
+    if (!parentObjectBox)
+      return null;
+
+    let parentChildBox = this.getChildObjectBox(parentObjectBox);
+
+    if (!parentChildBox)
+      return null;
+
+    let childObjectBox = this.findChildObjectBox(parentChildBox, aObject);
+
+    return childObjectBox ? childObjectBox
+      : this.populateChildBox(aObject, parentChildBox);
+  },
+
+  /**
+   * Locate the object box for a given object node.
+   * @param aObject
+   *        The given object node in the tree.
+   * @returns an object box or null.
+   */
+  findObjectBox: function IOBox_findObjectBox(aObject)
+  {
+    if (!aObject)
+      return null;
+
+    if (aObject == this.rootObject)
+      return this.rootObjectBox;
+
+    let parentNode = this.view.getParentObject(aObject);
+    let parentObjectBox = this.findObjectBox(parentNode);
+    if (!parentObjectBox)
+      return null;
+
+    let parentChildBox = this.getChildObjectBox(parentObjectBox);
+    if (!parentChildBox)
+      return null;
+
+    return this.findChildObjectBox(parentChildBox, aObject);
+  },
+
+  getAncestorByClass: function IOBox_getAncestorByClass(node, className)
+  {
+    for (let parent = node; parent; parent = parent.parentNode) {
+      if (this.view.hasClass(parent, className))
+        return parent;
+    }
+
+    return null;
+  },
+
+  /**
+   * We want all children of the parent of repObject.
+   */
+  populateChildBox: function IOBox_populateChildBox(repObject, nodeChildBox)
+  {
+    if (!repObject)
+      return null;
+
+    let parentObjectBox = this.getAncestorByClass(nodeChildBox, "nodeBox");
+
+    if (parentObjectBox.populated)
+      return this.findChildObjectBox(nodeChildBox, repObject);
+
+    let lastSiblingBox = this.getChildObjectBox(nodeChildBox);
+    let siblingBox = nodeChildBox.firstChild;
+    let targetBox = null;
+    let view = this.view;
+    let targetSibling = null;
+    let parentNode = view.getParentObject(repObject);
+
+    for (let i = 0; 1; ++i) {
+      targetSibling = view.getChildObject(parentNode, i, targetSibling);
+      if (!targetSibling)
+        break;
+
+      // Check if we need to start appending, or continue to insert before
+      if (lastSiblingBox && lastSiblingBox.repObject == targetSibling)
+        lastSiblingBox = null;
+
+      if (!siblingBox || siblingBox.repObject != targetSibling) {
+        let newBox = view.createObjectBox(targetSibling);
+        if (newBox) {
+          if (lastSiblingBox)
+            nodeChildBox.insertBefore(newBox, lastSiblingBox);
+          else
+            nodeChildBox.appendChild(newBox);
+        }
+
+        siblingBox = newBox;
+      }
+
+      if (targetSibling == repObject)
+        targetBox = siblingBox;
+
+      if (siblingBox && siblingBox.repObject == targetSibling)
+        siblingBox = siblingBox.nextSibling;
+    }
+
+    if (targetBox)
+      parentObjectBox.populated = true;
+
+    return targetBox;
+  },
+
+  /**
+   * Get the parent object box of a given object box.
+   * @params aObjectBox
+   *         The object box of the parent.
+   * @returns an object box or null
+   */
+  getParentObjectBox: function IOBox_getParentObjectBox(aObjectBox)
+  {
+    let parent = aObjectBox.parentNode ? aObjectBox.parentNode.parentNode : null;
+    return parent && parent.repObject ? parent : null;
+  },
+
+  /**
+   * Get the child object box of a given object box.
+   * @param aObjectBox
+   *        The object box whose child you want.
+   * @returns an object box or null
+   */
+  getChildObjectBox: function IOBox_getChildObjectBox(aObjectBox)
+  {
+    return aObjectBox.querySelector(".nodeChildBox");
+  },
+
+  /**
+   * Find the child object box for a given repObject within the subtree
+   * rooted at aParentNodeBox.
+   * @param aParentNodeBox
+   *        root of the subtree in which to search for repObject.
+   * @param aRepObject
+   *        The object you wish to locate in the subtree.
+   * @returns an object box or null
+   */
+  findChildObjectBox: function IOBox_findChildObjectBox(aParentNodeBox, aRepObject)
+  {
+    let childBox = aParentNodeBox.firstChild;
+    while (childBox) {
+      if (childBox.repObject == aRepObject)
+        return childBox;
+      childBox = childBox.nextSibling;
+    }
+    return null; // not found
+  },
+
+  /**
+   * Determines if the given node is an ancestor of the current root.
+   * @param aNode
+   *        The node to look for within the tree.
+   * @returns boolean
+   */
+  isInExistingRoot: function IOBox_isInExistingRoot(aNode)
+  {
+    let parentNode = aNode;
+    while (parentNode && parentNode != this.rootObject) {
+      parentNode = this.view.getParentObject(parentNode);
+    }
+    return parentNode == this.rootObject;
+  },
+
+  /**
+   * Get the root node of a given node.
+   * @param aNode
+   *        The node whose root you wish to retrieve.
+   * @returns a root node or null
+   */
+  getRootNode: function IOBox_getRootNode(aNode)
+  {
+    let node = aNode;
+    let tmpNode;
+    while ((tmpNode = this.view.getParentObject(node)))
+      node = tmpNode;
+
+    return node;
+  },
+};
rename from browser/base/content/inspector.html
rename to browser/devtools/highlighter/inspector.html
rename from browser/base/content/inspector.js
rename to browser/devtools/highlighter/inspector.js
--- a/browser/base/content/inspector.js
+++ b/browser/devtools/highlighter/inspector.js
@@ -248,60 +248,78 @@ Highlighter.prototype = {
    */
   highlight: function Highlighter_highlight(aScroll)
   {
     // node is not set or node is not highlightable, bail
     if (!this.node || !this.isNodeHighlightable()) {
       return;
     }
 
+    if (aScroll) {
+      this.node.scrollIntoView();
+    }
+
     let clientRect = this.node.getBoundingClientRect();
 
+    // Go up in the tree of frames to determine the correct rectangle.
     // clientRect is read-only, we need to be able to change properties.
     let rect = {top: clientRect.top,
                 left: clientRect.left,
                 width: clientRect.width,
                 height: clientRect.height};
 
-    if (aScroll) {
-      this.node.scrollIntoView();
-    }
+    let frameWin = this.node.ownerDocument.defaultView;
+
+    // We iterate through all the parent windows.
+    while (true) {
+
+      // Does the selection overflow on the right of its window?
+      let diffx = frameWin.innerWidth - (rect.left + rect.width);
+      if (diffx < 0) {
+        rect.width += diffx;
+      }
 
-    // Go up in the tree of frames to determine the correct rectangle
-    // coordinates and size.
-    let frameWin = this.node.ownerDocument.defaultView;
-    do {
-      let frameRect = frameWin.frameElement ?
-                      frameWin.frameElement.getBoundingClientRect() :
-                      {top: 0, left: 0};
+      // Does the selection overflow on the bottom of its window?
+      let diffy = frameWin.innerHeight - (rect.top + rect.height);
+      if (diffy < 0) {
+        rect.height += diffy;
+      }
 
+      // Does the selection overflow on the left of its window?
+      if (rect.left < 0) {
+        rect.width += rect.left;
+        rect.left = 0;
+      }
+
+      // Does the selection overflow on the top of its window?
       if (rect.top < 0) {
         rect.height += rect.top;
         rect.top = 0;
       }
 
-      if (rect.left < 0) {
-        rect.width += rect.left;
-        rect.left = 0;
+      // Selection has been clipped to fit in its own window.
+
+      // Are we in the top-level window?
+      if (frameWin.parent === frameWin || !frameWin.frameElement) {
+        break;
       }
 
-      let diffx = frameWin.innerWidth - rect.left - rect.width;
-      if (diffx < 0) {
-        rect.width += diffx;
-      }
-      let diffy = frameWin.innerHeight - rect.top - rect.height;
-      if (diffy < 0) {
-        rect.height += diffy;
-      }
+      // We are in an iframe.
+      // We take into account the parent iframe position and its
+      // offset (borders and padding).
+      let frameRect = frameWin.frameElement.getBoundingClientRect();
 
-      rect.left += frameRect.left;
-      rect.top += frameRect.top;
+      let [offsetTop, offsetLeft] =
+        InspectorUI.getIframeContentOffset(frameWin.frameElement);
+
+      rect.top += frameRect.top + offsetTop;
+      rect.left += frameRect.left + offsetLeft;
 
       frameWin = frameWin.parent;
-    } while (frameWin != this.win);
+    }
 
     this.highlightRectangle(rect);
 
     if (this._highlighting) {
       Services.obs.notifyObservers(null,
         INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, null);
     }
   },
@@ -535,17 +553,20 @@ Highlighter.prototype = {
  * Main controller class for the Inspector.
  */
 var InspectorUI = {
   browser: null,
   tools: {},
   showTextNodesWithWhitespace: false,
   inspecting: false,
   treeLoaded: false,
-  prefEnabledName: "devtools.inspector.enabled",
+  get enabled()
+  {
+    return gPrefService.getBoolPref("devtools.inspector.enabled");
+  },
   isDirty: false,
 
   /**
    * Toggle the inspector interface elements on or off.
    *
    * @param aEvent
    *        The event that requested the UI change. Toolbar button or menu.
    */
@@ -627,22 +648,22 @@ var InspectorUI = {
       this.treeIFrame.setAttribute("ondblclick", "InspectorUI.onTreeDblClick(event);");
       this.treeIFrame = this.treePanel.insertBefore(this.treeIFrame, resizerBox);
     }
 
     this.treePanel.addEventListener("popupshown", function treePanelShown() {
       InspectorUI.treePanel.removeEventListener("popupshown",
         treePanelShown, false);
 
-        InspectorUI.treeIFrame.addEventListener("load",
-          function loadedInitializeTreePanel() {
-            InspectorUI.treeIFrame.removeEventListener("load",
-              loadedInitializeTreePanel, true);
-            InspectorUI.initializeTreePanel();
-          }, true);
+      InspectorUI.treeIFrame.addEventListener("load",
+        function loadedInitializeTreePanel() {
+          InspectorUI.treeIFrame.removeEventListener("load",
+            loadedInitializeTreePanel, true);
+          InspectorUI.initializeTreePanel();
+        }, true);
 
       let src = InspectorUI.treeIFrame.getAttribute("src");
       if (src != "chrome://browser/content/inspector.html") {
         InspectorUI.treeIFrame.setAttribute("src",
           "chrome://browser/content/inspector.html");
       } else {
         InspectorUI.treeIFrame.contentWindow.location.reload();
       }
@@ -756,22 +777,43 @@ var InspectorUI = {
 
     if (!next)
       delete this.treeWalker;
 
     return next;
   },
 
   /**
-   * Open inspector UI. tree. Add listeners for document scrolling,
-   * resize, tabContainer.TabSelect and others.
+   * Open inspector UI and HTML tree. Add listeners for document scrolling,
+   * resize, tabContainer.TabSelect and others. If a node is provided, then
+   * start inspecting it.
+   *
+   * @param [optional] aNode
+   *        The node to inspect.
    */
-  openInspectorUI: function IUI_openInspectorUI()
+  openInspectorUI: function IUI_openInspectorUI(aNode)
   {
-    // initialization
+    // Observer used to inspect the specified element from content after the
+    // inspector UI has been opened.
+    function inspectObserver(aElement) {
+      Services.obs.removeObserver(boundInspectObserver,
+                                  INSPECTOR_NOTIFICATIONS.OPENED,
+                                  false);
+      this.inspectNode(aElement);
+      this.stopInspecting();
+    };
+    var boundInspectObserver = inspectObserver.bind(this, aNode);
+
+    if (aNode) {
+      // Add the observer to inspect the node after initialization finishes.
+      Services.obs.addObserver(boundInspectObserver,
+                               INSPECTOR_NOTIFICATIONS.OPENED,
+                               false);
+    }
+    // Start initialization.
     this.browser = gBrowser.selectedBrowser;
     this.win = this.browser.contentWindow;
     this.winID = this.getWindowID(this.win);
     this.toolbar = document.getElementById("inspector-toolbar");
 
     if (!this.domplate) {
       Cu.import("resource:///modules/domplate.jsm", this);
       this.domplateUtils.setDOM(window);
@@ -1373,36 +1415,72 @@ var InspectorUI = {
    * @param integer aX
    * @param integer aY
    * @returns Node|null the element node found at the given coordinates.
    */
   elementFromPoint: function IUI_elementFromPoint(aDocument, aX, aY)
   {
     let node = aDocument.elementFromPoint(aX, aY);
     if (node && node.contentDocument) {
-      switch (node.nodeName.toLowerCase()) {
-        case "iframe":
-          let rect = node.getBoundingClientRect();
-          aX -= rect.left;
-          aY -= rect.top;
+      if (node instanceof HTMLIFrameElement) {
+        let rect = node.getBoundingClientRect();
+
+        // Gap between the iframe and its content window.
+        let [offsetTop, offsetLeft] = this.getIframeContentOffset(node);
+
+        aX -= rect.left + offsetLeft;
+        aY -= rect.top + offsetTop;
 
-        case "frame":
-          let subnode = this.elementFromPoint(node.contentDocument, aX, aY);
-          if (subnode) {
-            node = subnode;
-          }
+        if (aX < 0 || aY < 0) {
+          // Didn't reach the content document, still over the iframe.
+          return node;
+        }
+      }
+      if (node instanceof HTMLIFrameElement ||
+          node instanceof HTMLFrameElement) {
+        let subnode = this.elementFromPoint(node.contentDocument, aX, aY);
+        if (subnode) {
+          node = subnode;
+        }
       }
     }
     return node;
   },
 
   ///////////////////////////////////////////////////////////////////////////
   //// Utility functions
 
   /**
+   * Returns iframe content offset (iframe border + padding).
+   * Note: this function shouldn't need to exist, had the platform provided a
+   * suitable API for determining the offset between the iframe's content and
+   * its bounding client rect. Bug 626359 should provide us with such an API.
+   *
+   * @param aIframe
+   *        The iframe.
+   * @returns array [offsetTop, offsetLeft]
+   *          offsetTop is the distance from the top of the iframe and the
+   *            top of the content document.
+   *          offsetLeft is the distance from the left of the iframe and the
+   *            left of the content document.
+   */
+  getIframeContentOffset: function IUI_getIframeContentOffset(aIframe)
+  {
+    let style = aIframe.contentWindow.getComputedStyle(aIframe, null);
+
+    let paddingTop = parseInt(style.getPropertyValue("padding-top"));
+    let paddingLeft = parseInt(style.getPropertyValue("padding-left"));
+
+    let borderTop = parseInt(style.getPropertyValue("border-top-width"));
+    let borderLeft = parseInt(style.getPropertyValue("border-left-width"));
+
+    return [borderTop + paddingTop, borderLeft + paddingLeft];
+  },
+
+  /**
    * Does the given object have a class attribute?
    * @param aNode
    *        the DOM node.
    * @param aClass
    *        The class string.
    * @returns boolean
    */
   hasClass: function IUI_hasClass(aNode, aClass)
rename from browser/base/content/test/inspector/Makefile.in
rename to browser/devtools/highlighter/test/Makefile.in
--- a/browser/base/content/test/inspector/Makefile.in
+++ b/browser/devtools/highlighter/test/Makefile.in
@@ -29,21 +29,21 @@
 # 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 *****
 
-DEPTH		= ../../../../..
+DEPTH     = ../../../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
-relativesrcdir  = browser/base/content/test/inspector
+relativesrcdir  = browser/devtools/highlighter/test
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _BROWSER_FILES = \
 		browser_inspector_initialization.js \
 		browser_inspector_treeSelection.js \
 		browser_inspector_highlighter.js \
@@ -51,14 +51,15 @@ include $(topsrcdir)/config/rules.mk
 		browser_inspector_scrolling.js \
 		browser_inspector_store.js \
 		browser_inspector_tab_switch.js \
 		browser_inspector_treePanel_output.js \
 		browser_inspector_treePanel_input.html \
 		browser_inspector_treePanel_result.html \
 		browser_inspector_registertools.js \
 		browser_inspector_bug_665880.js \
+		browser_inspector_bug_674871.js \
 		browser_inspector_editor.js \
 		browser_inspector_bug_566084_location_changed.js \
 		$(NULL)
 
 libs::	$(_BROWSER_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
rename from browser/base/content/test/inspector/browser_inspector_bug_566084_location_changed.js
rename to browser/devtools/highlighter/test/browser_inspector_bug_566084_location_changed.js
rename from browser/base/content/test/inspector/browser_inspector_bug_665880.js
rename to browser/devtools/highlighter/test/browser_inspector_bug_665880.js
new file mode 100644
--- /dev/null
+++ b/browser/devtools/highlighter/test/browser_inspector_bug_674871.js
@@ -0,0 +1,114 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+
+function test()
+{
+  waitForExplicitFinish();
+
+  let doc;
+  let iframeNode, iframeBodyNode;
+
+  let iframeSrc = "<style>" +
+                  "body {" +
+                  "margin:0;" +
+                  "height:100%;" +
+                  "background-color:red" +
+                  "}" +
+                  "</style>" +
+                  "<body></body>";
+  let docSrc = "<style>" +
+               "iframe {" +
+               "height:200px;" +
+               "border: 11px solid black;" +
+               "padding: 13px;" +
+               "}" +
+               "body,iframe {" +
+               "margin:0" +
+               "}" +
+               "</style>" +
+               "<body>" +
+               "<iframe src='data:text/html," + iframeSrc + "'></iframe>" +
+               "</body>";
+
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function onload() {
+    gBrowser.selectedBrowser.removeEventListener("load", onload, true);
+    doc = content.document;
+    waitForFocus(setupTest, content);
+  }, true);
+
+  content.location = "data:text/html," + docSrc;
+
+  function setupTest()
+  {
+    iframeNode = doc.querySelector("iframe");
+    iframeBodyNode = iframeNode.contentDocument.querySelector("body");
+    ok(iframeNode, "we have the iframe node");
+    ok(iframeBodyNode, "we have the body node");
+    Services.obs.addObserver(runTests,
+      INSPECTOR_NOTIFICATIONS.OPENED, false);
+    InspectorUI.toggleInspectorUI();
+  }
+
+  function runTests()
+  {
+    Services.obs.removeObserver(runTests,
+      INSPECTOR_NOTIFICATIONS.OPENED);
+
+    executeSoon(function() {
+      Services.obs.addObserver(isTheIframeSelected,
+        INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
+
+      moveMouseOver(iframeNode, 1, 1);
+    });
+  }
+
+  function isTheIframeSelected()
+  {
+    Services.obs.removeObserver(isTheIframeSelected,
+      INSPECTOR_NOTIFICATIONS.HIGHLIGHTING);
+
+    is(InspectorUI.selection, iframeNode, "selection matches node");
+    iframeNode.style.marginBottom = doc.defaultView.innerHeight + "px";
+    doc.defaultView.scrollBy(0, 40);
+
+    executeSoon(function() {
+      Services.obs.addObserver(isTheIframeContentSelected,
+        INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
+
+      moveMouseOver(iframeNode, 40, 40);
+    });
+  }
+
+  function isTheIframeContentSelected()
+  {
+    Services.obs.removeObserver(isTheIframeContentSelected,
+      INSPECTOR_NOTIFICATIONS.HIGHLIGHTING);
+
+    is(InspectorUI.selection, iframeBodyNode, "selection matches node");
+    // 184 == 200 + 11(border) + 13(padding) - 40(scroll)
+    is(InspectorUI.highlighter._highlightRect.height, 184,
+      "highlighter height");
+
+    Services.obs.addObserver(finishUp,
+      INSPECTOR_NOTIFICATIONS.CLOSED, false);
+    InspectorUI.closeInspectorUI();
+  }
+
+  function finishUp() {
+    Services.obs.removeObserver(finishUp, INSPECTOR_NOTIFICATIONS.CLOSED);
+    doc = iframeNode = iframeBodyNode = null;
+    gBrowser.removeCurrentTab();
+    finish();
+  }
+
+
+  function moveMouseOver(aElement, x, y)
+  {
+    EventUtils.synthesizeMouse(aElement, x, y, {type: "mousemove"},
+                               aElement.ownerDocument.defaultView);
+  }
+
+}
+
rename from browser/base/content/test/inspector/browser_inspector_editor.js
rename to browser/devtools/highlighter/test/browser_inspector_editor.js
rename from browser/base/content/test/inspector/browser_inspector_highlighter.js
rename to browser/devtools/highlighter/test/browser_inspector_highlighter.js
rename from browser/base/content/test/inspector/browser_inspector_iframeTest.js
rename to browser/devtools/highlighter/test/browser_inspector_iframeTest.js
rename from browser/base/content/test/inspector/browser_inspector_initialization.js
rename to browser/devtools/highlighter/test/browser_inspector_initialization.js
--- a/browser/base/content/test/inspector/browser_inspector_initialization.js
+++ b/browser/devtools/highlighter/test/browser_inspector_initialization.js
@@ -31,44 +31,96 @@
  * 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 ***** */
+let doc;
+let salutation;
+
+function createDocument()
+{
+  doc.body.innerHTML = '<div id="first" style="{ margin: 10em; ' +
+    'font-size: 14pt; font-family: helvetica, sans-serif; color: #AAA}">\n' +
+    '<h1>Some header text</h1>\n' +
+    '<p id="salutation" style="{font-size: 12pt}">hi.</p>\n' +
+    '<p id="body" style="{font-size: 12pt}">I am a test-case. This text exists ' +
+    'solely to provide some things to test the inspector initialization.</p>\n' +
+    'If you are reading this, you should go do something else instead. Maybe ' +
+    'read a book. Or better yet, write some test-cases for another bit of code. ' +
+    '<span style="{font-style: italic}">Maybe more inspector test-cases!</span></p>\n' +
+    '<p id="closing">end transmission</p>\n' +
+    '</div>';
+  doc.title = "Inspector Initialization Test";
+  startInspectorTests();
+}
 
 function startInspectorTests()
 {
   ok(InspectorUI, "InspectorUI variable exists");
   Services.obs.addObserver(runInspectorTests,
     INSPECTOR_NOTIFICATIONS.OPENED, false);
   InspectorUI.toggleInspectorUI();
 }
 
 function runInspectorTests()
 {
   Services.obs.removeObserver(runInspectorTests,
     INSPECTOR_NOTIFICATIONS.OPENED, false);
-  Services.obs.addObserver(finishInspectorTests,
+  Services.obs.addObserver(runContextMenuTest,
     INSPECTOR_NOTIFICATIONS.CLOSED, false);
 
   ok(!InspectorUI.toolbar.hidden, "toolbar is visible");
   let iframe = document.getElementById("inspector-tree-iframe");
   is(InspectorUI.treeIFrame, iframe, "Inspector IFrame matches");
   ok(InspectorUI.inspecting, "Inspector is inspecting");
   ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open");
   ok(InspectorUI.highlighter, "Highlighter is up");
 
   executeSoon(function() {
     InspectorUI.closeInspectorUI();
   });
 }
 
+function runContextMenuTest()
+{
+  Services.obs.removeObserver(runContextMenuTest, INSPECTOR_NOTIFICATIONS.CLOSED, false);
+  Services.obs.addObserver(inspectNodesFromContextTest, INSPECTOR_NOTIFICATIONS.OPENED, false);
+  salutation = doc.getElementById("salutation");
+  ok(salutation, "hello, context menu test!");
+  let eventDeets = { type : "contextmenu", button : 2 };
+  let contextMenu = document.getElementById("contentAreaContextMenu");
+  ok(contextMenu, "we have the context menu");
+  let contextInspectMenuItem = document.getElementById("context-inspect");
+  ok(contextInspectMenuItem, "we have the inspect context menu item");
+  EventUtils.synthesizeMouse(salutation, 2, 2, eventDeets);
+  is(contextMenu.state, "showing", "context menu is open");
+  is(contextInspectMenuItem.hidden, !InspectorUI.enabled, "is context menu item enabled?");
+  contextMenu.hidePopup();
+  executeSoon(function() {
+    InspectorUI.openInspectorUI(salutation);
+  });
+}
+
+function inspectNodesFromContextTest()
+{
+  Services.obs.removeObserver(inspectNodesFromContextTest, INSPECTOR_NOTIFICATIONS.OPENED, false);
+  Services.obs.addObserver(finishInspectorTests, INSPECTOR_NOTIFICATIONS.CLOSED, false);
+  ok(!InspectorUI.inspecting, "Inspector is not actively highlighting");
+  is(InspectorUI.selection, salutation, "Inspector is highlighting salutation");
+  ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open");
+  // TODO: These tests depend on the style inspector patches.
+  todo(InspectorUI.isStylePanelOpen, "Inspector Style Panel is open");
+  todo(InspectorUI.isDOMPanelOpen, "Inspector DOM Panel is open");
+  InspectorUI.closeInspectorUI(true);
+}
+
 function finishInspectorTests()
 {
   Services.obs.removeObserver(finishInspectorTests,
     INSPECTOR_NOTIFICATIONS.CLOSED, false);
 
   ok(!InspectorUI.highlighter, "Highlighter is gone");
   ok(!InspectorUI.isTreePanelOpen, "Inspector Tree Panel is closed");
   ok(!InspectorUI.inspecting, "Inspector is not inspecting");
@@ -79,14 +131,15 @@ function finishInspectorTests()
 }
 
 function test()
 {
   waitForExplicitFinish();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-    waitForFocus(startInspectorTests, content);
+    doc = content.document;
+    waitForFocus(createDocument, content);
   }, true);
 
   content.location = "data:text/html,basic tests for inspector";
 }
 
rename from browser/base/content/test/inspector/browser_inspector_registertools.js
rename to browser/devtools/highlighter/test/browser_inspector_registertools.js
rename from browser/base/content/test/inspector/browser_inspector_scrolling.js
rename to browser/devtools/highlighter/test/browser_inspector_scrolling.js
rename from browser/base/content/test/inspector/browser_inspector_store.js
rename to browser/devtools/highlighter/test/browser_inspector_store.js
rename from browser/base/content/test/inspector/browser_inspector_tab_switch.js
rename to browser/devtools/highlighter/test/browser_inspector_tab_switch.js
rename from browser/base/content/test/inspector/browser_inspector_treePanel_click.js
rename to browser/devtools/highlighter/test/browser_inspector_treePanel_click.js
rename from browser/base/content/test/inspector/browser_inspector_treePanel_input.html
rename to browser/devtools/highlighter/test/browser_inspector_treePanel_input.html
rename from browser/base/content/test/inspector/browser_inspector_treePanel_output.js
rename to browser/devtools/highlighter/test/browser_inspector_treePanel_output.js
--- a/browser/base/content/test/inspector/browser_inspector_treePanel_output.js
+++ b/browser/devtools/highlighter/test/browser_inspector_treePanel_output.js
@@ -37,18 +37,18 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 let doc = null;
 let xhr = null;
 let expectedResult = "";
 
-const TEST_URI = "http://mochi.test:8888/browser/browser/base/content/test/inspector/browser_inspector_treePanel_input.html";
-const RESULT_URI = "http://mochi.test:8888/browser/browser/base/content/test/inspector/browser_inspector_treePanel_result.html";
+const TEST_URI = "http://mochi.test:8888/browser/browser/devtools/highlighter/test/browser_inspector_treePanel_input.html";
+const RESULT_URI = "http://mochi.test:8888/browser/browser/devtools/highlighter/test/browser_inspector_treePanel_result.html";
 
 function tabFocused()
 {
   xhr = new XMLHttpRequest();
   xhr.onreadystatechange = xhr_onReadyStateChange;
   xhr.open("GET", RESULT_URI, true);
   xhr.send(null);
 }
rename from browser/base/content/test/inspector/browser_inspector_treePanel_result.html
rename to browser/devtools/highlighter/test/browser_inspector_treePanel_result.html
rename from browser/base/content/test/inspector/browser_inspector_treeSelection.js
rename to browser/devtools/highlighter/test/browser_inspector_treeSelection.js
--- a/browser/devtools/jar.mn
+++ b/browser/devtools/jar.mn
@@ -1,7 +1,8 @@
 browser.jar:
     content/browser/NetworkPanel.xhtml            (webconsole/NetworkPanel.xhtml)
 *   content/browser/scratchpad.xul                (scratchpad/scratchpad.xul)
 *   content/browser/scratchpad.js                 (scratchpad/scratchpad.js)
     content/browser/csshtmltree.xhtml             (styleinspector/csshtmltree.xhtml)
     content/browser/orion.js                      (sourceeditor/orion/orion.js)
     content/browser/orion.css                     (sourceeditor/orion/orion.css)
+*   content/browser/inspector.html                (highlighter/inspector.html)
--- a/browser/devtools/sourceeditor/source-editor-textarea.jsm
+++ b/browser/devtools/sourceeditor/source-editor-textarea.jsm
@@ -1,9 +1,9 @@
-/* vim:set ts=2 sw=2 sts=2 et tw=80:
+/* vim:set ft=javascript ts=2 sw=2 sts=2 et tw=80:
  * ***** 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/
  *
@@ -124,17 +124,17 @@ SourceEditor.prototype = {
     this._editor = this._textbox.editor;
 
     this._expandTab = aConfig.expandTab !== undefined ?
                       aConfig.expandTab : SourceEditor.DEFAULTS.EXPAND_TAB;
     this._tabSize = aConfig.tabSize || SourceEditor.DEFAULTS.TAB_SIZE;
 
     this._textbox.style.MozTabSize = this._tabSize;
 
-    this._textbox.setAttribute("value", aConfig.placeholderText);
+    this._textbox.setAttribute("value", aConfig.placeholderText || "");
     this._textbox.setAttribute("class", "monospace");
     this._textbox.style.direction = "ltr";
     this._textbox.readOnly = aConfig.readOnly;
 
     // Make sure that the SourceEditor Selection events are fired properly.
     // Also make sure that the Tab key inserts spaces when expandTab is true.
     this._textbox.addEventListener("select", this._onSelect.bind(this), false);
     this._textbox.addEventListener("keypress", this._onKeyPress.bind(this), false);
--- a/browser/devtools/styleinspector/CssHtmlTree.jsm
+++ b/browser/devtools/styleinspector/CssHtmlTree.jsm
@@ -35,16 +35,17 @@
  * 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 ***** */
 
 const Cu = Components.utils;
+const FILTER_CHANGED_TIMEOUT = 300;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/PluralForm.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource:///modules/devtools/CssLogic.jsm");
 Cu.import("resource:///modules/devtools/Templater.jsm");
 
 var EXPORTED_SYMBOLS = ["CssHtmlTree", "PropertyView"];
@@ -60,31 +61,32 @@ var EXPORTED_SYMBOLS = ["CssHtmlTree", "
  */
 function CssHtmlTree(aStyleWin, aCssLogic, aPanel)
 {
   this.styleWin = aStyleWin;
   this.cssLogic = aCssLogic;
   this.doc = aPanel.ownerDocument;
   this.win = this.doc.defaultView;
   this.getRTLAttr = CssHtmlTree.getRTLAttr;
+  this.propertyViews = {};
 
   // The document in which we display the results (csshtmltree.xhtml).
   this.styleDocument = this.styleWin.contentWindow.document;
 
   // Nodes used in templating
   this.root = this.styleDocument.getElementById("root");
+  this.path = this.styleDocument.getElementById("path");
   this.templateRoot = this.styleDocument.getElementById("templateRoot");
+  this.templatePath = this.styleDocument.getElementById("templatePath");
   this.propertyContainer = this.styleDocument.getElementById("propertyContainer");
   this.templateProperty = this.styleDocument.getElementById("templateProperty");
   this.panel = aPanel;
 
   // The element that we're inspecting, and the document that it comes from.
   this.viewedElement = null;
-  this.viewedDocument = null;
-
   this.createStyleViews();
 }
 
 /**
  * Memonized lookup of a l10n string from a string bundle.
  * @param {string} aName The key to lookup.
  * @returns A localized version of the given key.
  */
@@ -143,86 +145,154 @@ XPCOMUtils.defineLazyGetter(CssHtmlTree,
   let mainWindow = Services.wm.getMostRecentWindow("navigator:browser");
   return mainWindow.getComputedStyle(mainWindow.gBrowser).direction;
 });
 
 XPCOMUtils.defineLazyGetter(CssHtmlTree, "_strings", function() Services.strings
     .createBundle("chrome://browser/locale/styleinspector.properties"));
 
 CssHtmlTree.prototype = {
+  htmlComplete: false,
+
+  // Used for cancelling timeouts in the style filter.
+  filterChangedTimeout: null,
+
+  // The search filter
+  searchField: null,
+  
+  // Reference to the "Only user Styles" checkbox.
+  onlyUserStylesCheckbox: null,
+
+  get showOnlyUserStyles()
+  {
+    return this.onlyUserStylesCheckbox.checked;
+  },
+
   /**
-   * Focus the output display on a specific element.
+   * Update the highlighted element. The CssHtmlTree panel will show the style
+   * information for the given element.
    * @param {nsIDOMElement} aElement The highlighted node to get styles for.
    */
   highlight: function CssHtmlTree_highlight(aElement)
   {
     if (this.viewedElement == aElement) {
       return;
     }
 
     this.viewedElement = aElement;
 
-    if (this.viewedElement) {
-      this.viewedDocument = this.viewedElement.ownerDocument;
-      CssHtmlTree.processTemplate(this.templateRoot, this.root, this);
+    CssHtmlTree.processTemplate(this.templatePath, this.path, this);
+
+    if (this.htmlComplete) {
+      this.refreshPanel();
     } else {
-      this.viewedDocument = null;
-      this.root.innerHTML = "";
-    }
-
-    this.propertyContainer.innerHTML = "";
+      CssHtmlTree.processTemplate(this.templateRoot, this.root, this);
 
-    // We use a setTimeout loop to display the properties in batches of 25 at a
-    // time. This gives a perceptibly more responsive UI and allows us to cancel
-    // the displaying of properties in the case that a new element is selected.
-    let i = 0;
-    let batchSize = 25;
-    let max = CssHtmlTree.propertyNames.length - 1;
-    function displayProperties() {
-      if (this.viewedElement == aElement && this.panel.isOpen()) {
-        // Display the next 25 properties
-        for (let step = i + batchSize; i < step && i <= max; i++) {
-          let propView = new PropertyView(this, CssHtmlTree.propertyNames[i]);
-          CssHtmlTree.processTemplate(
-              this.templateProperty, this.propertyContainer, propView, true);
-        }
-        if (i < max) {
-          // There are still some properties to display. We loop here to display
-          // the next batch of 25.
-          this.win.setTimeout(displayProperties.bind(this), 0);
+      // We use a setTimeout loop to display the properties in batches of 15 at a
+      // time. This results in a perceptibly more responsive UI.
+      let i = 0;
+      let batchSize = 15;
+      let max = CssHtmlTree.propertyNames.length - 1;
+      function displayProperties() {
+        if (this.viewedElement == aElement && this.panel.isOpen()) {
+          // Display the next 15 properties
+          for (let step = i + batchSize; i < step && i <= max; i++) {
+            let name = CssHtmlTree.propertyNames[i];
+            let propView = new PropertyView(this, name);
+            CssHtmlTree.processTemplate(this.templateProperty,
+              this.propertyContainer, propView, true);
+            propView.refreshMatchedSelectors();
+            propView.refreshUnmatchedSelectors();
+            this.propertyViews[name] = propView;
+          }
+          if (i < max) {
+            // There are still some properties to display. We loop here to display
+            // the next batch of 15.
+            this.win.setTimeout(displayProperties.bind(this), 50);
+          } else {
+            this.htmlComplete = true;
+            Services.obs.notifyObservers(null, "StyleInspector-populated", null);
+          }
         }
       }
+      this.win.setTimeout(displayProperties.bind(this), 50);
     }
-    this.win.setTimeout(displayProperties.bind(this), 0);
+  },
+
+  /**
+   * Refresh the panel content.
+   */
+  refreshPanel: function CssHtmlTree_refreshPanel()
+  {
+    for each(let propView in this.propertyViews) {
+      propView.refresh();
+    }
+    Services.obs.notifyObservers(null, "StyleInspector-populated", null);
   },
 
   /**
    * Called when the user clicks on a parent element in the "current element"
    * path.
    *
    * @param {Event} aEvent the DOM Event object.
    */
   pathClick: function CssHtmlTree_pathClick(aEvent)
   {
     aEvent.preventDefault();
     if (aEvent.target && this.viewedElement != aEvent.target.pathElement) {
-      this.propertyContainer.innerHTML = "";
       if (this.win.InspectorUI.selection) {
         if (aEvent.target.pathElement != this.win.InspectorUI.selection) {
           let elt = aEvent.target.pathElement;
           this.win.InspectorUI.inspectNode(elt);
           this.panel.selectNode(elt);
         }
       } else {
         this.panel.selectNode(aEvent.target.pathElement);
       }
     }
   },
 
   /**
+   * Called when the user enters a search term.
+   *
+   * @param {Event} aEvent the DOM Event object.
+   */
+  filterChanged: function CssHtmlTree_filterChanged(aEvent)
+  {
+    let win = this.styleWin.contentWindow;
+
+    if (this.filterChangedTimeout) {
+      win.clearTimeout(this.filterChangedTimeout);
+      this.filterChangeTimeout = null;
+    }
+
+    this.filterChangedTimeout = win.setTimeout(function() {
+      this.refreshPanel();
+    }.bind(this), FILTER_CHANGED_TIMEOUT);
+  },
+
+  /**
+   * The change event handler for the onlyUserStyles checkbox. When
+   * onlyUserStyles.checked is true we do not display properties that have no
+   * matched selectors, and we do not display UA styles. If .checked is false we
+   * do display even properties with no matched selectors, and we include the UA
+   * styles.
+   *
+   * @param {Event} aEvent the DOM Event object.
+   */
+  onlyUserStylesChanged: function CssHtmltree_onlyUserStylesChanged(aEvent)
+  {
+    this.cssLogic.sourceFilter = this.showOnlyUserStyles ?
+                                 CssLogic.FILTER.ALL :
+                                 CssLogic.FILTER.UA;
+    
+    this.refreshPanel();
+  },
+
+  /**
    * Provide access to the path to get from document.body to the selected
    * element.
    *
    * @return {array} the array holding the path from document.body to the
    * selected element.
    */
   get pathElements()
   {
@@ -268,184 +338,281 @@ CssHtmlTree.prototype = {
  * instance will render the rules.
  */
 function PropertyView(aTree, aName)
 {
   this.tree = aTree;
   this.name = aName;
   this.getRTLAttr = CssHtmlTree.getRTLAttr;
 
-  this.populated = false;
-  this.showUnmatched = false;
-
   this.link = "https://developer.mozilla.org/en/CSS/" + aName;
 
-  this.templateRules = aTree.styleDocument.getElementById("templateRules");
-
-  // The parent element which contains the open attribute
-  this.element = null;
-  // Destination for templateRules.
-  this.rules = null;
-
-  this.str = {};
+  this.templateMatchedSelectors = aTree.styleDocument.getElementById("templateMatchedSelectors");
+  this.templateUnmatchedSelectors = aTree.styleDocument.getElementById("templateUnmatchedSelectors");
 }
 
 PropertyView.prototype = {
-  /**
-   * The click event handler for the property name of the property view. If
-   * there are >0 rules then the rules are expanded. If there are 0 rules and
-   * >0 unmatched rules then the unmatched rules are expanded instead.
-   *
-   * @param {Event} aEvent the DOM event
-   */
-  click: function PropertyView_click(aEvent)
-  {
-    // Clicking on the property link itself is already handled
-    if (aEvent.target.tagName.toLowerCase() == "a") {
-      return;
-    }
+  // The parent element which contains the open attribute
+  element: null,
+
+  // Destination for property values
+  valueNode: null,
+
+  // Are matched rules expanded?
+  matchedExpanded: false,
+
+  // Are unmatched rules expanded?
+  unmatchedExpanded: false,
+
+  // Matched selector container
+  matchedSelectorsContainer: null,
+
+  // Unmatched selector container
+  unmatchedSelectorsContainer: null,
+
+  // Matched selector expando
+  matchedExpander: null,
 
-    if (this.element.hasAttribute("open")) {
-      this.element.removeAttribute("open");
-      return;
-    }
+  // Unmatched selector expando
+  unmatchedExpander: null,
+
+  // Container for X matched selectors
+  matchedSelectorsTitleNode: null,
 
-    if (!this.populated) {
-      let matchedRuleCount = this.propertyInfo.matchedRuleCount;
+  // Container for X unmatched selectors
+  unmatchedSelectorsTitleNode: null,
+
+  // Matched selectors table
+  matchedSelectorTable: null,
 
-      if (matchedRuleCount == 0 && this.showUnmatchedLink) {
-        this.showUnmatchedLinkClick(aEvent);
-      } else {
-        CssHtmlTree.processTemplate(this.templateRules, this.rules, this);
-      }
-      this.populated = true;
-    }
-    this.element.setAttribute("open", "");
-  },
+  // Unmatched selectors table
+  unmatchedSelectorTable: null,
+
+  // Cache for matched selector views
+  _matchedSelectorViews: null,
+
+  // Cache for unmatched selector views
+  _unmatchedSelectorViews: null,
+
+  // The previously selected element used for the selector view caches
+  prevViewedElement: null,
 
   /**
    * Get the computed style for the current property.
    *
    * @return {string} the computed style for the current property of the
    * currently highlighted element.
    */
   get value()
   {
     return this.propertyInfo.value;
   },
 
   /**
-   * An easy way to access the CssPropertyInfo behind this PropertyView
+   * An easy way to access the CssPropertyInfo behind this PropertyView.
    */
   get propertyInfo()
   {
     return this.tree.cssLogic.getPropertyInfo(this.name);
   },
 
   /**
-   * Compute the title of the property view. The title includes the number of
-   * selectors that match the currently selected element.
+   * Should this property be visible?
+   */
+  get visible()
+  {
+    if (this.tree.showOnlyUserStyles && this.matchedSelectorCount == 0) {
+      return false;
+    }
+
+    let searchTerm = this.tree.searchField.value.toLowerCase();
+    if (searchTerm && this.name.toLowerCase().indexOf(searchTerm) == -1 &&
+      this.value.toLowerCase().indexOf(searchTerm) == -1) {
+      return false;
+    }
+
+    return true;
+  },
+
+  /**
+   * Returns the className that should be assigned to the propertyView.
+   */
+  get className()
+  {
+    return this.visible ? "property-view" : "property-view-hidden";
+  },
+
+  /**
+   * The number of matched selectors.
+   */
+  get matchedSelectorCount()
+  {
+    return this.propertyInfo.matchedSelectors.length;
+  },
+
+  /**
+   * The number of unmatched selectors.
+   */
+  get unmatchedSelectorCount()
+  {
+    return this.propertyInfo.unmatchedSelectors.length;
+  },
+
+  /**
+   * Refresh the panel's CSS property value.
+   */
+  refresh: function PropertyView_refresh()
+  {
+    this.element.className = this.className;
+
+    if (this.prevViewedElement != this.tree.viewedElement) {
+      this._matchedSelectorViews = null;
+      this._unmatchedSelectorViews = null;
+      this.prevViewedElement = this.tree.viewedElement;
+    }
+
+    if (!this.tree.viewedElement || !this.visible) {
+      this.valueNode.innerHTML = "";
+      this.matchedSelectorsContainer.hidden = true;
+      this.unmatchedSelectorsContainer.hidden = true;
+      this.matchedSelectorTable.innerHTML = "";
+      this.unmatchedSelectorTable.innerHTML = "";
+      this.matchedExpander.removeAttribute("open");
+      this.unmatchedExpander.removeAttribute("open");
+      return;
+    }
+
+    this.valueNode.innerHTML = this.propertyInfo.value;
+    
+    this.refreshMatchedSelectors();
+    this.refreshUnmatchedSelectors();
+  },
+
+  /**
+   * Refresh the panel matched rules.
+   */
+  refreshMatchedSelectors: function PropertyView_refreshMatchedSelectors()
+  {
+    this.matchedSelectorsTitleNode.innerHTML = this.matchedSelectorTitle();
+    this.matchedSelectorsContainer.hidden = this.matchedSelectorCount == 0;
+
+    if (this.matchedExpanded && this.matchedSelectorCount > 0) {
+      CssHtmlTree.processTemplate(this.templateMatchedSelectors,
+        this.matchedSelectorTable, this);
+      this.matchedExpander.setAttribute("open", "");
+    } else {
+      this.matchedSelectorTable.innerHTML = "";
+      this.matchedExpander.removeAttribute("open");
+    }
+  },
+
+  /**
+   * Refresh the panel unmatched rules.
+   */
+  refreshUnmatchedSelectors: function PropertyView_refreshUnmatchedSelectors() {
+    this.unmatchedSelectorsTitleNode.innerHTML = this.unmatchedSelectorTitle();
+    this.unmatchedSelectorsContainer.hidden = this.unmatchedSelectorCount == 0;
+
+    if (this.unmatchedExpanded && this.unmatchedSelectorCount > 0) {
+      CssHtmlTree.processTemplate(this.templateUnmatchedSelectors,
+          this.unmatchedSelectorTable, this);
+      this.unmatchedExpander.setAttribute("open", "");
+    } else {
+      this.unmatchedSelectorTable.innerHTML = "";
+      this.unmatchedExpander.removeAttribute("open");
+    }
+  },
+
+  /**
+   * Compute the title of the matched selector expander. The title includes the
+   * number of selectors that match the currently selected element.
    *
-   * @param {nsIDOMElement} aElement reference to the DOM element where the rule
-   * title needs to be displayed.
    * @return {string} The rule title.
    */
-  ruleTitle: function PropertyView_ruleTitle(aElement)
+  matchedSelectorTitle: function PropertyView_matchedSelectorTitle()
   {
     let result = "";
-    let matchedSelectorCount = this.propertyInfo.matchedSelectors.length;
 
-    if (matchedSelectorCount > 0) {
-      aElement.classList.add("rule-count");
-      aElement.firstElementChild.className = "expander";
-
-      let str = CssHtmlTree.l10n("property.numberOfSelectors");
-      result = PluralForm.get(matchedSelectorCount, str)
-          .replace("#1", matchedSelectorCount);
-    } else if (this.showUnmatchedLink) {
-      aElement.classList.add("rule-unmatched");
-      aElement.firstElementChild.className = "expander";
-
-      let unmatchedSelectorCount = this.propertyInfo.unmatchedSelectors.length;
-      let str = CssHtmlTree.l10n("property.numberOfUnmatchedSelectors");
-      result = PluralForm.get(unmatchedSelectorCount, str)
-          .replace("#1", unmatchedSelectorCount);
+    if (this.matchedSelectorCount > 0) {
+      let str = CssHtmlTree.l10n("property.numberOfMatchedSelectors");
+      result = PluralForm.get(this.matchedSelectorCount, str)
+                         .replace("#1", this.matchedSelectorCount);
     }
     return result;
   },
 
   /**
-   * Close the property view.
+   * Compute the title of the unmatched selector expander. The title includes
+   * the number of selectors that match the currently selected element.
+   *
+   * @return {string} The rule title.
    */
-  close: function PropertyView_close()
+  unmatchedSelectorTitle: function PropertyView_unmatchedSelectorTitle()
   {
-    if (this.rules && this.element) {
-      this.element.removeAttribute("open");
-    }
-  },
+    let result = "";
 
-  /**
-   * Reset the property view.
-   */
-  reset: function PropertyView_reset()
-  {
-    this.close();
-    this.populated = false;
-    this.showUnmatched = false;
-    this.element = false;
+    if (this.unmatchedSelectorCount > 0) {
+      let str = CssHtmlTree.l10n("property.numberOfUnmatchedSelectors");
+      result = PluralForm.get(this.unmatchedSelectorCount, str)
+                         .replace("#1", this.unmatchedSelectorCount);
+    }
+    return result;
   },
 
   /**
-   * Provide access to the SelectorViews that we are currently displaying
+   * Provide access to the matched SelectorViews that we are currently
+   * displaying.
    */
-  get selectorViews()
+  get matchedSelectorViews()
   {
-    var all = [];
-
-    function convert(aSelectorInfo) {
-      all.push(new SelectorView(aSelectorInfo));
+    if (!this._matchedSelectorViews) {
+      this._matchedSelectorViews = [];
+      this.propertyInfo.matchedSelectors.forEach(
+        function matchedSelectorViews_convert(aSelectorInfo) {
+          this._matchedSelectorViews.push(new SelectorView(aSelectorInfo));
+        }, this);
     }
 
-    this.propertyInfo.matchedSelectors.forEach(convert);
-    if (this.showUnmatched) {
-      this.propertyInfo.unmatchedSelectors.forEach(convert);
+    return this._matchedSelectorViews;
+  },
+
+    /**
+   * Provide access to the unmatched SelectorViews that we are currently
+   * displaying.
+   */
+  get unmatchedSelectorViews()
+  {
+    if (!this._unmatchedSelectorViews) {
+      this._unmatchedSelectorViews = [];
+      this.propertyInfo.unmatchedSelectors.forEach(
+        function unmatchedSelectorViews_convert(aSelectorInfo) {
+          this._unmatchedSelectorViews.push(new SelectorView(aSelectorInfo));
+        }, this);
     }
 
-    return all;
+    return this._unmatchedSelectorViews;
   },
 
   /**
-   * Should we display a 'X unmatched rules' link?
-   * @return {boolean} false if we are already showing the unmatched links or
-   * if there are none to display, true otherwise.
+   * The action when a user expands matched selectors.
    */
-  get showUnmatchedLink()
+  matchedSelectorsClick: function PropertyView_matchedSelectorsClick(aEvent)
   {
-    return !this.showUnmatched && this.propertyInfo.unmatchedRuleCount > 0;
+    this.matchedExpanded = !this.matchedExpanded;
+    this.refreshMatchedSelectors();
+    aEvent.preventDefault();
   },
 
   /**
-   * The UI has a link to allow the user to display unmatched selectors.
-   * This provides localized link text.
+   * The action when a user expands unmatched selectors.
    */
-  get showUnmatchedLinkText()
+  unmatchedSelectorsClick: function PropertyView_unmatchedSelectorsClick(aEvent)
   {
-    let smur = CssHtmlTree.l10n("rule.showUnmatchedLink");
-    let unmatchedSelectorCount = this.propertyInfo.unmatchedSelectors.length;
-    let plural = PluralForm.get(unmatchedSelectorCount, smur);
-    return plural.replace("#1", unmatchedSelectorCount);
-  },
-
-  /**
-   * The action when a user clicks the 'show unmatched' link.
-   */
-  showUnmatchedLinkClick: function PropertyView_showUnmatchedLinkClick(aEvent)
-  {
-    this.showUnmatched = true;
-    CssHtmlTree.processTemplate(this.templateRules, this.rules, this);
+    this.unmatchedExpanded = !this.unmatchedExpanded;
+    this.refreshUnmatchedSelectors();
     aEvent.preventDefault();
   },
 };
 
 /**
  * A container to view us easy access to display data from a CssRule
  */
 function SelectorView(aSelectorInfo)
--- a/browser/devtools/styleinspector/StyleInspector.jsm
+++ b/browser/devtools/styleinspector/StyleInspector.jsm
@@ -63,28 +63,26 @@ var StyleInspector = {
    */
   createPanel: function SI_createPanel(aPreserveOnHide)
   {
     let win = Services.wm.getMostRecentWindow("navigator:browser");
     let popupSet = win.document.getElementById("mainPopupSet");
     let ns = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
     let panel = win.document.createElementNS(ns, "panel");
 
+    panel.setAttribute("class", "styleInspector");
     panel.setAttribute("orient", "vertical");
     panel.setAttribute("ignorekeys", "true");
     panel.setAttribute("noautofocus", "true");
     panel.setAttribute("noautohide", "true");
     panel.setAttribute("titlebar", "normal");
     panel.setAttribute("close", "true");
     panel.setAttribute("label", StyleInspector.l10n("panelTitle"));
-
-    // size panel to 200px wide by half browser height - 60.
-    let contentWindow = win.gBrowser.selectedBrowser.contentWindow;
-    panel.setAttribute("width", 200);
-    panel.setAttribute("height", contentWindow.outerHeight / 2 - 60);
+    panel.setAttribute("width", 350);
+    panel.setAttribute("height", win.screen.height / 2);
 
     let vbox = win.document.createElement("vbox");
     vbox.setAttribute("flex", "1");
     panel.appendChild(vbox);
 
     let iframe = win.document.createElementNS(ns, "iframe");
     iframe.setAttribute("flex", "1");
     iframe.setAttribute("tooltip", "aHTMLTooltip");
--- a/browser/devtools/styleinspector/csshtmltree.xhtml
+++ b/browser/devtools/styleinspector/csshtmltree.xhtml
@@ -61,29 +61,49 @@
     href="chrome://browser/skin/devtools/csshtmltree.css" />
 </head>
 <body role="application">
 
 <!-- The output from #templateRoot (below) is inserted here. -->
 <div id="root">
 </div>
 
+<!-- The output from #templatePath (below) is inserted here. -->
+<div id="path">
+</div>
+
 <!-- The output from #templateProperty (below) is appended here. -->
 <div id="propertyContainer">
 </div>
 
 <!--
 To visually debug the templates without running firefox, alter the display:none
 -->
 <div style="display:none;">
   <!--
-  templateRoot sits at the top of the window showing what we're looking at.
-  For data it needs an instance of CssHtmlTree.
+  templateRoot sits at the top of the window and contains the "include default
+  styles" checkbox. For data it needs an instance of CssHtmlTree.
   -->
   <div id="templateRoot">
+    <div class="filters">
+      <label class="userStylesLabel" dir="${getRTLAttr}">
+        &userStylesLabel;
+        <input class="userStyles" save="${onlyUserStylesCheckbox}" type="checkbox"
+               onchange="${onlyUserStylesChanged}" checked=""/>
+      </label>
+      <input save="${searchField}" class="searchfield" type="text"
+             oninput="${filterChanged}"/>
+    </div>
+  </div>
+
+  <!--
+  templatePath sits just below the top of the window showing what we're looking
+  at. For data it needs an instance of CssHtmlTree.
+  -->
+  <div id="templatePath">
     <p class="path">
       <label dir="${getRTLAttr}">&lookingAtLabel;</label>
       <ol>
         <li foreach="item in ${pathElements}" dir="${getRTLAttr}">
           <a href="#" onclick="${pathClick}" __pathElement="${item.element}">
             ${__element.pathElement = item.element; item.display}
           </a>
         </li>
@@ -93,61 +113,92 @@ To visually debug the templates without 
 
   <!--
   TemplateProperty lists the properties themselves. Each needs data like this:
   {
     property: ... // PropertyView from CssHtmlTree.jsm
   }
   -->
   <div id="templateProperty">
-    <div class="property-view" save="${element}" dir="${getRTLAttr}">
-      <div class="property-header" onclick="${click}">
+    <div class="${className}" save="${element}" dir="${getRTLAttr}">
+      <div class="property-header">
         <div class="property-name" dir="${getRTLAttr}">
           <a class="link" target="_blank" title="&helpLinkTitle;"
               href="${link}">${name}</a>
         </div>
-        <div class="property-value" dir="ltr">${value}</div>
-        <div class="link" dir="${getRTLAttr}">
-          <div></div>${ruleTitle(__element)}
+        <div save="${valueNode}" class="property-value" dir="ltr">${value}</div>
+      </div>
+
+      <div save="${matchedSelectorsContainer}" class="rulelink" dir="${getRTLAttr}">
+        <div onclick="${matchedSelectorsClick}" class="rule-matched">
+          <div save="${matchedExpander}" class="expander"></div>
+          <div save="${matchedSelectorsTitleNode}">
+            ${matchedSelectorTitle(__element)}
+          </div>
         </div>
+        <table save="${matchedSelectorTable}" dir="${getRTLAttr}"></table>
       </div>
-      <table class="rules" save="${rules}" dir="${getRTLAttr}"></table>
+
+      <div save="${unmatchedSelectorsContainer}" class="rulelink" dir="${getRTLAttr}">
+        <div onclick="${unmatchedSelectorsClick}" class="rule-unmatched">
+          <div save="${unmatchedExpander}" class="expander"></div>
+          <div save="${unmatchedSelectorsTitleNode}">
+            ${unmatchedSelectorTitle(__element)}
+          </div>
+        </div>
+        <table save="${unmatchedSelectorTable}" dir="${getRTLAttr}"></table>
+      </div>
     </div>
   </div>
 
   <!--
-  A templateRules sits inside each templateProperties showing the list of rules
-  that affect that property. Each needs data like this:
+  A templateMatchedSelectors sits inside each templateProperties showing the
+  list of selectors that affect that property. Each needs data like this:
   {
-    selectors: ..., // from cssLogic.getPropertyInfo(x).[un]matchedSelectors
-    statusText: function(status) {}, // convert rule.status to readable text
-    showUnmatchedRules: true / false, // show a "more unmatched rules" link
-    showUnmatchedRulesClick: function() {}, // click event handler for the
-        "show more unmatched rules"
+    matchedSelectorViews: ..., // from cssHtmlTree.propertyViews[name].matchedSelectorViews
   }
   This is a template so the parent does not need to be a table, except that
   using a div as the parent causes the DOM to muck with the tr elements
   -->
-  <table id="templateRules">
-    <loop foreach="selector in ${selectorViews}" if="${selector.selectorInfo.sheetAllowed}">
-      <tr>
-        <td dir="ltr" class="rule-text ${selector.statusClass}">
-          ${selector.humanReadableText(__element)}
-        </td>
-        <td class="rule-link">
-          <a target="_blank" href="view-source:${selector.selectorInfo.href}" class="link"
-              title="${selector.selectorInfo.href}">${selector.selectorInfo.source}</a>
-        </td>
-      </tr>
-    </loop>
-    <tr if="${showUnmatchedLink}">
-      <td colspan="4">
-        <div class="expander unmatched-rule"></div>
-        <div class="unmatched">
-          <a href="#" onclick="${showUnmatchedLinkClick}" class="unmatchedlink">${showUnmatchedLinkText}</a>
-        </div>
-      </td>
-    </tr>
-  </table>
+  <div id="templateMatchedSelectors">
+    <table>
+      <loop foreach="selector in ${matchedSelectorViews}">
+        <tr>
+          <td dir="ltr" class="rule-text ${selector.statusClass}">
+            ${selector.humanReadableText(__element)}
+          </td>
+          <td class="rule-link">
+            <a target="_blank" href="view-source:${selector.selectorInfo.href}" class="link"
+                title="${selector.selectorInfo.href}">${selector.selectorInfo.source}</a>
+          </td>
+        </tr>
+      </loop>
+    </table>
+  </div>
+
+  <!--
+  A templateUnmatchedSelectors sits inside each templateProperties showing the
+  list of selectors that fail to affect that property. Each needs data like this:
+  {
+    unmatchedSelectorViews: ..., // from cssHtmlTree.propertyViews[name].unmatchedSelectorViews
+  }
+  This is a template so the parent does not need to be a table, except that
+  using a div as the parent causes the DOM to muck with the tr elements
+  -->
+  <div id="templateUnmatchedSelectors">
+    <table>
+      <loop foreach="selector in ${unmatchedSelectorViews}">
+        <tr>
+          <td dir="ltr" class="rule-text unmatched">
+            ${selector.humanReadableText(__element)}
+          </td>
+          <td class="rule-link">
+            <a target="_blank" href="view-source:${selector.selectorInfo.href}" class="link"
+                title="${selector.selectorInfo.href}">${selector.selectorInfo.source}</a>
+          </td>
+        </tr>
+      </loop>
+    </table>
+  </div>
 </div>
 
 </body>
 </html>
--- a/browser/devtools/styleinspector/test/browser/Makefile.in
+++ b/browser/devtools/styleinspector/test/browser/Makefile.in
@@ -44,16 +44,18 @@ relativesrcdir  = browser/devtools/style
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _BROWSER_TEST_FILES = \
   browser_styleinspector.js \
   browser_styleinspector_webconsole.js \
   browser_bug683672.js \
+  browser_styleinspector_bug_672746_default_styles.js \
+  browser_styleinspector_bug_672744_search_filter.js \
   head.js \
   $(NULL)
 
 _BROWSER_TEST_PAGES = \
   browser_styleinspector_webconsole.htm \
   browser_bug683672.html \
   $(NULL)
 
--- a/browser/devtools/styleinspector/test/browser/browser_bug683672.js
+++ b/browser/devtools/styleinspector/test/browser/browser_bug683672.js
@@ -56,26 +56,25 @@ function testMatchedSelectors()
       "style inspector node matches the selected node");
 
   let propertyView = new PropertyView(htmlTree, "color");
   let numMatchedSelectors = propertyView.propertyInfo.matchedSelectors.length;
 
   is(numMatchedSelectors, 6,
       "CssLogic returns the correct number of matched selectors for div");
 
-  let dummy = content.document.getElementById("dummy");
-  let returnedRuleTitle = propertyView.ruleTitle(dummy);
-  let str = CssHtmlTree.l10n("property.numberOfSelectors");
-  let calculatedRuleTitle = PluralForm.get(numMatchedSelectors, str)
+  let returnedSelectorTitle = propertyView.matchedSelectorTitle();
+  let str = CssHtmlTree.l10n("property.numberOfMatchedSelectors");
+  let calculatedSelectorTitle = PluralForm.get(numMatchedSelectors, str)
                                       .replace("#1", numMatchedSelectors);
 
-  info("returnedRuleTitle: '" + returnedRuleTitle + "'");
+  info("returnedSelectorTitle: '" + returnedSelectorTitle + "'");
 
-  is(returnedRuleTitle, calculatedRuleTitle,
-      "returned title for matched rules is correct");
+  is(returnedSelectorTitle, calculatedSelectorTitle,
+      "returned title for matched selectors is correct");
 }
 
 function testUnmatchedSelectors()
 {
   info("checking selector counts, unmatched rules and titles");
   let body = content.document.body;
   ok(body, "captain, we have a body");
 
@@ -88,26 +87,25 @@ function testUnmatchedSelectors()
       "style inspector node matches the selected node");
 
   let propertyView = new PropertyView(htmlTree, "color");
   let numUnmatchedSelectors = propertyView.propertyInfo.unmatchedSelectors.length;
 
   is(numUnmatchedSelectors, 13,
       "CssLogic returns the correct number of unmatched selectors for body");
 
-  let dummy = content.document.getElementById("dummy");
-  let returnedRuleTitle = propertyView.ruleTitle(dummy);
+  let returnedSelectorTitle = propertyView.unmatchedSelectorTitle();
   let str = CssHtmlTree.l10n("property.numberOfUnmatchedSelectors");
-  let calculatedRuleTitle = PluralForm.get(numUnmatchedSelectors, str)
+  let calculatedSelectorTitle = PluralForm.get(numUnmatchedSelectors, str)
                                       .replace("#1", numUnmatchedSelectors);
 
-  info("returnedRuleTitle: '" + returnedRuleTitle + "'");
+  info("returnedSelectorTitle: '" + returnedSelectorTitle + "'");
 
-  is(returnedRuleTitle, calculatedRuleTitle,
-      "returned title for unmatched rules is correct");
+  is(returnedSelectorTitle, calculatedSelectorTitle,
+      "returned title for unmatched selectors is correct");
 }
 
 function finishUp()
 {
   Services.obs.removeObserver(finishUp, "StyleInspector-closed", false);
   ok(!stylePanel.isOpen(), "style inspector is closed");
   doc = stylePanel = null;
   gBrowser.removeCurrentTab();
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser/browser_styleinspector_bug_672744_search_filter.js
@@ -0,0 +1,112 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the search filter works properly.
+
+let doc;
+let stylePanel;
+
+function createDocument()
+{
+  doc.body.innerHTML = '<style type="text/css"> ' +
+    '.matches {color: #F00;}</style>' +
+    '<span id="matches" class="matches">Some styled text</span>' +
+    '</div>';
+  doc.title = "Style Inspector Search Filter Test";
+  ok(window.StyleInspector, "StyleInspector exists");
+  ok(StyleInspector.isEnabled, "style inspector preference is enabled");
+  stylePanel = StyleInspector.createPanel();
+  Services.obs.addObserver(runStyleInspectorTests, "StyleInspector-opened", false);
+  stylePanel.openPopup(gBrowser.selectedBrowser, "end_before", 0, 0, false, false);
+}
+
+function runStyleInspectorTests()
+{
+  Services.obs.removeObserver(runStyleInspectorTests, "StyleInspector-opened", false);
+
+  ok(stylePanel.isOpen(), "style inspector is open");
+
+  Services.obs.addObserver(SI_toggleDefaultStyles, "StyleInspector-populated", false);
+  SI_inspectNode();
+}
+
+function SI_inspectNode()
+{
+  var span = doc.querySelector("#matches");
+  ok(span, "captain, we have the matches span");
+
+  let htmlTree = stylePanel.cssHtmlTree;
+  stylePanel.selectNode(span);
+
+  is(span, htmlTree.viewedElement,
+    "style inspector node matches the selected node");
+  is(htmlTree.viewedElement, stylePanel.cssLogic.viewedElement,
+     "cssLogic node matches the cssHtmlTree node");
+}
+
+function SI_toggleDefaultStyles()
+{
+  Services.obs.removeObserver(SI_toggleDefaultStyles, "StyleInspector-populated", false);
+
+  info("clearing \"only user styles\" checkbox");
+  let iframe = stylePanel.querySelector("iframe");
+  let checkbox = iframe.contentDocument.querySelector(".userStyles");
+  Services.obs.addObserver(SI_AddFilterText, "StyleInspector-populated", false);
+  EventUtils.synthesizeMouse(checkbox, 5, 5, {}, iframe.contentWindow);
+}
+
+function SI_AddFilterText()
+{
+  Services.obs.removeObserver(SI_AddFilterText, "StyleInspector-populated", false);
+
+  let iframe = stylePanel.querySelector("iframe");
+  let searchbar = iframe.contentDocument.querySelector(".searchfield");
+
+  Services.obs.addObserver(SI_checkFilter, "StyleInspector-populated", false);
+  info("setting filter text to \"color\"");
+  searchbar.focus();
+  EventUtils.synthesizeKey("c", {}, iframe.contentWindow);
+  EventUtils.synthesizeKey("o", {}, iframe.contentWindow);
+  EventUtils.synthesizeKey("l", {}, iframe.contentWindow);
+  EventUtils.synthesizeKey("o", {}, iframe.contentWindow);
+  EventUtils.synthesizeKey("r", {}, iframe.contentWindow);
+}
+
+function SI_checkFilter()
+{
+  Services.obs.removeObserver(SI_checkFilter, "StyleInspector-populated", false);
+  let propertyViews = stylePanel.cssHtmlTree.propertyViews;
+
+  info("check that the correct properties are visible");
+  for each(let propView in propertyViews) {
+    let name = propView.name;
+    is(propView.visible, name.indexOf("color") > -1,
+      "span " + name + " property visibility check");
+  }
+
+  Services.obs.addObserver(finishUp, "StyleInspector-closed", false);
+  stylePanel.hidePopup();
+}
+
+function finishUp()
+{
+  Services.obs.removeObserver(finishUp, "StyleInspector-closed", false);
+  ok(!stylePanel.isOpen(), "style inspector is closed");
+  doc = stylePanel = null;
+  gBrowser.removeCurrentTab();
+  finish();
+}
+
+function test()
+{
+  waitForExplicitFinish();
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
+    gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
+    doc = content.document;
+    waitForFocus(createDocument, content);
+  }, true);
+
+  content.location = "data:text/html,default styles test";
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser/browser_styleinspector_bug_672746_default_styles.js
@@ -0,0 +1,107 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the checkbox to show only user styles works properly.
+
+let doc;
+let stylePanel;
+
+function createDocument()
+{
+  doc.body.innerHTML = '<style type="text/css"> ' +
+    '.matches {color: #F00;}</style>' +
+    '<span id="matches" class="matches">Some styled text</span>' +
+    '</div>';
+  doc.title = "Style Inspector Default Styles Test";
+  ok(window.StyleInspector, "StyleInspector exists");
+  ok(StyleInspector.isEnabled, "style inspector preference is enabled");
+  stylePanel = StyleInspector.createPanel();
+  Services.obs.addObserver(runStyleInspectorTests, "StyleInspector-opened", false);
+  stylePanel.openPopup(gBrowser.selectedBrowser, "end_before", 0, 0, false, false);
+}
+
+function runStyleInspectorTests()
+{
+  Services.obs.removeObserver(runStyleInspectorTests, "StyleInspector-opened", false);
+
+  ok(stylePanel.isOpen(), "style inspector is open");
+
+  Services.obs.addObserver(SI_check, "StyleInspector-populated", false);
+  SI_inspectNode();
+}
+
+function SI_inspectNode()
+{
+  let span = doc.querySelector("#matches");
+  ok(span, "captain, we have the matches span");
+
+  let htmlTree = stylePanel.cssHtmlTree;
+  stylePanel.selectNode(span);
+
+  is(span, htmlTree.viewedElement,
+    "style inspector node matches the selected node");
+  is(htmlTree.viewedElement, stylePanel.cssLogic.viewedElement,
+     "cssLogic node matches the cssHtmlTree node");
+}
+
+function SI_check()
+{
+  Services.obs.removeObserver(SI_check, "StyleInspector-populated", false);
+  is(propertyVisible("color"), true,
+    "span #matches color property is visible");
+  is(propertyVisible("background-color"), false,
+    "span #matches background-color property is hidden");
+
+  SI_toggleDefaultStyles();
+}
+
+function SI_toggleDefaultStyles()
+{
+  // Click on the checkbox.
+  let iframe = stylePanel.querySelector("iframe");
+  let checkbox = iframe.contentDocument.querySelector(".userStyles");
+  Services.obs.addObserver(SI_checkDefaultStyles, "StyleInspector-populated", false);
+  EventUtils.synthesizeMouse(checkbox, 5, 5, {}, iframe.contentWindow);
+}
+
+function SI_checkDefaultStyles()
+{
+  Services.obs.removeObserver(SI_checkDefaultStyles, "StyleInspector-populated", false);
+  // Check that the default styles are now applied.
+  is(propertyVisible("color"), true,
+      "span color property is visible");
+  is(propertyVisible("background-color"), true,
+      "span background-color property is visible");
+
+  Services.obs.addObserver(finishUp, "StyleInspector-closed", false);
+  stylePanel.hidePopup();
+}
+
+function propertyVisible(aName)
+{
+  let propertyViews = stylePanel.cssHtmlTree.propertyViews;
+  return propertyViews[aName].className == "property-view";
+}
+
+function finishUp()
+{
+  Services.obs.removeObserver(finishUp, "StyleInspector-closed", false);
+  ok(!stylePanel.isOpen(), "style inspector is closed");
+  doc = stylePanel = null;
+  gBrowser.removeCurrentTab();
+  finish();
+}
+
+function test()
+{
+  waitForExplicitFinish();
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
+    gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
+    doc = content.document;
+    waitForFocus(createDocument, content);
+  }, true);
+
+  content.location = "data:text/html,default styles test";
+}
--- a/browser/devtools/webconsole/HUDService.jsm
+++ b/browser/devtools/webconsole/HUDService.jsm
@@ -3610,33 +3610,33 @@ HeadsUpDisplay.prototype = {
         ]
       }
     ];
 
     let toolbar = this.makeXULNode("toolbar");
     toolbar.setAttribute("class", "hud-console-filter-toolbar");
     toolbar.setAttribute("mode", "full");
 
-#ifdef XP_MAC
+#ifdef XP_MACOSX
     this.makeCloseButton(toolbar);
 #endif
 
     for (let i = 0; i < BUTTONS.length; i++) {
       this.makeFilterButton(toolbar, BUTTONS[i]);
     }
 
     toolbar.appendChild(this.filterSpacer);
 
     let positionUI = this.createPositionUI();
     toolbar.appendChild(positionUI);
 
     toolbar.appendChild(this.filterBox);
     this.makeClearConsoleButton(toolbar);
 
-#ifndef XP_MAC
+#ifndef XP_MACOSX
     this.makeCloseButton(toolbar);
 #endif
 
     return toolbar;
   },
 
   /**
    * Creates the UI for re-positioning the console
@@ -4433,17 +4433,17 @@ function JSTermHelper(aJSTerm)
       errstr = HUDService.getStr("inspectStyle.mustBeDomNode");
     } else if (!(aNode.style instanceof Ci.nsIDOMCSSStyleDeclaration)) {
       errstr = HUDService.getStr("inspectStyle.nodeHasNoStyleProps");
     }
 
     if (!errstr) {
       let stylePanel = StyleInspector.createPanel();
       stylePanel.setAttribute("hudToolId", aJSTerm.hudId);
-      stylePanel.selectNode(aNode, true);
+      stylePanel.selectNode(aNode);
     } else {
       aJSTerm.writeOutput(errstr + "\n", CATEGORY_OUTPUT, SEVERITY_ERROR);
     }
   };
 
   /**
    * Prints aObject to the output.
    *
--- a/browser/devtools/webconsole/test/browser/browser_webconsole_bug_580400_groups.js
+++ b/browser/devtools/webconsole/test/browser/browser_webconsole_bug_580400_groups.js
@@ -77,13 +77,13 @@ function testGroups() {
     outputNode.getItemAtIndex(i).timestamp = 0;   // a "far past" value
   }
 
   jsterm.execute("2");
   is(outputNode.querySelectorAll(".webconsole-new-group").length, 1,
      "one group divider exists after the third console message");
 
   jsterm.clearOutput();
-  jsterm.history.splice(0);   // workaround for bug 592552
+  jsterm.history.splice(0, jsterm.history.length);   // workaround for bug 592552
 
   finishTest();
 }
 
--- a/browser/devtools/webconsole/test/browser/browser_webconsole_completion.js
+++ b/browser/devtools/webconsole/test/browser/browser_webconsole_completion.js
@@ -84,17 +84,17 @@ function testCompletion() {
   is(jsterm.completeNode.value, "                entsByClassName", "'document.getElem' another tab completion");
 
   // Test pressing shift_tab.
   jsterm.complete(jsterm.COMPLETE_BACKWARD);
   is(input.value, "document.getElem", "'document.getElem' untab completion");
   is(jsterm.completeNode.value, "                entById", "'document.getElem' completion");
 
   jsterm.clearOutput();
-  jsterm.history.splice(0);   // workaround for bug 592552
+  jsterm.history.splice(0, jsterm.history.length);   // workaround for bug 592552
 
   input.value = "docu";
   jsterm.complete(jsterm.COMPLETE_HINT_ONLY);
   is(jsterm.completeNode.value, "    ment", "'docu' completion");
   jsterm.execute();
   is(jsterm.completeNode.value, "", "clear completion on execute()");
 
   // Test multi-line completion works
--- a/browser/devtools/webconsole/test/browser/browser_webconsole_execution_scope.js
+++ b/browser/devtools/webconsole/test/browser/browser_webconsole_execution_scope.js
@@ -63,13 +63,13 @@ function testExecutionScope() {
 
   is(/location;/.test(nodes[0].textContent), true,
      "'location;' written to output");
 
   ok(nodes[0].textContent.indexOf(TEST_URI),
     "command was executed in the window scope");
 
   jsterm.clearOutput();
-  jsterm.history.splice(0);   // workaround for bug 592552
+  jsterm.history.splice(0, jsterm.history.length);   // workaround for bug 592552
 
   finishTest();
 }
 
--- a/browser/devtools/webconsole/test/browser/browser_webconsole_history.js
+++ b/browser/devtools/webconsole/test/browser/browser_webconsole_history.js
@@ -94,13 +94,13 @@ function testHistory() {
 
   is (input.value, "", "check input is still empty");
 
   let idxLast = executeList.length - 1;
   jsterm.historyPeruse(HISTORY_BACK);
   is (input.value, executeList[idxLast], "check history next idx:" + idxLast);
 
   jsterm.clearOutput();
-  jsterm.history.splice(0);   // workaround for bug 592552
+  jsterm.history.splice(0, jsterm.history.length);   // workaround for bug 592552
 
   finishTest();
 }
 
--- a/browser/devtools/webconsole/test/browser/browser_webconsole_js_input_and_output_styling.js
+++ b/browser/devtools/webconsole/test/browser/browser_webconsole_js_input_and_output_styling.js
@@ -70,13 +70,13 @@ function testJSInputAndOutputStyling() {
   let jsOutputNodes = jsterm.outputNode.
                       querySelectorAll(".webconsole-msg-output");
   isnot(jsOutputNodes[0].textContent.indexOf("4"), -1,
         "JS output node contains '4'");
   ok(jsOutputNodes[0].classList.contains("webconsole-msg-output"),
      "JS output node is of the CSS class 'webconsole-msg-output'");
 
   jsterm.clearOutput();
-  jsterm.history.splice(0);   // workaround for bug 592552
+  jsterm.history.splice(0, jsterm.history.length);   // workaround for bug 592552
 
   finishTest();
 }
 
--- a/browser/devtools/webconsole/test/browser/browser_webconsole_null_and_undefined_output.js
+++ b/browser/devtools/webconsole/test/browser/browser_webconsole_null_and_undefined_output.js
@@ -68,13 +68,13 @@ function testNullAndUndefinedOutput() {
   jsterm.clearOutput();
   jsterm.execute("undefined;");
 
   nodes = outputNode.querySelectorAll(".hud-msg-node");
   is(nodes.length, 2, "2 nodes in output");
   ok(nodes[1].textContent.indexOf("undefined") > -1, "'undefined' printed to output");
 
   jsterm.clearOutput();
-  jsterm.history.splice(0);   // workaround for bug 592552
+  jsterm.history.splice(0, jsterm.history.length);   // workaround for bug 592552
 
   finishTest();
 }
 
--- a/browser/devtools/webconsole/test/browser/browser_webconsole_output_order.js
+++ b/browser/devtools/webconsole/test/browser/browser_webconsole_output_order.js
@@ -66,13 +66,13 @@ function testOutputOrder() {
     /console\.log\('foo', 'bar'\);/.test(nodes[0].textContent);
 
   let outputSecond =
     /foo bar/.test(nodes[1].textContent);
 
   ok(executedStringFirst && outputSecond, "executed string comes first");
 
   jsterm.clearOutput();
-  jsterm.history.splice(0);   // workaround for bug 592552
+  jsterm.history.splice(0, jsterm.history.length);   // workaround for bug 592552
 
   finishTest();
 }
 
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -189,16 +189,19 @@ can reach it easily. -->
 <!ENTITY webConsoleCmd.label          "Web Console">
 <!ENTITY webConsoleCmd.accesskey      "W">
 <!ENTITY webConsoleCmd.commandkey     "k">
 
 <!ENTITY inspectMenu.label            "Inspect">
 <!ENTITY inspectMenu.accesskey        "T">
 <!ENTITY inspectMenu.commandkey       "I">
 
+<!ENTITY inspectContextMenu.label     "Inspect Element">
+<!ENTITY inspectContextMenu.accesskey "Q">
+
 <!-- LOCALIZATION NOTE (scratchpad.label): This menu item label appears
   -  in the Tools menu. See bug 653093.
   -  The Scratchpad is intended to provide a simple text editor for creating
   -  and evaluating bits of JavaScript code for the purposes of function
   -  prototyping, experimentation and convenient scripting.
   -
   -  It's quite possible that you won't have a good analogue for the word
   -  "Scratchpad" in your locale. You should feel free to find a close
--- a/browser/locales/en-US/chrome/browser/styleinspector.dtd
+++ b/browser/locales/en-US/chrome/browser/styleinspector.dtd
@@ -1,8 +1,13 @@
+<!-- LOCALIZATION NOTE (userStylesLabel): This is the label for the checkbox
+  -  that specifies whether the styles that are not from the user's stylesheet
+  -  should be displayed or not. -->
+<!ENTITY userStylesLabel    "Only user styles">
+
 <!-- LOCALIZATION NOTE (lookingAtLabel): This is the label for the path of
   -  the highlighted element in the web page. This path is based on the document
   -  tree. -->
 <!ENTITY lookingAtLabel        "Looking at:">
 
 <!-- LOCALIZATION NOTE (helpLinkTitle): For each style property
   -  the user can hover it and get a help link button which allows one to
   -  quickly jump to the documentation from the Mozilla Developer Network site.
--- a/browser/locales/en-US/chrome/browser/styleinspector.properties
+++ b/browser/locales/en-US/chrome/browser/styleinspector.properties
@@ -1,18 +1,18 @@
 # LOCALIZATION NOTE These strings are used inside the Style Inspector.
 
 # LOCALIZATION NOTE (panelTitle): This is the panel title
 panelTitle=Style Inspector
 
-# LOCALIZATION NOTE (property.numberOfSelectors): For each style property the
+# LOCALIZATION NOTE (property.numberOfMatchedSelectors): For each style property the
 # panel shows the number of selectors which match the currently selected
 # element, counted from all stylesheets in the web page inspected.
 # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
-property.numberOfSelectors=1 selector;#1 selectors
+property.numberOfMatchedSelectors=1 matched selector;#1 matched selectors
 
 # LOCALIZATION NOTE (property.numberOfUnmatchedSelectors): For each style
 # property the panel shows the number of selectors which do not match the
 # currently selected element, counted from all stylesheets in the web page
 # inspected.
 # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
 property.numberOfUnmatchedSelectors=1 unmatched selector;#1 unmatched selectors
 
@@ -27,23 +27,16 @@ rule.status.UNMATCHED=Unmatched
 
 # LOCALIZATION NOTE (rule.sourceElement, rule.sourceInline): For each
 # style property the panel shows the rules which hold that specific property.
 # For every rule, the rule source is also displayed: a rule can come from a
 # file, from the same page (inline), or from the element itself (element).
 rule.sourceInline=inline
 rule.sourceElement=element
 
-# LOCALIZATION NOTE (rule.showUnmatchedLink): For each style
-# property the panel shows the number of selectors which do not match the
-# currently selected element, counted from all stylesheets in the web page
-# inspected.
-# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
-rule.showUnmatchedLink=1 unmatched selector…;#1 unmatched selectors…
-
 # LOCALIZATION NOTE (group): Style properties are displayed in categories and
 # these are the category names.
 group.Text_Fonts_and_Color=Text, Fonts & Color
 group.Background=Background
 group.Dimensions=Dimensions
 group.Positioning_and_Page_Flow=Positioning and Page Flow
 group.Borders=Borders
 group.Lists=Lists
--- a/browser/themes/gnomestripe/browser/browser.css
+++ b/browser/themes/gnomestripe/browser/browser.css
@@ -951,21 +951,21 @@ toolbar[iconsize="small"] #feed-button {
 
 #urlbar-container {
   -moz-box-orient: horizontal;
   -moz-box-align: stretch;
 }
 
 #urlbar-icons {
   -moz-box-align: center;
-  -moz-padding-end: 2px;
 }
 
 .urlbar-icon {
   cursor: pointer;
+  padding: 0 3px;
 }
 
 #urlbar-search-splitter {
   -moz-appearance: none;
   width: 8px;
   -moz-margin-start: -4px;
 }
 
@@ -1310,93 +1310,47 @@ richlistitem[type~="action"][actiontype=
   color: GrayText;
   font-size: smaller;
 }
 
 .autocomplete-treebody::-moz-tree-cell(suggesthint) {
   border-top: 1px solid GrayText;
 }
 
-/* Go button */
+/* Combined go/reload/stop button in location bar */
 
 #go-button {
-  padding: 3px 2px 2px 2px;
-  list-style-image: url("chrome://browser/skin/Go-arrow.png");
+  padding-top: 2px;
+  padding-bottom: 2px;
 }
 
-#go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
-  -moz-transform: scaleX(-1);
-}
-
-/* Combined go/reload/stop button in location bar */
-
 #urlbar > toolbarbutton {
   -moz-appearance: none;
-  list-style-image: url("chrome://browser/skin/reload-stop-go.png");
-  margin: -1px;
-  -moz-margin-start: 0;
-  padding: 0 3px;
-  background-origin: border-box;
+  padding: 0;
   border: none;
-  -moz-border-start: 1px solid rgba(0,0,0,.35);
-  box-shadow: 0 1px 0 rgba(0,0,0,.1) inset,
-              -1px -1px 1px rgba(255,255,255,.2) inset;
-}
-
-#urlbar:-moz-locale-dir(ltr) > toolbarbutton {
-  border-top-right-radius: 2px;
-  border-bottom-right-radius: 2px;
+  cursor: pointer;
+  width: 22px;
 }
 
-#urlbar:-moz-locale-dir(rtl) > toolbarbutton {
-  border-top-left-radius: 2px;
-  border-bottom-left-radius: 2px;
+#go-button,
+#urlbar-go-button {
+  list-style-image: url("chrome://browser/skin/Go-arrow.png");
 }
 
-#urlbar > toolbarbutton:not([disabled]):active:hover,
-#urlbar-reload-button:not(:hover) {
-  -moz-border-start-style: none;
-  -moz-padding-start: 4px;
-  box-shadow: none;
-}
-
-#urlbar > toolbarbutton:not([disabled]):active:hover {
-  box-shadow: 0 0 6.5px rgba(0,0,0,.4) inset,
-              0 0 2px rgba(0,0,0,.4) inset;
-}
-
-#urlbar-go-button {
-  -moz-image-region: rect(0px, 56px, 14px, 42px);
-  background-image: -moz-linear-gradient(rgb(143,219,69), rgb(115,177,57));
-}
-
+#go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
 #urlbar-go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
   -moz-transform: scaleX(-1);
 }
 
-#urlbar-go-button:hover {
-  background-image: -moz-linear-gradient(rgb(163,232,92), rgb(137,196,81));
-}
-
 #urlbar-reload-button {
-  -moz-image-region: rect(0px, 14px, 14px, 0px);
-}
-
-#urlbar-reload-button:not([disabled]):hover {
-  -moz-image-region: rect(0px, 28px, 14px, 14px);
-  background-image: -moz-linear-gradient(rgb(137,183,233), rgb(79,130,195));
+  list-style-image: url("moz-icon://stock/gtk-refresh?size=menu");
 }
 
 #urlbar-stop-button {
-  -moz-image-region: rect(0px, 42px, 14px, 28px);
-  background-image: -moz-linear-gradient(rgb(226,99,99), rgb(199,68,68));
-}
-
-#urlbar-stop-button:hover {
-  background-image: -moz-linear-gradient(rgb(237,120,120), rgb(216,92,92));
+  list-style-image: url("moz-icon://stock/gtk-stop?size=menu");
 }
 
 /* Popup blocker button */
 #page-report-button {
   list-style-image: url("chrome://browser/skin/Info.png");
 }
 
 /* Star button */
--- a/browser/themes/gnomestripe/browser/devtools/csshtmltree.css
+++ b/browser/themes/gnomestripe/browser/devtools/csshtmltree.css
@@ -37,17 +37,18 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 body {
   font-family: sans-serif;
   font-size: 11px;
   background: #EEE;
 }
-.path {
+.path,
+.filters {
   font-size: 11px;
   word-spacing: -1px;
 }
 .path ol {
   list-style: none outside none;
   margin: 0;
   padding: 0;
 }
@@ -66,117 +67,95 @@ body {
 .path li:last-child {
   background: -moz-linear-gradient(top, #FFC, #DD8);
 }
 .path li:last-child:after {
   color: red;
   content: "";
 }
 
-#header,
-#footer {
-  padding: 5px;
-}
-
-#header label {
-  font-weight: bold;
-}
-
 .property-header {
   padding: 2px 5px;
   background: -moz-linear-gradient(top, #F8F8F8, #E8E8E8);
   color: #666;
 }
 
 .property-name,
-.property-value,
-.rule-count,
+.rule-matched,
 .rule-unmatched {
   cursor: pointer;
 }
 
 /* Take away these two :visited rules to get a core dumper     */
 /* See https://bugzilla.mozilla.org/show_bug.cgi?id=575675#c30 */
-.link,
-.unmatchedlink {
+.link {
   color: #55A;
 }
-.link:visited,
-.unmatchedlink:visited {
+.link:visited {
   color: #55A;
 }
-a.link,
-a.unmatchedlink {
+a.link {
   text-decoration: none;
   cursor: pointer;
 }
-a.link:visited,
-a.unmatchedlink:visited {
+a.link:visited {
   text-decoration: none;
 }
 
-.rule-count,
+.rule-matched,
 .rule-unmatched {
-  padding: 5px 0 0 15px;
+  padding: 2px 0;
+  white-space: nowrap;
 }
-.unmatched {
-  display: inline-block;
+
+.rulelink {
+  color: #55A;
 }
+
 .expander {
   width: 8px;
   height: 8px;
-  display: inline-block;
+  float: left;
+  -moz-margin-start: 15px;
   -moz-margin-end: 5px;
-  margin-bottom: 1px;
+  margin-top: 3px;
   background: url("chrome://browser/skin/devtools/arrows.png");
-}
-
-.unmatched-rule {
-  -moz-margin-start: 25px;
   background-position: 24px 0;
 }
 
-.property-view .rule-count .expander,
-.property-view .rule-unmatched .expander {
-  background-position: 24px 0;
+.searchfield {
+  background: url("chrome://browser/skin/devtools/search.png") no-repeat #FFF;
+  border-radius: 5px;
+  -moz-padding-start: 20px;
+  width: 135px;
+  float: right;
 }
-.property-view[dir="rtl"] .rule-count .expander,
-.property-view[dir="rtl"] .rule-unmatched .expander {
+
+.expander[dir="rtl"] {
   background-position: 16px 0;
 }
-.property-view[open] .rule-count .expander,
-.property-view[open] .rule-unmatched .expander {
+.expander[open] {
   background-position: 8px 0;
 }
 
 .property-name {
   display: inline-block;
   font-size: 12px;
   font-weight: bold;
   color: #000;
 }
 .property-value {
   display: inline-block;
   font-size: 10px;
 }
 
-.property-view > .rules {
+.property-view-hidden {
   display: none;
 }
-.property-view[open] > .rules {
-  display: table;
-}
-.rules {
-  -moz-margin-start: 32px;
-  max-height: 350px;
-  overflow-y: auto;
-}
-.rule-status {
-  white-space: nowrap;
-}
+
 .rule-link {
   text-align: end;
   -moz-padding-start: 10px;
 }
 
 /* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
 .rule-text {
   direction: ltr;
@@ -194,8 +173,18 @@ a.unmatchedlink:visited {
   text-decoration: line-through;
 }
 .parentmatch {
   color: #666;
 }
 .unmatched {
   color: brown;
 }
+
+.userStyles {
+  position: relative;
+  top: 3px;
+}
+
+.userStyles,
+.userStylesLabel {
+  cursor: pointer;
+}
\ No newline at end of file
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..df7212d78c8f86e7abe5073d85bf419786993550
GIT binary patch
literal 1445
zc%17D@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE;=WQl7;NpOBzNqJ&XDuZK6ep0G}
zXKrG8YEWuoN@d~6R2v2cW~I!Kh>{3jAFJg2T)jk)8oi3#0tOJUv9BmdOwLX%QAkQn
z&&;z`dcS+Wl0s&Rtx~wDuYqrYb81GWM^#a3aFt(3a#eP+Wr~u$oq|n;70`g()RIJn
zirk#MVyg;UC9t_xKsHENUr7P1q$Jx`3F4>--v9;Y{GwC^Q#}LSWCJq;1v5iELt_(j
zb8{U9BLhPNeFGzXLnB>7b1P#bD+2=sC{P00R+N%v73AUuwF}6zRmvzSDX`MlFE20G
zD>v55FG|-pw6wGYnPFt43sj+7T$xvrSfQI&tPC^3CAB!YD6^m>Ge1uO#7|7hFD<cE
zQi6FQw*YQzUNJP7fB~jokyxN_sAr&$q|nzFztY@Xxa#7Ppwu+{s*6J^3sUuiQj7CT
zi;{s6m!=HTTwvu~l$uzQUlfv`p92fUfQ<Z-{NjxK0tM$_Qw86|<jgz}AFSTj*UB@m
zxFj(zIn~p}RtYGgmzkMj<?8HW<YHiH=45K*WN7H(W@%|*=4@<YVCL%N=458z2-EA5
zpIn-onpXnTn}X15j#DovDL{0m7G;*DrnnX5=PH1`Y?X=IEhf0#0@0g-+byOz_38s1
zqmLHRFd<;-0Wsmp7RZ4o{M0;PYA*sN>rTV&CkzZslAbP(Ar-gIOxf=(ohWhqzW0|&
z%5$EucNmJziJ9UcY}`?-!m3zuX2F9?x{8aG4(>moX>nv>w|9Gzh2oBmj%RINv%&-y
zpVk#z=i6j)gwJ;IvDe>Qzh`+QC3QFR*HpyK+x@)y{pUUBtLLnH{Y3SwOWchrE88a)
zc|v(2D?~zyzr{BRL^aK3Wm<7rz(Bc<b3enw!|LW2?>MWhJ-C;7dz-+8nFfjSk&gGC
zud{8r!LAmz`Sx4$iy0w$V%@KA=9DSR@Xg=wy?(aOGSNN1m%SBx$;Z1U?6rA|pRU;H
zm5VfrJ9-)9Iu6Kp9}TMTYdz26=wbRy%0`bvl9@}xMQLKc&kD=LBX7&zKc2gO#e)TN
zAKaf*Yj<DZ_2hG(_nfJ^k<)ekwQc+LRaaN7eyrKO=mz(9ht^L&_k6gbDaOUB{dV!;
zhYEMAEIRI8{8!U>zx93gOMb=23DO>o4iAElPfA>xVBo>}dTUhg1C?NllMaVjd}g10
zR;g3pwA)2#<JUQsU#e~9T@6~f<f5JFnTN6~nz9S{*%GXu7FBM(9cwo!wNhDxD>m`0
zaijbLrazl*=Im|w7QQ+}%lO9E-|Ng<Ie!-KyyK!a`DJ+M)uvCcXEeR8uvw?{>_Eic
zt0ui_d`-z2I@@L6sJWQks5@rRy<5dI>Og|G$MV`ge)S5v&42rMTzdIs(dCzS4lg);
zGUd{bh})CqXP0bPeuMRfnI6;kSO0I+vq&&pJYHef^w)U`sNnQ;^>bP0l+XkKR`nx-
--- a/browser/themes/gnomestripe/browser/inspector.css
+++ b/browser/themes/gnomestripe/browser/inspector.css
@@ -197,26 +197,30 @@ code {
 }
 
 .nodeText {
   color: #333333;
 }
 
 .docType {
   position: absolute;
+  /* position DOCTYPE element above/outside the "nodeBox" that contains it */
+  /* Note: to be fixed in Bug #688439 */
   top: -16px;
   font-family: Menlo, Andale Mono, monospace;
   padding-left: 8px;
   color: #999;
   white-space: nowrap;
   font-style: italic;
 }
 
 .htmlNodeBox {
-  top: 16px;
+  /* make room for DOCTYPE element to be rendered above/outside "nodeBox" */
+  /* Note: to be fixed in Bug #688439 */
+  margin-top: 16px;
 }
 
 .nodeWhiteSpace {
   border: 1px solid LightGray;
   white-space: pre; /* otherwise the border will be collapsed around zero pixels */
   margin-left: 1px;
   color: gray;
 }
--- a/browser/themes/gnomestripe/browser/jar.mn
+++ b/browser/themes/gnomestripe/browser/jar.mn
@@ -22,17 +22,16 @@ browser.jar:
   skin/classic/browser/KUI-close.png
   skin/classic/browser/monitor.png
   skin/classic/browser/monitor_16-10.png
 * skin/classic/browser/pageInfo.css
   skin/classic/browser/pageInfo.png
   skin/classic/browser/page-livemarks.png
   skin/classic/browser/Privacy-16.png
   skin/classic/browser/Privacy-48.png
-  skin/classic/browser/reload-stop-go.png
   skin/classic/browser/searchbar.css                  (searchbar.css)
   skin/classic/browser/section_collapsed.png
   skin/classic/browser/section_collapsed-rtl.png
   skin/classic/browser/section_expanded.png
   skin/classic/browser/Secure.png
   skin/classic/browser/Security-broken.png
   skin/classic/browser/setDesktopBackground.css
   skin/classic/browser/Toolbar.png
@@ -80,16 +79,17 @@ browser.jar:
   skin/classic/browser/tabbrowser/tab-overflow-border.png (tabbrowser/tab-overflow-border.png)
   skin/classic/browser/tabbrowser/tabDragIndicator.png (tabbrowser/tabDragIndicator.png)
   skin/classic/browser/tabview/edit-light.png         (tabview/edit-light.png)
   skin/classic/browser/tabview/search.png             (tabview/search.png)  
   skin/classic/browser/tabview/stack-expander.png     (tabview/stack-expander.png)
   skin/classic/browser/tabview/tabview.png            (tabview/tabview.png)
   skin/classic/browser/tabview/tabview.css            (tabview/tabview.css)
   skin/classic/browser/devtools/arrows.png            (devtools/arrows.png)
+  skin/classic/browser/devtools/search.png            (devtools/search.png)
   skin/classic/browser/devtools/csshtmltree.css       (devtools/csshtmltree.css)
 #ifdef MOZ_SERVICES_SYNC
   skin/classic/browser/sync-16-throbber.png
   skin/classic/browser/sync-16.png
   skin/classic/browser/sync-24-throbber.png
   skin/classic/browser/sync-32.png
   skin/classic/browser/sync-bg.png
   skin/classic/browser/sync-desktopIcon.png
deleted file mode 100644
index 922a4c4c62e8ecd1bd380a62673dbc0b429b1756..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 9fc4e1b26fd0bef86053ba1f060f75cb425fb328..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/themes/pinstripe/browser/browser.css
+++ b/browser/themes/pinstripe/browser/browser.css
@@ -831,23 +831,20 @@ toolbar[mode="icons"] #zoom-in-button {
 
 #urlbar[focused="true"],
 .searchbar-textbox[focused="true"] {
   border-color: -moz-mac-focusring;
   box-shadow: @focusRingShadow@;
 }
 
 #urlbar {
+  -moz-padding-end: 4px;
   border-radius: @toolbarbuttonCornerRadius@;
 }
 
-#urlbar-container:not([combined]) > #urlbar {
-  -moz-padding-end: 3px;
-}
-
 #identity-box {
   background-image: -moz-linear-gradient(hsl(0,0%,98%), hsl(0,0%,92%));
   box-shadow: 0 1px 0 hsla(0,0%,0%,.05) inset;
   -moz-border-end: 1px solid hsla(0,0%,0%,.1);
   -moz-margin-end: 3px;
   padding: 1px 4px;
 }
 
@@ -905,20 +902,41 @@ toolbar[mode="icons"] #zoom-in-button {
   -moz-margin-start: 6px;
 }
 
 .urlbar-input-box {
   -moz-margin-start: 0;
   padding: 3px 0 2px;
 }
 
+.urlbar-history-dropmarker {
+  padding: 0 3px;
+  list-style-image: url("chrome://browser/skin/urlbar-history-dropmarker.png");
+  -moz-image-region: rect(0px, 11px, 14px, 0px);
+}
+
+.urlbar-history-dropmarker[open="true"],
+.urlbar-history-dropmarker:hover:active {
+  -moz-image-region: rect(0px, 22px, 14px, 11px);
+  background-image: -moz-radial-gradient(center, circle closest-side, hsla(205,100%,70%,.3), hsla(205,100%,70%,0));
+}
+
 #urlbar-icons {
   -moz-box-align: center;
 }
 
+.urlbar-icon {
+  padding: 2px 3px;
+}
+
+.urlbar-icon[open="true"],
+.urlbar-icon:hover:active {
+  background-image: -moz-radial-gradient(center, circle closest-side, hsla(205,100%,70%,.3), hsla(205,100%,70%,0));
+}
+
 #urlbar-search-splitter {
   min-width: 8px;
   width: 8px;
   background-image: none;
   margin: 0 -4px;
   position: relative;
   height: 22px;
 }
@@ -970,33 +988,32 @@ toolbar[mode="icons"] #zoom-in-button {
 /* ----- AUTOCOMPLETE ----- */
 
 #treecolAutoCompleteImage {
   max-width: 36px;
 }
 
 .ac-result-type-bookmark,
 .autocomplete-treebody::-moz-tree-image(bookmark, treecolAutoCompleteImage) {
-  list-style-image: url("chrome://browser/skin/places/pageStarred.png");
-  width: 16px;
-  height: 16px;
+  list-style-image: url("chrome://browser/skin/places/star-icons.png");
+  -moz-image-region: rect(0, 32px, 16px, 16px);
 }
 
 .ac-result-type-keyword,
 .autocomplete-treebody::-moz-tree-image(keyword, treecolAutoCompleteImage) {
   list-style-image: url(chrome://global/skin/icons/search-textbox.png);
   margin: 2px;
   width: 12px;
   height: 12px;
 }
 
 richlistitem[selected="true"][current="true"] > hbox > .ac-result-type-bookmark,
 .autocomplete-treebody::-moz-tree-image(selected, current, bookmark, treecolAutoCompleteImage) {
   list-style-image: url("chrome://browser/skin/places/star-icons.png");
-  -moz-image-region: rect(32px, 16px, 48px, 0px);
+  -moz-image-region: rect(0, 64px, 16px, 48px);
 }
 
 .ac-result-type-tag,
 .autocomplete-treebody::-moz-tree-image(tag, treecolAutoCompleteImage) {
   list-style-image: url("chrome://browser/skin/places/tag.png");
   width: 16px;
   height: 16px;
 }
@@ -1031,134 +1048,95 @@ richlistitem[type~="action"][actiontype=
   color: GrayText;
   font-size: smaller;
 }
 
 .autocomplete-treebody::-moz-tree-cell(suggesthint) {
   border-top: 1px solid GrayText;
 }
 
-/* ----- GO BUTTON ----- */
-
-#go-button {
-  list-style-image: url("chrome://browser/skin/Go-arrow.png");
-  -moz-image-region: rect(0px, 16px, 16px, 0px);
-}
-
-#go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
-  -moz-transform: scaleX(-1);
-}
-
-#go-button:hover {
-  -moz-image-region: rect(0px, 32px, 16px, 16px);
-}
-
-#go-button:hover:active {
-  -moz-image-region: rect(0px, 48px, 16px, 32px);
-}
 
 /* ----- COMBINED GO/RELOAD/STOP BUTTON IN LOCATION BAR ----- */
 
+#go-button,
 #urlbar > toolbarbutton {
-  list-style-image: url("chrome://browser/skin/reload-stop-go.png");
   margin: 0;
-  -moz-margin-start: 2px;
-  padding: 0 3px;
+  -moz-padding-start: 2px; 
+  -moz-padding-end: 1px; 
   background-origin: border-box;
-  border: none;
-  -moz-border-start: 1px solid rgba(0,0,0,.25);
-  box-shadow: 0 1px 0 rgba(0,0,0,.1) inset,
-              -1px -1px 1px rgba(255,255,255,.15) inset;
-}
-
-#urlbar:-moz-locale-dir(ltr) > toolbarbutton {
-  border-top-right-radius: 2px;
-  border-bottom-right-radius: 2px;
-}
-
-#urlbar:-moz-locale-dir(rtl) > toolbarbutton {
-  border-top-left-radius: 2px;
-  border-bottom-left-radius: 2px;
-}
-
-#urlbar > toolbarbutton:not([disabled]):active:hover,
-#urlbar-reload-button:not(:hover) {
-  -moz-border-start-style: none;
-  -moz-padding-start: 4px;
-  box-shadow: none;
-}
-
-#urlbar > toolbarbutton:not([disabled]):active:hover {
-  box-shadow: @toolbarbuttonPressedInnerShadow@;
-}
-
+  list-style-image: url("chrome://browser/skin/reload-stop-go.png");
+}
+
+#urlbar > toolbarbutton:not([disabled]):hover:active {
+  background-image: -moz-radial-gradient(center, circle closest-side, hsla(205,100%,70%,.3), hsla(205,100%,70%,0));
+}
+
+#go-button {
+  padding: 0 3px;
+}
+
+#go-button,
 #urlbar-go-button {
-  -moz-image-region: rect(0px, 56px, 14px, 42px);
-  background-image: -moz-linear-gradient(rgb(184,221,142), rgb(154,201,111) 49%, rgb(130,187,92) 51%, rgb(114,171,79));
-}
-
+  -moz-image-region: rect(0, 42px, 14px, 28px);
+}
+
+#go-button:hover:active,
+#urlbar-go-button:hover:active {
+  -moz-image-region: rect(14px, 42px, 28px, 28px);
+}
+
+#go-button:-moz-locale-dir(rtl),
 #urlbar-go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
   -moz-transform: scaleX(-1);
 }
 
 #urlbar-reload-button {
-  -moz-image-region: rect(0px, 14px, 14px, 0px);
-}
-
-#urlbar-reload-button:not([disabled]):hover {
-  -moz-image-region: rect(0px, 28px, 14px, 14px);
-  background-image: -moz-linear-gradient(rgb(162,207,241), rgb(111,178,225) 49%, rgb(91,159,217) 51%, rgb(62,138,200));
+  -moz-image-region: rect(0, 14px, 14px, 0);
+}
+
+#urlbar-reload-button:not([disabled]):hover:active {
+  -moz-image-region: rect(14px, 14px, 28px, 0);
+}
+
+#urlbar-reload-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
+  -moz-transform: scaleX(-1);
 }
 
 #urlbar-stop-button {
-  -moz-image-region: rect(0px, 42px, 14px, 28px);
-  background-image: -moz-linear-gradient(rgb(231,162,140), rgb(209,119,100) 49%, rgb(193,92,78) 51%, rgb(173,72,58));
+  -moz-image-region: rect(0, 28px, 14px, 14px);
+}
+
+#urlbar-stop-button:hover:active {
+  -moz-image-region: rect(14px, 28px, 28px, 14px);
 }
 
 /* POPUP BLOCKER BUTTON */
 #page-report-button {
   list-style-image: url("chrome://browser/skin/urlbar-popup-blocked.png");
   -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
-#page-report-button:hover {
-  -moz-image-region: rect(0, 32px, 16px, 16px);
-}
-
 #page-report-button:hover:active,
 #page-report-button[open="true"] {
-  -moz-image-region: rect(0, 48px, 16px, 32px);
+  -moz-image-region: rect(0, 32px, 16px, 16px);
 }
 
 /* STAR BUTTON */
 #star-button {
-  padding: 1px;
-  -moz-padding-start: 4px;
   list-style-image: url("chrome://browser/skin/places/star-icons.png");
   -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
-#star-button:hover {
+#star-button:hover:active,
+#star-button[starred="true"] {
   -moz-image-region: rect(0, 32px, 16px, 16px);
 }
 
-#star-button:hover:active {
-  -moz-image-region: rect(0, 48px, 16px, 32px);
-}
-
-#star-button[starred="true"] {
-  -moz-image-region: rect(16px, 16px, 32px, 0);
-}
-
-#star-button:hover[starred="true"] {
-  -moz-image-region: rect(16px, 32px, 32px, 16px);
-}
-
 #star-button:hover:active[starred="true"] {
-  -moz-image-region: rect(16px, 48px, 32px, 32px);
+  -moz-image-region: rect(0, 48px, 16px, 32px);
 }
 
 /* BOOKMARKING PANEL */
 #editBookmarkPanelStarIcon {
   list-style-image: url("chrome://browser/skin/places/starred48.png");
   width: 48px;
   height: 48px;
 }
--- a/browser/themes/pinstripe/browser/devtools/csshtmltree.css
+++ b/browser/themes/pinstripe/browser/devtools/csshtmltree.css
@@ -37,17 +37,18 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 body {
   font-family: sans-serif;
   font-size: 11px;
   background: #EEE;
 }
-.path {
+.path,
+.filters {
   font-size: 11px;
   word-spacing: -1px;
 }
 .path ol {
   list-style: none outside none;
   margin: 0;
   padding: 0;
 }
@@ -66,117 +67,95 @@ body {
 .path li:last-child {
   background: -moz-linear-gradient(top, #FFC, #DD8);
 }
 .path li:last-child:after {
   color: red;
   content: "";
 }
 
-#header,
-#footer {
-  padding: 5px;
-}
-
-#header label {
-  font-weight: bold;
-}
-
 .property-header {
   padding: 2px 5px;
   background: -moz-linear-gradient(top, #F8F8F8, #E8E8E8);
   color: #666;
 }
 
 .property-name,
-.property-value,
-.rule-count,
+.rule-matched,
 .rule-unmatched {
   cursor: pointer;
 }
 
 /* Take away these two :visited rules to get a core dumper     */
 /* See https://bugzilla.mozilla.org/show_bug.cgi?id=575675#c30 */
-.link,
-.unmatchedlink {
+.link {
   color: #55A;
 }
-.link:visited,
-.unmatchedlink:visited {
+.link:visited {
   color: #55A;
 }
-a.link,
-a.unmatchedlink {
+a.link {
   text-decoration: none;
   cursor: pointer;
 }
-a.link:visited,
-a.unmatchedlink:visited {
+a.link:visited {
   text-decoration: none;
 }
 
-.rule-count,
+.rule-matched,
 .rule-unmatched {
-  padding: 5px 0 0 15px;
+  padding: 2px 0;
+  white-space: nowrap;
 }
-.unmatched {
-  display: inline-block;
+
+.rulelink {
+  color: #55A;
 }
+
 .expander {
   width: 8px;
   height: 8px;
-  display: inline-block;
+  float: left;
+  -moz-margin-start: 15px;
   -moz-margin-end: 5px;
-  margin-bottom: 1px;
+  margin-top: 3px;
   background: url("chrome://browser/skin/devtools/arrows.png");
-}
-
-.unmatched-rule {
-  -moz-margin-start: 25px;
   background-position: 24px 0;
 }
 
-.property-view .rule-count .expander,
-.property-view .rule-unmatched .expander {
-  background-position: 24px 0;
+.searchfield {
+  background: url("chrome://browser/skin/devtools/search.png") no-repeat #FFF;
+  border-radius: 5px;
+  -moz-padding-start: 20px;
+  width: 135px;
+  float: right;
 }
-.property-view[dir="rtl"] .rule-count .expander,
-.property-view[dir="rtl"] .rule-unmatched .expander {
+
+.expander[dir="rtl"] {
   background-position: 16px 0;
 }
-.property-view[open] .rule-count .expander,
-.property-view[open] .rule-unmatched .expander {
+.expander[open] {
   background-position: 8px 0;
 }
 
 .property-name {
   display: inline-block;
   font-size: 12px;
   font-weight: bold;
   color: #000;
 }
 .property-value {
   display: inline-block;
   font-size: 10px;
 }
 
-.property-view > .rules {
+.property-view-hidden {
   display: none;
 }
-.property-view[open] > .rules {
-  display: table;
-}
-.rules {
-  -moz-margin-start: 32px;
-  max-height: 350px;
-  overflow-y: auto;
-}
-.rule-status {
-  white-space: nowrap;
-}
+
 .rule-link {
   text-align: end;
   -moz-padding-start: 10px;
 }
 
 /* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
 .rule-text {
   direction: ltr;
@@ -194,8 +173,18 @@ a.unmatchedlink:visited {
   text-decoration: line-through;
 }
 .parentmatch {
   color: #666;
 }
 .unmatched {
   color: brown;
 }
+
+.userStyles {
+  position: relative;
+  top: 3px;
+}
+
+.userStyles,
+.userStylesLabel {
+  cursor: pointer;
+}
\ No newline at end of file
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..df7212d78c8f86e7abe5073d85bf419786993550
GIT binary patch
literal 1445
zc%17D@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE;=WQl7;NpOBzNqJ&XDuZK6ep0G}
zXKrG8YEWuoN@d~6R2v2cW~I!Kh>{3jAFJg2T)jk)8oi3#0tOJUv9BmdOwLX%QAkQn
z&&;z`dcS+Wl0s&Rtx~wDuYqrYb81GWM^#a3aFt(3a#eP+Wr~u$oq|n;70`g()RIJn
zirk#MVyg;UC9t_xKsHENUr7P1q$Jx`3F4>--v9;Y{GwC^Q#}LSWCJq;1v5iELt_(j
zb8{U9BLhPNeFGzXLnB>7b1P#bD+2=sC{P00R+N%v73AUuwF}6zRmvzSDX`MlFE20G
zD>v55FG|-pw6wGYnPFt43sj+7T$xvrSfQI&tPC^3CAB!YD6^m>Ge1uO#7|7hFD<cE
zQi6FQw*YQzUNJP7fB~jokyxN_sAr&$q|nzFztY@Xxa#7Ppwu+{s*6J^3sUuiQj7CT
zi;{s6m!=HTTwvu~l$uzQUlfv`p92fUfQ<Z-{NjxK0tM$_Qw86|<jgz}AFSTj*UB@m
zxFj(zIn~p}RtYGgmzkMj<?8HW<YHiH=45K*WN7H(W@%|*=4@<YVCL%N=458z2-EA5
zpIn-onpXnTn}X15j#DovDL{0m7G;*DrnnX5=PH1`Y?X=IEhf0#0@0g-+byOz_38s1
zqmLHRFd<;-0Wsmp7RZ4o{M0;PYA*sN>rTV&CkzZslAbP(Ar-gIOxf=(ohWhqzW0|&
z%5$EucNmJziJ9UcY}`?-!m3zuX2F9?x{8aG4(>moX>nv>w|9Gzh2oBmj%RINv%&-y
zpVk#z=i6j)gwJ;IvDe>Qzh`+QC3QFR*HpyK+x@)y{pUUBtLLnH{Y3SwOWchrE88a)
zc|v(2D?~zyzr{BRL^aK3Wm<7rz(Bc<b3enw!|LW2?>MWhJ-C;7dz-+8nFfjSk&gGC
zud{8r!LAmz`Sx4$iy0w$V%@KA=9DSR@Xg=wy?(aOGSNN1m%SBx$;Z1U?6rA|pRU;H
zm5VfrJ9-)9Iu6Kp9}TMTYdz26=wbRy%0`bvl9@}xMQLKc&kD=LBX7&zKc2gO#e)TN
zAKaf*Yj<DZ_2hG(_nfJ^k<)ekwQc+LRaaN7eyrKO=mz(9ht^L&_k6gbDaOUB{dV!;
zhYEMAEIRI8{8!U>zx93gOMb=23DO>o4iAElPfA>xVBo>}dTUhg1C?NllMaVjd}g10
zR;g3pwA)2#<JUQsU#e~9T@6~f<f5JFnTN6~nz9S{*%GXu7FBM(9cwo!wNhDxD>m`0
zaijbLrazl*=Im|w7QQ+}%lO9E-|Ng<Ie!-KyyK!a`DJ+M)uvCcXEeR8uvw?{>_Eic
zt0ui_d`-z2I@@L6sJWQks5@rRy<5dI>Og|G$MV`ge)S5v&42rMTzdIs(dCzS4lg);
zGUd{bh})CqXP0bPeuMRfnI6;kSO0I+vq&&pJYHef^w)U`sNnQ;^>bP0l+XkKR`nx-
--- a/browser/themes/pinstripe/browser/inspector.css
+++ b/browser/themes/pinstripe/browser/inspector.css
@@ -197,26 +197,30 @@ code {
 }
 
 .nodeText {
   color: #333333;
 }
 
 .docType {
   position: absolute;
+  /* position DOCTYPE element above/outside the "nodeBox" that contains it */
+  /* Note: to be fixed in Bug #688439 */
   top: -16px;
   font-family: Menlo, Andale Mono, monospace;
   padding-left: 8px;
   color: #999;
   white-space: nowrap;
   font-style: italic;
 }
 
 .htmlNodeBox {
-  top: 16px;
+  /* make room for DOCTYPE element to be rendered above/outside "nodeBox" */
+  /* Note: to be fixed in Bug #688439 */
+  margin-top: 16px;
 }
 
 .nodeWhiteSpace {
   border: 1px solid LightGray;
   white-space: pre; /* otherwise the border will be collapsed around zero pixels */
   margin-left: 1px;
   color: gray;
 }
--- a/browser/themes/pinstripe/browser/jar.mn
+++ b/browser/themes/pinstripe/browser/jar.mn
@@ -9,17 +9,16 @@ browser.jar:
   skin/classic/browser/aboutSyncTabs.css
 #endif
   skin/classic/browser/actionicon-tab.png
 * skin/classic/browser/browser.css                          (browser.css)
 * skin/classic/browser/engineManager.css                    (engineManager.css)
   skin/classic/browser/fullscreen-video.css
   skin/classic/browser/Geolocation-16.png
   skin/classic/browser/Geolocation-64.png
-  skin/classic/browser/Go-arrow.png
   skin/classic/browser/home.png
   skin/classic/browser/hud-style-check-box-checked.png
   skin/classic/browser/hud-style-check-box-empty.png
   skin/classic/browser/hud-style-dropmarker-double-arrows.png
   skin/classic/browser/hud-style-expander-closed.png
   skin/classic/browser/hud-style-expander-open.png
   skin/classic/browser/hud-style-new-folder-plus-sign.png
   skin/classic/browser/hud-style-twisties.png
@@ -40,16 +39,17 @@ browser.jar:
   skin/classic/browser/Search.png
   skin/classic/browser/section_collapsed.png
   skin/classic/browser/section_collapsed-rtl.png
   skin/classic/browser/section_expanded.png
   skin/classic/browser/Secure-Glyph-White.png
   skin/classic/browser/keyhole-circle.png
   skin/classic/browser/Toolbar.png
   skin/classic/browser/toolbarbutton-dropmarker.png
+  skin/classic/browser/urlbar-history-dropmarker.png
   skin/classic/browser/urlbar-arrow.png
   skin/classic/browser/urlbar-popup-blocked.png
   skin/classic/browser/feeds/subscribe.css                  (feeds/subscribe.css)
   skin/classic/browser/feeds/subscribe-ui.css               (feeds/subscribe-ui.css)
   skin/classic/browser/feeds/feedIcon.png                   (feeds/feedIcon.png)
   skin/classic/browser/feeds/feedIcon16.png                 (feeds/feedIcon16.png)
   skin/classic/browser/feeds/videoFeedIcon.png              (feeds/videoFeedIcon.png)
   skin/classic/browser/feeds/videoFeedIcon16.png            (feeds/videoFeedIcon16.png)
@@ -71,17 +71,16 @@ browser.jar:
   skin/classic/browser/places/toolbarDropMarker.png         (places/toolbarDropMarker.png)
   skin/classic/browser/places/folderDropArrow.png           (places/folderDropArrow.png)
   skin/classic/browser/places/editBookmarkOverlay.css       (places/editBookmarkOverlay.css)
   skin/classic/browser/places/minus.png                     (places/minus.png)
   skin/classic/browser/places/minus-active.png              (places/minus-active.png)
   skin/classic/browser/places/plus.png                      (places/plus.png)
   skin/classic/browser/places/plus-active.png               (places/plus-active.png)
   skin/classic/browser/places/starPage.png                  (places/starPage.png)
-  skin/classic/browser/places/pageStarred.png               (places/pageStarred.png)
   skin/classic/browser/places/searching_16.png              (places/searching_16.png)
   skin/classic/browser/places/starred48.png                 (places/starred48.png)
   skin/classic/browser/places/unstarred48.png               (places/unstarred48.png)
   skin/classic/browser/places/unfiledBookmarks.png          (places/unfiledBookmarks.png)
   skin/classic/browser/places/twisty-open.gif               (places/twisty-open.gif)
   skin/classic/browser/places/twisty-closed.gif             (places/twisty-closed.gif)
   skin/classic/browser/places/tag.png                       (places/tag.png)
   skin/classic/browser/places/downloads.png                 (places/downloads.png)
@@ -119,16 +118,17 @@ browser.jar:
   skin/classic/browser/tabbrowser/tabDragIndicator.png                   (tabbrowser/tabDragIndicator.png)
   skin/classic/browser/tabview/close.png                    (tabview/close.png)
   skin/classic/browser/tabview/edit-light.png               (tabview/edit-light.png)
   skin/classic/browser/tabview/search.png                   (tabview/search.png)
   skin/classic/browser/tabview/stack-expander.png           (tabview/stack-expander.png)
   skin/classic/browser/tabview/tabview.png                  (tabview/tabview.png)
   skin/classic/browser/tabview/tabview.css                  (tabview/tabview.css)
   skin/classic/browser/devtools/arrows.png                  (devtools/arrows.png)
+  skin/classic/browser/devtools/search.png                  (devtools/search.png)
   skin/classic/browser/devtools/csshtmltree.css             (devtools/csshtmltree.css)
 #ifdef MOZ_SERVICES_SYNC
   skin/classic/browser/sync-throbber.png
   skin/classic/browser/sync-16.png
   skin/classic/browser/sync-32.png
   skin/classic/browser/sync-bg.png
   skin/classic/browser/sync-desktopIcon.png
   skin/classic/browser/sync-mobileIcon.png
deleted file mode 100644
index 9f025f744eff57c84c1fc948670962941cec09f8..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
index 30d73dd79991103380627a80e3557b8bf56dc7f0..e5610bace4e1ce8b011df55b348bea29a4ecf61f
GIT binary patch
literal 1906
zc$@)p2aWiNP)<h;3K|Lk000e1NJLTq002M$000mO1^@s6rssJn000L$Nkl<Zc-ozp
zeNdFw6~?z?AiA&!h>%@HVj3+mp`gT7Obrp@+C<c3hN`2f8o#ojNoZt}n&Oy5{3swq
zKxJ7lM1g?CAOwsERzwl35f%Zvl;uOj;sVaX3Q_py>ACORrAzwmHj$a%aORxn4D+1(
z@m?hH@$sS@K73e`l$4Z5WKe8V=eDuL9(hEDJq-YxJf&3U5g9CgLUM_8dm2$w2?+_3
zBS(%XFJ8Qe^73*}96&ko0c<F;h4T66%Xscjmq2lVEgb++9F&ntr<KWYTJa?ulo0_>
zV17RFBgg+24InWwQIeaRTi)5(iH?pA<mBWO+u8-L?|duH`hv0$Z9A4|450X|4V_H`
z(vX-kw`~{TwzUk>C7+&sf&mm0CeCSFI?>fnPEJ<V)YQOiHe+yb5ZA6<v$+dg*PRwa
z`Rk~1tSTSDTg1!{%0RgQ5uNzzFNjpiR-b@JbOStg=^*<<CMXy13s--D=;fGg?Sh}0
zpFn3mu(-JR?_FJ8c>MUW0E-I?3oo!5(~KLy+FWZU5P`01vMWN;{)OO@VSy#b^l)99
zbDq_>#-bm8=I3vpKxaPC`OO0rQ+8Z}*I!x$+#@eS`bO+|R%04F##wD1@f~3#dKf$|
z;<a)8?4pa%YPCiA`T4CSB_*h?u7<&25LSO=WQ4(DmJ@1BLt1@$dU_G{ZkfFLWCT$}
zw7RZ2g_%1_u=KbdtIj{dto%XDCf=f$azc%1NUP^PTb^2=j&NN3QPCvTXRXq(c*s_3
z;jTUp&)rRUW^Wrqh~3oR3pMHTI80pnnV$7f?-l^tiN6tz#1Jva4R;fFIo&)r$Td3N
zvq_Sfnb}icUyttYZuIr_VPIeY!^6YE%JTuRnB|08Z*Q-#BkJnvK!fX;9G-FS^`lK#
zU(^qE<p?%aJjSYX!+1W&gy*saFpFZ!v6`S+SJ;Qp)J9ORVd87i_gpvS!6T{?o*!SQ
z6>lKZddR<MgM42*gJJ{Au^Q8m_7Yq-=HlsBKQaJlA?_1hM90shi}&1;kdY0wwYBC4
z4<1-d+l6WR`};w6go%3BIlb~h=;XK4O#bmYEG{r(X4V6{FpYm)J*cPO>6Q0`SA47u
zb=z>t<h4f!#ld!>(>|o}iqXOCk6HaIKhXvQ@FSXuHlp=s($06x90>qtolduz%nZ>A
z|6lValL<F&+%PvZG;9LkB#}rQq>FZ{Tvn!-Up!QY-{lYB*^E9>SZ&UMA3$1@G$=BZ
z^#X8M{z<0FecNfXd|xxB#or;iY;cEmLlfM$=9yOR{wkF9^0VyEhtNXYwg=bTB3`oG
z0TKYRn>TN&o12?|92y$3IRI8`Y-}8217m|@y)G-hl<*;hxvWSU3Od;b-^@PDNHdOO
z&WS!O{MrbYuq3l|VT6kHuwHJ!VOexWn8$~uL(}5hF+J&?DAVHF;IZ>NbJ(9xs4V8K
zc$ph(<iEveB6QYY1a|XVhTwAf^5sI>-Zlro?ug3D$~-nO>JfTfmd6XwkE2ZWMb@0X
z)tLWPKfF_V#<Ae*e)z^zL8kgVjhW|t)&?A>Z`Ncf4*rwrMUfw9g7>?}(=6si*w2mD
ziNR}otb44#{gTqs(ki;-Y!1L^G=e^n6-;Y+6Ug2;_+Ne>TfQjq7W~qT!ixRoXb)zm
z_6YHBHAVy_=pb7bTWZxa&VbvR#BxR4ZMI`XQT&y@2CEZFxn7KHZuB2w@LHDWJAfWK
zl8TCof78Q9F#G7yBevxkEM__3{FjxL8Av<UCtJ2}4B7#AgEgIaIsHC@GK`p;a2xXy
z^+Ft|xsSz14QvPKt$M}}U}O5-87ZB@ec_XCgwOGA;vSyW8iky9vH|WJkL&FW;3{#Q
zs3B@u%;0eik1vQ0ASETmnQnH$FuM%f+uK3+LMvU4o%9?Qat|Lq#MP@;M@j2AHh`sj
zEjYWqxgW1)_QEf=4%0WEf-E$qN%s1l7VmA}!2jSa1ZVVsbfbi$r4N9>)31H#JY{D-
ze6&57ajcU*e>G6-I@_d(E^1N4)(SZvO*f`Q=8TfoQN+9xzvQa9;d<g*qL{CI4X-s4
zj{kE6G#bskD_5?dt*wnccsj}G=lo)sUsY9gh=$X}hC=rQNc)222snqv5JbqQbEmIO
zCga(lxJ9~9t){a+mGG1<ij1P1!Fy{C<l%{MUb5Sl_l+5lsiNn)M`lB@zZPCQvs(gp
z98&|BN_hIcmlEamey%}r;5yvZC*h)s_7xd`A2;^{Q9^`S)xwEVUTY?1S!!ed`qB$;
z_L(zhs+d{+miA0dO_eYJJTp2vx{%Dr6%-Uy(OofPYycs<1*Aa{K2E{W=cGaEC}x_N
zWU0}Q^j8xn%c-_Y&@9+4=e02dzUyOsriRC!^HZlpvA<1BvN9mOV>HQMdM|m`)bM@h
s0^U6&7a0J{r7^R1p2=&t#>0~T56HDsY7y&<qW}N^07*qoM6N<$g4uqwqW}N^
index 0406477f52e20d343d5d7903aee28d6d05bcbc63..699ef2326e0561a10742dff28711cfc4c77edd56
GIT binary patch
literal 912
zc$@){18@9^P)<h;3K|Lk000e1NJLTq001fg000~a1^@s67vL@H000A5Nkl<Zc-rOG
z&x;dh9LMoqdmV`TXl&|eN<k0=uRRHS68awqLQkFwUMdQ9!|pQ6?y^6~{t8%nXjd$@
z7O(yda}pkS>a>=pq_j<I8wnKxg-_pyQIpLxlUZb;(!=YJZ=U&nznNubKW|BTBOL1R
z-rinvREu;vo%49V(xN*%J2l+KQwR<n7$i`^kjpTEdW4TE+<>#_p^Lb5(XFkmS@fWQ
zA%uxVcXxNMK(H_)^$011kINR#Z-j&3Q4cP<xw%<G55hj0dA)%Q%1tb~y}fPVAXpeg
zNFjK{)9z}!-8QfgGSnv)U0+}CK-eGslFtb=Dl~*2VBjEFq!2uUOP2JpBYn)+qN}T`
zT?h?HFKP*NP|=XJwKW3=<vik&^Qyq2_HxnX<>ev%d7Y=0>m#I4&cYO(Us+jE1sUou
z7fq7HLuej)NpM|+6oQ9?U}38ESz21E;Sq!k^|3$w;^JZ(!o5%f>Tee{Usza(kV5c?
zVc;NGOkI{41{Q+D<ij*SKVL^5!hM{}>lg3<9v_AVv|6pJ5Io|Mx`Bgmy=+N(8(0Vq
z;n!2%_#y^SKp!6z4Vs&qyM{PWHz-{)pFN8q9O|Jn2OBrA0f*;!h!*mTj}9{~!Ib?A
z{ZILSE!zBMaAfJ}y>I_Mk80`Z%vaB9xQ(X}96B&apn@TnVFL9CQ`1xP>%m#{&_#KA
zI{oEev*<wqLkOA}a&K@2f`u8WM@S)*rl&J^pBXp^9^u#1sn7qYp$B0f&Ai?~2IVFe
zJ$<Kd;2>BSL`WfcObsUS7k?U92pJ|{`0sXl9SCFTiO&f%Dl~*2VBjEFq!2tRr>9e&
z{cd0(Sd6EqciO*nAv7ets3p)rMME09zZp0v=Mfj5|5X)Oyh=|e*SbTzR(d+Q{&R#B
z%2}Ag^BbI*F2k$zbYjVS2!~Hk;JOGY1P=$nqH=nwFaK1-BM2GB)6?<!Cv6D9^hCWd
zJ(<>%2q^@Q7zPf4#nfewFZ^g=AvjDvOf$E>ucHs)KF;O!3wQvJV0xOlnO%k85s%aj
z9E8$fVm|%Bz(Q~+PEW^fJidql6wpUudOG&Wch?XH>IPHO)69*>vlzl*dU~R10~>I7
mj)!RB$kP)uF5%5jPyYfEhJw@=xn~am0000<MNUMnLSTZ9DVa|I
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..53bd1cb0ca3a69eb5846f44d5ab2c7bacdc70e62
GIT binary patch
literal 389
zc$@)+0eb$4P)<h;3K|Lk000e1NJLTq000&M000gM1^@s6D>3ZN0003@Nkl<Zc-rmL
zy-LGS7zW_hic$)?skEpF1*cv>cb%QR1h2q?gOfOjgNx7$@B%Cv!Of<mttPFMBS~Xg
zn$(2oV!<i|3$I@a(SYfXgW%xsa5!*y;rlru0Keit_$&A{mrHZpMUO8OAPB{8@;r~T
zbIzf6spafbn)C>Ua7fBcpDC8gCyJs#*L4_%;pyLHSw^XRodpmhp`~McpJ0g0XDhnh
z*Hx)fZ5T!ywrzX*;gVEgj^nI&B`zLWQ=~=^Kp+u+k0%<<<|boz@1|+?L*0`x_SVw%
z4FF+({}Ko76mbZAUPv-%crj6`WHn8LWm!<wdsM5phXA5M!-?;;G6X(b1GmC0nZj9J
zRUwMf4S@KdsW0p{B19k{m!sA#?3R9&=N}(TbA8lG&F`p5qLaipdmMf4bk+b&kF&3H
j+x6L>e2~dM`|~~kic*Ihb0ca%00000NkvXXu0mjf+@!4A
index 0bbc27e2294d83c7fce14973966bd4817074e46a..8c4f4d96f06ed2067f62d012d1f91ab1b98503f8
GIT binary patch
literal 758
zc$@+D0tx+zP)<h;3K|Lk000e1NJLTq001BW000mO1^@s6cL04^0008LNkl<Zc-p1a
z-%C?r7zgm?Hh&b+mA_JFOKnk67u`i5NP-~<g8xAfT?lm}X%V_H*IL?ILt8-@k`Y4P
zMi=2lbZ1>Ch4aT0J4aJHy3(6nJ$;|?yz6xgZFTYCeV_L{XYcnM&dxbNME~UKM4Al>
zzzz;@Lg5~q(r1_RZ0R41#bWJX0qsZn+Oz=n6K{4p>R<0zK!3qPe><O-2{1f7YyjoK
z(5~K5H~z~6%7ZC)q97e$XlRJ?rLG>F$6qEXUwmFBKr|X9(a3c!($}PV^#JbCO=6z0
zt!C84P^2kVJTJCdq<43KNF+jx=len56<F5;9DDYIm~1Eyo5%`LH)35w@5ZhG;c%Eh
z51`fy!3$r2c$B(I4^SIhBPN@xr`*vvzJ193WZjQrUx9c;-G64pa!UYvdZU4X0b=^*
zs7qiHD2K^lBz8~*sEMu;Q-3pd{`ux%tbGE?=8CR<zA*OlNG3oi6e6YvK<$_HIk*U=
zV8|NW_p1Qa4-8`Z?RSOEyRtrC_h_Z*+|!L}%uUtH$2n+vvtTetOb>uMA?r<03R6-W
zGA2}js(Z`Cv<I&c^&*ga&}cdPc&!@qY3Va%T+9Rr1Og;lP^-0+thr%I<}=`uc}fMS
z>|Y{Q8(MBt4;$(fkSA=O#5gTIanHk*2AQY$-1KICzkd}-<AMZ`c5DVJpjqmKdJ$E4
z7rp~2p22So7#D%GWARgAv(^<@YL)uW9q{>l%`gWfI-yIelTZ(BV8~jR`X^L*6PL^H
z%+CX{qrD3^Dti}tq-M$b;PUAjU!ntZ69~t<)kBz**Xy;zd!QWNf<60VB%G}E)pkkw
z?b(U4TeFl6>+dd&ZWXEbz@Ga0`a0nQSTc6X*HE#E0!9BiR`kqXFYk_jEV~)Ec;s4p
oSJ?jdbF8!JR1o1%^iMJS4R$)?zL<C|I{*Lx07*qoM6N<$f*~7VO8@`>
deleted file mode 100644
index 1f76506488a6613146fc335961b739efc66eca10..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 851ae1615dd175ade57fd2b2ac0caa9b7c4b5b17..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/themes/winstripe/browser/browser.css
+++ b/browser/themes/winstripe/browser/browser.css
@@ -1178,31 +1178,32 @@ toolbar[mode="full"] .toolbarbutton-1 > 
   -moz-image-region: rect(16px, 48px, 32px, 32px);
 }
 #close-button:hover:active {
   -moz-image-region: rect(32px, 48px, 48px, 32px);
 }
 
 /* ::::: Location Bar ::::: */
 
-#urlbar {
-  width: 7em;
-  min-width: 7em;
-}
-
 #urlbar,
 .searchbar-textbox {
   -moz-appearance: none;
   margin: 1px 3px;
-  padding: 2px;
+  padding: 0;
   background-clip: padding-box;
   border: 1px solid ThreeDShadow;
   border-radius: 2.5px;
 }
 
+#urlbar {
+  width: 7em;
+  min-width: 7em;
+  -moz-padding-end: 2px;
+}
+
 @media all and (-moz-windows-default-theme) {
   #urlbar,
   .searchbar-textbox {
     @navbarTextboxCustomBorder@
   }
 }
 
 #urlbar:-moz-lwtheme,
@@ -1227,44 +1228,55 @@ html|*.urlbar-input:-moz-lwtheme:-moz-pl
   -moz-box-align: stretch;
 }
 
 .urlbar-textbox-container {
   -moz-box-align: stretch;
 }
 
 #urlbar-icons {
-  height: 18px;
   -moz-box-align: center;
 }
 
 .urlbar-icon {
-  padding: 0 2px !important;
+  padding: 3px 3px;
+}
+
+.searchbar-engine-button,
+.search-go-container {
+  padding: 2px 2px;
 }
 
 .urlbar-icon:-moz-system-metric(touch-enabled) {
   -moz-margin-end: 1px !important;
   padding: 0 3px !important;
 }
 
+.urlbar-icon:hover {
+  background-image: -moz-radial-gradient(center, circle closest-side, hsla(200,100%,70%,.3), hsla(200,100%,70%,0));
+}
+
+.urlbar-icon[open="true"],
+.urlbar-icon:hover:active {
+  background-image: -moz-radial-gradient(center, circle closest-side, hsla(200,100%,70%,.1), hsla(200,100%,70%,0));
+}
+
 #urlbar-search-splitter {
   min-width: 6px;
   -moz-margin-start: -3px;
   border: none;
   background: transparent;
 }
 
 #urlbar-search-splitter + #urlbar-container > #urlbar ,
 #urlbar-search-splitter + #search-container > #searchbar > .searchbar-textbox {
   -moz-margin-start: 0;
 }
 
 #urlbar-display-box {
-  margin-top: -2px;
-  margin-bottom: -2px;
   -moz-border-end: 1px solid #AAA;
   -moz-margin-end: 3px;
 }
 
 #urlbar-display {
   margin-top: 0;
   margin-bottom: 0;
   color: GrayText;
@@ -1272,18 +1284,16 @@ html|*.urlbar-input:-moz-lwtheme:-moz-pl
 
 /* identity box */
 
 #identity-box {
   background-image: -moz-linear-gradient(hsl(0,0%,98%), hsl(0,0%,92%));
   box-shadow: 0 1px 0 hsla(0,0%,0%,.05) inset;
   -moz-border-end: 1px solid hsla(0,0%,0%,.1);
   padding: 2px;
-  margin: -2px;
-  -moz-margin-end: 0;
 }
 
 #identity-box:-moz-locale-dir(ltr) {
   border-top-left-radius: 1.5px;
   border-bottom-left-radius: 1.5px;
 }
 
 #identity-box:-moz-locale-dir(rtl) {
@@ -1347,31 +1357,37 @@ html|*.urlbar-input:-moz-lwtheme:-moz-pl
   -moz-margin-start: 1px;
   -moz-margin-end: 3px;
 }
 
 /* Location bar dropmarker */
 
 .urlbar-history-dropmarker {
   -moz-appearance: none;
-  padding: 0 1px;
+  padding: 0 3px;
   background-color: transparent;
   border: none;
   width: auto;
-  list-style-image: url(mainwindow-dropdown-arrow.png);
-  -moz-image-region: rect(0, 13px, 11px, 0);
+  list-style-image: url("chrome://browser/skin/urlbar-history-dropmarker.png");
+  -moz-image-region: rect(0px, 11px, 14px, 0px);
 }
 
 .urlbar-history-dropmarker:-moz-system-metric(touch-enabled) {
   min-width: 6.4mozmm;
 }
 
+.urlbar-history-dropmarker:hover {
+  background-image: -moz-radial-gradient(center, circle closest-side, hsla(205,100%,70%,.3), hsla(205,100%,70%,0));
+  -moz-image-region: rect(0px, 22px, 14px, 11px);
+}
+
 .urlbar-history-dropmarker:hover:active,
 .urlbar-history-dropmarker[open="true"] {
-  -moz-image-region: rect(0, 26px, 11px, 13px);
+  background-image: -moz-radial-gradient(center, circle closest-side, hsla(205,100%,70%,.1), hsla(205,100%,70%,0));
+  -moz-image-region: rect(0px, 33px, 14px, 22px);
 }
 
 /* page proxy icon */
 
 #page-proxy-favicon,
 #urlbar-throbber {
   width: 16px;
   height: 16px;
@@ -1464,97 +1480,83 @@ richlistitem[type~="action"][actiontype=
   color: GrayText;
   font-size: smaller;
 }
 
 .autocomplete-treebody::-moz-tree-cell(suggesthint) {
   border-top: 1px solid GrayText;
 }
 
-/* go button */
-
-#go-button {
-  list-style-image: url("chrome://browser/skin/Go-arrow.png");
-  -moz-image-region: rect(0px, 16px, 16px, 0px);
-}
-
-#go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
-  -moz-transform: scaleX(-1);
-}
-
-#go-button:hover {
-  -moz-image-region: rect(16px, 16px, 32px, 0px);
-}
-
 /* combined go/reload/stop button in location bar */
 
+#go-button,
 #urlbar > toolbarbutton {
   -moz-appearance: none;
-  list-style-image: url("chrome://browser/skin/reload-stop-go.png");
-  margin: -2px;
-  -moz-margin-start: 0;
-  padding: 0 3px;
+  padding: 0 2px;
   background-origin: border-box;
   border: none;
-  -moz-border-start: 1px solid rgba(0,0,0,.25);
-  box-shadow: 0 1px 0 rgba(0,0,0,.1) inset,
-              -1px -1px 1px rgba(255,255,255,.25) inset;
-}
-
-#urlbar:-moz-locale-dir(ltr) > toolbarbutton {
-  border-top-right-radius: 1.5px;
-  border-bottom-right-radius: 1.5px;
-}
-
-#urlbar:-moz-locale-dir(rtl) > toolbarbutton {
-  border-top-left-radius: 1.5px;
-  border-bottom-left-radius: 1.5px;
-}
-
-#urlbar > toolbarbutton:not([disabled]):active:hover,
-#urlbar-reload-button:not(:hover) {
-  -moz-border-start-style: none;
-  -moz-padding-start: 4px;
-  box-shadow: none;
-}
-
-#urlbar > toolbarbutton:not([disabled]):active:hover {
-  box-shadow: 0 0 6.5px rgba(0,0,0,.4) inset,
-              0 0 2px rgba(0,0,0,.4) inset;
-}
-
-#urlbar-go-button {
-  -moz-image-region: rect(0px, 56px, 14px, 42px);
-  background-image: -moz-linear-gradient(rgb(115,213,115), rgb(96,190,96) 49%, rgb(82,174,82) 51%, rgb(79,155,79));
-}
-
-#urlbar-go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
-  -moz-transform: scaleX(-1);
-}
-
-#urlbar-go-button:hover {
-  background-image: -moz-linear-gradient(rgb(96,221,96), rgb(71,191,71) 49%, rgb(54,171,54) 51%, rgb(50,147,50));
+  list-style-image: url("chrome://browser/skin/reload-stop-go.png");
+}
+
+#go-button {
+  padding: 0 3px;
 }
 
 #urlbar-reload-button {
-  -moz-image-region: rect(0px, 14px, 14px, 0px);
+  -moz-image-region: rect(0, 14px, 14px, 0);
 }
 
 #urlbar-reload-button:not([disabled]):hover {
-  -moz-image-region: rect(0px, 28px, 14px, 14px);
-  background-image: -moz-linear-gradient(rgb(162,207,241), rgb(111,178,225) 49%, rgb(91,159,217) 51%, rgb(62,138,200));
+  background-image: -moz-radial-gradient(center, circle closest-side, hsla(200,100%,70%,.2), hsla(200,100%,70%,0));
+  -moz-image-region: rect(14px, 14px, 28px, 0);
+}
+
+#urlbar-reload-button:not([disabled]):hover:active {
+  background-image: -moz-radial-gradient(center, circle closest-side, hsla(200,100%,60%,.1), hsla(200,100%,60%,0));
+  -moz-image-region: rect(28px, 14px, 42px, 0);
+}
+
+#urlbar-reload-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
+  -moz-transform: scaleX(-1);
+}
+
+#go-button,
+#urlbar-go-button {
+  -moz-image-region: rect(0, 42px, 14px, 28px);
+}
+
+#go-button:hover,
+#urlbar-go-button:hover {
+  background-image: -moz-radial-gradient(center, circle closest-side, hsla(110,70%,50%,.2), hsla(110,70%,50%,0));
+  -moz-image-region: rect(14px, 42px, 28px, 28px);
+}
+
+#go-button:hover:active,
+#urlbar-go-button:hover:active {
+  background-image: -moz-radial-gradient(center, circle closest-side, hsla(110,70%,50%,.1), hsla(110,70%,50%,0));
+  -moz-image-region: rect(28px, 42px, 42px, 28px);
+}
+
+#go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
+#urlbar-go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
+  -moz-transform: scaleX(-1);
 }
 
 #urlbar-stop-button {
-  -moz-image-region: rect(0px, 42px, 14px, 28px);
-  background-image: -moz-linear-gradient(rgb(231,162,140), rgb(209,119,100) 49%, rgb(193,92,78) 51%, rgb(173,72,58));
-}
-
-#urlbar-stop-button:hover {
-  background-image: -moz-linear-gradient(rgb(244,156,128), rgb(215,101,77) 49%, rgb(194,66,48) 51%, rgb(170,41,23));
+  -moz-image-region: rect(0, 28px, 14px, 14px);
+}
+
+#urlbar-stop-button:not([disabled]):hover {
+  background-image: -moz-radial-gradient(center, circle closest-side, hsla(5,100%,75%,.3), hsla(5,100%,75%,0));
+  -moz-image-region: rect(14px, 28px, 28px, 14px);
+}
+
+#urlbar-stop-button:hover:active {
+  background-image: -moz-radial-gradient(center, circle closest-side, hsla(5,100%,75%,.1), hsla(5,100%,75%,0));
+  -moz-image-region: rect(28px, 28px, 42px, 14px);
 }
 
 /* popup blocker button */
 
 #page-report-button {
   list-style-image: url("chrome://browser/skin/urlbar-popup-blocked.png");
   -moz-image-region: rect(0, 16px, 16px, 0);
 }
@@ -1571,20 +1573,22 @@ richlistitem[type~="action"][actiontype=
 /* star button */
 
 #star-button {
   list-style-image: url("chrome://browser/skin/places/bookmark.png");
   -moz-image-region: rect(0px 16px 16px 0px);
 }
 
 #star-button:hover {
-  -moz-image-region: rect(0px 32px 16px 16px);
+  background-image: -moz-radial-gradient(center, circle closest-side, hsla(45,100%,73%,.3), hsla(45,100%,73%,0));
+  -moz-image-region: rect(0px 32px 16px 16px); 
 }
 
 #star-button:hover:active {
+  background-image: -moz-radial-gradient(center, circle closest-side, hsla(45,100%,73%,.1), hsla(45,100%,73%,0));
   -moz-image-region: rect(0px 48px 16px 32px);
 }
 
 #star-button[starred="true"] {
   list-style-image: url("chrome://browser/skin/places/editBookmark.png");
 }
 
 /* bookmarking panel */
@@ -2220,18 +2224,16 @@ toolbarbutton.bookmark-item[dragover="tr
 #notification-popup-box {
   position: relative;
   background-color: #fff;
   background-clip: padding-box;
   padding-left: 3px;
   border-radius: 2.5px 0 0 2.5px;
   -moz-border-image: url("chrome://browser/skin/urlbar-arrow.png") 0 8 0 0 / 0 8px 0 0;
   -moz-margin-end: -8px;
-  margin-top: -2px;
-  margin-bottom: -2px;
 }
 
 #notification-popup-box:not([hidden]) + #identity-box {
   -moz-padding-start: 10px;
   border-radius: 0;
 }
 
 #notification-popup-box:-moz-locale-dir(rtl),
--- a/browser/themes/winstripe/browser/devtools/csshtmltree.css
+++ b/browser/themes/winstripe/browser/devtools/csshtmltree.css
@@ -37,17 +37,18 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 body {
   font-family: sans-serif;
   font-size: 11px;
   background: #EEE;
 }
-.path {
+.path,
+.filters {
   font-size: 11px;
   word-spacing: -1px;
 }
 .path ol {
   list-style: none outside none;
   margin: 0;
   padding: 0;
 }
@@ -66,117 +67,95 @@ body {
 .path li:last-child {
   background: -moz-linear-gradient(top, #FFC, #DD8);
 }
 .path li:last-child:after {
   color: red;
   content: "";
 }
 
-#header,
-#footer {
-  padding: 5px;
-}
-
-#header label {
-  font-weight: bold;
-}
-
 .property-header {
   padding: 2px 5px;
   background: -moz-linear-gradient(top, #F8F8F8, #E8E8E8);
   color: #666;
 }
 
 .property-name,
-.property-value,
-.rule-count,
+.rule-matched,
 .rule-unmatched {
   cursor: pointer;
 }
 
 /* Take away these two :visited rules to get a core dumper     */
 /* See https://bugzilla.mozilla.org/show_bug.cgi?id=575675#c30 */
-.link,
-.unmatchedlink {
+.link {
   color: #55A;
 }
-.link:visited,
-.unmatchedlink:visited {
+.link:visited {
   color: #55A;
 }
-a.link,
-a.unmatchedlink {
+a.link {
   text-decoration: none;
   cursor: pointer;
 }
-a.link:visited,
-a.unmatchedlink:visited {
+a.link:visited {
   text-decoration: none;
 }
 
-.rule-count,
+.rule-matched,
 .rule-unmatched {
-  padding: 5px 0 0 15px;
+  padding: 2px 0;
+  white-space: nowrap;
 }
-.unmatched {
-  display: inline-block;
+
+.rulelink {
+  color: #55A;
 }
+
 .expander {
   width: 8px;
   height: 8px;
-  display: inline-block;
+  float: left;
+  -moz-margin-start: 15px;
   -moz-margin-end: 5px;
-  margin-bottom: 1px;
+  margin-top: 3px;
   background: url("chrome://browser/skin/devtools/arrows.png");
-}
-
-.unmatched-rule {
-  -moz-margin-start: 25px;
   background-position: 24px 0;
 }
 
-.property-view .rule-count .expander,
-.property-view .rule-unmatched .expander {
-  background-position: 24px 0;
+.searchfield {
+  background: url("chrome://browser/skin/devtools/search.png") no-repeat #FFF;
+  border-radius: 5px;
+  -moz-padding-start: 20px;
+  width: 135px;
+  float: right;
 }
-.property-view[dir="rtl"] .rule-count .expander,
-.property-view[dir="rtl"] .rule-unmatched .expander {
+
+.expander[dir="rtl"] {
   background-position: 16px 0;
 }
-.property-view[open] .rule-count .expander,
-.property-view[open] .rule-unmatched .expander {
+.expander[open] {
   background-position: 8px 0;
 }
 
 .property-name {
   display: inline-block;
   font-size: 12px;
   font-weight: bold;
   color: #000;
 }
 .property-value {
   display: inline-block;
   font-size: 10px;
 }
 
-.property-view > .rules {
+.property-view-hidden {
   display: none;
 }
-.property-view[open] > .rules {
-  display: table;
-}
-.rules {
-  -moz-margin-start: 32px;
-  max-height: 350px;
-  overflow-y: auto;
-}
-.rule-status {
-  white-space: nowrap;
-}
+
 .rule-link {
   text-align: end;
   -moz-padding-start: 10px;
 }
 
 /* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
 .rule-text {
   direction: ltr;
@@ -194,8 +173,18 @@ a.unmatchedlink:visited {
   text-decoration: line-through;
 }
 .parentmatch {
   color: #666;
 }
 .unmatched {
   color: brown;
 }
+
+.userStyles {
+  position: relative;
+  top: 3px;
+}
+
+.userStyles,
+.userStylesLabel {
+  cursor: pointer;
+}
\ No newline at end of file
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..df7212d78c8f86e7abe5073d85bf419786993550
GIT binary patch
literal 1445
zc%17D@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE;=WQl7;NpOBzNqJ&XDuZK6ep0G}
zXKrG8YEWuoN@d~6R2v2cW~I!Kh>{3jAFJg2T)jk)8oi3#0tOJUv9BmdOwLX%QAkQn
z&&;z`dcS+Wl0s&Rtx~wDuYqrYb81GWM^#a3aFt(3a#eP+Wr~u$oq|n;70`g()RIJn
zirk#MVyg;UC9t_xKsHENUr7P1q$Jx`3F4>--v9;Y{GwC^Q#}LSWCJq;1v5iELt_(j
zb8{U9BLhPNeFGzXLnB>7b1P#bD+2=sC{P00R+N%v73AUuwF}6zRmvzSDX`MlFE20G
zD>v55FG|-pw6wGYnPFt43sj+7T$xvrSfQI&tPC^3CAB!YD6^m>Ge1uO#7|7hFD<cE
zQi6FQw*YQzUNJP7fB~jokyxN_sAr&$q|nzFztY@Xxa#7Ppwu+{s*6J^3sUuiQj7CT
zi;{s6m!=HTTwvu~l$uzQUlfv`p92fUfQ<Z-{NjxK0tM$_Qw86|<jgz}AFSTj*UB@m
zxFj(zIn~p}RtYGgmzkMj<?8HW<YHiH=45K*WN7H(W@%|*=4@<YVCL%N=458z2-EA5
zpIn-onpXnTn}X15j#DovDL{0m7G;*DrnnX5=PH1`Y?X=IEhf0#0@0g-+byOz_38s1
zqmLHRFd<;-0Wsmp7RZ4o{M0;PYA*sN>rTV&CkzZslAbP(Ar-gIOxf=(ohWhqzW0|&
z%5$EucNmJziJ9UcY}`?-!m3zuX2F9?x{8aG4(>moX>nv>w|9Gzh2oBmj%RINv%&-y
zpVk#z=i6j)gwJ;IvDe>Qzh`+QC3QFR*HpyK+x@)y{pUUBtLLnH{Y3SwOWchrE88a)
zc|v(2D?~zyzr{BRL^aK3Wm<7rz(Bc<b3enw!|LW2?>MWhJ-C;7dz-+8nFfjSk&gGC
zud{8r!LAmz`Sx4$iy0w$V%@KA=9DSR@Xg=wy?(aOGSNN1m%SBx$;Z1U?6rA|pRU;H
zm5VfrJ9-)9Iu6Kp9}TMTYdz26=wbRy%0`bvl9@}xMQLKc&kD=LBX7&zKc2gO#e)TN
zAKaf*Yj<DZ_2hG(_nfJ^k<)ekwQc+LRaaN7eyrKO=mz(9ht^L&_k6gbDaOUB{dV!;
zhYEMAEIRI8{8!U>zx93gOMb=23DO>o4iAElPfA>xVBo>}dTUhg1C?NllMaVjd}g10
zR;g3pwA)2#<JUQsU#e~9T@6~f<f5JFnTN6~nz9S{*%GXu7FBM(9cwo!wNhDxD>m`0
zaijbLrazl*=Im|w7QQ+}%lO9E-|Ng<Ie!-KyyK!a`DJ+M)uvCcXEeR8uvw?{>_Eic
zt0ui_d`-z2I@@L6sJWQks5@rRy<5dI>Og|G$MV`ge)S5v&42rMTzdIs(dCzS4lg);
zGUd{bh})CqXP0bPeuMRfnI6;kSO0I+vq&&pJYHef^w)U`sNnQ;^>bP0l+XkKR`nx-
--- a/browser/themes/winstripe/browser/inspector.css
+++ b/browser/themes/winstripe/browser/inspector.css
@@ -196,26 +196,30 @@ code {
 }
 
 .nodeText {
   color: #333333;
 }
 
 .docType {
   position: absolute;
+  /* position DOCTYPE element above/outside the "nodeBox" that contains it */
+  /* Note: to be fixed in Bug #688439 */
   top: -16px;
   font-family: Menlo, Andale Mono, monospace;
   padding-left: 8px;
   color: #999;
   white-space: nowrap;
   font-style: italic;
 }
 
 .htmlNodeBox {
-  top: 16px;
+  /* make room for DOCTYPE element to be rendered above/outside "nodeBox" */
+  /* Note: to be fixed in Bug #688439 */
+  margin-top: 16px;
 }
 
 .nodeWhiteSpace {
   border: 1px solid LightGray;
   white-space: pre;
   margin-left: 1px;
   color: gray;
 }
--- a/browser/themes/winstripe/browser/jar.mn
+++ b/browser/themes/winstripe/browser/jar.mn
@@ -32,28 +32,28 @@ browser.jar:
         skin/classic/browser/livemark-item.png                       (livemark-item.png)
         skin/classic/browser/livemark-folder.png                     (livemark-folder.png)
         skin/classic/browser/Privacy-16.png
         skin/classic/browser/Privacy-48.png
         skin/classic/browser/reload-stop-go.png
         skin/classic/browser/Secure24.png                            (Secure24.png)
         skin/classic/browser/Toolbar.png                             (Toolbar.png)
         skin/classic/browser/Toolbar-inverted.png
-        skin/classic/browser/Go-arrow.png                            (Go-arrow.png)
 *       skin/classic/browser/searchbar.css                           (searchbar.css)
         skin/classic/browser/section_collapsed.png
         skin/classic/browser/section_collapsed-rtl.png
         skin/classic/browser/section_expanded.png
         skin/classic/browser/setDesktopBackground.css
         skin/classic/browser/menu-back.png                           (menu-back.png)
         skin/classic/browser/menu-forward.png                        (menu-forward.png)
         skin/classic/browser/monitor.png
         skin/classic/browser/monitor_16-10.png
         skin/classic/browser/urlbar-arrow.png
         skin/classic/browser/urlbar-popup-blocked.png
+        skin/classic/browser/urlbar-history-dropmarker.png
         skin/classic/browser/feeds/feedIcon.png                      (feeds/feedIcon.png)
         skin/classic/browser/feeds/feedIcon16.png                    (feeds/feedIcon16.png)
         skin/classic/browser/feeds/audioFeedIcon.png                 (feeds/audioFeedIcon.png)
         skin/classic/browser/feeds/audioFeedIcon16.png               (feeds/audioFeedIcon16.png)
         skin/classic/browser/feeds/videoFeedIcon.png                 (feeds/videoFeedIcon.png)
         skin/classic/browser/feeds/videoFeedIcon16.png               (feeds/videoFeedIcon16.png)
         skin/classic/browser/feeds/subscribe.css                     (feeds/subscribe.css)
         skin/classic/browser/feeds/subscribe-ui.css                  (feeds/subscribe-ui.css)
@@ -102,16 +102,17 @@ browser.jar:
         skin/classic/browser/tabview/edit-light.png                 (tabview/edit-light.png)
         skin/classic/browser/tabview/grain.png                      (tabview/grain.png)
         skin/classic/browser/tabview/search.png                     (tabview/search.png)
         skin/classic/browser/tabview/stack-expander.png             (tabview/stack-expander.png)
         skin/classic/browser/tabview/tabview.png                    (tabview/tabview.png)
         skin/classic/browser/tabview/tabview-inverted.png           (tabview/tabview-inverted.png)
         skin/classic/browser/tabview/tabview.css                    (tabview/tabview.css)
         skin/classic/browser/devtools/arrows.png                    (devtools/arrows.png)
+        skin/classic/browser/devtools/search.png                    (devtools/search.png)
         skin/classic/browser/devtools/csshtmltree.css               (devtools/csshtmltree.css)
 #ifdef MOZ_SERVICES_SYNC
         skin/classic/browser/sync-throbber.png
         skin/classic/browser/sync-16.png
         skin/classic/browser/sync-32.png
         skin/classic/browser/sync-bg.png
         skin/classic/browser/sync-desktopIcon.png
         skin/classic/browser/sync-mobileIcon.png
@@ -153,28 +154,28 @@ browser.jar:
         skin/classic/aero/browser/livemark-item.png                  (livemark-item-aero.png)
         skin/classic/aero/browser/livemark-folder.png                (livemark-folder-aero.png)
         skin/classic/aero/browser/Privacy-16.png                     (Privacy-16-aero.png)
         skin/classic/aero/browser/Privacy-48.png                     (Privacy-48-aero.png)
         skin/classic/aero/browser/reload-stop-go.png
         skin/classic/aero/browser/Secure24.png                       (Secure24-aero.png)
         skin/classic/aero/browser/Toolbar.png
         skin/classic/aero/browser/Toolbar-inverted.png
-        skin/classic/aero/browser/Go-arrow.png                       (Go-arrow-aero.png)
 *       skin/classic/aero/browser/searchbar.css                      (searchbar.css)
         skin/classic/aero/browser/section_collapsed.png
         skin/classic/aero/browser/section_collapsed-rtl.png
         skin/classic/aero/browser/section_expanded.png
         skin/classic/aero/browser/setDesktopBackground.css
         skin/classic/aero/browser/menu-back.png                      (menu-back-aero.png)
         skin/classic/aero/browser/menu-forward.png                   (menu-forward-aero.png)
         skin/classic/aero/browser/monitor.png
         skin/classic/aero/browser/monitor_16-10.png
         skin/classic/aero/browser/urlbar-arrow.png
         skin/classic/aero/browser/urlbar-popup-blocked.png
+        skin/classic/aero/browser/urlbar-history-dropmarker.png
         skin/classic/aero/browser/feeds/feedIcon.png                 (feeds/feedIcon-aero.png)
         skin/classic/aero/browser/feeds/feedIcon16.png               (feeds/feedIcon16-aero.png)
         skin/classic/aero/browser/feeds/audioFeedIcon.png            (feeds/audioFeedIcon-aero.png)
         skin/classic/aero/browser/feeds/audioFeedIcon16.png          (feeds/audioFeedIcon16-aero.png)
         skin/classic/aero/browser/feeds/videoFeedIcon.png            (feeds/videoFeedIcon-aero.png)
         skin/classic/aero/browser/feeds/videoFeedIcon16.png          (feeds/videoFeedIcon16-aero.png)
         skin/classic/aero/browser/feeds/subscribe.css                (feeds/subscribe.css)
         skin/classic/aero/browser/feeds/subscribe-ui.css             (feeds/subscribe-ui.css)
@@ -223,16 +224,19 @@ browser.jar:
         skin/classic/aero/browser/tabview/close.png                  (tabview/close.png)
         skin/classic/aero/browser/tabview/edit-light.png             (tabview/edit-light.png)
         skin/classic/aero/browser/tabview/grain.png                  (tabview/grain.png)
         skin/classic/aero/browser/tabview/search.png                 (tabview/search.png)
         skin/classic/aero/browser/tabview/stack-expander.png         (tabview/stack-expander.png)
         skin/classic/aero/browser/tabview/tabview.png                (tabview/tabview.png)
         skin/classic/aero/browser/tabview/tabview-inverted.png       (tabview/tabview-inverted.png)
         skin/classic/aero/browser/tabview/tabview.css                (tabview/tabview.css)
+        skin/classic/aero/browser/devtools/arrows.png                (devtools/arrows.png)
+        skin/classic/aero/browser/devtools/search.png                (devtools/search.png)
+        skin/classic/aero/browser/devtools/csshtmltree.css           (devtools/csshtmltree.css)
 #ifdef MOZ_SERVICES_SYNC
         skin/classic/aero/browser/sync-throbber.png
         skin/classic/aero/browser/sync-16.png
         skin/classic/aero/browser/sync-32.png
         skin/classic/aero/browser/sync-bg.png
         skin/classic/aero/browser/sync-desktopIcon.png
         skin/classic/aero/browser/sync-mobileIcon.png
         skin/classic/aero/browser/sync-notification-24.png
index 006a3f10f29ab757ab9be2c52eac6298d2b485ef..2e9a206347873920ddd70fac6c74b9786fc1c6cd
GIT binary patch
literal 1779
zc$@+A1`PR$P)<h;3K|Lk000e1NJLTq001xm000mO1^@s6P_F#3000KMNkl<Zc-oa#
zX-t%75dPfH+IXjJys9x?wKX=1Qo*B5T8~<7YdmUfTB}rAE7qtejfx1Xpx^-%H7W>N
z0Z}YMp&;UNxyoS?SdN8d*%OdsVefAbFlIWlB4Gn~{CJYtnP-ycdH0=nKIZi4)BPee
zG?WPs55I|s#&|$p`Cg_kym?Gb&^V?cZt+cZ?4szJV`C`Shv)V2OEHN5J-eO1iQP)^
zK)ilMojG%ciHL}B%gM<Bfj|HlyI}6M4OAW+$|$4ex#<f%L07O16p?dXF!x3V{5P;O
zZiKj}#s$t#!Fb9W83+ptV-gY)1S*vZlu9LBzkWS!fPbOi)2}@-foV-&o5{(-!7L4f
zmb5j=wa3R(?R5?C0yeTf@)EvOTI?smcn{@X%K)A9*|TTeii(QBWHN!#XoSMTLZ^RW
zAOoU(Jf`aKNJbg$>ZUIX0<QJ01G>^<pu9ZarRwkq;=Iy;|2lSN!g05Buq6W__UOE{
zBWu}duQEX5S-kVEX=!P>4Gj%ox7!_{I3*?J9@U7`yN5*81de4SCnquW;WJp(m4&XF
z{Jr-~>VJXLRXJc%rGh4JPbSr*VbfVj$Rz6NBZmJS%L`b~P7Bz;9+Lg%FMDC2uJEuF
za|ftK947-P%Iosw%c+TpiS_B}=}=Hm05X}(ar&K|odk+0=co|}xss@;s8sCrR7SaY
zwWfWO+L5=VUiauA7^=^Mxe-rZTML}AiGXnpm>V)3HR5#SZkDv9ew`}6H0KxoI(7wr
zJ?n!AKelm5LR`T7OliSk8E{Dex<CMZ5Kv4xsu2gdq11!DUobH-F)iig<<QjB1nuqZ
zU@#cKVzJQ4_ZXm<a#Yi3G>(6ytgH;sxUxBEMH5%C2W*X3!PcG&R(&N{j4H60G{Bj4
z1dQ7#M>XOgHwHM-ZfLr-v>ruVl;r;*GpjF}!FU6Dpb0?uJx4nqde=;<3#QsUAL@-@
zP{@|z;$o9lt924R5Qx*!(E&IkdhGo{acPc=PPkQTZMX(DeF<1iD3ogl3ui>r9D!oW
zIchfDBe1Hkg6{rLn(FXbF1{;yv-xY;zv^=LD?l3y&~)&nAdV!*TaG<f4z1wLW&mJ>
zNF>^ZVmLhESBlr`^-xk$VydX9@W9^T)qbNG98gzX;XZ?<ISZ^tB?{Jci?<LccI2!E
zIar=#g6`p7Ek3g@-7m|~L(6&d_-ojBS)R8VG|>PGpMF8LI>Bxwa^nsy<5B-GngKE~
zvb3~xhgdAOavV3H0jgD1RdHmPj8m@&pT_DVqZ##8_eJ{hQ)ZjC9BiBhtX2!c+6@kK
zZD8vt1$|ktK^3#Wm5g@}B1=Mim-F2C-?E8M)e%oY?gt>*;|v8Kx>SF5A?F4eCgapg
zFV71Tqwe3opMuw8Km#-*`T6-b$uRa%Z_o2737N=f1luoITXMn9wSdjWA*|0~HDj(B
ztjz+@WNizT1iw$lNqlb;!~IvY-r|3LR)Hb}pkk*pl&7KM@6B@mRqQS@+}*?Ue*2k>
zj0_<T>3{~>+S&l0*lgrdkJBEYMWwmtk!fqmf=*5ac58<dC}(?e2iop#POS|Z*WVs^
zD_}Jn+?caV17cr*lI;MMJ}7?Q^SH(j)PkL@$O$BFpFMz!ipkE-Zl=XWVr@1XT^Rz!
zlyltwtgI{<ah(_0Ag1orWJV|aP2H)<fKFotbQ-F`u6+!4-D8R|Cjxt08ff!9#dWwd
z`ZK^^#l~}`2W?Qx2apDVw!qtDDE2W^3^hl9V&p_4cW@sA=gyrQLED!E(=aO(3c$Ij
z$Kh7d=LF@<W-~l|_^=DPLwXyaD<q5fV1)6J7d&l?2m6y-V6MS8zsR>-SL`P?*Iod7
zb0R!#jRRxRubuVb(}y@+A;f{tc%wts4bLI*E!jJC8G-JV0V~;P#MP{jCDrZuyA037
z{?GVdv3K^l4;n^2PFE;0GIIWd2M<6lm(#*hq0plM@CjmpP$&#Ra}8t)=LC>Di+Xwt
z_zY&`=RR`LKiCQu+zHy8AH|Kai#MTAhR_(l#6yeAi)wn|7LY~E{7|%iu+x|4k!9?x
zD_&C{Wd$!02Ykt1^IOVWgZXy}e#_X6n2Qsf{In+0b7CRZraKv+4>jDdGjHF%EhMod
z8Zq|#`ST0`<MCZxT?<kCsidSNA<oKVCj<Lg1_yIuW8C88hS)_O(lb-&n+X3I)={Gu
zM;bbn#hND?OO~9NFa~Q*27Eu~O+=9)Bo=?aLqm;tn?UjJbD8(h<R;=EcP#Z#@Bdo(
V<;Y<h_VWM$002ovPDHLkV1imlQndg8
index aaae5b861d3a234efb46c86a3619b64f58059e2e..fbca0523df169b6892d2b5050035152fb6b92606
GIT binary patch
literal 1642
zc$@)h29^1VP)<h;3K|Lk000e1NJLTq001xm000mO1^@s6P_F#3000ItNkl<Zc-obg
zc~DbV6vi)kF0DAzacPUCj;MfEi$zf!rS7-@tu-R+pjA-<f;u8rKqRqjL1c4S)UuRC
zkYUjv${L_na0fwx7y`o7ju=Q-D~rX`bCEcb29-a4Gv}T29XQ{8=RP1#-;&W#<5@Ef
zJS*mB8Y5(ksFgYrhf)stU_St;#NTAvC4ZBtF*F{9(SNA7IisD*UoJ@US#lX;t+5&?
z+DGQrM6422hZ<fkv?sI1Y9PRLn&H)Bi$HKx4=~mrs{t0*f^loO#}kWhd(~llnC8ZE
z`Xvs;RbCw?mQ@DV74Ij9Xl^V9F4)b=ZHzYoN!%8QwwakVCIjAVMmNRJFb8_E4@o?=
zIQ!%_X3obND6l8m)n|=zV4xf*4?_&I3-%JNk2SzIn{HTo$`Jm^wT7N+Rv_dp1I+1v
z&;V}-!{Tmd=5Wm!56N9`iNe5>@)Kgr9j7&_8Ep_eX%?=_Y~g-#Tvin-Q5a~e2ohuN
z7_CvwXa;;XO<{274K8wY3YrtmV6b@S5Kj|KA=yDE*Kf;I1F9KefX8Mw^0qT>Na(K?
z6H=16OLE0!CnV650U-AQX!ivg(;Tf)4QhjF5B9DrvL_pH-`#}!NJuefTuNo|^4zwH
zGZN@819*7}Ndp?w9Ia6eYR}Lf>|KXLIfZT45X9}CU7zMW9}2t-;K_weL#Gd=yC_3(
z9p-555^7Le7m7XDYflYC*OeZVbT>zLLuV?yMao6I-q6Z}cWYfuQC*Kq-0HD698Wd6
z^=^Qq@5SYA=(_=L=}AHohDnBZYke)5UD7*#_1GI8Za(ALtw1AaN-zUyIvYB#T0(z;
zExaz-sW3p_0?pAH)u7fC$^%wH2wS6`cy4Ab<ZWYqe^Pw35oCz~&)nY+YU+eX8n7qM
z-I%49WlMB%=i^)N`ZvPM5;Pd|eo%wMH(*a}rY+G9VSl+4_g&V0Wd{yQ2Yx?PBS)=}
zyHpxxK0}Z0;HMtOti`;oOtPfpNHa+Bmo&Pm25V0W4?RU~lE(&?KK803<1=i?g1o&X
zx$Ry+GxQV!$fH$*HR)}ir>IR#w<hzkcO1fswEo(ljK8v@E5{06(?S1G4Xx3)aMOQ<
z414qymzY5&c^b0}c|S5~ubRVOK?AN$-Qkfm@?fATYydT>)G#$Z+^aThVo~lMk~Sz4
zyaHJ)u3gwj<O%R^+m!*-q~h=kXb<gGT;eF(nJXSftncm<;_BSoqmtetJ9rSjt|QWB
zrh)QTh(Xl7O_?L2D|?!tkq=OHU?fk2peo(2!P|s!p@xTh2t{EcXBRp6ywtr3<mmv<
zPme^N1%DU1HlT*17+(1+l;Nru)t+YyaA%)NWY?`B?eN0j(LST&xu#6OUqTlth&%!A
zIRI3<;qb0+;#x0gE<DhJ8lT|-h!V`TUBtJ&B2Wr1V(`BB0<=Wn@Mqt|(m0Uc_isTB
zPhno!K+3@dxorh@02PiZX+?8M2j&Y#HNZ1rl6xMw_rhZyfY=vgWk<R?Zo743j0R2u
zjZqUrcURS4Z#><kzQ&kdkY2>KNr#@tXS-gCqq=DfFA{;qsQHa*RT&U?88r9Y!qcvC
zfkAxh{SP>ZBMeqM59K<`_ClunVv$M%$5*jF<FnO;bol2*j`C|h%d5GYnHVHKpKnyt
zTI$j<DDocUZDFpvE?1kRY#@P6Cg*b|2|=0yot6IbN9Q(HU)@R0BeAuyW;NZ9f;wKe
zBn_g0>k%eoqOyTNw#MX=(6!M2$QiotbD&;e0e?msSC&U@6iKozhjP7DPEd4abw8i2
zF+tgY+Q|*fH*rq0@8ky<iMX4X1h4h1t(c!m@!G&xU@oaJ@cY{H_L}8bo2zUf(}w7l
zap&C;#hQw;?MQrvHQ7urIt4HIR?H>T#{E!x!$YeaYg)<%PVe|iKR<X4)aO`3UeIdM
zx&1m;iXqQC=<F^CUQ<_}V*`1oR|9J2{m+2sT9zgb$*05O^AtoKnMk3r^LJz#nzW)C
z)PAA-&snMk(Gb`XKOFWaeEtNPfG`vq|FVpzqe(W^B%71z$_9cgH8mscwX@D~ba&Hd
oWg_;@Ww2&XHK#2#KUd`c1L=DksDR{$rvLx|07*qoM6N<$f`AMCM*si-
index e070eb424b03f8bedf69aaeab810f398cc3b28ec..1017be9032a298c8aa1f4a5cd4576087d8bb6f0d
GIT binary patch
literal 1945
zc$@*52WI$*P)<h;3K|Lk000e1NJLTq001fg001fo1^@s6#ly*4000MINkl<Zc-qz2
ze{2)y9mnymP$19*xYqDcGcWF<(y;~75!U>&;}C)azJR7_owSOo0<~NJS*L1Jt4aF<
zMll_fB!nMv33N~bDQUyffwlteHZiRMnRaPoIOc`UYec7POp(~oVr}~FO?WPH>@((9
znfAv^&)wITyHB3SclVX=5|RH4H+1lhecj>DDoAVlTP2utT|u|)J>)_gE<#`-0);Rn
z%SBc~In)iT&J}X|zV5jg!~ne44BGP3H|sD6aWHIeXI$j9?k6FLL8a6UL?L+gT0!+h
zSP&%Ob`09QyVHe12-;Dk>mI}*T1L>Vd%6@X2x3q$5QQKCJxkd!2?{X?;&5jKZEWj^
zK+vu~u<Kz+DyNI^4=7j=#1Mrb0Ua{8=3NIBVh}y5F+pFB>>q%@!@gY$L(*lt$mX3L
z3Km35z?=Q}19BZ=aE%7txZ|~9{QFk!+KsLI3`8MX3@Y34n>gk=#Ni$dx?$U%1O!Dl
z6Oz9(5QQKC3xXJQ*xX*)w#S7JA&A30X6e^&+1&y`r_%|j=Lw_pXS)nUAxOXr1q*^0
z)VvGx?z)zB+jq_ix4asIz=AvF^Q%E$Y-)332!bvY>-qw8BZ1{kLDx0zd<KF9yeV}B
z3xXFM!hO!Rc5Cab7n|E+5LoQbPW{{tI^xHTuPnkPh=U<iWt-Ktn<LM`>rhv?R>-@r
zSkt^?$=asK@Y<$U>xZq49$g3YvFRuFpa~W(<0#g^eX}=Nj*#QD@ju$SWyKG6g+I^s
zJs7WzvjczD%|xz{_h14hViGj=si%Y<cL#&&ka`9&L5Ir26x@q^Jx;-7OtJ&t&_#=m
z58Y_@lrfWOA*bkYQ<wDA`4*pAypZkbn1%u!Iu8@aob<uB|L#H?E<#`-0);TdG0@Xb
zKMv(kH~#b8r&c*Ew;i$o(-)ttt!Q}1{1kt#IUOja=E8lLYKI*?srSfW9R?u|h9SrZ
znq0N&2_(@Al~Om*GrW3L@?Wc0eJ^b`^N^3}aQQ#*&ohsOtcIgzvf-HdC-xtqJ~Jik
zl#!Dbc7N)^AO!6w(sd8w5G^C<KUS_(=tB~{P%zMg<fSK8_W$LnZ$Fqan-ehw({Mi&
zW>@{bs?_{t=uE>e%p_ynf7<_5>N8*<f8=7GH$I6#V0TY;Jq$_Vxb%N}>@kHtB+-i=
zz1@G|@o#z^mOUQ^X2Ojx;ER>LmF4E)(AkEcn@Pqq{-|%h{%59+Txj-zj|U*|uy5DG
zkThAlr-2nK6#9_V`cdd`6Xl_xq03C>Vjc>`{3rbnUzz=pi@5j3hjB~YQ#=?n(1WDb
z3zaRXd5|DEggQg<>J!z)qd{lwI-7vtrn;vO0|5g)NTMHodb>9ote$nfOJ8xi;%lLf
zP@lP<kO%mlp7589S$Y-eYk|PAd!nATdpcEKZlDKA^rH|8eMp|HDDQnYSoT29o9Vr(
z($K!p8FR0hWIRX6%$sS(wq7@eAm~D|t}j405^(IEep_1l9VF3@!j!r~--(5#Nj#sn
z{F6~I`gr=ae_rU-P|VzICK)aEogYsESM&Rea0%jI2wA(QUzL=6AB7He_3k4j&*ysJ
z2VW0<!`x~9Gt?Hcs^6)epZ$Ta-QO7Xpa~W(<0#fZcTc$euh0Tat8cIWR^aWxm-JFk
zPk)8p*``F#YU&dp^?jf6j?dTiJi96RU$%Mr#!3zA9P)<SyqP;b4&ScEIqfMhIk-Pq
zQP)|wK!;5YIxf9&<}UAdp$!)yun>Vl7~&M>qvgw2LOIk8tWFDhw>HjR{v{ntO3haD
zuV%!&P<yC$eoEL$7(XVct0i8CL5PE42r`0x5DGmBK@2LTZXgQ5vpS^HTk77x;lP|_
zJC?<lZC@sgp9GEszM{XglkHi(8gk1y7X~3{N0F|35Qk_PL8JBc3Kj%0C>V%BkbpNM
zs9tguz^FP_HLreq{kf%Em&(#@OV3vyuD%jB-=5X0kENzF5eV$=$*zYXDIAynceS+&
z76dUwAxOZ>F==;wMo&5e4^$qnED3H6o(paX%9YXgmT!*!3QQQekg@rr0SG+o+qEzx
zP1f$|H`Ub&7DP*6BqY*jb5dPXo#fP9XZgB(g`>|=V^i-iZmD}Z#ycNTh!%s&7PNMA
zt>n~Ld*0XKduTN1w4c16fZ(ROry~m&8i+!WfCWJe>Ux*{(c_O6*SuVFwq|3E)NHCb
zU(s1Hcg)gH+YoJmz_ELxp0#`WSxJe3C<F<3p<qD}gUWF;-B)(FtT?bSa4zstKp6j6
z{$_dR%~Y`dlp8}3bfH++7oZynICf8O6c;}OK?2^Cx`G9P{#nPlIVn3>_K<&r-|~n3
z!Wd`&%laS4%Xl*ttm|2XOArS`$l5)<K6mbO@H*5LUSRv0uhGh;$_C$h->@(2`$JiK
z*~4}-Vn0JOetXJa_nrq$uy7eiu?Ftj`ObIx8dPqo{Ce50vO>FCvS%{=*StI2oH%z=
f>AyGGA+Pu^rcK9Q4oGc(00000NkvXXu0mjfNiei8
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fc8b0be983652ea7a0bd19553b894aadc23fda6b
GIT binary patch
literal 480
zc$@*?0U!Q}P)<h;3K|Lk000e1NJLTq001EX000gM1^@s6p&oUN0004}Nkl<Zc-rmM
z%}N4M6bJCkC`8hT%1DT!fmZVX?rYt;N9YZFfXEg_K@r(DDkut~qOcE5YZSi{Q%iF+
zOCc!=GO8ir^q)W(N=I82)Z)iw?i}u%x%Zq~LqtFBKZ)O!#QgHQVQFnEzjJU*yLQ(X
z+xthfxVkAIj%BQm2FL@+5P;RqUK$_|BtrmJ%tW($$SwFzV|1QKQ#6?=5}!T6DDByu
zX2hwXrpIz`0+L}Y{Go1!Hv!2o7LVgG_tb0UyuA3)WahT$j8Bv8*c*Cz6}k%xcWq?r
zAqZ3g2g*Wh>r|{Bf<Ps3pp@1`Z6wMMy8Pj{_|?rv0^;cOho7VI%K^MsNYAiy<(dTn
zNFoQ!=ksovjIba8N#uYjRhViU=P?H&JQB##N%(>sF5fujRi%naKOZ*&Neq=Myymf>
z5lCXFY<Gy;ZawmZ{Gk{fINTo0b(CAUeJ-p74hSrA)!#JgQvwGBmP#$E5VwEBV#_8{
z>HbQs)ixbqAO-qLv6>M#11Zo~b5E%5?jQOvHdNE&EfZd?I98)^*s1-_WmWg*Zp?S&
W?K3g#I)Y;W0000<MNUMnLSTXx!PWEt
index 0ee9f505fb6bdb93e7808d7981c6e7dab048314b..e6fd29f7d3866263660d1f7e537ae96a4858a051
GIT binary patch
literal 745
zc%17D@N?(olHy`uVBq!ia0vp^20$#p!3HD)*8SPYz`(S@)5S5Q;?~uxzS+WoB5VnY
z0VfWvTDth)sSH#5#R@D;v8=zOcg@YMb12RD`)0fD+G{~tT3U4vloV2~wl4bEJaOW|
zD=!aqyBY>fkCeTy{eJE}O~u4%u{L|Z@A*Dwg0r}#l2ZGv|MsW9$MraJFA@J1`i5Wg
z+W$T<d+9TO-S<%8Aa0#pyKn_bjo;ic6<^&OQx*V4YJ(LdS6pH0miAZG{>?pS{oiS8
z-u#^0eS1=9R^!jF>Q3UNcR7E1ExUg1{N6vBS4!pHt6t82e(q5C!gZf3^f&77J#goi
zGGp7_h50gdH*eldw`Zw3x4B#<=yUVui4Ny0zx6Rc-+AE7+xA5_d(Zq%U~>A_vZnow
z-S>~>7b9+0%KJE+m^Yy`tFGW%cgC8xd-&B9Qv6TM`W*A%*{Rx#60>ypc_%c_c<%dt
zCcE{bjb@Q@QVQ&b{?FK#*>@kil~S3}AalfKzD_}HWv~g~>@(^2S_BIm8YkpewVQ2s
zP0lr%Un%T%fRWYd<evk*4kp*sKF>5yWRVF_c%sf7vv;eaRJ*U3v3?^nWA;&Fv%SmT
zyMe4YvxkL`WsT_hlz&II_9F{eL?&b<#%73YJ$dU)o8kjors?0ez0_UP=CnBMTACRT
z<9op!d(=N4U%y9OYU?Jm&50Zp{Rf`zovUMDxqTaVQlTQ-#(PQ{4l_&l{P&i6(-aZY
z;kafy2UkGa+%xjCtF|Ml`1-H@!2G?zZE75q0b5_$YB;fqY<~5R|Kf5Z6UP(Ht3uy9
z3TiEwq5Apn<oweYSQPnJh3#c`UD1#fX3AYsQkiDTUOIs<Yr^Yai;cf4g4q{J_ua3b
z+-&8+ZhB%S>#kiUdmkMX+fq?=t=hlYn3sRsf}_Tl{{;Tu${u~;(ac%TpMLnoe){dd
V^yd#$U4coM!PC{xWt~$(69CWeSx^7~
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -839,16 +839,19 @@ user_pref("camino.use_system_proxy_setti
       processLogFD.close()
 
       for processPID in processList:
         self.log.info("INFO | automation.py | Checking for orphan process with PID: %d", processPID)
         if self.isPidAlive(processPID):
           self.log.info("TEST-UNEXPECTED-FAIL | automation.py | child process %d still alive after shutdown", processPID)
           self.killPid(processPID)
 
+  def checkForCrashes(self, profileDir, symbolsPath):
+    automationutils.checkForCrashes(os.path.join(profileDir, "minidumps"), symbolsPath, self.lastTestSeen)
+
   def runApp(self, testURL, env, app, profileDir, extraArgs,
              runSSLTunnel = False, utilityPath = None,
              xrePath = None, certPath = None,
              debuggerInfo = None, symbolsPath = None,
              timeout = -1, maxTime = None):
     """
     Run the app, log the duration it took to execute, return the status code.
     Kills the app if it runs for longer than |maxTime| seconds, or outputs nothing for |timeout| seconds.
@@ -905,17 +908,17 @@ user_pref("camino.use_system_proxy_setti
                  stderr = subprocess.STDOUT)
     self.log.info("INFO | automation.py | Application pid: %d", proc.pid)
 
     status = self.waitForFinish(proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath)
     self.log.info("INFO | automation.py | Application ran for: %s", str(datetime.now() - startTime))
 
     # Do a final check for zombie child processes.
     self.checkForZombies(processLog)
-    automationutils.checkForCrashes(os.path.join(profileDir, "minidumps"), symbolsPath, self.lastTestSeen)
+    self.checkForCrashes(profileDir, symbolsPath)
 
     if os.path.exists(processLog):
       os.unlink(processLog)
 
     if self.IS_TEST_BUILD and runSSLTunnel:
       ssltunnelProcess.kill()
 
     return status
--- a/build/macosx/universal/unify
+++ b/build/macosx/universal/unify
@@ -1055,24 +1055,34 @@ sub makeUniversalInternal($$$$) {
       return complain(1, 'makeUniversal: symlink: '.$!.' for:',
                       $aLink,
                       $fileTargetPath);
     }
 
     return 1;
   }
   elsif($aSourceFile->lIsRegularFile()) {
-    my ($machPPC, $machX86);
+    my ($machPPC, $machX86, $fileName);
     if (!defined($filePPC) || !defined($fileX86)) {
       # One of the source files isn't present.  The right thing to do is
       # to just copy what does exist straight over, so skip Mach-O checks.
       $machPPC = 0;
       $machX86 = 0;
+      if (defined($filePPC)) {
+        $fileName = $filePPC;
+      } elsif (defined($fileX86)) {
+        $fileName = $fileX86;
+      } else {
+        complain(1, "The file must exist in at least one directory");
+        exit(1);
+      }
     }
     else {
+      # both files exist, pick the name of one.
+      $fileName = $fileX86;
       if (!defined($machPPC=$filePPC->isMachO())) {
         return complain(1, 'makeUniversal: isFileMachO ppc failed for:',
                         $filePPC->path());
       }
       if (!defined($machX86=$fileX86->isMachO())) {
         return complain(1, 'makeUniversal: isFileMachO x86 failed for:',
                         $fileX86->path());
       }
@@ -1084,17 +1094,17 @@ sub makeUniversalInternal($$$$) {
                   $fileX86->path());
     }
 
     if ($machPPC) {
       # makeUniversalFile will print an error if it fails.
       return makeUniversalFile($filePPC, $fileX86, $fileTargetPath);
     }
 
-    if (grep { $filePPC->path() =~ m/$_/; } @gSortMatches) {
+    if (grep { $fileName->path() =~ m/$_/; } @gSortMatches) {
       # Regular files, but should be compared with sorting first.
       # copyIfIdenticalWhenSorted will print an error if it fails.
       return copyIfIdenticalWhenSorted($filePPC, $fileX86, $fileTargetPath);
     }
 
     # Regular file.  copyIfIdentical will print an error if it fails.
     return copyIfIdentical($filePPC, $fileX86, $fileTargetPath);
   }
--- a/caps/tests/mochitest/test_bug470804.html
+++ b/caps/tests/mochitest/test_bug470804.html
@@ -20,17 +20,19 @@ https://bugzilla.mozilla.org/show_bug.cg
 /** Test for Bug 470804
     Passing a null targetURL to checkLoadURIWithPrincipal shouldn't crash
  **/
 
 netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
 const nsIScriptSecurityManager = Components.interfaces.nsIScriptSecurityManager;
 var secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
                        .getService(nsIScriptSecurityManager);
-var principal = document.nodePrincipal;
+var principal = SpecialPowers.getNodePrincipal(document);
+isnot(principal, undefined, "Should have a principal");
+isnot(principal, null, "Should have a non-null principal");
 is(secMan.isSystemPrincipal(principal), false,
    "Shouldn't have system principal here");
 try {
   secMan.checkLoadURIWithPrincipal(principal, null,
                                    nsIScriptSecurityManager.STANDARD);
 } catch (e) {
   // throwing is fine, it's just crashing that's bad
 }
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -1402,19 +1402,20 @@ ifneq ($(PREF_JS_EXPORTS),)
 ifeq (WINNT,$(OS_ARCH))
 PREF_PPFLAGS = --line-endings=crlf
 endif
 
 ifndef NO_DIST_INSTALL
 $(FINAL_TARGET)/$(PREF_DIR):
 	$(NSINSTALL) -D $@
 
-libs:: $(FINAL_TARGET)/$(PREF_DIR) $(PREF_JS_EXPORTS)
+libs:: $(FINAL_TARGET)/$(PREF_DIR)
+libs:: $(PREF_JS_EXPORTS)
 	$(EXIT_ON_ERROR)  \
-	for i in $(PREF_JS_EXPORTS); do \
+	for i in $^; do \
 	  dest=$(FINAL_TARGET)/$(PREF_DIR)/`basename $$i`; \
 	  $(RM) -f $$dest; \
 	  $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(PREF_PPFLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $$i > $$dest; \
 	done
 endif
 endif
 
 ################################################################################
@@ -1647,36 +1648,37 @@ ifndef NO_DIST_INSTALL
 	  $(JAR_MANIFEST)
 endif
 endif
 
 ifneq ($(DIST_FILES),)
 $(DIST)/bin:
 	$(NSINSTALL) -D $@
 
-libs:: $(DIST_FILES) $(DIST)/bin
+libs:: $(DIST)/bin
+libs:: $(DIST_FILES)
 	@$(EXIT_ON_ERROR) \
-	for f in $(DIST_FILES); do \
+	for f in $^; do \
 	  dest=$(FINAL_TARGET)/`basename $$f`; \
 	  $(RM) -f $$dest; \
 	  $(PYTHON) $(MOZILLA_DIR)/config/Preprocessor.py \
 	    $(XULAPP_DEFINES) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) \
-	    $(srcdir)/$$f > $$dest; \
+	    $$f > $$dest; \
 	done
 endif
 
 ifneq ($(DIST_CHROME_FILES),)
 libs:: $(DIST_CHROME_FILES)
 	@$(EXIT_ON_ERROR) \
-	for f in $(DIST_CHROME_FILES); do \
+	for f in $^; do \
 	  dest=$(FINAL_TARGET)/chrome/`basename $$f`; \
 	  $(RM) -f $$dest; \
 	  $(PYTHON) $(MOZILLA_DIR)/config/Preprocessor.py \
 	    $(XULAPP_DEFINES) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) \
-	    $(srcdir)/$$f > $$dest; \
+	    $$f > $$dest; \
 	done
 endif
 
 ifneq ($(XPI_PKGNAME),)
 libs realchrome::
 ifdef STRIP_XPI
 ifndef MOZ_DEBUG
 	@echo "Stripping $(XPI_PKGNAME) package directory..."
--- a/config/system-headers
+++ b/config/system-headers
@@ -35,17 +35,16 @@ app/Message.h
 app/MessageRunner.h
 arpa/inet.h
 arpa/nameser.h
 asm/sigcontext.h
 asm/signal.h
 ASRegistry.h
 assert.h
 atk/atk.h
-atlbase.h
 atlcom.h
 atlconv.h
 atlctl.cpp
 atlctl.h
 ATLCTL.H
 atlhost.h
 atlimpl.cpp
 atlwin.cpp
--- a/configure.in
+++ b/configure.in
@@ -2311,23 +2311,16 @@ ia64*-hpux*)
         fi
         ;;
     esac
 
     case "$host_os" in
     cygwin*|msvc*|mks*)
         AC_MSG_ERROR([Using a Cygwin build environment is unsupported. Configure cannot check for presence of necessary headers. Please upgrade to MozillaBuild; see https://developer.mozilla.org/en/Windows_Build_Prerequisites.])
         ;;
-    *)
-        AC_CHECK_HEADERS(oleacc.idl)
-        AC_LANG_SAVE
-        AC_LANG_CPLUSPLUS
-        MOZ_CHECK_HEADERS(atlbase.h)
-        AC_LANG_RESTORE
-        ;;
     esac
 
     case "$target" in
     i*86-*)
         if test "$HAVE_64BIT_OS"; then
             AC_MSG_ERROR([You are targeting i386 but using the 64-bit compiler.])
         fi
 
@@ -5249,29 +5242,16 @@ dnl ====================================
 MOZ_ARG_DISABLE_BOOL(accessibility,
 [  --disable-accessibility Disable accessibility support (off by default on OS X)],
     ACCESSIBILITY=,
     ACCESSIBILITY=1 )
 if test "$ACCESSIBILITY"; then
     AC_DEFINE(ACCESSIBILITY)
 fi
 
-if test -n "$ACCESSIBILITY" -a "$COMPILE_ENVIRONMENT" = "1"; then
-case "$target" in
-*-mingw*)
-    if test "$ac_cv_header_atlbase_h" = "no"; then
-        AC_MSG_ERROR([System header atlbase.h is not available. See http://developer.mozilla.org/en/docs/atlbase.h for details on fixing this problem.])
-    fi
-    if test "$ac_cv_header_oleacc_idl" = "no"; then
-        AC_MSG_ERROR([System header oleacc.idl is not available. See http://developer.mozilla.org/en/docs/oleacc.idl for details on fixing this problem.])
-    fi
-    ;;
-esac
-fi
-
 dnl ========================================================
 dnl Disable printing
 dnl ========================================================
 MOZ_ARG_DISABLE_BOOL(printing,
 [  --disable-printing      Disable printing support],
     NS_PRINTING=,
     NS_PRINTING=1)
 
new file mode 100644
--- /dev/null
+++ b/content/base/crashtests/682463.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+
+function boom()
+{
+  var j = document.createTextNode("j");
+  var r = document.createRange();
+  r.setEnd(j, 1);
+  j.splitText(0);
+  r.setEnd(j, 0);
+}
+
+</script>
+</head>
+
+<body onload="boom();"></body>
+
+</html>
\ No newline at end of file
--- a/content/base/crashtests/crashtests.list
+++ b/content/base/crashtests/crashtests.list
@@ -90,8 +90,9 @@ load 628599-1.html
 load 637214-1.svg
 load 637214-2.svg
 load 642022-1.html
 load 646184.html
 load 658845-1.svg
 load 667336-1.html
 load 679459.html
 load 679689-1.html
+load 682463.html
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1796,16 +1796,36 @@ public:
                                   nsIDocument* aDocument);
 
   /**
    * Calling this adds support for
    * ontouch* event handler DOM attributes.
    */
   static void InitializeTouchEventTable();
 
+  /**
+   * Test whether the given URI always inherits a security context
+   * from the document it comes from.
+   */
+  static nsresult URIInheritsSecurityContext(nsIURI *aURI, PRBool *aResult);
+
+  /**
+   * Set the given principal as the owner of the given channel, if
+   * needed.  aURI must be the URI of aChannel.  aPrincipal may be
+   * null.  If aSetUpForAboutBlank is true, then about:blank will get
+   * the principal set up on it.
+   *
+   * The return value is whether the principal was set up as the owner
+   * of the channel.
+   */
+  static bool SetUpChannelOwner(nsIPrincipal* aLoadingPrincipal,
+                                nsIChannel* aChannel,
+                                nsIURI* aURI,
+                                PRBool aSetUpForAboutBlank);
+
   static nsresult Btoa(const nsAString& aBinaryData,
                        nsAString& aAsciiBase64String);
 
   static nsresult Atob(const nsAString& aAsciiString,
                        nsAString& aBinaryData);
   
 private:
   static PRBool InitializeEventTable();
@@ -2128,9 +2148,26 @@ public:
     return GetParameter(nsnull, aResult);
   }
 
 private:
   NS_ConvertUTF16toUTF8 mString;
   nsIMIMEHeaderParam*   mService;
 };
 
+class nsDocElementCreatedNotificationRunner : public nsRunnable
+{
+public:
+    nsDocElementCreatedNotificationRunner(nsIDocument* aDoc)
+        : mDoc(aDoc)
+    {
+    }
+
+    NS_IMETHOD Run()
+    {
+        nsContentSink::NotifyDocElementCreated(mDoc);
+        return NS_OK;
+    }
+
+    nsCOMPtr<nsIDocument> mDoc;
+};
+
 #endif /* nsContentUtils_h___ */
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -1356,18 +1356,18 @@ protected:
      NS_IMETHOD because some subclasses implement DOM methods with
      this exact name and signature and then the calling convention
      needs to match.
 
      Note that we include DOCUMENT_ONLY_EVENT events here so that we
      can forward all the document stuff to this implementation.
   */
 #define EVENT(name_, id_, type_, struct_)                         \
-  NS_IMETHOD GetOn##name_(JSContext *cx, jsval *vp);              \
-  NS_IMETHOD SetOn##name_(JSContext *cx, const jsval &v);
+  NS_IMETHOD GetOn##name_(JSContext *cx, JS::Value *vp);          \
+  NS_IMETHOD SetOn##name_(JSContext *cx, const JS::Value &v);
 #define TOUCH_EVENT EVENT
 #define DOCUMENT_ONLY_EVENT EVENT
 #include "nsEventNameList.h"
 #undef DOCUMENT_ONLY_EVENT
 #undef TOUCH_EVENT
 #undef EVENT  
 
   static void Trace(nsINode *tmp, TraceCallback cb, void *closure);
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -4669,16 +4669,17 @@ nsContentUtils::FilterDropEffect(PRUint3
 
 /* static */
 PRBool
 nsContentUtils::URIIsLocalFile(nsIURI *aURI)
 {
   PRBool isFile;
   nsCOMPtr<nsINetUtil> util = do_QueryInterface(sIOService);
 
+  // Important: we do NOT test the entire URI chain here!
   return util && NS_SUCCEEDED(util->ProtocolHasFlags(aURI,
                                 nsIProtocolHandler::URI_IS_LOCAL_FILE,
                                 &isFile)) &&
          isFile;
 }
 
 nsresult
 nsContentUtils::SplitURIAtHash(nsIURI *aURI,
@@ -5716,16 +5717,81 @@ nsContentUtils::IsPatternMatching(nsAStr
 
   res = JS_ExecuteRegExpNoStatics(ctx, re, reinterpret_cast<jschar*>
                                     (aValue.BeginWriting()),
                                   aValue.Length(), &idx, JS_TRUE, &rval);
 
   return res == JS_FALSE || rval != JSVAL_NULL;
 }
 
+// static
+nsresult
+nsContentUtils::URIInheritsSecurityContext(nsIURI *aURI, PRBool *aResult)
+{
+  // Note: about:blank URIs do NOT inherit the security context from the
+  // current document, which is what this function tests for...
+  return NS_URIChainHasFlags(aURI,
+                             nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
+                             aResult);
+}
+
+// static
+bool
+nsContentUtils::SetUpChannelOwner(nsIPrincipal* aLoadingPrincipal,
+                                  nsIChannel* aChannel,
+                                  nsIURI* aURI,
+                                  PRBool aSetUpForAboutBlank)
+{
+  //
+  // Set the owner of the channel, but only for channels that can't
+  // provide their own security context.
+  //
+  // XXX: It seems wrong that the owner is ignored - even if one is
+  //      supplied) unless the URI is javascript or data or about:blank.
+  // XXX: If this is ever changed, check all callers for what owners
+  //      they're passing in.  In particular, see the code and
+  //      comments in nsDocShell::LoadURI where we fall back on
+  //      inheriting the owner if called from chrome.  That would be
+  //      very wrong if this code changed anything but channels that
+  //      can't provide their own security context!
+  //
+  //      (Currently chrome URIs set the owner when they are created!
+  //      So setting a NULL owner would be bad!)
+  //
+  PRBool inherit;
+  // We expect URIInheritsSecurityContext to return success for an
+  // about:blank URI, so don't call NS_IsAboutBlank() if this call fails.
+  // This condition needs to match the one in nsDocShell::InternalLoad where
+  // we're checking for things that will use the owner.
+  if (NS_SUCCEEDED(URIInheritsSecurityContext(aURI, &inherit)) &&
+      (inherit || (aSetUpForAboutBlank && NS_IsAboutBlank(aURI)))) {
+    aChannel->SetOwner(aLoadingPrincipal);
+    return true;
+  }
+
+  //
+  // file: uri special-casing
+  //
+  // If this is a file: load opened from another file: then it may need
+  // to inherit the owner from the referrer so they can script each other.
+  // If we don't set the owner explicitly then each file: gets an owner
+  // based on its own codebase later.
+  //
+  if (URIIsLocalFile(aURI) && aLoadingPrincipal &&
+      NS_SUCCEEDED(aLoadingPrincipal->CheckMayLoad(aURI, PR_FALSE)) &&
+      // One more check here.  CheckMayLoad will always return true for the
+      // system principal, but we do NOT want to inherit in that case.
+      !IsSystemPrincipal(aLoadingPrincipal)) {
+    aChannel->SetOwner(aLoadingPrincipal);
+    return true;
+  }
+
+  return false;
+}
+
 PRBool
 nsContentUtils::IsFullScreenApiEnabled()
 {
   return sIsFullScreenApiEnabled;
 }
 
 PRBool nsContentUtils::IsRequestFullScreenAllowed()
 {
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -645,16 +645,17 @@ GK_ATOM(onblur, "onblur")
 GK_ATOM(onbroadcast, "onbroadcast")
 GK_ATOM(onchange, "onchange")
 GK_ATOM(onclick, "onclick")
 GK_ATOM(onclose, "onclose")
 GK_ATOM(oncommand, "oncommand")
 GK_ATOM(oncommandupdate, "oncommandupdate")
 GK_ATOM(oncompositionend, "oncompositionend")
 GK_ATOM(oncompositionstart, "oncompositionstart")
+GK_ATOM(oncompositionupdate, "oncompositionupdate")
 GK_ATOM(oncontextmenu, "oncontextmenu")
 GK_ATOM(oncopy, "oncopy")
 GK_ATOM(oncut, "oncut")
 GK_ATOM(ondblclick, "ondblclick")
 GK_ATOM(onDOMActivate, "onDOMActivate")
 GK_ATOM(onDOMAttrModified, "onDOMAttrModified")
 GK_ATOM(onDOMCharacterDataModified, "onDOMCharacterDataModified")
 GK_ATOM(onDOMFocusIn, "onDOMFocusIn")
@@ -1896,16 +1897,17 @@ GK_ATOM(_moz_mac_lion_theme, "-moz-mac-l
 GK_ATOM(_moz_windows_compositor, "-moz-windows-compositor")
 GK_ATOM(_moz_windows_classic, "-moz-windows-classic")
 GK_ATOM(_moz_windows_theme, "-moz-windows-theme")
 GK_ATOM(_moz_touch_enabled, "-moz-touch-enabled")
 GK_ATOM(_moz_maemo_classic, "-moz-maemo-classic")
 GK_ATOM(_moz_menubar_drag, "-moz-menubar-drag")
 GK_ATOM(_moz_device_pixel_ratio, "-moz-device-pixel-ratio")
 GK_ATOM(_moz_device_orientation, "-moz-device-orientation")
+GK_ATOM(_moz_is_resource_document, "-moz-is-resource-document")
 
 #ifdef ACCESSIBILITY
 GK_ATOM(anonid, "anonid")
 GK_ATOM(aria_activedescendant, "aria-activedescendant")
 GK_ATOM(aria_atomic, "aria-atomic")
 GK_ATOM(aria_autocomplete, "aria-autocomplete")
 GK_ATOM(aria_busy, "aria-busy")
 GK_ATOM(aria_checked, "aria-checked")
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -1125,33 +1125,16 @@ nsObjectLoadingContent::LoadObject(const
     return NS_OK;
   }
 
   NS_TryToSetImmutable(uri);
 
   return LoadObject(uri, aNotify, aTypeHint, aForceLoad);
 }
 
-static PRBool
-IsAboutBlank(nsIURI* aURI)
-{
-  // XXXbz this duplicates an nsDocShell function, sadly
-  NS_PRECONDITION(aURI, "Must have URI");
-    
-  // GetSpec can be expensive for some URIs, so check the scheme first.
-  PRBool isAbout = PR_FALSE;
-  if (NS_FAILED(aURI->SchemeIs("about", &isAbout)) || !isAbout) {
-    return PR_FALSE;
-  }
-    
-  nsCAutoString str;
-  aURI->GetSpec(str);
-  return str.EqualsLiteral("about:blank");  
-}
-
 void
 nsObjectLoadingContent::UpdateFallbackState(nsIContent* aContent,
                                             AutoFallback& fallback,
                                             const nsCString& aTypeHint)
 {
   // Notify the UI and update the fallback state
   PluginSupportState state = GetPluginSupportState(aContent, aTypeHint);
   if (state != ePluginOtherState) {
@@ -1455,27 +1438,18 @@ nsObjectLoadingContent::LoadObject(nsIUR
     nsCAutoString typeHint, dummy;
     NS_ParseContentType(aTypeHint, typeHint, dummy);
     if (!typeHint.IsEmpty()) {
       chan->SetContentType(typeHint);
     }
   }
 
   // Set up the channel's principal and such, like nsDocShell::DoURILoad does
-  PRBool inheritPrincipal;
-  rv = NS_URIChainHasFlags(aURI,
-                           nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
-                           &inheritPrincipal);
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (inheritPrincipal || IsAboutBlank(aURI) ||
-      (nsContentUtils::URIIsLocalFile(aURI) &&
-       NS_SUCCEEDED(thisContent->NodePrincipal()->CheckMayLoad(aURI,
-                                                               PR_FALSE)))) {
-    chan->SetOwner(thisContent->NodePrincipal());
-  }
+  nsContentUtils::SetUpChannelOwner(thisContent->NodePrincipal(),
+                                    chan, aURI, PR_TRUE);
 
   nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(chan);
   if (scriptChannel) {
     // Allow execution against our context if the principals match
     scriptChannel->
       SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
   }
 
--- a/content/base/src/nsRange.cpp
+++ b/content/base/src/nsRange.cpp
@@ -266,72 +266,106 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 void
 nsRange::CharacterDataChanged(nsIDocument* aDocument,
                               nsIContent* aContent,
                               CharacterDataChangeInfo* aInfo)
 {
   NS_ASSERTION(mIsPositioned, "shouldn't be notified if not positioned");
 
+  nsINode* newRoot = nsnull;
+  nsINode* newStartNode = nsnull;
+  nsINode* newEndNode = nsnull;
+  PRUint32 newStartOffset = 0;
+  PRUint32 newEndOffset = 0;
+
   // If the changed node contains our start boundary and the change starts
   // before the boundary we'll need to adjust the offset.
   if (aContent == mStartParent &&
       aInfo->mChangeStart < static_cast<PRUint32>(mStartOffset)) {
     if (aInfo->mDetails) {
       // splitText(), aInfo->mDetails->mNextSibling is the new text node
       NS_ASSERTION(aInfo->mDetails->mType ==
                    CharacterDataChangeInfo::Details::eSplit,
                    "only a split can start before the end");
       NS_ASSERTION(static_cast<PRUint32>(mStartOffset) <= aInfo->mChangeEnd,
                    "mStartOffset is beyond the end of this node");
-      mStartOffset = static_cast<PRUint32>(mStartOffset) - aInfo->mChangeStart;
-      mStartParent = aInfo->mDetails->mNextSibling;
+      newStartOffset = static_cast<PRUint32>(mStartOffset) - aInfo->mChangeStart;
+      newStartNode = aInfo->mDetails->mNextSibling;
+      if (NS_UNLIKELY(aContent == mRoot)) {
+        newRoot = IsValidBoundary(newStartNode);
+      }
     } else {
       // If boundary is inside changed text, position it before change
       // else adjust start offset for the change in length.
       mStartOffset = static_cast<PRUint32>(mStartOffset) <= aInfo->mChangeEnd ?
         aInfo->mChangeStart :
         mStartOffset + aInfo->mChangeStart - aInfo->mChangeEnd +
           aInfo->mReplaceLength;
     }
   }
 
-  // Do the same thing for the end boundary.
-  if (aContent == mEndParent && aInfo->mChangeStart < static_cast<PRUint32>(mEndOffset)) {
-    if (aInfo->mDetails) {
+  // Do the same thing for the end boundary, except for splitText of a node
+  // with no parent then only switch to the new node if the start boundary
+  // did so too (otherwise the range would end up with disconnected nodes).
+  if (aContent == mEndParent &&
+      aInfo->mChangeStart < static_cast<PRUint32>(mEndOffset)) {
+    if (aInfo->mDetails && (aContent->GetParent() || newStartNode)) {
       // splitText(), aInfo->mDetails->mNextSibling is the new text node
       NS_ASSERTION(aInfo->mDetails->mType ==
                    CharacterDataChangeInfo::Details::eSplit,
                    "only a split can start before the end");
       NS_ASSERTION(static_cast<PRUint32>(mEndOffset) <= aInfo->mChangeEnd,
                    "mEndOffset is beyond the end of this node");
-      mEndOffset = static_cast<PRUint32>(mEndOffset) - aInfo->mChangeStart;
-      mEndParent = aInfo->mDetails->mNextSibling;
+      newEndOffset = static_cast<PRUint32>(mEndOffset) - aInfo->mChangeStart;
+      newEndNode = aInfo->mDetails->mNextSibling;
     } else {
       mEndOffset = static_cast<PRUint32>(mEndOffset) <= aInfo->mChangeEnd ?
         aInfo->mChangeStart :
         mEndOffset + aInfo->mChangeStart - aInfo->mChangeEnd +
           aInfo->mReplaceLength;
     }
   }
 
   if (aInfo->mDetails &&
       aInfo->mDetails->mType == CharacterDataChangeInfo::Details::eMerge) {
     // normalize(), aInfo->mDetails->mNextSibling is the merged text node
     // that will be removed
     nsIContent* removed = aInfo->mDetails->mNextSibling;
     if (removed == mStartParent) {
-      mStartOffset = static_cast<PRUint32>(mStartOffset) + aInfo->mChangeStart;
-      mStartParent = aContent;
+      newStartOffset = static_cast<PRUint32>(mStartOffset) + aInfo->mChangeStart;
+      newStartNode = aContent;
+      if (NS_UNLIKELY(removed == mRoot)) {
+        newRoot = IsValidBoundary(newStartNode);
+      }
     }
     if (removed == mEndParent) {
-      mEndOffset = static_cast<PRUint32>(mEndOffset) + aInfo->mChangeStart;
-      mEndParent = aContent;
+      newEndOffset = static_cast<PRUint32>(mEndOffset) + aInfo->mChangeStart;
+      newEndNode = aContent;
+      if (NS_UNLIKELY(removed == mRoot)) {
+        newRoot = IsValidBoundary(newEndNode);
+      }
     }
   }
+  if (newStartNode || newEndNode) {
+    if (!newStartNode) {
+      newStartNode = mStartParent;
+      newStartOffset = mStartOffset;
+    }
+    if (!newEndNode) {
+      newEndNode = mEndParent;
+      newEndOffset = mEndOffset;
+    }
+    DoSetRange(newStartNode, newStartOffset, newEndNode, newEndOffset,
+               newRoot ? newRoot : mRoot.get()
+#ifdef DEBUG
+               , !newEndNode->GetParent()
+#endif
+               );
+  }
 }
 
 void
 nsRange::ContentInserted(nsIDocument* aDocument,
                          nsIContent* aContainer,
                          nsIContent* aChild,
                          PRInt32 aIndexInContainer)
 {
@@ -468,22 +502,26 @@ static PRUint32 GetNodeLength(nsINode *a
 // It's important that all setting of the range start/end points 
 // go through this function, which will do all the right voodoo
 // for content notification of range ownership.  
 // Calling DoSetRange with either parent argument null will collapse
 // the range to have both endpoints point to the other node
 void
 nsRange::DoSetRange(nsINode* aStartN, PRInt32 aStartOffset,
                     nsINode* aEndN, PRInt32 aEndOffset,
-                    nsINode* aRoot)
+                    nsINode* aRoot
+#ifdef DEBUG
+                    , bool aNotInsertedYet
+#endif
+                    )
 {
   NS_PRECONDITION((aStartN && aEndN && aRoot) ||
                   (!aStartN && !aEndN && !aRoot),
                   "Set all or none");
-  NS_PRECONDITION(!aRoot ||
+  NS_PRECONDITION(!aRoot || aNotInsertedYet ||
                   (nsContentUtils::ContentIsDescendantOf(aStartN, aRoot) &&
                    nsContentUtils::ContentIsDescendantOf(aEndN, aRoot) &&
                    aRoot == IsValidBoundary(aStartN) &&
                    aRoot == IsValidBoundary(aEndN)),
                   "Wrong root");
   NS_PRECONDITION(!aRoot ||
                   (aStartN->IsNodeOfType(nsINode::eCONTENT) &&
                    aEndN->IsNodeOfType(nsINode::eCONTENT) &&
--- a/content/base/src/nsRange.h
+++ b/content/base/src/nsRange.h
@@ -144,17 +144,23 @@ public:
                                      PRBool *outNodeAfter);
   static nsresult CompareNodeToRange(nsINode* aNode, nsIRange* aRange,
                                      PRBool *outNodeBefore,
                                      PRBool *outNodeAfter);
 
 protected:
   void DoSetRange(nsINode* aStartN, PRInt32 aStartOffset,
                   nsINode* aEndN, PRInt32 aEndOffset,
-                  nsINode* aRoot);
+                  nsINode* aRoot
+#ifdef DEBUG
+                  // CharacterDataChanged use this to disable an assertion since
+                  // the new text node of a splitText hasn't been inserted yet.
+                  , bool aNotInsertedYet = false
+#endif
+                  );
 };
 
 // Make a new nsIDOMRange object
 nsresult NS_NewRange(nsIDOMRange** aInstancePtrResult);
 
 // Make a new nsIRangeUtils object
 nsresult NS_NewRangeUtils(nsIRangeUtils** aInstancePtrResult);
 
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -413,28 +413,30 @@ NS_IMPL_ADDREF_INHERITED(nsXMLHttpReques
 NS_IMPL_RELEASE_INHERITED(nsXMLHttpRequestUpload, nsXHREventTarget)
 
 /////////////////////////////////////////////
 //
 //
 /////////////////////////////////////////////
 
 nsXMLHttpRequest::nsXMLHttpRequest()
-  : mResponseType(XML_HTTP_RESPONSE_TYPE_DEFAULT),
+  : mResponseBodyDecodedPos(0),
+    mResponseType(XML_HTTP_RESPONSE_TYPE_DEFAULT),
     mRequestObserver(nsnull), mState(XML_HTTP_REQUEST_UNSENT),
     mUploadTransferred(0), mUploadTotal(0), mUploadComplete(PR_TRUE),
+    mProgressSinceLastProgressEvent(PR_FALSE),
     mUploadProgress(0), mUploadProgressMax(0),
     mErrorLoad(PR_FALSE), mTimerIsActive(PR_FALSE),
     mProgressEventWasDelayed(PR_FALSE),
     mLoadLengthComputable(PR_FALSE), mLoadTotal(0),
     mFirstStartRequestSeen(PR_FALSE),
-    mResultArrayBuffer(nsnull),
-    mResultJSON(JSVAL_VOID)
+    mInLoadProgressEvent(PR_FALSE),
+    mResultJSON(JSVAL_VOID),
+    mResultArrayBuffer(nsnull)
 {
-  mResponseBodyUnicode.SetIsVoid(PR_TRUE);
   nsLayoutStatics::AddRef();
 }
 
 nsXMLHttpRequest::~nsXMLHttpRequest()
 {
   if (mListenerManager) {
     mListenerManager->Disconnect();
   }
@@ -550,16 +552,29 @@ nsXMLHttpRequest::Initialize(nsISupports
   nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aOwner);
   NS_ENSURE_STATE(sgo);
   mScriptContext = sgo->GetContext();
   NS_ENSURE_STATE(mScriptContext);
   return NS_OK; 
 }
 
 void
+nsXMLHttpRequest::ResetResponse()
+{
+  mResponseXML = nsnull;
+  mResponseBody.Truncate();
+  mResponseText.Truncate();
+  mResponseBlob = nsnull;
+  mResultArrayBuffer = nsnull;
+  mResultJSON = JSVAL_VOID;
+  mLoadTransferred = 0;
+  mResponseBodyDecodedPos = 0;
+}
+
+void
 nsXMLHttpRequest::SetRequestObserver(nsIRequestObserver* aObserver)
 {
   mRequestObserver = aObserver;
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLHttpRequest)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLHttpRequest,
@@ -697,186 +712,190 @@ nsXMLHttpRequest::GetResponseXML(nsIDOMD
   return NS_OK;
 }
 
 /*
  * This piece copied from nsXMLDocument, we try to get the charset
  * from HTTP headers.
  */
 nsresult
-nsXMLHttpRequest::DetectCharset(nsACString& aCharset)
+nsXMLHttpRequest::DetectCharset()
 {
-  aCharset.Truncate();
-  nsresult rv;
-  nsCAutoString charsetVal;
-  nsCOMPtr<nsIChannel> channel(do_QueryInterface(mReadRequest));
+  mResponseCharset.Truncate();
+  mDecoder = nsnull;
+
+  if (mResponseType != XML_HTTP_RESPONSE_TYPE_DEFAULT &&
+      mResponseType != XML_HTTP_RESPONSE_TYPE_TEXT &&
+      mResponseType != XML_HTTP_RESPONSE_TYPE_JSON &&
+      mResponseType != XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT) {
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIChannel> channel = do_QueryInterface(mReadRequest);
   if (!channel) {
     channel = mChannel;
-    if (!channel) {
-      // There will be no mChannel when we got a necko error in
-      // OnStopRequest or if we were never sent.
-      return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  nsCAutoString charsetVal;
+  nsresult rv = channel ? channel->GetContentCharset(charsetVal) :
+                NS_ERROR_FAILURE;
+  if (NS_SUCCEEDED(rv)) {
+    nsCOMPtr<nsICharsetAlias> calias =
+      do_GetService(NS_CHARSETALIAS_CONTRACTID, &rv);
+    if (NS_SUCCEEDED(rv) && calias) {
+      rv = calias->GetPreferred(charsetVal, mResponseCharset);
     }
   }
 
-  rv = channel->GetContentCharset(charsetVal);
-  if (NS_SUCCEEDED(rv)) {
-    nsCOMPtr<nsICharsetAlias> calias(do_GetService(NS_CHARSETALIAS_CONTRACTID,&rv));
-    if(NS_SUCCEEDED(rv) && calias) {
-      rv = calias->GetPreferred(charsetVal, aCharset);
-    }
+  if (NS_FAILED(rv) || mResponseCharset.IsEmpty()) {
+    // MS documentation states UTF-8 is default for responseText
+    mResponseCharset.AssignLiteral("UTF-8");
   }
-  return rv;
+
+  nsCOMPtr<nsICharsetConverterManager> ccm =
+    do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return ccm->GetUnicodeDecoderRaw(mResponseCharset.get(),
+                                   getter_AddRefs(mDecoder));
 }
 
 nsresult
-nsXMLHttpRequest::ConvertBodyToText(nsAString& aOutBuffer)
+nsXMLHttpRequest::AppendToResponseText(const char * aSrcBuffer,
+                                       PRUint32 aSrcBufferLen)
 {
+  NS_ENSURE_STATE(mDecoder);
+
+  PRInt32 destBufferLen;
+  nsresult rv = mDecoder->GetMaxLength(aSrcBuffer, aSrcBufferLen,
+                                       &destBufferLen);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!mResponseText.SetCapacity(mResponseText.Length() + destBufferLen)) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  PRUnichar* destBuffer = mResponseText.BeginWriting() + mResponseText.Length();
+
+  PRInt32 totalChars = mResponseText.Length();
+
   // This code here is basically a copy of a similar thing in
   // nsScanner::Append(const char* aBuffer, PRUint32 aLen).
   // If we get illegal characters in the input we replace
   // them and don't just fail.
-  if (!mResponseBodyUnicode.IsVoid()) {
-    aOutBuffer = mResponseBodyUnicode;
-    return NS_OK;
-  }
-  
-  PRInt32 dataLen = mResponseBody.Length();
-  if (!dataLen) {
-    mResponseBodyUnicode.SetIsVoid(PR_FALSE);
-    return NS_OK;
-  }
-
-  nsresult rv = NS_OK;
-
-  nsCAutoString dataCharset;
-  nsCOMPtr<nsIDocument> document(do_QueryInterface(mResponseXML));
-  if (document) {
-    dataCharset = document->GetDocumentCharacterSet();
-  } else {
-    if (NS_FAILED(DetectCharset(dataCharset)) || dataCharset.IsEmpty()) {
-      // MS documentation states UTF-8 is default for responseText
-      dataCharset.AssignLiteral("UTF-8");
-    }
-  }
-
-  // XXXbz is the charset ever "ASCII" as opposed to "us-ascii"?
-  if (dataCharset.EqualsLiteral("ASCII")) {
-    CopyASCIItoUTF16(mResponseBody, mResponseBodyUnicode);
-    aOutBuffer = mResponseBodyUnicode;
-    return NS_OK;
-  }
-
-  // can't fast-path UTF-8 using CopyUTF8toUTF16, since above we assumed UTF-8
-  // by default and CopyUTF8toUTF16 will stop if it encounters bytes that aren't
-  // valid UTF-8.  So we have to do the whole unicode decoder thing.
-
-  nsCOMPtr<nsICharsetConverterManager> ccm =
-    do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
-  if (NS_FAILED(rv))
-    return rv;
-
-  nsCOMPtr<nsIUnicodeDecoder> decoder;
-  rv = ccm->GetUnicodeDecoderRaw(dataCharset.get(),
-                                 getter_AddRefs(decoder));
-  if (NS_FAILED(rv))
-    return rv;
-
-  const char * inBuffer = mResponseBody.get();
-  PRInt32 outBufferLength;
-  rv = decoder->GetMaxLength(inBuffer, dataLen, &outBufferLength);
-  if (NS_FAILED(rv))
-    return rv;
-
-  nsStringBuffer* buf =
-    nsStringBuffer::Alloc((outBufferLength + 1) * sizeof(PRUnichar));
-  if (!buf) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  PRUnichar* outBuffer = static_cast<PRUnichar*>(buf->Data());
-
-  PRInt32 totalChars = 0,
-          outBufferIndex = 0,
-          outLen = outBufferLength;
-
   do {
-    PRInt32 inBufferLength = dataLen;
-    rv = decoder->Convert(inBuffer,
-                          &inBufferLength,
-                          &outBuffer[outBufferIndex],
-                          &outLen);
-    totalChars += outLen;
+    PRInt32 srclen = (PRInt32)aSrcBufferLen;
+    PRInt32 destlen = (PRInt32)destBufferLen;
+    rv = mDecoder->Convert(aSrcBuffer,
+                           &srclen,
+                           destBuffer,
+                           &destlen);
     if (NS_FAILED(rv)) {
       // We consume one byte, replace it with U+FFFD
       // and try the conversion again.
-      outBuffer[outBufferIndex + outLen++] = (PRUnichar)0xFFFD;
-      outBufferIndex += outLen;
-      outLen = outBufferLength - (++totalChars);
-
-      decoder->Reset();
-
-      if((inBufferLength + 1) > dataLen) {
-        inBufferLength = dataLen;
-      } else {
-        inBufferLength++;
+
+      destBuffer[destlen] = (PRUnichar)0xFFFD; // add replacement character
+      destlen++; // skip written replacement character
+      destBuffer += destlen;
+      destBufferLen -= destlen;
+
+      if (srclen < (PRInt32)aSrcBufferLen) {
+        srclen++; // Consume the invalid character
       }
-
-      inBuffer = &inBuffer[inBufferLength];
-      dataLen -= inBufferLength;
+      aSrcBuffer += srclen;
+      aSrcBufferLen -= srclen;
+
+      mDecoder->Reset();
     }
-  } while ( NS_FAILED(rv) && (dataLen > 0) );
-
-  // Use the string buffer if it is small, or doesn't contain
-  // too much extra data.
-  if (outBufferLength < 127 ||
-      (outBufferLength * 0.9) < totalChars) {
-    outBuffer[totalChars] = PRUnichar(0);
-    // Move ownership to mResponseBodyUnicode.
-    buf->ToString(totalChars, mResponseBodyUnicode, PR_TRUE);
-  } else {
-    mResponseBodyUnicode.Assign(outBuffer, totalChars);
-    buf->Release();
-  }
-  aOutBuffer = mResponseBodyUnicode;
+
+    totalChars += destlen;
+
+  } while (NS_FAILED(rv) && aSrcBufferLen > 0);
+
+  mResponseText.SetLength(totalChars);
+
   return NS_OK;
 }
 
 /* readonly attribute AString responseText; */
 NS_IMETHODIMP nsXMLHttpRequest::GetResponseText(nsAString& aResponseText)
 {
-  nsresult rv = NS_OK;
-
   aResponseText.Truncate();
 
   if (mResponseType != XML_HTTP_RESPONSE_TYPE_DEFAULT &&
-      mResponseType != XML_HTTP_RESPONSE_TYPE_TEXT) {
+      mResponseType != XML_HTTP_RESPONSE_TYPE_TEXT &&
+      mResponseType != XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT) {
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
-  if (mState & (XML_HTTP_REQUEST_DONE |
-                XML_HTTP_REQUEST_LOADING)) {
-    rv = ConvertBodyToText(aResponseText);
+  if (mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT &&
+      !mInLoadProgressEvent) {
+    aResponseText.SetIsVoid(PR_TRUE);
+    return NS_OK;
+  }
+
+  if (!(mState & (XML_HTTP_REQUEST_DONE | XML_HTTP_REQUEST_LOADING))) {
+    return NS_OK;
+  }
+
+  // We only decode text lazily if we're also parsing to a doc.
+  // Also, if we've decoded all current data already, then no need to decode
+  // more.
+  if (!mResponseXML ||
+      mResponseBodyDecodedPos == mResponseBody.Length()) {
+    aResponseText = mResponseText;
+    return NS_OK;
   }
 
-  return rv;
+  nsresult rv;
+
+  nsCOMPtr<nsIDocument> document = do_QueryInterface(mResponseXML);
+  if (mResponseCharset != document->GetDocumentCharacterSet()) {
+    mResponseCharset == document->GetDocumentCharacterSet();
+    mResponseText.Truncate();
+    mResponseBodyDecodedPos = 0;
+
+    nsCOMPtr<nsICharsetConverterManager> ccm =
+      do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = ccm->GetUnicodeDecoderRaw(mResponseCharset.get(),
+                                   getter_AddRefs(mDecoder));
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  NS_ASSERTION(mResponseBodyDecodedPos < mResponseBody.Length(),
+               "Unexpected mResponseBodyDecodedPos");
+  rv = AppendToResponseText(mResponseBody.get() + mResponseBodyDecodedPos,
+                            mResponseBody.Length() - mResponseBodyDecodedPos);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  mResponseBodyDecodedPos = mResponseBody.Length();
+  
+  if (mState & XML_HTTP_REQUEST_DONE) {
+    // Free memory buffer which we no longer need
+    mResponseBody.Truncate();
+    mResponseBodyDecodedPos = 0;
+  }
+
+  aResponseText = mResponseText;
+
+  return NS_OK;
 }
 
 nsresult
 nsXMLHttpRequest::CreateResponseParsedJSON(JSContext* aCx)
 {
   if (!aCx) {
     return NS_ERROR_FAILURE;
   }
 
-  nsString bodyString;
-  ConvertBodyToText(bodyString);
   if (!JS_ParseJSON(aCx,
-                    (jschar*)PromiseFlatString(bodyString).get(),
-                    bodyString.Length(), &mResultJSON)) {
+                    (jschar*)mResponseText.get(),
+                    mResponseText.Length(), &mResultJSON)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 nsresult
 nsXMLHttpRequest::CreateResponseArrayBuffer(JSContext *aCx)
@@ -918,16 +937,22 @@ NS_IMETHODIMP nsXMLHttpRequest::GetRespo
     aResponseType.AssignLiteral("document");
     break;
   case XML_HTTP_RESPONSE_TYPE_TEXT:
     aResponseType.AssignLiteral("text");
     break;
   case XML_HTTP_RESPONSE_TYPE_JSON:
     aResponseType.AssignLiteral("moz-json");
     break;
+  case XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT:
+    aResponseType.AssignLiteral("moz-chunked-text");
+    break;
+  case XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER:
+    aResponseType.AssignLiteral("moz-chunked-arraybuffer");
+    break;
   default:
     NS_ERROR("Should not happen");
   }
 
   return NS_OK;
 }
 
 /* attribute AString responseType; */
@@ -947,16 +972,26 @@ NS_IMETHODIMP nsXMLHttpRequest::SetRespo
   } else if (aResponseType.EqualsLiteral("blob")) {
     mResponseType = XML_HTTP_RESPONSE_TYPE_BLOB;
   } else if (aResponseType.EqualsLiteral("document")) {
     mResponseType = XML_HTTP_RESPONSE_TYPE_DOCUMENT;
   } else if (aResponseType.EqualsLiteral("text")) {
     mResponseType = XML_HTTP_RESPONSE_TYPE_TEXT;
   } else if (aResponseType.EqualsLiteral("moz-json")) {
     mResponseType = XML_HTTP_RESPONSE_TYPE_JSON;
+  } else if (aResponseType.EqualsLiteral("moz-chunked-text")) {
+    if (!(mState & XML_HTTP_REQUEST_ASYNC)) {
+      return NS_ERROR_DOM_INVALID_STATE_ERR;
+    }
+    mResponseType = XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT;
+  } else if (aResponseType.EqualsLiteral("moz-chunked-arraybuffer")) {
+    if (!(mState & XML_HTTP_REQUEST_ASYNC)) {
+      return NS_ERROR_DOM_INVALID_STATE_ERR;
+    }
+    mResponseType = XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER;
   }
   // If the given value is not the empty string, "arraybuffer",
   // "blob", "document", or "text" terminate these steps.
 
   // If the state is OPENED, SetCacheAsFile would have no effect here
   // because the channel hasn't initialized the cache entry yet.
   // SetCacheAsFile will be called from OnStartRequest.
   // If the state is HEADERS_RECEIVED, however, we need to call
@@ -974,30 +1009,39 @@ NS_IMETHODIMP nsXMLHttpRequest::SetRespo
 /* readonly attribute jsval response; */
 NS_IMETHODIMP nsXMLHttpRequest::GetResponse(JSContext *aCx, jsval *aResult)
 {
   nsresult rv = NS_OK;
 
   switch (mResponseType) {
   case XML_HTTP_RESPONSE_TYPE_DEFAULT:
   case XML_HTTP_RESPONSE_TYPE_TEXT:
+  case XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT:
     {
       nsString str;
       rv = GetResponseText(str);
       if (NS_FAILED(rv)) return rv;
-      nsStringBuffer* buf;
-      *aResult = XPCStringConvert::ReadableToJSVal(aCx, str, &buf);
-      if (buf) {
-        str.ForgetSharedBuffer();
+      if (str.IsVoid()) {
+        *aResult = JSVAL_NULL;
+      } else {
+        nsStringBuffer* buf;
+        *aResult = XPCStringConvert::ReadableToJSVal(aCx, str, &buf);
+        if (buf) {
+          str.ForgetSharedBuffer();
+        }
       }
     }
     break;
 
   case XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER:
-    if (mState & XML_HTTP_REQUEST_DONE) {
+  case XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER:
+    if ((mResponseType == XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER &&
+         mState & XML_HTTP_REQUEST_DONE) ||
+        (mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER &&
+         mInLoadProgressEvent)) {
       if (!mResultArrayBuffer) {
          rv = CreateResponseArrayBuffer(aCx);
          NS_ENSURE_SUCCESS(rv, rv);
       }
       *aResult = OBJECT_TO_JSVAL(mResultArrayBuffer);
     } else {
       *aResult = JSVAL_NULL;
     }
@@ -1024,18 +1068,17 @@ NS_IMETHODIMP nsXMLHttpRequest::GetRespo
     break;
 
   case XML_HTTP_RESPONSE_TYPE_JSON:
     if (mState & XML_HTTP_REQUEST_DONE) {
       if (mResultJSON == JSVAL_VOID) {
         rv = CreateResponseParsedJSON(aCx);
         NS_ENSURE_SUCCESS(rv, rv);
 
-        mResponseBody.Truncate();
-        mResponseBodyUnicode.SetIsVoid(PR_TRUE);
+        mResponseText.Truncate();
       }
       *aResult = mResultJSON;
     } else {
       *aResult = JSVAL_NULL;
     }
     break;
 
   default:
@@ -1120,24 +1163,19 @@ nsXMLHttpRequest::Abort()
     mReadRequest->Cancel(NS_BINDING_ABORTED);
   }
   if (mChannel) {
     mChannel->Cancel(NS_BINDING_ABORTED);
   }
   if (mCORSPreflightChannel) {
     mCORSPreflightChannel->Cancel(NS_BINDING_ABORTED);
   }
-  mResponseXML = nsnull;
   PRUint32 responseLength = mResponseBody.Length();
-  mResponseBody.Truncate();
-  mResponseBodyUnicode.SetIsVoid(PR_TRUE);
-  mResponseBlob = nsnull;
+  ResetResponse();
   mState |= XML_HTTP_REQUEST_ABORTED;
-  mResultArrayBuffer = nsnull;
-  mResultJSON = JSVAL_VOID;
   
   if (!(mState & (XML_HTTP_REQUEST_UNSENT |
                   XML_HTTP_REQUEST_OPENED |
                   XML_HTTP_REQUEST_DONE))) {
     ChangeState(XML_HTTP_REQUEST_DONE, PR_TRUE);
   }
 
   if (!(mState & XML_HTTP_REQUEST_SYNCLOOPING)) {
@@ -1322,17 +1360,19 @@ void
 nsXMLHttpRequest::DispatchProgressEvent(nsDOMEventTargetHelper* aTarget,
                                         const nsAString& aType,
                                         PRBool aUseLSEventWrapper,
                                         PRBool aLengthComputable,
                                         PRUint64 aLoaded, PRUint64 aTotal,
                                         PRUint64 aPosition, PRUint64 aTotalSize)
 {
   NS_ASSERTION(aTarget, "null target");
-  if (aType.IsEmpty() ||
+  NS_ASSERTION(!aType.IsEmpty(), "missing event type");
+
+  if (NS_FAILED(CheckInnerWindowCorrectness()) ||
       (!AllowUploadProgress() &&
        (aTarget == mUpload || aType.EqualsLiteral(UPLOADPROGRESS_STR)))) {
     return;
   }
 
   PRBool dispatchLoadend = aType.EqualsLiteral(LOAD_STR) ||
                            aType.EqualsLiteral(ERROR_STR) ||
                            aType.EqualsLiteral(ABORT_STR);
@@ -1586,29 +1626,38 @@ nsXMLHttpRequest::StreamReaderFunc(nsIIn
   nsXMLHttpRequest* xmlHttpRequest = static_cast<nsXMLHttpRequest*>(closure);
   if (!xmlHttpRequest || !writeCount) {
     NS_WARNING("XMLHttpRequest cannot read from stream: no closure or writeCount");
     return NS_ERROR_FAILURE;
   }
 
   if (xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB &&
       xmlHttpRequest->mResponseBlob) {
-    xmlHttpRequest->ChangeState(XML_HTTP_REQUEST_LOADING);
     *writeCount = count;
     return NS_OK;
   }
 
-  if (xmlHttpRequest->mResponseType != XML_HTTP_RESPONSE_TYPE_DOCUMENT) {
+  if ((xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_DEFAULT &&
+       xmlHttpRequest->mResponseXML) ||
+      xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER ||
+      xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB ||
+      xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER) {
     // Copy for our own use
     PRUint32 previousLength = xmlHttpRequest->mResponseBody.Length();
     xmlHttpRequest->mResponseBody.Append(fromRawSegment,count);
     if (count > 0 && xmlHttpRequest->mResponseBody.Length() == previousLength) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
-    xmlHttpRequest->mResponseBodyUnicode.SetIsVoid(PR_TRUE);
+  } else if (xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_DEFAULT ||
+             xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_TEXT ||
+             xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_JSON ||
+             xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT) {
+    NS_ASSERTION(!xmlHttpRequest->mResponseXML,
+                 "We shouldn't be parsing a doc here");
+    xmlHttpRequest->AppendToResponseText(fromRawSegment, count);
   }
 
   nsresult rv = NS_OK;
 
   if (xmlHttpRequest->mState & XML_HTTP_REQUEST_PARSEBODY) {
     // Give the same data to the parser.
 
     // We need to wrap the data in a new lightweight stream and pass that
@@ -1627,18 +1676,16 @@ nsXMLHttpRequest::StreamReaderFunc(nsIIn
       // No use to continue parsing if we failed here, but we
       // should still finish reading the stream
       if (NS_FAILED(parsingResult)) {
         xmlHttpRequest->mState &= ~XML_HTTP_REQUEST_PARSEBODY;
       }
     }
   }
 
-  xmlHttpRequest->ChangeState(XML_HTTP_REQUEST_LOADING);
-
   if (NS_SUCCEEDED(rv)) {
     *writeCount = count;
   } else {
     *writeCount = 0;
   }
 
   return rv;
 }
@@ -1661,34 +1708,48 @@ void nsXMLHttpRequest::CreateResponseBlo
     nsCOMPtr<nsISupports> cacheToken;
     if (cc) {
       cc->GetCacheToken(getter_AddRefs(cacheToken));
     }
 
     mResponseBlob =
       new nsDOMFileFile(file, NS_ConvertASCIItoUTF16(contentType), cacheToken);
     mResponseBody.Truncate();
-    mResponseBodyUnicode.SetIsVoid(PR_TRUE);
   }
 }
 
-/* void onDataAvailable (in nsIRequest request, in nsISupports ctxt, in nsIInputStream inStr, in unsigned long sourceOffset, in unsigned long count); */
 NS_IMETHODIMP
-nsXMLHttpRequest::OnDataAvailable(nsIRequest *request, nsISupports *ctxt, nsIInputStream *inStr, PRUint32 sourceOffset, PRUint32 count)
+nsXMLHttpRequest::OnDataAvailable(nsIRequest *request,
+                                  nsISupports *ctxt,
+                                  nsIInputStream *inStr,
+                                  PRUint32 sourceOffset,
+                                  PRUint32 count)
 {
   NS_ENSURE_ARG_POINTER(inStr);
 
   NS_ABORT_IF_FALSE(mContext.get() == ctxt,"start context different from OnDataAvailable context");
 
   if (mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB && !mResponseBlob) {
     CreateResponseBlob(request);
   }
 
+  mProgressSinceLastProgressEvent = PR_TRUE;
+
   PRUint32 totalRead;
-  return inStr->ReadSegments(nsXMLHttpRequest::StreamReaderFunc, (void*)this, count, &totalRead);
+  nsresult rv = inStr->ReadSegments(nsXMLHttpRequest::StreamReaderFunc,
+                                    (void*)this, count, &totalRead);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  mLoadTransferred += totalRead;
+
+  ChangeState(XML_HTTP_REQUEST_LOADING);
+  
+  MaybeDispatchProgressEvents(PR_FALSE);
+
+  return NS_OK;
 }
 
 PRBool
 IsSameOrBaseChannel(nsIRequest* aPossibleBase, nsIChannel* aChannel)
 {
   nsCOMPtr<nsIMultiPartChannel> mpChannel = do_QueryInterface(aPossibleBase);
   if (mpChannel) {
     nsCOMPtr<nsIChannel> baseChannel;
@@ -1738,61 +1799,64 @@ nsXMLHttpRequest::OnStartRequest(nsIRequ
     documentPrincipal = do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
     NS_ENSURE_SUCCESS(rv, rv);
   } else {
     documentPrincipal = mPrincipal;
   }
 
   channel->SetOwner(documentPrincipal);
 
+  nsresult status;
+  request->GetStatus(&status);
+  mErrorLoad = mErrorLoad || NS_FAILED(status);
+
+  if (mUpload && !mUploadComplete && !mErrorLoad &&
+      (mState & XML_HTTP_REQUEST_ASYNC)) {
+    if (mTimerIsActive) {
+      mTimerIsActive = PR_FALSE;
+      mProgressNotifier->Cancel();
+    }
+    MaybeDispatchProgressEvents(PR_TRUE);
+    mUploadComplete = PR_TRUE;
+    DispatchProgressEvent(mUpload, NS_LITERAL_STRING(LOAD_STR),
+                          PR_TRUE, mUploadTotal, mUploadTotal);
+  }
+
   mReadRequest = request;
   mContext = ctxt;
   mState |= XML_HTTP_REQUEST_PARSEBODY;
   mState &= ~XML_HTTP_REQUEST_MPART_HEADERS;
   ChangeState(XML_HTTP_REQUEST_HEADERS_RECEIVED);
 
   if (mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB) {
     nsCOMPtr<nsICachingChannel> cc(do_QueryInterface(mChannel));
     if (cc) {
       cc->SetCacheAsFile(PR_TRUE);
     }
   }
 
-  nsresult status;
-  request->GetStatus(&status);
-  mErrorLoad = mErrorLoad || NS_FAILED(status);
-
-  if (mUpload && !mUploadComplete && !mErrorLoad &&
-      (mState & XML_HTTP_REQUEST_ASYNC)) {
-    mUploadComplete = PR_TRUE;
-    DispatchProgressEvent(mUpload, NS_LITERAL_STRING(LOAD_STR),
-                          PR_TRUE, mUploadTotal, mUploadTotal);
+  ResetResponse();
+
+  if (!mOverrideMimeType.IsEmpty()) {
+    channel->SetContentType(mOverrideMimeType);
   }
 
-  // Reset responseBody
-  mResponseBody.Truncate();
-  mResponseBodyUnicode.SetIsVoid(PR_TRUE);
-  mResponseBlob = nsnull;
-  mResultArrayBuffer = nsnull;
+  DetectCharset();
 
   // Set up responseXML
   PRBool parseBody = mResponseType == XML_HTTP_RESPONSE_TYPE_DEFAULT ||
                      mResponseType == XML_HTTP_RESPONSE_TYPE_DOCUMENT;
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
   if (parseBody && httpChannel) {
     nsCAutoString method;
     httpChannel->GetRequestMethod(method);
     parseBody = !method.EqualsLiteral("HEAD");
   }
 
   if (parseBody && NS_SUCCEEDED(status)) {
-    if (!mOverrideMimeType.IsEmpty()) {
-      channel->SetContentType(mOverrideMimeType);
-    }
-
     // We can gain a huge performance win by not even trying to
     // parse non-XML data. This also protects us from the situation
     // where we have an XML document and sink, but HTML (or other)
     // parser, which can produce unreliable results.
     nsCAutoString type;
     channel->GetContentType(type);
 
     if (type.Find("xml") == kNotFound) {
@@ -1913,16 +1977,20 @@ nsXMLHttpRequest::OnStopRequest(nsIReque
     NS_ABORT_IF_FALSE(parser, "stream listener was expected to be a parser");
     mXMLParserStreamListener->OnStopRequest(request, ctxt, status);
   }
 
   mXMLParserStreamListener = nsnull;
   mReadRequest = nsnull;
   mContext = nsnull;
 
+  // If we're received data since the last progress event, make sure to fire
+  // an event for it.
+  MaybeDispatchProgressEvents(PR_TRUE);
+
   nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
   NS_ENSURE_TRUE(channel, NS_ERROR_UNEXPECTED);
 
   if (NS_SUCCEEDED(status) && mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB) {
     if (!mResponseBlob) {
       CreateResponseBlob(request);
     }
     if (!mResponseBlob) {
@@ -1937,18 +2005,17 @@ nsXMLHttpRequest::OnStopRequest(nsIReque
       if (blobData) {
         memcpy(blobData, mResponseBody.BeginReading(), blobLen);
 
         mResponseBlob =
           new nsDOMMemoryFile(blobData, blobLen,
                               NS_ConvertASCIItoUTF16(contentType));
         mResponseBody.Truncate();
       }
-      NS_ASSERTION(mResponseBodyUnicode.IsVoid(),
-                   "mResponseBodyUnicode should be empty");
+      NS_ASSERTION(mResponseText.IsEmpty(), "mResponseText should be empty");
     }
   }
 
   channel->SetNotificationCallbacks(nsnull);
   mNotificationCallbacks = nsnull;
   mChannelEventSink = nsnull;
   mProgressEventSink = nsnull;
 
@@ -1982,24 +2049,23 @@ nsXMLHttpRequest::OnStopRequest(nsIReque
     mResponseXML->GetDocumentElement(getter_AddRefs(root));
     if (!root) {
       mResponseXML = nsnull;
     }
   }
 
   ChangeState(XML_HTTP_REQUEST_DONE, PR_TRUE);
 
-  PRUint32 responseLength = mResponseBody.Length();
   NS_NAMED_LITERAL_STRING(errorStr, ERROR_STR);
   NS_NAMED_LITERAL_STRING(loadStr, LOAD_STR);
   DispatchProgressEvent(this,
                         mErrorLoad ? errorStr : loadStr,
                         !mErrorLoad,
-                        responseLength,
-                        mErrorLoad ? 0 : responseLength);
+                        mLoadTransferred,
+                        mErrorLoad ? 0 : mLoadTransferred);
   if (mErrorLoad && mUpload && !mUploadComplete) {
     DispatchProgressEvent(mUpload, errorStr, PR_TRUE,
                           mUploadTransferred, mUploadTotal);
   }
 
   if (mErrorLoad) {
     // By nulling out channel here we make it so that Send() can test
     // for that and throw. Also calling the various status
@@ -2387,23 +2453,17 @@ nsXMLHttpRequest::Send(nsIVariant *aBody
       if (!contentType.LowerCaseEqualsLiteral("text/plain") &&
           !contentType.LowerCaseEqualsLiteral("application/x-www-form-urlencoded") &&
           !contentType.LowerCaseEqualsLiteral("multipart/form-data")) {
         mCORSUnsafeHeaders.AppendElement(NS_LITERAL_CSTRING("Content-Type"));
       }
     }
   }
 
-  // Reset responseBody
-  mResponseBody.Truncate();
-  mResponseBodyUnicode.SetIsVoid(PR_TRUE);
-  mResponseBlob = nsnull;
-
-  // Reset responseXML
-  mResponseXML = nsnull;
+  ResetResponse();
 
   rv = CheckChannelForCrossSiteRequest(mChannel);
   NS_ENSURE_SUCCESS(rv, rv);
 
   PRBool withCredentials = !!(mState & XML_HTTP_REQUEST_AC_WITH_CREDENTIALS);
 
   // Hook us up to listen to redirects and the like
   mChannel->GetNotificationCallbacks(getter_AddRefs(mNotificationCallbacks));
@@ -2919,67 +2979,111 @@ nsXMLHttpRequest::OnRedirectVerifyCallba
   mRedirectCallback->OnRedirectVerifyCallback(result);
   mRedirectCallback = nsnull;
 }
 
 /////////////////////////////////////////////////////
 // nsIProgressEventSink methods:
 //
 
+void
+nsXMLHttpRequest::MaybeDispatchProgressEvents(PRBool aFinalProgress)
+{
+  if (aFinalProgress && mTimerIsActive) {
+    mTimerIsActive = PR_FALSE;
+    mProgressNotifier->Cancel();
+  }
+
+  if (mTimerIsActive ||
+      !mProgressSinceLastProgressEvent ||
+      mErrorLoad ||
+      !(mState & XML_HTTP_REQUEST_ASYNC)) {
+    return;
+  }
+
+  if (!aFinalProgress) {
+    StartProgressEventTimer();
+  }
+
+  // We're uploading if our state is XML_HTTP_REQUEST_OPENED or
+  // XML_HTTP_REQUEST_SENT
+  if ((XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT) & mState) {
+    if (aFinalProgress) {
+      mUploadTotal = mUploadTransferred;
+      mUploadProgressMax = mUploadProgress;
+      mUploadLengthComputable = PR_TRUE;
+    }
+    DispatchProgressEvent(this, NS_LITERAL_STRING(UPLOADPROGRESS_STR),
+                          PR_TRUE, mUploadLengthComputable, mUploadTransferred,
+                          mUploadTotal, mUploadProgress,
+                          mUploadProgressMax);
+    if (mUpload && !mUploadComplete) {
+      DispatchProgressEvent(mUpload, NS_LITERAL_STRING(PROGRESS_STR),
+                            PR_TRUE, mUploadLengthComputable, mUploadTransferred,
+                            mUploadTotal, mUploadProgress,
+                            mUploadProgressMax);
+    }
+  } else {
+    if (aFinalProgress) {
+      mLoadTotal = mLoadTransferred;
+      mLoadLengthComputable = PR_TRUE;
+    }
+    mInLoadProgressEvent = PR_TRUE;
+    DispatchProgressEvent(this, NS_LITERAL_STRING(PROGRESS_STR),
+                          PR_TRUE, mLoadLengthComputable, mLoadTransferred,
+                          mLoadTotal, mLoadTransferred, mLoadTotal);
+    mInLoadProgressEvent = PR_FALSE;
+    if (mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT ||
+        mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER) {
+      mResponseBody.Truncate();
+      mResponseText.Truncate();
+      mResultArrayBuffer = nsnull;
+    }
+  }
+
+  mProgressSinceLastProgressEvent = PR_FALSE;
+}
+
 NS_IMETHODIMP
 nsXMLHttpRequest::OnProgress(nsIRequest *aRequest, nsISupports *aContext, PRUint64 aProgress, PRUint64 aProgressMax)
 {
   // We're in middle of processing multipart headers and we don't want to report
   // any progress because upload's 'load' is dispatched when we start to load
   // the first response.
   if (XML_HTTP_REQUEST_MPART_HEADERS & mState) {
     return NS_OK;
   }
 
   // We're uploading if our state is XML_HTTP_REQUEST_OPENED or
   // XML_HTTP_REQUEST_SENT
   PRBool upload = !!((XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT) & mState);
-  PRUint64 loaded = aProgress;
-  PRUint64 total = aProgressMax;
   // When uploading, OnProgress reports also headers in aProgress and aProgressMax.
   // So, try to remove the headers, if possible.
   PRBool lengthComputable = (aProgressMax != LL_MAXUINT);
   if (upload) {
-   if (lengthComputable) {
+    PRUint64 loaded = aProgress;
+    PRUint64 total = aProgressMax;
+    if (lengthComputable) {
       PRUint64 headerSize = aProgressMax - mUploadTotal;
       loaded -= headerSize;
       total -= headerSize;
     }
+    mUploadLengthComputable = lengthComputable;
     mUploadTransferred = loaded;
     mUploadProgress = aProgress;
     mUploadProgressMax = aProgressMax;
+    mProgressSinceLastProgressEvent = PR_TRUE;
+
+    MaybeDispatchProgressEvents(PR_FALSE);
   } else {
     mLoadLengthComputable = lengthComputable;
-    mLoadTotal = mLoadLengthComputable ? total : 0;
-  }
-
-  if (mTimerIsActive) {
-    // The progress event will be dispatched when the notifier calls Notify().
-    mProgressEventWasDelayed = PR_TRUE;
-    return NS_OK;
-  }
-
-  if (!mErrorLoad && (mState & XML_HTTP_REQUEST_ASYNC)) {
-    StartProgressEventTimer();
-    NS_NAMED_LITERAL_STRING(progress, PROGRESS_STR);
-    NS_NAMED_LITERAL_STRING(uploadprogress, UPLOADPROGRESS_STR);
-    DispatchProgressEvent(this, upload ? uploadprogress : progress, PR_TRUE,
-                          lengthComputable, loaded, lengthComputable ? total : 0,
-                          aProgress, aProgressMax);
-
-    if (upload && mUpload && !mUploadComplete) {
-      NS_WARN_IF_FALSE(mUploadTotal == total, "Wrong upload total?");
-      DispatchProgressEvent(mUpload, progress,  PR_TRUE, lengthComputable, loaded,
-                            lengthComputable ? total : 0, aProgress, aProgressMax);
-    }
+    mLoadTotal = lengthComputable ? aProgressMax : 0;
+    
+    // Don't dispatch progress events here. OnDataAvailable will take care
+    // of that.
   }
 
   if (mProgressEventSink) {
     mProgressEventSink->OnProgress(aRequest, aContext, aProgress,
                                    aProgressMax);
   }
 
   return NS_OK;
@@ -3085,45 +3189,20 @@ nsXMLHttpRequest::GetUpload(nsIXMLHttpRe
   NS_ADDREF(*aUpload = mUpload);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXMLHttpRequest::Notify(nsITimer* aTimer)
 {
   mTimerIsActive = PR_FALSE;
-  if (NS_SUCCEEDED(CheckInnerWindowCorrectness()) && !mErrorLoad &&
-      (mState & XML_HTTP_REQUEST_ASYNC)) {
-    if (mProgressEventWasDelayed) {
-      mProgressEventWasDelayed = PR_FALSE;
-      if (!(XML_HTTP_REQUEST_MPART_HEADERS & mState)) {
-        StartProgressEventTimer();
-        // We're uploading if our state is XML_HTTP_REQUEST_OPENED or
-        // XML_HTTP_REQUEST_SENT
-        if ((XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT) & mState) {
-          DispatchProgressEvent(this, NS_LITERAL_STRING(UPLOADPROGRESS_STR),
-                                PR_TRUE, PR_TRUE, mUploadTransferred,
-                                mUploadTotal, mUploadProgress,
-                                mUploadProgressMax);
-          if (mUpload && !mUploadComplete) {
-            DispatchProgressEvent(mUpload, NS_LITERAL_STRING(PROGRESS_STR),
-                                  PR_TRUE, PR_TRUE, mUploadTransferred,
-                                  mUploadTotal, mUploadProgress,
-                                  mUploadProgressMax);
-          }
-        } else {
-          DispatchProgressEvent(this, NS_LITERAL_STRING(PROGRESS_STR),
-                                mLoadLengthComputable, mResponseBody.Length(),
-                                mLoadTotal);
-        }
-      }
-    }
-  } else if (mProgressNotifier) {
-    mProgressNotifier->Cancel();
+  if (!(XML_HTTP_REQUEST_MPART_HEADERS & mState)) {
+    MaybeDispatchProgressEvents(PR_FALSE);
   }
+
   return NS_OK;
 }
 
 void
 nsXMLHttpRequest::StartProgressEventTimer()
 {
   if (!mProgressNotifier) {
     mProgressNotifier = do_CreateInstance(NS_TIMER_CONTRACTID);
--- a/content/base/src/nsXMLHttpRequest.h
+++ b/content/base/src/nsXMLHttpRequest.h
@@ -63,16 +63,17 @@
 #include "nsITimer.h"
 #include "nsIPrivateDOMEvent.h"
 #include "nsDOMProgressEvent.h"
 #include "nsDOMEventTargetWrapperCache.h"
 #include "nsContentUtils.h"
 
 class nsILoadGroup;
 class AsyncVerifyRedirectCallbackForwarder;
+class nsIUnicodeDecoder;
 
 class nsXHREventTarget : public nsDOMEventTargetWrapperCache,
                          public nsIXMLHttpRequestEventTarget
 {
 public:
   virtual ~nsXHREventTarget() {}
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXHREventTarget,
@@ -183,31 +184,36 @@ public:
                              PRBool aLengthComputable,
                              PRUint64 aLoaded, PRUint64 aTotal)
   {
     DispatchProgressEvent(aTarget, aType, PR_FALSE,
                           aLengthComputable, aLoaded, aTotal,
                           aLoaded, aLengthComputable ? aTotal : LL_MAXUINT);
   }
 
+  // Dispatch the "progress" event on the XHR or XHR.upload object if we've
+  // received data since the last "progress" event. Also dispatches
+  // "uploadprogress" as needed.
+  void MaybeDispatchProgressEvents(PRBool aFinalProgress);
+
   // This is called by the factory constructor.
   nsresult Init();
 
   void SetRequestObserver(nsIRequestObserver* aObserver);
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(nsXMLHttpRequest,
                                            nsXHREventTarget)
   PRBool AllowUploadProgress();
   void RootResultArrayBuffer();
   
 protected:
   friend class nsMultipartProxyListener;
 
-  nsresult DetectCharset(nsACString& aCharset);
-  nsresult ConvertBodyToText(nsAString& aOutBuffer);
+  nsresult DetectCharset();
+  nsresult AppendToResponseText(const char * aBuffer, PRUint32 aBufferLen);
   static NS_METHOD StreamReaderFunc(nsIInputStream* in,
                 void* closure,
                 const char* fromRawSegment,
                 PRUint32 toOffset,
                 PRUint32 count,
                 PRUint32 *writeCount);
   nsresult CreateResponseParsedJSON(JSContext* aCx);
   nsresult CreateResponseArrayBuffer(JSContext* aCx);
@@ -263,33 +269,50 @@ protected:
     NS_DECL_NSIHTTPHEADERVISITOR
     nsHeaderVisitor() { }
     virtual ~nsHeaderVisitor() {}
     const nsACString &Headers() { return mHeaders; }
   private:
     nsCString mHeaders;
   };
 
-  // The bytes of our response body
+  // The bytes of our response body. Only used for DEFAULT, ARRAYBUFFER and
+  // BLOB responseTypes
   nsCString mResponseBody;
 
-  // The Unicode version of our response body.  This is just a cache; if the
-  // string is not void, we have a cached value.  This works because we only
-  // allow looking at this value once state is INTERACTIVE, and at that
-  // point our charset can only change due to more data coming in, which
-  // will cause us to clear the cached value anyway.
-  nsString mResponseBodyUnicode;
+  // The text version of our response body. This is incrementally decoded into
+  // as we receive network data. However for the DEFAULT responseType we
+  // lazily decode into this from mResponseBody only when .responseText is
+  // accessed.
+  // Only used for DEFAULT and TEXT responseTypes.
+  nsString mResponseText;
+  
+  // For DEFAULT responseType we use this to keep track of how far we've
+  // lazily decoded from mResponseBody to mResponseText
+  PRUint32 mResponseBodyDecodedPos;
+
+  // Decoder used for decoding into mResponseText
+  // Only used for DEFAULT, TEXT and JSON responseTypes.
+  // In cases where we've only received half a surrogate, the decoder itself
+  // carries the state to remember this. Next time we receive more data we
+  // simply feed the new data into the decoder which will handle the second
+  // part of the surrogate.
+  nsCOMPtr<nsIUnicodeDecoder> mDecoder;
+
+  nsCString mResponseCharset;
 
   enum {
     XML_HTTP_RESPONSE_TYPE_DEFAULT,
     XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER,
     XML_HTTP_RESPONSE_TYPE_BLOB,
     XML_HTTP_RESPONSE_TYPE_DOCUMENT,
     XML_HTTP_RESPONSE_TYPE_TEXT,
-    XML_HTTP_RESPONSE_TYPE_JSON
+    XML_HTTP_RESPONSE_TYPE_JSON,
+    XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT,
+    XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER
   } mResponseType;
 
   nsCOMPtr<nsIDOMBlob> mResponseBlob;
 
   nsCString mOverrideMimeType;
 
   /**
    * The notification callbacks the channel had when Send() was
@@ -308,36 +331,42 @@ protected:
 
   nsCOMPtr<nsIURI> mBaseURI;
 
   PRUint32 mState;
 
   nsRefPtr<nsXMLHttpRequestUpload> mUpload;
   PRUint64 mUploadTransferred;
   PRUint64 mUploadTotal;
+  PRPackedBool mUploadLengthComputable;
   PRPackedBool mUploadComplete;
+  PRPackedBool mProgressSinceLastProgressEvent;
   PRUint64 mUploadProgress; // For legacy
   PRUint64 mUploadProgressMax; // For legacy
 
   PRPackedBool mErrorLoad;
 
   PRPackedBool mTimerIsActive;
   PRPackedBool mProgressEventWasDelayed;
   PRPackedBool mLoadLengthComputable;
   PRUint64 mLoadTotal; // 0 if not known.
+  PRUint64 mLoadTransferred;
   nsCOMPtr<nsITimer> mProgressNotifier;
 
   PRPackedBool mFirstStartRequestSeen;
+  PRPackedBool mInLoadProgressEvent;
   
   nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
   nsCOMPtr<nsIChannel> mNewRedirectChannel;
   
   jsval mResultJSON;
   JSObject* mResultArrayBuffer;
 
+  void ResetResponse();
+
   struct RequestHeader
   {
     nsCString header;
     nsCString value;
   };
   nsTArray<RequestHeader> mModifiedRequestHeaders;
 };
 
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -261,16 +261,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug450160.html \
 		test_bug453736.html \
 		test_bug454326.html \
 		test_bug505783.html \
 		test_bug457746.html \
 		test_bug587931.html \
 		test_bug592829.html \
 		test_bug518104.html \
+		test_bug682463.html \
 		bug457746.sjs \
 		test_CrossSiteXHR.html \
 		test_CrossSiteXHR_origin.html \
 		file_CrossSiteXHR_inner.html \
 		file_CrossSiteXHR_inner_data.sjs \
 		file_CrossSiteXHR_inner.jar \
 		file_CrossSiteXHR_server.sjs \
 		test_CrossSiteXHR_cache.html \
@@ -493,29 +494,32 @@ include $(topsrcdir)/config/rules.mk
 		badMessageEvent.eventsource \
 		badMessageEvent.eventsource^headers^ \
 		forRemoval.resource \
 		forRemoval.resource^headers^ \
 		accesscontrol.resource \
 		accesscontrol.resource^headers^ \
 		invalid_accesscontrol.resource \
 		invalid_accesscontrol.resource^headers^ \
+		test_xhr_progressevents.html \
+		progressserver.sjs \
 		somedatas.resource \
 		somedatas.resource^headers^ \
 		delayedServerEvents.sjs \
 		test_bug664916.html \
 		test_bug666604.html \
 		test_bug675121.html \
 		file_bug675121.sjs \
 		test_bug654352.html \
 		test_bug675166.html \
 		test_bug682554.html \
 		test_bug682592.html \
 		bug682592-subframe.html \
 		bug682592-subframe-ref.html \
+		test_bug684671.html \
 		test_bug685798.html \
 		test_bug686449.xhtml \
 		$(NULL)
 
 _CHROME_FILES =	\
 		test_bug357450.js \
 		$(NULL)
 
--- a/content/base/test/file_websocket_wsh.py
+++ b/content/base/test/file_websocket_wsh.py
@@ -100,10 +100,18 @@ def web_socket_transfer_data(request):
     while not request.client_terminated:
       msgutil.receive_message(request)
     global test37code
     test37code = request.ws_close_code
     global test37reason
     test37reason = request.ws_close_reason
   elif request.ws_protocol == "test-37c":
     request.ws_stream.close_connection(test37code, test37reason)
+  elif request.ws_protocol == "test-42":
+    # Echo back 3 messages
+    msgutil.send_message(request,
+                         msgutil.receive_message(request))
+    msgutil.send_message(request, 
+                         msgutil.receive_message(request))
+    msgutil.send_message(request, 
+                         msgutil.receive_message(request))
   while not request.client_terminated:
     msgutil.receive_message(request)
new file mode 100644
--- /dev/null
+++ b/content/base/test/progressserver.sjs
@@ -0,0 +1,51 @@
+const CC = Components.Constructor;
+const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
+                             "nsIBinaryInputStream",
+                             "setInputStream");
+
+function setReq(req) {
+  setObjectState("content/base/test/progressserver", req);
+}
+
+function getReq() {
+  var req;
+  getObjectState("content/base/test/progressserver", function(v) {
+    req = v;
+  });
+  return req;
+}
+
+function handleRequest(request, response)
+{
+  var pairs = request.queryString.split('&');
+  var command = pairs.shift();
+
+  var bodyStream = new BinaryInputStream(request.bodyInputStream);
+  var body = "";
+  var bodyAvail;
+  while ((bodyAvail = bodyStream.available()) > 0)
+    body += String.fromCharCode.apply(null, bodyStream.readByteArray(bodyAvail));
+
+  if (command == "open") {
+    response.processAsync();
+    setReq(response);
+
+    response.setHeader("Cache-Control", "no-cache", false);
+    pairs.forEach(function (val) {
+      var [name, value] = val.split('=');
+      response.setHeader(name, unescape(value), false);
+    });
+    response.write(body);
+    return;
+  }
+
+  if (command == "send") {
+    getReq().write(body);
+  }
+  else if (command == "close") {
+    getReq().finish();
+    setReq(null);
+  }
+  response.setHeader("Content-Type", "text/plain");
+  response.write("ok");
+}
--- a/content/base/test/test_XHR.html
+++ b/content/base/test/test_XHR.html
@@ -9,51 +9,16 @@
 <p id="display"></p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 SimpleTest.waitForExplicitFinish();
 
-// test receiving as JSON
-function testJSON(aJsonStr, invalid) {
-  var errorThrown = false;
-  var anotherErrorThrown = false;
-  var xhr = new XMLHttpRequest();
-  
-  var didthrow = false;
-  try { xhr.responseType = 'moz-json'; } catch (e) { didthrow = true; }
-  ok(didthrow, 
-     "should have thrown when setting responseType to moz-json before open");
-
-  xhr.open("POST", 'responseIdentical.sjs', false);
-  xhr.responseType = 'moz-json';
-  xhr.send(aJsonStr);
-
-  if (!invalid) {
-    is(JSON.stringify(xhr.response), aJsonStr);
-    is(xhr.response, xhr.response, "returning the same object on each access");
-  }
-  else {
-    var didThrow = false;
-    try { xhr.response } catch(ex) { didThrow = true; }
-    ok(didThrow, "accessing response should throw");
-
-    didThrow = false;
-    try { xhr.response } catch(ex) { didThrow = true; }
-    ok(didThrow, "accessing response should throw");
-  } 
-}
-
-var jsonStr = '{"title":"aBook","author":"john"}';
-testJSON(jsonStr, false);
-var invalidJson = '{ "abc": }'
-testJSON(invalidJson, true);
-
 var path = "/tests/content/base/test/";
 
 var passFiles = [['file_XHR_pass1.xml', 'GET'],
                  ['file_XHR_pass2.txt', 'GET'],
                  ['file_XHR_pass3.txt', 'GET'],
                  ];
 
 var failFiles = [['//example.com' + path + 'file_XHR_pass1.xml', 'GET'],
@@ -104,28 +69,35 @@ function checkResponseTextAccessThrows(x
   try { xhr.responseText } catch (e) { didthrow = true; }
   ok(didthrow, "should have thrown when accessing responseText");
 }
 function checkResponseXMLAccessThrows(xhr) {
   var didthrow = false;
   try { xhr.responseXML } catch (e) { didthrow = true; }
   ok(didthrow, "should have thrown when accessing responseXML");
 }
-function checkSetResponseTypeThrows(xhr) {
+function checkResponseAccessThrows(xhr) {
   var didthrow = false;
-  try { xhr.responseType = 'document'; } catch (e) { didthrow = true; }
-  ok(didthrow, "should have thrown when accessing responseType");
+  try { xhr.response } catch (e) { didthrow = true; }
+  ok(didthrow, "should have thrown when accessing response");
+}
+function checkSetResponseTypeThrows(xhr, type) {
+  var didthrow = false;
+  try { xhr.responseType = type; } catch (e) { didthrow = true; }
+  ok(didthrow, "should have thrown when setting responseType");
 }
 
 xhr = new XMLHttpRequest();
-checkSetResponseTypeThrows(xhr);
+checkSetResponseTypeThrows(xhr, "document");
 xhr.open("GET", 'file_XHR_pass1.xml', false); 
+checkSetResponseTypeThrows(xhr, "moz-chunked-text");
+checkSetResponseTypeThrows(xhr, "moz-chunked-arraybuffer");
 xhr.responseType = 'document';
 xhr.send(null);
-checkSetResponseTypeThrows(xhr);
+checkSetResponseTypeThrows(xhr, "document");
 is(xhr.status, 200, "wrong status");
 checkResponseTextAccessThrows(xhr);
 is((new XMLSerializer()).serializeToString(xhr.response.documentElement),
    "<res>hello</res>",
    "wrong response");
 
 // test response (responseType='text')
 xhr = new XMLHttpRequest();
@@ -173,26 +145,40 @@ xhr.open("GET", 'file_XHR_binary1.bin', 
 xhr.responseType = 'arraybuffer';
 xhr.send(null)
 is(xhr.status, 200, "wrong status");
 checkResponseTextAccessThrows(xhr);
 checkResponseXMLAccessThrows(xhr);
 ab = xhr.response;
 ok(ab != null, "should have a non-null arraybuffer");
 arraybuffer_equals_to(ab, "\xaa\xee\0\x03\xff\xff\xff\xff\xbb\xbb\xbb\xbb");
+is(xhr.response, xhr.response, "returns the same ArrayBuffer");
 
-// test array buffer GetResult returns the same object
-xhr = new XMLHttpRequest();
-xhr.open("GET", 'file_XHR_binary1.bin', false); 
-xhr.responseType = 'arraybuffer';
-xhr.send(null)
+// test response (responseType='moz-json')
+var xhr = new XMLHttpRequest();
+xhr.open("POST", 'responseIdentical.sjs', false);
+xhr.responseType = 'moz-json';
+jsonObjStr = JSON.stringify({title: "aBook", author: "john"});
+xhr.send(jsonObjStr);
 is(xhr.status, 200, "wrong status");
 checkResponseTextAccessThrows(xhr);
 checkResponseXMLAccessThrows(xhr);
-is(xhr.response, xhr.response, "returns the same ArrayBuffer");
+is(JSON.stringify(xhr.response), jsonObjStr, "correct result");
+is(xhr.response, xhr.response, "returning the same object on each access");
+
+// with invalid json
+var xhr = new XMLHttpRequest();
+xhr.open("POST", 'responseIdentical.sjs', false);
+xhr.responseType = 'moz-json';
+xhr.send("{");
+is(xhr.status, 200, "wrong status");
+checkResponseTextAccessThrows(xhr);
+checkResponseXMLAccessThrows(xhr);
+checkResponseAccessThrows(xhr);
+checkResponseAccessThrows(xhr); // Check twice to ensure that we still throw
 
 // test response (responseType='blob')
 var onloadCount = 0;
 function checkOnloadCount() {
   if (++onloadCount >= 2) SimpleTest.finish();
 };
 
 // with a simple text file
--- a/content/base/test/test_bug353334.html
+++ b/content/base/test/test_bug353334.html
@@ -27,28 +27,30 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 /** Test for Bug 353334 **/