Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/accessible/html/HTMLTableAccessible.cpp
Line
Count
Source (jump to first uncovered line)
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
6
#include "HTMLTableAccessible.h"
7
8
#include "mozilla/DebugOnly.h"
9
10
#include "Accessible-inl.h"
11
#include "nsAccessibilityService.h"
12
#include "nsAccUtils.h"
13
#include "DocAccessible.h"
14
#include "nsTextEquivUtils.h"
15
#include "Relation.h"
16
#include "Role.h"
17
#include "States.h"
18
#include "TreeWalker.h"
19
20
#include "mozilla/dom/HTMLTableElement.h"
21
#include "nsIHTMLCollection.h"
22
#include "nsIDocument.h"
23
#include "nsIMutableArray.h"
24
#include "nsIPersistentProperties2.h"
25
#include "nsIPresShell.h"
26
#include "nsITableCellLayout.h"
27
#include "nsFrameSelection.h"
28
#include "nsError.h"
29
#include "nsArrayUtils.h"
30
#include "nsComponentManagerUtils.h"
31
#include "nsNameSpaceManager.h"
32
#include "nsTableCellFrame.h"
33
#include "nsTableWrapperFrame.h"
34
35
using namespace mozilla;
36
using namespace mozilla::dom;
37
using namespace mozilla::a11y;
38
39
////////////////////////////////////////////////////////////////////////////////
40
// HTMLTableCellAccessible
41
////////////////////////////////////////////////////////////////////////////////
42
43
HTMLTableCellAccessible::
44
  HTMLTableCellAccessible(nsIContent* aContent, DocAccessible* aDoc) :
45
  HyperTextAccessibleWrap(aContent, aDoc)
46
0
{
47
0
  mType = eHTMLTableCellType;
48
0
  mGenericTypes |= eTableCell;
49
0
}
50
51
////////////////////////////////////////////////////////////////////////////////
52
// HTMLTableCellAccessible: Accessible implementation
53
54
role
55
HTMLTableCellAccessible::NativeRole() const
56
0
{
57
0
  if (mContent->IsMathMLElement(nsGkAtoms::mtd_)) {
58
0
    return roles::MATHML_CELL;
59
0
  }
60
0
  return roles::CELL;
61
0
}
62
63
uint64_t
64
HTMLTableCellAccessible::NativeState() const
65
0
{
66
0
  uint64_t state = HyperTextAccessibleWrap::NativeState();
67
0
68
0
  nsIFrame *frame = mContent->GetPrimaryFrame();
69
0
  NS_ASSERTION(frame, "No frame for valid cell accessible!");
70
0
71
0
  if (frame && frame->IsSelected())
72
0
    state |= states::SELECTED;
73
0
74
0
  return state;
75
0
}
76
77
uint64_t
78
HTMLTableCellAccessible::NativeInteractiveState() const
79
0
{
80
0
  return HyperTextAccessibleWrap::NativeInteractiveState() | states::SELECTABLE;
81
0
}
82
83
already_AddRefed<nsIPersistentProperties>
84
HTMLTableCellAccessible::NativeAttributes()
85
0
{
86
0
  nsCOMPtr<nsIPersistentProperties> attributes =
87
0
    HyperTextAccessibleWrap::NativeAttributes();
88
0
89
0
  // table-cell-index attribute
90
0
  TableAccessible* table = Table();
91
0
  if (!table)
92
0
    return attributes.forget();
93
0
94
0
  int32_t rowIdx = -1, colIdx = -1;
95
0
  nsresult rv = GetCellIndexes(rowIdx, colIdx);
96
0
  if (NS_FAILED(rv))
97
0
    return attributes.forget();
98
0
99
0
  nsAutoString stringIdx;
100
0
  stringIdx.AppendInt(table->CellIndexAt(rowIdx, colIdx));
101
0
  nsAccUtils::SetAccAttr(attributes, nsGkAtoms::tableCellIndex, stringIdx);
102
0
103
0
  // abbr attribute
104
0
105
0
  // Pick up object attribute from abbr DOM element (a child of the cell) or
106
0
  // from abbr DOM attribute.
107
0
  nsAutoString abbrText;
108
0
  if (ChildCount() == 1) {
109
0
    Accessible* abbr = FirstChild();
110
0
    if (abbr->IsAbbreviation()) {
111
0
      nsIContent* firstChildNode = abbr->GetContent()->GetFirstChild();
112
0
      if (firstChildNode) {
113
0
        nsTextEquivUtils::
114
0
          AppendTextEquivFromTextContent(firstChildNode, &abbrText);
115
0
      }
116
0
    }
117
0
  }
118
0
  if (abbrText.IsEmpty())
119
0
    mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::abbr, abbrText);
120
0
121
0
  if (!abbrText.IsEmpty())
122
0
    nsAccUtils::SetAccAttr(attributes, nsGkAtoms::abbr, abbrText);
123
0
124
0
  // axis attribute
125
0
  nsAutoString axisText;
126
0
  mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::axis, axisText);
127
0
  if (!axisText.IsEmpty())
128
0
    nsAccUtils::SetAccAttr(attributes, nsGkAtoms::axis, axisText);
129
0
130
#ifdef DEBUG
131
  nsAutoString unused;
132
  attributes->SetStringProperty(NS_LITERAL_CSTRING("cppclass"),
133
                                NS_LITERAL_STRING("HTMLTableCellAccessible"),
134
                                unused);
135
#endif
136
137
0
  return attributes.forget();
138
0
}
139
140
GroupPos
141
HTMLTableCellAccessible::GroupPosition()
142
0
{
143
0
  int32_t count = 0, index = 0;
144
0
  TableAccessible* table = Table();
145
0
  if (table && nsCoreUtils::GetUIntAttr(table->AsAccessible()->GetContent(),
146
0
                                        nsGkAtoms::aria_colcount, &count) &&
147
0
      nsCoreUtils::GetUIntAttr(mContent, nsGkAtoms::aria_colindex, &index)) {
148
0
    return GroupPos(0, index, count);
149
0
  }
150
0
151
0
  return HyperTextAccessibleWrap::GroupPosition();
152
0
}
153
154
////////////////////////////////////////////////////////////////////////////////
155
// HTMLTableCellAccessible: TableCellAccessible implementation
156
157
TableAccessible*
158
HTMLTableCellAccessible::Table() const
159
0
{
160
0
  Accessible* parent = const_cast<HTMLTableCellAccessible*>(this);
161
0
  while ((parent = parent->Parent())) {
162
0
    if (parent->IsTable())
163
0
      return parent->AsTable();
164
0
  }
165
0
166
0
  return nullptr;
167
0
}
168
169
uint32_t
170
HTMLTableCellAccessible::ColIdx() const
171
0
{
172
0
  nsTableCellFrame* cellFrame = GetCellFrame();
173
0
  NS_ENSURE_TRUE(cellFrame, 0);
174
0
  return cellFrame->ColIndex();
175
0
}
176
177
uint32_t
178
HTMLTableCellAccessible::RowIdx() const
179
0
{
180
0
  nsTableCellFrame* cellFrame = GetCellFrame();
181
0
  NS_ENSURE_TRUE(cellFrame, 0);
182
0
  return cellFrame->RowIndex();
183
0
}
184
185
uint32_t
186
HTMLTableCellAccessible::ColExtent() const
187
0
{
188
0
  int32_t rowIdx = -1, colIdx = -1;
189
0
  GetCellIndexes(rowIdx, colIdx);
190
0
191
0
  TableAccessible* table = Table();
192
0
  NS_ASSERTION(table, "cell not in a table!");
193
0
  if (!table)
194
0
    return 0;
195
0
196
0
  return table->ColExtentAt(rowIdx, colIdx);
197
0
}
198
199
uint32_t
200
HTMLTableCellAccessible::RowExtent() const
201
0
{
202
0
  int32_t rowIdx = -1, colIdx = -1;
203
0
  GetCellIndexes(rowIdx, colIdx);
204
0
205
0
  TableAccessible* table = Table();
206
0
  NS_ASSERTION(table, "cell not in atable!");
207
0
  if (!table)
208
0
    return 0;
209
0
210
0
  return table->RowExtentAt(rowIdx, colIdx);
211
0
}
212
213
void
214
HTMLTableCellAccessible::ColHeaderCells(nsTArray<Accessible*>* aCells)
215
0
{
216
0
  IDRefsIterator itr(mDoc, mContent, nsGkAtoms::headers);
217
0
  while (Accessible* cell = itr.Next()) {
218
0
    a11y::role cellRole = cell->Role();
219
0
    if (cellRole == roles::COLUMNHEADER) {
220
0
      aCells->AppendElement(cell);
221
0
    } else if (cellRole != roles::ROWHEADER) {
222
0
      // If referred table cell is at the same column then treat it as a column
223
0
      // header.
224
0
      TableCellAccessible* tableCell = cell->AsTableCell();
225
0
      if (tableCell && tableCell->ColIdx() == ColIdx())
226
0
        aCells->AppendElement(cell);
227
0
    }
228
0
  }
229
0
230
0
  if (aCells->IsEmpty())
231
0
    TableCellAccessible::ColHeaderCells(aCells);
232
0
}
233
234
void
235
HTMLTableCellAccessible::RowHeaderCells(nsTArray<Accessible*>* aCells)
236
0
{
237
0
  IDRefsIterator itr(mDoc, mContent, nsGkAtoms::headers);
238
0
  while (Accessible* cell = itr.Next()) {
239
0
    a11y::role cellRole = cell->Role();
240
0
    if (cellRole == roles::ROWHEADER) {
241
0
      aCells->AppendElement(cell);
242
0
    } else if (cellRole != roles::COLUMNHEADER) {
243
0
      // If referred table cell is at the same row then treat it as a column
244
0
      // header.
245
0
      TableCellAccessible* tableCell = cell->AsTableCell();
246
0
      if (tableCell && tableCell->RowIdx() == RowIdx())
247
0
        aCells->AppendElement(cell);
248
0
    }
249
0
  }
250
0
251
0
  if (aCells->IsEmpty())
252
0
    TableCellAccessible::RowHeaderCells(aCells);
253
0
}
254
255
bool
256
HTMLTableCellAccessible::Selected()
257
0
{
258
0
  int32_t rowIdx = -1, colIdx = -1;
259
0
  GetCellIndexes(rowIdx, colIdx);
260
0
261
0
  TableAccessible* table = Table();
262
0
  NS_ENSURE_TRUE(table, false);
263
0
264
0
  return table->IsCellSelected(rowIdx, colIdx);
265
0
}
266
267
////////////////////////////////////////////////////////////////////////////////
268
// HTMLTableCellAccessible: protected implementation
269
270
nsITableCellLayout*
271
HTMLTableCellAccessible::GetCellLayout() const
272
0
{
273
0
  return do_QueryFrame(mContent->GetPrimaryFrame());
274
0
}
275
276
nsTableCellFrame*
277
HTMLTableCellAccessible::GetCellFrame() const
278
0
{
279
0
  return do_QueryFrame(mContent->GetPrimaryFrame());
280
0
}
281
282
nsresult
283
HTMLTableCellAccessible::GetCellIndexes(int32_t& aRowIdx, int32_t& aColIdx) const
284
0
{
285
0
  nsITableCellLayout *cellLayout = GetCellLayout();
286
0
  NS_ENSURE_STATE(cellLayout);
287
0
288
0
  return cellLayout->GetCellIndexes(aRowIdx, aColIdx);
289
0
}
290
291
292
////////////////////////////////////////////////////////////////////////////////
293
// HTMLTableHeaderCellAccessible
294
////////////////////////////////////////////////////////////////////////////////
295
296
HTMLTableHeaderCellAccessible::
297
  HTMLTableHeaderCellAccessible(nsIContent* aContent, DocAccessible* aDoc) :
298
  HTMLTableCellAccessible(aContent, aDoc)
299
0
{
300
0
}
301
302
////////////////////////////////////////////////////////////////////////////////
303
// HTMLTableHeaderCellAccessible: Accessible implementation
304
305
role
306
HTMLTableHeaderCellAccessible::NativeRole() const
307
0
{
308
0
  // Check value of @scope attribute.
309
0
  static Element::AttrValuesArray scopeValues[] =
310
0
    { &nsGkAtoms::col, &nsGkAtoms::colgroup,
311
0
      &nsGkAtoms::row, &nsGkAtoms::rowgroup, nullptr };
312
0
  int32_t valueIdx =
313
0
    mContent->AsElement()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::scope,
314
0
                                           scopeValues, eCaseMatters);
315
0
316
0
  switch (valueIdx) {
317
0
    case 0:
318
0
    case 1:
319
0
      return roles::COLUMNHEADER;
320
0
    case 2:
321
0
    case 3:
322
0
      return roles::ROWHEADER;
323
0
  }
324
0
325
0
  TableAccessible* table = Table();
326
0
  if (!table)
327
0
    return roles::NOTHING;
328
0
329
0
  // If the cell next to this one is not a header cell then assume this cell is
330
0
  // a row header for it.
331
0
  uint32_t rowIdx = RowIdx(), colIdx = ColIdx();
332
0
  Accessible* cell = table->CellAt(rowIdx, colIdx + ColExtent());
333
0
  if (cell && !nsCoreUtils::IsHTMLTableHeader(cell->GetContent()))
334
0
    return roles::ROWHEADER;
335
0
336
0
  // If the cell below this one is not a header cell then assume this cell is
337
0
  // a column header for it.
338
0
  uint32_t rowExtent = RowExtent();
339
0
  cell = table->CellAt(rowIdx + rowExtent, colIdx);
340
0
  if (cell && !nsCoreUtils::IsHTMLTableHeader(cell->GetContent()))
341
0
    return roles::COLUMNHEADER;
342
0
343
0
  // Otherwise if this cell is surrounded by header cells only then make a guess
344
0
  // based on its cell spanning. In other words if it is row spanned then assume
345
0
  // it's a row header, otherwise it's a column header.
346
0
  return rowExtent > 1 ? roles::ROWHEADER : roles::COLUMNHEADER;
347
0
}
348
349
350
////////////////////////////////////////////////////////////////////////////////
351
// HTMLTableRowAccessible
352
////////////////////////////////////////////////////////////////////////////////
353
354
role
355
HTMLTableRowAccessible::NativeRole() const
356
0
{
357
0
  if (mContent->IsMathMLElement(nsGkAtoms::mtr_)) {
358
0
    return roles::MATHML_TABLE_ROW;
359
0
  } else if (mContent->IsMathMLElement(nsGkAtoms::mlabeledtr_)) {
360
0
    return roles::MATHML_LABELED_ROW;
361
0
  }
362
0
  return roles::ROW;
363
0
}
364
365
GroupPos
366
HTMLTableRowAccessible::GroupPosition()
367
0
{
368
0
  int32_t count = 0, index = 0;
369
0
  Accessible* table = nsAccUtils::TableFor(this);
370
0
  if (table && nsCoreUtils::GetUIntAttr(table->GetContent(),
371
0
                                        nsGkAtoms::aria_rowcount, &count) &&
372
0
      nsCoreUtils::GetUIntAttr(mContent, nsGkAtoms::aria_rowindex, &index)) {
373
0
    return GroupPos(0, index, count);
374
0
  }
375
0
376
0
  return AccessibleWrap::GroupPosition();
377
0
}
378
379
////////////////////////////////////////////////////////////////////////////////
380
// HTMLTableAccessible
381
////////////////////////////////////////////////////////////////////////////////
382
383
////////////////////////////////////////////////////////////////////////////////
384
// HTMLTableAccessible: Accessible
385
386
bool
387
HTMLTableAccessible::InsertChildAt(uint32_t aIndex, Accessible* aChild)
388
0
{
389
0
  // Move caption accessible so that it's the first child. Check for the first
390
0
  // caption only, because nsAccessibilityService ensures we don't create
391
0
  // accessibles for the other captions, since only the first is actually
392
0
  // visible.
393
0
  return Accessible::InsertChildAt(aChild->IsHTMLCaption() ? 0 : aIndex, aChild);
394
0
}
395
396
role
397
HTMLTableAccessible::NativeRole() const
398
0
{
399
0
  if (mContent->IsMathMLElement(nsGkAtoms::mtable_)) {
400
0
    return roles::MATHML_TABLE;
401
0
  }
402
0
  return roles::TABLE;
403
0
}
404
405
uint64_t
406
HTMLTableAccessible::NativeState() const
407
0
{
408
0
  return Accessible::NativeState() | states::READONLY;
409
0
}
410
411
ENameValueFlag
412
HTMLTableAccessible::NativeName(nsString& aName) const
413
0
{
414
0
  ENameValueFlag nameFlag = Accessible::NativeName(aName);
415
0
  if (!aName.IsEmpty())
416
0
    return nameFlag;
417
0
418
0
  // Use table caption as a name.
419
0
  Accessible* caption = Caption();
420
0
  if (caption) {
421
0
    nsIContent* captionContent = caption->GetContent();
422
0
    if (captionContent) {
423
0
      nsTextEquivUtils::AppendTextEquivFromContent(this, captionContent, &aName);
424
0
      if (!aName.IsEmpty())
425
0
        return eNameOK;
426
0
    }
427
0
  }
428
0
429
0
  // If no caption then use summary as a name.
430
0
  mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::summary, aName);
431
0
  return eNameOK;
432
0
}
433
434
already_AddRefed<nsIPersistentProperties>
435
HTMLTableAccessible::NativeAttributes()
436
0
{
437
0
  nsCOMPtr<nsIPersistentProperties> attributes =
438
0
    AccessibleWrap::NativeAttributes();
439
0
440
0
  if (mContent->IsMathMLElement(nsGkAtoms::mtable_)) {
441
0
    GetAccService()->MarkupAttributes(mContent, attributes);
442
0
  }
443
0
444
0
  if (IsProbablyLayoutTable()) {
445
0
    nsAutoString unused;
446
0
    attributes->SetStringProperty(NS_LITERAL_CSTRING("layout-guess"),
447
0
                                  NS_LITERAL_STRING("true"), unused);
448
0
  }
449
0
450
0
  return attributes.forget();
451
0
}
452
453
////////////////////////////////////////////////////////////////////////////////
454
// HTMLTableAccessible: Accessible
455
456
Relation
457
HTMLTableAccessible::RelationByType(RelationType aType) const
458
0
{
459
0
  Relation rel = AccessibleWrap::RelationByType(aType);
460
0
  if (aType == RelationType::LABELLED_BY)
461
0
    rel.AppendTarget(Caption());
462
0
463
0
  return rel;
464
0
}
465
466
////////////////////////////////////////////////////////////////////////////////
467
// HTMLTableAccessible: Table
468
469
Accessible*
470
HTMLTableAccessible::Caption() const
471
0
{
472
0
  Accessible* child = mChildren.SafeElementAt(0, nullptr);
473
0
  return child && child->Role() == roles::CAPTION ? child : nullptr;
474
0
}
475
476
void
477
HTMLTableAccessible::Summary(nsString& aSummary)
478
0
{
479
0
  dom::HTMLTableElement* table = dom::HTMLTableElement::FromNode(mContent);
480
0
481
0
  if (table)
482
0
    table->GetSummary(aSummary);
483
0
}
484
485
uint32_t
486
HTMLTableAccessible::ColCount() const
487
0
{
488
0
  nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
489
0
  return tableFrame ? tableFrame->GetColCount() : 0;
490
0
}
491
492
uint32_t
493
HTMLTableAccessible::RowCount()
494
0
{
495
0
  nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
496
0
  return tableFrame ? tableFrame->GetRowCount() : 0;
497
0
}
498
499
uint32_t
500
HTMLTableAccessible::SelectedCellCount()
501
0
{
502
0
  nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
503
0
  if (!tableFrame)
504
0
    return 0;
505
0
506
0
  uint32_t count = 0, rowCount = RowCount(), colCount = ColCount();
507
0
  for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
508
0
    for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) {
509
0
      nsTableCellFrame* cellFrame = tableFrame->GetCellFrameAt(rowIdx, colIdx);
510
0
      if (!cellFrame || !cellFrame->IsSelected())
511
0
        continue;
512
0
513
0
      uint32_t startRow = cellFrame->RowIndex();
514
0
      uint32_t startCol = cellFrame->ColIndex();
515
0
      if (startRow == rowIdx && startCol == colIdx)
516
0
        count++;
517
0
    }
518
0
  }
519
0
520
0
  return count;
521
0
}
522
523
uint32_t
524
HTMLTableAccessible::SelectedColCount()
525
0
{
526
0
  uint32_t count = 0, colCount = ColCount();
527
0
528
0
  for (uint32_t colIdx = 0; colIdx < colCount; colIdx++)
529
0
    if (IsColSelected(colIdx))
530
0
      count++;
531
0
532
0
  return count;
533
0
}
534
535
uint32_t
536
HTMLTableAccessible::SelectedRowCount()
537
0
{
538
0
  uint32_t count = 0, rowCount = RowCount();
539
0
540
0
  for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++)
541
0
    if (IsRowSelected(rowIdx))
542
0
      count++;
543
0
544
0
  return count;
545
0
}
546
547
void
548
HTMLTableAccessible::SelectedCells(nsTArray<Accessible*>* aCells)
549
0
{
550
0
  nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
551
0
  if (!tableFrame)
552
0
    return;
553
0
554
0
  uint32_t rowCount = RowCount(), colCount = ColCount();
555
0
  for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
556
0
    for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) {
557
0
      nsTableCellFrame* cellFrame = tableFrame->GetCellFrameAt(rowIdx, colIdx);
558
0
      if (!cellFrame || !cellFrame->IsSelected())
559
0
        continue;
560
0
561
0
      uint32_t startRow = cellFrame->RowIndex();
562
0
      uint32_t startCol = cellFrame->ColIndex();
563
0
      if (startRow != rowIdx || startCol != colIdx)
564
0
        continue;
565
0
566
0
      Accessible* cell = mDoc->GetAccessible(cellFrame->GetContent());
567
0
        aCells->AppendElement(cell);
568
0
    }
569
0
  }
570
0
}
571
572
void
573
HTMLTableAccessible::SelectedCellIndices(nsTArray<uint32_t>* aCells)
574
0
{
575
0
  nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
576
0
  if (!tableFrame)
577
0
    return;
578
0
579
0
  uint32_t rowCount = RowCount(), colCount = ColCount();
580
0
  for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
581
0
    for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) {
582
0
      nsTableCellFrame* cellFrame = tableFrame->GetCellFrameAt(rowIdx, colIdx);
583
0
      if (!cellFrame || !cellFrame->IsSelected())
584
0
        continue;
585
0
586
0
      uint32_t startCol = cellFrame->ColIndex();
587
0
      uint32_t startRow = cellFrame->RowIndex();
588
0
      if (startRow == rowIdx && startCol == colIdx)
589
0
        aCells->AppendElement(CellIndexAt(rowIdx, colIdx));
590
0
    }
591
0
  }
592
0
}
593
594
void
595
HTMLTableAccessible::SelectedColIndices(nsTArray<uint32_t>* aCols)
596
0
{
597
0
  uint32_t colCount = ColCount();
598
0
  for (uint32_t colIdx = 0; colIdx < colCount; colIdx++)
599
0
    if (IsColSelected(colIdx))
600
0
      aCols->AppendElement(colIdx);
601
0
}
602
603
void
604
HTMLTableAccessible::SelectedRowIndices(nsTArray<uint32_t>* aRows)
605
0
{
606
0
  uint32_t rowCount = RowCount();
607
0
  for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++)
608
0
    if (IsRowSelected(rowIdx))
609
0
      aRows->AppendElement(rowIdx);
610
0
}
611
612
Accessible*
613
HTMLTableAccessible::CellAt(uint32_t aRowIdx, uint32_t aColIdx)
614
0
{
615
0
  nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
616
0
  if (!tableFrame)
617
0
    return nullptr;
618
0
619
0
  nsIContent* cellContent = tableFrame->GetCellAt(aRowIdx, aColIdx);
620
0
  Accessible* cell = mDoc->GetAccessible(cellContent);
621
0
622
0
  // XXX bug 576838: crazy tables (like table6 in tables/test_table2.html) may
623
0
  // return itself as a cell what makes Orca hang.
624
0
  return cell == this ? nullptr : cell;
625
0
}
626
627
int32_t
628
HTMLTableAccessible::CellIndexAt(uint32_t aRowIdx, uint32_t aColIdx)
629
0
{
630
0
  nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
631
0
  if (!tableFrame)
632
0
    return -1;
633
0
634
0
  return tableFrame->GetIndexByRowAndColumn(aRowIdx, aColIdx);
635
0
}
636
637
int32_t
638
HTMLTableAccessible::ColIndexAt(uint32_t aCellIdx)
639
0
{
640
0
  nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
641
0
  if (!tableFrame)
642
0
    return -1;
643
0
644
0
  int32_t rowIdx = -1, colIdx = -1;
645
0
  tableFrame->GetRowAndColumnByIndex(aCellIdx, &rowIdx, &colIdx);
646
0
  return colIdx;
647
0
}
648
649
int32_t
650
HTMLTableAccessible::RowIndexAt(uint32_t aCellIdx)
651
0
{
652
0
  nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
653
0
  if (!tableFrame)
654
0
    return -1;
655
0
656
0
  int32_t rowIdx = -1, colIdx = -1;
657
0
  tableFrame->GetRowAndColumnByIndex(aCellIdx, &rowIdx, &colIdx);
658
0
  return rowIdx;
659
0
}
660
661
void
662
HTMLTableAccessible::RowAndColIndicesAt(uint32_t aCellIdx, int32_t* aRowIdx,
663
                                        int32_t* aColIdx)
664
0
{
665
0
  nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
666
0
  if (tableFrame)
667
0
    tableFrame->GetRowAndColumnByIndex(aCellIdx, aRowIdx, aColIdx);
668
0
}
669
670
uint32_t
671
HTMLTableAccessible::ColExtentAt(uint32_t aRowIdx, uint32_t aColIdx)
672
0
{
673
0
  nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
674
0
  if (!tableFrame)
675
0
    return 0;
676
0
677
0
  return tableFrame->GetEffectiveColSpanAt(aRowIdx, aColIdx);
678
0
}
679
680
uint32_t
681
HTMLTableAccessible::RowExtentAt(uint32_t aRowIdx, uint32_t aColIdx)
682
0
{
683
0
  nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
684
0
  if (!tableFrame)
685
0
    return 0;
686
0
687
0
  return tableFrame->GetEffectiveRowSpanAt(aRowIdx, aColIdx);
688
0
}
689
690
bool
691
HTMLTableAccessible::IsColSelected(uint32_t aColIdx)
692
0
{
693
0
  bool isSelected = false;
694
0
695
0
  uint32_t rowCount = RowCount();
696
0
  for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
697
0
    isSelected = IsCellSelected(rowIdx, aColIdx);
698
0
    if (!isSelected)
699
0
      return false;
700
0
  }
701
0
702
0
  return isSelected;
703
0
}
704
705
bool
706
HTMLTableAccessible::IsRowSelected(uint32_t aRowIdx)
707
0
{
708
0
  bool isSelected = false;
709
0
710
0
  uint32_t colCount = ColCount();
711
0
  for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) {
712
0
    isSelected = IsCellSelected(aRowIdx, colIdx);
713
0
    if (!isSelected)
714
0
      return false;
715
0
  }
716
0
717
0
  return isSelected;
718
0
}
719
720
bool
721
HTMLTableAccessible::IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx)
722
0
{
723
0
  nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
724
0
  if (!tableFrame)
725
0
    return false;
726
0
727
0
  nsTableCellFrame* cellFrame = tableFrame->GetCellFrameAt(aRowIdx, aColIdx);
728
0
  return cellFrame ? cellFrame->IsSelected() : false;
729
0
}
730
731
void
732
HTMLTableAccessible::SelectRow(uint32_t aRowIdx)
733
0
{
734
0
  DebugOnly<nsresult> rv =
735
0
    RemoveRowsOrColumnsFromSelection(aRowIdx, TableSelection::Row, true);
736
0
  NS_ASSERTION(NS_SUCCEEDED(rv),
737
0
               "RemoveRowsOrColumnsFromSelection() Shouldn't fail!");
738
0
739
0
  AddRowOrColumnToSelection(aRowIdx, TableSelection::Row);
740
0
}
741
742
void
743
HTMLTableAccessible::SelectCol(uint32_t aColIdx)
744
0
{
745
0
  DebugOnly<nsresult> rv =
746
0
    RemoveRowsOrColumnsFromSelection(aColIdx, TableSelection::Column, true);
747
0
  NS_ASSERTION(NS_SUCCEEDED(rv),
748
0
               "RemoveRowsOrColumnsFromSelection() Shouldn't fail!");
749
0
750
0
  AddRowOrColumnToSelection(aColIdx, TableSelection::Column);
751
0
}
752
753
void
754
HTMLTableAccessible::UnselectRow(uint32_t aRowIdx)
755
0
{
756
0
  RemoveRowsOrColumnsFromSelection(aRowIdx, TableSelection::Row, false);
757
0
}
758
759
void
760
HTMLTableAccessible::UnselectCol(uint32_t aColIdx)
761
0
{
762
0
  RemoveRowsOrColumnsFromSelection(aColIdx, TableSelection::Column, false);
763
0
}
764
765
nsresult
766
HTMLTableAccessible::AddRowOrColumnToSelection(int32_t aIndex, TableSelection aTarget)
767
0
{
768
0
  bool doSelectRow = (aTarget == TableSelection::Row);
769
0
770
0
  nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
771
0
  if (!tableFrame)
772
0
    return NS_OK;
773
0
774
0
  uint32_t count = 0;
775
0
  if (doSelectRow)
776
0
    count = ColCount();
777
0
  else
778
0
    count = RowCount();
779
0
780
0
  nsIPresShell* presShell(mDoc->PresShell());
781
0
  RefPtr<nsFrameSelection> tableSelection =
782
0
    const_cast<nsFrameSelection*>(presShell->ConstFrameSelection());
783
0
784
0
  for (uint32_t idx = 0; idx < count; idx++) {
785
0
    int32_t rowIdx = doSelectRow ? aIndex : idx;
786
0
    int32_t colIdx = doSelectRow ? idx : aIndex;
787
0
    nsTableCellFrame* cellFrame = tableFrame->GetCellFrameAt(rowIdx, colIdx);
788
0
    if (cellFrame && !cellFrame->IsSelected()) {
789
0
      nsresult rv = tableSelection->SelectCellElement(cellFrame->GetContent());
790
0
      NS_ENSURE_SUCCESS(rv, rv);
791
0
    }
792
0
  }
793
0
794
0
  return NS_OK;
795
0
}
796
797
nsresult
798
HTMLTableAccessible::RemoveRowsOrColumnsFromSelection(int32_t aIndex,
799
                                                      TableSelection aTarget,
800
                                                      bool aIsOuter)
801
0
{
802
0
  nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
803
0
  if (!tableFrame)
804
0
    return NS_OK;
805
0
806
0
  nsIPresShell* presShell(mDoc->PresShell());
807
0
  RefPtr<nsFrameSelection> tableSelection =
808
0
    const_cast<nsFrameSelection*>(presShell->ConstFrameSelection());
809
0
810
0
  bool doUnselectRow = (aTarget == TableSelection::Row);
811
0
  uint32_t count = doUnselectRow ? ColCount() : RowCount();
812
0
813
0
  int32_t startRowIdx = doUnselectRow ? aIndex : 0;
814
0
  int32_t endRowIdx = doUnselectRow ? aIndex : count - 1;
815
0
  int32_t startColIdx = doUnselectRow ? 0 : aIndex;
816
0
  int32_t endColIdx = doUnselectRow ? count - 1 : aIndex;
817
0
818
0
  if (aIsOuter)
819
0
    return tableSelection->RestrictCellsToSelection(mContent,
820
0
                                                    startRowIdx, startColIdx,
821
0
                                                    endRowIdx, endColIdx);
822
0
823
0
  return tableSelection->RemoveCellsFromSelection(mContent,
824
0
                                                  startRowIdx, startColIdx,
825
0
                                                  endRowIdx, endColIdx);
826
0
}
827
828
void
829
HTMLTableAccessible::Description(nsString& aDescription)
830
0
{
831
0
  // Helpful for debugging layout vs. data tables
832
0
  aDescription.Truncate();
833
0
  Accessible::Description(aDescription);
834
0
  if (!aDescription.IsEmpty())
835
0
    return;
836
0
837
0
  // Use summary as description if it weren't used as a name.
838
0
  // XXX: get rid code duplication with NameInternal().
839
0
  Accessible* caption = Caption();
840
0
  if (caption) {
841
0
    nsIContent* captionContent = caption->GetContent();
842
0
    if (captionContent) {
843
0
      nsAutoString captionText;
844
0
      nsTextEquivUtils::AppendTextEquivFromContent(this, captionContent,
845
0
                                                   &captionText);
846
0
847
0
      if (!captionText.IsEmpty()) { // summary isn't used as a name.
848
0
        mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::summary,
849
0
                                       aDescription);
850
0
      }
851
0
    }
852
0
  }
853
0
854
#ifdef SHOW_LAYOUT_HEURISTIC
855
  if (aDescription.IsEmpty()) {
856
    bool isProbablyForLayout = IsProbablyLayoutTable();
857
    aDescription = mLayoutHeuristic;
858
  }
859
  printf("\nTABLE: %s\n", NS_ConvertUTF16toUTF8(mLayoutHeuristic).get());
860
#endif
861
}
862
863
////////////////////////////////////////////////////////////////////////////////
864
// HTMLCaptionAccessible
865
////////////////////////////////////////////////////////////////////////////////
866
867
Relation
868
HTMLCaptionAccessible::RelationByType(RelationType aType) const
869
0
{
870
0
  Relation rel = HyperTextAccessible::RelationByType(aType);
871
0
  if (aType == RelationType::LABEL_FOR)
872
0
    rel.AppendTarget(Parent());
873
0
874
0
  return rel;
875
0
}
876
877
role
878
HTMLCaptionAccessible::NativeRole() const
879
0
{
880
0
  return roles::CAPTION;
881
0
}