accessible/src/xul/XULTreeAccessible.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 et sw=2 tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "XULTreeAccessible.h"
     9 #include "Accessible-inl.h"
    10 #include "DocAccessible-inl.h"
    11 #include "nsAccCache.h"
    12 #include "nsAccUtils.h"
    13 #include "nsCoreUtils.h"
    14 #include "nsEventShell.h"
    15 #include "DocAccessible.h"
    16 #include "Relation.h"
    17 #include "Role.h"
    18 #include "States.h"
    20 #include "nsComponentManagerUtils.h"
    21 #include "nsIAccessibleRelation.h"
    22 #include "nsIAutoCompleteInput.h"
    23 #include "nsIAutoCompletePopup.h"
    24 #include "nsIBoxObject.h"
    25 #include "nsIDOMXULElement.h"
    26 #include "nsIDOMXULMenuListElement.h"
    27 #include "nsIDOMXULMultSelectCntrlEl.h"
    28 #include "nsIDOMXULTreeElement.h"
    29 #include "nsITreeSelection.h"
    30 #include "nsIMutableArray.h"
    31 #include "nsTreeBodyFrame.h"
    32 #include "nsTreeColumns.h"
    33 #include "nsTreeUtils.h"
    35 using namespace mozilla::a11y;
    37 ////////////////////////////////////////////////////////////////////////////////
    38 // XULTreeAccessible
    39 ////////////////////////////////////////////////////////////////////////////////
    41 XULTreeAccessible::
    42   XULTreeAccessible(nsIContent* aContent, DocAccessible* aDoc,
    43                     nsTreeBodyFrame* aTreeFrame) :
    44   AccessibleWrap(aContent, aDoc),
    45   mAccessibleCache(kDefaultTreeCacheSize)
    46 {
    47   mType = eXULTreeType;
    48   mGenericTypes |= eSelect;
    50   nsCOMPtr<nsITreeView> view = aTreeFrame->GetExistingView();
    51   mTreeView = view;
    53   mTree = nsCoreUtils::GetTreeBoxObject(aContent);
    54   NS_ASSERTION(mTree, "Can't get mTree!\n");
    56   nsIContent* parentContent = mContent->GetParent();
    57   if (parentContent) {
    58     nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
    59       do_QueryInterface(parentContent);
    60     if (autoCompletePopupElm)
    61       mGenericTypes |= eAutoCompletePopup;
    62   }
    63 }
    65 ////////////////////////////////////////////////////////////////////////////////
    66 // XULTreeAccessible: nsISupports and cycle collection implementation
    68 NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeAccessible, Accessible,
    69                                    mTree, mAccessibleCache)
    71 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(XULTreeAccessible)
    72 NS_INTERFACE_MAP_END_INHERITING(Accessible)
    74 NS_IMPL_ADDREF_INHERITED(XULTreeAccessible, Accessible)
    75 NS_IMPL_RELEASE_INHERITED(XULTreeAccessible, Accessible)
    77 ////////////////////////////////////////////////////////////////////////////////
    78 // XULTreeAccessible: Accessible implementation
    80 uint64_t
    81 XULTreeAccessible::NativeState()
    82 {
    83   // Get focus status from base class.
    84   uint64_t state = Accessible::NativeState();
    86   // readonly state
    87   state |= states::READONLY;
    89   // multiselectable state.
    90   if (!mTreeView)
    91     return state;
    93   nsCOMPtr<nsITreeSelection> selection;
    94   mTreeView->GetSelection(getter_AddRefs(selection));
    95   NS_ENSURE_TRUE(selection, state);
    97   bool isSingle = false;
    98   nsresult rv = selection->GetSingle(&isSingle);
    99   NS_ENSURE_SUCCESS(rv, state);
   101   if (!isSingle)
   102     state |= states::MULTISELECTABLE;
   104   return state;
   105 }
   107 void
   108 XULTreeAccessible::Value(nsString& aValue)
   109 {
   110   aValue.Truncate();
   111   if (!mTreeView)
   112     return;
   114   // Return the value is the first selected child.
   115   nsCOMPtr<nsITreeSelection> selection;
   116   mTreeView->GetSelection(getter_AddRefs(selection));
   117   if (!selection)
   118     return;
   120   int32_t currentIndex;
   121   nsCOMPtr<nsIDOMElement> selectItem;
   122   selection->GetCurrentIndex(&currentIndex);
   123   if (currentIndex >= 0) {
   124     nsCOMPtr<nsITreeColumn> keyCol;
   126     nsCOMPtr<nsITreeColumns> cols;
   127     mTree->GetColumns(getter_AddRefs(cols));
   128     if (cols)
   129       cols->GetKeyColumn(getter_AddRefs(keyCol));
   131     mTreeView->GetCellText(currentIndex, keyCol, aValue);
   132   }
   134 }
   136 ////////////////////////////////////////////////////////////////////////////////
   137 // XULTreeAccessible: Accessible implementation
   139 void
   140 XULTreeAccessible::Shutdown()
   141 {
   142   // XXX: we don't remove accessible from document cache if shutdown wasn't
   143   // initiated by document destroying. Note, we can't remove accessible from
   144   // document cache here while document is going to be shutdown. Note, this is
   145   // not unique place where we have similar problem.
   146   ClearCache(mAccessibleCache);
   148   mTree = nullptr;
   149   mTreeView = nullptr;
   151   AccessibleWrap::Shutdown();
   152 }
   154 role
   155 XULTreeAccessible::NativeRole()
   156 {
   157   // No primary column means we're in a list. In fact, history and mail turn off
   158   // the primary flag when switching to a flat view.
   160   nsIContent* child = nsTreeUtils::GetDescendantChild(mContent, nsGkAtoms::treechildren);
   161   NS_ASSERTION(child, "tree without treechildren!");
   162   nsTreeBodyFrame* treeFrame = do_QueryFrame(child->GetPrimaryFrame());
   163   NS_ASSERTION(treeFrame, "xul tree accessible for tree without a frame!");
   164   if (!treeFrame)
   165     return roles::LIST;
   167   nsRefPtr<nsTreeColumns> cols = treeFrame->Columns();
   168   nsCOMPtr<nsITreeColumn> primaryCol;
   169   cols->GetPrimaryColumn(getter_AddRefs(primaryCol));
   171   return primaryCol ? roles::OUTLINE : roles::LIST;
   172 }
   174 ////////////////////////////////////////////////////////////////////////////////
   175 // XULTreeAccessible: Accessible implementation (DON'T put methods here)
   177 Accessible*
   178 XULTreeAccessible::ChildAtPoint(int32_t aX, int32_t aY,
   179                                 EWhichChildAtPoint aWhichChild)
   180 {
   181   nsIFrame *frame = GetFrame();
   182   if (!frame)
   183     return nullptr;
   185   nsPresContext *presContext = frame->PresContext();
   186   nsIPresShell* presShell = presContext->PresShell();
   188   nsIFrame *rootFrame = presShell->GetRootFrame();
   189   NS_ENSURE_TRUE(rootFrame, nullptr);
   191   nsIntRect rootRect = rootFrame->GetScreenRect();
   193   int32_t clientX = presContext->DevPixelsToIntCSSPixels(aX) - rootRect.x;
   194   int32_t clientY = presContext->DevPixelsToIntCSSPixels(aY) - rootRect.y;
   196   int32_t row = -1;
   197   nsCOMPtr<nsITreeColumn> column;
   198   nsAutoCString childEltUnused;
   199   mTree->GetCellAt(clientX, clientY, &row, getter_AddRefs(column),
   200                    childEltUnused);
   202   // If we failed to find tree cell for the given point then it might be
   203   // tree columns.
   204   if (row == -1 || !column)
   205     return AccessibleWrap::ChildAtPoint(aX, aY, aWhichChild);
   207   Accessible* child = GetTreeItemAccessible(row);
   208   if (aWhichChild == eDeepestChild && child) {
   209     // Look for accessible cell for the found item accessible.
   210     nsRefPtr<XULTreeItemAccessibleBase> treeitem = do_QueryObject(child);
   212     Accessible* cell = treeitem->GetCellAccessible(column);
   213     if (cell)
   214       child = cell;
   215   }
   217   return child;
   218 }
   220 ////////////////////////////////////////////////////////////////////////////////
   221 // XULTreeAccessible: SelectAccessible
   223 Accessible*
   224 XULTreeAccessible::CurrentItem()
   225 {
   226   if (!mTreeView)
   227     return nullptr;
   229   nsCOMPtr<nsITreeSelection> selection;
   230   mTreeView->GetSelection(getter_AddRefs(selection));
   231   if (selection) {
   232     int32_t currentIndex = -1;
   233     selection->GetCurrentIndex(&currentIndex);
   234     if (currentIndex >= 0)
   235       return GetTreeItemAccessible(currentIndex);
   236   }
   238   return nullptr;
   239 }
   241 void
   242 XULTreeAccessible::SetCurrentItem(Accessible* aItem)
   243 {
   244   NS_ERROR("XULTreeAccessible::SetCurrentItem not implemented");
   245 }
   247 already_AddRefed<nsIArray>
   248 XULTreeAccessible::SelectedItems()
   249 {
   250   if (!mTreeView)
   251     return nullptr;
   253   nsCOMPtr<nsITreeSelection> selection;
   254   mTreeView->GetSelection(getter_AddRefs(selection));
   255   if (!selection)
   256     return nullptr;
   258   nsCOMPtr<nsIMutableArray> selectedItems =
   259     do_CreateInstance(NS_ARRAY_CONTRACTID);
   260   if (!selectedItems)
   261     return nullptr;
   263   int32_t rangeCount = 0;
   264   selection->GetRangeCount(&rangeCount);
   265   for (int32_t rangeIdx = 0; rangeIdx < rangeCount; rangeIdx++) {
   266     int32_t firstIdx = 0, lastIdx = -1;
   267     selection->GetRangeAt(rangeIdx, &firstIdx, &lastIdx);
   268     for (int32_t rowIdx = firstIdx; rowIdx <= lastIdx; rowIdx++) {
   269       nsIAccessible* item = GetTreeItemAccessible(rowIdx);
   270       if (item)
   271         selectedItems->AppendElement(item, false);
   272     }
   273   }
   275   return selectedItems.forget();
   276 }
   278 uint32_t
   279 XULTreeAccessible::SelectedItemCount()
   280 {
   281   if (!mTreeView)
   282     return 0;
   284   nsCOMPtr<nsITreeSelection> selection;
   285   mTreeView->GetSelection(getter_AddRefs(selection));
   286   if (selection) {
   287     int32_t count = 0;
   288     selection->GetCount(&count);
   289     return count;
   290   }
   292   return 0;
   293 }
   295 bool
   296 XULTreeAccessible::AddItemToSelection(uint32_t aIndex)
   297 {
   298   if (!mTreeView)
   299     return false;
   301   nsCOMPtr<nsITreeSelection> selection;
   302   mTreeView->GetSelection(getter_AddRefs(selection));
   303   if (selection) {
   304     bool isSelected = false;
   305     selection->IsSelected(aIndex, &isSelected);
   306     if (!isSelected)
   307       selection->ToggleSelect(aIndex);
   309     return true;
   310   }
   311   return false;
   312 }
   314 bool
   315 XULTreeAccessible::RemoveItemFromSelection(uint32_t aIndex)
   316 {
   317   if (!mTreeView)
   318     return false;
   320   nsCOMPtr<nsITreeSelection> selection;
   321   mTreeView->GetSelection(getter_AddRefs(selection));
   322   if (selection) {
   323     bool isSelected = false;
   324     selection->IsSelected(aIndex, &isSelected);
   325     if (isSelected)
   326       selection->ToggleSelect(aIndex);
   328     return true;
   329   }
   330   return false;
   331 }
   333 bool
   334 XULTreeAccessible::IsItemSelected(uint32_t aIndex)
   335 {
   336   if (!mTreeView)
   337     return false;
   339   nsCOMPtr<nsITreeSelection> selection;
   340   mTreeView->GetSelection(getter_AddRefs(selection));
   341   if (selection) {
   342     bool isSelected = false;
   343     selection->IsSelected(aIndex, &isSelected);
   344     return isSelected;
   345   }
   346   return false;
   347 }
   349 bool
   350 XULTreeAccessible::UnselectAll()
   351 {
   352   if (!mTreeView)
   353     return false;
   355   nsCOMPtr<nsITreeSelection> selection;
   356   mTreeView->GetSelection(getter_AddRefs(selection));
   357   if (!selection)
   358     return false;
   360   selection->ClearSelection();
   361   return true;
   362 }
   364 Accessible*
   365 XULTreeAccessible::GetSelectedItem(uint32_t aIndex)
   366 {
   367   if (!mTreeView)
   368     return nullptr;
   370   nsCOMPtr<nsITreeSelection> selection;
   371   mTreeView->GetSelection(getter_AddRefs(selection));
   372   if (!selection)
   373     return nullptr;
   375   uint32_t selCount = 0;
   376   int32_t rangeCount = 0;
   377   selection->GetRangeCount(&rangeCount);
   378   for (int32_t rangeIdx = 0; rangeIdx < rangeCount; rangeIdx++) {
   379     int32_t firstIdx = 0, lastIdx = -1;
   380     selection->GetRangeAt(rangeIdx, &firstIdx, &lastIdx);
   381     for (int32_t rowIdx = firstIdx; rowIdx <= lastIdx; rowIdx++) {
   382       if (selCount == aIndex)
   383         return GetTreeItemAccessible(rowIdx);
   385       selCount++;
   386     }
   387   }
   389   return nullptr;
   390 }
   392 bool
   393 XULTreeAccessible::SelectAll()
   394 {
   395   // see if we are multiple select if so set ourselves as such
   396   if (!mTreeView)
   397     return false;
   399   nsCOMPtr<nsITreeSelection> selection;
   400   mTreeView->GetSelection(getter_AddRefs(selection));
   401   if (selection) {
   402     bool single = false;
   403     selection->GetSingle(&single);
   404     if (!single) {
   405       selection->SelectAll();
   406       return true;
   407     }
   408   }
   410   return false;
   411 }
   413 ////////////////////////////////////////////////////////////////////////////////
   414 // XULTreeAccessible: Accessible implementation
   416 Accessible*
   417 XULTreeAccessible::GetChildAt(uint32_t aIndex) const
   418 {
   419   uint32_t childCount = Accessible::ChildCount();
   420   if (aIndex < childCount)
   421     return Accessible::GetChildAt(aIndex);
   423   return GetTreeItemAccessible(aIndex - childCount);
   424 }
   426 uint32_t
   427 XULTreeAccessible::ChildCount() const
   428 {
   429   // Tree's children count is row count + treecols count.
   430   uint32_t childCount = Accessible::ChildCount();
   431   if (!mTreeView)
   432     return childCount;
   434   int32_t rowCount = 0;
   435   mTreeView->GetRowCount(&rowCount);
   436   childCount += rowCount;
   438   return childCount;
   439 }
   441 Relation
   442 XULTreeAccessible::RelationByType(RelationType aType)
   443 {
   444   if (aType == RelationType::NODE_PARENT_OF) {
   445     if (mTreeView)
   446       return Relation(new XULTreeItemIterator(this, mTreeView, -1));
   448     return Relation();
   449   }
   451   return Accessible::RelationByType(aType);
   452 }
   454 ////////////////////////////////////////////////////////////////////////////////
   455 // XULTreeAccessible: Widgets
   457 bool
   458 XULTreeAccessible::IsWidget() const
   459 {
   460   return true;
   461 }
   463 bool
   464 XULTreeAccessible::IsActiveWidget() const
   465 {
   466   if (IsAutoCompletePopup()) {
   467     nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
   468       do_QueryInterface(mContent->GetParent());
   470     if (autoCompletePopupElm) {
   471       bool isOpen = false;
   472       autoCompletePopupElm->GetPopupOpen(&isOpen);
   473       return isOpen;
   474     }
   475   }
   476   return FocusMgr()->HasDOMFocus(mContent);
   477 }
   479 bool
   480 XULTreeAccessible::AreItemsOperable() const
   481 {
   482   if (IsAutoCompletePopup()) {
   483     nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
   484       do_QueryInterface(mContent->GetParent());
   486     if (autoCompletePopupElm) {
   487       bool isOpen = false;
   488       autoCompletePopupElm->GetPopupOpen(&isOpen);
   489       return isOpen;
   490     }
   491   }
   492   return true;
   493 }
   495 Accessible*
   496 XULTreeAccessible::ContainerWidget() const
   497 {
   498   if (IsAutoCompletePopup()) {
   499     // This works for XUL autocompletes. It doesn't work for HTML forms
   500     // autocomplete because of potential crossprocess calls (when autocomplete
   501     // lives in content process while popup lives in chrome process). If that's
   502     // a problem then rethink Widgets interface.
   503     nsCOMPtr<nsIDOMXULMenuListElement> menuListElm =
   504       do_QueryInterface(mContent->GetParent());
   505     if (menuListElm) {
   506       nsCOMPtr<nsIDOMNode> inputElm;
   507       menuListElm->GetInputField(getter_AddRefs(inputElm));
   508       if (inputElm) {
   509         nsCOMPtr<nsINode> inputNode = do_QueryInterface(inputElm);
   510         if (inputNode) {
   511           Accessible* input = 
   512             mDoc->GetAccessible(inputNode);
   513           return input ? input->ContainerWidget() : nullptr;
   514         }
   515       }
   516     }
   517   }
   518   return nullptr;
   519 }
   521 ////////////////////////////////////////////////////////////////////////////////
   522 // XULTreeAccessible: public implementation
   524 Accessible*
   525 XULTreeAccessible::GetTreeItemAccessible(int32_t aRow) const
   526 {
   527   if (aRow < 0 || IsDefunct() || !mTreeView)
   528     return nullptr;
   530   int32_t rowCount = 0;
   531   nsresult rv = mTreeView->GetRowCount(&rowCount);
   532   if (NS_FAILED(rv) || aRow >= rowCount)
   533     return nullptr;
   535   void *key = reinterpret_cast<void*>(aRow);
   536   Accessible* cachedTreeItem = mAccessibleCache.GetWeak(key);
   537   if (cachedTreeItem)
   538     return cachedTreeItem;
   540   nsRefPtr<Accessible> treeItem = CreateTreeItemAccessible(aRow);
   541   if (treeItem) {
   542     mAccessibleCache.Put(key, treeItem);
   543     Document()->BindToDocument(treeItem, nullptr);
   544     return treeItem;
   545   }
   547   return nullptr;
   548 }
   550 void
   551 XULTreeAccessible::InvalidateCache(int32_t aRow, int32_t aCount)
   552 {
   553   if (IsDefunct())
   554     return;
   556   if (!mTreeView) {
   557     ClearCache(mAccessibleCache);
   558     return;
   559   }
   561   // Do not invalidate the cache if rows have been inserted.
   562   if (aCount > 0)
   563     return;
   565   DocAccessible* document = Document();
   567   // Fire destroy event for removed tree items and delete them from caches.
   568   for (int32_t rowIdx = aRow; rowIdx < aRow - aCount; rowIdx++) {
   570     void* key = reinterpret_cast<void*>(rowIdx);
   571     Accessible* treeItem = mAccessibleCache.GetWeak(key);
   573     if (treeItem) {
   574       nsRefPtr<AccEvent> event =
   575         new AccEvent(nsIAccessibleEvent::EVENT_HIDE, treeItem);
   576       nsEventShell::FireEvent(event);
   578       // Unbind from document, shutdown and remove from tree cache.
   579       document->UnbindFromDocument(treeItem);
   580       mAccessibleCache.Remove(key);
   581     }
   582   }
   584   // We dealt with removed tree items already however we may keep tree items
   585   // having row indexes greater than row count. We should remove these dead tree
   586   // items silently from caches.
   587   int32_t newRowCount = 0;
   588   nsresult rv = mTreeView->GetRowCount(&newRowCount);
   589   if (NS_FAILED(rv))
   590     return;
   592   int32_t oldRowCount = newRowCount - aCount;
   594   for (int32_t rowIdx = newRowCount; rowIdx < oldRowCount; ++rowIdx) {
   596     void *key = reinterpret_cast<void*>(rowIdx);
   597     Accessible* treeItem = mAccessibleCache.GetWeak(key);
   599     if (treeItem) {
   600       // Unbind from document, shutdown and remove from tree cache.
   601       document->UnbindFromDocument(treeItem);
   602       mAccessibleCache.Remove(key);
   603     }
   604   }
   605 }
   607 void
   608 XULTreeAccessible::TreeViewInvalidated(int32_t aStartRow, int32_t aEndRow,
   609                                        int32_t aStartCol, int32_t aEndCol)
   610 {
   611   if (IsDefunct())
   612     return;
   614   if (!mTreeView) {
   615     ClearCache(mAccessibleCache);
   616     return;
   617   }
   619   int32_t endRow = aEndRow;
   621   nsresult rv;
   622   if (endRow == -1) {
   623     int32_t rowCount = 0;
   624     rv = mTreeView->GetRowCount(&rowCount);
   625     if (NS_FAILED(rv))
   626       return;
   628     endRow = rowCount - 1;
   629   }
   631   nsCOMPtr<nsITreeColumns> treeColumns;
   632   mTree->GetColumns(getter_AddRefs(treeColumns));
   633   if (!treeColumns)
   634     return;
   636   int32_t endCol = aEndCol;
   638   if (endCol == -1) {
   639     int32_t colCount = 0;
   640     rv = treeColumns->GetCount(&colCount);
   641     if (NS_FAILED(rv))
   642       return;
   644     endCol = colCount - 1;
   645   }
   647   for (int32_t rowIdx = aStartRow; rowIdx <= endRow; ++rowIdx) {
   649     void *key = reinterpret_cast<void*>(rowIdx);
   650     Accessible* accessible = mAccessibleCache.GetWeak(key);
   652     if (accessible) {
   653       nsRefPtr<XULTreeItemAccessibleBase> treeitemAcc = do_QueryObject(accessible);
   654       NS_ASSERTION(treeitemAcc, "Wrong accessible at the given key!");
   656       treeitemAcc->RowInvalidated(aStartCol, endCol);
   657     }
   658   }
   659 }
   661 void
   662 XULTreeAccessible::TreeViewChanged(nsITreeView* aView)
   663 {
   664   if (IsDefunct())
   665     return;
   667   // Fire reorder event on tree accessible on accessible tree (do not fire
   668   // show/hide events on tree items because it can be expensive to fire them for
   669   // each tree item.
   670   nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(this);
   671   Document()->FireDelayedEvent(reorderEvent);
   673   // Clear cache.
   674   ClearCache(mAccessibleCache);
   675   mTreeView = aView;
   676 }
   678 ////////////////////////////////////////////////////////////////////////////////
   679 // XULTreeAccessible: protected implementation
   681 already_AddRefed<Accessible>
   682 XULTreeAccessible::CreateTreeItemAccessible(int32_t aRow) const
   683 {
   684   nsRefPtr<Accessible> accessible =
   685     new XULTreeItemAccessible(mContent, mDoc, const_cast<XULTreeAccessible*>(this),
   686                               mTree, mTreeView, aRow);
   688   return accessible.forget();
   689 }
   691 ////////////////////////////////////////////////////////////////////////////////
   692 // XULTreeItemAccessibleBase
   693 ////////////////////////////////////////////////////////////////////////////////
   695 XULTreeItemAccessibleBase::
   696   XULTreeItemAccessibleBase(nsIContent* aContent, DocAccessible* aDoc,
   697                             Accessible* aParent, nsITreeBoxObject* aTree,
   698                             nsITreeView* aTreeView, int32_t aRow) :
   699   AccessibleWrap(aContent, aDoc),
   700   mTree(aTree), mTreeView(aTreeView), mRow(aRow)
   701 {
   702   mParent = aParent;
   703   mStateFlags |= eSharedNode;
   704 }
   706 ////////////////////////////////////////////////////////////////////////////////
   707 // XULTreeItemAccessibleBase: nsISupports implementation
   709 NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessibleBase, Accessible,
   710                                    mTree)
   712 NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessibleBase)
   713   NS_INTERFACE_TABLE_INHERITED(XULTreeItemAccessibleBase,
   714                                XULTreeItemAccessibleBase)
   715 NS_INTERFACE_TABLE_TAIL_INHERITING(Accessible)
   716 NS_IMPL_ADDREF_INHERITED(XULTreeItemAccessibleBase, Accessible)
   717 NS_IMPL_RELEASE_INHERITED(XULTreeItemAccessibleBase, Accessible)
   719 ////////////////////////////////////////////////////////////////////////////////
   720 // XULTreeItemAccessibleBase: nsIAccessible implementation
   722 Accessible*
   723 XULTreeItemAccessibleBase::FocusedChild()
   724 {
   725   return FocusMgr()->FocusedAccessible() == this ? this : nullptr;
   726 }
   728 NS_IMETHODIMP
   729 XULTreeItemAccessibleBase::GetBounds(int32_t* aX, int32_t* aY,
   730                                      int32_t* aWidth, int32_t* aHeight)
   731 {
   732   NS_ENSURE_ARG_POINTER(aX);
   733   *aX = 0;
   734   NS_ENSURE_ARG_POINTER(aY);
   735   *aY = 0;
   736   NS_ENSURE_ARG_POINTER(aWidth);
   737   *aWidth = 0;
   738   NS_ENSURE_ARG_POINTER(aHeight);
   739   *aHeight = 0;
   741   if (IsDefunct())
   742     return NS_ERROR_FAILURE;
   744   // Get x coordinate and width from treechildren element, get y coordinate and
   745   // height from tree cell.
   747   nsCOMPtr<nsIBoxObject> boxObj = nsCoreUtils::GetTreeBodyBoxObject(mTree);
   748   NS_ENSURE_STATE(boxObj);
   750   nsCOMPtr<nsITreeColumn> column = nsCoreUtils::GetFirstSensibleColumn(mTree);
   752   int32_t x = 0, y = 0, width = 0, height = 0;
   753   nsresult rv = mTree->GetCoordsForCellItem(mRow, column, EmptyCString(),
   754                                             &x, &y, &width, &height);
   755   NS_ENSURE_SUCCESS(rv, rv);
   757   boxObj->GetWidth(&width);
   759   int32_t tcX = 0, tcY = 0;
   760   boxObj->GetScreenX(&tcX);
   761   boxObj->GetScreenY(&tcY);
   763   x = tcX;
   764   y += tcY;
   766   nsPresContext* presContext = mDoc->PresContext();
   767   *aX = presContext->CSSPixelsToDevPixels(x);
   768   *aY = presContext->CSSPixelsToDevPixels(y);
   769   *aWidth = presContext->CSSPixelsToDevPixels(width);
   770   *aHeight = presContext->CSSPixelsToDevPixels(height);
   772   return NS_OK;
   773 }
   775 NS_IMETHODIMP
   776 XULTreeItemAccessibleBase::SetSelected(bool aSelect)
   777 {
   778   if (IsDefunct())
   779     return NS_ERROR_FAILURE;
   781   nsCOMPtr<nsITreeSelection> selection;
   782   mTreeView->GetSelection(getter_AddRefs(selection));
   783   if (selection) {
   784     bool isSelected;
   785     selection->IsSelected(mRow, &isSelected);
   786     if (isSelected != aSelect)
   787       selection->ToggleSelect(mRow);
   788   }
   790   return NS_OK;
   791 }
   793 NS_IMETHODIMP
   794 XULTreeItemAccessibleBase::TakeFocus()
   795 {
   796   if (IsDefunct())
   797     return NS_ERROR_FAILURE;
   799   nsCOMPtr<nsITreeSelection> selection;
   800   mTreeView->GetSelection(getter_AddRefs(selection));
   801   if (selection)
   802     selection->SetCurrentIndex(mRow);
   804   // focus event will be fired here
   805   return Accessible::TakeFocus();
   806 }
   808 Relation
   809 XULTreeItemAccessibleBase::RelationByType(RelationType aType)
   810 {
   812   switch (aType) {
   813     case RelationType::NODE_CHILD_OF: {
   814       int32_t parentIndex = -1;
   815       if (!NS_SUCCEEDED(mTreeView->GetParentIndex(mRow, &parentIndex)))
   816         return Relation();
   818       if (parentIndex == -1)
   819         return Relation(mParent);
   821       XULTreeAccessible* treeAcc = mParent->AsXULTree();
   822       return Relation(treeAcc->GetTreeItemAccessible(parentIndex));
   823     }
   825     case RelationType::NODE_PARENT_OF: {
   826       bool isTrue = false;
   827       if (NS_FAILED(mTreeView->IsContainerEmpty(mRow, &isTrue)) || isTrue)
   828         return Relation();
   830       if (NS_FAILED(mTreeView->IsContainerOpen(mRow, &isTrue)) || !isTrue)
   831         return Relation();
   833       XULTreeAccessible* tree = mParent->AsXULTree();
   834       return Relation(new XULTreeItemIterator(tree, mTreeView, mRow));
   835     }
   837     default:
   838       return Relation();
   839   }
   840 }
   842 uint8_t
   843 XULTreeItemAccessibleBase::ActionCount()
   844 {
   845   // "activate" action is available for all treeitems, "expand/collapse" action
   846   // is avaible for treeitem which is container.
   847   return IsExpandable() ? 2 : 1;
   848 }
   850 NS_IMETHODIMP
   851 XULTreeItemAccessibleBase::GetActionName(uint8_t aIndex, nsAString& aName)
   852 {
   853   if (IsDefunct())
   854     return NS_ERROR_FAILURE;
   856   if (aIndex == eAction_Click) {
   857     aName.AssignLiteral("activate");
   858     return NS_OK;
   859   }
   861   if (aIndex == eAction_Expand && IsExpandable()) {
   862     bool isContainerOpen;
   863     mTreeView->IsContainerOpen(mRow, &isContainerOpen);
   864     if (isContainerOpen)
   865       aName.AssignLiteral("collapse");
   866     else
   867       aName.AssignLiteral("expand");
   869     return NS_OK;
   870   }
   872   return NS_ERROR_INVALID_ARG;
   873 }
   875 NS_IMETHODIMP
   876 XULTreeItemAccessibleBase::DoAction(uint8_t aIndex)
   877 {
   878   if (IsDefunct())
   879     return NS_ERROR_FAILURE;
   881   if (aIndex != eAction_Click &&
   882       (aIndex != eAction_Expand || !IsExpandable()))
   883     return NS_ERROR_INVALID_ARG;
   885   DoCommand(nullptr, aIndex);
   886   return NS_OK;
   887 }
   889 ////////////////////////////////////////////////////////////////////////////////
   890 // XULTreeItemAccessibleBase: Accessible implementation
   892 void
   893 XULTreeItemAccessibleBase::Shutdown()
   894 {
   895   mTree = nullptr;
   896   mTreeView = nullptr;
   897   mRow = -1;
   899   AccessibleWrap::Shutdown();
   900 }
   902 GroupPos
   903 XULTreeItemAccessibleBase::GroupPosition()
   904 {
   905   GroupPos groupPos;
   907   int32_t level;
   908   nsresult rv = mTreeView->GetLevel(mRow, &level);
   909   NS_ENSURE_SUCCESS(rv, groupPos);
   911   int32_t topCount = 1;
   912   for (int32_t index = mRow - 1; index >= 0; index--) {
   913     int32_t lvl = -1;
   914     if (NS_SUCCEEDED(mTreeView->GetLevel(index, &lvl))) {
   915       if (lvl < level)
   916         break;
   918       if (lvl == level)
   919         topCount++;
   920     }
   921   }
   923   int32_t rowCount = 0;
   924   rv = mTreeView->GetRowCount(&rowCount);
   925   NS_ENSURE_SUCCESS(rv, groupPos);
   927   int32_t bottomCount = 0;
   928   for (int32_t index = mRow + 1; index < rowCount; index++) {
   929     int32_t lvl = -1;
   930     if (NS_SUCCEEDED(mTreeView->GetLevel(index, &lvl))) {
   931       if (lvl < level)
   932         break;
   934       if (lvl == level)
   935         bottomCount++;
   936     }
   937   }
   939   groupPos.level = level + 1;
   940   groupPos.setSize = topCount + bottomCount;
   941   groupPos.posInSet = topCount;
   943   return groupPos;
   944 }
   946 uint64_t
   947 XULTreeItemAccessibleBase::NativeState()
   948 {
   950   // focusable and selectable states
   951   uint64_t state = NativeInteractiveState();
   953   // expanded/collapsed state
   954   if (IsExpandable()) {
   955     bool isContainerOpen;
   956     mTreeView->IsContainerOpen(mRow, &isContainerOpen);
   957     state |= isContainerOpen ? states::EXPANDED : states::COLLAPSED;
   958   }
   960   // selected state
   961   nsCOMPtr<nsITreeSelection> selection;
   962   mTreeView->GetSelection(getter_AddRefs(selection));
   963   if (selection) {
   964     bool isSelected;
   965     selection->IsSelected(mRow, &isSelected);
   966     if (isSelected)
   967       state |= states::SELECTED;
   968   }
   970   // focused state
   971   if (FocusMgr()->IsFocused(this))
   972     state |= states::FOCUSED;
   974   // invisible state
   975   int32_t firstVisibleRow, lastVisibleRow;
   976   mTree->GetFirstVisibleRow(&firstVisibleRow);
   977   mTree->GetLastVisibleRow(&lastVisibleRow);
   978   if (mRow < firstVisibleRow || mRow > lastVisibleRow)
   979     state |= states::INVISIBLE;
   981   return state;
   982 }
   984 uint64_t
   985 XULTreeItemAccessibleBase::NativeInteractiveState() const
   986 {
   987   return states::FOCUSABLE | states::SELECTABLE;
   988 }
   990 int32_t
   991 XULTreeItemAccessibleBase::IndexInParent() const
   992 {
   993   return mParent ? mParent->ContentChildCount() + mRow : -1;
   994 }
   996 ////////////////////////////////////////////////////////////////////////////////
   997 // XULTreeItemAccessibleBase: Widgets
   999 Accessible*
  1000 XULTreeItemAccessibleBase::ContainerWidget() const
  1002   return mParent;
  1005 ////////////////////////////////////////////////////////////////////////////////
  1006 // XULTreeItemAccessibleBase: Accessible protected methods
  1008 void
  1009 XULTreeItemAccessibleBase::DispatchClickEvent(nsIContent* aContent,
  1010                                               uint32_t aActionIndex)
  1012   if (IsDefunct())
  1013     return;
  1015   nsCOMPtr<nsITreeColumns> columns;
  1016   mTree->GetColumns(getter_AddRefs(columns));
  1017   if (!columns)
  1018     return;
  1020   // Get column and pseudo element.
  1021   nsCOMPtr<nsITreeColumn> column;
  1022   nsAutoCString pseudoElm;
  1024   if (aActionIndex == eAction_Click) {
  1025     // Key column is visible and clickable.
  1026     columns->GetKeyColumn(getter_AddRefs(column));
  1027   } else {
  1028     // Primary column contains a twisty we should click on.
  1029     columns->GetPrimaryColumn(getter_AddRefs(column));
  1030     pseudoElm = NS_LITERAL_CSTRING("twisty");
  1033   if (column)
  1034     nsCoreUtils::DispatchClickEvent(mTree, mRow, column, pseudoElm);
  1037 Accessible*
  1038 XULTreeItemAccessibleBase::GetSiblingAtOffset(int32_t aOffset,
  1039                                               nsresult* aError) const
  1041   if (aError)
  1042     *aError = NS_OK; // fail peacefully
  1044   return mParent->GetChildAt(IndexInParent() + aOffset);
  1047 ////////////////////////////////////////////////////////////////////////////////
  1048 // XULTreeItemAccessibleBase: protected implementation
  1050 bool
  1051 XULTreeItemAccessibleBase::IsExpandable()
  1054   bool isContainer = false;
  1055   mTreeView->IsContainer(mRow, &isContainer);
  1056   if (isContainer) {
  1057     bool isEmpty = false;
  1058     mTreeView->IsContainerEmpty(mRow, &isEmpty);
  1059     if (!isEmpty) {
  1060       nsCOMPtr<nsITreeColumns> columns;
  1061       mTree->GetColumns(getter_AddRefs(columns));
  1062       nsCOMPtr<nsITreeColumn> primaryColumn;
  1063       if (columns) {
  1064         columns->GetPrimaryColumn(getter_AddRefs(primaryColumn));
  1065         if (primaryColumn &&
  1066             !nsCoreUtils::IsColumnHidden(primaryColumn))
  1067           return true;
  1072   return false;
  1075 void
  1076 XULTreeItemAccessibleBase::GetCellName(nsITreeColumn* aColumn, nsAString& aName)
  1079   mTreeView->GetCellText(mRow, aColumn, aName);
  1081   // If there is still no name try the cell value:
  1082   // This is for graphical cells. We need tree/table view implementors to
  1083   // implement FooView::GetCellValue to return a meaningful string for cases
  1084   // where there is something shown in the cell (non-text) such as a star icon;
  1085   // in which case GetCellValue for that cell would return "starred" or
  1086   // "flagged" for example.
  1087   if (aName.IsEmpty())
  1088     mTreeView->GetCellValue(mRow, aColumn, aName);
  1092 ////////////////////////////////////////////////////////////////////////////////
  1093 // XULTreeItemAccessible
  1094 ////////////////////////////////////////////////////////////////////////////////
  1096 XULTreeItemAccessible::
  1097   XULTreeItemAccessible(nsIContent* aContent, DocAccessible* aDoc,
  1098                         Accessible* aParent, nsITreeBoxObject* aTree,
  1099                         nsITreeView* aTreeView, int32_t aRow) :
  1100   XULTreeItemAccessibleBase(aContent, aDoc, aParent, aTree, aTreeView, aRow)
  1102   mColumn = nsCoreUtils::GetFirstSensibleColumn(mTree);
  1103   GetCellName(mColumn, mCachedName);
  1106 ////////////////////////////////////////////////////////////////////////////////
  1107 // XULTreeItemAccessible: nsISupports implementation
  1109 NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessible,
  1110                                    XULTreeItemAccessibleBase,
  1111                                    mColumn)
  1113 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessible)
  1114 NS_INTERFACE_MAP_END_INHERITING(XULTreeItemAccessibleBase)
  1115 NS_IMPL_ADDREF_INHERITED(XULTreeItemAccessible, XULTreeItemAccessibleBase)
  1116 NS_IMPL_RELEASE_INHERITED(XULTreeItemAccessible, XULTreeItemAccessibleBase)
  1118 ////////////////////////////////////////////////////////////////////////////////
  1119 // XULTreeItemAccessible: nsIAccessible implementation
  1121 ENameValueFlag
  1122 XULTreeItemAccessible::Name(nsString& aName)
  1124   aName.Truncate();
  1126   GetCellName(mColumn, aName);
  1127   return eNameOK;
  1130 ////////////////////////////////////////////////////////////////////////////////
  1131 // XULTreeItemAccessible: Accessible implementation
  1133 void
  1134 XULTreeItemAccessible::Shutdown()
  1136   mColumn = nullptr;
  1137   XULTreeItemAccessibleBase::Shutdown();
  1140 role
  1141 XULTreeItemAccessible::NativeRole()
  1143   nsCOMPtr<nsITreeColumns> columns;
  1144   mTree->GetColumns(getter_AddRefs(columns));
  1145   if (!columns) {
  1146     NS_ERROR("No tree columns object in the tree!");
  1147     return roles::NOTHING;
  1150   nsCOMPtr<nsITreeColumn> primaryColumn;
  1151   columns->GetPrimaryColumn(getter_AddRefs(primaryColumn));
  1153   return primaryColumn ? roles::OUTLINEITEM : roles::LISTITEM;
  1156 ////////////////////////////////////////////////////////////////////////////////
  1157 // XULTreeItemAccessible: XULTreeItemAccessibleBase implementation
  1159 void
  1160 XULTreeItemAccessible::RowInvalidated(int32_t aStartColIdx, int32_t aEndColIdx)
  1162   nsAutoString name;
  1163   Name(name);
  1165   if (name != mCachedName) {
  1166     nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this);
  1167     mCachedName = name;
  1171 ////////////////////////////////////////////////////////////////////////////////
  1172 // XULTreeItemAccessible: Accessible protected implementation
  1174 void
  1175 XULTreeItemAccessible::CacheChildren()
  1180 ////////////////////////////////////////////////////////////////////////////////
  1181 //  XULTreeColumAccessible
  1182 ////////////////////////////////////////////////////////////////////////////////
  1184 XULTreeColumAccessible::
  1185   XULTreeColumAccessible(nsIContent* aContent, DocAccessible* aDoc) :
  1186   XULColumAccessible(aContent, aDoc)
  1190 Accessible*
  1191 XULTreeColumAccessible::GetSiblingAtOffset(int32_t aOffset,
  1192                                            nsresult* aError) const
  1194   if (aOffset < 0)
  1195     return XULColumAccessible::GetSiblingAtOffset(aOffset, aError);
  1197   if (aError)
  1198     *aError =  NS_OK; // fail peacefully
  1200   nsCOMPtr<nsITreeBoxObject> tree = nsCoreUtils::GetTreeBoxObject(mContent);
  1201   if (tree) {
  1202     nsCOMPtr<nsITreeView> treeView;
  1203     tree->GetView(getter_AddRefs(treeView));
  1204     if (treeView) {
  1205       int32_t rowCount = 0;
  1206       treeView->GetRowCount(&rowCount);
  1207       if (rowCount > 0 && aOffset <= rowCount) {
  1208         XULTreeAccessible* treeAcc = Parent()->AsXULTree();
  1210         if (treeAcc)
  1211           return treeAcc->GetTreeItemAccessible(aOffset - 1);
  1216   return nullptr;

mercurial