1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Mozilla Foundation.
19 : * Portions created by the Initial Developer are Copyright (C) 2009
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Alexander Surkov <surkov.alexander@gmail.com> (original author)
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "nsARIAGridAccessible.h"
40 :
41 : #include "AccIterator.h"
42 : #include "nsAccUtils.h"
43 : #include "Role.h"
44 : #include "States.h"
45 :
46 : #include "nsIMutableArray.h"
47 : #include "nsComponentManagerUtils.h"
48 :
49 : using namespace mozilla::a11y;
50 :
51 : ////////////////////////////////////////////////////////////////////////////////
52 : // nsARIAGridAccessible
53 : ////////////////////////////////////////////////////////////////////////////////
54 :
55 :
56 : ////////////////////////////////////////////////////////////////////////////////
57 : // Constructor
58 :
59 0 : nsARIAGridAccessible::
60 : nsARIAGridAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
61 0 : nsAccessibleWrap(aContent, aDoc)
62 : {
63 0 : }
64 :
65 : ////////////////////////////////////////////////////////////////////////////////
66 : // nsISupports
67 :
68 0 : NS_IMPL_ISUPPORTS_INHERITED1(nsARIAGridAccessible,
69 : nsAccessible,
70 : nsIAccessibleTable)
71 :
72 : ////////////////////////////////////////////////////////////////////////////////
73 : // nsIAccessibleTable
74 :
75 : NS_IMETHODIMP
76 0 : nsARIAGridAccessible::GetCaption(nsIAccessible **aCaption)
77 : {
78 0 : NS_ENSURE_ARG_POINTER(aCaption);
79 0 : *aCaption = nsnull;
80 :
81 0 : if (IsDefunct())
82 0 : return NS_ERROR_FAILURE;
83 :
84 : // XXX: should be pointed by aria-labelledby on grid?
85 0 : return NS_ERROR_NOT_IMPLEMENTED;
86 : }
87 :
88 : NS_IMETHODIMP
89 0 : nsARIAGridAccessible::GetSummary(nsAString &aSummary)
90 : {
91 0 : aSummary.Truncate();
92 :
93 0 : if (IsDefunct())
94 0 : return NS_ERROR_FAILURE;
95 :
96 : // XXX: should be pointed by aria-describedby on grid?
97 0 : return NS_ERROR_NOT_IMPLEMENTED;
98 : }
99 :
100 : NS_IMETHODIMP
101 0 : nsARIAGridAccessible::GetColumnCount(PRInt32 *acolumnCount)
102 : {
103 0 : NS_ENSURE_ARG_POINTER(acolumnCount);
104 0 : *acolumnCount = 0;
105 :
106 0 : if (IsDefunct())
107 0 : return NS_ERROR_FAILURE;
108 :
109 0 : AccIterator rowIter(this, filters::GetRow);
110 0 : nsAccessible* row = rowIter.Next();
111 0 : if (!row)
112 0 : return NS_OK;
113 :
114 0 : AccIterator cellIter(row, filters::GetCell);
115 0 : nsAccessible *cell = nsnull;
116 :
117 0 : while ((cell = cellIter.Next()))
118 0 : (*acolumnCount)++;
119 :
120 0 : return NS_OK;
121 : }
122 :
123 : NS_IMETHODIMP
124 0 : nsARIAGridAccessible::GetRowCount(PRInt32 *arowCount)
125 : {
126 0 : NS_ENSURE_ARG_POINTER(arowCount);
127 0 : *arowCount = 0;
128 :
129 0 : if (IsDefunct())
130 0 : return NS_ERROR_FAILURE;
131 :
132 0 : AccIterator rowIter(this, filters::GetRow);
133 0 : while (rowIter.Next())
134 0 : (*arowCount)++;
135 :
136 0 : return NS_OK;
137 : }
138 :
139 : NS_IMETHODIMP
140 0 : nsARIAGridAccessible::GetCellAt(PRInt32 aRowIndex, PRInt32 aColumnIndex,
141 : nsIAccessible **aAccessible)
142 : {
143 0 : NS_ENSURE_ARG_POINTER(aAccessible);
144 0 : *aAccessible = nsnull;
145 :
146 0 : if (IsDefunct())
147 0 : return NS_ERROR_FAILURE;
148 :
149 0 : nsAccessible *row = GetRowAt(aRowIndex);
150 0 : NS_ENSURE_ARG(row);
151 :
152 0 : nsAccessible *cell = GetCellInRowAt(row, aColumnIndex);
153 0 : NS_ENSURE_ARG(cell);
154 :
155 0 : NS_ADDREF(*aAccessible = cell);
156 0 : return NS_OK;
157 : }
158 :
159 : NS_IMETHODIMP
160 0 : nsARIAGridAccessible::GetCellIndexAt(PRInt32 aRowIndex, PRInt32 aColumnIndex,
161 : PRInt32 *aCellIndex)
162 : {
163 0 : NS_ENSURE_ARG_POINTER(aCellIndex);
164 0 : *aCellIndex = -1;
165 :
166 0 : if (IsDefunct())
167 0 : return NS_ERROR_FAILURE;
168 :
169 0 : NS_ENSURE_ARG(aRowIndex >= 0 && aColumnIndex >= 0);
170 :
171 0 : PRInt32 rowCount = 0;
172 0 : GetRowCount(&rowCount);
173 0 : NS_ENSURE_ARG(aRowIndex < rowCount);
174 :
175 0 : PRInt32 colsCount = 0;
176 0 : GetColumnCount(&colsCount);
177 0 : NS_ENSURE_ARG(aColumnIndex < colsCount);
178 :
179 0 : *aCellIndex = colsCount * aRowIndex + aColumnIndex;
180 0 : return NS_OK;
181 : }
182 :
183 : NS_IMETHODIMP
184 0 : nsARIAGridAccessible::GetColumnIndexAt(PRInt32 aCellIndex,
185 : PRInt32 *aColumnIndex)
186 : {
187 0 : NS_ENSURE_ARG_POINTER(aColumnIndex);
188 0 : *aColumnIndex = -1;
189 :
190 0 : if (IsDefunct())
191 0 : return NS_ERROR_FAILURE;
192 :
193 0 : NS_ENSURE_ARG(aCellIndex >= 0);
194 :
195 0 : PRInt32 rowCount = 0;
196 0 : GetRowCount(&rowCount);
197 :
198 0 : PRInt32 colsCount = 0;
199 0 : GetColumnCount(&colsCount);
200 :
201 0 : NS_ENSURE_ARG(aCellIndex < rowCount * colsCount);
202 :
203 0 : *aColumnIndex = aCellIndex % colsCount;
204 0 : return NS_OK;
205 : }
206 :
207 : NS_IMETHODIMP
208 0 : nsARIAGridAccessible::GetRowIndexAt(PRInt32 aCellIndex, PRInt32 *aRowIndex)
209 : {
210 0 : NS_ENSURE_ARG_POINTER(aRowIndex);
211 0 : *aRowIndex = -1;
212 :
213 0 : if (IsDefunct())
214 0 : return NS_ERROR_FAILURE;
215 :
216 0 : NS_ENSURE_ARG(aCellIndex >= 0);
217 :
218 0 : PRInt32 rowCount = 0;
219 0 : GetRowCount(&rowCount);
220 :
221 0 : PRInt32 colsCount = 0;
222 0 : GetColumnCount(&colsCount);
223 :
224 0 : NS_ENSURE_ARG(aCellIndex < rowCount * colsCount);
225 :
226 0 : *aRowIndex = aCellIndex / colsCount;
227 0 : return NS_OK;
228 : }
229 :
230 : NS_IMETHODIMP
231 0 : nsARIAGridAccessible::GetRowAndColumnIndicesAt(PRInt32 aCellIndex,
232 : PRInt32* aRowIndex,
233 : PRInt32* aColumnIndex)
234 : {
235 0 : NS_ENSURE_ARG_POINTER(aRowIndex);
236 0 : *aRowIndex = -1;
237 0 : NS_ENSURE_ARG_POINTER(aColumnIndex);
238 0 : *aColumnIndex = -1;
239 :
240 0 : if (IsDefunct())
241 0 : return NS_ERROR_FAILURE;
242 :
243 0 : NS_ENSURE_ARG(aCellIndex >= 0);
244 :
245 0 : PRInt32 rowCount = 0;
246 0 : GetRowCount(&rowCount);
247 :
248 0 : PRInt32 colsCount = 0;
249 0 : GetColumnCount(&colsCount);
250 :
251 0 : NS_ENSURE_ARG(aCellIndex < rowCount * colsCount);
252 :
253 0 : *aColumnIndex = aCellIndex % colsCount;
254 0 : *aRowIndex = aCellIndex / colsCount;
255 0 : return NS_OK;
256 : }
257 :
258 : NS_IMETHODIMP
259 0 : nsARIAGridAccessible::GetColumnExtentAt(PRInt32 aRow, PRInt32 aColumn,
260 : PRInt32 *aExtentCount)
261 : {
262 0 : NS_ENSURE_ARG_POINTER(aExtentCount);
263 0 : *aExtentCount = 0;
264 :
265 0 : if (IsDefunct())
266 0 : return NS_ERROR_FAILURE;
267 :
268 0 : NS_ENSURE_ARG(IsValidRowNColumn(aRow, aColumn));
269 :
270 0 : *aExtentCount = 1;
271 0 : return NS_OK;
272 : }
273 :
274 : NS_IMETHODIMP
275 0 : nsARIAGridAccessible::GetRowExtentAt(PRInt32 aRow, PRInt32 aColumn,
276 : PRInt32 *aExtentCount)
277 : {
278 0 : NS_ENSURE_ARG_POINTER(aExtentCount);
279 0 : *aExtentCount = 0;
280 :
281 0 : if (IsDefunct())
282 0 : return NS_ERROR_FAILURE;
283 :
284 0 : NS_ENSURE_ARG(IsValidRowNColumn(aRow, aColumn));
285 :
286 0 : *aExtentCount = 1;
287 0 : return NS_OK;
288 : }
289 :
290 : NS_IMETHODIMP
291 0 : nsARIAGridAccessible::GetColumnDescription(PRInt32 aColumn,
292 : nsAString& aDescription)
293 : {
294 0 : aDescription.Truncate();
295 :
296 0 : if (IsDefunct())
297 0 : return NS_ERROR_FAILURE;
298 :
299 0 : NS_ENSURE_ARG(IsValidColumn(aColumn));
300 :
301 : // XXX: not implemented
302 0 : return NS_ERROR_NOT_IMPLEMENTED;
303 : }
304 :
305 : NS_IMETHODIMP
306 0 : nsARIAGridAccessible::GetRowDescription(PRInt32 aRow, nsAString& aDescription)
307 : {
308 0 : aDescription.Truncate();
309 :
310 0 : if (IsDefunct())
311 0 : return NS_ERROR_FAILURE;
312 :
313 0 : NS_ENSURE_ARG(IsValidRow(aRow));
314 :
315 : // XXX: not implemented
316 0 : return NS_ERROR_NOT_IMPLEMENTED;
317 : }
318 :
319 : NS_IMETHODIMP
320 0 : nsARIAGridAccessible::IsColumnSelected(PRInt32 aColumn, bool *aIsSelected)
321 : {
322 0 : NS_ENSURE_ARG_POINTER(aIsSelected);
323 0 : *aIsSelected = false;
324 :
325 0 : if (IsDefunct())
326 0 : return NS_ERROR_FAILURE;
327 :
328 0 : NS_ENSURE_ARG(IsValidColumn(aColumn));
329 :
330 0 : AccIterator rowIter(this, filters::GetRow);
331 0 : nsAccessible *row = rowIter.Next();
332 0 : if (!row)
333 0 : return NS_OK;
334 :
335 0 : do {
336 0 : if (!nsAccUtils::IsARIASelected(row)) {
337 0 : nsAccessible *cell = GetCellInRowAt(row, aColumn);
338 0 : if (!cell) // Do not fail due to wrong markup
339 0 : return NS_OK;
340 :
341 0 : if (!nsAccUtils::IsARIASelected(cell))
342 0 : return NS_OK;
343 : }
344 : } while ((row = rowIter.Next()));
345 :
346 0 : *aIsSelected = true;
347 0 : return NS_OK;
348 : }
349 :
350 : NS_IMETHODIMP
351 0 : nsARIAGridAccessible::IsRowSelected(PRInt32 aRow, bool *aIsSelected)
352 : {
353 0 : NS_ENSURE_ARG_POINTER(aIsSelected);
354 0 : *aIsSelected = false;
355 :
356 0 : if (IsDefunct())
357 0 : return NS_ERROR_FAILURE;
358 :
359 0 : nsAccessible *row = GetRowAt(aRow);
360 0 : NS_ENSURE_ARG(row);
361 :
362 0 : if (!nsAccUtils::IsARIASelected(row)) {
363 0 : AccIterator cellIter(row, filters::GetCell);
364 0 : nsAccessible *cell = nsnull;
365 0 : while ((cell = cellIter.Next())) {
366 0 : if (!nsAccUtils::IsARIASelected(cell))
367 0 : return NS_OK;
368 : }
369 : }
370 :
371 0 : *aIsSelected = true;
372 0 : return NS_OK;
373 : }
374 :
375 : NS_IMETHODIMP
376 0 : nsARIAGridAccessible::IsCellSelected(PRInt32 aRow, PRInt32 aColumn,
377 : bool *aIsSelected)
378 : {
379 0 : NS_ENSURE_ARG_POINTER(aIsSelected);
380 0 : *aIsSelected = false;
381 :
382 0 : if (IsDefunct())
383 0 : return NS_ERROR_FAILURE;
384 :
385 0 : nsAccessible *row = GetRowAt(aRow);
386 0 : NS_ENSURE_ARG(row);
387 :
388 0 : if (!nsAccUtils::IsARIASelected(row)) {
389 0 : nsAccessible *cell = GetCellInRowAt(row, aColumn);
390 0 : NS_ENSURE_ARG(cell);
391 :
392 0 : if (!nsAccUtils::IsARIASelected(cell))
393 0 : return NS_OK;
394 : }
395 :
396 0 : *aIsSelected = true;
397 0 : return NS_OK;
398 : }
399 :
400 : NS_IMETHODIMP
401 0 : nsARIAGridAccessible::GetSelectedCellCount(PRUint32* aCount)
402 : {
403 0 : NS_ENSURE_ARG_POINTER(aCount);
404 0 : *aCount = 0;
405 :
406 0 : if (IsDefunct())
407 0 : return NS_ERROR_FAILURE;
408 :
409 0 : PRInt32 colCount = 0;
410 0 : GetColumnCount(&colCount);
411 :
412 0 : AccIterator rowIter(this, filters::GetRow);
413 :
414 0 : nsAccessible *row = nsnull;
415 0 : while ((row = rowIter.Next())) {
416 0 : if (nsAccUtils::IsARIASelected(row)) {
417 0 : (*aCount) += colCount;
418 0 : continue;
419 : }
420 :
421 0 : AccIterator cellIter(row, filters::GetCell);
422 0 : nsAccessible *cell = nsnull;
423 :
424 0 : while ((cell = cellIter.Next())) {
425 0 : if (nsAccUtils::IsARIASelected(cell))
426 0 : (*aCount)++;
427 : }
428 : }
429 :
430 0 : return NS_OK;
431 : }
432 :
433 : NS_IMETHODIMP
434 0 : nsARIAGridAccessible::GetSelectedColumnCount(PRUint32* aCount)
435 : {
436 0 : return GetSelectedColumnsArray(aCount);
437 : }
438 :
439 : NS_IMETHODIMP
440 0 : nsARIAGridAccessible::GetSelectedRowCount(PRUint32* aCount)
441 : {
442 0 : NS_ENSURE_ARG_POINTER(aCount);
443 0 : *aCount = 0;
444 :
445 0 : if (IsDefunct())
446 0 : return NS_ERROR_FAILURE;
447 :
448 0 : AccIterator rowIter(this, filters::GetRow);
449 :
450 0 : nsAccessible *row = nsnull;
451 0 : while ((row = rowIter.Next())) {
452 0 : if (nsAccUtils::IsARIASelected(row)) {
453 0 : (*aCount)++;
454 0 : continue;
455 : }
456 :
457 0 : AccIterator cellIter(row, filters::GetCell);
458 0 : nsAccessible *cell = cellIter.Next();
459 0 : if (!cell)
460 0 : continue;
461 :
462 0 : bool isRowSelected = true;
463 0 : do {
464 0 : if (!nsAccUtils::IsARIASelected(cell)) {
465 0 : isRowSelected = false;
466 0 : break;
467 : }
468 : } while ((cell = cellIter.Next()));
469 :
470 0 : if (isRowSelected)
471 0 : (*aCount)++;
472 : }
473 :
474 0 : return NS_OK;
475 : }
476 :
477 : NS_IMETHODIMP
478 0 : nsARIAGridAccessible::GetSelectedCells(nsIArray **aCells)
479 : {
480 0 : NS_ENSURE_ARG_POINTER(aCells);
481 0 : *aCells = nsnull;
482 :
483 0 : if (IsDefunct())
484 0 : return NS_ERROR_FAILURE;
485 :
486 0 : nsresult rv = NS_OK;
487 : nsCOMPtr<nsIMutableArray> selCells =
488 0 : do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
489 0 : NS_ENSURE_SUCCESS(rv, rv);
490 :
491 0 : AccIterator rowIter(this, filters::GetRow);
492 :
493 0 : nsAccessible *row = nsnull;
494 0 : while ((row = rowIter.Next())) {
495 0 : AccIterator cellIter(row, filters::GetCell);
496 0 : nsAccessible *cell = nsnull;
497 :
498 0 : if (nsAccUtils::IsARIASelected(row)) {
499 0 : while ((cell = cellIter.Next()))
500 0 : selCells->AppendElement(static_cast<nsIAccessible *>(cell), false);
501 :
502 0 : continue;
503 : }
504 :
505 0 : while ((cell = cellIter.Next())) {
506 0 : if (nsAccUtils::IsARIASelected(cell))
507 0 : selCells->AppendElement(static_cast<nsIAccessible *>(cell), false);
508 : }
509 : }
510 :
511 0 : NS_ADDREF(*aCells = selCells);
512 0 : return NS_OK;
513 : }
514 :
515 : NS_IMETHODIMP
516 0 : nsARIAGridAccessible::GetSelectedCellIndices(PRUint32 *aCellsCount,
517 : PRInt32 **aCells)
518 : {
519 0 : NS_ENSURE_ARG_POINTER(aCellsCount);
520 0 : *aCellsCount = 0;
521 0 : NS_ENSURE_ARG_POINTER(aCells);
522 0 : *aCells = nsnull;
523 :
524 0 : if (IsDefunct())
525 0 : return NS_ERROR_FAILURE;
526 :
527 0 : PRInt32 rowCount = 0;
528 0 : GetRowCount(&rowCount);
529 :
530 0 : PRInt32 colCount = 0;
531 0 : GetColumnCount(&colCount);
532 :
533 0 : nsTArray<PRInt32> selCells(rowCount * colCount);
534 :
535 0 : AccIterator rowIter(this, filters::GetRow);
536 :
537 0 : nsAccessible *row = nsnull;
538 0 : for (PRInt32 rowIdx = 0; (row = rowIter.Next()); rowIdx++) {
539 0 : if (nsAccUtils::IsARIASelected(row)) {
540 0 : for (PRInt32 colIdx = 0; colIdx < colCount; colIdx++)
541 0 : selCells.AppendElement(rowIdx * colCount + colIdx);
542 :
543 0 : continue;
544 : }
545 :
546 0 : AccIterator cellIter(row, filters::GetCell);
547 0 : nsAccessible *cell = nsnull;
548 :
549 0 : for (PRInt32 colIdx = 0; (cell = cellIter.Next()); colIdx++) {
550 0 : if (nsAccUtils::IsARIASelected(cell))
551 0 : selCells.AppendElement(rowIdx * colCount + colIdx);
552 : }
553 : }
554 :
555 0 : PRUint32 selCellsCount = selCells.Length();
556 0 : if (!selCellsCount)
557 0 : return NS_OK;
558 :
559 : *aCells = static_cast<PRInt32*>(
560 0 : nsMemory::Clone(selCells.Elements(), selCellsCount * sizeof(PRInt32)));
561 0 : NS_ENSURE_TRUE(*aCells, NS_ERROR_OUT_OF_MEMORY);
562 :
563 0 : *aCellsCount = selCellsCount;
564 0 : return NS_OK;
565 : }
566 :
567 : NS_IMETHODIMP
568 0 : nsARIAGridAccessible::GetSelectedColumnIndices(PRUint32 *acolumnCount,
569 : PRInt32 **aColumns)
570 : {
571 0 : NS_ENSURE_ARG_POINTER(aColumns);
572 :
573 0 : return GetSelectedColumnsArray(acolumnCount, aColumns);
574 : }
575 :
576 : NS_IMETHODIMP
577 0 : nsARIAGridAccessible::GetSelectedRowIndices(PRUint32 *arowCount,
578 : PRInt32 **aRows)
579 : {
580 0 : NS_ENSURE_ARG_POINTER(arowCount);
581 0 : *arowCount = 0;
582 0 : NS_ENSURE_ARG_POINTER(aRows);
583 0 : *aRows = nsnull;
584 :
585 0 : if (IsDefunct())
586 0 : return NS_ERROR_FAILURE;
587 :
588 0 : PRInt32 rowCount = 0;
589 0 : GetRowCount(&rowCount);
590 0 : if (!rowCount)
591 0 : return NS_OK;
592 :
593 0 : nsTArray<PRInt32> selRows(rowCount);
594 :
595 0 : AccIterator rowIter(this, filters::GetRow);
596 :
597 0 : nsAccessible *row = nsnull;
598 0 : for (PRInt32 rowIdx = 0; (row = rowIter.Next()); rowIdx++) {
599 0 : if (nsAccUtils::IsARIASelected(row)) {
600 0 : selRows.AppendElement(rowIdx);
601 0 : continue;
602 : }
603 :
604 0 : AccIterator cellIter(row, filters::GetCell);
605 0 : nsAccessible *cell = cellIter.Next();
606 0 : if (!cell)
607 0 : continue;
608 :
609 0 : bool isRowSelected = true;
610 0 : do {
611 0 : if (!nsAccUtils::IsARIASelected(cell)) {
612 0 : isRowSelected = false;
613 0 : break;
614 : }
615 : } while ((cell = cellIter.Next()));
616 :
617 0 : if (isRowSelected)
618 0 : selRows.AppendElement(rowIdx);
619 : }
620 :
621 0 : PRUint32 selrowCount = selRows.Length();
622 0 : if (!selrowCount)
623 0 : return NS_OK;
624 :
625 : *aRows = static_cast<PRInt32*>(
626 0 : nsMemory::Clone(selRows.Elements(), selrowCount * sizeof(PRInt32)));
627 0 : NS_ENSURE_TRUE(*aRows, NS_ERROR_OUT_OF_MEMORY);
628 :
629 0 : *arowCount = selrowCount;
630 0 : return NS_OK;
631 : }
632 :
633 : NS_IMETHODIMP
634 0 : nsARIAGridAccessible::SelectRow(PRInt32 aRow)
635 : {
636 0 : NS_ENSURE_ARG(IsValidRow(aRow));
637 :
638 0 : if (IsDefunct())
639 0 : return NS_ERROR_FAILURE;
640 :
641 0 : AccIterator rowIter(this, filters::GetRow);
642 :
643 0 : nsAccessible *row = nsnull;
644 0 : for (PRInt32 rowIdx = 0; (row = rowIter.Next()); rowIdx++) {
645 0 : nsresult rv = SetARIASelected(row, rowIdx == aRow);
646 0 : NS_ENSURE_SUCCESS(rv, rv);
647 : }
648 :
649 0 : return NS_OK;
650 : }
651 :
652 : NS_IMETHODIMP
653 0 : nsARIAGridAccessible::SelectColumn(PRInt32 aColumn)
654 : {
655 0 : NS_ENSURE_ARG(IsValidColumn(aColumn));
656 :
657 0 : if (IsDefunct())
658 0 : return NS_ERROR_FAILURE;
659 :
660 0 : AccIterator rowIter(this, filters::GetRow);
661 :
662 0 : nsAccessible *row = nsnull;
663 0 : while ((row = rowIter.Next())) {
664 : // Unselect all cells in the row.
665 0 : nsresult rv = SetARIASelected(row, false);
666 0 : NS_ENSURE_SUCCESS(rv, rv);
667 :
668 : // Select cell at the column index.
669 0 : nsAccessible *cell = GetCellInRowAt(row, aColumn);
670 0 : if (cell) {
671 0 : rv = SetARIASelected(cell, true);
672 0 : NS_ENSURE_SUCCESS(rv, rv);
673 : }
674 : }
675 :
676 0 : return NS_OK;
677 : }
678 :
679 : NS_IMETHODIMP
680 0 : nsARIAGridAccessible::UnselectRow(PRInt32 aRow)
681 : {
682 0 : if (IsDefunct())
683 0 : return NS_ERROR_FAILURE;
684 :
685 0 : nsAccessible *row = GetRowAt(aRow);
686 0 : NS_ENSURE_ARG(row);
687 :
688 0 : return SetARIASelected(row, false);
689 : }
690 :
691 : NS_IMETHODIMP
692 0 : nsARIAGridAccessible::UnselectColumn(PRInt32 aColumn)
693 : {
694 0 : NS_ENSURE_ARG(IsValidColumn(aColumn));
695 :
696 0 : if (IsDefunct())
697 0 : return NS_ERROR_FAILURE;
698 :
699 0 : AccIterator rowIter(this, filters::GetRow);
700 :
701 0 : nsAccessible *row = nsnull;
702 0 : while ((row = rowIter.Next())) {
703 0 : nsAccessible *cell = GetCellInRowAt(row, aColumn);
704 0 : if (cell) {
705 0 : nsresult rv = SetARIASelected(cell, false);
706 0 : NS_ENSURE_SUCCESS(rv, rv);
707 : }
708 : }
709 :
710 0 : return NS_OK;
711 : }
712 :
713 : NS_IMETHODIMP
714 0 : nsARIAGridAccessible::IsProbablyForLayout(bool *aIsProbablyForLayout)
715 : {
716 0 : NS_ENSURE_ARG_POINTER(aIsProbablyForLayout);
717 0 : *aIsProbablyForLayout = false;
718 :
719 0 : return NS_OK;
720 : }
721 :
722 : ////////////////////////////////////////////////////////////////////////////////
723 : // Protected
724 :
725 : bool
726 0 : nsARIAGridAccessible::IsValidRow(PRInt32 aRow)
727 : {
728 0 : if (aRow < 0)
729 0 : return false;
730 :
731 0 : PRInt32 rowCount = 0;
732 0 : GetRowCount(&rowCount);
733 0 : return aRow < rowCount;
734 : }
735 :
736 : bool
737 0 : nsARIAGridAccessible::IsValidColumn(PRInt32 aColumn)
738 : {
739 0 : if (aColumn < 0)
740 0 : return false;
741 :
742 0 : PRInt32 colCount = 0;
743 0 : GetColumnCount(&colCount);
744 0 : return aColumn < colCount;
745 : }
746 :
747 : bool
748 0 : nsARIAGridAccessible::IsValidRowNColumn(PRInt32 aRow, PRInt32 aColumn)
749 : {
750 0 : if (aRow < 0 || aColumn < 0)
751 0 : return false;
752 :
753 0 : PRInt32 rowCount = 0;
754 0 : GetRowCount(&rowCount);
755 0 : if (aRow >= rowCount)
756 0 : return false;
757 :
758 0 : PRInt32 colCount = 0;
759 0 : GetColumnCount(&colCount);
760 0 : return aColumn < colCount;
761 : }
762 :
763 : nsAccessible*
764 0 : nsARIAGridAccessible::GetRowAt(PRInt32 aRow)
765 : {
766 0 : PRInt32 rowIdx = aRow;
767 :
768 0 : AccIterator rowIter(this, filters::GetRow);
769 :
770 0 : nsAccessible *row = rowIter.Next();
771 0 : while (rowIdx != 0 && (row = rowIter.Next()))
772 0 : rowIdx--;
773 :
774 0 : return row;
775 : }
776 :
777 : nsAccessible*
778 0 : nsARIAGridAccessible::GetCellInRowAt(nsAccessible *aRow, PRInt32 aColumn)
779 : {
780 0 : PRInt32 colIdx = aColumn;
781 :
782 0 : AccIterator cellIter(aRow, filters::GetCell);
783 0 : nsAccessible *cell = cellIter.Next();
784 0 : while (colIdx != 0 && (cell = cellIter.Next()))
785 0 : colIdx--;
786 :
787 0 : return cell;
788 : }
789 :
790 : nsresult
791 0 : nsARIAGridAccessible::SetARIASelected(nsAccessible *aAccessible,
792 : bool aIsSelected, bool aNotify)
793 : {
794 0 : nsIContent *content = aAccessible->GetContent();
795 0 : NS_ENSURE_STATE(content);
796 :
797 0 : nsresult rv = NS_OK;
798 0 : if (aIsSelected)
799 : rv = content->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected,
800 0 : NS_LITERAL_STRING("true"), aNotify);
801 : else
802 : rv = content->UnsetAttr(kNameSpaceID_None,
803 0 : nsGkAtoms::aria_selected, aNotify);
804 :
805 0 : NS_ENSURE_SUCCESS(rv, rv);
806 :
807 : // No "smart" select/unselect for internal call.
808 0 : if (!aNotify)
809 0 : return NS_OK;
810 :
811 : // If row or cell accessible was selected then we're able to not bother about
812 : // selection of its cells or its row because our algorithm is row oriented,
813 : // i.e. we check selection on row firstly and then on cells.
814 0 : if (aIsSelected)
815 0 : return NS_OK;
816 :
817 0 : roles::Role role = aAccessible->Role();
818 :
819 : // If the given accessible is row that was unselected then remove
820 : // aria-selected from cell accessible.
821 0 : if (role == roles::ROW) {
822 0 : AccIterator cellIter(aAccessible, filters::GetCell);
823 0 : nsAccessible *cell = nsnull;
824 :
825 0 : while ((cell = cellIter.Next())) {
826 0 : rv = SetARIASelected(cell, false, false);
827 0 : NS_ENSURE_SUCCESS(rv, rv);
828 : }
829 0 : return NS_OK;
830 : }
831 :
832 : // If the given accessible is cell that was unselected and its row is selected
833 : // then remove aria-selected from row and put aria-selected on
834 : // siblings cells.
835 0 : if (role == roles::GRID_CELL || role == roles::ROWHEADER ||
836 : role == roles::COLUMNHEADER) {
837 0 : nsAccessible* row = aAccessible->Parent();
838 :
839 0 : if (row && row->Role() == roles::ROW &&
840 0 : nsAccUtils::IsARIASelected(row)) {
841 0 : rv = SetARIASelected(row, false, false);
842 0 : NS_ENSURE_SUCCESS(rv, rv);
843 :
844 0 : AccIterator cellIter(row, filters::GetCell);
845 0 : nsAccessible *cell = nsnull;
846 0 : while ((cell = cellIter.Next())) {
847 0 : if (cell != aAccessible) {
848 0 : rv = SetARIASelected(cell, true, false);
849 0 : NS_ENSURE_SUCCESS(rv, rv);
850 : }
851 : }
852 : }
853 : }
854 :
855 0 : return NS_OK;
856 : }
857 :
858 : nsresult
859 0 : nsARIAGridAccessible::GetSelectedColumnsArray(PRUint32 *acolumnCount,
860 : PRInt32 **aColumns)
861 : {
862 0 : NS_ENSURE_ARG_POINTER(acolumnCount);
863 0 : *acolumnCount = 0;
864 0 : if (aColumns)
865 0 : *aColumns = nsnull;
866 :
867 0 : if (IsDefunct())
868 0 : return NS_ERROR_FAILURE;
869 :
870 0 : AccIterator rowIter(this, filters::GetRow);
871 0 : nsAccessible *row = rowIter.Next();
872 0 : if (!row)
873 0 : return NS_OK;
874 :
875 0 : PRInt32 colCount = 0;
876 0 : GetColumnCount(&colCount);
877 0 : if (!colCount)
878 0 : return NS_OK;
879 :
880 0 : PRInt32 selColCount = colCount;
881 :
882 0 : nsTArray<bool> isColSelArray(selColCount);
883 0 : isColSelArray.AppendElements(selColCount);
884 0 : for (PRInt32 i = 0; i < selColCount; i++)
885 0 : isColSelArray[i] = true;
886 :
887 0 : do {
888 0 : if (nsAccUtils::IsARIASelected(row))
889 0 : continue;
890 :
891 0 : PRInt32 colIdx = 0;
892 :
893 0 : AccIterator cellIter(row, filters::GetCell);
894 0 : nsAccessible *cell = nsnull;
895 0 : for (colIdx = 0; (cell = cellIter.Next()); colIdx++) {
896 0 : if (isColSelArray.SafeElementAt(colIdx, false) &&
897 0 : !nsAccUtils::IsARIASelected(cell)) {
898 0 : isColSelArray[colIdx] = false;
899 0 : selColCount--;
900 : }
901 : }
902 : } while ((row = rowIter.Next()));
903 :
904 0 : if (!selColCount)
905 0 : return NS_OK;
906 :
907 0 : if (!aColumns) {
908 0 : *acolumnCount = selColCount;
909 0 : return NS_OK;
910 : }
911 :
912 : *aColumns = static_cast<PRInt32*>(
913 0 : nsMemory::Alloc(selColCount * sizeof(PRInt32)));
914 0 : NS_ENSURE_TRUE(*aColumns, NS_ERROR_OUT_OF_MEMORY);
915 :
916 0 : *acolumnCount = selColCount;
917 0 : for (PRInt32 colIdx = 0, idx = 0; colIdx < colCount; colIdx++) {
918 0 : if (isColSelArray[colIdx])
919 0 : (*aColumns)[idx++] = colIdx;
920 : }
921 :
922 0 : return NS_OK;
923 : }
924 :
925 :
926 : ////////////////////////////////////////////////////////////////////////////////
927 : // nsARIAGridCellAccessible
928 : ////////////////////////////////////////////////////////////////////////////////
929 :
930 :
931 : ////////////////////////////////////////////////////////////////////////////////
932 : // Constructor
933 :
934 0 : nsARIAGridCellAccessible::
935 : nsARIAGridCellAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
936 0 : nsHyperTextAccessibleWrap(aContent, aDoc)
937 : {
938 0 : }
939 :
940 : ////////////////////////////////////////////////////////////////////////////////
941 : // nsISupports
942 :
943 0 : NS_IMPL_ISUPPORTS_INHERITED1(nsARIAGridCellAccessible,
944 : nsHyperTextAccessible,
945 : nsIAccessibleTableCell)
946 :
947 : ////////////////////////////////////////////////////////////////////////////////
948 : // nsIAccessibleTableCell
949 :
950 : NS_IMETHODIMP
951 0 : nsARIAGridCellAccessible::GetTable(nsIAccessibleTable **aTable)
952 : {
953 0 : NS_ENSURE_ARG_POINTER(aTable);
954 0 : *aTable = nsnull;
955 :
956 0 : nsAccessible* thisRow = Parent();
957 0 : if (!thisRow || thisRow->Role() != roles::ROW)
958 0 : return NS_OK;
959 :
960 0 : nsAccessible* table = thisRow->Parent();
961 0 : if (!table)
962 0 : return NS_OK;
963 :
964 0 : roles::Role tableRole = table->Role();
965 0 : if (tableRole != roles::TABLE && tableRole != roles::TREE_TABLE)
966 0 : return NS_OK;
967 :
968 0 : CallQueryInterface(table, aTable);
969 0 : return NS_OK;
970 : }
971 :
972 : NS_IMETHODIMP
973 0 : nsARIAGridCellAccessible::GetColumnIndex(PRInt32 *aColumnIndex)
974 : {
975 0 : NS_ENSURE_ARG_POINTER(aColumnIndex);
976 0 : *aColumnIndex = -1;
977 :
978 0 : if (IsDefunct())
979 0 : return NS_ERROR_FAILURE;
980 :
981 0 : nsAccessible* row = Parent();
982 0 : if (!row)
983 0 : return NS_OK;
984 :
985 0 : *aColumnIndex = 0;
986 :
987 0 : PRInt32 indexInRow = IndexInParent();
988 0 : for (PRInt32 idx = 0; idx < indexInRow; idx++) {
989 0 : nsAccessible* cell = row->GetChildAt(idx);
990 0 : roles::Role role = cell->Role();
991 0 : if (role == roles::GRID_CELL || role == roles::ROWHEADER ||
992 : role == roles::COLUMNHEADER)
993 0 : (*aColumnIndex)++;
994 : }
995 :
996 0 : return NS_OK;
997 : }
998 :
999 : NS_IMETHODIMP
1000 0 : nsARIAGridCellAccessible::GetRowIndex(PRInt32 *aRowIndex)
1001 : {
1002 0 : NS_ENSURE_ARG_POINTER(aRowIndex);
1003 0 : *aRowIndex = -1;
1004 :
1005 0 : if (IsDefunct())
1006 0 : return NS_ERROR_FAILURE;
1007 :
1008 0 : nsAccessible* row = Parent();
1009 0 : if (!row)
1010 0 : return NS_OK;
1011 :
1012 0 : nsAccessible* table = row->Parent();
1013 0 : if (!table)
1014 0 : return NS_OK;
1015 :
1016 0 : *aRowIndex = 0;
1017 :
1018 0 : PRInt32 indexInTable = row->IndexInParent();
1019 0 : for (PRInt32 idx = 0; idx < indexInTable; idx++) {
1020 0 : row = table->GetChildAt(idx);
1021 0 : if (row->Role() == roles::ROW)
1022 0 : (*aRowIndex)++;
1023 : }
1024 :
1025 0 : return NS_OK;
1026 : }
1027 :
1028 : NS_IMETHODIMP
1029 0 : nsARIAGridCellAccessible::GetColumnExtent(PRInt32 *aExtentCount)
1030 : {
1031 0 : NS_ENSURE_ARG_POINTER(aExtentCount);
1032 0 : *aExtentCount = 0;
1033 :
1034 0 : if (IsDefunct())
1035 0 : return NS_ERROR_FAILURE;
1036 :
1037 0 : *aExtentCount = 1;
1038 0 : return NS_OK;
1039 : }
1040 :
1041 : NS_IMETHODIMP
1042 0 : nsARIAGridCellAccessible::GetRowExtent(PRInt32 *aExtentCount)
1043 : {
1044 0 : NS_ENSURE_ARG_POINTER(aExtentCount);
1045 0 : *aExtentCount = 0;
1046 :
1047 0 : if (IsDefunct())
1048 0 : return NS_ERROR_FAILURE;
1049 :
1050 0 : *aExtentCount = 1;
1051 0 : return NS_OK;
1052 : }
1053 :
1054 : NS_IMETHODIMP
1055 0 : nsARIAGridCellAccessible::GetColumnHeaderCells(nsIArray **aHeaderCells)
1056 : {
1057 0 : NS_ENSURE_ARG_POINTER(aHeaderCells);
1058 0 : *aHeaderCells = nsnull;
1059 :
1060 0 : if (IsDefunct())
1061 0 : return NS_ERROR_FAILURE;
1062 :
1063 0 : nsCOMPtr<nsIAccessibleTable> table;
1064 0 : GetTable(getter_AddRefs(table));
1065 0 : if (!table)
1066 0 : return NS_OK;
1067 :
1068 : return nsAccUtils::GetHeaderCellsFor(table, this,
1069 : nsAccUtils::eColumnHeaderCells,
1070 0 : aHeaderCells);
1071 : }
1072 :
1073 : NS_IMETHODIMP
1074 0 : nsARIAGridCellAccessible::GetRowHeaderCells(nsIArray **aHeaderCells)
1075 : {
1076 0 : NS_ENSURE_ARG_POINTER(aHeaderCells);
1077 0 : *aHeaderCells = nsnull;
1078 :
1079 0 : if (IsDefunct())
1080 0 : return NS_ERROR_FAILURE;
1081 :
1082 0 : nsCOMPtr<nsIAccessibleTable> table;
1083 0 : GetTable(getter_AddRefs(table));
1084 0 : if (!table)
1085 0 : return NS_OK;
1086 :
1087 : return nsAccUtils::GetHeaderCellsFor(table, this,
1088 : nsAccUtils::eRowHeaderCells,
1089 0 : aHeaderCells);
1090 : }
1091 :
1092 : NS_IMETHODIMP
1093 0 : nsARIAGridCellAccessible::IsSelected(bool *aIsSelected)
1094 : {
1095 0 : NS_ENSURE_ARG_POINTER(aIsSelected);
1096 0 : *aIsSelected = false;
1097 :
1098 0 : if (IsDefunct())
1099 0 : return NS_ERROR_FAILURE;
1100 :
1101 0 : nsAccessible* row = Parent();
1102 0 : if (!row || row->Role() != roles::ROW)
1103 0 : return NS_OK;
1104 :
1105 0 : if (!nsAccUtils::IsARIASelected(row) && !nsAccUtils::IsARIASelected(this))
1106 0 : return NS_OK;
1107 :
1108 0 : *aIsSelected = true;
1109 0 : return NS_OK;
1110 : }
1111 :
1112 : ////////////////////////////////////////////////////////////////////////////////
1113 : // nsAccessible
1114 :
1115 : void
1116 0 : nsARIAGridCellAccessible::ApplyARIAState(PRUint64* aState)
1117 : {
1118 0 : nsHyperTextAccessibleWrap::ApplyARIAState(aState);
1119 :
1120 : // Return if the gridcell has aria-selected="true".
1121 0 : if (*aState & states::SELECTED)
1122 0 : return;
1123 :
1124 : // Check aria-selected="true" on the row.
1125 0 : nsAccessible* row = Parent();
1126 0 : if (!row || row->Role() != roles::ROW)
1127 0 : return;
1128 :
1129 0 : nsIContent *rowContent = row->GetContent();
1130 0 : if (nsAccUtils::HasDefinedARIAToken(rowContent,
1131 0 : nsGkAtoms::aria_selected) &&
1132 : !rowContent->AttrValueIs(kNameSpaceID_None,
1133 : nsGkAtoms::aria_selected,
1134 0 : nsGkAtoms::_false, eCaseMatters))
1135 0 : *aState |= states::SELECTABLE | states::SELECTED;
1136 : }
1137 :
1138 : nsresult
1139 0 : nsARIAGridCellAccessible::GetAttributesInternal(nsIPersistentProperties *aAttributes)
1140 : {
1141 0 : if (IsDefunct())
1142 0 : return NS_ERROR_FAILURE;
1143 :
1144 0 : nsresult rv = nsHyperTextAccessibleWrap::GetAttributesInternal(aAttributes);
1145 0 : NS_ENSURE_SUCCESS(rv, rv);
1146 :
1147 : // Expose "table-cell-index" attribute.
1148 :
1149 0 : nsAccessible* thisRow = Parent();
1150 0 : if (!thisRow || thisRow->Role() != roles::ROW)
1151 0 : return NS_OK;
1152 :
1153 0 : PRInt32 colIdx = 0, colCount = 0;
1154 0 : PRInt32 childCount = thisRow->GetChildCount();
1155 0 : for (PRInt32 childIdx = 0; childIdx < childCount; childIdx++) {
1156 0 : nsAccessible *child = thisRow->GetChildAt(childIdx);
1157 0 : if (child == this)
1158 0 : colIdx = colCount;
1159 :
1160 0 : roles::Role role = child->Role();
1161 0 : if (role == roles::GRID_CELL || role == roles::ROWHEADER ||
1162 : role == roles::COLUMNHEADER)
1163 0 : colCount++;
1164 : }
1165 :
1166 0 : nsAccessible* table = thisRow->Parent();
1167 0 : if (!table)
1168 0 : return NS_OK;
1169 :
1170 0 : roles::Role tableRole = table->Role();
1171 0 : if (tableRole != roles::TABLE && tableRole != roles::TREE_TABLE)
1172 0 : return NS_OK;
1173 :
1174 0 : PRInt32 rowIdx = 0;
1175 0 : childCount = table->GetChildCount();
1176 0 : for (PRInt32 childIdx = 0; childIdx < childCount; childIdx++) {
1177 0 : nsAccessible *child = table->GetChildAt(childIdx);
1178 0 : if (child == thisRow)
1179 0 : break;
1180 :
1181 0 : if (child->Role() == roles::ROW)
1182 0 : rowIdx++;
1183 : }
1184 :
1185 0 : PRInt32 idx = rowIdx * colCount + colIdx;
1186 :
1187 0 : nsAutoString stringIdx;
1188 0 : stringIdx.AppendInt(idx);
1189 : nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::tableCellIndex,
1190 0 : stringIdx);
1191 :
1192 0 : return NS_OK;
1193 : }
|