tor-browser

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

XULListboxAccessible.cpp (14879B)


      1 /* -*- Mode: C++; tab-width: 4; 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 "XULListboxAccessible.h"
      7 
      8 #include "LocalAccessible-inl.h"
      9 #include "nsAccessibilityService.h"
     10 #include "nsAccUtils.h"
     11 #include "DocAccessible.h"
     12 #include "mozilla/a11y/Role.h"
     13 #include "States.h"
     14 
     15 #include "nsComponentManagerUtils.h"
     16 #include "nsIAutoCompletePopup.h"
     17 #include "nsIDOMXULMenuListElement.h"
     18 #include "nsIDOMXULMultSelectCntrlEl.h"
     19 #include "nsIDOMXULSelectCntrlItemEl.h"
     20 #include "nsINodeList.h"
     21 
     22 using namespace mozilla::a11y;
     23 
     24 ////////////////////////////////////////////////////////////////////////////////
     25 // XULColumAccessible
     26 ////////////////////////////////////////////////////////////////////////////////
     27 
     28 XULColumAccessible::XULColumAccessible(nsIContent* aContent,
     29                                       DocAccessible* aDoc)
     30    : AccessibleWrap(aContent, aDoc) {}
     31 
     32 role XULColumAccessible::NativeRole() const { return roles::LIST; }
     33 
     34 uint64_t XULColumAccessible::NativeState() const { return states::READONLY; }
     35 
     36 ////////////////////////////////////////////////////////////////////////////////
     37 // XULColumnItemAccessible
     38 ////////////////////////////////////////////////////////////////////////////////
     39 
     40 XULColumnItemAccessible::XULColumnItemAccessible(nsIContent* aContent,
     41                                                 DocAccessible* aDoc)
     42    : LeafAccessible(aContent, aDoc) {}
     43 
     44 role XULColumnItemAccessible::NativeRole() const { return roles::COLUMNHEADER; }
     45 
     46 uint64_t XULColumnItemAccessible::NativeState() const {
     47  return states::READONLY;
     48 }
     49 
     50 bool XULColumnItemAccessible::HasPrimaryAction() const { return true; }
     51 
     52 void XULColumnItemAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName) {
     53  if (aIndex == eAction_Click) aName.AssignLiteral("click");
     54 }
     55 
     56 ////////////////////////////////////////////////////////////////////////////////
     57 // XULListboxAccessible
     58 ////////////////////////////////////////////////////////////////////////////////
     59 
     60 XULListboxAccessible::XULListboxAccessible(nsIContent* aContent,
     61                                           DocAccessible* aDoc)
     62    : XULSelectControlAccessible(aContent, aDoc) {
     63  dom::Element* parentEl = mContent->GetParentElement();
     64  if (parentEl) {
     65    nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
     66        parentEl->AsAutoCompletePopup();
     67    if (autoCompletePopupElm) mGenericTypes |= eAutoCompletePopup;
     68  }
     69 
     70  if (IsMulticolumn()) mGenericTypes |= eTable;
     71 }
     72 
     73 ////////////////////////////////////////////////////////////////////////////////
     74 // XULListboxAccessible: LocalAccessible
     75 
     76 uint64_t XULListboxAccessible::NativeState() const {
     77  // As a XULListboxAccessible we can have the following states:
     78  //   FOCUSED, READONLY, FOCUSABLE
     79 
     80  // Get focus status from base class
     81  uint64_t states = LocalAccessible::NativeState();
     82 
     83  // see if we are multiple select if so set ourselves as such
     84 
     85  if (mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::seltype,
     86                                         nsGkAtoms::multiple, eCaseMatters)) {
     87    states |= states::MULTISELECTABLE | states::EXTSELECTABLE;
     88  }
     89 
     90  return states;
     91 }
     92 
     93 role XULListboxAccessible::NativeRole() const {
     94  // A richlistbox is used with the new autocomplete URL bar, and has a parent
     95  // popup <panel>.
     96  if (mContent->GetParent() &&
     97      mContent->GetParent()->IsXULElement(nsGkAtoms::panel)) {
     98    return roles::COMBOBOX_LIST;
     99  }
    100 
    101  return IsMulticolumn() ? roles::TABLE : roles::LISTBOX;
    102 }
    103 
    104 ////////////////////////////////////////////////////////////////////////////////
    105 // XULListboxAccessible: Table
    106 
    107 uint32_t XULListboxAccessible::ColCount() const { return 0; }
    108 
    109 uint32_t XULListboxAccessible::RowCount() {
    110  nsCOMPtr<nsIDOMXULSelectControlElement> element = Elm()->AsXULSelectControl();
    111 
    112  uint32_t itemCount = 0;
    113  if (element) element->GetItemCount(&itemCount);
    114 
    115  return itemCount;
    116 }
    117 
    118 LocalAccessible* XULListboxAccessible::CellAt(uint32_t aRowIndex,
    119                                              uint32_t aColumnIndex) {
    120  nsCOMPtr<nsIDOMXULSelectControlElement> control = Elm()->AsXULSelectControl();
    121  NS_ENSURE_TRUE(control, nullptr);
    122 
    123  RefPtr<dom::Element> element;
    124  control->GetItemAtIndex(aRowIndex, getter_AddRefs(element));
    125  if (!element) return nullptr;
    126 
    127  LocalAccessible* row = mDoc->GetAccessible(element);
    128  NS_ENSURE_TRUE(row, nullptr);
    129 
    130  return row->LocalChildAt(aColumnIndex);
    131 }
    132 
    133 bool XULListboxAccessible::IsColSelected(uint32_t aColIdx) {
    134  nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
    135      Elm()->AsXULMultiSelectControl();
    136  NS_ASSERTION(control,
    137               "Doesn't implement nsIDOMXULMultiSelectControlElement.");
    138 
    139  int32_t selectedrowCount = 0;
    140  nsresult rv = control->GetSelectedCount(&selectedrowCount);
    141  NS_ENSURE_SUCCESS(rv, false);
    142 
    143  return selectedrowCount == static_cast<int32_t>(RowCount());
    144 }
    145 
    146 bool XULListboxAccessible::IsRowSelected(uint32_t aRowIdx) {
    147  nsCOMPtr<nsIDOMXULSelectControlElement> control = Elm()->AsXULSelectControl();
    148  NS_ASSERTION(control, "Doesn't implement nsIDOMXULSelectControlElement.");
    149 
    150  RefPtr<dom::Element> element;
    151  nsresult rv = control->GetItemAtIndex(aRowIdx, getter_AddRefs(element));
    152  NS_ENSURE_SUCCESS(rv, false);
    153  if (!element) {
    154    return false;
    155  }
    156 
    157  nsCOMPtr<nsIDOMXULSelectControlItemElement> item =
    158      element->AsXULSelectControlItem();
    159 
    160  bool isSelected = false;
    161  item->GetSelected(&isSelected);
    162  return isSelected;
    163 }
    164 
    165 bool XULListboxAccessible::IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx) {
    166  return IsRowSelected(aRowIdx);
    167 }
    168 
    169 uint32_t XULListboxAccessible::SelectedCellCount() {
    170  nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
    171      Elm()->AsXULMultiSelectControl();
    172  NS_ASSERTION(control,
    173               "Doesn't implement nsIDOMXULMultiSelectControlElement.");
    174 
    175  nsCOMPtr<nsINodeList> selectedItems;
    176  control->GetSelectedItems(getter_AddRefs(selectedItems));
    177  if (!selectedItems) return 0;
    178 
    179  uint32_t selectedItemsCount = selectedItems->Length();
    180 
    181  return selectedItemsCount * ColCount();
    182 }
    183 
    184 uint32_t XULListboxAccessible::SelectedColCount() {
    185  nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
    186      Elm()->AsXULMultiSelectControl();
    187  NS_ASSERTION(control,
    188               "Doesn't implement nsIDOMXULMultiSelectControlElement.");
    189 
    190  int32_t selectedRowCount = 0;
    191  nsresult rv = control->GetSelectedCount(&selectedRowCount);
    192  NS_ENSURE_SUCCESS(rv, 0);
    193 
    194  return selectedRowCount > 0 &&
    195                 selectedRowCount == static_cast<int32_t>(RowCount())
    196             ? ColCount()
    197             : 0;
    198 }
    199 
    200 uint32_t XULListboxAccessible::SelectedRowCount() {
    201  nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
    202      Elm()->AsXULMultiSelectControl();
    203  NS_ASSERTION(control,
    204               "Doesn't implement nsIDOMXULMultiSelectControlElement.");
    205 
    206  int32_t selectedRowCount = 0;
    207  nsresult rv = control->GetSelectedCount(&selectedRowCount);
    208  NS_ENSURE_SUCCESS(rv, 0);
    209 
    210  return selectedRowCount >= 0 ? selectedRowCount : 0;
    211 }
    212 
    213 void XULListboxAccessible::SelectedCells(nsTArray<Accessible*>* aCells) {
    214  nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
    215      Elm()->AsXULMultiSelectControl();
    216  NS_ASSERTION(control,
    217               "Doesn't implement nsIDOMXULMultiSelectControlElement.");
    218 
    219  nsCOMPtr<nsINodeList> selectedItems;
    220  control->GetSelectedItems(getter_AddRefs(selectedItems));
    221  if (!selectedItems) return;
    222 
    223  uint32_t selectedItemsCount = selectedItems->Length();
    224 
    225  for (uint32_t index = 0; index < selectedItemsCount; index++) {
    226    nsIContent* itemContent = selectedItems->Item(index);
    227    LocalAccessible* item = mDoc->GetAccessible(itemContent);
    228 
    229    if (item) {
    230      uint32_t cellCount = item->ChildCount();
    231      for (uint32_t cellIdx = 0; cellIdx < cellCount; cellIdx++) {
    232        LocalAccessible* cell = mChildren[cellIdx];
    233        if (cell->Role() == roles::CELL) aCells->AppendElement(cell);
    234      }
    235    }
    236  }
    237 }
    238 
    239 void XULListboxAccessible::SelectedCellIndices(nsTArray<uint32_t>* aCells) {
    240  nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
    241      Elm()->AsXULMultiSelectControl();
    242  NS_ASSERTION(control,
    243               "Doesn't implement nsIDOMXULMultiSelectControlElement.");
    244 
    245  nsCOMPtr<nsINodeList> selectedItems;
    246  control->GetSelectedItems(getter_AddRefs(selectedItems));
    247  if (!selectedItems) return;
    248 
    249  uint32_t selectedItemsCount = selectedItems->Length();
    250 
    251  uint32_t colCount = ColCount();
    252  aCells->SetCapacity(selectedItemsCount * colCount);
    253  aCells->AppendElements(selectedItemsCount * colCount);
    254 
    255  for (uint32_t selItemsIdx = 0, cellsIdx = 0; selItemsIdx < selectedItemsCount;
    256       selItemsIdx++) {
    257    nsIContent* itemContent = selectedItems->Item(selItemsIdx);
    258 
    259    nsCOMPtr<nsIDOMXULSelectControlItemElement> item =
    260        itemContent->AsElement()->AsXULSelectControlItem();
    261    if (item) {
    262      int32_t itemIdx = -1;
    263      control->GetIndexOfItem(item, &itemIdx);
    264      if (itemIdx >= 0) {
    265        for (uint32_t colIdx = 0; colIdx < colCount; colIdx++, cellsIdx++) {
    266          aCells->ElementAt(cellsIdx) = itemIdx * colCount + colIdx;
    267        }
    268      }
    269    }
    270  }
    271 }
    272 
    273 void XULListboxAccessible::SelectedColIndices(nsTArray<uint32_t>* aCols) {
    274  uint32_t selColCount = SelectedColCount();
    275  aCols->SetCapacity(selColCount);
    276 
    277  for (uint32_t colIdx = 0; colIdx < selColCount; colIdx++) {
    278    aCols->AppendElement(colIdx);
    279  }
    280 }
    281 
    282 void XULListboxAccessible::SelectedRowIndices(nsTArray<uint32_t>* aRows) {
    283  nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
    284      Elm()->AsXULMultiSelectControl();
    285  NS_ASSERTION(control,
    286               "Doesn't implement nsIDOMXULMultiSelectControlElement.");
    287 
    288  nsCOMPtr<nsINodeList> selectedItems;
    289  control->GetSelectedItems(getter_AddRefs(selectedItems));
    290  if (!selectedItems) return;
    291 
    292  uint32_t rowCount = selectedItems->Length();
    293 
    294  if (!rowCount) return;
    295 
    296  aRows->SetCapacity(rowCount);
    297  aRows->AppendElements(rowCount);
    298 
    299  for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
    300    nsIContent* itemContent = selectedItems->Item(rowIdx);
    301    nsCOMPtr<nsIDOMXULSelectControlItemElement> item =
    302        itemContent->AsElement()->AsXULSelectControlItem();
    303 
    304    if (item) {
    305      int32_t itemIdx = -1;
    306      control->GetIndexOfItem(item, &itemIdx);
    307      if (itemIdx >= 0) aRows->ElementAt(rowIdx) = itemIdx;
    308    }
    309  }
    310 }
    311 
    312 ////////////////////////////////////////////////////////////////////////////////
    313 // XULListboxAccessible: Widgets
    314 
    315 bool XULListboxAccessible::IsWidget() const { return true; }
    316 
    317 bool XULListboxAccessible::IsActiveWidget() const {
    318  if (IsAutoCompletePopup()) {
    319    nsIContent* parentContent = mContent->GetParent();
    320    if (parentContent) {
    321      nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
    322          parentContent->AsElement()->AsAutoCompletePopup();
    323      if (autoCompletePopupElm) {
    324        bool isOpen = false;
    325        autoCompletePopupElm->GetPopupOpen(&isOpen);
    326        return isOpen;
    327      }
    328    }
    329  }
    330  return FocusMgr()->HasDOMFocus(mContent);
    331 }
    332 
    333 bool XULListboxAccessible::AreItemsOperable() const {
    334  if (IsAutoCompletePopup()) {
    335    nsIContent* parentContent = mContent->GetParent();
    336    if (parentContent) {
    337      nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
    338          parentContent->AsElement()->AsAutoCompletePopup();
    339      if (autoCompletePopupElm) {
    340        bool isOpen = false;
    341        autoCompletePopupElm->GetPopupOpen(&isOpen);
    342        return isOpen;
    343      }
    344    }
    345  }
    346  return true;
    347 }
    348 
    349 LocalAccessible* XULListboxAccessible::ContainerWidget() const {
    350  return nullptr;
    351 }
    352 
    353 ////////////////////////////////////////////////////////////////////////////////
    354 // XULListitemAccessible
    355 ////////////////////////////////////////////////////////////////////////////////
    356 
    357 XULListitemAccessible::XULListitemAccessible(nsIContent* aContent,
    358                                             DocAccessible* aDoc)
    359    : XULMenuitemAccessible(aContent, aDoc) {
    360  mIsCheckbox = mContent->AsElement()->AttrValueIs(
    361      kNameSpaceID_None, nsGkAtoms::type, nsGkAtoms::checkbox, eCaseMatters);
    362  mType = eXULListItemType;
    363 }
    364 
    365 XULListitemAccessible::~XULListitemAccessible() {}
    366 
    367 LocalAccessible* XULListitemAccessible::GetListAccessible() const {
    368  if (IsDefunct()) return nullptr;
    369 
    370  nsCOMPtr<nsIDOMXULSelectControlItemElement> listItem =
    371      Elm()->AsXULSelectControlItem();
    372  if (!listItem) return nullptr;
    373 
    374  RefPtr<dom::Element> listElement;
    375  listItem->GetControl(getter_AddRefs(listElement));
    376  if (!listElement) return nullptr;
    377 
    378  return mDoc->GetAccessible(listElement);
    379 }
    380 
    381 ////////////////////////////////////////////////////////////////////////////////
    382 // XULListitemAccessible LocalAccessible
    383 
    384 EDescriptionValueFlag XULListitemAccessible::Description(
    385    nsString& aDesc) const {
    386  return AccessibleWrap::Description(aDesc);
    387 }
    388 
    389 ////////////////////////////////////////////////////////////////////////////////
    390 // XULListitemAccessible: LocalAccessible
    391 
    392 /**
    393 * Get the name from GetXULName.
    394 */
    395 ENameValueFlag XULListitemAccessible::NativeName(nsString& aName) const {
    396  return LocalAccessible::NativeName(aName);
    397 }
    398 
    399 role XULListitemAccessible::NativeRole() const {
    400  LocalAccessible* list = GetListAccessible();
    401  if (!list) {
    402    NS_ERROR("No list accessible for listitem accessible!");
    403    return roles::NOTHING;
    404  }
    405 
    406  if (list->Role() == roles::TABLE) return roles::ROW;
    407 
    408  if (mIsCheckbox) return roles::CHECK_RICH_OPTION;
    409 
    410  if (mParent && mParent->Role() == roles::COMBOBOX_LIST) {
    411    return roles::COMBOBOX_OPTION;
    412  }
    413 
    414  return roles::RICH_OPTION;
    415 }
    416 
    417 uint64_t XULListitemAccessible::NativeState() const {
    418  if (mIsCheckbox) return XULMenuitemAccessible::NativeState();
    419 
    420  uint64_t states = NativeInteractiveState();
    421 
    422  nsCOMPtr<nsIDOMXULSelectControlItemElement> listItem =
    423      Elm()->AsXULSelectControlItem();
    424  if (listItem) {
    425    bool isSelected;
    426    listItem->GetSelected(&isSelected);
    427    if (isSelected) states |= states::SELECTED;
    428 
    429    if (FocusMgr()->IsFocused(this)) states |= states::FOCUSED;
    430  }
    431 
    432  return states;
    433 }
    434 
    435 uint64_t XULListitemAccessible::NativeInteractiveState() const {
    436  return NativelyUnavailable() || (mParent && mParent->NativelyUnavailable())
    437             ? states::UNAVAILABLE
    438             : states::FOCUSABLE | states::SELECTABLE;
    439 }
    440 
    441 void XULListitemAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName) {
    442  if (aIndex == eAction_Click && mIsCheckbox) {
    443    uint64_t states = NativeState();
    444    if (states & states::CHECKED) {
    445      aName.AssignLiteral("uncheck");
    446    } else {
    447      aName.AssignLiteral("check");
    448    }
    449  }
    450 }
    451 
    452 ////////////////////////////////////////////////////////////////////////////////
    453 // XULListitemAccessible: Widgets
    454 
    455 LocalAccessible* XULListitemAccessible::ContainerWidget() const {
    456  return LocalParent();
    457 }