Merge from mozilla-central (yay method barrier removal).
authorDavid Anderson <danderson@mozilla.com>
Wed, 28 Mar 2012 13:46:36 -0700
changeset 106105 ab92bf1f7deadc2e04077a80505b687f589cc68e
parent 106104 15da4376607bdd326e62c68d42f1831ba10007df (current diff)
parent 90517 c3fd0768d46abdb77d0e51d4bcb52d5adf4d0445 (diff)
child 106106 9d13b69838c201fe7e2abaaff9ae7319d24a08a7
push id14706
push usereakhgari@mozilla.com
push dateTue, 11 Sep 2012 20:39:52 +0000
treeherdermozilla-inbound@d50bf1edaabe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone14.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 (yay method barrier removal).
accessible/src/atk/nsMaiInterfaceTable.cpp
accessible/src/base/AccEvent.cpp
accessible/src/base/Makefile.in
accessible/src/base/nsARIAGridAccessible.cpp
accessible/src/base/nsARIAGridAccessible.h
accessible/src/base/nsAccUtils.cpp
accessible/src/base/nsAccessible.h
accessible/src/base/nsRootAccessible.h
accessible/src/html/nsHTMLTableAccessible.cpp
accessible/src/html/nsHTMLTableAccessible.h
accessible/src/html/nsHyperTextAccessible.cpp
accessible/src/xul/Makefile.in
accessible/src/xul/nsXULListboxAccessible.cpp
accessible/src/xul/nsXULListboxAccessible.h
accessible/src/xul/nsXULTreeGridAccessible.cpp
accessible/src/xul/nsXULTreeGridAccessible.h
b2g/confvars.sh
browser/app/profile/firefox.js
browser/base/content/browser.js
browser/base/content/browser.xul
browser/components/migration/src/nsBrowserProfileMigratorUtils.cpp
browser/components/nsBrowserContentHandler.js
browser/components/nsBrowserGlue.js
browser/components/shell/src/nsWindowsShellService.cpp
browser/components/tabview/tabitems.js
browser/locales/en-US/chrome/browser/browser.properties
configure.in
content/base/public/nsIDocument.h
content/base/src/nsCCUncollectableMarker.cpp
content/base/src/nsCCUncollectableMarker.h
content/base/src/nsDocument.cpp
content/base/src/nsDocument.h
content/base/src/nsGkAtomList.h
content/base/src/nsImageLoadingContent.cpp
content/base/src/nsObjectLoadingContent.cpp
content/base/src/nsObjectLoadingContent.h
content/base/src/nsXMLHttpRequest.cpp
content/base/test/Makefile.in
content/events/src/nsEventStateManager.cpp
content/events/src/nsEventStateManager.h
content/html/content/src/nsHTMLObjectElement.cpp
content/html/content/src/nsHTMLSharedObjectElement.cpp
content/html/document/src/MediaDocument.cpp
content/html/document/src/MediaDocument.h
content/html/document/src/nsHTMLDocument.cpp
docshell/base/nsDocShell.cpp
docshell/base/nsDocShell.h
dom/base/nsDOMWindowUtils.cpp
dom/base/nsJSEnvironment.cpp
dom/base/nsStructuredCloneContainer.cpp
dom/indexedDB/IDBKeyRange.cpp
dom/indexedDB/IDBKeyRange.h
dom/interfaces/base/nsIDOMWindowUtils.idl
dom/src/storage/nsDOMStorage.cpp
dom/src/storage/nsDOMStorage.h
dom/workers/WorkerPrivate.cpp
editor/libeditor/text/tests/Makefile.in
editor/libeditor/text/tests/test_bug717147.html
embedding/components/find/src/nsFind.cpp
embedding/components/find/src/nsFind.h
gfx/thebes/gfxDWriteFontList.cpp
gfx/thebes/gfxDWriteFontList.h
gfx/thebes/gfxFT2FontList.cpp
gfx/thebes/gfxFT2FontList.h
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxFont.h
gfx/thebes/gfxFontUtils.h
gfx/thebes/gfxGDIFontList.cpp
gfx/thebes/gfxGDIFontList.h
gfx/thebes/gfxMacPlatformFontList.h
gfx/thebes/gfxMacPlatformFontList.mm
gfx/thebes/gfxPlatformFontList.cpp
gfx/thebes/gfxPlatformFontList.h
gfx/thebes/gfxWindowsPlatform.cpp
js/src/builtin/ParallelArray.cpp
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/ParseNode.cpp
js/src/frontend/ParseNode.h
js/src/frontend/Parser.cpp
js/src/frontend/SemanticAnalysis.cpp
js/src/ion/CodeGenerator.cpp
js/src/ion/CodeGenerator.h
js/src/ion/IonBuilder.cpp
js/src/ion/IonCaches.cpp
js/src/ion/LIR-Common.h
js/src/ion/LOpcodes.h
js/src/ion/Lowering.cpp
js/src/ion/Lowering.h
js/src/ion/MIR.h
js/src/ion/MOpcodes.h
js/src/jit-test/tests/basic/testInitDictionary.js
js/src/jsanalyze.cpp
js/src/jsanalyze.h
js/src/jsapi.cpp
js/src/jsdbgapi.cpp
js/src/jsdbgapi.h
js/src/jsexn.cpp
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsfuninlines.h
js/src/jsinfer.cpp
js/src/jsinterp.cpp
js/src/jsinterpinlines.h
js/src/jsiter.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/json.cpp
js/src/jsopcode.cpp
js/src/jsopcode.h
js/src/jsopcode.tbl
js/src/jsscope.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsstr.cpp
js/src/jsval.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/FastOps.cpp
js/src/methodjit/LoopState.cpp
js/src/methodjit/MonoIC.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls.cpp
js/src/methodjit/StubCalls.h
js/src/shell/js.cpp
js/src/vm/Debugger.cpp
js/src/vm/Stack-inl.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
js/xpconnect/src/XPCJSRuntime.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsGfxScrollFrame.h
layout/generic/nsIScrollableFrame.h
layout/generic/nsTextFrame.h
layout/generic/nsTextFrameThebes.cpp
layout/generic/nsTextRunTransformations.cpp
layout/xul/base/src/nsListBoxBodyFrame.cpp
mobile/android/base/GeckoApp.java
mobile/android/base/sync/repositories/android/PasswordColumns.java
modules/libpref/src/init/all.js
netwerk/cache/nsCacheService.cpp
parser/html/nsHtml5Module.cpp
parser/html/nsHtml5TreeOpExecutor.cpp
parser/html/nsHtml5TreeOpExecutor.h
parser/htmlparser/public/nsIParser.h
parser/htmlparser/src/nsParser.cpp
parser/htmlparser/src/nsParser.h
toolkit/components/places/AsyncFaviconHelpers.cpp
toolkit/components/places/nsFaviconService.cpp
toolkit/components/places/tests/favicons/test_favicons.js
toolkit/components/places/tests/head_common.js
toolkit/components/telemetry/TelemetryHistograms.h
toolkit/xre/nsAppRunner.cpp
widget/gtk2/nsWindow.cpp
widget/nsGUIEvent.h
xpcom/base/nsStackWalk.cpp
xulrunner/makefiles.sh
--- a/accessible/src/atk/Makefile.in
+++ b/accessible/src/atk/Makefile.in
@@ -94,12 +94,14 @@ CXXFLAGS	+= $(MOZ_GTK2_CFLAGS)
 
 ifdef MOZ_ENABLE_DBUS
 CXXFLAGS += $(MOZ_DBUS_CFLAGS)
 endif
 
 LOCAL_INCLUDES += \
   -I$(srcdir) \
   -I$(srcdir)/../base \
+  -I$(srcdir)/../generic \
   -I$(srcdir)/../html \
+  -I$(srcdir)/../xpcom \
   -I$(srcdir)/../xul \
   -I$(topsrcdir)/other-licenses/atk-1.0 \
   $(NULL)
--- a/accessible/src/atk/nsMaiInterfaceTable.cpp
+++ b/accessible/src/atk/nsMaiInterfaceTable.cpp
@@ -37,22 +37,24 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "InterfaceInitFuncs.h"
 
 #include "nsAccessibleWrap.h"
 #include "nsAccUtils.h"
 #include "nsIAccessibleTable.h"
+#include "TableAccessible.h"
 #include "nsMai.h"
 
 #include "nsArrayUtils.h"
 
+using namespace mozilla::a11y;
+
 extern "C" {
-
 static AtkObject*
 refAtCB(AtkTable *aTable, gint aRow, gint aColumn)
 {
     nsAccessibleWrap *accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
     if (!accWrap)
         return nsnull;
 
     nsCOMPtr<nsIAccessibleTable> accTable;
@@ -203,33 +205,27 @@ getRowExtentAtCB(AtkTable *aTable,
     PRInt32 extent;
     nsresult rv = accTable->GetRowExtentAt(aRow, aColumn, &extent);
     NS_ENSURE_SUCCESS(rv, -1);
 
     return static_cast<gint>(extent);
 }
 
 static AtkObject*
-getCaptionCB(AtkTable *aTable)
+getCaptionCB(AtkTable* aTable)
 {
-    nsAccessibleWrap *accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
-    if (!accWrap)
-        return nsnull;
+  nsAccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
+  if (!accWrap)
+    return nsnull;
 
-    nsCOMPtr<nsIAccessibleTable> accTable;
-    accWrap->QueryInterface(NS_GET_IID(nsIAccessibleTable),
-                            getter_AddRefs(accTable));
-    NS_ENSURE_TRUE(accTable, nsnull);
+  TableAccessible* table = accWrap->AsTable();
+  NS_ENSURE_TRUE(table, nsnull);
 
-    nsCOMPtr<nsIAccessible> caption;
-    nsresult rv = accTable->GetCaption(getter_AddRefs(caption));
-    if (NS_FAILED(rv) || !caption)
-        return nsnull;
-
-    return nsAccessibleWrap::GetAtkObject(caption);
+  nsAccessible* caption = table->Caption();
+  return caption ? nsAccessibleWrap::GetAtkObject(caption) : nsnull;
 }
 
 static const gchar*
 getColumnDescriptionCB(AtkTable *aTable, gint aColumn)
 {
     nsAccessibleWrap *accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
     if (!accWrap)
         return nsnull;
--- a/accessible/src/base/AccEvent.cpp
+++ b/accessible/src/base/AccEvent.cpp
@@ -39,19 +39,16 @@
 
 #include "AccEvent.h"
 
 #include "nsAccessibilityService.h"
 #include "nsAccUtils.h"
 #include "nsApplicationAccessibleWrap.h"
 #include "nsDocAccessible.h"
 #include "nsIAccessibleText.h"
-#ifdef MOZ_XUL
-#include "nsXULTreeAccessible.h"
-#endif
 #include "nsAccEvent.h"
 #include "States.h"
 
 #include "nsIDOMDocument.h"
 #include "nsEventStateManager.h"
 #include "nsIServiceManager.h"
 #ifdef MOZ_XUL
 #include "nsIDOMXULMultSelectCntrlEl.h"
--- a/accessible/src/base/Makefile.in
+++ b/accessible/src/base/Makefile.in
@@ -99,18 +99,19 @@ EXPORTS_mozilla/a11y = \
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
   -I$(srcdir) \
+  -I$(srcdir)/../generic \
+  -I$(srcdir)/../html \
   -I$(srcdir)/../xpcom \
-  -I$(srcdir)/../html \
   -I$(srcdir)/../xul \
   -I$(srcdir)/../../../layout/generic \
   -I$(srcdir)/../../../layout/style \
   -I$(srcdir)/../../../layout/xul/base/src \
   -I$(srcdir)/../xforms \
   $(NULL)
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
--- a/accessible/src/base/nsARIAGridAccessible.cpp
+++ b/accessible/src/base/nsARIAGridAccessible.cpp
@@ -53,42 +53,39 @@ using namespace mozilla::a11y;
 ////////////////////////////////////////////////////////////////////////////////
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // Constructor
 
 nsARIAGridAccessible::
   nsARIAGridAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
-  nsAccessibleWrap(aContent, aDoc)
+  nsAccessibleWrap(aContent, aDoc), xpcAccessibleTable(this)
 {
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsISupports
 
 NS_IMPL_ISUPPORTS_INHERITED1(nsARIAGridAccessible,
                              nsAccessible,
                              nsIAccessibleTable)
 
 ////////////////////////////////////////////////////////////////////////////////
-// nsIAccessibleTable
+//nsAccessNode
 
-NS_IMETHODIMP
-nsARIAGridAccessible::GetCaption(nsIAccessible **aCaption)
+void
+nsARIAGridAccessible::Shutdown()
 {
-  NS_ENSURE_ARG_POINTER(aCaption);
-  *aCaption = nsnull;
+  mTable = nsnull;
+  nsAccessibleWrap::Shutdown();
+}
 
-  if (IsDefunct())
-    return NS_ERROR_FAILURE;
-
-  // XXX: should be pointed by aria-labelledby on grid?
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
+////////////////////////////////////////////////////////////////////////////////
+// nsIAccessibleTable
 
 NS_IMETHODIMP
 nsARIAGridAccessible::GetSummary(nsAString &aSummary)
 {
   aSummary.Truncate();
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
@@ -705,25 +702,16 @@ nsARIAGridAccessible::UnselectColumn(PRI
       nsresult rv = SetARIASelected(cell, false);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsARIAGridAccessible::IsProbablyForLayout(bool *aIsProbablyForLayout)
-{
-  NS_ENSURE_ARG_POINTER(aIsProbablyForLayout);
-  *aIsProbablyForLayout = false;
-
-  return NS_OK;
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // Protected
 
 bool
 nsARIAGridAccessible::IsValidRow(PRInt32 aRow)
 {
   if (aRow < 0)
     return false;
--- a/accessible/src/base/nsARIAGridAccessible.h
+++ b/accessible/src/base/nsARIAGridAccessible.h
@@ -37,31 +37,41 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsARIAGridAccessible_h_
 #define nsARIAGridAccessible_h_
 
 #include "nsIAccessibleTable.h"
 
 #include "nsHyperTextAccessibleWrap.h"
+#include "TableAccessible.h"
+#include "xpcAccessibleTable.h"
 
 /**
  * Accessible for ARIA grid and treegrid.
  */
 class nsARIAGridAccessible : public nsAccessibleWrap,
-                             public nsIAccessibleTable
+                             public xpcAccessibleTable,
+                             public nsIAccessibleTable,
+                             public mozilla::a11y::TableAccessible
 {
 public:
   nsARIAGridAccessible(nsIContent* aContent, nsDocAccessible* aDoc);
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIAccessibleTable
-  NS_DECL_NSIACCESSIBLETABLE
+  NS_DECL_OR_FORWARD_NSIACCESSIBLETABLE_WITH_XPCACCESSIBLETABLE
+
+  // nsAccessible
+  virtual mozilla::a11y::TableAccessible* AsTable() { return this; }
+
+  // nsAccessNode
+  virtual void Shutdown();
 
 protected:
   /**
    * Return true if the given row index is valid.
    */
   bool IsValidRow(PRInt32 aRow);
 
   /**
--- a/accessible/src/base/nsAccUtils.cpp
+++ b/accessible/src/base/nsAccUtils.cpp
@@ -42,19 +42,17 @@
 #include "nsIAccessibleTypes.h"
 #include "Role.h"
 #include "States.h"
 
 #include "nsAccessibilityService.h"
 #include "nsARIAMap.h"
 #include "nsDocAccessible.h"
 #include "nsHyperTextAccessible.h"
-#include "nsHTMLTableAccessible.h"
 #include "nsTextAccessible.h"
-#include "nsXULTreeGridAccessible.h"
 
 #include "nsIDOMXULContainerElement.h"
 #include "nsIDOMXULSelectCntrlEl.h"
 #include "nsIDOMXULSelectCntrlItemEl.h"
 #include "nsWhitespaceTokenizer.h"
 #include "nsComponentManagerUtils.h"
 
 namespace dom = mozilla::dom;
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -61,16 +61,21 @@ class EmbeddedObjCollector;
 class KeyBinding;
 class nsAccessible;
 class nsHyperTextAccessible;
 class nsHTMLImageAccessible;
 class nsHTMLImageMapAccessible;
 class nsHTMLLIAccessible;
 struct nsRoleMapEntry;
 class Relation;
+namespace mozilla {
+namespace a11y {
+class TableAccessible;
+}
+}
 class nsTextAccessible;
 
 struct nsRect;
 class nsIContent;
 class nsIFrame;
 class nsIAtom;
 class nsIView;
 
@@ -466,16 +471,18 @@ public:
 
   inline bool IsMenuButton() const { return mFlags & eMenuButtonAccessible; }
 
   inline bool IsMenuPopup() const { return mFlags & eMenuPopupAccessible; }
 
   inline bool IsRoot() const { return mFlags & eRootAccessible; }
   nsRootAccessible* AsRoot();
 
+  virtual mozilla::a11y::TableAccessible* AsTable() { return nsnull; }
+
   inline bool IsTextLeaf() const { return mFlags & eTextLeafAccessible; }
   nsTextAccessible* AsTextLeaf();
 
   //////////////////////////////////////////////////////////////////////////////
   // ActionAccessible
 
   /**
    * Return the number of actions that can be performed on this accessible.
--- a/accessible/src/base/nsRootAccessible.h
+++ b/accessible/src/base/nsRootAccessible.h
@@ -36,25 +36,23 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _nsRootAccessible_H_
 #define _nsRootAccessible_H_
 
 #include "nsCaretAccessible.h"
 #include "nsDocAccessibleWrap.h"
 
-#ifdef MOZ_XUL
-#include "nsXULTreeAccessible.h"
-#endif
 
 #include "nsHashtable.h"
 #include "nsCaretAccessible.h"
 #include "nsIDocument.h"
 #include "nsIDOMEventListener.h"
 
+class nsXULTreeAccessible;
 class Relation;
 
 #define NS_ROOTACCESSIBLE_IMPL_CID                      \
 {  /* eaba2cf0-21b1-4e2b-b711-d3a89dcd5e1a */           \
   0xeaba2cf0,                                           \
   0x21b1,                                               \
   0x4e2b,                                               \
   { 0xb7, 0x11, 0xd3, 0xa8, 0x9d, 0xcd, 0x5e, 0x1a }    \
new file mode 100644
--- /dev/null
+++ b/accessible/src/generic/TableAccessible.h
@@ -0,0 +1,170 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef TABLE_ACCESSIBLE_H
+#define TABLE_ACCESSIBLE_H
+
+#include "nsString.h"
+#include "nsTArray.h"
+#include "prtypes.h"
+
+class nsAccessible;
+
+namespace mozilla {
+namespace a11y {
+
+/**
+ * Accessible table interface.
+ */
+class TableAccessible
+{
+public:
+
+  /**
+   * Return the caption accessible if any for this table.
+   */
+  virtual nsAccessible* Caption() { return nsnull; }
+
+  /**
+   * Get the summary for this table.
+   */
+  virtual void Summary(nsString& aSummary) { aSummary.Truncate(); }
+
+  /**
+   * Return the number of columns in the table.
+   */
+  virtual PRUint32 ColCount() { return 0; }
+
+  /**
+   * Return the number of rows in the table.
+   */
+  virtual PRUint32 RowCount() { return 0; }
+
+  /**
+   * Return the accessible for the cell at the given row and column indices.
+   */
+  virtual nsAccessible* CellAt(PRUint32 aRowIdx, PRUint32 aColIdx) { return nsnull; }
+
+  /**
+   * Return the index of the cell at the given row and column.
+   */
+  virtual PRInt32 CellIndexAt(PRUint32 aRowIdx, PRUint32 aColIdx) { return -1; }
+
+  /**
+   * Return the column index of the cell with the given index.
+   */
+  virtual PRInt32 ColIndexAt(PRUint32 aCellIdx) { return -1; }
+
+  /**
+   * Return the row index of the cell with the given index.
+   */
+  virtual PRInt32 RowIndexAt(PRUint32 aCellIdx) { return -1; }
+
+  /**
+   * Get the row and column indices for the cell at the given index.
+   */
+  virtual void RowAndColIndicesAt(PRUint32 aCellIdx, PRInt32* aRowIdx,
+                                  PRInt32* aColIdx) {}
+
+  /**
+   * Return the number of columns occupied by the cell at the given row and
+   * column indices.
+   */
+  virtual PRUint32 ColExtentAt(PRUint32 aRowIdx, PRUint32 aColIdx) { return 1; }
+
+  /**
+   * Return the number of rows occupied by the cell at the given row and column
+   * indices.
+   */
+  virtual PRUint32 RowExtentAt(PRUint32 aRowIdx, PRUint32 aColIdx) { return 1; }
+
+  /**
+   * Get the description of the given column.
+   */
+  virtual void ColDescription(PRUint32 aColIdx, nsString& aDescription)
+    { aDescription.Truncate(); }
+
+  /**
+   * Get the description for the given row.
+   */
+  virtual void RowDescription(PRUint32 aRowIdx, nsString& aDescription)
+    { aDescription.Truncate(); }
+
+  /**
+   * Return true if the given column is selected.
+   */
+  virtual bool IsColSelected(PRUint32 aColIdx) { return false; }
+
+  /**
+   * Return true if the given row is selected.
+   */
+  virtual bool IsRowSelected(PRUint32 aRowIdx) { return false; }
+
+  /**
+   * Return true if the given cell is selected.
+   */
+  virtual bool IsCellSelected(PRUint32 aRowIdx, PRUint32 aColIdx) { return false; }
+
+  /**
+   * Return the number of selected cells.
+   */
+  virtual PRUint32 SelectedCellCount() { return 0; }
+
+  /**
+   * Return the number of selected columns.
+   */
+  virtual PRUint32 SelectedColCount() { return 0; }
+
+  /**
+   * Return the number of selected rows.
+   */
+  virtual PRUint32 SelectedRowCount() { return 0; }
+
+  /**
+   * Get the set of selected cells.
+   */
+  virtual void SelectedCells(nsTArray<nsAccessible*>* aCells) {}
+
+  /**
+   * Get the set of selected column indices.
+   */
+  virtual void SelectedColIndices(nsTArray<PRUint32>* aCols) {}
+
+  /**
+   * Get the set of selected row indices.
+   */
+  virtual void SelectedRowIndices(nsTArray<PRUint32>* aRows) {}
+
+  /**
+   * Select the given column unselecting any other selected columns.
+   */
+  virtual void SelectCol(PRUint32 aColIdx) {}
+
+  /**
+   * Select the given row unselecting all other previously selected rows.
+   */
+  virtual void SelectRow(PRUint32 aRowIdx) {}
+
+  /**
+   * Unselect the given column leaving other selected columns selected.
+   */
+  virtual void UnselectCol(PRUint32 aColIdx) {}
+
+  /**
+   * Unselect the given row leaving other selected rows selected.
+   */
+  virtual void UnselectRow(PRUint32 aRowIdx) {}
+
+  /**
+   * Return true if the table is probably for layout.
+   */
+  virtual bool IsProbablyLayoutTable() { return false; }
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
--- a/accessible/src/html/Makefile.in
+++ b/accessible/src/html/Makefile.in
@@ -68,11 +68,13 @@ EXPORTS = \
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES = \
   -I$(srcdir)/../base \
+  -I$(srcdir)/../generic \
+  -I$(srcdir)/../xpcom \
   -I$(srcdir)/../../../layout/generic \
   -I$(srcdir)/../../../layout/xul/base/src \
   $(NULL)
--- a/accessible/src/html/nsHTMLTableAccessible.cpp
+++ b/accessible/src/html/nsHTMLTableAccessible.cpp
@@ -431,26 +431,36 @@ nsHTMLTableHeaderCellAccessible::NativeR
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLTableAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsHTMLTableAccessible::
   nsHTMLTableAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
-  nsAccessibleWrap(aContent, aDoc)
+  nsAccessibleWrap(aContent, aDoc), xpcAccessibleTable(this)
 {
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLTableAccessible: nsISupports implementation
 
 NS_IMPL_ISUPPORTS_INHERITED2(nsHTMLTableAccessible, nsAccessible,
                              nsHTMLTableAccessible, nsIAccessibleTable)
 
+////////////////////////////////////////////////////////////////////////////////
+//nsAccessNode
+
+void
+nsHTMLTableAccessible::Shutdown()
+{
+  mTable = nsnull;
+  nsAccessibleWrap::Shutdown();
+}
+
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLTableAccessible: nsAccessible implementation
 
 void
 nsHTMLTableAccessible::CacheChildren()
 {
   // Move caption accessible so that it's the first child. Check for the first
@@ -506,19 +516,17 @@ nsHTMLTableAccessible::GetNameInternal(n
 }
 
 nsresult
 nsHTMLTableAccessible::GetAttributesInternal(nsIPersistentProperties *aAttributes)
 {
   nsresult rv = nsAccessibleWrap::GetAttributesInternal(aAttributes);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  bool isProbablyForLayout;
-  IsProbablyForLayout(&isProbablyForLayout);
-  if (isProbablyForLayout) {
+  if (IsProbablyLayoutTable()) {
     nsAutoString oldValueUnused;
     aAttributes->SetStringProperty(NS_LITERAL_CSTRING("layout-guess"),
                                    NS_LITERAL_STRING("true"), oldValueUnused);
   }
   
   return NS_OK;
 }
 
@@ -533,23 +541,21 @@ nsHTMLTableAccessible::RelationByType(PR
     rel.AppendTarget(Caption());
 
   return rel;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLTableAccessible: nsIAccessibleTable implementation
 
-NS_IMETHODIMP
-nsHTMLTableAccessible::GetCaption(nsIAccessible **aCaption)
+nsAccessible*
+nsHTMLTableAccessible::Caption()
 {
-  NS_ENSURE_ARG_POINTER(aCaption);
-
-  NS_IF_ADDREF(*aCaption = Caption());
-  return NS_OK;
+  nsAccessible* child = mChildren.SafeElementAt(0, nsnull);
+  return child && child->Role() == roles::CAPTION ? child : nsnull;
 }
 
 NS_IMETHODIMP
 nsHTMLTableAccessible::GetSummary(nsAString &aSummary)
 {
   nsCOMPtr<nsIDOMHTMLTableElement> table(do_QueryInterface(mContent));
   NS_ENSURE_TRUE(table, NS_ERROR_FAILURE);
 
@@ -1302,18 +1308,17 @@ nsHTMLTableAccessible::Description(nsStr
         mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::summary,
                           aDescription);
       }
     }
   }
 
 #ifdef SHOW_LAYOUT_HEURISTIC
   if (aDescription.IsEmpty()) {
-    bool isProbablyForLayout;
-    IsProbablyForLayout(&isProbablyForLayout);
+    bool isProbablyForLayout = IsProbablyLayoutTable();
     aDescription = mLayoutHeuristic;
   }
 #ifdef DEBUG_A11Y
   printf("\nTABLE: %s\n", NS_ConvertUTF16toUTF8(mLayoutHeuristic).get());
 #endif
 #endif
 }
 
@@ -1352,41 +1357,39 @@ nsHTMLTableAccessible::HasDescendant(con
   // performance problems only. Note, currently 'aAllowEmpty' flag is used for
   // caption element only. On another hand we create accessible object for
   // the first entry of caption element (see
   // nsHTMLTableAccessible::CacheChildren).
   nodeList->Item(1, getter_AddRefs(foundItem));
   return !!foundItem;
 }
 
-NS_IMETHODIMP
-nsHTMLTableAccessible::IsProbablyForLayout(bool *aIsProbablyForLayout)
+bool
+nsHTMLTableAccessible::IsProbablyLayoutTable()
 {
   // Implement a heuristic to determine if table is most likely used for layout
   // XXX do we want to look for rowspan or colspan, especialy that span all but a couple cells
   // at the beginning or end of a row/col, and especially when they occur at the edge of a table?
   // XXX expose this info via object attributes to AT-SPI
 
   // XXX For now debugging descriptions are always on via SHOW_LAYOUT_HEURISTIC
   // This will allow release trunk builds to be used by testers to refine the algorithm
   // Change to |#define SHOW_LAYOUT_HEURISTIC DEBUG| before final release
 #ifdef SHOW_LAYOUT_HEURISTIC
 #define RETURN_LAYOUT_ANSWER(isLayout, heuristic) \
-  { *aIsProbablyForLayout = isLayout; \
-    mLayoutHeuristic = isLayout ? NS_LITERAL_STRING("layout table: ") : NS_LITERAL_STRING("data table: "); \
-    mLayoutHeuristic += NS_LITERAL_STRING(heuristic); return NS_OK; }
+  { \
+    mLayoutHeuristic = isLayout ? \
+      NS_LITERAL_STRING("layout table: " heuristic) : \
+      NS_LITERAL_STRING("data table: " heuristic); \
+    return isLayout; \
+  }
 #else
-#define RETURN_LAYOUT_ANSWER(isLayout, heuristic) { *aIsProbablyForLayout = isLayout; return NS_OK; }
+#define RETURN_LAYOUT_ANSWER(isLayout, heuristic) { return isLayout; }
 #endif
 
-  *aIsProbablyForLayout = false;
-
-  if (IsDefunct())
-    return NS_ERROR_FAILURE;
-
   nsDocAccessible* docAccessible = Document();
   if (docAccessible) {
     PRUint64 docState = docAccessible->State();
     if (docState & states::EDITABLE) {  // Need to see all elements while document is being edited
       RETURN_LAYOUT_ANSWER(false, "In editable document");
     }
   }
 
--- a/accessible/src/html/nsHTMLTableAccessible.h
+++ b/accessible/src/html/nsHTMLTableAccessible.h
@@ -36,16 +36,18 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _nsHTMLTableAccessible_H_
 #define _nsHTMLTableAccessible_H_
 
 #include "nsHyperTextAccessibleWrap.h"
 #include "nsIAccessibleTable.h"
+#include "TableAccessible.h"
+#include "xpcAccessibleTable.h"
 
 class nsITableLayout;
 class nsITableCellLayout;
 
 /**
  * HTML table cell accessible (html:td).
  */
 class nsHTMLTableCellAccessible : public nsHyperTextAccessibleWrap,
@@ -116,40 +118,45 @@ public:
 {  /* 8d6d9c40-74bd-47ac-88dc-4a23516aa23d */           \
   0x8d6d9c40,                                           \
   0x74bd,                                               \
   0x47ac,                                               \
   { 0x88, 0xdc, 0x4a, 0x23, 0x51, 0x6a, 0xa2, 0x3d }    \
 }
 
 class nsHTMLTableAccessible : public nsAccessibleWrap,
-                              public nsIAccessibleTable
+                              public xpcAccessibleTable,
+                              public nsIAccessibleTable,
+                              public mozilla::a11y::TableAccessible
 {
 public:
   nsHTMLTableAccessible(nsIContent* aContent, nsDocAccessible* aDoc);
 
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIACCESSIBLETABLE
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_TABLEACCESSIBLE_IMPL_CID)
 
+  // nsIAccessible Table
+  NS_DECL_OR_FORWARD_NSIACCESSIBLETABLE_WITH_XPCACCESSIBLETABLE
+
+  // TableAccessible
+  virtual nsAccessible* Caption();
+  virtual bool IsProbablyLayoutTable();
+
+  // nsAccessNode
+  virtual void Shutdown();
+
   // nsAccessible
+  virtual mozilla::a11y::TableAccessible* AsTable() { return this; }
   virtual void Description(nsString& aDescription);
   virtual nsresult GetNameInternal(nsAString& aName);
   virtual mozilla::a11y::role NativeRole();
   virtual PRUint64 NativeState();
   virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
   virtual Relation RelationByType(PRUint32 aRelationType);
 
-  // TableAccessible
-  inline nsAccessible* Caption() const
-  {
-    nsAccessible* child = mChildren.SafeElementAt(0, nsnull);
-    return child && child->Role() == mozilla::a11y::roles::CAPTION ? child : nsnull;
-  }
-
   // nsHTMLTableAccessible
 
   /**
    * Retun cell element at the given row and column index.
    */
   nsresult GetCellAt(PRInt32 aRowIndex, PRInt32 aColIndex,
                      nsIDOMElement* &aCell);
 
--- a/accessible/src/html/nsHyperTextAccessible.cpp
+++ b/accessible/src/html/nsHyperTextAccessible.cpp
@@ -127,17 +127,17 @@ role
 nsHyperTextAccessible::NativeRole()
 {
   nsIAtom *tag = mContent->Tag();
 
   if (tag == nsGkAtoms::form)
     return roles::FORM;
 
   if (tag == nsGkAtoms::blockquote || tag == nsGkAtoms::div ||
-      tag == nsGkAtoms::nav)
+      tag == nsGkAtoms::section || tag == nsGkAtoms::nav)
     return roles::SECTION;
 
   if (tag == nsGkAtoms::h1 || tag == nsGkAtoms::h2 ||
       tag == nsGkAtoms::h3 || tag == nsGkAtoms::h4 ||
       tag == nsGkAtoms::h5 || tag == nsGkAtoms::h6)
     return roles::HEADING;
 
   if (tag == nsGkAtoms::article)
@@ -1234,16 +1234,19 @@ nsHyperTextAccessible::GetAttributesInte
 
   // For the html landmark elements we expose them like we do aria landmarks to
   // make AT navigation schemes "just work". Note html:header is redundant as
   // a landmark since it usually contains headings. We're not yet sure how the
   // web will use html:footer but our best bet right now is as contentinfo.
   if (mContent->Tag() == nsGkAtoms::nav)
     nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
                            NS_LITERAL_STRING("navigation"));
+  else if (mContent->Tag() == nsGkAtoms::section) 
+    nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
+                           NS_LITERAL_STRING("region"));
   else if (mContent->Tag() == nsGkAtoms::footer) 
     nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
                            NS_LITERAL_STRING("contentinfo"));
   else if (mContent->Tag() == nsGkAtoms::aside) 
     nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
                            NS_LITERAL_STRING("complementary"));
 
   return  NS_OK;
--- a/accessible/src/msaa/Makefile.in
+++ b/accessible/src/msaa/Makefile.in
@@ -109,13 +109,15 @@ FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
   -I$(srcdir) \
   -I$(srcdir)/../base \
+  -I$(srcdir)/../generic \
   -I$(srcdir)/../html \
+  -I$(srcdir)/../xpcom \
   -I$(srcdir)/../xul \
   -I$(srcdir)/../../../content/base/src \
   -I$(srcdir)/../../../content/events/src \
   $(NULL)
--- a/accessible/src/xpcom/Makefile.in
+++ b/accessible/src/xpcom/Makefile.in
@@ -45,18 +45,20 @@ include $(DEPTH)/config/autoconf.mk
 
 MODULE = accessibility
 LIBRARY_NAME = accessibility_xpcom_s
 LIBXUL_LIBRARY = 1
 
 CPPSRCS = \
   nsAccEvent.cpp \
   nsAccessibleRelation.cpp \
+  xpcAccessibleTable.cpp \
   $(NULL)
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES = \
   -I$(srcdir)/../base \
+  -I$(srcdir)/../generic \
   $(NULL)
new file mode 100644
--- /dev/null
+++ b/accessible/src/xpcom/xpcAccessibleTable.cpp
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "xpcAccessibleTable.h"
+
+#include "nsAccessible.h"
+#include "TableAccessible.h"
+
+nsresult
+xpcAccessibleTable::GetCaption(nsIAccessible** aCaption)
+{
+  NS_ENSURE_ARG_POINTER(aCaption);
+  *aCaption = nsnull;
+  if (!mTable)
+    return NS_ERROR_FAILURE;
+
+  NS_IF_ADDREF(*aCaption = mTable->Caption());
+  return NS_OK;
+}
+
+nsresult
+xpcAccessibleTable::IsProbablyForLayout(bool* aResult)
+{
+  NS_ENSURE_ARG_POINTER(aResult);
+  *aResult = false;
+  if (!mTable)
+    return NS_ERROR_FAILURE;
+
+  *aResult = mTable->IsProbablyLayoutTable();
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/accessible/src/xpcom/xpcAccessibleTable.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MOZILLA_A11Y_XPCOM_XPACCESSIBLETABLE_H_
+#define MOZILLA_A11Y_XPCOM_XPACCESSIBLETABLE_H_
+
+#include "nscore.h"
+
+class nsIAccessible;
+namespace mozilla {
+namespace a11y {
+class TableAccessible;
+}
+}
+
+class xpcAccessibleTable
+{
+public:
+  xpcAccessibleTable(mozilla::a11y::TableAccessible* aTable) : mTable(aTable) { }
+
+  nsresult GetCaption(nsIAccessible** aCaption);
+  nsresult IsProbablyForLayout(bool* aIsForLayout);
+
+protected:
+  mozilla::a11y::TableAccessible* mTable;
+};
+
+#define NS_DECL_OR_FORWARD_NSIACCESSIBLETABLE_WITH_XPCACCESSIBLETABLE \
+  NS_IMETHOD GetCaption(nsIAccessible** aCaption) \
+    { return xpcAccessibleTable::GetCaption(aCaption); } \
+  NS_SCRIPTABLE NS_IMETHOD GetSummary(nsAString & aSummary); \
+  NS_SCRIPTABLE NS_IMETHOD GetColumnCount(PRInt32 *aColumnCount); \
+  NS_SCRIPTABLE NS_IMETHOD GetRowCount(PRInt32 *aRowCount); \
+  NS_SCRIPTABLE NS_IMETHOD GetCellAt(PRInt32 rowIndex, PRInt32 columnIndex, nsIAccessible * *_retval NS_OUTPARAM); \
+  NS_SCRIPTABLE NS_IMETHOD GetCellIndexAt(PRInt32 rowIndex, PRInt32 columnIndex, PRInt32 *_retval NS_OUTPARAM); \
+  NS_SCRIPTABLE NS_IMETHOD GetColumnIndexAt(PRInt32 cellIndex, PRInt32 *_retval NS_OUTPARAM); \
+  NS_SCRIPTABLE NS_IMETHOD GetRowIndexAt(PRInt32 cellIndex, PRInt32 *_retval NS_OUTPARAM); \
+  NS_SCRIPTABLE NS_IMETHOD GetRowAndColumnIndicesAt(PRInt32 cellIndex, PRInt32 *rowIndex NS_OUTPARAM, PRInt32 *columnIndex NS_OUTPARAM); \
+  NS_SCRIPTABLE NS_IMETHOD GetColumnExtentAt(PRInt32 row, PRInt32 column, PRInt32 *_retval NS_OUTPARAM); \
+  NS_SCRIPTABLE NS_IMETHOD GetRowExtentAt(PRInt32 row, PRInt32 column, PRInt32 *_retval NS_OUTPARAM); \
+  NS_SCRIPTABLE NS_IMETHOD GetColumnDescription(PRInt32 columnIndex, nsAString & _retval NS_OUTPARAM); \
+  NS_SCRIPTABLE NS_IMETHOD GetRowDescription(PRInt32 rowIndex, nsAString & _retval NS_OUTPARAM); \
+  NS_SCRIPTABLE NS_IMETHOD IsColumnSelected(PRInt32 columnIndex, bool *_retval NS_OUTPARAM); \
+  NS_SCRIPTABLE NS_IMETHOD IsRowSelected(PRInt32 rowIndex, bool *_retval NS_OUTPARAM); \
+  NS_SCRIPTABLE NS_IMETHOD IsCellSelected(PRInt32 rowIndex, PRInt32 columnIndex, bool *_retval NS_OUTPARAM); \
+  NS_SCRIPTABLE NS_IMETHOD GetSelectedCellCount(PRUint32 *aSelectedCellCount); \
+  NS_SCRIPTABLE NS_IMETHOD GetSelectedColumnCount(PRUint32 *aSelectedColumnCount); \
+  NS_SCRIPTABLE NS_IMETHOD GetSelectedRowCount(PRUint32 *aSelectedRowCount); \
+  NS_SCRIPTABLE NS_IMETHOD GetSelectedCells(nsIArray * *aSelectedCells); \
+  NS_SCRIPTABLE NS_IMETHOD GetSelectedCellIndices(PRUint32 *cellsArraySize NS_OUTPARAM, PRInt32 **cellsArray NS_OUTPARAM); \
+  NS_SCRIPTABLE NS_IMETHOD GetSelectedColumnIndices(PRUint32 *rowsArraySize NS_OUTPARAM, PRInt32 **rowsArray NS_OUTPARAM); \
+  NS_SCRIPTABLE NS_IMETHOD GetSelectedRowIndices(PRUint32 *rowsArraySize NS_OUTPARAM, PRInt32 **rowsArray NS_OUTPARAM); \
+  NS_SCRIPTABLE NS_IMETHOD SelectRow(PRInt32 rowIndex); \
+  NS_SCRIPTABLE NS_IMETHOD SelectColumn(PRInt32 columnIndex); \
+  NS_SCRIPTABLE NS_IMETHOD UnselectColumn(PRInt32 columnIndex); \
+  NS_IMETHOD UnselectRow(PRInt32 aRowIdx); \
+  NS_IMETHOD IsProbablyForLayout(bool* aResult) \
+  { return xpcAccessibleTable::IsProbablyForLayout(aResult); } \
+
+#endif // MOZILLA_A11Y_XPCOM_XPACCESSIBLETABLE_H_
--- a/accessible/src/xul/Makefile.in
+++ b/accessible/src/xul/Makefile.in
@@ -67,12 +67,14 @@ CPPSRCS = \
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES = \
   -I$(srcdir) \
   -I$(srcdir)/../base \
+  -I$(srcdir)/../generic \
   -I$(srcdir)/../html \
+  -I$(srcdir)/../xpcom \
   -I$(srcdir)/../../../layout/generic \
   -I$(srcdir)/../../../layout/xul/base/src \
   $(NULL)
--- a/accessible/src/xul/nsXULListboxAccessible.cpp
+++ b/accessible/src/xul/nsXULListboxAccessible.cpp
@@ -129,17 +129,17 @@ nsXULColumnItemAccessible::DoAction(PRUi
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULListboxAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsXULListboxAccessible::
   nsXULListboxAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
-  XULSelectControlAccessible(aContent, aDoc)
+  XULSelectControlAccessible(aContent, aDoc), xpcAccessibleTable(this)
 {
   nsIContent* parentContent = mContent->GetParent();
   if (parentContent) {
     nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
       do_QueryInterface(parentContent);
     if (autoCompletePopupElm)
       mFlags |= eAutoCompletePopupAccessible;
   }
@@ -159,16 +159,26 @@ nsXULListboxAccessible::QueryInterface(R
     *aInstancePtr = static_cast<nsIAccessibleTable*>(this);
     NS_ADDREF_THIS();
     return NS_OK;
   }
 
   return NS_ERROR_NO_INTERFACE;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+//nsAccessNode
+
+void
+nsXULListboxAccessible::Shutdown()
+{
+  mTable = nsnull;
+  XULSelectControlAccessible::Shutdown();
+}
+
 bool
 nsXULListboxAccessible::IsMulticolumn()
 {
   PRInt32 numColumns = 0;
   nsresult rv = GetColumnCount(&numColumns);
   if (NS_FAILED(rv))
     return false;
 
@@ -225,25 +235,16 @@ nsXULListboxAccessible::NativeRole()
 
   return IsMulticolumn() ? roles::TABLE : roles::LISTBOX;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULListboxAccessible. nsIAccessibleTable
 
 NS_IMETHODIMP
-nsXULListboxAccessible::GetCaption(nsIAccessible **aCaption)
-{
-  NS_ENSURE_ARG_POINTER(aCaption);
-  *aCaption = nsnull;
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 nsXULListboxAccessible::GetSummary(nsAString &aSummary)
 {
   aSummary.Truncate();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -815,25 +816,16 @@ nsXULListboxAccessible::UnselectRow(PRIn
 
 NS_IMETHODIMP
 nsXULListboxAccessible::UnselectColumn(PRInt32 aColumn)
 {
   // xul:listbox and xul:richlistbox support row selection only.
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsXULListboxAccessible::IsProbablyForLayout(bool *aIsProbablyForLayout)
-{
-  NS_ENSURE_ARG_POINTER(aIsProbablyForLayout);
-  *aIsProbablyForLayout = false;
-
-  return NS_OK;
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULListboxAccessible: Widgets
 
 bool
 nsXULListboxAccessible::IsWidget() const
 {
   return true;
 }
--- a/accessible/src/xul/nsXULListboxAccessible.h
+++ b/accessible/src/xul/nsXULListboxAccessible.h
@@ -35,21 +35,22 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 #ifndef __nsXULListboxAccessible_h__
 #define __nsXULListboxAccessible_h__
 
-#include "nsIAccessibleTable.h"
-
 #include "nsCOMPtr.h"
 #include "nsXULMenuAccessible.h"
 #include "nsBaseWidgetAccessible.h"
+#include "nsIAccessibleTable.h"
+#include "TableAccessible.h"
+#include "xpcAccessibleTable.h"
 #include "XULSelectControlAccessible.h"
 
 class nsIWeakReference;
 
 /**
  * nsXULColumnsAccessible are accessible for list and tree columns elements
  * (xul:treecols and xul:listcols).
  */
@@ -85,29 +86,37 @@ public:
 
   enum { eAction_Click = 0 };
 };
 
 /*
  * A class the represents the XUL Listbox widget.
  */
 class nsXULListboxAccessible : public XULSelectControlAccessible,
-                               public nsIAccessibleTable
+                               public xpcAccessibleTable,
+                               public nsIAccessibleTable,
+                               public mozilla::a11y::TableAccessible
 {
 public:
   nsXULListboxAccessible(nsIContent* aContent, nsDocAccessible* aDoc);
   virtual ~nsXULListboxAccessible() {}
 
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIACCESSIBLETABLE
+
+  // nsIAccessibleTable
+  NS_DECL_OR_FORWARD_NSIACCESSIBLETABLE_WITH_XPCACCESSIBLETABLE
 
   // nsIAccessible
   NS_IMETHOD GetValue(nsAString& aValue);
 
+  // nsAccessNode
+  virtual void Shutdown();
+
   // nsAccessible
+  virtual mozilla::a11y::TableAccessible* AsTable() { return this; }
   virtual mozilla::a11y::role NativeRole();
   virtual PRUint64 NativeState();
 
   // Widgets
   virtual bool IsWidget() const;
   virtual bool IsActiveWidget() const;
   virtual bool AreItemsOperable() const;
 
--- a/accessible/src/xul/nsXULTreeGridAccessible.cpp
+++ b/accessible/src/xul/nsXULTreeGridAccessible.cpp
@@ -53,40 +53,31 @@
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeGridAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsXULTreeGridAccessible::
   nsXULTreeGridAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
-  nsXULTreeAccessible(aContent, aDoc)
+  nsXULTreeAccessible(aContent, aDoc), xpcAccessibleTable(this)
 {
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeGridAccessible: nsISupports implementation
 
 NS_IMPL_ISUPPORTS_INHERITED1(nsXULTreeGridAccessible,
                              nsXULTreeAccessible,
                              nsIAccessibleTable)
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeGridAccessible: nsIAccessibleTable implementation
 
 NS_IMETHODIMP
-nsXULTreeGridAccessible::GetCaption(nsIAccessible **aCaption)
-{
-  NS_ENSURE_ARG_POINTER(aCaption);
-  *aCaption = nsnull;
-
-  return IsDefunct() ? NS_ERROR_FAILURE : NS_OK;
-}
-
-NS_IMETHODIMP
 nsXULTreeGridAccessible::GetSummary(nsAString &aSummary)
 {
   aSummary.Truncate();
   return IsDefunct() ? NS_ERROR_FAILURE : NS_OK;
 }
 
 NS_IMETHODIMP
 nsXULTreeGridAccessible::GetColumnCount(PRInt32 *aColumnCount)
@@ -565,23 +556,24 @@ nsXULTreeGridAccessible::UnselectRow(PRI
 }
 
 NS_IMETHODIMP
 nsXULTreeGridAccessible::UnselectColumn(PRInt32 aColumnIndex)
 {
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsXULTreeGridAccessible::IsProbablyForLayout(bool *aIsProbablyForLayout)
+////////////////////////////////////////////////////////////////////////////////
+// nsXULTreeGridAccessible: nsAccessNode implementation
+
+void
+nsXULTreeGridAccessible::Shutdown()
 {
-  NS_ENSURE_ARG_POINTER(aIsProbablyForLayout);
-  *aIsProbablyForLayout = false;
-
-  return NS_OK;
+  mTable = nsnull;
+  nsXULTreeAccessible::Shutdown();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULTreeGridAccessible: nsAccessible implementation
 
 role
 nsXULTreeGridAccessible::NativeRole()
 {
--- a/accessible/src/xul/nsXULTreeGridAccessible.h
+++ b/accessible/src/xul/nsXULTreeGridAccessible.h
@@ -34,36 +34,42 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef __nsXULTreeGridAccessible_h__
 #define __nsXULTreeGridAccessible_h__
 
-#include "nsIAccessibleTable.h"
-
 #include "nsXULTreeAccessible.h"
+#include "TableAccessible.h"
+#include "xpcAccessibleTable.h"
 
 /**
  * Represents accessible for XUL tree in the case when it has multiple columns.
  */
 class nsXULTreeGridAccessible : public nsXULTreeAccessible,
-                                public nsIAccessibleTable
+                                public xpcAccessibleTable,
+                                public nsIAccessibleTable,
+                                public mozilla::a11y::TableAccessible
 {
 public:
   nsXULTreeGridAccessible(nsIContent* aContent, nsDocAccessible* aDoc);
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIAccessibleTable
-  NS_DECL_NSIACCESSIBLETABLE
+  NS_DECL_OR_FORWARD_NSIACCESSIBLETABLE_WITH_XPCACCESSIBLETABLE
+
+  // nsAccessNode
+  virtual void Shutdown();
 
   // nsAccessible
+  virtual mozilla::a11y::TableAccessible* AsTable() { return this; }
   virtual mozilla::a11y::role NativeRole();
 
 protected:
 
   // nsXULTreeAccessible
   virtual already_AddRefed<nsAccessible> CreateTreeItemAccessible(PRInt32 aRow);
 };
 
--- a/accessible/tests/mochitest/elm/test_landmarks.html
+++ b/accessible/tests/mochitest/elm/test_landmarks.html
@@ -19,33 +19,36 @@
 
     function doTest()
     {
       testRole("nav", ROLE_SECTION);
       testRole("header", ROLE_HEADER);
       testRole("footer", ROLE_FOOTER);
       testRole("article", ROLE_DOCUMENT);
       testRole("aside", ROLE_NOTE);
+      testRole("section", ROLE_SECTION); // XXX bug 739612: not a landmark
 
       testRole("main", ROLE_DOCUMENT);
       testRole("form", ROLE_FORM);
 
       // Some AT may look for this
       testAttrs("nav", {"xml-roles" : "navigation"}, true);
       testAttrs("footer", {"xml-roles" : "contentinfo"}, true);
       testAttrs("aside", {"xml-roles" : "complementary"}, true);
+      testAttrs("section", {"xml-roles" : "region"}, true);
       testAttrs("main", {"xml-roles" : "main"}, true); // // ARIA override
       testAttrs("form", {"xml-roles" : "form"}, true);
 
       // And some AT may look for this
       testAttrs("nav", {"tag" : "nav"}, true);
       testAttrs("header", {"tag" : "header"}, true);
       testAttrs("footer", {"tag" : "footer"}, true);
       testAttrs("article", {"tag" : "article"}, true);
       testAttrs("aside", {"tag" : "aside"}, true);
+      testAttrs("section", {"tag" : "section"}, true);
       testAttrs("main", {"tag" : "article"}, true);
       testAttrs("form", {"tag" : "article"}, true);
 
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
@@ -64,28 +67,34 @@
     Bug 613502
   </a>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=610650"
      title="Change implementation of HTML5 landmark elements to conform">
     Bug 610650
   </a>
   <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=614310"
+     title="Map section to pane (like role=region)">
+    Mozilla Bug 614310
+  </a>
+  <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=734982"
      title="Map ARIA role FORM">
     Bug 734982
   </a>
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <nav id="nav">a nav</nav>
   <header id="header">a header</header>
   <footer id="footer">a footer</footer>
   <aside id="aside">by the way I am an aside</aside>
+  <section id="section">a section</section>
 
   <article id="article">an article</article>
   <article id="main" role="main">a main area</article>
   <article id="form" role="form">a form area</article>
 
 </body>
 </html>
--- a/accessible/tests/mochitest/role.js
+++ b/accessible/tests/mochitest/role.js
@@ -48,16 +48,17 @@ const ROLE_PAGETABLIST = nsIAccessibleRo
 const ROLE_PANE = nsIAccessibleRole.ROLE_PANE;
 const ROLE_PARAGRAPH = nsIAccessibleRole.ROLE_PARAGRAPH;
 const ROLE_PARENT_MENUITEM = nsIAccessibleRole.ROLE_PARENT_MENUITEM;
 const ROLE_PASSWORD_TEXT = nsIAccessibleRole.ROLE_PASSWORD_TEXT;
 const ROLE_PROGRESSBAR = nsIAccessibleRole.ROLE_PROGRESSBAR;
 const ROLE_PROPERTYPAGE = nsIAccessibleRole.ROLE_PROPERTYPAGE;
 const ROLE_PUSHBUTTON = nsIAccessibleRole.ROLE_PUSHBUTTON;
 const ROLE_RADIOBUTTON = nsIAccessibleRole.ROLE_RADIOBUTTON;
+const ROLE_RICH_OPTION = nsIAccessibleRole.ROLE_RICH_OPTION;
 const ROLE_ROW = nsIAccessibleRole.ROLE_ROW;
 const ROLE_ROWHEADER = nsIAccessibleRole.ROLE_ROWHEADER;
 const ROLE_SCROLLBAR = nsIAccessibleRole.ROLE_SCROLLBAR;
 const ROLE_SECTION = nsIAccessibleRole.ROLE_SECTION;
 const ROLE_SEPARATOR = nsIAccessibleRole.ROLE_SEPARATOR;
 const ROLE_SLIDER = nsIAccessibleRole.ROLE_SLIDER;
 const ROLE_STATICTEXT = nsIAccessibleRole.ROLE_STATICTEXT;
 const ROLE_TABLE = nsIAccessibleRole.ROLE_TABLE;
--- a/accessible/tests/mochitest/treeupdate/Makefile.in
+++ b/accessible/tests/mochitest/treeupdate/Makefile.in
@@ -52,16 +52,17 @@ include $(topsrcdir)/config/rules.mk
 		test_cssoverflow.html \
 		test_contextmenu.xul \
 		test_doc.html \
 		test_gencontent.html \
 		test_hidden.html \
 		test_imagemap.html \
 		test_list_editabledoc.html \
 		test_list.html \
+		test_listbox.xul \
 		test_menu.xul \
 		test_menubutton.xul \
 		test_recreation.html \
 		test_select.html \
 		test_textleaf.html \
 		test_visibility.html \
 		test_whitespace.html \
 		$(NULL)
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_listbox.xul
@@ -0,0 +1,180 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+                 type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        title="Accessible XUL listbox hierarchy tests">
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+
+  <script type="application/javascript"
+          src="../common.js" />
+  <script type="application/javascript"
+          src="../role.js" />
+  <script type="application/javascript"
+          src="../events.js" />
+
+  <script type="application/javascript">
+  <![CDATA[
+    ////////////////////////////////////////////////////////////////////////////
+    // Test
+
+    function insertListitem(aListboxID)
+    {
+      this.listboxNode = getNode(aListboxID);
+
+      this.listitemNode = document.createElement("listitem");
+      this.listitemNode.setAttribute("label", "item1");
+
+      this.eventSeq = [
+        new invokerChecker(EVENT_SHOW, this.listitemNode),
+        new invokerChecker(EVENT_REORDER, this.listboxNode)
+      ];
+
+      this.invoke = function insertListitem_invoke()
+      {
+        this.listboxNode.insertBefore(this.listitemNode,
+                                      this.listboxNode.firstChild);
+      }
+
+      this.finalCheck = function insertListitem_finalCheck()
+      {
+        var tree =
+          { LISTBOX: [
+            {
+              role: ROLE_RICH_OPTION,
+              name: "item1"
+            },
+            {
+              role: ROLE_RICH_OPTION,
+              name: "item2"
+            },
+            {
+              role: ROLE_RICH_OPTION,
+              name: "item3"
+            },
+            {
+              role: ROLE_RICH_OPTION,
+              name: "item4"
+            }
+          ] };
+        testAccessibleTree(this.listboxNode, tree);
+      }
+
+      this.getID = function insertListitem_getID()
+      {
+        return "insert listitem ";
+      }
+    }
+
+    function removeListitem(aListboxID)
+    {
+      this.listboxNode = getNode(aListboxID);
+      this.listitemNode = null;
+      this.listitem;
+
+      function getListitem(aThisObj)
+      {
+        return aThisObj.listitem;
+      }
+
+      this.eventSeq = [
+        new invokerChecker(EVENT_HIDE, getListitem, this),
+        new invokerChecker(EVENT_REORDER, this.listboxNode)
+      ];
+
+      this.invoke = function removeListitem_invoke()
+      {
+        this.listitemNode = this.listboxNode.firstChild;
+        this.listitem = getAccessible(this.listitemNode);
+
+        this.listboxNode.removeChild(this.listitemNode);
+      }
+
+      this.finalCheck = function removeListitem_finalCheck()
+      {
+        var tree =
+          { LISTBOX: [
+            {
+              role: ROLE_RICH_OPTION,
+              name: "item2"
+            },
+            {
+              role: ROLE_RICH_OPTION,
+              name: "item3"
+            },
+            {
+              role: ROLE_RICH_OPTION,
+              name: "item4"
+            }
+          ] };
+        testAccessibleTree(this.listboxNode, tree);
+      }
+
+      this.getID = function removeListitem_getID()
+      {
+        return "remove listitem ";
+      }
+    }
+
+    //gA11yEventDumpToConsole = true; // debug stuff
+
+    var gQueue = null;
+    function doTest()
+    {
+      var tree =
+        { LISTBOX: [
+          {
+            role: ROLE_RICH_OPTION,
+            name: "item2"
+          },
+          {
+            role: ROLE_RICH_OPTION,
+            name: "item3"
+          },
+          {
+            role: ROLE_RICH_OPTION,
+            name: "item4"
+          }
+        ] };
+      testAccessibleTree("listbox", tree);
+
+      gQueue = new eventQueue();
+      gQueue.push(new insertListitem("listbox"));
+      gQueue.push(new removeListitem("listbox"));
+      gQueue.invoke(); // Will call SimpleTest.finish()
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  ]]>
+  </script>
+
+  <hbox flex="1" style="overflow: auto;">
+    <body xmlns="http://www.w3.org/1999/xhtml">
+      <a target="_blank"
+         href="https://bugzilla.mozilla.org/show_bug.cgi?id=656225"
+         title="XUL listbox accessible tree doesn't get updated">
+        Mozilla Bug 656225
+      </a>
+      <br/>
+      <p id="display"></p>
+      <div id="content" style="display: none">
+      </div>
+      <pre id="test">
+      </pre>
+    </body>
+
+    <vbox flex="1">
+      <listbox id="listbox" rows="2">
+        <listitem label="item2"/>
+        <listitem label="item3"/>
+        <listitem label="item4"/>
+      </listbox>
+    </vbox>
+  </hbox>
+
+</window>
+
--- a/b2g/confvars.sh
+++ b/b2g/confvars.sh
@@ -64,8 +64,9 @@ if test "$LIBXUL_SDK"; then
 MOZ_XULRUNNER=1
 else
 MOZ_XULRUNNER=
 MOZ_PLACES=1
 fi
 
 MOZ_APP_ID={3c2e2abc-06d4-11e1-ac3b-374f68613e61}
 MOZ_EXTENSION_MANAGER=1
+ENABLE_MARIONETTE=1
--- a/browser/Makefile.in
+++ b/browser/Makefile.in
@@ -51,23 +51,24 @@ PARALLEL_DIRS = \
   themes \
   $(NULL)
 
 DIRS = \
   devtools \
   app \
   $(NULL)
 
-ifeq ($(OS_ARCH),WINNT)
+ifdef MAKENSISU
 DIRS += installer/windows
 endif
 
 include $(topsrcdir)/config/rules.mk
 
-ifeq ($(OS_ARCH),WINNT)
+ifdef MAKENSISU
+
 # For Windows build the uninstaller during the application build since the
 # uninstaller is included with the application for mar file generation.
 libs::
 	$(MAKE) -C installer/windows uninstaller
 ifdef MOZ_MAINTENANCE_SERVICE
 	$(MAKE) -C installer/windows maintenanceservice_installer
 endif
 endif
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -4408,32 +4408,29 @@ var FullScreen = {
       gNavToolbox.setAttribute("inFullscreen", true);
       document.documentElement.setAttribute("inFullscreen", true);
     }
 
     // In tabs-on-top mode, move window controls to the tab bar,
     // and in tabs-on-bottom mode, move them back to the navigation toolbar.
     // When there is a chance the tab bar may be collapsed, put window
     // controls on nav bar.
-    var fullscreenflex = document.getElementById("fullscreenflex");
     var fullscreenctls = document.getElementById("window-controls");
     var navbar = document.getElementById("nav-bar");
     var ctlsOnTabbar = window.toolbar.visible &&
                        (navbar.collapsed ||
                           (TabsOnTop.enabled &&
                            !gPrefService.getBoolPref("browser.tabs.autoHide")));
     if (fullscreenctls.parentNode == navbar && ctlsOnTabbar) {
+      fullscreenctls.removeAttribute("flex");
       document.getElementById("TabsToolbar").appendChild(fullscreenctls);
-      // we don't need this space in tabs-on-top mode, so prevent it from 
-      // being shown
-      fullscreenflex.removeAttribute("fullscreencontrol");
     }
     else if (fullscreenctls.parentNode.id == "TabsToolbar" && !ctlsOnTabbar) {
+      fullscreenctls.setAttribute("flex", "1");
       navbar.appendChild(fullscreenctls);
-      fullscreenflex.setAttribute("fullscreencontrol", "true");
     }
 
     var controls = document.getElementsByAttribute("fullscreencontrol", "true");
     for (var i = 0; i < controls.length; ++i)
       controls[i].hidden = aShow;
   }
 };
 XPCOMUtils.defineLazyGetter(FullScreen, "useLionFullScreen", function() {
@@ -8661,16 +8658,41 @@ let gPrivateBrowsingUI = {
         return;
 
     this._privateBrowsingService.privateBrowsingEnabled =
       !this.privateBrowsingEnabled;
   },
 
   get privateBrowsingEnabled() {
     return this._privateBrowsingService.privateBrowsingEnabled;
+  },
+
+  /**
+   * These accessors are used to support per-window Private Browsing mode.
+   * For now the getter returns nsIPrivateBrowsingService.privateBrowsingEnabled,
+   * and the setter should only be used in tests.
+   */
+  get privateWindow() {
+    return window.getInterface(Ci.nsIWebNavigation)
+                 .QueryInterface(Ci.nsIDocShellTreeItem)
+                 .treeOwner
+                 .QueryInterface(Ci.nsIInterfaceRequestor)
+                 .getInterface(Ci.nsIXULWindow)
+                 .docShell.QueryInterface(Ci.nsILoadContext)
+                 .usePrivateBrowsing;
+  },
+
+  set privateWindow(val) {
+    return window.getInterface(Ci.nsIWebNavigation)
+                 .QueryInterface(Ci.nsIDocShellTreeItem)
+                 .treeOwner
+                 .QueryInterface(Ci.nsIInterfaceRequestor)
+                 .getInterface(Ci.nsIXULWindow)
+                 .docShell.QueryInterface(Ci.nsILoadContext)
+                 .usePrivateBrowsing = val;
   }
 };
 
 var LightWeightThemeWebInstaller = {
   handleEvent: function (event) {
     switch (event.type) {
       case "InstallBrowserTheme":
       case "PreviewBrowserTheme":
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -470,17 +470,17 @@
       <hbox class="titlebar-placeholder" type="caption-buttons" ordinal="1000"/>
 #endif
     </toolbar>
 
     <toolbar id="nav-bar" class="toolbar-primary chromeclass-toolbar"
              toolbarname="&navbarCmd.label;" accesskey="&navbarCmd.accesskey;"
              fullscreentoolbar="true" mode="icons" customizable="true"
              iconsize="large"
-             defaultset="unified-back-forward-button,urlbar-container,reload-button,stop-button,search-container,home-button,bookmarks-menu-button-container,fullscreenflex,window-controls"
+             defaultset="unified-back-forward-button,urlbar-container,reload-button,stop-button,search-container,home-button,bookmarks-menu-button-container,window-controls"
              context="toolbar-context-menu">
 
       <toolbaritem id="unified-back-forward-button" class="chromeclass-toolbar-additional"
                    context="backForwardMenu" removable="true"
                    forwarddisabled="true"
                    title="&backForwardItem.title;">
         <toolbarbutton id="back-button" class="toolbarbutton-1"
                        label="&backCmd.label;"
@@ -692,18 +692,17 @@
             <menuitem id="BMB_unsortedBookmarks"
                       label="&bookmarksMenuButton.unsorted.label;"
                       oncommand="PlacesCommandHook.showPlacesOrganizer('UnfiledBookmarks');"
                       class="menuitem-iconic"/>
           </menupopup>
         </toolbarbutton>
       </toolbaritem>
 
-      <hbox id="fullscreenflex" flex="1" hidden="true" fullscreencontrol="true"/>
-      <hbox id="window-controls" hidden="true" fullscreencontrol="true">
+      <hbox id="window-controls" hidden="true" fullscreencontrol="true" pack="end">
         <toolbarbutton id="minimize-button"
                        tooltiptext="&fullScreenMinimize.tooltip;"
                        oncommand="window.minimize();"/>
 
         <toolbarbutton id="restore-button"
                        tooltiptext="&fullScreenRestore.tooltip;"
                        oncommand="BrowserFullScreen();"/>
 
--- a/browser/base/content/newtab/drop.js
+++ b/browser/base/content/newtab/drop.js
@@ -39,31 +39,30 @@ let gDrop = {
       this._rearrange();
     }
   },
 
   /**
    * Handles the 'drop' event.
    * @param aCell The drop target cell.
    * @param aEvent The 'dragexit' event.
-   * @param aCallback The callback to call when the drop is finished.
    */
-  drop: function Drop_drop(aCell, aEvent, aCallback) {
+  drop: function Drop_drop(aCell, aEvent) {
     // The cell that is the drop target could contain a pinned site. We need
     // to find out where that site has gone and re-pin it there.
     if (aCell.containsPinnedSite())
       this._repinSitesAfterDrop(aCell);
 
     // Pin the dragged or insert the new site.
     this._pinDraggedSite(aCell, aEvent);
 
     this._cancelDelayedArrange();
 
     // Update the grid and move all sites to their new places.
-    gUpdater.updateGrid(aCallback);
+    gUpdater.updateGrid();
   },
 
   /**
    * Re-pins all pinned sites in their (new) positions.
    * @param aCell The drop target cell.
    */
   _repinSitesAfterDrop: function Drop_repinSitesAfterDrop(aCell) {
     let sites = gDropPreview.rearrange(aCell);
--- a/browser/base/content/newtab/sites.js
+++ b/browser/base/content/newtab/sites.js
@@ -56,46 +56,44 @@ Site.prototype = {
       aIndex = this.cell.index;
 
     this._updateAttributes(true);
     gPinnedLinks.pin(this._link, aIndex);
   },
 
   /**
    * Unpins the site and calls the given callback when done.
-   * @param aCallback The callback to be called when finished.
    */
-  unpin: function Site_unpin(aCallback) {
+  unpin: function Site_unpin() {
     if (this.isPinned()) {
       this._updateAttributes(false);
       gPinnedLinks.unpin(this._link);
-      gUpdater.updateGrid(aCallback);
+      gUpdater.updateGrid();
     }
   },
 
   /**
    * Checks whether this site is pinned.
    * @return Whether this site is pinned.
    */
   isPinned: function Site_isPinned() {
     return gPinnedLinks.isPinned(this._link);
   },
 
   /**
    * Blocks the site (removes it from the grid) and calls the given callback
    * when done.
-   * @param aCallback The function to be called when finished.
    */
-  block: function Site_block(aCallback) {
+  block: function Site_block() {
     if (gBlockedLinks.isBlocked(this._link)) {
       if (aCallback)
         aCallback();
     } else {
       gBlockedLinks.block(this._link);
-      gUpdater.updateGrid(aCallback);
+      gUpdater.updateGrid();
     }
   },
 
   /**
    * Gets the DOM node specified by the given query selector.
    * @param aSelector The query selector.
    * @return The DOM node we found.
    */
--- a/browser/base/content/test/newtab/browser_newtab_block.js
+++ b/browser/base/content/test/newtab/browser_newtab_block.js
@@ -10,52 +10,52 @@ function runTests() {
   // we remove sites and expect the gaps to be filled as long as there still
   // are some sites available
   setLinks("0,1,2,3,4,5,6,7,8,9");
   setPinnedLinks("");
 
   yield addNewTabPageTab();
   checkGrid("0,1,2,3,4,5,6,7,8");
 
-  yield blockCell(cells[4]);
+  yield blockCell(4);
   checkGrid("0,1,2,3,5,6,7,8,9");
 
-  yield blockCell(cells[4]);
+  yield blockCell(4);
   checkGrid("0,1,2,3,6,7,8,9,");
 
-  yield blockCell(cells[4]);
+  yield blockCell(4);
   checkGrid("0,1,2,3,7,8,9,,");
 
   // we removed a pinned site
   yield restore();
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks(",1");
 
   yield addNewTabPageTab();
   checkGrid("0,1p,2,3,4,5,6,7,8");
 
-  yield blockCell(cells[1]);
+  yield blockCell(1);
   checkGrid("0,2,3,4,5,6,7,8,");
 
   // we remove the last site on the grid (which is pinned) and expect the gap
   // to be re-filled and the new site to be unpinned
   yield restore();
   setLinks("0,1,2,3,4,5,6,7,8,9");
   setPinnedLinks(",,,,,,,,8");
 
   yield addNewTabPageTab();
   checkGrid("0,1,2,3,4,5,6,7,8p");
 
-  yield blockCell(cells[8]);
+  yield blockCell(8);
   checkGrid("0,1,2,3,4,5,6,7,9");
 
   // we remove the first site on the grid with the last one pinned. all cells
   // but the last one should shift to the left and a new site fades in
   yield restore();
   setLinks("0,1,2,3,4,5,6,7,8,9");
   setPinnedLinks(",,,,,,,,8");
 
   yield addNewTabPageTab();
   checkGrid("0,1,2,3,4,5,6,7,8p");
 
-  yield blockCell(cells[0]);
+  yield blockCell(0);
   checkGrid("1,2,3,4,5,6,7,9,8p");
 }
--- a/browser/base/content/test/newtab/browser_newtab_bug722273.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug722273.js
@@ -15,31 +15,22 @@ let {NewTabUtils, Sanitizer} = tmp;
 let bhist = Cc["@mozilla.org/browser/global-history;2"]
   .getService(Ci.nsIBrowserHistory);
 
 function runTests() {
   clearHistory();
   fillHistory();
   yield addNewTabPageTab();
 
-  is(cells[0].site.url, URL, "first site is our fake site");
+  is(getCell(0).site.url, URL, "first site is our fake site");
 
-  let page = {
-    update: function () {
-      executeSoon(TestRunner.next);
-    },
-
-    observe: function () {}
-  };
-
-  NewTabUtils.allPages.register(page);
+  whenPagesUpdated();
   yield clearHistory();
 
-  NewTabUtils.allPages.unregister(page);
-  ok(!cells[0].site, "the fake site is gone");
+  ok(!getCell(0).site, "the fake site is gone");
 }
 
 function fillHistory() {
   let uri = makeURI(URL);
   for (let i = 59; i > 0; i--)
     bhist.addPageWithDetails(uri, "fake site", NOW - i * 60 * 1000000);
 }
 
--- a/browser/base/content/test/newtab/browser_newtab_bug723102.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug723102.js
@@ -9,10 +9,10 @@ function runTests() {
   yield addNewTabPageTab();
   let firstTab = gBrowser.selectedTab;
 
   yield addNewTabPageTab();
   gBrowser.removeTab(firstTab);
 
   ok(NewTabUtils.allPages.enabled, true, "page is enabled");
   NewTabUtils.allPages.enabled = false;
-  ok(cw.gGrid.node.hasAttribute("page-disabled"), "page is disabled");
+  ok(getGrid().node.hasAttribute("page-disabled"), "page is disabled");
 }
--- a/browser/base/content/test/newtab/browser_newtab_bug723121.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug723121.js
@@ -3,46 +3,28 @@
 
 function runTests() {
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks("");
 
   yield addNewTabPageTab();
   checkGridLocked(false, "grid is unlocked");
 
-  let cell = cells[0].node;
-  let site = cells[0].site.node;
+  let cell = getCell(0).node;
+  let site = getCell(0).site.node;
   let link = site.querySelector(".newtab-link");
 
-  sendDragEvent(link, "dragstart");
+  sendDragEvent("dragstart", link);
   checkGridLocked(true, "grid is now locked");
 
-  sendDragEvent(link, "dragend");
+  sendDragEvent("dragend", link);
   checkGridLocked(false, "grid isn't locked anymore");
 
-  sendDragEvent(cell, "dragstart");
+  sendDragEvent("dragstart", cell);
   checkGridLocked(false, "grid isn't locked - dragstart was ignored");
 
-  sendDragEvent(site, "dragstart");
+  sendDragEvent("dragstart", site);
   checkGridLocked(false, "grid isn't locked - dragstart was ignored");
 }
 
 function checkGridLocked(aLocked, aMessage) {
-  is(cw.gGrid.node.hasAttribute("locked"), aLocked, aMessage);
+  is(getGrid().node.hasAttribute("locked"), aLocked, aMessage);
 }
-
-function sendDragEvent(aNode, aType) {
-  let ifaceReq = cw.QueryInterface(Ci.nsIInterfaceRequestor);
-  let windowUtils = ifaceReq.getInterface(Ci.nsIDOMWindowUtils);
-
-  let dataTransfer = {
-    mozUserCancelled: false,
-    setData: function () null,
-    setDragImage: function () null,
-    getData: function () "about:blank"
-  };
-
-  let event = cw.document.createEvent("DragEvents");
-  event.initDragEvent(aType, true, true, cw, 0, 0, 0, 0, 0,
-                      false, false, false, false, 0, null, dataTransfer);
-
-  windowUtils.dispatchDOMEventViaPresShell(aNode, event, true);
-}
--- a/browser/base/content/test/newtab/browser_newtab_bug725996.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug725996.js
@@ -3,50 +3,21 @@
 
 function runTests() {
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks("");
 
   yield addNewTabPageTab();
   checkGrid("0,1,2,3,4,5,6,7,8");
 
-  let cell = cells[0].node;
+  let cell = getCell(0).node;
 
-  sendDropEvent(cell, "about:blank#99\nblank");
+  sendDragEvent("drop", cell, "about:blank#99\nblank");
   is(NewTabUtils.pinnedLinks.links[0].url, "about:blank#99",
      "first cell is pinned and contains the dropped site");
 
   yield whenPagesUpdated();
   checkGrid("99p,0,1,2,3,4,5,6,7");
 
-  sendDropEvent(cell, "");
+  sendDragEvent("drop", cell, "");
   is(NewTabUtils.pinnedLinks.links[0].url, "about:blank#99",
      "first cell is still pinned with the site we dropped before");
 }
-
-function sendDropEvent(aNode, aData) {
-  let ifaceReq = cw.QueryInterface(Ci.nsIInterfaceRequestor);
-  let windowUtils = ifaceReq.getInterface(Ci.nsIDOMWindowUtils);
-
-  let dataTransfer = {
-    mozUserCancelled: false,
-    setData: function () null,
-    setDragImage: function () null,
-    getData: function () aData,
-
-    types: {
-      contains: function (aType) aType == "text/x-moz-url"
-    },
-
-    mozGetDataAt: function (aType, aIndex) {
-      if (aIndex || aType != "text/x-moz-url")
-        return null;
-
-      return aData;
-    },
-  };
-
-  let event = cw.document.createEvent("DragEvents");
-  event.initDragEvent("drop", true, true, cw, 0, 0, 0, 0, 0,
-                      false, false, false, false, 0, null, dataTransfer);
-
-  windowUtils.dispatchDOMEventViaPresShell(aNode, event, true);
-}
--- a/browser/base/content/test/newtab/browser_newtab_bug734043.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug734043.js
@@ -4,22 +4,23 @@
 function runTests() {
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks("");
 
   yield addNewTabPageTab();
   checkGrid("0,1,2,3,4,5,6,7,8");
 
   let receivedError = false;
-  let block = cw.document.querySelector(".newtab-control-block");
+  let block = getContentDocument().querySelector(".newtab-control-block");
 
   function onError() {
     receivedError = true;
   }
 
+  let cw = getContentWindow();
   cw.addEventListener("error", onError);
 
   for (let i = 0; i < 3; i++)
     EventUtils.synthesizeMouseAtCenter(block, {}, cw);
 
   yield whenPagesUpdated();
   ok(!receivedError, "we got here without any errors");
   cw.removeEventListener("error", onError);
--- a/browser/base/content/test/newtab/browser_newtab_bug735987.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug735987.js
@@ -3,20 +3,20 @@
 
 function runTests() {
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks("");
 
   yield addNewTabPageTab();
   checkGrid("0,1,2,3,4,5,6,7,8");
 
-  yield simulateDrop(cells[1]);
+  yield simulateDrop(1);
   checkGrid("0,99p,1,2,3,4,5,6,7");
 
-  yield blockCell(cells[1]);
+  yield blockCell(1);
   checkGrid("0,1,2,3,4,5,6,7,8");
 
-  yield simulateDrop(cells[1]);
+  yield simulateDrop(1);
   checkGrid("0,99p,1,2,3,4,5,6,7");
 
-  yield blockCell(cells[1]);
+  yield blockCell(1);
   checkGrid("0,1,2,3,4,5,6,7,8");
 }
--- a/browser/base/content/test/newtab/browser_newtab_disable.js
+++ b/browser/base/content/test/newtab/browser_newtab_disable.js
@@ -6,29 +6,29 @@
  * decides not to use it.
  */
 function runTests() {
   // create a new tab page and hide it.
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks("");
 
   yield addNewTabPageTab();
-  let gridNode = cw.gGrid.node;
+  let gridNode = getGrid().node;
 
   ok(!gridNode.hasAttribute("page-disabled"), "page is not disabled");
 
   NewTabUtils.allPages.enabled = false;
   ok(gridNode.hasAttribute("page-disabled"), "page is disabled");
 
-  let oldGridNode = cw.gGrid.node;
+  let oldGridNode = gridNode;
 
   // create a second new tage page and make sure it's disabled. enable it
   // again and check if the former page gets enabled as well.
   yield addNewTabPageTab();
   ok(gridNode.hasAttribute("page-disabled"), "page is disabled");
 
   // check that no sites have been rendered
-  is(0, cw.document.querySelectorAll(".site").length, "no sites have been rendered");
+  is(0, getContentDocument().querySelectorAll(".site").length, "no sites have been rendered");
 
   NewTabUtils.allPages.enabled = true;
   ok(!gridNode.hasAttribute("page-disabled"), "page is not disabled");
   ok(!oldGridNode.hasAttribute("page-disabled"), "old page is not disabled");
 }
--- a/browser/base/content/test/newtab/browser_newtab_drag_drop.js
+++ b/browser/base/content/test/newtab/browser_newtab_drag_drop.js
@@ -10,106 +10,106 @@
 function runTests() {
   // test a simple drag-and-drop scenario
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks("");
 
   yield addNewTabPageTab();
   checkGrid("0,1,2,3,4,5,6,7,8");
 
-  yield simulateDrop(cells[1], cells[0]);
+  yield simulateDrop(1, 0);
   checkGrid("1,0p,2,3,4,5,6,7,8");
 
   // drag a cell to its current cell and make sure it's not pinned afterwards
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks("");
 
   yield addNewTabPageTab();
   checkGrid("0,1,2,3,4,5,6,7,8");
 
-  yield simulateDrop(cells[0], cells[0]);
+  yield simulateDrop(0, 0);
   checkGrid("0,1,2,3,4,5,6,7,8");
 
   // ensure that pinned pages aren't moved if that's not necessary
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks(",1,2");
 
   yield addNewTabPageTab();
   checkGrid("0,1p,2p,3,4,5,6,7,8");
 
-  yield simulateDrop(cells[3], cells[0]);
+  yield simulateDrop(3, 0);
   checkGrid("3,1p,2p,0p,4,5,6,7,8");
 
   // pinned sites should always be moved around as blocks. if a pinned site is
   // moved around, neighboring pinned are affected as well
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks("0,1");
 
   yield addNewTabPageTab();
   checkGrid("0p,1p,2,3,4,5,6,7,8");
 
-  yield simulateDrop(cells[0], cells[2]);
+  yield simulateDrop(0, 2);
   checkGrid("2p,0p,1p,3,4,5,6,7,8");
 
   // pinned sites should not be pushed out of the grid (unless there are only
   // pinned ones left on the grid)
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks(",,,,,,,7,8");
 
   yield addNewTabPageTab();
   checkGrid("0,1,2,3,4,5,6,7p,8p");
 
-  yield simulateDrop(cells[8], cells[2]);
+  yield simulateDrop(8, 2);
   checkGrid("0,1,3,4,5,6,7p,8p,2p");
 
   // make sure that pinned sites are re-positioned correctly
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks("0,1,2,,,5");
 
   yield addNewTabPageTab();
   checkGrid("0p,1p,2p,3,4,5p,6,7,8");
 
-  yield simulateDrop(cells[4], cells[0]);
+  yield simulateDrop(4, 0);
   checkGrid("3,1p,2p,4,0p,5p,6,7,8");
 
   // drag a new site onto the very first cell
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks(",,,,,,,7,8");
 
   yield addNewTabPageTab();
   checkGrid("0,1,2,3,4,5,6,7p,8p");
 
-  yield simulateDrop(cells[0]);
+  yield simulateDrop(0);
   checkGrid("99p,0,1,2,3,4,5,7p,8p");
 
   // drag a new site onto the grid and make sure that pinned cells don't get
   // pushed out
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks(",,,,,,,7,8");
 
   yield addNewTabPageTab();
   checkGrid("0,1,2,3,4,5,6,7p,8p");
 
-  yield simulateDrop(cells[7]);
+  yield simulateDrop(7);
   checkGrid("0,1,2,3,4,5,7p,99p,8p");
 
   // drag a new site beneath a pinned cell and make sure the pinned cell is
   // not moved
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks(",,,,,,,,8");
 
   yield addNewTabPageTab();
   checkGrid("0,1,2,3,4,5,6,7,8p");
 
-  yield simulateDrop(cells[7]);
+  yield simulateDrop(7);
   checkGrid("0,1,2,3,4,5,6,99p,8p");
 
   // drag a new site onto a block of pinned sites and make sure they're shifted
   // around accordingly
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks("0,1,2,,,,,,");
 
   yield addNewTabPageTab();
   checkGrid("0p,1p,2p");
 
-  yield simulateDrop(cells[1]);
+  yield simulateDrop(1);
   checkGrid("0p,99p,1p,2p,3,4,5,6,7");
 }
--- a/browser/base/content/test/newtab/browser_newtab_drop_preview.js
+++ b/browser/base/content/test/newtab/browser_newtab_drop_preview.js
@@ -8,14 +8,15 @@
 function runTests() {
   // the first three sites are pinned - make sure they're re-arranged correctly
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks("0,1,2,,,5");
 
   yield addNewTabPageTab();
   checkGrid("0p,1p,2p,3,4,5p,6,7,8");
 
-  cw.gDrag._draggedSite = cells[0].site;
-  let sites = cw.gDropPreview.rearrange(cells[4]);
+  let cw = getContentWindow();
+  cw.gDrag._draggedSite = getCell(0).site;
+  let sites = cw.gDropPreview.rearrange(getCell(4));
   cw.gDrag._draggedSite = null;
 
   checkGrid("3,1p,2p,4,0p,5p,6,7,8", sites);
 }
--- a/browser/base/content/test/newtab/browser_newtab_private_browsing.js
+++ b/browser/base/content/test/newtab/browser_newtab_private_browsing.js
@@ -11,31 +11,31 @@ let pb = Cc["@mozilla.org/privatebrowsin
          .getService(Ci.nsIPrivateBrowsingService);
 
 function runTests() {
   // prepare the grid
   setLinks("0,1,2,3,4,5,6,7,8,9");
   ok(!pb.privateBrowsingEnabled, "private browsing is disabled");
 
   yield addNewTabPageTab();
-  pinCell(cells[0]);
+  pinCell(0);
   checkGrid("0p,1,2,3,4,5,6,7,8");
 
   // enter private browsing mode
   yield togglePrivateBrowsing();
   ok(pb.privateBrowsingEnabled, "private browsing is enabled");
 
   yield addNewTabPageTab();
   checkGrid("0p,1,2,3,4,5,6,7,8");
 
   // modify the grid while we're in pb mode
-  yield blockCell(cells[1]);
+  yield blockCell(1);
   checkGrid("0p,2,3,4,5,6,7,8");
 
-  yield unpinCell(cells[0]);
+  yield unpinCell(0);
   checkGrid("0,2,3,4,5,6,7,8");
 
   // exit private browsing mode
   yield togglePrivateBrowsing();
   ok(!pb.privateBrowsingEnabled, "private browsing is disabled");
 
   // check that the grid is the same as before entering pb mode
   yield addNewTabPageTab();
--- a/browser/base/content/test/newtab/browser_newtab_reset.js
+++ b/browser/base/content/test/newtab/browser_newtab_reset.js
@@ -8,21 +8,21 @@ function runTests() {
   // Disabled until bug 716543 is fixed.
   return;
 
   // create a new tab page and check its modified state after blocking a site
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks("");
 
   yield addNewTabPageTab();
-  let resetButton = cw.document.getElementById("toolbar-button-reset");
+  let resetButton = getContentDocument().getElementById("toolbar-button-reset");
 
   checkGrid("0,1,2,3,4,5,6,7,8");
   ok(!resetButton.hasAttribute("modified"), "page is not modified");
 
-  yield blockCell(cells[4]);
+  yield blockCell(4);
   checkGrid("0,1,2,3,5,6,7,8,");
   ok(resetButton.hasAttribute("modified"), "page is modified");
 
-  yield cw.gToolbar.reset(TestRunner.next);
+  yield getContentWindow().gToolbar.reset(TestRunner.next);
   checkGrid("0,1,2,3,4,5,6,7,8");
   ok(!resetButton.hasAttribute("modified"), "page is not modified");
 }
--- a/browser/base/content/test/newtab/browser_newtab_tabsync.js
+++ b/browser/base/content/test/newtab/browser_newtab_tabsync.js
@@ -12,50 +12,50 @@ function runTests() {
   return;
 
   setLinks("0,1,2,3,4,5,6,7,8,9");
   setPinnedLinks(",1");
 
   yield addNewTabPageTab();
   checkGrid("0,1p,2,3,4,5,6,7,8");
 
-  let resetButton = cw.document.getElementById("toolbar-button-reset");
+  let resetButton = getContentDocument().getElementById("toolbar-button-reset");
   ok(!resetButton.hasAttribute("modified"), "page is not modified");
 
-  let oldCw = cw;
+  let oldSites = getGrid().sites;
   let oldResetButton = resetButton;
 
   // create the new tab page
   yield addNewTabPageTab();
   checkGrid("0,1p,2,3,4,5,6,7,8");
 
-  resetButton = cw.document.getElementById("toolbar-button-reset");
+  resetButton = getContentDocument().getElementById("toolbar-button-reset");
   ok(!resetButton.hasAttribute("modified"), "page is not modified");
 
   // unpin a cell
-  yield unpinCell(cells[1]);
+  yield unpinCell(1);
   checkGrid("0,1,2,3,4,5,6,7,8");
-  checkGrid("0,1,2,3,4,5,6,7,8", oldCw.gGrid.sites);
+  checkGrid("0,1,2,3,4,5,6,7,8", oldSites);
 
   // remove a cell
-  yield blockCell(cells[1]);
+  yield blockCell(1);
   checkGrid("0,2,3,4,5,6,7,8,9");
-  checkGrid("0,2,3,4,5,6,7,8,9", oldCw.gGrid.sites);
+  checkGrid("0,2,3,4,5,6,7,8,9", oldSites);
   ok(resetButton.hasAttribute("modified"), "page is modified");
   ok(oldResetButton.hasAttribute("modified"), "page is modified");
 
   // insert a new cell by dragging
-  yield simulateDrop(cells[1]);
+  yield simulateDrop(1);
   checkGrid("0,99p,2,3,4,5,6,7,8");
-  checkGrid("0,99p,2,3,4,5,6,7,8", oldCw.gGrid.sites);
+  checkGrid("0,99p,2,3,4,5,6,7,8", oldSites);
 
   // drag a cell around
-  yield simulateDrop(cells[1], cells[2]);
+  yield simulateDrop(1, 2);
   checkGrid("0,2p,99p,3,4,5,6,7,8");
-  checkGrid("0,2p,99p,3,4,5,6,7,8", oldCw.gGrid.sites);
+  checkGrid("0,2p,99p,3,4,5,6,7,8", oldSites);
 
   // reset the new tab page
-  yield cw.gToolbar.reset(TestRunner.next);
+  yield getContentWindow().gToolbar.reset(TestRunner.next);
   checkGrid("0,1,2,3,4,5,6,7,8");
-  checkGrid("0,1,2,3,4,5,6,7,8", oldCw.gGrid.sites);
+  checkGrid("0,1,2,3,4,5,6,7,8", oldSites);
   ok(!resetButton.hasAttribute("modified"), "page is not modified");
   ok(!oldResetButton.hasAttribute("modified"), "page is not modified");
 }
--- a/browser/base/content/test/newtab/browser_newtab_unpin.js
+++ b/browser/base/content/test/newtab/browser_newtab_unpin.js
@@ -9,48 +9,48 @@ function runTests() {
   // we have a pinned link that didn't change its position since it was pinned.
   // nothing should happend when we unpin it.
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks(",1");
 
   yield addNewTabPageTab();
   checkGrid("0,1p,2,3,4,5,6,7,8");
 
-  yield unpinCell(cells[1]);
+  yield unpinCell(1);
   checkGrid("0,1,2,3,4,5,6,7,8");
 
   // we have a pinned link that is not anymore in the list of the most-visited
   // links. this should disappear, the remaining links adjust their positions
   // and a new link will appear at the end of the grid.
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks(",99");
 
   yield addNewTabPageTab();
   checkGrid("0,99p,1,2,3,4,5,6,7");
 
-  yield unpinCell(cells[1]);
+  yield unpinCell(1);
   checkGrid("0,1,2,3,4,5,6,7,8");
 
   // we have a pinned link that changed its position since it was pinned. it
   // should be moved to its new position after being unpinned.
   setLinks("0,1,2,3,4,5,6,7");
   setPinnedLinks(",1,,,,,,,0");
 
   yield addNewTabPageTab();
   checkGrid("2,1p,3,4,5,6,7,,0p");
 
-  yield unpinCell(cells[1]);
+  yield unpinCell(1);
   checkGrid("1,2,3,4,5,6,7,,0p");
 
-  yield unpinCell(cells[8]);
+  yield unpinCell(8);
   checkGrid("0,1,2,3,4,5,6,7,");
 
   // we have pinned link that changed its position since it was pinned. the
   // link will disappear from the grid because it's now a much lower priority
   setLinks("0,1,2,3,4,5,6,7,8,9");
   setPinnedLinks("9");
 
   yield addNewTabPageTab();
   checkGrid("9p,0,1,2,3,4,5,6,7");
 
-  yield unpinCell(cells[0]);
+  yield unpinCell(0);
   checkGrid("0,1,2,3,4,5,6,7,8");
 }
--- a/browser/base/content/test/newtab/head.js
+++ b/browser/base/content/test/newtab/head.js
@@ -12,22 +12,16 @@ let NewTabUtils = tmp.NewTabUtils;
 registerCleanupFunction(function () {
   while (gBrowser.tabs.length > 1)
     gBrowser.removeTab(gBrowser.tabs[1]);
 
   Services.prefs.clearUserPref(PREF_NEWTAB_ENABLED);
 });
 
 /**
- * Global variables that are accessed by tests.
- */
-let cw;
-let cells;
-
-/**
  * We'll want to restore the original links provider later.
  */
 let originalProvider = NewTabUtils.links._provider;
 
 /**
  * Provide the default test function to start our test runner.
  */
 function test() {
@@ -77,16 +71,49 @@ let TestRunner = {
     if (numCallbacks)
       callbacks.splice(0, numCallbacks, cleanupAndFinish);
     else
       cleanupAndFinish();
   }
 };
 
 /**
+ * Returns the selected tab's content window.
+ * @return The content window.
+ */
+function getContentWindow() {
+  return gBrowser.selectedBrowser.contentWindow;
+}
+
+/**
+ * Returns the selected tab's content document.
+ * @return The content document.
+ */
+function getContentDocument() {
+  return gBrowser.selectedBrowser.contentDocument;
+}
+
+/**
+ * Returns the newtab grid of the selected tab.
+ * @return The newtab grid.
+ */
+function getGrid() {
+  return getContentWindow().gGrid;
+}
+
+/**
+ * Returns the cell at the given index of the selected tab's newtab grid.
+ * @param aIndex The cell index.
+ * @return The newtab cell.
+ */
+function getCell(aIndex) {
+  return getGrid().cells[aIndex];
+}
+
+/**
  * Allows to provide a list of links that is used to construct the grid.
  * @param aLinksPattern the pattern (see below)
  *
  * Example: setLinks("1,2,3")
  * Result: [{url: "about:blank#1", title: "site#1"},
  *          {url: "about:blank#2", title: "site#2"}
  *          {url: "about:blank#3", title: "site#3"}]
  */
@@ -138,154 +165,150 @@ function restore() {
 function addNewTabPageTab() {
   let tab = gBrowser.selectedTab = gBrowser.addTab("about:newtab");
   let browser = tab.linkedBrowser;
 
   // Wait for the new tab page to be loaded.
   browser.addEventListener("load", function onLoad() {
     browser.removeEventListener("load", onLoad, true);
 
-    cw = browser.contentWindow;
-
     if (NewTabUtils.allPages.enabled) {
       // Continue when the link cache has been populated.
       NewTabUtils.links.populateCache(function () {
-        cells = cw.gGrid.cells;
         executeSoon(TestRunner.next);
       });
     } else {
       TestRunner.next();
     }
-
   }, true);
 }
 
 /**
  * Compares the current grid arrangement with the given pattern.
  * @param the pattern (see below)
  * @param the array of sites to compare with (optional)
  *
  * Example: checkGrid("3p,2,,1p")
  * Result: We expect the first cell to contain the pinned site 'about:blank#3'.
  *         The second cell contains 'about:blank#2'. The third cell is empty.
  *         The fourth cell contains the pinned site 'about:blank#4'.
  */
 function checkGrid(aSitesPattern, aSites) {
-  let valid = true;
-
-  aSites = aSites || cw.gGrid.sites;
-
-  aSitesPattern.split(/\s*,\s*/).forEach(function (id, index) {
-    let site = aSites[index];
-    let match = id.match(/^\d+/);
-
-    // We expect the cell to be empty.
-    if (!match) {
-      if (site) {
-        valid = false;
-        ok(false, "expected cell#" + index + " to be empty");
-      }
-
-      return;
-    }
-
-    // We expect the cell to contain a site.
-    if (!site) {
-      valid = false;
-      ok(false, "didn't expect cell#" + index + " to be empty");
-
-      return;
-    }
-
-    let num = match[0];
+  let length = aSitesPattern.split(",").length;
+  let sites = (aSites || getGrid().sites).slice(0, length);
+  let expected = sites.map(function (aSite) {
+    if (!aSite)
+      return "";
 
-    // Check the site's url.
-    if (site.url != "about:blank#" + num) {
-      valid = false;
-      is(site.url, "about:blank#" + num, "cell#" + index + " has the wrong url");
-    }
-
-    let shouldBePinned = /p$/.test(id);
-    let cellContainsPinned = site.isPinned();
-    let cssClassPinned = site.node && site.node.querySelector(".newtab-control-pin").hasAttribute("pinned");
+    let pinned = aSite.isPinned();
+    let pinButton = aSite.node.querySelector(".newtab-control-pin");
+    let hasPinnedAttr = pinButton.hasAttribute("pinned");
 
-    // Check if the site should be and is pinned.
-    if (shouldBePinned) {
-      if (!cellContainsPinned) {
-        valid = false;
-        ok(false, "expected cell#" + index + " to be pinned");
-      } else if (!cssClassPinned) {
-        valid = false;
-        ok(false, "expected cell#" + index + " to have css class 'pinned'");
-      }
-    } else {
-      if (cellContainsPinned) {
-        valid = false;
-        ok(false, "didn't expect cell#" + index + " to be pinned");
-      } else if (cssClassPinned) {
-        valid = false;
-        ok(false, "didn't expect cell#" + index + " to have css class 'pinned'");
-      }
-    }
+    if (pinned != hasPinnedAttr)
+      ok(false, "invalid state (site.isPinned() != site[pinned])");
+
+    return aSite.url.replace(/^about:blank#(\d+)$/, "$1") + (pinned ? "p" : "");
   });
 
-  // If every test passed, say so.
-  if (valid)
-    ok(true, "grid status = " + aSitesPattern);
+  is(aSitesPattern, expected, "grid status = " + aSitesPattern);
 }
 
 /**
- * Blocks the given cell's site from the grid.
- * @param aCell the cell that contains the site to block
+ * Blocks a site from the grid.
+ * @param aIndex The cell index.
  */
-function blockCell(aCell) {
-  aCell.site.block(function () executeSoon(TestRunner.next));
+function blockCell(aIndex) {
+  whenPagesUpdated();
+  getCell(aIndex).site.block();
 }
 
 /**
- * Pins a given cell's site on a given position.
- * @param aCell the cell that contains the site to pin
- * @param aIndex the index the defines where the site should be pinned
+ * Pins a site on a given position.
+ * @param aIndex The cell index.
+ * @param aPinIndex The index the defines where the site should be pinned.
  */
-function pinCell(aCell, aIndex) {
-  aCell.site.pin(aIndex);
+function pinCell(aIndex, aPinIndex) {
+  getCell(aIndex).site.pin(aPinIndex);
 }
 
 /**
  * Unpins the given cell's site.
- * @param aCell the cell that contains the site to unpin
+ * @param aIndex The cell index.
  */
-function unpinCell(aCell) {
-  aCell.site.unpin(function () executeSoon(TestRunner.next));
+function unpinCell(aIndex) {
+  whenPagesUpdated();
+  getCell(aIndex).site.unpin();
 }
 
 /**
  * Simulates a drop and drop operation.
- * @param aDropTarget the cell that is the drop target
- * @param aDragSource the cell that contains the dragged site (optional)
+ * @param aDropIndex The cell index of the drop target.
+ * @param aDragIndex The cell index containing the dragged site (optional).
+ */
+function simulateDrop(aDropIndex, aDragIndex) {
+  let draggedSite;
+  let {gDrag: drag, gDrop: drop} = getContentWindow();
+  let event = createDragEvent("drop", "about:blank#99\nblank");
+
+  if (typeof aDragIndex != "undefined")
+    draggedSite = getCell(aDragIndex).site;
+
+  if (draggedSite)
+    drag.start(draggedSite, event);
+
+  whenPagesUpdated();
+  drop.drop(getCell(aDropIndex), event);
+
+  if (draggedSite)
+    drag.end(draggedSite);
+}
+
+/**
+ * Sends a custom drag event to a given DOM element.
+ * @param aEventType The drag event's type.
+ * @param aTarget The DOM element that the event is dispatched to.
+ * @param aData The event's drag data (optional).
  */
-function simulateDrop(aDropTarget, aDragSource) {
-  let event = {
-    clientX: 0,
-    clientY: 0,
-    dataTransfer: {
-      mozUserCancelled: false,
-      setData: function () null,
-      setDragImage: function () null,
-      getData: function () "about:blank#99\nblank"
+function sendDragEvent(aEventType, aTarget, aData) {
+  let event = createDragEvent(aEventType, aData);
+  let ifaceReq = getContentWindow().QueryInterface(Ci.nsIInterfaceRequestor);
+  let windowUtils = ifaceReq.getInterface(Ci.nsIDOMWindowUtils);
+  windowUtils.dispatchDOMEventViaPresShell(aTarget, event, true);
+}
+
+/**
+ * Creates a custom drag event.
+ * @param aEventType The drag event's type.
+ * @param aData The event's drag data (optional).
+ * @return The drag event.
+ */
+function createDragEvent(aEventType, aData) {
+  let dataTransfer = {
+    mozUserCancelled: false,
+    setData: function () null,
+    setDragImage: function () null,
+    getData: function () aData,
+
+    types: {
+      contains: function (aType) aType == "text/x-moz-url"
+    },
+
+    mozGetDataAt: function (aType, aIndex) {
+      if (aIndex || aType != "text/x-moz-url")
+        return null;
+
+      return aData;
     }
   };
 
-  if (aDragSource)
-    cw.gDrag.start(aDragSource.site, event);
+  let event = getContentDocument().createEvent("DragEvents");
+  event.initDragEvent(aEventType, true, true, getContentWindow(), 0, 0, 0, 0, 0,
+                      false, false, false, false, 0, null, dataTransfer);
 
-  cw.gDrop.drop(aDropTarget, event, function () executeSoon(TestRunner.next));
-
-  if (aDragSource)
-    cw.gDrag.end(aDragSource.site);
+  return event;
 }
 
 /**
  * Resumes testing when all pages have been updated.
  */
 function whenPagesUpdated(aCallback) {
   let page = {
     update: function () {
--- a/browser/components/migration/src/nsBrowserProfileMigratorUtils.cpp
+++ b/browser/components/migration/src/nsBrowserProfileMigratorUtils.cpp
@@ -49,20 +49,16 @@
 #include "nsNetUtil.h"
 #include "nsISupportsPrimitives.h"
 
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsIRDFService.h"
 #include "nsIStringBundle.h"
 #include "nsXPCOMCID.h"
 
-#define MIGRATION_BUNDLE "chrome://browser/locale/migration/migration.properties"
-
-#define DEFAULT_BOOKMARKS NS_LITERAL_CSTRING("resource:///defaults/profile/bookmarks.html")
-
 void SetUnicharPref(const char* aPref, const nsAString& aValue,
                     nsIPrefBranch* aPrefs)
 {
   nsCOMPtr<nsISupportsString> supportsString =
     do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);    
   if (supportsString) {
      supportsString->SetData(aValue); 
      aPrefs->SetComplexValue(aPref, NS_GET_IID(nsISupportsString),
--- a/browser/components/nsBrowserContentHandler.js
+++ b/browser/components/nsBrowserContentHandler.js
@@ -742,20 +742,16 @@ nsDefaultCommandLineHandler.prototype = 
   QueryInterface : function dch_QI(iid) {
     if (!iid.equals(nsISupports) &&
         !iid.equals(nsICommandLineHandler))
       throw Components.results.NS_ERROR_NO_INTERFACE;
 
     return this;
   },
 
-  // List of uri's that were passed via the command line without the app
-  // running and have already been handled. This is compared against uri's
-  // opened using DDE on Win32 so we only open one of the requests.
-  _handledURIs: [ ],
 #ifdef XP_WIN
   _haveProfile: false,
 #endif
 
   /* nsICommandLineHandler */
   handle : function dch_handle(cmdLine) {
     var urilist = [];
 
@@ -779,35 +775,18 @@ nsDefaultCommandLineHandler.prototype = 
         cmdLine.preventDefault = true;
       }
     }
 #endif
 
     try {
       var ar;
       while ((ar = cmdLine.handleFlagWithParam("url", false))) {
-        var found = false;
         var uri = resolveURIInternal(cmdLine, ar);
-        // count will never be greater than zero except on Win32.
-        var count = this._handledURIs.length;
-        for (var i = 0; i < count; ++i) {
-          if (this._handledURIs[i].spec == uri.spec) {
-            this._handledURIs.splice(i, 1);
-            found = true;
-            cmdLine.preventDefault = true;
-            break;
-          }
-        }
-        if (!found) {
-          urilist.push(uri);
-          // The requestpending command line flag is only used on Win32.
-          if (cmdLine.handleFlag("requestpending", false) &&
-              cmdLine.state == nsICommandLine.STATE_INITIAL_LAUNCH)
-            this._handledURIs.push(uri)
-        }
+        urilist.push(uri);
       }
     }
     catch (e) {
       Components.utils.reportError(e);
     }
 
     count = cmdLine.length;
 
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -1238,23 +1238,17 @@ BrowserGlue.prototype = {
     if (currentUIVersion < 2) {
       // This code adds the customizable bookmarks button.
       let currentsetResource = this._rdf.GetResource("currentset");
       let toolbarResource = this._rdf.GetResource(BROWSER_DOCURL + "nav-bar");
       let currentset = this._getPersist(toolbarResource, currentsetResource);
       // Need to migrate only if toolbar is customized and the element is not found.
       if (currentset &&
           currentset.indexOf("bookmarks-menu-button-container") == -1) {
-        if (currentset.indexOf("fullscreenflex") != -1) {
-          currentset = currentset.replace(/(^|,)fullscreenflex($|,)/,
-                                          "$1bookmarks-menu-button-container,fullscreenflex$2")
-        }
-        else {
-          currentset += ",bookmarks-menu-button-container";
-        }
+        currentset += ",bookmarks-menu-button-container";
         this._setPersist(toolbarResource, currentsetResource, currentset);
       }
     }
 
     if (currentUIVersion < 3) {
       // This code merges the reload/stop/go button into the url bar.
       let currentsetResource = this._rdf.GetResource("currentset");
       let toolbarResource = this._rdf.GetResource(BROWSER_DOCURL + "nav-bar");
--- a/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
+++ b/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
@@ -188,19 +188,19 @@ PrivateBrowsingService.prototype = {
           }
         }
         win.close();
       }
 
       if (!this._quitting && this._saveSession) {
         let browserWindow = this._getBrowserWindow();
 
-	// if there are open browser windows, load a dummy session to get a distinct 
+        // if there are open browser windows, load a dummy session to get a distinct 
         // separation between private and non-private sessions
-	if (browserWindow) {
+        if (browserWindow) {
           // set an empty session to transition from/to pb mode, see bug 476463
           ss.setBrowserState(blankState);
 
           // just in case the only remaining window after setBrowserState is different.
           // it probably shouldn't be with the current sessionstore impl, but we shouldn't
           // rely on behaviour the API doesn't guarantee
           browserWindow = this._getBrowserWindow();
           let browser = browserWindow.gBrowser;
@@ -212,17 +212,19 @@ PrivateBrowsingService.prototype = {
           browser.removeTab(browser.tabContainer.firstChild);
           browserWindow.getInterface(Ci.nsIWebNavigation)
                        .QueryInterface(Ci.nsIDocShellTreeItem)
                        .treeOwner
                        .QueryInterface(Ci.nsIInterfaceRequestor)
                        .getInterface(Ci.nsIXULWindow)
                        .docShell.contentViewer.resetCloseWindow();
         }
+      }
 
+      if (!this._quitting) {
         var windowsEnum = Services.wm.getEnumerator("navigator:browser");
         while (windowsEnum.hasMoreElements()) {
           var window = windowsEnum.getNext();
           window.getInterface(Ci.nsIWebNavigation)
                 .QueryInterface(Ci.nsIDocShellTreeItem)
                 .treeOwner
                 .QueryInterface(Ci.nsIInterfaceRequestor)
                 .getInterface(Ci.nsIXULWindow)
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_ui.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_ui.js
@@ -53,31 +53,41 @@ function test() {
   // add a new blank tab to ensure the title can be meaningfully compared later
   gBrowser.selectedTab = gBrowser.addTab();
   let originalTitle = document.title;
 
   // test the gPrivateBrowsingUI object
   ok(gPrivateBrowsingUI, "The gPrivateBrowsingUI object exists");
   is(pb.privateBrowsingEnabled, false, "The private browsing mode should not be started initially");
   is(gPrivateBrowsingUI.privateBrowsingEnabled, false, "gPrivateBrowsingUI should expose the correct private browsing status");
+  is(gPrivateBrowsingUI.privateWindow, false, "gPrivateBrowsingUI should expose the correct per-window private browsing status");
   ok(pbMenuItem, "The Private Browsing menu item exists");
   is(pbMenuItem.getAttribute("label"), pbMenuItem.getAttribute("startlabel"), "The Private Browsing menu item should read \"Start Private Browsing\"");
   gPrivateBrowsingUI.toggleMode();
   is(pb.privateBrowsingEnabled, true, "The private browsing mode should be started");
   is(gPrivateBrowsingUI.privateBrowsingEnabled, true, "gPrivateBrowsingUI should expose the correct private browsing status");
+  is(gPrivateBrowsingUI.privateWindow, true, "gPrivateBrowsingUI should expose the correct per-window private browsing status");
   // check to see if the Private Browsing mode was activated successfully
   is(observerData, "enter", "Private Browsing mode was activated using the gPrivateBrowsingUI object");
   is(pbMenuItem.getAttribute("label"), pbMenuItem.getAttribute("stoplabel"), "The Private Browsing menu item should read \"Stop Private Browsing\"");
   gPrivateBrowsingUI.toggleMode()
   is(pb.privateBrowsingEnabled, false, "The private browsing mode should not be started");
   is(gPrivateBrowsingUI.privateBrowsingEnabled, false, "gPrivateBrowsingUI should expose the correct private browsing status");
+  is(gPrivateBrowsingUI.privateWindow, false, "gPrivateBrowsingUI should expose the correct per-window private browsing status");
   // check to see if the Private Browsing mode was deactivated successfully
   is(observerData, "exit", "Private Browsing mode was deactivated using the gPrivateBrowsingUI object");
   is(pbMenuItem.getAttribute("label"), pbMenuItem.getAttribute("startlabel"), "The Private Browsing menu item should read \"Start Private Browsing\"");
 
+  // These are tests for the privateWindow setter.  Note that the setter should
+  // not be used anywhere else for now!
+  gPrivateBrowsingUI.privateWindow = true;
+  is(gPrivateBrowsingUI.privateWindow, true, "gPrivateBrowsingUI should accept the correct per-window private browsing status");
+  gPrivateBrowsingUI.privateWindow = false;
+  is(gPrivateBrowsingUI.privateWindow, false, "gPrivateBrowsingUI should accept the correct per-window private browsing status");
+
   // now, test using the <command> object
   let cmd = document.getElementById("Tools:PrivateBrowsing");
   isnot(cmd, null, "XUL command object for the private browsing service exists");
   var func = new Function("", cmd.getAttribute("oncommand"));
   func.call(cmd);
   // check to see if the Private Browsing mode was activated successfully
   is(observerData, "enter", "Private Browsing mode was activated using the command object");
   // check to see that the window title has been changed correctly
--- a/browser/components/shell/src/nsWindowsShellService.cpp
+++ b/browser/components/shell/src/nsWindowsShellService.cpp
@@ -72,17 +72,20 @@
 
 #ifdef _WIN32_WINNT
 #undef _WIN32_WINNT
 #endif
 #define _WIN32_WINNT 0x0600
 #define INITGUID
 #include <shlobj.h>
 
+#pragma comment(lib, "shlwapi.lib") // for SHDeleteKeyW
+
 #include <mbstring.h>
+#include <shlwapi.h>
 
 #ifndef MAX_BUF
 #define MAX_BUF 4096
 #endif
 
 #define REG_SUCCEEDED(val) \
   (val == ERROR_SUCCESS)
 
@@ -124,49 +127,40 @@ OpenKeyForReading(HKEY aKeyRoot, const n
 //   are mapped like so:
 //
 //   HKCU\SOFTWARE\Classes\.<ext>\      (default)         REG_SZ     FirefoxHTML
 //
 //   as aliases to the class:
 //
 //   HKCU\SOFTWARE\Classes\FirefoxHTML\
 //     DefaultIcon                      (default)         REG_SZ     <apppath>,1
-//     shell\open\command               (default)         REG_SZ     <apppath> -requestPending -osint -url "%1"
-//     shell\open\ddeexec               (default)         REG_SZ     "%1",,0,0,,,,
-//     shell\open\ddeexec               NoActivateHandler REG_SZ
-//                       \Application   (default)         REG_SZ     Firefox
-//                       \Topic         (default)         REG_SZ     WWW_OpenURL
+//     shell\open\command               (default)         REG_SZ     <apppath> -osint -url "%1"
+//     shell\open\ddeexec               (default)         REG_SZ     <empty string>
 //
-// - Windows Vista Protocol Handler
+// - Windows Vista and above Protocol Handler
 //
 //   HKCU\SOFTWARE\Classes\FirefoxURL\  (default)         REG_SZ     <appname> URL
 //                                      EditFlags         REG_DWORD  2
 //                                      FriendlyTypeName  REG_SZ     <appname> URL
 //     DefaultIcon                      (default)         REG_SZ     <apppath>,1
-//     shell\open\command               (default)         REG_SZ     <apppath> -requestPending -osint -url "%1"
-//     shell\open\ddeexec               (default)         REG_SZ     "%1",,0,0,,,,
-//     shell\open\ddeexec               NoActivateHandler REG_SZ
-//                       \Application   (default)         REG_SZ     Firefox
-//                       \Topic         (default)         REG_SZ     WWW_OpenURL
+//     shell\open\command               (default)         REG_SZ     <apppath> -osint -url "%1"
+//     shell\open\ddeexec               (default)         REG_SZ     <empty string>
 //
 // - Protocol Mappings
 //   -----------------
 //   The following protocols:
 //    HTTP, HTTPS, FTP
 //   are mapped like so:
 //
 //   HKCU\SOFTWARE\Classes\<protocol>\
 //     DefaultIcon                      (default)         REG_SZ     <apppath>,1
-//     shell\open\command               (default)         REG_SZ     <apppath> -requestPending -osint -url "%1"
-//     shell\open\ddeexec               (default)         REG_SZ     "%1",,0,0,,,,
-//     shell\open\ddeexec               NoActivateHandler REG_SZ
-//                       \Application   (default)         REG_SZ     Firefox
-//                       \Topic         (default)         REG_SZ     WWW_OpenURL
+//     shell\open\command               (default)         REG_SZ     <apppath> -osint -url "%1"
+//     shell\open\ddeexec               (default)         REG_SZ     <empty string>
 //
-// - Windows Start Menu (Win2K SP2, XP SP1, and newer)
+// - Windows Start Menu (XP SP1 and newer)
 //   -------------------------------------------------
 //   The following keys are set to make Firefox appear in the Start Menu as the
 //   browser:
 //   
 //   HKCU\SOFTWARE\Clients\StartMenuInternet\FIREFOX.EXE\
 //                                      (default)         REG_SZ     <appname>
 //     DefaultIcon                      (default)         REG_SZ     <apppath>,0
 //     InstallInfo                      HideIconsCommand  REG_SZ     <uninstpath> /HideShortcuts
@@ -175,50 +169,71 @@ OpenKeyForReading(HKEY aKeyRoot, const n
 //     InstallInfo                      ShowIconsCommand  REG_SZ     <uninstpath> /ShowShortcuts
 //     shell\open\command               (default)         REG_SZ     <apppath>
 //     shell\properties                 (default)         REG_SZ     <appname> &Options
 //     shell\properties\command         (default)         REG_SZ     <apppath> -preferences
 //     shell\safemode                   (default)         REG_SZ     <appname> &Safe Mode
 //     shell\safemode\command           (default)         REG_SZ     <apppath> -safe-mode
 //
 
+// The values checked are all default values so the value name is not needed.
 typedef struct {
   char* keyName;
-  char* valueName;
   char* valueData;
+  char* oldValueData;
 } SETTING;
 
 #define APP_REG_NAME L"Firefox"
-#define CLS_HTML "FirefoxHTML"
-#define CLS_URL "FirefoxURL"
-#define VAL_OPEN "\"%APPPATH%\" -requestPending -osint -url \"%1\""
 #define VAL_FILE_ICON "%APPPATH%,1"
+#define VAL_OPEN "\"%APPPATH%\" -osint -url \"%1\""
+#define OLD_VAL_OPEN "\"%APPPATH%\" -requestPending -osint -url \"%1\""
 #define DI "\\DefaultIcon"
-#define SOP "\\shell\\open\\command"
+#define SOC "\\shell\\open\\command"
+#define SOD "\\shell\\open\\ddeexec"
+// Used for updating the FTP protocol handler's shell open command under HKCU.
+#define FTP_SOC L"Software\\Classes\\ftp\\shell\\open\\command"
 
 #define MAKE_KEY_NAME1(PREFIX, MID) \
   PREFIX MID
 
 // The DefaultIcon registry key value should never be used when checking if
 // Firefox is the default browser for file handlers since other applications
 // (e.g. MS Office) may modify the DefaultIcon registry key value to add Icon
 // Handlers. see http://msdn2.microsoft.com/en-us/library/aa969357.aspx for
-// more info.
+// more info. The FTP protocol is not checked so advanced users can set the FTP
+// handler to another application and still have Firefox check if it is the
+// default HTTP and HTTPS handler.
 static SETTING gSettings[] = {
   // File Handler Class
-  { MAKE_KEY_NAME1(CLS_HTML, SOP), "", VAL_OPEN },
+  { MAKE_KEY_NAME1("FirefoxHTML", SOC), VAL_OPEN, OLD_VAL_OPEN },
 
   // Protocol Handler Class - for Vista and above
-  { MAKE_KEY_NAME1(CLS_URL, SOP), "", VAL_OPEN },
+  { MAKE_KEY_NAME1("FirefoxURL", SOC), VAL_OPEN, OLD_VAL_OPEN },
 
   // Protocol Handlers
-  { MAKE_KEY_NAME1("HTTP", DI),    "", VAL_FILE_ICON },
-  { MAKE_KEY_NAME1("HTTP", SOP),   "", VAL_OPEN },
-  { MAKE_KEY_NAME1("HTTPS", DI),   "", VAL_FILE_ICON },
-  { MAKE_KEY_NAME1("HTTPS", SOP),  "", VAL_OPEN }
+  { MAKE_KEY_NAME1("HTTP", DI), VAL_FILE_ICON },
+  { MAKE_KEY_NAME1("HTTP", SOC), VAL_OPEN, OLD_VAL_OPEN },
+  { MAKE_KEY_NAME1("HTTPS", DI), VAL_FILE_ICON },
+  { MAKE_KEY_NAME1("HTTPS", SOC), VAL_OPEN, OLD_VAL_OPEN }
+};
+
+// The settings to disable DDE are separate from the default browser settings
+// since they are only checked when Firefox is the default browser and if they
+// are incorrect they are fixed without notifying the user.
+static SETTING gDDESettings[] = {
+  // File Handler Class
+  { MAKE_KEY_NAME1("Software\\Classes\\FirefoxHTML", SOD) },
+
+  // Protocol Handler Class - for Vista and above
+  { MAKE_KEY_NAME1("Software\\Classes\\FirefoxURL", SOD) },
+
+  // Protocol Handlers
+  { MAKE_KEY_NAME1("Software\\Classes\\FTP", SOD) },
+  { MAKE_KEY_NAME1("Software\\Classes\\HTTP", SOD) },
+  { MAKE_KEY_NAME1("Software\\Classes\\HTTPS", SOD) }
 };
 
 nsresult
 GetHelperPath(nsAutoString& aPath)
 {
   nsresult rv;
   nsCOMPtr<nsIProperties> directoryService = 
     do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
@@ -240,21 +255,20 @@ GetHelperPath(nsAutoString& aPath)
 }
 
 nsresult
 LaunchHelper(nsAutoString& aPath)
 {
   STARTUPINFOW si = {sizeof(si), 0};
   PROCESS_INFORMATION pi = {0};
 
-  BOOL ok = CreateProcessW(NULL, (LPWSTR)aPath.get(), NULL, NULL,
-                           FALSE, 0, NULL, NULL, &si, &pi);
-
-  if (!ok)
+  if (!CreateProcessW(NULL, (LPWSTR)aPath.get(), NULL, NULL, FALSE, 0, NULL,
+                      NULL, &si, &pi)) {
     return NS_ERROR_FAILURE;
+  }
 
   CloseHandle(pi.hProcess);
   CloseHandle(pi.hThread);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindowsShellService::ShortcutMaintenance()
@@ -362,66 +376,194 @@ nsWindowsShellService::IsDefaultBrowser(
                                         bool* aIsDefaultBrowser)
 {
   // If this is the first browser window, maintain internal state that we've
   // checked this session (so that subsequent window opens don't show the 
   // default browser dialog).
   if (aStartupCheck)
     mCheckedThisSession = true;
 
-  SETTING* settings;
-  SETTING* end = gSettings + sizeof(gSettings)/sizeof(SETTING);
-
   *aIsDefaultBrowser = true;
 
   PRUnichar exePath[MAX_BUF];
   if (!::GetModuleFileNameW(0, exePath, MAX_BUF))
     return NS_ERROR_FAILURE;
 
   // Convert the path to a long path since GetModuleFileNameW returns the path
   // that was used to launch Firefox which is not necessarily a long path.
   if (!::GetLongPathNameW(exePath, exePath, MAX_BUF))
     return NS_ERROR_FAILURE;
 
   nsAutoString appLongPath(exePath);
 
+  HKEY theKey;
+  DWORD res;
   nsresult rv;
   PRUnichar currValue[MAX_BUF];
+
+  SETTING* settings;
+  SETTING* end = gSettings + sizeof(gSettings) / sizeof(SETTING);
+
   for (settings = gSettings; settings < end; ++settings) {
-    NS_ConvertUTF8toUTF16 dataLongPath(settings->valueData);
-    NS_ConvertUTF8toUTF16 key(settings->keyName);
-    NS_ConvertUTF8toUTF16 value(settings->valueName);
-    PRInt32 offset = dataLongPath.Find("%APPPATH%");
-    dataLongPath.Replace(offset, 9, appLongPath);
+    NS_ConvertUTF8toUTF16 keyName(settings->keyName);
+    NS_ConvertUTF8toUTF16 valueData(settings->valueData);
+    PRInt32 offset = valueData.Find("%APPPATH%");
+    valueData.Replace(offset, 9, appLongPath);
 
-    ::ZeroMemory(currValue, sizeof(currValue));
-    HKEY theKey;
-    rv = OpenKeyForReading(HKEY_CLASSES_ROOT, key, &theKey);
+    rv = OpenKeyForReading(HKEY_CLASSES_ROOT, keyName, &theKey);
     if (NS_FAILED(rv)) {
       *aIsDefaultBrowser = false;
       return NS_OK;
     }
 
+    ::ZeroMemory(currValue, sizeof(currValue));
     DWORD len = sizeof currValue;
-    DWORD res = ::RegQueryValueExW(theKey, PromiseFlatString(value).get(),
-                                   NULL, NULL, (LPBYTE)currValue, &len);
-    // Close the key we opened.
+    res = ::RegQueryValueExW(theKey, L"", NULL, NULL, (LPBYTE)currValue, &len);
+    // Close the key that was opened.
     ::RegCloseKey(theKey);
     if (REG_FAILED(res) ||
-        !dataLongPath.Equals(currValue, CaseInsensitiveCompare)) {
-      // Key wasn't set, or was set to something other than our registry entry
-      *aIsDefaultBrowser = false;
-      return NS_OK;
+        !valueData.Equals(currValue, CaseInsensitiveCompare)) {
+      // Key wasn't set or was set to something other than our registry entry.
+      NS_ConvertUTF8toUTF16 oldValueData(settings->oldValueData);
+      offset = oldValueData.Find("%APPPATH%");
+      oldValueData.Replace(offset, 9, appLongPath);
+      // The current registry value doesn't match the current or the old format.
+      if (!oldValueData.Equals(currValue, CaseInsensitiveCompare)) {
+        *aIsDefaultBrowser = false;
+        return NS_OK;
+      }
+
+      res = ::RegOpenKeyExW(HKEY_CLASSES_ROOT, PromiseFlatString(keyName).get(),
+                            0, KEY_SET_VALUE, &theKey);
+      if (REG_FAILED(res)) {
+        // If updating the open command fails try to update it using the helper
+        // application when setting Firefox as the default browser.
+        *aIsDefaultBrowser = false;
+        return NS_OK;
+      }
+
+      const nsString &flatValue = PromiseFlatString(valueData);
+      res = ::RegSetValueExW(theKey, L"", 0, REG_SZ,
+                             (const BYTE *) flatValue.get(),
+                             (flatValue.Length() + 1) * sizeof(PRUnichar));
+      // Close the key that was created.
+      ::RegCloseKey(theKey);
+      if (REG_FAILED(res)) {
+        // If updating the open command fails try to update it using the helper
+        // application when setting Firefox as the default browser.
+        *aIsDefaultBrowser = false;
+        return NS_OK;
+      }
     }
   }
 
-  // Only check if Firefox is the default browser on Vista if the previous
-  // checks show that Firefox is the default browser.
-  if (*aIsDefaultBrowser)
+  // Only check if Firefox is the default browser on Vista and above if the
+  // previous checks show that Firefox is the default browser.
+  if (*aIsDefaultBrowser) {
     IsDefaultBrowserVista(aIsDefaultBrowser);
+  }
+
+  // To handle the case where DDE isn't disabled due for a user because there
+  // account didn't perform a Firefox update this will check if Firefox is the
+  // default browser and if dde is disabled for each handler
+  // and if it isn't disable it. When Firefox is not the default browser the
+  // helper application will disable dde for each handler.
+  if (*aIsDefaultBrowser) {
+    // Check ftp settings
+
+    end = gDDESettings + sizeof(gDDESettings) / sizeof(SETTING);
+
+    for (settings = gDDESettings; settings < end; ++settings) {
+      NS_ConvertUTF8toUTF16 keyName(settings->keyName);
+
+      rv = OpenKeyForReading(HKEY_CURRENT_USER, keyName, &theKey);
+      if (NS_FAILED(rv)) {
+        ::RegCloseKey(theKey);
+        // If disabling DDE fails try to disable it using the helper
+        // application when setting Firefox as the default browser.
+        *aIsDefaultBrowser = false;
+        return NS_OK;
+      }
+
+      ::ZeroMemory(currValue, sizeof(currValue));
+      DWORD len = sizeof currValue;
+      res = ::RegQueryValueExW(theKey, L"", NULL, NULL, (LPBYTE)currValue,
+                               &len);
+      // Close the key that was opened.
+      ::RegCloseKey(theKey);
+      if (REG_FAILED(res) || PRUnichar('\0') != *currValue) {
+        // Key wasn't set or was set to something other than our registry entry.
+        // Delete the key along with all of its childrean and then recreate it.
+        const nsString &flatName = PromiseFlatString(keyName);
+        ::SHDeleteKeyW(HKEY_CURRENT_USER, flatName.get());
+        res = ::RegCreateKeyExW(HKEY_CURRENT_USER, flatName.get(), 0, NULL,
+                                REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL,
+                                &theKey, NULL);
+        if (REG_FAILED(res)) {
+          // If disabling DDE fails try to disable it using the helper
+          // application when setting Firefox as the default browser.
+          *aIsDefaultBrowser = false;
+          return NS_OK;
+        }
+
+        res = ::RegSetValueExW(theKey, L"", 0, REG_SZ, (const BYTE *) L"",
+                               sizeof(PRUnichar));
+        // Close the key that was created.
+        ::RegCloseKey(theKey);
+        if (REG_FAILED(res)) {
+          // If disabling DDE fails try to disable it using the helper
+          // application when setting Firefox as the default browser.
+          *aIsDefaultBrowser = false;
+          return NS_OK;
+        }
+      }
+    }
+
+    // Update the FTP protocol handler's shell open command if it is the old
+    // format.
+    res = ::RegOpenKeyExW(HKEY_CURRENT_USER, FTP_SOC, 0, KEY_ALL_ACCESS,
+                          &theKey);
+    // Don't update the FTP protocol handler's shell open command when opening
+    // its registry key fails under HKCU since it most likely doesn't exist.
+    if (NS_FAILED(rv)) {
+      return NS_OK;
+    }
+
+    NS_ConvertUTF8toUTF16 oldValueOpen(OLD_VAL_OPEN);
+    PRInt32 offset = oldValueOpen.Find("%APPPATH%");
+    oldValueOpen.Replace(offset, 9, appLongPath);
+
+    ::ZeroMemory(currValue, sizeof(currValue));
+    DWORD len = sizeof currValue;
+    res = ::RegQueryValueExW(theKey, L"", NULL, NULL, (LPBYTE)currValue,
+                             &len);
+
+    // Don't update the FTP protocol handler's shell open command when the
+    // current registry value doesn't exist or matches the old format.
+    if (REG_FAILED(res) ||
+        !oldValueOpen.Equals(currValue, CaseInsensitiveCompare)) {
+      ::RegCloseKey(theKey);
+      return NS_OK;
+    }
+
+    NS_ConvertUTF8toUTF16 valueData(VAL_OPEN);
+    valueData.Replace(offset, 9, appLongPath);
+    const nsString &flatValue = PromiseFlatString(valueData);
+    res = ::RegSetValueExW(theKey, L"", 0, REG_SZ,
+                           (const BYTE *) flatValue.get(),
+                           (flatValue.Length() + 1) * sizeof(PRUnichar));
+    // Close the key that was created.
+    ::RegCloseKey(theKey);
+    // If updating the FTP protocol handlers shell open command fails try to
+    // update it using the helper application when setting Firefox as the
+    // default browser.
+    if (REG_FAILED(res)) {
+      *aIsDefaultBrowser = false;
+    }
+  }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindowsShellService::SetDefaultBrowser(bool aClaimAllTypes, bool aForAllUsers)
 {
   nsAutoString appHelperPath;
--- a/browser/components/thumbnails/PageThumbsProtocol.js
+++ b/browser/components/thumbnails/PageThumbsProtocol.js
@@ -20,19 +20,16 @@
 const Cu = Components.utils;
 const Cc = Components.classes;
 const Cr = Components.results;
 const Ci = Components.interfaces;
 
 Cu.import("resource:///modules/PageThumbs.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
-  "resource://gre/modules/NetUtil.jsm");
-
 XPCOMUtils.defineLazyModuleGetter(this, "Services",
   "resource://gre/modules/Services.jsm");
 
 /**
  * Implements the thumbnail protocol handler responsible for moz-page-thumb: URIs.
  */
 function Protocol() {
 }
@@ -99,345 +96,294 @@ function Channel(aURI) {
   // nsIChannel
   this.originalURI = aURI;
 
   // nsIHttpChannel
   this._responseHeaders = {"content-type": PageThumbs.contentType};
 }
 
 Channel.prototype = {
-  /**
-   * Tracks if the channel has been opened, yet.
-   */
+  _uri: null,
+  _referrer: null,
+  _canceled: false,
+  _status: Cr.NS_OK,
+  _isPending: false,
   _wasOpened: false,
+  _responseText: "OK",
+  _responseStatus: 200,
+  _responseHeaders: null,
+  _requestMethod: "GET",
+  _requestStarted: false,
+  _allowPipelining: true,
+  _requestSucceeded: true,
+
+  /* :::::::: nsIChannel ::::::::::::::: */
+
+  get URI() this._uri,
+  owner: null,
+  notificationCallbacks: null,
+  get securityInfo() null,
+
+  contentType: PageThumbs.contentType,
+  contentCharset: null,
+  contentLength: -1,
 
-  /**
-   * Opens this channel asynchronously.
-   * @param aListener The listener that receives the channel data when available.
-   * @param aContext A custom context passed to the listener's methods.
-   */
+  get contentDisposition() {
+    throw (Components.returnCode = Cr.NS_ERROR_NOT_AVAILABLE);
+  },
+
+  get contentDispositionFilename() {
+    throw (Components.returnCode = Cr.NS_ERROR_NOT_AVAILABLE);
+  },
+
+  get contentDispositionHeader() {
+    throw (Components.returnCode = Cr.NS_ERROR_NOT_AVAILABLE);
+  },
+
+  open: function Channel_open() {
+    throw (Components.returnCode = Cr.NS_ERROR_NOT_IMPLEMENTED);
+  },
+
   asyncOpen: function Channel_asyncOpen(aListener, aContext) {
+    if (this._isPending)
+      throw (Components.returnCode = Cr.NS_ERROR_IN_PROGRESS);
+
     if (this._wasOpened)
-      throw Cr.NS_ERROR_ALREADY_OPENED;
+      throw (Components.returnCode = Cr.NS_ERROR_ALREADY_OPENED);
 
-    if (this.canceled)
-      return;
-
-    this._listener = aListener;
-    this._context = aContext;
+    if (this._canceled)
+      return (Components.returnCode = this._status);
 
     this._isPending = true;
     this._wasOpened = true;
 
-    // Try to read the data from the thumbnail cache.
-    this._readCache(function (aData) {
-      let telemetryThumbnailFound = true;
+    this._listener = aListener;
+    this._context = aContext;
 
-      // Update response if there's no data.
-      if (!aData) {
-        this._responseStatus = 404;
-        this._responseText = "Not Found";
-        telemetryThumbnailFound = false;
-      }
-
-      Services.telemetry.getHistogramById("FX_THUMBNAILS_HIT_OR_MISS")
-        .add(telemetryThumbnailFound);
-
-      this._startRequest();
-
-      if (!this.canceled) {
-        this._addToLoadGroup();
+    if (this.loadGroup)
+      this.loadGroup.addRequest(this, null);
 
-        if (aData)
-          this._serveData(aData);
-
-        if (!this.canceled)
-          this._stopRequest();
-      }
-    }.bind(this));
-  },
+    if (this._canceled)
+      return;
 
-  /**
-   * Reads a data stream from the cache entry.
-   * @param aCallback The callback the data is passed to.
-   */
-  _readCache: function Channel_readCache(aCallback) {
     let {url} = parseURI(this._uri);
-
-    // Return early if there's no valid URL given.
     if (!url) {
-      aCallback(null);
+      this._serveThumbnailNotFound();
       return;
     }
 
-    // Try to get a cache entry.
     PageThumbsCache.getReadEntry(url, function (aEntry) {
       let inputStream = aEntry && aEntry.openInputStream(0);
-
-      function closeEntryAndFinish(aData) {
-        if (aEntry) {
+      if (!inputStream || !inputStream.available()) {
+        if (aEntry)
           aEntry.close();
-        }
-        aCallback(aData);
-      }
-
-      // Check if we have a valid entry and if it has any data.
-      if (!inputStream || !inputStream.available()) {
-        closeEntryAndFinish();
+        this._serveThumbnailNotFound();
         return;
       }
 
-      try {
-        // Read the cache entry's data.
-        NetUtil.asyncFetch(inputStream, function (aData, aStatus) {
-          // We might have been canceled while waiting.
-          if (this.canceled)
-            return;
+      this._entry = aEntry;
+      this._pump = Cc["@mozilla.org/network/input-stream-pump;1"].
+                   createInstance(Ci.nsIInputStreamPump);
 
-          // Check if we have a valid data stream.
-          if (!Components.isSuccessCode(aStatus) || !aData.available())
-            aData = null;
+      this._pump.init(inputStream, -1, -1, 0, 0, true);
+      this._pump.asyncRead(this, null);
 
-          closeEntryAndFinish(aData);
-        }.bind(this));
-      } catch (e) {
-        closeEntryAndFinish();
-      }
+      this._trackThumbnailHitOrMiss(true);
     }.bind(this));
   },
 
   /**
-   * Calls onStartRequest on the channel listener.
-   */
-  _startRequest: function Channel_startRequest() {
-    try {
-      this._listener.onStartRequest(this, this._context);
-    } catch (e) {
-      // The listener might throw if the request has been canceled.
-      this.cancel(Cr.NS_BINDING_ABORTED);
-    }
-  },
-
-  /**
-   * Calls onDataAvailable on the channel listener and passes the data stream.
-   * @param aData The data to be delivered.
+   * Serves a "404 Not Found" if we didn't find the requested thumbnail.
    */
-  _serveData: function Channel_serveData(aData) {
-    try {
-      let available = aData.available();
-      this._listener.onDataAvailable(this, this._context, aData, 0, available);
-    } catch (e) {
-      // The listener might throw if the request has been canceled.
-      this.cancel(Cr.NS_BINDING_ABORTED);
-    }
-  },
+  _serveThumbnailNotFound: function Channel_serveThumbnailNotFound() {
+    this._responseStatus = 404;
+    this._responseText = "Not Found";
+    this._requestSucceeded = false;
 
-  /**
-   * Calls onStopRequest on the channel listener.
-   */
-  _stopRequest: function Channel_stopRequest() {
-    try {
-      this._listener.onStopRequest(this, this._context, this.status);
-    } catch (e) {
-      // This might throw but is generally ignored.
-    }
+    this.onStartRequest(this, null);
+    this.onStopRequest(this, null, Cr.NS_OK);
 
-    // The request has finished, clean up after ourselves.
-    this._cleanup();
+    this._trackThumbnailHitOrMiss(false);
   },
 
   /**
-   * Adds this request to the load group, if any.
+   * Implements telemetry tracking for thumbnail cache hits and misses.
+   * @param aFound Whether the thumbnail was found.
    */
-  _addToLoadGroup: function Channel_addToLoadGroup() {
-    if (this.loadGroup)
-      this.loadGroup.addRequest(this, this._context);
+  _trackThumbnailHitOrMiss: function Channel_trackThumbnailHitOrMiss(aFound) {
+    Services.telemetry.getHistogramById("FX_THUMBNAILS_HIT_OR_MISS")
+      .add(aFound);
   },
 
-  /**
-   * Removes this request from its load group, if any.
-   */
-  _removeFromLoadGroup: function Channel_removeFromLoadGroup() {
-    if (!this.loadGroup)
-      return;
+  /* :::::::: nsIStreamListener ::::::::::::::: */
+
+  onStartRequest: function Channel_onStartRequest(aRequest, aContext) {
+    if (!this.canceled && Components.isSuccessCode(this._status))
+      this._status = aRequest.status;
 
-    try {
-      this.loadGroup.removeRequest(this, this._context, this.status);
-    } catch (e) {
-      // This might throw but is ignored.
-    }
+    this._requestStarted = true;
+    this._listener.onStartRequest(this, this._context);
+  },
+
+  onDataAvailable: function Channel_onDataAvailable(aRequest, aContext,
+                                                    aInStream, aOffset, aCount) {
+    this._listener.onDataAvailable(this, this._context, aInStream, aOffset, aCount);
   },
 
-  /**
-   * Cleans up the channel when the request has finished.
-   */
-  _cleanup: function Channel_cleanup() {
-    this._removeFromLoadGroup();
-    this.loadGroup = null;
+  onStopRequest: function Channel_onStopRequest(aRequest, aContext, aStatus) {
+    this._isPending = false;
+    this._status = aStatus;
 
-    this._isPending = false;
+    this._listener.onStopRequest(this, this._context, aStatus);
+    this._listener = null;
+    this._context = null;
 
-    delete this._listener;
-    delete this._context;
+    if (this._entry)
+      this._entry.close();
+
+    if (this.loadGroup)
+      this.loadGroup.removeRequest(this, null, aStatus);
   },
 
-  /* :::::::: nsIChannel ::::::::::::::: */
+  /* :::::::: nsIRequest ::::::::::::::: */
+
+  get status() this._status,
+  get name() this._uri.spec,
+  isPending: function Channel_isPending() this._isPending,
 
-  contentType: PageThumbs.contentType,
-  contentLength: -1,
-  owner: null,
-  contentCharset: null,
-  notificationCallbacks: null,
+  loadFlags: Ci.nsIRequest.LOAD_NORMAL,
+  loadGroup: null,
+
+  cancel: function Channel_cancel(aStatus) {
+    if (this._canceled)
+      return;
 
-  get URI() this._uri,
-  get securityInfo() null,
+    this._canceled = true;
+    this._status = aStatus;
+
+    if (this._pump)
+      this._pump.cancel(aStatus);
+  },
 
-  /**
-   * Opens this channel synchronously. Not supported.
-   */
-  open: function Channel_open() {
-    // Synchronous data delivery is not implemented.
-    throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+  suspend: function Channel_suspend() {
+    if (this._pump)
+      this._pump.suspend();
+  },
+
+  resume: function Channel_resume() {
+    if (this._pump)
+      this._pump.resume();
   },
 
   /* :::::::: nsIHttpChannel ::::::::::::::: */
 
-  redirectionLimit: 10,
-  requestMethod: "GET",
-  allowPipelining: true,
-  referrer: null,
+  get referrer() this._referrer,
 
-  get requestSucceeded() true,
+  set referrer(aReferrer) {
+    if (this._wasOpened)
+      throw (Components.returnCode = Cr.NS_ERROR_IN_PROGRESS);
 
-  _responseStatus: 200,
-  get responseStatus() this._responseStatus,
+    this._referrer = aReferrer;
+  },
 
-  _responseText: "OK",
-  get responseStatusText() this._responseText,
+  get requestMethod() this._requestMethod,
 
-  /**
-   * Checks if the server sent the equivalent of a "Cache-control: no-cache"
-   * response header.
-   * @return Always false.
-   */
-  isNoCacheResponse: function () false,
+  set requestMethod(aMethod) {
+    if (this._wasOpened)
+      throw (Components.returnCode = Cr.NS_ERROR_IN_PROGRESS);
+
+    this._requestMethod = aMethod.toUpperCase();
+  },
 
-  /**
-   * Checks if the server sent the equivalent of a "Cache-control: no-cache"
-   * response header.
-   * @return Always false.
-   */
-  isNoStoreResponse: function () false,
+  get allowPipelining() this._allowPipelining,
 
-  /**
-   * Returns the value of a particular request header. Not implemented.
-   */
-  getRequestHeader: function Channel_getRequestHeader() {
-    throw Cr.NS_ERROR_NOT_AVAILABLE;
+  set allowPipelining(aAllow) {
+    if (this._wasOpened)
+      throw (Components.returnCode = Cr.NS_ERROR_FAILURE);
+
+    this._allowPipelining = aAllow;
   },
 
-  /**
-   * This method is called to set the value of a particular request header.
-   * Not implemented.
-   */
-  setRequestHeader: function Channel_setRequestHeader() {
-    if (this._wasOpened)
-      throw Cr.NS_ERROR_IN_PROGRESS;
+  redirectionLimit: 10,
+
+  get responseStatus() {
+    if (this._requestStarted)
+      throw (Components.returnCode = Cr.NS_ERROR_NOT_AVAILABLE);
+
+    return this._responseStatus;
+  },
+
+  get responseStatusText() {
+    if (this._requestStarted)
+      throw (Components.returnCode = Cr.NS_ERROR_NOT_AVAILABLE);
+
+    return this._responseText;
   },
 
-  /**
-   * Call this method to visit all request headers. Not implemented.
-   */
-  visitRequestHeaders: function () {},
+  get requestSucceeded() {
+    if (this._requestStarted)
+      throw (Components.returnCode = Cr.NS_ERROR_NOT_AVAILABLE);
+
+    return this._requestSucceeded;
+  },
+
+  isNoCacheResponse: function Channel_isNoCacheResponse() false,
+  isNoStoreResponse: function Channel_isNoStoreResponse() false,
 
-  /**
-   * Gets the value of a particular response header.
-   * @param aHeader The case-insensitive name of the response header to query.
-   * @return The header value.
-   */
+  getRequestHeader: function Channel_getRequestHeader() {
+    throw (Components.returnCode = Cr.NS_ERROR_NOT_AVAILABLE);
+  },
+
+  setRequestHeader: function Channel_setRequestHeader() {
+    if (this._wasOpened)
+      throw (Components.returnCode = Cr.NS_ERROR_IN_PROGRESS);
+  },
+
+  visitRequestHeaders: function Channel_visitRequestHeaders() {},
+
   getResponseHeader: function Channel_getResponseHeader(aHeader) {
     let name = aHeader.toLowerCase();
     if (name in this._responseHeaders)
       return this._responseHeaders[name];
 
-    throw Cr.NS_ERROR_NOT_AVAILABLE;
+    throw (Components.returnCode = Cr.NS_ERROR_NOT_AVAILABLE);
   },
 
-  /**
-   * This method is called to set the value of a particular response header.
-   * @param aHeader The case-insensitive name of the response header to query.
-   * @param aValue The response header value to set.
-   */
   setResponseHeader: function Channel_setResponseHeader(aHeader, aValue, aMerge) {
     let name = aHeader.toLowerCase();
     if (!aValue && !aMerge)
       delete this._responseHeaders[name];
     else
       this._responseHeaders[name] = aValue;
   },
 
-  /**
-   * Call this method to visit all response headers.
-   * @param aVisitor The header visitor.
-   */
   visitResponseHeaders: function Channel_visitResponseHeaders(aVisitor) {
     for (let name in this._responseHeaders) {
       let value = this._responseHeaders[name];
 
       try {
         aVisitor.visitHeader(name, value);
       } catch (e) {
         // The visitor can throw to stop the iteration.
         return;
       }
     }
   },
 
-  /* :::::::: nsIRequest ::::::::::::::: */
-
-  loadFlags: Ci.nsIRequest.LOAD_NORMAL,
-  loadGroup: null,
-
-  get name() this._uri.spec,
-
-  _status: Cr.NS_OK,
-  get status() this._status,
-
-  _isPending: false,
-  isPending: function () this._isPending,
-
-  resume: function () {},
-  suspend: function () {},
-
-  /**
-   * Cancels this request.
-   * @param aStatus The reason for cancelling.
-   */
-  cancel: function Channel_cancel(aStatus) {
-    if (this.canceled)
-      return;
-
-    this._isCanceled = true;
-    this._status = aStatus;
-
-    this._cleanup();
-  },
-
   /* :::::::: nsIHttpChannelInternal ::::::::::::::: */
 
   documentURI: null,
-
-  _isCanceled: false,
-  get canceled() this._isCanceled,
+  get canceled() this._canceled,
+  allowSpdy: false,
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIChannel,
                                          Ci.nsIHttpChannel,
                                          Ci.nsIHttpChannelInternal,
                                          Ci.nsIRequest])
-};
+}
 
 /**
  * Parses a given URI and extracts all parameters relevant to this protocol.
  * @param aURI The URI to parse.
  * @return The parsed parameters.
  */
 function parseURI(aURI) {
   let {scheme, staticHost} = PageThumbs;
--- a/browser/installer/windows/nsis/installer.nsi
+++ b/browser/installer/windows/nsis/installer.nsi
@@ -98,17 +98,17 @@ Var PageName
 !include locales.nsi
 
 VIAddVersionKey "FileDescription" "${BrandShortName} Installer"
 VIAddVersionKey "OriginalFilename" "setup.exe"
 
 ; Must be inserted before other macros that use logging
 !insertmacro _LoggingCommon
 
-!insertmacro AddDDEHandlerValues
+!insertmacro AddDisabledDDEHandlerValues
 !insertmacro ChangeMUIHeaderImage
 !insertmacro CheckForFilesInUse
 !insertmacro CleanUpdatesDir
 !insertmacro CopyFilesFromDir
 !insertmacro CreateRegKey
 !insertmacro GetPathFromString
 !insertmacro GetParent
 !insertmacro InitHashAppModelId
@@ -347,27 +347,25 @@ Section "-Application" APP_IDX
 
   ${FixClassKeys}
 
   ; Uninstall keys can only exist under HKLM on some versions of windows. Since
   ; it doesn't cause problems always add them.
   ${SetUninstallKeys}
 
   ; On install always add the FirefoxHTML and FirefoxURL keys.
-  ; An empty string is used for the 5th param because FirefoxHTML and FirefoxURL
-  ; are not protocol handlers.
+  ; An empty string is used for the 5th param because FirefoxHTML is not a
+  ; protocol handler.
   ${GetLongPath} "$INSTDIR\${FileMainEXE}" $8
-  StrCpy $2 "$\"$8$\" -requestPending -osint -url $\"%1$\""
-  StrCpy $3 "$\"%1$\",,0,0,,,,"
+  StrCpy $2 "$\"$8$\" -osint -url $\"%1$\""
 
-  ${AddDDEHandlerValues} "FirefoxHTML" "$2" "$8,1" "${AppRegName} Document" "" \
-                         "${DDEApplication}" "$3" "WWW_OpenURL"
-
-  ${AddDDEHandlerValues} "FirefoxURL" "$2" "$8,1" "${AppRegName} URL" "true" \
-                         "${DDEApplication}" "$3" "WWW_OpenURL"
+  ${AddDisabledDDEHandlerValues} "FirefoxHTML" "$2" "$8,1" \
+                                 "${AppRegName} Document" ""
+  ${AddDisabledDDEHandlerValues} "FirefoxURL" "$2" "$8,1" "${AppRegName} URL" \
+                                 "true"
 
   ; The following keys should only be set if we can write to HKLM
   ${If} $TmpVal == "HKLM"
     ; Set the Start Menu Internet and Vista Registered App HKLM registry keys.
     ${SetStartMenuInternet}
     ${FixShellIconHandler}
 
     ; If we are writing to HKLM and create either the desktop or start menu
--- a/browser/installer/windows/nsis/shared.nsh
+++ b/browser/installer/windows/nsis/shared.nsh
@@ -74,17 +74,17 @@
     ${StrFilter} "${FileMainEXE}" "+" "" "" $1
     ReadRegStr $0 HKLM "Software\Clients\StartMenuInternet\$1\DefaultIcon" ""
     ${GetPathFromString} "$0" $0
     ${GetParent} "$0" $0
     ${If} ${FileExists} "$0"
       ${GetLongPath} "$0" $0
     ${EndIf}
     ${If} "$0" == "$INSTDIR"
-      ${SetStartMenuInternet}
+      ${SetStartMenuInternet} ; Does not use SHCTX
     ${EndIf}
 
     ReadRegStr $0 HKLM "Software\mozilla.org\Mozilla" "CurrentVersion"
     ${If} "$0" != "${GREVersion}"
       WriteRegStr HKLM "Software\mozilla.org\Mozilla" "CurrentVersion" "${GREVersion}"
     ${EndIf}
   ${EndIf}
 
@@ -151,22 +151,22 @@
     ${EndIf}
   ${EndIf}
 !endif
 
 !macroend
 !define PostUpdate "!insertmacro PostUpdate"
 
 !macro SetAsDefaultAppGlobal
-  ${RemoveDeprecatedKeys}
+  ${RemoveDeprecatedKeys} ; Does not use SHCTX
 
   SetShellVarContext all      ; Set SHCTX to all users (e.g. HKLM)
-  ${SetHandlers}
-  ${SetStartMenuInternet}
-  ${FixShellIconHandler}
+  ${SetHandlers} ; Uses SHCTX
+  ${SetStartMenuInternet} ; Does not use SHCTX
+  ${FixShellIconHandler} ; Does not use SHCTX
   ${ShowShortcuts}
   ${StrFilter} "${FileMainEXE}" "+" "" "" $R9
   WriteRegStr HKLM "Software\Clients\StartMenuInternet" "" "$R9"
 !macroend
 !define SetAsDefaultAppGlobal "!insertmacro SetAsDefaultAppGlobal"
 
 ; Removes shortcuts for this installation. This should also remove the
 ; application from Open With for the file types the application handles
@@ -301,17 +301,17 @@
 !define ShowShortcuts "!insertmacro ShowShortcuts"
 
 ; Adds the protocol and file handler registry entries for making Firefox the
 ; default handler (uses SHCTX).
 !macro SetHandlers
   ${GetLongPath} "$INSTDIR\${FileMainEXE}" $8
 
   StrCpy $0 "SOFTWARE\Classes"
-  StrCpy $2 "$\"$8$\" -requestPending -osint -url $\"%1$\""
+  StrCpy $2 "$\"$8$\" -osint -url $\"%1$\""
 
   ; Associate the file handlers with FirefoxHTML
   ReadRegStr $6 SHCTX "$0\.htm" ""
   ${If} "$6" != "FirefoxHTML"
     WriteRegStr SHCTX "$0\.htm"   "" "FirefoxHTML"
   ${EndIf}
 
   ReadRegStr $6 SHCTX "$0\.html" ""
@@ -335,35 +335,30 @@
   ${EndIf}
 
   ; Only add webm if it's not present
   ${CheckIfRegistryKeyExists} "$0" ".webm" $7
   ${If} $7 == "false"
     WriteRegStr SHCTX "$0\.webm"  "" "FirefoxHTML"
   ${EndIf}
 
-  StrCpy $3 "$\"%1$\",,0,0,,,,"
-
   ; An empty string is used for the 5th param because FirefoxHTML is not a
   ; protocol handler
-  ${AddDDEHandlerValues} "FirefoxHTML" "$2" "$8,1" "${AppRegName} HTML Document" "" \
-                         "${DDEApplication}" "$3" "WWW_OpenURL"
+  ${AddDisabledDDEHandlerValues} "FirefoxHTML" "$2" "$8,1" \
+                                 "${AppRegName} HTML Document" ""
 
-  ${AddDDEHandlerValues} "FirefoxURL" "$2" "$8,1" "${AppRegName} URL" "true" \
-                         "${DDEApplication}" "$3" "WWW_OpenURL"
+  ${AddDisabledDDEHandlerValues} "FirefoxURL" "$2" "$8,1" "${AppRegName} URL" \
+                                 "true"
 
   ; An empty string is used for the 4th & 5th params because the following
   ; protocol handlers already have a display name and the additional keys
   ; required for a protocol handler.
-  ${AddDDEHandlerValues} "ftp" "$2" "$8,1" "" "" \
-                         "${DDEApplication}" "$3" "WWW_OpenURL"
-  ${AddDDEHandlerValues} "http" "$2" "$8,1" "" "" \
-                         "${DDEApplication}" "$3" "WWW_OpenURL"
-  ${AddDDEHandlerValues} "https" "$2" "$8,1" "" "" \
-                         "${DDEApplication}" "$3" "WWW_OpenURL"
+  ${AddDisabledDDEHandlerValues} "ftp" "$2" "$8,1" "" ""
+  ${AddDisabledDDEHandlerValues} "http" "$2" "$8,1" "" ""
+  ${AddDisabledDDEHandlerValues} "https" "$2" "$8,1" "" ""
 !macroend
 !define SetHandlers "!insertmacro SetHandlers"
 
 ; Adds the HKLM\Software\Clients\StartMenuInternet\FIREFOX.EXE registry
 ; entries (does not use SHCTX).
 ;
 ; The values for StartMenuInternet are only valid under HKLM and there can only
 ; be one installation registerred under StartMenuInternet per application since
@@ -562,52 +557,51 @@
 !macroend
 !define FixClassKeys "!insertmacro FixClassKeys"
 
 ; Updates protocol handlers if their registry open command value is for this
 ; install location (uses SHCTX).
 !macro UpdateProtocolHandlers
   ; Store the command to open the app with an url in a register for easy access.
   ${GetLongPath} "$INSTDIR\${FileMainEXE}" $8
-  StrCpy $2 "$\"$8$\" -requestPending -osint -url $\"%1$\""
-  StrCpy $3 "$\"%1$\",,0,0,,,,"
+  StrCpy $2 "$\"$8$\" -osint -url $\"%1$\""
 
   ; Only set the file and protocol handlers if the existing one under HKCR is
   ; for this install location.
 
   ${IsHandlerForInstallDir} "FirefoxHTML" $R9
   ${If} "$R9" == "true"
     ; An empty string is used for the 5th param because FirefoxHTML is not a
     ; protocol handler.
-    ${AddDDEHandlerValues} "FirefoxHTML" "$2" "$8,1" "${AppRegName} HTML Document" "" \
-                           "${DDEApplication}" "$3" "WWW_OpenURL"
+    ${AddDisabledDDEHandlerValues} "FirefoxHTML" "$2" "$8,1" \
+                                   "${AppRegName} HTML Document" ""
   ${EndIf}
 
   ${IsHandlerForInstallDir} "FirefoxURL" $R9
   ${If} "$R9" == "true"
-    ${AddDDEHandlerValues} "FirefoxURL" "$2" "$8,1" "${AppRegName} URL" "true" \
-                           "${DDEApplication}" "$3" "WWW_OpenURL"
+    ${AddDisabledDDEHandlerValues} "FirefoxURL" "$2" "$8,1" \
+                                   "${AppRegName} URL" "true"
   ${EndIf}
 
+  ; An empty string is used for the 4th & 5th params because the following
+  ; protocol handlers already have a display name and the additional keys
+  ; required for a protocol handler.
   ${IsHandlerForInstallDir} "ftp" $R9
   ${If} "$R9" == "true"
-    ${AddDDEHandlerValues} "ftp" "$2" "$8,1" "" "" \
-                           "${DDEApplication}" "$3" "WWW_OpenURL"
+    ${AddDisabledDDEHandlerValues} "ftp" "$2" "$8,1" "" ""
   ${EndIf}
 
   ${IsHandlerForInstallDir} "http" $R9
   ${If} "$R9" == "true"
-    ${AddDDEHandlerValues} "http" "$2" "$8,1" "" "" \
-                           "${DDEApplication}" "$3" "WWW_OpenURL"
+    ${AddDisabledDDEHandlerValues} "http" "$2" "$8,1" "" ""
   ${EndIf}
 
   ${IsHandlerForInstallDir} "https" $R9
   ${If} "$R9" == "true"
-    ${AddDDEHandlerValues} "https" "$2" "$8,1" "" "" \
-                           "${DDEApplication}" "$3" "WWW_OpenURL"
+    ${AddDisabledDDEHandlerValues} "https" "$2" "$8,1" "" ""
   ${EndIf}
 !macroend
 !define UpdateProtocolHandlers "!insertmacro UpdateProtocolHandlers"
 
 !ifdef MOZ_MAINTENANCE_SERVICE
 ; Adds maintenance service certificate keys for the install dir.
 ; For the cert to work, it must also be signed by a trusted cert for the user.
 !macro AddMaintCertKeys
@@ -1159,21 +1153,23 @@ Function SetAsDefaultAppUser
   ${EndUnless}
 
   ; The code after ElevateUAC won't be executed on Vista and above when the
   ; user:
   ; a) is a member of the administrators group (e.g. elevation is required)
   ; b) is not a member of the administrators group and chooses to elevate
   ${ElevateUAC}
 
-  ${SetStartMenuInternet}
+  ${SetStartMenuInternet} ; Does not use SHCTX
 
   SetShellVarContext all  ; Set SHCTX to all users (e.g. HKLM)
-  ${FixShellIconHandler}
-  ${RemoveDeprecatedKeys}
+
+  ${FixClassKeys} ; Does not use SHCTX
+  ${FixShellIconHandler} ; Does not use SHCTX
+  ${RemoveDeprecatedKeys} ; Does not use SHCTX
 
   ClearErrors
   ${GetParameters} $0
   ${GetOptions} "$0" "/UAC:" $0
   ${If} ${Errors}
     Call SetAsDefaultAppUserHKCU
   ${Else}
     GetFunctionAddress $0 SetAsDefaultAppUserHKCU
--- a/browser/installer/windows/nsis/uninstaller.nsi
+++ b/browser/installer/windows/nsis/uninstaller.nsi
@@ -87,17 +87,17 @@ Var MaintCertKey
 !include common.nsh
 !include locales.nsi
 
 ; This is named BrandShortName helper because we use this for software update
 ; post update cleanup.
 VIAddVersionKey "FileDescription" "${BrandShortName} Helper"
 VIAddVersionKey "OriginalFilename" "helper.exe"
 
-!insertmacro AddDDEHandlerValues
+!insertmacro AddDisabledDDEHandlerValues
 !insertmacro CleanVirtualStore
 !insertmacro ElevateUAC
 !insertmacro GetLongPath
 !insertmacro GetPathFromString
 !insertmacro InitHashAppModelId
 !insertmacro IsHandlerForInstallDir
 !insertmacro IsPinnedToTaskBar
 !insertmacro IsUserAdmin
--- a/browser/makefiles.sh
+++ b/browser/makefiles.sh
@@ -97,17 +97,17 @@ security/manager/locales/Makefile
 "
 
 if [ "$MOZ_SAFE_BROWSING" ]; then
   add_makefiles "
     browser/components/safebrowsing/Makefile
   "
 fi
 
-if [ "$MOZ_WIDGET_TOOLKIT" = "windows" ]; then
+if [ "$MAKENSISU" ]; then
   add_makefiles "
     browser/installer/windows/Makefile
   "
 fi
 
 if [ "$MOZ_WIDGET_TOOLKIT" = "gtk2" -o "$MOZ_WIDGET_TOOLKIT" = "qt" ]; then
   add_makefiles "
     browser/themes/gnomestripe/Makefile
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -1143,17 +1143,17 @@ toolbar[mode=full] .toolbarbutton-1 > .t
 /* feed button */
 
 #feed-button {
   -moz-image-region: rect(0, 342px, 18px, 324px);
 }
 
 /* ::::: fullscreen window controls ::::: */
 
-#TabsToolbar > #window-controls {
+#window-controls {
   -moz-margin-start: 4px;
 }
 
 #minimize-button,
 #restore-button,
 #close-button {
   list-style-image: url("chrome://global/skin/icons/windowControls.png");
   padding: 0;
--- a/build/mobile/robocop/Assert.java.in
+++ b/build/mobile/robocop/Assert.java.in
@@ -36,16 +36,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 package @ANDROID_PACKAGE_NAME@;
 
 public interface Assert {
     void dumpLog(String message);
+    void dumpLog(String message, Throwable t);
     void setLogFile(String filename);
     void setTestName(String testName);
 
     void finalize();
     void ok(boolean condition, String name, String diag);
     void is(Object a, Object b, String name);
     void isnot(Object a, Object b, String name);
     void todo(boolean condition, String name, String diag);
--- a/build/mobile/robocop/FennecMochitestAssert.java.in
+++ b/build/mobile/robocop/FennecMochitestAssert.java.in
@@ -61,16 +61,21 @@ public class FennecMochitestAssert imple
     public FennecMochitestAssert() {
     }
 
     /** Write information to a logfile and logcat */
     public void dumpLog(String message) {
         FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_INFO, message);
     }
 
+    /** Write information to a logfile and logcat */
+    public void dumpLog(String message, Throwable t) {
+        FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_INFO, message, t);
+    }
+
     /** Set the filename used for dumpLog. */
     public void setLogFile(String filename) {
         FennecNativeDriver.setLogFile(filename);
 
         String message;
         if (!mLogStarted) {
             dumpLog(Integer.toString(mLineNumber++) + " INFO SimpleTest START");
             mLogStarted = true;
--- a/build/mobile/robocop/FennecNativeDriver.java.in
+++ b/build/mobile/robocop/FennecNativeDriver.java.in
@@ -36,24 +36,24 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 package @ANDROID_PACKAGE_NAME@;
 
 import java.io.BufferedOutputStream;
 import java.io.BufferedReader;
-import java.io.BufferedWriter;
 import java.io.DataOutputStream;
 import java.io.File;
 import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.io.PrintWriter;
 import java.nio.IntBuffer;
 import java.util.HashMap;
 import java.util.List;
 
 import java.lang.Class;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
@@ -454,46 +454,53 @@ public class FennecNativeDriver implemen
         }
     }
 
     public static void setLogLevel(LogLevel level) {
         mLogLevel = level;
     }
 
     public static void log(LogLevel level, String message) {
+        log(level, message, null);
+    }
+
+    public static void log(LogLevel level, Throwable t) {
+        log(level, null, t);
+    }
+
+    public static void log(LogLevel level, String message, Throwable t) {
         if (mLogFile == null) {
             assert(false);
         }
 
         if (level.isEnabled(mLogLevel)) {
-            File file = new File(mLogFile);
-            BufferedWriter bw = null;
-
+            PrintWriter pw = null;
             try {
-                bw = new BufferedWriter(new FileWriter(mLogFile, true));
-                bw.write(message);
-                bw.newLine();
-            } catch(IOException e) {
+                pw = new PrintWriter(new FileWriter(mLogFile, true));
+                if (message != null) {
+                    pw.println(message);
+                }
+                if (t != null) {
+                    t.printStackTrace(pw);
+                }
+            } catch (IOException ioe) {
                 Log.e("Robocop", "exception with file writer on: " + mLogFile);
             } finally {
-                try {
-                    if (bw != null) {
-                        bw.flush();
-                        bw.close();
-                    }
-                } catch (IOException ex) {
-                    ex.printStackTrace();
-                }
+                pw.close();
+            }
+            // PrintWriter doesn't throw IOE but sets an error flag instead,
+            // so check for that
+            if (pw.checkError()) {
+                Log.e("Robocop", "exception with file writer on: " + mLogFile);
             }
         }
 
         if (level == LogLevel.LOG_LEVEL_INFO) {
-            Log.i("Robocop", message);
+            Log.i("Robocop", message, t);
         } else if (level == LogLevel.LOG_LEVEL_DEBUG) {
-            Log.d("Robocop", message);
+            Log.d("Robocop", message, t);
         } else if (level == LogLevel.LOG_LEVEL_WARN) {
-            Log.w("Robocop", message);
+            Log.w("Robocop", message, t);
         } else if (level == LogLevel.LOG_LEVEL_ERROR) {
-            Log.e("Robocop", message);
+            Log.e("Robocop", message, t);
         }
     }
-
 }
--- a/build/mobile/robocop/FennecTalosAssert.java.in
+++ b/build/mobile/robocop/FennecTalosAssert.java.in
@@ -44,16 +44,21 @@ public class FennecTalosAssert implement
 
     /**
      *  Write information to a logfile and logcat
      */
     public void dumpLog(String message) {
         FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_INFO, message);
     }
 
+    /** Write information to a logfile and logcat */
+    public void dumpLog(String message, Throwable t) {
+        FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_INFO, message, t);
+    }
+
     /**
      *  Set the filename used for dumpLog.
      */
     public void setLogFile(String filename) {
         FennecNativeDriver.setLogFile(filename);
     }
 
     public void setTestName(String testName) { }
--- a/build/mobile/robocop/Makefile.in
+++ b/build/mobile/robocop/Makefile.in
@@ -122,18 +122,18 @@ tools:: robocop.apk
 classes.dex: robocop.ap_
 classes.dex: $(_ROBOCOP_TOOLS)
 classes.dex: $(_JAVA_HARNESS)
 classes.dex: $(_JAVA_TESTS)
 	$(NSINSTALL) -D classes
 	$(JAVAC) $(JAVAC_FLAGS) -d classes $(JAVAFILES) $(_JAVA_HARNESS) $(addprefix $(DEPTH)/mobile/android/base/tests/,$(_JAVA_TESTS))
 	$(DX) --dex --output=$@ classes $(ROBOTIUM_PATH)
 
-robocop.ap_: AndroidManifest.xml
-	$(AAPT) package -f -M AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -I . -S res -F $@ -J ./
+robocop.ap_: AndroidManifest.xml $(TESTPATH)/assets/*
+	$(AAPT) package -f -M AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -I . -S res -A $(TESTPATH)/assets -F $@ -J ./
 
 robocop.apk: robocop.ap_ classes.dex
 	cp $(TESTPATH)/robocop.ini robocop.ini
 	cp $(srcdir)/parse_ids.py parse_ids.py
 
 export::
 	$(NSINSTALL) -D res
 	@(cd $(srcdir)/res && tar $(TAR_CREATE_FLAGS) - *) | (cd $(DEPTH)/build/mobile/robocop/res && tar -xf -)
--- a/build/unix/build-toolchain/build-gcc.py
+++ b/build/unix/build-toolchain/build-gcc.py
@@ -260,16 +260,16 @@ os.makedirs(build_dir)
 
 build_aux_tools(build_dir)
 
 stage1_dir = build_dir + '/stage1'
 build_one_stage({"CC": "gcc", "CXX" : "g++"}, stage1_dir, True)
 
 stage1_tool_inst_dir = stage1_dir + '/inst'
 stage2_dir = build_dir + '/stage2'
-build_one_stage({"CC"     : stage1_tool_inst_dir + "/bin/gcc -fgnu89-inline",
-                 "CXX"    : stage1_tool_inst_dir + "/bin/g++",
-                 "AR"     : stage1_tool_inst_dir + "/bin/ar",
+build_one_stage({"PATH"   : stage1_tool_inst_dir + "/bin:/bin:/usr/bin",
+                 "CC"     : "gcc -fgnu89-inline",
+                 "CXX"    : "g++",
                  "RANLIB" : "true" },
                 stage2_dir, False)
 
 build_tar_package(aux_inst_dir + "/bin/tar",
                   "toolchain.tar", stage2_dir, "inst")
--- a/configure.in
+++ b/configure.in
@@ -6314,39 +6314,48 @@ if test -n "$MOZ_TREE_FREETYPE"; then
    AC_DEFINE(HAVE_FT_LOAD_SFNT_TABLE)
    AC_SUBST(CAIRO_FT_CFLAGS)
 fi
 
 dnl ========================================================
 dnl Installer
 dnl ========================================================
 dnl Abort Windows build if the required major version and
-dnl minimum minor version of Unicode NSIS isn't in the path.
+dnl minimum minor version of Unicode NSIS isn't in the path
+dnl (unless in case of cross compiling, for which Unicode
+dnl is not yet sufficient).
 if test "$OS_ARCH" = "WINNT"; then
     REQ_NSIS_MAJOR_VER=2
     MIN_NSIS_MINOR_VER=33
     MOZ_PATH_PROGS(MAKENSISU, $MAKENSISU makensisu-2.46 makensisu makensis)
-    if test -z "$MAKENSISU" -o "$MAKENSISU" = ":"; then
-        AC_MSG_ERROR([To build the installer you must have the latest MozillaBuild or Unicode NSIS with a major version of $REQ_NSIS_MAJOR_VER and a minimum minor version of $MIN_NSIS_MINOR_VER in your path.])
-    fi
-    changequote(,)
-    MAKENSISU_VER=`"$MAKENSISU" -version 2>/dev/null | sed -e '/-Unicode/!s/.*//g' -e 's/^v\([0-9]\+\.[0-9]\+\)\-Unicode$/\1/g'`
-    changequote([,])
-    if test ! "$MAKENSISU_VER" = ""; then
-        MAKENSISU_MAJOR_VER=`echo $MAKENSISU_VER | $AWK -F\. '{ print $1 }'`
-        MAKENSISU_MINOR_VER=`echo $MAKENSISU_VER | $AWK -F\. '{ print $2 }'`
-    fi
-    AC_MSG_CHECKING([for Unicode NSIS with major version == $REQ_NSIS_MAJOR_VER and minor version >= $MIN_NSIS_MINOR_VER])
-    if test "$MAKENSISU_VER" = "" ||
-       test ! "$MAKENSISU_MAJOR_VER" = "$REQ_NSIS_MAJOR_VER" -o \
-            ! "$MAKENSISU_MINOR_VER" -ge $MIN_NSIS_MINOR_VER; then
-        AC_MSG_RESULT([no])
-        AC_MSG_ERROR([To build the installer you must have the latest MozillaBuild or Unicode NSIS with a major version of $REQ_NSIS_MAJOR_VER and a minimum minor version of $MIN_NSIS_MINOR_VER in your path.])
-    fi
-    AC_MSG_RESULT([yes])
+    if test -n "$MAKENSISU" -a "$MAKENSISU" != ":"; then
+      AC_MSG_RESULT([yes])
+      changequote(,)
+      MAKENSISU_VER=`"$MAKENSISU" -version 2>/dev/null | sed -e '/-Unicode/!s/.*//g' -e 's/^v\([0-9]\+\.[0-9]\+\)\-Unicode$/\1/g'`
+      changequote([,])
+      if test ! "$MAKENSISU_VER" = ""; then
+          MAKENSISU_MAJOR_VER=`echo $MAKENSISU_VER | $AWK -F\. '{ print $1 }'`
+          MAKENSISU_MINOR_VER=`echo $MAKENSISU_VER | $AWK -F\. '{ print $2 }'`
+      fi
+      AC_MSG_CHECKING([for Unicode NSIS with major version == $REQ_NSIS_MAJOR_VER and minor version >= $MIN_NSIS_MINOR_VER])
+      if test "$MAKENSISU_VER" = "" || \
+         test ! "$MAKENSISU_MAJOR_VER" = "$REQ_NSIS_MAJOR_VER" -o \
+              ! "$MAKENSISU_MINOR_VER" -ge $MIN_NSIS_MINOR_VER; then
+          AC_MSG_RESULT([no])
+          if test -z "$CROSS_COMPILE"; then
+            AC_MSG_ERROR([To build the installer you must have the latest MozillaBuild or Unicode NSIS with a major version of $REQ_NSIS_MAJOR_VER and a minimum minor version of $MIN_NSIS_MINOR_VER in your path.])
+          else
+            MAKENSISU=
+          fi
+      fi
+    elif test -z "$CROSS_COMPILE"; then
+      AC_MSG_ERROR([To build the installer you must have the latest MozillaBuild or Unicode NSIS with a major version of $REQ_NSIS_MAJOR_VER and a minimum minor version of $MIN_NSIS_MINOR_VER in your path.])
+    else
+      MAKENSISU=
+    fi
 fi
 
 AC_MSG_CHECKING([for tar archiver])
 AC_CHECK_PROGS(TAR, gnutar gtar tar, "")
 if test -z "$TAR"; then
     AC_MSG_ERROR([no tar archiver found in \$PATH])
 fi
 AC_MSG_RESULT([$TAR])
@@ -6454,24 +6463,16 @@ dnl ====================================
 dnl build the tests by default
 dnl ========================================================
 MOZ_ARG_DISABLE_BOOL(tests,
 [  --disable-tests         Do not build test libraries & programs],
     ENABLE_TESTS=,
     ENABLE_TESTS=1 )
 
 dnl ========================================================
-dnl Marionette
-dnl ========================================================
-MOZ_ARG_ENABLE_BOOL(marionette,
-[  --enable-marionette     Enable Marionette for remote testing and control],
-    ENABLE_MARIONETTE=1,
-    ENABLE_MARIONETTE)
-
-dnl ========================================================
 dnl parental controls (for Windows Vista)
 dnl ========================================================
 MOZ_ARG_DISABLE_BOOL(parental-controls,
 [  --disable-parental-controls
                           Do not build parental controls],
    MOZ_DISABLE_PARENTAL_CONTROLS=1,
    MOZ_DISABLE_PARENTAL_CONTROLS=)
 if test -n "$MOZ_DISABLE_PARENTAL_CONTROLS"; then
--- a/content/base/src/contentSecurityPolicy.js
+++ b/content/base/src/contentSecurityPolicy.js
@@ -14,16 +14,17 @@
  * The Original Code is the ContentSecurityPolicy module.
  *
  * The Initial Developer of the Original Code is
  *   Mozilla Corporation
  *
  * Contributor(s):
  *   Sid Stamm <sid@mozilla.com>
  *   Brandon Sterne <bsterne@mozilla.com>
+ *   Ian Melven <imelven@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
@@ -296,28 +297,32 @@ ContentSecurityPolicy.prototype = {
       // should be taken care of in CSPRep.fromString (where it converts any
       // relative URIs into absolute ones based on "self").
       for (let i in uris) {
         if (uris[i] === "")
           continue;
 
         var failure = function(aEvt) {  
           if (req.readyState == 4 && req.status != 200) {
-            CSPError("Failed to send report to " + reportURI);
+            CSPError("Failed to send report to " + uris[i]);
           }  
         };  
         var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]  
                     .createInstance(Ci.nsIXMLHttpRequest);  
 
         try {
           req.open("POST", uris[i], true);
           req.setRequestHeader('Content-Type', 'application/json');
           req.upload.addEventListener("error", failure, false);
           req.upload.addEventListener("abort", failure, false);
 
+          // we need to set an nsIChannelEventSink on the XHR object
+          // so we can tell it to not follow redirects when posting the reports
+          req.channel.notificationCallbacks = new CSPReportRedirectSink();
+
           req.send(JSON.stringify(report));
           CSPdebug("Sent violation report to " + uris[i]);
         } catch(e) {
           // it's possible that the URI was invalid, just log a
           // warning and skip over that.
           CSPWarning("Tried to send report to invalid URI: \"" + uris[i] + "\"");
         }
       }
@@ -489,9 +494,59 @@ ContentSecurityPolicy.prototype = {
                                      CSP_VIOLATION_TOPIC,
                                      violatedDirective);
         reportSender.sendReports(blockedContentSource, violatedDirective,
                                  aSourceFile, aScriptSample, aLineNum);
       }, Ci.nsIThread.DISPATCH_NORMAL);
   },
 };
 
+// The POST of the violation report (if it happens) should not follow
+// redirects, per the spec. hence, we implement an nsIChannelEventSink
+// with an object so we can tell XHR to abort if a redirect happens.
+function CSPReportRedirectSink() {
+}
+
+CSPReportRedirectSink.prototype = {
+  QueryInterface: function requestor_qi(iid) {
+    if (iid.equals(Ci.nsISupports) ||
+        iid.equals(Ci.nsIInterfaceRequestor) ||
+        iid.equals(Ci.nsIChannelEventSink))
+      return this;
+    throw Cr.NS_ERROR_NO_INTERFACE;
+  },
+
+  // nsIInterfaceRequestor
+  getInterface: function requestor_gi(iid) {
+    if (iid.equals(Ci.nsIChannelEventSink))
+      return this;
+
+    throw Components.results.NS_ERROR_NO_INTERFACE;
+  },
+
+  // nsIChannelEventSink
+  asyncOnChannelRedirect: function channel_redirect(oldChannel, newChannel,
+                                                    flags, callback) {
+    CSPWarning("Post of violation report to " + oldChannel.URI.asciiSpec +
+               " failed, as a redirect occurred");
+
+    // cancel the old channel so XHR failure callback happens
+    oldChannel.cancel(Cr.NS_ERROR_ABORT);
+
+    // notify an observer that we have blocked the report POST due to a redirect,
+    // used in testing, do this async since we're in an async call now to begin with
+    Services.tm.mainThread.dispatch(
+      function() {
+        observerSubject = Cc["@mozilla.org/supports-cstring;1"]
+                             .createInstance(Ci.nsISupportsCString);
+        observerSubject.data = oldChannel.URI.asciiSpec;
+
+        Services.obs.notifyObservers(observerSubject,
+                                     CSP_VIOLATION_TOPIC,
+                                     "denied redirect while sending violation report");
+      }, Ci.nsIThread.DISPATCH_NORMAL);
+
+    // throw to stop the redirect happening
+    throw Cr.NS_BINDING_REDIRECTED;
+  }
+};
+
 var NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentSecurityPolicy]);
--- a/content/base/src/nsCCUncollectableMarker.cpp
+++ b/content/base/src/nsCCUncollectableMarker.cpp
@@ -373,8 +373,34 @@ nsCCUncollectableMarker::Observe(nsISupp
   if (xulCache) {
     xulCache->MarkInCCGeneration(sGeneration);
   }
 #endif
 
   return NS_OK;
 }
 
+static PLDHashOperator
+TraceActiveWindowGlobal(const PRUint64& aId, nsGlobalWindow*& aWindow, void* aClosure)
+{
+  if (aWindow->GetDocShell() && aWindow->IsOuterWindow()) {
+    if (JSObject* global = aWindow->FastGetGlobalJSObject()) {
+      JSTracer* trc = static_cast<JSTracer *>(aClosure);
+      JS_CALL_OBJECT_TRACER(trc, global, "active window global");
+    }
+  }
+  return PL_DHASH_NEXT;
+}
+
+void
+mozilla::dom::TraceBlackJS(JSTracer* aTrc)
+{
+  if (!nsCCUncollectableMarker::sGeneration) {
+    return;
+  }
+
+  // Mark globals of active windows black.
+  nsGlobalWindow::WindowByIdTable* windowsById =
+    nsGlobalWindow::GetWindowsTable();
+  if (windowsById) {
+    windowsById->Enumerate(TraceActiveWindowGlobal, aTrc);
+  }
+}
--- a/content/base/src/nsCCUncollectableMarker.h
+++ b/content/base/src/nsCCUncollectableMarker.h
@@ -33,16 +33,18 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsIObserver.h"
 #include "nsCycleCollectionParticipant.h"
 
+struct JSTracer;
+
 class nsCCUncollectableMarker : public nsIObserver
 {
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   /**
    * Inits a global nsCCUncollectableMarker. Should only be called once.
    */
@@ -51,20 +53,26 @@ class nsCCUncollectableMarker : public n
   /**
    * Checks if we're collecting during a given generation
    */
   static bool InGeneration(PRUint32 aGeneration)
   {
     return aGeneration && aGeneration == sGeneration;
   }
 
-  static bool InGeneration(nsCycleCollectionTraversalCallback &cb,
+  static bool InGeneration(nsCycleCollectionTraversalCallback& aCb,
                            PRUint32 aGeneration)
   {
-    return InGeneration(aGeneration) && !cb.WantAllTraces();
+    return InGeneration(aGeneration) && !aCb.WantAllTraces();
   }
 
   static PRUint32 sGeneration;
 
 private:
   nsCCUncollectableMarker() {}
 
 };
+
+namespace mozilla {
+namespace dom {
+void TraceBlackJS(JSTracer* aTrc);
+}
+}
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -2542,16 +2542,17 @@ nsDocument::InitCSP()
 #endif
   return NS_OK;
 }
 
 void
 nsDocument::StopDocumentLoad()
 {
   if (mParser) {
+    mParserAborted = true;
     mParser->Terminate();
   }
 }
 
 void
 nsDocument::SetDocumentURI(nsIURI* aURI)
 {
   nsCOMPtr<nsIURI> oldBase = GetDocBaseURI();
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -1183,16 +1183,20 @@ protected:
 
   // Whether we are currently in full-screen mode, as per the DOM API.
   bool mIsFullScreen:1;
 
   // Whether we're currently under a FlushPendingNotifications call to
   // our presshell.  This is used to handle flush reentry correctly.
   bool mInFlush:1;
 
+  // Parser aborted. True if the parser of this document was forcibly
+  // terminated instead of letting it finish at its own pace.
+  bool mParserAborted:1;
+
   PRUint8 mXMLDeclarationBits;
 
   nsInterfaceHashtable<nsPtrHashKey<nsIContent>, nsPIBoxObject> *mBoxObjectTable;
 
   // The channel that got passed to StartDocumentLoad(), if any
   nsCOMPtr<nsIChannel> mChannel;
   nsRefPtr<nsHTMLCSSStyleSheet> mStyleAttrStyleSheet;
   nsRefPtr<nsXMLEventsManager> mXMLEventsManager;
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -1930,17 +1930,18 @@ GK_ATOM(Stop, "Stop")
 GK_ATOM(Search, "Search")
 GK_ATOM(Bookmarks, "Bookmarks")
 GK_ATOM(Home, "Home")
 GK_ATOM(Clear, "Clear")
 GK_ATOM(VolumeUp, "VolumeUp")
 GK_ATOM(VolumeDown, "VolumeDown")
 GK_ATOM(Menu, "Menu")
 
-// Smooth scroll profiles
+// Smooth scroll events origins
+GK_ATOM(mouseWheel, "mouseWheel")  // For discrete wheel events (e.g. not OSX magic mouse)
 GK_ATOM(pixels,     "pixels")
 GK_ATOM(lines,      "lines")
 GK_ATOM(pages,      "pages")
 GK_ATOM(scrollbars, "scrollbars")
 GK_ATOM(other,      "other")
 
 #ifdef ACCESSIBILITY
 GK_ATOM(anonid, "anonid")
--- a/content/base/src/nsImageLoadingContent.cpp
+++ b/content/base/src/nsImageLoadingContent.cpp
@@ -309,52 +309,42 @@ nsImageLoadingContent::OnStopDecode(imgI
   if (mCurrentRequestNeedsResetAnimation) {
     nsCOMPtr<imgIContainer> container;
     mCurrentRequest->GetImage(getter_AddRefs(container));
     if (container)
       container->ResetAnimation();
     mCurrentRequestNeedsResetAnimation = false;
   }
 
-  // We just loaded all the data we're going to get. If we haven't done an
-  // initial paint, we want to make sure the image starts decoding for 2
-  // reasons:
+  // We just loaded all the data we're going to get. If we're visible and
+  // haven't done an initial paint (*), we want to make sure the image starts
+  // decoding immediately, for two reasons:
   //
   // 1) This image is sitting idle but might need to be decoded as soon as we
   // start painting, in which case we've wasted time.
   //
   // 2) We want to block onload until all visible images are decoded. We do this
-  // by blocking onload until all in progress decodes get at least one frame
+  // by blocking onload until all in-progress decodes get at least one frame
   // decoded. However, if all the data comes in while painting is suppressed
   // (ie, before the initial paint delay is finished), we fire onload without
   // doing a paint first. This means that decode-on-draw images don't start
   // decoding, so we can't wait for them to finish. See bug 512435.
+  //
+  // (*) IsPaintingSuppressed returns false if we haven't gotten the initial
+  // reflow yet, so we have to test !DidInitialReflow || IsPaintingSuppressed.
+  // It's possible for painting to be suppressed for reasons other than the
+  // initial paint delay (for example, being in the bfcache), but we probably
+  // aren't loading images in those situations.
 
-  // We can only do this if we have a presshell
   nsIDocument* doc = GetOurDocument();
   nsIPresShell* shell = doc ? doc->GetShell() : nsnull;
-  if (shell) {
-    // We need to figure out whether to kick off decoding
-    bool doRequestDecode = false;
-
-    // If we haven't got the initial reflow yet, IsPaintingSuppressed actually
-    // returns false
-    if (!shell->DidInitialReflow())
-      doRequestDecode = true;
+  if (shell && shell->IsVisible() &&
+      (!shell->DidInitialReflow() || shell->IsPaintingSuppressed())) {
 
-    // Figure out if painting is suppressed. Note that it's possible for painting
-    // to be suppressed for reasons other than the initial paint delay (for
-    // example - being in the bfcache), but we probably aren't loading images in
-    // those situations.
-    if (shell->IsPaintingSuppressed())
-      doRequestDecode = true;
-
-    // If we're requesting a decode, do it
-    if (doRequestDecode)
-      mCurrentRequest->RequestDecode();
+    mCurrentRequest->RequestDecode();
   }
 
   // Fire the appropriate DOM event.
   if (NS_SUCCEEDED(aStatus)) {
     FireEvent(NS_LITERAL_STRING("load"));
   } else {
     FireEvent(NS_LITERAL_STRING("error"));
   }
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -2763,20 +2763,23 @@ nsXMLHttpRequest::Send(nsIVariant *aBody
 
   // Hook us up to listen to redirects and the like
   mChannel->GetNotificationCallbacks(getter_AddRefs(mNotificationCallbacks));
   mChannel->SetNotificationCallbacks(this);
 
   // Create our listener
   nsCOMPtr<nsIStreamListener> listener = this;
   if (mState & XML_HTTP_REQUEST_MULTIPART) {
+    Telemetry::Accumulate(Telemetry::MULTIPART_XHR_RESPONSE, 1);
     listener = new nsMultipartProxyListener(listener);
     if (!listener) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
+  } else {
+    Telemetry::Accumulate(Telemetry::MULTIPART_XHR_RESPONSE, 0);
   }
 
   // Blocking gets are common enough out of XHR that we should mark
   // the channel slow by default for pipeline purposes
   AddLoadFlags(mChannel, nsIRequest::INHIBIT_PIPELINE);
 
   if (!IsSystemXHR()) {
     // Always create a nsCORSListenerProxy here even if it's
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -567,16 +567,22 @@ include $(topsrcdir)/config/rules.mk
 		test_bug696301-2.html \
 		bug696301-script-1.js \
 		bug696301-script-1.js^headers^ \
 		bug696301-script-2.js \
 		test_bug737565.html \
 		test_bug737612.html \
 		test_bug738108.html \
 		test_bug366944.html \
+		test_bug650386_redirect_301.html \
+		test_bug650386_redirect_302.html \
+		test_bug650386_redirect_303.html \
+		test_bug650386_redirect_307.html \
+		file_bug650386_content.sjs \
+		file_bug650386_report.sjs \
 		$(NULL)
 
 _CHROME_FILES =	\
 		test_bug357450.js \
 		$(NULL)
 
 # This test fails on the Mac for some reason
 ifneq (,$(filter gtk2 windows,$(MOZ_WIDGET_TOOLKIT)))
new file mode 100644
--- /dev/null
+++ b/content/base/test/file_bug650386_content.sjs
@@ -0,0 +1,37 @@
+// SJS file for tests for bug650386, serves file_bug650386_content.html
+// with a CSP that will trigger a violation and that will report it
+// to file_bug650386_report.sjs
+//
+// This handles 301, 302, 303 and 307 redirects. The HTTP status code
+// returned/type of redirect to do comes from the query string
+// parameter passed in from the test_bug650386_* files and then also
+// uses that value in the report-uri parameter of the CSP
+function handleRequest(request, response) {
+  response.setHeader("Cache-Control", "no-cache", false);
+
+  // this gets used in the CSP as part of the report URI.
+  var redirect = request.queryString;
+
+  if (redirect < 301 || (redirect > 303 && redirect <= 306) || redirect > 307) {
+    // if we somehow got some bogus redirect code here,
+    // do a 302 redirect to the same URL as the report URI
+    // redirects to - this will fail the test.
+    var loc = "http://example.com/some/fake/path";
+    response.setStatusLine("1.1", 302, "Found");
+    response.setHeader("Location", loc, false);
+    return;
+  }
+
+  var csp = "default-src \'self\';report-uri http://mochi.test:8888/tests/content/base/test/file_bug650386_report.sjs?" + redirect;
+
+  response.setHeader("X-Content-Security-Policy", csp, false);
+
+  // the actual file content.
+  // this image load will (intentionally) fail due to the CSP policy of default-src: 'self'
+  // specified by the CSP string above.
+  var content = "<!DOCTYPE HTML><html><body><img src = \"http://some.other.domain.example.com\"></body></html>";
+
+  response.write(content);
+
+  return;
+}
new file mode 100644
--- /dev/null
+++ b/content/base/test/file_bug650386_report.sjs
@@ -0,0 +1,16 @@
+// SJS file for tests for bug650386, this serves as CSP violation report target
+// and issues a redirect, to make sure the browser does not post to the target
+// of the redirect, per CSP spec.
+// This handles 301, 302, 303 and 307 redirects. The HTTP status code
+// returned/type of redirect to do comes from the query string
+// parameter
+function handleRequest(request, response) {
+  response.setHeader("Cache-Control", "no-cache", false);
+
+  var redirect = request.queryString;
+
+  var loc = "http://example.com/some/fake/path";
+  response.setStatusLine("1.1", redirect, "Found");
+  response.setHeader("Location", loc, false);
+  return;
+}
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug650386_redirect_301.html
@@ -0,0 +1,78 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=650386
+Test that CSP violation reports are not sent when a 301 redirect is encountered
+-->
+<head>
+  <title>Test for Bug 650386</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650386">Mozilla Bug 650386</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe id = "content_iframe"></iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 650386 **/
+
+// This is used to watch the redirect of the report POST get blocked
+function examiner() {
+  SpecialPowers.addObserver(this, "csp-on-violate-policy", false);
+  SpecialPowers.addObserver(this, "http-on-modify-request", false);
+}
+
+examiner.prototype  = {
+  observe: function(subject, topic, data) {
+    // subject should be an nsURI
+    if(!SpecialPowers.can_QI(subject))
+       return;
+
+    if (topic === "http-on-modify-request") {
+      // this is used to fail the test - if we see the POST to the target of the redirect
+      // we know this is a fail
+      var asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIHttpChannel"), "URI.asciiSpec");
+
+      if (asciiSpec == "http://example.com/some/fake/path")
+        window.done(false);
+    }
+
+    if(topic === "csp-on-violate-policy") {
+      // something was blocked, but we are looking specifically for the redirect being blocked
+      if (data == "denied redirect while sending violation report")
+        window.done(true);
+    }
+  },
+
+  // must eventually call this to remove the listener,
+  // or mochitests might get borked.
+  remove: function() {
+    SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+    SpecialPowers.removeObserver(this, "http-on-modify-request");
+  }
+}
+
+window.examiner = new examiner();
+
+// result == true if we saw the redirect blocked notify, false if we saw the post
+// to the redirect target go out
+window.done = function(result) {
+  ok(result, "a 301 redirect when posting violation report should be blocked");
+
+  // clean up observers and finish the test
+  window.examiner.remove();
+  SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+// save this for last so that our listeners are registered.
+document.getElementById('content_iframe').src = 'file_bug650386_content.sjs?301';
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug650386_redirect_302.html
@@ -0,0 +1,78 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=650386
+Test that CSP violation reports are not sent when a 302 redirect is encountered
+-->
+<head>
+  <title>Test for Bug 650386</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650386">Mozilla Bug 650386</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe id = "content_iframe"></iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 650386 **/
+
+// This is used to watch the redirect of the report POST get blocked
+function examiner() {
+  SpecialPowers.addObserver(this, "csp-on-violate-policy", false);
+  SpecialPowers.addObserver(this, "http-on-modify-request", false);
+}
+
+examiner.prototype  = {
+  observe: function(subject, topic, data) {
+    // subject should be an nsURI
+    if(!SpecialPowers.can_QI(subject))
+       return;
+
+    if (topic === "http-on-modify-request") {
+      // this is used to fail the test - if we see the POST to the target of the redirect
+      // we know this is a fail
+      var asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIHttpChannel"), "URI.asciiSpec");
+
+      if (asciiSpec == "http://example.com/some/fake/path")
+        window.done(false);
+    }
+
+    if(topic === "csp-on-violate-policy") {
+      // something was blocked, but we are looking specifically for the redirect being blocked
+      if (data == "denied redirect while sending violation report")
+        window.done(true);
+    }
+  },
+
+  // must eventually call this to remove the listener,
+  // or mochitests might get borked.
+  remove: function() {
+    SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+    SpecialPowers.removeObserver(this, "http-on-modify-request");
+  }
+}
+
+window.examiner = new examiner();
+
+// result == true if we saw the redirect blocked notify, false if we saw the post
+// to the redirect target go out
+window.done = function(result) {
+  ok(result, "a 302 redirect when posting violation report should be blocked");
+
+  // clean up observers and finish the test
+  window.examiner.remove();
+  SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+// save this for last so that our listeners are registered.
+document.getElementById('content_iframe').src = 'file_bug650386_content.sjs?302';
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug650386_redirect_303.html
@@ -0,0 +1,78 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=650386
+Test that CSP violation reports are not sent when a 303 redirect is encountered
+-->
+<head>
+  <title>Test for Bug 650386</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650386">Mozilla Bug 650386</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe id = "content_iframe"></iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 650386 **/
+
+// This is used to watch the redirect of the report POST get blocked
+function examiner() {
+  SpecialPowers.addObserver(this, "csp-on-violate-policy", false);
+  SpecialPowers.addObserver(this, "http-on-modify-request", false);
+}
+
+examiner.prototype  = {
+  observe: function(subject, topic, data) {
+    // subject should be an nsURI
+    if(!SpecialPowers.can_QI(subject))
+       return;
+
+    if (topic === "http-on-modify-request") {
+      // this is used to fail the test - if we see the POST to the target of the redirect
+      // we know this is a fail
+      var asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIHttpChannel"), "URI.asciiSpec");
+
+      if (asciiSpec == "http://example.com/some/fake/path")
+        window.done(false);
+    }
+
+    if(topic === "csp-on-violate-policy") {
+      // something was blocked, but we are looking specifically for the redirect being blocked
+      if (data == "denied redirect while sending violation report")
+        window.done(true);
+    }
+  },
+
+  // must eventually call this to remove the listener,
+  // or mochitests might get borked.
+  remove: function() {
+    SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+    SpecialPowers.removeObserver(this, "http-on-modify-request");
+  }
+}
+
+window.examiner = new examiner();
+
+// result == true if we saw the redirect blocked notify, false if we saw the post
+// to the redirect target go out
+window.done = function(result) {
+  ok(result, "a 303 redirect when posting violation report should be blocked");
+
+  // clean up observers and finish the test
+  window.examiner.remove();
+  SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+// save this for last so that our listeners are registered.
+document.getElementById('content_iframe').src = 'file_bug650386_content.sjs?303';
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug650386_redirect_307.html
@@ -0,0 +1,78 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=650386
+Test that CSP violation reports are not sent when a 307 redirect is encountered
+-->
+<head>
+  <title>Test for Bug 650386</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650386">Mozilla Bug 650386</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe id = "content_iframe"></iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 650386 **/
+
+// This is used to watch the redirect of the report POST get blocked
+function examiner() {
+  SpecialPowers.addObserver(this, "csp-on-violate-policy", false);
+  SpecialPowers.addObserver(this, "http-on-modify-request", false);
+}
+
+examiner.prototype  = {
+  observe: function(subject, topic, data) {
+    // subject should be an nsURI
+    if(!SpecialPowers.can_QI(subject))
+       return;
+
+    if (topic === "http-on-modify-request") {
+      // this is used to fail the test - if we see the POST to the target of the redirect
+      // we know this is a fail
+      var asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIHttpChannel"), "URI.asciiSpec");
+
+      if (asciiSpec == "http://example.com/some/fake/path")
+        window.done(false);
+    }
+
+    if(topic === "csp-on-violate-policy") {
+      // something was blocked, but we are looking specifically for the redirect being blocked
+      if (data == "denied redirect while sending violation report")
+        window.done(true);
+    }
+  },
+
+  // must eventually call this to remove the listener,
+  // or mochitests might get borked.
+  remove: function() {
+    SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+    SpecialPowers.removeObserver(this, "http-on-modify-request");
+  }
+}
+
+window.examiner = new examiner();
+
+// result == true if we saw the redirect blocked notify, false if we saw the post
+// to the redirect target go out
+window.done = function(result) {
+  ok(result, "a 307 redirect when posting violation report should be blocked");
+
+  // clean up observers and finish the test
+  window.examiner.remove();
+  SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+// save this for last so that our listeners are registered.
+document.getElementById('content_iframe').src = 'file_bug650386_content.sjs?307';
+</script>
+</pre>
+</body>
+</html>
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -2690,17 +2690,18 @@ nsEventStateManager::UseSystemScrollSett
   return Preferences::GetBool(prefName.get());
 }
 
 nsresult
 nsEventStateManager::DoScrollText(nsIFrame* aTargetFrame,
                                   nsMouseScrollEvent* aMouseEvent,
                                   nsIScrollableFrame::ScrollUnit aScrollQuantity,
                                   bool aAllowScrollSpeedOverride,
-                                  nsQueryContentEvent* aQueryEvent)
+                                  nsQueryContentEvent* aQueryEvent,
+                                  nsIAtom *aOrigin)
 {
   nsIScrollableFrame* frameToScroll = nsnull;
   nsIFrame* scrollFrame = aTargetFrame;
   PRInt32 numLines = aMouseEvent->delta;
   bool isHorizontal = aMouseEvent->scrollFlags & nsMouseScrollEvent::kIsHorizontal;
   aMouseEvent->scrollOverflow = 0;
 
   // If the user recently scrolled with the mousewheel, then they probably want
@@ -2852,27 +2853,27 @@ nsEventStateManager::DoScrollText(nsIFra
     } else {
       mode = nsIScrollableFrame::NORMAL;
     }
 
     // XXX Why don't we limit the pixel scroll amount to less one page??
 
     nsIntPoint overflow;
     frameToScroll->ScrollBy(nsIntPoint(scrollX, scrollY), aScrollQuantity,
-                            mode, &overflow);
+                            mode, &overflow, aOrigin);
     aMouseEvent->scrollOverflow = isHorizontal ? overflow.x : overflow.y;
     return NS_OK;
   }
   
   if (passToParent) {
     nsIFrame* newFrame = nsLayoutUtils::GetCrossDocParentFrame(
         aTargetFrame->PresContext()->FrameManager()->GetRootFrame());
     if (newFrame)
       return DoScrollText(newFrame, aMouseEvent, aScrollQuantity,
-                          aAllowScrollSpeedOverride, aQueryEvent);
+                          aAllowScrollSpeedOverride, aQueryEvent, aOrigin);
   }
 
   aMouseEvent->scrollOverflow = numLines;
 
   return NS_OK;
 }
 
 void
@@ -3208,27 +3209,30 @@ nsEventStateManager::PostHandleEvent(nsP
 
       if (*aStatus != nsEventStatus_eConsumeNoDefault) {
         bool useSysNumLines = UseSystemScrollSettingFor(msEvent);
         PRInt32 action = ComputeWheelActionFor(msEvent, useSysNumLines);
 
         switch (action) {
         case MOUSE_SCROLL_N_LINES:
           DoScrollText(aTargetFrame, msEvent, nsIScrollableFrame::LINES,
-                       useSysNumLines);
+                       useSysNumLines, nsnull, nsGkAtoms::mouseWheel);
           break;
 
         case MOUSE_SCROLL_PAGE:
           DoScrollText(aTargetFrame, msEvent, nsIScrollableFrame::PAGES,
                        false);
           break;
 
         case MOUSE_SCROLL_PIXELS:
-          DoScrollText(aTargetFrame, msEvent, nsIScrollableFrame::DEVICE_PIXELS,
-                       false);
+          {
+            bool fromLines = msEvent->scrollFlags & nsMouseScrollEvent::kFromLines;
+            DoScrollText(aTargetFrame, msEvent, nsIScrollableFrame::DEVICE_PIXELS,
+                         false, nsnull, (fromLines ? nsGkAtoms::mouseWheel : nsnull));
+          }
           break;
 
         case MOUSE_SCROLL_HISTORY:
           DoScrollHistory(msEvent->delta);
           break;
 
         case MOUSE_SCROLL_ZOOM:
           DoScrollZoom(aTargetFrame, msEvent->delta);
--- a/content/events/src/nsEventStateManager.h
+++ b/content/events/src/nsEventStateManager.h
@@ -348,17 +348,18 @@ protected:
    *                    And then, this method does NOT scroll any scrollable
    *                    elements.  I.e., you can just query the scroll target
    *                    information.
    */
   nsresult DoScrollText(nsIFrame* aTargetFrame,
                         nsMouseScrollEvent* aMouseEvent,
                         nsIScrollableFrame::ScrollUnit aScrollQuantity,
                         bool aAllowScrollSpeedOverride,
-                        nsQueryContentEvent* aQueryEvent = nsnull);
+                        nsQueryContentEvent* aQueryEvent = nsnull,
+                        nsIAtom *aOrigin = nsnull);
   void DoScrollHistory(PRInt32 direction);
   void DoScrollZoom(nsIFrame *aTargetFrame, PRInt32 adjustment);
   nsresult GetMarkupDocumentViewer(nsIMarkupDocumentViewer** aMv);
   nsresult ChangeTextSize(PRInt32 change);
   nsresult ChangeFullZoom(PRInt32 change);
   /**
    * Computes actual delta value used for scrolling.  If user customized the
    * scrolling speed and/or direction, this would return the customized value.
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -129,16 +129,17 @@
 #include "nsCCUncollectableMarker.h"
 #include "nsHtml5Module.h"
 #include "prprf.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/Preferences.h"
 #include "nsMimeTypes.h"
 #include "nsIRequest.h"
 #include "nsHtml5TreeOpExecutor.h"
+#include "nsHtml5Parser.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 #define NS_MAX_DOCUMENT_WRITE_DEPTH 20
 
 #include "prmem.h"
 #include "prtime.h"
@@ -1553,16 +1554,17 @@ nsHTMLDocument::Open(const nsAString& aC
   if (baseURI) {
     mDocumentBaseURI = baseURI;
   }
 
   // Store the security info of the caller now that we're done
   // resetting the document.
   mSecurityInfo = securityInfo;
 
+  mParserAborted = false;
   bool loadAsHtml5 = nsHtml5Module::sEnabled;
   if (loadAsHtml5) {
     mParser = nsHtml5Module::NewHtml5Parser();
     rv = NS_OK;
   } else {
     mParser = do_CreateInstance(kCParserCID, &rv);  
   }
 
@@ -1639,18 +1641,18 @@ nsHTMLDocument::Close()
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
   if (!mParser || !mParser->IsScriptCreated()) {
     return NS_OK;
   }
 
   ++mWriteLevel;
-  nsresult rv = mParser->Parse(EmptyString(), nsnull,
-                               GetContentTypeInternal(), true);
+  nsresult rv = (static_cast<nsHtml5Parser*>(mParser.get()))->Parse(
+    EmptyString(), nsnull, GetContentTypeInternal(), true);
   --mWriteLevel;
 
   // XXX Make sure that all the document.written content is
   // reflowed.  We should remove this call once we change
   // nsHTMLDocument::OpenCommon() so that it completely destroys the
   // earlier document's content and frame hierarchy.  Right now, it
   // re-uses the earlier document's root content object and
   // corresponding frame objects.  These re-used frame objects think
@@ -1696,16 +1698,23 @@ nsHTMLDocument::WriteCommon(JSContext *c
   NS_ENSURE_STATE(!mTooDeepWriteRecursion);
 
   if (!IsHTML() || mDisableDocWrite) {
     // No calling document.write*() on XHTML!
 
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
+  if (mParserAborted) {
+    // Hixie says aborting the parser doesn't undefine the insertion point.
+    // However, since we null out mParser in that case, we track the
+    // theoretically defined insertion point using mParserAborted.
+    return NS_OK;
+  }
+
   nsresult rv = NS_OK;
 
   void *key = GenerateParserKey();
   if (mParser && !mParser->IsInsertionPointDefined()) {
     if (mExternalScriptsBeingEvaluated) {
       // Instead of implying a call to document.open(), ignore the call.
       nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
                                       "DOM Events", this,
@@ -1759,23 +1768,21 @@ nsHTMLDocument::WriteCommon(JSContext *c
 
   ++mWriteLevel;
 
   // This could be done with less code, but for performance reasons it
   // makes sense to have the code for two separate Parse() calls here
   // since the concatenation of strings costs more than we like. And
   // why pay that price when we don't need to?
   if (aNewlineTerminate) {
-    rv = mParser->Parse(aText + new_line,
-                        key, GetContentTypeInternal(),
-                        false);
+    rv = (static_cast<nsHtml5Parser*>(mParser.get()))->Parse(
+      aText + new_line, key, GetContentTypeInternal(), false);
   } else {
-    rv = mParser->Parse(aText,
-                        key, GetContentTypeInternal(),
-                        false);
+    rv = (static_cast<nsHtml5Parser*>(mParser.get()))->Parse(
+      aText, key, GetContentTypeInternal(), false);
   }
 
   --mWriteLevel;
 
   mTooDeepWriteRecursion = (mWriteLevel != 0 && mTooDeepWriteRecursion);
 
   return rv;
 }
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -8343,23 +8343,16 @@ nsDocShell::InternalLoad(nsIURI * aURI,
         // that history.go(0) and the like trigger full refreshes, rather than
         // short-circuited loads.
         bool doShortCircuitedLoad =
           (historyNavBetweenSameDoc && mOSHE != aSHEntry) ||
           (!aSHEntry && aPostData == nsnull &&
            sameExceptHashes && !newHash.IsEmpty());
 
         if (doShortCircuitedLoad) {
-            // If our load group contains a LOAD_DOCUMENT_URI request with a
-            // channel which doesn't match our document's channel, cancel it.
-            //
-            // That is, a short-circuited load will cancel a non-short-circuited
-            // load of a different document.
-            StopOutstandingOtherDocumentLoad();
-
             // Save the current URI; we need it if we fire a hashchange later.
             nsCOMPtr<nsIURI> oldURI = mCurrentURI;
 
             // Save the position of the scrollers.
             nscoord cx = 0, cy = 0;
             GetCurScrollPos(ScrollOrientation_X, &cx);
             GetCurScrollPos(ScrollOrientation_Y, &cy);
 
@@ -8649,57 +8642,16 @@ nsDocShell::InternalLoad(nsIURI * aURI,
     if (NS_FAILED(rv)) {
         nsCOMPtr<nsIChannel> chan(do_QueryInterface(req));
         DisplayLoadError(rv, aURI, nsnull, chan);
     }
 
     return rv;
 }
 
-// If our load group contains a LOAD_DOCUMENT_URI channel that's not our
-// document's channel, cancel it.
-void
-nsDocShell::StopOutstandingOtherDocumentLoad()
-{
-    nsCOMPtr<nsIChannel> docChannel = GetCurrentDocChannel();
-    if (!docChannel || !mLoadGroup) {
-        return;
-    }
-
-    nsCOMPtr<nsISimpleEnumerator> requests;
-    mLoadGroup->GetRequests(getter_AddRefs(requests));
-    if (!requests) {
-        return;
-    }
-
-    while (true) {
-        bool hasMoreElements = false;
-        requests->HasMoreElements(&hasMoreElements);
-        if (!hasMoreElements) {
-            break;
-        }
-
-        nsCOMPtr<nsISupports> next;
-        requests->GetNext(getter_AddRefs(next));
-
-        nsCOMPtr<nsIChannel> channel = do_QueryInterface(next);
-        if (!channel) {
-            continue;
-        }
-
-        nsLoadFlags flags;
-        channel->GetLoadFlags(&flags);
-
-        // As promised, cancel the channel if it's loading a different document.
-        if ((flags & nsIChannel::LOAD_DOCUMENT_URI) && channel != docChannel) {
-            channel->Cancel(NS_BINDING_ABORTED);
-        }
-    }
-}
-
 nsIPrincipal*
 nsDocShell::GetInheritedPrincipal(bool aConsiderCurrentDocument)
 {
     nsCOMPtr<nsIDocument> document;
     bool inheritedFromCurrent = false;
 
     if (aConsiderCurrentDocument && mContentViewer) {
         document = mContentViewer->GetDocument();
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -667,21 +667,16 @@ protected:
     // helpers for executing commands
     nsresult GetControllerForCommand(const char *inCommand,
                                      nsIController** outController);
     nsresult IsCommandEnabled(const char * inCommand, bool* outEnabled);
     nsresult DoCommand(const char * inCommand);
     nsresult EnsureCommandHandler();
 
     nsIChannel* GetCurrentDocChannel();
-
-    // If our load group contains a LOAD_DOCUMENT_URI channel that's not our
-    // document's channel, cancel it.
-    void StopOutstandingOtherDocumentLoad();
-
 protected:
     // Override the parent setter from nsDocLoader
     virtual nsresult SetDocLoaderParent(nsDocLoader * aLoader);
 
     void ClearFrameHistory(nsISHEntry* aEntry);
 
     nsresult MaybeInitTiming();
 
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1148,17 +1148,17 @@ NS_IMETHODIMP
 Navigator::GetMozBluetooth(nsIDOMBluetoothAdapter** aBluetooth)
 {
   nsCOMPtr<nsIDOMBluetoothAdapter> bluetooth = mBluetooth;
 
   if (!bluetooth) {
     nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
     NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
 
-    mBluetooth = new bluetooth::BluetoothAdapter();
+    mBluetooth = new bluetooth::BluetoothAdapter(window);
 
     bluetooth = mBluetooth;
   }
 
   bluetooth.forget(aBluetooth);
   return NS_OK;
 }
 #endif //MOZ_B2G_BT
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -938,26 +938,27 @@ nsJSContext::JSOptionChangedCallback(con
   if (strict)
     newDefaultJSOptions |= JSOPTION_STRICT;
   else
     newDefaultJSOptions &= ~JSOPTION_STRICT;
 
   nsIScriptGlobalObject *global = context->GetGlobalObject();
   // XXX should we check for sysprin instead of a chrome window, to make
   // XXX components be covered by the chrome pref instead of the content one?
+  nsCOMPtr<nsIDOMWindow> contentWindow(do_QueryInterface(global));
   nsCOMPtr<nsIDOMChromeWindow> chromeWindow(do_QueryInterface(global));
 
-  bool useMethodJIT = Preferences::GetBool(chromeWindow ?
+  bool useMethodJIT = Preferences::GetBool(chromeWindow || !contentWindow ?
                                                js_methodjit_chrome_str :
                                                js_methodjit_content_str);
-  bool usePCCounts = Preferences::GetBool(chromeWindow ?
+  bool usePCCounts = Preferences::GetBool(chromeWindow || !contentWindow ?
                                             js_pccounts_chrome_str :
                                             js_pccounts_content_str);
   bool useMethodJITAlways = Preferences::GetBool(js_methodjit_always_str);
-  bool useTypeInference = !chromeWindow && Preferences::GetBool(js_typeinfer_str);
+  bool useTypeInference = !chromeWindow && contentWindow && Preferences::GetBool(js_typeinfer_str);
   bool useHardening = Preferences::GetBool(js_jit_hardening_str);
   nsCOMPtr<nsIXULRuntime> xr = do_GetService(XULRUNTIME_SERVICE_CONTRACTID);
   if (xr) {
     bool safeMode = false;
     xr->GetInSafeMode(&safeMode);
     if (safeMode) {
       useMethodJIT = false;
       usePCCounts = false;
@@ -987,17 +988,17 @@ nsJSContext::JSOptionChangedCallback(con
   else
     newDefaultJSOptions &= ~JSOPTION_TYPE_INFERENCE;
 
 #ifdef DEBUG
   // In debug builds, warnings are enabled in chrome context if
   // javascript.options.strict.debug is true
   bool strictDebug = Preferences::GetBool(js_strict_debug_option_str);
   if (strictDebug && (newDefaultJSOptions & JSOPTION_STRICT) == 0) {
-    if (chromeWindow)
+    if (chromeWindow || !contentWindow)
       newDefaultJSOptions |= JSOPTION_STRICT;
   }
 #endif
 
   bool werror = Preferences::GetBool(js_werror_option_str);
   if (werror)
     newDefaultJSOptions |= JSOPTION_WERROR;
   else
@@ -2741,17 +2742,17 @@ static JSFunctionSpec DMDFunctions[] = {
 nsresult
 nsJSContext::InitClasses(JSObject* aGlobalObj)
 {
   nsresult rv = InitializeExternalClasses();
   NS_ENSURE_SUCCESS(rv, rv);
 
   JSAutoRequest ar(mContext);
 
-  ::JS_SetOptions(mContext, mDefaultJSOptions);
+  JSOptionChangedCallback(js_options_dot_str, this);
 
   // Attempt to initialize profiling functions
   ::JS_DefineProfilingFunctions(mContext, aGlobalObj);
 
 #ifdef NS_TRACE_MALLOC
   // Attempt to initialize TraceMalloc functions
   ::JS_DefineFunctions(mContext, aGlobalObj, TraceMallocFunctions);
 #endif
--- a/dom/base/nsStructuredCloneContainer.cpp
+++ b/dom/base/nsStructuredCloneContainer.cpp
@@ -80,16 +80,17 @@ nsStructuredCloneContainer::InitFromVari
   jsval jsData;
   nsresult rv = aData->GetAsJSVal(&jsData);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
 
   // Make sure that we serialize in the right context.
   JSAutoRequest ar(aCx);
   JSAutoEnterCompartment ac;
   NS_ENSURE_STATE(ac.enter(aCx, JS_GetGlobalObject(aCx)));
+  JS_WrapValue(aCx, &jsData);
 
   nsCxPusher cxPusher;
   cxPusher.Push(aCx);
 
   uint64_t* jsBytes = nsnull;
   bool success = JS_WriteStructuredClone(aCx, jsData, &jsBytes, &mSize,
                                            nsnull, nsnull);
   NS_ENSURE_STATE(success);
--- a/dom/bluetooth/BluetoothAdapter.cpp
+++ b/dom/bluetooth/BluetoothAdapter.cpp
@@ -1,21 +1,41 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=40: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "BluetoothAdapter.h"
+
 #include "nsDOMClassInfo.h"
 #include "nsDOMEvent.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOMCIDInternal.h"
 #include "mozilla/LazyIdleThread.h"
+#include "mozilla/Util.h"
 #include <dlfcn.h>
-#include "BluetoothAdapter.h"
+
+static void
+FireEnabled(bool aResult, nsIDOMDOMRequest* aDomRequest)
+{
+  nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
+
+  if (!rs) {
+    NS_WARNING("No DOMRequest Service!");
+    return;
+  }
+
+  mozilla::DebugOnly<nsresult> rv = aResult ?     
+                                    rs->FireSuccess(aDomRequest, JSVAL_VOID) :
+                                    rs->FireError(aDomRequest, 
+                                                  NS_LITERAL_STRING("Bluetooth firmware loading failed"));
+
+  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Bluetooth firmware loading failed");
+}
 
 USING_BLUETOOTH_NAMESPACE
 
 static struct BluedroidFunctions {
   bool initialized;
   bool tried_initialization;
 
   BluedroidFunctions() :
@@ -62,178 +82,169 @@ static bool EnsureBluetoothInit() {
   }
   sBluedroidFunctions.initialized = true;
   return true;
 }
 
 class ToggleBtResultTask : public nsRunnable
 {
   public:
-    ToggleBtResultTask(nsRefPtr<BluetoothAdapter>& adapterPtr, bool result)
-      : mResult(result)
+    ToggleBtResultTask(nsRefPtr<BluetoothAdapter>& adapterPtr, 
+                       nsCOMPtr<nsIDOMDOMRequest>& req,
+                       bool enabled,
+                       bool result)
+      : mResult(result),
+        mEnabled(enabled)
     {
       MOZ_ASSERT(!NS_IsMainThread());
 
+      mDOMRequest.swap(req);
       mAdapterPtr.swap(adapterPtr);
     }
 
     NS_IMETHOD Run() 
     {
       MOZ_ASSERT(NS_IsMainThread());
 
-      if (!mResult) {
-        //TODO:Bug-731361
-        NS_WARNING("BT firmware loading fails.\n");
+      // Update bt power status to BluetoothAdapter only if loading bluetooth 
+      // firmware succeeds.
+      if (mResult) {
+        mAdapterPtr->SetEnabledInternal(mEnabled);
       }
- 
+
+      FireEnabled(mResult, mDOMRequest);
+
       //mAdapterPtr must be null before returning to prevent the background 
       //thread from racing to release it during the destruction of this runnable.
-      mAdapterPtr->FirePowered();
       mAdapterPtr = nsnull;
+      mDOMRequest = nsnull;
 
       return NS_OK;
     }
 
   private:
     nsRefPtr<BluetoothAdapter> mAdapterPtr;
+    nsCOMPtr<nsIDOMDOMRequest> mDOMRequest;
+    bool mEnabled;
     bool mResult;
 };
 
 class ToggleBtTask : public nsRunnable
 {
   public:
-    ToggleBtTask(bool onOff, BluetoothAdapter* adapterPtr)
-      : mOnOff(onOff),
+    ToggleBtTask(bool enabled, nsIDOMDOMRequest* req, BluetoothAdapter* adapterPtr)
+      : mEnabled(enabled),
+        mDOMRequest(req),
         mAdapterPtr(adapterPtr) 
     {
       MOZ_ASSERT(NS_IsMainThread());
     }
 
     NS_IMETHOD Run() 
     {
       MOZ_ASSERT(!NS_IsMainThread());
 
+      bool result;
+
+#ifdef MOZ_WIDGET_GONK
+      // Platform specific check for gonk until object is divided in
+      // different implementations per platform. Linux doesn't require
+      // bluetooth firmware loading, but code should work otherwise.
       if(!EnsureBluetoothInit()) {
         NS_ERROR("Failed to load bluedroid library.\n");
         return NS_ERROR_FAILURE;
       }
 
-      bool result;
-
-      //Toggle BT here
+      // return 1 if it's enabled, 0 if it's disabled, and -1 on error
+      int isEnabled = sBluedroidFunctions.bt_is_enabled();
 
-      if (mOnOff) {
-        result = sBluedroidFunctions.bt_enable();
+      if ((isEnabled == 1 && mEnabled) || (isEnabled == 0 && !mEnabled)) {
+        result = true;
+      } else if (isEnabled < 0) {
+        result = false;
+      } else if (mEnabled) {
+        result = (sBluedroidFunctions.bt_enable() == 0) ? true : false;
       } else {
-        result = sBluedroidFunctions.bt_disable();
+        result = (sBluedroidFunctions.bt_disable() == 0) ? true : false;
       }
+#else
+      result = true;
+      NS_WARNING("No bluetooth support in this build configuration, faking a success event instead");
+#endif
 
       // Create a result thread and pass it to Main Thread, 
-      nsCOMPtr<nsIRunnable> resultRunnable = new ToggleBtResultTask(mAdapterPtr, result);
+      nsCOMPtr<nsIRunnable> resultRunnable = new ToggleBtResultTask(mAdapterPtr, mDOMRequest, mEnabled, result);
 
       if (NS_FAILED(NS_DispatchToMainThread(resultRunnable))) {
         NS_WARNING("Failed to dispatch to main thread!");
       }
 
       return NS_OK;
     }
 
   private:
-    bool mOnOff;
+    bool mEnabled;
     nsRefPtr<BluetoothAdapter> mAdapterPtr;
+    nsCOMPtr<nsIDOMDOMRequest> mDOMRequest;
 };
 
 DOMCI_DATA(BluetoothAdapter, BluetoothAdapter)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothAdapter)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothAdapter, 
                                                   nsDOMEventTargetHelper)
-  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(powered)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(enabled)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothAdapter, 
                                                 nsDOMEventTargetHelper)
-  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(powered)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(enabled)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothAdapter)
   NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothAdapter)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothAdapter)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(BluetoothAdapter, nsDOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(BluetoothAdapter, nsDOMEventTargetHelper)
 
-BluetoothAdapter::BluetoothAdapter() 
-  : mPower(false)
+BluetoothAdapter::BluetoothAdapter(nsPIDOMWindow *aWindow) 
 {
+  BindToOwner(aWindow);
 }
 
 NS_IMETHODIMP
-BluetoothAdapter::GetPower(bool* aPower)
+BluetoothAdapter::SetEnabled(bool aEnabled, nsIDOMDOMRequest** aDomRequest)
 {
-#ifdef MOZ_WIDGET_GONK
-  if(!EnsureBluetoothInit()) {
-    NS_ERROR("Failed to load bluedroid library.\n");
+  nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
+
+  if (!rs) {
+    NS_ERROR("No DOMRequest Service!");
     return NS_ERROR_FAILURE;
   }
-  *aPower = sBluedroidFunctions.bt_is_enabled();
-#else
-  *aPower = mPower;
-#endif
+
+  nsCOMPtr<nsIDOMDOMRequest> request;
+  nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(request));
+  NS_ENSURE_SUCCESS(rv, rv);
+  
+  if (!mToggleBtThread) {
+    mToggleBtThread = new LazyIdleThread(15000);
+  }
+
+  nsCOMPtr<nsIRunnable> r = new ToggleBtTask(aEnabled, request, this);
+
+  rv = mToggleBtThread->Dispatch(r, NS_DISPATCH_NORMAL);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  request.forget(aDomRequest);
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
-BluetoothAdapter::SetPower(bool aPower)
+BluetoothAdapter::GetEnabled(bool* aEnabled)
 {
-
-#ifdef MOZ_WIDGET_GONK
-  // Platform specific check for gonk until object is divided in
-  // different implementations per platform. Linux doesn't require
-  // bluetooth firmware loading, but code should work otherwise.
-  if(!EnsureBluetoothInit()) {
-    NS_ERROR("Failed to load bluedroid library.\n");
-    return NS_ERROR_FAILURE;
-  }
-#endif
-  if (mPower != aPower) {
-    mPower = aPower;
-
-#ifdef MOZ_WIDGET_GONK
-    return ToggleBluetoothAsync();
-#endif
-  }
-
-  return NS_OK;
+  *aEnabled = mEnabled;
+  return NS_OK; 
 }
 
-nsresult
-BluetoothAdapter::ToggleBluetoothAsync()
-{
-  if (!mToggleBtThread) {
-    mToggleBtThread = new LazyIdleThread(15000);
-  }
-
-  nsCOMPtr<nsIRunnable> r = new ToggleBtTask(mPower, this);
-
-  return mToggleBtThread->Dispatch(r, NS_DISPATCH_NORMAL);
-}
-
-nsresult
-BluetoothAdapter::FirePowered()
-{
-  nsRefPtr<nsDOMEvent> event = new nsDOMEvent(nsnull, nsnull);
-  nsresult rv = event->InitEvent(NS_LITERAL_STRING("powered"), false, false);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = event->SetTrusted(true);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  bool dummy;
-  rv = DispatchEvent(event, &dummy);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
-}
-
-NS_IMPL_EVENT_HANDLER(BluetoothAdapter, powered)
--- a/dom/bluetooth/BluetoothAdapter.h
+++ b/dom/bluetooth/BluetoothAdapter.h
@@ -5,16 +5,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_bluetooth_bluetoothadapter_h__
 #define mozilla_dom_bluetooth_bluetoothadapter_h__
 
 #include "BluetoothCommon.h"
 #include "nsDOMEventTargetHelper.h"
 #include "nsIDOMBluetoothAdapter.h"
+#include "nsIDOMDOMRequest.h"
 
 class nsIEventTarget;
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothAdapter : public nsIDOMBluetoothAdapter
                        , public nsDOMEventTargetHelper
 {
@@ -22,24 +23,24 @@ public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMBLUETOOTHADAPTER
 
   NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BluetoothAdapter,
                                            nsDOMEventTargetHelper)
 
-  BluetoothAdapter();
+  BluetoothAdapter(nsPIDOMWindow*);
 
-  nsresult FirePowered();
+  inline void SetEnabledInternal(bool aEnabled) {mEnabled = aEnabled;}
 
 protected:
-  bool mPower;
+  bool mEnabled;
 
-  NS_DECL_EVENT_HANDLER(powered)
+  NS_DECL_EVENT_HANDLER(enabled)
 
 private:
   nsCOMPtr<nsIEventTarget> mToggleBtThread;
-  nsresult ToggleBluetoothAsync();
 };
 
 END_BLUETOOTH_NAMESPACE
+
 #endif
--- a/dom/bluetooth/nsIDOMBluetoothAdapter.idl
+++ b/dom/bluetooth/nsIDOMBluetoothAdapter.idl
@@ -1,17 +1,18 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=40: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIDOMEventTarget.idl"
 
+interface nsIDOMDOMRequest;
 interface nsIDOMEventListener;
 
-[scriptable, builtinclass, uuid(3dbaa9f4-5c93-11e1-8592-ff9bfcc3ab4b)]
+[scriptable, builtinclass, uuid(ac288eab-dcdb-4f6a-b94d-6c0e286d6a73)]
 interface nsIDOMBluetoothAdapter : nsIDOMEventTarget
 {
-  attribute boolean power;
+  readonly attribute bool enabled;
 
-  attribute nsIDOMEventListener onpowered;
+  nsIDOMDOMRequest setEnabled(in boolean enabled);
 };
--- a/dom/indexedDB/IDBKeyRange.cpp
+++ b/dom/indexedDB/IDBKeyRange.cpp
@@ -339,16 +339,23 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBKeyRange)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBKeyRange)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBKeyRange)
 
 DOMCI_DATA(IDBKeyRange, IDBKeyRange)
 
+IDBKeyRange::~IDBKeyRange()
+{
+  if (mRooted) {
+    NS_DROP_JS_OBJECTS(this, IDBKeyRange);
+  }
+}
+
 NS_IMETHODIMP
 IDBKeyRange::GetLower(JSContext* aCx,
                       jsval* aLower)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (!mHaveCachedLowerVal) {
     if (!mRooted) {
--- a/dom/indexedDB/IDBKeyRange.h
+++ b/dom/indexedDB/IDBKeyRange.h
@@ -165,17 +165,17 @@ public:
       rv = Upper().BindToStatement(aStatement, NS_LITERAL_CSTRING("upper_key"));
       NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     }
 
     return NS_OK;
   }
 
 protected:
-  ~IDBKeyRange() { }
+  ~IDBKeyRange();
 
   Key mLower;
   Key mUpper;
   jsval mCachedLowerVal;
   jsval mCachedUpperVal;
   bool mLowerOpen;
   bool mUpperOpen;
   bool mIsOnly;
--- a/dom/src/storage/nsDOMStorage.cpp
+++ b/dom/src/storage/nsDOMStorage.cpp
@@ -1313,30 +1313,27 @@ DOMStorageImpl::Clear(bool aCallerSecure
   mItems.Clear();
   return NS_OK;
 }
 
 nsDOMStorage::nsDOMStorage()
   : mStorageType(nsPIDOMStorage::Unknown)
   , mEventBroadcaster(nsnull)
 {
-  mSecurityChecker = this;
-
   if (XRE_GetProcessType() != GeckoProcessType_Default)
     mStorageImpl = new StorageChild(this);
   else
     mStorageImpl = new DOMStorageImpl(this);
 }
 
 nsDOMStorage::nsDOMStorage(nsDOMStorage& aThat)
   : mStorageType(aThat.mStorageType)
+  , mPrincipal(aThat.mPrincipal)
   , mEventBroadcaster(nsnull)
 {
-  mSecurityChecker = this;
-
   if (XRE_GetProcessType() != GeckoProcessType_Default) {
     StorageChild* other = static_cast<StorageChild*>(aThat.mStorageImpl.get());
     mStorageImpl = new StorageChild(this, *other);
   } else {
     DOMStorageImpl* other = static_cast<DOMStorageImpl*>(aThat.mStorageImpl.get());
     mStorageImpl = new DOMStorageImpl(this, *other);
   }
 }
@@ -1377,31 +1374,33 @@ GetDomainURI(nsIPrincipal *aPrincipal, b
 nsresult
 nsDOMStorage::InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI)
 {
   nsCOMPtr<nsIURI> domainURI;
   nsresult rv = GetDomainURI(aPrincipal, true, getter_AddRefs(domainURI));
   NS_ENSURE_SUCCESS(rv, rv);
 
   mDocumentURI = aDocumentURI;
+  mPrincipal = aPrincipal;
 
   mStorageType = SessionStorage;
 
   mStorageImpl->InitAsSessionStorage(domainURI);
   return NS_OK;
 }
 
 nsresult
 nsDOMStorage::InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI)
 {
   nsCOMPtr<nsIURI> domainURI;
   nsresult rv = GetDomainURI(aPrincipal, false, getter_AddRefs(domainURI));
   NS_ENSURE_SUCCESS(rv, rv);
 
   mDocumentURI = aDocumentURI;
+  mPrincipal = aPrincipal;
 
   mStorageType = LocalStorage;
 
   bool canUseChromePersist = false;
   nsCOMPtr<nsIURI> URI;
   if (NS_SUCCEEDED(aPrincipal->GetURI(getter_AddRefs(URI))) && URI) {
     canUseChromePersist = URICanUseChromePersist(URI);
   }
@@ -1490,18 +1489,17 @@ nsDOMStorage::CacheStoragePermissions()
   nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
   if (!ssm)
     return false;
 
   nsCOMPtr<nsIPrincipal> subjectPrincipal;
   nsresult rv = ssm->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
   NS_ENSURE_SUCCESS(rv, false);
 
-  NS_ASSERTION(mSecurityChecker, "Has non-null mSecurityChecker");
-  return mSecurityChecker->CanAccess(subjectPrincipal);
+  return CanAccess(subjectPrincipal);
 }
 
 // static
 bool
 nsDOMStorage::URICanUseChromePersist(nsIURI* aURI) {
   bool isAbout;
   return
     (NS_SUCCEEDED(aURI->SchemeIs("moz-safe-about", &isAbout)) && isAbout) ||
@@ -1724,27 +1722,27 @@ nsDOMStorage::CanAccessSystem(nsIPrincip
   nsresult rv = ssm->IsSystemPrincipal(aPrincipal, &isSystem);
 
   return NS_SUCCEEDED(rv) && isSystem;
 }
 
 bool
 nsDOMStorage::CanAccess(nsIPrincipal *aPrincipal)
 {
-  // Allow C++/system callers to access the storage
-  if (CanAccessSystem(aPrincipal))
+  // Allow C++ callers to access the storage
+  if (!aPrincipal)
     return true;
 
-  nsCAutoString domain;
-  nsCOMPtr<nsIURI> unused;
-  nsresult rv = GetPrincipalURIAndHost(aPrincipal,
-                                       getter_AddRefs(unused), domain);
-  NS_ENSURE_SUCCESS(rv, false);
-
-  return domain.Equals(mStorageImpl->mDomain);
+  // Allow more powerful principals (e.g. system) to access the storage
+  bool subsumes;
+  nsresult rv = aPrincipal->SubsumesIgnoringDomain(mPrincipal, &subsumes);
+  if (NS_FAILED(rv))
+    return false;
+
+  return subsumes;
 }
 
 nsPIDOMStorage::nsDOMStorageType
 nsDOMStorage::StorageType()
 {
   return mStorageType;
 }
 
@@ -1792,42 +1790,39 @@ NS_INTERFACE_MAP_END
 
 nsDOMStorage2::nsDOMStorage2()
 {
 }
 
 nsDOMStorage2::nsDOMStorage2(nsDOMStorage2& aThat)
 {
   mStorage = new nsDOMStorage(*aThat.mStorage.get());
-  mStorage->mSecurityChecker = mStorage;
   mPrincipal = aThat.mPrincipal;
 }
 
 nsresult
 nsDOMStorage2::InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI)
 {
   mStorage = new nsDOMStorage();
   if (!mStorage)
     return NS_ERROR_OUT_OF_MEMORY;
 
-  mStorage->mSecurityChecker = this;
   mPrincipal = aPrincipal;
   mDocumentURI = aDocumentURI;
 
   return mStorage->InitAsSessionStorage(aPrincipal, aDocumentURI);
 }
 
 nsresult
 nsDOMStorage2::InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI)
 {
   mStorage = new nsDOMStorage();
   if (!mStorage)
     return NS_ERROR_OUT_OF_MEMORY;
 
-  mStorage->mSecurityChecker = this;
   mPrincipal = aPrincipal;
   mDocumentURI = aDocumentURI;
 
   return mStorage->InitAsLocalStorage(aPrincipal, aDocumentURI);
 }
 
 already_AddRefed<nsIDOMStorage>
 nsDOMStorage2::Clone()
@@ -1887,30 +1882,17 @@ nsIPrincipal*
 nsDOMStorage2::Principal()
 {
   return mPrincipal;
 }
 
 bool
 nsDOMStorage2::CanAccess(nsIPrincipal *aPrincipal)
 {
-  if (mStorage->mSecurityChecker != this)
-    return mStorage->mSecurityChecker->CanAccess(aPrincipal);
-
-  // Allow C++ callers to access the storage
-  if (!aPrincipal)
-    return true;
-
-  // Allow more powerful principals (e.g. system) to access the storage
-  bool subsumes;
-  nsresult rv = aPrincipal->SubsumesIgnoringDomain(mPrincipal, &subsumes);
-  if (NS_FAILED(rv))
-    return false;
-
-  return subsumes;
+  return mStorage->CanAccess(aPrincipal);
 }
 
 nsPIDOMStorage::nsDOMStorageType
 nsDOMStorage2::StorageType()
 {
   if (mStorage)
     return mStorage->StorageType();
 
--- a/dom/src/storage/nsDOMStorage.h
+++ b/dom/src/storage/nsDOMStorage.h
@@ -414,17 +414,17 @@ public:
 
   // true if this storage was initialized as a localStorage object.  localStorage
   // objects are scoped to scheme/host/port in the database, while globalStorage
   // objects are scoped just to host.  this flag also tells the manager to map
   // this storage also in mLocalStorages hash table.
   nsDOMStorageType mStorageType;
 
   friend class nsIDOMStorage2;
-  nsPIDOMStorage* mSecurityChecker;
+  nsCOMPtr<nsIPrincipal> mPrincipal;
   nsPIDOMStorage* mEventBroadcaster;
 };
 
 class nsDOMStorage2 : public nsIDOMStorage,
                       public nsPIDOMStorage
 {
 public:
   // nsISupports
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -137,18 +137,18 @@ DataCallInfo.protoptype = {
 
 
 function RadioInterfaceLayer() {
   this.worker = new ChromeWorker("resource://gre/modules/ril_worker.js");
   this.worker.onerror = this.onerror.bind(this);
   this.worker.onmessage = this.onmessage.bind(this);
   debug("Starting Worker\n");
   this.radioState = {
-    radioState:     null,
-    cardState:      null,
+    radioState:     RIL.GECKO_RADIOSTATE_UNAVAILABLE,
+    cardState:      RIL.GECKO_CARDSTATE_UNAVAILABLE,
     connected:      null,
     roaming:        null,
     signalStrength: null,
     bars:           null,
     operator:       null,
     type:           null,
     msisdn:         null,
   };
@@ -189,25 +189,25 @@ RadioInterfaceLayer.prototype = {
       case "callDisconnected":
         // This one will handle its own notifications.
         this.handleCallDisconnected(message.call);
         break;
       case "enumerateCalls":
         // This one will handle its own notifications.
         this.handleEnumerateCalls(message.calls);
         break;
-      case "registrationstatechange":
-        this.updateDataConnection(message.registrationState);
+      case "voiceregistrationstatechange":
+        this.updateDataConnection(message.voiceRegistrationState);
         break;
-      case "gprsregistrationstatechange":
-        let state = message.gprsRegistrationState;
+      case "dataregistrationstatechange":
+        let state = message.dataRegistrationState;
         this.updateDataConnection(state);
 
         //TODO for simplicity's sake, for now we only look at
-        // gprsRegistrationState for the radio registration state.
+        // dataRegistrationState for the radio registration state.
 
         if (!state || state.regState == RIL.NETWORK_CREG_STATE_UNKNOWN) {
           this.resetRadioState();
           this.notifyRadioStateChanged();
           return;
         }
 
         this.radioState.connected =
@@ -277,16 +277,19 @@ RadioInterfaceLayer.prototype = {
                + " timezone=" + message.networkTimeZoneInMinutes
                + " dst=" + message.dstFlag
                + " timestamp=" + message.localTimeStampInMS);
         }
         break;
       case "siminfo":
         this.radioState.msisdn = message.msisdn;
         break;
+      case "error":
+        debug("Received error message: " + JSON.stringify(message));
+        break;
       default:
         throw new Error("Don't know about this message type: " + message.type);
     }
   },
 
   _isDataEnabled: function _isDataEnabled() {
     try {
       return Services.prefs.getBoolPref("ril.data.enabled");
@@ -1078,17 +1081,18 @@ let RILNetworkInterface = {
       event.preventDefault();
     };
   },
 
   // nsIRILDataCallback
 
   dataCallStateChanged: function dataCallStateChanged(cid, interfaceName, callState) {
     if (this.connecting &&
-        callState == RIL.GECKO_NETWORK_STATE_CONNECTING) {
+        (callState == RIL.GECKO_NETWORK_STATE_CONNECTING ||
+         callState == RIL.GECKO_NETWORK_STATE_CONNECTED)) {
       this.connecting = false;
       this.cid = cid;
       this.name = interfaceName;
       debug("Data call ID: " + cid + ", interface name: " + interfaceName);
     }
     if (this.cid != cid) {
       return;
     }
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -52,18 +52,18 @@ const REQUEST_HANGUP = 12;
 const REQUEST_HANGUP_WAITING_OR_BACKGROUND = 13;
 const REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND = 14;
 const REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE = 15;
 const REQUEST_SWITCH_HOLDING_AND_ACTIVE = 15;
 const REQUEST_CONFERENCE = 16;
 const REQUEST_UDUB = 17;
 const REQUEST_LAST_CALL_FAIL_CAUSE = 18;
 const REQUEST_SIGNAL_STRENGTH = 19;
-const REQUEST_REGISTRATION_STATE = 20;
-const REQUEST_GPRS_REGISTRATION_STATE = 21;
+const REQUEST_VOICE_REGISTRATION_STATE = 20;
+const REQUEST_DATA_REGISTRATION_STATE = 21;
 const REQUEST_OPERATOR = 22;
 const REQUEST_RADIO_POWER = 23;
 const REQUEST_DTMF = 24;
 const REQUEST_SEND_SMS = 25;
 const REQUEST_SEND_SMS_EXPECT_MORE = 26;
 const REQUEST_SETUP_DATA_CALL = 27;
 const REQUEST_SIM_IO = 28;
 const REQUEST_SEND_USSD = 29;
@@ -109,17 +109,17 @@ const REQUEST_STK_SET_PROFILE = 68;
 const REQUEST_STK_SEND_ENVELOPE_COMMAND = 69;
 const REQUEST_STK_SEND_TERMINAL_RESPONSE = 70;
 const REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM = 71;
 const REQUEST_EXPLICIT_CALL_TRANSFER = 72;
 const REQUEST_SET_PREFERRED_NETWORK_TYPE = 73;
 const REQUEST_GET_PREFERRED_NETWORK_TYPE = 74;
 const REQUEST_GET_NEIGHBORING_CELL_IDS = 75;
 const REQUEST_SET_LOCATION_UPDATES = 76;
-const REQUEST_CDMA_SET_SUBSCRIPTION = 77;
+const REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE = 77;
 const REQUEST_CDMA_SET_ROAMING_PREFERENCE = 78;
 const REQUEST_CDMA_QUERY_ROAMING_PREFERENCE = 79;
 const REQUEST_SET_TTY_MODE = 80;
 const REQUEST_QUERY_TTY_MODE = 81;
 const REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE = 82;
 const REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE = 83;
 const REQUEST_CDMA_FLASH = 84;
 const REQUEST_CDMA_BURST_DTMF = 85;
@@ -136,24 +136,46 @@ const REQUEST_CDMA_SUBSCRIPTION = 95;
 const REQUEST_CDMA_WRITE_SMS_TO_RUIM = 96;
 const REQUEST_CDMA_DELETE_SMS_ON_RUIM = 97;
 const REQUEST_DEVICE_IDENTITY = 98;
 const REQUEST_EXIT_EMERGENCY_CALLBACK_MODE = 99;
 const REQUEST_GET_SMSC_ADDRESS = 100;
 const REQUEST_SET_SMSC_ADDRESS = 101;
 const REQUEST_REPORT_SMS_MEMORY_STATUS = 102;
 const REQUEST_REPORT_STK_SERVICE_IS_RUNNING = 103;
+const REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE = 104;
+const REQUEST_ISIM_AUTHENTICATION = 105;
+const REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU = 106;
+const REQUEST_STK_SEND_ENVELOPE_WITH_STATUS = 107;
+
+// Akami/Maguro specific parcel types.
+const REQUEST_VOICE_RADIO_TECH = 105;
+const REQUEST_IMS_REGISTRATION_STATE = 106;
+const REQUEST_IMS_SEND_SMS = 107;
+const REQUEST_GET_DATA_CALL_PROFILE = 108;
+const REQUEST_SET_UICC_SUBSCRIPTION = 109;
+const REQUEST_SET_DATA_SUBSCRIPTION = 110;
+const REQUEST_GET_UICC_SUBSCRIPTION = 111;
+const REQUEST_GET_DATA_SUBSCRIPTION = 112;
+const REQUEST_SET_SUBSCRIPTION_MODE = 113;
+const REQUEST_SET_TRANSMIT_POWER = 114;
+const REQUEST_SETUP_QOS = 115;
+const REQUEST_RELEASE_QOS = 116;
+const REQUEST_GET_QOS_STATUS = 117;
+const REQUEST_MODIFY_QOS = 118;
+const REQUEST_SUSPEND_QOS = 119;
+const REQUEST_RESUME_QOS = 120;
 
 const RESPONSE_TYPE_SOLICITED = 0;
 const RESPONSE_TYPE_UNSOLICITED = 1;
 
 const UNSOLICITED_RESPONSE_BASE = 1000;
 const UNSOLICITED_RESPONSE_RADIO_STATE_CHANGED = 1000;
 const UNSOLICITED_RESPONSE_CALL_STATE_CHANGED = 1001;
-const UNSOLICITED_RESPONSE_NETWORK_STATE_CHANGED = 1002;
+const UNSOLICITED_RESPONSE_VOICE_NETWORK_STATE_CHANGED = 1002;
 const UNSOLICITED_RESPONSE_NEW_SMS = 1003;
 const UNSOLICITED_RESPONSE_NEW_SMS_STATUS_REPORT = 1004;
 const UNSOLICITED_RESPONSE_NEW_SMS_ON_SIM = 1005;
 const UNSOLICITED_ON_USSD = 1006;
 const UNSOLICITED_ON_USSD_REQUEST = 1007;
 const UNSOLICITED_NITZ_TIME_RECEIVED = 1008;
 const UNSOLICITED_SIGNAL_STRENGTH = 1009;
 const UNSOLICITED_DATA_CALL_LIST_CHANGED = 1010;
@@ -172,16 +194,30 @@ const UNSOLICITED_CDMA_RUIM_SMS_STORAGE_
 const UNSOLICITED_RESTRICTED_STATE_CHANGED = 1023;
 const UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE = 1024;
 const UNSOLICITED_CDMA_CALL_WAITING = 1025;
 const UNSOLICITED_CDMA_OTA_PROVISION_STATUS = 1026;
 const UNSOLICITED_CDMA_INFO_REC = 1027;
 const UNSOLICITED_OEM_HOOK_RAW = 1028;
 const UNSOLICITED_RINGBACK_TONE = 1029;
 const UNSOLICITED_RESEND_INCALL_MUTE = 1030;
+const UNSOLICITED_CDMA_SUBSCRIPTION_SOURCE_CHANGED = 1031;
+const UNSOLICITED_CDMA_PRL_CHANGED = 1032;
+const UNSOLICITED_EXIT_EMERGENCY_CALLBACK_MODE = 1033;
+const UNSOLICITED_RIL_CONNECTED = 1034;
+
+// Akami/Maguro specific parcels.
+const UNSOLICITED_VOICE_RADIO_TECH_CHANGED = 1034;
+const UNSOLICITED_RESPONSE_IMS_NETWORK_STATE_CHANGED = 1035;
+const UNSOLICITED_RESPONSE_TETHERED_MODE_STATE_CHANGED = 1036;
+const UNSOLICITED_RESPONSE_DATA_NETWORK_STATE_CHANGED = 1037;
+const UNSOLICITED_ON_SS = 1038;
+const UNSOLICITED_STK_CC_ALPHA_NOTIFY = 1039;
+const UNSOLICITED_UICC_SUBSCRIPTION_STATUS_CHANGED = 1040;
+const UNSOLICITED_QOS_STATE_CHANGED_IND = 1041;
 
 const ERROR_SUCCESS = 0;
 const ERROR_RADIO_NOT_AVAILABLE = 1;
 const ERROR_GENERIC_FAILURE = 2;
 const ERROR_PASSWORD_INCORRECT = 3;
 const ERROR_SIM_PIN2 = 4;
 const ERROR_SIM_PUK2 = 5;
 const ERROR_REQUEST_NOT_SUPPORTED = 6;
@@ -189,43 +225,113 @@ const ERROR_CANCELLED = 7;
 const ERROR_OP_NOT_ALLOWED_DURING_VOICE_CALL = 8;
 const ERROR_OP_NOT_ALLOWED_BEFORE_REG_TO_NW = 9;
 const ERROR_SMS_SEND_FAIL_RETRY = 10;
 const ERROR_SIM_ABSENT = 11;
 const ERROR_SUBSCRIPTION_NOT_AVAILABLE = 12;
 const ERROR_MODE_NOT_SUPPORTED = 13;
 const ERROR_FDN_CHECK_FAILURE = 14;
 const ERROR_ILLEGAL_SIM_OR_ME = 15;
+const ERROR_DIAL_MODIFIED_TO_USSD = 17;
+const ERROR_DIAL_MODIFIED_TO_SS = 18;
+const ERROR_DIAL_MODIFIED_TO_DIAL = 19;
+const ERROR_USSD_MODIFIED_TO_DIAL = 20;
+const ERROR_USSD_MODIFIED_TO_SS = 21;
+const ERROR_USSD_MODIFIED_TO_USSD = 22;
+const ERROR_SS_MODIFIED_TO_DIAL = 23;
+const ERROR_SS_MODIFIED_TO_USSD = 24;
+const ERROR_SS_MODIFIED_TO_SS = 25;
+const ERROR_SUBSCRIPTION_NOT_SUPPORTED = 26;
 
 const RADIO_STATE_OFF = 0;
 const RADIO_STATE_UNAVAILABLE = 1;
+const RADIO_STATE_ON = 2;
+
+// RIL v5 legacy constants:
 const RADIO_STATE_SIM_NOT_READY = 2;
 const RADIO_STATE_SIM_LOCKED_OR_ABSENT = 3;
 const RADIO_STATE_SIM_READY = 4;
 const RADIO_STATE_RUIM_NOT_READY = 5;
 const RADIO_STATE_RUIM_READY = 6;
 const RADIO_STATE_RUIM_LOCKED_OR_ABSENT = 7;
 const RADIO_STATE_NV_NOT_READY = 8;
 const RADIO_STATE_NV_READY = 9;
 
 const CARD_STATE_ABSENT = 0;
 const CARD_STATE_PRESENT = 1;
 const CARD_STATE_ERROR = 2;
 
-const CARD_APP_STATE_UNKNOWN = 0;
-const CARD_APP_STATE_DETECTED = 1;
-const CARD_APP_STATE_PIN = 2; // If PIN1 or UPin is required.
-const CARD_APP_STATE_PUK = 3; // If PUK1 or Puk for UPin is required.
-const CARD_APP_STATE_SUBSCRIPTION_PERSO = 4; // perso_substate should be looked
-                                             // at when app_state is assigned
-                                             // to this value.
-const CARD_APP_STATE_READY = 5;
+const CARD_PERSOSUBSTATE_UNKNOWN = 0;
+const CARD_PERSOSUBSTATE_IN_PROGRESS = 1;
+const CARD_PERSOSUBSTATE_READY = 2;
+const CARD_PERSOSUBSTATE_SIM_NETWORK = 3;
+const CARD_PERSOSUBSTATE_SIM_NETWORK_SUBSET = 4;
+const CARD_PERSOSUBSTATE_SIM_CORPORATE = 5;
+const CARD_PERSOSUBSTATE_SIM_SERVICE_PROVIDER = 6;
+const CARD_PERSOSUBSTATE_SIM_SIM = 7;
+const CARD_PERSOSUBSTATE_SIM_NETWORK_PUK = 8;
+const CARD_PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK = 9;
+const CARD_PERSOSUBSTATE_SIM_CORPORATE_PUK = 10;
+const CARD_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK = 11;
+const CARD_PERSOSUBSTATE_SIM_SIM_PUK = 12;
+const CARD_PERSOSUBSTATE_RUIM_NETWORK1 = 13;
+const CARD_PERSOSUBSTATE_RUIM_NETWORK2 = 14;
+const CARD_PERSOSUBSTATE_RUIM_HRPD = 15;
+const CARD_PERSOSUBSTATE_RUIM_CORPORATE = 16;
+const CARD_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER = 17;
+const CARD_PERSOSUBSTATE_RUIM_RUIM = 18;
+const CARD_PERSOSUBSTATE_RUIM_NETWORK1_PUK = 19;
+const CARD_PERSOSUBSTATE_RUIM_NETWORK2_PUK = 20;
+const CARD_PERSOSUBSTATE_RUIM_HRPD_PUK = 21;
+const CARD_PERSOSUBSTATE_RUIM_CORPORATE_PUK = 22;
+const CARD_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK = 23;
+const CARD_PERSOSUBSTATE_RUIM_RUIM_PUK = 24;
+
+const CARD_APPSTATE_ILLEGAL = -1;
+const CARD_APPSTATE_UNKNOWN = 0;
+const CARD_APPSTATE_DETECTED = 1;
+const CARD_APPSTATE_PIN = 2; // If PIN1 or UPin is required.
+const CARD_APPSTATE_PUK = 3; // If PUK1 or Puk for UPin is required.
+const CARD_APPSTATE_SUBSCRIPTION_PERSO = 4; // perso_substate should be looked
+                                            // at when app_state is assigned
+                                            // to this value.
+const CARD_APPSTATE_READY = 5;
+
+const CARD_PINSTATE_UNKNOWN = 0;
+const CARD_PINSTATE_ENABLED_NOT_VERIFIED = 1;
+const CARD_PINSTATE_ENABLED_VERIFIED = 2;
+const CARD_PINSTATE_DISABLED = 3;
+const CARD_PINSTATE_ENABLED_BLOCKED = 4;
+const CARD_PINSTATE_ENABLED_PERM_BLOCKED = 5;
+
+const CARD_APPTYPE_UNKNOWN = 0;
+const CARD_APPTYPE_SIM = 1;
+const CARD_APPTYPE_USIM = 2;
+const CARD_APPTYPE_RUIM = 3;
+const CARD_APPTYPE_CSIM = 4;
+const CARD_APPTYPE_ISIM = 5;
 
 const CARD_MAX_APPS = 8;
 
+const NETWORK_SELECTION_MODE_AUTOMATIC = 0;
+const NETWORK_SELECTION_MODE_MANUAL = 1;
+
+const PREFERRED_NETWORK_TYPE_GSM_WCDMA = 0;
+const PREFERRED_NETWORK_TYPE_GSM_ONLY = 1;
+const PREFERRED_NETWORK_TYPE_WCDMA = 2;
+const PREFERRED_NETWORK_TYPE_GSM_WCDMA_AUTO = 3;
+const PREFERRED_NETWORK_TYPE_CDMA_EVDO_AUTO = 4;
+const PREFERRED_NETWORK_TYPE_CDMA_ONLY = 5;
+const PREFERRED_NETWORK_TYPE_EVDO_ONLY = 6;
+const PREFERRED_NETWORK_TYPE_GSM_WCDMA_CDMA_EVDO_AUTO = 7;
+const PREFERRED_NETWORK_TYPE_LTE_CDMA_EVDO = 8;
+const PREFERRED_NETWORK_TYPE_LTE_GSM_WCDMA = 9;
+const PREFERRED_NETWORK_TYPE_LTE_CMDA_EVDO_GSM_WCDMA = 10;
+const PREFERRED_NETWORK_TYPE_LTE_ONLY = 11;
+
 // Network registration states. See TS 27.007 7.2
 const NETWORK_CREG_STATE_NOT_SEARCHING = 0;
 const NETWORK_CREG_STATE_REGISTERED_HOME = 1;
 const NETWORK_CREG_STATE_SEARCHING = 2;
 const NETWORK_CREG_STATE_DENIED = 3;
 const NETWORK_CREG_STATE_UNKNOWN = 4;
 const NETWORK_CREG_STATE_REGISTERED_ROAMING = 5;
 
@@ -237,16 +343,19 @@ const NETWORK_CREG_TECH_IS95A = 4;
 const NETWORK_CREG_TECH_IS95B = 5;
 const NETWORK_CREG_TECH_1XRTT = 6;
 const NETWORK_CREG_TECH_EVDO0 = 7;
 const NETWORK_CREG_TECH_EVDOA = 8;
 const NETWORK_CREG_TECH_HSDPA = 9;
 const NETWORK_CREG_TECH_HSUPA = 10;
 const NETWORK_CREG_TECH_HSPA = 11;
 const NETWORK_CREG_TECH_EVDOB = 12;
+const NETWORK_CREG_TECH_EHRPD = 13;
+const NETWORK_CREG_TECH_LTE = 14;
+const NETWORK_CREG_TECH_HSPAP = 15;
 
 const CALL_STATE_ACTIVE = 0;
 const CALL_STATE_HOLDING = 1;
 const CALL_STATE_DIALING = 2;
 const CALL_STATE_ALERTING = 3;
 const CALL_STATE_INCOMING = 4;
 const CALL_STATE_WAITING = 5;
 
@@ -1089,16 +1198,19 @@ const PDU_NL_SINGLE_SHIFT_TABLES = [
   // 0123456789ABCDEF
   + "PQRSTUVWXYZ     "
   // 012345.....6789ABCDEF
   + "     \u20ac          "
   // 0123456789ABCDEF
   + "                "
 ];
 
+const RADIOTECH_FAMILY_3GPP = 1;  // GSM, WCDMA, LTE
+const RADIOTECH_FAMILY_3GPP2 = 2; // CDMA, EVDO
+
 const DATACALL_RADIOTECHNOLOGY_CDMA = 0;
 const DATACALL_RADIOTECHNOLOGY_GSM = 1;
 
 const DATACALL_AUTH_NONE = 0;
 const DATACALL_AUTH_PAP = 1;
 const DATACALL_AUTH_CHAP = 2;
 const DATACALL_AUTH_PAP_OR_CHAP = 3;
 
@@ -1109,26 +1221,50 @@ const DATACALL_PROFILE_OEM_BASE = 1000;
 const DATACALL_DEACTIVATE_NO_REASON = 0;
 const DATACALL_DEACTIVATE_RADIO_SHUTDOWN = 1;
 
 const DATACALL_ACTIVE_UNKNOWN = -1;
 const DATACALL_INACTIVE = 0;
 const DATACALL_ACTIVE_DOWN = 1;
 const DATACALL_ACTIVE_UP = 2;
 
+const DATACALL_FAIL_NONE = 0;
+const DATACALL_FAIL_OPERATOR_BARRED = 0x08;
+const DATACALL_FAIL_INSUFFICIENT_RESOURCES = 0x1A;
+const DATACALL_FAIL_MISSING_UKNOWN_APN = 0x1B;
+const DATACALL_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C;
+const DATACALL_FAIL_USER_AUTHENTICATION = 0x1D;
+const DATACALL_FAIL_ACTIVATION_REJECT_GGSN = 0x1E;
+const DATACALL_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F;
+const DATACALL_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20;
+const DATACALL_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21;
+const DATACALL_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22;
+const DATACALL_FAIL_NSAPI_IN_USE = 0x23;
+const DATACALL_FAIL_ONLY_IPV4_ALLOWED = 0x32;
+const DATACALL_FAIL_ONLY_IPV6_ALLOWED = 0x33;
+const DATACALL_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34;
+const DATACALL_FAIL_PROTOCOL_ERRORS = 0x6F;
+const DATACALL_FAIL_VOICE_REGISTRATION_FAIL = -1;
+const DATACALL_FAIL_DATA_REGISTRATION_FAIL = -2;
+const DATACALL_FAIL_SIGNAL_LOST = -3;
+const DATACALL_FAIL_PREF_RADIO_TECH_CHANGED = -4;
+const DATACALL_FAIL_RADIO_POWER_OFF = -5;
+const DATACALL_FAIL_TETHERED_CALL_ACTIVE = -6;
+const DATACALL_FAIL_ERROR_UNSPECIFIED = 0xffff;
+
 // Keep consistent with nsINetworkManager.NETWORK_STATE_*.
 const GECKO_NETWORK_STATE_UNKNOWN = -1;
 const GECKO_NETWORK_STATE_CONNECTING = 0;
 const GECKO_NETWORK_STATE_CONNECTED = 1;
 const GECKO_NETWORK_STATE_SUSPENDED = 2;
 const GECKO_NETWORK_STATE_DISCONNECTING = 3;
 const GECKO_NETWORK_STATE_DISCONNECTED = 4;
 
 // Other Gecko-specific constants
-const GECKO_RADIOSTATE_UNAVAILABLE   = "unavailable";
+const GECKO_RADIOSTATE_UNAVAILABLE   = null;
 const GECKO_RADIOSTATE_OFF           = "off";
 const GECKO_RADIOSTATE_READY         = "ready";
 
 const GECKO_CARDSTATE_UNAVAILABLE    = null;
 const GECKO_CARDSTATE_ABSENT         = "absent";
 const GECKO_CARDSTATE_PIN_REQUIRED   = "pin_required";
 const GECKO_CARDSTATE_PUK_REQUIRED   = "puk_required";
 const GECKO_CARDSTATE_NETWORK_LOCKED = "network_locked";
@@ -1144,12 +1280,15 @@ const GECKO_RADIO_TECH = [
   "is95b",
   "1xrtt",
   "evdo0",
   "evdoa",
   "hsdpa",
   "hsupa",
   "hspa",
   "evdob",
+  "ehrpd",
+  "lte",
+  "hspa+",
 ];
 
 // Allow this file to be imported via Components.utils.import().
 const EXPORTED_SYMBOLS = Object.keys(this);
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -72,16 +72,19 @@ let DEBUG;
 const INT32_MAX   = 2147483647;
 const UINT8_SIZE  = 1;
 const UINT16_SIZE = 2;
 const UINT32_SIZE = 4;
 const PARCEL_SIZE_SIZE = UINT32_SIZE;
 
 let RILQUIRKS_CALLSTATE_EXTRA_UINT32 = false;
 let RILQUIRKS_DATACALLSTATE_DOWN_IS_UP = false;
+// This flag defaults to true since on RIL v6 and later, we get the
+// version number via the UNSOLICITED_RIL_CONNECTED parcel.
+let RILQUIRKS_V5_LEGACY = true;
 
 /**
  * This object contains helpers buffering incoming data & deconstructing it
  * into parcels as well as buffering outgoing data & constructing parcels.
  * For that it maintains two buffers and corresponding uint8 views, indexes.
  *
  * The incoming buffer is a circular buffer where we store incoming data.
  * As soon as a complete parcel is received, it is processed right away, so
@@ -549,17 +552,17 @@ let Buf = {
  * via post messages. It maintains state about the radio, ICC, calls, etc.
  * and acts upon state changes accordingly.
  */
 let RIL = {
 
   /**
    * One of the RADIO_STATE_* constants.
    */
-  radioState: RADIO_STATE_UNAVAILABLE,
+  radioState: GECKO_RADIOSTATE_UNAVAILABLE,
 
   /**
    * ICC status. Keeps a reference of the data response to the
    * getICCStatus request.
    */
   iccStatus: null,
 
   /**
@@ -571,18 +574,18 @@ let RIL = {
    * Strings
    */
   IMEI: null,
   IMEISV: null,
   IMSI: null,
   SMSC: null,
   MSISDN: null,
 
-  registrationState: {},
-  gprsRegistrationState: {},
+  voiceRegistrationState: {},
+  dataRegistrationState: {},
 
   /**
    * List of strings identifying the network operator.
    */
   operator: null,
 
   /**
    * String containing the baseband version.
@@ -646,16 +649,23 @@ let RIL = {
       if (DEBUG) {
         debug("Detected I9100, enabling " +
               "RILQUIRKS_CALLSTATE_EXTRA_UINT32, " +
               "RILQUIRKS_DATACALLSTATE_DOWN_IS_UP.");
       }
       RILQUIRKS_CALLSTATE_EXTRA_UINT32 = true;
       RILQUIRKS_DATACALLSTATE_DOWN_IS_UP = true;
     }
+    if (model_id == "I9023" || model_id == "I9020") {
+      if (DEBUG) {
+        debug("Detected I9020/I9023, enabling " +
+              "RILQUIRKS_DATACALLSTATE_DOWN_IS_UP");
+      }
+      RILQUIRKS_DATACALLSTATE_DOWN_IS_UP = true;
+    }
 
     this.rilQuirksInitialized = true;
   },
 
   /**
    * Parse an integer from a string, falling back to a default value
    * if the the provided value is not a string or does not contain a valid
    * number.
@@ -815,39 +825,55 @@ let RIL = {
    */
   setScreenState: function setScreenState(on) {
     Buf.newParcel(REQUEST_SCREEN_STATE);
     Buf.writeUint32(1);
     Buf.writeUint32(on ? 1 : 0);
     Buf.sendParcel();
   },
 
-  getRegistrationState: function getRegistrationState() {
-    Buf.simpleRequest(REQUEST_REGISTRATION_STATE);
+  getVoiceRegistrationState: function getVoiceRegistrationState() {
+    Buf.simpleRequest(REQUEST_VOICE_REGISTRATION_STATE);
   },
 
-  getGPRSRegistrationState: function getGPRSRegistrationState() {
-    Buf.simpleRequest(REQUEST_GPRS_REGISTRATION_STATE);
+  getDataRegistrationState: function getDataRegistrationState() {
+    Buf.simpleRequest(REQUEST_DATA_REGISTRATION_STATE);
   },
 
   getOperator: function getOperator() {
     Buf.simpleRequest(REQUEST_OPERATOR);
   },
 
   getNetworkSelectionMode: function getNetworkSelectionMode() {
     Buf.simpleRequest(REQUEST_QUERY_NETWORK_SELECTION_MODE);
   },
 
+  setNetworkSelectionAutomatic: function setNetworkSelectionAutomatic() {
+    Buf.simpleRequest(REQUEST_SET_NETWORK_SELECTION_AUTOMATIC);
+  },
+
+  /**
+   * Set the preferred network type.
+   *
+   * @param network_type
+   *        The network type. One of the PREFERRED_NETWORK_TYPE_* constants.
+   */
+  setPreferredNetworkType: function setPreferredNetworkType(network_type) {
+    Buf.newParcel(REQUEST_SET_PREFERRED_NETWORK_TYPE);
+    Buf.writeUint32(network_type);
+    Buf.sendParcel();
+  },
+
   /**
    * Request various states about the network.
    */
   requestNetworkInfo: function requestNetworkInfo() {
     if (DEBUG) debug("Requesting phone state");
-    this.getRegistrationState();
-    this.getGPRSRegistrationState(); //TODO only GSM
+    this.getVoiceRegistrationState();
+    this.getDataRegistrationState(); //TODO only GSM
     this.getOperator();
     this.getNetworkSelectionMode();
   },
 
   /**
    * Get current calls.
    */
   getCurrentCalls: function getCurrentCalls() {
@@ -1163,78 +1189,60 @@ let RIL = {
         return;
       }
       this.cardState = GECKO_CARDSTATE_ABSENT;
       this.sendDOMMessage({type: "cardstatechange",
                            cardState: this.cardState});
       return;
     }
 
-    if ((this.radioState == RADIO_STATE_OFF) ||
-        (this.radioState == RADIO_STATE_UNAVAILABLE) ||
-        (this.radioState == RADIO_STATE_SIM_NOT_READY) ||
-        (this.radioState == RADIO_STATE_RUIM_NOT_READY) ||
-        (this.radioState == RADIO_STATE_NV_NOT_READY) ||
-        (this.radioState == RADIO_STATE_NV_READY)) {
-      if (DEBUG) debug("ICC not ready");
-      if (this.cardState == GECKO_CARDSTATE_NOT_READY) {
+    let app = iccStatus.apps[iccStatus.gsmUmtsSubscriptionAppIndex];
+    if (!app) {
+      if (DEBUG) {
+        debug("Subscription application is not present in iccStatus.");
+      }
+      if (this.cardState == GECKO_CARDSTATE_ABSENT) {
         return;
       }
-      this.cardState = GECKO_CARDSTATE_NOT_READY;
+      this.cardState = GECKO_CARDSTATE_ABSENT;
+      this.operator = null;
       this.sendDOMMessage({type: "cardstatechange",
                            cardState: this.cardState});
       return;
     }
 
-    if ((this.radioState == RADIO_STATE_SIM_LOCKED_OR_ABSENT) ||
-        (this.radioState == RADIO_STATE_SIM_READY) ||
-        (this.radioState == RADIO_STATE_RUIM_LOCKED_OR_ABSENT) ||
-        (this.radioState == RADIO_STATE_RUIM_READY)) {
-      let app = iccStatus.apps[iccStatus.gsmUmtsSubscriptionAppIndex];
-      if (!app) {
-        if (DEBUG) {
-          debug("Subscription application is not present in iccStatus.");
-        }
-        if (this.cardState == GECKO_CARDSTATE_ABSENT) {
-          return;
-        }
-        this.cardState = GECKO_CARDSTATE_ABSENT;
-        this.operator = null;
-        this.sendDOMMessage({type: "cardstatechange",
-                             cardState: this.cardState});
-        return;
-      }
+    let newCardState;
+    switch (app.app_state) {
+      case CARD_APPSTATE_PIN:
+        newCardState = GECKO_CARDSTATE_PIN_REQUIRED;
+        break;
+      case CARD_APPSTATE_PUK:
+        newCardState = GECKO_CARDSTATE_PUK_REQUIRED;
+        break;
+      case CARD_APPSTATE_SUBSCRIPTION_PERSO:
+        newCardState = GECKO_CARDSTATE_NETWORK_LOCKED;
+        break;
+      case CARD_APPSTATE_READY:
+        this.requestNetworkInfo();
+        this.getSignalStrength();
+        this.getMSISDN();
+        newCardState = GECKO_CARDSTATE_READY;
+        break;
+      case CARD_APPSTATE_UNKNOWN:
+      case CARD_APPSTATE_DETECTED:
+      default:
+        newCardState = GECKO_CARDSTATE_NOT_READY;
+    }
 
-      let newCardState;
-      switch (app.app_state) {
-        case CARD_APP_STATE_PIN:
-          newCardState = GECKO_CARDSTATE_PIN_REQUIRED;
-          break;
-        case CARD_APP_STATE_PUK:
-          newCardState = GECKO_CARDSTATE_PUK_REQUIRED;
-          break;
-        case CARD_APP_STATE_SUBSCRIPTION_PERSO:
-          newCardState = GECKO_CARDSTATE_NETWORK_LOCKED;
-          break;
-        case CARD_APP_STATE_READY:
-          newCardState = GECKO_CARDSTATE_READY;
-          break;
-        case CARD_APP_STATE_UNKNOWN:
-        case CARD_APP_STATE_DETECTED:
-        default:
-          newCardState = GECKO_CARDSTATE_NOT_READY;
-      }
-
-      if (this.cardState == newCardState) {
-        return;
-      }
-      this.cardState = newCardState;
-      this.sendDOMMessage({type: "cardstatechange",
-                           cardState: this.cardState});
+    if (this.cardState == newCardState) {
+      return;
     }
+    this.cardState = newCardState;
+    this.sendDOMMessage({type: "cardstatechange",
+                         cardState: this.cardState});
   },
 
   /**
    * Process the MSISDN ICC I/O response.
    */
   _processMSISDNResponse: function _processMSISDNResponse(options) {
     let sw1 = Buf.readUint32();
     let sw2 = Buf.readUint32();
@@ -1269,24 +1277,28 @@ let RIL = {
         let number = GsmPDUHelper.readStringAsBCD().toString().substr(4); 
         if (DEBUG) debug("MSISDN: " + number);
         this.MSISDN = number || null;
         this.sendDOMMessage({type: "siminfo", msisdn: this.MSISDN});
         break;
     } 
   },
 
-  _processRegistrationState: function _processRegistrationState(state) {
-    let rs = this.registrationState;
+  _processVoiceRegistrationState: function _processVoiceRegistrationState(state) {
+    let rs = this.voiceRegistrationState;
     let stateChanged = false;
 
     let regState = RIL.parseInt(state[0], NETWORK_CREG_STATE_UNKNOWN);
     if (rs.regState != regState) {
       rs.regState = regState;
       stateChanged = true;
+      if (regState == NETWORK_CREG_STATE_REGISTERED_HOME ||
+          regState == NETWORK_CREG_STATE_REGISTERED_ROAMING) {
+        RIL.getSMSCAddress();
+      }
     }
 
     let radioTech = RIL.parseInt(state[3], NETWORK_CREG_TECH_UNKNOWN);
     if (rs.radioTech != radioTech) {
       rs.radioTech = radioTech;
       stateChanged = true;
     }
 
@@ -1305,40 +1317,40 @@ let RIL = {
       let networkId = RIL.parseInt(state[9]);
       let roamingIndicator = RIL.parseInt(state[10]);
       let systemIsInPRL = RIL.parseInt(state[11]);
       let defaultRoamingIndicator = RIL.parseInt(state[12]);
       let reasonForDenial = RIL.parseInt(state[13]);
     }
 
     if (stateChanged) {
-      this.sendDOMMessage({type: "registrationstatechange",
-                           registrationState: rs});
+      this.sendDOMMessage({type: "voiceregistrationstatechange",
+                           voiceRegistrationState: rs});
     }
   },
 
-  _processGPRSRegistrationState: function _processGPRSRegistrationState(state) {
-    let rs = this.gprsRegistrationState;
+  _processDataRegistrationState: function _processDataRegistrationState(state) {
+    let rs = this.dataRegistrationState;
     let stateChanged = false;
 
     let regState = RIL.parseInt(state[0], NETWORK_CREG_STATE_UNKNOWN);
     if (rs.regState != regState) {
       rs.regState = regState;
       stateChanged = true;
     }
 
     let radioTech = RIL.parseInt(state[3], NETWORK_CREG_TECH_UNKNOWN);
     if (rs.radioTech != radioTech) {
       rs.radioTech = radioTech;
       stateChanged = true;
     }
 
     if (stateChanged) {
-      this.sendDOMMessage({type: "gprsregistrationstatechange",
-                           gprsRegistrationState: rs});
+      this.sendDOMMessage({type: "dataregistrationstatechange",
+                           dataRegistrationState: rs});
     }
   },
 
   /**
    * Helpers for processing call state.
    */
   _processCalls: function _processCalls(newCalls) {
     // Go through the calls we currently have on file and see if any of them
@@ -1381,16 +1393,82 @@ let RIL = {
       }
     }
 
     // Update our mute status. If there is anything in our currentCalls map then
     // we know it's a voice call and we should leave audio on.
     this.muted = Object.getOwnPropertyNames(this.currentCalls).length == 0;
   },
 
+  _handleChangedCallState: function _handleChangedCallState(changedCall) {
+    let message = {type: "callStateChange",
+                   call: {callIndex: changedCall.callIndex,
+                          state: changedCall.state,
+                          number: changedCall.number,
+                          name: changedCall.name}};
+    this.sendDOMMessage(message);
+  },
+
+  _handleDisconnectedCall: function _handleDisconnectedCall(disconnectedCall) {
+    let message = {type: "callDisconnected",
+                   call: {callIndex: disconnectedCall.callIndex}};
+    this.sendDOMMessage(message);
+  },
+
+  _processDataCallList: function _processDataCallList(datacalls) {
+    for each (let currentDataCall in this.currentDataCalls) {
+      let updatedDataCall;
+      if (datacalls) {
+        updatedDataCall = datacalls[currentDataCall.cid];
+        delete datacalls[currentDataCall.cid];
+      }
+
+      if (!updatedDataCall) {
+        delete this.currentDataCalls[currentDataCall.callIndex];
+        currentDataCall.state = GECKO_NETWORK_STATE_DISCONNECTED;
+        this.sendDOMMessage({type: "datacallstatechange",
+                             datacall: currentDataCall});
+        continue;
+      }
+
+      this._setDataCallGeckoState(updatedDataCall);
+      if (updatedDataCall.state != currentDataCall.state) {
+        currentDataCall.status = updatedDataCall.status;
+        currentDataCall.active = updatedDataCall.active;
+        currentDataCall.state = updatedDataCall.state;
+        this.sendDOMMessage({type: "datacallstatechange",
+                             datacall: currentDataCall});
+      }
+    }
+
+    for each (let newDataCall in datacalls) {
+      this.currentDataCalls[newDataCall.cid] = newDataCall;
+      this._setDataCallGeckoState(newDataCall);
+      this.sendDOMMessage({type: "datacallstatechange",
+                           datacall: newDataCall});
+    }
+  },
+
+  _setDataCallGeckoState: function _setDataCallGeckoState(datacall) {
+    switch (datacall.active) {
+      case DATACALL_INACTIVE:
+        datacall.state = GECKO_NETWORK_STATE_DISCONNECTED;
+        break;
+      case DATACALL_ACTIVE_DOWN:
+        datacall.state = GECKO_NETWORK_STATE_SUSPENDED;
+        if (RILQUIRKS_DATACALLSTATE_DOWN_IS_UP) {
+          datacall.state = GECKO_NETWORK_STATE_CONNECTED;
+        }
+        break;
+      case DATACALL_ACTIVE_UP:
+        datacall.state = GECKO_NETWORK_STATE_CONNECTED;
+        break;
+    }
+  },
+
   /**
    * Helper for processing received multipart SMS.
    *
    * @return null for handled segments, and an object containing full message
    *         body once all segments are received.
    */
   _processReceivedSmsSegment: function _processReceivedSmsSegment(original) {
     let hash = original.sender + ":" + original.header.segmentRef;
@@ -1434,73 +1512,16 @@ let RIL = {
 
     if (DEBUG) {
       debug("Got full multipart SMS: " + JSON.stringify(options));
     }
 
     return options;
   },
 
-  _handleChangedCallState: function _handleChangedCallState(changedCall) {
-    let message = {type: "callStateChange",
-                   call: {callIndex: changedCall.callIndex,
-                          state: changedCall.state,
-                          number: changedCall.number,
-                          name: changedCall.name}};
-    this.sendDOMMessage(message);
-  },
-
-  _handleDisconnectedCall: function _handleDisconnectedCall(disconnectedCall) {
-    let message = {type: "callDisconnected",
-                   call: {callIndex: disconnectedCall.callIndex}};
-    this.sendDOMMessage(message);
-  },
-
-  _processDataCallList: function _processDataCallList(datacalls) {
-    for each (let currentDataCall in this.currentDataCalls) {
-      let newDataCall;
-      if (datacalls) {
-        newDataCall = datacalls[currentDataCall.cid];
-        delete datacalls[currentDataCall.cid];
-      }
-
-      if (newDataCall) {
-        switch (newDataCall.active) {
-          case DATACALL_INACTIVE:
-            newDataCall.state = GECKO_NETWORK_STATE_DISCONNECTED;
-            break;
-          case DATACALL_ACTIVE_DOWN:
-            newDataCall.state = GECKO_NETWORK_STATE_SUSPENDED;
-            if (RILQUIRKS_DATACALLSTATE_DOWN_IS_UP) {
-              newDataCall.state = GECKO_NETWORK_STATE_CONNECTED;
-            }
-            break;
-          case DATACALL_ACTIVE_UP:
-            newDataCall.state = GECKO_NETWORK_STATE_CONNECTED;
-            break;
-        }
-        if (newDataCall.state != currentDataCall.state) {
-          currentDataCall.active = newDataCall.active;
-          currentDataCall.state = newDataCall.state;
-          this.sendDOMMessage({type: "datacallstatechange",
-                               datacall: currentDataCall});
-        }
-      } else {
-        delete this.currentDataCalls[currentDataCall.callIndex];
-        currentDataCall.state = GECKO_NETWORK_STATE_DISCONNECTED;
-        this.sendDOMMessage({type: "datacallstatechange",
-                             datacall: currentDataCall});
-      }
-    }
-
-    for each (let datacall in datacalls) {
-      if (DEBUG) debug("Unexpected data call: " + JSON.stringify(datacall));
-    }
-  },
-
   /**
    * Handle incoming messages from the main UI thread.
    *
    * @param message
    *        Object containing the message. Messages are supposed
    */
   handleDOMMessage: function handleMessage(message) {
     if (DEBUG) debug("Received DOM message " + JSON.stringify(message));
@@ -1564,34 +1585,36 @@ let RIL = {
     if (typeof method == "function") {
       if (DEBUG) debug("Handling parcel as " + method.name);
       method.call(this, length, options);
     }
   }
 };
 
 RIL[REQUEST_GET_SIM_STATUS] = function REQUEST_GET_SIM_STATUS() {
-  let iccStatus = {
-    cardState:                   Buf.readUint32(), // CARD_STATE_*
-    universalPINState:           Buf.readUint32(), // PINSTATE_*
-    gsmUmtsSubscriptionAppIndex: Buf.readUint32(),
-    setCdmaSubscriptionAppIndex: Buf.readUint32(),
-    apps:                        []
-  };
+  let iccStatus = {};
+  iccStatus.cardState = Buf.readUint32(); // CARD_STATE_*
+  iccStatus.universalPINState = Buf.readUint32(); // CARD_PINSTATE_*
+  iccStatus.gsmUmtsSubscriptionAppIndex = Buf.readUint32();
+  iccStatus.cdmaSubscriptionAppIndex = Buf.readUint32();
+  if (!RILQUIRKS_V5_LEGACY) {
+    iccStatus.imsSubscriptionAppIndex = Buf.readUint32();
+  }
 
   let apps_length = Buf.readUint32();
   if (apps_length > CARD_MAX_APPS) {
     apps_length = CARD_MAX_APPS;
   }
 
+  iccStatus.apps = [];
   for (let i = 0 ; i < apps_length ; i++) {
     iccStatus.apps.push({
-      app_type:       Buf.readUint32(), // APPTYPE_*
-      app_state:      Buf.readUint32(), // CARD_APP_STATE_*
-      perso_substate: Buf.readUint32(), // PERSOSUBSTATE_*
+      app_type:       Buf.readUint32(), // CARD_APPTYPE_*
+      app_state:      Buf.readUint32(), // CARD_APPSTATE_*
+      perso_substate: Buf.readUint32(), // CARD_PERSOSUBSTATE_*
       aid:            Buf.readString(),
       app_label:      Buf.readString(),
       pin1_replaced:  Buf.readUint32(),
       pin1:           Buf.readUint32(),
       pin2:           Buf.readUint32()
     });
   }
 
@@ -1668,53 +1691,75 @@ RIL[REQUEST_HANGUP] = function REQUEST_H
 RIL[REQUEST_HANGUP_WAITING_OR_BACKGROUND] = null;
 RIL[REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND] = null;
 RIL[REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE] = null;
 RIL[REQUEST_SWITCH_HOLDING_AND_ACTIVE] = null;
 RIL[REQUEST_CONFERENCE] = null;
 RIL[REQUEST_UDUB] = null;
 RIL[REQUEST_LAST_CALL_FAIL_CAUSE] = null;
 RIL[REQUEST_SIGNAL_STRENGTH] = function REQUEST_SIGNAL_STRENGTH() {
-  let signalStrength = Buf.readUint32();
+  let obj = {};
+
+  // GSM
+  // Valid values are (0-31, 99) as defined in TS 27.007 8.5.
+  obj.gsmSignalStrength = Buf.readUint32();
   // The SGS2 seems to compute the number of bars for us and expose those
   // instead of the actual signal strength.
-  let bars = signalStrength >> 8;
-  signalStrength = signalStrength & 0xff;
-  let strength = {
+  obj.bars = obj.gsmSignalStrength >> 8; //TODO remove this, see bug 729173
+  obj.gsmSignalStrength = obj.gsmSignalStrength & 0xff;
+  // GSM bit error rate (0-7, 99) as defined in TS 27.007 8.5.
+  obj.gsmBitErrorRate = Buf.readUint32();
+
+  // CDMA
+  // The CDMA RSSI value.
+  obj.cdmaDBM = Buf.readUint32();
+  // The CDMA EC/IO.
+  obj.cdmaECIO = Buf.readUint32();
+  // The EVDO RSSI value.
+
+  // EVDO
+  obj.evdoDBM = Buf.readUint32();
+  // The EVDO EC/IO.
+  obj.evdoECIO = Buf.readUint32();
+  // Signal-to-noise ratio. Valid values are 0 to 8.
+  obj.evdoSNR = Buf.readUint32();
+
+  // LTE
+  if (!RILQUIRKS_V5_LEGACY) {
     // Valid values are (0-31, 99) as defined in TS 27.007 8.5.
-    gsmSignalStrength: signalStrength,
-    // Non-standard extension by the SGS2.
-    bars:              bars,
-    // GSM bit error rate (0-7, 99) as defined in TS 27.007 8.5.
-    gsmBitErrorRate:   Buf.readUint32(),
-    // The CDMA RSSI value.
-    cdmaDBM:           Buf.readUint32(),
-    // The CDMA EC/IO.
-    cdmaECIO:          Buf.readUint32(),
-    // The EVDO RSSI value.
-    evdoDBM:           Buf.readUint32(),
-    // The EVDO EC/IO.
-    evdoECIO:          Buf.readUint32(),
-    // Valid values are 0-8.  8 is the highest signal to noise ratio
-    evdoSNR:           Buf.readUint32()
-  };
-  if (DEBUG) debug("Signal strength " + JSON.stringify(strength));
+    obj.lteSignalStrength = Buf.readUint32();
+    // Reference signal receive power in dBm, multiplied by -1.
+    // Valid values are 44 to 140.
+    obj.lteRSRP = Buf.readUint32();
+    // Reference signal receive quality in dB, multiplied by -1.
+    // Valid values are 3 to 20.
+    obj.lteRSRQ = Buf.readUint32();
+    // Signal-to-noise ratio for the reference signal.
+    // Valid values are -200 (20.0 dB) to +300 (30 dB).
+    obj.lteRSSNR = Buf.readUint32();
+    // Channel Quality Indicator, valid values are 0 to 15.
+    obj.lteCQI = Buf.readUint32();
+  }
+
+  if (DEBUG) debug("Signal strength " + JSON.stringify(obj));
   this.sendDOMMessage({type: "signalstrengthchange",
-                       signalStrength: strength});
+                       signalStrength: obj});
 };
-RIL[REQUEST_REGISTRATION_STATE] = function REQUEST_REGISTRATION_STATE(length) {
+RIL[REQUEST_VOICE_REGISTRATION_STATE] = function REQUEST_VOICE_REGISTRATION_STATE(length) {
   let state = Buf.readStringList();
-  this._processRegistrationState(state);
+debug("voice registration state: " + state);
+  this._processVoiceRegistrationState(state);
 };
-RIL[REQUEST_GPRS_REGISTRATION_STATE] = function REQUEST_GPRS_REGISTRATION_STATE(length) {
+RIL[REQUEST_DATA_REGISTRATION_STATE] = function REQUEST_DATA_REGISTRATION_STATE(length) {
   let state = Buf.readStringList();
-  this._processGPRSRegistrationState(state);
+  this._processDataRegistrationState(state);
 };
 RIL[REQUEST_OPERATOR] = function REQUEST_OPERATOR(length) {
   let operator = Buf.readStringList();
+  if (DEBUG) debug("Operator data: " + operator);
   if (operator.length < 3) {
     if (DEBUG) debug("Expected at least 3 strings for operator.");
   }
   if (!this.operator ||
       this.operator.alphaLong  != operator[0] ||
       this.operator.alphaShort != operator[1] ||
       this.operator.numeric    != operator[2]) {
     this.operator = {alphaLong:  operator[0],
@@ -1743,32 +1788,44 @@ RIL[REQUEST_SEND_SMS] = function REQUEST
     this.sendSMS(options);
     return;
   }
 
   options.type = "sms-sent";
   this.sendDOMMessage(options);
 };
 RIL[REQUEST_SEND_SMS_EXPECT_MORE] = null;
-RIL[REQUEST_SETUP_DATA_CALL] = function REQUEST_SETUP_DATA_CALL(length, options) {
+
+RIL.readSetupDataCall_v5 = function readSetupDataCall_v5(options) {
+  if (!options) {
+    options = {};
+  }
   let [cid, ifname, ipaddr, dns, gw] = Buf.readStringList();
   options.cid = cid;
   options.ifname = ifname;
   options.ipaddr = ipaddr;
   options.dns = dns;
   options.gw = gw;
   options.active = DATACALL_ACTIVE_UNKNOWN;
   options.state = GECKO_NETWORK_STATE_CONNECTING;
-  this.currentDataCalls[options.cid] = options;
-  this.sendDOMMessage({type: "datacallstatechange",
-                       datacall: options});
+  return options;
+};
 
-  // Let's get the list of data calls to ensure we know whether it's active
-  // or not.
-  this.getDataCallList();
+RIL[REQUEST_SETUP_DATA_CALL] = function REQUEST_SETUP_DATA_CALL(length, options) {
+  if (RILQUIRKS_V5_LEGACY) {
+    this.readSetupDataCall_v5(options);
+    this.currentDataCalls[options.cid] = options;
+    this.sendDOMMessage({type: "datacallstatechange",
+                         datacall: options});
+    // Let's get the list of data calls to ensure we know whether it's active
+    // or not.
+    this.getDataCallList();
+    return;
+  }
+  this[REQUEST_DATA_CALL_LIST](length, options);
 };
 RIL[REQUEST_SIM_IO] = function REQUEST_SIM_IO(length, options) {
   switch (options.fileid) {
     case ICC_EF_MSISDN:
       this._processMSISDNResponse(options);
       break;
   }
 };
@@ -1804,43 +1861,80 @@ RIL[REQUEST_QUERY_NETWORK_SELECTION_MODE
 };
 RIL[REQUEST_SET_NETWORK_SELECTION_AUTOMATIC] = null;
 RIL[REQUEST_SET_NETWORK_SELECTION_MANUAL] = null;
 RIL[REQUEST_QUERY_AVAILABLE_NETWORKS] = null;
 RIL[REQUEST_DTMF_START] = null;
 RIL[REQUEST_DTMF_STOP] = null;
 RIL[REQUEST_BASEBAND_VERSION] = function REQUEST_BASEBAND_VERSION() {
   this.basebandVersion = Buf.readString();
+  if (DEBUG) debug("Baseband version: " + this.basebandVersion);
 };
 RIL[REQUEST_SEPARATE_CONNECTION] = null;
 RIL[REQUEST_SET_MUTE] = null;
 RIL[REQUEST_GET_MUTE] = null;
 RIL[REQUEST_QUERY_CLIP] = null;
 RIL[REQUEST_LAST_DATA_CALL_FAIL_CAUSE] = null;
+
+RIL.readDataCall_v5 = function readDataCall_v5() {
+  return {
+    cid: Buf.readUint32().toString(),
+    active: Buf.readUint32(), // DATACALL_ACTIVE_*
+    type: Buf.readString(),
+    apn: Buf.readString(),
+    address: Buf.readString()
+  };
+};
+
+RIL.readDataCall_v6 = function readDataCall_v6(obj) {
+  if (!obj) {
+    obj = {};
+  }
+  obj.status = Buf.readUint32();  // DATACALL_FAIL_*
+  obj.suggestedRetryTime = Buf.readUint32();
+  obj.cid = Buf.readUint32().toString();
+  obj.active = Buf.readUint32();  // DATACALL_ACTIVE_*
+  obj.type = Buf.readString();
+  obj.ifname = Buf.readString();
+  obj.ipaddr = Buf.readString();
+  obj.dns = Buf.readString();
+  obj.gw = Buf.readString();
+  if (obj.dns) {
+    obj.dns = obj.dns.split(" ");
+  }
+  //TODO for now we only support one address and gateway
+  if (obj.ipaddr) {
+    obj.ipaddr = obj.ipaddr.split(" ")[0];
+  }
+  if (obj.gw) {
+    obj.gw = obj.gw.split(" ")[0];
+  }
+  return obj;
+};
+
 RIL[REQUEST_DATA_CALL_LIST] = function REQUEST_DATA_CALL_LIST(length) {
   this.initRILQuirks();
-
-  let num = 0;
-  if (length) {
-    num = Buf.readUint32();
-  }
-  if (!num) {
+  if (!length) {
     this._processDataCallList(null);
     return;
   }
 
+  let version = 0;
+  if (!RILQUIRKS_V5_LEGACY) {
+    version = Buf.readUint32();
+  }
+  let num = num = Buf.readUint32();
   let datacalls = {};
   for (let i = 0; i < num; i++) {
-    let datacall = {
-      cid: Buf.readUint32().toString(),
-      active: Buf.readUint32(),
-      type: Buf.readString(),
-      apn: Buf.readString(),
-      address: Buf.readString()
-    };
+    let datacall;
+    if (version < 6) {
+      datacall = this.readDataCall_v5();
+    } else {
+      datacall = this.readDataCall_v6();
+    }
     datacalls[datacall.cid] = datacall;
   }
 
   this._processDataCallList(datacalls);
 };
 RIL[REQUEST_RESET_RADIO] = null;
 RIL[REQUEST_OEM_HOOK_RAW] = null;
 RIL[REQUEST_OEM_HOOK_STRINGS] = null;
@@ -1855,17 +1949,17 @@ RIL[REQUEST_STK_SET_PROFILE] = null;
 RIL[REQUEST_STK_SEND_ENVELOPE_COMMAND] = null;
 RIL[REQUEST_STK_SEND_TERMINAL_RESPONSE] = null;
 RIL[REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM] = null;
 RIL[REQUEST_EXPLICIT_CALL_TRANSFER] = null;
 RIL[REQUEST_SET_PREFERRED_NETWORK_TYPE] = null;
 RIL[REQUEST_GET_PREFERRED_NETWORK_TYPE] = null;
 RIL[REQUEST_GET_NEIGHBORING_CELL_IDS] = null;
 RIL[REQUEST_SET_LOCATION_UPDATES] = null;
-RIL[REQUEST_CDMA_SET_SUBSCRIPTION] = null;
+RIL[REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE] = null;
 RIL[REQUEST_CDMA_SET_ROAMING_PREFERENCE] = null;
 RIL[REQUEST_CDMA_QUERY_ROAMING_PREFERENCE] = null;
 RIL[REQUEST_SET_TTY_MODE] = null;
 RIL[REQUEST_QUERY_TTY_MODE] = null;
 RIL[REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE] = null;
 RIL[REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE] = null;
 RIL[REQUEST_CDMA_FLASH] = null;
 RIL[REQUEST_CDMA_BURST_DTMF] = null;
@@ -1894,107 +1988,81 @@ RIL[REQUEST_GET_SMSC_ADDRESS] = function
   if (this.SMSC && options.body) {
     this.sendSMS(options);
   }
 };
 RIL[REQUEST_SET_SMSC_ADDRESS] = null;
 RIL[REQUEST_REPORT_SMS_MEMORY_STATUS] = null;
 RIL[REQUEST_REPORT_STK_SERVICE_IS_RUNNING] = null;
 RIL[UNSOLICITED_RESPONSE_RADIO_STATE_CHANGED] = function UNSOLICITED_RESPONSE_RADIO_STATE_CHANGED() {
-  let newState = Buf.readUint32();
+  let radioState = Buf.readUint32();
+
+  let newState;
+  if (radioState == RADIO_STATE_UNAVAILABLE) {
+    newState = GECKO_RADIOSTATE_UNAVAILABLE;
+  } else if (radioState == RADIO_STATE_OFF) {
+    newState = GECKO_RADIOSTATE_OFF;
+  } else {
+    newState = GECKO_RADIOSTATE_READY;
+  }
+
   if (DEBUG) {
-    debug("Radio state changed from " + this.radioState + " to " + newState);
+    debug("Radio state changed from '" + this.radioState +
+          "' to '" + newState + "'");
   }
   if (this.radioState == newState) {
-    // No change in state, return.
     return;
   }
 
-  let gsm = newState == RADIO_STATE_SIM_NOT_READY        ||
-            newState == RADIO_STATE_SIM_LOCKED_OR_ABSENT ||
-            newState == RADIO_STATE_SIM_READY;
-  let cdma = newState == RADIO_STATE_RUIM_NOT_READY       ||
-             newState == RADIO_STATE_RUIM_READY            ||
-             newState == RADIO_STATE_RUIM_LOCKED_OR_ABSENT ||
-             newState == RADIO_STATE_NV_NOT_READY          ||
-             newState == RADIO_STATE_NV_READY;
+  // TODO hardcoded for now (see bug 726098)
+  let cdma = false;
 
-  // Figure out state transitions and send out more RIL requests as necessary
-  // as well as events to the main thread.
-
-  if (this.radioState == RADIO_STATE_UNAVAILABLE &&
-      newState != RADIO_STATE_UNAVAILABLE) {
+  if (this.radioState == GECKO_RADIOSTATE_UNAVAILABLE &&
+      newState != GECKO_RADIOSTATE_UNAVAILABLE) {
     // The radio became available, let's get its info.
-    if (gsm) {
+    if (cdma) {
+      this.getDeviceIdentity();
+    } else {
       this.getIMEI();
       this.getIMEISV();
     }
-    if (cdma) {
-      this.getDeviceIdentity();
-    }
     this.getBasebandVersion();
-    this.setScreenState(true);
-    this.sendDOMMessage({
-      type: "radiostatechange",
-      radioState: (newState == RADIO_STATE_OFF) ?
-                   GECKO_RADIOSTATE_OFF : GECKO_RADIOSTATE_READY
-    });
 
     //XXX TODO For now, just turn the radio on if it's off. for the real
     // deal we probably want to do the opposite: start with a known state
     // when we boot up and let the UI layer control the radio power.
-    if (newState == RADIO_STATE_OFF) {
+    if (newState == GECKO_RADIOSTATE_OFF) {
       this.setRadioPower(true);
     }
   }
 
-  if (newState == RADIO_STATE_UNAVAILABLE) {
-    // The radio is no longer available, we need to deal with any
-    // remaining pending requests.
-    //TODO do that
-    this.sendDOMMessage({type: "radiostatechange",
-                         radioState: GECKO_RADIOSTATE_UNAVAILABLE});
-  }
+  this.radioState = newState;
+  this.sendDOMMessage({
+    type: "radiostatechange",
+    radioState: newState
+  });
 
-  if (newState == RADIO_STATE_SIM_READY  ||
-      newState == RADIO_STATE_RUIM_READY ||
-      newState == RADIO_STATE_NV_READY) {
-    // The ICC has become available. Get all the things.
-    this.getICCStatus();
-    this.requestNetworkInfo();
-    this.getSignalStrength();
-    this.getSMSCAddress();
-    this.getMSISDN();
-    this.sendDOMMessage({type: "cardstatechange",
-                         cardState: GECKO_CARDSTATE_READY});
+  // If the radio is up and on, so let's query the card state.
+  // On older RILs only if the card is actually ready, though.
+  if (radioState == RADIO_STATE_UNAVAILABLE ||
+      radioState == RADIO_STATE_OFF) {
+    return;
   }
-  if (newState == RADIO_STATE_SIM_LOCKED_OR_ABSENT  ||
-      newState == RADIO_STATE_RUIM_LOCKED_OR_ABSENT) {
-    this.getICCStatus();
-    this.sendDOMMessage({type: "cardstatechange",
-                         cardState: GECKO_CARDSTATE_UNAVAILABLE});
+  if (RILQUIRKS_V5_LEGACY &&
+      (radioState == RADIO_STATE_SIM_NOT_READY ||
+       radioState == RADIO_STATE_RUIM_NOT_READY ||
+       radioState == RADIO_STATE_NV_NOT_READY)) {
+    return;
   }
-
-  let wasOn = this.radioState != RADIO_STATE_OFF &&
-              this.radioState != RADIO_STATE_UNAVAILABLE;
-  let isOn = newState != RADIO_STATE_OFF &&
-             newState != RADIO_STATE_UNAVAILABLE;
-  if (!wasOn && isOn) {
-    //TODO
-  }
-  if (wasOn && !isOn) {
-    //TODO
-  }
-
-  this.radioState = newState;
+  this.getICCStatus();
 };
 RIL[UNSOLICITED_RESPONSE_CALL_STATE_CHANGED] = function UNSOLICITED_RESPONSE_CALL_STATE_CHANGED() {
   this.getCurrentCalls();
 };
-RIL[UNSOLICITED_RESPONSE_NETWORK_STATE_CHANGED] = function UNSOLICITED_RESPONSE_NETWORK_STATE_CHANGED() {
+RIL[UNSOLICITED_RESPONSE_VOICE_NETWORK_STATE_CHANGED] = function UNSOLICITED_RESPONSE_VOICE_NETWORK_STATE_CHANGED() {
   if (DEBUG) debug("Network state changed, re-requesting phone state.");
   this.requestNetworkInfo();
 };
 RIL[UNSOLICITED_RESPONSE_NEW_SMS] = function UNSOLICITED_RESPONSE_NEW_SMS(length) {
   if (!length) {
     if (DEBUG) debug("Received empty SMS!");
     //TODO: should we acknowledge the SMS here? maybe only after multiple
     //failures.
@@ -2081,18 +2149,22 @@ RIL[UNSOLICITED_NITZ_TIME_RECEIVED] = fu
                        networkTimeZoneInMinutes: tz * 15,
                        dstFlag: dst,
                        localTimeStampInMS: now});
 };
 
 RIL[UNSOLICITED_SIGNAL_STRENGTH] = function UNSOLICITED_SIGNAL_STRENGTH() {
   this[REQUEST_SIGNAL_STRENGTH]();
 };
-RIL[UNSOLICITED_DATA_CALL_LIST_CHANGED] = function UNSOLICITED_DATA_CALL_LIST_CHANGED(length) {
-  this.getDataCallList();
+RIL[UNSOLICITED_DATA_CALL_LIST_CHANGED] = function UNSOLICITED_DATA_CALL_LIST_CHANGED(length, options) {
+  if (RILQUIRKS_V5_LEGACY) {
+    this.getDataCallList();
+    return;
+  }
+  this[REQUEST_GET_DATA_CALL_LIST](length, options);
 };
 RIL[UNSOLICITED_SUPP_SVC_NOTIFICATION] = null;
 RIL[UNSOLICITED_STK_SESSION_END] = null;
 RIL[UNSOLICITED_STK_PROACTIVE_COMMAND] = null;
 RIL[UNSOLICITED_STK_EVENT_NOTIFY] = null;
 RIL[UNSOLICITED_STK_CALL_SETUP] = null;
 RIL[UNSOLICITED_SIM_SMS_STORAGE_FULL] = null;
 RIL[UNSOLICITED_SIM_REFRESH] = null;
@@ -2119,16 +2191,24 @@ RIL[UNSOLICITED_CDMA_RUIM_SMS_STORAGE_FU
 RIL[UNSOLICITED_RESTRICTED_STATE_CHANGED] = null;
 RIL[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE] = null;
 RIL[UNSOLICITED_CDMA_CALL_WAITING] = null;
 RIL[UNSOLICITED_CDMA_OTA_PROVISION_STATUS] = null;
 RIL[UNSOLICITED_CDMA_INFO_REC] = null;
 RIL[UNSOLICITED_OEM_HOOK_RAW] = null;
 RIL[UNSOLICITED_RINGBACK_TONE] = null;
 RIL[UNSOLICITED_RESEND_INCALL_MUTE] = null;
+RIL[UNSOLICITED_RIL_CONNECTED] = function UNSOLICITED_RIL_CONNECTED(length, options) {
+  let version = Buf.readUint32List()[0];
+  RILQUIRKS_V5_LEGACY = (version < 5);
+  if (DEBUG) {
+    debug("Detected RIL version " + version);
+    debug("RILQUIRKS_V5_LEGACY is " + RILQUIRKS_V5_LEGACY);
+  }
+};
 
 
 /**
  * This object exposes the functionality to parse and serialize PDU strings
  *
  * A PDU is a string containing a series of hexadecimally encoded octets
  * or nibble-swapped binary-coded decimals (BCDs). It contains not only the
  * message text but information about the sender, the SMS service center,
--- a/dom/tests/mochitest/ajax/lib/AJAX_setup.js
+++ b/dom/tests/mochitest/ajax/lib/AJAX_setup.js
@@ -3,17 +3,17 @@ var AJAXtests = [];
 function runAJAXTest() {
   if (AJAXtests.length == 0) {
     SimpleTest.finish();
     return;
   }
 
   var test = AJAXtests.shift();
   var testframe = document.getElementById("testframe");
-  setTimeout(function() { testframe.src = test; }, 0);
+  testframe.src = test;
 }
 
 function onManifestLoad(manifest) {
   if (manifest.testcases) {
     AJAXtests = manifest.testcases;
     runAJAXTest();    
   } else {
     ok(false, "manifest check", "no manifest!?!");
--- a/dom/tests/mochitest/dom-level1-core/DOMTestCase.js
+++ b/dom/tests/mochitest/dom-level1-core/DOMTestCase.js
@@ -639,39 +639,16 @@ function getResourceURI(name, scheme, co
     return fileBase + name + getSuffix(contentType);
 }
 
 
 function getImplementation() {
     return builder.getImplementation();
 }
 
-//sayrer override the SimpleTest logger
-SimpleTest._logResult = function(test, passString, failString) {
-  var msg = test.result ? passString : failString;
-  msg += " | " + test.name;
-  if (test.result) {
-      if (test.todo)
-          parentRunner.logger.error(msg)
-      else
-          parentRunner.logger.log(msg);
-  } else {
-      msg += " | " + test.diag;
-      if (test.todo) {
-        parentRunner.logger.log(msg)
-      } else {
-        if (todoTests[docName]) {
-          parentRunner.logger.log("expected error in todo testcase | " + test.name);
-        } else {
-          parentRunner.logger.error(msg);
-        }
-      } 
-  }
-}
-
 function testFails (test) {
   if (!test.result) {
     test.todo = true;
     return true;
   }
   return false;
 }
 
--- a/dom/tests/mochitest/dom-level2-core/DOMTestCase.js
+++ b/dom/tests/mochitest/dom-level2-core/DOMTestCase.js
@@ -643,39 +643,16 @@ function getResourceURI(name, scheme, co
     return fileBase + name + getSuffix(contentType);
 }
 
 
 function getImplementation() {
     return builder.getImplementation();
 }
 
-//sayrer override the SimpleTest logger
-SimpleTest._logResult = function(test, passString, failString) {
-  var msg = test.result ? passString : failString;
-  msg += " | " + test.name;
-  if (test.result) {
-      if (test.todo)
-          parentRunner.logger.error(msg)
-      else
-          parentRunner.logger.log(msg);
-  } else {
-      msg += " | " + test.diag;
-      if (test.todo) {
-        parentRunner.logger.log(msg)
-      } else {
-        if (todoTests[docName]) {
-          parentRunner.logger.log("expected error in todo testcase | " + test.name);
-        } else {
-          parentRunner.logger.error(msg);
-        }
-      } 
-  }
-}
-
 window.doc = window;  
 SimpleTest.waitForExplicitFinish();
 addLoadEvent(function(){ setUpPage(); });
 function testFails (test) {
   if (!test.result) {
     test.todo = true;
     return true;
   }
--- a/dom/tests/mochitest/dom-level2-html/DOMTestCase.js
+++ b/dom/tests/mochitest/dom-level2-html/DOMTestCase.js
@@ -643,39 +643,16 @@ function getResourceURI(name, scheme, co
     return fileBase + name + getSuffix(contentType);
 }
 
 
 function getImplementation() {
     return builder.getImplementation();
 }
 
-//sayrer override the SimpleTest logger
-SimpleTest._logResult = function(test, passString, failString) {
-  var msg = test.result ? passString : failString;
-  msg += " | " + test.name;
-  if (test.result) {
-      if (test.todo)
-          parentRunner.logger.error(msg)
-      else
-          parentRunner.logger.log(msg);
-  } else {
-      msg += " | " + test.diag;
-      if (test.todo) {
-        parentRunner.logger.log(msg)
-      } else {
-	// if (todoTests[docName]) {
-        //  parentRunner.logger.log("expected error in todo testcase | " + test.name);
-        //} else {
-          parentRunner.logger.error(msg);
-	  //}
-      } 
-  }
-}
-
 window.doc = window;  
 SimpleTest.waitForExplicitFinish();
 addLoadEvent(function(){ setUpPage(); });
 function testFails (test) {
   if (!test.result) {
     test.todo = true;
     return true;
   }
--- a/dom/workers/EventTarget.cpp
+++ b/dom/workers/EventTarget.cpp
@@ -64,17 +64,17 @@ namespace {
 
 DECL_EVENTTARGET_CLASS(gClass, "EventTarget")
 DECL_EVENTTARGET_CLASS(gMainThreadClass, "WorkerEventTarget")
 
 #undef DECL_EVENTTARGET_CLASS
 
 inline
 bool
-EnsureObjectIsEventTarget(JSContext* aCx, JSObject* aObj, char* aFunctionName)
+EnsureObjectIsEventTarget(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
 {
   JSClass* classPtr = JS_GetClass(aObj);
   if (ClassIsWorker(classPtr) || ClassIsWorkerGlobalScope(classPtr) ||
       ClassIsXMLHttpRequest(classPtr)) {
     return true;
   }
 
   JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -3159,35 +3159,43 @@ WorkerPrivate::NotifyFeatures(JSContext*
       NS_WARNING("Failed to notify child worker!");
     }
   }
 }
 
 void
 WorkerPrivate::CancelAllTimeouts(JSContext* aCx)
 {
+  AssertIsOnWorkerThread();
+
   if (mTimerRunning) {
     NS_ASSERTION(mTimer, "Huh?!");
     NS_ASSERTION(!mTimeouts.IsEmpty(), "Huh?!");
 
     if (NS_FAILED(mTimer->Cancel())) {
       NS_WARNING("Failed to cancel timer!");
     }
 
     for (PRUint32 index = 0; index < mTimeouts.Length(); index++) {
       mTimeouts[index]->mCanceled = true;
     }
 
-    RunExpiredTimeouts(aCx);
-
-    mTimer = nsnull;
+    if (!RunExpiredTimeouts(aCx)) {
+      JS_ReportPendingException(aCx);
+    }
+
+    mTimerRunning = false;
   }
-  else {
+#ifdef DEBUG
+  else if (!mRunningExpiredTimeouts) {
     NS_ASSERTION(mTimeouts.IsEmpty(), "Huh?!");
   }
+#endif
+
+  mTimer = nsnull;
 }
 
 PRUint32
 WorkerPrivate::CreateNewSyncLoop()
 {
   AssertIsOnWorkerThread();
 
   NS_ASSERTION(mSyncQueues.Length() < PR_UINT32_MAX,
@@ -3506,18 +3514,25 @@ WorkerPrivate::SetTimeout(JSContext* aCx
   const PRUint32 timerId = mNextTimeoutId++;
 
   Status currentStatus;
   {
     MutexAutoLock lock(mMutex);
     currentStatus = mStatus;
   }
 
-  if (currentStatus > Running) {
+  // It's a script bug if setTimeout/setInterval are called from a close handler
+  // so throw an exception.
+  if (currentStatus == Closing) {
     JS_ReportError(aCx, "Cannot schedule timeouts from the close handler!");
+  }
+
+  // If the worker is trying to call setTimeout/setInterval and the parent
+  // thread has initiated the close process then just silently fail.
+  if (currentStatus >= Closing) {
     return false;
   }
 
   nsAutoPtr<TimeoutInfo> newInfo(new TimeoutInfo());
   newInfo->mIsInterval = aIsInterval;
   newInfo->mId = timerId;
 
   if (NS_UNLIKELY(timerId == PR_UINT32_MAX)) {
@@ -3650,16 +3665,17 @@ WorkerPrivate::RunExpiredTimeouts(JSCont
 
   // We may be called recursively (e.g. close() inside a timeout) or we could
   // have been canceled while this event was pending, bail out if there is
   // nothing to do.
   if (mRunningExpiredTimeouts || !mTimerRunning) {
     return true;
   }
 
+  NS_ASSERTION(mTimer, "Must have a timer!");
   NS_ASSERTION(!mTimeouts.IsEmpty(), "Should have some work to do!");
 
   bool retval = true;
 
   AutoPtrComparator<TimeoutInfo> comparator = GetAutoPtrComparator(mTimeouts);
   JSObject* global = JS_GetGlobalObject(aCx);
   JSPrincipals* principal = GetWorkerPrincipal();
 
@@ -3714,22 +3730,26 @@ WorkerPrivate::RunExpiredTimeouts(JSCont
                                 info->mExtraArgVals.Length(),
                                 info->mExtraArgVals.Elements(), &rval) &&
           !JS_ReportPendingException(aCx)) {
         retval = false;
         break;
       }
     }
 
+    NS_ASSERTION(mRunningExpiredTimeouts, "Someone changed this!");
+
     // Reschedule intervals.
-    if (info->mIsInterval) {
+    if (info->mIsInterval && !info->mCanceled) {
       PRUint32 timeoutIndex = mTimeouts.IndexOf(info);
       NS_ASSERTION(timeoutIndex != PRUint32(-1),
                    "Should still be in the main list!");
 
+      // This is nasty but we have to keep the old nsAutoPtr from deleting the
+      // info we're about to re-add.
       mTimeouts[timeoutIndex].forget();
       mTimeouts.RemoveElementAt(timeoutIndex);
 
       NS_ASSERTION(!mTimeouts.Contains(info), "Shouldn't have duplicates!");
 
       // NB: We must ensure that info->mTargetTime > now (where now is the
       // now above, not literally TimeStamp::Now()) or we will remove the
       // interval in the next loop below.
@@ -3750,18 +3770,18 @@ WorkerPrivate::RunExpiredTimeouts(JSCont
                    "Interval timers can only be removed when canceled!");
       mTimeouts.RemoveElement(info);
     }
     else {
       index++;
     }
   }
 
-  // Signal the parent that we're no longer using timeouts or reschedule the
-  // timer.
+  // Either signal the parent that we're no longer using timeouts or reschedule
+  // the timer.
   if (mTimeouts.IsEmpty()) {
     if (!ModifyBusyCountFromWorker(aCx, false)) {
       retval = false;
     }
     mTimerRunning = false;
   }
   else if (retval && !RescheduleTimeoutTimer(aCx)) {
     retval = false;
--- a/dom/workers/test/Makefile.in
+++ b/dom/workers/test/Makefile.in
@@ -51,16 +51,18 @@ DIRS = \
 
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES = \
   test_404.html \
   test_atob.html \
   atob_worker.js \
   test_blobWorkers.html \
+  test_clearTimeouts.html \
+  clearTimeouts_worker.js \
   test_close.html \
   close_worker.js \
   test_closeOnGC.html \
   closeOnGC_worker.js \
   closeOnGC_server.sjs \
   test_dataURLWorker.html \
   test_errorPropagation.html \
   errorPropagation_iframe.html \
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/clearTimeouts_worker.js
@@ -0,0 +1,12 @@
+var count = 0;
+function timerFunction() {
+  if (++count == 30) {
+    close();
+    postMessage("ready");
+    while (true) { }
+  }
+}
+
+for (var i = 0; i < 10; i++) {
+  setInterval(timerFunction, 500);
+}
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/test_clearTimeouts.html
@@ -0,0 +1,30 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for DOM Worker Threads</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+  new Worker("clearTimeouts_worker.js").onmessage = function(event) {
+    event.target.terminate();
+
+    is(event.data, "ready", "Correct message");
+    setTimeout(function() { SimpleTest.finish(); }, 1000);
+  }
+
+  SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+</body>
+</html>
--- a/editor/libeditor/text/tests/Makefile.in
+++ b/editor/libeditor/text/tests/Makefile.in
@@ -60,17 +60,16 @@ include $(topsrcdir)/config/rules.mk
 		test_bug604532.html \
 		test_bug625452.html \
 		test_bug629172.html \
 		test_bug638596.html \
 		test_bug641466.html \
 		test_bug645914.html \
 		test_bug681229.html \
 		test_bug692520.html \
-		test_bug717147.html \
 		test_dom_input_event_on_texteditor.html \
 		$(NULL)
 
 # disables the key handling test on gtk2 because gtk2 overrides some key events
 # on our editor, and the combinations depend on the system.
 ifneq ($(MOZ_WIDGET_TOOLKIT),gtk2)
 _TEST_FILES += \
 		test_texteditor_keyevent_handling.html \
deleted file mode 100644
--- a/editor/libeditor/text/tests/test_bug717147.html
+++ /dev/null
@@ -1,99 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=717147
--->
-<head>
-  <title>Test for Bug 717147</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717147">Mozilla Bug 717147</a>
-<p id="display"></p>
-<div id="content">
-  <iframe id="formTarget" name="formTarget"></iframe>
-  <form action="data:text/html," target="formTarget">
-    <input name="test" id="initValue"><input type="submit">
-  </form>
-</div>
-<pre id="test">
-<script type="application/javascript">
-
-/** Test for Bug 717147 **/
-SimpleTest.waitForExplicitFinish();
-SimpleTest.waitForFocus(function() {
-  var formTarget = document.getElementById("formTarget");
-  var initValue = document.getElementById("initValue");
-
-  formTarget.addEventListener("load", function() {
-    var newInput = document.createElement("input");
-    newInput.setAttribute("name", "test");
-    document.body.appendChild(newInput);
-
-    setTimeout(function() {
-      var popupShown = false;
-      function listener() {
-        popupShown = true;
-      }
-      SpecialPowers.addAutoCompletePopupEventListener(window, listener);
-
-      newInput.value = "";
-      newInput.focus();
-
-      synthesizeComposition({ type: "compositionstart" });
-      synthesizeComposition({ type: "compositionupdate", data: "f" });
-      synthesizeText(
-        { "composition":
-          { "string": "f",
-            "clauses":
-            [
-              { "length": 1, "attr": COMPOSITION_ATTR_RAWINPUT }
-            ]
-          },
-          "caret": { "start": 1, "length": 0 }
-        });
-
-      hitEventLoop(function() {
-        ok(!popupShown, "Popup must not be opened during composition");
-
-        synthesizeText(
-          { "composition":
-            { "string": "f",
-              "clauses":
-              [
-                { "length": 0, "attr": 0 }
-              ]
-            },
-            "caret": { "start": 1, "length": 0 }
-          });
-        synthesizeComposition({ type: "compositionend", data: "f" });
-
-        hitEventLoop(function () {
-          ok(popupShown, "Popup must be opened after compositionend");
-
-          SpecialPowers.removeAutoCompletePopupEventListener(window, listener);
-          SimpleTest.finish();
-        }, 100);
-      }, 100);
-    }, 0);
-  }, false);
-
-  initValue.focus();
-  initValue.value = "foo";
-  synthesizeKey("VK_ENTER", {});
-});
-
-function hitEventLoop(func, times) {
-  if (times > 0) {
-    setTimeout(hitEventLoop, 0, func, times - 1);
-  } else {
-    setTimeout(func, 0);
-  }
-}
-
-</script>
-</pre>
-</body>
-</html>
--- a/embedding/components/find/src/nsFind.cpp
+++ b/embedding/components/find/src/nsFind.cpp
@@ -50,23 +50,23 @@
 #include "nsITextControlFrame.h"
 #include "nsIFormControl.h"
 #include "nsIEditor.h"
 #include "nsIPlaintextEditor.h"
 #include "nsIDocument.h"
 #include "nsTextFragment.h"
 #include "nsString.h"
 #include "nsIAtom.h"
-#include "nsParserCIID.h"
 #include "nsServiceManagerUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsIDOMElement.h"
 #include "nsIWordBreaker.h"
 #include "nsCRT.h"
 #include "nsRange.h"
+#include "nsContentUtils.h"
 
 // Yikes!  Casting a char to unichar can fill with ones!
 #define CHAR_TO_UNICHAR(c) ((PRUnichar)(const unsigned char)c)
 
 static NS_DEFINE_CID(kCContentIteratorCID, NS_CONTENTITERATOR_CID);
 static NS_DEFINE_CID(kCPreContentIteratorCID, NS_PRECONTENTITERATOR_CID);
 
 #define CH_SHY ((PRUnichar) 0xAD)
@@ -452,63 +452,27 @@ NS_NewFindContentIterator(bool aFindBack
   nsFindContentIterator* it = new nsFindContentIterator(aFindBackward);
   if (!it) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   return it->QueryInterface(NS_GET_IID(nsIContentIterator), (void **)aResult);
 }
 // --------------------------------------------------------------------
 
-// Sure would be nice if we could just get these from somewhere else!
-PRInt32 nsFind::sInstanceCount = 0;
-nsIAtom* nsFind::sImgAtom = nsnull;
-nsIAtom* nsFind::sHRAtom = nsnull;
-nsIAtom* nsFind::sScriptAtom = nsnull;
-nsIAtom* nsFind::sNoframesAtom = nsnull;
-nsIAtom* nsFind::sSelectAtom = nsnull;
-nsIAtom* nsFind::sTextareaAtom = nsnull;
-nsIAtom* nsFind::sThAtom = nsnull;
-nsIAtom* nsFind::sTdAtom = nsnull;
-
 NS_IMPL_ISUPPORTS1(nsFind, nsIFind)
 
 nsFind::nsFind()
   : mFindBackward(false)
   , mCaseSensitive(false)
   , mIterOffset(0)
 {
-  // Initialize the atoms if they aren't already:
-  if (sInstanceCount <= 0)
-  {
-    sImgAtom = NS_NewAtom("img");
-    sHRAtom = NS_NewAtom("hr");
-    sScriptAtom = NS_NewAtom("script");
-    sNoframesAtom = NS_NewAtom("noframes");
-    sSelectAtom = NS_NewAtom("select");
-    sTextareaAtom = NS_NewAtom("textarea");
-    sThAtom = NS_NewAtom("th");
-    sTdAtom = NS_NewAtom("td");
-  }
-  ++sInstanceCount;
 }
 
 nsFind::~nsFind()
 {
-  if (sInstanceCount <= 1)
-  {
-    NS_IF_RELEASE(sImgAtom);
-    NS_IF_RELEASE(sHRAtom);
-    NS_IF_RELEASE(sScriptAtom);
-    NS_IF_RELEASE(sNoframesAtom);
-    NS_IF_RELEASE(sSelectAtom);
-    NS_IF_RELEASE(sTextareaAtom);
-    NS_IF_RELEASE(sThAtom);
-    NS_IF_RELEASE(sTdAtom);
-  }
-  --sInstanceCount;
 }
 
 #ifdef DEBUG_FIND
 static void DumpNode(nsIDOMNode* aNode)
 {
   if (!aNode)
   {
     printf(">>>> Node: NULL\n");
@@ -775,31 +739,23 @@ nsFind::NextNode(nsIDOMRange* aSearchRan
 bool nsFind::IsBlockNode(nsIContent* aContent)
 {
   if (!aContent->IsHTML()) {
     return false;
   }
 
   nsIAtom *atom = aContent->Tag();
 
-  if (atom == sImgAtom ||
-      atom == sHRAtom ||
-      atom == sThAtom ||
-      atom == sTdAtom)
+  if (atom == nsGkAtoms::img ||
+      atom == nsGkAtoms::hr ||
+      atom == nsGkAtoms::th ||
+      atom == nsGkAtoms::td)
     return true;
 
-  if (!mParserService) {
-    mParserService = do_GetService(NS_PARSERSERVICE_CONTRACTID);
-    if (!mParserService)
-      return false;
-  }
-
-  bool isBlock = false;
-  mParserService->IsBlock(mParserService->HTMLAtomTagToId(atom), isBlock);
-  return isBlock;
+  return nsContentUtils::IsHTMLBlock(atom);
 }
 
 bool nsFind::IsTextNode(nsIDOMNode* aNode)
 {
   PRUint16 nodeType;
   aNode->GetNodeType(&nodeType);
 
   return nodeType == nsIDOMNode::TEXT_NODE ||
@@ -844,19 +800,19 @@ bool nsFind::SkipNode(nsIContent* aConte
 
   nsIContent *content = aContent;
   while (content)
   {
     atom = content->Tag();
 
     if (aContent->IsNodeOfType(nsINode::eCOMMENT) ||
         (content->IsHTML() &&
-         (atom == sScriptAtom ||
-          atom == sNoframesAtom ||
-          atom == sSelectAtom)))
+         (atom == nsGkAtoms::script ||
+          atom == nsGkAtoms::noframes ||
+          atom == nsGkAtoms::select)))
     {
 #ifdef DEBUG_FIND
       printf("Skipping node: ");
       nsCOMPtr<nsIDOMNode> node (do_QueryInterface(content));
       DumpNode(node);
 #endif
 
       return true;
--- a/embedding/components/find/src/nsFind.h
+++ b/embedding/components/find/src/nsFind.h
@@ -40,17 +40,16 @@
 #define nsFind_h__
 
 #include "nsIFind.h"
 
 #include "nsCOMPtr.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMRange.h"
 #include "nsIContentIterator.h"
-#include "nsIParserService.h"
 #include "nsIWordBreaker.h"
 
 class nsIAtom;
 class nsIContent;
 
 #define NS_FIND_CONTRACTID "@mozilla.org/embedcomp/rangefind;1"
 
 #define NS_FIND_CID \
@@ -65,36 +64,22 @@ public:
   NS_DECL_NSIFIND
 
   nsFind();
   virtual ~nsFind();
 
   static already_AddRefed<nsIDOMRange> CreateRange();
 
 protected:
-  static PRInt32 sInstanceCount;
-
-  // HTML tags we treat specially
-  static nsIAtom* sImgAtom;
-  static nsIAtom* sHRAtom;
-  // Nodes we skip
-  static nsIAtom* sScriptAtom;
-  static nsIAtom* sNoframesAtom;
-  static nsIAtom* sSelectAtom;
-  static nsIAtom* sTextareaAtom;
-  static nsIAtom* sThAtom;
-  static nsIAtom* sTdAtom;
-
   // Parameters set from the interface:
   //nsCOMPtr<nsIDOMRange> mRange;   // search only in this range
   bool mFindBackward;
   bool mCaseSensitive;
 
   nsCOMPtr<nsIWordBreaker> mWordBreaker;
-  nsCOMPtr<nsIParserService> mParserService;
 
   PRInt32 mIterOffset;
   nsCOMPtr<nsIDOMNode> mIterNode;
 
   // Last block parent, so that we will notice crossing block boundaries:
   nsCOMPtr<nsIDOMNode> mLastBlockParent;
   nsresult GetBlockParent(nsIDOMNode* aNode, nsIDOMNode** aParent);
 
--- a/gfx/thebes/Makefile.in
+++ b/gfx/thebes/Makefile.in
@@ -45,16 +45,18 @@ LIBRARY_NAME	= thebes
 LIBXUL_LIBRARY	= 1
 EXPORT_LIBRARY	= 1
 
 EXPORTS	= \
         gfx2DGlue.h \
 	gfx3DMatrix.h \
 	gfxASurface.h \
 	gfxAlphaRecovery.h \
+	gfxAtomList.h \
+	gfxAtoms.h \
 	gfxBlur.h \
 	gfxCachedTempSurface.h \
 	gfxColor.h \
 	gfxContext.h \
 	gfxDrawable.h \
 	gfxFailure.h \
 	gfxFont.h \
 	gfxFontConstants.h \
--- a/gfx/thebes/gfxAtomList.h
+++ b/gfx/thebes/gfxAtomList.h
@@ -90,8 +90,14 @@ GFX_ATOM(x_tibt, "x-tibt")
 
 // used in gfxGDIFontList.h
 GFX_ATOM(ko_xxx, "ko-xxx")
 GFX_ATOM(x_central_euro, "x-central-euro")
 GFX_ATOM(x_symbol, "x-symbol")
 
 // referenced in all.js
 GFX_ATOM(x_user_def, "x-user-def")
+
+// additional languages that use Turkish-style case transformation
+GFX_ATOM(az, "az")
+GFX_ATOM(ba, "ba")
+GFX_ATOM(crh, "crh")
+GFX_ATOM(tt, "tt")
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -244,16 +244,33 @@ gfxDWriteFontFamily::LocalizedName(nsASt
     hr = names->GetString(idx, famName.Elements(), length + 1);
     if (FAILED(hr)) {
         return;
     }
 
     aLocalizedName = nsDependentString(famName.Elements());
 }
 
+void
+gfxDWriteFontFamily::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                         FontListSizes*    aSizes) const
+{
+    gfxFontFamily::SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    // TODO:
+    // This doesn't currently account for |mDWFamily|
+}
+
+void
+gfxDWriteFontFamily::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                         FontListSizes*    aSizes) const
+{
+    aSizes->mFontListSize += aMallocSizeOf(this);
+    SizeOfExcludingThis(aMallocSizeOf, aSizes);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // gfxDWriteFontEntry
 
 gfxDWriteFontEntry::~gfxDWriteFontEntry()
 {
 }
 
 bool
@@ -372,17 +389,18 @@ gfxDWriteFontEntry::ReadCMAP()
         PRUint8 *cmap = buffer.Elements();
 
         bool          unicodeFont = false, symbolFont = false;
         rv = gfxFontUtils::ReadCMAP(cmap, buffer.Length(),
                                     mCharacterMap, mUVSOffset,
                                     unicodeFont, symbolFont);
 #ifdef PR_LOGGING
         LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d\n",
-                      NS_ConvertUTF16toUTF8(mName).get(), mCharacterMap.GetSize()));
+                      NS_ConvertUTF16toUTF8(mName).get(),
+                      mCharacterMap.SizeOfExcludingThis(moz_malloc_size_of)));
         if (LOG_CMAPDATA_ENABLED()) {
             char prefix[256];
             sprintf(prefix, "(cmapdata) name: %.220s",
                     NS_ConvertUTF16toUTF8(mName).get());
             mCharacterMap.Dump(prefix, eGfxLog_cmapdata);
         }
 #endif
         mHasCmapTable = NS_SUCCEEDED(rv);
@@ -419,17 +437,18 @@ gfxDWriteFontEntry::ReadCMAP()
                                     mUVSOffset,
                                     isUnicode,
                                     isSymbol);
     }
     fontFace->ReleaseFontTable(tableContext);
 
 #ifdef PR_LOGGING
     LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d\n",
-                  NS_ConvertUTF16toUTF8(mName).get(), mCharacterMap.GetSize()));
+                  NS_ConvertUTF16toUTF8(mName).get(),
+                  mCharacterMap.SizeOfExcludingThis(moz_malloc_size_of)));
     if (LOG_CMAPDATA_ENABLED()) {
         char prefix[256];
         sprintf(prefix, "(cmapdata) name: %.220s",
                 NS_ConvertUTF16toUTF8(mName).get());
         mCharacterMap.Dump(prefix, eGfxLog_cmapdata);
     }
 #endif
 
@@ -539,16 +558,33 @@ gfxDWriteFontEntry::IsCJKFont()
         if ((PRUint32(os2->codePageRange1) & CJK_CODEPAGE_BITS) != 0) {
             mIsCJK = true;
         }
     }
 
     return mIsCJK;
 }
 
+void
+gfxDWriteFontEntry::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                        FontListSizes*    aSizes) const
+{
+    gfxFontEntry::SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    // TODO:
+    // This doesn't currently account for the |mFont| and |mFontFile| members
+}
+
+void
+gfxDWriteFontEntry::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                        FontListSizes*    aSizes) const
+{
+    aSizes->mFontListSize += aMallocSizeOf(this);
+    SizeOfExcludingThis(aMallocSizeOf, aSizes);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // gfxDWriteFontList
 
 gfxDWriteFontList::gfxDWriteFontList()
     : mInitialized(false), mForceGDIClassicMaxFontSize(0.0)
 {
     mFontSubstitutes.Init();
 }
@@ -582,27 +618,26 @@ gfxDWriteFontList::GetDefaultFont(const 
 
     return nsnull;
 }
 
 gfxFontEntry *
 gfxDWriteFontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                    const nsAString& aFullname)
 {
-    bool found;
     gfxFontEntry *lookup;
 
     // initialize name lookup tables if needed
     if (!mFaceNamesInitialized) {
         InitFaceNameLists();
     }
 
     // lookup in name lookup tables, return null if not found
-    if (!(lookup = mPostscriptNames.GetWeak(aFullname, &found)) &&
-        !(lookup = mFullnames.GetWeak(aFullname, &found))) 
+    if (!(lookup = mPostscriptNames.GetWeak(aFullname)) &&
+        !(lookup = mFullnames.GetWeak(aFullname))) 
     {
         return nsnull;
     }
     gfxDWriteFontEntry* dwriteLookup = static_cast<gfxDWriteFontEntry*>(lookup);
     gfxDWriteFontEntry *fe =
         new gfxDWriteFontEntry(lookup->Name(),
                                dwriteLookup->mFont,
                                aProxyEntry->Weight(),
@@ -1177,29 +1212,55 @@ gfxDWriteFontList::ResolveFontName(const
     if (!mInitialized) {
         mInitialized = true;
         DelayedInitFontList();
     }
 
     nsAutoString keyName(aFontName);
     BuildKeyNameFromFontName(keyName);
 
-    nsRefPtr<gfxFontFamily> ff;
-    if (mFontSubstitutes.Get(keyName, &ff)) {
+    gfxFontFamily *ff = mFontSubstitutes.GetWeak(keyName);
+    if (ff) {
         aResolvedFontName = ff->Name();
         return true;
     }
 
     if (mNonExistingFonts.Contains(keyName)) {
         return false;
     }
 
     return gfxPlatformFontList::ResolveFontName(aFontName, aResolvedFontName);
 }
 
+void
+gfxDWriteFontList::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                       FontListSizes*    aSizes) const
+{
+    gfxPlatformFontList::SizeOfExcludingThis(aMallocSizeOf, aSizes);
+
+    aSizes->mFontListSize +=
+        mFontSubstitutes.SizeOfExcludingThis(SizeOfFamilyNameEntryExcludingThis,
+                                             aMallocSizeOf);
+
+    aSizes->mFontListSize +=
+        mNonExistingFonts.SizeOfExcludingThis(aMallocSizeOf);
+    for (PRUint32 i = 0; i < mNonExistingFonts.Length(); ++i) {
+        aSizes->mFontListSize +=
+            mNonExistingFonts[i].SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+    }
+}
+
+void
+gfxDWriteFontList::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                       FontListSizes*    aSizes) const
+{
+    aSizes->mFontListSize += aMallocSizeOf(this);
+    SizeOfExcludingThis(aMallocSizeOf, aSizes);
+}
+
 static nsresult GetFamilyName(IDWriteFont *aFont, nsString& aFamilyName)
 {
     HRESULT hr;
     nsRefPtr<IDWriteFontFamily> family;
 
     // clean out previous value
     aFamilyName.Truncate();
 
--- a/gfx/thebes/gfxDWriteFontList.h
+++ b/gfx/thebes/gfxDWriteFontList.h
@@ -74,16 +74,21 @@ public:
     virtual ~gfxDWriteFontFamily();
     
     virtual void FindStyleVariations();
 
     virtual void LocalizedName(nsAString& aLocalizedName);
 
     void SetForceGDIClassic(bool aForce) { mForceGDIClassic = aForce; }
 
+    virtual void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                     FontListSizes*    aSizes) const;
+    virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                     FontListSizes*    aSizes) const;
+
 protected:
     /** This font family's directwrite fontfamily object */
     nsRefPtr<IDWriteFontFamily> mDWFamily;
     bool mForceGDIClassic;
 };
 
 /**
  * \brief Class representing DirectWrite FontEntry (a unique font style/family)
@@ -174,16 +179,21 @@ public:
 
     nsresult ReadCMAP();
 
     bool IsCJKFont();
 
     void SetForceGDIClassic(bool aForce) { mForceGDIClassic = aForce; }
     bool GetForceGDIClassic() { return mForceGDIClassic; }
 
+    virtual void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                     FontListSizes*    aSizes) const;
+    virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                     FontListSizes*    aSizes) const;
+
 protected:
     friend class gfxDWriteFont;
     friend class gfxDWriteFontList;
 
     virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle,
                                         bool aNeedsBold);
     
     nsresult CreateFontFace(
@@ -375,16 +385,21 @@ public:
     bool UseGDIFontTableAccess() { return mGDIFontTableAccess; }
 
     virtual gfxFontFamily* FindFamily(const nsAString& aFamily);
 
     virtual void GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray);
 
     gfxFloat GetForceGDIClassicMaxFontSize() { return mForceGDIClassicMaxFontSize; }
 
+    virtual void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                     FontListSizes*    aSizes) const;
+    virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                     FontListSizes*    aSizes) const;
+
 private:
     friend class gfxDWriteFontFamily;
 
     nsresult GetFontSubstitutes();
 
     void GetDirectWriteSubstitutes();
 
     // search fonts system-wide for a given character, null otherwise
@@ -396,17 +411,17 @@ private:
     virtual bool UsesSystemFallback() { return true; }
 
     /**
      * Fonts listed in the registry as substitutes but for which no actual
      * font family is found.
      */
     nsTArray<nsString> mNonExistingFonts;
 
-    typedef nsDataHashtable<nsStringHashKey, nsRefPtr<gfxFontFamily> > FontTable;
+    typedef nsRefPtrHashtable<nsStringHashKey, gfxFontFamily> FontTable;
 
     /**
      * Table of font substitutes, we grab this from the registry to get
      * alternative font names.
      */
     FontTable mFontSubstitutes;
 
     bool mInitialized;
--- a/gfx/thebes/gfxFT2FontList.cpp
+++ b/gfx/thebes/gfxFT2FontList.cpp
@@ -384,16 +384,33 @@ FT2FontEntry::GetFontTable(PRUint32 aTab
     }
     PRUint8 *buf = aBuffer.Elements();
     status = FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, buf, &len);
     NS_ENSURE_TRUE(status == 0, NS_ERROR_FAILURE);
 
     return NS_OK;
 }
 
+void
+FT2FontEntry::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                  FontListSizes*    aSizes) const
+{
+    gfxFontEntry::SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    aSizes->mFontListSize +=
+        mFilename.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+}
+
+void
+FT2FontEntry::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                  FontListSizes*    aSizes) const
+{
+    aSizes->mFontListSize += aMallocSizeOf(this);
+    SizeOfExcludingThis(aMallocSizeOf, aSizes);
+}
+
 /*
  * FT2FontFamily
  * A standard gfxFontFamily; just adds a method used to support sending
  * the font list from chrome to content via IPC.
  */
 
 void
 FT2FontFamily::AddFacesToFontList(InfallibleTArray<FontListEntry>* aFontList)
--- a/gfx/thebes/gfxFT2FontList.h
+++ b/gfx/thebes/gfxFT2FontList.h
@@ -97,16 +97,21 @@ public:
                                         bool aNeedsBold);
 
     cairo_font_face_t *CairoFontFace();
     cairo_scaled_font_t *CreateScaledFont(const gfxFontStyle *aStyle);
 
     nsresult ReadCMAP();
     nsresult GetFontTable(PRUint32 aTableTag, FallibleTArray<PRUint8>& aBuffer);
 
+    virtual void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                     FontListSizes*    aSizes) const;
+    virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                     FontListSizes*    aSizes) const;
+
     FT_Face mFTFace;
     cairo_font_face_t *mFontFace;
 
     nsCString mFilename;
     PRUint8 mFTFontIndex;
 };
 
 class FT2FontFamily : public gfxFontFamily
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -267,16 +267,23 @@ public:
 
     // Disconnect from the HashEntry (because the blob has already been
     // removed from the hashtable).
     void ForgetHashEntry()
     {
         mHashEntry = nsnull;
     }
 
+    size_t SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const {
+        return mTableData.SizeOfExcludingThis(aMallocSizeOf);
+    }
+    size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const {
+        return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
+    }
+
 private:
     // The font table data block, owned (via adoption)
     FallibleTArray<PRUint8> mTableData;
     // The blob destroy function needs to know the hashtable entry,
     FontTableHashEntry *mHashEntry;
     // and the owning hashtable, so that it can remove the entry.
     nsTHashtable<FontTableHashEntry> *mHashtable;
 
@@ -396,16 +403,56 @@ void
 gfxFontEntry::CheckForGraphiteTables()
 {
     AutoFallibleTArray<PRUint8,16384> buffer;
     mHasGraphiteTables =
         NS_SUCCEEDED(GetFontTable(TRUETYPE_TAG('S','i','l','f'), buffer));
 }
 #endif
 
+/* static */ size_t
+gfxFontEntry::FontTableHashEntry::SizeOfEntryExcludingThis
+    (FontTableHashEntry *aEntry,
+     nsMallocSizeOfFun   aMallocSizeOf,
+     void*               aUserArg)
+{
+    FontListSizes *sizes = static_cast<FontListSizes*>(aUserArg);
+    if (aEntry->mBlob) {
+        sizes->mFontTableCacheSize += aMallocSizeOf(aEntry->mBlob);
+    }
+    if (aEntry->mSharedBlobData) {
+        sizes->mFontTableCacheSize +=
+            aEntry->mSharedBlobData->SizeOfIncludingThis(aMallocSizeOf);
+    }
+
+    // the size of the table is recorded in the FontListSizes record,
+    // so we return 0 here for the function result
+    return 0;
+}
+
+void
+gfxFontEntry::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                  FontListSizes*    aSizes) const
+{
+    aSizes->mFontListSize += mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+    aSizes->mCharMapsSize += mCharacterMap.SizeOfExcludingThis(aMallocSizeOf);
+    aSizes->mFontTableCacheSize +=
+        mFontTableCache.SizeOfExcludingThis(
+            FontTableHashEntry::SizeOfEntryExcludingThis,
+            aMallocSizeOf, aSizes);
+}
+
+void
+gfxFontEntry::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                  FontListSizes*    aSizes) const
+{
+    aSizes->mFontListSize += aMallocSizeOf(this);
+    SizeOfExcludingThis(aMallocSizeOf, aSizes);
+}
+
 //////////////////////////////////////////////////////////////////////////////
 //
 // class gfxFontFamily
 //
 //////////////////////////////////////////////////////////////////////////////
 
 // we consider faces with mStandardFace == true to be "greater than" those with false,
 // because during style matching, later entries will replace earlier ones
@@ -970,16 +1017,42 @@ gfxFontFamily::FindFont(const nsAString&
     for (PRUint32 i = 0; i < numFonts; i++) {
         gfxFontEntry *fe = mAvailableFonts[i].get();
         if (fe && fe->Name() == aPostscriptName)
             return fe;
     }
     return nsnull;
 }
 
+void
+gfxFontFamily::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                   FontListSizes*    aSizes) const
+{
+    aSizes->mFontListSize +=
+        mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+    aSizes->mCharMapsSize += mCharacterMap.SizeOfExcludingThis(aMallocSizeOf);
+
+    aSizes->mFontListSize +=
+        mAvailableFonts.SizeOfExcludingThis(aMallocSizeOf);
+    for (PRUint32 i = 0; i < mAvailableFonts.Length(); ++i) {
+        gfxFontEntry *fe = mAvailableFonts[i];
+        if (fe) {
+            fe->SizeOfIncludingThis(aMallocSizeOf, aSizes);
+        }
+    }
+}
+
+void
+gfxFontFamily::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                   FontListSizes*    aSizes) const
+{
+    aSizes->mFontListSize += aMallocSizeOf(this);
+    SizeOfExcludingThis(aMallocSizeOf, aSizes);
+}
+ 
 /*
  * gfxFontCache - global cache of gfxFont instances.
  * Expires unused fonts after a short interval;
  * notifies fonts to age their cached shaped-word records;
  * observes memory-pressure notification and tells fonts to clear their
  * shaped-word caches to free up memory.
  */
 
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -86,16 +86,18 @@ typedef struct _hb_blob_t hb_blob_t;
 
 // An OpenType feature tag and value pair
 struct THEBES_API gfxFontFeature {
     PRUint32 mTag; // see http://www.microsoft.com/typography/otspec/featuretags.htm
     PRUint32 mValue; // 0 = off, 1 = on, larger values may be used as parameters
                      // to features that select among multiple alternatives
 };
 
+struct FontListSizes;
+
 inline bool
 operator<(const gfxFontFeature& a, const gfxFontFeature& b)
 {
     return (a.mTag < b.mTag) || ((a.mTag == b.mTag) && (a.mValue < b.mValue));
 }
 
 inline bool
 operator==(const gfxFontFeature& a, const gfxFontFeature& b)
@@ -309,16 +311,22 @@ public:
     // reference is owned by the caller.  Removing the last reference
     // unregisters the table from the font entry.
     //
     // Pass NULL for aBuffer to indicate that the table is not present and
     // NULL will be returned.  Also returns NULL on OOM.
     hb_blob_t *ShareFontTableAndGetBlob(PRUint32 aTag,
                                         FallibleTArray<PRUint8>* aTable);
 
+    // For memory reporting
+    virtual void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                     FontListSizes*    aSizes) const;
+    virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                     FontListSizes*    aSizes) const;
+
     nsString         mName;
 
     bool             mItalic      : 1;
     bool             mFixedPitch  : 1;
     bool             mIsProxy     : 1;
     bool             mIsValid     : 1;
     bool             mIsBadUnderlineFont : 1;
     bool             mIsUserFont  : 1;
@@ -463,16 +471,21 @@ private:
         void SaveTable(FallibleTArray<PRUint8>& aTable);
 
         // Return a strong reference to the blob.
         // Callers must hb_blob_destroy the returned blob.
         hb_blob_t *GetBlob() const;
 
         void Clear();
 
+        static size_t
+        SizeOfEntryExcludingThis(FontTableHashEntry *aEntry,
+                                 nsMallocSizeOfFun   aMallocSizeOf,
+                                 void*               aUserArg);
+
     private:
         static void DeleteFontTableBlobData(void *aBlobData);
         // not implemented
         FontTableHashEntry& operator=(FontTableHashEntry& toCopy);
 
         FontTableBlobData *mSharedBlobData;
         hb_blob_t *mBlob;
     };
@@ -629,16 +642,22 @@ public:
     // sort available fonts to put preferred (standard) faces towards the end
     void SortAvailableFonts();
 
     // check whether the family fits into the simple 4-face model,
     // so we can use simplified style-matching;
     // if so set the mIsSimpleFamily flag (defaults to False before we've checked)
     void CheckForSimpleFamily();
 
+    // For memory reporter
+    virtual void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                     FontListSizes*    aSizes) const;
+    virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                     FontListSizes*    aSizes) const;
+
 protected:
     // fills in an array with weights of faces that match style,
     // returns whether any matching entries found
     virtual bool FindWeightsForStyle(gfxFontEntry* aFontsForWeights[],
                                        bool anItalic, PRInt16 aStretch);
 
     bool ReadOtherFamilyNamesForFace(gfxPlatformFontList *aPlatformFontList,
                                        FallibleTArray<PRUint8>& aNameTable,
--- a/gfx/thebes/gfxFontUtils.h
+++ b/gfx/thebes/gfxFontUtils.h
@@ -259,24 +259,28 @@ public:
             const PRUint32 end = NS_MIN<PRUint32>(aEnd - blockFirstBit, BLOCK_SIZE_BITS - 1);
 
             for (PRUint32 bit = start; bit <= end; ++bit) {
                 block->mBits[bit>>3] &= ~(1 << (bit & 0x7));
             }
         }
     }
 
-    PRUint32 GetSize() {
-        PRUint32 size = 0;
+    size_t SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const {
+        size_t total = mBlocks.SizeOfExcludingThis(aMallocSizeOf);
         for (PRUint32 i = 0; i < mBlocks.Length(); i++) {
-            if (mBlocks[i])
-                size += sizeof(Block);
-            size += sizeof(nsAutoPtr<Block>);
+            if (mBlocks[i]) {
+                total += aMallocSizeOf(mBlocks[i]);
+            }
         }
-        return size;
+        return total;
+    }
+
+    size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const {
+        return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
     }
 
     // clear out all blocks in the array
     void reset() {
         PRUint32 i;
         for (i = 0; i < mBlocks.Length(); i++)
             mBlocks[i] = nsnull;    
     }
--- a/gfx/thebes/gfxGDIFontList.cpp
+++ b/gfx/thebes/gfxGDIFontList.cpp
@@ -241,17 +241,18 @@ GDIFontEntry::ReadCMAP()
     nsresult rv = gfxFontUtils::ReadCMAP(cmap, buffer.Length(),
                                          mCharacterMap, mUVSOffset,
                                          unicodeFont, symbolFont);
     mSymbolFont = symbolFont;
     mHasCmapTable = NS_SUCCEEDED(rv);
 
 #ifdef PR_LOGGING
     LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d\n",
-                  NS_ConvertUTF16toUTF8(mName).get(), mCharacterMap.GetSize()));
+                  NS_ConvertUTF16toUTF8(mName).get(),
+                  mCharacterMap.SizeOfExcludingThis(moz_malloc_size_of)));
     if (LOG_CMAPDATA_ENABLED()) {
         char prefix[256];
         sprintf(prefix, "(cmapdata) name: %.220s",
                 NS_ConvertUTF16toUTF8(mName).get());
         mCharacterMap.Dump(prefix, eGfxLog_cmapdata);
     }
 #endif
     return rv;
@@ -454,16 +455,24 @@ GDIFontEntry::CreateFontEntry(const nsAS
     // jtdfix - need to set charset, unicode ranges, pitch/family
 
     GDIFontEntry *fe = new GDIFontEntry(aName, aFontType, aItalic,
                                         aWeight, aStretch, aUserFontData);
 
     return fe;
 }
 
+void
+GDIFontEntry::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                  FontListSizes*    aSizes) const
+{
+    aSizes->mFontListSize += aMallocSizeOf(this);
+    SizeOfExcludingThis(aMallocSizeOf, aSizes);
+}
+
 /***************************************************************
  *
  * GDIFontFamily
  *
  */
 
 int CALLBACK
 GDIFontFamily::FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
@@ -653,17 +662,17 @@ gfxGDIFontList::GetFontSubstitutes()
     }
 
     // "Courier" on a default Windows install is an ugly bitmap font.
     // If there is no substitution for Courier in the registry
     // substitute "Courier" with "Courier New".
     nsAutoString substituteName;
     substituteName.AssignLiteral("Courier");
     BuildKeyNameFromFontName(substituteName);
-    if (!mFontSubstitutes.Get(substituteName)) {
+    if (!mFontSubstitutes.GetWeak(substituteName)) {
         gfxFontFamily *ff;
         nsAutoString actualFontName;
         actualFontName.AssignLiteral("Courier New");
         BuildKeyNameFromFontName(actualFontName);
         ff = mFontFamilies.GetWeak(actualFontName);
         if (ff) {
             mFontSubstitutes.Put(substituteName, ff);
         }
@@ -738,27 +747,26 @@ gfxGDIFontList::EnumFontFamExProc(ENUMLO
 
     return 1;
 }
 
 gfxFontEntry* 
 gfxGDIFontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                 const nsAString& aFullname)
 {
-    bool found;
     gfxFontEntry *lookup;
 
     // initialize name lookup tables if needed
     if (!mFaceNamesInitialized) {
         InitFaceNameLists();
     }
 
     // lookup in name lookup tables, return null if not found
-    if (!(lookup = mPostscriptNames.GetWeak(aFullname, &found)) &&
-        !(lookup = mFullnames.GetWeak(aFullname, &found))) 
+    if (!(lookup = mPostscriptNames.GetWeak(aFullname)) &&
+        !(lookup = mFullnames.GetWeak(aFullname))) 
     {
         return nsnull;
     }
 
     // create a new font entry with the proxy entry style characteristics
     PRUint16 w = (aProxyEntry->mWeight == 0 ? 400 : aProxyEntry->mWeight);
     bool isCFF = false; // jtdfix -- need to determine this
     
@@ -1033,22 +1041,46 @@ gfxGDIFontList::GetDefaultFont(const gfx
 
 
 bool 
 gfxGDIFontList::ResolveFontName(const nsAString& aFontName, nsAString& aResolvedFontName)
 {
     nsAutoString keyName(aFontName);
     BuildKeyNameFromFontName(keyName);
 
-    nsRefPtr<gfxFontFamily> ff;
-    if (mFontSubstitutes.Get(keyName, &ff)) {
+    gfxFontFamily *ff = mFontSubstitutes.GetWeak(keyName);
+    if (ff) {
         aResolvedFontName = ff->Name();
         return true;
     }
 
     if (mNonExistingFonts.Contains(keyName))
         return false;
 
     if (gfxPlatformFontList::ResolveFontName(aFontName, aResolvedFontName))
         return true;
 
     return false;
 }
+
+void
+gfxGDIFontList::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                    FontListSizes*    aSizes) const
+{
+    gfxPlatformFontList::SizeOfExcludingThis(aMallocSizeOf, aSizes);
+    aSizes->mFontListSize +=
+        mFontSubstitutes.SizeOfExcludingThis(SizeOfFamilyNameEntryExcludingThis,
+                                             aMallocSizeOf);
+    aSizes->mFontListSize +=
+        mNonExistingFonts.SizeOfExcludingThis(aMallocSizeOf);
+    for (PRUint32 i = 0; i < mNonExistingFonts.Length(); ++i) {
+        aSizes->mFontListSize +=
+            mNonExistingFonts[i].SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+    }
+}
+
+void
+gfxGDIFontList::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                    FontListSizes*    aSizes) const
+{
+    aSizes->mFontListSize += aMallocSizeOf(this);
+    SizeOfExcludingThis(aMallocSizeOf, aSizes);
+}
--- a/gfx/thebes/gfxGDIFontList.h
+++ b/gfx/thebes/gfxGDIFontList.h
@@ -269,16 +269,19 @@ public:
     }
 
     virtual bool SkipDuringSystemFallback() { 
         return !HasCmapTable(); // explicitly skip non-SFNT fonts
     }
 
     virtual bool TestCharacterMap(PRUint32 aCh);
 
+    virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                     FontListSizes*    aSizes) const;
+
     // create a font entry for a font with a given name
     static GDIFontEntry* CreateFontEntry(const nsAString& aName,
                                          gfxWindowsFontType aFontType,
                                          bool aItalic,
                                          PRUint16 aWeight, PRInt16 aStretch,
                                          gfxUserFontData* aUserFontData);
 
     // create a font entry for a font referenced by its fullname
@@ -342,29 +345,34 @@ public:
                                           const nsAString& aFontName);
 
     virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
                                            const PRUint8 *aFontData, PRUint32 aLength);
 
<