Bug 1252211 - Convert TreeContentView to WebIDL. r=bz.
☠☠ backed out by 54ce8da73fbb ☠ ☠
authorPeter Van der Beken <peterv@propagandism.org>
Thu, 08 Jun 2017 21:04:02 +0200
changeset 412424 629ace67da3bec76161266bcccdbcb96561ec96f
parent 412423 82c5f20d6ee239c5e52b62440471c8a85ac6763f
child 412425 2ae6c80f571087633e123c0fe0f4aa45874787a5
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1252211
milestone56.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
Bug 1252211 - Convert TreeContentView to WebIDL. r=bz.
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfoID.h
dom/bindings/Bindings.conf
dom/webidl/LegacyQueryInterface.webidl
dom/webidl/TreeContentView.webidl
dom/webidl/moz.build
layout/xul/crashtests/crashtests.list
layout/xul/tree/nsTreeContentView.cpp
layout/xul/tree/nsTreeContentView.h
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -68,20 +68,16 @@
 // Event related includes
 #include "nsIDOMEventTarget.h"
 
 // CSS related includes
 #include "nsIDOMCSSRule.h"
 #include "nsMemory.h"
 
 // includes needed for the prototype chain interfaces
-#ifdef MOZ_XUL
-#include "nsITreeContentView.h"
-#include "nsITreeView.h"
-#endif
 
 #include "nsIEventListenerService.h"
 #include "nsIMessageManager.h"
 
 #include "mozilla/dom/TouchEvent.h"
 
 #include "nsWrapperCacheInlines.h"
 #include "mozilla/dom/HTMLCollectionBinding.h"
@@ -169,22 +165,16 @@ static nsDOMClassInfoData sClassInfoData
                            XPC_SCRIPTABLE_WANT_RESOLVE |
                            XPC_SCRIPTABLE_WANT_HASINSTANCE |
                            XPC_SCRIPTABLE_WANT_CALL |
                            XPC_SCRIPTABLE_WANT_CONSTRUCT |
                            XPC_SCRIPTABLE_DONT_ENUM_QUERY_INTERFACE)
 
   // Misc Core related classes
 
-  // XUL classes
-#ifdef MOZ_XUL
-  NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(TreeContentView, nsDOMGenericSH,
-                                      DEFAULT_SCRIPTABLE_FLAGS)
-#endif
-
   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ContentFrameMessageManager,
                                        nsMessageManagerSH<nsEventTargetSH>,
                                        DOM_DEFAULT_SCRIPTABLE_FLAGS |
                                        XPC_SCRIPTABLE_WANT_ENUMERATE |
                                        XPC_SCRIPTABLE_IS_GLOBAL_OBJECT)
   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ContentProcessMessageManager,
                                        nsMessageManagerSH<nsDOMGenericSH>,
                                        DOM_DEFAULT_SCRIPTABLE_FLAGS |
@@ -443,23 +433,16 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(DOMPrototype, nsIDOMDOMConstructor)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMConstructor)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(DOMConstructor, nsIDOMDOMConstructor)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMConstructor)
   DOM_CLASSINFO_MAP_END
 
-#ifdef MOZ_XUL
-  DOM_CLASSINFO_MAP_BEGIN(TreeContentView, nsITreeContentView)
-    DOM_CLASSINFO_MAP_ENTRY(nsITreeContentView)
-    DOM_CLASSINFO_MAP_ENTRY(nsITreeView)
-  DOM_CLASSINFO_MAP_END
-#endif
-
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ContentFrameMessageManager, nsISupports)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
     DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager)
     DOM_CLASSINFO_MAP_ENTRY(nsIMessageSender)
     DOM_CLASSINFO_MAP_ENTRY(nsISyncMessageSender)
     DOM_CLASSINFO_MAP_ENTRY(nsIContentFrameMessageManager)
   DOM_CLASSINFO_MAP_END
 
--- a/dom/base/nsDOMClassInfoID.h
+++ b/dom/base/nsDOMClassInfoID.h
@@ -14,21 +14,16 @@
 
 #include "nsIXPCScriptable.h"
 
 enum nsDOMClassInfoID
 {
   eDOMClassInfo_DOMPrototype_id,
   eDOMClassInfo_DOMConstructor_id,
 
-  // XUL classes
-#ifdef MOZ_XUL
-  eDOMClassInfo_TreeContentView_id,
-#endif
-
   eDOMClassInfo_ContentFrameMessageManager_id,
   eDOMClassInfo_ContentProcessMessageManager_id,
   eDOMClassInfo_ChromeMessageBroadcaster_id,
   eDOMClassInfo_ChromeMessageSender_id,
 
   eDOMClassInfo_XULControlElement_id,
   eDOMClassInfo_XULLabeledControlElement_id,
   eDOMClassInfo_XULButtonElement_id,
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1085,16 +1085,20 @@ DOMInterfaces = {
     'nativeType': 'nsTreeColumn',
     'headerFile': 'nsTreeColumns.h',
 },
 
 'TreeColumns': {
     'nativeType': 'nsTreeColumns',
 },
 
+'TreeContentView': {
+    'nativeType': 'nsTreeContentView',
+},
+
 'TreeWalker': {
     'wrapperCache': False,
 },
 
 'VTTCue': {
     'nativeType': 'mozilla::dom::TextTrackCue'
 },
 
--- a/dom/webidl/LegacyQueryInterface.webidl
+++ b/dom/webidl/LegacyQueryInterface.webidl
@@ -77,16 +77,17 @@ SVGRect implements LegacyQueryInterface;
 SVGStringList implements LegacyQueryInterface;
 SVGTransformList implements LegacyQueryInterface;
 Screen implements LegacyQueryInterface;
 StyleSheet implements LegacyQueryInterface;
 Text implements LegacyQueryInterface;
 Touch implements LegacyQueryInterface;
 TouchList implements LegacyQueryInterface;
 TreeColumns implements LegacyQueryInterface;
+TreeContentView implements LegacyQueryInterface;
 TreeWalker implements LegacyQueryInterface;
 ValidityState implements LegacyQueryInterface;
 WebSocket implements LegacyQueryInterface;
 Window implements LegacyQueryInterface;
 XMLHttpRequest implements LegacyQueryInterface;
 XMLHttpRequestUpload implements LegacyQueryInterface;
 XMLSerializer implements LegacyQueryInterface;
 XPathEvaluator implements LegacyQueryInterface;
new file mode 100644
--- /dev/null
+++ b/dom/webidl/TreeContentView.webidl
@@ -0,0 +1,20 @@
+/* -*- 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/. */
+
+[Func="IsChromeOrXBL"]
+interface TreeContentView
+{
+  /**
+   * Retrieve the content item associated with the specified row.
+   */
+  [Throws]
+  Element? getItemAtIndex(long row);
+
+  /**
+   * Retrieve the index associated with the specified content item.
+   */
+  long getIndexOfItem(Element? item);
+};
+TreeContentView implements TreeView;
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -921,16 +921,17 @@ WEBIDL_FILES = [
     'TimeRanges.webidl',
     'Touch.webidl',
     'TouchEvent.webidl',
     'TouchList.webidl',
     'TransitionEvent.webidl',
     'TreeBoxObject.webidl',
     'TreeColumn.webidl',
     'TreeColumns.webidl',
+    'TreeContentView.webidl',
     'TreeView.webidl',
     'TreeWalker.webidl',
     'U2F.webidl',
     'UDPMessageEvent.webidl',
     'UDPSocket.webidl',
     'UIEvent.webidl',
     'URL.webidl',
     'URLSearchParams.webidl',
--- a/layout/xul/crashtests/crashtests.list
+++ b/layout/xul/crashtests/crashtests.list
@@ -85,15 +85,15 @@ load 470272.html
 load 472189.xul
 load 475133.html
 asserts-if(stylo,1) load 488210-1.xhtml # bug 1370830
 load 495728-1.xul
 load 508927-1.xul
 load 508927-2.xul
 load 514300-1.xul
 asserts-if(stylo,2) load 536931-1.xhtml # bug 1370830
-asserts(1) load 538308-1.xul
+load 538308-1.xul
 load 557174-1.xml
 load 564705-1.xul
 asserts-if(stylo,2) load 583957-1.html # bug 1370830
 load 617089.html
 asserts-if(stylo,1) load menulist-focused.xhtml # bug 1370830
 load 716503.html
--- a/layout/xul/tree/nsTreeContentView.cpp
+++ b/layout/xul/tree/nsTreeContentView.cpp
@@ -4,44 +4,37 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsNameSpaceManager.h"
 #include "nsGkAtoms.h"
 #include "nsIBoxObject.h"
 #include "nsTreeUtils.h"
 #include "nsTreeContentView.h"
 #include "ChildIterator.h"
-#include "nsDOMClassInfoID.h"
 #include "nsError.h"
 #include "nsIXULSortService.h"
-#include "nsContentUtils.h"
 #include "nsTreeBodyFrame.h"
 #include "mozilla/dom/Element.h"
+#include "mozilla/dom/TreeContentViewBinding.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIDocument.h"
 
 using namespace mozilla;
 
-#define NS_ENSURE_NATIVE_COLUMN(_col)                                \
-  RefPtr<nsTreeColumn> col = nsTreeBodyFrame::GetColumnImpl(_col); \
-  if (!col) {                                                        \
-    return NS_ERROR_INVALID_ARG;                                     \
-  }
-
 // A content model view implementation for the tree.
 
 #define ROW_FLAG_CONTAINER      0x01
 #define ROW_FLAG_OPEN           0x02
 #define ROW_FLAG_EMPTY          0x04
 #define ROW_FLAG_SEPARATOR      0x08
 
 class Row
 {
   public:
-    Row(nsIContent* aContent, int32_t aParentIndex)
+    Row(Element* aContent, int32_t aParentIndex)
       : mContent(aContent), mParentIndex(aParentIndex),
         mSubtreeSize(0), mFlags(0) {
     }
 
     ~Row() {
     }
 
     void SetContainer(bool aContainer) {
@@ -60,17 +53,17 @@ class Row
     bool IsEmpty() { return !!(mFlags & ROW_FLAG_EMPTY); }
 
     void SetSeparator(bool aSeparator) {
       aSeparator ? mFlags |= ROW_FLAG_SEPARATOR : mFlags &= ~ROW_FLAG_SEPARATOR;
     }
     bool IsSeparator() { return !!(mFlags & ROW_FLAG_SEPARATOR); }
 
     // Weak reference to a content item.
-    nsIContent*         mContent;
+    Element*            mContent;
 
     // The parent index of the item, set to -1 for the top level items.
     int32_t             mParentIndex;
 
     // Subtree size for this item.
     int32_t             mSubtreeSize;
 
   private:
@@ -105,46 +98,59 @@ NS_NewTreeContentView(nsITreeView** aRes
 {
   *aResult = new nsTreeContentView;
   if (! *aResult)
     return NS_ERROR_OUT_OF_MEMORY;
   NS_ADDREF(*aResult);
   return NS_OK;
 }
 
-NS_IMPL_CYCLE_COLLECTION(nsTreeContentView,
-                         mBoxObject,
-                         mSelection,
-                         mRoot,
-                         mBody)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsTreeContentView,
+                                      mBoxObject,
+                                      mSelection,
+                                      mRoot,
+                                      mBody)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsTreeContentView)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsTreeContentView)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsTreeContentView)
   NS_INTERFACE_MAP_ENTRY(nsITreeView)
   NS_INTERFACE_MAP_ENTRY(nsITreeContentView)
   NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver)
   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsITreeContentView)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(TreeContentView)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
 NS_INTERFACE_MAP_END
 
+JSObject*
+nsTreeContentView::WrapObject(JSContext* aCx,
+                              JS::Handle<JSObject*> aGivenProto)
+{
+  return TreeContentViewBinding::Wrap(aCx, this, aGivenProto);
+}
+
+nsISupports*
+nsTreeContentView::GetParentObject()
+{
+  return mBoxObject;
+}
+
 NS_IMETHODIMP
 nsTreeContentView::GetRowCount(int32_t* aRowCount)
 {
   *aRowCount = mRows.Length();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsTreeContentView::GetSelection(nsITreeSelection** aSelection)
 {
-  NS_IF_ADDREF(*aSelection = mSelection);
+  NS_IF_ADDREF(*aSelection = GetSelection());
 
   return NS_OK;
 }
 
 bool
 nsTreeContentView::CanTrustTreeSelection(nsISupports* aValue)
 {
   // Untrusted content is only allowed to specify known-good views
@@ -152,319 +158,465 @@ nsTreeContentView::CanTrustTreeSelection
     return true;
   nsCOMPtr<nsINativeTreeSelection> nativeTreeSel = do_QueryInterface(aValue);
   return nativeTreeSel && NS_SUCCEEDED(nativeTreeSel->EnsureNative());
 }
 
 NS_IMETHODIMP
 nsTreeContentView::SetSelection(nsITreeSelection* aSelection)
 {
-  NS_ENSURE_TRUE(!aSelection || CanTrustTreeSelection(aSelection),
-                 NS_ERROR_DOM_SECURITY_ERR);
-
-  mSelection = aSelection;
-  return NS_OK;
+  ErrorResult rv;
+  SetSelection(aSelection, rv);
+  return rv.StealNSResult();
 }
 
-NS_IMETHODIMP
-nsTreeContentView::GetRowProperties(int32_t aIndex, nsAString& aProps)
+void
+nsTreeContentView::SetSelection(nsITreeSelection* aSelection, ErrorResult& aError)
 {
-  NS_PRECONDITION(aIndex >= 0 && aIndex < int32_t(mRows.Length()), "bad index");
-  if (aIndex < 0 || aIndex >= int32_t(mRows.Length()))
-    return NS_ERROR_INVALID_ARG;   
+  if (aSelection && !CanTrustTreeSelection(aSelection)) {
+    aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    return;
+  }
+
+  mSelection = aSelection;
+}
 
-  Row* row = mRows[aIndex].get();
+void
+nsTreeContentView::GetRowProperties(int32_t aRow, nsAString& aProperties,
+                                    ErrorResult& aError)
+{
+  if (!IsValidRowIndex(aRow)) {
+    aError.Throw(NS_ERROR_INVALID_ARG);
+    return;
+  }
+
+  Row* row = mRows[aRow].get();
   nsIContent* realRow;
   if (row->IsSeparator())
     realRow = row->mContent;
   else
     realRow = nsTreeUtils::GetImmediateChild(row->mContent, nsGkAtoms::treerow);
 
   if (realRow) {
-    realRow->GetAttr(kNameSpaceID_None, nsGkAtoms::properties, aProps);
+    realRow->GetAttr(kNameSpaceID_None, nsGkAtoms::properties, aProperties);
+  }
+}
+
+NS_IMETHODIMP
+nsTreeContentView::GetRowProperties(int32_t aIndex, nsAString& aProps)
+{
+  ErrorResult rv;
+  GetRowProperties(aIndex, aProps, rv);
+  return rv.StealNSResult();
+}
+
+void
+nsTreeContentView::GetCellProperties(int32_t aRow, nsTreeColumn& aColumn,
+                                     nsAString& aProperties,
+                                     ErrorResult& aError)
+{
+  if (!IsValidRowIndex(aRow)) {
+    aError.Throw(NS_ERROR_INVALID_ARG);
+    return;
   }
 
-  return NS_OK;
+  Row* row = mRows[aRow].get();
+  nsIContent* realRow =
+    nsTreeUtils::GetImmediateChild(row->mContent, nsGkAtoms::treerow);
+  if (realRow) {
+    nsIContent* cell = GetCell(realRow, aColumn);
+    if (cell) {
+      cell->GetAttr(kNameSpaceID_None, nsGkAtoms::properties, aProperties);
+    }
+  }
 }
 
 NS_IMETHODIMP
 nsTreeContentView::GetCellProperties(int32_t aRow, nsITreeColumn* aCol,
                                      nsAString& aProps)
 {
-  NS_ENSURE_NATIVE_COLUMN(aCol);
-  NS_PRECONDITION(aRow >= 0 && aRow < int32_t(mRows.Length()), "bad row");
-  if (aRow < 0 || aRow >= int32_t(mRows.Length()))
-    return NS_ERROR_INVALID_ARG;   
+  RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
+  NS_ENSURE_ARG(col);
+
+  ErrorResult rv;
+  GetCellProperties(aRow, *col, aProps, rv);
+  return rv.StealNSResult();
+}
 
-  Row* row = mRows[aRow].get();
-  nsIContent* realRow =
-    nsTreeUtils::GetImmediateChild(row->mContent, nsGkAtoms::treerow);
-  if (realRow) {
-    nsIContent* cell = GetCell(realRow, aCol);
-    if (cell) {
-      cell->GetAttr(kNameSpaceID_None, nsGkAtoms::properties, aProps);
-    }
-  }
+void
+nsTreeContentView::GetColumnProperties(nsTreeColumn& aColumn,
+                                       nsAString& aProperties)
+{
+  nsCOMPtr<nsIDOMElement> element;
+  aColumn.GetElement(getter_AddRefs(element));
 
-  return NS_OK;
+  element->GetAttribute(NS_LITERAL_STRING("properties"), aProperties);
 }
 
 NS_IMETHODIMP
 nsTreeContentView::GetColumnProperties(nsITreeColumn* aCol, nsAString& aProps)
 {
-  NS_ENSURE_NATIVE_COLUMN(aCol);
-  nsCOMPtr<nsIDOMElement> element;
-  aCol->GetElement(getter_AddRefs(element));
+  RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
+  NS_ENSURE_ARG(col);
+
+  GetColumnProperties(*col, aProps);
+  return NS_OK;
+}
 
-  element->GetAttribute(NS_LITERAL_STRING("properties"), aProps);
-  return NS_OK;
+bool
+nsTreeContentView::IsContainer(int32_t aRow, ErrorResult& aError)
+{
+  if (!IsValidRowIndex(aRow)) {
+    aError.Throw(NS_ERROR_INVALID_ARG);
+    return false;
+  }
+
+  return mRows[aRow]->IsContainer();
 }
 
 NS_IMETHODIMP
 nsTreeContentView::IsContainer(int32_t aIndex, bool* _retval)
 {
-  NS_PRECONDITION(aIndex >= 0 && aIndex < int32_t(mRows.Length()), "bad index");
-  if (aIndex < 0 || aIndex >= int32_t(mRows.Length()))
-    return NS_ERROR_INVALID_ARG;   
+  ErrorResult rv;
+  *_retval = IsContainer(aIndex, rv);
+  return rv.StealNSResult();
+}
 
-  *_retval = mRows[aIndex]->IsContainer();
+bool
+nsTreeContentView::IsContainerOpen(int32_t aRow, ErrorResult& aError)
+{
+  if (!IsValidRowIndex(aRow)) {
+    aError.Throw(NS_ERROR_INVALID_ARG);
+    return false;
+  }
 
-  return NS_OK;
+  return mRows[aRow]->IsOpen();
 }
 
 NS_IMETHODIMP
 nsTreeContentView::IsContainerOpen(int32_t aIndex, bool* _retval)
 {
-  NS_PRECONDITION(aIndex >= 0 && aIndex < int32_t(mRows.Length()), "bad index");
-  if (aIndex < 0 || aIndex >= int32_t(mRows.Length()))
-    return NS_ERROR_INVALID_ARG;   
+  ErrorResult rv;
+  *_retval = IsContainerOpen(aIndex, rv);
+  return rv.StealNSResult();
+}
 
-  *_retval = mRows[aIndex]->IsOpen();
+bool
+nsTreeContentView::IsContainerEmpty(int32_t aRow, ErrorResult& aError)
+{
+  if (!IsValidRowIndex(aRow)) {
+    aError.Throw(NS_ERROR_INVALID_ARG);
+    return false;
+  }
 
-  return NS_OK;
+  return mRows[aRow]->IsEmpty();
 }
 
 NS_IMETHODIMP
 nsTreeContentView::IsContainerEmpty(int32_t aIndex, bool* _retval)
 {
-  NS_PRECONDITION(aIndex >= 0 && aIndex < int32_t(mRows.Length()), "bad index");
-  if (aIndex < 0 || aIndex >= int32_t(mRows.Length()))
-    return NS_ERROR_INVALID_ARG;   
+  ErrorResult rv;
+  *_retval = IsContainerEmpty(aIndex, rv);
+  return rv.StealNSResult();
+}
 
-  *_retval = mRows[aIndex]->IsEmpty();
+bool
+nsTreeContentView::IsSeparator(int32_t aRow, ErrorResult& aError)
+{
+  if (!IsValidRowIndex(aRow)) {
+    aError.Throw(NS_ERROR_INVALID_ARG);
+    return false;
+  }
 
-  return NS_OK;
+  return mRows[aRow]->IsSeparator();
 }
 
 NS_IMETHODIMP
 nsTreeContentView::IsSeparator(int32_t aIndex, bool *_retval)
 {
-  NS_PRECONDITION(aIndex >= 0 && aIndex < int32_t(mRows.Length()), "bad index");
-  if (aIndex < 0 || aIndex >= int32_t(mRows.Length()))
-    return NS_ERROR_INVALID_ARG;   
-
-  *_retval = mRows[aIndex]->IsSeparator();
-
-  return NS_OK;
+  ErrorResult rv;
+  *_retval = IsSeparator(aIndex, rv);
+  return rv.StealNSResult();
 }
 
 NS_IMETHODIMP
 nsTreeContentView::IsSorted(bool *_retval)
 {
-  *_retval = false;
+  *_retval = IsSorted();
 
   return NS_OK;
 }
 
+bool
+nsTreeContentView::CanDrop(int32_t aRow, int32_t aOrientation,
+                           DataTransfer* aDataTransfer, ErrorResult& aError)
+{
+  if (!IsValidRowIndex(aRow)) {
+    aError.Throw(NS_ERROR_INVALID_ARG);
+  }
+  return false;
+}
+
 NS_IMETHODIMP
 nsTreeContentView::CanDrop(int32_t aIndex, int32_t aOrientation,
                            nsIDOMDataTransfer* aDataTransfer, bool *_retval)
 {
-  NS_PRECONDITION(aIndex >= 0 && aIndex < int32_t(mRows.Length()), "bad index");
-  if (aIndex < 0 || aIndex >= int32_t(mRows.Length()))
-    return NS_ERROR_INVALID_ARG;   
-
-  *_retval = false;
- 
-  return NS_OK;
+  ErrorResult rv;
+  *_retval = CanDrop(aIndex, aOrientation, DataTransfer::Cast(aDataTransfer),
+                     rv);
+  return rv.StealNSResult();
 }
  
+void
+nsTreeContentView::Drop(int32_t aRow, int32_t aOrientation,
+                        DataTransfer* aDataTransfer, ErrorResult& aError)
+{
+  if (!IsValidRowIndex(aRow)) {
+    aError.Throw(NS_ERROR_INVALID_ARG);
+  }
+}
+
 NS_IMETHODIMP
 nsTreeContentView::Drop(int32_t aRow, int32_t aOrientation, nsIDOMDataTransfer* aDataTransfer)
 {
-  NS_PRECONDITION(aRow >= 0 && aRow < int32_t(mRows.Length()), "bad row");
-  if (aRow < 0 || aRow >= int32_t(mRows.Length()))
-    return NS_ERROR_INVALID_ARG;   
+  ErrorResult rv;
+  Drop(aRow, aOrientation, DataTransfer::Cast(aDataTransfer), rv);
+  return rv.StealNSResult();
+}
 
-  return NS_OK;
+int32_t
+nsTreeContentView::GetParentIndex(int32_t aRow, ErrorResult& aError)
+{
+  if (!IsValidRowIndex(aRow)) {
+    aError.Throw(NS_ERROR_INVALID_ARG);
+    return 0;
+  }
+
+  return mRows[aRow]->mParentIndex;
 }
 
 NS_IMETHODIMP
 nsTreeContentView::GetParentIndex(int32_t aRowIndex, int32_t* _retval)
 {
-  NS_PRECONDITION(aRowIndex >= 0 && aRowIndex < int32_t(mRows.Length()),
-                  "bad row index");
-  if (aRowIndex < 0 || aRowIndex >= int32_t(mRows.Length()))
-    return NS_ERROR_INVALID_ARG;   
+  ErrorResult rv;
+  *_retval = GetParentIndex(aRowIndex, rv);
+  return rv.StealNSResult();
+}
+
+bool
+nsTreeContentView::HasNextSibling(int32_t aRow, int32_t aAfterIndex,
+                                  ErrorResult& aError)
+{
+  if (!IsValidRowIndex(aRow)) {
+    aError.Throw(NS_ERROR_INVALID_ARG);
+    return false;
+  }
 
-  *_retval = mRows[aRowIndex]->mParentIndex;
+  // We have a next sibling if the row is not the last in the subtree.
+  int32_t parentIndex = mRows[aRow]->mParentIndex;
+  if (parentIndex < 0) {
+    return uint32_t(aRow) < mRows.Length() - 1;
+  }
 
-  return NS_OK;
+  // Compute the last index in this subtree.
+  int32_t lastIndex = parentIndex + (mRows[parentIndex])->mSubtreeSize;
+  Row* row = mRows[lastIndex].get();
+  while (row->mParentIndex != parentIndex) {
+    lastIndex = row->mParentIndex;
+    row = mRows[lastIndex].get();
+  }
+
+  return aRow < lastIndex;
 }
 
 NS_IMETHODIMP
 nsTreeContentView::HasNextSibling(int32_t aRowIndex, int32_t aAfterIndex, bool* _retval)
 {
-  NS_PRECONDITION(aRowIndex >= 0 && aRowIndex < int32_t(mRows.Length()),
-                  "bad row index");
-  if (aRowIndex < 0 || aRowIndex >= int32_t(mRows.Length()))
-    return NS_ERROR_INVALID_ARG;   
+  ErrorResult rv;
+  *_retval = HasNextSibling(aRowIndex, aAfterIndex, rv);
+  return rv.StealNSResult();
+}
 
-  // We have a next sibling if the row is not the last in the subtree.
-  int32_t parentIndex = mRows[aRowIndex]->mParentIndex;
-  if (parentIndex >= 0) {
-    // Compute the last index in this subtree.
-    int32_t lastIndex = parentIndex + (mRows[parentIndex])->mSubtreeSize;
-    Row* row = mRows[lastIndex].get();
-    while (row->mParentIndex != parentIndex) {
-      lastIndex = row->mParentIndex;
-      row = mRows[lastIndex].get();
-    }
-
-    *_retval = aRowIndex < lastIndex;
-  }
-  else {
-    *_retval = uint32_t(aRowIndex) < mRows.Length() - 1;
+int32_t
+nsTreeContentView::GetLevel(int32_t aRow, ErrorResult& aError)
+{
+  if (!IsValidRowIndex(aRow)) {
+    aError.Throw(NS_ERROR_INVALID_ARG);
+    return 0;
   }
 
-  return NS_OK;
+  int32_t level = 0;
+  Row* row = mRows[aRow].get();
+  while (row->mParentIndex >= 0) {
+    level++;
+    row = mRows[row->mParentIndex].get();
+  }
+  return level;
 }
 
 NS_IMETHODIMP
 nsTreeContentView::GetLevel(int32_t aIndex, int32_t* _retval)
 {
-  NS_PRECONDITION(aIndex >= 0 && aIndex < int32_t(mRows.Length()), "bad index");
-  if (aIndex < 0 || aIndex >= int32_t(mRows.Length()))
-    return NS_ERROR_INVALID_ARG;   
-
-  int32_t level = 0;
-  Row* row = mRows[aIndex].get();
-  while (row->mParentIndex >= 0) {
-    level++;
-    row = mRows[row->mParentIndex].get();
-  }
-  *_retval = level;
-
-  return NS_OK;
+  ErrorResult rv;
+  *_retval = GetLevel(aIndex, rv);
+  return rv.StealNSResult();
 }
 
- NS_IMETHODIMP
-nsTreeContentView::GetImageSrc(int32_t aRow, nsITreeColumn* aCol, nsAString& _retval)
+void
+nsTreeContentView::GetImageSrc(int32_t aRow, nsTreeColumn& aColumn,
+                               nsAString& aSrc, ErrorResult& aError)
 {
-  _retval.Truncate();
-  NS_ENSURE_NATIVE_COLUMN(aCol);
-  NS_PRECONDITION(aRow >= 0 && aRow < int32_t(mRows.Length()), "bad row");
-  if (aRow < 0 || aRow >= int32_t(mRows.Length()))
-    return NS_ERROR_INVALID_ARG;   
+  if (!IsValidRowIndex(aRow)) {
+    aError.Throw(NS_ERROR_INVALID_ARG);
+    return;
+  }
 
   Row* row = mRows[aRow].get();
 
   nsIContent* realRow =
     nsTreeUtils::GetImmediateChild(row->mContent, nsGkAtoms::treerow);
   if (realRow) {
-    nsIContent* cell = GetCell(realRow, aCol);
+    nsIContent* cell = GetCell(realRow, aColumn);
     if (cell)
-      cell->GetAttr(kNameSpaceID_None, nsGkAtoms::src, _retval);
+      cell->GetAttr(kNameSpaceID_None, nsGkAtoms::src, aSrc);
   }
-
-  return NS_OK;
 }
 
 NS_IMETHODIMP
-nsTreeContentView::GetProgressMode(int32_t aRow, nsITreeColumn* aCol, int32_t* _retval)
+nsTreeContentView::GetImageSrc(int32_t aRow, nsITreeColumn* aCol, nsAString& _retval)
 {
-  NS_ENSURE_NATIVE_COLUMN(aCol);
-  NS_PRECONDITION(aRow >= 0 && aRow < int32_t(mRows.Length()), "bad row");
-  if (aRow < 0 || aRow >= int32_t(mRows.Length()))
-    return NS_ERROR_INVALID_ARG;   
+  RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
+  NS_ENSURE_ARG(col);
+
+  ErrorResult rv;
+  GetImageSrc(aRow, *col, _retval, rv);
+  return rv.StealNSResult();
+}
 
-  *_retval = nsITreeView::PROGRESS_NONE;
+int32_t
+nsTreeContentView::GetProgressMode(int32_t aRow, nsTreeColumn& aColumn,
+                                   ErrorResult& aError)
+{
+  if (!IsValidRowIndex(aRow)) {
+    aError.Throw(NS_ERROR_INVALID_ARG);
+    return 0;
+  }
 
   Row* row = mRows[aRow].get();
 
   nsIContent* realRow =
     nsTreeUtils::GetImmediateChild(row->mContent, nsGkAtoms::treerow);
   if (realRow) {
-    nsIContent* cell = GetCell(realRow, aCol);
+    nsIContent* cell = GetCell(realRow, aColumn);
     if (cell) {
       static nsIContent::AttrValuesArray strings[] =
         {&nsGkAtoms::normal, &nsGkAtoms::undetermined, nullptr};
       switch (cell->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::mode,
                                     strings, eCaseMatters)) {
-        case 0: *_retval = nsITreeView::PROGRESS_NORMAL; break;
-        case 1: *_retval = nsITreeView::PROGRESS_UNDETERMINED; break;
+        case 0:
+        {
+          return nsITreeView::PROGRESS_NORMAL;
+        }
+        case 1:
+        {
+          return nsITreeView::PROGRESS_UNDETERMINED;
+        }
       }
     }
   }
 
-  return NS_OK;
+  return nsITreeView::PROGRESS_NONE;
 }
 
 NS_IMETHODIMP
-nsTreeContentView::GetCellValue(int32_t aRow, nsITreeColumn* aCol, nsAString& _retval)
+nsTreeContentView::GetProgressMode(int32_t aRow, nsITreeColumn* aCol, int32_t* _retval)
 {
-  _retval.Truncate();
-  NS_ENSURE_NATIVE_COLUMN(aCol);
-  NS_PRECONDITION(aRow >= 0 && aRow < int32_t(mRows.Length()), "bad row");
-  if (aRow < 0 || aRow >= int32_t(mRows.Length()))
-    return NS_ERROR_INVALID_ARG;   
+  RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
+  NS_ENSURE_ARG(col);
+
+  ErrorResult rv;
+  *_retval = GetProgressMode(aRow, *col, rv);
+  return rv.StealNSResult();
+}
+
+void
+nsTreeContentView::GetCellValue(int32_t aRow, nsTreeColumn& aColumn,
+                                nsAString& aValue, ErrorResult& aError)
+{
+  if (!IsValidRowIndex(aRow)) {
+    aError.Throw(NS_ERROR_INVALID_ARG);
+    return;
+  }
 
   Row* row = mRows[aRow].get();
 
   nsIContent* realRow =
     nsTreeUtils::GetImmediateChild(row->mContent, nsGkAtoms::treerow);
   if (realRow) {
-    nsIContent* cell = GetCell(realRow, aCol);
+    nsIContent* cell = GetCell(realRow, aColumn);
     if (cell)
-      cell->GetAttr(kNameSpaceID_None, nsGkAtoms::value, _retval);
+      cell->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aValue);
+  }
+}
+
+NS_IMETHODIMP
+nsTreeContentView::GetCellValue(int32_t aRow, nsITreeColumn* aCol, nsAString& _retval)
+{
+  RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
+  NS_ENSURE_ARG(col);
+
+  ErrorResult rv;
+  GetCellValue(aRow, *col, _retval, rv);
+  return rv.StealNSResult();
+}
+
+void
+nsTreeContentView::GetCellText(int32_t aRow, nsTreeColumn& aColumn,
+                               nsAString& aText, ErrorResult& aError)
+{
+  if (!IsValidRowIndex(aRow)) {
+    aError.Throw(NS_ERROR_INVALID_ARG);
+    return;
   }
 
-  return NS_OK;
+  Row* row = mRows[aRow].get();
+
+  // Check for a "label" attribute - this is valid on an <treeitem>
+  // with a single implied column.
+  if (row->mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::label, aText) &&
+      !aText.IsEmpty()) {
+    return;
+  }
+
+  if (row->mContent->IsXULElement(nsGkAtoms::treeitem)) {
+    nsIContent* realRow =
+      nsTreeUtils::GetImmediateChild(row->mContent, nsGkAtoms::treerow);
+    if (realRow) {
+      nsIContent* cell = GetCell(realRow, aColumn);
+      if (cell)
+        cell->GetAttr(kNameSpaceID_None, nsGkAtoms::label, aText);
+    }
+  }
 }
 
 NS_IMETHODIMP
 nsTreeContentView::GetCellText(int32_t aRow, nsITreeColumn* aCol, nsAString& _retval)
 {
-  _retval.Truncate();
-  NS_ENSURE_NATIVE_COLUMN(aCol);
-  NS_PRECONDITION(aRow >= 0 && aRow < int32_t(mRows.Length()), "bad row");
-  NS_PRECONDITION(aCol, "bad column");
-
-  if (aRow < 0 || aRow >= int32_t(mRows.Length()) || !aCol)
-    return NS_ERROR_INVALID_ARG;
-
-  Row* row = mRows[aRow].get();
+  RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
+  NS_ENSURE_ARG(col);
 
-  // Check for a "label" attribute - this is valid on an <treeitem>
-  // with a single implied column.
-  if (row->mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::label, _retval)
-      && !_retval.IsEmpty())
-    return NS_OK;
+  ErrorResult rv;
+  GetCellText(aRow, *col, _retval, rv);
+  return rv.StealNSResult();
+}
 
-  if (row->mContent->IsXULElement(nsGkAtoms::treeitem)) {
-    nsIContent* realRow =
-      nsTreeUtils::GetImmediateChild(row->mContent, nsGkAtoms::treerow);
-    if (realRow) {
-      nsIContent* cell = GetCell(realRow, aCol);
-      if (cell)
-        cell->GetAttr(kNameSpaceID_None, nsGkAtoms::label, _retval);
-    }
-  }
-
-  return NS_OK;
+void
+nsTreeContentView::SetTree(TreeBoxObject* aTree, ErrorResult& aError)
+{
+  aError = SetTree(aTree);
 }
 
 NS_IMETHODIMP
 nsTreeContentView::SetTree(nsITreeBoxObject* aTree)
 {
   ClearRows();
 
   mBoxObject = aTree;
@@ -498,45 +650,50 @@ nsTreeContentView::SetTree(nsITreeBoxObj
       int32_t index = 0;
       Serialize(mBody, -1, &index, mRows);
     }
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsTreeContentView::ToggleOpenState(int32_t aIndex)
+void
+nsTreeContentView::ToggleOpenState(int32_t aRow, ErrorResult& aError)
 {
-  NS_PRECONDITION(aIndex >= 0 && aIndex < int32_t(mRows.Length()), "bad index");
-  if (aIndex < 0 || aIndex >= int32_t(mRows.Length()))
-    return NS_ERROR_INVALID_ARG;   
+  if (!IsValidRowIndex(aRow)) {
+    aError.Throw(NS_ERROR_INVALID_ARG);
+    return;
+  }
 
   // We don't serialize content right here, since content might be generated
   // lazily.
-  Row* row = mRows[aIndex].get();
+  Row* row = mRows[aRow].get();
 
   if (row->IsOpen())
     row->mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::open, NS_LITERAL_STRING("false"), true);
   else
     row->mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::open, NS_LITERAL_STRING("true"), true);
-
-  return NS_OK;
 }
 
 NS_IMETHODIMP
-nsTreeContentView::CycleHeader(nsITreeColumn* aCol)
+nsTreeContentView::ToggleOpenState(int32_t aIndex)
 {
-  NS_ENSURE_NATIVE_COLUMN(aCol);
+  ErrorResult rv;
+  ToggleOpenState(aIndex, rv);
+  return rv.StealNSResult();
+}
 
+void
+nsTreeContentView::CycleHeader(nsTreeColumn& aColumn, ErrorResult& aError)
+{
   if (!mRoot)
-    return NS_OK;
+    return;
 
   nsCOMPtr<nsIDOMElement> element;
-  aCol->GetElement(getter_AddRefs(element));
+  aColumn.GetElement(getter_AddRefs(element));
   if (element) {
     nsCOMPtr<nsIContent> column = do_QueryInterface(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;
@@ -555,123 +712,171 @@ nsTreeContentView::CycleHeader(nsITreeCo
         sortdirection.Append(' ');
         sortdirection += hints;
 
         nsCOMPtr<nsIDOMNode> rootnode = do_QueryInterface(mRoot);
         xs->Sort(rootnode, sort, sortdirection);
       }
     }
   }
+}
 
-  return NS_OK;
+NS_IMETHODIMP
+nsTreeContentView::CycleHeader(nsITreeColumn* aCol)
+{
+  RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
+  NS_ENSURE_ARG(col);
+
+  ErrorResult rv;
+  CycleHeader(*col, rv);
+  return rv.StealNSResult();
 }
 
 NS_IMETHODIMP
 nsTreeContentView::SelectionChanged()
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsTreeContentView::CycleCell(int32_t aRow, nsITreeColumn* aCol)
 {
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsTreeContentView::IsEditable(int32_t aRow, nsITreeColumn* aCol, bool* _retval)
+bool
+nsTreeContentView::IsEditable(int32_t aRow, nsTreeColumn& aColumn,
+                              ErrorResult& aError)
 {
-  *_retval = false;
-  NS_ENSURE_NATIVE_COLUMN(aCol);
-  NS_PRECONDITION(aRow >= 0 && aRow < int32_t(mRows.Length()), "bad row");
-  if (aRow < 0 || aRow >= int32_t(mRows.Length()))
-    return NS_ERROR_INVALID_ARG;   
-
-  *_retval = true;
+  if (!IsValidRowIndex(aRow)) {
+    aError.Throw(NS_ERROR_INVALID_ARG);
+    return false;
+  }
 
   Row* row = mRows[aRow].get();
 
   nsIContent* realRow =
     nsTreeUtils::GetImmediateChild(row->mContent, nsGkAtoms::treerow);
   if (realRow) {
-    nsIContent* cell = GetCell(realRow, aCol);
+    nsIContent* cell = GetCell(realRow, aColumn);
     if (cell && cell->AttrValueIs(kNameSpaceID_None, nsGkAtoms::editable,
                                   nsGkAtoms::_false, eCaseMatters)) {
-      *_retval = false;
+      return false;
     }
   }
 
-  return NS_OK;
+  return true;
 }
 
 NS_IMETHODIMP
-nsTreeContentView::IsSelectable(int32_t aRow, nsITreeColumn* aCol, bool* _retval)
+nsTreeContentView::IsEditable(int32_t aRow, nsITreeColumn* aCol, bool* _retval)
 {
-  NS_ENSURE_NATIVE_COLUMN(aCol);
-  NS_PRECONDITION(aRow >= 0 && aRow < int32_t(mRows.Length()), "bad row");
-  if (aRow < 0 || aRow >= int32_t(mRows.Length()))
-    return NS_ERROR_INVALID_ARG;   
+  RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
+  NS_ENSURE_ARG(col);
+
+  ErrorResult rv;
+  *_retval = IsEditable(aRow, *col, rv);
+  return rv.StealNSResult();
+}
 
-  *_retval = true;
+bool
+nsTreeContentView::IsSelectable(int32_t aRow, nsTreeColumn& aColumn,
+                                ErrorResult& aError)
+{
+  if (!IsValidRowIndex(aRow)) {
+    aError.Throw(NS_ERROR_INVALID_ARG);
+    return false;
+  }
 
   Row* row = mRows[aRow].get();
 
   nsIContent* realRow =
     nsTreeUtils::GetImmediateChild(row->mContent, nsGkAtoms::treerow);
   if (realRow) {
-    nsIContent* cell = GetCell(realRow, aCol);
+    nsIContent* cell = GetCell(realRow, aColumn);
     if (cell && cell->AttrValueIs(kNameSpaceID_None, nsGkAtoms::selectable,
                                   nsGkAtoms::_false, eCaseMatters)) {
-      *_retval = false;
+      return false;
     }
   }
 
-  return NS_OK;
+  return true;
 }
 
 NS_IMETHODIMP
-nsTreeContentView::SetCellValue(int32_t aRow, nsITreeColumn* aCol, const nsAString& aValue)
+nsTreeContentView::IsSelectable(int32_t aRow, nsITreeColumn* aCol, bool* _retval)
 {
-  NS_ENSURE_NATIVE_COLUMN(aCol);
-  NS_PRECONDITION(aRow >= 0 && aRow < int32_t(mRows.Length()), "bad row");
-  if (aRow < 0 || aRow >= int32_t(mRows.Length()))
-    return NS_ERROR_INVALID_ARG;   
+  RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
+  NS_ENSURE_ARG(col);
+
+  ErrorResult rv;
+  *_retval = IsSelectable(aRow, *col, rv);
+  return rv.StealNSResult();
+}
+
+void
+nsTreeContentView::SetCellValue(int32_t aRow, nsTreeColumn& aColumn,
+                                const nsAString& aValue, ErrorResult& aError)
+{
+  if (!IsValidRowIndex(aRow)) {
+    aError.Throw(NS_ERROR_INVALID_ARG);
+    return;
+  }
 
   Row* row = mRows[aRow].get();
 
   nsIContent* realRow =
     nsTreeUtils::GetImmediateChild(row->mContent, nsGkAtoms::treerow);
   if (realRow) {
-    nsIContent* cell = GetCell(realRow, aCol);
+    nsIContent* cell = GetCell(realRow, aColumn);
     if (cell)
       cell->SetAttr(kNameSpaceID_None, nsGkAtoms::value, aValue, true);
   }
-
-  return NS_OK;
 }
 
 NS_IMETHODIMP
-nsTreeContentView::SetCellText(int32_t aRow, nsITreeColumn* aCol, const nsAString& aValue)
+nsTreeContentView::SetCellValue(int32_t aRow, nsITreeColumn* aCol, const nsAString& aValue)
 {
-  NS_ENSURE_NATIVE_COLUMN(aCol);
-  NS_PRECONDITION(aRow >= 0 && aRow < int32_t(mRows.Length()), "bad row");
-  if (aRow < 0 || aRow >= int32_t(mRows.Length()))
-    return NS_ERROR_INVALID_ARG;   
+  RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
+  NS_ENSURE_ARG(col);
+
+  ErrorResult rv;
+  SetCellValue(aRow, *col, aValue, rv);
+  return rv.StealNSResult();
+}
+
+void
+nsTreeContentView::SetCellText(int32_t aRow, nsTreeColumn& aColumn,
+                               const nsAString& aValue, ErrorResult& aError)
+{
+  if (!IsValidRowIndex(aRow)) {
+    aError.Throw(NS_ERROR_INVALID_ARG);
+    return;
+  }
 
   Row* row = mRows[aRow].get();
 
   nsIContent* realRow =
     nsTreeUtils::GetImmediateChild(row->mContent, nsGkAtoms::treerow);
   if (realRow) {
-    nsIContent* cell = GetCell(realRow, aCol);
+    nsIContent* cell = GetCell(realRow, aColumn);
     if (cell)
       cell->SetAttr(kNameSpaceID_None, nsGkAtoms::label, aValue, true);
   }
+}
 
-  return NS_OK;
+NS_IMETHODIMP
+nsTreeContentView::SetCellText(int32_t aRow, nsITreeColumn* aCol, const nsAString& aValue)
+{
+  RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
+  NS_ENSURE_ARG(col);
+
+  ErrorResult rv;
+  SetCellText(aRow, *col, aValue, rv);
+  return rv.StealNSResult();
 }
 
 NS_IMETHODIMP
 nsTreeContentView::PerformAction(const char16_t* aAction)
 {
   return NS_OK;
 }
 
@@ -682,35 +887,56 @@ nsTreeContentView::PerformActionOnRow(co
 }
 
 NS_IMETHODIMP
 nsTreeContentView::PerformActionOnCell(const char16_t* aAction, int32_t aRow, nsITreeColumn* aCol)
 {
   return NS_OK;
 }
 
+Element*
+nsTreeContentView::GetItemAtIndex(int32_t aIndex, ErrorResult& aError)
+{
+  if (!IsValidRowIndex(aIndex)) {
+    aError.Throw(NS_ERROR_INVALID_ARG);
+    return nullptr;
+  }
+
+  return mRows[aIndex]->mContent;
+}
 
 NS_IMETHODIMP
 nsTreeContentView::GetItemAtIndex(int32_t aIndex, nsIDOMElement** _retval)
 {
-  NS_PRECONDITION(aIndex >= 0 && aIndex < int32_t(mRows.Length()), "bad index");
-  if (aIndex < 0 || aIndex >= int32_t(mRows.Length()))
-    return NS_ERROR_INVALID_ARG;   
+  ErrorResult rv;
+  Element* element = GetItemAtIndex(aIndex, rv);
+  if (rv.Failed()) {
+    return rv.StealNSResult();
+  }
 
-  Row* row = mRows[aIndex].get();
-  row->mContent->QueryInterface(NS_GET_IID(nsIDOMElement), (void**)_retval);
+  if (!element) {
+    *_retval = nullptr;
+    return NS_OK;
+  }
 
-  return NS_OK;
+  return CallQueryInterface(element, _retval);
+}
+
+int32_t
+nsTreeContentView::GetIndexOfItem(Element* aItem)
+{
+  return FindContent(aItem);
 }
 
 NS_IMETHODIMP
 nsTreeContentView::GetIndexOfItem(nsIDOMElement* aItem, int32_t* _retval)
 {
-  nsCOMPtr<nsIContent> content = do_QueryInterface(aItem);
-  *_retval = FindContent(content);
+  nsCOMPtr<Element> element = do_QueryInterface(aItem);
+
+  *_retval = GetIndexOfItem(element);
 
   return NS_OK;
 }
 
 void
 nsTreeContentView::AttributeChanged(nsIDocument*  aDocument,
                                     dom::Element* aElement,
                                     int32_t       aNameSpaceID,
@@ -1039,27 +1265,27 @@ nsTreeContentView::Serialize(nsIContent*
   if (!aContent->IsXULElement())
     return;
 
   dom::FlattenedChildIterator iter(aContent);
   for (nsIContent* content = iter.GetNextChild(); content; content = iter.GetNextChild()) {
     int32_t count = aRows.Length();
 
     if (content->IsXULElement(nsGkAtoms::treeitem)) {
-      SerializeItem(content, aParentIndex, aIndex, aRows);
+      SerializeItem(content->AsElement(), aParentIndex, aIndex, aRows);
     } else if (content->IsXULElement(nsGkAtoms::treeseparator)) {
-      SerializeSeparator(content, aParentIndex, aIndex, aRows);
+      SerializeSeparator(content->AsElement(), aParentIndex, aIndex, aRows);
     }
 
     *aIndex += aRows.Length() - count;
   }
 }
 
 void
-nsTreeContentView::SerializeItem(nsIContent* aContent, int32_t aParentIndex,
+nsTreeContentView::SerializeItem(Element* aContent, int32_t aParentIndex,
                                  int32_t* aIndex, nsTArray<UniquePtr<Row>>& aRows)
 {
   if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidden,
                             nsGkAtoms::_true, eCaseMatters))
     return;
 
   aRows.AppendElement(MakeUnique<Row>(aContent, aParentIndex));
   Row* row = aRows.LastElement().get();
@@ -1084,17 +1310,17 @@ nsTreeContentView::SerializeItem(nsICont
     } else if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::empty,
                                      nsGkAtoms::_true, eCaseMatters)) {
       row->SetEmpty(true);
     }
   } 
 }
 
 void
-nsTreeContentView::SerializeSeparator(nsIContent* aContent,
+nsTreeContentView::SerializeSeparator(Element* aContent,
                                       int32_t aParentIndex, int32_t* aIndex,
                                       nsTArray<UniquePtr<Row>>& aRows)
 {
   if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidden,
                             nsGkAtoms::_true, eCaseMatters))
     return;
 
   auto row = MakeUnique<Row>(aContent, aParentIndex);
@@ -1226,19 +1452,19 @@ nsTreeContentView::InsertRowFor(nsIConte
   }
 }
 
 int32_t
 nsTreeContentView::InsertRow(int32_t aParentIndex, int32_t aIndex, nsIContent* aContent)
 {
   AutoTArray<UniquePtr<Row>, 8> rows;
   if (aContent->IsXULElement(nsGkAtoms::treeitem)) {
-    SerializeItem(aContent, aParentIndex, &aIndex, rows);
+    SerializeItem(aContent->AsElement(), aParentIndex, &aIndex, rows);
   } else if (aContent->IsXULElement(nsGkAtoms::treeseparator)) {
-    SerializeSeparator(aContent, aParentIndex, &aIndex, rows);
+    SerializeSeparator(aContent->AsElement(), aParentIndex, &aIndex, rows);
   }
 
   // We can't use InsertElementsAt since the destination can't steal
   // ownership from its const source argument.
   int32_t count = rows.Length();
   for (nsTArray<Row>::index_type i = 0; i < size_t(count); i++) {
     mRows.InsertElementAt(aParentIndex + aIndex + i + 1, Move(rows[i]));
   }
@@ -1337,22 +1563,20 @@ nsTreeContentView::UpdateParentIndexes(i
     Row* row = mRows[i].get();
     if (row->mParentIndex > aIndex) {
       row->mParentIndex += aCount;
     }
   }
 }
 
 nsIContent*
-nsTreeContentView::GetCell(nsIContent* aContainer, nsITreeColumn* aCol)
+nsTreeContentView::GetCell(nsIContent* aContainer, nsTreeColumn& aCol)
 {
-  nsCOMPtr<nsIAtom> colAtom;
-  int32_t colIndex;
-  aCol->GetAtom(getter_AddRefs(colAtom));
-  aCol->GetIndex(&colIndex);
+  nsCOMPtr<nsIAtom> colAtom(aCol.GetAtom());
+  int32_t colIndex(aCol.GetIndex());
 
   // Traverse through cells, try to find the cell by "ref" attribute or by cell
   // index in a row. "ref" attribute has higher priority.
   nsIContent* result = nullptr;
   int32_t j = 0;
   dom::FlattenedChildIterator iter(aContainer);
   for (nsIContent* cell = iter.GetNextChild(); cell; cell = iter.GetNextChild()) {
     if (cell->IsXULElement(nsGkAtoms::treecell)) {
@@ -1365,8 +1589,14 @@ nsTreeContentView::GetCell(nsIContent* a
         result = cell;
       }
       j++;
     }
   }
 
   return result;
 }
+
+bool
+nsTreeContentView::IsValidRowIndex(int32_t aRowIndex)
+{
+  return aRowIndex >= 0 && aRowIndex < int32_t(mRows.Length());
+}
--- a/layout/xul/tree/nsTreeContentView.h
+++ b/layout/xul/tree/nsTreeContentView.h
@@ -5,38 +5,122 @@
 
 #ifndef nsTreeContentView_h__
 #define nsTreeContentView_h__
 
 #include "nsCycleCollectionParticipant.h"
 #include "nsTArray.h"
 #include "nsStubDocumentObserver.h"
 #include "nsITreeBoxObject.h"
-#include "nsITreeColumns.h"
 #include "nsITreeView.h"
 #include "nsITreeContentView.h"
 #include "nsITreeSelection.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/UniquePtr.h"
 
 class nsIDocument;
+class nsSelection;
+class nsTreeColumn;
 class Row;
 
+namespace mozilla {
+namespace dom {
+class DataTransfer;
+class TreeBoxObject;
+} // namespace dom
+} // namespace mozilla
+
 nsresult NS_NewTreeContentView(nsITreeView** aResult);
 
 class nsTreeContentView final : public nsINativeTreeView,
                                 public nsITreeContentView,
-                                public nsStubDocumentObserver
+                                public nsStubDocumentObserver,
+                                public nsWrapperCache
 {
   public:
     nsTreeContentView(void);
 
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-    NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsTreeContentView,
-                                             nsINativeTreeView)
+    NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsTreeContentView,
+                                                           nsINativeTreeView)
+
+    virtual JSObject* WrapObject(JSContext* aCx,
+                                 JS::Handle<JSObject*> aGivenProto) override;
+    nsISupports* GetParentObject();
+
+    int32_t RowCount()
+    {
+        return mRows.Length();
+    }
+    nsITreeSelection* GetSelection()
+    {
+        return mSelection;
+    }
+    void SetSelection(nsITreeSelection* aSelection,
+                      mozilla::ErrorResult& aError);
+    void GetRowProperties(int32_t aRow, nsAString& aProperties,
+                          mozilla::ErrorResult& aError);
+    void GetCellProperties(int32_t aRow, nsTreeColumn& aColumn,
+                           nsAString& aProperies, mozilla::ErrorResult& aError);
+    void GetColumnProperties(nsTreeColumn& aColumn, nsAString& aProperies);
+    bool IsContainer(int32_t aRow, mozilla::ErrorResult& aError);
+    bool IsContainerOpen(int32_t aRow, mozilla::ErrorResult& aError);
+    bool IsContainerEmpty(int32_t aRow, mozilla::ErrorResult& aError);
+    bool IsSeparator(int32_t aRow, mozilla::ErrorResult& aError);
+    bool IsSorted()
+    {
+        return false;
+    }
+    bool CanDrop(int32_t aRow, int32_t aOrientation,
+                 mozilla::dom::DataTransfer* aDataTransfer,
+                 mozilla::ErrorResult& aError);
+    void Drop(int32_t aRow, int32_t aOrientation,
+              mozilla::dom::DataTransfer* aDataTransfer,
+              mozilla::ErrorResult& aError);
+    int32_t GetParentIndex(int32_t aRow, mozilla::ErrorResult& aError);
+    bool HasNextSibling(int32_t aRow, int32_t aAfterIndex,
+                        mozilla::ErrorResult& aError);
+    int32_t GetLevel(int32_t aRow, mozilla::ErrorResult& aError);
+    void GetImageSrc(int32_t aRow, nsTreeColumn& aColumn, nsAString& aSrc,
+                     mozilla::ErrorResult& aError);
+    int32_t GetProgressMode(int32_t aRow, nsTreeColumn& aColumn,
+                            mozilla::ErrorResult& aError);
+    void GetCellValue(int32_t aRow, nsTreeColumn& aColumn, nsAString& aValue,
+                      mozilla::ErrorResult& aError);
+    void GetCellText(int32_t aRow, nsTreeColumn& aColumn, nsAString& aText,
+                     mozilla::ErrorResult& aError);
+    void SetTree(mozilla::dom::TreeBoxObject* aTree,
+                 mozilla::ErrorResult& aError);
+    void ToggleOpenState(int32_t aRow, mozilla::ErrorResult& aError);
+    void CycleHeader(nsTreeColumn& aColumn, mozilla::ErrorResult& aError);
+    // XPCOM SelectionChanged() is OK
+    void CycleCell(int32_t aRow, nsTreeColumn& aColumn)
+    {
+    }
+    bool IsEditable(int32_t aRow, nsTreeColumn& aColumn,
+                    mozilla::ErrorResult& aError);
+    bool IsSelectable(int32_t aRow, nsTreeColumn& aColumn,
+                      mozilla::ErrorResult& aError);
+    void SetCellValue(int32_t aRow, nsTreeColumn& aColumn,
+                      const nsAString& aValue, mozilla::ErrorResult& aError);
+    void SetCellText(int32_t aRow, nsTreeColumn& aColumn,
+                      const nsAString& aText, mozilla::ErrorResult& aError);
+    void PerformAction(const nsAString& aAction)
+    {
+    }
+    void PerformActionOnRow(const nsAString& aAction, int32_t aRow)
+    {
+    }
+    void PerformActionOnCell(const nsAString& aAction, int32_t aRow,
+                             nsTreeColumn& aColumn)
+    {
+    }
+    mozilla::dom::Element* GetItemAtIndex(int32_t aRow,
+                                          mozilla::ErrorResult& aError);
+    int32_t GetIndexOfItem(mozilla::dom::Element* aItem);
 
     NS_DECL_NSITREEVIEW
     // nsINativeTreeView: Untrusted code can use us
     NS_IMETHOD EnsureNative() override { return NS_OK; }
 
     NS_DECL_NSITREECONTENTVIEW
 
     // nsIDocumentObserver
@@ -50,20 +134,20 @@ class nsTreeContentView final : public n
 
   protected:
     ~nsTreeContentView(void);
 
     // Recursive methods which deal with serializing of nested content.
     void Serialize(nsIContent* aContent, int32_t aParentIndex, int32_t* aIndex,
                    nsTArray<mozilla::UniquePtr<Row>>& aRows);
 
-    void SerializeItem(nsIContent* aContent, int32_t aParentIndex,
+    void SerializeItem(Element* aContent, int32_t aParentIndex,
                        int32_t* aIndex, nsTArray<mozilla::UniquePtr<Row>>& aRows);
 
-    void SerializeSeparator(nsIContent* aContent, int32_t aParentIndex,
+    void SerializeSeparator(Element* aContent, int32_t aParentIndex,
                             int32_t* aIndex, nsTArray<mozilla::UniquePtr<Row>>& aRows);
 
     void GetIndexInSubtree(nsIContent* aContainer, nsIContent* aContent, int32_t* aResult);
     
     // Helper methods which we use to manage our plain array of rows.
     int32_t EnsureSubtree(int32_t aIndex);
 
     int32_t RemoveSubtree(int32_t aIndex);
@@ -82,19 +166,21 @@ class nsTreeContentView final : public n
 
     int32_t FindContent(nsIContent* aContent);
 
     void UpdateSubtreeSizes(int32_t aIndex, int32_t aCount);
 
     void UpdateParentIndexes(int32_t aIndex, int32_t aSkip, int32_t aCount);
 
     // Content helpers.
-    nsIContent* GetCell(nsIContent* aContainer, nsITreeColumn* aCol);
+    nsIContent* GetCell(nsIContent* aContainer, nsTreeColumn& aCol);
 
   private:
+    bool IsValidRowIndex(int32_t aRowIndex);
+
     nsCOMPtr<nsITreeBoxObject>          mBoxObject;
     nsCOMPtr<nsITreeSelection>          mSelection;
     nsCOMPtr<nsIContent>                mRoot;
     nsCOMPtr<nsIContent>                mBody;
     nsIDocument*                        mDocument;      // WEAK
     nsTArray<mozilla::UniquePtr<Row>>   mRows;
 };