LCOV - code coverage report
Current view: top level - layout/xul/tree - nsTreeContentView.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 789 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 105 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "nsNameSpaceManager.h"
       7             : #include "nsGkAtoms.h"
       8             : #include "nsIBoxObject.h"
       9             : #include "nsTreeUtils.h"
      10             : #include "nsTreeContentView.h"
      11             : #include "ChildIterator.h"
      12             : #include "nsError.h"
      13             : #include "nsIXULSortService.h"
      14             : #include "nsTreeBodyFrame.h"
      15             : #include "mozilla/dom/Element.h"
      16             : #include "mozilla/dom/TreeContentViewBinding.h"
      17             : #include "nsServiceManagerUtils.h"
      18             : #include "nsIDocument.h"
      19             : 
      20             : using namespace mozilla;
      21             : 
      22             : // A content model view implementation for the tree.
      23             : 
      24             : #define ROW_FLAG_CONTAINER      0x01
      25             : #define ROW_FLAG_OPEN           0x02
      26             : #define ROW_FLAG_EMPTY          0x04
      27             : #define ROW_FLAG_SEPARATOR      0x08
      28             : 
      29             : class Row
      30             : {
      31             :   public:
      32           0 :     Row(Element* aContent, int32_t aParentIndex)
      33           0 :       : mContent(aContent), mParentIndex(aParentIndex),
      34           0 :         mSubtreeSize(0), mFlags(0) {
      35           0 :     }
      36             : 
      37           0 :     ~Row() {
      38           0 :     }
      39             : 
      40           0 :     void SetContainer(bool aContainer) {
      41           0 :       aContainer ? mFlags |= ROW_FLAG_CONTAINER : mFlags &= ~ROW_FLAG_CONTAINER;
      42           0 :     }
      43           0 :     bool IsContainer() { return mFlags & ROW_FLAG_CONTAINER; }
      44             : 
      45           0 :     void SetOpen(bool aOpen) {
      46           0 :       aOpen ? mFlags |= ROW_FLAG_OPEN : mFlags &= ~ROW_FLAG_OPEN;
      47           0 :     }
      48           0 :     bool IsOpen() { return !!(mFlags & ROW_FLAG_OPEN); }
      49             : 
      50           0 :     void SetEmpty(bool aEmpty) {
      51           0 :       aEmpty ? mFlags |= ROW_FLAG_EMPTY : mFlags &= ~ROW_FLAG_EMPTY;
      52           0 :     }
      53           0 :     bool IsEmpty() { return !!(mFlags & ROW_FLAG_EMPTY); }
      54             : 
      55           0 :     void SetSeparator(bool aSeparator) {
      56           0 :       aSeparator ? mFlags |= ROW_FLAG_SEPARATOR : mFlags &= ~ROW_FLAG_SEPARATOR;
      57           0 :     }
      58           0 :     bool IsSeparator() { return !!(mFlags & ROW_FLAG_SEPARATOR); }
      59             : 
      60             :     // Weak reference to a content item.
      61             :     Element*            mContent;
      62             : 
      63             :     // The parent index of the item, set to -1 for the top level items.
      64             :     int32_t             mParentIndex;
      65             : 
      66             :     // Subtree size for this item.
      67             :     int32_t             mSubtreeSize;
      68             : 
      69             :   private:
      70             :     // State flags
      71             :     int8_t              mFlags;
      72             : };
      73             : 
      74             : 
      75             : // We don't reference count the reference to the document
      76             : // If the document goes away first, we'll be informed and we
      77             : // can drop our reference.
      78             : // If we go away first, we'll get rid of ourselves from the
      79             : // document's observer list.
      80             : 
      81           0 : nsTreeContentView::nsTreeContentView(void) :
      82             :   mBoxObject(nullptr),
      83             :   mSelection(nullptr),
      84             :   mRoot(nullptr),
      85           0 :   mDocument(nullptr)
      86             : {
      87           0 : }
      88             : 
      89           0 : nsTreeContentView::~nsTreeContentView(void)
      90             : {
      91             :   // Remove ourselves from mDocument's observers.
      92           0 :   if (mDocument)
      93           0 :     mDocument->RemoveObserver(this);
      94           0 : }
      95             : 
      96             : nsresult
      97           0 : NS_NewTreeContentView(nsITreeView** aResult)
      98             : {
      99           0 :   *aResult = new nsTreeContentView;
     100           0 :   if (! *aResult)
     101           0 :     return NS_ERROR_OUT_OF_MEMORY;
     102           0 :   NS_ADDREF(*aResult);
     103           0 :   return NS_OK;
     104             : }
     105             : 
     106           0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsTreeContentView,
     107             :                                       mBoxObject,
     108             :                                       mSelection,
     109             :                                       mRoot,
     110             :                                       mBody)
     111             : 
     112           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsTreeContentView)
     113           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsTreeContentView)
     114             : 
     115           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsTreeContentView)
     116           0 :   NS_INTERFACE_MAP_ENTRY(nsITreeView)
     117           0 :   NS_INTERFACE_MAP_ENTRY(nsITreeContentView)
     118           0 :   NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver)
     119           0 :   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
     120           0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsITreeContentView)
     121           0 :   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     122           0 : NS_INTERFACE_MAP_END
     123             : 
     124             : JSObject*
     125           0 : nsTreeContentView::WrapObject(JSContext* aCx,
     126             :                               JS::Handle<JSObject*> aGivenProto)
     127             : {
     128           0 :   return TreeContentViewBinding::Wrap(aCx, this, aGivenProto);
     129             : }
     130             : 
     131             : nsISupports*
     132           0 : nsTreeContentView::GetParentObject()
     133             : {
     134           0 :   return mBoxObject;
     135             : }
     136             : 
     137             : NS_IMETHODIMP
     138           0 : nsTreeContentView::GetRowCount(int32_t* aRowCount)
     139             : {
     140           0 :   *aRowCount = mRows.Length();
     141             : 
     142           0 :   return NS_OK;
     143             : }
     144             : 
     145             : NS_IMETHODIMP
     146           0 : nsTreeContentView::GetSelection(nsITreeSelection** aSelection)
     147             : {
     148           0 :   NS_IF_ADDREF(*aSelection = GetSelection());
     149             : 
     150           0 :   return NS_OK;
     151             : }
     152             : 
     153             : bool
     154           0 : nsTreeContentView::CanTrustTreeSelection(nsISupports* aValue)
     155             : {
     156             :   // Untrusted content is only allowed to specify known-good views
     157           0 :   if (nsContentUtils::LegacyIsCallerChromeOrNativeCode())
     158           0 :     return true;
     159           0 :   nsCOMPtr<nsINativeTreeSelection> nativeTreeSel = do_QueryInterface(aValue);
     160           0 :   return nativeTreeSel && NS_SUCCEEDED(nativeTreeSel->EnsureNative());
     161             : }
     162             : 
     163             : NS_IMETHODIMP
     164           0 : nsTreeContentView::SetSelection(nsITreeSelection* aSelection)
     165             : {
     166           0 :   ErrorResult rv;
     167           0 :   SetSelection(aSelection, rv);
     168           0 :   return rv.StealNSResult();
     169             : }
     170             : 
     171             : void
     172           0 : nsTreeContentView::SetSelection(nsITreeSelection* aSelection, ErrorResult& aError)
     173             : {
     174           0 :   if (aSelection && !CanTrustTreeSelection(aSelection)) {
     175           0 :     aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
     176           0 :     return;
     177             :   }
     178             : 
     179           0 :   mSelection = aSelection;
     180             : }
     181             : 
     182             : void
     183           0 : nsTreeContentView::GetRowProperties(int32_t aRow, nsAString& aProperties,
     184             :                                     ErrorResult& aError)
     185             : {
     186           0 :   if (!IsValidRowIndex(aRow)) {
     187           0 :     aError.Throw(NS_ERROR_INVALID_ARG);
     188           0 :     return;
     189             :   }
     190             : 
     191           0 :   Row* row = mRows[aRow].get();
     192             :   nsIContent* realRow;
     193           0 :   if (row->IsSeparator())
     194           0 :     realRow = row->mContent;
     195             :   else
     196           0 :     realRow = nsTreeUtils::GetImmediateChild(row->mContent, nsGkAtoms::treerow);
     197             : 
     198           0 :   if (realRow) {
     199           0 :     realRow->GetAttr(kNameSpaceID_None, nsGkAtoms::properties, aProperties);
     200             :   }
     201             : }
     202             : 
     203             : NS_IMETHODIMP
     204           0 : nsTreeContentView::GetRowProperties(int32_t aIndex, nsAString& aProps)
     205             : {
     206           0 :   ErrorResult rv;
     207           0 :   GetRowProperties(aIndex, aProps, rv);
     208           0 :   return rv.StealNSResult();
     209             : }
     210             : 
     211             : void
     212           0 : nsTreeContentView::GetCellProperties(int32_t aRow, nsTreeColumn& aColumn,
     213             :                                      nsAString& aProperties,
     214             :                                      ErrorResult& aError)
     215             : {
     216           0 :   if (!IsValidRowIndex(aRow)) {
     217           0 :     aError.Throw(NS_ERROR_INVALID_ARG);
     218           0 :     return;
     219             :   }
     220             : 
     221           0 :   Row* row = mRows[aRow].get();
     222             :   nsIContent* realRow =
     223           0 :     nsTreeUtils::GetImmediateChild(row->mContent, nsGkAtoms::treerow);
     224           0 :   if (realRow) {
     225           0 :     nsIContent* cell = GetCell(realRow, aColumn);
     226           0 :     if (cell) {
     227           0 :       cell->GetAttr(kNameSpaceID_None, nsGkAtoms::properties, aProperties);
     228             :     }
     229             :   }
     230             : }
     231             : 
     232             : NS_IMETHODIMP
     233           0 : nsTreeContentView::GetCellProperties(int32_t aRow, nsITreeColumn* aCol,
     234             :                                      nsAString& aProps)
     235             : {
     236           0 :   RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
     237           0 :   NS_ENSURE_ARG(col);
     238             : 
     239           0 :   ErrorResult rv;
     240           0 :   GetCellProperties(aRow, *col, aProps, rv);
     241           0 :   return rv.StealNSResult();
     242             : }
     243             : 
     244             : void
     245           0 : nsTreeContentView::GetColumnProperties(nsTreeColumn& aColumn,
     246             :                                        nsAString& aProperties)
     247             : {
     248           0 :   nsCOMPtr<nsIDOMElement> element;
     249           0 :   aColumn.GetElement(getter_AddRefs(element));
     250             : 
     251           0 :   element->GetAttribute(NS_LITERAL_STRING("properties"), aProperties);
     252           0 : }
     253             : 
     254             : NS_IMETHODIMP
     255           0 : nsTreeContentView::GetColumnProperties(nsITreeColumn* aCol, nsAString& aProps)
     256             : {
     257           0 :   RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
     258           0 :   NS_ENSURE_ARG(col);
     259             : 
     260           0 :   GetColumnProperties(*col, aProps);
     261           0 :   return NS_OK;
     262             : }
     263             : 
     264             : bool
     265           0 : nsTreeContentView::IsContainer(int32_t aRow, ErrorResult& aError)
     266             : {
     267           0 :   if (!IsValidRowIndex(aRow)) {
     268           0 :     aError.Throw(NS_ERROR_INVALID_ARG);
     269           0 :     return false;
     270             :   }
     271             : 
     272           0 :   return mRows[aRow]->IsContainer();
     273             : }
     274             : 
     275             : NS_IMETHODIMP
     276           0 : nsTreeContentView::IsContainer(int32_t aIndex, bool* _retval)
     277             : {
     278           0 :   ErrorResult rv;
     279           0 :   *_retval = IsContainer(aIndex, rv);
     280           0 :   return rv.StealNSResult();
     281             : }
     282             : 
     283             : bool
     284           0 : nsTreeContentView::IsContainerOpen(int32_t aRow, ErrorResult& aError)
     285             : {
     286           0 :   if (!IsValidRowIndex(aRow)) {
     287           0 :     aError.Throw(NS_ERROR_INVALID_ARG);
     288           0 :     return false;
     289             :   }
     290             : 
     291           0 :   return mRows[aRow]->IsOpen();
     292             : }
     293             : 
     294             : NS_IMETHODIMP
     295           0 : nsTreeContentView::IsContainerOpen(int32_t aIndex, bool* _retval)
     296             : {
     297           0 :   ErrorResult rv;
     298           0 :   *_retval = IsContainerOpen(aIndex, rv);
     299           0 :   return rv.StealNSResult();
     300             : }
     301             : 
     302             : bool
     303           0 : nsTreeContentView::IsContainerEmpty(int32_t aRow, ErrorResult& aError)
     304             : {
     305           0 :   if (!IsValidRowIndex(aRow)) {
     306           0 :     aError.Throw(NS_ERROR_INVALID_ARG);
     307           0 :     return false;
     308             :   }
     309             : 
     310           0 :   return mRows[aRow]->IsEmpty();
     311             : }
     312             : 
     313             : NS_IMETHODIMP
     314           0 : nsTreeContentView::IsContainerEmpty(int32_t aIndex, bool* _retval)
     315             : {
     316           0 :   ErrorResult rv;
     317           0 :   *_retval = IsContainerEmpty(aIndex, rv);
     318           0 :   return rv.StealNSResult();
     319             : }
     320             : 
     321             : bool
     322           0 : nsTreeContentView::IsSeparator(int32_t aRow, ErrorResult& aError)
     323             : {
     324           0 :   if (!IsValidRowIndex(aRow)) {
     325           0 :     aError.Throw(NS_ERROR_INVALID_ARG);
     326           0 :     return false;
     327             :   }
     328             : 
     329           0 :   return mRows[aRow]->IsSeparator();
     330             : }
     331             : 
     332             : NS_IMETHODIMP
     333           0 : nsTreeContentView::IsSeparator(int32_t aIndex, bool *_retval)
     334             : {
     335           0 :   ErrorResult rv;
     336           0 :   *_retval = IsSeparator(aIndex, rv);
     337           0 :   return rv.StealNSResult();
     338             : }
     339             : 
     340             : NS_IMETHODIMP
     341           0 : nsTreeContentView::IsSorted(bool *_retval)
     342             : {
     343           0 :   *_retval = IsSorted();
     344             : 
     345           0 :   return NS_OK;
     346             : }
     347             : 
     348             : bool
     349           0 : nsTreeContentView::CanDrop(int32_t aRow, int32_t aOrientation,
     350             :                            DataTransfer* aDataTransfer, ErrorResult& aError)
     351             : {
     352           0 :   if (!IsValidRowIndex(aRow)) {
     353           0 :     aError.Throw(NS_ERROR_INVALID_ARG);
     354             :   }
     355           0 :   return false;
     356             : }
     357             : 
     358             : NS_IMETHODIMP
     359           0 : nsTreeContentView::CanDrop(int32_t aIndex, int32_t aOrientation,
     360             :                            nsIDOMDataTransfer* aDataTransfer, bool *_retval)
     361             : {
     362           0 :   ErrorResult rv;
     363           0 :   *_retval = CanDrop(aIndex, aOrientation, DataTransfer::Cast(aDataTransfer),
     364             :                      rv);
     365           0 :   return rv.StealNSResult();
     366             : }
     367             : 
     368             : void
     369           0 : nsTreeContentView::Drop(int32_t aRow, int32_t aOrientation,
     370             :                         DataTransfer* aDataTransfer, ErrorResult& aError)
     371             : {
     372           0 :   if (!IsValidRowIndex(aRow)) {
     373           0 :     aError.Throw(NS_ERROR_INVALID_ARG);
     374             :   }
     375           0 : }
     376             : 
     377             : NS_IMETHODIMP
     378           0 : nsTreeContentView::Drop(int32_t aRow, int32_t aOrientation, nsIDOMDataTransfer* aDataTransfer)
     379             : {
     380           0 :   ErrorResult rv;
     381           0 :   Drop(aRow, aOrientation, DataTransfer::Cast(aDataTransfer), rv);
     382           0 :   return rv.StealNSResult();
     383             : }
     384             : 
     385             : int32_t
     386           0 : nsTreeContentView::GetParentIndex(int32_t aRow, ErrorResult& aError)
     387             : {
     388           0 :   if (!IsValidRowIndex(aRow)) {
     389           0 :     aError.Throw(NS_ERROR_INVALID_ARG);
     390           0 :     return 0;
     391             :   }
     392             : 
     393           0 :   return mRows[aRow]->mParentIndex;
     394             : }
     395             : 
     396             : NS_IMETHODIMP
     397           0 : nsTreeContentView::GetParentIndex(int32_t aRowIndex, int32_t* _retval)
     398             : {
     399           0 :   ErrorResult rv;
     400           0 :   *_retval = GetParentIndex(aRowIndex, rv);
     401           0 :   return rv.StealNSResult();
     402             : }
     403             : 
     404             : bool
     405           0 : nsTreeContentView::HasNextSibling(int32_t aRow, int32_t aAfterIndex,
     406             :                                   ErrorResult& aError)
     407             : {
     408           0 :   if (!IsValidRowIndex(aRow)) {
     409           0 :     aError.Throw(NS_ERROR_INVALID_ARG);
     410           0 :     return false;
     411             :   }
     412             : 
     413             :   // We have a next sibling if the row is not the last in the subtree.
     414           0 :   int32_t parentIndex = mRows[aRow]->mParentIndex;
     415           0 :   if (parentIndex < 0) {
     416           0 :     return uint32_t(aRow) < mRows.Length() - 1;
     417             :   }
     418             : 
     419             :   // Compute the last index in this subtree.
     420           0 :   int32_t lastIndex = parentIndex + (mRows[parentIndex])->mSubtreeSize;
     421           0 :   Row* row = mRows[lastIndex].get();
     422           0 :   while (row->mParentIndex != parentIndex) {
     423           0 :     lastIndex = row->mParentIndex;
     424           0 :     row = mRows[lastIndex].get();
     425             :   }
     426             : 
     427           0 :   return aRow < lastIndex;
     428             : }
     429             : 
     430             : NS_IMETHODIMP
     431           0 : nsTreeContentView::HasNextSibling(int32_t aRowIndex, int32_t aAfterIndex, bool* _retval)
     432             : {
     433           0 :   ErrorResult rv;
     434           0 :   *_retval = HasNextSibling(aRowIndex, aAfterIndex, rv);
     435           0 :   return rv.StealNSResult();
     436             : }
     437             : 
     438             : int32_t
     439           0 : nsTreeContentView::GetLevel(int32_t aRow, ErrorResult& aError)
     440             : {
     441           0 :   if (!IsValidRowIndex(aRow)) {
     442           0 :     aError.Throw(NS_ERROR_INVALID_ARG);
     443           0 :     return 0;
     444             :   }
     445             : 
     446           0 :   int32_t level = 0;
     447           0 :   Row* row = mRows[aRow].get();
     448           0 :   while (row->mParentIndex >= 0) {
     449           0 :     level++;
     450           0 :     row = mRows[row->mParentIndex].get();
     451             :   }
     452           0 :   return level;
     453             : }
     454             : 
     455             : NS_IMETHODIMP
     456           0 : nsTreeContentView::GetLevel(int32_t aIndex, int32_t* _retval)
     457             : {
     458           0 :   ErrorResult rv;
     459           0 :   *_retval = GetLevel(aIndex, rv);
     460           0 :   return rv.StealNSResult();
     461             : }
     462             : 
     463             : void
     464           0 : nsTreeContentView::GetImageSrc(int32_t aRow, nsTreeColumn& aColumn,
     465             :                                nsAString& aSrc, ErrorResult& aError)
     466             : {
     467           0 :   if (!IsValidRowIndex(aRow)) {
     468           0 :     aError.Throw(NS_ERROR_INVALID_ARG);
     469           0 :     return;
     470             :   }
     471             : 
     472           0 :   Row* row = mRows[aRow].get();
     473             : 
     474             :   nsIContent* realRow =
     475           0 :     nsTreeUtils::GetImmediateChild(row->mContent, nsGkAtoms::treerow);
     476           0 :   if (realRow) {
     477           0 :     nsIContent* cell = GetCell(realRow, aColumn);
     478           0 :     if (cell)
     479           0 :       cell->GetAttr(kNameSpaceID_None, nsGkAtoms::src, aSrc);
     480             :   }
     481             : }
     482             : 
     483             : NS_IMETHODIMP
     484           0 : nsTreeContentView::GetImageSrc(int32_t aRow, nsITreeColumn* aCol, nsAString& _retval)
     485             : {
     486           0 :   RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
     487           0 :   NS_ENSURE_ARG(col);
     488             : 
     489           0 :   ErrorResult rv;
     490           0 :   GetImageSrc(aRow, *col, _retval, rv);
     491           0 :   return rv.StealNSResult();
     492             : }
     493             : 
     494             : int32_t
     495           0 : nsTreeContentView::GetProgressMode(int32_t aRow, nsTreeColumn& aColumn,
     496             :                                    ErrorResult& aError)
     497             : {
     498           0 :   if (!IsValidRowIndex(aRow)) {
     499           0 :     aError.Throw(NS_ERROR_INVALID_ARG);
     500           0 :     return 0;
     501             :   }
     502             : 
     503           0 :   Row* row = mRows[aRow].get();
     504             : 
     505             :   nsIContent* realRow =
     506           0 :     nsTreeUtils::GetImmediateChild(row->mContent, nsGkAtoms::treerow);
     507           0 :   if (realRow) {
     508           0 :     nsIContent* cell = GetCell(realRow, aColumn);
     509           0 :     if (cell) {
     510             :       static nsIContent::AttrValuesArray strings[] =
     511             :         {&nsGkAtoms::normal, &nsGkAtoms::undetermined, nullptr};
     512           0 :       switch (cell->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::mode,
     513           0 :                                     strings, eCaseMatters)) {
     514             :         case 0:
     515             :         {
     516           0 :           return nsITreeView::PROGRESS_NORMAL;
     517             :         }
     518             :         case 1:
     519             :         {
     520           0 :           return nsITreeView::PROGRESS_UNDETERMINED;
     521             :         }
     522             :       }
     523             :     }
     524             :   }
     525             : 
     526           0 :   return nsITreeView::PROGRESS_NONE;
     527             : }
     528             : 
     529             : NS_IMETHODIMP
     530           0 : nsTreeContentView::GetProgressMode(int32_t aRow, nsITreeColumn* aCol, int32_t* _retval)
     531             : {
     532           0 :   RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
     533           0 :   NS_ENSURE_ARG(col);
     534             : 
     535           0 :   ErrorResult rv;
     536           0 :   *_retval = GetProgressMode(aRow, *col, rv);
     537           0 :   return rv.StealNSResult();
     538             : }
     539             : 
     540             : void
     541           0 : nsTreeContentView::GetCellValue(int32_t aRow, nsTreeColumn& aColumn,
     542             :                                 nsAString& aValue, ErrorResult& aError)
     543             : {
     544           0 :   if (!IsValidRowIndex(aRow)) {
     545           0 :     aError.Throw(NS_ERROR_INVALID_ARG);
     546           0 :     return;
     547             :   }
     548             : 
     549           0 :   Row* row = mRows[aRow].get();
     550             : 
     551             :   nsIContent* realRow =
     552           0 :     nsTreeUtils::GetImmediateChild(row->mContent, nsGkAtoms::treerow);
     553           0 :   if (realRow) {
     554           0 :     nsIContent* cell = GetCell(realRow, aColumn);
     555           0 :     if (cell)
     556           0 :       cell->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aValue);
     557             :   }
     558             : }
     559             : 
     560             : NS_IMETHODIMP
     561           0 : nsTreeContentView::GetCellValue(int32_t aRow, nsITreeColumn* aCol, nsAString& _retval)
     562             : {
     563           0 :   RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
     564           0 :   NS_ENSURE_ARG(col);
     565             : 
     566           0 :   ErrorResult rv;
     567           0 :   GetCellValue(aRow, *col, _retval, rv);
     568           0 :   return rv.StealNSResult();
     569             : }
     570             : 
     571             : void
     572           0 : nsTreeContentView::GetCellText(int32_t aRow, nsTreeColumn& aColumn,
     573             :                                nsAString& aText, ErrorResult& aError)
     574             : {
     575           0 :   if (!IsValidRowIndex(aRow)) {
     576           0 :     aError.Throw(NS_ERROR_INVALID_ARG);
     577           0 :     return;
     578             :   }
     579             : 
     580           0 :   Row* row = mRows[aRow].get();
     581             : 
     582             :   // Check for a "label" attribute - this is valid on an <treeitem>
     583             :   // with a single implied column.
     584           0 :   if (row->mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::label, aText) &&
     585           0 :       !aText.IsEmpty()) {
     586           0 :     return;
     587             :   }
     588             : 
     589           0 :   if (row->mContent->IsXULElement(nsGkAtoms::treeitem)) {
     590             :     nsIContent* realRow =
     591           0 :       nsTreeUtils::GetImmediateChild(row->mContent, nsGkAtoms::treerow);
     592           0 :     if (realRow) {
     593           0 :       nsIContent* cell = GetCell(realRow, aColumn);
     594           0 :       if (cell)
     595           0 :         cell->GetAttr(kNameSpaceID_None, nsGkAtoms::label, aText);
     596             :     }
     597             :   }
     598             : }
     599             : 
     600             : NS_IMETHODIMP
     601           0 : nsTreeContentView::GetCellText(int32_t aRow, nsITreeColumn* aCol, nsAString& _retval)
     602             : {
     603           0 :   RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
     604           0 :   NS_ENSURE_ARG(col);
     605             : 
     606           0 :   ErrorResult rv;
     607           0 :   GetCellText(aRow, *col, _retval, rv);
     608           0 :   return rv.StealNSResult();
     609             : }
     610             : 
     611             : void
     612           0 : nsTreeContentView::SetTree(TreeBoxObject* aTree, ErrorResult& aError)
     613             : {
     614           0 :   aError = SetTree(aTree);
     615           0 : }
     616             : 
     617             : NS_IMETHODIMP
     618           0 : nsTreeContentView::SetTree(nsITreeBoxObject* aTree)
     619             : {
     620           0 :   ClearRows();
     621             : 
     622           0 :   mBoxObject = aTree;
     623             : 
     624           0 :   MOZ_ASSERT(!mRoot, "mRoot should have been cleared out by ClearRows");
     625             : 
     626           0 :   if (aTree) {
     627             :     // Get our root element
     628           0 :     nsCOMPtr<nsIBoxObject> boxObject = do_QueryInterface(mBoxObject);
     629           0 :     if (!boxObject) {
     630           0 :       mBoxObject = nullptr;
     631           0 :       return NS_ERROR_INVALID_ARG;
     632             :     }
     633           0 :     nsCOMPtr<nsIDOMElement> element;
     634           0 :     boxObject->GetElement(getter_AddRefs(element));
     635             : 
     636           0 :     mRoot = do_QueryInterface(element);
     637           0 :     NS_ENSURE_STATE(mRoot);
     638             : 
     639             :     // Add ourselves to document's observers.
     640           0 :     nsIDocument* document = mRoot->GetComposedDoc();
     641           0 :     if (document) {
     642           0 :       document->AddObserver(this);
     643           0 :       mDocument = document;
     644             :     }
     645             : 
     646           0 :     nsCOMPtr<nsIDOMElement> bodyElement;
     647           0 :     mBoxObject->GetTreeBody(getter_AddRefs(bodyElement));
     648           0 :     if (bodyElement) {
     649           0 :       mBody = do_QueryInterface(bodyElement);
     650           0 :       int32_t index = 0;
     651           0 :       Serialize(mBody, -1, &index, mRows);
     652             :     }
     653             :   }
     654             : 
     655           0 :   return NS_OK;
     656             : }
     657             : 
     658             : void
     659           0 : nsTreeContentView::ToggleOpenState(int32_t aRow, ErrorResult& aError)
     660             : {
     661           0 :   if (!IsValidRowIndex(aRow)) {
     662           0 :     aError.Throw(NS_ERROR_INVALID_ARG);
     663           0 :     return;
     664             :   }
     665             : 
     666             :   // We don't serialize content right here, since content might be generated
     667             :   // lazily.
     668           0 :   Row* row = mRows[aRow].get();
     669             : 
     670           0 :   if (row->IsOpen())
     671           0 :     row->mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::open, NS_LITERAL_STRING("false"), true);
     672             :   else
     673           0 :     row->mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::open, NS_LITERAL_STRING("true"), true);
     674             : }
     675             : 
     676             : NS_IMETHODIMP
     677           0 : nsTreeContentView::ToggleOpenState(int32_t aIndex)
     678             : {
     679           0 :   ErrorResult rv;
     680           0 :   ToggleOpenState(aIndex, rv);
     681           0 :   return rv.StealNSResult();
     682             : }
     683             : 
     684             : void
     685           0 : nsTreeContentView::CycleHeader(nsTreeColumn& aColumn, ErrorResult& aError)
     686             : {
     687           0 :   if (!mRoot)
     688           0 :     return;
     689             : 
     690           0 :   nsCOMPtr<nsIDOMElement> element;
     691           0 :   aColumn.GetElement(getter_AddRefs(element));
     692           0 :   if (element) {
     693           0 :     nsCOMPtr<nsIContent> column = do_QueryInterface(element);
     694           0 :     nsAutoString sort;
     695           0 :     column->GetAttr(kNameSpaceID_None, nsGkAtoms::sort, sort);
     696           0 :     if (!sort.IsEmpty()) {
     697           0 :       nsCOMPtr<nsIXULSortService> xs = do_GetService("@mozilla.org/xul/xul-sort-service;1");
     698           0 :       if (xs) {
     699           0 :         nsAutoString sortdirection;
     700             :         static nsIContent::AttrValuesArray strings[] =
     701             :           {&nsGkAtoms::ascending, &nsGkAtoms::descending, nullptr};
     702           0 :         switch (column->FindAttrValueIn(kNameSpaceID_None,
     703             :                                         nsGkAtoms::sortDirection,
     704           0 :                                         strings, eCaseMatters)) {
     705           0 :           case 0: sortdirection.AssignLiteral("descending"); break;
     706           0 :           case 1: sortdirection.AssignLiteral("natural"); break;
     707           0 :           default: sortdirection.AssignLiteral("ascending"); break;
     708             :         }
     709             : 
     710           0 :         nsAutoString hints;
     711           0 :         column->GetAttr(kNameSpaceID_None, nsGkAtoms::sorthints, hints);
     712           0 :         sortdirection.Append(' ');
     713           0 :         sortdirection += hints;
     714             : 
     715           0 :         nsCOMPtr<nsIDOMNode> rootnode = do_QueryInterface(mRoot);
     716           0 :         xs->Sort(rootnode, sort, sortdirection);
     717             :       }
     718             :     }
     719             :   }
     720             : }
     721             : 
     722             : NS_IMETHODIMP
     723           0 : nsTreeContentView::CycleHeader(nsITreeColumn* aCol)
     724             : {
     725           0 :   RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
     726           0 :   NS_ENSURE_ARG(col);
     727             : 
     728           0 :   ErrorResult rv;
     729           0 :   CycleHeader(*col, rv);
     730           0 :   return rv.StealNSResult();
     731             : }
     732             : 
     733             : NS_IMETHODIMP
     734           0 : nsTreeContentView::SelectionChanged()
     735             : {
     736           0 :   return NS_OK;
     737             : }
     738             : 
     739             : NS_IMETHODIMP
     740           0 : nsTreeContentView::CycleCell(int32_t aRow, nsITreeColumn* aCol)
     741             : {
     742           0 :   return NS_OK;
     743             : }
     744             : 
     745             : bool
     746           0 : nsTreeContentView::IsEditable(int32_t aRow, nsTreeColumn& aColumn,
     747             :                               ErrorResult& aError)
     748             : {
     749           0 :   if (!IsValidRowIndex(aRow)) {
     750           0 :     aError.Throw(NS_ERROR_INVALID_ARG);
     751           0 :     return false;
     752             :   }
     753             : 
     754           0 :   Row* row = mRows[aRow].get();
     755             : 
     756             :   nsIContent* realRow =
     757           0 :     nsTreeUtils::GetImmediateChild(row->mContent, nsGkAtoms::treerow);
     758           0 :   if (realRow) {
     759           0 :     nsIContent* cell = GetCell(realRow, aColumn);
     760           0 :     if (cell && cell->AttrValueIs(kNameSpaceID_None, nsGkAtoms::editable,
     761             :                                   nsGkAtoms::_false, eCaseMatters)) {
     762           0 :       return false;
     763             :     }
     764             :   }
     765             : 
     766           0 :   return true;
     767             : }
     768             : 
     769             : NS_IMETHODIMP
     770           0 : nsTreeContentView::IsEditable(int32_t aRow, nsITreeColumn* aCol, bool* _retval)
     771             : {
     772           0 :   RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
     773           0 :   NS_ENSURE_ARG(col);
     774             : 
     775           0 :   ErrorResult rv;
     776           0 :   *_retval = IsEditable(aRow, *col, rv);
     777           0 :   return rv.StealNSResult();
     778             : }
     779             : 
     780             : bool
     781           0 : nsTreeContentView::IsSelectable(int32_t aRow, nsTreeColumn& aColumn,
     782             :                                 ErrorResult& aError)
     783             : {
     784           0 :   if (!IsValidRowIndex(aRow)) {
     785           0 :     aError.Throw(NS_ERROR_INVALID_ARG);
     786           0 :     return false;
     787             :   }
     788             : 
     789           0 :   Row* row = mRows[aRow].get();
     790             : 
     791             :   nsIContent* realRow =
     792           0 :     nsTreeUtils::GetImmediateChild(row->mContent, nsGkAtoms::treerow);
     793           0 :   if (realRow) {
     794           0 :     nsIContent* cell = GetCell(realRow, aColumn);
     795           0 :     if (cell && cell->AttrValueIs(kNameSpaceID_None, nsGkAtoms::selectable,
     796             :                                   nsGkAtoms::_false, eCaseMatters)) {
     797           0 :       return false;
     798             :     }
     799             :   }
     800             : 
     801           0 :   return true;
     802             : }
     803             : 
     804             : NS_IMETHODIMP
     805           0 : nsTreeContentView::IsSelectable(int32_t aRow, nsITreeColumn* aCol, bool* _retval)
     806             : {
     807           0 :   RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
     808           0 :   NS_ENSURE_ARG(col);
     809             : 
     810           0 :   ErrorResult rv;
     811           0 :   *_retval = IsSelectable(aRow, *col, rv);
     812           0 :   return rv.StealNSResult();
     813             : }
     814             : 
     815             : void
     816           0 : nsTreeContentView::SetCellValue(int32_t aRow, nsTreeColumn& aColumn,
     817             :                                 const nsAString& aValue, ErrorResult& aError)
     818             : {
     819           0 :   if (!IsValidRowIndex(aRow)) {
     820           0 :     aError.Throw(NS_ERROR_INVALID_ARG);
     821           0 :     return;
     822             :   }
     823             : 
     824           0 :   Row* row = mRows[aRow].get();
     825             : 
     826             :   nsIContent* realRow =
     827           0 :     nsTreeUtils::GetImmediateChild(row->mContent, nsGkAtoms::treerow);
     828           0 :   if (realRow) {
     829           0 :     nsIContent* cell = GetCell(realRow, aColumn);
     830           0 :     if (cell)
     831           0 :       cell->SetAttr(kNameSpaceID_None, nsGkAtoms::value, aValue, true);
     832             :   }
     833             : }
     834             : 
     835             : NS_IMETHODIMP
     836           0 : nsTreeContentView::SetCellValue(int32_t aRow, nsITreeColumn* aCol, const nsAString& aValue)
     837             : {
     838           0 :   RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
     839           0 :   NS_ENSURE_ARG(col);
     840             : 
     841           0 :   ErrorResult rv;
     842           0 :   SetCellValue(aRow, *col, aValue, rv);
     843           0 :   return rv.StealNSResult();
     844             : }
     845             : 
     846             : void
     847           0 : nsTreeContentView::SetCellText(int32_t aRow, nsTreeColumn& aColumn,
     848             :                                const nsAString& aValue, ErrorResult& aError)
     849             : {
     850           0 :   if (!IsValidRowIndex(aRow)) {
     851           0 :     aError.Throw(NS_ERROR_INVALID_ARG);
     852           0 :     return;
     853             :   }
     854             : 
     855           0 :   Row* row = mRows[aRow].get();
     856             : 
     857             :   nsIContent* realRow =
     858           0 :     nsTreeUtils::GetImmediateChild(row->mContent, nsGkAtoms::treerow);
     859           0 :   if (realRow) {
     860           0 :     nsIContent* cell = GetCell(realRow, aColumn);
     861           0 :     if (cell)
     862           0 :       cell->SetAttr(kNameSpaceID_None, nsGkAtoms::label, aValue, true);
     863             :   }
     864             : }
     865             : 
     866             : NS_IMETHODIMP
     867           0 : nsTreeContentView::SetCellText(int32_t aRow, nsITreeColumn* aCol, const nsAString& aValue)
     868             : {
     869           0 :   RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
     870           0 :   NS_ENSURE_ARG(col);
     871             : 
     872           0 :   ErrorResult rv;
     873           0 :   SetCellText(aRow, *col, aValue, rv);
     874           0 :   return rv.StealNSResult();
     875             : }
     876             : 
     877             : NS_IMETHODIMP
     878           0 : nsTreeContentView::PerformAction(const char16_t* aAction)
     879             : {
     880           0 :   return NS_OK;
     881             : }
     882             : 
     883             : NS_IMETHODIMP
     884           0 : nsTreeContentView::PerformActionOnRow(const char16_t* aAction, int32_t aRow)
     885             : {
     886           0 :   return NS_OK;
     887             : }
     888             : 
     889             : NS_IMETHODIMP
     890           0 : nsTreeContentView::PerformActionOnCell(const char16_t* aAction, int32_t aRow, nsITreeColumn* aCol)
     891             : {
     892           0 :   return NS_OK;
     893             : }
     894             : 
     895             : Element*
     896           0 : nsTreeContentView::GetItemAtIndex(int32_t aIndex, ErrorResult& aError)
     897             : {
     898           0 :   if (!IsValidRowIndex(aIndex)) {
     899           0 :     aError.Throw(NS_ERROR_INVALID_ARG);
     900           0 :     return nullptr;
     901             :   }
     902             : 
     903           0 :   return mRows[aIndex]->mContent;
     904             : }
     905             : 
     906             : NS_IMETHODIMP
     907           0 : nsTreeContentView::GetItemAtIndex(int32_t aIndex, nsIDOMElement** _retval)
     908             : {
     909           0 :   ErrorResult rv;
     910           0 :   Element* element = GetItemAtIndex(aIndex, rv);
     911           0 :   if (rv.Failed()) {
     912           0 :     return rv.StealNSResult();
     913             :   }
     914             : 
     915           0 :   if (!element) {
     916           0 :     *_retval = nullptr;
     917           0 :     return NS_OK;
     918             :   }
     919             : 
     920           0 :   return CallQueryInterface(element, _retval);
     921             : }
     922             : 
     923             : int32_t
     924           0 : nsTreeContentView::GetIndexOfItem(Element* aItem)
     925             : {
     926           0 :   return FindContent(aItem);
     927             : }
     928             : 
     929             : NS_IMETHODIMP
     930           0 : nsTreeContentView::GetIndexOfItem(nsIDOMElement* aItem, int32_t* _retval)
     931             : {
     932           0 :   nsCOMPtr<Element> element = do_QueryInterface(aItem);
     933             : 
     934           0 :   *_retval = GetIndexOfItem(element);
     935             : 
     936           0 :   return NS_OK;
     937             : }
     938             : 
     939             : void
     940           0 : nsTreeContentView::AttributeChanged(nsIDocument*  aDocument,
     941             :                                     dom::Element* aElement,
     942             :                                     int32_t       aNameSpaceID,
     943             :                                     nsIAtom*      aAttribute,
     944             :                                     int32_t       aModType,
     945             :                                     const nsAttrValue* aOldValue)
     946             : {
     947             :   // Lots of codepaths under here that do all sorts of stuff, so be safe.
     948           0 :   nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
     949             : 
     950             :   // Make sure this notification concerns us.
     951             :   // First check the tag to see if it's one that we care about.
     952             : 
     953           0 :   if (mBoxObject && (aElement == mRoot || aElement == mBody)) {
     954           0 :     mBoxObject->ClearStyleAndImageCaches();
     955           0 :     mBoxObject->Invalidate();
     956             :   }
     957             : 
     958             :   // We don't consider non-XUL nodes.
     959           0 :   nsIContent* parent = nullptr;
     960           0 :   if (!aElement->IsXULElement() ||
     961           0 :       ((parent = aElement->GetParent()) && !parent->IsXULElement())) {
     962           0 :     return;
     963             :   }
     964           0 :   if (!aElement->IsAnyOfXULElements(nsGkAtoms::treecol,
     965             :                                     nsGkAtoms::treeitem,
     966             :                                     nsGkAtoms::treeseparator,
     967             :                                     nsGkAtoms::treerow,
     968             :                                     nsGkAtoms::treecell)) {
     969           0 :     return;
     970             :   }
     971             : 
     972             :   // If we have a legal tag, go up to the tree/select and make sure
     973             :   // that it's ours.
     974             : 
     975           0 :   for (nsIContent* element = aElement; element != mBody; element = element->GetParent()) {
     976           0 :     if (!element)
     977           0 :       return; // this is not for us
     978           0 :     if (element->IsXULElement(nsGkAtoms::tree))
     979           0 :       return; // this is not for us
     980             :   }
     981             : 
     982             :   // Handle changes of the hidden attribute.
     983           0 :   if (aAttribute == nsGkAtoms::hidden &&
     984           0 :       aElement->IsAnyOfXULElements(nsGkAtoms::treeitem,
     985             :                                    nsGkAtoms::treeseparator)) {
     986           0 :     bool hidden = aElement->AttrValueIs(kNameSpaceID_None,
     987             :                                           nsGkAtoms::hidden,
     988           0 :                                           nsGkAtoms::_true, eCaseMatters);
     989             : 
     990           0 :     int32_t index = FindContent(aElement);
     991           0 :     if (hidden && index >= 0) {
     992             :       // Hide this row along with its children.
     993           0 :       int32_t count = RemoveRow(index);
     994           0 :       if (mBoxObject)
     995           0 :         mBoxObject->RowCountChanged(index, -count);
     996             :     }
     997           0 :     else if (!hidden && index < 0) {
     998             :       // Show this row along with its children.
     999           0 :       nsCOMPtr<nsIContent> parent = aElement->GetParent();
    1000           0 :       if (parent) {
    1001           0 :         InsertRowFor(parent, aElement);
    1002             :       }
    1003             :     }
    1004             : 
    1005           0 :     return;
    1006             :   }
    1007             : 
    1008           0 :   if (aElement->IsXULElement(nsGkAtoms::treecol)) {
    1009           0 :     if (aAttribute == nsGkAtoms::properties) {
    1010           0 :       if (mBoxObject) {
    1011           0 :         nsCOMPtr<nsITreeColumns> cols;
    1012           0 :         mBoxObject->GetColumns(getter_AddRefs(cols));
    1013           0 :         if (cols) {
    1014           0 :           nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aElement);
    1015           0 :           nsCOMPtr<nsITreeColumn> col;
    1016           0 :           cols->GetColumnFor(element, getter_AddRefs(col));
    1017           0 :           mBoxObject->InvalidateColumn(col);
    1018             :         }
    1019             :       }
    1020             :     }
    1021             :   }
    1022           0 :   else if (aElement->IsXULElement(nsGkAtoms::treeitem)) {
    1023           0 :     int32_t index = FindContent(aElement);
    1024           0 :     if (index >= 0) {
    1025           0 :       Row* row = mRows[index].get();
    1026           0 :       if (aAttribute == nsGkAtoms::container) {
    1027             :         bool isContainer =
    1028           0 :           aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::container,
    1029           0 :                                 nsGkAtoms::_true, eCaseMatters);
    1030           0 :         row->SetContainer(isContainer);
    1031           0 :         if (mBoxObject)
    1032           0 :           mBoxObject->InvalidateRow(index);
    1033             :       }
    1034           0 :       else if (aAttribute == nsGkAtoms::open) {
    1035             :         bool isOpen =
    1036           0 :           aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::open,
    1037           0 :                                 nsGkAtoms::_true, eCaseMatters);
    1038           0 :         bool wasOpen = row->IsOpen();
    1039           0 :         if (! isOpen && wasOpen)
    1040           0 :           CloseContainer(index);
    1041           0 :         else if (isOpen && ! wasOpen)
    1042           0 :           OpenContainer(index);
    1043             :       }
    1044           0 :       else if (aAttribute == nsGkAtoms::empty) {
    1045             :         bool isEmpty =
    1046           0 :           aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::empty,
    1047           0 :                                 nsGkAtoms::_true, eCaseMatters);
    1048           0 :         row->SetEmpty(isEmpty);
    1049           0 :         if (mBoxObject)
    1050           0 :           mBoxObject->InvalidateRow(index);
    1051             :       }
    1052             :     }
    1053             :   }
    1054           0 :   else if (aElement->IsXULElement(nsGkAtoms::treeseparator)) {
    1055           0 :     int32_t index = FindContent(aElement);
    1056           0 :     if (index >= 0) {
    1057           0 :       if (aAttribute == nsGkAtoms::properties && mBoxObject) {
    1058           0 :         mBoxObject->InvalidateRow(index);
    1059             :       }
    1060             :     }
    1061             :   }
    1062           0 :   else if (aElement->IsXULElement(nsGkAtoms::treerow)) {
    1063           0 :     if (aAttribute == nsGkAtoms::properties) {
    1064           0 :       nsCOMPtr<nsIContent> parent = aElement->GetParent();
    1065           0 :       if (parent) {
    1066           0 :         int32_t index = FindContent(parent);
    1067           0 :         if (index >= 0 && mBoxObject) {
    1068           0 :           mBoxObject->InvalidateRow(index);
    1069             :         }
    1070             :       }
    1071             :     }
    1072             :   }
    1073           0 :   else if (aElement->IsXULElement(nsGkAtoms::treecell)) {
    1074           0 :     if (aAttribute == nsGkAtoms::ref ||
    1075           0 :         aAttribute == nsGkAtoms::properties ||
    1076           0 :         aAttribute == nsGkAtoms::mode ||
    1077           0 :         aAttribute == nsGkAtoms::src ||
    1078           0 :         aAttribute == nsGkAtoms::value ||
    1079           0 :         aAttribute == nsGkAtoms::label) {
    1080           0 :       nsIContent* parent = aElement->GetParent();
    1081           0 :       if (parent) {
    1082           0 :         nsCOMPtr<nsIContent> grandParent = parent->GetParent();
    1083           0 :         if (grandParent && grandParent->IsXULElement()) {
    1084           0 :           int32_t index = FindContent(grandParent);
    1085           0 :           if (index >= 0 && mBoxObject) {
    1086             :             // XXX Should we make an effort to invalidate only cell ?
    1087           0 :             mBoxObject->InvalidateRow(index);
    1088             :           }
    1089             :         }
    1090             :       }
    1091             :     }
    1092             :   }
    1093             : }
    1094             : 
    1095             : void
    1096           0 : nsTreeContentView::ContentAppended(nsIDocument *aDocument,
    1097             :                                    nsIContent* aContainer,
    1098             :                                    nsIContent* aFirstNewContent,
    1099             :                                    int32_t     /* unused */)
    1100             : {
    1101           0 :   for (nsIContent* cur = aFirstNewContent; cur; cur = cur->GetNextSibling()) {
    1102             :     // Our contentinserted doesn't use the index
    1103           0 :     ContentInserted(aDocument, aContainer, cur, 0);
    1104             :   }
    1105           0 : }
    1106             : 
    1107             : void
    1108           0 : nsTreeContentView::ContentInserted(nsIDocument *aDocument,
    1109             :                                    nsIContent* aContainer,
    1110             :                                    nsIContent* aChild,
    1111             :                                    int32_t /* unused */)
    1112             : {
    1113           0 :   NS_ASSERTION(aChild, "null ptr");
    1114             : 
    1115             :   // Make sure this notification concerns us.
    1116             :   // First check the tag to see if it's one that we care about.
    1117             : 
    1118             :   // Don't allow non-XUL nodes.
    1119           0 :   if (!aChild->IsXULElement() || !aContainer->IsXULElement())
    1120           0 :     return;
    1121             : 
    1122           0 :   if (!aChild->IsAnyOfXULElements(nsGkAtoms::treeitem,
    1123             :                                   nsGkAtoms::treeseparator,
    1124             :                                   nsGkAtoms::treechildren,
    1125             :                                   nsGkAtoms::treerow,
    1126             :                                   nsGkAtoms::treecell)) {
    1127           0 :     return;
    1128             :   }
    1129             : 
    1130             :   // If we have a legal tag, go up to the tree/select and make sure
    1131             :   // that it's ours.
    1132             : 
    1133           0 :   for (nsIContent* element = aContainer; element != mBody; element = element->GetParent()) {
    1134           0 :     if (!element)
    1135           0 :       return; // this is not for us
    1136           0 :     if (element->IsXULElement(nsGkAtoms::tree))
    1137           0 :       return; // this is not for us
    1138             :   }
    1139             : 
    1140             :   // Lots of codepaths under here that do all sorts of stuff, so be safe.
    1141           0 :   nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
    1142             : 
    1143           0 :   if (aChild->IsXULElement(nsGkAtoms::treechildren)) {
    1144           0 :     int32_t index = FindContent(aContainer);
    1145           0 :     if (index >= 0) {
    1146           0 :       Row* row = mRows[index].get();
    1147           0 :       row->SetEmpty(false);
    1148           0 :       if (mBoxObject)
    1149           0 :         mBoxObject->InvalidateRow(index);
    1150           0 :       if (row->IsContainer() && row->IsOpen()) {
    1151           0 :         int32_t count = EnsureSubtree(index);
    1152           0 :         if (mBoxObject)
    1153           0 :           mBoxObject->RowCountChanged(index + 1, count);
    1154             :       }
    1155             :     }
    1156             :   }
    1157           0 :   else if (aChild->IsAnyOfXULElements(nsGkAtoms::treeitem,
    1158             :                                       nsGkAtoms::treeseparator)) {
    1159           0 :     InsertRowFor(aContainer, aChild);
    1160             :   }
    1161           0 :   else if (aChild->IsXULElement(nsGkAtoms::treerow)) {
    1162           0 :     int32_t index = FindContent(aContainer);
    1163           0 :     if (index >= 0 && mBoxObject)
    1164           0 :       mBoxObject->InvalidateRow(index);
    1165             :   }
    1166           0 :   else if (aChild->IsXULElement(nsGkAtoms::treecell)) {
    1167           0 :     nsCOMPtr<nsIContent> parent = aContainer->GetParent();
    1168           0 :     if (parent) {
    1169           0 :       int32_t index = FindContent(parent);
    1170           0 :       if (index >= 0 && mBoxObject)
    1171           0 :         mBoxObject->InvalidateRow(index);
    1172             :     }
    1173             :   }
    1174             : }
    1175             : 
    1176             : void
    1177           0 : nsTreeContentView::ContentRemoved(nsIDocument *aDocument,
    1178             :                                   nsIContent* aContainer,
    1179             :                                   nsIContent* aChild,
    1180             :                                   int32_t aIndexInContainer,
    1181             :                                   nsIContent* aPreviousSibling)
    1182             : {
    1183           0 :   NS_ASSERTION(aChild, "null ptr");
    1184             : 
    1185             :   // Make sure this notification concerns us.
    1186             :   // First check the tag to see if it's one that we care about.
    1187             : 
    1188             :   // We don't consider non-XUL nodes.
    1189           0 :   if (!aChild->IsXULElement() || !aContainer->IsXULElement())
    1190           0 :     return;
    1191             : 
    1192           0 :   if (!aChild->IsAnyOfXULElements(nsGkAtoms::treeitem,
    1193             :                                   nsGkAtoms::treeseparator,
    1194             :                                   nsGkAtoms::treechildren,
    1195             :                                   nsGkAtoms::treerow,
    1196             :                                   nsGkAtoms::treecell)) {
    1197           0 :     return;
    1198             :   }
    1199             : 
    1200             :   // If we have a legal tag, go up to the tree/select and make sure
    1201             :   // that it's ours.
    1202             : 
    1203           0 :   for (nsIContent* element = aContainer; element != mBody; element = element->GetParent()) {
    1204           0 :     if (!element)
    1205           0 :       return; // this is not for us
    1206           0 :     if (element->IsXULElement(nsGkAtoms::tree))
    1207           0 :       return; // this is not for us
    1208             :   }
    1209             : 
    1210             :   // Lots of codepaths under here that do all sorts of stuff, so be safe.
    1211           0 :   nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
    1212             : 
    1213           0 :   if (aChild->IsXULElement(nsGkAtoms::treechildren)) {
    1214           0 :     int32_t index = FindContent(aContainer);
    1215           0 :     if (index >= 0) {
    1216           0 :       Row* row = mRows[index].get();
    1217           0 :       row->SetEmpty(true);
    1218           0 :       int32_t count = RemoveSubtree(index);
    1219             :       // Invalidate also the row to update twisty.
    1220           0 :       if (mBoxObject) {
    1221           0 :         mBoxObject->InvalidateRow(index);
    1222           0 :         mBoxObject->RowCountChanged(index + 1, -count);
    1223             :       }
    1224             :     }
    1225             :   }
    1226           0 :   else if (aChild->IsAnyOfXULElements(nsGkAtoms::treeitem,
    1227             :                                       nsGkAtoms::treeseparator)) {
    1228           0 :     int32_t index = FindContent(aChild);
    1229           0 :     if (index >= 0) {
    1230           0 :       int32_t count = RemoveRow(index);
    1231           0 :       if (mBoxObject)
    1232           0 :         mBoxObject->RowCountChanged(index, -count);
    1233             :     }
    1234             :   }
    1235           0 :   else if (aChild->IsXULElement(nsGkAtoms::treerow)) {
    1236           0 :     int32_t index = FindContent(aContainer);
    1237           0 :     if (index >= 0 && mBoxObject)
    1238           0 :       mBoxObject->InvalidateRow(index);
    1239             :   }
    1240           0 :   else if (aChild->IsXULElement(nsGkAtoms::treecell)) {
    1241           0 :     nsCOMPtr<nsIContent> parent = aContainer->GetParent();
    1242           0 :     if (parent) {
    1243           0 :       int32_t index = FindContent(parent);
    1244           0 :       if (index >= 0 && mBoxObject)
    1245           0 :         mBoxObject->InvalidateRow(index);
    1246             :     }
    1247             :   }
    1248             : }
    1249             : 
    1250             : void
    1251           0 : nsTreeContentView::NodeWillBeDestroyed(const nsINode* aNode)
    1252             : {
    1253             :   // XXXbz do we need this strong ref?  Do we drop refs to self in ClearRows?
    1254           0 :   nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
    1255           0 :   ClearRows();
    1256           0 : }
    1257             : 
    1258             : 
    1259             : // Recursively serialize content, starting with aContent.
    1260             : void
    1261           0 : nsTreeContentView::Serialize(nsIContent* aContent, int32_t aParentIndex,
    1262             :                              int32_t* aIndex, nsTArray<UniquePtr<Row>>& aRows)
    1263             : {
    1264             :   // Don't allow non-XUL nodes.
    1265           0 :   if (!aContent->IsXULElement())
    1266           0 :     return;
    1267             : 
    1268           0 :   dom::FlattenedChildIterator iter(aContent);
    1269           0 :   for (nsIContent* content = iter.GetNextChild(); content; content = iter.GetNextChild()) {
    1270           0 :     int32_t count = aRows.Length();
    1271             : 
    1272           0 :     if (content->IsXULElement(nsGkAtoms::treeitem)) {
    1273           0 :       SerializeItem(content->AsElement(), aParentIndex, aIndex, aRows);
    1274           0 :     } else if (content->IsXULElement(nsGkAtoms::treeseparator)) {
    1275           0 :       SerializeSeparator(content->AsElement(), aParentIndex, aIndex, aRows);
    1276             :     }
    1277             : 
    1278           0 :     *aIndex += aRows.Length() - count;
    1279             :   }
    1280             : }
    1281             : 
    1282             : void
    1283           0 : nsTreeContentView::SerializeItem(Element* aContent, int32_t aParentIndex,
    1284             :                                  int32_t* aIndex, nsTArray<UniquePtr<Row>>& aRows)
    1285             : {
    1286           0 :   if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidden,
    1287             :                             nsGkAtoms::_true, eCaseMatters))
    1288           0 :     return;
    1289             : 
    1290           0 :   aRows.AppendElement(MakeUnique<Row>(aContent, aParentIndex));
    1291           0 :   Row* row = aRows.LastElement().get();
    1292             : 
    1293           0 :   if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::container,
    1294             :                             nsGkAtoms::_true, eCaseMatters)) {
    1295           0 :     row->SetContainer(true);
    1296           0 :     if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::open,
    1297             :                               nsGkAtoms::_true, eCaseMatters)) {
    1298           0 :       row->SetOpen(true);
    1299             :       nsIContent* child =
    1300           0 :         nsTreeUtils::GetImmediateChild(aContent, nsGkAtoms::treechildren);
    1301           0 :       if (child && child->IsXULElement()) {
    1302             :         // Now, recursively serialize our child.
    1303           0 :         int32_t count = aRows.Length();
    1304           0 :         int32_t index = 0;
    1305           0 :         Serialize(child, aParentIndex + *aIndex + 1, &index, aRows);
    1306           0 :         row->mSubtreeSize += aRows.Length() - count;
    1307             :       }
    1308             :       else
    1309           0 :         row->SetEmpty(true);
    1310           0 :     } else if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::empty,
    1311             :                                      nsGkAtoms::_true, eCaseMatters)) {
    1312           0 :       row->SetEmpty(true);
    1313             :     }
    1314             :   }
    1315             : }
    1316             : 
    1317             : void
    1318           0 : nsTreeContentView::SerializeSeparator(Element* aContent,
    1319             :                                       int32_t aParentIndex, int32_t* aIndex,
    1320             :                                       nsTArray<UniquePtr<Row>>& aRows)
    1321             : {
    1322           0 :   if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidden,
    1323             :                             nsGkAtoms::_true, eCaseMatters))
    1324           0 :     return;
    1325             : 
    1326           0 :   auto row = MakeUnique<Row>(aContent, aParentIndex);
    1327           0 :   row->SetSeparator(true);
    1328           0 :   aRows.AppendElement(Move(row));
    1329             : }
    1330             : 
    1331             : void
    1332           0 : nsTreeContentView::GetIndexInSubtree(nsIContent* aContainer,
    1333             :                                      nsIContent* aContent, int32_t* aIndex)
    1334             : {
    1335           0 :   uint32_t childCount = aContainer->GetChildCount();
    1336             : 
    1337           0 :   if (!aContainer->IsXULElement())
    1338           0 :     return;
    1339             : 
    1340           0 :   for (uint32_t i = 0; i < childCount; i++) {
    1341           0 :     nsIContent *content = aContainer->GetChildAt(i);
    1342             : 
    1343           0 :     if (content == aContent)
    1344           0 :       break;
    1345             : 
    1346           0 :     if (content->IsXULElement(nsGkAtoms::treeitem)) {
    1347           0 :       if (! content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidden,
    1348             :                                  nsGkAtoms::_true, eCaseMatters)) {
    1349           0 :         (*aIndex)++;
    1350           0 :         if (content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::container,
    1351           0 :                                  nsGkAtoms::_true, eCaseMatters) &&
    1352           0 :             content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::open,
    1353             :                                  nsGkAtoms::_true, eCaseMatters)) {
    1354             :           nsIContent* child =
    1355           0 :             nsTreeUtils::GetImmediateChild(content, nsGkAtoms::treechildren);
    1356           0 :           if (child && child->IsXULElement())
    1357           0 :             GetIndexInSubtree(child, aContent, aIndex);
    1358             :         }
    1359             :       }
    1360             :     }
    1361           0 :     else if (content->IsXULElement(nsGkAtoms::treeseparator)) {
    1362           0 :       if (! content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidden,
    1363             :                                  nsGkAtoms::_true, eCaseMatters))
    1364           0 :         (*aIndex)++;
    1365             :     }
    1366             :   }
    1367             : }
    1368             : 
    1369             : int32_t
    1370           0 : nsTreeContentView::EnsureSubtree(int32_t aIndex)
    1371             : {
    1372           0 :   Row* row = mRows[aIndex].get();
    1373             : 
    1374             :   nsIContent* child;
    1375           0 :   child = nsTreeUtils::GetImmediateChild(row->mContent, nsGkAtoms::treechildren);
    1376           0 :   if (!child || !child->IsXULElement()) {
    1377           0 :     return 0;
    1378             :   }
    1379             : 
    1380           0 :   AutoTArray<UniquePtr<Row>, 8> rows;
    1381           0 :   int32_t index = 0;
    1382           0 :   Serialize(child, aIndex, &index, rows);
    1383             :   // Insert |rows| into |mRows| at position |aIndex|, by first creating empty
    1384             :   // UniquePtr entries and then Move'ing |rows|'s entries into them. (Note
    1385             :   // that we can't simply use InsertElementsAt with an array argument, since
    1386             :   // the destination can't steal ownership from its const source argument.)
    1387           0 :   UniquePtr<Row>* newRows = mRows.InsertElementsAt(aIndex + 1,
    1388           0 :                                                    rows.Length());
    1389           0 :   for (nsTArray<Row>::index_type i = 0; i < rows.Length(); i++) {
    1390           0 :     newRows[i] = Move(rows[i]);
    1391             :   }
    1392           0 :   int32_t count = rows.Length();
    1393             : 
    1394           0 :   row->mSubtreeSize += count;
    1395           0 :   UpdateSubtreeSizes(row->mParentIndex, count);
    1396             : 
    1397             :   // Update parent indexes, but skip newly added rows.
    1398             :   // They already have correct values.
    1399           0 :   UpdateParentIndexes(aIndex, count + 1, count);
    1400             : 
    1401           0 :   return count;
    1402             : }
    1403             : 
    1404             : int32_t
    1405           0 : nsTreeContentView::RemoveSubtree(int32_t aIndex)
    1406             : {
    1407           0 :   Row* row = mRows[aIndex].get();
    1408           0 :   int32_t count = row->mSubtreeSize;
    1409             : 
    1410           0 :   mRows.RemoveElementsAt(aIndex + 1, count);
    1411             : 
    1412           0 :   row->mSubtreeSize -= count;
    1413           0 :   UpdateSubtreeSizes(row->mParentIndex, -count);
    1414             : 
    1415           0 :   UpdateParentIndexes(aIndex, 0, -count);
    1416             : 
    1417           0 :   return count;
    1418             : }
    1419             : 
    1420             : void
    1421           0 : nsTreeContentView::InsertRowFor(nsIContent* aParent, nsIContent* aChild)
    1422             : {
    1423           0 :   int32_t grandParentIndex = -1;
    1424           0 :   bool insertRow = false;
    1425             : 
    1426           0 :   nsCOMPtr<nsIContent> grandParent = aParent->GetParent();
    1427             : 
    1428           0 :   if (grandParent->IsXULElement(nsGkAtoms::tree)) {
    1429             :     // Allow insertion to the outermost container.
    1430           0 :     insertRow = true;
    1431             :   }
    1432             :   else {
    1433             :     // Test insertion to an inner container.
    1434             : 
    1435             :     // First try to find this parent in our array of rows, if we find one
    1436             :     // we can be sure that all other parents are open too.
    1437           0 :     grandParentIndex = FindContent(grandParent);
    1438           0 :     if (grandParentIndex >= 0) {
    1439             :       // Got it, now test if it is open.
    1440           0 :       if (mRows[grandParentIndex]->IsOpen())
    1441           0 :         insertRow = true;
    1442             :     }
    1443             :   }
    1444             : 
    1445           0 :   if (insertRow) {
    1446           0 :     int32_t index = 0;
    1447           0 :     GetIndexInSubtree(aParent, aChild, &index);
    1448             : 
    1449           0 :     int32_t count = InsertRow(grandParentIndex, index, aChild);
    1450           0 :     if (mBoxObject)
    1451           0 :       mBoxObject->RowCountChanged(grandParentIndex + index + 1, count);
    1452             :   }
    1453           0 : }
    1454             : 
    1455             : int32_t
    1456           0 : nsTreeContentView::InsertRow(int32_t aParentIndex, int32_t aIndex, nsIContent* aContent)
    1457             : {
    1458           0 :   AutoTArray<UniquePtr<Row>, 8> rows;
    1459           0 :   if (aContent->IsXULElement(nsGkAtoms::treeitem)) {
    1460           0 :     SerializeItem(aContent->AsElement(), aParentIndex, &aIndex, rows);
    1461           0 :   } else if (aContent->IsXULElement(nsGkAtoms::treeseparator)) {
    1462           0 :     SerializeSeparator(aContent->AsElement(), aParentIndex, &aIndex, rows);
    1463             :   }
    1464             : 
    1465             :   // We can't use InsertElementsAt since the destination can't steal
    1466             :   // ownership from its const source argument.
    1467           0 :   int32_t count = rows.Length();
    1468           0 :   for (nsTArray<Row>::index_type i = 0; i < size_t(count); i++) {
    1469           0 :     mRows.InsertElementAt(aParentIndex + aIndex + i + 1, Move(rows[i]));
    1470             :   }
    1471             : 
    1472           0 :   UpdateSubtreeSizes(aParentIndex, count);
    1473             : 
    1474             :   // Update parent indexes, but skip added rows.
    1475             :   // They already have correct values.
    1476           0 :   UpdateParentIndexes(aParentIndex + aIndex, count + 1, count);
    1477             : 
    1478           0 :   return count;
    1479             : }
    1480             : 
    1481             : int32_t
    1482           0 : nsTreeContentView::RemoveRow(int32_t aIndex)
    1483             : {
    1484           0 :   Row* row = mRows[aIndex].get();
    1485           0 :   int32_t count = row->mSubtreeSize + 1;
    1486           0 :   int32_t parentIndex = row->mParentIndex;
    1487             : 
    1488           0 :   mRows.RemoveElementsAt(aIndex, count);
    1489             : 
    1490           0 :   UpdateSubtreeSizes(parentIndex, -count);
    1491             : 
    1492           0 :   UpdateParentIndexes(aIndex, 0, -count);
    1493             : 
    1494           0 :   return count;
    1495             : }
    1496             : 
    1497             : void
    1498           0 : nsTreeContentView::ClearRows()
    1499             : {
    1500           0 :   mRows.Clear();
    1501           0 :   mRoot = nullptr;
    1502           0 :   mBody = nullptr;
    1503             :   // Remove ourselves from mDocument's observers.
    1504           0 :   if (mDocument) {
    1505           0 :     mDocument->RemoveObserver(this);
    1506           0 :     mDocument = nullptr;
    1507             :   }
    1508           0 : }
    1509             : 
    1510             : void
    1511           0 : nsTreeContentView::OpenContainer(int32_t aIndex)
    1512             : {
    1513           0 :   Row* row = mRows[aIndex].get();
    1514           0 :   row->SetOpen(true);
    1515             : 
    1516           0 :   int32_t count = EnsureSubtree(aIndex);
    1517           0 :   if (mBoxObject) {
    1518           0 :     mBoxObject->InvalidateRow(aIndex);
    1519           0 :     mBoxObject->RowCountChanged(aIndex + 1, count);
    1520             :   }
    1521           0 : }
    1522             : 
    1523             : void
    1524           0 : nsTreeContentView::CloseContainer(int32_t aIndex)
    1525             : {
    1526           0 :   Row* row = mRows[aIndex].get();
    1527           0 :   row->SetOpen(false);
    1528             : 
    1529           0 :   int32_t count = RemoveSubtree(aIndex);
    1530           0 :   if (mBoxObject) {
    1531           0 :     mBoxObject->InvalidateRow(aIndex);
    1532           0 :     mBoxObject->RowCountChanged(aIndex + 1, -count);
    1533             :   }
    1534           0 : }
    1535             : 
    1536             : int32_t
    1537           0 : nsTreeContentView::FindContent(nsIContent* aContent)
    1538             : {
    1539           0 :   for (uint32_t i = 0; i < mRows.Length(); i++) {
    1540           0 :     if (mRows[i]->mContent == aContent) {
    1541           0 :       return i;
    1542             :     }
    1543             :   }
    1544             : 
    1545           0 :   return -1;
    1546             : }
    1547             : 
    1548             : void
    1549           0 : nsTreeContentView::UpdateSubtreeSizes(int32_t aParentIndex, int32_t count)
    1550             : {
    1551           0 :   while (aParentIndex >= 0) {
    1552           0 :     Row* row = mRows[aParentIndex].get();
    1553           0 :     row->mSubtreeSize += count;
    1554           0 :     aParentIndex = row->mParentIndex;
    1555             :   }
    1556           0 : }
    1557             : 
    1558             : void
    1559           0 : nsTreeContentView::UpdateParentIndexes(int32_t aIndex, int32_t aSkip, int32_t aCount)
    1560             : {
    1561           0 :   int32_t count = mRows.Length();
    1562           0 :   for (int32_t i = aIndex + aSkip; i < count; i++) {
    1563           0 :     Row* row = mRows[i].get();
    1564           0 :     if (row->mParentIndex > aIndex) {
    1565           0 :       row->mParentIndex += aCount;
    1566             :     }
    1567             :   }
    1568           0 : }
    1569             : 
    1570             : nsIContent*
    1571           0 : nsTreeContentView::GetCell(nsIContent* aContainer, nsTreeColumn& aCol)
    1572             : {
    1573           0 :   nsCOMPtr<nsIAtom> colAtom(aCol.GetAtom());
    1574           0 :   int32_t colIndex(aCol.GetIndex());
    1575             : 
    1576             :   // Traverse through cells, try to find the cell by "ref" attribute or by cell
    1577             :   // index in a row. "ref" attribute has higher priority.
    1578           0 :   nsIContent* result = nullptr;
    1579           0 :   int32_t j = 0;
    1580           0 :   dom::FlattenedChildIterator iter(aContainer);
    1581           0 :   for (nsIContent* cell = iter.GetNextChild(); cell; cell = iter.GetNextChild()) {
    1582           0 :     if (cell->IsXULElement(nsGkAtoms::treecell)) {
    1583           0 :       if (colAtom && cell->AttrValueIs(kNameSpaceID_None, nsGkAtoms::ref,
    1584           0 :                                        colAtom, eCaseMatters)) {
    1585           0 :         result = cell;
    1586           0 :         break;
    1587             :       }
    1588           0 :       else if (j == colIndex) {
    1589           0 :         result = cell;
    1590             :       }
    1591           0 :       j++;
    1592             :     }
    1593             :   }
    1594             : 
    1595           0 :   return result;
    1596             : }
    1597             : 
    1598             : bool
    1599           0 : nsTreeContentView::IsValidRowIndex(int32_t aRowIndex)
    1600             : {
    1601           0 :   return aRowIndex >= 0 && aRowIndex < int32_t(mRows.Length());
    1602             : }

Generated by: LCOV version 1.13