ARIAGridAccessible.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "ARIAGridAccessible-inl.h"
  6. #include "Accessible-inl.h"
  7. #include "AccIterator.h"
  8. #include "nsAccUtils.h"
  9. #include "Role.h"
  10. #include "States.h"
  11. #include "nsIMutableArray.h"
  12. #include "nsIPersistentProperties2.h"
  13. #include "nsComponentManagerUtils.h"
  14. using namespace mozilla;
  15. using namespace mozilla::a11y;
  16. ////////////////////////////////////////////////////////////////////////////////
  17. // ARIAGridAccessible
  18. ////////////////////////////////////////////////////////////////////////////////
  19. ////////////////////////////////////////////////////////////////////////////////
  20. // Constructor
  21. ARIAGridAccessible::
  22. ARIAGridAccessible(nsIContent* aContent, DocAccessible* aDoc) :
  23. AccessibleWrap(aContent, aDoc)
  24. {
  25. }
  26. NS_IMPL_ISUPPORTS_INHERITED0(ARIAGridAccessible, Accessible)
  27. ////////////////////////////////////////////////////////////////////////////////
  28. // Table
  29. uint32_t
  30. ARIAGridAccessible::ColCount()
  31. {
  32. AccIterator rowIter(this, filters::GetRow);
  33. Accessible* row = rowIter.Next();
  34. if (!row)
  35. return 0;
  36. AccIterator cellIter(row, filters::GetCell);
  37. Accessible* cell = nullptr;
  38. uint32_t colCount = 0;
  39. while ((cell = cellIter.Next()))
  40. colCount++;
  41. return colCount;
  42. }
  43. uint32_t
  44. ARIAGridAccessible::RowCount()
  45. {
  46. uint32_t rowCount = 0;
  47. AccIterator rowIter(this, filters::GetRow);
  48. while (rowIter.Next())
  49. rowCount++;
  50. return rowCount;
  51. }
  52. Accessible*
  53. ARIAGridAccessible::CellAt(uint32_t aRowIndex, uint32_t aColumnIndex)
  54. {
  55. Accessible* row = GetRowAt(aRowIndex);
  56. if (!row)
  57. return nullptr;
  58. return GetCellInRowAt(row, aColumnIndex);
  59. }
  60. bool
  61. ARIAGridAccessible::IsColSelected(uint32_t aColIdx)
  62. {
  63. if (IsARIARole(nsGkAtoms::table))
  64. return false;
  65. AccIterator rowIter(this, filters::GetRow);
  66. Accessible* row = rowIter.Next();
  67. if (!row)
  68. return false;
  69. do {
  70. if (!nsAccUtils::IsARIASelected(row)) {
  71. Accessible* cell = GetCellInRowAt(row, aColIdx);
  72. if (!cell || !nsAccUtils::IsARIASelected(cell))
  73. return false;
  74. }
  75. } while ((row = rowIter.Next()));
  76. return true;
  77. }
  78. bool
  79. ARIAGridAccessible::IsRowSelected(uint32_t aRowIdx)
  80. {
  81. if (IsARIARole(nsGkAtoms::table))
  82. return false;
  83. Accessible* row = GetRowAt(aRowIdx);
  84. if(!row)
  85. return false;
  86. if (!nsAccUtils::IsARIASelected(row)) {
  87. AccIterator cellIter(row, filters::GetCell);
  88. Accessible* cell = nullptr;
  89. while ((cell = cellIter.Next())) {
  90. if (!nsAccUtils::IsARIASelected(cell))
  91. return false;
  92. }
  93. }
  94. return true;
  95. }
  96. bool
  97. ARIAGridAccessible::IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx)
  98. {
  99. if (IsARIARole(nsGkAtoms::table))
  100. return false;
  101. Accessible* row = GetRowAt(aRowIdx);
  102. if(!row)
  103. return false;
  104. if (!nsAccUtils::IsARIASelected(row)) {
  105. Accessible* cell = GetCellInRowAt(row, aColIdx);
  106. if (!cell || !nsAccUtils::IsARIASelected(cell))
  107. return false;
  108. }
  109. return true;
  110. }
  111. uint32_t
  112. ARIAGridAccessible::SelectedCellCount()
  113. {
  114. if (IsARIARole(nsGkAtoms::table))
  115. return 0;
  116. uint32_t count = 0, colCount = ColCount();
  117. AccIterator rowIter(this, filters::GetRow);
  118. Accessible* row = nullptr;
  119. while ((row = rowIter.Next())) {
  120. if (nsAccUtils::IsARIASelected(row)) {
  121. count += colCount;
  122. continue;
  123. }
  124. AccIterator cellIter(row, filters::GetCell);
  125. Accessible* cell = nullptr;
  126. while ((cell = cellIter.Next())) {
  127. if (nsAccUtils::IsARIASelected(cell))
  128. count++;
  129. }
  130. }
  131. return count;
  132. }
  133. uint32_t
  134. ARIAGridAccessible::SelectedColCount()
  135. {
  136. if (IsARIARole(nsGkAtoms::table))
  137. return 0;
  138. uint32_t colCount = ColCount();
  139. if (!colCount)
  140. return 0;
  141. AccIterator rowIter(this, filters::GetRow);
  142. Accessible* row = rowIter.Next();
  143. if (!row)
  144. return 0;
  145. nsTArray<bool> isColSelArray(colCount);
  146. isColSelArray.AppendElements(colCount);
  147. memset(isColSelArray.Elements(), true, colCount * sizeof(bool));
  148. uint32_t selColCount = colCount;
  149. do {
  150. if (nsAccUtils::IsARIASelected(row))
  151. continue;
  152. AccIterator cellIter(row, filters::GetCell);
  153. Accessible* cell = nullptr;
  154. for (uint32_t colIdx = 0;
  155. (cell = cellIter.Next()) && colIdx < colCount; colIdx++)
  156. if (isColSelArray[colIdx] && !nsAccUtils::IsARIASelected(cell)) {
  157. isColSelArray[colIdx] = false;
  158. selColCount--;
  159. }
  160. } while ((row = rowIter.Next()));
  161. return selColCount;
  162. }
  163. uint32_t
  164. ARIAGridAccessible::SelectedRowCount()
  165. {
  166. if (IsARIARole(nsGkAtoms::table))
  167. return 0;
  168. uint32_t count = 0;
  169. AccIterator rowIter(this, filters::GetRow);
  170. Accessible* row = nullptr;
  171. while ((row = rowIter.Next())) {
  172. if (nsAccUtils::IsARIASelected(row)) {
  173. count++;
  174. continue;
  175. }
  176. AccIterator cellIter(row, filters::GetCell);
  177. Accessible* cell = cellIter.Next();
  178. if (!cell)
  179. continue;
  180. bool isRowSelected = true;
  181. do {
  182. if (!nsAccUtils::IsARIASelected(cell)) {
  183. isRowSelected = false;
  184. break;
  185. }
  186. } while ((cell = cellIter.Next()));
  187. if (isRowSelected)
  188. count++;
  189. }
  190. return count;
  191. }
  192. void
  193. ARIAGridAccessible::SelectedCells(nsTArray<Accessible*>* aCells)
  194. {
  195. if (IsARIARole(nsGkAtoms::table))
  196. return;
  197. AccIterator rowIter(this, filters::GetRow);
  198. Accessible* row = nullptr;
  199. while ((row = rowIter.Next())) {
  200. AccIterator cellIter(row, filters::GetCell);
  201. Accessible* cell = nullptr;
  202. if (nsAccUtils::IsARIASelected(row)) {
  203. while ((cell = cellIter.Next()))
  204. aCells->AppendElement(cell);
  205. continue;
  206. }
  207. while ((cell = cellIter.Next())) {
  208. if (nsAccUtils::IsARIASelected(cell))
  209. aCells->AppendElement(cell);
  210. }
  211. }
  212. }
  213. void
  214. ARIAGridAccessible::SelectedCellIndices(nsTArray<uint32_t>* aCells)
  215. {
  216. if (IsARIARole(nsGkAtoms::table))
  217. return;
  218. uint32_t colCount = ColCount();
  219. AccIterator rowIter(this, filters::GetRow);
  220. Accessible* row = nullptr;
  221. for (uint32_t rowIdx = 0; (row = rowIter.Next()); rowIdx++) {
  222. if (nsAccUtils::IsARIASelected(row)) {
  223. for (uint32_t colIdx = 0; colIdx < colCount; colIdx++)
  224. aCells->AppendElement(rowIdx * colCount + colIdx);
  225. continue;
  226. }
  227. AccIterator cellIter(row, filters::GetCell);
  228. Accessible* cell = nullptr;
  229. for (uint32_t colIdx = 0; (cell = cellIter.Next()); colIdx++) {
  230. if (nsAccUtils::IsARIASelected(cell))
  231. aCells->AppendElement(rowIdx * colCount + colIdx);
  232. }
  233. }
  234. }
  235. void
  236. ARIAGridAccessible::SelectedColIndices(nsTArray<uint32_t>* aCols)
  237. {
  238. if (IsARIARole(nsGkAtoms::table))
  239. return;
  240. uint32_t colCount = ColCount();
  241. if (!colCount)
  242. return;
  243. AccIterator rowIter(this, filters::GetRow);
  244. Accessible* row = rowIter.Next();
  245. if (!row)
  246. return;
  247. nsTArray<bool> isColSelArray(colCount);
  248. isColSelArray.AppendElements(colCount);
  249. memset(isColSelArray.Elements(), true, colCount * sizeof(bool));
  250. do {
  251. if (nsAccUtils::IsARIASelected(row))
  252. continue;
  253. AccIterator cellIter(row, filters::GetCell);
  254. Accessible* cell = nullptr;
  255. for (uint32_t colIdx = 0;
  256. (cell = cellIter.Next()) && colIdx < colCount; colIdx++)
  257. if (isColSelArray[colIdx] && !nsAccUtils::IsARIASelected(cell)) {
  258. isColSelArray[colIdx] = false;
  259. }
  260. } while ((row = rowIter.Next()));
  261. for (uint32_t colIdx = 0; colIdx < colCount; colIdx++)
  262. if (isColSelArray[colIdx])
  263. aCols->AppendElement(colIdx);
  264. }
  265. void
  266. ARIAGridAccessible::SelectedRowIndices(nsTArray<uint32_t>* aRows)
  267. {
  268. if (IsARIARole(nsGkAtoms::table))
  269. return;
  270. AccIterator rowIter(this, filters::GetRow);
  271. Accessible* row = nullptr;
  272. for (uint32_t rowIdx = 0; (row = rowIter.Next()); rowIdx++) {
  273. if (nsAccUtils::IsARIASelected(row)) {
  274. aRows->AppendElement(rowIdx);
  275. continue;
  276. }
  277. AccIterator cellIter(row, filters::GetCell);
  278. Accessible* cell = cellIter.Next();
  279. if (!cell)
  280. continue;
  281. bool isRowSelected = true;
  282. do {
  283. if (!nsAccUtils::IsARIASelected(cell)) {
  284. isRowSelected = false;
  285. break;
  286. }
  287. } while ((cell = cellIter.Next()));
  288. if (isRowSelected)
  289. aRows->AppendElement(rowIdx);
  290. }
  291. }
  292. void
  293. ARIAGridAccessible::SelectRow(uint32_t aRowIdx)
  294. {
  295. if (IsARIARole(nsGkAtoms::table))
  296. return;
  297. AccIterator rowIter(this, filters::GetRow);
  298. Accessible* row = nullptr;
  299. for (uint32_t rowIdx = 0; (row = rowIter.Next()); rowIdx++) {
  300. DebugOnly<nsresult> rv = SetARIASelected(row, rowIdx == aRowIdx);
  301. NS_ASSERTION(NS_SUCCEEDED(rv), "SetARIASelected() Shouldn't fail!");
  302. }
  303. }
  304. void
  305. ARIAGridAccessible::SelectCol(uint32_t aColIdx)
  306. {
  307. if (IsARIARole(nsGkAtoms::table))
  308. return;
  309. AccIterator rowIter(this, filters::GetRow);
  310. Accessible* row = nullptr;
  311. while ((row = rowIter.Next())) {
  312. // Unselect all cells in the row.
  313. DebugOnly<nsresult> rv = SetARIASelected(row, false);
  314. NS_ASSERTION(NS_SUCCEEDED(rv), "SetARIASelected() Shouldn't fail!");
  315. // Select cell at the column index.
  316. Accessible* cell = GetCellInRowAt(row, aColIdx);
  317. if (cell)
  318. SetARIASelected(cell, true);
  319. }
  320. }
  321. void
  322. ARIAGridAccessible::UnselectRow(uint32_t aRowIdx)
  323. {
  324. if (IsARIARole(nsGkAtoms::table))
  325. return;
  326. Accessible* row = GetRowAt(aRowIdx);
  327. if (row)
  328. SetARIASelected(row, false);
  329. }
  330. void
  331. ARIAGridAccessible::UnselectCol(uint32_t aColIdx)
  332. {
  333. if (IsARIARole(nsGkAtoms::table))
  334. return;
  335. AccIterator rowIter(this, filters::GetRow);
  336. Accessible* row = nullptr;
  337. while ((row = rowIter.Next())) {
  338. Accessible* cell = GetCellInRowAt(row, aColIdx);
  339. if (cell)
  340. SetARIASelected(cell, false);
  341. }
  342. }
  343. ////////////////////////////////////////////////////////////////////////////////
  344. // Protected
  345. Accessible*
  346. ARIAGridAccessible::GetRowAt(int32_t aRow)
  347. {
  348. int32_t rowIdx = aRow;
  349. AccIterator rowIter(this, filters::GetRow);
  350. Accessible* row = rowIter.Next();
  351. while (rowIdx != 0 && (row = rowIter.Next()))
  352. rowIdx--;
  353. return row;
  354. }
  355. Accessible*
  356. ARIAGridAccessible::GetCellInRowAt(Accessible* aRow, int32_t aColumn)
  357. {
  358. int32_t colIdx = aColumn;
  359. AccIterator cellIter(aRow, filters::GetCell);
  360. Accessible* cell = cellIter.Next();
  361. while (colIdx != 0 && (cell = cellIter.Next()))
  362. colIdx--;
  363. return cell;
  364. }
  365. nsresult
  366. ARIAGridAccessible::SetARIASelected(Accessible* aAccessible,
  367. bool aIsSelected, bool aNotify)
  368. {
  369. if (IsARIARole(nsGkAtoms::table))
  370. return NS_OK;
  371. nsIContent *content = aAccessible->GetContent();
  372. NS_ENSURE_STATE(content);
  373. nsresult rv = NS_OK;
  374. if (aIsSelected)
  375. rv = content->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected,
  376. NS_LITERAL_STRING("true"), aNotify);
  377. else
  378. rv = content->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected,
  379. NS_LITERAL_STRING("false"), aNotify);
  380. NS_ENSURE_SUCCESS(rv, rv);
  381. // No "smart" select/unselect for internal call.
  382. if (!aNotify)
  383. return NS_OK;
  384. // If row or cell accessible was selected then we're able to not bother about
  385. // selection of its cells or its row because our algorithm is row oriented,
  386. // i.e. we check selection on row firstly and then on cells.
  387. if (aIsSelected)
  388. return NS_OK;
  389. roles::Role role = aAccessible->Role();
  390. // If the given accessible is row that was unselected then remove
  391. // aria-selected from cell accessible.
  392. if (role == roles::ROW) {
  393. AccIterator cellIter(aAccessible, filters::GetCell);
  394. Accessible* cell = nullptr;
  395. while ((cell = cellIter.Next())) {
  396. rv = SetARIASelected(cell, false, false);
  397. NS_ENSURE_SUCCESS(rv, rv);
  398. }
  399. return NS_OK;
  400. }
  401. // If the given accessible is cell that was unselected and its row is selected
  402. // then remove aria-selected from row and put aria-selected on
  403. // siblings cells.
  404. if (role == roles::GRID_CELL || role == roles::ROWHEADER ||
  405. role == roles::COLUMNHEADER) {
  406. Accessible* row = aAccessible->Parent();
  407. if (row && row->Role() == roles::ROW &&
  408. nsAccUtils::IsARIASelected(row)) {
  409. rv = SetARIASelected(row, false, false);
  410. NS_ENSURE_SUCCESS(rv, rv);
  411. AccIterator cellIter(row, filters::GetCell);
  412. Accessible* cell = nullptr;
  413. while ((cell = cellIter.Next())) {
  414. if (cell != aAccessible) {
  415. rv = SetARIASelected(cell, true, false);
  416. NS_ENSURE_SUCCESS(rv, rv);
  417. }
  418. }
  419. }
  420. }
  421. return NS_OK;
  422. }
  423. ////////////////////////////////////////////////////////////////////////////////
  424. // ARIARowAccessible
  425. ////////////////////////////////////////////////////////////////////////////////
  426. ARIARowAccessible::
  427. ARIARowAccessible(nsIContent* aContent, DocAccessible* aDoc) :
  428. AccessibleWrap(aContent, aDoc)
  429. {
  430. mGenericTypes |= eTableRow;
  431. }
  432. NS_IMPL_ISUPPORTS_INHERITED0(ARIARowAccessible, Accessible)
  433. GroupPos
  434. ARIARowAccessible::GroupPosition()
  435. {
  436. int32_t count = 0, index = 0;
  437. Accessible* table = nsAccUtils::TableFor(this);
  438. if (table && nsCoreUtils::GetUIntAttr(table->GetContent(),
  439. nsGkAtoms::aria_rowcount, &count) &&
  440. nsCoreUtils::GetUIntAttr(mContent, nsGkAtoms::aria_rowindex, &index)) {
  441. return GroupPos(0, index, count);
  442. }
  443. return AccessibleWrap::GroupPosition();
  444. }
  445. ////////////////////////////////////////////////////////////////////////////////
  446. // ARIAGridCellAccessible
  447. ////////////////////////////////////////////////////////////////////////////////
  448. ////////////////////////////////////////////////////////////////////////////////
  449. // Constructor
  450. ARIAGridCellAccessible::
  451. ARIAGridCellAccessible(nsIContent* aContent, DocAccessible* aDoc) :
  452. HyperTextAccessibleWrap(aContent, aDoc)
  453. {
  454. mGenericTypes |= eTableCell;
  455. }
  456. NS_IMPL_ISUPPORTS_INHERITED0(ARIAGridCellAccessible, HyperTextAccessible)
  457. ////////////////////////////////////////////////////////////////////////////////
  458. // TableCell
  459. TableAccessible*
  460. ARIAGridCellAccessible::Table() const
  461. {
  462. Accessible* table = nsAccUtils::TableFor(Row());
  463. return table ? table->AsTable() : nullptr;
  464. }
  465. uint32_t
  466. ARIAGridCellAccessible::ColIdx() const
  467. {
  468. Accessible* row = Row();
  469. if (!row)
  470. return 0;
  471. int32_t indexInRow = IndexInParent();
  472. uint32_t colIdx = 0;
  473. for (int32_t idx = 0; idx < indexInRow; idx++) {
  474. Accessible* cell = row->GetChildAt(idx);
  475. roles::Role role = cell->Role();
  476. if (role == roles::CELL || role == roles::GRID_CELL ||
  477. role == roles::ROWHEADER || role == roles::COLUMNHEADER)
  478. colIdx++;
  479. }
  480. return colIdx;
  481. }
  482. uint32_t
  483. ARIAGridCellAccessible::RowIdx() const
  484. {
  485. return RowIndexFor(Row());
  486. }
  487. bool
  488. ARIAGridCellAccessible::Selected()
  489. {
  490. Accessible* row = Row();
  491. if (!row)
  492. return false;
  493. return nsAccUtils::IsARIASelected(row) || nsAccUtils::IsARIASelected(this);
  494. }
  495. ////////////////////////////////////////////////////////////////////////////////
  496. // Accessible
  497. void
  498. ARIAGridCellAccessible::ApplyARIAState(uint64_t* aState) const
  499. {
  500. HyperTextAccessibleWrap::ApplyARIAState(aState);
  501. // Return if the gridcell has aria-selected="true".
  502. if (*aState & states::SELECTED)
  503. return;
  504. // Check aria-selected="true" on the row.
  505. Accessible* row = Parent();
  506. if (!row || row->Role() != roles::ROW)
  507. return;
  508. nsIContent *rowContent = row->GetContent();
  509. if (nsAccUtils::HasDefinedARIAToken(rowContent,
  510. nsGkAtoms::aria_selected) &&
  511. !rowContent->AttrValueIs(kNameSpaceID_None,
  512. nsGkAtoms::aria_selected,
  513. nsGkAtoms::_false, eCaseMatters))
  514. *aState |= states::SELECTABLE | states::SELECTED;
  515. }
  516. already_AddRefed<nsIPersistentProperties>
  517. ARIAGridCellAccessible::NativeAttributes()
  518. {
  519. nsCOMPtr<nsIPersistentProperties> attributes =
  520. HyperTextAccessibleWrap::NativeAttributes();
  521. // Expose "table-cell-index" attribute.
  522. Accessible* thisRow = Row();
  523. if (!thisRow)
  524. return attributes.forget();
  525. int32_t colIdx = 0, colCount = 0;
  526. uint32_t childCount = thisRow->ChildCount();
  527. for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) {
  528. Accessible* child = thisRow->GetChildAt(childIdx);
  529. if (child == this)
  530. colIdx = colCount;
  531. roles::Role role = child->Role();
  532. if (role == roles::CELL || role == roles::GRID_CELL ||
  533. role == roles::ROWHEADER || role == roles::COLUMNHEADER)
  534. colCount++;
  535. }
  536. int32_t rowIdx = RowIndexFor(thisRow);
  537. nsAutoString stringIdx;
  538. stringIdx.AppendInt(rowIdx * colCount + colIdx);
  539. nsAccUtils::SetAccAttr(attributes, nsGkAtoms::tableCellIndex, stringIdx);
  540. #ifdef DEBUG
  541. nsAutoString unused;
  542. attributes->SetStringProperty(NS_LITERAL_CSTRING("cppclass"),
  543. NS_LITERAL_STRING("ARIAGridCellAccessible"),
  544. unused);
  545. #endif
  546. return attributes.forget();
  547. }
  548. GroupPos
  549. ARIAGridCellAccessible::GroupPosition()
  550. {
  551. int32_t count = 0, index = 0;
  552. TableAccessible* table = Table();
  553. if (table && nsCoreUtils::GetUIntAttr(table->AsAccessible()->GetContent(),
  554. nsGkAtoms::aria_colcount, &count) &&
  555. nsCoreUtils::GetUIntAttr(mContent, nsGkAtoms::aria_colindex, &index)) {
  556. return GroupPos(0, index, count);
  557. }
  558. return GroupPos();
  559. }