Merge m-c to b2g-inbound.
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 04 Nov 2013 16:32:13 -0500
changeset 153512 7e42fe7d6e463c3410921a6cd4244b98edee9909
parent 153511 2f2ed7cd726b78f51e5ee192277a610b384d3484 (current diff)
parent 153424 7d298c4380ad7e0f65c421a7ae6345bfb7a3f3f5 (diff)
child 153513 c0593c024b1c1e1aec398419b7b0ecc69b1e0cd1
push id35816
push userkwierso@gmail.com
push dateTue, 05 Nov 2013 05:22:53 +0000
treeherdermozilla-inbound@442b47e9fb80 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone28.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to b2g-inbound.
js/src/devtools/rootAnalysis/expect.json
layout/generic/nsTextFrameTextRunCache.h
--- a/CLOBBER
+++ b/CLOBBER
@@ -13,9 +13,9 @@
 #          |               |
 #          O <-- Clobber   O  <-- Clobber
 #
 # Note: The description below will be part of the error message shown to users.
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
-Bug 933120 needs a clobber because of bug 852814
+Bug 906990 needs a clobber because of bug 928195
--- a/accessible/public/nsIAccessibleSelectable.idl
+++ b/accessible/public/nsIAccessibleSelectable.idl
@@ -1,72 +1,64 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 #include "nsISupports.idl"
-#include "nsIAccessible.idl"
-#include "nsIArray.idl"
+
+interface nsIAccessible;
+interface nsIArray;
 
 /**
- * An interface for the accessibility module and in-process accessibility clients
- * for dealing with getting and changing the selection of accessible nodes.
+ * An accessibility interface for selectable widgets.
  */
-[scriptable, uuid(34d268d6-1dd2-11b2-9d63-83a5e0ada290)]
+[scriptable, uuid(3e507fc4-4fcc-4223-a674-a095f591eba1)]
 interface nsIAccessibleSelectable : nsISupports
 {
-    const unsigned long eSelection_Add = 0;
-    const unsigned long eSelection_Remove = 1;
-    const unsigned long eSelection_GetState = 2;
+  /**
+   * Return an nsIArray of selected items within the widget.
+   */
+  readonly attribute nsIArray selectedItems;
 
-    /**
-     * Return an nsIArray of selected nsIAccessible children 
-     */
-    nsIArray GetSelectedChildren();
-    
-    /**
-     * Returns the number of accessible children currently selected.
-     */
-    readonly attribute long selectionCount;
+  /**
+   * Return the number of currently selected items.
+   */
+  readonly attribute unsigned long selectedItemCount;
 
-    /**
-     * Adds the specified accessible child of the object to the
-     * object's selection.
-     * If the specified object is already selected, then it does nothing.
-     * @throws NS_ERROR_FAILURE if the specified object is not selectable.
-     */
-    void addChildToSelection(in long index);
+  /**
+   * Return a nth selected item within the widget.
+   */
+  nsIAccessible getSelectedItemAt(in unsigned long index);
 
-    /**
-     * Removes the specified child of the object from the object's selection.
-     * If the specified object was not selected, then it does nothing.
-     * @throws NS_ERROR_FAILURE if the specified object is not selectable.
-     */
-    void removeChildFromSelection(in long index);
+  /**
+   * Return true if the given item is selected.
+   */
+  [binaryname(ScriptableIsItemSelected)]
+  boolean isItemSelected(in unsigned long index);
 
-    /**
-     * Clears the selection in the object so that no children in the object
-     * are selected.
-     */
-    void clearSelection();
+  /**
+   * Adds the specified item to the widget's selection.
+   */
+  [binaryname(ScriptableAddItemToSelection)]
+  void addItemToSelection(in unsigned long index);
 
-    /**
-     * Returns a reference to the accessible object representing the specified
-     * selected child of the object.
-     * @param index Zero-based selected accessible child index 
-     * @return The nth selected accessible child
-     */
-    nsIAccessible refSelection(in long index);
+  /**
+   * Removes the specified item from the widget's selection.
+   */
+  [binaryname(ScriptableRemoveItemFromSelection)]
+  void removeItemFromSelection(in unsigned long index);
 
-    /**
-      * Determines if the current child of this object is selected
-      * @param The zero-based accessible child index
-      * @return Returns true if the child is selected, false if not.
-      */
-    boolean isChildSelected(in long index);
+  /**
+   * Select all items.
+   *
+   * @return false if the object does not accept multiple selection,
+   *         otherwise true.
+   */
+  [binaryname(ScriptableSelectAll)]
+  boolean selectAll();
 
-    /**
-     * Select all children
-     * @return If the object does not accept multiple selection, return false.
-     *         Otherwise, returns true.
-     */
-    boolean selectAllSelection();
+  /**
+   * Unselect all items.
+   */
+  [binaryname(ScriptableUnselectAll)]
+  void unselectAll();
 };
--- a/accessible/src/generic/Accessible.cpp
+++ b/accessible/src/generic/Accessible.cpp
@@ -1008,17 +1008,17 @@ NS_IMETHODIMP
 Accessible::TakeSelection()
 {
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
   Accessible* select = nsAccUtils::GetSelectableContainer(this, State());
   if (select) {
     if (select->State() & states::MULTISELECTABLE)
-      select->ClearSelection();
+      select->UnselectAll();
     return SetSelected(true);
   }
 
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 Accessible::TakeFocus()
@@ -2327,128 +2327,16 @@ Accessible::ScrollToPoint(uint32_t aCoor
 
   nsIFrame *parentFrame = frame;
   while ((parentFrame = parentFrame->GetParent()))
     nsCoreUtils::ScrollFrameToPoint(parentFrame, frame, coords);
 
   return NS_OK;
 }
 
-// nsIAccessibleSelectable
-NS_IMETHODIMP
-Accessible::GetSelectedChildren(nsIArray** aSelectedAccessibles)
-{
-  NS_ENSURE_ARG_POINTER(aSelectedAccessibles);
-  *aSelectedAccessibles = nullptr;
-
-  if (IsDefunct() || !IsSelect())
-    return NS_ERROR_FAILURE;
-
-  nsCOMPtr<nsIArray> items = SelectedItems();
-  if (items) {
-    uint32_t length = 0;
-    items->GetLength(&length);
-    if (length)
-      items.swap(*aSelectedAccessibles);
-  }
-
-  return NS_OK;
-}
-
-// return the nth selected descendant nsIAccessible object
-NS_IMETHODIMP
-Accessible::RefSelection(int32_t aIndex, nsIAccessible** aSelected)
-{
-  NS_ENSURE_ARG_POINTER(aSelected);
-  *aSelected = nullptr;
-
-  if (IsDefunct() || !IsSelect())
-    return NS_ERROR_FAILURE;
-
-  if (aIndex < 0) {
-    return NS_ERROR_INVALID_ARG;
-  }
-
-  *aSelected = GetSelectedItem(aIndex);
-  if (*aSelected) {
-    NS_ADDREF(*aSelected);
-    return NS_OK;
-  }
-
-  return NS_ERROR_INVALID_ARG;
-}
-
-NS_IMETHODIMP
-Accessible::GetSelectionCount(int32_t* aSelectionCount)
-{
-  NS_ENSURE_ARG_POINTER(aSelectionCount);
-  *aSelectionCount = 0;
-
-  if (IsDefunct() || !IsSelect())
-    return NS_ERROR_FAILURE;
-
-  *aSelectionCount = SelectedItemCount();
-  return NS_OK;
-}
-
-NS_IMETHODIMP Accessible::AddChildToSelection(int32_t aIndex)
-{
-  if (IsDefunct() || !IsSelect())
-    return NS_ERROR_FAILURE;
-
-  return aIndex >= 0 && AddItemToSelection(aIndex) ?
-    NS_OK : NS_ERROR_INVALID_ARG;
-}
-
-NS_IMETHODIMP Accessible::RemoveChildFromSelection(int32_t aIndex)
-{
-  if (IsDefunct() || !IsSelect())
-    return NS_ERROR_FAILURE;
-
-  return aIndex >=0 && RemoveItemFromSelection(aIndex) ?
-    NS_OK : NS_ERROR_INVALID_ARG;
-}
-
-NS_IMETHODIMP Accessible::IsChildSelected(int32_t aIndex, bool *aIsSelected)
-{
-  NS_ENSURE_ARG_POINTER(aIsSelected);
-  *aIsSelected = false;
-
-  if (IsDefunct() || !IsSelect())
-    return NS_ERROR_FAILURE;
-
-  NS_ENSURE_TRUE(aIndex >= 0, NS_ERROR_FAILURE);
-
-  *aIsSelected = IsItemSelected(aIndex);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-Accessible::ClearSelection()
-{
-  if (IsDefunct() || !IsSelect())
-    return NS_ERROR_FAILURE;
-
-  UnselectAll();
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-Accessible::SelectAllSelection(bool* aIsMultiSelect)
-{
-  NS_ENSURE_ARG_POINTER(aIsMultiSelect);
-  *aIsMultiSelect = false;
-
-  if (IsDefunct() || !IsSelect())
-    return NS_ERROR_FAILURE;
-
-  *aIsMultiSelect = SelectAll();
-  return NS_OK;
-}
-
 // nsIAccessibleHyperLink
 // Because of new-atk design, any embedded object in text can implement
 // nsIAccessibleHyperLink, which helps determine where it is located
 // within containing text
 
 // readonly attribute long nsIAccessibleHyperLink::anchorCount
 NS_IMETHODIMP
 Accessible::GetAnchorCount(int32_t *aAnchorCount)
--- a/accessible/src/generic/Accessible.h
+++ b/accessible/src/generic/Accessible.h
@@ -8,19 +8,19 @@
 
 #include "mozilla/a11y/AccTypes.h"
 #include "mozilla/a11y/RelationType.h"
 #include "mozilla/a11y/Role.h"
 #include "mozilla/a11y/States.h"
 
 #include "nsIAccessible.h"
 #include "nsIAccessibleHyperLink.h"
-#include "nsIAccessibleSelectable.h"
 #include "nsIAccessibleValue.h"
 #include "nsIAccessibleStates.h"
+#include "xpcAccessibleSelectable.h"
 
 #include "nsIContent.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsRefPtrHashtable.h"
 
 struct nsRoleMapEntry;
 
@@ -99,29 +99,28 @@ typedef nsRefPtrHashtable<nsPtrHashKey<c
   0x133c8bf4,                                           \
   0x4913,                                               \
   0x4355,                                               \
   { 0xbd, 0x50, 0x42, 0x6b, 0xd1, 0xd6, 0xe1, 0xad }    \
 }
 
 class Accessible : public nsIAccessible,
                    public nsIAccessibleHyperLink,
-                   public nsIAccessibleSelectable,
+                   public xpcAccessibleSelectable,
                    public nsIAccessibleValue
 {
 public:
   Accessible(nsIContent* aContent, DocAccessible* aDoc);
   virtual ~Accessible();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(Accessible, nsIAccessible)
 
   NS_DECL_NSIACCESSIBLE
   NS_DECL_NSIACCESSIBLEHYPERLINK
-  NS_DECL_NSIACCESSIBLESELECTABLE
   NS_DECL_NSIACCESSIBLEVALUE
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ACCESSIBLE_IMPL_IID)
 
   //////////////////////////////////////////////////////////////////////////////
   // Public methods
 
   /**
    * Return the document accessible for this accessible.
--- a/accessible/src/xpcom/moz.build
+++ b/accessible/src/xpcom/moz.build
@@ -1,18 +1,23 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 MODULE = 'accessibility'
 
+EXPORTS += [
+    'xpcAccessibleSelectable.h',
+]
+
 SOURCES += [
     'nsAccessibleRelation.cpp',
+    'xpcAccessibleSelectable.cpp',
     'xpcAccessibleTable.cpp',
     'xpcAccessibleTableCell.cpp',
 ]
 
 GENERATED_SOURCES += [
     'xpcAccEvents.cpp',
 ]
 
new file mode 100644
--- /dev/null
+++ b/accessible/src/xpcom/xpcAccessibleSelectable.cpp
@@ -0,0 +1,134 @@
+/* -*- 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 "xpcAccessibleSelectable.h"
+
+#include "Accessible-inl.h"
+
+using namespace mozilla::a11y;
+
+NS_IMETHODIMP
+xpcAccessibleSelectable::GetSelectedItems(nsIArray** aSelectedItems)
+{
+  NS_ENSURE_ARG_POINTER(aSelectedItems);
+  *aSelectedItems = nullptr;
+
+  Accessible* acc = static_cast<Accessible*>(this);
+  if (acc->IsDefunct())
+    return NS_ERROR_FAILURE;
+  NS_PRECONDITION(acc->IsSelect(), "Called on non selectable widget!");
+
+  nsCOMPtr<nsIArray> items = acc->SelectedItems();
+  if (items) {
+    uint32_t length = 0;
+    items->GetLength(&length);
+    if (length)
+      items.swap(*aSelectedItems);
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+xpcAccessibleSelectable::GetSelectedItemCount(uint32_t* aSelectionCount)
+{
+  NS_ENSURE_ARG_POINTER(aSelectionCount);
+  *aSelectionCount = 0;
+
+  Accessible* acc = static_cast<Accessible*>(this);
+  if (acc->IsDefunct())
+    return NS_ERROR_FAILURE;
+  NS_PRECONDITION(acc->IsSelect(), "Called on non selectable widget!");
+
+  *aSelectionCount = acc->SelectedItemCount();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+xpcAccessibleSelectable::GetSelectedItemAt(uint32_t aIndex,
+                                           nsIAccessible** aSelected)
+{
+  NS_ENSURE_ARG_POINTER(aSelected);
+  *aSelected = nullptr;
+
+  Accessible* acc = static_cast<Accessible*>(this);
+  if (acc->IsDefunct())
+    return NS_ERROR_FAILURE;
+  NS_PRECONDITION(acc->IsSelect(), "Called on non selectable widget!");
+
+  *aSelected = acc->GetSelectedItem(aIndex);
+  if (*aSelected) {
+    NS_ADDREF(*aSelected);
+    return NS_OK;
+  }
+
+  return NS_ERROR_INVALID_ARG;
+}
+
+NS_IMETHODIMP
+xpcAccessibleSelectable::ScriptableIsItemSelected(uint32_t aIndex,
+                                                  bool* aIsSelected)
+{
+  NS_ENSURE_ARG_POINTER(aIsSelected);
+  *aIsSelected = false;
+
+  Accessible* acc = static_cast<Accessible*>(this);
+  if (acc->IsDefunct())
+    return NS_ERROR_FAILURE;
+  NS_PRECONDITION(acc->IsSelect(), "Called on non selectable widget!");
+
+  *aIsSelected = acc->IsItemSelected(aIndex);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+xpcAccessibleSelectable::ScriptableAddItemToSelection(uint32_t aIndex)
+{
+  Accessible* acc = static_cast<Accessible*>(this);
+  if (acc->IsDefunct())
+    return NS_ERROR_FAILURE;
+  NS_PRECONDITION(acc->IsSelect(), "Called on non selectable widget!");
+
+  return acc->AddItemToSelection(aIndex) ? NS_OK : NS_ERROR_INVALID_ARG;
+}
+
+NS_IMETHODIMP
+xpcAccessibleSelectable::ScriptableRemoveItemFromSelection(uint32_t aIndex)
+{
+  Accessible* acc = static_cast<Accessible*>(this);
+  if (acc->IsDefunct())
+    return NS_ERROR_FAILURE;
+  NS_PRECONDITION(acc->IsSelect(), "Called on non selectable widget!");
+
+  return acc->RemoveItemFromSelection(aIndex) ? NS_OK : NS_ERROR_INVALID_ARG;
+}
+
+NS_IMETHODIMP
+xpcAccessibleSelectable::ScriptableSelectAll(bool* aIsMultiSelect)
+{
+  NS_ENSURE_ARG_POINTER(aIsMultiSelect);
+  *aIsMultiSelect = false;
+
+  Accessible* acc = static_cast<Accessible*>(this);
+  if (acc->IsDefunct())
+    return NS_ERROR_FAILURE;
+  NS_PRECONDITION(acc->IsSelect(), "Called on non selectable widget!");
+
+  *aIsMultiSelect = acc->SelectAll();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+xpcAccessibleSelectable::ScriptableUnselectAll()
+{
+  Accessible* acc = static_cast<Accessible*>(this);
+  if (acc->IsDefunct())
+    return NS_ERROR_FAILURE;
+  NS_PRECONDITION(acc->IsSelect(), "Called on non selectable widget!");
+
+  acc->UnselectAll();
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/accessible/src/xpcom/xpcAccessibleSelectable.h
@@ -0,0 +1,41 @@
+/* -*- 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_xpcAccessibleSelectable_h_
+#define mozilla_a11y_xpcAccessibleSelectable_h_
+
+#include "nsIAccessibleSelectable.h"
+
+class nsIAccessible;
+class nsIArray;
+
+namespace mozilla {
+namespace a11y {
+
+class xpcAccessibleSelectable : public nsIAccessibleSelectable
+{
+public:
+  NS_IMETHOD GetSelectedItems(nsIArray** aSelectedItems) MOZ_FINAL;
+  NS_IMETHOD GetSelectedItemCount(uint32_t* aSelectedItemCount) MOZ_FINAL;
+  NS_IMETHOD GetSelectedItemAt(uint32_t aIndex, nsIAccessible** aItem) MOZ_FINAL;
+  NS_IMETHOD ScriptableIsItemSelected(uint32_t aIndex, bool* aIsSelected) MOZ_FINAL;
+  NS_IMETHOD ScriptableAddItemToSelection(uint32_t aIndex) MOZ_FINAL;
+  NS_IMETHOD ScriptableRemoveItemFromSelection(uint32_t aIndex) MOZ_FINAL;
+  NS_IMETHOD ScriptableSelectAll(bool* aIsMultiSelect) MOZ_FINAL;
+  NS_IMETHOD ScriptableUnselectAll() MOZ_FINAL;
+
+private:
+  xpcAccessibleSelectable() { }
+  friend class Accessible;
+
+  xpcAccessibleSelectable(const xpcAccessibleSelectable&) MOZ_DELETE;
+  xpcAccessibleSelectable& operator =(const xpcAccessibleSelectable&) MOZ_DELETE;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
--- a/accessible/src/xul/XULTreeGridAccessible.cpp
+++ b/accessible/src/xul/XULTreeGridAccessible.cpp
@@ -56,31 +56,24 @@ XULTreeGridAccessible::SelectedCellCount
 }
 
 uint32_t
 XULTreeGridAccessible::SelectedColCount()
 {
   // If all the row has been selected, then all the columns are selected,
   // because we can't select a column alone.
 
-  int32_t selectedRowCount = 0;
-  nsresult rv = GetSelectionCount(&selectedRowCount);
-  NS_ENSURE_SUCCESS(rv, 0);
-
+  uint32_t selectedRowCount = SelectedItemCount();
   return selectedRowCount > 0 && selectedRowCount == RowCount() ? ColCount() : 0;
 }
 
 uint32_t
 XULTreeGridAccessible::SelectedRowCount()
 {
-  int32_t selectedRowCount = 0;
-  nsresult rv = GetSelectionCount(&selectedRowCount);
-  NS_ENSURE_SUCCESS(rv, 0);
-
-  return selectedRowCount >= 0 ? selectedRowCount : 0;
+  return SelectedItemCount();
 }
 
 void
 XULTreeGridAccessible::SelectedCells(nsTArray<Accessible*>* aCells)
 {
   uint32_t colCount = ColCount(), rowCount = RowCount();
 
   for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
@@ -159,22 +152,17 @@ XULTreeGridAccessible::ColDescription(ui
   }
 }
 
 bool
 XULTreeGridAccessible::IsColSelected(uint32_t aColIdx)
 {
   // If all the row has been selected, then all the columns are selected.
   // Because we can't select a column alone.
-
-  int32_t selectedrowCount = 0;
-  nsresult rv = GetSelectionCount(&selectedrowCount);
-  NS_ENSURE_SUCCESS(rv, false);
-
-  return selectedrowCount == RowCount();
+  return SelectedItemCount() == RowCount();
 }
 
 bool
 XULTreeGridAccessible::IsRowSelected(uint32_t aRowIdx)
 {
   if (!mTreeView)
     return false;
 
--- a/accessible/tests/mochitest/selectable.js
+++ b/accessible/tests/mochitest/selectable.js
@@ -9,74 +9,72 @@ function testSelectableSelection(aIdenti
   var acc = getAccessible(aIdentifier, [nsIAccessibleSelectable]);
   if (!acc)
     return;
 
   var msg = aMsg ? aMsg : "";
   var len = aSelectedChildren.length;
 
   // getSelectedChildren
-  var selectedChildren = acc.GetSelectedChildren();
+  var selectedChildren = acc.selectedItems;
   is(selectedChildren ? selectedChildren.length : 0, len,
      msg + "getSelectedChildren: wrong selected children count for " +
      prettyName(aIdentifier));
 
   for (var idx = 0; idx < len; idx++) {
     var expectedAcc = getAccessible(aSelectedChildren[idx]);
     var actualAcc = selectedChildren.queryElementAt(idx, nsIAccessible);
     is(actualAcc, expectedAcc,
        msg + "getSelectedChildren: wrong selected child at index " + idx +
        " for " + prettyName(aIdentifier) + " { actual : " +
        prettyName(actualAcc) + ", expected: " + prettyName(expectedAcc) + "}");
   }
 
-  // selectionCount
-  // XXX: nsIAccessibleText and nsIAccessibleSelectable both have
-  // selectionCount property.
-  //is(acc.selectionCount, aSelectedChildren.length,
-  //   "selectionCount: wrong selected children count for " + prettyName(aIdentifier));
+  // selectedItemCount
+  is(acc.selectedItemCount, aSelectedChildren.length,
+     "selectedItemCount: wrong selected children count for " + prettyName(aIdentifier));
 
-  // refSelection
+  // getSelectedItemAt
   for (var idx = 0; idx < len; idx++) {
     var expectedAcc = getAccessible(aSelectedChildren[idx]);
-    is(acc.refSelection(idx), expectedAcc,
-       msg + "refSelection: wrong selected child at index " + idx + " for " +
+    is(acc.getSelectedItemAt(idx), expectedAcc,
+       msg + "getSelectedItemAt: wrong selected child at index " + idx + " for " +
        prettyName(aIdentifier));
   }
 
-  // isChildSelected
-  testIsChildSelected(acc, acc, { value: 0 }, aSelectedChildren, msg);
+  // isItemSelected
+  testIsItemSelected(acc, acc, { value: 0 }, aSelectedChildren, msg);
 }
 
 /**
- * Test isChildSelected method, helper for testSelectableSelection
+ * Test isItemSelected method, helper for testSelectableSelection
  */
-function testIsChildSelected(aSelectAcc, aTraversedAcc, aIndexObj, aSelectedChildren, aMsg)
+function testIsItemSelected(aSelectAcc, aTraversedAcc, aIndexObj, aSelectedChildren, aMsg)
 {
   var childCount = aTraversedAcc.childCount;
   for (var idx = 0; idx < childCount; idx++) {
     var child = aTraversedAcc.getChildAt(idx);
     var [state, extraState] = getStates(child);
     if (state & STATE_SELECTABLE) {
       var isSelected = false;
       var len = aSelectedChildren.length;
       for (var jdx = 0; jdx < len; jdx++) {
         if (child == getAccessible(aSelectedChildren[jdx])) {
           isSelected = true;
           break;
         }
       }
 
-      // isChildSelected
-      is(aSelectAcc.isChildSelected(aIndexObj.value++), isSelected,
-         aMsg + "isChildSelected: wrong selected child " + prettyName(child) +
+      // isItemSelected
+      is(aSelectAcc.isItemSelected(aIndexObj.value++), isSelected,
+         aMsg + "isItemSelected: wrong selected child " + prettyName(child) +
          " for " + prettyName(aSelectAcc));
 
       // selected state
       testStates(child, isSelected ? STATE_SELECTED : 0, 0,
                  !isSelected ? STATE_SELECTED : 0 , 0);
 
       continue;
     }
 
-    testIsChildSelected(aSelectAcc, child, aIndexObj, aSelectedChildren);
+    testIsItemSelected(aSelectAcc, child, aIndexObj, aSelectedChildren);
   }
 }
--- a/accessible/tests/mochitest/selectable/test_aria.html
+++ b/accessible/tests/mochitest/selectable/test_aria.html
@@ -22,20 +22,20 @@
 
   <script type="application/javascript">
     function testSelectable(aID, aSelectableChildren)
     {
       var acc = getAccessible(aID, [nsIAccessibleSelectable]);
 
       testSelectableSelection(acc, []);
 
-      acc.selectAllSelection();
+      acc.selectAll();
       testSelectableSelection(acc, aSelectableChildren);
 
-      acc.clearSelection();
+      acc.unselectAll();
       testSelectableSelection(acc, []);
     }
 
     function doTest()
     {
       //////////////////////////////////////////////////////////////////////////
       // role="tablist"
 
@@ -59,23 +59,23 @@
 
       id = "listbox2";
       ok(isAccessible(id, [nsIAccessibleSelectable]),
          "No selectable accessible for " + id);
 
       testSelectableSelection(id, [ ]);
 
       select = getAccessible(id, [nsIAccessibleSelectable]);
-      select.addChildToSelection(0);
+      select.addItemToSelection(0);
       testSelectableSelection(id, [ "listbox2_item1" ]);
-      select.removeChildFromSelection(0);
+      select.removeItemFromSelection(0);
       testSelectableSelection(id, [ ]);
-      select.selectAllSelection();
+      select.selectAll();
       testSelectableSelection(id, [ "listbox2_item1", "listbox2_item2" ]);
-      select.clearSelection();
+      select.unselectAll();
       testSelectableSelection(id, [ ]);
       
       //////////////////////////////////////////////////////////////////////////
       // role="grid"
 
       id = "grid1";
       ok(isAccessible(id, [nsIAccessibleSelectable]),
          "No selectable accessible for " + id);
--- a/accessible/tests/mochitest/selectable/test_listbox.xul
+++ b/accessible/tests/mochitest/selectable/test_listbox.xul
@@ -36,65 +36,65 @@
 
       var id = "listbox";
       ok(isAccessible(id, [nsIAccessibleSelectable]),
          "No selectable accessible for list of " + id);
 
       var select = getAccessible(id, [nsIAccessibleSelectable]);
       testSelectableSelection(select, [ ]);
 
-      select.addChildToSelection(1);
-      testSelectableSelection(select, [ "lb1_item2" ], "addChildToSelect(1): ");
+      select.addItemToSelection(1);
+      testSelectableSelection(select, [ "lb1_item2" ], "addItemToSelect(1): ");
 
-      select.removeChildFromSelection(1);
+      select.removeItemFromSelection(1);
       testSelectableSelection(select, [ ],
-                              "removeChildFromSelection(1): ");
+                              "removeItemFromSelection(1): ");
 
-      todo(select.selectAllSelection() == false,
+      todo(select.selectAll() == false,
            "No way to select all items in listbox '" + id + "'");
-      testSelectableSelection(select, [ "lb1_item1" ], "selectAllSelection: ");
+      testSelectableSelection(select, [ "lb1_item1" ], "selectAll: ");
 
-      select.addChildToSelection(1);
-      select.clearSelection();
-      testSelectableSelection(select, [ ], "clearSelection: ");
+      select.addItemToSelection(1);
+      select.unselectAll();
+      testSelectableSelection(select, [ ], "unselectAll: ");
 
       //////////////////////////////////////////////////////////////////////////
       // multiple selectable listbox
 
       var id = "listbox2";
       ok(isAccessible(id, [nsIAccessibleSelectable]),
          "No selectable accessible for list of " + id);
 
       var select = getAccessible(id, [nsIAccessibleSelectable]);
       testSelectableSelection(select, [ ]);
 
-      select.addChildToSelection(1);
-      testSelectableSelection(select, [ "lb2_item2" ], "addChildToSelect(1): ");
+      select.addItemToSelection(1);
+      testSelectableSelection(select, [ "lb2_item2" ], "addItemToSelect(1): ");
 
-      select.removeChildFromSelection(1);
+      select.removeItemFromSelection(1);
       testSelectableSelection(select, [ ],
-                              "removeChildFromSelection(1): ");
+                              "removeItemFromSelection(1): ");
 
-      is(select.selectAllSelection(), true,
+      is(select.selectAll(), true,
          "All items should be selected in listbox '" + id + "'");
       testSelectableSelection(select, [ "lb2_item1", "lb2_item2" ],
-                              "selectAllSelection: ");
+                              "selectAll: ");
 
-      select.clearSelection();
-      testSelectableSelection(select, [ ], "clearSelection: ");
+      select.unselectAll();
+      testSelectableSelection(select, [ ], "unselectAll: ");
 
       //////////////////////////////////////////////////////////////////////////
       // listbox with headers
 
-      // XXX: addChildToSelection/removeChildFromSelection don't work correctly
+      // XXX: addItemToSelection/removeItemFromSelection don't work correctly
       // on listboxes with headers because header is inserted into hierarchy
       // and child indexes that are used in these methods are shifted (see bug
       // 591939).
       todo(false,
-           "Fix addChildToSelection/removeChildFromSelection on listboxes with headers.");
+           "Fix addItemToSelection/removeItemFromSelection on listboxes with headers.");
 
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   ]]>
   </script>
--- a/accessible/tests/mochitest/selectable/test_menulist.xul
+++ b/accessible/tests/mochitest/selectable/test_menulist.xul
@@ -38,30 +38,30 @@
       var combobox = getAccessible(id);
       var comboboxList = combobox.firstChild;
       ok(isAccessible(comboboxList, [nsIAccessibleSelectable]),
          "No selectable accessible for list of " + id);
 
       var select = getAccessible(comboboxList, [nsIAccessibleSelectable]);
       testSelectableSelection(select, [ "cb1_item1" ]);
 
-      select.addChildToSelection(1);
-      testSelectableSelection(select, [ "cb1_item2" ], "addChildToSelect(1): ");
+      select.addItemToSelection(1);
+      testSelectableSelection(select, [ "cb1_item2" ], "addItemToSelection(1): ");
 
-      select.removeChildFromSelection(1);
+      select.removeItemFromSelection(1);
       testSelectableSelection(select, [ ],
-                              "removeChildFromSelection(1): ");
+                              "removeItemFromSelection(1): ");
 
-      is(select.selectAllSelection(), false,
+      is(select.selectAll(), false,
          "No way to select all items in combobox '" + id + "'");
-      testSelectableSelection(select, [ ], "selectAllSelection: ");
+      testSelectableSelection(select, [ ], "selectAll: ");
 
-      select.addChildToSelection(1);
-      select.clearSelection();
-      testSelectableSelection(select, [ ], "clearSelection: ");
+      select.addItemToSelection(1);
+      select.unselectAll();
+      testSelectableSelection(select, [ ], "unselectAll: ");
 
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   ]]>
   </script>
--- a/accessible/tests/mochitest/selectable/test_select.html
+++ b/accessible/tests/mochitest/selectable/test_select.html
@@ -32,154 +32,154 @@
       var comboboxList = combobox.firstChild;
       ok(isAccessible(comboboxList, [nsIAccessibleSelectable]),
          "No selectable accessible for list of " + id);
 
       var select = getAccessible(comboboxList, [nsIAccessibleSelectable]);
       testSelectableSelection(select, [ "cb1_item1" ]);
 
       // select 2nd item
-      select.addChildToSelection(1);
-      testSelectableSelection(select, [ "cb1_item2" ], "addChildToSelect(1): ");
+      select.addItemToSelection(1);
+      testSelectableSelection(select, [ "cb1_item2" ], "addItemToSelection(1): ");
 
       // unselect 2nd item, 1st item gets selected automatically
-      select.removeChildFromSelection(1);
+      select.removeItemFromSelection(1);
       testSelectableSelection(select, [ "cb1_item1" ],
-                              "removeChildFromSelection(1): ");
+                              "removeItemFromSelection(1): ");
 
       // doesn't change selection
-      is(select.selectAllSelection(), false,
+      is(select.selectAll(), false,
          "No way to select all items in combobox '" + id + "'");
-      testSelectableSelection(select, [ "cb1_item1" ], "selectAllSelection: ");
+      testSelectableSelection(select, [ "cb1_item1" ], "selectAll: ");
 
       // doesn't change selection
-      select.clearSelection();
-      testSelectableSelection(select, [ "cb1_item1" ], "clearSelection: ");
+      select.unselectAll();
+      testSelectableSelection(select, [ "cb1_item1" ], "unselectAll: ");
 
       //////////////////////////////////////////////////////////////////////////
       // select@size="1" with optgroups
 
       id = "combobox2";
       combobox = getAccessible(id);
       comboboxList = combobox.firstChild;
       ok(isAccessible(comboboxList, [nsIAccessibleSelectable]),
          "No selectable accessible for list of " + id);
 
       select = getAccessible(comboboxList, [nsIAccessibleSelectable]);
       testSelectableSelection(select, [ "cb2_item1" ]);
 
-      select.addChildToSelection(1);
+      select.addItemToSelection(1);
       testSelectableSelection(select, [ "cb2_item2" ]);
 
-      select.removeChildFromSelection(1);
+      select.removeItemFromSelection(1);
       testSelectableSelection(select, [ "cb2_item1" ]);
 
-      is(select.selectAllSelection(), false,
+      is(select.selectAll(), false,
          "No way to select all items in combobox " + id + "'");
       testSelectableSelection(select, [ "cb2_item1" ]);
 
-      select.clearSelection();
+      select.unselectAll();
       testSelectableSelection(select, [ "cb2_item1" ]);
 
       //////////////////////////////////////////////////////////////////////////
       // select@size="4" aka single selectable listbox
 
       var id = "listbox";
       ok(isAccessible(id, [nsIAccessibleSelectable]),
          "No selectable accessible for " + id);
 
       select = getAccessible(id, [nsIAccessibleSelectable]);
       testSelectableSelection(select, [ ]);
 
       // select 2nd item
-      select.addChildToSelection(1);
-      testSelectableSelection(select, [ "lb1_item2" ], "addChildToSelect(1): ");
+      select.addItemToSelection(1);
+      testSelectableSelection(select, [ "lb1_item2" ], "addItemToSelection(1): ");
 
       // unselect 2nd item, 1st item gets selected automatically
-      select.removeChildFromSelection(1);
+      select.removeItemFromSelection(1);
       testSelectableSelection(select, [ ],
-                              "removeChildFromSelection(1): ");
+                              "removeItemFromSelection(1): ");
 
       // doesn't change selection
-      is(select.selectAllSelection(), false,
+      is(select.selectAll(), false,
          "No way to select all items in single selectable listbox '" + id + "'");
-      testSelectableSelection(select, [ ], "selectAllSelection: ");
+      testSelectableSelection(select, [ ], "selectAll: ");
 
       // doesn't change selection
-      select.clearSelection();
-      testSelectableSelection(select, [ ], "clearSelection: ");
+      select.unselectAll();
+      testSelectableSelection(select, [ ], "unselectAll: ");
 
       //////////////////////////////////////////////////////////////////////////
       // select@size="4" with optgroups, single selectable
 
       id = "listbox2";
       ok(isAccessible(id, [nsIAccessibleSelectable]),
          "No selectable accessible for " + id);
 
       select = getAccessible(id, [nsIAccessibleSelectable]);
       testSelectableSelection(select, [ ]);
 
-      select.addChildToSelection(1);
+      select.addItemToSelection(1);
       testSelectableSelection(select, [ "lb2_item2" ]);
 
-      select.removeChildFromSelection(1);
+      select.removeItemFromSelection(1);
       testSelectableSelection(select, [ ]);
 
-      is(select.selectAllSelection(), false,
+      is(select.selectAll(), false,
          "No way to select all items in single selectable listbox " + id + "'");
       testSelectableSelection(select, [ ]);
 
-      select.clearSelection();
+      select.unselectAll();
       testSelectableSelection(select, [ ]);
 
       //////////////////////////////////////////////////////////////////////////
       // select@size="4" multiselect aka listbox
 
       id = "listbox3";
       ok(isAccessible(id, [nsIAccessibleSelectable]),
          "No selectable accessible for " + id);
 
       select = getAccessible(id, [nsIAccessibleSelectable]);
       testSelectableSelection(select, [ ]);
 
-      select.addChildToSelection(0);
-      testSelectableSelection(select, [ "lb3_item1" ], "addChildToSelection: ");
+      select.addItemToSelection(0);
+      testSelectableSelection(select, [ "lb3_item1" ], "addItemToSelection: ");
 
-      select.removeChildFromSelection(0);
-      testSelectableSelection(select, [ ], "removeChildFromSelection: ");
+      select.removeItemFromSelection(0);
+      testSelectableSelection(select, [ ], "removeItemFromSelection: ");
 
-      is(select.selectAllSelection(), true,
+      is(select.selectAll(), true,
          "All items in listbox '" + id + "' should be selected");
       testSelectableSelection(select, [ "lb3_item1", "lb3_item2"],
-                              "selectAllSelection: ");
+                              "selectAll: ");
 
-      select.clearSelection();
-      testSelectableSelection(select, [ ], "clearSelection: ");
+      select.unselectAll();
+      testSelectableSelection(select, [ ], "unselectAll: ");
 
       //////////////////////////////////////////////////////////////////////////
       // select@size="4" multiselect with optgroups
 
       var id = "listbox4";
       ok(isAccessible(id, [nsIAccessibleSelectable]),
          "No selectable accessible for " + id);
 
       select = getAccessible(id, [nsIAccessibleSelectable]);
       testSelectableSelection(select, [ ]);
 
-      select.addChildToSelection(0);
+      select.addItemToSelection(0);
       testSelectableSelection(select, [ "lb4_item1" ]);
 
-      select.removeChildFromSelection(0);
+      select.removeItemFromSelection(0);
       testSelectableSelection(select, [ ]);
 
-      is(select.selectAllSelection(), true,
+      is(select.selectAll(), true,
          "All items in listbox '" + id + "' should be selected");
       testSelectableSelection(select, [ "lb4_item1", "lb4_item2"]);
 
-      select.clearSelection();
+      select.unselectAll();
       testSelectableSelection(select, [ ]);
 
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
--- a/accessible/tests/mochitest/selectable/test_tree.xul
+++ b/accessible/tests/mochitest/selectable/test_tree.xul
@@ -48,58 +48,58 @@
       {
         var tree = getAccessible(this.DOMNode);
 
         var isTreeMultiSelectable = false;
         var seltype = this.DOMNode.getAttribute("seltype");
         if (seltype != "single" && seltype != "cell" && seltype != "text")
           isTreeMultiSelectable = true;
 
-        // selectAllSelection
+        // selectAll
         var accSelectable = getAccessible(this.DOMNode,
                                           [nsIAccessibleSelectable]);
         ok(accSelectable, "tree is not selectable!");
         if (accSelectable) {
-          is(accSelectable.selectAllSelection(), isTreeMultiSelectable,
-             "SelectAllSelection is not correct for seltype: " + seltype);
+          is(accSelectable.selectAll(), isTreeMultiSelectable,
+             "SelectAll is not correct for seltype: " + seltype);
         }
 
         var selectedChildren = [];
         if (isTreeMultiSelectable) {
           var rows = tree.children;
           for (var i = 0; i < rows.length; i++) {
           var row = rows.queryElementAt(i, nsIAccessible);
             if (getRole(row) == ROLE_OUTLINEITEM || getRole(row) == ROLE_ROW)
               selectedChildren.push(row);
           }
         }
         testSelectableSelection(accSelectable, selectedChildren,
-                                "selectAllSelection test. ");
+                                "selectAll test. ");
 
-        // clearSelection
-        accSelectable.clearSelection();
-        testSelectableSelection(accSelectable, [], "clearSelection test. ");
+        // unselectAll
+        accSelectable.unselectAll();
+        testSelectableSelection(accSelectable, [], "unselectAll test. ");
 
-        // addChildToSelection
-        accSelectable.addChildToSelection(1);
-        accSelectable.addChildToSelection(3);
+        // addItemToSelection
+        accSelectable.addItemToSelection(1);
+        accSelectable.addItemToSelection(3);
 
         selectedChildren = isTreeMultiSelectable ?
           [ accSelectable.getChildAt(2), accSelectable.getChildAt(4) ] :
           [ accSelectable.getChildAt(2) ];
         testSelectableSelection(accSelectable, selectedChildren,
-                                "addChildToSelection test. ");
+                                "addItemToSelection test. ");
 
-        // removeChildFromSelection
-        accSelectable.removeChildFromSelection(1);
+        // removeItemFromSelection
+        accSelectable.removeItemFromSelection(1);
 
         selectedChildren = isTreeMultiSelectable ?
           [ accSelectable.getChildAt(4) ] : [ ];
         testSelectableSelection(accSelectable, selectedChildren,
-                                "removeChildFromSelection test. ");
+                                "removeItemFromSelection test. ");
       }
 
       this.getID = function getID()
       {
         "tree processor for " + prettyName(aTreeID);
       }
     }
 
--- a/browser/base/content/browser-plugins.js
+++ b/browser/base/content/browser-plugins.js
@@ -209,16 +209,24 @@ var gPluginHandler = {
     if (pluginName && "install" + os in this.supportedPlugins.plugins[pluginName]) {
       return true;
     }
     return false;
   },
 
   handleEvent : function(event) {
     let eventType = event.type;
+
+    if (eventType == "PluginRemoved") {
+      let doc = event.target;
+      let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document);
+      this._setPluginNotificationIcon(browser);
+      return;
+    }
+
     let plugin = event.target;
     let doc = plugin.ownerDocument;
 
     if (!(plugin instanceof Ci.nsIObjectLoadingContent))
       return;
 
     if (eventType == "PluginBindingAttached") {
       // The plugin binding fires this event when it is created.
@@ -308,23 +316,25 @@ var gPluginHandler = {
     if (eventType != "PluginCrashed") {
       let overlay = this.getPluginUI(plugin, "main");
       if (overlay != null) {
         if (!this.isTooSmall(plugin, overlay))
           overlay.style.visibility = "visible";
 
         plugin.addEventListener("overflow", function(event) {
           overlay.style.visibility = "hidden";
+          gPluginHandler._setPluginNotificationIcon(browser);
         });
         plugin.addEventListener("underflow", function(event) {
           // this is triggered if only one dimension underflows,
           // the other dimension might still overflow
           if (!gPluginHandler.isTooSmall(plugin, overlay)) {
             overlay.style.visibility = "visible";
           }
+          gPluginHandler._setPluginNotificationIcon(browser);
         });
       }
     }
 
     // Only show the notification after we've done the isTooSmall check, so
     // that the notification can decide whether to show the "alert" icon
     if (shouldShowNotification) {
       this._showClickToPlayNotification(browser, plugin, false);
@@ -659,42 +669,58 @@ var gPluginHandler = {
    */
   _updatePluginPermission: function PH_setPermissionForPlugins(aNotification, aPluginInfo, aNewState) {
     let permission;
     let expireType;
     let expireTime;
     let histogram =
       Services.telemetry.getHistogramById("PLUGINS_NOTIFICATION_USER_ACTION");
 
+    // Update the permission manager.
+    // Also update the current state of pluginInfo.fallbackType so that
+    // subsequent opening of the notification shows the current state.
     switch (aNewState) {
       case "allownow":
         permission = Ci.nsIPermissionManager.ALLOW_ACTION;
         expireType = Ci.nsIPermissionManager.EXPIRE_SESSION;
         expireTime = Date.now() + Services.prefs.getIntPref(this.PREF_SESSION_PERSIST_MINUTES) * 60 * 1000;
         histogram.add(0);
+        aPluginInfo.fallbackType = Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE;
         break;
 
       case "allowalways":
         permission = Ci.nsIPermissionManager.ALLOW_ACTION;
         expireType = Ci.nsIPermissionManager.EXPIRE_TIME;
         expireTime = Date.now() +
           Services.prefs.getIntPref(this.PREF_PERSISTENT_DAYS) * 24 * 60 * 60 * 1000;
         histogram.add(1);
+        aPluginInfo.fallbackType = Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE;
         break;
 
       case "block":
         permission = Ci.nsIPermissionManager.PROMPT_ACTION;
         expireType = Ci.nsIPermissionManager.EXPIRE_NEVER;
         expireTime = 0;
         histogram.add(2);
+        switch (aPluginInfo.blocklistState) {
+          case Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE:
+            aPluginInfo.fallbackType = Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE;
+            break;
+          case Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE:
+            aPluginInfo.fallbackType = Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE;
+            break;
+          default:
+            aPluginInfo.fallbackType = Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY;
+        }
         break;
 
       // In case a plugin has already been allowed in another tab, the "continue allowing" button
       // shouldn't change any permissions but should run the plugin-enablement code below.
       case "continue":
+        aPluginInfo.fallbackType = Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE;
         break;
       default:
         Cu.reportError(Error("Unexpected plugin state: " + aNewState));
         return;
     }
 
     let browser = aNotification.browser;
     let contentWindow = browser.contentWindow;
@@ -713,26 +739,28 @@ var gPluginHandler = {
     let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                            .getInterface(Ci.nsIDOMWindowUtils);
     let plugins = cwu.plugins;
     let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
 
     let pluginFound = false;
     for (let plugin of plugins) {
       plugin.QueryInterface(Ci.nsIObjectLoadingContent);
-      // canActivatePlugin will return false if this isn't a known plugin type,
-      // so the pluginHost.getPermissionStringForType call is protected
-      if (gPluginHandler.canActivatePlugin(plugin) &&
-          aPluginInfo.permissionString == pluginHost.getPermissionStringForType(plugin.actualType)) {
-        let overlay = this.getPluginUI(plugin, "main");
-        if (overlay) {
-          overlay.removeEventListener("click", gPluginHandler._overlayClickListener, true);
+      if (!gPluginHandler.isKnownPlugin(plugin)) {
+        continue;
+      }
+      if (aPluginInfo.permissionString == pluginHost.getPermissionStringForType(plugin.actualType)) {
+        pluginFound = true;
+        if (gPluginHandler.canActivatePlugin(plugin)) {
+          let overlay = this.getPluginUI(plugin, "main");
+          if (overlay) {
+            overlay.removeEventListener("click", gPluginHandler._overlayClickListener, true);
+          }
+          plugin.playPlugin();
         }
-        plugin.playPlugin();
-        pluginFound = true;
       }
     }
 
     // If there are no instances of the plugin on the page any more, what the
     // user probably needs is for us to allow and then refresh.
     if (!pluginFound) {
       browser.reload();
     }
@@ -779,24 +807,16 @@ var gPluginHandler = {
       if (pluginInfo.permissionString === null) {
         Cu.reportError("No permission string for active plugin.");
         continue;
       }
       if (centerActions.has(pluginInfo.permissionString)) {
         continue;
       }
 
-      // Assume that plugins are hidden and then set override later
-      pluginInfo.hidden = true;
-
-      let overlay = this.getPluginUI(plugin, "main");
-      if (overlay && overlay.style.visibility != "hidden" && overlay.style.visibility != "") {
-        pluginInfo.hidden = false;
-      }
-
       let permissionObj = Services.perms.
         getPermissionObject(principal, pluginInfo.permissionString, false);
       if (permissionObj) {
         pluginInfo.pluginPermissionHost = permissionObj.host;
         pluginInfo.pluginPermissionType = permissionObj.expireType;
       }
       else {
         pluginInfo.pluginPermissionHost = principalHost;
@@ -814,60 +834,98 @@ var gPluginHandler = {
       else {
         url = Services.urlFormatter.formatURLPref("app.support.baseURL") + "clicktoplay";
       }
       pluginInfo.detailsLink = url;
       
       centerActions.set(pluginInfo.permissionString, pluginInfo);
     }
 
-    let pluginBlocked = false;
-    let pluginHidden = false;
-    for (let pluginInfo of centerActions.values()) {
-      let fallbackType = pluginInfo.fallbackType;
-      if (fallbackType == Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE ||
-          fallbackType == Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE ||
-          fallbackType == Ci.nsIObjectLoadingContent.PLUGIN_BLOCKLISTED) {
-        pluginBlocked = true;
-        pluginHidden = false;
-        break;
-      }
-      if (fallbackType == Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY && pluginInfo.hidden) {
-        pluginHidden = true;
-      }
-    }
-
-    let iconClasses = document.getElementById("plugins-notification-icon").classList;
-    iconClasses.toggle("plugin-blocked", pluginBlocked);
-    iconClasses.toggle("plugin-hidden", pluginHidden);
-
     let primaryPluginPermission = null;
     if (aShowNow) {
       primaryPluginPermission = this._getPluginInfo(aPlugin).permissionString;
     }
 
     if (notification) {
       // Don't modify the notification UI while it's on the screen, that would be
       // jumpy and might allow clickjacking.
       if (aShowNow) {
         notification.options.primaryPlugin = primaryPluginPermission;
         notification.reshow();
+        setTimeout(() => { this._setPluginNotificationIcon(aBrowser); }, 0);
       }
       return;
     }
 
     let options = {
       dismissed: !aShowNow,
       eventCallback: this._clickToPlayNotificationEventCallback,
       primaryPlugin: primaryPluginPermission,
       centerActions: centerActions
     };
     PopupNotifications.show(aBrowser, "click-to-play-plugins",
                             "", "plugins-notification-icon",
                             null, null, options);
+    setTimeout(() => { this._setPluginNotificationIcon(aBrowser); }, 0);
+  },
+
+  _setPluginNotificationIcon : function PH_setPluginNotificationIcon(aBrowser) {
+    // Because this is called on a timeout, sanity-check before continuing
+    if (!aBrowser.docShell || !aBrowser.contentWindow) {
+      return;
+    }
+
+    let notification = PopupNotifications.getNotification("click-to-play-plugins", aBrowser);
+    if (!notification)
+      return;
+
+    let iconClasses = document.getElementById("plugins-notification-icon").classList;
+
+    // Make a copy so we can remove visible plugins
+    let actions = new Map(notification.options.centerActions);
+
+    for (let pluginInfo of actions.values()) {
+      let fallbackType = pluginInfo.fallbackType;
+      if (fallbackType == Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE ||
+          fallbackType == Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE ||
+          fallbackType == Ci.nsIObjectLoadingContent.PLUGIN_BLOCKLISTED) {
+        iconClasses.add("plugin-blocked");
+        iconClasses.remove("plugin-hidden");
+        return;
+      }
+    }
+
+    iconClasses.remove("plugin-blocked");
+
+    let contentWindow = aBrowser.contentWindow;
+    let contentDoc = aBrowser.contentDocument;
+    let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                           .getInterface(Ci.nsIDOMWindowUtils);
+    for (let plugin of cwu.plugins) {
+      let fallbackType = plugin.pluginFallbackType;
+      if (fallbackType != Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY) {
+        continue;
+      }
+      let info = this._getPluginInfo(plugin);
+      if (!actions.has(info.permissionString)) {
+        continue;
+      }
+      let overlay = this.getPluginUI(plugin, "main");
+      if (!overlay) {
+        continue;
+      }
+      if (!this.isTooSmall(plugin, overlay)) {
+        actions.delete(info.permissionString);
+        if (actions.size == 0) {
+          break;
+        }
+      }
+    }
+
+    iconClasses.toggle("plugin-hidden", actions.size != 0);
   },
 
   // Crashed-plugin observer. Notified once per plugin crash, before events
   // are dispatched to individual plugin instances.
   pluginCrashed : function(subject, topic, data) {
     let propertyBag = subject;
     if (!(propertyBag instanceof Ci.nsIPropertyBag2) ||
         !(propertyBag instanceof Ci.nsIWritablePropertyBag2))
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -751,16 +751,17 @@ var gBrowserInit = {
 
     gBrowser.addEventListener("DOMUpdatePageReport", gPopupBlockerObserver, false);
 
     // Note that the XBL binding is untrusted
     gBrowser.addEventListener("PluginBindingAttached", gPluginHandler, true, true);
     gBrowser.addEventListener("PluginCrashed",         gPluginHandler, true);
     gBrowser.addEventListener("PluginOutdated",        gPluginHandler, true);
     gBrowser.addEventListener("PluginInstantiated",    gPluginHandler, true);
+    gBrowser.addEventListener("PluginRemoved",         gPluginHandler, true);
 
     gBrowser.addEventListener("NewPluginInstalled", gPluginHandler.newPluginInstalled, true);
 
     Services.obs.addObserver(gPluginHandler.pluginCrashed, "plugin-crashed", false);
 
     window.addEventListener("AppCommand", HandleAppCommandEvent, true);
 
     messageManager.loadFrameScript("chrome://browser/content/content.js", true);
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -56,16 +56,17 @@ support-files =
   plugin_bug787619.html
   plugin_bug797677.html
   plugin_bug820497.html
   plugin_clickToPlayAllow.html
   plugin_clickToPlayDeny.html
   plugin_data_url.html
   plugin_hidden_to_visible.html
   plugin_small.html
+  plugin_syncRemoved.html
   plugin_test.html
   plugin_test2.html
   plugin_test3.html
   plugin_two_types.html
   plugin_unknown.html
   print_postdata.sjs
   redirect_bug623155.sjs
   test-mixedcontent-securityerrors.html
--- a/browser/base/content/test/general/browser_pluginnotification.js
+++ b/browser/base/content/test/general/browser_pluginnotification.js
@@ -830,11 +830,19 @@ function test24d() {
   var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(objLoadingContent.activated, "Test 24d, plugin should be activated");
 
   // this resets the vulnerable plugin permission
   setAndUpdateBlocklist(gHttpTestRoot + "blockNoPlugins.xml",
   function() {
     clearAllPluginPermissions();
     resetBlocklist();
-    finishTest();
+    prepareTest(test25, gTestRoot + "plugin_syncRemoved.html");
   });
 }
+
+function test25() {
+  let notification = PopupNotifications.getNotification("click-to-play-plugins");
+  ok(notification, "Test 25: There should be a plugin notification even if the plugin was immediately removed");
+  ok(notification.dismissed, "Test 25: The notification should be dismissed by default");
+
+  finishTest();
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/plugin_syncRemoved.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<body>
+<script type="text/javascript">
+  // create an embed, insert it in the doc and immediately remove it
+  var embed = document.createElement('embed');
+  embed.setAttribute("type", "application/x-test");
+  embed.setAttribute("style", "width: 0px; height: 0px;");
+  document.body.appendChild(embed);
+  window.getComputedStyle(embed, null).top;
+  document.body.remove(embed);
+</script>
--- a/browser/components/migration/src/SafariProfileMigrator.js
+++ b/browser/components/migration/src/SafariProfileMigrator.js
@@ -337,39 +337,16 @@ Preferences.prototype = {
         // Firefox has an elaborate set of Image preferences. The correlation is:
         // Mode:                            Safari    Firefox
         // Blocked                          FALSE     2
         // Allowed                          TRUE      1
         // Allowed, originating site only   --        3
         this._set("WebKitDisplayImagesKey", "permissions.default.image",
                   function(webkitVal) webkitVal ? 1 : 2);
 
-        // Default charset migration
-        this._set("WebKitDefaultTextEncodingName", "intl.charset.default",
-          function(webkitCharset) {
-            // We don't support x-mac-korean (see bug 713516), but it mostly matches
-            // EUC-KR.
-            if (webkitCharset == "x-mac-korean")
-              return "EUC-KR";
-
-            // getCharsetAlias throws if an invalid value is passed in.
-            try {
-              return Cc["@mozilla.org/charset-converter-manager;1"].
-                     getService(Ci.nsICharsetConverterManager).
-                     getCharsetAlias(webkitCharset);
-            }
-            catch(ex) {
-              Cu.reportError("Could not convert webkit charset '" + webkitCharset +
-                             "' to a supported charset");
-            }
-            // Don't set the preference if we could not get the corresponding
-            // charset.
-            return undefined;
-          });
-
 #ifdef XP_WIN
         // Cookie-accept policy.
         // For the OS X version, see WebFoundationCookieBehavior.
         // Setting                    Safari          Firefox
         // Always Accept              0               0
         // Accept from Originating    2               1
         // Never Accept               1               2
         this._set("WebKitCookieStorageAcceptPolicy",
--- a/browser/components/preferences/applications.js
+++ b/browser/components/preferences/applications.js
@@ -3,25 +3,20 @@
 # 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/.
  */
 
 //****************************************************************************//
 // Constants & Enumeration Values
 
-/*
-#ifndef XP_MACOSX
-*/
 var Cc = Components.classes;
 var Ci = Components.interfaces;
 var Cr = Components.results;
-/*
-#endif
-*/
+
 Components.utils.import('resource://gre/modules/Services.jsm');
 
 const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
 const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed";
 const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed";
 const TYPE_PDF = "application/pdf";
 
 const PREF_PDFJS_DISABLED = "pdfjs.disabled";
@@ -154,24 +149,24 @@ function isFeedType(t) {
 
 //****************************************************************************//
 // HandlerInfoWrapper
 
 /**
  * This object wraps nsIHandlerInfo with some additional functionality
  * the Applications prefpane needs to display and allow modification of
  * the list of handled types.
- * 
+ *
  * We create an instance of this wrapper for each entry we might display
  * in the prefpane, and we compose the instances from various sources,
- * including navigator.plugins and the handler service.
+ * including plugins and the handler service.
  *
  * We don't implement all the original nsIHandlerInfo functionality,
  * just the stuff that the prefpane needs.
- * 
+ *
  * In theory, all of the custom functionality in this wrapper should get
  * pushed down into nsIHandlerInfo eventually.
  */
 function HandlerInfoWrapper(aType, aHandlerInfo) {
   this._type = aType;
   this.wrappedHandlerInfo = aHandlerInfo;
 }
 
@@ -271,17 +266,17 @@ HandlerInfoWrapper.prototype = {
 
   get defaultDescription() {
     return this.wrappedHandlerInfo.defaultDescription;
   },
 
   // What to do with content of this type.
   get preferredAction() {
     // If we have an enabled plugin, then the action is to use that plugin.
-    if (this.plugin && !this.isDisabledPluginType)
+    if (this.pluginName && !this.isDisabledPluginType)
       return kActionUsePlugin;
 
     // If the action is to use a helper app, but we don't have a preferred
     // handler app, then switch to using the system default, if any; otherwise
     // fall back to saving to disk, which is the default action in nsMIMEInfo.
     // Note: "save to disk" is an invalid value for protocol info objects,
     // but the alwaysAskBeforeHandling getter will detect that situation
     // and always return true in that case to override this invalid value.
@@ -307,17 +302,17 @@ HandlerInfoWrapper.prototype = {
   },
 
   get alwaysAskBeforeHandling() {
     // If this type is handled only by a plugin, we can't trust the value
     // in the handler info object, since it'll be a default based on the absence
     // of any user configuration, and the default in that case is to always ask,
     // even though we never ask for content handled by a plugin, so special case
     // plugin-handled types by returning false here.
-    if (this.plugin && this.handledOnlyByPlugin)
+    if (this.pluginName && this.handledOnlyByPlugin)
       return false;
 
     // If this is a protocol type and the preferred action is "save to disk",
     // which is invalid for such types, then return true here to override that
     // action.  This could happen when the preferred action is to use a helper
     // app, but the preferredApplicationHandler is invalid, and there isn't
     // a default handler, so the preferredAction getter returns save to disk
     // instead.
@@ -1087,33 +1082,40 @@ var gApplicationsPane = {
    * the user an option to enable it.
    *
    * Also note that enabledPlugin does not get updated when
    * plugin.disable_full_page_plugin_for_types changes, so even if we could use
    * enabledPlugin to get the plugin that would be used, we'd still need to
    * check the pref ourselves to find out if it's enabled.
    */
   _loadPluginHandlers: function() {
-    for (let i = 0; i < navigator.plugins.length; ++i) {
-      let plugin = navigator.plugins[i];
-      for (let j = 0; j < plugin.length; ++j) {
-        let type = plugin[j].type;
+    "use strict";
+
+    let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
+    let pluginTags = pluginHost.getPluginTags();
+
+    for (let i = 0; i < pluginTags.length; ++i) {
+      let pluginTag = pluginTags[i];
+
+      let mimeTypes = pluginTag.getMimeTypes();
+      for (let j = 0; j < mimeTypes.length; ++j) {
+        let type = mimeTypes[j];
 
         let handlerInfoWrapper;
         if (type in this._handledTypes)
           handlerInfoWrapper = this._handledTypes[type];
         else {
           let wrappedHandlerInfo =
             this._mimeSvc.getFromTypeAndExtension(type, null);
           handlerInfoWrapper = new HandlerInfoWrapper(type, wrappedHandlerInfo);
           handlerInfoWrapper.handledOnlyByPlugin = true;
           this._handledTypes[type] = handlerInfoWrapper;
         }
 
-        handlerInfoWrapper.plugin = plugin;
+        handlerInfoWrapper.pluginName = pluginTag.name;
       }
     }
   },
 
   /**
    * Load the set of handlers defined by the application datastore.
    */
   _loadApplicationHandlers: function() {
@@ -1297,17 +1299,17 @@ var gApplicationsPane = {
         // in the first place?
 
       case Ci.nsIHandlerInfo.useSystemDefault:
         return this._prefsBundle.getFormattedString("useDefault",
                                                     [aHandlerInfo.defaultDescription]);
 
       case kActionUsePlugin:
         return this._prefsBundle.getFormattedString("usePluginIn",
-                                                    [aHandlerInfo.plugin.name,
+                                                    [aHandlerInfo.pluginName,
                                                      this._brandShortName]);
     }
   },
 
   _selectLastSelectedType: function() {
     // If the list is disabled by the pref.downloads.disable_button.edit_actions
     // preference being locked, then don't select the type, as that would cause
     // it to appear selected, with a different background and an actions menu
@@ -1479,21 +1481,21 @@ var gApplicationsPane = {
       // to make changes to the datastore when the user selects the item.
       menuItem.handlerApp = possibleApp;
 
       menuPopup.appendChild(menuItem);
       possibleAppMenuItems.push(menuItem);
     }
 
     // Create a menu item for the plugin.
-    if (handlerInfo.plugin) {
+    if (handlerInfo.pluginName) {
       var pluginMenuItem = document.createElement("menuitem");
       pluginMenuItem.setAttribute("action", kActionUsePlugin);
       let label = this._prefsBundle.getFormattedString("usePluginIn",
-                                                       [handlerInfo.plugin.name,
+                                                       [handlerInfo.pluginName,
                                                         this._brandShortName]);
       pluginMenuItem.setAttribute("label", label);
       pluginMenuItem.setAttribute("tooltiptext", label);
       pluginMenuItem.setAttribute(APP_ICON_ATTR_NAME, "plugin");
       menuPopup.appendChild(pluginMenuItem);
     }
 
     // Create a menu item for selecting a local application.
@@ -1646,17 +1648,17 @@ var gApplicationsPane = {
       handlerInfo.alwaysAskBeforeHandling = true;
     }
     else if (aActionItem.hasAttribute("action")) {
       let action = parseInt(aActionItem.getAttribute("action"));
 
       // Set the plugin state if we're enabling or disabling a plugin.
       if (action == kActionUsePlugin)
         handlerInfo.enablePluginType();
-      else if (handlerInfo.plugin && !handlerInfo.isDisabledPluginType)
+      else if (handlerInfo.pluginName && !handlerInfo.isDisabledPluginType)
         handlerInfo.disablePluginType();
 
       // Set the preferred application handler.
       // We leave the existing preferred app in the list when we set
       // the preferred action to something other than useHelperApp so that
       // legacy datastores that don't have the preferred app in the list
       // of possible apps still include the preferred app in the list of apps
       // the user can choose to handle the type.
--- a/browser/components/preferences/fonts.js
+++ b/browser/components/preferences/fonts.js
@@ -93,28 +93,16 @@ var gFontsDialog = {
       if (fontItems.length)
         break;
     }
     if (fontItems.length)
       return fontItems[0].getAttribute("value");
     return defaultValue;
   },
   
-  _charsetMenuInitialized: false,
-  readDefaultCharset: function ()
-  {
-    if (!this._charsetMenuInitialized) {
-      var os = Components.classes["@mozilla.org/observer-service;1"]
-                         .getService(Components.interfaces.nsIObserverService);
-      os.notifyObservers(null, "charsetmenu-selected", "other");
-      this._charsetMenuInitialized = true;
-    }
-    return undefined;
-  },
-  
   readUseDocumentFonts: function ()
   {
     var preference = document.getElementById("browser.display.use_document_fonts");
     return preference.value == 1;
   },
   
   writeUseDocumentFonts: function ()
   {
--- a/browser/components/preferences/fonts.xul
+++ b/browser/components/preferences/fonts.xul
@@ -32,17 +32,17 @@
   <prefpane id="FontsDialogPane"
             helpTopic="prefs-fonts-and-colors">
   
     <preferences id="fontPreferences">
       <preference id="font.language.group"  name="font.language.group"  type="wstring"/>
       <preference id="browser.display.use_document_fonts"
                   name="browser.display.use_document_fonts"
                   type="int"/>
-      <preference id="intl.charset.default" name="intl.charset.default" type="wstring"/>
+      <preference id="intl.charset.fallback.override" name="intl.charset.fallback.override" type="string"/>
     </preferences>
     
     <stringbundle id="bundlePreferences" src="chrome://browser/locale/preferences/preferences.properties"/>
     <script type="application/javascript" src="chrome://mozapps/content/preferences/fontbuilder.js"/>
     <script type="application/javascript" src="chrome://browser/content/preferences/fonts.js"/>
 
     <!-- Fonts for: [ Language ] -->
     <groupbox>
@@ -257,21 +257,32 @@
     <!-- Character Encoding -->
     <groupbox>
       <caption label="&languages.customize.Fallback.grouplabel;"/>
       <description>&languages.customize.Fallback.desc;</description>
       <hbox align="center">
         <label value="&languages.customize.Fallback.label;"
                accesskey="&languages.customize.Fallback.accesskey;"
                control="DefaultCharsetList"/>
-        <menulist id="DefaultCharsetList" ref="NC:DecodersRoot" datasources="rdf:charset-menu"
-                  preference="intl.charset.default" 
-                  onsyncfrompreference="return gFontsDialog.readDefaultCharset();">
-          <template>
-            <menupopup>
-              <menuitem label="rdf:http://home.netscape.com/NC-rdf#Name" value="..." uri="..."/>
-            </menupopup>
-          </template>
+        <menulist id="DefaultCharsetList" preference="intl.charset.fallback.override">
+          <menupopup>
+            <menuitem label="&languages.customize.Fallback.auto;"        value=""/>
+            <menuitem label="&languages.customize.Fallback.arabic;"      value="windows-1256"/>
+            <menuitem label="&languages.customize.Fallback.baltic;"      value="windows-1257"/>
+            <menuitem label="&languages.customize.Fallback.ceiso;"       value="ISO-8859-2"/>
+            <menuitem label="&languages.customize.Fallback.cewindows;"   value="windows-1250"/>
+            <menuitem label="&languages.customize.Fallback.simplified;"  value="gbk"/>
+            <menuitem label="&languages.customize.Fallback.traditional;" value="Big5"/>
+            <menuitem label="&languages.customize.Fallback.cyrillic;"    value="windows-1251"/>
+            <menuitem label="&languages.customize.Fallback.greek;"       value="ISO-8859-7"/>
+            <menuitem label="&languages.customize.Fallback.hebrew;"      value="windows-1255"/>
+            <menuitem label="&languages.customize.Fallback.japanese;"    value="Shift_JIS"/>
+            <menuitem label="&languages.customize.Fallback.korean;"      value="EUC-KR"/>
+            <menuitem label="&languages.customize.Fallback.thai;"        value="windows-874"/>
+            <menuitem label="&languages.customize.Fallback.turkish;"     value="windows-1254"/>
+            <menuitem label="&languages.customize.Fallback.vietnamese;"  value="windows-1258"/>
+            <menuitem label="&languages.customize.Fallback.other;"       value="windows-1252"/>
+          </menupopup>
         </menulist>
       </hbox>
     </groupbox>
   </prefpane>
 </prefwindow>
--- a/browser/components/preferences/in-content/applications.js
+++ b/browser/components/preferences/in-content/applications.js
@@ -141,24 +141,24 @@ function isFeedType(t) {
 
 //****************************************************************************//
 // HandlerInfoWrapper
 
 /**
  * This object wraps nsIHandlerInfo with some additional functionality
  * the Applications prefpane needs to display and allow modification of
  * the list of handled types.
- * 
+ *
  * We create an instance of this wrapper for each entry we might display
  * in the prefpane, and we compose the instances from various sources,
- * including navigator.plugins and the handler service.
+ * including plugins and the handler service.
  *
  * We don't implement all the original nsIHandlerInfo functionality,
  * just the stuff that the prefpane needs.
- * 
+ *
  * In theory, all of the custom functionality in this wrapper should get
  * pushed down into nsIHandlerInfo eventually.
  */
 function HandlerInfoWrapper(aType, aHandlerInfo) {
   this._type = aType;
   this.wrappedHandlerInfo = aHandlerInfo;
 }
 
@@ -258,17 +258,17 @@ HandlerInfoWrapper.prototype = {
 
   get defaultDescription() {
     return this.wrappedHandlerInfo.defaultDescription;
   },
 
   // What to do with content of this type.
   get preferredAction() {
     // If we have an enabled plugin, then the action is to use that plugin.
-    if (this.plugin && !this.isDisabledPluginType)
+    if (this.pluginName && !this.isDisabledPluginType)
       return kActionUsePlugin;
 
     // If the action is to use a helper app, but we don't have a preferred
     // handler app, then switch to using the system default, if any; otherwise
     // fall back to saving to disk, which is the default action in nsMIMEInfo.
     // Note: "save to disk" is an invalid value for protocol info objects,
     // but the alwaysAskBeforeHandling getter will detect that situation
     // and always return true in that case to override this invalid value.
@@ -294,17 +294,17 @@ HandlerInfoWrapper.prototype = {
   },
 
   get alwaysAskBeforeHandling() {
     // If this type is handled only by a plugin, we can't trust the value
     // in the handler info object, since it'll be a default based on the absence
     // of any user configuration, and the default in that case is to always ask,
     // even though we never ask for content handled by a plugin, so special case
     // plugin-handled types by returning false here.
-    if (this.plugin && this.handledOnlyByPlugin)
+    if (this.pluginName && this.handledOnlyByPlugin)
       return false;
 
     // If this is a protocol type and the preferred action is "save to disk",
     // which is invalid for such types, then return true here to override that
     // action.  This could happen when the preferred action is to use a helper
     // app, but the preferredApplicationHandler is invalid, and there isn't
     // a default handler, so the preferredAction getter returns save to disk
     // instead.
@@ -1074,33 +1074,40 @@ var gApplicationsPane = {
    * the user an option to enable it.
    *
    * Also note that enabledPlugin does not get updated when
    * plugin.disable_full_page_plugin_for_types changes, so even if we could use
    * enabledPlugin to get the plugin that would be used, we'd still need to
    * check the pref ourselves to find out if it's enabled.
    */
   _loadPluginHandlers: function() {
-    for (let i = 0; i < navigator.plugins.length; ++i) {
-      let plugin = navigator.plugins[i];
-      for (let j = 0; j < plugin.length; ++j) {
-        let type = plugin[j].type;
+    "use strict";
+
+    let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
+    let pluginTags = pluginHost.getPluginTags();
+
+    for (let i = 0; i < pluginTags.length; ++i) {
+      let pluginTag = pluginTags[i];
+
+      let mimeTypes = pluginTag.getMimeTypes();
+      for (let j = 0; j < mimeTypes.length; ++j) {
+        let type = mimeTypes[j];
 
         let handlerInfoWrapper;
         if (type in this._handledTypes)
           handlerInfoWrapper = this._handledTypes[type];
         else {
           let wrappedHandlerInfo =
             this._mimeSvc.getFromTypeAndExtension(type, null);
           handlerInfoWrapper = new HandlerInfoWrapper(type, wrappedHandlerInfo);
           handlerInfoWrapper.handledOnlyByPlugin = true;
           this._handledTypes[type] = handlerInfoWrapper;
         }
 
-        handlerInfoWrapper.plugin = plugin;
+        handlerInfoWrapper.pluginName = pluginTag.name;
       }
     }
   },
 
   /**
    * Load the set of handlers defined by the application datastore.
    */
   _loadApplicationHandlers: function() {
@@ -1284,17 +1291,17 @@ var gApplicationsPane = {
         // in the first place?
 
       case Ci.nsIHandlerInfo.useSystemDefault:
         return this._prefsBundle.getFormattedString("useDefault",
                                                     [aHandlerInfo.defaultDescription]);
 
       case kActionUsePlugin:
         return this._prefsBundle.getFormattedString("usePluginIn",
-                                                    [aHandlerInfo.plugin.name,
+                                                    [aHandlerInfo.pluginName,
                                                      this._brandShortName]);
     }
   },
 
   _selectLastSelectedType: function() {
     // If the list is disabled by the pref.downloads.disable_button.edit_actions
     // preference being locked, then don't select the type, as that would cause
     // it to appear selected, with a different background and an actions menu
@@ -1466,21 +1473,21 @@ var gApplicationsPane = {
       // to make changes to the datastore when the user selects the item.
       menuItem.handlerApp = possibleApp;
 
       menuPopup.appendChild(menuItem);
       possibleAppMenuItems.push(menuItem);
     }
 
     // Create a menu item for the plugin.
-    if (handlerInfo.plugin) {
+    if (handlerInfo.pluginName) {
       var pluginMenuItem = document.createElement("menuitem");
       pluginMenuItem.setAttribute("action", kActionUsePlugin);
       let label = this._prefsBundle.getFormattedString("usePluginIn",
-                                                       [handlerInfo.plugin.name,
+                                                       [handlerInfo.pluginName,
                                                         this._brandShortName]);
       pluginMenuItem.setAttribute("label", label);
       pluginMenuItem.setAttribute("tooltiptext", label);
       pluginMenuItem.setAttribute(APP_ICON_ATTR_NAME, "plugin");
       menuPopup.appendChild(pluginMenuItem);
     }
 
     // Create a menu item for selecting a local application.
@@ -1633,17 +1640,17 @@ var gApplicationsPane = {
       handlerInfo.alwaysAskBeforeHandling = true;
     }
     else if (aActionItem.hasAttribute("action")) {
       let action = parseInt(aActionItem.getAttribute("action"));
 
       // Set the plugin state if we're enabling or disabling a plugin.
       if (action == kActionUsePlugin)
         handlerInfo.enablePluginType();
-      else if (handlerInfo.plugin && !handlerInfo.isDisabledPluginType)
+      else if (handlerInfo.pluginName && !handlerInfo.isDisabledPluginType)
         handlerInfo.disablePluginType();
 
       // Set the preferred application handler.
       // We leave the existing preferred app in the list when we set
       // the preferred action to something other than useHelperApp so that
       // legacy datastores that don't have the preferred app in the list
       // of possible apps still include the preferred app in the list of apps
       // the user can choose to handle the type.
--- a/browser/components/sessionstore/content/content-sessionStore.js
+++ b/browser/components/sessionstore/content/content-sessionStore.js
@@ -4,16 +4,19 @@
 
 "use strict";
 
 function debug(msg) {
   Services.console.logStringMessage("SessionStoreContent: " + msg);
 }
 
 let Cu = Components.utils;
+let Cc = Components.classes;
+let Ci = Components.interfaces;
+let Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
 
 XPCOMUtils.defineLazyModuleGetter(this, "DocShellCapabilities",
   "resource:///modules/sessionstore/DocShellCapabilities.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PageStyle",
   "resource:///modules/sessionstore/PageStyle.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "SessionHistory",
--- a/browser/components/sessionstore/src/SessionStore.jsm
+++ b/browser/components/sessionstore/src/SessionStore.jsm
@@ -2556,16 +2556,20 @@ let SessionStoreInternal = {
       else
         tabbrowser.showTab(tab);
 
       if ("attributes" in tabData) {
         // Ensure that we persist tab attributes restored from previous sessions.
         Object.keys(tabData.attributes).forEach(a => TabAttributes.persist(a));
       }
 
+      // Any data that's in the process of being collected for this tab will be
+      // out of date now that we're restoring it.
+      TabState.dropPendingCollections(tab);
+
       browser.__SS_tabStillLoading = true;
 
       // keep the data around to prevent dataloss in case
       // a tab gets closed before it's been properly restored
       browser.__SS_data = tabData;
       browser.__SS_restoreState = TAB_STATE_NEEDS_RESTORE;
       browser.setAttribute("pending", "true");
       tab.setAttribute("pending", "true");
@@ -4369,22 +4373,34 @@ let TabState = {
       TabStateCache.set(tab, tabData);
     }
 
     // Prevent all running asynchronous collections from filling the cache.
     // Every asynchronous data collection started before a collectSync() call
     // can't expect to retrieve different data than the sync call. That's why
     // we just fill the cache with the data collected from the sync call and
     // discard any data collected asynchronously.
-    this._pendingCollections.delete(tab);
+    this.dropPendingCollections(tab);
 
     return tabData;
   },
 
   /**
+   * Drop any pending calls to TabState.collect. These calls will
+   * continue to run, but they won't store their results in the
+   * TabStateCache.
+   *
+   * @param tab
+   *        tabbrowser tab
+   */
+  dropPendingCollections: function (tab) {
+    this._pendingCollections.delete(tab);
+  },
+
+  /**
    * Collect data related to a single tab, including private data.
    * Use with caution.
    *
    * @param tab
    *        tabbrowser tab
    *
    * @returns {object} An object with the data for this tab. This data is never
    *                   cached, it will always be read from the tab and thus be
@@ -4527,18 +4543,20 @@ let TabState = {
     let tabData = {entries: [], lastAccessed: tab.lastAccessed };
     let browser = tab.linkedBrowser;
 
     if (!browser || !browser.currentURI) {
       // can happen when calling this function right after .addTab()
       return tabData;
     }
     if (browser.__SS_data && browser.__SS_tabStillLoading) {
-      // use the data to be restored when the tab hasn't been completely loaded
-      tabData = browser.__SS_data;
+      // Use the data to be restored when the tab hasn't been
+      // completely loaded. We clone the data, since we're updating it
+      // here and the caller may update it further.
+      tabData = JSON.parse(JSON.stringify(browser.__SS_data));
       if (tab.pinned)
         tabData.pinned = true;
       else
         delete tabData.pinned;
       tabData.hidden = tab.hidden;
 
       // If __SS_extdata is set then we'll use that since it might be newer.
       if (tab.__SS_extdata)
--- a/browser/devtools/debugger/test/browser.ini
+++ b/browser/devtools/debugger/test/browser.ini
@@ -80,16 +80,18 @@ support-files =
 [browser_dbg_breakpoints-contextmenu.js]
 [browser_dbg_breakpoints-disabled-reload.js]
 [browser_dbg_breakpoints-editor.js]
 [browser_dbg_breakpoints-highlight.js]
 [browser_dbg_breakpoints-new-script.js]
 [browser_dbg_breakpoints-pane.js]
 [browser_dbg_chrome-debugging.js]
 [browser_dbg_clean-exit-window.js]
+# Disabled because of leaks - See Bug 933950.
+skip-if = true
 [browser_dbg_clean-exit.js]
 [browser_dbg_closure-inspection.js]
 [browser_dbg_cmd-blackbox.js]
 [browser_dbg_cmd-break.js]
 [browser_dbg_cmd-dbg.js]
 [browser_dbg_conditional-breakpoints-01.js]
 [browser_dbg_conditional-breakpoints-02.js]
 [browser_dbg_debugger-statement.js]
--- a/browser/devtools/framework/target.js
+++ b/browser/devtools/framework/target.js
@@ -10,18 +10,16 @@ var promise = require("sdk/core/promise"
 var EventEmitter = require("devtools/shared/event-emitter");
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "DebuggerServer",
   "resource://gre/modules/devtools/dbg-server.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "DebuggerClient",
   "resource://gre/modules/devtools/dbg-client.jsm");
 
-loader.lazyGetter(this, "InspectorFront", () => require("devtools/server/actors/inspector").InspectorFront);
-
 const targets = new WeakMap();
 const promiseTargets = new WeakMap();
 
 /**
  * Functions for creating Targets
  */
 exports.TargetFactory = {
   /**
@@ -248,27 +246,16 @@ TabTarget.prototype = {
   get isLocalTab() {
     return !!this._tab;
   },
 
   get isThreadPaused() {
     return !!this._isThreadPaused;
   },
 
-  get inspector() {
-    if (!this.form) {
-      throw new Error("Target.inspector requires an initialized remote actor.");
-    }
-    if (this._inspector) {
-      return this._inspector;
-    }
-    this._inspector = InspectorFront(this.client, this.form);
-    return this._inspector;
-  },
-
   /**
    * Adds remote protocol capabilities to the target, so that it can be used
    * for tools that support the Remote Debugging Protocol even for local
    * connections.
    */
   makeRemote: function TabTarget_makeRemote() {
     if (this._remote) {
       return this._remote.promise;
@@ -436,21 +423,16 @@ TabTarget.prototype = {
       return this._destroyer.promise;
     }
 
     this._destroyer = promise.defer();
 
     // Before taking any action, notify listeners that destruction is imminent.
     this.emit("close");
 
-    if (this._inspector) {
-      this._inspector.destroy();
-      this._inspector = null;
-    }
-
     // First of all, do cleanup tasks that pertain to both remoted and
     // non-remoted targets.
     this.off("thread-resumed", this._handleThreadState);
     this.off("thread-paused", this._handleThreadState);
 
     if (this._tab) {
       this._teardownListeners();
     }
--- a/browser/devtools/inspector/inspector-panel.js
+++ b/browser/devtools/inspector/inspector-panel.js
@@ -13,16 +13,17 @@ let EventEmitter = require("devtools/sha
 let {CssLogic} = require("devtools/styleinspector/css-logic");
 
 loader.lazyGetter(this, "MarkupView", () => require("devtools/markupview/markup-view").MarkupView);
 loader.lazyGetter(this, "Selection", () => require("devtools/inspector/selection").Selection);
 loader.lazyGetter(this, "HTMLBreadcrumbs", () => require("devtools/inspector/breadcrumbs").HTMLBreadcrumbs);
 loader.lazyGetter(this, "Highlighter", () => require("devtools/inspector/highlighter").Highlighter);
 loader.lazyGetter(this, "ToolSidebar", () => require("devtools/framework/sidebar").ToolSidebar);
 loader.lazyGetter(this, "SelectorSearch", () => require("devtools/inspector/selector-search").SelectorSearch);
+loader.lazyGetter(this, "InspectorFront", () => require("devtools/server/actors/inspector").InspectorFront);
 
 const LAYOUT_CHANGE_TIMER = 250;
 
 /**
  * Represents an open instance of the Inspector for a tab.
  * The inspector controls the highlighter, the breadcrumbs,
  * the markup view, and the sidebar (computed view, rule view
  * and layout view).
@@ -55,16 +56,17 @@ const LAYOUT_CHANGE_TIMER = 250;
  *      Fired when the rule view updates to a new node
  */
 function InspectorPanel(iframeWindow, toolbox) {
   this._toolbox = toolbox;
   this._target = toolbox._target;
   this.panelDoc = iframeWindow.document;
   this.panelWin = iframeWindow;
   this.panelWin.inspector = this;
+  this._inspector = null;
 
   this._onBeforeNavigate = this._onBeforeNavigate.bind(this);
   this._target.on("will-navigate", this._onBeforeNavigate);
 
   EventEmitter.decorate(this);
 }
 
 exports.InspectorPanel = InspectorPanel;
@@ -78,16 +80,26 @@ InspectorPanel.prototype = {
       return this._getWalker();
     }).then(() => {
       return this._getDefaultNodeForSelection();
     }).then(defaultSelection => {
       return this._deferredOpen(defaultSelection);
     }).then(null, console.error);
   },
 
+  get inspector() {
+    if (!this._target.form) {
+      throw new Error("Target.inspector requires an initialized remote actor.");
+    }
+    if (!this._inspector) {
+      this._inspector = InspectorFront(this._target.client, this._target.form);
+    }
+    return this._inspector;
+  },
+
   _deferredOpen: function(defaultSelection) {
     let deferred = promise.defer();
 
     this.outerHTMLEditable = this._target.client.traits.editOuterHTML;
 
     this.onNewRoot = this.onNewRoot.bind(this);
     this.walker.on("new-root", this.onNewRoot);
 
@@ -179,20 +191,19 @@ InspectorPanel.prototype = {
   _onBeforeNavigate: function() {
     this._defaultNode = null;
     this.selection.setNodeFront(null);
     this._destroyMarkup();
     this.isDirty = false;
   },
 
   _getWalker: function() {
-    let inspector = this.target.inspector;
-    return inspector.getWalker().then(walker => {
+    return this.inspector.getWalker().then(walker => {
       this.walker = walker;
-      return inspector.getPageStyle();
+      return this.inspector.getPageStyle();
     }).then(pageStyle => {
       this.pageStyle = pageStyle;
     });
   },
 
   /**
    * Return a promise that will resolve to the default node for selection.
    */
@@ -495,17 +506,22 @@ InspectorPanel.prototype = {
       this.highlighter.off("unlocked", this.onLockStateChanged);
       this.highlighter.destroy();
     }
 
     delete this.onLockStateChanged;
 
     if (this.walker) {
       this.walker.off("new-root", this.onNewRoot);
-      this._destroyPromise = this.walker.release().then(null, console.error);
+      this._destroyPromise = this.walker.release()
+        .then(() => this._inspector.destroy())
+        .then(() => {
+          this._inspector = null;
+        }, console.error);
+
       delete this.walker;
       delete this.pageStyle;
     } else {
       this._destroyPromise = promise.resolve(null);
     }
 
     this.cancelUpdate();
     this.cancelLayoutChange();
--- a/browser/devtools/inspector/test/browser_inspector_basic_highlighter.js
+++ b/browser/devtools/inspector/test/browser_inspector_basic_highlighter.js
@@ -72,17 +72,17 @@ function test() {
     return deferred.promise;
   }
 
   function destroyInspector() {
     return inspector.destroy();
   }
 
   function verifyNoNodeSelected() {
-    ok(doc.querySelectorAll(":-moz-devtools-highlighted").length === 0, "no node selected");
+    is(doc.querySelectorAll(":-moz-devtools-highlighted").length, 0, "no node selected");
     return promise.resolve();
   }
 
   function finishUp() {
     let h = require("devtools/inspector/highlighter");
     h._forceBasic.value = false;
     inspector = doc = null;
     gBrowser.removeCurrentTab();
--- a/browser/devtools/markupview/markup-view.js
+++ b/browser/devtools/markupview/markup-view.js
@@ -945,17 +945,17 @@ MarkupView.prototype = {
     this._inspector.selection.off("new-node-front", this._boundOnNewSelection);
     delete this._boundOnNewSelection;
 
     this.walker.off("mutations", this._boundMutationObserver)
     delete this._boundMutationObserver;
 
     delete this._elt;
 
-    for ([key, container] of this._containers) {
+    for (let [key, container] of this._containers) {
       container.destroy();
     }
     delete this._containers;
   },
 
   /**
    * Initialize the preview panel.
    */
--- a/browser/devtools/scratchpad/scratchpad.js
+++ b/browser/devtools/scratchpad/scratchpad.js
@@ -346,17 +346,17 @@ var Scratchpad = {
       let deferred = promise.defer();
 
       webConsoleClient.evaluateJS(aString, aResponse => {
         this.debuggerClient = debuggerClient;
         this.webConsoleClient = webConsoleClient;
         if (aResponse.error) {
           deferred.reject(aResponse);
         }
-        else if (aResponse.exception) {
+        else if (aResponse.exception !== null) {
           deferred.resolve([aString, aResponse]);
         }
         else {
           deferred.resolve([aString, undefined, aResponse.result]);
         }
       }, evalOptions);
 
       return deferred.promise;
@@ -604,17 +604,31 @@ var Scratchpad = {
    * @return Promise
    *         The promise that indicates when writing the comment completes.
    */
   writeAsErrorComment: function SP_writeAsErrorComment(aError)
   {
     let deferred = promise.defer();
 
     if (VariablesView.isPrimitive({ value: aError })) {
-      deferred.resolve(aError);
+      let type = aError.type;
+      if (type == "undefined" ||
+          type == "null" ||
+          type == "Infinity" ||
+          type == "-Infinity" ||
+          type == "NaN" ||
+          type == "-0") {
+        deferred.resolve(type);
+      }
+      else if (type == "longString") {
+        deferred.resolve(aError.initial + "\u2026");
+      }
+      else {
+        deferred.resolve(aError);
+      }
     }
     else {
       let objectClient = new ObjectClient(this.debuggerClient, aError);
       objectClient.getPrototypeAndProperties(aResponse => {
         if (aResponse.error) {
           deferred.reject(aResponse);
           return;
         }
@@ -1356,16 +1370,17 @@ var Scratchpad = {
     this.editor.destroy();
     this.editor = null;
 
     if (this._sidebar) {
       this._sidebar.destroy();
       this._sidebar = null;
     }
 
+    scratchpadTargets = null;
     this.webConsoleClient = null;
     this.debuggerClient = null;
     this.initialized = false;
   },
 
   /**
    * Prompt to save scratchpad if it has unsaved changes.
    *
--- a/browser/devtools/scratchpad/test/browser.ini
+++ b/browser/devtools/scratchpad/test/browser.ini
@@ -26,11 +26,12 @@ support-files = head.js
 [browser_scratchpad_initialization.js]
 [browser_scratchpad_inspect.js]
 [browser_scratchpad_long_string.js]
 [browser_scratchpad_open.js]
 [browser_scratchpad_open_error_console.js]
 # Disabled, as escodegen is being replaced - bug 930141
 # [browser_scratchpad_pprint-02.js]
 # [browser_scratchpad_pprint.js]
+[browser_scratchpad_throw_output.js]
 [browser_scratchpad_restore.js]
 [browser_scratchpad_tab_switch.js]
 [browser_scratchpad_ui.js]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/scratchpad/test/browser_scratchpad_throw_output.js
@@ -0,0 +1,50 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let temp = {};
+Cu.import("resource://gre/modules/devtools/dbg-server.jsm", temp);
+
+function test()
+{
+  waitForExplicitFinish();
+
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
+    gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
+    openScratchpad(testThrowOutput);
+  }, true);
+
+  content.location = "data:text/html;charset=utf8,<p>Test throw outputs in Scratchpad</p>";
+}
+
+function testThrowOutput()
+{
+  let scratchpad = gScratchpadWindow.Scratchpad, tests = [];
+
+  let falsyValues = ["false", "0", "-0", "null", "undefined", "Infinity",
+                      "-Infinity", "NaN"];
+  falsyValues.forEach(function(value) {
+    tests.push({
+      method: "display",
+      code: "throw " + value + ";",
+      result: "throw " + value + ";\n/*\nException: " + value + "\n*/",
+      label: "Correct exception message for '" + value + "' is shown"
+    });
+  });
+
+  let longString = Array(temp.DebuggerServer.LONG_STRING_LENGTH + 1).join("a"),
+      shortedString = longString.substring(0,
+                        temp.DebuggerServer.LONG_STRING_INITIAL_LENGTH
+                      ) + "\u2026";
+  tests.push({
+    method: "display",
+    code: "throw '" + longString + "';",
+    result: "throw '" + longString + "';\n/*\nException: " + shortedString + "\n*/",
+    label: "Correct exception message for a longString is shown"
+  });
+
+  runAsyncTests(scratchpad, tests).then(function() {
+    finish();
+  });
+}
--- a/browser/devtools/styleinspector/test/browser_bug722196_rule_view_media_queries.js
+++ b/browser/devtools/styleinspector/test/browser_bug722196_rule_view_media_queries.js
@@ -1,17 +1,17 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that we correctly display appropriate media query titles in the
 // rule view.
 
 let doc;
-let inspector = null;
+let inspector;
 
 const TEST_URI = "http://example.com/browser/browser/devtools/styleinspector/" +
   "test/browser_bug722196_identify_media_queries.html";
 
 function test()
 {
   waitForExplicitFinish();
   addTab(TEST_URI);
@@ -50,12 +50,12 @@ function checkSheets()
   is(elementStyle.rules[1].title, inline +
     ":15 @media screen and (min-width: 1px)", "check rule 1 title");
   is(elementStyle.rules[2].title, inline + ":8", "check rule 2 title");
   finishUp();
 }
 
 function finishUp()
 {
-  doc = null;
+  doc = inspector = null;
   gBrowser.removeCurrentTab();
   finish();
 }
--- a/browser/devtools/webconsole/webconsole.js
+++ b/browser/devtools/webconsole/webconsole.js
@@ -2601,39 +2601,38 @@ WebConsoleFrame.prototype = {
    *        The line number on which the error occurred. If zero or omitted,
    *        there is no line number associated with this message.
    * @return nsIDOMNode
    *         The new anchor element, ready to be added to the message node.
    */
   createLocationNode: function WCF_createLocationNode(aSourceURL, aSourceLine)
   {
     let locationNode = this.document.createElementNS(XHTML_NS, "a");
+    let filenameNode = this.document.createElementNS(XHTML_NS, "span");
 
     // Create the text, which consists of an abbreviated version of the URL
-    // plus an optional line number. Scratchpad URLs should not be abbreviated.
-    let displayLocation;
+    // Scratchpad URLs should not be abbreviated.
+    let filename;
     let fullURL;
     let isScratchpad = false;
 
     if (/^Scratchpad\/\d+$/.test(aSourceURL)) {
-      displayLocation = aSourceURL;
+      filename = aSourceURL;
       fullURL = aSourceURL;
       isScratchpad = true;
     }
     else {
       fullURL = aSourceURL.split(" -> ").pop();
-      displayLocation = WebConsoleUtils.abbreviateSourceURL(fullURL);
-    }
-
-    if (aSourceLine) {
-      displayLocation += ":" + aSourceLine;
-      locationNode.sourceLine = aSourceLine;
-    }
-
-    locationNode.textContent = " " + displayLocation;
+      filename = WebConsoleUtils.abbreviateSourceURL(fullURL);
+    }
+
+    filenameNode.className = "filename";
+    filenameNode.textContent = " " + filename;
+    locationNode.appendChild(filenameNode);
+
     locationNode.href = isScratchpad ? "#" : fullURL;
     locationNode.draggable = false;
     locationNode.setAttribute("title", aSourceURL);
     locationNode.className = "location devtools-monospace";
 
     // Make the location clickable.
     this._addMessageLinkCallback(locationNode, () => {
       if (isScratchpad) {
@@ -2646,16 +2645,24 @@ WebConsoleFrame.prototype = {
                locationNode.parentNode.category == CATEGORY_WEBDEV) {
         this.owner.viewSourceInDebugger(fullURL, aSourceLine);
       }
       else {
         this.owner.viewSource(fullURL, aSourceLine);
       }
     });
 
+    if (aSourceLine) {
+      let lineNumberNode = this.document.createElementNS(XHTML_NS, "span");
+      lineNumberNode.className = "line-number";
+      lineNumberNode.textContent = ":" + aSourceLine;
+      locationNode.appendChild(lineNumberNode);
+      locationNode.sourceLine = aSourceLine;
+    }
+
     return locationNode;
   },
 
   /**
    * Adjusts the category and severity of the given message.
    *
    * @param nsIDOMNode aMessageNode
    *        The message node to alter.
--- a/browser/locales/en-US/chrome/browser/preferences/fonts.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/fonts.dtd
@@ -67,8 +67,45 @@
 
 <!ENTITY  allowPagesToUse.label                   "Allow pages to choose their own fonts, instead of my selections above">
 <!ENTITY  allowPagesToUse.accesskey               "A">
 
 <!ENTITY languages.customize.Fallback.grouplabel  "Character Encoding for Legacy Content">
 <!ENTITY languages.customize.Fallback.label       "Fallback Character Encoding:">
 <!ENTITY languages.customize.Fallback.accesskey   "C">
 <!ENTITY languages.customize.Fallback.desc        "This character encoding is used for legacy content that fails to declare its encoding.">
+
+<!ENTITY languages.customize.Fallback.auto        "Default for Current Locale">
+<!-- LOCALIZATION NOTE (languages.customize.Fallback.arabic):
+     Translate "Arabic" as an adjective for an encoding, not as the name of the language. -->
+<!ENTITY languages.customize.Fallback.arabic      "Arabic">
+<!ENTITY languages.customize.Fallback.baltic      "Baltic">
+<!ENTITY languages.customize.Fallback.ceiso       "Central European, ISO">
+<!ENTITY languages.customize.Fallback.cewindows   "Central European, Microsoft">
+<!-- LOCALIZATION NOTE (languages.customize.Fallback.simplified):
+     Translate "Chinese" as an adjective for an encoding, not as the name of the language. -->
+<!ENTITY languages.customize.Fallback.simplified  "Chinese, Simplified">
+<!-- LOCALIZATION NOTE (languages.customize.Fallback.traditional):
+     Translate "Chinese" as an adjective for an encoding, not as the name of the language. -->
+<!ENTITY languages.customize.Fallback.traditional "Chinese, Traditional">
+<!ENTITY languages.customize.Fallback.cyrillic    "Cyrillic">
+<!-- LOCALIZATION NOTE (languages.customize.Fallback.greek):
+     Translate "Greek" as an adjective for an encoding, not as the name of the language. -->
+<!ENTITY languages.customize.Fallback.greek       "Greek">
+<!-- LOCALIZATION NOTE (languages.customize.Fallback.hebrew):
+     Translate "Hebrew" as an adjective for an encoding, not as the name of the language. -->
+<!ENTITY languages.customize.Fallback.hebrew      "Hebrew">
+<!-- LOCALIZATION NOTE (languages.customize.Fallback.japanese):
+     Translate "Japanese" as an adjective for an encoding, not as the name of the language. -->
+<!ENTITY languages.customize.Fallback.japanese    "Japanese">
+<!-- LOCALIZATION NOTE (languages.customize.Fallback.korean):
+     Translate "Korean" as an adjective for an encoding, not as the name of the language. -->
+<!ENTITY languages.customize.Fallback.korean      "Korean">
+<!-- LOCALIZATION NOTE (languages.customize.Fallback.thai):
+     Translate "Thai" as an adjective for an encoding, not as the name of the language. -->
+<!ENTITY languages.customize.Fallback.thai        "Thai">
+<!-- LOCALIZATION NOTE (languages.customize.Fallback.turkish):
+     Translate "Turkish" as an adjective for an encoding, not as the name of the language. -->
+<!ENTITY languages.customize.Fallback.turkish     "Turkish">
+<!-- LOCALIZATION NOTE (languages.customize.Fallback.vietnamese):
+     Translate "Vietnamese" as an adjective for an encoding, not as the name of the language. -->
+<!ENTITY languages.customize.Fallback.vietnamese  "Vietnamese">
+<!ENTITY languages.customize.Fallback.other       "Other (incl. Western European)">
--- a/browser/themes/shared/devtools/webconsole.inc.css
+++ b/browser/themes/shared/devtools/webconsole.inc.css
@@ -61,33 +61,42 @@ a {
 }
 
 .message > .repeats[value="1"] {
   display: none;
 }
 
 .message > .location {
   -moz-margin-start: 6px;
+  display: flex;
   flex: 0 0 auto;
   align-self: flex-start;
+  justify-content: flex-end;
   width: 10em;
   margin-top: 4px;
-  text-align: end;
   color: -moz-nativehyperlinktext;
-  text-overflow: ellipsis;
   text-decoration: none;
-  overflow: hidden;
-  white-space: nowrap;
 }
 
 .message > .location:hover,
 .message > .location:focus {
   text-decoration: underline;
 }
 
+.message > .location > .filename {
+  text-overflow: ellipsis;
+  text-align: end;
+  overflow: hidden;
+  white-space: nowrap;
+}
+
+.message > .location > .line-number {
+  flex: 0 0 auto;
+}
+
 .jsterm-input-container {
   background: white;
 }
 
 #output-wrapper {
   background: #fff;
   color: #000;
   direction: ltr;
--- a/build/docs/mozinfo.rst
+++ b/build/docs/mozinfo.rst
@@ -61,16 +61,23 @@ bits
 
 crashreporter
    Whether the crash reporter is enabled for this build.
 
    Values are ``true`` and ``false``.
 
    Always defined.
 
+datareporting
+  Whether data reporting (MOZ_DATA_REPORTING) is enabled for this build.
+
+   Values are ``true`` and ``false``.
+
+   Always defined.
+
 debug
    Whether this is a debug build.
 
    Values are ``true`` and ``false``.
 
    Always defined.
 
 mozconfig
--- a/configure.in
+++ b/configure.in
@@ -5511,65 +5511,68 @@ fi
 if test -n "$MOZ_TREMOR"; then
     AC_DEFINE(MOZ_TREMOR)
 fi
 
 if test -n "$MOZ_OPUS"; then
     AC_DEFINE(MOZ_OPUS)
 fi
 
-dnl ========================================================
-dnl = Check alsa availability on Linux if using sydneyaudio
-dnl ========================================================
-
-dnl If using sydneyaudio with Linux, ensure that the alsa library is available
+dnl ====================================================
+dnl = Check alsa availability on Linux if using libcubeb
+dnl ====================================================
+
+dnl If using libcubeb with Linux, ensure that the alsa library is available
 if test -n "$MOZ_CUBEB" -a "$OS_TARGET" = "Linux"; then
     MOZ_ALSA=1
 fi
 
 MOZ_ARG_ENABLE_BOOL(alsa,
 [  --enable-alsa          Enable Alsa support (default on Linux)],
-MOZ_ALSA=1,
-MOZ_ALSA=)
+   MOZ_ALSA=1,
+   MOZ_ALSA=)
 
 if test -n "$MOZ_ALSA"; then
     AC_DEFINE(MOZ_CUBEB)
     PKG_CHECK_MODULES(MOZ_ALSA, alsa, ,
          [echo "$MOZ_ALSA_PKG_ERRORS"
           AC_MSG_ERROR([Need alsa for Ogg, Wave or WebM decoding on Linux.  Disable with --disable-ogg --disable-wave --disable-webm.  (On Ubuntu, you might try installing the package libasound2-dev.)])])
 fi
 
 AC_SUBST(MOZ_ALSA)
 AC_SUBST(MOZ_ALSA_CFLAGS)
 AC_SUBST(MOZ_ALSA_LIBS)
 
 dnl ========================================================
-dnl = Enable PulseAudio
-dnl ========================================================
-
-MOZ_ARG_ENABLE_BOOL(pulseaudio,
-[  --enable-pulseaudio          Enable PulseAudio support (experimental)],
-MOZ_PULSEAUDIO=1,
-MOZ_PULSEAUDIO=)
+dnl = Disable PulseAudio
+dnl ========================================================
+
+dnl If using libcubeb with Linux, ensure that the PA library is available
+if test -n "$MOZ_CUBEB" -a "$OS_TARGET" = "Linux" -a -z "$MOZ_B2G"; then
+    MOZ_PULSEAUDIO=1
+fi
+
+MOZ_ARG_DISABLE_BOOL(pulseaudio,
+[  --disable-pulseaudio          Disable PulseAudio support],
+   MOZ_PULSEAUDIO=,
+   MOZ_PULSEAUDIO=1)
 
 if test -n "$MOZ_PULSEAUDIO"; then
     AC_DEFINE(MOZ_CUBEB)
     if test -z "$gonkdir"; then
         PKG_CHECK_MODULES(MOZ_PULSEAUDIO, libpulse, ,
              [echo "$MOZ_PULSEAUDIO_PKG_ERRORS"
               AC_MSG_ERROR([pulseaudio audio backend requires libpulse development package])])
     else
         MOZ_PULSEAUDIO_CFLAGS="-I$gonkdir/external/pulseaudio/pulseaudio/src"
-        MOZ_PULSEAUDIO_LIBS="-lpulse"
     fi
 fi
 
 AC_SUBST(MOZ_PULSEAUDIO)
 AC_SUBST(MOZ_PULSEAUDIO_CFLAGS)
-AC_SUBST(MOZ_PULSEAUDIO_LIBS)
 
 dnl ========================================================
 dnl = Enable GStreamer
 dnl ========================================================
 if test "$OS_TARGET" = "Linux"; then
   MOZ_GSTREAMER=1
 fi
 
@@ -9124,17 +9127,17 @@ ac_configure_args="$ac_configure_args --
 
 MOZ_ARG_WITH_STRING(intl-api,
 [  --with-intl-api, --with-intl-api=build, --without-intl-api
     Determine the status of the ECMAScript Internationalization API.  The first
     (or lack of any of these) builds and exposes the API.  The second builds it
     but doesn't use ICU or expose the API to script.  The third doesn't build
     ICU at all.],
     WITH_INTL="--with-intl-api=$withval"
-])
+)
 if test -z "$WITH_INTL"; then
 if test "$MOZ_BUILD_APP" = "browser"; then
     WITH_INTL="--with-intl-api"
 else
     # Internationalization isn't built or exposed by default in non-desktop
     # builds.  Bugs to enable:
     #
     #   Android:  bug 864843
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -70,16 +70,17 @@
 #include "mozilla/Assertions.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ImageData.h"
 #include "mozilla/dom/PBrowserParent.h"
 #include "mozilla/dom/TypedArray.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/PathHelpers.h"
+#include "mozilla/gfx/DataSurfaceHelpers.h"
 #include "mozilla/ipc/DocumentRendererParent.h"
 #include "mozilla/ipc/PDocumentRendererParent.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/unused.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsWrapperCacheInlines.h"
@@ -1055,50 +1056,30 @@ CanvasRenderingContext2D::Render(gfxCont
 
 void
 CanvasRenderingContext2D::GetImageBuffer(uint8_t** aImageBuffer,
                                          int32_t* aFormat)
 {
   *aImageBuffer = nullptr;
   *aFormat = 0;
 
-  nsRefPtr<gfxASurface> surface;
-  nsresult rv = GetThebesSurface(getter_AddRefs(surface));
-  if (NS_FAILED(rv)) {
-    return;
-  }
-
-  static const fallible_t fallible = fallible_t();
-  uint8_t* imageBuffer = new (fallible) uint8_t[mWidth * mHeight * 4];
-  if (!imageBuffer) {
+  EnsureTarget();
+  RefPtr<SourceSurface> snapshot = mTarget->Snapshot();
+  if (!snapshot) {
     return;
   }
 
-  nsRefPtr<gfxImageSurface> imgsurf =
-    new gfxImageSurface(imageBuffer,
-                        gfxIntSize(mWidth, mHeight),
-                        mWidth * 4,
-                        gfxImageFormatARGB32);
-
-  if (!imgsurf || imgsurf->CairoStatus()) {
-    delete[] imageBuffer;
+  RefPtr<DataSourceSurface> data = snapshot->GetDataSurface();
+  if (!data) {
     return;
   }
 
-  nsRefPtr<gfxContext> ctx = new gfxContext(imgsurf);
-  if (!ctx || ctx->HasError()) {
-    delete[] imageBuffer;
-    return;
-  }
-
-  ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
-  ctx->SetSource(surface, gfxPoint(0, 0));
-  ctx->Paint();
-
-  *aImageBuffer = imageBuffer;
+  MOZ_ASSERT(data->GetSize() == IntSize(mWidth, mHeight));
+
+  *aImageBuffer = SurfaceToPackedBGRA(data);
   *aFormat = imgIEncoder::INPUT_FORMAT_HOSTARGB;
 }
 
 NS_IMETHODIMP
 CanvasRenderingContext2D::GetInputStream(const char *aMimeType,
                                          const PRUnichar *aEncoderOptions,
                                          nsIInputStream **aStream)
 {
@@ -2573,17 +2554,17 @@ CanvasRenderingContext2D::DrawOrMeasureT
   // This is only needed to know if we can know the drawing bounding box easily.
   bool doDrawShadow = NeedToDrawShadow();
 
   CanvasBidiProcessor processor;
 
   GetAppUnitsValues(&processor.mAppUnitsPerDevPixel, nullptr);
   processor.mPt = gfxPoint(aX, aY);
   processor.mThebes =
-    new gfxContext(gfxPlatform::GetPlatform()->ScreenReferenceSurface());
+    new gfxContext(gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget());
 
   // If we don't have a target then we don't have a transform. A target won't
   // be needed in the case where we're measuring the text size. This allows
   // to avoid creating a target if it's only being used to measure text sizes.
   if (mTarget) {
     Matrix matrix = mTarget->GetTransform();
     processor.mThebes->SetMatrix(gfxMatrix(matrix._11, matrix._12, matrix._21, matrix._22, matrix._31, matrix._32));
   }
@@ -3296,16 +3277,19 @@ CanvasRenderingContext2D::DrawWindow(nsG
     renderDocFlags |= nsIPresShell::RENDER_DRAWWINDOW_NOT_FLUSHING;
   }
 
   // gfxContext-over-Azure may modify the DrawTarget's transform, so
   // save and restore it
   Matrix matrix = mTarget->GetTransform();
   double sw = matrix._11 * w;
   double sh = matrix._22 * h;
+  if (!sw || !sh) {
+    return;
+  }
   nsRefPtr<gfxContext> thebes;
   nsRefPtr<gfxASurface> drawSurf;
   RefPtr<DrawTarget> drawDT;
   if (gfxPlatform::GetPlatform()->SupportsAzureContentForDrawTarget(mTarget)) {
     thebes = new gfxContext(mTarget);
     thebes->SetMatrix(gfxMatrix(matrix._11, matrix._12, matrix._21,
                                 matrix._22, matrix._31, matrix._32));
   } else if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
@@ -3358,16 +3342,21 @@ CanvasRenderingContext2D::DrawWindow(nsG
 
       source =
         mTarget->CreateSourceSurfaceFromData(data->GetData(),
                                              data->GetSize(),
                                              data->Stride(),
                                              data->GetFormat());
     }
 
+    if (!source) {
+      error.Throw(NS_ERROR_FAILURE);
+      return;
+    }
+
     mgfx::Rect destRect(0, 0, w, h);
     mgfx::Rect sourceRect(0, 0, sw, sh);
     mTarget->DrawSurface(source, destRect, sourceRect,
                          DrawSurfaceOptions(mgfx::FILTER_POINT),
                          DrawOptions(1.0f, OP_SOURCE, AA_NONE));
     mTarget->Flush();
   } else {
     mTarget->SetTransform(matrix);
--- a/content/html/content/src/HTMLCanvasElement.cpp
+++ b/content/html/content/src/HTMLCanvasElement.cpp
@@ -28,16 +28,17 @@
 #include "nsIScriptSecurityManager.h"
 #include "nsITimer.h"
 #include "nsIWritablePropertyBag2.h"
 #include "nsIXPConnect.h"
 #include "nsJSUtils.h"
 #include "nsMathUtils.h"
 #include "nsNetUtil.h"
 #include "nsStreamUtils.h"
+#include "ActiveLayerTracker.h"
 
 #ifdef MOZ_WEBGL
 #include "../canvas/src/WebGL2Context.h"
 #endif
 
 using namespace mozilla::layers;
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Canvas)
@@ -830,17 +831,17 @@ void
 HTMLCanvasElement::InvalidateCanvasContent(const gfx::Rect* damageRect)
 {
   // We don't need to flush anything here; if there's no frame or if
   // we plan to reframe we don't need to invalidate it anyway.
   nsIFrame *frame = GetPrimaryFrame();
   if (!frame)
     return;
 
-  frame->MarkLayersActive(nsChangeHint(0));
+  ActiveLayerTracker::NotifyContentChange(frame);
 
   Layer* layer = nullptr;
   if (damageRect) {
     nsIntSize size = GetWidthHeight();
     if (size.width != 0 && size.height != 0) {
 
       gfx::Rect realRect(*damageRect);
       realRect.RoundOut();
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -78,16 +78,17 @@
 #include "nsArrayUtils.h"
 #include "nsIEffectiveTLDService.h"
 
 #include "nsIPrompt.h"
 //AHMED 12-2
 #include "nsBidiUtils.h"
 
 #include "mozilla/dom/EncodingUtils.h"
+#include "mozilla/dom/FallbackEncoding.h"
 #include "nsIEditingSession.h"
 #include "nsIEditor.h"
 #include "nsNodeInfoManager.h"
 #include "nsIPlaintextEditor.h"
 #include "nsIHTMLEditor.h"
 #include "nsIEditorStyleSheets.h"
 #include "nsIInlineSpellChecker.h"
 #include "nsRange.h"
@@ -440,36 +441,23 @@ nsHTMLDocument::TryParentCharset(nsIDocS
     }
 
     aCharset.Assign(parentCharset);
     aCharsetSource = kCharsetFromParentFrame;
   }
 }
 
 void
-nsHTMLDocument::TryWeakDocTypeDefault(int32_t& aCharsetSource,
-                                      nsACString& aCharset)
+nsHTMLDocument::TryFallback(int32_t& aCharsetSource, nsACString& aCharset)
 {
-  if (kCharsetFromWeakDocTypeDefault <= aCharsetSource)
+  if (kCharsetFromFallback <= aCharsetSource)
     return;
 
-  const nsAdoptingCString& defCharset =
-    Preferences::GetLocalizedCString("intl.charset.default");
-
-  // Don't let the user break things by setting intl.charset.default to
-  // not a rough ASCII superset
-  nsAutoCString canonical;
-  if (EncodingUtils::FindEncodingForLabel(defCharset, canonical) &&
-      EncodingUtils::IsAsciiCompatible(canonical)) {
-    aCharset = canonical;
-  } else {
-    aCharset.AssignLiteral("windows-1252");
-  }
-  aCharsetSource = kCharsetFromWeakDocTypeDefault;
-  return;
+  aCharsetSource = kCharsetFromFallback;
+  FallbackEncoding::FromLocale(aCharset);
 }
 
 void
 nsHTMLDocument::SetDocumentCharacterSet(const nsACString& aCharSetID)
 {
   nsDocument::SetDocumentCharacterSet(aCharSetID);
   // Make sure to stash this charset on our channel as needed if it's a wyciwyg
   // channel.
@@ -637,17 +625,17 @@ nsHTMLDocument::StartDocumentLoad(const 
   
   // For error reporting
   nsHtml5TreeOpExecutor* executor = nullptr;
   if (loadAsHtml5) {
     executor = static_cast<nsHtml5TreeOpExecutor*> (mParser->GetContentSink());
   }
 
   if (!IsHTML() || !docShell) { // no docshell for text/html XHR
-    charsetSource = IsHTML() ? kCharsetFromWeakDocTypeDefault
+    charsetSource = IsHTML() ? kCharsetFromFallback
                              : kCharsetFromDocTypeDefault;
     charset.AssignLiteral("UTF-8");
     TryChannelCharset(aChannel, charsetSource, charset, executor);
     parserCharsetSource = charsetSource;
     parserCharset = charset;
   } else {
     NS_ASSERTION(docShell, "Unexpected null value");
 
@@ -678,17 +666,17 @@ nsHTMLDocument::StartDocumentLoad(const 
 
     TryHintCharset(muCV, charsetSource, charset); // XXX mailnews-only
     TryParentCharset(docShell, charsetSource, charset);
 
     if (cachingChan && !urlSpec.IsEmpty()) {
       TryCacheCharset(cachingChan, charsetSource, charset);
     }
 
-    TryWeakDocTypeDefault(charsetSource, charset);
+    TryFallback(charsetSource, charset);
 
     if (wyciwygChannel) {
       // We know for sure that the parser needs to be using UTF16.
       parserCharset = "UTF-16";
       parserCharsetSource = charsetSource < kCharsetFromChannel ?
         kCharsetFromChannel : charsetSource;
         
       nsAutoCString cachedCharset;
--- a/content/html/document/src/nsHTMLDocument.h
+++ b/content/html/document/src/nsHTMLDocument.h
@@ -308,18 +308,17 @@ protected:
                             nsIDocShell*  aDocShell,
                             int32_t& aCharsetSource,
                             nsACString& aCharset);
   static void TryCacheCharset(nsICachingChannel* aCachingChannel,
                                 int32_t& aCharsetSource,
                                 nsACString& aCharset);
   void TryParentCharset(nsIDocShell*  aDocShell,
                         int32_t& charsetSource, nsACString& aCharset);
-  static void TryWeakDocTypeDefault(int32_t& aCharsetSource,
-                                    nsACString& aCharset);
+  static void TryFallback(int32_t& aCharsetSource, nsACString& aCharset);
 
   // Override so we can munge the charset on our wyciwyg channel as needed.
   virtual void SetDocumentCharacterSet(const nsACString& aCharSetID) MOZ_OVERRIDE;
 
   // Tracks if we are currently processing any document.write calls (either
   // implicit or explicit). Note that if a write call writes out something which
   // would block the parser, then mWriteLevel will be incorrect until the parser
   // finishes processing that script.
--- a/content/media/VideoUtils.cpp
+++ b/content/media/VideoUtils.cpp
@@ -5,16 +5,18 @@
 #include "VideoUtils.h"
 #include "MediaResource.h"
 #include "mozilla/dom/TimeRanges.h"
 #include "nsMathUtils.h"
 #include "nsSize.h"
 
 #include <stdint.h>
 
+namespace mozilla {
+
 // Converts from number of audio frames to microseconds, given the specified
 // audio rate.
 CheckedInt64 FramesToUsecs(int64_t aFrames, uint32_t aRate) {
   return (CheckedInt64(aFrames) * USECS_PER_S) / aRate;
 }
 
 // Converts from microseconds to number of audio frames, given the specified
 // audio rate.
@@ -84,8 +86,19 @@ void GetEstimatedBufferedTimeRanges(mozi
       aOutBuffered->Add(double(startUs) / USECS_PER_S,
                         double(endUs) / USECS_PER_S);
     }
     startOffset = aStream->GetNextCachedData(endOffset);
   }
   return;
 }
 
+bool
+IsVideoContentType(const nsCString& aContentType)
+{
+  NS_NAMED_LITERAL_CSTRING(video, "video");
+  if (FindInReadable(video, aContentType)) {
+    return true;
+  }
+  return false;
+}
+
+} // end namespace mozilla
\ No newline at end of file
--- a/content/media/VideoUtils.h
+++ b/content/media/VideoUtils.h
@@ -70,38 +70,35 @@ private:
   ReentrantMonitorConditionallyEnter& operator =(const ReentrantMonitorConditionallyEnter&);
   static void* operator new(size_t) CPP_THROW_NEW;
   static void operator delete(void*);
 
   ReentrantMonitor* mReentrantMonitor;
 };
 
 // Shuts down a thread asynchronously.
-class ShutdownThreadEvent : public nsRunnable 
+class ShutdownThreadEvent : public nsRunnable
 {
 public:
   ShutdownThreadEvent(nsIThread* aThread) : mThread(aThread) {}
   ~ShutdownThreadEvent() {}
   NS_IMETHOD Run() MOZ_OVERRIDE {
     mThread->Shutdown();
     mThread = nullptr;
     return NS_OK;
   }
 private:
   nsCOMPtr<nsIThread> mThread;
 };
 
 class MediaResource;
-} // namespace mozilla
 
-namespace mozilla {
 namespace dom {
 class TimeRanges;
 }
-}
 
 // Estimates the buffered ranges of a MediaResource using a simple
 // (byteOffset/length)*duration method. Probably inaccurate, but won't
 // do file I/O, and can be used when we don't have detailed knowledge
 // of the byte->time mapping of a resource. aDurationUsecs is the duration
 // of the media in microseconds. Estimated buffered ranges are stored in
 // aOutBuffered. Ranges are 0-normalized, i.e. in the range of (0,duration].
 void GetEstimatedBufferedTimeRanges(mozilla::MediaResource* aStream,
@@ -145,9 +142,13 @@ void ScaleDisplayByAspectRatio(nsIntSize
 #if (defined(XP_WIN) || defined(XP_MACOSX) || defined(LINUX)) && \
     !defined(MOZ_ASAN)
 #define MEDIA_THREAD_STACK_SIZE (128 * 1024)
 #else
 // All other platforms use their system defaults.
 #define MEDIA_THREAD_STACK_SIZE nsIThreadManager::DEFAULT_STACK_SIZE
 #endif
 
+bool IsVideoContentType(const nsCString& aContentType);
+
+} // end namespace mozilla
+
 #endif
--- a/content/media/mediasource/MediaSource.cpp
+++ b/content/media/mediasource/MediaSource.cpp
@@ -318,21 +318,22 @@ MediaSource::EndOfStreamInternal(const O
     //   HAVE_NOTHING -> run "unsupported" steps of resource fetch
     // > HAVE_NOTHING -> run "corrupted" steps of resource fetch
     break;
   default:
     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
   }
 }
 
-static const char* const gMediaSourceTypes[5] = {
+static const char* const gMediaSourceTypes[6] = {
   "video/webm",
   "audio/webm",
   "video/mp4",
   "audio/mp4",
+  "audio/mpeg",
   nullptr
 };
 
 /* static */ bool
 MediaSource::IsTypeSupportedInternal(const nsAString& aType, ErrorResult& aRv)
 {
   if (aType.IsEmpty()) {
     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
--- a/content/media/test/Makefile.in
+++ b/content/media/test/Makefile.in
@@ -170,36 +170,43 @@ endif
 #   test_preload_suspend.html
 # Bug 567954 and Bug 574586:
 #   test_mixed_principals.html
 # Disabled since we don't play Wave files standalone, for now
 #		test_audioDocumentTitle.html
 # Bug 751539:
 #		test_played.html
 
+# Disabled since it causes random memory corruption, bug 921622, so
+# the best-case scenario is that it results in random crashes while it
+# runs, like bug 918417, bug 920827, bug 923996, bug 928225, bug 929521
+# bug 930982, bug 932193. Worst-case but quite likely, it causes random
+# crashes and failures in other tests which run after it. Don't even think
+# about reenabling it on any platform unless you *know* that you have fixed
+# that. Then don't think about reenabling it on Windows until you know that
+# you have fixed the timeouts of bug 832768, bug 814533, bug 840742
+#		test_playback_rate.html \
+
 # The below tests are disabled on Windows due to frequent timeouts.
 # Bug 832768 and Bug 864682:
 #		test_buffered.html
 #		test_bug465498.html
 # Bug 707777:
 #		test_bug493187.html
 # Bug 897843:
 #		test_media_selection.html
 # Bug 832678, bug 795271, and bug 857424
 #		test_seek.html
-# Bug 832768, bug 814533, bug 840742
-#		test_playback_rate.html
 ifneq ($(OS_ARCH), WINNT)
 MOCHITEST_FILES += \
 		test_buffered.html \
 		test_bug465498.html \
 		test_bug493187.html \
 		test_media_selection.html \
 		test_seek.html \
-		test_playback_rate.html \
 		$(NULL)
 endif
 
 # sample files
 MOCHITEST_FILES += \
 		320x240.ogv \
 		448636.ogv \
 		audio-overhang.ogg \
--- a/content/media/wmf/WMFReader.cpp
+++ b/content/media/wmf/WMFReader.cpp
@@ -126,26 +126,16 @@ WMFReader::InitializeDXVA()
     return false;
   }
 
   mDXVA2Manager = DXVA2Manager::Create();
 
   return mDXVA2Manager != nullptr;
 }
 
-static bool
-IsVideoContentType(const nsCString& aContentType)
-{
-  NS_NAMED_LITERAL_CSTRING(video, "video");
-  if (FindInReadable(video, aContentType)) {
-    return true;
-  }
-  return false;
-}
-
 nsresult
 WMFReader::Init(MediaDecoderReader* aCloneDonor)
 {
   NS_ASSERTION(NS_IsMainThread(), "Must be on main thread.");
 
   nsresult rv = WMFDecoder::LoadDLLs();
   NS_ENSURE_SUCCESS(rv, rv);
 
--- a/content/svg/content/src/SVGCircleElement.cpp
+++ b/content/svg/content/src/SVGCircleElement.cpp
@@ -1,20 +1,23 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/SVGCircleElement.h"
+#include "mozilla/gfx/2D.h"
 #include "nsGkAtoms.h"
 #include "gfxContext.h"
 #include "mozilla/dom/SVGCircleElementBinding.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Circle)
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace dom {
 
 JSObject*
 SVGCircleElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
   return SVGCircleElementBinding::Wrap(aCx, aScope, this);
 }
@@ -85,10 +88,25 @@ SVGCircleElement::ConstructPath(gfxConte
   float x, y, r;
 
   GetAnimatedLengthValues(&x, &y, &r, nullptr);
 
   if (r > 0.0f)
     aCtx->Arc(gfxPoint(x, y), r, 0, 2*M_PI);
 }
 
+TemporaryRef<Path>
+SVGCircleElement::BuildPath()
+{
+  RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
+
+  float x, y, r;
+  GetAnimatedLengthValues(&x, &y, &r, nullptr);
+
+  if (r > 0.0f) {
+    pathBuilder->Arc(Point(x, y), r, 0, Float(2*M_PI));
+  }
+
+  return pathBuilder->Finish();
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/content/svg/content/src/SVGCircleElement.h
+++ b/content/svg/content/src/SVGCircleElement.h
@@ -27,16 +27,17 @@ protected:
                                             already_AddRefed<nsINodeInfo> aNodeInfo));
 
 public:
   // nsSVGSVGElement methods:
   virtual bool HasValidDimensions() const MOZ_OVERRIDE;
 
   // nsSVGPathGeometryElement methods:
   virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
+  virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<SVGAnimatedLength> Cx();
   already_AddRefed<SVGAnimatedLength> Cy();
   already_AddRefed<SVGAnimatedLength> R();
 
--- a/content/svg/content/src/SVGContentUtils.cpp
+++ b/content/svg/content/src/SVGContentUtils.cpp
@@ -560,8 +560,30 @@ SVGContentUtils::ParseInteger(const nsAS
     ++iter;
   } while (iter != end);
 
   aValue = int32_t(clamped(sign * value,
                            int64_t(std::numeric_limits<int32_t>::min()),
                            int64_t(std::numeric_limits<int32_t>::max())));
   return true;
 }
+
+float
+SVGContentUtils::CoordToFloat(nsPresContext *aPresContext,
+                              nsSVGElement *aContent,
+                              const nsStyleCoord &aCoord)
+{
+  switch (aCoord.GetUnit()) {
+  case eStyleUnit_Factor:
+    // user units
+    return aCoord.GetFactorValue();
+
+  case eStyleUnit_Coord:
+    return nsPresContext::AppUnitsToFloatCSSPixels(aCoord.GetCoordValue());
+
+  case eStyleUnit_Percent: {
+    SVGSVGElement* ctx = aContent->GetCtx();
+    return ctx ? aCoord.GetPercentValue() * ctx->GetLength(SVGContentUtils::XY) : 0.0f;
+  }
+  default:
+    return 0.0f;
+  }
+}
--- a/content/svg/content/src/SVGContentUtils.h
+++ b/content/svg/content/src/SVGContentUtils.h
@@ -11,17 +11,19 @@
 #include <math.h>
 
 #include "gfxMatrix.h"
 #include "mozilla/RangedPtr.h"
 
 class nsIContent;
 class nsIDocument;
 class nsIFrame;
+class nsPresContext;
 class nsStyleContext;
+class nsStyleCoord;
 class nsSVGElement;
 
 namespace mozilla {
 class SVGAnimatedPreserveAspectRatio;
 class SVGPreserveAspectRatio;
 namespace dom {
 class Element;
 class SVGSVGElement;
@@ -164,11 +166,20 @@ public:
 
   /**
    * Parse an integer of the form:
    * integer ::= [+-]? [0-9]+
    * Parsing fails if the number cannot be represented by an int32_t.
    */
   static bool
   ParseInteger(const nsAString& aString, int32_t& aValue);
+
+  /**
+   * Converts an nsStyleCoord into a userspace value.  Handles units
+   * Factor (straight userspace), Coord (dimensioned), and Percent (of
+   * aContent's SVG viewport)
+   */
+  static float CoordToFloat(nsPresContext *aPresContext,
+                            nsSVGElement *aContent,
+                            const nsStyleCoord &aCoord);
 };
 
 #endif
--- a/content/svg/content/src/SVGEllipseElement.cpp
+++ b/content/svg/content/src/SVGEllipseElement.cpp
@@ -1,19 +1,23 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/SVGEllipseElement.h"
 #include "mozilla/dom/SVGEllipseElementBinding.h"
+#include "mozilla/gfx/2D.h"
+#include "mozilla/gfx/PathHelpers.h"
 #include "gfxContext.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Ellipse)
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace dom {
 
 JSObject*
 SVGEllipseElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
   return SVGEllipseElementBinding::Wrap(aCx, aScope, this);
 }
@@ -95,10 +99,25 @@ SVGEllipseElement::ConstructPath(gfxCont
 
   GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr);
 
   if (rx > 0.0f && ry > 0.0f) {
     aCtx->Ellipse(gfxPoint(x, y), gfxSize(2.0*rx, 2.0*ry));
   }
 }
 
+TemporaryRef<Path>
+SVGEllipseElement::BuildPath()
+{
+  RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
+
+  float x, y, rx, ry;
+  GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr);
+
+  if (rx > 0.0f && ry > 0.0f) {
+    AppendEllipseToPath(pathBuilder, Point(x, y), Size(2.0*rx, 2.0*ry));
+  }
+
+  return pathBuilder->Finish();
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/content/svg/content/src/SVGEllipseElement.h
+++ b/content/svg/content/src/SVGEllipseElement.h
@@ -27,16 +27,17 @@ protected:
                                              already_AddRefed<nsINodeInfo> aNodeInfo));
 
 public:
   // nsSVGSVGElement methods:
   virtual bool HasValidDimensions() const MOZ_OVERRIDE;
 
   // nsSVGPathGeometryElement methods:
   virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
+  virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<SVGAnimatedLength> Cx();
   already_AddRefed<SVGAnimatedLength> Cy();
   already_AddRefed<SVGAnimatedLength> Rx();
   already_AddRefed<SVGAnimatedLength> Ry();
--- a/content/svg/content/src/SVGImageElement.cpp
+++ b/content/svg/content/src/SVGImageElement.cpp
@@ -1,26 +1,29 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Util.h"
 
 #include "mozilla/dom/SVGImageElement.h"
+#include "mozilla/gfx/2D.h"
 #include "nsCOMPtr.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 #include "imgINotificationObserver.h"
 #include "gfxContext.h"
 #include "mozilla/dom/SVGImageElementBinding.h"
 #include "nsContentUtils.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Image)
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace dom {
 
 JSObject*
 SVGImageElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
   return SVGImageElementBinding::Wrap(aCx, aScope, this);
 }
@@ -231,16 +234,39 @@ SVGImageElement::ConstructPath(gfxContex
   GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
 
   if (width <= 0 || height <= 0)
     return;
 
   aCtx->Rectangle(gfxRect(x, y, width, height));
 }
 
+TemporaryRef<Path>
+SVGImageElement::BuildPath()
+{
+  // We get called in order to get bounds for this element, and for
+  // hit-testing against it. For that we just pretend to be a rectangle.
+
+  RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
+
+  float x, y, width, height;
+  GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
+
+  if (width <= 0 || height <= 0) {
+    Rect r(x, y, width, height);
+    pathBuilder->MoveTo(r.TopLeft());
+    pathBuilder->LineTo(r.TopRight());
+    pathBuilder->LineTo(r.BottomRight());
+    pathBuilder->LineTo(r.BottomLeft());
+    pathBuilder->Close();
+  }
+
+  return pathBuilder->Finish();
+}
+
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
 /* virtual */ bool
 SVGImageElement::HasValidDimensions() const
 {
   return mLengthAttributes[ATTR_WIDTH].IsExplicitlySet() &&
          mLengthAttributes[ATTR_WIDTH].GetAnimValInSpecifiedUnits() > 0 &&
--- a/content/svg/content/src/SVGImageElement.h
+++ b/content/svg/content/src/SVGImageElement.h
@@ -50,16 +50,17 @@ public:
   virtual void UnbindFromTree(bool aDeep, bool aNullParent) MOZ_OVERRIDE;
 
   virtual nsEventStates IntrinsicState() const MOZ_OVERRIDE;
 
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* name) const MOZ_OVERRIDE;
 
   // nsSVGPathGeometryElement methods:
   virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
+  virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
 
   // nsSVGSVGElement methods:
   virtual bool HasValidDimensions() const MOZ_OVERRIDE;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   nsresult CopyInnerTo(mozilla::dom::Element* aDest);
 
--- a/content/svg/content/src/SVGLineElement.cpp
+++ b/content/svg/content/src/SVGLineElement.cpp
@@ -1,19 +1,22 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/SVGLineElement.h"
 #include "mozilla/dom/SVGLineElementBinding.h"
+#include "mozilla/gfx/2D.h"
 #include "gfxContext.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Line)
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace dom {
 
 JSObject*
 SVGLineElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
   return SVGLineElementBinding::Wrap(aCx, aScope, this);
 }
@@ -110,10 +113,24 @@ SVGLineElement::ConstructPath(gfxContext
   float x1, y1, x2, y2;
 
   GetAnimatedLengthValues(&x1, &y1, &x2, &y2, nullptr);
 
   aCtx->MoveTo(gfxPoint(x1, y1));
   aCtx->LineTo(gfxPoint(x2, y2));
 }
 
+TemporaryRef<Path>
+SVGLineElement::BuildPath()
+{
+  RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
+
+  float x1, y1, x2, y2;
+  GetAnimatedLengthValues(&x1, &y1, &x2, &y2, nullptr);
+
+  pathBuilder->MoveTo(Point(x1, y1));
+  pathBuilder->LineTo(Point(x2, y2));
+
+  return pathBuilder->Finish();
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/content/svg/content/src/SVGLineElement.h
+++ b/content/svg/content/src/SVGLineElement.h
@@ -29,16 +29,17 @@ protected:
 public:
   // nsIContent interface
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* name) const MOZ_OVERRIDE;
 
   // nsSVGPathGeometryElement methods:
   virtual bool IsMarkable() MOZ_OVERRIDE { return true; }
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks) MOZ_OVERRIDE;
   virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
+  virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
   // WebIDL
   already_AddRefed<SVGAnimatedLength> X1();
   already_AddRefed<SVGAnimatedLength> Y1();
   already_AddRefed<SVGAnimatedLength> X2();
   already_AddRefed<SVGAnimatedLength> Y2();
--- a/content/svg/content/src/SVGPathData.cpp
+++ b/content/svg/content/src/SVGPathData.cpp
@@ -11,16 +11,17 @@
 #include "mozilla/gfx/Types.h"
 #include "mozilla/gfx/Point.h"
 #include "mozilla/RefPtr.h"
 #include "nsError.h"
 #include "nsString.h"
 #include "nsSVGPathDataParser.h"
 #include "nsSVGPathGeometryElement.h" // for nsSVGMark
 #include <stdarg.h>
+#include "nsStyleConsts.h"
 #include "SVGContentUtils.h"
 #include "SVGPathSegUtils.h"
 #include "gfxContext.h"
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 
@@ -212,94 +213,113 @@ SVGPathData::GetPathSegAtLength(float aD
 
 /**
  * The SVG spec says we have to paint stroke caps for zero length subpaths:
  *
  *   http://www.w3.org/TR/SVG11/implnote.html#PathElementImplementationNotes
  *
  * Cairo only does this for |stroke-linecap: round| and not for
  * |stroke-linecap: square| (since that's what Adobe Acrobat has always done).
+ * Most likely the other backends that DrawTarget uses have the same behavior.
  *
  * To help us conform to the SVG spec we have this helper function to draw an
  * approximation of square caps for zero length subpaths. It does this by
- * inserting a subpath containing a single axis aligned straight line that is
- * as small as it can be without cairo throwing it away for being too small to
- * affect rendering. Cairo will then draw stroke caps for this axis aligned
- * line, creating an axis aligned rectangle (approximating the square that
- * would ideally be drawn).
+ * inserting a subpath containing a single user space axis aligned straight
+ * line that is as small as it can be while minimizing the risk of it being
+ * thrown away by the DrawTarget's backend for being too small to affect
+ * rendering. The idea is that we'll then get stroke caps drawn for this axis
+ * aligned line, creating an axis aligned rectangle that approximates the
+ * square that would ideally be drawn.
+ *
+ * Since we don't have any information about transforms from user space to
+ * device space, we choose the length of the small line that we insert by
+ * making it a small percentage of the stroke width of the path. This should
+ * hopefully allow us to make the line as long as possible (to avoid rounding
+ * issues in the backend resulting in the backend seeing it as having zero
+ * length) while still avoiding the small rectangle being noticably different
+ * from a square.
  *
  * Note that this function inserts a subpath into the current gfx path that
  * will be present during both fill and stroke operations.
  */
 static void
+ApproximateZeroLengthSubpathSquareCaps(PathBuilder* aPB,
+                                       const Point& aPoint,
+                                       Float aStrokeWidth)
+{
+  // Note that caps are proportional to stroke width, so if stroke width is
+  // zero it's actually fine for |tinyLength| below to end up being zero.
+  // However, it would be a waste to inserting a LineTo in that case, so better
+  // not to.
+  MOZ_ASSERT(aStrokeWidth > 0.0f,
+             "Make the caller check for this, or check it here");
+
+  // The fraction of the stroke width that we choose for the length of the
+  // line is rather arbitrary, other than being chosen to meet the requirements
+  // described in the comment above.
+
+  Float tinyLength = aStrokeWidth / 32;
+
+  aPB->MoveTo(aPoint);
+  aPB->LineTo(aPoint + Point(tinyLength, 0));
+  aPB->MoveTo(aPoint);
+}
+
+static void
 ApproximateZeroLengthSubpathSquareCaps(const gfxPoint &aPoint, gfxContext *aCtx)
 {
   // Cairo's fixed point fractional part is 8 bits wide, so its device space
   // coordinate granularity is 1/256 pixels. However, to prevent user space
   // |aPoint| and |aPoint + tinyAdvance| being rounded to the same device
   // coordinates, we double this for |tinyAdvance|:
 
   const gfxSize tinyAdvance = aCtx->DeviceToUser(gfxSize(2.0/256.0, 0.0));
 
   aCtx->MoveTo(aPoint);
   aCtx->LineTo(aPoint + gfxPoint(tinyAdvance.width, tinyAdvance.height));
   aCtx->MoveTo(aPoint);
 }
 
-static void
-ApproximateZeroLengthSubpathSquareCaps(const Point& aPoint,
-                                       DrawTarget* aDT,
-                                       PathBuilder* aPB)
-{
-  // Cairo's fixed point fractional part is 8 bits wide, so its device space
-  // coordinate granularity is 1/256 pixels. However, to prevent user space
-  // |aPoint| and |aPoint + tinyAdvance| being rounded to the same device
-  // coordinates, we double this for |tinyAdvance|:
-
-  Matrix currentTransform = aDT->GetTransform();
-  currentTransform.Invert();
-  Size tinyAdvance = currentTransform * Size(2.0/256.0, 0.0);
-
-  aPB->MoveTo(aPoint);
-  aPB->LineTo(aPoint + Point(tinyAdvance.width, tinyAdvance.height));
-  aPB->MoveTo(aPoint);
-}
-
 #define MAYBE_APPROXIMATE_ZERO_LENGTH_SUBPATH_SQUARE_CAPS_TO_DT               \
   do {                                                                        \
-    if (capsAreSquare && !subpathHasLength && subpathContainsNonArc &&        \
-        SVGPathSegUtils::IsValidType(prevSegType) &&                          \
-        (!IsMoveto(prevSegType) ||                                            \
-         segType == PATHSEG_CLOSEPATH)) {                                     \
-      ApproximateZeroLengthSubpathSquareCaps(segStart, aDT, builder);         \
+    if (capsAreSquare && !subpathHasLength && aStrokeWidth > 0 &&             \
+        subpathContainsNonArc && SVGPathSegUtils::IsValidType(prevSegType) && \
+        (!IsMoveto(prevSegType) || segType == PATHSEG_CLOSEPATH)) {           \
+      ApproximateZeroLengthSubpathSquareCaps(builder, segStart, aStrokeWidth);\
     }                                                                         \
   } while(0)
 
 #define MAYBE_APPROXIMATE_ZERO_LENGTH_SUBPATH_SQUARE_CAPS                     \
   do {                                                                        \
     if (capsAreSquare && !subpathHasLength && subpathContainsNonArc &&        \
         SVGPathSegUtils::IsValidType(prevSegType) &&                          \
         (!IsMoveto(prevSegType) ||                                            \
          segType == PATHSEG_CLOSEPATH)) {                                     \
       ApproximateZeroLengthSubpathSquareCaps(segStart, aCtx);                 \
     }                                                                         \
   } while(0)
 
 TemporaryRef<Path>
-SVGPathData::ConstructPath(DrawTarget *aDT,
-                           FillRule aFillRule,
-                           CapStyle aCapStyle) const
+SVGPathData::BuildPath(FillRule aFillRule,
+                       uint8_t aStrokeLineCap,
+                       Float aStrokeWidth) const
 {
   if (mData.IsEmpty() || !IsMoveto(SVGPathSegUtils::DecodeType(mData[0]))) {
     return nullptr; // paths without an initial moveto are invalid
   }
 
-  RefPtr<PathBuilder> builder = aDT->CreatePathBuilder(aFillRule);
+  RefPtr<DrawTarget> drawTarget =
+    gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
+  NS_ASSERTION(gfxPlatform::GetPlatform()->
+                 SupportsAzureContentForDrawTarget(drawTarget),
+               "Should support Moz2D content drawing");
 
-  bool capsAreSquare = aCapStyle == CAP_SQUARE;
+  RefPtr<PathBuilder> builder = drawTarget->CreatePathBuilder(aFillRule);
+
+  bool capsAreSquare = aStrokeLineCap == NS_STYLE_STROKE_LINECAP_SQUARE;
   bool subpathHasLength = false;  // visual length
   bool subpathContainsNonArc = false;
 
   uint32_t segType     = PATHSEG_UNKNOWN;
   uint32_t prevSegType = PATHSEG_UNKNOWN;
   Point pathStart(0.0, 0.0); // start point of [sub]path
   Point segStart(0.0, 0.0);
   Point segEnd;
--- a/content/svg/content/src/SVGPathData.h
+++ b/content/svg/content/src/SVGPathData.h
@@ -7,16 +7,17 @@
 #define MOZILLA_SVGPATHDATA_H__
 
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsIContent.h"
 #include "nsINode.h"
 #include "nsIWeakReferenceUtils.h"
 #include "mozilla/gfx/2D.h"
+#include "mozilla/gfx/Types.h"
 #include "mozilla/RefPtr.h"
 #include "nsSVGElement.h"
 #include "nsTArray.h"
 
 #include <string.h>
 
 class gfxContext;
 class gfxPath;
@@ -80,16 +81,17 @@ class SVGPathData
   friend class DOMSVGPathSeg;
   friend class ::nsSVGPathDataParser;
   // nsSVGPathDataParser will not keep wrappers in sync, so consumers
   // are responsible for that!
 
   typedef gfx::DrawTarget DrawTarget;
   typedef gfx::Path Path;
   typedef gfx::FillRule FillRule;
+  typedef gfx::Float Float;
   typedef gfx::CapStyle CapStyle;
 
 public:
   typedef const float* const_iterator;
 
   SVGPathData(){}
   ~SVGPathData(){}
 
@@ -156,19 +158,19 @@ public:
    * Returns true, except on OOM, in which case returns false.
    */
   bool GetDistancesFromOriginToEndsOfVisibleSegments(nsTArray<double> *aArray) const;
 
   already_AddRefed<gfxPath>
   ToPath(const gfxMatrix& aMatrix) const;
 
   void ConstructPath(gfxContext *aCtx) const;
-  TemporaryRef<Path> ConstructPath(DrawTarget* aDT,
-                                   FillRule aFillRule,
-                                   CapStyle aCapStyle) const;
+  TemporaryRef<Path> BuildPath(FillRule aFillRule,
+                               uint8_t aCapStyle,
+                               Float aStrokeWidth) const;
 
   const_iterator begin() const { return mData.Elements(); }
   const_iterator end() const { return mData.Elements() + mData.Length(); }
 
   // Access to methods that can modify objects of this type is deliberately
   // limited. This is to reduce the chances of someone modifying objects of
   // this type without taking the necessary steps to keep DOM wrappers in sync.
   // If you need wider access to these methods, consider adding a method to
--- a/content/svg/content/src/SVGPathElement.cpp
+++ b/content/svg/content/src/SVGPathElement.cpp
@@ -8,22 +8,28 @@
 #include <algorithm>
 
 #include "DOMSVGPathSeg.h"
 #include "DOMSVGPathSegList.h"
 #include "DOMSVGPoint.h"
 #include "gfxPath.h"
 #include "mozilla/dom/SVGPathElementBinding.h"
 #include "nsCOMPtr.h"
+#include "nsComputedDOMStyle.h"
 #include "nsGkAtoms.h"
+#include "nsStyleConsts.h"
+#include "nsStyleStruct.h"
+#include "SVGContentUtils.h"
 
 class gfxContext;
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Path)
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace dom {
 
 JSObject*
 SVGPathElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
   return SVGPathElementBinding::Wrap(aCx, aScope, this);
 }
@@ -345,10 +351,48 @@ SVGPathElement::GetPathLengthScale(PathL
       if (path) {
         return path->GetLength() / authorsPathLengthEstimate;
       }
     }
   }
   return 1.0;
 }
 
+TemporaryRef<Path>
+SVGPathElement::BuildPath()
+{
+  // The Moz2D PathBuilder that our SVGPathData will be using only cares about
+  // the fill rule. However, in order to fulfill the requirements of the SVG
+  // spec regarding zero length sub-paths when square line caps are in use,
+  // SVGPathData needs to know our stroke-linecap style and, if "square", then
+  // also our stroke width. See the comment for
+  // ApproximateZeroLengthSubpathSquareCaps for more info.
+
+  uint8_t strokeLineCap = NS_STYLE_STROKE_LINECAP_BUTT;
+  Float strokeWidth = 0;
+
+  nsRefPtr<nsStyleContext> styleContext =
+    nsComputedDOMStyle::GetStyleContextForElementNoFlush(this, nullptr, nullptr);
+  if (styleContext) {
+    const nsStyleSVG* style = styleContext->StyleSVG();
+    // Note: the path that we return may be used for hit-testing, and SVG
+    // exposes hit-testing of strokes that are not actually painted. For that
+    // reason we do not check for eStyleSVGPaintType_None or check the stroke
+    // opacity here.
+    if (style->mStrokeLinecap == NS_STYLE_STROKE_LINECAP_SQUARE) {
+      strokeLineCap = style->mStrokeLinecap;
+      strokeWidth = GetStrokeWidth();
+    }
+  }
+
+  // The fill rule that we pass must be the current
+  // computed value of our CSS 'fill-rule' property if the path that we return
+  // will be used for painting or hit-testing. For all other uses (bounds
+  // calculatons, length measurement, position-at-offset calculations) the fill
+  // rule that we pass doesn't matter. As a result we can just pass the current
+  // computed value regardless of who's calling us, or what they're going to do
+  // with the path that we return.
+
+  return mD.GetAnimValue().BuildPath(GetFillRule(), strokeLineCap, strokeWidth);
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/content/svg/content/src/SVGPathElement.h
+++ b/content/svg/content/src/SVGPathElement.h
@@ -42,16 +42,17 @@ public:
   // nsSVGSVGElement methods:
   virtual bool HasValidDimensions() const MOZ_OVERRIDE;
 
   // nsSVGPathGeometryElement methods:
   virtual bool AttributeDefinesGeometry(const nsIAtom *aName) MOZ_OVERRIDE;
   virtual bool IsMarkable() MOZ_OVERRIDE;
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks) MOZ_OVERRIDE;
   virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
+  virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
 
   virtual already_AddRefed<gfxPath> GetPath(const gfxMatrix &aMatrix) MOZ_OVERRIDE;
 
   // nsIContent interface
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   virtual SVGAnimatedPathSegList* GetAnimPathSegList() MOZ_OVERRIDE {
     return &mD;
--- a/content/svg/content/src/SVGPoint.h
+++ b/content/svg/content/src/SVGPoint.h
@@ -3,26 +3,29 @@
  * 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_SVGPOINT_H__
 #define MOZILLA_SVGPOINT_H__
 
 #include "nsDebug.h"
 #include "gfxPoint.h"
+#include "mozilla/gfx/Point.h"
 
 namespace mozilla {
 
 /**
  * This class is currently used for point list attributes.
  *
  * The DOM wrapper class for this class is DOMSVGPoint.
  */
 class SVGPoint
 {
+  typedef mozilla::gfx::Point Point;
+
 public:
 
   SVGPoint()
     : mX(0.0f)
     , mY(0.0f)
   {}
 
   SVGPoint(float aX, float aY)
@@ -52,16 +55,20 @@ public:
     mY += rhs.mY;
     return *this;
   }
 
   operator gfxPoint() const {
     return gfxPoint(mX, mY);
   }
 
+  operator Point() const {
+    return Point(mX, mY);
+  }
+
 #ifdef DEBUG
   bool IsValid() const {
     return NS_finite(mX) && NS_finite(mY);
   }
 #endif
 
   void SetX(float aX)
     { mX = aX; }
--- a/content/svg/content/src/SVGRectElement.cpp
+++ b/content/svg/content/src/SVGRectElement.cpp
@@ -2,20 +2,24 @@
 /* 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 "mozilla/dom/SVGRectElement.h"
 #include "nsGkAtoms.h"
 #include "gfxContext.h"
 #include "mozilla/dom/SVGRectElementBinding.h"
+#include "mozilla/gfx/2D.h"
+#include "mozilla/gfx/PathHelpers.h"
 #include <algorithm>
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Rect)
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace dom {
 
 class SVGAnimatedLength;
 
 JSObject*
 SVGRectElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
@@ -143,10 +147,56 @@ SVGRectElement::ConstructPath(gfxContext
   if (ry > halfHeight)
     ry = halfHeight;
 
   gfxSize corner(rx, ry);
   aCtx->RoundedRectangle(gfxRect(x, y, width, height),
                          gfxCornerSizes(corner, corner, corner, corner));
 }
 
+TemporaryRef<Path>
+SVGRectElement::BuildPath()
+{
+  RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
+
+  float x, y, width, height, rx, ry;
+  GetAnimatedLengthValues(&x, &y, &width, &height, &rx, &ry, nullptr);
+
+  if (width > 0 && height > 0) {
+    rx = std::max(rx, 0.0f);
+    ry = std::max(ry, 0.0f);
+
+    if (rx == 0 && ry == 0) {
+      // Optimization for the no rounded corners case.
+      Rect r(x, y, width, height);
+      pathBuilder->MoveTo(r.TopLeft());
+      pathBuilder->LineTo(r.TopRight());
+      pathBuilder->LineTo(r.BottomRight());
+      pathBuilder->LineTo(r.BottomLeft());
+      pathBuilder->Close();
+    } else {
+      // If either the 'rx' or the 'ry' attribute isn't set, then we have to
+      // set it to the value of the other:
+      bool hasRx = mLengthAttributes[ATTR_RX].IsExplicitlySet();
+      bool hasRy = mLengthAttributes[ATTR_RY].IsExplicitlySet();
+      MOZ_ASSERT(hasRx || hasRy);
+
+      if (hasRx && !hasRy) {
+        ry = rx;
+      } else if (hasRy && !hasRx) {
+        rx = ry;
+      }
+
+      // Clamp rx and ry to half the rect's width and height respectively:
+      rx = std::min(rx, width / 2);
+      ry = std::min(ry, height / 2);
+
+      Size cornerRadii(rx, ry);
+      Size radii[] = { cornerRadii, cornerRadii, cornerRadii, cornerRadii };
+      AppendRoundedRectToPath(pathBuilder, Rect(x, y, width, height), radii);
+    }
+  }
+
+  return pathBuilder->Finish();
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/content/svg/content/src/SVGRectElement.h
+++ b/content/svg/content/src/SVGRectElement.h
@@ -27,16 +27,17 @@ protected:
                                           already_AddRefed<nsINodeInfo> aNodeInfo));
 
 public:
   // nsSVGSVGElement methods:
   virtual bool HasValidDimensions() const MOZ_OVERRIDE;
 
   // nsSVGPathGeometryElement methods:
   virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
+  virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<SVGAnimatedLength> X();
   already_AddRefed<SVGAnimatedLength> Y();
   already_AddRefed<SVGAnimatedLength> Height();
   already_AddRefed<SVGAnimatedLength> Width();
--- a/content/svg/content/src/nsSVGPathGeometryElement.cpp
+++ b/content/svg/content/src/nsSVGPathGeometryElement.cpp
@@ -1,15 +1,23 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsSVGPathGeometryElement.h"
+
+#include "gfxPlatform.h"
+#include "mozilla/gfx/2D.h"
+#include "nsComputedDOMStyle.h"
 #include "nsSVGLength2.h"
+#include "SVGContentUtils.h"
+
+using namespace mozilla;
+using namespace mozilla::gfx;
 
 //----------------------------------------------------------------------
 // Implementation
 
 nsSVGPathGeometryElement::nsSVGPathGeometryElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : nsSVGPathGeometryElementBase(aNodeInfo)
 {
 }
@@ -52,8 +60,66 @@ nsSVGPathGeometryElement::GetMarkPoints(
 {
 }
 
 already_AddRefed<gfxPath>
 nsSVGPathGeometryElement::GetPath(const gfxMatrix &aMatrix)
 {
   return nullptr;
 }
+
+TemporaryRef<PathBuilder>
+nsSVGPathGeometryElement::CreatePathBuilder()
+{
+  RefPtr<DrawTarget> drawTarget =
+    gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
+  NS_ASSERTION(gfxPlatform::GetPlatform()->
+                 SupportsAzureContentForDrawTarget(drawTarget),
+               "Should support Moz2D content drawing");
+
+  // The fill rule that we pass to CreatePathBuilder must be the current
+  // computed value of our CSS 'fill-rule' property if the path that we return
+  // will be used for painting or hit-testing. For all other uses (bounds
+  // calculatons, length measurement, position-at-offset calculations) the fill
+  // rule that we pass doesn't matter. As a result we can just pass the current
+  // computed value regardless of who's calling us, or what they're going to do
+  // with the path that we return.
+
+  return drawTarget->CreatePathBuilder(GetFillRule());
+}
+
+FillRule
+nsSVGPathGeometryElement::GetFillRule()
+{
+  FillRule fillRule = FILL_WINDING; // Equivalent to NS_STYLE_FILL_RULE_NONZERO
+
+  nsRefPtr<nsStyleContext> styleContext =
+    nsComputedDOMStyle::GetStyleContextForElementNoFlush(this, nullptr,
+                                                         nullptr);
+  
+  if (styleContext) {
+    MOZ_ASSERT(styleContext->StyleSVG()->mFillRule ==
+                                           NS_STYLE_FILL_RULE_NONZERO ||
+               styleContext->StyleSVG()->mFillRule ==
+                                           NS_STYLE_FILL_RULE_EVENODD);
+
+    if (styleContext->StyleSVG()->mFillRule == NS_STYLE_FILL_RULE_EVENODD) {
+      fillRule = FILL_EVEN_ODD;
+    }
+  } else {
+    // ReportToConsole
+    NS_WARNING("Couldn't get style context for content in GetFillRule");
+  }
+
+  return fillRule;
+}
+
+Float
+nsSVGPathGeometryElement::GetStrokeWidth()
+{
+  nsRefPtr<nsStyleContext> styleContext =
+    nsComputedDOMStyle::GetStyleContextForElementNoFlush(this, nullptr,
+                                                         nullptr);
+  return styleContext ?
+    SVGContentUtils::CoordToFloat(styleContext->PresContext(), this,
+                                  styleContext->StyleSVG()->mStrokeWidth) :
+    0.0f;
+}
--- a/content/svg/content/src/nsSVGPathGeometryElement.h
+++ b/content/svg/content/src/nsSVGPathGeometryElement.h
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __NS_SVGPATHGEOMETRYELEMENT_H__
 #define __NS_SVGPATHGEOMETRYELEMENT_H__
 
+#include "mozilla/gfx/2D.h"
 #include "SVGGraphicsElement.h"
 
 class gfxPath;
 struct gfxMatrix;
 template <class E> class nsTArray;
 
 struct nsSVGMark {
   enum Type {
@@ -28,16 +29,22 @@ struct nsSVGMark {
 };
 
 class gfxContext;
 
 typedef mozilla::dom::SVGGraphicsElement nsSVGPathGeometryElementBase;
 
 class nsSVGPathGeometryElement : public nsSVGPathGeometryElementBase
 {
+protected:
+  typedef mozilla::gfx::FillRule FillRule;
+  typedef mozilla::gfx::Float Float;
+  typedef mozilla::gfx::Path Path;
+  typedef mozilla::gfx::PathBuilder PathBuilder;
+
 public:
   nsSVGPathGeometryElement(already_AddRefed<nsINodeInfo> aNodeInfo);
 
   virtual bool AttributeDefinesGeometry(const nsIAtom *aName);
 
   /**
    * Returns true if this element's geometry depends on the width or height of its
    * coordinate context (typically the viewport established by its nearest <svg>
@@ -47,12 +54,39 @@ public:
    * This could be moved up to a more general class so it can be used for non-leaf
    * elements, but that would require care and for now there's no need.
    */
   bool GeometryDependsOnCoordCtx();
 
   virtual bool IsMarkable();
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks);
   virtual void ConstructPath(gfxContext *aCtx) = 0;
+
+  /**
+   * Returns a Path that can be used to paint, hit-test or calculate bounds for
+   * this element.
+   */
+  virtual mozilla::TemporaryRef<Path> BuildPath() = 0;
+
   virtual already_AddRefed<gfxPath> GetPath(const gfxMatrix &aMatrix);
+
+  /**
+   * Returns a PathBuilder object created using the current computed value of
+   * the CSS property 'fill-rule' for this element.
+   */
+  mozilla::TemporaryRef<PathBuilder> CreatePathBuilder();
+
+  /**
+   * Returns the current computed value of the CSS property 'fill-rule' for
+   * this element.
+   */
+  FillRule GetFillRule();
+
+  /**
+   * Returns the current computed value of the CSS property 'stroke-width' for
+   * this element. (I.e. this does NOT take account of the value of the
+   * 'stroke' and 'stroke-opacity' properties to, say, return zero if they are
+   * "none" or "0", respectively.)
+   */
+  Float GetStrokeWidth();
 };
 
 #endif
--- a/content/svg/content/src/nsSVGPolyElement.cpp
+++ b/content/svg/content/src/nsSVGPolyElement.cpp
@@ -1,19 +1,21 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsSVGPolyElement.h"
 #include "DOMSVGPointList.h"
 #include "gfxContext.h"
+#include "mozilla/gfx/2D.h"
 #include "SVGContentUtils.h"
 
 using namespace mozilla;
+using namespace mozilla::gfx;
 
 //----------------------------------------------------------------------
 // nsISupports methods
 
 NS_IMPL_ADDREF_INHERITED(nsSVGPolyElement,nsSVGPolyElementBase)
 NS_IMPL_RELEASE_INHERITED(nsSVGPolyElement,nsSVGPolyElementBase)
 
 NS_INTERFACE_MAP_BEGIN(nsSVGPolyElement)
@@ -115,8 +117,24 @@ nsSVGPolyElement::ConstructPath(gfxConte
     return;
 
   aCtx->MoveTo(points[0]);
   for (uint32_t i = 1; i < points.Length(); ++i) {
     aCtx->LineTo(points[i]);
   }
 }
 
+TemporaryRef<Path>
+nsSVGPolyElement::BuildPath()
+{
+  RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
+
+  const SVGPointList &points = mPoints.GetAnimValue();
+
+  if (!points.IsEmpty()) {
+    pathBuilder->MoveTo(points[0]);
+    for (uint32_t i = 1; i < points.Length(); ++i) {
+      pathBuilder->LineTo(points[i]);
+    }
+  }
+
+  return pathBuilder->Finish();
+}
--- a/content/svg/content/src/nsSVGPolyElement.h
+++ b/content/svg/content/src/nsSVGPolyElement.h
@@ -38,16 +38,17 @@ public:
     return nsGkAtoms::points;
   }
 
   // nsSVGPathGeometryElement methods:
   virtual bool AttributeDefinesGeometry(const nsIAtom *aName) MOZ_OVERRIDE;
   virtual bool IsMarkable() MOZ_OVERRIDE { return true; }
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks) MOZ_OVERRIDE;
   virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
+  virtual mozilla::TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<mozilla::DOMSVGPointList> Points();
   already_AddRefed<mozilla::DOMSVGPointList> AnimatedPoints();
 
 protected:
   SVGAnimatedPointList mPoints;
 };
--- a/content/svg/content/test/test_bbox.xhtml
+++ b/content/svg/content/test/test_bbox.xhtml
@@ -15,57 +15,57 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 <iframe id="svg" src="bbox-helper.svg"></iframe>
 
 <pre id="test">
 <script class="testbody" type="application/javascript">//<![CDATA[
 
 SimpleTest.waitForExplicitFinish();
 
-function fuzzyEq(a, b) {
-  var epsilon = 0.0002;
-  return Math.abs(a - b) < epsilon;
-}
-
 function run()
 {
   var doc = $("svg").contentDocument;
 
+  function isFuzzy(a, b, error, name)
+  {
+    ok(!(Math.abs(a - b) > error), name, "got " + a + ", expected " + b + " (within " + error + ")");
+  }
+
   function getBBox(id) {
     return doc.getElementById(id).getBBox();
   }
-  function checkBBox(id, x, y, width, height) {
+  function checkBBox(id, x, y, width, height, error) {
     var bbox = getBBox(id);
-    is(bbox.x, x, id + ".getBBox().x");
-    is(bbox.y, y, id + ".getBBox().y");
-    is(bbox.width, width, id + ".getBBox().width");
-    is(bbox.height, height, id + ".getBBox().height");
+    isFuzzy(bbox.x, x, error, id + ".getBBox().x");
+    isFuzzy(bbox.y, y, error, id + ".getBBox().y");
+    isFuzzy(bbox.width, width, error, id + ".getBBox().width");
+    isFuzzy(bbox.height, height, error, id + ".getBBox().height");
   }
   function compareBBox(id1, id2) {
     var bbox1 = getBBox(id1);
     var bbox2 = getBBox(id2);
     is(bbox1.x, bbox2.x, id1 + ".getBBox().x");
     is(bbox1.y, bbox2.y, id1 + ".getBBox().y");
-    ok(fuzzyEq(bbox1.width, bbox2.width), id1 + ".getBBox().width");
+    isFuzzy(bbox1.width, bbox2.width, 0.0002, id1 + ".getBBox().width");
     is(bbox1.height, bbox2.height, id1 + ".getBBox().height");
   }
   function compareBBoxHeight(id1, id2) {
     var bbox1 = getBBox(id1);
     var bbox2 = getBBox(id2);
     is(bbox1.height, bbox2.height, id1 + ".getBBox().height");
   }
 
-  checkBBox("fO", 10, 10, 100, 100);
-  checkBBox("i", 10, 10, 100, 100);
+  checkBBox("fO", 10, 10, 100, 100, 0.0);
+  checkBBox("i", 10, 10, 100, 100, 0.0);
   compareBBoxHeight("a", "b");
   compareBBoxHeight("a", "y");
   compareBBox("b", "tspan");
-  checkBBox("v", 95, 45, 10, 155);
-  checkBBox("h", 195, 45, 105, 55);
-  checkBBox("e", 95, 95, 10, 10);
+  checkBBox("v", 95, 45, 10, 155, 0.001);
+  checkBBox("h", 195, 45, 105, 55, 0.001);
+  checkBBox("e", 95, 95, 10, 10, 0.001);
   
   SimpleTest.finish();
 }
 
 window.addEventListener("load", run, false);
 
 //]]></script>
 </pre>
--- a/content/svg/content/test/test_pointer-events-2.xhtml
+++ b/content/svg/content/test/test_pointer-events-2.xhtml
@@ -46,17 +46,17 @@ function run()
   </div>
   <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" id="svg">
     <defs>
       <clipPath id="clip">
         <rect x="20" y="20" width="30" height="30"/>
       </clipPath>
     </defs>
     <rect id="bad" width="100%" height="100%" fill="blue"/>
-    <circle id="circle" cx="50%" cy="50%" r="1" stroke-width="1000" fill="black" pointer-events="all"/>
+    <circle id="circle" cx="50%" cy="50%" r="500" stroke-width="500" fill="none" pointer-events="all"/>
     <foreignObject id="fo" x="200" y="50" width="50" height="50" clip-path="url(#clip)">
       <svg>
         <path id="path" d="M0,0 H50 V50 H0 Z" fill="green"/>
       </svg>
     </foreignObject>
   </svg>
 
 </div>
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -1891,17 +1891,17 @@ nsDocShell::GatherCharsetMenuTelemetry()
   bool isFileURL = false;
   nsIURI* url = doc->GetOriginalURI();
   if (url) {
     url->SchemeIs("file", &isFileURL);
   }
 
   int32_t charsetSource = doc->GetDocumentCharacterSetSource();
   switch (charsetSource) {
-    case kCharsetFromWeakDocTypeDefault:
+    case kCharsetFromFallback:
     case kCharsetFromDocTypeDefault:
     case kCharsetFromCache:
     case kCharsetFromParentFrame:
     case kCharsetFromHintPrevDoc:
       // Changing charset on an unlabeled doc.
       if (isFileURL) {
         Telemetry::Accumulate(Telemetry::CHARSET_OVERRIDE_SITUATION, 0);
       } else {
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -429,16 +429,17 @@ public:
                                            bool aFreezeChildren = true);
   virtual NS_HIDDEN_(nsresult) ResumeTimeouts(bool aThawChildren = true);
   virtual NS_HIDDEN_(uint32_t) TimeoutSuspendCount();
   virtual NS_HIDDEN_(nsresult) FireDelayedDOMEvents();
   virtual NS_HIDDEN_(bool) IsFrozen() const
   {
     return mIsFrozen;
   }
+  virtual NS_HIDDEN_(bool) IsRunningTimeout() { return mTimeoutFiringDepth > 0; }
 
   virtual NS_HIDDEN_(bool) WouldReuseInnerWindow(nsIDocument *aNewDocument);
 
   virtual NS_HIDDEN_(void) SetDocShell(nsIDocShell* aDocShell);
   virtual void DetachFromDocShell();
   virtual NS_HIDDEN_(nsresult) SetNewDocument(nsIDocument *aDocument,
                                               nsISupports *aState,
                                               bool aForceReuseInnerWindow);
--- a/dom/base/nsMimeTypeArray.cpp
+++ b/dom/base/nsMimeTypeArray.cpp
@@ -74,19 +74,17 @@ nsMimeTypeArray::NamedItem(const nsAStri
   return NamedGetter(aName, unused);
 }
 
 nsMimeType*
 nsMimeTypeArray::IndexedGetter(uint32_t aIndex, bool &aFound)
 {
   aFound = false;
 
-  if (mMimeTypes.IsEmpty()) {
-    EnsureMimeTypes();
-  }
+  EnsurePluginMimeTypes();
 
   MOZ_ASSERT(mMimeTypes.Length() >= mPluginMimeTypeCount);
 
   if (aIndex >= mPluginMimeTypeCount) {
     return nullptr;
   }
 
   aFound = true;
@@ -94,19 +92,17 @@ nsMimeTypeArray::IndexedGetter(uint32_t 
   return mMimeTypes[aIndex];
 }
 
 nsMimeType*
 nsMimeTypeArray::NamedGetter(const nsAString& aName, bool &aFound)
 {
   aFound = false;
 
-  if (mMimeTypes.IsEmpty()) {
-    EnsureMimeTypes();
-  }
+  EnsurePluginMimeTypes();
 
   for (uint32_t i = 0; i < mMimeTypes.Length(); ++i) {
     if (aName.Equals(mMimeTypes[i]->Type())) {
       aFound = true;
 
       return mMimeTypes[i];
     }
   }
@@ -156,39 +152,35 @@ nsMimeTypeArray::NamedGetter(const nsASt
   mMimeTypes.AppendElement(mt);
 
   return mt;
 }
 
 uint32_t
 nsMimeTypeArray::Length()
 {
-  if (mMimeTypes.IsEmpty()) {
-    EnsureMimeTypes();
-  }
+  EnsurePluginMimeTypes();
 
   MOZ_ASSERT(mMimeTypes.Length() >= mPluginMimeTypeCount);
 
   return mPluginMimeTypeCount;
 }
 
 void
 nsMimeTypeArray::GetSupportedNames(nsTArray< nsString >& aRetval)
 {
-  if (mMimeTypes.IsEmpty()) {
-    EnsureMimeTypes();
-  }
+  EnsurePluginMimeTypes();
 
   for (uint32_t i = 0; i < mMimeTypes.Length(); ++i) {
     aRetval.AppendElement(mMimeTypes[i]->Type());
   }
 }
 
 void
-nsMimeTypeArray::EnsureMimeTypes()
+nsMimeTypeArray::EnsurePluginMimeTypes()
 {
   if (!mMimeTypes.IsEmpty() || !mWindow) {
     return;
   }
 
   nsCOMPtr<nsIDOMNavigator> navigator;
   mWindow->GetNavigator(getter_AddRefs(navigator));
 
@@ -198,24 +190,17 @@ nsMimeTypeArray::EnsureMimeTypes()
 
   ErrorResult rv;
   nsPluginArray *pluginArray =
     static_cast<Navigator*>(navigator.get())->GetPlugins(rv);
   if (!pluginArray) {
     return;
   }
 
-  nsTArray<nsRefPtr<nsPluginElement> > plugins;
-  pluginArray->GetPlugins(plugins);
-
-  for (uint32_t i = 0; i < plugins.Length(); ++i) {
-    nsPluginElement *plugin = plugins[i];
-
-    mMimeTypes.AppendElements(plugin->MimeTypes());
-  }
+  pluginArray->GetMimeTypes(mMimeTypes);
 
   mPluginMimeTypeCount = mMimeTypes.Length();
 }
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsMimeType, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsMimeType, Release)
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(nsMimeType, mWindow, mPluginElement)
--- a/dom/base/nsMimeTypeArray.h
+++ b/dom/base/nsMimeTypeArray.h
@@ -36,17 +36,17 @@ public:
   nsMimeType* Item(uint32_t index);
   nsMimeType* NamedItem(const nsAString& name);
   nsMimeType* IndexedGetter(uint32_t index, bool &found);
   nsMimeType* NamedGetter(const nsAString& name, bool &found);
   uint32_t Length();
   void GetSupportedNames(nsTArray< nsString >& retval);
 
 protected:
-  void EnsureMimeTypes();
+  void EnsurePluginMimeTypes();
   void Clear();
 
   nsCOMPtr<nsPIDOMWindow> mWindow;
 
   // mMimeTypes contains all mime types handled by plugins followed by
   // any other mime types that we handle internally and have been
   // looked up before.
   nsTArray<nsRefPtr<nsMimeType> > mMimeTypes;
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -184,16 +184,18 @@ public:
   nsIDocument* GetDoc()
   {
     if (!mDoc) {
       MaybeCreateDoc();
     }
     return mDoc;
   }
 
+  virtual NS_HIDDEN_(bool) IsRunningTimeout() = 0;
+
 protected:
   // Lazily instantiate an about:blank document if necessary, and if
   // we have what it takes to do so.
   void MaybeCreateDoc();
 
 public:
   // Internal getter/setter for the frame element, this version of the
   // getter crosses chrome boundaries whereas the public scriptable
--- a/dom/base/nsPluginArray.cpp
+++ b/dom/base/nsPluginArray.cpp
@@ -63,29 +63,30 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(nsPluginArray,
                                         mWindow,
                                         mPlugins)
 
 void
-nsPluginArray::GetPlugins(nsTArray<nsRefPtr<nsPluginElement> >& aPlugins)
+nsPluginArray::GetMimeTypes(nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes)
 {
-  aPlugins.Clear();
+  aMimeTypes.Clear();
 
   if (!AllowPlugins()) {
     return;
   }
 
-  if (mPlugins.IsEmpty()) {
-    EnsurePlugins();
+  EnsurePlugins();
+
+  for (uint32_t i = 0; i < mPlugins.Length(); ++i) {
+    nsPluginElement *plugin = mPlugins[i];
+    aMimeTypes.AppendElements(plugin->MimeTypes());
   }
-
-  aPlugins = mPlugins;
 }
 
 nsPluginElement*
 nsPluginArray::Item(uint32_t aIndex)
 {
   bool unused;
   return IndexedGetter(aIndex, unused);
 }
@@ -146,19 +147,17 @@ nsPluginElement*
 nsPluginArray::IndexedGetter(uint32_t aIndex, bool &aFound)
 {
   aFound = false;
 
   if (!AllowPlugins()) {
     return nullptr;
   }
 
-  if (mPlugins.IsEmpty()) {
-    EnsurePlugins();
-  }
+  EnsurePlugins();
 
   aFound = aIndex < mPlugins.Length();
 
   return aFound ? mPlugins[aIndex] : nullptr;
 }
 
 void
 nsPluginArray::Invalidate()
@@ -174,19 +173,17 @@ nsPluginElement*
 nsPluginArray::NamedGetter(const nsAString& aName, bool &aFound)
 {
   aFound = false;
 
   if (!AllowPlugins()) {
     return nullptr;
   }
 
-  if (mPlugins.IsEmpty()) {
-    EnsurePlugins();
-  }
+  EnsurePlugins();
 
   for (uint32_t i = 0; i < mPlugins.Length(); ++i) {
     nsAutoString pluginName;
     nsPluginElement* plugin = mPlugins[i];
     plugin->GetName(pluginName);
 
     if (pluginName.Equals(aName)) {
       aFound = true;
@@ -200,19 +197,17 @@ nsPluginArray::NamedGetter(const nsAStri
 
 uint32_t
 nsPluginArray::Length()
 {
   if (!AllowPlugins()) {
     return 0;
   }
 
-  if (mPlugins.IsEmpty()) {
-    EnsurePlugins();
-  }
+  EnsurePlugins();
 
   return mPlugins.Length();
 }
 
 void
 nsPluginArray::GetSupportedNames(nsTArray< nsString >& aRetval)
 {
   aRetval.Clear();
@@ -245,21 +240,24 @@ nsPluginArray::AllowPlugins() const
   nsCOMPtr<nsIDocShell> docShell = do_GetInterface(mWindow);
 
   return docShell && docShell->PluginsAllowedInCurrentDoc();
 }
 
 void
 nsPluginArray::EnsurePlugins()
 {
-  nsRefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
+  if (!mPlugins.IsEmpty()) {
+    // We already have an array of plugin elements.
+    return;
+  }
 
-  if (!mPlugins.IsEmpty() || !pluginHost) {
-    // We already have an array of plugin elements, or no plugin host
-
+  nsRefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
+  if (!pluginHost) {
+    // We have no plugin host.
     return;
   }
 
   nsTArray<nsRefPtr<nsPluginTag> > pluginTags;
   pluginHost->GetPlugins(pluginTags);
 
   // need to wrap each of these with a nsPluginElement, which is
   // scriptable.
@@ -322,42 +320,42 @@ void
 nsPluginElement::GetName(nsString& retval) const
 {
   CopyUTF8toUTF16(mPluginTag->mName, retval);
 }
 
 nsMimeType*
 nsPluginElement::Item(uint32_t aIndex)
 {
-  EnsureMimeTypes();
+  EnsurePluginMimeTypes();
 
   return mMimeTypes.SafeElementAt(aIndex);
 }
 
 nsMimeType*
 nsPluginElement::NamedItem(const nsAString& aName)
 {
   bool unused;
   return NamedGetter(aName, unused);
 }
 
 nsMimeType*
 nsPluginElement::IndexedGetter(uint32_t aIndex, bool &aFound)
 {
-  EnsureMimeTypes();
+  EnsurePluginMimeTypes();
 
   aFound = aIndex < mMimeTypes.Length();
 
   return aFound ? mMimeTypes[aIndex] : nullptr;
 }
 
 nsMimeType*
 nsPluginElement::NamedGetter(const nsAString& aName, bool &aFound)
 {
-  EnsureMimeTypes();
+  EnsurePluginMimeTypes();
 
   aFound = false;
 
   for (uint32_t i = 0; i < mMimeTypes.Length(); ++i) {
     if (mMimeTypes[i]->Type().Equals(aName)) {
       aFound = true;
 
       return mMimeTypes[i];
@@ -365,41 +363,41 @@ nsPluginElement::NamedGetter(const nsASt
   }
 
   return nullptr;
 }
 
 uint32_t
 nsPluginElement::Length()
 {
-  EnsureMimeTypes();
+  EnsurePluginMimeTypes();
 
   return mMimeTypes.Length();
 }
 
 void
 nsPluginElement::GetSupportedNames(nsTArray< nsString >& retval)
 {
-  EnsureMimeTypes();
+  EnsurePluginMimeTypes();
 
   for (uint32_t i = 0; i < mMimeTypes.Length(); ++i) {
     retval.AppendElement(mMimeTypes[i]->Type());
   }
 }
 
 nsTArray<nsRefPtr<nsMimeType> >&
 nsPluginElement::MimeTypes()
 {
-  EnsureMimeTypes();
+  EnsurePluginMimeTypes();
 
   return mMimeTypes;
 }
 
 void
-nsPluginElement::EnsureMimeTypes()
+nsPluginElement::EnsurePluginMimeTypes()
 {
   if (!mMimeTypes.IsEmpty()) {
     return;
   }
 
   for (uint32_t i = 0; i < mPluginTag->mMimeTypes.Length(); ++i) {
     NS_ConvertUTF8toUTF16 type(mPluginTag->mMimeTypes[i]);
     mMimeTypes.AppendElement(new nsMimeType(mWindow, this, i, type));
--- a/dom/base/nsPluginArray.h
+++ b/dom/base/nsPluginArray.h
@@ -38,17 +38,17 @@ public:
 
   // nsPluginArray registers itself as an observer with a weak reference.
   // This can't be done in the constructor, because at that point its
   // refcount is 0 (and it gets destroyed upon registration). So, Init()
   // must be called after construction.
   void Init();
   void Invalidate();
 
-  void GetPlugins(nsTArray<nsRefPtr<nsPluginElement> >& aPlugins);
+  void GetMimeTypes(nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes);
 
   // PluginArray WebIDL methods
 
   nsPluginElement* Item(uint32_t aIndex);
   nsPluginElement* NamedItem(const nsAString& aName);
   void Refresh(bool aReloadDocuments);
   nsPluginElement* IndexedGetter(uint32_t aIndex, bool &aFound);
   nsPluginElement* NamedGetter(const nsAString& aName, bool &aFound);
@@ -92,16 +92,16 @@ public:
   nsMimeType* IndexedGetter(uint32_t index, bool &found);
   nsMimeType* NamedGetter(const nsAString& name, bool &found);
   uint32_t Length();
   void GetSupportedNames(nsTArray< nsString >& retval);
 
   nsTArray<nsRefPtr<nsMimeType> >& MimeTypes();
 
 protected:
-  void EnsureMimeTypes();
+  void EnsurePluginMimeTypes();
 
   nsCOMPtr<nsPIDOMWindow> mWindow;
   nsRefPtr<nsPluginTag> mPluginTag;
   nsTArray<nsRefPtr<nsMimeType> > mMimeTypes;
 };
 
 #endif /* nsPluginArray_h___ */
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -461,32 +461,36 @@ class CGWrapper(CGThing):
         self.declareOnly = declareOnly
         self.defineOnly = defineOnly
         self.reindent = reindent
     def declare(self):
         if self.defineOnly:
             return ''
         decl = self.child.declare()
         if self.reindent:
-            # We don't use lineStartDetector because we don't want to
-            # insert whitespace at the beginning of our _first_ line.
-            decl = stripTrailingWhitespace(
-                decl.replace("\n", "\n" + (" " * len(self.declarePre))))
+            decl = self.reindentString(decl, self.declarePre)
         return self.declarePre + decl + self.declarePost
     def define(self):
         if self.declareOnly:
             return ''
         defn = self.child.define()
         if self.reindent:
-            # We don't use lineStartDetector because we don't want to
-            # insert whitespace at the beginning of our _first_ line.
-            defn = stripTrailingWhitespace(
-                defn.replace("\n", "\n" + (" " * len(self.definePre))))
+            defn = self.reindentString(defn, self.definePre)
         return self.definePre + defn + self.definePost
 
+    @staticmethod
+    def reindentString(stringToIndent, widthString):
+        # We don't use lineStartDetector because we don't want to
+        # insert whitespace at the beginning of our _first_ line.
+        # Use the length of the last line of width string, in case
+        # it is a multiline string.
+        lastLineWidth = len(widthString.splitlines()[-1])
+        return stripTrailingWhitespace(
+            stringToIndent.replace("\n", "\n" + (" " * lastLineWidth)))
+
     def deps(self):
         return self.child.deps()
 
 class CGIfWrapper(CGWrapper):
     def __init__(self, child, condition):
         pre = CGWrapper(CGGeneric(condition), pre="if (", post=") {\n",
                         reindent=True)
         CGWrapper.__init__(self, CGIndenter(child), pre=pre.define(),
@@ -2950,24 +2954,26 @@ for (uint32_t i = 0; i < length; ++i) {
         else:
             callbackObject = None
 
         dictionaryMemberTypes = filter(lambda t: t.isDictionary(), memberTypes)
         if len(dictionaryMemberTypes) > 0:
             assert len(dictionaryMemberTypes) == 1
             name = dictionaryMemberTypes[0].inner.identifier.name
             setDictionary = CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, ${mutableVal}, tryNext)) || !tryNext;" % (unionArgumentObj, name))
+            names.append(name)
         else:
             setDictionary = None
 
         objectMemberTypes = filter(lambda t: t.isObject(), memberTypes)
         if len(objectMemberTypes) > 0:
             assert len(objectMemberTypes) == 1
             object = CGGeneric("%s.SetToObject(cx, argObj);\n"
                                "done = true;" % unionArgumentObj)
+            names.append(objectMemberTypes[0].name)
         else:
             object = None
 
         hasObjectTypes = interfaceObject or arrayObject or dateObject or callbackObject or object
         if hasObjectTypes:
             # "object" is not distinguishable from other types
             assert not object or not (interfaceObject or arrayObject or dateObject or callbackObject)
             if arrayObject or dateObject or callbackObject:
--- a/dom/bluetooth/ipc/PBluetooth.ipdl
+++ b/dom/bluetooth/ipc/PBluetooth.ipdl
@@ -7,17 +7,17 @@
 include protocol PBlob;
 include protocol PBluetoothRequest;
 include protocol PContent;
 
 include BluetoothTypes;
 
 include "mozilla/dom/bluetooth/ipc/BluetoothMessageUtils.h";
 
-using mozilla::dom::bluetooth::BluetoothObjectType;
+using mozilla::dom::bluetooth::BluetoothObjectType from "mozilla/dom/bluetooth/BluetoothCommon.h";
 
 namespace mozilla {
 namespace dom {
 namespace bluetooth {
 
 /**
  * Bluetooth request types.
  */
new file mode 100644
--- /dev/null
+++ b/dom/encoding/FallbackEncoding.cpp
@@ -0,0 +1,137 @@
+/* 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 "mozilla/dom/FallbackEncoding.h"
+
+#include "mozilla/dom/EncodingUtils.h"
+#include "nsUConvPropertySearch.h"
+#include "nsIChromeRegistry.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/Services.h"
+
+namespace mozilla {
+namespace dom {
+
+static const char* localesFallbacks[][3] = {
+#include "localesfallbacks.properties.h"
+};
+
+FallbackEncoding* FallbackEncoding::sInstance = nullptr;
+
+FallbackEncoding::FallbackEncoding()
+{
+  MOZ_COUNT_CTOR(FallbackEncoding);
+  MOZ_ASSERT(!FallbackEncoding::sInstance,
+             "Singleton already exists.");
+}
+
+FallbackEncoding::~FallbackEncoding()
+{
+  MOZ_COUNT_DTOR(FallbackEncoding);
+}
+
+void
+FallbackEncoding::Get(nsACString& aFallback)
+{
+  if (!mFallback.IsEmpty()) {
+    aFallback = mFallback;
+    return;
+  }
+
+  const nsAdoptingCString& override =
+    Preferences::GetCString("intl.charset.fallback.override");
+  // Don't let the user break things by setting the override to unreasonable
+  // values via about:config
+  if (!EncodingUtils::FindEncodingForLabel(override, mFallback) ||
+      !EncodingUtils::IsAsciiCompatible(mFallback) ||
+      mFallback.EqualsLiteral("UTF-8")) {
+    mFallback.Truncate();
+  }
+
+  if (!mFallback.IsEmpty()) {
+    aFallback = mFallback;
+    return;
+  }
+
+  nsAutoCString locale;
+  nsCOMPtr<nsIXULChromeRegistry> registry =
+    mozilla::services::GetXULChromeRegistryService();
+  if (registry) {
+    registry->GetSelectedLocale(NS_LITERAL_CSTRING("global"), locale);
+  }
+
+  // Let's lower case the string just in case unofficial language packs
+  // don't stick to conventions.
+  ToLowerCase(locale); // ASCII lowercasing with CString input!
+
+  // Special case Traditional Chinese before throwing away stuff after the
+  // language itself. Today we only ship zh-TW, but be defensive about
+  // possible future values.
+  if (locale.EqualsLiteral("zh-tw") ||
+      locale.EqualsLiteral("zh-hk") ||
+      locale.EqualsLiteral("zh-mo") ||
+      locale.EqualsLiteral("zh-hant")) {
+    mFallback.AssignLiteral("Big5");
+    aFallback = mFallback;
+    return;
+  }
+
+  // Throw away regions and other variants to accommodate weird stuff seen
+  // in telemetry--apparently unofficial language packs.
+  int32_t index = locale.FindChar('-');
+  if (index >= 0) {
+    locale.Truncate(index);
+  }
+
+  if (NS_FAILED(nsUConvPropertySearch::SearchPropertyValue(
+      localesFallbacks, ArrayLength(localesFallbacks), locale, mFallback))) {
+    mFallback.AssignLiteral("windows-1252");
+  }
+
+  aFallback = mFallback;
+}
+
+void
+FallbackEncoding::FromLocale(nsACString& aFallback)
+{
+  MOZ_ASSERT(FallbackEncoding::sInstance,
+             "Using uninitialized fallback cache.");
+  FallbackEncoding::sInstance->Get(aFallback);
+}
+
+// PrefChangedFunc
+int
+FallbackEncoding::PrefChanged(const char*, void*)
+{
+  MOZ_ASSERT(FallbackEncoding::sInstance,
+             "Pref callback called with null fallback cache.");
+  FallbackEncoding::sInstance->Invalidate();
+  return 0;
+}
+
+void
+FallbackEncoding::Initialize()
+{
+  MOZ_ASSERT(!FallbackEncoding::sInstance,
+             "Initializing pre-existing fallback cache.");
+  FallbackEncoding::sInstance = new FallbackEncoding;
+  Preferences::RegisterCallback(FallbackEncoding::PrefChanged,
+                                "intl.charset.fallback.override",
+                                nullptr);
+  Preferences::RegisterCallback(FallbackEncoding::PrefChanged,
+                                "general.useragent.locale",
+                                nullptr);
+}
+
+void
+FallbackEncoding::Shutdown()
+{
+  MOZ_ASSERT(FallbackEncoding::sInstance,
+             "Releasing non-existent fallback cache.");
+  delete FallbackEncoding::sInstance;
+  FallbackEncoding::sInstance = nullptr;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/encoding/FallbackEncoding.h
@@ -0,0 +1,72 @@
+/* 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_dom_FallbackEncoding_h_
+#define mozilla_dom_FallbackEncoding_h_
+
+#include "nsString.h"
+
+namespace mozilla {
+namespace dom {
+
+class FallbackEncoding
+{
+public:
+
+  /**
+   * Gets the locale-dependent fallback encoding for legacy HTML and plain
+   * text content.
+   *
+   * @param aFallback the outparam for the fallback encoding
+   */
+  static void FromLocale(nsACString& aFallback);
+
+  // public API ends here!
+
+  /**
+   * Allocate sInstance used by FromLocale().
+   * To be called from nsLayoutStatics only.
+   */
+  static void Initialize();
+
+  /**
+   * Delete sInstance used by FromLocale().
+   * To be called from nsLayoutStatics only.
+   */
+  static void Shutdown();
+
+private:
+
+  /**
+   * The fallback cache.
+   */
+  static FallbackEncoding* sInstance;
+
+  FallbackEncoding();
+  ~FallbackEncoding();
+
+  /**
+   * Invalidates the cache.
+   */
+  void Invalidate()
+  {
+    mFallback.Truncate();
+  }
+
+  static int PrefChanged(const char*, void*);
+
+  /**
+   * Gets the fallback encoding label.
+   * @param aFallback the fallback encoding
+   */
+  void Get(nsACString& aFallback);
+
+  nsCString mFallback;
+};
+
+} // dom
+} // mozilla
+
+#endif // mozilla_dom_FallbackEncoding_h_
+
--- a/dom/encoding/Makefile.in
+++ b/dom/encoding/Makefile.in
@@ -4,16 +4,20 @@
 
 LOCAL_INCLUDES = \
 	-I$(topsrcdir)/intl/locale/src \
 	$(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
 EncodingUtils.$(OBJ_SUFFIX): labelsencodings.properties.h
+FallbackEncoding.$(OBJ_SUFFIX): localesfallbacks.properties.h
 
 PROPS2ARRAYS = $(topsrcdir)/intl/locale/src/props2arrays.py
 labelsencodings.properties.h: $(PROPS2ARRAYS) labelsencodings.properties
 	$(PYTHON) $^ $@
+localesfallbacks.properties.h: $(PROPS2ARRAYS) localesfallbacks.properties
+	$(PYTHON) $^ $@
 
 GARBAGE += \
-	charsetalias.properties.h \
+	labelsencodings.properties.h \
+	localesfallbacks.properties.h \
 	$(NULL)
new file mode 100644
--- /dev/null
+++ b/dom/encoding/localesfallbacks.properties
@@ -0,0 +1,72 @@
+# 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/.
+
+# This file contains mappings from languages to legacy encodings for languages
+# that are associated with legacy encoding other than windows-1252 (except
+# Traditional Chinese, which is handled as a special case elsewhere).
+#
+# The keys are language codes without regions. The values are Gecko-canonical
+# encoding labels (not necessarily lower case!).
+#
+# Rules:
+#
+# * Avoid editing this file!
+#
+# * If you do edit this file, be sure to file a spec bug against WHATWG HTML
+#   to keep this file in sync with
+#   http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#determining-the-character-encoding
+#
+# * As an exception to the previous rule, gbk is used instead of GB18030 
+#   until/unless work on http://encoding.spec.whatwg.org/ shows that the former
+#   can be treated as an alias of the latter and our decoder implementation 
+#   has been audited to match the spec.
+#
+# * Use only the language code without a hyphen or anything that would come
+#   after the hyphen.
+#
+# * Don't put windows-1252-affiliated languages here.
+#
+# * Don't put Traditional Chinese here.
+
+ar=windows-1256
+# https://www.w3.org/Bugs/Public/show_bug.cgi?id=23089
+ba=windows-1251
+# https://www.w3.org/Bugs/Public/show_bug.cgi?id=23089
+be=windows-1251
+bg=windows-1251
+cs=windows-1250
+# https://www.w3.org/Bugs/Public/show_bug.cgi?id=23090
+el=ISO-8859-7
+et=windows-1257
+fa=windows-1256
+he=windows-1255
+hr=windows-1250
+hu=ISO-8859-2
+ja=Shift_JIS
+# https://www.w3.org/Bugs/Public/show_bug.cgi?id=23089
+kk=windows-1251
+ko=EUC-KR
+ku=windows-1254
+# https://www.w3.org/Bugs/Public/show_bug.cgi?id=23089
+ky=windows-1251
+lt=windows-1257
+lv=windows-1257
+# https://www.w3.org/Bugs/Public/show_bug.cgi?id=23089
+mk=windows-1251
+pl=ISO-8859-2
+ru=windows-1251
+# https://www.w3.org/Bugs/Public/show_bug.cgi?id=23089
+sah=windows-1251
+sk=windows-1250
+sl=ISO-8859-2
+sr=windows-1251
+# https://www.w3.org/Bugs/Public/show_bug.cgi?id=23089
+tg=windows-1251
+th=windows-874
+tr=windows-1254
+# https://www.w3.org/Bugs/Public/show_bug.cgi?id=23089
+tt=windows-1251
+uk=windows-1251
+vi=windows-1258
+zh=gbk
--- a/dom/encoding/moz.build
+++ b/dom/encoding/moz.build
@@ -5,22 +5,24 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 TEST_DIRS += ['test']
 
 MODULE = 'dom'
 
 EXPORTS.mozilla.dom += [
     'EncodingUtils.h',
+    'FallbackEncoding.h',
     'TextDecoder.h',
     'TextEncoder.h',
 ]
 
 SOURCES += [
     'EncodingUtils.cpp',
+    'FallbackEncoding.cpp',
     'TextDecoder.cpp',
     'TextEncoder.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
 LIBXUL_LIBRARY = True
 
--- a/dom/fmradio/ipc/PFMRadio.ipdl
+++ b/dom/fmradio/ipc/PFMRadio.ipdl
@@ -1,18 +1,17 @@
 /* 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 "mozilla/HalTypes.h";
 
 include protocol PContent;
 include protocol PFMRadioRequest;
 
-using mozilla::hal::FMRadioSeekDirection;
+using mozilla::hal::FMRadioSeekDirection from "mozilla/HalTypes.h";
 
 namespace mozilla {
 namespace dom {
 
 struct EnableRequestArgs
 {
   double frequency;
 };
--- a/dom/indexedDB/IDBDatabase.h
+++ b/dom/indexedDB/IDBDatabase.h
@@ -157,16 +157,22 @@ public:
     return mContentParent;
   }
 
   already_AddRefed<IDBObjectStore>
   CreateObjectStoreInternal(IDBTransaction* aTransaction,
                             const ObjectStoreInfoGuts& aInfo,
                             ErrorResult& aRv);
 
+  IDBFactory*
+  Factory() const
+  {
+    return mFactory;
+  }
+
   // nsWrapperCache
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
   // WebIDL
   nsPIDOMWindow*
   GetParentObject() const
   {
@@ -217,16 +223,17 @@ public:
     return PersistenceTypeToStorage(mPersistenceType);
   }
 
   already_AddRefed<IDBRequest>
   MozCreateFileHandle(const nsAString& aName, const Optional<nsAString>& aType,
                       ErrorResult& aRv);
 
   virtual void LastRelease() MOZ_OVERRIDE;
+
 private:
   IDBDatabase();
   ~IDBDatabase();
 
   void OnUnlink();
 
   // The factory must be kept alive when IndexedDB is used in multiple
   // processes. If it dies then the entire actor tree will be destroyed with it
--- a/dom/indexedDB/IDBFactory.h
+++ b/dom/indexedDB/IDBFactory.h
@@ -142,16 +142,22 @@ public:
   }
 
   const nsCString&
   GetASCIIOrigin() const
   {
     return mASCIIOrigin;
   }
 
+  bool
+  FromIPC()
+  {
+    return !!mContentParent;
+  }
+
   // nsWrapperCache
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
   // WebIDL
   nsPIDOMWindow*
   GetParentObject() const
   {
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -61,69 +61,60 @@ IDBRequest::IDBRequest()
 IDBRequest::~IDBRequest()
 {
   mResultVal = JSVAL_VOID;
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
 // static
 already_AddRefed<IDBRequest>
-IDBRequest::Create(IDBWrapperCache* aOwnerCache,
+IDBRequest::Create(IDBDatabase* aDatabase,
                    IDBTransaction* aTransaction)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   nsRefPtr<IDBRequest> request(new IDBRequest());
 
   request->mTransaction = aTransaction;
-  request->BindToOwner(aOwnerCache);
-  request->SetScriptOwner(aOwnerCache->GetScriptOwner());
-  request->CaptureCaller();
+  request->BindToOwner(aDatabase);
+  request->SetScriptOwner(aDatabase->GetScriptOwner());
+
+  if (!aDatabase->Factory()->FromIPC()) {
+    request->CaptureCaller();
+  }
+
 
   return request.forget();
 }
 
 // static
 already_AddRefed<IDBRequest>
 IDBRequest::Create(IDBObjectStore* aSourceAsObjectStore,
-                   IDBWrapperCache* aOwnerCache,
+                   IDBDatabase* aDatabase,
                    IDBTransaction* aTransaction)
 {
-  nsRefPtr<IDBRequest> request = Create(aOwnerCache, aTransaction);
+  nsRefPtr<IDBRequest> request = Create(aDatabase, aTransaction);
 
   request->mSourceAsObjectStore = aSourceAsObjectStore;
 
   return request.forget();
 }
 
 // static
 already_AddRefed<IDBRequest>
 IDBRequest::Create(IDBIndex* aSourceAsIndex,
-                   IDBWrapperCache* aOwnerCache,
+                   IDBDatabase* aDatabase,
                    IDBTransaction* aTransaction)
 {
-  nsRefPtr<IDBRequest> request = Create(aOwnerCache, aTransaction);
+  nsRefPtr<IDBRequest> request = Create(aDatabase, aTransaction);
 
   request->mSourceAsIndex = aSourceAsIndex;
 
   return request.forget();
 }
 
-// static
-already_AddRefed<IDBRequest>
-IDBRequest::Create(IDBCursor* aSourceAsCursor,
-                   IDBWrapperCache* aOwnerCache,
-                   IDBTransaction* aTransaction)
-{
-  nsRefPtr<IDBRequest> request = Create(aOwnerCache, aTransaction);
-
-  request->mSourceAsCursor = aSourceAsCursor;
-
-  return request.forget();
-}
-
 #ifdef DEBUG
 void
 IDBRequest::AssertSourceIsCorrect() const
 {
   // At most one of mSourceAs* is allowed to be non-null.  Check that by
   // summing the double negation of each one and asserting the sum is at most
   // 1.
 
@@ -282,21 +273,17 @@ IDBRequest::GetJSContext()
 void
 IDBRequest::CaptureCaller()
 {
   AutoJSContext cx;
 
   const char* filename = nullptr;
   uint32_t lineNo = 0;
   if (!nsJSUtils::GetCallingLocation(cx, &filename, &lineNo)) {
-    // If our caller is in another process, we won't have a JSContext on the
-    // stack, and AutoJSContext will push the SafeJSContext. But that won't have
-    // any script on it (certainly not after the push), so GetCallingLocation
-    // will fail when it calls JS_DescribeScriptedCaller. That's fine.
-    NS_WARNING("Failed to get caller.");
+    MOZ_CRASH("Failed to get caller.");
     return;
   }
 
   mFilename.Assign(NS_ConvertUTF8toUTF16(filename));
   mLineNo = lineNo;
 }
 
 void
@@ -413,19 +400,22 @@ IDBOpenDBRequest::Create(IDBFactory* aFa
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aFactory, "Null pointer!");
 
   nsRefPtr<IDBOpenDBRequest> request = new IDBOpenDBRequest();
 
   request->BindToOwner(aOwner);
   request->SetScriptOwner(aScriptOwner);
-  request->CaptureCaller();
   request->mFactory = aFactory;
 
+  if (!aFactory->FromIPC()) {
+    request->CaptureCaller();
+  }
+
   return request.forget();
 }
 
 void
 IDBOpenDBRequest::SetTransaction(IDBTransaction* aTransaction)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
--- a/dom/indexedDB/IDBRequest.h
+++ b/dom/indexedDB/IDBRequest.h
@@ -41,31 +41,27 @@ class IndexedDBRequestParentBase;
 class IDBRequest : public IDBWrapperCache
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(IDBRequest,
                                                          IDBWrapperCache)
 
   static
-  already_AddRefed<IDBRequest> Create(IDBWrapperCache* aOwnerCache,
+  already_AddRefed<IDBRequest> Create(IDBDatabase* aDatabase,
                                       IDBTransaction* aTransaction);
 
   static
   already_AddRefed<IDBRequest> Create(IDBObjectStore* aSource,
-                                      IDBWrapperCache* aOwnerCache,
+                                      IDBDatabase* aDatabase,
                                       IDBTransaction* aTransaction);
 
   static
   already_AddRefed<IDBRequest> Create(IDBIndex* aSource,
-                                      IDBWrapperCache* aOwnerCache,
-                                      IDBTransaction* aTransaction);
-  static
-  already_AddRefed<IDBRequest> Create(IDBCursor* aSource,
-                                      IDBWrapperCache* aOwnerCache,
+                                      IDBDatabase* aDatabase,
                                       IDBTransaction* aTransaction);
 
   // nsIDOMEventTarget
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor) MOZ_OVERRIDE;
 
   void GetSource(Nullable<OwningIDBObjectStoreOrIDBIndexOrIDBCursor>& aSource) const;
 
   void Reset();
--- a/dom/indexedDB/ipc/IndexedDBParams.ipdlh
+++ b/dom/indexedDB/ipc/IndexedDBParams.ipdlh
@@ -1,19 +1,19 @@
 /* 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 "mozilla/dom/indexedDB/SerializationHelpers.h";
 
-using mozilla::dom::indexedDB::Key;
-using mozilla::dom::indexedDB::IDBCursor::Direction;
-using mozilla::dom::indexedDB::SerializedStructuredCloneReadInfo;
+using class mozilla::dom::indexedDB::Key from "mozilla/dom/indexedDB/Key.h";
+using mozilla::dom::indexedDB::IDBCursor::Direction from "mozilla/dom/indexedDB/IDBCursor.h";
+using struct mozilla::dom::indexedDB::SerializedStructuredCloneReadInfo from "mozilla/dom/indexedDB/IndexedDatabase.h";
 
-using mozilla::void_t;
+using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 
 namespace mozilla {
 namespace dom {
 namespace indexedDB {
 namespace ipc {
 
 struct KeyRange
 {
--- a/dom/indexedDB/ipc/PIndexedDB.ipdl
+++ b/dom/indexedDB/ipc/PIndexedDB.ipdl
@@ -4,17 +4,17 @@
 
 include protocol PBrowser;
 include protocol PContent;
 include protocol PIndexedDBDatabase;
 include protocol PIndexedDBDeleteDatabaseRequest;
 
 include "mozilla/dom/indexedDB/SerializationHelpers.h";
 
-using mozilla::dom::quota::PersistenceType;
+using mozilla::dom::quota::PersistenceType from "mozilla/dom/quota/PersistenceType.h";
 
 namespace mozilla {
 namespace dom {
 namespace indexedDB {
 
 protocol PIndexedDB
 {
   manager PBrowser or PContent;
--- a/dom/indexedDB/ipc/PIndexedDBCursor.ipdl
+++ b/dom/indexedDB/ipc/PIndexedDBCursor.ipdl
@@ -3,20 +3,20 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PIndexedDBIndex;
 include protocol PIndexedDBObjectStore;
 include protocol PIndexedDBRequest;
 
 include "mozilla/dom/indexedDB/SerializationHelpers.h";
 
-using mozilla::dom::indexedDB::Key;
-using mozilla::dom::indexedDB::IDBCursor::Direction;
+using class mozilla::dom::indexedDB::Key from "mozilla/dom/indexedDB/Key.h";
+using mozilla::dom::indexedDB::IDBCursor::Direction from "mozilla/dom/indexedDB/IDBCursor.h";
 
-using mozilla::void_t;
+using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 
 namespace mozilla {
 namespace dom {
 namespace indexedDB {
 
 namespace ipc {
 
 struct ContinueParams
--- a/dom/indexedDB/ipc/PIndexedDBDatabase.ipdl
+++ b/dom/indexedDB/ipc/PIndexedDBDatabase.ipdl
@@ -2,19 +2,19 @@
  * 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 protocol PIndexedDB;
 include protocol PIndexedDBTransaction;
 
 include "mozilla/dom/indexedDB/SerializationHelpers.h";
 
-using mozilla::dom::indexedDB::DatabaseInfoGuts;
-using mozilla::dom::indexedDB::ObjectStoreInfoGuts;
-using mozilla::dom::indexedDB::IDBTransaction::Mode;
+using struct mozilla::dom::indexedDB::DatabaseInfoGuts from "mozilla/dom/indexedDB/DatabaseInfo.h";
+using struct mozilla::dom::indexedDB::ObjectStoreInfoGuts from "mozilla/dom/indexedDB/DatabaseInfo.h";
+using mozilla::dom::indexedDB::IDBTransaction::Mode from "mozilla/dom/indexedDB/IDBTransaction.h";
 
 namespace mozilla {
 namespace dom {
 namespace indexedDB {
 
 namespace ipc {
 
 struct NormalTransactionParams
--- a/dom/indexedDB/ipc/PIndexedDBObjectStore.ipdl
+++ b/dom/indexedDB/ipc/PIndexedDBObjectStore.ipdl
@@ -5,19 +5,19 @@
 include protocol PBlob;
 include protocol PIndexedDBCursor;
 include protocol PIndexedDBIndex;
 include protocol PIndexedDBRequest;
 include protocol PIndexedDBTransaction;
 
 include IndexedDBParams;
 
-using mozilla::dom::indexedDB::IndexInfo;
-using mozilla::dom::indexedDB::IndexUpdateInfo;
-using mozilla::dom::indexedDB::SerializedStructuredCloneWriteInfo;
+using struct mozilla::dom::indexedDB::IndexInfo from "mozilla/dom/indexedDB/DatabaseInfo.h";
+using struct mozilla::dom::indexedDB::IndexUpdateInfo from "mozilla/dom/indexedDB/DatabaseInfo.h";
+using struct mozilla::dom::indexedDB::SerializedStructuredCloneWriteInfo from "mozilla/dom/indexedDB/IndexedDatabase.h";
 
 namespace mozilla {
 namespace dom {
 namespace indexedDB {
 
 namespace ipc {
 
 struct AddPutParams
--- a/dom/indexedDB/ipc/PIndexedDBRequest.ipdl
+++ b/dom/indexedDB/ipc/PIndexedDBRequest.ipdl
@@ -4,20 +4,20 @@
 
 include protocol PBlob;
 include protocol PIndexedDBCursor;
 include protocol PIndexedDBIndex;
 include protocol PIndexedDBObjectStore;
 
 include "mozilla/dom/indexedDB/SerializationHelpers.h";
 
-using mozilla::dom::indexedDB::Key;
-using mozilla::dom::indexedDB::SerializedStructuredCloneReadInfo;
+using class mozilla::dom::indexedDB::Key from "mozilla/dom/indexedDB/Key.h";
+using struct mozilla::dom::indexedDB::SerializedStructuredCloneReadInfo from "mozilla/dom/indexedDB/IndexedDatabase.h";
 
-using mozilla::void_t;
+using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 
 namespace mozilla {
 namespace dom {
 namespace indexedDB {
 
 namespace ipc {
 
 struct GetResponse
--- a/dom/indexedDB/ipc/PIndexedDBTransaction.ipdl
+++ b/dom/indexedDB/ipc/PIndexedDBTransaction.ipdl
@@ -2,17 +2,17 @@
  * 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 protocol PIndexedDBDatabase;
 include protocol PIndexedDBObjectStore;
 
 include "mozilla/dom/indexedDB/SerializationHelpers.h";
 
-using mozilla::dom::indexedDB::ObjectStoreInfoGuts;
+using struct mozilla::dom::indexedDB::ObjectStoreInfoGuts from "mozilla/dom/indexedDB/DatabaseInfo.h";
 
 namespace mozilla {
 namespace dom {
 namespace indexedDB {
 
 namespace ipc {
 
 struct CreateObjectStoreParams
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -112,16 +112,17 @@
 #include "StructuredCloneUtils.h"
 #include "URIUtils.h"
 #include "nsContentUtils.h"
 #include "nsIPrincipal.h"
 #include "nsDeviceStorage.h"
 #include "AudioChannelService.h"
 #include "JavaScriptChild.h"
 #include "mozilla/dom/telephony/PTelephonyChild.h"
+#include "mozilla/net/NeckoMessageUtils.h"
 
 using namespace base;
 using namespace mozilla;
 using namespace mozilla::docshell;
 using namespace mozilla::dom::bluetooth;
 using namespace mozilla::dom::devicestorage;
 using namespace mozilla::dom::ipc;
 using namespace mozilla::dom::mobilemessage;
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -86,16 +86,17 @@
 #include "PreallocatedProcessManager.h"
 #include "ProcessPriorityManager.h"
 #include "SandboxHal.h"
 #include "StructuredCloneUtils.h"
 #include "TabParent.h"
 #include "URIUtils.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsIDocShell.h"
+#include "mozilla/net/NeckoMessageUtils.h"
 
 #if defined(ANDROID) || defined(LINUX)
 #include "nsSystemInfo.h"
 #endif
 
 #ifdef ANDROID
 # include "gfxAndroidPlatform.h"
 #endif
@@ -1416,16 +1417,17 @@ ContentParent::ContentParent(mozIApplica
 
     // From this point on, NS_WARNING, NS_ASSERTION, etc. should print out the
     // PID along with the warning.
     nsDebugImpl::SetMultiprocessMode("Parent");
 
     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     mSubprocess = new GeckoChildProcessHost(GeckoProcessType_Content,
                                             aOSPrivileges);
+    mSubprocess->SetSandboxEnabled(ShouldSandboxContentProcesses());
 
     IToplevelProtocol::SetTransport(mSubprocess->GetChannel());
 
     std::vector<std::string> extraArgs;
     if (aIsNuwaProcess) {
         extraArgs.push_back("-nuwa");
     }
     mSubprocess->LaunchAndWaitForProcessHandle(extraArgs);
@@ -3277,10 +3279,20 @@ bool
 ContentParent::ShouldContinueFromReplyTimeout()
 {
   // The only time ContentParent sends blocking messages is for CPOWs, so
   // timeouts should only ever occur in electrolysis-enabled sessions.
   MOZ_ASSERT(Preferences::GetBool("browser.tabs.remote", false));
   return false;
 }
 
+bool
+ContentParent::ShouldSandboxContentProcesses()
+{
+#ifdef MOZ_CONTENT_SANDBOX
+  return !PR_GetEnv("MOZ_DISABLE_CONTENT_SANDBOX");
+#else
+  return true;
+#endif
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -215,16 +215,17 @@ public:
     virtual bool SendNuwaFork();
 
 protected:
     void OnChannelConnected(int32_t pid) MOZ_OVERRIDE;
     virtual void ActorDestroy(ActorDestroyReason why);
     void OnNuwaForkTimeout();
 
     bool ShouldContinueFromReplyTimeout() MOZ_OVERRIDE;
+    bool ShouldSandboxContentProcesses();
 
 private:
     static nsDataHashtable<nsStringHashKey, ContentParent*> *sAppContentParents;
     static nsTArray<ContentParent*>* sNonAppContentParents;
     static nsTArray<ContentParent*>* sPrivateContent;
     static StaticAutoPtr<LinkedList<ContentParent> > sContentParents;
 
     static void JoinProcessesIOThread(const nsTArray<ContentParent*>* aProcesses,
--- a/dom/ipc/DOMTypes.ipdlh
+++ b/dom/ipc/DOMTypes.ipdlh
@@ -2,17 +2,17 @@
 /* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
 /* 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 protocol PBlob;
 include InputStreamParams;
 
-using mozilla::SerializedStructuredCloneBuffer;
+using struct mozilla::SerializedStructuredCloneBuffer from "ipc/IPCMessageUtils.h";
 
 namespace mozilla {
 namespace dom {
 
 struct ClonedMessageData
 {
   SerializedStructuredCloneBuffer data;
   PBlob[] blobs;
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -12,52 +12,45 @@ include protocol PDocumentRenderer;
 include protocol PContentPermissionRequest;
 include protocol PRenderFrame;
 include protocol POfflineCacheUpdate;
 include protocol PIndexedDB;
 include DOMTypes;
 include JavaScriptTypes;
 include URIParams;
 
-include "gfxMatrix.h";
-include "FrameMetrics.h";
-include "ipc/nsGUIEventIPC.h";
-include "mozilla/dom/TabMessageUtils.h";
-include "mozilla/dom/ScreenOrientation.h";
-include "mozilla/dom/PermissionMessageUtils.h";
-include "mozilla/layout/RenderFrameUtils.h";
-include "mozilla/layers/CompositorTypes.h";
 
-using IPC::Principal;
-using gfxMatrix;
-using gfxSize;
-using CSSRect;
-using mozilla::layers::FrameMetrics;
-using FrameMetrics::ViewID;
-using mozilla::layout::ScrollingBehavior;
-using mozilla::void_t;
-using mozilla::WindowsHandle;
-using nscolor;
-using mozilla::WidgetCompositionEvent;
-using nsIMEUpdatePreference;
-using nsIntPoint;
-using nsIntRect;
-using nsIntSize;
-using mozilla::WidgetKeyboardEvent;
-using mozilla::WidgetMouseEvent;
-using mozilla::WidgetWheelEvent;
-using nsRect;
-using mozilla::WidgetSelectionEvent;
-using mozilla::WidgetTextEvent;
-using mozilla::WidgetTouchEvent;
-using RemoteDOMEvent;
-using mozilla::dom::ScreenOrientation;
-using mozilla::layers::TextureFactoryIdentifier;
-using mozilla::CSSIntPoint;
-using mozilla::CSSToScreenScale;
+using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
+using struct gfxMatrix from "gfxMatrix.h";
+using struct gfxSize from "gfxPoint.h";
+using CSSRect from "Units.h";
+using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
+using FrameMetrics::ViewID from "FrameMetrics.h";
+using mozilla::layout::ScrollingBehavior from "mozilla/layout/RenderFrameUtils.h";
+using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
+using mozilla::WindowsHandle from "ipc/IPCMessageUtils.h";
+using nscolor from "nsColor.h";
+using class mozilla::WidgetCompositionEvent from "ipc/nsGUIEventIPC.h";
+using struct nsIMEUpdatePreference from "nsIWidget.h";
+using struct nsIntPoint from "nsPoint.h";
+using struct nsIntRect from "nsRect.h";
+using struct nsIntSize from "nsSize.h";
+using class mozilla::WidgetKeyboardEvent from "ipc/nsGUIEventIPC.h";
+using class mozilla::WidgetMouseEvent from "ipc/nsGUIEventIPC.h";
+using class mozilla::WidgetWheelEvent from "ipc/nsGUIEventIPC.h";
+using struct nsRect from "nsRect.h";
+using class mozilla::WidgetSelectionEvent from "ipc/nsGUIEventIPC.h";
+using class mozilla::WidgetTextEvent from "ipc/nsGUIEventIPC.h";
+using class mozilla::WidgetTouchEvent from "ipc/nsGUIEventIPC.h";
+using struct mozilla::dom::RemoteDOMEvent from "mozilla/dom/TabMessageUtils.h";
+using mozilla::dom::ScreenOrientation from "mozilla/dom/ScreenOrientation.h";
+using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
+using mozilla::CSSIntPoint from "Units.h";
+using mozilla::CSSToScreenScale from "Units.h";
+
 namespace mozilla {
 namespace dom {
 
 intr protocol PBrowser
 {
     manager PContent;
 
     manages PContentDialog;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -25,42 +25,31 @@ include protocol PTestShell;
 include protocol PJavaScript;
 include DOMTypes;
 include JavaScriptTypes;
 include InputStreamParams;
 include PTabContext;
 include URIParams;
 include ProtocolTypes;
 
-include "mozilla/chrome/RegistryMessageUtils.h";
-include "mozilla/dom/PermissionMessageUtils.h";
-include "mozilla/dom/TabMessageUtils.h";
-include "mozilla/HalTypes.h";
-include "mozilla/layout/RenderFrameUtils.h";
-include "mozilla/net/NeckoMessageUtils.h";
-include "nsGeoPositionIPCSerialiser.h";
-include "gfxPoint.h";
-
-using GeoPosition;
-using PrefTuple;
+using GeoPosition from "nsGeoPositionIPCSerialiser.h";
 
-using ChromePackage;
-using ResourceMapping;
-using OverrideMapping;
-using base::ChildPrivileges;
-using IPC::Permission;
-using IPC::Principal;
-using mozilla::null_t;
-using mozilla::void_t;
-using mozilla::dom::AudioChannelType;
-using mozilla::dom::AudioChannelState;
-using mozilla::dom::BlobConstructorParams;
-using mozilla::dom::NativeThreadId;
-using mozilla::hal::ProcessPriority;
-using gfxIntSize;
+using struct ChromePackage from "mozilla/chrome/RegistryMessageUtils.h";
+using struct ResourceMapping from "mozilla/chrome/RegistryMessageUtils.h";
+using struct OverrideMapping from "mozilla/chrome/RegistryMessageUtils.h";
+using base::ChildPrivileges from "base/process_util.h";
+using struct IPC::Permission from "mozilla/net/NeckoMessageUtils.h";
+using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
+using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
+using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
+using mozilla::dom::AudioChannelType from "AudioChannelCommon.h";
+using mozilla::dom::AudioChannelState from "AudioChannelCommon.h";
+using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
+using mozilla::hal::ProcessPriority from "mozilla/HalTypes.h";
+using gfxIntSize from "nsSize.h";
 
 namespace mozilla {
 namespace dom {
 
 struct FontListEntry {
     nsString  familyName;
     nsString  faceName;
     nsCString filepath;
--- a/dom/ipc/PDocumentRenderer.ipdl
+++ b/dom/ipc/PDocumentRenderer.ipdl
@@ -2,17 +2,17 @@
 /* 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 protocol PBrowser;
 
 include "mozilla/GfxMessageUtils.h";
 
-using nsIntSize;
+using struct nsIntSize from "nsSize.h";
 
 namespace mozilla {
 namespace ipc {
 
 protocol PDocumentRenderer
 {
   manager PBrowser;
 
--- a/dom/ipc/PTabContext.ipdlh
+++ b/dom/ipc/PTabContext.ipdlh
@@ -1,19 +1,18 @@
 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8 -*- */
 /* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
 /* 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 protocol PBrowser;
 
-include "mozilla/layout/RenderFrameUtils.h";
 
-using mozilla::layout::ScrollingBehavior;
+using mozilla::layout::ScrollingBehavior from "mozilla/layout/RenderFrameUtils.h";
 
 namespace mozilla {
 namespace dom {
 
 // An IPCTabContext which corresponds to a PBrowser opened by a child when it
 // receives window.open().
 //
 // If isBrowserElement is false, this PopupIPCTabContext corresponds to an app
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -64,16 +64,17 @@
 #include "nsWeakReference.h"
 #include "PCOMContentPermissionRequestChild.h"
 #include "PuppetWidget.h"
 #include "StructuredCloneUtils.h"
 #include "nsViewportInfo.h"
 #include "JavaScriptChild.h"
 #include "APZCCallbackHelper.h"
 #include "nsILoadContext.h"
+#include "ipc/nsGUIEventIPC.h"
 
 #define BROWSER_ELEMENT_CHILD_SCRIPT \
     NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js")
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::dom::ipc;
 using namespace mozilla::ipc;
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -30,30 +30,27 @@
 #include "nsIDialogCreator.h"
 #include "nsIPresShell.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsWeakReference.h"
 #include "nsITabChild.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/TabContext.h"
 #include "mozilla/EventForwards.h"
+#include "mozilla/layers/CompositorTypes.h"
 
 struct gfxMatrix;
 class nsICachedFileDescriptorListener;
 class nsIDOMWindowUtils;
 
 namespace mozilla {
 namespace layout {
 class RenderFrameChild;
 }
 
-namespace layers {
-struct TextureFactoryIdentifier;
-}
-
 namespace dom {
 
 class TabChild;
 class PContentDialogChild;
 class ClonedMessageData;
 
 class TabChildGlobal : public nsDOMEventTargetHelper,
                        public nsIContentFrameMessageManager,
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -17,17 +17,19 @@
 #include "nsIDialogParamBlock.h"
 #include "nsISecureBrowserUI.h"
 #include "nsITabParent.h"
 #include "Units.h"
 #include "js/TypeDecls.h"
 
 struct gfxMatrix;
 class nsFrameLoader;
+class nsIContent;
 class nsIURI;
+class nsIWidget;
 class CpowHolder;
 
 namespace mozilla {
 
 namespace layers {
 struct FrameMetrics;
 struct TextureFactoryIdentifier;
 }
--- a/dom/media/MediaPermissionGonk.cpp
+++ b/dom/media/MediaPermissionGonk.cpp
@@ -15,16 +15,17 @@
 #include "nsTArray.h"
 #include "GetUserMediaRequest.h"
 #include "PCOMContentPermissionRequestChild.h"
 #include "mozilla/dom/PBrowserChild.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/MediaStreamTrackBinding.h"
 #include "nsISupportsPrimitives.h"
 #include "nsServiceManagerUtils.h"
+#include "mozilla/dom/PermissionMessageUtils.h"
 
 #define AUDIO_PERMISSION_NAME "audio-capture"
 
 namespace mozilla {
 
 static MediaPermissionManager *gMediaPermMgr = nullptr;
 
 // Helper function for notifying permission granted
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -11,17 +11,17 @@ Cu.import("resource://gre/modules/XPCOMU
 
 const PC_CONTRACT = "@mozilla.org/dom/peerconnection;1";
 const PC_OBS_CONTRACT = "@mozilla.org/dom/peerconnectionobserver;1";
 const PC_ICE_CONTRACT = "@mozilla.org/dom/rtcicecandidate;1";
 const PC_SESSION_CONTRACT = "@mozilla.org/dom/rtcsessiondescription;1";
 const PC_MANAGER_CONTRACT = "@mozilla.org/dom/peerconnectionmanager;1";
 const PC_STATS_CONTRACT = "@mozilla.org/dom/rtcstatsreport;1";
 
-const PC_CID = Components.ID("{fc684a5c-c729-42c7-aa82-3c10dc4398f3}");
+const PC_CID = Components.ID("{00e0e20d-1494-4776-8e0e-0f0acbea3c79}");
 const PC_OBS_CID = Components.ID("{1d44a18e-4545-4ff3-863d-6dbd6234a583}");
 const PC_ICE_CID = Components.ID("{02b9970c-433d-4cc2-923d-f7028ac66073}");
 const PC_SESSION_CID = Components.ID("{1775081b-b62d-4954-8ffe-a067bbf508a7}");
 const PC_MANAGER_CID = Components.ID("{7293e901-2be3-4c02-b4bd-cbef6fc24f78}");
 const PC_STATS_CID = Components.ID("{7fe6e18b-0da3-4056-bf3b-440ef3809e06}");
 
 // Global list of PeerConnection objects, so they can be cleaned up when
 // a page is torn down. (Maps inner window ID to an array of PC objects).
@@ -714,28 +714,36 @@ RTCPeerConnection.prototype = {
   },
 
   changeIceConnectionState: function(state) {
     this._iceConnectionState = state;
     this.dispatchEvent(new this._win.Event("iceconnectionstatechange"));
   },
 
   getStats: function(selector, onSuccess, onError) {
-    this._onGetStatsSuccess = onSuccess;
-    this._onGetStatsFailure = onError;
-
     this._queueOrRun({
       func: this._getStats,
-      args: [selector],
+      args: [selector, onSuccess, onError, false],
       wait: true
     });
   },
 
-  _getStats: function(selector) {
-    this._getPC().getStats(selector);
+  getStatsInternal: function(selector, onSuccess, onError) {
+    this._queueOrRun({
+      func: this._getStats,
+      args: [selector, onSuccess, onError, true],
+      wait: true
+    });
+  },
+
+  _getStats: function(selector, onSuccess, onError, internal) {
+    this._onGetStatsSuccess = onSuccess;
+    this._onGetStatsFailure = onError;
+
+    this._getPC().getStats(selector, internal);
   },
 
   createDataChannel: function(label, dict) {
     this._checkClosed();
     if (dict == undefined) {
       dict = {};
     }
     if (dict.maxRetransmitNum != undefined) {
@@ -1072,16 +1080,17 @@ PeerConnectionObserver.prototype = {
     let report = {};
     appendStats(dict.rtpStreamStats, report);
     appendStats(dict.inboundRTPStreamStats, report);
     appendStats(dict.outboundRTPStreamStats, report);
     appendStats(dict.mediaStreamTrackStats, report);
     appendStats(dict.mediaStreamStats, report);
     appendStats(dict.transportStats, report);
     appendStats(dict.iceComponentStats, report);
+    appendStats(dict.iceCandidatePairStats, report);
     appendStats(dict.iceCandidateStats, report);
     appendStats(dict.codecStats, report);
 
     this.callCB(this._dompc._onGetStatsSuccess,
                 this._dompc._win.RTCStatsReport._create(this._dompc._win,
                                                         new RTCStatsReport(this._dompc._win,
                                                                            report)));
     this._dompc._executeNext();
--- a/dom/media/PeerConnection.manifest
+++ b/dom/media/PeerConnection.manifest
@@ -1,13 +1,13 @@
-component {fc684a5c-c729-42c7-aa82-3c10dc4398f3} PeerConnection.js
+component {00e0e20d-1494-4776-8e0e-0f0acbea3c79} PeerConnection.js
 component {1d44a18e-4545-4ff3-863d-6dbd6234a583} PeerConnection.js
 component {02b9970c-433d-4cc2-923d-f7028ac66073} PeerConnection.js
 component {1775081b-b62d-4954-8ffe-a067bbf508a7} PeerConnection.js
 component {7293e901-2be3-4c02-b4bd-cbef6fc24f78} PeerConnection.js
 component {7fe6e18b-0da3-4056-bf3b-440ef3809e06} PeerConnection.js
 
-contract @mozilla.org/dom/peerconnection;1 {fc684a5c-c729-42c7-aa82-3c10dc4398f3}
+contract @mozilla.org/dom/peerconnection;1 {00e0e20d-1494-4776-8e0e-0f0acbea3c79}
 contract @mozilla.org/dom/peerconnectionobserver;1 {1d44a18e-4545-4ff3-863d-6dbd6234a583}
 contract @mozilla.org/dom/rtcicecandidate;1 {02b9970c-433d-4cc2-923d-f7028ac66073}
 contract @mozilla.org/dom/rtcsessiondescription;1 {1775081b-b62d-4954-8ffe-a067bbf508a7}
 contract @mozilla.org/dom/peerconnectionmanager;1 {7293e901-2be3-4c02-b4bd-cbef6fc24f78}
 contract @mozilla.org/dom/rtcstatsreport;1 {7fe6e18b-0da3-4056-bf3b-440ef3809e06}
--- a/dom/mobilemessage/src/ipc/PMobileMessageCursor.ipdl
+++ b/dom/mobilemessage/src/ipc/PMobileMessageCursor.ipdl
@@ -1,16 +1,14 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* 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 "mozilla/dom/mobilemessage/Types.h";
-
 include protocol PSms;
 include protocol PBlob;
 include SmsTypes;
 
 namespace mozilla {
 namespace dom {
 namespace mobilemessage {
 
--- a/dom/mobilemessage/src/ipc/PSmsRequest.ipdl
+++ b/dom/mobilemessage/src/ipc/PSmsRequest.ipdl
@@ -1,17 +1,14 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* 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 "mozilla/dom/mobilemessage/Types.h";
-
 include protocol PSms;
 include protocol PBlob;
 include SmsTypes;
 
 namespace mozilla {
 namespace dom {
 namespace mobilemessage {
 
--- a/dom/mobilemessage/src/ipc/SmsTypes.ipdlh
+++ b/dom/mobilemessage/src/ipc/SmsTypes.ipdlh
@@ -1,22 +1,21 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* 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 "mozilla/dom/mobilemessage/Types.h";
 include protocol PBlob;
 
-using DeliveryState;
-using DeliveryStatus;
-using MessageClass;
-using ReadState;
-using MessageType;
+using DeliveryState from "mozilla/dom/mobilemessage/Types.h";
+using DeliveryStatus from "mozilla/dom/mobilemessage/Types.h";
+using MessageClass from "mozilla/dom/mobilemessage/Types.h";
+using ReadState from "mozilla/dom/mobilemessage/Types.h";
+using MessageType from "mozilla/dom/mobilemessage/Types.h";
 
 namespace mozilla {
 namespace dom {
 namespace mobilemessage {
 
 struct SmsSegmentInfoData
 {
   int32_t segments;
--- a/dom/network/src/PTCPSocket.ipdl
+++ b/dom/network/src/PTCPSocket.ipdl
@@ -4,17 +4,17 @@
 /* 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 protocol PNecko;
 
 include "mozilla/net/NeckoMessageUtils.h";
 
-using mozilla::void_t;
+using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 
 struct TCPError {
   nsString name;
 };
 
 union SendableData {
   uint8_t[];
   nsString;
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -519,17 +519,17 @@ nsJSObjWrapper::NP_Deallocate(NPObject *
 // static
 void
 nsJSObjWrapper::NP_Invalidate(NPObject *npobj)
 {
   nsJSObjWrapper *jsnpobj = (nsJSObjWrapper *)npobj;
 
   if (jsnpobj && jsnpobj->mJSObj) {
     // Unroot the object's JSObject
-    js_RemoveRoot(sJSRuntime, &jsnpobj->mJSObj);
+    JS_RemoveObjectRootRT(sJSRuntime, &jsnpobj->mJSObj);
 
     if (sJSObjWrappers.ops) {
       // Remove the wrapper from the hash
 
       nsJSObjWrapperKey key(jsnpobj->mJSObj, jsnpobj->mNpp);
       PL_DHashTableOperate(&sJSObjWrappers, &key, PL_DHASH_REMOVE);
     }
 
--- a/dom/plugins/ipc/PBrowserStream.ipdl
+++ b/dom/plugins/ipc/PBrowserStream.ipdl
@@ -1,22 +1,21 @@
 /* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
 /* 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 protocol PPluginInstance;
 
-include "mozilla/plugins/PluginMessageUtils.h";
 
-using mozilla::plugins::Buffer;
-using mozilla::plugins::IPCByteRanges;
+using mozilla::plugins::Buffer from "mozilla/plugins/PluginMessageUtils.h";
+using mozilla::plugins::IPCByteRanges from "mozilla/plugins/PluginMessageUtils.h";
 
-using NPError;
-using NPReason;
+using NPError from "npapi.h";
+using NPReason from "npapi.h";
 
 namespace mozilla {
 namespace plugins {
 
 /**
  * NPBrowserStream represents a NPStream sent from the browser to the plugin.
  */
 
--- a/dom/plugins/ipc/PPluginInstance.ipdl
+++ b/dom/plugins/ipc/PPluginInstance.ipdl
@@ -6,37 +6,35 @@
 include protocol PPluginBackgroundDestroyer;
 include protocol PPluginModule;
 include protocol PPluginScriptableObject;
 include protocol PBrowserStream;
 include protocol PPluginStream;
 include protocol PStreamNotify;
 include protocol PPluginSurface;
 
-include "mozilla/plugins/PluginMessageUtils.h";
-include "ipc/nsGUIEventIPC.h";
-include "gfxTypes.h";
+include "mozilla/GfxMessageUtils.h";
 
-using NPError;
-using NPRemoteWindow;
-using NPRemoteEvent;
-using NPRect;
-using NPImageFormat;
-using NPNURLVariable;
-using NPCoordinateSpace;
-using NPNVariable;
-using mozilla::plugins::NativeWindowHandle;
-using gfxSurfaceType;
-using gfxIntSize;
-using mozilla::null_t;
-using mozilla::plugins::WindowsSharedMemoryHandle;
-using mozilla::plugins::DXGISharedSurfaceHandle;
-using mozilla::CrossProcessMutexHandle;
-using SurfaceDescriptorX11;
-using nsIntRect;
+using NPError from "npapi.h";
+using struct mozilla::plugins::NPRemoteWindow from "mozilla/plugins/PluginMessageUtils.h";
+using struct mozilla::plugins::NPRemoteEvent from "mozilla/plugins/PluginMessageUtils.h";
+using NPRect from "npapi.h";
+using NPImageFormat from "npapi.h";
+using NPNURLVariable from "npapi.h";
+using NPCoordinateSpace from "npapi.h";
+using NPNVariable from "npapi.h";
+using mozilla::plugins::NativeWindowHandle from "mozilla/plugins/PluginMessageUtils.h";
+using gfxSurfaceType from "gfxTypes.h";
+using gfxIntSize from "nsSize.h";
+using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
+using mozilla::plugins::WindowsSharedMemoryHandle from "mozilla/plugins/PluginMessageUtils.h";
+using mozilla::plugins::DXGISharedSurfaceHandle from "mozilla/plugins/PluginMessageUtils.h";
+using mozilla::CrossProcessMutexHandle from "mozilla/ipc/CrossProcessMutex.h";
+using struct SurfaceDescriptorX11 from "gfxipc/ShadowLayerUtils.h";
+using struct nsIntRect from "nsRect.h";
 
 namespace mozilla {
 namespace plugins {
 
 struct IOSurfaceDescriptor {
   uint32_t surfaceId;
   double contentsScaleFactor;
 };
--- a/dom/plugins/ipc/PPluginModule.ipdl
+++ b/dom/plugins/ipc/PPluginModule.ipdl
@@ -3,25 +3,22 @@
  * 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 protocol PPluginIdentifier;
 include protocol PPluginInstance;
 include protocol PPluginScriptableObject;
 include protocol PCrashReporter;
 
-include "npapi.h";
-include "mozilla/plugins/PluginMessageUtils.h";
-include "mozilla/dom/TabMessageUtils.h";
 
-using NPError;
-using NPNVariable;
-using mozilla::dom::NativeThreadId;
-using mac_plugin_interposing::NSCursorInfo;
-using nsID;
+using NPError from "npapi.h";
+using NPNVariable from "npapi.h";
+using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
+using class mac_plugin_interposing::NSCursorInfo from "mozilla/plugins/PluginMessageUtils.h";
+using struct nsID from "nsID.h";
 
 namespace mozilla {
 namespace plugins {
 
 intr protocol PPluginModule
 {
   manages PPluginInstance;
   manages PPluginIdentifier;
--- a/dom/plugins/ipc/PPluginScriptableObject.ipdl
+++ b/dom/plugins/ipc/PPluginScriptableObject.ipdl
@@ -1,22 +1,18 @@
 /* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
 /* 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 protocol PPluginInstance;
 include protocol PPluginIdentifier;
 
-include "npapi.h";
-include "npruntime.h";
-include "mozilla/plugins/PluginMessageUtils.h";
-
-using mozilla::void_t;
-using mozilla::null_t;
+using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
+using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
 
 namespace mozilla {
 namespace plugins {
 
 union Variant {
   void_t;
   null_t;
   bool;
--- a/dom/plugins/ipc/PPluginStream.ipdl
+++ b/dom/plugins/ipc/PPluginStream.ipdl
@@ -1,20 +1,19 @@
 /* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
 /* 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 protocol PPluginInstance;
 
-include "mozilla/plugins/PluginMessageUtils.h";
 
-using mozilla::plugins::Buffer;
-using NPError;
-using NPReason;
+using mozilla::plugins::Buffer from "mozilla/plugins/PluginMessageUtils.h";
+using NPError from "npapi.h";
+using NPReason from "npapi.h";
 
 namespace mozilla {
 namespace plugins {
 
 /**
  * PPluginStream represents an NPStream sent from the plugin to the browser.
  */
 
--- a/dom/plugins/ipc/PStreamNotify.ipdl
+++ b/dom/plugins/ipc/PStreamNotify.ipdl
@@ -1,19 +1,18 @@
 /* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
 /* 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 protocol PPluginInstance;
 
-include "npapi.h";
 
-using NPReason;
+using NPReason from "npapi.h";
 
 namespace mozilla {
 namespace plugins {
 
 intr protocol PStreamNotify
 {
   manager PPluginInstance;
 
--- a/dom/plugins/ipc/PluginModuleChild.h
+++ b/dom/plugins/ipc/PluginModuleChild.h
@@ -26,16 +26,17 @@
 
 #ifdef MOZ_WIDGET_COCOA
 #include "PluginInterposeOSX.h"
 #endif
 
 #include "mozilla/plugins/PPluginModuleChild.h"
 #include "mozilla/plugins/PluginInstanceChild.h"
 #include "mozilla/plugins/PluginIdentifierChild.h"
+#include "mozilla/plugins/PluginMessageUtils.h"
 
 // NOTE: stolen from nsNPAPIPlugin.h
 
 /*
  * Use this macro before each exported function
  * (between the return address and the function
  * itself), to ensure that the function has the
  * right calling conventions on OS/2.
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -8,16 +8,17 @@
 #define mozilla_plugins_PluginModuleParent_h
 
 #include "base/process.h"
 #include "mozilla/FileUtils.h"
 #include "mozilla/PluginLibrary.h"
 #include "mozilla/plugins/ScopedMethodFactory.h"
 #include "mozilla/plugins/PluginProcessParent.h"
 #include "mozilla/plugins/PPluginModuleParent.h"
+#include "mozilla/plugins/PluginMessageUtils.h"
 #include "npapi.h"
 #include "npfunctions.h"
 #include "nsAutoPtr.h"
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
 #include "nsIObserver.h"
 
 #ifdef MOZ_CRASHREPORTER
--- a/dom/plugins/ipc/PluginScriptableObjectChild.h
+++ b/dom/plugins/ipc/PluginScriptableObjectChild.h
@@ -3,16 +3,17 @@
  * 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 dom_plugins_PluginScriptableObjectChild_h
 #define dom_plugins_PluginScriptableObjectChild_h 1
 
 #include "mozilla/plugins/PPluginScriptableObjectChild.h"
+#include "mozilla/plugins/PluginMessageUtils.h"
 
 #include "npruntime.h"
 
 namespace mozilla {
 namespace plugins {
 
 class PluginInstanceChild;
 class PluginScriptableObjectChild;
--- a/dom/plugins/ipc/PluginScriptableObjectParent.h
+++ b/dom/plugins/ipc/PluginScriptableObjectParent.h
@@ -3,16 +3,17 @@
  * 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 dom_plugins_PluginScriptableObjectParent_h
 #define dom_plugins_PluginScriptableObjectParent_h 1
 
 #include "mozilla/plugins/PPluginScriptableObjectParent.h"
+#include "mozilla/plugins/PluginMessageUtils.h"
 
 #include "npfunctions.h"
 #include "npruntime.h"
 
 namespace mozilla {
 namespace plugins {
 
 class PluginInstanceParent;
--- a/dom/plugins/test/mochitest/test_painting.html
+++ b/dom/plugins/test/mochitest/test_painting.html
@@ -92,17 +92,17 @@ function waitForPaint(func) {
 
 function waitForPaintHelper(func) {
   if (paint_waiter.getPaintCount() != paint_waiter.last_paint_count) {
     // hide the paint waiter
     paint_waiter.style.height = "0px";
     setTimeout(func, 0);
     return;
   }
-  setTimeout(function() { waitForPaintHelper(func); }, 100);
+  setTimeout(function() { waitForPaintHelper(func); }, 1000);
 }
 
 </script>
 
 <p id="display"></p>
 <div id="container">
   <embed id="paint-waiter" type="application/x-test"/>
   <div id="clip">
--- a/dom/src/geolocation/nsGeolocation.cpp
+++ b/dom/src/geolocation/nsGeolocation.cpp
@@ -19,16 +19,17 @@
 #include "nsIObserverService.h"
 #include "nsPIDOMWindow.h"
 #include "nsThreadUtils.h"
 #include "mozilla/Services.h"
 #include "mozilla/unused.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "PCOMContentPermissionRequestChild.h"
+#include "mozilla/dom/PermissionMessageUtils.h"
 
 class nsIPrincipal;
 
 #ifdef MOZ_ENABLE_QTMOBILITY
 #include "QTMLocationProvider.h"
 #endif
 
 #ifdef MOZ_WIDGET_ANDROID
--- a/dom/src/notification/Notification.cpp
+++ b/dom/src/notification/Notification.cpp
@@ -18,16 +18,17 @@
 #include "nsINotificationStorage.h"
 #include "nsIPermissionManager.h"
 #include "nsIUUIDGenerator.h"
 #include "nsServiceManagerUtils.h"
 #include "nsToolkitCompsCID.h"
 #include "nsGlobalWindow.h"
 #include "nsDOMJSUtils.h"
 #include "nsIScriptSecurityManager.h"
+#include "mozilla/dom/PermissionMessageUtils.h"
 #ifdef MOZ_B2G
 #include "nsIDOMDesktopNotification.h"
 #endif
 
 namespace mozilla {
 namespace dom {
 
 class NotificationStorageCallback MOZ_FINAL : public nsINotificationStorageCallback
--- a/dom/tests/mochitest/general/test_clientRects.html
+++ b/dom/tests/mochitest/general/test_clientRects.html
@@ -102,17 +102,17 @@ function checkElement(id, list, eps, doc
 
 <script>
 function doTest() {
   checkElement("d1", [[50,50,20,30]]);
   checkElement("d2", [[50,100,200,100],[250,100,200,100]]);
   checkElement("d3", []);
   checkElement("d4", [[50,250,50,50]]);
   checkElement("d5", [[70,330,40,40]]);
-  checkElement("s1", [[100,350,20,20]]);
+  checkElement("s1", [[100,350,20,20]], 0.1);
   var sqrt2 = Math.sqrt(2);
   checkElement("d6", [[100 - 50*sqrt2,500 - 50*sqrt2,100*sqrt2,100*sqrt2]], 0.1);
   checkElement("d7", [[50,550,100,100]]);
   checkElement("d8", [[50,700,100,100]]);
   checkElement("d9", [[0,0,800,1000]]);
   checkElement("d10", [[0,25,100,100]], 0, doc("f1"));
   checkElement("d11", [[0,0,100,100]], 0, doc("f2"));
   checkElement("d12", [[0,0,100,100]], 0, doc("f3"));
--- a/dom/webidl/PeerConnectionImpl.webidl
+++ b/dom/webidl/PeerConnectionImpl.webidl
@@ -30,17 +30,17 @@ interface PeerConnectionImpl  {
   void createAnswer(optional MediaConstraintsInternal constraints);
   [Throws]
   void setLocalDescription(long action, DOMString sdp);
   [Throws]
   void setRemoteDescription(long action, DOMString sdp);
 
   /* Stats call */
   [Throws]
-  void getStats(MediaStreamTrack? selector);
+  void getStats(MediaStreamTrack? selector, boolean internalStats);
 
   /* Adds the stream created by GetUserMedia */
   [Throws]
   void addStream(MediaStream stream);
   [Throws]
   void removeStream(MediaStream stream);
   [Throws]
   void closeStreams();
--- a/dom/webidl/RTCPeerConnection.webidl
+++ b/dom/webidl/RTCPeerConnection.webidl
@@ -120,15 +120,20 @@ interface mozRTCPeerConnection : EventTa
   attribute EventHandler onaddstream;
   attribute EventHandler onremovestream;
   attribute EventHandler oniceconnectionstatechange;
 
   void getStats (MediaStreamTrack? selector,
                  RTCStatsCallback successCallback,
                  RTCPeerConnectionErrorCallback failureCallback);
 
+  [ChromeOnly]
+  void getStatsInternal (MediaStreamTrack? selector,
+                         RTCStatsCallback successCallback,
+                         RTCPeerConnectionErrorCallback failureCallback);
+
   // Data channel.
   RTCDataChannel createDataChannel (DOMString label,
                                     optional RTCDataChannelInit dataChannelDict);
   attribute EventHandler ondatachannel;
   attribute EventHandler onconnection;
   attribute EventHandler onclosedconnection;
 };
--- a/dom/webidl/RTCStatsReport.webidl
+++ b/dom/webidl/RTCStatsReport.webidl
@@ -4,17 +4,23 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
  * http://dev.w3.org/2011/webrtc/editor/webrtc.html#rtcstatsreport-object
  */
 
 enum RTCStatsType {
   "inboundrtp",
-  "outboundrtp"
+  "outboundrtp",
+  "session",
+  "track",
+  "transport",
+  "candidatepair",
+  "localcandidate",
+  "remotecandidate"
 };
 
 dictionary RTCStats {
   DOMHighResTimeStamp timestamp;
   RTCStatsType type;
   DOMString id;
 };
 
@@ -65,16 +71,36 @@ dictionary RTCTransportStats: RTCStats {
 dictionary RTCIceComponentStats : RTCStats {
   DOMString transportId;
   long component;
   unsigned long bytesSent;
   unsigned long bytesReceived;
   boolean activeConnection;
 };
 
+enum RTCStatsIceCandidatePairState {
+  "frozen",
+  "waiting",
+  "inprogress",
+  "failed",
+  "succeeded",
+  "cancelled"
+};
+
+dictionary RTCIceCandidatePairStats : RTCStats {
+  DOMString componentId;
+  DOMString localCandidateId;
+  DOMString remoteCandidateId;
+  RTCStatsIceCandidatePairState state;
+  unsigned long long mozPriority;
+  boolean readable;
+  boolean nominated;
+  boolean selected;
+};
+
 enum RTCStatsIceCandidateType {
   "host",
   "serverreflexive",
   "peerreflexive",
   "relayed"
 };
 
 dictionary RTCIceCandidateStats : RTCStats {
@@ -100,16 +126,17 @@ callback RTCStatsReportCallback = void (
 dictionary RTCStatsReportInternal {
   sequence<RTCRTPStreamStats>         rtpStreamStats;
   sequence<RTCInboundRTPStreamStats>  inboundRTPStreamStats;
   sequence<RTCOutboundRTPStreamStats> outboundRTPStreamStats;
   sequence<RTCMediaStreamTrackStats>  mediaStreamTrackStats;
   sequence<RTCMediaStreamStats>       mediaStreamStats;
   sequence<RTCTransportStats>         transportStats;
   sequence<RTCIceComponentStats>      iceComponentStats;
+  sequence<RTCIceCandidatePairStats>  iceCandidatePairStats;
   sequence<RTCIceCandidateStats>      iceCandidateStats;
   sequence<RTCCodecStats>             codecStats;
 };
 
 [Pref="media.peerconnection.enabled",
 // TODO: Use MapClass here once it's available (Bug 928114)
 // MapClass(DOMString, object)
  JSImplementation="@mozilla.org/dom/rtcstatsreport;1"]
--- a/extensions/cookie/nsPermissionManager.cpp
+++ b/extensions/cookie/nsPermissionManager.cpp
@@ -27,16 +27,17 @@
 #include "nsIPrincipal.h"
 #include "nsContentUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIAppsService.h"
 #include "mozIApplication.h"
 #include "nsIEffectiveTLDService.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDocument.h"
+#include "mozilla/net/NeckoMessageUtils.h"
 
 static nsPermissionManager *gPermissionManager = nullptr;
 
 using mozilla::dom::ContentParent;
 using mozilla::dom::ContentChild;
 using mozilla::unused; // ha!
 
 static bool
--- a/extensions/universalchardet/tests/CharsetDetectionTests.js
+++ b/extensions/universalchardet/tests/CharsetDetectionTests.js
@@ -40,27 +40,19 @@ function InitDetectorTests()
     } catch (e) {
         gOldPref = "";
     }
     SetDetectorPref(gDetectorList[0]);
     gTestIndex = 0;
     $("testframe").onload = DoDetectionTest;
 
     if (gExpectedCharset == "default") {
-        try {
-            gExpectedCharset = prefService
-                .getComplexValue("intl.charset.default",
-                                 Ci.nsIPrefLocalizedString)
-                .data;
-            if (gExpectedCharset == "ISO-8859-1") {
-                gExpectedCharset = "windows-1252";
-            }
-        } catch (e) {
-            gExpectedCharset = "windows-1252";
-        }
+        // No point trying to be generic here, because we have plenty of other
+        // unit tests that fail if run using a non-windows-1252 locale.
+        gExpectedCharset = "windows-1252";
     }
 
     // Get the local directory. This needs to be a file: URI because chrome:
     // URIs are always UTF-8 (bug 617339) and we are testing decoding from other
     // charsets.
     var jar = getJar(getRootDirectory(window.location.href));
     var dir = jar ?
                 extractJarToTmp(jar) :
--- a/gfx/2d/BaseRect.h
+++ b/gfx/2d/BaseRect.h
@@ -3,16 +3,17 @@
  * 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_GFX_BASERECT_H_
 #define MOZILLA_GFX_BASERECT_H_
 
 #include <cmath>
 #include <mozilla/Assertions.h>
+#include <mozilla/FloatingPoint.h>
 #include <algorithm>
 
 namespace mozilla {
 namespace gfx {
 
 /**
  * Rectangles have two interpretations: a set of (zero-size) points,
  * and a rectangular area of the plane. Most rectangle operations behave
@@ -54,20 +55,20 @@ struct BaseRect {
   // Emptiness. An empty rect is one that has no area, i.e. its height or width
   // is <= 0
   bool IsEmpty() const { return height <= 0 || width <= 0; }
   void SetEmpty() { width = height = 0; }
 
   // "Finite" means not inf and not NaN
   bool IsFinite() const
   {
-    return (std::isfinite(x) &&
-            std::isfinite(y) &&
-            std::isfinite(width) &&
-            std::isfinite(height));
+    return (mozilla::IsFinite(x) &&
+            mozilla::IsFinite(y) &&
+            mozilla::IsFinite(width) &&
+            mozilla::IsFinite(height));
   }
 
   // Returns true if this rectangle contains the interior of aRect. Always
   // returns true if aRect is empty, and always returns false is aRect is
   // nonempty but this rect is empty.
   bool Contains(const Sub& aRect) const
   {
     return aRect.IsEmpty() ||
new file mode 100644
--- /dev/null
+++ b/gfx/2d/DataSurfaceHelpers.h
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#pragma once
+
+#include "2D.h"
+
+namespace mozilla {
+namespace gfx {
+
+static inline void
+ConvertBGRXToBGRA(uint8_t* aData, const IntSize &aSize, int32_t aStride)
+{
+  uint32_t* pixel = reinterpret_cast<uint32_t*>(aData);
+
+  for (int row = 0; row < aSize.height; ++row) {
+    for (int column = 0; column < aSize.width; ++column) {
+#ifdef IS_BIG_ENDIAN
+      pixel[column] |= 0x000000FF;
+#else
+      pixel[column] |= 0xFF000000;
+#endif
+    }
+    pixel += (aStride/4);
+  }
+}
+
+/*
+ * Convert aSurface to a packed buffer in BGRA format. The pixel data is
+ * returned in a buffer allocated with new uint8_t[].
+ */
+inline uint8_t *
+SurfaceToPackedBGRA(SourceSurface *aSurface)
+{
+  RefPtr<DataSourceSurface> data = aSurface->GetDataSurface();
+  if (!data) {
+    return nullptr;
+  }
+
+  SurfaceFormat format = data->GetFormat();
+  if (format != FORMAT_B8G8R8A8 && format != FORMAT_B8G8R8X8) {
+    return nullptr;
+  }
+
+  IntSize size = data->GetSize();
+
+  uint8_t* imageBuffer = new (std::nothrow) uint8_t[size.width * size.height * sizeof(uint32_t)];
+  if (!imageBuffer) {
+    return nullptr;
+  }
+
+  size_t stride = data->Stride();
+
+  uint32_t* src = reinterpret_cast<uint32_t*>(data->GetData());
+  uint32_t* dst = reinterpret_cast<uint32_t*>(imageBuffer);
+
+  if (stride == size.width * sizeof(uint32_t)) {
+    // DataSourceSurface is already packed. We can use memcpy.
+    memcpy(dst, src, size.width * size.height * sizeof(uint32_t));
+  } else {
+    for (int row = 0; row < size.height; ++row) {
+      for (int column = 0; column < size.width; ++column) {
+        *dst++ = src[column];
+      }
+      src += (stride/4);
+    }
+  }
+
+  if (format == FORMAT_B8G8R8X8) {
+    // Convert BGRX to BGRA by setting a to 255.
+    ConvertBGRXToBGRA(reinterpret_cast<uint8_t *>(imageBuffer), size, size.width * sizeof(uint32_t));
+  }
+
+  return imageBuffer;
+}
+
+}
+}
--- a/gfx/2d/DrawTargetCairo.cpp
+++ b/gfx/2d/DrawTargetCairo.cpp
@@ -109,23 +109,39 @@ GetCairoSurfaceSize(cairo_surface_t* sur
       // It's valid to call these CGBitmapContext functions on non-bitmap
       // contexts; they'll just return 0 in that case.
       size.width = CGBitmapContextGetWidth(cgc);
       size.height = CGBitmapContextGetHeight(cgc);
       return true;
     }
 #endif
 #ifdef CAIRO_HAS_WIN32_SURFACE
+#ifdef MOZ2D_HAS_MOZ_CAIRO
     case CAIRO_SURFACE_TYPE_WIN32:
     case CAIRO_SURFACE_TYPE_WIN32_PRINTING:
     {
       size.width = cairo_win32_surface_get_width(surface);
       size.height = cairo_win32_surface_get_height(surface);
       return true;
     }
+#else
+    case CAIRO_SURFACE_TYPE_WIN32:
+    {
+      cairo_surface_t *img = cairo_win32_surface_get_image(surface);
+
+      if (!img) {
+        // XXX - fix me
+        MOZ_ASSERT(false);
+        return true;
+      }
+      size.width = cairo_image_surface_get_width(img);
+      size.height = cairo_image_surface_get_height(img);
+      return true;
+    }
+#endif
 #endif
 
     default:
       return false;
   }
 }
 
 static bool
@@ -1147,16 +1163,35 @@ DrawTargetCairo::CreateShadowDrawTarget(
 
 bool
 DrawTargetCairo::Init(cairo_surface_t* aSurface, const IntSize& aSize)
 {
   cairo_surface_reference(aSurface);
   return InitAlreadyReferenced(aSurface, aSize);
 }
 
+bool
+DrawTargetCairo::Init(const IntSize& aSize, SurfaceFormat aFormat)
+{
+  cairo_surface_t *surf = cairo_image_surface_create(GfxFormatToCairoFormat(aFormat), aSize.width, aSize.height);
+  return InitAlreadyReferenced(surf, aSize);
+}
+
+bool
+DrawTargetCairo::Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat)
+{
+  cairo_surface_t* surf =
+    cairo_image_surface_create_for_data(aData,
+                                        GfxFormatToCairoFormat(aFormat),
+                                        aSize.width,
+                                        aSize.height,
+                                        aStride);
+  return InitAlreadyReferenced(surf, aSize);
+}
+
 void *
 DrawTargetCairo::GetNativeSurface(NativeSurfaceType aType)
 {
   if (aType == NATIVE_SURFACE_CAIRO_SURFACE) {
     return cairo_get_target(mContext);
   }
   if (aType == NATIVE_SURFACE_CAIRO_CONTEXT) {
     return mContext;
--- a/gfx/2d/DrawTargetCairo.h
+++ b/gfx/2d/DrawTargetCairo.h
@@ -142,16 +142,18 @@ public:
   virtual TemporaryRef<GradientStops>
     CreateGradientStops(GradientStop *aStops,
                         uint32_t aNumStops,
                         ExtendMode aExtendMode = EXTEND_CLAMP) const;
 
   virtual void *GetNativeSurface(NativeSurfaceType aType);
 
   bool Init(cairo_surface_t* aSurface, const IntSize& aSize);
+  bool Init(const IntSize& aSize, SurfaceFormat aFormat);
+  bool Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat);
 
   virtual void SetTransform(const Matrix& aTransform);
 
   // Call to set up aContext for drawing (with the current transform, etc).
   // Pass the path you're going to be using if you have one.
   // Implicitly calls WillChange(aPath).
   void PrepareForDrawing(cairo_t* aContext, const Path* aPath = nullptr);
 
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -20,16 +20,17 @@
 #include "skia/SkBlurMaskFilter.h"
 #include "skia/SkColorFilter.h"
 #include "skia/SkLayerRasterizer.h"
 #include "skia/SkLayerDrawLooper.h"
 #include "skia/SkDashPathEffect.h"
 #include "Logging.h"
 #include "HelpersSkia.h"
 #include "Tools.h"
+#include "DataSurfaceHelpers.h"
 #include <algorithm>
 
 namespace mozilla {
 namespace gfx {
 
 class GradientStopsSkia : public GradientStops
 {
 public:
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -222,16 +222,27 @@ Factory::CreateDrawTarget(BackendType aB
       RefPtr<DrawTargetSkia> newTarget;
       newTarget = new DrawTargetSkia();
       if (newTarget->Init(aSize, aFormat)) {
         retVal = newTarget;
       }
       break;
     }
 #endif
+#ifdef USE_CAIRO
+  case BACKEND_CAIRO:
+    {
+      RefPtr<DrawTargetCairo> newTarget;
+      newTarget = new DrawTargetCairo();
+      if (newTarget->Init(aSize, aFormat)) {
+        retVal = newTarget;
+      }
+      break;
+    }
+#endif
   default:
     gfxDebug() << "Invalid draw target type specified.";
     return nullptr;
   }
 
   if (mRecorder && retVal) {
     RefPtr<DrawTarget> recordDT;
     recordDT = new DrawTargetRecording(mRecorder, retVal);
@@ -275,29 +286,42 @@ Factory::CreateDrawTargetForData(Backend
   case BACKEND_COREGRAPHICS:
     {
       RefPtr<DrawTargetCG> newTarget = new DrawTargetCG();
       if (newTarget->Init(aBackend, aData, aSize, aStride, aFormat))
         return newTarget;
       break;
     }
 #endif
+#ifdef USE_CAIRO
+  case BACKEND_CAIRO:
+    {
+      RefPtr<DrawTargetCairo> newTarget;
+      newTarget = new DrawTargetCairo();
+      if (newTarget->Init(aData, aSize, aStride, aFormat)) {
+        retVal = newTarget;
+      }
+      break;
+    }
+#endif
   default:
     gfxDebug() << "Invalid draw target type specified.";
     return nullptr;
   }
 
   if (mRecorder && retVal) {
     RefPtr<DrawTarget> recordDT = new DrawTargetRecording(mRecorder, retVal);
     return recordDT;
   }
 
-  gfxDebug() << "Failed to create DrawTarget, Type: " << aBackend << " Size: " << aSize;
-  // Failed
-  return nullptr;
+  if (!retVal) {
+    gfxDebug() << "Failed to create DrawTarget, Type: " << aBackend << " Size: " << aSize;
+  }
+
+  return retVal;
 }
 
 TemporaryRef<ScaledFont>
 Factory::CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSize)
 {
   switch (aNativeFont.mType) {
 #ifdef WIN32
   case NATIVE_FONT_DWRITE_FONT_FACE:
--- a/gfx/2d/HelpersSkia.h
+++ b/gfx/2d/HelpersSkia.h
@@ -149,29 +149,16 @@ StrokeOptionsToPaint(SkPaint& aPaint, co
                                                   SkFloatToScalar(aOptions.mDashOffset));
     SkSafeUnref(aPaint.setPathEffect(dash));
   }
 
   aPaint.setStyle(SkPaint::kStroke_Style);
   return true;
 }
 
-static inline void
-ConvertBGRXToBGRA(unsigned char* aData, const IntSize &aSize, int32_t aStride)
-{
-    uint32_t* pixel = reinterpret_cast<uint32_t*>(aData);
-
-    for (int row = 0; row < aSize.height; ++row) {
-        for (int column = 0; column < aSize.width; ++column) {
-            pixel[column] |= 0xFF000000;
-        }
-        pixel += (aStride/4);
-    }
-}
-
 static inline SkXfermode::Mode
 GfxOpToSkiaOp(CompositionOp op)
 {
   switch (op)
   {
     case OP_OVER:
       return SkXfermode::kSrcOver_Mode;
     case OP_ADD:
--- a/gfx/2d/Makefile.in
+++ b/gfx/2d/Makefile.in
@@ -1,16 +1,16 @@
 #
 # 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/.
 
 VPATH		=  $(srcdir) $(srcdir)/unittest
 
-DEFINES += -DMOZ_GFX -DUSE_CAIRO -DGFX2D_INTERNAL
+DEFINES += -DMOZ_GFX -DUSE_CAIRO -DGFX2D_INTERNAL -DMOZ2D_HAS_MOZ_CAIRO
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),$(findstring $(MOZ_WIDGET_TOOLKIT),android gtk2 gtk3 gonk qt))
 DEFINES += -DMOZ_ENABLE_FREETYPE
 OS_CXXFLAGS += $(CAIRO_FT_CFLAGS)
 endif
 
 DEFINES += -DSK_A32_SHIFT=24 -DSK_R32_SHIFT=16 -DSK_G32_SHIFT=8 -DSK_B32_SHIFT=0
 
--- a/gfx/2d/PathCG.cpp
+++ b/gfx/2d/PathCG.cpp
@@ -236,16 +236,19 @@ PathCG::StrokeContainsPoint(const Stroke
 
 //XXX: what should these functions return for an empty path?
 // currently they return CGRectNull {inf,inf, 0, 0}
 Rect
 PathCG::GetBounds(const Matrix &aTransform) const
 {
   //XXX: are these bounds tight enough
   Rect bounds = CGRectToRect(CGPathGetBoundingBox(mPath));
+  if (!bounds.IsFinite()) {
+    return Rect();
+  }
   //XXX: curretnly this returns the bounds of the transformed bounds
   // this is strictly looser than the bounds of the transformed path
   return aTransform.TransformBounds(bounds);
 }
 
 Rect
 PathCG::GetStrokedBounds(const StrokeOptions &aStrokeOptions,
                          const Matrix &aTransform) const
@@ -261,15 +264,19 @@ PathCG::GetStrokedBounds(const StrokeOpt
 
   SetStrokeOptions(cg, aStrokeOptions);
 
   CGContextReplacePathWithStrokedPath(cg);
   Rect bounds = CGRectToRect(CGContextGetPathBoundingBox(cg));
 
   CGContextRestoreGState(cg);
 
+  if (!bounds.IsFinite()) {
+    return Rect();
+  }
+
   return aTransform.TransformBounds(bounds);
 }
 
 
 }
 
 }
--- a/gfx/2d/PathD2D.cpp
+++ b/gfx/2d/PathD2D.cpp
@@ -327,41 +327,43 @@ PathD2D::StrokeContainsPoint(const Strok
   }
 
   return !!result;
 }
 
 Rect
 PathD2D::GetBounds(const Matrix &aTransform) const
 {
-  D2D1_RECT_F bounds;
+  D2D1_RECT_F d2dBounds;
 
-  HRESULT hr = mGeometry->GetBounds(D2DMatrix(aTransform), &bounds);
+  HRESULT hr = mGeometry->GetBounds(D2DMatrix(aTransform), &d2dBounds);
 
-  if (FAILED(hr)) {
+  Rect bounds = ToRect(d2dBounds);
+  if (FAILED(hr) || !bounds.IsFinite()) {
     gfxWarning() << "Failed to get stroked bounds for path. Code: " << hr;
-    bounds.bottom = bounds.left = bounds.right = bounds.top = 0;
+    return Rect();
   }
 
-  return ToRect(bounds);
+  return bounds;
 }
 
 Rect
 PathD2D::GetStrokedBounds(const StrokeOptions &aStrokeOptions,
                           const Matrix &aTransform) const
 {
-  D2D1_RECT_F bounds;
+  D2D1_RECT_F d2dBounds;
 
   RefPtr<ID2D1StrokeStyle> strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions);
   HRESULT hr =
     mGeometry->GetWidenedBounds(aStrokeOptions.mLineWidth, strokeStyle,
-                                D2DMatrix(aTransform), &bounds);
+                                D2DMatrix(aTransform), &d2dBounds);
 
-  if (FAILED(hr)) {
+  Rect bounds = ToRect(d2dBounds);
+  if (FAILED(hr) || !bounds.IsFinite()) {
     gfxWarning() << "Failed to get stroked bounds for path. Code: " << hr;
-    bounds.bottom = bounds.left = bounds.right = bounds.top = 0;
+    return Rect();
   }
 
-  return ToRect(bounds);
+  return bounds;
 }
 
 }
 }
new file mode 100644
--- /dev/null
+++ b/gfx/2d/PathHelpers.cpp
@@ -0,0 +1,167 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "PathHelpers.h"
+
+namespace mozilla {
+namespace gfx {
+
+void
+AppendRoundedRectToPath(PathBuilder* aPathBuilder,
+                        const Rect& aRect,
+                        // paren's needed due to operator precedence:
+                        const Size(& aCornerRadii)[4],
+                        bool aDrawClockwise)
+{
+  // For CW drawing, this looks like:
+  //
+  //  ...******0**      1    C
+  //              ****
+  //                  ***    2
+  //                     **
+  //                       *
+  //                        *
+  //                         3
+  //                         *
+  //                         *
+  //
+  // Where 0, 1, 2, 3 are the control points of the Bezier curve for
+  // the corner, and C is the actual corner point.
+  //
+  // At the start of the loop, the current point is assumed to be
+  // the point adjacent to the top left corner on the top
+  // horizontal.  Note that corner indices start at the top left and
+  // continue clockwise, whereas in our loop i = 0 refers to the top
+  // right corner.
+  //
+  // When going CCW, the control points are swapped, and the first
+  // corner that's drawn is the top left (along with the top segment).
+  //
+  // There is considerable latitude in how one chooses the four
+  // control points for a Bezier curve approximation to an ellipse.
+  // For the overall path to be continuous and show no corner at the
+  // endpoints of the arc, points 0 and 3 must be at the ends of the
+  // straight segments of the rectangle; points 0, 1, and C must be
+  // collinear; and points 3, 2, and C must also be collinear.  This
+  // leaves only two free parameters: the ratio of the line segments
+  // 01 and 0C, and the ratio of the line segments 32 and 3C.  See
+  // the following papers for extensive discussion of how to choose
+  // these ratios:
+  //
+  //   Dokken, Tor, et al. "Good approximation of circles by
+  //      curvature-continuous Bezier curves."  Computer-Aided
+  //      Geometric Design 7(1990) 33--41.
+  //   Goldapp, Michael. "Approximation of circular arcs by cubic
+  //      polynomials." Computer-Aided Geometric Design 8(1991) 227--238.
+  //   Maisonobe, Luc. "Drawing an elliptical arc using polylines,
+  //      quadratic, or cubic Bezier curves."
+  //      http://www.spaceroots.org/documents/ellipse/elliptical-arc.pdf
+  //
+  // We follow the approach in section 2 of Goldapp (least-error,
+  // Hermite-type approximation) and make both ratios equal to
+  //
+  //          2   2 + n - sqrt(2n + 28)
+  //  alpha = - * ---------------------
+  //          3           n - 4
+  //
+  // where n = 3( cbrt(sqrt(2)+1) - cbrt(sqrt(2)-1) ).
+  //
+  // This is the result of Goldapp's equation (10b) when the angle
+  // swept out by the arc is pi/2, and the parameter "a-bar" is the
+  // expression given immediately below equation (21).
+  //
+  // Using this value, the maximum radial error for a circle, as a
+  // fraction of the radius, is on the order of 0.2 x 10^-3.
+  // Neither Dokken nor Goldapp discusses error for a general
+  // ellipse; Maisonobe does, but his choice of control points
+  // follows different constraints, and Goldapp's expression for
+  // 'alpha' gives much smaller radial error, even for very flat
+  // ellipses, than Maisonobe's equivalent.
+  //
+  // For the various corners and for each axis, the sign of this
+  // constant changes, or it might be 0 -- it's multiplied by the
+  // appropriate multiplier from the list before using.
+
+  const Float alpha = Float(0.55191497064665766025);
+
+  typedef struct { Float a, b; } twoFloats;
+
+  twoFloats cwCornerMults[4] = { { -1,  0 },    // cc == clockwise
+                                 {  0, -1 },
+                                 { +1,  0 },
+                                 {  0, +1 } };
+  twoFloats ccwCornerMults[4] = { { +1,  0 },   // ccw == counter-clockwise
+                                  {  0, -1 },
+                                  { -1,  0 },
+                                  {  0, +1 } };
+
+  twoFloats *cornerMults = aDrawClockwise ? cwCornerMults : ccwCornerMults;
+
+  Point cornerCoords[] = { aRect.TopLeft(), aRect.TopRight(),
+                           aRect.BottomRight(), aRect.BottomLeft() };
+
+  Point pc, p0, p1, p2, p3;
+
+  // The indexes of the corners:
+  const int kTopLeft = 0, kTopRight = 1;
+
+  if (aDrawClockwise) {
+    aPathBuilder->MoveTo(Point(aRect.X() + aCornerRadii[kTopLeft].width,
+                               aRect.Y()));
+  } else {
+    aPathBuilder->MoveTo(Point(aRect.X() + aRect.Width() - aCornerRadii[kTopRight].width,
+                               aRect.Y()));
+  }
+
+  for (int i = 0; i < 4; ++i) {
+    // the corner index -- either 1 2 3 0 (cw) or 0 3 2 1 (ccw)
+    int c = aDrawClockwise ? ((i+1) % 4) : ((4-i) % 4);
+
+    // i+2 and i+3 respectively.  These are used to index into the corner
+    // multiplier table, and were deduced by calculating out the long form
+    // of each corner and finding a pattern in the signs and values.
+    int i2 = (i+2) % 4;
+    int i3 = (i+3) % 4;
+
+    pc = cornerCoords[c];
+
+    if (aCornerRadii[c].width > 0.0 && aCornerRadii[c].height > 0.0) {
+      p0.x = pc.x + cornerMults[i].a * aCornerRadii[c].width;
+      p0.y = pc.y + cornerMults[i].b * aCornerRadii[c].height;
+
+      p3.x = pc.x + cornerMults[i3].a * aCornerRadii[c].width;
+      p3.y = pc.y + cornerMults[i3].b * aCornerRadii[c].height;
+
+      p1.x = p0.x + alpha * cornerMults[i2].a * aCornerRadii[c].width;
+      p1.y = p0.y + alpha * cornerMults[i2].b * aCornerRadii[c].height;
+
+      p2.x = p3.x - alpha * cornerMults[i3].a * aCornerRadii[c].width;
+      p2.y = p3.y - alpha * cornerMults[i3].b * aCornerRadii[c].height;
+
+      aPathBuilder->LineTo(p0);
+      aPathBuilder->BezierTo(p1, p2, p3);
+    } else {
+      aPathBuilder->LineTo(pc);
+    }
+  }
+
+  aPathBuilder->Close();
+}
+
+void
+AppendEllipseToPath(PathBuilder* aPathBuilder,
+                    const Point& aCenter,
+                    const Size& aDimensions)
+{
+  Size halfDim = aDimensions / 2.0;
+  Rect rect(aCenter - Point(halfDim.width, halfDim.height), aDimensions);
+  Size radii[] = { halfDim, halfDim, halfDim, halfDim };
+
+  AppendRoundedRectToPath(aPathBuilder, rect, radii);
+}
+
+} // namespace gfx
+} // namespace mozilla
+
--- a/gfx/2d/PathHelpers.h
+++ b/gfx/2d/PathHelpers.h
@@ -76,12 +76,40 @@ void ArcToBezier(T* aSink, const Point &
 
     aSink->BezierTo(cp1, cp2, currentEndPoint);
 
     arcSweepLeft -= Float(M_PI / 2.0f);
     currentStartAngle = currentEndAngle;
   }
 }
 
-}
-}
+/**
+ * Appends a path represending a rounded rectangle to the path being built by
+ * aPathBuilder.
+ *
+ * aRect           The rectangle to append.
+ * aCornerRadii    Contains the radii of the top-left, top-right, bottom-right
+ *                 and bottom-left corners, in that order.
+ * aDrawClockwise  If set to true, the path will start at the left of the top
+ *                 left edge and draw clockwise. If set to false the path will
+ *                 start at the right of the top left edge and draw counter-
+ *                 clockwise.
+ */
+GFX2D_API void AppendRoundedRectToPath(PathBuilder* aPathBuilder,
+                                       const Rect& aRect,
+                                       const Size(& aCornerRadii)[4],
+                                       bool aDrawClockwise = true);
+
+/**
+ * Appends a path represending an ellipse to the path being built by
+ * aPathBuilder.
+ *
+ * The ellipse extends aDimensions.width / 2.0 in the horizontal direction
+ * from aCenter, and aDimensions.height / 2.0 in the vertical direction.
+ */
+GFX2D_API void AppendEllipseToPath(PathBuilder* aPathBuilder,
+                                   const Point& aCenter,
+                                   const Size& aDimensions);
+
+} // namespace gfx
+} // namespace mozilla
 
 #endif /* MOZILLA_GFX_PATHHELPERS_H_ */
--- a/gfx/2d/SourceSurfaceSkia.cpp
+++ b/gfx/2d/SourceSurfaceSkia.cpp
@@ -5,16 +5,17 @@
 
 
 #include "Logging.h"
 #include "SourceSurfaceSkia.h"
 #include "skia/SkBitmap.h"
 #include "skia/SkDevice.h"
 #include "HelpersSkia.h"
 #include "DrawTargetSkia.h"
+#include "DataSurfaceHelpers.h"
 
 namespace mozilla {
 namespace gfx {
 
 SourceSurfaceSkia::SourceSurfaceSkia()
   : mDrawTarget(nullptr), mLocked(false)
 {
 }
--- a/gfx/2d/moz.build
+++ b/gfx/2d/moz.build
@@ -15,16 +15,17 @@ EXPORTS.mozilla.gfx += [
     'BaseMargin.h',
     'BasePoint.h',
     'BasePoint3D.h',
     'BasePoint4D.h',
     'BaseRect.h',
     'BaseSize.h',
     'Blur.h',
     'BorrowedContext.h',
+    'DataSurfaceHelpers.h',
     'Matrix.h',
     'PathHelpers.h',
     'Point.h',
     'Rect.h',
     'Scale.h',
     'ScaleFactor.h',
     'Tools.h',
     'Types.h',
@@ -84,16 +85,17 @@ SOURCES += [
     'DrawEventRecorder.cpp',
     'DrawTargetCairo.cpp',
     'DrawTargetDual.cpp',
     'DrawTargetRecording.cpp',
     'Factory.cpp',
     'ImageScaling.cpp',
     'Matrix.cpp',
     'PathCairo.cpp',
+    'PathHelpers.cpp',
     'PathRecording.cpp',
     'RecordedEvent.cpp',
     'Scale.cpp',
     'ScaledFontBase.cpp',
     'ScaledFontCairo.cpp',
     'SourceSurfaceCairo.cpp',
     'SourceSurfaceRawData.cpp',
 ]
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -7,40 +7,40 @@
 
 include LayersSurfaces;
 include protocol PCompositable;
 include protocol PCompositor;
 include protocol PGrallocBuffer;
 include protocol PLayer;
 include protocol PRenderFrame;
 
-include "mozilla/WidgetUtils.h";
-include "mozilla/TimeStamp.h";
-include "mozilla/dom/ScreenOrientation.h";
-include "nsCSSProperty.h";
 include "gfxipc/ShadowLayerUtils.h";
 include "mozilla/GfxMessageUtils.h";
 include "ImageLayers.h";
-include "mozilla/layers/CompositorTypes.h";
 
-using gfxPoint3D;
-using nscoord;
-using nsRect;
-using nsPoint;
-using mozilla::TimeDuration;
-using mozilla::TimeStamp;
-using mozilla::ScreenRotation;
-using nsCSSProperty;
-using mozilla::dom::ScreenOrientation;
-using mozilla::layers::TextureInfo;
-using mozilla::LayerMargin;
-using mozilla::LayerPoint;
-using mozilla::LayerRect;
-using mozilla::layers::ScaleMode;
-using mozilla::layers::DiagnosticTypes;
+using mozilla::GraphicsFilterType from "mozilla/GfxMessageUtils.h";
+using struct gfxRGBA from "gfxColor.h";
+using struct gfxPoint3D from "gfxPoint3D.h";
+using class gfx3DMatrix from "gfx3DMatrix.h";
+using nscoord from "nsCoord.h";
+using struct nsIntPoint from "nsPoint.h";
+using struct nsRect from "nsRect.h";
+using struct nsPoint from "nsPoint.h";
+using class mozilla::TimeDuration from "mozilla/TimeStamp.h";
+using class mozilla::TimeStamp from "mozilla/TimeStamp.h";
+using mozilla::ScreenRotation from "mozilla/WidgetUtils.h";
+using nsCSSProperty from "nsCSSProperty.h";
+using mozilla::dom::ScreenOrientation from "mozilla/dom/ScreenOrientation.h";
+using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h";
+using mozilla::LayerMargin from "Units.h";
+using mozilla::LayerPoint from "Units.h";
+using mozilla::LayerRect from "Units.h";
+using mozilla::layers::ScaleMode from "mozilla/layers/LayersTypes.h";
+using mozilla::layers::DiagnosticTypes from "mozilla/layers/CompositorTypes.h";
+using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
 
 namespace mozilla {
 namespace layers {
 
 struct TargetConfig {
   nsIntRect naturalBounds;
   ScreenRotation rotation;
   nsIntRect clientBounds;
--- a/gfx/layers/ipc/LayersSurfaces.ipdlh
+++ b/gfx/layers/ipc/LayersSurfaces.ipdlh
@@ -1,37 +1,29 @@
 /* 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 protocol PGrallocBuffer;
 
-include "gfxipc/ShadowLayerUtils.h";
-include "mozilla/gfx/Types.h";
-include "nsRegion.h";
 
-using gfx3DMatrix;
-using gfxIntSize;
-using gfxPoint;
-using gfxRGBA;
-using nsIntPoint;
-using nsIntRect;
-using nsIntRegion;
-using nsIntSize;
-using mozilla::GraphicsFilterType;
-using mozilla::layers::FrameMetrics;
-using mozilla::layers::MagicGrallocBufferHandle;
-using mozilla::layers::SurfaceDescriptorX11;
-using mozilla::null_t;
-using mozilla::WindowsHandle;
-using mozilla::gl::SharedTextureHandle;
-using mozilla::gl::SharedTextureShareType;
-using mozilla::gfx::SurfaceStreamHandle;
-using mozilla::gfx::SurfaceFormat;
-using mozilla::gfx::IntSize;
+using gfxIntSize from "nsSize.h";
+using struct gfxPoint from "gfxPoint.h";
+using struct nsIntRect from "nsRect.h";
+using nsIntRegion from "nsRegion.h";
+using struct nsIntSize from "nsSize.h";
+using struct mozilla::layers::MagicGrallocBufferHandle from "gfxipc/ShadowLayerUtils.h";
+using struct mozilla::layers::SurfaceDescriptorX11 from "gfxipc/ShadowLayerUtils.h";
+using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
+using mozilla::WindowsHandle from "ipc/IPCMessageUtils.h";
+using mozilla::gl::SharedTextureHandle from "GLContextTypes.h";
+using mozilla::gl::SharedTextureShareType from "GLContextTypes.h";
+using mozilla::gfx::SurfaceStreamHandle from "SurfaceTypes.h";
+using mozilla::gfx::SurfaceFormat from "mozilla/gfx/Types.h";
+using mozilla::gfx::IntSize from "mozilla/gfx/Point.h";
 
 namespace mozilla {
 namespace layers {
 
 union MaybeMagicGrallocBufferHandle {
   MagicGrallocBufferHandle;
   null_t;
 };
--- a/gfx/layers/ipc/PCompositable.ipdl
+++ b/gfx/layers/ipc/PCompositable.ipdl
@@ -3,17 +3,16 @@
  */
 /* 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 protocol PLayerTransaction;
 include protocol PImageBridge;
 include protocol PCompositor;
-include "mozilla/layers/CompositorTypes.h";
 
 namespace mozilla {
 namespace layers {
 
 async protocol PCompositable
 {
     manager PImageBridge or PLayerTransaction;
 parent:
--- a/gfx/layers/ipc/PCompositor.ipdl
+++ b/gfx/layers/ipc/PCompositor.ipdl
@@ -3,22 +3,21 @@
  */
 /* 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 LayersSurfaces;
 include protocol PGrallocBuffer;
 include protocol PLayerTransaction;
-include "mozilla/layers/CompositorTypes.h";
 include "mozilla/GfxMessageUtils.h";
 
-using mozilla::null_t;
-using mozilla::layers::TextureFactoryIdentifier;
-using mozilla::layers::LayersBackend;
+using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
+using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
+using mozilla::layers::LayersBackend from "mozilla/layers/LayersTypes.h";
 
 namespace mozilla {
 namespace layers {
 
 
 /**
  * The PCompositor protocol is used to manage communication between
  * the main thread and the compositor thread context. It's primary
--- a/gfx/layers/ipc/PImageBridge.ipdl
+++ b/gfx/layers/ipc/PImageBridge.ipdl
@@ -4,21 +4,19 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include LayersSurfaces;
 include LayersMessages;
 include protocol PGrallocBuffer;
 include protocol PCompositable;
 include ProtocolTypes;
 
-include "mozilla/layers/CompositorTypes.h";
 include "mozilla/GfxMessageUtils.h";
 
-using ImageHandle;
-using mozilla::layers::TextureInfo;
+using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h";
 
 namespace mozilla {
 namespace layers {
 
 /**
  * The PImageBridge protocol is used to allow isolated threads or processes to push
  * frames directly to the compositor thread/process without relying on the main thread
  * which might be too busy dealing with content script.
--- a/gfx/layers/ipc/PLayerTransaction.ipdl
+++ b/gfx/layers/ipc/PLayerTransaction.ipdl
@@ -8,23 +8,19 @@
 include LayersSurfaces;
 include LayersMessages;
 include protocol PCompositable;
 include protocol PCompositor;
 include protocol PGrallocBuffer;
 include protocol PLayer;
 include protocol PRenderFrame;
 
-include "mozilla/WidgetUtils.h";
-include "mozilla/dom/ScreenOrientation.h";
-include "nsCSSProperty.h";
-include "gfxipc/ShadowLayerUtils.h";
 include "mozilla/GfxMessageUtils.h";
 
-using mozilla::layers::TextureInfo;
+using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h";
 
 /**
  * The layers protocol is spoken between thread contexts that manage
  * layer (sub)trees.  The protocol comprises atomically publishing
  * layer subtrees to a "shadow" thread context (which grafts the
  * subtree into its own tree), and atomically updating a published
  * subtree.  ("Atomic" in this sense is wrt painting.)
  */
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -17,16 +17,17 @@
 #include "gfxColor.h"
 #include "gfxMatrix.h"
 #include "gfxASurface.h"
 #include "gfxPattern.h"
 #include "gfxPlatform.h"
 #include "gfxTeeSurface.h"
 #include "GeckoProfiler.h"
 #include "gfx2DGlue.h"
+#include "mozilla/gfx/PathHelpers.h"
 #include <algorithm>
 
 #if CAIRO_HAS_DWRITE_FONT
 #include "gfxWindowsPlatform.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::gfx;
@@ -1707,64 +1708,69 @@ gfxContext::PopGroupToSource()
 }
 
 bool
 gfxContext::PointInFill(const gfxPoint& pt)
 {
   if (mCairo) {
     return cairo_in_fill(mCairo, pt.x, pt.y);
   } else {
-    return mPath->ContainsPoint(ToPoint(pt), mTransform);
+    EnsurePath();
+    return mPath->ContainsPoint(ToPoint(pt), Matrix());
   }
 }
 
 bool
 gfxContext::PointInStroke(const gfxPoint& pt)
 {
   if (mCairo) {
     return cairo_in_stroke(mCairo, pt.x, pt.y);
   } else {
+    EnsurePath();
     return mPath->StrokeContainsPoint(CurrentState().strokeOptions,
                                       ToPoint(pt),
-                                      mTransform);
+                                      Matrix());
   }
 }
 
 gfxRect
 gfxContext::GetUserPathExtent()
 {
   if (mCairo) {
     double xmin, ymin, xmax, ymax;
     cairo_path_extents(mCairo, &xmin, &ymin, &xmax, &ymax);
     return gfxRect(xmin, ymin, xmax - xmin, ymax - ymin);
   } else {
+    EnsurePath();
     return ThebesRect(mPath->GetBounds());
   }
 }
 
 gfxRect
 gfxContext::GetUserFillExtent()
 {
   if (mCairo) {
     double xmin, ymin, xmax, ymax;
     cairo_fill_extents(mCairo, &xmin, &ymin, &xmax, &ymax);
     return gfxRect(xmin, ymin, xmax - xmin, ymax - ymin);
   } else {
+    EnsurePath();
     return ThebesRect(mPath->GetBounds());
   }
 }
 
 gfxRect
 gfxContext::GetUserStrokeExtent()
 {
   if (mCairo) {
     double xmin, ymin, xmax, ymax;
     cairo_stroke_extents(mCairo, &xmin, &ymin, &xmax, &ymax);
     return gfxRect(xmin, ymin, xmax - xmin, ymax - ymin);
   } else {
+    EnsurePath();
     return ThebesRect(mPath->GetStrokedBounds(CurrentState().strokeOptions, mTransform));
   }
 }
 
 bool
 gfxContext::HasError()
 {
   if (mCairo) {
@@ -1906,72 +1912,21 @@ gfxContext::RoundedRectangle(const gfxRe
         } else {
             cairo_line_to (mCairo, pc.x, pc.y);
         }
     }
 
     cairo_close_path (mCairo);
   } else {
     EnsurePathBuilder();
-
-    const gfxFloat alpha = 0.55191497064665766025;
-
-    typedef struct { gfxFloat a, b; } twoFloats;
-
-    twoFloats cwCornerMults[4] = { { -1,  0 },
-                                   {  0, -1 },
-                                   { +1,  0 },
-                                   {  0, +1 } };
-    twoFloats ccwCornerMults[4] = { { +1,  0 },
-                                    {  0, -1 },
-                                    { -1,  0 },
-                                    {  0, +1 } };
-
-    twoFloats *cornerMults = draw_clockwise ? cwCornerMults : ccwCornerMults;
-
-    gfxPoint pc, p0, p1, p2, p3;
-
-    if (draw_clockwise)
-        mPathBuilder->MoveTo(Point(Float(rect.X() + corners[NS_CORNER_TOP_LEFT].width), Float(rect.Y())));
-    else
-        mPathBuilder->MoveTo(Point(Float(rect.X() + rect.Width() - corners[NS_CORNER_TOP_RIGHT].width), Float(rect.Y())));
-
-    NS_FOR_CSS_CORNERS(i) {
-        // the corner index -- either 1 2 3 0 (cw) or 0 3 2 1 (ccw)
-        mozilla::css::Corner c = mozilla::css::Corner(draw_clockwise ? ((i+1) % 4) : ((4-i) % 4));
-
-        // i+2 and i+3 respectively.  These are used to index into the corner
-        // multiplier table, and were deduced by calculating out the long form
-        // of each corner and finding a pattern in the signs and values.
-        int i2 = (i+2) % 4;
-        int i3 = (i+3) % 4;
-
-        pc = rect.AtCorner(c);
-
-        if (corners[c].width > 0.0 && corners[c].height > 0.0) {
-            p0.x = pc.x + cornerMults[i].a * corners[c].width;
-            p0.y = pc.y + cornerMults[i].b * corners[c].height;
-
-            p3.x = pc.x + cornerMults[i3].a * corners[c].width;
-            p3.y = pc.y + cornerMults[i3].b * corners[c].height;
-
-            p1.x = p0.x + alpha * cornerMults[i2].a * corners[c].width;
-            p1.y = p0.y + alpha * cornerMults[i2].b * corners[c].height;
-
-            p2.x = p3.x - alpha * cornerMults[i3].a * corners[c].width;
-            p2.y = p3.y - alpha * cornerMults[i3].b * corners[c].height;
-
-            mPathBuilder->LineTo(ToPoint(p0));
-            mPathBuilder->BezierTo(ToPoint(p1), ToPoint(p2), ToPoint(p3));
-        } else {
-            mPathBuilder->LineTo(ToPoint(pc));
-        }
-    }
-
-    mPathBuilder->Close();
+    Size radii[] = { ToSize(corners[NS_CORNER_TOP_LEFT]),
+                     ToSize(corners[NS_CORNER_TOP_RIGHT]),
+                     ToSize(corners[NS_CORNER_BOTTOM_RIGHT]),
+                     ToSize(corners[NS_CORNER_BOTTOM_LEFT]) };
+    AppendRoundedRectToPath(mPathBuilder, ToRect(rect), radii, draw_clockwise);
   }
 }
 
 #ifdef MOZ_DUMP_PAINTING
 void
 gfxContext::WriteAsPNG(const char* aFile)
 { 
   nsRefPtr<gfxASurface> surf = CurrentSurface();
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -2642,17 +2642,20 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint
       Matrix *passedInvMatrix = nullptr;
 
       RefPtr<GlyphRenderingOptions> renderingOptions =
         GetGlyphRenderingOptions();
 
       DrawOptions drawOptions;
       drawOptions.mAntialiasMode = Get2DAAMode(mAntialiasOption);
 
-      if (mScaledFont) {
+      // The cairo DrawTarget backend uses the cairo_scaled_font directly
+      // and so has the font skew matrix applied already.
+      if (mScaledFont &&
+          dt->GetType() != BACKEND_CAIRO) {
         cairo_matrix_t matrix;
         cairo_scaled_font_get_font_matrix(mScaledFont, &matrix);
         if (matrix.xy != 0) {
           // If this matrix applies a skew, which can happen when drawing
           // oblique fonts, we will set the DrawTarget matrix to apply the
           // skew. We'll need to move the glyphs by the inverse of the skew to
           // get the glyphs positioned correctly in the new device space
           // though, since the font matrix should only be applied to drawing
--- a/gfx/thebes/gfxMacPlatformFontList.mm
+++ b/gfx/thebes/gfxMacPlatformFontList.mm
@@ -825,17 +825,17 @@ gfxMacPlatformFontList::GlobalFontFallba
 
     // use CoreText to find the fallback family
 
     gfxFontEntry *fontEntry = nullptr;
     CTFontRef fallback;
     bool cantUseFallbackFont = false;
 
     if (!mDefaultFont) {
-        mDefaultFont = ::CTFontCreateWithName(CFSTR("Lucida Grande"), 12.f,
+        mDefaultFont = ::CTFontCreateWithName(CFSTR("LucidaGrande"), 12.f,
                                               NULL);
     }
 
     fallback = ::CTFontCreateForString(mDefaultFont, str,
                                        ::CFRangeMake(0, len));
 
     if (fallback) {
         CFStringRef familyName = ::CTFontCopyFamilyName(fallback);
--- a/hal/sandbox/PHal.ipdl
+++ b/hal/sandbox/PHal.ipdl
@@ -1,37 +1,32 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et ft=cpp : */
 /* 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 protocol PContent;
 include protocol PBrowser;
-include "prtime.h";
-include "mozilla/HalSensor.h";
-include "mozilla/HalTypes.h";
-include "mozilla/dom/ScreenOrientation.h";
-include "nsRect.h";
 
-using mozilla::dom::ScreenOrientation;
-using mozilla::hal::FlashMode;
-using mozilla::hal::LightType;
-using mozilla::hal::LightMode;
-using mozilla::hal::SensorType;
-using mozilla::hal::SensorAccuracyType;
-using mozilla::hal::WakeLockControl;
-using mozilla::hal::SwitchState;
-using mozilla::hal::SwitchDevice;
-using mozilla::hal::ProcessPriority;
-using nsIntRect;
-using PRTime;
-using mozilla::hal::FMRadioCountry;
-using mozilla::hal::FMRadioOperation;
-using mozilla::hal::FMRadioOperationStatus;
+using mozilla::dom::ScreenOrientation from "mozilla/dom/ScreenOrientation.h";
+using mozilla::hal::FlashMode from "mozilla/HalTypes.h";
+using mozilla::hal::LightType from "mozilla/HalTypes.h";
+using mozilla::hal::LightMode from "mozilla/HalTypes.h";
+using mozilla::hal::SensorType from "mozilla/HalSensor.h";
+using mozilla::hal::SensorAccuracyType from "mozilla/HalSensor.h";
+using mozilla::hal::WakeLockControl from "mozilla/HalTypes.h";
+using mozilla::hal::SwitchState from "mozilla/HalTypes.h";
+using mozilla::hal::SwitchDevice from "mozilla/HalTypes.h";
+using mozilla::hal::ProcessPriority from "mozilla/HalTypes.h";
+using struct nsIntRect from "nsRect.h";
+using PRTime from "prtime.h";
+using mozilla::hal::FMRadioCountry from "mozilla/HalTypes.h";
+using mozilla::hal::FMRadioOperation from "mozilla/HalTypes.h";
+using mozilla::hal::FMRadioOperationStatus from "mozilla/HalTypes.h";
 
 namespace mozilla {
 
 namespace hal {
 struct BatteryInformation {
   double level;
   bool   charging;
   double remainingTime;
--- a/ipc/app/MozillaRuntimeMain.cpp
+++ b/ipc/app/MozillaRuntimeMain.cpp
@@ -65,24 +65,26 @@ InitializeBinder(void *aDummy) {
     android::ProcessState::self()->startThreadPool();
     setpriority(PRIO_PROCESS, 0, curPrio);
 }
 #endif
 
 int
 main(int argc, char* argv[])
 {
-#ifdef MOZ_NUWA_PROCESS
     bool isNuwa = false;
+    bool isSandboxEnabled = false;
     for (int i = 1; i < argc; i++) {
-        if (strcmp(argv[i], "-nuwa") == 0) {
-            PrepareNuwaProcess();
-            isNuwa = true;
-            break;
-        }
+        isNuwa |= strcmp(argv[i], "-nuwa") == 0;
+        isSandboxEnabled |= strcmp(argv[i], "-sandbox") == 0;
+    }
+
+#ifdef MOZ_NUWA_PROCESS
+    if (isNuwa) {
+        PrepareNuwaProcess();
     }
 #endif
 
 #ifdef MOZ_WIDGET_GONK
     // This creates a ThreadPool for binder ipc. A ThreadPool is necessary to
     // receive binder calls, though not necessary to send binder calls.
     // ProcessState::Self() also needs to be called once on the main thread to
     // register the main thread with the binder driver.
@@ -94,29 +96,31 @@ main(int argc, char* argv[])
         NuwaAddFinalConstructor(&InitializeBinder, nullptr);
     }
 #else
     InitializeBinder(nullptr);
 #endif
 #endif
 
 #if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
-    sandbox::TargetServices* target_service =
-        sandbox::SandboxFactory::GetTargetServices();
-    if (!target_service) {
-        return 1;
-    }
+    if (isSandboxEnabled) {
+        sandbox::TargetServices* target_service =
+            sandbox::SandboxFactory::GetTargetServices();
+        if (!target_service) {
+            return 1;
+        }
 
-    sandbox::ResultCode result = target_service->Init();
-    if (result != sandbox::SBOX_ALL_OK) {
-        return 2;
+        sandbox::ResultCode result = target_service->Init();
+        if (result != sandbox::SBOX_ALL_OK) {
+            return 2;
+        }
+
+        // Initialization is finished, switch to the lowered token
+        target_service->LowerToken();
     }
-
-    // Initialization is finished, switch to the lowered token
-    target_service->LowerToken();
 #endif
 
     // Check for the absolute minimum number of args we need to move
     // forward here. We expect the last arg to be the child process type.
     if (argc < 1)
       return 3;
     GeckoProcessType proctype = XRE_StringToChildProcessType(argv[--argc]);
 
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -82,16 +82,17 @@ GeckoChildProcessHost::DefaultChildPrivi
   return (kLowRightsSubprocesses ?
           base::PRIVILEGES_UNPRIVILEGED : base::PRIVILEGES_INHERIT);
 }
 
 GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
                                              ChildPrivileges aPrivileges)
   : ChildProcessHost(RENDER_PROCESS), // FIXME/cjones: we should own this enum
     mProcessType(aProcessType),
+    mSandboxEnabled(true),
     mPrivileges(aPrivileges),
     mMonitor("mozilla.ipc.GeckChildProcessHost.mMonitor"),
     mProcessState(CREATING_CHANNEL),
     mDelegate(nullptr),
     mChildProcessHandle(0)
 #if defined(MOZ_WIDGET_COCOA)
   , mChildTask(MACH_PORT_NULL)
 #endif
@@ -734,16 +735,23 @@ GeckoChildProcessHost::PerformAsyncLaunc
     }
     file = Omnijar::GetPath(Omnijar::APP);
     if (file && NS_SUCCEEDED(file->GetPath(path))) {
       cmdLine.AppendLooseValue(UTF8ToWide("-appomni"));
       cmdLine.AppendLooseValue(path.get());
     }
   }
 
+#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
+  if (mSandboxEnabled) {
+    // Tell the process that it should lower its rights after initialization.
+    cmdLine.AppendLooseValue(UTF8ToWide("-sandbox"));
+  }
+#endif
+
   // Add the application directory path (-appdir path)
   AddAppDirToCommandLine(cmdLine);
 
   // XXX Command line params past this point are expected to be at
   // the end of the command line string, and in a specific order.
   // See XRE_InitChildProcess in nsEmbedFunction.
 
   // Win app model id
@@ -756,24 +764,27 @@ GeckoChildProcessHost::PerformAsyncLaunc
   cmdLine.AppendLooseValue(
     UTF8ToWide(CrashReporter::GetChildNotificationPipe()));
 #endif
 
   // Process type
   cmdLine.AppendLooseValue(UTF8ToWide(childProcessType));
 
 #if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
-  mozilla::SandboxBroker sandboxBroker;
-  sandboxBroker.LaunchApp(cmdLine.program().c_str(),
-                          cmdLine.command_line_string().c_str(),
-                          &process);
-#else
-  base::LaunchApp(cmdLine, false, false, &process);
+  if (mSandboxEnabled) {
+
+    mozilla::SandboxBroker sandboxBroker;
+    sandboxBroker.LaunchApp(cmdLine.program().c_str(),
+                            cmdLine.command_line_string().c_str(),
+                            &process);
+  } else
 #endif
-
+  {
+    base::LaunchApp(cmdLine, false, false, &process);
+  }
 
 #else
 #  error Sorry
 #endif
 
   if (!process) {
     MonitorAutoLock lock(mMonitor);
     mProcessState = PROCESS_ERROR;
--- a/ipc/glue/GeckoChildProcessHost.h
+++ b/ipc/glue/GeckoChildProcessHost.h
@@ -118,21 +118,27 @@ public:
 #endif
 
   /**
    * Must run on the IO thread.  Cause the OS process to exit and
    * ensure its OS resources are cleaned up.
    */
   void Join();
 
+  void SetSandboxEnabled(bool aSandboxEnabled) {
+    mSandboxEnabled = aSandboxEnabled;
+  }
+
 protected:
   GeckoProcessType mProcessType;
+  bool mSandboxEnabled;
   ChildPrivileges mPrivileges;
   Monitor mMonitor;
   FilePath mProcessPath;
+
   // This value must be accessed while holding mMonitor.
   enum {
     // This object has been constructed, but the OS process has not
     // yet.
     CREATING_CHANNEL = 0,
     // The IPC channel for our subprocess has been created, but the OS
     // process has still not been created.
     CHANNEL_INITIALIZED,
--- a/ipc/glue/InputStreamParams.ipdlh
+++ b/ipc/glue/InputStreamParams.ipdlh
@@ -1,15 +1,14 @@
 /* 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 "ipc/IPCMessageUtils.h";
 
-using mozilla::void_t;
+using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 include protocol PBlob;
 
 namespace mozilla {
 namespace ipc {
 
 struct StringInputStreamParams
 {
   nsCString data;
--- a/ipc/glue/URIParams.ipdlh
+++ b/ipc/glue/URIParams.ipdlh
@@ -1,15 +1,14 @@
 /* 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 "ipc/IPCMessageUtils.h";
 
-using mozilla::void_t;
+using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 
 namespace mozilla {
 namespace ipc {
 
 struct SimpleURIParams
 {
   nsCString scheme;
   nsCString path;
--- a/ipc/ipdl/ipdl/ast.py
+++ b/ipc/ipdl/ipdl/ast.py
@@ -181,19 +181,30 @@ class Include(Node):
     def __init__(self, loc, type, name):
         Node.__init__(self, loc)
         suffix = 'ipdl'
         if type == 'header':
             suffix += 'h'
         self.file = "%s.%s" % (name, suffix)
 
 class UsingStmt(Node):
-    def __init__(self, loc, cxxTypeSpec):
+    def __init__(self, loc, cxxTypeSpec, cxxHeader=None, kind=None):
         Node.__init__(self, loc)
+        assert not isinstance(cxxTypeSpec, str)
+        assert cxxHeader is None or isinstance(cxxHeader, str);
+        assert kind is None or kind == 'class' or kind == 'struct'
         self.type = cxxTypeSpec
+        self.header = cxxHeader
+        self.kind = kind
+    def canBeForwardDeclared(self):
+        return self.isClass() or self.isStruct()
+    def isClass(self):
+        return self.kind == 'class'
+    def isStruct(self):
+        return self.kind == 'struct'
 
 # "singletons"
 class PrettyPrinted:
     @classmethod
     def __hash__(cls): return hash(cls.pretty)
     @classmethod
     def __str__(cls):  return cls.pretty
     
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -3,17 +3,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import os, re, sys
 from copy import deepcopy
 
 import ipdl.ast
 import ipdl.builtin
 from ipdl.cxx.ast import *
-from ipdl.type import Actor, ActorType, ProcessGraph, TypeVisitor
+from ipdl.type import Actor, ActorType, ProcessGraph, TypeVisitor, builtinHeaderIncludes
 
 # FIXME/cjones: the chromium Message logging code doesn't work on
 # gcc/POSIX, because it wprintf()s across the chromium/mozilla
 # boundary. one side builds with -fshort-wchar, the other doesn't.
 # this code will remain off until the chromium base lib is replaced
 EMIT_LOGGING_CODE = ('win32' == sys.platform)
 
 ##-----------------------------------------------------------------------------
@@ -234,18 +234,18 @@ def _shmemForget(shmemexpr):
 
 def _shmemRevokeRights(shmemexpr):
     return ExprCall(ExprSelect(shmemexpr, '.', 'RevokeRights'),
                     args=[ _shmemBackstagePass() ])
 
 def _lookupShmem(idexpr):
     return ExprCall(ExprVar('LookupSharedMemory'), args=[ idexpr ])
 
-def _makeForwardDeclForQClass(clsname, quals):
-    fd = ForwardDecl(clsname, cls=1)
+def _makeForwardDeclForQClass(clsname, quals, cls=1, struct=0):
+    fd = ForwardDecl(clsname, cls=cls, struct=struct)
     if 0 == len(quals):
         return fd
 
     outerns = Namespace(quals[0])
     innerns = outerns
     for ns in quals[1:]:
         tmpns = Namespace(ns)
         innerns.addstmt(tmpns)
@@ -1413,16 +1413,48 @@ class _GenerateProtocolCode(ipdl.ast.Vis
 
     def visitTranslationUnit(self, tu):
         hf = self.hdrfile
 
         hf.addthing(_DISCLAIMER)
         hf.addthings(_includeGuardStart(hf))
         hf.addthing(Whitespace.NL)
 
+        for inc in builtinHeaderIncludes:
+            self.visitBuiltinCxxInclude(inc)
+
+        # Compute the set of includes we need for declared structure/union
+        # classes for this protocol.
+        typesToIncludes = {}
+        for using in tu.using:
+            typestr = str(using.type.spec)
+            assert typestr not in typesToIncludes
+            typesToIncludes[typestr] = using.header
+
+        aggregateTypeIncludes = set()
+        for su in tu.structsAndUnions:
+            typedeps = _ComputeTypeDeps(su.decl.type, True)
+            if isinstance(su, ipdl.ast.StructDecl):
+                for f in su.fields:
+                    f.ipdltype.accept(typedeps)
+            elif isinstance(su, ipdl.ast.UnionDecl):
+                for c in su.components:
+                    c.ipdltype.accept(typedeps)
+
+            for typename in [t.fromtype.name for t in typedeps.usingTypedefs]:
+                if typename in typesToIncludes:
+                    aggregateTypeIncludes.add(typesToIncludes[typename])
+
+        if len(aggregateTypeIncludes) != 0:
+            hf.addthing(Whitespace.NL)
+            hf.addthings([ Whitespace("// Headers for typedefs"), Whitespace.NL ])
+
+            for headername in sorted(iter(aggregateTypeIncludes)):
+                hf.addthing(CppDirective('include', '"' + headername + '"'))
+            
         ipdl.ast.Visitor.visitTranslationUnit(self, tu)
         if tu.filetype == 'header':
             self.cppIncludeHeaders.append(_ipdlhHeaderName(tu))
 
         hf.addthing(Whitespace.NL)
         hf.addthings(_includeGuardEnd(hf))
 
         cf = self.cppfile
@@ -1439,17 +1471,17 @@ class _GenerateProtocolCode(ipdl.ast.Vis
             cf.addthing(_putInNamespaces(ns, self.protocol.namespaces))
             ns.addstmts(([ Whitespace.NL]
                          + self.funcDefns
                          +[ Whitespace.NL ]))
 
         cf.addthings(self.structUnionDefns)
 
 
-    def visitCxxInclude(self, inc):
+    def visitBuiltinCxxInclude(self, inc):
         self.hdrfile.addthing(CppDirective('include', '"'+ inc.file +'"'))
 
     def visitInclude(self, inc):
         if inc.tu.filetype == 'header':
             self.hdrfile.addthing(CppDirective(
                     'include', '"'+ _ipdlhHeaderName(inc.tu) +'.h"'))
 
     def processStructOrUnionClass(self, su, which, forwarddecls, cls):
@@ -1835,24 +1867,25 @@ def _generateMessageClass(clsname, msgid
 ##--------------------------------------------------
 
 class _ComputeTypeDeps(TypeVisitor):
     '''Pass that gathers the C++ types that a particular IPDL type
 (recursively) depends on.  There are two kinds of dependencies: (i)
 types that need forward declaration; (ii) types that need a |using|
 stmt.  Some types generate both kinds.'''
 
-    def __init__(self, fortype):
+    def __init__(self, fortype, unqualifiedTypedefs=False):
         ipdl.type.TypeVisitor.__init__(self)
         self.usingTypedefs = [ ]
         self.forwardDeclStmts = [ ]
         self.fortype = fortype
+        self.unqualifiedTypedefs = unqualifiedTypedefs
 
     def maybeTypedef(self, fqname, name):
-        if fqname != name:
+        if fqname != name or self.unqualifiedTypedefs:
             self.usingTypedefs.append(Typedef(Type(fqname), name))
         
     def visitBuiltinCxxType(self, t):
         if t in self.visited: return
         self.visited.add(t)
         self.maybeTypedef(t.fullname(), t.name())
 
     def visitImportedCxxType(self, t):
@@ -2448,16 +2481,20 @@ class _GenerateProtocolActorCode(ipdl.as
         self.protocol = None
         self.hdrfile = None
         self.cppfile = None
         self.ns = None
         self.cls = None
         self.includedActorTypedefs = [ ]
         self.includedActorUsings = [ ]
         self.protocolCxxIncludes = [ ]
+        self.actorForwardDecls = [ ]
+        self.usingDecls = [ ]
+        self.externalIncludes = set()
+        self.nonForwardDeclaredHeaders = set()
 
     def lower(self, tu, clsname, cxxHeaderFile, cxxFile):
         self.clsname = clsname
         self.hdrfile = cxxHeaderFile
         self.cppfile = cxxFile
         tu.accept(self)
 
     def standardTypedefs(self):
@@ -2489,37 +2526,56 @@ class _GenerateProtocolActorCode(ipdl.as
                 Whitespace.NL,
                 CppDirective(
                     'include',
                     '"'+ _protocolHeaderName(tu.protocol) +'.h"')
             ])
 
         for inc in tu.includes:
             inc.accept(self)
+        for inc in tu.cxxIncludes:
+            inc.accept(self)
+
+        for using in tu.using:
+            using.accept(self)
 
         # this generates the actor's full impl in self.cls
         tu.protocol.accept(self)
 
         clsdecl, clsdefn = _splitClassDeclDefn(self.cls)
 
         # XXX damn C++ ... return types in the method defn aren't in
         # class scope
         for stmt in clsdefn.stmts:
             if isinstance(stmt, MethodDefn):
                 if stmt.decl.ret and stmt.decl.ret.name == 'Result':
                     stmt.decl.ret.name = clsdecl.name +'::'+ stmt.decl.ret.name
 
+        def setToIncludes(s):
+            return [ CppDirective('include', '"%s"' % i)
+                     for i in sorted(iter(s)) ]
+
         def makeNamespace(p, file):
             if 0 == len(p.namespaces):
                 return file
             ns = Namespace(p.namespaces[-1].name)
             outerns = _putInNamespaces(ns, p.namespaces[:-1])
             file.addthing(outerns)
             return ns
 
+        if len(self.nonForwardDeclaredHeaders) != 0:
+            self.hdrfile.addthings(
+                [ Whitespace('// Headers for things that cannot be forward declared'),
+                  Whitespace.NL ]
+                + setToIncludes(self.nonForwardDeclaredHeaders)
+                + [ Whitespace.NL ]
+            )
+        self.hdrfile.addthings(self.actorForwardDecls)
+        self.hdrfile.addthings(self.usingDecls)
+
         hdrns = makeNamespace(self.protocol, self.hdrfile)
         hdrns.addstmts([
             Whitespace.NL,
             Whitespace.NL,
             clsdecl,
             Whitespace.NL,
             Whitespace.NL
         ])
@@ -2537,18 +2593,18 @@ class _GenerateProtocolActorCode(ipdl.as
             + _includeGuardEnd(hf))
 
         # make the .cpp file
         cf.addthings([
             _DISCLAIMER,
             Whitespace.NL,
             CppDirective(
                 'include',
-                '"'+ _protocolHeaderName(self.protocol, self.side) +'.h"')
-        ])
+                '"'+ _protocolHeaderName(self.protocol, self.side) +'.h"') ]
+            + setToIncludes(self.externalIncludes))
              
         if self.protocol.decl.type.isToplevel():
             cf.addthings([
                 CppDirective('ifdef', 'MOZ_CRASHREPORTER'),
                 CppDirective('  include', '"nsXULAppAPI.h"'),
                 CppDirective('endif')
             ])
 
@@ -2566,23 +2622,42 @@ class _GenerateProtocolActorCode(ipdl.as
         cppns.addstmts([
             Whitespace.NL,
             Whitespace.NL,
             clsdefn,
             Whitespace.NL,
             Whitespace.NL
         ])
 
+    def visitUsingStmt(self, using):
+        if using.header is None:
+            return
+
+        if using.canBeForwardDeclared():
+            spec = using.type.spec
+
+            self.usingDecls.extend([
+                _makeForwardDeclForQClass(spec.baseid, spec.quals,
+                                          cls=using.isClass(),
+                                          struct=using.isStruct()),
+                Whitespace.NL
+            ])
+            self.externalIncludes.add(using.header)
+        else:
+            self.nonForwardDeclaredHeaders.add(using.header)
+
+    def visitCxxInclude(self, inc):
+        self.nonForwardDeclaredHeaders.add(inc.file)
 
     def visitInclude(self, inc):
         ip = inc.tu.protocol
         if not ip:
             return
 
-        self.hdrfile.addthings([
+        self.actorForwardDecls.extend([
             _makeForwardDeclForActor(ip.decl.type, self.side),
             Whitespace.NL
         ])
         self.protocolCxxIncludes.append(
             CppDirective(
                 'include',
                 '"%s.h"'% (_protocolHeaderName(ip, self.side))))
 
@@ -2640,18 +2715,17 @@ class _GenerateProtocolActorCode(ipdl.as
 
         # |friend| managed actors so that they can call our Dealloc*()
         friends.update(ptype.manages)
 
         # don't friend ourself if we're a self-managed protocol
         friends.discard(ptype)
 
         for friend in friends:
-            self.hdrfile.addthings([
-                Whitespace.NL,
+            self.actorForwardDecls.extend([
                 _makeForwardDeclForActor(friend, self.prettyside),
                 Whitespace.NL
             ])
             self.cls.addstmts([
                 FriendClassDecl(_actorName(friend.fullname(),
                                            self.prettyside)),
                 Whitespace.NL ])
 
--- a/ipc/ipdl/ipdl/parser.py
+++ b/ipc/ipdl/ipdl/parser.py
@@ -116,19 +116,21 @@ def locFromTok(p, num):
 reserved = set((
         'answer',
         'as',
         'async',
         'both',
         'bridges',
         'call',
         'child',
+        'class',
         'compress',
         '__delete__',
         'delete',                       # reserve 'delete' to prevent its use
+        'from',
         'goto',
         'include',
         'intr',
         'manager',
         'manages',
         'namespace',
         'nullable',
         'opens',
@@ -262,23 +264,39 @@ def p_IncludeStmt(p):
         id = p[2]
         type = 'header'
     inc = Include(loc, type, id)
 
     path = Parser.current.resolveIncludePath(inc.file)
     if path is None:
         raise ParseError(loc, "can't locate include file `%s'"% (
                 inc.file))
-    
+
     inc.tu = Parser(type, id).parse(open(path).read(), path, Parser.current.includedirs, Parser.current.errout)
     p[0] = inc
 
 def p_UsingStmt(p):
-    """UsingStmt : USING CxxType"""
-    p[0] = UsingStmt(locFromTok(p, 1), p[2])
+    """UsingStmt : USING CxxType FROM STRING
+                 | USING CLASS CxxType FROM STRING
+                 | USING STRUCT CxxType FROM STRING"""
+    if 6 == len(p):
+        header = p[5]
+    elif 5 == len(p):
+        header = p[4]
+    else:
+        header = None
+    if 6 == len(p):
+        kind = p[2]
+    else:
+        kind = None
+    if 6 == len(p):
+        cxxtype = p[3]
+    else:
+        cxxtype = p[2]
+    p[0] = UsingStmt(locFromTok(p, 1), cxxtype, header, kind)
 
 ##--------------------
 ## Namespaced stuff
 def p_NamespacedStuff(p):
     """NamespacedStuff : NamespacedStuff NamespaceThing
                        | NamespaceThing"""
     if 2 == len(p):
         p[0] = p[1]
--- a/ipc/ipdl/ipdl/type.py
+++ b/ipc/ipdl/ipdl/type.py
@@ -592,18 +592,16 @@ With this information, it finally type c
     def check(self, tu, errout=sys.stderr):
         def runpass(tcheckpass):
             tu.accept(tcheckpass)
             if len(self.errors):
                 self.reportErrors(errout)
                 return False
             return True
 
-        tu.cxxIncludes = builtinHeaderIncludes + tu.cxxIncludes
-
         # tag each relevant node with "decl" information, giving type, name,
         # and location of declaration
         if not runpass(GatherDecls(builtinUsing, self.errors)):
             return False
 
         # now that the nodes have decls, type checking is much easier.
         if not runpass(CheckTypes(self.errors)):
             return False
--- a/ipc/ipdl/test/cxx/PTestActorPunning.ipdl
+++ b/ipc/ipdl/test/cxx/PTestActorPunning.ipdl
@@ -1,15 +1,13 @@
 
 include protocol PTestActorPunningPunned;
 include protocol PTestActorPunningSub;
 include "mozilla/_ipdltest/IPDLUnitTestUtils.h";
 
-using mozilla::_ipdltest::Bad;
-
 namespace mozilla {
 namespace _ipdltest {
 
 protocol PTestActorPunning {
     manages PTestActorPunningPunned;
     manages PTestActorPunningSub;
 
 child:
--- a/ipc/ipdl/test/cxx/PTestDataStructures.ipdl
+++ b/ipc/ipdl/test/cxx/PTestDataStructures.ipdl
@@ -1,15 +1,13 @@
 include protocol PTestDataStructuresSub;
 include PTestDataStructuresCommon;
 
 include "mozilla/GfxMessageUtils.h";
 
-include "mozilla/GfxMessageUtils.h";
-
 namespace mozilla {
 namespace _ipdltest {
 
 sync protocol PTestDataStructures {
     manages PTestDataStructuresSub;
 
 child:
     PTestDataStructuresSub(int i);
--- a/ipc/ipdl/test/cxx/PTestDataStructuresCommon.ipdlh
+++ b/ipc/ipdl/test/cxx/PTestDataStructuresCommon.ipdlh
@@ -1,12 +1,12 @@
 include protocol PTestDataStructuresSub;
 
-using mozilla::null_t;
-using nsIntRegion;
+using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
+using nsIntRegion from "nsRegion.h";
 
 namespace mozilla {
 namespace _foo {
 
 union IntDouble {
     int;
     double;
 };
--- a/ipc/ipdl/test/cxx/PTestJSON.ipdl
+++ b/ipc/ipdl/test/cxx/PTestJSON.ipdl
@@ -1,12 +1,12 @@
 include protocol PTestHandle;
 
-using mozilla::void_t;
-using mozilla::null_t;
+using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
+using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
 
 namespace mozilla {
 namespace _ipdltest {
 
 union Key {
 //    int;
 //    double;
     nsString;
--- a/ipc/ipdl/test/ipdl/error/shmem.ipdl
+++ b/ipc/ipdl/test/ipdl/error/shmem.ipdl
@@ -1,5 +1,5 @@
-using mozilla::ipc::Shmem;      // redeclaration
+using class mozilla::ipc::Shmem from "mozilla/ipc/Shmem.h";      // redeclaration
 
 protocol shmem {
 child: Msg(Shmem s);
 };
--- a/ipc/ipdl/test/ipdl/ok/header.ipdlh
+++ b/ipc/ipdl/test/ipdl/ok/header.ipdlh
@@ -1,12 +1,10 @@
-include "foo.h";
-
-using foo;
-using bar::baz;
+using foo from "foo.h";
+using bar::baz from "foo.h";
 
 struct Outer { };
 
 namespace a { struct Inner1 { }; }
 
 namespace b { struct Inner2 { }; }
 
 namespace c {
--- a/ipc/ipdl/test/ipdl/ok/multipleUsingCxxTypes.ipdl
+++ b/ipc/ipdl/test/ipdl/ok/multipleUsingCxxTypes.ipdl
@@ -1,7 +1,7 @@
-using mozilla::void_t;
-using mozilla::void_t;
+using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
+using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 
 protocol multipleUsingCxxTypes {
 child:
     Msg(void_t foo);
 };
--- a/ipc/testshell/XPCShellEnvironment.cpp
+++ b/ipc/testshell/XPCShellEnvironment.cpp
@@ -223,27 +223,28 @@ Quit(JSContext *cx,
     return false;
 }
 
 static bool
 DumpXPC(JSContext *cx,
         unsigned argc,
         JS::Value *vp)
 {
-    int32_t depth = 2;
+    JS::CallArgs args = CallArgsFromVp(argc, vp);
 
-    if (argc > 0) {
-        if (!JS_ValueToInt32(cx, JS_ARGV(cx, vp)[0], &depth))
+    uint16_t depth = 2;
+    if (args.length() > 0) {
+        if (!JS::ToUint16(cx, args[0], &depth))
             return false;
     }
 
     nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
-    if(xpc)
+    if (xpc)
         xpc->DebugDump(int16_t(depth));
-    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    args.rval().setUndefined();
     return true;
 }
 
 static bool
 GC(JSContext *cx,
    unsigned argc,
    JS::Value *vp)
 {
--- a/js/ipc/JavaScriptTypes.ipdlh
+++ b/js/ipc/JavaScriptTypes.ipdlh
@@ -2,17 +2,17 @@
  * vim: set ts=4 sw=4 et 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 DOMTypes;
 
-using mozilla::void_t;
+using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 
 namespace mozilla {
 namespace jsipc {
 
 struct JSIID
 {
     uint32_t m0;
     uint16_t m1;
--- a/js/ipc/PJavaScript.ipdl
+++ b/js/ipc/PJavaScript.ipdl
@@ -4,17 +4,17 @@
  * 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 protocol PContent;
 include DOMTypes;
 include JavaScriptTypes;
 
-using mozilla::void_t;
+using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 
 namespace mozilla {
 namespace jsipc {
 
 intr protocol PJavaScript
 {
     manager PContent;
 
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -87,17 +87,17 @@ struct InefficientNonFlatteningStringHas
 //
 // In some classes, one or more of the macro arguments aren't used.  We use '_'
 // for those.
 //
 #define DECL_SIZE(kind, gc, mSize)                      size_t mSize;
 #define ZERO_SIZE(kind, gc, mSize)                      mSize(0),
 #define COPY_OTHER_SIZE(kind, gc, mSize)                mSize(other.mSize),
 #define ADD_OTHER_SIZE(kind, gc, mSize)                 mSize += other.mSize;
-#define ADD_SIZE_TO_N_IF_LIVE_GC_THING(kind, gc, mSize) n += (js::gc == js::IsLiveGCThing) ? mSize : 0;
+#define ADD_SIZE_TO_N_IF_LIVE_GC_THING(kind, gc, mSize) n += (js::gc) ? mSize : 0;
 #define ADD_TO_TAB_SIZES(kind, gc, mSize)               sizes->add(JS::TabSizes::kind, mSize);
 
 // Used to annotate which size_t fields measure live GC things and which don't.
 enum {
     NotLiveGCThing = false,
     IsLiveGCThing = true
 };
 
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -768,23 +768,19 @@ static bool
 OOMAfterAllocations(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() != 1) {
         JS_ReportError(cx, "count argument required");
         return false;
     }
 
-    int32_t count;
-    if (!JS_ValueToInt32(cx, args[0], &count))
+    uint32_t count;
+    if (!JS::ToUint32(cx, args[0], &count))
         return false;
-    if (count <= 0) {
-        JS_ReportError(cx, "count argument must be positive");
-        return false;
-    }
 
     OOM_maxAllocations = OOM_counter + count;
     return true;
 }
 #endif
 
 static unsigned finalizeCount = 0;
 
--- a/js/src/devtools/rootAnalysis/analyze.py
+++ b/js/src/devtools/rootAnalysis/analyze.py
@@ -123,17 +123,17 @@ JOBS = { 'dbs':
              (('%(sixgill_bin)s/xdbkeys', 'src_body.xdb',),
               'allFunctions.txt'),
 
          'hazards':
              (generate_hazards, 'rootingHazards.txt'),
 
          'explain':
              (('python', '%(analysis_scriptdir)s/explain.py',
-               '--expect-file=%(analysis_scriptdir)s/expect.json',
+               '--expect-file=%(expect_file)s',
                '%(hazards)s', '%(gcFunctions)s',
                '[explained_hazards]', '[unnecessary]', '[refs]'),
               ('hazards.txt', 'unnecessary.txt', 'refs.txt'))
          }
 
 def out_indexes(command):
     for i in range(len(command)):
         m = re.match(r'^\[(.*)\]$', command[i])
@@ -205,32 +205,39 @@ parser.add_argument('--upto', metavar='U
 parser.add_argument('--jobs', '-j', default=None, metavar='JOBS', type=int,
                     help='number of simultaneous analyzeRoots.js jobs')
 parser.add_argument('--list', const=True, nargs='?', type=bool,
                     help='display available steps')
 parser.add_argument('--buildcommand', '--build', '-b', type=str, nargs='?',
                     help='command to build the tree being analyzed')
 parser.add_argument('--tag', '-t', type=str, nargs='?',
                     help='name of job, also sets build command to "build.<tag>"')
+parser.add_argument('--expect-file', type=str, nargs='?',
+                    help='file containing expected number of hazards/refs')
 
 args = parser.parse_args()
 for k,v in vars(args).items():
     if v is not None:
         data[k] = v
 
 if args.tag and not args.buildcommand:
     args.buildcommand="build.%s" % args.tag
 
 if args.buildcommand:
     data['buildcommand'] = args.buildcommand
 elif 'BUILD' in os.environ:
     data['buildcommand'] = os.environ['BUILD']
 else:
     data['buildcommand'] = 'make -j4 -s'
 
+if args.expect_file:
+    data['expect_file'] = args.expect_file
+else:
+    data['expect_file'] = '%(analysis_scriptdir)s/expect.json'
+
 if 'ANALYZED_OBJDIR' in os.environ:
     data['objdir'] = os.environ['ANALYZED_OBJDIR']
 
 if 'SOURCE' in os.environ:
     data['source'] = os.environ['SOURCE']
 
 steps = [ 'dbs',
           'callgraph',
new file mode 100644
--- /dev/null
+++ b/js/src/devtools/rootAnalysis/expect.browser.json
@@ -0,0 +1,3 @@
+{
+  "expect-hazards": 19
+}
rename from js/src/devtools/rootAnalysis/expect.json
rename to js/src/devtools/rootAnalysis/expect.shell.json
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -380,20 +380,20 @@ frontend::CompileScript(ExclusiveContext
      * header) override any source map urls passed as comment pragmas.
      */
     if (options.sourceMapURL) {
         if (!ss->setSourceMapURL(cx, options.sourceMapURL))
             return nullptr;
     }
 
     /*
-     * Nowadays the threaded interpreter needs a stop instruction, so we
+     * Nowadays the threaded interpreter needs a last return instruction, so we
      * do have to emit that here.
      */
-    if (Emit1(cx, &bce, JSOP_STOP) < 0)
+    if (Emit1(cx, &bce, JSOP_RETRVAL) < 0)
         return nullptr;
 
     if (!JSScript::fullyInitFromEmitter(cx, script, &bce))
         return nullptr;
 
     bce.tellDebuggerAboutCompiledScript(cx);
 
     if (sct && !extraSct && !sct->complete())
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -1135,27 +1135,16 @@ TryConvertFreeName(BytecodeEmitter *bce,
     }
 
     /*
      * When parsing inner functions lazily, parse nodes for outer functions no
      * longer exist and only the function's scope chain is available for
      * resolving upvar accesses within the inner function.
      */
     if (bce->emitterMode == BytecodeEmitter::LazyFunction) {
-        // The only statements within a lazy function which can push lexical
-        // scopes are try/catch blocks. Use generic ops in this case.
-        for (StmtInfoBCE *stmt = bce->topStmt; stmt; stmt = stmt->down) {
-            switch (stmt->type) {
-              case STMT_TRY:
-              case STMT_FINALLY:
-                return true;
-              default:;
-            }
-        }
-
         size_t hops = 0;
         FunctionBox *funbox = bce->sc->asFunctionBox();
         if (funbox->hasExtensibleScope())
             return false;
         if (funbox->function()->isNamedLambda() && funbox->function()->atom() == pn->pn_atom)
             return false;
         if (funbox->isHeavyweight()) {
             hops++;
@@ -2695,20 +2684,20 @@ frontend::EmitFunctionScript(ExclusiveCo
             return false;
 
         // No need to check for finally blocks, etc as in EmitReturn.
         if (Emit1(cx, bce, JSOP_RETURN) < 0)
             return false;
     }
 
     /*
-     * Always end the script with a JSOP_STOP. Some other parts of the codebase
+     * Always end the script with a JSOP_RETRVAL. Some other parts of the codebase
      * depend on this opcode, e.g. js_InternalInterpret.
      */
-    if (Emit1(cx, bce, JSOP_STOP) < 0)
+    if (Emit1(cx, bce, JSOP_RETRVAL) < 0)
         return false;
 
     if (!JSScript::fullyInitFromEmitter(cx, bce->script, bce))
         return false;
 
     /*
      * If this function is only expected to run once, mark the script so that
      * initializers created within it may be given more precise types.
@@ -3157,17 +3146,17 @@ enum GroupOption { GroupIsDecl, GroupIsN
  * we set *pop to JSOP_NOP so callers can veto emitting pn followed by a pop.
  */
 static bool
 MaybeEmitGroupAssignment(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn,
                          GroupOption groupOption, JSOp *pop)
 {
     JS_ASSERT(pn->isKind(PNK_ASSIGN));
     JS_ASSERT(pn->isOp(JSOP_NOP));
-    JS_ASSERT(*pop == JSOP_POP || *pop == JSOP_POPV);
+    JS_ASSERT(*pop == JSOP_POP || *pop == JSOP_SETRVAL);
 
     ParseNode *lhs = pn->pn_left;
     ParseNode *rhs = pn->pn_right;
     if (lhs->isKind(PNK_ARRAY) && rhs->isKind(PNK_ARRAY) &&
         !(rhs->pn_xflags & PNX_SPECIALARRAYINIT) &&
         lhs->pn_count <= rhs->pn_count)
     {
         if (groupOption == GroupIsDecl && !EmitDestructuringDecls(cx, bce, prologOp, lhs))
@@ -3189,17 +3178,17 @@ MaybeEmitGroupAssignment(ExclusiveContex
  * decompile so we restrict the ourselves to cases where the lhs and rhs are in
  * 1:1 correspondence and lhs elements are simple names.
  */
 static bool
 MaybeEmitLetGroupDecl(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSOp *pop)
 {
     JS_ASSERT(pn->isKind(PNK_ASSIGN));
     JS_ASSERT(pn->isOp(JSOP_NOP));
-    JS_ASSERT(*pop == JSOP_POP || *pop == JSOP_POPV);
+    JS_ASSERT(*pop == JSOP_POP || *pop == JSOP_SETRVAL);
 
     ParseNode *lhs = pn->pn_left;
     ParseNode *rhs = pn->pn_right;
     if (lhs->isKind(PNK_ARRAY) && rhs->isKind(PNK_ARRAY) &&
         !(rhs->pn_xflags & PNX_SPECIALARRAYINIT) &&
         !(lhs->pn_xflags & PNX_SPECIALARRAYINIT) &&
         lhs->pn_count == rhs->pn_count)
     {
@@ -5304,17 +5293,17 @@ EmitStatement(ExclusiveContext *cx, Byte
 
     /*
      * Top-level or called-from-a-native JS_Execute/EvaluateScript,
      * debugger, and eval frames may need the value of the ultimate
      * expression statement as the script's result, despite the fact
      * that it appears useless to the compiler.
      *
      * API users may also set the JSOPTION_NO_SCRIPT_RVAL option when
-     * calling JS_Compile* to suppress JSOP_POPV.
+     * calling JS_Compile* to suppress JSOP_SETRVAL.
      */
     bool wantval = false;
     bool useful = false;
     if (bce->sc->isFunctionBox()) {
         JS_ASSERT(!bce->script->noScriptRval);
     } else {
         useful = wantval = !bce->script->noScriptRval;
     }
@@ -5334,17 +5323,17 @@ EmitStatement(ExclusiveContext *cx, Byte
             bce->topStmt->type == STMT_LABEL &&
             bce->topStmt->update >= bce->offset())
         {
             useful = true;
         }
     }
 
     if (useful) {
-        JSOp op = wantval ? JSOP_POPV : JSOP_POP;
+        JSOp op = wantval ? JSOP_SETRVAL : JSOP_POP;
         JS_ASSERT_IF(pn2->isKind(PNK_ASSIGN), pn2->isOp(JSOP_NOP));
 #if JS_HAS_DESTRUCTURING
         if (!wantval &&
             pn2->isKind(PNK_ASSIGN) &&
             !MaybeEmitGroupAssignment(cx, bce, op, pn2, GroupIsNotDecl, &op))
         {
             return false;
         }
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -265,57 +265,37 @@ HashTableWriteBarrierPost(JSRuntime *rt,
 #ifdef JSGC_GENERATIONAL
     if (key && IsInsideNursery(rt, key)) {
         JS::shadow::Runtime *shadowRuntime = JS::shadow::Runtime::asShadowRuntime(rt);
         shadowRuntime->gcStoreBufferPtr()->putGeneric(gc::HashKeyRef<Map, Key>(map, key));
     }
 #endif
 }
 
+/*
+ * Base class for barriered pointer types.
+ */
 template<class T, typename Unioned = uintptr_t>
-class EncapsulatedPtr
+class BarrieredPtr
 {
   protected:
     union {
         T *value;
         Unioned other;
     };
 
+    BarrieredPtr(T *v) : value(v) {}
+    ~BarrieredPtr() { pre(); }
+
   public:
-    EncapsulatedPtr() : value(nullptr) {}
-    EncapsulatedPtr(T *v) : value(v) {}
-    explicit EncapsulatedPtr(const EncapsulatedPtr<T> &v) : value(v.value) {}
-
-    ~EncapsulatedPtr() { pre(); }
-
     void init(T *v) {
         JS_ASSERT(!IsPoisonedPtr<T>(v));
         this->value = v;
     }
 
-    /* Use to set the pointer to nullptr. */
-    void clear() {
-        pre();
-        value = nullptr;
-    }
-
-    EncapsulatedPtr<T, Unioned> &operator=(T *v) {
-        pre();
-        JS_ASSERT(!IsPoisonedPtr<T>(v));
-        value = v;
-        return *this;
-    }
-
-    EncapsulatedPtr<T, Unioned> &operator=(const EncapsulatedPtr<T> &v) {
-        pre();
-        JS_ASSERT(!IsPoisonedPtr<T>(v.value));
-        value = v.value;
-        return *this;
-    }
-
     /* Use this if the automatic coercion to T* isn't working. */
     T *get() const { return value; }
 
     /*
      * Use these if you want to change the value without invoking the barrier.
      * Obviously this is dangerous unless you know the barrier is not needed.
      */
     T **unsafeGet() { return &value; }
@@ -327,29 +307,58 @@ class EncapsulatedPtr
     T *operator->() const { return value; }
 
     operator T*() const { return value; }
 
   protected:
     void pre() { T::writeBarrierPre(value); }
 };
 
+template<class T, typename Unioned = uintptr_t>
+class EncapsulatedPtr : public BarrieredPtr<T, Unioned>
+{
+  public:
+    EncapsulatedPtr() : BarrieredPtr<T, Unioned>(nullptr) {}
+    EncapsulatedPtr(T *v) : BarrieredPtr<T, Unioned>(v) {}
+    explicit EncapsulatedPtr(const EncapsulatedPtr<T, Unioned> &v)
+      : BarrieredPtr<T, Unioned>(v.value) {}
+
+    /* Use to set the pointer to nullptr. */
+    void clear() {
+        this->pre();
+        this->value = nullptr;
+    }
+
+    EncapsulatedPtr<T, Unioned> &operator=(T *v) {
+        this->pre();
+        JS_ASSERT(!IsPoisonedPtr<T>(v));
+        this->value = v;
+        return *this;
+    }
+
+    EncapsulatedPtr<T, Unioned> &operator=(const EncapsulatedPtr<T> &v) {
+        this->pre();
+        JS_ASSERT(!IsPoisonedPtr<T>(v.value));
+        this->value = v.value;
+        return *this;
+    }
+};
+
 /*
  * A pre- and post-barriered heap pointer, for use inside the JS engine.
  *
  * Not to be confused with JS::Heap<T>.
  */
 template <class T, class Unioned = uintptr_t>
-class HeapPtr : public EncapsulatedPtr<T, Unioned>
+class HeapPtr : public BarrieredPtr<T, Unioned>
 {
   public:
-    HeapPtr() : EncapsulatedPtr<T>(nullptr) {}
-    explicit HeapPtr(T *v) : EncapsulatedPtr<T>(v) { post(); }
-    explicit HeapPtr(const HeapPtr<T> &v)
-      : EncapsulatedPtr<T>(v) { post(); }
+    HeapPtr() : BarrieredPtr<T, Unioned>(nullptr) {}
+    explicit HeapPtr(T *v) : BarrieredPtr<T, Unioned>(v) { post(); }
+    explicit HeapPtr(const HeapPtr<T> &v) : BarrieredPtr<T, Unioned>(v) { post(); }
 
     void init(T *v) {
         JS_ASSERT(!IsPoisonedPtr<T>(v));
         this->value = v;
         post();
     }
 
     HeapPtr<T, Unioned> &operator=(T *v) {
@@ -405,25 +414,25 @@ class FixedHeapPtr
     }
 
     void init(T *ptr) {
         value = ptr;
     }
 };
 
 template <class T>
-class RelocatablePtr : public EncapsulatedPtr<T>
+class RelocatablePtr : public BarrieredPtr<T>
 {
   public:
-    RelocatablePtr() : EncapsulatedPtr<T>(nullptr) {}
-    explicit RelocatablePtr(T *v) : EncapsulatedPtr<T>(v) {
+    RelocatablePtr() : BarrieredPtr<T>(nullptr) {}
+    explicit RelocatablePtr(T *v) : BarrieredPtr<T>(v) {
         if (v)
             post();
     }
-    RelocatablePtr(const RelocatablePtr<T> &v) : EncapsulatedPtr<T>(v) {
+    RelocatablePtr(const RelocatablePtr<T> &v) : BarrieredPtr<T>(v) {
         if (this->value)
             post();
     }
 
     ~RelocatablePtr() {
         if (this->value)
             relocate(this->value->runtimeFromAnyThread());
     }
@@ -490,16 +499,19 @@ BarrieredSetPair(Zone *zone,
     v1.post();
     v2.post();
 }
 
 class Shape;
 class BaseShape;
 namespace types { struct TypeObject; }
 
+typedef BarrieredPtr<JSObject> BarrieredPtrObject;
+typedef BarrieredPtr<JSScript> BarrieredPtrScript;
+
 typedef EncapsulatedPtr<JSObject> EncapsulatedPtrObject;
 typedef EncapsulatedPtr<JSScript> EncapsulatedPtrScript;
 
 typedef RelocatablePtr<JSObject> RelocatablePtrObject;
 typedef RelocatablePtr<JSScript> RelocatablePtrScript;
 
 typedef HeapPtr<JSObject> HeapPtrObject;
 typedef HeapPtr<JSFunction> HeapPtrFunction;
@@ -535,64 +547,50 @@ struct EncapsulatedPtrHasher
     static HashNumber hash(Lookup obj) { return DefaultHasher<T *>::hash(obj); }
     static bool match(const Key &k, Lookup l) { return k.get() == l; }
     static void rekey(Key &k, const Key& newKey) { k.unsafeSet(newKey); }
 };
 
 template <class T>
 struct DefaultHasher< EncapsulatedPtr<T> > : EncapsulatedPtrHasher<T> { };
 
-class EncapsulatedValue : public ValueOperations<EncapsulatedValue>
+/*
+ * Base class for barriered value types.
+ */
+class BarrieredValue : public ValueOperations<BarrieredValue>
 {
   protected:
     Value value;
 
     /*
      * Ensure that EncapsulatedValue is not constructable, except by our
      * implementations.
      */
-    EncapsulatedValue() MOZ_DELETE;
+    BarrieredValue() MOZ_DELETE;
 
-  public:
-    EncapsulatedValue(const Value &v) : value(v) {
-        JS_ASSERT(!IsPoisonedValue(v));
-    }
-    EncapsulatedValue(const EncapsulatedValue &v) : value(v) {
+    BarrieredValue(const Value &v) : value(v) {
         JS_ASSERT(!IsPoisonedValue(v));
     }
 
-    ~EncapsulatedValue() {
+    ~BarrieredValue() {
         pre();
     }
 
+  public:
     void init(const Value &v) {
         JS_ASSERT(!IsPoisonedValue(v));
         value = v;
     }
     void init(JSRuntime *rt, const Value &v) {
         JS_ASSERT(!IsPoisonedValue(v));
         value = v;
     }
 
-    EncapsulatedValue &operator=(const Value &v) {
-        pre();
-        JS_ASSERT(!IsPoisonedValue(v));
-        value = v;
-        return *this;
-    }
-
-    EncapsulatedValue &operator=(const EncapsulatedValue &v) {
-        pre();
-        JS_ASSERT(!IsPoisonedValue(v));
-        value = v.get();
-        return *this;
-    }
-
-    bool operator==(const EncapsulatedValue &v) const { return value == v.value; }
-    bool operator!=(const EncapsulatedValue &v) const { return value != v.value; }
+    bool operator==(const BarrieredValue &v) const { return value == v.value; }
+    bool operator!=(const BarrieredValue &v) const { return value != v.value; }
 
     const Value &get() const { return value; }
     Value *unsafeGet() { return &value; }
     operator const Value &() const { return value; }
 
     JSGCTraceKind gcKind() const { return value.gcKind(); }
 
     uint64_t asRawBits() const { return value.asRawBits(); }
@@ -631,43 +629,64 @@ class EncapsulatedValue : public ValueOp
     static JS::shadow::Runtime *shadowRuntimeFromMainThread(const Value &v) {
         return reinterpret_cast<JS::shadow::Runtime*>(runtimeFromMainThread(v));
     }
     static JS::shadow::Runtime *shadowRuntimeFromAnyThread(const Value &v) {
         return reinterpret_cast<JS::shadow::Runtime*>(runtimeFromAnyThread(v));
     }
 
   private:
-    friend class ValueOperations<EncapsulatedValue>;
+    friend class ValueOperations<BarrieredValue>;
     const Value * extract() const { return &value; }
 };
 
+class EncapsulatedValue : public BarrieredValue
+{
+  public:
+    EncapsulatedValue(const Value &v) : BarrieredValue(v) {}
+    EncapsulatedValue(const EncapsulatedValue &v) : BarrieredValue(v) {}
+
+    EncapsulatedValue &operator=(const Value &v) {
+        pre();
+        JS_ASSERT(!IsPoisonedValue(v));
+        value = v;
+        return *this;
+    }
+
+    EncapsulatedValue &operator=(const EncapsulatedValue &v) {
+        pre();
+        JS_ASSERT(!IsPoisonedValue(v));
+        value = v.get();
+        return *this;
+    }
+};
+
 /*
  * A pre- and post-barriered heap JS::Value, for use inside the JS engine.
  *
  * Not to be confused with JS::Heap<JS::Value>.
  */
-class HeapValue : public EncapsulatedValue
+class HeapValue : public BarrieredValue
 {
   public:
     explicit HeapValue()
-      : EncapsulatedValue(UndefinedValue())
+      : BarrieredValue(UndefinedValue())
     {
         post();
     }
 
     explicit HeapValue(const Value &v)
-      : EncapsulatedValue(v)
+      : BarrieredValue(v)
     {
         JS_ASSERT(!IsPoisonedValue(v));
         post();
     }
 
     explicit HeapValue(const HeapValue &v)
-      : EncapsulatedValue(v.value)
+      : BarrieredValue(v.value)
     {
         JS_ASSERT(!IsPoisonedValue(v.value));
         post();
     }
 
     ~HeapValue() {
         pre();
     }
@@ -740,33 +759,30 @@ class HeapValue : public EncapsulatedVal
         writeBarrierPost(value, &value);
     }
 
     void post(JSRuntime *rt) {
         writeBarrierPost(rt, value, &value);
     }
 };
 
-class RelocatableValue : public EncapsulatedValue
+class RelocatableValue : public BarrieredValue
 {
   public:
-    explicit RelocatableValue()
-      : EncapsulatedValue(UndefinedValue())
-    {}
+    explicit RelocatableValue() : BarrieredValue(UndefinedValue()) {}
 
     explicit RelocatableValue(const Value &v)
-      : EncapsulatedValue(v)
+      : BarrieredValue(v)
     {
-        JS_ASSERT(!IsPoisonedValue(v));
         if (v.isMarkable())
             post();
     }
 
     RelocatableValue(const RelocatableValue &v)
-      : EncapsulatedValue(v.value)
+      : BarrieredValue(v.value)
     {
         JS_ASSERT(!IsPoisonedValue(v.value));
         if (v.value.isMarkable())
             post();
     }
 
     ~RelocatableValue()
     {
@@ -817,43 +833,35 @@ class RelocatableValue : public Encapsul
     void relocate(JSRuntime *rt) {
 #ifdef JSGC_GENERATIONAL
         JS::shadow::Runtime *shadowRuntime = JS::shadow::Runtime::asShadowRuntime(rt);
         shadowRuntime->gcStoreBufferPtr()->removeRelocatableValue(&value);
 #endif
     }
 };
 
-class HeapSlot : public EncapsulatedValue
+class HeapSlot : public BarrieredValue
 {
-    /*
-     * Operator= is not valid for HeapSlot because is must take the object and
-     * slot offset to provide to the post/generational barrier.
-     */
-    inline HeapSlot &operator=(const Value &v) MOZ_DELETE;
-    inline HeapSlot &operator=(const HeapValue &v) MOZ_DELETE;
-    inline HeapSlot &operator=(const HeapSlot &v) MOZ_DELETE;
-
   public:
     enum Kind {
         Slot,
         Element
     };
 
     explicit HeapSlot() MOZ_DELETE;
 
     explicit HeapSlot(JSObject *obj, Kind kind, uint32_t slot, const Value &v)
-      : EncapsulatedValue(v)
+      : BarrieredValue(v)
     {
         JS_ASSERT(!IsPoisonedValue(v));
         post(obj, kind, slot, v);
     }
 
     explicit HeapSlot(JSObject *obj, Kind kind, uint32_t slot, const HeapSlot &s)
-      : EncapsulatedValue(s.value)
+      : BarrieredValue(s.value)
     {
         JS_ASSERT(!IsPoisonedValue(s.value));
         post(obj, kind, slot, s);
     }
 
     ~HeapSlot() {
         pre();
     }
@@ -920,17 +928,17 @@ class HeapSlot : public EncapsulatedValu
     }
 
     void post(JSRuntime *rt, JSObject *owner, Kind kind, uint32_t slot, Value target) {
         HeapSlot::writeBarrierPost(rt, owner, kind, slot, target);
     }
 };
 
 static inline const Value *
-Valueify(const EncapsulatedValue *array)
+Valueify(const BarrieredValue *array)
 {
     JS_STATIC_ASSERT(sizeof(HeapValue) == sizeof(Value));
     JS_STATIC_ASSERT(sizeof(HeapSlot) == sizeof(Value));
     return (const Value *)array;
 }
 
 static inline HeapValue *
 HeapValueify(Value *v)
@@ -949,37 +957,32 @@ class HeapSlotArray
 
     operator const Value *() const { return Valueify(array); }
     operator HeapSlot *() const { return array; }
 
     HeapSlotArray operator +(int offset) const { return HeapSlotArray(array + offset); }
     HeapSlotArray operator +(uint32_t offset) const { return HeapSlotArray(array + offset); }
 };
 
-class EncapsulatedId
+/*
+ * Base class for barriered jsid types.
+ */
+class BarrieredId
 {
   protected:
     jsid value;
 
   private:
-    EncapsulatedId(const EncapsulatedId &v) MOZ_DELETE;
+    BarrieredId(const BarrieredId &v) MOZ_DELETE;
+
+  protected:
+    explicit BarrieredId(jsid id) : value(id) {}
+    ~BarrieredId() { pre(); }
 
   public:
-    explicit EncapsulatedId() : value(JSID_VOID) {}
-    explicit EncapsulatedId(jsid id) : value(id) {}
-    ~EncapsulatedId() { pre(); }
-
-    EncapsulatedId &operator=(const EncapsulatedId &v) {
-        if (v.value != value)
-            pre();
-        JS_ASSERT(!IsPoisonedId(v.value));
-        value = v.value;
-        return *this;
-    }
-
     bool operator==(jsid id) const { return value == id; }
     bool operator!=(jsid id) const { return value != id; }
 
     jsid get() const { return value; }
     jsid *unsafeGet() { return &value; }
     void unsafeSet(jsid newId) { value = newId; }
     operator jsid() const { return value; }
 
@@ -1000,23 +1003,46 @@ class EncapsulatedId
                 js::gc::MarkStringUnbarriered(shadowZone->barrierTracer(), &str, "write barrier");
                 JS_ASSERT(str == JSID_TO_STRING(value));
             }
         }
 #endif
     }
 };
 
-class RelocatableId : public EncapsulatedId
+class EncapsulatedId : public BarrieredId
 {
   public:
-    explicit RelocatableId() : EncapsulatedId() {}
-    explicit inline RelocatableId(jsid id) : EncapsulatedId(id) {}
+    explicit EncapsulatedId(jsid id) : BarrieredId(id) {}
+    explicit EncapsulatedId() : BarrieredId(JSID_VOID) {}
+
+    EncapsulatedId &operator=(const EncapsulatedId &v) {
+        if (v.value != value)
+            pre();
+        JS_ASSERT(!IsPoisonedId(v.value));
+        value = v.value;
+        return *this;
+    }
+};
+
+class RelocatableId : public BarrieredId
+{
+  public:
+    explicit RelocatableId() : BarrieredId(JSID_VOID) {}
+    explicit inline RelocatableId(jsid id) : BarrieredId(id) {}
     ~RelocatableId() { pre(); }
 
+    bool operator==(jsid id) const { return value == id; }
+    bool operator!=(jsid id) const { return value != id; }
+
+    jsid get() const { return value; }
+    operator jsid() const { return value; }
+
+    jsid *unsafeGet() { return &value; }
+
     RelocatableId &operator=(jsid id) {
         if (id != value)
             pre();
         JS_ASSERT(!IsPoisonedId(id));
         value = id;
         return *this;
     }
 
@@ -1029,23 +1055,23 @@ class RelocatableId : public Encapsulate
     }
 };
 
 /*
  * A pre- and post-barriered heap jsid, for use inside the JS engine.
  *
  * Not to be confused with JS::Heap<jsid>.
  */
-class HeapId : public EncapsulatedId
+class HeapId : public BarrieredId
 {
   public:
-    explicit HeapId() : EncapsulatedId() {}
+    explicit HeapId() : BarrieredId(JSID_VOID) {}
 
     explicit HeapId(jsid id)
-      : EncapsulatedId(id)
+      : BarrieredId(id)
     {
         JS_ASSERT(!IsPoisonedId(id));
         post();
     }
 
     ~HeapId() { pre(); }
 
     void init(jsid id) {
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -214,17 +214,17 @@ void
 MarkUnbarriered(JSTracer *trc, T **thingp, const char *name)
 {
     JS_SET_TRACING_NAME(trc, name);
     MarkInternal(trc, thingp);
 }
 
 template <typename T>
 static void
-Mark(JSTracer *trc, EncapsulatedPtr<T> *thing, const char *name)
+Mark(JSTracer *trc, BarrieredPtr<T> *thing, const char *name)
 {
     JS_SET_TRACING_NAME(trc, name);
     MarkInternal(trc, thing->unsafeGet());
 }
 
 } /* namespace gc */
 } /* namespace js */
 
@@ -306,17 +306,17 @@ IsAboutToBeFinalized(T **thingp)
      */
     JS_ASSERT(!(*thingp)->arenaHeader()->allocatedDuringIncremental);
 
     return !(*thingp)->isMarked();
 }
 
 #define DeclMarkerImpl(base, type)                                                                \
 void                                                                                              \
-Mark##base(JSTracer *trc, EncapsulatedPtr<type> *thing, const char *name)                         \
+Mark##base(JSTracer *trc, BarrieredPtr<type> *thing, const char *name)                         \
 {                                                                                                 \
     Mark<type>(trc, thing, name);                                                                 \
 }                                                                                                 \
                                                                                                   \
 void                                                                                              \
 Mark##base##Root(JSTracer *trc, type **thingp, const char *name)                                  \
 {                                                                                                 \
     MarkRoot<type>(trc, thingp, name);                                                            \
@@ -347,29 +347,29 @@ Mark##base##RootRange(JSTracer *trc, siz
                                                                                                   \
 bool                                                                                              \
 Is##base##Marked(type **thingp)                                                                   \
 {                                                                                                 \
     return IsMarked<type>(thingp);                                                                \
 }                                                                                                 \
                                                                                                   \
 bool                                                                                              \
-Is##base##Marked(EncapsulatedPtr<type> *thingp)                                                   \
+Is##base##Marked(BarrieredPtr<type> *thingp)                                                   \
 {                                                                                                 \
     return IsMarked<type>(thingp->unsafeGet());                                                   \
 }                                                                                                 \
                                                                                                   \
 bool                                                                                              \
 Is##base##AboutToBeFinalized(type **thingp)                                                       \
 {                                                                                                 \
     return IsAboutToBeFinalized<type>(thingp);                                                    \
 }                                                                                                 \
                                                                                                   \
 bool                                                                                              \
-Is##base##AboutToBeFinalized(EncapsulatedPtr<type> *thingp)                                       \
+Is##base##AboutToBeFinalized(BarrieredPtr<type> *thingp)                                       \
 {                                                                                                 \
     return IsAboutToBeFinalized<type>(thingp->unsafeGet());                                       \
 }
 
 DeclMarkerImpl(BaseShape, BaseShape)
 DeclMarkerImpl(BaseShape, UnownedBaseShape)
 DeclMarkerImpl(IonCode, jit::IonCode)
 DeclMarkerImpl(Object, ArgumentsObject)
@@ -471,17 +471,17 @@ MarkIdInternal(JSTracer *trc, jsid *id)
         *id = OBJECT_TO_JSID(obj);
     } else {
         /* Unset realLocation manually if we do not call MarkInternal. */
         JS_UNSET_TRACING_LOCATION(trc);
     }
 }
 
 void
-gc::MarkId(JSTracer *trc, EncapsulatedId *id, const char *name)
+gc::MarkId(JSTracer *trc, BarrieredId *id, const char *name)
 {
     JS_SET_TRACING_NAME(trc, name);
     MarkIdInternal(trc, id->unsafeGet());
 }
 
 void
 gc::MarkIdRoot(JSTracer *trc, jsid *id, const char *name)
 {
@@ -532,17 +532,17 @@ MarkValueInternal(JSTracer *trc, Value *
             v->setObjectOrNull((JSObject *)thing);
     } else {
         /* Unset realLocation manually if we do not call MarkInternal. */
         JS_UNSET_TRACING_LOCATION(trc);
     }
 }
 
 void
-gc::MarkValue(JSTracer *trc, EncapsulatedValue *v, const char *name)
+gc::MarkValue(JSTracer *trc, BarrieredValue *v, const char *name)
 {
     JS_SET_TRACING_NAME(trc, name);
     MarkValueInternal(trc, v->unsafeGet());
 }
 
 void
 gc::MarkValueRoot(JSTracer *trc, Value *v, const char *name)
 {
@@ -563,17 +563,17 @@ gc::MarkTypeRoot(JSTracer *trc, types::T
     } else if (v->isTypeObject()) {
         types::TypeObject *typeObj = v->typeObject();
         MarkInternal(trc, &typeObj);
         *v = types::Type::ObjectType(typeObj);
     }
 }
 
 void
-gc::MarkValueRange(JSTracer *trc, size_t len, EncapsulatedValue *vec, const char *name)
+gc::MarkValueRange(JSTracer *trc, size_t len, BarrieredValue *vec, const char *name)
 {
     for (size_t i = 0; i < len; ++i) {
         JS_SET_TRACING_INDEX(trc, name, i);
         MarkValueInternal(trc, vec[i].unsafeGet());
     }
 }
 
 void
@@ -872,17 +872,17 @@ PushMarkStack(GCMarker *gcmarker, BaseSh
 }
 
 static void
 ScanShape(GCMarker *gcmarker, Shape *shape)
 {
   restart:
     PushMarkStack(gcmarker, shape->base());
 
-    const EncapsulatedId &id = shape->propidRef();
+    const BarrieredId &id = shape->propidRef();
     if (JSID_IS_STRING(id))
         PushMarkStack(gcmarker, JSID_TO_STRING(id));
     else if (JS_UNLIKELY(JSID_IS_OBJECT(id)))
         PushMarkStack(gcmarker, JSID_TO_OBJECT(id));
 
     shape = shape->previous();
     if (shape && shape->markIfUnmarked(gcmarker->getMarkColor()))
         goto restart;
--- a/js/src/gc/Marking.h
+++ b/js/src/gc/Marking.h
@@ -76,25 +76,25 @@ namespace gc {
  *     object not in the group of compartments currently being swept, as even if
  *     it is unmarked it may still become marked before it is swept.
  *
  * IsObjectMarked(JSObject **thing);
  *     This function is indended to be used in rare cases in code used to mark
  *     GC things.  It indicates whether the object is currently marked.
  */
 #define DeclMarker(base, type)                                                                    \
-void Mark##base(JSTracer *trc, EncapsulatedPtr<type> *thing, const char *name);                   \
+void Mark##base(JSTracer *trc, BarrieredPtr<type> *thing, const char *name);                   \
 void Mark##base##Root(JSTracer *trc, type **thingp, const char *name);                            \
 void Mark##base##Unbarriered(JSTracer *trc, type **thingp, const char *name);                     \
 void Mark##base##Range(JSTracer *trc, size_t len, HeapPtr<type> *thing, const char *name);        \
 void Mark##base##RootRange(JSTracer *trc, size_t len, type **thing, const char *name);            \
 bool Is##base##Marked(type **thingp);                                                             \
-bool Is##base##Marked(EncapsulatedPtr<type> *thingp);                                             \
+bool Is##base##Marked(BarrieredPtr<type> *thingp);                                             \
 bool Is##base##AboutToBeFinalized(type **thingp);                                                 \
-bool Is##base##AboutToBeFinalized(EncapsulatedPtr<type> *thingp);
+bool Is##base##AboutToBeFinalized(BarrieredPtr<type> *thingp);                                 \
 
 DeclMarker(BaseShape, BaseShape)
 DeclMarker(BaseShape, UnownedBaseShape)
 DeclMarker(IonCode, jit::IonCode)
 DeclMarker(Object, ArgumentsObject)
 DeclMarker(Object, ArrayBufferObject)
 DeclMarker(Object, ArrayBufferViewObject)
 DeclMarker(Object, DebugScopeObject)
@@ -137,37 +137,37 @@ void
 MarkGCThingRoot(JSTracer *trc, void **thingp, const char *name);
 
 void
 MarkGCThingUnbarriered(JSTracer *trc, void **thingp, const char *name);
 
 /*** ID Marking ***/
 
 void
-MarkId(JSTracer *trc, EncapsulatedId *id, const char *name);
+MarkId(JSTracer *trc, BarrieredId *id, const char *name);
 
 void
 MarkIdRoot(JSTracer *trc, jsid *id, const char *name);
 
 void
 MarkIdUnbarriered(JSTracer *trc, jsid *id, const char *name);
 
 void
 MarkIdRange(JSTracer *trc, size_t len, HeapId *vec, const char *name);
 
 void
 MarkIdRootRange(JSTracer *trc, size_t len, jsid *vec, const char *name);
 
 /*** Value Marking ***/
 
 void
-MarkValue(JSTracer *trc, EncapsulatedValue *v, const char *name);
+MarkValue(JSTracer *trc, BarrieredValue *v, const char *name);
 
 void
-MarkValueRange(JSTracer *trc, size_t len, EncapsulatedValue *vec, const char *name);
+MarkValueRange(JSTracer *trc, size_t len, BarrieredValue *vec, const char *name);
 
 inline void
 MarkValueRange(JSTracer *trc, HeapValue *begin, HeapValue *end, const char *name)
 {
     return MarkValueRange(trc, end - begin, begin, name);
 }
 
 void
@@ -254,29 +254,29 @@ PushArena(GCMarker *gcmarker, ArenaHeade
 /*** Generic ***/
 
 /*
  * The Mark() functions interface should only be used by code that must be
  * templated.  Other uses should use the more specific, type-named functions.
  */
 
 inline void
-Mark(JSTracer *trc, EncapsulatedValue *v, const char *name)
+Mark(JSTracer *trc, BarrieredValue *v, const char *name)
 {
     MarkValue(trc, v, name);
 }
 
 inline void
-Mark(JSTracer *trc, EncapsulatedPtrObject *o, const char *name)
+Mark(JSTracer *trc, BarrieredPtrObject *o, const char *name)
 {
     MarkObject(trc, o, name);
 }
 
 inline void
-Mark(JSTracer *trc, EncapsulatedPtrScript *o, const char *name)
+Mark(JSTracer *trc, BarrieredPtrScript *o, const char *name)
 {
     MarkScript(trc, o, name);
 }
 
 inline void
 Mark(JSTracer *trc, HeapPtr<jit::IonCode> *code, const char *name)
 {
     MarkIonCode(trc, code, name);
@@ -298,51 +298,51 @@ Mark(JSTracer *trc, ScopeObject **obj, c
 
 bool
 IsCellMarked(Cell **thingp);
 
 bool
 IsCellAboutToBeFinalized(Cell **thing);
 
 inline bool
-IsMarked(EncapsulatedValue *v)
+IsMarked(BarrieredValue *v)
 {
     if (!v->isMarkable())
         return true;
     return IsValueMarked(v->unsafeGet());
 }
 
 inline bool
-IsMarked(EncapsulatedPtrObject *objp)
+IsMarked(BarrieredPtrObject *objp)
 {
     return IsObjectMarked(objp);
 }
 
 inline bool
-IsMarked(EncapsulatedPtrScript *scriptp)
+IsMarked(BarrieredPtrScript *scriptp)
 {
     return IsScriptMarked(scriptp);
 }
 
 inline bool
-IsAboutToBeFinalized(EncapsulatedValue *v)
+IsAboutToBeFinalized(BarrieredValue *v)
 {
     if (!v->isMarkable())
         return false;
     return IsValueAboutToBeFinalized(v->unsafeGet());
 }
 
 inline bool
-IsAboutToBeFinalized(EncapsulatedPtrObject *objp)
+IsAboutToBeFinalized(BarrieredPtrObject *objp)
 {
     return IsObjectAboutToBeFinalized(objp);
 }
 
 inline bool
-IsAboutToBeFinalized(EncapsulatedPtrScript *scriptp)
+IsAboutToBeFinalized(BarrieredPtrScript *scriptp)
 {
     return IsScriptAboutToBeFinalized(scriptp);
 }
 
 #ifdef JS_ION
 /* Nonsense to get WeakCache to work with new Marking semantics. */
 
 inline bool
--- a/js/src/jit-test/jit_test.py
+++ b/js/src/jit-test/jit_test.py
@@ -191,17 +191,16 @@ def main(argv):
                 job_list.append(new_test)
 
     prefix = [os.path.abspath(args[0])] + shlex.split(options.shell_args)
     prolog = os.path.join(jittests.LIB_DIR, 'prolog.js')
     if options.remote:
         prolog = posixpath.join(options.remote_test_root, 'jit-tests', 'jit-tests', 'lib', 'prolog.js')
 
     prefix += ['-f', prolog]
-    prefix += ['--js-cache', jittests.JS_CACHE_DIR]
 
     # Avoid racing on the cache by having the js shell create a new cache
     # subdir for each process. The js shell takes care of deleting these
     # subdirs when the process exits.
     if options.max_jobs > 1 and jittests.HAVE_MULTIPROCESSING:
         prefix += ['--js-cache-per-process']
 
     # Clean up any remnants from previous crashes etc
--- a/js/src/jit/BacktrackingAllocator.cpp
+++ b/js/src/jit/BacktrackingAllocator.cpp
@@ -363,24 +363,27 @@ BacktrackingAllocator::groupAndQueueRegi
 
         BacktrackingVirtualRegister &reg = vregs[i];
         JS_ASSERT(reg.numIntervals() <= 2);
         JS_ASSERT(!reg.canonicalSpill());
 
         if (!reg.numIntervals())
             continue;
 
+        // Disable this for now; see bugs 906858, 931487, and 932465.
+#if 0
         // Eagerly set the canonical spill slot for registers which are preset
         // for that slot, and reuse it for other registers in the group.
         LDefinition *def = reg.def();
         if (def->policy() == LDefinition::PRESET && !def->output()->isRegister()) {
             reg.setCanonicalSpill(*def->output());
             if (reg.group() && reg.group()->spill.isUse())
                 reg.group()->spill = *def->output();
         }
+#endif
 
         // Place all intervals for this register on the allocation queue.
         // During initial queueing use single queue items for groups of
         // registers, so that they will be allocated together and reduce the
         // risk of unnecessary conflicts. This is in keeping with the idea that
         // register groups are effectively single registers whose value changes
         // during execution. If any intervals in the group are evicted later
         // then they will be reallocated individually.
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -723,30 +723,34 @@ BaselineCompiler::emitSPSPop()
 
 MethodStatus
 BaselineCompiler::emitBody()
 {
     JS_ASSERT(pc == script->code);
 
     bool lastOpUnreachable = false;
     uint32_t emittedOps = 0;
+    mozilla::DebugOnly<jsbytecode *> prevpc = pc;
 
     while (true) {
         JSOp op = JSOp(*pc);
         IonSpew(IonSpew_BaselineOp, "Compiling op @ %d: %s",
                 int(pc - script->code), js_CodeName[op]);
 
         BytecodeInfo *info = analysis_.maybeInfo(pc);
 
         // Skip unreachable ops.
         if (!info) {
-            if (op == JSOP_STOP)
+            // Test if last instructions and stop emitting in that case.
+            pc += GetBytecodeLength(pc);
+            if (pc >= script->code + script->length)
                 break;
-            pc += GetBytecodeLength(pc);
+
             lastOpUnreachable = true;
+            prevpc = pc;
             continue;
         }
 
         // Fully sync the stack if there are incoming jumps.
         if (info->jumpTarget) {
             frame.syncStack(0);
             frame.setStackDepth(info->stackDepth);
         }
@@ -786,25 +790,29 @@ BaselineCompiler::emitBody()
           case OP:                             \
             if (!this->emit_##OP())            \
                 return Method_Error;           \
             break;
 OPCODE_LIST(EMIT_OP)
 #undef EMIT_OP
         }
 
-        if (op == JSOP_STOP)
+        // Test if last instructions and stop emitting in that case.
+        pc += GetBytecodeLength(pc);
+        if (pc >= script->code + script->length)
             break;
 
-        pc += GetBytecodeLength(pc);
         emittedOps++;
         lastOpUnreachable = false;
+#ifdef DEBUG
+        prevpc = pc;
+#endif
     }
 
-    JS_ASSERT(JSOp(*pc) == JSOP_STOP);
+    JS_ASSERT(JSOp(*prevpc) == JSOP_RETRVAL);
     return Method_Compiled;
 }
 
 bool
 BaselineCompiler::emit_JSOP_NOP()
 {
     return true;
 }
@@ -2687,36 +2695,36 @@ BaselineCompiler::emitReturn()
         pushArg(Imm32(1));
         pushArg(R0.scratchReg());
         if (!callVM(DebugEpilogueInfo))
             return false;
 
         masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
     }
 
-    if (JSOp(*pc) != JSOP_STOP) {
-        // JSOP_STOP is immediately followed by the return label, so we don't
-        // need a jump.
+    // Only emit the jump if this JSOP_RETRVAL is not the last instruction.
+    // Not needed for last instruction, because last instruction flows
+    // into return label.
+    if (pc + GetBytecodeLength(pc) < script->code + script->length)
         masm.jump(&return_);
-    }
 
     return true;
 }
 
 bool
 BaselineCompiler::emit_JSOP_RETURN()
 {
     JS_ASSERT(frame.stackDepth() == 1);
 
     frame.popValue(JSReturnOperand);
     return emitReturn();
 }
 
 bool
-BaselineCompiler::emit_JSOP_STOP()
+BaselineCompiler::emit_JSOP_RETRVAL()
 {
     JS_ASSERT(frame.stackDepth() == 0);
 
     masm.moveValue(UndefinedValue(), JSReturnOperand);
 
     if (!script->noScriptRval) {
         // Return the value in the return value slot, if any.
         Label done;
@@ -2724,22 +2732,16 @@ BaselineCompiler::emit_JSOP_STOP()
         masm.branchTest32(Assembler::Zero, flags, Imm32(BaselineFrame::HAS_RVAL), &done);
         masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
         masm.bind(&done);
     }
 
     return emitReturn();
 }
 
-bool
-BaselineCompiler::emit_JSOP_RETRVAL()
-{
-    return emit_JSOP_STOP();
-}
-
 typedef bool (*ToIdFn)(JSContext *, HandleScript, jsbytecode *, HandleValue, HandleValue,
                        MutableHandleValue);
 static const VMFunction ToIdInfo = FunctionInfo<ToIdFn>(js::ToIdOperation);
 
 bool
 BaselineCompiler::emit_JSOP_TOID()
 {
     // Load index in R0, but keep values on the stack for the decompiler.
@@ -2844,22 +2846,16 @@ BaselineCompiler::emit_JSOP_CALLEE()
     JS_ASSERT(function());
     frame.syncStack(0);
     masm.loadPtr(frame.addressOfCallee(), R0.scratchReg());
     masm.tagValue(JSVAL_TYPE_OBJECT, R0.scratchReg(), R0);
     frame.push(R0);
     return true;
 }
 
-bool
-BaselineCompiler::emit_JSOP_POPV()
-{
-    return emit_JSOP_SETRVAL();
-}
-
 typedef bool (*NewArgumentsObjectFn)(JSContext *, BaselineFrame *, MutableHandleValue);
 static const VMFunction NewArgumentsObjectInfo =
     FunctionInfo<NewArgumentsObjectFn>(jit::NewArgumentsObject);
 
 bool
 BaselineCompiler::emit_JSOP_ARGUMENTS()
 {
     frame.syncStack(0);
--- a/js/src/jit/BaselineCompiler.h
+++ b/js/src/jit/BaselineCompiler.h
@@ -159,21 +159,19 @@ namespace jit {
     _(JSOP_REST)               \
     _(JSOP_TOID)               \
     _(JSOP_TABLESWITCH)        \
     _(JSOP_ITER)               \
     _(JSOP_MOREITER)           \
     _(JSOP_ITERNEXT)           \
     _(JSOP_ENDITER)            \
     _(JSOP_CALLEE)             \
-    _(JSOP_POPV)               \
     _(JSOP_SETRVAL)            \
-    _(JSOP_RETURN)             \
-    _(JSOP_STOP)               \
-    _(JSOP_RETRVAL)
+    _(JSOP_RETRVAL)            \
+    _(JSOP_RETURN)
 
 class BaselineCompiler : public BaselineCompilerSpecific
 {
     FixedList<Label>            labels_;
     NonAssertingLabel           return_;
 #ifdef JSGC_GENERATIONAL
     NonAssertingLabel           postBarrierSlot_;
 #endif
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -1217,17 +1217,16 @@ IonBuilder::traverseBytecode()
               case JSOP_POPN:
               case JSOP_DUP:
               case JSOP_DUP2:
               case JSOP_PICK:
               case JSOP_SWAP:
               case JSOP_SETARG:
               case JSOP_SETLOCAL:
               case JSOP_SETRVAL:
-              case JSOP_POPV:
               case JSOP_VOID:
                 // Don't require SSA uses for values popped by these ops.
                 break;
 
               case JSOP_POS:
               case JSOP_TOID:
                 // These ops may leave their input on the stack without setting
                 // the Folded flag. If this value will be popped immediately,
@@ -1266,17 +1265,16 @@ IonBuilder::snoopControlFlow(JSOp op)
     switch (op) {
       case JSOP_NOP:
         return maybeLoop(op, info().getNote(gsn, pc));
 
       case JSOP_POP:
         return maybeLoop(op, info().getNote(gsn, pc));
 
       case JSOP_RETURN:
-      case JSOP_STOP:
       case JSOP_RETRVAL:
         return processReturn(op);
 
       case JSOP_THROW:
         return processThrow();
 
       case JSOP_GOTO:
       {
@@ -1673,17 +1671,16 @@ IonBuilder::inspectOpcode(JSOp op)
 
       case JSOP_ENDITER:
         return jsop_iterend();
 
       case JSOP_IN:
         return jsop_in();
 
       case JSOP_SETRVAL:
-      case JSOP_POPV:
         JS_ASSERT(!script()->noScriptRval);
         current->setSlot(info().returnValueSlot(), current->pop());
         return true;
 
       case JSOP_INSTANCEOF:
         return jsop_instanceof();
 
       default:
@@ -3473,28 +3470,25 @@ IonBuilder::processReturn(JSOp op)
 {
     MDefinition *def;
     switch (op) {
       case JSOP_RETURN:
         // Return the last instruction.
         def = current->pop();
         break;
 
-      case JSOP_STOP:
+      case JSOP_RETRVAL:
         // Return undefined eagerly if script doesn't use return value.
         if (script()->noScriptRval) {
             MInstruction *ins = MConstant::New(UndefinedValue());
             current->add(ins);
             def = ins;
             break;
         }
 
-        // Fall through
-      case JSOP_RETRVAL:
-        // Return the value in the return value slot.
         def = current->getSlot(info().returnValueSlot());
         break;
 
       default:
         def = nullptr;
         MOZ_ASSUME_UNREACHABLE("unknown return op");
     }
 
@@ -5928,28 +5922,35 @@ IonBuilder::maybeInsertResume()
 
     MNop *ins = MNop::New();
     current->add(ins);
 
     return resumeAfter(ins);
 }
 
 static bool
-ClassHasEffectlessLookup(JSCompartment *comp, const Class *clasp, PropertyName *name)
-{
-    if (!clasp->isNative() || clasp->ops.lookupGeneric)
-        return false;
-    if (clasp->resolve != JS_ResolveStub &&
-        // Note: str_resolve only resolves integers, not names.
-        clasp->resolve != (JSResolveOp)str_resolve &&
-        (clasp->resolve != (JSResolveOp)fun_resolve ||
-         FunctionHasResolveHook(comp->runtimeFromAnyThread(), name)))
-    {
-        return false;
-    }
+ClassHasEffectlessLookup(const Class *clasp)
+{
+    return clasp->isNative() && !clasp->ops.lookupGeneric;
+}
+
+static bool
+ClassHasResolveHook(JSCompartment *comp, const Class *clasp, PropertyName *name)
+{
+    if (clasp->resolve == JS_ResolveStub)
+        return false;
+
+    if (clasp->resolve == (JSResolveOp)str_resolve) {
+        // str_resolve only resolves integers, not names.
+        return false;
+    }
+
+    if (clasp->resolve == (JSResolveOp)fun_resolve)
+        return FunctionHasResolveHook(comp->runtimeFromAnyThread(), name);
+
     return true;
 }
 
 bool
 IonBuilder::testSingletonProperty(JSObject *obj, JSObject *singleton, PropertyName *name)
 {
     // We would like to completely no-op property/global accesses which can
     // produce only a particular JSObject. When indicating the access result is
@@ -5961,30 +5962,33 @@ IonBuilder::testSingletonProperty(JSObje
     // If the access definitely goes through obj, either directly or on the
     // prototype chain, and the object has singleton type, then the type
     // information for that property reflects the value that will definitely be
     // read on accesses to the object. If the property is later deleted or
     // reconfigured as a getter/setter then the type information for the
     // property will change and trigger invalidation.
 
     while (obj) {
-        if (!ClassHasEffectlessLookup(compartment, obj->getClass(), name))
+        if (!ClassHasEffectlessLookup(obj->getClass()))
             return false;
 
         types::TypeObjectKey *objType = types::TypeObjectKey::get(obj);
         if (objType->unknownProperties())
             return false;
 
         types::HeapTypeSetKey property = objType->property(NameToId(name), context());
         if (property.isOwnProperty(constraints())) {
             if (obj->hasSingletonType())
                 return property.singleton(constraints()) == singleton;
             return false;
         }
 
+        if (ClassHasResolveHook(compartment, obj->getClass(), name))
+            return false;
+
         obj = obj->getProto();
     }
 
     return false;
 }
 
 bool
 IonBuilder::testSingletonPropertyTypes(MDefinition *obj, JSObject *singleton, PropertyName *name,
@@ -7599,17 +7603,17 @@ IonBuilder::objectsHaveCommonPrototype(t
         if (!type)
             continue;
 
         while (type) {
             if (type->unknownProperties())
                 return false;
 
             const Class *clasp = type->clasp();
-            if (!ClassHasEffectlessLookup(compartment, clasp, name))
+            if (!ClassHasEffectlessLookup(clasp) || ClassHasResolveHook(compartment, clasp, name))
                 return false;
 
             // Look for a getter/setter on the class itself which may need
             // to be called.
             if (isGetter && clasp->ops.getGeneric)
                 return false;
             if (!isGetter && clasp->ops.setGeneric)
                 return false;
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -2013,27 +2013,35 @@ class LNotI : public LInstructionHelper<
 class LNotD : public LInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(NotD)
 
     LNotD(const LAllocation &input) {
         setOperand(0, input);
     }
+
+    MNot *mir() {
+        return mir_->toNot();
+    }
 };
 
 // Not operation on a float32.
 class LNotF : public LInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(NotF)
 
     LNotF(const LAllocation &input) {
         setOperand(0, input);
     }
+
+    MNot *mir() {
+        return mir_->toNot();
+    }
 };
 
 // Boolean complement operation on an object.
 class LNotO : public LInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(NotO)
 
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -2141,22 +2141,24 @@ class MCompare
         // All other possible compares
         Compare_Unknown
     };
 
   private:
     CompareType compareType_;
     JSOp jsop_;
     bool operandMightEmulateUndefined_;
+    bool operandsAreNeverNaN_;
 
     MCompare(MDefinition *left, MDefinition *right, JSOp jsop)
       : MBinaryInstruction(left, right),
         compareType_(Compare_Unknown),
         jsop_(jsop),
-        operandMightEmulateUndefined_(true)
+        operandMightEmulateUndefined_(true),
+        operandsAreNeverNaN_(false)
     {
         setResultType(MIRType_Boolean);
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(Compare)
     static MCompare *New(MDefinition *left, MDefinition *right, JSOp op);
@@ -2190,27 +2192,31 @@ class MCompare
         return this;
     }
     void markNoOperandEmulatesUndefined() {
         operandMightEmulateUndefined_ = false;
     }
     bool operandMightEmulateUndefined() const {
         return operandMightEmulateUndefined_;
     }
+    bool operandsAreNeverNaN() const {
+        return operandsAreNeverNaN_;
+    }
     AliasSet getAliasSet() const {
         // Strict equality is never effectful.
         if (jsop_ == JSOP_STRICTEQ || jsop_ == JSOP_STRICTNE)
             return AliasSet::None();
         if (compareType_ == Compare_Unknown)
             return AliasSet::Store(AliasSet::Any);
         JS_ASSERT(compareType_ <= Compare_Value);
         return AliasSet::None();
     }
 
     void printOpcode(FILE *fp) const;
+    void collectRangeInfo();
 
     void trySpecializeFloat32();
     bool isFloat32Commutative() const { return true; }
 
 # ifdef DEBUG
     bool isConsistentFloat32Use() const {
         return compareType_ == Compare_Float32;
     }
@@ -5148,21 +5154,23 @@ class MTypedObjectElements
 };
 
 // Perform !-operation
 class MNot
   : public MUnaryInstruction,
     public TestPolicy
 {
     bool operandMightEmulateUndefined_;
+    bool operandIsNeverNaN_;
 
   public:
     MNot(MDefinition *input)
       : MUnaryInstruction(input),
-        operandMightEmulateUndefined_(true)
+        operandMightEmulateUndefined_(true),
+        operandIsNeverNaN_(false)
     {
         setResultType(MIRType_Boolean);
         setMovable();
     }
 
     static MNot *New(MDefinition *elements) {
         return new MNot(elements);
     }
@@ -5178,27 +5186,31 @@ class MNot
     MDefinition *foldsTo(bool useValueNumbers);
 
     void markOperandCantEmulateUndefined() {
         operandMightEmulateUndefined_ = false;
     }
     bool operandMightEmulateUndefined() const {
         return operandMightEmulateUndefined_;
     }
+    bool operandIsNeverNaN() const {
+        return operandIsNeverNaN_;
+    }
 
     MDefinition *operand() const {
         return getOperand(0);
     }
 
     virtual AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     TypePolicy *typePolicy() {
         return this;
     }
+    void collectRangeInfo();
 
     void trySpecializeFloat32();
     bool isFloat32Commutative() const { return true; }
 #ifdef DEBUG
     bool isConsistentFloat32Use() const {
         return true;
     }
 #endif
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -18,17 +18,17 @@
 #include "jit/MIRGraph.h"
 #include "vm/NumericConversions.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::Abs;
 using mozilla::CountLeadingZeroes32;
-using mozilla::DoubleIsInt32;
+using mozilla::DoubleEqualsInt32;
 using mozilla::ExponentComponent;
 using mozilla::IsInfinite;
 using mozilla::IsFinite;
 using mozilla::IsNaN;
 using mozilla::IsNegative;
 using mozilla::NegativeInfinity;
 using mozilla::PositiveInfinity;
 using mozilla::Swap;
@@ -201,29 +201,29 @@ RangeAnalysis::addBetaNodes()
         switch (jsop) {
           case JSOP_LE:
             comp.setDouble(conservativeLower, bound);
             break;
           case JSOP_LT:
             // For integers, if x < c, the upper bound of x is c-1.
             if (val->type() == MIRType_Int32) {
                 int32_t intbound;
-                if (DoubleIsInt32(bound, &intbound) && SafeSub(intbound, 1, &intbound))
+                if (DoubleEqualsInt32(bound, &intbound) && SafeSub(intbound, 1, &intbound))
                     bound = intbound;
             }
             comp.setDouble(conservativeLower, bound);
             break;
           case JSOP_GE:
             comp.setDouble(bound, conservativeUpper);
             break;
           case JSOP_GT:
             // For integers, if x > c, the lower bound of x is c+1.
             if (val->type() == MIRType_Int32) {
                 int32_t intbound;
-                if (DoubleIsInt32(bound, &intbound) && SafeAdd(intbound, 1, &intbound))
+                if (DoubleEqualsInt32(bound, &intbound) && SafeAdd(intbound, 1, &intbound))
                     bound = intbound;
             }
             comp.setDouble(bound, conservativeUpper);
             break;
           case JSOP_EQ:
             comp.setDouble(bound, bound);
             break;
           default:
@@ -2402,8 +2402,20 @@ MMod::collectRangeInfo()
 }
 
 void
 MBoundsCheckLower::collectRangeInfo()
 {
     Range indexRange(index());
     fallible_ = !indexRange.hasInt32LowerBound() || indexRange.lower() < minimum_;
 }
+
+void
+MCompare::collectRangeInfo()
+{
+    operandsAreNeverNaN_ = !Range(lhs()).canBeNaN() && !Range(rhs()).canBeNaN();
+}
+
+void
+MNot::collectRangeInfo()
+{
+    operandIsNeverNaN_ = !Range(operand()).canBeNaN();
+}
--- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp
@@ -189,88 +189,116 @@ CodeGeneratorX86Shared::visitCompareAndB
 
 bool
 CodeGeneratorX86Shared::visitCompareD(LCompareD *comp)
 {
     FloatRegister lhs = ToFloatRegister(comp->left());
     FloatRegister rhs = ToFloatRegister(comp->right());
 
     Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->mir()->jsop());
+
+    Assembler::NaNCond nanCond = Assembler::NaNCondFromDoubleCondition(cond);
+    if (comp->mir()->operandsAreNeverNaN())
+        nanCond = Assembler::NaN_HandledByCond;
+
     masm.compareDouble(cond, lhs, rhs);
-    masm.emitSet(Assembler::ConditionFromDoubleCondition(cond), ToRegister(comp->output()),
-            Assembler::NaNCondFromDoubleCondition(cond));
+    masm.emitSet(Assembler::ConditionFromDoubleCondition(cond), ToRegister(comp->output()), nanCond);
     return true;
 }
 
 bool
 CodeGeneratorX86Shared::visitCompareF(LCompareF *comp)
 {
     FloatRegister lhs = ToFloatRegister(comp->left());
     FloatRegister rhs = ToFloatRegister(comp->right());
 
     Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->mir()->jsop());
+
+    Assembler::NaNCond nanCond = Assembler::NaNCondFromDoubleCondition(cond);
+    if (comp->mir()->operandsAreNeverNaN())
+        nanCond = Assembler::NaN_HandledByCond;
+
     masm.compareFloat(cond, lhs, rhs);
-    masm.emitSet(Assembler::ConditionFromDoubleCondition(cond), ToRegister(comp->output()),
-            Assembler::NaNCondFromDoubleCondition(cond));
+    masm.emitSet(Assembler::ConditionFromDoubleCondition(cond), ToRegister(comp->output()), nanCond);
     return true;
 }
 
 bool
 CodeGeneratorX86Shared::visitNotI(LNotI *ins)
 {
     masm.cmpl(ToRegister(ins->input()), Imm32(0));
     masm.emitSet(Assembler::Equal, ToRegister(ins->output()));
     return true;
 }
 
 bool
 CodeGeneratorX86Shared::visitNotD(LNotD *ins)
 {
     FloatRegister opd = ToFloatRegister(ins->input());
 
+    // Not returns true if the input is a NaN. We don't have to worry about
+    // it if we know the input is never NaN though.
+    Assembler::NaNCond nanCond = Assembler::NaN_IsTrue;
+    if (ins->mir()->operandIsNeverNaN())
+        nanCond = Assembler::NaN_HandledByCond;
+
     masm.xorpd(ScratchFloatReg, ScratchFloatReg);
     masm.compareDouble(Assembler::DoubleEqualOrUnordered, opd, ScratchFloatReg);
-    masm.emitSet(Assembler::Equal, ToRegister(ins->output()), Assembler::NaN_IsTrue);
+    masm.emitSet(Assembler::Equal, ToRegister(ins->output()), nanCond);
     return true;
 }
 
 bool
 CodeGeneratorX86Shared::visitNotF(LNotF *ins)
 {
     FloatRegister opd = ToFloatRegister(ins->input());
 
+    // Not returns true if the input is a NaN. We don't have to worry about
+    // it if we know the input is never NaN though.
+    Assembler::NaNCond nanCond = Assembler::NaN_IsTrue;
+    if (ins->mir()->operandIsNeverNaN())
+        nanCond = Assembler::NaN_HandledByCond;
+
     masm.xorps(ScratchFloatReg, ScratchFloatReg);
     masm.compareFloat(Assembler::DoubleEqualOrUnordered, opd, ScratchFloatReg);
-    masm.emitSet(Assembler::Equal, ToRegister(ins->output()), Assembler::NaN_IsTrue);
+    masm.emitSet(Assembler::Equal, ToRegister(ins->output()), nanCond);
     return true;
 }
 
 bool
 CodeGeneratorX86Shared::visitCompareDAndBranch(LCompareDAndBranch *comp)
 {
     FloatRegister lhs = ToFloatRegister(comp->left());
     FloatRegister rhs = ToFloatRegister(comp->right());
 
     Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->mir()->jsop());
+
+    Assembler::NaNCond nanCond = Assembler::NaNCondFromDoubleCondition(cond);
+    if (comp->mir()->operandsAreNeverNaN())
+        nanCond = Assembler::NaN_HandledByCond;
+
     masm.compareDouble(cond, lhs, rhs);
-    emitBranch(Assembler::ConditionFromDoubleCondition(cond), comp->ifTrue(), comp->ifFalse(),
-               Assembler::NaNCondFromDoubleCondition(cond));
+    emitBranch(Assembler::ConditionFromDoubleCondition(cond), comp->ifTrue(), comp->ifFalse(), nanCond);
     return true;
 }
 
 bool
 CodeGeneratorX86Shared::visitCompareFAndBranch(LCompareFAndBranch *comp)
 {
     FloatRegister lhs = ToFloatRegister(comp->left());
     FloatRegister rhs = ToFloatRegister(comp->right());
 
     Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->mir()->jsop());
+
+    Assembler::NaNCond nanCond = Assembler::NaNCondFromDoubleCondition(cond);
+    if (comp->mir()->operandsAreNeverNaN())
+        nanCond = Assembler::NaN_HandledByCond;
+
     masm.compareFloat(cond, lhs, rhs);
-    emitBranch(Assembler::ConditionFromDoubleCondition(cond), comp->ifTrue(), comp->ifFalse(),
-               Assembler::NaNCondFromDoubleCondition(cond));
+    emitBranch(Assembler::ConditionFromDoubleCondition(cond), comp->ifTrue(), comp->ifFalse(), nanCond);
     return true;
 }
 
 bool
 CodeGeneratorX86Shared::visitAsmJSPassStackArg(LAsmJSPassStackArg *ins)
 {
     const MAsmJSPassStackArg *mir = ins->mir();
     Address dst(StackPointer, mir->spOffset());
--- a/js/src/jsanalyze.cpp
+++ b/js/src/jsanalyze.cpp
@@ -222,17 +222,17 @@ ScriptAnalysis::analyzeBytecode(JSContex
 
         JS_ASSERT(stackDepth >= nuses);
         stackDepth -= nuses;
         stackDepth += ndefs;
 
         switch (op) {
 
           case JSOP_RETURN:
-          case JSOP_STOP:
+          case JSOP_RETRVAL:
             numReturnSites_++;
             break;
 
           case JSOP_NAME:
           case JSOP_CALLNAME:
           case JSOP_BINDNAME:
           case JSOP_SETNAME:
           case JSOP_DELNAME:
@@ -1216,17 +1216,16 @@ ScriptAnalysis::analyzeSSA(JSContext *cx
                     }
                 }
             }
             break;
           }
 
           case JSOP_THROW:
           case JSOP_RETURN:
-          case JSOP_STOP:
           case JSOP_RETRVAL:
             mergeAllExceptionTargets(cx, values, exceptionTargets);
             break;
 
           default:;
         }
 
         if (IsJumpOpcode(op)) {
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -240,31 +240,28 @@ JS_ConvertArgumentsVA(JSContext *cx, uns
             break;
         }
         RootedValue arg(cx, *sp);
         switch (c) {
           case 'b':
             *va_arg(ap, bool *) = ToBoolean(*sp);
             break;
           case 'c':
-            if (!JS_ValueToUint16(cx, *sp, va_arg(ap, uint16_t *)))
+            if (!ToUint16(cx, arg, va_arg(ap, uint16_t *)))
                 return false;
             break;
           case 'i':
+          case 'j': // "j" was broken, you should not use it.
             if (!ToInt32(cx, arg, va_arg(ap, int32_t *)))
                 return false;
             break;
           case 'u':
             if (!ToUint32(cx, arg, va_arg(ap, uint32_t *)))
                 return false;
             break;
-          case 'j':
-            if (!JS_ValueToInt32(cx, *sp, va_arg(ap, int32_t *)))
-                return false;
-            break;
           case 'd':
             if (!ToNumber(cx, arg, va_arg(ap, double *)))
                 return false;
             break;
           case 'I':
             if (!ToNumber(cx, arg, &d))
                 return false;
             *va_arg(ap, double *) = ToInteger(d);
@@ -443,68 +440,16 @@ JS_DoubleToInt32(double d)
 
 JS_PUBLIC_API(uint32_t)
 JS_DoubleToUint32(double d)
 {
     return