Use is<>() / downcast<>() for Accessibility objects
[WebKit-https.git] / Source / WebCore / accessibility / AccessibilityTableColumn.cpp
1 /*
2  * Copyright (C) 2008 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "AccessibilityTableColumn.h"
31
32 #include "AXObjectCache.h"
33 #include "AccessibilityTableCell.h"
34 #include "HTMLElement.h"
35 #include "HTMLNames.h"
36 #include "RenderTable.h"
37 #include "RenderTableCell.h"
38 #include "RenderTableSection.h"
39
40 namespace WebCore {
41     
42 using namespace HTMLNames;
43
44 AccessibilityTableColumn::AccessibilityTableColumn()
45 {
46 }
47
48 AccessibilityTableColumn::~AccessibilityTableColumn()
49 {
50 }    
51
52 PassRefPtr<AccessibilityTableColumn> AccessibilityTableColumn::create()
53 {
54     return adoptRef(new AccessibilityTableColumn());
55 }
56
57 void AccessibilityTableColumn::setParent(AccessibilityObject* parent)
58 {
59     AccessibilityMockObject::setParent(parent);
60     
61     clearChildren();
62 }
63     
64 LayoutRect AccessibilityTableColumn::elementRect() const
65 {
66     // this will be filled in when addChildren is called
67     return m_columnRect;
68 }
69
70 AccessibilityObject* AccessibilityTableColumn::headerObject()
71 {
72     if (!m_parent)
73         return nullptr;
74     
75     RenderObject* renderer = m_parent->renderer();
76     if (!renderer)
77         return nullptr;
78     
79     if (!m_parent->isAccessibilityTable())
80         return nullptr;
81     
82     auto& parentTable = downcast<AccessibilityTable>(*m_parent);
83     if (parentTable.isAriaTable()) {
84         for (const auto& cell : children()) {
85             if (cell->ariaRoleAttribute() == ColumnHeaderRole)
86                 return cell.get();
87         }
88         
89         return nullptr;
90     }
91
92     if (!is<RenderTable>(*renderer))
93         return nullptr;
94     
95     RenderTable& table = downcast<RenderTable>(*renderer);
96
97     // try the <thead> section first. this doesn't require th tags
98     if (auto* headerObject = headerObjectForSection(table.header(), false))
99         return headerObject;
100     
101     RenderTableSection* bodySection = table.firstBody();
102     while (bodySection && bodySection->isAnonymous())
103         bodySection = table.sectionBelow(bodySection, SkipEmptySections);
104     
105     // now try for <th> tags in the first body. If the first body is 
106     return headerObjectForSection(bodySection, true);
107 }
108
109 AccessibilityObject* AccessibilityTableColumn::headerObjectForSection(RenderTableSection* section, bool thTagRequired)
110 {
111     if (!section)
112         return nullptr;
113     
114     unsigned numCols = section->numColumns();
115     if (m_columnIndex >= numCols)
116         return nullptr;
117     
118     if (!section->numRows())
119         return nullptr;
120     
121     RenderTableCell* cell = nullptr;
122     // also account for cells that have a span
123     for (int testCol = m_columnIndex; testCol >= 0; --testCol) {
124         
125         // Run down the rows in case initial rows are invalid (like when a <caption> is used).
126         unsigned rowCount = section->numRows();
127         for (unsigned testRow = 0; testRow < rowCount; testRow++) {
128             RenderTableCell* testCell = section->primaryCellAt(testRow, testCol);
129             // No cell at this index, keep checking more rows and columns.
130             if (!testCell)
131                 continue;
132             
133             // If we've reached a cell that doesn't even overlap our column it can't be the header.
134             if ((testCell->col() + (testCell->colSpan()-1)) < m_columnIndex)
135                 break;
136             
137             // If this does not have an element (like a <caption>) then check the next row
138             if (!testCell->element())
139                 continue;
140             
141             // If th is required, but we found an element that doesn't have a th tag, we can stop looking.
142             if (thTagRequired && !testCell->element()->hasTagName(thTag))
143                 break;
144             
145             cell = testCell;
146             break;
147         }
148     }
149     
150     if (!cell)
151         return nullptr;
152
153     return axObjectCache()->getOrCreate(cell);
154 }
155     
156 bool AccessibilityTableColumn::computeAccessibilityIsIgnored() const
157 {
158     if (!m_parent)
159         return true;
160     
161 #if PLATFORM(IOS) || PLATFORM(GTK) || PLATFORM(EFL)
162     return true;
163 #endif
164     
165     return m_parent->accessibilityIsIgnored();
166 }
167     
168 void AccessibilityTableColumn::addChildren()
169 {
170     ASSERT(!m_haveChildren); 
171     
172     m_haveChildren = true;
173     if (!m_parent || !m_parent->isAccessibilityTable())
174         return;
175     
176     AccessibilityTable& parentTable = downcast<AccessibilityTable>(*m_parent);
177     int numRows = parentTable.rowCount();
178     
179     for (int i = 0; i < numRows; ++i) {
180         AccessibilityTableCell* cell = parentTable.cellForColumnAndRow(m_columnIndex, i);
181         if (!cell)
182             continue;
183         
184         // make sure the last one isn't the same as this one (rowspan cells)
185         if (m_children.size() > 0 && m_children.last() == cell)
186             continue;
187             
188         m_children.append(cell);
189         m_columnRect.unite(cell->elementRect());
190     }
191 }
192     
193 } // namespace WebCore