Use "= default" to denote default constructor or destructor
[WebKit-https.git] / Source / WebCore / accessibility / AccessibilityARIAGridCell.cpp
1 /*
2  * Copyright (C) 2009 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 "AccessibilityARIAGridCell.h"
31
32 #include "AccessibilityObject.h"
33 #include "AccessibilityTable.h"
34 #include "AccessibilityTableRow.h"
35 #include "HTMLNames.h"
36
37 namespace WebCore {
38     
39 using namespace HTMLNames;
40
41 AccessibilityARIAGridCell::AccessibilityARIAGridCell(RenderObject* renderer)
42     : AccessibilityTableCell(renderer)
43 {
44 }
45
46 AccessibilityARIAGridCell::~AccessibilityARIAGridCell() = default;
47
48 Ref<AccessibilityARIAGridCell> AccessibilityARIAGridCell::create(RenderObject* renderer)
49 {
50     return adoptRef(*new AccessibilityARIAGridCell(renderer));
51 }
52
53 AccessibilityTable* AccessibilityARIAGridCell::parentTable() const
54 {
55     // ARIA gridcells may have multiple levels of unignored ancestors that are not the parent table,
56     // including rows and interactive rowgroups. In addition, poorly-formed grids may contain elements
57     // which pass the tests for inclusion.
58     for (AccessibilityObject* parent = parentObjectUnignored(); parent; parent = parent->parentObjectUnignored()) {
59         if (is<AccessibilityTable>(*parent) && downcast<AccessibilityTable>(*parent).isExposableThroughAccessibility())
60             return downcast<AccessibilityTable>(parent);
61     }
62
63     return nullptr;
64 }
65     
66 void AccessibilityARIAGridCell::rowIndexRange(std::pair<unsigned, unsigned>& rowRange) const
67 {
68     AccessibilityObject* parent = parentObjectUnignored();
69     if (!parent)
70         return;
71
72     if (is<AccessibilityTableRow>(*parent)) {
73         // We already got a table row, use its API.
74         rowRange.first = downcast<AccessibilityTableRow>(*parent).rowIndex();
75     } else if (is<AccessibilityTable>(*parent) && downcast<AccessibilityTable>(*parent).isExposableThroughAccessibility()) {
76         // We reached the parent table, so we need to inspect its
77         // children to determine the row index for the cell in it.
78         unsigned columnCount = downcast<AccessibilityTable>(*parent).columnCount();
79         if (!columnCount)
80             return;
81
82         const auto& siblings = parent->children();
83         unsigned childrenSize = siblings.size();
84         for (unsigned k = 0; k < childrenSize; ++k) {
85             if (siblings[k].get() == this) {
86                 rowRange.first = k / columnCount;
87                 break;
88             }
89         }
90     }
91
92     // ARIA 1.1, aria-rowspan attribute is intended for cells and gridcells which are not contained in a native table.
93     // So we should check for that attribute here.
94     rowRange.second = ariaRowSpanWithRowIndex(rowRange.first);
95 }
96
97 unsigned AccessibilityARIAGridCell::ariaRowSpanWithRowIndex(unsigned rowIndex) const
98 {
99     int rowSpan = AccessibilityTableCell::ariaRowSpan();
100     if (rowSpan == -1) {
101         std::pair<unsigned, unsigned> range;
102         AccessibilityTableCell::rowIndexRange(range);
103         return std::max(static_cast<int>(range.second), 1);
104     }
105
106     AccessibilityObject* parent = parentObjectUnignored();
107     if (!parent)
108         return 1;
109     
110     // Setting the value to 0 indicates that the cell or gridcell is to span all the remaining rows in the row group.
111     if (!rowSpan) {
112         // rowSpan defaults to 1.
113         rowSpan = 1;
114         if (AccessibilityObject* parentRowGroup = this->parentRowGroup()) {
115             // If the row group is the parent table, we use total row count to calculate the span.
116             if (is<AccessibilityTable>(*parentRowGroup))
117                 rowSpan = downcast<AccessibilityTable>(*parentRowGroup).rowCount() - rowIndex;
118             // Otherwise, we have to get the index for the current row within the parent row group.
119             else if (is<AccessibilityTableRow>(*parent)) {
120                 const auto& siblings = parentRowGroup->children();
121                 unsigned rowCount = siblings.size();
122                 for (unsigned k = 0; k < rowCount; ++k) {
123                     if (siblings[k].get() == parent) {
124                         rowSpan = rowCount - k;
125                         break;
126                     }
127                 }
128             }
129         }
130     }
131
132     return rowSpan;
133 }
134
135 void AccessibilityARIAGridCell::columnIndexRange(std::pair<unsigned, unsigned>& columnRange) const
136 {
137     AccessibilityObject* parent = parentObjectUnignored();
138     if (!parent)
139         return;
140
141     if (!is<AccessibilityTableRow>(*parent)
142         && !(is<AccessibilityTable>(*parent) && downcast<AccessibilityTable>(*parent).isExposableThroughAccessibility()))
143         return;
144
145     const AccessibilityChildrenVector& siblings = parent->children();
146     unsigned childrenSize = siblings.size();
147     unsigned indexWithSpan = 0;
148     for (unsigned k = 0; k < childrenSize; ++k) {
149         auto child = siblings[k].get();
150         if (child == this) {
151             columnRange.first = indexWithSpan;
152             break;
153         }
154         indexWithSpan += is<AccessibilityTableCell>(*child) ? std::max(downcast<AccessibilityTableCell>(*child).ariaColumnSpan(), 1) : 1;
155     }
156     
157     // ARIA 1.1, aria-colspan attribute is intended for cells and gridcells which are not contained in a native table.
158     // So we should check for that attribute here.
159     int columnSpan = AccessibilityTableCell::ariaColumnSpan();
160     if (columnSpan == -1) {
161         std::pair<unsigned, unsigned> range;
162         AccessibilityTableCell::columnIndexRange(range);
163         columnSpan = range.second;
164     }
165
166     columnRange.second = std::max(columnSpan, 1);
167 }
168
169 AccessibilityObject* AccessibilityARIAGridCell::parentRowGroup() const
170 {
171     for (AccessibilityObject* parent = parentObject(); parent; parent = parent->parentObject()) {
172         if (parent->hasTagName(theadTag) || parent->hasTagName(tbodyTag) || parent->hasTagName(tfootTag) || parent->roleValue() == RowGroupRole)
173             return parent;
174     }
175     
176     // If there's no row group found, we use the parent table as the row group.
177     return parentTable();
178 }
179
180 String AccessibilityARIAGridCell::ariaReadOnlyValue() const
181 {
182     if (hasAttribute(aria_readonlyAttr))
183         return getAttribute(aria_readonlyAttr).string().convertToASCIILowercase();
184
185     // ARIA 1.1 requires user agents to propagate the grid's aria-readonly value to all
186     // gridcell elements if the property is not present on the gridcell element itelf.
187     if (AccessibilityObject* parent = parentTable())
188         return parent->ariaReadOnlyValue();
189
190     return String();
191 }
192   
193 } // namespace WebCore