Line data Source code
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 "nsIDOMElement.h"
22 : #include "nsIDOMRange.h"
23 : #include "nsISelectionPrivate.h"
24 : #include "nsIDOMNodeList.h"
25 : #include "nsIDOMHTMLCollection.h"
26 : #include "nsIDocument.h"
27 : #include "nsIMutableArray.h"
28 : #include "nsIPersistentProperties2.h"
29 : #include "nsIPresShell.h"
30 : #include "nsITableCellLayout.h"
31 : #include "nsFrameSelection.h"
32 : #include "nsError.h"
33 : #include "nsArrayUtils.h"
34 : #include "nsComponentManagerUtils.h"
35 : #include "nsNameSpaceManager.h"
36 : #include "nsTableCellFrame.h"
37 : #include "nsTableWrapperFrame.h"
38 :
39 : using namespace mozilla;
40 : using namespace mozilla::dom;
41 : using namespace mozilla::a11y;
42 :
43 : ////////////////////////////////////////////////////////////////////////////////
44 : // HTMLTableCellAccessible
45 : ////////////////////////////////////////////////////////////////////////////////
46 :
47 0 : HTMLTableCellAccessible::
48 0 : HTMLTableCellAccessible(nsIContent* aContent, DocAccessible* aDoc) :
49 0 : HyperTextAccessibleWrap(aContent, aDoc)
50 : {
51 0 : mType = eHTMLTableCellType;
52 0 : mGenericTypes |= eTableCell;
53 0 : }
54 :
55 0 : NS_IMPL_ISUPPORTS_INHERITED0(HTMLTableCellAccessible, HyperTextAccessible)
56 :
57 : ////////////////////////////////////////////////////////////////////////////////
58 : // HTMLTableCellAccessible: Accessible implementation
59 :
60 : role
61 0 : HTMLTableCellAccessible::NativeRole()
62 : {
63 0 : if (mContent->IsMathMLElement(nsGkAtoms::mtd_)) {
64 0 : return roles::MATHML_CELL;
65 : }
66 0 : return roles::CELL;
67 : }
68 :
69 : uint64_t
70 0 : HTMLTableCellAccessible::NativeState()
71 : {
72 0 : uint64_t state = HyperTextAccessibleWrap::NativeState();
73 :
74 0 : nsIFrame *frame = mContent->GetPrimaryFrame();
75 0 : NS_ASSERTION(frame, "No frame for valid cell accessible!");
76 :
77 0 : if (frame && frame->IsSelected())
78 0 : state |= states::SELECTED;
79 :
80 0 : return state;
81 : }
82 :
83 : uint64_t
84 0 : HTMLTableCellAccessible::NativeInteractiveState() const
85 : {
86 0 : return HyperTextAccessibleWrap::NativeInteractiveState() | states::SELECTABLE;
87 : }
88 :
89 : already_AddRefed<nsIPersistentProperties>
90 0 : HTMLTableCellAccessible::NativeAttributes()
91 : {
92 : nsCOMPtr<nsIPersistentProperties> attributes =
93 0 : HyperTextAccessibleWrap::NativeAttributes();
94 :
95 : // table-cell-index attribute
96 0 : TableAccessible* table = Table();
97 0 : if (!table)
98 0 : return attributes.forget();
99 :
100 0 : int32_t rowIdx = -1, colIdx = -1;
101 0 : nsresult rv = GetCellIndexes(rowIdx, colIdx);
102 0 : if (NS_FAILED(rv))
103 0 : return attributes.forget();
104 :
105 0 : nsAutoString stringIdx;
106 0 : stringIdx.AppendInt(table->CellIndexAt(rowIdx, colIdx));
107 0 : nsAccUtils::SetAccAttr(attributes, nsGkAtoms::tableCellIndex, stringIdx);
108 :
109 : // abbr attribute
110 :
111 : // Pick up object attribute from abbr DOM element (a child of the cell) or
112 : // from abbr DOM attribute.
113 0 : nsAutoString abbrText;
114 0 : if (ChildCount() == 1) {
115 0 : Accessible* abbr = FirstChild();
116 0 : if (abbr->IsAbbreviation()) {
117 0 : nsIContent* firstChildNode = abbr->GetContent()->GetFirstChild();
118 0 : if (firstChildNode) {
119 : nsTextEquivUtils::
120 0 : AppendTextEquivFromTextContent(firstChildNode, &abbrText);
121 : }
122 : }
123 : }
124 0 : if (abbrText.IsEmpty())
125 0 : mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::abbr, abbrText);
126 :
127 0 : if (!abbrText.IsEmpty())
128 0 : nsAccUtils::SetAccAttr(attributes, nsGkAtoms::abbr, abbrText);
129 :
130 : // axis attribute
131 0 : nsAutoString axisText;
132 0 : mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::axis, axisText);
133 0 : if (!axisText.IsEmpty())
134 0 : nsAccUtils::SetAccAttr(attributes, nsGkAtoms::axis, axisText);
135 :
136 : #ifdef DEBUG
137 0 : nsAutoString unused;
138 0 : attributes->SetStringProperty(NS_LITERAL_CSTRING("cppclass"),
139 0 : NS_LITERAL_STRING("HTMLTableCellAccessible"),
140 0 : unused);
141 : #endif
142 :
143 0 : return attributes.forget();
144 : }
145 :
146 : GroupPos
147 0 : HTMLTableCellAccessible::GroupPosition()
148 : {
149 0 : int32_t count = 0, index = 0;
150 0 : TableAccessible* table = Table();
151 0 : if (table && nsCoreUtils::GetUIntAttr(table->AsAccessible()->GetContent(),
152 0 : nsGkAtoms::aria_colcount, &count) &&
153 0 : nsCoreUtils::GetUIntAttr(mContent, nsGkAtoms::aria_colindex, &index)) {
154 0 : return GroupPos(0, index, count);
155 : }
156 :
157 0 : return HyperTextAccessibleWrap::GroupPosition();
158 : }
159 :
160 : ////////////////////////////////////////////////////////////////////////////////
161 : // HTMLTableCellAccessible: TableCellAccessible implementation
162 :
163 : TableAccessible*
164 0 : HTMLTableCellAccessible::Table() const
165 : {
166 0 : Accessible* parent = const_cast<HTMLTableCellAccessible*>(this);
167 0 : while ((parent = parent->Parent())) {
168 0 : if (parent->IsTable())
169 0 : return parent->AsTable();
170 : }
171 :
172 0 : return nullptr;
173 : }
174 :
175 : uint32_t
176 0 : HTMLTableCellAccessible::ColIdx() const
177 : {
178 0 : nsITableCellLayout* cellLayout = GetCellLayout();
179 0 : NS_ENSURE_TRUE(cellLayout, 0);
180 :
181 0 : int32_t colIdx = 0;
182 0 : cellLayout->GetColIndex(colIdx);
183 0 : return colIdx > 0 ? static_cast<uint32_t>(colIdx) : 0;
184 : }
185 :
186 : uint32_t
187 0 : HTMLTableCellAccessible::RowIdx() const
188 : {
189 0 : nsITableCellLayout* cellLayout = GetCellLayout();
190 0 : NS_ENSURE_TRUE(cellLayout, 0);
191 :
192 0 : int32_t rowIdx = 0;
193 0 : cellLayout->GetRowIndex(rowIdx);
194 0 : return rowIdx > 0 ? static_cast<uint32_t>(rowIdx) : 0;
195 : }
196 :
197 : uint32_t
198 0 : HTMLTableCellAccessible::ColExtent() const
199 : {
200 0 : int32_t rowIdx = -1, colIdx = -1;
201 0 : GetCellIndexes(rowIdx, colIdx);
202 :
203 0 : TableAccessible* table = Table();
204 0 : NS_ASSERTION(table, "cell not in a table!");
205 0 : if (!table)
206 0 : return 0;
207 :
208 0 : return table->ColExtentAt(rowIdx, colIdx);
209 : }
210 :
211 : uint32_t
212 0 : HTMLTableCellAccessible::RowExtent() const
213 : {
214 0 : int32_t rowIdx = -1, colIdx = -1;
215 0 : GetCellIndexes(rowIdx, colIdx);
216 :
217 0 : TableAccessible* table = Table();
218 0 : NS_ASSERTION(table, "cell not in atable!");
219 0 : if (!table)
220 0 : return 0;
221 :
222 0 : return table->RowExtentAt(rowIdx, colIdx);
223 : }
224 :
225 : void
226 0 : HTMLTableCellAccessible::ColHeaderCells(nsTArray<Accessible*>* aCells)
227 : {
228 0 : IDRefsIterator itr(mDoc, mContent, nsGkAtoms::headers);
229 0 : while (Accessible* cell = itr.Next()) {
230 0 : a11y::role cellRole = cell->Role();
231 0 : if (cellRole == roles::COLUMNHEADER) {
232 0 : aCells->AppendElement(cell);
233 0 : } else if (cellRole != roles::ROWHEADER) {
234 : // If referred table cell is at the same column then treat it as a column
235 : // header.
236 0 : TableCellAccessible* tableCell = cell->AsTableCell();
237 0 : if (tableCell && tableCell->ColIdx() == ColIdx())
238 0 : aCells->AppendElement(cell);
239 : }
240 0 : }
241 :
242 0 : if (aCells->IsEmpty())
243 0 : TableCellAccessible::ColHeaderCells(aCells);
244 0 : }
245 :
246 : void
247 0 : HTMLTableCellAccessible::RowHeaderCells(nsTArray<Accessible*>* aCells)
248 : {
249 0 : IDRefsIterator itr(mDoc, mContent, nsGkAtoms::headers);
250 0 : while (Accessible* cell = itr.Next()) {
251 0 : a11y::role cellRole = cell->Role();
252 0 : if (cellRole == roles::ROWHEADER) {
253 0 : aCells->AppendElement(cell);
254 0 : } else if (cellRole != roles::COLUMNHEADER) {
255 : // If referred table cell is at the same row then treat it as a column
256 : // header.
257 0 : TableCellAccessible* tableCell = cell->AsTableCell();
258 0 : if (tableCell && tableCell->RowIdx() == RowIdx())
259 0 : aCells->AppendElement(cell);
260 : }
261 0 : }
262 :
263 0 : if (aCells->IsEmpty())
264 0 : TableCellAccessible::RowHeaderCells(aCells);
265 0 : }
266 :
267 : bool
268 0 : HTMLTableCellAccessible::Selected()
269 : {
270 0 : int32_t rowIdx = -1, colIdx = -1;
271 0 : GetCellIndexes(rowIdx, colIdx);
272 :
273 0 : TableAccessible* table = Table();
274 0 : NS_ENSURE_TRUE(table, false);
275 :
276 0 : return table->IsCellSelected(rowIdx, colIdx);
277 : }
278 :
279 : ////////////////////////////////////////////////////////////////////////////////
280 : // HTMLTableCellAccessible: protected implementation
281 :
282 : nsITableCellLayout*
283 0 : HTMLTableCellAccessible::GetCellLayout() const
284 : {
285 0 : return do_QueryFrame(mContent->GetPrimaryFrame());
286 : }
287 :
288 : nsresult
289 0 : HTMLTableCellAccessible::GetCellIndexes(int32_t& aRowIdx, int32_t& aColIdx) const
290 : {
291 0 : nsITableCellLayout *cellLayout = GetCellLayout();
292 0 : NS_ENSURE_STATE(cellLayout);
293 :
294 0 : return cellLayout->GetCellIndexes(aRowIdx, aColIdx);
295 : }
296 :
297 :
298 : ////////////////////////////////////////////////////////////////////////////////
299 : // HTMLTableHeaderCellAccessible
300 : ////////////////////////////////////////////////////////////////////////////////
301 :
302 0 : HTMLTableHeaderCellAccessible::
303 0 : HTMLTableHeaderCellAccessible(nsIContent* aContent, DocAccessible* aDoc) :
304 0 : HTMLTableCellAccessible(aContent, aDoc)
305 : {
306 0 : }
307 :
308 : ////////////////////////////////////////////////////////////////////////////////
309 : // HTMLTableHeaderCellAccessible: Accessible implementation
310 :
311 : role
312 0 : HTMLTableHeaderCellAccessible::NativeRole()
313 : {
314 : // Check value of @scope attribute.
315 : static nsIContent::AttrValuesArray scopeValues[] =
316 : { &nsGkAtoms::col, &nsGkAtoms::colgroup,
317 : &nsGkAtoms::row, &nsGkAtoms::rowgroup, nullptr };
318 : int32_t valueIdx =
319 0 : mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::scope,
320 0 : scopeValues, eCaseMatters);
321 :
322 0 : switch (valueIdx) {
323 : case 0:
324 : case 1:
325 0 : return roles::COLUMNHEADER;
326 : case 2:
327 : case 3:
328 0 : return roles::ROWHEADER;
329 : }
330 :
331 0 : TableAccessible* table = Table();
332 0 : if (!table)
333 0 : return roles::NOTHING;
334 :
335 : // If the cell next to this one is not a header cell then assume this cell is
336 : // a row header for it.
337 0 : uint32_t rowIdx = RowIdx(), colIdx = ColIdx();
338 0 : Accessible* cell = table->CellAt(rowIdx, colIdx + ColExtent());
339 0 : if (cell && !nsCoreUtils::IsHTMLTableHeader(cell->GetContent()))
340 0 : return roles::ROWHEADER;
341 :
342 : // If the cell below this one is not a header cell then assume this cell is
343 : // a column header for it.
344 0 : uint32_t rowExtent = RowExtent();
345 0 : cell = table->CellAt(rowIdx + rowExtent, colIdx);
346 0 : if (cell && !nsCoreUtils::IsHTMLTableHeader(cell->GetContent()))
347 0 : return roles::COLUMNHEADER;
348 :
349 : // Otherwise if this cell is surrounded by header cells only then make a guess
350 : // based on its cell spanning. In other words if it is row spanned then assume
351 : // it's a row header, otherwise it's a column header.
352 0 : return rowExtent > 1 ? roles::ROWHEADER : roles::COLUMNHEADER;
353 : }
354 :
355 :
356 : ////////////////////////////////////////////////////////////////////////////////
357 : // HTMLTableRowAccessible
358 : ////////////////////////////////////////////////////////////////////////////////
359 :
360 0 : NS_IMPL_ISUPPORTS_INHERITED0(HTMLTableRowAccessible, Accessible)
361 :
362 : role
363 0 : HTMLTableRowAccessible::NativeRole()
364 : {
365 0 : if (mContent->IsMathMLElement(nsGkAtoms::mtr_)) {
366 0 : return roles::MATHML_TABLE_ROW;
367 0 : } else if (mContent->IsMathMLElement(nsGkAtoms::mlabeledtr_)) {
368 0 : return roles::MATHML_LABELED_ROW;
369 : }
370 0 : return roles::ROW;
371 : }
372 :
373 : GroupPos
374 0 : HTMLTableRowAccessible::GroupPosition()
375 : {
376 0 : int32_t count = 0, index = 0;
377 0 : Accessible* table = nsAccUtils::TableFor(this);
378 0 : if (table && nsCoreUtils::GetUIntAttr(table->GetContent(),
379 0 : nsGkAtoms::aria_rowcount, &count) &&
380 0 : nsCoreUtils::GetUIntAttr(mContent, nsGkAtoms::aria_rowindex, &index)) {
381 0 : return GroupPos(0, index, count);
382 : }
383 :
384 0 : return AccessibleWrap::GroupPosition();
385 : }
386 :
387 : ////////////////////////////////////////////////////////////////////////////////
388 : // HTMLTableAccessible
389 : ////////////////////////////////////////////////////////////////////////////////
390 :
391 0 : NS_IMPL_ISUPPORTS_INHERITED0(HTMLTableAccessible, Accessible)
392 :
393 : ////////////////////////////////////////////////////////////////////////////////
394 : // HTMLTableAccessible: Accessible
395 :
396 : bool
397 0 : HTMLTableAccessible::InsertChildAt(uint32_t aIndex, Accessible* aChild)
398 : {
399 : // Move caption accessible so that it's the first child. Check for the first
400 : // caption only, because nsAccessibilityService ensures we don't create
401 : // accessibles for the other captions, since only the first is actually
402 : // visible.
403 0 : return Accessible::InsertChildAt(aChild->IsHTMLCaption() ? 0 : aIndex, aChild);
404 : }
405 :
406 : role
407 0 : HTMLTableAccessible::NativeRole()
408 : {
409 0 : if (mContent->IsMathMLElement(nsGkAtoms::mtable_)) {
410 0 : return roles::MATHML_TABLE;
411 : }
412 0 : return roles::TABLE;
413 : }
414 :
415 : uint64_t
416 0 : HTMLTableAccessible::NativeState()
417 : {
418 0 : return Accessible::NativeState() | states::READONLY;
419 : }
420 :
421 : ENameValueFlag
422 0 : HTMLTableAccessible::NativeName(nsString& aName)
423 : {
424 0 : ENameValueFlag nameFlag = Accessible::NativeName(aName);
425 0 : if (!aName.IsEmpty())
426 0 : return nameFlag;
427 :
428 : // Use table caption as a name.
429 0 : Accessible* caption = Caption();
430 0 : if (caption) {
431 0 : nsIContent* captionContent = caption->GetContent();
432 0 : if (captionContent) {
433 0 : nsTextEquivUtils::AppendTextEquivFromContent(this, captionContent, &aName);
434 0 : if (!aName.IsEmpty())
435 0 : return eNameOK;
436 : }
437 : }
438 :
439 : // If no caption then use summary as a name.
440 0 : mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::summary, aName);
441 0 : return eNameOK;
442 : }
443 :
444 : already_AddRefed<nsIPersistentProperties>
445 0 : HTMLTableAccessible::NativeAttributes()
446 : {
447 : nsCOMPtr<nsIPersistentProperties> attributes =
448 0 : AccessibleWrap::NativeAttributes();
449 :
450 0 : if (mContent->IsMathMLElement(nsGkAtoms::mtable_)) {
451 0 : GetAccService()->MarkupAttributes(mContent, attributes);
452 : }
453 :
454 0 : if (IsProbablyLayoutTable()) {
455 0 : nsAutoString unused;
456 0 : attributes->SetStringProperty(NS_LITERAL_CSTRING("layout-guess"),
457 0 : NS_LITERAL_STRING("true"), unused);
458 : }
459 :
460 0 : return attributes.forget();
461 : }
462 :
463 : ////////////////////////////////////////////////////////////////////////////////
464 : // HTMLTableAccessible: Accessible
465 :
466 : Relation
467 0 : HTMLTableAccessible::RelationByType(RelationType aType)
468 : {
469 0 : Relation rel = AccessibleWrap::RelationByType(aType);
470 0 : if (aType == RelationType::LABELLED_BY)
471 0 : rel.AppendTarget(Caption());
472 :
473 0 : return rel;
474 : }
475 :
476 : ////////////////////////////////////////////////////////////////////////////////
477 : // HTMLTableAccessible: Table
478 :
479 : Accessible*
480 0 : HTMLTableAccessible::Caption() const
481 : {
482 0 : Accessible* child = mChildren.SafeElementAt(0, nullptr);
483 0 : return child && child->Role() == roles::CAPTION ? child : nullptr;
484 : }
485 :
486 : void
487 0 : HTMLTableAccessible::Summary(nsString& aSummary)
488 : {
489 0 : dom::HTMLTableElement* table = dom::HTMLTableElement::FromContent(mContent);
490 :
491 0 : if (table)
492 0 : table->GetSummary(aSummary);
493 0 : }
494 :
495 : uint32_t
496 0 : HTMLTableAccessible::ColCount()
497 : {
498 0 : nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
499 0 : return tableFrame ? tableFrame->GetColCount() : 0;
500 : }
501 :
502 : uint32_t
503 0 : HTMLTableAccessible::RowCount()
504 : {
505 0 : nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
506 0 : return tableFrame ? tableFrame->GetRowCount() : 0;
507 : }
508 :
509 : uint32_t
510 0 : HTMLTableAccessible::SelectedCellCount()
511 : {
512 0 : nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
513 0 : if (!tableFrame)
514 0 : return 0;
515 :
516 0 : uint32_t count = 0, rowCount = RowCount(), colCount = ColCount();
517 0 : for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
518 0 : for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) {
519 0 : nsTableCellFrame* cellFrame = tableFrame->GetCellFrameAt(rowIdx, colIdx);
520 0 : if (!cellFrame || !cellFrame->IsSelected())
521 0 : continue;
522 :
523 0 : int32_t startRow = -1, startCol = -1;
524 0 : cellFrame->GetRowIndex(startRow);
525 0 : cellFrame->GetColIndex(startCol);
526 0 : if (startRow >= 0 && (uint32_t)startRow == rowIdx &&
527 0 : startCol >= 0 && (uint32_t)startCol == colIdx)
528 0 : count++;
529 : }
530 : }
531 :
532 0 : return count;
533 : }
534 :
535 : uint32_t
536 0 : HTMLTableAccessible::SelectedColCount()
537 : {
538 0 : uint32_t count = 0, colCount = ColCount();
539 :
540 0 : for (uint32_t colIdx = 0; colIdx < colCount; colIdx++)
541 0 : if (IsColSelected(colIdx))
542 0 : count++;
543 :
544 0 : return count;
545 : }
546 :
547 : uint32_t
548 0 : HTMLTableAccessible::SelectedRowCount()
549 : {
550 0 : uint32_t count = 0, rowCount = RowCount();
551 :
552 0 : for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++)
553 0 : if (IsRowSelected(rowIdx))
554 0 : count++;
555 :
556 0 : return count;
557 : }
558 :
559 : void
560 0 : HTMLTableAccessible::SelectedCells(nsTArray<Accessible*>* aCells)
561 : {
562 0 : nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
563 0 : if (!tableFrame)
564 0 : return;
565 :
566 0 : uint32_t rowCount = RowCount(), colCount = ColCount();
567 0 : for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
568 0 : for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) {
569 0 : nsTableCellFrame* cellFrame = tableFrame->GetCellFrameAt(rowIdx, colIdx);
570 0 : if (!cellFrame || !cellFrame->IsSelected())
571 0 : continue;
572 :
573 0 : int32_t startCol = -1, startRow = -1;
574 0 : cellFrame->GetRowIndex(startRow);
575 0 : cellFrame->GetColIndex(startCol);
576 0 : if ((startRow >= 0 && (uint32_t)startRow != rowIdx) ||
577 0 : (startCol >= 0 && (uint32_t)startCol != colIdx))
578 0 : continue;
579 :
580 0 : Accessible* cell = mDoc->GetAccessible(cellFrame->GetContent());
581 0 : aCells->AppendElement(cell);
582 : }
583 : }
584 : }
585 :
586 : void
587 0 : HTMLTableAccessible::SelectedCellIndices(nsTArray<uint32_t>* aCells)
588 : {
589 0 : nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
590 0 : if (!tableFrame)
591 0 : return;
592 :
593 0 : uint32_t rowCount = RowCount(), colCount = ColCount();
594 0 : for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
595 0 : for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) {
596 0 : nsTableCellFrame* cellFrame = tableFrame->GetCellFrameAt(rowIdx, colIdx);
597 0 : if (!cellFrame || !cellFrame->IsSelected())
598 0 : continue;
599 :
600 0 : int32_t startRow = -1, startCol = -1;
601 0 : cellFrame->GetColIndex(startCol);
602 0 : cellFrame->GetRowIndex(startRow);
603 0 : if (startRow >= 0 && (uint32_t)startRow == rowIdx &&
604 0 : startCol >= 0 && (uint32_t)startCol == colIdx)
605 0 : aCells->AppendElement(CellIndexAt(rowIdx, colIdx));
606 : }
607 : }
608 : }
609 :
610 : void
611 0 : HTMLTableAccessible::SelectedColIndices(nsTArray<uint32_t>* aCols)
612 : {
613 0 : uint32_t colCount = ColCount();
614 0 : for (uint32_t colIdx = 0; colIdx < colCount; colIdx++)
615 0 : if (IsColSelected(colIdx))
616 0 : aCols->AppendElement(colIdx);
617 0 : }
618 :
619 : void
620 0 : HTMLTableAccessible::SelectedRowIndices(nsTArray<uint32_t>* aRows)
621 : {
622 0 : uint32_t rowCount = RowCount();
623 0 : for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++)
624 0 : if (IsRowSelected(rowIdx))
625 0 : aRows->AppendElement(rowIdx);
626 0 : }
627 :
628 : Accessible*
629 0 : HTMLTableAccessible::CellAt(uint32_t aRowIdx, uint32_t aColIdx)
630 : {
631 0 : nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
632 0 : if (!tableFrame)
633 0 : return nullptr;
634 :
635 0 : nsIContent* cellContent = tableFrame->GetCellAt(aRowIdx, aColIdx);
636 0 : Accessible* cell = mDoc->GetAccessible(cellContent);
637 :
638 : // XXX bug 576838: crazy tables (like table6 in tables/test_table2.html) may
639 : // return itself as a cell what makes Orca hang.
640 0 : return cell == this ? nullptr : cell;
641 : }
642 :
643 : int32_t
644 0 : HTMLTableAccessible::CellIndexAt(uint32_t aRowIdx, uint32_t aColIdx)
645 : {
646 0 : nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
647 0 : if (!tableFrame)
648 0 : return -1;
649 :
650 0 : return tableFrame->GetIndexByRowAndColumn(aRowIdx, aColIdx);
651 : }
652 :
653 : int32_t
654 0 : HTMLTableAccessible::ColIndexAt(uint32_t aCellIdx)
655 : {
656 0 : nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
657 0 : if (!tableFrame)
658 0 : return -1;
659 :
660 0 : int32_t rowIdx = -1, colIdx = -1;
661 0 : tableFrame->GetRowAndColumnByIndex(aCellIdx, &rowIdx, &colIdx);
662 0 : return colIdx;
663 : }
664 :
665 : int32_t
666 0 : HTMLTableAccessible::RowIndexAt(uint32_t aCellIdx)
667 : {
668 0 : nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
669 0 : if (!tableFrame)
670 0 : return -1;
671 :
672 0 : int32_t rowIdx = -1, colIdx = -1;
673 0 : tableFrame->GetRowAndColumnByIndex(aCellIdx, &rowIdx, &colIdx);
674 0 : return rowIdx;
675 : }
676 :
677 : void
678 0 : HTMLTableAccessible::RowAndColIndicesAt(uint32_t aCellIdx, int32_t* aRowIdx,
679 : int32_t* aColIdx)
680 : {
681 0 : nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
682 0 : if (tableFrame)
683 0 : tableFrame->GetRowAndColumnByIndex(aCellIdx, aRowIdx, aColIdx);
684 0 : }
685 :
686 : uint32_t
687 0 : HTMLTableAccessible::ColExtentAt(uint32_t aRowIdx, uint32_t aColIdx)
688 : {
689 0 : nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
690 0 : if (!tableFrame)
691 0 : return 0;
692 :
693 0 : return tableFrame->GetEffectiveColSpanAt(aRowIdx, aColIdx);
694 : }
695 :
696 : uint32_t
697 0 : HTMLTableAccessible::RowExtentAt(uint32_t aRowIdx, uint32_t aColIdx)
698 : {
699 0 : nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
700 0 : if (!tableFrame)
701 0 : return 0;
702 :
703 0 : return tableFrame->GetEffectiveRowSpanAt(aRowIdx, aColIdx);
704 : }
705 :
706 : bool
707 0 : HTMLTableAccessible::IsColSelected(uint32_t aColIdx)
708 : {
709 0 : bool isSelected = false;
710 :
711 0 : uint32_t rowCount = RowCount();
712 0 : for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
713 0 : isSelected = IsCellSelected(rowIdx, aColIdx);
714 0 : if (!isSelected)
715 0 : return false;
716 : }
717 :
718 0 : return isSelected;
719 : }
720 :
721 : bool
722 0 : HTMLTableAccessible::IsRowSelected(uint32_t aRowIdx)
723 : {
724 0 : bool isSelected = false;
725 :
726 0 : uint32_t colCount = ColCount();
727 0 : for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) {
728 0 : isSelected = IsCellSelected(aRowIdx, colIdx);
729 0 : if (!isSelected)
730 0 : return false;
731 : }
732 :
733 0 : return isSelected;
734 : }
735 :
736 : bool
737 0 : HTMLTableAccessible::IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx)
738 : {
739 0 : nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
740 0 : if (!tableFrame)
741 0 : return false;
742 :
743 0 : nsTableCellFrame* cellFrame = tableFrame->GetCellFrameAt(aRowIdx, aColIdx);
744 0 : return cellFrame ? cellFrame->IsSelected() : false;
745 : }
746 :
747 : void
748 0 : HTMLTableAccessible::SelectRow(uint32_t aRowIdx)
749 : {
750 : DebugOnly<nsresult> rv =
751 0 : RemoveRowsOrColumnsFromSelection(aRowIdx,
752 : nsISelectionPrivate::TABLESELECTION_ROW,
753 0 : true);
754 0 : NS_ASSERTION(NS_SUCCEEDED(rv),
755 : "RemoveRowsOrColumnsFromSelection() Shouldn't fail!");
756 :
757 0 : AddRowOrColumnToSelection(aRowIdx, nsISelectionPrivate::TABLESELECTION_ROW);
758 0 : }
759 :
760 : void
761 0 : HTMLTableAccessible::SelectCol(uint32_t aColIdx)
762 : {
763 : DebugOnly<nsresult> rv =
764 0 : RemoveRowsOrColumnsFromSelection(aColIdx,
765 : nsISelectionPrivate::TABLESELECTION_COLUMN,
766 0 : true);
767 0 : NS_ASSERTION(NS_SUCCEEDED(rv),
768 : "RemoveRowsOrColumnsFromSelection() Shouldn't fail!");
769 :
770 0 : AddRowOrColumnToSelection(aColIdx, nsISelectionPrivate::TABLESELECTION_COLUMN);
771 0 : }
772 :
773 : void
774 0 : HTMLTableAccessible::UnselectRow(uint32_t aRowIdx)
775 : {
776 0 : RemoveRowsOrColumnsFromSelection(aRowIdx,
777 : nsISelectionPrivate::TABLESELECTION_ROW,
778 0 : false);
779 0 : }
780 :
781 : void
782 0 : HTMLTableAccessible::UnselectCol(uint32_t aColIdx)
783 : {
784 0 : RemoveRowsOrColumnsFromSelection(aColIdx,
785 : nsISelectionPrivate::TABLESELECTION_COLUMN,
786 0 : false);
787 0 : }
788 :
789 : nsresult
790 0 : HTMLTableAccessible::AddRowOrColumnToSelection(int32_t aIndex, uint32_t aTarget)
791 : {
792 0 : bool doSelectRow = (aTarget == nsISelectionPrivate::TABLESELECTION_ROW);
793 :
794 0 : nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
795 0 : if (!tableFrame)
796 0 : return NS_OK;
797 :
798 0 : uint32_t count = 0;
799 0 : if (doSelectRow)
800 0 : count = ColCount();
801 : else
802 0 : count = RowCount();
803 :
804 0 : nsIPresShell* presShell(mDoc->PresShell());
805 : RefPtr<nsFrameSelection> tableSelection =
806 0 : const_cast<nsFrameSelection*>(presShell->ConstFrameSelection());
807 :
808 0 : for (uint32_t idx = 0; idx < count; idx++) {
809 0 : int32_t rowIdx = doSelectRow ? aIndex : idx;
810 0 : int32_t colIdx = doSelectRow ? idx : aIndex;
811 0 : nsTableCellFrame* cellFrame = tableFrame->GetCellFrameAt(rowIdx, colIdx);
812 0 : if (cellFrame && !cellFrame->IsSelected()) {
813 0 : nsresult rv = tableSelection->SelectCellElement(cellFrame->GetContent());
814 0 : NS_ENSURE_SUCCESS(rv, rv);
815 : }
816 : }
817 :
818 0 : return NS_OK;
819 : }
820 :
821 : nsresult
822 0 : HTMLTableAccessible::RemoveRowsOrColumnsFromSelection(int32_t aIndex,
823 : uint32_t aTarget,
824 : bool aIsOuter)
825 : {
826 0 : nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
827 0 : if (!tableFrame)
828 0 : return NS_OK;
829 :
830 0 : nsIPresShell* presShell(mDoc->PresShell());
831 : RefPtr<nsFrameSelection> tableSelection =
832 0 : const_cast<nsFrameSelection*>(presShell->ConstFrameSelection());
833 :
834 0 : bool doUnselectRow = (aTarget == nsISelectionPrivate::TABLESELECTION_ROW);
835 0 : uint32_t count = doUnselectRow ? ColCount() : RowCount();
836 :
837 0 : int32_t startRowIdx = doUnselectRow ? aIndex : 0;
838 0 : int32_t endRowIdx = doUnselectRow ? aIndex : count - 1;
839 0 : int32_t startColIdx = doUnselectRow ? 0 : aIndex;
840 0 : int32_t endColIdx = doUnselectRow ? count - 1 : aIndex;
841 :
842 0 : if (aIsOuter)
843 0 : return tableSelection->RestrictCellsToSelection(mContent,
844 : startRowIdx, startColIdx,
845 0 : endRowIdx, endColIdx);
846 :
847 0 : return tableSelection->RemoveCellsFromSelection(mContent,
848 : startRowIdx, startColIdx,
849 0 : endRowIdx, endColIdx);
850 : }
851 :
852 : void
853 0 : HTMLTableAccessible::Description(nsString& aDescription)
854 : {
855 : // Helpful for debugging layout vs. data tables
856 0 : aDescription.Truncate();
857 0 : Accessible::Description(aDescription);
858 0 : if (!aDescription.IsEmpty())
859 0 : return;
860 :
861 : // Use summary as description if it weren't used as a name.
862 : // XXX: get rid code duplication with NameInternal().
863 0 : Accessible* caption = Caption();
864 0 : if (caption) {
865 0 : nsIContent* captionContent = caption->GetContent();
866 0 : if (captionContent) {
867 0 : nsAutoString captionText;
868 0 : nsTextEquivUtils::AppendTextEquivFromContent(this, captionContent,
869 0 : &captionText);
870 :
871 0 : if (!captionText.IsEmpty()) { // summary isn't used as a name.
872 0 : mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::summary,
873 0 : aDescription);
874 : }
875 : }
876 : }
877 :
878 : #ifdef SHOW_LAYOUT_HEURISTIC
879 : if (aDescription.IsEmpty()) {
880 : bool isProbablyForLayout = IsProbablyLayoutTable();
881 : aDescription = mLayoutHeuristic;
882 : }
883 : printf("\nTABLE: %s\n", NS_ConvertUTF16toUTF8(mLayoutHeuristic).get());
884 : #endif
885 : }
886 :
887 : bool
888 0 : HTMLTableAccessible::HasDescendant(const nsAString& aTagName, bool aAllowEmpty)
889 : {
890 : nsCOMPtr<nsIHTMLCollection> elements =
891 0 : mContent->AsElement()->GetElementsByTagName(aTagName);
892 :
893 0 : Element* foundItem = elements->Item(0);
894 0 : if (!foundItem)
895 0 : return false;
896 :
897 0 : if (aAllowEmpty)
898 0 : return true;
899 :
900 : // Make sure that the item we found has contents and either has multiple
901 : // children or the found item is not a whitespace-only text node.
902 0 : if (foundItem->GetChildCount() > 1)
903 0 : return true; // Treat multiple child nodes as non-empty
904 :
905 0 : nsIContent *innerItemContent = foundItem->GetFirstChild();
906 0 : if (innerItemContent && !innerItemContent->TextIsOnlyWhitespace())
907 0 : return true;
908 :
909 : // If we found more than one node then return true not depending on
910 : // aAllowEmpty flag.
911 : // XXX it might be dummy but bug 501375 where we changed this addresses
912 : // performance problems only. Note, currently 'aAllowEmpty' flag is used for
913 : // caption element only. On another hand we create accessible object for
914 : // the first entry of caption element (see
915 : // HTMLTableAccessible::InsertChildAt).
916 0 : return !!elements->Item(1);
917 : }
918 :
919 : bool
920 0 : HTMLTableAccessible::IsProbablyLayoutTable()
921 : {
922 : // Implement a heuristic to determine if table is most likely used for layout
923 : // XXX do we want to look for rowspan or colspan, especialy that span all but a couple cells
924 : // at the beginning or end of a row/col, and especially when they occur at the edge of a table?
925 : // XXX expose this info via object attributes to AT-SPI
926 :
927 : // XXX For now debugging descriptions are always on via SHOW_LAYOUT_HEURISTIC
928 : // This will allow release trunk builds to be used by testers to refine the algorithm
929 : // Change to |#define SHOW_LAYOUT_HEURISTIC DEBUG| before final release
930 : #ifdef SHOW_LAYOUT_HEURISTIC
931 : #define RETURN_LAYOUT_ANSWER(isLayout, heuristic) \
932 : { \
933 : mLayoutHeuristic = isLayout ? \
934 : NS_LITERAL_STRING("layout table: " heuristic) : \
935 : NS_LITERAL_STRING("data table: " heuristic); \
936 : return isLayout; \
937 : }
938 : #else
939 : #define RETURN_LAYOUT_ANSWER(isLayout, heuristic) { return isLayout; }
940 : #endif
941 :
942 0 : DocAccessible* docAccessible = Document();
943 0 : if (docAccessible) {
944 0 : uint64_t docState = docAccessible->State();
945 0 : if (docState & states::EDITABLE) { // Need to see all elements while document is being edited
946 0 : RETURN_LAYOUT_ANSWER(false, "In editable document");
947 : }
948 : }
949 :
950 : // Check to see if an ARIA role overrides the role from native markup,
951 : // but for which we still expose table semantics (treegrid, for example).
952 0 : if (Role() != roles::TABLE)
953 0 : RETURN_LAYOUT_ANSWER(false, "Has role attribute");
954 :
955 0 : if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::role)) {
956 : // Role attribute is present, but overridden roles have already been dealt with.
957 : // Only landmarks and other roles that don't override the role from native
958 : // markup are left to deal with here.
959 0 : RETURN_LAYOUT_ANSWER(false, "Has role attribute, weak role, and role is table");
960 : }
961 :
962 0 : NS_ASSERTION(mContent->IsHTMLElement(nsGkAtoms::table),
963 : "table should not be built by CSS display:table style");
964 :
965 : // Check if datatable attribute has "0" value.
966 0 : if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::datatable,
967 0 : NS_LITERAL_STRING("0"), eCaseMatters)) {
968 0 : RETURN_LAYOUT_ANSWER(true, "Has datatable = 0 attribute, it's for layout");
969 : }
970 :
971 : // Check for legitimate data table attributes.
972 0 : nsAutoString summary;
973 0 : if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::summary, summary) &&
974 0 : !summary.IsEmpty())
975 0 : RETURN_LAYOUT_ANSWER(false, "Has summary -- legitimate table structures");
976 :
977 : // Check for legitimate data table elements.
978 0 : Accessible* caption = FirstChild();
979 0 : if (caption && caption->Role() == roles::CAPTION && caption->HasChildren())
980 0 : RETURN_LAYOUT_ANSWER(false, "Not empty caption -- legitimate table structures");
981 :
982 0 : for (nsIContent* childElm = mContent->GetFirstChild(); childElm;
983 0 : childElm = childElm->GetNextSibling()) {
984 0 : if (!childElm->IsHTMLElement())
985 0 : continue;
986 :
987 0 : if (childElm->IsAnyOfHTMLElements(nsGkAtoms::col,
988 : nsGkAtoms::colgroup,
989 : nsGkAtoms::tfoot,
990 : nsGkAtoms::thead)) {
991 0 : RETURN_LAYOUT_ANSWER(false,
992 : "Has col, colgroup, tfoot or thead -- legitimate table structures");
993 : }
994 :
995 0 : if (childElm->IsHTMLElement(nsGkAtoms::tbody)) {
996 0 : for (nsIContent* rowElm = childElm->GetFirstChild(); rowElm;
997 0 : rowElm = rowElm->GetNextSibling()) {
998 0 : if (rowElm->IsHTMLElement(nsGkAtoms::tr)) {
999 0 : for (nsIContent* cellElm = rowElm->GetFirstChild(); cellElm;
1000 0 : cellElm = cellElm->GetNextSibling()) {
1001 0 : if (cellElm->IsHTMLElement()) {
1002 :
1003 0 : if (cellElm->NodeInfo()->Equals(nsGkAtoms::th)) {
1004 0 : RETURN_LAYOUT_ANSWER(false,
1005 : "Has th -- legitimate table structures");
1006 : }
1007 :
1008 0 : if (cellElm->HasAttr(kNameSpaceID_None, nsGkAtoms::headers) ||
1009 0 : cellElm->HasAttr(kNameSpaceID_None, nsGkAtoms::scope) ||
1010 0 : cellElm->HasAttr(kNameSpaceID_None, nsGkAtoms::abbr)) {
1011 0 : RETURN_LAYOUT_ANSWER(false,
1012 : "Has headers, scope, or abbr attribute -- legitimate table structures");
1013 : }
1014 :
1015 0 : Accessible* cell = mDoc->GetAccessible(cellElm);
1016 0 : if (cell && cell->ChildCount() == 1 &&
1017 0 : cell->FirstChild()->IsAbbreviation()) {
1018 0 : RETURN_LAYOUT_ANSWER(false,
1019 : "has abbr -- legitimate table structures");
1020 : }
1021 : }
1022 : }
1023 : }
1024 : }
1025 : }
1026 : }
1027 :
1028 0 : if (HasDescendant(NS_LITERAL_STRING("table"))) {
1029 0 : RETURN_LAYOUT_ANSWER(true, "Has a nested table within it");
1030 : }
1031 :
1032 : // If only 1 column or only 1 row, it's for layout
1033 0 : uint32_t colCount = ColCount();
1034 0 : if (colCount <=1) {
1035 0 : RETURN_LAYOUT_ANSWER(true, "Has only 1 column");
1036 : }
1037 0 : uint32_t rowCount = RowCount();
1038 0 : if (rowCount <=1) {
1039 0 : RETURN_LAYOUT_ANSWER(true, "Has only 1 row");
1040 : }
1041 :
1042 : // Check for many columns
1043 0 : if (colCount >= 5) {
1044 0 : RETURN_LAYOUT_ANSWER(false, ">=5 columns");
1045 : }
1046 :
1047 : // Now we know there are 2-4 columns and 2 or more rows
1048 : // Check to see if there are visible borders on the cells
1049 : // XXX currently, we just check the first cell -- do we really need to do more?
1050 0 : nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
1051 0 : if (!tableFrame)
1052 0 : RETURN_LAYOUT_ANSWER(false, "table with no frame!");
1053 :
1054 0 : nsIFrame* cellFrame = tableFrame->GetCellFrameAt(0, 0);
1055 0 : if (!cellFrame)
1056 0 : RETURN_LAYOUT_ANSWER(false, "table's first cell has no frame!");
1057 :
1058 0 : nsMargin border;
1059 0 : cellFrame->GetXULBorder(border);
1060 0 : if (border.top && border.bottom && border.left && border.right) {
1061 0 : RETURN_LAYOUT_ANSWER(false, "Has nonzero border-width on table cell");
1062 : }
1063 :
1064 : /**
1065 : * Rules for non-bordered tables with 2-4 columns and 2+ rows from here on forward
1066 : */
1067 :
1068 : // Check for styled background color across rows (alternating background
1069 : // color is a common feature for data tables).
1070 0 : uint32_t childCount = ChildCount();
1071 0 : nscolor rowColor = 0;
1072 : nscolor prevRowColor;
1073 0 : for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) {
1074 0 : Accessible* child = GetChildAt(childIdx);
1075 0 : if (child->Role() == roles::ROW) {
1076 0 : prevRowColor = rowColor;
1077 0 : nsIFrame* rowFrame = child->GetFrame();
1078 0 : rowColor = rowFrame->StyleBackground()->BackgroundColor(rowFrame);
1079 :
1080 0 : if (childIdx > 0 && prevRowColor != rowColor)
1081 0 : RETURN_LAYOUT_ANSWER(false, "2 styles of row background color, non-bordered");
1082 : }
1083 : }
1084 :
1085 : // Check for many rows
1086 0 : const uint32_t kMaxLayoutRows = 20;
1087 0 : if (rowCount > kMaxLayoutRows) { // A ton of rows, this is probably for data
1088 0 : RETURN_LAYOUT_ANSWER(false, ">= kMaxLayoutRows (20) and non-bordered");
1089 : }
1090 :
1091 : // Check for very wide table.
1092 0 : nsIFrame* documentFrame = Document()->GetFrame();
1093 0 : nsSize documentSize = documentFrame->GetSize();
1094 0 : if (documentSize.width > 0) {
1095 0 : nsSize tableSize = GetFrame()->GetSize();
1096 0 : int32_t percentageOfDocWidth = (100 * tableSize.width) / documentSize.width;
1097 0 : if (percentageOfDocWidth > 95) {
1098 : // 3-4 columns, no borders, not a lot of rows, and 95% of the doc's width
1099 : // Probably for layout
1100 0 : RETURN_LAYOUT_ANSWER(true,
1101 : "<= 4 columns, table width is 95% of document width");
1102 : }
1103 : }
1104 :
1105 : // Two column rules
1106 0 : if (rowCount * colCount <= 10) {
1107 0 : RETURN_LAYOUT_ANSWER(true, "2-4 columns, 10 cells or less, non-bordered");
1108 : }
1109 :
1110 0 : if (HasDescendant(NS_LITERAL_STRING("embed")) ||
1111 0 : HasDescendant(NS_LITERAL_STRING("object")) ||
1112 0 : HasDescendant(NS_LITERAL_STRING("applet")) ||
1113 0 : HasDescendant(NS_LITERAL_STRING("iframe"))) {
1114 0 : RETURN_LAYOUT_ANSWER(true, "Has no borders, and has iframe, object, applet or iframe, typical of advertisements");
1115 : }
1116 :
1117 0 : RETURN_LAYOUT_ANSWER(false, "no layout factor strong enough, so will guess data");
1118 : }
1119 :
1120 :
1121 : ////////////////////////////////////////////////////////////////////////////////
1122 : // HTMLCaptionAccessible
1123 : ////////////////////////////////////////////////////////////////////////////////
1124 :
1125 : Relation
1126 0 : HTMLCaptionAccessible::RelationByType(RelationType aType)
1127 : {
1128 0 : Relation rel = HyperTextAccessible::RelationByType(aType);
1129 0 : if (aType == RelationType::LABEL_FOR)
1130 0 : rel.AppendTarget(Parent());
1131 :
1132 0 : return rel;
1133 : }
1134 :
1135 : role
1136 0 : HTMLCaptionAccessible::NativeRole()
1137 : {
1138 0 : return roles::CAPTION;
1139 : }
|