Merge from mozilla-central (yay method barrier removal).
authorDavid Anderson <danderson@mozilla.com>
Wed, 28 Mar 2012 13:46:36 -0700
changeset 109654 ab92bf1f7deadc2e04077a80505b687f589cc68e
parent 109653 15da4376607bdd326e62c68d42f1831ba10007df (current diff)
parent 92314 c3fd0768d46abdb77d0e51d4bcb52d5adf4d0445 (diff)
child 109655 9d13b69838c201fe7e2abaaff9ae7319d24a08a7
push id2248
push userakeybl@mozilla.com
push dateMon, 08 Oct 2012 19:23:44 +0000
treeherdermozilla-aurora@118a3b748323 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone14.0a1
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);
 
     virtual bool ResolveFontName(const nsAString& aFontName,
                                    nsAString& aResolvedFontName);
 
+    virtual void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                     FontListSizes*    aSizes) const;
+    virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                     FontListSizes*    aSizes) const;
+
 private:
     friend class gfxWindowsPlatform;
 
     gfxGDIFontList();
 
     void InitializeFontEmbeddingProcs();
 
     nsresult GetFontSubstitutes();
 
     static int CALLBACK EnumFontFamExProc(ENUMLOGFONTEXW *lpelfe,
                                           NEWTEXTMETRICEXW *lpntme,
                                           DWORD fontType,
                                           LPARAM lParam);
 
-    typedef nsDataHashtable<nsStringHashKey, nsRefPtr<gfxFontFamily> > FontTable;
+    typedef nsRefPtrHashtable<nsStringHashKey, gfxFontFamily> FontTable;
 
     FontTable mFontSubstitutes;
     nsTArray<nsString> mNonExistingFonts;
 };
 
 #endif /* GFX_GDIFONTLIST_H */
--- a/gfx/thebes/gfxMacPlatformFontList.h
+++ b/gfx/thebes/gfxMacPlatformFontList.h
@@ -106,16 +106,19 @@ public:
 
     ATSFontRef GetATSFontRef();
 
     virtual CGFontRef GetFontRef();
 
     virtual nsresult GetFontTable(PRUint32 aTableTag,
                                   FallibleTArray<PRUint8>& aBuffer);
 
+    virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                     FontListSizes*    aSizes) const;
+
 protected:
     virtual bool HasFontTable(PRUint32 aTableTag);
 
     ATSFontRef   mATSFontRef;
     bool mATSFontRefInitialized;
 };
 
 class CGFontEntry : public MacOSFontEntry
@@ -129,16 +132,19 @@ public:
                 PRUint16 aWeight, PRUint16 aStretch, PRUint32 aItalicStyle,
                 bool aIsUserFont, bool aIsLocal);
 
     virtual CGFontRef GetFontRef();
 
     virtual nsresult GetFontTable(PRUint32 aTableTag,
                                   FallibleTArray<PRUint8>& aBuffer);
 
+    virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
+                                     FontListSizes*    aSizes) const;
+
 protected:
     virtual bool HasFontTable(PRUint32 aTableTag);
 };
 
 class gfxMacPlatformFontList : public gfxPlatformFontList {
 public:
     static gfxMacPlatformFontList* PlatformFontList() {
         return static_cast<gfxMacPlatformFontList*>(sPlatformFontList);
--- a/gfx/thebes/gfxMacPlatformFontList.mm
+++ b/gfx/thebes/gfxMacPlatformFontList.mm
@@ -265,17 +265,17 @@ MacOSFontEntry::ReadCMAP()
                                          gScriptsThatRequireShaping[s].rangeEnd);
             }
         }
     }
 
 #ifdef PR_LOGGING
     LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d\n",
                   NS_ConvertUTF16toUTF8(mName).get(),
-                  mCharacterMap.GetSize()));
+                  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