Merge mozilla-central to autoland. a=merge CLOSED TREE
authorNarcis Beleuzu <nbeleuzu@mozilla.com>
Wed, 06 Jun 2018 20:04:08 +0300
changeset 421625 f962de7415dbe37ae58c0bc8ad32e47ee1b186aa
parent 421624 52ef9348401dd27c93b5954b067503ac1634a475 (current diff)
parent 421595 04cc917f68c5d554e5b9542cb3745c9453bba58d (diff)
child 421626 6d5d80cfaaae6c787d67ac508eba04d2d77de689
push id34099
push userncsoregi@mozilla.com
push dateWed, 06 Jun 2018 22:00:08 +0000
treeherdermozilla-central@1ab062fd31db [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone62.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 mozilla-central to autoland. a=merge CLOSED TREE
layout/reftests/css-break/reftest.list
layout/xul/tree/nsITreeColumns.idl
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1253064 - Prefer Clang to GCC in local developer builds
+Bug 1459785 - ANGLE update; moved files require clobber due to bug 1421146.
--- a/accessible/base/nsCoreUtils.cpp
+++ b/accessible/base/nsCoreUtils.cpp
@@ -65,17 +65,17 @@ nsCoreUtils::HasClickListener(nsIContent
   return listenerManager &&
     (listenerManager->HasListenersFor(nsGkAtoms::onclick) ||
      listenerManager->HasListenersFor(nsGkAtoms::onmousedown) ||
      listenerManager->HasListenersFor(nsGkAtoms::onmouseup));
 }
 
 void
 nsCoreUtils::DispatchClickEvent(nsITreeBoxObject *aTreeBoxObj,
-                                int32_t aRowIndex, nsITreeColumn *aColumn,
+                                int32_t aRowIndex, nsTreeColumn *aColumn,
                                 const nsAString& aPseudoElt)
 {
   RefPtr<dom::Element> tcElm;
   aTreeBoxObj->GetTreeBody(getter_AddRefs(tcElm));
   if (!tcElm)
     return;
 
   nsIDocument *document = tcElm->GetUncomposedDoc();
@@ -514,17 +514,17 @@ nsCoreUtils::GetTreeBoxObject(nsIContent
         return treeBox.forget();
     }
     currentContent = currentContent->GetFlattenedTreeParent();
   }
 
   return nullptr;
 }
 
-already_AddRefed<nsITreeColumn>
+already_AddRefed<nsTreeColumn>
 nsCoreUtils::GetFirstSensibleColumn(nsITreeBoxObject *aTree)
 {
   RefPtr<nsTreeColumns> cols;
   aTree->GetColumns(getter_AddRefs(cols));
   if (!cols)
     return nullptr;
 
   RefPtr<nsTreeColumn> column = cols->GetFirstColumn();
@@ -551,68 +551,61 @@ nsCoreUtils::GetSensibleColumnCount(nsIT
       count++;
 
     column = column->GetNext();
   }
 
   return count;
 }
 
-already_AddRefed<nsITreeColumn>
+already_AddRefed<nsTreeColumn>
 nsCoreUtils::GetSensibleColumnAt(nsITreeBoxObject *aTree, uint32_t aIndex)
 {
   uint32_t idx = aIndex;
 
-  nsCOMPtr<nsITreeColumn> column = GetFirstSensibleColumn(aTree);
+  nsCOMPtr<nsTreeColumn> column = GetFirstSensibleColumn(aTree);
   while (column) {
     if (idx == 0)
       return column.forget();
 
     idx--;
     column = GetNextSensibleColumn(column);
   }
 
   return nullptr;
 }
 
-already_AddRefed<nsITreeColumn>
-nsCoreUtils::GetNextSensibleColumn(nsITreeColumn *aColumn)
+already_AddRefed<nsTreeColumn>
+nsCoreUtils::GetNextSensibleColumn(nsTreeColumn* aColumn)
 {
-  nsCOMPtr<nsITreeColumn> nextColumn;
-  aColumn->GetNext(getter_AddRefs(nextColumn));
+  RefPtr<nsTreeColumn> nextColumn = aColumn->GetNext();
 
   while (nextColumn && IsColumnHidden(nextColumn)) {
-    nsCOMPtr<nsITreeColumn> tempColumn;
-    nextColumn->GetNext(getter_AddRefs(tempColumn));
-    nextColumn.swap(tempColumn);
+    nextColumn = nextColumn->GetNext();
   }
 
   return nextColumn.forget();
 }
 
-already_AddRefed<nsITreeColumn>
-nsCoreUtils::GetPreviousSensibleColumn(nsITreeColumn *aColumn)
+already_AddRefed<nsTreeColumn>
+nsCoreUtils::GetPreviousSensibleColumn(nsTreeColumn* aColumn)
 {
-  nsCOMPtr<nsITreeColumn> prevColumn;
-  aColumn->GetPrevious(getter_AddRefs(prevColumn));
+  RefPtr<nsTreeColumn> prevColumn = aColumn->GetPrevious();
 
   while (prevColumn && IsColumnHidden(prevColumn)) {
-    nsCOMPtr<nsITreeColumn> tempColumn;
-    prevColumn->GetPrevious(getter_AddRefs(tempColumn));
-    prevColumn.swap(tempColumn);
+    prevColumn = prevColumn->GetPrevious();
   }
 
   return prevColumn.forget();
 }
 
 bool
-nsCoreUtils::IsColumnHidden(nsITreeColumn *aColumn)
+nsCoreUtils::IsColumnHidden(nsTreeColumn* aColumn)
 {
-  RefPtr<Element> element;
-  aColumn->GetElement(getter_AddRefs(element));
+  Element* element = aColumn->Element();
   return element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidden,
                               nsGkAtoms::_true, eCaseMatters);
 }
 
 void
 nsCoreUtils::ScrollTo(nsIPresShell* aPresShell, nsIContent* aContent,
                       uint32_t aScrollType)
 {
--- a/accessible/base/nsCoreUtils.h
+++ b/accessible/base/nsCoreUtils.h
@@ -12,20 +12,20 @@
 #include "nsIContent.h"
 #include "nsIDocument.h" // for GetShell()
 #include "nsIPresShell.h"
 
 #include "nsPoint.h"
 #include "nsTArray.h"
 
 class nsRange;
+class nsTreeColumn;
 class nsIBoxObject;
 class nsIFrame;
 class nsIDocShell;
-class nsITreeColumn;
 class nsITreeBoxObject;
 class nsIWidget;
 
 /**
  * Core utils.
  */
 class nsCoreUtils
 {
@@ -46,17 +46,17 @@ public:
    *
    * @param  aTreeBoxObj  [in] tree box object
    * @param  aRowIndex    [in] row index
    * @param  aColumn      [in] column object
    * @param  aPseudoElm   [in] pseudo elemenet inside the cell, see
    *                       nsITreeBoxObject for available values
    */
   static void DispatchClickEvent(nsITreeBoxObject *aTreeBoxObj,
-                                 int32_t aRowIndex, nsITreeColumn *aColumn,
+                                 int32_t aRowIndex, nsTreeColumn *aColumn,
                                  const nsAString& aPseudoElt = EmptyString());
 
   /**
    * Send mouse event to the given element.
    *
    * @param aMessage     [in] an event message (see EventForwards.h)
    * @param aX           [in] x coordinate in dev pixels
    * @param aY           [in] y coordinate in dev pixels
@@ -244,46 +244,46 @@ public:
    * Return tree box object from any levels DOMNode under the XUL tree.
    */
   static already_AddRefed<nsITreeBoxObject>
     GetTreeBoxObject(nsIContent* aContent);
 
   /**
    * Return first sensible column for the given tree box object.
    */
-  static already_AddRefed<nsITreeColumn>
+  static already_AddRefed<nsTreeColumn>
     GetFirstSensibleColumn(nsITreeBoxObject *aTree);
 
   /**
    * Return sensible columns count for the given tree box object.
    */
   static uint32_t GetSensibleColumnCount(nsITreeBoxObject *aTree);
 
   /**
    * Return sensible column at the given index for the given tree box object.
    */
-  static already_AddRefed<nsITreeColumn>
+  static already_AddRefed<nsTreeColumn>
     GetSensibleColumnAt(nsITreeBoxObject *aTree, uint32_t aIndex);
 
   /**
    * Return next sensible column for the given column.
    */
-  static already_AddRefed<nsITreeColumn>
-    GetNextSensibleColumn(nsITreeColumn *aColumn);
+  static already_AddRefed<nsTreeColumn>
+    GetNextSensibleColumn(nsTreeColumn *aColumn);
 
   /**
    * Return previous sensible column for the given column.
    */
-  static already_AddRefed<nsITreeColumn>
-    GetPreviousSensibleColumn(nsITreeColumn *aColumn);
+  static already_AddRefed<nsTreeColumn>
+    GetPreviousSensibleColumn(nsTreeColumn *aColumn);
 
   /**
    * Return true if the given column is hidden (i.e. not sensible).
    */
-  static bool IsColumnHidden(nsITreeColumn *aColumn);
+  static bool IsColumnHidden(nsTreeColumn *aColumn);
 
   /**
    * Scroll content into view.
    */
   static void ScrollTo(nsIPresShell* aPresShell, nsIContent* aContent,
                        uint32_t aScrollType);
 
   /**
--- a/accessible/tests/mochitest/jsat/a11y.ini
+++ b/accessible/tests/mochitest/jsat/a11y.ini
@@ -2,17 +2,16 @@
 support-files =
   jsatcommon.js
   output.js
   doc_traversal.html
   doc_content_integration.html
   doc_content_text.html
   !/accessible/tests/mochitest/*.js
   !/accessible/tests/mochitest/moz.png
-skip-if = (os == 'win' && (os_version == '5.1' || os_version == '5.2'))
 
 [test_alive.html]
 [test_content_integration.html]
 [test_explicit_names.html]
 [test_hints.html]
 [test_landmarks.html]
 [test_live_regions.html]
 [test_output_mathml.html]
--- a/accessible/windows/msaa/XULTreeGridAccessibleWrap.h
+++ b/accessible/windows/msaa/XULTreeGridAccessibleWrap.h
@@ -47,17 +47,17 @@ class XULTreeGridCellAccessibleWrap : pu
   ~XULTreeGridCellAccessibleWrap() {}
 
 public:
   XULTreeGridCellAccessibleWrap(nsIContent* aContent,
                                 DocAccessible* aDoc,
                                 XULTreeGridRowAccessible* aRowAcc,
                                 nsITreeBoxObject* aTree,
                                 nsITreeView* aTreeView,
-                                int32_t aRow, nsITreeColumn* aColumn) :
+                                int32_t aRow, nsTreeColumn* aColumn) :
     XULTreeGridCellAccessible(aContent, aDoc, aRowAcc, aTree, aTreeView, aRow,
                               aColumn), ia2AccessibleTableCell(this) {}
 
   // IUnknown
   DECL_IUNKNOWN_INHERITED
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
--- a/accessible/xul/XULTreeAccessible.cpp
+++ b/accessible/xul/XULTreeAccessible.cpp
@@ -189,17 +189,17 @@ XULTreeAccessible::ChildAtPoint(int32_t 
   NS_ENSURE_TRUE(rootFrame, nullptr);
 
   CSSIntRect rootRect = rootFrame->GetScreenRect();
 
   int32_t clientX = presContext->DevPixelsToIntCSSPixels(aX) - rootRect.X();
   int32_t clientY = presContext->DevPixelsToIntCSSPixels(aY) - rootRect.Y();
 
   int32_t row = -1;
-  nsCOMPtr<nsITreeColumn> column;
+  RefPtr<nsTreeColumn> column;
   nsAutoString childEltUnused;
   mTree->GetCellAt(clientX, clientY, &row, getter_AddRefs(column),
                    childEltUnused);
 
   // If we failed to find tree cell for the given point then it might be
   // tree columns.
   if (row == -1 || !column)
     return AccessibleWrap::ChildAtPoint(aX, aY, aWhichChild);
@@ -719,17 +719,17 @@ XULTreeItemAccessibleBase::BoundsInCSSPi
   // Get x coordinate and width from treechildren element, get y coordinate and
   // height from tree cell.
 
   nsCOMPtr<nsIBoxObject> boxObj = nsCoreUtils::GetTreeBodyBoxObject(mTree);
   if (!boxObj) {
     return nsIntRect();
   }
 
-  nsCOMPtr<nsITreeColumn> column = nsCoreUtils::GetFirstSensibleColumn(mTree);
+  RefPtr<nsTreeColumn> column = nsCoreUtils::GetFirstSensibleColumn(mTree);
 
   int32_t x = 0, y = 0, width = 0, height = 0;
   nsresult rv = mTree->GetCoordsForCellItem(mRow, column, EmptyString(),
                                             &x, &y, &width, &height);
   if (NS_FAILED(rv)) {
     return nsIntRect();
   }
 
@@ -1034,17 +1034,17 @@ XULTreeItemAccessibleBase::IsExpandable(
       }
     }
   }
 
   return false;
 }
 
 void
-XULTreeItemAccessibleBase::GetCellName(nsITreeColumn* aColumn, nsAString& aName) const
+XULTreeItemAccessibleBase::GetCellName(nsTreeColumn* aColumn, nsAString& aName) const
 {
 
   mTreeView->GetCellText(mRow, aColumn, aName);
 
   // If there is still no name try the cell value:
   // This is for graphical cells. We need tree/table view implementors to
   // implement FooView::GetCellValue to return a meaningful string for cases
   // where there is something shown in the cell (non-text) such as a star icon;
--- a/accessible/xul/XULTreeAccessible.h
+++ b/accessible/xul/XULTreeAccessible.h
@@ -6,17 +6,17 @@
 #ifndef mozilla_a11y_XULTreeAccessible_h__
 #define mozilla_a11y_XULTreeAccessible_h__
 
 #include "nsITreeBoxObject.h"
 #include "nsITreeView.h"
 #include "XULListboxAccessible.h"
 
 class nsTreeBodyFrame;
-class nsITreeColumn;
+class nsTreeColumn;
 
 namespace mozilla {
 namespace a11y {
 
 class XULTreeGridCellAccessible;
 
 /*
  * A class the represents the XUL Tree widget.
@@ -172,17 +172,17 @@ public:
    * Return row index associated with the accessible.
    */
   int32_t GetRowIndex() const { return mRow; }
 
   /**
    * Return cell accessible for the given column. If XUL tree accessible is not
    * accessible table then return null.
    */
-  virtual XULTreeGridCellAccessible* GetCellAccessible(nsITreeColumn* aColumn) const
+  virtual XULTreeGridCellAccessible* GetCellAccessible(nsTreeColumn* aColumn) const
     { return nullptr; }
 
   /**
    * Proccess row invalidation. Used to fires name change events.
    */
   virtual void RowInvalidated(int32_t aStartColIdx, int32_t aEndColIdx) = 0;
 
 protected:
@@ -201,17 +201,17 @@ protected:
   /**
    * Return true if the tree item accessible is expandable (contains subrows).
    */
   bool IsExpandable() const;
 
   /**
    * Return name for cell at the given column.
    */
-  void GetCellName(nsITreeColumn* aColumn, nsAString& aName) const;
+  void GetCellName(nsTreeColumn* aColumn, nsAString& aName) const;
 
   nsCOMPtr<nsITreeBoxObject> mTree;
   nsITreeView* mTreeView;
   int32_t mRow;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(XULTreeItemAccessibleBase,
                               XULTREEITEMBASEACCESSIBLE_IMPL_CID)
@@ -239,17 +239,17 @@ public:
 
   // XULTreeItemAccessibleBase
   virtual void RowInvalidated(int32_t aStartColIdx, int32_t aEndColIdx) override;
 
 protected:
   virtual ~XULTreeItemAccessible();
 
   // XULTreeItemAccessible
-  nsCOMPtr<nsITreeColumn> mColumn;
+  RefPtr<nsTreeColumn> mColumn;
   nsString mCachedName;
 };
 
 
 /**
  * Accessible class for columns element of XUL tree.
  */
 class XULTreeColumAccessible : public XULColumAccessible
--- a/accessible/xul/XULTreeGridAccessible.cpp
+++ b/accessible/xul/XULTreeGridAccessible.cpp
@@ -17,16 +17,17 @@
 #include "nsTreeColumns.h"
 
 #include "nsIBoxObject.h"
 #include "nsIMutableArray.h"
 #include "nsIPersistentProperties2.h"
 #include "nsITreeSelection.h"
 #include "nsComponentManagerUtils.h"
 #include "mozilla/dom/Element.h"
+#include "mozilla/dom/TreeColumnBinding.h"
 
 using namespace mozilla::a11y;
 using namespace mozilla;
 
 XULTreeGridAccessible::~XULTreeGridAccessible()
 {
 }
 
@@ -121,17 +122,17 @@ XULTreeGridAccessible::SelectedRowIndice
 
 Accessible*
 XULTreeGridAccessible::CellAt(uint32_t aRowIndex, uint32_t aColumnIndex)
 {
   Accessible* row = GetTreeItemAccessible(aRowIndex);
   if (!row)
     return nullptr;
 
-  nsCOMPtr<nsITreeColumn> column =
+  RefPtr<nsTreeColumn> column =
     nsCoreUtils::GetSensibleColumnAt(mTree, aColumnIndex);
   if (!column)
     return nullptr;
 
   RefPtr<XULTreeItemAccessibleBase> rowAcc = do_QueryObject(row);
   if (!rowAcc)
     return nullptr;
 
@@ -293,17 +294,17 @@ XULTreeGridRowAccessible::NativeRole() c
 }
 
 ENameValueFlag
 XULTreeGridRowAccessible::Name(nsString& aName) const
 {
   aName.Truncate();
 
   // XXX: the row name sholdn't be a concatenation of cell names (bug 664384).
-  nsCOMPtr<nsITreeColumn> column = nsCoreUtils::GetFirstSensibleColumn(mTree);
+  RefPtr<nsTreeColumn> column = nsCoreUtils::GetFirstSensibleColumn(mTree);
   while (column) {
     if (!aName.IsEmpty())
       aName.Append(' ');
 
     nsAutoString cellName;
     GetCellName(column, cellName);
     aName.Append(cellName);
 
@@ -328,17 +329,17 @@ XULTreeGridRowAccessible::ChildAtPoint(i
   NS_ENSURE_TRUE(rootFrame, nullptr);
 
   CSSIntRect rootRect = rootFrame->GetScreenRect();
 
   int32_t clientX = presContext->DevPixelsToIntCSSPixels(aX) - rootRect.X();
   int32_t clientY = presContext->DevPixelsToIntCSSPixels(aY) - rootRect.Y();
 
   int32_t row = -1;
-  nsCOMPtr<nsITreeColumn> column;
+  RefPtr<nsTreeColumn> column;
   nsAutoString childEltUnused;
   mTree->GetCellAt(clientX, clientY, &row, getter_AddRefs(column),
                    childEltUnused);
 
   // Return if we failed to find tree cell in the row for the given point.
   if (row != mRow || !column)
     return nullptr;
 
@@ -346,17 +347,17 @@ XULTreeGridRowAccessible::ChildAtPoint(i
 }
 
 Accessible*
 XULTreeGridRowAccessible::GetChildAt(uint32_t aIndex) const
 {
   if (IsDefunct())
     return nullptr;
 
-  nsCOMPtr<nsITreeColumn> column =
+  RefPtr<nsTreeColumn> column =
     nsCoreUtils::GetSensibleColumnAt(mTree, aIndex);
   if (!column)
     return nullptr;
 
   return GetCellAccessible(column);
 }
 
 uint32_t
@@ -364,17 +365,17 @@ XULTreeGridRowAccessible::ChildCount() c
 {
   return nsCoreUtils::GetSensibleColumnCount(mTree);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULTreeGridRowAccessible: XULTreeItemAccessibleBase implementation
 
 XULTreeGridCellAccessible*
-XULTreeGridRowAccessible::GetCellAccessible(nsITreeColumn* aColumn) const
+XULTreeGridRowAccessible::GetCellAccessible(nsTreeColumn* aColumn) const
 {
   MOZ_ASSERT(aColumn, "No tree column!");
 
   void* key = static_cast<void*>(aColumn);
   XULTreeGridCellAccessible* cachedCell = mAccessibleCache.GetWeak(key);
   if (cachedCell)
     return cachedCell;
 
@@ -415,29 +416,27 @@ XULTreeGridRowAccessible::RowInvalidated
 ////////////////////////////////////////////////////////////////////////////////
 // XULTreeGridCellAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 XULTreeGridCellAccessible::
   XULTreeGridCellAccessible(nsIContent* aContent, DocAccessible* aDoc,
                             XULTreeGridRowAccessible* aRowAcc,
                             nsITreeBoxObject* aTree, nsITreeView* aTreeView,
-                            int32_t aRow, nsITreeColumn* aColumn) :
+                            int32_t aRow, nsTreeColumn* aColumn) :
   LeafAccessible(aContent, aDoc), mTree(aTree),
   mTreeView(aTreeView), mRow(aRow), mColumn(aColumn)
 {
   mParent = aRowAcc;
   mStateFlags |= eSharedNode;
   mGenericTypes |= eTableCell;
 
   NS_ASSERTION(mTreeView, "mTreeView is null");
 
-  int16_t type = -1;
-  mColumn->GetType(&type);
-  if (type == nsITreeColumn::TYPE_CHECKBOX)
+  if (mColumn->Type() == dom::TreeColumnBinding::TYPE_CHECKBOX)
     mTreeView->GetCellValue(mRow, mColumn, mCachedTextEquiv);
   else
     mTreeView->GetCellText(mRow, mColumn, mCachedTextEquiv);
 }
 
 XULTreeGridCellAccessible::~XULTreeGridCellAccessible()
 {
 }
@@ -531,72 +530,62 @@ XULTreeGridCellAccessible::BoundsInAppUn
                 presContext->CSSPixelsToAppUnits(bounds.Y()),
                 presContext->CSSPixelsToAppUnits(bounds.Width()),
                 presContext->CSSPixelsToAppUnits(bounds.Height()));
 }
 
 uint8_t
 XULTreeGridCellAccessible::ActionCount() const
 {
-  bool isCycler = false;
-  mColumn->GetCycler(&isCycler);
-  if (isCycler)
+  if (mColumn->Cycler())
     return 1;
 
-  int16_t type;
-  mColumn->GetType(&type);
-  if (type == nsITreeColumn::TYPE_CHECKBOX && IsEditable())
+  if (mColumn->Type() == dom::TreeColumnBinding::TYPE_CHECKBOX && IsEditable())
     return 1;
 
   return 0;
 }
 
 void
 XULTreeGridCellAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
 {
   aName.Truncate();
 
   if (aIndex != eAction_Click || !mTreeView)
     return;
 
-  bool isCycler = false;
-  mColumn->GetCycler(&isCycler);
-  if (isCycler) {
+  if (mColumn->Cycler()) {
     aName.AssignLiteral("cycle");
     return;
   }
 
-  int16_t type = 0;
-  mColumn->GetType(&type);
-  if (type == nsITreeColumn::TYPE_CHECKBOX && IsEditable()) {
+  if (mColumn->Type() == dom::TreeColumnBinding::TYPE_CHECKBOX &&
+      IsEditable()) {
     nsAutoString value;
     mTreeView->GetCellValue(mRow, mColumn, value);
     if (value.EqualsLiteral("true"))
       aName.AssignLiteral("uncheck");
     else
       aName.AssignLiteral("check");
   }
 }
 
 bool
 XULTreeGridCellAccessible::DoAction(uint8_t aIndex) const
 {
   if (aIndex != eAction_Click)
     return false;
 
-  bool isCycler = false;
-  mColumn->GetCycler(&isCycler);
-  if (isCycler) {
+  if (mColumn->Cycler()) {
     DoCommand();
     return true;
   }
 
-  int16_t type;
-  mColumn->GetType(&type);
-  if (type == nsITreeColumn::TYPE_CHECKBOX && IsEditable()) {
+  if (mColumn->Type() == dom::TreeColumnBinding::TYPE_CHECKBOX &&
+      IsEditable()) {
     DoCommand();
     return true;
   }
 
   return false;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -611,34 +600,33 @@ XULTreeGridCellAccessible::Table() const
 
   return nullptr;
 }
 
 uint32_t
 XULTreeGridCellAccessible::ColIdx() const
 {
   uint32_t colIdx = 0;
-  nsCOMPtr<nsITreeColumn> column = mColumn;
+  RefPtr<nsTreeColumn> column = mColumn;
   while ((column = nsCoreUtils::GetPreviousSensibleColumn(column)))
     colIdx++;
 
   return colIdx;
 }
 
 uint32_t
 XULTreeGridCellAccessible::RowIdx() const
 {
   return mRow;
 }
 
 void
 XULTreeGridCellAccessible::ColHeaderCells(nsTArray<Accessible*>* aHeaderCells)
 {
-  RefPtr<dom::Element> columnElm;
-  mColumn->GetElement(getter_AddRefs(columnElm));
+  dom::Element* columnElm = mColumn->Element();
 
   Accessible* headerCell = mDoc->GetAccessible(columnElm);
   if (headerCell)
     aHeaderCells->AppendElement(headerCell);
 }
 
 bool
 XULTreeGridCellAccessible::Selected()
@@ -666,19 +654,17 @@ XULTreeGridCellAccessible::NativeAttribu
   if (!table)
     return attributes.forget();
 
   nsAutoString stringIdx;
   stringIdx.AppendInt(table->CellIndexAt(mRow, ColIdx()));
   nsAccUtils::SetAccAttr(attributes, nsGkAtoms::tableCellIndex, stringIdx);
 
   // "cycles" attribute
-  bool isCycler = false;
-  nsresult rv = mColumn->GetCycler(&isCycler);
-  if (NS_SUCCEEDED(rv) && isCycler)
+  if (mColumn->Cycler())
     nsAccUtils::SetAccAttr(attributes, nsGkAtoms::cycles,
                            NS_LITERAL_STRING("true"));
 
   return attributes.forget();
 }
 
 role
 XULTreeGridCellAccessible::NativeRole() const
@@ -700,19 +686,17 @@ XULTreeGridCellAccessible::NativeState()
   if (selection) {
     bool isSelected = false;
     selection->IsSelected(mRow, &isSelected);
     if (isSelected)
       states |= states::SELECTED;
   }
 
   // checked state
-  int16_t type;
-  mColumn->GetType(&type);
-  if (type == nsITreeColumn::TYPE_CHECKBOX) {
+  if (mColumn->Type() == dom::TreeColumnBinding::TYPE_CHECKBOX) {
     states |= states::CHECKABLE;
     nsAutoString checked;
     mTreeView->GetCellValue(mRow, mColumn, checked);
     if (checked.EqualsIgnoreCase("true"))
       states |= states::CHECKED;
   }
 
   return states;
@@ -740,19 +724,17 @@ XULTreeGridCellAccessible::RelationByTyp
 // XULTreeGridCellAccessible: public implementation
 
 bool
 XULTreeGridCellAccessible::CellInvalidated()
 {
 
   nsAutoString textEquiv;
 
-  int16_t type;
-  mColumn->GetType(&type);
-  if (type == nsITreeColumn::TYPE_CHECKBOX) {
+  if (mColumn->Type() == dom::TreeColumnBinding::TYPE_CHECKBOX) {
     mTreeView->GetCellValue(mRow, mColumn, textEquiv);
     if (mCachedTextEquiv != textEquiv) {
       bool isEnabled = textEquiv.EqualsLiteral("true");
       RefPtr<AccEvent> accEvent =
         new AccStateChangeEvent(this, states::CHECKED, isEnabled);
       nsEventShell::FireEvent(accEvent);
 
       mCachedTextEquiv = textEquiv;
@@ -777,17 +759,17 @@ XULTreeGridCellAccessible::CellInvalidat
 
 Accessible*
 XULTreeGridCellAccessible::GetSiblingAtOffset(int32_t aOffset,
                                               nsresult* aError) const
 {
   if (aError)
     *aError =  NS_OK; // fail peacefully
 
-  nsCOMPtr<nsITreeColumn> columnAtOffset(mColumn), column;
+  RefPtr<nsTreeColumn> columnAtOffset(mColumn), column;
   if (aOffset < 0) {
     for (int32_t index = aOffset; index < 0 && columnAtOffset; index++) {
       column = nsCoreUtils::GetPreviousSensibleColumn(columnAtOffset);
       column.swap(columnAtOffset);
     }
   } else {
     for (int32_t index = aOffset; index > 0 && columnAtOffset; index--) {
       column = nsCoreUtils::GetNextSensibleColumn(columnAtOffset);
@@ -821,20 +803,17 @@ XULTreeGridCellAccessible::IsEditable() 
 
   // XXX: logic corresponds to tree.xml, it's preferable to have interface
   // method to check it.
   bool isEditable = false;
   nsresult rv = mTreeView->IsEditable(mRow, mColumn, &isEditable);
   if (NS_FAILED(rv) || !isEditable)
     return false;
 
-  RefPtr<dom::Element> columnElm;
-  mColumn->GetElement(getter_AddRefs(columnElm));
-  if (!columnElm)
-    return false;
+  dom::Element* columnElm = mColumn->Element();
 
   if (!columnElm->AttrValueIs(kNameSpaceID_None,
                               nsGkAtoms::editable,
                               nsGkAtoms::_true,
                               eCaseMatters))
     return false;
 
   return mContent->AsElement()->AttrValueIs(kNameSpaceID_None,
--- a/accessible/xul/XULTreeGridAccessible.h
+++ b/accessible/xul/XULTreeGridAccessible.h
@@ -85,17 +85,17 @@ public:
   virtual ENameValueFlag Name(nsString& aName) const override;
   virtual Accessible* ChildAtPoint(int32_t aX, int32_t aY,
                                    EWhichChildAtPoint aWhichChild) override;
 
   virtual Accessible* GetChildAt(uint32_t aIndex) const override;
   virtual uint32_t ChildCount() const override;
 
   // XULTreeItemAccessibleBase
-  XULTreeGridCellAccessible* GetCellAccessible(nsITreeColumn* aColumn)
+  XULTreeGridCellAccessible* GetCellAccessible(nsTreeColumn* aColumn)
     const final;
   virtual void RowInvalidated(int32_t aStartColIdx, int32_t aEndColIdx) override;
 
 protected:
   virtual ~XULTreeGridRowAccessible();
 
   // XULTreeItemAccessibleBase
   mutable nsRefPtrHashtable<nsPtrHashKey<const void>, XULTreeGridCellAccessible>
@@ -111,17 +111,17 @@ protected:
 class XULTreeGridCellAccessible : public LeafAccessible,
                                   public TableCellAccessible
 {
 public:
 
   XULTreeGridCellAccessible(nsIContent* aContent, DocAccessible* aDoc,
                             XULTreeGridRowAccessible* aRowAcc,
                             nsITreeBoxObject* aTree, nsITreeView* aTreeView,
-                            int32_t aRow, nsITreeColumn* aColumn);
+                            int32_t aRow, nsTreeColumn* aColumn);
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(XULTreeGridCellAccessible,
                                            LeafAccessible)
 
   // Accessible
   virtual void Shutdown() override;
@@ -174,17 +174,17 @@ protected:
   bool IsEditable() const;
 
   enum { eAction_Click = 0 };
 
   nsCOMPtr<nsITreeBoxObject> mTree;
   nsITreeView* mTreeView;
 
   int32_t mRow;
-  nsCOMPtr<nsITreeColumn> mColumn;
+  RefPtr<nsTreeColumn> mColumn;
 
   nsString mCachedTextEquiv;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/browser/components/sessionstore/test/browser_aboutSessionRestore.js
+++ b/browser/components/sessionstore/test/browser_aboutSessionRestore.js
@@ -24,19 +24,21 @@ add_task(async function() {
   await promiseBrowserLoaded(browser);
 
   // Fake a post-crash tab.
   ss.setTabState(tab, JSON.stringify(TAB_STATE));
   await promiseTabRestored(tab);
 
   ok(gBrowser.tabs.length > 1, "we have more than one tab");
 
-  let view = browser.contentDocument.getElementById("tabList").view;
+  let tree = browser.contentDocument.getElementById("tabList");
+  let view = tree.view;
   ok(view.isContainer(0), "first entry is the window");
-  is(view.getCellProperties(1, { id: "title" }), "icon",
+  let titleColumn = tree.columns.title;
+  is(view.getCellProperties(1, titleColumn), "icon",
     "second entry is the tab and has a favicon");
 
   browser.messageManager.loadFrameScript(FRAME_SCRIPT, true);
 
   // Wait until the new window was restored.
   let win = await waitForNewWindow();
   await BrowserTestUtils.closeWindow(win);
 
--- a/dom/base/WindowDestroyedEvent.cpp
+++ b/dom/base/WindowDestroyedEvent.cpp
@@ -105,17 +105,17 @@ WindowDestroyedEvent::Run()
         } else {
           nsGlobalWindowOuter* outer = nsGlobalWindowOuter::FromSupports(window);
           currentInner = outer->GetCurrentInnerWindowInternal();
         }
         NS_ENSURE_TRUE(currentInner, NS_OK);
 
         AutoSafeJSContext cx;
         JS::Rooted<JSObject*> obj(cx, currentInner->FastGetGlobalJSObject());
-        if (obj && !js::IsSystemCompartment(js::GetObjectCompartment(obj))) {
+        if (obj && !js::IsSystemRealm(js::GetNonCCWObjectRealm(obj))) {
           JSCompartment* cpt = js::GetObjectCompartment(obj);
           nsCOMPtr<nsIPrincipal> pc = nsJSPrincipals::get(JS_GetCompartmentPrincipals(cpt));
 
           if (BasePrincipal::Cast(pc)->AddonPolicy()) {
             // We want to nuke all references to the add-on compartment.
             xpc::NukeAllWrappersForCompartment(cx, cpt,
                                                mIsInnerWindow ? js::DontNukeWindowReferences
                                                               : js::NukeWindowReferences);
--- a/dom/base/test/chrome/cpows_child.js
+++ b/dom/base/test/chrome/cpows_child.js
@@ -179,17 +179,17 @@ function compartment_test(finish)
 
   let sb = Cu.Sandbox('http://www.example.com', { wantGlobalProperties: ['XMLHttpRequest'] });
   sb.eval('function getUnprivilegedObject() { var xhr = new XMLHttpRequest(); xhr.expando = 42; return xhr; }');
   function testParentObject(obj) {
     let results = [];
     function is(a, b, msg) { results.push({ result: a === b ? "PASS" : "FAIL", message: msg }) };
     function ok(x, msg) { results.push({ result: x ? "PASS" : "FAIL", message: msg }) };
 
-    let cpowLocation = Cu.getCompartmentLocation(obj);
+    let cpowLocation = Cu.getRealmLocation(obj);
     ok(/Privileged Junk/.test(cpowLocation),
        "child->parent CPOWs should live in the privileged junk scope: " + cpowLocation);
     is(obj(), 42, "child->parent CPOW is invokable");
     try {
       obj.expando;
       ok(false, "child->parent CPOW cannot access properties");
     } catch (e) {
       ok(true, "child->parent CPOW cannot access properties");
--- a/dom/base/test/chrome/cpows_parent.xul
+++ b/dom/base/test/chrome/cpows_parent.xul
@@ -296,17 +296,17 @@
       let getUnprivilegedObject = message.objects.getUnprivilegedObject;
       let testParentObject = message.objects.testParentObject;
 
       // Make sure that parent->child CPOWs live in the parent's privileged junk scope.
       let unprivilegedObject = getUnprivilegedObject();
       is(Cu.getGlobalForObject(getUnprivilegedObject),
          Cu.getGlobalForObject(unprivilegedObject),
          "all parent->child CPOWs should live in the same scope");
-      let cpowLocation = Cu.getCompartmentLocation(getUnprivilegedObject);
+      let cpowLocation = Cu.getRealmLocation(getUnprivilegedObject);
       ok(/Privileged Junk/.test(cpowLocation),
          "parent->child CPOWs should live in the privileged junk scope: " + cpowLocation);
 
       // Make sure that parent->child CPOWs point through a privileged scope in the child
       // (the privileged junk scope, but we don't have a good way to test for that
       // specifically).
       is(unprivilegedObject.expando, undefined, "parent->child references should get Xrays");
       is(unprivilegedObject.wrappedJSObject.expando, 42, "parent->child references should get waivable Xrays");
--- a/dom/bindings/DOMJSClass.h
+++ b/dom/bindings/DOMJSClass.h
@@ -38,36 +38,37 @@ namespace dom {
  *
  * [SecureContext] API exposure is restricted to use by code in a Secure
  * Contexts:
  *
  *   https://w3c.github.io/webappsec-secure-contexts/
  *
  * Since we want [SecureContext] exposure to depend on the privileges of the
  * running code (rather than the privileges of an object's creator), this
- * function checks to see whether the given JSContext's Compartment is flagged
+ * function checks to see whether the given JSContext's Realm is flagged
  * as a Secure Context.  That allows us to make sure that system principal code
  * (which is marked as a Secure Context) can access Secure Context API on an
- * object in a different compartment, regardless of whether the other
- * compartment is a Secure Context or not.
+ * object in a different realm, regardless of whether the other realm is a
+ * Secure Context or not.
  *
- * Checking the JSContext's Compartment doesn't work for expanded principal
+ * Checking the JSContext's Realm doesn't work for expanded principal
  * globals accessing a Secure Context web page though (e.g. those used by frame
  * scripts).  To handle that we fall back to checking whether the JSObject came
  * from a Secure Context.
  *
  * Note: We'd prefer this function to live in BindingUtils.h, but we need to
  * call it in this header, and BindingUtils.h includes us (i.e. we'd have a
  * circular dependency between headers if it lived there).
  */
 inline bool
 IsSecureContextOrObjectIsFromSecureContext(JSContext* aCx, JSObject* aObj)
 {
-  return JS::RealmCreationOptionsRef(js::GetContextCompartment(aCx)).secureContext() ||
-         JS::RealmCreationOptionsRef(js::GetObjectCompartment(aObj)).secureContext();
+  MOZ_ASSERT(!js::IsWrapper(aObj));
+  return JS::GetIsSecureContext(js::GetContextRealm(aCx)) ||
+         JS::GetIsSecureContext(js::GetNonCCWObjectRealm(aObj));
 }
 
 typedef bool
 (* ResolveOwnProperty)(JSContext* cx, JS::Handle<JSObject*> wrapper,
                        JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
                        JS::MutableHandle<JS::PropertyDescriptor> desc);
 
 typedef bool
--- a/dom/webidl/TreeBoxObject.webidl
+++ b/dom/webidl/TreeBoxObject.webidl
@@ -78,16 +78,17 @@ interface TreeBoxObject : BoxObject {
   /**
    * Ensures that a row at a given index is visible.
    */
   void ensureRowIsVisible(long index);
 
   /**
    * Ensures that a given cell in the tree is visible.
    */
+  [Throws]
   void ensureCellIsVisible(long row, TreeColumn? col);
 
   /**
    * Scrolls such that the row at index is at the top of the visible view.
    */
   void scrollToRow(long index);
 
   /**
@@ -101,41 +102,23 @@ interface TreeBoxObject : BoxObject {
    * Scroll the tree up or down by numPages pages. A page
    * is considered to be the amount displayed by the tree.
    * Positive values move down in the tree. Prevents scrolling
    * off the end of the tree.
    */
   void scrollByPages(long numPages);
 
   /**
-   * Scrolls such that a given cell is visible (if possible)
-   * at the top left corner of the visible view.
-   */
-  void scrollToCell(long row, TreeColumn? col);
-
-  /**
-   * Scrolls horizontally so that the specified column is
-   * at the left of the view (if possible).
-   */
-  void scrollToColumn(TreeColumn? col);
-
-  /**
-   * Scroll to a specific horizontal pixel position.
-   */
-  void scrollToHorizontalPosition(long horizontalPosition);
-
-  /**
    * Invalidation methods for fine-grained painting control.
    */
   void invalidate();
   void invalidateColumn(TreeColumn? col);
   void invalidateRow(long index);
   void invalidateCell(long row, TreeColumn? col);
   void invalidateRange(long startIndex, long endIndex);
-  void invalidateColumnRange(long startIndex, long endIndex, TreeColumn? col);
 
   /**
    * A hit test that can tell you what row the mouse is over.
    * returns -1 for invalid mouse coordinates.
    *
    * The coordinate system is the client coordinate system for the
    * document this boxObject lives in, and the units are CSS pixels.
    */
--- a/dom/webidl/TreeColumn.webidl
+++ b/dom/webidl/TreeColumn.webidl
@@ -1,16 +1,15 @@
 /* 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/. */
 
 [Func="IsChromeOrXBL"]
 interface TreeColumn {
-  [Throws]
-  readonly attribute Element? element;
+  readonly attribute Element element;
 
   readonly attribute TreeColumns? columns;
 
   [Throws]
   readonly attribute long x;
   [Throws]
   readonly attribute long width;
 
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -1202,20 +1202,19 @@ public:
   {
     MOZ_ASSERT(!aRealmStats->extra);
 
     // ReportJSRuntimeExplicitTreeStats expects that
     // aRealmStats->extra is a xpc::RealmStatsExtras pointer.
     xpc::RealmStatsExtras* extras = new xpc::RealmStatsExtras;
 
     // This is the |jsPathPrefix|.  Each worker has exactly one realm.
-    JSCompartment* compartment = JS::GetCompartmentForRealm(aRealm);
     extras->jsPathPrefix.Assign(mRtPath);
     extras->jsPathPrefix += nsPrintfCString("zone(0x%p)/",
-                                            (void *)js::GetCompartmentZone(compartment));
+                                            (void *)js::GetRealmZone(aRealm));
     extras->jsPathPrefix += NS_LITERAL_CSTRING("realm(web-worker)/");
 
     // This should never be used when reporting with workers (hence the "?!").
     extras->domPathPrefix.AssignLiteral("explicit/workers/?!/");
 
     MOZ_ASSERT(StartsWithExplicit(extras->jsPathPrefix));
     MOZ_ASSERT(StartsWithExplicit(extras->domPathPrefix));
 
--- a/gfx/layers/apz/test/gtest/APZTestCommon.h
+++ b/gfx/layers/apz/test/gtest/APZTestCommon.h
@@ -38,16 +38,35 @@ using namespace mozilla::layers;
 using ::testing::_;
 using ::testing::NiceMock;
 using ::testing::AtLeast;
 using ::testing::AtMost;
 using ::testing::MockFunction;
 using ::testing::InSequence;
 typedef mozilla::layers::GeckoContentController::TapType TapType;
 
+// Some helper functions for constructing input event objects suitable to be
+// passed either to an APZC (which expects an transformed point), or to an APZTM
+// (which expects an untransformed point). We handle both cases by setting both
+// the transformed and untransformed fields to the same value.
+SingleTouchData
+CreateSingleTouchData(int32_t aIdentifier, const ScreenIntPoint& aPoint)
+{
+  SingleTouchData touch(aIdentifier, aPoint, ScreenSize(0, 0), 0, 0);
+  touch.mLocalScreenPoint = ParentLayerPoint(aPoint.x, aPoint.y);
+  return touch;
+}
+
+// Convenience wrapper for CreateSingleTouchData() that takes loose coordinates.
+SingleTouchData
+CreateSingleTouchData(int32_t aIdentifier, ScreenIntCoord aX, ScreenIntCoord aY)
+{
+  return CreateSingleTouchData(aIdentifier, ScreenIntPoint(aX, aY));
+}
+
 template<class T>
 class ScopedGfxPref {
 public:
   ScopedGfxPref(T (*aGetPrefFunc)(void), void (*aSetPrefFunc)(T), T aVal)
     : mSetPrefFunc(aSetPrefFunc)
   {
     mOldVal = aGetPrefFunc();
     aSetPrefFunc(aVal);
@@ -327,16 +346,29 @@ public:
      * Do not adjust the touch-start coordinates to overcome the touch-start
      * tolerance threshold. If this option is passed, it's up to the caller
      * to pass in coordinates that are sufficient to overcome the touch-start
      * tolerance *and* cause the desired amount of scrolling.
      */
     ExactCoordinates = 0x2
   };
 
+  enum class PinchOptions {
+    None = 0,
+    LiftFinger1 = 0x1,
+    LiftFinger2 = 0x2,
+    /*
+     * The bitwise OR result of (LiftFinger1 | LiftFinger2).
+     * Defined explicitly here because it is used as the default
+     * argument for PinchWithTouchInput which is defined BEFORE the
+     * definition of operator| for this class.
+     */
+    LiftBothFingers = 0x3
+  };
+
   template<class InputReceiver>
   void Tap(const RefPtr<InputReceiver>& aTarget, const ScreenIntPoint& aPoint,
            TimeDuration aTapLength,
            nsEventStatus (*aOutEventStatuses)[2] = nullptr,
            uint64_t* aOutInputBlockId = nullptr);
 
   template<class InputReceiver>
   void TapAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
@@ -385,21 +417,48 @@ public:
                  nsEventStatus (*aOutEventStatuses)[4] = nullptr,
                  uint64_t (*aOutInputBlockIds)[2] = nullptr);
 
   template<class InputReceiver>
   void DoubleTapAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
                                const ScreenIntPoint& aPoint,
                                uint64_t (*aOutInputBlockIds)[2] = nullptr);
 
+  template<class InputReceiver>
+  void PinchWithTouchInput(const RefPtr<InputReceiver>& aTarget,
+                           const ScreenIntPoint& aFocus, const ScreenIntPoint& aSecondFocus,
+                           float aScale,
+                           int& inputId,
+                           nsTArray<uint32_t>* aAllowedTouchBehaviors = nullptr,
+                           nsEventStatus (*aOutEventStatuses)[4] = nullptr,
+                           uint64_t* aOutInputBlockId = nullptr,
+                           PinchOptions aOptions = PinchOptions::LiftBothFingers);
+
+  // Pinch with one focus point. Zooms in place with no panning
+  template<class InputReceiver>
+  void PinchWithTouchInput(const RefPtr<InputReceiver>& aTarget,
+                           const ScreenIntPoint& aFocus, float aScale,
+                           int& inputId,
+                           nsTArray<uint32_t>* aAllowedTouchBehaviors = nullptr,
+                           nsEventStatus (*aOutEventStatuses)[4] = nullptr,
+                           uint64_t* aOutInputBlockId = nullptr,
+                           PinchOptions aOptions = PinchOptions::LiftBothFingers);
+
+  template<class InputReceiver>
+  void PinchWithTouchInputAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
+                                         const ScreenIntPoint& aFocus, float aScale,
+                                         int& inputId, bool aShouldTriggerPinch,
+                                         nsTArray<uint32_t>* aAllowedTouchBehaviors);
+
 protected:
   RefPtr<MockContentControllerDelayed> mcc;
 };
 
 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(APZCTesterBase::PanOptions)
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(APZCTesterBase::PinchOptions)
 
 template<class InputReceiver>
 void
 APZCTesterBase::Tap(const RefPtr<InputReceiver>& aTarget,
                     const ScreenIntPoint& aPoint, TimeDuration aTapLength,
                     nsEventStatus (*aOutEventStatuses)[2],
                     uint64_t* aOutInputBlockId)
 {
@@ -629,16 +688,129 @@ APZCTesterBase::DoubleTapAndCheckStatus(
   nsEventStatus statuses[4];
   DoubleTap(aTarget, aPoint, &statuses, aOutInputBlockIds);
   EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[0]);
   EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[1]);
   EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[2]);
   EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[3]);
 }
 
+template<class InputReceiver>
+void
+APZCTesterBase::PinchWithTouchInput(const RefPtr<InputReceiver>& aTarget,
+                                    const ScreenIntPoint& aFocus, float aScale,
+                                    int& inputId,
+                                    nsTArray<uint32_t>* aAllowedTouchBehaviors,
+                                    nsEventStatus (*aOutEventStatuses)[4],
+                                    uint64_t* aOutInputBlockId,
+                                    PinchOptions aOptions)
+{
+  //Perform a pinch gesture with the same start & end focus point
+  PinchWithTouchInput(aTarget, aFocus, aFocus, aScale, inputId,
+                      aAllowedTouchBehaviors, aOutEventStatuses,
+                      aOutInputBlockId, aOptions);
+}
+
+template<class InputReceiver>
+void
+APZCTesterBase::PinchWithTouchInput(const RefPtr<InputReceiver>& aTarget,
+                                    const ScreenIntPoint& aFocus, const ScreenIntPoint& aSecondFocus,
+                                    float aScale,
+                                    int& inputId,
+                                    nsTArray<uint32_t>* aAllowedTouchBehaviors,
+                                    nsEventStatus (*aOutEventStatuses)[4],
+                                    uint64_t* aOutInputBlockId,
+                                    PinchOptions aOptions)
+{
+  // Having pinch coordinates in float type may cause problems with high-precision scale values
+  // since SingleTouchData accepts integer value. But for trivial tests it should be ok.
+  float pinchLength = 100.0;
+  float pinchLengthScaled = pinchLength * aScale;
+
+  // Even if the caller doesn't care about the block id, we need it to set the
+  // allowed touch behaviour below, so make sure aOutInputBlockId is non-null.
+  uint64_t blockId;
+  if (!aOutInputBlockId) {
+    aOutInputBlockId = &blockId;
+  }
+
+  const TimeDuration TIME_BETWEEN_TOUCH_EVENT = TimeDuration::FromMilliseconds(50);
+
+  MultiTouchInput mtiStart = MultiTouchInput(MultiTouchInput::MULTITOUCH_START, 0, mcc->Time(), 0);
+  mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocus));
+  mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocus));
+  nsEventStatus status = aTarget->ReceiveInputEvent(mtiStart, aOutInputBlockId);
+  if (aOutEventStatuses) {
+    (*aOutEventStatuses)[0] = status;
+  }
+
+  mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
+
+  if (aAllowedTouchBehaviors) {
+    EXPECT_EQ(2UL, aAllowedTouchBehaviors->Length());
+    aTarget->SetAllowedTouchBehavior(*aOutInputBlockId, *aAllowedTouchBehaviors);
+  } else if (gfxPrefs::TouchActionEnabled()) {
+    SetDefaultAllowedTouchBehavior(aTarget, *aOutInputBlockId, 2);
+  }
+
+  MultiTouchInput mtiMove1 = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, mcc->Time(), 0);
+  mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocus.x - pinchLength, aFocus.y));
+  mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocus.x + pinchLength, aFocus.y));
+  status = aTarget->ReceiveInputEvent(mtiMove1, nullptr);
+  if (aOutEventStatuses) {
+    (*aOutEventStatuses)[1] = status;
+  }
+
+  mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
+
+  MultiTouchInput mtiMove2 = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, mcc->Time(), 0);
+  mtiMove2.mTouches.AppendElement(CreateSingleTouchData(inputId, aSecondFocus.x - pinchLengthScaled, aSecondFocus.y));
+  mtiMove2.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aSecondFocus.x + pinchLengthScaled, aSecondFocus.y));
+  status = aTarget->ReceiveInputEvent(mtiMove2, nullptr);
+  if (aOutEventStatuses) {
+    (*aOutEventStatuses)[2] = status;
+  }
+
+  if (aOptions & (PinchOptions::LiftFinger1 | PinchOptions::LiftFinger2)) {
+    mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
+
+    MultiTouchInput mtiEnd = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, 0, mcc->Time(), 0);
+    if (aOptions & PinchOptions::LiftFinger1) {
+      mtiEnd.mTouches.AppendElement(CreateSingleTouchData(inputId, aSecondFocus.x - pinchLengthScaled, aSecondFocus.y));
+    }
+    if (aOptions & PinchOptions::LiftFinger2) {
+      mtiEnd.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aSecondFocus.x + pinchLengthScaled, aSecondFocus.y));
+    }
+    status = aTarget->ReceiveInputEvent(mtiEnd, nullptr);
+    if (aOutEventStatuses) {
+      (*aOutEventStatuses)[3] = status;
+    }
+  }
+
+  inputId += 2;
+}
+
+template<class InputReceiver>
+void
+APZCTesterBase::PinchWithTouchInputAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
+                                                  const ScreenIntPoint& aFocus, float aScale,
+                                                  int& inputId, bool aShouldTriggerPinch,
+                                                  nsTArray<uint32_t>* aAllowedTouchBehaviors)
+{
+  nsEventStatus statuses[4];  // down, move, move, up
+  PinchWithTouchInput(aTarget, aFocus, aScale, inputId, aAllowedTouchBehaviors, &statuses);
+
+  nsEventStatus expectedMoveStatus = aShouldTriggerPinch
+      ? nsEventStatus_eConsumeDoDefault
+      : nsEventStatus_eIgnore;
+  EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[0]);
+  EXPECT_EQ(expectedMoveStatus, statuses[1]);
+  EXPECT_EQ(expectedMoveStatus, statuses[2]);
+}
+
 AsyncPanZoomController*
 TestAPZCTreeManager::NewAPZCInstance(LayersId aLayersId,
                                      GeckoContentController* aController)
 {
   MockContentControllerDelayed* mcc = static_cast<MockContentControllerDelayed*>(aController);
   return new TestAsyncPanZoomController(aLayersId, mcc, this,
       AsyncPanZoomController::USE_GESTURE_DETECTOR);
 }
--- a/gfx/layers/apz/test/gtest/InputUtils.h
+++ b/gfx/layers/apz/test/gtest/InputUtils.h
@@ -23,35 +23,16 @@
  * void SetAllowedTouchBehavior(uint64_t aInputBlockId,
  *                              const nsTArray<uint32_t>& aBehaviours);
  * The classes that currently implement these are APZCTreeManager and
  * TestAsyncPanZoomController. Using this template allows us to test individual
  * APZC instances in isolation and also an entire APZ tree, while using the same
  * code to dispatch input events.
  */
 
-// Some helper functions for constructing input event objects suitable to be
-// passed either to an APZC (which expects an transformed point), or to an APZTM
-// (which expects an untransformed point). We handle both cases by setting both
-// the transformed and untransformed fields to the same value.
-SingleTouchData
-CreateSingleTouchData(int32_t aIdentifier, const ScreenIntPoint& aPoint)
-{
-  SingleTouchData touch(aIdentifier, aPoint, ScreenSize(0, 0), 0, 0);
-  touch.mLocalScreenPoint = ParentLayerPoint(aPoint.x, aPoint.y);
-  return touch;
-}
-
-// Convenience wrapper for CreateSingleTouchData() that takes loose coordinates.
-SingleTouchData
-CreateSingleTouchData(int32_t aIdentifier, ScreenIntCoord aX, ScreenIntCoord aY)
-{
-  return CreateSingleTouchData(aIdentifier, ScreenIntPoint(aX, aY));
-}
-
 PinchGestureInput
 CreatePinchGestureInput(PinchGestureInput::PinchGestureType aType,
                         const ScreenPoint& aFocus,
                         float aCurrentSpan, float aPreviousSpan)
 {
   ParentLayerPoint localFocus(aFocus.x, aFocus.y);
   PinchGestureInput result(aType, 0, TimeStamp(), localFocus,
                            aCurrentSpan, aPreviousSpan, 0);
@@ -156,97 +137,16 @@ PinchWithPinchInputAndCheckStatus(const 
   nsEventStatus expectedStatus = aShouldTriggerPinch
       ? nsEventStatus_eConsumeNoDefault
       : nsEventStatus_eIgnore;
   EXPECT_EQ(expectedStatus, statuses[0]);
   EXPECT_EQ(expectedStatus, statuses[1]);
 }
 
 template<class InputReceiver>
-void
-PinchWithTouchInput(const RefPtr<InputReceiver>& aTarget,
-                    const ScreenIntPoint& aFocus, float aScale,
-                    int& inputId,
-                    nsTArray<uint32_t>* aAllowedTouchBehaviors = nullptr,
-                    nsEventStatus (*aOutEventStatuses)[4] = nullptr,
-                    uint64_t* aOutInputBlockId = nullptr)
-{
-  // Having pinch coordinates in float type may cause problems with high-precision scale values
-  // since SingleTouchData accepts integer value. But for trivial tests it should be ok.
-  float pinchLength = 100.0;
-  float pinchLengthScaled = pinchLength * aScale;
-
-  // Even if the caller doesn't care about the block id, we need it to set the
-  // allowed touch behaviour below, so make sure aOutInputBlockId is non-null.
-  uint64_t blockId;
-  if (!aOutInputBlockId) {
-    aOutInputBlockId = &blockId;
-  }
-
-  MultiTouchInput mtiStart = MultiTouchInput(MultiTouchInput::MULTITOUCH_START, 0, TimeStamp(), 0);
-  mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocus));
-  mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocus));
-  nsEventStatus status = aTarget->ReceiveInputEvent(mtiStart, aOutInputBlockId);
-  if (aOutEventStatuses) {
-    (*aOutEventStatuses)[0] = status;
-  }
-
-  if (aAllowedTouchBehaviors) {
-    EXPECT_EQ(2UL, aAllowedTouchBehaviors->Length());
-    aTarget->SetAllowedTouchBehavior(*aOutInputBlockId, *aAllowedTouchBehaviors);
-  } else if (gfxPrefs::TouchActionEnabled()) {
-    SetDefaultAllowedTouchBehavior(aTarget, *aOutInputBlockId, 2);
-  }
-
-  MultiTouchInput mtiMove1 = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, TimeStamp(), 0);
-  mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocus.x - pinchLength, aFocus.y));
-  mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocus.x + pinchLength, aFocus.y));
-  status = aTarget->ReceiveInputEvent(mtiMove1, nullptr);
-  if (aOutEventStatuses) {
-    (*aOutEventStatuses)[1] = status;
-  }
-
-  MultiTouchInput mtiMove2 = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, TimeStamp(), 0);
-  mtiMove2.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocus.x - pinchLengthScaled, aFocus.y));
-  mtiMove2.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocus.x + pinchLengthScaled, aFocus.y));
-  status = aTarget->ReceiveInputEvent(mtiMove2, nullptr);
-  if (aOutEventStatuses) {
-    (*aOutEventStatuses)[2] = status;
-  }
-
-  MultiTouchInput mtiEnd = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, 0, TimeStamp(), 0);
-  mtiEnd.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocus.x - pinchLengthScaled, aFocus.y));
-  mtiEnd.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocus.x + pinchLengthScaled, aFocus.y));
-  status = aTarget->ReceiveInputEvent(mtiEnd, nullptr);
-  if (aOutEventStatuses) {
-    (*aOutEventStatuses)[3] = status;
-  }
-
-  inputId += 2;
-}
-
-template<class InputReceiver>
-void
-PinchWithTouchInputAndCheckStatus(const RefPtr<InputReceiver>& aTarget,
-                                  const ScreenIntPoint& aFocus, float aScale,
-                                  int& inputId, bool aShouldTriggerPinch,
-                                  nsTArray<uint32_t>* aAllowedTouchBehaviors)
-{
-  nsEventStatus statuses[4];  // down, move, move, up
-  PinchWithTouchInput(aTarget, aFocus, aScale, inputId, aAllowedTouchBehaviors, &statuses);
-
-  nsEventStatus expectedMoveStatus = aShouldTriggerPinch
-      ? nsEventStatus_eConsumeDoDefault
-      : nsEventStatus_eIgnore;
-  EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[0]);
-  EXPECT_EQ(expectedMoveStatus, statuses[1]);
-  EXPECT_EQ(expectedMoveStatus, statuses[2]);
-}
-
-template<class InputReceiver>
 nsEventStatus
 Wheel(const RefPtr<InputReceiver>& aTarget, const ScreenIntPoint& aPoint,
       const ScreenPoint& aDelta, TimeStamp aTime, uint64_t* aOutInputBlockId = nullptr)
 {
   ScrollWheelInput input(MillisecondsSinceStartup(aTime), aTime, 0,
       ScrollWheelInput::SCROLLMODE_INSTANT, ScrollWheelInput::SCROLLDELTA_PIXEL,
       aPoint, aDelta.x, aDelta.y, false, WheelDeltaAdjustmentStrategy::eNone);
   return aTarget->ReceiveInputEvent(input, nullptr, aOutInputBlockId);
--- a/gfx/layers/apz/test/gtest/TestPinching.cpp
+++ b/gfx/layers/apz/test/gtest/TestPinching.cpp
@@ -265,16 +265,68 @@ TEST_F(APZCPinchGestureDetectorTester, P
   // Since we are preventing the pinch action we should not be sending the pinch
   // gesture notifications that would normally be sent when APZAllowZooming is
   // false.
   EXPECT_CALL(*mcc, NotifyPinchGesture(_, _, _, _)).Times(0);
 
   DoPinchWithPreventDefaultTest();
 }
 
+TEST_F(APZCPinchGestureDetectorTester, Panning_TwoFingerFling_ZoomDisabled) {
+  SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
+
+  apzc->SetFrameMetrics(GetPinchableFrameMetrics());
+  MakeApzcUnzoomable();
+
+  // Perform a two finger pan
+  int touchInputId = 0;
+  uint64_t blockId = 0;
+  PinchWithTouchInput(apzc, ScreenIntPoint(100, 200), ScreenIntPoint(100, 100),
+      1, touchInputId, nullptr, nullptr, &blockId);
+
+  // Expect to be in a flinging state
+  apzc->AssertStateIsFling();
+}
+
+TEST_F(APZCPinchGestureDetectorTester, Panning_TwoFingerFling_ZoomEnabled) {
+  SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
+
+  apzc->SetFrameMetrics(GetPinchableFrameMetrics());
+  MakeApzcZoomable();
+
+  // Perform a two finger pan
+  int touchInputId = 0;
+  uint64_t blockId = 0;
+  PinchWithTouchInput(apzc, ScreenIntPoint(100, 200), ScreenIntPoint(100, 100),
+      1, touchInputId, nullptr, nullptr, &blockId);
+
+  // Expect to NOT be in flinging state
+  apzc->AssertStateIsReset();
+}
+
+TEST_F(APZCPinchGestureDetectorTester, Panning_TwoThenOneFingerFling_ZoomEnabled) {
+  SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
+
+  apzc->SetFrameMetrics(GetPinchableFrameMetrics());
+  MakeApzcZoomable();
+
+  // Perform a two finger pan lifting only the first finger
+  int touchInputId = 0;
+  uint64_t blockId = 0;
+  PinchWithTouchInput(apzc, ScreenIntPoint(100, 200), ScreenIntPoint(100, 100),
+      1, touchInputId, nullptr, nullptr, &blockId, PinchOptions::LiftFinger2);
+
+  // Lift second finger after a pause
+  mcc->AdvanceBy(TimeDuration::FromMilliseconds(50));
+  TouchUp(apzc, ScreenIntPoint(100, 100), mcc->Time());
+
+  // Expect to NOT be in flinging state
+  apzc->AssertStateIsReset();
+}
+
 TEST_F(APZCPinchTester, Panning_TwoFinger_ZoomDisabled) {
   // set up APZ
   apzc->SetFrameMetrics(GetPinchableFrameMetrics());
   MakeApzcUnzoomable();
 
   nsEventStatus statuses[3];  // scalebegin, scale, scaleend
   PinchWithPinchInput(apzc, ScreenIntPoint(250, 350), ScreenIntPoint(200, 300),
       10, &statuses);
--- a/gfx/tests/reftest/reftest.list
+++ b/gfx/tests/reftest/reftest.list
@@ -1,11 +1,11 @@
 # 468496-1 will also detect bugs in video drivers.
 == 468496-1.html 468496-1-ref.html
-fuzzy(175,443) == 611498-1.html 611498-ref.html
+fuzzy(175,443) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 611498-1.html 611498-ref.html # Bug 1392106
 fuzzy-if(Android,8,1000) == 709477-1.html 709477-1-ref.html
 skip-if(!asyncPan) == 1086723.html 1086723-ref.html
 == 853889-1.html 853889-1-ref.html
 skip-if(Android) fuzzy-if(skiaContent,1,587) == 1143303-1.svg pass.svg
 fuzzy(100,30) == 1149923.html 1149923-ref.html # use fuzzy due to few distorted pixels caused by border-radius
 == 1131264-1.svg pass.svg
 == 1419528.html 1419528-ref.html
 == 1424673.html 1424673-ref.html
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -706,17 +706,20 @@ struct ZoneStats
     macro(Other,   GCHeapUsed,  regExpSharedsGCHeap) \
     macro(Other,   MallocHeap,  regExpSharedsMallocHeap) \
     macro(Other,   MallocHeap,  typePool) \
     macro(Other,   MallocHeap,  regexpZone) \
     macro(Other,   MallocHeap,  jitZone) \
     macro(Other,   MallocHeap,  baselineStubsOptimized) \
     macro(Other,   MallocHeap,  cachedCFG) \
     macro(Other,   MallocHeap,  uniqueIdMap) \
-    macro(Other,   MallocHeap,  shapeTables)
+    macro(Other,   MallocHeap,  shapeTables) \
+    macro(Other,   MallocHeap,  compartmentObjects) \
+    macro(Other,   MallocHeap,  crossCompartmentWrappersTables) \
+    macro(Other,   MallocHeap,  compartmentsPrivateData)
 
     ZoneStats()
       : FOR_EACH_SIZE(ZERO_SIZE)
         unusedGCThings(),
         stringInfo(),
         shapeInfo(),
         extra(),
         allStrings(nullptr),
@@ -822,22 +825,20 @@ struct RealmStats
     macro(Other,   MallocHeap, typeInferenceAllocationSiteTables) \
     macro(Other,   MallocHeap, typeInferenceArrayTypeTables) \
     macro(Other,   MallocHeap, typeInferenceObjectTypeTables) \
     macro(Other,   MallocHeap, realmObject) \
     macro(Other,   MallocHeap, realmTables) \
     macro(Other,   MallocHeap, innerViewsTable) \
     macro(Other,   MallocHeap, lazyArrayBuffersTable) \
     macro(Other,   MallocHeap, objectMetadataTable) \
-    macro(Other,   MallocHeap, crossCompartmentWrappersTable) \
     macro(Other,   MallocHeap, savedStacksSet) \
     macro(Other,   MallocHeap, varNamesSet) \
     macro(Other,   MallocHeap, nonSyntacticLexicalScopesTable) \
     macro(Other,   MallocHeap, jitRealm) \
-    macro(Other,   MallocHeap, privateData) \
     macro(Other,   MallocHeap, scriptCountsMap)
 
     RealmStats()
       : FOR_EACH_SIZE(ZERO_SIZE)
         classInfo(),
         extra(),
         allClasses(nullptr),
         notableClasses(),
--- a/js/public/Realm.h
+++ b/js/public/Realm.h
@@ -39,31 +39,43 @@ struct GCPolicy<Realm*> : public NonGCPo
     }
 };
 
 // Get the current realm, if any. The ECMAScript spec calls this "the current
 // Realm Record".
 extern JS_PUBLIC_API(Realm*)
 GetCurrentRealmOrNull(JSContext* cx);
 
+namespace shadow {
+
+class Realm
+{
+  protected:
+    JSCompartment* compartment_;
+
+    explicit Realm(JSCompartment* comp)
+      : compartment_(comp)
+    {}
+
+  public:
+    JSCompartment* compartment() {
+        return compartment_;
+    }
+    static shadow::Realm* get(JS::Realm* realm) {
+        return reinterpret_cast<shadow::Realm*>(realm);
+    }
+};
+
+}; // namespace shadow
+
 // Return the compartment that contains a given realm.
 inline JSCompartment*
-GetCompartmentForRealm(Realm* realm) {
-    // Implementation note: For now, realms are a fiction; we treat realms and
-    // compartments as being one-to-one, but they are actually identical.
-    return reinterpret_cast<JSCompartment*>(realm);
-}
-
-// Return the realm in a given compartment.
-//
-// Deprecated. There is currently exactly one realm per compartment, but this
-// will change.
-inline Realm*
-GetRealmForCompartment(JSCompartment* compartment) {
-    return reinterpret_cast<Realm*>(compartment);
+GetCompartmentForRealm(Realm* realm)
+{
+    return shadow::Realm::get(realm)->compartment();
 }
 
 // Return an object's realm. All objects except cross-compartment wrappers are
 // created in a particular realm, which never changes. Returns null if obj is
 // a cross-compartment wrapper.
 extern JS_PUBLIC_API(Realm*)
 GetObjectRealmOrNull(JSObject* obj);
 
--- a/js/public/RootingAPI.h
+++ b/js/public/RootingAPI.h
@@ -1058,17 +1058,19 @@ inline JS::Realm*
 GetContextRealm(const JSContext* cx)
 {
     return JS::RootingContext::get(cx)->realm_;
 }
 
 inline JSCompartment*
 GetContextCompartment(const JSContext* cx)
 {
-    return GetCompartmentForRealm(GetContextRealm(cx));
+    if (JS::Realm* realm = GetContextRealm(cx))
+        return GetCompartmentForRealm(realm);
+    return nullptr;
 }
 
 inline JS::Zone*
 GetContextZone(const JSContext* cx)
 {
     return JS::RootingContext::get(cx)->zone_;
 }
 
--- a/js/public/Utility.h
+++ b/js/public/Utility.h
@@ -433,40 +433,49 @@ static inline void js_free(void* p)
  *     error and we cannot override them not to.
  *
  * Allocation:
  *
  * - If the lifetime of the allocation is tied to the lifetime of a GC-thing
  *   (that is, finalizing the GC-thing will free the allocation), call one of
  *   the following functions:
  *
- *     JSContext::{malloc_,realloc_,calloc_,new_}
- *     JSRuntime::{malloc_,realloc_,calloc_,new_}
+ *     JSContext::{pod_malloc,pod_calloc,pod_realloc}
+ *     Zone::{pod_malloc,pod_calloc,pod_realloc}
  *
  *   These functions accumulate the number of bytes allocated which is used as
- *   part of the GC-triggering heuristic.
+ *   part of the GC-triggering heuristics.
  *
- *   The difference between the JSContext and JSRuntime versions is that the
- *   cx version reports an out-of-memory error on OOM. (This follows from the
+ *   The difference between the JSContext and Zone versions is that the
+ *   cx version report an out-of-memory error on OOM. (This follows from the
  *   general SpiderMonkey idiom that a JSContext-taking function reports its
  *   own errors.)
  *
+ *   If you don't want to report an error on failure, there are maybe_ versions
+ *   of these methods available too, e.g. maybe_pod_malloc.
+ *
+ *   The methods above use templates to allow allocating memory suitable for an
+ *   array of a given type and number of elements. There are _with_extra
+ *   versions to allow allocating an area of memory which is larger by a
+ *   specified number of bytes, e.g. pod_malloc_with_extra.
+ *
+ *   These methods are available on a JSRuntime, but calling them is
+ *   discouraged. Memory attributed to a runtime can only be reclaimed by full
+ *   GCs, and we try to avoid those where possible.
+ *
  * - Otherwise, use js_malloc/js_realloc/js_calloc/js_new
  *
  * Deallocation:
  *
  * - Ordinarily, use js_free/js_delete.
  *
  * - For deallocations during GC finalization, use one of the following
  *   operations on the FreeOp provided to the finalizer:
  *
  *     FreeOp::{free_,delete_}
- *
- *   The advantage of these operations is that the memory is batched and freed
- *   on another thread.
  */
 
 /*
  * Given a class which should provide a 'new' method, add
  * JS_DECLARE_NEW_METHODS (see js::MallocProvider for an example).
  *
  * Note: Do not add a ; at the end of a use of JS_DECLARE_NEW_METHODS,
  * or the build will break.
--- a/js/rust/build.rs
+++ b/js/rust/build.rs
@@ -231,16 +231,17 @@ const WHITELIST_TYPES: &'static [&'stati
     "js::StackFormat",
     "JSStructuredCloneCallbacks",
     "JS::Symbol",
     "JS::SymbolCode",
     "JS::TraceKind",
     "JS::TransferableOwnership",
     "JS::Value",
     "JS::WarningReporter",
+    "JS::shadow::Realm",
     "JS::shadow::Zone",
     "JS::Zone",
 ];
 
 /// Global variables we want to generate bindings to.
 const WHITELIST_VARS: &'static [&'static str] = &[
     "JS_STRUCTURED_CLONE_VERSION",
     "JSCLASS_.*",
--- a/js/rust/src/rust.rs
+++ b/js/rust/src/rust.rs
@@ -1050,17 +1050,18 @@ unsafe fn get_object_group(obj: *mut JSO
 
 #[inline]
 pub unsafe fn get_object_class(obj: *mut JSObject) -> *const JSClass {
     (*get_object_group(obj)).clasp as *const _
 }
 
 #[inline]
 pub unsafe fn get_object_compartment(obj: *mut JSObject) -> *mut JSCompartment {
-    (*get_object_group(obj)).realm as *mut JSCompartment
+    let realm = (*get_object_group(obj)).realm as *const JS::shadow::Realm;
+    (*realm).compartment_
 }
 
 #[inline]
 pub fn is_dom_class(class: &JSClass) -> bool {
     class.flags & JSCLASS_IS_DOMJSCLASS != 0
 }
 
 #[inline]
--- a/js/src/builtin/ModuleObject.cpp
+++ b/js/src/builtin/ModuleObject.cpp
@@ -1650,16 +1650,20 @@ js::GetOrCreateModuleMetaObject(JSContex
     if (JSObject* obj = module->metaObject())
         return obj;
 
     RootedObject metaObject(cx, NewObjectWithGivenProto<PlainObject>(cx, nullptr));
     if (!metaObject)
         return nullptr;
 
     JS::ModuleMetadataHook func = cx->runtime()->moduleMetadataHook;
-    MOZ_ASSERT(func);
+    if (!func) {
+        JS_ReportErrorASCII(cx, "Module metadata hook not set");
+        return nullptr;
+    }
+
     if (!func(cx, module, metaObject))
         return nullptr;
 
     module->setMetaObject(metaObject);
 
     return metaObject;
 }
--- a/js/src/builtin/SIMD.cpp
+++ b/js/src/builtin/SIMD.cpp
@@ -501,17 +501,17 @@ FillLanes(JSContext* cx, Handle<TypedObj
 }
 
 bool
 SimdTypeDescr::call(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     Rooted<SimdTypeDescr*> descr(cx, &args.callee().as<SimdTypeDescr>());
-    Rooted<TypedObject*> result(cx, TypedObject::createZeroed(cx, descr, 0));
+    Rooted<TypedObject*> result(cx, TypedObject::createZeroed(cx, descr));
     if (!result)
         return false;
 
 #define CASE_CALL_(Type) \
       case SimdType::Type:   return FillLanes< ::Type>(cx, result, args);
 
     switch (descr->type()) {
       FOR_EACH_SIMD(CASE_CALL_)
@@ -697,17 +697,17 @@ template<typename V>
 JSObject*
 js::CreateSimd(JSContext* cx, const typename V::Elem* data)
 {
     typedef typename V::Elem Elem;
     Rooted<TypeDescr*> typeDescr(cx, GetTypeDescr<V>(cx));
     if (!typeDescr)
         return nullptr;
 
-    Rooted<TypedObject*> result(cx, TypedObject::createZeroed(cx, typeDescr, 0));
+    Rooted<TypedObject*> result(cx, TypedObject::createZeroed(cx, typeDescr));
     if (!result)
         return nullptr;
 
     JS::AutoCheckCannotGC nogc(cx);
     Elem* resultMem = reinterpret_cast<Elem*>(result->typedMem(nogc));
     memcpy(resultMem, data, sizeof(Elem) * V::lanes);
     return result;
 }
@@ -1487,17 +1487,17 @@ Load(JSContext* cx, unsigned argc, Value
     RootedObject typedArray(cx);
     if (!TypedArrayFromArgs(cx, args, sizeof(Elem) * NumElem, &typedArray, &byteStart))
         return false;
 
     Rooted<TypeDescr*> typeDescr(cx, GetTypeDescr<V>(cx));
     if (!typeDescr)
         return false;
 
-    Rooted<TypedObject*> result(cx, TypedObject::createZeroed(cx, typeDescr, 0));
+    Rooted<TypedObject*> result(cx, TypedObject::createZeroed(cx, typeDescr));
     if (!result)
         return false;
 
     JS::AutoCheckCannotGC nogc(cx);
     SharedMem<Elem*> src =
         typedArray->as<TypedArrayObject>().viewDataEither().addBytes(byteStart).cast<Elem*>();
     Elem* dst = reinterpret_cast<Elem*>(result->typedMem(nogc));
     jit::AtomicOperations::podCopySafeWhenRacy(SharedMem<Elem*>::unshared(dst), src, NumElem);
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -1393,23 +1393,22 @@ TypedObject::GetByteOffset(JSContext* cx
 
 /******************************************************************************
  * Outline typed objects
  */
 
 /*static*/ OutlineTypedObject*
 OutlineTypedObject::createUnattached(JSContext* cx,
                                      HandleTypeDescr descr,
-                                     int32_t length,
                                      gc::InitialHeap heap)
 {
     if (descr->opaque())
-        return createUnattachedWithClass(cx, &OutlineOpaqueTypedObject::class_, descr, length, heap);
+        return createUnattachedWithClass(cx, &OutlineOpaqueTypedObject::class_, descr, heap);
     else
-        return createUnattachedWithClass(cx, &OutlineTransparentTypedObject::class_, descr, length, heap);
+        return createUnattachedWithClass(cx, &OutlineTransparentTypedObject::class_, descr, heap);
 }
 
 void
 OutlineTypedObject::setOwnerAndData(JSObject* owner, uint8_t* data)
 {
     // Make sure we don't associate with array buffers whose data is from an
     // inline typed object, see obj_trace.
     MOZ_ASSERT_IF(owner && owner->is<ArrayBufferObject>(),
@@ -1425,17 +1424,16 @@ OutlineTypedObject::setOwnerAndData(JSOb
     if (owner && !IsInsideNursery(this) && IsInsideNursery(owner))
         owner->storeBuffer()->putWholeCell(this);
 }
 
 /*static*/ OutlineTypedObject*
 OutlineTypedObject::createUnattachedWithClass(JSContext* cx,
                                               const Class* clasp,
                                               HandleTypeDescr descr,
-                                              int32_t length,
                                               gc::InitialHeap heap)
 {
     MOZ_ASSERT(clasp == &OutlineTransparentTypedObject::class_ ||
                clasp == &OutlineOpaqueTypedObject::class_);
 
     AutoSetNewObjectMetadata metadata(cx);
 
     RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, clasp,
@@ -1498,72 +1496,52 @@ OutlineTypedObject::attach(JSContext* cx
         attach(cx, owner->as<ArrayBufferObject>(), offset);
     } else {
         MOZ_ASSERT(owner->is<InlineTypedObject>());
         JS::AutoCheckCannotGC nogc(cx);
         setOwnerAndData(owner, owner->as<InlineTypedObject>().inlineTypedMem(nogc) + offset);
     }
 }
 
-// Returns a suitable JS_TYPEDOBJ_SLOT_LENGTH value for an instance of
-// the type `type`.
-static uint32_t
-TypedObjLengthFromType(TypeDescr& descr)
-{
-    switch (descr.kind()) {
-      case type::Scalar:
-      case type::Reference:
-      case type::Struct:
-      case type::Simd:
-        return 0;
-
-      case type::Array:
-        return descr.as<ArrayTypeDescr>().length();
-    }
-    MOZ_CRASH("Invalid kind");
-}
-
 /*static*/ OutlineTypedObject*
 OutlineTypedObject::createDerived(JSContext* cx, HandleTypeDescr type,
                                   HandleTypedObject typedObj, uint32_t offset)
 {
     MOZ_ASSERT(offset <= typedObj->size());
     MOZ_ASSERT(offset + type->size() <= typedObj->size());
 
-    int32_t length = TypedObjLengthFromType(*type);
-
     const js::Class* clasp = typedObj->opaque()
                              ? &OutlineOpaqueTypedObject::class_
                              : &OutlineTransparentTypedObject::class_;
     Rooted<OutlineTypedObject*> obj(cx);
-    obj = createUnattachedWithClass(cx, clasp, type, length);
+    obj = createUnattachedWithClass(cx, clasp, type);
     if (!obj)
         return nullptr;
 
     obj->attach(cx, *typedObj, offset);
     return obj;
 }
 
 /*static*/ TypedObject*
-TypedObject::createZeroed(JSContext* cx, HandleTypeDescr descr, int32_t length, gc::InitialHeap heap)
+TypedObject::createZeroed(JSContext* cx, HandleTypeDescr descr, gc::InitialHeap heap)
 {
     // If possible, create an object with inline data.
-    if (descr->size() <= InlineTypedObject::MaximumSize) {
+    if (InlineTypedObject::canAccommodateType(descr)) {
         AutoSetNewObjectMetadata metadata(cx);
 
         InlineTypedObject* obj = InlineTypedObject::create(cx, descr, heap);
         if (!obj)
             return nullptr;
         JS::AutoCheckCannotGC nogc(cx);
         descr->initInstances(cx->runtime(), obj->inlineTypedMem(nogc), 1);
         return obj;
     }
 
     // Create unattached wrapper object.
-    Rooted<OutlineTypedObject*> obj(cx, OutlineTypedObject::createUnattached(cx, descr, length, heap));
+    Rooted<OutlineTypedObject*> obj(cx, OutlineTypedObject::createUnattached(cx, descr, heap));
     if (!obj)
         return nullptr;
 
     // Allocate and initialize the memory for this instance.
     size_t totalSize = descr->size();
     Rooted<ArrayBufferObject*> buffer(cx);
     buffer = ArrayBufferObject::create(cx, totalSize);
     if (!buffer)
@@ -2253,61 +2231,42 @@ DEFINE_TYPEDOBJ_CLASS(OutlineOpaqueTyped
                       nullptr);
 DEFINE_TYPEDOBJ_CLASS(InlineTransparentTypedObject,
                       InlineTypedObject::obj_trace,
                       InlineTypedObject::obj_moved);
 DEFINE_TYPEDOBJ_CLASS(InlineOpaqueTypedObject,
                       InlineTypedObject::obj_trace,
                       InlineTypedObject::obj_moved);
 
-static int32_t
-LengthForType(TypeDescr& descr)
-{
-    switch (descr.kind()) {
-      case type::Scalar:
-      case type::Reference:
-      case type::Struct:
-      case type::Simd:
-        return 0;
-
-      case type::Array:
-        return descr.as<ArrayTypeDescr>().length();
-    }
-
-    MOZ_CRASH("Invalid kind");
-}
-
 /*static*/ bool
 TypedObject::construct(JSContext* cx, unsigned int argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     MOZ_ASSERT(args.callee().is<TypeDescr>());
     Rooted<TypeDescr*> callee(cx, &args.callee().as<TypeDescr>());
 
     // Typed object constructors are overloaded in two ways:
     //
     //   new TypeObj()
     //   new TypeObj(data)
 
     // Zero argument constructor:
     if (args.length() == 0) {
-        int32_t length = LengthForType(*callee);
-        Rooted<TypedObject*> obj(cx, createZeroed(cx, callee, length));
+        Rooted<TypedObject*> obj(cx, createZeroed(cx, callee));
         if (!obj)
             return false;
         args.rval().setObject(*obj);
         return true;
     }
 
     // Data constructor.
     if (args[0].isObject()) {
         // Create the typed object.
-        int32_t length = LengthForType(*callee);
-        Rooted<TypedObject*> obj(cx, createZeroed(cx, callee, length));
+        Rooted<TypedObject*> obj(cx, createZeroed(cx, callee));
         if (!obj)
             return false;
 
         // Initialize from `arg`.
         if (!ConvertAndCopyTo(cx, obj, args[0]))
             return false;
         args.rval().setObject(*obj);
         return true;
@@ -2350,19 +2309,18 @@ TypedObject::create(JSContext* cx, js::g
 bool
 js::NewOpaqueTypedObject(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 1);
     MOZ_ASSERT(args[0].isObject() && args[0].toObject().is<TypeDescr>());
 
     Rooted<TypeDescr*> descr(cx, &args[0].toObject().as<TypeDescr>());
-    int32_t length = TypedObjLengthFromType(*descr);
     Rooted<OutlineTypedObject*> obj(cx);
-    obj = OutlineTypedObject::createUnattachedWithClass(cx, &OutlineOpaqueTypedObject::class_, descr, length);
+    obj = OutlineTypedObject::createUnattachedWithClass(cx, &OutlineOpaqueTypedObject::class_, descr);
     if (!obj)
         return false;
     args.rval().setObject(*obj);
     return true;
 }
 
 bool
 js::NewDerivedTypedObject(JSContext* cx, unsigned argc, Value* vp)
@@ -2930,17 +2888,17 @@ TraceListVisitor::fillList(Vector<int32_
 
 static bool
 CreateTraceList(JSContext* cx, HandleTypeDescr descr)
 {
     // Trace lists are only used for inline typed objects. We don't use them
     // for larger objects, both to limit the size of the trace lists and
     // because tracing outline typed objects is considerably more complicated
     // than inline ones.
-    if (descr->size() > InlineTypedObject::MaximumSize || descr->transparent())
+    if (!InlineTypedObject::canAccommodateType(descr) || descr->transparent())
         return true;
 
     TraceListVisitor visitor;
     visitReferences(*descr, nullptr, visitor);
 
     Vector<int32_t> entries(cx);
     if (!visitor.fillList(entries))
         return false;
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -577,17 +577,17 @@ class TypedObject : public ShapedObject
         return typedMem(nogc) + offset;
     }
 
     inline MOZ_MUST_USE bool opaque() const;
 
     // Creates a new typed object whose memory is freshly allocated and
     // initialized with zeroes (or, in the case of references, an appropriate
     // default value).
-    static TypedObject* createZeroed(JSContext* cx, HandleTypeDescr typeObj, int32_t length,
+    static TypedObject* createZeroed(JSContext* cx, HandleTypeDescr typeObj,
                                      gc::InitialHeap heap = gc::DefaultHeap);
 
     // User-accessible constructor (`new TypeDescriptor(...)`). Note that the
     // callee here is the type descriptor.
     static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
 
     /* Accessors for self hosted code. */
     static MOZ_MUST_USE bool GetBuffer(JSContext* cx, unsigned argc, Value* vp);
@@ -638,29 +638,27 @@ class OutlineTypedObject : public TypedO
         MOZ_ASSERT(offset <= (size_t) size());
         setData(typedMemBase() + offset);
     }
 
     // Helper for createUnattached()
     static OutlineTypedObject* createUnattachedWithClass(JSContext* cx,
                                                          const Class* clasp,
                                                          HandleTypeDescr type,
-                                                         int32_t length,
                                                          gc::InitialHeap heap = gc::DefaultHeap);
 
     // Creates an unattached typed object or handle (depending on the
     // type parameter T). Note that it is only legal for unattached
     // handles to escape to the end user; for non-handles, the caller
     // should always invoke one of the `attach()` methods below.
     //
     // Arguments:
     // - type: type object for resulting object
-    // - length: 0 unless this is an array, otherwise the length
     static OutlineTypedObject* createUnattached(JSContext* cx, HandleTypeDescr type,
-                                                int32_t length, gc::InitialHeap heap = gc::DefaultHeap);
+                                                gc::InitialHeap heap = gc::DefaultHeap);
 
     // Creates a typedObj that aliases the memory pointed at by `owner`
     // at the given offset. The typedObj will be a handle iff type is a
     // handle and a typed object otherwise.
     static OutlineTypedObject* createDerived(JSContext* cx,
                                              HandleTypeDescr type,
                                              Handle<TypedObject*> typedContents,
                                              uint32_t offset);
@@ -697,25 +695,33 @@ class OutlineOpaqueTypedObject : public 
 // Class for a typed object whose data is allocated inline.
 class InlineTypedObject : public TypedObject
 {
     friend class TypedObject;
 
     // Start of the inline data, which immediately follows the shape and type.
     uint8_t data_[1];
 
+    static const size_t MaximumSize = JSObject::MAX_BYTE_SIZE - sizeof(TypedObject);
+
   protected:
     uint8_t* inlineTypedMem() const {
         return (uint8_t*) &data_;
     }
 
   public:
-    static const size_t MaximumSize = JSObject::MAX_BYTE_SIZE - sizeof(TypedObject);
+    static inline gc::AllocKind allocKindForTypeDescriptor(TypeDescr* descr);
 
-    static inline gc::AllocKind allocKindForTypeDescriptor(TypeDescr* descr);
+    static bool canAccommodateSize(size_t size) {
+        return size <= MaximumSize;
+    }
+
+    static bool canAccommodateType(TypeDescr* type) {
+        return type->size() <= MaximumSize;
+    }
 
     uint8_t* inlineTypedMem(const JS::AutoRequireNoGC&) const {
         return inlineTypedMem();
     }
 
     uint8_t* inlineTypedMemForGC() const {
         return inlineTypedMem();
     }
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -1333,18 +1333,22 @@ GCRuntime::finish()
     /* Free memory associated with GC verification. */
     finishVerifier();
 #endif
 
     /* Delete all remaining zones. */
     if (rt->gcInitialized) {
         AutoSetThreadIsSweeping threadIsSweeping;
         for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
-            for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next())
-                js_delete(JS::GetRealmForCompartment(comp.get()));
+            for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
+                for (RealmsInCompartmentIter realm(comp); !realm.done(); realm.next())
+                    js_delete(realm.get());
+                comp->realms().clear();
+                js_delete(comp.get());
+            }
             zone->compartments().clear();
             js_delete(zone.get());
         }
     }
 
     zones().clear();
 
     FreeChunkPool(fullChunks_.ref());
@@ -3815,20 +3819,27 @@ JS::Zone::sweepUniqueIds()
 }
 
 void
 Realm::destroy(FreeOp* fop)
 {
     JSRuntime* rt = fop->runtime();
     if (auto callback = rt->destroyRealmCallback)
         callback(fop, this);
+    if (principals())
+        JS_DropPrincipals(rt->mainContextFromOwnThread(), principals());
+    fop->delete_(this);
+}
+
+void
+JSCompartment::destroy(FreeOp* fop)
+{
+    JSRuntime* rt = fop->runtime();
     if (auto callback = rt->destroyCompartmentCallback)
         callback(fop, this);
-    if (principals())
-        JS_DropPrincipals(rt->mainContextFromOwnThread(), principals());
     fop->delete_(this);
     rt->gc.stats().sweptCompartment();
 }
 
 void
 Zone::destroy(FreeOp* fop)
 {
     MOZ_ASSERT(compartments().empty());
@@ -3851,32 +3862,63 @@ Zone::sweepCompartments(FreeOp* fop, boo
     MOZ_ASSERT(!compartments().empty());
     MOZ_ASSERT_IF(destroyingRuntime, !keepAtleastOne);
 
     JSCompartment** read = compartments().begin();
     JSCompartment** end = compartments().end();
     JSCompartment** write = read;
     while (read < end) {
         JSCompartment* comp = *read++;
-        Realm* realm = JS::GetRealmForCompartment(comp);
 
         /*
          * Don't delete the last compartment and realm if keepAtleastOne is
          * still true, meaning all the other compartments were deleted.
          */
-        bool dontDelete = read == end && keepAtleastOne;
-        if ((realm->marked() || dontDelete) && !destroyingRuntime) {
+        bool keepAtleastOneRealm = read == end && keepAtleastOne;
+        comp->sweepRealms(fop, keepAtleastOneRealm, destroyingRuntime);
+
+        if (!comp->realms().empty()) {
             *write++ = comp;
             keepAtleastOne = false;
         } else {
-            realm->destroy(fop);
+            comp->destroy(fop);
         }
     }
     compartments().shrinkTo(write - compartments().begin());
     MOZ_ASSERT_IF(keepAtleastOne, !compartments().empty());
+    MOZ_ASSERT_IF(destroyingRuntime, compartments().empty());
+}
+
+void
+JSCompartment::sweepRealms(FreeOp* fop, bool keepAtleastOne, bool destroyingRuntime)
+{
+    MOZ_ASSERT(!realms().empty());
+    MOZ_ASSERT_IF(destroyingRuntime, !keepAtleastOne);
+
+    Realm** read = realms().begin();
+    Realm** end = realms().end();
+    Realm** write = read;
+    while (read < end) {
+        Realm* realm = *read++;
+
+        /*
+         * Don't delete the last realm if keepAtleastOne is still true, meaning
+         * all the other realms were deleted.
+         */
+        bool dontDelete = read == end && keepAtleastOne;
+        if ((realm->marked() || dontDelete) && !destroyingRuntime) {
+            *write++ = realm;
+            keepAtleastOne = false;
+        } else {
+            realm->destroy(fop);
+        }
+    }
+    realms().shrinkTo(write - realms().begin());
+    MOZ_ASSERT_IF(keepAtleastOne, !realms().empty());
+    MOZ_ASSERT_IF(destroyingRuntime, realms().empty());
 }
 
 void
 GCRuntime::deleteEmptyZone(Zone* zone)
 {
     MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
     MOZ_ASSERT(zone->compartments().empty());
     for (auto& i : zones()) {
@@ -7947,16 +7989,17 @@ AutoPrepareForTracing::AutoPrepareForTra
 
 Realm*
 js::NewRealm(JSContext* cx, JSPrincipals* principals, const JS::RealmOptions& options)
 {
     JSRuntime* rt = cx->runtime();
     JS_AbortIfWrongThread(cx);
 
     UniquePtr<Zone> zoneHolder;
+    UniquePtr<JSCompartment> compHolder;
 
     Zone* zone = nullptr;
     JS::ZoneSpecifier zoneSpec = options.creationOptions().zoneSpecifier();
     switch (zoneSpec) {
       case JS::SystemZone:
         // systemZone might be null here, in which case we'll make a zone and
         // set this field below.
         zone = rt->gc.systemZone;
@@ -7979,24 +8022,28 @@ js::NewRealm(JSContext* cx, JSPrincipals
         if (!zoneHolder->init(isSystem)) {
             ReportOutOfMemory(cx);
             return nullptr;
         }
 
         zone = zoneHolder.get();
     }
 
-    UniquePtr<Realm> realm = cx->make_unique<Realm>(zone, options);
+    compHolder = cx->make_unique<JSCompartment>(zone);
+    if (!compHolder || !compHolder->init(cx))
+        return nullptr;
+
+    JSCompartment* comp = compHolder.get();
+    UniquePtr<Realm> realm(cx->new_<Realm>(comp, options));
     if (!realm || !realm->init(cx))
         return nullptr;
 
     // Set up the principals.
     JS::SetRealmPrincipals(realm.get(), principals);
 
-    JSCompartment* comp = realm->compartment();
     if (!comp->realms().append(realm.get())) {
         ReportOutOfMemory(cx);
         return nullptr;
     }
 
     AutoLockGC lock(rt);
 
     if (!zone->compartments().append(comp)) {
@@ -8013,16 +8060,17 @@ js::NewRealm(JSContext* cx, JSPrincipals
         // Lazily set the runtime's sytem zone.
         if (zoneSpec == JS::SystemZone) {
             MOZ_RELEASE_ASSERT(!rt->gc.systemZone);
             rt->gc.systemZone = zone;
             zone->isSystem = true;
         }
     }
 
+    mozilla::Unused << compHolder.release();
     mozilla::Unused << zoneHolder.release();
     return realm.release();
 }
 
 void
 gc::MergeRealms(Realm* source, Realm* target)
 {
     JSRuntime* rt = source->runtimeFromMainThread();
--- a/js/src/gc/PublicIterators.cpp
+++ b/js/src/gc/PublicIterators.cpp
@@ -150,8 +150,21 @@ JS::IterateRealms(JSContext* cx, void* d
     AutoTraceSession session(cx->runtime());
 
     Rooted<Realm*> realm(cx);
     for (RealmsIter r(cx->runtime()); !r.done(); r.next()) {
         realm = r;
         (*realmCallback)(cx, data, realm);
     }
 }
+
+JS_PUBLIC_API(void)
+JS::IterateRealmsInCompartment(JSContext* cx, JSCompartment* compartment, void* data,
+                               JS::IterateRealmCallback realmCallback)
+{
+    AutoTraceSession session(cx->runtime());
+
+    Rooted<Realm*> realm(cx);
+    for (RealmsInCompartmentIter r(compartment); !r.done(); r.next()) {
+        realm = r;
+        (*realmCallback)(cx, data, realm);
+    }
+}
--- a/js/src/gc/Zone.cpp
+++ b/js/src/gc/Zone.cpp
@@ -397,17 +397,19 @@ Zone::deleteEmptyCompartment(JSCompartme
     MOZ_ASSERT(comp->zone() == this);
     MOZ_ASSERT(arenas.checkEmptyArenaLists());
 
     MOZ_ASSERT(compartments().length() == 1);
     MOZ_ASSERT(compartments()[0] == comp);
     MOZ_ASSERT(comp->realms().length() == 1);
 
     Realm* realm = comp->realms()[0];
-    realm->destroy(runtimeFromMainThread()->defaultFreeOp());
+    FreeOp* fop = runtimeFromMainThread()->defaultFreeOp();
+    realm->destroy(fop);
+    comp->destroy(fop);
 
     compartments().clear();
 }
 
 void
 Zone::setHelperThreadOwnerContext(JSContext* cx)
 {
     MOZ_ASSERT_IF(cx, TlsContext.get() == cx);
--- a/js/src/gc/Zone.h
+++ b/js/src/gc/Zone.h
@@ -196,17 +196,20 @@ struct Zone : public JS::shadow::Zone,
     void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
                                 size_t* typePool,
                                 size_t* regexpZone,
                                 size_t* jitZone,
                                 size_t* baselineStubsOptimized,
                                 size_t* cachedCFG,
                                 size_t* uniqueIdMap,
                                 size_t* shapeTables,
-                                size_t* atomsMarkBitmaps);
+                                size_t* atomsMarkBitmaps,
+                                size_t* compartmentObjects,
+                                size_t* crossCompartmentWrappersTables,
+                                size_t* compartmentsPrivateData);
 
     // Iterate over all cells in the zone. See the definition of ZoneCellIter
     // in gc/GC-inl.h for the possible arguments and documentation.
     template <typename T, typename... Args>
     js::gc::ZoneCellIter<T> cellIter(Args&&... args) {
         return js::gc::ZoneCellIter<T>(const_cast<Zone*>(this), std::forward<Args>(args)...);
     }
 
--- a/js/src/jit-test/lib/wasm-binary.js
+++ b/js/src/jit-test/lib/wasm-binary.js
@@ -89,17 +89,17 @@ const I64TruncSF32Code = 0xae;
 const I64TruncUF32Code = 0xaf;
 const I64TruncSF64Code = 0xb0;
 const I64TruncUF64Code = 0xb1;
 const I64DivSCode      = 0x7f;
 const I64DivUCode      = 0x80;
 const I64RemSCode      = 0x81;
 const I64RemUCode      = 0x82;
 
-const FirstInvalidOpcode = wasmThreadsSupported() ? 0xc5 : 0xc0;
+const FirstInvalidOpcode = 0xc5;
 const LastInvalidOpcode = 0xfb;
 const MiscPrefix = 0xfc;
 const SimdPrefix = 0xfd;
 const ThreadPrefix = 0xfe;
 const MozPrefix = 0xff;
 
 // DefinitionKind
 const FunctionCode     = 0x00;
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/modules/bug-1466487.js
@@ -0,0 +1,7 @@
+if (helperThreadCount() === 0)
+    quit();
+evalInWorker(`
+    let m = parseModule("import.meta;");
+    m.declarationInstantiation();
+    m.evaluation();
+`);
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -1892,17 +1892,17 @@ GetTemplateObjectForNative(JSContext* cx
 }
 
 static bool
 GetTemplateObjectForClassHook(JSContext* cx, JSNative hook, CallArgs& args,
                               MutableHandleObject templateObject)
 {
     if (hook == TypedObject::construct) {
         Rooted<TypeDescr*> descr(cx, &args.callee().as<TypeDescr>());
-        templateObject.set(TypedObject::createZeroed(cx, descr, 1, gc::TenuredHeap));
+        templateObject.set(TypedObject::createZeroed(cx, descr, gc::TenuredHeap));
         return !!templateObject;
     }
 
     if (hook == SimdTypeDescr::call && JitSupportsSimd()) {
         Rooted<SimdTypeDescr*> descr(cx, &args.callee().as<SimdTypeDescr>());
         templateObject.set(cx->realm()->jitRealm()->getSimdTemplateObjectFor(cx, descr));
         return !!templateObject;
     }
--- a/js/src/jit/JitRealm.h
+++ b/js/src/jit/JitRealm.h
@@ -511,17 +511,17 @@ class JitRealm
         *requiredBarriersOut |= 1 << uint32_t(stub);
         return stubs_[stub].unbarrieredGet();
     }
 
   public:
     JSObject* getSimdTemplateObjectFor(JSContext* cx, Handle<SimdTypeDescr*> descr) {
         ReadBarrieredObject& tpl = simdTemplateObjects_[descr->type()];
         if (!tpl)
-            tpl.set(TypedObject::createZeroed(cx, descr, 0, gc::TenuredHeap));
+            tpl.set(TypedObject::createZeroed(cx, descr, gc::TenuredHeap));
         return tpl.get();
     }
 
     JSObject* maybeGetSimdTemplateObjectFor(SimdType type) const {
         // This function is used by Eager Simd Unbox phase which can run
         // off-thread, so we cannot use the usual read barrier. For more
         // information, see the comment above
         // CodeGenerator::simdRefreshTemplatesDuringLink_.
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -3765,17 +3765,17 @@ IonBuilder::InliningResult
 IonBuilder::inlineConstructTypedObject(CallInfo& callInfo, TypeDescr* descr)
 {
     // Only inline default constructors for now.
     if (callInfo.argc() != 0) {
         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
         return InliningStatus_NotInlined;
     }
 
-    if (size_t(descr->size()) > InlineTypedObject::MaximumSize)
+    if (!InlineTypedObject::canAccommodateType(descr))
         return InliningStatus_NotInlined;
 
     JSObject* obj = inspector->getTemplateObjectForClassHook(pc, descr->getClass());
     if (!obj || !obj->is<InlineTypedObject>())
         return InliningStatus_NotInlined;
 
     InlineTypedObject* templateObject = &obj->as<InlineTypedObject>();
     if (&templateObject->typeDescr() != descr)
@@ -3991,17 +3991,17 @@ IonBuilder::inlineConstructSimdObject(Ca
     MIRType simdType;
     if (!MaybeSimdTypeToMIRType(descr->type(), &simdType)) {
         trackOptimizationOutcome(TrackedOutcome::SimdTypeNotOptimized);
         return InliningStatus_NotInlined;
     }
 
     // Take the templateObject out of Baseline ICs, such that we can box
     // SIMD value type in the same kind of objects.
-    MOZ_ASSERT(size_t(descr->size(descr->type())) < InlineTypedObject::MaximumSize);
+    MOZ_ASSERT(InlineTypedObject::canAccommodateType(descr));
     MOZ_ASSERT(descr->getClass() == &SimdTypeDescr::class_,
                "getTemplateObjectForSimdCtor needs an update");
 
     JSObject* templateObject = inspector->getTemplateObjectForSimdCtor(pc, descr->type());
     if (!templateObject)
         return InliningStatus_NotInlined;
 
     // The previous assertion ensures this will never fail if we were able to
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -617,22 +617,16 @@ JS_SetDestroyCompartmentCallback(JSConte
 
 JS_PUBLIC_API(void)
 JS_SetSizeOfIncludingThisCompartmentCallback(JSContext* cx,
                                              JSSizeOfIncludingThisCompartmentCallback callback)
 {
     cx->runtime()->sizeOfIncludingThisCompartmentCallback = callback;
 }
 
-JS_PUBLIC_API(void)
-JS_SetCompartmentNameCallback(JSContext* cx, JSCompartmentNameCallback callback)
-{
-    cx->runtime()->compartmentNameCallback = callback;
-}
-
 #if defined(NIGHTLY_BUILD)
 JS_PUBLIC_API(void)
 JS_SetErrorInterceptorCallback(JSRuntime* rt, JSErrorInterceptor* callback)
 {
     rt->errorInterception.interceptor = callback;
 }
 
 JS_PUBLIC_API(JSErrorInterceptor*)
@@ -1855,19 +1849,19 @@ JS::RealmCreationOptions&
 JS::RealmCreationOptions::setNewZone()
 {
     zoneSpec_ = JS::NewZone;
     zone_ = nullptr;
     return *this;
 }
 
 const JS::RealmCreationOptions&
-JS::RealmCreationOptionsRef(JSCompartment* compartment)
-{
-    return JS::GetRealmForCompartment(compartment)->creationOptions();
+JS::RealmCreationOptionsRef(Realm* realm)
+{
+    return realm->creationOptions();
 }
 
 const JS::RealmCreationOptions&
 JS::RealmCreationOptionsRef(JSContext* cx)
 {
     return cx->realm()->creationOptions();
 }
 
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -959,19 +959,16 @@ JS_GetImplementationVersion(void);
 extern JS_PUBLIC_API(void)
 JS_SetDestroyCompartmentCallback(JSContext* cx, JSDestroyCompartmentCallback callback);
 
 extern JS_PUBLIC_API(void)
 JS_SetSizeOfIncludingThisCompartmentCallback(JSContext* cx,
                                              JSSizeOfIncludingThisCompartmentCallback callback);
 
 extern JS_PUBLIC_API(void)
-JS_SetCompartmentNameCallback(JSContext* cx, JSCompartmentNameCallback callback);
-
-extern JS_PUBLIC_API(void)
 JS_SetWrapObjectCallbacks(JSContext* cx, const JSWrapObjectCallbacks* callbacks);
 
 extern JS_PUBLIC_API(void)
 JS_SetExternalStringSizeofCallback(JSContext* cx, JSExternalStringSizeofCallback callback);
 
 #if defined(NIGHTLY_BUILD)
 
 // Set a callback that will be called whenever an error
@@ -1103,16 +1100,23 @@ using IterateRealmCallback = void (*)(JS
 /**
  * This function calls |realmCallback| on every realm. Beware that there is no
  * guarantee that the realm will survive after the callback returns. Also,
  * barriers are disabled via the TraceSession.
  */
 extern JS_PUBLIC_API(void)
 IterateRealms(JSContext* cx, void* data, IterateRealmCallback realmCallback);
 
+/**
+ * Like IterateRealms, but only iterates realms in |compartment|.
+ */
+extern JS_PUBLIC_API(void)
+IterateRealmsInCompartment(JSContext* cx, JSCompartment* compartment, void* data,
+                           IterateRealmCallback realmCallback);
+
 } // namespace JS
 
 typedef void (*JSIterateCompartmentCallback)(JSContext* cx, void* data, JSCompartment* compartment);
 
 /**
  * This function calls |compartmentCallback| on every compartment. Beware that
  * there is no guarantee that the compartment will survive after the callback
  * returns. Also, barriers are disabled via the TraceSession.
@@ -1947,17 +1951,17 @@ class JS_PUBLIC_API(RealmOptions)
     }
 
   private:
     RealmCreationOptions creationOptions_;
     RealmBehaviors behaviors_;
 };
 
 JS_PUBLIC_API(const RealmCreationOptions&)
-RealmCreationOptionsRef(JSCompartment* compartment);
+RealmCreationOptionsRef(JS::Realm* realm);
 
 JS_PUBLIC_API(const RealmCreationOptions&)
 RealmCreationOptionsRef(JSContext* cx);
 
 JS_PUBLIC_API(RealmBehaviors&)
 RealmBehaviorsRef(JS::Realm* realm);
 
 JS_PUBLIC_API(RealmBehaviors&)
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -152,18 +152,21 @@ JS_FRIEND_API(bool)
 JS::GetIsSecureContext(JS::Realm* realm)
 {
     return realm->creationOptions().secureContext();
 }
 
 JS_FRIEND_API(JSPrincipals*)
 JS_GetCompartmentPrincipals(JSCompartment* compartment)
 {
-    Realm* realm = JS::GetRealmForCompartment(compartment);
-    return realm->principals();
+    // Note: for now we assume a single realm per compartment. This API will go
+    // away after we remove the remaining callers. See bug 1465700.
+    MOZ_RELEASE_ASSERT(compartment->realms().length() == 1);
+
+    return compartment->realms()[0]->principals();
 }
 
 JS_FRIEND_API(JSPrincipals*)
 JS::GetRealmPrincipals(JS::Realm* realm)
 {
     return realm->principals();
 }
 
@@ -201,20 +204,20 @@ JS::SetRealmPrincipals(JS::Realm* realm,
 }
 
 JS_FRIEND_API(JSPrincipals*)
 JS_GetScriptPrincipals(JSScript* script)
 {
     return script->principals();
 }
 
-JS_FRIEND_API(JSCompartment*)
-js::GetScriptCompartment(JSScript* script)
+JS_FRIEND_API(JS::Realm*)
+js::GetScriptRealm(JSScript* script)
 {
-    return script->compartment();
+    return script->realm();
 }
 
 JS_FRIEND_API(bool)
 JS_ScriptHasMutedErrors(JSScript* script)
 {
     return script->mutedErrors();
 }
 
@@ -333,25 +336,37 @@ js::GetBuiltinClass(JSContext* cx, Handl
 JS_FRIEND_API(const char*)
 js::ObjectClassName(JSContext* cx, HandleObject obj)
 {
     assertSameCompartment(cx, obj);
     return GetObjectClassName(cx, obj);
 }
 
 JS_FRIEND_API(JS::Zone*)
-js::GetCompartmentZone(JSCompartment* comp)
+js::GetRealmZone(JS::Realm* realm)
 {
-    return comp->zone();
+    return realm->zone();
 }
 
 JS_FRIEND_API(bool)
 js::IsSystemCompartment(JSCompartment* comp)
 {
-    return JS::GetRealmForCompartment(comp)->isSystem();
+    // Note: for now we assume a single realm per compartment. This API will
+    // hopefully go away once Gecko supports same-compartment realms. Another
+    // option is to return comp->zone()->isSystem here, but we'd have to make
+    // sure that's equivalent.
+    MOZ_RELEASE_ASSERT(comp->realms().length() == 1);
+
+    return comp->realms()[0]->isSystem();
+}
+
+JS_FRIEND_API(bool)
+js::IsSystemRealm(JS::Realm* realm)
+{
+    return realm->isSystem();
 }
 
 JS_FRIEND_API(bool)
 js::IsSystemZone(Zone* zone)
 {
     return zone->isSystem;
 }
 
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -186,18 +186,18 @@ JS_SetSetUseCounterCallback(JSContext* c
 
 extern JS_FRIEND_API(JSPrincipals*)
 JS_GetCompartmentPrincipals(JSCompartment* compartment);
 
 extern JS_FRIEND_API(JSPrincipals*)
 JS_GetScriptPrincipals(JSScript* script);
 
 namespace js {
-extern JS_FRIEND_API(JSCompartment*)
-GetScriptCompartment(JSScript* script);
+extern JS_FRIEND_API(JS::Realm*)
+GetScriptRealm(JSScript* script);
 } /* namespace js */
 
 extern JS_FRIEND_API(bool)
 JS_ScriptHasMutedErrors(JSScript* script);
 
 extern JS_FRIEND_API(JSObject*)
 JS_CloneObject(JSContext* cx, JS::HandleObject obj, JS::HandleObject proto);
 
@@ -453,17 +453,17 @@ EnqueueJob(JSContext* cx, JS::HandleObje
  */
 extern JS_FRIEND_API(void)
 StopDrainingJobQueue(JSContext* cx);
 
 extern JS_FRIEND_API(void)
 RunJobs(JSContext* cx);
 
 extern JS_FRIEND_API(JS::Zone*)
-GetCompartmentZone(JSCompartment* comp);
+GetRealmZone(JS::Realm* realm);
 
 typedef bool
 (* PreserveWrapperCallback)(JSContext* cx, JSObject* obj);
 
 typedef enum  {
     CollectNurseryBeforeDump,
     IgnoreNurseryObjects
 } DumpHeapNurseryBehaviour;
@@ -476,16 +476,19 @@ extern JS_FRIEND_API(void)
 DumpHeap(JSContext* cx, FILE* fp, DumpHeapNurseryBehaviour nurseryBehaviour);
 
 #ifdef JS_OLD_GETTER_SETTER_METHODS
 JS_FRIEND_API(bool) obj_defineGetter(JSContext* cx, unsigned argc, JS::Value* vp);
 JS_FRIEND_API(bool) obj_defineSetter(JSContext* cx, unsigned argc, JS::Value* vp);
 #endif
 
 extern JS_FRIEND_API(bool)
+IsSystemRealm(JS::Realm* realm);
+
+extern JS_FRIEND_API(bool)
 IsSystemCompartment(JSCompartment* comp);
 
 extern JS_FRIEND_API(bool)
 IsSystemZone(JS::Zone* zone);
 
 extern JS_FRIEND_API(bool)
 IsAtomsZone(JS::Zone* zone);
 
--- a/js/src/proxy/Wrapper.cpp
+++ b/js/src/proxy/Wrapper.cpp
@@ -442,17 +442,17 @@ js::TransparentObjectWrapper(JSContext* 
 }
 
 ErrorCopier::~ErrorCopier()
 {
     JSContext* cx = ar->context();
 
     // The provenance of Debugger.DebuggeeWouldRun is the topmost locking
     // debugger compartment; it should not be copied around.
-    if (JS::GetCompartmentForRealm(ar->origin()) != cx->compartment() &&
+    if (ar->origin()->compartment() != cx->compartment() &&
         cx->isExceptionPending() &&
         !cx->isThrowingDebuggeeWouldRun())
     {
         RootedValue exc(cx);
         if (cx->getPendingException(&exc) && exc.isObject() && exc.toObject().is<ErrorObject>()) {
             cx->clearPendingException();
             ar.reset();
             Rooted<ErrorObject*> errObj(cx, &exc.toObject().as<ErrorObject>());
--- a/js/src/vm/CodeCoverage.cpp
+++ b/js/src/vm/CodeCoverage.cpp
@@ -551,23 +551,23 @@ LCovRealm::writeRealmName(JS::Realm* rea
 
     // lcov trace files are starting with an optional test case name, that we
     // recycle to be a realm name.
     //
     // Note: The test case name has some constraint in terms of valid character,
     // thus we escape invalid chracters with a "_" symbol in front of its
     // hexadecimal code.
     outTN_.put("TN:");
-    if (cx->runtime()->compartmentNameCallback) {
+    if (cx->runtime()->realmNameCallback) {
         char name[1024];
         {
             // Hazard analysis cannot tell that the callback does not GC.
             JS::AutoSuppressGCAnalysis nogc;
-            JSCompartment* comp = JS::GetCompartmentForRealm(realm);
-            (*cx->runtime()->compartmentNameCallback)(cx, comp, name, sizeof(name));
+            Rooted<Realm*> rootedRealm(cx, realm);
+            (*cx->runtime()->realmNameCallback)(cx, rootedRealm, name, sizeof(name));
         }
         for (char *s = name; s < name + sizeof(name) && *s; s++) {
             if (('a' <= *s && *s <= 'z') ||
                 ('A' <= *s && *s <= 'Z') ||
                 ('0' <= *s && *s <= '9'))
             {
                 outTN_.put(s, 1);
                 continue;
--- a/js/src/vm/JSCompartment.cpp
+++ b/js/src/vm/JSCompartment.cpp
@@ -50,24 +50,26 @@ ObjectRealm::ObjectRealm(JS::Zone* zone)
   : innerViews(zone)
 {}
 
 ObjectRealm::~ObjectRealm()
 {
     MOZ_ASSERT(enumerators == iteratorSentinel_.get());
 }
 
-Realm::Realm(JS::Zone* zone, const JS::RealmOptions& options)
-  : JSCompartment(zone),
+Realm::Realm(JSCompartment* comp, const JS::RealmOptions& options)
+  : JS::shadow::Realm(comp),
+    zone_(comp->zone()),
+    runtime_(comp->runtimeFromMainThread()),
     creationOptions_(options.creationOptions()),
     behaviors_(options.behaviors()),
     global_(nullptr),
-    objects_(zone),
+    objects_(zone_),
     randomKeyGenerator_(runtime_->forkRandomKeyGenerator()),
-    wasm(zone->runtimeFromMainThread()),
+    wasm(runtime_),
     performanceMonitoring(runtime_)
 {
     MOZ_ASSERT_IF(creationOptions_.mergeable(),
                   creationOptions_.invisibleToDebugger());
 
     runtime_->numRealms++;
 }
 
@@ -115,21 +117,16 @@ ObjectRealm::init(JSContext* cx)
     iteratorSentinel_ = std::move(sentinel);
     enumerators = iteratorSentinel_.get();
     return true;
 }
 
 bool
 Realm::init(JSContext* cx)
 {
-    // Initialize JSCompartment. This is temporary until Realm and
-    // JSCompartment are completely separated.
-    if (!JSCompartment::init(cx))
-        return false;
-
     /*
      * As a hack, we clear our timezone cache every time we create a new realm.
      * This ensures that the cache is always relatively fresh, but shouldn't
      * interfere with benchmarks that create tons of date objects (unless they
      * also create tons of iframes, which seems unlikely).
      */
     JS::ResetTimeZone();
 
@@ -1032,17 +1029,17 @@ Realm::purge()
 
 void
 Realm::clearTables()
 {
     global_.set(nullptr);
 
     // No scripts should have run in this realm. This is used when merging
     // a realm that has been used off thread into another realm and zone.
-    JS::GetCompartmentForRealm(this)->assertNoCrossCompartmentWrappers();
+    compartment()->assertNoCrossCompartmentWrappers();
     MOZ_ASSERT(!jitRealm_);
     MOZ_ASSERT(!debugEnvs_);
     MOZ_ASSERT(objects_.enumerators->next() == objects_.enumerators);
 
     objectGroups_.clearTables();
     if (savedStacks_.initialized())
         savedStacks_.clear();
     if (varNames_.initialized())
@@ -1071,17 +1068,17 @@ Realm::forgetAllocationMetadataBuilder()
 
     allocationMetadataBuilder_ = nullptr;
 }
 
 void
 Realm::setNewObjectMetadata(JSContext* cx, HandleObject obj)
 {
     MOZ_ASSERT(obj->realm() == this);
-    assertSameCompartment(cx, JS::GetCompartmentForRealm(this), obj);
+    assertSameCompartment(cx, compartment(), obj);
 
     AutoEnterOOMUnsafeRegion oomUnsafe;
     if (JSObject* metadata = allocationMetadataBuilder_->build(cx, obj, oomUnsafe)) {
         MOZ_ASSERT(metadata->realm() == obj->realm());
         assertSameCompartment(cx, metadata);
 
         if (!objects_.objectMetadataTable) {
             auto table = cx->make_unique<ObjectWeakMap>(cx);
@@ -1306,23 +1303,26 @@ Realm::clearBreakpointsIn(FreeOp* fop, j
 {
     for (auto script = zone()->cellIter<JSScript>(); !script.done(); script.next()) {
         if (script->realm() == this && script->hasAnyBreakpointsOrStepMode())
             script->clearBreakpointsIn(fop, dbg, handler);
     }
 }
 
 void
-JSCompartment::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
-                                      size_t* crossCompartmentWrappersArg)
+JSCompartment::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
+                                      size_t* compartmentObjects,
+                                      size_t* crossCompartmentWrappersTables,
+                                      size_t* compartmentsPrivateData)
 {
-    // Note that Realm inherits from JSCompartment (for now) so sizeof(*this) is
-    // included in that.
+    *compartmentObjects += mallocSizeOf(this);
+    *crossCompartmentWrappersTables += crossCompartmentWrappers.sizeOfExcludingThis(mallocSizeOf);
 
-    *crossCompartmentWrappersArg += crossCompartmentWrappers.sizeOfExcludingThis(mallocSizeOf);
+    if (auto callback = runtime_->sizeOfIncludingThisCompartmentCallback)
+        *compartmentsPrivateData += callback(mallocSizeOf, this);
 }
 
 void
 ObjectRealm::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
                                     size_t* innerViewsArg,
                                     size_t* lazyArrayBuffersArg,
                                     size_t* objectMetadataTablesArg,
                                     size_t* nonSyntacticLexicalEnvironmentsArg)
@@ -1344,27 +1344,22 @@ Realm::addSizeOfIncludingThis(mozilla::M
                               size_t* tiAllocationSiteTables,
                               size_t* tiArrayTypeTables,
                               size_t* tiObjectTypeTables,
                               size_t* realmObject,
                               size_t* realmTables,
                               size_t* innerViewsArg,
                               size_t* lazyArrayBuffersArg,
                               size_t* objectMetadataTablesArg,
-                              size_t* crossCompartmentWrappersArg,
                               size_t* savedStacksSet,
                               size_t* varNamesSet,
                               size_t* nonSyntacticLexicalEnvironmentsArg,
                               size_t* jitRealm,
-                              size_t* privateData,
                               size_t* scriptCountsMapArg)
 {
-    // This is temporary until Realm and JSCompartment are completely separated.
-    JSCompartment::addSizeOfExcludingThis(mallocSizeOf, crossCompartmentWrappersArg);
-
     *realmObject += mallocSizeOf(this);
     objectGroups_.addSizeOfExcludingThis(mallocSizeOf, tiAllocationSiteTables,
                                          tiArrayTypeTables, tiObjectTypeTables,
                                          realmTables);
     wasm.addSizeOfExcludingThis(mallocSizeOf, realmTables);
 
     objects_.addSizeOfExcludingThis(mallocSizeOf,
                                     innerViewsArg,
@@ -1373,25 +1368,20 @@ Realm::addSizeOfIncludingThis(mozilla::M
                                     nonSyntacticLexicalEnvironmentsArg);
 
     *savedStacksSet += savedStacks_.sizeOfExcludingThis(mallocSizeOf);
     *varNamesSet += varNames_.sizeOfExcludingThis(mallocSizeOf);
 
     if (jitRealm_)
         *jitRealm += jitRealm_->sizeOfIncludingThis(mallocSizeOf);
 
-    auto callback = runtime_->sizeOfIncludingThisCompartmentCallback;
-    if (callback)
-        *privateData += callback(mallocSizeOf, this);
-
     if (scriptCountsMap) {
         *scriptCountsMapArg += scriptCountsMap->sizeOfIncludingThis(mallocSizeOf);
-        for (auto r = scriptCountsMap->all(); !r.empty(); r.popFront()) {
+        for (auto r = scriptCountsMap->all(); !r.empty(); r.popFront())
             *scriptCountsMapArg += r.front().value()->sizeOfIncludingThis(mallocSizeOf);
-        }
     }
 }
 
 mozilla::HashCodeScrambler
 Realm::randomHashCodeScrambler()
 {
     return mozilla::HashCodeScrambler(randomKeyGenerator_.next(),
                                       randomKeyGenerator_.next());
--- a/js/src/vm/JSCompartment.h
+++ b/js/src/vm/JSCompartment.h
@@ -547,21 +547,20 @@ struct IteratorHashPolicy
 namespace js {
 class DebugEnvironments;
 class ObjectWeakMap;
 class WeakMapBase;
 } // namespace js
 
 struct JSCompartment
 {
-  protected:
+  private:
     JS::Zone*                    zone_;
     JSRuntime*                   runtime_;
 
-  private:
     js::WrapperMap crossCompartmentWrappers;
 
     using RealmVector = js::Vector<JS::Realm*, 1, js::SystemAllocPolicy>;
     RealmVector realms_;
 
   public:
     /*
      * During GC, stores the head of a list of incoming pointers from gray cells.
@@ -598,35 +597,35 @@ struct JSCompartment
     RealmVector& realms() {
         return realms_;
     }
 
     void assertNoCrossCompartmentWrappers() {
         MOZ_ASSERT(crossCompartmentWrappers.empty());
     }
 
-  protected:
-    void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
-                                size_t* crossCompartmentWrappersArg);
+    void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
+                                size_t* compartmentObjects,
+                                size_t* crossCompartmentWrappersTables,
+                                size_t* compartmentsPrivateData);
 
-  public:
 #ifdef JSGC_HASH_TABLE_CHECKS
     void checkWrapperMapAfterMovingGC();
 #endif
 
   private:
     bool getNonWrapperObjectForCurrentCompartment(JSContext* cx, js::MutableHandleObject obj);
     bool getOrCreateWrapper(JSContext* cx, js::HandleObject existing, js::MutableHandleObject obj);
 
-  protected:
+  public:
     explicit JSCompartment(JS::Zone* zone);
 
     MOZ_MUST_USE bool init(JSContext* cx);
+    void destroy(js::FreeOp* fop);
 
-  public:
     MOZ_MUST_USE inline bool wrap(JSContext* cx, JS::MutableHandleValue vp);
 
     MOZ_MUST_USE bool wrap(JSContext* cx, js::MutableHandleString strp);
 #ifdef ENABLE_BIGINT
     MOZ_MUST_USE bool wrap(JSContext* cx, js::MutableHandle<JS::BigInt*> bi);
 #endif
     MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandleObject obj);
     MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandle<js::PropertyDescriptor> desc);
@@ -670,18 +669,18 @@ struct JSCompartment
      * These methods mark pointers that cross compartment boundaries. They are
      * called in per-zone GCs to prevent the wrappers' outgoing edges from
      * dangling (full GCs naturally follow pointers across compartments) and
      * when compacting to update cross-compartment pointers.
      */
     void traceOutgoingCrossCompartmentWrappers(JSTracer* trc);
     static void traceIncomingCrossCompartmentEdgesForZoneGC(JSTracer* trc);
 
+    void sweepRealms(js::FreeOp* fop, bool keepAtleastOne, bool destroyingRuntime);
     void sweepAfterMinorGC(JSTracer* trc);
-
     void sweepCrossCompartmentWrappers();
 
     static void fixupCrossCompartmentWrappersAfterMovingGC(JSTracer* trc);
     void fixupAfterMovingGC();
 
     void findOutgoingEdges(js::gc::ZoneComponentFinder& finder);
 };
 
@@ -747,18 +746,21 @@ class ObjectRealm
 
     js::LexicalEnvironmentObject*
     getOrCreateNonSyntacticLexicalEnvironment(JSContext* cx, js::HandleObject enclosing);
     js::LexicalEnvironmentObject* getNonSyntacticLexicalEnvironment(JSObject* enclosing) const;
 };
 
 } // namespace js
 
-class JS::Realm : private JSCompartment
+class JS::Realm : public JS::shadow::Realm
 {
+    JS::Zone* zone_;
+    JSRuntime* runtime_;
+
     const JS::RealmCreationOptions creationOptions_;
     JS::RealmBehaviors behaviors_;
 
     friend struct ::JSContext;
     js::ReadBarrieredGlobalObject global_;
 
     // Note: this is private to enforce use of ObjectRealm::get(obj).
     js::ObjectRealm objects_;
@@ -880,44 +882,38 @@ class JS::Realm : private JSCompartment
 
   private:
     void updateDebuggerObservesFlag(unsigned flag);
 
     Realm(const Realm&) = delete;
     void operator=(const Realm&) = delete;
 
   public:
-    Realm(JS::Zone* zone, const JS::RealmOptions& options);
+    Realm(JSCompartment* comp, const JS::RealmOptions& options);
     ~Realm();
 
     MOZ_MUST_USE bool init(JSContext* cx);
     void destroy(js::FreeOp* fop);
     void clearTables();
 
     void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
                                 size_t* tiAllocationSiteTables,
                                 size_t* tiArrayTypeTables,
                                 size_t* tiObjectTypeTables,
                                 size_t* realmObject,
                                 size_t* realmTables,
                                 size_t* innerViews,
                                 size_t* lazyArrayBuffers,
                                 size_t* objectMetadataTables,
-                                size_t* crossCompartmentWrappers,
                                 size_t* savedStacksSet,
                                 size_t* varNamesSet,
                                 size_t* nonSyntacticLexicalScopes,
                                 size_t* jitRealm,
-                                size_t* privateData,
                                 size_t* scriptCountsMapArg);
 
-    JSCompartment* compartment() {
-        return this;
-    }
-
     JS::Zone* zone() {
         return zone_;
     }
     const JS::Zone* zone() const {
         return zone_;
     }
 
     JSRuntime* runtimeFromMainThread() const {
--- a/js/src/vm/JSContext.h
+++ b/js/src/vm/JSContext.h
@@ -140,17 +140,17 @@ struct JSContext : public JS::RootingCon
 
     template <typename T>
     bool isInsideCurrentZone(T thing) const {
         return thing->zoneFromAnyThread() == zone_;
     }
 
     template <typename T>
     inline bool isInsideCurrentCompartment(T thing) const {
-        return thing->compartment() == GetCompartmentForRealm(realm_);
+        return thing->compartment() == compartment();
     }
 
     void* onOutOfMemory(js::AllocFunction allocFunc, size_t nbytes, void* reallocPtr = nullptr) {
         if (helperThread()) {
             addPendingOutOfMemory();
             return nullptr;
         }
         return runtime_->onOutOfMemory(allocFunc, nbytes, reallocPtr, this);
@@ -237,31 +237,32 @@ struct JSContext : public JS::RootingCon
 
     void setHelperThread(js::HelperThread* helperThread);
     js::HelperThread* helperThread() const { return helperThread_; }
 
     bool isNurseryAllocSuppressed() const {
         return nurserySuppressions_;
     }
 
-    // Threads may freely access any data in their compartment and zone.
+    // Threads may freely access any data in their realm, compartment and zone.
     JSCompartment* compartment() const {
-        return JS::GetCompartmentForRealm(realm_);
+        return realm_ ? JS::GetCompartmentForRealm(realm_) : nullptr;
     }
+
     JS::Realm* realm() const {
         return realm_;
     }
 
 #ifdef DEBUG
     bool inAtomsZone() const;
 #endif
 
     JS::Zone* zone() const {
         MOZ_ASSERT_IF(!realm() && zone_, inAtomsZone());
-        MOZ_ASSERT_IF(realm(), js::GetCompartmentZone(GetCompartmentForRealm(realm())) == zone_);
+        MOZ_ASSERT_IF(realm(), js::GetRealmZone(realm()) == zone_);
         return zoneRaw();
     }
 
     // For use when the context's zone is being read by another thread and the
     // compartment and zone pointers might not be in sync.
     JS::Zone* zoneRaw() const {
         return zone_;
     }
--- a/js/src/vm/MemoryMetrics.cpp
+++ b/js/src/vm/MemoryMetrics.cpp
@@ -322,17 +322,20 @@ StatsZoneCallback(JSRuntime* rt, void* d
     zone->addSizeOfIncludingThis(rtStats->mallocSizeOf_,
                                  &zStats.typePool,
                                  &zStats.regexpZone,
                                  &zStats.jitZone,
                                  &zStats.baselineStubsOptimized,
                                  &zStats.cachedCFG,
                                  &zStats.uniqueIdMap,
                                  &zStats.shapeTables,
-                                 &rtStats->runtime.atomsMarkBitmaps);
+                                 &rtStats->runtime.atomsMarkBitmaps,
+                                 &zStats.compartmentObjects,
+                                 &zStats.crossCompartmentWrappersTables,
+                                 &zStats.compartmentsPrivateData);
 }
 
 static void
 StatsRealmCallback(JSContext* cx, void* data, Handle<Realm*> realm)
 {
     // Append a new RealmStats to the vector.
     RuntimeStats* rtStats = static_cast<StatsClosure*>(data)->rtStats;
 
@@ -350,22 +353,20 @@ StatsRealmCallback(JSContext* cx, void* 
                                   &realmStats.typeInferenceAllocationSiteTables,
                                   &realmStats.typeInferenceArrayTypeTables,
                                   &realmStats.typeInferenceObjectTypeTables,
                                   &realmStats.realmObject,
                                   &realmStats.realmTables,
                                   &realmStats.innerViewsTable,
                                   &realmStats.lazyArrayBuffersTable,
                                   &realmStats.objectMetadataTable,
-                                  &realmStats.crossCompartmentWrappersTable,
                                   &realmStats.savedStacksSet,
                                   &realmStats.varNamesSet,
                                   &realmStats.nonSyntacticLexicalScopesTable,
                                   &realmStats.jitRealm,
-                                  &realmStats.privateData,
                                   &realmStats.scriptCountsMap);
 }
 
 static void
 StatsArenaCallback(JSRuntime* rt, void* data, gc::Arena* arena,
                    JS::TraceKind traceKind, size_t thingSize)
 {
     RuntimeStats* rtStats = static_cast<StatsClosure*>(data)->rtStats;
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -102,17 +102,16 @@ JSRuntime::JSRuntime(JSRuntime* parentRu
     readableStreamCancelCallback(nullptr),
     readableStreamClosedCallback(nullptr),
     readableStreamErroredCallback(nullptr),
     readableStreamFinalizeCallback(nullptr),
     hadOutOfMemory(false),
     allowRelazificationForTesting(false),
     destroyCompartmentCallback(nullptr),
     sizeOfIncludingThisCompartmentCallback(nullptr),
-    compartmentNameCallback(nullptr),
     destroyRealmCallback(nullptr),
     realmNameCallback(nullptr),
     externalStringSizeofCallback(nullptr),
     securityCallbacks(&NullSecurityCallbacks),
     DOMcallbacks(nullptr),
     destroyPrincipals(nullptr),
     readPrincipals(nullptr),
     warningReporter(nullptr),
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -349,19 +349,16 @@ struct JSRuntime : public js::MallocProv
     js::MainThreadData<bool> allowRelazificationForTesting;
 
     /* Compartment destroy callback. */
     js::MainThreadData<JSDestroyCompartmentCallback> destroyCompartmentCallback;
 
     /* Compartment memory reporting callback. */
     js::MainThreadData<JSSizeOfIncludingThisCompartmentCallback> sizeOfIncludingThisCompartmentCallback;
 
-    /* Call this to get the name of a compartment. */
-    js::MainThreadData<JSCompartmentNameCallback> compartmentNameCallback;
-
     /* Realm destroy callback. */
     js::MainThreadData<JS::DestroyRealmCallback> destroyRealmCallback;
 
     /* Call this to get the name of a realm. */
     js::MainThreadData<JS::RealmNameCallback> realmNameCallback;
 
     /* Callback for doing memory reporting on external strings. */
     js::MainThreadData<JSExternalStringSizeofCallback> externalStringSizeofCallback;
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -4590,26 +4590,36 @@ void
 Zone::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
                              size_t* typePool,
                              size_t* regexpZone,
                              size_t* jitZone,
                              size_t* baselineStubsOptimized,
                              size_t* cachedCFG,
                              size_t* uniqueIdMap,
                              size_t* shapeTables,
-                             size_t* atomsMarkBitmaps)
+                             size_t* atomsMarkBitmaps,
+                             size_t* compartmentObjects,
+                             size_t* crossCompartmentWrappersTables,
+                             size_t* compartmentsPrivateData)
 {
     *typePool += types.typeLifoAlloc().sizeOfExcludingThis(mallocSizeOf);
     *regexpZone += regExps.sizeOfExcludingThis(mallocSizeOf);
     if (jitZone_)
         jitZone_->addSizeOfIncludingThis(mallocSizeOf, jitZone, baselineStubsOptimized, cachedCFG);
     *uniqueIdMap += uniqueIds().sizeOfExcludingThis(mallocSizeOf);
     *shapeTables += baseShapes().sizeOfExcludingThis(mallocSizeOf)
                   + initialShapes().sizeOfExcludingThis(mallocSizeOf);
     *atomsMarkBitmaps += markedAtoms().sizeOfExcludingThis(mallocSizeOf);
+
+    for (CompartmentsInZoneIter comp(this); !comp.done(); comp.next()) {
+        comp->addSizeOfIncludingThis(mallocSizeOf,
+                                     compartmentObjects,
+                                     crossCompartmentWrappersTables,
+                                     compartmentsPrivateData);
+    }
 }
 
 TypeZone::TypeZone(Zone* zone)
   : zone_(zone),
     typeLifoAlloc_(zone, (size_t) TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
     currentCompilationId_(zone),
     generation(zone, 0),
     sweepTypeLifoAlloc(zone, (size_t) TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
--- a/js/xpconnect/idl/xpccomponents.idl
+++ b/js/xpconnect/idl/xpccomponents.idl
@@ -646,25 +646,25 @@ interface nsIXPCComponents_Utils : nsISu
      * Gets the principal of a script object, after unwrapping any cross-
      * compartment wrappers.
      */
     [implicit_jscontext]
     nsIPrincipal getObjectPrincipal(in jsval obj);
 
     /*
      * Gets the URI or identifier string associated with an object's
-     * compartment (the same one used by the memory reporter machinery).
+     * realm (the same one used by the memory reporter machinery).
      *
      * Unwraps cross-compartment wrappers first.
      *
      * The string formats and values may change at any time. Do not depend on
      * this from addon code.
      */
     [implicit_jscontext]
-    ACString getCompartmentLocation(in jsval obj);
+    ACString getRealmLocation(in jsval obj);
 
     /*
      * Return a fractional number of milliseconds from process
      * startup, measured with a monotonic clock.
      */
     double now();
 
     /*
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -3006,27 +3006,27 @@ nsXPCComponents_Utils::GetObjectPrincipa
     MOZ_ASSERT(obj);
 
     nsCOMPtr<nsIPrincipal> prin = nsContentUtils::ObjectPrincipal(obj);
     prin.forget(result);
     return NS_OK;
 }
 
 NS_IMETHODIMP
-nsXPCComponents_Utils::GetCompartmentLocation(HandleValue val,
-                                              JSContext* cx,
-                                              nsACString& result)
+nsXPCComponents_Utils::GetRealmLocation(HandleValue val,
+                                        JSContext* cx,
+                                        nsACString& result)
 {
     if (!val.isObject())
         return NS_ERROR_INVALID_ARG;
     RootedObject obj(cx, &val.toObject());
     obj = js::CheckedUnwrap(obj);
     MOZ_ASSERT(obj);
 
-    result = xpc::CompartmentPrivate::Get(obj)->GetLocation();
+    result = xpc::RealmPrivate::Get(obj)->GetLocation();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXPCComponents_Utils::ReadUTF8File(nsIFile* aFile, nsACString& aResult)
 {
     NS_ENSURE_TRUE(aFile, NS_ERROR_INVALID_ARG);
 
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -201,24 +201,24 @@ CompartmentPrivate::SystemIsBeingShutDow
 RealmPrivate::RealmPrivate(JS::Realm* realm)
     : scriptability(realm)
     , scope(nullptr)
 {
 }
 
 static bool
 TryParseLocationURICandidate(const nsACString& uristr,
-                             CompartmentPrivate::LocationHint aLocationHint,
+                             RealmPrivate::LocationHint aLocationHint,
                              nsIURI** aURI)
 {
     static NS_NAMED_LITERAL_CSTRING(kGRE, "resource://gre/");
     static NS_NAMED_LITERAL_CSTRING(kToolkit, "chrome://global/");
     static NS_NAMED_LITERAL_CSTRING(kBrowser, "chrome://browser/");
 
-    if (aLocationHint == CompartmentPrivate::LocationHintAddon) {
+    if (aLocationHint == RealmPrivate::LocationHintAddon) {
         // Blacklist some known locations which are clearly not add-on related.
         if (StringBeginsWith(uristr, kGRE) ||
             StringBeginsWith(uristr, kToolkit) ||
             StringBeginsWith(uristr, kBrowser))
             return false;
 
         // -- GROSS HACK ALERT --
         // The Yandex Elements 8.10.2 extension implements its own "xb://" URL
@@ -244,18 +244,19 @@ TryParseLocationURICandidate(const nsACS
     // for memory reporter use.
     if (scheme.EqualsLiteral("data") || scheme.EqualsLiteral("blob"))
         return false;
 
     uri.forget(aURI);
     return true;
 }
 
-bool CompartmentPrivate::TryParseLocationURI(CompartmentPrivate::LocationHint aLocationHint,
-                                             nsIURI** aURI)
+bool
+RealmPrivate::TryParseLocationURI(RealmPrivate::LocationHint aLocationHint,
+                                  nsIURI** aURI)
 {
     if (!aURI)
         return false;
 
     // Need to parse the URI.
     if (location.IsEmpty())
         return false;
 
@@ -571,19 +572,20 @@ NukeAllWrappersForCompartment(JSContext*
                                      js::NukeAllReferences);
 
     // At this point, we should cross-compartment wrappers for the nuked
     // compartment. Set the wasNuked bit so WrapperFactory will return a
     // DeadObjectProxy when asked to create a new wrapper for it, and mark as
     // unscriptable.
     xpc::CompartmentPrivate::Get(compartment)->wasNuked = true;
 
-    // TODO: Loop over all realms in the compartment instead.
-    Realm* realm = GetRealmForCompartment(compartment);
-    xpc::RealmPrivate::Get(realm)->scriptability.Block();
+    auto blockScriptability = [](JSContext*, void*, Handle<Realm*> realm) {
+        xpc::RealmPrivate::Get(realm)->scriptability.Block();
+    };
+    JS::IterateRealmsInCompartment(cx, compartment, nullptr, blockScriptability);
 }
 
 } // namespace xpc
 
 static void
 CompartmentDestroyedCallback(JSFreeOp* fop, JSCompartment* compartment)
 {
     // NB - This callback may be called in JS_DestroyContext, which happens
@@ -1068,39 +1070,38 @@ XPCJSRuntime::Shutdown(JSContext* cx)
     CycleCollectedJSRuntime::Shutdown(cx);
 }
 
 XPCJSRuntime::~XPCJSRuntime()
 {
     MOZ_COUNT_DTOR_INHERITED(XPCJSRuntime, CycleCollectedJSRuntime);
 }
 
-// If |*anonymizeID| is non-zero and this is a user compartment, the name will
+// If |*anonymizeID| is non-zero and this is a user realm, the name will
 // be anonymized.
 static void
-GetCompartmentName(JSCompartment* c, nsCString& name, int* anonymizeID,
-                   bool replaceSlashes)
+GetRealmName(JS::Realm* realm, nsCString& name, int* anonymizeID,
+             bool replaceSlashes)
 {
-    JS::Realm* realm = JS::GetRealmForCompartment(c);
-    if (*anonymizeID && !js::IsSystemCompartment(c)) {
+    if (*anonymizeID && !js::IsSystemRealm(realm)) {
         name.AppendPrintf("<anonymized-%d>", *anonymizeID);
         *anonymizeID += 1;
     } else if (JSPrincipals* principals = JS::GetRealmPrincipals(realm)) {
         nsresult rv = nsJSPrincipals::get(principals)->GetScriptLocation(name);
         if (NS_FAILED(rv)) {
             name.AssignLiteral("(unknown)");
         }
 
-        // If the compartment's location (name) differs from the principal's
-        // script location, append the compartment's location to allow
-        // differentiation of multiple compartments owned by the same principal
-        // (e.g. components owned by the system or null principal).
-        CompartmentPrivate* compartmentPrivate = CompartmentPrivate::Get(c);
-        if (compartmentPrivate) {
-            const nsACString& location = compartmentPrivate->GetLocation();
+        // If the realm's location (name) differs from the principal's script
+        // location, append the realm's location to allow differentiation of
+        // multiple realms owned by the same principal (e.g. components owned
+        // by the system or null principal).
+        RealmPrivate* realmPrivate = RealmPrivate::Get(realm);
+        if (realmPrivate) {
+            const nsACString& location = realmPrivate->GetLocation();
             if (!location.IsEmpty() && !location.Equals(name)) {
                 name.AppendLiteral(", ");
                 name.Append(location);
             }
         }
 
         if (*anonymizeID) {
             // We might have a file:// URL that includes a path from the local
@@ -1151,27 +1152,27 @@ GetCompartmentName(JSCompartment* c, nsC
         if (replaceSlashes)
             name.ReplaceChar('/', '\\');
     } else {
         name.AssignLiteral("null-principal");
     }
 }
 
 extern void
-xpc::GetCurrentCompartmentName(JSContext* cx, nsCString& name)
+xpc::GetCurrentRealmName(JSContext* cx, nsCString& name)
 {
     RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
     if (!global) {
         name.AssignLiteral("no global");
         return;
     }
 
-    JSCompartment* compartment = GetObjectCompartment(global);
+    JS::Realm* realm = GetNonCCWObjectRealm(global);
     int anonymizeID = 0;
-    GetCompartmentName(compartment, name, &anonymizeID, false);
+    GetRealmName(realm, name, &anonymizeID, false);
 }
 
 void
 xpc::AddGCCallback(xpcGCCallback cb)
 {
     XPCJSRuntime::Get()->AddGCCallback(cb);
 }
 
@@ -1344,16 +1345,29 @@ ReportZoneStats(const JS::ZoneStats& zSt
     ZRREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("unique-id-map"),
         zStats.uniqueIdMap,
         "Address-independent cell identities.");
 
     ZRREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("shape-tables"),
         zStats.shapeTables,
         "Tables storing shape information.");
 
+    ZRREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("compartments/compartment-objects"),
+        zStats.compartmentObjects,
+        "The JSCompartment objects in this zone.");
+
+    ZRREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("compartments/cross-compartment-wrapper-tables"),
+        zStats.crossCompartmentWrappersTables,
+        "The cross-compartment wrapper tables.");
+
+    ZRREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("compartments/private-data"),
+        zStats.compartmentsPrivateData,
+        "Extra data attached to each compartment by XPConnect, including "
+        "its wrapped-js.");
+
     ZRREPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("lazy-scripts/gc-heap"),
         zStats.lazyScriptsGCHeap,
         "Scripts that haven't executed yet.");
 
     ZRREPORT_BYTES(pathPrefix + NS_LITERAL_CSTRING("lazy-scripts/malloc-heap"),
         zStats.lazyScriptsMallocHeap,
         "Lazy script tables containing closed-over bindings or inner functions.");
 
@@ -1744,17 +1758,17 @@ ReportRealmStats(const JS::RealmStats& r
         "Tables of type objects associated with array literals.");
 
     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("type-inference/object-type-tables"),
         realmStats.typeInferenceObjectTypeTables,
         "Tables of type objects associated with object literals.");
 
     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("realm-object"),
         realmStats.realmObject,
-        "The JSCompartment object itself.");
+        "The JS::Realm object itself.");
 
     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("realm-tables"),
         realmStats.realmTables,
         "Realm-wide tables storing object group information and wasm instances.");
 
     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("inner-views"),
         realmStats.innerViewsTable,
         "The table for array buffer inner views.");
@@ -1762,37 +1776,28 @@ ReportRealmStats(const JS::RealmStats& r
     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("lazy-array-buffers"),
         realmStats.lazyArrayBuffersTable,
         "The table for typed object lazy array buffers.");
 
     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("object-metadata"),
         realmStats.objectMetadataTable,
         "The table used by debugging tools for tracking object metadata");
 
-    ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("cross-compartment-wrapper-table"),
-        realmStats.crossCompartmentWrappersTable,
-        "The cross-compartment wrapper table.");
-
     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("saved-stacks-set"),
         realmStats.savedStacksSet,
         "The saved stacks set.");
 
     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("non-syntactic-lexical-scopes-table"),
         realmStats.nonSyntacticLexicalScopesTable,
         "The non-syntactic lexical scopes table.");
 
     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("jit-realm"),
         realmStats.jitRealm,
         "The JIT realm.");
 
-    ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("private-data"),
-        realmStats.privateData,
-        "Extra data attached to the realm by XPConnect, including "
-        "its wrapped-js.");
-
     ZRREPORT_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("script-counts-map"),
         realmStats.scriptCountsMap,
         "Profiling-related information for scripts.");
 
     if (sundriesGCHeap > 0) {
         // We deliberately don't use ZRREPORT_GC_BYTES here.
         REPORT_GC_BYTES(realmJSPathPrefix + NS_LITERAL_CSTRING("sundries/gc-heap"),
             sundriesGCHeap,
@@ -2041,21 +2046,20 @@ class JSMainRuntimeRealmsReporter final 
 
     struct Data {
         int anonymizeID;
         js::Vector<nsCString, 0, js::SystemAllocPolicy> paths;
     };
 
     static void RealmCallback(JSContext* cx, void* vdata, Handle<Realm*> realm) {
         // silently ignore OOM errors
-        JSCompartment* c = JS::GetCompartmentForRealm(realm);
         Data* data = static_cast<Data*>(vdata);
         nsCString path;
-        GetCompartmentName(c, path, &data->anonymizeID, /* replaceSlashes = */ true);
-        path.Insert(js::IsSystemCompartment(c)
+        GetRealmName(realm, path, &data->anonymizeID, /* replaceSlashes = */ true);
+        path.Insert(js::IsSystemRealm(realm)
                     ? NS_LITERAL_CSTRING("js-main-runtime-realms/system/")
                     : NS_LITERAL_CSTRING("js-main-runtime-realms/user/"),
                     0);
         mozilla::Unused << data->paths.append(path);
     }
 
     NS_IMETHOD CollectReports(nsIHandleReportCallback* handleReport,
                               nsISupports* data, bool anonymize) override
@@ -2189,20 +2193,19 @@ class XPCJSRuntimeStats : public JS::Run
         MOZ_ASSERT(StartsWithExplicit(extras->pathPrefix));
 
         zStats->extra = extras;
     }
 
     virtual void initExtraRealmStats(Handle<Realm*> realm,
                                      JS::RealmStats* realmStats) override
     {
-        JSCompartment* c = JS::GetCompartmentForRealm(realm);
         xpc::RealmStatsExtras* extras = new xpc::RealmStatsExtras;
-        nsCString cName;
-        GetCompartmentName(c, cName, &mAnonymizeID, /* replaceSlashes = */ true);
+        nsCString rName;
+        GetRealmName(realm, rName, &mAnonymizeID, /* replaceSlashes = */ true);
 
         // Get the realm's global.
         AutoSafeJSContext cx;
         bool needZone = true;
         RootedObject global(cx, JS::GetRealmGlobalOrNull(realm));
         if (global) {
             RefPtr<nsGlobalWindowInner> window;
             if (NS_SUCCEEDED(UNWRAP_OBJECT(Window, global, window))) {
@@ -2223,19 +2226,19 @@ class XPCJSRuntimeStats : public JS::Run
                 extras->domPathPrefix.AssignLiteral("explicit/dom/non-window-global?!/");
             }
         } else {
             extras->jsPathPrefix.AssignLiteral("explicit/js-non-window/zones/");
             extras->domPathPrefix.AssignLiteral("explicit/dom/no-global?!/");
         }
 
         if (needZone)
-            extras->jsPathPrefix += nsPrintfCString("zone(0x%p)/", (void*)js::GetCompartmentZone(c));
-
-        extras->jsPathPrefix += NS_LITERAL_CSTRING("realm(") + cName + NS_LITERAL_CSTRING(")/");
+            extras->jsPathPrefix += nsPrintfCString("zone(0x%p)/", (void*)js::GetRealmZone(realm));
+
+        extras->jsPathPrefix += NS_LITERAL_CSTRING("realm(") + rName + NS_LITERAL_CSTRING(")/");
 
         // extras->jsPathPrefix is used for almost all the realm-specific
         // reports. At this point it has the form
         // "<something>realm(<rname>)/".
         //
         // extras->domPathPrefix is used for DOM orphan nodes, which are
         // counted by the JS reporter but reported as part of the DOM
         // measurements. At this point it has the form "<something>/dom/" if
@@ -2637,45 +2640,38 @@ SetUseCounterCallback(JSObject* obj, JSU
         SetDocumentAndPageUseCounter(obj, eUseCounter_custom_JS_wasm);
         break;
       default:
         MOZ_ASSERT_UNREACHABLE("Unexpected JSUseCounter id");
     }
 }
 
 static void
-CompartmentNameCallback(JSContext* cx, JSCompartment* comp,
-                        char* buf, size_t bufsize)
+GetRealmNameCallback(JSContext* cx, Handle<Realm*> realm,
+                     char* buf, size_t bufsize)
 {
     nsCString name;
     // This is called via the JSAPI and isn't involved in memory reporting, so
-    // we don't need to anonymize compartment names.
+    // we don't need to anonymize realm names.
     int anonymizeID = 0;
-    GetCompartmentName(comp, name, &anonymizeID, /* replaceSlashes = */ false);
+    GetRealmName(realm, name, &anonymizeID, /* replaceSlashes = */ false);
     if (name.Length() >= bufsize)
         name.Truncate(bufsize - 1);
     memcpy(buf, name.get(), name.Length() + 1);
 }
 
 static void
 DestroyRealm(JSFreeOp* fop, JS::Realm* realm)
 {
     // Get the current compartment private into an AutoPtr (which will do the
     // cleanup for us), and null out the private field.
     mozilla::UniquePtr<RealmPrivate> priv(RealmPrivate::Get(realm));
     JS::SetRealmPrivate(realm, nullptr);
 }
 
-static void
-GetRealmName(JSContext* cx, Handle<Realm*> realm, char* buf, size_t bufsize)
-{
-    JSCompartment* comp = GetCompartmentForRealm(realm);
-    CompartmentNameCallback(cx, comp, buf, bufsize);
-}
-
 static bool
 PreserveWrapper(JSContext* cx, JSObject* obj)
 {
     MOZ_ASSERT(cx);
     MOZ_ASSERT(obj);
     MOZ_ASSERT(IS_WN_REFLECTOR(obj) || mozilla::dom::IsDOMObject(obj));
 
     return mozilla::dom::IsDOMObject(obj) && mozilla::dom::TryPreserveWrapper(obj);
@@ -2835,19 +2831,18 @@ XPCJSRuntime::Initialize(JSContext* cx)
     // finite threshold (0xffffffff is infinity for uint32_t parameters).
     // This leaves the maximum-JS_malloc-bytes threshold still in effect
     // to cause period, and we hope hygienic, last-ditch GCs from within
     // the GC's allocator.
     JS_SetGCParameter(cx, JSGC_MAX_BYTES, 0xffffffff);
 
     JS_SetDestroyCompartmentCallback(cx, CompartmentDestroyedCallback);
     JS_SetSizeOfIncludingThisCompartmentCallback(cx, CompartmentSizeOfIncludingThisCallback);
-    JS_SetCompartmentNameCallback(cx, CompartmentNameCallback);
     JS::SetDestroyRealmCallback(cx, DestroyRealm);
-    JS::SetRealmNameCallback(cx, GetRealmName);
+    JS::SetRealmNameCallback(cx, GetRealmNameCallback);
     mPrevGCSliceCallback = JS::SetGCSliceCallback(cx, GCSliceCallback);
     mPrevDoCycleCollectionCallback = JS::SetDoCycleCollectionCallback(cx,
             DoCycleCollectionCallback);
     JS_AddFinalizeCallback(cx, FinalizeCallback, nullptr);
     JS_AddWeakPointerZonesCallback(cx, WeakPointerZonesCallback, this);
     JS_AddWeakPointerCompartmentCallback(cx, WeakPointerCompartmentCallback, this);
     JS_SetWrapObjectCallbacks(cx, &WrapObjectCallbacks);
     js::SetPreserveWrapperCallback(cx, PreserveWrapper);
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -959,24 +959,24 @@ Base64Decode(JSContext* cx, HandleValue 
     out.setString(str);
     return true;
 }
 
 void
 SetLocationForGlobal(JSObject* global, const nsACString& location)
 {
     MOZ_ASSERT(global);
-    CompartmentPrivate::Get(global)->SetLocation(location);
+    RealmPrivate::Get(global)->SetLocation(location);
 }
 
 void
 SetLocationForGlobal(JSObject* global, nsIURI* locationURI)
 {
     MOZ_ASSERT(global);
-    CompartmentPrivate::Get(global)->SetLocationURI(locationURI);
+    RealmPrivate::Get(global)->SetLocationURI(locationURI);
 }
 
 } // namespace xpc
 
 static nsresult
 WriteScriptOrFunction(nsIObjectOutputStream* stream, JSContext* cx,
                       JSScript* scriptArg, HandleObject functionObj)
 {
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -2829,21 +2829,16 @@ bool ReportWrapperDenial(JSContext* cx, 
 // information needed to select the right security policy for cross-compartment
 // wrappers.
 class CompartmentPrivate
 {
     CompartmentPrivate() = delete;
     CompartmentPrivate(const CompartmentPrivate&) = delete;
 
 public:
-    enum LocationHint {
-        LocationHintRegular,
-        LocationHintAddon
-    };
-
     explicit CompartmentPrivate(JSCompartment* c);
 
     ~CompartmentPrivate();
 
     static CompartmentPrivate* Get(JSCompartment* compartment)
     {
         MOZ_ASSERT(compartment);
         void* priv = JS_GetCompartmentPrivate(compartment);
@@ -2906,71 +2901,25 @@ public:
     // True if this compartment has been nuked. If true, any wrappers into or
     // out of it should be considered invalid.
     bool wasNuked;
 
     // Whether we've emitted a warning about a property that was filtered out
     // by a security wrapper. See XrayWrapper.cpp.
     bool wrapperDenialWarnings[WrapperDenialTypeCount];
 
-    const nsACString& GetLocation() {
-        if (location.IsEmpty() && locationURI) {
-
-            nsCOMPtr<nsIXPConnectWrappedJS> jsLocationURI =
-                 do_QueryInterface(locationURI);
-            if (jsLocationURI) {
-                // We cannot call into JS-implemented nsIURI objects, because
-                // we are iterating over the JS heap at this point.
-                location =
-                    NS_LITERAL_CSTRING("<JS-implemented nsIURI location>");
-            } else if (NS_FAILED(locationURI->GetSpec(location))) {
-                location = NS_LITERAL_CSTRING("<unknown location>");
-            }
-        }
-        return location;
-    }
-    bool GetLocationURI(nsIURI** aURI) {
-        return GetLocationURI(LocationHintRegular, aURI);
-    }
-    bool GetLocationURI(LocationHint aLocationHint, nsIURI** aURI) {
-        if (locationURI) {
-            nsCOMPtr<nsIURI> rval = locationURI;
-            rval.forget(aURI);
-            return true;
-        }
-        return TryParseLocationURI(aLocationHint, aURI);
-    }
-    void SetLocation(const nsACString& aLocation) {
-        if (aLocation.IsEmpty())
-            return;
-        if (!location.IsEmpty() || locationURI)
-            return;
-        location = aLocation;
-    }
-    void SetLocationURI(nsIURI* aLocationURI) {
-        if (!aLocationURI)
-            return;
-        if (locationURI)
-            return;
-        locationURI = aLocationURI;
-    }
-
     JSObject2WrappedJSMap* GetWrappedJSMap() const { return mWrappedJSMap; }
     void UpdateWeakPointersAfterGC();
 
     void SystemIsBeingShutDown();
 
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
 
 private:
-    nsCString location;
-    nsCOMPtr<nsIURI> locationURI;
     JSObject2WrappedJSMap* mWrappedJSMap;
-
-    bool TryParseLocationURI(LocationHint aType, nsIURI** aURI);
 };
 
 bool IsUniversalXPConnectEnabled(JSCompartment* compartment);
 bool IsUniversalXPConnectEnabled(JSContext* cx);
 bool EnableUniversalXPConnect(JSContext* cx);
 
 inline void
 CrashIfNotInAutomation()
@@ -2979,23 +2928,28 @@ CrashIfNotInAutomation()
 }
 
 // XPConnect-specific data associated with each JavaScript realm. Per-Window
 // settings live here; security-wrapper-related settings live in the
 // CompartmentPrivate.
 //
 // Following the ECMAScript spec, a realm contains a global (e.g. an inner
 // Window) and its associated scripts and objects; a compartment may contain
-// several same-origin, same-principal realms.
+// several same-origin realms.
 class RealmPrivate
 {
     RealmPrivate() = delete;
     RealmPrivate(const RealmPrivate&) = delete;
 
 public:
+    enum LocationHint {
+        LocationHintRegular,
+        LocationHintAddon
+    };
+
     explicit RealmPrivate(JS::Realm* realm);
 
     static RealmPrivate* Get(JS::Realm* realm)
     {
         MOZ_ASSERT(realm);
         void* priv = JS::GetRealmPrivate(realm);
         return static_cast<RealmPrivate*>(priv);
     }
@@ -3010,16 +2964,65 @@ public:
     }
 
     // The scriptability of this realm.
     Scriptability scriptability;
 
     // Our XPCWrappedNativeScope. This is non-null if and only if this is an
     // XPConnect realm.
     XPCWrappedNativeScope* scope;
+
+    const nsACString& GetLocation() {
+        if (location.IsEmpty() && locationURI) {
+
+            nsCOMPtr<nsIXPConnectWrappedJS> jsLocationURI =
+                 do_QueryInterface(locationURI);
+            if (jsLocationURI) {
+                // We cannot call into JS-implemented nsIURI objects, because
+                // we are iterating over the JS heap at this point.
+                location =
+                    NS_LITERAL_CSTRING("<JS-implemented nsIURI location>");
+            } else if (NS_FAILED(locationURI->GetSpec(location))) {
+                location = NS_LITERAL_CSTRING("<unknown location>");
+            }
+        }
+        return location;
+    }
+    bool GetLocationURI(LocationHint aLocationHint, nsIURI** aURI) {
+        if (locationURI) {
+            nsCOMPtr<nsIURI> rval = locationURI;
+            rval.forget(aURI);
+            return true;
+        }
+        return TryParseLocationURI(aLocationHint, aURI);
+    }
+    bool GetLocationURI(nsIURI** aURI) {
+        return GetLocationURI(LocationHintRegular, aURI);
+    }
+
+    void SetLocation(const nsACString& aLocation) {
+        if (aLocation.IsEmpty())
+            return;
+        if (!location.IsEmpty() || locationURI)
+            return;
+        location = aLocation;
+    }
+    void SetLocationURI(nsIURI* aLocationURI) {
+        if (!aLocationURI)
+            return;
+        if (locationURI)
+            return;
+        locationURI = aLocationURI;
+    }
+
+private:
+    nsCString location;
+    nsCOMPtr<nsIURI> locationURI;
+
+    bool TryParseLocationURI(LocationHint aType, nsIURI** aURI);
 };
 
 inline XPCWrappedNativeScope*
 ObjectScope(JSObject* obj)
 {
     return RealmPrivate::Get(obj)->scope;
 }
 
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -610,21 +610,21 @@ DispatchScriptErrorEvent(nsPIDOMWindowIn
 // WindowID() is used to initialize the xpc::ErrorReport.  This may be null, of
 // course.  If it's not null, this function may return a null stack object if
 // the window is far enough gone, because in those cases we don't want to have
 // the stack in the console message keeping the window alive.
 JSObject*
 FindExceptionStackForConsoleReport(nsPIDOMWindowInner* win,
                                    JS::HandleValue exceptionValue);
 
-// Return a name for the compartment.
+// Return a name for the realm.
 // This function makes reasonable efforts to make this name both mostly human-readable
 // and unique. However, there are no guarantees of either property.
 extern void
-GetCurrentCompartmentName(JSContext*, nsCString& name);
+GetCurrentRealmName(JSContext*, nsCString& name);
 
 void AddGCCallback(xpcGCCallback cb);
 void RemoveGCCallback(xpcGCCallback cb);
 
 inline bool
 AreNonLocalConnectionsDisabled()
 {
     static int disabledForTest = -1;
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -8364,23 +8364,20 @@ PresShell::GetCurrentItemAndPositionForE
                           (currentIndex - firstVisibleRow + 1) * rowHeight);
           istree = true;
 
           RefPtr<nsTreeColumns> cols;
           treeBox->GetColumns(getter_AddRefs(cols));
           if (cols) {
             nsTreeColumn* col = cols->GetFirstColumn();
             if (col) {
-              RefPtr<Element> colElement;
-              col->GetElement(getter_AddRefs(colElement));
-              if (colElement) {
-                nsIFrame* frame = colElement->GetPrimaryFrame();
-                if (frame) {
-                  extraTreeY += frame->GetSize().height;
-                }
+              RefPtr<Element> colElement = col->Element();
+              nsIFrame* frame = colElement->GetPrimaryFrame();
+              if (frame) {
+                extraTreeY += frame->GetSize().height;
               }
             }
           }
         }
         else {
           multiSelect->GetCurrentItem(getter_AddRefs(item));
         }
       }
--- a/layout/reftests/css-break/reftest.list
+++ b/layout/reftests/css-break/reftest.list
@@ -1,14 +1,14 @@
 default-preferences pref(layout.css.box-decoration-break.enabled,true)
 
 == box-decoration-break-1.html box-decoration-break-1-ref.html
 fuzzy(1,20) fuzzy-if(skiaContent,1,700) fuzzy-if(webrender,21-26,8910-12357) == box-decoration-break-with-inset-box-shadow-1.html box-decoration-break-with-inset-box-shadow-1-ref.html
 fuzzy(45,460) fuzzy-if(skiaContent,57,439) fuzzy-if(Android,57,1330) == box-decoration-break-with-outset-box-shadow-1.html box-decoration-break-with-outset-box-shadow-1-ref.html # Bug 1386543
 random-if(!gtkWidget) == box-decoration-break-border-image.html box-decoration-break-border-image-ref.html
 == box-decoration-break-block-border-padding.html box-decoration-break-block-border-padding-ref.html
 == box-decoration-break-block-margin.html box-decoration-break-block-margin-ref.html
-fuzzy-if(!Android,1,62) fuzzy-if(Android,8,6627) == box-decoration-break-first-letter.html box-decoration-break-first-letter-ref.html #Bug 1313773
+fuzzy-if(!Android,1,62) fuzzy-if(Android,8,6627) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == box-decoration-break-first-letter.html box-decoration-break-first-letter-ref.html #Bug 1313773 # Bug 1392106
 == box-decoration-break-with-bidi.html box-decoration-break-with-bidi-ref.html
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == box-decoration-break-bug-1235152.html box-decoration-break-bug-1235152-ref.html # Bug 1392106
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == box-decoration-break-bug-1249913.html box-decoration-break-bug-1249913-ref.html # Bug 1392106
 == vertical-wm-001.html vertical-wm-001-ref.html
 random-if(Android) == 1405443.html 1405443-ref.html
--- a/layout/reftests/css-display/reftest.list
+++ b/layout/reftests/css-display/reftest.list
@@ -11,17 +11,17 @@ fuzzy-if(Android,8,604) == display-conte
 == display-contents-style-inheritance-1-stylechange.html display-contents-style-inheritance-1-ref.html
 fuzzy-if(winWidget,12,100) == display-contents-style-inheritance-1-dom-mutations.html display-contents-style-inheritance-1-ref.html
 == display-contents-tables.xhtml display-contents-tables-ref.xhtml
 == display-contents-tables-2.xhtml display-contents-tables-ref.xhtml
 == display-contents-tables-3.xhtml display-contents-tables-3-ref.xhtml
 == display-contents-visibility-hidden.html display-contents-visibility-hidden-ref.html
 == display-contents-visibility-hidden-2.html display-contents-visibility-hidden-ref.html
 == display-contents-495385-2d.html display-contents-495385-2d-ref.html
-fuzzy-if(Android,7,3935) == display-contents-xbl.xhtml display-contents-xbl-ref.html
+fuzzy-if(Android,7,3935) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == display-contents-xbl.xhtml display-contents-xbl-ref.html # bug 1392106
 == display-contents-xbl-2.xul display-contents-xbl-2-ref.xul
 == display-contents-xbl-3.xul display-contents-xbl-3-ref.xul
 skip == display-contents-xbl-4.xul display-contents-xbl-4-ref.xul # fails (not just asserts) due to bug 1089223
 asserts(0-1) fuzzy-if(Android,8,3216) == display-contents-fieldset.html display-contents-fieldset-ref.html # bug 1089223
 == display-contents-xbl-5.xul display-contents-xbl-3-ref.xul
 == display-contents-xbl-6.xhtml display-contents-xbl-6-ref.html
 == display-contents-xbl-7.xhtml display-contents-xbl-7-ref.html
 == display-contents-list-item-child.html display-contents-list-item-child-ref.html
--- a/layout/reftests/font-features/reftest.list
+++ b/layout/reftests/font-features/reftest.list
@@ -84,20 +84,20 @@ skip-if(winWidget) == annotations.html a
 # OpenType features should work across inter-word spaces
 == font-features-across-space-1.html font-features-across-space-1-ref.html
 == spacelookups.html spacelookups-ref.html
 # tests whether word cache is in use by testing for ignored space kerns
 == spacelookups-wordcache.html spacelookups-wordcache-ref.html
 # requires Japanese font with feature support, WinXP lacks one
 random-if(!winWidget&&!cocoaWidget) == fwid-spaces.html fwid-spaces-ref.html
 # Arial/Times New Roman on Win7+/OSX 10.6+ have kerning pairs that include spaces
-random-if(!winWidget&&!cocoaWidget) fails-if(winWidget||cocoaWidget) != kerning-spaces-arial-nokern.html kerning-spaces-arial-default.html
-random-if(!winWidget&&!cocoaWidget) fails-if(winWidget||cocoaWidget) == kerning-spaces-arial-kern.html kerning-spaces-arial-default.html
-random-if(!winWidget&&!cocoaWidget) fails-if(winWidget||cocoaWidget) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) != kerning-spaces-tnr-nokern.html kerning-spaces-tnr-default.html
-random-if(!winWidget&&!cocoaWidget) fails-if(winWidget||cocoaWidget) == kerning-spaces-tnr-kern.html kerning-spaces-tnr-default.html
+random-if(!winWidget&&!cocoaWidget) fails-if(winWidget||cocoaWidget) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) != kerning-spaces-arial-nokern.html kerning-spaces-arial-default.html # Bug 1392106
+random-if(!winWidget&&!cocoaWidget) fails-if(winWidget||cocoaWidget) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == kerning-spaces-arial-kern.html kerning-spaces-arial-default.html # Bug 1392106
+random-if(!winWidget&&!cocoaWidget) fails-if(winWidget||cocoaWidget) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) != kerning-spaces-tnr-nokern.html kerning-spaces-tnr-default.html # Bug 1392106
+random-if(!winWidget&&!cocoaWidget) fails-if(winWidget||cocoaWidget) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == kerning-spaces-tnr-kern.html kerning-spaces-tnr-default.html # Bug 1392106
 
 # font-variant-caps fallback
 # -- sanity check - none of these should look like the default rendering
 != caps-fallback-smallcaps1.html caps-fallback-default.html
 != caps-fallback-smallcaps2.html caps-fallback-default.html
 != caps-fallback-petitecaps.html caps-fallback-default.html
 != caps-fallback-allsmallcaps.html caps-fallback-default.html
 != caps-fallback-allpetitecaps.html caps-fallback-default.html
--- a/layout/reftests/font-matching/reftest.list
+++ b/layout/reftests/font-matching/reftest.list
@@ -153,12 +153,12 @@ skip-if(gtkWidget||/^Windows\x20NT\x206\
 # random-if(!OSX) != system-generic-fallback-zh-tw.html system-generic-fallback-zh-cn.html
 
 # Tests for legacy font family name (GDI-model families) matching;
 # these depend on specific fonts that are available as standard on macOS and Windows,
 # and are not expected to pass on platforms that don't have those same fonts.
 skip-if(!cocoaWidget) == legacy-family-names-1.html legacy-family-names-1-ref.html
 skip-if(!winWidget) == legacy-family-names-2.html legacy-family-names-2-ref.html
 
-== descriptor-ranges.html descriptor-ranges-ref.html
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == descriptor-ranges.html descriptor-ranges-ref.html # Bug 1392106
 
 # Reset default prefs.
 default-preferences
--- a/layout/reftests/forms/legend/reftest.list
+++ b/layout/reftests/forms/legend/reftest.list
@@ -1,3 +1,3 @@
 == legend.html legend-ref.html
-fuzzy-if(Android,255,41) == 1273433.html 1273433-ref.html
+fuzzy-if(Android,255,41) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 1273433.html 1273433-ref.html # Bug 1392106
 fails == 1339287.html 1339287-ref.html # bug 1383868
--- a/layout/reftests/mathml/reftest.list
+++ b/layout/reftests/mathml/reftest.list
@@ -147,17 +147,17 @@ fails-if(skiaContent&&OSX>=1010) == scal
 == mpadded-6.html mpadded-6-ref.html
 random-if(gtkWidget) == mpadded-7.html mpadded-7-ref.html # bug 1309430
 random-if(gtkWidget) == mpadded-8.html mpadded-8-ref.html # bug 1309430
 random-if(gtkWidget) == mpadded-9.html mpadded-9-ref.html # bug 1309430
 == math-display.html math-display-ref.html
 == scriptlevel-1.html scriptlevel-1-ref.html
 == scriptlevel-movablelimits-1.html scriptlevel-movablelimits-1-ref.html
 == munderover-align-accent-false.html munderover-align-accent-false-ref.html
-== munderover-align-accent-true.html munderover-align-accent-true-ref.html
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == munderover-align-accent-true.html munderover-align-accent-true-ref.html # Bug 1392106
 == munder-mover-align-accent-true.html munder-mover-align-accent-true-ref.html
 == munder-mover-align-accent-false.html munder-mover-align-accent-false-ref.html
 == mfrac-linethickness-1.xhtml mfrac-linethickness-1-ref.xhtml
 == mfrac-linethickness-2.xhtml mfrac-linethickness-2-ref.xhtml
 == mfrac-linethickness-3.xhtml mfrac-linethickness-3-ref.xhtml
 == mathml-negativespace.html mathml-negativespace-ref.html
 == negative-mspace-1.html negative-mspace-1-ref.html
 != link-1.xhtml link-ref.xhtml
--- a/layout/reftests/svg/reftest.list
+++ b/layout/reftests/svg/reftest.list
@@ -162,17 +162,17 @@ fuzzy-if(d2d&&layersGPUAccelerated,3,120
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == dynamic-text-01.svg dynamic-text-01-ref.svg # bug 1392106
 fuzzy-if(d2d&&layersGPUAccelerated,3,12739) == dynamic-text-02.svg dynamic-text-02-ref.svg # bug 776038 for Win7, Win8
 fuzzy-if(d2d&&layersGPUAccelerated,2,10539) == dynamic-text-03.svg dynamic-text-03-ref.svg # bug 776038 for Win7
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == dynamic-text-04.svg dynamic-text-04-ref.svg # bug 776038 for Win7 # bug 1392106
 == dynamic-text-05.svg pass.svg
 == dynamic-text-06.svg pass.svg
 == dynamic-text-07.svg dynamic-text-07-ref.svg
 == dynamic-text-08.svg dynamic-text-08-ref.svg
-== dynamic-text-attr-01.svg dynamic-text-attr-01-ref.svg
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == dynamic-text-attr-01.svg dynamic-text-attr-01-ref.svg # bug 1392106
 == dynamic-textPath-01.svg dynamic-textPath-01-ref.svg
 == dynamic-textPath-02.svg dynamic-textPath-02-ref.svg
 == dynamic-textPath-03.svg dynamic-textPath-03-ref.svg
 == dynamic-use-01.svg pass.svg
 == dynamic-use-02.svg pass.svg
 == dynamic-use-03.svg pass.svg
 == dynamic-use-04.svg pass.svg
 == dynamic-use-05.svg pass.svg
--- a/layout/reftests/svg/smil/style/reftest.list
+++ b/layout/reftests/svg/smil/style/reftest.list
@@ -62,20 +62,20 @@ fuzzy-if(skiaContent,1,885) == anim-css-
 fuzzy-if(skiaContent,1,210) == anim-css-fillopacity-1-from-by.svg       anim-css-fillopacity-1-ref.svg
 == anim-css-fillopacity-1-from-to.svg       anim-css-fillopacity-1-ref.svg
 fuzzy-if(skiaContent,1,550) == anim-css-fillopacity-1-to.svg            anim-css-fillopacity-1-ref.svg
 == anim-css-fillopacity-2-paced.svg         anim-css-fillopacity-2-ref.svg
 fails == anim-css-fillopacity-3-clamp-big.svg     anim-css-fillopacity-3-ref.svg # bug 501188
 fuzzy-if(skiaContent,1,365) == anim-css-fillopacity-3-clamp-small.svg   anim-css-fillopacity-3-ref.svg
 
 # 'font' shorthand property
-== anim-css-font-1.svg  anim-css-font-1-ref.svg
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == anim-css-font-1.svg  anim-css-font-1-ref.svg # Bug 1392106
 
 # 'font-size' property, from/by/to with pixel values only
-== anim-css-fontsize-1-from-by-px-px.svg    anim-css-fontsize-1-ref.svg
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == anim-css-fontsize-1-from-by-px-px.svg    anim-css-fontsize-1-ref.svg # Bug 1392106
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == anim-css-fontsize-1-from-to-px-px.svg    anim-css-fontsize-1-ref.svg # Bug 1392106
 
 # 'font-size' property (accepts unitless values)
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == anim-css-fontsize-1-from-to-no-no.svg    anim-css-fontsize-1-ref.svg # Bug 1392106
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == anim-css-fontsize-1-from-to-no-px.svg    anim-css-fontsize-1-ref.svg # Bug 1392106
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == anim-css-fontsize-1-from-to-px-no.svg    anim-css-fontsize-1-ref.svg # Bug 1392106
 
 # 'font-size' mapped attribute (accepts unitless values)
--- a/layout/reftests/w3c-css/failures.list
+++ b/layout/reftests/w3c-css/failures.list
@@ -51,21 +51,34 @@ css-values/calc-in-calc.html
 fails css-writing-modes/float-lft-orthog-htb-in-vlr-002.xht
 fails css-writing-modes/float-lft-orthog-htb-in-vrl-002.xht
 fails css-writing-modes/float-lft-orthog-vlr-in-htb-002.xht
 fails css-writing-modes/float-lft-orthog-vrl-in-htb-002.xht
 fails css-writing-modes/float-rgt-orthog-htb-in-vlr-003.xht
 fails css-writing-modes/float-rgt-orthog-htb-in-vrl-003.xht
 fails css-writing-modes/float-rgt-orthog-vlr-in-htb-003.xht
 fails css-writing-modes/float-rgt-orthog-vrl-in-htb-003.xht
-fails css-writing-modes/sizing-orthog-htb-in-vrl-001.xht
+fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-htb-in-vrl-001.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-htb-in-vrl-003.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-htb-in-vrl-009.xht
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-htb-in-vrl-003.xht
-fails css-writing-modes/sizing-orthog-htb-in-vrl-004.xht
+fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-htb-in-vrl-004.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-htb-in-vrl-006.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-htb-in-vrl-007.xht
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-htb-in-vrl-009.xht
-fails css-writing-modes/sizing-orthog-htb-in-vrl-013.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-htb-in-vrl-010.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-htb-in-vrl-011.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-htb-in-vrl-012.xht
+fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-htb-in-vrl-013.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-htb-in-vrl-015.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-htb-in-vrl-016.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-htb-in-vrl-018.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-htb-in-vrl-019.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-htb-in-vrl-02?.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-htb-in-vlr-0??.xht
 fails-if(OSX||winWidget||Android) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-htb-in-vlr-008.xht
 fails-if(OSX||winWidget||Android) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-htb-in-vlr-020.xht
 fails-if(OSX||winWidget||Android) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-htb-in-vrl-008.xht
 fails-if(OSX||winWidget||Android) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-htb-in-vrl-020.xht
 fuzzy-if(winWidget,255,648-713) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-vlr-in-htb-008.xht
 fuzzy-if(winWidget,255,648-713) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-vlr-in-htb-020.xht
 fuzzy-if(winWidget,255,648-713) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-vrl-in-htb-008.xht
 fuzzy-if(winWidget,255,648-713) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/sizing-orthog-vrl-in-htb-020.xht
@@ -113,16 +126,17 @@ fuzzy-if(OSX||winWidget,75,404) fuzzy-if
 fuzzy-if(OSX||winWidget,215,780)  css-writing-modes/text-baseline-???-00?.xht
 fuzzy-if(OSX,23,16) css-writing-modes/text-combine-upright-decorations-001.html
 fuzzy-if(OSX||winWidget,255,480)  css-writing-modes/text-indent-v??-0??.xht
 fuzzy-if(OSX||winWidget,226,960) fails-if(webrender&&cocoaWidget)  css-writing-modes/text-orientation-016.xht
 fuzzy-if(OSX||winWidget,223,720)  css-writing-modes/vertical-alignment-*.xht
 fuzzy-if(OSX||winWidget,158,624)  css-writing-modes/writing-mode-vertical-??-00?.*
 fuzzy(255,960) css-writing-modes/text-combine-upright-value-all-00?.html
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/text-combine-upright-compression-00?.html
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/text-combine-upright-inherit-all-00?.html
 
 # Bug 1167911
 skip css-writing-modes/abs-pos-non-replaced-icb-vlr-021.xht
 skip css-writing-modes/abs-pos-non-replaced-icb-vrl-020.xht
 
 # Bug 1244601
 fails css-writing-modes/block-flow-direction-slr-058.xht
 fails css-writing-modes/block-flow-direction-srl-057.xht
--- a/layout/reftests/w3c-css/received/reftest.list
+++ b/layout/reftests/w3c-css/received/reftest.list
@@ -911,56 +911,56 @@ fuzzy-if(OSX||winWidget,110,1200) random
 fuzzy-if(OSX||winWidget,110,1200) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/row-progression-vlr-003.xht css-writing-modes/block-flow-direction-001-ref.xht
 fuzzy-if(OSX||winWidget,110,1200) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/row-progression-vlr-005.xht css-writing-modes/block-flow-direction-001-ref.xht
 fuzzy-if(OSX||winWidget,110,1200) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/row-progression-vlr-007.xht css-writing-modes/block-flow-direction-001-ref.xht
 fuzzy-if(OSX||winWidget,110,1200) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/row-progression-vlr-009.xht css-writing-modes/block-flow-direction-001-ref.xht
 fuzzy-if(OSX||winWidget,110,1200) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/row-progression-vrl-002.xht css-writing-modes/block-flow-direction-001-ref.xht
 fuzzy-if(OSX||winWidget,110,1200) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/row-progression-vrl-004.xht css-writing-modes/block-flow-direction-001-ref.xht
 fuzzy-if(OSX||winWidget,110,1200) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/row-progression-vrl-006.xht css-writing-modes/block-flow-direction-001-ref.xht
 fuzzy-if(OSX||winWidget,110,1200) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/row-progression-vrl-008.xht css-writing-modes/block-flow-direction-001-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vlr-001.xht css-writing-modes/sizing-orthog-htb-in-vlr-001-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vlr-001.xht css-writing-modes/sizing-orthog-htb-in-vlr-001-ref.xht
 fails-if(Android) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vlr-003.xht css-writing-modes/sizing-orthog-htb-in-vlr-003-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vlr-004.xht css-writing-modes/sizing-orthog-htb-in-vlr-004-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vlr-006.xht css-writing-modes/sizing-orthog-htb-in-vlr-006-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vlr-007.xht css-writing-modes/sizing-orthog-htb-in-vlr-007-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vlr-004.xht css-writing-modes/sizing-orthog-htb-in-vlr-004-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vlr-006.xht css-writing-modes/sizing-orthog-htb-in-vlr-006-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vlr-007.xht css-writing-modes/sizing-orthog-htb-in-vlr-007-ref.xht
 fails-if(OSX||winWidget||Android) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vlr-008.xht css-writing-modes/sizing-orthog-htb-in-vlr-008-ref.xht
 fails-if(Android) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vlr-009.xht css-writing-modes/sizing-orthog-htb-in-vlr-003-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vlr-010.xht css-writing-modes/sizing-orthog-htb-in-vlr-010-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vlr-011.xht css-writing-modes/sizing-orthog-htb-in-vlr-011-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vlr-012.xht css-writing-modes/sizing-orthog-htb-in-vlr-006-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vlr-013.xht css-writing-modes/sizing-orthog-htb-in-vlr-013-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vlr-010.xht css-writing-modes/sizing-orthog-htb-in-vlr-010-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vlr-011.xht css-writing-modes/sizing-orthog-htb-in-vlr-011-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vlr-012.xht css-writing-modes/sizing-orthog-htb-in-vlr-006-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vlr-013.xht css-writing-modes/sizing-orthog-htb-in-vlr-013-ref.xht
 fails-if(Android) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vlr-015.xht css-writing-modes/sizing-orthog-htb-in-vlr-015-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vlr-016.xht css-writing-modes/sizing-orthog-htb-in-vlr-016-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vlr-018.xht css-writing-modes/sizing-orthog-htb-in-vlr-018-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vlr-019.xht css-writing-modes/sizing-orthog-htb-in-vlr-019-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vlr-016.xht css-writing-modes/sizing-orthog-htb-in-vlr-016-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vlr-018.xht css-writing-modes/sizing-orthog-htb-in-vlr-018-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vlr-019.xht css-writing-modes/sizing-orthog-htb-in-vlr-019-ref.xht
 fails-if(OSX||winWidget||Android) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vlr-020.xht css-writing-modes/sizing-orthog-htb-in-vlr-020-ref.xht
 fails-if(Android) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vlr-021.xht css-writing-modes/sizing-orthog-htb-in-vlr-015-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vlr-022.xht css-writing-modes/sizing-orthog-htb-in-vlr-022-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vlr-023.xht css-writing-modes/sizing-orthog-htb-in-vlr-023-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vlr-024.xht css-writing-modes/sizing-orthog-htb-in-vlr-018-ref.xht
-fails == css-writing-modes/sizing-orthog-htb-in-vrl-001.xht css-writing-modes/sizing-orthog-htb-in-vrl-001-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vlr-022.xht css-writing-modes/sizing-orthog-htb-in-vlr-022-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vlr-023.xht css-writing-modes/sizing-orthog-htb-in-vlr-023-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vlr-024.xht css-writing-modes/sizing-orthog-htb-in-vlr-018-ref.xht
+fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vrl-001.xht css-writing-modes/sizing-orthog-htb-in-vrl-001-ref.xht
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vrl-003.xht css-writing-modes/sizing-orthog-htb-in-vrl-003-ref.xht
-fails == css-writing-modes/sizing-orthog-htb-in-vrl-004.xht css-writing-modes/sizing-orthog-htb-in-vlr-004-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vrl-006.xht css-writing-modes/sizing-orthog-htb-in-vrl-006-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vrl-007.xht css-writing-modes/sizing-orthog-htb-in-vrl-007-ref.xht
+fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vrl-004.xht css-writing-modes/sizing-orthog-htb-in-vlr-004-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vrl-006.xht css-writing-modes/sizing-orthog-htb-in-vrl-006-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vrl-007.xht css-writing-modes/sizing-orthog-htb-in-vrl-007-ref.xht
 fails-if(OSX||winWidget||Android) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vrl-008.xht css-writing-modes/sizing-orthog-htb-in-vrl-008-ref.xht
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vrl-009.xht css-writing-modes/sizing-orthog-htb-in-vrl-003-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vrl-010.xht css-writing-modes/sizing-orthog-htb-in-vrl-010-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vrl-011.xht css-writing-modes/sizing-orthog-htb-in-vrl-011-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vrl-012.xht css-writing-modes/sizing-orthog-htb-in-vrl-006-ref.xht
-fails == css-writing-modes/sizing-orthog-htb-in-vrl-013.xht css-writing-modes/sizing-orthog-htb-in-vrl-013-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vrl-015.xht css-writing-modes/sizing-orthog-htb-in-vrl-015-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vrl-016.xht css-writing-modes/sizing-orthog-htb-in-vlr-016-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vrl-018.xht css-writing-modes/sizing-orthog-htb-in-vrl-018-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vrl-019.xht css-writing-modes/sizing-orthog-htb-in-vrl-019-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vrl-010.xht css-writing-modes/sizing-orthog-htb-in-vrl-010-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vrl-011.xht css-writing-modes/sizing-orthog-htb-in-vrl-011-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vrl-012.xht css-writing-modes/sizing-orthog-htb-in-vrl-006-ref.xht
+fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vrl-013.xht css-writing-modes/sizing-orthog-htb-in-vrl-013-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vrl-015.xht css-writing-modes/sizing-orthog-htb-in-vrl-015-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vrl-016.xht css-writing-modes/sizing-orthog-htb-in-vlr-016-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vrl-018.xht css-writing-modes/sizing-orthog-htb-in-vrl-018-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vrl-019.xht css-writing-modes/sizing-orthog-htb-in-vrl-019-ref.xht
 fails-if(OSX||winWidget||Android) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vrl-020.xht css-writing-modes/sizing-orthog-htb-in-vrl-020-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vrl-021.xht css-writing-modes/sizing-orthog-htb-in-vrl-015-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vrl-022.xht css-writing-modes/sizing-orthog-htb-in-vrl-022-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vrl-023.xht css-writing-modes/sizing-orthog-htb-in-vrl-023-ref.xht
-== css-writing-modes/sizing-orthog-htb-in-vrl-024.xht css-writing-modes/sizing-orthog-htb-in-vrl-018-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vrl-021.xht css-writing-modes/sizing-orthog-htb-in-vrl-015-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vrl-022.xht css-writing-modes/sizing-orthog-htb-in-vrl-022-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vrl-023.xht css-writing-modes/sizing-orthog-htb-in-vrl-023-ref.xht
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vrl-024.xht css-writing-modes/sizing-orthog-htb-in-vrl-018-ref.xht
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-prct-htb-in-vlr-001.xht css-writing-modes/sizing-orthog-prct-htb-in-vlr-001-ref.xht
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-prct-htb-in-vlr-002.xht css-writing-modes/sizing-orthog-prct-htb-in-vlr-002-ref.xht
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-prct-htb-in-vlr-003.xht css-writing-modes/sizing-orthog-prct-htb-in-vlr-003-ref.xht
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-prct-htb-in-vlr-004.xht css-writing-modes/sizing-orthog-prct-htb-in-vlr-004-ref.xht
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-prct-htb-in-vlr-005.xht css-writing-modes/sizing-orthog-prct-htb-in-vlr-005-ref.xht
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-prct-htb-in-vlr-006.xht css-writing-modes/sizing-orthog-prct-htb-in-vlr-006-ref.xht
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-prct-htb-in-vlr-007.xht css-writing-modes/sizing-orthog-prct-htb-in-vlr-007-ref.xht
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-prct-htb-in-vlr-008.xht css-writing-modes/sizing-orthog-prct-htb-in-vlr-008-ref.xht
@@ -1070,18 +1070,18 @@ fuzzy-if(OSX||winWidget,215,780) == css-
 fuzzy-if(OSX||winWidget,215,780) == css-writing-modes/text-baseline-srl-008.xht css-writing-modes/text-baseline-vrl-006-ref.xht
 fuzzy-if(OSX||winWidget,215,780) == css-writing-modes/text-baseline-vlr-003.xht css-writing-modes/text-baseline-vrl-002-ref.xht
 fuzzy-if(OSX||winWidget,215,780) == css-writing-modes/text-baseline-vlr-005.xht css-writing-modes/text-baseline-vrl-002-ref.xht
 fuzzy-if(OSX||winWidget,215,780) == css-writing-modes/text-baseline-vlr-007.xht css-writing-modes/text-baseline-vrl-006-ref.xht
 fuzzy-if(OSX||winWidget,215,780) == css-writing-modes/text-baseline-vrl-002.xht css-writing-modes/text-baseline-vrl-002-ref.xht
 fuzzy-if(OSX||winWidget,215,780) == css-writing-modes/text-baseline-vrl-004.xht css-writing-modes/text-baseline-vrl-002-ref.xht
 fuzzy-if(OSX||winWidget,215,780) == css-writing-modes/text-baseline-vrl-006.xht css-writing-modes/text-baseline-vrl-006-ref.xht
 fuzzy-if(OSX,23,16) == css-writing-modes/text-combine-upright-decorations-001.html css-writing-modes/reference/text-combine-upright-decorations-001.html
-== css-writing-modes/text-combine-upright-inherit-all-001.html css-writing-modes/reference/text-combine-upright-inherit-all-001.html
-== css-writing-modes/text-combine-upright-inherit-all-002.html css-writing-modes/reference/text-combine-upright-inherit-all-002.html
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/text-combine-upright-inherit-all-001.html css-writing-modes/reference/text-combine-upright-inherit-all-001.html
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/text-combine-upright-inherit-all-002.html css-writing-modes/reference/text-combine-upright-inherit-all-002.html
 == css-writing-modes/text-combine-upright-layout-rules-001.html css-writing-modes/reference/text-combine-upright-layout-rules-001-ref.html
 == css-writing-modes/text-combine-upright-line-breaking-rules-001.html css-writing-modes/text-combine-upright-line-breaking-rules-001-ref.html
 fuzzy(255,960) == css-writing-modes/text-combine-upright-value-all-001.html css-writing-modes/reference/text-combine-upright-value-single-character.html
 fuzzy(255,960) == css-writing-modes/text-combine-upright-value-all-002.html css-writing-modes/reference/vertical-ahem-1x1-ref.html
 fuzzy(255,960) != css-writing-modes/text-combine-upright-value-all-002.html css-writing-modes/reference/horizontal-ahem-1x1-notref.html
 fuzzy(255,960) == css-writing-modes/text-combine-upright-value-all-003.html css-writing-modes/reference/vertical-ahem-1x1-ref.html
 fuzzy(255,960) != css-writing-modes/text-combine-upright-value-all-003.html css-writing-modes/reference/horizontal-ahem-1x1-notref.html
 skip == css-writing-modes/text-combine-upright-value-digits2-001.html css-writing-modes/reference/text-combine-upright-value-single-character.html
--- a/layout/reftests/w3c-css/submitted/counter-styles-3/reftest.list
+++ b/layout/reftests/w3c-css/submitted/counter-styles-3/reftest.list
@@ -7,17 +7,17 @@ fails-if(webrender&&cocoaWidget) == syst
 == system-extends.html    system-extends-ref.html
 == system-cyclic-invalid.html     system-common-invalid-ref.html
 == system-fixed-invalid.html      system-common-invalid2-ref.html
 == system-symbolic-invalid.html   system-common-invalid-ref.html
 == system-alphabetic-invalid.html system-common-invalid2-ref.html
 == system-numeric-invalid.html    system-common-invalid2-ref.html
 == system-additive-invalid.html   system-common-invalid-ref.html
 == system-extends-invalid.html    system-extends-invalid-ref.html
-== descriptor-negative.html descriptor-negative-ref.html
+random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == descriptor-negative.html descriptor-negative-ref.html # Bug 1392106
 == descriptor-prefix.html   descriptor-prefix-ref.html
 == descriptor-suffix.html   descriptor-suffix-ref.html
 == descriptor-range.html    descriptor-range-ref.html
 fuzzy-if(webrender,22,3) == descriptor-pad.html      descriptor-pad-ref.html
 == descriptor-fallback.html descriptor-fallback-ref.html
 == descriptor-symbols.html  descriptor-symbols-ref.html
 == descriptor-negative-invalid.html descriptor-negative-invalid-ref.html
 == descriptor-prefix-invalid.html   descriptor-prefix-invalid-ref.html
--- a/layout/xul/nsXULTooltipListener.cpp
+++ b/layout/xul/nsXULTooltipListener.cpp
@@ -26,16 +26,17 @@
 #include "nsTreeColumns.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Event.h" // for Event
 #include "mozilla/dom/BoxObject.h"
 #include "mozilla/dom/MouseEvent.h"
+#include "mozilla/dom/TreeColumnBinding.h"
 #include "mozilla/TextEvents.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsXULTooltipListener* nsXULTooltipListener::sInstance = nullptr;
 
 //////////////////////////////////////////////////////////////////////////
@@ -346,37 +347,37 @@ nsXULTooltipListener::CheckTreeBodyMove(
 
   nsCOMPtr<nsITreeBoxObject> obx;
   GetSourceTreeBoxObject(getter_AddRefs(obx));
   if (bx && obx) {
     int32_t x = aMouseEvent->ScreenX(CallerType::System);
     int32_t y = aMouseEvent->ScreenY(CallerType::System);
 
     int32_t row;
-    nsCOMPtr<nsITreeColumn> col;
+    RefPtr<nsTreeColumn> col;
     nsAutoString obj;
 
     // subtract off the documentElement's boxObject
     int32_t boxX, boxY;
     bx->GetScreenX(&boxX);
     bx->GetScreenY(&boxY);
     x -= boxX;
     y -= boxY;
 
     obx->GetCellAt(x, y, &row, getter_AddRefs(col), obj);
 
     // determine if we are going to need a titletip
     // XXX check the disabletitletips attribute on the tree content
     mNeedTitletip = false;
     int16_t colType = -1;
     if (col) {
-      col->GetType(&colType);
+      colType = col->Type();
     }
     if (row >= 0 && obj.EqualsLiteral("text") &&
-        colType != nsITreeColumn::TYPE_PASSWORD) {
+        colType != TreeColumnBinding::TYPE_PASSWORD) {
       obx->IsCellCropped(row, col, &mNeedTitletip);
     }
 
     nsCOMPtr<nsIContent> currentTooltip = do_QueryReferent(mCurrentTooltip);
     if (currentTooltip && (row != mLastTreeRow || col != mLastTreeCol)) {
       HideTooltip();
     }
 
@@ -451,33 +452,33 @@ nsXULTooltipListener::ShowTooltip()
 }
 
 #ifdef MOZ_XUL
 // XXX: "This stuff inside DEBUG_crap could be used to make tree tooltips work
 //       in the future."
 #ifdef DEBUG_crap
 static void
 GetTreeCellCoords(nsITreeBoxObject* aTreeBox, nsIContent* aSourceNode,
-                  int32_t aRow, nsITreeColumn* aCol, int32_t* aX, int32_t* aY)
+                  int32_t aRow, nsTreeColumn* aCol, int32_t* aX, int32_t* aY)
 {
   int32_t junk;
   aTreeBox->GetCoordsForCellItem(aRow, aCol, EmptyCString(), aX, aY, &junk, &junk);
   RefPtr<nsXULElement> xulEl = nsXULElement::FromNode(aSourceNode);
   nsCOMPtr<nsIBoxObject> bx = xulEl->GetBoxObject(IgnoreErrors());
   int32_t myX, myY;
   bx->GetX(&myX);
   bx->GetY(&myY);
   *aX += myX;
   *aY += myY;
 }
 #endif
 
 static void
 SetTitletipLabel(nsITreeBoxObject* aTreeBox, Element* aTooltip,
-                 int32_t aRow, nsITreeColumn* aCol)
+                 int32_t aRow, nsTreeColumn* aCol)
 {
   nsCOMPtr<nsITreeView> view;
   aTreeBox->GetView(getter_AddRefs(view));
   if (view) {
     nsAutoString label;
 #ifdef DEBUG
     nsresult rv =
 #endif
--- a/layout/xul/nsXULTooltipListener.h
+++ b/layout/xul/nsXULTooltipListener.h
@@ -13,17 +13,17 @@
 #include "nsString.h"
 #ifdef MOZ_XUL
 #include "nsITreeBoxObject.h"
 #endif
 #include "nsWeakPtr.h"
 #include "mozilla/Attributes.h"
 
 class nsIContent;
-class nsITreeColumn;
+class nsTreeColumn;
 
 namespace mozilla {
 namespace dom {
 class Event;
 class MouseEvent;
 } // namespace dom
 } // namespace mozilla
 
@@ -94,13 +94,13 @@ protected:
   // the next time the mouse enters the node (bug #395668).
   bool mTooltipShownOnce;
 
 #ifdef MOZ_XUL
   // special members for handling trees
   bool mIsSourceTree;
   bool mNeedTitletip;
   int32_t mLastTreeRow;
-  nsCOMPtr<nsITreeColumn> mLastTreeCol;
+  RefPtr<nsTreeColumn> mLastTreeCol;
 #endif
 };
 
 #endif // nsXULTooltipListener
--- a/layout/xul/tree/TreeBoxObject.cpp
+++ b/layout/xul/tree/TreeBoxObject.cpp
@@ -301,135 +301,97 @@ NS_IMETHODIMP TreeBoxObject::GetLastVisi
 int32_t TreeBoxObject::HorizontalPosition()
 {
   nsTreeBodyFrame* body = GetTreeBodyFrame();
   if (body)
     return body->GetHorizontalPosition();
   return 0;
 }
 
-NS_IMETHODIMP TreeBoxObject::GetHorizontalPosition(int32_t *aHorizontalPosition)
-{
-  *aHorizontalPosition = HorizontalPosition();
-  return NS_OK;
-}
-
 int32_t TreeBoxObject::GetPageLength()
 {
   nsTreeBodyFrame* body = GetTreeBodyFrame();
   if (body)
     return body->PageLength();
   return 0;
 }
 
-NS_IMETHODIMP TreeBoxObject::GetPageLength(int32_t *aPageLength)
-{
-  *aPageLength = GetPageLength();
-  return NS_OK;
-}
-
-NS_IMETHODIMP TreeBoxObject::GetSelectionRegion(nsIScriptableRegion **aRegion)
-{
-  *aRegion = nullptr;
-  nsTreeBodyFrame* body = GetTreeBodyFrame();
-  if (body)
-    return body->GetSelectionRegion(aRegion);
-  return NS_OK;
-}
-
 already_AddRefed<nsIScriptableRegion>
 TreeBoxObject::SelectionRegion()
 {
+  nsTreeBodyFrame* body = GetTreeBodyFrame();
+  if (!body) {
+    return nullptr;
+  }
+
   nsCOMPtr<nsIScriptableRegion> region;
-  GetSelectionRegion(getter_AddRefs(region));
+  body->GetSelectionRegion(getter_AddRefs(region));
   return region.forget();
 }
 
 NS_IMETHODIMP
 TreeBoxObject::EnsureRowIsVisible(int32_t aRow)
 {
   nsTreeBodyFrame* body = GetTreeBodyFrame();
   if (body)
     return body->EnsureRowIsVisible(aRow);
   return NS_OK;
 }
 
-NS_IMETHODIMP
-TreeBoxObject::EnsureCellIsVisible(int32_t aRow, nsITreeColumn* aCol)
+void
+TreeBoxObject::EnsureCellIsVisible(int32_t aRow, nsTreeColumn* aCol, ErrorResult& aRv)
 {
   nsTreeBodyFrame* body = GetTreeBodyFrame();
-  if (body)
-    return body->EnsureCellIsVisible(aRow, aCol);
-  return NS_OK;
+  if (body) {
+    nsresult rv = body->EnsureCellIsVisible(aRow, aCol);
+    if (NS_FAILED(rv)) {
+      aRv.Throw(rv);
+    }
+  }
 }
 
-NS_IMETHODIMP
+void
 TreeBoxObject::ScrollToRow(int32_t aRow)
 {
   nsTreeBodyFrame* body = GetTreeBodyFrame(true);
-  if (body)
-    return body->ScrollToRow(aRow);
-  return NS_OK;
+  if (!body) {
+    return;
+  }
+    
+  body->ScrollToRow(aRow);
 }
 
-NS_IMETHODIMP
+void
 TreeBoxObject::ScrollByLines(int32_t aNumLines)
 {
   nsTreeBodyFrame* body = GetTreeBodyFrame();
-  if (body)
-    return body->ScrollByLines(aNumLines);
-  return NS_OK;
+  if (!body) {
+    return;
+  }
+  body->ScrollByLines(aNumLines);
 }
 
-NS_IMETHODIMP
+void
 TreeBoxObject::ScrollByPages(int32_t aNumPages)
 {
   nsTreeBodyFrame* body = GetTreeBodyFrame();
   if (body)
-    return body->ScrollByPages(aNumPages);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-TreeBoxObject::ScrollToCell(int32_t aRow, nsITreeColumn* aCol)
-{
-  nsTreeBodyFrame* body = GetTreeBodyFrame();
-  if (body)
-    return body->ScrollToCell(aRow, aCol);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-TreeBoxObject::ScrollToColumn(nsITreeColumn* aCol)
-{
-  nsTreeBodyFrame* body = GetTreeBodyFrame();
-  if (body)
-    return body->ScrollToColumn(aCol);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-TreeBoxObject::ScrollToHorizontalPosition(int32_t aHorizontalPosition)
-{
-  nsTreeBodyFrame* body = GetTreeBodyFrame();
-  if (body)
-    return body->ScrollToHorizontalPosition(aHorizontalPosition);
-  return NS_OK;
+    body->ScrollByPages(aNumPages);
 }
 
 NS_IMETHODIMP TreeBoxObject::Invalidate()
 {
   nsTreeBodyFrame* body = GetTreeBodyFrame();
   if (body)
     return body->Invalidate();
   return NS_OK;
 }
 
 NS_IMETHODIMP
-TreeBoxObject::InvalidateColumn(nsITreeColumn* aCol)
+TreeBoxObject::InvalidateColumn(nsTreeColumn* aCol)
 {
   nsTreeBodyFrame* body = GetTreeBodyFrame();
   if (body)
     return body->InvalidateColumn(aCol);
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -437,96 +399,78 @@ TreeBoxObject::InvalidateRow(int32_t aIn
 {
   nsTreeBodyFrame* body = GetTreeBodyFrame();
   if (body)
     return body->InvalidateRow(aIndex);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-TreeBoxObject::InvalidateCell(int32_t aRow, nsITreeColumn* aCol)
+TreeBoxObject::InvalidateCell(int32_t aRow, nsTreeColumn* aCol)
 {
   nsTreeBodyFrame* body = GetTreeBodyFrame();
   if (body)
     return body->InvalidateCell(aRow, aCol);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TreeBoxObject::InvalidateRange(int32_t aStart, int32_t aEnd)
 {
   nsTreeBodyFrame* body = GetTreeBodyFrame();
   if (body)
     return body->InvalidateRange(aStart, aEnd);
   return NS_OK;
 }
 
-NS_IMETHODIMP
-TreeBoxObject::InvalidateColumnRange(int32_t aStart, int32_t aEnd, nsITreeColumn* aCol)
-{
-  nsTreeBodyFrame* body = GetTreeBodyFrame();
-  if (body)
-    return body->InvalidateColumnRange(aStart, aEnd, aCol);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-TreeBoxObject::GetRowAt(int32_t x, int32_t y, int32_t *aRow)
-{
-  *aRow = 0;
-  nsTreeBodyFrame* body = GetTreeBodyFrame();
-  if (body)
-    return body->GetRowAt(x, y, aRow);
-  return NS_OK;
-}
-
 int32_t
 TreeBoxObject::GetRowAt(int32_t x, int32_t y)
 {
-  int32_t row;
-  GetRowAt(x, y, &row);
-  return row;
+  nsTreeBodyFrame* body = GetTreeBodyFrame();
+  if (!body) {
+    return 0;
+  }
+  return body->GetRowAt(x, y);
 }
 
 NS_IMETHODIMP
 TreeBoxObject::GetCellAt(int32_t aX, int32_t aY, int32_t *aRow,
-                         nsITreeColumn** aCol, nsAString& aChildElt)
+                         nsTreeColumn** aCol, nsAString& aChildElt)
 {
   *aRow = 0;
   *aCol = nullptr;
   nsTreeBodyFrame* body = GetTreeBodyFrame();
   if (body) {
     nsAutoCString element;
     nsresult retval = body->GetCellAt(aX, aY, aRow, aCol, element);
     CopyUTF8toUTF16(element, aChildElt);
     return retval;
   }
   return NS_OK;
 }
 
 void
 TreeBoxObject::GetCellAt(int32_t x, int32_t y, TreeCellInfo& aRetVal, ErrorResult& aRv)
 {
-  nsCOMPtr<nsITreeColumn> col;
-  GetCellAt(x, y, &aRetVal.mRow, getter_AddRefs(col), aRetVal.mChildElt);
-  aRetVal.mCol = col.forget().downcast<nsTreeColumn>();
+  GetCellAt(x, y, &aRetVal.mRow, getter_AddRefs(aRetVal.mCol),
+            aRetVal.mChildElt);
 }
 
 void
 TreeBoxObject::GetCellAt(JSContext* cx,
                          int32_t x, int32_t y,
                          JS::Handle<JSObject*> rowOut,
                          JS::Handle<JSObject*> colOut,
                          JS::Handle<JSObject*> childEltOut,
                          ErrorResult& aRv)
 {
   int32_t row;
-  nsITreeColumn* col;
+  RefPtr<nsTreeColumn> col;
   nsAutoString childElt;
-  GetCellAt(x, y, &row, &col, childElt);
+  GetCellAt(x, y, &row, getter_AddRefs(col), childElt);
 
   JS::Rooted<JS::Value> v(cx);
 
   if (!ToJSValue(cx, row, &v) ||
       !JS_SetProperty(cx, rowOut, "value", v)) {
     aRv.Throw(NS_ERROR_XPC_CANT_SET_OUT_VAL);
     return;
   }
@@ -538,17 +482,17 @@ TreeBoxObject::GetCellAt(JSContext* cx,
   if (!ToJSValue(cx, childElt, &v) ||
       !JS_SetProperty(cx, childEltOut, "value", v)) {
     aRv.Throw(NS_ERROR_XPC_CANT_SET_OUT_VAL);
     return;
   }
 }
 
 NS_IMETHODIMP
-TreeBoxObject::GetCoordsForCellItem(int32_t aRow, nsITreeColumn* aCol, const nsAString& aElement,
+TreeBoxObject::GetCoordsForCellItem(int32_t aRow, nsTreeColumn* aCol, const nsAString& aElement,
                                       int32_t *aX, int32_t *aY, int32_t *aWidth, int32_t *aHeight)
 {
   *aX = *aY = *aWidth = *aHeight = 0;
   nsTreeBodyFrame* body = GetTreeBodyFrame();
   NS_ConvertUTF16toUTF8 element(aElement);
   if (body)
     return body->GetCoordsForCellItem(aRow, aCol, element, aX, aY, aWidth, aHeight);
   return NS_OK;
@@ -594,27 +538,27 @@ TreeBoxObject::GetCoordsForCellItem(JSCo
   v.setInt32(h);
   if (!JS_SetProperty(cx, heightOut, "value", v)) {
     aRv.Throw(NS_ERROR_XPC_CANT_SET_OUT_VAL);
     return;
   }
 }
 
 NS_IMETHODIMP
-TreeBoxObject::IsCellCropped(int32_t aRow, nsITreeColumn* aCol, bool *aIsCropped)
+TreeBoxObject::IsCellCropped(int32_t aRow, nsTreeColumn* aCol, bool *aIsCropped)
 {
   *aIsCropped = false;
   nsTreeBodyFrame* body = GetTreeBodyFrame();
   if (body)
     return body->IsCellCropped(aRow, aCol, aIsCropped);
   return NS_OK;
 }
 
 bool
-TreeBoxObject::IsCellCropped(int32_t row, nsITreeColumn* col, ErrorResult& aRv)
+TreeBoxObject::IsCellCropped(int32_t row, nsTreeColumn* col, ErrorResult& aRv)
 {
   bool ret;
   aRv = IsCellCropped(row, col, &ret);
   return ret;
 }
 
 NS_IMETHODIMP
 TreeBoxObject::RowCountChanged(int32_t aIndex, int32_t aDelta)
@@ -647,32 +591,27 @@ NS_IMETHODIMP
 TreeBoxObject::ClearStyleAndImageCaches()
 {
   nsTreeBodyFrame* body = GetTreeBodyFrame();
   if (body)
     return body->ClearStyleAndImageCaches();
   return NS_OK;
 }
 
-NS_IMETHODIMP
-TreeBoxObject::RemoveImageCacheEntry(int32_t aRowIndex, nsITreeColumn* aCol)
+void
+TreeBoxObject::RemoveImageCacheEntry(int32_t aRowIndex, nsTreeColumn& aCol, ErrorResult& aRv)
 {
-  NS_ENSURE_ARG(aCol);
-  NS_ENSURE_TRUE(aRowIndex >= 0, NS_ERROR_INVALID_ARG);
+  if (NS_WARN_IF(aRowIndex < 0)) {
+    aRv.Throw(NS_ERROR_INVALID_ARG);
+    return;
+  }
   nsTreeBodyFrame* body = GetTreeBodyFrame();
   if (body) {
-    return body->RemoveImageCacheEntry(aRowIndex, aCol);
+    body->RemoveImageCacheEntry(aRowIndex, &aCol);
   }
-  return NS_OK;
-}
-
-void
-TreeBoxObject::RemoveImageCacheEntry(int32_t row, nsITreeColumn& col, ErrorResult& aRv)
-{
-  aRv = RemoveImageCacheEntry(row, &col);
 }
 
 void
 TreeBoxObject::ClearCachedValues()
 {
   mTreeBody = nullptr;
 }
 
--- a/layout/xul/tree/TreeBoxObject.h
+++ b/layout/xul/tree/TreeBoxObject.h
@@ -56,34 +56,42 @@ public:
   int32_t RowHeight();
 
   int32_t RowWidth();
 
   int32_t HorizontalPosition();
 
   already_AddRefed<nsIScriptableRegion> SelectionRegion();
 
+  void EnsureCellIsVisible(int32_t row, nsTreeColumn* col, ErrorResult& aRv);
+
+  void ScrollToRow(int32_t aRow);
+
+  void ScrollByLines(int32_t aNumLines);
+
+  void ScrollByPages(int32_t aNumPages);
+
   int32_t GetFirstVisibleRow();
 
   int32_t GetLastVisibleRow();
 
   int32_t GetPageLength();
 
   int32_t GetRowAt(int32_t x, int32_t y);
 
   void GetCellAt(int32_t x, int32_t y, TreeCellInfo& aRetVal, ErrorResult& aRv);
 
   already_AddRefed<DOMRect> GetCoordsForCellItem(int32_t row,
                                                  nsTreeColumn& col,
                                                  const nsAString& element,
                                                  ErrorResult& aRv);
 
-  bool IsCellCropped(int32_t row, nsITreeColumn* col, ErrorResult& aRv);
+  bool IsCellCropped(int32_t row, nsTreeColumn* col, ErrorResult& aRv);
 
-  void RemoveImageCacheEntry(int32_t row, nsITreeColumn& col, ErrorResult& aRv);
+  void RemoveImageCacheEntry(int32_t row, nsTreeColumn& col, ErrorResult& aRv);
 
   // Deprecated APIs from old IDL
   void GetCellAt(JSContext* cx,
                  int32_t x, int32_t y,
                  JS::Handle<JSObject*> rowOut,
                  JS::Handle<JSObject*> colOut,
                  JS::Handle<JSObject*> childEltOut,
                  ErrorResult& aRv);
@@ -100,28 +108,20 @@ public:
 
   // Same signature (except for nsresult return type) as the XPIDL impls
   // void Invalidate();
   // void BeginUpdateBatch();
   // void EndUpdateBatch();
   // void ClearStyleAndImageCaches();
   // void SetFocused(bool arg);
   // void EnsureRowIsVisible(int32_t index);
-  // void EnsureCellIsVisible(int32_t row, nsITreeColumn* col);
-  // void ScrollToRow(int32_t index);
-  // void ScrollByLines(int32_t numLines);
-  // void ScrollByPages(int32_t numPages);
-  // void ScrollToCell(int32_t row, nsITreeColumn* col);
-  // void ScrollToColumn(nsITreeColumn* col);
-  // void ScrollToHorizontalPosition(int32_t horizontalPosition);
-  // void InvalidateColumn(nsITreeColumn* col);
+  // void InvalidateColumn(nsTreeColumn* col);
   // void InvalidateRow(int32_t index);
-  // void InvalidateCell(int32_t row, nsITreeColumn* col);
+  // void InvalidateCell(int32_t row, nsTreeColumn* col);
   // void InvalidateRange(int32_t startIndex, int32_t endIndex);
-  // void InvalidateColumnRange(int32_t startIndex, int32_t endIndex, nsITreeColumn* col);
   // void RowCountChanged(int32_t index, int32_t count);
 
 protected:
   nsTreeBodyFrame* mTreeBody;
   nsCOMPtr<nsITreeView> mView;
 
 private:
   ~TreeBoxObject();
--- a/layout/xul/tree/moz.build
+++ b/layout/xul/tree/moz.build
@@ -4,17 +4,16 @@
 # 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/.
 
 with Files('**'):
     BUG_COMPONENT = ('Core', 'XUL')
 
 XPIDL_SOURCES += [
     'nsITreeBoxObject.idl',
-    'nsITreeColumns.idl',
     'nsITreeSelection.idl',
     'nsITreeView.idl',
 ]
 
 XPIDL_MODULE = 'layout_xul_tree'
 
 EXPORTS += [
     'nsTreeColFrame.h',
--- a/layout/xul/tree/nsITreeBoxObject.idl
+++ b/layout/xul/tree/nsITreeBoxObject.idl
@@ -2,20 +2,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/. */
 
 #include "nsISupports.idl"
 
 interface nsITreeView;
 interface nsITreeSelection;
-interface nsITreeColumn;
 interface nsIScriptableRegion;
 
 webidl Element;
+webidl TreeColumn;
 webidl TreeColumns;
 
 /**
  * This interface cannot become builtinclass until bug 1438525 is fixed.
  */
 [scriptable, uuid(f3da0c5e-51f5-45f0-b2cd-6be3ab6847ae)]
 interface nsITreeBoxObject : nsISupports
 {
@@ -47,128 +47,60 @@ interface nsITreeBoxObject : nsISupports
   readonly attribute long rowHeight;
 
   /**
    * Obtain the width of a row.
    */
   readonly attribute long rowWidth;
 
   /**
-   * Get the pixel position of the horizontal scrollbar.
-   */
-  readonly attribute long horizontalPosition;
-
-  /**
-   * Return the region for the visible parts of the selection, in device pixels.
-   */
-  readonly attribute nsIScriptableRegion selectionRegion;
-
-  /**
    * Get the index of the first visible row.
    */
   long getFirstVisibleRow();
 
   /**
    * Get the index of the last visible row.
    */
   long getLastVisibleRow();
 
   /**
-   * Gets the number of possible visible rows.
-   */
-  long getPageLength();
-
-  /**
    * Ensures that a row at a given index is visible.
    */
   void ensureRowIsVisible(in long index);
 
   /**
-   * Ensures that a given cell in the tree is visible.
-   */
-  void ensureCellIsVisible(in long row, in nsITreeColumn col);
-
-  /**
-   * Scrolls such that the row at index is at the top of the visible view.
-   */
-  void scrollToRow(in long index);
-
-  /**
-   * Scroll the tree up or down by numLines lines. Positive
-   * values move down in the tree. Prevents scrolling off the
-   * end of the tree. 
-   */
-  void scrollByLines(in long numLines);
-
-  /**
-   * Scroll the tree up or down by numPages pages. A page
-   * is considered to be the amount displayed by the tree.
-   * Positive values move down in the tree. Prevents scrolling
-   * off the end of the tree.
-   */
-  void scrollByPages(in long numPages);
-  
-  /**
-   * Scrolls such that a given cell is visible (if possible) 
-   * at the top left corner of the visible view. 
-   */
-  void scrollToCell(in long row, in nsITreeColumn col);
-
-  /**
-   * Scrolls horizontally so that the specified column is 
-   * at the left of the view (if possible).
-   */
-  void scrollToColumn(in nsITreeColumn col);
-
-  /**
-   * Scroll to a specific horizontal pixel position.
-   */
-  void scrollToHorizontalPosition(in long horizontalPosition);
-
-  /**
    * Invalidation methods for fine-grained painting control.
    */
   void invalidate();
-  void invalidateColumn(in nsITreeColumn col);
+  void invalidateColumn(in TreeColumn col);
   void invalidateRow(in long index);
-  void invalidateCell(in long row, in nsITreeColumn col);
+  void invalidateCell(in long row, in TreeColumn col);
   void invalidateRange(in long startIndex, in long endIndex);
-  void invalidateColumnRange(in long startIndex, in long endIndex,
-                             in nsITreeColumn col);
-
-  /**
-   * A hit test that can tell you what row the mouse is over.
-   * returns -1 for invalid mouse coordinates.
-   *
-   * The coordinate system is the client coordinate system for the
-   * document this boxObject lives in, and the units are CSS pixels.
-   */
-  long getRowAt(in long x, in long y);
 
   /**
    * A hit test that can tell you what cell the mouse is over.  Row is the row index
    * hit,  returns -1 for invalid mouse coordinates.  ColID is the column hit.
    * ChildElt is the pseudoelement hit: this can have values of
    * "cell", "twisty", "image", and "text".
    *
    * The coordinate system is the client coordinate system for the
    * document this boxObject lives in, and the units are CSS pixels.
    */
-  void getCellAt(in long x, in long y, out long row, out nsITreeColumn col, out AString childElt);
+  void getCellAt(in long x, in long y, out long row, out TreeColumn col, out AString childElt);
 
   /** 
    * Find the coordinates of an element within a specific cell. 
    */
-  void getCoordsForCellItem(in long row, in nsITreeColumn col, in AString element,
+  void getCoordsForCellItem(in long row, in TreeColumn col, in AString element,
                             out long x, out long y, out long width, out long height);
 
   /** 
    * Determine if the text of a cell is being cropped or not.
    */
-  boolean isCellCropped(in long row, in nsITreeColumn col);
+  boolean isCellCropped(in long row, in TreeColumn col);
 
   /**
    * The view is responsible for calling these notification methods when
    * rows are added or removed.  Index is the position at which the new
    * rows were added or at which rows were removed.  For
    * non-contiguous additions/removals, this method should be called multiple times.
    */
   void rowCountChanged(in long index, in long count);
@@ -185,17 +117,9 @@ interface nsITreeBoxObject : nsISupports
    * Notify the tree that the view has completed a batch update.
    */
   void endUpdateBatch();
 
   /**
    * Called on a theme switch to flush out the tree's style and image caches.
    */
   void clearStyleAndImageCaches();
-
-  /**
-   * Remove an image source from the image cache to allow its invalidation.
-   *
-   * @note This only affects images supplied by the view, not the ones supplied
-   *       through the styling context, like twisties or checkboxes.
-   */
-  void removeImageCacheEntry(in long row, in nsITreeColumn col);
 };
deleted file mode 100644
--- a/layout/xul/tree/nsITreeColumns.idl
+++ /dev/null
@@ -1,39 +0,0 @@
-/* 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"
-
-webidl Element;
-webidl TreeColumns;
-
-[scriptable, uuid(ae835ecf-6b32-4660-9b43-8a270df56e02)]
-interface nsITreeColumn : nsISupports
-{
-  readonly attribute Element element;
-
-  readonly attribute TreeColumns columns;
-
-  readonly attribute long x;
-  readonly attribute long width;
-
-  readonly attribute AString id;
-  [noscript] void getIdConst([shared] out wstring idConst);
-
-  readonly attribute long index;
-
-  readonly attribute boolean primary;
-  readonly attribute boolean cycler;
-  readonly attribute boolean editable;
-  readonly attribute boolean selectable;
-
-  const short TYPE_TEXT                = 1;
-  const short TYPE_CHECKBOX            = 2;
-  const short TYPE_PASSWORD            = 3;
-  readonly attribute short type;
-
-  nsITreeColumn getNext();
-  nsITreeColumn getPrevious();
-
-  void invalidate();
-};
--- a/layout/xul/tree/nsITreeSelection.idl
+++ b/layout/xul/tree/nsITreeSelection.idl
@@ -1,15 +1,16 @@
 /* -*- 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/. */
 
 interface nsITreeBoxObject;
-interface nsITreeColumn;
+
+webidl TreeColumn;
 
 #include "nsISupports.idl"
 
 [scriptable, uuid(ab6fe746-300b-4ab4-abb9-1c0e3977874c)]
 interface nsITreeSelection : nsISupports
 {
   /**
    * The tree widget for this selection.
@@ -104,17 +105,17 @@ interface nsITreeSelection : nsISupports
    * The current item (the one that gets a focus rect in addition to being
    * selected).
    */
   attribute long currentIndex;
 
   /**
    * The current column.
    */
-  attribute nsITreeColumn currentColumn;
+  attribute TreeColumn currentColumn;
 
   /**
    * The selection "pivot".  This is the first item the user selected as
    * part of a ranged select.
    */
   readonly attribute long shiftSelectPivot;
 };
 
--- a/layout/xul/tree/nsITreeView.idl
+++ b/layout/xul/tree/nsITreeView.idl
@@ -2,19 +2,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 "nsISupports.idl"
 
 interface nsITreeBoxObject;
 interface nsITreeSelection;
-interface nsITreeColumn;
 
 webidl DataTransfer;
+webidl TreeColumn;
 
 [scriptable, uuid(091116f0-0bdc-4b32-b9c8-c8d5a37cb088)]
 interface nsITreeView : nsISupports
 {
   /**
    * The total number of rows in the tree (including the offscreen rows).
    */
   readonly attribute long rowCount;
@@ -35,23 +35,23 @@ interface nsITreeView : nsISupports
 
   /**
    * A whitespace delimited list of properties for a given cell.  Each
    * property, x, that the view gives back will cause the pseudoclasses
    *  ::-moz-tree-cell(x), ::-moz-tree-row(x), ::-moz-tree-twisty(x),
    *  ::-moz-tree-image(x), ::-moz-tree-cell-text(x). to be matched on the
    *  cell.
    */
-  AString getCellProperties(in long row, in nsITreeColumn col);
+  AString getCellProperties(in long row, in TreeColumn col);
   
   /**
    * Called to get properties to paint a column background.  For shading the sort
    * column, etc.
    */
-  AString getColumnProperties(in nsITreeColumn col);
+  AString getColumnProperties(in TreeColumn col);
 
   /**
    * Methods that can be used to test whether or not a twisty should be drawn,
    * and if so, whether an open or closed twisty should be used.
    */
   boolean isContainer(in long index);
   boolean isContainerOpen(in long index);
   boolean isContainerEmpty(in long index);
@@ -108,89 +108,89 @@ interface nsITreeView : nsISupports
    */
   long getLevel(in long index);
 
   /**
    * The image path for a given cell. For defining an icon for a cell.
    * If the empty string is returned, the :moz-tree-image pseudoelement
    * will be used.
    */
-  AString getImageSrc(in long row, in nsITreeColumn col);
+  AString getImageSrc(in long row, in TreeColumn col);
 
   /**
    * The value for a given cell. This method is only called for columns
    * of type other than |text|.
    */
-  AString getCellValue(in long row, in nsITreeColumn col);
+  AString getCellValue(in long row, in TreeColumn col);
 
   /**
    * The text for a given cell.  If a column consists only of an image, then
    * the empty string is returned.  
    */
-  AString getCellText(in long row, in nsITreeColumn col);
+  AString getCellText(in long row, in TreeColumn col);
 
   /**
    * Called during initialization to link the view to the front end box object.
    */
   void setTree(in nsITreeBoxObject tree);
   
   /**
    * Called on the view when an item is opened or closed.
    */
   void toggleOpenState(in long index);
 
   /**
    * Called on the view when a header is clicked.
    */
-  void cycleHeader(in nsITreeColumn col);
+  void cycleHeader(in TreeColumn col);
 
   /**
    * Should be called from a XUL onselect handler whenever the selection changes.
    */
   void selectionChanged();
 
   /**
    * Called on the view when a cell in a non-selectable cycling column (e.g., unread/flag/etc.) is clicked.
    */
-  void cycleCell(in long row, in nsITreeColumn col);
+  void cycleCell(in long row, in TreeColumn col);
   
   /**
    * isEditable is called to ask the view if the cell contents are editable.
    * A value of true will result in the tree popping up a text field when 
    * the user tries to inline edit the cell.
    */
-  boolean isEditable(in long row, in nsITreeColumn col);
+  boolean isEditable(in long row, in TreeColumn col);
 
   /**
    * isSelectable is called to ask the view if the cell is selectable.
    * This method is only called if the selection style is |cell| or |text|.
    * XXXvarga shouldn't this be called isCellSelectable?
    */
-  boolean isSelectable(in long row, in nsITreeColumn col);
+  boolean isSelectable(in long row, in TreeColumn col);
 
   /**
    * setCellValue is called when the value of the cell has been set by the user.
    * This method is only called for columns of type other than |text|.
    */
-  void setCellValue(in long row, in nsITreeColumn col, in AString value);
+  void setCellValue(in long row, in TreeColumn col, in AString value);
 
   /**
    * setCellText is called when the contents of the cell have been edited by the user.
    */   
-  void setCellText(in long row, in nsITreeColumn col, in AString value);
+  void setCellText(in long row, in TreeColumn col, in AString value);
 
   /**
    * A command API that can be used to invoke commands on the selection.  The tree
    * will automatically invoke this method when certain keys are pressed.  For example,
    * when the DEL key is pressed, performAction will be called with the "delete" string.
    */
   void performAction(in wstring action);
 
   /**
    * A command API that can be used to invoke commands on a specific row.
    */
   void performActionOnRow(in wstring action, in long row);
 
   /**
    * A command API that can be used to invoke commands on a specific cell.
    */
-  void performActionOnCell(in wstring action, in long row, in nsITreeColumn col);
+  void performActionOnCell(in wstring action, in long row, in TreeColumn col);
 };
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -57,16 +57,17 @@
 #include "nsLayoutUtils.h"
 #include "nsIScrollableFrame.h"
 #include "nsDisplayList.h"
 #include "mozilla/dom/CustomEvent.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "mozilla/dom/TreeBoxObject.h"
+#include "mozilla/dom/TreeColumnBinding.h"
 #include "nsIScriptableRegion.h"
 #include <algorithm>
 #include "ScrollbarActivity.h"
 
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #include "nsIWritablePropertyBag2.h"
 #endif
@@ -585,16 +586,18 @@ nsresult
 nsTreeBodyFrame::GetSelectionRegion(nsIScriptableRegion **aRegion)
 {
   *aRegion = nullptr;
 
   nsCOMPtr<nsITreeSelection> selection;
   mView->GetSelection(getter_AddRefs(selection));
   NS_ENSURE_TRUE(selection, NS_OK);
 
+  // XXXbz should we just construct as |new ScriptableRegion()|
+  // instead, and make this method return void?
   nsCOMPtr<nsIScriptableRegion> region = do_CreateInstance("@mozilla.org/gfx/region;1");
   NS_ENSURE_TRUE(region, NS_ERROR_FAILURE);
   region->Init();
 
   RefPtr<nsPresContext> presContext = PresContext();
   nsIntRect rect = mRect.ToOutsidePixels(presContext->AppUnitsPerCSSPixel());
 
   nsIFrame* rootFrame = presContext->PresShell()->GetRootFrame();
@@ -629,32 +632,31 @@ nsTreeBodyFrame::Invalidate()
     return NS_OK;
 
   InvalidateFrame();
 
   return NS_OK;
 }
 
 nsresult
-nsTreeBodyFrame::InvalidateColumn(nsITreeColumn* aCol)
+nsTreeBodyFrame::InvalidateColumn(nsTreeColumn* aCol)
 {
   if (mUpdateBatchNest)
     return NS_OK;
 
-  RefPtr<nsTreeColumn> col = GetColumnImpl(aCol);
-  if (!col)
+  if (!aCol)
     return NS_ERROR_INVALID_ARG;
 
 #ifdef ACCESSIBILITY
   if (nsIPresShell::IsAccessibilityActive())
     FireInvalidateEvent(-1, -1, aCol, aCol);
 #endif
 
   nsRect columnRect;
-  nsresult rv = col->GetRect(this, mInnerBox.y, mInnerBox.height, &columnRect);
+  nsresult rv = aCol->GetRect(this, mInnerBox.y, mInnerBox.height, &columnRect);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // When false then column is out of view
   if (OffsetForHorzScroll(columnRect, true))
       InvalidateFrameWithRect(columnRect);
 
   return NS_OK;
 }
@@ -676,37 +678,36 @@ nsTreeBodyFrame::InvalidateRow(int32_t a
 
   nsRect rowRect(mInnerBox.x, mInnerBox.y+mRowHeight*aIndex, mInnerBox.width, mRowHeight);
   InvalidateFrameWithRect(rowRect);
 
   return NS_OK;
 }
 
 nsresult
-nsTreeBodyFrame::InvalidateCell(int32_t aIndex, nsITreeColumn* aCol)
+nsTreeBodyFrame::InvalidateCell(int32_t aIndex, nsTreeColumn* aCol)
 {
   if (mUpdateBatchNest)
     return NS_OK;
 
 #ifdef ACCESSIBILITY
   if (nsIPresShell::IsAccessibilityActive())
     FireInvalidateEvent(aIndex, aIndex, aCol, aCol);
 #endif
 
   aIndex -= mTopRowIndex;
   if (aIndex < 0 || aIndex > mPageLength)
     return NS_OK;
 
-  RefPtr<nsTreeColumn> col = GetColumnImpl(aCol);
-  if (!col)
+  if (!aCol)
     return NS_ERROR_INVALID_ARG;
 
   nsRect cellRect;
-  nsresult rv = col->GetRect(this, mInnerBox.y+mRowHeight*aIndex, mRowHeight,
-                             &cellRect);
+  nsresult rv = aCol->GetRect(this, mInnerBox.y+mRowHeight*aIndex, mRowHeight,
+                              &cellRect);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (OffsetForHorzScroll(cellRect, true))
     InvalidateFrameWithRect(cellRect);
 
   return NS_OK;
 }
 
@@ -738,59 +739,16 @@ nsTreeBodyFrame::InvalidateRange(int32_t
 #endif
 
   nsRect rangeRect(mInnerBox.x, mInnerBox.y+mRowHeight*(aStart-mTopRowIndex), mInnerBox.width, mRowHeight*(aEnd-aStart+1));
   InvalidateFrameWithRect(rangeRect);
 
   return NS_OK;
 }
 
-nsresult
-nsTreeBodyFrame::InvalidateColumnRange(int32_t aStart, int32_t aEnd, nsITreeColumn* aCol)
-{
-  if (mUpdateBatchNest)
-    return NS_OK;
-
-  RefPtr<nsTreeColumn> col = GetColumnImpl(aCol);
-  if (!col)
-    return NS_ERROR_INVALID_ARG;
-
-  if (aStart == aEnd)
-    return InvalidateCell(aStart, col);
-
-  int32_t last = LastVisibleRow();
-  if (aStart > aEnd || aEnd < mTopRowIndex || aStart > last)
-    return NS_OK;
-
-  if (aStart < mTopRowIndex)
-    aStart = mTopRowIndex;
-
-  if (aEnd > last)
-    aEnd = last;
-
-#ifdef ACCESSIBILITY
-  if (nsIPresShell::IsAccessibilityActive()) {
-    int32_t end =
-      mRowCount > 0 ? ((mRowCount <= aEnd) ? mRowCount - 1 : aEnd) : 0;
-    FireInvalidateEvent(aStart, end, aCol, aCol);
-  }
-#endif
-
-  nsRect rangeRect;
-  nsresult rv = col->GetRect(this,
-                             mInnerBox.y+mRowHeight*(aStart-mTopRowIndex),
-                             mRowHeight*(aEnd-aStart+1),
-                             &rangeRect);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  InvalidateFrameWithRect(rangeRect);
-
-  return NS_OK;
-}
-
 static void
 FindScrollParts(nsIFrame* aCurrFrame, nsTreeBodyFrame::ScrollParts* aResult)
 {
   if (!aResult->mColumnsScrollFrame) {
     nsIScrollableFrame* f = do_QueryFrame(aCurrFrame);
     if (f) {
       aResult->mColumnsFrame = aCurrFrame;
       aResult->mColumnsScrollFrame = f;
@@ -1016,38 +974,36 @@ nsTreeBodyFrame::AdjustClientCoordsToBox
   point -= GetOffsetTo(presContext->GetPresShell()->GetRootFrame());
 
   // Adjust by the inner box coords, so that we're in the inner box's
   // coordinate space.
   point -= mInnerBox.TopLeft();
   return point;
 } // AdjustClientCoordsToBoxCoordSpace
 
-nsresult
-nsTreeBodyFrame::GetRowAt(int32_t aX, int32_t aY, int32_t* _retval)
+int32_t
+nsTreeBodyFrame::GetRowAt(int32_t aX, int32_t aY)
 {
-  if (!mView)
-    return NS_OK;
+  if (!mView) {
+    return 0;
+  }
 
   nsPoint point = AdjustClientCoordsToBoxCoordSpace(aX, aY);
 
   // Check if the coordinates are above our visible space.
   if (point.y < 0) {
-    *_retval = -1;
-    return NS_OK;
+    return -1;
   }
 
-  *_retval = GetRowAt(point.x, point.y);
-
-  return NS_OK;
+  return GetRowAtInternal(point.x, point.y);
 }
 
 nsresult
-nsTreeBodyFrame::GetCellAt(int32_t aX, int32_t aY, int32_t* aRow, nsITreeColumn** aCol,
-                           nsACString& aChildElt)
+nsTreeBodyFrame::GetCellAt(int32_t aX, int32_t aY, int32_t* aRow,
+                           nsTreeColumn** aCol, nsACString& aChildElt)
 {
   if (!mView)
     return NS_OK;
 
   nsPoint point = AdjustClientCoordsToBoxCoordSpace(aX, aY);
 
   // Check if the coordinates are above our visible space.
   if (point.y < 0) {
@@ -1092,17 +1048,17 @@ nsTreeBodyFrame::GetCellAt(int32_t aX, i
 // cell rect fits inside the adjusted row rect.  It also can have border/padding
 // as well as margins.  The vertical direction isn't that important, but you need
 // to get the horizontal direction right.
 //
 // (3) GetImageSize() does not include margins (but it does include border/padding).
 // You need to make sure to add in the image's margins as well.
 //
 nsresult
-nsTreeBodyFrame::GetCoordsForCellItem(int32_t aRow, nsITreeColumn* aCol, const nsACString& aElement,
+nsTreeBodyFrame::GetCoordsForCellItem(int32_t aRow, nsTreeColumn* aCol, const nsACString& aElement,
                                       int32_t *aX, int32_t *aY, int32_t *aWidth, int32_t *aHeight)
 {
   *aX = 0;
   *aY = 0;
   *aWidth = 0;
   *aHeight = 0;
 
   bool isRTL = StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
@@ -1280,17 +1236,17 @@ nsTreeBodyFrame::GetCoordsForCellItem(in
   *aY = nsPresContext::AppUnitsToIntCSSPixels(theRect.y);
   *aWidth = nsPresContext::AppUnitsToIntCSSPixels(theRect.width);
   *aHeight = nsPresContext::AppUnitsToIntCSSPixels(theRect.height);
 
   return NS_OK;
 }
 
 int32_t
-nsTreeBodyFrame::GetRowAt(int32_t aX, int32_t aY)
+nsTreeBodyFrame::GetRowAtInternal(nscoord aX, nscoord aY)
 {
   if (mRowHeight <= 0)
     return -1;
 
   // Now just mod by our total inner box height and add to our top row index.
   int32_t row = (aY/mRowHeight)+mTopRowIndex;
 
   // Check if the coordinates are below our visible space (or within our visible
@@ -1637,17 +1593,17 @@ nsTreeBodyFrame::GetItemWithinCellAt(nsc
 void
 nsTreeBodyFrame::GetCellAt(nscoord aX, nscoord aY, int32_t* aRow,
                            nsTreeColumn** aCol,
                            nsICSSAnonBoxPseudo** aChildElt)
 {
   *aCol = nullptr;
   *aChildElt = nullptr;
 
-  *aRow = GetRowAt(aX, aY);
+  *aRow = GetRowAtInternal(aX, aY);
   if (*aRow < 0)
     return;
 
   // Determine the column hit.
   for (nsTreeColumn* currCol = mColumns->GetFirstColumn(); currCol;
        currCol = currCol->GetNext()) {
     nsRect cellRect;
     nsresult rv = currCol->GetRect(this,
@@ -1758,29 +1714,28 @@ nsTreeBodyFrame::GetCellWidth(int32_t aR
   nscoord width = nsLayoutUtils::AppUnitWidthOfStringBidi(cellText, this, *fm,
                                                           *aRenderingContext);
   nscoord totalTextWidth = width + bp.left + bp.right;
   aDesiredSize += totalTextWidth;
   return NS_OK;
 }
 
 nsresult
-nsTreeBodyFrame::IsCellCropped(int32_t aRow, nsITreeColumn* aCol, bool *_retval)
+nsTreeBodyFrame::IsCellCropped(int32_t aRow, nsTreeColumn* aCol, bool *_retval)
 {
   nscoord currentSize, desiredSize;
   nsresult rv;
 
-  RefPtr<nsTreeColumn> col = GetColumnImpl(aCol);
-  if (!col)
+  if (!aCol)
     return NS_ERROR_INVALID_ARG;
 
   RefPtr<gfxContext> rc =
     PresShell()->CreateReferenceRenderingContext();
 
-  rv = GetCellWidth(aRow, col, rc, desiredSize, currentSize);
+  rv = GetCellWidth(aRow, aCol, rc, desiredSize, currentSize);
   NS_ENSURE_SUCCESS(rv, rv);
 
   *_retval = desiredSize > currentSize;
 
   return NS_OK;
 }
 
 void
@@ -1959,17 +1914,17 @@ nsTreeBodyFrame::PrefillPropertyArray(in
       // current
       int32_t currentIndex;
       selection->GetCurrentIndex(&currentIndex);
       if (aRowIndex == currentIndex)
         mScratchArray.AppendElement(nsGkAtoms::current);
 
       // active
       if (aCol) {
-        nsCOMPtr<nsITreeColumn> currentColumn;
+        RefPtr<nsTreeColumn> currentColumn;
         selection->GetCurrentColumn(getter_AddRefs(currentColumn));
         if (aCol == currentColumn)
           mScratchArray.AppendElement(nsGkAtoms::active);
       }
     }
 
     // container or leaf
     bool isContainer = false;
@@ -2015,17 +1970,17 @@ nsTreeBodyFrame::PrefillPropertyArray(in
   }
 
   if (aCol) {
     mScratchArray.AppendElement(aCol->GetAtom());
 
     if (aCol->IsPrimary())
       mScratchArray.AppendElement(nsGkAtoms::primary);
 
-    if (aCol->GetType() == nsITreeColumn::TYPE_CHECKBOX) {
+    if (aCol->GetType() == TreeColumnBinding::TYPE_CHECKBOX) {
       mScratchArray.AppendElement(nsGkAtoms::checkbox);
 
       if (aRowIndex != -1) {
         nsAutoString value;
         mView->GetCellValue(aRowIndex, aCol, value);
         if (value.EqualsLiteral("true"))
           mScratchArray.AppendElement(nsGkAtoms::checked);
       }
@@ -2554,17 +2509,17 @@ nsresult
 nsTreeBodyFrame::HandleEvent(nsPresContext* aPresContext,
                              WidgetGUIEvent* aEvent,
                              nsEventStatus* aEventStatus)
 {
   if (aEvent->mMessage == eMouseOver || aEvent->mMessage == eMouseMove) {
     nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
     int32_t xTwips = pt.x - mInnerBox.x;
     int32_t yTwips = pt.y - mInnerBox.y;
-    int32_t newrow = GetRowAt(xTwips, yTwips);
+    int32_t newrow = GetRowAtInternal(xTwips, yTwips);
     if (mMouseOverRow != newrow) {
       // redraw the old and the new row
       if (mMouseOverRow != -1)
         InvalidateRow(mMouseOverRow);
       mMouseOverRow = newrow;
       if (mMouseOverRow != -1)
         InvalidateRow(mMouseOverRow);
     }
@@ -3386,22 +3341,22 @@ nsTreeBodyFrame::PaintCell(int32_t      
   // Now paint our element, but only if we aren't a cycler column.
   // XXX until we have the ability to load images, allow the view to
   // insert text into cycler columns...
   if (!aColumn->IsCycler()) {
     nsRect elementRect(currX, cellRect.y, remainingWidth, cellRect.height);
     nsRect dirtyRect;
     if (dirtyRect.IntersectRect(aDirtyRect, elementRect)) {
       switch (aColumn->GetType()) {
-        case nsITreeColumn::TYPE_TEXT:
-        case nsITreeColumn::TYPE_PASSWORD:
+        case TreeColumnBinding::TYPE_TEXT:
+        case TreeColumnBinding::TYPE_PASSWORD:
           result &= PaintText(aRowIndex, aColumn, elementRect, aPresContext,
                               aRenderingContext, aDirtyRect, currX);
           break;
-        case nsITreeColumn::TYPE_CHECKBOX:
+        case TreeColumnBinding::TYPE_CHECKBOX:
           result &= PaintCheckbox(aRowIndex, aColumn, elementRect, aPresContext,
                                   aRenderingContext, aDirtyRect);
           break;
       }
     }
   }
 
   aCurrX = currX;
@@ -3704,17 +3659,17 @@ nsTreeBodyFrame::PaintText(int32_t      
   MOZ_ASSERT(aColumn && aColumn->GetFrame(), "invalid column passed");
 
   bool isRTL = StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
 
   // Now obtain the text for our cell.
   nsAutoString text;
   mView->GetCellText(aRowIndex, aColumn, text);
 
-  if (aColumn->Type() == nsITreeColumn::TYPE_PASSWORD) {
+  if (aColumn->Type() == TreeColumnBinding::TYPE_PASSWORD) {
     TextEditRules::FillBufWithPWChars(&text, text.Length());
   }
 
   // We're going to paint this text so we need to ensure bidi is enabled if
   // necessary
   CheckTextForBidi(text);
 
   ImgDrawResult result = ImgDrawResult::SUCCESS;
@@ -4060,33 +4015,32 @@ nsresult nsTreeBodyFrame::EnsureRowIsVis
     int32_t distance = aRow - (mTopRowIndex+mPageLength)+1;
     ScrollToRowInternal(aParts, mTopRowIndex+distance);
   }
 
   return NS_OK;
 }
 
 nsresult
-nsTreeBodyFrame::EnsureCellIsVisible(int32_t aRow, nsITreeColumn* aCol)
+nsTreeBodyFrame::EnsureCellIsVisible(int32_t aRow, nsTreeColumn* aCol)
 {
-  RefPtr<nsTreeColumn> col = GetColumnImpl(aCol);
-  if (!col)
+  if (!aCol)
     return NS_ERROR_INVALID_ARG;
 
   ScrollParts parts = GetScrollParts();
 
   nscoord result = -1;
   nsresult rv;
 
   nscoord columnPos;
-  rv = col->GetXInTwips(this, &columnPos);
+  rv = aCol->GetXInTwips(this, &columnPos);
   if(NS_FAILED(rv)) return rv;
 
   nscoord columnWidth;
-  rv = col->GetWidthInTwips(this, &columnWidth);
+  rv = aCol->GetWidthInTwips(this, &columnWidth);
   if(NS_FAILED(rv)) return rv;
 
   // If the start of the column is before the
   // start of the horizontal view, then scroll
   if (columnPos < mHorzPosition)
     result = columnPos;
   // If the end of the column is past the end of
   // the horizontal view, then scroll
@@ -4099,102 +4053,49 @@ nsTreeBodyFrame::EnsureCellIsVisible(int
   }
 
   rv = EnsureRowIsVisibleInternal(parts, aRow);
   NS_ENSURE_SUCCESS(rv, rv);
   UpdateScrollbars(parts);
   return rv;
 }
 
-nsresult
-nsTreeBodyFrame::ScrollToCell(int32_t aRow, nsITreeColumn* aCol)
-{
-  ScrollParts parts = GetScrollParts();
-  nsresult rv = ScrollToRowInternal(parts, aRow);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = ScrollToColumnInternal(parts, aCol);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  UpdateScrollbars(parts);
-  return rv;
-}
-
-nsresult
-nsTreeBodyFrame::ScrollToColumn(nsITreeColumn* aCol)
-{
-  ScrollParts parts = GetScrollParts();
-  nsresult rv = ScrollToColumnInternal(parts, aCol);
-  NS_ENSURE_SUCCESS(rv, rv);
-  UpdateScrollbars(parts);
-  return rv;
-}
-
-nsresult nsTreeBodyFrame::ScrollToColumnInternal(const ScrollParts& aParts,
-                                                 nsITreeColumn* aCol)
-{
-  RefPtr<nsTreeColumn> col = GetColumnImpl(aCol);
-  if (!col)
-    return NS_ERROR_INVALID_ARG;
-
-  nscoord x;
-  nsresult rv = col->GetXInTwips(this, &x);
-  if (NS_FAILED(rv))
-    return rv;
-
-  return ScrollHorzInternal(aParts, x);
-}
-
-nsresult
-nsTreeBodyFrame::ScrollToHorizontalPosition(int32_t aHorizontalPosition)
-{
-  ScrollParts parts = GetScrollParts();
-  int32_t position = nsPresContext::CSSPixelsToAppUnits(aHorizontalPosition);
-  nsresult rv = ScrollHorzInternal(parts, position);
-  NS_ENSURE_SUCCESS(rv, rv);
-  UpdateScrollbars(parts);
-  return rv;
-}
-
-nsresult
+void
 nsTreeBodyFrame::ScrollToRow(int32_t aRow)
 {
   ScrollParts parts = GetScrollParts();
   ScrollToRowInternal(parts, aRow);
   UpdateScrollbars(parts);
-  return NS_OK;
 }
 
 nsresult nsTreeBodyFrame::ScrollToRowInternal(const ScrollParts& aParts, int32_t aRow)
 {
   ScrollInternal(aParts, aRow);
 
   return NS_OK;
 }
 
-nsresult
+void
 nsTreeBodyFrame::ScrollByLines(int32_t aNumLines)
 {
   if (!mView) {
-    return NS_OK;
+    return;
   }
   int32_t newIndex = mTopRowIndex + aNumLines;
   ScrollToRow(newIndex);
-  return NS_OK;
 }
 
-nsresult
+void
 nsTreeBodyFrame::ScrollByPages(int32_t aNumPages)
 {
   if (!mView) {
-    return NS_OK;
+    return;
   }
   int32_t newIndex = mTopRowIndex + aNumPages * mPageLength;
   ScrollToRow(newIndex);
-  return NS_OK;
 }
 
 nsresult
 nsTreeBodyFrame::ScrollInternal(const ScrollParts& aParts, int32_t aRow)
 {
   if (!mView) {
     return NS_OK;
   }
@@ -4367,30 +4268,29 @@ nsresult
 nsTreeBodyFrame::ClearStyleAndImageCaches()
 {
   mStyleCache.Clear();
   CancelImageRequests();
   mImageCache.Clear();
   return NS_OK;
 }
 
-nsresult
-nsTreeBodyFrame::RemoveImageCacheEntry(int32_t aRowIndex, nsITreeColumn* aCol)
+void
+nsTreeBodyFrame::RemoveImageCacheEntry(int32_t aRowIndex, nsTreeColumn* aCol)
 {
   nsAutoString imageSrc;
   if (NS_SUCCEEDED(mView->GetImageSrc(aRowIndex, aCol, imageSrc))) {
     nsTreeImageCacheEntry entry;
     if (mImageCache.Get(imageSrc, &entry)) {
       nsLayoutUtils::DeregisterImageRequest(PresContext(), entry.request,
                                             nullptr);
       entry.request->CancelAndForgetObserver(NS_BINDING_ABORTED);
       mImageCache.Remove(imageSrc);
     }
   }
-  return NS_OK;
 }
 
 /* virtual */ void
 nsTreeBodyFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle)
 {
   nsLeafBoxFrame::DidSetComputedStyle(aOldComputedStyle);
 
   // Clear the style cache; the pointers are no longer even valid
@@ -4465,17 +4365,17 @@ nsTreeBodyFrame::ComputeDropPosition(Wid
   *aScrollLines = 0;
 
   // Convert the event's point to our coordinates.  We want it in
   // the coordinates of our inner box's coordinates.
   nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
   int32_t xTwips = pt.x - mInnerBox.x;
   int32_t yTwips = pt.y - mInnerBox.y;
 
-  *aRow = GetRowAt(xTwips, yTwips);
+  *aRow = GetRowAtInternal(xTwips, yTwips);
   if (*aRow >=0) {
     // Compute the top/bottom of the row in question.
     int32_t yOffset = yTwips - mRowHeight * (*aRow - mTopRowIndex);
 
     bool isContainer = false;
     mView->IsContainer (*aRow, &isContainer);
     if (isContainer) {
       // for a container, use a 25%/50%/25% breakdown
@@ -4708,18 +4608,18 @@ nsTreeBodyFrame::FireRowCountChangedEven
 
   RefPtr<AsyncEventDispatcher> asyncDispatcher =
     new AsyncEventDispatcher(content, event);
   asyncDispatcher->PostDOMEvent();
 }
 
 void
 nsTreeBodyFrame::FireInvalidateEvent(int32_t aStartRowIdx, int32_t aEndRowIdx,
-                                     nsITreeColumn *aStartCol,
-                                     nsITreeColumn *aEndCol)
+                                     nsTreeColumn *aStartCol,
+                                     nsTreeColumn *aEndCol)
 {
   nsCOMPtr<nsIContent> content(GetBaseElement());
   if (!content)
     return;
 
   nsCOMPtr<nsIDocument> doc = content->OwnerDoc();
 
   RefPtr<Event> event = doc->CreateEvent(NS_LITERAL_STRING("customevent"),
@@ -4743,30 +4643,23 @@ nsTreeBodyFrame::FireInvalidateEvent(int
 
     // Set 'endrow' data - the end index of invalidated rows.
     propBag->SetPropertyAsInt32(NS_LITERAL_STRING("endrow"),
                                 aEndRowIdx);
   }
 
   if (aStartCol && aEndCol) {
     // Set 'startcolumn' data - the start index of invalidated rows.
-    int32_t startColIdx = 0;
-    nsresult rv = aStartCol->GetIndex(&startColIdx);
-    if (NS_FAILED(rv))
-      return;
+    int32_t startColIdx = aStartCol->GetIndex();
 
     propBag->SetPropertyAsInt32(NS_LITERAL_STRING("startcolumn"),
                                 startColIdx);
 
     // Set 'endcolumn' data - the start index of invalidated rows.
-    int32_t endColIdx = 0;
-    rv = aEndCol->GetIndex(&endColIdx);
-    if (NS_FAILED(rv))
-      return;
-
+    int32_t endColIdx = aEndCol->GetIndex();
     propBag->SetPropertyAsInt32(NS_LITERAL_STRING("endcolumn"),
                                 endColIdx);
   }
 
   InitCustomEvent(treeEvent, NS_LITERAL_STRING("TreeInvalidated"),
                   propBag);
 
   event->SetTrusted(true);
--- a/layout/xul/tree/nsTreeBodyFrame.h
+++ b/layout/xul/tree/nsTreeBodyFrame.h
@@ -86,43 +86,38 @@ public:
   int32_t RowHeight() const;
   int32_t RowWidth();
   int32_t GetHorizontalPosition() const;
   nsresult GetSelectionRegion(nsIScriptableRegion **aRegion);
   int32_t FirstVisibleRow() const { return mTopRowIndex; }
   int32_t LastVisibleRow() const { return mTopRowIndex + mPageLength; }
   int32_t PageLength() const { return mPageLength; }
   nsresult EnsureRowIsVisible(int32_t aRow);
-  nsresult EnsureCellIsVisible(int32_t aRow, nsITreeColumn *aCol);
-  nsresult ScrollToRow(int32_t aRow);
-  nsresult ScrollByLines(int32_t aNumLines);
-  nsresult ScrollByPages(int32_t aNumPages);
-  nsresult ScrollToCell(int32_t aRow, nsITreeColumn *aCol);
-  nsresult ScrollToColumn(nsITreeColumn *aCol);
-  nsresult ScrollToHorizontalPosition(int32_t aValue);
+  nsresult EnsureCellIsVisible(int32_t aRow, nsTreeColumn *aCol);
+  void ScrollToRow(int32_t aRow);
+  void ScrollByLines(int32_t aNumLines);
+  void ScrollByPages(int32_t aNumPages);
   nsresult Invalidate();
-  nsresult InvalidateColumn(nsITreeColumn *aCol);
+  nsresult InvalidateColumn(nsTreeColumn *aCol);
   nsresult InvalidateRow(int32_t aRow);
-  nsresult InvalidateCell(int32_t aRow, nsITreeColumn *aCol);
+  nsresult InvalidateCell(int32_t aRow, nsTreeColumn *aCol);
   nsresult InvalidateRange(int32_t aStart, int32_t aEnd);
-  nsresult InvalidateColumnRange(int32_t aStart, int32_t aEnd,
-                                 nsITreeColumn *aCol);
-  nsresult GetRowAt(int32_t aX, int32_t aY, int32_t *aValue);
+  int32_t GetRowAt(int32_t aX, int32_t aY);
   nsresult GetCellAt(int32_t aX, int32_t aY, int32_t *aRow,
-                     nsITreeColumn **aCol, nsACString &aChildElt);
-  nsresult GetCoordsForCellItem(int32_t aRow, nsITreeColumn *aCol,
+                     nsTreeColumn **aCol, nsACString &aChildElt);
+  nsresult GetCoordsForCellItem(int32_t aRow, nsTreeColumn *aCol,
                                 const nsACString &aElt,
                                 int32_t *aX, int32_t *aY,
                                 int32_t *aWidth, int32_t *aHeight);
-  nsresult IsCellCropped(int32_t aRow, nsITreeColumn *aCol, bool *aResult);
+  nsresult IsCellCropped(int32_t aRow, nsTreeColumn *aCol, bool *aResult);
   nsresult RowCountChanged(int32_t aIndex, int32_t aCount);
   nsresult BeginUpdateBatch();
   nsresult EndUpdateBatch();
   nsresult ClearStyleAndImageCaches();
-  nsresult RemoveImageCacheEntry(int32_t aRowIndex, nsITreeColumn* aCol);
+  void RemoveImageCacheEntry(int32_t aRowIndex, nsTreeColumn* aCol);
 
   void CancelImageRequests();
 
   void ManageReflowCallback(const nsRect& aRect, nscoord aHorzWidth);
 
   virtual nsSize GetXULMinSize(nsBoxLayoutState& aBoxLayoutState) override;
   virtual void SetXULBounds(nsBoxLayoutState& aBoxLayoutState, const nsRect& aRect,
                             bool aRemoveOverflowArea = false) override;
@@ -290,17 +285,17 @@ protected:
                                      nsPresContext*       aPresContext,
                                      gfxContext&          aRenderingContext,
                                      const nsRect&        aRect,
                                      const nsRect&        aDirtyRect);
 
 
   // An internal hit test.  aX and aY are expected to be in twips in the
   // coordinate system of this frame.
-  int32_t GetRowAt(nscoord aX, nscoord aY);
+  int32_t GetRowAtInternal(nscoord aX, nscoord aY);
 
   // Check for bidi characters in the text, and if there are any, ensure
   // that the prescontext is in bidi mode.
   void CheckTextForBidi(nsAutoString& aText);
 
   void AdjustForCellText(nsAutoString& aText,
                          int32_t aRowIndex,
                          nsTreeColumn* aColumn,
@@ -380,17 +375,16 @@ protected:
 
   // Use to auto-fill some of the common properties without the view having to do it.
   // Examples include container, open, selected, and focus.
   void PrefillPropertyArray(int32_t aRowIndex, nsTreeColumn* aCol);
 
   // Our internal scroll method, used by all the public scroll methods.
   nsresult ScrollInternal(const ScrollParts& aParts, int32_t aRow);
   nsresult ScrollToRowInternal(const ScrollParts& aParts, int32_t aRow);
-  nsresult ScrollToColumnInternal(const ScrollParts& aParts, nsITreeColumn* aCol);
   nsresult ScrollHorzInternal(const ScrollParts& aParts, int32_t aPosition);
   nsresult EnsureRowIsVisibleInternal(const ScrollParts& aParts, int32_t aRow);
 
   // Convert client pixels into appunits in our coordinate space.
   nsPoint AdjustClientCoordsToBoxCoordSpace(int32_t aX, int32_t aY);
 
   // Cache the box object
   void EnsureBoxObject();
@@ -425,25 +419,16 @@ protected:
 
   void InvalidateDropFeedback(int32_t aRow, int16_t aOrientation) {
     InvalidateRow(aRow);
     if (aOrientation != nsITreeView::DROP_ON)
       InvalidateRow(aRow + aOrientation);
   }
 
 public:
-  static
-  already_AddRefed<nsTreeColumn> GetColumnImpl(nsITreeColumn* aUnknownCol) {
-    if (!aUnknownCol)
-      return nullptr;
-
-    nsCOMPtr<nsTreeColumn> col = do_QueryInterface(aUnknownCol);
-    return col.forget();
-  }
-
   /**
    * Remove an nsITreeImageListener from being tracked by this frame. Only tree
    * image listeners that are created by this frame are tracked.
    *
    * @param aListener A pointer to an nsTreeImageListener to no longer
    *        track.
    */
   void RemoveTreeImageListener(nsTreeImageListener* aListener);
@@ -510,17 +495,17 @@ protected:
    * @param aEndRow    the end index of invalidated rows, -1 means that columns
    *                   have been invalidated only
    * @param aStartCol  the start invalidated column, nullptr means that only rows
    *                   have been invalidated
    * @param aEndCol    the end invalidated column, nullptr means that rows have
    *                   been invalidated only
    */
   void FireInvalidateEvent(int32_t aStartRow, int32_t aEndRow,
-                           nsITreeColumn *aStartCol, nsITreeColumn *aEndCol);
+                           nsTreeColumn *aStartCol, nsTreeColumn *aEndCol);
 #endif
 
 protected: // Data Members
 
   class Slots {
     public:
       Slots() {
       }
--- a/layout/xul/tree/nsTreeColumns.cpp
+++ b/layout/xul/tree/nsTreeColumns.cpp
@@ -25,17 +25,17 @@ nsTreeColumn::nsTreeColumn(nsTreeColumns
     mColumns(aColumns),
     mPrevious(nullptr)
 {
   NS_ASSERTION(aElement &&
                aElement->NodeInfo()->Equals(nsGkAtoms::treecol,
                                             kNameSpaceID_XUL),
                "nsTreeColumn's content must be a <xul:treecol>");
 
-  Invalidate();
+  Invalidate(IgnoreErrors());
 }
 
 nsTreeColumn::~nsTreeColumn()
 {
   if (mNext) {
     mNext->SetPrevious(nullptr);
   }
 }
@@ -57,26 +57,23 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsTreeColumn)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsTreeColumn)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsTreeColumn)
 
 // QueryInterface implementation for nsTreeColumn
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsTreeColumn)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  NS_INTERFACE_MAP_ENTRY(nsITreeColumn)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY_CONCRETE(nsTreeColumn)
 NS_INTERFACE_MAP_END
 
 nsIFrame*
 nsTreeColumn::GetFrame()
 {
-  NS_ENSURE_TRUE(mContent, nullptr);
-
   return mContent->GetPrimaryFrame();
 }
 
 bool
 nsTreeColumn::IsLastVisible(nsTreeBodyFrame* aBodyFrame)
 {
   NS_ASSERTION(GetFrame(), "should have checked for this already");
 
@@ -139,130 +136,30 @@ nsTreeColumn::GetWidthInTwips(nsTreeBody
   }
   *aResult = frame->GetRect().width;
   if (IsLastVisible(aBodyFrame))
     *aResult += aBodyFrame->mAdjustWidth;
   return NS_OK;
 }
 
 
-NS_IMETHODIMP
-nsTreeColumn::GetElement(Element** aElement)
-{
-  if (mContent) {
-    RefPtr<dom::Element> element = mContent;
-    element.forget(aElement);
-    return NS_OK;
-  }
-  *aElement = nullptr;
-  return NS_ERROR_FAILURE;
-}
-
-NS_IMETHODIMP
-nsTreeColumn::GetColumns(nsTreeColumns** aColumns)
-{
-  NS_IF_ADDREF(*aColumns = mColumns);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsTreeColumn::GetX(int32_t* aX)
-{
-  nsIFrame* frame = GetFrame();
-  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
-
-  *aX = nsPresContext::AppUnitsToIntCSSPixels(frame->GetRect().x);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsTreeColumn::GetWidth(int32_t* aWidth)
-{
-  nsIFrame* frame = GetFrame();
-  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
-
-  *aWidth = nsPresContext::AppUnitsToIntCSSPixels(frame->GetRect().width);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsTreeColumn::GetId(nsAString& aId)
+void
+nsTreeColumn::GetId(nsAString& aId) const
 {
   aId = GetId();
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsTreeColumn::GetIdConst(const char16_t** aIdConst)
-{
-  *aIdConst = mId.get();
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsTreeColumn::GetIndex(int32_t* aIndex)
-{
-  *aIndex = GetIndex();
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsTreeColumn::GetPrimary(bool* aPrimary)
-{
-  *aPrimary = IsPrimary();
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsTreeColumn::GetCycler(bool* aCycler)
-{
-  *aCycler = IsCycler();
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsTreeColumn::GetEditable(bool* aEditable)
-{
-  *aEditable = IsEditable();
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsTreeColumn::GetSelectable(bool* aSelectable)
-{
-  *aSelectable = IsSelectable();
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsTreeColumn::GetType(int16_t* aType)
-{
-  *aType = GetType();
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsTreeColumn::GetNext(nsITreeColumn** _retval)
-{
-  NS_IF_ADDREF(*_retval = GetNext());
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsTreeColumn::GetPrevious(nsITreeColumn** _retval)
-{
-  NS_IF_ADDREF(*_retval = GetPrevious());
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsTreeColumn::Invalidate()
+void
+nsTreeColumn::Invalidate(ErrorResult& aRv)
 {
   nsIFrame* frame = GetFrame();
-  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
+  if (NS_WARN_IF(!frame)) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
 
   // Fetch the Id.
   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, mId);
 
   // If we have an Id, cache the Id as an atom.
   if (!mId.IsEmpty()) {
     mAtom = NS_Atomize(mId);
   }
@@ -308,26 +205,26 @@ nsTreeColumn::Invalidate()
     !mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::selectable,
                            nsGkAtoms::_false, eCaseMatters);
 
   mOverflow =
     mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::overflow,
                           nsGkAtoms::_true, eCaseMatters);
 
   // Figure out our column type. Default type is text.
-  mType = nsITreeColumn::TYPE_TEXT;
+  mType = TreeColumnBinding::TYPE_TEXT;
   static Element::AttrValuesArray typestrings[] =
     {&nsGkAtoms::checkbox, &nsGkAtoms::password,
      nullptr};
   switch (mContent->FindAttrValueIn(kNameSpaceID_None,
                                     nsGkAtoms::type,
                                     typestrings,
                                     eCaseMatters)) {
-    case 0: mType = nsITreeColumn::TYPE_CHECKBOX; break;
-    case 1: mType = nsITreeColumn::TYPE_PASSWORD; break;
+    case 0: mType = TreeColumnBinding::TYPE_CHECKBOX; break;
+    case 1: mType = TreeColumnBinding::TYPE_PASSWORD; break;
   }
 
   // Fetch the crop style.
   mCropStyle = 0;
   static Element::AttrValuesArray cropstrings[] =
     {&nsGkAtoms::center, &nsGkAtoms::left, &nsGkAtoms::start, nullptr};
   switch (mContent->FindAttrValueIn(kNameSpaceID_None,
                                     nsGkAtoms::crop, cropstrings,
@@ -335,63 +232,58 @@ nsTreeColumn::Invalidate()
     case 0:
       mCropStyle = 1;
       break;
     case 1:
     case 2:
       mCropStyle = 2;
       break;
   }
-
-  return NS_OK;
 }
 
 nsIContent*
 nsTreeColumn::GetParentObject() const
 {
   return mContent;
 }
 
 /* virtual */ JSObject*
 nsTreeColumn::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return dom::TreeColumnBinding::Wrap(aCx, this, aGivenProto);
 }
 
-mozilla::dom::Element*
-nsTreeColumn::GetElement(mozilla::ErrorResult& aRv)
+Element*
+nsTreeColumn::Element()
 {
-  RefPtr<Element> element;
-  aRv = GetElement(getter_AddRefs(element));
-  if (aRv.Failed()) {
-    return nullptr;
-  }
-  return element;
+  return mContent;
 }
 
 int32_t
 nsTreeColumn::GetX(mozilla::ErrorResult& aRv)
 {
-  int32_t x;
-  aRv = GetX(&x);
-  return x;
+  nsIFrame* frame = GetFrame();
+  if (NS_WARN_IF(!frame)) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return 0;
+  }
+  
+  return nsPresContext::AppUnitsToIntCSSPixels(frame->GetRect().x);
 }
 
 int32_t
 nsTreeColumn::GetWidth(mozilla::ErrorResult& aRv)
 {
-  int32_t width;
-  aRv = GetWidth(&width);
-  return width;
-}
+  nsIFrame* frame = GetFrame();
+  if (NS_WARN_IF(!frame)) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return 0;
+  }
 
-void
-nsTreeColumn::Invalidate(mozilla::ErrorResult& aRv)
-{
-  aRv = Invalidate();
+  return nsPresContext::AppUnitsToIntCSSPixels(frame->GetRect().width);
 }
 
 nsTreeColumns::nsTreeColumns(nsTreeBodyFrame* aTree)
   : mTree(aTree)
 {
 }
 
 nsTreeColumns::~nsTreeColumns()
@@ -454,18 +346,17 @@ nsTreeColumns::GetLastColumn()
   return nullptr;
 }
 
 nsTreeColumn*
 nsTreeColumns::GetSortedColumn()
 {
   EnsureColumns();
   for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
-    if (currCol->mContent &&
-        nsContentUtils::HasNonEmptyAttr(currCol->mContent, kNameSpaceID_None,
+    if (nsContentUtils::HasNonEmptyAttr(currCol->mContent, kNameSpaceID_None,
                                         nsGkAtoms::sortDirection)) {
       return currCol;
     }
   }
   return nullptr;
 }
 
 nsTreeColumn*
@@ -474,25 +365,24 @@ nsTreeColumns::GetKeyColumn()
   EnsureColumns();
 
   nsTreeColumn* first = nullptr;
   nsTreeColumn* primary = nullptr;
   nsTreeColumn* sorted = nullptr;
 
   for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
     // Skip hidden columns.
-    if (!currCol->mContent ||
-        currCol->mContent->AttrValueIs(kNameSpaceID_None,
+    if (currCol->mContent->AttrValueIs(kNameSpaceID_None,
                                        nsGkAtoms::hidden,
                                        nsGkAtoms::_true,
                                        eCaseMatters))
       continue;
 
     // Skip non-text column
-    if (currCol->GetType() != nsITreeColumn::TYPE_TEXT)
+    if (currCol->GetType() != TreeColumnBinding::TYPE_TEXT)
       continue;
 
     if (!first)
       first = currCol;
 
     if (nsContentUtils::HasNonEmptyAttr(currCol->mContent, kNameSpaceID_None,
                                         nsGkAtoms::sortDirection)) {
       // Use sorted column as the key.
--- a/layout/xul/tree/nsTreeColumns.h
+++ b/layout/xul/tree/nsTreeColumns.h
@@ -2,17 +2,16 @@
 /* vim: set ts=8 sts=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 nsTreeColumns_h__
 #define nsTreeColumns_h__
 
-#include "nsITreeColumns.h"
 #include "nsITreeBoxObject.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/RefPtr.h"
 #include "nsCoord.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsQueryObject.h"
 #include "nsWrapperCache.h"
 #include "nsString.h"
@@ -37,46 +36,39 @@ class TreeBoxObject;
     0x02cd1963,                                      \
     0x4b5d,                                          \
     0x4a6c,                                          \
     {0x92, 0x23, 0x81, 0x4d, 0x3a, 0xde, 0x93, 0xa3} \
 }
 
 // This class is our column info.  We use it to iterate our columns and to obtain
 // information about each column.
-class nsTreeColumn final : public nsITreeColumn
+class nsTreeColumn final : public nsISupports
                          , public nsWrapperCache
 {
 public:
   nsTreeColumn(nsTreeColumns* aColumns, mozilla::dom::Element* aElement);
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_TREECOLUMN_IMPL_CID)
 
-  static already_AddRefed<nsTreeColumn> From(nsITreeColumn* aColumn)
-  {
-    RefPtr<nsTreeColumn> col = do_QueryObject(aColumn);
-    return col.forget();
-  }
-
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsTreeColumn)
-  NS_DECL_NSITREECOLUMN
 
   // WebIDL
   nsIContent* GetParentObject() const;
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
-  mozilla::dom::Element* GetElement(mozilla::ErrorResult& aRv);
+  mozilla::dom::Element* Element();
 
   nsTreeColumns* GetColumns() const { return mColumns; }
 
   int32_t GetX(mozilla::ErrorResult& aRv);
   int32_t GetWidth(mozilla::ErrorResult& aRv);
 
-  // GetId is fine
+  void GetId(nsAString& aId) const;
   int32_t Index() const { return mIndex; }
 
   bool Primary() const { return mIsPrimary; }
   bool Cycler() const { return mIsCycler; }
   bool Editable() const { return mIsEditable; }
   bool Selectable() const { return mIsSelectable; }
   int16_t Type() const { return mType; }
 
@@ -102,19 +94,18 @@ protected:
   nsresult GetRect(nsTreeBodyFrame* aBodyFrame, nscoord aY, nscoord aHeight,
                    nsRect* aResult);
 
   nsresult GetXInTwips(nsTreeBodyFrame* aBodyFrame, nscoord* aResult);
   nsresult GetWidthInTwips(nsTreeBodyFrame* aBodyFrame, nscoord* aResult);
 
   void SetColumns(nsTreeColumns* aColumns) { mColumns = aColumns; }
 
-  const nsAString& GetId() { return mId; }
-
 public:
+  const nsAString& GetId() const { return mId; }
   nsAtom* GetAtom() { return mAtom; }
   int32_t GetIndex() { return mIndex; }
 
 protected:
   bool IsPrimary() { return mIsPrimary; }
   bool IsCycler() { return mIsCycler; }
   bool IsEditable() { return mIsEditable; }
   bool IsSelectable() { return mIsSelectable; }
--- a/layout/xul/tree/nsTreeContentView.cpp
+++ b/layout/xul/tree/nsTreeContentView.cpp
@@ -228,45 +228,43 @@ nsTreeContentView::GetCellProperties(int
     Element* cell = GetCell(realRow, aColumn);
     if (cell) {
       cell->GetAttr(kNameSpaceID_None, nsGkAtoms::properties, aProperties);
     }
   }
 }
 
 NS_IMETHODIMP
-nsTreeContentView::GetCellProperties(int32_t aRow, nsITreeColumn* aCol,
+nsTreeContentView::GetCellProperties(int32_t aRow, nsTreeColumn* aCol,
                                      nsAString& aProps)
 {
-  RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
-  NS_ENSURE_ARG(col);
+  NS_ENSURE_ARG(aCol);
 
   ErrorResult rv;
-  GetCellProperties(aRow, *col, aProps, rv);
+  GetCellProperties(aRow, *aCol, aProps, rv);
   return rv.StealNSResult();
 }
 
 void
 nsTreeContentView::GetColumnProperties(nsTreeColumn& aColumn,
                                        nsAString& aProperties)
 {
-  RefPtr<Element> element = aColumn.GetElement(IgnoreErrors());
+  RefPtr<Element> element = aColumn.Element();
 
   if (element) {
     element->GetAttribute(NS_LITERAL_STRING("properties"), aProperties);
   }
 }
 
 NS_IMETHODIMP
-nsTreeContentView::GetColumnProperties(nsITreeColumn* aCol, nsAString& aProps)
+nsTreeContentView::GetColumnProperties(nsTreeColumn* aCol, nsAString& aProps)
 {
-  RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
-  NS_ENSURE_ARG(col);
+  NS_ENSURE_ARG(aCol);
 
-  GetColumnProperties(*col, aProps);
+  GetColumnProperties(*aCol, aProps);
   return NS_OK;
 }
 
 bool
 nsTreeContentView::IsContainer(int32_t aRow, ErrorResult& aError)
 {
   if (!IsValidRowIndex(aRow)) {
     aError.Throw(NS_ERROR_INVALID_ARG);
@@ -493,23 +491,22 @@ nsTreeContentView::GetImageSrc(int32_t a
   if (realRow) {
     Element* cell = GetCell(realRow, aColumn);
     if (cell)
       cell->GetAttr(kNameSpaceID_None, nsGkAtoms::src, aSrc);
   }
 }
 
 NS_IMETHODIMP
-nsTreeContentView::GetImageSrc(int32_t aRow, nsITreeColumn* aCol, nsAString& _retval)
+nsTreeContentView::GetImageSrc(int32_t aRow, nsTreeColumn* aCol, nsAString& _retval)
 {
-  RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
-  NS_ENSURE_ARG(col);
+  NS_ENSURE_ARG(aCol);
 
   ErrorResult rv;
-  GetImageSrc(aRow, *col, _retval, rv);
+  GetImageSrc(aRow, *aCol, _retval, rv);
   return rv.StealNSResult();
 }
 
 void
 nsTreeContentView::GetCellValue(int32_t aRow, nsTreeColumn& aColumn,
                                 nsAString& aValue, ErrorResult& aError)
 {
   if (!IsValidRowIndex(aRow)) {
@@ -524,23 +521,22 @@ nsTreeContentView::GetCellValue(int32_t 
   if (realRow) {
     Element* cell = GetCell(realRow, aColumn);
     if (cell)
       cell->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aValue);
   }
 }
 
 NS_IMETHODIMP
-nsTreeContentView::GetCellValue(int32_t aRow, nsITreeColumn* aCol, nsAString& _retval)
+nsTreeContentView::GetCellValue(int32_t aRow, nsTreeColumn* aCol, nsAString& _retval)
 {
-  RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
-  NS_ENSURE_ARG(col);
+  NS_ENSURE_ARG(aCol);
 
   ErrorResult rv;
-  GetCellValue(aRow, *col, _retval, rv);
+  GetCellValue(aRow, *aCol, _retval, rv);
   return rv.StealNSResult();
 }
 
 void
 nsTreeContentView::GetCellText(int32_t aRow, nsTreeColumn& aColumn,
                                nsAString& aText, ErrorResult& aError)
 {
   if (!IsValidRowIndex(aRow)) {
@@ -564,23 +560,22 @@ nsTreeContentView::GetCellText(int32_t a
       Element* cell = GetCell(realRow, aColumn);
       if (cell)
         cell->GetAttr(kNameSpaceID_None, nsGkAtoms::label, aText);
     }
   }
 }
 
 NS_IMETHODIMP
-nsTreeContentView::GetCellText(int32_t aRow, nsITreeColumn* aCol, nsAString& _retval)
+nsTreeContentView::GetCellText(int32_t aRow, nsTreeColumn* aCol, nsAString& _retval)
 {
-  RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
-  NS_ENSURE_ARG(col);
+  NS_ENSURE_ARG(aCol);
 
   ErrorResult rv;
-  GetCellText(aRow, *col, _retval, rv);
+  GetCellText(aRow, *aCol, _retval, rv);
   return rv.StealNSResult();
 }
 
 void
 nsTreeContentView::SetTree(TreeBoxObject* aTree, ErrorResult& aError)
 {
   aError = SetTree(aTree);
 }
@@ -656,65 +651,61 @@ nsTreeContentView::ToggleOpenState(int32
 }
 
 void
 nsTreeContentView::CycleHeader(nsTreeColumn& aColumn, ErrorResult& aError)
 {
   if (!mRoot)
     return;
 
-  RefPtr<Element> column;
-  aColumn.GetElement(getter_AddRefs(column));
-  if (column) {
-    nsAutoString sort;
-    column->GetAttr(kNameSpaceID_None, nsGkAtoms::sort, sort);
-    if (!sort.IsEmpty()) {
-      nsCOMPtr<nsIXULSortService> xs = do_GetService("@mozilla.org/xul/xul-sort-service;1");
-      if (xs) {
-        nsAutoString sortdirection;
-        static Element::AttrValuesArray strings[] =
-          {&nsGkAtoms::ascending, &nsGkAtoms::descending, nullptr};
-        switch (column->FindAttrValueIn(kNameSpaceID_None,
-                                        nsGkAtoms::sortDirection,
-                                        strings, eCaseMatters)) {
-          case 0: sortdirection.AssignLiteral("descending"); break;
-          case 1: sortdirection.AssignLiteral("natural"); break;
-          default: sortdirection.AssignLiteral("ascending"); break;
-        }
+  RefPtr<Element> column = aColumn.Element();
+  nsAutoString sort;
+  column->GetAttr(kNameSpaceID_None, nsGkAtoms::sort, sort);
+  if (!sort.IsEmpty()) {
+    nsCOMPtr<nsIXULSortService> xs = do_GetService("@mozilla.org/xul/xul-sort-service;1");
+    if (xs) {
+      nsAutoString sortdirection;
+      static Element::AttrValuesArray strings[] =
+        {&nsGkAtoms::ascending, &nsGkAtoms::descending, nullptr};
+      switch (column->FindAttrValueIn(kNameSpaceID_None,
+                                      nsGkAtoms::sortDirection,
+                                      strings, eCaseMatters)) {
+        case 0: sortdirection.AssignLiteral("descending"); break;
+        case 1: sortdirection.AssignLiteral("natural"); break;
+        default: sortdirection.AssignLiteral("ascending"); break;
+      }
 
-        nsAutoString hints;
-        column->GetAttr(kNameSpaceID_None, nsGkAtoms::sorthints, hints);
-        sortdirection.Append(' ');
-        sortdirection += hints;
+      nsAutoString hints;
+      column->GetAttr(kNameSpaceID_None, nsGkAtoms::sorthints, hints);
+      sortdirection.Append(' ');
+      sortdirection += hints;
 
-        xs->Sort(mRoot, sort, sortdirection);
-      }
+      xs->Sort(mRoot, sort, sortdirection);
     }
   }
 }
 
 NS_IMETHODIMP
-nsTreeContentView::CycleHeader(nsITreeColumn* aCol)
+nsTreeContentView::CycleHeader(nsTreeColumn* aCol)
 {
-  RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
-  NS_ENSURE_ARG(col);
+  NS_ENSURE_ARG(aCol);
 
   ErrorResult rv;
-  CycleHeader(*col, rv);
+  CycleHeader(*aCol, rv);
   return rv.StealNSResult();
 }
 
 NS_IMETHODIMP
 nsTreeContentView::SelectionChanged()
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsTreeContentView::CycleCell(int32_t aRow, nsITreeColumn* aCol)
+nsTreeContentView::CycleCell(int32_t aRow, nsTreeColumn* aCol)
 {
   return NS_OK;
 }
 
 bool
 nsTreeContentView::IsEditable(int32_t aRow, nsTreeColumn& aColumn,
                               ErrorResult& aError)
 {
@@ -734,23 +725,22 @@ nsTreeContentView::IsEditable(int32_t aR
       return false;
     }
   }
 
   return true;
 }
 
 NS_IMETHODIMP
-nsTreeContentView::IsEditable(int32_t aRow, nsITreeColumn* aCol, bool* _retval)
+nsTreeContentView::IsEditable(int32_t aRow, nsTreeColumn* aCol, bool* _retval)
 {
-  RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
-  NS_ENSURE_ARG(col);
+  NS_ENSURE_ARG(aCol);
 
   ErrorResult rv;
-  *_retval = IsEditable(aRow, *col, rv);
+  *_retval = IsEditable(aRow, *aCol, rv);
   return rv.StealNSResult();
 }
 
 bool
 nsTreeContentView::IsSelectable(int32_t aRow, nsTreeColumn& aColumn,
                                 ErrorResult& aError)
 {
   if (!IsValidRowIndex(aRow)) {
@@ -769,23 +759,22 @@ nsTreeContentView::IsSelectable(int32_t 
       return false;
     }
   }
 
   return true;
 }
 
 NS_IMETHODIMP
-nsTreeContentView::IsSelectable(int32_t aRow, nsITreeColumn* aCol, bool* _retval)
+nsTreeContentView::IsSelectable(int32_t aRow, nsTreeColumn* aCol, bool* _retval)
 {
-  RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
-  NS_ENSURE_ARG(col);
+  NS_ENSURE_ARG(aCol);
 
   ErrorResult rv;
-  *_retval = IsSelectable(aRow, *col, rv);
+  *_retval = IsSelectable(aRow, *aCol, rv);
   return rv.StealNSResult();
 }
 
 void
 nsTreeContentView::SetCellValue(int32_t aRow, nsTreeColumn& aColumn,
                                 const nsAString& aValue, ErrorResult& aError)
 {
   if (!IsValidRowIndex(aRow)) {
@@ -800,23 +789,22 @@ nsTreeContentView::SetCellValue(int32_t 
   if (realRow) {
     Element* cell = GetCell(realRow, aColumn);
     if (cell)
       cell->SetAttr(kNameSpaceID_None, nsGkAtoms::value, aValue, true);
   }
 }
 
 NS_IMETHODIMP
-nsTreeContentView::SetCellValue(int32_t aRow, nsITreeColumn* aCol, const nsAString& aValue)
+nsTreeContentView::SetCellValue(int32_t aRow, nsTreeColumn* aCol, const nsAString& aValue)
 {
-  RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
-  NS_ENSURE_ARG(col);
+  NS_ENSURE_ARG(aCol);
 
   ErrorResult rv;
-  SetCellValue(aRow, *col, aValue, rv);
+  SetCellValue(aRow, *aCol, aValue, rv);
   return rv.StealNSResult();
 }
 
 void
 nsTreeContentView::SetCellText(int32_t aRow, nsTreeColumn& aColumn,
                                const nsAString& aValue, ErrorResult& aError)
 {
   if (!IsValidRowIndex(aRow)) {
@@ -831,40 +819,39 @@ nsTreeContentView::SetCellText(int32_t a
   if (realRow) {
     Element* cell = GetCell(realRow, aColumn);
     if (cell)
       cell->SetAttr(kNameSpaceID_None, nsGkAtoms::label, aValue, true);
   }
 }
 
 NS_IMETHODIMP
-nsTreeContentView::SetCellText(int32_t aRow, nsITreeColumn* aCol, const nsAString& aValue)
+nsTreeContentView::SetCellText(int32_t aRow, nsTreeColumn* aCol, const nsAString& aValue)
 {
-  RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
-  NS_ENSURE_ARG(col);
+  NS_ENSURE_ARG(aCol);
 
   ErrorResult rv;
-  SetCellText(aRow, *col, aValue, rv);
+  SetCellText(aRow, *aCol, aValue, rv);
   return rv.StealNSResult();
 }
 
 NS_IMETHODIMP
 nsTreeContentView::PerformAction(const char16_t* aAction)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsTreeContentView::PerformActionOnRow(const char16_t* aAction, int32_t aRow)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsTreeContentView::PerformActionOnCell(const char16_t* aAction, int32_t aRow, nsITreeColumn* aCol)
+nsTreeContentView::PerformActionOnCell(const char16_t* aAction, int32_t aRow, nsTreeColumn* aCol)
 {
   return NS_OK;
 }
 
 Element*
 nsTreeContentView::GetItemAtIndex(int32_t aIndex, ErrorResult& aError)
 {
   if (!IsValidRowIndex(aIndex)) {
--- a/layout/xul/tree/nsTreeImageListener.cpp
+++ b/layout/xul/tree/nsTreeImageListener.cpp
@@ -42,17 +42,17 @@ nsTreeImageListener::Notify(imgIRequest 
   if (aType == imgINotificationObserver::FRAME_UPDATE) {
     Invalidate();
   }
 
   return NS_OK;
 }
 
 void
-nsTreeImageListener::AddCell(int32_t aIndex, nsITreeColumn* aCol)
+nsTreeImageListener::AddCell(int32_t aIndex, nsTreeColumn* aCol)
 {
   if (!mInvalidationArea) {
     mInvalidationArea = new InvalidationArea(aCol);
     mInvalidationArea->AddRow(aIndex);
   }
   else {
     InvalidationArea* currArea;
     for (currArea = mInvalidationArea; currArea; currArea = currArea->GetNext()) {
@@ -85,17 +85,17 @@ nsTreeImageListener::Invalidate()
             tree->InvalidateCell(i, currArea->GetCol());
           }
         }
       }
     }
   }
 }
 
-nsTreeImageListener::InvalidationArea::InvalidationArea(nsITreeColumn* aCol)
+nsTreeImageListener::InvalidationArea::InvalidationArea(nsTreeColumn* aCol)
   : mCol(aCol),
     mMin(-1), // min should start out "undefined"
     mMax(0),
     mNext(nullptr)
 {
 }
 
 void
--- a/layout/xul/tree/nsTreeImageListener.h
+++ b/layout/xul/tree/nsTreeImageListener.h
@@ -7,17 +7,17 @@
 #ifndef nsTreeImageListener_h__
 #define nsTreeImageListener_h__
 
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsTreeBodyFrame.h"
 #include "mozilla/Attributes.h"
 
-class nsITreeColumn;
+class nsTreeColumn;
 
 // This class handles image load observation.
 class nsTreeImageListener final : public imgINotificationObserver
 {
 public:
   explicit nsTreeImageListener(nsTreeBodyFrame *aTreeFrame);
 
   NS_DECL_ISUPPORTS
@@ -27,41 +27,41 @@ public:
 
   friend class nsTreeBodyFrame;
 
 protected:
   ~nsTreeImageListener();
 
   void UnsuppressInvalidation() { mInvalidationSuppressed = false; }
   void Invalidate();
-  void AddCell(int32_t aIndex, nsITreeColumn* aCol);
+  void AddCell(int32_t aIndex, nsTreeColumn* aCol);
 
 private:
   nsTreeBodyFrame* mTreeFrame;
 
   // A guard that prevents us from recursive painting.
   bool mInvalidationSuppressed;
 
   class InvalidationArea {
     public:
-      explicit InvalidationArea(nsITreeColumn* aCol);
+      explicit InvalidationArea(nsTreeColumn* aCol);
       ~InvalidationArea() { delete mNext; }
 
       friend class nsTreeImageListener;
 
     protected:
       void AddRow(int32_t aIndex);
-      nsITreeColumn* GetCol() { return mCol.get(); }
+      nsTreeColumn* GetCol() { return mCol.get(); }
       int32_t GetMin() { return mMin; }
       int32_t GetMax() { return mMax; }
       InvalidationArea* GetNext() { return mNext; }
       void SetNext(InvalidationArea* aNext) { mNext = aNext; }
 
     private:
-      nsCOMPtr<nsITreeColumn> mCol;
+      RefPtr<nsTreeColumn> mCol;
       int32_t                 mMin;
       int32_t                 mMax;
       InvalidationArea*       mNext;
   };
 
   InvalidationArea* mInvalidationArea;
 };
 
--- a/layout/xul/tree/nsTreeSelection.cpp
+++ b/layout/xul/tree/nsTreeSelection.cpp
@@ -651,23 +651,23 @@ NS_IMETHODIMP nsTreeSelection::SetCurren
   RefPtr<AsyncEventDispatcher> asyncDispatcher =
     new AsyncEventDispatcher(treeElt,
                              (aIndex != -1 ? DOMMenuItemActive :
                                              DOMMenuItemInactive),
                              true, false);
   return asyncDispatcher->PostDOMEvent();
 }
 
-NS_IMETHODIMP nsTreeSelection::GetCurrentColumn(nsITreeColumn** aCurrentColumn)
+NS_IMETHODIMP nsTreeSelection::GetCurrentColumn(nsTreeColumn** aCurrentColumn)
 {
   NS_IF_ADDREF(*aCurrentColumn = mCurrentColumn);
   return NS_OK;
 }
 
-NS_IMETHODIMP nsTreeSelection::SetCurrentColumn(nsITreeColumn* aCurrentColumn)
+NS_IMETHODIMP nsTreeSelection::SetCurrentColumn(nsTreeColumn* aCurrentColumn)
 {
   if (!mTree) {
     return NS_ERROR_UNEXPECTED;
   }
   if (mCurrentColumn == aCurrentColumn) {
     return NS_OK;
   }
 
--- a/layout/xul/tree/nsTreeSelection.h
+++ b/layout/xul/tree/nsTreeSelection.h
@@ -8,17 +8,17 @@
 #define nsTreeSelection_h__
 
 #include "nsITreeSelection.h"
 #include "nsITimer.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/Attributes.h"
 
 class nsITreeBoxObject;
-class nsITreeColumn;
+class nsTreeColumn;
 struct nsTreeRange;
 
 class nsTreeSelection final : public nsINativeTreeSelection
 {
 public:
   explicit nsTreeSelection(nsITreeBoxObject* aTree);
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@@ -40,17 +40,17 @@ protected:
   // Helper function to get the content node associated with mTree.
   already_AddRefed<nsIContent> GetContent();
 
   // Members
   nsCOMPtr<nsITreeBoxObject> mTree; // The tree will hold on to us through the view and let go when it dies.
 
   bool mSuppressed; // Whether or not we should be firing onselect events.
   int32_t mCurrentIndex; // The item to draw the rect around. The last one clicked, etc.
-  nsCOMPtr<nsITreeColumn> mCurrentColumn;
+  RefPtr<nsTreeColumn> mCurrentColumn;
   int32_t mShiftSelectPivot; // Used when multiple SHIFT+selects are performed to pivot on.
 
   nsTreeRange* mFirstRange; // Our list of ranges.
 
   nsCOMPtr<nsITimer> mSelectTimer;
 };
 
 nsresult
--- a/security/manager/pki/nsASN1Tree.cpp
+++ b/security/manager/pki/nsASN1Tree.cpp
@@ -187,23 +187,23 @@ nsNSSASN1Tree::SetSelection(nsITreeSelec
 
 NS_IMETHODIMP
 nsNSSASN1Tree::GetRowProperties(int32_t, nsAString&)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsNSSASN1Tree::GetCellProperties(int32_t, nsITreeColumn*, nsAString&)
+nsNSSASN1Tree::GetCellProperties(int32_t, nsTreeColumn*, nsAString&)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsNSSASN1Tree::GetColumnProperties(nsITreeColumn*, nsAString&)
+nsNSSASN1Tree::GetColumnProperties(nsTreeColumn*, nsAString&)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNSSASN1Tree::IsContainer(int32_t index, bool* _retval)
 {
   NS_ENSURE_ARG_MIN(index, 0);
@@ -257,29 +257,29 @@ nsNSSASN1Tree::GetLevel(int32_t index, i
   if (!n)
     return NS_ERROR_FAILURE;
 
   *_retval = nodeLevel;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsNSSASN1Tree::GetImageSrc(int32_t, nsITreeColumn*, nsAString&)
+nsNSSASN1Tree::GetImageSrc(int32_t, nsTreeColumn*, nsAString&)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsNSSASN1Tree::GetCellValue(int32_t, nsITreeColumn*, nsAString&)
+nsNSSASN1Tree::GetCellValue(int32_t, nsTreeColumn*, nsAString&)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsNSSASN1Tree::GetCellText(int32_t row, nsITreeColumn*, nsAString& _retval)
+nsNSSASN1Tree::GetCellText(int32_t row, nsTreeColumn*, nsAString& _retval)
 {
   NS_ENSURE_ARG_MIN(row, 0);
 
   _retval.Truncate();
 
   myNode* n = FindNodeFromIndex(row);
   if (!n)
     return NS_ERROR_FAILURE;
@@ -329,57 +329,57 @@ nsNSSASN1Tree::ToggleOpenState(int32_t i
     rowCountChange = CountVisibleNodes(n->child);
   }
   if (mTree)
     mTree->RowCountChanged(index, rowCountChange);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsNSSASN1Tree::CycleHeader(nsITreeColumn*)
+nsNSSASN1Tree::CycleHeader(nsTreeColumn*)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNSSASN1Tree::SelectionChanged()
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
-nsNSSASN1Tree::CycleCell(int32_t, nsITreeColumn*)
+nsNSSASN1Tree::CycleCell(int32_t, nsTreeColumn*)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsNSSASN1Tree::IsEditable(int32_t, nsITreeColumn*, bool* _retval)
+nsNSSASN1Tree::IsEditable(int32_t, nsTreeColumn*, bool* _retval)
 {
   NS_ENSURE_ARG_POINTER(_retval);
   *_retval = false;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsNSSASN1Tree::IsSelectable(int32_t, nsITreeColumn*, bool* _retval)
+nsNSSASN1Tree::IsSelectable(int32_t, nsTreeColumn*, bool* _retval)
 {
   NS_ENSURE_ARG_POINTER(_retval);
   *_retval = false;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsNSSASN1Tree::SetCellValue(int32_t, nsITreeColumn*, const nsAString&)
+nsNSSASN1Tree::SetCellValue(int32_t, nsTreeColumn*, const nsAString&)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsNSSASN1Tree::SetCellText(int32_t, nsITreeColumn*, const nsAString&)
+nsNSSASN1Tree::SetCellText(int32_t, nsTreeColumn*, const nsAString&)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNSSASN1Tree::PerformAction(const char16_t*)
 {
   return NS_OK;
@@ -387,17 +387,17 @@ nsNSSASN1Tree::PerformAction(const char1
 
 NS_IMETHODIMP
 nsNSSASN1Tree::PerformActionOnRow(const char16_t*, int32_t)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsNSSASN1Tree::PerformActionOnCell(const char16_t*, int32_t, nsITreeColumn*)
+nsNSSASN1Tree::PerformActionOnCell(const char16_t*, int32_t, nsTreeColumn*)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNSSASN1Tree::CanDrop(int32_t, int32_t, mozilla::dom::DataTransfer*, bool* _retval)
 {
   NS_ENSURE_ARG_POINTER(_retval);
--- a/security/manager/ssl/nsCertTree.cpp
+++ b/security/manager/ssl/nsCertTree.cpp
@@ -876,24 +876,24 @@ nsCertTree::SetSelection(nsITreeSelectio
 
 NS_IMETHODIMP
 nsCertTree::GetRowProperties(int32_t index, nsAString& aProps)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsCertTree::GetCellProperties(int32_t row, nsITreeColumn* col,
+nsCertTree::GetCellProperties(int32_t row, nsTreeColumn* col,
                               nsAString& aProps)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsCertTree::GetColumnProperties(nsITreeColumn* col, nsAString& aProps)
+nsCertTree::GetColumnProperties(nsTreeColumn* col, nsAString& aProps)
 {
   return NS_OK;
 }
 NS_IMETHODIMP
 nsCertTree::IsContainer(int32_t index, bool *_retval)
 {
   if (!mTreeArray)
     return NS_ERROR_NOT_INITIALIZED;
@@ -984,43 +984,42 @@ nsCertTree::GetLevel(int32_t index, int3
     *_retval = 0;
   } else {
     *_retval = 1;
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsCertTree::GetImageSrc(int32_t row, nsITreeColumn* col,
+nsCertTree::GetImageSrc(int32_t row, nsTreeColumn* col,
                         nsAString& _retval)
 {
   _retval.Truncate();
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsCertTree::GetCellValue(int32_t row, nsITreeColumn* col,
+nsCertTree::GetCellValue(int32_t row, nsTreeColumn* col,
                          nsAString& _retval)
 {
   _retval.Truncate();
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsCertTree::GetCellText(int32_t row, nsITreeColumn* col,
+nsCertTree::GetCellText(int32_t row, nsTreeColumn* col,
                         nsAString& _retval)
 {
   if (!mTreeArray)
     return NS_ERROR_NOT_INITIALIZED;
 
   nsresult rv = NS_OK;
   _retval.Truncate();
 
-  const char16_t* colID;
-  col->GetIdConst(&colID);
+  const nsAString& colID = col->GetId();
 
   treeArrayEl *el = GetThreadDescAtIndex(row);
   if (el) {
     if (NS_LITERAL_STRING("certcol").Equals(colID))
       _retval.Assign(el->orgName);
     else
       _retval.Truncate();
     return NS_OK;
@@ -1031,18 +1030,17 @@ nsCertTree::GetCellText(int32_t row, nsI
   if (!certdi)
     return NS_ERROR_FAILURE;
 
   nsCOMPtr<nsIX509Cert> cert = certdi->mCert;
   if (!cert && certdi->mAddonInfo) {
     cert = certdi->mAddonInfo->mCert;
   }
 
-  int32_t colIndex;
-  col->GetIndex(&colIndex);
+  int32_t colIndex = col->Index();
   uint32_t arrayIndex=absoluteCertOffset+colIndex*(mNumRows-mNumOrgs);
   uint32_t arrayLength=0;
   if (mCellText) {
     mCellText->GetLength(&arrayLength);
   }
   if (arrayIndex < arrayLength) {
     nsCOMPtr<nsISupportsString> myString(do_QueryElementAt(mCellText, arrayIndex));
     if (myString) {
@@ -1119,56 +1117,56 @@ nsCertTree::ToggleOpenState(int32_t inde
     el->open = !el->open;
     int32_t newChildren = (el->open) ? el->numChildren : -el->numChildren;
     if (mTree) mTree->RowCountChanged(index + 1, newChildren);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsCertTree::CycleHeader(nsITreeColumn* col)
+nsCertTree::CycleHeader(nsTreeColumn* col)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCertTree::SelectionChanged()
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
-nsCertTree::CycleCell(int32_t row, nsITreeColumn* col)
+nsCertTree::CycleCell(int32_t row, nsTreeColumn* col)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsCertTree::IsEditable(int32_t row, nsITreeColumn* col, bool *_retval)
+nsCertTree::IsEditable(int32_t row, nsTreeColumn* col, bool *_retval)
 {
   *_retval = false;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsCertTree::IsSelectable(int32_t row, nsITreeColumn* col, bool *_retval)
+nsCertTree::IsSelectable(int32_t row, nsTreeColumn* col, bool *_retval)
 {
   *_retval = false;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsCertTree::SetCellValue(int32_t row, nsITreeColumn* col,
+nsCertTree::SetCellValue(int32_t row, nsTreeColumn* col,
                          const nsAString& value)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsCertTree::SetCellText(int32_t row, nsITreeColumn* col,
+nsCertTree::SetCellText(int32_t row, nsTreeColumn* col,
                         const nsAString& value)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCertTree::PerformAction(const char16_t *action)
 {
@@ -1178,17 +1176,17 @@ nsCertTree::PerformAction(const char16_t
 NS_IMETHODIMP
 nsCertTree::PerformActionOnRow(const char16_t *action, int32_t row)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCertTree::PerformActionOnCell(const char16_t *action, int32_t row,
-                                nsITreeColumn* col)
+                                nsTreeColumn* col)
 {
   return NS_OK;
 }
 
 #ifdef DEBUG_CERT_TREE
 void
 nsCertTree::dumpMap()
 {
--- a/servo/components/style/gecko_bindings/sugar/refptr.rs
+++ b/servo/components/style/gecko_bindings/sugar/refptr.rs
@@ -1,15 +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/. */
 
 //! A rust helper to ease the use of Gecko's refcounted types.
 
-use gecko_bindings::structs;
+use Atom;
+use gecko_bindings::{structs, bindings};
 use gecko_bindings::sugar::ownership::HasArcFFI;
 use servo_arc::Arc;
 use std::{fmt, mem, ptr};
 use std::marker::PhantomData;
 use std::ops::{Deref, DerefMut};
 
 /// Trait for all objects that have Addref() and Release
 /// methods and can be placed inside RefPtr<T>
@@ -250,71 +251,87 @@ impl<T: RefCounted> PartialEq for RefPtr
         self.ptr == other.ptr
     }
 }
 
 unsafe impl<T: ThreadSafeRefCounted> Send for RefPtr<T> {}
 unsafe impl<T: ThreadSafeRefCounted> Sync for RefPtr<T> {}
 
 macro_rules! impl_refcount {
-    ($t:ty, $addref:ident, $release:ident) => {
+    ($t:ty, $addref:path, $release:path) => {
         unsafe impl RefCounted for $t {
+            #[inline]
             fn addref(&self) {
-                unsafe { ::gecko_bindings::bindings::$addref(self as *const _ as *mut _) }
+                unsafe { $addref(self as *const _ as *mut _) }
             }
+
+            #[inline]
             unsafe fn release(&self) {
-                ::gecko_bindings::bindings::$release(self as *const _ as *mut _)
+                $release(self as *const _ as *mut _)
             }
         }
     };
 }
 
 // Companion of NS_DECL_THREADSAFE_FFI_REFCOUNTING.
 //
 // Gets you a free RefCounted impl implemented via FFI.
 macro_rules! impl_threadsafe_refcount {
-    ($t:ty, $addref:ident, $release:ident) => {
+    ($t:ty, $addref:path, $release:path) => {
         impl_refcount!($t, $addref, $release);
         unsafe impl ThreadSafeRefCounted for $t {}
     };
 }
 
 impl_threadsafe_refcount!(
-    ::gecko_bindings::structs::RawGeckoURLExtraData,
-    Gecko_AddRefURLExtraDataArbitraryThread,
-    Gecko_ReleaseURLExtraDataArbitraryThread
+    structs::RawGeckoURLExtraData,
+    bindings::Gecko_AddRefURLExtraDataArbitraryThread,
+    bindings::Gecko_ReleaseURLExtraDataArbitraryThread
+);
+impl_threadsafe_refcount!(
+    structs::nsStyleQuoteValues,
+    bindings::Gecko_AddRefQuoteValuesArbitraryThread,
+    bindings::Gecko_ReleaseQuoteValuesArbitraryThread
 );
 impl_threadsafe_refcount!(
-    ::gecko_bindings::structs::nsStyleQuoteValues,
-    Gecko_AddRefQuoteValuesArbitraryThread,
-    Gecko_ReleaseQuoteValuesArbitraryThread
+    structs::nsCSSValueSharedList,
+    bindings::Gecko_AddRefCSSValueSharedListArbitraryThread,
+    bindings::Gecko_ReleaseCSSValueSharedListArbitraryThread
 );
 impl_threadsafe_refcount!(
-    ::gecko_bindings::structs::nsCSSValueSharedList,
-    Gecko_AddRefCSSValueSharedListArbitraryThread,
-    Gecko_ReleaseCSSValueSharedListArbitraryThread
+    structs::mozilla::css::URLValue,
+    bindings::Gecko_AddRefCSSURLValueArbitraryThread,
+    bindings::Gecko_ReleaseCSSURLValueArbitraryThread
 );
 impl_threadsafe_refcount!(
-    ::gecko_bindings::structs::mozilla::css::URLValue,
-    Gecko_AddRefCSSURLValueArbitraryThread,
-    Gecko_ReleaseCSSURLValueArbitraryThread
+    structs::mozilla::css::GridTemplateAreasValue,
+    bindings::Gecko_AddRefGridTemplateAreasValueArbitraryThread,
+    bindings::Gecko_ReleaseGridTemplateAreasValueArbitraryThread
 );
 impl_threadsafe_refcount!(
-    ::gecko_bindings::structs::mozilla::css::GridTemplateAreasValue,
-    Gecko_AddRefGridTemplateAreasValueArbitraryThread,
-    Gecko_ReleaseGridTemplateAreasValueArbitraryThread
+    structs::ImageValue,
+    bindings::Gecko_AddRefImageValueArbitraryThread,
+    bindings::Gecko_ReleaseImageValueArbitraryThread
 );
 impl_threadsafe_refcount!(
-    ::gecko_bindings::structs::ImageValue,
-    Gecko_AddRefImageValueArbitraryThread,
-    Gecko_ReleaseImageValueArbitraryThread
+    structs::SharedFontList,
+    bindings::Gecko_AddRefSharedFontListArbitraryThread,
+    bindings::Gecko_ReleaseSharedFontListArbitraryThread
 );
 impl_threadsafe_refcount!(
-    ::gecko_bindings::structs::SharedFontList,
-    Gecko_AddRefSharedFontListArbitraryThread,
-    Gecko_ReleaseSharedFontListArbitraryThread
+    structs::SheetLoadDataHolder,
+    bindings::Gecko_AddRefSheetLoadDataHolderArbitraryThread,
+    bindings::Gecko_ReleaseSheetLoadDataHolderArbitraryThread
 );
 
+#[inline]
+unsafe fn addref_atom(atom: *mut structs::nsAtom) {
+    mem::forget(Atom::from_raw(atom));
+}
+#[inline]
+unsafe fn release_atom(atom: *mut structs::nsAtom) {
+    let _ = Atom::from_addrefed(atom);
+}
 impl_threadsafe_refcount!(
-    ::gecko_bindings::structs::SheetLoadDataHolder,
-    Gecko_AddRefSheetLoadDataHolderArbitraryThread,
-    Gecko_ReleaseSheetLoadDataHolderArbitraryThread
+    structs::nsAtom,
+    addref_atom,
+    release_atom
 );
--- a/servo/components/style/parser.rs
+++ b/servo/components/style/parser.rs
@@ -152,22 +152,22 @@ impl<'a> ParserContext<'a> {
 
 /// A trait to abstract parsing of a specified value given a `ParserContext` and
 /// CSS input.
 ///
 /// This can be derived on keywords with `#[derive(Parse)]`.
 ///
 /// The derive code understands the following attributes on each of the variants:
 ///
-///  * `#[css(aliases = "foo,bar")]` can be used to alias a value with another
+///  * `#[parse(aliases = "foo,bar")]` can be used to alias a value with another
 ///    at parse-time.
 ///
-///  * `#[css(parse_condition = "function")]` can be used to make the parsing of
-///    the value conditional on `function`, which will be invoked with a
-///    `&ParserContext` reference.
+///  * `#[parse(condition = "function")]` can be used to make the parsing of the
+///    value conditional on `function`, which needs to fulfill
+///    `fn(&ParserContext) -> bool`.
 pub trait Parse: Sized {
     /// Parse a value of this type.
     ///
     /// Returns an error on failure.
     fn parse<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>,
     ) -> Result<Self, ParseError<'i>>;
--- a/servo/components/style/properties/declaration_block.rs
+++ b/servo/components/style/properties/declaration_block.rs
@@ -1111,19 +1111,17 @@ where
         parsing_mode,
         quirks_mode,
     );
 
     let mut input = ParserInput::new(input);
     let mut parser = Parser::new(&mut input);
     let start_position = parser.position();
     parser.parse_entirely(|parser| {
-        let name = id.name().into();
-        PropertyDeclaration::parse_into(declarations, id, name, &context, parser)
-            .map_err(|e| e.into())
+        PropertyDeclaration::parse_into(declarations, id, &context, parser)
     }).map_err(|err| {
         let location = err.location;
         let error = ContextualParseError::UnsupportedPropertyDeclaration(
             parser.slice_from(start_position), err);
         let error_context = ParserErrorContext { error_reporter: error_reporter };
         context.log_css_error(&error_context, location, error);
     })
 }
@@ -1164,17 +1162,17 @@ impl<'a, 'b, 'i> DeclarationParser<'i> f
                 return Err(input.new_custom_error(if is_non_mozilla_vendor_identifier(&name) {
                     StyleParseErrorKind::UnknownVendorProperty
                 } else {
                     StyleParseErrorKind::UnknownProperty(name)
                 }));
             }
         };
         input.parse_until_before(Delimiter::Bang, |input| {
-            PropertyDeclaration::parse_into(self.declarations, id, name, self.context, input)
+            PropertyDeclaration::parse_into(self.declarations, id, self.context, input)
         })?;
         let importance = match input.try(parse_important) {
             Ok(()) => Importance::Important,
             Err(_) => Importance::Normal,
         };
         // In case there is still unparsed text in the declaration, we should roll back.
         input.expect_exhausted()?;
         Ok(importance)
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -3269,20 +3269,17 @@ fn static_assert() {
         use gecko_bindings::structs::nsCSSPropertyID::eCSSProperty_UNKNOWN;
 
         let v = v.into_iter();
 
         if v.len() != 0 {
             self.gecko.mTransitions.ensure_len(v.len());
             self.gecko.mTransitionPropertyCount = v.len() as u32;
             for (servo, gecko) in v.zip(self.gecko.mTransitions.iter_mut()) {
-                if !gecko.mUnknownProperty.mRawPtr.is_null() {
-                    unsafe { Atom::from_addrefed(gecko.mUnknownProperty.mRawPtr) };
-                    gecko.mUnknownProperty.mRawPtr = ptr::null_mut();
-                }
+                unsafe { gecko.mUnknownProperty.clear() };
 
                 match servo {
                     TransitionProperty::Unsupported(ident) => {
                         gecko.mProperty = eCSSProperty_UNKNOWN;
                         gecko.mUnknownProperty.mRawPtr = ident.0.into_addrefed();
                     },
                     TransitionProperty::Custom(name) => {
                         gecko.mProperty = eCSSPropertyExtra_variable;
@@ -3350,20 +3347,17 @@ fn static_assert() {
         use gecko_bindings::structs::nsCSSPropertyID::eCSSProperty_UNKNOWN;
         self.gecko.mTransitions.ensure_len(other.gecko.mTransitions.len());
 
         let count = other.gecko.mTransitionPropertyCount;
         self.gecko.mTransitionPropertyCount = count;
 
         for (index, transition) in self.gecko.mTransitions.iter_mut().enumerate().take(count as usize) {
             transition.mProperty = other.gecko.mTransitions[index].mProperty;
-            if !transition.mUnknownProperty.mRawPtr.is_null() {
-                unsafe { Atom::from_addrefed(transition.mUnknownProperty.mRawPtr) };
-                transition.mUnknownProperty.mRawPtr = ptr::null_mut();
-            }
+            unsafe { transition.mUnknownProperty.clear() };
             if transition.mProperty == eCSSProperty_UNKNOWN ||
                transition.mProperty == eCSSPropertyExtra_variable {
                 let atom = other.gecko.mTransitions[index].mUnknownProperty.mRawPtr;
                 debug_assert!(!atom.is_null());
                 transition.mUnknownProperty.mRawPtr = unsafe { Atom::from_raw(atom) }.into_addrefed();
             }
         }
     }
--- a/servo/components/style/properties/helpers.mako.rs
+++ b/servo/components/style/properties/helpers.mako.rs
@@ -589,17 +589,17 @@
             % if include_aliases:
             <%
                 aliases = []
                 for alias, v in keyword.aliases_for(product).iteritems():
                     if variant == v:
                         aliases.append(alias)
             %>
             % if aliases:
-            #[css(aliases = "${','.join(aliases)}")]
+            #[parse(aliases = "${','.join(aliases)}")]
             % endif
             % endif
             ${to_camel_case(variant)},
             % endfor
         </%def>
         % if extra_specified:
             #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
             #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq,
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -18,17 +18,17 @@ use servo_arc::{Arc, UniqueArc};
 use smallbitvec::SmallBitVec;
 use std::borrow::Cow;
 use std::{ops, ptr};
 use std::cell::RefCell;
 use std::fmt::{self, Write};
 use std::mem::{self, ManuallyDrop};
 
 #[cfg(feature = "servo")] use cssparser::RGBA;
-use cssparser::{CowRcStr, Parser, TokenSerializationType, serialize_identifier};
+use cssparser::{Parser, TokenSerializationType};
 use cssparser::ParserInput;
 #[cfg(feature = "servo")] use euclid::SideOffsets2D;
 use context::QuirksMode;
 use font_metrics::FontMetricsProvider;
 #[cfg(feature = "gecko")] use gecko_bindings::bindings;
 #[cfg(feature = "gecko")] use gecko_bindings::structs::{self, nsCSSPropertyID};
 #[cfg(feature = "servo")] use logical_geometry::LogicalMargin;
 #[cfg(feature = "servo")] use computed_values;
@@ -44,16 +44,17 @@ use selectors::parser::SelectorParseErro
 use shared_lock::StylesheetGuards;
 use style_traits::{CssWriter, KeywordsCollectFn, ParseError, ParsingMode};
 use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss};
 use stylesheets::{CssRuleType, Origin, UrlExtraData};
 #[cfg(feature = "servo")] use values::Either;
 use values::generics::text::LineHeight;
 use values::computed;
 use values::computed::NonNegativeLength;
+use values::serialize_atom_name;
 use rule_tree::{CascadeLevel, StrongRuleNode};
 use self::computed_value_flags::*;
 use str::{CssString, CssStringBorrow, CssStringWriter};
 use style_adjuster::StyleAdjuster;
 
 pub use self::declaration_block::*;
 
 <%!
@@ -422,16 +423,27 @@ impl NonCustomPropertyId {
             % for property in data.longhands + data.shorthands + data.all_aliases():
                 ${property.nscsspropertyid()},
             % endfor
         ];
 
         MAP[self.0]
     }
 
+    /// Get the property name.
+    #[inline]
+    fn name(self) -> &'static str {
+        static MAP: [&'static str; ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())}] = [
+            % for property in data.longhands + data.shorthands + data.all_aliases():
+                "${property.name}",
+            % endfor
+        ];
+        MAP[self.0]
+    }
+
     #[inline]
     fn enabled_for_all_content(self) -> bool {
         ${static_non_custom_property_id_set(
             "EXPERIMENTAL",
             lambda p: p.experimental(product)
         )}
 
         ${static_non_custom_property_id_set(
@@ -854,22 +866,19 @@ impl ToCss for LonghandId {
 impl fmt::Debug for LonghandId {
     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
         formatter.write_str(self.name())
     }
 }
 
 impl LonghandId {
     /// Get the name of this longhand property.
+    #[inline]
     pub fn name(&self) -> &'static str {
-        match *self {
-            % for property in data.longhands:
-                LonghandId::${property.camel_case} => "${property.name}",
-            % endfor
-        }
+        NonCustomPropertyId::from(*self).name()
     }
 
     /// Returns whether the longhand property is inherited by default.
     pub fn inherited(&self) -> bool {
         ${static_longhand_id_set("INHERITED", lambda p: p.style_struct.inherited)}
         INHERITED.contains(*self)
     }
 
@@ -1197,22 +1206,19 @@ impl ToCss for ShorthandId {
         W: Write,
     {
         dest.write_str(self.name())
     }
 }
 
 impl ShorthandId {
     /// Get the name for this shorthand property.
+    #[inline]
     pub fn name(&self) -> &'static str {
-        match *self {
-            % for property in data.shorthands:
-                ShorthandId::${property.camel_case} => "${property.name}",
-            % endfor
-        }
+        NonCustomPropertyId::from(*self).name()
     }
 
     /// Converts from a ShorthandId to an adequate nsCSSPropertyID.
     #[cfg(feature = "gecko")]
     #[inline]
     pub fn to_nscsspropertyid(self) -> nsCSSPropertyID {
         NonCustomPropertyId::from(self).to_nscsspropertyid()
     }
@@ -1501,18 +1507,19 @@ pub enum PropertyDeclarationId<'a> {
 
 impl<'a> ToCss for PropertyDeclarationId<'a> {
     fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
     where
         W: Write,
     {
         match *self {
             PropertyDeclarationId::Longhand(id) => dest.write_str(id.name()),
-            PropertyDeclarationId::Custom(_) => {
-                serialize_identifier(&self.name(), dest)
+            PropertyDeclarationId::Custom(ref name) => {
+                dest.write_str("--")?;
+                serialize_atom_name(name, dest)
             }
         }
     }
 }
 
 impl<'a> PropertyDeclarationId<'a> {
     /// Whether a given declaration id is either the same as `other`, or a
     /// longhand of it.
@@ -1582,18 +1589,19 @@ impl ToCss for PropertyId {
     where
         W: Write,
     {
         match *self {
             PropertyId::Longhand(id) => dest.write_str(id.name()),
             PropertyId::Shorthand(id) => dest.write_str(id.name()),
             PropertyId::LonghandAlias(id, _) => dest.write_str(id.name()),
             PropertyId::ShorthandAlias(id, _) => dest.write_str(id.name()),
-            PropertyId::Custom(_) => {
-                serialize_identifier(&self.name(), dest)
+            PropertyId::Custom(ref name) => {
+                dest.write_str("--")?;
+                serialize_atom_name(name, dest)
             }
         }
     }
 }
 
 impl PropertyId {
     /// Return the longhand id that this property id represents.
     #[inline]
@@ -1752,31 +1760,16 @@ impl PropertyId {
             PropertyId::ShorthandAlias(id, _) |
             PropertyId::Shorthand(id) => Ok(id),
             PropertyId::LonghandAlias(id, _) |
             PropertyId::Longhand(id) => Err(PropertyDeclarationId::Longhand(id)),
             PropertyId::Custom(ref name) => Err(PropertyDeclarationId::Custom(name)),
         }
     }
 
-    /// Returns the name of the property without CSS escaping.
-    pub fn name(&self) -> Cow<'static, str> {
-        match *self {
-            PropertyId::ShorthandAlias(id, _) |
-            PropertyId::Shorthand(id) => id.name().into(),
-            PropertyId::LonghandAlias(id, _) |
-            PropertyId::Longhand(id) => id.name().into(),
-            PropertyId::Custom(ref name) => {
-                let mut s = String::new();
-                write!(&mut s, "--{}", name).unwrap();
-                s.into()
-            }
-        }
-    }
-
     fn non_custom_id(&self) -> Option<NonCustomPropertyId> {
         Some(match *self {
             PropertyId::Custom(_) => return None,
             PropertyId::Shorthand(shorthand_id) => shorthand_id.into(),
             PropertyId::Longhand(longhand_id) => longhand_id.into(),
             PropertyId::ShorthandAlias(_, alias_id) => alias_id.into(),
             PropertyId::LonghandAlias(_, alias_id) => alias_id.into(),
         })
@@ -2029,34 +2022,37 @@ impl PropertyDeclaration {
     /// > but does accept the `animation-play-state` property and interprets it specially.
     ///
     /// This will not actually parse Importance values, and will always set things
     /// to Importance::Normal. Parsing Importance values is the job of PropertyDeclarationParser,
     /// we only set them here so that we don't have to reallocate
     pub fn parse_into<'i, 't>(
         declarations: &mut SourcePropertyDeclaration,
         id: PropertyId,
-        name: CowRcStr<'i>,
         context: &ParserContext,
         input: &mut Parser<'i, 't>,
     ) -> Result<(), ParseError<'i>> {
         assert!(declarations.is_empty());
         debug_assert!(id.allowed_in(context), "{:?}", id);
 
+        let non_custom_id = id.non_custom_id();
         let start = input.state();
         match id {
             PropertyId::Custom(property_name) => {
                 // FIXME: fully implement https://github.com/w3c/csswg-drafts/issues/774
                 // before adding skip_whitespace here.
                 // This probably affects some test results.
                 let value = match input.try(|i| CSSWideKeyword::parse(i)) {
                     Ok(keyword) => DeclaredValueOwned::CSSWideKeyword(keyword),
                     Err(()) => match ::custom_properties::SpecifiedValue::parse(input) {
                         Ok(value) => DeclaredValueOwned::Value(value),
-                        Err(e) => return Err(StyleParseErrorKind::new_invalid(name, e)),
+                        Err(e) => return Err(StyleParseErrorKind::new_invalid(
+                            format!("--{}", property_name),
+                            e,
+                        )),
                     }
                 };
                 declarations.push(PropertyDeclaration::Custom(CustomDeclaration {
                     name: property_name,
                     value,
                 }));
                 Ok(())
             }
@@ -2071,29 +2067,35 @@ impl PropertyDeclaration {
                     input.look_for_var_functions();
                     input.parse_entirely(|input| id.parse_value(context, input))
                     .or_else(|err| {
                         while let Ok(_) = input.next() {}  // Look for var() after the error.
                         if input.seen_var_functions() {
                             input.reset(&start);
                             let (first_token_type, css) =
                                 ::custom_properties::parse_non_custom_with_var(input).map_err(|e| {
-                                    StyleParseErrorKind::new_invalid(name, e)
+                                    StyleParseErrorKind::new_invalid(
+                                        non_custom_id.unwrap().name(),
+                                        e,
+                                    )
                                 })?;
                             Ok(PropertyDeclaration::WithVariables(VariableDeclaration {
                                 id,
                                 value: Arc::new(UnparsedValue {
                                 css: css.into_owned(),
                                 first_token_type: first_token_type,
                                 url_data: context.url_data.clone(),
                                 from_shorthand: None,
                                 }),
                             }))
                         } else {
-                            Err(StyleParseErrorKind::new_invalid(name, err))
+                            Err(StyleParseErrorKind::new_invalid(
+                                non_custom_id.unwrap().name(),
+                                err,
+                            ))
                         }
                     })
                 }).map(|declaration| {
                     declarations.push(declaration)
                 })
             }
             PropertyId::ShorthandAlias(id, _) |
             PropertyId::Shorthand(id) => {
@@ -2117,17 +2119,20 @@ impl PropertyDeclaration {
                     // Not using parse_entirely here: each ${shorthand.ident}::parse_into function
                     // needs to do so *before* pushing to `declarations`.
                     id.parse_into(declarations, context, input).or_else(|err| {
                         while let Ok(_) = input.next() {}  // Look for var() after the error.
                         if input.seen_var_functions() {
                             input.reset(&start);
                             let (first_token_type, css) =
                                 ::custom_properties::parse_non_custom_with_var(input).map_err(|e| {
-                                    StyleParseErrorKind::new_invalid(name, e)
+                                    StyleParseErrorKind::new_invalid(
+                                        non_custom_id.unwrap().name(),
+                                        e,
+                                    )
                                 })?;
                             let unparsed = Arc::new(UnparsedValue {
                                 css: css.into_owned(),
                                 first_token_type: first_token_type,
                                 url_data: context.url_data.clone(),
                                 from_shorthand: Some(id),
                             });
                             if id == ShorthandId::All {
@@ -2139,17 +2144,20 @@ impl PropertyDeclaration {
                                             id,
                                             value: unparsed.clone(),
                                         })
                                     )
                                 }
                             }
                             Ok(())
                         } else {
-                            Err(StyleParseErrorKind::new_invalid(name, err))
+                            Err(StyleParseErrorKind::new_invalid(
+                                non_custom_id.unwrap().name(),
+                                err,
+                            ))
                         }
                     })
                 }
             }
         }
     }
 }
 
--- a/servo/components/style/stylesheets/keyframes_rule.rs
+++ b/servo/components/style/stylesheets/keyframes_rule.rs
@@ -618,22 +618,22 @@ impl<'a, 'b, 'i> DeclarationParser<'i> f
     fn parse_value<'t>(
         &mut self,
         name: CowRcStr<'i>,
         input: &mut Parser<'i, 't>,
     ) -> Result<(), ParseError<'i>> {
         let id = match PropertyId::parse(&name, self.context) {
             Ok(id) => id,
             Err(()) => return Err(input.new_custom_error(
-                StyleParseErrorKind::UnknownProperty(name.clone())
+                StyleParseErrorKind::UnknownProperty(name)
             )),
         };
 
         // TODO(emilio): Shouldn't this use parse_entirely?
-        PropertyDeclaration::parse_into(self.declarations, id, name, self.context, input)?;
+        PropertyDeclaration::parse_into(self.declarations, id, self.context, input)?;
 
         // In case there is still unparsed text in the declaration, we should
         // roll back.
         input.expect_exhausted()?;
 
         Ok(())
     }
 }
--- a/servo/components/style/stylesheets/supports_rule.rs
+++ b/servo/components/style/stylesheets/supports_rule.rs
@@ -311,25 +311,28 @@ impl Declaration {
     ///
     /// <https://drafts.csswg.org/css-conditional-3/#support-definition>
     pub fn eval(&self, context: &ParserContext) -> bool {
         debug_assert_eq!(context.rule_type(), CssRuleType::Style);
 
         let mut input = ParserInput::new(&self.0);
         let mut input = Parser::new(&mut input);
         input.parse_entirely(|input| -> Result<(), CssParseError<()>> {
-                let prop = input.expect_ident_cloned().unwrap();
-                input.expect_colon().unwrap();
+            let prop = input.expect_ident_cloned().unwrap();
+            input.expect_colon().unwrap();
 
-                let id = PropertyId::parse(&prop, context)
-                    .map_err(|_| input.new_custom_error(()))?;
+            let id = PropertyId::parse(&prop, context)
+                .map_err(|_| input.new_custom_error(()))?;
 
-                let mut declarations = SourcePropertyDeclaration::new();
-                input.parse_until_before(Delimiter::Bang, |input| {
-                    PropertyDeclaration::parse_into(&mut declarations, id, prop, &context, input)
-                        .map_err(|_| input.new_custom_error(()))
-                })?;
-                let _ = input.try(parse_important);
-                Ok(())
-            })
-            .is_ok()
+            let mut declarations = SourcePropertyDeclaration::new();
+            input.parse_until_before(Delimiter::Bang, |input| {
+                PropertyDeclaration::parse_into(
+                    &mut declarations,
+                    id,
+                    &context,
+                    input,
+                ).map_err(|_| input.new_custom_error(()))
+            })?;
+            let _ = input.try(parse_important);
+            Ok(())
+        }).is_ok()
     }
 }
--- a/servo/components/style/values/mod.rs
+++ b/servo/components/style/values/mod.rs
@@ -4,17 +4,17 @@
 
 //! Common [values][values] used in CSS.
 //!
 //! [values]: https://drafts.csswg.org/css-values/
 
 #![deny(missing_docs)]
 
 use Atom;
-pub use cssparser::{serialize_identifier, CowRcStr, Parser, SourceLocation, Token, RGBA};
+pub use cssparser::{serialize_identifier, serialize_name, CowRcStr, Parser, SourceLocation, Token, RGBA};
 use parser::{Parse, ParserContext};
 use selectors::parser::SelectorParseErrorKind;
 use std::fmt::{self, Debug, Write};
 use std::hash;
 use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
 use values::distance::{ComputeSquaredDistance, SquaredDistance};
 
 #[cfg(feature = "servo")]
@@ -55,16 +55,38 @@ pub fn serialize_atom_identifier<Static,
 ) -> fmt::Result
 where
     Static: ::string_cache::StaticAtomSet,
     W: Write,
 {
     serialize_identifier(&ident, dest)
 }
 
+/// Serialize a name which is represented as an Atom.
+#[cfg(feature = "gecko")]
+pub fn serialize_atom_name<W>(ident: &Atom, dest: &mut W) -> fmt::Result
+where
+    W: Write,
+{
+    ident.with_str(|s| serialize_name(s, dest))
+}
+
+/// Serialize a name which is represented as an Atom.
+#[cfg(feature = "servo")]
+pub fn serialize_atom_name<Static, W>(
+    ident: &::string_cache::Atom<Static>,
+    dest: &mut W,
+) -> fmt::Result
+where
+    Static: ::string_cache::StaticAtomSet,
+    W: Write,
+{
+    serialize_name(&ident, dest)
+}
+
 /// Serialize a normalized value into percentage.
 pub fn serialize_percentage<W>(value: CSSFloat, dest: &mut CssWriter<W>) -> fmt::Result
 where
     W: Write,
 {
     (value * 100.).to_css(dest)?;
     dest.write_str("%")
 }
--- a/servo/components/style/values/specified/box.rs
+++ b/servo/components/style/values/specified/box.rs
@@ -48,19 +48,19 @@ pub enum Display {
     TableFooterGroup,
     TableRow,
     TableColumnGroup,
     TableColumn,
     TableCell,
     TableCaption,
     ListItem,
     None,
-    #[css(aliases = "-webkit-flex")]
+    #[parse(aliases = "-webkit-flex")]
     Flex,
-    #[css(aliases = "-webkit-inline-flex")]
+    #[parse(aliases = "-webkit-inline-flex")]
     InlineFlex,
     #[cfg(feature = "gecko")]
     Grid,
     #[cfg(feature = "gecko")]
     InlineGrid,
     #[cfg(feature = "gecko")]
     Ruby,
     #[cfg(feature = "gecko")]
@@ -79,41 +79,41 @@ pub enum Display {
     WebkitBox,
     #[cfg(feature = "gecko")]
     WebkitInlineBox,
     #[cfg(feature = "gecko")]
     MozBox,
     #[cfg(feature = "gecko")]
     MozInlineBox,
     #[cfg(feature = "gecko")]
-    #[css(parse_condition = "moz_display_values_enabled")]
+    #[parse(condition = "moz_display_values_enabled")]
     MozGrid,
     #[cfg(feature = "gecko")]
-    #[css(parse_condition = "moz_display_values_enabled")]
+    #[parse(condition = "moz_display_values_enabled")]
     MozInlineGrid,
     #[cfg(feature = "gecko")]
-    #[css(parse_condition = "moz_display_values_enabled")]
+    #[parse(condition = "moz_display_values_enabled")]
     MozGridGroup,
     #[cfg(feature = "gecko")]
-    #[css(parse_condition = "moz_display_values_enabled")]
+    #[parse(condition = "moz_display_values_enabled")]
     MozGridLine,
     #[cfg(feature = "gecko")]
-    #[css(parse_condition = "moz_display_values_enabled")]
+    #[parse(condition = "moz_display_values_enabled")]
     MozStack,
     #[cfg(feature = "gecko")]
-    #[css(parse_condition = "moz_display_values_enabled")]
+    #[parse(condition = "moz_display_values_enabled")]
     MozInlineStack,
     #[cfg(feature = "gecko")]
-    #[css(parse_condition = "moz_display_values_enabled")]
+    #[parse(condition = "moz_display_values_enabled")]
     MozDeck,
     #[cfg(feature = "gecko")]
-    #[css(parse_condition = "moz_display_values_enabled")]
+    #[parse(condition = "moz_display_values_enabled")]
     MozPopup,
     #[cfg(feature = "gecko")]
-    #[css(parse_condition = "moz_display_values_enabled")]
+    #[parse(condition = "moz_display_values_enabled")]
     MozGroupbox,
 }
 
 impl Display {
     /// The initial display value.
     #[inline]
     pub fn inline() -> Self {
         Display::Inline
@@ -751,23 +751,23 @@ pub enum TransitionProperty {
     Unsupported(CustomIdent),
 }
 
 impl ToCss for TransitionProperty {
     fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
     where
         W: Write,
     {
-        use values::serialize_atom_identifier;
+        use values::serialize_atom_name;
         match *self {
             TransitionProperty::Shorthand(ref s) => s.to_css(dest),
             TransitionProperty::Longhand(ref l) => l.to_css(dest),
             TransitionProperty::Custom(ref name) => {
                 dest.write_str("--")?;
-                serialize_atom_identifier(name, dest)
+                serialize_atom_name(name, dest)
             }
             TransitionProperty::Unsupported(ref i) => i.to_css(dest),
         }
     }
 }
 
 impl Parse for TransitionProperty {
     fn parse<'i, 't>(
--- a/servo/components/style_derive/lib.rs
+++ b/servo/components/style_derive/lib.rs
@@ -35,17 +35,17 @@ pub fn derive_compute_squared_distance(s
 }
 
 #[proc_macro_derive(ToAnimatedValue)]
 pub fn derive_to_animated_value(stream: TokenStream) -> TokenStream {
     let input = syn::parse(stream).unwrap();
     to_animated_value::derive(input).into()
 }
 
-#[proc_macro_derive(Parse, attributes(css))]
+#[proc_macro_derive(Parse, attributes(css, parse))]
 pub fn derive_parse(stream: TokenStream) -> TokenStream {
     let input = syn::parse(stream).unwrap();
     parse::derive(input).into()
 }
 
 #[proc_macro_derive(ToAnimatedZero, attributes(animation, zero))]
 pub fn derive_to_animated_zero(stream: TokenStream) -> TokenStream {
     let input = syn::parse(stream).unwrap();
@@ -59,13 +59,13 @@ pub fn derive_to_computed_value(stream: 
 }
 
 #[proc_macro_derive(ToCss, attributes(css))]
 pub fn derive_to_css(stream: TokenStream) -> TokenStream {
     let input = syn::parse(stream).unwrap();
     to_css::derive(input).into()
 }
 
-#[proc_macro_derive(SpecifiedValueInfo, attributes(css, value_info))]
+#[proc_macro_derive(SpecifiedValueInfo, attributes(css, parse, value_info))]
 pub fn derive_specified_value_info(stream: TokenStream) -> TokenStream {
     let input = syn::parse(stream).unwrap();
     specified_value_info::derive(input).into()
 }
--- a/servo/components/style_derive/parse.rs
+++ b/servo/components/style_derive/parse.rs
@@ -1,52 +1,62 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use cg;
 use quote::Tokens;
-use syn::DeriveInput;
+use syn::{DeriveInput, Path};
 use synstructure;
 use to_css::CssVariantAttrs;
 
+#[darling(attributes(parse), default)]
+#[derive(Default, FromVariant)]
+pub struct ParseVariantAttrs {
+    pub aliases: Option<String>,
+    pub condition: Option<Path>,
+}
+
 pub fn derive(input: DeriveInput) -> Tokens {
     let name = &input.ident;
     let s = synstructure::Structure::new(&input);
 
     let mut saw_condition = false;
     let match_body = s.variants().iter().fold(quote!(), |match_body, variant| {
         let bindings = variant.bindings();
         assert!(
             bindings.is_empty(),
             "Parse is only supported for single-variant enums for now"
         );
 
-        let variant_attrs = cg::parse_variant_attrs_from_ast::<CssVariantAttrs>(&variant.ast());
-        if variant_attrs.skip {
+        let css_variant_attrs =
+            cg::parse_variant_attrs_from_ast::<CssVariantAttrs>(&variant.ast());
+        let parse_attrs =
+            cg::parse_variant_attrs_from_ast::<ParseVariantAttrs>(&variant.ast());
+        if css_variant_attrs.skip {
             return match_body;
         }
 
         let identifier = cg::to_css_identifier(
-            &variant_attrs.keyword.unwrap_or(variant.ast().ident.as_ref().into()),
+            &css_variant_attrs.keyword.unwrap_or(variant.ast().ident.as_ref().into()),
         );
         let ident = &variant.ast().ident;
 
-        saw_condition |= variant_attrs.parse_condition.is_some();
-        let condition = match variant_attrs.parse_condition {
+        saw_condition |= parse_attrs.condition.is_some();
+        let condition = match parse_attrs.condition {
             Some(ref p) => quote! { if #p(context) },
             None => quote! { },
         };
 
         let mut body = quote! {
             #match_body
             #identifier #condition => Ok(#name::#ident),
         };
 
-        let aliases = match variant_attrs.aliases {
+        let aliases = match parse_attrs.aliases {
             Some(aliases) => aliases,
             None => return body,
         };
 
         for alias in aliases.split(",") {
             body = quote! {
                 #body
                 #alias #condition => Ok(#name::#ident),
--- a/servo/components/style_derive/specified_value_info.rs
+++ b/servo/components/style_derive/specified_value_info.rs
@@ -1,16 +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/. */
 
 use cg;
 use quote::Tokens;
 use syn::{Data, DeriveInput, Fields, Ident, Type};
 use to_css::{CssFieldAttrs, CssInputAttrs, CssVariantAttrs};
+use parse::ParseVariantAttrs;
 
 pub fn derive(mut input: DeriveInput) -> Tokens {
     let css_attrs = cg::parse_input_attrs::<CssInputAttrs>(&input);
     let mut types = vec![];
     let mut values = vec![];
 
     let input_ident = input.ident;
     let input_name = || cg::to_css_identifier(input_ident.as_ref());
@@ -28,20 +29,21 @@ pub fn derive(mut input: DeriveInput) ->
         }
         input.generics.where_clause = where_clause;
 
         match input.data {
             Data::Enum(ref e) => {
                 for v in e.variants.iter() {
                     let css_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(&v);
                     let info_attrs = cg::parse_variant_attrs::<ValueInfoVariantAttrs>(&v);
+                    let parse_attrs = cg::parse_variant_attrs::<ParseVariantAttrs>(&v);
                     if css_attrs.skip {
                         continue;
                     }
-                    if let Some(aliases) = css_attrs.aliases {
+                    if let Some(aliases) = parse_attrs.aliases {
                         for alias in aliases.split(",") {
                             values.push(alias.to_string());
                         }
                     }
                     if let Some(other_values) = info_attrs.other_values {
                         for value in other_values.split(",") {
                             values.push(value.to_string());
                         }
--- a/servo/components/style_derive/to_css.rs
+++ b/servo/components/style_derive/to_css.rs
@@ -229,18 +229,16 @@ pub struct CssInputAttrs {
 
 #[darling(attributes(css), default)]
 #[derive(Default, FromVariant)]
 pub struct CssVariantAttrs {
     pub function: Option<Override<String>>,
     pub comma: bool,
     pub dimension: bool,
     pub keyword: Option<String>,
-    pub aliases: Option<String>,
-    pub parse_condition: Option<Path>,
     pub skip: bool,
 }
 
 #[darling(attributes(css), default)]
 #[derive(Default, FromField)]
 pub struct CssFieldAttrs {
     pub if_empty: Option<String>,
     pub field_bound: bool,
--- a/servo/components/style_traits/lib.rs
+++ b/servo/components/style_traits/lib.rs
@@ -172,17 +172,21 @@ pub enum ValueParseErrorKind<'i> {
     /// An invalid token was encountered while parsing a color value.
     InvalidColor(Token<'i>),
     /// An invalid filter value was encountered.
     InvalidFilter(Token<'i>),
 }
 
 impl<'i> StyleParseErrorKind<'i> {
     /// Create an InvalidValue parse error
-    pub fn new_invalid(name: CowRcStr<'i>, value_error: ParseError<'i>) -> ParseError<'i> {
+    pub fn new_invalid<S>(name: S, value_error: ParseError<'i>) -> ParseError<'i>
+    where
+        S: Into<CowRcStr<'i>>,
+    {
+        let name = name.into();
         let variant = match value_error.kind {
             cssparser::ParseErrorKind::Custom(StyleParseErrorKind::ValueError(e)) => {
                 match e {
                     ValueParseErrorKind::InvalidColor(token) => {
                         StyleParseErrorKind::InvalidColor(name, token)
                     }
                     ValueParseErrorKind::InvalidFilter(token) => {
                         StyleParseErrorKind::InvalidFilter(name, token)
--- a/servo/components/style_traits/specified_value_info.rs
+++ b/servo/components/style_traits/specified_value_info.rs
@@ -38,17 +38,17 @@ pub type KeywordsCollectFn<'a> = &'a mut
 /// names following the same rule as `ToCss` in that method.
 ///
 /// Some attributes of `ToCss` can affect the behavior, specifically:
 /// * If `#[css(function)]` is found, the content inside the annotated
 ///   variant (or the whole type) isn't traversed, only the function
 ///   name is listed in `collect_completion_keywords`.
 /// * If `#[css(skip)]` is found, the content inside the variant or
 ///   field is ignored.
-/// * Values listed in `#[css(if_empty)]`, `#[css(aliases)]`, and
+/// * Values listed in `#[css(if_empty)]`, `#[parse(aliases)]`, and
 ///   `#[css(keyword)]` are added into `collect_completion_keywords`.
 ///
 /// In addition to `css` attributes, it also has `value_info` helper
 /// attributes, including:
 /// * `#[value_info(ty = "TYPE")]` can be used to specify a constant
 ///   from `CssType` to `SUPPORTED_TYPES`.
 /// * `#[value_info(other_values = "value1,value2")]` can be used to
 ///   add other values related to a field, variant, or the type itself
--- a/testing/web-platform/tests/content-security-policy/generic/policy-inherited-correctly-by-plznavigate.html
+++ b/testing/web-platform/tests/content-security-policy/generic/policy-inherited-correctly-by-plznavigate.html
@@ -7,35 +7,37 @@
        PlzNavigate on).
        Also see crbug.com/778658. -->
   <script src='/resources/testharness.js'></script>
   <script src='/resources/testharnessreport.js'></script>
 </head>
 <body>
   <script>
     var t = async_test("iframe still inherits correct CSP");
-  </script>
 
-  <iframe id="x" srcdoc="<a href='about:blank'>123</a>"></iframe>
-
-  <script>
     window.onmessage = t.step_func_done(function(e) {
       assert_equals(e.data, "frame-src");
     });
 
-    x = document.getElementById('x');
-    x.onload = function() {
+    function doDocWrite() {
+      x = document.getElementById('x');
       x.location = "";
 
       // While document.write is deprecated I did not find another way to reproduce
       // the original exploit.
       x.contentDocument.write(
         '<script>window.addEventListener("securitypolicyviolation", function(e) {' +
         '  window.top.postMessage(e.violatedDirective, "*");' +
         '});</scr' + 'ipt>' +
         '<iframe src="../support/fail.html"></iframe>'
       );
       x.contentDocument.close();
+
+      var s = document.createElement('script');
+      s.async = true;
+      s.defer = true;
+      s.src = '../support/checkReport.sub.js?reportField=violated-directive&reportValue=frame-src%20%27none%27';
+      document.lastChild.appendChild(s);
     }
   </script>
-  <script async defer src='../support/checkReport.sub.js?reportField=violated-directive&reportValue=frame-src%20%27none%27''></script>
+  <iframe id="x" onload="doDocWrite()" srcdoc="<a href='about:blank'>123</a>"></iframe>
 </body>
 </html>
--- a/toolkit/components/perfmonitoring/nsPerformanceStats.cpp
+++ b/toolkit/components/perfmonitoring/nsPerformanceStats.cpp
@@ -105,26 +105,26 @@ URLForGlobal(JSContext* cx, JS::Handle<J
   url.Assign(NS_ConvertUTF8toUTF16(spec));
   return true;
 }
 
 /**
  * Extract a somewhat human-readable name from the current context.
  */
 void
-CompartmentName(JSContext* cx, JS::Handle<JSObject*> global, nsAString& name) {
+RealmName(JSContext* cx, JS::Handle<JSObject*> global, nsAString& name) {
   // Attempt to use the URL as name.
   if (URLForGlobal(cx, global, name)) {
     return;
   }
 
   // Otherwise, fallback to XPConnect's less readable but more
   // complete naming scheme.
   nsAutoCString cname;
-  xpc::GetCurrentCompartmentName(cx, cname);
+  xpc::GetCurrentRealmName(cx, cname);
   name.Assign(NS_ConvertUTF8toUTF16(cname));
 }
 
 /**
  * Generate a unique-to-the-application identifier for a group.
  */
 void
 GenerateUniqueGroupId(uint64_t uid, uint64_t processId, nsAString& groupId)
@@ -1030,17 +1030,17 @@ nsPerformanceStatsService::GetPerformanc
 
   // All compartments belong to the top group.
   if (!out.append(mTopGroup)) {
     JS_ReportOutOfMemory(cx);
     return false;
   }
 
   nsAutoString name;
-  CompartmentName(cx, global, name);
+  RealmName(cx, global, name);
   bool isSystem = nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(global));
 
   // Find out if the compartment is executed by a window. If so, its
   // duration should count towards the total duration of the window.
   uint64_t windowId = 0;
   if (nsCOMPtr<nsPIDOMWindowOuter> ptop = GetPrivateWindow(cx)) {
     windowId = ptop->WindowID();
     auto entry = mWindowIdToGroup.PutEntry(windowId);
--- a/toolkit/content/widgets/tree.xml
+++ b/toolkit/content/widgets/tree.xml
@@ -331,18 +331,18 @@
         <parameter name="row"/>
         <parameter name="column"/>
         <body>
           <![CDATA[
             if (!this.editable)
               return false;
             if (row < 0 || row >= this.view.rowCount || !column)
               return false;
-            if (column.type != Ci.nsITreeColumn.TYPE_TEXT &&
-                column.type != Ci.nsITreeColumn.TYPE_PASSWORD)
+            if (column.type != window.TreeColumn.TYPE_TEXT &&
+                column.type != window.TreeColumn.TYPE_PASSWORD)
               return false;
             if (column.cycler || !this.view.isEditable(row, column))
               return false;
 
             // Beyond this point, we are going to edit the cell.
             if (this._editingColumn)
               this.stopEditing();
 
@@ -1123,17 +1123,17 @@
 
            if (cell.childElt == "twisty")
              return;
 
            if (cell.col && event.button == 0) {
              if (cell.col.cycler) {
                view.cycleCell(cell.row, cell.col);
                return;
-             } else if (cell.col.type == Ci.nsITreeColumn.TYPE_CHECKBOX) {
+             } else if (cell.col.type == window.TreeColumn.TYPE_CHECKBOX) {
                if (this.parentNode.editable && cell.col.editable &&
                    view.isEditable(cell.row, cell.col)) {
                  var value = view.getCellValue(cell.row, cell.col);
                  value = value == "true" ? "false" : "true";
                  view.setCellValue(cell.row, cell.col, value);
                  return;
                }
              }
@@ -1217,17 +1217,17 @@
           selected group of items */
 
         if (!cell.col) return;
 
         // if the last row has changed in between the time we
         // mousedown and the time we click, don't fire the select handler.
         // see bug #92366
         if (!cell.col.cycler && this._lastSelectedRow == cell.row &&
-            cell.col.type != Ci.nsITreeColumn.TYPE_CHECKBOX) {
+            cell.col.type != window.TreeColumn.TYPE_CHECKBOX) {
 
           var cellSelType = this.parentNode._cellSelType;
           if (cellSelType == "text" && cell.childElt != "text" && cell.childElt != "image")
             return;
 
           if (cellSelType) {
             if (!cell.col.selectable ||
                 !view.isSelectable(cell.row, cell.col)) {
--- a/tools/profiler/core/ProfileBuffer.cpp
+++ b/tools/profiler/core/ProfileBuffer.cpp
@@ -125,18 +125,18 @@ ProfileBuffer::SizeOfIncludingThis(mozil
 }
 
 /* ProfileBufferCollector */
 
 static bool
 IsChromeJSScript(JSScript* aScript)
 {
   // WARNING: this function runs within the profiler's "critical section".
-  auto compartment = js::GetScriptCompartment(aScript);
-  return js::IsSystemCompartment(compartment);
+  auto realm = js::GetScriptRealm(aScript);
+  return js::IsSystemRealm(realm);
 }
 
 void
 ProfileBufferCollector::CollectNativeLeafAddr(void* aAddr)
 {
   mBuf.AddEntry(ProfileBufferEntry::NativeLeafAddr(aAddr));
 }