LCOV - code coverage report
Current view: top level - accessible/html - HTMLTableAccessible.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 542 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 67 0.0 %
Legend: Lines: hit not hit

          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             : }

Generated by: LCOV version 1.13