tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

XULTreeAccessible.cpp (30450B)


      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/. */
      6 
      7 #include "XULTreeAccessible.h"
      8 
      9 #include "LocalAccessible-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 "mozilla/a11y/Role.h"
     18 #include "States.h"
     19 #include "XULTreeGridAccessible.h"
     20 #include "nsQueryObject.h"
     21 
     22 #include "nsComponentManagerUtils.h"
     23 #include "nsIAutoCompletePopup.h"
     24 #include "nsIDOMXULMenuListElement.h"
     25 #include "nsITreeSelection.h"
     26 #include "nsTreeBodyFrame.h"
     27 #include "nsTreeColumns.h"
     28 #include "nsTreeUtils.h"
     29 #include "mozilla/PresShell.h"
     30 #include "mozilla/dom/XULTreeElementBinding.h"
     31 
     32 using namespace mozilla::a11y;
     33 
     34 ////////////////////////////////////////////////////////////////////////////////
     35 // XULTreeAccessible
     36 ////////////////////////////////////////////////////////////////////////////////
     37 
     38 XULTreeAccessible::XULTreeAccessible(nsIContent* aContent, DocAccessible* aDoc,
     39                                     nsTreeBodyFrame* aTreeFrame)
     40    : AccessibleWrap(aContent, aDoc),
     41      mAccessibleCache(kDefaultTreeCacheLength) {
     42  mType = eXULTreeType;
     43  mGenericTypes |= eSelect;
     44 
     45  nsCOMPtr<nsITreeView> view = aTreeFrame->GetExistingView();
     46  mTreeView = view;
     47 
     48  mTree = nsCoreUtils::GetTree(aContent);
     49  NS_ASSERTION(mTree, "Can't get mTree!\n");
     50 
     51  nsIContent* parentContent = mContent->GetParent();
     52  if (parentContent) {
     53    nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
     54        do_QueryInterface(parentContent);
     55    if (autoCompletePopupElm) mGenericTypes |= eAutoCompletePopup;
     56  }
     57 }
     58 
     59 XULTreeAccessible::~XULTreeAccessible() {}
     60 
     61 ////////////////////////////////////////////////////////////////////////////////
     62 // XULTreeAccessible: nsISupports and cycle collection implementation
     63 
     64 NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeAccessible, LocalAccessible, mTree,
     65                                   mAccessibleCache)
     66 
     67 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XULTreeAccessible)
     68 NS_INTERFACE_MAP_END_INHERITING(LocalAccessible)
     69 
     70 NS_IMPL_ADDREF_INHERITED(XULTreeAccessible, LocalAccessible)
     71 NS_IMPL_RELEASE_INHERITED(XULTreeAccessible, LocalAccessible)
     72 
     73 ////////////////////////////////////////////////////////////////////////////////
     74 // XULTreeAccessible: LocalAccessible implementation
     75 
     76 uint64_t XULTreeAccessible::NativeState() const {
     77  // Get focus status from base class.
     78  uint64_t state = LocalAccessible::NativeState();
     79 
     80  // readonly state
     81  state |= states::READONLY;
     82 
     83  // multiselectable state.
     84  if (!mTreeView) return state;
     85 
     86  nsCOMPtr<nsITreeSelection> selection;
     87  mTreeView->GetSelection(getter_AddRefs(selection));
     88  NS_ENSURE_TRUE(selection, state);
     89 
     90  bool isSingle = false;
     91  nsresult rv = selection->GetSingle(&isSingle);
     92  NS_ENSURE_SUCCESS(rv, state);
     93 
     94  if (!isSingle) state |= states::MULTISELECTABLE;
     95 
     96  return state;
     97 }
     98 
     99 void XULTreeAccessible::Value(nsString& aValue) const {
    100  aValue.Truncate();
    101  if (!mTreeView) return;
    102 
    103  // Return the value is the first selected child.
    104  nsCOMPtr<nsITreeSelection> selection;
    105  mTreeView->GetSelection(getter_AddRefs(selection));
    106  if (!selection) return;
    107 
    108  int32_t currentIndex;
    109  selection->GetCurrentIndex(&currentIndex);
    110  if (currentIndex >= 0) {
    111    RefPtr<nsTreeColumn> keyCol;
    112 
    113    RefPtr<nsTreeColumns> cols = mTree->GetColumns();
    114    if (cols) keyCol = cols->GetKeyColumn();
    115 
    116    mTreeView->GetCellText(currentIndex, keyCol, aValue);
    117  }
    118 }
    119 
    120 ////////////////////////////////////////////////////////////////////////////////
    121 // XULTreeAccessible: LocalAccessible implementation
    122 
    123 void XULTreeAccessible::Shutdown() {
    124  if (mDoc && !mDoc->IsDefunct()) {
    125    UnbindCacheEntriesFromDocument(mAccessibleCache);
    126  }
    127 
    128  mTree = nullptr;
    129  mTreeView = nullptr;
    130 
    131  AccessibleWrap::Shutdown();
    132 }
    133 
    134 role XULTreeAccessible::NativeRole() const {
    135  // No primary column means we're in a list. In fact, history and mail turn off
    136  // the primary flag when switching to a flat view.
    137 
    138  nsIContent* child =
    139      nsTreeUtils::GetDescendantChild(mContent, nsGkAtoms::treechildren);
    140  NS_ASSERTION(child, "tree without treechildren!");
    141  nsTreeBodyFrame* treeFrame = do_QueryFrame(child->GetPrimaryFrame());
    142  NS_ASSERTION(treeFrame, "xul tree accessible for tree without a frame!");
    143  if (!treeFrame) return roles::LIST;
    144 
    145  RefPtr<nsTreeColumns> cols = treeFrame->Columns();
    146  nsTreeColumn* primaryCol = cols->GetPrimaryColumn();
    147 
    148  return primaryCol ? roles::OUTLINE : roles::LIST;
    149 }
    150 
    151 ////////////////////////////////////////////////////////////////////////////////
    152 // XULTreeAccessible: LocalAccessible implementation (DON'T put methods here)
    153 
    154 LocalAccessible* XULTreeAccessible::LocalChildAtPoint(
    155    int32_t aX, int32_t aY, EWhichChildAtPoint aWhichChild) {
    156  nsIFrame* frame = GetFrame();
    157  if (!frame) return nullptr;
    158 
    159  nsPresContext* presContext = frame->PresContext();
    160  PresShell* presShell = presContext->PresShell();
    161 
    162  nsIFrame* rootFrame = presShell->GetRootFrame();
    163  NS_ENSURE_TRUE(rootFrame, nullptr);
    164 
    165  CSSIntRect rootRect = rootFrame->GetScreenRect();
    166 
    167  int32_t clientX = presContext->DevPixelsToIntCSSPixels(aX) - rootRect.X();
    168  int32_t clientY = presContext->DevPixelsToIntCSSPixels(aY) - rootRect.Y();
    169 
    170  ErrorResult rv;
    171  dom::TreeCellInfo cellInfo;
    172  mTree->GetCellAt(clientX, clientY, cellInfo, rv);
    173 
    174  // If we failed to find tree cell for the given point then it might be
    175  // tree columns.
    176  if (cellInfo.mRow == -1 || !cellInfo.mCol) {
    177    return AccessibleWrap::LocalChildAtPoint(aX, aY, aWhichChild);
    178  }
    179 
    180  XULTreeItemAccessibleBase* child = GetTreeItemAccessible(cellInfo.mRow);
    181  if (aWhichChild == EWhichChildAtPoint::DeepestChild && child) {
    182    LocalAccessible* cell = child->GetCellAccessible(cellInfo.mCol);
    183    if (cell) {
    184      return cell;
    185    }
    186  }
    187 
    188  return child;
    189 }
    190 
    191 ////////////////////////////////////////////////////////////////////////////////
    192 // XULTreeAccessible: SelectAccessible
    193 
    194 LocalAccessible* XULTreeAccessible::CurrentItem() const {
    195  if (!mTreeView) return nullptr;
    196 
    197  nsCOMPtr<nsITreeSelection> selection;
    198  mTreeView->GetSelection(getter_AddRefs(selection));
    199  if (selection) {
    200    int32_t currentIndex = -1;
    201    selection->GetCurrentIndex(&currentIndex);
    202    if (currentIndex >= 0) return GetTreeItemAccessible(currentIndex);
    203  }
    204 
    205  return nullptr;
    206 }
    207 
    208 void XULTreeAccessible::SetCurrentItem(const LocalAccessible* aItem) {
    209  NS_ERROR("XULTreeAccessible::SetCurrentItem not implemented");
    210 }
    211 
    212 void XULTreeAccessible::SelectedItems(nsTArray<Accessible*>* aItems) {
    213  if (!mTreeView) return;
    214 
    215  nsCOMPtr<nsITreeSelection> selection;
    216  mTreeView->GetSelection(getter_AddRefs(selection));
    217  if (!selection) return;
    218 
    219  int32_t rangeCount = 0;
    220  selection->GetRangeCount(&rangeCount);
    221  for (int32_t rangeIdx = 0; rangeIdx < rangeCount; rangeIdx++) {
    222    int32_t firstIdx = 0, lastIdx = -1;
    223    selection->GetRangeAt(rangeIdx, &firstIdx, &lastIdx);
    224    for (int32_t rowIdx = firstIdx; rowIdx <= lastIdx; rowIdx++) {
    225      LocalAccessible* item = GetTreeItemAccessible(rowIdx);
    226      if (item) aItems->AppendElement(item);
    227    }
    228  }
    229 }
    230 
    231 uint32_t XULTreeAccessible::SelectedItemCount() {
    232  if (!mTreeView) return 0;
    233 
    234  nsCOMPtr<nsITreeSelection> selection;
    235  mTreeView->GetSelection(getter_AddRefs(selection));
    236  if (selection) {
    237    int32_t count = 0;
    238    selection->GetCount(&count);
    239    return count;
    240  }
    241 
    242  return 0;
    243 }
    244 
    245 bool XULTreeAccessible::AddItemToSelection(uint32_t aIndex) {
    246  if (!mTreeView) return false;
    247 
    248  nsCOMPtr<nsITreeSelection> selection;
    249  mTreeView->GetSelection(getter_AddRefs(selection));
    250  if (selection) {
    251    bool isSelected = false;
    252    selection->IsSelected(aIndex, &isSelected);
    253    if (!isSelected) selection->ToggleSelect(aIndex);
    254 
    255    return true;
    256  }
    257  return false;
    258 }
    259 
    260 bool XULTreeAccessible::RemoveItemFromSelection(uint32_t aIndex) {
    261  if (!mTreeView) return false;
    262 
    263  nsCOMPtr<nsITreeSelection> selection;
    264  mTreeView->GetSelection(getter_AddRefs(selection));
    265  if (selection) {
    266    bool isSelected = false;
    267    selection->IsSelected(aIndex, &isSelected);
    268    if (isSelected) selection->ToggleSelect(aIndex);
    269 
    270    return true;
    271  }
    272  return false;
    273 }
    274 
    275 bool XULTreeAccessible::IsItemSelected(uint32_t aIndex) {
    276  if (!mTreeView) return false;
    277 
    278  nsCOMPtr<nsITreeSelection> selection;
    279  mTreeView->GetSelection(getter_AddRefs(selection));
    280  if (selection) {
    281    bool isSelected = false;
    282    selection->IsSelected(aIndex, &isSelected);
    283    return isSelected;
    284  }
    285  return false;
    286 }
    287 
    288 bool XULTreeAccessible::UnselectAll() {
    289  if (!mTreeView) return false;
    290 
    291  nsCOMPtr<nsITreeSelection> selection;
    292  mTreeView->GetSelection(getter_AddRefs(selection));
    293  if (!selection) return false;
    294 
    295  selection->ClearSelection();
    296  return true;
    297 }
    298 
    299 Accessible* XULTreeAccessible::GetSelectedItem(uint32_t aIndex) {
    300  if (!mTreeView) return nullptr;
    301 
    302  nsCOMPtr<nsITreeSelection> selection;
    303  mTreeView->GetSelection(getter_AddRefs(selection));
    304  if (!selection) return nullptr;
    305 
    306  uint32_t selCount = 0;
    307  int32_t rangeCount = 0;
    308  selection->GetRangeCount(&rangeCount);
    309  for (int32_t rangeIdx = 0; rangeIdx < rangeCount; rangeIdx++) {
    310    int32_t firstIdx = 0, lastIdx = -1;
    311    selection->GetRangeAt(rangeIdx, &firstIdx, &lastIdx);
    312    for (int32_t rowIdx = firstIdx; rowIdx <= lastIdx; rowIdx++) {
    313      if (selCount == aIndex) return GetTreeItemAccessible(rowIdx);
    314 
    315      selCount++;
    316    }
    317  }
    318 
    319  return nullptr;
    320 }
    321 
    322 bool XULTreeAccessible::SelectAll() {
    323  // see if we are multiple select if so set ourselves as such
    324  if (!mTreeView) return false;
    325 
    326  nsCOMPtr<nsITreeSelection> selection;
    327  mTreeView->GetSelection(getter_AddRefs(selection));
    328  if (selection) {
    329    bool single = false;
    330    selection->GetSingle(&single);
    331    if (!single) {
    332      selection->SelectAll();
    333      return true;
    334    }
    335  }
    336 
    337  return false;
    338 }
    339 
    340 ////////////////////////////////////////////////////////////////////////////////
    341 // XULTreeAccessible: LocalAccessible implementation
    342 
    343 LocalAccessible* XULTreeAccessible::LocalChildAt(uint32_t aIndex) const {
    344  uint32_t childCount = LocalAccessible::ChildCount();
    345  if (aIndex < childCount) {
    346    return LocalAccessible::LocalChildAt(aIndex);
    347  }
    348 
    349  return GetTreeItemAccessible(aIndex - childCount);
    350 }
    351 
    352 uint32_t XULTreeAccessible::ChildCount() const {
    353  // Tree's children count is row count + treecols count.
    354  uint32_t childCount = LocalAccessible::ChildCount();
    355  if (!mTreeView) return childCount;
    356 
    357  int32_t rowCount = 0;
    358  mTreeView->GetRowCount(&rowCount);
    359  childCount += rowCount;
    360 
    361  return childCount;
    362 }
    363 
    364 Relation XULTreeAccessible::RelationByType(RelationType aType) const {
    365  if (aType == RelationType::NODE_PARENT_OF) {
    366    if (mTreeView) {
    367      return Relation(new XULTreeItemIterator(this, mTreeView, -1));
    368    }
    369 
    370    return Relation();
    371  }
    372 
    373  return LocalAccessible::RelationByType(aType);
    374 }
    375 
    376 ////////////////////////////////////////////////////////////////////////////////
    377 // XULTreeAccessible: Widgets
    378 
    379 bool XULTreeAccessible::IsWidget() const { return true; }
    380 
    381 bool XULTreeAccessible::IsActiveWidget() const {
    382  if (IsAutoCompletePopup()) {
    383    nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
    384        do_QueryInterface(mContent->GetParent());
    385 
    386    if (autoCompletePopupElm) {
    387      bool isOpen = false;
    388      autoCompletePopupElm->GetPopupOpen(&isOpen);
    389      return isOpen;
    390    }
    391  }
    392  return FocusMgr()->HasDOMFocus(mContent);
    393 }
    394 
    395 bool XULTreeAccessible::AreItemsOperable() const {
    396  if (IsAutoCompletePopup()) {
    397    nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
    398        do_QueryInterface(mContent->GetParent());
    399 
    400    if (autoCompletePopupElm) {
    401      bool isOpen = false;
    402      autoCompletePopupElm->GetPopupOpen(&isOpen);
    403      return isOpen;
    404    }
    405  }
    406  return true;
    407 }
    408 
    409 LocalAccessible* XULTreeAccessible::ContainerWidget() const { return nullptr; }
    410 
    411 ////////////////////////////////////////////////////////////////////////////////
    412 // XULTreeAccessible: public implementation
    413 
    414 XULTreeItemAccessibleBase* XULTreeAccessible::GetTreeItemAccessible(
    415    int32_t aRow) const {
    416  if (aRow < 0 || IsDefunct() || !mTreeView) return nullptr;
    417 
    418  int32_t rowCount = 0;
    419  nsresult rv = mTreeView->GetRowCount(&rowCount);
    420  if (NS_FAILED(rv) || aRow >= rowCount) return nullptr;
    421 
    422  void* key = reinterpret_cast<void*>(intptr_t(aRow));
    423  return mAccessibleCache.WithEntryHandle(
    424      key, [&](auto&& entry) -> XULTreeItemAccessibleBase* {
    425        if (entry) {
    426          return entry->get();
    427        }
    428 
    429        RefPtr<XULTreeItemAccessibleBase> treeItem =
    430            CreateTreeItemAccessible(aRow);
    431        if (treeItem) {
    432          entry.Insert(RefPtr{treeItem});
    433          Document()->BindToDocument(treeItem, nullptr);
    434          return treeItem.get();
    435        }
    436 
    437        return nullptr;
    438      });
    439 }
    440 
    441 void XULTreeAccessible::InvalidateCache(int32_t aRow, int32_t aCount) {
    442  if (IsDefunct()) return;
    443 
    444  if (!mTreeView) {
    445    UnbindCacheEntriesFromDocument(mAccessibleCache);
    446    return;
    447  }
    448 
    449  // Do not invalidate the cache if rows have been inserted.
    450  if (aCount > 0) return;
    451 
    452  DocAccessible* document = Document();
    453 
    454  // Fire destroy event for removed tree items and delete them from caches.
    455  for (int32_t rowIdx = aRow; rowIdx < aRow - aCount; rowIdx++) {
    456    void* key = reinterpret_cast<void*>(intptr_t(rowIdx));
    457    XULTreeItemAccessibleBase* treeItem = mAccessibleCache.GetWeak(key);
    458 
    459    if (treeItem) {
    460      RefPtr<AccEvent> event =
    461          new AccEvent(nsIAccessibleEvent::EVENT_HIDE, treeItem);
    462      nsEventShell::FireEvent(event);
    463 
    464      // Unbind from document, shutdown and remove from tree cache.
    465      document->UnbindFromDocument(treeItem);
    466      mAccessibleCache.Remove(key);
    467    }
    468  }
    469 
    470  // We dealt with removed tree items already however we may keep tree items
    471  // having row indexes greater than row count. We should remove these dead tree
    472  // items silently from caches.
    473  int32_t newRowCount = 0;
    474  nsresult rv = mTreeView->GetRowCount(&newRowCount);
    475  if (NS_FAILED(rv)) return;
    476 
    477  int32_t oldRowCount = newRowCount - aCount;
    478 
    479  for (int32_t rowIdx = newRowCount; rowIdx < oldRowCount; ++rowIdx) {
    480    void* key = reinterpret_cast<void*>(intptr_t(rowIdx));
    481    XULTreeItemAccessibleBase* treeItem = mAccessibleCache.GetWeak(key);
    482 
    483    if (treeItem) {
    484      // Unbind from document, shutdown and remove from tree cache.
    485      document->UnbindFromDocument(treeItem);
    486      mAccessibleCache.Remove(key);
    487    }
    488  }
    489 }
    490 
    491 void XULTreeAccessible::TreeViewInvalidated(int32_t aStartRow, int32_t aEndRow,
    492                                            int32_t aStartCol,
    493                                            int32_t aEndCol) {
    494  if (IsDefunct()) return;
    495 
    496  if (!mTreeView) {
    497    UnbindCacheEntriesFromDocument(mAccessibleCache);
    498    return;
    499  }
    500 
    501  int32_t endRow = aEndRow;
    502 
    503  nsresult rv;
    504  if (endRow == -1) {
    505    int32_t rowCount = 0;
    506    rv = mTreeView->GetRowCount(&rowCount);
    507    if (NS_FAILED(rv)) return;
    508 
    509    endRow = rowCount - 1;
    510  }
    511 
    512  RefPtr<nsTreeColumns> treeColumns = mTree->GetColumns();
    513  if (!treeColumns) return;
    514 
    515  int32_t endCol = aEndCol;
    516 
    517  if (endCol == -1) {
    518    // We need to make sure to cast to int32_t before we do the subtraction, in
    519    // case the column count is 0.
    520    endCol = static_cast<int32_t>(treeColumns->Count()) - 1;
    521  }
    522 
    523  for (int32_t rowIdx = aStartRow; rowIdx <= endRow; ++rowIdx) {
    524    void* key = reinterpret_cast<void*>(intptr_t(rowIdx));
    525    XULTreeItemAccessibleBase* treeitemAcc = mAccessibleCache.GetWeak(key);
    526 
    527    if (treeitemAcc) {
    528      treeitemAcc->RowInvalidated(aStartCol, endCol);
    529    }
    530  }
    531 }
    532 
    533 void XULTreeAccessible::TreeViewChanged(nsITreeView* aView) {
    534  if (IsDefunct()) return;
    535 
    536  // Fire reorder event on tree accessible on accessible tree (do not fire
    537  // show/hide events on tree items because it can be expensive to fire them for
    538  // each tree item.
    539  RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(this);
    540  Document()->FireDelayedEvent(reorderEvent);
    541 
    542  // Clear cache.
    543  UnbindCacheEntriesFromDocument(mAccessibleCache);
    544 
    545  mTreeView = aView;
    546  LocalAccessible* item = CurrentItem();
    547  if (item) {
    548    FocusMgr()->ActiveItemChanged(item, true);
    549  }
    550 }
    551 
    552 ////////////////////////////////////////////////////////////////////////////////
    553 // XULTreeAccessible: protected implementation
    554 
    555 already_AddRefed<XULTreeItemAccessibleBase>
    556 XULTreeAccessible::CreateTreeItemAccessible(int32_t aRow) const {
    557  RefPtr<XULTreeItemAccessibleBase> accessible = new XULTreeItemAccessible(
    558      mContent, mDoc, const_cast<XULTreeAccessible*>(this), mTree, mTreeView,
    559      aRow);
    560 
    561  return accessible.forget();
    562 }
    563 
    564 ////////////////////////////////////////////////////////////////////////////////
    565 // XULTreeItemAccessibleBase
    566 ////////////////////////////////////////////////////////////////////////////////
    567 
    568 XULTreeItemAccessibleBase::XULTreeItemAccessibleBase(
    569    nsIContent* aContent, DocAccessible* aDoc, LocalAccessible* aParent,
    570    dom::XULTreeElement* aTree, nsITreeView* aTreeView, int32_t aRow)
    571    : AccessibleWrap(aContent, aDoc),
    572      mTree(aTree),
    573      mTreeView(aTreeView),
    574      mRow(aRow) {
    575  mParent = aParent;
    576  mStateFlags |= eSharedNode;
    577 }
    578 
    579 XULTreeItemAccessibleBase::~XULTreeItemAccessibleBase() {}
    580 
    581 ////////////////////////////////////////////////////////////////////////////////
    582 // XULTreeItemAccessibleBase: nsISupports implementation
    583 
    584 NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessibleBase, LocalAccessible,
    585                                   mTree)
    586 
    587 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(XULTreeItemAccessibleBase,
    588                                               LocalAccessible)
    589 
    590 ////////////////////////////////////////////////////////////////////////////////
    591 // XULTreeItemAccessibleBase: LocalAccessible
    592 
    593 Accessible* XULTreeItemAccessibleBase::FocusedChild() {
    594  return FocusMgr()->FocusedLocalAccessible() == this ? this : nullptr;
    595 }
    596 
    597 nsIntRect XULTreeItemAccessibleBase::BoundsInCSSPixels() const {
    598  // Get x coordinate and width from treechildren element, get y coordinate and
    599  // height from tree cell.
    600 
    601  RefPtr<nsTreeColumn> column = nsCoreUtils::GetFirstSensibleColumn(mTree);
    602 
    603  nsresult rv;
    604  nsIntRect rect = mTree->GetCoordsForCellItem(mRow, column, u"cell"_ns, rv);
    605  if (NS_FAILED(rv)) {
    606    return nsIntRect();
    607  }
    608 
    609  RefPtr<dom::Element> bodyElement = mTree->GetTreeBody();
    610  if (!bodyElement || !bodyElement->IsXULElement()) {
    611    return nsIntRect();
    612  }
    613 
    614  rect.width = bodyElement->ClientWidth();
    615 
    616  nsIFrame* bodyFrame = bodyElement->GetPrimaryFrame();
    617  if (!bodyFrame) {
    618    return nsIntRect();
    619  }
    620 
    621  CSSIntRect screenRect = bodyFrame->GetScreenRect();
    622  rect.x = screenRect.x;
    623  rect.y += screenRect.y;
    624  return rect;
    625 }
    626 
    627 nsRect XULTreeItemAccessibleBase::BoundsInAppUnits() const {
    628  nsIntRect bounds = BoundsInCSSPixels();
    629  nsPresContext* presContext = mDoc->PresContext();
    630  return nsRect(presContext->CSSPixelsToAppUnits(bounds.X()),
    631                presContext->CSSPixelsToAppUnits(bounds.Y()),
    632                presContext->CSSPixelsToAppUnits(bounds.Width()),
    633                presContext->CSSPixelsToAppUnits(bounds.Height()));
    634 }
    635 
    636 void XULTreeItemAccessibleBase::SetSelected(bool aSelect) {
    637  nsCOMPtr<nsITreeSelection> selection;
    638  mTreeView->GetSelection(getter_AddRefs(selection));
    639  if (selection) {
    640    bool isSelected = false;
    641    selection->IsSelected(mRow, &isSelected);
    642    if (isSelected != aSelect) selection->ToggleSelect(mRow);
    643  }
    644 }
    645 
    646 void XULTreeItemAccessibleBase::TakeFocus() const {
    647  nsCOMPtr<nsITreeSelection> selection;
    648  mTreeView->GetSelection(getter_AddRefs(selection));
    649  if (selection) selection->SetCurrentIndex(mRow);
    650 
    651  // focus event will be fired here
    652  LocalAccessible::TakeFocus();
    653 }
    654 
    655 Relation XULTreeItemAccessibleBase::RelationByType(RelationType aType) const {
    656  switch (aType) {
    657    case RelationType::NODE_CHILD_OF: {
    658      int32_t parentIndex = -1;
    659      if (!NS_SUCCEEDED(mTreeView->GetParentIndex(mRow, &parentIndex))) {
    660        return Relation();
    661      }
    662 
    663      if (parentIndex == -1) return Relation(mParent);
    664 
    665      XULTreeAccessible* treeAcc = mParent->AsXULTree();
    666      return Relation(treeAcc->GetTreeItemAccessible(parentIndex));
    667    }
    668 
    669    case RelationType::NODE_PARENT_OF: {
    670      bool isTrue = false;
    671      if (NS_FAILED(mTreeView->IsContainerEmpty(mRow, &isTrue)) || isTrue) {
    672        return Relation();
    673      }
    674 
    675      if (NS_FAILED(mTreeView->IsContainerOpen(mRow, &isTrue)) || !isTrue) {
    676        return Relation();
    677      }
    678 
    679      XULTreeAccessible* tree = mParent->AsXULTree();
    680      return Relation(new XULTreeItemIterator(tree, mTreeView, mRow));
    681    }
    682 
    683    default:
    684      return Relation();
    685  }
    686 }
    687 
    688 bool XULTreeItemAccessibleBase::HasPrimaryAction() const { return true; }
    689 
    690 uint8_t XULTreeItemAccessibleBase::ActionCount() const {
    691  // "activate" action is available for all treeitems, "expand/collapse" action
    692  // is avaible for treeitem which is container.
    693  return IsExpandable() ? 2 : 1;
    694 }
    695 
    696 void XULTreeItemAccessibleBase::ActionNameAt(uint8_t aIndex, nsAString& aName) {
    697  if (aIndex == eAction_Click) {
    698    aName.AssignLiteral("activate");
    699    return;
    700  }
    701 
    702  if (aIndex == eAction_Expand && IsExpandable()) {
    703    bool isContainerOpen = false;
    704    mTreeView->IsContainerOpen(mRow, &isContainerOpen);
    705    if (isContainerOpen) {
    706      aName.AssignLiteral("collapse");
    707    } else {
    708      aName.AssignLiteral("expand");
    709    }
    710  }
    711 }
    712 
    713 bool XULTreeItemAccessibleBase::DoAction(uint8_t aIndex) const {
    714  if (aIndex != eAction_Click &&
    715      (aIndex != eAction_Expand || !IsExpandable())) {
    716    return false;
    717  }
    718 
    719  DoCommand(aIndex);
    720  return true;
    721 }
    722 
    723 ////////////////////////////////////////////////////////////////////////////////
    724 // XULTreeItemAccessibleBase: LocalAccessible implementation
    725 
    726 void XULTreeItemAccessibleBase::Shutdown() {
    727  mTree = nullptr;
    728  mTreeView = nullptr;
    729  mRow = -1;
    730  mParent = nullptr;  // null-out to prevent base class's shutdown ops
    731 
    732  AccessibleWrap::Shutdown();
    733 }
    734 
    735 GroupPos XULTreeItemAccessibleBase::GroupPosition() {
    736  GroupPos groupPos;
    737 
    738  int32_t level;
    739  nsresult rv = mTreeView->GetLevel(mRow, &level);
    740  NS_ENSURE_SUCCESS(rv, groupPos);
    741 
    742  int32_t topCount = 1;
    743  for (int32_t index = mRow - 1; index >= 0; index--) {
    744    int32_t lvl = -1;
    745    if (NS_SUCCEEDED(mTreeView->GetLevel(index, &lvl))) {
    746      if (lvl < level) break;
    747 
    748      if (lvl == level) topCount++;
    749    }
    750  }
    751 
    752  int32_t rowCount = 0;
    753  rv = mTreeView->GetRowCount(&rowCount);
    754  NS_ENSURE_SUCCESS(rv, groupPos);
    755 
    756  int32_t bottomCount = 0;
    757  for (int32_t index = mRow + 1; index < rowCount; index++) {
    758    int32_t lvl = -1;
    759    if (NS_SUCCEEDED(mTreeView->GetLevel(index, &lvl))) {
    760      if (lvl < level) break;
    761 
    762      if (lvl == level) bottomCount++;
    763    }
    764  }
    765 
    766  groupPos.level = level + 1;
    767  groupPos.setSize = topCount + bottomCount;
    768  groupPos.posInSet = topCount;
    769 
    770  return groupPos;
    771 }
    772 
    773 uint64_t XULTreeItemAccessibleBase::NativeState() const {
    774  // focusable and selectable states
    775  uint64_t state = NativeInteractiveState();
    776 
    777  // expanded/collapsed state
    778  if (IsExpandable()) {
    779    bool isContainerOpen;
    780    mTreeView->IsContainerOpen(mRow, &isContainerOpen);
    781    if (isContainerOpen) {
    782      state |= states::EXPANDED;
    783    }
    784 
    785    state |= states::EXPANDABLE;
    786  }
    787 
    788  // selected state
    789  nsCOMPtr<nsITreeSelection> selection;
    790  mTreeView->GetSelection(getter_AddRefs(selection));
    791  if (selection) {
    792    bool isSelected;
    793    selection->IsSelected(mRow, &isSelected);
    794    if (isSelected) state |= states::SELECTED;
    795  }
    796 
    797  // focused state
    798  if (FocusMgr()->IsFocused(this)) state |= states::FOCUSED;
    799 
    800  // invisible state
    801  int32_t firstVisibleRow = mTree->GetFirstVisibleRow();
    802  int32_t lastVisibleRow = mTree->GetLastVisibleRow();
    803  if (mRow < firstVisibleRow || mRow > lastVisibleRow) {
    804    state |= states::INVISIBLE;
    805  }
    806 
    807  return state;
    808 }
    809 
    810 uint64_t XULTreeItemAccessibleBase::NativeInteractiveState() const {
    811  return states::FOCUSABLE | states::SELECTABLE;
    812 }
    813 
    814 int32_t XULTreeItemAccessibleBase::IndexInParent() const {
    815  return mParent ? mParent->ContentChildCount() + mRow : -1;
    816 }
    817 
    818 ////////////////////////////////////////////////////////////////////////////////
    819 // XULTreeItemAccessibleBase: Widgets
    820 
    821 LocalAccessible* XULTreeItemAccessibleBase::ContainerWidget() const {
    822  return mParent;
    823 }
    824 
    825 ////////////////////////////////////////////////////////////////////////////////
    826 // XULTreeItemAccessibleBase: LocalAccessible protected methods
    827 
    828 void XULTreeItemAccessibleBase::DispatchClickEvent(
    829    uint32_t aActionIndex) const {
    830  if (IsDefunct()) return;
    831 
    832  RefPtr<nsTreeColumns> columns = mTree->GetColumns();
    833  if (!columns) return;
    834 
    835  // Get column and pseudo element.
    836  RefPtr<nsTreeColumn> column;
    837  nsAutoString pseudoElm;
    838 
    839  if (aActionIndex == eAction_Click) {
    840    // Key column is visible and clickable.
    841    column = columns->GetKeyColumn();
    842  } else {
    843    // Primary column contains a twisty we should click on.
    844    column = columns->GetPrimaryColumn();
    845    pseudoElm = u"twisty"_ns;
    846  }
    847 
    848  if (column) {
    849    RefPtr<dom::XULTreeElement> tree = mTree;
    850    nsCoreUtils::DispatchClickEvent(tree, mRow, column, pseudoElm);
    851  }
    852 }
    853 
    854 LocalAccessible* XULTreeItemAccessibleBase::GetSiblingAtOffset(
    855    int32_t aOffset, nsresult* aError) const {
    856  if (aError) *aError = NS_OK;  // fail peacefully
    857 
    858  return mParent->LocalChildAt(IndexInParent() + aOffset);
    859 }
    860 
    861 ////////////////////////////////////////////////////////////////////////////////
    862 // XULTreeItemAccessibleBase: protected implementation
    863 
    864 bool XULTreeItemAccessibleBase::IsExpandable() const {
    865  bool isContainer = false;
    866  mTreeView->IsContainer(mRow, &isContainer);
    867  if (isContainer) {
    868    bool isEmpty = false;
    869    mTreeView->IsContainerEmpty(mRow, &isEmpty);
    870    if (!isEmpty) {
    871      RefPtr<nsTreeColumns> columns = mTree->GetColumns();
    872      if (columns) {
    873        nsTreeColumn* primaryColumn = columns->GetPrimaryColumn();
    874        if (primaryColumn && !nsCoreUtils::IsColumnHidden(primaryColumn)) {
    875          return true;
    876        }
    877      }
    878    }
    879  }
    880 
    881  return false;
    882 }
    883 
    884 void XULTreeItemAccessibleBase::GetCellName(nsTreeColumn* aColumn,
    885                                            nsAString& aName) const {
    886  mTreeView->GetCellText(mRow, aColumn, aName);
    887 
    888  // If there is still no name try the cell value:
    889  // This is for graphical cells. We need tree/table view implementors to
    890  // implement FooView::GetCellValue to return a meaningful string for cases
    891  // where there is something shown in the cell (non-text) such as a star icon;
    892  // in which case GetCellValue for that cell would return "starred" or
    893  // "flagged" for example.
    894  if (aName.IsEmpty()) mTreeView->GetCellValue(mRow, aColumn, aName);
    895 }
    896 
    897 ////////////////////////////////////////////////////////////////////////////////
    898 // XULTreeItemAccessible
    899 ////////////////////////////////////////////////////////////////////////////////
    900 
    901 XULTreeItemAccessible::XULTreeItemAccessible(
    902    nsIContent* aContent, DocAccessible* aDoc, LocalAccessible* aParent,
    903    dom::XULTreeElement* aTree, nsITreeView* aTreeView, int32_t aRow)
    904    : XULTreeItemAccessibleBase(aContent, aDoc, aParent, aTree, aTreeView,
    905                                aRow) {
    906  mStateFlags |= eNoKidsFromDOM;
    907  mColumn = nsCoreUtils::GetFirstSensibleColumn(mTree, FlushType::None);
    908  GetCellName(mColumn, mCachedName);
    909 }
    910 
    911 XULTreeItemAccessible::~XULTreeItemAccessible() {}
    912 
    913 ////////////////////////////////////////////////////////////////////////////////
    914 // XULTreeItemAccessible: nsISupports implementation
    915 
    916 NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeItemAccessible,
    917                                   XULTreeItemAccessibleBase, mColumn)
    918 
    919 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XULTreeItemAccessible)
    920 NS_INTERFACE_MAP_END_INHERITING(XULTreeItemAccessibleBase)
    921 NS_IMPL_ADDREF_INHERITED(XULTreeItemAccessible, XULTreeItemAccessibleBase)
    922 NS_IMPL_RELEASE_INHERITED(XULTreeItemAccessible, XULTreeItemAccessibleBase)
    923 
    924 ////////////////////////////////////////////////////////////////////////////////
    925 // XULTreeItemAccessible: nsIAccessible implementation
    926 
    927 ENameValueFlag XULTreeItemAccessible::DirectName(nsString& aName) const {
    928  aName.Truncate();
    929 
    930  GetCellName(mColumn, aName);
    931  return eNameOK;
    932 }
    933 
    934 ////////////////////////////////////////////////////////////////////////////////
    935 // XULTreeItemAccessible: LocalAccessible implementation
    936 
    937 void XULTreeItemAccessible::Shutdown() {
    938  mColumn = nullptr;
    939  XULTreeItemAccessibleBase::Shutdown();
    940 }
    941 
    942 role XULTreeItemAccessible::NativeRole() const {
    943  RefPtr<nsTreeColumns> columns = mTree->GetColumns();
    944  if (!columns) {
    945    NS_ERROR("No tree columns object in the tree!");
    946    return roles::NOTHING;
    947  }
    948 
    949  nsTreeColumn* primaryColumn = columns->GetPrimaryColumn();
    950 
    951  return primaryColumn ? roles::OUTLINEITEM : roles::LISTITEM;
    952 }
    953 
    954 ////////////////////////////////////////////////////////////////////////////////
    955 // XULTreeItemAccessible: XULTreeItemAccessibleBase implementation
    956 
    957 void XULTreeItemAccessible::RowInvalidated(int32_t aStartColIdx,
    958                                           int32_t aEndColIdx) {
    959  nsAutoString name;
    960  Name(name);
    961 
    962  if (name != mCachedName) {
    963    nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this);
    964    mCachedName = name;
    965  }
    966 }
    967 
    968 ////////////////////////////////////////////////////////////////////////////////
    969 //  XULTreeColumAccessible
    970 ////////////////////////////////////////////////////////////////////////////////
    971 
    972 XULTreeColumAccessible::XULTreeColumAccessible(nsIContent* aContent,
    973                                               DocAccessible* aDoc)
    974    : XULColumAccessible(aContent, aDoc) {}
    975 
    976 LocalAccessible* XULTreeColumAccessible::GetSiblingAtOffset(
    977    int32_t aOffset, nsresult* aError) const {
    978  if (aOffset < 0) {
    979    return XULColumAccessible::GetSiblingAtOffset(aOffset, aError);
    980  }
    981 
    982  if (aError) *aError = NS_OK;  // fail peacefully
    983 
    984  RefPtr<dom::XULTreeElement> tree = nsCoreUtils::GetTree(mContent);
    985  if (tree) {
    986    nsCOMPtr<nsITreeView> treeView = tree->GetView(FlushType::None);
    987    if (treeView) {
    988      int32_t rowCount = 0;
    989      treeView->GetRowCount(&rowCount);
    990      if (rowCount > 0 && aOffset <= rowCount) {
    991        XULTreeAccessible* treeAcc = LocalParent()->AsXULTree();
    992 
    993        if (treeAcc) return treeAcc->GetTreeItemAccessible(aOffset - 1);
    994      }
    995    }
    996  }
    997 
    998  return nullptr;
    999 }